diff options
Diffstat (limited to 'linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff')
-rw-r--r-- | linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff | 51503 |
1 files changed, 0 insertions, 51503 deletions
diff --git a/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff b/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff deleted file mode 100644 index 74e6375385..0000000000 --- a/linux/linux-mtx-1-2.4.27/01-mtd-2004-01-27.diff +++ /dev/null @@ -1,51503 +0,0 @@ -diff -Nurb linux-mips-2.4.27/drivers/mtd/Config.in linux/drivers/mtd/Config.in ---- linux-mips-2.4.27/drivers/mtd/Config.in 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/Config.in 2004-11-19 10:25:11.607244176 +0100 -@@ -1,5 +1,5 @@ - --# $Id$ -+# $Id$ - - mainmenu_option next_comment - comment 'Memory Technology Devices (MTD)' -@@ -30,6 +30,7 @@ - if [ "$CONFIG_NFTL" = "y" -o "$CONFIG_NFTL" = "m" ]; then - bool ' Write support for NFTL (BETA)' CONFIG_NFTL_RW - fi -+ dep_tristate ' INFTL (Inverse NAND Flash Translation Layer) support' CONFIG_INFTL $CONFIG_MTD - - source drivers/mtd/chips/Config.in - -diff -Nurb linux-mips-2.4.27/drivers/mtd/Makefile linux/drivers/mtd/Makefile ---- linux-mips-2.4.27/drivers/mtd/Makefile 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/Makefile 2004-11-19 10:25:11.608244024 +0100 -@@ -1,30 +1,7 @@ - # - # Makefile for the memory technology device drivers. - # --# Note! Dependencies are done automagically by 'make dep', which also --# removes any old dependencies. DON'T put your own dependencies here --# unless it's something special (ie not a .c file). --# --# Note 2! The CFLAGS definitions are now inherited from the --# parent makes.. --# --# $Id$ -- -- --obj-y += chips/chipslink.o maps/mapslink.o \ -- devices/devlink.o nand/nandlink.o --obj-m := --obj-n := --obj- := -- --O_TARGET := mtdlink.o -- --export-objs := mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o mtdconcat.o --list-multi := nftl.o -- --mod-subdirs := --subdir-y := chips maps devices nand --subdir-m := $(subdir-y) -+# $Id$ - - # *** BIG UGLY NOTE *** - # -@@ -52,15 +29,44 @@ - - # 'Users' - code which presents functionality to userspace. - obj-$(CONFIG_MTD_CHAR) += mtdchar.o --obj-$(CONFIG_MTD_BLOCK) += mtdblock.o --obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o --obj-$(CONFIG_FTL) += ftl.o --obj-$(CONFIG_NFTL) += nftl.o -+obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs.o -+obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o -+obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o -+obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o -+obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o - - nftl-objs := nftlcore.o nftlmount.o -+inftl-objs := inftlcore.o inftlmount.o -+ -+ifeq ($(PATCHLEVEL),4) -+ -+export-objs := mtdcore.o mtdpart.o redboot.o cmdlinepart.o afs.o \ -+ mtdconcat.o mtd_blkdevs-24.o -+ -+mtd_blkdevs-objs := mtd_blkdevs-24.o -+ -+obj-y += chips/chipslink.o maps/mapslink.o \ -+ devices/devlink.o nand/nandlink.o -+ -+O_TARGET := mtdlink.o -+ -+list-multi := nftl.o inftl.o mtd_blkdevs.o -+ -+mod-subdirs := -+subdir-y := chips maps devices nand -+subdir-m := $(subdir-y) - - include $(TOPDIR)/Rules.make - - nftl.o: $(nftl-objs) - $(LD) -r -o $@ $(nftl-objs) - -+inftl.o: $(inftl-objs) -+ $(LD) -r -o $@ $(inftl-objs) -+ -+mtd_blkdevs.o: $(mtd_blkdevs-objs) -+ $(LD) -r -o $@ $(mtd_blkdevs-objs) -+ -+else -+obj-y += chips/ maps/ devices/ nand/ -+endif -diff -Nurb linux-mips-2.4.27/drivers/mtd/afs.c linux/drivers/mtd/afs.c ---- linux-mips-2.4.27/drivers/mtd/afs.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/afs.c 2004-11-19 10:25:11.610243720 +0100 -@@ -21,7 +21,7 @@ - This is access code for flashes using ARM's flash partitioning - standards. - -- $Id$ -+ $Id$ - - ======================================================================*/ - -@@ -76,17 +76,19 @@ - return ret; - } - -+ ret = 1; -+ - /* - * Does it contain the magic number? - */ - if (fs.signature != 0xa0ffff9f) -- ret = 1; -+ ret = 0; - - /* - * Don't touch the SIB. - */ - if (fs.type == 2) -- ret = 1; -+ ret = 0; - - *iis_start = fs.image_info_base & mask; - *img_start = fs.image_start & mask; -@@ -96,14 +98,14 @@ - * be located after the footer structure. - */ - if (*iis_start >= ptr) -- ret = 1; -+ ret = 0; - - /* - * Check the start of this image. The image - * data can not be located after this block. - */ - if (*img_start > off) -- ret = 1; -+ ret = 0; - - return ret; - } -@@ -125,7 +127,9 @@ - return ret; - } - --int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts) -+static int parse_afs_partitions(struct mtd_info *mtd, -+ struct mtd_partition **pparts, -+ unsigned long origin) - { - struct mtd_partition *parts; - u_int mask, off, idx, sz; -@@ -150,7 +154,7 @@ - ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask); - if (ret < 0) - break; -- if (ret == 1) -+ if (ret == 0) - continue; - - ret = afs_read_iis(mtd, &iis, iis_ptr); -@@ -183,7 +187,7 @@ - ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask); - if (ret < 0) - break; -- if (ret == 1) -+ if (ret == 0) - continue; - - /* Read the image info block */ -@@ -227,7 +231,25 @@ - return idx ? idx : ret; - } - --EXPORT_SYMBOL(parse_afs_partitions); -+static struct mtd_part_parser afs_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_afs_partitions, -+ .name = "afs", -+}; -+ -+static int __init afs_parser_init(void) -+{ -+ return register_mtd_parser(&afs_parser); -+} -+ -+static void __exit afs_parser_exit(void) -+{ -+ deregister_mtd_parser(&afs_parser); -+} -+ -+module_init(afs_parser_init); -+module_exit(afs_parser_exit); -+ - - MODULE_AUTHOR("ARM Ltd"); - MODULE_DESCRIPTION("ARM Firmware Suite partition parser"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/Config.in linux/drivers/mtd/chips/Config.in ---- linux-mips-2.4.27/drivers/mtd/chips/Config.in 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/Config.in 2004-11-19 10:25:11.712228216 +0100 -@@ -1,6 +1,6 @@ - # drivers/mtd/chips/Config.in - --# $Id$ -+# $Id$ - - mainmenu_option next_comment - -@@ -11,13 +11,12 @@ - - if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then - define_bool CONFIG_MTD_GEN_PROBE y --else -- if [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then -+elif [ "$CONFIG_MTD_CFI" = "m" -o "$CONFIG_MTD_JEDECPROBE" = "m" ]; then - define_bool CONFIG_MTD_GEN_PROBE m -- else -+else - define_bool CONFIG_MTD_GEN_PROBE n -- fi - fi -+ - if [ "$CONFIG_MTD_GEN_PROBE" = "y" -o "$CONFIG_MTD_GEN_PROBE" = "m" ]; then - bool ' Flash chip driver advanced configuration options' CONFIG_MTD_CFI_ADV_OPTIONS - if [ "$CONFIG_MTD_CFI_ADV_OPTIONS" = "y" ]; then -@@ -44,8 +43,27 @@ - fi - dep_tristate ' Support for Intel/Sharp flash chips' CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_GEN_PROBE - dep_tristate ' Support for AMD/Fujitsu flash chips' CONFIG_MTD_CFI_AMDSTD $CONFIG_MTD_GEN_PROBE -+if [ "$CONFIG_MTD_CFI_AMDSTD" = "y" -o "$CONFIG_MTD_CFI_AMDSTD" = "m" ]; then -+ bool ' Retry failed commands (erase/program)' CONFIG_MTD_CFI_AMDSTD_RETRY n -+ if [ "$CONFIG_MTD_CFI_AMDSTD_RETRY" = "y" ]; then -+ int ' Max retries of failed commands (erase/program)' CONFIG_MTD_CFI_AMDSTD_RETRY_MAX 0 -+ fi -+fi -+ - dep_tristate ' Support for ST (Advanced Architecture) flash chips' CONFIG_MTD_CFI_STAA $CONFIG_MTD_GEN_PROBE - -+if [ "$CONFIG_MTD_CFI_INTELEXT" = "y" \ -+ -o "$CONFIG_MTD_CFI_AMDSTD" = "y" \ -+ -o "$CONFIG_MTD_CFI_STAA" = "y" ]; then -+ define_bool CONFIG_MTD_CFI_UTIL y -+elif [ "$CONFIG_MTD_CFI_INTELEXT" = "m" \ -+ -o "$CONFIG_MTD_CFI_AMDSTD" = "m" \ -+ -o "$CONFIG_MTD_CFI_STAA" = "m" ]; then -+ define_bool CONFIG_MTD_CFI_UTIL m -+else -+ define_bool CONFIG_MTD_CFI_UTIL n -+fi -+ - dep_tristate ' Support for RAM chips in bus mapping' CONFIG_MTD_RAM $CONFIG_MTD - dep_tristate ' Support for ROM chips in bus mapping' CONFIG_MTD_ROM $CONFIG_MTD - dep_tristate ' Support for absent chips in bus mapping' CONFIG_MTD_ABSENT $CONFIG_MTD -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/Makefile linux/drivers/mtd/chips/Makefile ---- linux-mips-2.4.27/drivers/mtd/chips/Makefile 2003-07-05 05:23:38.000000000 +0200 -+++ linux/drivers/mtd/chips/Makefile 2004-11-19 10:25:11.714227912 +0100 -@@ -1,11 +1,12 @@ - # - # linux/drivers/chips/Makefile - # --# $Id$ -+# $Id$ - -+ifeq ($(PATCHLEVEL),4) - O_TARGET := chipslink.o -- --export-objs := chipreg.o gen_probe.o -+export-objs := chipreg.o gen_probe.o cfi_util.o -+endif - - # *** BIG UGLY NOTE *** - # -@@ -17,6 +18,7 @@ - obj-$(CONFIG_MTD) += chipreg.o - obj-$(CONFIG_MTD_AMDSTD) += amd_flash.o - obj-$(CONFIG_MTD_CFI) += cfi_probe.o -+obj-$(CONFIG_MTD_CFI_UTIL) += cfi_util.o - obj-$(CONFIG_MTD_CFI_STAA) += cfi_cmdset_0020.o - obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o - obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o -@@ -28,4 +30,4 @@ - obj-$(CONFIG_MTD_SHARP) += sharp.o - obj-$(CONFIG_MTD_ABSENT) += map_absent.o - --include $(TOPDIR)/Rules.make -+-include $(TOPDIR)/Rules.make -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/amd_flash.c linux/drivers/mtd/chips/amd_flash.c ---- linux-mips-2.4.27/drivers/mtd/chips/amd_flash.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/amd_flash.c 2004-11-19 10:25:11.722226696 +0100 -@@ -3,7 +3,7 @@ - * - * Author: Jonas Holmberg <jonas.holmberg@axis.com> - * -- * $Id$ -+ * $Id$ - * - * Copyright (c) 2001 Axis Communications AB - * -@@ -19,6 +19,7 @@ - #include <linux/slab.h> - #include <linux/delay.h> - #include <linux/interrupt.h> -+#include <linux/init.h> - #include <linux/mtd/map.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/flashchip.h> -@@ -125,10 +126,10 @@ - - - static struct mtd_chip_driver amd_flash_chipdrv = { -- probe: amd_flash_probe, -- destroy: amd_flash_destroy, -- name: "amd_flash", -- module: THIS_MODULE -+ .probe = amd_flash_probe, -+ .destroy = amd_flash_destroy, -+ .name = "amd_flash", -+ .module = THIS_MODULE - }; - - -@@ -140,11 +141,11 @@ - static inline __u32 wide_read(struct map_info *map, __u32 addr) - { - if (map->buswidth == 1) { -- return map->read8(map, addr); -+ return map_read8(map, addr); - } else if (map->buswidth == 2) { -- return map->read16(map, addr); -+ return map_read16(map, addr); - } else if (map->buswidth == 4) { -- return map->read32(map, addr); -+ return map_read32(map, addr); - } - - return 0; -@@ -153,11 +154,11 @@ - static inline void wide_write(struct map_info *map, __u32 val, __u32 addr) - { - if (map->buswidth == 1) { -- map->write8(map, val, addr); -+ map_write8(map, val, addr); - } else if (map->buswidth == 2) { -- map->write16(map, val, addr); -+ map_write16(map, val, addr); - } else if (map->buswidth == 4) { -- map->write32(map, val, addr); -+ map_write32(map, val, addr); - } - } - -@@ -424,231 +425,228 @@ - - static struct mtd_info *amd_flash_probe(struct map_info *map) - { -- /* Keep this table on the stack so that it gets deallocated after the -- * probe is done. -- */ -- const struct amd_flash_info table[] = { -+ static const struct amd_flash_info table[] = { - { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV160DT, -- name: "AMD AM29LV160DT", -- size: 0x00200000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, -- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV160DT, -+ .name = "AMD AM29LV160DT", -+ .size = 0x00200000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, -+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV160DB, -- name: "AMD AM29LV160DB", -- size: 0x00200000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, -- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV160DB, -+ .name = "AMD AM29LV160DB", -+ .size = 0x00200000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, -+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } - } - }, { -- mfr_id: MANUFACTURER_TOSHIBA, -- dev_id: TC58FVT160, -- name: "Toshiba TC58FVT160", -- size: 0x00200000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, -- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } -+ .mfr_id = MANUFACTURER_TOSHIBA, -+ .dev_id = TC58FVT160, -+ .name = "Toshiba TC58FVT160", -+ .size = 0x00200000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, -+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV160TE, -- name: "Fujitsu MBM29LV160TE", -- size: 0x00200000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, -- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV160TE, -+ .name = "Fujitsu MBM29LV160TE", -+ .size = 0x00200000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, -+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } - } - }, { -- mfr_id: MANUFACTURER_TOSHIBA, -- dev_id: TC58FVB160, -- name: "Toshiba TC58FVB160", -- size: 0x00200000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, -- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } -+ .mfr_id = MANUFACTURER_TOSHIBA, -+ .dev_id = TC58FVB160, -+ .name = "Toshiba TC58FVB160", -+ .size = 0x00200000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, -+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV160BE, -- name: "Fujitsu MBM29LV160BE", -- size: 0x00200000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, -- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV160BE, -+ .name = "Fujitsu MBM29LV160BE", -+ .size = 0x00200000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, -+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV800BB, -- name: "AMD AM29LV800BB", -- size: 0x00100000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, -- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 } -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV800BB, -+ .name = "AMD AM29LV800BB", -+ .size = 0x00100000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, -+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F800BB, -- name: "AMD AM29F800BB", -- size: 0x00100000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, -- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 } -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F800BB, -+ .name = "AMD AM29F800BB", -+ .size = 0x00100000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, -+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV800BT, -- name: "AMD AM29LV800BT", -- size: 0x00100000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 }, -- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 } -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV800BT, -+ .name = "AMD AM29LV800BT", -+ .size = 0x00100000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, -+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F800BT, -- name: "AMD AM29F800BT", -- size: 0x00100000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 }, -- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 } -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F800BT, -+ .name = "AMD AM29F800BT", -+ .size = 0x00100000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, -+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV800BB, -- name: "AMD AM29LV800BB", -- size: 0x00100000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 }, -- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 } -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV800BB, -+ .name = "AMD AM29LV800BB", -+ .size = 0x00100000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, -+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV800BB, -- name: "Fujitsu MBM29LV800BB", -- size: 0x00100000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, -- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x010000, erasesize: 0x10000, numblocks: 15 } -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV800BB, -+ .name = "Fujitsu MBM29LV800BB", -+ .size = 0x00100000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, -+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } - } - }, { -- mfr_id: MANUFACTURER_ST, -- dev_id: M29W800T, -- name: "ST M29W800T", -- size: 0x00100000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 15 }, -- { offset: 0x0F0000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x0F8000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x0FC000, erasesize: 0x04000, numblocks: 1 } -+ .mfr_id = MANUFACTURER_ST, -+ .dev_id = M29W800T, -+ .name = "ST M29W800T", -+ .size = 0x00100000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, -+ { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } - } - }, { -- mfr_id: MANUFACTURER_ST, -- dev_id: M29W160DT, -- name: "ST M29W160DT", -- size: 0x00200000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, -- { offset: 0x1F0000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x1F8000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x1FC000, erasesize: 0x04000, numblocks: 1 } -+ .mfr_id = MANUFACTURER_ST, -+ .dev_id = M29W160DT, -+ .name = "ST M29W160DT", -+ .size = 0x00200000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, -+ { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } - } - }, { -- mfr_id: MANUFACTURER_ST, -- dev_id: M29W160DB, -- name: "ST M29W160DB", -- size: 0x00200000, -- numeraseregions: 4, -- regions: { -- { offset: 0x000000, erasesize: 0x04000, numblocks: 1 }, -- { offset: 0x004000, erasesize: 0x02000, numblocks: 2 }, -- { offset: 0x008000, erasesize: 0x08000, numblocks: 1 }, -- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } -+ .mfr_id = MANUFACTURER_ST, -+ .dev_id = M29W160DB, -+ .name = "ST M29W160DB", -+ .size = 0x00200000, -+ .numeraseregions = 4, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, -+ { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, -+ { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, -+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29BDS323D, -- name: "AMD AM29BDS323D", -- size: 0x00400000, -- numeraseregions: 3, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 48 }, -- { offset: 0x300000, erasesize: 0x10000, numblocks: 15 }, -- { offset: 0x3f0000, erasesize: 0x02000, numblocks: 8 }, -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29BDS323D, -+ .name = "AMD AM29BDS323D", -+ .size = 0x00400000, -+ .numeraseregions = 3, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 }, -+ { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 }, -+ { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 }, - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29BDS643D, -- name: "AMD AM29BDS643D", -- size: 0x00800000, -- numeraseregions: 3, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 96 }, -- { offset: 0x600000, erasesize: 0x10000, numblocks: 31 }, -- { offset: 0x7f0000, erasesize: 0x02000, numblocks: 8 }, -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29BDS643D, -+ .name = "AMD AM29BDS643D", -+ .size = 0x00800000, -+ .numeraseregions = 3, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 }, -+ { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 }, -+ { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 }, - } - }, { -- mfr_id: MANUFACTURER_ATMEL, -- dev_id: AT49xV16x, -- name: "Atmel AT49xV16x", -- size: 0x00200000, -- numeraseregions: 2, -- regions: { -- { offset: 0x000000, erasesize: 0x02000, numblocks: 8 }, -- { offset: 0x010000, erasesize: 0x10000, numblocks: 31 } -+ .mfr_id = MANUFACTURER_ATMEL, -+ .dev_id = AT49xV16x, -+ .name = "Atmel AT49xV16x", -+ .size = 0x00200000, -+ .numeraseregions = 2, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 }, -+ { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } - } - }, { -- mfr_id: MANUFACTURER_ATMEL, -- dev_id: AT49xV16xT, -- name: "Atmel AT49xV16xT", -- size: 0x00200000, -- numeraseregions: 2, -- regions: { -- { offset: 0x000000, erasesize: 0x10000, numblocks: 31 }, -- { offset: 0x1F0000, erasesize: 0x02000, numblocks: 8 } -+ .mfr_id = MANUFACTURER_ATMEL, -+ .dev_id = AT49xV16xT, -+ .name = "Atmel AT49xV16xT", -+ .size = 0x00200000, -+ .numeraseregions = 2, -+ .regions = { -+ { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, -+ { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } - } - } - }; -@@ -822,7 +820,7 @@ - - chip->state = FL_READY; - -- map->copy_from(map, buf, adr, len); -+ map_copy_from(map, buf, adr, len); - - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); -@@ -984,7 +982,7 @@ - u_char tmp_buf[4]; - __u32 datum; - -- map->copy_from(map, tmp_buf, -+ map_copy_from(map, tmp_buf, - bus_ofs + private->chips[chipnum].start, - map->buswidth); - while (len && i < map->buswidth) -@@ -1057,7 +1055,7 @@ - u_char tmp_buf[2]; - __u32 datum; - -- map->copy_from(map, tmp_buf, -+ map_copy_from(map, tmp_buf, - ofs + private->chips[chipnum].start, - map->buswidth); - while (len--) { -@@ -1178,7 +1176,7 @@ - __u8 verify; - - for (address = adr; address < (adr + size); address++) { -- if ((verify = map->read8(map, address)) != 0xFF) { -+ if ((verify = map_read8(map, address)) != 0xFF) { - error = 1; - break; - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0001.c linux/drivers/mtd/chips/cfi_cmdset_0001.c ---- linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0001.c 2003-07-05 05:23:38.000000000 +0200 -+++ linux/drivers/mtd/chips/cfi_cmdset_0001.c 2004-11-19 10:25:11.733225024 +0100 -@@ -4,7 +4,7 @@ - * - * (C) 2000 Red Hat. GPL'd - * -- * $Id$ -+ * $Id$ - * - * - * 10/10/2000 Nicolas Pitre <nico@cam.org> -@@ -21,6 +21,7 @@ - #include <linux/types.h> - #include <linux/kernel.h> - #include <linux/sched.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <asm/byteorder.h> - -@@ -29,10 +30,14 @@ - #include <linux/delay.h> - #include <linux/interrupt.h> - #include <linux/mtd/map.h> --#include <linux/mtd/cfi.h> -+#include <linux/mtd/mtd.h> - #include <linux/mtd/compatmac.h> -+#include <linux/mtd/cfi.h> -+ -+/* #define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE */ - --// debugging, turns off buffer write mode #define FORCE_WORD_WRITE -+// debugging, turns off buffer write mode if set to 1 -+#define FORCE_WORD_WRITE 0 - - static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); - static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -@@ -52,16 +57,21 @@ - - static struct mtd_info *cfi_intelext_setup (struct map_info *); - --static int do_point (struct mtd_info *mtd, loff_t from, size_t len, -+static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char **mtdbuf); --static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, -+static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, - size_t len); - -+ -+/* -+ * *********** SETUP AND PROBE BITS *********** -+ */ -+ - static struct mtd_chip_driver cfi_intelext_chipdrv = { -- probe: NULL, /* Not usable directly */ -- destroy: cfi_intelext_destroy, -- name: "cfi_cmdset_0001", -- module: THIS_MODULE -+ .probe = NULL, /* Not usable directly */ -+ .destroy = cfi_intelext_destroy, -+ .name = "cfi_cmdset_0001", -+ .module = THIS_MODULE - }; - - /* #define DEBUG_LOCK_BITS */ -@@ -102,13 +112,63 @@ - } - - printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", -- extp->VccOptimal >> 8, extp->VccOptimal & 0xf); -+ extp->VccOptimal >> 4, extp->VccOptimal & 0xf); - if (extp->VppOptimal) - printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", -- extp->VppOptimal >> 8, extp->VppOptimal & 0xf); -+ extp->VppOptimal >> 4, extp->VppOptimal & 0xf); - } - #endif - -+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE -+/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ -+static void fixup_intel_strataflash(struct map_info *map, void* param) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv; -+ -+ printk(KERN_WARNING "cfi_cmdset_0001: Suspend " -+ "erase on write disabled.\n"); -+ extp->SuspendCmdSupport &= ~1; -+} -+#endif -+ -+static void fixup_st_m28w320ct(struct map_info *map, void* param) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ -+ cfi->cfiq->BufWriteTimeoutTyp = 0; /* Not supported */ -+ cfi->cfiq->BufWriteTimeoutMax = 0; /* Not supported */ -+} -+ -+static void fixup_st_m28w320cb(struct map_info *map, void* param) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ -+ /* Note this is done after the region info is endian swapped */ -+ cfi->cfiq->EraseRegionInfo[1] = -+ (cfi->cfiq->EraseRegionInfo[1] & 0xffff0000) | 0x3e; -+}; -+ -+static struct cfi_fixup fixup_table[] = { -+#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE -+ { -+ CFI_MFR_ANY, CFI_ID_ANY, -+ fixup_intel_strataflash, NULL -+ }, -+#endif -+ { -+ 0x0020, /* STMicroelectronics */ -+ 0x00ba, /* M28W320CT */ -+ fixup_st_m28w320ct, NULL -+ }, { -+ 0x0020, /* STMicroelectronics */ -+ 0x00bb, /* M28W320CB */ -+ fixup_st_m28w320cb, NULL -+ }, { -+ 0, 0, NULL, NULL -+ } -+}; -+ - /* This routine is made available to other mtd code via - * inter_module_register. It must only be accessed through - * inter_module_get which will bump the use count of this module. The -@@ -120,7 +180,6 @@ - { - struct cfi_private *cfi = map->fldrv_priv; - int i; -- __u32 base = cfi->chips[0].start; - - if (cfi->cfi_mode == CFI_MODE_CFI) { - /* -@@ -130,59 +189,29 @@ - */ - __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; - struct cfi_pri_intelext *extp; -- int ofs_factor = cfi->interleave * cfi->device_type; -- -- //printk(" Intel/Sharp Extended Query Table at 0x%4.4X\n", adr); -- if (!adr) -- return NULL; - -- /* Switch it into Query Mode */ -- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); -- -- extp = kmalloc(sizeof(*extp), GFP_KERNEL); -- if (!extp) { -- printk(KERN_ERR "Failed to allocate memory\n"); -+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "Intel/Sharp"); -+ if (!extp) - return NULL; -- } -- -- /* Read in the Extended Query Table */ -- for (i=0; i<sizeof(*extp); i++) { -- ((unsigned char *)extp)[i] = -- cfi_read_query(map, (base+((adr+i)*ofs_factor))); -- } -- -- if (extp->MajorVersion != '1' || -- (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { -- printk(KERN_WARNING " Unknown IntelExt Extended Query " -- "version %c.%c.\n", extp->MajorVersion, -- extp->MinorVersion); -- kfree(extp); -- return NULL; -- } - - /* Do some byteswapping if necessary */ - extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); - extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); - extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); - -+ /* Install our own private info structure */ -+ cfi->cmdset_priv = extp; -+ -+ cfi_fixup(map, fixup_table); -+ - #ifdef DEBUG_CFI_FEATURES - /* Tell the user about it in lots of lovely detail */ - cfi_tell_features(extp); - #endif - - if(extp->SuspendCmdSupport & 1) { --//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE --#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE --/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ -- printk(KERN_WARNING "cfi_cmdset_0001: Suspend " -- "erase on write disabled.\n"); -- extp->SuspendCmdSupport &= ~1; --#else - printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); --#endif - } -- /* Install our own private info structure */ -- cfi->cmdset_priv = extp; - } - - for (i=0; i< cfi->numchips; i++) { -@@ -194,8 +223,6 @@ - - map->fldrv = &cfi_intelext_chipdrv; - -- /* Make sure it's in read mode */ -- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL); - return cfi_intelext_setup(map); - } - -@@ -261,20 +288,16 @@ - mtd->erase = cfi_intelext_erase_varsize; - mtd->read = cfi_intelext_read; - -- if(map->point && map->unpoint){ -- mtd->point = do_point; -- mtd->unpoint = do_unpoint; -+ if (map_is_linear(map)) { -+ mtd->point = cfi_intelext_point; -+ mtd->unpoint = cfi_intelext_unpoint; - } - --#ifndef FORCE_WORD_WRITE -- if ( cfi->cfiq->BufWriteTimeoutTyp ) { -- printk("Using buffer write method\n" ); -+ if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) { -+ printk(KERN_INFO "Using buffer write method\n" ); - mtd->write = cfi_intelext_write_buffers; - } else { --#else -- { --#endif -- printk("Using word write method\n" ); -+ printk(KERN_INFO "Using word write method\n" ); - mtd->write = cfi_intelext_write_words; - } - mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; -@@ -286,8 +309,8 @@ - mtd->resume = cfi_intelext_resume; - mtd->flags = MTD_CAP_NORFLASH; - map->fldrv = &cfi_intelext_chipdrv; -- MOD_INC_USE_COUNT; - mtd->name = map->name; -+ __module_get(THIS_MODULE); - return mtd; - - setup_err: -@@ -301,78 +324,170 @@ - return NULL; - } - --static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) -+/* -+ * *********** CHIP ACCESS FUNCTIONS *********** -+ */ -+ -+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) - { -- cfi_word status, status_OK; -- unsigned long timeo; - DECLARE_WAITQUEUE(wait, current); -- unsigned long cmd_addr; - struct cfi_private *cfi = map->fldrv_priv; -+ cfi_word status, status_OK = CMD(0x80); -+ unsigned long timeo; -+ struct cfi_pri_intelext *cfip = (struct cfi_pri_intelext *)cfi->cmdset_priv; - -- adr += chip->start; -- -- /* Ensure cmd read/writes are aligned. */ -- cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); -- -- /* Let's determine this according to the interleave only once */ -- status_OK = CMD(0x80); -- -+ resettime: - timeo = jiffies + HZ; - retry: -- spin_lock(chip->mutex); -- -- /* Check that the chip's ready to talk to us. -- * If it's in FL_ERASING state, suspend it and make it talk now. -- */ - switch (chip->state) { - -- case FL_READY: -- case FL_POINT: -+ case FL_STATUS: -+ for (;;) { -+ status = cfi_read(map, adr); -+ if ((status & status_OK) == status_OK) - break; - -+ if (time_after(jiffies, timeo)) { -+ printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n", -+ (long long)status); -+ spin_unlock(chip->mutex); -+ return -EIO; -+ } -+ spin_unlock(chip->mutex); -+ cfi_udelay(1); -+ spin_lock(chip->mutex); -+ /* Someone else might have been playing with it. */ -+ goto retry; -+ } -+ -+ case FL_READY: - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: -- cfi_write(map, CMD(0x70), cmd_addr); -- chip->state = FL_STATUS; -+ return 0; - -- case FL_STATUS: -- status = cfi_read(map, cmd_addr); -- if ((status & status_OK) == status_OK) { -- cfi_write(map, CMD(0xff), cmd_addr); -- chip->state = FL_READY; -+ case FL_ERASING: -+ if (!(cfip->FeatureSupport & 2) || -+ !(mode == FL_READY || mode == FL_POINT || -+ (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1)))) -+ goto sleep; -+ -+ -+ /* Erase suspend */ -+ cfi_write(map, CMD(0xB0), adr); -+ -+ /* If the flash has finished erasing, then 'erase suspend' -+ * appears to make some (28F320) flash devices switch to -+ * 'read' mode. Make sure that we switch to 'read status' -+ * mode so we get the right data. --rmk -+ */ -+ cfi_write(map, CMD(0x70), adr); -+ chip->oldstate = FL_ERASING; -+ chip->state = FL_ERASE_SUSPENDING; -+ chip->erase_suspended = 1; -+ for (;;) { -+ status = cfi_read(map, adr); -+ if ((status & status_OK) == status_OK) - break; -- } - -- /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { -- spin_unlock(chip->mutex); -- printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status); -+ /* Urgh. Resume and pretend we weren't here. */ -+ cfi_write(map, CMD(0xd0), adr); -+ /* Make sure we're in 'read status' mode if it had finished */ -+ cfi_write(map, CMD(0x70), adr); -+ chip->state = FL_ERASING; -+ chip->oldstate = FL_READY; -+ printk(KERN_ERR "Chip not ready after erase " -+ "suspended: status = 0x%x\n", status); - return -EIO; - } - -- /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock(chip->mutex); - cfi_udelay(1); -- goto retry; -+ spin_lock(chip->mutex); -+ /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING. -+ So we can just loop here. */ -+ } -+ chip->state = FL_STATUS; -+ return 0; -+ -+ case FL_POINT: -+ /* Only if there's no operation suspended... */ -+ if (mode == FL_READY && chip->oldstate == FL_READY) -+ return 0; - - default: -- /* Stick ourselves on a wait queue to be woken when -- someone changes the status */ -+ sleep: - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); -- timeo = jiffies + HZ; -- goto retry; -+ spin_lock(chip->mutex); -+ goto resettime; - } -+} -+ -+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ -+ switch(chip->oldstate) { -+ case FL_ERASING: -+ chip->state = chip->oldstate; -+ /* What if one interleaved chip has finished and the -+ other hasn't? The old code would leave the finished -+ one in READY mode. That's bad, and caused -EROFS -+ errors to be returned from do_erase_oneblock because -+ that's the only bit it checked for at the time. -+ As the state machine appears to explicitly allow -+ sending the 0x70 (Read Status) command to an erasing -+ chip and expecting it to be ignored, that's what we -+ do. */ -+ cfi_write(map, CMD(0xd0), adr); -+ cfi_write(map, CMD(0x70), adr); -+ chip->oldstate = FL_READY; -+ chip->state = FL_ERASING; -+ break; -+ -+ case FL_READY: -+ case FL_STATUS: -+ /* We should really make set_vpp() count, rather than doing this */ -+ DISABLE_VPP(map); -+ break; -+ default: -+ printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate); -+ } -+ wake_up(&chip->wq); -+} -+ -+static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) -+{ -+ unsigned long cmd_addr; -+ struct cfi_private *cfi = map->fldrv_priv; -+ int ret = 0; -+ -+ adr += chip->start; -+ -+ /* Ensure cmd read/writes are aligned. */ -+ cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); -+ -+ spin_lock(chip->mutex); -+ -+ ret = get_chip(map, chip, cmd_addr, FL_POINT); -+ -+ if (!ret) { -+ if (chip->state != FL_POINT && chip->state != FL_READY) -+ cfi_write(map, CMD(0xff), cmd_addr); - - chip->state = FL_POINT; - chip->ref_point_counter++; -+ } - spin_unlock(chip->mutex); -- return 0; -+ -+ return ret; - } --static int do_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) -+ -+static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) - { - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; -@@ -380,12 +495,10 @@ - int chipnum; - int ret = 0; - -- if (from + len > mtd->size) -+ if (!map->virt || (from + len > mtd->size)) - return -EINVAL; - -- *mtdbuf = map->point(map, from, len); -- if(*mtdbuf == NULL) -- return -EINVAL; /* can not point this region */ -+ *mtdbuf = (void *)map->virt + from; - *retlen = 0; - - /* Now lock the chip(s) to POINT state */ -@@ -418,14 +531,13 @@ - return 0; - } - --static void do_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) -+static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) - { - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - unsigned long ofs; - int chipnum; - -- map->unpoint(map, addr, from, len); - /* Now unlock the chip(s) POINT state */ - - /* ofs: offset within the first chip that the first read should start */ -@@ -446,13 +558,14 @@ - thislen = len; - - spin_lock(chip->mutex); -- if(chip->state == FL_POINT){ -+ if (chip->state == FL_POINT) { - chip->ref_point_counter--; - if(chip->ref_point_counter == 0) - chip->state = FL_READY; - } else -- printk("Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ -- wake_up(&chip->wq); -+ printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ -+ -+ put_chip(map, chip, chip->start); - spin_unlock(chip->mutex); - - len -= thislen; -@@ -463,136 +576,32 @@ - - static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) - { -- cfi_word status, status_OK; -- unsigned long timeo; -- DECLARE_WAITQUEUE(wait, current); -- int suspended = 0; - unsigned long cmd_addr; - struct cfi_private *cfi = map->fldrv_priv; -+ int ret; - - adr += chip->start; - - /* Ensure cmd read/writes are aligned. */ - cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); - -- /* Let's determine this according to the interleave only once */ -- status_OK = CMD(0x80); -- -- timeo = jiffies + HZ; -- retry: - spin_lock(chip->mutex); -- -- /* Check that the chip's ready to talk to us. -- * If it's in FL_ERASING state, suspend it and make it talk now. -- */ -- switch (chip->state) { -- case FL_ERASING: -- if (!cfi->cmdset_priv || -- !(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) -- goto sleep; /* We don't support erase suspend */ -- -- cfi_write (map, CMD(0xb0), cmd_addr); -- /* If the flash has finished erasing, then 'erase suspend' -- * appears to make some (28F320) flash devices switch to -- * 'read' mode. Make sure that we switch to 'read status' -- * mode so we get the right data. --rmk -- */ -- cfi_write(map, CMD(0x70), cmd_addr); -- chip->oldstate = FL_ERASING; -- chip->state = FL_ERASE_SUSPENDING; -- // printk("Erase suspending at 0x%lx\n", cmd_addr); -- for (;;) { -- status = cfi_read(map, cmd_addr); -- if ((status & status_OK) == status_OK) -- break; -- -- if (time_after(jiffies, timeo)) { -- /* Urgh */ -- cfi_write(map, CMD(0xd0), cmd_addr); -- /* make sure we're in 'read status' mode */ -- cfi_write(map, CMD(0x70), cmd_addr); -- chip->state = FL_ERASING; -- spin_unlock(chip->mutex); -- printk(KERN_ERR "Chip not ready after erase " -- "suspended: status = 0x%llx\n", (__u64)status); -- return -EIO; -- } -- -+ ret = get_chip(map, chip, cmd_addr, FL_READY); -+ if (ret) { - spin_unlock(chip->mutex); -- cfi_udelay(1); -- spin_lock(chip->mutex); -+ return ret; - } - -- suspended = 1; -+ if (chip->state != FL_POINT && chip->state != FL_READY) { - cfi_write(map, CMD(0xff), cmd_addr); -- chip->state = FL_READY; -- break; -- --#if 0 -- case FL_WRITING: -- /* Not quite yet */ --#endif -- -- case FL_READY: -- case FL_POINT: -- break; -- -- case FL_CFI_QUERY: -- case FL_JEDEC_QUERY: -- cfi_write(map, CMD(0x70), cmd_addr); -- chip->state = FL_STATUS; - -- case FL_STATUS: -- status = cfi_read(map, cmd_addr); -- if ((status & status_OK) == status_OK) { -- cfi_write(map, CMD(0xff), cmd_addr); - chip->state = FL_READY; -- break; - } - -- /* Urgh. Chip not yet ready to talk to us. */ -- if (time_after(jiffies, timeo)) { -- spin_unlock(chip->mutex); -- printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %llx\n", (__u64)status); -- return -EIO; -- } -+ map_copy_from(map, buf, adr, len); - -- /* Latency issues. Drop the lock, wait a while and retry */ -- spin_unlock(chip->mutex); -- cfi_udelay(1); -- goto retry; -+ put_chip(map, chip, cmd_addr); - -- default: -- sleep: -- /* Stick ourselves on a wait queue to be woken when -- someone changes the status */ -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -- spin_unlock(chip->mutex); -- schedule(); -- remove_wait_queue(&chip->wq, &wait); -- timeo = jiffies + HZ; -- goto retry; -- } -- -- map->copy_from(map, buf, adr, len); -- -- if (suspended) { -- chip->state = chip->oldstate; -- /* What if one interleaved chip has finished and the -- other hasn't? The old code would leave the finished -- one in READY mode. That's bad, and caused -EROFS -- errors to be returned from do_erase_oneblock because -- that's the only bit it checked for at the time. -- As the state machine appears to explicitly allow -- sending the 0x70 (Read Status) command to an erasing -- chip and expecting it to be ignored, that's what we -- do. */ -- cfi_write(map, CMD(0xd0), cmd_addr); -- cfi_write(map, CMD(0x70), cmd_addr); -- } -- -- wake_up(&chip->wq); - spin_unlock(chip->mutex); - return 0; - } -@@ -640,70 +649,52 @@ - { - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; -- struct cfi_pri_intelext *extp=cfi->cmdset_priv; -- int ofs_factor = cfi->interleave * cfi->device_type; -- int count=len; -+ struct cfi_pri_intelext *extp = cfi->cmdset_priv; - struct flchip *chip; -- int chip_num,offst; -- unsigned long timeo; -- DECLARE_WAITQUEUE(wait, current); -+ int ofs_factor = cfi->interleave * cfi->device_type; -+ int count = len; -+ int chip_num, offst; -+ int ret; - -- chip=0; -- /* Calculate which chip & protection register offset we need */ -- chip_num=((unsigned int)from/reg_sz); -- offst=from-(reg_sz*chip_num)+base_offst; -+ chip_num = ((unsigned int)from/reg_sz); -+ offst = from - (reg_sz*chip_num)+base_offst; - -- while(count){ -+ while (count) { -+ /* Calculate which chip & protection register offset we need */ - -- if(chip_num>=cfi->numchips) -+ if (chip_num >= cfi->numchips) - goto out; - -- /* Make sure that the chip is in the right state */ -+ chip = &cfi->chips[chip_num]; - -- timeo = jiffies + HZ; -- chip=&cfi->chips[chip_num]; -- retry: - spin_lock(chip->mutex); -- -- switch (chip->state) { -- case FL_READY: -- case FL_STATUS: -- case FL_CFI_QUERY: -- case FL_JEDEC_QUERY: -- break; -- -- default: -- /* Stick ourselves on a wait queue to be woken when -- someone changes the status */ -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -+ ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); -+ if (ret) { - spin_unlock(chip->mutex); -- schedule(); -- remove_wait_queue(&chip->wq, &wait); -- timeo = jiffies + HZ; -- goto retry; -+ return (len-count)?:ret; - } - -- /* Now read the data required from this flash */ -+ if (chip->state != FL_JEDEC_QUERY) { -+ cfi_write(map, CMD(0x90), chip->start); -+ chip->state = FL_JEDEC_QUERY; -+ } - -- cfi_send_gen_cmd(0x90, 0x55,chip->start, map, cfi, cfi->device_type, NULL); -- while(count && ((offst-base_offst)<reg_sz)){ -- *buf=map->read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); -+ while (count && ((offst-base_offst) < reg_sz)) { -+ *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); - buf++; - offst++; - count--; - } - -- chip->state=FL_CFI_QUERY; -+ put_chip(map, chip, chip->start); - spin_unlock(chip->mutex); -+ - /* Move on to the next chip */ - chip_num++; -- offst=base_offst; -- -+ offst = base_offst; - } - - out: -- wake_up(&chip->wq); - return len-count; - } - -@@ -749,103 +740,20 @@ - static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum) - { - struct cfi_private *cfi = map->fldrv_priv; -- struct cfi_pri_intelext *extp = cfi->cmdset_priv; -- cfi_word status, status_OK; -- unsigned long timeo; -- DECLARE_WAITQUEUE(wait, current); -- int z, suspended=0, ret=0; -- -- adr += chip->start; -- -- /* Let's determine this according to the interleave only once */ -- status_OK = CMD(0x80); -- -- timeo = jiffies + HZ; -- retry: -- spin_lock(chip->mutex); -- -- /* Check that the chip's ready to talk to us. -- * Later, we can actually think about interrupting it -- * if it's in FL_ERASING state. -- * Not just yet, though. -- */ -- switch (chip->state) { -- case FL_READY: -- break; -- -- case FL_CFI_QUERY: -- case FL_JEDEC_QUERY: -- cfi_write(map, CMD(0x70), adr); -- chip->state = FL_STATUS; -- -- case FL_STATUS: -- status = cfi_read(map, adr); -- if ((status & status_OK) == status_OK) -- break; -- -- /* Urgh. Chip not yet ready to talk to us. */ -- if (time_after(jiffies, timeo)) { -- spin_unlock(chip->mutex); -- printk(KERN_ERR "waiting for chip to be ready timed out in read\n"); -- return -EIO; -- } -- -- /* Latency issues. Drop the lock, wait a while and retry */ -- spin_unlock(chip->mutex); -- cfi_udelay(1); -- goto retry; -- -- case FL_ERASING: -- if (!extp || -- !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1))) -- goto sleep; /* We don't support erase suspend */ -- -- cfi_write (map, CMD(0xb0), adr); -- -- /* If the flash has finished erasing, then 'erase suspend' -- * appears to make some (28F320) flash devices switch to -- * 'read' mode. Make sure that we switch to 'read status' -- * mode so we get the right data. --rmk -- */ -- cfi_write(map, CMD(0x70), adr); -- chip->oldstate = FL_ERASING; -- chip->state = FL_ERASE_SUSPENDING; -- for (;;) { -- status = cfi_read(map, adr); -- if ((status & status_OK) == status_OK) -- break; -+ cfi_word status, status_OK; -+ unsigned long timeo; -+ int z, ret=0; - -- if (time_after(jiffies, timeo)) { -- /* Urgh */ -- cfi_write(map, CMD(0xd0), adr); -- /* make sure we're in 'read status' mode */ -- cfi_write(map, CMD(0x70), adr); -- chip->state = FL_ERASING; -- spin_unlock(chip->mutex); -- printk(KERN_ERR "Chip not ready after erase " -- "suspended: status = 0x%x\n", status); -- return -EIO; -- } -+ adr += chip->start; - -- spin_unlock(chip->mutex); -- cfi_udelay(1); -- spin_lock(chip->mutex); -- } -- suspended = 1; -- chip->state = FL_STATUS; -- break; -+ /* Let's determine this according to the interleave only once */ -+ status_OK = CMD(0x80); - -- default: -- sleep: -- /* Stick ourselves on a wait queue to be woken when -- someone changes the status */ -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -+ spin_lock(chip->mutex); -+ ret = get_chip(map, chip, adr, FL_WRITING); -+ if (ret) { - spin_unlock(chip->mutex); -- schedule(); -- remove_wait_queue(&chip->wq, &wait); -- timeo = jiffies + HZ; -- goto retry; -+ return ret; - } - - ENABLE_VPP(map); -@@ -862,6 +770,8 @@ - for (;;) { - if (chip->state != FL_WRITING) { - /* Someone's suspended the write. Sleep */ -+ DECLARE_WAITQUEUE(wait, current); -+ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); -@@ -879,7 +789,6 @@ - /* OK Still waiting */ - if (time_after(jiffies, timeo)) { - chip->state = FL_STATUS; -- DISABLE_VPP(map); - printk(KERN_ERR "waiting for chip to be ready timed out in word write\n"); - ret = -EIO; - goto out; -@@ -908,27 +817,11 @@ - /* put back into read status register mode */ - cfi_write(map, CMD(0x70), adr); - ret = -EROFS; -- goto out; - } - out: -- if (suspended) { -- chip->state = chip->oldstate; -- /* What if one interleaved chip has finished and the -- other hasn't? The old code would leave the finished -- one in READY mode. That's bad, and caused -EROFS -- errors to be returned from do_erase_oneblock because -- that's the only bit it checked for at the time. -- As the state machine appears to explicitly allow -- sending the 0x70 (Read Status) command to an erasing -- chip and expecting it to be ignored, that's what we -- do. */ -- cfi_write(map, CMD(0xd0), adr); -- cfi_write(map, CMD(0x70), adr); -- } else -- DISABLE_VPP(map); /* must not clear the VPP if there is a suspended erase to be resumed */ -- -- wake_up(&chip->wq); -+ put_chip(map, chip, adr); - spin_unlock(chip->mutex); -+ - return ret; - } - -@@ -1059,11 +952,9 @@ - unsigned long adr, const u_char *buf, int len) - { - struct cfi_private *cfi = map->fldrv_priv; -- struct cfi_pri_intelext *extp = cfi->cmdset_priv; - cfi_word status, status_OK; - unsigned long cmd_adr, timeo; -- DECLARE_WAITQUEUE(wait, current); -- int wbufsize, z, suspended=0, ret=0; -+ int wbufsize, z, ret=0, bytes, words; - - wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; - adr += chip->start; -@@ -1072,91 +963,18 @@ - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - -- timeo = jiffies + HZ; -- retry: - spin_lock(chip->mutex); -- -- /* Check that the chip's ready to talk to us. -- * Later, we can actually think about interrupting it -- * if it's in FL_ERASING state. -- * Not just yet, though. -- */ -- switch (chip->state) { -- case FL_READY: -- case FL_CFI_QUERY: -- case FL_JEDEC_QUERY: -- cfi_write(map, CMD(0x70), cmd_adr); -- chip->state = FL_STATUS; -- -- case FL_STATUS: -- status = cfi_read(map, cmd_adr); -- if ((status & status_OK) == status_OK) -- break; -- /* Urgh. Chip not yet ready to talk to us. */ -- if (time_after(jiffies, timeo)) { -+ ret = get_chip(map, chip, cmd_adr, FL_WRITING); -+ if (ret) { - spin_unlock(chip->mutex); -- printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n"); -- return -EIO; -+ return ret; - } - -- /* Latency issues. Drop the lock, wait a while and retry */ -- spin_unlock(chip->mutex); -- cfi_udelay(1); -- goto retry; -- -- case FL_ERASING: -- if (!extp || -- !((extp->FeatureSupport & 2) && (extp->SuspendCmdSupport & 1))) -- goto sleep; /* We don't support erase suspend */ -- -- cfi_write (map, CMD(0xb0), adr); -- -- /* If the flash has finished erasing, then 'erase suspend' -- * appears to make some (28F320) flash devices switch to -- * 'read' mode. Make sure that we switch to 'read status' -- * mode so we get the right data. --rmk -- */ -- cfi_write(map, CMD(0x70), adr); -- chip->oldstate = FL_ERASING; -- chip->state = FL_ERASE_SUSPENDING; -- for (;;) { -- status = cfi_read(map, adr); -- if ((status & status_OK) == status_OK) -- break; -- -- if (time_after(jiffies, timeo)) { -- /* Urgh */ -- cfi_write(map, CMD(0xd0), adr); -- /* make sure we're in 'read status' mode */ -- cfi_write(map, CMD(0x70), adr); -- chip->state = FL_ERASING; -- spin_unlock(chip->mutex); -- printk(KERN_ERR "Chip not ready after erase " -- "suspended: status = 0x%x\n", status); -- return -EIO; -- } -+ if (chip->state != FL_STATUS) -+ cfi_write(map, CMD(0x70), cmd_adr); - -- spin_unlock(chip->mutex); -- cfi_udelay(1); -- spin_lock(chip->mutex); -- } -- suspended = 1; -- chip->state = FL_STATUS; -- break; -+ status = cfi_read(map, cmd_adr); - -- default: -- sleep: -- /* Stick ourselves on a wait queue to be woken when -- someone changes the status */ -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -- spin_unlock(chip->mutex); -- schedule(); -- remove_wait_queue(&chip->wq, &wait); -- timeo = jiffies + HZ; -- goto retry; -- } -- /* We know we're now in FL_STATUS mode, and 'status' is current */ - /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set - [...], the device will not accept any more Write to Buffer commands". - So we must check here and reset those bits if they're set. Otherwise -@@ -1185,7 +1003,6 @@ - /* Argh. Not ready for write to buffer */ - cfi_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; -- DISABLE_VPP(map); - printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr)); - /* Odd. Clear status bits */ - cfi_write(map, CMD(0x50), cmd_adr); -@@ -1196,20 +1013,42 @@ - } - - /* Write length of data to come */ -- cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr ); -+ bytes = len & (CFIDEV_BUSWIDTH-1); -+ words = len / CFIDEV_BUSWIDTH; -+ cfi_write(map, CMD(words - !bytes), cmd_adr ); - - /* Write data */ -- for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { -+ z = 0; -+ while(z < words * CFIDEV_BUSWIDTH) { - if (cfi_buswidth_is_1()) { -- map->write8 (map, *((__u8*)buf)++, adr+z); -+ map_write8 (map, *((__u8*)buf)++, adr+z); - } else if (cfi_buswidth_is_2()) { -- map->write16 (map, *((__u16*)buf)++, adr+z); -+ map_write16 (map, *((__u16*)buf)++, adr+z); - } else if (cfi_buswidth_is_4()) { -- map->write32 (map, *((__u32*)buf)++, adr+z); -+ map_write32 (map, *((__u32*)buf)++, adr+z); - } else if (cfi_buswidth_is_8()) { -- map->write64 (map, *((__u64*)buf)++, adr+z); -+ map_write64 (map, *((__u64*)buf)++, adr+z); -+ } else { -+ ret = -EINVAL; -+ goto out; -+ } -+ z += CFIDEV_BUSWIDTH; -+ } -+ if (bytes) { -+ int i = 0, n = 0; -+ u_char tmp_buf[8], *tmp_p = tmp_buf; -+ -+ while (bytes--) -+ tmp_buf[i++] = buf[n++]; -+ while (i < CFIDEV_BUSWIDTH) -+ tmp_buf[i++] = 0xff; -+ if (cfi_buswidth_is_2()) { -+ map_write16 (map, *((__u16*)tmp_p)++, adr+z); -+ } else if (cfi_buswidth_is_4()) { -+ map_write32 (map, *((__u32*)tmp_p)++, adr+z); -+ } else if (cfi_buswidth_is_8()) { -+ map_write64 (map, *((__u64*)tmp_p)++, adr+z); - } else { -- DISABLE_VPP(map); - ret = -EINVAL; - goto out; - } -@@ -1227,6 +1066,7 @@ - for (;;) { - if (chip->state != FL_WRITING) { - /* Someone's suspended the write. Sleep */ -+ DECLARE_WAITQUEUE(wait, current); - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock(chip->mutex); -@@ -1244,7 +1084,6 @@ - /* OK Still waiting */ - if (time_after(jiffies, timeo)) { - chip->state = FL_STATUS; -- DISABLE_VPP(map); - printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); - ret = -EIO; - goto out; -@@ -1266,6 +1105,7 @@ - - /* Done and happy. */ - chip->state = FL_STATUS; -+ - /* check for lock bit */ - if (status & CMD(0x02)) { - /* clear status */ -@@ -1273,26 +1113,10 @@ - /* put back into read status register mode */ - cfi_write(map, CMD(0x70), adr); - ret = -EROFS; -- goto out; - } -- out: -- if (suspended) { -- chip->state = chip->oldstate; -- /* What if one interleaved chip has finished and the -- other hasn't? The old code would leave the finished -- one in READY mode. That's bad, and caused -EROFS -- errors to be returned from do_erase_oneblock because -- that's the only bit it checked for at the time. -- As the state machine appears to explicitly allow -- sending the 0x70 (Read Status) command to an erasing -- chip and expecting it to be ignored, that's what we -- do. */ -- cfi_write(map, CMD(0xd0), adr); -- cfi_write(map, CMD(0x70), adr); -- } else -- DISABLE_VPP(map); /* must not clear the VPP if there is a suspended erase to be resumed */ - -- wake_up(&chip->wq); -+ out: -+ put_chip(map, chip, cmd_adr); - spin_unlock(chip->mutex); - return ret; - } -@@ -1336,12 +1160,12 @@ - } - - /* Write buffer is worth it only if more than one word to write... */ -- while(len > CFIDEV_BUSWIDTH) { -+ while(len) { - /* We must not cross write block boundaries */ - int size = wbufsize - (ofs & (wbufsize-1)); - - if (size > len) -- size = len & ~(CFIDEV_BUSWIDTH-1); -+ size = len; - ret = do_write_buffer(map, &cfi->chips[chipnum], - ofs, buf, size); - if (ret) -@@ -1359,17 +1183,6 @@ - return 0; - } - } -- -- /* ... and write the remaining bytes */ -- if (len > 0) { -- size_t local_retlen; -- ret = cfi_intelext_write_words(mtd, ofs + (chipnum << cfi->chipshift), -- len, &local_retlen, buf); -- if (ret) -- return ret; -- (*retlen) += local_retlen; -- } -- - return 0; - } - -@@ -1479,45 +1292,12 @@ - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - -- timeo = jiffies + HZ; --retry: -+ retry: - spin_lock(chip->mutex); -- -- /* Check that the chip's ready to talk to us. */ -- switch (chip->state) { -- case FL_CFI_QUERY: -- case FL_JEDEC_QUERY: -- case FL_READY: -- cfi_write(map, CMD(0x70), adr); -- chip->state = FL_STATUS; -- -- case FL_STATUS: -- status = cfi_read(map, adr); -- if ((status & status_OK) == status_OK) -- break; -- -- /* Urgh. Chip not yet ready to talk to us. */ -- if (time_after(jiffies, timeo)) { -- spin_unlock(chip->mutex); -- printk(KERN_ERR "waiting for chip to be ready timed out in erase\n"); -- return -EIO; -- } -- -- /* Latency issues. Drop the lock, wait a while and retry */ -- spin_unlock(chip->mutex); -- cfi_udelay(1); -- goto retry; -- -- default: -- /* Stick ourselves on a wait queue to be woken when -- someone changes the status */ -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -+ ret = get_chip(map, chip, adr, FL_ERASING); -+ if (ret) { - spin_unlock(chip->mutex); -- schedule(); -- remove_wait_queue(&chip->wq, &wait); -- timeo = jiffies + HZ; -- goto retry; -+ return ret; - } - - ENABLE_VPP(map); -@@ -1528,7 +1308,7 @@ - cfi_write(map, CMD(0x20), adr); - cfi_write(map, CMD(0xD0), adr); - chip->state = FL_ERASING; -- chip->oldstate = 0; -+ chip->erase_suspended = 0; - - spin_unlock(chip->mutex); - set_current_state(TASK_UNINTERRUPTIBLE); -@@ -1550,11 +1330,11 @@ - spin_lock(chip->mutex); - continue; - } -- if (chip->oldstate) { -+ if (chip->erase_suspended) { - /* This erase was suspended and resumed. - Adjust the timeout */ - timeo = jiffies + (HZ*20); /* FIXME */ -- chip->oldstate = 0; -+ chip->erase_suspended = 0; - } - - status = cfi_read(map, adr); -@@ -1658,39 +1438,22 @@ - int i; - struct flchip *chip; - int ret = 0; -- DECLARE_WAITQUEUE(wait, current); - - for (i=0; !ret && i<cfi->numchips; i++) { - chip = &cfi->chips[i]; - -- retry: - spin_lock(chip->mutex); -+ ret = get_chip(map, chip, chip->start, FL_SYNCING); - -- switch(chip->state) { -- case FL_READY: -- case FL_STATUS: -- case FL_CFI_QUERY: -- case FL_JEDEC_QUERY: -+ if (!ret) { - chip->oldstate = chip->state; - chip->state = FL_SYNCING; - /* No need to wake_up() on this state change - - * as the whole point is that nobody can do anything - * with the chip now anyway. - */ -- case FL_SYNCING: -- spin_unlock(chip->mutex); -- break; -- -- default: -- /* Not an idle state */ -- add_wait_queue(&chip->wq, &wait); -- -- spin_unlock(chip->mutex); -- schedule(); -- remove_wait_queue(&chip->wq, &wait); -- -- goto retry; - } -+ spin_unlock(chip->mutex); - } - - /* Unlock the chips again */ -@@ -1731,52 +1494,18 @@ - struct cfi_private *cfi = map->fldrv_priv; - cfi_word status, status_OK; - unsigned long timeo = jiffies + HZ; -- DECLARE_WAITQUEUE(wait, current); -+ int ret; - - adr += chip->start; - - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - -- timeo = jiffies + HZ; --retry: - spin_lock(chip->mutex); -- -- /* Check that the chip's ready to talk to us. */ -- switch (chip->state) { -- case FL_CFI_QUERY: -- case FL_JEDEC_QUERY: -- case FL_READY: -- cfi_write(map, CMD(0x70), adr); -- chip->state = FL_STATUS; -- -- case FL_STATUS: -- status = cfi_read(map, adr); -- if ((status & status_OK) == status_OK) -- break; -- -- /* Urgh. Chip not yet ready to talk to us. */ -- if (time_after(jiffies, timeo)) { -- spin_unlock(chip->mutex); -- printk(KERN_ERR "%s: waiting for chip to be ready timed out\n", __FUNCTION__); -- return -EIO; -- } -- -- /* Latency issues. Drop the lock, wait a while and retry */ -- spin_unlock(chip->mutex); -- cfi_udelay(1); -- goto retry; -- -- default: -- /* Stick ourselves on a wait queue to be woken when -- someone changes the status */ -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -+ ret = get_chip(map, chip, adr, FL_LOCKING); -+ if (ret) { - spin_unlock(chip->mutex); -- schedule(); -- remove_wait_queue(&chip->wq, &wait); -- timeo = jiffies + HZ; -- goto retry; -+ return ret; - } - - ENABLE_VPP(map); -@@ -1823,8 +1552,7 @@ - - /* Done and happy. */ - chip->state = FL_STATUS; -- DISABLE_VPP(map); -- wake_up(&chip->wq); -+ put_chip(map, chip, adr); - spin_unlock(chip->mutex); - return 0; - } -@@ -1889,22 +1617,23 @@ - - spin_lock(chip->mutex); - -- switch(chip->state) { -+ switch (chip->state) { - case FL_READY: - case FL_STATUS: - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: -+ if (chip->oldstate == FL_READY) { - chip->oldstate = chip->state; - chip->state = FL_PM_SUSPENDED; - /* No need to wake_up() on this state change - - * as the whole point is that nobody can do anything - * with the chip now anyway. - */ -- case FL_PM_SUSPENDED: -+ } - break; -- - default: - ret = -EAGAIN; -+ case FL_PM_SUSPENDED: - break; - } - spin_unlock(chip->mutex); -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0002.c linux/drivers/mtd/chips/cfi_cmdset_0002.c ---- linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0002.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/cfi_cmdset_0002.c 2004-11-19 10:25:11.745223200 +0100 -@@ -6,16 +6,22 @@ - * - * 2_by_8 routines added by Simon Munton - * -+ * 4_by_16 work by Carolyn J. Smith -+ * -+ * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com -+ * - * This code is GPL - * -- * $Id$ -+ * $Id$ - * - */ - -+#include <linux/config.h> - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> - #include <linux/sched.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <asm/byteorder.h> - -@@ -23,16 +29,50 @@ - #include <linux/slab.h> - #include <linux/delay.h> - #include <linux/interrupt.h> -+#include <linux/mtd/compatmac.h> - #include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> - #include <linux/mtd/cfi.h> - - #define AMD_BOOTLOC_BUG -+#define FORCE_WORD_WRITE 0 -+ -+ -+/* -+ * This is an attempt to coalesce the retry logic in one place - that way -+ * there aren't #ifdefs scattered throughout. -+ */ -+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY -+ -+#ifndef CONFIG_MTD_CFI_AMDSTD_RETRY_MAX -+#define CONFIG_MTD_CFI_AMDSTD_RETRY_MAX 0 -+#endif -+ -+#define RETRY_CMD_LABEL retry_cmd: do {} while (0) -+#define HANDLE_WACKY_STATE() handle_wacky_state(__func__, retry_cmd_cnt, adr, datum, prev_oldstatus, prev_status, oldstatus, status) -+static int retry_cmd_max = CONFIG_MTD_CFI_AMDSTD_RETRY_MAX; -+#define DECLARE_RETRY_CMD_CNT() int retry_cmd_cnt = 0 -+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY -+#define CHECK_RETRIES() do { if (++retry_cmd_cnt <= retry_cmd_max) goto retry_cmd; } while (0) -+#endif -+ -+#else -+ -+#define RETRY_CMD_LABEL do {} while (0) -+#define HANDLE_WACKY_STATE() handle_wacky_state(__func__, adr, datum, prev_oldstatus, prev_status, oldstatus, status) -+#define DECLARE_RETRY_CMD_CNT() -+#define CHECK_RETRIES() -+ -+#endif /* !defined(CONFIG_MTD_CFI_AMDSTD_RETRY) */ -+ - - static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); --static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -+static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -+static int cfi_amdstd_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); - static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *); --static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *); - static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); -+static int cfi_amdstd_lock_varsize(struct mtd_info *, loff_t, size_t); -+static int cfi_amdstd_unlock_varsize(struct mtd_info *, loff_t, size_t); - static void cfi_amdstd_sync (struct mtd_info *); - static int cfi_amdstd_suspend (struct mtd_info *); - static void cfi_amdstd_resume (struct mtd_info *); -@@ -45,55 +85,136 @@ - - - static struct mtd_chip_driver cfi_amdstd_chipdrv = { -- probe: NULL, /* Not usable directly */ -- destroy: cfi_amdstd_destroy, -- name: "cfi_cmdset_0002", -- module: THIS_MODULE -+ .probe = NULL, /* Not usable directly */ -+ .destroy = cfi_amdstd_destroy, -+ .name = "cfi_cmdset_0002", -+ .module = THIS_MODULE - }; - --struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) -+ -+/* #define DEBUG_LOCK_BITS */ -+/* #define DEBUG_CFI_FEATURES */ -+ -+ -+#ifdef DEBUG_CFI_FEATURES -+static void cfi_tell_features(struct cfi_pri_amdstd *extp) - { -- struct cfi_private *cfi = map->fldrv_priv; -- unsigned char bootloc; -- int ofs_factor = cfi->interleave * cfi->device_type; -- int i; -- __u8 major, minor; -- __u32 base = cfi->chips[0].start; -+ const char* erase_suspend[3] = { -+ "Not supported", "Read only", "Read/write" -+ }; -+ const char* top_bottom[6] = { -+ "No WP", "8x8KiB sectors at top & bottom, no WP", -+ "Bottom boot", "Top boot", -+ "Uniform, Bottom WP", "Uniform, Top WP" -+ }; -+ -+ printk(" Silicon revision: %d\n", extp->SiliconRevision >> 1); -+ printk(" Address sensitive unlock: %s\n", -+ (extp->SiliconRevision & 1) ? "Not required" : "Required"); - -- if (cfi->cfi_mode==CFI_MODE_CFI){ -- __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; -+ if (extp->EraseSuspend < ARRAY_SIZE(erase_suspend)) -+ printk(" Erase Suspend: %s\n", erase_suspend[extp->EraseSuspend]); -+ else -+ printk(" Erase Suspend: Unknown value %d\n", extp->EraseSuspend); - -- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); -+ if (extp->BlkProt == 0) -+ printk(" Block protection: Not supported\n"); -+ else -+ printk(" Block protection: %d sectors per group\n", extp->BlkProt); -+ -+ -+ printk(" Temporary block unprotect: %s\n", -+ extp->TmpBlkUnprotect ? "Supported" : "Not supported"); -+ printk(" Block protect/unprotect scheme: %d\n", extp->BlkProtUnprot); -+ printk(" Number of simultaneous operations: %d\n", extp->SimultaneousOps); -+ printk(" Burst mode: %s\n", -+ extp->BurstMode ? "Supported" : "Not supported"); -+ if (extp->PageMode == 0) -+ printk(" Page mode: Not supported\n"); -+ else -+ printk(" Page mode: %d word page\n", extp->PageMode << 2); - -- major = cfi_read_query(map, base + (adr+3)*ofs_factor); -- minor = cfi_read_query(map, base + (adr+4)*ofs_factor); -+ printk(" Vpp Supply Minimum Program/Erase Voltage: %d.%d V\n", -+ extp->VppMin >> 4, extp->VppMin & 0xf); -+ printk(" Vpp Supply Maximum Program/Erase Voltage: %d.%d V\n", -+ extp->VppMax >> 4, extp->VppMax & 0xf); - -- printk(KERN_NOTICE " Amd/Fujitsu Extended Query Table v%c.%c at 0x%4.4X\n", -- major, minor, adr); -- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL); -- -- cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL); -- cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); -- cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); -- cfi->mfr = cfi_read_query(map, base); -- cfi->id = cfi_read_query(map, base + ofs_factor); -+ if (extp->TopBottom < ARRAY_SIZE(top_bottom)) -+ printk(" Top/Bottom Boot Block: %s\n", top_bottom[extp->TopBottom]); -+ else -+ printk(" Top/Bottom Boot Block: Unknown value %d\n", extp->TopBottom); -+} -+#endif - -- /* Wheee. Bring me the head of someone at AMD. */ - #ifdef AMD_BOOTLOC_BUG -+/* Wheee. Bring me the head of someone at AMD. */ -+static void fixup_amd_bootblock(struct map_info *map, void* param) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv; -+ __u8 major = extp->MajorVersion; -+ __u8 minor = extp->MinorVersion; -+ - if (((major << 8) | minor) < 0x3131) { - /* CFI version 1.0 => don't trust bootloc */ - if (cfi->id & 0x80) { - printk(KERN_WARNING "%s: JEDEC Device ID is 0x%02X. Assuming broken CFI table.\n", map->name, cfi->id); -- bootloc = 3; /* top boot */ -+ extp->TopBottom = 3; /* top boot */ - } else { -- bootloc = 2; /* bottom boot */ -+ extp->TopBottom = 2; /* bottom boot */ - } -- } else -+ } -+} - #endif -+ -+static struct cfi_fixup fixup_table[] = { -+#ifdef AMD_BOOTLOC_BUG - { -- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); -- bootloc = cfi_read_query(map, base + (adr+15)*ofs_factor); -+ 0x0001, /* AMD */ -+ CFI_ID_ANY, -+ fixup_amd_bootblock, NULL -+ }, -+#endif -+ { 0, 0, NULL, NULL } -+}; -+ -+ -+struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ unsigned char bootloc; -+ int i; -+ -+ if (cfi->cfi_mode==CFI_MODE_CFI){ -+ /* -+ * It's a real CFI chip, not one for which the probe -+ * routine faked a CFI structure. So we read the feature -+ * table from it. -+ */ -+ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; -+ struct cfi_pri_amdstd *extp; -+ -+ extp = (struct cfi_pri_amdstd*)cfi_read_pri(map, adr, sizeof(*extp), "Amd/Fujitsu"); -+ if (!extp) -+ return NULL; -+ -+ /* Install our own private info structure */ -+ cfi->cmdset_priv = extp; -+ -+ cfi_fixup(map, fixup_table); -+ -+#ifdef DEBUG_CFI_FEATURES -+ /* Tell the user about it in lots of lovely detail */ -+ cfi_tell_features(extp); -+#endif -+ -+ bootloc = extp->TopBottom; -+ if ((bootloc != 2) && (bootloc != 3)) { -+ printk(KERN_WARNING "%s: CFI does not contain boot " -+ "bank location. Assuming top.\n", map->name); -+ bootloc = 2; - } -+ - if (bootloc == 3 && cfi->cfiq->NumEraseRegions > 1) { - printk(KERN_WARNING "%s: Swapping erase regions for broken CFI table.\n", map->name); - -@@ -106,6 +227,11 @@ - cfi->cfiq->EraseRegionInfo[j] = swap; - } - } -+ /* -+ * These might already be setup (more correctly) by -+ * jedec_probe.c - still need it for cfi_probe.c path. -+ */ -+ if ( ! (cfi->addr_unlock1 && cfi->addr_unlock2) ) { - switch (cfi->device_type) { - case CFI_DEVICETYPE_X8: - cfi->addr_unlock1 = 0x555; -@@ -125,9 +251,13 @@ - cfi->addr_unlock2 = 0xaaa; - break; - default: -- printk(KERN_NOTICE "Eep. Unknown cfi_cmdset_0002 device type %d\n", cfi->device_type); -+ printk(KERN_WARNING -+ "MTD %s(): Unsupported device type %d\n", -+ __func__, cfi->device_type); - return NULL; - } -+ } -+ - } /* CFI mode */ - - for (i=0; i< cfi->numchips; i++) { -@@ -138,15 +268,17 @@ - - map->fldrv = &cfi_amdstd_chipdrv; - -- cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL); - return cfi_amdstd_setup(map); - } - -+ - static struct mtd_info *cfi_amdstd_setup(struct map_info *map) - { - struct cfi_private *cfi = map->fldrv_priv; - struct mtd_info *mtd; - unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave; -+ unsigned long offset = 0; -+ int i,j; - - mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); - printk(KERN_NOTICE "number of %s chips: %d\n", -@@ -163,15 +295,9 @@ - /* Also select the correct geometry setup too */ - mtd->size = devsize * cfi->numchips; - -- if (cfi->cfiq->NumEraseRegions == 1) { -- /* No need to muck about with multiple erase sizes */ -- mtd->erasesize = ((cfi->cfiq->EraseRegionInfo[0] >> 8) & ~0xff) * cfi->interleave; -- } else { -- unsigned long offset = 0; -- int i,j; -- - mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; -- mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); -+ mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) -+ * mtd->numeraseregions, GFP_KERNEL); - if (!mtd->eraseregions) { - printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); - goto setup_err; -@@ -206,39 +332,52 @@ - mtd->eraseregions[i].numblocks); - } - #endif -- } - - switch (CFIDEV_BUSWIDTH) - { - case 1: - case 2: - case 4: --#if 1 -- if (mtd->numeraseregions > 1) -- mtd->erase = cfi_amdstd_erase_varsize; -- else -+#ifdef CFI_WORD_64 -+ case 8: - #endif -- if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) -+ if (mtd->numeraseregions == 1 -+ && ((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) { - mtd->erase = cfi_amdstd_erase_chip; -- else -- mtd->erase = cfi_amdstd_erase_onesize; -+ } else { -+ mtd->erase = cfi_amdstd_erase_varsize; -+ mtd->lock = cfi_amdstd_lock_varsize; -+ mtd->unlock = cfi_amdstd_unlock_varsize; -+ } -+ -+ if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) { -+ DEBUG(MTD_DEBUG_LEVEL1, "Using buffer write method\n" ); -+ mtd->write = cfi_amdstd_write_buffers; -+ } else { -+ DEBUG(MTD_DEBUG_LEVEL1, "Using word write method\n" ); -+ mtd->write = cfi_amdstd_write_words; -+ } -+ - mtd->read = cfi_amdstd_read; -- mtd->write = cfi_amdstd_write; - break; - - default: -- printk(KERN_WARNING "Unsupported buswidth\n"); -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); - goto setup_err; - break; - } - if (cfi->fast_prog) { -- /* In cfi_amdstd_write() we frob the protection stuff -+ /* In cfi_amdstd_write_words() we frob the protection stuff - without paying any attention to the state machine. - This upsets in-progress erases. So we turn this flag - off for now till the code gets fixed. */ - printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n"); - cfi->fast_prog = 0; - } -+ /* FIXME: erase-suspend-program is broken. See -+ http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */ -+ printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n"); - - - /* does this chip have a secsi area? */ -@@ -266,7 +405,7 @@ - mtd->flags = MTD_CAP_NORFLASH; - map->fldrv = &cfi_amdstd_chipdrv; - mtd->name = map->name; -- MOD_INC_USE_COUNT; -+ __module_get(THIS_MODULE); - return mtd; - - setup_err: -@@ -280,46 +419,210 @@ - return NULL; - } - --static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) -+ -+/* This is more work to coalesce the retry #ifdefs in one location */ -+static inline void handle_wacky_state(const char *func, -+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY -+ int retry_cmd_cnt, -+#endif -+ unsigned long adr, -+ cfi_word datum, -+ cfi_word prev_oldstatus, -+ cfi_word prev_status, -+ cfi_word oldstatus, -+ cfi_word status) -+{ -+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY -+ if ( retry_cmd_cnt == retry_cmd_max ) { -+#endif -+ printk(KERN_WARNING -+ "MTD %s(): Wacky! Unable to decode failure status\n" -+ "Possible buggy device - try " -+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY -+ "increasing retry_cmd_max from %d\n" -+#else -+ "enabling CONFIG_MTD_CFI_AMDSTD_RETRY\n" -+ "in your kernel config and setting driver retry_cmd_max\n" -+#endif -+ , func -+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY -+ , retry_cmd_max -+#endif -+ ); -+ -+ printk(KERN_WARNING -+ "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", -+ func, adr, datum, -+ prev_oldstatus, prev_status, -+ oldstatus, status); -+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY -+ } -+#endif -+} -+ -+ -+static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) - { - DECLARE_WAITQUEUE(wait, current); -- unsigned long timeo = jiffies + HZ; -+ struct cfi_private *cfi = map->fldrv_priv; -+ cfi_word status, oldstatus; -+ cfi_word dq6 = CMD(1<<6); -+ cfi_word dq2 = CMD(1<<2); -+ unsigned long timeo; -+ struct cfi_pri_amdstd *cfip = (struct cfi_pri_amdstd *)cfi->cmdset_priv; - -+ resettime: -+ timeo = jiffies + HZ; - retry: -+ switch (chip->state) { -+ -+ case FL_STATUS: -+ for (;;) { -+ oldstatus = cfi_read(map, adr); -+ status = cfi_read(map, adr); -+ if (((oldstatus ^ status) & (dq6 | dq2)) == 0) -+ break; -+ -+ if (time_after(jiffies, timeo)) { -+ printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n", -+ (long long)status); -+ cfi_spin_unlock(chip->mutex); -+ return -EIO; -+ } -+ cfi_spin_unlock(chip->mutex); -+ cfi_udelay(1); - cfi_spin_lock(chip->mutex); -+ /* Someone else might have been playing with it. */ -+ goto retry; -+ } - -- if (chip->state != FL_READY){ --#if 0 -- printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state); --#endif -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -+ case FL_READY: -+ case FL_CFI_QUERY: -+ case FL_JEDEC_QUERY: -+ return 0; -+ -+ case FL_ERASING: -+ if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */ -+ goto sleep; -+ -+ if (!(mode == FL_READY || mode == FL_POINT -+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x2)) -+ || (mode == FL_WRITING && (cfip->EraseSuspend & 0x1)))) -+ goto sleep; -+ -+ oldstatus = cfi_read(map, adr); -+ status = cfi_read(map, adr); -+ if ((oldstatus ^ status) & dq2) { -+ printk(KERN_ERR "Can't suspend erase -- block in progress\n"); -+ goto sleep; -+ } -+ -+ /* Erase suspend */ -+ /* FIXME - is there a way to verify suspend? */ -+ cfi_write(map, CMD(0xB0), chip->in_progress_block_addr); -+ chip->oldstate = FL_ERASING; -+ chip->state = FL_ERASE_SUSPENDING; -+ chip->erase_suspended = 1; -+ for (;;) { -+ oldstatus = cfi_read(map, chip->in_progress_block_addr); -+ status = cfi_read(map, chip->in_progress_block_addr); -+ if (((oldstatus ^ status) & dq6) == 0) -+ break; -+ -+ if (time_after(jiffies, timeo)) { -+ /* Urgh. Resume and pretend we weren't here. */ -+ /* FIXME - is there a way to verify resume? */ -+ cfi_write(map, CMD(0x30), chip->in_progress_block_addr); -+ chip->state = FL_ERASING; -+ chip->oldstate = FL_READY; -+ printk(KERN_ERR "Chip not ready after erase " -+ "suspended: status = 0x%x\n", status); -+ return -EIO; -+ } - - cfi_spin_unlock(chip->mutex); -+ cfi_udelay(1); -+ cfi_spin_lock(chip->mutex); -+ /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING. -+ So we can just loop here. */ -+ } -+ chip->state = FL_READY; -+ return 0; -+ -+ case FL_POINT: -+ /* Only if there's no operation suspended... */ -+ if (mode == FL_READY && chip->oldstate == FL_READY) -+ return 0; - -+ default: -+ sleep: -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ add_wait_queue(&chip->wq, &wait); -+ cfi_spin_unlock(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); --#if 0 -- if(signal_pending(current)) -- return -EINTR; --#endif -- timeo = jiffies + HZ; -+ cfi_spin_lock(chip->mutex); -+ goto resettime; -+ } -+} - -- goto retry; -+ -+static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ -+ switch(chip->oldstate) { -+ case FL_ERASING: -+ chip->state = chip->oldstate; -+ cfi_write(map, CMD(0x30), chip->in_progress_block_addr); -+ chip->oldstate = FL_READY; -+ chip->state = FL_ERASING; -+ break; -+ -+ case FL_READY: -+ case FL_STATUS: -+ /* We should really make set_vpp() count, rather than doing this */ -+ DISABLE_VPP(map); -+ break; -+ default: -+ printk(KERN_ERR "MTD: put_chip() called with oldstate %d!!\n", chip->oldstate); - } -+ wake_up(&chip->wq); -+} -+ -+ -+static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) -+{ -+ unsigned long cmd_addr; -+ struct cfi_private *cfi = map->fldrv_priv; -+ int ret; - - adr += chip->start; - -+ /* Ensure cmd read/writes are aligned. */ -+ cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); -+ -+ cfi_spin_lock(chip->mutex); -+ ret = get_chip(map, chip, cmd_addr, FL_READY); -+ if (ret) { -+ cfi_spin_unlock(chip->mutex); -+ return ret; -+ } -+ -+ if (chip->state != FL_POINT && chip->state != FL_READY) { -+ cfi_write(map, CMD(0xf0), cmd_addr); - chip->state = FL_READY; -+ } - -- map->copy_from(map, buf, adr, len); -+ map_copy_from(map, buf, adr, len); - -- wake_up(&chip->wq); -- cfi_spin_unlock(chip->mutex); -+ put_chip(map, chip, cmd_addr); - -+ cfi_spin_unlock(chip->mutex); - return 0; - } - -+ - static int cfi_amdstd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) - { - struct map_info *map = mtd->priv; -@@ -361,6 +664,7 @@ - return ret; - } - -+ - static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) - { - DECLARE_WAITQUEUE(wait, current); -@@ -394,12 +698,14 @@ - - chip->state = FL_READY; - -+ /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */ - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - -- map->copy_from(map, buf, adr, len); -+ map_copy_from(map, buf, adr, len); - -+ /* should these be CFI_DEVICETYPE_X8 instead of cfi->device_type? */ - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); - cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); -@@ -454,125 +760,241 @@ - return ret; - } - --static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast) -+ -+static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum, int fast) - { -- unsigned long timeo = jiffies + HZ; -- unsigned int oldstatus, status; -- unsigned int dq6, dq5; - struct cfi_private *cfi = map->fldrv_priv; -- DECLARE_WAITQUEUE(wait, current); -+ unsigned long timeo = jiffies + HZ; -+ cfi_word oldstatus, status, prev_oldstatus, prev_status; -+ cfi_word dq6 = CMD(1<<6); -+ /* -+ * We use a 1ms + 1 jiffies generic timeout for writes (most devices -+ * have a max write time of a few hundreds usec). However, we should -+ * use the maximum timeout value given by the chip at probe time -+ * instead. Unfortunately, struct flchip does have a field for -+ * maximum timeout, only for typical which can be far too short -+ * depending of the conditions. The ' + 1' is to avoid having a -+ * timeout of 0 jiffies if HZ is smaller than 1000. -+ */ -+ unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; - int ret = 0; -+ int ta = 0; -+ DECLARE_RETRY_CMD_CNT(); - -- retry: -- cfi_spin_lock(chip->mutex); -- -- if (chip->state != FL_READY) { --#if 0 -- printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state); --#endif -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -+ adr += chip->start; - -+ cfi_spin_lock(chip->mutex); -+ ret = get_chip(map, chip, adr, FL_WRITING); -+ if (ret) { - cfi_spin_unlock(chip->mutex); -- -- schedule(); -- remove_wait_queue(&chip->wq, &wait); --#if 0 -- printk(KERN_DEBUG "Wake up to write:\n"); -- if(signal_pending(current)) -- return -EINTR; --#endif -- timeo = jiffies + HZ; -- -- goto retry; -+ return ret; - } - -- chip->state = FL_WRITING; -+ RETRY_CMD_LABEL; -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n", -+ __func__, adr, datum ); -+ -+ /* -+ * Check for a NOP for the case when the datum to write is already -+ * present - it saves time and works around buggy chips that corrupt -+ * data at other locations when 0xff is written to a location that -+ * already contains 0xff. -+ */ -+ status = cfi_read(map, adr); -+ if (status == datum) { -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): NOP 0x%.8x == 0x%.8x\n", -+ __func__, status, datum ); -+ goto op_done; -+ } - -- adr += chip->start; - ENABLE_VPP(map); - if (fast) { /* Unlock bypass */ - cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL); -- } -- else { -+ } else { -+ /* -+ * The CFI_DEVICETYPE_X8 argument is needed even when -+ * cfi->device_type != CFI_DEVICETYPE_X8. The addresses for -+ * command sequences don't scale even when the device is -+ * wider. This is the case for many of the cfi_send_gen_cmd() -+ * below. I'm not sure, however, why some use -+ * cfi->device_type. -+ */ - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - } -- - cfi_write(map, datum, adr); -+ chip->state = FL_WRITING; - - cfi_spin_unlock(chip->mutex); - cfi_udelay(chip->word_write_time); - cfi_spin_lock(chip->mutex); - -- /* Polling toggle bits instead of reading back many times -- This ensures that write operation is really completed, -- or tells us why it failed. */ -- dq6 = CMD(1<<6); -- dq5 = CMD(1<<5); -- timeo = jiffies + (HZ/1000); /* setting timeout to 1ms for now */ -+ /* -+ * Polling toggle bits instead of reading back many times This ensures -+ * that write operation is really completed, or tells us why it -+ * failed. -+ * -+ * It may appear that the polling and decoding of error state might be -+ * simplified. Don't do it unless you really know what you are doing. -+ * -+ * You must remember that JESD21-C 3.5.3 states that the status must -+ * be read back an _additional_ two times before a failure is -+ * determined. This is because these devices have internal state -+ * machines that are asynchronous to the external data bus. During an -+ * erase or write the read-back status of the polling bits might be -+ * transitioning internaly when the external read-back occurs. This -+ * means that the bits aren't in the final state and they might appear -+ * to report an error as they are in a transient state: dq7 is -+ * asynchronous with dq6 and other status bits. -+ * -+ * This asynchronous behaviour can cause infrequent errors that will -+ * usually disappear the next time an erase or write happens (Try -+ * tracking those errors down!). To ensure that the bits are not in -+ * transition, the location must be read-back two more times and -+ * compared against what was written - BOTH reads MUST match what was -+ * written. Don't think this can be simplified to only the last read -+ * matching the datum written: status bits *can* match the datum -+ * written. -+ * -+ * If the final comparison fails, error state can *then* be decoded. -+ * -+ * - Thayne Harbaugh -+ */ -+ /* See comment above for timeout value. */ -+ timeo = jiffies + uWriteTimeout; -+ for (;;) { -+ if (chip->state != FL_WRITING) { -+ /* Someone's suspended the write. Sleep */ -+ DECLARE_WAITQUEUE(wait, current); -+ -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ add_wait_queue(&chip->wq, &wait); -+ cfi_spin_unlock(chip->mutex); -+ schedule(); -+ remove_wait_queue(&chip->wq, &wait); -+ timeo = jiffies + (HZ / 2); /* FIXME */ -+ cfi_spin_lock(chip->mutex); -+ continue; -+ } - - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", -+ __func__, oldstatus, status ); - -- while( (status & dq6) != (oldstatus & dq6) && -- (status & dq5) != dq5 && -- !time_after(jiffies, timeo) ) { -+ /* -+ * This only checks if dq6 is still toggling and that our -+ * timer hasn't expired. We purposefully ignore the chip's -+ * internal timer that will assert dq5 and leave dq6 toggling. -+ * This is done for a variety of reasons: -+ * -+ * 1) Not all chips support dq5. -+ * -+ * 2) Dealing with asynchronous status bit and data updates -+ * and reading a device two more times creates _messy_ logic -+ * when trying to deal with interleaved devices - some may be -+ * changing while others are still busy. -+ * -+ * 3) Checking dq5 only helps to optimize an error case that -+ * should at worst be infrequent and at best non-existent. -+ * -+ * If our timeout occurs _then_ we will check dq5 to see if -+ * the device also had an internal timeout. -+ */ -+ if ( (((status ^ oldstatus) & dq6) == 0) -+ || ( ta = time_after(jiffies, timeo)) ) -+ break; - -- if (need_resched()) { -+ /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); -- yield(); -+ cfi_udelay(1); - cfi_spin_lock(chip->mutex); -- } else -- udelay(1); -- -- oldstatus = cfi_read( map, adr ); -- status = cfi_read( map, adr ); - } - -- if( (status & dq6) != (oldstatus & dq6) ) { -- /* The erasing didn't stop?? */ -- if( (status & dq5) == dq5 ) { -- /* When DQ5 raises, we must check once again -- if DQ6 is toggling. If not, the erase has been -- completed OK. If not, reset chip. */ -+ /* -+ * Something kicked us out of the read-back loop. We'll check success -+ * befor checking failure. Even though dq6 might be true data, it is -+ * unkown if all of the other bits have changed to true data due to -+ * the asynchronous nature of the internal state machine. We will -+ * read two more times and use this to either verify that the write -+ * completed successfully or that something really went wrong. BOTH -+ * reads must match what was written - this certifies that bits aren't -+ * still changing and that the status bits erroneously match the datum -+ * that was written. -+ */ -+ prev_oldstatus = oldstatus; -+ prev_status = status; - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", -+ __func__, oldstatus, status ); - -- if ( (oldstatus & 0x00FF) == (status & 0x00FF) ) { -- printk(KERN_WARNING "Warning: DQ5 raised while program operation was in progress, however operation completed OK\n" ); -+ if ( oldstatus == datum && status == datum ) { -+ /* success - do nothing */ -+ goto op_done; -+ } -+ -+ if ( ta ) { -+ /* Only check dq5 on the chips that are still toggling. */ -+ cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; -+ if ( status & dq5mask ) { -+ /* dq5 asserted - decode interleave chips */ -+ printk( KERN_WARNING -+ "MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n", -+ __func__, -+ status & dq5mask, status, datum ); - } else { -- /* DQ5 is active so we can do a reset and stop the erase */ -- cfi_write(map, CMD(0xF0), chip->start); -- printk(KERN_WARNING "Internal flash device timeout occurred or write operation was performed while flash was programming.\n" ); -+ printk( KERN_WARNING -+ "MTD %s(): Software timed out during write.\n", -+ __func__ ); -+ } -+ goto op_failed; - } -- } else { -- printk(KERN_WARNING "Waiting for write to complete timed out in do_write_oneword."); - -+ /* -+ * If we get to here then it means that something -+ * is wrong and it's not a timeout. Something -+ * is seriously wacky! Dump some debug info. -+ */ -+ /* -+ * Found a clue about the chips that reach this state. -+ * Some flash chips (SST >cough<) -+ * are horribly broken. They do not ignore traffic that is -+ * destined to other devices. This happens because some solutions -+ * are on shared busses, the erase and program sequences have -+ * have multiple commands, and the sequence is interspersed with -+ * commands destined to other devices. A good flash chip will -+ * examine the command and destination address and will ignore -+ * commands that are for other devices. -+ */ -+ HANDLE_WACKY_STATE(); -+ -+ op_failed: -+ /* reset on all failures. */ -+ cfi_write( map, CMD(0xF0), chip->start ); -+ /* FIXME - should have reset delay before continuing */ -+ CHECK_RETRIES(); -+ ret = -EIO; -+ -+ op_done: - chip->state = FL_READY; -- wake_up(&chip->wq); -- cfi_spin_unlock(chip->mutex); -- DISABLE_VPP(map); -- ret = -EIO; -- } -- } -- -- DISABLE_VPP(map); -- chip->state = FL_READY; -- wake_up(&chip->wq); -+ put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); - - return ret; - } - --static int cfi_amdstd_write (struct mtd_info *mtd, loff_t to , size_t len, size_t *retlen, const u_char *buf) -+ -+static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) - { - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - int ret = 0; - int chipnum; - unsigned long ofs, chipstart; -+ DECLARE_WAITQUEUE(wait, current); - - *retlen = 0; - if (!len) -@@ -587,19 +1009,52 @@ - unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1); - int i = ofs - bus_ofs; - int n = 0; -- u_char tmp_buf[4]; -- __u32 datum; -+ u_char tmp_buf[8]; -+ cfi_word datum; -+ -+ retry: -+ cfi_spin_lock(cfi->chips[chipnum].mutex); -+ -+ if (cfi->chips[chipnum].state != FL_READY) { -+#if 0 -+ printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state); -+#endif -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ add_wait_queue(&cfi->chips[chipnum].wq, &wait); -+ -+ cfi_spin_unlock(cfi->chips[chipnum].mutex); -+ -+ schedule(); -+ remove_wait_queue(&cfi->chips[chipnum].wq, &wait); -+#if 0 -+ if(signal_pending(current)) -+ return -EINTR; -+#endif -+ goto retry; -+ } -+ -+ map_copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); - -- map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); -- while (len && i < CFIDEV_BUSWIDTH) -- tmp_buf[i++] = buf[n++], len--; -+ cfi_spin_unlock(cfi->chips[chipnum].mutex); -+ -+ while (len && i < CFIDEV_BUSWIDTH) { -+ tmp_buf[i++] = buf[n++]; -+ len--; -+ } - -+ /* already know that buswidth > 1 */ - if (cfi_buswidth_is_2()) { - datum = *(__u16*)tmp_buf; - } else if (cfi_buswidth_is_4()) { - datum = *(__u32*)tmp_buf; -+#ifdef CFI_WORD_64 -+ } else if (cfi_buswidth_is_8()) { -+ datum = *(__u64*)tmp_buf; -+#endif - } else { -- return -EINVAL; /* should never happen, but be safe */ -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); -+ return -EINVAL; - } - - ret = do_write_oneword(map, &cfi->chips[chipnum], -@@ -628,7 +1083,7 @@ - - /* We are now aligned, write as much as possible */ - while(len >= CFIDEV_BUSWIDTH) { -- __u32 datum; -+ cfi_word datum; - - if (cfi_buswidth_is_1()) { - datum = *(__u8*)buf; -@@ -636,7 +1091,13 @@ - datum = *(__u16*)buf; - } else if (cfi_buswidth_is_4()) { - datum = *(__u32*)buf; -+#ifdef CFI_WORD_64 -+ } else if (cfi_buswidth_is_8()) { -+ datum = *(__u64*)buf; -+#endif - } else { -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); - return -EINVAL; - } - ret = do_write_oneword(map, &cfi->chips[chipnum], -@@ -685,10 +1146,34 @@ - /* Write the trailing bytes if any */ - if (len & (CFIDEV_BUSWIDTH-1)) { - int i = 0, n = 0; -- u_char tmp_buf[4]; -- __u32 datum; -+ u_char tmp_buf[8]; -+ cfi_word datum; -+ -+ retry1: -+ cfi_spin_lock(cfi->chips[chipnum].mutex); -+ -+ if (cfi->chips[chipnum].state != FL_READY) { -+#if 0 -+ printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", cfi->chips[chipnum].state); -+#endif -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ add_wait_queue(&cfi->chips[chipnum].wq, &wait); -+ -+ cfi_spin_unlock(cfi->chips[chipnum].mutex); -+ -+ schedule(); -+ remove_wait_queue(&cfi->chips[chipnum].wq, &wait); -+#if 0 -+ if(signal_pending(current)) -+ return -EINTR; -+#endif -+ goto retry1; -+ } -+ -+ map_copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); -+ -+ cfi_spin_unlock(cfi->chips[chipnum].mutex); - -- map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); - while (len--) - tmp_buf[i++] = buf[n++]; - -@@ -696,8 +1181,14 @@ - datum = *(__u16*)tmp_buf; - } else if (cfi_buswidth_is_4()) { - datum = *(__u32*)tmp_buf; -+#ifdef CFI_WORD_64 -+ } else if (cfi_buswidth_is_8()) { -+ datum = *(__u64*)tmp_buf; -+#endif - } else { -- return -EINVAL; /* should never happen, but be safe */ -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); -+ return -EINVAL; - } - - ret = do_write_oneword(map, &cfi->chips[chipnum], -@@ -711,289 +1202,446 @@ - return 0; - } - --static inline int do_erase_chip(struct map_info *map, struct flchip *chip) -+ -+/* -+ * FIXME: interleaved mode not tested, and probably not supported! -+ */ -+static inline int do_write_buffer(struct map_info *map, struct flchip *chip, -+ unsigned long adr, const u_char *buf, int len) - { -- unsigned int oldstatus, status; -- unsigned int dq6, dq5; -- unsigned long timeo = jiffies + HZ; -- unsigned int adr; - struct cfi_private *cfi = map->fldrv_priv; -- DECLARE_WAITQUEUE(wait, current); -- -- retry: -- cfi_spin_lock(chip->mutex); -+ unsigned long timeo = jiffies + HZ; -+ cfi_word oldstatus, status, prev_oldstatus, prev_status; -+ cfi_word dq6 = CMD(1<<6); -+ /* see comments in do_write_oneword() regarding uWriteTimeo. */ -+ static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; -+ int ret = -EIO; -+ int ta = 0; -+ unsigned long cmd_adr; -+ int z, bytes, words; -+ cfi_word datum; -+ DECLARE_RETRY_CMD_CNT(); - -- if (chip->state != FL_READY){ -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -+ adr += chip->start; -+ cmd_adr = adr; - -+ cfi_spin_lock(chip->mutex); -+ ret = get_chip(map, chip, adr, FL_WRITING); -+ if (ret) { - cfi_spin_unlock(chip->mutex); -+ return ret; -+ } - -- schedule(); -- remove_wait_queue(&chip->wq, &wait); --#if 0 -- if(signal_pending(current)) -- return -EINTR; -+ if (cfi_buswidth_is_1()) { -+ datum = *(__u8*)buf; -+ } else if (cfi_buswidth_is_2()) { -+ datum = *(__u16*)buf; -+ } else if (cfi_buswidth_is_4()) { -+ datum = *(__u32*)buf; -+#ifdef CFI_WORD_64 -+ } else if (cfi_buswidth_is_8()) { -+ datum = *(__u64*)buf; - #endif -- timeo = jiffies + HZ; -- -- goto retry; -+ } else { -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); -+ return -EINVAL; - } - -- chip->state = FL_ERASING; -+ RETRY_CMD_LABEL; -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n", -+ __func__, adr, datum ); - -- /* Handle devices with one erase region, that only implement -- * the chip erase command. -- */ - ENABLE_VPP(map); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -- cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -- cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -- cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -- cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -- timeo = jiffies + (HZ*20); -- adr = cfi->addr_unlock1; -+ //cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - -- /* Wait for the end of programing/erasure by using the toggle method. -- * As long as there is a programming procedure going on, bit 6 of the last -- * written byte is toggling it's state with each consectuve read. -- * The toggling stops as soon as the procedure is completed. -- * -- * If the process has gone on for too long on the chip bit 5 gets. -- * After bit5 is set you can kill the operation by sending a reset -- * command to the chip. -- */ -- dq6 = CMD(1<<6); -- dq5 = CMD(1<<5); -+ /* Write Buffer Load */ -+ cfi_write(map, CMD(0x25), cmd_adr); - -- oldstatus = cfi_read(map, adr); -- status = cfi_read(map, adr); -- while( ((status & dq6) != (oldstatus & dq6)) && -- ((status & dq5) != dq5) && -- !time_after(jiffies, timeo)) { -- int wait_reps; -+ chip->state = FL_WRITING_TO_BUFFER; -+ -+ /* Write length of data to come */ -+ bytes = len & (CFIDEV_BUSWIDTH-1); -+ words = len / CFIDEV_BUSWIDTH; -+ cfi_write(map, CMD(words - !bytes), cmd_adr ); -+ /* Write data */ -+ z = 0; -+ while(z < words * CFIDEV_BUSWIDTH) { -+ if (cfi_buswidth_is_1()) { -+ datum = *((__u8*)buf); -+ map_write8 (map, *((__u8*)buf)++, adr+z); -+ } else if (cfi_buswidth_is_2()) { -+ datum = *((__u16*)buf); -+ map_write16 (map, *((__u16*)buf)++, adr+z); -+ } else if (cfi_buswidth_is_4()) { -+ datum = *((__u32*)buf); -+ map_write32 (map, *((__u32*)buf)++, adr+z); -+#ifdef CFI_WORD_64 -+ } else if (cfi_buswidth_is_8()) { -+ datum = *((__u64*)buf); -+ map_write64 (map, *((__u64*)buf)++, adr+z); -+#endif -+ } else { -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); -+ ret = -EINVAL; -+ goto op_failed; -+ } -+ z += CFIDEV_BUSWIDTH; -+ } -+ if (bytes) { -+ int i = 0, n = 0; -+ u_char tmp_buf[8], *tmp_p = tmp_buf; -+ -+ while (bytes--) -+ tmp_buf[i++] = buf[n++]; -+ while (i < CFIDEV_BUSWIDTH) -+ tmp_buf[i++] = 0xff; -+ if (cfi_buswidth_is_2()) { -+ datum = *((__u16*)tmp_p); -+ map_write16 (map, *((__u16*)tmp_p)++, adr+z); -+ } else if (cfi_buswidth_is_4()) { -+ datum = *((__u32*)tmp_p); -+ map_write32 (map, *((__u32*)tmp_p)++, adr+z); -+#ifdef CFI_WORD_64 -+ } else if (cfi_buswidth_is_8()) { -+ datum = *((__u64*)tmp_p); -+ map_write64 (map, *((__u64*)tmp_p)++, adr+z); -+#endif -+ } else { -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); -+ ret = -EINVAL; -+ goto op_failed; -+ } -+ } else if (words > 0) { -+ z -= CFIDEV_BUSWIDTH; -+ } -+ -+ adr += z; -+ -+ /* Write Buffer Program Confirm: GO GO GO */ -+ cfi_write(map, CMD(0x29), cmd_adr); -+ chip->state = FL_WRITING; - -- /* an initial short sleep */ - cfi_spin_unlock(chip->mutex); -- schedule_timeout(HZ/100); -+ cfi_udelay(chip->buffer_write_time); - cfi_spin_lock(chip->mutex); - -- if (chip->state != FL_ERASING) { -- /* Someone's suspended the erase. Sleep */ -+ timeo = jiffies + uWriteTimeout; -+ -+ for (;;) { -+ if (chip->state != FL_WRITING) { -+ /* Someone's suspended the write. Sleep */ -+ DECLARE_WAITQUEUE(wait, current); -+ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); -- - cfi_spin_unlock(chip->mutex); -- printk("erase suspended. Sleeping\n"); -- - schedule(); - remove_wait_queue(&chip->wq, &wait); --#if 0 -- if (signal_pending(current)) -- return -EINTR; --#endif -- timeo = jiffies + (HZ*2); /* FIXME */ -+ timeo = jiffies + (HZ / 2); /* FIXME */ - cfi_spin_lock(chip->mutex); - continue; - } - -- /* Busy wait for 1/10 of a milisecond */ -- for(wait_reps = 0; -- (wait_reps < 100) && -- ((status & dq6) != (oldstatus & dq6)) && -- ((status & dq5) != dq5); -- wait_reps++) { -+ oldstatus = cfi_read(map, adr); -+ status = cfi_read(map, adr); -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", -+ __func__, oldstatus, status ); -+ -+ /* See comments in do_write_oneword() about checking status */ -+ if ( (((status ^ oldstatus) & dq6) == 0) -+ || ( ta = time_after(jiffies, timeo)) ) { -+ break; -+ } - - /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); -- - cfi_udelay(1); -- - cfi_spin_lock(chip->mutex); -- oldstatus = cfi_read(map, adr); -- status = cfi_read(map, adr); - } -+ -+ /* See comments in do_write_oneword() about "two more checks" */ -+ prev_oldstatus = oldstatus; -+ prev_status = status; - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", -+ __func__, oldstatus, status ); -+ -+ if ( oldstatus == datum && status == datum ) { -+ /* success - do nothing */ -+ goto op_done; -+ } -+ -+ if ( ta ) { -+ /* Only check dq5 on the chips that are still toggling. */ -+ cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; -+ if ( status & dq5mask ) { -+ /* dq5 asserted - decode interleave chips */ -+ printk( KERN_WARNING -+ "MTD %s(): FLASH internal timeout: 0x%.8x 0x%.8x 0x%8x\n", -+ __func__, -+ status & dq5mask, status, datum ); -+ } else { -+ printk( KERN_WARNING -+ "MTD %s(): Software timed out during write.\n", -+ __func__ ); - } -- if ((status & dq6) != (oldstatus & dq6)) { -- /* The erasing didn't stop?? */ -- if ((status & dq5) == dq5) { -- /* dq5 is active so we can do a reset and stop the erase */ -- cfi_write(map, CMD(0xF0), chip->start); -+ goto op_failed; - } -+ -+ HANDLE_WACKY_STATE(); -+ -+ op_failed: -+ /* reset on all failures. */ -+ cfi_write( map, CMD(0xF0), chip->start ); -+ /* FIXME - should have reset delay before continuing */ -+ CHECK_RETRIES(); -+ ret = -EIO; -+ -+ op_done: - chip->state = FL_READY; -- wake_up(&chip->wq); -+ put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); -- printk("waiting for erase to complete timed out."); -- DISABLE_VPP(map); -- return -EIO; -+ -+ return ret; -+} -+ -+ -+static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ struct map_info *map = mtd->priv; -+ struct cfi_private *cfi = map->fldrv_priv; -+ int wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; -+ int ret = 0; -+ int chipnum; -+ unsigned long ofs; -+ -+ *retlen = 0; -+ if (!len) -+ return 0; -+ -+ chipnum = to >> cfi->chipshift; -+ ofs = to - (chipnum << cfi->chipshift); -+ -+ /* If it's not bus-aligned, do the first word write */ -+ if (ofs & (CFIDEV_BUSWIDTH-1)) { -+ size_t local_len = (-ofs)&(CFIDEV_BUSWIDTH-1); -+ if (local_len > len) -+ local_len = len; -+ ret = cfi_amdstd_write_words(mtd, to, local_len, -+ retlen, buf); -+ if (ret) -+ return ret; -+ ofs += local_len; -+ buf += local_len; -+ len -= local_len; -+ -+ if (ofs >> cfi->chipshift) { -+ chipnum ++; -+ ofs = 0; -+ if (chipnum == cfi->numchips) -+ return 0; -+ } -+ } -+ -+ /* Write buffer is worth it only if more than one word to write... */ -+ while (len) { -+ /* We must not cross write block boundaries */ -+ int size = wbufsize - (ofs & (wbufsize-1)); -+ -+ if (size > len) -+ size = len; -+ ret = do_write_buffer(map, &cfi->chips[chipnum], -+ ofs, buf, size); -+ if (ret) -+ return ret; -+ -+ ofs += size; -+ buf += size; -+ (*retlen) += size; -+ len -= size; -+ -+ if (ofs >> cfi->chipshift) { -+ chipnum ++; -+ ofs = 0; -+ if (chipnum == cfi->numchips) -+ return 0; -+ } - } -- DISABLE_VPP(map); -- chip->state = FL_READY; -- wake_up(&chip->wq); -- cfi_spin_unlock(chip->mutex); - - return 0; - } - --static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) -+ -+/* -+ * Handle devices with one erase region, that only implement -+ * the chip erase command. -+ */ -+static inline int do_erase_chip(struct map_info *map, struct flchip *chip) - { -- unsigned int oldstatus, status; -- unsigned int dq6, dq5; -- unsigned long timeo = jiffies + HZ; - struct cfi_private *cfi = map->fldrv_priv; -+ cfi_word oldstatus, status, prev_oldstatus, prev_status; -+ cfi_word dq6 = CMD(1<<6); -+ unsigned long timeo = jiffies + HZ; -+ unsigned long int adr; - DECLARE_WAITQUEUE(wait, current); -+ int ret = 0; -+ int ta = 0; -+ cfi_word datum = 0; -+ DECLARE_RETRY_CMD_CNT(); - -- retry: -- cfi_spin_lock(chip->mutex); -- -- if (chip->state != FL_READY){ -- set_current_state(TASK_UNINTERRUPTIBLE); -- add_wait_queue(&chip->wq, &wait); -+ adr = cfi->addr_unlock1; - -+ cfi_spin_lock(chip->mutex); -+ ret = get_chip(map, chip, adr, FL_WRITING); -+ if (ret) { - cfi_spin_unlock(chip->mutex); -- -- schedule(); -- remove_wait_queue(&chip->wq, &wait); --#if 0 -- if(signal_pending(current)) -- return -EINTR; --#endif -- timeo = jiffies + HZ; -- -- goto retry; -+ return ret; - } - -- chip->state = FL_ERASING; -+ RETRY_CMD_LABEL; -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", -+ __func__, chip->start ); - -- adr += chip->start; - ENABLE_VPP(map); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -- cfi_write(map, CMD(0x30), adr); -- -- timeo = jiffies + (HZ*20); -- -- /* Wait for the end of programing/erasure by using the toggle method. -- * As long as there is a programming procedure going on, bit 6 of the last -- * written byte is toggling it's state with each consectuve read. -- * The toggling stops as soon as the procedure is completed. -- * -- * If the process has gone on for too long on the chip bit 5 gets. -- * After bit5 is set you can kill the operation by sending a reset -- * command to the chip. -- */ -- dq6 = CMD(1<<6); -- dq5 = CMD(1<<5); -+ cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); - -- oldstatus = cfi_read(map, adr); -- status = cfi_read(map, adr); -- while( ((status & dq6) != (oldstatus & dq6)) && -- ((status & dq5) != dq5) && -- !time_after(jiffies, timeo)) { -- int wait_reps; -+ chip->state = FL_ERASING; -+ chip->erase_suspended = 0; -+ chip->in_progress_block_addr = adr; - -- /* an initial short sleep */ - cfi_spin_unlock(chip->mutex); -- schedule_timeout(HZ/100); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((chip->erase_time*HZ)/(2*1000)); - cfi_spin_lock(chip->mutex); - -+ timeo = jiffies + (HZ*20); -+ -+ for (;;) { - if (chip->state != FL_ERASING) { - /* Someone's suspended the erase. Sleep */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); -- - cfi_spin_unlock(chip->mutex); -- printk(KERN_DEBUG "erase suspended. Sleeping\n"); -- - schedule(); - remove_wait_queue(&chip->wq, &wait); --#if 0 -- if (signal_pending(current)) -- return -EINTR; --#endif -- timeo = jiffies + (HZ*2); /* FIXME */ - cfi_spin_lock(chip->mutex); - continue; - } -+ if (chip->erase_suspended) { -+ /* This erase was suspended and resumed. -+ Adjust the timeout */ -+ timeo = jiffies + (HZ*20); /* FIXME */ -+ chip->erase_suspended = 0; -+ } - -- /* Busy wait for 1/10 of a milisecond */ -- for(wait_reps = 0; -- (wait_reps < 100) && -- ((status & dq6) != (oldstatus & dq6)) && -- ((status & dq5) != dq5); -- wait_reps++) { -+ oldstatus = cfi_read(map, adr); -+ status = cfi_read(map, adr); -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", -+ __func__, oldstatus, status ); -+ if ( (((status ^ oldstatus) & dq6) == 0) -+ || ( ta = time_after(jiffies, timeo)) ) -+ break; - - /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); -- -- cfi_udelay(1); -- -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout(1); - cfi_spin_lock(chip->mutex); -- oldstatus = cfi_read(map, adr); -- status = cfi_read(map, adr); - } -+ -+ prev_oldstatus = oldstatus; -+ prev_status = status; - oldstatus = cfi_read(map, adr); - status = cfi_read(map, adr); -- } -- if( (status & dq6) != (oldstatus & dq6) ) -- { -- /* The erasing didn't stop?? */ -- if( ( status & dq5 ) == dq5 ) -- { -- /* When DQ5 raises, we must check once again if DQ6 is toggling. -- If not, the erase has been completed OK. If not, reset chip. */ -- oldstatus = cfi_read( map, adr ); -- status = cfi_read( map, adr ); -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", -+ __func__, oldstatus, status ); - -- if( ( oldstatus & 0x00FF ) == ( status & 0x00FF ) ) -- { -- printk( "Warning: DQ5 raised while erase operation was in progress, but erase completed OK\n" ); -- } -- else -- { -- /* DQ5 is active so we can do a reset and stop the erase */ -- cfi_write(map, CMD(0xF0), chip->start); -- printk( KERN_WARNING "Internal flash device timeout occured or write operation was performed while flash was erasing\n" ); -+ if ( cfi_buswidth_is_1() ) { -+ datum = (__u8)~0; -+ } else if ( cfi_buswidth_is_2() ) { -+ datum = (__u16)~0; -+ } else if ( cfi_buswidth_is_4() ) { -+ datum = (__u32)~0; -+#ifdef CFI_WORD_64 -+ } else if ( cfi_buswidth_is_8() ) { -+ datum = (__u64)~0; -+#endif -+ } else { -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); -+ goto op_failed; -+ } -+ -+ if ( oldstatus == datum && status == datum ) { -+ /* success - do nothing */ -+ goto op_done; -+ } -+ -+ if ( ta ) { -+ /* Only check dq5 on the chips that are still toggling. */ -+ cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; -+ if ( status & dq5mask ) { -+ /* dq5 asserted - decode interleave chips */ -+ printk( KERN_WARNING -+ "MTD %s(): FLASH internal timeout: 0x%.8x\n", -+ __func__, -+ status & dq5mask ); -+ } else { -+ printk( KERN_WARNING -+ "MTD %s(): Software timed out during write.\n", -+ __func__ ); - } -+ goto op_failed; - } -- else -- { -- printk( "Waiting for erase to complete timed out in do_erase_oneblock."); - -- chip->state = FL_READY; -- wake_up(&chip->wq); -- cfi_spin_unlock(chip->mutex); -- DISABLE_VPP(map); -- return -EIO; -- } -- } -+ HANDLE_WACKY_STATE(); - -- DISABLE_VPP(map); -+ op_failed: -+ /* reset on all failures. */ -+ cfi_write( map, CMD(0xF0), chip->start ); -+ /* FIXME - should have reset delay before continuing */ -+ CHECK_RETRIES(); -+ ret = -EIO; -+ -+ op_done: - chip->state = FL_READY; -- wake_up(&chip->wq); -+ put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); -- return 0; -+ -+ return ret; - } - --static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) -+ -+typedef int (*frob_t)(struct map_info *map, struct flchip *chip, -+ unsigned long adr, void *thunk); -+ -+ -+static int cfi_amdstd_varsize_frob(struct mtd_info *mtd, frob_t frob, -+ loff_t ofs, size_t len, void *thunk) - { - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; -- unsigned long adr, len; -+ unsigned long adr; - int chipnum, ret = 0; - int i, first; - struct mtd_erase_region_info *regions = mtd->eraseregions; - -- if (instr->addr > mtd->size) -+ if (ofs > mtd->size) - return -EINVAL; - -- if ((instr->len + instr->addr) > mtd->size) -+ if ((len + ofs) > mtd->size) - return -EINVAL; - - /* Check that both start and end of the requested erase are -@@ -1008,7 +1656,7 @@ - start of the requested erase, and then go back one. - */ - -- while (i < mtd->numeraseregions && instr->addr >= regions[i].offset) -+ while (i < mtd->numeraseregions && ofs >= regions[i].offset) - i++; - i--; - -@@ -1018,7 +1666,7 @@ - effect here. - */ - -- if (instr->addr & (regions[i].erasesize-1)) -+ if (ofs & (regions[i].erasesize-1)) - return -EINVAL; - - /* Remember the erase region we start on */ -@@ -1028,7 +1676,7 @@ - * with the erase region at that address. - */ - -- while (i<mtd->numeraseregions && (instr->addr + instr->len) >= regions[i].offset) -+ while (i<mtd->numeraseregions && (ofs + len) >= regions[i].offset) - i++; - - /* As before, drop back one to point at the region in which -@@ -1036,17 +1684,16 @@ - */ - i--; - -- if ((instr->addr + instr->len) & (regions[i].erasesize-1)) -+ if ((ofs + len) & (regions[i].erasesize-1)) - return -EINVAL; - -- chipnum = instr->addr >> cfi->chipshift; -- adr = instr->addr - (chipnum << cfi->chipshift); -- len = instr->len; -+ chipnum = ofs >> cfi->chipshift; -+ adr = ofs - (chipnum << cfi->chipshift); - - i=first; - -- while(len) { -- ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); -+ while (len) { -+ ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk); - - if (ret) - return ret; -@@ -1066,50 +1713,171 @@ - } - } - -- instr->state = MTD_ERASE_DONE; -- if (instr->callback) -- instr->callback(instr); -- - return 0; - } - --static int cfi_amdstd_erase_onesize(struct mtd_info *mtd, struct erase_info *instr) -+ -+static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) - { -- struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; -- unsigned long adr, len; -- int chipnum, ret = 0; -+ cfi_word oldstatus, status, prev_oldstatus, prev_status; -+ cfi_word dq6 = CMD(1<<6); -+ unsigned long timeo = jiffies + HZ; -+ DECLARE_WAITQUEUE(wait, current); -+ int ret = 0; -+ int ta = 0; -+ cfi_word datum = 0; -+ DECLARE_RETRY_CMD_CNT(); - -- if (instr->addr & (mtd->erasesize - 1)) -- return -EINVAL; -+ adr += chip->start; - -- if (instr->len & (mtd->erasesize -1)) -- return -EINVAL; -+ cfi_spin_lock(chip->mutex); -+ ret = get_chip(map, chip, adr, FL_ERASING); -+ if (ret) { -+ cfi_spin_unlock(chip->mutex); -+ return ret; -+ } - -- if ((instr->len + instr->addr) > mtd->size) -- return -EINVAL; -+ RETRY_CMD_LABEL; -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", -+ __func__, adr ); - -- chipnum = instr->addr >> cfi->chipshift; -- adr = instr->addr - (chipnum << cfi->chipshift); -- len = instr->len; -+ ENABLE_VPP(map); -+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ cfi_write(map, CMD(0x30), adr); - -- while(len) { -- ret = do_erase_oneblock(map, &cfi->chips[chipnum], adr); -+ chip->state = FL_ERASING; -+ chip->erase_suspended = 0; -+ chip->in_progress_block_addr = adr; - -- if (ret) -- return ret; -+ cfi_spin_unlock(chip->mutex); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout((chip->erase_time*HZ)/(2*1000)); -+ cfi_spin_lock(chip->mutex); - -- adr += mtd->erasesize; -- len -= mtd->erasesize; -+ timeo = jiffies + (HZ*20); - -- if (adr >> cfi->chipshift) { -- adr = 0; -- chipnum++; -+ /* Wait for the end of programing/erasure by using the toggle method. -+ * As long as there is a programming procedure going on, bit 6 is -+ * toggling its state with each consecutive read. The toggling stops -+ * as soon as the procedure is completed. -+ * -+ * If the process has gone on for too long on the chip, bit 5 gets -+ * set. After bit5 is set you can kill the operation by sending a -+ * reset command to the chip. -+ */ -+ /* See comments in do_write_oneword(). */ - -- if (chipnum >= cfi->numchips) -+ for (;;) { -+ if (chip->state != FL_ERASING) { -+ /* Someone's suspended the erase. Sleep */ -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ add_wait_queue(&chip->wq, &wait); -+ cfi_spin_unlock(chip->mutex); -+ schedule(); -+ remove_wait_queue(&chip->wq, &wait); -+ cfi_spin_lock(chip->mutex); -+ continue; -+ } -+ if (chip->erase_suspended) { -+ /* This erase was suspended and resumed. -+ Adjust the timeout */ -+ timeo = jiffies + (HZ*20); /* FIXME */ -+ chip->erase_suspended = 0; -+ } -+ -+ oldstatus = cfi_read(map, adr); -+ status = cfi_read(map, adr); -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", -+ __func__, oldstatus, status ); -+ if ( (((status ^ oldstatus) & dq6) == 0) -+ || ( ta = time_after(jiffies, timeo)) ) - break; -+ -+ /* Latency issues. Drop the lock, wait a while and retry */ -+ cfi_spin_unlock(chip->mutex); -+ set_current_state(TASK_UNINTERRUPTIBLE); -+ schedule_timeout(1); -+ cfi_spin_lock(chip->mutex); - } -+ -+ prev_oldstatus = oldstatus; -+ prev_status = status; -+ oldstatus = cfi_read(map, adr); -+ status = cfi_read(map, adr); -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", -+ __func__, oldstatus, status ); -+ -+ if ( cfi_buswidth_is_1() ) { -+ datum = (__u8)~0; -+ } else if ( cfi_buswidth_is_2() ) { -+ datum = (__u16)~0; -+ } else if ( cfi_buswidth_is_4() ) { -+ datum = (__u32)~0; -+#ifdef CFI_WORD_64 -+ } else if ( cfi_buswidth_is_8() ) { -+ datum = (__u64)~0; -+#endif -+ } else { -+ printk(KERN_WARNING "MTD %s(): Unsupported buswidth %d\n", -+ __func__, CFIDEV_BUSWIDTH); -+ goto op_failed; -+ } -+ -+ if ( oldstatus == datum && status == datum ) { -+ /* success - do nothing */ -+ goto op_done; -+ } -+ -+ if ( ta ) { -+ /* Only check dq5 on the chips that are still toggling. */ -+ cfi_word dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; -+ if ( status & dq5mask ) { -+ /* dq5 asserted - decode interleave chips */ -+ printk( KERN_WARNING -+ "MTD %s(): FLASH internal timeout: 0x%.8x\n", -+ __func__, -+ status & dq5mask ); -+ } else { -+ printk( KERN_WARNING -+ "MTD %s(): Software timed out during write.\n", -+ __func__ ); - } -+ goto op_failed; -+ } -+ -+ HANDLE_WACKY_STATE(); -+ -+ op_failed: -+ /* reset on all failures. */ -+ cfi_write( map, CMD(0xF0), chip->start ); -+ /* FIXME - should have reset delay before continuing */ -+ CHECK_RETRIES(); -+ ret = -EIO; -+ -+ op_done: -+ chip->state = FL_READY; -+ put_chip(map, chip, adr); -+ cfi_spin_unlock(chip->mutex); -+ return ret; -+} -+ -+ -+int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ unsigned long ofs, len; -+ int ret; -+ -+ ofs = instr->addr; -+ len = instr->len; -+ -+ ret = cfi_amdstd_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0); -+ if (ret) -+ return ret; - - instr->state = MTD_ERASE_DONE; - if (instr->callback) -@@ -1118,6 +1886,7 @@ - return 0; - } - -+ - static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) - { - struct map_info *map = mtd->priv; -@@ -1141,6 +1910,7 @@ - return 0; - } - -+ - static void cfi_amdstd_sync (struct mtd_info *mtd) - { - struct map_info *map = mtd->priv; -@@ -1254,6 +2024,7 @@ - return ret; - } - -+ - static void cfi_amdstd_resume(struct mtd_info *mtd) - { - struct map_info *map = mtd->priv; -@@ -1279,6 +2050,137 @@ - } - } - -+ -+#ifdef DEBUG_LOCK_BITS -+ -+static int do_printlockstatus_oneblock(struct map_info *map, -+ struct flchip *chip, -+ unsigned long adr, -+ void *thunk) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ int ofs_factor = cfi->interleave * cfi->device_type; -+ -+ cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); -+ printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", -+ adr, cfi_read_query(map, adr+(2*ofs_factor))); -+ cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); -+ -+ return 0; -+} -+ -+ -+#define debug_dump_locks(mtd, frob, ofs, len, thunk) \ -+ cfi_amdstd_varsize_frob((mtd), (frob), (ofs), (len), (thunk)) -+ -+#else -+ -+#define debug_dump_locks(...) -+ -+#endif /* DEBUG_LOCK_BITS */ -+ -+ -+struct xxlock_thunk { -+ cfi_word val; -+ flstate_t state; -+}; -+ -+ -+#define DO_XXLOCK_ONEBLOCK_LOCK ((struct xxlock_thunk){0x01, FL_LOCKING}) -+#define DO_XXLOCK_ONEBLOCK_UNLOCK ((struct xxlock_thunk){0x00, FL_UNLOCKING}) -+ -+ -+/* -+ * FIXME - this is *very* specific to a particular chip. It likely won't -+ * work for all chips that require unlock. It also hasn't been tested -+ * with interleaved chips. -+ */ -+static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ struct xxlock_thunk *xxlt = (struct xxlock_thunk *)thunk; -+ int ret; -+ -+ /* -+ * This is easy because these are writes to registers and not writes -+ * to flash memory - that means that we don't have to check status -+ * and timeout. -+ */ -+ -+ adr += chip->start; -+ /* -+ * lock block registers: -+ * - on 64k boundariesand -+ * - bit 1 set high -+ * - block lock registers are 4MiB lower - overflow subtract (danger) -+ */ -+ adr = ((adr & ~0xffff) | 0x2) + ~0x3fffff; -+ -+ cfi_spin_lock(chip->mutex); -+ ret = get_chip(map, chip, adr, FL_LOCKING); -+ if (ret) { -+ cfi_spin_unlock(chip->mutex); -+ return ret; -+ } -+ -+ chip->state = xxlt->state; -+ cfi_write(map, CMD(xxlt->val), adr); -+ -+ /* Done and happy. */ -+ chip->state = FL_READY; -+ put_chip(map, chip, adr); -+ cfi_spin_unlock(chip->mutex); -+ return 0; -+} -+ -+ -+static int cfi_amdstd_lock_varsize(struct mtd_info *mtd, -+ loff_t ofs, -+ size_t len) -+{ -+ int ret; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, -+ "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", -+ __func__, ofs, len); -+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); -+ -+ ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, -+ (void *)&DO_XXLOCK_ONEBLOCK_LOCK); -+ -+ DEBUG(MTD_DEBUG_LEVEL3, -+ "%s: lock status after, ret=%d\n", -+ __func__, ret); -+ -+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); -+ -+ return ret; -+} -+ -+ -+static int cfi_amdstd_unlock_varsize(struct mtd_info *mtd, -+ loff_t ofs, -+ size_t len) -+{ -+ int ret; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, -+ "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", -+ __func__, ofs, len); -+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); -+ -+ ret = cfi_amdstd_varsize_frob(mtd, do_xxlock_oneblock, ofs, len, -+ (void *)&DO_XXLOCK_ONEBLOCK_UNLOCK); -+ -+ DEBUG(MTD_DEBUG_LEVEL3, -+ "%s: lock status after, ret=%d\n", -+ __func__, ret); -+ debug_dump_locks(mtd, do_printlockstatus_oneblock, ofs, len, 0); -+ -+ return ret; -+} -+ -+ - static void cfi_amdstd_destroy(struct mtd_info *mtd) - { - struct map_info *map = mtd->priv; -@@ -1291,17 +2193,20 @@ - - static char im_name[]="cfi_cmdset_0002"; - -+ - int __init cfi_amdstd_init(void) - { - inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0002); - return 0; - } - -+ - static void __exit cfi_amdstd_exit(void) - { - inter_module_unregister(im_name); - } - -+ - module_init(cfi_amdstd_init); - module_exit(cfi_amdstd_exit); - -@@ -1309,3 +2214,7 @@ - MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al."); - MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips"); - -+#ifdef CONFIG_MTD_CFI_AMDSTD_RETRY -+MODULE_PARM(retry_cmd_max, "i"); -+MODULE_PARM_DESC(retry_cmd_max, "Number of times to retry an erase or program command if it fails - should only be needed by buggy hardware: default 0"); -+#endif -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0020.c linux/drivers/mtd/chips/cfi_cmdset_0020.c ---- linux-mips-2.4.27/drivers/mtd/chips/cfi_cmdset_0020.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/cfi_cmdset_0020.c 2004-11-19 10:25:11.747222896 +0100 -@@ -21,16 +21,19 @@ - #include <linux/types.h> - #include <linux/kernel.h> - #include <linux/sched.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <asm/byteorder.h> - - #include <linux/errno.h> -+#include <linux/init.h> - #include <linux/slab.h> - #include <linux/delay.h> - #include <linux/interrupt.h> -+#include <linux/mtd/compatmac.h> - #include <linux/mtd/map.h> - #include <linux/mtd/cfi.h> --#include <linux/mtd/compatmac.h> -+#include <linux/mtd/mtd.h> - - - static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); -@@ -51,10 +54,10 @@ - static struct mtd_info *cfi_staa_setup (struct map_info *); - - static struct mtd_chip_driver cfi_staa_chipdrv = { -- probe: NULL, /* Not usable directly */ -- destroy: cfi_staa_destroy, -- name: "cfi_cmdset_0020", -- module: THIS_MODULE -+ .probe = NULL, /* Not usable directly */ -+ .destroy = cfi_staa_destroy, -+ .name = "cfi_cmdset_0020", -+ .module = THIS_MODULE - }; - - /* #define DEBUG_LOCK_BITS */ -@@ -113,7 +116,6 @@ - { - struct cfi_private *cfi = map->fldrv_priv; - int i; -- __u32 base = cfi->chips[0].start; - - if (cfi->cfi_mode) { - /* -@@ -123,35 +125,10 @@ - */ - __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; - struct cfi_pri_intelext *extp; -- int ofs_factor = cfi->interleave * cfi->device_type; -- -- printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr); -- if (!adr) -- return NULL; -- -- /* Switch it into Query Mode */ -- cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); -- -- extp = kmalloc(sizeof(*extp), GFP_KERNEL); -- if (!extp) { -- printk(KERN_ERR "Failed to allocate memory\n"); -- return NULL; -- } -- -- /* Read in the Extended Query Table */ -- for (i=0; i<sizeof(*extp); i++) { -- ((unsigned char *)extp)[i] = -- cfi_read_query(map, (base+((adr+i)*ofs_factor))); -- } - -- if (extp->MajorVersion != '1' || -- (extp->MinorVersion < '0' || extp->MinorVersion > '2')) { -- printk(KERN_WARNING " Unknown staa Extended Query " -- "version %c.%c.\n", extp->MajorVersion, -- extp->MinorVersion); -- kfree(extp); -+ extp = (struct cfi_pri_intelext*)cfi_read_pri(map, adr, sizeof(*extp), "ST Microelectronics"); -+ if (!extp) - return NULL; -- } - - /* Do some byteswapping if necessary */ - extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); -@@ -172,11 +149,6 @@ - cfi->chips[i].erase_time = 1024; - } - -- map->fldrv = &cfi_staa_chipdrv; -- MOD_INC_USE_COUNT; -- -- /* Make sure it's in read mode */ -- cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL); - return cfi_staa_setup(map); - } - -@@ -208,6 +180,7 @@ - if (!mtd->eraseregions) { - printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); - kfree(cfi->cmdset_priv); -+ kfree(mtd); - return NULL; - } - -@@ -232,6 +205,7 @@ - printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); - kfree(mtd->eraseregions); - kfree(cfi->cmdset_priv); -+ kfree(mtd); - return NULL; - } - -@@ -256,7 +230,7 @@ - mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */ - mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ - map->fldrv = &cfi_staa_chipdrv; -- MOD_INC_USE_COUNT; -+ __module_get(THIS_MODULE); - mtd->name = map->name; - return mtd; - } -@@ -288,7 +262,7 @@ - */ - switch (chip->state) { - case FL_ERASING: -- if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2) -+ if (!(((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2)) - goto sleep; /* We don't support erase suspend */ - - cfi_write (map, CMD(0xb0), cmd_addr); -@@ -374,7 +348,7 @@ - goto retry; - } - -- map->copy_from(map, buf, adr, len); -+ map_copy_from(map, buf, adr, len); - - if (suspended) { - chip->state = chip->oldstate; -@@ -540,11 +514,11 @@ - /* Write data */ - for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { - if (cfi_buswidth_is_1()) { -- map->write8 (map, *((__u8*)buf)++, adr+z); -+ map_write8 (map, *((__u8*)buf)++, adr+z); - } else if (cfi_buswidth_is_2()) { -- map->write16 (map, *((__u16*)buf)++, adr+z); -+ map_write16 (map, *((__u16*)buf)++, adr+z); - } else if (cfi_buswidth_is_4()) { -- map->write32 (map, *((__u32*)buf)++, adr+z); -+ map_write32 (map, *((__u32*)buf)++, adr+z); - } else { - DISABLE_VPP(map); - return -EINVAL; -@@ -1436,13 +1410,13 @@ - - static char im_name[]="cfi_cmdset_0020"; - --mod_init_t cfi_staa_init(void) -+int __init cfi_staa_init(void) - { - inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020); - return 0; - } - --mod_exit_t cfi_staa_exit(void) -+static void __exit cfi_staa_exit(void) - { - inter_module_unregister(im_name); - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_probe.c linux/drivers/mtd/chips/cfi_probe.c ---- linux-mips-2.4.27/drivers/mtd/chips/cfi_probe.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/cfi_probe.c 2004-11-19 10:25:11.766220008 +0100 -@@ -1,13 +1,14 @@ - /* - Common Flash Interface probe code. - (C) 2000 Red Hat. GPL'd. -- $Id$ -+ $Id$ - */ - - #include <linux/config.h> - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <asm/byteorder.h> - #include <linux/errno.h> -@@ -25,7 +26,7 @@ - #endif - - static int cfi_probe_chip(struct map_info *map, __u32 base, -- struct flchip *chips, struct cfi_private *cfi); -+ unsigned long *chip_map, struct cfi_private *cfi); - static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi); - - struct mtd_info *cfi_probe(struct map_info *map); -@@ -48,7 +49,7 @@ - } - - static int cfi_probe_chip(struct map_info *map, __u32 base, -- struct flchip *chips, struct cfi_private *cfi) -+ unsigned long *chip_map, struct cfi_private *cfi) - { - int i; - -@@ -77,18 +78,24 @@ - } - - /* Check each previous chip to see if it's an alias */ -- for (i=0; i<cfi->numchips; i++) { -+ for (i=0; i < (base >> cfi->chipshift); i++) { -+ unsigned long start; -+ if(!test_bit(i, chip_map)) { -+ /* Skip location; no valid chip at this address */ -+ continue; -+ } -+ start = i << cfi->chipshift; - /* This chip should be in read mode if it's one - we've already touched. */ -- if (qry_present(map,chips[i].start,cfi)) { -+ if (qry_present(map, start, cfi)) { - /* Eep. This chip also had the QRY marker. - * Is it an alias for the new one? */ -- cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0xF0, 0, start, map, cfi, cfi->device_type, NULL); - - /* If the QRY marker goes away, it's an alias */ -- if (!qry_present(map, chips[i].start, cfi)) { -+ if (!qry_present(map, start, cfi)) { - printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", -- map->name, base, chips[i].start); -+ map->name, base, start); - return 0; - } - /* Yes, it's actually got QRY for data. Most -@@ -99,7 +106,7 @@ - - if (qry_present(map, base, cfi)) { - printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", -- map->name, base, chips[i].start); -+ map->name, base, start); - return 0; - } - } -@@ -107,13 +114,7 @@ - - /* OK, if we got to here, then none of the previous chips appear to - be aliases for the current one. */ -- if (cfi->numchips == MAX_CFI_CHIPS) { -- printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS); -- /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */ -- return -1; -- } -- chips[cfi->numchips].start = base; -- chips[cfi->numchips].state = FL_READY; -+ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ - cfi->numchips++; - - /* Put it back into Read Mode */ -@@ -179,9 +180,28 @@ - (cfi->cfiq->EraseRegionInfo[i] & 0xffff) + 1); - #endif - } -+ -+ /* Note we put the device back into Read Mode BEFORE going into Auto -+ * Select Mode, as some devices support nesting of modes, others -+ * don't. This way should always work. -+ * On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and -+ * so should be treated as nops or illegal (and so put the device -+ * back into Read Mode, which is a nop in this case). -+ */ -+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); -+ cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); -+ cfi->mfr = cfi_read_query(map, base); -+ cfi->id = cfi_read_query(map, base + ofs_factor); -+ - /* Put it back into Read Mode */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - -+ printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n", -+ map->name, cfi->interleave, cfi->device_type*8, base, -+ map->buswidth*8); -+ - return 1; - } - -@@ -240,11 +260,11 @@ - printk("No Alternate Algorithm Table\n"); - - -- printk("Vcc Minimum: %x.%x V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); -- printk("Vcc Maximum: %x.%x V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); -+ printk("Vcc Minimum: %2d.%d V\n", cfip->VccMin >> 4, cfip->VccMin & 0xf); -+ printk("Vcc Maximum: %2d.%d V\n", cfip->VccMax >> 4, cfip->VccMax & 0xf); - if (cfip->VppMin) { -- printk("Vpp Minimum: %x.%x V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf); -- printk("Vpp Maximum: %x.%x V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf); -+ printk("Vpp Minimum: %2d.%d V\n", cfip->VppMin >> 4, cfip->VppMin & 0xf); -+ printk("Vpp Maximum: %2d.%d V\n", cfip->VppMax >> 4, cfip->VppMax & 0xf); - } - else - printk("No Vpp line\n"); -@@ -303,8 +323,8 @@ - #endif /* DEBUG_CFI */ - - static struct chip_probe cfi_chip_probe = { -- name: "CFI", -- probe_chip: cfi_probe_chip -+ .name = "CFI", -+ .probe_chip = cfi_probe_chip - }; - - struct mtd_info *cfi_probe(struct map_info *map) -@@ -317,9 +337,9 @@ - } - - static struct mtd_chip_driver cfi_chipdrv = { -- probe: cfi_probe, -- name: "cfi_probe", -- module: THIS_MODULE -+ .probe = cfi_probe, -+ .name = "cfi_probe", -+ .module = THIS_MODULE - }; - - int __init cfi_probe_init(void) -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/cfi_util.c linux/drivers/mtd/chips/cfi_util.c ---- linux-mips-2.4.27/drivers/mtd/chips/cfi_util.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/chips/cfi_util.c 2004-11-19 10:25:11.767219856 +0100 -@@ -0,0 +1,91 @@ -+/* -+ * Common Flash Interface support: -+ * Generic utility functions not dependant on command set -+ * -+ * Copyright (C) 2002 Red Hat -+ * Copyright (C) 2003 STMicroelectronics Limited -+ * -+ * This code is covered by the GPL. -+ * -+ * $Id$ -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/sched.h> -+#include <asm/io.h> -+#include <asm/byteorder.h> -+ -+#include <linux/errno.h> -+#include <linux/slab.h> -+#include <linux/delay.h> -+#include <linux/interrupt.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/cfi.h> -+#include <linux/mtd/compatmac.h> -+ -+struct cfi_extquery * -+cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ __u32 base = 0; // cfi->chips[0].start; -+ int ofs_factor = cfi->interleave * cfi->device_type; -+ int i; -+ struct cfi_extquery *extp = NULL; -+ -+ printk(" %s Extended Query Table at 0x%4.4X\n", name, adr); -+ if (!adr) -+ goto out; -+ -+ /* Switch it into Query Mode */ -+ cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); -+ -+ extp = kmalloc(size, GFP_KERNEL); -+ if (!extp) { -+ printk(KERN_ERR "Failed to allocate memory\n"); -+ goto out; -+ } -+ -+ /* Read in the Extended Query Table */ -+ for (i=0; i<size; i++) { -+ ((unsigned char *)extp)[i] = -+ cfi_read_query(map, base+((adr+i)*ofs_factor)); -+ } -+ -+ if (extp->MajorVersion != '1' || -+ (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { -+ printk(KERN_WARNING " Unknown %s Extended Query " -+ "version %c.%c.\n", name, extp->MajorVersion, -+ extp->MinorVersion); -+ kfree(extp); -+ extp = NULL; -+ goto out; -+ } -+ -+out: -+ /* Make sure it's in read mode */ -+ cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL); -+ -+ return extp; -+} -+ -+EXPORT_SYMBOL(cfi_read_pri); -+ -+void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups) -+{ -+ struct cfi_private *cfi = map->fldrv_priv; -+ struct cfi_fixup *f; -+ -+ for (f=fixups; f->fixup; f++) { -+ if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) && -+ ((f->id == CFI_ID_ANY) || (f->id == cfi->id))) { -+ f->fixup(map, f->param); -+ } -+ } -+} -+ -+EXPORT_SYMBOL(cfi_fixup); -+ -+MODULE_LICENSE("GPL"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/chipreg.c linux/drivers/mtd/chips/chipreg.c ---- linux-mips-2.4.27/drivers/mtd/chips/chipreg.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/chipreg.c 2004-11-19 10:25:11.769219552 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Registration for chip drivers - * -@@ -7,10 +7,13 @@ - - #include <linux/kernel.h> - #include <linux/config.h> -+#include <linux/module.h> - #include <linux/kmod.h> - #include <linux/spinlock.h> --#include <linux/mtd/compatmac.h> -+#include <linux/slab.h> - #include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/compatmac.h> - - spinlock_t chip_drvs_lock = SPIN_LOCK_UNLOCKED; - static LIST_HEAD(chip_drvs_list); -@@ -44,10 +47,8 @@ - break; - } - } -- if (ret && !try_inc_mod_count(ret->module)) { -- /* Eep. Failed. */ -+ if (ret && !try_module_get(ret->module)) - ret = NULL; -- } - - spin_unlock(&chip_drvs_lock); - -@@ -64,32 +65,46 @@ - - drv = get_mtd_chip_driver(name); - -- if (!drv && !request_module(name)) -+ if (!drv && !request_module("%s", name)) - drv = get_mtd_chip_driver(name); - - if (!drv) - return NULL; - - ret = drv->probe(map); --#ifdef CONFIG_MODULES -+ - /* We decrease the use count here. It may have been a - probe-only module, which is no longer required from this - point, having given us a handle on (and increased the use - count of) the actual driver code. - */ -- if(drv->module) -- __MOD_DEC_USE_COUNT(drv->module); --#endif -+ module_put(drv->module); - - if (ret) - return ret; - - return NULL; - } -+/* -+ * Destroy an MTD device which was created for a map device. -+ * Make sure the MTD device is already unregistered before calling this -+ */ -+void map_destroy(struct mtd_info *mtd) -+{ -+ struct map_info *map = mtd->priv; -+ -+ if (map->fldrv->destroy) -+ map->fldrv->destroy(mtd); -+ -+ module_put(map->fldrv->module); -+ -+ kfree(mtd); -+} - - EXPORT_SYMBOL(register_mtd_chip_driver); - EXPORT_SYMBOL(unregister_mtd_chip_driver); - EXPORT_SYMBOL(do_map_probe); -+EXPORT_SYMBOL(map_destroy); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/gen_probe.c linux/drivers/mtd/chips/gen_probe.c ---- linux-mips-2.4.27/drivers/mtd/chips/gen_probe.c 2003-08-13 19:19:18.000000000 +0200 -+++ linux/drivers/mtd/chips/gen_probe.c 2004-11-19 10:25:11.770219400 +0100 -@@ -1,14 +1,17 @@ - /* - * Routines common to all CFI-type probes. -- * (C) 2001, 2001 Red Hat, Inc. -+ * (C) 2001-2003 Red Hat, Inc. - * GPL'd -- * $Id$ -+ * $Id$ - */ - - #include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/module.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> - #include <linux/mtd/cfi.h> -+#include <linux/mtd/mtd.h> - #include <linux/mtd/gen_probe.h> - - static struct mtd_info *check_cmd_set(struct map_info *, int); -@@ -50,11 +53,11 @@ - - struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chip_probe *cp) - { -- unsigned long base=0; - struct cfi_private cfi; - struct cfi_private *retcfi; -- struct flchip chip[MAX_CFI_CHIPS]; -- int i; -+ unsigned long *chip_map; -+ int i, j; -+ int max_chips; - - memset(&cfi, 0, sizeof(cfi)); - -@@ -77,8 +80,6 @@ - return NULL; - } - #endif -- chip[0].start = 0; -- chip[0].state = FL_READY; - cfi.chipshift = cfi.cfiq->DevSize; - - switch(cfi.interleave) { -@@ -103,20 +104,28 @@ - cfi.numchips = 1; - - /* -+ * Allocate memory for bitmap of valid chips. -+ * Align bitmap storage size to full byte. -+ */ -+ max_chips = map->size >> cfi.chipshift; -+ chip_map = kmalloc((max_chips / 8) + ((max_chips % 8) ? 1 : 0), GFP_KERNEL); -+ if (!chip_map) { -+ printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name); -+ kfree(cfi.cfiq); -+ return NULL; -+ } -+ -+ set_bit(0, chip_map); /* Mark first chip valid */ -+ -+ /* - * Now probe for other chips, checking sensibly for aliases while - * we're at it. The new_chip probe above should have let the first - * chip in read mode. -- * -- * NOTE: Here, we're checking if there is room for another chip -- * the same size within the mapping. Therefore, -- * base + chipsize <= map->size is the correct thing to do, -- * because, base + chipsize would be the _first_ byte of the -- * next chip, not the one we're currently pondering. - */ - -- for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size; -- base += (1<<cfi.chipshift)) -- cp->probe_chip(map, base, &chip[0], &cfi); -+ for (i = 1; i < max_chips; i++) { -+ cp->probe_chip(map, i << cfi.chipshift, chip_map, &cfi); -+ } - - /* - * Now allocate the space for the structures we need to return to -@@ -128,19 +137,26 @@ - if (!retcfi) { - printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name); - kfree(cfi.cfiq); -+ kfree(chip_map); - return NULL; - } - - memcpy(retcfi, &cfi, sizeof(cfi)); -- memcpy(&retcfi->chips[0], chip, sizeof(struct flchip) * cfi.numchips); -+ memset(&retcfi->chips[0], 0, sizeof(struct flchip) * cfi.numchips); - -- /* Fix up the stuff that breaks when you move it */ -- for (i=0; i< retcfi->numchips; i++) { -- init_waitqueue_head(&retcfi->chips[i].wq); -- spin_lock_init(&retcfi->chips[i]._spinlock); -- retcfi->chips[i].mutex = &retcfi->chips[i]._spinlock; -+ for (i = 0, j = 0; (j < cfi.numchips) && (i < max_chips); i++) { -+ if(test_bit(i, chip_map)) { -+ struct flchip *pchip = &retcfi->chips[j++]; -+ -+ pchip->start = (i << cfi.chipshift); -+ pchip->state = FL_READY; -+ init_waitqueue_head(&pchip->wq); -+ spin_lock_init(&pchip->_spinlock); -+ pchip->mutex = &pchip->_spinlock; -+ } - } - -+ kfree(chip_map); - return retcfi; - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/jedec.c linux/drivers/mtd/chips/jedec.c ---- linux-mips-2.4.27/drivers/mtd/chips/jedec.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/jedec.c 2004-11-19 10:25:11.772219096 +0100 -@@ -11,10 +11,16 @@ - * not going to guess how to send commands to them, plus I expect they will - * all speak CFI.. - * -- * $Id$ -+ * $Id$ - */ - -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/kernel.h> - #include <linux/mtd/jedec.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/compatmac.h> - - static struct mtd_info *jedec_probe(struct map_info *); - static int jedec_probe8(struct map_info *map,unsigned long base, -@@ -33,14 +39,51 @@ - - /* Listing of parts and sizes. We need this table to learn the sector - size of the chip and the total length */ --static const struct JEDECTable JEDEC_table[] = -- {{0x013D,"AMD Am29F017D",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, -- {0x01AD,"AMD Am29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, -- {0x01D5,"AMD Am29F080",1*1024*1024,64*1024,MTD_CAP_NORFLASH}, -- {0x01A4,"AMD Am29F040",512*1024,64*1024,MTD_CAP_NORFLASH}, -- {0x20E3,"AMD Am29W040B",512*1024,64*1024,MTD_CAP_NORFLASH}, -- {0xC2AD,"Macronix MX29F016",2*1024*1024,64*1024,MTD_CAP_NORFLASH}, -- {}}; -+static const struct JEDECTable JEDEC_table[] = { -+ { -+ .jedec = 0x013D, -+ .name = "AMD Am29F017D", -+ .size = 2*1024*1024, -+ .sectorsize = 64*1024, -+ .capabilities = MTD_CAP_NORFLASH -+ }, -+ { -+ .jedec = 0x01AD, -+ .name = "AMD Am29F016", -+ .size = 2*1024*1024, -+ .sectorsize = 64*1024, -+ .capabilities = MTD_CAP_NORFLASH -+ }, -+ { -+ .jedec = 0x01D5, -+ .name = "AMD Am29F080", -+ .size = 1*1024*1024, -+ .sectorsize = 64*1024, -+ .capabilities = MTD_CAP_NORFLASH -+ }, -+ { -+ .jedec = 0x01A4, -+ .name = "AMD Am29F040", -+ .size = 512*1024, -+ .sectorsize = 64*1024, -+ .capabilities = MTD_CAP_NORFLASH -+ }, -+ { -+ .jedec = 0x20E3, -+ .name = "AMD Am29W040B", -+ .size = 512*1024, -+ .sectorsize = 64*1024, -+ .capabilities = MTD_CAP_NORFLASH -+ }, -+ { -+ .jedec = 0xC2AD, -+ .name = "Macronix MX29F016", -+ .size = 2*1024*1024, -+ .sectorsize = 64*1024, -+ .capabilities = MTD_CAP_NORFLASH -+ }, -+ { .jedec = 0x0 } -+}; - - static const struct JEDECTable *jedec_idtoinf(__u8 mfr,__u8 id); - static void jedec_sync(struct mtd_info *mtd) {}; -@@ -54,9 +97,9 @@ - - - static struct mtd_chip_driver jedec_chipdrv = { -- probe: jedec_probe, -- name: "jedec", -- module: THIS_MODULE -+ .probe = jedec_probe, -+ .name = "jedec", -+ .module = THIS_MODULE - }; - - /* Probe entry point */ -@@ -131,8 +174,7 @@ - /* Generate a part name that includes the number of different chips and - other configuration information */ - count = 1; -- strncpy(Part,map->name,sizeof(Part)-10); -- Part[sizeof(Part)-11] = 0; -+ strlcpy(Part,map->name,sizeof(Part)-10); - strcat(Part," "); - Uniq = 0; - for (I = 0; priv->chips[I].jedec != 0 && I < MAX_JEDEC_CHIPS; I++) -@@ -209,8 +251,7 @@ - // printk("Part: '%s'\n",Part); - - memset(MTD,0,sizeof(*MTD)); -- // strncpy(MTD->name,Part,sizeof(MTD->name)); -- // MTD->name[sizeof(MTD->name)-1] = 0; -+ // strlcpy(MTD->name,Part,sizeof(MTD->name)); - MTD->name = map->name; - MTD->type = MTD_NORFLASH; - MTD->flags = MTD_CAP_NORFLASH; -@@ -229,7 +270,7 @@ - MTD->priv = map; - map->fldrv_priv = priv; - map->fldrv = &jedec_chipdrv; -- MOD_INC_USE_COUNT; -+ __module_get(THIS_MODULE); - return MTD; - } - -@@ -351,8 +392,8 @@ - static int jedec_probe8(struct map_info *map,unsigned long base, - struct jedec_private *priv) - { -- #define flread(x) map->read8(map,base+x) -- #define flwrite(v,x) map->write8(map,v,base+x) -+ #define flread(x) map_read8(map,base+x) -+ #define flwrite(v,x) map_write8(map,v,base+x) - - const unsigned long AutoSel1 = 0xAA; - const unsigned long AutoSel2 = 0x55; -@@ -411,8 +452,8 @@ - static int jedec_probe32(struct map_info *map,unsigned long base, - struct jedec_private *priv) - { -- #define flread(x) map->read32(map,base+((x)<<2)) -- #define flwrite(v,x) map->write32(map,v,base+((x)<<2)) -+ #define flread(x) map_read32(map,base+((x)<<2)) -+ #define flwrite(v,x) map_write32(map,v,base+((x)<<2)) - - const unsigned long AutoSel1 = 0xAAAAAAAA; - const unsigned long AutoSel2 = 0x55555555; -@@ -490,7 +531,7 @@ - { - struct map_info *map = (struct map_info *)mtd->priv; - -- map->copy_from(map, buf, from, len); -+ map_copy_from(map, buf, from, len); - *retlen = len; - return 0; - } -@@ -514,7 +555,7 @@ - get = priv->bank_fill[0] - offset; - - bank /= priv->bank_fill[0]; -- map->copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); -+ map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); - - len -= get; - *retlen += get; -@@ -545,8 +586,8 @@ - static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) - { - // Does IO to the currently selected chip -- #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift)) -- #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift)) -+ #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift)) -+ #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift)) - - unsigned long Time = 0; - unsigned long NoTime = 0; -@@ -608,7 +649,7 @@ - - /* Poll the flash for erasure completion, specs say this can take as long - as 480 seconds to do all the sectors (for a 2 meg flash). -- Erasure time is dependant on chip age, temp and wear.. */ -+ Erasure time is dependent on chip age, temp and wear.. */ - - /* This being a generic routine assumes a 32 bit bus. It does read32s - and bundles interleved chips into the same grouping. This will work -@@ -651,19 +692,19 @@ - or this is not really flash ;> */ - switch (map->buswidth) { - case 1: -- Last[0] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); -- Last[1] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); -- Last[2] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); - break; - case 2: -- Last[0] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); -- Last[1] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); -- Last[2] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); - break; - case 3: -- Last[0] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); -- Last[1] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); -- Last[2] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); - break; - } - Count = 3; -@@ -699,13 +740,13 @@ - - switch (map->buswidth) { - case 1: -- Last[Count % 4] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); - break; - case 2: -- Last[Count % 4] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); - break; - case 4: -- Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); -+ Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); - break; - } - Count++; -@@ -755,10 +796,10 @@ - size_t *retlen, const u_char *buf) - { - /* Does IO to the currently selected chip. It takes the bank addressing -- base (which is divisable by the chip size) adds the necesary lower bits -- of addrshift (interleve index) and then adds the control register index. */ -- #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) -- #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) -+ base (which is divisible by the chip size) adds the necessary lower bits -+ of addrshift (interleave index) and then adds the control register index. */ -+ #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) -+ #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) - - struct map_info *map = (struct map_info *)mtd->priv; - struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv; -@@ -794,7 +835,7 @@ - // Loop over this page - for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) - { -- unsigned char oldbyte = map->read8(map,base+off); -+ unsigned char oldbyte = map_read8(map,base+off); - unsigned char Last[4]; - unsigned long Count = 0; - -@@ -809,10 +850,10 @@ - flwrite(0xAA,0x555); - flwrite(0x55,0x2AA); - flwrite(0xA0,0x555); -- map->write8(map,*buf,base + off); -- Last[0] = map->read8(map,base + off); -- Last[1] = map->read8(map,base + off); -- Last[2] = map->read8(map,base + off); -+ map_write8(map,*buf,base + off); -+ Last[0] = map_read8(map,base + off); -+ Last[1] = map_read8(map,base + off); -+ Last[2] = map_read8(map,base + off); - - /* Wait for the flash to finish the operation. We store the last 4 - status bytes that have been retrieved so we can determine why -@@ -820,7 +861,7 @@ - failure */ - for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && - Count < 10000; Count++) -- Last[Count % 4] = map->read8(map,base + off); -+ Last[Count % 4] = map_read8(map,base + off); - if (Last[(Count - 1) % 4] != *buf) - { - jedec_flash_failed(Last[(Count - 3) % 4]); -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/jedec_probe.c linux/drivers/mtd/chips/jedec_probe.c ---- linux-mips-2.4.27/drivers/mtd/chips/jedec_probe.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/jedec_probe.c 2004-11-19 10:25:11.774218792 +0100 -@@ -1,9 +1,11 @@ - /* - Common Flash Interface probe code. - (C) 2000 Red Hat. GPL'd. -- $Id$ -+ $Id$ - See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) - for the standard this probe goes back to. -+ -+ Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com - */ - - #include <linux/config.h> -@@ -15,7 +17,9 @@ - #include <linux/errno.h> - #include <linux/slab.h> - #include <linux/interrupt.h> -+#include <linux/init.h> - -+#include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> - #include <linux/mtd/cfi.h> - #include <linux/mtd/gen_probe.h> -@@ -26,20 +30,24 @@ - #define MANUFACTURER_FUJITSU 0x0004 - #define MANUFACTURER_INTEL 0x0089 - #define MANUFACTURER_MACRONIX 0x00C2 --#define MANUFACTURER_ST 0x0020 -+#define MANUFACTURER_PMC 0x009D - #define MANUFACTURER_SST 0x00BF -+#define MANUFACTURER_ST 0x0020 - #define MANUFACTURER_TOSHIBA 0x0098 -+#define MANUFACTURER_WINBOND 0x00da - - - /* AMD */ - #define AM29F800BB 0x2258 - #define AM29F800BT 0x22D6 -+#define AM29LV400BB 0x22BA -+#define AM29LV400BT 0x22B9 - #define AM29LV800BB 0x225B - #define AM29LV800BT 0x22DA - #define AM29LV160DT 0x22C4 - #define AM29LV160DB 0x2249 - #define AM29F017D 0x003D --#define AM29F016 0x00AD -+#define AM29F016D 0x00AD - #define AM29F080 0x00D5 - #define AM29F040 0x00A4 - #define AM29LV040B 0x004F -@@ -54,6 +62,7 @@ - #define AT49BV32XT 0x00C9 - - /* Fujitsu */ -+#define MBM29F040C 0x00A4 - #define MBM29LV650UE 0x22D7 - #define MBM29LV320TE 0x22F6 - #define MBM29LV320BE 0x22F9 -@@ -61,6 +70,9 @@ - #define MBM29LV160BE 0x2249 - #define MBM29LV800BA 0x225B - #define MBM29LV800TA 0x22DA -+#define MBM29LV400TC 0x22B9 -+#define MBM29LV400BC 0x22BA -+ - - /* Intel */ - #define I28F004B3T 0x00d4 -@@ -93,8 +105,14 @@ - #define MX29F004T 0x0045 - #define MX29F004B 0x0046 - -+/* PMC */ -+#define PM49FL002 0x006D -+#define PM49FL004 0x006E -+#define PM49FL008 0x006A -+ - /* ST - www.st.com */ --#define M29W800T 0x00D7 -+#define M29W800DT 0x00D7 -+#define M29W800DB 0x005B - #define M29W160DT 0x22C4 - #define M29W160DB 0x2249 - #define M29W040B 0x00E3 -@@ -110,6 +128,7 @@ - #define SST39LF040 0x00D7 - #define SST39SF010A 0x00B5 - #define SST39SF020A 0x00B6 -+#define SST49LF004B 0x0060 - #define SST49LF030A 0x001C - #define SST49LF040A 0x0051 - #define SST49LF080A 0x005B -@@ -122,15 +141,87 @@ - #define TC58FVT641 0x0093 - #define TC58FVB641 0x0095 - -+/* Winbond */ -+#define W49V002A 0x00b0 -+ -+ -+/* -+ * Unlock address sets for AMD command sets. -+ * Intel command sets use the MTD_UADDR_UNNECESSARY. -+ * Each identifier, except MTD_UADDR_UNNECESSARY, and -+ * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[]. -+ * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure -+ * initialization need not require initializing all of the -+ * unlock addresses for all bit widths. -+ */ -+enum uaddr { -+ MTD_UADDR_NOT_SUPPORTED = 0, /* data width not supported */ -+ MTD_UADDR_0x0555_0x02AA, -+ MTD_UADDR_0x0555_0x0AAA, -+ MTD_UADDR_0x5555_0x2AAA, -+ MTD_UADDR_0x0AAA_0x0555, -+ MTD_UADDR_DONT_CARE, /* Requires an arbitrary address */ -+ MTD_UADDR_UNNECESSARY, /* Does not require any address */ -+}; -+ -+ -+struct unlock_addr { -+ int addr1; -+ int addr2; -+}; -+ -+ -+/* -+ * I don't like the fact that the first entry in unlock_addrs[] -+ * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore, -+ * should not be used. The problem is that structures with -+ * initializers have extra fields initialized to 0. It is _very_ -+ * desireable to have the unlock address entries for unsupported -+ * data widths automatically initialized - that means that -+ * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here -+ * must go unused. -+ */ -+static const struct unlock_addr unlock_addrs[] = { -+ [MTD_UADDR_NOT_SUPPORTED] = { -+ .addr1 = 0xffff, -+ .addr2 = 0xffff -+ }, -+ -+ [MTD_UADDR_0x0555_0x02AA] = { -+ .addr1 = 0x0555, -+ .addr2 = 0x02aa -+ }, -+ -+ [MTD_UADDR_0x0555_0x0AAA] = { -+ .addr1 = 0x0555, -+ .addr2 = 0x0aaa -+ }, -+ -+ [MTD_UADDR_0x5555_0x2AAA] = { -+ .addr1 = 0x5555, -+ .addr2 = 0x2aaa -+ }, -+ -+ [MTD_UADDR_0x0AAA_0x0555] = { -+ .addr1 = 0x0AAA, -+ .addr2 = 0x0555 -+ }, -+ -+ [MTD_UADDR_DONT_CARE] = { -+ .addr1 = 0x0000, /* Doesn't matter which address */ -+ .addr2 = 0x0000 /* is used - must be last entry */ -+ } -+}; -+ - - struct amd_flash_info { - const __u16 mfr_id; - const __u16 dev_id; - const char *name; - const int DevSize; -- const int InterfaceDesc; - const int NumEraseRegions; - const int CmdSet; -+ const __u8 uaddr[4]; /* unlock addrs for 8, 16, 32, 64 */ - const ulong regions[4]; - }; - -@@ -145,760 +236,1214 @@ - #define SIZE_4MiB 22 - #define SIZE_8MiB 23 - -+ -+/* -+ * Please keep this list ordered by manufacturer! -+ * Fortunately, the list isn't searched often and so a -+ * slow, linear search isn't so bad. -+ */ - static const struct amd_flash_info jedec_table[] = { - { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F032B, -- name: "AMD AM29F032B", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,64) -- } -- }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV160DT, -- name: "AMD AM29LV160DT", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,31), -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F032B, -+ .name = "AMD AM29F032B", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,64) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV160DT, -+ .name = "AMD AM29LV160DT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV160DB, -- name: "AMD AM29LV160DB", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV160DB, -+ .name = "AMD AM29LV160DB", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { -- mfr_id: MANUFACTURER_TOSHIBA, -- dev_id: TC58FVT160, -- name: "Toshiba TC58FVT160", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,31), -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV400BB, -+ .name = "AMD AM29LV400BB", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), -+ ERASEINFO(0x02000,2), -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x10000,7) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV400BT, -+ .name = "AMD AM29LV400BT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,7), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_TOSHIBA, -- dev_id: TC58FVB160, -- name: "Toshiba TC58FVB160", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV800BB, -+ .name = "AMD AM29LV800BB", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), -- ERASEINFO(0x10000,31) -+ ERASEINFO(0x10000,15), - } - }, { -- mfr_id: MANUFACTURER_TOSHIBA, -- dev_id: TC58FVB321, -- name: "Toshiba TC58FVB321", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x02000,8), -- ERASEINFO(0x10000,63) -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F800BB, -+ .name = "AMD AM29F800BB", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), -+ ERASEINFO(0x02000,2), -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x10000,15), - } - }, { -- mfr_id: MANUFACTURER_TOSHIBA, -- dev_id: TC58FVT321, -- name: "Toshiba TC58FVT321", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x10000,63), -- ERASEINFO(0x02000,8) -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV800BT, -+ .name = "AMD AM29LV800BT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,15), -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x02000,2), -+ ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_TOSHIBA, -- dev_id: TC58FVB641, -- name: "Toshiba TC58FVB641", -- DevSize: SIZE_8MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x02000,8), -- ERASEINFO(0x10000,127) -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F800BT, -+ .name = "AMD AM29F800BT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,15), -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x02000,2), -+ ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_TOSHIBA, -- dev_id: TC58FVT641, -- name: "Toshiba TC58FVT641", -- DevSize: SIZE_8MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x10000,127), -- ERASEINFO(0x02000,8) -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F017D, -+ .name = "AMD AM29F017D", -+ .uaddr = { -+ [0] = MTD_UADDR_DONT_CARE /* x8 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,32), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F016D, -+ .name = "AMD AM29F016D", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,32), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F080, -+ .name = "AMD AM29F080", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,16), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29F040, -+ .name = "AMD AM29F040", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,8), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_AMD, -+ .dev_id = AM29LV040B, -+ .name = "AMD AM29LV040B", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,8), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_ATMEL, -+ .dev_id = AT49BV512, -+ .name = "Atmel AT49BV512", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_64KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,1) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_ATMEL, -+ .dev_id = AT29LV512, -+ .name = "Atmel AT29LV512", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_64KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x80,256), -+ ERASEINFO(0x80,256) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_ATMEL, -+ .dev_id = AT49BV16X, -+ .name = "Atmel AT49BV16X", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x02000,8), -+ ERASEINFO(0x10000,31) - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV650UE, -- name: "Fujitsu MBM29LV650UE", -- DevSize: SIZE_8MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,128) -- } -- }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV320TE, -- name: "Fujitsu MBM29LV320TE", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x10000,63), -+ .mfr_id = MANUFACTURER_ATMEL, -+ .dev_id = AT49BV16XT, -+ .name = "Atmel AT49BV16XT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x10000,31), - ERASEINFO(0x02000,8) - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV320BE, -- name: "Fujitsu MBM29LV320BE", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x02000,8), -+ .mfr_id = MANUFACTURER_ATMEL, -+ .dev_id = AT49BV32X, -+ .name = "Atmel AT49BV32X", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x02000,8), - ERASEINFO(0x10000,63) - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV160TE, -- name: "Fujitsu MBM29LV160TE", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,31), -- ERASEINFO(0x08000,1), -- ERASEINFO(0x02000,2), -- ERASEINFO(0x04000,1) -+ .mfr_id = MANUFACTURER_ATMEL, -+ .dev_id = AT49BV32XT, -+ .name = "Atmel AT49BV32XT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x10000,63), -+ ERASEINFO(0x02000,8) - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV160BE, -- name: "Fujitsu MBM29LV160BE", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -- ERASEINFO(0x02000,2), -- ERASEINFO(0x08000,1), -- ERASEINFO(0x10000,31) -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29F040C, -+ .name = "Fujitsu MBM29F040C", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,8) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV650UE, -+ .name = "Fujitsu MBM29LV650UE", -+ .uaddr = { -+ [0] = MTD_UADDR_DONT_CARE /* x16 */ -+ }, -+ .DevSize = SIZE_8MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,128) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV320TE, -+ .name = "Fujitsu MBM29LV320TE", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x10000,63), -+ ERASEINFO(0x02000,8) - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV800BA, -- name: "Fujitsu MBM29LV800BA", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -- ERASEINFO(0x02000,2), -- ERASEINFO(0x08000,1), -- ERASEINFO(0x10000,15) -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV320BE, -+ .name = "Fujitsu MBM29LV320BE", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x02000,8), -+ ERASEINFO(0x10000,63) - } - }, { -- mfr_id: MANUFACTURER_FUJITSU, -- dev_id: MBM29LV800TA, -- name: "Fujitsu MBM29LV800TA", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,15), -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV160TE, -+ .name = "Fujitsu MBM29LV160TE", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV800BB, -- name: "AMD AM29LV800BB", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV160BE, -+ .name = "Fujitsu MBM29LV160BE", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), -- ERASEINFO(0x10000,15), -+ ERASEINFO(0x10000,31) - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F800BB, -- name: "AMD AM29F800BB", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV800BA, -+ .name = "Fujitsu MBM29LV800BA", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), -- ERASEINFO(0x10000,15), -+ ERASEINFO(0x10000,15) - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV800BT, -- name: "AMD AM29LV800BT", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,15), -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV800TA, -+ .name = "Fujitsu MBM29LV800TA", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F800BT, -- name: "AMD AM29F800BT", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,15), -- ERASEINFO(0x08000,1), -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV400BC, -+ .name = "Fujitsu MBM29LV400BC", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), -- ERASEINFO(0x04000,1) -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x10000,7) - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV800BB, -- name: "AMD AM29LV800BB", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,15), -+ .mfr_id = MANUFACTURER_FUJITSU, -+ .dev_id = MBM29LV400TC, -+ .name = "Fujitsu MBM29LV400TC", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,7), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F004B3B, -- name: "Intel 28F004B3B", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F004B3B, -+ .name = "Intel 28F004B3B", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x02000, 8), - ERASEINFO(0x10000, 7), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F004B3T, -- name: "Intel 28F004B3T", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F004B3T, -+ .name = "Intel 28F004B3T", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x10000, 7), - ERASEINFO(0x02000, 8), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F400B3B, -- name: "Intel 28F400B3B", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F400B3B, -+ .name = "Intel 28F400B3B", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x02000, 8), - ERASEINFO(0x10000, 7), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F400B3T, -- name: "Intel 28F400B3T", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F400B3T, -+ .name = "Intel 28F400B3T", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x10000, 7), - ERASEINFO(0x02000, 8), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F008B3B, -- name: "Intel 28F008B3B", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F008B3B, -+ .name = "Intel 28F008B3B", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x02000, 8), - ERASEINFO(0x10000, 15), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F008B3T, -- name: "Intel 28F008B3T", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F008B3T, -+ .name = "Intel 28F008B3T", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x10000, 15), - ERASEINFO(0x02000, 8), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F008S5, -- name: "Intel 28F008S5", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_INTEL_EXT, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,16), -- } -- }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F016S5, -- name: "Intel 28F016S5", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_INTEL_EXT, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,32), -- } -- }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F008SA, -- name: "Intel 28F008SA", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 1, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F008S5, -+ .name = "Intel 28F008S5", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_INTEL_EXT, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,16), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F016S5, -+ .name = "Intel 28F016S5", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_INTEL_EXT, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,32), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F008SA, -+ .name = "Intel 28F008SA", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 1, -+ .regions = { - ERASEINFO(0x10000, 16), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F800B3B, -- name: "Intel 28F800B3B", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F800B3B, -+ .name = "Intel 28F800B3B", -+ .uaddr = { -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x02000, 8), - ERASEINFO(0x10000, 15), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F800B3T, -- name: "Intel 28F800B3T", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F800B3T, -+ .name = "Intel 28F800B3T", -+ .uaddr = { -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x10000, 15), - ERASEINFO(0x02000, 8), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F016B3B, -- name: "Intel 28F016B3B", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F016B3B, -+ .name = "Intel 28F016B3B", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x02000, 8), - ERASEINFO(0x10000, 31), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F016S3, -- name: "Intel I28F016S3", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 1, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F016S3, -+ .name = "Intel I28F016S3", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 1, -+ .regions = { - ERASEINFO(0x10000, 32), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F016B3T, -- name: "Intel 28F016B3T", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F016B3T, -+ .name = "Intel 28F016B3T", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x10000, 31), - ERASEINFO(0x02000, 8), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F160B3B, -- name: "Intel 28F160B3B", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F160B3B, -+ .name = "Intel 28F160B3B", -+ .uaddr = { -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x02000, 8), - ERASEINFO(0x10000, 31), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F160B3T, -- name: "Intel 28F160B3T", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F160B3T, -+ .name = "Intel 28F160B3T", -+ .uaddr = { -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x10000, 31), - ERASEINFO(0x02000, 8), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F320B3B, -- name: "Intel 28F320B3B", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F320B3B, -+ .name = "Intel 28F320B3B", -+ .uaddr = { -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x02000, 8), - ERASEINFO(0x10000, 63), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F320B3T, -- name: "Intel 28F320B3T", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F320B3T, -+ .name = "Intel 28F320B3T", -+ .uaddr = { -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x10000, 63), - ERASEINFO(0x02000, 8), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F640B3B, -- name: "Intel 28F640B3B", -- DevSize: SIZE_8MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F640B3B, -+ .name = "Intel 28F640B3B", -+ .uaddr = { -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_8MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x02000, 8), - ERASEINFO(0x10000, 127), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I28F640B3T, -- name: "Intel 28F640B3T", -- DevSize: SIZE_8MiB, -- CmdSet: P_ID_INTEL_STD, -- NumEraseRegions: 2, -- regions: { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I28F640B3T, -+ .name = "Intel 28F640B3T", -+ .uaddr = { -+ [1] = MTD_UADDR_UNNECESSARY, /* x16 */ -+ }, -+ .DevSize = SIZE_8MiB, -+ .CmdSet = P_ID_INTEL_STD, -+ .NumEraseRegions= 2, -+ .regions = { - ERASEINFO(0x10000, 127), - ERASEINFO(0x02000, 8), - } - }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I82802AB, -- name: "Intel 82802AB", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_INTEL_EXT, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,8), -- } -- }, { -- mfr_id: MANUFACTURER_INTEL, -- dev_id: I82802AC, -- name: "Intel 82802AC", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_INTEL_EXT, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,16), -- } -- }, { -- mfr_id: MANUFACTURER_ST, -- dev_id: M29W800T, -- name: "ST M29W800T", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,15), -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I82802AB, -+ .name = "Intel 82802AB", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_INTEL_EXT, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,8), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_INTEL, -+ .dev_id = I82802AC, -+ .name = "Intel 82802AC", -+ .uaddr = { -+ [0] = MTD_UADDR_UNNECESSARY, /* x8 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_INTEL_EXT, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,16), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_MACRONIX, -+ .dev_id = MX29LV160T, -+ .name = "MXIC MX29LV160T", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_ST, -- dev_id: M29W160DT, -- name: "ST M29W160DT", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,31), -- ERASEINFO(0x08000,1), -- ERASEINFO(0x02000,2), -- ERASEINFO(0x04000,1) -- } -- }, { -- mfr_id: MANUFACTURER_ST, -- dev_id: M29W160DB, -- name: "ST M29W160DB", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -+ .mfr_id = MANUFACTURER_MACRONIX, -+ .dev_id = MX29LV160B, -+ .name = "MXIC MX29LV160B", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { -- mfr_id: MANUFACTURER_ATMEL, -- dev_id: AT49BV512, -- name: "Atmel AT49BV512", -- DevSize: SIZE_64KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,1) -- } -- }, { -- mfr_id: MANUFACTURER_ATMEL, -- dev_id: AT29LV512, -- name: "Atmel AT29LV512", -- DevSize: SIZE_64KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: { -- ERASEINFO(0x80,256), -- ERASEINFO(0x80,256) -- } -- }, { -- mfr_id: MANUFACTURER_ATMEL, -- dev_id: AT49BV16X, -- name: "Atmel AT49BV16X", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x02000,8), -- ERASEINFO(0x10000,31) -+ .mfr_id = MANUFACTURER_MACRONIX, -+ .dev_id = MX29F016, -+ .name = "Macronix MX29F016", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,32), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_MACRONIX, -+ .dev_id = MX29F004T, -+ .name = "Macronix MX29F004T", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,7), -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x02000,2), -+ ERASEINFO(0x04000,1), - } - }, { -- mfr_id: MANUFACTURER_ATMEL, -- dev_id: AT49BV16XT, -- name: "Atmel AT49BV16XT", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x10000,31), -- ERASEINFO(0x02000,8) -+ .mfr_id = MANUFACTURER_MACRONIX, -+ .dev_id = MX29F004B, -+ .name = "Macronix MX29F004B", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), -+ ERASEINFO(0x02000,2), -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x10000,7), - } - }, { -- mfr_id: MANUFACTURER_ATMEL, -- dev_id: AT49BV32X, -- name: "Atmel AT49BV32X", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x02000,8), -- ERASEINFO(0x10000,63) -+ .mfr_id = MANUFACTURER_PMC, -+ .dev_id = PM49FL002, -+ .name = "PMC Pm49FL002", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_256KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO( 0x01000, 64 ) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_PMC, -+ .dev_id = PM49FL004, -+ .name = "PMC Pm49FL004", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO( 0x01000, 128 ) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_PMC, -+ .dev_id = PM49FL008, -+ .name = "PMC Pm49FL008", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO( 0x01000, 256 ) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST39LF512, -+ .name = "SST 39LF512", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_64KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,16), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST39LF010, -+ .name = "SST 39LF010", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_128KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,32), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST39LF020, -+ .name = "SST 39LF020", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_256KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,64), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST39LF040, -+ .name = "SST 39LF040", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,128), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST39SF010A, -+ .name = "SST 39SF010A", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_128KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,32), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST39SF020A, -+ .name = "SST 39SF020A", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_256KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,64), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST49LF004B, -+ .name = "SST 49LF004B", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,128), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST49LF030A, -+ .name = "SST 49LF030A", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,96), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST49LF040A, -+ .name = "SST 49LF040A", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,128), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_SST, -+ .dev_id = SST49LF080A, -+ .name = "SST 49LF080A", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x01000,256), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ -+ .dev_id = M29W800DT, -+ .name = "ST M29W800DT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ -+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,15), -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x02000,2), -+ ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_ATMEL, -- dev_id: AT49BV32XT, -- name: "Atmel AT49BV32XT", -- DevSize: SIZE_4MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 2, -- regions: {ERASEINFO(0x10000,63), -- ERASEINFO(0x02000,8) -+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ -+ .dev_id = M29W800DB, -+ .name = "ST M29W800DB", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ -+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ -+ }, -+ .DevSize = SIZE_1MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), -+ ERASEINFO(0x02000,2), -+ ERASEINFO(0x08000,1), -+ ERASEINFO(0x10000,15) - } - }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F017D, -- name: "AMD AM29F017D", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,32), -- } -- }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F016, -- name: "AMD AM29F016", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,32), -- } -- }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F080, -- name: "AMD AM29F080", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,16), -- } -- }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29F040, -- name: "AMD AM29F040", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,8), -- } -- }, { -- mfr_id: MANUFACTURER_AMD, -- dev_id: AM29LV040B, -- name: "AMD AM29LV040B", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,8), -- } -- }, { -- mfr_id: MANUFACTURER_ST, -- dev_id: M29W040B, -- name: "ST M29W040B", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,8), -- } -- }, { -- mfr_id: MANUFACTURER_MACRONIX, -- dev_id: MX29LV160T, -- name: "MXIC MX29LV160T", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,31), -+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ -+ .dev_id = M29W160DT, -+ .name = "ST M29W160DT", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_MACRONIX, -- dev_id: MX29LV160B, -- name: "MXIC MX29LV160B", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -+ .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ -+ .dev_id = M29W160DB, -+ .name = "ST M29W160DB", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { -- mfr_id: MANUFACTURER_MACRONIX, -- dev_id: MX29F016, -- name: "Macronix MX29F016", -- DevSize: SIZE_2MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x10000,32), -- } -- }, { -- mfr_id: MANUFACTURER_MACRONIX, -- dev_id: MX29F004T, -- name: "Macronix MX29F004T", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x10000,7), -+ .mfr_id = MANUFACTURER_ST, -+ .dev_id = M29W040B, -+ .name = "ST M29W040B", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ -+ }, -+ .DevSize = SIZE_512KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 1, -+ .regions = { -+ ERASEINFO(0x10000,8), -+ } -+ }, { -+ .mfr_id = MANUFACTURER_TOSHIBA, -+ .dev_id = TC58FVT160, -+ .name = "Toshiba TC58FVT160", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), -- ERASEINFO(0x04000,1), -+ ERASEINFO(0x04000,1) - } - }, { -- mfr_id: MANUFACTURER_MACRONIX, -- dev_id: MX29F004B, -- name: "Macronix MX29F004B", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 4, -- regions: {ERASEINFO(0x04000,1), -+ .mfr_id = MANUFACTURER_TOSHIBA, -+ .dev_id = TC58FVB160, -+ .name = "Toshiba TC58FVB160", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ -+ }, -+ .DevSize = SIZE_2MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), -- ERASEINFO(0x10000,7), -+ ERASEINFO(0x10000,31) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_TOSHIBA, -+ .dev_id = TC58FVB321, -+ .name = "Toshiba TC58FVB321", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x02000,8), -+ ERASEINFO(0x10000,63) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_TOSHIBA, -+ .dev_id = TC58FVT321, -+ .name = "Toshiba TC58FVT321", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ -+ }, -+ .DevSize = SIZE_4MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x10000,63), -+ ERASEINFO(0x02000,8) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_TOSHIBA, -+ .dev_id = TC58FVB641, -+ .name = "Toshiba TC58FVB641", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_8MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x02000,8), -+ ERASEINFO(0x10000,127) -+ } -+ }, { -+ .mfr_id = MANUFACTURER_TOSHIBA, -+ .dev_id = TC58FVT641, -+ .name = "Toshiba TC58FVT641", -+ .uaddr = { -+ [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ -+ [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ -+ }, -+ .DevSize = SIZE_8MiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 2, -+ .regions = { -+ ERASEINFO(0x10000,127), -+ ERASEINFO(0x02000,8) - } - }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST39LF512, -- name: "SST 39LF512", -- DevSize: SIZE_64KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,16), -- } -- }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST39LF010, -- name: "SST 39LF010", -- DevSize: SIZE_128KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,32), -- } -- }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST39LF020, -- name: "SST 39LF020", -- DevSize: SIZE_256KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,64), -- } -- }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST39LF040, -- name: "SST 39LF040", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,128), -- } -- }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST39SF010A, -- name: "SST 39SF010A", -- DevSize: SIZE_128KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,32), -- } -- }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST39SF020A, -- name: "SST 39SF020A", -- DevSize: SIZE_256KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,64), -- } -- }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST49LF030A, -- name: "SST 49LF030A", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,96), -- } -- }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST49LF040A, -- name: "SST 49LF040A", -- DevSize: SIZE_512KiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,128), -- } -- }, { -- mfr_id: MANUFACTURER_SST, -- dev_id: SST49LF080A, -- name: "SST 49LF080A", -- DevSize: SIZE_1MiB, -- CmdSet: P_ID_AMD_STD, -- NumEraseRegions: 1, -- regions: {ERASEINFO(0x01000,256), -+ .mfr_id = MANUFACTURER_WINBOND, -+ .dev_id = W49V002A, -+ .name = "Winbond W49V002A", -+ .uaddr = { -+ [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ -+ }, -+ .DevSize = SIZE_256KiB, -+ .CmdSet = P_ID_AMD_STD, -+ .NumEraseRegions= 4, -+ .regions = { -+ ERASEINFO(0x10000, 3), -+ ERASEINFO(0x08000, 1), -+ ERASEINFO(0x02000, 2), -+ ERASEINFO(0x04000, 1), - } - } - }; -@@ -907,7 +1452,7 @@ - static int cfi_jedec_setup(struct cfi_private *p_cfi, int index); - - static int jedec_probe_chip(struct map_info *map, __u32 base, -- struct flchip *chips, struct cfi_private *cfi); -+ unsigned long *chip_map, struct cfi_private *cfi); - - struct mtd_info *jedec_probe(struct map_info *map); - -@@ -944,11 +1489,43 @@ - * this should be safe. - */ - cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); -+ /* FIXME - should have reset delay before continuing */ -+} - -+ -+static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type) -+{ -+ int uaddr_idx; -+ __u8 uaddr = MTD_UADDR_NOT_SUPPORTED; -+ -+ switch ( device_type ) { -+ case CFI_DEVICETYPE_X8: uaddr_idx = 0; break; -+ case CFI_DEVICETYPE_X16: uaddr_idx = 1; break; -+ case CFI_DEVICETYPE_X32: uaddr_idx = 2; break; -+ default: -+ printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n", -+ __func__, device_type); -+ goto uaddr_done; -+ } -+ -+ uaddr = finfo->uaddr[uaddr_idx]; -+ -+ if (uaddr != MTD_UADDR_NOT_SUPPORTED ) { -+ /* ASSERT("The unlock addresses for non-8-bit mode -+ are bollocks. We don't really need an array."); */ -+ uaddr = finfo->uaddr[0]; -+ } -+ -+ uaddr_done: -+ return uaddr; - } -+ -+ - static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) - { - int i,num_erase_regions; -+ unsigned long mask; -+ __u8 uaddr; - - printk("Found: %s\n",jedec_table[index].name); - -@@ -971,41 +1548,170 @@ - p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i]; - } - p_cfi->cmdset_priv = 0; -+ -+ /* This may be redundant for some cases, but it doesn't hurt */ -+ p_cfi->mfr = jedec_table[index].mfr_id; -+ p_cfi->id = jedec_table[index].dev_id; -+ -+ uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type); -+ if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) { -+ kfree( p_cfi->cfiq ); -+ return 0; -+ } -+ -+ /* Mask out address bits which are smaller than the device type */ -+ mask = ~(p_cfi->device_type-1); -+ p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1 & mask; -+ p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2 & mask; -+ - return 1; /* ok */ - } - --static int jedec_probe_chip(struct map_info *map, __u32 base, -- struct flchip *chips, struct cfi_private *cfi) -+ -+/* -+ * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing -+ * the mapped address, unlock addresses, and proper chip ID. This function -+ * attempts to minimize errors. It is doubtfull that this probe will ever -+ * be perfect - consequently there should be some module parameters that -+ * could be manually specified to force the chip info. -+ */ -+static inline int jedec_match( __u32 base, -+ struct map_info *map, -+ struct cfi_private *cfi, -+ const struct amd_flash_info *finfo ) - { -- int i; -- int unlockpass = 0; -+ int rc = 0; /* failure until all tests pass */ -+ u32 mfr, id; -+ __u8 uaddr; -+ unsigned long mask; - -- if (!cfi->numchips) { -+ /* -+ * The IDs must match. For X16 and X32 devices operating in -+ * a lower width ( X8 or X16 ), the device ID's are usually just -+ * the lower byte(s) of the larger device ID for wider mode. If -+ * a part is found that doesn't fit this assumption (device id for -+ * smaller width mode is completely unrealated to full-width mode) -+ * then the jedec_table[] will have to be augmented with the IDs -+ * for different widths. -+ */ - switch (cfi->device_type) { - case CFI_DEVICETYPE_X8: -- cfi->addr_unlock1 = 0x555; -- cfi->addr_unlock2 = 0x2aa; -+ mfr = (__u8)finfo->mfr_id; -+ id = (__u8)finfo->dev_id; - break; - case CFI_DEVICETYPE_X16: -- cfi->addr_unlock1 = 0xaaa; -- if (map->buswidth == cfi->interleave) { -- /* X16 chip(s) in X8 mode */ -- cfi->addr_unlock2 = 0x555; -- } else { -- cfi->addr_unlock2 = 0x554; -- } -+ mfr = (__u16)finfo->mfr_id; -+ id = (__u16)finfo->dev_id; - break; - case CFI_DEVICETYPE_X32: -- cfi->addr_unlock1 = 0x1555; -- cfi->addr_unlock2 = 0xaaa; -+ mfr = (__u16)finfo->mfr_id; -+ id = (__u32)finfo->dev_id; - break; - default: -- printk(KERN_NOTICE "Eep. Unknown jedec_probe device type %d\n", cfi->device_type); -- return 0; -+ printk(KERN_WARNING -+ "MTD %s(): Unsupported device type %d\n", -+ __func__, cfi->device_type); -+ goto match_done; -+ } -+ if ( cfi->mfr != mfr || cfi->id != id ) { -+ goto match_done; -+ } -+ -+ /* the part size must fit in the memory window */ -+ DEBUG( MTD_DEBUG_LEVEL3, -+ "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", -+ __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) ); -+ if ( base + cfi->interleave * ( 1 << finfo->DevSize ) > map->size ) { -+ DEBUG( MTD_DEBUG_LEVEL3, -+ "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", -+ __func__, finfo->mfr_id, finfo->dev_id, -+ 1 << finfo->DevSize ); -+ goto match_done; -+ } -+ -+ uaddr = finfo_uaddr(finfo, cfi->device_type); -+ if ( uaddr == MTD_UADDR_NOT_SUPPORTED ) { -+ goto match_done; -+ } -+ -+ mask = ~(cfi->device_type-1); -+ -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", -+ __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); -+ if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr -+ && ( (unlock_addrs[uaddr].addr1 & mask) != cfi->addr_unlock1 || -+ (unlock_addrs[uaddr].addr2 & mask) != cfi->addr_unlock2 ) ) { -+ DEBUG( MTD_DEBUG_LEVEL3, -+ "MTD %s(): 0x%.4x 0x%.4x did not match\n", -+ __func__, -+ unlock_addrs[uaddr].addr1 & mask, -+ unlock_addrs[uaddr].addr2 & mask); -+ goto match_done; - } -+ -+ /* -+ * Make sure the ID's dissappear when the device is taken out of -+ * ID mode. The only time this should fail when it should succeed -+ * is when the ID's are written as data to the same -+ * addresses. For this rare and unfortunate case the chip -+ * cannot be probed correctly. -+ * FIXME - write a driver that takes all of the chip info as -+ * module parameters, doesn't probe but forces a load. -+ */ -+ DEBUG( MTD_DEBUG_LEVEL3, -+ "MTD %s(): check ID's disappear when not in ID mode\n", -+ __func__ ); -+ jedec_reset( base, map, cfi ); -+ mfr = jedec_read_mfr( map, base, cfi ); -+ id = jedec_read_id( map, base, cfi ); -+ if ( mfr == cfi->mfr && id == cfi->id ) { -+ DEBUG( MTD_DEBUG_LEVEL3, -+ "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" -+ "You might need to manually specify JEDEC parameters.\n", -+ __func__, cfi->mfr, cfi->id ); -+ goto match_done; -+ } -+ -+ /* all tests passed - mark as success */ -+ rc = 1; -+ -+ /* -+ * Put the device back in ID mode - only need to do this if we -+ * were truly frobbing a real device. -+ */ -+ DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); -+ if(cfi->addr_unlock1) { -+ cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); - } -+ cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ /* FIXME - should have a delay before continuing */ -+ -+ match_done: -+ return rc; -+} -+ -+ -+static int jedec_probe_chip(struct map_info *map, __u32 base, -+ unsigned long *chip_map, struct cfi_private *cfi) -+{ -+ int i; -+ enum uaddr uaddr_idx = MTD_UADDR_NOT_SUPPORTED; - - retry: -+ if (!cfi->numchips) { -+ unsigned long mask = ~(cfi->device_type-1); -+ -+ uaddr_idx++; -+ -+ if (MTD_UADDR_UNNECESSARY == uaddr_idx) -+ return 0; -+ -+ /* Mask out address bits which are smaller than the device type */ -+ cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1 & mask; -+ cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2 & mask; -+ } -+ - /* Make certain we aren't probing past the end of map */ - if (base >= map->size) { - printk(KERN_NOTICE -@@ -1038,6 +1744,7 @@ - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); - } - cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); -+ /* FIXME - should have a delay before continuing */ - - if (!cfi->numchips) { - /* This is the first time we're called. Set up the CFI -@@ -1045,26 +1752,21 @@ - - cfi->mfr = jedec_read_mfr(map, base, cfi); - cfi->id = jedec_read_id(map, base, cfi); -- printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n", -+ DEBUG(MTD_DEBUG_LEVEL3, -+ "Search for id:(%02x %02x) interleave(%d) type(%d)\n", - cfi->mfr, cfi->id, cfi->interleave, cfi->device_type); - for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) { -- if (cfi->mfr == jedec_table[i].mfr_id && -- cfi->id == jedec_table[i].dev_id) { -+ if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { -+ DEBUG( MTD_DEBUG_LEVEL3, -+ "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", -+ __func__, cfi->mfr, cfi->id, -+ cfi->addr_unlock1, cfi->addr_unlock2 ); - if (!cfi_jedec_setup(cfi, i)) - return 0; - goto ok_out; - } - } -- switch(unlockpass++) { -- case 0: -- cfi->addr_unlock1 |= cfi->addr_unlock1 << 4; -- cfi->addr_unlock2 |= cfi->addr_unlock2 << 4; -- goto retry; -- case 1: -- cfi->addr_unlock1 = cfi->addr_unlock2 = 0; - goto retry; -- } -- return 0; - } else { - __u16 mfr; - __u16 id; -@@ -1081,21 +1783,24 @@ - } - } - -- /* Check each previous chip to see if it's an alias */ -- for (i=0; i<cfi->numchips; i++) { -- /* This chip should be in read mode if it's one -- we've already touched. */ -- if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr && -- jedec_read_id(map, chips[i].start, cfi) == cfi->id) { -+ /* Check each previous chip locations to see if it's an alias */ -+ for (i=0; i < (base >> cfi->chipshift); i++) { -+ unsigned long start; -+ if(!test_bit(i, chip_map)) { -+ continue; /* Skip location; no valid chip at this address */ -+ } -+ start = i << cfi->chipshift; -+ if (jedec_read_mfr(map, start, cfi) == cfi->mfr && -+ jedec_read_id(map, start, cfi) == cfi->id) { - /* Eep. This chip also looks like it's in autoselect mode. - Is it an alias for the new one? */ -- jedec_reset(chips[i].start, map, cfi); -+ jedec_reset(start, map, cfi); - - /* If the device IDs go away, it's an alias */ - if (jedec_read_mfr(map, base, cfi) != cfi->mfr || - jedec_read_id(map, base, cfi) != cfi->id) { - printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", -- map->name, base, chips[i].start); -+ map->name, base, start); - return 0; - } - -@@ -1107,7 +1812,7 @@ - if (jedec_read_mfr(map, base, cfi) == cfi->mfr && - jedec_read_id(map, base, cfi) == cfi->id) { - printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", -- map->name, base, chips[i].start); -+ map->name, base, start); - return 0; - } - } -@@ -1115,13 +1820,7 @@ - - /* OK, if we got to here, then none of the previous chips appear to - be aliases for the current one. */ -- if (cfi->numchips == MAX_CFI_CHIPS) { -- printk(KERN_WARNING"%s: Too many flash chips detected. Increase MAX_CFI_CHIPS from %d.\n", map->name, MAX_CFI_CHIPS); -- /* Doesn't matter about resetting it to Read Mode - we're not going to talk to it anyway */ -- return -1; -- } -- chips[cfi->numchips].start = base; -- chips[cfi->numchips].state = FL_READY; -+ set_bit((base >> cfi->chipshift), chip_map); /* Update chip map */ - cfi->numchips++; - - ok_out: -@@ -1136,8 +1835,8 @@ - } - - static struct chip_probe jedec_chip_probe = { -- name: "JEDEC", -- probe_chip: jedec_probe_chip -+ .name = "JEDEC", -+ .probe_chip = jedec_probe_chip - }; - - struct mtd_info *jedec_probe(struct map_info *map) -@@ -1150,9 +1849,9 @@ - } - - static struct mtd_chip_driver jedec_chipdrv = { -- probe: jedec_probe, -- name: "jedec_probe", -- module: THIS_MODULE -+ .probe = jedec_probe, -+ .name = "jedec_probe", -+ .module = THIS_MODULE - }; - - int __init jedec_probe_init(void) -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/map_absent.c linux/drivers/mtd/chips/map_absent.c ---- linux-mips-2.4.27/drivers/mtd/chips/map_absent.c 2001-11-05 21:15:51.000000000 +0100 -+++ linux/drivers/mtd/chips/map_absent.c 2004-11-19 10:25:11.776218488 +0100 -@@ -1,7 +1,7 @@ - /* - * Common code to handle absent "placeholder" devices - * Copyright 2001 Resilience Corporation <ebrower@resilience.com> -- * $Id$ -+ * $Id$ - * - * This map driver is used to allocate "placeholder" MTD - * devices on systems that have socketed/removable media. -@@ -23,9 +23,10 @@ - #include <linux/kernel.h> - #include <linux/errno.h> - #include <linux/slab.h> -- -+#include <linux/init.h> -+#include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -- -+#include <linux/mtd/compatmac.h> - - static int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); - static int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -@@ -36,10 +37,10 @@ - - - static struct mtd_chip_driver map_absent_chipdrv = { -- probe: map_absent_probe, -- destroy: map_absent_destroy, -- name: "map_absent", -- module: THIS_MODULE -+ .probe = map_absent_probe, -+ .destroy = map_absent_destroy, -+ .name = "map_absent", -+ .module = THIS_MODULE - }; - - static struct mtd_info *map_absent_probe(struct map_info *map) -@@ -65,7 +66,7 @@ - mtd->flags = 0; - mtd->erasesize = PAGE_SIZE; - -- MOD_INC_USE_COUNT; -+ __module_get(THIS_MODULE); - return mtd; - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/map_ram.c linux/drivers/mtd/chips/map_ram.c ---- linux-mips-2.4.27/drivers/mtd/chips/map_ram.c 2001-11-05 21:15:51.000000000 +0100 -+++ linux/drivers/mtd/chips/map_ram.c 2004-11-19 10:25:11.777218336 +0100 -@@ -1,7 +1,7 @@ - /* - * Common code to handle map devices which are simple RAM - * (C) 2000 Red Hat. GPL'd. -- * $Id$ -+ * $Id$ - */ - - #include <linux/module.h> -@@ -11,8 +11,10 @@ - #include <asm/byteorder.h> - #include <linux/errno.h> - #include <linux/slab.h> -- -+#include <linux/init.h> -+#include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -+#include <linux/mtd/compatmac.h> - - - static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); -@@ -23,9 +25,9 @@ - - - static struct mtd_chip_driver mapram_chipdrv = { -- probe: map_ram_probe, -- name: "map_ram", -- module: THIS_MODULE -+ .probe = map_ram_probe, -+ .name = "map_ram", -+ .module = THIS_MODULE - }; - - static struct mtd_info *map_ram_probe(struct map_info *map) -@@ -34,21 +36,21 @@ - - /* Check the first byte is RAM */ - #if 0 -- map->write8(map, 0x55, 0); -- if (map->read8(map, 0) != 0x55) -+ map_write8(map, 0x55, 0); -+ if (map_read8(map, 0) != 0x55) - return NULL; - -- map->write8(map, 0xAA, 0); -- if (map->read8(map, 0) != 0xAA) -+ map_write8(map, 0xAA, 0); -+ if (map_read8(map, 0) != 0xAA) - return NULL; - - /* Check the last byte is RAM */ -- map->write8(map, 0x55, map->size-1); -- if (map->read8(map, map->size-1) != 0x55) -+ map_write8(map, 0x55, map->size-1); -+ if (map_read8(map, map->size-1) != 0x55) - return NULL; - -- map->write8(map, 0xAA, map->size-1); -- if (map->read8(map, map->size-1) != 0xAA) -+ map_write8(map, 0xAA, map->size-1); -+ if (map_read8(map, map->size-1) != 0xAA) - return NULL; - #endif - /* OK. It seems to be RAM. */ -@@ -74,7 +76,7 @@ - while(mtd->size & (mtd->erasesize - 1)) - mtd->erasesize >>= 1; - -- MOD_INC_USE_COUNT; -+ __module_get(THIS_MODULE); - return mtd; - } - -@@ -83,7 +85,7 @@ - { - struct map_info *map = (struct map_info *)mtd->priv; - -- map->copy_from(map, buf, from, len); -+ map_copy_from(map, buf, from, len); - *retlen = len; - return 0; - } -@@ -92,7 +94,7 @@ - { - struct map_info *map = (struct map_info *)mtd->priv; - -- map->copy_to(map, to, buf, len); -+ map_copy_to(map, to, buf, len); - *retlen = len; - return 0; - } -@@ -105,7 +107,7 @@ - unsigned long i; - - for (i=0; i<instr->len; i++) -- map->write8(map, 0xFF, instr->addr + i); -+ map_write8(map, 0xFF, instr->addr + i); - - if (instr->callback) - instr->callback(instr); -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/map_rom.c linux/drivers/mtd/chips/map_rom.c ---- linux-mips-2.4.27/drivers/mtd/chips/map_rom.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/chips/map_rom.c 2004-11-19 10:25:11.778218184 +0100 -@@ -1,7 +1,7 @@ - /* - * Common code to handle map devices which are simple ROM - * (C) 2000 Red Hat. GPL'd. -- * $Id$ -+ * $Id$ - */ - - #include <linux/version.h> -@@ -12,8 +12,10 @@ - #include <asm/byteorder.h> - #include <linux/errno.h> - #include <linux/slab.h> -- -+#include <linux/init.h> -+#include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -+#include <linux/mtd/compatmac.h> - - static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); - static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); -@@ -21,9 +23,9 @@ - struct mtd_info *map_rom_probe(struct map_info *map); - - static struct mtd_chip_driver maprom_chipdrv = { -- probe: map_rom_probe, -- name: "map_rom", -- module: THIS_MODULE -+ .probe = map_rom_probe, -+ .name = "map_rom", -+ .module = THIS_MODULE - }; - - struct mtd_info *map_rom_probe(struct map_info *map) -@@ -49,7 +51,7 @@ - while(mtd->size & (mtd->erasesize - 1)) - mtd->erasesize >>= 1; - -- MOD_INC_USE_COUNT; -+ __module_get(THIS_MODULE); - return mtd; - } - -@@ -58,7 +60,7 @@ - { - struct map_info *map = (struct map_info *)mtd->priv; - -- map->copy_from(map, buf, from, len); -+ map_copy_from(map, buf, from, len); - *retlen = len; - return 0; - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/chips/sharp.c linux/drivers/mtd/chips/sharp.c ---- linux-mips-2.4.27/drivers/mtd/chips/sharp.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/chips/sharp.c 2004-11-19 10:25:11.792216056 +0100 -@@ -4,7 +4,7 @@ - * Copyright 2000,2001 David A. Schleef <ds@schleef.org> - * 2000,2001 Lineo, Inc. - * -- * $Id$ -+ * $Id$ - * - * Devices supported: - * LH28F016SCT Symmetrical block flash memory, 2Mx8 -@@ -28,6 +28,7 @@ - #include <linux/errno.h> - #include <linux/interrupt.h> - #include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> - #include <linux/mtd/cfi.h> - #include <linux/delay.h> - -@@ -98,10 +99,10 @@ - static void sharp_destroy(struct mtd_info *mtd); - - static struct mtd_chip_driver sharp_chipdrv = { -- probe: sharp_probe, -- destroy: sharp_destroy, -- name: "sharp", -- module: THIS_MODULE -+ .probe = sharp_probe, -+ .destroy = sharp_destroy, -+ .name = "sharp", -+ .module = THIS_MODULE - }; - - -@@ -116,8 +117,10 @@ - return NULL; - - sharp = kmalloc(sizeof(*sharp), GFP_KERNEL); -- if(!sharp) -+ if(!sharp) { -+ kfree(mtd); - return NULL; -+ } - - memset(mtd, 0, sizeof(*mtd)); - -@@ -163,12 +166,12 @@ - u32 read0, read4; - int width = 4; - -- tmp = map->read32(map, base+0); -+ tmp = map_read32(map, base+0); - -- map->write32(map, CMD_READ_ID, base+0); -+ map_write32(map, CMD_READ_ID, base+0); - -- read0=map->read32(map, base+0); -- read4=map->read32(map, base+4); -+ read0=map_read32(map, base+0); -+ read4=map_read32(map, base+4); - if(read0 == 0x89898989){ - printk("Looks like sharp flash\n"); - switch(read4){ -@@ -196,10 +199,10 @@ - printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n", - read0,read4); - } -- }else if((map->read32(map, base+0) == CMD_READ_ID)){ -+ }else if((map_read32(map, base+0) == CMD_READ_ID)){ - /* RAM, probably */ - printk("Looks like RAM\n"); -- map->write32(map, tmp, base+0); -+ map_write32(map, tmp, base+0); - }else{ - printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n", - read0,read4); -@@ -221,10 +224,10 @@ - - switch(chip->state){ - case FL_READY: -- map->write32(map,CMD_READ_STATUS,adr); -+ map_write32(map,CMD_READ_STATUS,adr); - chip->state = FL_STATUS; - case FL_STATUS: -- status = map->read32(map,adr); -+ status = map_read32(map,adr); - //printk("status=%08x\n",status); - - udelay(100); -@@ -252,7 +255,7 @@ - goto retry; - } - -- map->write32(map,CMD_RESET, adr); -+ map_write32(map,CMD_RESET, adr); - - chip->state = FL_READY; - -@@ -293,7 +296,7 @@ - if(ret<0) - break; - -- map->copy_from(map,buf,ofs,thislen); -+ map_copy_from(map,buf,ofs,thislen); - - sharp_release(&sharp->chips[chipnum]); - -@@ -354,17 +357,17 @@ - ret = sharp_wait(map,chip); - - for(try=0;try<10;try++){ -- map->write32(map,CMD_BYTE_WRITE,adr); -+ map_write32(map,CMD_BYTE_WRITE,adr); - /* cpu_to_le32 -> hack to fix the writel be->le conversion */ -- map->write32(map,cpu_to_le32(datum),adr); -+ map_write32(map,cpu_to_le32(datum),adr); - - chip->state = FL_WRITING; - - timeo = jiffies + (HZ/2); - -- map->write32(map,CMD_READ_STATUS,adr); -+ map_write32(map,CMD_READ_STATUS,adr); - for(i=0;i<100;i++){ -- status = map->read32(map,adr); -+ status = map_read32(map,adr); - if((status & SR_READY)==SR_READY) - break; - } -@@ -377,9 +380,9 @@ - - printk("sharp: error writing byte at addr=%08lx status=%08x\n",adr,status); - -- map->write32(map,CMD_CLEAR_STATUS,adr); -+ map_write32(map,CMD_CLEAR_STATUS,adr); - } -- map->write32(map,CMD_RESET,adr); -+ map_write32(map,CMD_RESET,adr); - chip->state = FL_READY; - - wake_up(&chip->wq); -@@ -436,14 +439,14 @@ - int status; - DECLARE_WAITQUEUE(wait, current); - -- map->write32(map,CMD_READ_STATUS,adr); -- status = map->read32(map,adr); -+ map_write32(map,CMD_READ_STATUS,adr); -+ status = map_read32(map,adr); - - timeo = jiffies + HZ; - - while(time_before(jiffies, timeo)){ -- map->write32(map,CMD_READ_STATUS,adr); -- status = map->read32(map,adr); -+ map_write32(map,CMD_READ_STATUS,adr); -+ status = map_read32(map,adr); - if((status & SR_READY)==SR_READY){ - ret = 0; - goto out; -@@ -485,26 +488,26 @@ - sharp_unlock_oneblock(map,chip,adr); - #endif - -- map->write32(map,CMD_BLOCK_ERASE_1,adr); -- map->write32(map,CMD_BLOCK_ERASE_2,adr); -+ map_write32(map,CMD_BLOCK_ERASE_1,adr); -+ map_write32(map,CMD_BLOCK_ERASE_2,adr); - - chip->state = FL_ERASING; - - ret = sharp_do_wait_for_ready(map,chip,adr); - if(ret<0)return ret; - -- map->write32(map,CMD_READ_STATUS,adr); -- status = map->read32(map,adr); -+ map_write32(map,CMD_READ_STATUS,adr); -+ status = map_read32(map,adr); - - if(!(status&SR_ERRORS)){ -- map->write32(map,CMD_RESET,adr); -+ map_write32(map,CMD_RESET,adr); - chip->state = FL_READY; - //spin_unlock_bh(chip->mutex); - return 0; - } - - printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status); -- map->write32(map,CMD_CLEAR_STATUS,adr); -+ map_write32(map,CMD_CLEAR_STATUS,adr); - - //spin_unlock_bh(chip->mutex); - -@@ -518,17 +521,17 @@ - int i; - int status; - -- map->write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr); -- map->write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr); -+ map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr); -+ map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr); - - udelay(100); - -- status = map->read32(map,adr); -+ status = map_read32(map,adr); - printk("status=%08x\n",status); - - for(i=0;i<1000;i++){ -- //map->write32(map,CMD_READ_STATUS,adr); -- status = map->read32(map,adr); -+ //map_write32(map,CMD_READ_STATUS,adr); -+ status = map_read32(map,adr); - if((status & SR_READY)==SR_READY) - break; - udelay(100); -@@ -538,13 +541,13 @@ - } - - if(!(status&SR_ERRORS)){ -- map->write32(map,CMD_RESET,adr); -+ map_write32(map,CMD_RESET,adr); - chip->state = FL_READY; - return; - } - - printk("sharp: error unlocking block at addr=%08lx status=%08x\n",adr,status); -- map->write32(map,CMD_CLEAR_STATUS,adr); -+ map_write32(map,CMD_CLEAR_STATUS,adr); - } - #endif - -diff -Nurb linux-mips-2.4.27/drivers/mtd/cmdlinepart.c linux/drivers/mtd/cmdlinepart.c ---- linux-mips-2.4.27/drivers/mtd/cmdlinepart.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/cmdlinepart.c 2004-11-19 10:25:11.628240984 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Read flash partition table from command line - * -@@ -28,7 +28,7 @@ - - #include <linux/mtd/mtd.h> - #include <linux/mtd/partitions.h> --#include <asm/setup.h> -+#include <linux/mtd/compatmac.h> - #include <linux/bootmem.h> - - /* error message prefix */ -@@ -178,8 +178,7 @@ - parts[this_part].mask_flags = mask_flags; - if (name) - { -- strncpy(extra_mem, name, name_len); -- extra_mem[name_len] = 0; -+ strlcpy(extra_mem, name, name_len + 1); - } - else - { -@@ -258,8 +257,7 @@ - this_mtd->parts = parts; - this_mtd->num_parts = num_parts; - this_mtd->mtd_id = (char*)(this_mtd + 1); -- strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len); -- this_mtd->mtd_id[mtd_id_len] = 0; -+ strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); - - /* link into chain */ - this_mtd->next = partitions; -@@ -291,13 +289,14 @@ - * information. It returns partitions for the requested mtd device, or - * the first one in the chain if a NULL mtd_id is passed in. - */ --int parse_cmdline_partitions(struct mtd_info *master, -+static int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, -- const char *mtd_id) -+ unsigned long origin) - { - unsigned long offset; - int i; - struct cmdline_mtd_partition *part; -+ char *mtd_id = master->name; - - if(!cmdline) - return -EINVAL; -@@ -349,7 +348,25 @@ - - __setup("mtdparts=", mtdpart_setup); - --EXPORT_SYMBOL(parse_cmdline_partitions); -+static struct mtd_part_parser cmdline_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_cmdline_partitions, -+ .name = "cmdlinepart", -+}; -+ -+static int __init cmdline_parser_init(void) -+{ -+ return register_mtd_parser(&cmdline_parser); -+} -+ -+static void __exit cmdline_parser_exit(void) -+{ -+ deregister_mtd_parser(&cmdline_parser); -+} -+ -+module_init(cmdline_parser_init); -+module_exit(cmdline_parser_exit); -+ - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/Config.in linux/drivers/mtd/devices/Config.in ---- linux-mips-2.4.27/drivers/mtd/devices/Config.in 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/devices/Config.in 2004-11-19 10:25:11.811213168 +0100 -@@ -1,6 +1,6 @@ --# drivers/mtd/maps/Config.in -+# drivers/mtd/devices/Config.in - --# $Id$ -+# $Id$ - - mainmenu_option next_comment - -@@ -28,13 +28,13 @@ - dep_tristate ' MTD emulation using block device' CONFIG_MTD_BLKMTD $CONFIG_MTD - - comment 'Disk-On-Chip Device Drivers' -- dep_tristate ' M-Systems Disk-On-Chip 1000' CONFIG_MTD_DOC1000 $CONFIG_MTD - dep_tristate ' M-Systems Disk-On-Chip 2000 and Millennium' CONFIG_MTD_DOC2000 $CONFIG_MTD - dep_tristate ' M-Systems Disk-On-Chip Millennium-only alternative driver (see help)' CONFIG_MTD_DOC2001 $CONFIG_MTD -- if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then -+ dep_tristate ' M-Systems Disk-On-Chip Millennium Plus driver (see help)' CONFIG_MTD_DOC2001PLUS $CONFIG_MTD -+ if [ "$CONFIG_MTD_DOC2001PLUS" = "y" -o "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" ]; then - define_bool CONFIG_MTD_DOCPROBE y - else -- if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then -+ if [ "$CONFIG_MTD_DOC2001PLUS" = "m" -o "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" ]; then - define_bool CONFIG_MTD_DOCPROBE m - else - define_bool CONFIG_MTD_DOCPROBE n -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/Makefile linux/drivers/mtd/devices/Makefile ---- linux-mips-2.4.27/drivers/mtd/devices/Makefile 2002-03-30 09:15:50.000000000 +0100 -+++ linux/drivers/mtd/devices/Makefile 2004-11-19 10:25:11.813212864 +0100 -@@ -1,9 +1,12 @@ - # - # linux/drivers/devices/Makefile - # --# $Id$ -+# $Id$ - -+ifeq ($(PATCHLEVEL),4) - O_TARGET := devlink.o -+export-objs := docecc.o -+endif - - # *** BIG UGLY NOTE *** - # -@@ -12,15 +15,16 @@ - # here where previously there was none. We now have to ensure that - # doc200[01].o are linked before docprobe.o - --obj-$(CONFIG_MTD_DOC1000) += doc1000.o - obj-$(CONFIG_MTD_DOC2000) += doc2000.o - obj-$(CONFIG_MTD_DOC2001) += doc2001.o -+obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o - obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o - obj-$(CONFIG_MTD_SLRAM) += slram.o -+obj-$(CONFIG_MTD_PHRAM) += phram.o - obj-$(CONFIG_MTD_PMC551) += pmc551.o - obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o - obj-$(CONFIG_MTD_MTDRAM) += mtdram.o - obj-$(CONFIG_MTD_LART) += lart.o - obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o - --include $(TOPDIR)/Rules.make -+-include $(TOPDIR)/Rules.make -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/blkmtd-25.c linux/drivers/mtd/devices/blkmtd-25.c ---- linux-mips-2.4.27/drivers/mtd/devices/blkmtd-25.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/devices/blkmtd-25.c 2004-11-19 10:25:11.814212712 +0100 -@@ -0,0 +1,827 @@ -+/* -+ * $Id$ -+ * -+ * blkmtd.c - use a block device as a fake MTD -+ * -+ * Author: Simon Evans <spse@secret.org.uk> -+ * -+ * Copyright (C) 2001,2002 Simon Evans -+ * -+ * Licence: GPL -+ * -+ * How it works: -+ * The driver uses raw/io to read/write the device and the page -+ * cache to cache access. Writes update the page cache with the -+ * new data and mark it dirty and add the page into a BIO which -+ * is then written out. -+ * -+ * It can be loaded Read-Only to prevent erases and writes to the -+ * medium. -+ * -+ */ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/fs.h> -+#include <linux/blkdev.h> -+#include <linux/bio.h> -+#include <linux/pagemap.h> -+#include <linux/list.h> -+#include <linux/init.h> -+#include <linux/mtd/mtd.h> -+ -+ -+#define err(format, arg...) printk(KERN_ERR "blkmtd: " format "\n" , ## arg) -+#define info(format, arg...) printk(KERN_INFO "blkmtd: " format "\n" , ## arg) -+#define warn(format, arg...) printk(KERN_WARNING "blkmtd: " format "\n" , ## arg) -+#define crit(format, arg...) printk(KERN_CRIT "blkmtd: " format "\n" , ## arg) -+ -+ -+/* Default erase size in K, always make it a multiple of PAGE_SIZE */ -+#define CONFIG_MTD_BLKDEV_ERASESIZE (128 << 10) /* 128KiB */ -+#define VERSION "$Revision$" -+ -+/* Info for the block device */ -+struct blkmtd_dev { -+ struct list_head list; -+ struct block_device *blkdev; -+ struct mtd_info mtd_info; -+ struct semaphore wrbuf_mutex; -+}; -+ -+ -+/* Static info about the MTD, used in cleanup_module */ -+static LIST_HEAD(blkmtd_device_list); -+ -+ -+static void blkmtd_sync(struct mtd_info *mtd); -+ -+#define MAX_DEVICES 4 -+ -+/* Module parameters passed by insmod/modprobe */ -+char *device[MAX_DEVICES]; /* the block device to use */ -+int erasesz[MAX_DEVICES]; /* optional default erase size */ -+int ro[MAX_DEVICES]; /* optional read only flag */ -+int sync; -+ -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>"); -+MODULE_DESCRIPTION("Emulate an MTD using a block device"); -+MODULE_PARM(device, "1-4s"); -+MODULE_PARM_DESC(device, "block device to use"); -+MODULE_PARM(erasesz, "1-4i"); -+MODULE_PARM_DESC(erasesz, "optional erase size to use in KiB. eg 4=4KiB."); -+MODULE_PARM(ro, "1-4i"); -+MODULE_PARM_DESC(ro, "1=Read only, writes and erases cause errors"); -+MODULE_PARM(sync, "i"); -+MODULE_PARM_DESC(sync, "1=Synchronous writes"); -+ -+ -+/* completion handler for BIO reads */ -+static int bi_read_complete(struct bio *bio, unsigned int bytes_done, int error) -+{ -+ if (bio->bi_size) -+ return 1; -+ -+ complete((struct completion*)bio->bi_private); -+ return 0; -+} -+ -+ -+/* completion handler for BIO writes */ -+static int bi_write_complete(struct bio *bio, unsigned int bytes_done, int error) -+{ -+ const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); -+ struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; -+ -+ if (bio->bi_size) -+ return 1; -+ -+ if(!uptodate) -+ err("bi_write_complete: not uptodate\n"); -+ -+ do { -+ struct page *page = bvec->bv_page; -+ DEBUG(3, "Cleaning up page %ld\n", page->index); -+ if (--bvec >= bio->bi_io_vec) -+ prefetchw(&bvec->bv_page->flags); -+ -+ if (uptodate) { -+ SetPageUptodate(page); -+ } else { -+ ClearPageUptodate(page); -+ SetPageError(page); -+ } -+ ClearPageDirty(page); -+ unlock_page(page); -+ page_cache_release(page); -+ } while (bvec >= bio->bi_io_vec); -+ -+ complete((struct completion*)bio->bi_private); -+ return 0; -+} -+ -+ -+/* read one page from the block device */ -+static int blkmtd_readpage(struct blkmtd_dev *dev, struct page *page) -+{ -+ struct bio *bio; -+ struct completion event; -+ int err = -ENOMEM; -+ -+ if(PageUptodate(page)) { -+ DEBUG(2, "blkmtd: readpage page %ld is already upto date\n", page->index); -+ unlock_page(page); -+ return 0; -+ } -+ -+ ClearPageUptodate(page); -+ ClearPageError(page); -+ -+ bio = bio_alloc(GFP_KERNEL, 1); -+ if(bio) { -+ init_completion(&event); -+ bio->bi_bdev = dev->blkdev; -+ bio->bi_sector = page->index << (PAGE_SHIFT-9); -+ bio->bi_private = &event; -+ bio->bi_end_io = bi_read_complete; -+ if(bio_add_page(bio, page, PAGE_SIZE, 0) == PAGE_SIZE) { -+ submit_bio(READ, bio); -+ blk_run_queues(); -+ wait_for_completion(&event); -+ err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO; -+ bio_put(bio); -+ } -+ } -+ -+ if(err) -+ SetPageError(page); -+ else -+ SetPageUptodate(page); -+ flush_dcache_page(page); -+ unlock_page(page); -+ return err; -+} -+ -+ -+/* write out the current BIO and wait for it to finish */ -+static int blkmtd_write_out(struct bio *bio) -+{ -+ struct completion event; -+ int err; -+ -+ if(!bio->bi_vcnt) { -+ bio_put(bio); -+ return 0; -+ } -+ -+ init_completion(&event); -+ bio->bi_private = &event; -+ bio->bi_end_io = bi_write_complete; -+ submit_bio(WRITE, bio); -+ blk_run_queues(); -+ wait_for_completion(&event); -+ DEBUG(3, "submit_bio completed, bi_vcnt = %d\n", bio->bi_vcnt); -+ err = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : -EIO; -+ bio_put(bio); -+ return err; -+} -+ -+ -+/** -+ * blkmtd_add_page - add a page to the current BIO -+ * @bio: bio to add to (NULL to alloc initial bio) -+ * @blkdev: block device -+ * @page: page to add -+ * @pagecnt: pages left to add -+ * -+ * Adds a page to the current bio, allocating it if necessary. If it cannot be -+ * added, the current bio is written out and a new one is allocated. Returns -+ * the new bio to add or NULL on error -+ */ -+static struct bio *blkmtd_add_page(struct bio *bio, struct block_device *blkdev, -+ struct page *page, int pagecnt) -+{ -+ -+ retry: -+ if(!bio) { -+ bio = bio_alloc(GFP_KERNEL, pagecnt); -+ if(!bio) -+ return NULL; -+ bio->bi_sector = page->index << (PAGE_SHIFT-9); -+ bio->bi_bdev = blkdev; -+ } -+ -+ if(bio_add_page(bio, page, PAGE_SIZE, 0) != PAGE_SIZE) { -+ blkmtd_write_out(bio); -+ bio = NULL; -+ goto retry; -+ } -+ return bio; -+} -+ -+ -+/** -+ * write_pages - write block of data to device via the page cache -+ * @dev: device to write to -+ * @buf: data source or NULL if erase (output is set to 0xff) -+ * @to: offset into output device -+ * @len: amount to data to write -+ * @retlen: amount of data written -+ * -+ * Grab pages from the page cache and fill them with the source data. -+ * Non page aligned start and end result in a readin of the page and -+ * part of the page being modified. Pages are added to the bio and then written -+ * out. -+ */ -+static int write_pages(struct blkmtd_dev *dev, const u_char *buf, loff_t to, -+ size_t len, size_t *retlen) -+{ -+ int pagenr, offset; -+ size_t start_len = 0, end_len; -+ int pagecnt = 0; -+ int err = 0; -+ struct bio *bio = NULL; -+ size_t thislen = 0; -+ -+ pagenr = to >> PAGE_SHIFT; -+ offset = to & ~PAGE_MASK; -+ -+ DEBUG(2, "blkmtd: write_pages: buf = %p to = %ld len = %d pagenr = %d offset = %d\n", -+ buf, (long)to, len, pagenr, offset); -+ -+ /* see if we have to do a partial write at the start */ -+ if(offset) { -+ start_len = ((offset + len) > PAGE_SIZE) ? PAGE_SIZE - offset : len; -+ len -= start_len; -+ } -+ -+ /* calculate the length of the other two regions */ -+ end_len = len & ~PAGE_MASK; -+ len -= end_len; -+ -+ if(start_len) -+ pagecnt++; -+ -+ if(len) -+ pagecnt += len >> PAGE_SHIFT; -+ -+ if(end_len) -+ pagecnt++; -+ -+ down(&dev->wrbuf_mutex); -+ -+ DEBUG(3, "blkmtd: write: start_len = %d len = %d end_len = %d pagecnt = %d\n", -+ start_len, len, end_len, pagecnt); -+ -+ if(start_len) { -+ /* do partial start region */ -+ struct page *page; -+ -+ DEBUG(3, "blkmtd: write: doing partial start, page = %d len = %d offset = %d\n", -+ pagenr, start_len, offset); -+ -+ BUG_ON(!buf); -+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev); -+ lock_page(page); -+ if(PageDirty(page)) { -+ err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d\n", -+ to, start_len, len, end_len, pagenr); -+ BUG(); -+ } -+ memcpy(page_address(page)+offset, buf, start_len); -+ SetPageDirty(page); -+ SetPageUptodate(page); -+ buf += start_len; -+ thislen = start_len; -+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt); -+ if(!bio) { -+ err = -ENOMEM; -+ err("bio_add_page failed\n"); -+ goto write_err; -+ } -+ pagecnt--; -+ pagenr++; -+ } -+ -+ /* Now do the main loop to a page aligned, n page sized output */ -+ if(len) { -+ int pagesc = len >> PAGE_SHIFT; -+ DEBUG(3, "blkmtd: write: whole pages start = %d, count = %d\n", -+ pagenr, pagesc); -+ while(pagesc) { -+ struct page *page; -+ -+ /* see if page is in the page cache */ -+ DEBUG(3, "blkmtd: write: grabbing page %d from page cache\n", pagenr); -+ page = grab_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr); -+ if(PageDirty(page)) { -+ BUG(); -+ } -+ if(!page) { -+ warn("write: cannot grab cache page %d", pagenr); -+ err = -ENOMEM; -+ goto write_err; -+ } -+ if(!buf) { -+ memset(page_address(page), 0xff, PAGE_SIZE); -+ } else { -+ memcpy(page_address(page), buf, PAGE_SIZE); -+ buf += PAGE_SIZE; -+ } -+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt); -+ if(!bio) { -+ err = -ENOMEM; -+ err("bio_add_page failed\n"); -+ goto write_err; -+ } -+ pagenr++; -+ pagecnt--; -+ SetPageDirty(page); -+ SetPageUptodate(page); -+ pagesc--; -+ thislen += PAGE_SIZE; -+ } -+ } -+ -+ if(end_len) { -+ /* do the third region */ -+ struct page *page; -+ DEBUG(3, "blkmtd: write: doing partial end, page = %d len = %d\n", -+ pagenr, end_len); -+ BUG_ON(!buf); -+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev); -+ lock_page(page); -+ if(PageDirty(page)) { -+ err("to = %lld start_len = %d len = %d end_len = %d pagenr = %d\n", -+ to, start_len, len, end_len, pagenr); -+ BUG(); -+ } -+ memcpy(page_address(page), buf, end_len); -+ SetPageDirty(page); -+ SetPageUptodate(page); -+ DEBUG(3, "blkmtd: write: writing out partial end\n"); -+ thislen += end_len; -+ bio = blkmtd_add_page(bio, dev->blkdev, page, pagecnt); -+ if(!bio) { -+ err = -ENOMEM; -+ err("bio_add_page failed\n"); -+ goto write_err; -+ } -+ pagenr++; -+ } -+ -+ DEBUG(3, "blkmtd: write: got %d vectors to write\n", bio->bi_vcnt); -+ write_err: -+ if(bio) -+ blkmtd_write_out(bio); -+ -+ DEBUG(2, "blkmtd: write: end, retlen = %d, err = %d\n", *retlen, err); -+ up(&dev->wrbuf_mutex); -+ -+ if(retlen) -+ *retlen = thislen; -+ return err; -+} -+ -+ -+/* erase a specified part of the device */ -+static int blkmtd_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ struct blkmtd_dev *dev = mtd->priv; -+ struct mtd_erase_region_info *einfo = mtd->eraseregions; -+ int numregions = mtd->numeraseregions; -+ size_t from; -+ u_long len; -+ int err = -EIO; -+ int retlen; -+ -+ instr->state = MTD_ERASING; -+ from = instr->addr; -+ len = instr->len; -+ -+ /* check erase region has valid start and length */ -+ DEBUG(2, "blkmtd: erase: dev = `%s' from = 0x%x len = 0x%lx\n", -+ mtd->name+9, from, len); -+ while(numregions) { -+ DEBUG(3, "blkmtd: checking erase region = 0x%08X size = 0x%X num = 0x%x\n", -+ einfo->offset, einfo->erasesize, einfo->numblocks); -+ if(from >= einfo->offset -+ && from < einfo->offset + (einfo->erasesize * einfo->numblocks)) { -+ if(len == einfo->erasesize -+ && ( (from - einfo->offset) % einfo->erasesize == 0)) -+ break; -+ } -+ numregions--; -+ einfo++; -+ } -+ -+ if(!numregions) { -+ /* Not a valid erase block */ -+ err("erase: invalid erase request 0x%lX @ 0x%08X", len, from); -+ instr->state = MTD_ERASE_FAILED; -+ err = -EIO; -+ } -+ -+ if(instr->state != MTD_ERASE_FAILED) { -+ /* do the erase */ -+ DEBUG(3, "Doing erase from = %d len = %ld\n", from, len); -+ err = write_pages(dev, NULL, from, len, &retlen); -+ if(err || retlen != len) { -+ err("erase failed err = %d", err); -+ instr->state = MTD_ERASE_FAILED; -+ } else { -+ instr->state = MTD_ERASE_DONE; -+ } -+ } -+ -+ DEBUG(3, "blkmtd: erase: checking callback\n"); -+ if (instr->callback) { -+ (*(instr->callback))(instr); -+ } -+ DEBUG(2, "blkmtd: erase: finished (err = %d)\n", err); -+ return err; -+} -+ -+ -+/* read a range of the data via the page cache */ -+static int blkmtd_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ struct blkmtd_dev *dev = mtd->priv; -+ int err = 0; -+ int offset; -+ int pagenr, pages; -+ size_t thislen = 0; -+ -+ DEBUG(2, "blkmtd: read: dev = `%s' from = %ld len = %d buf = %p\n", -+ mtd->name+9, (long int)from, len, buf); -+ -+ if(from > mtd->size) -+ return -EINVAL; -+ if(from + len > mtd->size) -+ len = mtd->size - from; -+ -+ pagenr = from >> PAGE_SHIFT; -+ offset = from - (pagenr << PAGE_SHIFT); -+ -+ pages = (offset+len+PAGE_SIZE-1) >> PAGE_SHIFT; -+ DEBUG(3, "blkmtd: read: pagenr = %d offset = %d, pages = %d\n", -+ pagenr, offset, pages); -+ -+ while(pages) { -+ struct page *page; -+ int cpylen; -+ -+ DEBUG(3, "blkmtd: read: looking for page: %d\n", pagenr); -+ page = read_cache_page(dev->blkdev->bd_inode->i_mapping, pagenr, (filler_t *)blkmtd_readpage, dev); -+ if(IS_ERR(page)) { -+ err = -EIO; -+ goto readerr; -+ } -+ -+ cpylen = (PAGE_SIZE > len) ? len : PAGE_SIZE; -+ if(offset+cpylen > PAGE_SIZE) -+ cpylen = PAGE_SIZE-offset; -+ -+ memcpy(buf + thislen, page_address(page) + offset, cpylen); -+ offset = 0; -+ len -= cpylen; -+ thislen += cpylen; -+ pagenr++; -+ pages--; -+ if(!PageDirty(page)) -+ page_cache_release(page); -+ } -+ -+ readerr: -+ if(retlen) -+ *retlen = thislen; -+ DEBUG(2, "blkmtd: end read: retlen = %d, err = %d\n", thislen, err); -+ return err; -+} -+ -+ -+/* write data to the underlying device */ -+static int blkmtd_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ struct blkmtd_dev *dev = mtd->priv; -+ int err; -+ -+ if(!len) -+ return 0; -+ -+ DEBUG(2, "blkmtd: write: dev = `%s' to = %ld len = %d buf = %p\n", -+ mtd->name+9, (long int)to, len, buf); -+ -+ if(to >= mtd->size) { -+ return -ENOSPC; -+ } -+ -+ if(to + len > mtd->size) { -+ len = mtd->size - to; -+ } -+ -+ err = write_pages(dev, buf, to, len, retlen); -+ if(err > 0) -+ err = 0; -+ DEBUG(2, "blkmtd: write: end, err = %d\n", err); -+ return err; -+} -+ -+ -+/* sync the device - wait until the write queue is empty */ -+static void blkmtd_sync(struct mtd_info *mtd) -+{ -+ /* Currently all writes are synchronous */ -+} -+ -+ -+static void free_device(struct blkmtd_dev *dev) -+{ -+ DEBUG(2, "blkmtd: free_device() dev = %p\n", dev); -+ if(dev) { -+ if(dev->mtd_info.eraseregions) -+ kfree(dev->mtd_info.eraseregions); -+ if(dev->mtd_info.name) -+ kfree(dev->mtd_info.name); -+ -+ if(dev->blkdev) { -+ invalidate_inode_pages(dev->blkdev->bd_inode->i_mapping); -+ close_bdev_excl(dev->blkdev, BDEV_RAW); -+ } -+ kfree(dev); -+ } -+} -+ -+ -+/* For a given size and initial erase size, calculate the number -+ * and size of each erase region. Goes round the loop twice, -+ * once to find out how many regions, then allocates space, -+ * then round the loop again to fill it in. -+ */ -+static struct mtd_erase_region_info *calc_erase_regions( -+ size_t erase_size, size_t total_size, int *regions) -+{ -+ struct mtd_erase_region_info *info = NULL; -+ -+ DEBUG(2, "calc_erase_regions, es = %d size = %d regions = %d\n", -+ erase_size, total_size, *regions); -+ /* Make any user specified erasesize be a power of 2 -+ and at least PAGE_SIZE */ -+ if(erase_size) { -+ int es = erase_size; -+ erase_size = 1; -+ while(es != 1) { -+ es >>= 1; -+ erase_size <<= 1; -+ } -+ if(erase_size < PAGE_SIZE) -+ erase_size = PAGE_SIZE; -+ } else { -+ erase_size = CONFIG_MTD_BLKDEV_ERASESIZE; -+ } -+ -+ *regions = 0; -+ -+ do { -+ int tot_size = total_size; -+ int er_size = erase_size; -+ int count = 0, offset = 0, regcnt = 0; -+ -+ while(tot_size) { -+ count = tot_size / er_size; -+ if(count) { -+ tot_size = tot_size % er_size; -+ if(info) { -+ DEBUG(2, "adding to erase info off=%d er=%d cnt=%d\n", -+ offset, er_size, count); -+ (info+regcnt)->offset = offset; -+ (info+regcnt)->erasesize = er_size; -+ (info+regcnt)->numblocks = count; -+ (*regions)++; -+ } -+ regcnt++; -+ offset += (count * er_size); -+ } -+ while(er_size > tot_size) -+ er_size >>= 1; -+ } -+ if(info == NULL) { -+ info = kmalloc(regcnt * sizeof(struct mtd_erase_region_info), GFP_KERNEL); -+ if(!info) -+ break; -+ } -+ } while(!(*regions)); -+ DEBUG(2, "calc_erase_regions done, es = %d size = %d regions = %d\n", -+ erase_size, total_size, *regions); -+ return info; -+} -+ -+ -+extern dev_t __init name_to_dev_t(const char *line); -+ -+static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size) -+{ -+ struct block_device *bdev; -+ int mode; -+ struct blkmtd_dev *dev; -+ -+ if(!devname) -+ return NULL; -+ -+ /* Get a handle on the device */ -+ -+ -+#ifdef MODULE -+ mode = (readonly) ? O_RDONLY : O_RDWR; -+ bdev = open_bdev_excl(devname, mode, BDEV_RAW, NULL); -+#else -+ mode = (readonly) ? FMODE_READ : FMODE_WRITE; -+ bdev = open_by_devnum(name_to_dev_t(devname), mode, BDEV_RAW); -+#endif -+ if(IS_ERR(bdev)) { -+ err("error: cannot open device %s", devname); -+ DEBUG(2, "blkmtd: opening bdev returned %ld\n", PTR_ERR(bdev)); -+ return NULL; -+ } -+ -+ DEBUG(1, "blkmtd: found a block device major = %d, minor = %d\n", -+ MAJOR(bdev->bd_dev), MINOR(bdev->bd_dev)); -+ -+ if(MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) { -+ err("attempting to use an MTD device as a block device"); -+ blkdev_put(bdev, BDEV_RAW); -+ return NULL; -+ } -+ -+ dev = kmalloc(sizeof(struct blkmtd_dev), GFP_KERNEL); -+ if(dev == NULL) { -+ blkdev_put(bdev, BDEV_RAW); -+ return NULL; -+ } -+ -+ memset(dev, 0, sizeof(struct blkmtd_dev)); -+ if(!readonly) { -+ init_MUTEX(&dev->wrbuf_mutex); -+ } -+ -+ dev->blkdev = bdev; -+ dev->mtd_info.size = dev->blkdev->bd_inode->i_size & PAGE_MASK; -+ -+ /* Setup the MTD structure */ -+ /* make the name contain the block device in */ -+ dev->mtd_info.name = kmalloc(sizeof("blkmtd: ") + strlen(devname), GFP_KERNEL); -+ if(dev->mtd_info.name == NULL) -+ goto devinit_err; -+ -+ sprintf(dev->mtd_info.name, "blkmtd: %s", devname); -+ dev->mtd_info.eraseregions = calc_erase_regions(erase_size, dev->mtd_info.size, -+ &dev->mtd_info.numeraseregions); -+ if(dev->mtd_info.eraseregions == NULL) -+ goto devinit_err; -+ -+ dev->mtd_info.erasesize = dev->mtd_info.eraseregions->erasesize; -+ DEBUG(1, "blkmtd: init: found %d erase regions\n", -+ dev->mtd_info.numeraseregions); -+ -+ if(readonly) { -+ dev->mtd_info.type = MTD_ROM; -+ dev->mtd_info.flags = MTD_CAP_ROM; -+ } else { -+ dev->mtd_info.type = MTD_RAM; -+ dev->mtd_info.flags = MTD_CAP_RAM; -+ dev->mtd_info.erase = blkmtd_erase; -+ dev->mtd_info.write = blkmtd_write; -+ dev->mtd_info.writev = default_mtd_writev; -+ dev->mtd_info.sync = blkmtd_sync; -+ } -+ dev->mtd_info.read = blkmtd_read; -+ dev->mtd_info.readv = default_mtd_readv; -+ dev->mtd_info.priv = dev; -+ dev->mtd_info.owner = THIS_MODULE; -+ -+ list_add(&dev->list, &blkmtd_device_list); -+ if (add_mtd_device(&dev->mtd_info)) { -+ /* Device didnt get added, so free the entry */ -+ list_del(&dev->list); -+ goto devinit_err; -+ } else { -+ info("mtd%d: [%s] erase_size = %dKiB %s", -+ dev->mtd_info.index, dev->mtd_info.name + strlen("blkmtd: "), -+ dev->mtd_info.erasesize >> 10, -+ readonly ? "(read-only)" : ""); -+ } -+ -+ return dev; -+ -+ devinit_err: -+ free_device(dev); -+ return NULL; -+} -+ -+ -+/* Cleanup and exit - sync the device and kill of the kernel thread */ -+static void __devexit cleanup_blkmtd(void) -+{ -+ struct list_head *temp1, *temp2; -+ -+ /* Remove the MTD devices */ -+ list_for_each_safe(temp1, temp2, &blkmtd_device_list) { -+ struct blkmtd_dev *dev = list_entry(temp1, struct blkmtd_dev, -+ list); -+ blkmtd_sync(&dev->mtd_info); -+ del_mtd_device(&dev->mtd_info); -+ info("mtd%d: [%s] removed", dev->mtd_info.index, -+ dev->mtd_info.name + strlen("blkmtd: ")); -+ list_del(&dev->list); -+ free_device(dev); -+ } -+} -+ -+#ifndef MODULE -+ -+/* Handle kernel boot params */ -+ -+ -+static int __init param_blkmtd_device(char *str) -+{ -+ int i; -+ -+ for(i = 0; i < MAX_DEVICES; i++) { -+ device[i] = str; -+ DEBUG(2, "blkmtd: device setup: %d = %s\n", i, device[i]); -+ strsep(&str, ","); -+ } -+ return 1; -+} -+ -+ -+static int __init param_blkmtd_erasesz(char *str) -+{ -+ int i; -+ for(i = 0; i < MAX_DEVICES; i++) { -+ char *val = strsep(&str, ","); -+ if(val) -+ erasesz[i] = simple_strtoul(val, NULL, 0); -+ DEBUG(2, "blkmtd: erasesz setup: %d = %d\n", i, erasesz[i]); -+ } -+ -+ return 1; -+} -+ -+ -+static int __init param_blkmtd_ro(char *str) -+{ -+ int i; -+ for(i = 0; i < MAX_DEVICES; i++) { -+ char *val = strsep(&str, ","); -+ if(val) -+ ro[i] = simple_strtoul(val, NULL, 0); -+ DEBUG(2, "blkmtd: ro setup: %d = %d\n", i, ro[i]); -+ } -+ -+ return 1; -+} -+ -+ -+static int __init param_blkmtd_sync(char *str) -+{ -+ if(str[0] == '1') -+ sync = 1; -+ return 1; -+} -+ -+__setup("blkmtd_device=", param_blkmtd_device); -+__setup("blkmtd_erasesz=", param_blkmtd_erasesz); -+__setup("blkmtd_ro=", param_blkmtd_ro); -+__setup("blkmtd_sync=", param_blkmtd_sync); -+ -+#endif -+ -+ -+/* Startup */ -+static int __init init_blkmtd(void) -+{ -+ int i; -+ -+ info("version " VERSION); -+ /* Check args - device[0] is the bare minimum*/ -+ if(!device[0]) { -+ err("error: missing `device' name\n"); -+ return -EINVAL; -+ } -+ -+ for(i = 0; i < MAX_DEVICES; i++) -+ add_device(device[i], ro[i], erasesz[i] << 10); -+ -+ if(list_empty(&blkmtd_device_list)) -+ return -EINVAL; -+ -+ return 0; -+} -+ -+module_init(init_blkmtd); -+module_exit(cleanup_blkmtd); -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/blkmtd.c linux/drivers/mtd/devices/blkmtd.c ---- linux-mips-2.4.27/drivers/mtd/devices/blkmtd.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/devices/blkmtd.c 2004-11-19 10:25:11.816212408 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * blkmtd.c - use a block device as a fake MTD - * -@@ -143,7 +143,7 @@ - for(cnt = 0; cnt < pages; cnt++) { - page = grab_cache_page(dev->binding->bd_inode->i_mapping, pagenrs[cnt]); - pagelst[cnt] = page; -- if(!PageUptodate(page)) { -+ if(!Page_Uptodate(page)) { - iobuf->blocks[iobuf->nr_pages] = pagenrs[cnt]; - iobuf->maplist[iobuf->nr_pages++] = page; - } -@@ -912,7 +912,7 @@ - dev->mtd_info.point = 0; - dev->mtd_info.unpoint = 0; - dev->mtd_info.priv = dev; -- dev->mtd_info.module = THIS_MODULE; -+ dev->mtd_info.owner = THIS_MODULE; - - list_add(&dev->list, &blkmtd_device_list); - if (add_mtd_device(&dev->mtd_info)) { -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/doc2000.c linux/drivers/mtd/devices/doc2000.c ---- linux-mips-2.4.27/drivers/mtd/devices/doc2000.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/devices/doc2000.c 2004-11-19 10:25:11.818212104 +0100 -@@ -4,7 +4,7 @@ - * (c) 1999 Machine Vision Holdings, Inc. - * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/kernel.h> -@@ -25,6 +25,7 @@ - #include <linux/mtd/doc2000.h> - - #define DOC_SUPPORT_2000 -+#define DOC_SUPPORT_2000TSOP - #define DOC_SUPPORT_MILLENNIUM - - #ifdef DOC_SUPPORT_2000 -@@ -33,7 +34,7 @@ - #define DoC_is_2000(doc) (0) - #endif - --#ifdef DOC_SUPPORT_MILLENNIUM -+#if defined(DOC_SUPPORT_2000TSOP) || defined(DOC_SUPPORT_MILLENNIUM) - #define DoC_is_Millennium(doc) (doc->ChipID == DOC_ChipID_DocMil) - #else - #define DoC_is_Millennium(doc) (0) -@@ -56,6 +57,9 @@ - size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel); - static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel); -+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs, -+ unsigned long count, loff_t to, size_t *retlen, -+ u_char *eccbuf, struct nand_oobinfo *oobsel); - static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, - size_t *retlen, u_char *buf); - static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, -@@ -92,6 +96,10 @@ - - /* Out-of-line routine to wait for chip response */ - while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { -+ /* issue 2 read from NOP register after reading from CDSNControl register -+ see Software Requirement 11.4 item 2. */ -+ DoC_Delay(doc, 2); -+ - if (time_after(jiffies, timeo)) { - DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); - return -EIO; -@@ -145,6 +153,8 @@ - - /* Send the command */ - WriteDOC_(command, docptr, doc->ioreg); -+ if (DoC_is_Millennium(doc)) -+ WriteDOC(command, docptr, WritePipeTerm); - - /* Lower the CLE line */ - WriteDOC(xtraflags | CDSN_CTRL_CE, docptr, CDSNControl); -@@ -206,6 +216,9 @@ - } - } - -+ if (DoC_is_Millennium(doc)) -+ WriteDOC(ofs & 0xff, docptr, WritePipeTerm); -+ - DoC_Delay(doc, 2); /* Needed for some slow flash chips. mf. */ - - /* FIXME: The SlowIO's for millennium could be replaced by -@@ -344,15 +357,25 @@ - - /* Read the manufacturer and device id codes from the device */ - -- /* CDSN Slow IO register see Software Requirement 11.4 item 5. */ -+ if (DoC_is_Millennium(doc)) { -+ DoC_Delay(doc, 2); -+ dummy = ReadDOC(doc->virtadr, ReadPipeInit); -+ mfr = ReadDOC(doc->virtadr, LastDataRead); -+ -+ DoC_Delay(doc, 2); -+ dummy = ReadDOC(doc->virtadr, ReadPipeInit); -+ id = ReadDOC(doc->virtadr, LastDataRead); -+ } else { -+ /* CDSN Slow IO register see Software Req 11.4 item 5. */ - dummy = ReadDOC(doc->virtadr, CDSNSlowIO); - DoC_Delay(doc, 2); - mfr = ReadDOC_(doc->virtadr, doc->ioreg); - -- /* CDSN Slow IO register see Software Requirement 11.4 item 5. */ -+ /* CDSN Slow IO register see Software Req 11.4 item 5. */ - dummy = ReadDOC(doc->virtadr, CDSNSlowIO); - DoC_Delay(doc, 2); - id = ReadDOC_(doc->virtadr, doc->ioreg); -+ } - - /* No response - return failure */ - if (mfr == 0xff || mfr == 0) -@@ -410,20 +433,16 @@ - - /* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ - --static void DoC_ScanChips(struct DiskOnChip *this) -+static void DoC_ScanChips(struct DiskOnChip *this, int maxchips) - { - int floor, chip; - int numchips[MAX_FLOORS]; -- int maxchips = MAX_CHIPS; - int ret = 1; - - this->numchips = 0; - this->mfr = 0; - this->id = 0; - -- if (DoC_is_Millennium(this)) -- maxchips = MAX_CHIPS_MIL; -- - /* For each floor, find the number of valid chips it contains */ - for (floor = 0; floor < MAX_FLOORS; floor++) { - ret = 1; -@@ -515,6 +534,7 @@ - { - struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv; - struct DiskOnChip *old = NULL; -+ int maxchips; - - /* We must avoid being called twice for the same device. */ - -@@ -538,14 +558,28 @@ - - - switch (this->ChipID) { -+ case DOC_ChipID_Doc2kTSOP: -+ mtd->name = "DiskOnChip 2000 TSOP"; -+ this->ioreg = DoC_Mil_CDSN_IO; -+ /* Pretend it's a Millennium */ -+ this->ChipID = DOC_ChipID_DocMil; -+ maxchips = MAX_CHIPS; -+ break; - case DOC_ChipID_Doc2k: - mtd->name = "DiskOnChip 2000"; - this->ioreg = DoC_2k_CDSN_IO; -+ maxchips = MAX_CHIPS; - break; - case DOC_ChipID_DocMil: - mtd->name = "DiskOnChip Millennium"; - this->ioreg = DoC_Mil_CDSN_IO; -+ maxchips = MAX_CHIPS_MIL; - break; -+ default: -+ printk("Unknown ChipID 0x%02x\n", this->ChipID); -+ kfree(mtd); -+ iounmap((void *) this->virtadr); -+ return; - } - - printk(KERN_NOTICE "%s found at address 0x%lX\n", mtd->name, -@@ -553,11 +587,12 @@ - - mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH; -+ mtd->ecctype = MTD_ECC_RS_DiskOnChip; - mtd->size = 0; - mtd->erasesize = 0; - mtd->oobblock = 512; - mtd->oobsize = 16; -- mtd->module = THIS_MODULE; -+ mtd->owner = THIS_MODULE; - mtd->erase = doc_erase; - mtd->point = NULL; - mtd->unpoint = NULL; -@@ -565,6 +600,7 @@ - mtd->write = doc_write; - mtd->read_ecc = doc_read_ecc; - mtd->write_ecc = doc_write_ecc; -+ mtd->writev_ecc = doc_writev_ecc; - mtd->read_oob = doc_read_oob; - mtd->write_oob = doc_write_oob; - mtd->sync = NULL; -@@ -577,7 +613,7 @@ - init_MUTEX(&this->lock); - - /* Ident all the chips present. */ -- DoC_ScanChips(this); -+ DoC_ScanChips(this, maxchips); - - if (!this->totlen) { - kfree(mtd); -@@ -608,6 +644,7 @@ - unsigned char syndrome[6]; - volatile char dummy; - int i, len256 = 0, ret=0; -+ size_t left = len; - - docptr = this->virtadr; - -@@ -617,6 +654,10 @@ - - down(&this->lock); - -+ *retlen = 0; -+ while (left) { -+ len = left; -+ - /* Don't allow a single read to cross a 512-byte block boundary */ - if (from + len > ((from | 0x1ff) + 1)) - len = ((from | 0x1ff) + 1) - from; -@@ -673,7 +714,7 @@ - DoC_ReadBuf(this, &buf[len256], len - len256); - - /* Let the caller know we completed it */ -- *retlen = len; -+ *retlen += len; - - if (eccbuf) { - /* Read the ECC data through the DiskOnChip ECC logic */ -@@ -730,11 +771,16 @@ - - /* according to 11.4.1, we need to wait for the busy line - * drop if we read to the end of the page. */ -- if(0 == ((from + *retlen) & 0x1ff)) -+ if(0 == ((from + len) & 0x1ff)) - { - DoC_WaitReady(this); - } - -+ from += len; -+ left -= len; -+ buf += len; -+ } -+ - up(&this->lock); - - return ret; -@@ -757,6 +803,8 @@ - volatile char dummy; - int len256 = 0; - struct Nand *mychip; -+ size_t left = len; -+ int status; - - docptr = this->virtadr; - -@@ -766,15 +814,21 @@ - - down(&this->lock); - -+ *retlen = 0; -+ while (left) { -+ len = left; -+ - /* Don't allow a single write to cross a 512-byte block boundary */ - if (to + len > ((to | 0x1ff) + 1)) - len = ((to | 0x1ff) + 1) - to; - - /* The ECC will not be calculated correctly if less than 512 is written */ -+/* DBB- - if (len != 0x200 && eccbuf) - printk(KERN_WARNING - "ECC needs a full sector write (adr: %lx size %lx)\n", - (long) to, (long) len); -+ -DBB */ - - /* printk("DoC_Write (adr: %lx size %lx)\n", (long) to, (long) len); */ - -@@ -853,6 +907,9 @@ - WriteDOC_(0, docptr, this->ioreg); - } - -+ WriteDOC(CDSN_CTRL_ECC_IO | CDSN_CTRL_FLASH_IO | CDSN_CTRL_CE, docptr, -+ CDSNControl); -+ - /* Read the ECC data through the DiskOnChip ECC logic */ - for (di = 0; di < 6; di++) { - eccbuf[di] = ReadDOC(docptr, ECCSyndrome0 + di); -@@ -874,10 +931,16 @@ - DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); - /* There's an implicit DoC_WaitReady() in DoC_Command */ - -+ if (DoC_is_Millennium(this)) { -+ ReadDOC(docptr, ReadPipeInit); -+ status = ReadDOC(docptr, LastDataRead); -+ } else { - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); -+ status = ReadDOC_(docptr, this->ioreg); -+ } - -- if (ReadDOC_(docptr, this->ioreg) & 1) { -+ if (status & 1) { - printk(KERN_ERR "Error programming flash\n"); - /* Error in programming */ - *retlen = 0; -@@ -886,7 +949,7 @@ - } - - /* Let the caller know we completed it */ -- *retlen = len; -+ *retlen += len; - - if (eccbuf) { - unsigned char x[8]; -@@ -901,13 +964,81 @@ - x[7]=0x55; - - ret = doc_write_oob_nolock(mtd, to, 8, &dummy, x); -+ if (ret) { - up(&this->lock); - return ret; - } -+ } -+ -+ to += len; -+ left -= len; -+ buf += len; -+ } -+ - up(&this->lock); - return 0; - } - -+static int doc_writev_ecc(struct mtd_info *mtd, const struct iovec *vecs, -+ unsigned long count, loff_t to, size_t *retlen, -+ u_char *eccbuf, struct nand_oobinfo *oobsel) -+{ -+ static char static_buf[512]; -+ static DECLARE_MUTEX(writev_buf_sem); -+ -+ size_t totretlen = 0; -+ size_t thisvecofs = 0; -+ int ret= 0; -+ -+ down(&writev_buf_sem); -+ -+ while(count) { -+ size_t thislen, thisretlen; -+ unsigned char *buf; -+ -+ buf = vecs->iov_base + thisvecofs; -+ thislen = vecs->iov_len - thisvecofs; -+ -+ -+ if (thislen >= 512) { -+ thislen = thislen & ~(512-1); -+ thisvecofs += thislen; -+ } else { -+ /* Not enough to fill a page. Copy into buf */ -+ memcpy(static_buf, buf, thislen); -+ buf = &static_buf[thislen]; -+ -+ while(count && thislen < 512) { -+ vecs++; -+ count--; -+ thisvecofs = min((512-thislen), vecs->iov_len); -+ memcpy(buf, vecs->iov_base, thisvecofs); -+ thislen += thisvecofs; -+ buf += thisvecofs; -+ } -+ buf = static_buf; -+ } -+ if (count && thisvecofs == vecs->iov_len) { -+ thisvecofs = 0; -+ vecs++; -+ count--; -+ } -+ ret = doc_write_ecc(mtd, to, thislen, &thisretlen, buf, eccbuf, oobsel); -+ -+ totretlen += thisretlen; -+ -+ if (ret || thisretlen != thislen) -+ break; -+ -+ to += thislen; -+ } -+ -+ up(&writev_buf_sem); -+ *retlen = totretlen; -+ return ret; -+} -+ -+ - static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, - size_t * retlen, u_char * buf) - { -@@ -977,6 +1108,7 @@ - unsigned long docptr = this->virtadr; - struct Nand *mychip = &this->chips[ofs >> this->chipshift]; - volatile int dummy; -+ int status; - - // printk("doc_write_oob(%lx, %d): %2.2X %2.2X %2.2X %2.2X ... %2.2X %2.2X .. %2.2X %2.2X\n",(long)ofs, len, - // buf[0], buf[1], buf[2], buf[3], buf[8], buf[9], buf[14],buf[15]); -@@ -1025,10 +1157,16 @@ - DoC_Command(this, NAND_CMD_STATUS, 0); - /* DoC_WaitReady() is implicit in DoC_Command */ - -+ if (DoC_is_Millennium(this)) { -+ ReadDOC(docptr, ReadPipeInit); -+ status = ReadDOC(docptr, LastDataRead); -+ } else { - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); -+ status = ReadDOC_(docptr, this->ioreg); -+ } - -- if (ReadDOC_(docptr, this->ioreg) & 1) { -+ if (status & 1) { - printk(KERN_ERR "Error programming oob data\n"); - /* There was an error */ - *retlen = 0; -@@ -1044,10 +1182,16 @@ - DoC_Command(this, NAND_CMD_STATUS, 0); - /* DoC_WaitReady() is implicit in DoC_Command */ - -+ if (DoC_is_Millennium(this)) { -+ ReadDOC(docptr, ReadPipeInit); -+ status = ReadDOC(docptr, LastDataRead); -+ } else { - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); -+ status = ReadDOC_(docptr, this->ioreg); -+ } - -- if (ReadDOC_(docptr, this->ioreg) & 1) { -+ if (status & 1) { - printk(KERN_ERR "Error programming oob data\n"); - /* There was an error */ - *retlen = 0; -@@ -1080,6 +1224,7 @@ - volatile int dummy; - unsigned long docptr; - struct Nand *mychip; -+ int status; - - down(&this->lock); - -@@ -1111,10 +1256,16 @@ - - DoC_Command(this, NAND_CMD_STATUS, CDSN_CTRL_WP); - -+ if (DoC_is_Millennium(this)) { -+ ReadDOC(docptr, ReadPipeInit); -+ status = ReadDOC(docptr, LastDataRead); -+ } else { - dummy = ReadDOC(docptr, CDSNSlowIO); - DoC_Delay(this, 2); -+ status = ReadDOC_(docptr, this->ioreg); -+ } - -- if (ReadDOC_(docptr, this->ioreg) & 1) { -+ if (status & 1) { - printk(KERN_ERR "Error erasing at 0x%x\n", ofs); - /* There was an error */ - instr->state = MTD_ERASE_FAILED; -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/doc2001.c linux/drivers/mtd/devices/doc2001.c ---- linux-mips-2.4.27/drivers/mtd/devices/doc2001.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/devices/doc2001.c 2004-11-19 10:25:11.835209520 +0100 -@@ -4,7 +4,7 @@ - * (c) 1999 Machine Vision Holdings, Inc. - * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/kernel.h> -@@ -359,14 +359,15 @@ - - mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH; -+ mtd->ecctype = MTD_ECC_RS_DiskOnChip; - mtd->size = 0; - -- /* FIXME: erase size is not always 8kB */ -+ /* FIXME: erase size is not always 8KiB */ - mtd->erasesize = 0x2000; - - mtd->oobblock = 512; - mtd->oobsize = 16; -- mtd->module = THIS_MODULE; -+ mtd->owner = THIS_MODULE; - mtd->erase = doc_erase; - mtd->point = NULL; - mtd->unpoint = NULL; -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/doc2001plus.c linux/drivers/mtd/devices/doc2001plus.c ---- linux-mips-2.4.27/drivers/mtd/devices/doc2001plus.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/devices/doc2001plus.c 2004-11-19 10:25:11.837209216 +0100 -@@ -0,0 +1,1154 @@ -+/* -+ * Linux driver for Disk-On-Chip Millennium Plus -+ * -+ * (c) 2002-2003 Greg Ungerer <gerg@snapgear.com> -+ * (c) 2002-2003 SnapGear Inc -+ * (c) 1999 Machine Vision Holdings, Inc. -+ * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> -+ * -+ * $Id$ -+ * -+ * Released under GPL -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <asm/errno.h> -+#include <asm/io.h> -+#include <asm/uaccess.h> -+#include <linux/miscdevice.h> -+#include <linux/pci.h> -+#include <linux/delay.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <linux/types.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nand.h> -+#include <linux/mtd/doc2000.h> -+ -+/* #define ECC_DEBUG */ -+ -+/* I have no idea why some DoC chips can not use memcop_form|to_io(). -+ * This may be due to the different revisions of the ASIC controller built-in or -+ * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment -+ * this:*/ -+#undef USE_MEMCPY -+ -+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf); -+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf); -+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf, u_char *eccbuf, -+ struct nand_oobinfo *oobsel); -+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf, u_char *eccbuf, -+ struct nand_oobinfo *oobsel); -+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, -+ size_t *retlen, u_char *buf); -+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, -+ size_t *retlen, const u_char *buf); -+static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); -+ -+static struct mtd_info *docmilpluslist = NULL; -+ -+ -+/* Perform the required delay cycles by writing to the NOP register */ -+static void DoC_Delay(unsigned long docptr, int cycles) -+{ -+ int i; -+ -+ for (i = 0; (i < cycles); i++) -+ WriteDOC(0, docptr, Mplus_NOP); -+} -+ -+#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) -+ -+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ -+static int _DoC_WaitReady(unsigned long docptr) -+{ -+ unsigned int c = 0xffff; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, -+ "_DoC_WaitReady called for out-of-line wait\n"); -+ -+ /* Out-of-line routine to wait for chip response */ -+ while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c) -+ ; -+ -+ if (c == 0) -+ DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); -+ -+ return (c == 0); -+} -+ -+static inline int DoC_WaitReady(unsigned long docptr) -+{ -+ /* This is inline, to optimise the common case, where it's ready instantly */ -+ int ret = 0; -+ -+ /* read form NOP register should be issued prior to the read from CDSNControl -+ see Software Requirement 11.4 item 2. */ -+ DoC_Delay(docptr, 4); -+ -+ if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) -+ /* Call the out-of-line routine to wait */ -+ ret = _DoC_WaitReady(docptr); -+ -+ return ret; -+} -+ -+/* For some reason the Millennium Plus seems to occassionally put itself -+ * into reset mode. For me this happens randomly, with no pattern that I -+ * can detect. M-systems suggest always check this on any block level -+ * operation and setting to normal mode if in reset mode. -+ */ -+static inline void DoC_CheckASIC(unsigned long docptr) -+{ -+ /* Make sure the DoC is in normal mode */ -+ if ((ReadDOC(docptr, Mplus_DOCControl) & DOC_MODE_NORMAL) == 0) { -+ WriteDOC((DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_DOCControl); -+ WriteDOC(~(DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_CtrlConfirm); -+ } -+} -+ -+/* DoC_Command: Send a flash command to the flash chip through the Flash -+ * command register. Need 2 Write Pipeline Terminates to complete send. -+ */ -+static inline void DoC_Command(unsigned long docptr, unsigned char command, -+ unsigned char xtraflags) -+{ -+ WriteDOC(command, docptr, Mplus_FlashCmd); -+ WriteDOC(command, docptr, Mplus_WritePipeTerm); -+ WriteDOC(command, docptr, Mplus_WritePipeTerm); -+} -+ -+/* DoC_Address: Set the current address for the flash chip through the Flash -+ * Address register. Need 2 Write Pipeline Terminates to complete send. -+ */ -+static inline void DoC_Address(struct DiskOnChip *doc, int numbytes, -+ unsigned long ofs, unsigned char xtraflags1, -+ unsigned char xtraflags2) -+{ -+ unsigned long docptr = doc->virtadr; -+ -+ /* Allow for possible Mill Plus internal flash interleaving */ -+ ofs >>= doc->interleave; -+ -+ switch (numbytes) { -+ case 1: -+ /* Send single byte, bits 0-7. */ -+ WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress); -+ break; -+ case 2: -+ /* Send bits 9-16 followed by 17-23 */ -+ WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress); -+ WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress); -+ break; -+ case 3: -+ /* Send 0-7, 9-16, then 17-23 */ -+ WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress); -+ WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress); -+ WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress); -+ break; -+ default: -+ return; -+ } -+ -+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm); -+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm); -+} -+ -+/* DoC_SelectChip: Select a given flash chip within the current floor */ -+static int DoC_SelectChip(unsigned long docptr, int chip) -+{ -+ /* No choice for flash chip on Millennium Plus */ -+ return 0; -+} -+ -+/* DoC_SelectFloor: Select a given floor (bank of flash chips) */ -+static int DoC_SelectFloor(unsigned long docptr, int floor) -+{ -+ WriteDOC((floor & 0x3), docptr, Mplus_DeviceSelect); -+ return 0; -+} -+ -+/* -+ * Translate the given offset into the appropriate command and offset. -+ * This does the mapping using the 16bit interleave layout defined by -+ * M-Systems, and looks like this for a sector pair: -+ * +-----------+-------+-------+-------+--------------+---------+-----------+ -+ * | 0 --- 511 |512-517|518-519|520-521| 522 --- 1033 |1034-1039|1040 - 1055| -+ * +-----------+-------+-------+-------+--------------+---------+-----------+ -+ * | Data 0 | ECC 0 |Flags0 |Flags1 | Data 1 |ECC 1 | OOB 1 + 2 | -+ * +-----------+-------+-------+-------+--------------+---------+-----------+ -+ */ -+/* FIXME: This lives in INFTL not here. Other users of flash devices -+ may not want it */ -+static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from) -+{ -+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; -+ -+ if (this->interleave) { -+ unsigned int ofs = *from & 0x3ff; -+ unsigned int cmd; -+ -+ if (ofs < 512) { -+ cmd = NAND_CMD_READ0; -+ ofs &= 0x1ff; -+ } else if (ofs < 1014) { -+ cmd = NAND_CMD_READ1; -+ ofs = (ofs & 0x1ff) + 10; -+ } else { -+ cmd = NAND_CMD_READOOB; -+ ofs = ofs - 1014; -+ } -+ -+ *from = (*from & ~0x3ff) | ofs; -+ return cmd; -+ } else { -+ /* No interleave */ -+ if ((*from) & 0x100) -+ return NAND_CMD_READ1; -+ return NAND_CMD_READ0; -+ } -+} -+ -+static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from) -+{ -+ unsigned int ofs, cmd; -+ -+ if (*from & 0x200) { -+ cmd = NAND_CMD_READOOB; -+ ofs = 10 + (*from & 0xf); -+ } else { -+ cmd = NAND_CMD_READ1; -+ ofs = (*from & 0xf); -+ } -+ -+ *from = (*from & ~0x3ff) | ofs; -+ return cmd; -+} -+ -+static unsigned int DoC_GetFlagsOffset(struct mtd_info *mtd, loff_t *from) -+{ -+ unsigned int ofs, cmd; -+ -+ cmd = NAND_CMD_READ1; -+ ofs = (*from & 0x200) ? 8 : 6; -+ *from = (*from & ~0x3ff) | ofs; -+ return cmd; -+} -+ -+static unsigned int DoC_GetHdrOffset(struct mtd_info *mtd, loff_t *from) -+{ -+ unsigned int ofs, cmd; -+ -+ cmd = NAND_CMD_READOOB; -+ ofs = (*from & 0x200) ? 24 : 16; -+ *from = (*from & ~0x3ff) | ofs; -+ return cmd; -+} -+ -+static inline void MemReadDOC(unsigned long docptr, unsigned char *buf, int len) -+{ -+#ifndef USE_MEMCPY -+ int i; -+ for (i = 0; i < len; i++) -+ buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); -+#else -+ memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len); -+#endif -+} -+ -+static inline void MemWriteDOC(unsigned long docptr, unsigned char *buf, int len) -+{ -+#ifndef USE_MEMCPY -+ int i; -+ for (i = 0; i < len; i++) -+ WriteDOC(buf[i], docptr, Mil_CDSN_IO + i); -+#else -+ memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len); -+#endif -+} -+ -+/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ -+static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) -+{ -+ int mfr, id, i, j; -+ volatile char dummy; -+ unsigned long docptr = doc->virtadr; -+ -+ /* Page in the required floor/chip */ -+ DoC_SelectFloor(docptr, floor); -+ DoC_SelectChip(docptr, chip); -+ -+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ -+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); -+ -+ /* Reset the chip, see Software Requirement 11.4 item 1. */ -+ DoC_Command(docptr, NAND_CMD_RESET, 0); -+ DoC_WaitReady(docptr); -+ -+ /* Read the NAND chip ID: 1. Send ReadID command */ -+ DoC_Command(docptr, NAND_CMD_READID, 0); -+ -+ /* Read the NAND chip ID: 2. Send address byte zero */ -+ DoC_Address(doc, 1, 0x00, 0, 0x00); -+ -+ WriteDOC(0, docptr, Mplus_FlashControl); -+ DoC_WaitReady(docptr); -+ -+ /* Read the manufacturer and device id codes of the flash device through -+ CDSN IO register see Software Requirement 11.4 item 5.*/ -+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit); -+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit); -+ -+ mfr = ReadDOC(docptr, Mil_CDSN_IO); -+ if (doc->interleave) -+ dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ -+ -+ id = ReadDOC(docptr, Mil_CDSN_IO); -+ if (doc->interleave) -+ dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ -+ -+ dummy = ReadDOC(docptr, Mplus_LastDataRead); -+ dummy = ReadDOC(docptr, Mplus_LastDataRead); -+ -+ /* Disable flash internally */ -+ WriteDOC(0, docptr, Mplus_FlashSelect); -+ -+ /* No response - return failure */ -+ if (mfr == 0xff || mfr == 0) -+ return 0; -+ -+ for (i = 0; nand_flash_ids[i].name != NULL; i++) { -+ if (id == nand_flash_ids[i].id) { -+ /* Try to identify manufacturer */ -+ for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { -+ if (nand_manuf_ids[j].id == mfr) -+ break; -+ } -+ printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " -+ "Chip ID: %2.2X (%s:%s)\n", mfr, id, -+ nand_manuf_ids[j].name, nand_flash_ids[i].name); -+ doc->mfr = mfr; -+ doc->id = id; -+ doc->chipshift = nand_flash_ids[i].chipshift; -+ doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave; -+ break; -+ } -+ } -+ -+ if (nand_flash_ids[i].name == NULL) -+ return 0; -+ return 1; -+} -+ -+/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ -+static void DoC_ScanChips(struct DiskOnChip *this) -+{ -+ int floor, chip; -+ int numchips[MAX_FLOORS_MPLUS]; -+ int ret; -+ -+ this->numchips = 0; -+ this->mfr = 0; -+ this->id = 0; -+ -+ /* Work out the intended interleave setting */ -+ this->interleave = 0; -+ if (this->ChipID == DOC_ChipID_DocMilPlus32) -+ this->interleave = 1; -+ -+ /* Check the ASIC agrees */ -+ if ( (this->interleave << 2) != -+ (ReadDOC(this->virtadr, Mplus_Configuration) & 4)) { -+ u_char conf = ReadDOC(this->virtadr, Mplus_Configuration); -+ printk(KERN_NOTICE "Setting DiskOnChip Millennium Plus interleave to %s\n", -+ this->interleave?"on (16-bit)":"off (8-bit)"); -+ conf ^= 4; -+ WriteDOC(this->virtadr, conf, Mplus_Configuration); -+ } -+ -+ /* For each floor, find the number of valid chips it contains */ -+ for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) { -+ numchips[floor] = 0; -+ for (chip = 0; chip < MAX_CHIPS_MPLUS && ret != 0; chip++) { -+ ret = DoC_IdentChip(this, floor, chip); -+ if (ret) { -+ numchips[floor]++; -+ this->numchips++; -+ } -+ } -+ } -+ /* If there are none at all that we recognise, bail */ -+ if (!this->numchips) { -+ printk("No flash chips recognised.\n"); -+ return; -+ } -+ -+ /* Allocate an array to hold the information for each chip */ -+ this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL); -+ if (!this->chips){ -+ printk("MTD: No memory for allocating chip info structures\n"); -+ return; -+ } -+ -+ /* Fill out the chip array with {floor, chipno} for each -+ * detected chip in the device. */ -+ for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { -+ for (chip = 0 ; chip < numchips[floor] ; chip++) { -+ this->chips[ret].floor = floor; -+ this->chips[ret].chip = chip; -+ this->chips[ret].curadr = 0; -+ this->chips[ret].curmode = 0x50; -+ ret++; -+ } -+ } -+ -+ /* Calculate and print the total size of the device */ -+ this->totlen = this->numchips * (1 << this->chipshift); -+ printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n", -+ this->numchips ,this->totlen >> 20); -+} -+ -+static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) -+{ -+ int tmp1, tmp2, retval; -+ -+ if (doc1->physadr == doc2->physadr) -+ return 1; -+ -+ /* Use the alias resolution register which was set aside for this -+ * purpose. If it's value is the same on both chips, they might -+ * be the same chip, and we write to one and check for a change in -+ * the other. It's unclear if this register is usuable in the -+ * DoC 2000 (it's in the Millennium docs), but it seems to work. */ -+ tmp1 = ReadDOC(doc1->virtadr, Mplus_AliasResolution); -+ tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); -+ if (tmp1 != tmp2) -+ return 0; -+ -+ WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); -+ tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); -+ if (tmp2 == (tmp1+1) % 0xff) -+ retval = 1; -+ else -+ retval = 0; -+ -+ /* Restore register contents. May not be necessary, but do it just to -+ * be safe. */ -+ WriteDOC(tmp1, doc1->virtadr, Mplus_AliasResolution); -+ -+ return retval; -+} -+ -+static const char im_name[] = "DoCMilPlus_init"; -+ -+/* This routine is made available to other mtd code via -+ * inter_module_register. It must only be accessed through -+ * inter_module_get which will bump the use count of this module. The -+ * addresses passed back in mtd are valid as long as the use count of -+ * this module is non-zero, i.e. between inter_module_get and -+ * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000. -+ */ -+static void DoCMilPlus_init(struct mtd_info *mtd) -+{ -+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; -+ struct DiskOnChip *old = NULL; -+ -+ /* We must avoid being called twice for the same device. */ -+ if (docmilpluslist) -+ old = (struct DiskOnChip *)docmilpluslist->priv; -+ -+ while (old) { -+ if (DoCMilPlus_is_alias(this, old)) { -+ printk(KERN_NOTICE "Ignoring DiskOnChip Millennium " -+ "Plus at 0x%lX - already configured\n", -+ this->physadr); -+ iounmap((void *)this->virtadr); -+ kfree(mtd); -+ return; -+ } -+ if (old->nextdoc) -+ old = (struct DiskOnChip *)old->nextdoc->priv; -+ else -+ old = NULL; -+ } -+ -+ mtd->name = "DiskOnChip Millennium Plus"; -+ printk(KERN_NOTICE "DiskOnChip Millennium Plus found at " -+ "address 0x%lX\n", this->physadr); -+ -+ mtd->type = MTD_NANDFLASH; -+ mtd->flags = MTD_CAP_NANDFLASH; -+ mtd->ecctype = MTD_ECC_RS_DiskOnChip; -+ mtd->size = 0; -+ -+ mtd->erasesize = 0; -+ mtd->oobblock = 512; -+ mtd->oobsize = 16; -+ mtd->owner = THIS_MODULE; -+ mtd->erase = doc_erase; -+ mtd->point = NULL; -+ mtd->unpoint = NULL; -+ mtd->read = doc_read; -+ mtd->write = doc_write; -+ mtd->read_ecc = doc_read_ecc; -+ mtd->write_ecc = doc_write_ecc; -+ mtd->read_oob = doc_read_oob; -+ mtd->write_oob = doc_write_oob; -+ mtd->sync = NULL; -+ -+ this->totlen = 0; -+ this->numchips = 0; -+ this->curfloor = -1; -+ this->curchip = -1; -+ -+ /* Ident all the chips present. */ -+ DoC_ScanChips(this); -+ -+ if (!this->totlen) { -+ kfree(mtd); -+ iounmap((void *)this->virtadr); -+ } else { -+ this->nextdoc = docmilpluslist; -+ docmilpluslist = mtd; -+ mtd->size = this->totlen; -+ mtd->erasesize = this->erasesize; -+ add_mtd_device(mtd); -+ return; -+ } -+} -+ -+#if 0 -+static int doc_dumpblk(struct mtd_info *mtd, loff_t from) -+{ -+ int i; -+ loff_t fofs; -+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; -+ unsigned long docptr = this->virtadr; -+ struct Nand *mychip = &this->chips[from >> (this->chipshift)]; -+ unsigned char *bp, buf[1056]; -+ char c[32]; -+ -+ from &= ~0x3ff; -+ -+ /* Don't allow read past end of device */ -+ if (from >= this->totlen) -+ return -EINVAL; -+ -+ DoC_CheckASIC(docptr); -+ -+ /* Find the chip which is to be used and select it */ -+ if (this->curfloor != mychip->floor) { -+ DoC_SelectFloor(docptr, mychip->floor); -+ DoC_SelectChip(docptr, mychip->chip); -+ } else if (this->curchip != mychip->chip) { -+ DoC_SelectChip(docptr, mychip->chip); -+ } -+ this->curfloor = mychip->floor; -+ this->curchip = mychip->chip; -+ -+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ -+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); -+ -+ /* Reset the chip, see Software Requirement 11.4 item 1. */ -+ DoC_Command(docptr, NAND_CMD_RESET, 0); -+ DoC_WaitReady(docptr); -+ -+ fofs = from; -+ DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0); -+ DoC_Address(this, 3, fofs, 0, 0x00); -+ WriteDOC(0, docptr, Mplus_FlashControl); -+ DoC_WaitReady(docptr); -+ -+ /* disable the ECC engine */ -+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); -+ -+ ReadDOC(docptr, Mplus_ReadPipeInit); -+ ReadDOC(docptr, Mplus_ReadPipeInit); -+ -+ /* Read the data via the internal pipeline through CDSN IO -+ register, see Pipelined Read Operations 11.3 */ -+ MemReadDOC(docptr, buf, 1054); -+ buf[1054] = ReadDOC(docptr, Mplus_LastDataRead); -+ buf[1055] = ReadDOC(docptr, Mplus_LastDataRead); -+ -+ memset(&c[0], 0, sizeof(c)); -+ printk("DUMP OFFSET=%x:\n", (int)from); -+ -+ for (i = 0, bp = &buf[0]; (i < 1056); i++) { -+ if ((i % 16) == 0) -+ printk("%08x: ", i); -+ printk(" %02x", *bp); -+ c[(i & 0xf)] = ((*bp >= 0x20) && (*bp <= 0x7f)) ? *bp : '.'; -+ bp++; -+ if (((i + 1) % 16) == 0) -+ printk(" %s\n", c); -+ } -+ printk("\n"); -+ -+ /* Disable flash internally */ -+ WriteDOC(0, docptr, Mplus_FlashSelect); -+ -+ return 0; -+} -+#endif -+ -+static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ /* Just a special case of doc_read_ecc */ -+ return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); -+} -+ -+static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf, u_char *eccbuf, -+ struct nand_oobinfo *oobsel) -+{ -+ int ret, i; -+ volatile char dummy; -+ loff_t fofs; -+ unsigned char syndrome[6]; -+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; -+ unsigned long docptr = this->virtadr; -+ struct Nand *mychip = &this->chips[from >> (this->chipshift)]; -+ -+ /* Don't allow read past end of device */ -+ if (from >= this->totlen) -+ return -EINVAL; -+ -+ /* Don't allow a single read to cross a 512-byte block boundary */ -+ if (from + len > ((from | 0x1ff) + 1)) -+ len = ((from | 0x1ff) + 1) - from; -+ -+ DoC_CheckASIC(docptr); -+ -+ /* Find the chip which is to be used and select it */ -+ if (this->curfloor != mychip->floor) { -+ DoC_SelectFloor(docptr, mychip->floor); -+ DoC_SelectChip(docptr, mychip->chip); -+ } else if (this->curchip != mychip->chip) { -+ DoC_SelectChip(docptr, mychip->chip); -+ } -+ this->curfloor = mychip->floor; -+ this->curchip = mychip->chip; -+ -+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ -+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); -+ -+ /* Reset the chip, see Software Requirement 11.4 item 1. */ -+ DoC_Command(docptr, NAND_CMD_RESET, 0); -+ DoC_WaitReady(docptr); -+ -+ fofs = from; -+ DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0); -+ DoC_Address(this, 3, fofs, 0, 0x00); -+ WriteDOC(0, docptr, Mplus_FlashControl); -+ DoC_WaitReady(docptr); -+ -+ if (eccbuf) { -+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ -+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); -+ WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); -+ } else { -+ /* disable the ECC engine */ -+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); -+ } -+ -+ /* Let the caller know we completed it */ -+ *retlen = len; -+ ret = 0; -+ -+ ReadDOC(docptr, Mplus_ReadPipeInit); -+ ReadDOC(docptr, Mplus_ReadPipeInit); -+ -+ if (eccbuf) { -+ /* Read the data via the internal pipeline through CDSN IO -+ register, see Pipelined Read Operations 11.3 */ -+ MemReadDOC(docptr, buf, len); -+ -+ /* Read the ECC data following raw data */ -+ MemReadDOC(docptr, eccbuf, 4); -+ eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead); -+ eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead); -+ -+ /* Flush the pipeline */ -+ dummy = ReadDOC(docptr, Mplus_ECCConf); -+ dummy = ReadDOC(docptr, Mplus_ECCConf); -+ -+ /* Check the ECC Status */ -+ if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) { -+ int nb_errors; -+ /* There was an ECC error */ -+#ifdef ECC_DEBUG -+ printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); -+#endif -+ /* Read the ECC syndrom through the DiskOnChip ECC logic. -+ These syndrome will be all ZERO when there is no error */ -+ for (i = 0; i < 6; i++) -+ syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); -+ -+ nb_errors = doc_decode_ecc(buf, syndrome); -+#ifdef ECC_DEBUG -+ printk("ECC Errors corrected: %x\n", nb_errors); -+#endif -+ if (nb_errors < 0) { -+ /* We return error, but have actually done the read. Not that -+ this can be told to user-space, via sys_read(), but at least -+ MTD-aware stuff can know about it by checking *retlen */ -+#ifdef ECC_DEBUG -+ printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n", -+ __FILE__, __LINE__, (int)from); -+ printk(" syndrome= %02x:%02x:%02x:%02x:%02x:" -+ "%02x\n", -+ syndrome[0], syndrome[1], syndrome[2], -+ syndrome[3], syndrome[4], syndrome[5]); -+ printk(" eccbuf= %02x:%02x:%02x:%02x:%02x:" -+ "%02x\n", -+ eccbuf[0], eccbuf[1], eccbuf[2], -+ eccbuf[3], eccbuf[4], eccbuf[5]); -+#endif -+ ret = -EIO; -+ } -+ } -+ -+#ifdef PSYCHO_DEBUG -+ printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", -+ (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], -+ eccbuf[4], eccbuf[5]); -+#endif -+ -+ /* disable the ECC engine */ -+ WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf); -+ } else { -+ /* Read the data via the internal pipeline through CDSN IO -+ register, see Pipelined Read Operations 11.3 */ -+ MemReadDOC(docptr, buf, len-2); -+ buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead); -+ buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead); -+ } -+ -+ /* Disable flash internally */ -+ WriteDOC(0, docptr, Mplus_FlashSelect); -+ -+ return ret; -+} -+ -+static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ char eccbuf[6]; -+ return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL); -+} -+ -+static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf, u_char *eccbuf, -+ struct nand_oobinfo *oobsel) -+{ -+ int i, before, ret = 0; -+ loff_t fto; -+ volatile char dummy; -+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; -+ unsigned long docptr = this->virtadr; -+ struct Nand *mychip = &this->chips[to >> (this->chipshift)]; -+ -+ /* Don't allow write past end of device */ -+ if (to >= this->totlen) -+ return -EINVAL; -+ -+ /* Don't allow writes which aren't exactly one block (512 bytes) */ -+ if ((to & 0x1ff) || (len != 0x200)) -+ return -EINVAL; -+ -+ /* Determine position of OOB flags, before or after data */ -+ before = (this->interleave && (to & 0x200)); -+ -+ DoC_CheckASIC(docptr); -+ -+ /* Find the chip which is to be used and select it */ -+ if (this->curfloor != mychip->floor) { -+ DoC_SelectFloor(docptr, mychip->floor); -+ DoC_SelectChip(docptr, mychip->chip); -+ } else if (this->curchip != mychip->chip) { -+ DoC_SelectChip(docptr, mychip->chip); -+ } -+ this->curfloor = mychip->floor; -+ this->curchip = mychip->chip; -+ -+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ -+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); -+ -+ /* Reset the chip, see Software Requirement 11.4 item 1. */ -+ DoC_Command(docptr, NAND_CMD_RESET, 0); -+ DoC_WaitReady(docptr); -+ -+ /* Set device to appropriate plane of flash */ -+ fto = to; -+ WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd); -+ -+ /* On interleaved devices the flags for 2nd half 512 are before data */ -+ if (eccbuf && before) -+ fto -= 2; -+ -+ /* issue the Serial Data In command to initial the Page Program process */ -+ DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); -+ DoC_Address(this, 3, fto, 0x00, 0x00); -+ -+ /* Disable the ECC engine */ -+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); -+ -+ if (eccbuf) { -+ if (before) { -+ /* Write the block status BLOCK_USED (0x5555) */ -+ WriteDOC(0x55, docptr, Mil_CDSN_IO); -+ WriteDOC(0x55, docptr, Mil_CDSN_IO); -+ } -+ -+ /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ -+ WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf); -+ } -+ -+ MemWriteDOC(docptr, (unsigned char *) buf, len); -+ -+ if (eccbuf) { -+ /* Write ECC data to flash, the ECC info is generated by -+ the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */ -+ DoC_Delay(docptr, 3); -+ -+ /* Read the ECC data through the DiskOnChip ECC logic */ -+ for (i = 0; i < 6; i++) -+ eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); -+ -+ /* disable the ECC engine */ -+ WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); -+ -+ /* Write the ECC data to flash */ -+ MemWriteDOC(docptr, eccbuf, 6); -+ -+ if (!before) { -+ /* Write the block status BLOCK_USED (0x5555) */ -+ WriteDOC(0x55, docptr, Mil_CDSN_IO+6); -+ WriteDOC(0x55, docptr, Mil_CDSN_IO+7); -+ } -+ -+#ifdef PSYCHO_DEBUG -+ printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", -+ (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], -+ eccbuf[4], eccbuf[5]); -+#endif -+ } -+ -+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm); -+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm); -+ -+ /* Commit the Page Program command and wait for ready -+ see Software Requirement 11.4 item 1.*/ -+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); -+ DoC_WaitReady(docptr); -+ -+ /* Read the status of the flash device through CDSN IO register -+ see Software Requirement 11.4 item 5.*/ -+ DoC_Command(docptr, NAND_CMD_STATUS, 0); -+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit); -+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit); -+ DoC_Delay(docptr, 2); -+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { -+ printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to); -+ /* Error in programming -+ FIXME: implement Bad Block Replacement (in nftl.c ??) */ -+ *retlen = 0; -+ ret = -EIO; -+ } -+ dummy = ReadDOC(docptr, Mplus_LastDataRead); -+ -+ /* Disable flash internally */ -+ WriteDOC(0, docptr, Mplus_FlashSelect); -+ -+ /* Let the caller know we completed it */ -+ *retlen = len; -+ -+ return ret; -+} -+ -+static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ loff_t fofs, base; -+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; -+ unsigned long docptr = this->virtadr; -+ struct Nand *mychip = &this->chips[ofs >> this->chipshift]; -+ size_t i, size, got, want; -+ -+ DoC_CheckASIC(docptr); -+ -+ /* Find the chip which is to be used and select it */ -+ if (this->curfloor != mychip->floor) { -+ DoC_SelectFloor(docptr, mychip->floor); -+ DoC_SelectChip(docptr, mychip->chip); -+ } else if (this->curchip != mychip->chip) { -+ DoC_SelectChip(docptr, mychip->chip); -+ } -+ this->curfloor = mychip->floor; -+ this->curchip = mychip->chip; -+ -+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ -+ WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); -+ -+ /* disable the ECC engine */ -+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); -+ DoC_WaitReady(docptr); -+ -+ /* Maximum of 16 bytes in the OOB region, so limit read to that */ -+ if (len > 16) -+ len = 16; -+ got = 0; -+ want = len; -+ -+ for (i = 0; ((i < 3) && (want > 0)); i++) { -+ /* Figure out which region we are accessing... */ -+ fofs = ofs; -+ base = ofs & 0xf; -+ if (!this->interleave) { -+ DoC_Command(docptr, NAND_CMD_READOOB, 0); -+ size = 16 - base; -+ } else if (base < 6) { -+ DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0); -+ size = 6 - base; -+ } else if (base < 8) { -+ DoC_Command(docptr, DoC_GetFlagsOffset(mtd, &fofs), 0); -+ size = 8 - base; -+ } else { -+ DoC_Command(docptr, DoC_GetHdrOffset(mtd, &fofs), 0); -+ size = 16 - base; -+ } -+ if (size > want) -+ size = want; -+ -+ /* Issue read command */ -+ DoC_Address(this, 3, fofs, 0, 0x00); -+ WriteDOC(0, docptr, Mplus_FlashControl); -+ DoC_WaitReady(docptr); -+ -+ ReadDOC(docptr, Mplus_ReadPipeInit); -+ ReadDOC(docptr, Mplus_ReadPipeInit); -+ MemReadDOC(docptr, &buf[got], size - 2); -+ buf[got + size - 2] = ReadDOC(docptr, Mplus_LastDataRead); -+ buf[got + size - 1] = ReadDOC(docptr, Mplus_LastDataRead); -+ -+ ofs += size; -+ got += size; -+ want -= size; -+ } -+ -+ /* Disable flash internally */ -+ WriteDOC(0, docptr, Mplus_FlashSelect); -+ -+ *retlen = len; -+ return 0; -+} -+ -+static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ volatile char dummy; -+ loff_t fofs, base; -+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; -+ unsigned long docptr = this->virtadr; -+ struct Nand *mychip = &this->chips[ofs >> this->chipshift]; -+ size_t i, size, got, want; -+ int ret = 0; -+ -+ DoC_CheckASIC(docptr); -+ -+ /* Find the chip which is to be used and select it */ -+ if (this->curfloor != mychip->floor) { -+ DoC_SelectFloor(docptr, mychip->floor); -+ DoC_SelectChip(docptr, mychip->chip); -+ } else if (this->curchip != mychip->chip) { -+ DoC_SelectChip(docptr, mychip->chip); -+ } -+ this->curfloor = mychip->floor; -+ this->curchip = mychip->chip; -+ -+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ -+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); -+ -+ -+ /* Maximum of 16 bytes in the OOB region, so limit write to that */ -+ if (len > 16) -+ len = 16; -+ got = 0; -+ want = len; -+ -+ for (i = 0; ((i < 3) && (want > 0)); i++) { -+ /* Reset the chip, see Software Requirement 11.4 item 1. */ -+ DoC_Command(docptr, NAND_CMD_RESET, 0); -+ DoC_WaitReady(docptr); -+ -+ /* Figure out which region we are accessing... */ -+ fofs = ofs; -+ base = ofs & 0x0f; -+ if (!this->interleave) { -+ WriteDOC(NAND_CMD_READOOB, docptr, Mplus_FlashCmd); -+ size = 16 - base; -+ } else if (base < 6) { -+ WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd); -+ size = 6 - base; -+ } else if (base < 8) { -+ WriteDOC(DoC_GetFlagsOffset(mtd, &fofs), docptr, Mplus_FlashCmd); -+ size = 8 - base; -+ } else { -+ WriteDOC(DoC_GetHdrOffset(mtd, &fofs), docptr, Mplus_FlashCmd); -+ size = 16 - base; -+ } -+ if (size > want) -+ size = want; -+ -+ /* Issue the Serial Data In command to initial the Page Program process */ -+ DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); -+ DoC_Address(this, 3, fofs, 0, 0x00); -+ -+ /* Disable the ECC engine */ -+ WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); -+ -+ /* Write the data via the internal pipeline through CDSN IO -+ register, see Pipelined Write Operations 11.2 */ -+ MemWriteDOC(docptr, (unsigned char *) &buf[got], size); -+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm); -+ WriteDOC(0x00, docptr, Mplus_WritePipeTerm); -+ -+ /* Commit the Page Program command and wait for ready -+ see Software Requirement 11.4 item 1.*/ -+ DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); -+ DoC_WaitReady(docptr); -+ -+ /* Read the status of the flash device through CDSN IO register -+ see Software Requirement 11.4 item 5.*/ -+ DoC_Command(docptr, NAND_CMD_STATUS, 0x00); -+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit); -+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit); -+ DoC_Delay(docptr, 2); -+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { -+ printk("MTD: Error 0x%x programming oob at 0x%x\n", -+ dummy, (int)ofs); -+ /* FIXME: implement Bad Block Replacement */ -+ *retlen = 0; -+ ret = -EIO; -+ } -+ dummy = ReadDOC(docptr, Mplus_LastDataRead); -+ -+ ofs += size; -+ got += size; -+ want -= size; -+ } -+ -+ /* Disable flash internally */ -+ WriteDOC(0, docptr, Mplus_FlashSelect); -+ -+ *retlen = len; -+ return ret; -+} -+ -+int doc_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ volatile char dummy; -+ struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; -+ __u32 ofs = instr->addr; -+ __u32 len = instr->len; -+ unsigned long docptr = this->virtadr; -+ struct Nand *mychip = &this->chips[ofs >> this->chipshift]; -+ -+ DoC_CheckASIC(docptr); -+ -+ if (len != mtd->erasesize) -+ printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n", -+ len, mtd->erasesize); -+ -+ /* Find the chip which is to be used and select it */ -+ if (this->curfloor != mychip->floor) { -+ DoC_SelectFloor(docptr, mychip->floor); -+ DoC_SelectChip(docptr, mychip->chip); -+ } else if (this->curchip != mychip->chip) { -+ DoC_SelectChip(docptr, mychip->chip); -+ } -+ this->curfloor = mychip->floor; -+ this->curchip = mychip->chip; -+ -+ instr->state = MTD_ERASE_PENDING; -+ -+ /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ -+ WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); -+ -+ DoC_Command(docptr, NAND_CMD_RESET, 0x00); -+ DoC_WaitReady(docptr); -+ -+ DoC_Command(docptr, NAND_CMD_ERASE1, 0); -+ DoC_Address(this, 2, ofs, 0, 0x00); -+ DoC_Command(docptr, NAND_CMD_ERASE2, 0); -+ DoC_WaitReady(docptr); -+ instr->state = MTD_ERASING; -+ -+ /* Read the status of the flash device through CDSN IO register -+ see Software Requirement 11.4 item 5. */ -+ DoC_Command(docptr, NAND_CMD_STATUS, 0); -+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit); -+ dummy = ReadDOC(docptr, Mplus_ReadPipeInit); -+ if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { -+ printk("MTD: Error 0x%x erasing at 0x%x\n", dummy, ofs); -+ /* FIXME: implement Bad Block Replacement (in nftl.c ??) */ -+ instr->state = MTD_ERASE_FAILED; -+ } else { -+ instr->state = MTD_ERASE_DONE; -+ } -+ dummy = ReadDOC(docptr, Mplus_LastDataRead); -+ -+ /* Disable flash internally */ -+ WriteDOC(0, docptr, Mplus_FlashSelect); -+ -+ if (instr->callback) -+ instr->callback(instr); -+ -+ return 0; -+} -+ -+/**************************************************************************** -+ * -+ * Module stuff -+ * -+ ****************************************************************************/ -+ -+int __init init_doc2001plus(void) -+{ -+ inter_module_register(im_name, THIS_MODULE, &DoCMilPlus_init); -+ return 0; -+} -+ -+static void __exit cleanup_doc2001plus(void) -+{ -+ struct mtd_info *mtd; -+ struct DiskOnChip *this; -+ -+ while ((mtd=docmilpluslist)) { -+ this = (struct DiskOnChip *)mtd->priv; -+ docmilpluslist = this->nextdoc; -+ -+ del_mtd_device(mtd); -+ -+ iounmap((void *)this->virtadr); -+ kfree(this->chips); -+ kfree(mtd); -+ } -+ inter_module_unregister(im_name); -+} -+ -+module_exit(cleanup_doc2001plus); -+module_init(init_doc2001plus); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al."); -+MODULE_DESCRIPTION("Driver for DiskOnChip Millennium Plus"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/docecc.c linux/drivers/mtd/devices/docecc.c ---- linux-mips-2.4.27/drivers/mtd/devices/docecc.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/devices/docecc.c 2004-11-19 10:25:11.851207088 +0100 -@@ -7,7 +7,7 @@ - * Author: Fabrice Bellard (fabrice.bellard@netgem.com) - * Copyright (C) 2000 Netgem S.A. - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -519,6 +519,8 @@ - return nb_errors; - } - -+EXPORT_SYMBOL_GPL(doc_decode_ecc); -+ - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Fabrice Bellard <fabrice.bellard@netgem.com>"); - MODULE_DESCRIPTION("ECC code for correcting errors detected by DiskOnChip 2000 and Millennium ECC hardware"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/docprobe.c linux/drivers/mtd/devices/docprobe.c ---- linux-mips-2.4.27/drivers/mtd/devices/docprobe.c 2003-06-16 01:42:21.000000000 +0200 -+++ linux/drivers/mtd/devices/docprobe.c 2004-11-19 10:25:11.853206784 +0100 -@@ -4,7 +4,7 @@ - /* (C) 1999 Machine Vision Holdings, Inc. */ - /* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ - --/* $Id$ */ -+/* $Id$ */ - - - -@@ -31,14 +31,12 @@ - /* DOC_SINGLE_DRIVER: - Millennium driver has been merged into DOC2000 driver. - -- The newly-merged driver doesn't appear to work for writing. It's the -- same with the DiskOnChip 2000 and the Millennium. If you have a -- Millennium and you want write support to work, remove the definition -- of DOC_SINGLE_DRIVER below to use the old doc2001-specific driver. -- -- Otherwise, it's left on in the hope that it'll annoy someone with -- a Millennium enough that they go through and work out what the -- difference is :) -+ The old Millennium-only driver has been retained just in case there -+ are problems with the new code. If the combined driver doesn't work -+ for you, you can try the old one by undefining DOC_SINGLE_DRIVER -+ below and also enabling it in your configuration. If this fixes the -+ problems, please send a report to the MTD mailing list at -+ <linux-mtd@lists.infradead.org>. - */ - #define DOC_SINGLE_DRIVER - -@@ -47,18 +45,15 @@ - #include <linux/module.h> - #include <asm/errno.h> - #include <asm/io.h> --#include <asm/uaccess.h> --#include <linux/miscdevice.h> --#include <linux/pci.h> - #include <linux/delay.h> - #include <linux/slab.h> --#include <linux/sched.h> - #include <linux/init.h> - #include <linux/types.h> - - #include <linux/mtd/mtd.h> - #include <linux/mtd/nand.h> - #include <linux/mtd/doc2000.h> -+#include <linux/mtd/compatmac.h> - - /* Where to look for the devices? */ - #ifndef CONFIG_MTD_DOCPROBE_ADDRESS -@@ -92,17 +87,17 @@ - 0xff000000, - #elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) - 0xff000000, --#else -+##else - #warning Unknown architecture for DiskOnChip. No default probe locations defined - #endif -- 0 }; -+ 0xffffffff }; - - /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */ - - static inline int __init doccheck(unsigned long potential, unsigned long physadr) - { - unsigned long window=potential; -- unsigned char tmp, ChipID; -+ unsigned char tmp, tmpb, tmpc, ChipID; - #ifndef DOC_PASSIVE_PROBE - unsigned char tmp2; - #endif -@@ -140,26 +135,80 @@ - window, DOCControl); - #endif /* !DOC_PASSIVE_PROBE */ - -+ /* We need to read the ChipID register four times. For some -+ newer DiskOnChip 2000 units, the first three reads will -+ return the DiskOnChip Millennium ident. Don't ask. */ - ChipID = ReadDOC(window, ChipID); - - switch (ChipID) { - case DOC_ChipID_Doc2k: - /* Check the TOGGLE bit in the ECC register */ - tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; -- if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp) -+ tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; -+ tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; -+ if (tmp != tmpb && tmp == tmpc) - return ChipID; - break; - - case DOC_ChipID_DocMil: -+ /* Check for the new 2000 with Millennium ASIC */ -+ ReadDOC(window, ChipID); -+ ReadDOC(window, ChipID); -+ if (ReadDOC(window, ChipID) != DOC_ChipID_DocMil) -+ ChipID = DOC_ChipID_Doc2kTSOP; -+ - /* Check the TOGGLE bit in the ECC register */ - tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; -- if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp) -+ tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; -+ tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; -+ if (tmp != tmpb && tmp == tmpc) -+ return ChipID; -+ break; -+ -+ case DOC_ChipID_DocMilPlus16: -+ case DOC_ChipID_DocMilPlus32: -+ case 0: -+ /* Possible Millennium+, need to do more checks */ -+#ifndef DOC_PASSIVE_PROBE -+ /* Possibly release from power down mode */ -+ for (tmp = 0; (tmp < 4); tmp++) -+ ReadDOC(window, Mplus_Power); -+ -+ /* Reset the DiskOnChip ASIC */ -+ tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | -+ DOC_MODE_BDECT; -+ WriteDOC(tmp, window, Mplus_DOCControl); -+ WriteDOC(~tmp, window, Mplus_CtrlConfirm); -+ -+ mdelay(1); -+ /* Enable the DiskOnChip ASIC */ -+ tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | -+ DOC_MODE_BDECT; -+ WriteDOC(tmp, window, Mplus_DOCControl); -+ WriteDOC(~tmp, window, Mplus_CtrlConfirm); -+ mdelay(1); -+#endif /* !DOC_PASSIVE_PROBE */ -+ -+ ChipID = ReadDOC(window, ChipID); -+ -+ switch (ChipID) { -+ case DOC_ChipID_DocMilPlus16: -+ case DOC_ChipID_DocMilPlus32: -+ /* Check the TOGGLE bit in the toggle register */ -+ tmp = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; -+ tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; -+ tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; -+ if (tmp != tmpb && tmp == tmpc) - return ChipID; -+ default: - break; -+ } -+ /* FALL TRHU */ - - default: --#ifndef CONFIG_MTD_DOCPROBE_55AA -- printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n", -+ -+#ifdef CONFIG_MTD_DOCPROBE_55AA -+ printk(KERN_DEBUG "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n", - ChipID, physadr); - #endif - #ifndef DOC_PASSIVE_PROBE -@@ -200,6 +249,12 @@ - return; - - if ((ChipID = doccheck(docptr, physadr))) { -+ if (ChipID == DOC_ChipID_Doc2kTSOP) { -+ /* Remove this at your own peril. The hardware driver works but nothing prevents you from erasing bad blocks */ -+ printk(KERN_NOTICE "Refusing to drive DiskOnChip 2000 TSOP until Bad Block Table is correctly supported by INFTL\n"); -+ iounmap((void *)docptr); -+ return; -+ } - docfound = 1; - mtd = kmalloc(sizeof(struct DiskOnChip) + sizeof(struct mtd_info), GFP_KERNEL); - -@@ -221,6 +276,12 @@ - sprintf(namebuf, "with ChipID %2.2X", ChipID); - - switch(ChipID) { -+ case DOC_ChipID_Doc2kTSOP: -+ name="2000 TSOP"; -+ im_funcname = "DoC2k_init"; -+ im_modname = "doc2000"; -+ break; -+ - case DOC_ChipID_Doc2k: - name="2000"; - im_funcname = "DoC2k_init"; -@@ -237,6 +298,13 @@ - im_modname = "doc2001"; - #endif /* DOC_SINGLE_DRIVER */ - break; -+ -+ case DOC_ChipID_DocMilPlus16: -+ case DOC_ChipID_DocMilPlus32: -+ name="MillenniumPlus"; -+ im_funcname = "DoCMilPlus_init"; -+ im_modname = "doc2001plus"; -+ break; - } - - if (im_funcname) -@@ -248,6 +316,7 @@ - return; - } - printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr); -+ kfree(mtd); - } - iounmap((void *)docptr); - } -@@ -267,7 +336,7 @@ - printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); - DoC_Probe(doc_config_location); - } else { -- for (i=0; doc_locations[i]; i++) { -+ for (i=0; (doc_locations[i] != 0xffffffff); i++) { - DoC_Probe(doc_locations[i]); - } - } -@@ -275,11 +344,7 @@ - found, so the user knows we at least tried. */ - if (!docfound) - printk(KERN_INFO "No recognised DiskOnChip devices found\n"); -- /* So it looks like we've been used and we get unloaded */ -- MOD_INC_USE_COUNT; -- MOD_DEC_USE_COUNT; -- return 0; -- -+ return -EAGAIN; - } - - module_init(init_doc); -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/lart.c linux/drivers/mtd/devices/lart.c ---- linux-mips-2.4.27/drivers/mtd/devices/lart.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/devices/lart.c 2004-11-19 10:25:11.854206632 +0100 -@@ -2,7 +2,7 @@ - /* - * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. - * -- * $Id$ -+ * $Id$ - * - * Author: Abraham vd Merwe <abraham@2d3d.co.za> - * -@@ -584,45 +584,40 @@ - - static struct mtd_info mtd; - --static struct mtd_erase_region_info erase_regions[] = --{ -+static struct mtd_erase_region_info erase_regions[] = { - /* parameter blocks */ - { -- offset: 0x00000000, -- erasesize: FLASH_BLOCKSIZE_PARAM, -- numblocks: FLASH_NUMBLOCKS_16m_PARAM -+ .offset = 0x00000000, -+ .erasesize = FLASH_BLOCKSIZE_PARAM, -+ .numblocks = FLASH_NUMBLOCKS_16m_PARAM, - }, - /* main blocks */ - { -- offset: FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, -- erasesize: FLASH_BLOCKSIZE_MAIN, -- numblocks: FLASH_NUMBLOCKS_16m_MAIN -+ .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, -+ .erasesize = FLASH_BLOCKSIZE_MAIN, -+ .numblocks = FLASH_NUMBLOCKS_16m_MAIN, - } - }; - - #ifdef HAVE_PARTITIONS --static struct mtd_partition lart_partitions[] = --{ -+static struct mtd_partition lart_partitions[] = { - /* blob */ - { -- name: "blob", -- offset: BLOB_START, -- size: BLOB_LEN, -- mask_flags: 0 -+ .name = "blob", -+ .offset = BLOB_START, -+ .size = BLOB_LEN, - }, - /* kernel */ - { -- name: "kernel", -- offset: KERNEL_START, /* MTDPART_OFS_APPEND */ -- size: KERNEL_LEN, -- mask_flags: 0 -+ .name = "kernel", -+ .offset = KERNEL_START, /* MTDPART_OFS_APPEND */ -+ .size = KERNEL_LEN, - }, - /* initial ramdisk / file system */ - { -- name: "file system", -- offset: INITRD_START, /* MTDPART_OFS_APPEND */ -- size: INITRD_LEN, /* MTDPART_SIZ_FULL */ -- mask_flags: 0 -+ .name = "file system", -+ .offset = INITRD_START, /* MTDPART_OFS_APPEND */ -+ .size = INITRD_LEN, /* MTDPART_SIZ_FULL */ - } - }; - #endif -@@ -646,10 +641,10 @@ - mtd.erasesize = FLASH_BLOCKSIZE_MAIN; - mtd.numeraseregions = NB_OF (erase_regions); - mtd.eraseregions = erase_regions; -- mtd.module = THIS_MODULE; - mtd.erase = flash_erase; - mtd.read = flash_read; - mtd.write = flash_write; -+ mtd.owner = THIS_MODULE; - - #ifdef LART_DEBUG - printk (KERN_DEBUG -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/ms02-nv.c linux/drivers/mtd/devices/ms02-nv.c ---- linux-mips-2.4.27/drivers/mtd/devices/ms02-nv.c 2004-07-30 12:22:40.000000000 +0200 -+++ linux/drivers/mtd/devices/ms02-nv.c 2004-11-19 10:25:11.856206328 +0100 -@@ -6,7 +6,7 @@ - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/init.h> -@@ -31,7 +31,7 @@ - static char version[] __initdata = - "ms02-nv.c: v.1.0.0 13 Aug 2001 Maciej W. Rozycki.\n"; - --MODULE_AUTHOR("Maciej W. Rozycki <macro@linux-mips.org>"); -+MODULE_AUTHOR("Maciej W. Rozycki <macro@ds2.pg.gda.pl>"); - MODULE_DESCRIPTION("DEC MS02-NV NVRAM module driver"); - MODULE_LICENSE("GPL"); - -@@ -222,7 +222,7 @@ - mtd->flags = MTD_CAP_RAM | MTD_XIP; - mtd->size = fixsize; - mtd->name = (char *)ms02nv_name; -- mtd->module = THIS_MODULE; -+ mtd->owner = THIS_MODULE; - mtd->read = ms02nv_read; - mtd->write = ms02nv_write; - -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/mtdram.c linux/drivers/mtd/devices/mtdram.c ---- linux-mips-2.4.27/drivers/mtd/devices/mtdram.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/devices/mtdram.c 2004-11-19 10:25:11.859205872 +0100 -@@ -1,6 +1,6 @@ - /* - * mtdram - a test mtd device -- * $Id$ -+ * $Id$ - * Author: Alexander Larsson <alex@cendio.se> - * - * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> -@@ -13,6 +13,8 @@ - #include <linux/module.h> - #include <linux/slab.h> - #include <linux/ioport.h> -+#include <linux/vmalloc.h> -+#include <linux/init.h> - #include <linux/mtd/compatmac.h> - #include <linux/mtd/mtd.h> - -@@ -136,7 +138,7 @@ - mtd->erasesize = MTDRAM_ERASE_SIZE; - mtd->priv = mapped_address; - -- mtd->module = THIS_MODULE; -+ mtd->owner = THIS_MODULE; - mtd->erase = ram_erase; - mtd->point = ram_point; - mtd->unpoint = ram_unpoint; -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/phram.c linux/drivers/mtd/devices/phram.c ---- linux-mips-2.4.27/drivers/mtd/devices/phram.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/devices/phram.c 2004-11-19 10:25:11.860205720 +0100 -@@ -0,0 +1,362 @@ -+/** -+ * -+ * $Id$ -+ * -+ * Copyright (c) Jochen Schaeuble <psionic@psionic.de> -+ * 07/2003 rewritten by Joern Engel <joern@wh.fh-wedel.de> -+ * -+ * DISCLAIMER: This driver makes use of Rusty's excellent module code, -+ * so it will not work for 2.4 without changes and it wont work for 2.4 -+ * as a module without major changes. Oh well! -+ * -+ * Usage: -+ * -+ * one commend line parameter per device, each in the form: -+ * phram=<name>,<start>,<len> -+ * <name> may be up to 63 characters. -+ * <start> and <len> can be octal, decimal or hexadecimal. If followed -+ * by "k", "M" or "G", the numbers will be interpreted as kilo, mega or -+ * gigabytes. -+ * -+ */ -+ -+#include <asm/io.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/list.h> -+#include <linux/module.h> -+#include <linux/moduleparam.h> -+#include <linux/mtd/mtd.h> -+ -+#define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args) -+ -+struct phram_mtd_list { -+ struct list_head list; -+ struct mtd_info *mtdinfo; -+}; -+ -+static LIST_HEAD(phram_list); -+ -+ -+ -+int phram_erase(struct mtd_info *mtd, struct erase_info *instr) -+{ -+ u_char *start = (u_char *)mtd->priv; -+ -+ if (instr->addr + instr->len > mtd->size) -+ return -EINVAL; -+ -+ memset(start + instr->addr, 0xff, instr->len); -+ -+ /* This'll catch a few races. Free the thing before returning :) -+ * I don't feel at all ashamed. This kind of thing is possible anyway -+ * with flash, but unlikely. -+ */ -+ -+ instr->state = MTD_ERASE_DONE; -+ -+ if (instr->callback) -+ (*(instr->callback))(instr); -+ else -+ kfree(instr); -+ -+ return 0; -+} -+ -+int phram_point(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char **mtdbuf) -+{ -+ u_char *start = (u_char *)mtd->priv; -+ -+ if (from + len > mtd->size) -+ return -EINVAL; -+ -+ *mtdbuf = start + from; -+ *retlen = len; -+ return 0; -+} -+ -+void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) -+{ -+} -+ -+int phram_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ u_char *start = (u_char *)mtd->priv; -+ -+ if (from + len > mtd->size) -+ return -EINVAL; -+ -+ memcpy(buf, start + from, len); -+ -+ *retlen = len; -+ return 0; -+} -+ -+int phram_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ u_char *start = (u_char *)mtd->priv; -+ -+ if (to + len > mtd->size) -+ return -EINVAL; -+ -+ memcpy(start + to, buf, len); -+ -+ *retlen = len; -+ return 0; -+} -+ -+ -+ -+static void unregister_devices(void) -+{ -+ struct phram_mtd_list *this; -+ -+ list_for_each_entry(this, &phram_list, list) { -+ del_mtd_device(this->mtdinfo); -+ iounmap(this->mtdinfo->priv); -+ kfree(this->mtdinfo); -+ kfree(this); -+ } -+} -+ -+static int register_device(char *name, unsigned long start, unsigned long len) -+{ -+ struct phram_mtd_list *new; -+ int ret = -ENOMEM; -+ -+ new = kmalloc(sizeof(*new), GFP_KERNEL); -+ if (!new) -+ goto out0; -+ -+ new->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL); -+ if (!new->mtdinfo) -+ goto out1; -+ -+ memset(new->mtdinfo, 0, sizeof(struct mtd_info)); -+ -+ ret = -EIO; -+ new->mtdinfo->priv = ioremap(start, len); -+ if (!new->mtdinfo->priv) { -+ ERROR("ioremap failed\n"); -+ goto out2; -+ } -+ -+ -+ new->mtdinfo->name = name; -+ new->mtdinfo->size = len; -+ new->mtdinfo->flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE; -+ new->mtdinfo->erase = phram_erase; -+ new->mtdinfo->point = phram_point; -+ new->mtdinfo->unpoint = phram_unpoint; -+ new->mtdinfo->read = phram_read; -+ new->mtdinfo->write = phram_write; -+ new->mtdinfo->owner = THIS_MODULE; -+ new->mtdinfo->type = MTD_RAM; -+ new->mtdinfo->erasesize = 0x0; -+ -+ ret = -EAGAIN; -+ if (add_mtd_device(new->mtdinfo)) { -+ ERROR("Failed to register new device\n"); -+ goto out3; -+ } -+ -+ list_add_tail(&new->list, &phram_list); -+ return 0; -+ -+out3: -+ iounmap(new->mtdinfo->priv); -+out2: -+ kfree(new->mtdinfo); -+out1: -+ kfree(new); -+out0: -+ return ret; -+} -+ -+static int ustrtoul(const char *cp, char **endp, unsigned int base) -+{ -+ unsigned long result = simple_strtoul(cp, endp, base); -+ -+ switch (**endp) { -+ case 'G': -+ result *= 1024; -+ case 'M': -+ result *= 1024; -+ case 'k': -+ result *= 1024; -+ endp++; -+ } -+ return result; -+} -+ -+static int parse_num32(uint32_t *num32, const char *token) -+{ -+ char *endp; -+ unsigned long n; -+ -+ n = ustrtoul(token, &endp, 0); -+ if (*endp) -+ return -EINVAL; -+ -+ *num32 = n; -+ return 0; -+} -+ -+static int parse_name(char **pname, const char *token) -+{ -+ size_t len; -+ char *name; -+ -+ len = strlen(token) + 1; -+ if (len > 64) -+ return -ENOSPC; -+ -+ name = kmalloc(len, GFP_KERNEL); -+ if (!name) -+ return -ENOMEM; -+ -+ strcpy(name, token); -+ -+ *pname = name; -+ return 0; -+} -+ -+#define parse_err(fmt, args...) do { \ -+ ERROR(fmt , ## args); \ -+ return 0; \ -+} while (0) -+ -+static int phram_setup(const char *val, struct kernel_param *kp) -+{ -+ char buf[64+12+12], *str = buf; -+ char *token[3]; -+ char *name; -+ uint32_t start; -+ uint32_t len; -+ int i, ret; -+ -+ if (strnlen(val, sizeof(str)) >= sizeof(str)) -+ parse_err("parameter too long\n"); -+ -+ strcpy(str, val); -+ -+ for (i=0; i<3; i++) -+ token[i] = strsep(&str, ","); -+ -+ if (str) -+ parse_err("too many arguments\n"); -+ -+ if (!token[2]) -+ parse_err("not enough arguments\n"); -+ -+ ret = parse_name(&name, token[0]); -+ if (ret == -ENOMEM) -+ parse_err("out of memory\n"); -+ if (ret == -ENOSPC) -+ parse_err("name too long\n"); -+ if (ret) -+ return 0; -+ -+ ret = parse_num32(&start, token[1]); -+ if (ret) -+ parse_err("illegal start address\n"); -+ -+ ret = parse_num32(&len, token[2]); -+ if (ret) -+ parse_err("illegal device length\n"); -+ -+ register_device(name, start, len); -+ -+ return 0; -+} -+ -+module_param_call(phram, phram_setup, NULL, NULL, 000); -+MODULE_PARM_DESC(phram, "Memory region to map. \"map=<name>,<start><length>\""); -+ -+/* -+ * Just for compatibility with slram, this is horrible and should go someday. -+ */ -+static int __init slram_setup(const char *val, struct kernel_param *kp) -+{ -+ char buf[256], *str = buf; -+ -+ if (!val || !val[0]) -+ parse_err("no arguments to \"slram=\"\n"); -+ -+ if (strnlen(val, sizeof(str)) >= sizeof(str)) -+ parse_err("parameter too long\n"); -+ -+ strcpy(str, val); -+ -+ while (str) { -+ char *token[3]; -+ char *name; -+ uint32_t start; -+ uint32_t len; -+ int i, ret; -+ -+ for (i=0; i<3; i++) { -+ token[i] = strsep(&str, ","); -+ if (token[i]) -+ continue; -+ parse_err("wrong number of arguments to \"slram=\"\n"); -+ } -+ -+ /* name */ -+ ret = parse_name(&name, token[0]); -+ if (ret == -ENOMEM) -+ parse_err("of memory\n"); -+ if (ret == -ENOSPC) -+ parse_err("too long\n"); -+ if (ret) -+ return 1; -+ -+ /* start */ -+ ret = parse_num32(&start, token[1]); -+ if (ret) -+ parse_err("illegal start address\n"); -+ -+ /* len */ -+ if (token[2][0] == '+') -+ ret = parse_num32(&len, token[2] + 1); -+ else -+ ret = parse_num32(&len, token[2]); -+ -+ if (ret) -+ parse_err("illegal device length\n"); -+ -+ if (token[2][0] != '+') { -+ if (len < start) -+ parse_err("end < start\n"); -+ len -= start; -+ } -+ -+ register_device(name, start, len); -+ } -+ return 1; -+} -+ -+module_param_call(slram, slram_setup, NULL, NULL, 000); -+MODULE_PARM_DESC(slram, "List of memory regions to map. \"map=<name>,<start><length/end>\""); -+ -+ -+int __init init_phram(void) -+{ -+ printk(KERN_ERR "phram loaded\n"); -+ return 0; -+} -+ -+static void __exit cleanup_phram(void) -+{ -+ unregister_devices(); -+} -+ -+module_init(init_phram); -+module_exit(cleanup_phram); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>"); -+MODULE_DESCRIPTION("MTD driver for physical RAM"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/pmc551.c linux/drivers/mtd/devices/pmc551.c ---- linux-mips-2.4.27/drivers/mtd/devices/pmc551.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/devices/pmc551.c 2004-11-19 10:25:11.862205416 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * PMC551 PCI Mezzanine Ram Device - * -@@ -681,11 +681,6 @@ - - printk(KERN_INFO PMC551_VERSION); - -- if(!pci_present()) { -- printk(KERN_NOTICE "pmc551: PCI not enabled.\n"); -- return -ENODEV; -- } -- - /* - * PCU-bus chipset probe. - */ -@@ -787,10 +782,10 @@ - mtd->write = pmc551_write; - mtd->point = pmc551_point; - mtd->unpoint = pmc551_unpoint; -- mtd->module = THIS_MODULE; - mtd->type = MTD_RAM; - mtd->name = "PMC551 RAM board"; - mtd->erasesize = 0x10000; -+ mtd->owner = THIS_MODULE; - - if (add_mtd_device(mtd)) { - printk(KERN_NOTICE "pmc551: Failed to register new device\n"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/devices/slram.c linux/drivers/mtd/devices/slram.c ---- linux-mips-2.4.27/drivers/mtd/devices/slram.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/devices/slram.c 2004-11-19 10:25:11.863205264 +0100 -@@ -1,6 +1,6 @@ - /*====================================================================== - -- $Id$ -+ $Id$ - - This driver provides a method to access memory not used by the kernel - itself (i.e. if the kernel commandline mem=xxx is used). To actually -@@ -199,7 +199,7 @@ - (*curmtd)->mtdinfo->unpoint = slram_unpoint; - (*curmtd)->mtdinfo->read = slram_read; - (*curmtd)->mtdinfo->write = slram_write; -- (*curmtd)->mtdinfo->module = THIS_MODULE; -+ (*curmtd)->mtdinfo->owner = THIS_MODULE; - (*curmtd)->mtdinfo->type = MTD_RAM; - (*curmtd)->mtdinfo->erasesize = 0x0; - -diff -Nurb linux-mips-2.4.27/drivers/mtd/ftl.c linux/drivers/mtd/ftl.c ---- linux-mips-2.4.27/drivers/mtd/ftl.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/ftl.c 2004-11-19 10:25:11.630240680 +0100 -@@ -1,5 +1,5 @@ - /* This version ported to the Linux-MTD system by dwmw2@infradead.org -- * $Id$ -+ * $Id$ - * - * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> - * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups -@@ -55,8 +55,8 @@ - contact M-Systems (http://www.m-sys.com) directly. - - ======================================================================*/ -+#include <linux/mtd/blktrans.h> - #include <linux/module.h> --#include <linux/mtd/compatmac.h> - #include <linux/mtd/mtd.h> - /*#define PSYCHO_DEBUG */ - -@@ -68,43 +68,13 @@ - #include <linux/timer.h> - #include <linux/major.h> - #include <linux/fs.h> --#include <linux/ioctl.h> -+#include <linux/init.h> - #include <linux/hdreg.h> -- --#if (LINUX_VERSION_CODE >= 0x20100) - #include <linux/vmalloc.h> --#endif --#if (LINUX_VERSION_CODE >= 0x20303) - #include <linux/blkpg.h> --#endif -+#include <asm/uaccess.h> - - #include <linux/mtd/ftl.h> --/*====================================================================*/ --/* Stuff which really ought to be in compatmac.h */ -- --#if (LINUX_VERSION_CODE < 0x20328) --#define register_disk(dev, drive, minors, ops, size) \ -- do { (dev)->part[(drive)*(minors)].nr_sects = size; \ -- if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \ -- resetup_one_dev(dev, drive); } while (0) --#endif -- --#if (LINUX_VERSION_CODE < 0x20320) --#define BLK_DEFAULT_QUEUE(n) blk_dev[n].request_fn --#define blk_init_queue(q, req) q = (req) --#define blk_cleanup_queue(q) q = NULL --#define request_arg_t void --#else --#define request_arg_t request_queue_t *q --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) --#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT --#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT --#else --#define BLK_INC_USE_COUNT do {} while(0) --#define BLK_DEC_USE_COUNT do {} while(0) --#endif - - /*====================================================================*/ - -@@ -119,19 +89,6 @@ - #define FTL_MAJOR 44 - #endif - --/* Funky stuff for setting up a block device */ --#define MAJOR_NR FTL_MAJOR --#define DEVICE_NAME "ftl" --#define DEVICE_REQUEST do_ftl_request --#define DEVICE_ON(device) --#define DEVICE_OFF(device) -- --#define DEVICE_NR(minor) ((minor)>>5) --#define REGION_NR(minor) (((minor)>>3)&3) --#define PART_NR(minor) ((minor)&7) --#define MINOR_NR(dev,reg,part) (((dev)<<5)+((reg)<<3)+(part)) -- --#include <linux/blk.h> - - /*====================================================================*/ - -@@ -142,8 +99,7 @@ - #define MAX_REGION 4 - - /* Maximum number of partitions in an FTL region */ --#define PART_BITS 3 --#define MAX_PART 8 -+#define PART_BITS 4 - - /* Maximum number of outstanding erase requests per socket */ - #define MAX_ERASE 8 -@@ -154,7 +110,7 @@ - - /* Each memory region corresponds to a minor device */ - typedef struct partition_t { -- struct mtd_info *mtd; -+ struct mtd_blktrans_dev mbd; - u_int32_t state; - u_int32_t *VirtualBlockMap; - u_int32_t *VirtualPageMap; -@@ -179,21 +135,10 @@ - region_info_t region; - memory_handle_t handle; - #endif -- atomic_t open; - } partition_t; - --partition_t *myparts[MAX_MTD_DEVICES]; -- --static void ftl_notify_add(struct mtd_info *mtd); --static void ftl_notify_remove(struct mtd_info *mtd); -- - void ftl_freepart(partition_t *part); - --static struct mtd_notifier ftl_notifier = { -- add: ftl_notify_add, -- remove: ftl_notify_remove, --}; -- - /* Partition state flags */ - #define FTL_FORMATTED 0x01 - -@@ -204,51 +149,11 @@ - #define XFER_PREPARED 0x03 - #define XFER_FAILED 0x04 - --static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)]; --static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)]; --static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)]; -- --static struct gendisk ftl_gendisk = { -- major: FTL_MAJOR, -- major_name: "ftl", -- minor_shift: PART_BITS, -- max_p: MAX_PART, --#if (LINUX_VERSION_CODE < 0x20328) -- max_nr: MAX_DEV*MAX_PART, --#endif -- part: ftl_hd, -- sizes: ftl_sizes, --}; -- - /*====================================================================*/ - --static int ftl_ioctl(struct inode *inode, struct file *file, -- u_int cmd, u_long arg); --static int ftl_open(struct inode *inode, struct file *file); --static release_t ftl_close(struct inode *inode, struct file *file); --static int ftl_reread_partitions(int minor); - - static void ftl_erase_callback(struct erase_info *done); - --#if LINUX_VERSION_CODE < 0x20326 --static struct file_operations ftl_blk_fops = { -- open: ftl_open, -- release: ftl_close, -- ioctl: ftl_ioctl, -- read: block_read, -- write: block_write, -- fsync: block_fsync --}; --#else --static struct block_device_operations ftl_blk_fops = { --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) -- owner: THIS_MODULE, --#endif -- open: ftl_open, -- release: ftl_close, -- ioctl: ftl_ioctl, --}; --#endif - - /*====================================================================== - -@@ -264,13 +169,13 @@ - loff_t offset, max_offset; - int ret; - part->header.FormattedSize = 0; -- max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size; -+ max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size; - /* Search first megabyte for a valid FTL header */ - for (offset = 0; - (offset + sizeof(header)) < max_offset; -- offset += part->mtd->erasesize ? : 0x2000) { -+ offset += part->mbd.mtd->erasesize ? : 0x2000) { - -- ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret, -+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, - (unsigned char *)&header); - - if (ret) -@@ -283,15 +188,15 @@ - printk(KERN_NOTICE "ftl_cs: FTL header not found.\n"); - return -ENOENT; - } -- if ((le16_to_cpu(header.NumEraseUnits) > 65536) || header.BlockSize != 9 || -+ if (header.BlockSize != 9 || - (header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) || - (header.NumTransferUnits >= le16_to_cpu(header.NumEraseUnits))) { - printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n"); - return -1; - } -- if ((1 << header.EraseUnitSize) != part->mtd->erasesize) { -+ if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) { - printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n", -- 1 << header.EraseUnitSize,part->mtd->erasesize); -+ 1 << header.EraseUnitSize,part->mbd.mtd->erasesize); - return -1; - } - part->header = header; -@@ -326,7 +231,7 @@ - for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { - offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) - << part->header.EraseUnitSize); -- ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval, -+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, - (unsigned char *)&header); - - if (ret) -@@ -391,7 +296,7 @@ - part->EUNInfo[i].Deleted = 0; - offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); - -- ret = part->mtd->read(part->mtd, offset, -+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, - part->BlocksPerUnit * sizeof(u_int32_t), &retval, - (unsigned char *)part->bam_cache); - -@@ -456,7 +361,7 @@ - erase->len = 1 << part->header.EraseUnitSize; - erase->priv = (u_long)part; - -- ret = part->mtd->erase(part->mtd, erase); -+ ret = part->mbd.mtd->erase(part->mbd.mtd, erase); - - if (!ret) - xfer->EraseCount++; -@@ -523,7 +428,7 @@ - header.LogicalEUN = cpu_to_le16(0xffff); - header.EraseCount = cpu_to_le32(xfer->EraseCount); - -- ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header), -+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header), - &retlen, (u_char *)&header); - - if (ret) { -@@ -539,7 +444,7 @@ - - for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { - -- ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), -+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), - &retlen, (u_char *)&ctl); - - if (ret) -@@ -586,7 +491,7 @@ - - offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); - -- ret = part->mtd->read(part->mtd, offset, -+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, - part->BlocksPerUnit * sizeof(u_int32_t), - &retlen, (u_char *) (part->bam_cache)); - -@@ -604,7 +509,7 @@ - offset = xfer->Offset + 20; /* Bad! */ - unit = cpu_to_le16(0x7fff); - -- ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t), -+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), - &retlen, (u_char *) &unit); - - if (ret) { -@@ -624,7 +529,7 @@ - break; - case BLOCK_DATA: - case BLOCK_REPLACEMENT: -- ret = part->mtd->read(part->mtd, src, SECTOR_SIZE, -+ ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE, - &retlen, (u_char *) buf); - if (ret) { - printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n"); -@@ -632,7 +537,7 @@ - } - - -- ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE, -+ ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE, - &retlen, (u_char *) buf); - if (ret) { - printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n"); -@@ -651,7 +556,7 @@ - } - - /* Write the BAM to the transfer unit */ -- ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), -+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), - part->BlocksPerUnit * sizeof(int32_t), &retlen, - (u_char *)part->bam_cache); - if (ret) { -@@ -661,7 +566,7 @@ - - - /* All clear? Then update the LogicalEUN again */ -- ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t), -+ ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), - &retlen, (u_char *)&srcunitswap); - - if (ret) { -@@ -749,8 +654,8 @@ - if (queued) { - DEBUG(1, "ftl_cs: waiting for transfer " - "unit to be prepared...\n"); -- if (part->mtd->sync) -- part->mtd->sync(part->mtd); -+ if (part->mbd.mtd->sync) -+ part->mbd.mtd->sync(part->mbd.mtd); - } else { - static int ne = 0; - if (++ne < 5) -@@ -848,7 +753,7 @@ - /* Invalidate cache */ - part->bam_index = 0xffff; - -- ret = part->mtd->read(part->mtd, -+ ret = part->mbd.mtd->read(part->mbd.mtd, - part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), - part->BlocksPerUnit * sizeof(u_int32_t), - &retlen, (u_char *) (part->bam_cache)); -@@ -877,78 +782,6 @@ - - } /* find_free */ - --/*====================================================================== -- -- This gets a memory handle for the region corresponding to the -- minor device number. -- --======================================================================*/ -- --static int ftl_open(struct inode *inode, struct file *file) --{ -- int minor = MINOR(inode->i_rdev); -- partition_t *partition; -- -- if (minor>>4 >= MAX_MTD_DEVICES) -- return -ENODEV; -- -- partition = myparts[minor>>4]; -- -- if (!partition) -- return -ENODEV; -- -- if (partition->state != FTL_FORMATTED) -- return -ENXIO; -- -- if (ftl_gendisk.part[minor].nr_sects == 0) -- return -ENXIO; -- -- BLK_INC_USE_COUNT; -- -- if (!get_mtd_device(partition->mtd, -1)) { -- BLK_DEC_USE_COUNT; -- return -ENXIO; -- } -- -- if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) { -- put_mtd_device(partition->mtd); -- BLK_DEC_USE_COUNT; -- return -EROFS; -- } -- -- DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor); -- -- atomic_inc(&partition->open); -- -- return 0; --} -- --/*====================================================================*/ -- --static release_t ftl_close(struct inode *inode, struct file *file) --{ -- int minor = MINOR(inode->i_rdev); -- partition_t *part = myparts[minor >> 4]; -- int i; -- -- DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor); -- -- /* Wait for any pending erase operations to complete */ -- if (part->mtd->sync) -- part->mtd->sync(part->mtd); -- -- for (i = 0; i < part->header.NumTransferUnits; i++) { -- if (part->XferInfo[i].state == XFER_ERASED) -- prepare_xfer(part, i); -- } -- -- atomic_dec(&part->open); -- -- put_mtd_device(part->mtd); -- BLK_DEC_USE_COUNT; -- release_return(0); --} /* ftl_close */ -- - - /*====================================================================== - -@@ -983,7 +816,7 @@ - else { - offset = (part->EUNInfo[log_addr / bsize].Offset - + (log_addr % bsize)); -- ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE, -+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE, - &retlen, (u_char *) buffer); - - if (ret) { -@@ -1022,7 +855,7 @@ - le32_to_cpu(part->header.BAMOffset)); - - #ifdef PSYCHO_DEBUG -- ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t), -+ ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), - &retlen, (u_char *)&old_addr); - if (ret) { - printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret); -@@ -1059,7 +892,7 @@ - #endif - part->bam_cache[blk] = le_virt_addr; - } -- ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), -+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), - &retlen, (u_char *)&le_virt_addr); - - if (ret) { -@@ -1119,7 +952,7 @@ - part->EUNInfo[part->bam_index].Deleted++; - offset = (part->EUNInfo[part->bam_index].Offset + - blk * SECTOR_SIZE); -- ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen, -+ ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, - buffer); - - if (ret) { -@@ -1151,164 +984,32 @@ - return 0; - } /* ftl_write */ - --/*====================================================================== -- -- IOCTL calls for getting device parameters. -- --======================================================================*/ -- --static int ftl_ioctl(struct inode *inode, struct file *file, -- u_int cmd, u_long arg) -+static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) - { -- struct hd_geometry *geo = (struct hd_geometry *)arg; -- int ret = 0, minor = MINOR(inode->i_rdev); -- partition_t *part= myparts[minor >> 4]; -+ partition_t *part = (void *)dev; - u_long sect; - -- if (!part) -- return -ENODEV; /* How? */ -- -- switch (cmd) { -- case HDIO_GETGEO: -- ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo)); -- if (ret) return ret; -- /* Sort of arbitrary: round size down to 4K boundary */ -+ /* Sort of arbitrary: round size down to 4KiB boundary */ - sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; -- put_user(1, (char *)&geo->heads); -- put_user(8, (char *)&geo->sectors); -- put_user((sect>>3), (short *)&geo->cylinders); -- put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start); -- break; -- case BLKGETSIZE: -- ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg); -- break; --#ifdef BLKGETSIZE64 -- case BLKGETSIZE64: -- ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg); -- break; --#endif -- case BLKRRPART: -- ret = ftl_reread_partitions(minor); -- break; --#if (LINUX_VERSION_CODE < 0x20303) -- case BLKFLSBUF: --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) -- if (!capable(CAP_SYS_ADMIN)) return -EACCES; --#endif -- fsync_dev(inode->i_rdev); -- invalidate_buffers(inode->i_rdev); -- break; -- RO_IOCTLS(inode->i_rdev, arg); --#else -- case BLKROSET: -- case BLKROGET: -- case BLKFLSBUF: -- ret = blk_ioctl(inode->i_rdev, cmd, arg); -- break; --#endif -- default: -- ret = -EINVAL; -- } -- -- return ret; --} /* ftl_ioctl */ -- --/*====================================================================== - -- Handler for block device requests -+ geo->heads = 1; -+ geo->sectors = 8; -+ geo->cylinders = sect >> 3; - --======================================================================*/ -- --static int ftl_reread_partitions(int minor) --{ -- partition_t *part = myparts[minor >> 4]; -- int i, whole; -- -- DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor); -- if ((atomic_read(&part->open) > 1)) { -- return -EBUSY; -- } -- whole = minor & ~(MAX_PART-1); -- -- i = MAX_PART - 1; -- while (i-- > 0) { -- if (ftl_hd[whole+i].nr_sects > 0) { -- kdev_t rdev = MKDEV(FTL_MAJOR, whole+i); -- -- invalidate_device(rdev, 1); -- } -- ftl_hd[whole+i].start_sect = 0; -- ftl_hd[whole+i].nr_sects = 0; -- } -- -- scan_header(part); -- -- register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART, -- &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE); -- --#ifdef PCMCIA_DEBUG -- for (i = 0; i < MAX_PART; i++) { -- if (ftl_hd[whole+i].nr_sects > 0) -- printk(KERN_INFO " %d: start %ld size %ld\n", i, -- ftl_hd[whole+i].start_sect, -- ftl_hd[whole+i].nr_sects); -- } --#endif - return 0; - } - --/*====================================================================== -- -- Handler for block device requests -- --======================================================================*/ -- --static void do_ftl_request(request_arg_t) -+static int ftl_readsect(struct mtd_blktrans_dev *dev, -+ unsigned long block, char *buf) - { -- int ret, minor; -- partition_t *part; -- -- do { -- // sti(); -- INIT_REQUEST; -- -- minor = MINOR(CURRENT->rq_dev); -- -- part = myparts[minor >> 4]; -- if (part) { -- ret = 0; -- -- switch (CURRENT->cmd) { -- case READ: -- ret = ftl_read(part, CURRENT->buffer, -- CURRENT->sector+ftl_hd[minor].start_sect, -- CURRENT->current_nr_sectors); -- if (ret) printk("ftl_read returned %d\n", ret); -- break; -- -- case WRITE: -- ret = ftl_write(part, CURRENT->buffer, -- CURRENT->sector+ftl_hd[minor].start_sect, -- CURRENT->current_nr_sectors); -- if (ret) printk("ftl_write returned %d\n", ret); -- break; -- -- default: -- panic("ftl_cs: unknown block command!\n"); -- -- } -- } else { -- ret = 1; -- printk("NULL part in ftl_request\n"); -- } -- -- if (!ret) { -- CURRENT->sector += CURRENT->current_nr_sectors; -- } -+ return ftl_read((void *)dev, buf, block, 1); -+} - -- end_request((ret == 0) ? 1 : 0); -- } while (1); --} /* do_ftl_request */ -+static int ftl_writesect(struct mtd_blktrans_dev *dev, -+ unsigned long block, char *buf) -+{ -+ return ftl_write((void *)dev, buf, block, 1); -+} - - /*====================================================================*/ - -@@ -1337,19 +1038,9 @@ - - } /* ftl_freepart */ - --static void ftl_notify_add(struct mtd_info *mtd) -+static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) - { - partition_t *partition; -- int device; -- -- for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++) -- ; -- -- if (device == MAX_MTD_DEVICES) { -- printk(KERN_NOTICE "Maximum number of FTL partitions reached\n" -- "Not scanning <%s>\n", mtd->name); -- return; -- } - - partition = kmalloc(sizeof(partition_t), GFP_KERNEL); - -@@ -1361,92 +1052,55 @@ - - memset(partition, 0, sizeof(partition_t)); - -- partition->mtd = mtd; -+ partition->mbd.mtd = mtd; - - if ((scan_header(partition) == 0) && - (build_maps(partition) == 0)) { - - partition->state = FTL_FORMATTED; -- atomic_set(&partition->open, 0); -- myparts[device] = partition; -- ftl_reread_partitions(device << 4); - #ifdef PCMCIA_DEBUG -- printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n", -+ printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", - le32_to_cpu(partition->header.FormattedSize) >> 10); - #endif -+ partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9; -+ partition->mbd.blksize = SECTOR_SIZE; -+ partition->mbd.tr = tr; -+ partition->mbd.devnum = -1; -+ if (add_mtd_blktrans_dev((void *)partition)) -+ kfree(partition); -+ - } else - kfree(partition); - } - --static void ftl_notify_remove(struct mtd_info *mtd) -+static void ftl_remove_dev(struct mtd_blktrans_dev *dev) - { -- int i,j; -- -- /* Q: What happens if you try to remove a device which has -- * a currently-open FTL partition on it? -- * -- * A: You don't. The ftl_open routine is responsible for -- * increasing the use count of the driver module which -- * it uses. -- */ -- -- /* That's the theory, anyway :) */ -- -- for (i=0; i< MAX_MTD_DEVICES; i++) -- if (myparts[i] && myparts[i]->mtd == mtd) { -- -- if (myparts[i]->state == FTL_FORMATTED) -- ftl_freepart(myparts[i]); -- -- myparts[i]->state = 0; -- for (j=0; j<16; j++) { -- ftl_gendisk.part[j].nr_sects=0; -- ftl_gendisk.part[j].start_sect=0; -- } -- kfree(myparts[i]); -- myparts[i] = NULL; -- } -+ del_mtd_blktrans_dev(dev); -+ kfree(dev); - } - -+struct mtd_blktrans_ops ftl_tr = { -+ .name = "ftl", -+ .major = FTL_MAJOR, -+ .part_bits = PART_BITS, -+ .readsect = ftl_readsect, -+ .writesect = ftl_writesect, -+ .getgeo = ftl_getgeo, -+ .add_mtd = ftl_add_mtd, -+ .remove_dev = ftl_remove_dev, -+ .owner = THIS_MODULE, -+}; -+ - int init_ftl(void) - { -- int i; -- -- memset(myparts, 0, sizeof(myparts)); -+ DEBUG(0, "$Id$\n"); - -- DEBUG(0, "$Id$\n"); -- -- if (register_blkdev(FTL_MAJOR, "ftl", &ftl_blk_fops)) { -- printk(KERN_NOTICE "ftl_cs: unable to grab major " -- "device number!\n"); -- return -EAGAIN; -- } -- -- for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++) -- ftl_blocksizes[i] = 1024; -- for (i = 0; i < MAX_DEV*MAX_PART; i++) { -- ftl_hd[i].nr_sects = 0; -- ftl_hd[i].start_sect = 0; -- } -- blksize_size[FTL_MAJOR] = ftl_blocksizes; -- ftl_gendisk.major = FTL_MAJOR; -- blk_init_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR), &do_ftl_request); -- add_gendisk(&ftl_gendisk); -- -- register_mtd_user(&ftl_notifier); -- -- return 0; -+ return register_mtd_blktrans(&ftl_tr); - } - - static void __exit cleanup_ftl(void) - { -- unregister_mtd_user(&ftl_notifier); -- -- unregister_blkdev(FTL_MAJOR, "ftl"); -- blk_cleanup_queue(BLK_DEFAULT_QUEUE(FTL_MAJOR)); -- blksize_size[FTL_MAJOR] = NULL; -- -- del_gendisk(&ftl_gendisk); -+ deregister_mtd_blktrans(&ftl_tr); - } - - module_init(init_ftl); -diff -Nurb linux-mips-2.4.27/drivers/mtd/inftlcore.c linux/drivers/mtd/inftlcore.c ---- linux-mips-2.4.27/drivers/mtd/inftlcore.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/inftlcore.c 2004-11-19 10:25:11.632240376 +0100 -@@ -0,0 +1,900 @@ -+/* -+ * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) -+ * -+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) -+ * -+ * Based heavily on the nftlcore.c code which is: -+ * (c) 1999 Machine Vision Holdings, Inc. -+ * Author: David Woodhouse <dwmw2@infradead.org> -+ * -+ * $Id$ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/config.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <linux/kmod.h> -+#include <linux/hdreg.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nftl.h> -+#include <linux/mtd/inftl.h> -+#include <asm/uaccess.h> -+#include <asm/errno.h> -+#include <asm/io.h> -+ -+/* -+ * Maximum number of loops while examining next block, to have a -+ * chance to detect consistency problems (they should never happen -+ * because of the checks done in the mounting. -+ */ -+#define MAX_LOOPS 10000 -+ -+extern void INFTL_dumptables(struct INFTLrecord *inftl); -+extern void INFTL_dumpVUchains(struct INFTLrecord *inftl); -+ -+static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) -+{ -+ struct INFTLrecord *inftl; -+ unsigned long temp; -+ -+ if (mtd->ecctype != MTD_ECC_RS_DiskOnChip) -+ return; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name); -+ -+ inftl = kmalloc(sizeof(*inftl), GFP_KERNEL); -+ -+ if (!inftl) { -+ printk(KERN_WARNING "INFTL: Out of memory for data structures\n"); -+ return; -+ } -+ memset(inftl, 0, sizeof(*inftl)); -+ -+ inftl->mbd.mtd = mtd; -+ inftl->mbd.devnum = -1; -+ inftl->mbd.blksize = 512; -+ inftl->mbd.tr = tr; -+ -+ if (INFTL_mount(inftl) < 0) { -+ printk(KERN_WARNING "INFTL: could not mount device\n"); -+ kfree(inftl); -+ return; -+ } -+ -+ /* OK, it's a new one. Set up all the data structures. */ -+ -+ /* Calculate geometry */ -+ inftl->cylinders = 1024; -+ inftl->heads = 16; -+ -+ temp = inftl->cylinders * inftl->heads; -+ inftl->sectors = inftl->mbd.size / temp; -+ if (inftl->mbd.size % temp) { -+ inftl->sectors++; -+ temp = inftl->cylinders * inftl->sectors; -+ inftl->heads = inftl->mbd.size / temp; -+ -+ if (inftl->mbd.size % temp) { -+ inftl->heads++; -+ temp = inftl->heads * inftl->sectors; -+ inftl->cylinders = inftl->mbd.size / temp; -+ } -+ } -+ -+ if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { -+ /* -+ Oh no we don't have -+ mbd.size == heads * cylinders * sectors -+ */ -+ printk(KERN_WARNING "INFTL: cannot calculate a geometry to " -+ "match size of 0x%lx.\n", inftl->mbd.size); -+ printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " -+ "(== 0x%lx sects)\n", -+ inftl->cylinders, inftl->heads , inftl->sectors, -+ (long)inftl->cylinders * (long)inftl->heads * -+ (long)inftl->sectors ); -+ } -+ -+ if (add_mtd_blktrans_dev(&inftl->mbd)) { -+ if (inftl->PUtable) -+ kfree(inftl->PUtable); -+ if (inftl->VUtable) -+ kfree(inftl->VUtable); -+ kfree(inftl); -+ return; -+ } -+#ifdef PSYCHO_DEBUG -+ printk(KERN_INFO "INFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a'); -+#endif -+ return; -+} -+ -+static void inftl_remove_dev(struct mtd_blktrans_dev *dev) -+{ -+ struct INFTLrecord *inftl = (void *)dev; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum); -+ -+ del_mtd_blktrans_dev(dev); -+ -+ if (inftl->PUtable) -+ kfree(inftl->PUtable); -+ if (inftl->VUtable) -+ kfree(inftl->VUtable); -+ kfree(inftl); -+} -+ -+/* -+ * Actual INFTL access routines. -+ */ -+ -+/* -+ * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition. -+ * This function is used when the give Virtual Unit Chain. -+ */ -+static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) -+{ -+ u16 pot = inftl->LastFreeEUN; -+ int silly = inftl->nb_blocks; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=0x%x," -+ "desperate=%d)\n", (int)inftl, desperate); -+ -+ /* -+ * Normally, we force a fold to happen before we run out of free -+ * blocks completely. -+ */ -+ if (!desperate && inftl->numfreeEUNs < 2) { -+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free " -+ "EUNs (%d)\n", inftl->numfreeEUNs); -+ return 0xffff; -+ } -+ -+ /* Scan for a free block */ -+ do { -+ if (inftl->PUtable[pot] == BLOCK_FREE) { -+ inftl->LastFreeEUN = pot; -+ return pot; -+ } -+ -+ if (++pot > inftl->lastEUN) -+ pot = 0; -+ -+ if (!silly--) { -+ printk(KERN_WARNING "INFTL: no free blocks found! " -+ "EUN range = %d - %d\n", 0, inftl->LastFreeEUN); -+ return BLOCK_NIL; -+ } -+ } while (pot != inftl->LastFreeEUN); -+ -+ return BLOCK_NIL; -+} -+ -+static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock) -+{ -+ u16 BlockMap[MAX_SECTORS_PER_UNIT]; -+ unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT]; -+ unsigned int thisEUN, prevEUN, status; -+ int block, silly; -+ unsigned int targetEUN; -+ struct inftl_oob oob; -+ size_t retlen; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=0x%x,thisVUC=%d," -+ "pending=%d)\n", (int)inftl, thisVUC, pendingblock); -+ -+ memset(BlockMap, 0xff, sizeof(BlockMap)); -+ memset(BlockDeleted, 0, sizeof(BlockDeleted)); -+ -+ thisEUN = targetEUN = inftl->VUtable[thisVUC]; -+ -+ if (thisEUN == BLOCK_NIL) { -+ printk(KERN_WARNING "INFTL: trying to fold non-existent " -+ "Virtual Unit Chain %d!\n", thisVUC); -+ return BLOCK_NIL; -+ } -+ -+ /* -+ * Scan to find the Erase Unit which holds the actual data for each -+ * 512-byte block within the Chain. -+ */ -+ silly = MAX_LOOPS; -+ while (thisEUN < inftl->nb_blocks) { -+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) { -+ if ((BlockMap[block] != 0xffff) || BlockDeleted[block]) -+ continue; -+ -+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) -+ + (block * SECTORSIZE), 16 , &retlen, -+ (char *)&oob) < 0) -+ status = SECTOR_IGNORE; -+ else -+ status = oob.b.Status | oob.b.Status1; -+ -+ switch(status) { -+ case SECTOR_FREE: -+ case SECTOR_IGNORE: -+ break; -+ case SECTOR_USED: -+ BlockMap[block] = thisEUN; -+ continue; -+ case SECTOR_DELETED: -+ BlockDeleted[block] = 1; -+ continue; -+ default: -+ printk(KERN_WARNING "INFTL: unknown status " -+ "for block %d in EUN %d: %x\n", -+ block, thisEUN, status); -+ break; -+ } -+ } -+ -+ if (!silly--) { -+ printk(KERN_WARNING "INFTL: infinite loop in Virtual " -+ "Unit Chain 0x%x\n", thisVUC); -+ return BLOCK_NIL; -+ } -+ -+ thisEUN = inftl->PUtable[thisEUN]; -+ } -+ -+ /* -+ * OK. We now know the location of every block in the Virtual Unit -+ * Chain, and the Erase Unit into which we are supposed to be copying. -+ * Go for it. -+ */ -+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n", -+ thisVUC, targetEUN); -+ -+ for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) { -+ unsigned char movebuf[SECTORSIZE]; -+ int ret; -+ -+ /* -+ * If it's in the target EUN already, or if it's pending write, -+ * do nothing. -+ */ -+ if (BlockMap[block] == targetEUN || (pendingblock == -+ (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) { -+ continue; -+ } -+ -+ /* -+ * Copy only in non free block (free blocks can only -+ * happen in case of media errors or deleted blocks). -+ */ -+ if (BlockMap[block] == BLOCK_NIL) -+ continue; -+ -+ ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize * -+ BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, -+ &retlen, movebuf, (char *)&oob, NULL); -+ if (ret < 0) { -+ ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize * -+ BlockMap[block]) + (block * SECTORSIZE), -+ SECTORSIZE, &retlen, movebuf, (char *)&oob, -+ NULL); -+ if (ret != -EIO) -+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " -+ "away on retry?\n"); -+ } -+ MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) + -+ (block * SECTORSIZE), SECTORSIZE, &retlen, -+ movebuf, (char *)&oob, NULL); -+ } -+ -+ /* -+ * Newest unit in chain now contains data from _all_ older units. -+ * So go through and erase each unit in chain, oldest first. (This -+ * is important, by doing oldest first if we crash/reboot then it -+ * it is relatively simple to clean up the mess). -+ */ -+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n", -+ thisVUC); -+ -+ for (;;) { -+ /* Find oldest unit in chain. */ -+ thisEUN = inftl->VUtable[thisVUC]; -+ prevEUN = BLOCK_NIL; -+ while (inftl->PUtable[thisEUN] != BLOCK_NIL) { -+ prevEUN = thisEUN; -+ thisEUN = inftl->PUtable[thisEUN]; -+ } -+ -+ /* Check if we are all done */ -+ if (thisEUN == targetEUN) -+ break; -+ -+ if (INFTL_formatblock(inftl, thisEUN) < 0) { -+ /* -+ * Could not erase : mark block as reserved. -+ * FixMe: Update Bad Unit Table on disk. -+ */ -+ inftl->PUtable[thisEUN] = BLOCK_RESERVED; -+ } else { -+ /* Correctly erased : mark it as free */ -+ inftl->PUtable[thisEUN] = BLOCK_FREE; -+ inftl->PUtable[prevEUN] = BLOCK_NIL; -+ inftl->numfreeEUNs++; -+ } -+ } -+ -+ return targetEUN; -+} -+ -+u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) -+{ -+ /* -+ * This is the part that needs some cleverness applied. -+ * For now, I'm doing the minimum applicable to actually -+ * get the thing to work. -+ * Wear-levelling and other clever stuff needs to be implemented -+ * and we also need to do some assessment of the results when -+ * the system loses power half-way through the routine. -+ */ -+ u16 LongestChain = 0; -+ u16 ChainLength = 0, thislen; -+ u16 chain, EUN; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=0x%x," -+ "pending=%d)\n", (int)inftl, pendingblock); -+ -+ for (chain = 0; chain < inftl->nb_blocks; chain++) { -+ EUN = inftl->VUtable[chain]; -+ thislen = 0; -+ -+ while (EUN <= inftl->lastEUN) { -+ thislen++; -+ EUN = inftl->PUtable[EUN]; -+ if (thislen > 0xff00) { -+ printk(KERN_WARNING "INFTL: endless loop in " -+ "Virtual Chain %d: Unit %x\n", -+ chain, EUN); -+ /* -+ * Actually, don't return failure. -+ * Just ignore this chain and get on with it. -+ */ -+ thislen = 0; -+ break; -+ } -+ } -+ -+ if (thislen > ChainLength) { -+ ChainLength = thislen; -+ LongestChain = chain; -+ } -+ } -+ -+ if (ChainLength < 2) { -+ printk(KERN_WARNING "INFTL: no Virtual Unit Chains available " -+ "for folding. Failing request\n"); -+ return BLOCK_NIL; -+ } -+ -+ return INFTL_foldchain(inftl, LongestChain, pendingblock); -+} -+ -+static int nrbits(unsigned int val, int bitcount) -+{ -+ int i, total = 0; -+ -+ for (i = 0; (i < bitcount); i++) -+ total += (((0x1 << i) & val) ? 1 : 0); -+ return total; -+} -+ -+/* -+ * INFTL_findwriteunit: Return the unit number into which we can write -+ * for this block. Make it available if it isn't already. -+ */ -+static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) -+{ -+ unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE); -+ unsigned int thisEUN, writeEUN, prev_block, status; -+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1); -+ struct inftl_oob oob; -+ struct inftl_bci bci; -+ unsigned char anac, nacs, parity; -+ size_t retlen; -+ int silly, silly2 = 3; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=0x%x," -+ "block=%d)\n", (int)inftl, block); -+ -+ do { -+ /* -+ * Scan the media to find a unit in the VUC which has -+ * a free space for the block in question. -+ */ -+ writeEUN = BLOCK_NIL; -+ thisEUN = inftl->VUtable[thisVUC]; -+ silly = MAX_LOOPS; -+ -+ while (thisEUN <= inftl->lastEUN) { -+ MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + -+ blockofs, 8, &retlen, (char *)&bci); -+ -+ status = bci.Status | bci.Status1; -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " -+ "EUN %d is %x\n", block , writeEUN, status); -+ -+ switch(status) { -+ case SECTOR_FREE: -+ writeEUN = thisEUN; -+ break; -+ case SECTOR_DELETED: -+ case SECTOR_USED: -+ /* Can't go any further */ -+ goto hitused; -+ case SECTOR_IGNORE: -+ break; -+ default: -+ /* -+ * Invalid block. Don't use it any more. -+ * Must implement. -+ */ -+ break; -+ } -+ -+ if (!silly--) { -+ printk(KERN_WARNING "INFTL: infinite loop in " -+ "Virtual Unit Chain 0x%x\n", thisVUC); -+ return 0xffff; -+ } -+ -+ /* Skip to next block in chain */ -+ thisEUN = inftl->PUtable[thisEUN]; -+ } -+ -+hitused: -+ if (writeEUN != BLOCK_NIL) -+ return writeEUN; -+ -+ -+ /* -+ * OK. We didn't find one in the existing chain, or there -+ * is no existing chain. Allocate a new one. -+ */ -+ writeEUN = INFTL_findfreeblock(inftl, 0); -+ -+ if (writeEUN == BLOCK_NIL) { -+ /* -+ * That didn't work - there were no free blocks just -+ * waiting to be picked up. We're going to have to fold -+ * a chain to make room. -+ */ -+ thisEUN = INFTL_makefreeblock(inftl, 0xffff); -+ -+ /* -+ * Hopefully we free something, lets try again. -+ * This time we are desperate... -+ */ -+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 " -+ "to find free EUN to accommodate write to " -+ "VUC %d\n", thisVUC); -+ writeEUN = INFTL_findfreeblock(inftl, 1); -+ if (writeEUN == BLOCK_NIL) { -+ /* -+ * Ouch. This should never happen - we should -+ * always be able to make some room somehow. -+ * If we get here, we've allocated more storage -+ * space than actual media, or our makefreeblock -+ * routine is missing something. -+ */ -+ printk(KERN_WARNING "INFTL: cannot make free " -+ "space.\n"); -+#ifdef DEBUG -+ INFTL_dumptables(inftl); -+ INFTL_dumpVUchains(inftl); -+#endif -+ return BLOCK_NIL; -+ } -+ } -+ -+ /* -+ * Insert new block into virtual chain. Firstly update the -+ * block headers in flash... -+ */ -+ anac = 0; -+ nacs = 0; -+ thisEUN = inftl->VUtable[thisVUC]; -+ if (thisEUN != BLOCK_NIL) { -+ MTD_READOOB(inftl->mbd.mtd, thisEUN * inftl->EraseSize -+ + 8, 8, &retlen, (char *)&oob.u); -+ anac = oob.u.a.ANAC + 1; -+ nacs = oob.u.a.NACs + 1; -+ } -+ -+ prev_block = inftl->VUtable[thisVUC]; -+ if (prev_block < inftl->nb_blocks) -+ prev_block -= inftl->firstEUN; -+ -+ parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0; -+ parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; -+ parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; -+ parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; -+ -+ oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); -+ oob.u.a.prevUnitNo = cpu_to_le16(prev_block); -+ oob.u.a.ANAC = anac; -+ oob.u.a.NACs = nacs; -+ oob.u.a.parityPerField = parity; -+ oob.u.a.discarded = 0xaa; -+ -+ MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 8, 8, -+ &retlen, (char *)&oob.u); -+ -+ /* Also back up header... */ -+ oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC); -+ oob.u.b.prevUnitNo = cpu_to_le16(prev_block); -+ oob.u.b.ANAC = anac; -+ oob.u.b.NACs = nacs; -+ oob.u.b.parityPerField = parity; -+ oob.u.b.discarded = 0xaa; -+ -+ MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + -+ SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); -+ -+ inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; -+ inftl->VUtable[thisVUC] = writeEUN; -+ -+ inftl->numfreeEUNs--; -+ return writeEUN; -+ -+ } while (silly2--); -+ -+ printk(KERN_WARNING "INFTL: error folding to make room for Virtual " -+ "Unit Chain 0x%x\n", thisVUC); -+ return 0xffff; -+} -+ -+/* -+ * Given a Virtual Unit Chain, see if it can be deleted, and if so do it. -+ */ -+static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) -+{ -+ unsigned char BlockUsed[MAX_SECTORS_PER_UNIT]; -+ unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT]; -+ unsigned int thisEUN, status; -+ int block, silly; -+ struct inftl_bci bci; -+ size_t retlen; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=0x%x," -+ "thisVUC=%d)\n", (int)inftl, thisVUC); -+ -+ memset(BlockUsed, 0, sizeof(BlockUsed)); -+ memset(BlockDeleted, 0, sizeof(BlockDeleted)); -+ -+ thisEUN = inftl->VUtable[thisVUC]; -+ if (thisEUN == BLOCK_NIL) { -+ printk(KERN_WARNING "INFTL: trying to delete non-existent " -+ "Virtual Unit Chain %d!\n", thisVUC); -+ return; -+ } -+ -+ /* -+ * Scan through the Erase Units to determine whether any data is in -+ * each of the 512-byte blocks within the Chain. -+ */ -+ silly = MAX_LOOPS; -+ while (thisEUN < inftl->nb_blocks) { -+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) { -+ if (BlockUsed[block] || BlockDeleted[block]) -+ continue; -+ -+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) -+ + (block * SECTORSIZE), 8 , &retlen, -+ (char *)&bci) < 0) -+ status = SECTOR_IGNORE; -+ else -+ status = bci.Status | bci.Status1; -+ -+ switch(status) { -+ case SECTOR_FREE: -+ case SECTOR_IGNORE: -+ break; -+ case SECTOR_USED: -+ BlockUsed[block] = 1; -+ continue; -+ case SECTOR_DELETED: -+ BlockDeleted[block] = 1; -+ continue; -+ default: -+ printk(KERN_WARNING "INFTL: unknown status " -+ "for block %d in EUN %d: 0x%x\n", -+ block, thisEUN, status); -+ } -+ } -+ -+ if (!silly--) { -+ printk(KERN_WARNING "INFTL: infinite loop in Virtual " -+ "Unit Chain 0x%x\n", thisVUC); -+ return; -+ } -+ -+ thisEUN = inftl->PUtable[thisEUN]; -+ } -+ -+ for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) -+ if (BlockUsed[block]) -+ return; -+ -+ /* -+ * For each block in the chain free it and make it available -+ * for future use. Erase from the oldest unit first. -+ */ -+ DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC); -+ -+ for (;;) { -+ u16 *prevEUN = &inftl->VUtable[thisVUC]; -+ thisEUN = *prevEUN; -+ -+ /* If the chain is all gone already, we're done */ -+ if (thisEUN == BLOCK_NIL) { -+ DEBUG(MTD_DEBUG_LEVEL2, "INFTL: Empty VUC %d for deletion was already absent\n", thisEUN); -+ return; -+ } -+ -+ /* Find oldest unit in chain. */ -+ while (inftl->PUtable[thisEUN] != BLOCK_NIL) { -+ BUG_ON(thisEUN >= inftl->nb_blocks); -+ -+ prevEUN = &inftl->PUtable[thisEUN]; -+ thisEUN = *prevEUN; -+ } -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "Deleting EUN %d from VUC %d\n", -+ thisEUN, thisVUC); -+ -+ if (INFTL_formatblock(inftl, thisEUN) < 0) { -+ /* -+ * Could not erase : mark block as reserved. -+ * FixMe: Update Bad Unit Table on medium. -+ */ -+ inftl->PUtable[thisEUN] = BLOCK_RESERVED; -+ } else { -+ /* Correctly erased : mark it as free */ -+ inftl->PUtable[thisEUN] = BLOCK_FREE; -+ inftl->numfreeEUNs++; -+ } -+ -+ /* Now sort out whatever was pointing to it... */ -+ *prevEUN = BLOCK_NIL; -+ -+ /* Ideally we'd actually be responsive to new -+ requests while we're doing this -- if there's -+ free space why should others be made to wait? */ -+ cond_resched(); -+ } -+ -+ inftl->VUtable[thisVUC] = BLOCK_NIL; -+} -+ -+static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block) -+{ -+ unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; -+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); -+ unsigned int status; -+ int silly = MAX_LOOPS; -+ size_t retlen; -+ struct inftl_bci bci; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=0x%x," -+ "block=%d)\n", (int)inftl, block); -+ -+ while (thisEUN < inftl->nb_blocks) { -+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + -+ blockofs, 8, &retlen, (char *)&bci) < 0) -+ status = SECTOR_IGNORE; -+ else -+ status = bci.Status | bci.Status1; -+ -+ switch (status) { -+ case SECTOR_FREE: -+ case SECTOR_IGNORE: -+ break; -+ case SECTOR_DELETED: -+ thisEUN = BLOCK_NIL; -+ goto foundit; -+ case SECTOR_USED: -+ goto foundit; -+ default: -+ printk(KERN_WARNING "INFTL: unknown status for " -+ "block %d in EUN %d: 0x%x\n", -+ block, thisEUN, status); -+ break; -+ } -+ -+ if (!silly--) { -+ printk(KERN_WARNING "INFTL: infinite loop in Virtual " -+ "Unit Chain 0x%x\n", -+ block / (inftl->EraseSize / SECTORSIZE)); -+ return 1; -+ } -+ thisEUN = inftl->PUtable[thisEUN]; -+ } -+ -+foundit: -+ if (thisEUN != BLOCK_NIL) { -+ loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; -+ -+ if (MTD_READOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0) -+ return -EIO; -+ bci.Status = bci.Status1 = SECTOR_DELETED; -+ if (MTD_WRITEOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0) -+ return -EIO; -+ INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE)); -+ } -+ return 0; -+} -+ -+static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, -+ char *buffer) -+{ -+ struct INFTLrecord *inftl = (void *)mbd; -+ unsigned int writeEUN; -+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); -+ size_t retlen; -+ u8 eccbuf[6]; -+ char *p, *pend; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=0x%x,block=%d," -+ "buffer=0x%x)\n", (int)inftl, block, (int)buffer); -+ -+ /* Is block all zero? */ -+ pend = buffer + SECTORSIZE; -+ for (p = buffer; p < pend && !*p; p++) -+ ; -+ -+ if (p < pend) { -+ writeEUN = INFTL_findwriteunit(inftl, block); -+ -+ if (writeEUN == BLOCK_NIL) { -+ printk(KERN_WARNING "inftl_writeblock(): cannot find " -+ "block to write to\n"); -+ /* -+ * If we _still_ haven't got a block to use, -+ * we're screwed. -+ */ -+ return 1; -+ } -+ -+ MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) + -+ blockofs, SECTORSIZE, &retlen, (char *)buffer, -+ (char *)eccbuf, NULL); -+ /* -+ * No need to write SECTOR_USED flags since they are written -+ * in mtd_writeecc -+ */ -+ } else { -+ INFTL_deleteblock(inftl, block); -+ } -+ -+ return 0; -+} -+ -+static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, -+ char *buffer) -+{ -+ struct INFTLrecord *inftl = (void *)mbd; -+ unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; -+ unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); -+ unsigned int status; -+ int silly = MAX_LOOPS; -+ struct inftl_bci bci; -+ size_t retlen; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=0x%x,block=%d," -+ "buffer=0x%x)\n", (int)inftl, block, (int)buffer); -+ -+ while (thisEUN < inftl->nb_blocks) { -+ if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + -+ blockofs, 8, &retlen, (char *)&bci) < 0) -+ status = SECTOR_IGNORE; -+ else -+ status = bci.Status | bci.Status1; -+ -+ switch (status) { -+ case SECTOR_DELETED: -+ thisEUN = BLOCK_NIL; -+ goto foundit; -+ case SECTOR_USED: -+ goto foundit; -+ case SECTOR_FREE: -+ case SECTOR_IGNORE: -+ break; -+ default: -+ printk(KERN_WARNING "INFTL: unknown status for " -+ "block %ld in EUN %d: 0x%04x\n", -+ block, thisEUN, status); -+ break; -+ } -+ -+ if (!silly--) { -+ printk(KERN_WARNING "INFTL: infinite loop in " -+ "Virtual Unit Chain 0x%lx\n", -+ block / (inftl->EraseSize / SECTORSIZE)); -+ return 1; -+ } -+ -+ thisEUN = inftl->PUtable[thisEUN]; -+ } -+ -+foundit: -+ if (thisEUN == BLOCK_NIL) { -+ /* The requested block is not on the media, return all 0x00 */ -+ memset(buffer, 0, SECTORSIZE); -+ } else { -+ size_t retlen; -+ loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; -+ u_char eccbuf[6]; -+ if (MTD_READECC(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen, -+ buffer, eccbuf, NULL)) -+ return -EIO; -+ } -+ return 0; -+} -+ -+static int inftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) -+{ -+ struct INFTLrecord *inftl = (void *)dev; -+ -+ geo->heads = inftl->heads; -+ geo->sectors = inftl->sectors; -+ geo->cylinders = inftl->cylinders; -+ -+ return 0; -+} -+ -+struct mtd_blktrans_ops inftl_tr = { -+ .name = "inftl", -+ .major = INFTL_MAJOR, -+ .part_bits = INFTL_PARTN_BITS, -+ .getgeo = inftl_getgeo, -+ .readsect = inftl_readblock, -+ .writesect = inftl_writeblock, -+ .add_mtd = inftl_add_mtd, -+ .remove_dev = inftl_remove_dev, -+ .owner = THIS_MODULE, -+}; -+ -+extern char inftlmountrev[]; -+ -+int __init init_inftl(void) -+{ -+ printk(KERN_INFO "INFTL: inftlcore.c $Revision$, " -+ "inftlmount.c %s\n", inftlmountrev); -+ -+ return register_mtd_blktrans(&inftl_tr); -+} -+ -+static void __exit cleanup_inftl(void) -+{ -+ deregister_mtd_blktrans(&inftl_tr); -+} -+ -+module_init(init_inftl); -+module_exit(cleanup_inftl); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al."); -+MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/inftlmount.c linux/drivers/mtd/inftlmount.c ---- linux-mips-2.4.27/drivers/mtd/inftlmount.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/inftlmount.c 2004-11-19 10:25:11.633240224 +0100 -@@ -0,0 +1,817 @@ -+/* -+ * inftlmount.c -- INFTL mount code with extensive checks. -+ * -+ * Author: Greg Ungerer (gerg@snapgear.com) -+ * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com) -+ * -+ * Based heavily on the nftlmount.c code which is: -+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) -+ * Copyright (C) 2000 Netgem S.A. -+ * -+ * $Id$ -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <asm/errno.h> -+#include <asm/io.h> -+#include <asm/uaccess.h> -+#include <linux/miscdevice.h> -+#include <linux/pci.h> -+#include <linux/delay.h> -+#include <linux/slab.h> -+#include <linux/sched.h> -+#include <linux/init.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nftl.h> -+#include <linux/mtd/inftl.h> -+#include <linux/mtd/compatmac.h> -+ -+char inftlmountrev[]="$Revision$"; -+ -+/* -+ * find_boot_record: Find the INFTL Media Header and its Spare copy which -+ * contains the various device information of the INFTL partition and -+ * Bad Unit Table. Update the PUtable[] table according to the Bad -+ * Unit Table. PUtable[] is used for management of Erase Unit in -+ * other routines in inftlcore.c and inftlmount.c. -+ */ -+static int find_boot_record(struct INFTLrecord *inftl) -+{ -+ struct inftl_unittail h1; -+ //struct inftl_oob oob; -+ unsigned int i, block, boot_record_count = 0; -+ u8 buf[SECTORSIZE]; -+ struct INFTLMediaHeader *mh = &inftl->MediaHdr; -+ struct INFTLPartition *ip; -+ int retlen; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=0x%x)\n", -+ (int)inftl); -+ -+ /* -+ * Assume logical EraseSize == physical erasesize for starting the -+ * scan. We'll sort it out later if we find a MediaHeader which says -+ * otherwise. -+ */ -+ inftl->EraseSize = inftl->mbd.mtd->erasesize; -+ inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; -+ -+ inftl->MediaUnit = BLOCK_NIL; -+ inftl->SpareMediaUnit = BLOCK_NIL; -+ -+ /* Search for a valid boot record */ -+ for (block = 0; block < inftl->nb_blocks; block++) { -+ int ret; -+ -+ /* -+ * Check for BNAND header first. Then whinge if it's found -+ * but later checks fail. -+ */ -+ if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize, -+ SECTORSIZE, &retlen, buf))) { -+ static int warncount = 5; -+ -+ if (warncount) { -+ printk(KERN_WARNING "INFTL: block read at 0x%x " -+ "of mtd%d failed: %d\n", -+ block * inftl->EraseSize, -+ inftl->mbd.mtd->index, ret); -+ if (!--warncount) -+ printk(KERN_WARNING "INFTL: further " -+ "failures for this block will " -+ "not be printed\n"); -+ } -+ continue; -+ } -+ -+ if (retlen < 6 || memcmp(buf, "BNAND", 6)) { -+ /* BNAND\0 not found. Continue */ -+ continue; -+ } -+ -+ /* To be safer with BIOS, also use erase mark as discriminant */ -+ if ((ret = MTD_READOOB(inftl->mbd.mtd, block * inftl->EraseSize + -+ SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) { -+ printk(KERN_WARNING "INFTL: ANAND header found at " -+ "0x%x in mtd%d, but OOB data read failed " -+ "(err %d)\n", block * inftl->EraseSize, -+ inftl->mbd.mtd->index, ret); -+ continue; -+ } -+ -+ if (boot_record_count) { -+ /* -+ * We've already processed one. So we just check if -+ * this one is the same as the first one we found. -+ */ -+ if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) { -+ printk(KERN_WARNING "INFTL: Media Headers at " -+ "0x%x and 0x%x disagree.\n", -+ inftl->MediaUnit * inftl->EraseSize, -+ block * inftl->EraseSize); -+ return -1; -+ } -+ if (boot_record_count == 1) -+ inftl->SpareMediaUnit = block; -+ -+ /* -+ * Mark this boot record (INFTL MediaHeader) block as -+ * reserved. -+ */ -+ inftl->PUtable[block] = BLOCK_RESERVED; -+ -+ boot_record_count++; -+ continue; -+ } -+ -+ /* -+ * This is the first we've seen. -+ * Copy the media header structure into place. -+ */ -+ memcpy(mh, buf, sizeof(struct INFTLMediaHeader)); -+ mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); -+ mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); -+ mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); -+ mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); -+ mh->FormatFlags = le32_to_cpu(mh->FormatFlags); -+ mh->PercentUsed = le32_to_cpu(mh->PercentUsed); -+ -+#ifdef CONFIG_MTD_DEBUG_VERBOSE -+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { -+ printk("INFTL: Media Header ->\n" -+ " bootRecordID = %s\n" -+ " NoOfBootImageBlocks = %d\n" -+ " NoOfBinaryPartitions = %d\n" -+ " NoOfBDTLPartitions = %d\n" -+ " BlockMultiplerBits = %d\n" -+ " FormatFlgs = %d\n" -+ " OsakVersion = 0x%x\n" -+ " PercentUsed = %d\n", -+ mh->bootRecordID, mh->NoOfBootImageBlocks, -+ mh->NoOfBinaryPartitions, -+ mh->NoOfBDTLPartitions, -+ mh->BlockMultiplierBits, mh->FormatFlags, -+ mh->OsakVersion, mh->PercentUsed); -+ } -+#endif -+ -+ if (mh->NoOfBDTLPartitions == 0) { -+ printk(KERN_WARNING "INFTL: Media Header sanity check " -+ "failed: NoOfBDTLPartitions (%d) == 0, " -+ "must be at least 1\n", mh->NoOfBDTLPartitions); -+ return -1; -+ } -+ -+ if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) { -+ printk(KERN_WARNING "INFTL: Media Header sanity check " -+ "failed: Total Partitions (%d) > 4, " -+ "BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions + -+ mh->NoOfBinaryPartitions, -+ mh->NoOfBDTLPartitions, -+ mh->NoOfBinaryPartitions); -+ return -1; -+ } -+ -+ if (mh->BlockMultiplierBits > 1) { -+ printk(KERN_WARNING "INFTL: sorry, we don't support " -+ "UnitSizeFactor 0x%02x\n", -+ mh->BlockMultiplierBits); -+ return -1; -+ } else if (mh->BlockMultiplierBits == 1) { -+ printk(KERN_WARNING "INFTL: support for INFTL with " -+ "UnitSizeFactor 0x%02x is experimental\n", -+ mh->BlockMultiplierBits); -+ inftl->EraseSize = inftl->mbd.mtd->erasesize << -+ (0xff - mh->BlockMultiplierBits); -+ inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; -+ } -+ -+ /* Scan the partitions */ -+ for (i = 0; (i < 4); i++) { -+ ip = &mh->Partitions[i]; -+ ip->virtualUnits = le32_to_cpu(ip->virtualUnits); -+ ip->firstUnit = le32_to_cpu(ip->firstUnit); -+ ip->lastUnit = le32_to_cpu(ip->lastUnit); -+ ip->flags = le32_to_cpu(ip->flags); -+ ip->spareUnits = le32_to_cpu(ip->spareUnits); -+ ip->Reserved0 = le32_to_cpu(ip->Reserved0); -+ -+#ifdef CONFIG_MTD_DEBUG_VERBOSE -+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { -+ printk(" PARTITION[%d] ->\n" -+ " virtualUnits = %d\n" -+ " firstUnit = %d\n" -+ " lastUnit = %d\n" -+ " flags = 0x%x\n" -+ " spareUnits = %d\n", -+ i, ip->virtualUnits, ip->firstUnit, -+ ip->lastUnit, ip->flags, -+ ip->spareUnits); -+ } -+#endif -+ -+ if (ip->Reserved0 != ip->firstUnit) { -+ struct erase_info *instr = &inftl->instr; -+ -+ /* -+ * Most likely this is using the -+ * undocumented qiuck mount feature. -+ * We don't support that, we will need -+ * to erase the hidden block for full -+ * compatibility. -+ */ -+ instr->addr = ip->Reserved0 * inftl->EraseSize; -+ instr->len = inftl->EraseSize; -+ MTD_ERASE(inftl->mbd.mtd, instr); -+ } -+ if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) { -+ printk(KERN_WARNING "INFTL: Media Header " -+ "Partition %d sanity check failed\n" -+ " firstUnit %d : lastUnit %d > " -+ "virtualUnits %d\n", i, ip->lastUnit, -+ ip->firstUnit, ip->Reserved0); -+ return -1; -+ } -+ if (ip->Reserved1 != 0) { -+ printk(KERN_WARNING "INFTL: Media Header " -+ "Partition %d sanity check failed: " -+ "Reserved1 %d != 0\n", -+ i, ip->Reserved1); -+ return -1; -+ } -+ -+ if (ip->flags & INFTL_BDTL) -+ break; -+ } -+ -+ if (i >= 4) { -+ printk(KERN_WARNING "INFTL: Media Header Partition " -+ "sanity check failed:\n No partition " -+ "marked as Disk Partition\n"); -+ return -1; -+ } -+ -+ inftl->nb_boot_blocks = ip->firstUnit; -+ inftl->numvunits = ip->virtualUnits; -+ if (inftl->numvunits > (inftl->nb_blocks - -+ inftl->nb_boot_blocks - 2)) { -+ printk(KERN_WARNING "INFTL: Media Header sanity check " -+ "failed:\n numvunits (%d) > nb_blocks " -+ "(%d) - nb_boot_blocks(%d) - 2\n", -+ inftl->numvunits, inftl->nb_blocks, -+ inftl->nb_boot_blocks); -+ return -1; -+ } -+ -+ inftl->mbd.size = inftl->numvunits * -+ (inftl->EraseSize / SECTORSIZE); -+ -+ /* -+ * Block count is set to last used EUN (we won't need to keep -+ * any meta-data past that point). -+ */ -+ inftl->firstEUN = ip->firstUnit; -+ inftl->lastEUN = ip->lastUnit; -+ inftl->nb_blocks = ip->lastUnit + 1; -+ -+ /* Memory alloc */ -+ inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL); -+ if (!inftl->PUtable) { -+ printk(KERN_WARNING "INFTL: allocation of PUtable " -+ "failed (%d bytes)\n", -+ inftl->nb_blocks * sizeof(u16)); -+ return -ENOMEM; -+ } -+ -+ inftl->VUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL); -+ if (!inftl->VUtable) { -+ kfree(inftl->PUtable); -+ printk(KERN_WARNING "INFTL: allocation of VUtable " -+ "failed (%d bytes)\n", -+ inftl->nb_blocks * sizeof(u16)); -+ return -ENOMEM; -+ } -+ -+ /* Mark the blocks before INFTL MediaHeader as reserved */ -+ for (i = 0; i < inftl->nb_boot_blocks; i++) -+ inftl->PUtable[i] = BLOCK_RESERVED; -+ /* Mark all remaining blocks as potentially containing data */ -+ for (; i < inftl->nb_blocks; i++) -+ inftl->PUtable[i] = BLOCK_NOTEXPLORED; -+ -+ /* Mark this boot record (NFTL MediaHeader) block as reserved */ -+ inftl->PUtable[block] = BLOCK_RESERVED; -+ -+#if 0 -+ /* Read Bad Erase Unit Table and modify PUtable[] accordingly */ -+ for (i = 0; i < inftl->nb_blocks; i++) { -+ if ((i & (SECTORSIZE - 1)) == 0) { -+ /* read one sector for every SECTORSIZE of blocks */ -+ if ((ret = MTD_READECC(inftl->mbd.mtd, -+ block * inftl->EraseSize + i + SECTORSIZE, -+ SECTORSIZE, &retlen, buf, -+ (char *)&oob, NULL)) < 0) { -+ printk(KERN_WARNING "INFTL: read of " -+ "bad sector table failed " -+ "(err %d)\n", ret); -+ kfree(inftl->VUtable); -+ kfree(inftl->PUtable); -+ return -1; -+ } -+ } -+ /* Mark the Bad Erase Unit as RESERVED in PUtable */ -+ if (buf[i & (SECTORSIZE - 1)] != 0xff) -+ inftl->PUtable[i] = BLOCK_RESERVED; -+ } -+#endif -+ -+ inftl->MediaUnit = block; -+ boot_record_count++; -+ } -+ -+ return boot_record_count ? 0 : -1; -+} -+ -+static int memcmpb(void *a, int c, int n) -+{ -+ int i; -+ for (i = 0; i < n; i++) { -+ if (c != ((unsigned char *)a)[i]) -+ return 1; -+ } -+ return 0; -+} -+ -+/* -+ * check_free_sector: check if a free sector is actually FREE, -+ * i.e. All 0xff in data and oob area. -+ */ -+static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, -+ int len, int check_oob) -+{ -+ int i, retlen; -+ u8 buf[SECTORSIZE]; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x," -+ "address=0x%x,len=%d,check_oob=%d)\n", (int)inftl, -+ address, len, check_oob); -+ -+ for (i = 0; i < len; i += SECTORSIZE) { -+ /* -+ * We want to read the sector without ECC check here since a -+ * free sector does not have ECC syndrome on it yet. -+ */ -+ if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0) -+ return -1; -+ if (memcmpb(buf, 0xff, SECTORSIZE) != 0) -+ return -1; -+ -+ if (check_oob) { -+ if (MTD_READOOB(inftl->mbd.mtd, address, -+ inftl->mbd.mtd->oobsize, &retlen, buf) < 0) -+ return -1; -+ if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0) -+ return -1; -+ } -+ address += SECTORSIZE; -+ } -+ -+ return 0; -+} -+ -+/* -+ * INFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase -+ * Unit and Update INFTL metadata. Each erase operation is -+ * checked with check_free_sectors. -+ * -+ * Return: 0 when succeed, -1 on error. -+ * -+ * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? -+ * 2. UnitSizeFactor != 0xFF -+ */ -+int INFTL_formatblock(struct INFTLrecord *inftl, int block) -+{ -+ int retlen; -+ struct inftl_unittail uci; -+ struct erase_info *instr = &inftl->instr; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x," -+ "block=%d)\n", (int)inftl, block); -+ -+ memset(instr, 0, sizeof(struct erase_info)); -+ -+ /* FIXME: Shouldn't we be setting the 'discarded' flag to zero -+ _first_? */ -+ -+ /* Use async erase interface, test return code */ -+ instr->addr = block * inftl->EraseSize; -+ instr->len = inftl->EraseSize; -+ MTD_ERASE(inftl->mbd.mtd, instr); -+ -+ if (instr->state == MTD_ERASE_FAILED) { -+ /* -+ * Could not format, FixMe: We should update the BadUnitTable -+ * both in memory and on disk. -+ */ -+ printk(KERN_WARNING "INFTL: error while formatting block %d\n", -+ block); -+ return -1; -+ } -+ -+ /* -+ * Check the "freeness" of Erase Unit before updating metadata. -+ * FixMe: is this check really necessary? Since we have check the -+ * return code after the erase operation. -+ */ -+ if (check_free_sectors(inftl, instr->addr, inftl->EraseSize, 1) != 0) -+ return -1; -+ -+ uci.EraseMark = cpu_to_le16(ERASE_MARK); -+ uci.EraseMark1 = cpu_to_le16(ERASE_MARK); -+ uci.Reserved[0] = 0; -+ uci.Reserved[1] = 0; -+ uci.Reserved[2] = 0; -+ uci.Reserved[3] = 0; -+ if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 + -+ 8, 8, &retlen, (char *)&uci) < 0) -+ return -1; -+ return 0; -+} -+ -+/* -+ * format_chain: Format an invalid Virtual Unit chain. It frees all the Erase -+ * Units in a Virtual Unit Chain, i.e. all the units are disconnected. -+ * -+ * Since the chain is invalid then we will have to erase it from its -+ * head (normally for INFTL we go from the oldest). But if it has a -+ * loop then there is no oldest... -+ */ -+static void format_chain(struct INFTLrecord *inftl, unsigned int first_block) -+{ -+ unsigned int block = first_block, block1; -+ -+ printk(KERN_WARNING "INFTL: formatting chain at block %d\n", -+ first_block); -+ -+ for (;;) { -+ block1 = inftl->PUtable[block]; -+ -+ printk(KERN_WARNING "INFTL: formatting block %d\n", block); -+ if (INFTL_formatblock(inftl, block) < 0) { -+ /* -+ * Cannot format !!!! Mark it as Bad Unit, -+ * FixMe: update the BadUnitTable on disk. -+ */ -+ inftl->PUtable[block] = BLOCK_RESERVED; -+ } else { -+ inftl->PUtable[block] = BLOCK_FREE; -+ } -+ -+ /* Goto next block on the chain */ -+ block = block1; -+ -+ if (block == BLOCK_NIL || block >= inftl->lastEUN) -+ break; -+ } -+} -+ -+void INFTL_dumptables(struct INFTLrecord *s) -+{ -+ int i; -+ -+ printk("-------------------------------------------" -+ "----------------------------------\n"); -+ -+ printk("VUtable[%d] ->", s->nb_blocks); -+ for (i = 0; i < s->nb_blocks; i++) { -+ if ((i % 8) == 0) -+ printk("\n%04x: ", i); -+ printk("%04x ", s->VUtable[i]); -+ } -+ -+ printk("\n-------------------------------------------" -+ "----------------------------------\n"); -+ -+ printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); -+ for (i = 0; i <= s->lastEUN; i++) { -+ if ((i % 8) == 0) -+ printk("\n%04x: ", i); -+ printk("%04x ", s->PUtable[i]); -+ } -+ -+ printk("\n-------------------------------------------" -+ "----------------------------------\n"); -+ -+ printk("INFTL ->\n" -+ " EraseSize = %d\n" -+ " h/s/c = %d/%d/%d\n" -+ " numvunits = %d\n" -+ " firstEUN = %d\n" -+ " lastEUN = %d\n" -+ " numfreeEUNs = %d\n" -+ " LastFreeEUN = %d\n" -+ " nb_blocks = %d\n" -+ " nb_boot_blocks = %d", -+ s->EraseSize, s->heads, s->sectors, s->cylinders, -+ s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs, -+ s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks); -+ -+ printk("\n-------------------------------------------" -+ "----------------------------------\n"); -+} -+ -+void INFTL_dumpVUchains(struct INFTLrecord *s) -+{ -+ int logical, block, i; -+ -+ printk("-------------------------------------------" -+ "----------------------------------\n"); -+ -+ printk("INFTL Virtual Unit Chains:\n"); -+ for (logical = 0; logical < s->nb_blocks; logical++) { -+ block = s->VUtable[logical]; -+ if (block > s->nb_blocks) -+ continue; -+ printk(" LOGICAL %d --> %d ", logical, block); -+ for (i = 0; i < s->nb_blocks; i++) { -+ if (s->PUtable[block] == BLOCK_NIL) -+ break; -+ block = s->PUtable[block]; -+ printk("%d ", block); -+ } -+ printk("\n"); -+ } -+ -+ printk("-------------------------------------------" -+ "----------------------------------\n"); -+} -+ -+int INFTL_mount(struct INFTLrecord *s) -+{ -+ unsigned int block, first_block, prev_block, last_block; -+ unsigned int first_logical_block, logical_block, erase_mark; -+ int chain_length, do_format_chain; -+ struct inftl_unithead1 h0; -+ struct inftl_unittail h1; -+ int i, retlen; -+ u8 *ANACtable, ANAC; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=0x%x)\n", (int)s); -+ -+ /* Search for INFTL MediaHeader and Spare INFTL Media Header */ -+ if (find_boot_record(s) < 0) { -+ printk(KERN_WARNING "INFTL: could not find valid boot record?\n"); -+ return -1; -+ } -+ -+ /* Init the logical to physical table */ -+ for (i = 0; i < s->nb_blocks; i++) -+ s->VUtable[i] = BLOCK_NIL; -+ -+ logical_block = block = BLOCK_NIL; -+ -+ /* Temporary buffer to store ANAC numbers. */ -+ ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL); -+ memset(ANACtable, 0, s->nb_blocks); -+ -+ /* -+ * First pass is to explore each physical unit, and construct the -+ * virtual chains that exist (newest physical unit goes into VUtable). -+ * Any block that is in any way invalid will be left in the -+ * NOTEXPLORED state. Then at the end we will try to format it and -+ * mark it as free. -+ */ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n"); -+ for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) { -+ if (s->PUtable[first_block] != BLOCK_NOTEXPLORED) -+ continue; -+ -+ do_format_chain = 0; -+ first_logical_block = BLOCK_NIL; -+ last_block = BLOCK_NIL; -+ block = first_block; -+ -+ for (chain_length = 0; ; chain_length++) { -+ -+ if ((chain_length == 0) && -+ (s->PUtable[block] != BLOCK_NOTEXPLORED)) { -+ /* Nothing to do here, onto next block */ -+ break; -+ } -+ -+ if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, -+ 8, &retlen, (char *)&h0) < 0 || -+ MTD_READOOB(s->mbd.mtd, block * s->EraseSize + -+ 2 * SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) { -+ /* Should never happen? */ -+ do_format_chain++; -+ break; -+ } -+ -+ logical_block = le16_to_cpu(h0.virtualUnitNo); -+ prev_block = le16_to_cpu(h0.prevUnitNo); -+ erase_mark = le16_to_cpu((h1.EraseMark | h1.EraseMark1)); -+ ANACtable[block] = h0.ANAC; -+ -+ /* Previous block is relative to start of Partition */ -+ if (prev_block < s->nb_blocks) -+ prev_block += s->firstEUN; -+ -+ /* Already explored partial chain? */ -+ if (s->PUtable[block] != BLOCK_NOTEXPLORED) { -+ /* Check if chain for this logical */ -+ if (logical_block == first_logical_block) { -+ if (last_block != BLOCK_NIL) -+ s->PUtable[last_block] = block; -+ } -+ break; -+ } -+ -+ /* Check for invalid block */ -+ if (erase_mark != ERASE_MARK) { -+ printk(KERN_WARNING "INFTL: corrupt block %d " -+ "in chain %d, chain length %d, erase " -+ "mark 0x%x?\n", block, first_block, -+ chain_length, erase_mark); -+ /* -+ * Assume end of chain, probably incomplete -+ * fold/erase... -+ */ -+ if (chain_length == 0) -+ do_format_chain++; -+ break; -+ } -+ -+ /* Check for it being free already then... */ -+ if ((logical_block == BLOCK_FREE) || -+ (logical_block == BLOCK_NIL)) { -+ s->PUtable[block] = BLOCK_FREE; -+ break; -+ } -+ -+ /* Sanity checks on block numbers */ -+ if ((logical_block >= s->nb_blocks) || -+ ((prev_block >= s->nb_blocks) && -+ (prev_block != BLOCK_NIL))) { -+ if (chain_length > 0) { -+ printk(KERN_WARNING "INFTL: corrupt " -+ "block %d in chain %d?\n", -+ block, first_block); -+ do_format_chain++; -+ } -+ break; -+ } -+ -+ if (first_logical_block == BLOCK_NIL) { -+ first_logical_block = logical_block; -+ } else { -+ if (first_logical_block != logical_block) { -+ /* Normal for folded chain... */ -+ break; -+ } -+ } -+ -+ /* -+ * Current block is valid, so if we followed a virtual -+ * chain to get here then we can set the previous -+ * block pointer in our PUtable now. Then move onto -+ * the previous block in the chain. -+ */ -+ s->PUtable[block] = BLOCK_NIL; -+ if (last_block != BLOCK_NIL) -+ s->PUtable[last_block] = block; -+ last_block = block; -+ block = prev_block; -+ -+ /* Check for end of chain */ -+ if (block == BLOCK_NIL) -+ break; -+ -+ /* Validate next block before following it... */ -+ if (block > s->lastEUN) { -+ printk(KERN_WARNING "INFTL: invalid previous " -+ "block %d in chain %d?\n", block, -+ first_block); -+ do_format_chain++; -+ break; -+ } -+ } -+ -+ if (do_format_chain) { -+ format_chain(s, first_block); -+ continue; -+ } -+ -+ /* -+ * Looks like a valid chain then. It may not really be the -+ * newest block in the chain, but it is the newest we have -+ * found so far. We might update it in later iterations of -+ * this loop if we find something newer. -+ */ -+ s->VUtable[first_logical_block] = first_block; -+ logical_block = BLOCK_NIL; -+ } -+ -+#ifdef CONFIG_MTD_DEBUG_VERBOSE -+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2) -+ INFTL_dumptables(s); -+#endif -+ -+ /* -+ * Second pass, check for infinite loops in chains. These are -+ * possible because we don't update the previous pointers when -+ * we fold chains. No big deal, just fix them up in PUtable. -+ */ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n"); -+ for (logical_block = 0; logical_block < s->numvunits; logical_block++) { -+ block = s->VUtable[logical_block]; -+ last_block = BLOCK_NIL; -+ -+ /* Check for free/reserved/nil */ -+ if (block >= BLOCK_RESERVED) -+ continue; -+ -+ ANAC = ANACtable[block]; -+ for (i = 0; i < s->numvunits; i++) { -+ if (s->PUtable[block] == BLOCK_NIL) -+ break; -+ if (s->PUtable[block] > s->lastEUN) { -+ printk(KERN_WARNING "INFTL: invalid prev %d, " -+ "in virtual chain %d\n", -+ s->PUtable[block], logical_block); -+ s->PUtable[block] = BLOCK_NIL; -+ -+ } -+ if (ANACtable[block] != ANAC) { -+ /* -+ * Chain must point back to itself. This is ok, -+ * but we will need adjust the tables with this -+ * newest block and oldest block. -+ */ -+ s->VUtable[logical_block] = block; -+ s->PUtable[last_block] = BLOCK_NIL; -+ break; -+ } -+ -+ ANAC--; -+ last_block = block; -+ block = s->PUtable[block]; -+ } -+ -+ if (i >= s->nb_blocks) { -+ /* -+ * Uhoo, infinite chain with valid ANACS! -+ * Format whole chain... -+ */ -+ format_chain(s, first_block); -+ } -+ } -+ -+#ifdef CONFIG_MTD_DEBUG_VERBOSE -+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2) -+ INFTL_dumptables(s); -+ if (CONFIG_MTD_DEBUG_VERBOSE >= 2) -+ INFTL_dumpVUchains(s); -+#endif -+ -+ /* -+ * Third pass, format unreferenced blocks and init free block count. -+ */ -+ s->numfreeEUNs = 0; -+ s->LastFreeEUN = BLOCK_NIL; -+ -+ DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n"); -+ for (block = s->firstEUN; block <= s->lastEUN; block++) { -+ if (s->PUtable[block] == BLOCK_NOTEXPLORED) { -+ printk("INFTL: unreferenced block %d, formatting it\n", -+ block); -+ if (INFTL_formatblock(s, block) < 0) -+ s->PUtable[block] = BLOCK_RESERVED; -+ else -+ s->PUtable[block] = BLOCK_FREE; -+ } -+ if (s->PUtable[block] == BLOCK_FREE) { -+ s->numfreeEUNs++; -+ if (s->LastFreeEUN == BLOCK_NIL) -+ s->LastFreeEUN = block; -+ } -+ } -+ -+ kfree(ANACtable); -+ return 0; -+} -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/Config.in linux/drivers/mtd/maps/Config.in ---- linux-mips-2.4.27/drivers/mtd/maps/Config.in 2004-02-26 01:46:35.000000000 +0100 -+++ linux/drivers/mtd/maps/Config.in 2004-11-19 10:25:11.888201464 +0100 -@@ -1,17 +1,14 @@ - # drivers/mtd/maps/Config.in - --# $Id$ -+# $Id$ - - mainmenu_option next_comment - - comment 'Mapping drivers for chip access' - --dep_tristate ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE --if [ "$CONFIG_MTD_PHYSMAP" = "y" -o "$CONFIG_MTD_PHYSMAP" = "m" ]; then -- hex ' Physical start address of flash mapping' CONFIG_MTD_PHYSMAP_START 0x8000000 -- hex ' Physical length of flash mapping' CONFIG_MTD_PHYSMAP_LEN 0x4000000 -- int ' Bus width in octets' CONFIG_MTD_PHYSMAP_BUSWIDTH 2 --fi -+bool ' Support for non-linear mappings of flash chips' CONFIG_MTD_COMPLEX_MAPPINGS -+ -+bool ' CFI Flash device in physical memory map' CONFIG_MTD_PHYSMAP $CONFIG_MTD_GEN_PROBE - - if [ "$CONFIG_SPARC" = "y" -o "$CONFIG_SPARC64" = "y" ]; then - dep_tristate ' Sun Microsystems userflash support' CONFIG_MTD_SUN_UFLASH $CONFIG_MTD_CFI -@@ -21,56 +18,68 @@ - dep_tristate ' CFI Flash device mapped on Photron PNC-2000' CONFIG_MTD_PNC2000 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS - dep_tristate ' CFI Flash device mapped on AMD SC520 CDP' CONFIG_MTD_SC520CDP $CONFIG_MTD_CFI - dep_tristate ' CFI Flash device mapped on AMD NetSc520' CONFIG_MTD_NETSC520 $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS -- dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS -- dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS -+ dep_tristate ' CFI Flash device mapped on Arcom SBC-GXx boards' CONFIG_MTD_SBC_GXX $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_COMPLEX_MAPPINGS -+ dep_tristate ' CFI Flash device mapped on Arcom ELAN-104NC' CONFIG_MTD_ELAN_104NC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_COMPLEX_MAPPINGS - dep_tristate ' CFI Flash device mapped on DIL/Net PC' CONFIG_MTD_DILNETPC $CONFIG_MTD_CFI_INTELEXT $CONFIG_MTD_PARTITIONS $CONFIG_MTD_CONCAT - if [ "$CONFIG_MTD_DILNETPC" = "y" -o "$CONFIG_MTD_DILNETPC" = "m" ]; then - hex ' Size of boot partition' CONFIG_MTD_DILNETPC_BOOTSIZE 0x80000 - fi -- dep_tristate ' JEDEC Flash device mapped on Mixcom piggyback card' CONFIG_MTD_MIXMEM $CONFIG_MTD_JEDEC -- dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC -- dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC -+ dep_tristate ' JEDEC Flash device mapped on Octagon 5066 SBC' CONFIG_MTD_OCTAGON $CONFIG_MTD_JEDEC $CONFIG_MTD_COMPLEX_MAPPINGS -+ dep_tristate ' JEDEC Flash device mapped on Tempustech VMAX SBC301' CONFIG_MTD_VMAX $CONFIG_MTD_JEDEC $CONFIG_MTD_COMPLEX_MAPPINGS - dep_tristate ' Flash device mapped with DOCCS on NatSemi SCx200' CONFIG_MTD_SCx200_DOCFLASH $CONFIG_MTD_CFI - dep_tristate ' BIOS flash chip on Intel L440GX boards' CONFIG_MTD_L440GX $CONFIG_MTD_JEDECPROBE - dep_tristate ' ROM connected to AMD76X southbridge' CONFIG_MTD_AMD76XROM $CONFIG_MTD_GEN_PROBE -- dep_tristate ' ROM connected to Intel Hub Controller 2' CONFIG_MTD_ICH2ROM $CONFIG_MTD_JEDECPROBE -+ dep_tristate ' ROM connected to Intel Hub Controller 2/3/4/5' CONFIG_MTD_ICHXROM $CONFIG_MTD_JEDECPROBE $CONFIG_MTD_COMPLEX_MAPPINGS - dep_tristate ' CFI Flash device mapped on SnapGear/SecureEdge' CONFIG_MTD_NETtel $CONFIG_MTD_PARTITIONS - dep_tristate ' BIOS flash chip on Intel SCB2 boards' CONFIG_MTD_SCB2_FLASH $CONFIG_MTD_GEN_PROBE - fi - --if [ "$CONFIG_PPC" = "y" ]; then -- dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI $CONFIG_TQM8xxL -+if [ "$CONFIG_PPC32" = "y" ]; then -+ if [ "$CONFIG_6xx" = "y" -a "$CONFIG_8260" = "y" ]; then -+ dep_tristate ' Flash device on SBC8240' CONFIG_MTD_SBC8240 $CONFIG_MTD_JEDECPROBE -+ fi -+ if [ "$CONFIG_8xx" = "y" ]; then -+ if [ "$CONFIG_TQM8xxL" = "y" ]; then -+ dep_tristate ' CFI Flash device mapped on TQM8XXL' CONFIG_MTD_TQM8XXL $CONFIG_MTD_CFI -+ fi -+ if [ "$CONFIG_RPXLITE" = "y" -o "$CONFIG_RPXCLASSIC" = "y" ]; then - dep_tristate ' CFI Flash device mapped on RPX Lite or CLLF' CONFIG_MTD_RPXLITE $CONFIG_MTD_CFI -+ fi -+ if [ "$CONFIG_MBX" = "y" ]; then - dep_tristate ' System flash on MBX860 board' CONFIG_MTD_MBX860 $CONFIG_MTD_CFI -+ fi -+ if [ "$CONFIG_DBOX2" = "y" ]; then - dep_tristate ' CFI Flash device mapped on D-Box2' CONFIG_MTD_DBOX2 $CONFIG_MTD_CFI -+ fi - dep_tristate ' CFI Flash device mapping on FlagaDM' CONFIG_MTD_CFI_FLAGADM $CONFIG_MTD_CFI -- dep_tristate ' CFI Flash device mapped on IBM Redwood-4/5' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI -+ fi -+ if [ "$CONFIG_4xx" = "y" ]; then -+ if [ "$CONFIG_40x" = "y" ]; then -+ if [ "$CONFIG_REDWOOD_4" = "y" -o "$CONFIG_REDWOOD_5" = "y" -o "$CONFIG_REDWOOD_6" = "y" ]; then -+ dep_tristate ' CFI Flash device mapped on IBM Redwood' CONFIG_MTD_REDWOOD $CONFIG_MTD_CFI -+ fi -+ dep_tristate ' CFI Flash device mapped on IBM Beech' CONFIG_MTD_BEECH $CONFIG_MTD_CFI $CONFIG_BEECH -+ dep_tristate ' CFI Flash device mapped on IBM Arctic' CONFIG_MTD_ARCTIC $CONFIG_MTD_CFI $CONFIG_ARCTIC2 -+ fi -+ if [ "$CONFIG_440" = "y" ]; then -+ dep_tristate ' Flash devices mapped on IBM Ebony' CONFIG_MTD_EBONY $CONFIG_MTD_CFI $CONFIG_EBONY -+ fi -+ fi - fi - --if [ "$CONFIG_MIPS" = "y" ]; then -- dep_tristate ' Pb1000 MTD support' CONFIG_MTD_PB1000 $CONFIG_MIPS_PB1000 -- dep_tristate ' Pb1500 MTD support' CONFIG_MTD_PB1500 $CONFIG_MIPS_PB1500 -- dep_tristate ' Pb1100 MTD support' CONFIG_MTD_PB1100 $CONFIG_MIPS_PB1100 -- dep_tristate ' Bosporus MTD support' CONFIG_MTD_BOSPORUS $CONFIG_MIPS_BOSPORUS -- dep_tristate ' XXS1500 boot flash device' CONFIG_MTD_XXS1500 $CONFIG_MIPS_XXS1500 -- dep_tristate ' MTX-1 flash device' CONFIG_MTD_MTX1 $CONFIG_MIPS_MTX1 -- if [ "$CONFIG_MTD_PB1500" = "y" -o "$CONFIG_MTD_PB1500" = "m" \ -- -o "$CONFIG_MTD_PB1100" = "y" -o "$CONFIG_MTD_PB1100" = "m" ]; then -- bool ' Pb[15]00 boot flash device' CONFIG_MTD_PB1500_BOOT -- bool ' Pb[15]00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER -+if [ "$CONFIG_MIPS" = "y" -o "$CONFIG_MIPS64" = "y" ]; then -+ if [ "$CONFIG_MIPS_PB1000" = "y" -o "$CONFIG_MIPS_PB1100" = "y" -o "$CONFIG_MIPS_PB1500" = "y" ]; then -+ tristate ' Pb1x00 MTD support' CONFIG_MTD_PB1XXX -+ if [ "$CONFIG_MIPS_PB1500" = "y" -o "$CONFIG_MIPS_PB1100" = "m" ]; then -+ bool ' Pb1x00 boot flash device' CONFIG_MTD_PB1500_BOOT -+ bool ' Pb1x00 user flash device (2nd 32MiB bank)' CONFIG_MTD_PB1500_USER -+ fi - fi - tristate ' Db1x00 MTD support' CONFIG_MTD_DB1X00 - if [ "$CONFIG_MTD_DB1X00" = "y" -o "$CONFIG_MTD_DB1X00" = "m" ]; then - bool ' Db1x00 boot flash device' CONFIG_MTD_DB1X00_BOOT - bool ' Db1x00 user flash device (2nd bank)' CONFIG_MTD_DB1X00_USER - fi -- tristate ' Pb1550 MTD support' CONFIG_MTD_PB1550 -- if [ "$CONFIG_MTD_PB1550" = "y" -o "$CONFIG_MTD_PB1550" = "m" ]; then -- bool ' Pb1550 Boot Flash' CONFIG_MTD_PB1550_BOOT -- bool ' Pb1550 User Parameter Flash' CONFIG_MTD_PB1550_USER -- fi -- dep_tristate ' Hydrogen 3 MTD support' CONFIG_MTD_HYDROGEN3 $CONFIG_MIPS_HYDROGEN3 -- dep_tristate ' Mirage MTD support' CONFIG_MTD_MIRAGE $CONFIG_MIPS_MIRAGE - dep_tristate ' Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board' CONFIG_MTD_CSTM_MIPS_IXX $CONFIG_MTD_CFI $CONFIG_MTD_JEDEC $CONFIG_MTD_PARTITIONS - if [ "$CONFIG_MTD_CSTM_MIPS_IXX" = "y" -o "$CONFIG_MTD_CSTM_MIPS_IXX" = "m" ]; then - hex ' Physical start address of flash mapping' CONFIG_MTD_CSTM_MIPS_IXX_START 0x8000000 -@@ -78,7 +87,7 @@ - int ' Bus width in octets' CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH 2 - fi - dep_tristate ' Momenco Ocelot boot flash device' CONFIG_MTD_OCELOT $CONFIG_MOMENCO_OCELOT -- dep_tristate ' LASAT flash device' CONFIG_MTD_LASAT $CONFIG_MTD_CFI $CONFIG_LASAT -+ dep_tristate ' LASAT flash device' CONFIG_MTD_LASAT $CONFIG_LASAT - fi - - if [ "$CONFIG_SUPERH" = "y" ]; then -@@ -90,21 +99,24 @@ - fi - - if [ "$CONFIG_ARM" = "y" ]; then -- dep_tristate ' CFI Flash device mapped on Nora' CONFIG_MTD_NORA $CONFIG_MTD_CFI - dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI - dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712 - dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS -- dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE -+ dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_COMPLEX_MAPPINGS - dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310 -+ dep_tristate ' CFI Flash device mapped on the XScale Lubbock board' CONFIG_MTD_LUBBOCK $CONFIG_MTD_CFI $CONFIG_ARCH_LUBBOCK -+ dep_tristate ' CFI Flash device mapped on XScale IXP425 systems' CONFIG_MTD_IXP425 $CONFIG_MTD_CFI $CONFIG_MTD_COMPLEX_MAPPINGS - dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT - dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET - dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12 - dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI -+ dep_tristate ' CFI Flash device mapped on Hynix evaluation boards' CONFIG_MTD_H720X $CONFIG_MTD_CFI - dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE - dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA -+ dep_tristate ' NOR Flash device on TOTO board' CONFIG_MTD_NOR_TOTO $CONFIG_MTD $CONFIG_OMAP_TOTO - fi - if [ "$CONFIG_ALPHA" = "y" ]; then -- dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE -+ dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE $CONFIG_MTD_COMPLEX_MAPPINGS - fi - - if [ "$CONFIG_UCLINUX" = "y" ]; then -@@ -112,7 +124,7 @@ - fi - - # This needs CFI or JEDEC, depending on the cards found. --dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI --dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA -+dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI $CONFIG_MTD_COMPLEX_MAPPINGS -+dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA $CONFIG_MTD_COMPLEX_MAPPINGS - - endmenu -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/Makefile linux/drivers/mtd/maps/Makefile ---- linux-mips-2.4.27/drivers/mtd/maps/Makefile 2004-02-26 01:46:35.000000000 +0100 -+++ linux/drivers/mtd/maps/Makefile 2004-11-19 10:25:11.890201160 +0100 -@@ -1,12 +1,16 @@ - # - # linux/drivers/maps/Makefile - # --# $Id$ -+# $Id$ - --BELOW25 := $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/) -- --ifeq ($(BELOW25),y) -+ifeq ($(PATCHLEVEL),4) - O_TARGET := mapslink.o -+export-objs := map_funcs.o -+endif -+ -+ -+ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) -+obj-$(CONFIG_MTD) += map_funcs.o - endif - - # Chip mappings -@@ -21,19 +25,13 @@ - obj-$(CONFIG_MTD_IQ80310) += iq80310.o - obj-$(CONFIG_MTD_L440GX) += l440gx.o - obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o --obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o -+obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o - obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o -+obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o - obj-$(CONFIG_MTD_MBX860) += mbx860.o --obj-$(CONFIG_MTD_NORA) += nora.o - obj-$(CONFIG_MTD_CEIVA) += ceiva.o - obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o --ifneq ($(CONFIG_MTD_PHYSMAP),n) -- ifeq ($(CONFIG_MTD_PHYSMAP_BUSWIDTH),8) -- obj-$(CONFIG_MTD_PHYSMAP) += physmap64.o -- else -- obj-$(CONFIG_MTD_PHYSMAP) += physmap.o -- endif --endif -+obj-$(CONFIG_MTD_PHYSMAP) += physmap.o - obj-$(CONFIG_MTD_PNC2000) += pnc2000.o - obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o - obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o -@@ -49,16 +47,9 @@ - obj-$(CONFIG_MTD_OCELOT) += ocelot.o - obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o - obj-$(CONFIG_MTD_PCI) += pci.o --obj-$(CONFIG_MTD_PB1000) += pb1xxx-flash.o --obj-$(CONFIG_MTD_PB1100) += pb1xxx-flash.o --obj-$(CONFIG_MTD_PB1500) += pb1xxx-flash.o --obj-$(CONFIG_MTD_XXS1500) += xxs1500.o --obj-$(CONFIG_MTD_MTX1) += mtx-1.o --obj-$(CONFIG_MTD_LASAT) += lasat.o -+obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o - obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o --obj-$(CONFIG_MTD_PB1550) += pb1550-flash.o --obj-$(CONFIG_MTD_HYDROGEN3) += hydrogen3-flash.o --obj-$(CONFIG_MTD_BOSPORUS) += pb1xxx-flash.o -+obj-$(CONFIG_MTD_LASAT) += lasat.o - obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o - obj-$(CONFIG_MTD_EDB7312) += edb7312.o - obj-$(CONFIG_MTD_IMPA7) += impa7.o -@@ -67,6 +58,13 @@ - obj-$(CONFIG_MTD_UCLINUX) += uclinux.o - obj-$(CONFIG_MTD_NETtel) += nettel.o - obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o --obj-$(CONFIG_MTD_MIRAGE) += mirage-flash.o -+obj-$(CONFIG_MTD_EBONY) += ebony.o -+obj-$(CONFIG_MTD_BEECH) += beech-mtd.o -+obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o -+obj-$(CONFIG_MTD_H720X) += h720x-flash.o -+obj-$(CONFIG_MTD_SBC8240) += sbc8240.o -+obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o -+obj-$(CONFIG_MTD_MPC1211) += mpc1211.o -+obj-$(CONFIG_MTD_IXP425) += ixp425.o - --include $(TOPDIR)/Rules.make -+-include $(TOPDIR)/Rules.make -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/amd76xrom.c linux/drivers/mtd/maps/amd76xrom.c ---- linux-mips-2.4.27/drivers/mtd/maps/amd76xrom.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/amd76xrom.c 2004-11-19 10:25:11.891201008 +0100 -@@ -2,12 +2,13 @@ - * amd76xrom.c - * - * Normal mappings of chips in physical memory -- * $Id$ -+ * $Id$ - */ - - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -16,77 +17,59 @@ - #include <linux/pci_ids.h> - - -+#define xstr(s) str(s) -+#define str(s) #s -+#define MOD_NAME xstr(KBUILD_BASENAME) -+ -+#define MTD_DEV_NAME_LENGTH 16 -+ - struct amd76xrom_map_info { - struct map_info map; - struct mtd_info *mtd; - unsigned long window_addr; - u32 window_start, window_size; - struct pci_dev *pdev; -+ struct resource window_rsrc; -+ struct resource rom_rsrc; -+ char mtd_name[MTD_DEV_NAME_LENGTH]; - }; - --static __u8 amd76xrom_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --static __u16 amd76xrom_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} - --static __u32 amd76xrom_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -+static struct amd76xrom_map_info amd76xrom_map = { -+ .map = { -+ .name = MOD_NAME, -+ .size = 0, -+ .buswidth = 1, -+ } -+ /* remaining fields of structure are initialized to 0 */ -+}; - --static void amd76xrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} - --static void amd76xrom_write8(struct map_info *map, __u8 d, unsigned long adr) -+static void amd76xrom_cleanup(struct amd76xrom_map_info *info) - { -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -+ u8 byte; - --static void amd76xrom_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -+ /* Disable writes through the rom window */ -+ pci_read_config_byte(info->pdev, 0x40, &byte); -+ pci_write_config_byte(info->pdev, 0x40, byte & ~1); - --static void amd76xrom_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -+ if (info->mtd) { -+ del_mtd_device(info->mtd); -+ map_destroy(info->mtd); -+ info->mtd = NULL; -+ info->map.virt = 0; -+ } -+ if (info->rom_rsrc.parent) -+ release_resource(&info->rom_rsrc); -+ if (info->window_rsrc.parent) -+ release_resource(&info->window_rsrc); - --static void amd76xrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); -+ if (info->window_addr) { -+ iounmap((void *)(info->window_addr)); -+ info->window_addr = 0; -+ } - } - --static struct amd76xrom_map_info amd76xrom_map = { -- map: { -- name: "AMD76X rom", -- size: 0, -- buswidth: 1, -- read8: amd76xrom_read8, -- read16: amd76xrom_read16, -- read32: amd76xrom_read32, -- copy_from: amd76xrom_copy_from, -- write8: amd76xrom_write8, -- write16: amd76xrom_write16, -- write32: amd76xrom_write32, -- copy_to: amd76xrom_copy_to, -- /* The standard rom socket is for single power supply chips -- * that don't have an extra vpp. -- */ -- }, -- mtd: 0, -- window_addr: 0, --}; - - static int __devinit amd76xrom_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -@@ -97,6 +80,10 @@ - u8 segen_bits; - }; - static struct rom_window rom_window[] = { -+ /* -+ * Need the 5MiB window for chips that have block lock/unlock -+ * registers located below 4MiB window. -+ */ - { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), }, - { 0xffc00000, 4*1024*1024, (1<<7), }, - { 0xffff0000, 64*1024, 0 }, -@@ -112,19 +99,29 @@ - int i; - u32 rom_size; - -+ info->pdev = pdev; - window = &rom_window[0]; --#if 0 -- while(window->size) { -- if (request_mem_region(window->start, window->size, "amd76xrom")) { -- break; -- } -- window++; -- } -- if (!window->size) { -- printk(KERN_ERR "amd76xrom: cannot reserve rom window\n"); -- goto err_out_none; -+ -+ while (window->size) { -+ /* -+ * Try to reserve the window mem region. If this fails then -+ * it is likely due to a fragment of the window being -+ * "reseved" by the BIOS. In the case that the -+ * request_mem_region() fails then once the rom size is -+ * discovered we will try to reserve the unreserved fragment. -+ */ -+ info->window_rsrc.name = MOD_NAME; -+ info->window_rsrc.start = window->start; -+ info->window_rsrc.end = window->start + window->size - 1; -+ info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; -+ if (request_resource(&iomem_resource, &info->window_rsrc)) { -+ info->window_rsrc.parent = NULL; -+ printk(KERN_ERR MOD_NAME -+ " %s(): Unable to register resource" -+ " 0x%.08lx-0x%.08lx - kernel bug?\n", -+ __func__, -+ info->window_rsrc.start, info->window_rsrc.end); - } --#endif - - /* Enable the selected rom window */ - pci_read_config_byte(pdev, 0x43, &byte); -@@ -136,49 +133,94 @@ - - /* FIXME handle registers 0x80 - 0x8C the bios region locks */ - -- printk(KERN_NOTICE "amd76xrom window : %x at %x\n", -+ printk(KERN_NOTICE MOD_NAME " window : %x at %x\n", - window->size, window->start); - /* For write accesses caches are useless */ -- info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size); -+ info->window_addr = -+ (unsigned long)ioremap_nocache(window->start, -+ window->size); - - if (!info->window_addr) { - printk(KERN_ERR "Failed to ioremap\n"); -- goto err_out_free_mmio_region; -+ continue; - } -- info->mtd = 0; -+ -+ info->mtd = NULL; -+ - for(i = 0; (rom_size = rom_probe_sizes[i]); i++) { - char **chip_type; - if (rom_size > window->size) { - continue; - } -- info->map.map_priv_1 = -+ info->map.phys = window->start + window->size - rom_size; -+ info->map.virt = - info->window_addr + window->size - rom_size; - info->map.size = rom_size; -+ simple_map_init(&info->map); - chip_type = rom_probe_types; - for(; !info->mtd && *chip_type; chip_type++) { - info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map); - } -- if (info->mtd) { -- break; -- } -+ if (info->mtd) goto found_mtd; - } -- if (!info->mtd) { -- goto err_out_iounmap; -+ iounmap((void *)(info->window_addr)); -+ info->window_addr = 0; -+ -+ /* Disable writes through the rom window */ -+ pci_read_config_byte(pdev, 0x40, &byte); -+ pci_write_config_byte(pdev, 0x40, byte & ~1); -+ -+ window++; - } -- printk(KERN_NOTICE "amd76xrom chip at offset: %x\n", -+ goto failed; -+ -+ found_mtd: -+ printk(KERN_NOTICE MOD_NAME " chip at offset: 0x%x\n", - window->size - rom_size); - -- info->mtd->module = THIS_MODULE; -+ info->mtd->owner = THIS_MODULE; -+ -+ if (!info->window_rsrc.parent) { -+ /* failed to reserve entire window - try fragments */ -+ info->window_rsrc.name = MOD_NAME; -+ info->window_rsrc.start = window->start; -+ info->window_rsrc.end = window->start + window->size - rom_size - 1; -+ info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; -+ if (request_resource(&iomem_resource, &info->window_rsrc)) { -+ printk(KERN_ERR MOD_NAME -+ ": cannot reserve window resource fragment\n"); -+ goto failed; -+ } -+ } -+ - add_mtd_device(info->mtd); - info->window_start = window->start; - info->window_size = window->size; -+ -+ if (info->window_rsrc.parent) { -+ /* -+ * Registering the MTD device in iomem may not be possible -+ * if there is a BIOS "reserved" and BUSY range. If this -+ * fails then continue anyway. -+ */ -+ snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH, -+ "mtd%d", info->mtd->index); -+ -+ info->rom_rsrc.name = info->mtd_name; -+ info->rom_rsrc.start = window->start + window->size - rom_size; -+ info->rom_rsrc.end = window->start + window->size - 1; -+ info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; -+ if (request_resource(&info->window_rsrc, &info->rom_rsrc)) { -+ printk(KERN_ERR MOD_NAME -+ ": cannot reserve MTD resource\n"); -+ info->rom_rsrc.parent = NULL; -+ } -+ } -+ - return 0; - --err_out_iounmap: -- iounmap((void *)(info->window_addr)); --err_out_free_mmio_region: -- release_mem_region(window->start, window->size); --err_out_none: -+ failed: -+ amd76xrom_cleanup(info); - return -ENODEV; - } - -@@ -186,21 +228,8 @@ - static void __devexit amd76xrom_remove_one (struct pci_dev *pdev) - { - struct amd76xrom_map_info *info = &amd76xrom_map; -- u8 byte; -- -- del_mtd_device(info->mtd); -- map_destroy(info->mtd); -- info->mtd = 0; -- info->map.map_priv_1 = 0; -- -- iounmap((void *)(info->window_addr)); -- info->window_addr = 0; -- -- /* Disable writes through the rom window */ -- pci_read_config_byte(pdev, 0x40, &byte); -- pci_write_config_byte(pdev, 0x40, byte & ~1); - -- release_mem_region(info->window_start, info->window_size); -+ amd76xrom_cleanup(info); - } - - static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = { -@@ -208,6 +237,7 @@ - PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, - PCI_ANY_ID, PCI_ANY_ID, }, -+ { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */ - { 0, } - }; - -@@ -215,10 +245,10 @@ - - #if 0 - static struct pci_driver amd76xrom_driver = { -- name: "amd76xrom", -- id_table: amd76xrom_pci_tbl, -- probe: amd76xrom_init_one, -- remove: amd76xrom_remove_one, -+ .name = MOD_NAME, -+ .id_table = amd76xrom_pci_tbl, -+ .probe = amd76xrom_init_one, -+ .remove = amd76xrom_remove_one, - }; - #endif - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/arctic-mtd.c linux/drivers/mtd/maps/arctic-mtd.c ---- linux-mips-2.4.27/drivers/mtd/maps/arctic-mtd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/arctic-mtd.c 2004-11-19 10:25:11.893200704 +0100 -@@ -0,0 +1,135 @@ -+/* -+ * $Id$ -+ * -+ * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for -+ * IBM 405LP Arctic boards. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Copyright (C) 2002, International Business Machines Corporation -+ * All Rights Reserved. -+ * -+ * Bishop Brock -+ * IBM Research, Austin Center for Low-Power Computing -+ * bcbrock@us.ibm.com -+ * March 2002 -+ * -+ * modified for Arctic by, -+ * David Gibson -+ * IBM OzLabs, Canberra, Australia -+ * <arctic@gibson.dropbear.id.au> -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/init.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+ -+#include <asm/io.h> -+#include <asm/ibm4xx.h> -+ -+/* -+ * 0 : 0xFE00 0000 - 0xFEFF FFFF : Filesystem 1 (16MiB) -+ * 1 : 0xFF00 0000 - 0xFF4F FFFF : kernel (5.12MiB) -+ * 2 : 0xFF50 0000 - 0xFFF5 FFFF : Filesystem 2 (10.624MiB) (if non-XIP) -+ * 3 : 0xFFF6 0000 - 0xFFFF FFFF : PIBS Firmware (640KiB) -+ */ -+ -+#define FFS1_SIZE 0x01000000 /* 16MiB */ -+#define KERNEL_SIZE 0x00500000 /* 5.12MiB */ -+#define FFS2_SIZE 0x00a60000 /* 10.624MiB */ -+#define FIRMWARE_SIZE 0x000a0000 /* 640KiB */ -+ -+ -+#define NAME "Arctic Linux Flash" -+#define PADDR SUBZERO_BOOTFLASH_PADDR -+#define BUSWIDTH 2 -+#define SIZE SUBZERO_BOOTFLASH_SIZE -+#define PARTITIONS 4 -+ -+/* Flash memories on these boards are memory resources, accessed big-endian. */ -+ -+{ -+ /* do nothing for now */ -+} -+ -+static struct map_info arctic_mtd_map = { -+ .name = NAME, -+ .size = SIZE, -+ .buswidth = BUSWIDTH, -+ .phys = PADDR, -+}; -+ -+static struct mtd_info *arctic_mtd; -+ -+static struct mtd_partition arctic_partitions[PARTITIONS] = { -+ { .name = "Filesystem", -+ .size = FFS1_SIZE, -+ .offset = 0,}, -+ { .name = "Kernel", -+ .size = KERNEL_SIZE, -+ .offset = FFS1_SIZE,}, -+ { .name = "Filesystem", -+ .size = FFS2_SIZE, -+ .offset = FFS1_SIZE + KERNEL_SIZE,}, -+ { .name = "Firmware", -+ .size = FIRMWARE_SIZE, -+ .offset = SUBZERO_BOOTFLASH_SIZE - FIRMWARE_SIZE,}, -+}; -+ -+static int __init -+init_arctic_mtd(void) -+{ -+ printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR); -+ -+ arctic_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE); -+ -+ if (!arctic_mtd_map.virt) { -+ printk("%s: failed to ioremap 0x%x\n", NAME, PADDR); -+ return -EIO; -+ } -+ simple_map_init(&arctic_mtd_map); -+ -+ printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8); -+ arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map); -+ -+ if (!arctic_mtd) -+ return -ENXIO; -+ -+ arctic_mtd->owner = THIS_MODULE; -+ -+ return add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS); -+} -+ -+static void __exit -+cleanup_arctic_mtd(void) -+{ -+ if (arctic_mtd) { -+ del_mtd_partitions(arctic_mtd); -+ map_destroy(arctic_mtd); -+ iounmap((void *) arctic_mtd_map.virt); -+ } -+} -+ -+module_init(init_arctic_mtd); -+module_exit(cleanup_arctic_mtd); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>"); -+MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/autcpu12-nvram.c linux/drivers/mtd/maps/autcpu12-nvram.c ---- linux-mips-2.4.27/drivers/mtd/maps/autcpu12-nvram.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/autcpu12-nvram.c 2004-11-19 10:25:11.894200552 +0100 -@@ -2,7 +2,7 @@ - * NV-RAM memory access on autcpu12 - * (C) 2002 Thomas Gleixner (gleixner@autronix.de) - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -24,6 +24,7 @@ - #include <linux/types.h> - #include <linux/kernel.h> - #include <linux/ioport.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <asm/sizes.h> - #include <asm/hardware.h> -@@ -32,80 +33,27 @@ - #include <linux/mtd/map.h> - #include <linux/mtd/partitions.h> - --__u8 autcpu12_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 autcpu12_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 autcpu12_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- while(len) { -- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); -- from++; -- to++; -- len--; -- } --} - - static struct mtd_info *sram_mtd; - - struct map_info autcpu12_sram_map = { -- name: "SRAM", -- size: 32768, -- buswidth: 8, -- read8: autcpu12_read8, -- read16: autcpu12_read16, -- read32: autcpu12_read32, -- copy_from: autcpu12_copy_from, -- write8: autcpu12_write8, -- write16: autcpu12_write16, -- write32: autcpu12_write32, -- copy_to: autcpu12_copy_to -+ .name = "SRAM", -+ .size = 32768, -+ .buswidth = 4, -+ .phys = 0x12000000, - }; - - static int __init init_autcpu12_sram (void) - { - int err, save0, save1; - -- autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K); -- if (!autcpu12_sram_map.map_priv_1) { -+ autcpu12_sram_map.virt = (unsigned long)ioremap(0x12000000, SZ_128K); -+ if (!autcpu12_sram_map.virt) { - printk("Failed to ioremap autcpu12 NV-RAM space\n"); - err = -EIO; - goto out; - } -+ simple_map_init(&autcpu_sram_map); - - /* - * Check for 32K/128K -@@ -115,20 +63,20 @@ - * Read and check result on ofs 0x0 - * Restore contents - */ -- save0 = autcpu12_read32(&autcpu12_sram_map,0); -- save1 = autcpu12_read32(&autcpu12_sram_map,0x10000); -- autcpu12_write32(&autcpu12_sram_map,~save0,0x10000); -+ save0 = map_read32(&autcpu12_sram_map,0); -+ save1 = map_read32(&autcpu12_sram_map,0x10000); -+ map_write32(&autcpu12_sram_map,~save0,0x10000); - /* if we find this pattern on 0x0, we have 32K size - * restore contents and exit - */ -- if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) { -- autcpu12_write32(&autcpu12_sram_map,save0,0x0); -+ if ( map_read32(&autcpu12_sram_map,0) != save0) { -+ map_write32(&autcpu12_sram_map,save0,0x0); - goto map; - } - /* We have a 128K found, restore 0x10000 and set size - * to 128K - */ -- autcpu12_write32(&autcpu12_sram_map,save1,0x10000); -+ ma[_write32(&autcpu12_sram_map,save1,0x10000); - autcpu12_sram_map.size = SZ_128K; - - map: -@@ -139,7 +87,7 @@ - goto out_ioremap; - } - -- sram_mtd->module = THIS_MODULE; -+ sram_mtd->owner = THIS_MODULE; - sram_mtd->erasesize = 16; - - if (add_mtd_device(sram_mtd)) { -@@ -148,7 +96,7 @@ - goto out_probe; - } - -- printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); -+ printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); - - return 0; - -@@ -157,7 +105,7 @@ - sram_mtd = 0; - - out_ioremap: -- iounmap((void *)autcpu12_sram_map.map_priv_1); -+ iounmap((void *)autcpu12_sram_map.virt); - out: - return err; - } -@@ -167,7 +115,7 @@ - if (sram_mtd) { - del_mtd_device(sram_mtd); - map_destroy(sram_mtd); -- iounmap((void *)autcpu12_sram_map.map_priv_1); -+ iounmap((void *)autcpu12_sram_map.virt); - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/beech-mtd.c linux/drivers/mtd/maps/beech-mtd.c ---- linux-mips-2.4.27/drivers/mtd/maps/beech-mtd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/beech-mtd.c 2004-11-19 10:25:11.895200400 +0100 -@@ -0,0 +1,112 @@ -+/* -+ * $Id$ -+ * -+ * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for -+ * IBM 405LP Beech boards. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation; either version 2 of the License, or -+ * (at your option) any later version. -+ * -+ * This program is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with this program; if not, write to the Free Software -+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ * -+ * Copyright (C) 2002, International Business Machines Corporation -+ * All Rights Reserved. -+ * -+ * Bishop Brock -+ * IBM Research, Austin Center for Low-Power Computing -+ * bcbrock@us.ibm.com -+ * March 2002 -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/init.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+ -+#include <asm/io.h> -+#include <asm/ibm4xx.h> -+ -+#define NAME "Beech Linux Flash" -+#define PADDR BEECH_BIGFLASH_PADDR -+#define SIZE BEECH_BIGFLASH_SIZE -+#define BUSWIDTH 1 -+ -+/* Flash memories on these boards are memory resources, accessed big-endian. */ -+ -+ -+static struct map_info beech_mtd_map = { -+ .name = NAME, -+ .size = SIZE, -+ .buswidth = BUSWIDTH, -+ .phys = PADDR -+}; -+ -+static struct mtd_info *beech_mtd; -+ -+static struct mtd_partition beech_partitions[2] = { -+ { -+ .name = "Linux Kernel", -+ .size = BEECH_KERNEL_SIZE, -+ .offset = BEECH_KERNEL_OFFSET -+ }, { -+ .name = "Free Area", -+ .size = BEECH_FREE_AREA_SIZE, -+ .offset = BEECH_FREE_AREA_OFFSET -+ } -+}; -+ -+static int __init -+init_beech_mtd(void) -+{ -+ printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR); -+ -+ beech_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE); -+ -+ if (!beech_mtd_map.virt) { -+ printk("%s: failed to ioremap 0x%x\n", NAME, PADDR); -+ return -EIO; -+ } -+ -+ simple_map_init(&beech_mtd_map); -+ -+ printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8); -+ beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map); -+ -+ if (!beech_mtd) -+ return -ENXIO; -+ -+ beech_mtd->owner = THIS_MODULE; -+ -+ return add_mtd_partitions(beech_mtd, beech_partitions, 2); -+} -+ -+static void __exit -+cleanup_beech_mtd(void) -+{ -+ if (beech_mtd) { -+ del_mtd_partitions(beech_mtd); -+ map_destroy(beech_mtd); -+ iounmap((void *) beech_mtd_map.virt); -+ } -+} -+ -+module_init(init_beech_mtd); -+module_exit(cleanup_beech_mtd); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>"); -+MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/cdb89712.c linux/drivers/mtd/maps/cdb89712.c ---- linux-mips-2.4.27/drivers/mtd/maps/cdb89712.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/cdb89712.c 2004-11-19 10:25:11.897200096 +0100 -@@ -1,13 +1,14 @@ - /* - * Flash on Cirrus CDB89712 - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> - #include <linux/ioport.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <asm/arch/hardware.h> - #include <linux/mtd/mtd.h> -@@ -16,77 +17,21 @@ - - - --__u8 cdb89712_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 cdb89712_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 cdb89712_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void cdb89712_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void cdb89712_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void cdb89712_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void cdb89712_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- // printk ("cdb89712_copy_from: 0x%x@0x%x -> 0x%x\n", len, from, to); -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void cdb89712_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- while(len) { -- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); -- from++; -- to++; -- len--; -- } --} -- - - static struct mtd_info *flash_mtd; - - struct map_info cdb89712_flash_map = { -- name: "flash", -- size: FLASH_SIZE, -- buswidth: FLASH_WIDTH, -- read8: cdb89712_read8, -- read16: cdb89712_read16, -- read32: cdb89712_read32, -- copy_from: cdb89712_copy_from, -- write8: cdb89712_write8, -- write16: cdb89712_write16, -- write32: cdb89712_write32, -- copy_to: cdb89712_copy_to -+ .name = "flash", -+ .size = FLASH_SIZE, -+ .buswidth = FLASH_WIDTH, -+ .phys = FLASH_START, - }; - - struct resource cdb89712_flash_resource = { -- name: "Flash", -- start: FLASH_START, -- end: FLASH_START + FLASH_SIZE - 1, -- flags: IORESOURCE_IO | IORESOURCE_BUSY, -+ .name = "Flash", -+ .start = FLASH_START, -+ .end = FLASH_START + FLASH_SIZE - 1, -+ .flags = IORESOURCE_IO | IORESOURCE_BUSY, - }; - - static int __init init_cdb89712_flash (void) -@@ -99,13 +44,13 @@ - goto out; - } - -- cdb89712_flash_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); -- if (!cdb89712_flash_map.map_priv_1) { -+ cdb89712_flash_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); -+ if (!cdb89712_flash_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); - err = -EIO; - goto out_resource; - } -- -+ simple_map_init(&cdb89712_flash_map); - flash_mtd = do_map_probe("cfi_probe", &cdb89712_flash_map); - if (!flash_mtd) { - flash_mtd = do_map_probe("map_rom", &cdb89712_flash_map); -@@ -118,7 +63,7 @@ - goto out_ioremap; - } - -- flash_mtd->module = THIS_MODULE; -+ flash_mtd->owner = THIS_MODULE; - - if (add_mtd_device(flash_mtd)) { - printk("FLASH device addition failed\n"); -@@ -132,7 +77,7 @@ - map_destroy(flash_mtd); - flash_mtd = 0; - out_ioremap: -- iounmap((void *)cdb89712_flash_map.map_priv_1); -+ iounmap((void *)cdb89712_flash_map.virt); - out_resource: - release_resource (&cdb89712_flash_resource); - out: -@@ -146,24 +91,17 @@ - static struct mtd_info *sram_mtd; - - struct map_info cdb89712_sram_map = { -- name: "SRAM", -- size: SRAM_SIZE, -- buswidth: SRAM_WIDTH, -- read8: cdb89712_read8, -- read16: cdb89712_read16, -- read32: cdb89712_read32, -- copy_from: cdb89712_copy_from, -- write8: cdb89712_write8, -- write16: cdb89712_write16, -- write32: cdb89712_write32, -- copy_to: cdb89712_copy_to -+ .name = "SRAM", -+ .size = SRAM_SIZE, -+ .buswidth = SRAM_WIDTH, -+ .phys = SRAM_START, - }; - - struct resource cdb89712_sram_resource = { -- name: "SRAM", -- start: SRAM_START, -- end: SRAM_START + SRAM_SIZE - 1, -- flags: IORESOURCE_IO | IORESOURCE_BUSY, -+ .name = "SRAM", -+ .start = SRAM_START, -+ .end = SRAM_START + SRAM_SIZE - 1, -+ .flags = IORESOURCE_IO | IORESOURCE_BUSY, - }; - - static int __init init_cdb89712_sram (void) -@@ -176,13 +114,13 @@ - goto out; - } - -- cdb89712_sram_map.map_priv_1 = (unsigned long)ioremap(SRAM_START, SRAM_SIZE); -- if (!cdb89712_sram_map.map_priv_1) { -+ cdb89712_sram_map.virt = (unsigned long)ioremap(SRAM_START, SRAM_SIZE); -+ if (!cdb89712_sram_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); - err = -EIO; - goto out_resource; - } -- -+ simple_map_init(&cdb89712_sram_map); - sram_mtd = do_map_probe("map_ram", &cdb89712_sram_map); - if (!sram_mtd) { - printk("SRAM probe failed\n"); -@@ -190,7 +128,7 @@ - goto out_ioremap; - } - -- sram_mtd->module = THIS_MODULE; -+ sram_mtd->owner = THIS_MODULE; - sram_mtd->erasesize = 16; - - if (add_mtd_device(sram_mtd)) { -@@ -205,7 +143,7 @@ - map_destroy(sram_mtd); - sram_mtd = 0; - out_ioremap: -- iounmap((void *)cdb89712_sram_map.map_priv_1); -+ iounmap((void *)cdb89712_sram_map.virt); - out_resource: - release_resource (&cdb89712_sram_resource); - out: -@@ -221,20 +159,17 @@ - static struct mtd_info *bootrom_mtd; - - struct map_info cdb89712_bootrom_map = { -- name: "BootROM", -- size: BOOTROM_SIZE, -- buswidth: BOOTROM_WIDTH, -- read8: cdb89712_read8, -- read16: cdb89712_read16, -- read32: cdb89712_read32, -- copy_from: cdb89712_copy_from, -+ .name = "BootROM", -+ .size = BOOTROM_SIZE, -+ .buswidth = BOOTROM_WIDTH, -+ .phys = BOOTROM_START, - }; - - struct resource cdb89712_bootrom_resource = { -- name: "BootROM", -- start: BOOTROM_START, -- end: BOOTROM_START + BOOTROM_SIZE - 1, -- flags: IORESOURCE_IO | IORESOURCE_BUSY, -+ .name = "BootROM", -+ .start = BOOTROM_START, -+ .end = BOOTROM_START + BOOTROM_SIZE - 1, -+ .flags = IORESOURCE_IO | IORESOURCE_BUSY, - }; - - static int __init init_cdb89712_bootrom (void) -@@ -247,13 +182,13 @@ - goto out; - } - -- cdb89712_bootrom_map.map_priv_1 = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE); -- if (!cdb89712_bootrom_map.map_priv_1) { -+ cdb89712_bootrom_map.virt = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE); -+ if (!cdb89712_bootrom_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); - err = -EIO; - goto out_resource; - } -- -+ simple_map_init(&cdb89712_bootrom_map); - bootrom_mtd = do_map_probe("map_rom", &cdb89712_bootrom_map); - if (!bootrom_mtd) { - printk("BootROM probe failed\n"); -@@ -261,7 +196,7 @@ - goto out_ioremap; - } - -- bootrom_mtd->module = THIS_MODULE; -+ bootrom_mtd->owner = THIS_MODULE; - bootrom_mtd->erasesize = 0x10000; - - if (add_mtd_device(bootrom_mtd)) { -@@ -276,7 +211,7 @@ - map_destroy(bootrom_mtd); - bootrom_mtd = 0; - out_ioremap: -- iounmap((void *)cdb89712_bootrom_map.map_priv_1); -+ iounmap((void *)cdb89712_bootrom_map.virt); - out_resource: - release_resource (&cdb89712_bootrom_resource); - out: -@@ -306,21 +241,21 @@ - if (sram_mtd) { - del_mtd_device(sram_mtd); - map_destroy(sram_mtd); -- iounmap((void *)cdb89712_sram_map.map_priv_1); -+ iounmap((void *)cdb89712_sram_map.virt); - release_resource (&cdb89712_sram_resource); - } - - if (flash_mtd) { - del_mtd_device(flash_mtd); - map_destroy(flash_mtd); -- iounmap((void *)cdb89712_flash_map.map_priv_1); -+ iounmap((void *)cdb89712_flash_map.virt); - release_resource (&cdb89712_flash_resource); - } - - if (bootrom_mtd) { - del_mtd_device(bootrom_mtd); - map_destroy(bootrom_mtd); -- iounmap((void *)cdb89712_bootrom_map.map_priv_1); -+ iounmap((void *)cdb89712_bootrom_map.virt); - release_resource (&cdb89712_bootrom_resource); - } - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ceiva.c linux/drivers/mtd/maps/ceiva.c ---- linux-mips-2.4.27/drivers/mtd/maps/ceiva.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/ceiva.c 2004-11-19 10:25:11.898199944 +0100 -@@ -11,7 +11,7 @@ - * - * (C) 2000 Nicolas Pitre <nico@cam.org> - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/config.h> -@@ -19,6 +19,7 @@ - #include <linux/types.h> - #include <linux/ioport.h> - #include <linux/kernel.h> -+#include <linux/init.h> - - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -31,62 +32,10 @@ - #include <asm/sizes.h> - - /* -- * This isnt complete yet, so... -+ * This isn't complete yet, so... - */ - #define CONFIG_MTD_CEIVA_STATICMAP - --static __u8 clps_read8(struct map_info *map, unsigned long ofs) --{ -- return readb(map->map_priv_1 + ofs); --} -- --static __u16 clps_read16(struct map_info *map, unsigned long ofs) --{ -- return readw(map->map_priv_1 + ofs); --} -- --static __u32 clps_read32(struct map_info *map, unsigned long ofs) --{ -- return readl(map->map_priv_1 + ofs); --} -- --static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy(to, (void *)(map->map_priv_1 + from), len); --} -- --static void clps_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- writeb(d, map->map_priv_1 + adr); --} -- --static void clps_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- writew(d, map->map_priv_1 + adr); --} -- --static void clps_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- writel(d, map->map_priv_1 + adr); --} -- --static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy((void *)(map->map_priv_1 + to), from, len); --} -- --static struct map_info clps_map __initdata = { -- name: "clps flash", -- read8: clps_read8, -- read16: clps_read16, -- read32: clps_read32, -- copy_from: clps_copy_from, -- write8: clps_write8, -- write16: clps_write16, -- write32: clps_write32, -- copy_to: clps_copy_to, --}; -- - #ifdef CONFIG_MTD_CEIVA_STATICMAP - /* - * See include/linux/mtd/partitions.h for definition of the mtd_partition -@@ -176,7 +125,7 @@ - maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); - if (!maps) - return -ENOMEM; -- -+ memset(maps, 0, sizeof(struct map_info) * nr); - /* - * Claim and then map the memory regions. - */ -@@ -191,7 +140,9 @@ - } - - clps[i].map = maps + i; -- memcpy(clps[i].map, &clps_map, sizeof(struct map_info)); -+ -+ clps[i].map->name = "clps flash"; -+ clps[i].map->phys = clps[i].base; - - clps[i].vbase = ioremap(clps[i].base, clps[i].size); - if (!clps[i].vbase) { -@@ -199,16 +150,18 @@ - break; - } - -- clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase; -+ clps[i].map->virt = (unsigned long)clps[i].vbase; - clps[i].map->buswidth = clps[i].width; - clps[i].map->size = clps[i].size; - -+ simple_map_init(&clps[i].map); -+ - clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); - if (clps[i].mtd == NULL) { - ret = -ENXIO; - break; - } -- clps[i].mtd->module = THIS_MODULE; -+ clps[i].mtd->owner = THIS_MODULE; - subdev[i] = clps[i].mtd; - - printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " -@@ -318,10 +271,8 @@ - return nr; - } - --extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); --extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); -- - static struct mtd_partition *parsed_parts; -+static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; - - static void __init clps_locate_partitions(struct mtd_info *mtd) - { -@@ -331,20 +282,11 @@ - /* - * Partition selection stuff. - */ --#ifdef CONFIG_MTD_CMDLINE_PARTS -- nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps"); -+ nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); - if (nr_parts > 0) { - part_type = "command line"; - break; - } --#endif --#ifdef CONFIG_MTD_REDBOOT_PARTS -- nr_parts = parse_redboot_partitions(mtd, &parsed_parts); -- if (nr_parts > 0) { -- part_type = "RedBoot"; -- break; -- } --#endif - #ifdef CONFIG_MTD_CEIVA_STATICMAP - nr_parts = clps_static_partitions(&parsed_parts); - if (nr_parts > 0) { -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/cfi_flagadm.c linux/drivers/mtd/maps/cfi_flagadm.c ---- linux-mips-2.4.27/drivers/mtd/maps/cfi_flagadm.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/cfi_flagadm.c 2004-11-19 10:25:11.900199640 +0100 -@@ -1,7 +1,7 @@ - /* - * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is> - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the -@@ -27,6 +27,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -55,83 +56,33 @@ - #define FLASH_PARTITION3_ADDR 0x00240000 - #define FLASH_PARTITION3_SIZE 0x001C0000 - --__u8 flagadm_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 flagadm_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 flagadm_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void flagadm_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void flagadm_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void flagadm_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void flagadm_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void flagadm_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} - - struct map_info flagadm_map = { -- name: "FlagaDM flash device", -- size: FLASH_SIZE, -- buswidth: 2, -- read8: flagadm_read8, -- read16: flagadm_read16, -- read32: flagadm_read32, -- copy_from: flagadm_copy_from, -- write8: flagadm_write8, -- write16: flagadm_write16, -- write32: flagadm_write32, -- copy_to: flagadm_copy_to -+ .name = "FlagaDM flash device", -+ .size = FLASH_SIZE, -+ .buswidth = 2, - }; - - struct mtd_partition flagadm_parts[] = { - { -- name : "Bootloader", -- offset : FLASH_PARTITION0_ADDR, -- size : FLASH_PARTITION0_SIZE -+ .name = "Bootloader", -+ .offset = FLASH_PARTITION0_ADDR, -+ .size = FLASH_PARTITION0_SIZE - }, - { -- name : "Kernel image", -- offset : FLASH_PARTITION1_ADDR, -- size : FLASH_PARTITION1_SIZE -+ .name = "Kernel image", -+ .offset = FLASH_PARTITION1_ADDR, -+ .size = FLASH_PARTITION1_SIZE - }, - { -- name : "Initial ramdisk image", -- offset : FLASH_PARTITION2_ADDR, -- size : FLASH_PARTITION2_SIZE -+ .name = "Initial ramdisk image", -+ .offset = FLASH_PARTITION2_ADDR, -+ .size = FLASH_PARTITION2_SIZE - }, - { -- name : "Persistant storage", -- offset : FLASH_PARTITION3_ADDR, -- size : FLASH_PARTITION3_SIZE -+ .name = "Persistant storage", -+ .offset = FLASH_PARTITION3_ADDR, -+ .size = FLASH_PARTITION3_SIZE - } - }; - -@@ -144,22 +95,26 @@ - printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", - FLASH_SIZE, FLASH_PHYS_ADDR); - -- flagadm_map.map_priv_1 = (unsigned long)ioremap(FLASH_PHYS_ADDR, -+ flagadm_map.phys = FLASH_PHYS_ADDR; -+ flagadm_map.virt = (unsigned long)ioremap(FLASH_PHYS_ADDR, - FLASH_SIZE); - -- if (!flagadm_map.map_priv_1) { -+ if (!flagadm_map.virt) { - printk("Failed to ioremap\n"); - return -EIO; - } -+ -+ simple_map_init(&flagadm_map); -+ - mymtd = do_map_probe("cfi_probe", &flagadm_map); - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT); - printk(KERN_NOTICE "FlagaDM flash device initialized\n"); - return 0; - } - -- iounmap((void *)flagadm_map.map_priv_1); -+ iounmap((void *)flagadm_map.virt); - return -ENXIO; - } - -@@ -169,9 +124,9 @@ - del_mtd_partitions(mymtd); - map_destroy(mymtd); - } -- if (flagadm_map.map_priv_1) { -- iounmap((void *)flagadm_map.map_priv_1); -- flagadm_map.map_priv_1 = 0; -+ if (flagadm_map.virt) { -+ iounmap((void *)flagadm_map.virt); -+ flagadm_map.virt = 0; - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/cstm_mips_ixx.c linux/drivers/mtd/maps/cstm_mips_ixx.c ---- linux-mips-2.4.27/drivers/mtd/maps/cstm_mips_ixx.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/cstm_mips_ixx.c 2004-11-19 10:25:11.901199488 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. - * Config with both CFI and JEDEC device support. -@@ -33,55 +33,13 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> - #include <linux/mtd/partitions.h> - #include <linux/config.h> -- --#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - #include <linux/delay.h> --#endif -- --__u8 cstm_mips_ixx_read8(struct map_info *map, unsigned long ofs) --{ -- return *(__u8 *)(map->map_priv_1 + ofs); --} -- --__u16 cstm_mips_ixx_read16(struct map_info *map, unsigned long ofs) --{ -- return *(__u16 *)(map->map_priv_1 + ofs); --} -- --__u32 cstm_mips_ixx_read32(struct map_info *map, unsigned long ofs) --{ -- return *(__u32 *)(map->map_priv_1 + ofs); --} -- --void cstm_mips_ixx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void cstm_mips_ixx_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- *(__u8 *)(map->map_priv_1 + adr) = d; --} -- --void cstm_mips_ixx_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- *(__u16 *)(map->map_priv_1 + adr) = d; --} -- --void cstm_mips_ixx_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- *(__u32 *)(map->map_priv_1 + adr) = d; --} -- --void cstm_mips_ixx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} - - #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - #define CC_GCR 0xB4013818 -@@ -97,10 +55,17 @@ - #define CC_GPAICR 0xB4013804 - #endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ - -+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) - { -+ static spinlock_t vpp_lock = SPIN_LOCK_UNLOCKED; -+ static int vpp_count = 0; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&vpp_lock, flags); -+ - if (vpp) { --#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -+ if (!vpp_count++) { - __u16 data; - __u8 data1; - static u8 first = 1; -@@ -116,10 +81,9 @@ - enabling vpp after powerup */ - udelay(40); - } --#endif /* CONFIG_MIPS_ITE8172 */ - } -- else { --#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -+ } else { -+ if (!--vpp_count) { - __u16 data; - - // Set GPIO port B pin3 to high -@@ -127,26 +91,11 @@ - data = (data & 0xff3f) | 0x0040; - *(__u16 *)CC_GPBCR = data; - *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7; --#endif /* CONFIG_MIPS_ITE8172 */ - } -+ } -+ spin_unlock_irqrestore(&vpp_lock, flags); - } -- --const struct map_info basic_cstm_mips_ixx_map = { -- NULL, -- 0, -- 0, -- cstm_mips_ixx_read8, -- cstm_mips_ixx_read16, -- cstm_mips_ixx_read32, -- cstm_mips_ixx_copy_from, -- cstm_mips_ixx_write8, -- cstm_mips_ixx_write16, -- cstm_mips_ixx_write32, -- cstm_mips_ixx_copy_to, -- cstm_mips_ixx_set_vpp, -- 0, -- 0 --}; -+#endif - - /* board and partition description */ - -@@ -175,9 +124,9 @@ - static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { - { // 28F128J3A in 2x16 configuration - { -- name: "main partition ", -- size: 0x02000000, // 128 x 2 x 128k byte sectors -- offset: 0, -+ .name = "main partition ", -+ .size = 0x02000000, // 128 x 2 x 128k byte sectors -+ .offset = 0, - }, - }, - }; -@@ -197,9 +146,9 @@ - static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { - { - { -- name: "main partition", -- size: CONFIG_MTD_CSTM_MIPS_IXX_LEN, -- offset: 0, -+ .name = "main partition", -+ .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, -+ .offset = 0, - }, - }, - }; -@@ -216,17 +165,24 @@ - - /* Initialize mapping */ - for (i=0;i<PHYSMAP_NUMBER;i++) { -- printk(KERN_NOTICE "cstm_mips_ixx flash device: %lx at %lx\n", cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); -- memcpy((char *)&cstm_mips_ixx_map[i],(char *)&basic_cstm_mips_ixx_map,sizeof(struct map_info)); -- cstm_mips_ixx_map[i].map_priv_1 = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size); -- if (!cstm_mips_ixx_map[i].map_priv_1) { -+ printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", -+ cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); -+ -+ -+ cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr; -+ cstm_mips_ixx_map[i].virt = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size); -+ if (!cstm_mips_ixx_map[i].virt) { - printk(KERN_WARNING "Failed to ioremap\n"); - return -EIO; - } - cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name; - cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size; - cstm_mips_ixx_map[i].buswidth = cstm_mips_ixx_board_desc[i].buswidth; -- //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].map_priv_1)); -+#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -+ cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp; -+#endif -+ simple_map_init(&cstm_mips_ixx_map[i]); -+ //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt)); - } - - #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) -@@ -244,7 +200,7 @@ - printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd); - } - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - - cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd; - add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions); -@@ -266,9 +222,9 @@ - del_mtd_partitions(mymtd); - map_destroy(mymtd); - } -- if (cstm_mips_ixx_map[i].map_priv_1) { -- iounmap((void *)cstm_mips_ixx_map[i].map_priv_1); -- cstm_mips_ixx_map[i].map_priv_1 = 0; -+ if (cstm_mips_ixx_map[i].virt) { -+ iounmap((void *)cstm_mips_ixx_map[i].virt); -+ cstm_mips_ixx_map[i].virt = 0; - } - } - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/db1x00-flash.c linux/drivers/mtd/maps/db1x00-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/db1x00-flash.c 2003-02-16 07:25:24.000000000 +0100 -+++ linux/drivers/mtd/maps/db1x00-flash.c 2004-11-19 10:25:11.903199184 +0100 -@@ -8,6 +8,7 @@ - #include <linux/config.h> - #include <linux/module.h> - #include <linux/types.h> -+#include <linux/init.h> - #include <linux/kernel.h> - - #include <linux/mtd/mtd.h> -@@ -29,76 +30,6 @@ - static unsigned long flash_size; - - static BCSR * const bcsr = (BCSR *)0xAE000000; -- --__u8 physmap_read8(struct map_info *map, unsigned long ofs) --{ -- __u8 ret; -- ret = __raw_readb(map->map_priv_1 + ofs); -- DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); -- return ret; --} -- --__u16 physmap_read16(struct map_info *map, unsigned long ofs) --{ -- __u16 ret; -- ret = __raw_readw(map->map_priv_1 + ofs); -- DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); -- return ret; --} -- --__u32 physmap_read32(struct map_info *map, unsigned long ofs) --{ -- __u32 ret; -- ret = __raw_readl(map->map_priv_1 + ofs); -- DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); -- return ret; --} -- --void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to); -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from); -- memcpy_toio(map->map_priv_1 + to, from, len); --} -- --static struct map_info db1x00_map = { -- name: "Db1x00 flash", -- read8: physmap_read8, -- read16: physmap_read16, -- read32: physmap_read32, -- copy_from: physmap_copy_from, -- write8: physmap_write8, -- write16: physmap_write16, -- write32: physmap_write32, -- copy_to: physmap_copy_to, --}; -- - static unsigned char flash_buswidth = 4; - - /* -@@ -115,58 +46,62 @@ - */ - static struct mtd_partition db1x00_partitions[] = { - { -- name: "User FS", -- size: 0x1c00000, -- offset: 0x0000000 -+ .name = "User FS", -+ .size = 0x1c00000, -+ .offset = 0x0000000 - },{ -- name: "yamon", -- size: 0x0100000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE -+ .name = "yamon", -+ .size = 0x0100000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE - },{ -- name: "raw kernel", -- size: (0x300000-0x40000), /* last 256KB is yamon env */ -- offset: MTDPART_OFS_APPEND, -+ .name = "raw kernel", -+ .size = (0x300000-0x40000), /* last 256KB is env */ -+ .offset = MTDPART_OFS_APPEND, - } - }; - #elif defined(DB1X00_BOOT_ONLY) - static struct mtd_partition db1x00_partitions[] = { - { -- name: "User FS", -- size: 0x00c00000, -- offset: 0x0000000 -+ .name = "User FS", -+ .size = 0x00c00000, -+ .offset = 0x0000000 - },{ -- name: "yamon", -- size: 0x0100000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE -+ .name = "yamon", -+ .size = 0x0100000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE - },{ -- name: "raw kernel", -- size: (0x300000-0x40000), /* last 256KB is yamon env */ -- offset: MTDPART_OFS_APPEND, -+ .name = "raw kernel", -+ .size = (0x300000-0x40000), /* last 256KB is env */ -+ .offset = MTDPART_OFS_APPEND, - } - }; - #elif defined(DB1X00_USER_ONLY) - static struct mtd_partition db1x00_partitions[] = { - { -- name: "User FS", -- size: 0x0e00000, -- offset: 0x0000000 -+ .name = "User FS", -+ .size = 0x0e00000, -+ .offset = 0x0000000 - },{ -- name: "raw kernel", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .name = "raw kernel", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - #else - #error MTD_DB1X00 define combo error /* should never happen */ - #endif -+#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -+#define NAME "Db1x00 Linux Flash" - --#define NB_OF(x) (sizeof(x)/sizeof(x[0])) -+static struct map_info db1xxx_mtd_map = { -+ .name = NAME, -+}; - - static struct mtd_partition *parsed_parts; --static struct mtd_info *mymtd; -+static struct mtd_info *db1xxx_mtd; - - /* - * Probe the flash density and setup window address and size -@@ -174,7 +109,7 @@ - * want the MTD driver to be probing the boot or user flash, - * so having the option to enable only one bank is important. - */ --int setup_flash_params() -+int setup_flash_params(void) - { - switch ((bcsr->status >> 14) & 0x3) { - case 0: /* 64Mbit devices */ -@@ -228,6 +163,10 @@ - default: - return 1; - } -+ db1xxx_mtd_map.size = window_size; -+ db1xxx_mtd_map.buswidth = flash_buswidth; -+ db1xxx_mtd_map.phys = window_addr; -+ db1xxx_mtd_map.buswidth = flash_buswidth; - return 0; - } - -@@ -235,10 +174,6 @@ - { - struct mtd_partition *parts; - int nb_parts = 0; -- char *part_type; -- -- /* Default flash buswidth */ -- db1x00_map.buswidth = flash_buswidth; - - if (setup_flash_params()) - return -ENXIO; -@@ -246,32 +181,29 @@ - /* - * Static partition definition selection - */ -- part_type = "static"; - parts = db1x00_partitions; - nb_parts = NB_OF(db1x00_partitions); -- db1x00_map.size = window_size; - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n", -- db1x00_map.buswidth*8); -- db1x00_map.map_priv_1 = -- (unsigned long)ioremap(window_addr, window_size); -- mymtd = do_map_probe("cfi_probe", &db1x00_map); -- if (!mymtd) return -ENXIO; -- mymtd->module = THIS_MODULE; -+ db1xxx_mtd_map.buswidth*8); -+ db1xxx_mtd_map.virt = (unsigned long)ioremap(window_addr, window_size); -+ db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map); -+ if (!db1xxx_mtd) return -ENXIO; -+ db1xxx_mtd->owner = THIS_MODULE; - -- add_mtd_partitions(mymtd, parts, nb_parts); -+ add_mtd_partitions(db1xxx_mtd, parts, nb_parts); - return 0; - } - - static void __exit db1x00_mtd_cleanup(void) - { -- if (mymtd) { -- del_mtd_partitions(mymtd); -- map_destroy(mymtd); -+ if (db1xxx_mtd) { -+ del_mtd_partitions(db1xxx_mtd); -+ map_destroy(db1xxx_mtd); - if (parsed_parts) - kfree(parsed_parts); - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/dbox2-flash.c linux/drivers/mtd/maps/dbox2-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/dbox2-flash.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/dbox2-flash.c 2004-11-19 10:25:11.904199032 +0100 -@@ -1,12 +1,13 @@ - /* -- * $Id$ -+ * $Id$ - * -- * Nokia / Sagem D-Box 2 flash driver -+ * D-Box 2 flash driver - */ - - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -16,22 +17,44 @@ - /* partition_info gives details on the logical partitions that the split the - * single flash device into. If the size if zero we use up to the end of the - * device. */ --static struct mtd_partition partition_info[]= {{name: "BR bootloader", // raw -- size: 128 * 1024, -- offset: 0, -- mask_flags: MTD_WRITEABLE}, -- {name: "PPC bootloader", // flfs -- size: 128 * 1024, -- offset: MTDPART_OFS_APPEND, -- mask_flags: 0}, -- {name: "Kernel", // idxfs -- size: 768 * 1024, -- offset: MTDPART_OFS_APPEND, -- mask_flags: 0}, -- {name: "System", // jffs -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -- mask_flags: 0}}; -+static struct mtd_partition partition_info[]= { -+ { -+ .name = "BR bootloader", -+ .size = 128 * 1024, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE -+ }, -+ { -+ .name = "flfs (ppcboot)", -+ .size = 128 * 1024, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = 0 -+ }, -+ { -+ .name = "root (cramfs)", -+ .size = 7040 * 1024, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = 0 -+ }, -+ { -+ .name = "var (jffs2)", -+ .size = 896 * 1024, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = 0 -+ }, -+ { -+ .name = "flash without bootloader", -+ .size = MTDPART_SIZ_FULL, -+ .offset = 128 * 1024, -+ .mask_flags = 0 -+ }, -+ { -+ .name = "complete flash", -+ .size = MTDPART_SIZ_FULL, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE -+ } -+}; - - #define NUM_PARTITIONS (sizeof(partition_info) / sizeof(partition_info[0])) - -@@ -40,72 +63,24 @@ - - static struct mtd_info *mymtd; - --__u8 dbox2_flash_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 dbox2_flash_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 dbox2_flash_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void dbox2_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void dbox2_flash_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void dbox2_flash_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void dbox2_flash_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void dbox2_flash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} - - struct map_info dbox2_flash_map = { -- name: "D-Box 2 flash memory", -- size: WINDOW_SIZE, -- buswidth: 4, -- read8: dbox2_flash_read8, -- read16: dbox2_flash_read16, -- read32: dbox2_flash_read32, -- copy_from: dbox2_flash_copy_from, -- write8: dbox2_flash_write8, -- write16: dbox2_flash_write16, -- write32: dbox2_flash_write32, -- copy_to: dbox2_flash_copy_to -+ .name = "D-Box 2 flash memory", -+ .size = WINDOW_SIZE, -+ .buswidth = 4, -+ .phys = WINDOW_ADDR, - }; - - int __init init_dbox2_flash(void) - { - printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR); -- dbox2_flash_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); -+ dbox2_flash_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - -- if (!dbox2_flash_map.map_priv_1) { -+ if (!dbox2_flash_map.virt) { - printk("Failed to ioremap\n"); - return -EIO; - } -+ simple_map_init(&dbox2_flash_map); - - // Probe for dual Intel 28F320 or dual AMD - mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); -@@ -117,7 +92,7 @@ - } - - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - - /* Create MTD devices for each partition. */ - add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); -@@ -125,7 +100,7 @@ - return 0; - } - -- iounmap((void *)dbox2_flash_map.map_priv_1); -+ iounmap((void *)dbox2_flash_map.virt); - return -ENXIO; - } - -@@ -135,9 +110,9 @@ - del_mtd_partitions(mymtd); - map_destroy(mymtd); - } -- if (dbox2_flash_map.map_priv_1) { -- iounmap((void *)dbox2_flash_map.map_priv_1); -- dbox2_flash_map.map_priv_1 = 0; -+ if (dbox2_flash_map.virt) { -+ iounmap((void *)dbox2_flash_map.virt); -+ dbox2_flash_map.virt = 0; - } - } - -@@ -146,5 +121,5 @@ - - - MODULE_LICENSE("GPL"); --MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>"); --MODULE_DESCRIPTION("MTD map driver for Nokia/Sagem D-Box 2 board"); -+MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>"); -+MODULE_DESCRIPTION("MTD map driver for D-Box 2 board"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/dc21285.c linux/drivers/mtd/maps/dc21285.c ---- linux-mips-2.4.27/drivers/mtd/maps/dc21285.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/dc21285.c 2004-11-19 10:25:11.906198728 +0100 -@@ -5,12 +5,13 @@ - * - * This code is GPL - * -- * $Id$ -+ * $Id$ - */ - #include <linux/config.h> - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -92,26 +93,42 @@ - } - - struct map_info dc21285_map = { -- name: "DC21285 flash", -- size: 16*1024*1024, -- read8: dc21285_read8, -- read16: dc21285_read16, -- read32: dc21285_read32, -- copy_from: dc21285_copy_from, -- write8: dc21285_write8, -- write16: dc21285_write16, -- write32: dc21285_write32, -- copy_to: dc21285_copy_to -+ .name = "DC21285 flash", -+ .phys = NO_XIP, -+ .size = 16*1024*1024, -+ .read8 = dc21285_read8, -+ .read16 = dc21285_read16, -+ .read32 = dc21285_read32, -+ .copy_from = dc21285_copy_from, -+ .write8 = dc21285_write8, -+ .write16 = dc21285_write16, -+ .write32 = dc21285_write32, -+ .copy_to = dc21285_copy_to - }; - - - /* Partition stuff */ - static struct mtd_partition *dc21285_parts; -- --extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); -+#ifdef CONFIG_MTD_PARTITIONS -+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; -+#endif - - int __init init_dc21285(void) - { -+ -+ /* -+ * Flash timing is determined with bits 19-16 of the -+ * CSR_SA110_CNTL. The value is the number of wait cycles, or -+ * 0 for 16 cycles (the default). Cycles are 20 ns. -+ * Here we use 7 for 140 ns flash chips. -+ */ -+ /* access time */ -+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); -+ /* burst time */ -+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); -+ /* tristate time */ -+ *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); -+ - /* Determine buswidth */ - switch (*CSR_SA110_CNTL & (3<<14)) { - case SA110_CNTL_ROMWIDTH_8: -@@ -141,33 +158,18 @@ - if (mymtd) { - int nrparts = 0; - -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - - /* partition fixup */ - --#ifdef CONFIG_MTD_REDBOOT_PARTS -- nrparts = parse_redboot_partitions(mymtd, &dc21285_parts); --#endif -+#ifdef CONFIG_MTD_PARTITIONS -+ nrparts = parse_mtd_partitions(mymtd, probes, &dc21285_parts, (void *)0); - if (nrparts > 0) { - add_mtd_partitions(mymtd, dc21285_parts, nrparts); -- } else if (nrparts == 0) { -- printk(KERN_NOTICE "RedBoot partition table failed\n"); -- add_mtd_device(mymtd); -+ return 0; - } -- -- /* -- * Flash timing is determined with bits 19-16 of the -- * CSR_SA110_CNTL. The value is the number of wait cycles, or -- * 0 for 16 cycles (the default). Cycles are 20 ns. -- * Here we use 7 for 140 ns flash chips. -- */ -- /* access time */ -- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); -- /* burst time */ -- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); -- /* tristate time */ -- *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); -- -+#endif -+ add_mtd_device(mymtd); - return 0; - } - -@@ -177,17 +179,16 @@ - - static void __exit cleanup_dc21285(void) - { -- if (mymtd) { -+#ifdef CONFIG_MTD_PARTITIONS -+ if (dc21285_parts) { -+ del_mtd_partitions(mymtd); -+ kfree(dc21285_parts); -+ } else -+#endif - del_mtd_device(mymtd); -+ - map_destroy(mymtd); -- mymtd = NULL; -- } -- if (dc21285_map.map_priv_1) { - iounmap((void *)dc21285_map.map_priv_1); -- dc21285_map.map_priv_1 = 0; -- } -- if(dc21285_parts) -- kfree(dc21285_parts); - } - - module_init(init_dc21285); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/dilnetpc.c linux/drivers/mtd/maps/dilnetpc.c ---- linux-mips-2.4.27/drivers/mtd/maps/dilnetpc.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/dilnetpc.c 2004-11-19 10:25:11.907198576 +0100 -@@ -14,7 +14,7 @@ - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * -- * $Id$ -+ * $Id$ - * - * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems - * featuring the AMD Elan SC410 processor. There are two variants of this -@@ -29,6 +29,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -36,7 +37,7 @@ - #include <linux/mtd/concat.h> - - /* --** The DIL/NetPC keeps it's BIOS in two distinct flash blocks. -+** The DIL/NetPC keeps its BIOS in two distinct flash blocks. - ** Destroying any of these blocks transforms the DNPC into - ** a paperweight (albeit not a very useful one, considering - ** it only weighs a few grams). -@@ -189,45 +190,6 @@ - } - - --static __u8 dnpc_read8(struct map_info *map, unsigned long ofs) --{ -- return readb(map->map_priv_1 + ofs); --} -- --static __u16 dnpc_read16(struct map_info *map, unsigned long ofs) --{ -- return readw(map->map_priv_1 + ofs); --} -- --static __u32 dnpc_read32(struct map_info *map, unsigned long ofs) --{ -- return readl(map->map_priv_1 + ofs); --} -- --static void dnpc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); --} -- --static void dnpc_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- writeb(d, map->map_priv_1 + adr); --} -- --static void dnpc_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- writew(d, map->map_priv_1 + adr); --} -- --static void dnpc_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- writel(d, map->map_priv_1 + adr); --} -- --static void dnpc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio((void *)(map->map_priv_1 + to), from, len); --} - - /* - ************************************************************ -@@ -288,19 +250,11 @@ - #define WINDOW_ADDR FLASH_BASE - - static struct map_info dnpc_map = { -- name: "ADNP Flash Bank", -- size: ADNP_WINDOW_SIZE, -- buswidth: 1, -- read8: dnpc_read8, -- read16: dnpc_read16, -- read32: dnpc_read32, -- copy_from: dnpc_copy_from, -- write8: dnpc_write8, -- write16: dnpc_write16, -- write32: dnpc_write32, -- copy_to: dnpc_copy_to, -- set_vpp: adnp_set_vpp, -- map_priv_2: WINDOW_ADDR -+ .name = "ADNP Flash Bank", -+ .size = ADNP_WINDOW_SIZE, -+ .buswidth = 1, -+ .set_vpp = adnp_set_vpp, -+ .phys = WINDOW_ADDR - }; - - /* -@@ -316,29 +270,29 @@ - static struct mtd_partition partition_info[]= - { - { -- name: "ADNP boot", -- offset: 0, -- size: 0xf0000, -+ .name = "ADNP boot", -+ .offset = 0, -+ .size = 0xf0000, - }, - { -- name: "ADNP system BIOS", -- offset: MTDPART_OFS_NXTBLK, -- size: 0x10000, -+ .name = "ADNP system BIOS", -+ .offset = MTDPART_OFS_NXTBLK, -+ .size = 0x10000, - #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED -- mask_flags: MTD_WRITEABLE, -+ .mask_flags = MTD_WRITEABLE, - #endif - }, - { -- name: "ADNP file system", -- offset: MTDPART_OFS_NXTBLK, -- size: 0x2f0000, -+ .name = "ADNP file system", -+ .offset = MTDPART_OFS_NXTBLK, -+ .size = 0x2f0000, - }, - { -- name: "ADNP system BIOS entry", -- offset: MTDPART_OFS_NXTBLK, -- size: MTDPART_SIZ_FULL, -+ .name = "ADNP system BIOS entry", -+ .offset = MTDPART_OFS_NXTBLK, -+ .size = MTDPART_SIZ_FULL, - #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED -- mask_flags: MTD_WRITEABLE, -+ .mask_flags = MTD_WRITEABLE, - #endif - }, - }; -@@ -369,21 +323,21 @@ - static struct mtd_partition higlvl_partition_info[]= - { - { -- name: "ADNP boot block", -- offset: 0, -- size: CONFIG_MTD_DILNETPC_BOOTSIZE, -+ .name = "ADNP boot block", -+ .offset = 0, -+ .size = CONFIG_MTD_DILNETPC_BOOTSIZE, - }, - { -- name: "ADNP file system space", -- offset: MTDPART_OFS_NXTBLK, -- size: ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, -+ .name = "ADNP file system space", -+ .offset = MTDPART_OFS_NXTBLK, -+ .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, - }, - { -- name: "ADNP system BIOS + BIOS Entry", -- offset: MTDPART_OFS_NXTBLK, -- size: MTDPART_SIZ_FULL, -+ .name = "ADNP system BIOS + BIOS Entry", -+ .offset = MTDPART_OFS_NXTBLK, -+ .size = MTDPART_SIZ_FULL, - #ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED -- mask_flags: MTD_WRITEABLE, -+ .mask_flags = MTD_WRITEABLE, - #endif - }, - }; -@@ -447,18 +401,19 @@ - } - - printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", -- is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.map_priv_2); -+ is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); - -- dnpc_map.map_priv_1 = (unsigned long)ioremap_nocache(dnpc_map.map_priv_2, dnpc_map.size); -+ dnpc_map.virt = (unsigned long)ioremap_nocache(dnpc_map.phys, dnpc_map.size); - -- dnpc_map_flash(dnpc_map.map_priv_2, dnpc_map.size); -+ dnpc_map_flash(dnpc_map.phys, dnpc_map.size); - -- if (!dnpc_map.map_priv_1) { -+ if (!dnpc_map.virt) { - printk("Failed to ioremap_nocache\n"); - return -EIO; - } -+ simple_map_init(&dnpc_map); - -- printk("FLASH virtual address: 0x%lx\n", dnpc_map.map_priv_1); -+ printk("FLASH virtual address: 0x%lx\n", dnpc_map.virt); - - mymtd = do_map_probe("jedec_probe", &dnpc_map); - -@@ -475,11 +430,11 @@ - mymtd->erasesize = 0x10000; - - if (!mymtd) { -- iounmap((void *)dnpc_map.map_priv_1); -+ iounmap((void *)dnpc_map.virt); - return -ENXIO; - } - -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - - /* - ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions() -@@ -525,10 +480,10 @@ - del_mtd_partitions(mymtd); - map_destroy(mymtd); - } -- if (dnpc_map.map_priv_1) { -- iounmap((void *)dnpc_map.map_priv_1); -+ if (dnpc_map.virt) { -+ iounmap((void *)dnpc_map.virt); - dnpc_unmap_flash(); -- dnpc_map.map_priv_1 = 0; -+ dnpc_map.virt = 0; - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ebony.c linux/drivers/mtd/maps/ebony.c ---- linux-mips-2.4.27/drivers/mtd/maps/ebony.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/ebony.c 2004-11-19 10:25:11.909198272 +0100 -@@ -0,0 +1,164 @@ -+/* -+ * $Id$ -+ * -+ * Mapping for Ebony user flash -+ * -+ * Matt Porter <mporter@mvista.com> -+ * -+ * Copyright 2002 MontaVista Software Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <linux/config.h> -+#include <asm/io.h> -+#include <asm/ibm440.h> -+#include <platforms/ebony.h> -+ -+static struct mtd_info *flash; -+ -+static struct map_info ebony_small_map = { -+ .name = "Ebony small flash", -+ .size = EBONY_SMALL_FLASH_SIZE, -+ .buswidth = 1, -+}; -+ -+static struct map_info ebony_large_map = { -+ .name = "Ebony large flash", -+ .size = EBONY_LARGE_FLASH_SIZE, -+ .buswidth = 1, -+}; -+ -+static struct mtd_partition ebony_small_partitions[] = { -+ { -+ .name = "OpenBIOS", -+ .offset = 0x0, -+ .size = 0x80000, -+ } -+}; -+ -+static struct mtd_partition ebony_large_partitions[] = { -+ { -+ .name = "fs", -+ .offset = 0, -+ .size = 0x380000, -+ }, -+ { -+ .name = "firmware", -+ .offset = 0x380000, -+ .size = 0x80000, -+ } -+}; -+ -+int __init init_ebony(void) -+{ -+ u8 fpga0_reg; -+ unsigned long fpga0_adr; -+ unsigned long long small_flash_base, large_flash_base; -+ -+ fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16); -+ if (!fpga0_adr) -+ return -ENOMEM; -+ -+ fpga0_reg = readb(fpga0_adr); -+ iounmap64(fpga0_adr); -+ -+ if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && -+ !EBONY_FLASH_SEL(fpga0_reg)) -+ small_flash_base = EBONY_SMALL_FLASH_HIGH2; -+ else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && -+ EBONY_FLASH_SEL(fpga0_reg)) -+ small_flash_base = EBONY_SMALL_FLASH_HIGH1; -+ else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) && -+ !EBONY_FLASH_SEL(fpga0_reg)) -+ small_flash_base = EBONY_SMALL_FLASH_LOW2; -+ else -+ small_flash_base = EBONY_SMALL_FLASH_LOW1; -+ -+ if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && -+ !EBONY_ONBRD_FLASH_EN(fpga0_reg)) -+ large_flash_base = EBONY_LARGE_FLASH_LOW; -+ else -+ large_flash_base = EBONY_LARGE_FLASH_HIGH; -+ -+ ebony_small_map.phys = small_flash_base; -+ ebony_small_map.virt = -+ (unsigned long)ioremap64(small_flash_base, -+ ebony_small_map.size); -+ -+ if (!ebony_small_map.virt) { -+ printk("Failed to ioremap flash\n"); -+ return -EIO; -+ } -+ -+ simple_map_init(&ebony_small_map); -+ -+ flash = do_map_probe("map_rom", &ebony_small_map); -+ if (flash) { -+ flash->owner = THIS_MODULE; -+ add_mtd_partitions(flash, ebony_small_partitions, -+ ARRAY_SIZE(ebony_small_partitions)); -+ } else { -+ printk("map probe failed for flash\n"); -+ return -ENXIO; -+ } -+ -+ ebony_large_map.phys = large_flash_base; -+ ebony_large_map.virt = -+ (unsigned long)ioremap64(large_flash_base, -+ ebony_large_map.size); -+ -+ if (!ebony_large_map.virt) { -+ printk("Failed to ioremap flash\n"); -+ return -EIO; -+ } -+ -+ simple_map_init(&ebony_large_map); -+ -+ flash = do_map_probe("cfi_probe", &ebony_large_map); -+ if (flash) { -+ flash->owner = THIS_MODULE; -+ add_mtd_partitions(flash, ebony_large_partitions, -+ ARRAY_SIZE(ebony_large_partitions)); -+ } else { -+ printk("map probe failed for flash\n"); -+ return -ENXIO; -+ } -+ -+ return 0; -+} -+ -+static void __exit cleanup_ebony(void) -+{ -+ if (flash) { -+ del_mtd_partitions(flash); -+ map_destroy(flash); -+ } -+ -+ if (ebony_small_map.virt) { -+ iounmap((void *)ebony_small_map.virt); -+ ebony_small_map.virt = 0; -+ } -+ -+ if (ebony_large_map.virt) { -+ iounmap((void *)ebony_large_map.virt); -+ ebony_large_map.virt = 0; -+ } -+} -+ -+module_init(init_ebony); -+module_exit(cleanup_ebony); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Matt Porter <mporter@mvista.com>"); -+MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/edb7312.c linux/drivers/mtd/maps/edb7312.c ---- linux-mips-2.4.27/drivers/mtd/maps/edb7312.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/edb7312.c 2004-11-19 10:25:11.910198120 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Handle mapping of the NOR flash on Cogent EDB7312 boards - * -@@ -13,6 +13,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -35,61 +36,11 @@ - - static struct mtd_info *mymtd; - --__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} -- - struct map_info edb7312nor_map = { -- name: "NOR flash on EDB7312", -- size: WINDOW_SIZE, -- buswidth: BUSWIDTH, -- read8: edb7312nor_read8, -- read16: edb7312nor_read16, -- read32: edb7312nor_read32, -- copy_from: edb7312nor_copy_from, -- write8: edb7312nor_write8, -- write16: edb7312nor_write16, -- write32: edb7312nor_write32, -- copy_to: edb7312nor_copy_to -+ .name = "NOR flash on EDB7312", -+ .size = WINDOW_SIZE, -+ .buswidth = BUSWIDTH, -+ .phys = WINDOW_ADDR, - }; - - #ifdef CONFIG_MTD_PARTITIONS -@@ -100,29 +51,23 @@ - static struct mtd_partition static_partitions[3] = - { - { -- name: "ARMboot", -- size: 0x40000, -- offset: 0 -+ .name = "ARMboot", -+ .size = 0x40000, -+ .offset = 0 - }, - { -- name: "Kernel", -- size: 0x200000, -- offset: 0x40000 -+ .name = "Kernel", -+ .size = 0x200000, -+ .offset = 0x40000 - }, - { -- name: "RootFS", -- size: 0xDC0000, -- offset: 0x240000 -+ .name = "RootFS", -+ .size = 0xDC0000, -+ .offset = 0x240000 - }, - }; - --#define NB_OF(x) (sizeof (x) / sizeof (x[0])) -- --#ifdef CONFIG_MTD_CMDLINE_PARTS --int parse_cmdline_partitions(struct mtd_info *master, -- struct mtd_partition **pparts, -- const char *mtd_id); --#endif -+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - - #endif - -@@ -137,32 +82,33 @@ - - printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", - WINDOW_SIZE, WINDOW_ADDR); -- edb7312nor_map.map_priv_1 = (unsigned long) -+ edb7312nor_map.virt = (unsigned long) - ioremap(WINDOW_ADDR, WINDOW_SIZE); - -- if (!edb7312nor_map.map_priv_1) { -+ if (!edb7312nor_map.virt) { - printk(MSG_PREFIX "failed to ioremap\n"); - return -EIO; - } - -+ simple_map_init(&edb7312nor_map); -+ - mymtd = 0; - type = rom_probe_types; - for(; !mymtd && *type; type++) { - mymtd = do_map_probe(*type, &edb7312nor_map); - } - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - - #ifdef CONFIG_MTD_PARTITIONS --#ifdef CONFIG_MTD_CMDLINE_PARTS -- mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID); -+ mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID); - if (mtd_parts_nb > 0) -- part_type = "command line"; --#endif -+ part_type = "detected"; -+ - if (mtd_parts_nb == 0) - { - mtd_parts = static_partitions; -- mtd_parts_nb = NB_OF(static_partitions); -+ mtd_parts_nb = ARRAY_SIZE(static_partitions); - part_type = "static"; - } - #endif -@@ -178,7 +124,7 @@ - return 0; - } - -- iounmap((void *)edb7312nor_map.map_priv_1); -+ iounmap((void *)edb7312nor_map.virt); - return -ENXIO; - } - -@@ -188,9 +134,9 @@ - del_mtd_device(mymtd); - map_destroy(mymtd); - } -- if (edb7312nor_map.map_priv_1) { -- iounmap((void *)edb7312nor_map.map_priv_1); -- edb7312nor_map.map_priv_1 = 0; -+ if (edb7312nor_map.virt) { -+ iounmap((void *)edb7312nor_map.virt); -+ edb7312nor_map.virt = 0; - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/elan-104nc.c linux/drivers/mtd/maps/elan-104nc.c ---- linux-mips-2.4.27/drivers/mtd/maps/elan-104nc.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/elan-104nc.c 2004-11-19 10:25:11.912197816 +0100 -@@ -16,7 +16,7 @@ - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - -- $Id$ -+ $Id$ - - The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 - mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. -@@ -40,6 +40,7 @@ - #include <asm/io.h> - - #include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> - #include <linux/mtd/partitions.h> - - #define WINDOW_START 0xb0000 -@@ -59,14 +60,14 @@ - * single flash device into. If the size if zero we use up to the end of the - * device. */ - static struct mtd_partition partition_info[]={ -- { name: "ELAN-104NC flash boot partition", -- offset: 0, -- size: 640*1024 }, -- { name: "ELAN-104NC flash partition 1", -- offset: 640*1024, -- size: 896*1024 }, -- { name: "ELAN-104NC flash partition 2", -- offset: (640+896)*1024 } -+ { .name = "ELAN-104NC flash boot partition", -+ .offset = 0, -+ .size = 640*1024 }, -+ { .name = "ELAN-104NC flash partition 1", -+ .offset = 640*1024, -+ .size = 896*1024 }, -+ { .name = "ELAN-104NC flash partition 2", -+ .offset = (640+896)*1024 } - }; - #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) - -@@ -195,19 +196,20 @@ - } - - static struct map_info elan_104nc_map = { -- name: "ELAN-104NC flash", -- size: 8*1024*1024, /* this must be set to a maximum possible amount -+ .name = "ELAN-104NC flash", -+ .phys = NO_XIP, -+ .size = 8*1024*1024, /* this must be set to a maximum possible amount - of flash so the cfi probe routines find all - the chips */ -- buswidth: 2, -- read8: elan_104nc_read8, -- read16: elan_104nc_read16, -- read32: elan_104nc_read32, -- copy_from: elan_104nc_copy_from, -- write8: elan_104nc_write8, -- write16: elan_104nc_write16, -- write32: elan_104nc_write32, -- copy_to: elan_104nc_copy_to -+ .buswidth = 2, -+ .read8 = elan_104nc_read8, -+ .read16 = elan_104nc_read16, -+ .read32 = elan_104nc_read32, -+ .copy_from = elan_104nc_copy_from, -+ .write8 = elan_104nc_write8, -+ .write16 = elan_104nc_write16, -+ .write32 = elan_104nc_write32, -+ .copy_to = elan_104nc_copy_to - }; - - /* MTD device for all of the flash. */ -@@ -221,20 +223,13 @@ - } - - iounmap((void *)iomapadr); -- release_region(PAGE_IO,PAGE_IO_SIZE); - } - - int __init init_elan_104nc(void) - { -- /* Urg! We use I/O port 0x22 without request_region()ing it */ -- /* -- if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) { -- printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", -- elan_104nc_map.name, -- PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); -- return -EAGAIN; -- } -- */ -+ /* Urg! We use I/O port 0x22 without request_region()ing it, -+ because it's already allocated to the PIC. */ -+ - iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); - if (!iomapadr) { - printk( KERN_ERR"%s: failed to ioremap memory region\n", -@@ -242,10 +237,6 @@ - return -EIO; - } - -- /* -- request_region( PAGE_IO, PAGE_IO_SIZE, "ELAN-104NC flash" ); -- */ -- - printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", - elan_104nc_map.name, - PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1, -@@ -260,7 +251,7 @@ - return -ENXIO; - } - -- all_mtd->module=THIS_MODULE; -+ all_mtd->owner = THIS_MODULE; - - /* Create MTD devices for each partition. */ - add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS ); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/epxa10db-flash.c linux/drivers/mtd/maps/epxa10db-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/epxa10db-flash.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/epxa10db-flash.c 2004-11-19 10:25:11.913197664 +0100 -@@ -5,7 +5,7 @@ - * Copyright (C) 2001 Altera Corporation - * Copyright (C) 2001 Red Hat, Inc. - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -26,6 +26,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -43,87 +44,38 @@ - - static struct mtd_info *mymtd; - --extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); - static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); - --static __u8 epxa_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --static __u16 epxa_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --static __u32 epxa_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); --} -- --static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio((void *)(map->map_priv_1 + to), from, len); --} -- -- - - static struct map_info epxa_map = { -- name: "EPXA flash", -- size: FLASH_SIZE, -- buswidth: 2, -- read8: epxa_read8, -- read16: epxa_read16, -- read32: epxa_read32, -- copy_from: epxa_copy_from, -- write8: epxa_write8, -- write16: epxa_write16, -- write32: epxa_write32, -- copy_to: epxa_copy_to -+ .name = "EPXA flash", -+ .size = FLASH_SIZE, -+ .buswidth = 2, -+ .phys = FLASH_START, - }; - -+static const char *probes[] = { "RedBoot", "afs", NULL }; - - static int __init epxa_mtd_init(void) - { - int i; - -- printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); -- epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); -- if (!epxa_map.map_priv_1) { -+ printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); -+ -+ epxa_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); -+ if (!epxa_map.virt) { - printk("Failed to ioremap %s flash\n",BOARD_NAME); - return -EIO; - } -+ simple_map_init(&epxa_map); - - mymtd = do_map_probe("cfi_probe", &epxa_map); - if (!mymtd) { -- iounmap((void *)epxa_map.map_priv_1); -+ iounmap((void *)epxa_map.virt); - return -ENXIO; - } - -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - - /* Unlock the flash device. */ - if(mymtd->unlock){ -@@ -135,23 +87,14 @@ - } - } - --#ifdef CONFIG_MTD_REDBOOT_PARTS -- nr_parts = parse_redboot_partitions(mymtd, &parts); -- -- if (nr_parts > 0) { -- add_mtd_partitions(mymtd, parts, nr_parts); -- return 0; -- } --#endif --#ifdef CONFIG_MTD_AFS_PARTS -- nr_parts = parse_afs_partitions(mymtd, &parts); -+#ifdef CONFIG_MTD_PARTITIONS -+ nr_parts = parse_mtd_partitions(mymtd, probes, &parts, 0); - - if (nr_parts > 0) { - add_mtd_partitions(mymtd, parts, nr_parts); - return 0; - } - #endif -- - /* No recognised partitioning schemes found - use defaults */ - nr_parts = epxa_default_partitions(mymtd, &parts); - if (nr_parts > 0) { -@@ -173,9 +116,9 @@ - del_mtd_device(mymtd); - map_destroy(mymtd); - } -- if (epxa_map.map_priv_1) { -- iounmap((void *)epxa_map.map_priv_1); -- epxa_map.map_priv_1 = 0; -+ if (epxa_map.virt) { -+ iounmap((void *)epxa_map.virt); -+ epxa_map.virt = 0; - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/fortunet.c linux/drivers/mtd/maps/fortunet.c ---- linux-mips-2.4.27/drivers/mtd/maps/fortunet.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/fortunet.c 2004-11-19 10:25:11.915197360 +0100 -@@ -1,11 +1,12 @@ - /* fortunet.c memory map - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -23,7 +24,7 @@ - - struct map_region - { -- int window_addr_phyical; -+ int window_addr_physical; - int altbuswidth; - struct map_info map_info; - struct mtd_info *mymtd; -@@ -37,57 +38,10 @@ - static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0}; - - --__u8 fortunet_read8(struct map_info *map, unsigned long ofs) --{ -- return *(__u8 *)(map->map_priv_1 + ofs); --} -- --__u16 fortunet_read16(struct map_info *map, unsigned long ofs) --{ -- return *(__u16 *)(map->map_priv_1 + ofs); --} -- --__u32 fortunet_read32(struct map_info *map, unsigned long ofs) --{ -- return *(__u32 *)(map->map_priv_1 + ofs); --} -- --void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy(to, (void *)(map->map_priv_1 + from), len); --} -- --void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- *(__u8 *)(map->map_priv_1 + adr) = d; --} -- --void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- *(__u16 *)(map->map_priv_1 + adr) = d; --} -- --void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- *(__u32 *)(map->map_priv_1 + adr) = d; --} -- --void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy((void *)(map->map_priv_1 + to), from, len); --} - - struct map_info default_map = { -- size: DEF_WINDOW_SIZE, -- buswidth: 4, -- read8: fortunet_read8, -- read16: fortunet_read16, -- read32: fortunet_read32, -- copy_from: fortunet_copy_from, -- write8: fortunet_write8, -- write16: fortunet_write16, -- write32: fortunet_write32, -- copy_to: fortunet_copy_to -+ .size = DEF_WINDOW_SIZE, -+ .buswidth = 4, - }; - - static char * __init get_string_option(char *dest,int dest_size,char *sor) -@@ -147,7 +101,7 @@ - get_options (get_string_option(string,sizeof(string),line),6,params); - if(params[0]<1) - { -- printk(MTD_FORTUNET_PK "Bad paramters for MTD Region " -+ printk(MTD_FORTUNET_PK "Bad parameters for MTD Region " - " name,region-number[,base,size,buswidth,altbuswidth]\n"); - return 1; - } -@@ -161,14 +115,14 @@ - memcpy(&map_regions[params[1]].map_info, - &default_map,sizeof(map_regions[params[1]].map_info)); - map_regions_set[params[1]] = 1; -- map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY; -+ map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY; - map_regions[params[1]].altbuswidth = 2; - map_regions[params[1]].mymtd = NULL; - map_regions[params[1]].map_info.name = map_regions[params[1]].map_name; - strcpy(map_regions[params[1]].map_info.name,string); - if(params[0]>1) - { -- map_regions[params[1]].window_addr_phyical = params[2]; -+ map_regions[params[1]].window_addr_physical = params[2]; - } - if(params[0]>2) - { -@@ -185,14 +139,14 @@ - return 1; - } - --static int __init MTD_New_Partion(char *line) -+static int __init MTD_New_Partition(char *line) - { - char string[MAX_NAME_SIZE]; - int params[4]; - get_options (get_string_option(string,sizeof(string),line),4,params); - if(params[0]<3) - { -- printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion " -+ printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition " - " name,region-number,size,offset\n"); - return 1; - } -@@ -204,7 +158,7 @@ - } - if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS) - { -- printk(MTD_FORTUNET_PK "Out of space for partion in this region\n"); -+ printk(MTD_FORTUNET_PK "Out of space for partition in this region\n"); - return 1; - } - map_regions[params[1]].parts[map_regions_parts[params[1]]].name = -@@ -220,7 +174,10 @@ - } - - __setup("MTD_Region=", MTD_New_Region); --__setup("MTD_Partion=", MTD_New_Partion); -+__setup("MTD_Partition=", MTD_New_Partition); -+ -+/* Backwards-spelling-compatibility */ -+__setup("MTD_Partion=", MTD_New_Partition); - - int __init init_fortunet(void) - { -@@ -229,13 +186,13 @@ - { - if(map_regions_parts[ix]&&(!map_regions_set[ix])) - { -- printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n", -+ printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n", - ix); - memset(&map_regions[ix],0,sizeof(map_regions[ix])); - memcpy(&map_regions[ix].map_info,&default_map, - sizeof(map_regions[ix].map_info)); - map_regions_set[ix] = 1; -- map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY; -+ map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY; - map_regions[ix].altbuswidth = 2; - map_regions[ix].mymtd = NULL; - map_regions[ix].map_info.name = map_regions[ix].map_name; -@@ -244,30 +201,35 @@ - if(map_regions_set[ix]) - { - iy++; -- printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly " -+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically " - " address %x size %x\n", - map_regions[ix].map_info.name, -- map_regions[ix].window_addr_phyical, -+ map_regions[ix].window_addr_physical, - map_regions[ix].map_info.size); -- map_regions[ix].map_info.map_priv_1 = -+ -+ map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, -+ -+ map_regions[ix].map_info.virt = - (int)ioremap_nocache( -- map_regions[ix].window_addr_phyical, -+ map_regions[ix].window_addr_physical, - map_regions[ix].map_info.size); -- if(!map_regions[ix].map_info.map_priv_1) -+ if(!map_regions[ix].map_info.virt) - { - printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n", - map_regions[ix].map_info.name); - return -ENXIO; - } -- printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n", -+ simple_map_init(&map_regions[ix].map_info); -+ -+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n", - map_regions[ix].map_info.name, -- map_regions[ix].map_info.map_priv_1); -+ map_regions[ix].map_info.virt); - map_regions[ix].mymtd = do_map_probe("cfi_probe", - &map_regions[ix].map_info); - if((!map_regions[ix].mymtd)&&( - map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth)) - { -- printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth " -+ printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate buswidth " - "for %s flash.\n", - map_regions[ix].map_info.name); - map_regions[ix].map_info.buswidth = -@@ -275,7 +237,7 @@ - map_regions[ix].mymtd = do_map_probe("cfi_probe", - &map_regions[ix].map_info); - } -- map_regions[ix].mymtd->module = THIS_MODULE; -+ map_regions[ix].mymtd->owner = THIS_MODULE; - add_mtd_partitions(map_regions[ix].mymtd, - map_regions[ix].parts,map_regions_parts[ix]); - } -@@ -297,7 +259,7 @@ - del_mtd_partitions( map_regions[ix].mymtd ); - map_destroy( map_regions[ix].mymtd ); - } -- iounmap((void *)map_regions[ix].map_info.map_priv_1); -+ iounmap((void *)map_regions[ix].map_info.virt); - } - } - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/h720x-flash.c linux/drivers/mtd/maps/h720x-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/h720x-flash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/h720x-flash.c 2004-11-19 10:25:11.917197056 +0100 -@@ -0,0 +1,142 @@ -+/* -+ * Flash memory access on Hynix GMS30C7201/HMS30C7202 based -+ * evaluation boards -+ * -+ * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> -+ * 2003 Thomas Gleixner <tglx@linutronix.de> -+*/ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/errno.h> -+#include <linux/slab.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <asm/hardware.h> -+#include <asm/io.h> -+ -+static struct mtd_info *mymtd; -+ -+static struct map_info h720x_map = { -+ .name = "H720X", -+ .buswidth = 4, -+ .size = FLASH_SIZE, -+ .phys = FLASH_PHYS, -+}; -+ -+static struct mtd_partition h720x_partitions[] = { -+ { -+ .name = "ArMon", -+ .size = 0x00080000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE -+ },{ -+ .name = "Env", -+ .size = 0x00040000, -+ .offset = 0x00080000, -+ .mask_flags = MTD_WRITEABLE -+ },{ -+ .name = "Kernel", -+ .size = 0x00180000, -+ .offset = 0x000c0000, -+ .mask_flags = MTD_WRITEABLE -+ },{ -+ .name = "Ramdisk", -+ .size = 0x00400000, -+ .offset = 0x00240000, -+ .mask_flags = MTD_WRITEABLE -+ },{ -+ .name = "jffs2", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND -+ } -+}; -+ -+#define NUM_PARTITIONS (sizeof(h720x_partitions)/sizeof(h720x_partitions[0])) -+ -+static int nr_mtd_parts; -+static struct mtd_partition *mtd_parts; -+static const char *probes[] = { "cmdlinepart", NULL }; -+ -+/* -+ * Initialize FLASH support -+ */ -+int __init h720x_mtd_init(void) -+{ -+ -+ char *part_type = NULL; -+ -+ h720x_map.virt = (unsigned long)ioremap(FLASH_PHYS, FLASH_SIZE); -+ -+ if (!h720x_map.virt) { -+ printk(KERN_ERR "H720x-MTD: ioremap failed\n"); -+ return -EIO; -+ } -+ -+ simple_map_init(&h720x_map); -+ -+ // Probe for flash buswidth 4 -+ printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n"); -+ mymtd = do_map_probe("cfi_probe", &h720x_map); -+ if (!mymtd) { -+ printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n"); -+ // Probe for buswidth 2 -+ h720x_map.buswidth = 2; -+ mymtd = do_map_probe("cfi_probe", &h720x_map); -+ } -+ -+ if (mymtd) { -+ mymtd->owner = THIS_MODULE; -+ -+#ifdef CONFIG_MTD_PARTITIONS -+ nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); -+ if (nr_mtd_parts > 0) -+ part_type = "command line"; -+#endif -+ if (nr_mtd_parts <= 0) { -+ mtd_parts = h720x_partitions; -+ nr_mtd_parts = NUM_PARTITIONS; -+ part_type = "builtin"; -+ } -+ printk(KERN_INFO "Using %s partition table\n", part_type); -+ add_mtd_partitions(mymtd, mtd_parts, nr_mtd_parts); -+ return 0; -+ } -+ -+ iounmap((void *)h720x_map.virt); -+ return -ENXIO; -+} -+ -+/* -+ * Cleanup -+ */ -+static void __exit h720x_mtd_cleanup(void) -+{ -+ -+ if (mymtd) { -+ del_mtd_partitions(mymtd); -+ map_destroy(mymtd); -+ } -+ -+ /* Free partition info, if commandline partition was used */ -+ if (mtd_parts && (mtd_parts != h720x_partitions)) -+ kfree (mtd_parts); -+ -+ if (h720x_map.virt) { -+ iounmap((void *)h720x_map.virt); -+ h720x_map.virt = 0; -+ } -+} -+ -+ -+module_init(h720x_mtd_init); -+module_exit(h720x_mtd_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); -+MODULE_DESCRIPTION("MTD map driver for Hynix evaluation boards"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ichxrom.c linux/drivers/mtd/maps/ichxrom.c ---- linux-mips-2.4.27/drivers/mtd/maps/ichxrom.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/ichxrom.c 2004-11-19 10:25:11.918196904 +0100 -@@ -0,0 +1,380 @@ -+/* -+ * ichxrom.c -+ * -+ * Normal mappings of chips in physical memory -+ * $Id$ -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <asm/io.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/config.h> -+#include <linux/pci.h> -+#include <linux/pci_ids.h> -+ -+#define xstr(s) str(s) -+#define str(s) #s -+#define MOD_NAME xstr(KBUILD_BASENAME) -+ -+#define MTD_DEV_NAME_LENGTH 16 -+ -+#define RESERVE_MEM_REGION 0 -+ -+#define ICHX_FWH_REGION_START 0xFF000000UL -+#define ICHX_FWH_REGION_SIZE 0x01000000UL -+#define BIOS_CNTL 0x4e -+#define FWH_DEC_EN1 0xE3 -+#define FWH_DEC_EN2 0xF0 -+#define FWH_SEL1 0xE8 -+#define FWH_SEL2 0xEE -+ -+struct ichxrom_map_info { -+ struct map_info map; -+ struct mtd_info *mtd; -+ unsigned long window_addr; -+ struct pci_dev *pdev; -+ struct resource window_rsrc; -+ struct resource rom_rsrc; -+ char mtd_name[MTD_DEV_NAME_LENGTH]; -+}; -+ -+static inline unsigned long addr(struct map_info *map, unsigned long ofs) -+{ -+ unsigned long offset; -+ offset = ((8*1024*1024) - map->size) + ofs; -+ if (offset >= (4*1024*1024)) { -+ offset += 0x400000; -+ } -+ return map->map_priv_1 + 0x400000 + offset; -+} -+ -+static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr) -+{ -+ return addr - map->map_priv_1 + ICHX_FWH_REGION_START; -+} -+ -+static __u8 ichxrom_read8(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readb(addr(map, ofs)); -+} -+ -+static __u16 ichxrom_read16(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readw(addr(map, ofs)); -+} -+ -+static __u32 ichxrom_read32(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readl(addr(map, ofs)); -+} -+ -+static void ichxrom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -+{ -+ memcpy_fromio(to, addr(map, from), len); -+} -+ -+static void ichxrom_write8(struct map_info *map, __u8 d, unsigned long ofs) -+{ -+ __raw_writeb(d, addr(map,ofs)); -+ mb(); -+} -+ -+static void ichxrom_write16(struct map_info *map, __u16 d, unsigned long ofs) -+{ -+ __raw_writew(d, addr(map, ofs)); -+ mb(); -+} -+ -+static void ichxrom_write32(struct map_info *map, __u32 d, unsigned long ofs) -+{ -+ __raw_writel(d, addr(map, ofs)); -+ mb(); -+} -+ -+static void ichxrom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -+{ -+ memcpy_toio(addr(map, to), from, len); -+} -+ -+static struct ichxrom_map_info ichxrom_map = { -+ .map = { -+ .name = MOD_NAME, -+ .phys = NO_XIP, -+ .size = 0, -+ .buswidth = 1, -+ .read8 = ichxrom_read8, -+ .read16 = ichxrom_read16, -+ .read32 = ichxrom_read32, -+ .copy_from = ichxrom_copy_from, -+ .write8 = ichxrom_write8, -+ .write16 = ichxrom_write16, -+ .write32 = ichxrom_write32, -+ .copy_to = ichxrom_copy_to, -+ /* Firmware hubs only use vpp when being programmed -+ * in a factory setting. So in-place programming -+ * needs to use a different method. -+ */ -+ }, -+ /* remaining fields of structure are initialized to 0 */ -+}; -+ -+enum fwh_lock_state { -+ FWH_DENY_WRITE = 1, -+ FWH_IMMUTABLE = 2, -+ FWH_DENY_READ = 4, -+}; -+ -+static void ichxrom_cleanup(struct ichxrom_map_info *info) -+{ -+ u16 word; -+ -+ /* Disable writes through the rom window */ -+ pci_read_config_word(info->pdev, BIOS_CNTL, &word); -+ pci_write_config_word(info->pdev, BIOS_CNTL, word & ~1); -+ -+ if (info->mtd) { -+ del_mtd_device(info->mtd); -+ map_destroy(info->mtd); -+ info->mtd = NULL; -+ info->map.virt = 0; -+ } -+ if (info->rom_rsrc.parent) -+ release_resource(&info->rom_rsrc); -+ if (info->window_rsrc.parent) -+ release_resource(&info->window_rsrc); -+ -+ if (info->window_addr) { -+ iounmap((void *)(info->window_addr)); -+ info->window_addr = 0; -+ } -+} -+ -+ -+static int ichxrom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len, -+ enum fwh_lock_state state) -+{ -+ struct map_info *map = mtd->priv; -+ unsigned long start = ofs; -+ unsigned long end = start + len -1; -+ -+ /* FIXME do I need to guard against concurrency here? */ -+ /* round down to 64K boundaries */ -+ start = start & ~0xFFFF; -+ end = end & ~0xFFFF; -+ while (start <= end) { -+ unsigned long ctrl_addr; -+ ctrl_addr = addr(map, start) - 0x400000 + 2; -+ writeb(state, ctrl_addr); -+ start = start + 0x10000; -+ } -+ return 0; -+} -+ -+static int ichxrom_lock(struct mtd_info *mtd, loff_t ofs, size_t len) -+{ -+ return ichxrom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE); -+} -+ -+static int ichxrom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) -+{ -+ return ichxrom_set_lock_state(mtd, ofs, len, 0); -+} -+ -+static int __devinit ichxrom_init_one (struct pci_dev *pdev, -+ const struct pci_device_id *ent) -+{ -+ u16 word; -+ struct ichxrom_map_info *info = &ichxrom_map; -+ unsigned long map_size; -+ -+ /* For now I just handle the ichx and I assume there -+ * are not a lot of resources up at the top of the address -+ * space. It is possible to handle other devices in the -+ * top 16MB but it is very painful. Also since -+ * you can only really attach a FWH to an ICHX there -+ * a number of simplifications you can make. -+ * -+ * Also you can page firmware hubs if an 8MB window isn't enough -+ * but don't currently handle that case either. -+ */ -+ -+ info->pdev = pdev; -+ -+ /* -+ * Try to reserve the window mem region. If this fails then -+ * it is likely due to the window being "reseved" by the BIOS. -+ */ -+ info->window_rsrc.name = MOD_NAME; -+ info->window_rsrc.start = ICHX_FWH_REGION_START; -+ info->window_rsrc.end = ICHX_FWH_REGION_START + ICHX_FWH_REGION_SIZE - 1; -+ info->window_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; -+ if (request_resource(&iomem_resource, &info->window_rsrc)) { -+ info->window_rsrc.parent = NULL; -+ printk(KERN_ERR MOD_NAME -+ " %s(): Unable to register resource" -+ " 0x%.08lx-0x%.08lx - kernel bug?\n", -+ __func__, -+ info->window_rsrc.start, info->window_rsrc.end); -+ } -+ -+ /* Enable writes through the rom window */ -+ pci_read_config_word(pdev, BIOS_CNTL, &word); -+ if (!(word & 1) && (word & (1<<1))) { -+ /* The BIOS will generate an error if I enable -+ * this device, so don't even try. -+ */ -+ printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n"); -+ goto failed; -+ } -+ pci_write_config_word(pdev, BIOS_CNTL, word | 1); -+ -+ -+ /* Map the firmware hub into my address space. */ -+ /* Does this use too much virtual address space? */ -+ info->window_addr = (unsigned long)ioremap( -+ ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE); -+ if (!info->window_addr) { -+ printk(KERN_ERR "Failed to ioremap\n"); -+ goto failed; -+ } -+ -+ /* For now assume the firmware has setup all relevant firmware -+ * windows. We don't have enough information to handle this case -+ * intelligently. -+ */ -+ -+ /* FIXME select the firmware hub and enable a window to it. */ -+ -+ info->mtd = 0; -+ info->map.map_priv_1 = info->window_addr; -+ -+ map_size = ICHX_FWH_REGION_SIZE; -+ while(!info->mtd && (map_size > 0)) { -+ info->map.size = map_size; -+ info->mtd = do_map_probe("jedec_probe", &ichxrom_map.map); -+ map_size -= 512*1024; -+ } -+ if (!info->mtd) { -+ goto failed; -+ } -+ /* I know I can only be a firmware hub here so put -+ * in the special lock and unlock routines. -+ */ -+ info->mtd->lock = ichxrom_lock; -+ info->mtd->unlock = ichxrom_unlock; -+ -+ info->mtd->owner = THIS_MODULE; -+ add_mtd_device(info->mtd); -+ -+ if (info->window_rsrc.parent) { -+ /* -+ * Registering the MTD device in iomem may not be possible -+ * if there is a BIOS "reserved" and BUSY range. If this -+ * fails then continue anyway. -+ */ -+ snprintf(info->mtd_name, MTD_DEV_NAME_LENGTH, -+ "mtd%d", info->mtd->index); -+ -+ info->rom_rsrc.name = info->mtd_name; -+ info->rom_rsrc.start = ICHX_FWH_REGION_START -+ + ICHX_FWH_REGION_SIZE - map_size; -+ info->rom_rsrc.end = ICHX_FWH_REGION_START -+ + ICHX_FWH_REGION_SIZE; -+ info->rom_rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY; -+ if (request_resource(&info->window_rsrc, &info->rom_rsrc)) { -+ printk(KERN_ERR MOD_NAME -+ ": cannot reserve MTD resource\n"); -+ info->rom_rsrc.parent = NULL; -+ } -+ } -+ -+ return 0; -+ -+ failed: -+ ichxrom_cleanup(info); -+ return -ENODEV; -+} -+ -+ -+static void __devexit ichxrom_remove_one (struct pci_dev *pdev) -+{ -+ struct ichxrom_map_info *info = &ichxrom_map; -+ u16 word; -+ -+ del_mtd_device(info->mtd); -+ map_destroy(info->mtd); -+ info->mtd = 0; -+ info->map.map_priv_1 = 0; -+ -+ iounmap((void *)(info->window_addr)); -+ info->window_addr = 0; -+ -+ /* Disable writes through the rom window */ -+ pci_read_config_word(pdev, BIOS_CNTL, &word); -+ pci_write_config_word(pdev, BIOS_CNTL, word & ~1); -+ -+#if RESERVE_MEM_REGION -+ release_mem_region(ICHX_FWH_REGION_START, ICHX_FWH_REGION_SIZE); -+#endif -+} -+ -+static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = { -+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, -+ PCI_ANY_ID, PCI_ANY_ID, }, -+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, -+ PCI_ANY_ID, PCI_ANY_ID, }, -+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, -+ PCI_ANY_ID, PCI_ANY_ID, }, -+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, -+ PCI_ANY_ID, PCI_ANY_ID, }, -+ { 0, }, -+}; -+ -+MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl); -+ -+#if 0 -+static struct pci_driver ichxrom_driver = { -+ .name = MOD_NAME, -+ .id_table = ichxrom_pci_tbl, -+ .probe = ichxrom_init_one, -+ .remove = ichxrom_remove_one, -+}; -+#endif -+ -+static struct pci_dev *mydev; -+int __init init_ichxrom(void) -+{ -+ struct pci_dev *pdev; -+ struct pci_device_id *id; -+ pdev = 0; -+ for(id = ichxrom_pci_tbl; id->vendor; id++) { -+ pdev = pci_find_device(id->vendor, id->device, 0); -+ if (pdev) { -+ break; -+ } -+ } -+ if (pdev) { -+ mydev = pdev; -+ return ichxrom_init_one(pdev, &ichxrom_pci_tbl[0]); -+ } -+ return -ENXIO; -+#if 0 -+ return pci_module_init(&ichxrom_driver); -+#endif -+} -+ -+static void __exit cleanup_ichxrom(void) -+{ -+ ichxrom_remove_one(mydev); -+} -+ -+module_init(init_ichxrom); -+module_exit(cleanup_ichxrom); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>"); -+MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICHX southbridge"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/impa7.c linux/drivers/mtd/maps/impa7.c ---- linux-mips-2.4.27/drivers/mtd/maps/impa7.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/impa7.c 2004-11-19 10:25:11.920196600 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Handle mapping of the NOR flash on implementa A7 boards - * -@@ -13,6 +13,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -37,75 +38,17 @@ - - static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 }; - --__u8 impa7_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 impa7_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 impa7_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void impa7_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void impa7_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void impa7_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} - - static struct map_info impa7_map[NUM_FLASHBANKS] = { - { -- name: "impA7 NOR Flash Bank #0", -- size: WINDOW_SIZE0, -- buswidth: BUSWIDTH, -- read8: impa7_read8, -- read16: impa7_read16, -- read32: impa7_read32, -- copy_from: impa7_copy_from, -- write8: impa7_write8, -- write16: impa7_write16, -- write32: impa7_write32, -- copy_to: impa7_copy_to -+ .name = "impA7 NOR Flash Bank #0", -+ .size = WINDOW_SIZE0, -+ .buswidth = BUSWIDTH, - }, - { -- name: "impA7 NOR Flash Bank #1", -- size: WINDOW_SIZE1, -- buswidth: BUSWIDTH, -- read8: impa7_read8, -- read16: impa7_read16, -- read32: impa7_read32, -- copy_from: impa7_copy_from, -- write8: impa7_write8, -- write16: impa7_write16, -- write32: impa7_write32, -- copy_to: impa7_copy_to -+ .name = "impA7 NOR Flash Bank #1", -+ .size = WINDOW_SIZE1, -+ .buswidth = BUSWIDTH, - }, - }; - -@@ -117,24 +60,18 @@ - static struct mtd_partition static_partitions[] = - { - { -- name: "FileSystem", -- size: 0x800000, -- offset: 0x00000000 -+ .name = "FileSystem", -+ .size = 0x800000, -+ .offset = 0x00000000 - }, - }; - --#define NB_OF(x) (sizeof (x) / sizeof (x[0])) -+static int mtd_parts_nb[NUM_FLASHBANKS]; -+static struct mtd_partition *mtd_parts[NUM_FLASHBANKS]; - --#ifdef CONFIG_MTD_CMDLINE_PARTS --int parse_cmdline_partitions(struct mtd_info *master, -- struct mtd_partition **pparts, -- const char *mtd_id); - #endif - --#endif -- --static int mtd_parts_nb = 0; --static struct mtd_partition *mtd_parts = 0; -+static const char *probes[] = { "cmdlinepart", NULL }; - - int __init init_impa7(void) - { -@@ -146,20 +83,21 @@ - { WINDOW_ADDR0, WINDOW_SIZE0 }, - { WINDOW_ADDR1, WINDOW_SIZE1 }, - }; -- char mtdid[10]; - int devicesfound = 0; - - for(i=0; i<NUM_FLASHBANKS; i++) - { - printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n", - pt[i].size, pt[i].addr); -- impa7_map[i].map_priv_1 = (unsigned long) -- ioremap(pt[i].addr, pt[i].size); - -- if (!impa7_map[i].map_priv_1) { -+ impa7_map[i].phys = pt[i].addr; -+ impa7_map[i].virt = (unsigned long) -+ ioremap(pt[i].addr, pt[i].size); -+ if (!impa7_map[i].virt) { - printk(MSG_PREFIX "failed to ioremap\n"); - return -EIO; - } -+ simple_map_init(&impa7_map[i]); - - impa7_mtd[i] = 0; - type = rom_probe_types; -@@ -167,43 +105,34 @@ - impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]); - } - -- if (impa7_mtd[i]) -- { -- impa7_mtd[i]->module = THIS_MODULE; -- add_mtd_device(impa7_mtd[i]); -+ if (impa7_mtd[i]) { -+ impa7_mtd[i]->owner = THIS_MODULE; - devicesfound++; - #ifdef CONFIG_MTD_PARTITIONS --#ifdef CONFIG_MTD_CMDLINE_PARTS -- sprintf(mtdid, MTDID, i); -- mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i], -- &mtd_parts, -- mtdid); -- if (mtd_parts_nb > 0) -+ mtd_parts_nb[i] = parse_mtd_partitions(impa7_mtd[i], -+ probes, -+ &mtd_parts[i], -+ 0); -+ if (mtd_parts_nb[i] > 0) { - part_type = "command line"; --#endif -- if (mtd_parts_nb <= 0) -- { -- mtd_parts = static_partitions; -- mtd_parts_nb = NB_OF(static_partitions); -+ } else { -+ mtd_parts[i] = static_partitions; -+ mtd_parts_nb[i] = ARRAY_SIZE(static_partitions); - part_type = "static"; - } -- if (mtd_parts_nb <= 0) -- { -- printk(KERN_NOTICE MSG_PREFIX -- "no partition info available\n"); -- } -- else -- { -+ - printk(KERN_NOTICE MSG_PREFIX - "using %s partition definition\n", - part_type); - add_mtd_partitions(impa7_mtd[i], -- mtd_parts, mtd_parts_nb); -- } -+ mtd_parts[i], mtd_parts_nb[i]); -+#else -+ add_mtd_device(impa7_mtd[i]); -+ - #endif - } - else -- iounmap((void *)impa7_map[i].map_priv_1); -+ iounmap((void *)impa7_map[i].virt); - } - return devicesfound == 0 ? -ENXIO : 0; - } -@@ -211,17 +140,16 @@ - static void __exit cleanup_impa7(void) - { - int i; -- for (i=0; i<NUM_FLASHBANKS; i++) -- { -- if (impa7_mtd[i]) -- { -+ for (i=0; i<NUM_FLASHBANKS; i++) { -+ if (impa7_mtd[i]) { -+#ifdef CONFIG_MTD_PARTITIONS -+ del_mtd_partitions(impa7_mtd[i]); -+#else - del_mtd_device(impa7_mtd[i]); -+#endif - map_destroy(impa7_mtd[i]); -- } -- if (impa7_map[i].map_priv_1) -- { -- iounmap((void *)impa7_map[i].map_priv_1); -- impa7_map[i].map_priv_1 = 0; -+ iounmap((void *)impa7_map[i].virt); -+ impa7_map[i].virt = 0; - } - } - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/integrator-flash-v24.c linux/drivers/mtd/maps/integrator-flash-v24.c ---- linux-mips-2.4.27/drivers/mtd/maps/integrator-flash-v24.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/integrator-flash-v24.c 2004-11-19 10:25:11.921196448 +0100 -@@ -0,0 +1,258 @@ -+/*====================================================================== -+ -+ drivers/mtd/maps/armflash.c: ARM Flash Layout/Partitioning -+ -+ Copyright (C) 2000 ARM Limited -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ This is access code for flashes using ARM's flash partitioning -+ standards. -+ -+ $Id$ -+ -+======================================================================*/ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/ioport.h> -+#include <linux/init.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+ -+#include <asm/hardware.h> -+#include <asm/io.h> -+#include <asm/system.h> -+ -+// board specific stuff - sorry, it should be in arch/arm/mach-*. -+#ifdef CONFIG_ARCH_INTEGRATOR -+ -+#define FLASH_BASE INTEGRATOR_FLASH_BASE -+#define FLASH_SIZE INTEGRATOR_FLASH_SIZE -+ -+#define FLASH_PART_SIZE 0x400000 -+ -+#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) -+#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) -+#define EBI_CSR1 (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET) -+#define EBI_LOCK (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET) -+ -+/* -+ * Initialise the flash access systems: -+ * - Disable VPP -+ * - Assert WP -+ * - Set write enable bit in EBI reg -+ */ -+static void armflash_flash_init(void) -+{ -+ unsigned int tmp; -+ -+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); -+ -+ tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE; -+ __raw_writel(tmp, EBI_CSR1); -+ -+ if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) { -+ __raw_writel(0xa05f, EBI_LOCK); -+ __raw_writel(tmp, EBI_CSR1); -+ __raw_writel(0, EBI_LOCK); -+ } -+} -+ -+/* -+ * Shutdown the flash access systems: -+ * - Disable VPP -+ * - Assert WP -+ * - Clear write enable bit in EBI reg -+ */ -+static void armflash_flash_exit(void) -+{ -+ unsigned int tmp; -+ -+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); -+ -+ /* -+ * Clear the write enable bit in system controller EBI register. -+ */ -+ tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE; -+ __raw_writel(tmp, EBI_CSR1); -+ -+ if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) { -+ __raw_writel(0xa05f, EBI_LOCK); -+ __raw_writel(tmp, EBI_CSR1); -+ __raw_writel(0, EBI_LOCK); -+ } -+} -+ -+static void armflash_flash_wp(int on) -+{ -+ unsigned int reg; -+ -+ if (on) -+ reg = SC_CTRLC; -+ else -+ reg = SC_CTRLS; -+ -+ __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg); -+} -+ -+static void armflash_set_vpp(struct map_info *map, int on) -+{ -+ unsigned int reg; -+ -+ if (on) -+ reg = SC_CTRLS; -+ else -+ reg = SC_CTRLC; -+ -+ __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg); -+} -+#endif -+ -+#ifdef CONFIG_ARCH_P720T -+ -+#define FLASH_BASE (0x04000000) -+#define FLASH_SIZE (64*1024*1024) -+ -+#define FLASH_PART_SIZE (4*1024*1024) -+#define FLASH_BLOCK_SIZE (128*1024) -+ -+static void armflash_flash_init(void) -+{ -+} -+ -+static void armflash_flash_exit(void) -+{ -+} -+ -+static void armflash_flash_wp(int on) -+{ -+} -+ -+static void armflash_set_vpp(struct map_info *map, int on) -+{ -+} -+#endif -+ -+ -+static struct map_info armflash_map = -+{ -+ .name = "AFS", -+ .set_vpp = armflash_set_vpp, -+ .phys = FLASH_BASE, -+}; -+ -+static struct mtd_info *mtd; -+static struct mtd_partition *parts; -+static const char *probes[] = { "RedBoot", "afs", NULL }; -+ -+static int __init armflash_cfi_init(void *base, u_int size) -+{ -+ int ret; -+ -+ armflash_flash_init(); -+ armflash_flash_wp(1); -+ -+ /* -+ * look for CFI based flash parts fitted to this board -+ */ -+ armflash_map.size = size; -+ armflash_map.buswidth = 4; -+ armflash_map.virt = (unsigned long) base; -+ -+ simple_map_init(&armflash_map); -+ -+ /* -+ * Also, the CFI layer automatically works out what size -+ * of chips we have, and does the necessary identification -+ * for us automatically. -+ */ -+ mtd = do_map_probe("cfi_probe", &armflash_map); -+ if (!mtd) -+ return -ENXIO; -+ -+ mtd->owner = THIS_MODULE; -+ -+ ret = parse_mtd_partitions(mtd, probes, &parts, (void *)0); -+ if (ret > 0) { -+ ret = add_mtd_partitions(mtd, parts, ret); -+ if (ret) -+ printk(KERN_ERR "mtd partition registration " -+ "failed: %d\n", ret); -+ } -+ -+ /* -+ * If we got an error, free all resources. -+ */ -+ if (ret < 0) { -+ del_mtd_partitions(mtd); -+ map_destroy(mtd); -+ } -+ -+ return ret; -+} -+ -+static void armflash_cfi_exit(void) -+{ -+ if (mtd) { -+ del_mtd_partitions(mtd); -+ map_destroy(mtd); -+ } -+ if (parts) -+ kfree(parts); -+} -+ -+static int __init armflash_init(void) -+{ -+ int err = -EBUSY; -+ void *base; -+ -+ if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL) -+ goto out; -+ -+ base = ioremap(FLASH_BASE, FLASH_SIZE); -+ err = -ENOMEM; -+ if (base == NULL) -+ goto release; -+ -+ err = armflash_cfi_init(base, FLASH_SIZE); -+ if (err) { -+ iounmap(base); -+release: -+ release_mem_region(FLASH_BASE, FLASH_SIZE); -+ } -+out: -+ return err; -+} -+ -+static void __exit armflash_exit(void) -+{ -+ armflash_cfi_exit(); -+ iounmap((void *)armflash_map.virt); -+ release_mem_region(FLASH_BASE, FLASH_SIZE); -+ armflash_flash_exit(); -+} -+ -+module_init(armflash_init); -+module_exit(armflash_exit); -+ -+MODULE_AUTHOR("ARM Ltd"); -+MODULE_DESCRIPTION("ARM Integrator CFI map driver"); -+MODULE_LICENSE("GPL"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/integrator-flash.c linux/drivers/mtd/maps/integrator-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/integrator-flash.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/integrator-flash.c 2004-11-19 10:25:11.923196144 +0100 -@@ -1,8 +1,9 @@ - /*====================================================================== - -- drivers/mtd/maps/armflash.c: ARM Flash Layout/Partitioning -+ drivers/mtd/maps/integrator-flash.c: ARM Integrator flash map driver - - Copyright (C) 2000 ARM Limited -+ Copyright (C) 2003 Deep Blue Solutions Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by -@@ -21,7 +22,7 @@ - This is access code for flashes using ARM's flash partitioning - standards. - -- $Id$ -+ $Id$ - - ======================================================================*/ - -@@ -31,268 +32,181 @@ - #include <linux/kernel.h> - #include <linux/slab.h> - #include <linux/ioport.h> -+#include <linux/device.h> - #include <linux/init.h> - - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> - #include <linux/mtd/partitions.h> - -+#include <asm/mach/flash.h> - #include <asm/hardware.h> - #include <asm/io.h> - #include <asm/system.h> - --extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **); -- --// board specific stuff - sorry, it should be in arch/arm/mach-*. --#ifdef CONFIG_ARCH_INTEGRATOR -- --#define FLASH_BASE INTEGRATOR_FLASH_BASE --#define FLASH_SIZE INTEGRATOR_FLASH_SIZE -- --#define FLASH_PART_SIZE 0x400000 -- --#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) --#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) --#define EBI_CSR1 (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_CSR1_OFFSET) --#define EBI_LOCK (IO_ADDRESS(INTEGRATOR_EBI_BASE) + INTEGRATOR_EBI_LOCK_OFFSET) -- --/* -- * Initialise the flash access systems: -- * - Disable VPP -- * - Assert WP -- * - Set write enable bit in EBI reg -- */ --static void armflash_flash_init(void) --{ -- unsigned int tmp; -- -- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); -- -- tmp = __raw_readl(EBI_CSR1) | INTEGRATOR_EBI_WRITE_ENABLE; -- __raw_writel(tmp, EBI_CSR1); -- -- if (!(__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE)) { -- __raw_writel(0xa05f, EBI_LOCK); -- __raw_writel(tmp, EBI_CSR1); -- __raw_writel(0, EBI_LOCK); -- } --} -- --/* -- * Shutdown the flash access systems: -- * - Disable VPP -- * - Assert WP -- * - Clear write enable bit in EBI reg -- */ --static void armflash_flash_exit(void) --{ -- unsigned int tmp; -- -- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP, SC_CTRLC); -- -- /* -- * Clear the write enable bit in system controller EBI register. -- */ -- tmp = __raw_readl(EBI_CSR1) & ~INTEGRATOR_EBI_WRITE_ENABLE; -- __raw_writel(tmp, EBI_CSR1); -- -- if (__raw_readl(EBI_CSR1) & INTEGRATOR_EBI_WRITE_ENABLE) { -- __raw_writel(0xa05f, EBI_LOCK); -- __raw_writel(tmp, EBI_CSR1); -- __raw_writel(0, EBI_LOCK); -- } --} -- --static void armflash_flash_wp(int on) --{ -- unsigned int reg; -- -- if (on) -- reg = SC_CTRLC; -- else -- reg = SC_CTRLS; -- -- __raw_writel(INTEGRATOR_SC_CTRL_nFLWP, reg); --} -- --static void armflash_set_vpp(struct map_info *map, int on) --{ -- unsigned int reg; -- -- if (on) -- reg = SC_CTRLS; -- else -- reg = SC_CTRLC; -- -- __raw_writel(INTEGRATOR_SC_CTRL_nFLVPPEN, reg); --} --#endif -- - #ifdef CONFIG_ARCH_P720T -- - #define FLASH_BASE (0x04000000) - #define FLASH_SIZE (64*1024*1024) -- --#define FLASH_PART_SIZE (4*1024*1024) --#define FLASH_BLOCK_SIZE (128*1024) -- --static void armflash_flash_init(void) --{ --} -- --static void armflash_flash_exit(void) --{ --} -- --static void armflash_flash_wp(int on) --{ --} -- --static void armflash_set_vpp(struct map_info *map, int on) --{ --} - #endif - --static __u8 armflash_read8(struct map_info *map, unsigned long ofs) --{ -- return readb(ofs + map->map_priv_2); --} -- --static __u16 armflash_read16(struct map_info *map, unsigned long ofs) --{ -- return readw(ofs + map->map_priv_2); --} -+struct armflash_info { -+ struct flash_platform_data *plat; -+ struct resource *res; -+ struct mtd_partition *parts; -+ struct mtd_info *mtd; -+ struct map_info map; -+}; - --static __u32 armflash_read32(struct map_info *map, unsigned long ofs) -+static void armflash_set_vpp(struct map_info *map, int on) - { -- return readl(ofs + map->map_priv_2); --} -+ struct armflash_info *info = container_of(map, struct armflash_info, map); - --static void armflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy(to, (void *) (from + map->map_priv_2), len); -+ if (info->plat && info->plat->set_vpp) -+ info->plat->set_vpp(on); - } - --static void armflash_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- writeb(d, adr + map->map_priv_2); --} -- --static void armflash_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- writew(d, adr + map->map_priv_2); --} -+static const char *probes[] = { "RedBoot", "afs", NULL }; - --static void armflash_write32(struct map_info *map, __u32 d, unsigned long adr) -+static int armflash_probe(struct device *_dev) - { -- writel(d, adr + map->map_priv_2); --} -+ struct platform_device *dev = to_platform_device(_dev); -+ struct flash_platform_data *plat = dev->dev.platform_data; -+ struct resource *res = dev->resource; -+ unsigned int size = res->end - res->start + 1; -+ struct armflash_info *info; -+ int err; -+ void *base; - --static void armflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy((void *) (to + map->map_priv_2), from, len); --} -+ info = kmalloc(sizeof(struct armflash_info), GFP_KERNEL); -+ if (!info) { -+ err = -ENOMEM; -+ goto out; -+ } - --static struct map_info armflash_map = --{ -- name: "AFS", -- read8: armflash_read8, -- read16: armflash_read16, -- read32: armflash_read32, -- copy_from: armflash_copy_from, -- write8: armflash_write8, -- write16: armflash_write16, -- write32: armflash_write32, -- copy_to: armflash_copy_to, -- set_vpp: armflash_set_vpp, --}; -+ memset(info, 0, sizeof(struct armflash_info)); - --static struct mtd_info *mtd; --static struct mtd_partition *parts; -+ info->plat = plat; -+ if (plat && plat->init) { -+ err = plat->init(); -+ if (err) -+ goto no_resource; -+ } - --static int __init armflash_cfi_init(void *base, u_int size) --{ -- int ret; -+ info->res = request_mem_region(res->start, size, "armflash"); -+ if (!info->res) { -+ err = -EBUSY; -+ goto no_resource; -+ } - -- armflash_flash_init(); -- armflash_flash_wp(1); -+ base = ioremap(res->start, size); -+ if (!base) { -+ err = -ENOMEM; -+ goto no_mem; -+ } - - /* - * look for CFI based flash parts fitted to this board - */ -- armflash_map.size = size; -- armflash_map.buswidth = 4; -- armflash_map.map_priv_2 = (unsigned long) base; -+ info->map.size = size; -+ info->map.buswidth = plat->width; -+ info->map.phys = res->start; -+ info->map.virt = (unsigned long) base; -+ info->map.name = dev->dev.bus_id; -+ info->map.set_vpp = armflash_set_vpp; -+ -+ simple_map_init(&info->map); - - /* - * Also, the CFI layer automatically works out what size - * of chips we have, and does the necessary identification - * for us automatically. - */ -- mtd = do_map_probe("cfi_probe", &armflash_map); -- if (!mtd) -- return -ENXIO; -- -- mtd->module = THIS_MODULE; -- -- ret = parse_afs_partitions(mtd, &parts); -- if (ret > 0) { -- ret = add_mtd_partitions(mtd, parts, ret); -- if (ret) -- printk(KERN_ERR "mtd partition registration " -- "failed: %d\n", ret); -+ info->mtd = do_map_probe(plat->map_name, &info->map); -+ if (!info->mtd) { -+ err = -ENXIO; -+ goto no_device; - } - -+ info->mtd->owner = THIS_MODULE; -+ -+ err = parse_mtd_partitions(info->mtd, probes, &info->parts, 0); -+ if (err > 0) { -+ err = add_mtd_partitions(info->mtd, info->parts, err); -+ if (err) -+ printk(KERN_ERR -+ "mtd partition registration failed: %d\n", err); -+ } -+ -+ if (err == 0) -+ dev_set_drvdata(&dev->dev, info); -+ - /* - * If we got an error, free all resources. - */ -- if (ret < 0) { -- del_mtd_partitions(mtd); -- map_destroy(mtd); -+ if (err < 0) { -+ if (info->mtd) { -+ del_mtd_partitions(info->mtd); -+ map_destroy(info->mtd); - } -+ if (info->parts) -+ kfree(info->parts); - -- return ret; --} -- --static void armflash_cfi_exit(void) --{ -- if (mtd) { -- del_mtd_partitions(mtd); -- map_destroy(mtd); -+ no_device: -+ iounmap(base); -+ no_mem: -+ release_mem_region(res->start, size); -+ no_resource: -+ if (plat && plat->exit) -+ plat->exit(); -+ kfree(info); - } -- if (parts) -- kfree(parts); -+ out: -+ return err; - } - --static int __init armflash_init(void) -+static int armflash_remove(struct device *_dev) - { -- int err = -EBUSY; -- void *base; -+ struct platform_device *dev = to_platform_device(_dev); -+ struct armflash_info *info = dev_get_drvdata(&dev->dev); - -- if (request_mem_region(FLASH_BASE, FLASH_SIZE, "flash") == NULL) -- goto out; -+ dev_set_drvdata(&dev->dev, NULL); - -- base = ioremap(FLASH_BASE, FLASH_SIZE); -- err = -ENOMEM; -- if (base == NULL) -- goto release; -+ if (info) { -+ if (info->mtd) { -+ del_mtd_partitions(info->mtd); -+ map_destroy(info->mtd); -+ } -+ if (info->parts) -+ kfree(info->parts); - -- err = armflash_cfi_init(base, FLASH_SIZE); -- if (err) { -- iounmap(base); --release: -- release_mem_region(FLASH_BASE, FLASH_SIZE); -+ iounmap((void *)info->map.virt); -+ release_resource(info->res); -+ kfree(info->res); -+ -+ if (info->plat && info->plat->exit) -+ info->plat->exit(); -+ -+ kfree(info); - } --out: -- return err; -+ -+ return 0; -+} -+ -+static struct device_driver armflash_driver = { -+ .name = "armflash", -+ .bus = &platform_bus_type, -+ .probe = armflash_probe, -+ .remove = armflash_remove, -+}; -+ -+static int __init armflash_init(void) -+{ -+ return driver_register(&armflash_driver); - } - - static void __exit armflash_exit(void) - { -- armflash_cfi_exit(); -- iounmap((void *)armflash_map.map_priv_2); -- release_mem_region(FLASH_BASE, FLASH_SIZE); -- armflash_flash_exit(); -+ driver_unregister(&armflash_driver); - } - - module_init(armflash_init); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/iq80310.c linux/drivers/mtd/maps/iq80310.c ---- linux-mips-2.4.27/drivers/mtd/maps/iq80310.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/iq80310.c 2004-11-19 10:25:11.924195992 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Mapping for the Intel XScale IQ80310 evaluation board - * -@@ -14,6 +14,8 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/slab.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -26,127 +28,72 @@ - - static struct mtd_info *mymtd; - --static __u8 iq80310_read8(struct map_info *map, unsigned long ofs) --{ -- return *(__u8 *)(map->map_priv_1 + ofs); --} -- --static __u16 iq80310_read16(struct map_info *map, unsigned long ofs) --{ -- return *(__u16 *)(map->map_priv_1 + ofs); --} -- --static __u32 iq80310_read32(struct map_info *map, unsigned long ofs) --{ -- return *(__u32 *)(map->map_priv_1 + ofs); --} -- --static void iq80310_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy(to, (void *)(map->map_priv_1 + from), len); --} -- --static void iq80310_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- *(__u8 *)(map->map_priv_1 + adr) = d; --} -- --static void iq80310_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- *(__u16 *)(map->map_priv_1 + adr) = d; --} -- --static void iq80310_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- *(__u32 *)(map->map_priv_1 + adr) = d; --} -- --static void iq80310_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy((void *)(map->map_priv_1 + to), from, len); --} -- - static struct map_info iq80310_map = { -- name: "IQ80310 flash", -- size: WINDOW_SIZE, -- buswidth: BUSWIDTH, -- read8: iq80310_read8, -- read16: iq80310_read16, -- read32: iq80310_read32, -- copy_from: iq80310_copy_from, -- write8: iq80310_write8, -- write16: iq80310_write16, -- write32: iq80310_write32, -- copy_to: iq80310_copy_to -+ .name = "IQ80310 flash", -+ .size = WINDOW_SIZE, -+ .buswidth = BUSWIDTH, -+ .phys = WINDOW_ADDR - }; - - static struct mtd_partition iq80310_partitions[4] = { - { -- name: "Firmware", -- size: 0x00080000, -- offset: 0, -- mask_flags: MTD_WRITEABLE /* force read-only */ -+ .name = "Firmware", -+ .size = 0x00080000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE /* force read-only */ - },{ -- name: "Kernel", -- size: 0x000a0000, -- offset: 0x00080000, -+ .name = "Kernel", -+ .size = 0x000a0000, -+ .offset = 0x00080000, - },{ -- name: "Filesystem", -- size: 0x00600000, -- offset: 0x00120000 -+ .name = "Filesystem", -+ .size = 0x00600000, -+ .offset = 0x00120000 - },{ -- name: "RedBoot", -- size: 0x000e0000, -- offset: 0x00720000, -- mask_flags: MTD_WRITEABLE -+ .name = "RedBoot", -+ .size = 0x000e0000, -+ .offset = 0x00720000, -+ .mask_flags = MTD_WRITEABLE - } - }; - --#define NB_OF(x) (sizeof(x)/sizeof(x[0])) -- - static struct mtd_info *mymtd; - static struct mtd_partition *parsed_parts; -- --extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; - - static int __init init_iq80310(void) - { - struct mtd_partition *parts; - int nb_parts = 0; - int parsed_nr_parts = 0; -- char *part_type = "static"; -+ int ret; - -- iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); -- if (!iq80310_map.map_priv_1) { -+ iq80310_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); -+ if (!iq80310_map.virt) { - printk("Failed to ioremap\n"); - return -EIO; - } -+ simple_map_init(&iq80310_map); -+ - mymtd = do_map_probe("cfi_probe", &iq80310_map); - if (!mymtd) { -- iounmap((void *)iq80310_map.map_priv_1); -+ iounmap((void *)iq80310_map.virt); - return -ENXIO; - } -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - --#ifdef CONFIG_MTD_REDBOOT_PARTS -- if (parsed_nr_parts == 0) { -- int ret = parse_redboot_partitions(mymtd, &parsed_parts); -+ ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0); - -- if (ret > 0) { -- part_type = "RedBoot"; -+ if (ret > 0) - parsed_nr_parts = ret; -- } -- } --#endif - - if (parsed_nr_parts > 0) { - parts = parsed_parts; - nb_parts = parsed_nr_parts; - } else { - parts = iq80310_partitions; -- nb_parts = NB_OF(iq80310_partitions); -+ nb_parts = ARRAY_SIZE(iq80310_partitions); - } -- printk(KERN_NOTICE "Using %s partition definition\n", part_type); - add_mtd_partitions(mymtd, parts, nb_parts); - return 0; - } -@@ -159,8 +106,8 @@ - if (parsed_parts) - kfree(parsed_parts); - } -- if (iq80310_map.map_priv_1) -- iounmap((void *)iq80310_map.map_priv_1); -+ if (iq80310_map.virt) -+ iounmap((void *)iq80310_map.virt); - } - - module_init(init_iq80310); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ixp425.c linux/drivers/mtd/maps/ixp425.c ---- linux-mips-2.4.27/drivers/mtd/maps/ixp425.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/ixp425.c 2004-11-19 10:25:11.925195840 +0100 -@@ -0,0 +1,220 @@ -+/* -+ * $Id$ -+ * -+ * drivers/mtd/maps/ixp425.c -+ * -+ * MTD Map file for IXP425 based systems. Please do not make per-board -+ * map driver as the code will be 90% identical. For now just add -+ * if(machine_is_XXX()) checks to the code. I'll clean this stuff to -+ * use platform_data in the the future so we can get rid of that too. -+ * -+ * Original Author: Intel Corporation -+ * Maintainer: Deepak Saxena <dsaxena@mvista.com> -+ * -+ * Copyright (C) 2002 Intel Corporation -+ * Copyright (C) 2003 MontaVista Software, Inc. -+ * -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/init.h> -+#include <linux/kernel.h> -+#include <linux/string.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <linux/ioport.h> -+#include <asm/io.h> -+#include <asm/mach-types.h> -+ -+#include <linux/reboot.h> -+ -+#define WINDOW_ADDR 0x50000000 -+#define BUSWIDTH 2 -+ -+#ifndef __ARMEB__ -+#define BYTE0(h) ((h) & 0xFF) -+#define BYTE1(h) (((h) >> 8) & 0xFF) -+#else -+#define BYTE0(h) (((h) >> 8) & 0xFF) -+#define BYTE1(h) ((h) & 0xFF) -+#endif -+ -+static __u16 -+ixp425_read16(struct map_info *map, unsigned long ofs) -+{ -+ return *(__u16 *) (map->map_priv_1 + ofs); -+} -+ -+/* -+ * The IXP425 expansion bus only allows 16-bit wide acceses -+ * when attached to a 16-bit wide device (such as the 28F128J3A), -+ * so we can't just memcpy_fromio(). -+ */ -+static void -+ixp425_copy_from(struct map_info *map, void *to, -+ unsigned long from, ssize_t len) -+{ -+ int i; -+ u8 *dest = (u8 *) to; -+ u16 *src = (u16 *) (map->map_priv_1 + from); -+ u16 data; -+ -+ for (i = 0; i < (len / 2); i++) { -+ data = src[i]; -+ dest[i * 2] = BYTE0(data); -+ dest[i * 2 + 1] = BYTE1(data); -+ } -+ -+ if (len & 1) -+ dest[len - 1] = BYTE0(src[i]); -+} -+ -+static void -+ixp425_write16(struct map_info *map, __u16 d, unsigned long adr) -+{ -+ *(__u16 *) (map->map_priv_1 + adr) = d; -+} -+ -+static struct map_info ixp425_map = { -+ .name = "IXP425 Flash", -+ .buswidth = BUSWIDTH, -+ .read16 = ixp425_read16, -+ .copy_from = ixp425_copy_from, -+ .write16 = ixp425_write16, -+}; -+ -+/* -+ * Put flash back in read mode so RedBoot can boot properly. -+ */ -+int ixp425_mtd_reboot(struct notifier_block *n, unsigned long code, void *p) -+{ -+ if (code != SYS_RESTART) -+ return NOTIFY_DONE; -+ -+ ixp425_write16(&ixp425_map, 0xff, 0x55 * 0x2); -+ return NOTIFY_DONE; -+} -+ -+static struct notifier_block ixp425_mtd_notifier = { -+ notifier_call:ixp425_mtd_reboot, -+ next:NULL, -+ priority:0 -+}; -+ -+static struct mtd_partition *parsed_parts; -+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; -+ -+static struct mtd_partition ixp425_partitions[] = { -+ { -+ .name = "image", -+ .offset = 0x00040000, -+ .size = 0x00400000, -+ }, { -+ .name = "user", -+ .offset = 0x00440000, -+ .size = MTDPART_SIZ_FULL -+ } -+}; -+ -+#define NB_OF(x) (sizeof(x)/sizeof(x[0])) -+ -+static struct mtd_info *ixp425_mtd; -+static struct resource *mtd_resource; -+ -+static void -+ixp425_exit(void) -+{ -+ if (ixp425_mtd) { -+ del_mtd_partitions(ixp425_mtd); -+ map_destroy(ixp425_mtd); -+ } -+ if (ixp425_map.map_priv_1) -+ iounmap((void *) ixp425_map.map_priv_1); -+ if (mtd_resource) -+ release_mem_region(WINDOW_ADDR, ixp425_map.size); -+ -+ if (parsed_parts) -+ kfree(parsed_parts); -+ -+ unregister_reboot_notifier(&ixp425_mtd_notifier); -+ -+ /* Disable flash write */ -+ *IXP425_EXP_CS0 &= ~IXP425_FLASH_WRITABLE; -+ -+ if(machine_is_adi_coyote()) -+ *IXP425_EXP_CS1 &= ~IXP425_FLASH_WRITABLE; -+} -+ -+static int __init -+ixp425_init(void) -+{ -+ int res = -1, npart; -+ -+ /* Enable flash write */ -+ *IXP425_EXP_CS0 |= IXP425_FLASH_WRITABLE; -+ -+ /* -+ * Coyote requires CS1 write to be enabled and has 32MB flash. -+ * This will move to the platform init code in 2.6 -+ */ -+ if(machine_is_adi_coyote()) { -+ *IXP425_EXP_CS1 |= IXP425_FLASH_WRITABLE; -+ ixp425_map.size = 0x02000000; -+ } else -+ ixp425_map.size = 0x01000000; -+ -+ ixp425_map.map_priv_1 = 0; -+ mtd_resource = -+ request_mem_region(WINDOW_ADDR, ixp425_map.size, "IXP425 Flash"); -+ if (!mtd_resource) { -+ printk(KERN_ERR -+ "ixp425 flash: Could not request mem region.\n"); -+ res = -ENOMEM; -+ goto Error; -+ } -+ -+ ixp425_map.map_priv_1 = -+ (unsigned long) ioremap(WINDOW_ADDR, ixp425_map.size); -+ if (!ixp425_map.map_priv_1) { -+ printk("ixp425 Flash: Failed to map IO region. (ioremap)\n"); -+ res = -EIO; -+ goto Error; -+ } -+ -+ ixp425_mtd = do_map_probe("cfi_probe", &ixp425_map); -+ if (!ixp425_mtd) { -+ res = -ENXIO; -+ goto Error; -+ } -+ ixp425_mtd->owner = THIS_MODULE; -+ -+ /* Try to parse RedBoot partitions */ -+ npart = parse_mtd_partitions(ixp425_mtd, probes, &parsed_parts, 0); -+ if (npart > 0) -+ res = add_mtd_partitions(ixp425_mtd, parsed_parts, npart); -+ else { -+ printk("IXP425 Flash: Using static MTD partitions.\n"); -+ res = add_mtd_partitions(ixp425_mtd, ixp425_partitions, -+ NB_OF(ixp425_partitions)); -+ } -+ -+ if (res) -+ goto Error; -+ -+ register_reboot_notifier(&ixp425_mtd_notifier); -+ -+ return res; -+ -+Error: -+ ixp425_exit(); -+ return res; -+} -+ -+module_init(ixp425_init); -+module_exit(ixp425_exit); -+ -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("MTD map driver for ixp425 evaluation board"); -+MODULE_AUTHOR("Deepak Saxena"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/l440gx.c linux/drivers/mtd/maps/l440gx.c ---- linux-mips-2.4.27/drivers/mtd/maps/l440gx.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/l440gx.c 2004-11-19 10:25:11.927195536 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * BIOS Flash chip on Intel 440GX board. - * -@@ -9,6 +9,7 @@ - #include <linux/module.h> - #include <linux/pci.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -27,48 +28,6 @@ - - static struct mtd_info *mymtd; - --__u8 l440gx_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 l440gx_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 l440gx_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void l440gx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void l440gx_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void l440gx_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void l440gx_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void l440gx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} - - /* Is this really the vpp port? */ - void l440gx_set_vpp(struct map_info *map, int vpp) -@@ -85,22 +44,15 @@ - } - - struct map_info l440gx_map = { -- name: "L440GX BIOS", -- size: WINDOW_SIZE, -- buswidth: BUSWIDTH, -- read8: l440gx_read8, -- read16: l440gx_read16, -- read32: l440gx_read32, -- copy_from: l440gx_copy_from, -- write8: l440gx_write8, -- write16: l440gx_write16, -- write32: l440gx_write32, -- copy_to: l440gx_copy_to, -+ .name = "L440GX BIOS", -+ .size = WINDOW_SIZE, -+ .buswidth = BUSWIDTH, -+ .phys = WINDOW_ADDR, - #if 0 - /* FIXME verify that this is the - * appripriate code for vpp enable/disable - */ -- set_vpp: l440gx_set_vpp -+ .set_vpp = l440gx_set_vpp - #endif - }; - -@@ -113,7 +65,6 @@ - dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_0, NULL); - -- - pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_82371AB_3, NULL); - -@@ -122,15 +73,14 @@ - return -ENODEV; - } - -+ l440gx_map.virt = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); - -- l440gx_map.map_priv_1 = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); -- -- if (!l440gx_map.map_priv_1) { -+ if (!l440gx_map.virt) { - printk(KERN_WARNING "Failed to ioremap L440GX flash region\n"); - return -ENOMEM; - } -- -- printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.map_priv_1); -+ simple_map_init(&l440gx_map); -+ printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt); - - /* Setup the pm iobase resource - * This code should move into some kind of generic bridge -@@ -153,7 +103,7 @@ - /* Allocate the resource region */ - if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) { - printk(KERN_WARNING "Could not allocate pm iobase resource\n"); -- iounmap((void *)l440gx_map.map_priv_1); -+ iounmap((void *)l440gx_map.virt); - return -ENXIO; - } - } -@@ -181,13 +131,13 @@ - mymtd = do_map_probe("map_rom", &l440gx_map); - } - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - - add_mtd_device(mymtd); - return 0; - } - -- iounmap((void *)l440gx_map.map_priv_1); -+ iounmap((void *)l440gx_map.virt); - return -ENXIO; - } - -@@ -196,7 +146,7 @@ - del_mtd_device(mymtd); - map_destroy(mymtd); - -- iounmap((void *)l440gx_map.map_priv_1); -+ iounmap((void *)l440gx_map.virt); - } - - module_init(init_l440gx); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/lasat.c linux/drivers/mtd/maps/lasat.c ---- linux-mips-2.4.27/drivers/mtd/maps/lasat.c 2003-08-18 04:59:02.000000000 +0200 -+++ linux/drivers/mtd/maps/lasat.c 2004-11-19 10:25:11.928195384 +0100 -@@ -1,11 +1,20 @@ - /* -- * Flash device on lasat 100 and 200 boards -+ * Flash device on Lasat 100 and 200 boards -+ * -+ * (C) 2002 Brian Murphy <brian@murphy.dk> -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License version -+ * 2 as published by the Free Software Foundation. -+ * -+ * $Id$ - * - */ - - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -13,123 +22,80 @@ - #include <linux/config.h> - #include <asm/lasat/lasat.h> - --static struct mtd_info *mymtd; -- --static __u8 sp_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --static __u16 sp_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --static __u32 sp_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --static void sp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -+static struct mtd_info *lasat_mtd; - --static void sp_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --static void sp_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --static void sp_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -+static struct mtd_partition partition_info[LASAT_MTD_LAST]; -+static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"}; - --static void sp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -+static void lasat_set_vpp(struct map_info *map, int vpp) - { -- memcpy_toio(map->map_priv_1 + to, from, len); -+ if (vpp) -+ *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit; -+ else -+ *lasat_misc->flash_wp_reg &= ~(1 << lasat_misc->flash_wp_bit); - } - --static struct map_info sp_map = { -- name: "SP flash", -- buswidth: 4, -- read8: sp_read8, -- read16: sp_read16, -- read32: sp_read32, -- copy_from: sp_copy_from, -- write8: sp_write8, -- write16: sp_write16, -- write32: sp_write32, -- copy_to: sp_copy_to -+static struct map_info lasat_map = { -+ .name = "LASAT flash", -+ .buswidth = 4, -+ .set_vpp = lasat_set_vpp - }; - --static struct mtd_partition partition_info[LASAT_MTD_LAST]; --static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Config", "Filesystem"}; -- --static int __init init_sp(void) -+static int __init init_lasat(void) - { - int i; -- int nparts = 0; -- /* this does not play well with the old flash code which -- * protects and uprotects the flash when necessary */ -+ /* since we use AMD chips and set_vpp is not implimented -+ * for these (yet) we still have to permanently enable flash write */ - printk(KERN_NOTICE "Unprotecting flash\n"); -- *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit; -+ ENABLE_VPP((&lasat_map)); - -- sp_map.map_priv_1 = ioremap_nocache( -- lasat_flash_partition_start(LASAT_MTD_BOOTLOADER), -- lasat_board_info.li_flash_size); -- sp_map.size = lasat_board_info.li_flash_size; -+ lasat_map.phys = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER); -+ lasat_map.virt = (unsigned long)ioremap_nocache( -+ lasat_map.phys, lasat_board_info.li_flash_size); -+ lasat_map.size = lasat_board_info.li_flash_size; - -- printk(KERN_NOTICE "sp flash device: %lx at %lx\n", -- sp_map.size, sp_map.map_priv_1); -+ simple_map_init(&lasat_map); - - for (i=0; i < LASAT_MTD_LAST; i++) - partition_info[i].name = lasat_mtd_partnames[i]; - -- mymtd = do_map_probe("cfi_probe", &sp_map); -- if (mymtd) { -+ lasat_mtd = do_map_probe("cfi_probe", &lasat_map); -+ -+ if (!lasat_mtd) -+ lasat_mtd = do_map_probe("jedec_probe", &lasat_map); -+ -+ if (lasat_mtd) { - u32 size, offset = 0; - -- mymtd->module = THIS_MODULE; -+ lasat_mtd->owner = THIS_MODULE; - - for (i=0; i < LASAT_MTD_LAST; i++) { - size = lasat_flash_partition_size(i); -- if (size != 0) { -- nparts++; - partition_info[i].size = size; - partition_info[i].offset = offset; - offset += size; - } -- } - -- add_mtd_partitions( mymtd, partition_info, nparts ); -+ add_mtd_partitions( lasat_mtd, partition_info, LASAT_MTD_LAST ); - return 0; - } - - return -ENXIO; - } - --static void __exit cleanup_sp(void) -+static void __exit cleanup_lasat(void) - { -- if (mymtd) { -- del_mtd_partitions(mymtd); -- map_destroy(mymtd); -+ if (lasat_mtd) { -+ del_mtd_partitions(lasat_mtd); -+ map_destroy(lasat_mtd); - } -- if (sp_map.map_priv_1) { -- sp_map.map_priv_1 = 0; -+ if (lasat_map.virt) { -+ lasat_map.virt = 0; - } - } - --module_init(init_sp); --module_exit(cleanup_sp); -+module_init(init_lasat); -+module_exit(cleanup_lasat); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/lubbock-flash.c linux/drivers/mtd/maps/lubbock-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/lubbock-flash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/lubbock-flash.c 2004-11-19 10:25:11.930195080 +0100 -@@ -0,0 +1,151 @@ -+/* -+ * $Id$ -+ * -+ * Map driver for the Lubbock developer platform. -+ * -+ * Author: Nicolas Pitre -+ * Copyright: (C) 2001 MontaVista Software Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <asm/io.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <asm/hardware.h> -+ -+ -+#define ROM_ADDR 0x00000000 -+#define FLASH_ADDR 0x04000000 -+ -+#define WINDOW_SIZE 64*1024*1024 -+ -+static struct map_info lubbock_maps[2] = { { -+ .size = WINDOW_SIZE, -+ .phys = 0x00000000, -+}, { -+ .size = WINDOW_SIZE, -+ .phys = 0x04000000, -+} }; -+ -+static struct mtd_partition lubbock_partitions[] = { -+ { -+ .name = "Bootloader", -+ .size = 0x00040000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE /* force read-only */ -+ },{ -+ .name = "Kernel", -+ .size = 0x00100000, -+ .offset = 0x00040000, -+ },{ -+ .name = "Filesystem", -+ .size = MTDPART_SIZ_FULL, -+ .offset = 0x00140000 -+ } -+}; -+ -+static struct mtd_info *mymtds[2]; -+static struct mtd_partition *parsed_parts[2]; -+static int nr_parsed_parts[2]; -+ -+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; -+ -+static int __init init_lubbock(void) -+{ -+ int flashboot = (CONF_SWITCHES & 1); -+ int ret = 0, i; -+ -+ lubbock_maps[0].buswidth = lubbock_maps[1].buswidth = -+ (BOOT_DEF & 1) ? 2 : 4; -+ -+ /* Compensate for the nROMBT switch which swaps the flash banks */ -+ printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n", -+ flashboot?"Flash":"ROM", flashboot); -+ -+ lubbock_maps[flashboot^1].name = "Lubbock Application Flash"; -+ lubbock_maps[flashboot].name = "Lubbock Boot ROM"; -+ -+ for (i = 0; i < 2; i++) { -+ lubbock_maps[i].virt = (unsigned long)__ioremap(lubbock_maps[i].phys, WINDOW_SIZE, 0); -+ if (!lubbock_maps[i].virt) { -+ printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name); -+ if (!ret) -+ ret = -ENOMEM; -+ continue; -+ } -+ simple_map_init(&lubbock_maps[i]); -+ -+ printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit buswidth)\n", -+ lubbock_maps[i].name, lubbock_maps[i].phys, -+ lubbock_maps[i].buswidth * 8); -+ -+ mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); -+ -+ if (!mymtds[i]) { -+ iounmap((void *)lubbock_maps[i].virt); -+ if (!ret) -+ ret = -EIO; -+ continue; -+ } -+ mymtds[i]->owner = THIS_MODULE; -+ -+ int ret = parse_mtd_partitions(mymtds[i], probes, -+ &parsed_parts[i], 0); -+ -+ if (ret > 0) -+ nr_parsed_parts[i] = ret; -+ } -+ -+ if (!mymtds[0] && !mymtds[1]) -+ return ret; -+ -+ for (i = 0; i < 2; i++) { -+ if (!mymtds[i]) { -+ printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); -+ } else if (nr_parsed_parts[i]) { -+ add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]); -+ } else if (!i) { -+ printk("Using static partitions on %s\n", lubbock_maps[i].name); -+ add_mtd_partitions(mymtds[i], lubbock_partitions, ARRAY_SIZE(lubbock_partitions)); -+ } else { -+ printk("Registering %s as whole device\n", lubbock_maps[i].name); -+ add_mtd_device(mymtds[i]); -+ } -+ } -+ return 0; -+} -+ -+static void __exit cleanup_lubbock(void) -+{ -+ int i; -+ for (i = 0; i < 2; i++) { -+ if (!mymtds[i]) -+ continue; -+ -+ if (nr_parsed_parts[i] || !i) -+ del_mtd_partitions(mymtds[i]); -+ else -+ del_mtd_device(mymtds[i]); -+ -+ map_destroy(mymtds[i]); -+ iounmap((void *)lubbock_maps[i].virt); -+ -+ if (parsed_parts[i]) -+ kfree(parsed_parts[i]); -+ } -+} -+ -+module_init(init_lubbock); -+module_exit(cleanup_lubbock); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); -+MODULE_DESCRIPTION("MTD map driver for Intel Lubbock"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/map_funcs.c linux/drivers/mtd/maps/map_funcs.c ---- linux-mips-2.4.27/drivers/mtd/maps/map_funcs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/map_funcs.c 2004-11-19 10:25:11.931194928 +0100 -@@ -0,0 +1,96 @@ -+/* -+ * $Id$ -+ * -+ * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS -+ * is enabled. -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/config.h> -+#include <linux/types.h> -+#include <linux/string.h> -+#include <asm/io.h> -+ -+#include <linux/mtd/map.h> -+ -+static u8 simple_map_read8(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readb(map->virt + ofs); -+} -+ -+static u16 simple_map_read16(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readw(map->virt + ofs); -+} -+ -+static u32 simple_map_read32(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readl(map->virt + ofs); -+} -+ -+static u64 simple_map_read64(struct map_info *map, unsigned long ofs) -+{ -+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ -+ BUG(); -+ return 0; -+#else -+ return __raw_readll(map->virt + ofs); -+#endif -+} -+ -+static void simple_map_write8(struct map_info *map, u8 datum, unsigned long ofs) -+{ -+ __raw_writeb(datum, map->virt + ofs); -+ mb(); -+} -+ -+static void simple_map_write16(struct map_info *map, u16 datum, unsigned long ofs) -+{ -+ __raw_writew(datum, map->virt + ofs); -+ mb(); -+} -+ -+static void simple_map_write32(struct map_info *map, u32 datum, unsigned long ofs) -+{ -+ __raw_writel(datum, map->virt + ofs); -+ mb(); -+} -+ -+static void simple_map_write64(struct map_info *map, u64 datum, unsigned long ofs) -+{ -+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ -+ BUG(); -+#else -+ __raw_writell(datum, map->virt + ofs); -+ mb(); -+#endif /* CFI_B8 */ -+} -+ -+static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -+{ -+ memcpy_fromio(to, map->virt + from, len); -+} -+ -+static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -+{ -+ memcpy_toio(map->virt + to, from, len); -+} -+ -+void simple_map_init(struct map_info *map) -+{ -+ map->read8 = simple_map_read8; -+ map->read16 = simple_map_read16; -+ map->read32 = simple_map_read32; -+ map->read64 = simple_map_read64; -+ map->write8 = simple_map_write8; -+ map->write16 = simple_map_write16; -+ map->write32 = simple_map_write32; -+ map->write64 = simple_map_write64; -+ map->copy_from = simple_map_copy_from; -+ map->copy_to = simple_map_copy_to; -+} -+ -+EXPORT_SYMBOL(simple_map_init); -+ -+MODULE_LICENSE("GPL"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/mbx860.c linux/drivers/mtd/maps/mbx860.c ---- linux-mips-2.4.27/drivers/mtd/maps/mbx860.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/mbx860.c 2004-11-19 10:25:11.933194624 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Handle mapping of the flash on MBX860 boards - * -@@ -15,6 +15,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -36,91 +37,46 @@ - * single flash device into. If the size if zero we use up to the end of the - * device. */ - static struct mtd_partition partition_info[]={ -- { name: "MBX flash BOOT partition", -- offset: 0, -- size: BOOT_PARTITION_SIZE_KiB*1024 }, -- { name: "MBX flash DATA partition", -- offset: BOOT_PARTITION_SIZE_KiB*1024, -- size: (KERNEL_PARTITION_SIZE_KiB)*1024 }, -- { name: "MBX flash APPLICATION partition", -- offset: (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } -+ { .name = "MBX flash BOOT partition", -+ .offset = 0, -+ .size = BOOT_PARTITION_SIZE_KiB*1024 }, -+ { .name = "MBX flash DATA partition", -+ .offset = BOOT_PARTITION_SIZE_KiB*1024, -+ .size = (KERNEL_PARTITION_SIZE_KiB)*1024 }, -+ { .name = "MBX flash APPLICATION partition", -+ .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } - }; - - - static struct mtd_info *mymtd; - --__u8 mbx_read8(struct map_info *map, unsigned long ofs) --{ -- return readb(map->map_priv_1 + ofs); --} -- --__u16 mbx_read16(struct map_info *map, unsigned long ofs) --{ -- return readw(map->map_priv_1 + ofs); --} -- --__u32 mbx_read32(struct map_info *map, unsigned long ofs) --{ -- return readl(map->map_priv_1 + ofs); --} -- --void mbx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); --} -- --void mbx_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- writeb(d, map->map_priv_1 + adr); --} -- --void mbx_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- writew(d, map->map_priv_1 + adr); --} -- --void mbx_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- writel(d, map->map_priv_1 + adr); --} -- --void mbx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio((void *)(map->map_priv_1 + to), from, len); --} -- - struct map_info mbx_map = { -- name: "MBX flash", -- size: WINDOW_SIZE, -- buswidth: 4, -- read8: mbx_read8, -- read16: mbx_read16, -- read32: mbx_read32, -- copy_from: mbx_copy_from, -- write8: mbx_write8, -- write16: mbx_write16, -- write32: mbx_write32, -- copy_to: mbx_copy_to -+ .name = "MBX flash", -+ .size = WINDOW_SIZE, -+ .phys = WINDOW_ADDR, -+ .buswidth = 4, - }; - - int __init init_mbx(void) - { -- printk(KERN_NOTICE "Motorola MBX flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); -- mbx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); -+ printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR); -+ mbx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); - -- if (!mbx_map.map_priv_1) { -+ if (!mbx_map.virt) { - printk("Failed to ioremap\n"); - return -EIO; - } -+ simple_map_init(&mbx_map); -+ - mymtd = do_map_probe("jedec_probe", &mbx_map); - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - add_mtd_device(mymtd); - add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); - return 0; - } - -- iounmap((void *)mbx_map.map_priv_1); -+ iounmap((void *)mbx_map.virt); - return -ENXIO; - } - -@@ -130,9 +86,9 @@ - del_mtd_device(mymtd); - map_destroy(mymtd); - } -- if (mbx_map.map_priv_1) { -- iounmap((void *)mbx_map.map_priv_1); -- mbx_map.map_priv_1 = 0; -+ if (mbx_map.virt) { -+ iounmap((void *)mbx_map.virt); -+ mbx_map.virt = 0; - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/mpc1211.c linux/drivers/mtd/maps/mpc1211.c ---- linux-mips-2.4.27/drivers/mtd/maps/mpc1211.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/mpc1211.c 2004-11-19 10:25:11.934194472 +0100 -@@ -0,0 +1,79 @@ -+/* -+ * Flash on MPC-1211 -+ * -+ * (C) 2002 Interface, Saito.K & Jeanne -+ * -+ * GPL'd -+ */ -+ -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <asm/io.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+#include <linux/config.h> -+ -+static struct mtd_info *flash_mtd; -+static struct mtd_partition *parsed_parts; -+ -+struct map_info mpc1211_flash_map = { -+ .name = "MPC-1211 FLASH", -+ .size = 0x80000, -+ .buswidth = 1, -+}; -+ -+static struct mtd_partition mpc1211_partitions[] = { -+ { -+ .name = "IPL & ETH-BOOT", -+ .offset = 0x00000000, -+ .size = 0x10000, -+ }, -+ { -+ .name = "Flash FS", -+ .offset = 0x00010000, -+ .size = MTDPART_SIZ_FULL, -+ } -+}; -+ -+static int __init init_mpc1211_maps(void) -+{ -+ int nr_parts; -+ -+ mpc1211_flash_map.phys = 0; -+ mpc1211_flash_map.virt = P2SEGADDR(0); -+ -+ simple_map_init(&mpc1211_flash_map); -+ -+ printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); -+ flash_mtd = do_map_probe("jedec_probe", &mpc1211_flash_map); -+ if (!flash_mtd) { -+ printk(KERN_NOTICE "Flash chips not detected at either possible location.\n"); -+ return -ENXIO; -+ } -+ printk(KERN_NOTICE "MPC-1211: Flash at 0x%08lx\n", mpc1211_flash_map.virt & 0x1fffffff); -+ flash_mtd->module = THIS_MODULE; -+ -+ parsed_parts = mpc1211_partitions; -+ nr_parts = ARRAY_SIZE(mpc1211_partitions); -+ -+ add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); -+ return 0; -+} -+ -+static void __exit cleanup_mpc1211_maps(void) -+{ -+ if (parsed_parts) -+ del_mtd_partitions(flash_mtd); -+ else -+ del_mtd_device(flash_mtd); -+ map_destroy(flash_mtd); -+} -+ -+module_init(init_mpc1211_maps); -+module_exit(cleanup_mpc1211_maps); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Saito.K & Jeanne <ksaito@interface.co.jp>"); -+MODULE_DESCRIPTION("MTD map driver for MPC-1211 boards. Interface"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/netsc520.c linux/drivers/mtd/maps/netsc520.c ---- linux-mips-2.4.27/drivers/mtd/maps/netsc520.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/netsc520.c 2004-11-19 10:25:11.935194320 +0100 -@@ -3,7 +3,7 @@ - * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) - * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -27,6 +27,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -50,95 +51,41 @@ - ** recoverable afterwards. - */ - --static __u8 netsc520_read8(struct map_info *map, unsigned long ofs) --{ -- return readb(map->map_priv_1 + ofs); --} -- --static __u16 netsc520_read16(struct map_info *map, unsigned long ofs) --{ -- return readw(map->map_priv_1 + ofs); --} -- --static __u32 netsc520_read32(struct map_info *map, unsigned long ofs) --{ -- return readl(map->map_priv_1 + ofs); --} -- --static void netsc520_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); --} -- --static void netsc520_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- writeb(d, map->map_priv_1 + adr); --} -- --static void netsc520_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- writew(d, map->map_priv_1 + adr); --} -- --static void netsc520_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- writel(d, map->map_priv_1 + adr); --} -- --static void netsc520_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio((void *)(map->map_priv_1 + to), from, len); --} -- - /* partition_info gives details on the logical partitions that the split the - * single flash device into. If the size if zero we use up to the end of the - * device. */ - static struct mtd_partition partition_info[]={ - { -- name: "NetSc520 boot kernel", -- offset: 0, -- size: 0xc0000 -+ .name = "NetSc520 boot kernel", -+ .offset = 0, -+ .size = 0xc0000 - }, - { -- name: "NetSc520 Low BIOS", -- offset: 0xc0000, -- size: 0x40000 -+ .name = "NetSc520 Low BIOS", -+ .offset = 0xc0000, -+ .size = 0x40000 - }, - { -- name: "NetSc520 file system", -- offset: 0x100000, -- size: 0xe80000 -+ .name = "NetSc520 file system", -+ .offset = 0x100000, -+ .size = 0xe80000 - }, - { -- name: "NetSc520 High BIOS", -- offset: 0xf80000, -- size: 0x80000 -+ .name = "NetSc520 High BIOS", -+ .offset = 0xf80000, -+ .size = 0x80000 - }, - }; - #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) - --/* -- * If no idea what is going on here. This is taken from the FlashFX stuff. -- */ --#define ROMCS 1 -- -- - #define WINDOW_SIZE 0x00100000 - #define WINDOW_ADDR 0x00200000 - - static struct map_info netsc520_map = { -- name: "netsc520 Flash Bank", -- size: WINDOW_SIZE, -- buswidth: 4, -- read8: netsc520_read8, -- read16: netsc520_read16, -- read32: netsc520_read32, -- copy_from: netsc520_copy_from, -- write8: netsc520_write8, -- write16: netsc520_write16, -- write32: netsc520_write32, -- copy_to: netsc520_copy_to, -- map_priv_2: WINDOW_ADDR -+ .name = "netsc520 Flash Bank", -+ .size = WINDOW_SIZE, -+ .buswidth = 4, -+ .phys = WINDOW_ADDR, - }; - - #define NUM_FLASH_BANKS (sizeof(netsc520_map)/sizeof(struct map_info)) -@@ -147,13 +94,16 @@ - - static int __init init_netsc520(void) - { -- printk(KERN_NOTICE "NetSc520 flash device: %lx at %lx\n", netsc520_map.size, netsc520_map.map_priv_2); -- netsc520_map.map_priv_1 = (unsigned long)ioremap_nocache(netsc520_map.map_priv_2, netsc520_map.size); -+ printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys); -+ netsc520_map.virt = (unsigned long)ioremap_nocache(netsc520_map.phys, netsc520_map.size); - -- if (!netsc520_map.map_priv_1) { -+ if (!netsc520_map.virt) { - printk("Failed to ioremap_nocache\n"); - return -EIO; - } -+ -+ simple_map_init(&netsc520_map); -+ - mymtd = do_map_probe("cfi_probe", &netsc520_map); - if(!mymtd) - mymtd = do_map_probe("map_ram", &netsc520_map); -@@ -161,11 +111,11 @@ - mymtd = do_map_probe("map_rom", &netsc520_map); - - if (!mymtd) { -- iounmap((void *)netsc520_map.map_priv_1); -+ iounmap((void *)netsc520_map.virt); - return -ENXIO; - } - -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS ); - return 0; - } -@@ -176,9 +126,9 @@ - del_mtd_partitions(mymtd); - map_destroy(mymtd); - } -- if (netsc520_map.map_priv_1) { -- iounmap((void *)netsc520_map.map_priv_1); -- netsc520_map.map_priv_1 = 0; -+ if (netsc520_map.virt) { -+ iounmap((void *)netsc520_map.virt); -+ netsc520_map.virt = 0; - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/nettel.c linux/drivers/mtd/maps/nettel.c ---- linux-mips-2.4.27/drivers/mtd/maps/nettel.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/nettel.c 2004-11-19 10:25:11.937194016 +0100 -@@ -6,7 +6,7 @@ - * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) - * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) - * -- * $Id$ -+ * $Id$ - */ - - /****************************************************************************/ -@@ -59,128 +59,72 @@ - - /****************************************************************************/ - --static __u8 nettel_read8(struct map_info *map, unsigned long ofs) --{ -- return(readb(map->map_priv_1 + ofs)); --} -- --static __u16 nettel_read16(struct map_info *map, unsigned long ofs) --{ -- return(readw(map->map_priv_1 + ofs)); --} -- --static __u32 nettel_read32(struct map_info *map, unsigned long ofs) --{ -- return(readl(map->map_priv_1 + ofs)); --} -- --static void nettel_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --static void nettel_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- writeb(d, map->map_priv_1 + adr); --} -- --static void nettel_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- writew(d, map->map_priv_1 + adr); --} -- --static void nettel_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- writel(d, map->map_priv_1 + adr); --} -- --static void nettel_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} -- - /****************************************************************************/ - - #ifdef CONFIG_MTD_CFI_INTELEXT - static struct map_info nettel_intel_map = { -- name: "SnapGear Intel", -- size: 0, -- buswidth: INTEL_BUSWIDTH, -- read8: nettel_read8, -- read16: nettel_read16, -- read32: nettel_read32, -- copy_from: nettel_copy_from, -- write8: nettel_write8, -- write16: nettel_write16, -- write32: nettel_write32, -- copy_to: nettel_copy_to -+ .name = "SnapGear Intel", -+ .size = 0, -+ .buswidth = INTEL_BUSWIDTH, - }; - - static struct mtd_partition nettel_intel_partitions[] = { - { -- name: "SnapGear kernel", -- offset: 0, -- size: 0x000e0000 -+ .name = "SnapGear kernel", -+ .offset = 0, -+ .size = 0x000e0000 - }, - { -- name: "SnapGear filesystem", -- offset: 0x00100000, -+ .name = "SnapGear filesystem", -+ .offset = 0x00100000, - }, - { -- name: "SnapGear config", -- offset: 0x000e0000, -- size: 0x00020000 -+ .name = "SnapGear config", -+ .offset = 0x000e0000, -+ .size = 0x00020000 - }, - { -- name: "SnapGear Intel", -- offset: 0 -+ .name = "SnapGear Intel", -+ .offset = 0 - }, - { -- name: "SnapGear BIOS Config", -- offset: 0x007e0000, -- size: 0x00020000 -+ .name = "SnapGear BIOS Config", -+ .offset = 0x007e0000, -+ .size = 0x00020000 - }, - { -- name: "SnapGear BIOS", -- offset: 0x007e0000, -- size: 0x00020000 -+ .name = "SnapGear BIOS", -+ .offset = 0x007e0000, -+ .size = 0x00020000 - }, - }; - #endif - - static struct map_info nettel_amd_map = { -- name: "SnapGear AMD", -- size: AMD_WINDOW_MAXSIZE, -- buswidth: AMD_BUSWIDTH, -- read8: nettel_read8, -- read16: nettel_read16, -- read32: nettel_read32, -- copy_from: nettel_copy_from, -- write8: nettel_write8, -- write16: nettel_write16, -- write32: nettel_write32, -- copy_to: nettel_copy_to -+ .name = "SnapGear AMD", -+ .size = AMD_WINDOW_MAXSIZE, -+ .buswidth = AMD_BUSWIDTH, - }; - - static struct mtd_partition nettel_amd_partitions[] = { - { -- name: "SnapGear BIOS config", -- offset: 0x000e0000, -- size: 0x00010000 -+ .name = "SnapGear BIOS config", -+ .offset = 0x000e0000, -+ .size = 0x00010000 - }, - { -- name: "SnapGear BIOS", -- offset: 0x000f0000, -- size: 0x00010000 -+ .name = "SnapGear BIOS", -+ .offset = 0x000f0000, -+ .size = 0x00010000 - }, - { -- name: "SnapGear AMD", -- offset: 0 -+ .name = "SnapGear AMD", -+ .offset = 0 - }, - { -- name: "SnapGear high BIOS", -- offset: 0x001f0000, -- size: 0x00010000 -+ .name = "SnapGear high BIOS", -+ .offset = 0x001f0000, -+ .size = 0x00010000 - } - }; - -@@ -328,18 +272,20 @@ - *amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize); - __asm__ ("wbinvd"); - -- nettel_amd_map.map_priv_1 = (unsigned long) -+ nettel_amd_map.phys = amdaddr; -+ nettel_amd_map.virt = (unsigned long) - ioremap_nocache(amdaddr, maxsize); -- if (!nettel_amd_map.map_priv_1) { -+ if (!nettel_amd_map.virt) { - printk("SNAPGEAR: failed to ioremap() BOOTCS\n"); - return(-EIO); - } -+ simple_map_init(&nettel_amd_map); - - if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) { - printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n", - amd_mtd->size>>10); - -- amd_mtd->module = THIS_MODULE; -+ amd_mtd->owner = THIS_MODULE; - - /* The high BIOS partition is only present for 2MB units */ - num_amd_partitions = NUM_AMD_PARTITIONS; -@@ -387,8 +333,8 @@ - - /* Destroy useless AMD MTD mapping */ - amd_mtd = NULL; -- iounmap((void *) nettel_amd_map.map_priv_1); -- nettel_amd_map.map_priv_1 = (unsigned long) NULL; -+ iounmap((void *) nettel_amd_map.virt); -+ nettel_amd_map.virt = (unsigned long) NULL; - #else - /* Only AMD flash supported */ - return(-ENXIO); -@@ -411,16 +357,18 @@ - - /* Probe for the the size of the first Intel flash */ - nettel_intel_map.size = maxsize; -- nettel_intel_map.map_priv_1 = (unsigned long) -+ nettel_intel_map.phys = intel0addr; -+ nettel_intel_map.virt = (unsigned long) - ioremap_nocache(intel0addr, maxsize); -- if (!nettel_intel_map.map_priv_1) { -+ if (!nettel_intel_map.virt) { - printk("SNAPGEAR: failed to ioremap() ROMCS1\n"); - return(-EIO); - } -+ simple_map_init(&nettel_intel_map); - - intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map); - if (! intel_mtd) { -- iounmap((void *) nettel_intel_map.map_priv_1); -+ iounmap((void *) nettel_intel_map.virt); - return(-ENXIO); - } - -@@ -441,19 +389,19 @@ - /* Delete the old map and probe again to do both chips */ - map_destroy(intel_mtd); - intel_mtd = NULL; -- iounmap((void *) nettel_intel_map.map_priv_1); -+ iounmap((void *) nettel_intel_map.virt); - - nettel_intel_map.size = maxsize; -- nettel_intel_map.map_priv_1 = (unsigned long) -+ nettel_intel_map.virt = (unsigned long) - ioremap_nocache(intel0addr, maxsize); -- if (!nettel_intel_map.map_priv_1) { -+ if (!nettel_intel_map.virt) { - printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n"); - return(-EIO); - } - - intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map); - if (! intel_mtd) { -- iounmap((void *) nettel_intel_map.map_priv_1); -+ iounmap((void *) nettel_intel_map.virt); - return(-ENXIO); - } - -@@ -468,7 +416,7 @@ - printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n", - (intel_mtd->size >> 10)); - -- intel_mtd->module = THIS_MODULE; -+ intel_mtd->owner = THIS_MODULE; - - #ifndef CONFIG_BLK_DEV_INITRD - ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1); -@@ -523,18 +471,18 @@ - del_mtd_partitions(amd_mtd); - map_destroy(amd_mtd); - } -- if (nettel_amd_map.map_priv_1) { -- iounmap((void *)nettel_amd_map.map_priv_1); -- nettel_amd_map.map_priv_1 = 0; -+ if (nettel_amd_map.virt) { -+ iounmap((void *)nettel_amd_map.virt); -+ nettel_amd_map.virt = 0; - } - #ifdef CONFIG_MTD_CFI_INTELEXT - if (intel_mtd) { - del_mtd_partitions(intel_mtd); - map_destroy(intel_mtd); - } -- if (nettel_intel_map.map_priv_1) { -- iounmap((void *)nettel_intel_map.map_priv_1); -- nettel_intel_map.map_priv_1 = 0; -+ if (nettel_intel_map.virt) { -+ iounmap((void *)nettel_intel_map.virt); -+ nettel_intel_map.virt = 0; - } - #endif - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/ocelot.c linux/drivers/mtd/maps/ocelot.c ---- linux-mips-2.4.27/drivers/mtd/maps/ocelot.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/ocelot.c 2004-11-19 10:25:11.938193864 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Flash on Momenco Ocelot - */ -@@ -7,6 +7,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -20,47 +21,23 @@ - #define NVRAM_WINDOW_SIZE 0x00007FF0 - #define NVRAM_BUSWIDTH 1 - --extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -- - static unsigned int cacheflush = 0; - - static struct mtd_info *flash_mtd; - static struct mtd_info *nvram_mtd; - --__u8 ocelot_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --void ocelot_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- cacheflush = 1; -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void ocelot_copy_from_cache(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- if (cacheflush) { -- dma_cache_inv(map->map_priv_2, map->size); -- cacheflush = 0; -- } -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void ocelot_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -+static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) - { -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -+ struct map_info *map = (struct map_info *)mtd->priv; -+ size_t done = 0; - --void ocelot_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ - /* If we use memcpy, it does word-wide writes. Even though we told the - GT64120A that it's an 8-bit wide region, word-wide writes don't work. - We end up just writing the first byte of the four to all four bytes. - So we have this loop instead */ -+ *retlen = len; - while(len) { -- __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); -+ __raw_writeb(*(unsigned char *) from, map->virt + to); - from++; - to++; - len--; -@@ -70,24 +47,21 @@ - static struct mtd_partition *parsed_parts; - - struct map_info ocelot_flash_map = { -- name: "Ocelot boot flash", -- size: FLASH_WINDOW_SIZE, -- buswidth: FLASH_BUSWIDTH, -- read8: ocelot_read8, -- copy_from: ocelot_copy_from_cache, -- write8: ocelot_write8, -+ .name = "Ocelot boot flash", -+ .size = FLASH_WINDOW_SIZE, -+ .buswidth = FLASH_BUSWIDTH, -+ .phys = FLASH_WINDOW_ADDR, - }; - - struct map_info ocelot_nvram_map = { -- name: "Ocelot NVRAM", -- size: NVRAM_WINDOW_SIZE, -- buswidth: NVRAM_BUSWIDTH, -- read8: ocelot_read8, -- copy_from: ocelot_copy_from, -- write8: ocelot_write8, -- copy_to: ocelot_copy_to -+ .name = "Ocelot NVRAM", -+ .size = NVRAM_WINDOW_SIZE, -+ .buswidth = NVRAM_BUSWIDTH, -+ .phys = NVRAM_WINDOW_ADDR, - }; - -+static const char *probes[] = { "RedBoot", NULL }; -+ - static int __init init_ocelot_maps(void) - { - void *pld; -@@ -107,12 +81,13 @@ - iounmap(pld); - - /* Now ioremap the NVRAM space */ -- ocelot_nvram_map.map_priv_1 = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); -- if (!ocelot_nvram_map.map_priv_1) { -+ ocelot_nvram_map.virt = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); -+ if (!ocelot_nvram_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n"); - return -EIO; - } -- // ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1; -+ -+ simple_map_init(&ocelot_nvram_map); - - /* And do the RAM probe on it to get an MTD device */ - nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map); -@@ -120,22 +95,21 @@ - printk("NVRAM probe failed\n"); - goto fail_1; - } -- nvram_mtd->module = THIS_MODULE; -+ nvram_mtd->owner = THIS_MODULE; - nvram_mtd->erasesize = 16; -+ /* Override the write() method */ -+ nvram_mtd->write = ocelot_ram_write; - - /* Now map the flash space */ -- ocelot_flash_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); -- if (!ocelot_flash_map.map_priv_1) { -+ ocelot_flash_map.virt = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); -+ if (!ocelot_flash_map.virt) { - printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n"); - goto fail_2; - } - /* Now the cached version */ -- ocelot_flash_map.map_priv_2 = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0); -+ ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0); - -- if (!ocelot_flash_map.map_priv_2) { -- /* Doesn't matter if it failed. Just use the uncached version */ -- ocelot_flash_map.map_priv_2 = ocelot_flash_map.map_priv_1; -- } -+ simple_map_init(&ocelot_flash_map); - - /* Only probe for flash if the write jumper is present */ - if (brd_status & 0x40) { -@@ -155,10 +129,10 @@ - - add_mtd_device(nvram_mtd); - -- flash_mtd->module = THIS_MODULE; -- nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); -+ flash_mtd->owner = THIS_MODULE; -+ nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - -- if (nr_parts) -+ if (nr_parts > 0) - add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); - else - add_mtd_device(flash_mtd); -@@ -166,14 +140,13 @@ - return 0; - - fail3: -- iounmap((void *)ocelot_flash_map.map_priv_1); -- if (ocelot_flash_map.map_priv_2 && -- ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1) -- iounmap((void *)ocelot_flash_map.map_priv_2); -+ iounmap((void *)ocelot_flash_map.virt); -+ if (ocelot_flash_map.cached) -+ iounmap((void *)ocelot_flash_map.cached); - fail_2: - map_destroy(nvram_mtd); - fail_1: -- iounmap((void *)ocelot_nvram_map.map_priv_1); -+ iounmap((void *)ocelot_nvram_map.virt); - - return -ENXIO; - } -@@ -182,16 +155,16 @@ - { - del_mtd_device(nvram_mtd); - map_destroy(nvram_mtd); -- iounmap((void *)ocelot_nvram_map.map_priv_1); -+ iounmap((void *)ocelot_nvram_map.virt); - - if (parsed_parts) - del_mtd_partitions(flash_mtd); - else - del_mtd_device(flash_mtd); - map_destroy(flash_mtd); -- iounmap((void *)ocelot_flash_map.map_priv_1); -- if (ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1) -- iounmap((void *)ocelot_flash_map.map_priv_2); -+ iounmap((void *)ocelot_flash_map.virt); -+ if (ocelot_flash_map.cached) -+ iounmap((void *)ocelot_flash_map.cached); - } - - module_init(init_ocelot_maps); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/octagon-5066.c linux/drivers/mtd/maps/octagon-5066.c ---- linux-mips-2.4.27/drivers/mtd/maps/octagon-5066.c 2003-08-13 19:19:18.000000000 +0200 -+++ linux/drivers/mtd/maps/octagon-5066.c 2004-11-19 10:25:11.940193560 +0100 -@@ -1,4 +1,4 @@ --// $Id$ -+// $Id$ - /* ###################################################################### - - Octagon 5066 MTD Driver. -@@ -31,6 +31,7 @@ - #include <asm/io.h> - - #include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> - - #define WINDOW_START 0xe8000 - #define WINDOW_LENGTH 0x8000 -@@ -151,32 +152,34 @@ - - static struct map_info oct5066_map[2] = { - { -- name: "Octagon 5066 Socket", -- size: 512 * 1024, -- buswidth: 1, -- read8: oct5066_read8, -- read16: oct5066_read16, -- read32: oct5066_read32, -- copy_from: oct5066_copy_from, -- write8: oct5066_write8, -- write16: oct5066_write16, -- write32: oct5066_write32, -- copy_to: oct5066_copy_to, -- map_priv_1: 1<<6 -+ .name = "Octagon 5066 Socket", -+ .phys = NO_XIP, -+ .size = 512 * 1024, -+ .buswidth = 1, -+ .read8 = oct5066_read8, -+ .read16 = oct5066_read16, -+ .read32 = oct5066_read32, -+ .copy_from = oct5066_copy_from, -+ .write8 = oct5066_write8, -+ .write16 = oct5066_write16, -+ .write32 = oct5066_write32, -+ .copy_to = oct5066_copy_to, -+ .map_priv_1 = 1<<6 - }, - { -- name: "Octagon 5066 Internal Flash", -- size: 2 * 1024 * 1024, -- buswidth: 1, -- read8: oct5066_read8, -- read16: oct5066_read16, -- read32: oct5066_read32, -- copy_from: oct5066_copy_from, -- write8: oct5066_write8, -- write16: oct5066_write16, -- write32: oct5066_write32, -- copy_to: oct5066_copy_to, -- map_priv_1: 2<<6 -+ .name = "Octagon 5066 Internal Flash", -+ .phys = NO_XIP, -+ .size = 2 * 1024 * 1024, -+ .buswidth = 1, -+ .read8 = oct5066_read8, -+ .read16 = oct5066_read16, -+ .read32 = oct5066_read32, -+ .copy_from = oct5066_copy_from, -+ .write8 = oct5066_write8, -+ .write16 = oct5066_write16, -+ .write32 = oct5066_write32, -+ .copy_to = oct5066_copy_to, -+ .map_priv_1 = 2<<6 - } - }; - -@@ -244,6 +247,7 @@ - } - if (OctProbe() != 0) { - printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n"); -+ iounmap((void *)iomapadr); - ret = -EAGAIN; - goto out_unmap; - } -@@ -261,7 +265,7 @@ - if (!oct5066_mtd[i]) - oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]); - if (oct5066_mtd[i]) { -- oct5066_mtd[i]->module = THIS_MODULE; -+ oct5066_mtd[i]->owner = THIS_MODULE; - add_mtd_device(oct5066_mtd[i]); - } - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/omap-toto-flash.c linux/drivers/mtd/maps/omap-toto-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/omap-toto-flash.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/omap-toto-flash.c 2004-11-19 10:25:11.941193408 +0100 -@@ -0,0 +1,137 @@ -+/* -+ * NOR Flash memory access on TI Toto board -+ * -+ * jzhang@ti.com (C) 2003 Texas Instruments. -+ * -+ * (C) 2002 MontVista Software, Inc. -+ * -+ * $Id$ -+ */ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+ -+#include <linux/errno.h> -+#include <linux/init.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+ -+#include <asm/hardware.h> -+#include <asm/io.h> -+ -+ -+#ifndef CONFIG_ARCH_OMAP -+#error This is for OMAP architecture only -+#endif -+ -+//these lines need be moved to a hardware header file -+#define OMAP_TOTO_FLASH_BASE 0xd8000000 -+#define OMAP_TOTO_FLASH_SIZE 0x80000 -+ -+static struct map_info omap_toto_map_flash = { -+ .name = "OMAP Toto flash", -+ .buswidth = 2, -+ .virt = OMAP_TOTO_FLASH_BASE, -+}; -+ -+ -+static struct mtd_partition toto_flash_partitions[] = { -+ { -+ .name = "BootLoader", -+ .size = 0x00040000, /* hopefully u-boot will stay 128k + 128*/ -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "ReservedSpace", -+ .size = 0x00030000, -+ .offset = MTDPART_OFS_APPEND, -+ //mask_flags: MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "EnvArea", /* bottom 64KiB for env vars */ -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, -+ } -+}; -+ -+static struct mtd_partition *parsed_parts; -+ -+static struct mtd_info *flash_mtd; -+ -+static int __init init_flash (void) -+{ -+ -+ struct mtd_partition *parts; -+ int nb_parts = 0; -+ int parsed_nr_parts = 0; -+ const char *part_type; -+ -+ /* -+ * Static partition definition selection -+ */ -+ part_type = "static"; -+ -+ parts = toto_flash_partitions; -+ nb_parts = ARRAY_SIZE(toto_flash_partitions); -+ omap_toto_map_flash.size = OMAP_TOTO_FLASH_SIZE; -+ omap_toto_map_flash.phys = virt_to_phys(OMAP_TOTO_FLASH_BASE); -+ -+ simple_map_init(&omap_toto_map_flash); -+ /* -+ * Now let's probe for the actual flash. Do it here since -+ * specific machine settings might have been set above. -+ */ -+ printk(KERN_NOTICE "OMAP toto flash: probing %d-bit flash bus\n", -+ omap_toto_map_flash.buswidth*8); -+ flash_mtd = do_map_probe("jedec_probe", &omap_toto_map_flash); -+ if (!flash_mtd) -+ return -ENXIO; -+ -+ if (parsed_nr_parts > 0) { -+ parts = parsed_parts; -+ nb_parts = parsed_nr_parts; -+ } -+ -+ if (nb_parts == 0) { -+ printk(KERN_NOTICE "OMAP toto flash: no partition info available," -+ "registering whole flash at once\n"); -+ if (add_mtd_device(flash_mtd)){ -+ return -ENXIO; -+ } -+ } else { -+ printk(KERN_NOTICE "Using %s partition definition\n", -+ part_type); -+ return add_mtd_partitions(flash_mtd, parts, nb_parts); -+ } -+ return 0; -+} -+ -+int __init omap_toto_mtd_init(void) -+{ -+ int status; -+ -+ if (status = init_flash()) { -+ printk(KERN_ERR "OMAP Toto Flash: unable to init map for toto flash\n"); -+ } -+ return status; -+} -+ -+static void __exit omap_toto_mtd_cleanup(void) -+{ -+ if (flash_mtd) { -+ del_mtd_partitions(flash_mtd); -+ map_destroy(flash_mtd); -+ if (parsed_parts) -+ kfree(parsed_parts); -+ } -+} -+ -+module_init(omap_toto_mtd_init); -+module_exit(omap_toto_mtd_cleanup); -+ -+MODULE_AUTHOR("Jian Zhang"); -+MODULE_DESCRIPTION("OMAP Toto board map driver"); -+MODULE_LICENSE("GPL"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/pb1xxx-flash.c linux/drivers/mtd/maps/pb1xxx-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/pb1xxx-flash.c 2003-05-19 08:27:22.000000000 +0200 -+++ linux/drivers/mtd/maps/pb1xxx-flash.c 2004-11-19 10:25:11.943193104 +0100 -@@ -3,12 +3,13 @@ - * - * (C) 2001 Pete Popov <ppopov@mvista.com> - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/config.h> - #include <linux/module.h> - #include <linux/types.h> -+#include <linux/init.h> - #include <linux/kernel.h> - - #include <linux/mtd/mtd.h> -@@ -25,210 +26,110 @@ - #endif - - #ifdef CONFIG_MIPS_PB1000 -+ - #define WINDOW_ADDR 0x1F800000 - #define WINDOW_SIZE 0x800000 --#endif -- --__u8 physmap_read8(struct map_info *map, unsigned long ofs) --{ -- __u8 ret; -- ret = __raw_readb(map->map_priv_1 + ofs); -- DBG("read8 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); -- return ret; --} -- --__u16 physmap_read16(struct map_info *map, unsigned long ofs) --{ -- __u16 ret; -- ret = __raw_readw(map->map_priv_1 + ofs); -- DBG("read16 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); -- return ret; --} -- --__u32 physmap_read32(struct map_info *map, unsigned long ofs) --{ -- __u32 ret; -- ret = __raw_readl(map->map_priv_1 + ofs); -- DBG("read32 from %x, %x\n", (unsigned)(map->map_priv_1 + ofs), ret); -- return ret; --} -- --void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- DBG("physmap_copy from %x to %x\n", (unsigned)from, (unsigned)to); -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- DBG("write8 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- DBG("write16 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- DBG("write32 at %x, %x\n", (unsigned)(map->map_priv_1 + adr), d); -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- DBG("physmap_copy_to %x from %x\n", (unsigned)to, (unsigned)from); -- memcpy_toio(map->map_priv_1 + to, from, len); --} -- -- -- --static struct map_info pb1xxx_map = { -- name: "Pb1xxx flash", -- read8: physmap_read8, -- read16: physmap_read16, -- read32: physmap_read32, -- copy_from: physmap_copy_from, -- write8: physmap_write8, -- write16: physmap_write16, -- write32: physmap_write32, -- copy_to: physmap_copy_to, --}; - -- --#ifdef CONFIG_MIPS_PB1000 -- --static unsigned long flash_size = 0x00800000; --static unsigned char flash_buswidth = 4; - static struct mtd_partition pb1xxx_partitions[] = { - { -- name: "yamon env", -- size: 0x00020000, -- offset: 0, -- mask_flags: MTD_WRITEABLE -- },{ -- name: "User FS", -- size: 0x003e0000, -- offset: 0x20000, -- },{ -- name: "boot code", -- size: 0x100000, -- offset: 0x400000, -- mask_flags: MTD_WRITEABLE -- },{ -- name: "raw/kernel", -- size: 0x300000, -- offset: 0x500000 -- } -+ .name = "yamon env", -+ .size = 0x00020000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE}, -+ { -+ .name = "User FS", -+ .size = 0x003e0000, -+ .offset = 0x20000,}, -+ { -+ .name = "boot code", -+ .size = 0x100000, -+ .offset = 0x400000, -+ .mask_flags = MTD_WRITEABLE}, -+ { -+ .name = "raw/kernel", -+ .size = 0x300000, -+ .offset = 0x500000} - }; - - #elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) - --static unsigned char flash_buswidth = 4; - #if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) --/* both 32MiB banks will be used. Combine the first 32MiB bank and the -- * first 28MiB of the second bank together into a single jffs/jffs2 -+/* both 32MB banks will be used. Combine the first 32MB bank and the -+ * first 28MB of the second bank together into a single jffs/jffs2 - * partition. - */ --static unsigned long flash_size = 0x04000000; - #define WINDOW_ADDR 0x1C000000 - #define WINDOW_SIZE 0x4000000 - static struct mtd_partition pb1xxx_partitions[] = { - { -- name: "User FS", -- size: 0x3c00000, -- offset: 0x0000000 -- },{ -- name: "yamon", -- size: 0x0100000, -- offset: 0x3c00000, -- mask_flags: MTD_WRITEABLE -- },{ -- name: "raw kernel", -- size: 0x02c0000, -- offset: 0x3d00000 -+ .name = "User FS", -+ .size = 0x3c00000, -+ .offset = 0x0000000 -+ },{ -+ .name = "yamon", -+ .size = 0x0100000, -+ .offset = 0x3c00000, -+ .mask_flags = MTD_WRITEABLE -+ },{ -+ .name = "raw kernel", -+ .size = 0x02c0000, -+ .offset = 0x3d00000 - } - }; - #elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) --static unsigned long flash_size = 0x02000000; - #define WINDOW_ADDR 0x1E000000 - #define WINDOW_SIZE 0x2000000 - static struct mtd_partition pb1xxx_partitions[] = { - { -- name: "User FS", -- size: 0x1c00000, -- offset: 0x0000000 -- },{ -- name: "yamon", -- size: 0x0100000, -- offset: 0x1c00000, -- mask_flags: MTD_WRITEABLE -- },{ -- name: "raw kernel", -- size: 0x02c0000, -- offset: 0x1d00000 -+ .name = "User FS", -+ .size = 0x1c00000, -+ .offset = 0x0000000 -+ },{ -+ .name = "yamon", -+ .size = 0x0100000, -+ .offset = 0x1c00000, -+ .mask_flags = MTD_WRITEABLE -+ },{ -+ .name = "raw kernel", -+ .size = 0x02c0000, -+ .offset = 0x1d00000 - } - }; - #elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) --static unsigned long flash_size = 0x02000000; - #define WINDOW_ADDR 0x1C000000 - #define WINDOW_SIZE 0x2000000 - static struct mtd_partition pb1xxx_partitions[] = { - { -- name: "User FS", -- size: 0x1e00000, -- offset: 0x0000000 -- },{ -- name: "raw kernel", -- size: 0x0200000, -- offset: 0x1e00000, -+ .name = "User FS", -+ .size = 0x1e00000, -+ .offset = 0x0000000 -+ },{ -+ .name = "raw kernel", -+ .size = 0x0200000, -+ .offset = 0x1e00000, - } - }; - #else - #error MTD_PB1500 define combo error /* should never happen */ - #endif --#elif defined(CONFIG_MTD_BOSPORUS) --static unsigned char flash_buswidth = 2; --static unsigned long flash_size = 0x02000000; --#define WINDOW_ADDR 0x1F000000 --#define WINDOW_SIZE 0x2000000 --static struct mtd_partition pb1xxx_partitions[] = { -- { -- name: "User FS", -- size: 0x00400000, -- offset: 0x00000000, -- },{ -- name: "Yamon-2", -- size: 0x00100000, -- offset: 0x00400000, -- },{ -- name: "Root FS", -- size: 0x00700000, -- offset: 0x00500000, -- },{ -- name: "Yamon-1", -- size: 0x00100000, -- offset: 0x00C00000, -- },{ -- name: "Kernel", -- size: 0x00300000, -- offset: 0x00D00000, -- } --}; - #else - #error Unsupported board - #endif - -+#define NAME "Pb1x00 Linux Flash" -+#define PADDR WINDOW_ADDR -+#define BUSWIDTH 4 -+#define SIZE WINDOW_SIZE -+#define PARTITIONS 4 -+ -+static struct map_info pb1xxx_mtd_map = { -+ .name = NAME, -+ .size = SIZE, -+ .buswidth = BUSWIDTH, -+ .phys = PADDR, -+}; - --#define NB_OF(x) (sizeof(x)/sizeof(x[0])) -- --static struct mtd_partition *parsed_parts; --static struct mtd_info *mymtd; -+static struct mtd_info *pb1xxx_mtd; - - int __init pb1xxx_mtd_init(void) - { -@@ -236,40 +137,37 @@ - int nb_parts = 0; - char *part_type; - -- /* Default flash buswidth */ -- pb1xxx_map.buswidth = flash_buswidth; -- - /* - * Static partition definition selection - */ - part_type = "static"; - parts = pb1xxx_partitions; -- nb_parts = NB_OF(pb1xxx_partitions); -- pb1xxx_map.size = flash_size; -+ nb_parts = ARRAY_SIZE(pb1xxx_partitions); - - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ - printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n", -- pb1xxx_map.buswidth*8); -- pb1xxx_map.map_priv_1 = -- (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); -- mymtd = do_map_probe("cfi_probe", &pb1xxx_map); -- if (!mymtd) return -ENXIO; -- mymtd->module = THIS_MODULE; -+ BUSWIDTH*8); -+ pb1xxx_mtd_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); -+ -+ simple_map_init(&pb1xxx_mtd_map); -+ -+ pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map); -+ if (!pb1xxx_mtd) return -ENXIO; -+ pb1xxx_mtd->owner = THIS_MODULE; - -- add_mtd_partitions(mymtd, parts, nb_parts); -+ add_mtd_partitions(pb1xxx_mtd, parts, nb_parts); - return 0; - } - - static void __exit pb1xxx_mtd_cleanup(void) - { -- if (mymtd) { -- del_mtd_partitions(mymtd); -- map_destroy(mymtd); -- if (parsed_parts) -- kfree(parsed_parts); -+ if (pb1xxx_mtd) { -+ del_mtd_partitions(pb1xxx_mtd); -+ map_destroy(pb1xxx_mtd); -+ iounmap((void *) pb1xxx_mtd_map.virt); - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/pci.c linux/drivers/mtd/maps/pci.c ---- linux-mips-2.4.27/drivers/mtd/maps/pci.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/pci.c 2004-11-19 10:25:11.944192952 +0100 -@@ -7,7 +7,7 @@ - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * -- * $Id$ -+ * $Id$ - * - * Generic PCI memory map driver. We support the following boards: - * - Intel IQ80310 ATU. -@@ -98,10 +98,10 @@ - } - - static struct mtd_pci_info intel_iq80310_info = { -- init: intel_iq80310_init, -- exit: intel_iq80310_exit, -- translate: intel_iq80310_translate, -- map_name: "cfi_probe", -+ .init = intel_iq80310_init, -+ .exit = intel_iq80310_exit, -+ .translate = intel_iq80310_translate, -+ .map_name = "cfi_probe", - }; - - /* -@@ -181,10 +181,10 @@ - } - - static struct mtd_pci_info intel_dc21285_info = { -- init: intel_dc21285_init, -- exit: intel_dc21285_exit, -- translate: intel_dc21285_translate, -- map_name: "jedec_probe", -+ .init = intel_dc21285_init, -+ .exit = intel_dc21285_exit, -+ .translate = intel_dc21285_translate, -+ .map_name = "jedec_probe", - }; - - /* -@@ -193,22 +193,20 @@ - - static struct pci_device_id mtd_pci_ids[] __devinitdata = { - { -- vendor: PCI_VENDOR_ID_INTEL, -- device: 0x530d, -- subvendor: PCI_ANY_ID, -- subdevice: PCI_ANY_ID, -- class: PCI_CLASS_MEMORY_OTHER << 8, -- class_mask: 0xffff00, -- driver_data: (unsigned long)&intel_iq80310_info, -+ .vendor = PCI_VENDOR_ID_INTEL, -+ .device = 0x530d, -+ .subvendor = PCI_ANY_ID, -+ .subdevice = PCI_ANY_ID, -+ .class = PCI_CLASS_MEMORY_OTHER << 8, -+ .class_mask = 0xffff00, -+ .driver_data = (unsigned long)&intel_iq80310_info, - }, - { -- vendor: PCI_VENDOR_ID_DEC, -- device: PCI_DEVICE_ID_DEC_21285, -- subvendor: 0, /* DC21285 defaults to 0 on reset */ -- subdevice: 0, /* DC21285 defaults to 0 on reset */ -- class: 0, -- class_mask: 0, -- driver_data: (unsigned long)&intel_dc21285_info, -+ .vendor = PCI_VENDOR_ID_DEC, -+ .device = PCI_DEVICE_ID_DEC_21285, -+ .subvendor = 0, /* DC21285 defaults to 0 on reset */ -+ .subdevice = 0, /* DC21285 defaults to 0 on reset */ -+ .driver_data = (unsigned long)&intel_dc21285_info, - }, - { 0, } - }; -@@ -275,14 +273,15 @@ - } - - static struct map_info mtd_pci_map = { -- read8: mtd_pci_read8, -- read16: mtd_pci_read16, -- read32: mtd_pci_read32, -- copy_from: mtd_pci_copyfrom, -- write8: mtd_pci_write8, -- write16: mtd_pci_write16, -- write32: mtd_pci_write32, -- copy_to: mtd_pci_copyto, -+ .phys = NO_XIP, -+ .read8 = mtd_pci_read8, -+ .read16 = mtd_pci_read16, -+ .read32 = mtd_pci_read32, -+ .copy_from = mtd_pci_copyfrom, -+ .write8 = mtd_pci_write8, -+ .write16 = mtd_pci_write16, -+ .write32 = mtd_pci_write32, -+ .copy_to = mtd_pci_copyto, - }; - - static int __devinit -@@ -322,7 +321,7 @@ - if (!mtd) - goto release; - -- mtd->module = THIS_MODULE; -+ mtd->owner = THIS_MODULE; - add_mtd_device(mtd); - - pci_set_drvdata(dev, mtd); -@@ -359,10 +358,10 @@ - } - - static struct pci_driver mtd_pci_driver = { -- name: "MTD PCI", -- probe: mtd_pci_probe, -- remove: __devexit_p(mtd_pci_remove), -- id_table: mtd_pci_ids, -+ .name = "MTD PCI", -+ .probe = mtd_pci_probe, -+ .remove = __devexit_p(mtd_pci_remove), -+ .id_table = mtd_pci_ids, - }; - - static int __init mtd_pci_maps_init(void) -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/pcmciamtd.c linux/drivers/mtd/maps/pcmciamtd.c ---- linux-mips-2.4.27/drivers/mtd/maps/pcmciamtd.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/maps/pcmciamtd.c 2004-11-19 10:25:11.946192648 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * pcmciamtd.c - MTD driver for PCMCIA flash memory cards - * -@@ -14,6 +14,7 @@ - #include <linux/module.h> - #include <linux/slab.h> - #include <linux/timer.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <asm/system.h> - -@@ -24,6 +25,7 @@ - #include <pcmcia/ds.h> - - #include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> - - #ifdef CONFIG_MTD_DEBUG - static int debug = CONFIG_MTD_DEBUG_VERBOSE; -@@ -47,7 +49,7 @@ - - - #define DRIVER_DESC "PCMCIA Flash memory card driver" --#define DRIVER_VERSION "$Revision$" -+#define DRIVER_VERSION "$Revision$" - - /* Size of the PCMCIA address space: 26 bits = 64 MB */ - #define MAX_PCMCIA_ADDR 0x4000000 -@@ -96,7 +98,7 @@ - MODULE_PARM(mem_speed, "i"); - MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns"); - MODULE_PARM(force_size, "i"); --MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)"); -+MODULE_PARM_DESC(force_size, "Force size of card in MiB (1-64)"); - MODULE_PARM(setvpp, "i"); - MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)"); - MODULE_PARM(vpp, "i"); -@@ -106,11 +108,13 @@ - - - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69) - static inline void cs_error(client_handle_t handle, int func, int ret) - { - error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); - } -+#endif - - - /* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */ -@@ -529,6 +533,7 @@ - - card_settings(dev, link, &new_name); - -+ dev->pcmcia_map.phys = NO_XIP; - dev->pcmcia_map.read8 = pcmcia_read8_remap; - dev->pcmcia_map.read16 = pcmcia_read16_remap; - dev->pcmcia_map.copy_from = pcmcia_copy_from_remap; -@@ -539,7 +544,7 @@ - dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp; - - /* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum -- that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the -+ that PCMCIA can support (64MiB) - this is ideal and we aim for a window the size of the - whole card - otherwise we try smaller windows until we succeed */ - - req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE; -@@ -552,7 +557,7 @@ - - do { - int ret; -- DEBUG(2, "requesting window with size = %dKB memspeed = %d", -+ DEBUG(2, "requesting window with size = %dKiB memspeed = %d", - req.Size >> 10, req.AccessSpeed); - link->win = (window_handle_t)link->handle; - ret = CardServices(RequestWindow, &link->win, &req); -@@ -560,7 +565,7 @@ - if(ret) { - req.Size >>= 1; - } else { -- DEBUG(2, "Got window of size %dKB", req.Size >> 10); -+ DEBUG(2, "Got window of size %dKiB", req.Size >> 10); - dev->win_size = req.Size; - break; - } -@@ -573,7 +578,7 @@ - pcmciamtd_release((u_long)link); - return; - } -- DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10); -+ DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); - - /* Get write protect status */ - CS_CHECK(GetStatus, link->handle, &status); -@@ -642,21 +647,21 @@ - } - - dev->mtd_info = mtd; -- mtd->module = THIS_MODULE; -+ mtd->owner = THIS_MODULE; - - if(new_name) { - int size = 0; - char unit = ' '; - /* Since we are using a default name, make it better by adding in the - size */ -- if(mtd->size < 1048576) { /* <1MB in size, show size in K */ -+ if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */ - size = mtd->size >> 10; - unit = 'K'; - } else { - size = mtd->size >> 20; - unit = 'M'; - } -- snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%cB %s", size, unit, "PCMCIA Memory card"); -+ snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%ciB %s", size, unit, "PCMCIA Memory card"); - } - - /* If the memory found is fits completely into the mapped PCMCIA window, -@@ -828,16 +833,20 @@ - } - - -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68) -+static struct pcmcia_driver pcmciamtd_driver = { -+ .drv = { -+ .name = "pcmciamtd" -+ }, -+ .attach = pcmciamtd_attach, -+ .detach = pcmciamtd_detach, -+ .owner = THIS_MODULE -+}; -+#endif -+ -+ - static int __init init_pcmciamtd(void) - { -- servinfo_t serv; -- -- info(DRIVER_DESC " " DRIVER_VERSION); -- CardServices(GetCardServicesInfo, &serv); -- if (serv.Revision != CS_RELEASE_CODE) { -- err("Card Services release does not match!"); -- return -1; -- } - - if(buswidth && buswidth != 1 && buswidth != 2) { - info("bad buswidth (%d), using default", buswidth); -@@ -851,15 +860,24 @@ - info("bad mem_type (%d), using default", mem_type); - mem_type = 0; - } -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68) -+ return pcmcia_register_driver(&pcmciamtd_driver); -+#else - register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach); - return 0; -+#endif - } - - - static void __exit exit_pcmciamtd(void) - { - DEBUG(1, DRIVER_DESC " unloading"); -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,68) -+ pcmcia_unregister_driver(&pcmciamtd_driver); -+#else - unregister_pccard_driver(&dev_info); -+#endif - - while(dev_list) { - dev_link_t *link = dev_list; -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/physmap.c linux/drivers/mtd/maps/physmap.c ---- linux-mips-2.4.27/drivers/mtd/maps/physmap.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/maps/physmap.c 2004-11-19 10:25:11.947192496 +0100 -@@ -1,179 +1,114 @@ - /* -- * $Id$ -+ * $Id$ - * - * Normal mappings of chips in physical memory -+ * -+ * Copyright (C) 2003 MontaVista Software Inc. -+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net -+ * -+ * 031022 - [jsun] add run-time configure and partition setup - */ - - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/slab.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> - #include <linux/config.h> -- --#ifdef CONFIG_MTD_PARTITIONS - #include <linux/mtd/partitions.h> --#endif -- --#define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START --#define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN --#define BUSWIDTH CONFIG_MTD_PHYSMAP_BUSWIDTH - - static struct mtd_info *mymtd; - --__u8 physmap_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 physmap_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 physmap_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -+struct map_info physmap_map = {.name = "phys_mapped_flash"}; - --void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -+#ifdef CONFIG_MTD_PARTITIONS -+static struct mtd_partition *mtd_parts; -+static int mtd_parts_nb; - --void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -+static int num_physmap_partitions; -+static struct mtd_partition *physmap_partitions; - --void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -+char *part_probes[] __initdata = {"cmdlinepart", "RedBoot", NULL}; - --void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -+void physmap_set_partitions(struct mtd_partition *parts, int num_parts) - { -- memcpy_toio(map->map_priv_1 + to, from, len); -+ physmap_partitions=parts; -+ num_physmap_partitions=num_parts; - } -- --struct map_info physmap_map = { -- name: "Physically mapped flash", -- size: WINDOW_SIZE, -- buswidth: BUSWIDTH, -- read8: physmap_read8, -- read16: physmap_read16, -- read32: physmap_read32, -- copy_from: physmap_copy_from, -- write8: physmap_write8, -- write16: physmap_write16, -- write32: physmap_write32, -- copy_to: physmap_copy_to --}; -- --#ifdef CONFIG_MTD_PARTITIONS --#ifdef CONFIG_MTD_CMDLINE_PARTS --static struct mtd_partition *mtd_parts = 0; --static int mtd_parts_nb = 0; --#else --static struct mtd_partition physmap_partitions[] = { --/* Put your own partition definitions here */ --#if 0 -- { -- name: "bootROM", -- size: 0x80000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "zImage", -- size: 0x100000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "ramdisk.gz", -- size: 0x300000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "User FS", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -- } --#endif --}; -- --#define NUM_PARTITIONS (sizeof(physmap_partitions)/sizeof(struct mtd_partition)) -- --#endif --#endif -+#endif /* CONFIG_MTD_PARTITIONS */ - - int __init init_physmap(void) - { - static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 }; - const char **type; - -- printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); -- physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); -+ printk(KERN_NOTICE "physmap flash device: %lx at %lx\n", physmap_map.size, physmap_map.phys); -+ physmap_map.virt = (unsigned long)ioremap(physmap_map.phys, physmap_map.size); - -- if (!physmap_map.map_priv_1) { -+ if (!physmap_map.virt) { - printk("Failed to ioremap\n"); - return -EIO; - } - -+ simple_map_init(&physmap_map); -+ - mymtd = 0; - type = rom_probe_types; - for(; !mymtd && *type; type++) { - mymtd = do_map_probe(*type, &physmap_map); - } - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - -- add_mtd_device(mymtd); - #ifdef CONFIG_MTD_PARTITIONS --#ifdef CONFIG_MTD_CMDLINE_PARTS -- mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, -- "phys"); -+ mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, -+ &mtd_parts, 0); -+ - if (mtd_parts_nb > 0) - { -- printk(KERN_NOTICE -- "Using command line partition definition\n"); - add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb); -+ return 0; - } --#else -- if (NUM_PARTITIONS != 0) -+ -+ if (num_physmap_partitions != 0) - { - printk(KERN_NOTICE - "Using physmap partition definition\n"); -- add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS); -+ add_mtd_partitions (mymtd, physmap_partitions, num_physmap_partitions); -+ return 0; - } - - #endif --#endif -+ add_mtd_device(mymtd); -+ - return 0; - } - -- iounmap((void *)physmap_map.map_priv_1); -+ iounmap((void *)physmap_map.virt); - return -ENXIO; - } - - static void __exit cleanup_physmap(void) - { -- if (mymtd) { -+#ifdef CONFIG_MTD_PARTITIONS -+ if (mtd_parts_nb) { -+ del_mtd_partitions(mymtd); -+ kfree(mtd_parts); -+ } else if (num_physmap_partitions) { -+ del_mtd_partitions(mymtd); -+ } else { - del_mtd_device(mymtd); -- map_destroy(mymtd); -- } -- if (physmap_map.map_priv_1) { -- iounmap((void *)physmap_map.map_priv_1); -- physmap_map.map_priv_1 = 0; - } -+#else -+ del_mtd_device(mymtd); -+#endif -+ map_destroy(mymtd); -+ -+ iounmap((void *)physmap_map.virt); -+ physmap_map.virt = 0; - } - - module_init(init_physmap); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/pnc2000.c linux/drivers/mtd/maps/pnc2000.c ---- linux-mips-2.4.27/drivers/mtd/maps/pnc2000.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/pnc2000.c 2004-11-19 10:25:11.949192192 +0100 -@@ -5,12 +5,13 @@ - * - * This code is GPL - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -24,58 +25,13 @@ - * MAP DRIVER STUFF - */ - --__u8 pnc_read8(struct map_info *map, unsigned long ofs) --{ -- return *(__u8 *)(WINDOW_ADDR + ofs); --} -- --__u16 pnc_read16(struct map_info *map, unsigned long ofs) --{ -- return *(__u16 *)(WINDOW_ADDR + ofs); --} -- --__u32 pnc_read32(struct map_info *map, unsigned long ofs) --{ -- return *(volatile unsigned int *)(WINDOW_ADDR + ofs); --} -- --void pnc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy(to, (void *)(WINDOW_ADDR + from), len); --} -- --void pnc_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- *(__u8 *)(WINDOW_ADDR + adr) = d; --} -- --void pnc_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- *(__u16 *)(WINDOW_ADDR + adr) = d; --} -- --void pnc_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- *(__u32 *)(WINDOW_ADDR + adr) = d; --} -- --void pnc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy((void *)(WINDOW_ADDR + to), from, len); --} - - struct map_info pnc_map = { -- name: "PNC-2000", -- size: WINDOW_SIZE, -- buswidth: 4, -- read8: pnc_read8, -- read16: pnc_read16, -- read32: pnc_read32, -- copy_from: pnc_copy_from, -- write8: pnc_write8, -- write16: pnc_write16, -- write32: pnc_write32, -- copy_to: pnc_copy_to -+ .name = "PNC-2000", -+ .size = WINDOW_SIZE, -+ .buswidth = 4, -+ .phys = 0xFFFFFFFF, -+ .virt = WINDOW_ADDR, - }; - - -@@ -84,19 +40,19 @@ - */ - static struct mtd_partition pnc_partitions[3] = { - { -- name: "PNC-2000 boot firmware", -- size: 0x20000, -- offset: 0 -+ .name = "PNC-2000 boot firmware", -+ .size = 0x20000, -+ .offset = 0 - }, - { -- name: "PNC-2000 kernel", -- size: 0x1a0000, -- offset: 0x20000 -+ .name = "PNC-2000 kernel", -+ .size = 0x1a0000, -+ .offset = 0x20000 - }, - { -- name: "PNC-2000 filesystem", -- size: 0x240000, -- offset: 0x1c0000 -+ .name = "PNC-2000 filesystem", -+ .size = 0x240000, -+ .offset = 0x1c0000 - } - }; - -@@ -110,9 +66,11 @@ - { - printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); - -+ simple_map_init(&pnc_map); -+ - mymtd = do_map_probe("cfi_probe", &pnc_map); - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - return add_mtd_partitions(mymtd, pnc_partitions, 3); - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/redwood.c linux/drivers/mtd/maps/redwood.c ---- linux-mips-2.4.27/drivers/mtd/maps/redwood.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/maps/redwood.c 2004-11-19 10:25:11.962190216 +0100 -@@ -1,38 +1,23 @@ - /* -- * $Id: -+ * $Id$ - * -- * redwood.c - mapper for IBM Redwood-4/5 board. -+ * drivers/mtd/maps/redwood.c - * -- * Copyright 2001 MontaVista Softare Inc. -+ * FLASH map for the IBM Redwood 4/5/6 boards. - * -- * This program is free software; you can redistribute it and/or modify it -- * under the terms of the GNU General Public License as published by the -- * Free Software Foundation; either version 2 of the License, or (at your -- * option) any later version. -- * -- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED -- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN -- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF -- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- * -- * You should have received a copy of the GNU General Public License along -- * with this program; if not, write to the Free Software Foundation, Inc., -- * 675 Mass Ave, Cambridge, MA 02139, USA. -- * -- * History: 12/17/2001 - Armin -- * migrated to use do_map_probe -+ * Author: MontaVista Software, Inc. <source@mvista.com> - * -+ * 2001-2003 (c) MontaVista, Software, Inc. This file is licensed under -+ * the terms of the GNU General Public License version 2. This program -+ * is licensed "as is" without any warranty of any kind, whether express -+ * or implied. - */ - -+#include <linux/config.h> - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -40,96 +25,102 @@ - - #include <asm/io.h> - -+#if !defined (CONFIG_REDWOOD_6) -+ - #define WINDOW_ADDR 0xffc00000 - #define WINDOW_SIZE 0x00400000 - --__u8 redwood_flash_read8(struct map_info *map, unsigned long ofs) --{ -- return *(__u8 *)(map->map_priv_1 + ofs); --} -- --__u16 redwood_flash_read16(struct map_info *map, unsigned long ofs) --{ -- return *(__u16 *)(map->map_priv_1 + ofs); --} -- --__u32 redwood_flash_read32(struct map_info *map, unsigned long ofs) --{ -- return *(volatile unsigned int *)(map->map_priv_1 + ofs); --} -- --void redwood_flash_copy_from(struct map_info *map, void *to, -- unsigned long from, ssize_t len) --{ -- memcpy(to, (void *)(map->map_priv_1 + from), len); --} -- --void redwood_flash_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- *(__u8 *)(map->map_priv_1 + adr) = d; --} -- --void redwood_flash_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- *(__u16 *)(map->map_priv_1 + adr) = d; --} -- --void redwood_flash_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- *(__u32 *)(map->map_priv_1 + adr) = d; --} -- --void redwood_flash_copy_to(struct map_info *map, unsigned long to, -- const void *from, ssize_t len) --{ -- memcpy((void *)(map->map_priv_1 + to), from, len); --} -+#define RW_PART0_OF 0 -+#define RW_PART0_SZ 0x10000 -+#define RW_PART1_OF RW_PART0_SZ -+#define RW_PART1_SZ 0x200000 - 0x10000 -+#define RW_PART2_OF 0x200000 -+#define RW_PART2_SZ 0x10000 -+#define RW_PART3_OF 0x210000 -+#define RW_PART3_SZ 0x200000 - (0x10000 + 0x20000) -+#define RW_PART4_OF 0x3e0000 -+#define RW_PART4_SZ 0x20000 - --struct map_info redwood_flash_map = { -- name: "IBM Redwood", -- size: WINDOW_SIZE, -- buswidth: 2, -- read8: redwood_flash_read8, -- read16: redwood_flash_read16, -- read32: redwood_flash_read32, -- copy_from: redwood_flash_copy_from, -- write8: redwood_flash_write8, -- write16: redwood_flash_write16, -- write32: redwood_flash_write32, -- copy_to: redwood_flash_copy_to -+static struct mtd_partition redwood_flash_partitions[] = { -+ { -+ .name = "Redwood OpenBIOS Vital Product Data", -+ .offset = RW_PART0_OF, -+ .size = RW_PART0_SZ, -+ .mask_flags = MTD_WRITEABLE /* force read-only */ -+ }, -+ { -+ .name = "Redwood kernel", -+ .offset = RW_PART1_OF, -+ .size = RW_PART1_SZ -+ }, -+ { -+ .name = "Redwood OpenBIOS non-volatile storage", -+ .offset = RW_PART2_OF, -+ .size = RW_PART2_SZ, -+ .mask_flags = MTD_WRITEABLE /* force read-only */ -+ }, -+ { -+ .name = "Redwood filesystem", -+ .offset = RW_PART3_OF, -+ .size = RW_PART3_SZ -+ }, -+ { -+ .name = "Redwood OpenBIOS", -+ .offset = RW_PART4_OF, -+ .size = RW_PART4_SZ, -+ .mask_flags = MTD_WRITEABLE /* force read-only */ -+ } - }; - -+#else /* CONFIG_REDWOOD_6 */ -+/* FIXME: the window is bigger - armin */ -+#define WINDOW_ADDR 0xff800000 -+#define WINDOW_SIZE 0x00800000 -+ -+#define RW_PART0_OF 0 -+#define RW_PART0_SZ 0x400000 /* 4 MiB data */ -+#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ -+#define RW_PART1_SZ 0x10000 /* 64K VPD */ -+#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ -+#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) -+#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ -+#define RW_PART3_SZ 0x20000 - - static struct mtd_partition redwood_flash_partitions[] = { - { -- name: "Redwood OpenBIOS Vital Product Data", -- offset: 0, -- size: 0x10000, -- mask_flags: MTD_WRITEABLE /* force read-only */ -+ .name = "Redwood filesystem", -+ .offset = RW_PART0_OF, -+ .size = RW_PART0_SZ - }, - { -- name: "Redwood kernel", -- offset: 0x10000, -- size: 0x200000 - 0x10000 -+ .name = "Redwood OpenBIOS Vital Product Data", -+ .offset = RW_PART1_OF, -+ .size = RW_PART1_SZ, -+ .mask_flags = MTD_WRITEABLE /* force read-only */ - }, - { -- name: "Redwood OpenBIOS non-volatile storage", -- offset: 0x200000, -- size: 0x10000, -- mask_flags: MTD_WRITEABLE /* force read-only */ -+ .name = "Redwood kernel", -+ .offset = RW_PART2_OF, -+ .size = RW_PART2_SZ - }, - { -- name: "Redwood filesystem", -- offset: 0x210000, -- size: 0x200000 - (0x10000 + 0x20000) -- }, -- { -- name: "Redwood OpenBIOS", -- offset: 0x3e0000, -- size: 0x20000, -- mask_flags: MTD_WRITEABLE /* force read-only */ -+ .name = "Redwood OpenBIOS", -+ .offset = RW_PART3_OF, -+ .size = RW_PART3_SZ, -+ .mask_flags = MTD_WRITEABLE /* force read-only */ - } - }; -+ -+#endif /* CONFIG_REDWOOD_6 */ -+ -+struct map_info redwood_flash_map = { -+ .name = "IBM Redwood", -+ .size = WINDOW_SIZE, -+ .buswidth = 2, -+ .phys = WINDOW_ADDR, -+}; -+ -+ - #define NUM_REDWOOD_FLASH_PARTITIONS \ - (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0])) - -@@ -140,18 +131,19 @@ - printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n", - WINDOW_SIZE, WINDOW_ADDR); - -- redwood_flash_map.map_priv_1 = -+ redwood_flash_map.virt = - (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - -- if (!redwood_flash_map.map_priv_1) { -+ if (!redwood_flash_map.virt) { - printk("init_redwood_flash: failed to ioremap\n"); - return -EIO; - } -+ simple_map_init(&redwood_flash_map); - - redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map); - - if (redwood_mtd) { -- redwood_mtd->module = THIS_MODULE; -+ redwood_mtd->owner = THIS_MODULE; - return add_mtd_partitions(redwood_mtd, - redwood_flash_partitions, - NUM_REDWOOD_FLASH_PARTITIONS); -@@ -164,10 +156,15 @@ - { - if (redwood_mtd) { - del_mtd_partitions(redwood_mtd); -- iounmap((void *)redwood_flash_map.map_priv_1); -+ /* moved iounmap after map_destroy - armin */ - map_destroy(redwood_mtd); -+ iounmap((void *)redwood_flash_map.virt); - } - } - - module_init(init_redwood_flash); - module_exit(cleanup_redwood_flash); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("MontaVista Software <source@mvista.com>"); -+MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/rpxlite.c linux/drivers/mtd/maps/rpxlite.c ---- linux-mips-2.4.27/drivers/mtd/maps/rpxlite.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/rpxlite.c 2004-11-19 10:25:11.963190064 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Handle mapping of the flash on the RPX Lite and CLLF boards - */ -@@ -7,6 +7,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -17,80 +18,31 @@ - - static struct mtd_info *mymtd; - --__u8 rpxlite_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --__u16 rpxlite_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --__u32 rpxlite_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void rpxlite_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); --} -- --void rpxlite_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void rpxlite_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio((void *)(map->map_priv_1 + to), from, len); --} -- --struct map_info rpxlite_map = { -- name: "RPX", -- size: WINDOW_SIZE, -- buswidth: 4, -- read8: rpxlite_read8, -- read16: rpxlite_read16, -- read32: rpxlite_read32, -- copy_from: rpxlite_copy_from, -- write8: rpxlite_write8, -- write16: rpxlite_write16, -- write32: rpxlite_write32, -- copy_to: rpxlite_copy_to -+static struct map_info rpxlite_map = { -+ .name = "RPX", -+ .size = WINDOW_SIZE, -+ .buswidth = 4, -+ .phys = WINDOW_ADDR, - }; - - int __init init_rpxlite(void) - { - printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); -- rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); -+ rpxlite_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); - -- if (!rpxlite_map.map_priv_1) { -+ if (!rpxlite_map.virt) { - printk("Failed to ioremap\n"); - return -EIO; - } -+ simple_map_init(&rpxlite_map); - mymtd = do_map_probe("cfi_probe", &rpxlite_map); - if (mymtd) { -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - add_mtd_device(mymtd); - return 0; - } - -- iounmap((void *)rpxlite_map.map_priv_1); -+ iounmap((void *)rpxlite_map.virt); - return -ENXIO; - } - -@@ -100,9 +52,9 @@ - del_mtd_device(mymtd); - map_destroy(mymtd); - } -- if (rpxlite_map.map_priv_1) { -- iounmap((void *)rpxlite_map.map_priv_1); -- rpxlite_map.map_priv_1 = 0; -+ if (rpxlite_map.virt) { -+ iounmap((void *)rpxlite_map.virt); -+ rpxlite_map.virt = 0; - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sa1100-flash.c linux/drivers/mtd/maps/sa1100-flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/sa1100-flash.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/maps/sa1100-flash.c 2004-11-19 10:25:11.966189608 +0100 -@@ -3,7 +3,7 @@ - * - * (C) 2000 Nicolas Pitre <nico@cam.org> - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/config.h> -@@ -11,278 +11,212 @@ - #include <linux/types.h> - #include <linux/ioport.h> - #include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/errno.h> -+#include <linux/slab.h> - - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> - #include <linux/mtd/partitions.h> -+#include <linux/mtd/concat.h> - - #include <asm/hardware.h> -+#include <asm/mach-types.h> - #include <asm/io.h> -+#include <asm/sizes.h> - -+#include <asm/arch/h3600.h> - - #ifndef CONFIG_ARCH_SA1100 - #error This is for SA1100 architecture only - #endif - -+/* -+ * This isnt complete yet, so... -+ */ -+#define CONFIG_MTD_SA1100_STATICMAP 1 - --#define WINDOW_ADDR 0xe8000000 -- --static __u8 sa1100_read8(struct map_info *map, unsigned long ofs) --{ -- return readb(map->map_priv_1 + ofs); --} -- --static __u16 sa1100_read16(struct map_info *map, unsigned long ofs) --{ -- return readw(map->map_priv_1 + ofs); --} -- --static __u32 sa1100_read32(struct map_info *map, unsigned long ofs) --{ -- return readl(map->map_priv_1 + ofs); --} -- --static void sa1100_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy(to, (void *)(map->map_priv_1 + from), len); --} -- --static void sa1100_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- writeb(d, map->map_priv_1 + adr); --} -- --static void sa1100_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- writew(d, map->map_priv_1 + adr); --} -- --static void sa1100_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- writel(d, map->map_priv_1 + adr); --} -- --static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy((void *)(map->map_priv_1 + to), from, len); --} -- --static struct map_info sa1100_map = { -- name: "SA1100 flash", -- read8: sa1100_read8, -- read16: sa1100_read16, -- read32: sa1100_read32, -- copy_from: sa1100_copy_from, -- write8: sa1100_write8, -- write16: sa1100_write16, -- write32: sa1100_write32, -- copy_to: sa1100_copy_to, -- -- map_priv_1: WINDOW_ADDR, -- map_priv_2: -1, --}; -- -- -+#ifdef CONFIG_MTD_SA1100_STATICMAP - /* - * Here are partition information for all known SA1100-based devices. - * See include/linux/mtd/partitions.h for definition of the mtd_partition - * structure. - * -- * The *_max_flash_size is the maximum possible mapped flash size which -- * is not necessarily the actual flash size. It must be no more than -- * the value specified in the "struct map_desc *_io_desc" mapping -- * definition for the corresponding machine. -+ * Please note: -+ * 1. We no longer support static flash mappings via the machine io_desc -+ * structure. -+ * 2. The flash size given should be the largest flash size that can -+ * be accommodated. -+ * -+ * The MTD layer will detect flash chip aliasing and reduce the size of -+ * the map accordingly. - * - * Please keep these in alphabetical order, and formatted as per existing - * entries. Thanks. - */ - - #ifdef CONFIG_SA1100_ADSBITSY --#define ADSBITSY_FLASH_SIZE 0x02000000 - static struct mtd_partition adsbitsy_partitions[] = { - { -- name: "bootROM", -- size: 0x80000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "zImage", -- size: 0x100000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "ramdisk.gz", -- size: 0x300000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "User FS", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .name = "bootROM", -+ .size = 0x80000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "zImage", -+ .size = 0x100000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "ramdisk.gz", -+ .size = 0x300000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "User FS", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - #endif - - #ifdef CONFIG_SA1100_ASSABET - /* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */ --#define ASSABET4_FLASH_SIZE 0x00400000 - static struct mtd_partition assabet4_partitions[] = { - { -- name: "bootloader", -- size: 0x00020000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "bootloader params", -- size: 0x00020000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "jffs", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .name = "bootloader", -+ .size = 0x00020000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "bootloader params", -+ .size = 0x00020000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "jffs", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - - /* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */ --#define ASSABET5_FLASH_SIZE 0x02000000 - static struct mtd_partition assabet5_partitions[] = { - { -- name: "bootloader", -- size: 0x00040000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "bootloader params", -- size: 0x00040000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "jffs", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .name = "bootloader", -+ .size = 0x00040000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "bootloader params", -+ .size = 0x00040000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "jffs", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - --#define ASSABET_FLASH_SIZE ASSABET5_FLASH_SIZE - #define assabet_partitions assabet5_partitions - #endif - - #ifdef CONFIG_SA1100_BADGE4 -- - /* -- * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit) -+ * 1 x Intel 28F320C3 Advanced+ Boot Block Flash (32 Mi bit) - * Eight 4 KiW Parameter Bottom Blocks (64 KiB) - * Sixty-three 32 KiW Main Blocks (4032 Ki b) -+ * -+ * <or> -+ * -+ * 1 x Intel 28F640C3 Advanced+ Boot Block Flash (64 Mi bit) -+ * Eight 4 KiW Parameter Bottom Blocks (64 KiB) -+ * One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b) - */ --#define BADGE4_FLASH_SIZE 0x00400000 - static struct mtd_partition badge4_partitions[] = { - { -- name: "BLOB boot loader", -- offset: 0, -- size: 0x0000A000 -- }, { -- name: "params", -- offset: MTDPART_OFS_APPEND, -- size: 0x00006000 -- }, { -- name: "kernel", -- offset: MTDPART_OFS_APPEND, -- size: 0x00100000 -- }, { -- name: "root", -- offset: MTDPART_OFS_APPEND, -- size: MTDPART_SIZ_FULL -+ .name = "BLOB boot loader", -+ .offset = 0, -+ .size = 0x0000A000 -+ }, { -+ .name = "params", -+ .offset = MTDPART_OFS_APPEND, -+ .size = 0x00006000 -+ }, { -+ .name = "root", -+ .offset = MTDPART_OFS_APPEND, -+ .size = MTDPART_SIZ_FULL - } - }; -- - #endif - - - #ifdef CONFIG_SA1100_CERF - #ifdef CONFIG_SA1100_CERF_FLASH_32MB --#define CERF_FLASH_SIZE 0x02000000 --static struct mtd_partition cerf_partitions[] = { -- { -- name: "firmware", -- size: 0x00040000, -- offset: 0, -- }, { -- name: "params", -- size: 0x00040000, -- offset: 0x00040000, -- }, { -- name: "kernel", -- size: 0x00100000, -- offset: 0x00080000, -- }, { -- name: "rootdisk", -- size: 0x01E80000, -- offset: 0x00180000, -- } --}; -+# define CERF_FLASH_SIZE 0x02000000 - #elif defined CONFIG_SA1100_CERF_FLASH_16MB --#define CERF_FLASH_SIZE 0x01000000 -+# define CERF_FLASH_SIZE 0x01000000 -+#elif defined CONFIG_SA1100_CERF_FLASH_8MB -+# define CERF_FLASH_SIZE 0x00800000 -+#else -+# error "Undefined flash size for CERF in sa1100-flash.c" -+#endif -+ - static struct mtd_partition cerf_partitions[] = { - { -- name: "firmware", -- size: 0x00020000, -- offset: 0, -- }, { -- name: "params", -- size: 0x00020000, -- offset: 0x00020000, -- }, { -- name: "kernel", -- size: 0x00100000, -- offset: 0x00040000, -- }, { -- name: "rootdisk", -- size: 0x00EC0000, -- offset: 0x00140000, -+ .name = "Bootloader", -+ .size = 0x00020000, -+ .offset = 0x00000000, -+ }, { -+ .name = "Params", -+ .size = 0x00040000, -+ .offset = 0x00020000, -+ }, { -+ .name = "Kernel", -+ .size = 0x00100000, -+ .offset = 0x00060000, -+ }, { -+ .name = "Filesystem", -+ .size = CERF_FLASH_SIZE-0x00160000, -+ .offset = 0x00160000, - } - }; --#elif defined CONFIG_SA1100_CERF_FLASH_8MB --# error "Unwritten type definition" --#else --# error "Undefined memory orientation for CERF in sa1100-flash.c" --#endif - #endif - - #ifdef CONFIG_SA1100_CONSUS --#define CONSUS_FLASH_SIZE 0x02000000 - static struct mtd_partition consus_partitions[] = { - { -- name: "Consus boot firmware", -- offset: 0, -- size: 0x00040000, -- mask_flags: MTD_WRITABLE, /* force read-only */ -- }, { -- name: "Consus kernel", -- offset: 0x00040000, -- size: 0x00100000, -- mask_flags: 0, -+ .name = "Consus boot firmware", -+ .offset = 0, -+ .size = 0x00040000, -+ .mask_flags = MTD_WRITABLE, /* force read-only */ -+ }, { -+ .name = "Consus kernel", -+ .offset = 0x00040000, -+ .size = 0x00100000, -+ .mask_flags = 0, - }, { -- name: "Consus disk", -- offset: 0x00140000, -+ .name = "Consus disk", -+ .offset = 0x00140000, - /* The rest (up to 16M) for jffs. We could put 0 and - make it find the size automatically, but right now - i have 32 megs. jffs will use all 32 megs if given - the chance, and this leads to horrible problems - when you try to re-flash the image because blob - won't erase the whole partition. */ -- size: 0x01000000 - 0x00140000, -- mask_flags: 0, -+ .size = 0x01000000 - 0x00140000, -+ .mask_flags = 0, - }, { - /* this disk is a secondary disk, which can be used as - needed, for simplicity, make it the size of the other - consus partition, although realistically it could be - the remainder of the disk (depending on the file - system used) */ -- name: "Consus disk2", -- offset: 0x01000000, -- size: 0x01000000 - 0x00140000, -- mask_flags: 0, -+ .name = "Consus disk2", -+ .offset = 0x01000000, -+ .size = 0x01000000 - 0x00140000, -+ .mask_flags = 0, - } - }; - #endif -@@ -292,96 +226,95 @@ - #define FLEXANET_FLASH_SIZE 0x02000000 - static struct mtd_partition flexanet_partitions[] = { - { -- name: "bootloader", -- size: 0x00040000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "bootloader params", -- size: 0x00040000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "kernel", -- size: 0x000C0000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "altkernel", -- size: 0x000C0000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "root", -- size: 0x00400000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "free1", -- size: 0x00300000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "free2", -- size: 0x00300000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -- }, { -- name: "free3", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, -+ .name = "bootloader", -+ .size = 0x00040000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "bootloader params", -+ .size = 0x00040000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "kernel", -+ .size = 0x000C0000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "altkernel", -+ .size = 0x000C0000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "root", -+ .size = 0x00400000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "free1", -+ .size = 0x00300000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "free2", -+ .size = 0x00300000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, -+ }, { -+ .name = "free3", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, - } - }; - #endif - - #ifdef CONFIG_SA1100_FREEBIRD --#define FREEBIRD_FLASH_SIZE 0x02000000 - static struct mtd_partition freebird_partitions[] = { --#if CONFIG_SA1100_FREEBIRD_NEW -+#ifdef CONFIG_SA1100_FREEBIRD_NEW - { -- name: "firmware", -- size: 0x00040000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "kernel", -- size: 0x00080000, -- offset: 0x00040000, -- }, { -- name: "params", -- size: 0x00040000, -- offset: 0x000C0000, -- }, { -- name: "initrd", -- size: 0x00100000, -- offset: 0x00100000, -- }, { -- name: "root cramfs", -- size: 0x00300000, -- offset: 0x00200000, -- }, { -- name: "usr cramfs", -- size: 0x00C00000, -- offset: 0x00500000, -- }, { -- name: "local", -- size: MTDPART_SIZ_FULL, -- offset: 0x01100000, -+ .name = "firmware", -+ .size = 0x00040000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "kernel", -+ .size = 0x00080000, -+ .offset = 0x00040000, -+ }, { -+ .name = "params", -+ .size = 0x00040000, -+ .offset = 0x000C0000, -+ }, { -+ .name = "initrd", -+ .size = 0x00100000, -+ .offset = 0x00100000, -+ }, { -+ .name = "root cramfs", -+ .size = 0x00300000, -+ .offset = 0x00200000, -+ }, { -+ .name = "usr cramfs", -+ .size = 0x00C00000, -+ .offset = 0x00500000, -+ }, { -+ .name = "local", -+ .size = MTDPART_SIZ_FULL, -+ .offset = 0x01100000, - } - #else - { -- size: 0x00040000, -- offset: 0, -+ .size = 0x00040000, -+ .offset = 0, - }, { -- size: 0x000c0000, -- offset: MTDPART_OFS_APPEND, -+ .size = 0x000c0000, -+ .offset = MTDPART_OFS_APPEND, - }, { -- size: 0x00400000, -- offset: MTDPART_OFS_APPEND, -+ .size = 0x00400000, -+ .offset = MTDPART_OFS_APPEND, - }, { -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - #endif - }; -@@ -389,178 +322,215 @@ - - #ifdef CONFIG_SA1100_FRODO - /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */ --#define FRODO_FLASH_SIZE 0x02000000 - static struct mtd_partition frodo_partitions[] = - { - { -- name: "Boot Loader", -- size: 0x00040000, -- offset: 0x00000000 -- }, { -- name: "Parameter Block", -- size: 0x00040000, -- offset: MTDPART_OFS_APPEND -- }, { -- name: "Linux Kernel", -- size: 0x00100000, -- offset: MTDPART_OFS_APPEND -- }, { -- name: "Ramdisk", -- size: 0x00680000, -- offset: MTDPART_OFS_APPEND -- }, { -- name: "Flash File System", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND -+ .name = "bootloader", -+ .size = 0x00040000, -+ .offset = 0x00000000, -+ .mask_flags = MTD_WRITEABLE -+ }, { -+ .name = "bootloader params", -+ .size = 0x00040000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE -+ }, { -+ .name = "kernel", -+ .size = 0x00100000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE -+ }, { -+ .name = "ramdisk", -+ .size = 0x00400000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE -+ }, { -+ .name = "file system", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND - } - }; - #endif - - #ifdef CONFIG_SA1100_GRAPHICSCLIENT --#define GRAPHICSCLIENT_FLASH_SIZE 0x02000000 - static struct mtd_partition graphicsclient_partitions[] = { - { -- name: "zImage", -- size: 0x100000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "ramdisk.gz", -- size: 0x300000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "User FS", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .name = "zImage", -+ .size = 0x100000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "ramdisk.gz", -+ .size = 0x300000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "User FS", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - #endif - - #ifdef CONFIG_SA1100_GRAPHICSMASTER --#define GRAPHICSMASTER_FLASH_SIZE 0x01000000 - static struct mtd_partition graphicsmaster_partitions[] = { - { -- name: "zImage", -- size: 0x100000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -+ .name = "zImage", -+ .size = 0x100000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { -- name: "ramdisk.gz", -- size: 0x300000, -- offset: MTDPART_OFS_APPEND, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -+ .name = "ramdisk.gz", -+ .size = 0x300000, -+ .offset = MTDPART_OFS_APPEND, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { -- name: "User FS", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .name = "User FS", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - #endif - --#ifdef CONFIG_SA1100_H3600 --#define H3600_FLASH_SIZE 0x02000000 --static struct mtd_partition h3600_partitions[] = { -+#ifdef CONFIG_SA1100_H3XXX -+static struct mtd_partition h3xxx_partitions[] = { - { -- name: "H3600 boot firmware", -- size: 0x00040000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "H3600 kernel", -- size: 0x00080000, -- offset: 0x00040000, -+ .name = "H3XXX boot firmware", -+ .size = 0x00040000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { -- name: "H3600 params", -- size: 0x00040000, -- offset: 0x000C0000, -+#ifdef CONFIG_MTD_2PARTS_IPAQ -+ .name = "H3XXX root jffs2", -+ .size = MTDPART_SIZ_FULL, -+ .offset = 0x00040000, -+#else -+ .name = "H3XXX kernel", -+ .size = 0x00080000, -+ .offset = 0x00040000, -+ }, { -+ .name = "H3XXX params", -+ .size = 0x00040000, -+ .offset = 0x000C0000, - }, { - #ifdef CONFIG_JFFS2_FS -- name: "H3600 root jffs2", -- size: MTDPART_SIZ_FULL, -- offset: 0x00100000, -+ .name = "H3XXX root jffs2", -+ .size = MTDPART_SIZ_FULL, -+ .offset = 0x00100000, - #else -- name: "H3600 initrd", -- size: 0x00100000, -- offset: 0x00100000, -+ .name = "H3XXX initrd", -+ .size = 0x00100000, -+ .offset = 0x00100000, - }, { -- name: "H3600 root cramfs", -- size: 0x00300000, -- offset: 0x00200000, -+ .name = "H3XXX root cramfs", -+ .size = 0x00300000, -+ .offset = 0x00200000, - }, { -- name: "H3600 usr cramfs", -- size: 0x00800000, -- offset: 0x00500000, -+ .name = "H3XXX usr cramfs", -+ .size = 0x00800000, -+ .offset = 0x00500000, - }, { -- name: "H3600 usr local", -- size: MTDPART_SIZ_FULL, -- offset: 0x00d00000, -+ .name = "H3XXX usr local", -+ .size = MTDPART_SIZ_FULL, -+ .offset = 0x00d00000, -+#endif - #endif - } - }; - --static void h3600_set_vpp(struct map_info *map, int vpp) -+static void h3xxx_set_vpp(struct map_info *map, int vpp) - { - assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp); - } -+#else -+#define h3xxx_set_vpp NULL -+#endif -+ -+#ifdef CONFIG_SA1100_HACKKIT -+static struct mtd_partition hackkit_partitions[] = { -+ { -+ .name = "BLOB", -+ .size = 0x00040000, -+ .offset = 0x00000000, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "config", -+ .size = 0x00040000, -+ .offset = MTDPART_OFS_APPEND, -+ }, { -+ .name = "kernel", -+ .size = 0x00100000, -+ .offset = MTDPART_OFS_APPEND, -+ }, { -+ .name = "initrd", -+ .size = 0x00180000, -+ .offset = MTDPART_OFS_APPEND, -+ }, { -+ .name = "rootfs", -+ .size = 0x700000, -+ .offset = MTDPART_OFS_APPEND, -+ }, { -+ .name = "data", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, -+ } -+}; - #endif - - #ifdef CONFIG_SA1100_HUW_WEBPANEL --#define HUW_WEBPANEL_FLASH_SIZE 0x01000000 - static struct mtd_partition huw_webpanel_partitions[] = { - { -- name: "Loader", -- size: 0x00040000, -- offset: 0, -- }, { -- name: "Sector 1", -- size: 0x00040000, -- offset: MTDPART_OFS_APPEND, -+ .name = "Loader", -+ .size = 0x00040000, -+ .offset = 0, -+ }, { -+ .name = "Sector 1", -+ .size = 0x00040000, -+ .offset = MTDPART_OFS_APPEND, - }, { -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - #endif - - #ifdef CONFIG_SA1100_JORNADA720 --#define JORNADA720_FLASH_SIZE 0x02000000 - static struct mtd_partition jornada720_partitions[] = { - { -- name: "JORNADA720 boot firmware", -- size: 0x00040000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -+ .name = "JORNADA720 boot firmware", -+ .size = 0x00040000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { -- name: "JORNADA720 kernel", -- size: 0x000c0000, -- offset: 0x00040000, -+ .name = "JORNADA720 kernel", -+ .size = 0x000c0000, -+ .offset = 0x00040000, - }, { -- name: "JORNADA720 params", -- size: 0x00040000, -- offset: 0x00100000, -+ .name = "JORNADA720 params", -+ .size = 0x00040000, -+ .offset = 0x00100000, - }, { -- name: "JORNADA720 initrd", -- size: 0x00100000, -- offset: 0x00140000, -+ .name = "JORNADA720 initrd", -+ .size = 0x00100000, -+ .offset = 0x00140000, - }, { -- name: "JORNADA720 root cramfs", -- size: 0x00300000, -- offset: 0x00240000, -+ .name = "JORNADA720 root cramfs", -+ .size = 0x00300000, -+ .offset = 0x00240000, - }, { -- name: "JORNADA720 usr cramfs", -- size: 0x00800000, -- offset: 0x00540000, -+ .name = "JORNADA720 usr cramfs", -+ .size = 0x00800000, -+ .offset = 0x00540000, - }, { -- name: "JORNADA720 usr local", -- size: 0 /* will expand to the end of the flash */ -- offset: 0x00d00000, -+ .name = "JORNADA720 usr local", -+ .size = 0, /* will expand to the end of the flash */ -+ .offset = 0x00d00000, - } - }; - --static void jornada720_set_vpp(int vpp) -+static void jornada720_set_vpp(struct map_info *map, int vpp) - { - if (vpp) - PPSR |= 0x80; -@@ -568,454 +538,811 @@ - PPSR &= ~0x80; - PPDR |= 0x80; - } -- -+#else -+#define jornada720_set_vpp NULL - #endif - - #ifdef CONFIG_SA1100_PANGOLIN --#define PANGOLIN_FLASH_SIZE 0x04000000 - static struct mtd_partition pangolin_partitions[] = { - { -- name: "boot firmware", -- size: 0x00080000, -- offset: 0x00000000, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "kernel", -- size: 0x00100000, -- offset: 0x00080000, -- }, { -- name: "initrd", -- size: 0x00280000, -- offset: 0x00180000, -- }, { -- name: "initrd-test", -- size: 0x03C00000, -- offset: 0x00400000, -+ .name = "boot firmware", -+ .size = 0x00080000, -+ .offset = 0x00000000, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "kernel", -+ .size = 0x00100000, -+ .offset = 0x00080000, -+ }, { -+ .name = "initrd", -+ .size = 0x00280000, -+ .offset = 0x00180000, -+ }, { -+ .name = "initrd-test", -+ .size = 0x03C00000, -+ .offset = 0x00400000, - } - }; - #endif - - #ifdef CONFIG_SA1100_PT_SYSTEM3 - /* erase size is 0x40000 == 256k partitions have to have this boundary */ --#define SYSTEM3_FLASH_SIZE 0x01000000 - static struct mtd_partition system3_partitions[] = { - { -- name: "BLOB", -- size: 0x00040000, -- offset: 0x00000000, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "config", -- size: 0x00040000, -- offset: MTDPART_OFS_APPEND, -- }, { -- name: "kernel", -- size: 0x00100000, -- offset: MTDPART_OFS_APPEND, -- }, { -- name: "root", -- size: MTDPART_SIZ_FULL, -- offset: MTDPART_OFS_APPEND, -+ .name = "BLOB", -+ .size = 0x00040000, -+ .offset = 0x00000000, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "config", -+ .size = 0x00040000, -+ .offset = MTDPART_OFS_APPEND, -+ }, { -+ .name = "kernel", -+ .size = 0x00100000, -+ .offset = MTDPART_OFS_APPEND, -+ }, { -+ .name = "root", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - #endif - - #ifdef CONFIG_SA1100_SHANNON --#define SHANNON_FLASH_SIZE 0x00400000 - static struct mtd_partition shannon_partitions[] = { - { -- name: "BLOB boot loader", -- offset: 0, -- size: 0x20000 -+ .name = "BLOB boot loader", -+ .offset = 0, -+ .size = 0x20000 - }, - { -- name: "kernel", -- offset: MTDPART_OFS_APPEND, -- size: 0xe0000 -+ .name = "kernel", -+ .offset = MTDPART_OFS_APPEND, -+ .size = 0xe0000 - }, - { -- name: "initrd", -- offset: MTDPART_OFS_APPEND, -- size: MTDPART_SIZ_FULL -+ .name = "initrd", -+ .offset = MTDPART_OFS_APPEND, -+ .size = MTDPART_SIZ_FULL - } - }; - - #endif - - #ifdef CONFIG_SA1100_SHERMAN --#define SHERMAN_FLASH_SIZE 0x02000000 - static struct mtd_partition sherman_partitions[] = { - { -- size: 0x50000, -- offset: 0, -+ .size = 0x50000, -+ .offset = 0, - }, { -- size: 0x70000, -- offset: MTDPART_OFS_APPEND, -+ .size = 0x70000, -+ .offset = MTDPART_OFS_APPEND, - }, { -- size: 0x600000, -- offset: MTDPART_OFS_APPEND, -+ .size = 0x600000, -+ .offset = MTDPART_OFS_APPEND, - }, { -- size: 0xA0000, -- offset: MTDPART_OFS_APPEND, -+ .size = 0xA0000, -+ .offset = MTDPART_OFS_APPEND, - } - }; - #endif - - #ifdef CONFIG_SA1100_SIMPAD --#define SIMPAD_FLASH_SIZE 0x02000000 - static struct mtd_partition simpad_partitions[] = { - { -- name: "SIMpad boot firmware", -- size: 0x00080000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "SIMpad kernel", -- size: 0x00100000, -- offset: 0x00080000, -- }, { --#ifdef CONFIG_JFFS2_FS -- name: "SIMpad root jffs2", -- size: MTDPART_SIZ_FULL, -- offset: 0x00180000, -+ .name = "SIMpad boot firmware", -+ .size = 0x00080000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "SIMpad kernel", -+ .size = 0x00100000, -+ .offset = MTDPART_OFS_APPEND, -+ }, { -+#ifdef CONFIG_ROOT_CRAMFS -+ .name = "SIMpad root cramfs", -+ .size =0x00D80000, -+ .offset = MTDPART_OFS_APPEND -+ -+ }, { -+ .name = "SIMpad local jffs2", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND - #else -- name: "SIMpad initrd", -- size: 0x00300000, -- offset: 0x00180000, -- }, { -- name: "SIMpad root cramfs", -- size: 0x00300000, -- offset: 0x00480000, -- }, { -- name: "SIMpad usr cramfs", -- size: 0x005c0000, -- offset: 0x00780000, -- }, { -- name: "SIMpad usr local", -- size: MTDPART_SIZ_FULL, -- offset: 0x00d40000, -+ .name = "SIMpad root jffs2", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND - #endif - } - }; - #endif /* CONFIG_SA1100_SIMPAD */ - - #ifdef CONFIG_SA1100_STORK --#define STORK_FLASH_SIZE 0x02000000 - static struct mtd_partition stork_partitions[] = { - { -- name: "STORK boot firmware", -- size: 0x00040000, -- offset: 0, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -- }, { -- name: "STORK params", -- size: 0x00040000, -- offset: 0x00040000, -- }, { -- name: "STORK kernel", -- size: 0x00100000, -- offset: 0x00080000, -+ .name = "STORK boot firmware", -+ .size = 0x00040000, -+ .offset = 0, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, { -+ .name = "STORK params", -+ .size = 0x00040000, -+ .offset = 0x00040000, -+ }, { -+ .name = "STORK kernel", -+ .size = 0x00100000, -+ .offset = 0x00080000, - }, { - #ifdef CONFIG_JFFS2_FS -- name: "STORK root jffs2", -- offset: 0x00180000, -- size: MTDPART_SIZ_FULL, -+ .name = "STORK root jffs2", -+ .offset = 0x00180000, -+ .size = MTDPART_SIZ_FULL, - #else -- name: "STORK initrd", -- size: 0x00100000, -- offset: 0x00180000, -- }, { -- name: "STORK root cramfs", -- size: 0x00300000, -- offset: 0x00280000, -- }, { -- name: "STORK usr cramfs", -- size: 0x00800000, -- offset: 0x00580000, -- }, { -- name: "STORK usr local", -- offset: 0x00d80000, -- size: MTDPART_SIZ_FULL, -+ .name = "STORK initrd", -+ .size = 0x00100000, -+ .offset = 0x00180000, -+ }, { -+ .name = "STORK root cramfs", -+ .size = 0x00300000, -+ .offset = 0x00280000, -+ }, { -+ .name = "STORK usr cramfs", -+ .size = 0x00800000, -+ .offset = 0x00580000, -+ }, { -+ .name = "STORK usr local", -+ .offset = 0x00d80000, -+ .size = MTDPART_SIZ_FULL, -+#endif -+ } -+}; - #endif -+ -+#ifdef CONFIG_SA1100_TRIZEPS -+static struct mtd_partition trizeps_partitions[] = { -+ { -+ .name = "Bootloader", -+ .size = 0x00100000, -+ .offset = 0, -+ }, { -+ .name = "Kernel", -+ .size = 0x00100000, -+ .offset = MTDPART_OFS_APPEND, -+ }, { -+ .name = "root", -+ .size = MTDPART_SIZ_FULL, -+ .offset = MTDPART_OFS_APPEND, - } - }; - #endif - - #ifdef CONFIG_SA1100_YOPY --#define YOPY_FLASH_SIZE 0x08000000 - static struct mtd_partition yopy_partitions[] = { - { -- name: "boot firmware", -- size: 0x00040000, -- offset: 0x00000000, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -+ .name = "boot firmware", -+ .size = 0x00040000, -+ .offset = 0x00000000, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, { -- name: "kernel", -- size: 0x00080000, -- offset: 0x00080000, -+ .name = "kernel", -+ .size = 0x00080000, -+ .offset = 0x00080000, - }, { -- name: "initrd", -- size: 0x00300000, -- offset: 0x00100000, -+ .name = "initrd", -+ .size = 0x00300000, -+ .offset = 0x00100000, - }, { -- name: "root", -- size: 0x01000000, -- offset: 0x00400000, -+ .name = "root", -+ .size = 0x01000000, -+ .offset = 0x00400000, - } - }; - #endif - --extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); --extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts); -- --static struct mtd_partition *parsed_parts; --static struct mtd_info *mymtd; -- --int __init sa1100_mtd_init(void) -+static int __init sa1100_static_partitions(struct mtd_partition **parts) - { -- struct mtd_partition *parts; -- int nb_parts = 0, ret; -- int parsed_nr_parts = 0; -- const char *part_type; -- unsigned long base = -1UL; -- -- /* Default flash buswidth */ -- sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4; -- -- /* -- * Static partition definition selection -- */ -- part_type = "static"; -+ int nb_parts = 0; - - #ifdef CONFIG_SA1100_ADSBITSY - if (machine_is_adsbitsy()) { -- parts = adsbitsy_partitions; -+ *parts = adsbitsy_partitions; - nb_parts = ARRAY_SIZE(adsbitsy_partitions); -- sa1100_map.size = ADSBITSY_FLASH_SIZE; -- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2 : 4; - } - #endif - #ifdef CONFIG_SA1100_ASSABET - if (machine_is_assabet()) { -- parts = assabet_partitions; -+ *parts = assabet_partitions; - nb_parts = ARRAY_SIZE(assabet_partitions); -- sa1100_map.size = ASSABET_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_BADGE4 - if (machine_is_badge4()) { -- parts = badge4_partitions; -+ *parts = badge4_partitions; - nb_parts = ARRAY_SIZE(badge4_partitions); -- sa1100_map.size = BADGE4_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_CERF - if (machine_is_cerf()) { -- parts = cerf_partitions; -+ *parts = cerf_partitions; - nb_parts = ARRAY_SIZE(cerf_partitions); -- sa1100_map.size = CERF_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_CONSUS - if (machine_is_consus()) { -- parts = consus_partitions; -+ *parts = consus_partitions; - nb_parts = ARRAY_SIZE(consus_partitions); -- sa1100_map.size = CONSUS_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_FLEXANET - if (machine_is_flexanet()) { -- parts = flexanet_partitions; -+ *parts = flexanet_partitions; - nb_parts = ARRAY_SIZE(flexanet_partitions); -- sa1100_map.size = FLEXANET_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_FREEBIRD - if (machine_is_freebird()) { -- parts = freebird_partitions; -+ *parts = freebird_partitions; - nb_parts = ARRAY_SIZE(freebird_partitions); -- sa1100_map.size = FREEBIRD_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_FRODO - if (machine_is_frodo()) { -- parts = frodo_partitions; -+ *parts = frodo_partitions; - nb_parts = ARRAY_SIZE(frodo_partitions); -- sa1100_map.size = FRODO_FLASH_SIZE; -- base = 0x00000000; - } - #endif - #ifdef CONFIG_SA1100_GRAPHICSCLIENT - if (machine_is_graphicsclient()) { -- parts = graphicsclient_partitions; -+ *parts = graphicsclient_partitions; - nb_parts = ARRAY_SIZE(graphicsclient_partitions); -- sa1100_map.size = GRAPHICSCLIENT_FLASH_SIZE; -- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; - } - #endif - #ifdef CONFIG_SA1100_GRAPHICSMASTER - if (machine_is_graphicsmaster()) { -- parts = graphicsmaster_partitions; -+ *parts = graphicsmaster_partitions; - nb_parts = ARRAY_SIZE(graphicsmaster_partitions); -- sa1100_map.size = GRAPHICSMASTER_FLASH_SIZE; -- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4; - } - #endif --#ifdef CONFIG_SA1100_H3600 -- if (machine_is_h3600()) { -- parts = h3600_partitions; -- nb_parts = ARRAY_SIZE(h3600_partitions); -- sa1100_map.size = H3600_FLASH_SIZE; -- sa1100_map.set_vpp = h3600_set_vpp; -+#ifdef CONFIG_SA1100_H3XXX -+ if (machine_is_h3xxx()) { -+ *parts = h3xxx_partitions; -+ nb_parts = ARRAY_SIZE(h3xxx_partitions); -+ } -+#endif -+#ifdef CONFIG_SA1100_HACKKIT -+ if (machine_is_hackkit()) { -+ *parts = hackkit_partitions; -+ nb_parts = ARRAY_SIZE(hackkit_partitions); - } - #endif - #ifdef CONFIG_SA1100_HUW_WEBPANEL - if (machine_is_huw_webpanel()) { -- parts = huw_webpanel_partitions; -+ *parts = huw_webpanel_partitions; - nb_parts = ARRAY_SIZE(huw_webpanel_partitions); -- sa1100_map.size = HUW_WEBPANEL_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_JORNADA720 - if (machine_is_jornada720()) { -- parts = jornada720_partitions; -+ *parts = jornada720_partitions; - nb_parts = ARRAY_SIZE(jornada720_partitions); -- sa1100_map.size = JORNADA720_FLASH_SIZE; -- sa1100_map.set_vpp = jornada720_set_vpp; - } - #endif - #ifdef CONFIG_SA1100_PANGOLIN - if (machine_is_pangolin()) { -- parts = pangolin_partitions; -+ *parts = pangolin_partitions; - nb_parts = ARRAY_SIZE(pangolin_partitions); -- sa1100_map.size = PANGOLIN_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_PT_SYSTEM3 - if (machine_is_pt_system3()) { -- parts = system3_partitions; -+ *parts = system3_partitions; - nb_parts = ARRAY_SIZE(system3_partitions); -- sa1100_map.size = SYSTEM3_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_SHANNON - if (machine_is_shannon()) { -- parts = shannon_partitions; -+ *parts = shannon_partitions; - nb_parts = ARRAY_SIZE(shannon_partitions); -- sa1100_map.size = SHANNON_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_SHERMAN - if (machine_is_sherman()) { -- parts = sherman_partitions; -+ *parts = sherman_partitions; - nb_parts = ARRAY_SIZE(sherman_partitions); -- sa1100_map.size = SHERMAN_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_SIMPAD - if (machine_is_simpad()) { -- parts = simpad_partitions; -+ *parts = simpad_partitions; - nb_parts = ARRAY_SIZE(simpad_partitions); -- sa1100_map.size = SIMPAD_FLASH_SIZE; - } - #endif - #ifdef CONFIG_SA1100_STORK - if (machine_is_stork()) { -- parts = stork_partitions; -+ *parts = stork_partitions; - nb_parts = ARRAY_SIZE(stork_partitions); -- sa1100_map.size = STORK_FLASH_SIZE; -+ } -+#endif -+#ifdef CONFIG_SA1100_TRIZEPS -+ if (machine_is_trizeps()) { -+ *parts = trizeps_partitions; -+ nb_parts = ARRAY_SIZE(trizeps_partitions); - } - #endif - #ifdef CONFIG_SA1100_YOPY - if (machine_is_yopy()) { -- parts = yopy_partitions; -+ *parts = yopy_partitions; - nb_parts = ARRAY_SIZE(yopy_partitions); -- sa1100_map.size = YOPY_FLASH_SIZE; - } - #endif - -+ return nb_parts; -+} -+#endif -+ -+struct sa_info { -+ unsigned long base; -+ unsigned long size; -+ int width; -+ void *vbase; -+ void (*set_vpp)(struct map_info *, int); -+ struct map_info *map; -+ struct mtd_info *mtd; -+ struct resource *res; -+}; -+ -+#define NR_SUBMTD 4 -+ -+static struct sa_info info[NR_SUBMTD]; -+ -+static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd) -+{ -+ struct mtd_info *subdev[nr]; -+ struct map_info *maps; -+ int i, found = 0, ret = 0; -+ - /* -- * For simple flash devices, use ioremap to map the flash. -+ * Allocate the map_info structs in one go. - */ -- if (base != (unsigned long)-1) { -- if (!request_mem_region(base, sa1100_map.size, "flash")) -- return -EBUSY; -- sa1100_map.map_priv_2 = base; -- sa1100_map.map_priv_1 = (unsigned long) -- ioremap(base, sa1100_map.size); -+ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); -+ if (!maps) -+ return -ENOMEM; -+ -+ memset(maps, 0, sizeof(struct map_info) * nr); -+ -+ /* -+ * Claim and then map the memory regions. -+ */ -+ for (i = 0; i < nr; i++) { -+ if (sa[i].base == (unsigned long)-1) -+ break; -+ -+ sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash"); -+ if (!sa[i].res) { -+ ret = -EBUSY; -+ break; -+ } -+ -+ sa[i].map = maps + i; -+ -+ sa[i].vbase = ioremap(sa[i].base, sa[i].size); -+ if (!sa[i].vbase) { - ret = -ENOMEM; -- if (!sa1100_map.map_priv_1) -- goto out_err; -+ break; - } - -+ sa[i].map->virt = (unsigned long)sa[i].vbase; -+ sa[i].map->phys = sa[i].base; -+ sa[i].map->set_vpp = sa[i].set_vpp; -+ sa[i].map->buswidth = sa[i].width; -+ sa[i].map->size = sa[i].size; -+ -+ simple_map_init(sa[i].map); -+ - /* - * Now let's probe for the actual flash. Do it here since - * specific machine settings might have been set above. - */ -- printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8); -- mymtd = do_map_probe("cfi_probe", &sa1100_map); -+ sa[i].mtd = do_map_probe("cfi_probe", sa[i].map); -+ if (sa[i].mtd == NULL) { - ret = -ENXIO; -- if (!mymtd) -- goto out_err; -- mymtd->module = THIS_MODULE; -+ break; -+ } -+ sa[i].mtd->owner = THIS_MODULE; -+ subdev[i] = sa[i].mtd; -+ -+ printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, " -+ "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20, -+ sa[i].width * 8); -+ found += 1; -+ } - - /* -- * Dynamic partition selection stuff (might override the static ones) -+ * ENXIO is special. It means we didn't find a chip when -+ * we probed. We need to tear down the mapping, free the -+ * resource and mark it as such. - */ --#ifdef CONFIG_MTD_REDBOOT_PARTS -- if (parsed_nr_parts == 0) { -- int ret = parse_redboot_partitions(mymtd, &parsed_parts); -+ if (ret == -ENXIO) { -+ iounmap(sa[i].vbase); -+ sa[i].vbase = NULL; -+ release_resource(sa[i].res); -+ sa[i].res = NULL; -+ } - -- if (ret > 0) { -- part_type = "RedBoot"; -- parsed_nr_parts = ret; -+ /* -+ * If we found one device, don't bother with concat support. -+ * If we found multiple devices, use concat if we have it -+ * available, otherwise fail. -+ */ -+ if (ret == 0 || ret == -ENXIO) { -+ if (found == 1) { -+ *rmtd = subdev[0]; -+ ret = 0; -+ } else if (found > 1) { -+ /* -+ * We detected multiple devices. Concatenate -+ * them together. -+ */ -+#ifdef CONFIG_MTD_CONCAT -+ *rmtd = mtd_concat_create(subdev, found, -+ "sa1100 flash"); -+ if (*rmtd == NULL) -+ ret = -ENXIO; -+#else -+ printk(KERN_ERR "SA1100 flash: multiple devices " -+ "found but MTD concat support disabled.\n"); -+ ret = -ENXIO; -+#endif - } - } -+ -+ /* -+ * If we failed, clean up. -+ */ -+ if (ret) { -+ do { -+ if (sa[i].mtd) -+ map_destroy(sa[i].mtd); -+ if (sa[i].vbase) -+ iounmap(sa[i].vbase); -+ if (sa[i].res) -+ release_resource(sa[i].res); -+ } while (i--); -+ -+ kfree(maps); -+ } -+ -+ return ret; -+} -+ -+static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd) -+{ -+ int i; -+ -+ del_mtd_partitions(mtd); -+ -+#ifdef CONFIG_MTD_CONCAT -+ if (mtd != sa[0].mtd) -+ mtd_concat_destroy(mtd); - #endif --#ifdef CONFIG_MTD_CMDLINE_PARTS -- if (parsed_nr_parts == 0) { -- int ret = parse_cmdline_partitions(mymtd, &parsed_parts, "sa1100"); -- if (ret > 0) { -- part_type = "Command Line"; -- parsed_nr_parts = ret; -+ -+ for (i = NR_SUBMTD; i >= 0; i--) { -+ if (sa[i].mtd) -+ map_destroy(sa[i].mtd); -+ if (sa[i].vbase) -+ iounmap(sa[i].vbase); -+ if (sa[i].res) -+ release_resource(sa[i].res); - } -+ kfree(sa[0].map); -+} -+ -+/* -+ * A Thought: can we automatically detect the flash? -+ * - Check to see if the region is busy (yes -> failure) -+ * - Is the MSC setup for flash (no -> failure) -+ * - Probe for flash -+ */ -+ -+static struct map_info sa1100_probe_map __initdata = { -+ .name = "SA1100-flash", -+}; -+ -+static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys) -+{ -+ struct mtd_info *mtd; -+ -+ printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ", -+ phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32); -+ -+ if (check_mem_region(phys, 0x08000000)) { -+ printk("busy\n"); -+ return; - } --#endif - -- if (parsed_nr_parts > 0) { -- parts = parsed_parts; -- nb_parts = parsed_nr_parts; -+ if ((msc & 3) == 1) { -+ printk("wrong type\n"); -+ return; - } - -- if (nb_parts == 0) { -- printk(KERN_NOTICE "SA1100 flash: no partition info available, registering whole flash at once\n"); -- add_mtd_device(mymtd); -- } else { -- printk(KERN_NOTICE "Using %s partition definition\n", part_type); -- add_mtd_partitions(mymtd, parts, nb_parts); -+ sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4; -+ sa1100_probe_map.size = SZ_1M; -+ sa1100_probe_map.phys = phys; -+ sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M); -+ if (sa1100_probe_map.virt == 0) -+ goto fail; -+ simple_map_init(&sa1100_probe_map); -+ -+ /* Shame cfi_probe blurts out kernel messages... */ -+ mtd = do_map_probe("cfi_probe", &sa1100_probe_map); -+ if (mtd) -+ map_destroy(mtd); -+ iounmap((void *)sa1100_probe_map.virt); -+ -+ if (!mtd) -+ goto fail; -+ -+ printk("pass\n"); -+ return; -+ -+ fail: -+ printk("failed\n"); -+} -+ -+static void __init sa1100_probe_flash(void) -+{ -+ printk(KERN_INFO "-- SA11xx Flash probe. Please report results.\n"); -+ sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS); -+ sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS); -+ sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS); -+ sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS); -+ sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS); -+ sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS); -+ printk(KERN_INFO "-- SA11xx Flash probe complete.\n"); -+} -+ -+static int __init sa1100_locate_flash(void) -+{ -+ int i, nr = -ENODEV; -+ -+ sa1100_probe_flash(); -+ -+ if (machine_is_adsbitsy()) { -+ info[0].base = SA1100_CS1_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_assabet()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ info[1].base = SA1100_CS1_PHYS; /* neponset */ -+ info[1].size = SZ_32M; -+ nr = 2; -+ } -+ if (machine_is_badge4()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_64M; -+ nr = 1; -+ } -+ if (machine_is_cerf()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_consus()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_flexanet()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_freebird()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_frodo()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_graphicsclient()) { -+ info[0].base = SA1100_CS1_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; - } -- return 0; -+ if (machine_is_graphicsmaster()) { -+ info[0].base = SA1100_CS1_PHYS; -+ info[0].size = SZ_16M; -+ nr = 1; -+ } -+ if (machine_is_h3xxx()) { -+ info[0].set_vpp = h3xxx_set_vpp; -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_huw_webpanel()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_16M; -+ nr = 1; -+ } -+ if (machine_is_itsy()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_jornada720()) { -+ info[0].set_vpp = jornada720_set_vpp; -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_nanoengine()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[1].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_pangolin()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_64M; -+ nr = 1; -+ } -+ if (machine_is_pfs168()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_pleb()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_4M; -+ info[1].base = SA1100_CS1_PHYS; -+ info[1].size = SZ_4M; -+ nr = 2; -+ } -+ if (machine_is_pt_system3()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_16M; -+ nr = 1; -+ } -+ if (machine_is_shannon()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_4M; -+ nr = 1; -+ } -+ if (machine_is_sherman()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_simpad()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_16M; -+ info[1].base = SA1100_CS1_PHYS; -+ info[1].size = SZ_16M; -+ nr = 2; -+ } -+ if (machine_is_stork()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_32M; -+ nr = 1; -+ } -+ if (machine_is_trizeps()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_16M; -+ nr = 1; -+ } -+ if (machine_is_victor()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_2M; -+ nr = 1; -+ } -+ if (machine_is_yopy()) { -+ info[0].base = SA1100_CS0_PHYS; -+ info[0].size = SZ_64M; -+ info[1].base = SA1100_CS1_PHYS; -+ info[1].size = SZ_64M; -+ nr = 2; -+ } -+ -+ if (nr < 0) -+ return nr; - -- out_err: -- if (sa1100_map.map_priv_2 != -1) { -- iounmap((void *)sa1100_map.map_priv_1); -- release_mem_region(sa1100_map.map_priv_2, sa1100_map.size); -+ /* -+ * Retrieve the buswidth from the MSC registers. -+ * We currently only implement CS0 and CS1 here. -+ */ -+ for (i = 0; i < nr; i++) { -+ switch (info[i].base) { -+ default: -+ printk(KERN_WARNING "SA1100 flash: unknown base address " -+ "0x%08lx, assuming CS0\n", info[i].base); -+ case SA1100_CS0_PHYS: -+ info[i].width = (MSC0 & MSC_RBW) ? 2 : 4; -+ break; -+ -+ case SA1100_CS1_PHYS: -+ info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4; -+ break; - } -- return ret; -+ } -+ -+ return nr; - } - --static void __exit sa1100_mtd_cleanup(void) -+static struct mtd_partition *parsed_parts; -+const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; -+ -+static void __init sa1100_locate_partitions(struct mtd_info *mtd) - { -- if (mymtd) { -- del_mtd_partitions(mymtd); -- map_destroy(mymtd); -- if (parsed_parts) -- kfree(parsed_parts); -+ const char *part_type = NULL; -+ int nr_parts = 0; -+ -+ do { -+ /* -+ * Partition selection stuff. -+ */ -+#ifdef CONFIG_MTD_PARTITIONS -+ nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0); -+ if (nr_parts > 0) { -+ part_type = "dynamic"; -+ break; - } -- if (sa1100_map.map_priv_2 != -1) { -- iounmap((void *)sa1100_map.map_priv_1); -- release_mem_region(sa1100_map.map_priv_2, sa1100_map.size); -+#endif -+#ifdef CONFIG_MTD_SA1100_STATICMAP -+ nr_parts = sa1100_static_partitions(&parsed_parts); -+ if (nr_parts > 0) { -+ part_type = "static"; -+ break; - } -+#endif -+ } while (0); -+ -+ if (nr_parts == 0) { -+ printk(KERN_NOTICE "SA1100 flash: no partition info " -+ "available, registering whole flash\n"); -+ add_mtd_device(mtd); -+ } else { -+ printk(KERN_NOTICE "SA1100 flash: using %s partition " -+ "definition\n", part_type); -+ add_mtd_partitions(mtd, parsed_parts, nr_parts); -+ } -+ -+ /* Always succeeds. */ -+} -+ -+static void __exit sa1100_destroy_partitions(void) -+{ -+ if (parsed_parts) -+ kfree(parsed_parts); -+} -+ -+static struct mtd_info *mymtd; -+ -+static int __init sa1100_mtd_init(void) -+{ -+ int ret; -+ int nr; -+ -+ nr = sa1100_locate_flash(); -+ if (nr < 0) -+ return nr; -+ -+ ret = sa1100_setup_mtd(info, nr, &mymtd); -+ if (ret == 0) -+ sa1100_locate_partitions(mymtd); -+ -+ return ret; -+} -+ -+static void __exit sa1100_mtd_cleanup(void) -+{ -+ sa1100_destroy_mtd(info, mymtd); -+ sa1100_destroy_partitions(); - } - - module_init(sa1100_mtd_init); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sbc8240.c linux/drivers/mtd/maps/sbc8240.c ---- linux-mips-2.4.27/drivers/mtd/maps/sbc8240.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/maps/sbc8240.c 2004-11-19 10:25:11.967189456 +0100 -@@ -0,0 +1,417 @@ -+/* -+ * Handle mapping of the flash memory access routines on the SBC8240 board. -+ * -+ * Carolyn Smith, Tektronix, Inc. -+ * -+ * This code is GPLed -+ * -+ * $Id$ -+ * -+ */ -+ -+/* -+ * The SBC8240 has 2 flash banks. -+ * Bank 0 is a 512 KiB AMD AM29F040B; 8 x 64 KiB sectors. -+ * It contains the U-Boot code (7 sectors) and the environment (1 sector). -+ * Bank 1 is 4 x 1 MiB AMD AM29LV800BT; 15 x 64 KiB sectors, 1 x 32 KiB sector, -+ * 2 x 8 KiB sectors, 1 x 16 KiB sectors. -+ * Both parts are JEDEC compatible. -+ */ -+ -+#include <linux/config.h> -+#include <linux/module.h> -+#include <linux/types.h> -+#include <linux/kernel.h> -+#include <asm/io.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/cfi.h> -+ -+#ifdef CONFIG_MTD_PARTITIONS -+#include <linux/mtd/partitions.h> -+#endif -+ -+#define DEBUG -+ -+#ifdef DEBUG -+# define debugk(fmt,args...) printk(fmt ,##args) -+#else -+# define debugk(fmt,args...) -+#endif -+ -+ -+#define WINDOW_ADDR0 0xFFF00000 /* 512 KiB */ -+#define WINDOW_SIZE0 0x00080000 -+#define BUSWIDTH0 1 -+ -+#define WINDOW_ADDR1 0xFF000000 /* 4 MiB */ -+#define WINDOW_SIZE1 0x00400000 -+#define BUSWIDTH1 8 -+ -+#define MSG_PREFIX "sbc8240:" /* prefix for our printk()'s */ -+#define MTDID "sbc8240-%d" /* for mtdparts= partitioning */ -+ -+ -+static __u8 sbc8240_read8 (struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readb(map->map_priv_1 + ofs); -+} -+ -+static __u16 sbc8240_read16 (struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readw(map->map_priv_1 + ofs); -+} -+ -+static __u32 sbc8240_read32 (struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readl(map->map_priv_1 + ofs); -+} -+ -+unsigned long long result64; -+ -+static __u64 sbc8240_read64 (struct map_info *map, unsigned long ofs) -+{ -+ unsigned long flags, msr, saved_msr; -+ volatile long saved_fr[2]; -+ volatile unsigned long long result; -+ volatile unsigned long *p; -+ -+ save_flags(flags); -+ cli(); -+ -+ /* turn off floating point unavailable exceptions */ -+ -+ __asm__ __volatile__ ( -+ "mfmsr %0" -+ : "=r" (msr) :); -+ -+ saved_msr = msr; -+ msr |= MSR_FP; -+ msr &= ~(MSR_FE0 | MSR_FE1); -+ -+ __asm__ __volatile__ ( -+ "mtmsr %0\n" -+ "isync\n" -+ : : "r" (msr)); -+ -+ /* read the data via a floating point register */ -+ -+ ofs = map->map_priv_1 + ofs; -+ p = (unsigned long *) &result64; -+ -+ __asm__ __volatile__ ( -+ "lfd 1,0(%1)\n" -+ "stfd 1,0(%0)\n" -+ : : "r" (p), "r" (ofs) -+ ); -+ -+ /* restore state */ -+ -+ __asm__ __volatile__ ( -+ "mtmsr %0\n" -+ "isync\n" -+ : : "r" (saved_msr)); -+ -+ restore_flags(flags); -+ -+ p = (unsigned long *) &result64; -+ debugk("sbc8240_read64 ofs 0x%x result 0x%08x%08x\n", ofs, *p, *(p+1)); -+ -+ return result64; -+} -+ -+static void sbc8240_copy_from (struct map_info *map, -+ void *to, unsigned long from, ssize_t len) -+{ -+ memcpy_fromio (to, (void *) (map->map_priv_1 + from), len); -+} -+ -+static void sbc8240_write8 (struct map_info *map, __u8 d, unsigned long adr) -+{ -+ __raw_writeb(d, map->map_priv_1 + adr); -+ mb(); -+} -+ -+static void sbc8240_write16 (struct map_info *map, __u16 d, -+ unsigned long adr) -+{ -+ __raw_writew(d, map->map_priv_1 + adr); -+ mb(); -+} -+ -+static void sbc8240_write32 (struct map_info *map, __u32 d, -+ unsigned long adr) -+{ -+ __raw_writel(d, map->map_priv_1 + adr); -+ mb(); -+} -+ -+static void sbc8240_write64 (struct map_info *map, __u64 data, -+ unsigned long adr) -+{ -+ unsigned long long tmp; -+ unsigned long flags, msr, saved_msr, *p; -+ volatile long saved_fr[2]; -+ -+ save_flags(flags); -+ cli(); -+ -+ /* turn off floating point unavailable exceptions */ -+ -+ __asm__ __volatile__ ( -+ "mfmsr %0" -+ : "=r" (msr) :); -+ -+ saved_msr = msr; -+ msr |= MSR_FP; -+ msr &= ~(MSR_FE0 | MSR_FE1); -+ -+ __asm__ __volatile__ ( -+ "mtmsr %0\n" -+ "isync\n" -+ : : "r" (msr)); -+ -+ -+ /* write the data via a floating point register */ -+ -+ tmp = data; -+ p = (unsigned long *) &tmp; -+ adr = map->map_priv_1 + adr; -+ debugk("sbc8240_write64 adr 0x%x data 0x%08x%08x\n", adr, *p, *(p+1)); -+ -+ __asm__ __volatile__ ( -+ "stfd 1,0(%2)\n" -+ "lfd 1,0(%0)\n" -+ "stfd 1,0(%1)\n" -+ "lfd 1,0(%2)\n" -+ : : "r" (p), "r" (adr), "b" (saved_fr) -+ ); -+ -+ /* restore state */ -+ -+ __asm__ __volatile__ ( -+ "mtmsr %0\n" -+ "isync\n" -+ : : "r" (saved_msr)); -+ -+ restore_flags(flags); -+} -+ -+static void sbc8240_copy_to (struct map_info *map, -+ unsigned long to, const void *from, ssize_t len) -+{ -+ memcpy_toio ((void *) (map->map_priv_1 + to), from, len); -+} -+ -+static struct map_info sbc8240_map[2] = { -+ { -+ .name = "sbc8240 Flash Bank #0", -+ .size = WINDOW_SIZE0, -+ .buswidth = BUSWIDTH0, -+ .read8 = sbc8240_read8, -+ .read16 = sbc8240_read16, -+ .read32 = sbc8240_read32, -+ .read64 = sbc8240_read64, -+ .copy_from = sbc8240_copy_from, -+ .write8 = sbc8240_write8, -+ .write16 = sbc8240_write16, -+ .write32 = sbc8240_write32, -+ .write64 = sbc8240_write64, -+ .copy_to = sbc8240_copy_to -+ }, -+ { -+ .name = "sbc8240 Flash Bank #1", -+ .size = WINDOW_SIZE1, -+ .buswidth = BUSWIDTH1, -+ .read8 = sbc8240_read8, -+ .read16 = sbc8240_read16, -+ .read32 = sbc8240_read32, -+ .read64 = sbc8240_read64, -+ .copy_from = sbc8240_copy_from, -+ .write8 = sbc8240_write8, -+ .write16 = sbc8240_write16, -+ .write32 = sbc8240_write32, -+ .write64 = sbc8240_write64, -+ .copy_to = sbc8240_copy_to -+ } -+}; -+ -+#define NUM_FLASH_BANKS (sizeof(sbc8240_map) / sizeof(struct map_info)) -+ -+/* -+ * The following defines the partition layout of SBC8240 boards. -+ * -+ * See include/linux/mtd/partitions.h for definition of the -+ * mtd_partition structure. -+ * -+ * The *_max_flash_size is the maximum possible mapped flash size -+ * which is not necessarily the actual flash size. It must correspond -+ * to the value specified in the mapping definition defined by the -+ * "struct map_desc *_io_desc" for the corresponding machine. -+ */ -+ -+#ifdef CONFIG_MTD_PARTITIONS -+ -+static struct mtd_partition sbc8240_uboot_partitions [] = { -+ /* Bank 0 */ -+ { -+ .name = "U-boot", /* U-Boot Firmware */ -+ .offset = 0, -+ .size = 0x00070000, /* 7 x 64 KiB sectors */ -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ -+ }, -+ { -+ .name = "environment", /* U-Boot environment */ -+ .offset = 0x00070000, -+ .size = 0x00010000, /* 1 x 64 KiB sector */ -+ }, -+}; -+ -+static struct mtd_partition sbc8240_fs_partitions [] = { -+ { -+ .name = "jffs", /* JFFS filesystem */ -+ .offset = 0, -+ .size = 0x003C0000, /* 4 * 15 * 64KiB */ -+ }, -+ { -+ .name = "tmp32", -+ .offset = 0x003C0000, -+ .size = 0x00020000, /* 4 * 32KiB */ -+ }, -+ { -+ .name = "tmp8a", -+ .offset = 0x003E0000, -+ .size = 0x00008000, /* 4 * 8KiB */ -+ }, -+ { -+ .name = "tmp8b", -+ .offset = 0x003E8000, -+ .size = 0x00008000, /* 4 * 8KiB */ -+ }, -+ { -+ .name = "tmp16", -+ .offset = 0x003F0000, -+ .size = 0x00010000, /* 4 * 16KiB */ -+ } -+}; -+ -+#define NB_OF(x) (sizeof (x) / sizeof (x[0])) -+ -+/* trivial struct to describe partition information */ -+struct mtd_part_def -+{ -+ int nums; -+ unsigned char *type; -+ struct mtd_partition* mtd_part; -+}; -+ -+static struct mtd_info *sbc8240_mtd[NUM_FLASH_BANKS]; -+static struct mtd_part_def sbc8240_part_banks[NUM_FLASH_BANKS]; -+ -+ -+#endif /* CONFIG_MTD_PARTITIONS */ -+ -+ -+int __init init_sbc8240_mtd (void) -+{ -+ static struct _cjs { -+ u_long addr; -+ u_long size; -+ } pt[NUM_FLASH_BANKS] = { -+ { -+ .addr = WINDOW_ADDR0, -+ .size = WINDOW_SIZE0 -+ }, -+ { -+ .addr = WINDOW_ADDR1, -+ .size = WINDOW_SIZE1 -+ }, -+ }; -+ -+ int devicesfound = 0; -+ int i; -+ -+ for (i = 0; i < NUM_FLASH_BANKS; i++) { -+ printk (KERN_NOTICE MSG_PREFIX -+ "Probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr); -+ -+ sbc8240_map[i].map_priv_1 = -+ (unsigned long) ioremap (pt[i].addr, pt[i].size); -+ if (!sbc8240_map[i].map_priv_1) { -+ printk (MSG_PREFIX "failed to ioremap\n"); -+ return -EIO; -+ } -+ -+ sbc8240_mtd[i] = do_map_probe("jedec_probe", &sbc8240_map[i]); -+ -+ if (sbc8240_mtd[i]) { -+ sbc8240_mtd[i]->module = THIS_MODULE; -+ devicesfound++; -+ } -+ } -+ -+ if (!devicesfound) { -+ printk(KERN_NOTICE MSG_PREFIX -+ "No suppported flash chips found!\n"); -+ return -ENXIO; -+ } -+ -+#ifdef CONFIG_MTD_PARTITIONS -+ sbc8240_part_banks[0].mtd_part = sbc8240_uboot_partitions; -+ sbc8240_part_banks[0].type = "static image"; -+ sbc8240_part_banks[0].nums = NB_OF(sbc8240_uboot_partitions); -+ sbc8240_part_banks[1].mtd_part = sbc8240_fs_partitions; -+ sbc8240_part_banks[1].type = "static file system"; -+ sbc8240_part_banks[1].nums = NB_OF(sbc8240_fs_partitions); -+ -+ for (i = 0; i < NUM_FLASH_BANKS; i++) { -+ -+ if (!sbc8240_mtd[i]) continue; -+ if (sbc8240_part_banks[i].nums == 0) { -+ printk (KERN_NOTICE MSG_PREFIX -+ "No partition info available, registering whole device\n"); -+ add_mtd_device(sbc8240_mtd[i]); -+ } else { -+ printk (KERN_NOTICE MSG_PREFIX -+ "Using %s partition definition\n", sbc8240_part_banks[i].mtd_part->name); -+ add_mtd_partitions (sbc8240_mtd[i], -+ sbc8240_part_banks[i].mtd_part, -+ sbc8240_part_banks[i].nums); -+ } -+ } -+#else -+ printk(KERN_NOTICE MSG_PREFIX -+ "Registering %d flash banks at once\n", devicesfound); -+ -+ for (i = 0; i < devicesfound; i++) { -+ add_mtd_device(sbc8240_mtd[i]); -+ } -+#endif /* CONFIG_MTD_PARTITIONS */ -+ -+ return devicesfound == 0 ? -ENXIO : 0; -+} -+ -+static void __exit cleanup_sbc8240_mtd (void) -+{ -+ int i; -+ -+ for (i = 0; i < NUM_FLASH_BANKS; i++) { -+ if (sbc8240_mtd[i]) { -+ del_mtd_device (sbc8240_mtd[i]); -+ map_destroy (sbc8240_mtd[i]); -+ } -+ if (sbc8240_map[i].map_priv_1) { -+ iounmap ((void *) sbc8240_map[i].map_priv_1); -+ sbc8240_map[i].map_priv_1 = 0; -+ } -+ } -+} -+ -+module_init (init_sbc8240_mtd); -+module_exit (cleanup_sbc8240_mtd); -+ -+MODULE_LICENSE ("GPL"); -+MODULE_AUTHOR ("Carolyn Smith <carolyn.smith@tektronix.com>"); -+MODULE_DESCRIPTION ("MTD map driver for SBC8240 boards"); -+ -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sbc_gxx.c linux/drivers/mtd/maps/sbc_gxx.c ---- linux-mips-2.4.27/drivers/mtd/maps/sbc_gxx.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/maps/sbc_gxx.c 2004-11-19 10:25:11.969189152 +0100 -@@ -17,7 +17,7 @@ - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - -- $Id$ -+ $Id$ - - The SBC-MediaGX / SBC-GXx has up to 16 MiB of - Intel StrataFlash (28F320/28F640) in x8 mode. -@@ -91,14 +91,14 @@ - * single flash device into. If the size if zero we use up to the end of the - * device. */ - static struct mtd_partition partition_info[]={ -- { name: "SBC-GXx flash boot partition", -- offset: 0, -- size: BOOT_PARTITION_SIZE_KiB*1024 }, -- { name: "SBC-GXx flash data partition", -- offset: BOOT_PARTITION_SIZE_KiB*1024, -- size: (DATA_PARTITION_SIZE_KiB)*1024 }, -- { name: "SBC-GXx flash application partition", -- offset: (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } -+ { .name = "SBC-GXx flash boot partition", -+ .offset = 0, -+ .size = BOOT_PARTITION_SIZE_KiB*1024 }, -+ { .name = "SBC-GXx flash data partition", -+ .offset = BOOT_PARTITION_SIZE_KiB*1024, -+ .size = (DATA_PARTITION_SIZE_KiB)*1024 }, -+ { .name = "SBC-GXx flash application partition", -+ .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } - }; - - #define NUM_PARTITIONS 3 -@@ -203,19 +203,20 @@ - } - - static struct map_info sbc_gxx_map = { -- name: "SBC-GXx flash", -- size: MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount -+ .name = "SBC-GXx flash", -+ .phys = NO_XIP, -+ .size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount - of flash so the cfi probe routines find all - the chips */ -- buswidth: 1, -- read8: sbc_gxx_read8, -- read16: sbc_gxx_read16, -- read32: sbc_gxx_read32, -- copy_from: sbc_gxx_copy_from, -- write8: sbc_gxx_write8, -- write16: sbc_gxx_write16, -- write32: sbc_gxx_write32, -- copy_to: sbc_gxx_copy_to -+ .buswidth = 1, -+ .read8 = sbc_gxx_read8, -+ .read16 = sbc_gxx_read16, -+ .read32 = sbc_gxx_read32, -+ .copy_from = sbc_gxx_copy_from, -+ .write8 = sbc_gxx_write8, -+ .write16 = sbc_gxx_write16, -+ .write32 = sbc_gxx_write32, -+ .copy_to = sbc_gxx_copy_to - }; - - /* MTD device for all of the flash. */ -@@ -234,12 +235,6 @@ - - int __init init_sbc_gxx(void) - { -- if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) { -- printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", -- sbc_gxx_map.name, -- PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); -- return -EAGAIN; -- } - iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); - if (!iomapadr) { - printk( KERN_ERR"%s: failed to ioremap memory region\n", -@@ -247,7 +242,14 @@ - return -EIO; - } - -- request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash" ); -+ if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { -+ printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", -+ sbc_gxx_map.name, -+ PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); -+ iounmap((void *)iomapadr); -+ return -EAGAIN; -+ } -+ - - printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", - sbc_gxx_map.name, -@@ -261,7 +263,7 @@ - return -ENXIO; - } - -- all_mtd->module=THIS_MODULE; -+ all_mtd->owner = THIS_MODULE; - - /* Create MTD devices for each partition. */ - add_mtd_partitions(all_mtd, partition_info, NUM_PARTITIONS ); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sc520cdp.c linux/drivers/mtd/maps/sc520cdp.c ---- linux-mips-2.4.27/drivers/mtd/maps/sc520cdp.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/sc520cdp.c 2004-11-19 10:25:11.970189000 +0100 -@@ -16,7 +16,7 @@ - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * -- * $Id$ -+ * $Id$ - * - * - * The SC520CDP is an evaluation board for the Elan SC520 processor available -@@ -29,6 +29,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -84,88 +85,25 @@ - #define WINDOW_SIZE_1 0x00800000 - #define WINDOW_SIZE_2 0x00080000 - --static __u8 sc520cdp_read8(struct map_info *map, unsigned long ofs) --{ -- return readb(map->map_priv_1 + ofs); --} -- --static __u16 sc520cdp_read16(struct map_info *map, unsigned long ofs) --{ -- return readw(map->map_priv_1 + ofs); --} -- --static __u32 sc520cdp_read32(struct map_info *map, unsigned long ofs) --{ -- return readl(map->map_priv_1 + ofs); --} -- --static void sc520cdp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); --} -- --static void sc520cdp_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- writeb(d, map->map_priv_1 + adr); --} -- --static void sc520cdp_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- writew(d, map->map_priv_1 + adr); --} -- --static void sc520cdp_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- writel(d, map->map_priv_1 + adr); --} -- --static void sc520cdp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio((void *)(map->map_priv_1 + to), from, len); --} - - static struct map_info sc520cdp_map[] = { - { -- name: "SC520CDP Flash Bank #0", -- size: WINDOW_SIZE_0, -- buswidth: 4, -- read8: sc520cdp_read8, -- read16: sc520cdp_read16, -- read32: sc520cdp_read32, -- copy_from: sc520cdp_copy_from, -- write8: sc520cdp_write8, -- write16: sc520cdp_write16, -- write32: sc520cdp_write32, -- copy_to: sc520cdp_copy_to, -- map_priv_2: WINDOW_ADDR_0 -+ .name = "SC520CDP Flash Bank #0", -+ .size = WINDOW_SIZE_0, -+ .buswidth = 4, -+ .phys = WINDOW_ADDR_0 - }, - { -- name: "SC520CDP Flash Bank #1", -- size: WINDOW_SIZE_1, -- buswidth: 4, -- read8: sc520cdp_read8, -- read16: sc520cdp_read16, -- read32: sc520cdp_read32, -- copy_from: sc520cdp_copy_from, -- write8: sc520cdp_write8, -- write16: sc520cdp_write16, -- write32: sc520cdp_write32, -- copy_to: sc520cdp_copy_to, -- map_priv_2: WINDOW_ADDR_1 -+ .name = "SC520CDP Flash Bank #1", -+ .size = WINDOW_SIZE_1, -+ .buswidth = 4, -+ .phys = WINDOW_ADDR_1 - }, - { -- name: "SC520CDP DIL Flash", -- size: WINDOW_SIZE_2, -- buswidth: 1, -- read8: sc520cdp_read8, -- read16: sc520cdp_read16, -- read32: sc520cdp_read32, -- copy_from: sc520cdp_copy_from, -- write8: sc520cdp_write8, -- write16: sc520cdp_write16, -- write32: sc520cdp_write32, -- copy_to: sc520cdp_copy_to, -- map_priv_2: WINDOW_ADDR_2 -+ .name = "SC520CDP DIL Flash", -+ .size = WINDOW_SIZE_2, -+ .buswidth = 1, -+ .phys = WINDOW_ADDR_2 - }, - }; - -@@ -255,9 +193,9 @@ - /* map in SC520's MMCR area */ - mmcr = (unsigned long *)ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT); - if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */ -- /* force map_priv_2 fields to BIOS defaults: */ -+ /* force physical address fields to BIOS defaults: */ - for(i = 0; i < NUM_FLASH_BANKS; i++) -- sc520cdp_map[i].map_priv_2 = par_table[i].default_address; -+ sc520cdp_map[i].phys = par_table[i].default_address; - return; - } - -@@ -282,7 +220,7 @@ - sc520cdp_map[i].name); - printk(KERN_NOTICE "Trying default address 0x%lx\n", - par_table[i].default_address); -- sc520cdp_map[i].map_priv_2 = par_table[i].default_address; -+ sc520cdp_map[i].phys = par_table[i].default_address; - } - } - iounmap((void *)mmcr); -@@ -300,13 +238,18 @@ - #endif - - for (i = 0; i < NUM_FLASH_BANKS; i++) { -- printk(KERN_NOTICE "SC520 CDP flash device: %lx at %lx\n", sc520cdp_map[i].size, sc520cdp_map[i].map_priv_2); -- sc520cdp_map[i].map_priv_1 = (unsigned long)ioremap_nocache(sc520cdp_map[i].map_priv_2, sc520cdp_map[i].size); -+ printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n", -+ sc520cdp_map[i].size, sc520cdp_map[i].phys); - -- if (!sc520cdp_map[i].map_priv_1) { -+ sc520cdp_map[i].virt = (unsigned long)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size); -+ -+ if (!sc520cdp_map[i].virt) { - printk("Failed to ioremap_nocache\n"); - return -EIO; - } -+ -+ simple_map_init(&sc520cdp_map[i]); -+ - mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]); - if(!mymtd[i]) - mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]); -@@ -314,11 +257,11 @@ - mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]); - - if (mymtd[i]) { -- mymtd[i]->module = THIS_MODULE; -+ mymtd[i]->owner = THIS_MODULE; - ++devices_found; - } - else { -- iounmap((void *)sc520cdp_map[i].map_priv_1); -+ iounmap((void *)sc520cdp_map[i].virt); - } - } - if(devices_found >= 2) { -@@ -346,9 +289,9 @@ - for (i = 0; i < NUM_FLASH_BANKS; i++) { - if (mymtd[i]) - map_destroy(mymtd[i]); -- if (sc520cdp_map[i].map_priv_1) { -- iounmap((void *)sc520cdp_map[i].map_priv_1); -- sc520cdp_map[i].map_priv_1 = 0; -+ if (sc520cdp_map[i].virt) { -+ iounmap((void *)sc520cdp_map[i].virt); -+ sc520cdp_map[i].virt = 0; - } - } - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/scb2_flash.c linux/drivers/mtd/maps/scb2_flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/scb2_flash.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/maps/scb2_flash.c 2004-11-19 10:25:11.972188696 +0100 -@@ -1,6 +1,6 @@ - /* - * MTD map driver for BIOS Flash on Intel SCB2 boards -- * $Id$ -+ * $Id$ - * Copyright (C) 2002 Sun Microsystems, Inc. - * Tim Hockin <thockin@sun.com> - * -@@ -14,7 +14,7 @@ - * try to request it here, but if it fails, we carry on anyway. - * - * This is how the chip is attached, so said the schematic: -- * * a 4 MiB (32 Mb) 16 bit chip -+ * * a 4 MiB (32 Mib) 16 bit chip - * * a 1 MiB memory region - * * A20 and A21 pulled up - * * D8-D15 ignored -@@ -48,6 +48,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -60,65 +61,13 @@ - #define SCB2_ADDR 0xfff00000 - #define SCB2_WINDOW 0x00100000 - --static __u8 scb2_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --static __u16 scb2_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --static __u32 scb2_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --static void scb2_copy_from(struct map_info *map, void *to, -- unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --static void scb2_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --static void scb2_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --static void scb2_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --static void scb2_copy_to(struct map_info *map, unsigned long to, -- const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} - - static void *scb2_ioaddr; - static struct mtd_info *scb2_mtd; - struct map_info scb2_map = { -- name: "SCB2 BIOS Flash", -- size: 0, -- buswidth: 1, -- read8: scb2_read8, -- read16: scb2_read16, -- read32: scb2_read32, -- copy_from: scb2_copy_from, -- write8: scb2_write8, -- write16: scb2_write16, -- write32: scb2_write32, -- copy_to: scb2_copy_to, -+ .name = "SCB2 BIOS Flash", -+ .size = 0, -+ .buswidth = 1, - }; - static int region_fail; - -@@ -137,6 +86,8 @@ - return -1; - } - -+ /* I wasn't here. I didn't see. dwmw2. */ -+ - /* the chip is sometimes bigger than the map - what a waste */ - mtd->size = map->size; - -@@ -211,9 +162,12 @@ - return -ENOMEM; - } - -- scb2_map.map_priv_1 = (unsigned long)scb2_ioaddr; -+ scb2_map.phys = SCB2_ADDR; -+ scb2_map.virt = (unsigned long)scb2_ioaddr; - scb2_map.size = SCB2_WINDOW; - -+ simple_map_init(&scb2_map); -+ - /* try to find a chip */ - scb2_mtd = do_map_probe("cfi_probe", &scb2_map); - -@@ -225,7 +179,7 @@ - return -ENODEV; - } - -- scb2_mtd->module = THIS_MODULE; -+ scb2_mtd->owner = THIS_MODULE; - if (scb2_fixup_mtd(scb2_mtd) < 0) { - del_mtd_device(scb2_mtd); - map_destroy(scb2_mtd); -@@ -235,7 +189,7 @@ - return -ENODEV; - } - -- printk(KERN_NOTICE MODNAME ": chip size %x at offset %x\n", -+ printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n", - scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size); - - add_mtd_device(scb2_mtd); -@@ -266,19 +220,19 @@ - - static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = { - { -- vendor: PCI_VENDOR_ID_SERVERWORKS, -- device: PCI_DEVICE_ID_SERVERWORKS_CSB5, -- subvendor: PCI_ANY_ID, -- subdevice: PCI_ANY_ID -+ .vendor = PCI_VENDOR_ID_SERVERWORKS, -+ .device = PCI_DEVICE_ID_SERVERWORKS_CSB5, -+ .subvendor = PCI_ANY_ID, -+ .subdevice = PCI_ANY_ID - }, - { 0, } - }; - - static struct pci_driver scb2_flash_driver = { -- name: "Intel SCB2 BIOS Flash", -- id_table: scb2_flash_pci_ids, -- probe: scb2_flash_probe, -- remove: __devexit_p(scb2_flash_remove), -+ .name = "Intel SCB2 BIOS Flash", -+ .id_table = scb2_flash_pci_ids, -+ .probe = scb2_flash_probe, -+ .remove = __devexit_p(scb2_flash_remove), - }; - - static int __init -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/scx200_docflash.c linux/drivers/mtd/maps/scx200_docflash.c ---- linux-mips-2.4.27/drivers/mtd/maps/scx200_docflash.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/maps/scx200_docflash.c 2004-11-19 10:25:11.973188544 +0100 -@@ -2,7 +2,7 @@ - - Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> - -- $Id$ -+ $Id$ - - National Semiconductor SCx200 flash mapped with DOCCS - */ -@@ -11,6 +11,7 @@ - #include <linux/config.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -75,46 +76,9 @@ - #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) - #endif - --static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs) --{ -- return __raw_readb(map->map_priv_1 + ofs); --} -- --static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs) --{ -- return __raw_readw(map->map_priv_1 + ofs); --} -- --static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); -- mb(); --} -- --static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); -- mb(); --} -- --static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} - - static struct map_info scx200_docflash_map = { - .name = "NatSemi SCx200 DOCCS Flash", -- .read8 = scx200_docflash_read8, -- .read16 = scx200_docflash_read16, -- .copy_from = scx200_docflash_copy_from, -- .write8 = scx200_docflash_write8, -- .write16 = scx200_docflash_write16, -- .copy_to = scx200_docflash_copy_to - }; - - int __init init_scx200_docflash(void) -@@ -213,8 +177,11 @@ - else - scx200_docflash_map.buswidth = 2; - -- scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size); -- if (!scx200_docflash_map.map_priv_1) { -+ simple_map_init(&scx200_docflash_map); -+ -+ scx200_docflash_map.phys = docmem.start; -+ scx200_docflash_map.virt = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size); -+ if (!scx200_docflash_map.virt) { - printk(KERN_ERR NAME ": failed to ioremap the flash\n"); - release_resource(&docmem); - return -EIO; -@@ -223,7 +190,7 @@ - mymtd = do_map_probe(flashtype, &scx200_docflash_map); - if (!mymtd) { - printk(KERN_ERR NAME ": unable to detect flash\n"); -- iounmap((void *)scx200_docflash_map.map_priv_1); -+ iounmap((void *)scx200_docflash_map.virt); - release_resource(&docmem); - return -ENXIO; - } -@@ -231,7 +198,7 @@ - if (size < mymtd->size) - printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n"); - -- mymtd->module = THIS_MODULE; -+ mymtd->owner = THIS_MODULE; - - #if PARTITION - partition_info[3].offset = mymtd->size-partition_info[3].size; -@@ -253,8 +220,8 @@ - #endif - map_destroy(mymtd); - } -- if (scx200_docflash_map.map_priv_1) { -- iounmap((void *)scx200_docflash_map.map_priv_1); -+ if (scx200_docflash_map.virt) { -+ iounmap((void *)scx200_docflash_map.virt); - release_resource(&docmem); - } - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/solutionengine.c linux/drivers/mtd/maps/solutionengine.c ---- linux-mips-2.4.27/drivers/mtd/maps/solutionengine.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/solutionengine.c 2004-11-19 10:25:11.975188240 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Flash and EPROM on Hitachi Solution Engine and similar boards. - * -@@ -11,6 +11,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/map.h> -@@ -18,60 +19,39 @@ - #include <linux/config.h> - - --extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -- --__u32 soleng_read32(struct map_info *map, unsigned long ofs) --{ -- return __raw_readl(map->map_priv_1 + ofs); --} -- --void soleng_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); -- mb(); --} -- --void soleng_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- -- - static struct mtd_info *flash_mtd; - static struct mtd_info *eprom_mtd; - - static struct mtd_partition *parsed_parts; - - struct map_info soleng_eprom_map = { -- name: "Solution Engine EPROM", -- size: 0x400000, -- buswidth: 4, -- copy_from: soleng_copy_from, -+ .name = "Solution Engine EPROM", -+ .size = 0x400000, -+ .buswidth = 4, - }; - - struct map_info soleng_flash_map = { -- name: "Solution Engine FLASH", -- size: 0x400000, -- buswidth: 4, -- read32: soleng_read32, -- copy_from: soleng_copy_from, -- write32: soleng_write32, -+ .name = "Solution Engine FLASH", -+ .size = 0x400000, -+ .buswidth = 4, - }; - -+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; -+ - #ifdef CONFIG_MTD_SUPERH_RESERVE - static struct mtd_partition superh_se_partitions[] = { - /* Reserved for boot code, read-only */ - { -- name: "flash_boot", -- offset: 0x00000000, -- size: CONFIG_MTD_SUPERH_RESERVE, -- mask_flags: MTD_WRITEABLE, -+ .name = "flash_boot", -+ .offset = 0x00000000, -+ .size = CONFIG_MTD_SUPERH_RESERVE, -+ .mask_flags = MTD_WRITEABLE, - }, - /* All else is writable (e.g. JFFS) */ - { -- name: "Flash FS", -- offset: MTDPART_OFS_NXTBLK, -- size: MTDPART_SIZ_FULL, -+ .name = "Flash FS", -+ .offset = MTDPART_OFS_NXTBLK, -+ .size = MTDPART_SIZ_FULL, - } - }; - #endif /* CONFIG_MTD_SUPERH_RESERVE */ -@@ -81,16 +61,22 @@ - int nr_parts = 0; - - /* First probe at offset 0 */ -- soleng_flash_map.map_priv_1 = P2SEGADDR(0); -- soleng_eprom_map.map_priv_1 = P1SEGADDR(0x01000000); -+ soleng_flash_map.phys = 0; -+ soleng_flash_map.virt = P2SEGADDR(0); -+ soleng_eprom_map.phys = 0x01000000; -+ soleng_eprom_map.virt = P1SEGADDR(0x01000000); -+ simple_map_init(&soleng_eprom_map); -+ simple_map_init(&soleng_flash_map); - - printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); - flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); - if (!flash_mtd) { - /* Not there. Try swapping */ - printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n"); -- soleng_flash_map.map_priv_1 = P2SEGADDR(0x01000000); -- soleng_eprom_map.map_priv_1 = P1SEGADDR(0); -+ soleng_flash_map.phys = 0x01000000; -+ soleng_flash_map.virt = P2SEGADDR(0x01000000); -+ soleng_eprom_map.phys = 0; -+ soleng_eprom_map.virt = P1SEGADDR(0); - flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); - if (!flash_mtd) { - /* Eep. */ -@@ -99,25 +85,20 @@ - } - } - printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n", -- soleng_flash_map.map_priv_1 & 0x1fffffff, -- soleng_eprom_map.map_priv_1 & 0x1fffffff); -- flash_mtd->module = THIS_MODULE; -+ soleng_flash_map.phys & 0x1fffffff, -+ soleng_eprom_map.phys & 0x1fffffff); -+ flash_mtd->owner = THIS_MODULE; - - eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map); - if (eprom_mtd) { -- eprom_mtd->module = THIS_MODULE; -+ eprom_mtd->owner = THIS_MODULE; - add_mtd_device(eprom_mtd); - } - --#ifdef CONFIG_MTD_REDBOOT_PARTS -- nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); -- if (nr_parts > 0) -- printk(KERN_NOTICE "Found RedBoot partition table.\n"); -- else if (nr_parts < 0) -- printk(KERN_NOTICE "Error looking for RedBoot partitions.\n"); --#endif /* CONFIG_MTD_REDBOOT_PARTS */ -+ nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); -+ - #if CONFIG_MTD_SUPERH_RESERVE -- if (nr_parts == 0) { -+ if (nr_parts <= 0) { - printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", - CONFIG_MTD_SUPERH_RESERVE); - parsed_parts = superh_se_partitions; -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/sun_uflash.c linux/drivers/mtd/maps/sun_uflash.c ---- linux-mips-2.4.27/drivers/mtd/maps/sun_uflash.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/sun_uflash.c 2004-11-19 10:25:11.976188088 +0100 -@@ -1,4 +1,4 @@ --/* $Id$ -+/* $Id$ - * - * sun_uflash - Driver implementation for user-programmable flash - * present on many Sun Microsystems SME boardsets. -@@ -48,60 +48,11 @@ - struct list_head list; - }; - --__u8 uflash_read8(struct map_info *map, unsigned long ofs) --{ -- return(__raw_readb(map->map_priv_1 + ofs)); --} -- --__u16 uflash_read16(struct map_info *map, unsigned long ofs) --{ -- return(__raw_readw(map->map_priv_1 + ofs)); --} -- --__u32 uflash_read32(struct map_info *map, unsigned long ofs) --{ -- return(__raw_readl(map->map_priv_1 + ofs)); --} -- --void uflash_copy_from(struct map_info *map, void *to, unsigned long from, -- ssize_t len) --{ -- memcpy_fromio(to, map->map_priv_1 + from, len); --} -- --void uflash_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- __raw_writeb(d, map->map_priv_1 + adr); --} -- --void uflash_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- __raw_writew(d, map->map_priv_1 + adr); --} -- --void uflash_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- __raw_writel(d, map->map_priv_1 + adr); --} -- --void uflash_copy_to(struct map_info *map, unsigned long to, const void *from, -- ssize_t len) --{ -- memcpy_toio(map->map_priv_1 + to, from, len); --} - - struct map_info uflash_map_templ = { -- name: "SUNW,???-????", -- size: UFLASH_WINDOW_SIZE, -- buswidth: UFLASH_BUSWIDTH, -- read8: uflash_read8, -- read16: uflash_read16, -- read32: uflash_read32, -- copy_from: uflash_copy_from, -- write8: uflash_write8, -- write16: uflash_write16, -- write32: uflash_write32, -- copy_to: uflash_copy_to -+ .name = "SUNW,???-????", -+ .size = UFLASH_WINDOW_SIZE, -+ .buswidth = UFLASH_BUSWIDTH, - }; - - int uflash_devinit(struct linux_ebus_device* edev) -@@ -145,20 +96,22 @@ - if(0 != pdev->name && 0 < strlen(pdev->name)) { - pdev->map.name = pdev->name; - } -- -- pdev->map.map_priv_1 = -+ pdev->phys = edev->resource[0].start; -+ pdev->virt = - (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size); -- if(0 == pdev->map.map_priv_1) { -+ if(0 == pdev->map.virt) { - printk("%s: failed to map device\n", __FUNCTION__); - kfree(pdev->name); - kfree(pdev); - return(-1); - } - -+ simple_map_init(&pdev->map); -+ - /* MTD registration */ - pdev->mtd = do_map_probe("cfi_probe", &pdev->map); - if(0 == pdev->mtd) { -- iounmap((void *)pdev->map.map_priv_1); -+ iounmap((void *)pdev->map.virt); - kfree(pdev->name); - kfree(pdev); - return(-ENXIO); -@@ -166,7 +119,7 @@ - - list_add(&pdev->list, &device_list); - -- pdev->mtd->module = THIS_MODULE; -+ pdev->mtd->owner = THIS_MODULE; - - add_mtd_device(pdev->mtd); - return(0); -@@ -211,9 +164,9 @@ - del_mtd_device(udev->mtd); - map_destroy(udev->mtd); - } -- if(0 != udev->map.map_priv_1) { -- iounmap((void*)udev->map.map_priv_1); -- udev->map.map_priv_1 = 0; -+ if(0 != udev->map.virt) { -+ iounmap((void*)udev->map.virt); -+ udev->map.virt = 0; - } - if(0 != udev->name) { - kfree(udev->name); -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/tqm8xxl.c linux/drivers/mtd/maps/tqm8xxl.c ---- linux-mips-2.4.27/drivers/mtd/maps/tqm8xxl.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/maps/tqm8xxl.c 2004-11-19 10:25:11.978187784 +0100 -@@ -2,7 +2,7 @@ - * Handle mapping of the flash memory access routines - * on TQM8xxL based devices. - * -- * $Id$ -+ * $Id$ - * - * based on rpxlite.c - * -@@ -26,6 +26,7 @@ - #include <linux/module.h> - #include <linux/types.h> - #include <linux/kernel.h> -+#include <linux/init.h> - #include <asm/io.h> - - #include <linux/mtd/mtd.h> -@@ -51,46 +52,6 @@ - static unsigned long num_banks; - static unsigned long start_scan_addr; - --__u8 tqm8xxl_read8(struct map_info *map, unsigned long ofs) --{ -- return *((__u8 *)(map->map_priv_1 + ofs)); --} -- --__u16 tqm8xxl_read16(struct map_info *map, unsigned long ofs) --{ -- return *((__u16 *)(map->map_priv_1 + ofs)); --} -- --__u32 tqm8xxl_read32(struct map_info *map, unsigned long ofs) --{ -- return *((__u32 *)(map->map_priv_1 + ofs)); --} -- --void tqm8xxl_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); --} -- --void tqm8xxl_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- *((__u8 *)(map->map_priv_1 + adr)) = d; --} -- --void tqm8xxl_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- *((__u16 *)( map->map_priv_1 + adr)) = d; --} -- --void tqm8xxl_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- *((__u32 *)(map->map_priv_1 + adr)) = d; --} -- --void tqm8xxl_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy_toio((void *)(map->map_priv_1 + to), from, len); --} -- - /* - * Here are partition information for all known TQM8xxL series devices. - * See include/linux/mtd/partitions.h for definition of the mtd_partition -@@ -107,50 +68,48 @@ - static unsigned long tqm8xxl_max_flash_size = 0x00800000; - - /* partition definition for first flash bank -- * also ref. to "drivers\char\flash_config.c" -+ * (cf. "drivers/char/flash_config.c") - */ - static struct mtd_partition tqm8xxl_partitions[] = { - { -- name: "ppcboot", -- offset: 0x00000000, -- size: 0x00020000, /* 128KB */ -- mask_flags: MTD_WRITEABLE, /* force read-only */ -+ .name = "ppcboot", -+ .offset = 0x00000000, -+ .size = 0x00020000, /* 128KB */ -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { -- name: "kernel", /* default kernel image */ -- offset: 0x00020000, -- size: 0x000e0000, -- mask_flags: MTD_WRITEABLE, /* force read-only */ -+ .name = "kernel", /* default kernel image */ -+ .offset = 0x00020000, -+ .size = 0x000e0000, -+ .mask_flags = MTD_WRITEABLE, /* force read-only */ - }, - { -- name: "user", -- offset: 0x00100000, -- size: 0x00100000, -+ .name = "user", -+ .offset = 0x00100000, -+ .size = 0x00100000, - }, - { -- name: "initrd", -- offset: 0x00200000, -- size: 0x00200000, -+ .name = "initrd", -+ .offset = 0x00200000, -+ .size = 0x00200000, - } - }; --/* partition definition for second flahs bank */ -+/* partition definition for second flash bank */ - static struct mtd_partition tqm8xxl_fs_partitions[] = { - { -- name: "cramfs", -- offset: 0x00000000, -- size: 0x00200000, -+ .name = "cramfs", -+ .offset = 0x00000000, -+ .size = 0x00200000, - }, - { -- name: "jffs", -- offset: 0x00200000, -- size: 0x00200000, -- //size: MTDPART_SIZ_FULL, -+ .name = "jffs", -+ .offset = 0x00200000, -+ .size = 0x00200000, -+ .//size = MTDPART_SIZ_FULL, - } - }; - #endif - --#define NB_OF(x) (sizeof(x)/sizeof(x[0])) -- - int __init init_tqm_mtd(void) - { - int idx = 0, ret = 0; -@@ -160,67 +119,73 @@ - - flash_addr = bd->bi_flashstart; - flash_size = bd->bi_flashsize; -- //request maximum flash size address spzce -+ -+ //request maximum flash size address space - start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); - if (!start_scan_addr) { -- //printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, FLASH_ADDR); -- printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); -+ printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); - return -EIO; - } -- for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) -- { -+ -+ for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { - if(mtd_size >= flash_size) - break; - -- printk("%s: chip probing count %d\n", __FUNCTION__, idx); -+ printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); - - map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); -- if(map_banks[idx] == NULL) -- { -- //return -ENOMEM; -+ if(map_banks[idx] == NULL) { - ret = -ENOMEM; -+ /* FIXME: What if some MTD devices were probed already? */ - goto error_mem; - } -+ - memset((void *)map_banks[idx], 0, sizeof(struct map_info)); - map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); -- if(map_banks[idx]->name == NULL) -- { -- //return -ENOMEM; -+ -+ if (!map_banks[idx]->name) { - ret = -ENOMEM; -+ /* FIXME: What if some MTD devices were probed already? */ - goto error_mem; - } -- memset((void *)map_banks[idx]->name, 0, 16); -- - sprintf(map_banks[idx]->name, "TQM8xxL%d", idx); -+ - map_banks[idx]->size = flash_size; - map_banks[idx]->buswidth = 4; -- map_banks[idx]->read8 = tqm8xxl_read8; -- map_banks[idx]->read16 = tqm8xxl_read16; -- map_banks[idx]->read32 = tqm8xxl_read32; -- map_banks[idx]->copy_from = tqm8xxl_copy_from; -- map_banks[idx]->write8 = tqm8xxl_write8; -- map_banks[idx]->write16 = tqm8xxl_write16; -- map_banks[idx]->write32 = tqm8xxl_write32; -- map_banks[idx]->copy_to = tqm8xxl_copy_to; -+ -+ simple_map_init(map_banks[idx]); -+ -+ map_banks[idx]->virt = start_scan_addr; -+ map_banks[idx]->phys = flash_addr; -+ /* FIXME: This looks utterly bogus, but I'm trying to -+ preserve the behaviour of the original (shown here)... -+ - map_banks[idx]->map_priv_1 = - start_scan_addr + ((idx > 0) ? - (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); -+ */ -+ -+ if (idx && mtd_banks[idx-1]) { -+ map_banks[idx]->virt += mtd_banks[idx-1]->size; -+ map_banks[idx]->phys += mtd_banks[idx-1]->size; -+ } -+ - //start to probe flash chips - mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); -- if(mtd_banks[idx]) -- { -- mtd_banks[idx]->module = THIS_MODULE; -+ -+ if (mtd_banks[idx]) { -+ mtd_banks[idx]->owner = THIS_MODULE; - mtd_size += mtd_banks[idx]->size; - num_banks++; -- printk("%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, -+ -+ printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, - mtd_banks[idx]->name, mtd_banks[idx]->size); - } - } - - /* no supported flash chips found */ -- if(!num_banks) -- { -- printk("TQM8xxL: No support flash chips found!\n"); -+ if (!num_banks) { -+ printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n"); - ret = -ENXIO; - goto error_mem; - } -@@ -231,12 +196,13 @@ - */ - part_banks[0].mtd_part = tqm8xxl_partitions; - part_banks[0].type = "Static image"; -- part_banks[0].nums = NB_OF(tqm8xxl_partitions); -+ part_banks[0].nums = ARRAY_SIZE(tqm8xxl_partitions); -+ - part_banks[1].mtd_part = tqm8xxl_fs_partitions; - part_banks[1].type = "Static file system"; -- part_banks[1].nums = NB_OF(tqm8xxl_fs_partitions); -- for(idx = 0; idx < num_banks ; idx++) -- { -+ part_banks[1].nums = ARRAY_SIZE(tqm8xxl_fs_partitions); -+ -+ for(idx = 0; idx < num_banks ; idx++) { - if (part_banks[idx].nums == 0) { - printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx); - add_mtd_device(mtd_banks[idx]); -@@ -254,12 +220,9 @@ - #endif - return 0; - error_mem: -- for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) -- { -- if(map_banks[idx] != NULL) -- { -- if(map_banks[idx]->name != NULL) -- { -+ for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { -+ if(map_banks[idx] != NULL) { -+ if(map_banks[idx]->name != NULL) { - kfree(map_banks[idx]->name); - map_banks[idx]->name = NULL; - } -@@ -267,18 +230,15 @@ - map_banks[idx] = NULL; - } - } -- //return -ENOMEM; - error: - iounmap((void *)start_scan_addr); -- //return -ENXIO; - return ret; - } - - static void __exit cleanup_tqm_mtd(void) - { - unsigned int idx = 0; -- for(idx = 0 ; idx < num_banks ; idx++) -- { -+ for(idx = 0 ; idx < num_banks ; idx++) { - /* destroy mtd_info previously allocated */ - if (mtd_banks[idx]) { - del_mtd_partitions(mtd_banks[idx]); -@@ -288,6 +248,7 @@ - kfree(map_banks[idx]->name); - kfree(map_banks[idx]); - } -+ - if (start_scan_addr) { - iounmap((void *)start_scan_addr); - start_scan_addr = 0; -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/tsunami_flash.c linux/drivers/mtd/maps/tsunami_flash.c ---- linux-mips-2.4.27/drivers/mtd/maps/tsunami_flash.c 2002-06-27 00:35:50.000000000 +0200 -+++ linux/drivers/mtd/maps/tsunami_flash.c 2004-11-19 10:25:11.979187632 +0100 -@@ -2,11 +2,13 @@ - * tsunami_flash.c - * - * flash chip on alpha ds10... -- * $Id$ -+ * $Id$ - */ - #include <asm/io.h> - #include <asm/core_tsunami.h> -+#include <linux/init.h> - #include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> - - #define FLASH_ENABLE_PORT 0x00C00001 - #define FLASH_ENABLE_BYTE 0x01 -@@ -58,18 +60,12 @@ - static struct map_info tsunami_flash_map = { - .name = "flash chip on the Tsunami TIG bus", - .size = MAX_TIG_FLASH_SIZE, -+ .phys = NO_XIP; - .buswidth = 1, - .read8 = tsunami_flash_read8, -- .read16 = 0, -- .read32 = 0, - .copy_from = tsunami_flash_copy_from, - .write8 = tsunami_flash_write8, -- .write16 = 0, -- .write32 = 0, - .copy_to = tsunami_flash_copy_to, -- .set_vpp = 0, -- .map_priv_1 = 0, -- - }; - - static struct mtd_info *tsunami_flash_mtd; -@@ -99,7 +95,7 @@ - tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map); - } - if (tsunami_flash_mtd) { -- tsunami_flash_mtd->module = THIS_MODULE; -+ tsunami_flash_mtd->owner = THIS_MODULE; - add_mtd_device(tsunami_flash_mtd); - return 0; - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/uclinux.c linux/drivers/mtd/maps/uclinux.c ---- linux-mips-2.4.27/drivers/mtd/maps/uclinux.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/maps/uclinux.c 2004-11-19 10:25:11.980187480 +0100 -@@ -5,7 +5,7 @@ - * - * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) - * -- * $Id$ -+ * $Id$ - */ - - /****************************************************************************/ -@@ -24,58 +24,11 @@ - - /****************************************************************************/ - --__u8 uclinux_read8(struct map_info *map, unsigned long ofs) --{ -- return(*((__u8 *) (map->map_priv_1 + ofs))); --} -- --__u16 uclinux_read16(struct map_info *map, unsigned long ofs) --{ -- return(*((__u16 *) (map->map_priv_1 + ofs))); --} -- --__u32 uclinux_read32(struct map_info *map, unsigned long ofs) --{ -- return(*((__u32 *) (map->map_priv_1 + ofs))); --} -- --void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) --{ -- memcpy(to, (void *)(map->map_priv_1 + from), len); --} -- --void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr) --{ -- *((__u8 *) (map->map_priv_1 + adr)) = d; --} -- --void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr) --{ -- *((__u16 *) (map->map_priv_1 + adr)) = d; --} -- --void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr) --{ -- *((__u32 *) (map->map_priv_1 + adr)) = d; --} -- --void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) --{ -- memcpy((void *) (map->map_priv_1 + to), from, len); --} - - /****************************************************************************/ - - struct map_info uclinux_ram_map = { -- name: "RAM", -- read8: uclinux_read8, -- read16: uclinux_read16, -- read32: uclinux_read32, -- copy_from: uclinux_copy_from, -- write8: uclinux_write8, -- write16: uclinux_write16, -- write32: uclinux_write32, -- copy_to: uclinux_copy_to, -+ .name = "RAM", - }; - - struct mtd_info *uclinux_ram_mtdinfo; -@@ -83,7 +36,7 @@ - /****************************************************************************/ - - struct mtd_partition uclinux_romfs[] = { -- { name: "ROMfs", offset: 0 } -+ { .name = "ROMfs" } - }; - - #define NUM_PARTITIONS (sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0])) -@@ -94,7 +47,7 @@ - size_t *retlen, u_char **mtdbuf) - { - struct map_info *map = (struct map_info *) mtd->priv; -- *mtdbuf = (u_char *) (map->map_priv_1 + ((int) from)); -+ *mtdbuf = (u_char *) (map->virt + ((int) from)); - *retlen = len; - return(0); - } -@@ -108,29 +61,31 @@ - extern char _ebss; - - mapp = &uclinux_ram_map; -- mapp->map_priv_2 = (unsigned long) &_ebss; -+ mapp->phys = (unsigned long) &_ebss; - mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8))); - mapp->buswidth = 4; - - printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", - (int) mapp->map_priv_2, (int) mapp->size); - -- mapp->map_priv_1 = (unsigned long) -- ioremap_nocache(mapp->map_priv_2, mapp->size); -+ mapp->virt = (unsigned long) -+ ioremap_nocache(mapp->phys, mapp->size); - -- if (mapp->map_priv_1 == 0) { -+ if (mapp->virt == 0) { - printk("uclinux[mtd]: ioremap_nocache() failed\n"); - return(-EIO); - } - -+ simple_map_init(mapp); -+ - mtd = do_map_probe("map_ram", mapp); - if (!mtd) { - printk("uclinux[mtd]: failed to find a mapping?\n"); -- iounmap((void *) mapp->map_priv_1); -+ iounmap((void *) mapp->virt); - return(-ENXIO); - } - -- mtd->module = THIS_MODULE; -+ mtd->owner = THIS_MODULE; - mtd->point = uclinux_point; - mtd->priv = mapp; - -@@ -155,8 +110,8 @@ - uclinux_ram_mtdinfo = NULL; - } - if (uclinux_ram_map.map_priv_1) { -- iounmap((void *) uclinux_ram_map.map_priv_1); -- uclinux_ram_map.map_priv_1 = 0; -+ iounmap((void *) uclinux_ram_map.virt); -+ uclinux_ram_map.virt = 0; - } - } - -diff -Nurb linux-mips-2.4.27/drivers/mtd/maps/vmax301.c linux/drivers/mtd/maps/vmax301.c ---- linux-mips-2.4.27/drivers/mtd/maps/vmax301.c 2001-11-05 21:15:52.000000000 +0100 -+++ linux/drivers/mtd/maps/vmax301.c 2004-11-19 10:25:11.982187176 +0100 -@@ -1,4 +1,4 @@ --// $Id$ -+// $Id$ - /* ###################################################################### - - Tempustech VMAX SBC301 MTD Driver. -@@ -24,6 +24,7 @@ - #include <asm/io.h> - - #include <linux/mtd/map.h> -+#include <linux/mtd/mtd.h> - - - #define WINDOW_START 0xd8000 -@@ -142,34 +143,36 @@ - - static struct map_info vmax_map[2] = { - { -- name: "VMAX301 Internal Flash", -- size: 3*2*1024*1024, -- buswidth: 1, -- read8: vmax301_read8, -- read16: vmax301_read16, -- read32: vmax301_read32, -- copy_from: vmax301_copy_from, -- write8: vmax301_write8, -- write16: vmax301_write16, -- write32: vmax301_write32, -- copy_to: vmax301_copy_to, -- map_priv_1: WINDOW_START + WINDOW_LENGTH, -- map_priv_2: 0xFFFFFFFF -+ .name = "VMAX301 Internal Flash", -+ .phys = NO_XIP, -+ .size = 3*2*1024*1024, -+ .buswidth = 1, -+ .read8 = vmax301_read8, -+ .read16 = vmax301_read16, -+ .read32 = vmax301_read32, -+ .copy_from = vmax301_copy_from, -+ .write8 = vmax301_write8, -+ .write16 = vmax301_write16, -+ .write32 = vmax301_write32, -+ .copy_to = vmax301_copy_to, -+ .map_priv_1 = WINDOW_START + WINDOW_LENGTH, -+ .map_priv_2 = 0xFFFFFFFF - }, - { -- name: "VMAX301 Socket", -- size: 0, -- buswidth: 1, -- read8: vmax301_read8, -- read16: vmax301_read16, -- read32: vmax301_read32, -- copy_from: vmax301_copy_from, -- write8: vmax301_write8, -- write16: vmax301_write16, -- write32: vmax301_write32, -- copy_to: vmax301_copy_to, -- map_priv_1: WINDOW_START + (3*WINDOW_LENGTH), -- map_priv_2: 0xFFFFFFFF -+ .name = "VMAX301 Socket", -+ .phys = NO_XIP, -+ .size = 0, -+ .buswidth = 1, -+ .read8 = vmax301_read8, -+ .read16 = vmax301_read16, -+ .read32 = vmax301_read32, -+ .copy_from = vmax301_copy_from, -+ .write8 = vmax301_write8, -+ .write16 = vmax301_write16, -+ .write32 = vmax301_write32, -+ .copy_to = vmax301_copy_to, -+ .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH), -+ .map_priv_2 = 0xFFFFFFFF - } - }; - -@@ -206,8 +209,8 @@ - address of the first half, because it's used more - often. - */ -- vmax_map[0].map_priv_1 = iomapadr + WINDOW_START; -- vmax_map[1].map_priv_1 = iomapadr + (3*WINDOW_START); -+ vmax_map[0].map_priv_2 = iomapadr + WINDOW_START; -+ vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START); - - for (i=0; i<2; i++) { - vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]); -@@ -218,7 +221,7 @@ - if (!vmax_mtd[i]) - vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]); - if (vmax_mtd[i]) { -- vmax_mtd[i]->module = THIS_MODULE; -+ vmax_mtd[i]->owner = THIS_MODULE; - add_mtd_device(vmax_mtd[i]); - } - } -diff -Nurb linux-mips-2.4.27/drivers/mtd/mtd_blkdevs-24.c linux/drivers/mtd/mtd_blkdevs-24.c ---- linux-mips-2.4.27/drivers/mtd/mtd_blkdevs-24.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/mtd_blkdevs-24.c 2004-11-19 10:25:11.640239160 +0100 -@@ -0,0 +1,699 @@ -+/* -+ * $Id$ -+ * -+ * (C) 2003 David Woodhouse <dwmw2@infradead.org> -+ * -+ * Interface to Linux 2.4 block layer for MTD 'translation layers'. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/module.h> -+#include <linux/list.h> -+#include <linux/fs.h> -+#include <linux/mtd/blktrans.h> -+#include <linux/mtd/mtd.h> -+#include <linux/blkdev.h> -+#include <linux/blk.h> -+#include <linux/blkpg.h> -+#include <linux/spinlock.h> -+#include <linux/hdreg.h> -+#include <linux/init.h> -+#include <asm/semaphore.h> -+#include <asm/uaccess.h> -+ -+static LIST_HEAD(blktrans_majors); -+ -+extern struct semaphore mtd_table_mutex; -+extern struct mtd_info *mtd_table[]; -+ -+struct mtd_blkcore_priv { -+ devfs_handle_t devfs_dir_handle; -+ int blksizes[256]; -+ int sizes[256]; -+ struct hd_struct part_table[256]; -+ struct gendisk gd; -+ spinlock_t devs_lock; /* See comment in _request function */ -+ struct completion thread_dead; -+ int exiting; -+ wait_queue_head_t thread_wq; -+}; -+ -+static inline struct mtd_blktrans_dev *tr_get_dev(struct mtd_blktrans_ops *tr, -+ int devnum) -+{ -+ struct list_head *this; -+ struct mtd_blktrans_dev *d; -+ -+ list_for_each(this, &tr->devs) { -+ d = list_entry(this, struct mtd_blktrans_dev, list); -+ -+ if (d->devnum == devnum) -+ return d; -+ } -+ return NULL; -+} -+ -+static inline struct mtd_blktrans_ops *get_tr(int major) -+{ -+ struct list_head *this; -+ struct mtd_blktrans_ops *t; -+ -+ list_for_each(this, &blktrans_majors) { -+ t = list_entry(this, struct mtd_blktrans_ops, list); -+ -+ if (t->major == major) -+ return t; -+ } -+ return NULL; -+} -+ -+static int do_blktrans_request(struct mtd_blktrans_ops *tr, -+ struct mtd_blktrans_dev *dev, -+ struct request *req) -+{ -+ unsigned long block, nsect; -+ char *buf; -+ int minor; -+ -+ minor = MINOR(req->rq_dev); -+ block = req->sector; -+ nsect = req->current_nr_sectors; -+ buf = req->buffer; -+ -+ if (block + nsect > tr->blkcore_priv->part_table[minor].nr_sects) { -+ printk(KERN_WARNING "Access beyond end of device.\n"); -+ return 0; -+ } -+ block += tr->blkcore_priv->part_table[minor].start_sect; -+ -+ switch(req->cmd) { -+ case READ: -+ for (; nsect > 0; nsect--, block++, buf += 512) -+ if (tr->readsect(dev, block, buf)) -+ return 0; -+ return 1; -+ -+ case WRITE: -+ if (!tr->writesect) -+ return 0; -+ -+ for (; nsect > 0; nsect--, block++, buf += 512) -+ if (tr->writesect(dev, block, buf)) -+ return 0; -+ return 1; -+ -+ default: -+ printk(KERN_NOTICE "Unknown request cmd %d\n", req->cmd); -+ return 0; -+ } -+} -+ -+static int mtd_blktrans_thread(void *arg) -+{ -+ struct mtd_blktrans_ops *tr = arg; -+ struct request_queue *rq = BLK_DEFAULT_QUEUE(tr->major); -+ -+ /* we might get involved when memory gets low, so use PF_MEMALLOC */ -+ current->flags |= PF_MEMALLOC; -+ -+ snprintf(current->comm, sizeof(current->comm), "%sd", tr->name); -+ -+ /* daemonize() doesn't do this for us since some kernel threads -+ actually want to deal with signals. We can't just call -+ exit_sighand() since that'll cause an oops when we finally -+ do exit. */ -+ -+#ifndef __rh_config_h__ /* HAVE_NPTL */ -+ spin_lock_irq(¤t->sigmask_lock); -+ sigfillset(¤t->blocked); -+ recalc_sigpending(current); -+ spin_unlock_irq(¤t->sigmask_lock); -+#else -+ spin_lock_irq(¤t->sighand->siglock); -+ sigfillset(¤t->blocked); -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->sighand->siglock); -+#endif -+ daemonize(); -+ -+ while (!tr->blkcore_priv->exiting) { -+ struct request *req; -+ struct mtd_blktrans_dev *dev; -+ int devnum; -+ int res = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ spin_lock_irq(&io_request_lock); -+ -+ if (list_empty(&rq->queue_head)) { -+ -+ add_wait_queue(&tr->blkcore_priv->thread_wq, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ spin_unlock_irq(&io_request_lock); -+ -+ schedule(); -+ remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait); -+ -+ continue; -+ } -+ -+ req = blkdev_entry_next_request(&rq->queue_head); -+ -+ devnum = MINOR(req->rq_dev) >> tr->part_bits; -+ -+ /* The ll_rw_blk code knows not to touch the request -+ at the head of the queue */ -+ spin_unlock_irq(&io_request_lock); -+ -+ /* FIXME: Where can we store the dev, on which -+ we already have a refcount anyway? We need to -+ lock against concurrent addition/removal of devices, -+ but if we use the mtd_table_mutex we deadlock when -+ grok_partitions is called from the registration -+ callbacks. */ -+ spin_lock(&tr->blkcore_priv->devs_lock); -+ dev = tr_get_dev(tr, devnum); -+ spin_unlock(&tr->blkcore_priv->devs_lock); -+ -+ BUG_ON(!dev); -+ -+ /* Ensure serialisation of requests */ -+ down(&dev->sem); -+ -+ res = do_blktrans_request(tr, dev, req); -+ up(&dev->sem); -+ -+ if (!end_that_request_first(req, res, tr->name)) { -+ spin_lock_irq(&io_request_lock); -+ blkdev_dequeue_request(req); -+ end_that_request_last(req); -+ spin_unlock_irq(&io_request_lock); -+ } -+ } -+ complete_and_exit(&tr->blkcore_priv->thread_dead, 0); -+} -+ -+static void mtd_blktrans_request(struct request_queue *rq) -+{ -+ struct mtd_blktrans_ops *tr = rq->queuedata; -+ wake_up(&tr->blkcore_priv->thread_wq); -+} -+ -+int blktrans_open(struct inode *i, struct file *f) -+{ -+ struct mtd_blktrans_ops *tr = NULL; -+ struct mtd_blktrans_dev *dev = NULL; -+ int major_nr = MAJOR(i->i_rdev); -+ int minor_nr = MINOR(i->i_rdev); -+ int devnum; -+ int ret = -ENODEV; -+ -+ if (is_read_only(i->i_rdev) && (f->f_mode & FMODE_WRITE)) -+ return -EROFS; -+ -+ down(&mtd_table_mutex); -+ -+ tr = get_tr(major_nr); -+ -+ if (!tr) -+ goto out; -+ -+ devnum = minor_nr >> tr->part_bits; -+ -+ dev = tr_get_dev(tr, devnum); -+ -+ if (!dev) -+ goto out; -+ -+ if (!tr->blkcore_priv->part_table[minor_nr].nr_sects) { -+ ret = -ENODEV; -+ goto out; -+ } -+ -+ if (!try_inc_mod_count(dev->mtd->owner)) -+ goto out; -+ -+ if (!try_inc_mod_count(tr->owner)) -+ goto out_tr; -+ -+ dev->mtd->usecount++; -+ -+ ret = 0; -+ if (tr->open && (ret = tr->open(dev))) { -+ dev->mtd->usecount--; -+ if (dev->mtd->owner) -+ __MOD_DEC_USE_COUNT(dev->mtd->owner); -+ out_tr: -+ if (tr->owner) -+ __MOD_DEC_USE_COUNT(tr->owner); -+ } -+ out: -+ up(&mtd_table_mutex); -+ -+ return ret; -+} -+ -+int blktrans_release(struct inode *i, struct file *f) -+{ -+ struct mtd_blktrans_dev *dev; -+ struct mtd_blktrans_ops *tr; -+ int ret = 0; -+ int devnum; -+ -+ down(&mtd_table_mutex); -+ -+ tr = get_tr(MAJOR(i->i_rdev)); -+ if (!tr) { -+ up(&mtd_table_mutex); -+ return -ENODEV; -+ } -+ -+ devnum = MINOR(i->i_rdev) >> tr->part_bits; -+ dev = tr_get_dev(tr, devnum); -+ -+ if (!dev) { -+ up(&mtd_table_mutex); -+ return -ENODEV; -+ } -+ -+ if (tr->release) -+ ret = tr->release(dev); -+ -+ if (!ret) { -+ dev->mtd->usecount--; -+ if (dev->mtd->owner) -+ __MOD_DEC_USE_COUNT(dev->mtd->owner); -+ if (tr->owner) -+ __MOD_DEC_USE_COUNT(tr->owner); -+ } -+ -+ up(&mtd_table_mutex); -+ -+ return ret; -+} -+ -+static int mtd_blktrans_rrpart(kdev_t rdev, struct mtd_blktrans_ops *tr, -+ struct mtd_blktrans_dev *dev) -+{ -+ struct gendisk *gd = &(tr->blkcore_priv->gd); -+ int i; -+ int minor = MINOR(rdev); -+ -+ if (minor & ((1<<tr->part_bits)-1) || !tr->part_bits) { -+ /* BLKRRPART on a partition. Go away. */ -+ return -ENOTTY; -+ } -+ -+ if (!capable(CAP_SYS_ADMIN)) -+ return -EACCES; -+ -+ /* We are required to prevent simultaneous open() ourselves. -+ The core doesn't do that for us. Did I ever mention how -+ much the Linux block layer sucks? Sledgehammer approach... */ -+ down(&mtd_table_mutex); -+ -+ for (i=0; i < (1<<tr->part_bits); i++) { -+ invalidate_device(MKDEV(tr->major, minor+i), 1); -+ gd->part[minor + i].start_sect = 0; -+ gd->part[minor + i].nr_sects = 0; -+ } -+ -+ grok_partitions(gd, minor, 1 << tr->part_bits, -+ tr->blkcore_priv->sizes[minor]); -+ up(&mtd_table_mutex); -+ -+ return 0; -+} -+ -+static int blktrans_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct mtd_blktrans_dev *dev; -+ struct mtd_blktrans_ops *tr; -+ int devnum; -+ -+ switch(cmd) { -+ case BLKGETSIZE: -+ case BLKGETSIZE64: -+ case BLKBSZSET: -+ case BLKBSZGET: -+ case BLKROSET: -+ case BLKROGET: -+ case BLKRASET: -+ case BLKRAGET: -+ case BLKPG: -+ case BLKELVGET: -+ case BLKELVSET: -+ return blk_ioctl(inode->i_rdev, cmd, arg); -+ } -+ -+ down(&mtd_table_mutex); -+ -+ tr = get_tr(MAJOR(inode->i_rdev)); -+ if (!tr) { -+ up(&mtd_table_mutex); -+ return -ENODEV; -+ } -+ -+ devnum = MINOR(inode->i_rdev) >> tr->part_bits; -+ dev = tr_get_dev(tr, devnum); -+ -+ up(&mtd_table_mutex); -+ -+ if (!dev) -+ return -ENODEV; -+ -+ switch(cmd) { -+ case BLKRRPART: -+ return mtd_blktrans_rrpart(inode->i_rdev, tr, dev); -+ -+ case BLKFLSBUF: -+ blk_ioctl(inode->i_rdev, cmd, arg); -+ if (tr->flush) -+ return tr->flush(dev); -+ /* The core code did the work, we had nothing to do. */ -+ return 0; -+ -+ case HDIO_GETGEO: -+ if (tr->getgeo) { -+ struct hd_geometry g; -+ struct gendisk *gd = &(tr->blkcore_priv->gd); -+ int ret; -+ -+ memset(&g, 0, sizeof(g)); -+ ret = tr->getgeo(dev, &g); -+ if (ret) -+ return ret; -+ -+ g.start = gd->part[MINOR(inode->i_rdev)].start_sect; -+ if (copy_to_user((void *)arg, &g, sizeof(g))) -+ return -EFAULT; -+ return 0; -+ } /* else */ -+ default: -+ return -ENOTTY; -+ } -+} -+ -+struct block_device_operations mtd_blktrans_ops = { -+ .owner = THIS_MODULE, -+ .open = blktrans_open, -+ .release = blktrans_release, -+ .ioctl = blktrans_ioctl, -+}; -+ -+int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) -+{ -+ struct mtd_blktrans_ops *tr = new->tr; -+ struct list_head *this; -+ int last_devnum = -1; -+ int i; -+ -+ if (!down_trylock(&mtd_table_mutex)) { -+ up(&mtd_table_mutex); -+ BUG(); -+ } -+ -+ spin_lock(&tr->blkcore_priv->devs_lock); -+ -+ list_for_each(this, &tr->devs) { -+ struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list); -+ if (new->devnum == -1) { -+ /* Use first free number */ -+ if (d->devnum != last_devnum+1) { -+ /* Found a free devnum. Plug it in here */ -+ new->devnum = last_devnum+1; -+ list_add_tail(&new->list, &d->list); -+ goto added; -+ } -+ } else if (d->devnum == new->devnum) { -+ /* Required number taken */ -+ spin_unlock(&tr->blkcore_priv->devs_lock); -+ return -EBUSY; -+ } else if (d->devnum > new->devnum) { -+ /* Required number was free */ -+ list_add_tail(&new->list, &d->list); -+ goto added; -+ } -+ last_devnum = d->devnum; -+ } -+ if (new->devnum == -1) -+ new->devnum = last_devnum+1; -+ -+ if ((new->devnum << tr->part_bits) > 256) { -+ spin_unlock(&tr->blkcore_priv->devs_lock); -+ return -EBUSY; -+ } -+ -+ init_MUTEX(&new->sem); -+ list_add_tail(&new->list, &tr->devs); -+ added: -+ spin_unlock(&tr->blkcore_priv->devs_lock); -+ -+ if (!tr->writesect) -+ new->readonly = 1; -+ -+ for (i = new->devnum << tr->part_bits; -+ i < (new->devnum+1) << tr->part_bits; -+ i++) { -+ set_device_ro(MKDEV(tr->major, i), new->readonly); -+ tr->blkcore_priv->blksizes[i] = new->blksize; -+ tr->blkcore_priv->sizes[i] = 0; -+ tr->blkcore_priv->part_table[i].nr_sects = 0; -+ tr->blkcore_priv->part_table[i].start_sect = 0; -+ } -+ -+ /* -+ <viro_zzz> dwmw2: BLOCK_SIZE_BITS has nothing to do with block devices -+ <viro> dwmw2: any code which sets blk_size[][] should be -+ size >> 10 /+ 2.4 and its dumb units */ -+ -+ tr->blkcore_priv->sizes[new->devnum << tr->part_bits] = -+ (new->size * new->blksize) >> 10; /* 2.4 and its dumb units */ -+ -+ /* But this is still in device's sectors? $DEITY knows */ -+ tr->blkcore_priv->part_table[new->devnum << tr->part_bits].nr_sects = new->size; -+ -+ if (tr->part_bits) { -+ grok_partitions(&tr->blkcore_priv->gd, new->devnum, -+ 1 << tr->part_bits, new->size); -+ } -+#ifdef CONFIG_DEVFS_FS -+ if (!tr->part_bits) { -+ char name[2]; -+ -+ name[0] = '0' + new->devnum; -+ name[1] = 0; -+ -+ new->blkcore_priv = -+ devfs_register(tr->blkcore_priv->devfs_dir_handle, -+ name, DEVFS_FL_DEFAULT, tr->major, -+ new->devnum, S_IFBLK|S_IRUGO|S_IWUGO, -+ &mtd_blktrans_ops, NULL); -+ } -+#endif -+ return 0; -+} -+ -+int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) -+{ -+ struct mtd_blktrans_ops *tr = old->tr; -+ int i; -+ -+ if (!down_trylock(&mtd_table_mutex)) { -+ up(&mtd_table_mutex); -+ BUG(); -+ } -+ -+#ifdef CONFIG_DEVFS_FS -+ if (!tr->part_bits) { -+ devfs_unregister(old->blkcore_priv); -+ old->blkcore_priv = NULL; -+ } else { -+ devfs_register_partitions(&tr->blkcore_priv->gd, -+ old->devnum << tr->part_bits, 1); -+ } -+#endif -+ spin_lock(&tr->blkcore_priv->devs_lock); -+ list_del(&old->list); -+ spin_unlock(&tr->blkcore_priv->devs_lock); -+ -+ for (i = (old->devnum << tr->part_bits); -+ i < ((old->devnum+1) << tr->part_bits); i++) { -+ tr->blkcore_priv->sizes[i] = 0; -+ tr->blkcore_priv->part_table[i].nr_sects = 0; -+ tr->blkcore_priv->part_table[i].start_sect = 0; -+ } -+ -+ return 0; -+} -+ -+void blktrans_notify_remove(struct mtd_info *mtd) -+{ -+ struct list_head *this, *this2, *next; -+ -+ list_for_each(this, &blktrans_majors) { -+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); -+ -+ list_for_each_safe(this2, next, &tr->devs) { -+ struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list); -+ -+ if (dev->mtd == mtd) -+ tr->remove_dev(dev); -+ } -+ } -+} -+ -+void blktrans_notify_add(struct mtd_info *mtd) -+{ -+ struct list_head *this; -+ -+ if (mtd->type == MTD_ABSENT) -+ return; -+ -+ list_for_each(this, &blktrans_majors) { -+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); -+ -+ tr->add_mtd(tr, mtd); -+ } -+ -+} -+ -+static struct mtd_notifier blktrans_notifier = { -+ .add = blktrans_notify_add, -+ .remove = blktrans_notify_remove, -+}; -+ -+int register_mtd_blktrans(struct mtd_blktrans_ops *tr) -+{ -+ int ret, i; -+ -+ /* Register the notifier if/when the first device type is -+ registered, to prevent the link/init ordering from fucking -+ us over. */ -+ if (!blktrans_notifier.list.next) -+ register_mtd_user(&blktrans_notifier); -+ -+ tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); -+ if (!tr->blkcore_priv) -+ return -ENOMEM; -+ -+ memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv)); -+ -+ down(&mtd_table_mutex); -+ -+ ret = devfs_register_blkdev(tr->major, tr->name, &mtd_blktrans_ops); -+ if (ret) { -+ printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", -+ tr->name, tr->major, ret); -+ kfree(tr->blkcore_priv); -+ up(&mtd_table_mutex); -+ return ret; -+ } -+ -+ blk_init_queue(BLK_DEFAULT_QUEUE(tr->major), &mtd_blktrans_request); -+ (BLK_DEFAULT_QUEUE(tr->major))->queuedata = tr; -+ -+ init_completion(&tr->blkcore_priv->thread_dead); -+ init_waitqueue_head(&tr->blkcore_priv->thread_wq); -+ -+ ret = kernel_thread(mtd_blktrans_thread, tr, -+ CLONE_FS|CLONE_FILES|CLONE_SIGHAND); -+ if (ret < 0) { -+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major)); -+ devfs_unregister_blkdev(tr->major, tr->name); -+ kfree(tr->blkcore_priv); -+ up(&mtd_table_mutex); -+ return ret; -+ } -+ -+ tr->blkcore_priv->devfs_dir_handle = -+ devfs_mk_dir(NULL, tr->name, NULL); -+ -+ blksize_size[tr->major] = tr->blkcore_priv->blksizes; -+ blk_size[tr->major] = tr->blkcore_priv->sizes; -+ -+ tr->blkcore_priv->gd.major = tr->major; -+ tr->blkcore_priv->gd.major_name = tr->name; -+ tr->blkcore_priv->gd.minor_shift = tr->part_bits; -+ tr->blkcore_priv->gd.max_p = (1<<tr->part_bits) - 1; -+ tr->blkcore_priv->gd.part = tr->blkcore_priv->part_table; -+ tr->blkcore_priv->gd.sizes = tr->blkcore_priv->sizes; -+ tr->blkcore_priv->gd.nr_real = 256 >> tr->part_bits; -+ -+ spin_lock_init(&tr->blkcore_priv->devs_lock); -+ -+ add_gendisk(&tr->blkcore_priv->gd); -+ -+ INIT_LIST_HEAD(&tr->devs); -+ list_add(&tr->list, &blktrans_majors); -+ -+ for (i=0; i<MAX_MTD_DEVICES; i++) { -+ if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT) -+ tr->add_mtd(tr, mtd_table[i]); -+ } -+ up(&mtd_table_mutex); -+ -+ return 0; -+} -+ -+int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) -+{ -+ struct list_head *this, *next; -+ -+ down(&mtd_table_mutex); -+ -+ /* Clean up the kernel thread */ -+ tr->blkcore_priv->exiting = 1; -+ wake_up(&tr->blkcore_priv->thread_wq); -+ wait_for_completion(&tr->blkcore_priv->thread_dead); -+ -+ /* Remove it from the list of active majors */ -+ list_del(&tr->list); -+ -+ /* Remove each of its devices */ -+ list_for_each_safe(this, next, &tr->devs) { -+ struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list); -+ tr->remove_dev(dev); -+ } -+ -+ blksize_size[tr->major] = NULL; -+ blk_size[tr->major] = NULL; -+ -+ del_gendisk(&tr->blkcore_priv->gd); -+ -+ blk_cleanup_queue(BLK_DEFAULT_QUEUE(tr->major)); -+ devfs_unregister_blkdev(tr->major, tr->name); -+ -+ devfs_unregister(tr->blkcore_priv->devfs_dir_handle); -+ -+ up(&mtd_table_mutex); -+ -+ kfree(tr->blkcore_priv); -+ -+ if (!list_empty(&tr->devs)) -+ BUG(); -+ return 0; -+} -+ -+static void __exit mtd_blktrans_exit(void) -+{ -+ /* No race here -- if someone's currently in register_mtd_blktrans -+ we're screwed anyway. */ -+ if (blktrans_notifier.list.next) -+ unregister_mtd_user(&blktrans_notifier); -+} -+ -+module_exit(mtd_blktrans_exit); -+ -+EXPORT_SYMBOL_GPL(register_mtd_blktrans); -+EXPORT_SYMBOL_GPL(deregister_mtd_blktrans); -+EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev); -+EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev); -+ -+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/mtd_blkdevs.c linux/drivers/mtd/mtd_blkdevs.c ---- linux-mips-2.4.27/drivers/mtd/mtd_blkdevs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/mtd_blkdevs.c 2004-11-19 10:25:11.642238856 +0100 -@@ -0,0 +1,479 @@ -+/* -+ * $Id$ -+ * -+ * (C) 2003 David Woodhouse <dwmw2@infradead.org> -+ * -+ * Interface to Linux 2.5 block layer for MTD 'translation layers'. -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/module.h> -+#include <linux/list.h> -+#include <linux/fs.h> -+#include <linux/mtd/blktrans.h> -+#include <linux/mtd/mtd.h> -+#include <linux/blkdev.h> -+#include <linux/blk.h> -+#include <linux/blkpg.h> -+#include <linux/spinlock.h> -+#include <linux/hdreg.h> -+#include <linux/init.h> -+#include <asm/semaphore.h> -+#include <asm/uaccess.h> -+#include <linux/devfs_fs_kernel.h> -+ -+static LIST_HEAD(blktrans_majors); -+ -+extern struct semaphore mtd_table_mutex; -+extern struct mtd_info *mtd_table[]; -+ -+struct mtd_blkcore_priv { -+ struct completion thread_dead; -+ int exiting; -+ wait_queue_head_t thread_wq; -+ struct request_queue *rq; -+ spinlock_t queue_lock; -+}; -+ -+static int do_blktrans_request(struct mtd_blktrans_ops *tr, -+ struct mtd_blktrans_dev *dev, -+ struct request *req) -+{ -+ unsigned long block, nsect; -+ char *buf; -+ -+ block = req->sector; -+ nsect = req->current_nr_sectors; -+ buf = req->buffer; -+ -+ if (!(req->flags & REQ_CMD)) -+ return 0; -+ -+ if (block + nsect > get_capacity(req->rq_disk)) -+ return 0; -+ -+ switch(rq_data_dir(req)) { -+ case READ: -+ for (; nsect > 0; nsect--, block++, buf += 512) -+ if (tr->readsect(dev, block, buf)) -+ return 0; -+ return 1; -+ -+ case WRITE: -+ if (!tr->writesect) -+ return 0; -+ -+ for (; nsect > 0; nsect--, block++, buf += 512) -+ if (tr->writesect(dev, block, buf)) -+ return 0; -+ return 1; -+ -+ default: -+ printk(KERN_NOTICE "Unknown request %ld\n", rq_data_dir(req)); -+ return 0; -+ } -+} -+ -+static int mtd_blktrans_thread(void *arg) -+{ -+ struct mtd_blktrans_ops *tr = arg; -+ struct request_queue *rq = tr->blkcore_priv->rq; -+ -+ /* we might get involved when memory gets low, so use PF_MEMALLOC */ -+ current->flags |= PF_MEMALLOC; -+ -+ daemonize("%sd", tr->name); -+ -+ /* daemonize() doesn't do this for us since some kernel threads -+ actually want to deal with signals. We can't just call -+ exit_sighand() since that'll cause an oops when we finally -+ do exit. */ -+ spin_lock_irq(¤t->sighand->siglock); -+ sigfillset(¤t->blocked); -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->sighand->siglock); -+ -+ spin_lock_irq(rq->queue_lock); -+ -+ while (!tr->blkcore_priv->exiting) { -+ struct request *req; -+ struct mtd_blktrans_dev *dev; -+ int res = 0; -+ DECLARE_WAITQUEUE(wait, current); -+ -+ req = elv_next_request(rq); -+ -+ if (!req) { -+ add_wait_queue(&tr->blkcore_priv->thread_wq, &wait); -+ set_current_state(TASK_INTERRUPTIBLE); -+ -+ spin_unlock_irq(rq->queue_lock); -+ -+ schedule(); -+ remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait); -+ -+ spin_lock_irq(rq->queue_lock); -+ -+ continue; -+ } -+ -+ dev = req->rq_disk->private_data; -+ tr = dev->tr; -+ -+ spin_unlock_irq(rq->queue_lock); -+ -+ down(&dev->sem); -+ res = do_blktrans_request(tr, dev, req); -+ up(&dev->sem); -+ -+ spin_lock_irq(rq->queue_lock); -+ -+ end_request(req, res); -+ } -+ complete_and_exit(&tr->blkcore_priv->thread_dead, 0); -+} -+ -+static void mtd_blktrans_request(struct request_queue *rq) -+{ -+ struct mtd_blktrans_ops *tr = rq->queuedata; -+ wake_up(&tr->blkcore_priv->thread_wq); -+} -+ -+ -+int blktrans_open(struct inode *i, struct file *f) -+{ -+ struct mtd_blktrans_dev *dev; -+ struct mtd_blktrans_ops *tr; -+ int ret = -ENODEV; -+ -+ dev = i->i_bdev->bd_disk->private_data; -+ tr = dev->tr; -+ -+ if (!try_module_get(dev->mtd->owner)) -+ goto out; -+ -+ if (!try_module_get(tr->owner)) -+ goto out_tr; -+ -+ /* FIXME: Locking. A hot pluggable device can go away -+ (del_mtd_device can be called for it) without its module -+ being unloaded. */ -+ dev->mtd->usecount++; -+ -+ ret = 0; -+ if (tr->open && (ret = tr->open(dev))) { -+ dev->mtd->usecount--; -+ module_put(dev->mtd->owner); -+ out_tr: -+ module_put(tr->owner); -+ } -+ out: -+ return ret; -+} -+ -+int blktrans_release(struct inode *i, struct file *f) -+{ -+ struct mtd_blktrans_dev *dev; -+ struct mtd_blktrans_ops *tr; -+ int ret = 0; -+ -+ dev = i->i_bdev->bd_disk->private_data; -+ tr = dev->tr; -+ -+ if (tr->release) -+ ret = tr->release(dev); -+ -+ if (!ret) { -+ dev->mtd->usecount--; -+ module_put(dev->mtd->owner); -+ module_put(tr->owner); -+ } -+ -+ return ret; -+} -+ -+ -+static int blktrans_ioctl(struct inode *inode, struct file *file, -+ unsigned int cmd, unsigned long arg) -+{ -+ struct mtd_blktrans_dev *dev = inode->i_bdev->bd_disk->private_data; -+ struct mtd_blktrans_ops *tr = dev->tr; -+ -+ switch (cmd) { -+ case BLKFLSBUF: -+ if (tr->flush) -+ return tr->flush(dev); -+ /* The core code did the work, we had nothing to do. */ -+ return 0; -+ -+ case HDIO_GETGEO: -+ if (tr->getgeo) { -+ struct hd_geometry g; -+ int ret; -+ -+ memset(&g, 0, sizeof(g)); -+ ret = tr->getgeo(dev, &g); -+ -+ if (ret) -+ return ret; -+ -+ g.start = get_start_sect(inode->i_bdev); -+ if (copy_to_user((void *)arg, &g, sizeof(g))) -+ return -EFAULT; -+ return 0; -+ } /* else */ -+ default: -+ return -ENOTTY; -+ } -+} -+ -+struct block_device_operations mtd_blktrans_ops = { -+ .owner = THIS_MODULE, -+ .open = blktrans_open, -+ .release = blktrans_release, -+ .ioctl = blktrans_ioctl, -+}; -+ -+int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) -+{ -+ struct mtd_blktrans_ops *tr = new->tr; -+ struct list_head *this; -+ int last_devnum = -1; -+ struct gendisk *gd; -+ -+ if (!down_trylock(&mtd_table_mutex)) { -+ up(&mtd_table_mutex); -+ BUG(); -+ } -+ -+ list_for_each(this, &tr->devs) { -+ struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list); -+ if (new->devnum == -1) { -+ /* Use first free number */ -+ if (d->devnum != last_devnum+1) { -+ /* Found a free devnum. Plug it in here */ -+ new->devnum = last_devnum+1; -+ list_add_tail(&new->list, &d->list); -+ goto added; -+ } -+ } else if (d->devnum == new->devnum) { -+ /* Required number taken */ -+ return -EBUSY; -+ } else if (d->devnum > new->devnum) { -+ /* Required number was free */ -+ list_add_tail(&new->list, &d->list); -+ goto added; -+ } -+ last_devnum = d->devnum; -+ } -+ if (new->devnum == -1) -+ new->devnum = last_devnum+1; -+ -+ if ((new->devnum << tr->part_bits) > 256) { -+ return -EBUSY; -+ } -+ -+ init_MUTEX(&new->sem); -+ list_add_tail(&new->list, &tr->devs); -+ added: -+ if (!tr->writesect) -+ new->readonly = 1; -+ -+ gd = alloc_disk(1 << tr->part_bits); -+ if (!gd) { -+ list_del(&new->list); -+ return -ENOMEM; -+ } -+ gd->major = tr->major; -+ gd->first_minor = (new->devnum) << tr->part_bits; -+ gd->fops = &mtd_blktrans_ops; -+ -+ snprintf(gd->disk_name, sizeof(gd->disk_name), -+ "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); -+ snprintf(gd->devfs_name, sizeof(gd->devfs_name), -+ "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); -+ -+ /* 2.5 has capacity in units of 512 bytes while still -+ having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */ -+ set_capacity(gd, (new->size * new->blksize) >> 9); -+ -+ gd->private_data = new; -+ new->blkcore_priv = gd; -+ gd->queue = tr->blkcore_priv->rq; -+ -+ if (new->readonly) -+ set_disk_ro(gd, 1); -+ -+ add_disk(gd); -+ -+ return 0; -+} -+ -+int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) -+{ -+ if (!down_trylock(&mtd_table_mutex)) { -+ up(&mtd_table_mutex); -+ BUG(); -+ } -+ -+ list_del(&old->list); -+ -+ del_gendisk(old->blkcore_priv); -+ put_disk(old->blkcore_priv); -+ -+ return 0; -+} -+ -+void blktrans_notify_remove(struct mtd_info *mtd) -+{ -+ struct list_head *this, *this2, *next; -+ -+ list_for_each(this, &blktrans_majors) { -+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); -+ -+ list_for_each_safe(this2, next, &tr->devs) { -+ struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list); -+ -+ if (dev->mtd == mtd) -+ tr->remove_dev(dev); -+ } -+ } -+} -+ -+void blktrans_notify_add(struct mtd_info *mtd) -+{ -+ struct list_head *this; -+ -+ if (mtd->type == MTD_ABSENT) -+ return; -+ -+ list_for_each(this, &blktrans_majors) { -+ struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); -+ -+ tr->add_mtd(tr, mtd); -+ } -+ -+} -+ -+static struct mtd_notifier blktrans_notifier = { -+ .add = blktrans_notify_add, -+ .remove = blktrans_notify_remove, -+}; -+ -+int register_mtd_blktrans(struct mtd_blktrans_ops *tr) -+{ -+ int ret, i; -+ -+ /* Register the notifier if/when the first device type is -+ registered, to prevent the link/init ordering from fucking -+ us over. */ -+ if (!blktrans_notifier.list.next) -+ register_mtd_user(&blktrans_notifier); -+ -+ tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); -+ if (!tr->blkcore_priv) -+ return -ENOMEM; -+ -+ memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv)); -+ -+ down(&mtd_table_mutex); -+ -+ ret = register_blkdev(tr->major, tr->name); -+ if (ret) { -+ printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", -+ tr->name, tr->major, ret); -+ kfree(tr->blkcore_priv); -+ up(&mtd_table_mutex); -+ return ret; -+ } -+ spin_lock_init(&tr->blkcore_priv->queue_lock); -+ init_completion(&tr->blkcore_priv->thread_dead); -+ init_waitqueue_head(&tr->blkcore_priv->thread_wq); -+ -+ tr->blkcore_priv->rq = blk_init_queue(mtd_blktrans_request, &tr->blkcore_priv->queue_lock); -+ if (!tr->blkcore_priv->rq) { -+ unregister_blkdev(tr->major, tr->name); -+ kfree(tr->blkcore_priv); -+ up(&mtd_table_mutex); -+ return -ENOMEM; -+ } -+ -+ tr->blkcore_priv->rq->queuedata = tr; -+ -+ ret = kernel_thread(mtd_blktrans_thread, tr, -+ CLONE_FS|CLONE_FILES|CLONE_SIGHAND); -+ if (ret < 0) { -+ blk_cleanup_queue(tr->blkcore_priv->rq); -+ unregister_blkdev(tr->major, tr->name); -+ kfree(tr->blkcore_priv); -+ up(&mtd_table_mutex); -+ return ret; -+ } -+ -+ devfs_mk_dir(tr->name); -+ -+ INIT_LIST_HEAD(&tr->devs); -+ list_add(&tr->list, &blktrans_majors); -+ -+ for (i=0; i<MAX_MTD_DEVICES; i++) { -+ if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT) -+ tr->add_mtd(tr, mtd_table[i]); -+ } -+ -+ up(&mtd_table_mutex); -+ -+ return 0; -+} -+ -+int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) -+{ -+ struct list_head *this, *next; -+ -+ down(&mtd_table_mutex); -+ -+ /* Clean up the kernel thread */ -+ tr->blkcore_priv->exiting = 1; -+ wake_up(&tr->blkcore_priv->thread_wq); -+ wait_for_completion(&tr->blkcore_priv->thread_dead); -+ -+ /* Remove it from the list of active majors */ -+ list_del(&tr->list); -+ -+ list_for_each_safe(this, next, &tr->devs) { -+ struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list); -+ tr->remove_dev(dev); -+ } -+ -+ devfs_remove(tr->name); -+ blk_cleanup_queue(tr->blkcore_priv->rq); -+ unregister_blkdev(tr->major, tr->name); -+ -+ up(&mtd_table_mutex); -+ -+ kfree(tr->blkcore_priv); -+ -+ if (!list_empty(&tr->devs)) -+ BUG(); -+ return 0; -+} -+ -+static void __exit mtd_blktrans_exit(void) -+{ -+ /* No race here -- if someone's currently in register_mtd_blktrans -+ we're screwed anyway. */ -+ if (blktrans_notifier.list.next) -+ unregister_mtd_user(&blktrans_notifier); -+} -+ -+module_exit(mtd_blktrans_exit); -+ -+EXPORT_SYMBOL_GPL(register_mtd_blktrans); -+EXPORT_SYMBOL_GPL(deregister_mtd_blktrans); -+EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev); -+EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev); -+ -+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); -+MODULE_LICENSE("GPL"); -+MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdblock.c linux/drivers/mtd/mtdblock.c ---- linux-mips-2.4.27/drivers/mtd/mtdblock.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/mtdblock.c 2004-11-19 10:25:11.643238704 +0100 -@@ -1,52 +1,25 @@ - /* - * Direct MTD block device access - * -- * $Id$ -+ * $Id$ - * -- * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache -+ * (C) 2000-2003 Nicolas Pitre <nico@cam.org> -+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> - */ - - #include <linux/config.h> - #include <linux/types.h> - #include <linux/module.h> - #include <linux/kernel.h> -+#include <linux/fs.h> -+#include <linux/init.h> - #include <linux/slab.h> -+#include <linux/vmalloc.h> - #include <linux/mtd/mtd.h> --#include <linux/mtd/compatmac.h> -- --#define MAJOR_NR MTD_BLOCK_MAJOR --#define DEVICE_NAME "mtdblock" --#define DEVICE_REQUEST mtdblock_request --#define DEVICE_NR(device) (device) --#define DEVICE_ON(device) --#define DEVICE_OFF(device) --#define DEVICE_NO_RANDOM --#include <linux/blk.h> --/* for old kernels... */ --#ifndef QUEUE_EMPTY --#define QUEUE_EMPTY (!CURRENT) --#endif --#if LINUX_VERSION_CODE < 0x20300 --#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync) --#else --#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged) --#endif -- --#ifdef CONFIG_DEVFS_FS --#include <linux/devfs_fs_kernel.h> --static void mtd_notify_add(struct mtd_info* mtd); --static void mtd_notify_remove(struct mtd_info* mtd); --static struct mtd_notifier notifier = { -- mtd_notify_add, -- mtd_notify_remove, -- NULL --}; --static devfs_handle_t devfs_dir_handle = NULL; --static devfs_handle_t devfs_rw_handle[MAX_MTD_DEVICES]; --#endif -+#include <linux/mtd/blktrans.h> - - static struct mtdblk_dev { -- struct mtd_info *mtd; /* Locked */ -+ struct mtd_info *mtd; - int count; - struct semaphore cache_sem; - unsigned char *cache_data; -@@ -55,19 +28,6 @@ - enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; - } *mtdblks[MAX_MTD_DEVICES]; - --static spinlock_t mtdblks_lock; -- --static int mtd_sizes[MAX_MTD_DEVICES]; --static int mtd_blksizes[MAX_MTD_DEVICES]; -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) --#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT --#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT --#else --#define BLK_INC_USE_COUNT do {} while(0) --#define BLK_DEC_USE_COUNT do {} while(0) --#endif -- - /* - * Cache stuff... - * -@@ -151,7 +111,7 @@ - return ret; - - /* -- * Here we could argably set the cache state to STATE_CLEAN. -+ * Here we could argubly set the cache state to STATE_CLEAN. - * However this could lead to inconsistency since we will not - * be notified if this content is altered on the flash by other - * means. Let's declare it empty and leave buffering tasks to -@@ -277,57 +237,47 @@ - return 0; - } - -+static int mtdblock_readsect(struct mtd_blktrans_dev *dev, -+ unsigned long block, char *buf) -+{ -+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; -+ return do_cached_read(mtdblk, block<<9, 512, buf); -+} - -+static int mtdblock_writesect(struct mtd_blktrans_dev *dev, -+ unsigned long block, char *buf) -+{ -+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; -+ if (unlikely(!mtdblk->cache_data)) { -+ mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize); -+ if (!mtdblk->cache_data) -+ return -EINTR; -+ /* -EINTR is not really correct, but it is the best match -+ * documented in man 2 write for all cases. We could also -+ * return -EAGAIN sometimes, but why bother? -+ */ -+ } -+ return do_cached_write(mtdblk, block<<9, 512, buf); -+} - --static int mtdblock_open(struct inode *inode, struct file *file) -+static int mtdblock_open(struct mtd_blktrans_dev *mbd) - { - struct mtdblk_dev *mtdblk; -- struct mtd_info *mtd; -- int dev; -+ struct mtd_info *mtd = mbd->mtd; -+ int dev = mbd->devnum; - - DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); - -- if (!inode) -- return -EINVAL; -- -- dev = MINOR(inode->i_rdev); -- if (dev >= MAX_MTD_DEVICES) -- return -EINVAL; -- -- BLK_INC_USE_COUNT; -- -- mtd = get_mtd_device(NULL, dev); -- if (!mtd) -- return -ENODEV; -- if (MTD_ABSENT == mtd->type) { -- put_mtd_device(mtd); -- BLK_DEC_USE_COUNT; -- return -ENODEV; -- } -- -- spin_lock(&mtdblks_lock); -- -- /* If it's already open, no need to piss about. */ - if (mtdblks[dev]) { - mtdblks[dev]->count++; -- spin_unlock(&mtdblks_lock); -- put_mtd_device(mtd); - return 0; - } - -- /* OK, it's not open. Try to find it */ -- -- /* First we have to drop the lock, because we have to -- to things which might sleep. -- */ -- spin_unlock(&mtdblks_lock); -- -+ /* OK, it's not open. Create cache info for it */ - mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); -- if (!mtdblk) { -- put_mtd_device(mtd); -- BLK_DEC_USE_COUNT; -+ if (!mtdblk) - return -ENOMEM; -- } -+ - memset(mtdblk, 0, sizeof(*mtdblk)); - mtdblk->count = 1; - mtdblk->mtd = mtd; -@@ -337,336 +287,102 @@ - if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM && - mtdblk->mtd->erasesize) { - mtdblk->cache_size = mtdblk->mtd->erasesize; -- mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize); -- if (!mtdblk->cache_data) { -- put_mtd_device(mtdblk->mtd); -- kfree(mtdblk); -- BLK_DEC_USE_COUNT; -- return -ENOMEM; -- } -- } -- -- /* OK, we've created a new one. Add it to the list. */ -- -- spin_lock(&mtdblks_lock); -- -- if (mtdblks[dev]) { -- /* Another CPU made one at the same time as us. */ -- mtdblks[dev]->count++; -- spin_unlock(&mtdblks_lock); -- put_mtd_device(mtdblk->mtd); -- vfree(mtdblk->cache_data); -- kfree(mtdblk); -- return 0; -+ mtdblk->cache_data = NULL; - } - - mtdblks[dev] = mtdblk; -- mtd_sizes[dev] = mtdblk->mtd->size/1024; -- if (mtdblk->mtd->erasesize) -- mtd_blksizes[dev] = mtdblk->mtd->erasesize; -- if (mtd_blksizes[dev] > PAGE_SIZE) -- mtd_blksizes[dev] = PAGE_SIZE; -- set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE)); -- -- spin_unlock(&mtdblks_lock); - - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); - - return 0; - } - --static release_t mtdblock_release(struct inode *inode, struct file *file) -+static int mtdblock_release(struct mtd_blktrans_dev *mbd) - { -- int dev; -- struct mtdblk_dev *mtdblk; -- DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); -+ int dev = mbd->devnum; -+ struct mtdblk_dev *mtdblk = mtdblks[dev]; - -- if (inode == NULL) -- release_return(-ENODEV); -- -- dev = MINOR(inode->i_rdev); -- mtdblk = mtdblks[dev]; -+ DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); - - down(&mtdblk->cache_sem); - write_cached_data(mtdblk); - up(&mtdblk->cache_sem); - -- spin_lock(&mtdblks_lock); - if (!--mtdblk->count) { - /* It was the last usage. Free the device */ - mtdblks[dev] = NULL; -- spin_unlock(&mtdblks_lock); - if (mtdblk->mtd->sync) - mtdblk->mtd->sync(mtdblk->mtd); -- put_mtd_device(mtdblk->mtd); - vfree(mtdblk->cache_data); - kfree(mtdblk); -- } else { -- spin_unlock(&mtdblks_lock); - } -- - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); - -- BLK_DEC_USE_COUNT; -- release_return(0); --} -- -- --/* -- * This is a special request_fn because it is executed in a process context -- * to be able to sleep independently of the caller. The io_request_lock -- * is held upon entry and exit. -- * The head of our request queue is considered active so there is no need -- * to dequeue requests before we are done. -- */ --static void handle_mtdblock_request(void) --{ -- struct request *req; -- struct mtdblk_dev *mtdblk; -- unsigned int res; -- -- for (;;) { -- INIT_REQUEST; -- req = CURRENT; -- spin_unlock_irq(&io_request_lock); -- mtdblk = mtdblks[MINOR(req->rq_dev)]; -- res = 0; -- -- if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES) -- panic("%s: minor out of bounds", __FUNCTION__); -- -- if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9)) -- goto end_req; -- -- // Handle the request -- switch (req->cmd) -- { -- int err; -- -- case READ: -- down(&mtdblk->cache_sem); -- err = do_cached_read (mtdblk, req->sector << 9, -- req->current_nr_sectors << 9, -- req->buffer); -- up(&mtdblk->cache_sem); -- if (!err) -- res = 1; -- break; -- -- case WRITE: -- // Read only device -- if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) ) -- break; -- -- // Do the write -- down(&mtdblk->cache_sem); -- err = do_cached_write (mtdblk, req->sector << 9, -- req->current_nr_sectors << 9, -- req->buffer); -- up(&mtdblk->cache_sem); -- if (!err) -- res = 1; -- break; -- } -- --end_req: -- spin_lock_irq(&io_request_lock); -- end_request(res); -- } --} -- --static volatile int leaving = 0; --static DECLARE_MUTEX_LOCKED(thread_sem); --static DECLARE_WAIT_QUEUE_HEAD(thr_wq); -- --int mtdblock_thread(void *dummy) --{ -- struct task_struct *tsk = current; -- DECLARE_WAITQUEUE(wait, tsk); -- -- /* we might get involved when memory gets low, so use PF_MEMALLOC */ -- tsk->flags |= PF_MEMALLOC; -- strcpy(tsk->comm, "mtdblockd"); -- spin_lock_irq(&tsk->sigmask_lock); -- sigfillset(&tsk->blocked); -- recalc_sigpending(tsk); -- spin_unlock_irq(&tsk->sigmask_lock); -- daemonize(); -- -- while (!leaving) { -- add_wait_queue(&thr_wq, &wait); -- set_current_state(TASK_INTERRUPTIBLE); -- spin_lock_irq(&io_request_lock); -- if (QUEUE_EMPTY || QUEUE_PLUGGED) { -- spin_unlock_irq(&io_request_lock); -- schedule(); -- remove_wait_queue(&thr_wq, &wait); -- } else { -- remove_wait_queue(&thr_wq, &wait); -- set_current_state(TASK_RUNNING); -- handle_mtdblock_request(); -- spin_unlock_irq(&io_request_lock); -- } -- } -- -- up(&thread_sem); - return 0; - } - --#if LINUX_VERSION_CODE < 0x20300 --#define RQFUNC_ARG void --#else --#define RQFUNC_ARG request_queue_t *q --#endif -- --static void mtdblock_request(RQFUNC_ARG) -+static int mtdblock_flush(struct mtd_blktrans_dev *dev) - { -- /* Don't do anything, except wake the thread if necessary */ -- wake_up(&thr_wq); --} -+ struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; - -- --static int mtdblock_ioctl(struct inode * inode, struct file * file, -- unsigned int cmd, unsigned long arg) --{ -- struct mtdblk_dev *mtdblk; -- -- mtdblk = mtdblks[MINOR(inode->i_rdev)]; -- --#ifdef PARANOIA -- if (!mtdblk) -- BUG(); --#endif -- -- switch (cmd) { -- case BLKGETSIZE: /* Return device size */ -- return put_user((mtdblk->mtd->size >> 9), (unsigned long *) arg); -- --#ifdef BLKGETSIZE64 -- case BLKGETSIZE64: -- return put_user((u64)mtdblk->mtd->size, (u64 *)arg); --#endif -- -- case BLKFLSBUF: --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) -- if(!capable(CAP_SYS_ADMIN)) -- return -EACCES; --#endif -- fsync_dev(inode->i_rdev); -- invalidate_buffers(inode->i_rdev); - down(&mtdblk->cache_sem); - write_cached_data(mtdblk); - up(&mtdblk->cache_sem); -+ - if (mtdblk->mtd->sync) - mtdblk->mtd->sync(mtdblk->mtd); - return 0; -- -- default: -- return -EINVAL; -- } - } - --#if LINUX_VERSION_CODE < 0x20326 --static struct file_operations mtd_fops = -+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) - { -- open: mtdblock_open, -- ioctl: mtdblock_ioctl, -- release: mtdblock_release, -- read: block_read, -- write: block_write --}; --#else --static struct block_device_operations mtd_fops = --{ --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) -- owner: THIS_MODULE, --#endif -- open: mtdblock_open, -- release: mtdblock_release, -- ioctl: mtdblock_ioctl --}; --#endif -+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); - --#ifdef CONFIG_DEVFS_FS --/* Notification that a new device has been added. Create the devfs entry for -- * it. */ -- --static void mtd_notify_add(struct mtd_info* mtd) --{ -- char name[8]; -- -- if (!mtd || mtd->type == MTD_ABSENT) -+ if (!dev) - return; - -- sprintf(name, "%d", mtd->index); -- devfs_rw_handle[mtd->index] = devfs_register(devfs_dir_handle, name, -- DEVFS_FL_DEFAULT, MTD_BLOCK_MAJOR, mtd->index, -- S_IFBLK | S_IRUGO | S_IWUGO, -- &mtd_fops, NULL); --} -- --static void mtd_notify_remove(struct mtd_info* mtd) --{ -- if (!mtd || mtd->type == MTD_ABSENT) -- return; -+ memset(dev, 0, sizeof(*dev)); - -- devfs_unregister(devfs_rw_handle[mtd->index]); --} --#endif -+ dev->mtd = mtd; -+ dev->devnum = mtd->index; -+ dev->blksize = 512; -+ dev->size = mtd->size >> 9; -+ dev->tr = tr; -+ -+ if (!(mtd->flags & MTD_WRITEABLE)) -+ dev->readonly = 1; -+ -+ add_mtd_blktrans_dev(dev); -+} -+ -+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) -+{ -+ del_mtd_blktrans_dev(dev); -+ kfree(dev); -+} -+ -+struct mtd_blktrans_ops mtdblock_tr = { -+ .name = "mtdblock", -+ .major = 31, -+ .part_bits = 0, -+ .open = mtdblock_open, -+ .flush = mtdblock_flush, -+ .release = mtdblock_release, -+ .readsect = mtdblock_readsect, -+ .writesect = mtdblock_writesect, -+ .add_mtd = mtdblock_add_mtd, -+ .remove_dev = mtdblock_remove_dev, -+ .owner = THIS_MODULE, -+}; - - int __init init_mtdblock(void) - { -- int i; -- -- spin_lock_init(&mtdblks_lock); --#ifdef CONFIG_DEVFS_FS -- if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops)) -- { -- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", -- MTD_BLOCK_MAJOR); -- return -EAGAIN; -- } -- -- devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL); -- register_mtd_user(¬ifier); --#else -- if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) { -- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", -- MTD_BLOCK_MAJOR); -- return -EAGAIN; -- } --#endif -- -- /* We fill it in at open() time. */ -- for (i=0; i< MAX_MTD_DEVICES; i++) { -- mtd_sizes[i] = 0; -- mtd_blksizes[i] = BLOCK_SIZE; -- } -- init_waitqueue_head(&thr_wq); -- /* Allow the block size to default to BLOCK_SIZE. */ -- blksize_size[MAJOR_NR] = mtd_blksizes; -- blk_size[MAJOR_NR] = mtd_sizes; -- -- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request); -- kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND); -- return 0; -+ return register_mtd_blktrans(&mtdblock_tr); - } - - static void __exit cleanup_mtdblock(void) - { -- leaving = 1; -- wake_up(&thr_wq); -- down(&thread_sem); --#ifdef CONFIG_DEVFS_FS -- unregister_mtd_user(¬ifier); -- devfs_unregister(devfs_dir_handle); -- devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME); --#else -- unregister_blkdev(MAJOR_NR,DEVICE_NAME); --#endif -- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); -- blksize_size[MAJOR_NR] = NULL; -- blk_size[MAJOR_NR] = NULL; -+ deregister_mtd_blktrans(&mtdblock_tr); - } - - module_init(init_mtdblock); -diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdblock_ro.c linux/drivers/mtd/mtdblock_ro.c ---- linux-mips-2.4.27/drivers/mtd/mtdblock_ro.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/mtdblock_ro.c 2004-11-19 10:25:11.645238400 +0100 -@@ -1,301 +1,87 @@ - /* -- * $Id$ -+ * $Id$ - * -- * Read-only version of the mtdblock device, without the -- * read/erase/modify/writeback stuff -+ * (C) 2003 David Woodhouse <dwmw2@infradead.org> -+ * -+ * Simple read-only (writable only for RAM) mtdblock driver - */ - --#ifdef MTDBLOCK_DEBUG --#define DEBUGLVL debug --#endif -- -- --#include <linux/module.h> --#include <linux/types.h> -- -+#include <linux/init.h> -+#include <linux/slab.h> - #include <linux/mtd/mtd.h> --#include <linux/mtd/compatmac.h> -- --#define MAJOR_NR MTD_BLOCK_MAJOR --#define DEVICE_NAME "mtdblock" --#define DEVICE_REQUEST mtdblock_request --#define DEVICE_NR(device) (device) --#define DEVICE_ON(device) --#define DEVICE_OFF(device) --#define DEVICE_NO_RANDOM --#include <linux/blk.h> -- --#if LINUX_VERSION_CODE < 0x20300 --#define RQFUNC_ARG void --#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0) --#else --#define RQFUNC_ARG request_queue_t *q --#endif -- --#ifdef MTDBLOCK_DEBUG --static int debug = MTDBLOCK_DEBUG; --MODULE_PARM(debug, "i"); --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) --#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT --#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT --#else --#define BLK_INC_USE_COUNT do {} while(0) --#define BLK_DEC_USE_COUNT do {} while(0) --#endif -- --static int mtd_sizes[MAX_MTD_DEVICES]; -+#include <linux/mtd/blktrans.h> - -- --static int mtdblock_open(struct inode *inode, struct file *file) -+static int mtdblock_readsect(struct mtd_blktrans_dev *dev, -+ unsigned long block, char *buf) - { -- struct mtd_info *mtd = NULL; -- -- int dev; -- -- DEBUG(1,"mtdblock_open\n"); -- -- if (inode == 0) -- return -EINVAL; -- -- dev = MINOR(inode->i_rdev); -- -- mtd = get_mtd_device(NULL, dev); -- if (!mtd) -- return -EINVAL; -- if (MTD_ABSENT == mtd->type) { -- put_mtd_device(mtd); -- return -EINVAL; -- } -- -- BLK_INC_USE_COUNT; -- -- mtd_sizes[dev] = mtd->size>>9; -- -- DEBUG(1, "ok\n"); -+ size_t retlen; - -+ if (dev->mtd->read(dev->mtd, (block * 512), 512, &retlen, buf)) -+ return 1; - return 0; - } - --static release_t mtdblock_release(struct inode *inode, struct file *file) -+static int mtdblock_writesect(struct mtd_blktrans_dev *dev, -+ unsigned long block, char *buf) - { -- int dev; -- struct mtd_info *mtd; -- -- DEBUG(1, "mtdblock_release\n"); -- -- if (inode == NULL) -- release_return(-ENODEV); -- -- dev = MINOR(inode->i_rdev); -- mtd = __get_mtd_device(NULL, dev); -- -- if (!mtd) { -- printk(KERN_WARNING "MTD device is absent on mtd_release!\n"); -- BLK_DEC_USE_COUNT; -- release_return(-ENODEV); -- } -- -- if (mtd->sync) -- mtd->sync(mtd); -- -- put_mtd_device(mtd); -- -- DEBUG(1, "ok\n"); -+ size_t retlen; - -- BLK_DEC_USE_COUNT; -- release_return(0); -+ if (dev->mtd->write(dev->mtd, (block * 512), 512, &retlen, buf)) -+ return 1; -+ return 0; - } - -- --static void mtdblock_request(RQFUNC_ARG) -+static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) - { -- struct request *current_request; -- unsigned int res = 0; -- struct mtd_info *mtd; -- -- while (1) -- { -- /* Grab the Request and unlink it from the request list, INIT_REQUEST -- will execute a return if we are done. */ -- INIT_REQUEST; -- current_request = CURRENT; -- -- if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES) -- { -- printk("mtd: Unsupported device!\n"); -- end_request(0); -- continue; -- } -- -- // Grab our MTD structure -- -- mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev)); -- if (!mtd) { -- printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV); -- end_request(0); -- } -- -- if (current_request->sector << 9 > mtd->size || -- (current_request->sector + current_request->current_nr_sectors) << 9 > mtd->size) -- { -- printk("mtd: Attempt to read past end of device!\n"); -- printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size, -- current_request->sector, current_request->current_nr_sectors); -- end_request(0); -- continue; -- } -- -- /* Remove the request we are handling from the request list so nobody messes -- with it */ --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) -- /* Now drop the lock that the ll_rw_blk functions grabbed for us -- and process the request. This is necessary due to the extreme time -- we spend processing it. */ -- spin_unlock_irq(&io_request_lock); --#endif -- -- // Handle the request -- switch (current_request->cmd) -- { -- size_t retlen; -+ struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); - -- case READ: -- if (MTD_READ(mtd,current_request->sector<<9, -- current_request->current_nr_sectors << 9, -- &retlen, current_request->buffer) == 0) -- res = 1; -- else -- res = 0; -- break; -+ if (!dev) -+ return; - -- case WRITE: -+ memset(dev, 0, sizeof(*dev)); - -- /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector, -- current_request->current_nr_sectors); -- */ -+ dev->mtd = mtd; -+ dev->devnum = mtd->index; -+ dev->blksize = 512; -+ dev->size = mtd->size >> 9; -+ dev->tr = tr; -+ if ((mtd->flags & (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) != -+ (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) -+ dev->readonly = 1; - -- // Read only device -- if ((mtd->flags & MTD_CAP_RAM) == 0) -- { -- res = 0; -- break; -- } -- -- // Do the write -- if (MTD_WRITE(mtd,current_request->sector<<9, -- current_request->current_nr_sectors << 9, -- &retlen, current_request->buffer) == 0) -- res = 1; -- else -- res = 0; -- break; -- -- // Shouldn't happen -- default: -- printk("mtd: unknown request\n"); -- break; -- } -- -- // Grab the lock and re-thread the item onto the linked list --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) -- spin_lock_irq(&io_request_lock); --#endif -- end_request(res); -- } -+ add_mtd_blktrans_dev(dev); - } - -- -- --static int mtdblock_ioctl(struct inode * inode, struct file * file, -- unsigned int cmd, unsigned long arg) -+static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) - { -- struct mtd_info *mtd; -- -- mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev)); -- -- if (!mtd) return -EINVAL; -- -- switch (cmd) { -- case BLKGETSIZE: /* Return device size */ -- return put_user((mtd->size >> 9), (unsigned long *) arg); -- --#ifdef BLKGETSIZE64 -- case BLKGETSIZE64: -- return put_user((u64)mtd->size, (u64 *)arg); --#endif -- -- case BLKFLSBUF: --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) -- if(!capable(CAP_SYS_ADMIN)) return -EACCES; --#endif -- fsync_dev(inode->i_rdev); -- invalidate_buffers(inode->i_rdev); -- if (mtd->sync) -- mtd->sync(mtd); -- return 0; -- -- default: -- return -ENOTTY; -- } -+ del_mtd_blktrans_dev(dev); -+ kfree(dev); - } - --#if LINUX_VERSION_CODE < 0x20326 --static struct file_operations mtd_fops = --{ -- open: mtdblock_open, -- ioctl: mtdblock_ioctl, -- release: mtdblock_release, -- read: block_read, -- write: block_write --}; --#else --static struct block_device_operations mtd_fops = --{ --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) -- owner: THIS_MODULE, --#endif -- open: mtdblock_open, -- release: mtdblock_release, -- ioctl: mtdblock_ioctl -+struct mtd_blktrans_ops mtdblock_tr = { -+ .name = "mtdblock", -+ .major = 31, -+ .part_bits = 0, -+ .readsect = mtdblock_readsect, -+ .writesect = mtdblock_writesect, -+ .add_mtd = mtdblock_add_mtd, -+ .remove_dev = mtdblock_remove_dev, -+ .owner = THIS_MODULE, - }; --#endif - --int __init init_mtdblock(void) -+static int __init mtdblock_init(void) - { -- int i; -- -- if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) { -- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", -- MTD_BLOCK_MAJOR); -- return -EAGAIN; -- } -- -- /* We fill it in at open() time. */ -- for (i=0; i< MAX_MTD_DEVICES; i++) { -- mtd_sizes[i] = 0; -- } -- -- /* Allow the block size to default to BLOCK_SIZE. */ -- blksize_size[MAJOR_NR] = NULL; -- blk_size[MAJOR_NR] = mtd_sizes; -- -- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request); -- return 0; -+ return register_mtd_blktrans(&mtdblock_tr); - } - --static void __exit cleanup_mtdblock(void) -+static void __exit mtdblock_exit(void) - { -- unregister_blkdev(MAJOR_NR,DEVICE_NAME); -- blk_size[MAJOR_NR] = NULL; -- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); -+ deregister_mtd_blktrans(&mtdblock_tr); - } - --module_init(init_mtdblock); --module_exit(cleanup_mtdblock); -- -+module_init(mtdblock_init); -+module_exit(mtdblock_exit); - - MODULE_LICENSE("GPL"); --MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al."); -+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); - MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdchar.c linux/drivers/mtd/mtdchar.c ---- linux-mips-2.4.27/drivers/mtd/mtdchar.c 2004-08-14 20:38:51.000000000 +0200 -+++ linux/drivers/mtd/mtdchar.c 2004-11-19 10:25:11.647238096 +0100 -@@ -1,8 +1,7 @@ - /* -- * $Id$ -+ * $Id$ - * - * Character-device access to raw MTD devices. -- * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c - * - */ - -@@ -10,7 +9,11 @@ - #include <linux/kernel.h> - #include <linux/module.h> - #include <linux/mtd/mtd.h> -+#include <linux/mtd/compatmac.h> - #include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/fs.h> -+#include <asm/uaccess.h> - - #ifdef CONFIG_DEVFS_FS - #include <linux/devfs_fs_kernel.h> -@@ -18,8 +21,8 @@ - static void mtd_notify_remove(struct mtd_info* mtd); - - static struct mtd_notifier notifier = { -- add: mtd_notify_add, -- remove: mtd_notify_remove, -+ .add = mtd_notify_add, -+ .remove = mtd_notify_remove, - }; - - static devfs_handle_t devfs_dir_handle; -@@ -60,7 +63,7 @@ - - static int mtd_open(struct inode *inode, struct file *file) - { -- int minor = minor(inode->i_rdev); -+ int minor = iminor(inode); - int devnum = minor >> 1; - struct mtd_info *mtd; - -@@ -125,15 +128,11 @@ - int ret=0; - int len; - char *kbuf; -- loff_t pos = *ppos; - - DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); - -- if (pos < 0 || pos > mtd->size) -- return 0; -- -- if (count > mtd->size - pos) -- count = mtd->size - pos; -+ if (*ppos + count > mtd->size) -+ count = mtd->size - *ppos; - - if (!count) - return 0; -@@ -150,9 +149,9 @@ - if (!kbuf) - return -ENOMEM; - -- ret = MTD_READ(mtd, pos, len, &retlen, kbuf); -+ ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); - if (!ret) { -- pos += retlen; -+ *ppos += retlen; - if (copy_to_user(buf, kbuf, retlen)) { - kfree(kbuf); - return -EFAULT; -@@ -171,8 +170,6 @@ - kfree(kbuf); - } - -- *ppos = pos; -- - return total_retlen; - } /* mtd_read */ - -@@ -182,17 +179,16 @@ - char *kbuf; - size_t retlen; - size_t total_retlen=0; -- loff_t pos = *ppos; - int ret=0; - int len; - - DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); - -- if (pos < 0 || pos >= mtd->size) -+ if (*ppos == mtd->size) - return -ENOSPC; - -- if (count > mtd->size - pos) -- count = mtd->size - pos; -+ if (*ppos + count > mtd->size) -+ count = mtd->size - *ppos; - - if (!count) - return 0; -@@ -214,9 +210,9 @@ - return -EFAULT; - } - -- ret = (*(mtd->write))(mtd, pos, len, &retlen, kbuf); -+ ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); - if (!ret) { -- pos += retlen; -+ *ppos += retlen; - total_retlen += retlen; - count -= retlen; - buf += retlen; -@@ -228,7 +224,6 @@ - - kfree(kbuf); - } -- *ppos = pos; - - return total_retlen; - } /* mtd_write */ -@@ -450,81 +445,13 @@ - break; - } - -- case MEMWRITEDATA: -- { -- struct mtd_oob_buf buf; -- void *databuf; -- ssize_t retlen; -- -- if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf))) -- return -EFAULT; -- -- if (buf.length > 0x4096) -- return -EINVAL; -- -- if (!mtd->write_ecc) -- ret = -EOPNOTSUPP; -- else -- ret = verify_area(VERIFY_READ, (char *)buf.ptr, buf.length); -- -- if (ret) -- return ret; -- -- databuf = kmalloc(buf.length, GFP_KERNEL); -- if (!databuf) -- return -ENOMEM; -- -- if (copy_from_user(databuf, buf.ptr, buf.length)) { -- kfree(databuf); -- return -EFAULT; -- } -- -- ret = (mtd->write_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0); -- -- if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t))) -- ret = -EFAULT; -- -- kfree(databuf); -- break; -- -- } -- -- case MEMREADDATA: -+ case MEMSETOOBSEL: - { -- struct mtd_oob_buf buf; -- void *databuf; -- ssize_t retlen = 0; -- -- if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf))) -+ if (copy_from_user(&mtd->oobinfo ,(void *)arg, sizeof(struct nand_oobinfo))) - return -EFAULT; -- -- if (buf.length > 0x4096) -- return -EINVAL; -- -- if (!mtd->read_ecc) -- ret = -EOPNOTSUPP; -- else -- ret = verify_area(VERIFY_WRITE, (char *)buf.ptr, buf.length); -- -- if (ret) -- return ret; -- -- databuf = kmalloc(buf.length, GFP_KERNEL); -- if (!databuf) -- return -ENOMEM; -- -- ret = (mtd->read_ecc)(mtd, buf.start, buf.length, &retlen, databuf, NULL, 0); -- -- if (copy_to_user((void *)arg + sizeof(u_int32_t), &retlen, sizeof(u_int32_t))) -- ret = -EFAULT; -- else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) -- ret = -EFAULT; -- -- kfree(databuf); - break; - } - -- - default: - DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO); - ret = -ENOTTY; -@@ -534,13 +461,13 @@ - } /* memory_ioctl */ - - static struct file_operations mtd_fops = { -- owner: THIS_MODULE, -- llseek: mtd_lseek, /* lseek */ -- read: mtd_read, /* read */ -- write: mtd_write, /* write */ -- ioctl: mtd_ioctl, /* ioctl */ -- open: mtd_open, /* open */ -- release: mtd_close, /* release */ -+ .owner = THIS_MODULE, -+ .llseek = mtd_lseek, -+ .read = mtd_read, -+ .write = mtd_write, -+ .ioctl = mtd_ioctl, -+ .open = mtd_open, -+ .release = mtd_close, - }; - - -@@ -580,26 +507,18 @@ - - static int __init init_mtdchar(void) - { --#ifdef CONFIG_DEVFS_FS -- if (devfs_register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) -+ if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) - { - printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", - MTD_CHAR_MAJOR); - return -EAGAIN; - } - -+#ifdef CONFIG_DEVFS_FS - devfs_dir_handle = devfs_mk_dir(NULL, "mtd", NULL); - - register_mtd_user(¬ifier); --#else -- if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) -- { -- printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", -- MTD_CHAR_MAJOR); -- return -EAGAIN; -- } - #endif -- - return 0; - } - -@@ -608,10 +527,8 @@ - #ifdef CONFIG_DEVFS_FS - unregister_mtd_user(¬ifier); - devfs_unregister(devfs_dir_handle); -- devfs_unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); --#else -- unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); - #endif -+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); - } - - module_init(init_mtdchar); -diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdconcat.c linux/drivers/mtd/mtdconcat.c ---- linux-mips-2.4.27/drivers/mtd/mtdconcat.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/mtdconcat.c 2004-11-19 10:25:11.649237792 +0100 -@@ -3,9 +3,11 @@ - * - * (C) 2002 Robert Kaiser <rkaiser@sysgo.de> - * -+ * NAND support by Christian Gan <cgan@iders.ca> -+ * - * This code is GPL - * -- * $Id$ -+ * $Id$ - */ - - #include <linux/module.h> -@@ -35,21 +37,20 @@ - #define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \ - ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *))) - -- - /* - * Given a pointer to the MTD object in the mtd_concat structure, - * we can retrieve the pointer to that structure with this macro. - */ - #define CONCAT(x) ((struct mtd_concat *)(x)) - -- - /* - * MTD methods which look up the relevant subdevice, translate the - * effective address and pass through to the subdevice. - */ - --static int concat_read (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf) -+static int -+concat_read(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t * retlen, u_char * buf) - { - struct mtd_concat *concat = CONCAT(mtd); - int err = -EINVAL; -@@ -57,43 +58,43 @@ - - *retlen = 0; - -- for(i = 0; i < concat->num_subdev; i++) -- { -+ for (i = 0; i < concat->num_subdev; i++) { - struct mtd_info *subdev = concat->subdev[i]; - size_t size, retsize; - -- if (from >= subdev->size) -- { -+ if (from >= subdev->size) { -+ /* Not destined for this subdev */ - size = 0; - from -= subdev->size; -+ continue; - } -- else -- { - if (from + len > subdev->size) -+ /* First part goes into this subdev */ - size = subdev->size - from; - else -+ /* Entire transaction goes into this subdev */ - size = len; - - err = subdev->read(subdev, from, size, &retsize, buf); - -- if(err) -+ if (err) - break; - - *retlen += retsize; - len -= size; -- if(len == 0) -+ if (len == 0) - break; - - err = -EINVAL; - buf += size; - from = 0; - } -- } - return err; - } - --static int concat_write (struct mtd_info *mtd, loff_t to, size_t len, -- size_t *retlen, const u_char *buf) -+static int -+concat_write(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t * retlen, const u_char * buf) - { - struct mtd_concat *concat = CONCAT(mtd); - int err = -EINVAL; -@@ -104,18 +105,15 @@ - - *retlen = 0; - -- for(i = 0; i < concat->num_subdev; i++) -- { -+ for (i = 0; i < concat->num_subdev; i++) { - struct mtd_info *subdev = concat->subdev[i]; - size_t size, retsize; - -- if (to >= subdev->size) -- { -+ if (to >= subdev->size) { - size = 0; - to -= subdev->size; -+ continue; - } -- else -- { - if (to + len > subdev->size) - size = subdev->size - to; - else -@@ -126,25 +124,232 @@ - else - err = subdev->write(subdev, to, size, &retsize, buf); - -- if(err) -+ if (err) - break; - - *retlen += retsize; - len -= size; -- if(len == 0) -+ if (len == 0) - break; - - err = -EINVAL; - buf += size; - to = 0; - } -+ return err; -+} -+ -+static int -+concat_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t * retlen, u_char * buf, u_char * eccbuf, -+ struct nand_oobinfo *oobsel) -+{ -+ struct mtd_concat *concat = CONCAT(mtd); -+ int err = -EINVAL; -+ int i; -+ -+ *retlen = 0; -+ -+ for (i = 0; i < concat->num_subdev; i++) { -+ struct mtd_info *subdev = concat->subdev[i]; -+ size_t size, retsize; -+ -+ if (from >= subdev->size) { -+ /* Not destined for this subdev */ -+ size = 0; -+ from -= subdev->size; -+ continue; -+ } -+ -+ if (from + len > subdev->size) -+ /* First part goes into this subdev */ -+ size = subdev->size - from; -+ else -+ /* Entire transaction goes into this subdev */ -+ size = len; -+ -+ if (subdev->read_ecc) -+ err = subdev->read_ecc(subdev, from, size, -+ &retsize, buf, eccbuf, oobsel); -+ else -+ err = -EINVAL; -+ -+ if (err) -+ break; -+ -+ *retlen += retsize; -+ len -= size; -+ if (len == 0) -+ break; -+ -+ err = -EINVAL; -+ buf += size; -+ if (eccbuf) { -+ eccbuf += subdev->oobsize; -+ /* in nand.c at least, eccbufs are -+ tagged with 2 (int)eccstatus'; we -+ must account for these */ -+ eccbuf += 2 * (sizeof (int)); -+ } -+ from = 0; - } - return err; - } - --static void concat_erase_callback (struct erase_info *instr) -+static int -+concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t * retlen, const u_char * buf, u_char * eccbuf, -+ struct nand_oobinfo *oobsel) - { -- wake_up((wait_queue_head_t *)instr->priv); -+ struct mtd_concat *concat = CONCAT(mtd); -+ int err = -EINVAL; -+ int i; -+ -+ if (!(mtd->flags & MTD_WRITEABLE)) -+ return -EROFS; -+ -+ *retlen = 0; -+ -+ for (i = 0; i < concat->num_subdev; i++) { -+ struct mtd_info *subdev = concat->subdev[i]; -+ size_t size, retsize; -+ -+ if (to >= subdev->size) { -+ size = 0; -+ to -= subdev->size; -+ continue; -+ } -+ if (to + len > subdev->size) -+ size = subdev->size - to; -+ else -+ size = len; -+ -+ if (!(subdev->flags & MTD_WRITEABLE)) -+ err = -EROFS; -+ else if (subdev->write_ecc) -+ err = subdev->write_ecc(subdev, to, size, -+ &retsize, buf, eccbuf, oobsel); -+ else -+ err = -EINVAL; -+ -+ if (err) -+ break; -+ -+ *retlen += retsize; -+ len -= size; -+ if (len == 0) -+ break; -+ -+ err = -EINVAL; -+ buf += size; -+ if (eccbuf) -+ eccbuf += subdev->oobsize; -+ to = 0; -+ } -+ return err; -+} -+ -+static int -+concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len, -+ size_t * retlen, u_char * buf) -+{ -+ struct mtd_concat *concat = CONCAT(mtd); -+ int err = -EINVAL; -+ int i; -+ -+ *retlen = 0; -+ -+ for (i = 0; i < concat->num_subdev; i++) { -+ struct mtd_info *subdev = concat->subdev[i]; -+ size_t size, retsize; -+ -+ if (from >= subdev->size) { -+ /* Not destined for this subdev */ -+ size = 0; -+ from -= subdev->size; -+ continue; -+ } -+ if (from + len > subdev->size) -+ /* First part goes into this subdev */ -+ size = subdev->size - from; -+ else -+ /* Entire transaction goes into this subdev */ -+ size = len; -+ -+ if (subdev->read_oob) -+ err = subdev->read_oob(subdev, from, size, -+ &retsize, buf); -+ else -+ err = -EINVAL; -+ -+ if (err) -+ break; -+ -+ *retlen += retsize; -+ len -= size; -+ if (len == 0) -+ break; -+ -+ err = -EINVAL; -+ buf += size; -+ from = 0; -+ } -+ return err; -+} -+ -+static int -+concat_write_oob(struct mtd_info *mtd, loff_t to, size_t len, -+ size_t * retlen, const u_char * buf) -+{ -+ struct mtd_concat *concat = CONCAT(mtd); -+ int err = -EINVAL; -+ int i; -+ -+ if (!(mtd->flags & MTD_WRITEABLE)) -+ return -EROFS; -+ -+ *retlen = 0; -+ -+ for (i = 0; i < concat->num_subdev; i++) { -+ struct mtd_info *subdev = concat->subdev[i]; -+ size_t size, retsize; -+ -+ if (to >= subdev->size) { -+ size = 0; -+ to -= subdev->size; -+ continue; -+ } -+ if (to + len > subdev->size) -+ size = subdev->size - to; -+ else -+ size = len; -+ -+ if (!(subdev->flags & MTD_WRITEABLE)) -+ err = -EROFS; -+ else if (subdev->write_oob) -+ err = subdev->write_oob(subdev, to, size, &retsize, -+ buf); -+ else -+ err = -EINVAL; -+ -+ if (err) -+ break; -+ -+ *retlen += retsize; -+ len -= size; -+ if (len == 0) -+ break; -+ -+ err = -EINVAL; -+ buf += size; -+ to = 0; -+ } -+ return err; -+} -+ -+static void concat_erase_callback(struct erase_info *instr) -+{ -+ wake_up((wait_queue_head_t *) instr->priv); - } - - static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase) -@@ -160,18 +365,18 @@ - - erase->mtd = mtd; - erase->callback = concat_erase_callback; -- erase->priv = (unsigned long)&waitq; -+ erase->priv = (unsigned long) &waitq; - - /* - * FIXME: Allow INTERRUPTIBLE. Which means - * not having the wait_queue head on the stack. - */ - err = mtd->erase(mtd, erase); -- if (!err) -- { -+ if (!err) { - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&waitq, &wait); -- if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED) -+ if (erase->state != MTD_ERASE_DONE -+ && erase->state != MTD_ERASE_FAILED) - schedule(); - remove_wait_queue(&waitq, &wait); - set_current_state(TASK_RUNNING); -@@ -181,7 +386,7 @@ - return err; - } - --static int concat_erase (struct mtd_info *mtd, struct erase_info *instr) -+static int concat_erase(struct mtd_info *mtd, struct erase_info *instr) - { - struct mtd_concat *concat = CONCAT(mtd); - struct mtd_info *subdev; -@@ -192,10 +397,10 @@ - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; - -- if(instr->addr > concat->mtd.size) -+ if (instr->addr > concat->mtd.size) - return -EINVAL; - -- if(instr->len + instr->addr > concat->mtd.size) -+ if (instr->len + instr->addr > concat->mtd.size) - return -EINVAL; - - /* -@@ -204,23 +409,22 @@ - * region info rather than looking at each particular sub-device - * in turn. - */ -- if (!concat->mtd.numeraseregions) -- { /* the easy case: device has uniform erase block size */ -- if(instr->addr & (concat->mtd.erasesize - 1)) -+ if (!concat->mtd.numeraseregions) { -+ /* the easy case: device has uniform erase block size */ -+ if (instr->addr & (concat->mtd.erasesize - 1)) - return -EINVAL; -- if(instr->len & (concat->mtd.erasesize - 1)) -+ if (instr->len & (concat->mtd.erasesize - 1)) - return -EINVAL; -- } -- else -- { /* device has variable erase size */ -- struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions; -+ } else { -+ /* device has variable erase size */ -+ struct mtd_erase_region_info *erase_regions = -+ concat->mtd.eraseregions; - - /* - * Find the erase region where the to-be-erased area begins: - */ -- for(i = 0; i < concat->mtd.numeraseregions && -- instr->addr >= erase_regions[i].offset; i++) -- ; -+ for (i = 0; i < concat->mtd.numeraseregions && -+ instr->addr >= erase_regions[i].offset; i++) ; - --i; - - /* -@@ -228,25 +432,26 @@ - * to-be-erased area begins. Verify that the starting - * offset is aligned to this region's erase size: - */ -- if (instr->addr & (erase_regions[i].erasesize-1)) -+ if (instr->addr & (erase_regions[i].erasesize - 1)) - return -EINVAL; - - /* - * now find the erase region where the to-be-erased area ends: - */ -- for(; i < concat->mtd.numeraseregions && -- (instr->addr + instr->len) >= erase_regions[i].offset ; ++i) -- ; -+ for (; i < concat->mtd.numeraseregions && -+ (instr->addr + instr->len) >= erase_regions[i].offset; -+ ++i) ; - --i; - /* - * check if the ending offset is aligned to this region's erase size - */ -- if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1)) -+ if ((instr->addr + instr->len) & (erase_regions[i].erasesize - -+ 1)) - return -EINVAL; - } - - /* make a local copy of instr to avoid modifying the caller's struct */ -- erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL); -+ erase = kmalloc(sizeof (struct erase_info), GFP_KERNEL); - - if (!erase) - return -ENOMEM; -@@ -258,39 +463,40 @@ - * find the subdevice where the to-be-erased area begins, adjust - * starting offset to be relative to the subdevice start - */ -- for(i = 0; i < concat->num_subdev; i++) -- { -+ for (i = 0; i < concat->num_subdev; i++) { - subdev = concat->subdev[i]; -- if(subdev->size <= erase->addr) -+ if (subdev->size <= erase->addr) - erase->addr -= subdev->size; - else - break; - } -- if(i >= concat->num_subdev) /* must never happen since size */ -- BUG(); /* limit has been verified above */ -+ -+ /* must never happen since size limit has been verified above */ -+ if (i >= concat->num_subdev) -+ BUG(); - - /* now do the erase: */ - err = 0; -- for(;length > 0; i++) /* loop for all subevices affected by this request */ -- { -+ for (; length > 0; i++) { -+ /* loop for all subdevices affected by this request */ - subdev = concat->subdev[i]; /* get current subdevice */ - - /* limit length to subdevice's size: */ -- if(erase->addr + length > subdev->size) -+ if (erase->addr + length > subdev->size) - erase->len = subdev->size - erase->addr; - else - erase->len = length; - -- if (!(subdev->flags & MTD_WRITEABLE)) -- { -+ if (!(subdev->flags & MTD_WRITEABLE)) { - err = -EROFS; - break; - } - length -= erase->len; -- if ((err = concat_dev_erase(subdev, erase))) -- { -- if(err == -EINVAL) /* sanity check: must never happen since */ -- BUG(); /* block alignment has been checked above */ -+ if ((err = concat_dev_erase(subdev, erase))) { -+ /* sanity check: should never happen since -+ * block alignment has been checked above */ -+ if (err == -EINVAL) -+ BUG(); - break; - } - /* -@@ -313,7 +519,7 @@ - return 0; - } - --static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len) -+static int concat_lock(struct mtd_info *mtd, loff_t ofs, size_t len) - { - struct mtd_concat *concat = CONCAT(mtd); - int i, err = -EINVAL; -@@ -321,18 +527,15 @@ - if ((len + ofs) > mtd->size) - return -EINVAL; - -- for(i = 0; i < concat->num_subdev; i++) -- { -+ for (i = 0; i < concat->num_subdev; i++) { - struct mtd_info *subdev = concat->subdev[i]; - size_t size; - -- if (ofs >= subdev->size) -- { -+ if (ofs >= subdev->size) { - size = 0; - ofs -= subdev->size; -+ continue; - } -- else -- { - if (ofs + len > subdev->size) - size = subdev->size - ofs; - else -@@ -340,21 +543,21 @@ - - err = subdev->lock(subdev, ofs, size); - -- if(err) -+ if (err) - break; - - len -= size; -- if(len == 0) -+ if (len == 0) - break; - - err = -EINVAL; - ofs = 0; - } -- } -+ - return err; - } - --static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len) -+static int concat_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) - { - struct mtd_concat *concat = CONCAT(mtd); - int i, err = 0; -@@ -362,18 +565,15 @@ - if ((len + ofs) > mtd->size) - return -EINVAL; - -- for(i = 0; i < concat->num_subdev; i++) -- { -+ for (i = 0; i < concat->num_subdev; i++) { - struct mtd_info *subdev = concat->subdev[i]; - size_t size; - -- if (ofs >= subdev->size) -- { -+ if (ofs >= subdev->size) { - size = 0; - ofs -= subdev->size; -+ continue; - } -- else -- { - if (ofs + len > subdev->size) - size = subdev->size - ofs; - else -@@ -381,17 +581,17 @@ - - err = subdev->unlock(subdev, ofs, size); - -- if(err) -+ if (err) - break; - - len -= size; -- if(len == 0) -+ if (len == 0) - break; - - err = -EINVAL; - ofs = 0; - } -- } -+ - return err; - } - -@@ -400,8 +600,7 @@ - struct mtd_concat *concat = CONCAT(mtd); - int i; - -- for(i = 0; i < concat->num_subdev; i++) -- { -+ for (i = 0; i < concat->num_subdev; i++) { - struct mtd_info *subdev = concat->subdev[i]; - subdev->sync(subdev); - } -@@ -412,10 +611,9 @@ - struct mtd_concat *concat = CONCAT(mtd); - int i, rc = 0; - -- for(i = 0; i < concat->num_subdev; i++) -- { -+ for (i = 0; i < concat->num_subdev; i++) { - struct mtd_info *subdev = concat->subdev[i]; -- if((rc = subdev->suspend(subdev)) < 0) -+ if ((rc = subdev->suspend(subdev)) < 0) - return rc; - } - return rc; -@@ -426,8 +624,7 @@ - struct mtd_concat *concat = CONCAT(mtd); - int i; - -- for(i = 0; i < concat->num_subdev; i++) -- { -+ for (i = 0; i < concat->num_subdev; i++) { - struct mtd_info *subdev = concat->subdev[i]; - subdev->resume(subdev); - } -@@ -439,11 +636,10 @@ - * stored to *new_dev upon success. This function does _not_ - * register any devices: this is the caller's responsibility. - */ --struct mtd_info *mtd_concat_create( -- struct mtd_info *subdev[], /* subdevices to concatenate */ -+struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to concatenate */ - int num_devs, /* number of subdevices */ -- char *name) /* name for the new device */ --{ -+ char *name) -+{ /* name for the new device */ - int i; - size_t size; - struct mtd_concat *concat; -@@ -451,21 +647,21 @@ - int num_erase_region; - - printk(KERN_NOTICE "Concatenating MTD devices:\n"); -- for(i = 0; i < num_devs; i++) -+ for (i = 0; i < num_devs; i++) - printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name); - printk(KERN_NOTICE "into device \"%s\"\n", name); - - /* allocate the device structure */ - size = SIZEOF_STRUCT_MTD_CONCAT(num_devs); -- concat = kmalloc (size, GFP_KERNEL); -- if(!concat) -- { -- printk ("memory allocation error while creating concatenated device \"%s\"\n", -+ concat = kmalloc(size, GFP_KERNEL); -+ if (!concat) { -+ printk -+ ("memory allocation error while creating concatenated device \"%s\"\n", - name); - return NULL; - } - memset(concat, 0, size); -- concat->subdev = (struct mtd_info **)(concat + 1); -+ concat->subdev = (struct mtd_info **) (concat + 1); - - /* - * Set up the new "super" device's MTD object structure, check for -@@ -479,39 +675,53 @@ - concat->mtd.oobsize = subdev[0]->oobsize; - concat->mtd.ecctype = subdev[0]->ecctype; - concat->mtd.eccsize = subdev[0]->eccsize; -+ if (subdev[0]->read_ecc) -+ concat->mtd.read_ecc = concat_read_ecc; -+ if (subdev[0]->write_ecc) -+ concat->mtd.write_ecc = concat_write_ecc; -+ if (subdev[0]->read_oob) -+ concat->mtd.read_oob = concat_read_oob; -+ if (subdev[0]->write_oob) -+ concat->mtd.write_oob = concat_write_oob; - - concat->subdev[0] = subdev[0]; - -- for(i = 1; i < num_devs; i++) -- { -- if(concat->mtd.type != subdev[i]->type) -- { -+ for (i = 1; i < num_devs; i++) { -+ if (concat->mtd.type != subdev[i]->type) { - kfree(concat); -- printk ("Incompatible device type on \"%s\"\n", subdev[i]->name); -+ printk("Incompatible device type on \"%s\"\n", -+ subdev[i]->name); - return NULL; - } -- if(concat->mtd.flags != subdev[i]->flags) -- { /* -- * Expect all flags except MTD_WRITEABLE to be equal on -- * all subdevices. -+ if (concat->mtd.flags != subdev[i]->flags) { -+ /* -+ * Expect all flags except MTD_WRITEABLE to be -+ * equal on all subdevices. - */ -- if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE) -- { -+ if ((concat->mtd.flags ^ subdev[i]-> -+ flags) & ~MTD_WRITEABLE) { - kfree(concat); -- printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name); -+ printk("Incompatible device flags on \"%s\"\n", -+ subdev[i]->name); - return NULL; -- } -- else /* if writeable attribute differs, make super device writeable */ -- concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE; -+ } else -+ /* if writeable attribute differs, -+ make super device writeable */ -+ concat->mtd.flags |= -+ subdev[i]->flags & MTD_WRITEABLE; - } - concat->mtd.size += subdev[i]->size; -- if(concat->mtd.oobblock != subdev[i]->oobblock || -+ if (concat->mtd.oobblock != subdev[i]->oobblock || - concat->mtd.oobsize != subdev[i]->oobsize || - concat->mtd.ecctype != subdev[i]->ecctype || -- concat->mtd.eccsize != subdev[i]->eccsize) -- { -+ concat->mtd.eccsize != subdev[i]->eccsize || -+ !concat->mtd.read_ecc != !subdev[i]->read_ecc || -+ !concat->mtd.write_ecc != !subdev[i]->write_ecc || -+ !concat->mtd.read_oob != !subdev[i]->read_oob || -+ !concat->mtd.write_oob != !subdev[i]->write_oob) { - kfree(concat); -- printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name); -+ printk("Incompatible OOB or ECC data on \"%s\"\n", -+ subdev[i]->name); - return NULL; - } - concat->subdev[i] = subdev[i]; -@@ -535,7 +745,6 @@ - concat->mtd.suspend = concat_suspend; - concat->mtd.resume = concat_resume; - -- - /* - * Combine the erase block size info of the subdevices: - * -@@ -544,44 +753,44 @@ - */ - max_erasesize = curr_erasesize = subdev[0]->erasesize; - num_erase_region = 1; -- for(i = 0; i < num_devs; i++) -- { -- if(subdev[i]->numeraseregions == 0) -- { /* current subdevice has uniform erase size */ -- if(subdev[i]->erasesize != curr_erasesize) -- { /* if it differs from the last subdevice's erase size, count it */ -+ for (i = 0; i < num_devs; i++) { -+ if (subdev[i]->numeraseregions == 0) { -+ /* current subdevice has uniform erase size */ -+ if (subdev[i]->erasesize != curr_erasesize) { -+ /* if it differs from the last subdevice's erase size, count it */ - ++num_erase_region; - curr_erasesize = subdev[i]->erasesize; -- if(curr_erasesize > max_erasesize) -+ if (curr_erasesize > max_erasesize) - max_erasesize = curr_erasesize; - } -- } -- else -- { /* current subdevice has variable erase size */ -+ } else { -+ /* current subdevice has variable erase size */ - int j; -- for(j = 0; j < subdev[i]->numeraseregions; j++) -- { /* walk the list of erase regions, count any changes */ -- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) -- { -+ for (j = 0; j < subdev[i]->numeraseregions; j++) { -+ -+ /* walk the list of erase regions, count any changes */ -+ if (subdev[i]->eraseregions[j].erasesize != -+ curr_erasesize) { - ++num_erase_region; -- curr_erasesize = subdev[i]->eraseregions[j].erasesize; -- if(curr_erasesize > max_erasesize) -+ curr_erasesize = -+ subdev[i]->eraseregions[j]. -+ erasesize; -+ if (curr_erasesize > max_erasesize) - max_erasesize = curr_erasesize; - } - } - } - } - -- if(num_erase_region == 1) -- { /* -+ if (num_erase_region == 1) { -+ /* - * All subdevices have the same uniform erase size. - * This is easy: - */ - concat->mtd.erasesize = curr_erasesize; - concat->mtd.numeraseregions = 0; -- } -- else -- { /* -+ } else { -+ /* - * erase block size varies across the subdevices: allocate - * space to store the data describing the variable erase regions - */ -@@ -590,12 +799,13 @@ - - concat->mtd.erasesize = max_erasesize; - concat->mtd.numeraseregions = num_erase_region; -- concat->mtd.eraseregions = erase_region_p = kmalloc ( -- num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL); -- if(!erase_region_p) -- { -+ concat->mtd.eraseregions = erase_region_p = -+ kmalloc(num_erase_region * -+ sizeof (struct mtd_erase_region_info), GFP_KERNEL); -+ if (!erase_region_p) { - kfree(concat); -- printk ("memory allocation error while creating erase region list" -+ printk -+ ("memory allocation error while creating erase region list" - " for device \"%s\"\n", name); - return NULL; - } -@@ -606,41 +816,48 @@ - */ - curr_erasesize = subdev[0]->erasesize; - begin = position = 0; -- for(i = 0; i < num_devs; i++) -- { -- if(subdev[i]->numeraseregions == 0) -- { /* current subdevice has uniform erase size */ -- if(subdev[i]->erasesize != curr_erasesize) -- { /* -+ for (i = 0; i < num_devs; i++) { -+ if (subdev[i]->numeraseregions == 0) { -+ /* current subdevice has uniform erase size */ -+ if (subdev[i]->erasesize != curr_erasesize) { -+ /* - * fill in an mtd_erase_region_info structure for the area - * we have walked so far: - */ - erase_region_p->offset = begin; -- erase_region_p->erasesize = curr_erasesize; -- erase_region_p->numblocks = (position - begin) / curr_erasesize; -+ erase_region_p->erasesize = -+ curr_erasesize; -+ erase_region_p->numblocks = -+ (position - begin) / curr_erasesize; - begin = position; - - curr_erasesize = subdev[i]->erasesize; - ++erase_region_p; - } - position += subdev[i]->size; -- } -- else -- { /* current subdevice has variable erase size */ -+ } else { -+ /* current subdevice has variable erase size */ - int j; -- for(j = 0; j < subdev[i]->numeraseregions; j++) -- { /* walk the list of erase regions, count any changes */ -- if(subdev[i]->eraseregions[j].erasesize != curr_erasesize) -- { -+ for (j = 0; j < subdev[i]->numeraseregions; j++) { -+ /* walk the list of erase regions, count any changes */ -+ if (subdev[i]->eraseregions[j]. -+ erasesize != curr_erasesize) { - erase_region_p->offset = begin; -- erase_region_p->erasesize = curr_erasesize; -- erase_region_p->numblocks = (position - begin) / curr_erasesize; -+ erase_region_p->erasesize = -+ curr_erasesize; -+ erase_region_p->numblocks = -+ (position - -+ begin) / curr_erasesize; - begin = position; - -- curr_erasesize = subdev[i]->eraseregions[j].erasesize; -+ curr_erasesize = -+ subdev[i]->eraseregions[j]. -+ erasesize; - ++erase_region_p; - } -- position += subdev[i]->eraseregions[j].numblocks * curr_erasesize; -+ position += -+ subdev[i]->eraseregions[j]. -+ numblocks * curr_erasesize; - } - } - } -@@ -660,16 +877,14 @@ - void mtd_concat_destroy(struct mtd_info *mtd) - { - struct mtd_concat *concat = CONCAT(mtd); -- if(concat->mtd.numeraseregions) -+ if (concat->mtd.numeraseregions) - kfree(concat->mtd.eraseregions); - kfree(concat); - } - -- - EXPORT_SYMBOL(mtd_concat_create); - EXPORT_SYMBOL(mtd_concat_destroy); - -- - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>"); - MODULE_DESCRIPTION("Generic support for concatenating of MTD devices"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdcore.c linux/drivers/mtd/mtdcore.c ---- linux-mips-2.4.27/drivers/mtd/mtdcore.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/mtdcore.c 2004-11-19 10:25:11.650237640 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Core registration and callback routines for MTD - * drivers and users. -@@ -17,6 +17,7 @@ - #include <linux/major.h> - #include <linux/fs.h> - #include <linux/ioctl.h> -+#include <linux/init.h> - #include <linux/mtd/compatmac.h> - #ifdef CONFIG_PROC_FS - #include <linux/proc_fs.h> -@@ -24,9 +25,15 @@ - - #include <linux/mtd/mtd.h> - --static DECLARE_MUTEX(mtd_table_mutex); --static struct mtd_info *mtd_table[MAX_MTD_DEVICES]; --static struct mtd_notifier *mtd_notifiers = NULL; -+/* These are exported solely for the purpose of mtd_blkdevs.c. You -+ should not use them for _anything_ else */ -+DECLARE_MUTEX(mtd_table_mutex); -+struct mtd_info *mtd_table[MAX_MTD_DEVICES]; -+ -+EXPORT_SYMBOL_GPL(mtd_table_mutex); -+EXPORT_SYMBOL_GPL(mtd_table); -+ -+static LIST_HEAD(mtd_notifiers); - - /** - * add_mtd_device - register an MTD device -@@ -44,21 +51,28 @@ - - down(&mtd_table_mutex); - -- for (i=0; i< MAX_MTD_DEVICES; i++) -- if (!mtd_table[i]) -- { -- struct mtd_notifier *not=mtd_notifiers; -+ for (i=0; i < MAX_MTD_DEVICES; i++) -+ if (!mtd_table[i]) { -+ struct list_head *this; - - mtd_table[i] = mtd; - mtd->index = i; -+ mtd->usecount = 0; -+ - DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name); -- while (not) -- { -- (*(not->add))(mtd); -- not = not->next; -+ /* No need to get a refcount on the module containing -+ the notifier, since we hold the mtd_table_mutex */ -+ list_for_each(this, &mtd_notifiers) { -+ struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); -+ not->add(mtd); - } -+ - up(&mtd_table_mutex); -- MOD_INC_USE_COUNT; -+ /* We _know_ we aren't being removed, because -+ our caller is still holding us here. So none -+ of this try_ nonsense, and no bitching about it -+ either. :) */ -+ __module_get(THIS_MODULE); - return 0; - } - -@@ -78,29 +92,34 @@ - - int del_mtd_device (struct mtd_info *mtd) - { -- struct mtd_notifier *not=mtd_notifiers; -- int i; -+ int ret; - - down(&mtd_table_mutex); - -- for (i=0; i < MAX_MTD_DEVICES; i++) -- { -- if (mtd_table[i] == mtd) -- { -- while (not) -- { -- (*(not->remove))(mtd); -- not = not->next; -- } -- mtd_table[i] = NULL; -- up (&mtd_table_mutex); -- MOD_DEC_USE_COUNT; -- return 0; -+ if (mtd_table[mtd->index] != mtd) { -+ ret = -ENODEV; -+ } else if (mtd->usecount) { -+ printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", -+ mtd->index, mtd->name, mtd->usecount); -+ ret = -EBUSY; -+ } else { -+ struct list_head *this; -+ -+ /* No need to get a refcount on the module containing -+ the notifier, since we hold the mtd_table_mutex */ -+ list_for_each(this, &mtd_notifiers) { -+ struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); -+ not->remove(mtd); - } -+ -+ mtd_table[mtd->index] = NULL; -+ -+ module_put(THIS_MODULE); -+ ret = 0; - } - - up(&mtd_table_mutex); -- return 1; -+ return ret; - } - - /** -@@ -118,10 +137,9 @@ - - down(&mtd_table_mutex); - -- new->next = mtd_notifiers; -- mtd_notifiers = new; -+ list_add(&new->list, &mtd_notifiers); - -- MOD_INC_USE_COUNT; -+ __module_get(THIS_MODULE); - - for (i=0; i< MAX_MTD_DEVICES; i++) - if (mtd_table[i]) -@@ -142,34 +160,24 @@ - - int unregister_mtd_user (struct mtd_notifier *old) - { -- struct mtd_notifier **prev = &mtd_notifiers; -- struct mtd_notifier *cur; - int i; - - down(&mtd_table_mutex); - -- while ((cur = *prev)) { -- if (cur == old) { -- *prev = cur->next; -- -- MOD_DEC_USE_COUNT; -+ module_put(THIS_MODULE); - - for (i=0; i< MAX_MTD_DEVICES; i++) - if (mtd_table[i]) - old->remove(mtd_table[i]); - -+ list_del(&old->list); - up(&mtd_table_mutex); - return 0; -- } -- prev = &cur->next; -- } -- up(&mtd_table_mutex); -- return 1; - } - - - /** -- * __get_mtd_device - obtain a validated handle for an MTD device -+ * get_mtd_device - obtain a validated handle for an MTD device - * @mtd: last known address of the required MTD device - * @num: internal device number of the required MTD device - * -@@ -177,11 +185,10 @@ - * table, if any. Given an address and num == -1, search the device table - * for a device with that address and return if it's still present. Given - * both, return the num'th driver only if its address matches. Return NULL -- * if not. get_mtd_device() increases the use count, but -- * __get_mtd_device() doesn't - you should generally use get_mtd_device(). -+ * if not. - */ - --struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num) -+struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) - { - struct mtd_info *ret = NULL; - int i; -@@ -198,10 +205,27 @@ - ret = NULL; - } - -+ if (ret && !try_module_get(ret->owner)) -+ ret = NULL; -+ -+ if (ret) -+ ret->usecount++; -+ - up(&mtd_table_mutex); - return ret; - } - -+void put_mtd_device(struct mtd_info *mtd) -+{ -+ int c; -+ -+ down(&mtd_table_mutex); -+ c = --mtd->usecount; -+ up(&mtd_table_mutex); -+ BUG_ON(c < 0); -+ -+ module_put(mtd->owner); -+} - - /* default_mtd_writev - default mtd writev method for MTD devices that - * dont implement their own -@@ -265,7 +289,8 @@ - - EXPORT_SYMBOL(add_mtd_device); - EXPORT_SYMBOL(del_mtd_device); --EXPORT_SYMBOL(__get_mtd_device); -+EXPORT_SYMBOL(get_mtd_device); -+EXPORT_SYMBOL(put_mtd_device); - EXPORT_SYMBOL(register_mtd_user); - EXPORT_SYMBOL(unregister_mtd_user); - EXPORT_SYMBOL(default_mtd_writev); -diff -Nurb linux-mips-2.4.27/drivers/mtd/mtdpart.c linux/drivers/mtd/mtdpart.c ---- linux-mips-2.4.27/drivers/mtd/mtdpart.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/mtdpart.c 2004-11-19 10:25:11.652237336 +0100 -@@ -5,7 +5,7 @@ - * - * This code is GPL - * -- * $Id$ -+ * $Id$ - * - * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> - * added support for read_oob, write_oob -@@ -16,10 +16,11 @@ - #include <linux/kernel.h> - #include <linux/slab.h> - #include <linux/list.h> -- -+#include <linux/config.h> -+#include <linux/kmod.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/partitions.h> -- -+#include <linux/mtd/compatmac.h> - - /* Our partition linked list */ - static LIST_HEAD(mtd_partitions); -@@ -54,8 +55,12 @@ - len = 0; - else if (from + len > mtd->size) - len = mtd->size - from; -+ if (part->master->read_ecc == NULL) - return part->master->read (part->master, from + part->offset, - len, retlen, buf); -+ else -+ return part->master->read_ecc (part->master, from + part->offset, -+ len, retlen, buf, NULL, &mtd->oobinfo); - } - - static int part_point (struct mtd_info *mtd, loff_t from, size_t len, -@@ -78,9 +83,11 @@ - - - static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, -- size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel) -+ size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) - { - struct mtd_part *part = PART(mtd); -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; - if (from >= mtd->size) - len = 0; - else if (from + len > mtd->size) -@@ -113,7 +120,7 @@ - size_t *retlen, u_char *buf) - { - struct mtd_part *part = PART(mtd); -- return part->master->read_user_prot_reg (part->master, from, -+ return part->master->read_fact_prot_reg (part->master, from, - len, retlen, buf); - } - -@@ -127,17 +134,24 @@ - len = 0; - else if (to + len > mtd->size) - len = mtd->size - to; -+ if (part->master->write_ecc == NULL) - return part->master->write (part->master, to + part->offset, - len, retlen, buf); -+ else -+ return part->master->write_ecc (part->master, to + part->offset, -+ len, retlen, buf, NULL, &mtd->oobinfo); -+ - } - - static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, -- u_char *eccbuf, int oobsel) -+ u_char *eccbuf, struct nand_oobinfo *oobsel) - { - struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; - if (to >= mtd->size) - len = 0; - else if (to + len > mtd->size) -@@ -174,25 +188,37 @@ - struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; -+ if (part->master->writev_ecc == NULL) - return part->master->writev (part->master, vecs, count, - to + part->offset, retlen); -+ else -+ return part->master->writev_ecc (part->master, vecs, count, -+ to + part->offset, retlen, -+ NULL, &mtd->oobinfo); - } - - static int part_readv (struct mtd_info *mtd, struct iovec *vecs, - unsigned long count, loff_t from, size_t *retlen) - { - struct mtd_part *part = PART(mtd); -+ if (part->master->readv_ecc == NULL) - return part->master->readv (part->master, vecs, count, - from + part->offset, retlen); -+ else -+ return part->master->readv_ecc (part->master, vecs, count, -+ from + part->offset, retlen, -+ NULL, &mtd->oobinfo); - } - - static int part_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t *retlen, -- u_char *eccbuf, int oobsel) -+ u_char *eccbuf, struct nand_oobinfo *oobsel) - { - struct mtd_part *part = PART(mtd); - if (!(mtd->flags & MTD_WRITEABLE)) - return -EROFS; -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; - return part->master->writev_ecc (part->master, vecs, count, - to + part->offset, retlen, - eccbuf, oobsel); -@@ -200,9 +226,11 @@ - - static int part_readv_ecc (struct mtd_info *mtd, struct iovec *vecs, - unsigned long count, loff_t from, size_t *retlen, -- u_char *eccbuf, int oobsel) -+ u_char *eccbuf, struct nand_oobinfo *oobsel) - { - struct mtd_part *part = PART(mtd); -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; - return part->master->readv_ecc (part->master, vecs, count, - from + part->offset, retlen, - eccbuf, oobsel); -@@ -288,7 +316,7 @@ - */ - - int add_mtd_partitions(struct mtd_info *master, -- struct mtd_partition *parts, -+ const struct mtd_partition *parts, - int nbparts) - { - struct mtd_part *slave; -@@ -321,7 +349,7 @@ - - slave->mtd.name = parts[i].name; - slave->mtd.bank_size = master->bank_size; -- slave->mtd.module = master->module; -+ slave->mtd.owner = master->owner; - - slave->mtd.read = part_read; - slave->mtd.write = part_write; -@@ -452,6 +480,75 @@ - EXPORT_SYMBOL(add_mtd_partitions); - EXPORT_SYMBOL(del_mtd_partitions); - -+static spinlock_t part_parser_lock = SPIN_LOCK_UNLOCKED; -+static LIST_HEAD(part_parsers); -+ -+struct mtd_part_parser *get_partition_parser(const char *name) -+{ -+ struct list_head *this; -+ void *ret = NULL; -+ spin_lock(&part_parser_lock); -+ -+ list_for_each(this, &part_parsers) { -+ struct mtd_part_parser *p = list_entry(this, struct mtd_part_parser, list); -+ -+ if (!strcmp(p->name, name) && try_module_get(p->owner)) { -+ ret = p; -+ break; -+ } -+ } -+ spin_unlock(&part_parser_lock); -+ -+ return ret; -+} -+ -+int register_mtd_parser(struct mtd_part_parser *p) -+{ -+ spin_lock(&part_parser_lock); -+ list_add(&p->list, &part_parsers); -+ spin_unlock(&part_parser_lock); -+ -+ return 0; -+} -+ -+int deregister_mtd_parser(struct mtd_part_parser *p) -+{ -+ spin_lock(&part_parser_lock); -+ list_del(&p->list); -+ spin_unlock(&part_parser_lock); -+ return 0; -+} -+ -+int parse_mtd_partitions(struct mtd_info *master, const char **types, -+ struct mtd_partition **pparts, unsigned long origin) -+{ -+ struct mtd_part_parser *parser; -+ int ret = 0; -+ -+ for ( ; ret <= 0 && *types; types++) { -+ parser = get_partition_parser(*types); -+#ifdef CONFIG_KMOD -+ if (!parser && !request_module("%s", *types)) -+ parser = get_partition_parser(*types); -+#endif -+ if (!parser) { -+ printk(KERN_NOTICE "%s partition parsing not available\n", -+ *types); -+ continue; -+ } -+ ret = (*parser->parse_fn)(master, pparts, origin); -+ if (ret > 0) { -+ printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", -+ ret, parser->name, master->name); -+ } -+ put_partition_parser(parser); -+ } -+ return ret; -+} -+ -+EXPORT_SYMBOL_GPL(parse_mtd_partitions); -+EXPORT_SYMBOL_GPL(register_mtd_parser); -+EXPORT_SYMBOL_GPL(deregister_mtd_parser); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/Config.in linux/drivers/mtd/nand/Config.in ---- linux-mips-2.4.27/drivers/mtd/nand/Config.in 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/nand/Config.in 2004-11-19 10:25:11.987186416 +0100 -@@ -1,6 +1,6 @@ - # drivers/mtd/nand/Config.in - --# $Id$ -+# $Id$ - - mainmenu_option next_comment - -@@ -11,26 +11,27 @@ - bool ' Verify NAND page writes' CONFIG_MTD_NAND_VERIFY_WRITE - fi - --if [ "$CONFIG_ARM" = "y" -a "$CONFIG_ARCH_P720T" = "y" ]; then -- dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND -+if [ "$CONFIG_ARM" = "y" ]; then -+ dep_tristate ' NAND Flash device on SPIA board' CONFIG_MTD_NAND_SPIA $CONFIG_MTD_NAND $CONFIG_ARCH_P720T -+ dep_tristate ' NAND Flash device on TOTO board' CONFIG_MTD_NAND_TOTO $CONFIG_MTD_NAND $CONFIG_ARCH_OMAP -+ dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND $CONFIG_ARCH_AUTCPU12 -+ dep_tristate ' NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND $CONFIG_ARCH_EDB7312 - fi - --if [ "$CONFIG_ARCH_AUTCPU12" = "y" ]; then -- dep_tristate ' SmartMedia Card on AUTCPU12 board' CONFIG_MTD_NAND_AUTCPU12 $CONFIG_MTD_NAND --fi -- --if [ "$CONFIG_ARCH_EDB7312" = "y" ]; then -- dep_tristate ' NAND Flash device on EDP7312 board' CONFIG_MTD_NAND_EDB7312 $CONFIG_MTD_NAND --fi -- --if [ "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then -+if [ "$CONFIG_MTD_DOC2001PLUS" = "y" -o "$CONFIG_MTD_DOC2001" = "y" -o "$CONFIG_MTD_DOC2000" = "y" -o "$CONFIG_MTD_NAND" = "y" ]; then - define_bool CONFIG_MTD_NAND_IDS y -+else -+ if [ "$CONFIG_MTD_DOC2001PLUS" = "m" -o "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then -+ define_bool CONFIG_MTD_NAND_IDS m -+ fi - fi - --if [ "$CONFIG_MTD_NAND_IDS" != "y" ]; then --if [ "$CONFIG_MTD_DOC2001" = "m" -o "$CONFIG_MTD_DOC2000" = "m" -o "$CONFIG_MTD_NAND" = "m" ]; then -- define_bool CONFIG_MTD_NAND_IDS m -+if [ "$CONFIG_TOSHIBA_RBTX4925" = "y" ]; then -+ dep_tristate ' SmartMedia Card on Toshiba RBTX4925 reference board' CONFIG_MTD_NAND_TX4925NDFMC $CONFIG_MTD_NAND $CONFIG_TOSHIBA_RBTX4925_MPLEX_NAND - fi -+ -+if [ "$CONFIG_TOSHIBA_RBTX4938" = "y" ]; then -+ dep_tristate ' NAND Flash device on Toshiba RBTX4938 reference board' CONFIG_MTD_NAND_TX4938NDFMC $CONFIG_MTD_NAND $CONFIG_TOSHIBA_RBTX4938_MPLEX_NAND - fi - - endmenu -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/Makefile linux/drivers/mtd/nand/Makefile ---- linux-mips-2.4.27/drivers/mtd/nand/Makefile 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/nand/Makefile 2004-11-19 10:25:11.989186112 +0100 -@@ -1,16 +1,20 @@ - # - # linux/drivers/nand/Makefile - # --# $Id$ -+# $Id$ - -+ifeq ($(PATCHLEVEL),4) - O_TARGET := nandlink.o -- - export-objs := nand.o nand_ecc.o nand_ids.o -+endif - - obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o - obj-$(CONFIG_MTD_NAND_SPIA) += spia.o -+obj-$(CONFIG_MTD_NAND_TOTO) += toto.o - obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o - obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o -+obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o -+obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o - obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o - --include $(TOPDIR)/Rules.make -+-include $(TOPDIR)/Rules.make -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/autcpu12.c linux/drivers/mtd/nand/autcpu12.c ---- linux-mips-2.4.27/drivers/mtd/nand/autcpu12.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/nand/autcpu12.c 2004-11-19 10:25:11.990185960 +0100 -@@ -4,9 +4,9 @@ - * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> - * - * Derived from drivers/mtd/spia.c -- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) -+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -25,10 +25,10 @@ - * added page_cache - * - * 10-06-2002 TG 128K card support added -- * - */ - - #include <linux/slab.h> -+#include <linux/init.h> - #include <linux/module.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/nand.h> -@@ -70,6 +70,7 @@ - /* - * Define partitions for flash devices - */ -+extern struct nand_oobinfo jffs2_oobinfo; - - static struct mtd_partition partition_info16k[] = { - { name: "AUTCPU12 flash partition 1", -@@ -95,7 +96,7 @@ - size: 16 * SZ_1M }, - { name: "AUTCPU12 flash partition 2", - offset: 16 * SZ_1M, -- size: 48 * SZ_1M}, -+ size: 48 * SZ_1M }, - }; - - static struct mtd_partition partition_info128k[] = { -@@ -104,7 +105,7 @@ - size: 16 * SZ_1M }, - { name: "AUTCPU12 flash partition 2", - offset: 16 * SZ_1M, -- size: 112 * SZ_1M}, -+ size: 112 * SZ_1M }, - }; - - #define NUM_PARTITIONS16K 2 -@@ -114,7 +115,7 @@ - /* - * hardware specific access to control-lines - */ --void autcpu12_hwcontrol(int cmd) -+static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd) - { - - switch(cmd){ -@@ -133,7 +134,7 @@ - /* - * read device ready pin - */ --int autcpu12_device_ready(void) -+int autcpu12_device_ready(struct mtd_info *mtd) - { - - return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0; -@@ -184,7 +185,7 @@ - this->eccmode = NAND_ECC_SOFT; - - /* Scan to find existance of the device */ -- if (nand_scan (autcpu12_mtd)) { -+ if (nand_scan (autcpu12_mtd, 1)) { - err = -ENXIO; - goto out_ior; - } -@@ -197,15 +198,6 @@ - goto out_ior; - } - -- /* Allocate memory for internal data buffer */ -- this->data_cache = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL); -- if (!this->data_cache) { -- printk ("Unable to allocate NAND data cache for AUTCPU12.\n"); -- err = -ENOMEM; -- goto out_buf; -- } -- this->cache_page = -1; -- - /* Register the partitions */ - switch(autcpu12_mtd->size){ - case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; -@@ -215,13 +207,11 @@ - default: { - printk ("Unsupported SmartMedia device\n"); - err = -ENXIO; -- goto out_cac; -+ goto out_buf; - } - } - goto out; - --out_cac: -- kfree (this->data_cache); - out_buf: - kfree (this->data_buf); - out_ior: -@@ -250,7 +240,6 @@ - - /* Free internal data buffers */ - kfree (this->data_buf); -- kfree (this->data_cache); - - /* unmap physical adress */ - iounmap((void *)autcpu12_fio_base); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/diskonchip.c linux/drivers/mtd/nand/diskonchip.c ---- linux-mips-2.4.27/drivers/mtd/nand/diskonchip.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/nand/diskonchip.c 2004-11-19 10:25:11.992185656 +0100 -@@ -0,0 +1,534 @@ -+/* -+ * drivers/mtd/nand/diskonchip.c -+ * -+ * (C) 2003 Red Hat, Inc. -+ * -+ * Author: David Woodhouse <dwmw2@infradead.org> -+ * -+ * Interface to generic NAND code for M-Systems DiskOnChip devices -+ * -+ * $Id$ -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/sched.h> -+#include <linux/delay.h> -+#include <asm/io.h> -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nand.h> -+#include <linux/mtd/doc2000.h> -+#include <linux/mtd/compatmac.h> -+ -+struct doc_priv { -+ unsigned long virtadr; -+ unsigned long physadr; -+ u_char ChipID; -+ u_char CDSNControl; -+ int chips_per_floor; /* The number of chips detected on each floor */ -+ int curfloor; -+ int curchip; -+}; -+ -+#define DoC_is_Millennium(doc) ((doc)->ChipID == DOC_ChipID_DocMil) -+#define DoC_is_2000(doc) ((doc)->ChipID == DOC_ChipID_Doc2k) -+ -+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd); -+static void doc200x_select_chip(struct mtd_info *mtd, int chip); -+ -+static int debug=0; -+MODULE_PARM(debug, "i"); -+ -+static int try_dword=1; -+MODULE_PARM(try_dword, "i"); -+ -+static void DoC_Delay(struct doc_priv *doc, unsigned short cycles) -+{ -+ volatile char dummy; -+ int i; -+ -+ for (i = 0; i < cycles; i++) { -+ if (DoC_is_Millennium(doc)) -+ dummy = ReadDOC(doc->virtadr, NOP); -+ else -+ dummy = ReadDOC(doc->virtadr, DOCStatus); -+ } -+ -+} -+/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ -+static int _DoC_WaitReady(struct doc_priv *doc) -+{ -+ unsigned long docptr = doc->virtadr; -+ unsigned long timeo = jiffies + (HZ * 10); -+ -+ if(debug) printk("_DoC_WaitReady...\n"); -+ /* Out-of-line routine to wait for chip response */ -+ while (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { -+ if (time_after(jiffies, timeo)) { -+ printk("_DoC_WaitReady timed out.\n"); -+ return -EIO; -+ } -+ udelay(1); -+ cond_resched(); -+ } -+ -+ return 0; -+} -+ -+static inline int DoC_WaitReady(struct doc_priv *doc) -+{ -+ unsigned long docptr = doc->virtadr; -+ int ret = 0; -+ -+ DoC_Delay(doc, 4); -+ -+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) -+ /* Call the out-of-line routine to wait */ -+ ret = _DoC_WaitReady(doc); -+ -+ DoC_Delay(doc, 2); -+ if(debug) printk("DoC_WaitReady OK\n"); -+ return ret; -+} -+ -+static void doc2000_write_byte(struct mtd_info *mtd, u_char datum) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ -+ if(debug)printk("write_byte %02x\n", datum); -+ WriteDOC(datum, docptr, CDSNSlowIO); -+ WriteDOC(datum, docptr, 2k_CDSN_IO); -+} -+ -+static u_char doc2000_read_byte(struct mtd_info *mtd) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ -+ ReadDOC(docptr, CDSNSlowIO); -+ u_char ret = ReadDOC(docptr, 2k_CDSN_IO); -+ if (debug) printk("read_byte returns %02x\n", ret); -+ return ret; -+} -+static void doc2000_writebuf(struct mtd_info *mtd, -+ const u_char *buf, int len) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ int i; -+ if (debug)printk("writebuf of %d bytes: ", len); -+ for (i=0; i < len; i++) { -+ WriteDOC_(buf[i], docptr, DoC_2k_CDSN_IO + i); -+ if (debug && i < 16) -+ printk("%02x ", buf[i]); -+ } -+ if (debug) printk("\n"); -+} -+ -+static void doc2000_readbuf(struct mtd_info *mtd, -+ u_char *buf, int len) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ int i; -+ -+ if (debug)printk("readbuf of %d bytes: ", len); -+ -+ for (i=0; i < len; i++) { -+ buf[i] = ReadDOC(docptr, 2k_CDSN_IO + i); -+ } -+} -+ -+static void doc2000_readbuf_dword(struct mtd_info *mtd, -+ u_char *buf, int len) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ int i; -+ -+ if (debug) printk("readbuf_dword of %d bytes: ", len); -+ -+ if (unlikely((((unsigned long)buf)|len) & 3)) { -+ for (i=0; i < len; i++) { -+ *(uint8_t *)(&buf[i]) = ReadDOC(docptr, 2k_CDSN_IO + i); -+ } -+ } else { -+ for (i=0; i < len; i+=4) { -+ *(uint32_t*)(&buf[i]) = readl(docptr + DoC_2k_CDSN_IO + i); -+ } -+ } -+} -+ -+static int doc2000_verifybuf(struct mtd_info *mtd, -+ const u_char *buf, int len) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ int i; -+ -+ for (i=0; i < len; i++) -+ if (buf[i] != ReadDOC(docptr, 2k_CDSN_IO)) -+ return i; -+ return 0; -+} -+ -+static uint16_t doc200x_ident_chip(struct mtd_info *mtd, int nr) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ uint16_t ret; -+ -+ doc200x_select_chip(mtd, nr); -+ doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); -+ this->write_byte(mtd, NAND_CMD_READID); -+ doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); -+ doc200x_hwcontrol(mtd, NAND_CTL_SETALE); -+ this->write_byte(mtd, 0); -+ doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); -+ -+ ret = this->read_byte(mtd) << 8; -+ ret |= this->read_byte(mtd); -+ -+ if (doc->ChipID == DOC_ChipID_Doc2k && try_dword && !nr) { -+ /* First chip probe. See if we get same results by 32-bit access */ -+ union { -+ uint32_t dword; -+ uint8_t byte[4]; -+ } ident; -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ -+ doc200x_hwcontrol(mtd, NAND_CTL_SETCLE); -+ doc2000_write_byte(mtd, NAND_CMD_READID); -+ doc200x_hwcontrol(mtd, NAND_CTL_CLRCLE); -+ doc200x_hwcontrol(mtd, NAND_CTL_SETALE); -+ doc2000_write_byte(mtd, 0); -+ doc200x_hwcontrol(mtd, NAND_CTL_CLRALE); -+ -+ ident.dword = readl(docptr + DoC_2k_CDSN_IO); -+ if (((ident.byte[0] << 8) | ident.byte[1]) == ret) { -+ printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n"); -+ this->read_buf = &doc2000_readbuf_dword; -+ } -+ } -+ -+ return ret; -+} -+ -+static void doc2000_count_chips(struct mtd_info *mtd) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ uint16_t mfrid; -+ int i; -+ -+ /* Max 4 chips per floor on DiskOnChip 2000 */ -+ doc->chips_per_floor = 4; -+ -+ /* Find out what the first chip is */ -+ mfrid = doc200x_ident_chip(mtd, 0); -+ -+ /* Find how many chips in each floor. */ -+ for (i = 1; i < 4; i++) { -+ if (doc200x_ident_chip(mtd, i) != mfrid) -+ break; -+ } -+ doc->chips_per_floor = i; -+} -+ -+static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) -+{ -+ struct doc_priv *doc = (void *)this->priv; -+ -+ int status; -+ -+ DoC_WaitReady(doc); -+ this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); -+ DoC_WaitReady(doc); -+ status = (int)this->read_byte(mtd); -+ -+ return status; -+} -+ -+static void doc2001_write_byte(struct mtd_info *mtd, u_char datum) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ -+ WriteDOC(datum, docptr, CDSNSlowIO); -+ WriteDOC(datum, docptr, Mil_CDSN_IO); -+ WriteDOC(datum, docptr, WritePipeTerm); -+} -+ -+static u_char doc2001_read_byte(struct mtd_info *mtd) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ -+ ReadDOC(docptr, CDSNSlowIO); -+ /* 11.4.5 -- delay twice to allow extended length cycle */ -+ DoC_Delay(doc, 2); -+ ReadDOC(docptr, ReadPipeInit); -+ return ReadDOC(docptr, Mil_CDSN_IO); -+} -+ -+static void doc2001_writebuf(struct mtd_info *mtd, -+ const u_char *buf, int len) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ int i; -+ -+ for (i=0; i < len; i++) -+ WriteDOC_(buf[i], docptr, DoC_Mil_CDSN_IO + i); -+ /* Terminate write pipeline */ -+ WriteDOC(0x00, docptr, WritePipeTerm); -+} -+ -+static void doc2001_readbuf(struct mtd_info *mtd, -+ u_char *buf, int len) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ int i; -+ -+ /* Start read pipeline */ -+ ReadDOC(docptr, ReadPipeInit); -+ -+ for (i=0; i < len-1; i++) -+ buf[i] = ReadDOC(docptr, Mil_CDSN_IO); -+ -+ /* Terminate read pipeline */ -+ buf[i] = ReadDOC(docptr, LastDataRead); -+} -+static int doc2001_verifybuf(struct mtd_info *mtd, -+ const u_char *buf, int len) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ int i; -+ -+ /* Start read pipeline */ -+ ReadDOC(docptr, ReadPipeInit); -+ -+ for (i=0; i < len-1; i++) -+ if (buf[i] != ReadDOC(docptr, Mil_CDSN_IO)) { -+ ReadDOC(docptr, LastDataRead); -+ return i; -+ } -+ if (buf[i] != ReadDOC(docptr, LastDataRead)) -+ return i; -+ return 0; -+} -+ -+static void doc200x_select_chip(struct mtd_info *mtd, int chip) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ int floor = 0; -+ -+ /* 11.4.4 -- deassert CE before changing chip */ -+ doc200x_hwcontrol(mtd, NAND_CTL_CLRNCE); -+ -+ if(debug)printk("select chip (%d)\n", chip); -+ -+ if (chip == -1) -+ return; -+ -+ floor = chip / doc->chips_per_floor; -+ chip -= (floor * doc->chips_per_floor); -+ -+ WriteDOC(floor, docptr, FloorSelect); -+ WriteDOC(chip, docptr, CDSNDeviceSelect); -+ -+ doc200x_hwcontrol(mtd, NAND_CTL_SETNCE); -+ -+ doc->curchip = chip; -+ doc->curfloor = floor; -+} -+ -+static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ -+ switch(cmd) { -+ case NAND_CTL_SETNCE: -+ doc->CDSNControl |= CDSN_CTRL_CE; -+ break; -+ case NAND_CTL_CLRNCE: -+ doc->CDSNControl &= ~CDSN_CTRL_CE; -+ break; -+ case NAND_CTL_SETCLE: -+ doc->CDSNControl |= CDSN_CTRL_CLE; -+ break; -+ case NAND_CTL_CLRCLE: -+ doc->CDSNControl &= ~CDSN_CTRL_CLE; -+ break; -+ case NAND_CTL_SETALE: -+ doc->CDSNControl |= CDSN_CTRL_ALE; -+ break; -+ case NAND_CTL_CLRALE: -+ doc->CDSNControl &= ~CDSN_CTRL_ALE; -+ break; -+ case NAND_CTL_SETWP: -+ doc->CDSNControl |= CDSN_CTRL_WP; -+ break; -+ case NAND_CTL_CLRWP: -+ doc->CDSNControl &= ~CDSN_CTRL_WP; -+ break; -+ } -+ if (debug)printk("hwcontrol(%d): %02x\n", cmd, doc->CDSNControl); -+ WriteDOC(doc->CDSNControl, docptr, CDSNControl); -+ /* 11.4.3 -- 4 NOPs after CSDNControl write */ -+ DoC_Delay(doc, 4); -+} -+ -+static int doc200x_dev_ready(struct mtd_info *mtd) -+{ -+ struct nand_chip *this = mtd->priv; -+ struct doc_priv *doc = (void *)this->priv; -+ unsigned long docptr = doc->virtadr; -+ -+ /* 11.4.2 -- must NOP four times before checking FR/B# */ -+ DoC_Delay(doc, 4); -+ if (!(ReadDOC(docptr, CDSNControl) & CDSN_CTRL_FR_B)) { -+ if(debug) -+ printk("not ready\n"); -+ return 0; -+ } -+ /* 11.4.2 -- Must NOP twice if it's ready */ -+ DoC_Delay(doc, 2); -+ if (debug)printk("was ready\n"); -+ return 1; -+} -+ -+static int doc200x_block_bad(struct mtd_info *mtd, unsigned long block) -+{ -+ /* FIXME: Look it up in the BBT */ -+ return 0; -+} -+ -+struct doc_priv mydoc = { -+ .physadr = 0xd4000, -+ .curfloor = -1, -+ .curchip = -1, -+}; -+ -+u_char mydatabuf[528]; -+ -+struct nand_chip mynand = { -+ .priv = (void *)&mydoc, -+ .select_chip = doc200x_select_chip, -+ .hwcontrol = doc200x_hwcontrol, -+ .dev_ready = doc200x_dev_ready, -+ .waitfunc = doc200x_wait, -+ .block_bad = doc200x_block_bad, -+ .eccmode = NAND_ECC_SOFT, -+ .data_buf = mydatabuf, -+}; -+ -+struct mtd_info mymtd = { -+ .priv = (void *)&mynand, -+ .owner = THIS_MODULE, -+}; -+ -+int __init init_nanddoc(void) -+{ -+ mydoc.virtadr = (unsigned long)ioremap(mydoc.physadr, DOC_IOREMAP_LEN); -+ int nrchips = 1; -+ char *name; -+ -+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, -+ mydoc.virtadr, DOCControl); -+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_RESET, -+ mydoc.virtadr, DOCControl); -+ -+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, -+ mydoc.virtadr, DOCControl); -+ WriteDOC(DOC_MODE_CLR_ERR | DOC_MODE_MDWREN | DOC_MODE_NORMAL, -+ mydoc.virtadr, DOCControl); -+ -+ mydoc.ChipID = ReadDOC(mydoc.virtadr, ChipID); -+ -+ switch(mydoc.ChipID) { -+ case DOC_ChipID_DocMil: -+ mynand.write_byte = doc2001_write_byte; -+ mynand.read_byte = doc2001_read_byte; -+ mynand.write_buf = doc2001_writebuf; -+ mynand.read_buf = doc2001_readbuf; -+ mynand.verify_buf = doc2001_verifybuf; -+ -+ ReadDOC(mydoc.virtadr, ChipID); -+ ReadDOC(mydoc.virtadr, ChipID); -+ if (ReadDOC(mydoc.virtadr, ChipID) != DOC_ChipID_DocMil) { -+ /* It's not a Millennium; it's one of the newer -+ DiskOnChip 2000 units with a similar ASIC. -+ Treat it like a Millennium, except that it -+ can have multiple chips. */ -+ doc2000_count_chips(&mymtd); -+ nrchips = 4 * mydoc.chips_per_floor; -+ name = "DiskOnChip 2000 (INFTL Model)"; -+ } else { -+ /* Bog-standard Millennium */ -+ mydoc.chips_per_floor = 1; -+ nrchips = 1; -+ name = "DiskOnChip Millennium"; -+ } -+ break; -+ -+ case DOC_ChipID_Doc2k: -+ mynand.write_byte = doc2000_write_byte; -+ mynand.read_byte = doc2000_read_byte; -+ mynand.write_buf = doc2000_writebuf; -+ mynand.read_buf = doc2000_readbuf; -+ mynand.verify_buf = doc2000_verifybuf; -+ -+ doc2000_count_chips(&mymtd); -+ nrchips = 4 * mydoc.chips_per_floor; -+ name = "DiskOnChip 2000 (NFTL Model)"; -+ mydoc.CDSNControl |= CDSN_CTRL_FLASH_IO; -+ -+ break; -+ -+ default: -+ return -EIO; -+ } -+ if (nand_scan(&mymtd, nrchips)) { -+ iounmap((void *)mydoc.virtadr); -+ return -EIO; -+ } -+ mymtd.name = name; -+ add_mtd_device(&mymtd); -+ -+ return 0; -+} -+ -+void __exit cleanup_nanddoc(void) -+{ -+ del_mtd_device(&mymtd); -+ iounmap((void *)mydoc.virtadr); -+} -+ -+module_init(init_nanddoc); -+module_exit(cleanup_nanddoc); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); -+MODULE_DESCRIPTION("M-Systems DiskOnChip 2000 and Millennium device driver\n"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/edb7312.c linux/drivers/mtd/nand/edb7312.c ---- linux-mips-2.4.27/drivers/mtd/nand/edb7312.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/nand/edb7312.c 2004-11-19 10:25:11.997184896 +0100 -@@ -6,7 +6,7 @@ - * Derived from drivers/mtd/nand/autcpu12.c - * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -20,6 +20,7 @@ - - #include <linux/slab.h> - #include <linux/module.h> -+#include <linux/init.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/nand.h> - #include <linux/mtd/partitions.h> -@@ -77,16 +78,13 @@ - }; - #define NUM_PARTITIONS 1 - --extern int parse_cmdline_partitions(struct mtd_info *master, -- struct mtd_partition **pparts, -- const char *mtd_id); - #endif - - - /* - * hardware specific access to control-lines - */ --static void ep7312_hwcontrol(int cmd) -+static void ep7312_hwcontrol(struct mtd_info *mtd, int cmd) - { - switch(cmd) { - -@@ -116,10 +114,13 @@ - /* - * read device ready pin - */ --static int ep7312_device_ready(void) -+static int ep7312_device_ready(struct mtd_info *mtd) - { - return 1; - } -+#ifdef CONFIG_MTD_PARTITIONS -+const char *part_probes[] = { "cmdlinepart", NULL }; -+#endif - - /* - * Main initialization routine -@@ -174,7 +175,7 @@ - this->chip_delay = 15; - - /* Scan to find existence of the device */ -- if (nand_scan (ep7312_mtd)) { -+ if (nand_scan (ep7312_mtd, 1)) { - iounmap((void *)ep7312_fio_base); - kfree (ep7312_mtd); - return -ENXIO; -@@ -189,27 +190,16 @@ - return -ENOMEM; - } - -- /* Allocate memory for internal data buffer */ -- this->data_cache = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL); -- if (!this->data_cache) { -- printk("Unable to allocate NAND data cache for EDB7312.\n"); -- kfree (this->data_buf); -- iounmap((void *)ep7312_fio_base); -- kfree (ep7312_mtd); -- return -ENOMEM; -- } -- this->cache_page = -1; -- --#ifdef CONFIG_MTD_CMDLINE_PARTS -- mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts, -- "edb7312-nand"); -+#ifdef CONFIG_PARTITIONS -+ ep7312_mtd->name = "edb7312-nand"; -+ mtd_parts_nb = parse_mtd_partitions(ep7312_mtd, part_probes, -+ &mtd_parts, 0); - if (mtd_parts_nb > 0) - part_type = "command line"; - else - mtd_parts_nb = 0; - #endif -- if (mtd_parts_nb == 0) -- { -+ if (mtd_parts_nb == 0) { - mtd_parts = partition_info; - mtd_parts_nb = NUM_PARTITIONS; - part_type = "static"; -@@ -236,7 +226,6 @@ - - /* Free internal data buffer */ - kfree (this->data_buf); -- kfree (this->data_cache); - - /* Free the MTD device structure */ - kfree (ep7312_mtd); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/nand.c linux/drivers/mtd/nand/nand.c ---- linux-mips-2.4.27/drivers/mtd/nand/nand.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/nand/nand.c 2004-11-19 10:25:12.010182920 +0100 -@@ -8,7 +8,7 @@ - * Additional technical information is available on - * http://www.linux-mtd.infradead.org/tech/nand.html - * -- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) -+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * 2002 Thomas Gleixner (tglx@linutronix.de) - * - * 10-29-2001 Thomas Gleixner (tglx@linutronix.de) -@@ -112,10 +112,27 @@ - * for mtd->read_ecc / mtd->write_ecc - * some minor cleanups - * -- * 12-05-2000 tglx: Dave Ellis (DGE@sixnetio) provided the fix for -+ * 12-05-2002 tglx: Dave Ellis (DGE@sixnetio) provided the fix for - * WRITE_VERIFY long time ago. Thanks for remembering me. - * -- * $Id$ -+ * 02-14-2003 tglx: Reject non page aligned writes -+ * Fixed ecc select in nand_write_page to match semantics. -+ * -+ * 02-18-2003 tglx: Changed oobsel to pointer. Added a default oob-selector -+ * -+ * 02-18-2003 tglx: Implemented oobsel again. Now it uses a pointer to -+ + a structure, which will be supplied by a filesystem driver -+ * If NULL is given, then the defaults (none or defaults -+ * supplied by ioctl (MEMSETOOBSEL) are used. -+ * For partitions the partition defaults are used (mtdpart.c) -+ * -+ * 06-04-2003 tglx: fix compile errors and fix write verify problem for -+ * some chips, which need either a delay between the readback -+ * and the next write command or have the CE removed. The -+ * CE disable/enable is much faster than a 20us delay and -+ * it should work on all available chips. -+ * -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -130,102 +147,151 @@ - #include <linux/mtd/mtd.h> - #include <linux/mtd/nand.h> - #include <linux/mtd/nand_ecc.h> -+#include <linux/mtd/compatmac.h> - #include <linux/interrupt.h> - #include <asm/io.h> - - /* -- * Macros for low-level register control -- */ --#define nand_select() this->hwcontrol(NAND_CTL_SETNCE); -- --#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE); -- --/* -- * out of band configuration for different filesystems -- */ --static int oobconfigs[][6] = { -- { 0,0,0,0,0,0}, -- -- { NAND_JFFS2_OOB_ECCPOS0, NAND_JFFS2_OOB_ECCPOS1, NAND_JFFS2_OOB_ECCPOS2, -- NAND_JFFS2_OOB_ECCPOS3, NAND_JFFS2_OOB_ECCPOS4, NAND_JFFS2_OOB_ECCPOS5 }, -- -- { NAND_YAFFS_OOB_ECCPOS0, NAND_YAFFS_OOB_ECCPOS1, NAND_YAFFS_OOB_ECCPOS2, -- NAND_YAFFS_OOB_ECCPOS3, NAND_YAFFS_OOB_ECCPOS4, NAND_YAFFS_OOB_ECCPOS5 } --}; -- --/* - * NAND low-level MTD interface functions - */ -+static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len); -+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len); -+static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len); -+ - static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); - static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, -- size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel); -+ size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); - static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); - static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf); - static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, -- size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel); -+ size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); - static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf); - static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t * retlen); - static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, -- unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, int oobsel); -+ unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); - static int nand_erase (struct mtd_info *mtd, struct erase_info *instr); - static void nand_sync (struct mtd_info *mtd); --static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, int col, -- int last, u_char *oob_buf, int oobsel); -+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel); -+ -+static u_char nand_read_byte(struct mtd_info *mtd) -+{ -+ struct nand_chip *this = mtd->priv; -+ return readb(this->IO_ADDR_R); -+} -+ -+static void nand_write_byte(struct mtd_info *mtd, u_char byte) -+{ -+ struct nand_chip *this = mtd->priv; -+ writeb(byte, this->IO_ADDR_W); -+} -+ -+static void nand_select_chip(struct mtd_info *mtd, int chip) -+{ -+ struct nand_chip *this = mtd->priv; -+ switch(chip) { -+ case -1: -+ this->hwcontrol(mtd, NAND_CTL_CLRNCE); -+ break; -+ case 0: -+ this->hwcontrol(mtd, NAND_CTL_SETNCE); -+ break; -+ -+ default: -+ BUG(); -+ } -+} -+ -+static void nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ writeb(buf[i], this->IO_ADDR_W); -+} -+ -+static void nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ buf[i] = readb(this->IO_ADDR_R); -+} -+ -+static int nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ if (buf[i] != readb(this->IO_ADDR_R)) -+ return i; -+ -+ return 0; -+} -+ -+/* Appropriate chip should already be selected */ -+static int nand_block_bad(struct mtd_info *mtd, unsigned long page) -+{ -+ struct nand_chip *this = mtd->priv; -+ -+ this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page); -+ if (this->read_byte(mtd) != 0xff) -+ return 1; -+ -+ return 0; -+} -+ - /* - * Send command to NAND device - */ - static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) - { - register struct nand_chip *this = mtd->priv; -- register unsigned long NAND_IO_ADDR = this->IO_ADDR_W; - - /* Begin command latch cycle */ -- this->hwcontrol (NAND_CTL_SETCLE); -+ this->hwcontrol(mtd, NAND_CTL_SETCLE); - /* - * Write out the command to the device. - */ -- if (command != NAND_CMD_SEQIN) -- writeb (command, NAND_IO_ADDR); -- else { -- if (mtd->oobblock == 256 && column >= 256) { -- column -= 256; -- writeb (NAND_CMD_READOOB, NAND_IO_ADDR); -- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); -- } else if (mtd->oobblock == 512 && column >= 256) { -- if (column < 512) { -- column -= 256; -- writeb (NAND_CMD_READ1, NAND_IO_ADDR); -- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); -- } else { -- column -= 512; -- writeb (NAND_CMD_READOOB, NAND_IO_ADDR); -- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); -- } -+ if (command == NAND_CMD_SEQIN) { -+ int readcmd; -+ -+ if (column >= mtd->oobblock) { -+ /* OOB area */ -+ column -= mtd->oobblock; -+ readcmd = NAND_CMD_READOOB; -+ } else if (column < 256) { -+ /* First 256 bytes --> READ0 */ -+ readcmd = NAND_CMD_READ0; - } else { -- writeb (NAND_CMD_READ0, NAND_IO_ADDR); -- writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); -+ column -= 256; -+ readcmd = NAND_CMD_READ1; - } -+ this->write_byte(mtd, readcmd); - } -+ this->write_byte(mtd, command); - - /* Set ALE and clear CLE to start address cycle */ -- this->hwcontrol (NAND_CTL_CLRCLE); -+ this->hwcontrol(mtd, NAND_CTL_CLRCLE); - - if (column != -1 || page_addr != -1) { -- this->hwcontrol (NAND_CTL_SETALE); -+ this->hwcontrol(mtd, NAND_CTL_SETALE); - - /* Serially input address */ - if (column != -1) -- writeb (column, NAND_IO_ADDR); -+ this->write_byte(mtd, column); - if (page_addr != -1) { -- writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR); -- writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR); -+ this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); -+ this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); - /* One more address cycle for higher density devices */ - if (mtd->size & 0x0c000000) -- writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR); -+ this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); - } - /* Latch in address */ -- this->hwcontrol (NAND_CTL_CLRALE); -+ this->hwcontrol(mtd, NAND_CTL_CLRALE); - } - - /* -@@ -244,10 +310,11 @@ - case NAND_CMD_RESET: - if (this->dev_ready) - break; -- this->hwcontrol (NAND_CTL_SETCLE); -- writeb (NAND_CMD_STATUS, NAND_IO_ADDR); -- this->hwcontrol (NAND_CTL_CLRCLE); -- while ( !(readb (this->IO_ADDR_R) & 0x40)); -+ udelay(this->chip_delay); -+ this->hwcontrol(mtd, NAND_CTL_SETCLE); -+ this->write_byte(mtd, NAND_CMD_STATUS); -+ this->hwcontrol(mtd, NAND_CTL_CLRCLE); -+ while ( !(this->read_byte(mtd) & 0x40)); - return; - - /* This applies to read commands */ -@@ -263,7 +330,7 @@ - } - - /* wait until command is processed */ -- while (!this->dev_ready()); -+ while (!this->dev_ready(mtd)); - } - - /* -@@ -288,17 +355,17 @@ - spin_unlock_bh (&this->chip_lock); - return; - } -- -+#if 0 /* This was broken. And of dubious utility */ - if (this->state == FL_ERASING) { - if (new_state != FL_ERASING) { - this->state = new_state; - spin_unlock_bh (&this->chip_lock); -- nand_select (); /* select in any case */ -+ this->select_chip(mtd, 0); /* select in any case */ - this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - return; - } - } -- -+#endif - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); -@@ -334,17 +401,17 @@ - return 0; - } - if (this->dev_ready) { -- if (this->dev_ready ()) -+ if (this->dev_ready(mtd)) - break; - } -- if (readb (this->IO_ADDR_R) & 0x40) -+ if (this->read_byte(mtd) & 0x40) - break; - - spin_unlock_bh (&this->chip_lock); - yield (); - spin_lock_bh (&this->chip_lock); - } -- status = (int) readb (this->IO_ADDR_R); -+ status = (int) this->read_byte(mtd); - spin_unlock_bh (&this->chip_lock); - - return status; -@@ -352,14 +419,15 @@ - - /* - * Nand_page_program function is used for write and writev ! -+ * This function will always program a full page of data -+ * If you call it with a non page aligned buffer, you're lost :) - */ --static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, -- int page, int col, int last, u_char *oob_buf, int oobsel) -+static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel) - { - int i, status; - u_char ecc_code[6], *oob_data; -- int eccmode = oobsel ? this->eccmode : NAND_ECC_NONE; -- int *oob_config = oobconfigs[oobsel]; -+ int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; -+ int *oob_config = oobsel->eccpos; - - /* pad oob area, if we have no oob buffer from fs-driver */ - if (!oob_buf) { -@@ -369,66 +437,42 @@ - } else - oob_data = oob_buf; - -- /* software ecc 3 Bytes ECC / 256 Byte Data ? */ -- if (eccmode == NAND_ECC_SOFT) { -- /* Read back previous written data, if col > 0 */ -- if (col) { -- this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); -- for (i = 0; i < col; i++) -- this->data_poi[i] = readb (this->IO_ADDR_R); -- } -- if ((col < this->eccsize) && (last >= this->eccsize)) { -- this->calculate_ecc (&this->data_poi[0], &(ecc_code[0])); -- for (i = 0; i < 3; i++) -- oob_data[oob_config[i]] = ecc_code[i]; -- } -- /* Calculate and write the second ECC if we have enough data */ -- if ((mtd->oobblock == 512) && (last == 512)) { -- this->calculate_ecc (&this->data_poi[256], &(ecc_code[3])); -- for (i = 3; i < 6; i++) -- oob_data[oob_config[i]] = ecc_code[i]; -- } -- } else { -- /* For hardware ECC skip ECC, if we have no full page write */ -- if (eccmode != NAND_ECC_NONE && (col || last != mtd->oobblock)) -- eccmode = NAND_ECC_NONE; -- } -- -- /* Prepad for partial page programming !!! */ -- for (i = 0; i < col; i++) -- this->data_poi[i] = 0xff; -- -- /* Postpad for partial page programming !!! oob is already padded */ -- for (i = last; i < mtd->oobblock; i++) -- this->data_poi[i] = 0xff; -- - /* Send command to begin auto page programming */ - this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); - - /* Write out complete page of data, take care of eccmode */ -- switch (this->eccmode) { -+ switch (eccmode) { - /* No ecc and software ecc 3/256, write all */ - case NAND_ECC_NONE: -+ printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); -+ this->write_buf(mtd, this->data_poi, mtd->oobblock); -+ break; - case NAND_ECC_SOFT: -- for (i = 0; i < mtd->oobblock; i++) -- writeb ( this->data_poi[i] , this->IO_ADDR_W); -+ this->calculate_ecc(mtd, &this->data_poi[0], &(ecc_code[0])); -+ for (i = 0; i < 3; i++) -+ oob_data[oob_config[i]] = ecc_code[i]; -+ /* Calculate and write the second ECC for 512 Byte page size */ -+ if (mtd->oobblock == 512) { -+ this->calculate_ecc(mtd, &this->data_poi[256], &(ecc_code[3])); -+ for (i = 3; i < 6; i++) -+ oob_data[oob_config[i]] = ecc_code[i]; -+ } -+ this->write_buf(mtd, this->data_poi, mtd->oobblock); - break; - - /* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */ - case NAND_ECC_HW3_256: -- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write */ -- for (i = 0; i < mtd->eccsize; i++) -- writeb ( this->data_poi[i] , this->IO_ADDR_W); -+ this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write */ -+ this->write_buf(mtd, this->data_poi, mtd->eccsize); - -- this->calculate_ecc (NULL, &(ecc_code[0])); -+ this->calculate_ecc(mtd, NULL, &(ecc_code[0])); - for (i = 0; i < 3; i++) - oob_data[oob_config[i]] = ecc_code[i]; - - if (mtd->oobblock == 512) { -- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write*/ -- for (i = mtd->eccsize; i < mtd->oobblock; i++) -- writeb ( this->data_poi[i] , this->IO_ADDR_W); -- this->calculate_ecc (NULL, &(ecc_code[3])); -+ this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write*/ -+ this->write_buf(mtd, &this->data_poi[mtd->eccsize], mtd->oobblock - mtd->eccsize); -+ this->calculate_ecc(mtd, NULL, &(ecc_code[3])); - for (i = 3; i < 6; i++) - oob_data[oob_config[i]] = ecc_code[i]; - } -@@ -436,20 +480,18 @@ - - /* Hardware ecc 3 byte / 512 byte data, write full page */ - case NAND_ECC_HW3_512: -- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */ -- for (i = 0; i < mtd->oobblock; i++) -- writeb ( this->data_poi[i] , this->IO_ADDR_W); -- this->calculate_ecc (NULL, &(ecc_code[0])); -+ this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic */ -+ this->write_buf(mtd, this->data_poi, mtd->oobblock); -+ this->calculate_ecc(mtd, NULL, &(ecc_code[0])); - for (i = 0; i < 3; i++) - oob_data[oob_config[i]] = ecc_code[i]; - break; - - /* Hardware ecc 6 byte / 512 byte data, write full page */ - case NAND_ECC_HW6_512: -- this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */ -- for (i = 0; i < mtd->oobblock; i++) -- writeb ( this->data_poi[i] , this->IO_ADDR_W); -- this->calculate_ecc (NULL, &(ecc_code[0])); -+ this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic */ -+ this->write_buf(mtd, this->data_poi, mtd->oobblock); -+ this->calculate_ecc(mtd, NULL, &(ecc_code[0])); - for (i = 0; i < 6; i++) - oob_data[oob_config[i]] = ecc_code[i]; - break; -@@ -460,8 +502,7 @@ - } - - /* Write out OOB data */ -- for (i = 0; i < mtd->oobsize; i++) -- writeb ( oob_data[i] , this->IO_ADDR_W); -+ this->write_buf(mtd, oob_data, mtd->oobsize); - - /* Send command to actually program the data */ - this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); -@@ -490,25 +531,21 @@ - */ - - /* Send command to read back the page */ -- this->cmdfunc (mtd, NAND_CMD_READ0, col, page); -+ this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); - /* Loop through and verify the data */ -- for (i = col; i < last; i++) { -- if (this->data_poi[i] != readb (this->IO_ADDR_R)) { -+ if (this->verify_buf(mtd, this->data_poi, mtd->oobblock)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); - return -EIO; - } -- } - - /* check, if we have a fs-supplied oob-buffer */ - if (oob_buf) { -- for (i = 0; i < mtd->oobsize; i++) { -- if (oob_data[i] != readb (this->IO_ADDR_R)) { -+ if (this->verify_buf(mtd, oob_data, mtd->oobsize)) { - DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); - return -EIO; - } -- } - } else { -- if (eccmode != NAND_ECC_NONE && !col && last == mtd->oobblock) { -+ if (eccmode != NAND_ECC_NONE) { - int ecc_bytes = 0; - - switch (this->eccmode) { -@@ -518,8 +555,7 @@ - case NAND_ECC_HW6_512: ecc_bytes = 6; break; - } - -- for (i = 0; i < mtd->oobsize; i++) -- oob_data[i] = readb (this->IO_ADDR_R); -+ this->read_buf(mtd, oob_data, mtd->oobsize); - - for (i = 0; i < ecc_bytes; i++) { - if (oob_data[oob_config[i]] != ecc_code[i]) { -@@ -531,6 +567,13 @@ - } - } - } -+ /* -+ * Terminate the read command. This is faster than sending a reset command or -+ * applying a 20us delay before issuing the next programm sequence. -+ * This is not a problem for all chips, but I have found a bunch of them. -+ */ -+ this->select_chip(mtd, -1); -+ this->select_chip(mtd, 0); - #endif - return 0; - } -@@ -540,7 +583,7 @@ - */ - static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) - { -- return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, 0)); -+ return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); - } - - -@@ -548,7 +591,7 @@ - * NAND read with ECC - */ - static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, -- size_t * retlen, u_char * buf, u_char * oob_buf, int oobsel) -+ size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) - { - int j, col, page, end, ecc; - int erase_state = 0; -@@ -557,9 +600,15 @@ - u_char *data_poi, *oob_data = oob_buf; - u_char ecc_calc[6]; - u_char ecc_code[6]; -- int eccmode = oobsel ? this->eccmode : NAND_ECC_NONE; -+ int eccmode; -+ int *oob_config; -+ -+ // use chip default if zero -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; - -- int *oob_config = oobconfigs[oobsel]; -+ eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; -+ oob_config = oobsel->eccpos; - - DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); - -@@ -574,7 +623,7 @@ - nand_get_chip (this, mtd ,FL_READING, &erase_state); - - /* Select the NAND device */ -- nand_select (); -+ this->select_chip(mtd, 0); - - /* First we calculate the starting page */ - page = from >> this->page_shift; -@@ -596,7 +645,7 @@ - if (!this->dev_ready) - udelay (this->chip_delay); - else -- while (!this->dev_ready()); -+ while (!this->dev_ready(mtd)); - } - - /* -@@ -616,39 +665,40 @@ - - j = 0; - switch (eccmode) { -- case NAND_ECC_NONE: /* No ECC, Read in a page */ -- while (j < end) -- data_poi[j++] = readb (this->IO_ADDR_R); -+ case NAND_ECC_NONE: { /* No ECC, Read in a page */ -+ static unsigned long lastwhinge = 0; -+ if ((lastwhinge / HZ) != (jiffies / HZ)) { -+ printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n"); -+ lastwhinge = jiffies; -+ } -+ this->read_buf(mtd, data_poi, end); - break; -+ } - - case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ -- while (j < end) -- data_poi[j++] = readb (this->IO_ADDR_R); -- this->calculate_ecc (&data_poi[0], &ecc_calc[0]); -+ this->read_buf(mtd, data_poi, end); -+ this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); - if (mtd->oobblock == 512) -- this->calculate_ecc (&data_poi[256], &ecc_calc[3]); -+ this->calculate_ecc(mtd, &data_poi[256], &ecc_calc[3]); - break; - - case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */ -- this->enable_hwecc (NAND_ECC_READ); -- while (j < ecc) -- data_poi[j++] = readb (this->IO_ADDR_R); -- this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */ -+ this->enable_hwecc(mtd, NAND_ECC_READ); -+ this->read_buf(mtd, data_poi, ecc); -+ this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); /* read from hardware */ - - if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */ -- this->enable_hwecc (NAND_ECC_READ); -- while (j < end) -- data_poi[j++] = readb (this->IO_ADDR_R); -- this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */ -+ this->enable_hwecc(mtd, NAND_ECC_READ); -+ this->read_buf(mtd, &data_poi[ecc], end-ecc); -+ this->calculate_ecc(mtd, &data_poi[256], &ecc_calc[3]); /* read from hardware */ - } - break; - - case NAND_ECC_HW3_512: - case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page */ -- this->enable_hwecc (NAND_ECC_READ); -- while (j < end) -- data_poi[j++] = readb (this->IO_ADDR_R); -- this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */ -+ this->enable_hwecc(mtd, NAND_ECC_READ); -+ this->read_buf(mtd, data_poi, end); -+ this->calculate_ecc(mtd, &data_poi[0], &ecc_calc[0]); /* read from hardware */ - break; - - default: -@@ -658,7 +708,7 @@ - - /* read oobdata */ - for (j = 0; j < mtd->oobsize; j++) -- oob_data[oob + j] = readb (this->IO_ADDR_R); -+ oob_data[oob + j] = this->read_byte(mtd); - - /* Skip ECC, if not active */ - if (eccmode == NAND_ECC_NONE) -@@ -669,7 +719,7 @@ - ecc_code[j] = oob_data[oob + oob_config[j]]; - - /* correct data, if neccecary */ -- ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]); -+ ecc_status = this->correct_data(mtd, &data_poi[0], &ecc_code[0], &ecc_calc[0]); - /* check, if we have a fs supplied oob-buffer */ - if (oob_buf) { - oob += mtd->oobsize; -@@ -682,7 +732,7 @@ - } - - if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) { -- ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]); -+ ecc_status = this->correct_data(mtd, &data_poi[256], &ecc_code[3], &ecc_calc[3]); - if (oob_buf) { - *((int *)&oob_data[oob]) = ecc_status; - oob += sizeof(int); -@@ -705,7 +755,7 @@ - } - - /* De-select the NAND device */ -- nand_deselect (); -+ this->select_chip(mtd, -1); - - /* Wake up anyone waiting on the device */ - spin_lock_bh (&this->chip_lock); -@@ -753,7 +803,7 @@ - nand_get_chip (this, mtd , FL_READING, &erase_state); - - /* Select the NAND device */ -- nand_select (); -+ this->select_chip(mtd, 0); - - /* Send the read command */ - this->cmdfunc (mtd, NAND_CMD_READOOB, col, page); -@@ -761,13 +811,20 @@ - * Read the data, if we read more than one page - * oob data, let the device transfer the data ! - */ -- for (i = 0; i < len; i++) { -- buf[i] = readb (this->IO_ADDR_R); -- if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1)) -+ i = 0; -+ while (i < len) { -+ int thislen = (mtd->oobsize - col) & (mtd->oobsize - 1); -+ if (!thislen) -+ thislen = mtd->oobsize; -+ thislen = min_t(int, thislen, len); -+ this->read_buf(mtd, &buf[i], thislen); -+ i += thislen; -+ col += thislen; -+ /* Delay between pages */ - udelay (this->chip_delay); - } - /* De-select the NAND device */ -- nand_deselect (); -+ this->select_chip(mtd, -1); - - /* Wake up anyone waiting on the device */ - spin_lock_bh (&this->chip_lock); -@@ -780,45 +837,54 @@ - return 0; - } - -+#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0 -+ - /* - * Use NAND write ECC - */ - static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) - { -- return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, 0)); -+ return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); - } - /* - * NAND write with ECC - */ - static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, -- size_t * retlen, const u_char * buf, u_char * eccbuf, int oobsel) -+ size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel) - { -- int i, page, col, cnt, ret = 0, oob = 0, written = 0; -+ int page, ret = 0, oob = 0, written = 0; - struct nand_chip *this = mtd->priv; - - DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); - - /* Do not allow write past end of device */ - if ((to + len) > mtd->size) { -- DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); -+ DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); -+ return -EINVAL; -+ } -+ -+ /* reject writes, which are not page aligned */ -+ if (NOTALIGNED (to) || NOTALIGNED(len)) { -+ printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); - return -EINVAL; - } - -+ // if oobsel is NULL, use chip defaults -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; -+ - /* Shift to get page */ - page = ((int) to) >> this->page_shift; - -- /* Get the starting column */ -- col = to & (mtd->oobblock - 1); -- - /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd, FL_WRITING, NULL); - - /* Select the NAND device */ -- nand_select (); -+ this->select_chip(mtd, 0); - - /* Check the WP bit */ - this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); -- if (!(readb (this->IO_ADDR_R) & 0x80)) { -+ if (!(this->read_byte(mtd) & 0x80)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n"); - ret = -EIO; - goto out; -@@ -826,42 +892,27 @@ - - /* Loop until all data is written */ - while (written < len) { -- /* -- * Check, if we have a full page write, then we can -- * use the given buffer, else we have to copy -- */ -- if (!col && (len - written) >= mtd->oobblock) { -+ int cnt = mtd->oobblock; - this->data_poi = (u_char*) &buf[written]; -- cnt = mtd->oobblock; -- } else { -- cnt = 0; -- for (i = col; i < len && i < mtd->oobblock; i++) { -- this->data_buf[i] = buf[written + i]; -- cnt++; -- } -- this->data_poi = this->data_buf; -- } -- /* We use the same function for write and writev !) */ -+ /* We use the same function for write and writev */ - if (eccbuf) { -- ret = nand_write_page (mtd, this, page, col, cnt ,&eccbuf[oob], oobsel); -+ ret = nand_write_page (mtd, this, page, &eccbuf[oob], oobsel); - oob += mtd->oobsize; - } else -- ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel); -+ ret = nand_write_page (mtd, this, page, NULL, oobsel); - - if (ret) - goto out; - - /* Update written bytes count */ - written += cnt; -- /* Next write is aligned */ -- col = 0; - /* Increment page address */ - page++; - } - - out: - /* De-select the NAND device */ -- nand_deselect (); -+ this->select_chip(mtd, -1); - - /* Wake up anyone waiting on the device */ - spin_lock_bh (&this->chip_lock); -@@ -873,13 +924,21 @@ - return ret; - } - -+static u_char ffchars[] = { -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, -+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -+}; -+ - /* - * NAND write out-of-band - */ - static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) - { -- int i, column, page, status, ret = 0; -+ int column, page, status, ret = 0; - struct nand_chip *this = mtd->priv; -+#ifdef CONFIG_MTD_NAND_VERIFY_WRITE -+ int i; -+#endif - - DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); - -@@ -902,27 +961,31 @@ - nand_get_chip (this, mtd, FL_WRITING, NULL); - - /* Select the NAND device */ -- nand_select (); -+ this->select_chip(mtd, 0); -+ -+ /* Reset the chip. Some chips (like the Toshiba TC5832DC found -+ in one of my DiskOnChip 2000 test units) will clear the whole -+ data page too if we don't do this. I have no clue why, but -+ I seem to have 'fixed' it in the doc2000 driver in -+ August 1999. dwmw2. */ -+ this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); - - /* Check the WP bit */ - this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); -- if (!(readb (this->IO_ADDR_R) & 0x80)) { -+ if (!(this->read_byte(mtd) & 0x80)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n"); - ret = -EIO; - goto out; - } -- - /* Write out desired data */ - this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page); -+ - /* prepad 0xff for partial programming */ -- for (i = 0; i < column; i++) -- writeb (0xff, this->IO_ADDR_W); -+ this->write_buf(mtd, ffchars, column); - /* write data */ -- for (i = 0; i < len; i++) -- writeb (buf[i], this->IO_ADDR_W); -+ this->write_buf(mtd, buf, len); - /* postpad 0xff for partial programming */ -- for (i = len + column; i < mtd->oobsize; i++) -- writeb (0xff, this->IO_ADDR_W); -+ this->write_buf(mtd, ffchars, mtd->oobsize - (len+column)); - - /* Send command to program the OOB data */ - this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); -@@ -944,7 +1007,7 @@ - - /* Loop through and verify the data */ - for (i = 0; i < len; i++) { -- if (buf[i] != readb (this->IO_ADDR_R)) { -+ if (buf[i] != this->read_byte(mtd)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); - ret = -EIO; - goto out; -@@ -954,7 +1017,7 @@ - - out: - /* De-select the NAND device */ -- nand_deselect (); -+ this->select_chip(mtd, -1); - - /* Wake up anyone waiting on the device */ - spin_lock_bh (&this->chip_lock); -@@ -976,9 +1039,9 @@ - } - - static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, -- loff_t to, size_t * retlen, u_char *eccbuf, int oobsel) -+ loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) - { -- int i, page, col, cnt, len, total_len, ret = 0, written = 0; -+ int i, page, len, total_len, ret = 0, written = 0; - struct nand_chip *this = mtd->priv; - - /* Calculate total length of data */ -@@ -995,39 +1058,42 @@ - return -EINVAL; - } - -+ /* reject writes, which are not page aligned */ -+ if (NOTALIGNED (to) || NOTALIGNED(total_len)) { -+ printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); -+ return -EINVAL; -+ } -+ -+ // if oobsel is NULL, use chip defaults -+ if (oobsel == NULL) -+ oobsel = &mtd->oobinfo; -+ - /* Shift to get page */ - page = ((int) to) >> this->page_shift; - -- /* Get the starting column */ -- col = to & (mtd->oobblock - 1); -- - /* Grab the lock and see if the device is available */ - nand_get_chip (this, mtd, FL_WRITING, NULL); - - /* Select the NAND device */ -- nand_select (); -+ this->select_chip(mtd, 0); - - /* Check the WP bit */ - this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); -- if (!(readb (this->IO_ADDR_R) & 0x80)) { -+ if (!(this->read_byte(mtd) & 0x80)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n"); - ret = -EIO; - goto out; - } - - /* Loop until all iovecs' data has been written */ -- cnt = col; - len = 0; -- - while (count) { - /* -- * Check, if we write from offset 0 and if the tuple -- * gives us not enough data for a full page write. Then we -- * can use the iov direct, else we have to copy into -- * data_buf. -+ * Check, if the tuple gives us not enough data for a -+ * full page write. Then we can use the iov direct, -+ * else we have to copy into data_buf. - */ -- if (!cnt && (vecs->iov_len - len) >= mtd->oobblock) { -- cnt = mtd->oobblock; -+ if ((vecs->iov_len - len) >= mtd->oobblock) { - this->data_poi = (u_char *) vecs->iov_base; - this->data_poi += len; - len += mtd->oobblock; -@@ -1042,6 +1108,7 @@ - * Read data out of each tuple until we have a full page - * to write or we've read all the tuples. - */ -+ int cnt = 0; - while ((cnt < mtd->oobblock) && count) { - if (vecs->iov_base != NULL && vecs->iov_len) { - this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; -@@ -1057,15 +1124,12 @@ - } - - /* We use the same function for write and writev !) */ -- ret = nand_write_page (mtd, this, page, col, cnt, NULL, oobsel); -+ ret = nand_write_page (mtd, this, page, NULL, oobsel); - if (ret) - goto out; - - /* Update written bytes count */ -- written += (cnt - col); -- -- /* Reset written byte counter and column */ -- col = cnt = 0; -+ written += mtd->oobblock;; - - /* Increment page address */ - page++; -@@ -1073,7 +1137,7 @@ - - out: - /* De-select the NAND device */ -- nand_deselect (); -+ this->select_chip(mtd, -1); - - /* Wake up anyone waiting on the device */ - spin_lock_bh (&this->chip_lock); -@@ -1125,11 +1189,11 @@ - pages_per_block = mtd->erasesize / mtd->oobblock; - - /* Select the NAND device */ -- nand_select (); -+ this->select_chip(mtd, 0); - - /* Check the WP bit */ - this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); -- if (!(readb (this->IO_ADDR_R) & 0x80)) { -+ if (!(this->read_byte(mtd) & 0x80)) { - DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); - instr->state = MTD_ERASE_FAILED; - goto erase_exit; -@@ -1142,8 +1206,7 @@ - - while (len) { - /* Check if we have a bad block, we do not erase bad blocks ! */ -- this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page); -- if (readb (this->IO_ADDR_R) != 0xff) { -+ if (this->block_bad(mtd, page)) { - printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); - instr->state = MTD_ERASE_FAILED; - goto erase_exit; -@@ -1179,7 +1242,7 @@ - if (this->state == FL_ERASING || this->state == FL_READY) { - /* Select the NAND device again, if we were interrupted */ - this->state = FL_ERASING; -- nand_select (); -+ this->select_chip(mtd, 0); - continue; - } else { - set_current_state (TASK_UNINTERRUPTIBLE); -@@ -1194,7 +1257,7 @@ - - erase_exit: - /* De-select the NAND device */ -- nand_deselect (); -+ this->select_chip(mtd, -1); - spin_unlock_bh (&this->chip_lock); - - ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;; -@@ -1205,6 +1268,7 @@ - /* The device is ready */ - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; -+ wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - - /* Return more or less happy */ -@@ -1259,7 +1323,7 @@ - /* - * Scan for the NAND device - */ --int nand_scan (struct mtd_info *mtd) -+int nand_scan (struct mtd_info *mtd, int maxchips) - { - int i, nand_maf_id, nand_dev_id; - struct nand_chip *this = mtd->priv; -@@ -1276,23 +1340,38 @@ - if (this->waitfunc == NULL) - this->waitfunc = nand_wait; - -+ if (!this->block_bad) -+ this->block_bad = nand_block_bad; -+ if (!this->select_chip) -+ this->select_chip = nand_select_chip; -+ if (!this->write_byte) -+ this->write_byte = nand_write_byte; -+ if (!this->read_byte) -+ this->read_byte = nand_read_byte; -+ if (!this->write_buf) -+ this->write_buf = nand_write_buf; -+ if (!this->read_buf) -+ this->read_buf = nand_read_buf; -+ if (!this->verify_buf) -+ this->verify_buf = nand_verify_buf; -+ - /* Select the device */ -- nand_select (); -+ this->select_chip(mtd, 0); - - /* Send the command for reading device ID */ - this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); - - /* Read manufacturer and device IDs */ -- nand_maf_id = readb (this->IO_ADDR_R); -- nand_dev_id = readb (this->IO_ADDR_R); -+ nand_maf_id = this->read_byte(mtd); -+ nand_dev_id = this->read_byte(mtd); - - /* Print and store flash device information */ - for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) { - mtd->name = nand_flash_ids[i].name; - mtd->erasesize = nand_flash_ids[i].erasesize; -- mtd->size = (1 << nand_flash_ids[i].chipshift); - mtd->eccsize = 256; -+ this->chipshift = nand_flash_ids[i].chipshift; - if (nand_flash_ids[i].page256) { - mtd->oobblock = 256; - mtd->oobsize = 8; -@@ -1307,13 +1386,34 @@ - if (nand_manuf_ids[i].id == nand_maf_id) - break; - } -- printk (KERN_INFO "NAND device: Manufacture ID:" -+ printk (KERN_INFO "NAND device: Manufacturer ID:" - " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, - nand_manuf_ids[i].name , mtd->name); - break; - } - } - -+ if (!mtd->name) { -+ printk (KERN_WARNING "No NAND device found!!!\n"); -+ return 1; -+ } -+ -+ for (i=1; i < maxchips; i++) { -+ this->select_chip(mtd, i); -+ -+ /* Send the command for reading device ID */ -+ this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); -+ -+ /* Read manufacturer and device IDs */ -+ if (nand_maf_id != this->read_byte(mtd) || -+ nand_dev_id != this->read_byte(mtd)) -+ break; -+ } -+ if (i > 1) -+ printk(KERN_INFO "%d NAND chips detected\n", i); -+ -+ mtd->size = (1 << this->chipshift) /* * i when we fix the rest of the code */; -+ - /* - * check ECC mode, default to software - * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize -@@ -1324,6 +1424,7 @@ - switch (this->eccmode) { - - case NAND_ECC_HW3_512: -+ case NAND_ECC_HW6_512: - if (mtd->oobblock == 256) { - printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); - this->eccmode = NAND_ECC_SOFT; -@@ -1340,6 +1441,7 @@ - BUG(); - - case NAND_ECC_NONE: -+ printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); - this->eccmode = NAND_ECC_NONE; - break; - -@@ -1359,18 +1461,11 @@ - spin_lock_init (&this->chip_lock); - - /* De-select the device */ -- nand_deselect (); -- -- /* Print warning message for no device */ -- if (!mtd->size) { -- printk (KERN_WARNING "No NAND device found!!!\n"); -- return 1; -- } -+ this->select_chip(mtd, -1); - - /* Fill in remaining MTD driver data */ - mtd->type = MTD_NANDFLASH; - mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; -- mtd->module = THIS_MODULE; - mtd->ecctype = MTD_ECC_SW; - mtd->erase = nand_erase; - mtd->point = NULL; -@@ -1389,6 +1484,7 @@ - mtd->unlock = NULL; - mtd->suspend = NULL; - mtd->resume = NULL; -+ mtd->owner = THIS_MODULE; - - /* Return happy */ - return 0; -@@ -1397,5 +1493,5 @@ - EXPORT_SYMBOL (nand_scan); - - MODULE_LICENSE ("GPL"); --MODULE_AUTHOR ("Steven J. Hill <sjhill@cotw.com>, Thomas Gleixner <tglx@linutronix.de>"); -+MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); - MODULE_DESCRIPTION ("Generic NAND flash driver code"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/nand_ecc.c linux/drivers/mtd/nand/nand_ecc.c ---- linux-mips-2.4.27/drivers/mtd/nand/nand_ecc.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/nand/nand_ecc.c 2004-11-19 10:25:12.011182768 +0100 -@@ -1,10 +1,10 @@ - /* - * drivers/mtd/nand_ecc.c - * -- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) -+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * Toshiba America Electronics Components, Inc. - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License -@@ -17,6 +17,7 @@ - #include <linux/types.h> - #include <linux/kernel.h> - #include <linux/module.h> -+#include <linux/mtd/nand_ecc.h> - - /* - * Pre-calculated 256-way 1 byte column parity -@@ -84,7 +85,7 @@ - /* - * Calculate 3 byte ECC code for 256 byte block - */ --void nand_calculate_ecc (const u_char *dat, u_char *ecc_code) -+void nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) - { - u_char idx, reg1, reg2, reg3; - int j; -@@ -119,7 +120,7 @@ - /* - * Detect and correct a 1 bit error for 256 byte block - */ --int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc) -+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) - { - u_char a, b, c, d1, d2, d3, add, bit, i; - -@@ -209,5 +210,5 @@ - EXPORT_SYMBOL(nand_correct_data); - - MODULE_LICENSE("GPL"); --MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>"); -+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); - MODULE_DESCRIPTION("Generic NAND ECC support"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/nand_ids.c linux/drivers/mtd/nand/nand_ids.c ---- linux-mips-2.4.27/drivers/mtd/nand/nand_ids.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/nand/nand_ids.c 2004-11-19 10:25:12.013182464 +0100 -@@ -4,7 +4,7 @@ - * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) - * - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -18,21 +18,21 @@ - * Chip ID list - */ - struct nand_flash_dev nand_flash_ids[] = { -- {"NAND 1MB 5V", 0x6e, 20, 0x1000, 1}, // 1Mb 5V -- {"NAND 2MB 5V", 0x64, 21, 0x1000, 1}, // 2Mb 5V -- {"NAND 4MB 5V", 0x6b, 22, 0x2000, 0}, // 4Mb 5V -- {"NAND 1MB 3,3V", 0xe8, 20, 0x1000, 1}, // 1Mb 3.3V -- {"NAND 1MB 3,3V", 0xec, 20, 0x1000, 1}, // 1Mb 3.3V -- {"NAND 2MB 3,3V", 0xea, 21, 0x1000, 1}, // 2Mb 3.3V -- {"NAND 4MB 3,3V", 0xd5, 22, 0x2000, 0}, // 4Mb 3.3V -- {"NAND 4MB 3,3V", 0xe3, 22, 0x2000, 0}, // 4Mb 3.3V -- {"NAND 4MB 3,3V", 0xe5, 22, 0x2000, 0}, // 4Mb 3.3V -- {"NAND 8MB 3,3V", 0xd6, 23, 0x2000, 0}, // 8Mb 3.3V -- {"NAND 8MB 3,3V", 0xe6, 23, 0x2000, 0}, // 8Mb 3.3V -- {"NAND 16MB 3,3V", 0x73, 24, 0x4000, 0},// 16Mb 3,3V -- {"NAND 32MB 3,3V", 0x75, 25, 0x4000, 0}, // 32Mb 3,3V -- {"NAND 64MB 3,3V", 0x76, 26, 0x4000, 0}, // 64Mb 3,3V -- {"NAND 128MB 3,3V", 0x79, 27, 0x4000, 0}, // 128Mb 3,3V -+ {"NAND 1MiB 5V", 0x6e, 20, 0x1000, 1}, -+ {"NAND 2MiB 5V", 0x64, 21, 0x1000, 1}, -+ {"NAND 4MiB 5V", 0x6b, 22, 0x2000, 0}, -+ {"NAND 1MiB 3,3V", 0xe8, 20, 0x1000, 1}, -+ {"NAND 1MiB 3,3V", 0xec, 20, 0x1000, 1}, -+ {"NAND 2MiB 3,3V", 0xea, 21, 0x1000, 1}, -+ {"NAND 4MiB 3,3V", 0xd5, 22, 0x2000, 0}, -+ {"NAND 4MiB 3,3V", 0xe3, 22, 0x2000, 0}, -+ {"NAND 4MiB 3,3V", 0xe5, 22, 0x2000, 0}, -+ {"NAND 8MiB 3,3V", 0xd6, 23, 0x2000, 0}, -+ {"NAND 8MiB 3,3V", 0xe6, 23, 0x2000, 0}, -+ {"NAND 16MiB 3,3V", 0x73, 24, 0x4000, 0}, -+ {"NAND 32MiB 3,3V", 0x75, 25, 0x4000, 0}, -+ {"NAND 64MiB 3,3V", 0x76, 26, 0x4000, 0}, -+ {"NAND 128MiB 3,3V", 0x79, 27, 0x4000, 0}, - {NULL,} - }; - -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/spia.c linux/drivers/mtd/nand/spia.c ---- linux-mips-2.4.27/drivers/mtd/nand/spia.c 2003-02-26 01:53:50.000000000 +0100 -+++ linux/drivers/mtd/nand/spia.c 2004-11-19 10:25:12.014182312 +0100 -@@ -1,14 +1,14 @@ - /* - * drivers/mtd/nand/spia.c - * -- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) -+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * - * - * 10-29-2001 TG change to support hardwarespecific access - * to controllines (due to change in nand.c) - * page_cache added - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -20,6 +20,8 @@ - * a 64Mibit (8MiB x 8 bits) NAND flash device. - */ - -+#include <linux/kernel.h> -+#include <linux/init.h> - #include <linux/slab.h> - #include <linux/module.h> - #include <linux/mtd/mtd.h> -@@ -35,14 +37,14 @@ - /* - * Values specific to the SPIA board (used with EP7212 processor) - */ --#define SPIA_IO_ADDR = 0xd0000000 /* Start of EP7212 IO address space */ --#define SPIA_FIO_ADDR = 0xf0000000 /* Address where flash is mapped */ --#define SPIA_PEDR = 0x0080 /* -+#define SPIA_IO_BASE 0xd0000000 /* Start of EP7212 IO address space */ -+#define SPIA_FIO_BASE 0xf0000000 /* Address where flash is mapped */ -+#define SPIA_PEDR 0x0080 /* - * IO offset to Port E data register - * where the CLE, ALE and NCE pins - * are wired to. - */ --#define SPIA_PEDDR = 0x00c0 /* -+#define SPIA_PEDDR 0x00c0 /* - * IO offset to Port E data direction - * register so we can control the IO - * lines. -@@ -62,21 +64,20 @@ - MODULE_PARM(spia_pedr, "i"); - MODULE_PARM(spia_peddr, "i"); - --__setup("spia_io_base=",spia_io_base); --__setup("spia_fio_base=",spia_fio_base); --__setup("spia_pedr=",spia_pedr); --__setup("spia_peddr=",spia_peddr); -- - /* - * Define partitions for flash device - */ - const static struct mtd_partition partition_info[] = { -- { name: "SPIA flash partition 1", -- offset: 0, -- size: 2*1024*1024 }, -- { name: "SPIA flash partition 2", -- offset: 2*1024*1024, -- size: 6*1024*1024 } -+ { -+ .name = "SPIA flash partition 1", -+ .offset = 0, -+ .size = 2*1024*1024 -+ }, -+ { -+ .name = "SPIA flash partition 2", -+ .offset = 2*1024*1024, -+ .size = 6*1024*1024 -+ } - }; - #define NUM_PARTITIONS 2 - -@@ -84,7 +85,7 @@ - /* - * hardware specific access to control-lines - */ --void spia_hwcontrol(int cmd){ -+static void spia_hwcontrol(struct mtd_info *mtd, int cmd){ - - switch(cmd){ - -@@ -139,7 +140,7 @@ - this->chip_delay = 15; - - /* Scan to find existence of the device */ -- if (nand_scan (spia_mtd)) { -+ if (nand_scan (spia_mtd, 1)) { - kfree (spia_mtd); - return -ENXIO; - } -@@ -152,16 +153,6 @@ - return -ENOMEM; - } - -- /* Allocate memory for internal data buffer */ -- this->data_cache = kmalloc (sizeof(u_char) * (spia_mtd->oobblock + spia_mtd->oobsize), GFP_KERNEL); -- if (!this->data_cache) { -- printk ("Unable to allocate NAND data cache for SPIA.\n"); -- kfree (this->data_buf); -- kfree (spia_mtd); -- return = -ENOMEM; -- } -- this->cache_page = -1; -- - /* Register the partitions */ - add_mtd_partitions(spia_mtd, partition_info, NUM_PARTITIONS); - -@@ -183,7 +174,6 @@ - - /* Free internal data buffer */ - kfree (this->data_buf); -- kfree (this->page_cache); - - /* Free the MTD device structure */ - kfree (spia_mtd); -@@ -192,5 +182,5 @@ - #endif - - MODULE_LICENSE("GPL"); --MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com"); -+MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com"); - MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on SPIA board"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/toto.c linux/drivers/mtd/nand/toto.c ---- linux-mips-2.4.27/drivers/mtd/nand/toto.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/nand/toto.c 2004-11-19 10:25:12.016182008 +0100 -@@ -0,0 +1,221 @@ -+/* -+ * drivers/mtd/nand/toto.c -+ * -+ * Copyright (c) 2003 Texas Instruments -+ * -+ * Derived from drivers/mtd/autcpu12.c -+ * -+ * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * Overview: -+ * This is a device driver for the NAND flash device found on the -+ * TI fido board. It supports 32MiB and 64MiB cards -+ * -+ * $Id$ -+ */ -+ -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nand.h> -+#include <linux/mtd/partitions.h> -+#include <asm/io.h> -+#include <asm/arch/hardware.h> -+#include <asm/sizes.h> -+#include <asm/arch/toto.h> -+#include <asm/arch-omap1510/hardware.h> -+#include <asm/arch/gpio.h> -+ -+/* -+ * MTD structure for TOTO board -+ */ -+static struct mtd_info *toto_mtd = NULL; -+ -+static int toto_io_base = OMAP_FLASH_1_BASE; -+ -+#define CONFIG_NAND_WORKAROUND 1 -+ -+#define NAND_NCE 0x4000 -+#define NAND_CLE 0x1000 -+#define NAND_ALE 0x0002 -+#define NAND_MASK (NAND_CLE | NAND_ALE | NAND_NCE) -+ -+#define T_NAND_CTL_CLRALE(iob) gpiosetout(NAND_ALE, 0) -+#define T_NAND_CTL_SETALE(iob) gpiosetout(NAND_ALE, NAND_ALE) -+#ifdef CONFIG_NAND_WORKAROUND /* "some" dev boards busted, blue wired to rts2 :( */ -+#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0); rts2setout(2, 2) -+#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE); rts2setout(2, 0) -+#else -+#define T_NAND_CTL_CLRCLE(iob) gpiosetout(NAND_CLE, 0) -+#define T_NAND_CTL_SETCLE(iob) gpiosetout(NAND_CLE, NAND_CLE) -+#endif -+#define T_NAND_CTL_SETNCE(iob) gpiosetout(NAND_NCE, 0) -+#define T_NAND_CTL_CLRNCE(iob) gpiosetout(NAND_NCE, NAND_NCE) -+ -+/* -+ * Define partitions for flash devices -+ */ -+ -+static struct mtd_partition partition_info64M[] = { -+ { .name = "toto kernel partition 1", -+ .offset = 0, -+ .size = 2 * SZ_1M }, -+ { .name = "toto file sys partition 2", -+ .offset = 2 * SZ_1M, -+ .size = 14 * SZ_1M }, -+ { .name = "toto user partition 3", -+ .offset = 16 * SZ_1M, -+ .size = 16 * SZ_1M }, -+ { .name = "toto devboard extra partition 4", -+ .offset = 32 * SZ_1M, -+ .size = 32 * SZ_1M }, -+}; -+ -+static struct mtd_partition partition_info32M[] = { -+ { .name = "toto kernel partition 1", -+ .offset = 0, -+ .size = 2 * SZ_1M }, -+ { .name = "toto file sys partition 2", -+ .offset = 2 * SZ_1M, -+ .size = 14 * SZ_1M }, -+ { .name = "toto user partition 3", -+ .offset = 16 * SZ_1M, -+ .size = 16 * SZ_1M }, -+}; -+ -+#define NUM_PARTITIONS32M 3 -+#define NUM_PARTITIONS64M 4 -+/* -+ * hardware specific access to control-lines -+*/ -+ -+static void toto_hwcontrol(struct mtd_info *mtd, int cmd) -+{ -+ -+ udelay(1); /* hopefully enough time for tc make proceding write to clear */ -+ switch(cmd){ -+ -+ case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break; -+ case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break; -+ -+ case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break; -+ case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break; -+ -+ case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break; -+ case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break; -+ } -+ udelay(1); /* allow time to ensure gpio state to over take memory write */ -+} -+ -+/* -+ * Main initialization routine -+ */ -+int __init toto_init (void) -+{ -+ struct nand_chip *this; -+ int err = 0; -+ -+ /* Allocate memory for MTD device structure and private data */ -+ toto_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), -+ GFP_KERNEL); -+ if (!toto_mtd) { -+ printk (KERN_WARNING "Unable to allocate toto NAND MTD device structure.\n"); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *) (&toto_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *) toto_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *) this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ toto_mtd->priv = this; -+ -+ /* Set address of NAND IO lines */ -+ this->IO_ADDR_R = toto_io_base; -+ this->IO_ADDR_W = toto_io_base; -+ this->hwcontrol = toto_hwcontrol; -+ this->dev_ready = NULL; -+ /* 25 us command delay time */ -+ this->chip_delay = 30; -+ this->eccmode = NAND_ECC_SOFT; -+ -+ /* Scan to find existance of the device */ -+ if (nand_scan (toto_mtd, 1)) { -+ err = -ENXIO; -+ goto out_mtd; -+ } -+ -+ /* Allocate memory for internal data buffer */ -+ this->data_buf = kmalloc (sizeof(u_char) * (toto_mtd->oobblock + toto_mtd->oobsize), GFP_KERNEL); -+ if (!this->data_buf) { -+ printk (KERN_WARNING "Unable to allocate NAND data buffer for toto.\n"); -+ err = -ENOMEM; -+ goto out_mtd; -+ } -+ -+ /* Register the partitions */ -+ switch(toto_mtd->size){ -+ case SZ_64M: add_mtd_partitions(toto_mtd, partition_info64M, NUM_PARTITIONS64M); break; -+ case SZ_32M: add_mtd_partitions(toto_mtd, partition_info32M, NUM_PARTITIONS32M); break; -+ default: { -+ printk (KERN_WARNING "Unsupported Nand device\n"); -+ err = -ENXIO; -+ goto out_buf; -+ } -+ } -+ -+ gpioreserve(NAND_MASK); /* claim our gpios */ -+ archflashwp(0,0); /* open up flash for writing */ -+ -+ goto out; -+ -+out_buf: -+ kfree (this->data_buf); -+out_mtd: -+ kfree (toto_mtd); -+out: -+ return err; -+} -+ -+module_init(toto_init); -+ -+/* -+ * Clean up routine -+ */ -+static void __exit toto_cleanup (void) -+{ -+ struct nand_chip *this = (struct nand_chip *) &toto_mtd[1]; -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(toto_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device (toto_mtd); -+ -+ /* Free internal data buffers */ -+ kfree (this->data_buf); -+ -+ /* Free the MTD device structure */ -+ kfree (toto_mtd); -+ -+ /* stop flash writes */ -+ archflashwp(0,1); -+ -+ /* release gpios to system */ -+ gpiorelease(NAND_MASK); -+} -+module_exit(toto_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Richard Woodruff <r-woodruff2@ti.com>"); -+MODULE_DESCRIPTION("Glue layer for NAND flash on toto board"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/tx4925ndfmc.c linux/drivers/mtd/nand/tx4925ndfmc.c ---- linux-mips-2.4.27/drivers/mtd/nand/tx4925ndfmc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/nand/tx4925ndfmc.c 2004-11-19 10:25:12.017181856 +0100 -@@ -0,0 +1,442 @@ -+/* -+ * drivers/mtd/tx4925ndfmc.c -+ * -+ * Overview: -+ * This is a device driver for the NAND flash device found on the -+ * Toshiba RBTX4925 reference board, which is a SmartMediaCard. It supports -+ * 16MiB, 32MiB and 64MiB cards. -+ * -+ * Author: MontaVista Software, Inc. source@mvista.com -+ * -+ * Derived from drivers/mtd/autcpu12.c -+ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) -+ * -+ * $Id$ -+ * -+ * Copyright (C) 2001 Toshiba Corporation -+ * -+ * 2003 (c) MontaVista Software, Inc. This file is licensed under -+ * the terms of the GNU General Public License version 2. This program -+ * is licensed "as is" without any warranty of any kind, whether express -+ * or implied. -+ * -+ */ -+ -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nand.h> -+#include <linux/mtd/partitions.h> -+#include <linux/delay.h> -+#include <asm/io.h> -+#include <asm/tx4925/tx4925_nand.h> -+ -+extern struct nand_oobinfo jffs2_oobinfo; -+ -+/* -+ * MTD structure for RBTX4925 board -+ */ -+static struct mtd_info *tx4925ndfmc_mtd = NULL; -+ -+/* -+ * Module stuff -+ */ -+#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE) -+#define tx4925ndfmc_init init_module -+#define tx4925ndfmc_cleanup cleanup_module -+#endif -+ -+/* -+ * Define partitions for flash devices -+ */ -+ -+static struct mtd_partition partition_info16k[] = { -+ { .name = "RBTX4925 flash partition 1", -+ .offset = 0, -+ .size = 8 * 0x00100000 }, -+ { .name = "RBTX4925 flash partition 2", -+ .offset = 8 * 0x00100000, -+ .size = 8 * 0x00100000 }, -+}; -+ -+static struct mtd_partition partition_info32k[] = { -+ { .name = "RBTX4925 flash partition 1", -+ .offset = 0, -+ .size = 8 * 0x00100000 }, -+ { .name = "RBTX4925 flash partition 2", -+ .offset = 8 * 0x00100000, -+ .size = 24 * 0x00100000 }, -+}; -+ -+static struct mtd_partition partition_info64k[] = { -+ { .name = "User FS", -+ .offset = 0, -+ .size = 16 * 0x00100000 }, -+ { .name = "RBTX4925 flash partition 2", -+ .offset = 16 * 0x00100000, -+ .size = 48 * 0x00100000}, -+}; -+ -+static struct mtd_partition partition_info128k[] = { -+ { .name = "Skip bad section", -+ .offset = 0, -+ .size = 16 * 0x00100000 }, -+ { .name = "User FS", -+ .offset = 16 * 0x00100000, -+ .size = 112 * 0x00100000 }, -+}; -+#define NUM_PARTITIONS16K 2 -+#define NUM_PARTITIONS32K 2 -+#define NUM_PARTITIONS64K 2 -+#define NUM_PARTITIONS128K 2 -+ -+/* -+ * hardware specific access to control-lines -+*/ -+static void tx4925ndfmc_hwcontrol(struct mtd_info *mtd, int cmd) -+{ -+ -+ switch(cmd){ -+ -+ case NAND_CTL_SETCLE: -+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CLE; -+ break; -+ case NAND_CTL_CLRCLE: -+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CLE; -+ break; -+ case NAND_CTL_SETALE: -+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ALE; -+ break; -+ case NAND_CTL_CLRALE: -+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ALE; -+ break; -+ case NAND_CTL_SETNCE: -+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CE; -+ break; -+ case NAND_CTL_CLRNCE: -+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CE; -+ break; -+ case NAND_CTL_SETWP: -+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_WE; -+ break; -+ case NAND_CTL_CLRWP: -+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_WE; -+ break; -+ } -+} -+ -+/* -+* read device ready pin -+*/ -+static int tx4925ndfmc_device_ready(struct mtd_info *mtd) -+{ -+ int ready; -+ ready = (tx4925_ndfmcptr->sr & TX4925_NDSFR_BUSY) ? 0 : 1; -+ return ready; -+} -+void tx4925ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) -+{ -+ /* reset first */ -+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_MASK; -+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; -+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_ENAB; -+} -+static void tx4925ndfmc_disable_ecc(void) -+{ -+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; -+} -+static void tx4925ndfmc_enable_read_ecc(void) -+{ -+ tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK; -+ tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_READ; -+} -+void tx4925ndfmc_readecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){ -+ int i; -+ u_char *ecc = ecc_code; -+ tx4925ndfmc_enable_read_ecc(); -+ for (i = 0;i < 6;i++,ecc++) -+ *ecc = tx4925_read_nfmc(&(tx4925_ndfmcptr->dtr)); -+ tx4925ndfmc_disable_ecc(); -+} -+void tx4925ndfmc_device_setup(void) -+{ -+ -+ *(unsigned char *)0xbb005000 &= ~0x08; -+ -+ /* reset NDFMC */ -+ tx4925_ndfmcptr->rstr |= TX4925_NDFRSTR_RST; -+ while (tx4925_ndfmcptr->rstr & TX4925_NDFRSTR_RST); -+ -+ /* setup BusSeparete, Hold Time, Strobe Pulse Width */ -+ tx4925_ndfmcptr->mcr = TX4925_BSPRT ? TX4925_NDFMCR_BSPRT : 0; -+ tx4925_ndfmcptr->spr = TX4925_HOLD << 4 | TX4925_SPW; -+} -+static u_char tx4925ndfmc_nand_read_byte(struct mtd_info *mtd) -+{ -+ struct nand_chip *this = mtd->priv; -+ return tx4925_read_nfmc(this->IO_ADDR_R); -+} -+ -+static void tx4925ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte) -+{ -+ struct nand_chip *this = mtd->priv; -+ tx4925_write_nfmc(byte, this->IO_ADDR_W); -+} -+ -+static void tx4925ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ tx4925_write_nfmc(buf[i], this->IO_ADDR_W); -+} -+ -+static void tx4925ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ buf[i] = tx4925_read_nfmc(this->IO_ADDR_R); -+} -+ -+static int tx4925ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ if (buf[i] != tx4925_read_nfmc(this->IO_ADDR_R)) -+ return i; -+ -+ return 0; -+} -+ -+/* -+ * Send command to NAND device -+ */ -+static void tx4925ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) -+{ -+ register struct nand_chip *this = mtd->priv; -+ -+ /* Begin command latch cycle */ -+ this->hwcontrol(mtd, NAND_CTL_SETCLE); -+ /* -+ * Write out the command to the device. -+ */ -+ if (command == NAND_CMD_SEQIN) { -+ int readcmd; -+ -+ if (column >= mtd->oobblock) { -+ /* OOB area */ -+ column -= mtd->oobblock; -+ readcmd = NAND_CMD_READOOB; -+ } else if (column < 256) { -+ /* First 256 bytes --> READ0 */ -+ readcmd = NAND_CMD_READ0; -+ } else { -+ column -= 256; -+ readcmd = NAND_CMD_READ1; -+ } -+ this->write_byte(mtd, readcmd); -+ } -+ this->write_byte(mtd, command); -+ -+ /* Set ALE and clear CLE to start address cycle */ -+ this->hwcontrol(mtd, NAND_CTL_CLRCLE); -+ -+ if (column != -1 || page_addr != -1) { -+ this->hwcontrol(mtd, NAND_CTL_SETALE); -+ -+ /* Serially input address */ -+ if (column != -1) -+ this->write_byte(mtd, column); -+ if (page_addr != -1) { -+ this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); -+ this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); -+ /* One more address cycle for higher density devices */ -+ if (mtd->size & 0x0c000000) -+ this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); -+ } -+ /* Latch in address */ -+ this->hwcontrol(mtd, NAND_CTL_CLRALE); -+ } -+ -+ /* -+ * program and erase have their own busy handlers -+ * status and sequential in needs no delay -+ */ -+ switch (command) { -+ -+ case NAND_CMD_PAGEPROG: -+ /* Turn off WE */ -+ this->hwcontrol (mtd, NAND_CTL_CLRWP); -+ return; -+ -+ case NAND_CMD_SEQIN: -+ /* Turn on WE */ -+ this->hwcontrol (mtd, NAND_CTL_SETWP); -+ return; -+ -+ case NAND_CMD_ERASE1: -+ case NAND_CMD_ERASE2: -+ case NAND_CMD_STATUS: -+ return; -+ -+ case NAND_CMD_RESET: -+ if (this->dev_ready) -+ break; -+ this->hwcontrol(mtd, NAND_CTL_SETCLE); -+ this->write_byte(mtd, NAND_CMD_STATUS); -+ this->hwcontrol(mtd, NAND_CTL_CLRCLE); -+ while ( !(this->read_byte(mtd) & 0x40)); -+ return; -+ -+ /* This applies to read commands */ -+ default: -+ /* -+ * If we don't have access to the busy pin, we apply the given -+ * command delay -+ */ -+ if (!this->dev_ready) { -+ udelay (this->chip_delay); -+ return; -+ } -+ } -+ -+ /* wait until command is processed */ -+ while (!this->dev_ready(mtd)); -+} -+ -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio -+n **pparts, char *); -+#endif -+ -+/* -+ * Main initialization routine -+ */ -+extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); -+int __init tx4925ndfmc_init (void) -+{ -+ struct nand_chip *this; -+ int err = 0; -+ -+ /* Allocate memory for MTD device structure and private data */ -+ tx4925ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), -+ GFP_KERNEL); -+ if (!tx4925ndfmc_mtd) { -+ printk ("Unable to allocate RBTX4925 NAND MTD device structure.\n"); -+ err = -ENOMEM; -+ goto out; -+ } -+ -+ tx4925ndfmc_device_setup(); -+ -+ /* io is indirect via a register so don't need to ioremap address */ -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *) (&tx4925ndfmc_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *) tx4925ndfmc_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *) this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ tx4925ndfmc_mtd->priv = this; -+ -+ /* Set address of NAND IO lines */ -+ this->IO_ADDR_R = (unsigned long)&(tx4925_ndfmcptr->dtr); -+ this->IO_ADDR_W = (unsigned long)&(tx4925_ndfmcptr->dtr); -+ this->hwcontrol = tx4925ndfmc_hwcontrol; -+ this->enable_hwecc = tx4925ndfmc_enable_hwecc; -+ this->calculate_ecc = tx4925ndfmc_readecc; -+ this->correct_data = nand_correct_data; -+ this->eccmode = NAND_ECC_HW6_512; -+ this->dev_ready = tx4925ndfmc_device_ready; -+ /* 20 us command delay time */ -+ this->chip_delay = 20; -+ this->read_byte = tx4925ndfmc_nand_read_byte; -+ this->write_byte = tx4925ndfmc_nand_write_byte; -+ this->cmdfunc = tx4925ndfmc_nand_command; -+ this->write_buf = tx4925ndfmc_nand_write_buf; -+ this->read_buf = tx4925ndfmc_nand_read_buf; -+ this->verify_buf = tx4925ndfmc_nand_verify_buf; -+ -+ /* Scan to find existance of the device */ -+ if (nand_scan (tx4925ndfmc_mtd, 1)) { -+ err = -ENXIO; -+ goto out_ior; -+ } -+ -+ /* Allocate memory for internal data buffer */ -+ this->data_buf = kmalloc (sizeof(u_char) * (tx4925ndfmc_mtd->oobblock + tx4925ndfmc_mtd->oobsize), GFP_KERNEL); -+ if (!this->data_buf) { -+ printk ("Unable to allocate NAND data buffer for RBTX4925.\n"); -+ err = -ENOMEM; -+ goto out_ior; -+ } -+ -+ /* Register the partitions */ -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+ { -+ int mtd_parts_nb = 0; -+ struct mtd_partition *mtd_parts = 0; -+ mtd_parts_nb = parse_cmdline_partitions(tx4925ndfmc_mtd, &mtd_parts, "tx4925ndfmc"); -+ if (mtd_parts_nb > 0) -+ add_mtd_partitions(tx4925ndfmc_mtd, mtd_parts, mtd_parts_nb); -+ else -+ add_mtd_device(tx4925ndfmc_mtd); -+ } -+#else /* ifdef CONFIG_MTD_CMDLINE_PARTS */ -+ switch(tx4925ndfmc_mtd->size){ -+ case 0x01000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info16k, NUM_PARTITIONS16K); break; -+ case 0x02000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info32k, NUM_PARTITIONS32K); break; -+ case 0x04000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info64k, NUM_PARTITIONS64K); break; -+ case 0x08000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info128k, NUM_PARTITIONS128K); break; -+ default: { -+ printk ("Unsupported SmartMedia device\n"); -+ err = -ENXIO; -+ goto out_buf; -+ } -+ } -+#endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */ -+ goto out; -+ -+out_buf: -+ kfree (this->data_buf); -+out_ior: -+out: -+ return err; -+} -+ -+module_init(tx4925ndfmc_init); -+ -+/* -+ * Clean up routine -+ */ -+#ifdef MODULE -+static void __exit tx4925ndfmc_cleanup (void) -+{ -+ struct nand_chip *this = (struct nand_chip *) &tx4925ndfmc_mtd[1]; -+ -+ /* Unregister partitions */ -+ del_mtd_partitions(tx4925ndfmc_mtd); -+ -+ /* Unregister the device */ -+ del_mtd_device (tx4925ndfmc_mtd); -+ -+ /* Free internal data buffers */ -+ kfree (this->data_buf); -+ -+ /* Free the MTD device structure */ -+ kfree (tx4925ndfmc_mtd); -+} -+module_exit(tx4925ndfmc_cleanup); -+#endif -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>"); -+MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBTX4925"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nand/tx4938ndfmc.c linux/drivers/mtd/nand/tx4938ndfmc.c ---- linux-mips-2.4.27/drivers/mtd/nand/tx4938ndfmc.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/drivers/mtd/nand/tx4938ndfmc.c 2004-11-19 10:25:12.019181552 +0100 -@@ -0,0 +1,422 @@ -+/* -+ * drivers/mtd/nand/tx4938ndfmc.c -+ * -+ * Overview: -+ * This is a device driver for the NAND flash device connected to -+ * TX4938 internal NAND Memory Controller. -+ * TX4938 NDFMC is almost same as TX4925 NDFMC, but register size are 64 bit. -+ * -+ * Author: source@mvista.com -+ * -+ * Based on spia.c by Steven J. Hill -+ * -+ * $Id$ -+ * -+ * Copyright (C) 2000-2001 Toshiba Corporation -+ * -+ * 2003 (c) MontaVista Software, Inc. This file is licensed under the -+ * terms of the GNU General Public License version 2. This program is -+ * licensed "as is" without any warranty of any kind, whether express -+ * or implied. -+ */ -+#include <linux/config.h> -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nand.h> -+#include <linux/mtd/nand_ecc.h> -+#include <linux/mtd/partitions.h> -+#include <asm/io.h> -+#include <asm/bootinfo.h> -+#include <linux/delay.h> -+#include <asm/tx4938/rbtx4938.h> -+ -+extern struct nand_oobinfo jffs2_oobinfo; -+ -+/* -+ * MTD structure for TX4938 NDFMC -+ */ -+static struct mtd_info *tx4938ndfmc_mtd; -+ -+/* -+ * Define partitions for flash device -+ */ -+#define flush_wb() (void)tx4938_ndfmcptr->mcr; -+ -+#define NUM_PARTITIONS 3 -+#define NUMBER_OF_CIS_BLOCKS 24 -+#define SIZE_OF_BLOCK 0x00004000 -+#define NUMBER_OF_BLOCK_PER_ZONE 1024 -+#define SIZE_OF_ZONE (NUMBER_OF_BLOCK_PER_ZONE * SIZE_OF_BLOCK) -+#ifndef CONFIG_MTD_CMDLINE_PARTS -+/* -+ * You can use the following sample of MTD partitions -+ * on the NAND Flash Memory 32MB or more. -+ * -+ * The following figure shows the image of the sample partition on -+ * the 32MB NAND Flash Memory. -+ * -+ * Block No. -+ * 0 +-----------------------------+ ------ -+ * | CIS | ^ -+ * 24 +-----------------------------+ | -+ * | kernel image | | Zone 0 -+ * | | | -+ * +-----------------------------+ | -+ * 1023 | unused area | v -+ * +-----------------------------+ ------ -+ * 1024 | JFFS2 | ^ -+ * | | | -+ * | | | Zone 1 -+ * | | | -+ * | | | -+ * | | v -+ * 2047 +-----------------------------+ ------ -+ * -+ */ -+static struct mtd_partition partition_info[NUM_PARTITIONS] = { -+ { -+ .name = "RBTX4938 CIS Area", -+ .offset = 0, -+ .size = (NUMBER_OF_CIS_BLOCKS * SIZE_OF_BLOCK), -+ .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */ -+ }, -+ { -+ .name = "RBTX4938 kernel image", -+ .offset = MTDPART_OFS_APPEND, -+ .size = 8 * 0x00100000, /* 8MB (Depends on size of kernel image) */ -+ .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */ -+ }, -+ { -+ .name = "Root FS (JFFS2)", -+ .offset = (0 + SIZE_OF_ZONE), /* start address of next zone */ -+ .size = MTDPART_SIZ_FULL -+ }, -+}; -+#endif -+ -+static void tx4938ndfmc_hwcontrol(struct mtd_info *mtd, int cmd) -+{ -+ switch (cmd) { -+ case NAND_CTL_SETCLE: -+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CLE; -+ break; -+ case NAND_CTL_CLRCLE: -+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CLE; -+ break; -+ case NAND_CTL_SETALE: -+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_ALE; -+ break; -+ case NAND_CTL_CLRALE: -+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_ALE; -+ break; -+ /* TX4938_NDFMCR_CE bit is 0:high 1:low */ -+ case NAND_CTL_SETNCE: -+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CE; -+ break; -+ case NAND_CTL_CLRNCE: -+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CE; -+ break; -+ case NAND_CTL_SETWP: -+ tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_WE; -+ break; -+ case NAND_CTL_CLRWP: -+ tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_WE; -+ break; -+ } -+} -+static int tx4938ndfmc_dev_ready(struct mtd_info *mtd) -+{ -+ flush_wb(); -+ return !(tx4938_ndfmcptr->sr & TX4938_NDFSR_BUSY); -+} -+static void tx4938ndfmc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code) -+{ -+ u32 mcr = tx4938_ndfmcptr->mcr; -+ mcr &= ~TX4938_NDFMCR_ECC_ALL; -+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; -+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_READ; -+ ecc_code[1] = tx4938_ndfmcptr->dtr; -+ ecc_code[0] = tx4938_ndfmcptr->dtr; -+ ecc_code[2] = tx4938_ndfmcptr->dtr; -+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; -+} -+static void tx4938ndfmc_enable_hwecc(struct mtd_info *mtd, int mode) -+{ -+ u32 mcr = tx4938_ndfmcptr->mcr; -+ mcr &= ~TX4938_NDFMCR_ECC_ALL; -+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_RESET; -+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF; -+ tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_ON; -+} -+ -+static u_char tx4938ndfmc_nand_read_byte(struct mtd_info *mtd) -+{ -+ struct nand_chip *this = mtd->priv; -+ return tx4938_read_nfmc(this->IO_ADDR_R); -+} -+ -+static void tx4938ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte) -+{ -+ struct nand_chip *this = mtd->priv; -+ tx4938_write_nfmc(byte, this->IO_ADDR_W); -+} -+ -+static void tx4938ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ tx4938_write_nfmc(buf[i], this->IO_ADDR_W); -+} -+ -+static void tx4938ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ buf[i] = tx4938_read_nfmc(this->IO_ADDR_R); -+} -+ -+static int tx4938ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len) -+{ -+ int i; -+ struct nand_chip *this = mtd->priv; -+ -+ for (i=0; i<len; i++) -+ if (buf[i] != tx4938_read_nfmc(this->IO_ADDR_R)) -+ return i; -+ -+ return 0; -+} -+ -+/* -+ * Send command to NAND device -+ */ -+static void tx4938ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) -+{ -+ register struct nand_chip *this = mtd->priv; -+ -+ /* Begin command latch cycle */ -+ this->hwcontrol(mtd, NAND_CTL_SETCLE); -+ /* -+ * Write out the command to the device. -+ */ -+ if (command == NAND_CMD_SEQIN) { -+ int readcmd; -+ -+ if (column >= mtd->oobblock) { -+ /* OOB area */ -+ column -= mtd->oobblock; -+ readcmd = NAND_CMD_READOOB; -+ } else if (column < 256) { -+ /* First 256 bytes --> READ0 */ -+ readcmd = NAND_CMD_READ0; -+ } else { -+ column -= 256; -+ readcmd = NAND_CMD_READ1; -+ } -+ this->write_byte(mtd, readcmd); -+ } -+ this->write_byte(mtd, command); -+ -+ /* Set ALE and clear CLE to start address cycle */ -+ this->hwcontrol(mtd, NAND_CTL_CLRCLE); -+ -+ if (column != -1 || page_addr != -1) { -+ this->hwcontrol(mtd, NAND_CTL_SETALE); -+ -+ /* Serially input address */ -+ if (column != -1) -+ this->write_byte(mtd, column); -+ if (page_addr != -1) { -+ this->write_byte(mtd, (unsigned char) (page_addr & 0xff)); -+ this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff)); -+ /* One more address cycle for higher density devices */ -+ if (mtd->size & 0x0c000000) -+ this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f)); -+ } -+ /* Latch in address */ -+ this->hwcontrol(mtd, NAND_CTL_CLRALE); -+ } -+ -+ /* -+ * program and erase have their own busy handlers -+ * status and sequential in needs no delay -+ */ -+ switch (command) { -+ -+ case NAND_CMD_PAGEPROG: -+ /* Turn off WE */ -+ this->hwcontrol (mtd, NAND_CTL_CLRWP); -+ return; -+ -+ case NAND_CMD_SEQIN: -+ /* Turn on WE */ -+ this->hwcontrol (mtd, NAND_CTL_SETWP); -+ return; -+ -+ case NAND_CMD_ERASE1: -+ case NAND_CMD_ERASE2: -+ case NAND_CMD_STATUS: -+ return; -+ -+ case NAND_CMD_RESET: -+ if (this->dev_ready) -+ break; -+ this->hwcontrol(mtd, NAND_CTL_SETCLE); -+ this->write_byte(mtd, NAND_CMD_STATUS); -+ this->hwcontrol(mtd, NAND_CTL_CLRCLE); -+ while ( !(this->read_byte(mtd) & 0x40)); -+ return; -+ -+ /* This applies to read commands */ -+ default: -+ /* -+ * If we don't have access to the busy pin, we apply the given -+ * command delay -+ */ -+ if (!this->dev_ready) { -+ udelay (this->chip_delay); -+ return; -+ } -+ } -+ -+ /* wait until command is processed */ -+ while (!this->dev_ready(mtd)); -+} -+ -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); -+#endif -+/* -+ * Main initialization routine -+ */ -+int __init tx4938ndfmc_init (void) -+{ -+ struct nand_chip *this; -+ int bsprt = 0, hold = 0xf, spw = 0xf; -+ int protected = 0; -+ -+ if ((*rbtx4938_piosel_ptr & 0x0c) != 0x08) { -+ printk("TX4938 NDFMC: disabled by IOC PIOSEL\n"); -+ return -ENODEV; -+ } -+ bsprt = 1; -+ hold = 2; -+ spw = 9 - 1; /* 8 GBUSCLK = 80ns (@ GBUSCLK 100MHz) */ -+ -+ if ((tx4938_ccfgptr->pcfg & -+ (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL)) -+ != TX4938_PCFG_NDF_SEL) { -+ printk("TX4938 NDFMC: disabled by PCFG.\n"); -+ return -ENODEV; -+ } -+ -+ /* reset NDFMC */ -+ tx4938_ndfmcptr->rstr |= TX4938_NDFRSTR_RST; -+ while (tx4938_ndfmcptr->rstr & TX4938_NDFRSTR_RST) -+ ; -+ /* setup BusSeparete, Hold Time, Strobe Pulse Width */ -+ tx4938_ndfmcptr->mcr = bsprt ? TX4938_NDFMCR_BSPRT : 0; -+ tx4938_ndfmcptr->spr = hold << 4 | spw; -+ -+ /* Allocate memory for MTD device structure and private data */ -+ tx4938ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), -+ GFP_KERNEL); -+ if (!tx4938ndfmc_mtd) { -+ printk ("Unable to allocate TX4938 NDFMC MTD device structure.\n"); -+ return -ENOMEM; -+ } -+ -+ /* Get pointer to private data */ -+ this = (struct nand_chip *) (&tx4938ndfmc_mtd[1]); -+ -+ /* Initialize structures */ -+ memset((char *) tx4938ndfmc_mtd, 0, sizeof(struct mtd_info)); -+ memset((char *) this, 0, sizeof(struct nand_chip)); -+ -+ /* Link the private data with the MTD structure */ -+ tx4938ndfmc_mtd->priv = this; -+ -+ /* Set address of NAND IO lines */ -+ this->IO_ADDR_R = (unsigned long)&tx4938_ndfmcptr->dtr; -+ this->IO_ADDR_W = (unsigned long)&tx4938_ndfmcptr->dtr; -+ this->hwcontrol = tx4938ndfmc_hwcontrol; -+ this->dev_ready = tx4938ndfmc_dev_ready; -+ this->calculate_ecc = tx4938ndfmc_calculate_ecc; -+ this->correct_data = nand_correct_data; -+ this->enable_hwecc = tx4938ndfmc_enable_hwecc; -+ this->eccmode = NAND_ECC_HW3_256; -+ this->chip_delay = 100; -+ this->read_byte = tx4938ndfmc_nand_read_byte; -+ this->write_byte = tx4938ndfmc_nand_write_byte; -+ this->cmdfunc = tx4938ndfmc_nand_command; -+ this->write_buf = tx4938ndfmc_nand_write_buf; -+ this->read_buf = tx4938ndfmc_nand_read_buf; -+ this->verify_buf = tx4938ndfmc_nand_verify_buf; -+ -+ /* Scan to find existance of the device */ -+ if (nand_scan (tx4938ndfmc_mtd, 1)) { -+ kfree (tx4938ndfmc_mtd); -+ return -ENXIO; -+ } -+ -+ /* Allocate memory for internal data buffer */ -+ this->data_buf = kmalloc (sizeof(u_char) * (tx4938ndfmc_mtd->oobblock + tx4938ndfmc_mtd->oobsize), GFP_KERNEL); -+ if (!this->data_buf) { -+ printk ("Unable to allocate NAND data buffer for TX4938.\n"); -+ kfree (tx4938ndfmc_mtd); -+ return -ENOMEM; -+ } -+ -+ if (protected) { -+ printk(KERN_INFO "TX4938 NDFMC: write protected.\n"); -+ tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE); -+ } -+ -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+ { -+ int mtd_parts_nb = 0; -+ struct mtd_partition *mtd_parts = 0; -+ mtd_parts_nb = parse_cmdline_partitions(tx4938ndfmc_mtd, &mtd_parts, "tx4938ndfmc"); -+ if (mtd_parts_nb > 0) -+ add_mtd_partitions(tx4938ndfmc_mtd, mtd_parts, mtd_parts_nb); -+ else -+ add_mtd_device(tx4938ndfmc_mtd); -+ } -+#else -+ add_mtd_partitions(tx4938ndfmc_mtd, partition_info, NUM_PARTITIONS ); -+#endif -+ -+ return 0; -+} -+module_init(tx4938ndfmc_init); -+ -+/* -+ * Clean up routine -+ */ -+static void __exit tx4938ndfmc_cleanup (void) -+{ -+ struct nand_chip *this = (struct nand_chip *) tx4938ndfmc_mtd->priv; -+ -+ /* Unregister the device */ -+#ifdef CONFIG_MTD_CMDLINE_PARTS -+ del_mtd_partitions(tx4938ndfmc_mtd); -+#endif -+ del_mtd_device (tx4938ndfmc_mtd); -+ -+ /* Free the MTD device structure */ -+ kfree (tx4938ndfmc_mtd); -+ -+ /* Free internal data buffer */ -+ kfree (this->data_buf); -+} -+module_exit(tx4938ndfmc_cleanup); -+ -+MODULE_LICENSE("GPL"); -+MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>"); -+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on TX4938 NDFMC"); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nftlcore.c linux/drivers/mtd/nftlcore.c ---- linux-mips-2.4.27/drivers/mtd/nftlcore.c 2003-02-26 01:53:49.000000000 +0100 -+++ linux/drivers/mtd/nftlcore.c 2004-11-19 10:25:11.653237184 +0100 -@@ -1,7 +1,7 @@ - /* Linux driver for NAND Flash Translation Layer */ - /* (c) 1999 Machine Vision Holdings, Inc. */ - /* Author: David Woodhouse <dwmw2@infradead.org> */ --/* $Id$ */ -+/* $Id$ */ - - /* - The contents of this file are distributed under the GNU General -@@ -23,15 +23,13 @@ - #include <linux/slab.h> - #include <linux/sched.h> - #include <linux/init.h> --#include <linux/blkpg.h> -+#include <linux/hdreg.h> - --#ifdef CONFIG_KMOD - #include <linux/kmod.h> --#endif - #include <linux/mtd/mtd.h> - #include <linux/mtd/nand.h> - #include <linux/mtd/nftl.h> --#include <linux/mtd/compatmac.h> -+#include <linux/mtd/blktrans.h> - - /* maximum number of loops while examining next block, to have a - chance to detect consistency problems (they should never happen -@@ -39,187 +37,95 @@ - - #define MAX_LOOPS 10000 - --/* NFTL block device stuff */ --#define MAJOR_NR NFTL_MAJOR --#define DEVICE_REQUEST nftl_request --#define DEVICE_OFF(device) -- -- --#include <linux/blk.h> --#include <linux/hdreg.h> -- --/* Linux-specific block device functions */ -- --/* I _HATE_ the Linux block device setup more than anything else I've ever -- * encountered, except ... -- */ -- --static int nftl_sizes[256]; --static int nftl_blocksizes[256]; -- --/* .. for the Linux partition table handling. */ --struct hd_struct part_table[256]; -- --#if LINUX_VERSION_CODE < 0x20328 --static void dummy_init (struct gendisk *crap) --{} --#endif -- --static struct gendisk nftl_gendisk = { -- major: MAJOR_NR, -- major_name: "nftl", -- minor_shift: NFTL_PARTN_BITS, /* Bits to shift to get real from partition */ -- max_p: (1<<NFTL_PARTN_BITS)-1, /* Number of partitions per real */ --#if LINUX_VERSION_CODE < 0x20328 -- max_nr: MAX_NFTLS, /* maximum number of real */ -- init: dummy_init, /* init function */ --#endif -- part: part_table, /* hd struct */ -- sizes: nftl_sizes, /* block sizes */ --}; -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) --#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT --#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT --#else --#define BLK_INC_USE_COUNT do {} while(0) --#define BLK_DEC_USE_COUNT do {} while(0) --#endif -- --struct NFTLrecord *NFTLs[MAX_NFTLS]; - --static void NFTL_setup(struct mtd_info *mtd) -+static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) - { -- int i; - struct NFTLrecord *nftl; - unsigned long temp; -- int firstfree = -1; -- -- DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n"); - -- for (i = 0; i < MAX_NFTLS; i++) { -- if (!NFTLs[i] && firstfree == -1) -- firstfree = i; -- else if (NFTLs[i] && NFTLs[i]->mtd == mtd) { -- /* This is a Spare Media Header for an NFTL we've already found */ -- DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n"); -+ if (mtd->ecctype != MTD_ECC_RS_DiskOnChip) - return; -- } -- } -- if (firstfree == -1) { -- printk(KERN_WARNING "No more NFTL slot available\n"); -- return; -- } -+ -+ DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name); - - nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL); -+ - if (!nftl) { -- printk(KERN_WARNING "Out of memory for NFTL data structures\n"); -+ printk(KERN_WARNING "NFTL: out of memory for data structures\n"); - return; - } -+ memset(nftl, 0, sizeof(*nftl)); - -- init_MUTEX(&nftl->mutex); -- -- nftl->mtd = mtd; -+ nftl->mbd.mtd = mtd; -+ nftl->mbd.devnum = -1; -+ nftl->mbd.blksize = 512; -+ nftl->mbd.tr = tr; - - if (NFTL_mount(nftl) < 0) { -- printk(KERN_WARNING "Could not mount NFTL device\n"); -+ printk(KERN_WARNING "NFTL: could not mount device\n"); - kfree(nftl); - return; - } - - /* OK, it's a new one. Set up all the data structures. */ --#ifdef PSYCHO_DEBUG -- printk("Found new NFTL nftl%c\n", firstfree + 'a'); --#endif - -- /* linux stuff */ -- nftl->usecount = 0; -+ /* Calculate geometry */ - nftl->cylinders = 1024; - nftl->heads = 16; - - temp = nftl->cylinders * nftl->heads; -- nftl->sectors = nftl->nr_sects / temp; -- if (nftl->nr_sects % temp) { -+ nftl->sectors = nftl->mbd.size / temp; -+ if (nftl->mbd.size % temp) { - nftl->sectors++; - temp = nftl->cylinders * nftl->sectors; -- nftl->heads = nftl->nr_sects / temp; -+ nftl->heads = nftl->mbd.size / temp; - -- if (nftl->nr_sects % temp) { -+ if (nftl->mbd.size % temp) { - nftl->heads++; - temp = nftl->heads * nftl->sectors; -- nftl->cylinders = nftl->nr_sects / temp; -+ nftl->cylinders = nftl->mbd.size / temp; - } - } - -- if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) { -- printk(KERN_WARNING "Cannot calculate an NFTL geometry to " -- "match size of 0x%x.\n", nftl->nr_sects); -- printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", -+ if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { -+ /* -+ Oh no we don't have -+ mbd.size == heads * cylinders * sectors -+ */ -+ printk(KERN_WARNING "NFTL: cannot calculate a geometry to " -+ "match size of 0x%lx.\n", nftl->mbd.size); -+ printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " -+ "(== 0x%lx sects)\n", - nftl->cylinders, nftl->heads , nftl->sectors, -- (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors ); -- -- /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */ -+ (long)nftl->cylinders * (long)nftl->heads * -+ (long)nftl->sectors ); - } -- NFTLs[firstfree] = nftl; -- /* Finally, set up the block device sizes */ -- nftl_sizes[firstfree * 16] = nftl->nr_sects; -- //nftl_blocksizes[firstfree*16] = 512; -- part_table[firstfree * 16].nr_sects = nftl->nr_sects; -- -- nftl_gendisk.nr_real++; -- -- /* partition check ... */ --#if LINUX_VERSION_CODE < 0x20328 -- resetup_one_dev(&nftl_gendisk, firstfree); --#else -- grok_partitions(&nftl_gendisk, firstfree, 1<<NFTL_PARTN_BITS, nftl->nr_sects); --#endif --} -- --static void NFTL_unsetup(int i) --{ -- struct NFTLrecord *nftl = NFTLs[i]; -- -- DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i); -- -- NFTLs[i] = NULL; - -+ if (add_mtd_blktrans_dev(&nftl->mbd)) { - if (nftl->ReplUnitTable) - kfree(nftl->ReplUnitTable); - if (nftl->EUNtable) - kfree(nftl->EUNtable); -- -- nftl_gendisk.nr_real--; - kfree(nftl); --} -- --/* Search the MTD device for NFTL partitions */ --static void NFTL_notify_add(struct mtd_info *mtd) --{ -- DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name); -- -- if (mtd) { -- if (!mtd->read_oob) { -- /* If this MTD doesn't have out-of-band data, -- then there's no point continuing */ -- DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n"); - return; - } -- DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n", -- mtd->read, mtd->size, mtd->erasesize); -- -- NFTL_setup(mtd); -- } -+#ifdef PSYCHO_DEBUG -+ printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a'); -+#endif - } - --static void NFTL_notify_remove(struct mtd_info *mtd) -+static void nftl_remove_dev(struct mtd_blktrans_dev *dev) - { -- int i; -+ struct NFTLrecord *nftl = (void *)dev; - -- for (i = 0; i < MAX_NFTLS; i++) { -- if (NFTLs[i] && NFTLs[i]->mtd == mtd) -- NFTL_unsetup(i); -- } -+ DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum); -+ -+ del_mtd_blktrans_dev(dev); -+ if (nftl->ReplUnitTable) -+ kfree(nftl->ReplUnitTable); -+ if (nftl->EUNtable) -+ kfree(nftl->EUNtable); -+ kfree(nftl); - } - - #ifdef CONFIG_NFTL_RW -@@ -303,7 +209,7 @@ - - targetEUN = thisEUN; - for (block = 0; block < nftl->EraseSize / 512; block ++) { -- MTD_READOOB(nftl->mtd, -+ MTD_READOOB(nftl->mbd.mtd, - (thisEUN * nftl->EraseSize) + (block * 512), - 16 , &retlen, (char *)&oob); - if (block == 2) { -@@ -420,7 +326,7 @@ - chain by selecting the longer one */ - oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); - oob.u.c.unused = 0xffffffff; -- MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, -+ MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, - 8, &retlen, (char *)&oob.u); - } - -@@ -444,16 +350,16 @@ - if (BlockMap[block] == BLOCK_NIL) - continue; - -- ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), -+ ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), - 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); - if (ret < 0) { -- ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) -+ ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) - + (block * 512), 512, &retlen, - movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); - if (ret != -EIO) - printk("Error went away on retry.\n"); - } -- MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512), -+ MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), - 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); - } - -@@ -462,7 +368,7 @@ - = cpu_to_le16(thisVUC); - oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; - -- MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8, -+ MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, - 8, &retlen, (char *)&oob.u); - - /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ -@@ -582,7 +488,7 @@ - - lastEUN = writeEUN; - -- MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs, -+ MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, - 8, &retlen, (char *)&bci); - - DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", -@@ -670,12 +576,12 @@ - nftl->ReplUnitTable[writeEUN] = BLOCK_NIL; - - /* ... and on the flash itself */ -- MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8, -+ MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8, - &retlen, (char *)&oob.u); - - oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); - -- MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8, -+ MTD_WRITEOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8, - &retlen, (char *)&oob.u); - - /* we link the new block to the chain only after the -@@ -685,13 +591,13 @@ - /* Both in our cache... */ - nftl->ReplUnitTable[lastEUN] = writeEUN; - /* ... and on the flash itself */ -- MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8, -+ MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8, - 8, &retlen, (char *)&oob.u); - - oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum - = cpu_to_le16(writeEUN); - -- MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8, -+ MTD_WRITEOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8, - 8, &retlen, (char *)&oob.u); - } - -@@ -704,8 +610,10 @@ - return 0xffff; - } - --static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer) -+static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, -+ char *buffer) - { -+ struct NFTLrecord *nftl = (void *)mbd; - u16 writeEUN; - unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); - size_t retlen; -@@ -720,7 +628,7 @@ - return 1; - } - -- MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs, -+ MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, - 512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP); - /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */ - -@@ -728,8 +636,10 @@ - } - #endif /* CONFIG_NFTL_RW */ - --static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer) -+static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, -+ char *buffer) - { -+ struct NFTLrecord *nftl = (void *)mbd; - u16 lastgoodEUN; - u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)]; - unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); -@@ -742,7 +652,7 @@ - - if (thisEUN != BLOCK_NIL) { - while (thisEUN < nftl->nb_blocks) { -- if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs, -+ if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs, - 8, &retlen, (char *)&bci) < 0) - status = SECTOR_IGNORE; - else -@@ -761,13 +671,13 @@ - case SECTOR_IGNORE: - break; - default: -- printk("Unknown status for block %d in EUN %d: %x\n", -+ printk("Unknown status for block %ld in EUN %d: %x\n", - block, thisEUN, status); - break; - } - - if (!silly--) { -- printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", -+ printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n", - block / (nftl->EraseSize / 512)); - return 1; - } -@@ -783,264 +693,22 @@ - loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs; - size_t retlen; - u_char eccbuf[6]; -- if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP)) -+ if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP)) - return -EIO; - } - return 0; - } - --static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) --{ -- struct NFTLrecord *nftl; -- int p; -- -- nftl = NFTLs[MINOR(inode->i_rdev) >> NFTL_PARTN_BITS]; -- -- if (!nftl) return -EINVAL; -- -- switch (cmd) { -- case HDIO_GETGEO: { -- struct hd_geometry g; -- -- g.heads = nftl->heads; -- g.sectors = nftl->sectors; -- g.cylinders = nftl->cylinders; -- g.start = part_table[MINOR(inode->i_rdev)].start_sect; -- return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; -- } -- case BLKGETSIZE: /* Return device size */ -- return put_user(part_table[MINOR(inode->i_rdev)].nr_sects, -- (unsigned long *) arg); -- --#ifdef BLKGETSIZE64 -- case BLKGETSIZE64: -- return put_user((u64)part_table[MINOR(inode->i_rdev)].nr_sects << 9, -- (u64 *)arg); --#endif -- -- case BLKFLSBUF: -- if (!capable(CAP_SYS_ADMIN)) return -EACCES; -- fsync_dev(inode->i_rdev); -- invalidate_buffers(inode->i_rdev); -- if (nftl->mtd->sync) -- nftl->mtd->sync(nftl->mtd); -- return 0; -- -- case BLKRRPART: -- if (!capable(CAP_SYS_ADMIN)) return -EACCES; -- if (nftl->usecount > 1) return -EBUSY; -- /* -- * We have to flush all buffers and invalidate caches, -- * or we won't be able to re-use the partitions, -- * if there was a change and we don't want to reboot -- */ -- p = (1<<NFTL_PARTN_BITS) - 1; -- while (p-- > 0) { -- kdev_t devp = MKDEV(MAJOR(inode->i_dev), MINOR(inode->i_dev)+p); -- if (part_table[p].nr_sects > 0) -- invalidate_device (devp, 1); -- -- part_table[MINOR(inode->i_dev)+p].start_sect = 0; -- part_table[MINOR(inode->i_dev)+p].nr_sects = 0; -- } -- --#if LINUX_VERSION_CODE < 0x20328 -- resetup_one_dev(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS); --#else -- grok_partitions(&nftl_gendisk, MINOR(inode->i_rdev) >> NFTL_PARTN_BITS, -- 1<<NFTL_PARTN_BITS, nftl->nr_sects); --#endif -- return 0; -- --#if (LINUX_VERSION_CODE < 0x20303) -- RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */ --#else -- case BLKROSET: -- case BLKROGET: -- case BLKSSZGET: -- return blk_ioctl(inode->i_rdev, cmd, arg); --#endif -- -- default: -- return -EINVAL; -- } --} -- --void nftl_request(RQFUNC_ARG) --{ -- unsigned int dev, block, nsect; -- struct NFTLrecord *nftl; -- char *buffer; -- struct request *req; -- int res; -- -- while (1) { -- INIT_REQUEST; /* blk.h */ -- req = CURRENT; -- -- /* We can do this because the generic code knows not to -- touch the request at the head of the queue */ -- spin_unlock_irq(&io_request_lock); -- -- DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n"); -- DEBUG(MTD_DEBUG_LEVEL3, "NFTL %s request, from sector 0x%04lx for 0x%04lx sectors\n", -- (req->cmd == READ) ? "Read " : "Write", -- req->sector, req->current_nr_sectors); -- -- dev = MINOR(req->rq_dev); -- block = req->sector; -- nsect = req->current_nr_sectors; -- buffer = req->buffer; -- res = 1; /* succeed */ -- -- if (dev >= MAX_NFTLS * (1<<NFTL_PARTN_BITS)) { -- /* there is no such partition */ -- printk("nftl: bad minor number: device = %s\n", -- kdevname(req->rq_dev)); -- res = 0; /* fail */ -- goto repeat; -- } -- -- nftl = NFTLs[dev / (1<<NFTL_PARTN_BITS)]; -- DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n"); -- down(&nftl->mutex); -- DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n"); -- -- if (block + nsect > part_table[dev].nr_sects) { -- /* access past the end of device */ -- printk("nftl%c%d: bad access: block = %d, count = %d\n", -- (MINOR(req->rq_dev)>>6)+'a', dev & 0xf, block, nsect); -- up(&nftl->mutex); -- res = 0; /* fail */ -- goto repeat; -- } -- -- block += part_table[dev].start_sect; -- -- if (req->cmd == READ) { -- DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x " -- "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors); -- -- for ( ; nsect > 0; nsect-- , block++, buffer += 512) { -- /* Read a single sector to req->buffer + (512 * i) */ -- if (NFTL_readblock(nftl, block, buffer)) { -- DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n"); -- up(&nftl->mutex); -- res = 0; -- goto repeat; -- } -- } -- -- DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n"); -- up(&nftl->mutex); -- goto repeat; -- } else if (req->cmd == WRITE) { -- DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x " -- "(req->nr_sectors == %lx)\n", nsect, block, -- req->nr_sectors); --#ifdef CONFIG_NFTL_RW -- for ( ; nsect > 0; nsect-- , block++, buffer += 512) { -- /* Read a single sector to req->buffer + (512 * i) */ -- if (NFTL_writeblock(nftl, block, buffer)) { -- DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n"); -- up(&nftl->mutex); -- res = 0; -- goto repeat; -- } -- } -- DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n"); --#else -- res = 0; /* Writes always fail */ --#endif /* CONFIG_NFTL_RW */ -- up(&nftl->mutex); -- goto repeat; -- } else { -- DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n"); -- up(&nftl->mutex); -- res = 0; -- goto repeat; -- } -- repeat: -- DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res); -- spin_lock_irq(&io_request_lock); -- end_request(res); -- } --} -- --static int nftl_open(struct inode *ip, struct file *fp) --{ -- int nftlnum = MINOR(ip->i_rdev) >> NFTL_PARTN_BITS; -- struct NFTLrecord *thisNFTL; -- thisNFTL = NFTLs[nftlnum]; -- -- DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n"); -- --#ifdef CONFIG_KMOD -- if (!thisNFTL && nftlnum == 0) { -- request_module("docprobe"); -- thisNFTL = NFTLs[nftlnum]; -- } --#endif -- if (!thisNFTL) { -- DEBUG(MTD_DEBUG_LEVEL2,"ENODEV: thisNFTL = %d, minor = %d, ip = %p, fp = %p\n", -- nftlnum, ip->i_rdev, ip, fp); -- return -ENODEV; -- } -- --#ifndef CONFIG_NFTL_RW -- if (fp->f_mode & FMODE_WRITE) -- return -EROFS; --#endif /* !CONFIG_NFTL_RW */ -- -- thisNFTL->usecount++; -- BLK_INC_USE_COUNT; -- if (!get_mtd_device(thisNFTL->mtd, -1)) { -- BLK_DEC_USE_COUNT; -- return -ENXIO; -- } -- -- return 0; --} -- --static int nftl_release(struct inode *inode, struct file *fp) -+static int nftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo) - { -- struct NFTLrecord *thisNFTL; -- -- thisNFTL = NFTLs[MINOR(inode->i_rdev) / 16]; -- -- DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); -- -- if (thisNFTL->mtd->sync) -- thisNFTL->mtd->sync(thisNFTL->mtd); -- thisNFTL->usecount--; -- BLK_DEC_USE_COUNT; -+ struct NFTLrecord *nftl = (void *)dev; - -- put_mtd_device(thisNFTL->mtd); -+ geo->heads = nftl->heads; -+ geo->sectors = nftl->sectors; -+ geo->cylinders = nftl->cylinders; - - return 0; - } --#if LINUX_VERSION_CODE < 0x20326 --static struct file_operations nftl_fops = { -- read: block_read, -- write: block_write, -- ioctl: nftl_ioctl, -- open: nftl_open, -- release: nftl_release, -- fsync: block_fsync, --}; --#else --static struct block_device_operations nftl_fops = --{ --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14) -- owner: THIS_MODULE, --#endif -- open: nftl_open, -- release: nftl_release, -- ioctl: nftl_ioctl --}; --#endif -- -- - - /**************************************************************************** - * -@@ -1048,49 +716,33 @@ - * - ****************************************************************************/ - --static struct mtd_notifier nftl_notifier = { -- add: NFTL_notify_add, -- remove: NFTL_notify_remove -+ -+struct mtd_blktrans_ops nftl_tr = { -+ .name = "nftl", -+ .major = NFTL_MAJOR, -+ .part_bits = NFTL_PARTN_BITS, -+ .getgeo = nftl_getgeo, -+ .readsect = nftl_readblock, -+#ifdef CONFIG_NFTL_RW -+ .writesect = nftl_writeblock, -+#endif -+ .add_mtd = nftl_add_mtd, -+ .remove_dev = nftl_remove_dev, -+ .owner = THIS_MODULE, - }; - - extern char nftlmountrev[]; - - int __init init_nftl(void) - { -- int i; -- --#ifdef PRERELEASE -- printk(KERN_INFO "NFTL driver: nftlcore.c $Revision$, nftlmount.c %s\n", nftlmountrev); --#endif -- -- if (register_blkdev(MAJOR_NR, "nftl", &nftl_fops)){ -- printk("unable to register NFTL block device on major %d\n", MAJOR_NR); -- return -EBUSY; -- } else { -- blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &nftl_request); -+ printk(KERN_INFO "NFTL driver: nftlcore.c $Revision$, nftlmount.c %s\n", nftlmountrev); - -- /* set block size to 1kB each */ -- for (i = 0; i < 256; i++) { -- nftl_blocksizes[i] = 1024; -- } -- blksize_size[MAJOR_NR] = nftl_blocksizes; -- -- add_gendisk(&nftl_gendisk); -- } -- -- register_mtd_user(&nftl_notifier); -- -- return 0; -+ return register_mtd_blktrans(&nftl_tr); - } - - static void __exit cleanup_nftl(void) - { -- unregister_mtd_user(&nftl_notifier); -- unregister_blkdev(MAJOR_NR, "nftl"); -- -- blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); -- -- del_gendisk(&nftl_gendisk); -+ deregister_mtd_blktrans(&nftl_tr); - } - - module_init(init_nftl); -diff -Nurb linux-mips-2.4.27/drivers/mtd/nftlmount.c linux/drivers/mtd/nftlmount.c ---- linux-mips-2.4.27/drivers/mtd/nftlmount.c 2003-07-05 05:23:38.000000000 +0200 -+++ linux/drivers/mtd/nftlmount.c 2004-11-19 10:25:11.655236880 +0100 -@@ -4,7 +4,7 @@ - * Author: Fabrice Bellard (fabrice.bellard@netgem.com) - * Copyright (C) 2000 Netgem S.A. - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by -@@ -21,26 +21,17 @@ - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - --#define __NO_VERSION__ - #include <linux/kernel.h> --#include <linux/module.h> - #include <asm/errno.h> --#include <asm/io.h> --#include <asm/uaccess.h> --#include <linux/miscdevice.h> --#include <linux/pci.h> - #include <linux/delay.h> - #include <linux/slab.h> --#include <linux/sched.h> --#include <linux/init.h> - #include <linux/mtd/mtd.h> - #include <linux/mtd/nand.h> - #include <linux/mtd/nftl.h> --#include <linux/mtd/compatmac.h> - - #define SECTORSIZE 512 - --char nftlmountrev[]="$Revision$"; -+char nftlmountrev[]="$Revision$"; - - /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the - * various device information of the NFTL partition and Bad Unit Table. Update -@@ -59,8 +50,8 @@ - - /* Assume logical EraseSize == physical erasesize for starting the scan. - We'll sort it out later if we find a MediaHeader which says otherwise */ -- nftl->EraseSize = nftl->mtd->erasesize; -- nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize; -+ nftl->EraseSize = nftl->mbd.mtd->erasesize; -+ nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; - - nftl->MediaUnit = BLOCK_NIL; - nftl->SpareMediaUnit = BLOCK_NIL; -@@ -71,12 +62,12 @@ - - /* Check for ANAND header first. Then can whinge if it's found but later - checks fail */ -- if ((ret = MTD_READ(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) { -+ if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) { - static int warncount = 5; - - if (warncount) { - printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n", -- block * nftl->EraseSize, nftl->mtd->index, ret); -+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret); - if (!--warncount) - printk(KERN_WARNING "Further failures for this block will not be printed\n"); - } -@@ -87,16 +78,16 @@ - /* ANAND\0 not found. Continue */ - #if 0 - printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", -- block * nftl->EraseSize, nftl->mtd->index); -+ block * nftl->EraseSize, nftl->mbd.mtd->index); - #endif - continue; - } - - /* To be safer with BIOS, also use erase mark as discriminant */ -- if ((ret = MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, -- 8, &retlen, (char *)&h1)) < 0) { -+ if ((ret = MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, -+ 8, &retlen, (char *)&h1) < 0)) { - printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n", -- block * nftl->EraseSize, nftl->mtd->index, ret); -+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret); - continue; - } - -@@ -106,23 +97,23 @@ - */ - if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { - printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", -- block * nftl->EraseSize, nftl->mtd->index, -+ block * nftl->EraseSize, nftl->mbd.mtd->index, - le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); - continue; - } - - /* Finally reread to check ECC */ -- if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, -- &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) { -+ if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, -+ &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) { - printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n", -- block * nftl->EraseSize, nftl->mtd->index, ret); -+ block * nftl->EraseSize, nftl->mbd.mtd->index, ret); - continue; - } - - /* Paranoia. Check the ANAND header is still there after the ECC read */ - if (memcmp(buf, "ANAND", 6)) { - printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n", -- block * nftl->EraseSize, nftl->mtd->index); -+ block * nftl->EraseSize, nftl->mbd.mtd->index); - printk(KERN_NOTICE "New data are: %02x %02x %02x %02x %02x %02x\n", - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); - continue; -@@ -137,8 +128,12 @@ - printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n", - nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize); - /* if (debug) Print both side by side */ -+ if (boot_record_count < 2) { -+ /* We haven't yet seen two real ones */ - return -1; - } -+ continue; -+ } - if (boot_record_count == 1) - nftl->SpareMediaUnit = block; - -@@ -163,8 +158,8 @@ - } else if (mh->UnitSizeFactor != 0xff) { - printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n", - mh->UnitSizeFactor); -- nftl->EraseSize = nftl->mtd->erasesize << (0xff - mh->UnitSizeFactor); -- nftl->nb_blocks = nftl->mtd->size / nftl->EraseSize; -+ nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor); -+ nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; - } - nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); - if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { -@@ -182,7 +177,7 @@ - return -1; - } - -- nftl->nr_sects = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); -+ nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); - - /* If we're not using the last sectors in the device for some reason, - reduce nb_blocks accordingly so we forget they're there */ -@@ -220,7 +215,7 @@ - for (i = 0; i < nftl->nb_blocks; i++) { - if ((i & (SECTORSIZE - 1)) == 0) { - /* read one sector for every SECTORSIZE of blocks */ -- if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize + -+ if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize + - i + SECTORSIZE, SECTORSIZE, &retlen, buf, - (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) { - printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n", -@@ -263,16 +258,16 @@ - for (i = 0; i < len; i += SECTORSIZE) { - /* we want to read the sector without ECC check here since a free - sector does not have ECC syndrome on it yet */ -- if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0) -+ if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0) - return -1; - if (memcmpb(buf, 0xff, SECTORSIZE) != 0) - return -1; - - if (check_oob) { -- if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize, -+ if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize, - &retlen, buf) < 0) - return -1; -- if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0) -+ if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0) - return -1; - } - address += SECTORSIZE; -@@ -297,7 +292,7 @@ - struct erase_info *instr = &nftl->instr; - - /* Read the Unit Control Information #1 for Wear-Leveling */ -- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, -+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, - 8, &retlen, (char *)&uci) < 0) - goto default_uci1; - -@@ -314,7 +309,7 @@ - /* XXX: use async erase interface, XXX: test return code */ - instr->addr = block * nftl->EraseSize; - instr->len = nftl->EraseSize; -- MTD_ERASE(nftl->mtd, instr); -+ MTD_ERASE(nftl->mbd.mtd, instr); - - if (instr->state == MTD_ERASE_FAILED) { - /* could not format, FixMe: We should update the BadUnitTable -@@ -337,7 +332,7 @@ - return -1; - - uci.WearInfo = le32_to_cpu(nb_erases); -- if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, -+ if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, - &retlen, (char *)&uci) < 0) - return -1; - return 0; -@@ -363,7 +358,7 @@ - block = first_block; - for (;;) { - for (i = 0; i < sectors_per_block; i++) { -- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE, -+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE, - 8, &retlen, (char *)&bci) < 0) - status = SECTOR_IGNORE; - else -@@ -383,7 +378,7 @@ - /* sector not free actually : mark it as SECTOR_IGNORE */ - bci.Status = SECTOR_IGNORE; - bci.Status1 = SECTOR_IGNORE; -- MTD_WRITEOOB(nftl->mtd, -+ MTD_WRITEOOB(nftl->mbd.mtd, - block * nftl->EraseSize + i * SECTORSIZE, - 8, &retlen, (char *)&bci); - } -@@ -476,7 +471,7 @@ - size_t retlen; - - /* check erase mark. */ -- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, -+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, - &retlen, (char *)&h1) < 0) - return -1; - -@@ -491,7 +486,7 @@ - h1.EraseMark = cpu_to_le16(ERASE_MARK); - h1.EraseMark1 = cpu_to_le16(ERASE_MARK); - h1.WearInfo = cpu_to_le32(0); -- if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, -+ if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, - &retlen, (char *)&h1) < 0) - return -1; - } else { -@@ -503,7 +498,7 @@ - SECTORSIZE, 0) != 0) - return -1; - -- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i, -+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i, - 16, &retlen, buf) < 0) - return -1; - if (i == SECTORSIZE) { -@@ -533,7 +528,7 @@ - struct nftl_uci2 uci; - size_t retlen; - -- if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8, -+ if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8, - 8, &retlen, (char *)&uci) < 0) - return 0; - -@@ -572,9 +567,9 @@ - - for (;;) { - /* read the block header. If error, we format the chain */ -- if (MTD_READOOB(s->mtd, block * s->EraseSize + 8, 8, -+ if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, - &retlen, (char *)&h0) < 0 || -- MTD_READOOB(s->mtd, block * s->EraseSize + SECTORSIZE + 8, 8, -+ MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, - &retlen, (char *)&h1) < 0) { - s->ReplUnitTable[block] = BLOCK_NIL; - do_format_chain = 1; -diff -Nurb linux-mips-2.4.27/drivers/mtd/redboot.c linux/drivers/mtd/redboot.c ---- linux-mips-2.4.27/drivers/mtd/redboot.c 2001-12-02 12:34:42.000000000 +0100 -+++ linux/drivers/mtd/redboot.c 2004-11-19 10:25:11.656236728 +0100 -@@ -1,5 +1,5 @@ - /* -- * $Id$ -+ * $Id$ - * - * Parse RedBoot-style Flash Image System (FIS) tables and - * produce a Linux partition array to match. -@@ -7,6 +7,7 @@ - - #include <linux/kernel.h> - #include <linux/slab.h> -+#include <linux/init.h> - - #include <linux/mtd/mtd.h> - #include <linux/mtd/partitions.h> -@@ -34,7 +35,9 @@ - return 1; - } - --int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts) -+static int parse_redboot_partitions(struct mtd_info *master, -+ struct mtd_partition **pparts, -+ unsigned long fis_origin) - { - int nrparts = 0; - struct fis_image_desc *buf; -@@ -43,7 +46,9 @@ - int ret, i; - size_t retlen; - char *names; -+ char *nullname; - int namelen = 0; -+ static char nullstring[] = "unallocated"; - - buf = kmalloc(PAGE_SIZE, GFP_KERNEL); - -@@ -90,7 +95,11 @@ - goto out; - } - new_fl->img = &buf[i]; -+ if (fis_origin) { -+ buf[i].flash_base -= fis_origin; -+ } else { - buf[i].flash_base &= master->size-1; -+ } - - /* I'm sure the JFFS2 code has done me permanent damage. - * I now think the following is _normal_ -@@ -110,18 +119,24 @@ - if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base) - nrparts++; - } -- parts = kmalloc(sizeof(*parts)*nrparts + namelen, GFP_KERNEL); -+ parts = kmalloc(sizeof(*parts)*nrparts + sizeof(nullstring) + namelen, GFP_KERNEL); - - if (!parts) { - ret = -ENOMEM; - goto out; - } -- names = (char *)&parts[nrparts]; -+ - memset(parts, 0, sizeof(*parts)*nrparts + namelen); -+ -+ /* FIXME: Include nullname only if it's used */ -+ nullname = (char *)&parts[nrparts]; -+ sprintf(nullname, nullstring); -+ names = nullname + sizeof(nullstring); -+ - i=0; - - if (fl->img->flash_base) { -- parts[0].name = "unallocated space"; -+ parts[0].name = nullname; - parts[0].size = fl->img->flash_base; - parts[0].offset = 0; - } -@@ -133,11 +148,11 @@ - strcpy(names, fl->img->name); - names += strlen(names)+1; - -- if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize < fl->next->img->flash_base) { -+ if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) { - i++; - parts[i].offset = parts[i-1].size + parts[i-1].offset; - parts[i].size = fl->next->img->flash_base - parts[i].offset; -- parts[i].name = "unallocated space"; -+ parts[i].name = nullname; - } - tmp_fl = fl; - fl = fl->next; -@@ -155,7 +170,24 @@ - return ret; - } - --EXPORT_SYMBOL(parse_redboot_partitions); -+static struct mtd_part_parser redboot_parser = { -+ .owner = THIS_MODULE, -+ .parse_fn = parse_redboot_partitions, -+ .name = "RedBoot", -+}; -+ -+static int __init redboot_parser_init(void) -+{ -+ return register_mtd_parser(&redboot_parser); -+} -+ -+static void __exit redboot_parser_exit(void) -+{ -+ deregister_mtd_parser(&redboot_parser); -+} -+ -+module_init(redboot_parser_init); -+module_exit(redboot_parser_exit); - - MODULE_LICENSE("GPL"); - MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>"); -diff -Nurb linux-mips-2.4.27/fs/Config.in linux/fs/Config.in ---- linux-mips-2.4.27/fs/Config.in 2004-02-20 02:22:19.000000000 +0100 -+++ linux/fs/Config.in 2004-11-19 10:25:12.229149632 +0100 -@@ -49,6 +49,7 @@ - dep_tristate 'Journalling Flash File System v2 (JFFS2) support' CONFIG_JFFS2_FS $CONFIG_MTD - if [ "$CONFIG_JFFS2_FS" = "y" -o "$CONFIG_JFFS2_FS" = "m" ] ; then - int 'JFFS2 debugging verbosity (0 = quiet, 2 = noisy)' CONFIG_JFFS2_FS_DEBUG 0 -+ bool 'JFFS2 support for NAND chips' CONFIG_JFFS2_FS_NAND - fi - tristate 'Compressed ROM file system support' CONFIG_CRAMFS - bool 'Virtual memory file system support (former shm fs)' CONFIG_TMPFS -diff -Nurb linux-mips-2.4.27/fs/jffs2/Makefile linux/fs/jffs2/Makefile ---- linux-mips-2.4.27/fs/jffs2/Makefile 2003-08-13 19:19:25.000000000 +0200 -+++ linux/fs/jffs2/Makefile 2004-11-19 10:25:12.071173648 +0100 -@@ -1,7 +1,7 @@ - # - # Makefile for the linux Journalling Flash FileSystem (JFFS) routines. - # --# $Id$ -+# $Id$ - # - # Note! Dependencies are done automagically by 'make dep', which also - # removes any old dependencies. DON'T put your own dependencies here -@@ -10,16 +10,31 @@ - # Note 2! The CFLAGS definitions are now in the main makefile... - - --COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o pushpull.o \ -- compr_zlib.o -+obj-$(CONFIG_JFFS2_FS) := jffs2.o -+ -+COMPR_OBJS := compr.o compr_rubin.o compr_rtime.o compr_zlib.o - JFFS2_OBJS := dir.o file.o ioctl.o nodelist.o malloc.o \ -- read.o nodemgmt.o readinode.o super.o write.o scan.o gc.o \ -- symlink.o build.o erase.o background.o -+ read.o nodemgmt.o readinode.o write.o scan.o gc.o \ -+ symlink.o build.o erase.o background.o fs.o writev.o - --O_TARGET := jffs2.o -+BELOW25 := $(shell echo $(PATCHLEVEL) | sed s/[1234]/y/) -+ -+ifeq ($(BELOW25),y) -+LINUX_OBJS := super-v24.o crc32.o rbtree.o -+else -+LINUX_OBJS := super.o -+endif - --obj-y := $(COMPR_OBJS) $(JFFS2_OBJS) --obj-m := $(O_TARGET) -+NAND_OBJS-$(CONFIG_JFFS2_FS_NAND) := wbuf.o - -+jffs2-objs := $(COMPR_OBJS) $(JFFS2_OBJS) $(VERS_OBJS) $(NAND_OBJS-y) \ -+ $(LINUX_OBJS) -+ -+ -+# 2.4 build compatibility -+ifeq ($(BELOW25),y) -+obj-y := $(jffs2-objs) -+O_TARGET := jffs2.o - include $(TOPDIR)/Rules.make -+endif - -diff -Nurb linux-mips-2.4.27/fs/jffs2/background.c linux/fs/jffs2/background.c ---- linux-mips-2.4.27/fs/jffs2/background.c 2001-11-06 08:56:10.000000000 +0100 -+++ linux/fs/jffs2/background.c 2004-11-19 10:25:12.072173496 +0100 -@@ -1,61 +1,36 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #define __KERNEL_SYSCALLS__ - - #include <linux/kernel.h> --#include <linux/sched.h> --#include <linux/unistd.h> - #include <linux/jffs2.h> - #include <linux/mtd/mtd.h> --#include <linux/interrupt.h> - #include <linux/completion.h> -+#include <linux/sched.h> -+#include <linux/unistd.h> -+#include <linux/suspend.h> - #include "nodelist.h" - - - static int jffs2_garbage_collect_thread(void *); --static int thread_should_wake(struct jffs2_sb_info *c); - - void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) - { -- spin_lock_bh(&c->erase_completion_lock); -- if (c->gc_task && thread_should_wake(c)) -+ spin_lock(&c->erase_completion_lock); -+ if (c->gc_task && jffs2_thread_should_wake(c)) - send_sig(SIGHUP, c->gc_task, 1); -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - } - - /* This must only ever be called when no GC thread is currently running */ -@@ -86,12 +61,12 @@ - - void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c) - { -- spin_lock_bh(&c->erase_completion_lock); -+ spin_lock(&c->erase_completion_lock); - if (c->gc_task) { - D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); - send_sig(SIGKILL, c->gc_task, 1); - } -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - wait_for_completion(&c->gc_thread_exit); - } - -@@ -99,34 +74,37 @@ - { - struct jffs2_sb_info *c = _c; - -- daemonize(); -- current->tty = NULL; -+ daemonize("jffs2_gcd_mtd%d", c->mtd->index); -+ allow_signal(SIGKILL); -+ allow_signal(SIGSTOP); -+ allow_signal(SIGCONT); -+ - c->gc_task = current; - up(&c->gc_thread_start); - -- sprintf(current->comm, "jffs2_gcd_mtd%d", c->mtd->index); -- -- /* FIXME in the 2.2 backport */ -- current->nice = 10; -+ set_user_nice(current, 10); - - for (;;) { -- spin_lock_irq(¤t->sigmask_lock); -- siginitsetinv (¤t->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); -- recalc_sigpending(current); -- spin_unlock_irq(¤t->sigmask_lock); -+ allow_signal(SIGHUP); - -- if (!thread_should_wake(c)) { -+ if (!jffs2_thread_should_wake(c)) { - set_current_state (TASK_INTERRUPTIBLE); - D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread sleeping...\n")); -- /* Yes, there's a race here; we checked thread_should_wake() before -- setting current->state to TASK_INTERRUPTIBLE. But it doesn't -+ /* Yes, there's a race here; we checked jffs2_thread_should_wake() -+ before setting current->state to TASK_INTERRUPTIBLE. But it doesn't - matter - We don't care if we miss a wakeup, because the GC thread - is only an optimisation anyway. */ - schedule(); - } - -- if (current->need_resched) -- schedule(); -+ if (current->flags & PF_FREEZE) { -+ refrigerator(0); -+ /* refrigerator() should recalc sigpending for us -+ but doesn't. No matter - allow_signal() will. */ -+ continue; -+ } -+ -+ cond_resched(); - - /* Put_super will send a SIGKILL and then wait on the sem. - */ -@@ -134,9 +112,7 @@ - siginfo_t info; - unsigned long signr; - -- spin_lock_irq(¤t->sigmask_lock); -- signr = dequeue_signal(¤t->blocked, &info); -- spin_unlock_irq(¤t->sigmask_lock); -+ signr = dequeue_signal_lock(current, ¤t->blocked, &info); - - switch(signr) { - case SIGSTOP: -@@ -147,9 +123,10 @@ - - case SIGKILL: - D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n")); -- spin_lock_bh(&c->erase_completion_lock); -+ die: -+ spin_lock(&c->erase_completion_lock); - c->gc_task = NULL; -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - complete_and_exit(&c->gc_thread_exit, 0); - - case SIGHUP: -@@ -157,27 +134,15 @@ - break; - default: - D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): signal %ld received\n", signr)); -- - } - } - /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */ -- spin_lock_irq(¤t->sigmask_lock); -- siginitsetinv (¤t->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT)); -- recalc_sigpending(current); -- spin_unlock_irq(¤t->sigmask_lock); -+ disallow_signal(SIGHUP); - - D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n")); -- jffs2_garbage_collect_pass(c); -+ if (jffs2_garbage_collect_pass(c) == -ENOSPC) { -+ printk(KERN_NOTICE "No space for garbage collection. Aborting GC thread\n"); -+ goto die; -+ } - } --} -- --static int thread_should_wake(struct jffs2_sb_info *c) --{ -- D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x\n", -- c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size)); -- if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && -- c->dirty_size > c->sector_size) -- return 1; -- else -- return 0; - } -diff -Nurb linux-mips-2.4.27/fs/jffs2/build.c linux/fs/jffs2/build.c ---- linux-mips-2.4.27/fs/jffs2/build.c 2003-07-05 05:23:44.000000000 +0200 -+++ linux/fs/jffs2/build.c 2004-11-19 10:25:12.073173344 +0100 -@@ -1,47 +1,22 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/kernel.h> --#include <linux/jffs2.h> -+#include <linux/sched.h> - #include <linux/slab.h> - #include "nodelist.h" - --int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *); --int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *); -+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **); - - static inline struct jffs2_inode_cache * - first_inode_chain(int *i, struct jffs2_sb_info *c) -@@ -68,16 +43,52 @@ - ic; \ - ic = next_inode(&i, ic, (c))) - -+ -+static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) -+{ -+ struct jffs2_full_dirent *fd; -+ -+ D1(printk(KERN_DEBUG "jffs2_build_inode building directory inode #%u\n", ic->ino)); -+ -+ /* For each child, increase nlink */ -+ for(fd = ic->scan_dents; fd; fd = fd->next) { -+ struct jffs2_inode_cache *child_ic; -+ if (!fd->ino) -+ continue; -+ -+ /* XXX: Can get high latency here with huge directories */ -+ -+ child_ic = jffs2_get_ino_cache(c, fd->ino); -+ if (!child_ic) { -+ printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", -+ fd->name, fd->ino, ic->ino); -+ continue; -+ } -+ -+ if (child_ic->nlink++ && fd->type == DT_DIR) { -+ 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); -+ if (fd->ino == 1 && ic->ino == 1) { -+ printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n"); -+ printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n"); -+ } -+ /* What do we do about it? */ -+ } -+ D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino)); -+ /* Can't free them. We might need them in pass 2 */ -+ } -+} -+ - /* Scan plan: - - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go - - Scan directory tree from top down, setting nlink in inocaches - - Scan inocaches for inodes with nlink==0 - */ --int jffs2_build_filesystem(struct jffs2_sb_info *c) -+static int jffs2_build_filesystem(struct jffs2_sb_info *c) - { - int ret; - int i; - struct jffs2_inode_cache *ic; -+ struct jffs2_full_dirent *dead_fds = NULL; - - /* First, scan the medium and build all the inode caches with - lists of physical nodes */ -@@ -90,14 +101,17 @@ - return ret; - - D1(printk(KERN_DEBUG "Scanned flash completely\n")); -- /* Now build the data map for each inode, marking obsoleted nodes -- as such, and also increase nlink of any children. */ -+ D1(jffs2_dump_block_lists(c)); -+ -+ /* Now scan the directory tree, increasing nlink according to every dirent found. */ - for_each_inode(i, c, ic) { - D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino)); -- ret = jffs2_build_inode_pass1(c, ic); -- if (ret) { -- D1(printk(KERN_WARNING "Eep. jffs2_build_inode_pass1 for ino %d returned %d\n", ic->ino, ret)); -- return ret; -+ -+ D1(BUG_ON(ic->ino > c->highest_ino)); -+ -+ if (ic->scan_dents) { -+ jffs2_build_inode_pass1(c, ic); -+ cond_resched(); - } - } - D1(printk(KERN_DEBUG "Pass 1 complete\n")); -@@ -107,181 +121,226 @@ - children too, and repeat the scan. As that's going to be - a fairly uncommon occurrence, it's not so evil to do it this - way. Recursion bad. */ -- do { -- D1(printk(KERN_DEBUG "Pass 2 (re)starting\n")); -- ret = 0; -+ D1(printk(KERN_DEBUG "Pass 2 starting\n")); -+ - for_each_inode(i, c, ic) { - D1(printk(KERN_DEBUG "Pass 2: ino #%u, nlink %d, ic %p, nodes %p\n", ic->ino, ic->nlink, ic, ic->nodes)); - if (ic->nlink) - continue; - -- ret = jffs2_build_remove_unlinked_inode(c, ic); -- if (ret) -- break; -- /* -EAGAIN means the inode's nlink was zero, so we deleted it, -- and furthermore that it had children and their nlink has now -- gone to zero too. So we have to restart the scan. */ -+ jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); -+ cond_resched(); -+ } -+ -+ D1(printk(KERN_DEBUG "Pass 2a starting\n")); -+ -+ while (dead_fds) { -+ struct jffs2_inode_cache *ic; -+ struct jffs2_full_dirent *fd = dead_fds; -+ -+ dead_fds = fd->next; -+ -+ ic = jffs2_get_ino_cache(c, fd->ino); -+ D1(printk(KERN_DEBUG "Removing dead_fd ino #%u (\"%s\"), ic at %p\n", fd->ino, fd->name, ic)); -+ -+ if (ic) -+ jffs2_build_remove_unlinked_inode(c, ic, &dead_fds); -+ jffs2_free_full_dirent(fd); - } -- } while(ret == -EAGAIN); - - D1(printk(KERN_DEBUG "Pass 2 complete\n")); - -- /* Finally, we can scan again and free the dirent nodes and scan_info structs */ -+ /* Finally, we can scan again and free the dirent structs */ - for_each_inode(i, c, ic) { -- struct jffs2_scan_info *scan = ic->scan; - struct jffs2_full_dirent *fd; - D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes)); -- if (!scan) { -- if (ic->nlink) { -- D1(printk(KERN_WARNING "Why no scan struct for ino #%u which has nlink %d?\n", ic->ino, ic->nlink)); -- } -- continue; -- } -- ic->scan = NULL; -- while(scan->dents) { -- fd = scan->dents; -- scan->dents = fd->next; -+ -+ while(ic->scan_dents) { -+ fd = ic->scan_dents; -+ ic->scan_dents = fd->next; - jffs2_free_full_dirent(fd); - } -- kfree(scan); -+ ic->scan_dents = NULL; -+ cond_resched(); - } - D1(printk(KERN_DEBUG "Pass 3 complete\n")); -+ D1(jffs2_dump_block_lists(c)); -+ -+ /* Rotate the lists by some number to ensure wear levelling */ -+ jffs2_rotate_lists(c); - - return ret; - } - --int jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) -+static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, struct jffs2_full_dirent **dead_fds) - { -- struct jffs2_tmp_dnode_info *tn; -+ struct jffs2_raw_node_ref *raw; - struct jffs2_full_dirent *fd; -- struct jffs2_node_frag *fraglist = NULL; -- struct jffs2_tmp_dnode_info *metadata = NULL; -- -- D1(printk(KERN_DEBUG "jffs2_build_inode building inode #%u\n", ic->ino)); -- if (ic->ino > c->highest_ino) -- c->highest_ino = ic->ino; - -- if (!ic->scan->tmpnodes && ic->ino != 1) { -- D1(printk(KERN_DEBUG "jffs2_build_inode: ino #%u has no data nodes!\n", ic->ino)); -- } -- /* Build the list to make sure any obsolete nodes are marked as such */ -- while(ic->scan->tmpnodes) { -- tn = ic->scan->tmpnodes; -- ic->scan->tmpnodes = tn->next; -- -- if (metadata && tn->version > metadata->version) { -- D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring old metadata at 0x%08x\n", -- metadata->fn->raw->flash_offset &~3)); -+ D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino)); - -- jffs2_free_full_dnode(metadata->fn); -- jffs2_free_tmp_dnode_info(metadata); -- metadata = NULL; -+ for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) { -+ D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw))); -+ jffs2_mark_node_obsolete(c, raw); - } - -- if (tn->fn->size) { -- jffs2_add_full_dnode_to_fraglist (c, &fraglist, tn->fn); -- jffs2_free_tmp_dnode_info(tn); -- } else { -- if (!metadata) { -- metadata = tn; -- } else { -- D1(printk(KERN_DEBUG "jffs2_build_inode_pass1 ignoring new metadata at 0x%08x\n", -- tn->fn->raw->flash_offset &~3)); -- -- jffs2_free_full_dnode(tn->fn); -- jffs2_free_tmp_dnode_info(tn); -- } -- } -- } -+ if (ic->scan_dents) { -+ int whinged = 0; -+ D1(printk(KERN_DEBUG "Inode #%u was a directory which may have children...\n", ic->ino)); - -- /* OK. Now clear up */ -- if (metadata) { -- jffs2_free_full_dnode(metadata->fn); -- jffs2_free_tmp_dnode_info(metadata); -- } -- metadata = NULL; -+ while(ic->scan_dents) { -+ struct jffs2_inode_cache *child_ic; - -- while (fraglist) { -- struct jffs2_node_frag *frag; -- frag = fraglist; -- fraglist = fraglist->next; -+ fd = ic->scan_dents; -+ ic->scan_dents = fd->next; - -- if (frag->node && !(--frag->node->frags)) { -- jffs2_free_full_dnode(frag->node); -+ if (!fd->ino) { -+ /* It's a deletion dirent. Ignore it */ -+ D1(printk(KERN_DEBUG "Child \"%s\" is a deletion dirent, skipping...\n", fd->name)); -+ jffs2_free_full_dirent(fd); -+ continue; - } -- jffs2_free_node_frag(frag); -+ if (!whinged) { -+ whinged = 1; -+ printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino); - } - -- /* Now for each child, increase nlink */ -- for(fd=ic->scan->dents; fd; fd = fd->next) { -- struct jffs2_inode_cache *child_ic; -- if (!fd->ino) -- continue; -+ D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n", -+ fd->name, fd->ino)); - - child_ic = jffs2_get_ino_cache(c, fd->ino); - if (!child_ic) { -- printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n", -- fd->name, fd->ino, ic->ino); -+ printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino); -+ jffs2_free_full_dirent(fd); - continue; - } - -- if (child_ic->nlink++ && fd->type == DT_DIR) { -- 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); -- if (fd->ino == 1 && ic->ino == 1) { -- printk(KERN_NOTICE "This is mostly harmless, and probably caused by creating a JFFS2 image\n"); -- printk(KERN_NOTICE "using a buggy version of mkfs.jffs2. Use at least v1.17.\n"); -+ /* Reduce nlink of the child. If it's now zero, stick it on the -+ dead_fds list to be cleaned up later. Else just free the fd */ -+ -+ child_ic->nlink--; -+ -+ if (!child_ic->nlink) { -+ D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got zero nlink. Adding to dead_fds list.\n", -+ fd->ino, fd->name)); -+ fd->next = *dead_fds; -+ *dead_fds = fd; -+ } else { -+ D1(printk(KERN_DEBUG "Inode #%u (\"%s\") has now got nlink %d. Ignoring.\n", -+ fd->ino, fd->name, child_ic->nlink)); -+ jffs2_free_full_dirent(fd); - } -- /* What do we do about it? */ - } -- D1(printk(KERN_DEBUG "Increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino)); -- /* Can't free them. We might need them in pass 2 */ - } -- return 0; -+ -+ /* -+ We don't delete the inocache from the hash list and free it yet. -+ The erase code will do that, when all the nodes are completely gone. -+ */ - } - --int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) -+static void jffs2_calc_trigger_levels(struct jffs2_sb_info *c) - { -- struct jffs2_raw_node_ref *raw; -- struct jffs2_full_dirent *fd; -- int ret = 0; -+ uint32_t size; - -- if(!ic->scan) { -- D1(printk(KERN_DEBUG "ino #%u was already removed\n", ic->ino)); -- return 0; -- } -+ /* Deletion should almost _always_ be allowed. We're fairly -+ buggered once we stop allowing people to delete stuff -+ because there's not enough free space... */ -+ c->resv_blocks_deletion = 2; -+ -+ /* Be conservative about how much space we need before we allow writes. -+ On top of that which is required for deletia, require an extra 2% -+ of the medium to be available, for overhead caused by nodes being -+ split across blocks, etc. */ -+ -+ size = c->flash_size / 50; /* 2% of flash size */ -+ size += c->nr_blocks * 100; /* And 100 bytes per eraseblock */ -+ size += c->sector_size - 1; /* ... and round up */ -+ -+ c->resv_blocks_write = c->resv_blocks_deletion + (size / c->sector_size); -+ -+ /* When do we let the GC thread run in the background */ -+ -+ c->resv_blocks_gctrigger = c->resv_blocks_write + 1; -+ -+ /* When do we allow garbage collection to merge nodes to make -+ long-term progress at the expense of short-term space exhaustion? */ -+ c->resv_blocks_gcmerge = c->resv_blocks_deletion + 1; -+ -+ /* When do we allow garbage collection to eat from bad blocks rather -+ than actually making progress? */ -+ c->resv_blocks_gcbad = 0;//c->resv_blocks_deletion + 2; -+ -+ /* If there's less than this amount of dirty space, don't bother -+ trying to GC to make more space. It'll be a fruitless task */ -+ c->nospc_dirty_size = c->sector_size + (c->flash_size / 100); -+ -+ D1(printk(KERN_DEBUG "JFFS2 trigger levels (size %d KiB, block size %d KiB, %d blocks)\n", -+ c->flash_size / 1024, c->sector_size / 1024, c->nr_blocks)); -+ D1(printk(KERN_DEBUG "Blocks required to allow deletion: %d (%d KiB)\n", -+ c->resv_blocks_deletion, c->resv_blocks_deletion*c->sector_size/1024)); -+ D1(printk(KERN_DEBUG "Blocks required to allow writes: %d (%d KiB)\n", -+ c->resv_blocks_write, c->resv_blocks_write*c->sector_size/1024)); -+ D1(printk(KERN_DEBUG "Blocks required to quiesce GC thread: %d (%d KiB)\n", -+ c->resv_blocks_gctrigger, c->resv_blocks_gctrigger*c->sector_size/1024)); -+ D1(printk(KERN_DEBUG "Blocks required to allow GC merges: %d (%d KiB)\n", -+ c->resv_blocks_gcmerge, c->resv_blocks_gcmerge*c->sector_size/1024)); -+ D1(printk(KERN_DEBUG "Blocks required to GC bad blocks: %d (%d KiB)\n", -+ c->resv_blocks_gcbad, c->resv_blocks_gcbad*c->sector_size/1024)); -+ D1(printk(KERN_DEBUG "Amount of dirty space required to GC: %d bytes\n", -+ c->nospc_dirty_size)); -+} - -- D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino)); -+int jffs2_do_mount_fs(struct jffs2_sb_info *c) -+{ -+ int i; - -- for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) { -- D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", raw->flash_offset&~3)); -- jffs2_mark_node_obsolete(c, raw); -+ c->free_size = c->flash_size; -+ c->nr_blocks = c->flash_size / c->sector_size; -+ c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL); -+ if (!c->blocks) -+ return -ENOMEM; -+ for (i=0; i<c->nr_blocks; i++) { -+ INIT_LIST_HEAD(&c->blocks[i].list); -+ c->blocks[i].offset = i * c->sector_size; -+ c->blocks[i].free_size = c->sector_size; -+ c->blocks[i].dirty_size = 0; -+ c->blocks[i].wasted_size = 0; -+ c->blocks[i].unchecked_size = 0; -+ c->blocks[i].used_size = 0; -+ c->blocks[i].first_node = NULL; -+ c->blocks[i].last_node = NULL; -+ } -+ -+ init_MUTEX(&c->alloc_sem); -+ init_MUTEX(&c->erase_free_sem); -+ init_waitqueue_head(&c->erase_wait); -+ init_waitqueue_head(&c->inocache_wq); -+ spin_lock_init(&c->erase_completion_lock); -+ spin_lock_init(&c->inocache_lock); -+ -+ INIT_LIST_HEAD(&c->clean_list); -+ INIT_LIST_HEAD(&c->very_dirty_list); -+ INIT_LIST_HEAD(&c->dirty_list); -+ INIT_LIST_HEAD(&c->erasable_list); -+ INIT_LIST_HEAD(&c->erasing_list); -+ INIT_LIST_HEAD(&c->erase_pending_list); -+ INIT_LIST_HEAD(&c->erasable_pending_wbuf_list); -+ INIT_LIST_HEAD(&c->erase_complete_list); -+ INIT_LIST_HEAD(&c->free_list); -+ INIT_LIST_HEAD(&c->bad_list); -+ INIT_LIST_HEAD(&c->bad_used_list); -+ c->highest_ino = 1; -+ -+ if (jffs2_build_filesystem(c)) { -+ D1(printk(KERN_DEBUG "build_fs failed\n")); -+ jffs2_free_ino_caches(c); -+ jffs2_free_raw_node_refs(c); -+ kfree(c->blocks); -+ return -EIO; - } - -- if (ic->scan->dents) { -- printk(KERN_NOTICE "Inode #%u was a directory with children - removing those too...\n", ic->ino); -- -- while(ic->scan->dents) { -- struct jffs2_inode_cache *child_ic; -+ jffs2_calc_trigger_levels(c); - -- fd = ic->scan->dents; -- ic->scan->dents = fd->next; -- -- D1(printk(KERN_DEBUG "Removing child \"%s\", ino #%u\n", -- fd->name, fd->ino)); -- -- child_ic = jffs2_get_ino_cache(c, fd->ino); -- if (!child_ic) { -- printk(KERN_NOTICE "Cannot remove child \"%s\", ino #%u, because it doesn't exist\n", fd->name, fd->ino); -- continue; -- } -- jffs2_free_full_dirent(fd); -- child_ic->nlink--; -- } -- ret = -EAGAIN; -- } -- kfree(ic->scan); -- ic->scan = NULL; -- // jffs2_del_ino_cache(c, ic); -- // jffs2_free_inode_cache(ic); -- return ret; -+ return 0; - } -diff -Nurb linux-mips-2.4.27/fs/jffs2/compr.c linux/fs/jffs2/compr.c ---- linux-mips-2.4.27/fs/jffs2/compr.c 2001-11-05 21:16:18.000000000 +0100 -+++ linux/fs/jffs2/compr.c 2004-11-19 10:25:12.085171520 +0100 -@@ -1,59 +1,37 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * - * Created by Arjan van de Ven <arjanv@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/kernel.h> - #include <linux/string.h> --#include <linux/types.h> - #include <linux/errno.h> -+#include <linux/types.h> -+#include <linux/slab.h> - #include <linux/jffs2.h> -+#include "nodelist.h" - --int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); --void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); --int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); --void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); --int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); --void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); --int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen); --void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, __u32 srclen, __u32 destlen); -+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen); -+void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen); -+int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen); -+void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen); -+int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen); -+void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen); -+int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen); -+void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen); - - - /* jffs2_compress: - * @data: Pointer to uncompressed data -- * @cdata: Pointer to buffer for compressed data -+ * @cdata: Pointer to returned pointer to buffer for compressed data - * @datalen: On entry, holds the amount of data available for compression. - * On exit, expected to hold the amount of data actually compressed. - * @cdatalen: On entry, holds the amount of space available for compressed -@@ -68,47 +46,59 @@ - * jffs2_compress should compress as much as will fit, and should set - * *datalen accordingly to show the amount of data which were compressed. - */ --unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 *datalen, __u32 *cdatalen) -+unsigned char jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, -+ uint32_t *datalen, uint32_t *cdatalen) - { -+#ifdef JFFS2_COMPRESSION - int ret; - -- ret = zlib_compress(data_in, cpage_out, datalen, cdatalen); -+ *cpage_out = kmalloc(*cdatalen, GFP_KERNEL); -+ if (!*cpage_out) { -+ printk(KERN_WARNING "No memory for compressor allocation. Compression failed\n"); -+ goto out; -+ } -+ -+#ifdef JFFS2_USE_ZLIB -+ ret = jffs2_zlib_compress(data_in, *cpage_out, datalen, cdatalen); - if (!ret) { - return JFFS2_COMPR_ZLIB; - } --#if 0 /* Disabled 23/9/1. With zlib it hardly ever gets a look in */ -- ret = dynrubin_compress(data_in, cpage_out, datalen, cdatalen); -+#endif -+#ifdef JFFS2_USE_DYNRUBIN -+ ret = jffs2_dynrubin_compress(data_in, *cpage_out, datalen, cdatalen); - if (!ret) { - return JFFS2_COMPR_DYNRUBIN; - } - #endif --#if 0 /* Disabled 26/2/1. Obsoleted by dynrubin */ -- ret = rubinmips_compress(data_in, cpage_out, datalen, cdatalen); -+#ifdef JFFS2_USE_RUBINMIPS -+ ret = jffs2_rubinmips_compress(data_in, *cpage_out, datalen, cdatalen); - if (!ret) { - return JFFS2_COMPR_RUBINMIPS; - } - #endif -+#ifdef JFFS2_USE_RTIME - /* rtime does manage to recompress already-compressed data */ -- ret = rtime_compress(data_in, cpage_out, datalen, cdatalen); -+ ret = jffs2_rtime_compress(data_in, *cpage_out, datalen, cdatalen); - if (!ret) { - return JFFS2_COMPR_RTIME; - } --#if 0 -- /* We don't need to copy. Let the caller special-case the COMPR_NONE case. */ -- /* If we get here, no compression is going to work */ -- /* But we might want to use the fragmentation part -- Arjan */ -- memcpy(cpage_out,data_in,min(*datalen,*cdatalen)); -- if (*datalen > *cdatalen) -- *datalen = *cdatalen; - #endif -+ kfree(*cpage_out); -+#endif /* Compression */ -+ out: -+ *cpage_out = data_in; -+ *datalen = *cdatalen; - return JFFS2_COMPR_NONE; /* We failed to compress */ -- - } - -+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig) -+{ -+ if (orig != comprbuf) -+ kfree(comprbuf); -+} - - int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, -- unsigned char *data_out, __u32 cdatalen, __u32 datalen) -+ unsigned char *data_out, uint32_t cdatalen, uint32_t datalen) - { - switch (comprtype) { - case JFFS2_COMPR_NONE: -@@ -119,30 +109,27 @@ - case JFFS2_COMPR_ZERO: - memset(data_out, 0, datalen); - break; -- -+#ifdef JFFS2_USE_ZLIB - case JFFS2_COMPR_ZLIB: -- zlib_decompress(cdata_in, data_out, cdatalen, datalen); -+ jffs2_zlib_decompress(cdata_in, data_out, cdatalen, datalen); - break; -- -+#endif -+#ifdef JFFS2_USE_RTIME - case JFFS2_COMPR_RTIME: -- rtime_decompress(cdata_in, data_out, cdatalen, datalen); -+ jffs2_rtime_decompress(cdata_in, data_out, cdatalen, datalen); - break; -- -- case JFFS2_COMPR_RUBINMIPS: --#if 0 /* Disabled 23/9/1 */ -- rubinmips_decompress(cdata_in, data_out, cdatalen, datalen); --#else -- printk(KERN_WARNING "JFFS2: Rubinmips compression encountered but support not compiled in!\n"); - #endif -+#ifdef JFFS2_USE_RUBINMIPS -+ case JFFS2_COMPR_RUBINMIPS: -+ jffs2_rubinmips_decompress(cdata_in, data_out, cdatalen, datalen); - break; -- case JFFS2_COMPR_DYNRUBIN: --#if 1 /* Phase this one out */ -- dynrubin_decompress(cdata_in, data_out, cdatalen, datalen); --#else -- printk(KERN_WARNING "JFFS2: Dynrubin compression encountered but support not compiled in!\n"); - #endif -- break; -+#ifdef JFFS2_USE_DYNRUBIN -+ case JFFS2_COMPR_DYNRUBIN: - -+ jffs2_dynrubin_decompress(cdata_in, data_out, cdatalen, datalen); -+ break; -+#endif - default: - printk(KERN_NOTICE "Unknown JFFS2 compression type 0x%02x\n", comprtype); - return -EIO; -diff -Nurb linux-mips-2.4.27/fs/jffs2/compr_rtime.c linux/fs/jffs2/compr_rtime.c ---- linux-mips-2.4.27/fs/jffs2/compr_rtime.c 2001-10-19 03:24:56.000000000 +0200 -+++ linux/fs/jffs2/compr_rtime.c 2004-11-19 10:25:12.087171216 +0100 -@@ -1,43 +1,19 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * - * Created by Arjan van de Ven <arjanv@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - * - * Very simple lz77-ish encoder. - * - * Theory of operation: Both encoder and decoder have a list of "last -- * occurances" for every possible source-value; after sending the -+ * occurrences" for every possible source-value; after sending the - * first source-byte, the second byte indicated the "run" length of - * matches - * -@@ -51,10 +27,10 @@ - #include <linux/string.h> - - /* _compress returns the compressed size, -1 if bigger */ --int rtime_compress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 *sourcelen, __u32 *dstlen) -+int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen) - { -- int positions[256]; -+ short positions[256]; - int outpos = 0; - int pos=0; - -@@ -91,10 +67,10 @@ - } - - --void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 srclen, __u32 destlen) -+void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t srclen, uint32_t destlen) - { -- int positions[256]; -+ short positions[256]; - int outpos = 0; - int pos=0; - -diff -Nurb linux-mips-2.4.27/fs/jffs2/compr_rubin.c linux/fs/jffs2/compr_rubin.c ---- linux-mips-2.4.27/fs/jffs2/compr_rubin.c 2001-11-05 21:16:18.000000000 +0100 -+++ linux/fs/jffs2/compr_rubin.c 2004-11-19 10:25:12.088171064 +0100 -@@ -1,37 +1,13 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001, 2002 Red Hat, Inc. - * - * Created by Arjan van de Ven <arjanv@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - -@@ -43,7 +19,7 @@ - - - --void init_rubin(struct rubin_state *rs, int div, int *bits) -+static void init_rubin(struct rubin_state *rs, int div, int *bits) - { - int c; - -@@ -56,7 +32,7 @@ - } - - --int encode(struct rubin_state *rs, long A, long B, int symbol) -+static int encode(struct rubin_state *rs, long A, long B, int symbol) - { - - long i0, i1; -@@ -91,7 +67,7 @@ - } - - --void end_rubin(struct rubin_state *rs) -+static void end_rubin(struct rubin_state *rs) - { - - int i; -@@ -104,7 +80,7 @@ - } - - --void init_decode(struct rubin_state *rs, int div, int *bits) -+static void init_decode(struct rubin_state *rs, int div, int *bits) - { - init_rubin(rs, div, bits); - -@@ -151,7 +127,7 @@ - rs->rec_q = rec_q; - } - --int decode(struct rubin_state *rs, long A, long B) -+static int decode(struct rubin_state *rs, long A, long B) - { - unsigned long p = rs->p, q = rs->q; - long i0, threshold; -@@ -212,8 +188,8 @@ - - - --int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, -- unsigned char *cpage_out, __u32 *sourcelen, __u32 *dstlen) -+static int rubin_do_compress(int bit_divider, int *bits, unsigned char *data_in, -+ unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) - { - int outpos = 0; - int pos=0; -@@ -246,20 +222,20 @@ - } - #if 0 - /* _compress returns the compressed size, -1 if bigger */ --int rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 *sourcelen, __u32 *dstlen) -+int jffs2_rubinmips_compress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen) - { - return rubin_do_compress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); - } - #endif --int dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 *sourcelen, __u32 *dstlen) -+int jffs2_dynrubin_compress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen) - { - int bits[8]; - unsigned char histo[256]; - int i; - int ret; -- __u32 mysrclen, mydstlen; -+ uint32_t mysrclen, mydstlen; - - mysrclen = *sourcelen; - mydstlen = *dstlen - 8; -@@ -315,8 +291,8 @@ - return 0; - } - --void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, -- unsigned char *page_out, __u32 srclen, __u32 destlen) -+static void rubin_do_decompress(int bit_divider, int *bits, unsigned char *cdata_in, -+ unsigned char *page_out, uint32_t srclen, uint32_t destlen) - { - int outpos = 0; - struct rubin_state rs; -@@ -330,14 +306,14 @@ - } - - --void rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 sourcelen, __u32 dstlen) -+void jffs2_rubinmips_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t sourcelen, uint32_t dstlen) - { - rubin_do_decompress(BIT_DIVIDER_MIPS, bits_mips, data_in, cpage_out, sourcelen, dstlen); - } - --void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 sourcelen, __u32 dstlen) -+void jffs2_dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t sourcelen, uint32_t dstlen) - { - int bits[8]; - int c; -diff -Nurb linux-mips-2.4.27/fs/jffs2/compr_rubin.h linux/fs/jffs2/compr_rubin.h ---- linux-mips-2.4.27/fs/jffs2/compr_rubin.h 2001-10-19 03:24:56.000000000 +0200 -+++ linux/fs/jffs2/compr_rubin.h 2004-11-19 10:25:12.090170760 +0100 -@@ -1,7 +1,7 @@ - /* Rubin encoder/decoder header */ - /* work started at : aug 3, 1994 */ - /* last modification : aug 15, 1994 */ --/* $Id$ */ -+/* $Id$ */ - - #include "pushpull.h" - -@@ -19,10 +19,3 @@ - int bit_divider; - int bits[8]; - }; -- -- --void init_rubin (struct rubin_state *rs, int div, int *bits); --int encode (struct rubin_state *, long, long, int); --void end_rubin (struct rubin_state *); --void init_decode (struct rubin_state *, int div, int *bits); --int decode (struct rubin_state *, long, long); -diff -Nurb linux-mips-2.4.27/fs/jffs2/compr_zlib.c linux/fs/jffs2/compr_zlib.c ---- linux-mips-2.4.27/fs/jffs2/compr_zlib.c 2003-01-11 18:53:17.000000000 +0100 -+++ linux/fs/jffs2/compr_zlib.c 2004-11-19 10:25:12.091170608 +0100 -@@ -1,50 +1,26 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001, 2002 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - --#ifndef __KERNEL__ -+#if !defined(__KERNEL__) && !defined(__ECOS) - #error "The userspace support got too messy and was removed. Update your mkfs.jffs2" - #endif - - #include <linux/config.h> - #include <linux/kernel.h> --#include <linux/mtd/compatmac.h> /* for min() */ - #include <linux/slab.h> --#include <linux/jffs2.h> - #include <linux/zlib.h> -+#include <linux/zutil.h> -+#include <asm/semaphore.h> - #include "nodelist.h" - - /* Plan: call deflate() with avail_in == *sourcelen, -@@ -58,21 +34,24 @@ - - static DECLARE_MUTEX(deflate_sem); - static DECLARE_MUTEX(inflate_sem); --static void *deflate_workspace; --static void *inflate_workspace; -+static z_stream inf_strm, def_strm; -+ -+#ifdef __KERNEL__ /* Linux-only */ -+#include <linux/vmalloc.h> -+#include <linux/init.h> - - int __init jffs2_zlib_init(void) - { -- deflate_workspace = vmalloc(zlib_deflate_workspacesize()); -- if (!deflate_workspace) { -+ def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); -+ if (!def_strm.workspace) { - printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize()); - return -ENOMEM; - } - D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize())); -- inflate_workspace = vmalloc(zlib_inflate_workspacesize()); -- if (!inflate_workspace) { -+ inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); -+ if (!inf_strm.workspace) { - printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize()); -- vfree(deflate_workspace); -+ vfree(def_strm.workspace); - return -ENOMEM; - } - D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize())); -@@ -81,97 +60,120 @@ - - void jffs2_zlib_exit(void) - { -- vfree(deflate_workspace); -- vfree(inflate_workspace); -+ vfree(def_strm.workspace); -+ vfree(inf_strm.workspace); - } -+#endif /* __KERNEL__ */ - --int zlib_compress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 *sourcelen, __u32 *dstlen) -+int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t *sourcelen, uint32_t *dstlen) - { -- z_stream strm; - int ret; - - if (*dstlen <= STREAM_END_SPACE) - return -1; - - down(&deflate_sem); -- strm.workspace = deflate_workspace; - -- if (Z_OK != zlib_deflateInit(&strm, 3)) { -+ if (Z_OK != zlib_deflateInit(&def_strm, 3)) { - printk(KERN_WARNING "deflateInit failed\n"); - up(&deflate_sem); - return -1; - } - -- strm.next_in = data_in; -- strm.total_in = 0; -+ def_strm.next_in = data_in; -+ def_strm.total_in = 0; - -- strm.next_out = cpage_out; -- strm.total_out = 0; -+ def_strm.next_out = cpage_out; -+ def_strm.total_out = 0; - -- while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) { -- strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE); -- strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out); -+ while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) { -+ def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE); -+ def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out); - D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n", -- strm.avail_in, strm.avail_out)); -- ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH); -+ def_strm.avail_in, def_strm.avail_out)); -+ ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); - D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", -- strm.avail_in, strm.avail_out, strm.total_in, strm.total_out)); -+ def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out)); - if (ret != Z_OK) { - D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret)); -- zlib_deflateEnd(&strm); -+ zlib_deflateEnd(&def_strm); - up(&deflate_sem); - return -1; - } - } -- strm.avail_out += STREAM_END_SPACE; -- strm.avail_in = 0; -- ret = zlib_deflate(&strm, Z_FINISH); -- zlib_deflateEnd(&strm); -- up(&deflate_sem); -+ def_strm.avail_out += STREAM_END_SPACE; -+ def_strm.avail_in = 0; -+ ret = zlib_deflate(&def_strm, Z_FINISH); -+ zlib_deflateEnd(&def_strm); -+ - if (ret != Z_STREAM_END) { - D1(printk(KERN_DEBUG "final deflate returned %d\n", ret)); -- return -1; -+ ret = -1; -+ goto out; - } - -- D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", -- strm.total_in, strm.total_out)); -+ if (def_strm.total_out >= def_strm.total_in) { -+ D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n", -+ def_strm.total_in, def_strm.total_out)); -+ ret = -1; -+ goto out; -+ } - -- if (strm.total_out >= strm.total_in) -- return -1; -+ D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", -+ def_strm.total_in, def_strm.total_out)); - -- *dstlen = strm.total_out; -- *sourcelen = strm.total_in; -- return 0; -+ *dstlen = def_strm.total_out; -+ *sourcelen = def_strm.total_in; -+ ret = 0; -+ out: -+ up(&deflate_sem); -+ return ret; - } - --void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 srclen, __u32 destlen) -+void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, -+ uint32_t srclen, uint32_t destlen) - { -- z_stream strm; - int ret; -+ int wbits = MAX_WBITS; - - down(&inflate_sem); -- strm.workspace = inflate_workspace; - -- if (Z_OK != zlib_inflateInit(&strm)) { -+ inf_strm.next_in = data_in; -+ inf_strm.avail_in = srclen; -+ inf_strm.total_in = 0; -+ -+ inf_strm.next_out = cpage_out; -+ inf_strm.avail_out = destlen; -+ inf_strm.total_out = 0; -+ -+ /* If it's deflate, and it's got no preset dictionary, then -+ we can tell zlib to skip the adler32 check. */ -+ if (srclen > 2 && !(data_in[1] & PRESET_DICT) && -+ ((data_in[0] & 0x0f) == Z_DEFLATED) && -+ !(((data_in[0]<<8) + data_in[1]) % 31)) { -+ -+ D2(printk(KERN_DEBUG "inflate skipping adler32\n")); -+ wbits = -((data_in[0] >> 4) + 8); -+ inf_strm.next_in += 2; -+ inf_strm.avail_in -= 2; -+ } else { -+ /* Let this remain D1 for now -- it should never happen */ -+ D1(printk(KERN_DEBUG "inflate not skipping adler32\n")); -+ } -+ -+ -+ if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) { - printk(KERN_WARNING "inflateInit failed\n"); - up(&inflate_sem); - return; - } -- strm.next_in = data_in; -- strm.avail_in = srclen; -- strm.total_in = 0; -- -- strm.next_out = cpage_out; -- strm.avail_out = destlen; -- strm.total_out = 0; - -- while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK) -+ while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK) - ; - if (ret != Z_STREAM_END) { - printk(KERN_NOTICE "inflate returned %d\n", ret); - } -- zlib_inflateEnd(&strm); -+ zlib_inflateEnd(&inf_strm); - up(&inflate_sem); - } -diff -Nurb linux-mips-2.4.27/fs/jffs2/comprtest.c linux/fs/jffs2/comprtest.c ---- linux-mips-2.4.27/fs/jffs2/comprtest.c 2001-10-19 03:24:56.000000000 +0200 -+++ linux/fs/jffs2/comprtest.c 2004-11-19 10:25:12.093170304 +0100 -@@ -1,4 +1,4 @@ --/* $Id$ */ -+/* $Id$ */ - - #include <linux/kernel.h> - #include <linux/string.h> -@@ -266,13 +266,13 @@ - static unsigned char decomprbuf[TESTDATA_LEN]; - - int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, -- unsigned char *data_out, __u32 cdatalen, __u32 datalen); -+ unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); - unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 *datalen, __u32 *cdatalen); -+ uint32_t *datalen, uint32_t *cdatalen); - - int init_module(void ) { - unsigned char comprtype; -- __u32 c, d; -+ uint32_t c, d; - int ret; - - printk("Original data: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", -diff -Nurb linux-mips-2.4.27/fs/jffs2/crc32.c linux/fs/jffs2/crc32.c ---- linux-mips-2.4.27/fs/jffs2/crc32.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/jffs2/crc32.c 2004-11-19 10:25:12.095170000 +0100 -@@ -0,0 +1,97 @@ -+/* -+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or -+ * code or tables extracted from it, as desired without restriction. -+ * -+ * First, the polynomial itself and its table of feedback terms. The -+ * polynomial is -+ * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 -+ * -+ * Note that we take it "backwards" and put the highest-order term in -+ * the lowest-order bit. The X^32 term is "implied"; the LSB is the -+ * X^31 term, etc. The X^0 term (usually shown as "+1") results in -+ * the MSB being 1 -+ * -+ * Note that the usual hardware shift register implementation, which -+ * is what we're using (we're merely optimizing it by doing eight-bit -+ * chunks at a time) shifts bits into the lowest-order term. In our -+ * implementation, that means shifting towards the right. Why do we -+ * do it this way? Because the calculated CRC must be transmitted in -+ * order from highest-order term to lowest-order term. UARTs transmit -+ * characters in order from LSB to MSB. By storing the CRC this way -+ * we hand it to the UART in the order low-byte to high-byte; the UART -+ * sends each low-bit to hight-bit; and the result is transmission bit -+ * by bit from highest- to lowest-order term without requiring any bit -+ * shuffling on our part. Reception works similarly -+ * -+ * The feedback terms table consists of 256, 32-bit entries. Notes -+ * -+ * The table can be generated at runtime if desired; code to do so -+ * is shown later. It might not be obvious, but the feedback -+ * terms simply represent the results of eight shift/xor opera -+ * tions for all combinations of data and CRC register values -+ * -+ * The values must be right-shifted by eight bits by the "updcrc -+ * logic; the shift must be unsigned (bring in zeroes). On some -+ * hardware you could probably optimize the shift in assembler by -+ * using byte-swap instructions -+ * polynomial $edb88320 -+ */ -+ -+/* $Id$ */ -+ -+#include "crc32.h" -+ -+const uint32_t crc32_table[256] = { -+ 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, -+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, -+ 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, -+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, -+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, -+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, -+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, -+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, -+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, -+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, -+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, -+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, -+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, -+ 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, -+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, -+ 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, -+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, -+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, -+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, -+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, -+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, -+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, -+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, -+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, -+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, -+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, -+ 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, -+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, -+ 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, -+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, -+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, -+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, -+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, -+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, -+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, -+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, -+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, -+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, -+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, -+ 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, -+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, -+ 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, -+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, -+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, -+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, -+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, -+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, -+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, -+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, -+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, -+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, -+ 0x2d02ef8dL -+}; -diff -Nurb linux-mips-2.4.27/fs/jffs2/crc32.h linux/fs/jffs2/crc32.h ---- linux-mips-2.4.27/fs/jffs2/crc32.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/jffs2/crc32.h 2004-11-19 10:25:12.096169848 +0100 -@@ -0,0 +1,21 @@ -+#ifndef CRC32_H -+#define CRC32_H -+ -+/* $Id$ */ -+ -+#include <linux/types.h> -+ -+extern const uint32_t crc32_table[256]; -+ -+/* Return a 32-bit CRC of the contents of the buffer. */ -+ -+static inline uint32_t -+crc32(uint32_t val, const void *ss, int len) -+{ -+ const unsigned char *s = ss; -+ while (--len >= 0) -+ val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); -+ return val; -+} -+ -+#endif -diff -Nurb linux-mips-2.4.27/fs/jffs2/dir.c linux/fs/jffs2/dir.c ---- linux-mips-2.4.27/fs/jffs2/dir.c 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/dir.c 2004-11-19 10:25:12.097169696 +0100 -@@ -1,84 +1,73 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/kernel.h> - #include <linux/slab.h> -+#include <linux/sched.h> - #include <linux/fs.h> --#include <linux/mtd/compatmac.h> /* For completion */ -+#include <linux/crc32.h> - #include <linux/jffs2.h> - #include <linux/jffs2_fs_i.h> - #include <linux/jffs2_fs_sb.h> -+#include <linux/time.h> - #include "nodelist.h" --#include <linux/crc32.h> -+ -+/* Urgh. Please tell me there's a nicer way of doing these. */ -+#include <linux/version.h> -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) -+typedef int mknod_arg_t; -+#define NAMEI_COMPAT(x) ((void *)x) -+#else -+typedef dev_t mknod_arg_t; -+#define NAMEI_COMPAT(x) (x) -+#endif - - static int jffs2_readdir (struct file *, void *, filldir_t); - --static int jffs2_create (struct inode *,struct dentry *,int); --static struct dentry *jffs2_lookup (struct inode *,struct dentry *); -+static int jffs2_create (struct inode *,struct dentry *,int, -+ struct nameidata *); -+static struct dentry *jffs2_lookup (struct inode *,struct dentry *, -+ struct nameidata *); - static int jffs2_link (struct dentry *,struct inode *,struct dentry *); - static int jffs2_unlink (struct inode *,struct dentry *); - static int jffs2_symlink (struct inode *,struct dentry *,const char *); - static int jffs2_mkdir (struct inode *,struct dentry *,int); - static int jffs2_rmdir (struct inode *,struct dentry *); --static int jffs2_mknod (struct inode *,struct dentry *,int,int); -+static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t); - static int jffs2_rename (struct inode *, struct dentry *, - struct inode *, struct dentry *); - - struct file_operations jffs2_dir_operations = - { -- read: generic_read_dir, -- readdir: jffs2_readdir, -- ioctl: jffs2_ioctl, -- fsync: jffs2_null_fsync -+ .read = generic_read_dir, -+ .readdir = jffs2_readdir, -+ .ioctl = jffs2_ioctl, -+ .fsync = jffs2_fsync - }; - - - struct inode_operations jffs2_dir_inode_operations = - { -- create: jffs2_create, -- lookup: jffs2_lookup, -- link: jffs2_link, -- unlink: jffs2_unlink, -- symlink: jffs2_symlink, -- mkdir: jffs2_mkdir, -- rmdir: jffs2_rmdir, -- mknod: jffs2_mknod, -- rename: jffs2_rename, -- setattr: jffs2_setattr, -+ .create = NAMEI_COMPAT(jffs2_create), -+ .lookup = NAMEI_COMPAT(jffs2_lookup), -+ .link = jffs2_link, -+ .unlink = jffs2_unlink, -+ .symlink = jffs2_symlink, -+ .mkdir = jffs2_mkdir, -+ .rmdir = jffs2_rmdir, -+ .mknod = jffs2_mknod, -+ .rename = jffs2_rename, -+ .setattr = jffs2_setattr, - }; - - /***********************************************************************/ -@@ -88,12 +77,13 @@ - and we use the same hash function as the dentries. Makes this - nice and simple - */ --static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target) -+static struct dentry *jffs2_lookup(struct inode *dir_i, struct dentry *target, -+ struct nameidata *nd) - { - struct jffs2_inode_info *dir_f; - struct jffs2_sb_info *c; - struct jffs2_full_dirent *fd = NULL, *fd_list; -- __u32 ino = 0; -+ uint32_t ino = 0; - struct inode *inode = NULL; - - D1(printk(KERN_DEBUG "jffs2_lookup()\n")); -@@ -153,8 +143,9 @@ - offset++; - } - if (offset == 1) { -- D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", filp->f_dentry->d_parent->d_inode->i_ino)); -- if (filldir(dirent, "..", 2, 1, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) -+ unsigned long pino = parent_ino(filp->f_dentry); -+ D1(printk(KERN_DEBUG "Dirent 1: \"..\", ino #%lu\n", pino)); -+ if (filldir(dirent, "..", 2, 1, pino, DT_DIR) < 0) - goto out; - offset++; - } -@@ -188,18 +179,14 @@ - - /***********************************************************************/ - --static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode) -+ -+static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, -+ struct nameidata *nd) - { -+ struct jffs2_raw_inode *ri; - struct jffs2_inode_info *f, *dir_f; - struct jffs2_sb_info *c; - struct inode *inode; -- struct jffs2_raw_inode *ri; -- struct jffs2_raw_dirent *rd; -- struct jffs2_full_dnode *fn; -- struct jffs2_full_dirent *fd; -- int namelen; -- __u32 alloclen, phys_ofs; -- __u32 writtenlen; - int ret; - - ri = jffs2_alloc_raw_inode(); -@@ -210,23 +197,11 @@ - - D1(printk(KERN_DEBUG "jffs2_create()\n")); - -- /* Try to reserve enough space for both node and dirent. -- * Just the node will do for now, though -- */ -- namelen = dentry->d_name.len; -- ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); -- D1(printk(KERN_DEBUG "jffs2_create(): reserved 0x%x bytes\n", alloclen)); -- if (ret) { -- jffs2_free_raw_inode(ri); -- return ret; -- } -- - inode = jffs2_new_inode(dir_i, mode, ri); - - if (IS_ERR(inode)) { - D1(printk(KERN_DEBUG "jffs2_new_inode() failed\n")); - jffs2_free_raw_inode(ri); -- jffs2_complete_reservation(c); - return PTR_ERR(inode); - } - -@@ -236,93 +211,22 @@ - inode->i_mapping->nrpages = 0; - - f = JFFS2_INODE_INFO(inode); -+ dir_f = JFFS2_INODE_INFO(dir_i); - -- ri->data_crc = 0; -- ri->node_crc = crc32(0, ri, sizeof(*ri)-8); -- -- fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen); -- D1(printk(KERN_DEBUG "jffs2_create created file with mode 0x%x\n", ri->mode)); -- jffs2_free_raw_inode(ri); -- -- if (IS_ERR(fn)) { -- D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); -- /* Eeek. Wave bye bye */ -- up(&f->sem); -- jffs2_complete_reservation(c); -- jffs2_clear_inode(inode); -- return PTR_ERR(fn); -- } -- /* No data here. Only a metadata node, which will be -- obsoleted by the first data write -- */ -- f->metadata = fn; -- -- /* Work out where to put the dirent node now. */ -- writtenlen = PAD(writtenlen); -- phys_ofs += writtenlen; -- alloclen -= writtenlen; -- up(&f->sem); -- -- if (alloclen < sizeof(*rd)+namelen) { -- /* Not enough space left in this chunk. Get some more */ -- jffs2_complete_reservation(c); -- ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); -+ ret = jffs2_do_create(c, dir_f, f, ri, -+ dentry->d_name.name, dentry->d_name.len); - - if (ret) { -- /* Eep. */ -- D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); - jffs2_clear_inode(inode); -+ make_bad_inode(inode); -+ iput(inode); -+ jffs2_free_raw_inode(ri); - return ret; - } -- } - -- rd = jffs2_alloc_raw_dirent(); -- if (!rd) { -- /* Argh. Now we treat it like a normal delete */ -- jffs2_complete_reservation(c); -- jffs2_clear_inode(inode); -- return -ENOMEM; -- } -- -- dir_f = JFFS2_INODE_INFO(dir_i); -- down(&dir_f->sem); -- -- rd->magic = JFFS2_MAGIC_BITMASK; -- rd->nodetype = JFFS2_NODETYPE_DIRENT; -- rd->totlen = sizeof(*rd) + namelen; -- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); -- -- rd->pino = dir_i->i_ino; -- rd->version = ++dir_f->highest_version; -- rd->ino = inode->i_ino; -- rd->mctime = CURRENT_TIME; -- rd->nsize = namelen; -- rd->type = DT_REG; -- rd->node_crc = crc32(0, rd, sizeof(*rd)-8); -- rd->name_crc = crc32(0, dentry->d_name.name, namelen); -- -- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); -- -- jffs2_complete_reservation(c); -- -- if (IS_ERR(fd)) { -- /* dirent failed to write. Delete the inode normally -- as if it were the final unlink() */ -- jffs2_free_raw_dirent(rd); -- up(&dir_f->sem); -- jffs2_clear_inode(inode); -- return PTR_ERR(fd); -- } -- -- dir_i->i_mtime = dir_i->i_ctime = rd->mctime; -- -- jffs2_free_raw_dirent(rd); -- -- /* Link the fd into the inode's list, obsoleting an old -- one if necessary. */ -- jffs2_add_fd_to_list(c, fd, &dir_f->dents); -- up(&dir_f->sem); -+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); - -+ jffs2_free_raw_inode(ri); - d_instantiate(dentry, inode); - - D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n", -@@ -332,173 +236,48 @@ - - /***********************************************************************/ - --static int jffs2_do_unlink(struct inode *dir_i, struct dentry *dentry, int rename) --{ -- struct jffs2_inode_info *dir_f, *f; -- struct jffs2_sb_info *c; -- struct jffs2_raw_dirent *rd; -- struct jffs2_full_dirent *fd; -- __u32 alloclen, phys_ofs; -- int ret; -- -- c = JFFS2_SB_INFO(dir_i->i_sb); -- -- rd = jffs2_alloc_raw_dirent(); -- if (!rd) -- return -ENOMEM; -- -- ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_DELETION); -- if (ret) { -- jffs2_free_raw_dirent(rd); -- return ret; -- } -- -- dir_f = JFFS2_INODE_INFO(dir_i); -- down(&dir_f->sem); -- -- /* Build a deletion node */ -- rd->magic = JFFS2_MAGIC_BITMASK; -- rd->nodetype = JFFS2_NODETYPE_DIRENT; -- rd->totlen = sizeof(*rd) + dentry->d_name.len; -- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); -- -- rd->pino = dir_i->i_ino; -- rd->version = ++dir_f->highest_version; -- rd->ino = 0; -- rd->mctime = CURRENT_TIME; -- rd->nsize = dentry->d_name.len; -- rd->type = DT_UNKNOWN; -- rd->node_crc = crc32(0, rd, sizeof(*rd)-8); -- rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len); -- -- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL); -- -- jffs2_complete_reservation(c); -- jffs2_free_raw_dirent(rd); -- -- if (IS_ERR(fd)) { -- up(&dir_f->sem); -- return PTR_ERR(fd); -- } -- -- /* File it. This will mark the old one obsolete. */ -- jffs2_add_fd_to_list(c, fd, &dir_f->dents); -- up(&dir_f->sem); -- -- if (!rename) { -- f = JFFS2_INODE_INFO(dentry->d_inode); -- down(&f->sem); -- -- while (f->dents) { -- /* There can be only deleted ones */ -- fd = f->dents; -- -- f->dents = fd->next; -- -- if (fd->ino) { -- printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", -- f->inocache->ino, fd->name, fd->ino); -- } else { -- D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, f->inocache->ino)); -- } -- jffs2_mark_node_obsolete(c, fd->raw); -- jffs2_free_full_dirent(fd); -- } -- /* Don't oops on unlinking a bad inode */ -- if (f->inocache) -- f->inocache->nlink--; -- dentry->d_inode->i_nlink--; -- up(&f->sem); -- } -- -- return 0; --} - - static int jffs2_unlink(struct inode *dir_i, struct dentry *dentry) - { -- return jffs2_do_unlink(dir_i, dentry, 0); --} --/***********************************************************************/ -- --static int jffs2_do_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry, int rename) --{ -- struct jffs2_inode_info *dir_f, *f; -- struct jffs2_sb_info *c; -- struct jffs2_raw_dirent *rd; -- struct jffs2_full_dirent *fd; -- __u32 alloclen, phys_ofs; -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb); -+ struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); -+ struct jffs2_inode_info *dead_f = JFFS2_INODE_INFO(dentry->d_inode); - int ret; - -- c = JFFS2_SB_INFO(dir_i->i_sb); -- -- rd = jffs2_alloc_raw_dirent(); -- if (!rd) -- return -ENOMEM; -- -- ret = jffs2_reserve_space(c, sizeof(*rd)+dentry->d_name.len, &phys_ofs, &alloclen, ALLOC_NORMAL); -- if (ret) { -- jffs2_free_raw_dirent(rd); -+ ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name, -+ dentry->d_name.len, dead_f); -+ if (dead_f->inocache) -+ dentry->d_inode->i_nlink = dead_f->inocache->nlink; - return ret; -- } -- -- dir_f = JFFS2_INODE_INFO(dir_i); -- down(&dir_f->sem); -- -- /* Build a deletion node */ -- rd->magic = JFFS2_MAGIC_BITMASK; -- rd->nodetype = JFFS2_NODETYPE_DIRENT; -- rd->totlen = sizeof(*rd) + dentry->d_name.len; -- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); -- -- rd->pino = dir_i->i_ino; -- rd->version = ++dir_f->highest_version; -- rd->ino = old_dentry->d_inode->i_ino; -- rd->mctime = CURRENT_TIME; -- rd->nsize = dentry->d_name.len; -- -- /* XXX: This is ugly. */ -- rd->type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; -- if (!rd->type) rd->type = DT_REG; -- -- rd->node_crc = crc32(0, rd, sizeof(*rd)-8); -- rd->name_crc = crc32(0, dentry->d_name.name, dentry->d_name.len); -- -- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, dentry->d_name.len, phys_ofs, NULL); -- -- jffs2_complete_reservation(c); -- jffs2_free_raw_dirent(rd); -- -- if (IS_ERR(fd)) { -- up(&dir_f->sem); -- return PTR_ERR(fd); -- } -- -- /* File it. This will mark the old one obsolete. */ -- jffs2_add_fd_to_list(c, fd, &dir_f->dents); -- up(&dir_f->sem); -- -- if (!rename) { -- f = JFFS2_INODE_INFO(old_dentry->d_inode); -- down(&f->sem); -- old_dentry->d_inode->i_nlink = ++f->inocache->nlink; -- up(&f->sem); -- } -- return 0; - } -+/***********************************************************************/ -+ - - static int jffs2_link (struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry) - { -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dentry->d_inode->i_sb); -+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); -+ struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i); - int ret; -+ uint8_t type; - -- /* Can't link a bad inode. */ -- if (!JFFS2_INODE_INFO(old_dentry->d_inode)->inocache) -+ /* Don't let people make hard links to bad inodes. */ -+ if (!f->inocache) - return -EIO; - - if (S_ISDIR(old_dentry->d_inode->i_mode)) - return -EPERM; - -- ret = jffs2_do_link(old_dentry, dir_i, dentry, 0); -+ /* XXX: This is ugly */ -+ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; -+ if (!type) type = DT_REG; -+ -+ ret = jffs2_do_link(c, dir_f, f->inocache->ino, type, dentry->d_name.name, dentry->d_name.len); -+ - if (!ret) { -+ down(&f->sem); -+ old_dentry->d_inode->i_nlink = ++f->inocache->nlink; -+ up(&f->sem); - d_instantiate(dentry, old_dentry->d_inode); - atomic_inc(&old_dentry->d_inode->i_count); - } -@@ -517,8 +296,7 @@ - struct jffs2_full_dnode *fn; - struct jffs2_full_dirent *fd; - int namelen; -- __u32 alloclen, phys_ofs; -- __u32 writtenlen; -+ uint32_t alloclen, phys_ofs; - int ret; - - /* FIXME: If you care. We'd need to use frags for the target -@@ -556,15 +334,16 @@ - - f = JFFS2_INODE_INFO(inode); - -- inode->i_size = ri->isize = ri->dsize = ri->csize = strlen(target); -- ri->totlen = sizeof(*ri) + ri->dsize; -- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); -+ inode->i_size = strlen(target); -+ ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size); -+ ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size); -+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); - - ri->compr = JFFS2_COMPR_NONE; -- ri->data_crc = crc32(0, target, strlen(target)); -- ri->node_crc = crc32(0, ri, sizeof(*ri)-8); -+ ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target))); -+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - -- fn = jffs2_write_dnode(inode, ri, target, strlen(target), phys_ofs, &writtenlen); -+ fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL); - - jffs2_free_raw_inode(ri); - -@@ -581,13 +360,6 @@ - f->metadata = fn; - up(&f->sem); - -- /* Work out where to put the dirent node now. */ -- writtenlen = (writtenlen+3)&~3; -- phys_ofs += writtenlen; -- alloclen -= writtenlen; -- -- if (alloclen < sizeof(*rd)+namelen) { -- /* Not enough space left in this chunk. Get some more */ - jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { -@@ -595,7 +367,6 @@ - jffs2_clear_inode(inode); - return ret; - } -- } - - rd = jffs2_alloc_raw_dirent(); - if (!rd) { -@@ -608,41 +379,42 @@ - dir_f = JFFS2_INODE_INFO(dir_i); - down(&dir_f->sem); - -- rd->magic = JFFS2_MAGIC_BITMASK; -- rd->nodetype = JFFS2_NODETYPE_DIRENT; -- rd->totlen = sizeof(*rd) + namelen; -- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); -- -- rd->pino = dir_i->i_ino; -- rd->version = ++dir_f->highest_version; -- rd->ino = inode->i_ino; -- rd->mctime = CURRENT_TIME; -+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); -+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); -+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); -+ -+ rd->pino = cpu_to_je32(dir_i->i_ino); -+ rd->version = cpu_to_je32(++dir_f->highest_version); -+ rd->ino = cpu_to_je32(inode->i_ino); -+ rd->mctime = cpu_to_je32(get_seconds()); - rd->nsize = namelen; - rd->type = DT_LNK; -- rd->node_crc = crc32(0, rd, sizeof(*rd)-8); -- rd->name_crc = crc32(0, dentry->d_name.name, namelen); -+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); -+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); - -- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); -- -- jffs2_complete_reservation(c); -+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); - - if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally - as if it were the final unlink() */ -+ jffs2_complete_reservation(c); - jffs2_free_raw_dirent(rd); - up(&dir_f->sem); - jffs2_clear_inode(inode); - return PTR_ERR(fd); - } - -- dir_i->i_mtime = dir_i->i_ctime = rd->mctime; -+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); - - jffs2_free_raw_dirent(rd); - - /* Link the fd into the inode's list, obsoleting an old - one if necessary. */ - jffs2_add_fd_to_list(c, fd, &dir_f->dents); -+ - up(&dir_f->sem); -+ jffs2_complete_reservation(c); - - d_instantiate(dentry, inode); - return 0; -@@ -659,8 +431,7 @@ - struct jffs2_full_dnode *fn; - struct jffs2_full_dirent *fd; - int namelen; -- __u32 alloclen, phys_ofs; -- __u32 writtenlen; -+ uint32_t alloclen, phys_ofs; - int ret; - - mode |= S_IFDIR; -@@ -692,13 +463,15 @@ - - inode->i_op = &jffs2_dir_inode_operations; - inode->i_fop = &jffs2_dir_operations; -+ /* Directories get nlink 2 at start */ -+ inode->i_nlink = 2; - - f = JFFS2_INODE_INFO(inode); - -- ri->data_crc = 0; -- ri->node_crc = crc32(0, ri, sizeof(*ri)-8); -+ ri->data_crc = cpu_to_je32(0); -+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - -- fn = jffs2_write_dnode(inode, ri, NULL, 0, phys_ofs, &writtenlen); -+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); - - jffs2_free_raw_inode(ri); - -@@ -715,13 +488,6 @@ - f->metadata = fn; - up(&f->sem); - -- /* Work out where to put the dirent node now. */ -- writtenlen = PAD(writtenlen); -- phys_ofs += writtenlen; -- alloclen -= writtenlen; -- -- if (alloclen < sizeof(*rd)+namelen) { -- /* Not enough space left in this chunk. Get some more */ - jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { -@@ -729,7 +495,6 @@ - jffs2_clear_inode(inode); - return ret; - } -- } - - rd = jffs2_alloc_raw_dirent(); - if (!rd) { -@@ -742,41 +507,43 @@ - dir_f = JFFS2_INODE_INFO(dir_i); - down(&dir_f->sem); - -- rd->magic = JFFS2_MAGIC_BITMASK; -- rd->nodetype = JFFS2_NODETYPE_DIRENT; -- rd->totlen = sizeof(*rd) + namelen; -- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); -- -- rd->pino = dir_i->i_ino; -- rd->version = ++dir_f->highest_version; -- rd->ino = inode->i_ino; -- rd->mctime = CURRENT_TIME; -+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); -+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); -+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); -+ -+ rd->pino = cpu_to_je32(dir_i->i_ino); -+ rd->version = cpu_to_je32(++dir_f->highest_version); -+ rd->ino = cpu_to_je32(inode->i_ino); -+ rd->mctime = cpu_to_je32(get_seconds()); - rd->nsize = namelen; - rd->type = DT_DIR; -- rd->node_crc = crc32(0, rd, sizeof(*rd)-8); -- rd->name_crc = crc32(0, dentry->d_name.name, namelen); -+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); -+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); - -- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); -- -- jffs2_complete_reservation(c); -+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); - - if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally - as if it were the final unlink() */ -+ jffs2_complete_reservation(c); - jffs2_free_raw_dirent(rd); - up(&dir_f->sem); - jffs2_clear_inode(inode); - return PTR_ERR(fd); - } - -- dir_i->i_mtime = dir_i->i_ctime = rd->mctime; -+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); -+ dir_i->i_nlink++; - - jffs2_free_raw_dirent(rd); - - /* Link the fd into the inode's list, obsoleting an old - one if necessary. */ - jffs2_add_fd_to_list(c, fd, &dir_f->dents); -+ - up(&dir_f->sem); -+ jffs2_complete_reservation(c); - - d_instantiate(dentry, inode); - return 0; -@@ -786,15 +553,19 @@ - { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); - struct jffs2_full_dirent *fd; -+ int ret; - - for (fd = f->dents ; fd; fd = fd->next) { - if (fd->ino) - return -ENOTEMPTY; - } -- return jffs2_unlink(dir_i, dentry); -+ ret = jffs2_unlink(dir_i, dentry); -+ if (!ret) -+ dir_i->i_nlink--; -+ return ret; - } - --static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, int rdev) -+static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev) - { - struct jffs2_inode_info *f, *dir_f; - struct jffs2_sb_info *c; -@@ -804,12 +575,14 @@ - struct jffs2_full_dnode *fn; - struct jffs2_full_dirent *fd; - int namelen; -- unsigned short dev; -+ jint16_t dev; - int devlen = 0; -- __u32 alloclen, phys_ofs; -- __u32 writtenlen; -+ uint32_t alloclen, phys_ofs; - int ret; - -+ if (!old_valid_dev(rdev)) -+ return -EINVAL; -+ - ri = jffs2_alloc_raw_inode(); - if (!ri) - return -ENOMEM; -@@ -817,7 +590,7 @@ - c = JFFS2_SB_INFO(dir_i->i_sb); - - if (S_ISBLK(mode) || S_ISCHR(mode)) { -- dev = (MAJOR(to_kdev_t(rdev)) << 8) | MINOR(to_kdev_t(rdev)); -+ dev = cpu_to_je16(old_encode_dev(rdev)); - devlen = sizeof(dev); - } - -@@ -844,15 +617,15 @@ - - f = JFFS2_INODE_INFO(inode); - -- ri->dsize = ri->csize = devlen; -- ri->totlen = sizeof(*ri) + ri->csize; -- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); -+ ri->dsize = ri->csize = cpu_to_je32(devlen); -+ ri->totlen = cpu_to_je32(sizeof(*ri) + devlen); -+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); - - ri->compr = JFFS2_COMPR_NONE; -- ri->data_crc = crc32(0, &dev, devlen); -- ri->node_crc = crc32(0, ri, sizeof(*ri)-8); -+ ri->data_crc = cpu_to_je32(crc32(0, &dev, devlen)); -+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); - -- fn = jffs2_write_dnode(inode, ri, (char *)&dev, devlen, phys_ofs, &writtenlen); -+ fn = jffs2_write_dnode(c, f, ri, (char *)&dev, devlen, phys_ofs, ALLOC_NORMAL); - - jffs2_free_raw_inode(ri); - -@@ -869,13 +642,6 @@ - f->metadata = fn; - up(&f->sem); - -- /* Work out where to put the dirent node now. */ -- writtenlen = (writtenlen+3)&~3; -- phys_ofs += writtenlen; -- alloclen -= writtenlen; -- -- if (alloclen < sizeof(*rd)+namelen) { -- /* Not enough space left in this chunk. Get some more */ - jffs2_complete_reservation(c); - ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); - if (ret) { -@@ -883,7 +649,6 @@ - jffs2_clear_inode(inode); - return ret; - } -- } - - rd = jffs2_alloc_raw_dirent(); - if (!rd) { -@@ -896,44 +661,45 @@ - dir_f = JFFS2_INODE_INFO(dir_i); - down(&dir_f->sem); - -- rd->magic = JFFS2_MAGIC_BITMASK; -- rd->nodetype = JFFS2_NODETYPE_DIRENT; -- rd->totlen = sizeof(*rd) + namelen; -- rd->hdr_crc = crc32(0, rd, sizeof(struct jffs2_unknown_node)-4); -- -- rd->pino = dir_i->i_ino; -- rd->version = ++dir_f->highest_version; -- rd->ino = inode->i_ino; -- rd->mctime = CURRENT_TIME; -+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); -+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); -+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); -+ -+ rd->pino = cpu_to_je32(dir_i->i_ino); -+ rd->version = cpu_to_je32(++dir_f->highest_version); -+ rd->ino = cpu_to_je32(inode->i_ino); -+ rd->mctime = cpu_to_je32(get_seconds()); - rd->nsize = namelen; - - /* XXX: This is ugly. */ - rd->type = (mode & S_IFMT) >> 12; - -- rd->node_crc = crc32(0, rd, sizeof(*rd)-8); -- rd->name_crc = crc32(0, dentry->d_name.name, namelen); -- -- fd = jffs2_write_dirent(dir_i, rd, dentry->d_name.name, namelen, phys_ofs, &writtenlen); -+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); -+ rd->name_crc = cpu_to_je32(crc32(0, dentry->d_name.name, namelen)); - -- jffs2_complete_reservation(c); -+ fd = jffs2_write_dirent(c, dir_f, rd, dentry->d_name.name, namelen, phys_ofs, ALLOC_NORMAL); - - if (IS_ERR(fd)) { - /* dirent failed to write. Delete the inode normally - as if it were the final unlink() */ -+ jffs2_complete_reservation(c); - jffs2_free_raw_dirent(rd); - up(&dir_f->sem); - jffs2_clear_inode(inode); - return PTR_ERR(fd); - } - -- dir_i->i_mtime = dir_i->i_ctime = rd->mctime; -+ dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); - - jffs2_free_raw_dirent(rd); - - /* Link the fd into the inode's list, obsoleting an old - one if necessary. */ - jffs2_add_fd_to_list(c, fd, &dir_f->dents); -+ - up(&dir_f->sem); -+ jffs2_complete_reservation(c); - - d_instantiate(dentry, inode); - -@@ -944,7 +710,9 @@ - struct inode *new_dir_i, struct dentry *new_dentry) - { - int ret; -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb); - struct jffs2_inode_info *victim_f = NULL; -+ uint8_t type; - - /* The VFS will check for us and prevent trying to rename a - * file over a directory and vice versa, but if it's a directory, -@@ -973,7 +741,15 @@ - */ - - /* Make a hard link */ -- ret = jffs2_do_link(old_dentry, new_dir_i, new_dentry, 1); -+ -+ /* XXX: This is ugly */ -+ type = (old_dentry->d_inode->i_mode & S_IFMT) >> 12; -+ if (!type) type = DT_REG; -+ -+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(new_dir_i), -+ old_dentry->d_inode->i_ino, type, -+ new_dentry->d_name.name, new_dentry->d_name.len); -+ - if (ret) - return ret; - -@@ -989,22 +765,36 @@ - } - } - -+ /* If it was a directory we moved, and there was no victim, -+ increase i_nlink on its new parent */ -+ if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f) -+ new_dir_i->i_nlink++; -+ - /* Unlink the original */ -- ret = jffs2_do_unlink(old_dir_i, old_dentry, 1); -+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i), -+ old_dentry->d_name.name, old_dentry->d_name.len, NULL); -+ -+ /* We don't touch inode->i_nlink */ - - if (ret) { - /* Oh shit. We really ought to make a single node which can do both atomically */ - struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode); - down(&f->sem); -+ old_dentry->d_inode->i_nlink++; - if (f->inocache) -- old_dentry->d_inode->i_nlink = f->inocache->nlink++; -+ f->inocache->nlink++; - up(&f->sem); - - printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret); - /* Might as well let the VFS know */ - d_instantiate(new_dentry, old_dentry->d_inode); - atomic_inc(&old_dentry->d_inode->i_count); -- } - return ret; -+ } -+ -+ if (S_ISDIR(old_dentry->d_inode->i_mode)) -+ old_dir_i->i_nlink--; -+ -+ return 0; - } - -diff -Nurb linux-mips-2.4.27/fs/jffs2/erase.c linux/fs/jffs2/erase.c ---- linux-mips-2.4.27/fs/jffs2/erase.c 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/erase.c 2004-11-19 10:25:12.099169392 +0100 -@@ -1,68 +1,60 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ -+ - #include <linux/kernel.h> - #include <linux/slab.h> - #include <linux/mtd/mtd.h> --#include <linux/jffs2.h> --#include <linux/interrupt.h> --#include "nodelist.h" -+#include <linux/compiler.h> - #include <linux/crc32.h> -+#include <linux/sched.h> -+#include <linux/pagemap.h> -+#include "nodelist.h" - - struct erase_priv_struct { - struct jffs2_eraseblock *jeb; - struct jffs2_sb_info *c; - }; - -+#ifndef __ECOS - static void jffs2_erase_callback(struct erase_info *); -+#endif -+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); - static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); - - void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) - { -- struct erase_info *instr; - int ret; -+#ifdef __ECOS -+ ret = jffs2_flash_erase(c, jeb); -+ if (!ret) { -+ jffs2_erase_succeeded(c, jeb); -+ return; -+ } -+#else /* Linux */ -+ struct erase_info *instr; - - instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); - if (!instr) { - printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); -- spin_lock_bh(&c->erase_completion_lock); -+ spin_lock(&c->erase_completion_lock); - list_del(&jeb->list); - list_add(&jeb->list, &c->erase_pending_list); - c->erasing_size -= c->sector_size; -- spin_unlock_bh(&c->erase_completion_lock); -+ c->dirty_size += c->sector_size; -+ jeb->dirty_size = c->sector_size; -+ spin_unlock(&c->erase_completion_lock); - return; - } - -@@ -77,19 +69,27 @@ - ((struct erase_priv_struct *)instr->priv)->jeb = jeb; - ((struct erase_priv_struct *)instr->priv)->c = c; - -+ /* NAND , read out the fail counter, if possible */ -+ if (!jffs2_can_mark_obsolete(c)) -+ jffs2_nand_read_failcnt(c,jeb); -+ - ret = c->mtd->erase(c->mtd, instr); -- if (!ret) { -+ if (!ret) - return; -- } -+ -+ kfree(instr); -+#endif /* __ECOS */ -+ - if (ret == -ENOMEM || ret == -EAGAIN) { - /* Erase failed immediately. Refile it on the list */ - D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); -- spin_lock_bh(&c->erase_completion_lock); -+ spin_lock(&c->erase_completion_lock); - list_del(&jeb->list); - list_add(&jeb->list, &c->erase_pending_list); - c->erasing_size -= c->sector_size; -- spin_unlock_bh(&c->erase_completion_lock); -- kfree(instr); -+ c->dirty_size += c->sector_size; -+ jeb->dirty_size = c->sector_size; -+ spin_unlock(&c->erase_completion_lock); - return; - } - -@@ -97,74 +97,101 @@ - printk(KERN_WARNING "Erase at 0x%08x failed immediately: -EROFS. Is the sector locked?\n", jeb->offset); - else - printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); -- spin_lock_bh(&c->erase_completion_lock); -- list_del(&jeb->list); -- list_add(&jeb->list, &c->bad_list); -- c->nr_erasing_blocks--; -- c->bad_size += c->sector_size; -- c->erasing_size -= c->sector_size; -- spin_unlock_bh(&c->erase_completion_lock); -- wake_up(&c->erase_wait); -- kfree(instr); -+ -+ jffs2_erase_failed(c, jeb); - } - --void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) -+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count) - { - struct jffs2_eraseblock *jeb; - -- spin_lock_bh(&c->erase_completion_lock); -- while (!list_empty(&c->erase_pending_list)) { -+ down(&c->erase_free_sem); - -- jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list); -+ spin_lock(&c->erase_completion_lock); - -- D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset)); -+ while (!list_empty(&c->erase_complete_list) || -+ !list_empty(&c->erase_pending_list)) { - -+ if (!list_empty(&c->erase_complete_list)) { -+ jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); -+ list_del(&jeb->list); -+ spin_unlock(&c->erase_completion_lock); -+ jffs2_mark_erased_block(c, jeb); -+ -+ if (!--count) { -+ D1(printk(KERN_DEBUG "Count reached. jffs2_erase_pending_blocks leaving\n")); -+ goto done; -+ } -+ -+ } else if (!list_empty(&c->erase_pending_list)) { -+ jeb = list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list); -+ D1(printk(KERN_DEBUG "Starting erase of pending block 0x%08x\n", jeb->offset)); - list_del(&jeb->list); - c->erasing_size += c->sector_size; -+ c->wasted_size -= jeb->wasted_size; - c->free_size -= jeb->free_size; - c->used_size -= jeb->used_size; - c->dirty_size -= jeb->dirty_size; -- jeb->used_size = jeb->dirty_size = jeb->free_size = 0; -+ jeb->wasted_size = jeb->used_size = jeb->dirty_size = jeb->free_size = 0; - jffs2_free_all_node_refs(c, jeb); - list_add(&jeb->list, &c->erasing_list); -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - - jffs2_erase_block(c, jeb); -+ -+ } else { -+ BUG(); -+ } -+ - /* Be nice */ -- if (current->need_resched) -- schedule(); -- spin_lock_bh(&c->erase_completion_lock); -+ cond_resched(); -+ spin_lock(&c->erase_completion_lock); - } -- spin_unlock_bh(&c->erase_completion_lock); -+ -+ spin_unlock(&c->erase_completion_lock); -+ done: - D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); -+ -+ up(&c->erase_free_sem); -+} -+ -+static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) -+{ -+ D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", jeb->offset)); -+ spin_lock(&c->erase_completion_lock); -+ list_del(&jeb->list); -+ list_add_tail(&jeb->list, &c->erase_complete_list); -+ spin_unlock(&c->erase_completion_lock); -+ /* Ensure that kupdated calls us again to mark them clean */ -+ jffs2_erase_pending_trigger(c); - } - -+static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) -+{ -+ spin_lock(&c->erase_completion_lock); -+ c->erasing_size -= c->sector_size; -+ c->bad_size += c->sector_size; -+ list_del(&jeb->list); -+ list_add(&jeb->list, &c->bad_list); -+ c->nr_erasing_blocks--; -+ spin_unlock(&c->erase_completion_lock); -+ wake_up(&c->erase_wait); -+} - -+#ifndef __ECOS - static void jffs2_erase_callback(struct erase_info *instr) - { - struct erase_priv_struct *priv = (void *)instr->priv; - - if(instr->state != MTD_ERASE_DONE) { - printk(KERN_WARNING "Erase at 0x%08x finished, but state != MTD_ERASE_DONE. State is 0x%x instead.\n", instr->addr, instr->state); -- spin_lock(&priv->c->erase_completion_lock); -- priv->c->erasing_size -= priv->c->sector_size; -- priv->c->bad_size += priv->c->sector_size; -- list_del(&priv->jeb->list); -- list_add(&priv->jeb->list, &priv->c->bad_list); -- priv->c->nr_erasing_blocks--; -- spin_unlock(&priv->c->erase_completion_lock); -- wake_up(&priv->c->erase_wait); -+ jffs2_erase_failed(priv->c, priv->jeb); - } else { -- D1(printk(KERN_DEBUG "Erase completed successfully at 0x%08x\n", instr->addr)); -- spin_lock(&priv->c->erase_completion_lock); -- list_del(&priv->jeb->list); -- list_add_tail(&priv->jeb->list, &priv->c->erase_complete_list); -- spin_unlock(&priv->c->erase_completion_lock); -+ jffs2_erase_succeeded(priv->c, priv->jeb); - } -- /* Make sure someone picks up the block off the erase_complete list */ -- OFNI_BS_2SFFJ(priv->c)->s_dirt = 1; - kfree(instr); - } -+#endif /* !__ECOS */ - - /* Hmmm. Maybe we should accept the extra space it takes and make - this a standard doubly-linked list? */ -@@ -221,7 +248,7 @@ - this = ic->nodes; - - while(this) { -- printk( "0x%08x(%d)->", this->flash_offset & ~3, this->flash_offset &3); -+ printk( "0x%08x(%d)->", ref_offset(this), ref_flags(this)); - if (++i == 5) { - printk("\n" KERN_DEBUG); - i=0; -@@ -256,54 +283,43 @@ - jeb->last_node = NULL; - } - --void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) -+static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) - { -- OFNI_BS_2SFFJ(c)->s_dirt = 1; --} -- --void jffs2_mark_erased_blocks(struct jffs2_sb_info *c) --{ -- static struct jffs2_unknown_node marker = {JFFS2_MAGIC_BITMASK, JFFS2_NODETYPE_CLEANMARKER, sizeof(struct jffs2_unknown_node)}; -- struct jffs2_eraseblock *jeb; -- struct jffs2_raw_node_ref *marker_ref; -+ struct jffs2_raw_node_ref *marker_ref = NULL; - unsigned char *ebuf; -- ssize_t retlen; -+ size_t retlen; - int ret; - -- marker.hdr_crc = crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4); -- -- spin_lock_bh(&c->erase_completion_lock); -- while (!list_empty(&c->erase_complete_list)) { -- jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); -- list_del(&jeb->list); -- spin_unlock_bh(&c->erase_completion_lock); -- -+ if (!jffs2_cleanmarker_oob(c)) { - marker_ref = jffs2_alloc_raw_node_ref(); - if (!marker_ref) { - printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); -- /* Come back later */ -+ /* Stick it back on the list from whence it came and come back later */ - jffs2_erase_pending_trigger(c); -+ spin_lock(&c->erase_completion_lock); -+ list_add(&jeb->list, &c->erase_complete_list); -+ spin_unlock(&c->erase_completion_lock); - return; - } -- -+ } - ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!ebuf) { - printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset); - } else { -- __u32 ofs = jeb->offset; -+ uint32_t ofs = jeb->offset; - - D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset)); - while(ofs < jeb->offset + c->sector_size) { -- __u32 readlen = min((__u32)PAGE_SIZE, jeb->offset + c->sector_size - ofs); -+ uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs); - int i; - -- ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf); -- if (ret < 0) { -+ ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf); -+ if (ret) { - printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret); - goto bad; - } - if (retlen != readlen) { -- printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen); -+ printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); - goto bad; - } - for (i=0; i<readlen; i += sizeof(unsigned long)) { -@@ -312,62 +328,89 @@ - if (datum + 1) { - printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, ofs + i); - bad: -+ if (!jffs2_cleanmarker_oob(c)) - jffs2_free_raw_node_ref(marker_ref); -+ else -+ jffs2_write_nand_badblock( c ,jeb ); - kfree(ebuf); - bad2: -- spin_lock_bh(&c->erase_completion_lock); -+ spin_lock(&c->erase_completion_lock); - c->erasing_size -= c->sector_size; - c->bad_size += c->sector_size; - - list_add_tail(&jeb->list, &c->bad_list); - c->nr_erasing_blocks--; -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - wake_up(&c->erase_wait); - return; - } - } - ofs += readlen; -+ cond_resched(); - } - kfree(ebuf); - } - - /* Write the erase complete marker */ - D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset)); -- ret = c->mtd->write(c->mtd, jeb->offset, sizeof(marker), &retlen, (char *)&marker); -+ if (jffs2_cleanmarker_oob(c)) { -+ -+ if (jffs2_write_nand_cleanmarker(c, jeb)) -+ goto bad2; -+ -+ jeb->first_node = jeb->last_node = NULL; -+ -+ jeb->free_size = c->sector_size; -+ jeb->used_size = 0; -+ jeb->dirty_size = 0; -+ jeb->wasted_size = 0; -+ } else { -+ struct jffs2_unknown_node marker = { -+ .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK), -+ .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), -+ .totlen = cpu_to_je32(c->cleanmarker_size) -+ }; -+ -+ marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4)); -+ -+ /* We only write the header; the rest was noise or padding anyway */ -+ ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker); - if (ret) { - printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n", - jeb->offset, ret); - goto bad2; - } - if (retlen != sizeof(marker)) { -- printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n", -+ printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %zd\n", - jeb->offset, sizeof(marker), retlen); - goto bad2; - } - - marker_ref->next_in_ino = NULL; - marker_ref->next_phys = NULL; -- marker_ref->flash_offset = jeb->offset; -- marker_ref->totlen = PAD(sizeof(marker)); -+ marker_ref->flash_offset = jeb->offset | REF_NORMAL; -+ marker_ref->__totlen = c->cleanmarker_size; - - jeb->first_node = jeb->last_node = marker_ref; - -- jeb->free_size = c->sector_size - marker_ref->totlen; -- jeb->used_size = marker_ref->totlen; -+ jeb->free_size = c->sector_size - c->cleanmarker_size; -+ jeb->used_size = c->cleanmarker_size; - jeb->dirty_size = 0; -+ jeb->wasted_size = 0; -+ } - -- spin_lock_bh(&c->erase_completion_lock); -+ spin_lock(&c->erase_completion_lock); - c->erasing_size -= c->sector_size; - c->free_size += jeb->free_size; - c->used_size += jeb->used_size; - - ACCT_SANITY_CHECK(c,jeb); -- ACCT_PARANOIA_CHECK(jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); - - list_add_tail(&jeb->list, &c->free_list); - c->nr_erasing_blocks--; - c->nr_free_blocks++; -+ spin_unlock(&c->erase_completion_lock); - wake_up(&c->erase_wait); -- } -- spin_unlock_bh(&c->erase_completion_lock); - } -+ -diff -Nurb linux-mips-2.4.27/fs/jffs2/file.c linux/fs/jffs2/file.c ---- linux-mips-2.4.27/fs/jffs2/file.c 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/file.c 2004-11-19 10:25:12.101169088 +0100 -@@ -1,319 +1,106 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - -+#include <linux/version.h> - #include <linux/kernel.h> --#include <linux/mtd/compatmac.h> /* for min() */ - #include <linux/slab.h> - #include <linux/fs.h> -+#include <linux/time.h> - #include <linux/pagemap.h> -+#include <linux/highmem.h> -+#include <linux/crc32.h> - #include <linux/jffs2.h> - #include "nodelist.h" --#include <linux/crc32.h> - - extern int generic_file_open(struct inode *, struct file *) __attribute__((weak)); - extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin) __attribute__((weak)); - - --int jffs2_null_fsync(struct file *filp, struct dentry *dentry, int datasync) -+int jffs2_fsync(struct file *filp, struct dentry *dentry, int datasync) - { -- /* Move along. Nothing to see here */ -+ struct inode *inode = dentry->d_inode; -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -+ -+ /* Trigger GC to flush any pending writes for this inode */ -+ jffs2_flush_wbuf_gc(c, inode->i_ino); -+ - return 0; - } - - struct file_operations jffs2_file_operations = - { -- llseek: generic_file_llseek, -- open: generic_file_open, -- read: generic_file_read, -- write: generic_file_write, -- ioctl: jffs2_ioctl, -- mmap: generic_file_mmap, -- fsync: jffs2_null_fsync -+ .llseek = generic_file_llseek, -+ .open = generic_file_open, -+ .read = generic_file_read, -+ .write = generic_file_write, -+ .ioctl = jffs2_ioctl, -+ .mmap = generic_file_readonly_mmap, -+ .fsync = jffs2_fsync, -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29) -+ .sendfile = generic_file_sendfile -+#endif - }; - - /* jffs2_file_inode_operations */ - - struct inode_operations jffs2_file_inode_operations = - { -- setattr: jffs2_setattr -+ .setattr = jffs2_setattr - }; - - struct address_space_operations jffs2_file_address_operations = - { -- readpage: jffs2_readpage, -- prepare_write: jffs2_prepare_write, -- commit_write: jffs2_commit_write -+ .readpage = jffs2_readpage, -+ .prepare_write =jffs2_prepare_write, -+ .commit_write = jffs2_commit_write - }; - --int jffs2_setattr (struct dentry *dentry, struct iattr *iattr) --{ -- struct jffs2_full_dnode *old_metadata, *new_metadata; -- struct inode *inode = dentry->d_inode; -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); -- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -- struct jffs2_raw_inode *ri; -- unsigned short dev; -- unsigned char *mdata = NULL; -- int mdatalen = 0; -- unsigned int ivalid; -- __u32 phys_ofs, alloclen; -- int ret; -- D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); -- ret = inode_change_ok(inode, iattr); -- if (ret) -- return ret; -- -- /* Special cases - we don't want more than one data node -- for these types on the medium at any time. So setattr -- must read the original data associated with the node -- (i.e. the device numbers or the target name) and write -- it out again with the appropriate data attached */ -- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { -- /* For these, we don't actually need to read the old node */ -- dev = (MAJOR(to_kdev_t(dentry->d_inode->i_rdev)) << 8) | -- MINOR(to_kdev_t(dentry->d_inode->i_rdev)); -- mdata = (char *)&dev; -- mdatalen = sizeof(dev); -- D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); -- } else if (S_ISLNK(inode->i_mode)) { -- mdatalen = f->metadata->size; -- mdata = kmalloc(f->metadata->size, GFP_USER); -- if (!mdata) -- return -ENOMEM; -- ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen); -- if (ret) { -- kfree(mdata); -- return ret; -- } -- D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); -- } -- -- ri = jffs2_alloc_raw_inode(); -- if (!ri) { -- if (S_ISLNK(inode->i_mode)) -- kfree(mdata); -- return -ENOMEM; -- } -- -- ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL); -- if (ret) { -- jffs2_free_raw_inode(ri); -- if (S_ISLNK(inode->i_mode)) -- kfree(mdata); -- return ret; -- } -- down(&f->sem); -- ivalid = iattr->ia_valid; -- -- ri->magic = JFFS2_MAGIC_BITMASK; -- ri->nodetype = JFFS2_NODETYPE_INODE; -- ri->totlen = sizeof(*ri) + mdatalen; -- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); -- -- ri->ino = inode->i_ino; -- ri->version = ++f->highest_version; -- -- ri->mode = (ivalid & ATTR_MODE)?iattr->ia_mode:inode->i_mode; -- ri->uid = (ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid; -- ri->gid = (ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid; -- -- if (ivalid & ATTR_MODE && ri->mode & S_ISGID && -- !in_group_p(ri->gid) && !capable(CAP_FSETID)) -- ri->mode &= ~S_ISGID; -- -- ri->isize = (ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size; -- ri->atime = (ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime; -- ri->mtime = (ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime; -- ri->ctime = (ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime; -- -- ri->offset = 0; -- ri->csize = ri->dsize = mdatalen; -- ri->compr = JFFS2_COMPR_NONE; -- if (inode->i_size < ri->isize) { -- /* It's an extension. Make it a hole node */ -- ri->compr = JFFS2_COMPR_ZERO; -- ri->dsize = ri->isize - inode->i_size; -- ri->offset = inode->i_size; -- } -- ri->node_crc = crc32(0, ri, sizeof(*ri)-8); -- if (mdatalen) -- ri->data_crc = crc32(0, mdata, mdatalen); -- else -- ri->data_crc = 0; -- -- new_metadata = jffs2_write_dnode(inode, ri, mdata, mdatalen, phys_ofs, NULL); -- if (S_ISLNK(inode->i_mode)) -- kfree(mdata); -- -- jffs2_complete_reservation(c); -- -- if (IS_ERR(new_metadata)) { -- jffs2_free_raw_inode(ri); -- up(&f->sem); -- return PTR_ERR(new_metadata); -- } -- /* It worked. Update the inode */ -- inode->i_atime = ri->atime; -- inode->i_ctime = ri->ctime; -- inode->i_mtime = ri->mtime; -- inode->i_mode = ri->mode; -- inode->i_uid = ri->uid; -- inode->i_gid = ri->gid; -- -- -- old_metadata = f->metadata; -- -- if (inode->i_size > ri->isize) { -- vmtruncate(inode, ri->isize); -- jffs2_truncate_fraglist (c, &f->fraglist, ri->isize); -- } -- -- if (inode->i_size < ri->isize) { -- jffs2_add_full_dnode_to_inode(c, f, new_metadata); -- inode->i_size = ri->isize; -- f->metadata = NULL; -- } else { -- f->metadata = new_metadata; -- } -- if (old_metadata) { -- jffs2_mark_node_obsolete(c, old_metadata->raw); -- jffs2_free_full_dnode(old_metadata); -- } -- jffs2_free_raw_inode(ri); -- up(&f->sem); -- return 0; --} -- - int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg) - { - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -- struct jffs2_node_frag *frag = f->fraglist; -- __u32 offset = pg->index << PAGE_CACHE_SHIFT; -- __u32 end = offset + PAGE_CACHE_SIZE; - unsigned char *pg_buf; - int ret; - -- D1(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%x\n", inode->i_ino, offset)); -+ D2(printk(KERN_DEBUG "jffs2_do_readpage_nolock(): ino #%lu, page at offset 0x%lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT)); - - if (!PageLocked(pg)) - PAGE_BUG(pg); - -- while(frag && frag->ofs + frag->size <= offset) { -- // D1(printk(KERN_DEBUG "skipping frag %d-%d; before the region we care about\n", frag->ofs, frag->ofs + frag->size)); -- frag = frag->next; -- } -- - pg_buf = kmap(pg); -+ /* FIXME: Can kmap fail? */ - -- /* XXX FIXME: Where a single physical node actually shows up in two -- frags, we read it twice. Don't do that. */ -- /* Now we're pointing at the first frag which overlaps our page */ -- while(offset < end) { -- D2(printk(KERN_DEBUG "jffs2_readpage: offset %d, end %d\n", offset, end)); -- if (!frag || frag->ofs > offset) { -- __u32 holesize = end - offset; -- if (frag) { -- D1(printk(KERN_NOTICE "Eep. Hole in ino %ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", inode->i_ino, frag->ofs, offset)); -- holesize = min(holesize, frag->ofs - offset); -- D1(jffs2_print_frag_list(f)); -- } -- D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); -- memset(pg_buf, 0, holesize); -- pg_buf += holesize; -- offset += holesize; -- continue; -- } else if (frag->ofs < offset && (offset & (PAGE_CACHE_SIZE-1)) != 0) { -- D1(printk(KERN_NOTICE "Eep. Overlap in ino #%ld fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", -- inode->i_ino, frag->ofs, offset)); -- D1(jffs2_print_frag_list(f)); -- memset(pg_buf, 0, end - offset); -- ClearPageUptodate(pg); -- SetPageError(pg); -- kunmap(pg); -- return -EIO; -- } else if (!frag->node) { -- __u32 holeend = min(end, frag->ofs + frag->size); -- D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size)); -- memset(pg_buf, 0, holeend - offset); -- pg_buf += holeend - offset; -- offset = holeend; -- frag = frag->next; -- continue; -- } else { -- __u32 readlen; -- __u32 fragofs; /* offset within the frag to start reading */ -+ ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE); - -- fragofs = offset - frag->ofs; -- readlen = min(frag->size - fragofs, end - offset); -- D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs, -- fragofs+frag->ofs+readlen, frag->node->raw->flash_offset & ~3)); -- ret = jffs2_read_dnode(c, frag->node, pg_buf, fragofs + frag->ofs - frag->node->ofs, readlen); -- D2(printk(KERN_DEBUG "node read done\n")); - if (ret) { -- D1(printk(KERN_DEBUG"jffs2_readpage error %d\n",ret)); -- memset(pg_buf, 0, readlen); - ClearPageUptodate(pg); - SetPageError(pg); -- kunmap(pg); -- return ret; -- } -- -- pg_buf += readlen; -- offset += readlen; -- frag = frag->next; -- D2(printk(KERN_DEBUG "node read was OK. Looping\n")); -- } -- } -- D2(printk(KERN_DEBUG "readpage finishing\n")); -+ } else { - SetPageUptodate(pg); - ClearPageError(pg); -+ } - - flush_dcache_page(pg); -- - kunmap(pg); -- D1(printk(KERN_DEBUG "readpage finished\n")); -+ -+ D2(printk(KERN_DEBUG "readpage finished\n")); - return 0; - } - - int jffs2_do_readpage_unlock(struct inode *inode, struct page *pg) - { - int ret = jffs2_do_readpage_nolock(inode, pg); -- UnlockPage(pg); -+ unlock_page(pg); - return ret; - } - -@@ -333,17 +120,17 @@ - { - struct inode *inode = pg->mapping->host; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); -- __u32 pageofs = pg->index << PAGE_CACHE_SHIFT; -+ uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT; - int ret = 0; - -- D1(printk(KERN_DEBUG "jffs2_prepare_write() nrpages %ld\n", inode->i_mapping->nrpages)); -+ D1(printk(KERN_DEBUG "jffs2_prepare_write()\n")); - - if (pageofs > inode->i_size) { - /* Make new hole frag from old EOF to new page */ - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); - struct jffs2_raw_inode ri; - struct jffs2_full_dnode *fn; -- __u32 phys_ofs, alloc_len; -+ uint32_t phys_ofs, alloc_len; - - D1(printk(KERN_DEBUG "Writing new hole frag 0x%x-0x%x between current EOF and new page\n", - (unsigned int)inode->i_size, pageofs)); -@@ -355,29 +142,30 @@ - down(&f->sem); - memset(&ri, 0, sizeof(ri)); - -- ri.magic = JFFS2_MAGIC_BITMASK; -- ri.nodetype = JFFS2_NODETYPE_INODE; -- ri.totlen = sizeof(ri); -- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); -- -- ri.ino = f->inocache->ino; -- ri.version = ++f->highest_version; -- ri.mode = inode->i_mode; -- ri.uid = inode->i_uid; -- ri.gid = inode->i_gid; -- ri.isize = max((__u32)inode->i_size, pageofs); -- ri.atime = ri.ctime = ri.mtime = CURRENT_TIME; -- ri.offset = inode->i_size; -- ri.dsize = pageofs - inode->i_size; -- ri.csize = 0; -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri)); -+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); -+ -+ ri.ino = cpu_to_je32(f->inocache->ino); -+ ri.version = cpu_to_je32(++f->highest_version); -+ ri.mode = cpu_to_jemode(inode->i_mode); -+ ri.uid = cpu_to_je16(inode->i_uid); -+ ri.gid = cpu_to_je16(inode->i_gid); -+ ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); -+ ri.atime = ri.ctime = ri.mtime = cpu_to_je32(get_seconds()); -+ ri.offset = cpu_to_je32(inode->i_size); -+ ri.dsize = cpu_to_je32(pageofs - inode->i_size); -+ ri.csize = cpu_to_je32(0); - ri.compr = JFFS2_COMPR_ZERO; -- ri.node_crc = crc32(0, &ri, sizeof(ri)-8); -- ri.data_crc = 0; -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); -+ ri.data_crc = cpu_to_je32(0); -+ -+ fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_NORMAL); - -- fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL); -- jffs2_complete_reservation(c); - if (IS_ERR(fn)) { - ret = PTR_ERR(fn); -+ jffs2_complete_reservation(c); - up(&f->sem); - return ret; - } -@@ -391,16 +179,17 @@ - D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in prepare_write, returned %d\n", ret)); - jffs2_mark_node_obsolete(c, fn->raw); - jffs2_free_full_dnode(fn); -+ jffs2_complete_reservation(c); - up(&f->sem); - return ret; - } -+ jffs2_complete_reservation(c); - inode->i_size = pageofs; - up(&f->sem); - } - -- - /* Read in the page if it wasn't already present, unless it's a whole page */ -- if (!Page_Uptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { -+ if (!PageUptodate(pg) && (start || end < PAGE_CACHE_SIZE)) { - down(&f->sem); - ret = jffs2_do_readpage_nolock(inode, pg); - up(&f->sem); -@@ -417,14 +206,12 @@ - struct inode *inode = pg->mapping->host; - struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -- __u32 newsize = max_t(__u32, filp->f_dentry->d_inode->i_size, (pg->index << PAGE_CACHE_SHIFT) + end); -- __u32 file_ofs = (pg->index << PAGE_CACHE_SHIFT); -- __u32 writelen = min((__u32)PAGE_CACHE_SIZE, newsize - file_ofs); - struct jffs2_raw_inode *ri; - int ret = 0; -- ssize_t writtenlen = 0; -+ uint32_t writtenlen = 0; - -- D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags)); -+ D1(printk(KERN_DEBUG "jffs2_commit_write(): ino #%lu, page at 0x%lx, range %d-%d, flags %lx\n", -+ inode->i_ino, pg->index << PAGE_CACHE_SHIFT, start, end, pg->flags)); - - if (!start && end == PAGE_CACHE_SIZE) { - /* We need to avoid deadlock with page_cache_read() in -@@ -435,109 +222,47 @@ - } - - ri = jffs2_alloc_raw_inode(); -- if (!ri) -- return -ENOMEM; -- -- while(writelen) { -- struct jffs2_full_dnode *fn; -- unsigned char *comprbuf = NULL; -- unsigned char comprtype = JFFS2_COMPR_NONE; -- __u32 phys_ofs, alloclen; -- __u32 datalen, cdatalen; - -- D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, file_ofs)); -- -- ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); -- if (ret) { -- SetPageError(pg); -- D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); -- break; -+ if (!ri) { -+ D1(printk(KERN_DEBUG "jffs2_commit_write(): Allocation of raw inode failed\n")); -+ return -ENOMEM; - } -- down(&f->sem); -- datalen = writelen; -- cdatalen = min(alloclen - sizeof(*ri), writelen); -- -- comprbuf = kmalloc(cdatalen, GFP_KERNEL); -- if (comprbuf) { -- comprtype = jffs2_compress(page_address(pg)+ (file_ofs & (PAGE_CACHE_SIZE-1)), comprbuf, &datalen, &cdatalen); -- } -- if (comprtype == JFFS2_COMPR_NONE) { -- /* Either compression failed, or the allocation of comprbuf failed */ -- if (comprbuf) -- kfree(comprbuf); -- comprbuf = page_address(pg) + (file_ofs & (PAGE_CACHE_SIZE -1)); -- datalen = cdatalen; -- } -- /* Now comprbuf points to the data to be written, be it compressed or not. -- comprtype holds the compression type, and comprtype == JFFS2_COMPR_NONE means -- that the comprbuf doesn't need to be kfree()d. -- */ -- -- ri->magic = JFFS2_MAGIC_BITMASK; -- ri->nodetype = JFFS2_NODETYPE_INODE; -- ri->totlen = sizeof(*ri) + cdatalen; -- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); -- -- ri->ino = inode->i_ino; -- ri->version = ++f->highest_version; -- ri->mode = inode->i_mode; -- ri->uid = inode->i_uid; -- ri->gid = inode->i_gid; -- ri->isize = max((__u32)inode->i_size, file_ofs + datalen); -- ri->atime = ri->ctime = ri->mtime = CURRENT_TIME; -- ri->offset = file_ofs; -- ri->csize = cdatalen; -- ri->dsize = datalen; -- ri->compr = comprtype; -- ri->node_crc = crc32(0, ri, sizeof(*ri)-8); -- ri->data_crc = crc32(0, comprbuf, cdatalen); -- -- fn = jffs2_write_dnode(inode, ri, comprbuf, cdatalen, phys_ofs, NULL); - -- jffs2_complete_reservation(c); -+ /* Set the fields that the generic jffs2_write_inode_range() code can't find */ -+ ri->ino = cpu_to_je32(inode->i_ino); -+ ri->mode = cpu_to_jemode(inode->i_mode); -+ ri->uid = cpu_to_je16(inode->i_uid); -+ ri->gid = cpu_to_je16(inode->i_gid); -+ ri->isize = cpu_to_je32((uint32_t)inode->i_size); -+ ri->atime = ri->ctime = ri->mtime = cpu_to_je32(get_seconds()); -+ -+ /* In 2.4, it was already kmapped by generic_file_write(). Doesn't -+ hurt to do it again. The alternative is ifdefs, which are ugly. */ -+ kmap(pg); -+ -+ ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + start, -+ (pg->index << PAGE_CACHE_SHIFT) + start, -+ end - start, &writtenlen); - -- if (comprtype != JFFS2_COMPR_NONE) -- kfree(comprbuf); -+ kunmap(pg); - -- if (IS_ERR(fn)) { -- ret = PTR_ERR(fn); -- up(&f->sem); -- SetPageError(pg); -- break; -- } -- ret = jffs2_add_full_dnode_to_inode(c, f, fn); -- if (f->metadata) { -- jffs2_mark_node_obsolete(c, f->metadata->raw); -- jffs2_free_full_dnode(f->metadata); -- f->metadata = NULL; -- } -- up(&f->sem); - if (ret) { -- /* Eep */ -- D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret)); -- jffs2_mark_node_obsolete(c, fn->raw); -- jffs2_free_full_dnode(fn); -+ /* There was an error writing. */ - SetPageError(pg); -- break; - } -- inode->i_size = ri->isize; -+ -+ if (writtenlen) { -+ if (inode->i_size < (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen) { -+ inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; - inode->i_blocks = (inode->i_size + 511) >> 9; -- inode->i_ctime = inode->i_mtime = ri->ctime; -- if (!datalen) { -- printk(KERN_WARNING "Eep. We didn't actually write any bloody data\n"); -- ret = -EIO; -- SetPageError(pg); -- break; -+ -+ inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); - } -- D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen)); -- writtenlen += datalen; -- file_ofs += datalen; -- writelen -= datalen; - } - - jffs2_free_raw_inode(ri); - -- if (writtenlen < end) { -+ if (start+writtenlen < end) { - /* generic_file_write has written more to the page cache than we've - actually written to the medium. Mark the page !Uptodate so that - it gets reread */ -@@ -545,13 +270,7 @@ - SetPageError(pg); - ClearPageUptodate(pg); - } -- if (writtenlen <= start) { -- /* We didn't even get to the start of the affected part */ -- ret = ret?ret:-ENOSPC; -- D1(printk(KERN_DEBUG "jffs2_commit_write(): Only %x bytes written to page. start (%x) not reached, returning %d\n", writtenlen, start, ret)); -- } -- writtenlen = min(end-start, writtenlen-start); - -- D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d. nrpages is %ld\n",writtenlen?writtenlen:ret, inode->i_mapping->nrpages)); -+ D1(printk(KERN_DEBUG "jffs2_commit_write() returning %d\n",writtenlen?writtenlen:ret)); - return writtenlen?writtenlen:ret; - } -diff -Nurb linux-mips-2.4.27/fs/jffs2/fs.c linux/fs/jffs2/fs.c ---- linux-mips-2.4.27/fs/jffs2/fs.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/jffs2/fs.c 2004-11-19 10:25:12.102168936 +0100 -@@ -0,0 +1,618 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001-2003 Red Hat, Inc. -+ * -+ * Created by David Woodhouse <dwmw2@redhat.com> -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ * -+ * $Id$ -+ * -+ */ -+ -+#include <linux/version.h> -+#include <linux/config.h> -+#include <linux/kernel.h> -+#include <linux/sched.h> -+#include <linux/fs.h> -+#include <linux/list.h> -+#include <linux/mtd/mtd.h> -+#include <linux/pagemap.h> -+#include <linux/slab.h> -+#include <linux/vfs.h> -+#include <linux/crc32.h> -+#include "nodelist.h" -+ -+ -+static int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) -+{ -+ struct jffs2_full_dnode *old_metadata, *new_metadata; -+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -+ struct jffs2_raw_inode *ri; -+ unsigned short dev; -+ unsigned char *mdata = NULL; -+ int mdatalen = 0; -+ unsigned int ivalid; -+ uint32_t phys_ofs, alloclen; -+ int ret; -+ D1(printk(KERN_DEBUG "jffs2_setattr(): ino #%lu\n", inode->i_ino)); -+ ret = inode_change_ok(inode, iattr); -+ if (ret) -+ return ret; -+ -+ /* Special cases - we don't want more than one data node -+ for these types on the medium at any time. So setattr -+ must read the original data associated with the node -+ (i.e. the device numbers or the target name) and write -+ it out again with the appropriate data attached */ -+ if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { -+ /* For these, we don't actually need to read the old node */ -+ dev = old_encode_dev(inode->i_rdev); -+ mdata = (char *)&dev; -+ mdatalen = sizeof(dev); -+ D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of kdev_t\n", mdatalen)); -+ } else if (S_ISLNK(inode->i_mode)) { -+ mdatalen = f->metadata->size; -+ mdata = kmalloc(f->metadata->size, GFP_USER); -+ if (!mdata) -+ return -ENOMEM; -+ ret = jffs2_read_dnode(c, f->metadata, mdata, 0, mdatalen); -+ if (ret) { -+ kfree(mdata); -+ return ret; -+ } -+ D1(printk(KERN_DEBUG "jffs2_setattr(): Writing %d bytes of symlink target\n", mdatalen)); -+ } -+ -+ ri = jffs2_alloc_raw_inode(); -+ if (!ri) { -+ if (S_ISLNK(inode->i_mode)) -+ kfree(mdata); -+ return -ENOMEM; -+ } -+ -+ ret = jffs2_reserve_space(c, sizeof(*ri) + mdatalen, &phys_ofs, &alloclen, ALLOC_NORMAL); -+ if (ret) { -+ jffs2_free_raw_inode(ri); -+ if (S_ISLNK(inode->i_mode & S_IFMT)) -+ kfree(mdata); -+ return ret; -+ } -+ down(&f->sem); -+ ivalid = iattr->ia_valid; -+ -+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri->totlen = cpu_to_je32(sizeof(*ri) + mdatalen); -+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); -+ -+ ri->ino = cpu_to_je32(inode->i_ino); -+ ri->version = cpu_to_je32(++f->highest_version); -+ -+ ri->uid = cpu_to_je16((ivalid & ATTR_UID)?iattr->ia_uid:inode->i_uid); -+ ri->gid = cpu_to_je16((ivalid & ATTR_GID)?iattr->ia_gid:inode->i_gid); -+ -+ if (ivalid & ATTR_MODE) -+ if (iattr->ia_mode & S_ISGID && -+ !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID)) -+ ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID); -+ else -+ ri->mode = cpu_to_jemode(iattr->ia_mode); -+ else -+ ri->mode = cpu_to_jemode(inode->i_mode); -+ -+ -+ ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size); -+ ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime)); -+ ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime)); -+ ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime)); -+ -+ ri->offset = cpu_to_je32(0); -+ ri->csize = ri->dsize = cpu_to_je32(mdatalen); -+ ri->compr = JFFS2_COMPR_NONE; -+ if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { -+ /* It's an extension. Make it a hole node */ -+ ri->compr = JFFS2_COMPR_ZERO; -+ ri->dsize = cpu_to_je32(iattr->ia_size - inode->i_size); -+ ri->offset = cpu_to_je32(inode->i_size); -+ } -+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); -+ if (mdatalen) -+ ri->data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); -+ else -+ ri->data_crc = cpu_to_je32(0); -+ -+ new_metadata = jffs2_write_dnode(c, f, ri, mdata, mdatalen, phys_ofs, ALLOC_NORMAL); -+ if (S_ISLNK(inode->i_mode)) -+ kfree(mdata); -+ -+ if (IS_ERR(new_metadata)) { -+ jffs2_complete_reservation(c); -+ jffs2_free_raw_inode(ri); -+ up(&f->sem); -+ return PTR_ERR(new_metadata); -+ } -+ /* It worked. Update the inode */ -+ inode->i_atime = ITIME(je32_to_cpu(ri->atime)); -+ inode->i_ctime = ITIME(je32_to_cpu(ri->ctime)); -+ inode->i_mtime = ITIME(je32_to_cpu(ri->mtime)); -+ inode->i_mode = jemode_to_cpu(ri->mode); -+ inode->i_uid = je16_to_cpu(ri->uid); -+ inode->i_gid = je16_to_cpu(ri->gid); -+ -+ -+ old_metadata = f->metadata; -+ -+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) -+ jffs2_truncate_fraglist (c, &f->fragtree, iattr->ia_size); -+ -+ if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { -+ jffs2_add_full_dnode_to_inode(c, f, new_metadata); -+ inode->i_size = iattr->ia_size; -+ f->metadata = NULL; -+ } else { -+ f->metadata = new_metadata; -+ } -+ if (old_metadata) { -+ jffs2_mark_node_obsolete(c, old_metadata->raw); -+ jffs2_free_full_dnode(old_metadata); -+ } -+ jffs2_free_raw_inode(ri); -+ -+ up(&f->sem); -+ jffs2_complete_reservation(c); -+ -+ /* We have to do the vmtruncate() without f->sem held, since -+ some pages may be locked and waiting for it in readpage(). -+ We are protected from a simultaneous write() extending i_size -+ back past iattr->ia_size, because do_truncate() holds the -+ generic inode semaphore. */ -+ if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) -+ vmtruncate(inode, iattr->ia_size); -+ -+ return 0; -+} -+ -+int jffs2_setattr(struct dentry *dentry, struct iattr *iattr) -+{ -+ return jffs2_do_setattr(dentry->d_inode, iattr); -+} -+ -+int jffs2_statfs(struct super_block *sb, struct kstatfs *buf) -+{ -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); -+ unsigned long avail; -+ -+ buf->f_type = JFFS2_SUPER_MAGIC; -+ buf->f_bsize = 1 << PAGE_SHIFT; -+ buf->f_blocks = c->flash_size >> PAGE_SHIFT; -+ buf->f_files = 0; -+ buf->f_ffree = 0; -+ buf->f_namelen = JFFS2_MAX_NAME_LEN; -+ -+ spin_lock(&c->erase_completion_lock); -+ -+ avail = c->dirty_size + c->free_size; -+ if (avail > c->sector_size * c->resv_blocks_write) -+ avail -= c->sector_size * c->resv_blocks_write; -+ else -+ avail = 0; -+ -+ buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; -+ -+ D1(jffs2_dump_block_lists(c)); -+ -+ spin_unlock(&c->erase_completion_lock); -+ -+ return 0; -+} -+ -+ -+void jffs2_clear_inode (struct inode *inode) -+{ -+ /* We can forget about this inode for now - drop all -+ * the nodelists associated with it, etc. -+ */ -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); -+ -+ D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); -+ -+ jffs2_do_clear_inode(c, f); -+} -+ -+void jffs2_read_inode (struct inode *inode) -+{ -+ struct jffs2_inode_info *f; -+ struct jffs2_sb_info *c; -+ struct jffs2_raw_inode latest_node; -+ int ret; -+ -+ D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino)); -+ -+ f = JFFS2_INODE_INFO(inode); -+ c = JFFS2_SB_INFO(inode->i_sb); -+ -+ jffs2_init_inode_info(f); -+ -+ ret = jffs2_do_read_inode(c, f, inode->i_ino, &latest_node); -+ -+ if (ret) { -+ make_bad_inode(inode); -+ up(&f->sem); -+ return; -+ } -+ inode->i_mode = jemode_to_cpu(latest_node.mode); -+ inode->i_uid = je16_to_cpu(latest_node.uid); -+ inode->i_gid = je16_to_cpu(latest_node.gid); -+ inode->i_size = je32_to_cpu(latest_node.isize); -+ inode->i_atime = ITIME(je32_to_cpu(latest_node.atime)); -+ inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); -+ inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); -+ -+ inode->i_nlink = f->inocache->nlink; -+ -+ inode->i_blksize = PAGE_SIZE; -+ inode->i_blocks = (inode->i_size + 511) >> 9; -+ -+ switch (inode->i_mode & S_IFMT) { -+ jint16_t rdev; -+ -+ case S_IFLNK: -+ inode->i_op = &jffs2_symlink_inode_operations; -+ break; -+ -+ case S_IFDIR: -+ { -+ struct jffs2_full_dirent *fd; -+ -+ for (fd=f->dents; fd; fd = fd->next) { -+ if (fd->type == DT_DIR && fd->ino) -+ inode->i_nlink++; -+ } -+ /* and '..' */ -+ inode->i_nlink++; -+ /* Root dir gets i_nlink 3 for some reason */ -+ if (inode->i_ino == 1) -+ inode->i_nlink++; -+ -+ inode->i_op = &jffs2_dir_inode_operations; -+ inode->i_fop = &jffs2_dir_operations; -+ break; -+ } -+ case S_IFREG: -+ inode->i_op = &jffs2_file_inode_operations; -+ inode->i_fop = &jffs2_file_operations; -+ inode->i_mapping->a_ops = &jffs2_file_address_operations; -+ inode->i_mapping->nrpages = 0; -+ break; -+ -+ case S_IFBLK: -+ case S_IFCHR: -+ /* Read the device numbers from the media */ -+ D1(printk(KERN_DEBUG "Reading device numbers from flash\n")); -+ if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) { -+ /* Eep */ -+ printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino); -+ up(&f->sem); -+ jffs2_do_clear_inode(c, f); -+ make_bad_inode(inode); -+ return; -+ } -+ -+ case S_IFSOCK: -+ case S_IFIFO: -+ inode->i_op = &jffs2_file_inode_operations; -+ init_special_inode(inode, inode->i_mode, -+ old_decode_dev((je16_to_cpu(rdev)))); -+ break; -+ -+ default: -+ printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu\n", inode->i_mode, (unsigned long)inode->i_ino); -+ } -+ -+ up(&f->sem); -+ -+ D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); -+} -+ -+void jffs2_dirty_inode(struct inode *inode) -+{ -+ struct iattr iattr; -+ -+ if (!(inode->i_state & I_DIRTY_DATASYNC)) { -+ D2(printk(KERN_DEBUG "jffs2_dirty_inode() not calling setattr() for ino #%lu\n", inode->i_ino)); -+ return; -+ } -+ -+ D1(printk(KERN_DEBUG "jffs2_dirty_inode() calling setattr() for ino #%lu\n", inode->i_ino)); -+ -+ iattr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME; -+ iattr.ia_mode = inode->i_mode; -+ iattr.ia_uid = inode->i_uid; -+ iattr.ia_gid = inode->i_gid; -+ iattr.ia_atime = inode->i_atime; -+ iattr.ia_mtime = inode->i_mtime; -+ iattr.ia_ctime = inode->i_ctime; -+ -+ jffs2_do_setattr(inode, &iattr); -+} -+ -+int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) -+{ -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); -+ -+ if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY)) -+ return -EROFS; -+ -+ /* We stop if it was running, then restart if it needs to. -+ This also catches the case where it was stopped and this -+ is just a remount to restart it */ -+ if (!(sb->s_flags & MS_RDONLY)) -+ jffs2_stop_garbage_collect_thread(c); -+ -+ if (!(*flags & MS_RDONLY)) -+ jffs2_start_garbage_collect_thread(c); -+ -+ sb->s_flags = (sb->s_flags & ~MS_RDONLY)|(*flags & MS_RDONLY); -+ -+ return 0; -+} -+ -+void jffs2_write_super (struct super_block *sb) -+{ -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); -+ sb->s_dirt = 0; -+ -+ if (sb->s_flags & MS_RDONLY) -+ return; -+ -+ D1(printk(KERN_DEBUG "jffs2_write_super()\n")); -+ jffs2_garbage_collect_trigger(c); -+ jffs2_erase_pending_blocks(c, 0); -+ jffs2_flush_wbuf_gc(c, 0); -+} -+ -+ -+/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, -+ fill in the raw_inode while you're at it. */ -+struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri) -+{ -+ struct inode *inode; -+ struct super_block *sb = dir_i->i_sb; -+ struct jffs2_sb_info *c; -+ struct jffs2_inode_info *f; -+ int ret; -+ -+ D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode)); -+ -+ c = JFFS2_SB_INFO(sb); -+ -+ inode = new_inode(sb); -+ -+ if (!inode) -+ return ERR_PTR(-ENOMEM); -+ -+ f = JFFS2_INODE_INFO(inode); -+ jffs2_init_inode_info(f); -+ -+ memset(ri, 0, sizeof(*ri)); -+ /* Set OS-specific defaults for new inodes */ -+ ri->uid = cpu_to_je16(current->fsuid); -+ -+ if (dir_i->i_mode & S_ISGID) { -+ ri->gid = cpu_to_je16(dir_i->i_gid); -+ if (S_ISDIR(mode)) -+ mode |= S_ISGID; -+ } else { -+ ri->gid = cpu_to_je16(current->fsgid); -+ } -+ ri->mode = cpu_to_jemode(mode); -+ ret = jffs2_do_new_inode (c, f, mode, ri); -+ if (ret) { -+ make_bad_inode(inode); -+ iput(inode); -+ return ERR_PTR(ret); -+ } -+ inode->i_nlink = 1; -+ inode->i_ino = je32_to_cpu(ri->ino); -+ inode->i_mode = jemode_to_cpu(ri->mode); -+ inode->i_gid = je16_to_cpu(ri->gid); -+ inode->i_uid = je16_to_cpu(ri->uid); -+ inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; -+ ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime)); -+ -+ inode->i_blksize = PAGE_SIZE; -+ inode->i_blocks = 0; -+ inode->i_size = 0; -+ -+ insert_inode_hash(inode); -+ -+ return inode; -+} -+ -+ -+int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) -+{ -+ struct jffs2_sb_info *c; -+ struct inode *root_i; -+ int ret; -+ size_t blocks; -+ -+ c = JFFS2_SB_INFO(sb); -+ -+ c->flash_size = c->mtd->size; -+ -+ /* -+ * Check, if we have to concatenate physical blocks to larger virtual blocks -+ * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation) -+ */ -+ blocks = c->flash_size / c->mtd->erasesize; -+ while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) -+ blocks >>= 1; -+ -+ c->sector_size = c->flash_size / blocks; -+ if (c->sector_size != c->mtd->erasesize) -+ printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", -+ c->mtd->erasesize / 1024, c->sector_size / 1024); -+ -+ if (c->flash_size < 5*c->sector_size) { -+ printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size); -+ return -EINVAL; -+ } -+ -+ c->cleanmarker_size = sizeof(struct jffs2_unknown_node); -+ /* Joern -- stick alignment for weird 8-byte-page flash here */ -+ -+ if (jffs2_cleanmarker_oob(c)) { -+ /* NAND (or other bizarre) flash... do setup accordingly */ -+ ret = jffs2_nand_flash_setup(c); -+ if (ret) -+ return ret; -+ } -+ -+ c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL); -+ if (!c->inocache_list) { -+ ret = -ENOMEM; -+ goto out_wbuf; -+ } -+ memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *)); -+ -+ if ((ret = jffs2_do_mount_fs(c))) -+ goto out_inohash; -+ -+ ret = -EINVAL; -+ -+ D1(printk(KERN_DEBUG "jffs2_do_fill_super(): Getting root inode\n")); -+ root_i = iget(sb, 1); -+ if (is_bad_inode(root_i)) { -+ D1(printk(KERN_WARNING "get root inode failed\n")); -+ goto out_nodes; -+ } -+ -+ D1(printk(KERN_DEBUG "jffs2_do_fill_super(): d_alloc_root()\n")); -+ sb->s_root = d_alloc_root(root_i); -+ if (!sb->s_root) -+ goto out_root_i; -+ -+#if LINUX_VERSION_CODE >= 0x20403 -+ sb->s_maxbytes = 0xFFFFFFFF; -+#endif -+ sb->s_blocksize = PAGE_CACHE_SIZE; -+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT; -+ sb->s_magic = JFFS2_SUPER_MAGIC; -+ if (!(sb->s_flags & MS_RDONLY)) -+ jffs2_start_garbage_collect_thread(c); -+ return 0; -+ -+ out_root_i: -+ iput(root_i); -+ out_nodes: -+ jffs2_free_ino_caches(c); -+ jffs2_free_raw_node_refs(c); -+ kfree(c->blocks); -+ out_inohash: -+ kfree(c->inocache_list); -+ out_wbuf: -+ jffs2_nand_flash_cleanup(c); -+ -+ return ret; -+} -+ -+void jffs2_gc_release_inode(struct jffs2_sb_info *c, -+ struct jffs2_inode_info *f) -+{ -+ iput(OFNI_EDONI_2SFFJ(f)); -+} -+ -+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, -+ int inum, int nlink) -+{ -+ struct inode *inode; -+ struct jffs2_inode_cache *ic; -+ if (!nlink) { -+ /* The inode has zero nlink but its nodes weren't yet marked -+ obsolete. This has to be because we're still waiting for -+ the final (close() and) iput() to happen. -+ -+ There's a possibility that the final iput() could have -+ happened while we were contemplating. In order to ensure -+ that we don't cause a new read_inode() (which would fail) -+ for the inode in question, we use ilookup() in this case -+ instead of iget(). -+ -+ The nlink can't _become_ zero at this point because we're -+ holding the alloc_sem, and jffs2_do_unlink() would also -+ need that while decrementing nlink on any inode. -+ */ -+ inode = ilookup(OFNI_BS_2SFFJ(c), inum); -+ if (!inode) { -+ D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n", -+ inum)); -+ -+ spin_lock(&c->inocache_lock); -+ ic = jffs2_get_ino_cache(c, inum); -+ if (!ic) { -+ D1(printk(KERN_DEBUG "Inode cache for ino #%u is gone.\n", inum)); -+ spin_unlock(&c->inocache_lock); -+ return NULL; -+ } -+ if (ic->state != INO_STATE_CHECKEDABSENT) { -+ /* Wait for progress. Don't just loop */ -+ D1(printk(KERN_DEBUG "Waiting for ino #%u in state %d\n", -+ ic->ino, ic->state)); -+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); -+ } else { -+ spin_unlock(&c->inocache_lock); -+ } -+ -+ return NULL; -+ } -+ } else { -+ /* Inode has links to it still; they're not going away because -+ jffs2_do_unlink() would need the alloc_sem and we have it. -+ Just iget() it, and if read_inode() is necessary that's OK. -+ */ -+ inode = iget(OFNI_BS_2SFFJ(c), inum); -+ if (!inode) -+ return ERR_PTR(-ENOMEM); -+ } -+ if (is_bad_inode(inode)) { -+ printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n", -+ inum, nlink); -+ /* NB. This will happen again. We need to do something appropriate here. */ -+ iput(inode); -+ return ERR_PTR(-EIO); -+ } -+ -+ return JFFS2_INODE_INFO(inode); -+} -+ -+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, -+ struct jffs2_inode_info *f, -+ unsigned long offset, -+ unsigned long *priv) -+{ -+ struct inode *inode = OFNI_EDONI_2SFFJ(f); -+ struct page *pg; -+ -+ pg = read_cache_page(inode->i_mapping, offset >> PAGE_CACHE_SHIFT, -+ (void *)jffs2_do_readpage_unlock, inode); -+ if (IS_ERR(pg)) -+ return (void *)pg; -+ -+ *priv = (unsigned long)pg; -+ return kmap(pg); -+} -+ -+void jffs2_gc_release_page(struct jffs2_sb_info *c, -+ unsigned char *ptr, -+ unsigned long *priv) -+{ -+ struct page *pg = (void *)*priv; -+ -+ kunmap(pg); -+ page_cache_release(pg); -+} -diff -Nurb linux-mips-2.4.27/fs/jffs2/gc.c linux/fs/jffs2/gc.c ---- linux-mips-2.4.27/fs/jffs2/gc.c 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/gc.c 2004-11-19 10:25:12.104168632 +0100 -@@ -1,76 +1,67 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/kernel.h> - #include <linux/mtd/mtd.h> - #include <linux/slab.h> --#include <linux/jffs2.h> --#include <linux/sched.h> --#include <linux/interrupt.h> - #include <linux/pagemap.h> --#include "nodelist.h" - #include <linux/crc32.h> -+#include <linux/compiler.h> -+#include <linux/stat.h> -+#include "nodelist.h" - -+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, -+ struct jffs2_inode_cache *ic, -+ struct jffs2_raw_node_ref *raw); - static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dnode *fd); -+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); - static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dirent *fd); -+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); - static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dirent *fd); -+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd); - static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *indeo, struct jffs2_full_dnode *fn, -- __u32 start, __u32 end); -+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, -+ uint32_t start, uint32_t end); - static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dnode *fn, -- __u32 start, __u32 end); -+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, -+ uint32_t start, uint32_t end); -+static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f); - - /* Called with erase_completion_lock held */ - static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) - { - struct jffs2_eraseblock *ret; - struct list_head *nextlist = NULL; -+ int n = jiffies % 128; - - /* Pick an eraseblock to garbage collect next. This is where we'll - put the clever wear-levelling algorithms. Eventually. */ -- if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > JFFS2_RESERVED_BLOCKS_GCBAD) { -+ /* We possibly want to favour the dirtier blocks more when the -+ number of free blocks is low. */ -+ if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) { - D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n")); - nextlist = &c->bad_used_list; -- } else if (jiffies % 100 && !list_empty(&c->dirty_list)) { -- /* Most of the time, pick one off the dirty list */ -+ } else if (n < 50 && !list_empty(&c->erasable_list)) { -+ /* Note that most of them will have gone directly to be erased. -+ So don't favour the erasable_list _too_ much. */ -+ D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next\n")); -+ nextlist = &c->erasable_list; -+ } else if (n < 110 && !list_empty(&c->very_dirty_list)) { -+ /* Most of the time, pick one off the very_dirty list */ -+ D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next\n")); -+ nextlist = &c->very_dirty_list; -+ } else if (n < 126 && !list_empty(&c->dirty_list)) { - D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next\n")); - nextlist = &c->dirty_list; - } else if (!list_empty(&c->clean_list)) { -@@ -80,9 +71,16 @@ - D1(printk(KERN_DEBUG "Picking block from dirty_list to GC next (clean_list was empty)\n")); - - nextlist = &c->dirty_list; -+ } else if (!list_empty(&c->very_dirty_list)) { -+ D1(printk(KERN_DEBUG "Picking block from very_dirty_list to GC next (clean_list and dirty_list were empty)\n")); -+ nextlist = &c->very_dirty_list; -+ } else if (!list_empty(&c->erasable_list)) { -+ D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n")); -+ -+ nextlist = &c->erasable_list; - } else { -- /* Eep. Both were empty */ -- printk(KERN_NOTICE "jffs2: No clean _or_ dirty blocks to GC from! Where are they all?\n"); -+ /* Eep. All were empty */ -+ printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"); - return NULL; - } - -@@ -94,6 +92,17 @@ - printk(KERN_WARNING "Eep. ret->gc_node for block at 0x%08x is NULL\n", ret->offset); - BUG(); - } -+ -+ /* Have we accidentally picked a clean block with wasted space ? */ -+ if (ret->wasted_size) { -+ D1(printk(KERN_DEBUG "Converting wasted_size %08x to dirty_size\n", ret->wasted_size)); -+ ret->dirty_size += ret->wasted_size; -+ c->wasted_size -= ret->wasted_size; -+ c->dirty_size += ret->wasted_size; -+ ret->wasted_size = 0; -+ } -+ -+ D1(jffs2_dump_block_lists(c)); - return ret; - } - -@@ -103,21 +112,90 @@ - */ - int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) - { -- struct jffs2_eraseblock *jeb; - struct jffs2_inode_info *f; -- struct jffs2_raw_node_ref *raw; -- struct jffs2_node_frag *frag; -- struct jffs2_full_dnode *fn = NULL; -- struct jffs2_full_dirent *fd; - struct jffs2_inode_cache *ic; -- __u32 start = 0, end = 0, nrfrags = 0; -- struct inode *inode; -- int ret = 0; -+ struct jffs2_eraseblock *jeb; -+ struct jffs2_raw_node_ref *raw; -+ int ret = 0, inum, nlink; - - if (down_interruptible(&c->alloc_sem)) - return -EINTR; - -- spin_lock_bh(&c->erase_completion_lock); -+ for (;;) { -+ spin_lock(&c->erase_completion_lock); -+ if (!c->unchecked_size) -+ break; -+ -+ /* We can't start doing GC yet. We haven't finished checking -+ the node CRCs etc. Do it now. */ -+ -+ /* checked_ino is protected by the alloc_sem */ -+ if (c->checked_ino > c->highest_ino) { -+ printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", -+ c->unchecked_size); -+ D1(jffs2_dump_block_lists(c)); -+ spin_unlock(&c->erase_completion_lock); -+ BUG(); -+ } -+ -+ spin_unlock(&c->erase_completion_lock); -+ -+ spin_lock(&c->inocache_lock); -+ -+ ic = jffs2_get_ino_cache(c, c->checked_ino++); -+ -+ if (!ic) { -+ spin_unlock(&c->inocache_lock); -+ continue; -+ } -+ -+ if (!ic->nlink) { -+ D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n", -+ ic->ino)); -+ spin_unlock(&c->inocache_lock); -+ continue; -+ } -+ switch(ic->state) { -+ case INO_STATE_CHECKEDABSENT: -+ case INO_STATE_PRESENT: -+ D1(printk(KERN_DEBUG "Skipping ino #%u already checked\n", ic->ino)); -+ spin_unlock(&c->inocache_lock); -+ continue; -+ -+ case INO_STATE_GC: -+ case INO_STATE_CHECKING: -+ printk(KERN_WARNING "Inode #%u is in state %d during CRC check phase!\n", ic->ino, ic->state); -+ spin_unlock(&c->inocache_lock); -+ BUG(); -+ -+ case INO_STATE_READING: -+ /* We need to wait for it to finish, lest we move on -+ and trigger the BUG() above while we haven't yet -+ finished checking all its nodes */ -+ D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino)); -+ up(&c->alloc_sem); -+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); -+ return 0; -+ -+ default: -+ BUG(); -+ -+ case INO_STATE_UNCHECKED: -+ ; -+ } -+ ic->state = INO_STATE_CHECKING; -+ spin_unlock(&c->inocache_lock); -+ -+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%u\n", ic->ino)); -+ -+ ret = jffs2_do_crccheck_inode(c, ic); -+ if (ret) -+ printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); -+ -+ jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); -+ up(&c->alloc_sem); -+ return ret; -+ } - - /* First, work out which block we're garbage-collecting */ - jeb = c->gcblock; -@@ -127,12 +205,14 @@ - - if (!jeb) { - printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"); -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - up(&c->alloc_sem); - return -EIO; - } - -- D1(printk(KERN_DEBUG "garbage collect from block at phys 0x%08x\n", jeb->offset)); -+ D1(printk(KERN_DEBUG "GC from block %08x, used_size %08x, dirty_size %08x, free_size %08x\n", jeb->offset, jeb->used_size, jeb->dirty_size, jeb->free_size)); -+ D1(if (c->nextblock) -+ printk(KERN_DEBUG "Nextblock at %08x, used_size %08x, dirty_size %08x, wasted_size %08x, free_size %08x\n", c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->free_size)); - - if (!jeb->used_size) { - up(&c->alloc_sem); -@@ -141,92 +221,211 @@ - - raw = jeb->gc_node; - -- while(raw->flash_offset & 1) { -- D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", raw->flash_offset &~3)); -- jeb->gc_node = raw = raw->next_phys; -- if (!raw) { -+ while(ref_obsolete(raw)) { -+ D1(printk(KERN_DEBUG "Node at 0x%08x is obsolete... skipping\n", ref_offset(raw))); -+ raw = raw->next_phys; -+ if (unlikely(!raw)) { - printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); - printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", - jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); -- spin_unlock_bh(&c->erase_completion_lock); -+ jeb->gc_node = raw; -+ spin_unlock(&c->erase_completion_lock); - up(&c->alloc_sem); - BUG(); - } - } -- D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", raw->flash_offset &~3)); -+ jeb->gc_node = raw; -+ -+ D1(printk(KERN_DEBUG "Going to garbage collect node at 0x%08x\n", ref_offset(raw))); -+ - if (!raw->next_in_ino) { - /* Inode-less node. Clean marker, snapshot or something like that */ -- spin_unlock_bh(&c->erase_completion_lock); -+ /* FIXME: If it's something that needs to be copied, including something -+ we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */ -+ spin_unlock(&c->erase_completion_lock); - jffs2_mark_node_obsolete(c, raw); - up(&c->alloc_sem); - goto eraseit_lock; - } - - ic = jffs2_raw_ref_to_ic(raw); -- D1(printk(KERN_DEBUG "Inode number is #%u\n", ic->ino)); -- -- spin_unlock_bh(&c->erase_completion_lock); - -- D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, raw->flash_offset&~3, ic->ino)); -- if (!ic->nlink) { -- /* The inode has zero nlink but its nodes weren't yet marked -- obsolete. This has to be because we're still waiting for -- the final (close() and) iput() to happen. -- -- There's a possibility that the final iput() could have -- happened while we were contemplating. In order to ensure -- that we don't cause a new read_inode() (which would fail) -- for the inode in question, we use ilookup() in this case -- instead of iget(). -- -- The nlink can't _become_ zero at this point because we're -- holding the alloc_sem, and jffs2_do_unlink() would also -- need that while decrementing nlink on any inode. -+ /* We need to hold the inocache. Either the erase_completion_lock or -+ the inocache_lock are sufficient; we trade down since the inocache_lock -+ causes less contention. */ -+ spin_lock(&c->inocache_lock); -+ -+ spin_unlock(&c->erase_completion_lock); -+ -+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), ic->ino)); -+ -+ /* Three possibilities: -+ 1. Inode is already in-core. We must iget it and do proper -+ updating to its fragtree, etc. -+ 2. Inode is not in-core, node is REF_PRISTINE. We lock the -+ inocache to prevent a read_inode(), copy the node intact. -+ 3. Inode is not in-core, node is not pristine. We must iget() -+ and take the slow path. - */ -- inode = ilookup(OFNI_BS_2SFFJ(c), ic->ino); -- if (!inode) { -- D1(printk(KERN_DEBUG "ilookup() failed for ino #%u; inode is probably deleted.\n", -+ -+ switch(ic->state) { -+ case INO_STATE_CHECKEDABSENT: -+ /* It's been checked, but it's not currently in-core. -+ We can just copy any pristine nodes, but have -+ to prevent anyone else from doing read_inode() while -+ we're at it, so we set the state accordingly */ -+ if (ref_flags(raw) == REF_PRISTINE) -+ ic->state = INO_STATE_GC; -+ else { -+ D1(printk(KERN_DEBUG "Ino #%u is absent but node not REF_PRISTINE. Reading.\n", - ic->ino)); -- up(&c->alloc_sem); -- return 0; - } -- } else { -- /* Inode has links to it still; they're not going away because -- jffs2_do_unlink() would need the alloc_sem and we have it. -- Just iget() it, and if read_inode() is necessary that's OK. -+ break; -+ -+ case INO_STATE_PRESENT: -+ /* It's in-core. GC must iget() it. */ -+ break; -+ -+ case INO_STATE_UNCHECKED: -+ case INO_STATE_CHECKING: -+ case INO_STATE_GC: -+ /* Should never happen. We should have finished checking -+ by the time we actually start doing any GC, and since -+ we're holding the alloc_sem, no other garbage collection -+ can happen. - */ -- inode = iget(OFNI_BS_2SFFJ(c), ic->ino); -- if (!inode) { -+ printk(KERN_CRIT "Inode #%u already in state %d in jffs2_garbage_collect_pass()!\n", -+ ic->ino, ic->state); - up(&c->alloc_sem); -- return -ENOMEM; -+ spin_unlock(&c->inocache_lock); -+ BUG(); -+ -+ case INO_STATE_READING: -+ /* Someone's currently trying to read it. We must wait for -+ them to finish and then go through the full iget() route -+ to do the GC. However, sometimes read_inode() needs to get -+ the alloc_sem() (for marking nodes invalid) so we must -+ drop the alloc_sem before sleeping. */ -+ -+ up(&c->alloc_sem); -+ D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", -+ ic->ino, ic->state)); -+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); -+ /* And because we dropped the alloc_sem we must start again from the -+ beginning. Ponder chance of livelock here -- we're returning success -+ without actually making any progress. -+ -+ Q: What are the chances that the inode is back in INO_STATE_READING -+ again by the time we next enter this function? And that this happens -+ enough times to cause a real delay? -+ -+ A: Small enough that I don't care :) -+ */ -+ return 0; - } -+ -+ /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the -+ node intact, and we don't have to muck about with the fragtree etc. -+ because we know it's not in-core. If it _was_ in-core, we go through -+ all the iget() crap anyway */ -+ -+ if (ic->state == INO_STATE_GC) { -+ spin_unlock(&c->inocache_lock); -+ -+ ret = jffs2_garbage_collect_pristine(c, ic, raw); -+ -+ spin_lock(&c->inocache_lock); -+ ic->state = INO_STATE_CHECKEDABSENT; -+ wake_up(&c->inocache_wq); -+ -+ if (ret != -EBADFD) { -+ spin_unlock(&c->inocache_lock); -+ goto release_sem; - } -- if (is_bad_inode(inode)) { -- printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino); -- /* NB. This will happen again. We need to do something appropriate here. */ -+ -+ /* Fall through if it wanted us to, with inocache_lock held */ -+ } -+ -+ /* Prevent the fairly unlikely race where the gcblock is -+ entirely obsoleted by the final close of a file which had -+ the only valid nodes in the block, followed by erasure, -+ followed by freeing of the ic because the erased block(s) -+ held _all_ the nodes of that inode.... never been seen but -+ it's vaguely possible. */ -+ -+ inum = ic->ino; -+ nlink = ic->nlink; -+ spin_unlock(&c->inocache_lock); -+ -+ f = jffs2_gc_fetch_inode(c, inum, nlink); -+ if (IS_ERR(f)) -+ return PTR_ERR(f); -+ if (!f) -+ return 0; -+ -+ ret = jffs2_garbage_collect_live(c, jeb, raw, f); -+ -+ jffs2_gc_release_inode(c, f); -+ -+ release_sem: - up(&c->alloc_sem); -- iput(inode); -- return -EIO; -+ -+ eraseit_lock: -+ /* If we've finished this block, start it erasing */ -+ spin_lock(&c->erase_completion_lock); -+ -+ eraseit: -+ if (c->gcblock && !c->gcblock->used_size) { -+ D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset)); -+ /* We're GC'ing an empty block? */ -+ list_add_tail(&c->gcblock->list, &c->erase_pending_list); -+ c->gcblock = NULL; -+ c->nr_erasing_blocks++; -+ jffs2_erase_pending_trigger(c); - } -+ spin_unlock(&c->erase_completion_lock); -+ -+ return ret; -+} -+ -+static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -+ struct jffs2_raw_node_ref *raw, struct jffs2_inode_info *f) -+{ -+ struct jffs2_node_frag *frag; -+ struct jffs2_full_dnode *fn = NULL; -+ struct jffs2_full_dirent *fd; -+ uint32_t start = 0, end = 0, nrfrags = 0; -+ int ret = 0; - -- f = JFFS2_INODE_INFO(inode); - down(&f->sem); -+ - /* Now we have the lock for this inode. Check that it's still the one at the head - of the list. */ - -- if (raw->flash_offset & 1) { -+ spin_lock(&c->erase_completion_lock); -+ -+ if (c->gcblock != jeb) { -+ spin_unlock(&c->erase_completion_lock); -+ D1(printk(KERN_DEBUG "GC block is no longer gcblock. Restart\n")); -+ goto upnout; -+ } -+ if (ref_obsolete(raw)) { -+ spin_unlock(&c->erase_completion_lock); - D1(printk(KERN_DEBUG "node to be GC'd was obsoleted in the meantime.\n")); - /* They'll call again */ - goto upnout; - } -+ spin_unlock(&c->erase_completion_lock); -+ - /* OK. Looks safe. And nobody can get us now because we have the semaphore. Move the block */ - if (f->metadata && f->metadata->raw == raw) { - fn = f->metadata; -- ret = jffs2_garbage_collect_metadata(c, jeb, inode, fn); -+ ret = jffs2_garbage_collect_metadata(c, jeb, f, fn); - goto upnout; - } - -- for (frag = f->fraglist; frag; frag = frag->next) { -+ /* FIXME. Read node and do lookup? */ -+ for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { - if (frag->node && frag->node->raw == raw) { - fn = frag->node; - end = frag->ofs + frag->size; -@@ -237,13 +436,22 @@ - } - } - if (fn) { -+ if (ref_flags(raw) == REF_PRISTINE) { -+ ret = jffs2_garbage_collect_pristine(c, f->inocache, raw); -+ if (!ret) { -+ /* Urgh. Return it sensibly. */ -+ frag->node->raw = f->inocache->nodes; -+ } -+ if (ret != -EBADFD) -+ goto upnout; -+ } - /* We found a datanode. Do the GC */ - if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) { - /* It crosses a page boundary. Therefore, it must be a hole. */ -- ret = jffs2_garbage_collect_hole(c, jeb, inode, fn, start, end); -+ ret = jffs2_garbage_collect_hole(c, jeb, f, fn, start, end); - } else { - /* It could still be a hole. But we GC the page this way anyway */ -- ret = jffs2_garbage_collect_dnode(c, jeb, inode, fn, start, end); -+ ret = jffs2_garbage_collect_dnode(c, jeb, f, fn, start, end); - } - goto upnout; - } -@@ -255,12 +463,13 @@ - } - - if (fd && fd->ino) { -- ret = jffs2_garbage_collect_dirent(c, jeb, inode, fd); -+ ret = jffs2_garbage_collect_dirent(c, jeb, f, fd); - } else if (fd) { -- ret = jffs2_garbage_collect_deletion_dirent(c, jeb, inode, fd); -+ ret = jffs2_garbage_collect_deletion_dirent(c, jeb, f, fd); - } else { -- printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%lu\n", raw->flash_offset&~3, inode->i_ino); -- if (raw->flash_offset & 1) { -+ printk(KERN_WARNING "Raw node at 0x%08x wasn't in node lists for ino #%u\n", -+ ref_offset(raw), f->inocache->ino); -+ if (ref_obsolete(raw)) { - printk(KERN_WARNING "But it's obsolete so we don't mind too much\n"); - } else { - ret = -EIO; -@@ -268,46 +477,197 @@ - } - upnout: - up(&f->sem); -- up(&c->alloc_sem); -- iput(inode); - -- eraseit_lock: -- /* If we've finished this block, start it erasing */ -- spin_lock_bh(&c->erase_completion_lock); -+ return ret; -+} - -- eraseit: -- if (c->gcblock && !c->gcblock->used_size) { -- D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset)); -- /* We're GC'ing an empty block? */ -- list_add_tail(&c->gcblock->list, &c->erase_pending_list); -- c->gcblock = NULL; -- c->nr_erasing_blocks++; -- jffs2_erase_pending_trigger(c); -+static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, -+ struct jffs2_inode_cache *ic, -+ struct jffs2_raw_node_ref *raw) -+{ -+ union jffs2_node_union *node; -+ struct jffs2_raw_node_ref *nraw; -+ size_t retlen; -+ int ret; -+ uint32_t phys_ofs, alloclen; -+ uint32_t crc, rawlen; -+ int retried = 0; -+ -+ D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw))); -+ -+ rawlen = ref_totlen(c, c->gcblock, raw); -+ -+ /* Ask for a small amount of space (or the totlen if smaller) because we -+ don't want to force wastage of the end of a block if splitting would -+ work. */ -+ ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, -+ rawlen), &phys_ofs, &alloclen); -+ if (ret) -+ return ret; -+ -+ if (alloclen < rawlen) { -+ /* Doesn't fit untouched. We'll go the old route and split it */ -+ return -EBADFD; -+ } -+ -+ node = kmalloc(rawlen, GFP_KERNEL); -+ if (!node) -+ return -ENOMEM; -+ -+ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)node); -+ if (!ret && retlen != rawlen) -+ ret = -EIO; -+ if (ret) -+ goto out_node; -+ -+ crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4); -+ if (je32_to_cpu(node->u.hdr_crc) != crc) { -+ printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -+ ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); -+ goto bail; -+ } -+ -+ switch(je16_to_cpu(node->u.nodetype)) { -+ case JFFS2_NODETYPE_INODE: -+ crc = crc32(0, node, sizeof(node->i)-8); -+ if (je32_to_cpu(node->i.node_crc) != crc) { -+ printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -+ ref_offset(raw), je32_to_cpu(node->i.node_crc), crc); -+ goto bail; -+ } -+ -+ if (je32_to_cpu(node->i.dsize)) { -+ crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize)); -+ if (je32_to_cpu(node->i.data_crc) != crc) { -+ printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -+ ref_offset(raw), je32_to_cpu(node->i.data_crc), crc); -+ goto bail; - } -- spin_unlock_bh(&c->erase_completion_lock); -+ } -+ break; -+ -+ case JFFS2_NODETYPE_DIRENT: -+ crc = crc32(0, node, sizeof(node->d)-8); -+ if (je32_to_cpu(node->d.node_crc) != crc) { -+ printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -+ ref_offset(raw), je32_to_cpu(node->d.node_crc), crc); -+ goto bail; -+ } -+ -+ if (node->d.nsize) { -+ crc = crc32(0, node->d.name, node->d.nsize); -+ if (je32_to_cpu(node->d.name_crc) != crc) { -+ printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -+ ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); -+ goto bail; -+ } -+ } -+ break; -+ default: -+ printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", -+ ref_offset(raw), je16_to_cpu(node->u.nodetype)); -+ goto bail; -+ } -+ -+ nraw = jffs2_alloc_raw_node_ref(); -+ if (!nraw) { -+ ret = -ENOMEM; -+ goto out_node; -+ } -+ -+ /* OK, all the CRCs are good; this node can just be copied as-is. */ -+ retry: -+ nraw->flash_offset = phys_ofs; -+ nraw->__totlen = rawlen; -+ nraw->next_phys = NULL; -+ -+ ret = jffs2_flash_write(c, phys_ofs, rawlen, &retlen, (char *)node); -+ -+ if (ret || (retlen != rawlen)) { -+ printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", -+ rawlen, phys_ofs, ret, retlen); -+ if (retlen) { -+ /* Doesn't belong to any inode */ -+ nraw->next_in_ino = NULL; -+ -+ nraw->flash_offset |= REF_OBSOLETE; -+ jffs2_add_physical_node_ref(c, nraw); -+ jffs2_mark_node_obsolete(c, nraw); -+ } else { -+ printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset); -+ jffs2_free_raw_node_ref(nraw); -+ } -+ if (!retried && (nraw == jffs2_alloc_raw_node_ref())) { -+ /* Try to reallocate space and retry */ -+ uint32_t dummy; -+ struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size]; -+ -+ retried = 1; -+ -+ D1(printk(KERN_DEBUG "Retrying failed write of REF_PRISTINE node.\n")); -+ -+ ACCT_SANITY_CHECK(c,jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ -+ ret = jffs2_reserve_space_gc(c, rawlen, &phys_ofs, &dummy); -+ -+ if (!ret) { -+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", phys_ofs)); - -+ ACCT_SANITY_CHECK(c,jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ -+ goto retry; -+ } -+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); -+ jffs2_free_raw_node_ref(nraw); -+ } -+ -+ if (!ret) -+ ret = -EIO; -+ goto out_node; -+ } -+ nraw->flash_offset |= REF_PRISTINE; -+ jffs2_add_physical_node_ref(c, nraw); -+ -+ /* Link into per-inode list. This is safe because of the ic -+ state being INO_STATE_GC. Note that if we're doing this -+ for an inode which is in-code, the 'nraw' pointer is then -+ going to be fetched from ic->nodes by our caller. */ -+ nraw->next_in_ino = ic->nodes; -+ ic->nodes = nraw; -+ -+ jffs2_mark_node_obsolete(c, raw); -+ D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); -+ -+ out_node: -+ kfree(node); - return ret; -+ bail: -+ ret = -EBADFD; -+ goto out_node; - } - - static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dnode *fn) -+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) - { -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_full_dnode *new_fn; - struct jffs2_raw_inode ri; -- unsigned short dev; -+ jint16_t dev; - char *mdata = NULL, mdatalen = 0; -- __u32 alloclen, phys_ofs; -+ uint32_t alloclen, phys_ofs; - int ret; - -- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { -+ if (S_ISBLK(JFFS2_F_I_MODE(f)) || -+ S_ISCHR(JFFS2_F_I_MODE(f)) ) { - /* For these, we don't actually need to read the old node */ -- dev = (MAJOR(to_kdev_t(inode->i_rdev)) << 8) | -- MINOR(to_kdev_t(inode->i_rdev)); -+ /* FIXME: for minor or major > 255. */ -+ dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | -+ JFFS2_F_I_RDEV_MIN(f))); - mdata = (char *)&dev; - mdatalen = sizeof(dev); - D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen)); -- } else if (S_ISLNK(inode->i_mode)) { -+ } else if (S_ISLNK(JFFS2_F_I_MODE(f))) { - mdatalen = fn->size; - mdata = kmalloc(fn->size, GFP_KERNEL); - if (!mdata) { -@@ -326,34 +686,34 @@ - - ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen); - if (ret) { -- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_metadata failed: %d\n", -+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", - sizeof(ri)+ mdatalen, ret); - goto out; - } - - memset(&ri, 0, sizeof(ri)); -- ri.magic = JFFS2_MAGIC_BITMASK; -- ri.nodetype = JFFS2_NODETYPE_INODE; -- ri.totlen = sizeof(ri) + mdatalen; -- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); -- -- ri.ino = inode->i_ino; -- ri.version = ++f->highest_version; -- ri.mode = inode->i_mode; -- ri.uid = inode->i_uid; -- ri.gid = inode->i_gid; -- ri.isize = inode->i_size; -- ri.atime = inode->i_atime; -- ri.ctime = inode->i_ctime; -- ri.mtime = inode->i_mtime; -- ri.offset = 0; -- ri.csize = mdatalen; -- ri.dsize = mdatalen; -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri) + mdatalen); -+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); -+ -+ ri.ino = cpu_to_je32(f->inocache->ino); -+ ri.version = cpu_to_je32(++f->highest_version); -+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); -+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); -+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); -+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); -+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); -+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); -+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); -+ ri.offset = cpu_to_je32(0); -+ ri.csize = cpu_to_je32(mdatalen); -+ ri.dsize = cpu_to_je32(mdatalen); - ri.compr = JFFS2_COMPR_NONE; -- ri.node_crc = crc32(0, &ri, sizeof(ri)-8); -- ri.data_crc = crc32(0, mdata, mdatalen); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); -+ ri.data_crc = cpu_to_je32(crc32(0, mdata, mdatalen)); - -- new_fn = jffs2_write_dnode(inode, &ri, mdata, mdatalen, phys_ofs, NULL); -+ new_fn = jffs2_write_dnode(c, f, &ri, mdata, mdatalen, phys_ofs, ALLOC_GC); - - if (IS_ERR(new_fn)) { - printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn)); -@@ -364,41 +724,40 @@ - jffs2_free_full_dnode(fn); - f->metadata = new_fn; - out: -- if (S_ISLNK(inode->i_mode)) -+ if (S_ISLNK(JFFS2_F_I_MODE(f))) - kfree(mdata); - return ret; - } - - static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dirent *fd) -+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) - { -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_full_dirent *new_fd; - struct jffs2_raw_dirent rd; -- __u32 alloclen, phys_ofs; -+ uint32_t alloclen, phys_ofs; - int ret; - -- rd.magic = JFFS2_MAGIC_BITMASK; -- rd.nodetype = JFFS2_NODETYPE_DIRENT; -+ rd.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd.nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); - rd.nsize = strlen(fd->name); -- rd.totlen = sizeof(rd) + rd.nsize; -- rd.hdr_crc = crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4); -+ rd.totlen = cpu_to_je32(sizeof(rd) + rd.nsize); -+ rd.hdr_crc = cpu_to_je32(crc32(0, &rd, sizeof(struct jffs2_unknown_node)-4)); - -- rd.pino = inode->i_ino; -- rd.version = ++f->highest_version; -- rd.ino = fd->ino; -- rd.mctime = max(inode->i_mtime, inode->i_ctime); -+ rd.pino = cpu_to_je32(f->inocache->ino); -+ rd.version = cpu_to_je32(++f->highest_version); -+ rd.ino = cpu_to_je32(fd->ino); -+ rd.mctime = cpu_to_je32(max(JFFS2_F_I_MTIME(f), JFFS2_F_I_CTIME(f))); - rd.type = fd->type; -- rd.node_crc = crc32(0, &rd, sizeof(rd)-8); -- rd.name_crc = crc32(0, fd->name, rd.nsize); -+ rd.node_crc = cpu_to_je32(crc32(0, &rd, sizeof(rd)-8)); -+ rd.name_crc = cpu_to_je32(crc32(0, fd->name, rd.nsize)); - - ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); - if (ret) { -- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dirent failed: %d\n", -+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", - sizeof(rd)+rd.nsize, ret); - return ret; - } -- new_fd = jffs2_write_dirent(inode, &rd, fd->name, rd.nsize, phys_ofs, NULL); -+ new_fd = jffs2_write_dirent(c, f, &rd, fd->name, rd.nsize, phys_ofs, ALLOC_GC); - - if (IS_ERR(new_fd)) { - printk(KERN_WARNING "jffs2_write_dirent in garbage_collect_dirent failed: %ld\n", PTR_ERR(new_fd)); -@@ -409,19 +768,98 @@ - } - - static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dirent *fd) -+ struct jffs2_inode_info *f, struct jffs2_full_dirent *fd) - { -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_full_dirent **fdp = &f->dents; - int found = 0; - -- /* FIXME: When we run on NAND flash, we need to work out whether -- this deletion dirent is still needed to actively delete a -- 'real' dirent with the same name that's still somewhere else -- on the flash. For now, we know that we've actually obliterated -- all the older dirents when they became obsolete, so we didn't -- really need to write the deletion to flash in the first place. -- */ -+ /* On a medium where we can't actually mark nodes obsolete -+ pernamently, such as NAND flash, we need to work out -+ whether this deletion dirent is still needed to actively -+ delete a 'real' dirent with the same name that's still -+ somewhere else on the flash. */ -+ if (!jffs2_can_mark_obsolete(c)) { -+ struct jffs2_raw_dirent *rd; -+ struct jffs2_raw_node_ref *raw; -+ int ret; -+ size_t retlen; -+ int name_len = strlen(fd->name); -+ uint32_t name_crc = crc32(0, fd->name, name_len); -+ uint32_t rawlen = ref_totlen(c, jeb, fd->raw); -+ -+ rd = kmalloc(rawlen, GFP_KERNEL); -+ if (!rd) -+ return -ENOMEM; -+ -+ /* Prevent the erase code from nicking the obsolete node refs while -+ we're looking at them. I really don't like this extra lock but -+ can't see any alternative. Suggestions on a postcard to... */ -+ down(&c->erase_free_sem); -+ -+ for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) { -+ -+ /* We only care about obsolete ones */ -+ if (!(ref_obsolete(raw))) -+ continue; -+ -+ /* Any dirent with the same name is going to have the same length... */ -+ if (ref_totlen(c, NULL, raw) != rawlen) -+ continue; -+ -+ /* Doesn't matter if there's one in the same erase block. We're going to -+ delete it too at the same time. */ -+ if ((raw->flash_offset & ~(c->sector_size-1)) == -+ (fd->raw->flash_offset & ~(c->sector_size-1))) -+ continue; -+ -+ D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw))); -+ -+ /* This is an obsolete node belonging to the same directory, and it's of the right -+ length. We need to take a closer look...*/ -+ ret = jffs2_flash_read(c, ref_offset(raw), rawlen, &retlen, (char *)rd); -+ if (ret) { -+ printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Read error (%d) reading obsolete node at %08x\n", ret, ref_offset(raw)); -+ /* If we can't read it, we don't need to continue to obsolete it. Continue */ -+ continue; -+ } -+ if (retlen != rawlen) { -+ printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n", -+ retlen, rawlen, ref_offset(raw)); -+ continue; -+ } -+ -+ if (je16_to_cpu(rd->nodetype) != JFFS2_NODETYPE_DIRENT) -+ continue; -+ -+ /* If the name CRC doesn't match, skip */ -+ if (je32_to_cpu(rd->name_crc) != name_crc) -+ continue; -+ -+ /* If the name length doesn't match, or it's another deletion dirent, skip */ -+ if (rd->nsize != name_len || !je32_to_cpu(rd->ino)) -+ continue; -+ -+ /* OK, check the actual name now */ -+ if (memcmp(rd->name, fd->name, name_len)) -+ continue; -+ -+ /* OK. The name really does match. There really is still an older node on -+ the flash which our deletion dirent obsoletes. So we have to write out -+ a new deletion dirent to replace it */ -+ up(&c->erase_free_sem); -+ -+ D1(printk(KERN_DEBUG "Deletion dirent at %08x still obsoletes real dirent \"%s\" at %08x for ino #%u\n", -+ ref_offset(fd->raw), fd->name, ref_offset(raw), je32_to_cpu(rd->ino))); -+ kfree(rd); -+ -+ return jffs2_garbage_collect_dirent(c, jeb, f, fd); -+ } -+ -+ up(&c->erase_free_sem); -+ kfree(rd); -+ } -+ -+ /* No need for it any more. Just mark it obsolete and remove it from the list */ - while (*fdp) { - if ((*fdp) == fd) { - found = 1; -@@ -431,7 +869,7 @@ - fdp = &(*fdp)->next; - } - if (!found) { -- printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%lu\n", fd->name, inode->i_ino); -+ printk(KERN_WARNING "Deletion dirent \"%s\" not found in list for ino #%u\n", fd->name, f->inocache->ino); - } - jffs2_mark_node_obsolete(c, fd->raw); - jffs2_free_full_dirent(fd); -@@ -439,93 +877,95 @@ - } - - static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dnode *fn, -- __u32 start, __u32 end) -+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, -+ uint32_t start, uint32_t end) - { -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_raw_inode ri; - struct jffs2_node_frag *frag; - struct jffs2_full_dnode *new_fn; -- __u32 alloclen, phys_ofs; -+ uint32_t alloclen, phys_ofs; - int ret; - -- D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%lu from offset 0x%x to 0x%x\n", -- inode->i_ino, start, end)); -+ D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n", -+ f->inocache->ino, start, end)); - - memset(&ri, 0, sizeof(ri)); - - if(fn->frags > 1) { - size_t readlen; -- __u32 crc; -+ uint32_t crc; - /* It's partially obsoleted by a later write. So we have to - write it out again with the _same_ version as before */ -- ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(ri), &readlen, (char *)&ri); -+ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); - if (readlen != sizeof(ri) || ret) { -- printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hold node\n", ret, readlen); -+ printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen); - goto fill; - } -- if (ri.nodetype != JFFS2_NODETYPE_INODE) { -+ if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) { - printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had node type 0x%04x instead of JFFS2_NODETYPE_INODE(0x%04x)\n", -- fn->raw->flash_offset & ~3, ri.nodetype, JFFS2_NODETYPE_INODE); -+ ref_offset(fn->raw), -+ je16_to_cpu(ri.nodetype), JFFS2_NODETYPE_INODE); - return -EIO; - } -- if (ri.totlen != sizeof(ri)) { -- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n", -- fn->raw->flash_offset & ~3, ri.totlen, sizeof(ri)); -+ if (je32_to_cpu(ri.totlen) != sizeof(ri)) { -+ printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n", -+ ref_offset(fn->raw), -+ je32_to_cpu(ri.totlen), sizeof(ri)); - return -EIO; - } - crc = crc32(0, &ri, sizeof(ri)-8); -- if (crc != ri.node_crc) { -+ if (crc != je32_to_cpu(ri.node_crc)) { - printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had CRC 0x%08x which doesn't match calculated CRC 0x%08x\n", -- fn->raw->flash_offset & ~3, ri.node_crc, crc); -+ ref_offset(fn->raw), -+ je32_to_cpu(ri.node_crc), crc); - /* FIXME: We could possibly deal with this by writing new holes for each frag */ -- printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", -- start, end, inode->i_ino); -+ printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", -+ start, end, f->inocache->ino); - goto fill; - } - if (ri.compr != JFFS2_COMPR_ZERO) { -- printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", fn->raw->flash_offset & ~3); -- printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%lu will be lost\n", -- start, end, inode->i_ino); -+ printk(KERN_WARNING "jffs2_garbage_collect_hole: Node 0x%08x wasn't a hole node!\n", ref_offset(fn->raw)); -+ printk(KERN_WARNING "Data in the range 0x%08x to 0x%08x of inode #%u will be lost\n", -+ start, end, f->inocache->ino); - goto fill; - } - } else { - fill: -- ri.magic = JFFS2_MAGIC_BITMASK; -- ri.nodetype = JFFS2_NODETYPE_INODE; -- ri.totlen = sizeof(ri); -- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); -- -- ri.ino = inode->i_ino; -- ri.version = ++f->highest_version; -- ri.offset = start; -- ri.dsize = end - start; -- ri.csize = 0; -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri)); -+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); -+ -+ ri.ino = cpu_to_je32(f->inocache->ino); -+ ri.version = cpu_to_je32(++f->highest_version); -+ ri.offset = cpu_to_je32(start); -+ ri.dsize = cpu_to_je32(end - start); -+ ri.csize = cpu_to_je32(0); - ri.compr = JFFS2_COMPR_ZERO; - } -- ri.mode = inode->i_mode; -- ri.uid = inode->i_uid; -- ri.gid = inode->i_gid; -- ri.isize = inode->i_size; -- ri.atime = inode->i_atime; -- ri.ctime = inode->i_ctime; -- ri.mtime = inode->i_mtime; -- ri.data_crc = 0; -- ri.node_crc = crc32(0, &ri, sizeof(ri)-8); -+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); -+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); -+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); -+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); -+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); -+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); -+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); -+ ri.data_crc = cpu_to_je32(0); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); - - ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); - if (ret) { -- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n", -+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", - sizeof(ri), ret); - return ret; - } -- new_fn = jffs2_write_dnode(inode, &ri, NULL, 0, phys_ofs, NULL); -+ new_fn = jffs2_write_dnode(c, f, &ri, NULL, 0, phys_ofs, ALLOC_GC); - - if (IS_ERR(new_fn)) { - printk(KERN_WARNING "Error writing new hole node: %ld\n", PTR_ERR(new_fn)); - return PTR_ERR(new_fn); - } -- if (ri.version == f->highest_version) { -+ if (je32_to_cpu(ri.version) == f->highest_version) { - jffs2_add_full_dnode_to_inode(c, f, new_fn); - if (f->metadata) { - jffs2_mark_node_obsolete(c, f->metadata->raw); -@@ -541,12 +981,17 @@ - * number as before. (Except in case of error -- see 'goto fill;' - * above.) - */ -- D1(if(fn->frags <= 1) { -+ D1(if(unlikely(fn->frags <= 1)) { - printk(KERN_WARNING "jffs2_garbage_collect_hole: Replacing fn with %d frag(s) but new ver %d != highest_version %d of ino #%d\n", -- fn->frags, ri.version, f->highest_version, ri.ino); -+ fn->frags, je32_to_cpu(ri.version), f->highest_version, -+ je32_to_cpu(ri.ino)); - }); - -- for (frag = f->fraglist; frag; frag = frag->next) { -+ /* This is a partially-overlapped hole node. Mark it REF_NORMAL not REF_PRISTINE */ -+ mark_ref_normal(new_fn->raw); -+ -+ for (frag = jffs2_lookup_node_frag(&f->fragtree, fn->ofs); -+ frag; frag = frag_next(frag)) { - if (frag->ofs > fn->size + fn->ofs) - break; - if (frag->node == fn) { -@@ -571,49 +1016,146 @@ - } - - static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -- struct inode *inode, struct jffs2_full_dnode *fn, -- __u32 start, __u32 end) -+ struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, -+ uint32_t start, uint32_t end) - { -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_full_dnode *new_fn; - struct jffs2_raw_inode ri; -- __u32 alloclen, phys_ofs, offset, orig_end; -+ uint32_t alloclen, phys_ofs, offset, orig_end, orig_start; - int ret = 0; - unsigned char *comprbuf = NULL, *writebuf; -- struct page *pg; -+ unsigned long pg; - unsigned char *pg_ptr; - -- - memset(&ri, 0, sizeof(ri)); - -- D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%lu from offset 0x%x to 0x%x\n", -- inode->i_ino, start, end)); -+ D1(printk(KERN_DEBUG "Writing replacement dnode for ino #%u from offset 0x%x to 0x%x\n", -+ f->inocache->ino, start, end)); - - orig_end = end; -+ orig_start = start; - -+ if (c->nr_free_blocks + c->nr_erasing_blocks > c->resv_blocks_gcmerge) { -+ /* Attempt to do some merging. But only expand to cover logically -+ adjacent frags if the block containing them is already considered -+ to be dirty. Otherwise we end up with GC just going round in -+ circles dirtying the nodes it already wrote out, especially -+ on NAND where we have small eraseblocks and hence a much higher -+ chance of nodes having to be split to cross boundaries. */ - -- /* If we're looking at the last node in the block we're -- garbage-collecting, we allow ourselves to merge as if the -- block was already erasing. We're likely to be GC'ing a -- partial page, and the next block we GC is likely to have -- the other half of this page right at the beginning, which -- means we'd expand it _then_, as nr_erasing_blocks would have -- increased since we checked, and in doing so would obsolete -- the partial node which we'd have written here. Meaning that -- the GC would churn and churn, and just leave dirty blocks in -- it's wake. -- */ -- if(c->nr_free_blocks + c->nr_erasing_blocks > JFFS2_RESERVED_BLOCKS_GCMERGE - (fn->raw->next_phys?0:1)) { -- /* Shitloads of space */ -- /* FIXME: Integrate this properly with GC calculations */ -- start &= ~(PAGE_CACHE_SIZE-1); -- end = min_t(__u32, start + PAGE_CACHE_SIZE, inode->i_size); -- D1(printk(KERN_DEBUG "Plenty of free space, so expanding to write from offset 0x%x to 0x%x\n", -- start, end)); -- if (end < orig_end) { -- printk(KERN_WARNING "Eep. jffs2_garbage_collect_dnode extended node to write, but it got smaller: start 0x%x, orig_end 0x%x, end 0x%x\n", start, orig_end, end); -- end = orig_end; -+ struct jffs2_node_frag *frag; -+ uint32_t min, max; -+ -+ min = start & ~(PAGE_CACHE_SIZE-1); -+ max = min + PAGE_CACHE_SIZE; -+ -+ frag = jffs2_lookup_node_frag(&f->fragtree, start); -+ -+ /* BUG_ON(!frag) but that'll happen anyway... */ -+ -+ BUG_ON(frag->ofs != start); -+ -+ /* First grow down... */ -+ while((frag = frag_prev(frag)) && frag->ofs >= min) { -+ -+ /* If the previous frag doesn't even reach the beginning, there's -+ excessive fragmentation. Just merge. */ -+ if (frag->ofs > min) { -+ D1(printk(KERN_DEBUG "Expanding down to cover partial frag (0x%x-0x%x)\n", -+ frag->ofs, frag->ofs+frag->size)); -+ start = frag->ofs; -+ continue; -+ } -+ /* OK. This frag holds the first byte of the page. */ -+ if (!frag->node || !frag->node->raw) { -+ D1(printk(KERN_DEBUG "First frag in page is hole (0x%x-0x%x). Not expanding down.\n", -+ frag->ofs, frag->ofs+frag->size)); -+ break; -+ } else { -+ -+ /* OK, it's a frag which extends to the beginning of the page. Does it live -+ in a block which is still considered clean? If so, don't obsolete it. -+ If not, cover it anyway. */ -+ -+ struct jffs2_raw_node_ref *raw = frag->node->raw; -+ struct jffs2_eraseblock *jeb; -+ -+ jeb = &c->blocks[raw->flash_offset / c->sector_size]; -+ -+ if (jeb == c->gcblock) { -+ D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in gcblock at %08x\n", -+ frag->ofs, frag->ofs+frag->size, ref_offset(raw))); -+ start = frag->ofs; -+ break; - } -+ if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { -+ D1(printk(KERN_DEBUG "Not expanding down to cover frag (0x%x-0x%x) in clean block %08x\n", -+ frag->ofs, frag->ofs+frag->size, jeb->offset)); -+ break; -+ } -+ -+ D1(printk(KERN_DEBUG "Expanding down to cover frag (0x%x-0x%x) in dirty block %08x\n", -+ frag->ofs, frag->ofs+frag->size, jeb->offset)); -+ start = frag->ofs; -+ break; -+ } -+ } -+ -+ /* ... then up */ -+ -+ /* Find last frag which is actually part of the node we're to GC. */ -+ frag = jffs2_lookup_node_frag(&f->fragtree, end-1); -+ -+ while((frag = frag_next(frag)) && frag->ofs+frag->size <= max) { -+ -+ /* If the previous frag doesn't even reach the beginning, there's lots -+ of fragmentation. Just merge. */ -+ if (frag->ofs+frag->size < max) { -+ D1(printk(KERN_DEBUG "Expanding up to cover partial frag (0x%x-0x%x)\n", -+ frag->ofs, frag->ofs+frag->size)); -+ end = frag->ofs + frag->size; -+ continue; -+ } -+ -+ if (!frag->node || !frag->node->raw) { -+ D1(printk(KERN_DEBUG "Last frag in page is hole (0x%x-0x%x). Not expanding up.\n", -+ frag->ofs, frag->ofs+frag->size)); -+ break; -+ } else { -+ -+ /* OK, it's a frag which extends to the beginning of the page. Does it live -+ in a block which is still considered clean? If so, don't obsolete it. -+ If not, cover it anyway. */ -+ -+ struct jffs2_raw_node_ref *raw = frag->node->raw; -+ struct jffs2_eraseblock *jeb; -+ -+ jeb = &c->blocks[raw->flash_offset / c->sector_size]; -+ -+ if (jeb == c->gcblock) { -+ D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in gcblock at %08x\n", -+ frag->ofs, frag->ofs+frag->size, ref_offset(raw))); -+ end = frag->ofs + frag->size; -+ break; -+ } -+ if (!ISDIRTY(jeb->dirty_size + jeb->wasted_size)) { -+ D1(printk(KERN_DEBUG "Not expanding up to cover frag (0x%x-0x%x) in clean block %08x\n", -+ frag->ofs, frag->ofs+frag->size, jeb->offset)); -+ break; -+ } -+ -+ D1(printk(KERN_DEBUG "Expanding up to cover frag (0x%x-0x%x) in dirty block %08x\n", -+ frag->ofs, frag->ofs+frag->size, jeb->offset)); -+ end = frag->ofs + frag->size; -+ break; -+ } -+ } -+ D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n", -+ orig_start, orig_end, start, end)); -+ -+ BUG_ON(end > JFFS2_F_I_SIZE(f)); -+ BUG_ON(end < orig_end); -+ BUG_ON(start > orig_start); - } - - /* First, use readpage() to read the appropriate page into the page cache */ -@@ -623,63 +1165,57 @@ - * page OK. We'll actually write it out again in commit_write, which is a little - * suboptimal, but at least we're correct. - */ -- pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); -+ pg_ptr = jffs2_gc_fetch_page(c, f, start, &pg); - -- if (IS_ERR(pg)) { -- printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg)); -- return PTR_ERR(pg); -+ if (IS_ERR(pg_ptr)) { -+ printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg_ptr)); -+ return PTR_ERR(pg_ptr); - } -- pg_ptr = (char *)kmap(pg); -- comprbuf = kmalloc(end - start, GFP_KERNEL); - - offset = start; - while(offset < orig_end) { -- __u32 datalen; -- __u32 cdatalen; -+ uint32_t datalen; -+ uint32_t cdatalen; - char comprtype = JFFS2_COMPR_NONE; - - ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen); - - if (ret) { -- printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n", -+ printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", - sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret); - break; - } -- cdatalen = min(alloclen - sizeof(ri), end - offset); -+ cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset); - datalen = end - offset; - - writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1)); - -- if (comprbuf) { -- comprtype = jffs2_compress(writebuf, comprbuf, &datalen, &cdatalen); -- } -- if (comprtype) { -- writebuf = comprbuf; -- } else { -- datalen = cdatalen; -- } -- ri.magic = JFFS2_MAGIC_BITMASK; -- ri.nodetype = JFFS2_NODETYPE_INODE; -- ri.totlen = sizeof(ri) + cdatalen; -- ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4); -- -- ri.ino = inode->i_ino; -- ri.version = ++f->highest_version; -- ri.mode = inode->i_mode; -- ri.uid = inode->i_uid; -- ri.gid = inode->i_gid; -- ri.isize = inode->i_size; -- ri.atime = inode->i_atime; -- ri.ctime = inode->i_ctime; -- ri.mtime = inode->i_mtime; -- ri.offset = offset; -- ri.csize = cdatalen; -- ri.dsize = datalen; -+ comprtype = jffs2_compress(writebuf, &comprbuf, &datalen, &cdatalen); -+ -+ ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri.totlen = cpu_to_je32(sizeof(ri) + cdatalen); -+ ri.hdr_crc = cpu_to_je32(crc32(0, &ri, sizeof(struct jffs2_unknown_node)-4)); -+ -+ ri.ino = cpu_to_je32(f->inocache->ino); -+ ri.version = cpu_to_je32(++f->highest_version); -+ ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); -+ ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); -+ ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); -+ ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); -+ ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f)); -+ ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f)); -+ ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f)); -+ ri.offset = cpu_to_je32(offset); -+ ri.csize = cpu_to_je32(cdatalen); -+ ri.dsize = cpu_to_je32(datalen); - ri.compr = comprtype; -- ri.node_crc = crc32(0, &ri, sizeof(ri)-8); -- ri.data_crc = crc32(0, writebuf, cdatalen); -+ ri.node_crc = cpu_to_je32(crc32(0, &ri, sizeof(ri)-8)); -+ ri.data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); -+ -+ new_fn = jffs2_write_dnode(c, f, &ri, comprbuf, cdatalen, phys_ofs, ALLOC_GC); - -- new_fn = jffs2_write_dnode(inode, &ri, writebuf, cdatalen, phys_ofs, NULL); -+ jffs2_free_comprbuf(comprbuf, writebuf); - - if (IS_ERR(new_fn)) { - printk(KERN_WARNING "Error writing new dnode: %ld\n", PTR_ERR(new_fn)); -@@ -694,12 +1230,8 @@ - f->metadata = NULL; - } - } -- if (comprbuf) kfree(comprbuf); - -- kunmap(pg); -- /* XXX: Does the page get freed automatically? */ -- /* AAA: Judging by the unmount getting stuck in __wait_on_page, nope. */ -- page_cache_release(pg); -+ jffs2_gc_release_page(c, pg_ptr, &pg); - return ret; - } - -diff -Nurb linux-mips-2.4.27/fs/jffs2/ioctl.c linux/fs/jffs2/ioctl.c ---- linux-mips-2.4.27/fs/jffs2/ioctl.c 2001-10-19 03:24:56.000000000 +0200 -+++ linux/fs/jffs2/ioctl.c 2004-11-19 10:25:12.108168024 +0100 -@@ -1,37 +1,13 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - -@@ -42,6 +18,6 @@ - { - /* Later, this will provide for lsattr.jffs2 and chattr.jffs2, which - will include compression support etc. */ -- return -EINVAL; -+ return -ENOTTY; - } - -diff -Nurb linux-mips-2.4.27/fs/jffs2/malloc.c linux/fs/jffs2/malloc.c ---- linux-mips-2.4.27/fs/jffs2/malloc.c 2001-10-19 03:24:56.000000000 +0200 -+++ linux/fs/jffs2/malloc.c 2004-11-19 10:25:12.110167720 +0100 -@@ -1,37 +1,13 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - -@@ -47,6 +23,9 @@ - #define JFFS2_SLAB_POISON 0 - #endif - -+// replace this by #define D3 (x) x for cache debugging -+#define D3(x) -+ - /* These are initialised to NULL in the kernel startup code. - If you're porting to other operating systems, beware */ - static kmem_cache_t *full_dnode_slab; -@@ -57,57 +36,47 @@ - static kmem_cache_t *node_frag_slab; - static kmem_cache_t *inode_cache_slab; - --void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn) --{ -- struct jffs2_tmp_dnode_info *next; -- -- while (tn) { -- next = tn; -- tn = tn->next; -- jffs2_free_full_dnode(next->fn); -- jffs2_free_tmp_dnode_info(next); -- } --} -- --void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) --{ -- struct jffs2_full_dirent *next; -- -- while (fd) { -- next = fd->next; -- jffs2_free_full_dirent(fd); -- fd = next; -- } --} -- - int __init jffs2_create_slab_caches(void) - { -- full_dnode_slab = kmem_cache_create("jffs2_full_dnode", sizeof(struct jffs2_full_dnode), 0, JFFS2_SLAB_POISON, NULL, NULL); -+ full_dnode_slab = kmem_cache_create("jffs2_full_dnode", -+ sizeof(struct jffs2_full_dnode), -+ 0, JFFS2_SLAB_POISON, NULL, NULL); - if (!full_dnode_slab) - goto err; - -- raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", sizeof(struct jffs2_raw_dirent), 0, JFFS2_SLAB_POISON, NULL, NULL); -+ raw_dirent_slab = kmem_cache_create("jffs2_raw_dirent", -+ sizeof(struct jffs2_raw_dirent), -+ 0, JFFS2_SLAB_POISON, NULL, NULL); - if (!raw_dirent_slab) - goto err; - -- raw_inode_slab = kmem_cache_create("jffs2_raw_inode", sizeof(struct jffs2_raw_inode), 0, JFFS2_SLAB_POISON, NULL, NULL); -+ raw_inode_slab = kmem_cache_create("jffs2_raw_inode", -+ sizeof(struct jffs2_raw_inode), -+ 0, JFFS2_SLAB_POISON, NULL, NULL); - if (!raw_inode_slab) - goto err; - -- tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", sizeof(struct jffs2_tmp_dnode_info), 0, JFFS2_SLAB_POISON, NULL, NULL); -+ tmp_dnode_info_slab = kmem_cache_create("jffs2_tmp_dnode", -+ sizeof(struct jffs2_tmp_dnode_info), -+ 0, JFFS2_SLAB_POISON, NULL, NULL); - if (!tmp_dnode_info_slab) - goto err; - -- raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", sizeof(struct jffs2_raw_node_ref), 0, JFFS2_SLAB_POISON, NULL, NULL); -+ raw_node_ref_slab = kmem_cache_create("jffs2_raw_node_ref", -+ sizeof(struct jffs2_raw_node_ref), -+ 0, JFFS2_SLAB_POISON, NULL, NULL); - if (!raw_node_ref_slab) - goto err; - -- node_frag_slab = kmem_cache_create("jffs2_node_frag", sizeof(struct jffs2_node_frag), 0, JFFS2_SLAB_POISON, NULL, NULL); -+ node_frag_slab = kmem_cache_create("jffs2_node_frag", -+ sizeof(struct jffs2_node_frag), -+ 0, JFFS2_SLAB_POISON, NULL, NULL); - if (!node_frag_slab) - goto err; - -- inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), 0, JFFS2_SLAB_POISON, NULL, NULL); -- -+ inode_cache_slab = kmem_cache_create("jffs2_inode_cache", -+ sizeof(struct jffs2_inode_cache), -+ 0, JFFS2_SLAB_POISON, NULL, NULL); - if (inode_cache_slab) - return 0; - err: -@@ -131,7 +100,6 @@ - kmem_cache_destroy(node_frag_slab); - if(inode_cache_slab) - kmem_cache_destroy(inode_cache_slab); -- - } - - struct jffs2_full_dirent *jffs2_alloc_full_dirent(int namesize) -@@ -146,75 +114,92 @@ - - struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) - { -- void *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); -+ struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); -+ D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret)); - return ret; - } - - void jffs2_free_full_dnode(struct jffs2_full_dnode *x) - { -+ D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x)); - kmem_cache_free(full_dnode_slab, x); - } - - struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) - { -- return kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); -+ struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); -+ D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret)); -+ return ret; - } - - void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) - { -+ D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x)); - kmem_cache_free(raw_dirent_slab, x); - } - - struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) - { -- return kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); -+ struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); -+ D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret)); -+ return ret; - } - - void jffs2_free_raw_inode(struct jffs2_raw_inode *x) - { -+ D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x)); - kmem_cache_free(raw_inode_slab, x); - } - - struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) - { -- return kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); -+ struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); -+ D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret)); -+ return ret; - } - - void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) - { -+ D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x)); - kmem_cache_free(tmp_dnode_info_slab, x); - } - - struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) - { -- return kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); -+ struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); -+ D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret)); -+ return ret; - } - - void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) - { -+ D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x)); - kmem_cache_free(raw_node_ref_slab, x); - } - - struct jffs2_node_frag *jffs2_alloc_node_frag(void) - { -- return kmem_cache_alloc(node_frag_slab, GFP_KERNEL); -+ struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); -+ D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret)); -+ return ret; - } - - void jffs2_free_node_frag(struct jffs2_node_frag *x) - { -+ D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x)); - kmem_cache_free(node_frag_slab, x); - } - - struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) - { - struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); -- D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); -+ D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); - return ret; - } - - void jffs2_free_inode_cache(struct jffs2_inode_cache *x) - { -- D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x)); -+ D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x)); - kmem_cache_free(inode_cache_slab, x); - } - -diff -Nurb linux-mips-2.4.27/fs/jffs2/nodelist.c linux/fs/jffs2/nodelist.c ---- linux-mips-2.4.27/fs/jffs2/nodelist.c 2003-07-05 05:23:44.000000000 +0200 -+++ linux/fs/jffs2/nodelist.c 2004-11-19 10:25:12.112167416 +0100 -@@ -1,44 +1,24 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001, 2002 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/kernel.h> --#include <linux/jffs2.h> -+#include <linux/sched.h> - #include <linux/fs.h> - #include <linux/mtd/mtd.h> -+#include <linux/rbtree.h> -+#include <linux/crc32.h> -+#include <linux/slab.h> -+#include <linux/pagemap.h> - #include "nodelist.h" - - void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) -@@ -78,7 +58,7 @@ - /* Put a new tmp_dnode_info into the list, keeping the list in - order of increasing version - */ --void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list) -+static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list) - { - struct jffs2_tmp_dnode_info **prev = list; - -@@ -89,13 +69,37 @@ - *prev = tn; - } - -+static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn) -+{ -+ struct jffs2_tmp_dnode_info *next; -+ -+ while (tn) { -+ next = tn; -+ tn = tn->next; -+ jffs2_free_full_dnode(next->fn); -+ jffs2_free_tmp_dnode_info(next); -+ } -+} -+ -+static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd) -+{ -+ struct jffs2_full_dirent *next; -+ -+ while (fd) { -+ next = fd->next; -+ jffs2_free_full_dirent(fd); -+ fd = next; -+ } -+} -+ -+ - /* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated - with this ino, returning the former in order of version */ - - int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f, - struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, -- __u32 *highest_version, __u32 *latest_mctime, -- __u32 *mctime_ver) -+ uint32_t *highest_version, uint32_t *latest_mctime, -+ uint32_t *mctime_ver) - { - struct jffs2_raw_node_ref *ref = f->inocache->nodes; - struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL; -@@ -109,43 +113,71 @@ - - D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino)); - if (!f->inocache->nodes) { -- printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino); -+ printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", (unsigned long)ino); - } -+ -+ spin_lock(&c->erase_completion_lock); -+ - for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) { - /* Work out whether it's a data node or a dirent node */ -- if (ref->flash_offset & 1) { -+ if (ref_obsolete(ref)) { - /* FIXME: On NAND flash we may need to read these */ -- D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref->flash_offset &~3)); -+ D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref))); - continue; - } -- err = c->mtd->read(c->mtd, (ref->flash_offset & ~3), min(ref->totlen, sizeof(node)), &retlen, (void *)&node); -+ /* We can hold a pointer to a non-obsolete node without the spinlock, -+ but _obsolete_ nodes may disappear at any time, if the block -+ they're in gets erased */ -+ spin_unlock(&c->erase_completion_lock); -+ -+ cond_resched(); -+ -+ /* FIXME: point() */ -+ err = jffs2_flash_read(c, (ref_offset(ref)), -+ min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node)), -+ &retlen, (void *)&node); - if (err) { -- printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, (ref->flash_offset) & ~3); -+ printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref)); - goto free_out; - } - - - /* Check we've managed to read at least the common node header */ -- if (retlen < min(ref->totlen, sizeof(node.u))) { -+ if (retlen < min_t(uint32_t, ref_totlen(c, NULL, ref), sizeof(node.u))) { - printk(KERN_WARNING "short read in get_inode_nodes()\n"); - err = -EIO; - goto free_out; - } - -- switch (node.u.nodetype) { -+ switch (je16_to_cpu(node.u.nodetype)) { - case JFFS2_NODETYPE_DIRENT: -- D1(printk(KERN_DEBUG "Node at %08x is a dirent node\n", ref->flash_offset &~3)); -+ D1(printk(KERN_DEBUG "Node at %08x (%d) is a dirent node\n", ref_offset(ref), ref_flags(ref))); -+ if (ref_flags(ref) == REF_UNCHECKED) { -+ printk(KERN_WARNING "BUG: Dirent node at 0x%08x never got checked? How?\n", ref_offset(ref)); -+ BUG(); -+ } - if (retlen < sizeof(node.d)) { - printk(KERN_WARNING "short read in get_inode_nodes()\n"); - err = -EIO; - goto free_out; - } -- if (node.d.version > *highest_version) -- *highest_version = node.d.version; -- if (ref->flash_offset & 1) { -- /* Obsoleted */ -+ /* sanity check */ -+ if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) { -+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n", -+ ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen)); -+ jffs2_mark_node_obsolete(c, ref); -+ spin_lock(&c->erase_completion_lock); - continue; - } -+ if (je32_to_cpu(node.d.version) > *highest_version) -+ *highest_version = je32_to_cpu(node.d.version); -+ if (ref_obsolete(ref)) { -+ /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ -+ printk(KERN_ERR "Dirent node at 0x%08x became obsolete while we weren't looking\n", -+ ref_offset(ref)); -+ BUG(); -+ } -+ - fd = jffs2_alloc_full_dirent(node.d.nsize+1); - if (!fd) { - err = -ENOMEM; -@@ -153,29 +185,30 @@ - } - memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1); - fd->raw = ref; -- fd->version = node.d.version; -- fd->ino = node.d.ino; -+ fd->version = je32_to_cpu(node.d.version); -+ fd->ino = je32_to_cpu(node.d.ino); - fd->type = node.d.type; - - /* Pick out the mctime of the latest dirent */ - if(fd->version > *mctime_ver) { - *mctime_ver = fd->version; -- *latest_mctime = node.d.mctime; -+ *latest_mctime = je32_to_cpu(node.d.mctime); - } - - /* memcpy as much of the name as possible from the raw - dirent we've already read from the flash - */ - if (retlen > sizeof(struct jffs2_raw_dirent)) -- memcpy(&fd->name[0], &node.d.name[0], min((__u32)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); -+ memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); - - /* Do we need to copy any more of the name directly - from the flash? - */ - if (node.d.nsize + sizeof(struct jffs2_raw_dirent) > retlen) { -+ /* FIXME: point() */ - int already = retlen - sizeof(struct jffs2_raw_dirent); - -- err = c->mtd->read(c->mtd, (ref->flash_offset & ~3) + retlen, -+ err = jffs2_flash_read(c, (ref_offset(ref)) + retlen, - node.d.nsize - already, &retlen, &fd->name[already]); - if (!err && retlen != node.d.nsize - already) - err = -EIO; -@@ -196,21 +229,126 @@ - break; - - case JFFS2_NODETYPE_INODE: -- D1(printk(KERN_DEBUG "Node at %08x is a data node\n", ref->flash_offset &~3)); -+ D1(printk(KERN_DEBUG "Node at %08x (%d) is a data node\n", ref_offset(ref), ref_flags(ref))); - if (retlen < sizeof(node.i)) { - printk(KERN_WARNING "read too short for dnode\n"); - err = -EIO; - goto free_out; - } -- if (node.i.version > *highest_version) -- *highest_version = node.i.version; -- D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", node.i.version, *highest_version)); -- -- if (ref->flash_offset & 1) { -- D1(printk(KERN_DEBUG "obsoleted\n")); -- /* Obsoleted */ -+ if (je32_to_cpu(node.i.version) > *highest_version) -+ *highest_version = je32_to_cpu(node.i.version); -+ D1(printk(KERN_DEBUG "version %d, highest_version now %d\n", je32_to_cpu(node.i.version), *highest_version)); -+ -+ if (ref_obsolete(ref)) { -+ /* Obsoleted. This cannot happen, surely? dwmw2 20020308 */ -+ printk(KERN_ERR "Inode node at 0x%08x became obsolete while we weren't looking\n", -+ ref_offset(ref)); -+ BUG(); -+ } -+ -+ /* If we've never checked the CRCs on this node, check them now. */ -+ if (ref_flags(ref) == REF_UNCHECKED) { -+ uint32_t crc, len; -+ struct jffs2_eraseblock *jeb; -+ -+ crc = crc32(0, &node, sizeof(node.i)-8); -+ if (crc != je32_to_cpu(node.i.node_crc)) { -+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -+ ref_offset(ref), je32_to_cpu(node.i.node_crc), crc); -+ jffs2_mark_node_obsolete(c, ref); -+ spin_lock(&c->erase_completion_lock); - continue; - } -+ -+ /* sanity checks */ -+ if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) || -+ PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) { -+ 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", -+ ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino), -+ je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize), -+ je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize)); -+ jffs2_mark_node_obsolete(c, ref); -+ spin_lock(&c->erase_completion_lock); -+ continue; -+ } -+ -+ if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) { -+ unsigned char *buf=NULL; -+ uint32_t pointed = 0; -+#ifndef __ECOS -+ if (c->mtd->point) { -+ err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), -+ &retlen, &buf); -+ if (!err && retlen < je32_to_cpu(node.i.csize)) { -+ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); -+ c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); -+ } else if (err){ -+ D1(printk(KERN_DEBUG "MTD point failed %d\n", err)); -+ } else -+ pointed = 1; /* succefully pointed to device */ -+ } -+#endif -+ if(!pointed){ -+ buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL); -+ if (!buf) -+ return -ENOMEM; -+ -+ err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), -+ &retlen, buf); -+ if (!err && retlen != je32_to_cpu(node.i.csize)) -+ err = -EIO; -+ if (err) { -+ kfree(buf); -+ return err; -+ } -+ } -+ crc = crc32(0, buf, je32_to_cpu(node.i.csize)); -+ if(!pointed) -+ kfree(buf); -+#ifndef __ECOS -+ else -+ c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); -+#endif -+ -+ if (crc != je32_to_cpu(node.i.data_crc)) { -+ printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -+ ref_offset(ref), je32_to_cpu(node.i.data_crc), crc); -+ jffs2_mark_node_obsolete(c, ref); -+ spin_lock(&c->erase_completion_lock); -+ continue; -+ } -+ -+ } -+ -+ /* Mark the node as having been checked and fix the accounting accordingly */ -+ spin_lock(&c->erase_completion_lock); -+ jeb = &c->blocks[ref->flash_offset / c->sector_size]; -+ len = ref_totlen(c, jeb, ref); -+ -+ jeb->used_size += len; -+ jeb->unchecked_size -= len; -+ c->used_size += len; -+ c->unchecked_size -= len; -+ -+ /* If node covers at least a whole page, or if it starts at the -+ beginning of a page and runs to the end of the file, or if -+ it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. -+ -+ If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) -+ when the overlapping node(s) get added to the tree anyway. -+ */ -+ if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) || -+ ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) && -+ (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) { -+ D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref))); -+ ref->flash_offset = ref_offset(ref) | REF_PRISTINE; -+ } else { -+ D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref))); -+ ref->flash_offset = ref_offset(ref) | REF_NORMAL; -+ } -+ spin_unlock(&c->erase_completion_lock); -+ } -+ - tn = jffs2_alloc_tmp_dnode_info(); - if (!tn) { - D1(printk(KERN_DEBUG "alloc tn failed\n")); -@@ -225,36 +363,76 @@ - jffs2_free_tmp_dnode_info(tn); - goto free_out; - } -- tn->version = node.i.version; -- tn->fn->ofs = node.i.offset; -+ tn->version = je32_to_cpu(node.i.version); -+ tn->fn->ofs = je32_to_cpu(node.i.offset); - /* There was a bug where we wrote hole nodes out with - csize/dsize swapped. Deal with it */ -- if (node.i.compr == JFFS2_COMPR_ZERO && !node.i.dsize && node.i.csize) -- tn->fn->size = node.i.csize; -+ if (node.i.compr == JFFS2_COMPR_ZERO && !je32_to_cpu(node.i.dsize) && je32_to_cpu(node.i.csize)) -+ tn->fn->size = je32_to_cpu(node.i.csize); - else // normal case... -- tn->fn->size = node.i.dsize; -+ tn->fn->size = je32_to_cpu(node.i.dsize); - tn->fn->raw = ref; -- D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", ref->flash_offset &~3, node.i.version, node.i.offset, node.i.dsize)); -+ D1(printk(KERN_DEBUG "dnode @%08x: ver %u, offset %04x, dsize %04x\n", -+ ref_offset(ref), je32_to_cpu(node.i.version), -+ je32_to_cpu(node.i.offset), je32_to_cpu(node.i.dsize))); - jffs2_add_tn_to_list(tn, &ret_tn); - break; - - default: -- switch(node.u.nodetype & JFFS2_COMPAT_MASK) { -+ if (ref_flags(ref) == REF_UNCHECKED) { -+ struct jffs2_eraseblock *jeb; -+ uint32_t len; -+ -+ printk(KERN_ERR "Eep. Unknown node type %04x at %08x was marked REF_UNCHECKED\n", -+ je16_to_cpu(node.u.nodetype), ref_offset(ref)); -+ -+ /* Mark the node as having been checked and fix the accounting accordingly */ -+ spin_lock(&c->erase_completion_lock); -+ jeb = &c->blocks[ref->flash_offset / c->sector_size]; -+ len = ref_totlen(c, jeb, ref); -+ -+ jeb->used_size += len; -+ jeb->unchecked_size -= len; -+ c->used_size += len; -+ c->unchecked_size -= len; -+ -+ mark_ref_normal(ref); -+ spin_unlock(&c->erase_completion_lock); -+ } -+ node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype)); -+ if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) { -+ /* Hmmm. This should have been caught at scan time. */ -+ printk(KERN_ERR "Node header CRC failed at %08x. But it must have been OK earlier.\n", -+ ref_offset(ref)); -+ printk(KERN_ERR "Node was: { %04x, %04x, %08x, %08x }\n", -+ je16_to_cpu(node.u.magic), je16_to_cpu(node.u.nodetype), je32_to_cpu(node.u.totlen), -+ je32_to_cpu(node.u.hdr_crc)); -+ jffs2_mark_node_obsolete(c, ref); -+ } else switch(je16_to_cpu(node.u.nodetype) & JFFS2_COMPAT_MASK) { - case JFFS2_FEATURE_INCOMPAT: -- printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); -+ printk(KERN_NOTICE "Unknown INCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); -+ /* EEP */ -+ BUG(); - break; - case JFFS2_FEATURE_ROCOMPAT: -- printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); -+ printk(KERN_NOTICE "Unknown ROCOMPAT nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); -+ if (!(c->flags & JFFS2_SB_FLAG_RO)) -+ BUG(); - break; - case JFFS2_FEATURE_RWCOMPAT_COPY: -- printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); -+ printk(KERN_NOTICE "Unknown RWCOMPAT_COPY nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); - break; - case JFFS2_FEATURE_RWCOMPAT_DELETE: -- printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08X\n", node.u.nodetype, ref->flash_offset & ~3); -+ printk(KERN_NOTICE "Unknown RWCOMPAT_DELETE nodetype %04X at %08x\n", je16_to_cpu(node.u.nodetype), ref_offset(ref)); -+ jffs2_mark_node_obsolete(c, ref); - break; - } -+ - } -+ spin_lock(&c->erase_completion_lock); -+ - } -+ spin_unlock(&c->erase_completion_lock); - *tnp = ret_tn; - *fdp = ret_fd; - -@@ -266,19 +444,30 @@ - return err; - } - -+void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) -+{ -+ spin_lock(&c->inocache_lock); -+ ic->state = state; -+ wake_up(&c->inocache_wq); -+ spin_unlock(&c->inocache_lock); -+} -+ -+/* During mount, this needs no locking. During normal operation, its -+ callers want to do other stuff while still holding the inocache_lock. -+ Rather than introducing special case get_ino_cache functions or -+ callbacks, we just let the caller do the locking itself. */ -+ - struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) - { - struct jffs2_inode_cache *ret; - - D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino)); -- spin_lock (&c->inocache_lock); -+ - ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; - while (ret && ret->ino < ino) { - ret = ret->next; - } - -- spin_unlock(&c->inocache_lock); -- - if (ret && ret->ino != ino) - ret = NULL; - -@@ -299,6 +488,7 @@ - } - new->next = *prev; - *prev = new; -+ - spin_unlock(&c->inocache_lock); - } - -@@ -316,6 +506,7 @@ - if ((*prev) == old) { - *prev = old->next; - } -+ - spin_unlock(&c->inocache_lock); - } - -@@ -352,3 +543,128 @@ - } - } - -+struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset) -+{ -+ /* The common case in lookup is that there will be a node -+ which precisely matches. So we go looking for that first */ -+ struct rb_node *next; -+ struct jffs2_node_frag *prev = NULL; -+ struct jffs2_node_frag *frag = NULL; -+ -+ D2(printk(KERN_DEBUG "jffs2_lookup_node_frag(%p, %d)\n", fragtree, offset)); -+ -+ next = fragtree->rb_node; -+ -+ while(next) { -+ frag = rb_entry(next, struct jffs2_node_frag, rb); -+ -+ D2(printk(KERN_DEBUG "Considering frag %d-%d (%p). left %p, right %p\n", -+ frag->ofs, frag->ofs+frag->size, frag, frag->rb.rb_left, frag->rb.rb_right)); -+ if (frag->ofs + frag->size <= offset) { -+ D2(printk(KERN_DEBUG "Going right from frag %d-%d, before the region we care about\n", -+ frag->ofs, frag->ofs+frag->size)); -+ /* Remember the closest smaller match on the way down */ -+ if (!prev || frag->ofs > prev->ofs) -+ prev = frag; -+ next = frag->rb.rb_right; -+ } else if (frag->ofs > offset) { -+ D2(printk(KERN_DEBUG "Going left from frag %d-%d, after the region we care about\n", -+ frag->ofs, frag->ofs+frag->size)); -+ next = frag->rb.rb_left; -+ } else { -+ D2(printk(KERN_DEBUG "Returning frag %d,%d, matched\n", -+ frag->ofs, frag->ofs+frag->size)); -+ return frag; -+ } -+ } -+ -+ /* Exact match not found. Go back up looking at each parent, -+ and return the closest smaller one */ -+ -+ if (prev) -+ D2(printk(KERN_DEBUG "No match. Returning frag %d,%d, closest previous\n", -+ prev->ofs, prev->ofs+prev->size)); -+ else -+ D2(printk(KERN_DEBUG "Returning NULL, empty fragtree\n")); -+ -+ return prev; -+} -+ -+/* Pass 'c' argument to indicate that nodes should be marked obsolete as -+ they're killed. */ -+void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c) -+{ -+ struct jffs2_node_frag *frag; -+ struct jffs2_node_frag *parent; -+ -+ if (!root->rb_node) -+ return; -+ -+ frag = (rb_entry(root->rb_node, struct jffs2_node_frag, rb)); -+ -+ while(frag) { -+ if (frag->rb.rb_left) { -+ D2(printk(KERN_DEBUG "Going left from frag (%p) %d-%d\n", -+ frag, frag->ofs, frag->ofs+frag->size)); -+ frag = frag_left(frag); -+ continue; -+ } -+ if (frag->rb.rb_right) { -+ D2(printk(KERN_DEBUG "Going right from frag (%p) %d-%d\n", -+ frag, frag->ofs, frag->ofs+frag->size)); -+ frag = frag_right(frag); -+ continue; -+ } -+ -+ D2(printk(KERN_DEBUG "jffs2_kill_fragtree: frag at 0x%x-0x%x: node %p, frags %d--\n", -+ frag->ofs, frag->ofs+frag->size, frag->node, -+ frag->node?frag->node->frags:0)); -+ -+ if (frag->node && !(--frag->node->frags)) { -+ /* Not a hole, and it's the final remaining frag -+ of this node. Free the node */ -+ if (c) -+ jffs2_mark_node_obsolete(c, frag->node->raw); -+ -+ jffs2_free_full_dnode(frag->node); -+ } -+ parent = frag_parent(frag); -+ if (parent) { -+ if (frag_left(parent) == frag) -+ parent->rb.rb_left = NULL; -+ else -+ parent->rb.rb_right = NULL; -+ } -+ -+ jffs2_free_node_frag(frag); -+ frag = parent; -+ -+ cond_resched(); -+ } -+} -+ -+void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base) -+{ -+ struct rb_node *parent = &base->rb; -+ struct rb_node **link = &parent; -+ -+ D2(printk(KERN_DEBUG "jffs2_fragtree_insert(%p; %d-%d, %p)\n", newfrag, -+ newfrag->ofs, newfrag->ofs+newfrag->size, base)); -+ -+ while (*link) { -+ parent = *link; -+ base = rb_entry(parent, struct jffs2_node_frag, rb); -+ -+ D2(printk(KERN_DEBUG "fragtree_insert considering frag at 0x%x\n", base->ofs)); -+ if (newfrag->ofs > base->ofs) -+ link = &base->rb.rb_right; -+ else if (newfrag->ofs < base->ofs) -+ link = &base->rb.rb_left; -+ else { -+ printk(KERN_CRIT "Duplicate frag at %08x (%p,%p)\n", newfrag->ofs, newfrag, base); -+ BUG(); -+ } -+ } -+ -+ rb_link_node(&newfrag->rb, &base->rb, link); -+} -diff -Nurb linux-mips-2.4.27/fs/jffs2/nodelist.h linux/fs/jffs2/nodelist.h ---- linux-mips-2.4.27/fs/jffs2/nodelist.h 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/nodelist.h 2004-11-19 10:25:12.113167264 +0100 -@@ -1,48 +1,35 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - -+#ifndef __JFFS2_NODELIST_H__ -+#define __JFFS2_NODELIST_H__ -+ - #include <linux/config.h> - #include <linux/fs.h> -- -+#include <linux/types.h> -+#include <linux/jffs2.h> - #include <linux/jffs2_fs_sb.h> - #include <linux/jffs2_fs_i.h> - -+#ifdef __ECOS -+#include "os-ecos.h" -+#else -+#include <linux/mtd/compatmac.h> /* For min/max in older kernels */ -+#include "os-linux.h" -+#endif -+ - #ifndef CONFIG_JFFS2_FS_DEBUG --#define CONFIG_JFFS2_FS_DEBUG 2 -+#define CONFIG_JFFS2_FS_DEBUG 1 - #endif - - #if CONFIG_JFFS2_FS_DEBUG > 0 -@@ -71,17 +58,21 @@ - for this inode instead. The inode_cache will have NULL in the first - word so you know when you've got there :) */ - struct jffs2_raw_node_ref *next_phys; -- // __u32 ino; -- __u32 flash_offset; -- __u32 totlen; --// __u16 nodetype; -+ uint32_t flash_offset; -+ uint32_t __totlen; /* This may die; use ref_totlen(c, jeb, ) below */ -+}; - - /* flash_offset & 3 always has to be zero, because nodes are - always aligned at 4 bytes. So we have a couple of extra bits -- to play with. So we set the least significant bit to 1 to -- signify that the node is obsoleted by later nodes. -- */ --}; -+ to play with, which indicate the node's status; see below: */ -+#define REF_UNCHECKED 0 /* We haven't yet checked the CRC or built its inode */ -+#define REF_OBSOLETE 1 /* Obsolete, can be completely ignored */ -+#define REF_PRISTINE 2 /* Completely clean. GC without looking */ -+#define REF_NORMAL 3 /* Possibly overlapped. Read the page and write again on GC */ -+#define ref_flags(ref) ((ref)->flash_offset & 3) -+#define ref_offset(ref) ((ref)->flash_offset & ~3) -+#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE) -+#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0) - - /* - Used for keeping track of deletion nodes &c, which can only be marked -@@ -101,19 +92,35 @@ - a pointer to the first physical node which is part of this inode, too. - */ - struct jffs2_inode_cache { -- struct jffs2_scan_info *scan; /* Used during scan to hold -- temporary lists of nodes, and later must be set to -+ struct jffs2_full_dirent *scan_dents; /* Used during scan to hold -+ temporary lists of dirents, and later must be set to - NULL to mark the end of the raw_node_ref->next_in_ino - chain. */ - struct jffs2_inode_cache *next; - struct jffs2_raw_node_ref *nodes; -- __u32 ino; -+ uint32_t ino; - int nlink; -+ int state; - }; - -+/* Inode states for 'state' above. We need the 'GC' state to prevent -+ someone from doing a read_inode() while we're moving a 'REF_PRISTINE' -+ node without going through all the iget() nonsense */ -+#define INO_STATE_UNCHECKED 0 /* CRC checks not yet done */ -+#define INO_STATE_CHECKING 1 /* CRC checks in progress */ -+#define INO_STATE_PRESENT 2 /* In core */ -+#define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */ -+#define INO_STATE_GC 4 /* GCing a 'pristine' node */ -+#define INO_STATE_READING 5 /* In read_inode() */ -+ -+#define INOCACHE_HASHSIZE 128 -+ - struct jffs2_scan_info { - struct jffs2_full_dirent *dents; - struct jffs2_tmp_dnode_info *tmpnodes; -+ /* Latest i_size info */ -+ uint32_t version; -+ uint32_t isize; - }; - /* - Larger representation of a raw node, kept in-core only when the -@@ -123,9 +130,9 @@ - struct jffs2_full_dnode - { - struct jffs2_raw_node_ref *raw; -- __u32 ofs; /* Don't really need this, but optimisation */ -- __u32 size; -- __u32 frags; /* Number of fragments which currently refer -+ uint32_t ofs; /* Don't really need this, but optimisation */ -+ uint32_t size; -+ uint32_t frags; /* Number of fragments which currently refer - to this node. When this reaches zero, - the node is obsolete. - */ -@@ -140,15 +147,15 @@ - { - struct jffs2_tmp_dnode_info *next; - struct jffs2_full_dnode *fn; -- __u32 version; -+ uint32_t version; - }; - - struct jffs2_full_dirent - { - struct jffs2_raw_node_ref *raw; - struct jffs2_full_dirent *next; -- __u32 version; -- __u32 ino; /* == zero for unlink */ -+ uint32_t version; -+ uint32_t ino; /* == zero for unlink */ - unsigned int nhash; - unsigned char type; - unsigned char name[0]; -@@ -159,21 +166,23 @@ - */ - struct jffs2_node_frag - { -- struct jffs2_node_frag *next; -+ struct rb_node rb; - struct jffs2_full_dnode *node; /* NULL for holes */ -- __u32 size; -- __u32 ofs; /* Don't really need this, but optimisation */ -+ uint32_t size; -+ uint32_t ofs; /* Don't really need this, but optimisation */ - }; - - struct jffs2_eraseblock - { - struct list_head list; - int bad_count; -- __u32 offset; /* of this block in the MTD */ -+ uint32_t offset; /* of this block in the MTD */ - -- __u32 used_size; -- __u32 dirty_size; -- __u32 free_size; /* Note that sector_size - free_size -+ uint32_t unchecked_size; -+ uint32_t used_size; -+ uint32_t dirty_size; -+ uint32_t wasted_size; -+ uint32_t free_size; /* Note that sector_size - free_size - is the address of the first free space */ - struct jffs2_raw_node_ref *first_node; - struct jffs2_raw_node_ref *last_node; -@@ -190,45 +199,134 @@ - }; - - #define ACCT_SANITY_CHECK(c, jeb) do { \ -- if (jeb->used_size + jeb->dirty_size + jeb->free_size != c->sector_size) { \ -- printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", jeb->offset); \ -- printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x != total %08x\n", \ -- jeb->free_size, jeb->dirty_size, jeb->used_size, c->sector_size); \ -+ struct jffs2_eraseblock *___j = jeb; \ -+ if ((___j) && ___j->used_size + ___j->dirty_size + ___j->free_size + ___j->wasted_size + ___j->unchecked_size != c->sector_size) { \ -+ printk(KERN_NOTICE "Eeep. Space accounting for block at 0x%08x is screwed\n", ___j->offset); \ -+ printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + wasted %08x + unchecked %08x != total %08x\n", \ -+ ___j->free_size, ___j->dirty_size, ___j->used_size, ___j->wasted_size, ___j->unchecked_size, c->sector_size); \ - BUG(); \ - } \ -- if (c->used_size + c->dirty_size + c->free_size + c->erasing_size + c->bad_size != c->flash_size) { \ -+ 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) { \ - printk(KERN_NOTICE "Eeep. Space accounting superblock info is screwed\n"); \ -- printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x != total %08x\n", \ -- c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->flash_size); \ -+ printk(KERN_NOTICE "free 0x%08x + dirty 0x%08x + used %08x + erasing %08x + bad %08x + wasted %08x + unchecked %08x != total %08x\n", \ -+ c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, c->wasted_size, c->unchecked_size, c->flash_size); \ - BUG(); \ - } \ - } while(0) - -+static inline void paranoia_failed_dump(struct jffs2_eraseblock *jeb) -+{ -+ struct jffs2_raw_node_ref *ref; -+ int i=0; -+ -+ printk(KERN_NOTICE); -+ for (ref = jeb->first_node; ref; ref = ref->next_phys) { -+ printk("%08x->", ref_offset(ref)); -+ if (++i == 8) { -+ i = 0; -+ printk("\n" KERN_NOTICE); -+ } -+ } -+ printk("\n"); -+} -+ -+ - #define ACCT_PARANOIA_CHECK(jeb) do { \ -- __u32 my_used_size = 0; \ -+ uint32_t my_used_size = 0; \ -+ uint32_t my_unchecked_size = 0; \ - struct jffs2_raw_node_ref *ref2 = jeb->first_node; \ - while (ref2) { \ -- if (!(ref2->flash_offset & 1)) \ -- my_used_size += ref2->totlen; \ -+ if (unlikely(ref2->flash_offset < jeb->offset || \ -+ ref2->flash_offset > jeb->offset + c->sector_size)) { \ -+ printk(KERN_NOTICE "Node %08x shouldn't be in block at %08x!\n", \ -+ ref_offset(ref2), jeb->offset); \ -+ paranoia_failed_dump(jeb); \ -+ BUG(); \ -+ } \ -+ if (ref_flags(ref2) == REF_UNCHECKED) \ -+ my_unchecked_size += ref_totlen(c, jeb, ref2); \ -+ else if (!ref_obsolete(ref2)) \ -+ my_used_size += ref_totlen(c, jeb, ref2); \ -+ if (unlikely((!ref2->next_phys) != (ref2 == jeb->last_node))) { \ -+ printk("ref for node at %p (phys %08x) has next_phys->%p (%08x), last_node->%p (phys %08x)\n", \ -+ ref2, ref_offset(ref2), ref2->next_phys, ref_offset(ref2->next_phys), \ -+ jeb->last_node, ref_offset(jeb->last_node)); \ -+ paranoia_failed_dump(jeb); \ -+ BUG(); \ -+ } \ - ref2 = ref2->next_phys; \ - } \ - if (my_used_size != jeb->used_size) { \ - printk(KERN_NOTICE "Calculated used size %08x != stored used size %08x\n", my_used_size, jeb->used_size); \ - BUG(); \ - } \ -+ if (my_unchecked_size != jeb->unchecked_size) { \ -+ printk(KERN_NOTICE "Calculated unchecked size %08x != stored unchecked size %08x\n", my_unchecked_size, jeb->unchecked_size); \ -+ BUG(); \ -+ } \ - } while(0) - -+/* Calculate totlen from surrounding nodes or eraseblock */ -+static inline uint32_t __ref_totlen(struct jffs2_sb_info *c, -+ struct jffs2_eraseblock *jeb, -+ struct jffs2_raw_node_ref *ref) -+{ -+ uint32_t ref_end; -+ -+ if (ref->next_phys) -+ ref_end = ref_offset(ref->next_phys); -+ else { -+ if (!jeb) -+ jeb = &c->blocks[ref->flash_offset / c->sector_size]; -+ -+ /* Last node in block. Use free_space */ -+ BUG_ON(ref != jeb->last_node); -+ ref_end = jeb->offset + c->sector_size - jeb->free_size; -+ } -+ return ref_end - ref_offset(ref); -+} -+ -+static inline uint32_t ref_totlen(struct jffs2_sb_info *c, -+ struct jffs2_eraseblock *jeb, -+ struct jffs2_raw_node_ref *ref) -+{ -+ uint32_t ret; -+ -+ D1(if (jeb && jeb != &c->blocks[ref->flash_offset / c->sector_size]) { -+ printk(KERN_CRIT "ref_totlen called with wrong block -- at 0x%08x instead of 0x%08x; ref 0x%08x\n", -+ jeb->offset, c->blocks[ref->flash_offset / c->sector_size].offset, ref_offset(ref)); -+ BUG(); -+ }) -+ -+#if 1 -+ ret = ref->__totlen; -+#else -+ /* This doesn't actually work yet */ -+ ret = __ref_totlen(c, jeb, ref); -+ if (ret != ref->__totlen) { -+ printk(KERN_CRIT "Totlen for ref at %p (0x%08x-0x%08x) miscalculated as 0x%x instead of %x\n", -+ ref, ref_offset(ref), ref_offset(ref)+ref->__totlen, -+ ret, ref->__totlen); -+ if (!jeb) -+ jeb = &c->blocks[ref->flash_offset / c->sector_size]; -+ paranoia_failed_dump(jeb); -+ BUG(); -+ } -+#endif -+ return ret; -+} -+ -+ - #define ALLOC_NORMAL 0 /* Normal allocation */ - #define ALLOC_DELETION 1 /* Deletion node. Best to allow it */ - #define ALLOC_GC 2 /* Space requested for GC. Give it or die */ -+#define ALLOC_NORETRY 3 /* For jffs2_write_dnode: On failure, return -EAGAIN instead of retrying */ - --#define JFFS2_RESERVED_BLOCKS_BASE 3 /* Number of free blocks there must be before we... */ --#define JFFS2_RESERVED_BLOCKS_WRITE (JFFS2_RESERVED_BLOCKS_BASE + 2) /* ... allow a normal filesystem write */ --#define JFFS2_RESERVED_BLOCKS_DELETION (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... allow a normal filesystem deletion */ --#define JFFS2_RESERVED_BLOCKS_GCTRIGGER (JFFS2_RESERVED_BLOCKS_BASE + 3) /* ... wake up the GC thread */ --#define JFFS2_RESERVED_BLOCKS_GCBAD (JFFS2_RESERVED_BLOCKS_BASE + 1) /* ... pick a block from the bad_list to GC */ --#define JFFS2_RESERVED_BLOCKS_GCMERGE (JFFS2_RESERVED_BLOCKS_BASE) /* ... merge pages when garbage collecting */ -+/* How much dirty space before it goes on the very_dirty_list */ -+#define VERYDIRTY(c, size) ((size) >= ((c)->sector_size / 2)) - -+/* check if dirty space is more than 255 Byte */ -+#define ISDIRTY(size) ((size) > sizeof (struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN) - - #define PAD(x) (((x)+3)&~3) - -@@ -241,43 +339,75 @@ - return ((struct jffs2_inode_cache *)raw); - } - -+static inline struct jffs2_node_frag *frag_first(struct rb_root *root) -+{ -+ struct rb_node *node = root->rb_node; -+ -+ if (!node) -+ return NULL; -+ while(node->rb_left) -+ node = node->rb_left; -+ return rb_entry(node, struct jffs2_node_frag, rb); -+} -+#define rb_parent(rb) ((rb)->rb_parent) -+#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb) -+#define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb) -+#define frag_parent(frag) rb_entry(rb_parent(&(frag)->rb), struct jffs2_node_frag, rb) -+#define frag_left(frag) rb_entry((frag)->rb.rb_left, struct jffs2_node_frag, rb) -+#define frag_right(frag) rb_entry((frag)->rb.rb_right, struct jffs2_node_frag, rb) -+#define frag_erase(frag, list) rb_erase(&frag->rb, list); -+ - /* nodelist.c */ - D1(void jffs2_print_frag_list(struct jffs2_inode_info *f)); - void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list); --void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list); - int jffs2_get_inode_nodes(struct jffs2_sb_info *c, ino_t ino, struct jffs2_inode_info *f, - struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, -- __u32 *highest_version, __u32 *latest_mctime, -- __u32 *mctime_ver); -+ uint32_t *highest_version, uint32_t *latest_mctime, -+ uint32_t *mctime_ver); -+void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); - struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino); - void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new); - void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old); - void jffs2_free_ino_caches(struct jffs2_sb_info *c); - void jffs2_free_raw_node_refs(struct jffs2_sb_info *c); -+struct jffs2_node_frag *jffs2_lookup_node_frag(struct rb_root *fragtree, uint32_t offset); -+void jffs2_kill_fragtree(struct rb_root *root, struct jffs2_sb_info *c_delete); -+void jffs2_fragtree_insert(struct jffs2_node_frag *newfrag, struct jffs2_node_frag *base); -+struct rb_node *rb_next(struct rb_node *); -+struct rb_node *rb_prev(struct rb_node *); -+void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root); - - /* nodemgmt.c */ --int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio); --int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len); --int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty); -+int jffs2_thread_should_wake(struct jffs2_sb_info *c); -+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio); -+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); -+int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new); - void jffs2_complete_reservation(struct jffs2_sb_info *c); - void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *raw); -+void jffs2_dump_block_lists(struct jffs2_sb_info *c); - - /* write.c */ --struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri); --struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs, __u32 *writelen); --struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs, __u32 *writelen); -+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri); -+ -+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); -+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); -+int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, -+ struct jffs2_raw_inode *ri, unsigned char *buf, -+ uint32_t offset, uint32_t writelen, uint32_t *retlen); -+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); -+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); -+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); -+ - - /* readinode.c */ --void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size); --int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn); -+void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); - int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); --void jffs2_read_inode (struct inode *); --void jffs2_clear_inode (struct inode *); -+int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, -+ uint32_t ino, struct jffs2_raw_inode *latest_node); -+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); -+void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); - - /* malloc.c */ --void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn); --void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd); -- - int jffs2_create_slab_caches(void); - void jffs2_destroy_slab_caches(void); - -@@ -301,54 +431,41 @@ - /* gc.c */ - int jffs2_garbage_collect_pass(struct jffs2_sb_info *c); - --/* background.c */ --int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); --void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); --void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c); -- --/* dir.c */ --extern struct file_operations jffs2_dir_operations; --extern struct inode_operations jffs2_dir_inode_operations; -- --/* file.c */ --extern struct file_operations jffs2_file_operations; --extern struct inode_operations jffs2_file_inode_operations; --extern struct address_space_operations jffs2_file_address_operations; --int jffs2_null_fsync(struct file *, struct dentry *, int); --int jffs2_setattr (struct dentry *dentry, struct iattr *iattr); --int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg); --int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); --int jffs2_readpage (struct file *, struct page *); --int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned); --int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned); -- --/* ioctl.c */ --int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -- - /* read.c */ - int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len); -+int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, -+ unsigned char *buf, uint32_t offset, uint32_t len); -+char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f); - - /* compr.c */ --unsigned char jffs2_compress(unsigned char *data_in, unsigned char *cpage_out, -- __u32 *datalen, __u32 *cdatalen); -+unsigned char jffs2_compress(unsigned char *data_in, unsigned char **cpage_out, -+ uint32_t *datalen, uint32_t *cdatalen); -+void jffs2_free_comprbuf(unsigned char *comprbuf, unsigned char *orig); - int jffs2_decompress(unsigned char comprtype, unsigned char *cdata_in, -- unsigned char *data_out, __u32 cdatalen, __u32 datalen); -+ unsigned char *data_out, uint32_t cdatalen, uint32_t datalen); - - /* scan.c */ - int jffs2_scan_medium(struct jffs2_sb_info *c); -+void jffs2_rotate_lists(struct jffs2_sb_info *c); - - /* build.c */ --int jffs2_build_filesystem(struct jffs2_sb_info *c); -- --/* symlink.c */ --extern struct inode_operations jffs2_symlink_inode_operations; -+int jffs2_do_mount_fs(struct jffs2_sb_info *c); - - /* erase.c */ - void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); --void jffs2_erase_pending_blocks(struct jffs2_sb_info *c); --void jffs2_mark_erased_blocks(struct jffs2_sb_info *c); --void jffs2_erase_pending_trigger(struct jffs2_sb_info *c); -+void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count); -+ -+#ifdef CONFIG_JFFS2_FS_NAND -+/* wbuf.c */ -+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino); -+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c); -+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+#endif - - /* compr_zlib.c */ - int jffs2_zlib_init(void); - void jffs2_zlib_exit(void); -+ -+#endif /* __JFFS2_NODELIST_H__ */ -diff -Nurb linux-mips-2.4.27/fs/jffs2/nodemgmt.c linux/fs/jffs2/nodemgmt.c ---- linux-mips-2.4.27/fs/jffs2/nodemgmt.c 2002-06-27 00:36:20.000000000 +0200 -+++ linux/fs/jffs2/nodemgmt.c 2004-11-19 10:25:12.115166960 +0100 -@@ -1,45 +1,21 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/kernel.h> - #include <linux/slab.h> --#include <linux/jffs2.h> - #include <linux/mtd/mtd.h> --#include <linux/interrupt.h> -+#include <linux/compiler.h> -+#include <linux/sched.h> /* For cond_resched() */ - #include "nodelist.h" - - /** -@@ -62,53 +38,95 @@ - * for the requested allocation. - */ - --static int jffs2_do_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len); -+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len); - --int jffs2_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len, int prio) -+int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len, int prio) - { - int ret = -EAGAIN; -- int blocksneeded = JFFS2_RESERVED_BLOCKS_WRITE; -+ int blocksneeded = c->resv_blocks_write; - /* align it */ - minsize = PAD(minsize); - -- if (prio == ALLOC_DELETION) -- blocksneeded = JFFS2_RESERVED_BLOCKS_DELETION; -- - D1(printk(KERN_DEBUG "jffs2_reserve_space(): Requested 0x%x bytes\n", minsize)); - down(&c->alloc_sem); - - D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); - -- spin_lock_bh(&c->erase_completion_lock); -+ spin_lock(&c->erase_completion_lock); - -- /* this needs a little more thought */ -+ /* this needs a little more thought (true <tglx> :)) */ - while(ret == -EAGAIN) { - while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { - int ret; -+ uint32_t dirty, avail; -+ -+ /* calculate real dirty size -+ * dirty_size contains blocks on erase_pending_list -+ * those blocks are counted in c->nr_erasing_blocks. -+ * If one block is actually erased, it is not longer counted as dirty_space -+ * but it is counted in c->nr_erasing_blocks, so we add it and subtract it -+ * with c->nr_erasing_blocks * c->sector_size again. -+ * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks -+ * This helps us to force gc and pick eventually a clean block to spread the load. -+ * We add unchecked_size here, as we hopefully will find some space to use. -+ * This will affect the sum only once, as gc first finishes checking -+ * of nodes. -+ */ -+ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; -+ if (dirty < c->nospc_dirty_size) { -+ if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { -+ printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n"); -+ break; -+ } -+ D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n", -+ dirty, c->unchecked_size, c->sector_size)); -+ -+ spin_unlock(&c->erase_completion_lock); -+ up(&c->alloc_sem); -+ return -ENOSPC; -+ } - -+ /* Calc possibly available space. Possibly available means that we -+ * don't know, if unchecked size contains obsoleted nodes, which could give us some -+ * more usable space. This will affect the sum only once, as gc first finishes checking -+ * of nodes. -+ + Return -ENOSPC, if the maximum possibly available space is less or equal than -+ * blocksneeded * sector_size. -+ * This blocks endless gc looping on a filesystem, which is nearly full, even if -+ * the check above passes. -+ */ -+ avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; -+ if ( (avail / c->sector_size) <= blocksneeded) { -+ if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) { -+ printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n"); -+ break; -+ } -+ -+ D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", -+ avail, blocksneeded * c->sector_size)); -+ spin_unlock(&c->erase_completion_lock); - up(&c->alloc_sem); -- if (c->dirty_size < c->sector_size) { -- D1(printk(KERN_DEBUG "Short on space, but total dirty size 0x%08x < sector size 0x%08x, so -ENOSPC\n", c->dirty_size, c->sector_size)); -- spin_unlock_bh(&c->erase_completion_lock); - return -ENOSPC; - } -- D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", -- c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->used_size, c->erasing_size, c->bad_size, -- c->free_size + c->dirty_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); -- spin_unlock_bh(&c->erase_completion_lock); -+ -+ up(&c->alloc_sem); -+ -+ D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", -+ 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, -+ c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); -+ spin_unlock(&c->erase_completion_lock); - - ret = jffs2_garbage_collect_pass(c); - if (ret) - return ret; - -- if (current->need_resched) -- schedule(); -+ cond_resched(); - - if (signal_pending(current)) - return -EINTR; - - down(&c->alloc_sem); -- spin_lock_bh(&c->erase_completion_lock); -+ spin_lock(&c->erase_completion_lock); - } - - ret = jffs2_do_reserve_space(c, minsize, ofs, len); -@@ -116,45 +134,72 @@ - D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); - } - } -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - if (ret) - up(&c->alloc_sem); - return ret; - } - --int jffs2_reserve_space_gc(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len) -+int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) - { - int ret = -EAGAIN; - minsize = PAD(minsize); - - D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize)); - -- spin_lock_bh(&c->erase_completion_lock); -+ spin_lock(&c->erase_completion_lock); - while(ret == -EAGAIN) { - ret = jffs2_do_reserve_space(c, minsize, ofs, len); - if (ret) { - D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); - } - } -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - return ret; - } - - /* Called with alloc sem _and_ erase_completion_lock */ --static int jffs2_do_reserve_space(struct jffs2_sb_info *c, __u32 minsize, __u32 *ofs, __u32 *len) -+static int jffs2_do_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs, uint32_t *len) - { - struct jffs2_eraseblock *jeb = c->nextblock; - - restart: - if (jeb && minsize > jeb->free_size) { - /* Skip the end of this block and file it as having some dirty space */ -- c->dirty_size += jeb->free_size; -+ /* If there's a pending write to it, flush now */ -+ if (jffs2_wbuf_dirty(c)) { -+ spin_unlock(&c->erase_completion_lock); -+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); -+ jffs2_flush_wbuf_pad(c); -+ spin_lock(&c->erase_completion_lock); -+ jeb = c->nextblock; -+ goto restart; -+ } -+ c->wasted_size += jeb->free_size; - c->free_size -= jeb->free_size; -- jeb->dirty_size += jeb->free_size; -+ jeb->wasted_size += jeb->free_size; - jeb->free_size = 0; -+ -+ /* Check, if we have a dirty block now, or if it was dirty already */ -+ if (ISDIRTY (jeb->wasted_size + jeb->dirty_size)) { -+ c->dirty_size += jeb->wasted_size; -+ c->wasted_size -= jeb->wasted_size; -+ jeb->dirty_size += jeb->wasted_size; -+ jeb->wasted_size = 0; -+ if (VERYDIRTY(c, jeb->dirty_size)) { -+ 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", -+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); -+ list_add_tail(&jeb->list, &c->very_dirty_list); -+ } else { - D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to dirty_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", - jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); - list_add_tail(&jeb->list, &c->dirty_list); -+ } -+ } else { -+ D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", -+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); -+ list_add_tail(&jeb->list, &c->clean_list); -+ } - c->nextblock = jeb = NULL; - } - -@@ -164,33 +209,44 @@ - - if (list_empty(&c->free_list)) { - -- DECLARE_WAITQUEUE(wait, current); -+ if (!c->nr_erasing_blocks && -+ !list_empty(&c->erasable_list)) { -+ struct jffs2_eraseblock *ejeb; -+ -+ ejeb = list_entry(c->erasable_list.next, struct jffs2_eraseblock, list); -+ list_del(&ejeb->list); -+ list_add_tail(&ejeb->list, &c->erase_pending_list); -+ c->nr_erasing_blocks++; -+ jffs2_erase_pending_trigger(c); -+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Triggering erase of erasable block at 0x%08x\n", -+ ejeb->offset)); -+ } -+ -+ if (!c->nr_erasing_blocks && -+ !list_empty(&c->erasable_pending_wbuf_list)) { -+ D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); -+ /* c->nextblock is NULL, no update to c->nextblock allowed */ -+ spin_unlock(&c->erase_completion_lock); -+ jffs2_flush_wbuf_pad(c); -+ spin_lock(&c->erase_completion_lock); -+ /* Have another go. It'll be on the erasable_list now */ -+ return -EAGAIN; -+ } - - if (!c->nr_erasing_blocks) { --// if (list_empty(&c->erasing_list) && list_empty(&c->erase_pending_list) && list_empty(c->erase_complete_list)) { - /* Ouch. We're in GC, or we wouldn't have got here. - And there's no space left. At all. */ -- printk(KERN_CRIT "Argh. No free space left for GC. nr_erasing_blocks is %d. nr_free_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n", -- c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); -+ 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", -+ c->nr_erasing_blocks, c->nr_free_blocks, list_empty(&c->erasable_list)?"yes":"no", -+ list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no"); - return -ENOSPC; - } -- /* Make sure this can't deadlock. Someone has to start the erases -- of erase_pending blocks */ -- set_current_state(TASK_INTERRUPTIBLE); -- add_wait_queue(&c->erase_wait, &wait); -- D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasingempty: %s, erasependingempty: %s)\n", -- c->nr_erasing_blocks, list_empty(&c->erasing_list)?"yes":"no", list_empty(&c->erase_pending_list)?"yes":"no")); -- if (!list_empty(&c->erase_pending_list)) { -- D1(printk(KERN_DEBUG "Triggering pending erases\n")); -- jffs2_erase_pending_trigger(c); -- } -- spin_unlock_bh(&c->erase_completion_lock); -- schedule(); -- remove_wait_queue(&c->erase_wait, &wait); -- spin_lock_bh(&c->erase_completion_lock); -- if (signal_pending(current)) { -- return -EINTR; -- } -+ -+ spin_unlock(&c->erase_completion_lock); -+ /* Don't wait for it; just erase one right now */ -+ jffs2_erase_pending_blocks(c, 1); -+ spin_lock(&c->erase_completion_lock); -+ - /* An erase may have failed, decreasing the - amount of free space available. So we must - restart from the beginning */ -@@ -201,7 +257,8 @@ - list_del(next); - c->nextblock = jeb = list_entry(next, struct jffs2_eraseblock, list); - c->nr_free_blocks--; -- if (jeb->free_size != c->sector_size - sizeof(struct jffs2_unknown_node)) { -+ -+ if (jeb->free_size != c->sector_size - c->cleanmarker_size) { - printk(KERN_WARNING "Eep. Block 0x%08x taken from free_list had free_size of 0x%08x!!\n", jeb->offset, jeb->free_size); - goto restart; - } -@@ -210,6 +267,20 @@ - enough space */ - *ofs = jeb->offset + (c->sector_size - jeb->free_size); - *len = jeb->free_size; -+ -+ if (c->cleanmarker_size && jeb->used_size == c->cleanmarker_size && -+ !jeb->first_node->next_in_ino) { -+ /* Only node in it beforehand was a CLEANMARKER node (we think). -+ So mark it obsolete now that there's going to be another node -+ in the block. This will reduce used_size to zero but We've -+ already set c->nextblock so that jffs2_mark_node_obsolete() -+ won't try to refile it to the dirty_list. -+ */ -+ spin_unlock(&c->erase_completion_lock); -+ jffs2_mark_node_obsolete(c, jeb->first_node); -+ spin_lock(&c->erase_completion_lock); -+ } -+ - D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs)); - return 0; - } -@@ -217,9 +288,9 @@ - /** - * jffs2_add_physical_node_ref - add a physical node reference to the list - * @c: superblock info -- * @ofs: physical location of this physical node -+ * @new: new node reference to add - * @len: length of this physical node -- * @ino: inode number with which this physical node is associated -+ * @dirty: dirty flag for new node - * - * Should only be used to report nodes for which space has been allocated - * by jffs2_reserve_space. -@@ -227,47 +298,58 @@ - * Must be called with the alloc_sem held. - */ - --int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new, __u32 len, int dirty) -+int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *new) - { - struct jffs2_eraseblock *jeb; -+ uint32_t len; -+ -+ jeb = &c->blocks[new->flash_offset / c->sector_size]; -+ len = ref_totlen(c, jeb, new); - -- len = PAD(len); -- jeb = &c->blocks[(new->flash_offset & ~3) / c->sector_size]; -- D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", new->flash_offset & ~3, len)); -+ D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); - #if 1 -- if (jeb != c->nextblock || (new->flash_offset & ~3) != jeb->offset + (c->sector_size - jeb->free_size)) { -+ if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) { - printk(KERN_WARNING "argh. node added in wrong place\n"); - jffs2_free_raw_node_ref(new); - return -EINVAL; - } - #endif -+ spin_lock(&c->erase_completion_lock); -+ - if (!jeb->first_node) - jeb->first_node = new; - if (jeb->last_node) - jeb->last_node->next_phys = new; - jeb->last_node = new; - -- spin_lock_bh(&c->erase_completion_lock); - jeb->free_size -= len; - c->free_size -= len; -- if (dirty) { -- new->flash_offset |= 1; -+ if (ref_obsolete(new)) { - jeb->dirty_size += len; - c->dirty_size += len; - } else { - jeb->used_size += len; - c->used_size += len; - } -- spin_unlock_bh(&c->erase_completion_lock); -+ - if (!jeb->free_size && !jeb->dirty_size) { - /* If it lives on the dirty_list, jffs2_reserve_space will put it there */ - D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n", - jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); -+ if (jffs2_wbuf_dirty(c)) { -+ /* Flush the last write in the block if it's outstanding */ -+ spin_unlock(&c->erase_completion_lock); -+ jffs2_flush_wbuf_pad(c); -+ spin_lock(&c->erase_completion_lock); -+ } -+ - list_add_tail(&jeb->list, &c->clean_list); - c->nextblock = NULL; - } - ACCT_SANITY_CHECK(c,jeb); -- ACCT_PARANOIA_CHECK(jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ -+ spin_unlock(&c->erase_completion_lock); - - return 0; - } -@@ -280,20 +362,34 @@ - up(&c->alloc_sem); - } - -+static inline int on_list(struct list_head *obj, struct list_head *head) -+{ -+ struct list_head *this; -+ -+ list_for_each(this, head) { -+ if (this == obj) { -+ D1(printk("%p is on list at %p\n", obj, head)); -+ return 1; -+ -+ } -+ } -+ return 0; -+} -+ - void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref *ref) - { - struct jffs2_eraseblock *jeb; - int blocknr; - struct jffs2_unknown_node n; -- int ret; -- ssize_t retlen; -+ int ret, addedsize; -+ size_t retlen; - - if(!ref) { - printk(KERN_NOTICE "EEEEEK. jffs2_mark_node_obsolete called with NULL node\n"); - return; - } -- if (ref->flash_offset & 1) { -- D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref->flash_offset &~3)); -+ if (ref_obsolete(ref)) { -+ D1(printk(KERN_DEBUG "jffs2_mark_node_obsolete called with already obsolete node at 0x%08x\n", ref_offset(ref))); - return; - } - blocknr = ref->flash_offset / c->sector_size; -@@ -302,22 +398,63 @@ - BUG(); - } - jeb = &c->blocks[blocknr]; -- if (jeb->used_size < ref->totlen) { -+ -+ spin_lock(&c->erase_completion_lock); -+ -+ if (ref_flags(ref) == REF_UNCHECKED) { -+ D1(if (unlikely(jeb->unchecked_size < ref_totlen(c, jeb, ref))) { -+ printk(KERN_NOTICE "raw unchecked node of size 0x%08x freed from erase block %d at 0x%08x, but unchecked_size was already 0x%08x\n", -+ ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); -+ BUG(); -+ }) -+ D1(printk(KERN_DEBUG "Obsoleting previously unchecked node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); -+ jeb->unchecked_size -= ref_totlen(c, jeb, ref); -+ c->unchecked_size -= ref_totlen(c, jeb, ref); -+ } else { -+ D1(if (unlikely(jeb->used_size < ref_totlen(c, jeb, ref))) { - printk(KERN_NOTICE "raw node of size 0x%08x freed from erase block %d at 0x%08x, but used_size was already 0x%08x\n", -- ref->totlen, blocknr, ref->flash_offset, jeb->used_size); -+ ref_totlen(c, jeb, ref), blocknr, ref->flash_offset, jeb->used_size); - BUG(); -+ }) -+ D1(printk(KERN_DEBUG "Obsoleting node at 0x%08x of len %x: ", ref_offset(ref), ref_totlen(c, jeb, ref))); -+ jeb->used_size -= ref_totlen(c, jeb, ref); -+ c->used_size -= ref_totlen(c, jeb, ref); -+ } -+ -+ // Take care, that wasted size is taken into concern -+ if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) { -+ D1(printk("Dirtying\n")); -+ addedsize = ref_totlen(c, jeb, ref); -+ jeb->dirty_size += ref_totlen(c, jeb, ref); -+ c->dirty_size += ref_totlen(c, jeb, ref); -+ -+ /* Convert wasted space to dirty, if not a bad block */ -+ if (jeb->wasted_size) { -+ if (on_list(&jeb->list, &c->bad_used_list)) { -+ D1(printk(KERN_DEBUG "Leaving block at %08x on the bad_used_list\n", -+ jeb->offset)); -+ addedsize = 0; /* To fool the refiling code later */ -+ } else { -+ D1(printk(KERN_DEBUG "Converting %d bytes of wasted space to dirty in block at %08x\n", -+ jeb->wasted_size, jeb->offset)); -+ addedsize += jeb->wasted_size; -+ jeb->dirty_size += jeb->wasted_size; -+ c->dirty_size += jeb->wasted_size; -+ c->wasted_size -= jeb->wasted_size; -+ jeb->wasted_size = 0; - } -- -- spin_lock_bh(&c->erase_completion_lock); -- jeb->used_size -= ref->totlen; -- jeb->dirty_size += ref->totlen; -- c->used_size -= ref->totlen; -- c->dirty_size += ref->totlen; -- ref->flash_offset |= 1; -+ } -+ } else { -+ D1(printk("Wasting\n")); -+ addedsize = 0; -+ jeb->wasted_size += ref_totlen(c, jeb, ref); -+ c->wasted_size += ref_totlen(c, jeb, ref); -+ } -+ ref->flash_offset = ref_offset(ref) | REF_OBSOLETE; - - ACCT_SANITY_CHECK(c, jeb); - -- ACCT_PARANOIA_CHECK(jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); - - if (c->flags & JFFS2_SB_FLAG_MOUNTING) { - /* Mount in progress. Don't muck about with the block -@@ -325,68 +462,280 @@ - obliterate nodes that look obsolete. If they weren't - marked obsolete on the flash at the time they _became_ - obsolete, there was probably a reason for that. */ -- spin_unlock_bh(&c->erase_completion_lock); -+ spin_unlock(&c->erase_completion_lock); - return; - } -+ - if (jeb == c->nextblock) { - D2(printk(KERN_DEBUG "Not moving nextblock 0x%08x to dirty/erase_pending list\n", jeb->offset)); -- } else if (jeb == c->gcblock) { -- D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty/erase_pending list\n", jeb->offset)); --#if 0 /* We no longer do this here. It can screw the wear levelling. If you have a lot of static -- data and a few blocks free, and you just create new files and keep deleting/overwriting -- them, then you'd keep erasing and reusing those blocks without ever moving stuff around. -- So we leave completely obsoleted blocks on the dirty_list and let the GC delete them -- when it finds them there. That way, we still get the 'once in a while, take a clean block' -- to spread out the flash usage */ -- } else if (!jeb->used_size) { -+ } else if (!jeb->used_size && !jeb->unchecked_size) { -+ if (jeb == c->gcblock) { -+ D1(printk(KERN_DEBUG "gcblock at 0x%08x completely dirtied. Clearing gcblock...\n", jeb->offset)); -+ c->gcblock = NULL; -+ } else { - D1(printk(KERN_DEBUG "Eraseblock at 0x%08x completely dirtied. Removing from (dirty?) list...\n", jeb->offset)); - list_del(&jeb->list); -+ } -+ if (jffs2_wbuf_dirty(c)) { -+ D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n")); -+ list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list); -+ } else { -+ if (jiffies & 127) { -+ /* Most of the time, we just erase it immediately. Otherwise we -+ spend ages scanning it on mount, etc. */ - D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n")); - list_add_tail(&jeb->list, &c->erase_pending_list); - c->nr_erasing_blocks++; - jffs2_erase_pending_trigger(c); -- // OFNI_BS_2SFFJ(c)->s_dirt = 1; -+ } else { -+ /* Sometimes, however, we leave it elsewhere so it doesn't get -+ immediately reused, and we spread the load a bit. */ -+ D1(printk(KERN_DEBUG "...and adding to erasable_list\n")); -+ list_add_tail(&jeb->list, &c->erasable_list); -+ } -+ } - D1(printk(KERN_DEBUG "Done OK\n")); --#endif -- } else if (jeb->dirty_size == ref->totlen) { -+ } else if (jeb == c->gcblock) { -+ D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset)); -+ } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) { - D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset)); - list_del(&jeb->list); - D1(printk(KERN_DEBUG "...and adding to dirty_list\n")); - list_add_tail(&jeb->list, &c->dirty_list); -+ } else if (VERYDIRTY(c, jeb->dirty_size) && -+ !VERYDIRTY(c, jeb->dirty_size - addedsize)) { -+ D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is now very dirty. Removing from dirty list...\n", jeb->offset)); -+ list_del(&jeb->list); -+ D1(printk(KERN_DEBUG "...and adding to very_dirty_list\n")); -+ list_add_tail(&jeb->list, &c->very_dirty_list); -+ } else { -+ D1(printk(KERN_DEBUG "Eraseblock at 0x%08x not moved anywhere. (free 0x%08x, dirty 0x%08x, used 0x%08x)\n", -+ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); - } -- spin_unlock_bh(&c->erase_completion_lock); - -- if (c->mtd->type != MTD_NORFLASH && c->mtd->type != MTD_RAM) -+ spin_unlock(&c->erase_completion_lock); -+ -+ if (!jffs2_can_mark_obsolete(c)) - return; -- if (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) -+ if (jffs2_is_readonly(c)) - return; - -- D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref->flash_offset &~3)); -- ret = c->mtd->read(c->mtd, ref->flash_offset &~3, sizeof(n), &retlen, (char *)&n); -+ D1(printk(KERN_DEBUG "obliterating obsoleted node at 0x%08x\n", ref_offset(ref))); -+ ret = jffs2_flash_read(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); - if (ret) { -- printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret); -+ printk(KERN_WARNING "Read error reading from obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); - return; - } - if (retlen != sizeof(n)) { -- printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen); -+ printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); - return; - } -- if (PAD(n.totlen) != PAD(ref->totlen)) { -- printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen in node ref (0x%08x)\n", n.totlen, ref->totlen); -+ if (PAD(je32_to_cpu(n.totlen)) != PAD(ref_totlen(c, jeb, ref))) { -+ printk(KERN_WARNING "Node totlen on flash (0x%08x) != totlen from node ref (0x%08x)\n", je32_to_cpu(n.totlen), ref_totlen(c, jeb, ref)); - return; - } -- if (!(n.nodetype & JFFS2_NODE_ACCURATE)) { -- D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x\n", ref->flash_offset &~3, n.nodetype)); -+ if (!(je16_to_cpu(n.nodetype) & JFFS2_NODE_ACCURATE)) { -+ D1(printk(KERN_DEBUG "Node at 0x%08x was already marked obsolete (nodetype 0x%04x)\n", ref_offset(ref), je16_to_cpu(n.nodetype))); - return; - } -- n.nodetype &= ~JFFS2_NODE_ACCURATE; -- ret = c->mtd->write(c->mtd, ref->flash_offset&~3, sizeof(n), &retlen, (char *)&n); -+ /* XXX FIXME: This is ugly now */ -+ n.nodetype = cpu_to_je16(je16_to_cpu(n.nodetype) & ~JFFS2_NODE_ACCURATE); -+ ret = jffs2_flash_write(c, ref_offset(ref), sizeof(n), &retlen, (char *)&n); - if (ret) { -- printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, ret); -+ printk(KERN_WARNING "Write error in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), ret); - return; - } - if (retlen != sizeof(n)) { -- printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref->flash_offset &~3, retlen); -+ printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); - return; - } - } -+ -+#if CONFIG_JFFS2_FS_DEBUG > 0 -+void jffs2_dump_block_lists(struct jffs2_sb_info *c) -+{ -+ -+ -+ printk(KERN_DEBUG "jffs2_dump_block_lists:\n"); -+ printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size); -+ printk(KERN_DEBUG "used_size: %08x\n", c->used_size); -+ printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size); -+ printk(KERN_DEBUG "wasted_size: %08x\n", c->wasted_size); -+ printk(KERN_DEBUG "unchecked_size: %08x\n", c->unchecked_size); -+ printk(KERN_DEBUG "free_size: %08x\n", c->free_size); -+ printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size); -+ printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size); -+ printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size); -+ printk(KERN_DEBUG "jffs2_reserved_blocks size: %08x\n",c->sector_size * c->resv_blocks_write); -+ -+ if (c->nextblock) { -+ printk(KERN_DEBUG "nextblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", -+ c->nextblock->offset, c->nextblock->used_size, c->nextblock->dirty_size, c->nextblock->wasted_size, c->nextblock->unchecked_size, c->nextblock->free_size); -+ } else { -+ printk(KERN_DEBUG "nextblock: NULL\n"); -+ } -+ if (c->gcblock) { -+ printk(KERN_DEBUG "gcblock: %08x (used %08x, dirty %08x, wasted %08x, unchecked %08x, free %08x)\n", -+ c->gcblock->offset, c->gcblock->used_size, c->gcblock->dirty_size, c->gcblock->wasted_size, c->gcblock->unchecked_size, c->gcblock->free_size); -+ } else { -+ printk(KERN_DEBUG "gcblock: NULL\n"); -+ } -+ if (list_empty(&c->clean_list)) { -+ printk(KERN_DEBUG "clean_list: empty\n"); -+ } else { -+ struct list_head *this; -+ int numblocks = 0; -+ uint32_t dirty = 0; -+ -+ list_for_each(this, &c->clean_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ numblocks ++; -+ dirty += jeb->wasted_size; -+ 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); -+ } -+ printk (KERN_DEBUG "Contains %d blocks with total wasted size %u, average wasted size: %u\n", numblocks, dirty, dirty / numblocks); -+ } -+ if (list_empty(&c->very_dirty_list)) { -+ printk(KERN_DEBUG "very_dirty_list: empty\n"); -+ } else { -+ struct list_head *this; -+ int numblocks = 0; -+ uint32_t dirty = 0; -+ -+ list_for_each(this, &c->very_dirty_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ numblocks ++; -+ dirty += jeb->dirty_size; -+ printk(KERN_DEBUG "very_dirty_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); -+ } -+ printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", -+ numblocks, dirty, dirty / numblocks); -+ } -+ if (list_empty(&c->dirty_list)) { -+ printk(KERN_DEBUG "dirty_list: empty\n"); -+ } else { -+ struct list_head *this; -+ int numblocks = 0; -+ uint32_t dirty = 0; -+ -+ list_for_each(this, &c->dirty_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ numblocks ++; -+ dirty += jeb->dirty_size; -+ printk(KERN_DEBUG "dirty_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); -+ } -+ printk (KERN_DEBUG "Contains %d blocks with total dirty size %u, average dirty size: %u\n", -+ numblocks, dirty, dirty / numblocks); -+ } -+ if (list_empty(&c->erasable_list)) { -+ printk(KERN_DEBUG "erasable_list: empty\n"); -+ } else { -+ struct list_head *this; -+ -+ list_for_each(this, &c->erasable_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ printk(KERN_DEBUG "erasable_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); -+ } -+ } -+ if (list_empty(&c->erasing_list)) { -+ printk(KERN_DEBUG "erasing_list: empty\n"); -+ } else { -+ struct list_head *this; -+ -+ list_for_each(this, &c->erasing_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ printk(KERN_DEBUG "erasing_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); -+ } -+ } -+ if (list_empty(&c->erase_pending_list)) { -+ printk(KERN_DEBUG "erase_pending_list: empty\n"); -+ } else { -+ struct list_head *this; -+ -+ list_for_each(this, &c->erase_pending_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ printk(KERN_DEBUG "erase_pending_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); -+ } -+ } -+ if (list_empty(&c->erasable_pending_wbuf_list)) { -+ printk(KERN_DEBUG "erasable_pending_wbuf_list: empty\n"); -+ } else { -+ struct list_head *this; -+ -+ list_for_each(this, &c->erasable_pending_wbuf_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ printk(KERN_DEBUG "erasable_pending_wbuf_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); -+ } -+ } -+ if (list_empty(&c->free_list)) { -+ printk(KERN_DEBUG "free_list: empty\n"); -+ } else { -+ struct list_head *this; -+ -+ list_for_each(this, &c->free_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ printk(KERN_DEBUG "free_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); -+ } -+ } -+ if (list_empty(&c->bad_list)) { -+ printk(KERN_DEBUG "bad_list: empty\n"); -+ } else { -+ struct list_head *this; -+ -+ list_for_each(this, &c->bad_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ printk(KERN_DEBUG "bad_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); -+ } -+ } -+ if (list_empty(&c->bad_used_list)) { -+ printk(KERN_DEBUG "bad_used_list: empty\n"); -+ } else { -+ struct list_head *this; -+ -+ list_for_each(this, &c->bad_used_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ printk(KERN_DEBUG "bad_used_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); -+ } -+ } -+} -+#endif /* CONFIG_JFFS2_FS_DEBUG */ -+ -+int jffs2_thread_should_wake(struct jffs2_sb_info *c) -+{ -+ int ret = 0; -+ uint32_t dirty; -+ -+ if (c->unchecked_size) { -+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): unchecked_size %d, checked_ino #%d\n", -+ c->unchecked_size, c->checked_ino)); -+ return 1; -+ } -+ -+ /* dirty_size contains blocks on erase_pending_list -+ * those blocks are counted in c->nr_erasing_blocks. -+ * If one block is actually erased, it is not longer counted as dirty_space -+ * but it is counted in c->nr_erasing_blocks, so we add it and subtract it -+ * with c->nr_erasing_blocks * c->sector_size again. -+ * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks -+ * This helps us to force gc and pick eventually a clean block to spread the load. -+ */ -+ dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; -+ -+ if (c->nr_free_blocks + c->nr_erasing_blocks < c->resv_blocks_gctrigger && -+ (dirty > c->nospc_dirty_size)) -+ ret = 1; -+ -+ D1(printk(KERN_DEBUG "jffs2_thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", -+ c->nr_free_blocks, c->nr_erasing_blocks, c->dirty_size, ret?"yes":"no")); -+ -+ return ret; -+} -diff -Nurb linux-mips-2.4.27/fs/jffs2/os-linux.h linux/fs/jffs2/os-linux.h ---- linux-mips-2.4.27/fs/jffs2/os-linux.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/jffs2/os-linux.h 2004-11-19 10:25:12.116166808 +0100 -@@ -0,0 +1,212 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2002-2003 Red Hat, Inc. -+ * -+ * Created by David Woodhouse <dwmw2@redhat.com> -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ * -+ * $Id$ -+ * -+ */ -+ -+#ifndef __JFFS2_OS_LINUX_H__ -+#define __JFFS2_OS_LINUX_H__ -+#include <linux/version.h> -+ -+/* JFFS2 uses Linux mode bits natively -- no need for conversion */ -+#define os_to_jffs2_mode(x) (x) -+#define jffs2_to_os_mode(x) (x) -+ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73) -+#define kstatfs statfs -+#endif -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) -+#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode)) -+#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode) -+#define JFFS2_SB_INFO(sb) (sb->s_fs_info) -+#define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv) -+#elif defined(JFFS2_OUT_OF_KERNEL) -+#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u) -+#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) ) -+#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u) -+#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) ) -+#else -+#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i) -+#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) ) -+#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb) -+#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) ) -+#endif -+ -+ -+#define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size) -+#define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode) -+#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) -+#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1) -+#define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f))) -+#define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f))) -+#else -+#define JFFS2_F_I_RDEV_MIN(f) (MINOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) -+#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) -+#endif -+ -+/* Urgh. The things we do to keep the 2.4 build working */ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47) -+#define ITIME(sec) ((struct timespec){sec, 0}) -+#define I_SEC(tv) ((tv).tv_sec) -+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec) -+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec) -+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec) -+#else -+#define ITIME(x) (x) -+#define I_SEC(x) (x) -+#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime) -+#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime) -+#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime) -+#endif -+ -+#define sleep_on_spinunlock(wq, s) \ -+ do { \ -+ DECLARE_WAITQUEUE(__wait, current); \ -+ add_wait_queue((wq), &__wait); \ -+ set_current_state(TASK_UNINTERRUPTIBLE); \ -+ spin_unlock(s); \ -+ schedule(); \ -+ remove_wait_queue((wq), &__wait); \ -+ } while(0) -+ -+static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) -+{ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) -+ f->highest_version = 0; -+ f->fragtree = RB_ROOT; -+ f->metadata = NULL; -+ f->dents = NULL; -+ f->flags = 0; -+ f->usercompr = 0; -+#else -+ memset(f, 0, sizeof(*f)); -+ init_MUTEX_LOCKED(&f->sem); -+#endif -+} -+ -+#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) -+ -+#ifndef CONFIG_JFFS2_FS_NAND -+#define jffs2_can_mark_obsolete(c) (1) -+#define jffs2_cleanmarker_oob(c) (0) -+#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) -+ -+#define jffs2_flash_write(c, ofs, len, retlen, buf) ((c)->mtd->write((c)->mtd, ofs, len, retlen, buf)) -+#define jffs2_flash_read(c, ofs, len, retlen, buf) ((c)->mtd->read((c)->mtd, ofs, len, retlen, buf)) -+#define jffs2_flush_wbuf_pad(c) ({ (void)(c), 0; }) -+#define jffs2_flush_wbuf_gc(c, i) ({ (void)(c), (void) i, 0; }) -+#define jffs2_nand_read_failcnt(c,jeb) do { ; } while(0) -+#define jffs2_write_nand_badblock(c,jeb) do { ; } while(0) -+#define jffs2_nand_flash_setup(c) (0) -+#define jffs2_nand_flash_cleanup(c) do {} while(0) -+#define jffs2_wbuf_dirty(c) (0) -+#define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e) -+#define jffs2_wbuf_timeout NULL -+#define jffs2_wbuf_process NULL -+ -+#else /* NAND support present */ -+ -+#define jffs2_can_mark_obsolete(c) (c->mtd->type == MTD_NORFLASH || c->mtd->type == MTD_RAM) -+#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) -+ -+#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf)) -+#define jffs2_flash_read_oob(c, ofs, len, retlen, buf) ((c)->mtd->read_oob((c)->mtd, ofs, len, retlen, buf)) -+#define jffs2_wbuf_dirty(c) (!!(c)->wbuf_len) -+struct kstatfs; -+ -+/* wbuf.c */ -+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino); -+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf); -+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf); -+int jffs2_check_oob_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb,int mode); -+int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+void jffs2_wbuf_timeout(unsigned long data); -+void jffs2_wbuf_process(void *data); -+int jffs2_nand_flash_setup(struct jffs2_sb_info *c); -+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c); -+#endif /* NAND */ -+ -+/* erase.c */ -+static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) -+{ -+ OFNI_BS_2SFFJ(c)->s_dirt = 1; -+} -+ -+/* background.c */ -+int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c); -+void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c); -+void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c); -+ -+/* dir.c */ -+extern struct file_operations jffs2_dir_operations; -+extern struct inode_operations jffs2_dir_inode_operations; -+ -+/* file.c */ -+extern struct file_operations jffs2_file_operations; -+extern struct inode_operations jffs2_file_inode_operations; -+extern struct address_space_operations jffs2_file_address_operations; -+int jffs2_fsync(struct file *, struct dentry *, int); -+int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg); -+int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); -+int jffs2_readpage (struct file *, struct page *); -+int jffs2_prepare_write (struct file *, struct page *, unsigned, unsigned); -+int jffs2_commit_write (struct file *, struct page *, unsigned, unsigned); -+ -+/* ioctl.c */ -+int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -+ -+/* symlink.c */ -+extern struct inode_operations jffs2_symlink_inode_operations; -+ -+/* fs.c */ -+int jffs2_setattr (struct dentry *, struct iattr *); -+void jffs2_read_inode (struct inode *); -+void jffs2_clear_inode (struct inode *); -+void jffs2_dirty_inode(struct inode *inode); -+struct inode *jffs2_new_inode (struct inode *dir_i, int mode, -+ struct jffs2_raw_inode *ri); -+int jffs2_statfs (struct super_block *, struct kstatfs *); -+void jffs2_write_super (struct super_block *); -+int jffs2_remount_fs (struct super_block *, int *, char *); -+int jffs2_do_fill_super(struct super_block *sb, void *data, int silent); -+void jffs2_gc_release_inode(struct jffs2_sb_info *c, -+ struct jffs2_inode_info *f); -+struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c, -+ int inum, int nlink); -+ -+unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c, -+ struct jffs2_inode_info *f, -+ unsigned long offset, -+ unsigned long *priv); -+void jffs2_gc_release_page(struct jffs2_sb_info *c, -+ unsigned char *pg, -+ unsigned long *priv); -+ -+ -+/* writev.c */ -+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs, -+ unsigned long count, loff_t to, size_t *retlen); -+ -+/* Compression config */ -+#define JFFS2_COMPRESSION -+#undef JFFS2_USE_DYNRUBIN /* Disabled 23/9/1. With zlib it hardly ever gets a look in */ -+#undef JFFS2_USE_RUBINMIPS /* Disabled 26/2/1. Obsoleted by dynrubin */ -+#define JFFS2_USE_ZLIB -+#define JFFS2_USE_RTIME /* rtime does manage to recompress already-compressed data */ -+ -+ -+#endif /* __JFFS2_OS_LINUX_H__ */ -+ -+ -diff -Nurb linux-mips-2.4.27/fs/jffs2/pushpull.h linux/fs/jffs2/pushpull.h ---- linux-mips-2.4.27/fs/jffs2/pushpull.h 2001-11-05 21:16:19.000000000 +0100 -+++ linux/fs/jffs2/pushpull.h 2004-11-19 10:25:12.118166504 +0100 -@@ -1,42 +1,21 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001, 2002 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #ifndef __PUSHPULL_H__ - #define __PUSHPULL_H__ -+ -+#include <linux/errno.h> -+ - struct pushpull { - unsigned char *buf; - unsigned int buflen; -@@ -44,9 +23,36 @@ - unsigned int reserve; - }; - --void init_pushpull(struct pushpull *, char *, unsigned, unsigned, unsigned); --int pushbit(struct pushpull *pp, int bit, int use_reserved); --int pushedbits(struct pushpull *pp); -+ -+static inline void init_pushpull(struct pushpull *pp, char *buf, unsigned buflen, unsigned ofs, unsigned reserve) -+{ -+ pp->buf = buf; -+ pp->buflen = buflen; -+ pp->ofs = ofs; -+ pp->reserve = reserve; -+} -+ -+static inline int pushbit(struct pushpull *pp, int bit, int use_reserved) -+{ -+ if (pp->ofs >= pp->buflen - (use_reserved?0:pp->reserve)) { -+ return -ENOSPC; -+ } -+ -+ if (bit) { -+ pp->buf[pp->ofs >> 3] |= (1<<(7-(pp->ofs &7))); -+ } -+ else { -+ pp->buf[pp->ofs >> 3] &= ~(1<<(7-(pp->ofs &7))); -+ } -+ pp->ofs++; -+ -+ return 0; -+} -+ -+static inline int pushedbits(struct pushpull *pp) -+{ -+ return pp->ofs; -+} - - static inline int pullbit(struct pushpull *pp) - { -diff -Nurb linux-mips-2.4.27/fs/jffs2/rbtree.c linux/fs/jffs2/rbtree.c ---- linux-mips-2.4.27/fs/jffs2/rbtree.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/jffs2/rbtree.c 2004-11-19 10:25:12.120166200 +0100 -@@ -0,0 +1,363 @@ -+/* -+ Red Black Trees -+ (C) 1999 Andrea Arcangeli <andrea@suse.de> -+ (C) 2002 David Woodhouse <dwmw2@infradead.org> -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ $Id$ -+*/ -+ -+#ifdef __ECOS /* This file is _not_ under the eCos licence; it is pure GPL. */ -+#error "Licence problem. eCos has its own rbtree code." -+#endif -+ -+#include <linux/version.h> -+#include <linux/rbtree.h> -+ -+/* This wasn't present till 2.4.11, wasn't exported till 2.4.19 */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,11) || \ -+ (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) && defined(MODULE)) -+static void __rb_rotate_left(struct rb_node * node, struct rb_root * root) -+{ -+ struct rb_node * right = node->rb_right; -+ -+ if ((node->rb_right = right->rb_left)) -+ right->rb_left->rb_parent = node; -+ right->rb_left = node; -+ -+ if ((right->rb_parent = node->rb_parent)) -+ { -+ if (node == node->rb_parent->rb_left) -+ node->rb_parent->rb_left = right; -+ else -+ node->rb_parent->rb_right = right; -+ } -+ else -+ root->rb_node = right; -+ node->rb_parent = right; -+} -+ -+static void __rb_rotate_right(struct rb_node * node, struct rb_root * root) -+{ -+ struct rb_node * left = node->rb_left; -+ -+ if ((node->rb_left = left->rb_right)) -+ left->rb_right->rb_parent = node; -+ left->rb_right = node; -+ -+ if ((left->rb_parent = node->rb_parent)) -+ { -+ if (node == node->rb_parent->rb_right) -+ node->rb_parent->rb_right = left; -+ else -+ node->rb_parent->rb_left = left; -+ } -+ else -+ root->rb_node = left; -+ node->rb_parent = left; -+} -+ -+void rb_insert_color(struct rb_node * node, struct rb_root * root) -+{ -+ struct rb_node * parent, * gparent; -+ -+ while ((parent = node->rb_parent) && parent->rb_color == RB_RED) -+ { -+ gparent = parent->rb_parent; -+ -+ if (parent == gparent->rb_left) -+ { -+ { -+ register struct rb_node * uncle = gparent->rb_right; -+ if (uncle && uncle->rb_color == RB_RED) -+ { -+ uncle->rb_color = RB_BLACK; -+ parent->rb_color = RB_BLACK; -+ gparent->rb_color = RB_RED; -+ node = gparent; -+ continue; -+ } -+ } -+ -+ if (parent->rb_right == node) -+ { -+ register struct rb_node * tmp; -+ __rb_rotate_left(parent, root); -+ tmp = parent; -+ parent = node; -+ node = tmp; -+ } -+ -+ parent->rb_color = RB_BLACK; -+ gparent->rb_color = RB_RED; -+ __rb_rotate_right(gparent, root); -+ } else { -+ { -+ register struct rb_node * uncle = gparent->rb_left; -+ if (uncle && uncle->rb_color == RB_RED) -+ { -+ uncle->rb_color = RB_BLACK; -+ parent->rb_color = RB_BLACK; -+ gparent->rb_color = RB_RED; -+ node = gparent; -+ continue; -+ } -+ } -+ -+ if (parent->rb_left == node) -+ { -+ register struct rb_node * tmp; -+ __rb_rotate_right(parent, root); -+ tmp = parent; -+ parent = node; -+ node = tmp; -+ } -+ -+ parent->rb_color = RB_BLACK; -+ gparent->rb_color = RB_RED; -+ __rb_rotate_left(gparent, root); -+ } -+ } -+ -+ root->rb_node->rb_color = RB_BLACK; -+} -+ -+static void __rb_erase_color(struct rb_node * node, struct rb_node * parent, -+ struct rb_root * root) -+{ -+ struct rb_node * other; -+ -+ while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node) -+ { -+ if (parent->rb_left == node) -+ { -+ other = parent->rb_right; -+ if (other->rb_color == RB_RED) -+ { -+ other->rb_color = RB_BLACK; -+ parent->rb_color = RB_RED; -+ __rb_rotate_left(parent, root); -+ other = parent->rb_right; -+ } -+ if ((!other->rb_left || -+ other->rb_left->rb_color == RB_BLACK) -+ && (!other->rb_right || -+ other->rb_right->rb_color == RB_BLACK)) -+ { -+ other->rb_color = RB_RED; -+ node = parent; -+ parent = node->rb_parent; -+ } -+ else -+ { -+ if (!other->rb_right || -+ other->rb_right->rb_color == RB_BLACK) -+ { -+ register struct rb_node * o_left; -+ if ((o_left = other->rb_left)) -+ o_left->rb_color = RB_BLACK; -+ other->rb_color = RB_RED; -+ __rb_rotate_right(other, root); -+ other = parent->rb_right; -+ } -+ other->rb_color = parent->rb_color; -+ parent->rb_color = RB_BLACK; -+ if (other->rb_right) -+ other->rb_right->rb_color = RB_BLACK; -+ __rb_rotate_left(parent, root); -+ node = root->rb_node; -+ break; -+ } -+ } -+ else -+ { -+ other = parent->rb_left; -+ if (other->rb_color == RB_RED) -+ { -+ other->rb_color = RB_BLACK; -+ parent->rb_color = RB_RED; -+ __rb_rotate_right(parent, root); -+ other = parent->rb_left; -+ } -+ if ((!other->rb_left || -+ other->rb_left->rb_color == RB_BLACK) -+ && (!other->rb_right || -+ other->rb_right->rb_color == RB_BLACK)) -+ { -+ other->rb_color = RB_RED; -+ node = parent; -+ parent = node->rb_parent; -+ } -+ else -+ { -+ if (!other->rb_left || -+ other->rb_left->rb_color == RB_BLACK) -+ { -+ register struct rb_node * o_right; -+ if ((o_right = other->rb_right)) -+ o_right->rb_color = RB_BLACK; -+ other->rb_color = RB_RED; -+ __rb_rotate_left(other, root); -+ other = parent->rb_left; -+ } -+ other->rb_color = parent->rb_color; -+ parent->rb_color = RB_BLACK; -+ if (other->rb_left) -+ other->rb_left->rb_color = RB_BLACK; -+ __rb_rotate_right(parent, root); -+ node = root->rb_node; -+ break; -+ } -+ } -+ } -+ if (node) -+ node->rb_color = RB_BLACK; -+} -+ -+void rb_erase(struct rb_node * node, struct rb_root * root) -+{ -+ struct rb_node * child, * parent; -+ int color; -+ -+ if (!node->rb_left) -+ child = node->rb_right; -+ else if (!node->rb_right) -+ child = node->rb_left; -+ else -+ { -+ struct rb_node * old = node, * left; -+ -+ node = node->rb_right; -+ while ((left = node->rb_left)) -+ node = left; -+ child = node->rb_right; -+ parent = node->rb_parent; -+ color = node->rb_color; -+ -+ if (child) -+ child->rb_parent = parent; -+ if (parent) -+ { -+ if (parent->rb_left == node) -+ parent->rb_left = child; -+ else -+ parent->rb_right = child; -+ } -+ else -+ root->rb_node = child; -+ -+ if (node->rb_parent == old) -+ parent = node; -+ node->rb_parent = old->rb_parent; -+ node->rb_color = old->rb_color; -+ node->rb_right = old->rb_right; -+ node->rb_left = old->rb_left; -+ -+ if (old->rb_parent) -+ { -+ if (old->rb_parent->rb_left == old) -+ old->rb_parent->rb_left = node; -+ else -+ old->rb_parent->rb_right = node; -+ } else -+ root->rb_node = node; -+ -+ old->rb_left->rb_parent = node; -+ if (old->rb_right) -+ old->rb_right->rb_parent = node; -+ goto color; -+ } -+ -+ parent = node->rb_parent; -+ color = node->rb_color; -+ -+ if (child) -+ child->rb_parent = parent; -+ if (parent) -+ { -+ if (parent->rb_left == node) -+ parent->rb_left = child; -+ else -+ parent->rb_right = child; -+ } -+ else -+ root->rb_node = child; -+ -+ color: -+ if (color == RB_BLACK) -+ __rb_erase_color(child, parent, root); -+} -+#endif /* Before 2.4.11 */ -+ -+ /* These routines haven't made it into 2.4 (yet) */ -+struct rb_node *rb_next(struct rb_node *node) -+{ -+ /* If we have a right-hand child, go down and then left as far -+ as we can. */ -+ if (node->rb_right) { -+ node = node->rb_right; -+ while (node->rb_left) -+ node=node->rb_left; -+ return node; -+ } -+ -+ /* No right-hand children. Everything down and left is -+ smaller than us, so any 'next' node must be in the general -+ direction of our parent. Go up the tree; any time the -+ ancestor is a right-hand child of its parent, keep going -+ up. First time it's a left-hand child of its parent, said -+ parent is our 'next' node. */ -+ while (node->rb_parent && node == node->rb_parent->rb_right) -+ node = node->rb_parent; -+ -+ return node->rb_parent; -+} -+ -+struct rb_node *rb_prev(struct rb_node *node) -+{ -+ if (node->rb_left) { -+ node = node->rb_left; -+ while (node->rb_right) -+ node=node->rb_right; -+ return node; -+ } -+ while (node->rb_parent && node == node->rb_parent->rb_left) -+ node = node->rb_parent; -+ -+ return node->rb_parent; -+} -+ -+void rb_replace_node(struct rb_node *victim, struct rb_node *new, struct rb_root *root) -+{ -+ struct rb_node *parent = victim->rb_parent; -+ -+ /* Set the surrounding nodes to point to the replacement */ -+ if (parent) { -+ if (victim == parent->rb_left) -+ parent->rb_left = new; -+ else -+ parent->rb_right = new; -+ } else { -+ root->rb_node = new; -+ } -+ if (victim->rb_left) -+ victim->rb_left->rb_parent = new; -+ if (victim->rb_right) -+ victim->rb_right->rb_parent = new; -+ -+ /* Copy the pointers/colour from the victim to the replacement */ -+ *new = *victim; -+} -diff -Nurb linux-mips-2.4.27/fs/jffs2/read.c linux/fs/jffs2/read.c ---- linux-mips-2.4.27/fs/jffs2/read.c 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/read.c 2004-11-19 10:25:12.121166048 +0100 -@@ -1,52 +1,29 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/kernel.h> - #include <linux/slab.h> --#include <linux/jffs2.h> -+#include <linux/crc32.h> -+#include <linux/pagemap.h> - #include <linux/mtd/mtd.h> -+#include <linux/compiler.h> - #include "nodelist.h" --#include <linux/crc32.h> - - int jffs2_read_dnode(struct jffs2_sb_info *c, struct jffs2_full_dnode *fd, unsigned char *buf, int ofs, int len) - { - struct jffs2_raw_inode *ri; - size_t readlen; -- __u32 crc; -+ uint32_t crc; - unsigned char *decomprbuf = NULL; - unsigned char *readbuf = NULL; - int ret = 0; -@@ -55,35 +32,41 @@ - if (!ri) - return -ENOMEM; - -- ret = c->mtd->read(c->mtd, fd->raw->flash_offset & ~3, sizeof(*ri), &readlen, (char *)ri); -+ ret = jffs2_flash_read(c, ref_offset(fd->raw), sizeof(*ri), &readlen, (char *)ri); - if (ret) { - jffs2_free_raw_inode(ri); -- printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", fd->raw->flash_offset & ~3, ret); -+ printk(KERN_WARNING "Error reading node from 0x%08x: %d\n", ref_offset(fd->raw), ret); - return ret; - } - if (readlen != sizeof(*ri)) { - jffs2_free_raw_inode(ri); -- printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n", -- fd->raw->flash_offset & ~3, sizeof(*ri), readlen); -+ printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", -+ ref_offset(fd->raw), sizeof(*ri), readlen); - return -EIO; - } - crc = crc32(0, ri, sizeof(*ri)-8); - -- D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", fd->raw->flash_offset & ~3, ri->node_crc, crc, ri->dsize, ri->csize, ri->offset, buf)); -- if (crc != ri->node_crc) { -- printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n", ri->node_crc, crc, fd->raw->flash_offset & ~3); -+ D1(printk(KERN_DEBUG "Node read from %08x: node_crc %08x, calculated CRC %08x. dsize %x, csize %x, offset %x, buf %p\n", -+ ref_offset(fd->raw), je32_to_cpu(ri->node_crc), -+ crc, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), -+ je32_to_cpu(ri->offset), buf)); -+ if (crc != je32_to_cpu(ri->node_crc)) { -+ printk(KERN_WARNING "Node CRC %08x != calculated CRC %08x for node at %08x\n", -+ je32_to_cpu(ri->node_crc), crc, ref_offset(fd->raw)); - ret = -EIO; - goto out_ri; - } - /* There was a bug where we wrote hole nodes out with csize/dsize - swapped. Deal with it */ -- if (ri->compr == JFFS2_COMPR_ZERO && !ri->dsize && ri->csize) { -+ if (ri->compr == JFFS2_COMPR_ZERO && !je32_to_cpu(ri->dsize) && -+ je32_to_cpu(ri->csize)) { - ri->dsize = ri->csize; -- ri->csize = 0; -+ ri->csize = cpu_to_je32(0); - } - -- D1(if(ofs + len > ri->dsize) { -- printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", len, ofs, ri->dsize); -+ D1(if(ofs + len > je32_to_cpu(ri->dsize)) { -+ printk(KERN_WARNING "jffs2_read_dnode() asked for %d bytes at %d from %d-byte node\n", -+ len, ofs, je32_to_cpu(ri->dsize)); - ret = -EINVAL; - goto out_ri; - }); -@@ -100,18 +83,18 @@ - Reading partial node and it's uncompressed - read into readbuf, check CRC, and copy - Reading partial node and it's compressed - read into readbuf, check checksum, decompress to decomprbuf and copy - */ -- if (ri->compr == JFFS2_COMPR_NONE && len == ri->dsize) { -+ if (ri->compr == JFFS2_COMPR_NONE && len == je32_to_cpu(ri->dsize)) { - readbuf = buf; - } else { -- readbuf = kmalloc(ri->csize, GFP_KERNEL); -+ readbuf = kmalloc(je32_to_cpu(ri->csize), GFP_KERNEL); - if (!readbuf) { - ret = -ENOMEM; - goto out_ri; - } - } - if (ri->compr != JFFS2_COMPR_NONE) { -- if (len < ri->dsize) { -- decomprbuf = kmalloc(ri->dsize, GFP_KERNEL); -+ if (len < je32_to_cpu(ri->dsize)) { -+ decomprbuf = kmalloc(je32_to_cpu(ri->dsize), GFP_KERNEL); - if (!decomprbuf) { - ret = -ENOMEM; - goto out_readbuf; -@@ -123,31 +106,35 @@ - decomprbuf = readbuf; - } - -- D2(printk(KERN_DEBUG "Read %d bytes to %p\n", ri->csize, readbuf)); -- ret = c->mtd->read(c->mtd, (fd->raw->flash_offset &~3) + sizeof(*ri), ri->csize, &readlen, readbuf); -+ D2(printk(KERN_DEBUG "Read %d bytes to %p\n", je32_to_cpu(ri->csize), -+ readbuf)); -+ ret = jffs2_flash_read(c, (ref_offset(fd->raw)) + sizeof(*ri), -+ je32_to_cpu(ri->csize), &readlen, readbuf); - -- if (!ret && readlen != ri->csize) -+ if (!ret && readlen != je32_to_cpu(ri->csize)) - ret = -EIO; - if (ret) - goto out_decomprbuf; - -- crc = crc32(0, readbuf, ri->csize); -- if (crc != ri->data_crc) { -- printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", ri->data_crc, crc, fd->raw->flash_offset & ~3); -+ crc = crc32(0, readbuf, je32_to_cpu(ri->csize)); -+ if (crc != je32_to_cpu(ri->data_crc)) { -+ printk(KERN_WARNING "Data CRC %08x != calculated CRC %08x for node at %08x\n", -+ je32_to_cpu(ri->data_crc), crc, ref_offset(fd->raw)); - ret = -EIO; - goto out_decomprbuf; - } - D2(printk(KERN_DEBUG "Data CRC matches calculated CRC %08x\n", crc)); - if (ri->compr != JFFS2_COMPR_NONE) { -- D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", ri->csize, readbuf, ri->dsize, decomprbuf)); -- ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, ri->csize, ri->dsize); -+ D2(printk(KERN_DEBUG "Decompress %d bytes from %p to %d bytes at %p\n", -+ je32_to_cpu(ri->csize), readbuf, je32_to_cpu(ri->dsize), decomprbuf)); -+ ret = jffs2_decompress(ri->compr, readbuf, decomprbuf, je32_to_cpu(ri->csize), je32_to_cpu(ri->dsize)); - if (ret) { - printk(KERN_WARNING "Error: jffs2_decompress returned %d\n", ret); - goto out_decomprbuf; - } - } - -- if (len < ri->dsize) { -+ if (len < je32_to_cpu(ri->dsize)) { - memcpy(buf, decomprbuf+ofs, len); - } - out_decomprbuf: -@@ -161,3 +148,96 @@ - - return ret; - } -+ -+int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, -+ unsigned char *buf, uint32_t offset, uint32_t len) -+{ -+ uint32_t end = offset + len; -+ struct jffs2_node_frag *frag; -+ int ret; -+ -+ D1(printk(KERN_DEBUG "jffs2_read_inode_range: ino #%u, range 0x%08x-0x%08x\n", -+ f->inocache->ino, offset, offset+len)); -+ -+ frag = jffs2_lookup_node_frag(&f->fragtree, offset); -+ -+ /* XXX FIXME: Where a single physical node actually shows up in two -+ frags, we read it twice. Don't do that. */ -+ /* Now we're pointing at the first frag which overlaps our page */ -+ while(offset < end) { -+ D2(printk(KERN_DEBUG "jffs2_read_inode_range: offset %d, end %d\n", offset, end)); -+ if (unlikely(!frag || frag->ofs > offset)) { -+ uint32_t holesize = end - offset; -+ if (frag) { -+ D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset)); -+ holesize = min(holesize, frag->ofs - offset); -+ D1(jffs2_print_frag_list(f)); -+ } -+ D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize)); -+ memset(buf, 0, holesize); -+ buf += holesize; -+ offset += holesize; -+ continue; -+ } else if (unlikely(!frag->node)) { -+ uint32_t holeend = min(end, frag->ofs + frag->size); -+ D1(printk(KERN_DEBUG "Filling frag hole from %d-%d (frag 0x%x 0x%x)\n", offset, holeend, frag->ofs, frag->ofs + frag->size)); -+ memset(buf, 0, holeend - offset); -+ buf += holeend - offset; -+ offset = holeend; -+ frag = frag_next(frag); -+ continue; -+ } else { -+ uint32_t readlen; -+ uint32_t fragofs; /* offset within the frag to start reading */ -+ -+ fragofs = offset - frag->ofs; -+ readlen = min(frag->size - fragofs, end - offset); -+ D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n", -+ frag->ofs+fragofs, frag->ofs+fragofs+readlen, -+ ref_offset(frag->node->raw), ref_flags(frag->node->raw))); -+ ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen); -+ D2(printk(KERN_DEBUG "node read done\n")); -+ if (ret) { -+ D1(printk(KERN_DEBUG"jffs2_read_inode_range error %d\n",ret)); -+ memset(buf, 0, readlen); -+ return ret; -+ } -+ buf += readlen; -+ offset += readlen; -+ frag = frag_next(frag); -+ D2(printk(KERN_DEBUG "node read was OK. Looping\n")); -+ } -+ } -+ return 0; -+} -+ -+/* Core function to read symlink target. */ -+char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f) -+{ -+ char *buf; -+ int ret; -+ -+ down(&f->sem); -+ -+ if (!f->metadata) { -+ printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino); -+ up(&f->sem); -+ return ERR_PTR(-EINVAL); -+ } -+ buf = kmalloc(f->metadata->size+1, GFP_USER); -+ if (!buf) { -+ up(&f->sem); -+ return ERR_PTR(-ENOMEM); -+ } -+ buf[f->metadata->size]=0; -+ -+ ret = jffs2_read_dnode(c, f->metadata, buf, 0, f->metadata->size); -+ -+ up(&f->sem); -+ -+ if (ret) { -+ kfree(buf); -+ return ERR_PTR(ret); -+ } -+ return buf; -+} -diff -Nurb linux-mips-2.4.27/fs/jffs2/readinode.c linux/fs/jffs2/readinode.c ---- linux-mips-2.4.27/fs/jffs2/readinode.c 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/readinode.c 2004-11-19 10:25:12.123165744 +0100 -@@ -1,79 +1,122 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - --/* Given an inode, probably with existing list of fragments, add the new node -- * to the fragment list. -- */ - #include <linux/kernel.h> - #include <linux/slab.h> - #include <linux/fs.h> -+#include <linux/crc32.h> -+#include <linux/pagemap.h> - #include <linux/mtd/mtd.h> --#include <linux/jffs2.h> -+#include <linux/compiler.h> - #include "nodelist.h" --#include <linux/crc32.h> - -+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); - --D1(void jffs2_print_frag_list(struct jffs2_inode_info *f) -+#if CONFIG_JFFS2_FS_DEBUG >= 1 -+static void jffs2_print_fragtree(struct rb_root *list, int permitbug) - { -- struct jffs2_node_frag *this = f->fraglist; -+ struct jffs2_node_frag *this = frag_first(list); -+ uint32_t lastofs = 0; -+ int buggy = 0; - - while(this) { - if (this->node) -- printk(KERN_DEBUG "frag %04x-%04x: 0x%08x on flash (*%p->%p)\n", this->ofs, this->ofs+this->size, this->node->raw->flash_offset &~3, this, this->next); -+ printk(KERN_DEBUG "frag %04x-%04x: 0x%08x(%d) on flash (*%p). left (%p), right (%p), parent (%p)\n", -+ this->ofs, this->ofs+this->size, ref_offset(this->node->raw), ref_flags(this->node->raw), -+ this, frag_left(this), frag_right(this), frag_parent(this)); - else -- printk(KERN_DEBUG "frag %04x-%04x: hole (*%p->%p)\n", this->ofs, this->ofs+this->size, this, this->next); -- this = this->next; -+ printk(KERN_DEBUG "frag %04x-%04x: hole (*%p). left (%p} right (%p), parent (%p)\n", this->ofs, -+ this->ofs+this->size, this, frag_left(this), frag_right(this), frag_parent(this)); -+ if (this->ofs != lastofs) -+ buggy = 1; -+ lastofs = this->ofs+this->size; -+ this = frag_next(this); -+ } -+ if (buggy && !permitbug) { -+ printk(KERN_CRIT "Frag tree got a hole in it\n"); -+ BUG(); - } -+} -+ -+void jffs2_print_frag_list(struct jffs2_inode_info *f) -+{ -+ jffs2_print_fragtree(&f->fragtree, 0); -+ - if (f->metadata) { -- printk(KERN_DEBUG "metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3); -+ printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); - } --}) -- -+} - --int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) -+static int jffs2_sanitycheck_fragtree(struct jffs2_inode_info *f) - { -- int ret; -- D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); -+ struct jffs2_node_frag *frag; -+ int bitched = 0; - -- ret = jffs2_add_full_dnode_to_fraglist(c, &f->fraglist, fn); -+ for (frag = frag_first(&f->fragtree); frag; frag = frag_next(frag)) { - -- D2(jffs2_print_frag_list(f)); -- return ret; -+ struct jffs2_full_dnode *fn = frag->node; -+ if (!fn || !fn->raw) -+ continue; -+ -+ if (ref_flags(fn->raw) == REF_PRISTINE) { -+ -+ if (fn->frags > 1) { -+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(fn->raw), fn->frags); -+ bitched = 1; -+ } -+ /* A hole node which isn't multi-page should be garbage-collected -+ and merged anyway, so we just check for the frag size here, -+ rather than mucking around with actually reading the node -+ and checking the compression type, which is the real way -+ to tell a hole node. */ -+ if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE && frag_prev(frag)->node) { -+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n", -+ ref_offset(fn->raw)); -+ bitched = 1; -+ } -+ -+ if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE && frag_next(frag)->node) { -+ printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n", -+ ref_offset(fn->raw), frag->ofs, frag->ofs+frag->size); -+ bitched = 1; -+ } -+ } -+ } -+ -+ if (bitched) { -+ struct jffs2_node_frag *thisfrag; -+ -+ printk(KERN_WARNING "Inode is #%u\n", f->inocache->ino); -+ thisfrag = frag_first(&f->fragtree); -+ while (thisfrag) { -+ if (!thisfrag->node) { -+ printk("Frag @0x%x-0x%x; node-less hole\n", -+ thisfrag->ofs, thisfrag->size + thisfrag->ofs); -+ } else if (!thisfrag->node->raw) { -+ printk("Frag @0x%x-0x%x; raw-less hole\n", -+ thisfrag->ofs, thisfrag->size + thisfrag->ofs); -+ } else { -+ printk("Frag @0x%x-0x%x; raw at 0x%08x(%d) (0x%x-0x%x)\n", -+ thisfrag->ofs, thisfrag->size + thisfrag->ofs, -+ ref_offset(thisfrag->node->raw), ref_flags(thisfrag->node->raw), -+ thisfrag->node->ofs, thisfrag->node->ofs+thisfrag->node->size); -+ } -+ thisfrag = frag_next(thisfrag); -+ } -+ } -+ return bitched; - } -+#endif /* D1 */ - - static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) - { -@@ -82,42 +125,38 @@ - if (!this->node->frags) { - /* The node has no valid frags left. It's totally obsoleted */ - D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) obsolete\n", -- this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size)); -+ ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size)); - jffs2_mark_node_obsolete(c, this->node->raw); - jffs2_free_full_dnode(this->node); - } else { -- D2(printk(KERN_DEBUG "Not marking old node @0x%08x (0x%04x-0x%04x) obsolete. frags is %d\n", -- this->node->raw->flash_offset &~3, this->node->ofs, this->node->ofs+this->node->size, -+ D2(printk(KERN_DEBUG "Marking old node @0x%08x (0x%04x-0x%04x) REF_NORMAL. frags is %d\n", -+ ref_offset(this->node->raw), this->node->ofs, this->node->ofs+this->node->size, - this->node->frags)); -+ mark_ref_normal(this->node->raw); - } - - } - jffs2_free_node_frag(this); - } - --/* Doesn't set inode->i_size */ --int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct jffs2_node_frag **list, struct jffs2_full_dnode *fn) -+/* Given an inode, probably with existing list of fragments, add the new node -+ * to the fragment list. -+ */ -+int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) - { -+ int ret; -+ struct jffs2_node_frag *newfrag; - -- struct jffs2_node_frag *this, **prev, *old; -- struct jffs2_node_frag *newfrag, *newfrag2; -- __u32 lastend = 0; -- -+ D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); - - newfrag = jffs2_alloc_node_frag(); -- if (!newfrag) { -+ if (unlikely(!newfrag)) - return -ENOMEM; -- } -- -- D2(if (fn->raw) -- printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, fn->raw->flash_offset &~3, newfrag); -- else -- printk(KERN_DEBUG "adding hole node %04x-%04x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, newfrag)); - -- prev = list; -- this = *list; -+ D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", -+ fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); - -- if (!fn->size) { -+ if (unlikely(!fn->size)) { - jffs2_free_node_frag(newfrag); - return 0; - } -@@ -126,176 +165,358 @@ - newfrag->size = fn->size; - newfrag->node = fn; - newfrag->node->frags = 1; -- newfrag->next = (void *)0xdeadbeef; -+ -+ ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); -+ if (ret) -+ return ret; -+ -+ /* If we now share a page with other nodes, mark either previous -+ or next node REF_NORMAL, as appropriate. */ -+ if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { -+ struct jffs2_node_frag *prev = frag_prev(newfrag); -+ -+ mark_ref_normal(fn->raw); -+ /* If we don't start at zero there's _always_ a previous */ -+ if (prev->node) -+ mark_ref_normal(prev->node->raw); -+ } -+ -+ if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { -+ struct jffs2_node_frag *next = frag_next(newfrag); -+ -+ if (next) { -+ mark_ref_normal(fn->raw); -+ if (next->node) -+ mark_ref_normal(next->node->raw); -+ } -+ } -+ D2(if (jffs2_sanitycheck_fragtree(f)) { -+ printk(KERN_WARNING "Just added node %04x-%04x @0x%08x on flash, newfrag *%p\n", -+ fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag); -+ return 0; -+ }) -+ D2(jffs2_print_frag_list(f)); -+ return 0; -+} -+ -+/* Doesn't set inode->i_size */ -+static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) -+{ -+ struct jffs2_node_frag *this; -+ uint32_t lastend; - - /* Skip all the nodes which are completed before this one starts */ -- while(this && fn->ofs >= this->ofs+this->size) { -- lastend = this->ofs + this->size; -+ this = jffs2_lookup_node_frag(list, newfrag->node->ofs); - -- D2(printk(KERN_DEBUG "j_a_f_d_t_f: skipping frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n", -- this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next)); -- prev = &this->next; -- this = this->next; -+ if (this) { -+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", -+ this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); -+ lastend = this->ofs + this->size; -+ } else { -+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave no frag\n")); -+ lastend = 0; - } - - /* See if we ran off the end of the list */ -- if (!this) { -+ if (lastend <= newfrag->ofs) { - /* We did */ -- if (lastend < fn->ofs) { -+ -+ /* Check if 'this' node was on the same page as the new node. -+ If so, both 'this' and the new node get marked REF_NORMAL so -+ the GC can take a look. -+ */ -+ if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { -+ if (this->node) -+ mark_ref_normal(this->node->raw); -+ mark_ref_normal(newfrag->node->raw); -+ } -+ -+ if (lastend < newfrag->node->ofs) { - /* ... and we need to put a hole in before the new node */ - struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); -- if (!holefrag) -+ if (!holefrag) { -+ jffs2_free_node_frag(newfrag); - return -ENOMEM; -+ } - holefrag->ofs = lastend; -- holefrag->size = fn->ofs - lastend; -- holefrag->next = NULL; -+ holefrag->size = newfrag->node->ofs - lastend; - holefrag->node = NULL; -- *prev = holefrag; -- prev = &holefrag->next; -+ if (this) { -+ /* By definition, the 'this' node has no right-hand child, -+ because there are no frags with offset greater than it. -+ So that's where we want to put the hole */ -+ D2(printk(KERN_DEBUG "Adding hole frag (%p) on right of node at (%p)\n", holefrag, this)); -+ rb_link_node(&holefrag->rb, &this->rb, &this->rb.rb_right); -+ } else { -+ D2(printk(KERN_DEBUG "Adding hole frag (%p) at root of tree\n", holefrag)); -+ rb_link_node(&holefrag->rb, NULL, &list->rb_node); -+ } -+ rb_insert_color(&holefrag->rb, list); -+ this = holefrag; - } -- newfrag->next = NULL; -- *prev = newfrag; -+ if (this) { -+ /* By definition, the 'this' node has no right-hand child, -+ because there are no frags with offset greater than it. -+ So that's where we want to put the hole */ -+ D2(printk(KERN_DEBUG "Adding new frag (%p) on right of node at (%p)\n", newfrag, this)); -+ rb_link_node(&newfrag->rb, &this->rb, &this->rb.rb_right); -+ } else { -+ D2(printk(KERN_DEBUG "Adding new frag (%p) at root of tree\n", newfrag)); -+ rb_link_node(&newfrag->rb, NULL, &list->rb_node); -+ } -+ rb_insert_color(&newfrag->rb, list); - return 0; - } - -- D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p->%p)\n", -- this->ofs, this->ofs+this->size, this->node?(this->node->raw->flash_offset &~3):0xffffffff, this, this->next)); -+ D2(printk(KERN_DEBUG "j_a_f_d_t_f: dealing with frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", -+ this->ofs, this->ofs+this->size, this->node?(ref_offset(this->node->raw)):0xffffffff, this)); - -- /* OK. 'this' is pointing at the first frag that fn->ofs at least partially obsoletes, -- * - i.e. fn->ofs < this->ofs+this->size && fn->ofs >= this->ofs -+ /* OK. 'this' is pointing at the first frag that newfrag->ofs at least partially obsoletes, -+ * - i.e. newfrag->ofs < this->ofs+this->size && newfrag->ofs >= this->ofs - */ -- if (fn->ofs > this->ofs) { -+ if (newfrag->ofs > this->ofs) { - /* This node isn't completely obsoleted. The start of it remains valid */ -- if (this->ofs + this->size > fn->ofs + fn->size) { -+ -+ /* Mark the new node and the partially covered node REF_NORMAL -- let -+ the GC take a look at them */ -+ mark_ref_normal(newfrag->node->raw); -+ if (this->node) -+ mark_ref_normal(this->node->raw); -+ -+ if (this->ofs + this->size > newfrag->ofs + newfrag->size) { - /* The new node splits 'this' frag into two */ -- newfrag2 = jffs2_alloc_node_frag(); -+ struct jffs2_node_frag *newfrag2 = jffs2_alloc_node_frag(); - if (!newfrag2) { - jffs2_free_node_frag(newfrag); - return -ENOMEM; - } -- D1(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); -+ D2(printk(KERN_DEBUG "split old frag 0x%04x-0x%04x -->", this->ofs, this->ofs+this->size); - if (this->node) -- printk("phys 0x%08x\n", this->node->raw->flash_offset &~3); -+ printk("phys 0x%08x\n", ref_offset(this->node->raw)); - else - printk("hole\n"); - ) -- newfrag2->ofs = fn->ofs + fn->size; -+ -+ /* New second frag pointing to this's node */ -+ newfrag2->ofs = newfrag->ofs + newfrag->size; - newfrag2->size = (this->ofs+this->size) - newfrag2->ofs; -- newfrag2->next = this->next; - newfrag2->node = this->node; - if (this->node) - this->node->frags++; -- newfrag->next = newfrag2; -- this->next = newfrag; -+ -+ /* Adjust size of original 'this' */ - this->size = newfrag->ofs - this->ofs; -+ -+ /* Now, we know there's no node with offset -+ greater than this->ofs but smaller than -+ newfrag2->ofs or newfrag->ofs, for obvious -+ reasons. So we can do a tree insert from -+ 'this' to insert newfrag, and a tree insert -+ from newfrag to insert newfrag2. */ -+ jffs2_fragtree_insert(newfrag, this); -+ rb_insert_color(&newfrag->rb, list); -+ -+ jffs2_fragtree_insert(newfrag2, newfrag); -+ rb_insert_color(&newfrag2->rb, list); -+ - return 0; - } - /* New node just reduces 'this' frag in size, doesn't split it */ -- this->size = fn->ofs - this->ofs; -- newfrag->next = this->next; -- this->next = newfrag; -- this = newfrag->next; -+ this->size = newfrag->ofs - this->ofs; -+ -+ /* Again, we know it lives down here in the tree */ -+ jffs2_fragtree_insert(newfrag, this); -+ rb_insert_color(&newfrag->rb, list); - } else { -- D2(printk(KERN_DEBUG "Inserting newfrag (*%p) in before 'this' (*%p)\n", newfrag, this)); -- *prev = newfrag; -- newfrag->next = this; -+ /* New frag starts at the same point as 'this' used to. Replace -+ it in the tree without doing a delete and insertion */ -+ D2(printk(KERN_DEBUG "Inserting newfrag (*%p),%d-%d in before 'this' (*%p),%d-%d\n", -+ newfrag, newfrag->ofs, newfrag->ofs+newfrag->size, -+ this, this->ofs, this->ofs+this->size)); -+ -+ rb_replace_node(&this->rb, &newfrag->rb, list); -+ -+ if (newfrag->ofs + newfrag->size >= this->ofs+this->size) { -+ D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x)\n", this, this->ofs, this->ofs+this->size)); -+ jffs2_obsolete_node_frag(c, this); -+ } else { -+ this->ofs += newfrag->size; -+ this->size -= newfrag->size; -+ -+ jffs2_fragtree_insert(this, newfrag); -+ rb_insert_color(&this->rb, list); -+ return 0; - } -- /* OK, now we have newfrag added in the correct place in the list, but -- newfrag->next points to a fragment which may be overlapping it -+ } -+ /* OK, now we have newfrag added in the correct place in the tree, but -+ frag_next(newfrag) may be a fragment which is overlapped by it - */ -- while (this && newfrag->ofs + newfrag->size >= this->ofs + this->size) { -- /* 'this' frag is obsoleted. */ -- old = this; -- this = old->next; -- jffs2_obsolete_node_frag(c, old); -+ while ((this = frag_next(newfrag)) && newfrag->ofs + newfrag->size >= this->ofs + this->size) { -+ /* 'this' frag is obsoleted completely. */ -+ D2(printk(KERN_DEBUG "Obsoleting node frag %p (%x-%x) and removing from tree\n", this, this->ofs, this->ofs+this->size)); -+ rb_erase(&this->rb, list); -+ jffs2_obsolete_node_frag(c, this); - } - /* Now we're pointing at the first frag which isn't totally obsoleted by - the new frag */ -- newfrag->next = this; - - if (!this || newfrag->ofs + newfrag->size == this->ofs) { - return 0; - } -- /* Still some overlap */ -+ /* Still some overlap but we don't need to move it in the tree */ - this->size = (this->ofs + this->size) - (newfrag->ofs + newfrag->size); - this->ofs = newfrag->ofs + newfrag->size; -+ -+ /* And mark them REF_NORMAL so the GC takes a look at them */ -+ if (this->node) -+ mark_ref_normal(this->node->raw); -+ mark_ref_normal(newfrag->node->raw); -+ - return 0; - } - --void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct jffs2_node_frag **list, __u32 size) -+void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size) - { -+ struct jffs2_node_frag *frag = jffs2_lookup_node_frag(list, size); -+ - D1(printk(KERN_DEBUG "Truncating fraglist to 0x%08x bytes\n", size)); - -- while (*list) { -- if ((*list)->ofs >= size) { -- struct jffs2_node_frag *this = *list; -- *list = this->next; -- D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", this->ofs, this->ofs+this->size)); -- jffs2_obsolete_node_frag(c, this); -- continue; -- } else if ((*list)->ofs + (*list)->size > size) { -- D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", (*list)->ofs, (*list)->ofs + (*list)->size)); -- (*list)->size = size - (*list)->ofs; -- } -- list = &(*list)->next; -+ /* We know frag->ofs <= size. That's what lookup does for us */ -+ if (frag && frag->ofs != size) { -+ if (frag->ofs+frag->size >= size) { -+ D1(printk(KERN_DEBUG "Truncating frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); -+ frag->size = size - frag->ofs; -+ } -+ frag = frag_next(frag); -+ } -+ while (frag && frag->ofs >= size) { -+ struct jffs2_node_frag *next = frag_next(frag); -+ -+ D1(printk(KERN_DEBUG "Removing frag 0x%08x-0x%08x\n", frag->ofs, frag->ofs+frag->size)); -+ frag_erase(frag, list); -+ jffs2_obsolete_node_frag(c, frag); -+ frag = next; - } - } - - /* Scan the list of all nodes present for this ino, build map of versions, etc. */ - --void jffs2_read_inode (struct inode *inode) -+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, -+ struct jffs2_inode_info *f, -+ struct jffs2_raw_inode *latest_node); -+ -+int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, -+ uint32_t ino, struct jffs2_raw_inode *latest_node) - { -- struct jffs2_tmp_dnode_info *tn_list, *tn; -- struct jffs2_full_dirent *fd_list; -- struct jffs2_inode_info *f; -- struct jffs2_full_dnode *fn = NULL; -- struct jffs2_sb_info *c; -- struct jffs2_raw_inode latest_node; -- __u32 latest_mctime, mctime_ver; -- __u32 mdata_ver = 0; -- int ret; -- ssize_t retlen; -+ D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n")); - -- D1(printk(KERN_DEBUG "jffs2_read_inode(): inode->i_ino == %lu\n", inode->i_ino)); -+ retry_inocache: -+ spin_lock(&c->inocache_lock); -+ f->inocache = jffs2_get_ino_cache(c, ino); -+ -+ D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache)); -+ -+ if (f->inocache) { -+ /* Check its state. We may need to wait before we can use it */ -+ switch(f->inocache->state) { -+ case INO_STATE_UNCHECKED: -+ case INO_STATE_CHECKEDABSENT: -+ f->inocache->state = INO_STATE_READING; -+ break; - -- f = JFFS2_INODE_INFO(inode); -- c = JFFS2_SB_INFO(inode->i_sb); -+ case INO_STATE_CHECKING: -+ case INO_STATE_GC: -+ /* If it's in either of these states, we need -+ to wait for whoever's got it to finish and -+ put it back. */ -+ D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n", -+ ino, f->inocache->state)); -+ sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); -+ goto retry_inocache; -+ -+ case INO_STATE_READING: -+ case INO_STATE_PRESENT: -+ /* Eep. This should never happen. It can -+ happen if Linux calls read_inode() again -+ before clear_inode() has finished though. */ -+ printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); -+ /* Fail. That's probably better than allowing it to succeed */ -+ f->inocache = NULL; -+ break; - -- memset(f, 0, sizeof(*f)); -- D2(printk(KERN_DEBUG "getting inocache\n")); -- init_MUTEX(&f->sem); -- f->inocache = jffs2_get_ino_cache(c, inode->i_ino); -- D2(printk(KERN_DEBUG "jffs2_read_inode(): Got inocache at %p\n", f->inocache)); -+ default: -+ BUG(); -+ } -+ } -+ spin_unlock(&c->inocache_lock); - -- if (!f->inocache && inode->i_ino == 1) { -+ if (!f->inocache && ino == 1) { - /* Special case - no root inode on medium */ - f->inocache = jffs2_alloc_inode_cache(); - if (!f->inocache) { -- printk(KERN_CRIT "jffs2_read_inode(): Cannot allocate inocache for root inode\n"); -- make_bad_inode(inode); -- return; -+ printk(KERN_CRIT "jffs2_do_read_inode(): Cannot allocate inocache for root inode\n"); -+ return -ENOMEM; - } -- D1(printk(KERN_DEBUG "jffs2_read_inode(): Creating inocache for root inode\n")); -+ D1(printk(KERN_DEBUG "jffs2_do_read_inode(): Creating inocache for root inode\n")); - memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); - f->inocache->ino = f->inocache->nlink = 1; - f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; -+ f->inocache->state = INO_STATE_READING; - jffs2_add_ino_cache(c, f->inocache); - } - if (!f->inocache) { -- printk(KERN_WARNING "jffs2_read_inode() on nonexistent ino %lu\n", (unsigned long)inode->i_ino); -- make_bad_inode(inode); -- return; -+ printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino); -+ return -ENOENT; - } -- D1(printk(KERN_DEBUG "jffs2_read_inode(): ino #%lu nlink is %d\n", (unsigned long)inode->i_ino, f->inocache->nlink)); -- inode->i_nlink = f->inocache->nlink; -+ -+ return jffs2_do_read_inode_internal(c, f, latest_node); -+} -+ -+int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) -+{ -+ struct jffs2_raw_inode n; -+ struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); -+ int ret; -+ -+ if (!f) -+ return -ENOMEM; -+ -+ memset(f, 0, sizeof(*f)); -+ init_MUTEX_LOCKED(&f->sem); -+ f->inocache = ic; -+ -+ ret = jffs2_do_read_inode_internal(c, f, &n); -+ if (!ret) { -+ up(&f->sem); -+ jffs2_do_clear_inode(c, f); -+ } -+ kfree (f); -+ return ret; -+} -+ -+static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, -+ struct jffs2_inode_info *f, -+ struct jffs2_raw_inode *latest_node) -+{ -+ struct jffs2_tmp_dnode_info *tn_list, *tn; -+ struct jffs2_full_dirent *fd_list; -+ struct jffs2_full_dnode *fn = NULL; -+ uint32_t crc; -+ uint32_t latest_mctime, mctime_ver; -+ uint32_t mdata_ver = 0; -+ size_t retlen; -+ int ret; -+ -+ D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink)); - - /* Grab all nodes relevant to this ino */ -- ret = jffs2_get_inode_nodes(c, inode->i_ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); -+ ret = jffs2_get_inode_nodes(c, f->inocache->ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); - - if (ret) { -- printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %lu returned %d\n", inode->i_ino, ret); -- make_bad_inode(inode); -- return; -+ printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret); -+ if (f->inocache->state == INO_STATE_READING) -+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); -+ return ret; - } - f->dents = fd_list; - -@@ -304,205 +525,169 @@ - - fn = tn->fn; - -- if (f->metadata && tn->version > mdata_ver) { -- D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", f->metadata->raw->flash_offset &~3)); -+ if (f->metadata) { -+ if (likely(tn->version >= mdata_ver)) { -+ D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - - mdata_ver = 0; -+ } else { -+ /* This should never happen. */ -+ printk(KERN_WARNING "Er. New metadata at 0x%08x with ver %d is actually older than previous ver %d at 0x%08x\n", -+ ref_offset(fn->raw), tn->version, mdata_ver, ref_offset(f->metadata->raw)); -+ jffs2_mark_node_obsolete(c, fn->raw); -+ jffs2_free_full_dnode(fn); -+ /* Fill in latest_node from the metadata, not this one we're about to free... */ -+ fn = f->metadata; -+ goto next_tn; -+ } - } - - if (fn->size) { - jffs2_add_full_dnode_to_inode(c, f, fn); - } else { - /* Zero-sized node at end of version list. Just a metadata update */ -- D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", fn->raw->flash_offset &~3, tn->version)); -+ D1(printk(KERN_DEBUG "metadata @%08x: ver %d\n", ref_offset(fn->raw), tn->version)); - f->metadata = fn; - mdata_ver = tn->version; - } -+ next_tn: - tn_list = tn->next; - jffs2_free_tmp_dnode_info(tn); - } -+ D1(jffs2_sanitycheck_fragtree(f)); -+ - if (!fn) { - /* No data nodes for this inode. */ -- if (inode->i_ino != 1) { -- printk(KERN_WARNING "jffs2_read_inode(): No data nodes found for ino #%lu\n", inode->i_ino); -+ if (f->inocache->ino != 1) { -+ printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino); - if (!fd_list) { -- make_bad_inode(inode); -- return; -- } -- printk(KERN_WARNING "jffs2_read_inode(): But it has children so we fake some modes for it\n"); -+ if (f->inocache->state == INO_STATE_READING) -+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); -+ return -EIO; -+ } -+ printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n"); -+ } -+ latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); -+ latest_node->version = cpu_to_je32(0); -+ latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0); -+ latest_node->isize = cpu_to_je32(0); -+ latest_node->gid = cpu_to_je16(0); -+ latest_node->uid = cpu_to_je16(0); -+ if (f->inocache->state == INO_STATE_READING) -+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); -+ return 0; - } -- inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO; -- latest_node.version = 0; -- inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; -- inode->i_nlink = f->inocache->nlink; -- inode->i_size = 0; -- } else { -- __u32 crc; - -- ret = c->mtd->read(c->mtd, fn->raw->flash_offset & ~3, sizeof(latest_node), &retlen, (void *)&latest_node); -- if (ret || retlen != sizeof(latest_node)) { -- printk(KERN_NOTICE "MTD read in jffs2_read_inode() failed: Returned %d, %ld of %d bytes read\n", -- ret, (long)retlen, sizeof(latest_node)); -- jffs2_clear_inode(inode); -- make_bad_inode(inode); -- return; -- } -- -- crc = crc32(0, &latest_node, sizeof(latest_node)-8); -- if (crc != latest_node.node_crc) { -- printk(KERN_NOTICE "CRC failed for read_inode of inode %ld at physical location 0x%x\n", inode->i_ino, fn->raw->flash_offset & ~3); -- jffs2_clear_inode(inode); -- make_bad_inode(inode); -- return; -- } -- -- inode->i_mode = latest_node.mode; -- inode->i_uid = latest_node.uid; -- inode->i_gid = latest_node.gid; -- inode->i_size = latest_node.isize; -- if (S_ISREG(inode->i_mode)) -- jffs2_truncate_fraglist(c, &f->fraglist, latest_node.isize); -- inode->i_atime = latest_node.atime; -- inode->i_mtime = latest_node.mtime; -- inode->i_ctime = latest_node.ctime; -- } -- -- /* OK, now the special cases. Certain inode types should -- have only one data node, and it's kept as the metadata -- node */ -- if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode) || -- S_ISLNK(inode->i_mode)) { -- if (f->metadata) { -- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had metadata node\n", inode->i_ino, inode->i_mode); -- jffs2_clear_inode(inode); -- make_bad_inode(inode); -- return; -- } -- if (!f->fraglist) { -- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o has no fragments\n", inode->i_ino, inode->i_mode); -- jffs2_clear_inode(inode); -- make_bad_inode(inode); -- return; -- } -- /* ASSERT: f->fraglist != NULL */ -- if (f->fraglist->next) { -- printk(KERN_WARNING "Argh. Special inode #%lu with mode 0%o had more than one node\n", inode->i_ino, inode->i_mode); -- /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ -- jffs2_clear_inode(inode); -- make_bad_inode(inode); -- return; -- } -- /* OK. We're happy */ -- f->metadata = f->fraglist->node; -- jffs2_free_node_frag(f->fraglist); -- f->fraglist = NULL; -+ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); -+ if (ret || retlen != sizeof(*latest_node)) { -+ printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n", -+ ret, retlen, sizeof(*latest_node)); -+ /* FIXME: If this fails, there seems to be a memory leak. Find it. */ -+ up(&f->sem); -+ jffs2_do_clear_inode(c, f); -+ return ret?ret:-EIO; - } - -- inode->i_blksize = PAGE_SIZE; -- inode->i_blocks = (inode->i_size + 511) >> 9; -- -- switch (inode->i_mode & S_IFMT) { -- unsigned short rdev; -- -- case S_IFLNK: -- inode->i_op = &jffs2_symlink_inode_operations; -- /* Hack to work around broken isize in old symlink code. -- Remove this when dwmw2 comes to his senses and stops -- symlinks from being an entirely gratuitous special -- case. */ -- if (!inode->i_size) -- inode->i_size = latest_node.dsize; -- break; -+ crc = crc32(0, latest_node, sizeof(*latest_node)-8); -+ if (crc != je32_to_cpu(latest_node->node_crc)) { -+ printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw)); -+ up(&f->sem); -+ jffs2_do_clear_inode(c, f); -+ return -EIO; -+ } - -+ switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { - case S_IFDIR: -- if (mctime_ver > latest_node.version) { -+ if (mctime_ver > je32_to_cpu(latest_node->version)) { - /* The times in the latest_node are actually older than - mctime in the latest dirent. Cheat. */ -- inode->i_mtime = inode->i_ctime = inode->i_atime = -- latest_mctime; -+ latest_node->ctime = latest_node->mtime = cpu_to_je32(latest_mctime); - } -- inode->i_op = &jffs2_dir_inode_operations; -- inode->i_fop = &jffs2_dir_operations; - break; - -+ - case S_IFREG: -- inode->i_op = &jffs2_file_inode_operations; -- inode->i_fop = &jffs2_file_operations; -- inode->i_mapping->a_ops = &jffs2_file_address_operations; -- inode->i_mapping->nrpages = 0; -+ /* If it was a regular file, truncate it to the latest node's isize */ -+ jffs2_truncate_fraglist(c, &f->fragtree, je32_to_cpu(latest_node->isize)); - break; - -+ case S_IFLNK: -+ /* Hack to work around broken isize in old symlink code. -+ Remove this when dwmw2 comes to his senses and stops -+ symlinks from being an entirely gratuitous special -+ case. */ -+ if (!je32_to_cpu(latest_node->isize)) -+ latest_node->isize = latest_node->dsize; -+ /* fall through... */ -+ - case S_IFBLK: - case S_IFCHR: -- /* Read the device numbers from the media */ -- D1(printk(KERN_DEBUG "Reading device numbers from flash\n")); -- if (jffs2_read_dnode(c, f->metadata, (char *)&rdev, 0, sizeof(rdev)) < 0) { -- /* Eep */ -- printk(KERN_NOTICE "Read device numbers for inode %lu failed\n", (unsigned long)inode->i_ino); -- jffs2_clear_inode(inode); -- make_bad_inode(inode); -- return; -+ /* Certain inode types should have only one data node, and it's -+ kept as the metadata node */ -+ if (f->metadata) { -+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", -+ f->inocache->ino, jemode_to_cpu(latest_node->mode)); -+ up(&f->sem); -+ jffs2_do_clear_inode(c, f); -+ return -EIO; - } -- -- case S_IFSOCK: -- case S_IFIFO: -- inode->i_op = &jffs2_file_inode_operations; -- init_special_inode(inode, inode->i_mode, kdev_t_to_nr(MKDEV(rdev>>8, rdev&0xff))); -+ if (!frag_first(&f->fragtree)) { -+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", -+ f->inocache->ino, jemode_to_cpu(latest_node->mode)); -+ up(&f->sem); -+ jffs2_do_clear_inode(c, f); -+ return -EIO; -+ } -+ /* ASSERT: f->fraglist != NULL */ -+ if (frag_next(frag_first(&f->fragtree))) { -+ printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n", -+ f->inocache->ino, jemode_to_cpu(latest_node->mode)); -+ /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ -+ up(&f->sem); -+ jffs2_do_clear_inode(c, f); -+ return -EIO; -+ } -+ /* OK. We're happy */ -+ f->metadata = frag_first(&f->fragtree)->node; -+ jffs2_free_node_frag(frag_first(&f->fragtree)); -+ f->fragtree = RB_ROOT; - break; -- -- default: -- printk(KERN_WARNING "jffs2_read_inode(): Bogus imode %o for ino %lu", inode->i_mode, (unsigned long)inode->i_ino); - } -- D1(printk(KERN_DEBUG "jffs2_read_inode() returning\n")); -+ if (f->inocache->state == INO_STATE_READING) -+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); -+ -+ return 0; - } - --void jffs2_clear_inode (struct inode *inode) -+void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f) - { -- /* We can forget about this inode for now - drop all -- * the nodelists associated with it, etc. -- */ -- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -- struct jffs2_node_frag *frag, *frags; - struct jffs2_full_dirent *fd, *fds; -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - int deleted; - -- D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); -- - down(&f->sem); - deleted = f->inocache && !f->inocache->nlink; - -- frags = f->fraglist; -- fds = f->dents; - if (f->metadata) { - if (deleted) - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - } - -- while (frags) { -- frag = frags; -- frags = frag->next; -- D2(printk(KERN_DEBUG "jffs2_clear_inode: frag at 0x%x-0x%x: node %p, frags %d--\n", frag->ofs, frag->ofs+frag->size, frag->node, frag->node?frag->node->frags:0)); -+ jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL); - -- if (frag->node && !(--frag->node->frags)) { -- /* Not a hole, and it's the final remaining frag of this node. Free the node */ -- if (deleted) -- jffs2_mark_node_obsolete(c, frag->node->raw); -+ fds = f->dents; - -- jffs2_free_full_dnode(frag->node); -- } -- jffs2_free_node_frag(frag); -- } - while(fds) { - fd = fds; - fds = fd->next; - jffs2_free_full_dirent(fd); - } - -- up(&f->sem); --}; -+ if (f->inocache && f->inocache->state != INO_STATE_CHECKING) -+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); - -+ up(&f->sem); -+} -diff -Nurb linux-mips-2.4.27/fs/jffs2/scan.c linux/fs/jffs2/scan.c ---- linux-mips-2.4.27/fs/jffs2/scan.c 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/scan.c 2004-11-19 10:25:12.124165592 +0100 -@@ -1,47 +1,25 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - #include <linux/kernel.h> -+#include <linux/sched.h> - #include <linux/slab.h> --#include <linux/jffs2.h> - #include <linux/mtd/mtd.h> - #include <linux/pagemap.h> --#include "nodelist.h" - #include <linux/crc32.h> -+#include <linux/compiler.h> -+#include "nodelist.h" - -+#define EMPTY_SCAN_SIZE 1024 - - #define DIRTY_SPACE(x) do { typeof(x) _x = (x); \ - c->free_size -= _x; c->dirty_size += _x; \ -@@ -51,6 +29,10 @@ - c->free_size -= _x; c->used_size += _x; \ - jeb->free_size -= _x ; jeb->used_size += _x; \ - }while(0) -+#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \ -+ c->free_size -= _x; c->unchecked_size += _x; \ -+ jeb->free_size -= _x ; jeb->unchecked_size += _x; \ -+ }while(0) - - #define noisy_printk(noise, args...) do { \ - if (*(noise)) { \ -@@ -63,39 +45,84 @@ - } while(0) - - static uint32_t pseudo_random; --static void jffs2_rotate_lists(struct jffs2_sb_info *c); - --static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); -+static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -+ unsigned char *buf, uint32_t buf_size); - - /* These helper functions _must_ increase ofs and also do the dirty/used space accounting. - * Returning an error will abort the mount - bad checksums etc. should just mark the space - * as dirty. - */ --static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs, int *noise); --static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs); --static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs); -+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -+ struct jffs2_raw_inode *ri, uint32_t ofs); -+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -+ struct jffs2_raw_dirent *rd, uint32_t ofs); -+ -+#define BLK_STATE_ALLFF 0 -+#define BLK_STATE_CLEAN 1 -+#define BLK_STATE_PARTDIRTY 2 -+#define BLK_STATE_CLEANMARKER 3 -+#define BLK_STATE_ALLDIRTY 4 -+#define BLK_STATE_BADBLOCK 5 - -+static inline int min_free(struct jffs2_sb_info *c) -+{ -+ uint32_t min = 2 * sizeof(struct jffs2_raw_inode); -+#ifdef CONFIG_JFFS2_FS_NAND -+ if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) -+ return c->wbuf_pagesize; -+#endif -+ return min; - -+} - int jffs2_scan_medium(struct jffs2_sb_info *c) - { - int i, ret; -- __u32 empty_blocks = 0; -- -- if (!c->blocks) { -- printk(KERN_WARNING "EEEK! c->blocks is NULL!\n"); -- return -EINVAL; -+ uint32_t empty_blocks = 0, bad_blocks = 0; -+ unsigned char *flashbuf = NULL; -+ uint32_t buf_size = 0; -+#ifndef __ECOS -+ size_t pointlen; -+ -+ if (c->mtd->point) { -+ ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf); -+ if (!ret && pointlen < c->mtd->size) { -+ /* Don't muck about if it won't let us point to the whole flash */ -+ D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); -+ c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); -+ flashbuf = NULL; -+ } -+ if (ret) -+ D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); -+ } -+#endif -+ if (!flashbuf) { -+ /* For NAND it's quicker to read a whole eraseblock at a time, -+ apparently */ -+ if (jffs2_cleanmarker_oob(c)) -+ buf_size = c->sector_size; -+ else -+ buf_size = PAGE_SIZE; -+ -+ D1(printk(KERN_DEBUG "Allocating readbuf of %d bytes\n", buf_size)); -+ flashbuf = kmalloc(buf_size, GFP_KERNEL); -+ if (!flashbuf) -+ return -ENOMEM; - } -+ - for (i=0; i<c->nr_blocks; i++) { - struct jffs2_eraseblock *jeb = &c->blocks[i]; - -- ret = jffs2_scan_eraseblock(c, jeb); -+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset), buf_size); -+ - if (ret < 0) -- return ret; -+ goto out; - - ACCT_PARANOIA_CHECK(jeb); - - /* Now decide which list to put it on */ -- if (ret == 1) { -+ switch(ret) { -+ case BLK_STATE_ALLFF: - /* - * Empty block. Since we can't be sure it - * was entirely erased, we just queue it for erase -@@ -103,10 +130,12 @@ - * is complete. Meanwhile we still count it as empty - * for later checks. - */ -- list_add(&jeb->list, &c->erase_pending_list); - empty_blocks++; -+ list_add(&jeb->list, &c->erase_pending_list); - c->nr_erasing_blocks++; -- } else if (jeb->used_size == PAD(sizeof(struct jffs2_unknown_node)) && !jeb->first_node->next_in_ino) { -+ break; -+ -+ case BLK_STATE_CLEANMARKER: - /* Only a CLEANMARKER node is valid */ - if (!jeb->dirty_size) { - /* It's actually free */ -@@ -118,74 +147,227 @@ - list_add(&jeb->list, &c->erase_pending_list); - c->nr_erasing_blocks++; - } -- } else if (jeb->used_size > c->sector_size - (2*sizeof(struct jffs2_raw_inode))) { -+ break; -+ -+ case BLK_STATE_CLEAN: - /* Full (or almost full) of clean data. Clean list */ - list_add(&jeb->list, &c->clean_list); -- } else if (jeb->used_size) { -+ break; -+ -+ case BLK_STATE_PARTDIRTY: - /* Some data, but not full. Dirty list. */ - /* Except that we want to remember the block with most free space, - and stick it in the 'nextblock' position to start writing to it. - Later when we do snapshots, this must be the most recent block, - not the one with most free space. - */ -- if (jeb->free_size > 2*sizeof(struct jffs2_raw_inode) && -+ if (jeb->free_size > min_free(c) && - (!c->nextblock || c->nextblock->free_size < jeb->free_size)) { - /* Better candidate for the next writes to go to */ -- if (c->nextblock) -+ if (c->nextblock) { -+ c->nextblock->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; -+ c->dirty_size += c->nextblock->free_size + c->nextblock->wasted_size; -+ c->free_size -= c->nextblock->free_size; -+ c->wasted_size -= c->nextblock->wasted_size; -+ c->nextblock->free_size = c->nextblock->wasted_size = 0; -+ if (VERYDIRTY(c, c->nextblock->dirty_size)) { -+ list_add(&c->nextblock->list, &c->very_dirty_list); -+ } else { - list_add(&c->nextblock->list, &c->dirty_list); -+ } -+ } - c->nextblock = jeb; - } else { -+ jeb->dirty_size += jeb->free_size + jeb->wasted_size; -+ c->dirty_size += jeb->free_size + jeb->wasted_size; -+ c->free_size -= jeb->free_size; -+ c->wasted_size -= jeb->wasted_size; -+ jeb->free_size = jeb->wasted_size = 0; -+ if (VERYDIRTY(c, jeb->dirty_size)) { -+ list_add(&jeb->list, &c->very_dirty_list); -+ } else { - list_add(&jeb->list, &c->dirty_list); - } -- } else { -+ } -+ break; -+ -+ case BLK_STATE_ALLDIRTY: - /* Nothing valid - not even a clean marker. Needs erasing. */ - /* For now we just put it on the erasing list. We'll start the erases later */ -- printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset); -+ D1(printk(KERN_NOTICE "JFFS2: Erase block at 0x%08x is not formatted. It will be erased\n", jeb->offset)); - list_add(&jeb->list, &c->erase_pending_list); - c->nr_erasing_blocks++; -+ break; -+ -+ case BLK_STATE_BADBLOCK: -+ D1(printk(KERN_NOTICE "JFFS2: Block at 0x%08x is bad\n", jeb->offset)); -+ list_add(&jeb->list, &c->bad_list); -+ c->bad_size += c->sector_size; -+ c->free_size -= c->sector_size; -+ bad_blocks++; -+ break; -+ default: -+ printk(KERN_WARNING "jffs2_scan_medium(): unknown block state\n"); -+ BUG(); - } - } -- /* Rotate the lists by some number to ensure wear levelling */ -- jffs2_rotate_lists(c); - -+ /* Nextblock dirty is always seen as wasted, because we cannot recycle it now */ -+ if (c->nextblock && (c->nextblock->dirty_size)) { -+ c->nextblock->wasted_size += c->nextblock->dirty_size; -+ c->wasted_size += c->nextblock->dirty_size; -+ c->dirty_size -= c->nextblock->dirty_size; -+ c->nextblock->dirty_size = 0; -+ } -+#ifdef CONFIG_JFFS2_FS_NAND -+ if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) { -+ /* If we're going to start writing into a block which already -+ contains data, and the end of the data isn't page-aligned, -+ skip a little and align it. */ -+ -+ uint32_t skip = c->nextblock->free_size & (c->wbuf_pagesize-1); -+ -+ D1(printk(KERN_DEBUG "jffs2_scan_medium(): Skipping %d bytes in nextblock to ensure page alignment\n", -+ skip)); -+ c->nextblock->wasted_size += skip; -+ c->wasted_size += skip; -+ -+ c->nextblock->free_size -= skip; -+ c->free_size -= skip; -+ } -+#endif - if (c->nr_erasing_blocks) { -- if (!c->used_size && empty_blocks != c->nr_blocks) { -+ if ( !c->used_size && ((empty_blocks+bad_blocks)!= c->nr_blocks || bad_blocks == c->nr_blocks) ) { - printk(KERN_NOTICE "Cowardly refusing to erase blocks on filesystem with no valid JFFS2 nodes\n"); -- return -EIO; -+ printk(KERN_NOTICE "empty_blocks %d, bad_blocks %d, c->nr_blocks %d\n",empty_blocks,bad_blocks,c->nr_blocks); -+ ret = -EIO; -+ goto out; - } - jffs2_erase_pending_trigger(c); - } -+ ret = 0; -+ out: -+ if (buf_size) -+ kfree(flashbuf); -+#ifndef __ECOS -+ else -+ c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); -+#endif -+ return ret; -+} -+ -+static int jffs2_fill_scan_buf (struct jffs2_sb_info *c, unsigned char *buf, -+ uint32_t ofs, uint32_t len) -+{ -+ int ret; -+ size_t retlen; -+ -+ ret = jffs2_flash_read(c, ofs, len, &retlen, buf); -+ if (ret) { -+ D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", len, ofs, ret)); -+ return ret; -+ } -+ if (retlen < len) { -+ D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen)); -+ return -EIO; -+ } -+ D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs)); -+ D2(printk(KERN_DEBUG "000: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", -+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15])); - return 0; - } - --static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { -- struct jffs2_unknown_node node; -- __u32 ofs, prevofs; -- __u32 hdr_crc, nodetype; -+static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -+ unsigned char *buf, uint32_t buf_size) { -+ struct jffs2_unknown_node *node; -+ struct jffs2_unknown_node crcnode; -+ uint32_t ofs, prevofs; -+ uint32_t hdr_crc, buf_ofs, buf_len; - int err; - int noise = 0; -+ int wasempty = 0; -+ uint32_t empty_start = 0; -+#ifdef CONFIG_JFFS2_FS_NAND -+ int cleanmarkerfound = 0; -+#endif - - ofs = jeb->offset; - prevofs = jeb->offset - 1; - - D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs)); - -- err = jffs2_scan_empty(c, jeb, &ofs, &noise); -- if (err) return err; -- if (ofs == jeb->offset + c->sector_size) { -+#ifdef CONFIG_JFFS2_FS_NAND -+ if (jffs2_cleanmarker_oob(c)) { -+ int ret = jffs2_check_nand_cleanmarker(c, jeb); -+ D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret)); -+ /* Even if it's not found, we still scan to see -+ if the block is empty. We use this information -+ to decide whether to erase it or not. */ -+ switch (ret) { -+ case 0: cleanmarkerfound = 1; break; -+ case 1: break; -+ case 2: return BLK_STATE_BADBLOCK; -+ case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */ -+ default: return ret; -+ } -+ } -+#endif -+ buf_ofs = jeb->offset; -+ -+ if (!buf_size) { -+ buf_len = c->sector_size; -+ } else { -+ buf_len = EMPTY_SCAN_SIZE; -+ err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len); -+ if (err) -+ return err; -+ } -+ -+ /* We temporarily use 'ofs' as a pointer into the buffer/jeb */ -+ ofs = 0; -+ -+ /* Scan only 4KiB of 0xFF before declaring it's empty */ -+ while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF) -+ ofs += 4; -+ -+ if (ofs == EMPTY_SCAN_SIZE) { -+#ifdef CONFIG_JFFS2_FS_NAND -+ if (jffs2_cleanmarker_oob(c)) { -+ /* scan oob, take care of cleanmarker */ -+ int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound); -+ D2(printk(KERN_NOTICE "jffs2_check_oob_empty returned %d\n",ret)); -+ switch (ret) { -+ case 0: return cleanmarkerfound ? BLK_STATE_CLEANMARKER : BLK_STATE_ALLFF; -+ case 1: return BLK_STATE_ALLDIRTY; -+ case 2: return BLK_STATE_BADBLOCK; /* case 2/3 are paranoia checks */ -+ case 3: return BLK_STATE_ALLDIRTY; /* Block has failed to erase min. once */ -+ default: return ret; -+ } -+ } -+#endif - D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); -- return 1; /* special return code */ -+ return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ -+ } -+ if (ofs) { -+ D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset, -+ jeb->offset + ofs)); -+ DIRTY_SPACE(ofs); - } - -+ /* Now ofs is a complete physical flash offset as it always was... */ -+ ofs += jeb->offset; -+ - noise = 10; - - while(ofs < jeb->offset + c->sector_size) { -- ssize_t retlen; -- ACCT_PARANOIA_CHECK(jeb); -+ -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ -+ cond_resched(); - - if (ofs & 3) { - printk(KERN_WARNING "Eep. ofs 0x%08x not word-aligned!\n", ofs); -- ofs = (ofs+3)&~3; -+ ofs = PAD(ofs); - continue; - } - if (ofs == prevofs) { -@@ -196,102 +378,173 @@ - } - prevofs = ofs; - -- if (jeb->offset + c->sector_size < ofs + sizeof(node)) { -- D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. Not reading\n", sizeof(struct jffs2_unknown_node))); -+ if (jeb->offset + c->sector_size < ofs + sizeof(*node)) { -+ D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node), -+ jeb->offset, c->sector_size, ofs, sizeof(*node))); - DIRTY_SPACE((jeb->offset + c->sector_size)-ofs); - break; - } - -- err = c->mtd->read(c->mtd, ofs, sizeof(node), &retlen, (char *)&node); -- -- if (err) { -- D1(printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%x) returned %d\n", sizeof(node), ofs, err)); -+ if (buf_ofs + buf_len < ofs + sizeof(*node)) { -+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); -+ D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n", -+ sizeof(struct jffs2_unknown_node), buf_len, ofs)); -+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); -+ if (err) - return err; -+ buf_ofs = ofs; - } -- if (retlen < sizeof(node)) { -- D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen)); -- DIRTY_SPACE(retlen); -- ofs += retlen; -- continue; -+ -+ node = (struct jffs2_unknown_node *)&buf[ofs-buf_ofs]; -+ -+ if (*(uint32_t *)(&buf[ofs-buf_ofs]) == 0xffffffff) { -+ uint32_t inbuf_ofs = ofs - buf_ofs + 4; -+ uint32_t scanend; -+ -+ empty_start = ofs; -+ ofs += 4; -+ -+ /* If scanning empty space after only a cleanmarker, don't -+ bother scanning the whole block */ -+ if (unlikely(empty_start == jeb->offset + c->cleanmarker_size && -+ jeb->offset + EMPTY_SCAN_SIZE < buf_ofs + buf_len)) -+ scanend = jeb->offset + EMPTY_SCAN_SIZE - buf_ofs; -+ else -+ scanend = buf_len; -+ -+ D1(printk(KERN_DEBUG "Found empty flash at 0x%08x\n", ofs)); -+ while (inbuf_ofs < scanend) { -+ if (*(uint32_t *)(&buf[inbuf_ofs]) != 0xffffffff) -+ goto emptyends; -+ -+ inbuf_ofs+=4; -+ ofs += 4; - } -+ /* Ran off end. */ -+ D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs)); - -- if (node.magic == JFFS2_EMPTY_BITMASK && node.nodetype == JFFS2_EMPTY_BITMASK) { -- D1(printk(KERN_DEBUG "Found empty flash at 0x%x\n", ofs)); -- err = jffs2_scan_empty(c, jeb, &ofs, &noise); -- if (err) return err; -+ if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && -+ c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size) -+ return BLK_STATE_CLEANMARKER; -+ wasempty = 1; -+ continue; -+ } else if (wasempty) { -+ emptyends: -+ printk(KERN_WARNING "Empty flash at 0x%08x ends at 0x%08x\n", empty_start, ofs); -+ DIRTY_SPACE(ofs-empty_start); -+ wasempty = 0; - continue; - } - -- if (ofs == jeb->offset && node.magic == KSAMTIB_CIGAM_2SFFJ) { -+ if (ofs == jeb->offset && je16_to_cpu(node->magic) == KSAMTIB_CIGAM_2SFFJ) { - printk(KERN_WARNING "Magic bitmask is backwards at offset 0x%08x. Wrong endian filesystem?\n", ofs); - DIRTY_SPACE(4); - ofs += 4; - continue; - } -- if (node.magic == JFFS2_DIRTY_BITMASK) { -- D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs)); -+ if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) { -+ D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs)); - DIRTY_SPACE(4); - ofs += 4; - continue; - } -- if (node.magic == JFFS2_OLD_MAGIC_BITMASK) { -+ if (je16_to_cpu(node->magic) == JFFS2_OLD_MAGIC_BITMASK) { - printk(KERN_WARNING "Old JFFS2 bitmask found at 0x%08x\n", ofs); - printk(KERN_WARNING "You cannot use older JFFS2 filesystems with newer kernels\n"); - DIRTY_SPACE(4); - ofs += 4; - continue; - } -- if (node.magic != JFFS2_MAGIC_BITMASK) { -+ if (je16_to_cpu(node->magic) != JFFS2_MAGIC_BITMASK) { - /* OK. We're out of possibilities. Whinge and move on */ -- noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", JFFS2_MAGIC_BITMASK, ofs, node.magic); -+ noisy_printk(&noise, "jffs2_scan_eraseblock(): Magic bitmask 0x%04x not found at 0x%08x: 0x%04x instead\n", -+ JFFS2_MAGIC_BITMASK, ofs, -+ je16_to_cpu(node->magic)); - DIRTY_SPACE(4); - ofs += 4; - continue; - } - /* We seem to have a node of sorts. Check the CRC */ -- nodetype = node.nodetype; -- node.nodetype |= JFFS2_NODE_ACCURATE; -- hdr_crc = crc32(0, &node, sizeof(node)-4); -- node.nodetype = nodetype; -- if (hdr_crc != node.hdr_crc) { -+ crcnode.magic = node->magic; -+ crcnode.nodetype = cpu_to_je16( je16_to_cpu(node->nodetype) | JFFS2_NODE_ACCURATE); -+ crcnode.totlen = node->totlen; -+ hdr_crc = crc32(0, &crcnode, sizeof(crcnode)-4); -+ -+ if (hdr_crc != je32_to_cpu(node->hdr_crc)) { - 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", -- ofs, node.magic, node.nodetype, node.totlen, node.hdr_crc, hdr_crc); -+ ofs, je16_to_cpu(node->magic), -+ je16_to_cpu(node->nodetype), -+ je32_to_cpu(node->totlen), -+ je32_to_cpu(node->hdr_crc), -+ hdr_crc); - DIRTY_SPACE(4); - ofs += 4; - continue; - } - -- if (ofs + node.totlen > jeb->offset + c->sector_size) { -+ if (ofs + je32_to_cpu(node->totlen) > -+ jeb->offset + c->sector_size) { - /* Eep. Node goes over the end of the erase block. */ - printk(KERN_WARNING "Node at 0x%08x with length 0x%08x would run over the end of the erase block\n", -- ofs, node.totlen); -+ ofs, je32_to_cpu(node->totlen)); - printk(KERN_WARNING "Perhaps the file system was created with the wrong erase size?\n"); - DIRTY_SPACE(4); - ofs += 4; - continue; - } - -- switch(node.nodetype | JFFS2_NODE_ACCURATE) { -+ if (!(je16_to_cpu(node->nodetype) & JFFS2_NODE_ACCURATE)) { -+ /* Wheee. This is an obsoleted node */ -+ D2(printk(KERN_DEBUG "Node at 0x%08x is obsolete. Skipping\n", ofs)); -+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); -+ ofs += PAD(je32_to_cpu(node->totlen)); -+ continue; -+ } -+ -+ switch(je16_to_cpu(node->nodetype)) { - case JFFS2_NODETYPE_INODE: -- err = jffs2_scan_inode_node(c, jeb, &ofs); -+ if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) { -+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); -+ D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n", -+ sizeof(struct jffs2_raw_inode), buf_len, ofs)); -+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); -+ if (err) -+ return err; -+ buf_ofs = ofs; -+ node = (void *)buf; -+ } -+ err = jffs2_scan_inode_node(c, jeb, (void *)node, ofs); - if (err) return err; -+ ofs += PAD(je32_to_cpu(node->totlen)); - break; - - case JFFS2_NODETYPE_DIRENT: -- err = jffs2_scan_dirent_node(c, jeb, &ofs); -+ if (buf_ofs + buf_len < ofs + je32_to_cpu(node->totlen)) { -+ buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); -+ D1(printk(KERN_DEBUG "Fewer than %d bytes (dirent node) left to end of buf. Reading 0x%x at 0x%08x\n", -+ je32_to_cpu(node->totlen), buf_len, ofs)); -+ err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); -+ if (err) -+ return err; -+ buf_ofs = ofs; -+ node = (void *)buf; -+ } -+ err = jffs2_scan_dirent_node(c, jeb, (void *)node, ofs); - if (err) return err; -+ ofs += PAD(je32_to_cpu(node->totlen)); - break; - - case JFFS2_NODETYPE_CLEANMARKER: -- if (node.totlen != sizeof(struct jffs2_unknown_node)) { -+ D1(printk(KERN_DEBUG "CLEANMARKER node found at 0x%08x\n", ofs)); -+ if (je32_to_cpu(node->totlen) != c->cleanmarker_size) { - printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x has totlen 0x%x != normal 0x%x\n", -- ofs, node.totlen, sizeof(struct jffs2_unknown_node)); -+ ofs, je32_to_cpu(node->totlen), c->cleanmarker_size); - DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); -+ ofs += PAD(sizeof(struct jffs2_unknown_node)); - } else if (jeb->first_node) { - printk(KERN_NOTICE "CLEANMARKER node found at 0x%08x, not first node in block (0x%08x)\n", ofs, jeb->offset); - DIRTY_SPACE(PAD(sizeof(struct jffs2_unknown_node))); - ofs += PAD(sizeof(struct jffs2_unknown_node)); -- continue; - } else { - struct jffs2_raw_node_ref *marker_ref = jffs2_alloc_raw_node_ref(); - if (!marker_ref) { -@@ -300,98 +553,80 @@ - } - marker_ref->next_in_ino = NULL; - marker_ref->next_phys = NULL; -- marker_ref->flash_offset = ofs; -- marker_ref->totlen = sizeof(struct jffs2_unknown_node); -+ marker_ref->flash_offset = ofs | REF_NORMAL; -+ marker_ref->__totlen = c->cleanmarker_size; - jeb->first_node = jeb->last_node = marker_ref; - -- USED_SPACE(PAD(sizeof(struct jffs2_unknown_node))); -+ USED_SPACE(PAD(c->cleanmarker_size)); -+ ofs += PAD(c->cleanmarker_size); - } -- ofs += PAD(sizeof(struct jffs2_unknown_node)); -+ break; -+ -+ case JFFS2_NODETYPE_PADDING: -+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); -+ ofs += PAD(je32_to_cpu(node->totlen)); - break; - - default: -- switch (node.nodetype & JFFS2_COMPAT_MASK) { -+ switch (je16_to_cpu(node->nodetype) & JFFS2_COMPAT_MASK) { - case JFFS2_FEATURE_ROCOMPAT: -- printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); -+ printk(KERN_NOTICE "Read-only compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs); - c->flags |= JFFS2_SB_FLAG_RO; -- if (!(OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)) -+ if (!(jffs2_is_readonly(c))) - return -EROFS; -- DIRTY_SPACE(PAD(node.totlen)); -- ofs += PAD(node.totlen); -- continue; -+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); -+ ofs += PAD(je32_to_cpu(node->totlen)); -+ break; - - case JFFS2_FEATURE_INCOMPAT: -- printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); -+ printk(KERN_NOTICE "Incompatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs); - return -EINVAL; - - case JFFS2_FEATURE_RWCOMPAT_DELETE: -- printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); -- DIRTY_SPACE(PAD(node.totlen)); -- ofs += PAD(node.totlen); -+ D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs)); -+ DIRTY_SPACE(PAD(je32_to_cpu(node->totlen))); -+ ofs += PAD(je32_to_cpu(node->totlen)); - break; - - case JFFS2_FEATURE_RWCOMPAT_COPY: -- printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", node.nodetype, ofs); -- USED_SPACE(PAD(node.totlen)); -- ofs += PAD(node.totlen); -+ D1(printk(KERN_NOTICE "Unknown but compatible feature node (0x%04x) found at offset 0x%08x\n", je16_to_cpu(node->nodetype), ofs)); -+ USED_SPACE(PAD(je32_to_cpu(node->totlen))); -+ ofs += PAD(je32_to_cpu(node->totlen)); - break; - } - } - } -- D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, -- jeb->free_size, jeb->dirty_size, jeb->used_size)); -- return 0; --} - --/* We're pointing at the first empty word on the flash. Scan and account for the whole dirty region */ --static int jffs2_scan_empty(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *startofs, int *noise) --{ -- __u32 *buf; -- __u32 scanlen = (jeb->offset + c->sector_size) - *startofs; -- __u32 curofs = *startofs; -- -- buf = kmalloc(min((__u32)PAGE_SIZE, scanlen), GFP_KERNEL); -- if (!buf) { -- printk(KERN_WARNING "Scan buffer allocation failed\n"); -- return -ENOMEM; -- } -- while(scanlen) { -- ssize_t retlen; -- int ret, i; -- -- ret = c->mtd->read(c->mtd, curofs, min((__u32)PAGE_SIZE, scanlen), &retlen, (char *)buf); -- if(ret) { -- D1(printk(KERN_WARNING "jffs2_scan_empty(): Read 0x%x bytes at 0x%08x returned %d\n", min((__u32)PAGE_SIZE, scanlen), curofs, ret)); -- kfree(buf); -- return ret; -- } -- if (retlen < 4) { -- D1(printk(KERN_WARNING "Eep. too few bytes read in scan_empty()\n")); -- kfree(buf); -- return -EIO; -- } -- for (i=0; i<(retlen / 4); i++) { -- if (buf[i] != 0xffffffff) { -- curofs += i*4; -- -- noisy_printk(noise, "jffs2_scan_empty(): Empty block at 0x%08x ends at 0x%08x (with 0x%08x)! Marking dirty\n", *startofs, curofs, buf[i]); -- DIRTY_SPACE(curofs - (*startofs)); -- *startofs = curofs; -- kfree(buf); -- return 0; -- } -- } -- scanlen -= retlen&~3; -- curofs += retlen&~3; -- } - -- D1(printk(KERN_DEBUG "Empty flash detected from 0x%08x to 0x%08x\n", *startofs, curofs)); -- kfree(buf); -- *startofs = curofs; -- return 0; -+ D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, -+ jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); -+ -+ /* mark_node_obsolete can add to wasted !! */ -+ if (jeb->wasted_size) { -+ jeb->dirty_size += jeb->wasted_size; -+ c->dirty_size += jeb->wasted_size; -+ c->wasted_size -= jeb->wasted_size; -+ jeb->wasted_size = 0; -+ } -+ -+ if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size -+ && (!jeb->first_node || jeb->first_node->next_in_ino) ) -+ return BLK_STATE_CLEANMARKER; -+ -+ /* move blocks with max 4 byte dirty space to cleanlist */ -+ else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) { -+ c->dirty_size -= jeb->dirty_size; -+ c->wasted_size += jeb->dirty_size; -+ jeb->wasted_size += jeb->dirty_size; -+ jeb->dirty_size = 0; -+ return BLK_STATE_CLEAN; -+ } else if (jeb->used_size || jeb->unchecked_size) -+ return BLK_STATE_PARTDIRTY; -+ else -+ return BLK_STATE_ALLDIRTY; - } - --static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, __u32 ino) -+static struct jffs2_inode_cache *jffs2_scan_make_ino_cache(struct jffs2_sb_info *c, uint32_t ino) - { - struct jffs2_inode_cache *ic; - -@@ -399,137 +634,77 @@ - if (ic) - return ic; - -+ if (ino > c->highest_ino) -+ c->highest_ino = ino; -+ - ic = jffs2_alloc_inode_cache(); - if (!ic) { - printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of inode cache failed\n"); - return NULL; - } - memset(ic, 0, sizeof(*ic)); -- ic->scan = kmalloc(sizeof(struct jffs2_scan_info), GFP_KERNEL); -- if (!ic->scan) { -- printk(KERN_NOTICE "jffs2_scan_make_inode_cache(): allocation of scan info for inode cache failed\n"); -- jffs2_free_inode_cache(ic); -- return NULL; -- } -- memset(ic->scan, 0, sizeof(*ic->scan)); -+ - ic->ino = ino; - ic->nodes = (void *)ic; - jffs2_add_ino_cache(c, ic); - if (ino == 1) -- ic->nlink=1; -+ ic->nlink = 1; - return ic; - } - --static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs) -+static int jffs2_scan_inode_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -+ struct jffs2_raw_inode *ri, uint32_t ofs) - { - struct jffs2_raw_node_ref *raw; -- struct jffs2_full_dnode *fn; -- struct jffs2_tmp_dnode_info *tn, **tn_list; - struct jffs2_inode_cache *ic; -- struct jffs2_raw_inode ri; -- __u32 crc; -- __u16 oldnodetype; -- int ret; -- ssize_t retlen; -- -- D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", *ofs)); -- -- ret = c->mtd->read(c->mtd, *ofs, sizeof(ri), &retlen, (char *)&ri); -- if (ret) { -- printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs, ret); -- return ret; -- } -- if (retlen != sizeof(ri)) { -- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", -- retlen, *ofs, sizeof(ri)); -- return -EIO; -- } -+ uint32_t ino = je32_to_cpu(ri->ino); - -- /* We sort of assume that the node was accurate when it was -- first written to the medium :) */ -- oldnodetype = ri.nodetype; -- ri.nodetype |= JFFS2_NODE_ACCURATE; -- crc = crc32(0, &ri, sizeof(ri)-8); -- ri.nodetype = oldnodetype; -+ D1(printk(KERN_DEBUG "jffs2_scan_inode_node(): Node at 0x%08x\n", ofs)); - -- if(crc != ri.node_crc) { -- printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -- *ofs, ri.node_crc, crc); -- /* FIXME: Why do we believe totlen? */ -- DIRTY_SPACE(4); -- *ofs += 4; -- return 0; -- } -- /* There was a bug where we wrote hole nodes out with csize/dsize -- swapped. Deal with it */ -- if (ri.compr == JFFS2_COMPR_ZERO && !ri.dsize && ri.csize) { -- ri.dsize = ri.csize; -- ri.csize = 0; -- } -+ /* We do very little here now. Just check the ino# to which we should attribute -+ this node; we can do all the CRC checking etc. later. There's a tradeoff here -- -+ we used to scan the flash once only, reading everything we want from it into -+ memory, then building all our in-core data structures and freeing the extra -+ information. Now we allow the first part of the mount to complete a lot quicker, -+ but we have to go _back_ to the flash in order to finish the CRC checking, etc. -+ Which means that the _full_ amount of time to get to proper write mode with GC -+ operational may actually be _longer_ than before. Sucks to be me. */ - -- if (ri.csize) { -- /* Check data CRC too */ -- unsigned char *dbuf; -- __u32 crc; -- -- dbuf = kmalloc(PAGE_CACHE_SIZE, GFP_KERNEL); -- if (!dbuf) { -- printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of temporary data buffer for CRC check failed\n"); -- return -ENOMEM; -- } -- ret = c->mtd->read(c->mtd, *ofs+sizeof(ri), ri.csize, &retlen, dbuf); -- if (ret) { -- printk(KERN_NOTICE "jffs2_scan_inode_node(): Read error at 0x%08x: %d\n", *ofs+sizeof(ri), ret); -- kfree(dbuf); -- return ret; -- } -- if (retlen != ri.csize) { -- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", -- retlen, *ofs+ sizeof(ri), ri.csize); -- kfree(dbuf); -- return -EIO; -- } -- crc = crc32(0, dbuf, ri.csize); -- kfree(dbuf); -- if (crc != ri.data_crc) { -- printk(KERN_NOTICE "jffs2_scan_inode_node(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -- *ofs, ri.data_crc, crc); -- DIRTY_SPACE(PAD(ri.totlen)); -- *ofs += PAD(ri.totlen); -- return 0; -- } -- } -- -- /* Wheee. It worked */ - raw = jffs2_alloc_raw_node_ref(); - if (!raw) { - printk(KERN_NOTICE "jffs2_scan_inode_node(): allocation of node reference failed\n"); - return -ENOMEM; - } -- tn = jffs2_alloc_tmp_dnode_info(); -- if (!tn) { -- jffs2_free_raw_node_ref(raw); -- return -ENOMEM; -- } -- fn = jffs2_alloc_full_dnode(); -- if (!fn) { -- jffs2_free_tmp_dnode_info(tn); -+ -+ ic = jffs2_get_ino_cache(c, ino); -+ if (!ic) { -+ /* Inocache get failed. Either we read a bogus ino# or it's just genuinely the -+ first node we found for this inode. Do a CRC check to protect against the former -+ case */ -+ uint32_t crc = crc32(0, ri, sizeof(*ri)-8); -+ -+ if (crc != je32_to_cpu(ri->node_crc)) { -+ printk(KERN_NOTICE "jffs2_scan_inode_node(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -+ ofs, je32_to_cpu(ri->node_crc), crc); -+ /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ -+ DIRTY_SPACE(PAD(je32_to_cpu(ri->totlen))); - jffs2_free_raw_node_ref(raw); -- return -ENOMEM; -+ return 0; - } -- ic = jffs2_scan_make_ino_cache(c, ri.ino); -+ ic = jffs2_scan_make_ino_cache(c, ino); - if (!ic) { -- jffs2_free_full_dnode(fn); -- jffs2_free_tmp_dnode_info(tn); - jffs2_free_raw_node_ref(raw); - return -ENOMEM; - } -+ } - -- /* Build the data structures and file them for later */ -- raw->flash_offset = *ofs; -- raw->totlen = PAD(ri.totlen); -+ /* Wheee. It worked */ -+ -+ raw->flash_offset = ofs | REF_UNCHECKED; -+ raw->__totlen = PAD(je32_to_cpu(ri->totlen)); - raw->next_phys = NULL; - raw->next_in_ino = ic->nodes; -+ - ic->nodes = raw; - if (!jeb->first_node) - jeb->first_node = raw; -@@ -538,134 +713,56 @@ - jeb->last_node = raw; - - D1(printk(KERN_DEBUG "Node is ino #%u, version %d. Range 0x%x-0x%x\n", -- ri.ino, ri.version, ri.offset, ri.offset+ri.dsize)); -- -- pseudo_random += ri.version; -- -- for (tn_list = &ic->scan->tmpnodes; *tn_list; tn_list = &((*tn_list)->next)) { -- if ((*tn_list)->version < ri.version) -- continue; -- if ((*tn_list)->version > ri.version) -- break; -- /* Wheee. We've found another instance of the same version number. -- We should obsolete one of them. -- */ -- D1(printk(KERN_DEBUG "Duplicate version %d found in ino #%u. Previous one is at 0x%08x\n", ri.version, ic->ino, (*tn_list)->fn->raw->flash_offset &~3)); -- if (!jeb->used_size) { -- D1(printk(KERN_DEBUG "No valid nodes yet found in this eraseblock 0x%08x, so obsoleting the new instance at 0x%08x\n", -- jeb->offset, raw->flash_offset & ~3)); -- ri.nodetype &= ~JFFS2_NODE_ACCURATE; -- /* Perhaps we could also mark it as such on the medium. Maybe later */ -- } -- break; -- } -- -- if (ri.nodetype & JFFS2_NODE_ACCURATE) { -- memset(fn,0,sizeof(*fn)); -- -- fn->ofs = ri.offset; -- fn->size = ri.dsize; -- fn->frags = 0; -- fn->raw = raw; -- -- tn->next = NULL; -- tn->fn = fn; -- tn->version = ri.version; -+ je32_to_cpu(ri->ino), je32_to_cpu(ri->version), -+ je32_to_cpu(ri->offset), -+ je32_to_cpu(ri->offset)+je32_to_cpu(ri->dsize))); - -- USED_SPACE(PAD(ri.totlen)); -- jffs2_add_tn_to_list(tn, &ic->scan->tmpnodes); -- /* Make sure the one we just added is the _last_ in the list -- with this version number, so the older ones get obsoleted */ -- while (tn->next && tn->next->version == tn->version) { -+ pseudo_random += je32_to_cpu(ri->version); - -- D1(printk(KERN_DEBUG "Shifting new node at 0x%08x after other node at 0x%08x for version %d in list\n", -- fn->raw->flash_offset&~3, tn->next->fn->raw->flash_offset &~3, ri.version)); -- -- if(tn->fn != fn) -- BUG(); -- tn->fn = tn->next->fn; -- tn->next->fn = fn; -- tn = tn->next; -- } -- } else { -- jffs2_free_full_dnode(fn); -- jffs2_free_tmp_dnode_info(tn); -- raw->flash_offset |= 1; -- DIRTY_SPACE(PAD(ri.totlen)); -- } -- *ofs += PAD(ri.totlen); -+ UNCHECKED_SPACE(PAD(je32_to_cpu(ri->totlen))); - return 0; - } - --static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, __u32 *ofs) -+static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, -+ struct jffs2_raw_dirent *rd, uint32_t ofs) - { - struct jffs2_raw_node_ref *raw; - struct jffs2_full_dirent *fd; - struct jffs2_inode_cache *ic; -- struct jffs2_raw_dirent rd; -- __u16 oldnodetype; -- int ret; -- __u32 crc; -- ssize_t retlen; -- -- D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", *ofs)); -+ uint32_t crc; - -- ret = c->mtd->read(c->mtd, *ofs, sizeof(rd), &retlen, (char *)&rd); -- if (ret) { -- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", *ofs, ret); -- return ret; -- } -- if (retlen != sizeof(rd)) { -- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", -- retlen, *ofs, sizeof(rd)); -- return -EIO; -- } -+ D1(printk(KERN_DEBUG "jffs2_scan_dirent_node(): Node at 0x%08x\n", ofs)); - -- /* We sort of assume that the node was accurate when it was -- first written to the medium :) */ -- oldnodetype = rd.nodetype; -- rd.nodetype |= JFFS2_NODE_ACCURATE; -- crc = crc32(0, &rd, sizeof(rd)-8); -- rd.nodetype = oldnodetype; -+ /* We don't get here unless the node is still valid, so we don't have to -+ mask in the ACCURATE bit any more. */ -+ crc = crc32(0, rd, sizeof(*rd)-8); - -- if (crc != rd.node_crc) { -+ if (crc != je32_to_cpu(rd->node_crc)) { - printk(KERN_NOTICE "jffs2_scan_dirent_node(): Node CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -- *ofs, rd.node_crc, crc); -- /* FIXME: Why do we believe totlen? */ -- DIRTY_SPACE(4); -- *ofs += 4; -+ ofs, je32_to_cpu(rd->node_crc), crc); -+ /* We believe totlen because the CRC on the node _header_ was OK, just the node itself failed. */ -+ DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen))); - return 0; - } - -- pseudo_random += rd.version; -+ pseudo_random += je32_to_cpu(rd->version); - -- fd = jffs2_alloc_full_dirent(rd.nsize+1); -+ fd = jffs2_alloc_full_dirent(rd->nsize+1); - if (!fd) { - return -ENOMEM; --} -- ret = c->mtd->read(c->mtd, *ofs + sizeof(rd), rd.nsize, &retlen, &fd->name[0]); -- if (ret) { -- jffs2_free_full_dirent(fd); -- printk(KERN_NOTICE "jffs2_scan_dirent_node(): Read error at 0x%08x: %d\n", -- *ofs + sizeof(rd), ret); -- return ret; -- } -- if (retlen != rd.nsize) { -- jffs2_free_full_dirent(fd); -- printk(KERN_NOTICE "Short read: 0x%x bytes at 0x%08x instead of requested %x\n", -- retlen, *ofs + sizeof(rd), rd.nsize); -- return -EIO; - } -- crc = crc32(0, fd->name, rd.nsize); -- if (crc != rd.name_crc) { -+ memcpy(&fd->name, rd->name, rd->nsize); -+ fd->name[rd->nsize] = 0; -+ -+ crc = crc32(0, fd->name, rd->nsize); -+ if (crc != je32_to_cpu(rd->name_crc)) { - printk(KERN_NOTICE "jffs2_scan_dirent_node(): Name CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", -- *ofs, rd.name_crc, crc); -- fd->name[rd.nsize]=0; -- D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, rd.ino)); -+ ofs, je32_to_cpu(rd->name_crc), crc); -+ D1(printk(KERN_NOTICE "Name for which CRC failed is (now) '%s', ino #%d\n", fd->name, je32_to_cpu(rd->ino))); - jffs2_free_full_dirent(fd); - /* FIXME: Why do we believe totlen? */ -- DIRTY_SPACE(PAD(rd.totlen)); -- *ofs += PAD(rd.totlen); -+ /* We believe totlen because the CRC on the node _header_ was OK, just the name failed. */ -+ DIRTY_SPACE(PAD(je32_to_cpu(rd->totlen))); - return 0; - } - raw = jffs2_alloc_raw_node_ref(); -@@ -674,15 +771,15 @@ - printk(KERN_NOTICE "jffs2_scan_dirent_node(): allocation of node reference failed\n"); - return -ENOMEM; - } -- ic = jffs2_scan_make_ino_cache(c, rd.pino); -+ ic = jffs2_scan_make_ino_cache(c, je32_to_cpu(rd->pino)); - if (!ic) { - jffs2_free_full_dirent(fd); - jffs2_free_raw_node_ref(raw); - return -ENOMEM; - } - -- raw->totlen = PAD(rd.totlen); -- raw->flash_offset = *ofs; -+ raw->__totlen = PAD(je32_to_cpu(rd->totlen)); -+ raw->flash_offset = ofs | REF_PRISTINE; - raw->next_phys = NULL; - raw->next_in_ino = ic->nodes; - ic->nodes = raw; -@@ -692,24 +789,15 @@ - jeb->last_node->next_phys = raw; - jeb->last_node = raw; - -- if (rd.nodetype & JFFS2_NODE_ACCURATE) { - fd->raw = raw; - fd->next = NULL; -- fd->version = rd.version; -- fd->ino = rd.ino; -- fd->name[rd.nsize]=0; -- fd->nhash = full_name_hash(fd->name, rd.nsize); -- fd->type = rd.type; -- -- USED_SPACE(PAD(rd.totlen)); -- jffs2_add_fd_to_list(c, fd, &ic->scan->dents); -- } else { -- raw->flash_offset |= 1; -- jffs2_free_full_dirent(fd); -+ fd->version = je32_to_cpu(rd->version); -+ fd->ino = je32_to_cpu(rd->ino); -+ fd->nhash = full_name_hash(fd->name, rd->nsize); -+ fd->type = rd->type; -+ USED_SPACE(PAD(je32_to_cpu(rd->totlen))); -+ jffs2_add_fd_to_list(c, fd, &ic->scan_dents); - -- DIRTY_SPACE(PAD(rd.totlen)); -- } -- *ofs += PAD(rd.totlen); - return 0; - } - -@@ -731,26 +819,90 @@ - struct list_head *n = head->next; - - list_del(head); -- while(count--) -+ while(count--) { - n = n->next; -+ } - list_add(head, n); - } - --static void jffs2_rotate_lists(struct jffs2_sb_info *c) -+void jffs2_rotate_lists(struct jffs2_sb_info *c) - { - uint32_t x; -+ uint32_t rotateby; - - x = count_list(&c->clean_list); -- if (x) -- rotate_list((&c->clean_list), pseudo_random % x); -+ if (x) { -+ rotateby = pseudo_random % x; -+ D1(printk(KERN_DEBUG "Rotating clean_list by %d\n", rotateby)); -+ -+ rotate_list((&c->clean_list), rotateby); -+ -+ D1(printk(KERN_DEBUG "Erase block at front of clean_list is at %08x\n", -+ list_entry(c->clean_list.next, struct jffs2_eraseblock, list)->offset)); -+ } else { -+ D1(printk(KERN_DEBUG "Not rotating empty clean_list\n")); -+ } -+ -+ x = count_list(&c->very_dirty_list); -+ if (x) { -+ rotateby = pseudo_random % x; -+ D1(printk(KERN_DEBUG "Rotating very_dirty_list by %d\n", rotateby)); -+ -+ rotate_list((&c->very_dirty_list), rotateby); -+ -+ D1(printk(KERN_DEBUG "Erase block at front of very_dirty_list is at %08x\n", -+ list_entry(c->very_dirty_list.next, struct jffs2_eraseblock, list)->offset)); -+ } else { -+ D1(printk(KERN_DEBUG "Not rotating empty very_dirty_list\n")); -+ } - - x = count_list(&c->dirty_list); -- if (x) -- rotate_list((&c->dirty_list), pseudo_random % x); -+ if (x) { -+ rotateby = pseudo_random % x; -+ D1(printk(KERN_DEBUG "Rotating dirty_list by %d\n", rotateby)); -+ -+ rotate_list((&c->dirty_list), rotateby); -+ -+ D1(printk(KERN_DEBUG "Erase block at front of dirty_list is at %08x\n", -+ list_entry(c->dirty_list.next, struct jffs2_eraseblock, list)->offset)); -+ } else { -+ D1(printk(KERN_DEBUG "Not rotating empty dirty_list\n")); -+ } -+ -+ x = count_list(&c->erasable_list); -+ if (x) { -+ rotateby = pseudo_random % x; -+ D1(printk(KERN_DEBUG "Rotating erasable_list by %d\n", rotateby)); - -- if (c->nr_erasing_blocks) -- rotate_list((&c->erase_pending_list), pseudo_random % c->nr_erasing_blocks); -+ rotate_list((&c->erasable_list), rotateby); - -- if (c->nr_free_blocks) /* Not that it should ever be zero */ -- rotate_list((&c->free_list), pseudo_random % c->nr_free_blocks); -+ D1(printk(KERN_DEBUG "Erase block at front of erasable_list is at %08x\n", -+ list_entry(c->erasable_list.next, struct jffs2_eraseblock, list)->offset)); -+ } else { -+ D1(printk(KERN_DEBUG "Not rotating empty erasable_list\n")); -+ } -+ -+ if (c->nr_erasing_blocks) { -+ rotateby = pseudo_random % c->nr_erasing_blocks; -+ D1(printk(KERN_DEBUG "Rotating erase_pending_list by %d\n", rotateby)); -+ -+ rotate_list((&c->erase_pending_list), rotateby); -+ -+ D1(printk(KERN_DEBUG "Erase block at front of erase_pending_list is at %08x\n", -+ list_entry(c->erase_pending_list.next, struct jffs2_eraseblock, list)->offset)); -+ } else { -+ D1(printk(KERN_DEBUG "Not rotating empty erase_pending_list\n")); -+ } -+ -+ if (c->nr_free_blocks) { -+ rotateby = pseudo_random % c->nr_free_blocks; -+ D1(printk(KERN_DEBUG "Rotating free_list by %d\n", rotateby)); -+ -+ rotate_list((&c->free_list), rotateby); -+ -+ D1(printk(KERN_DEBUG "Erase block at front of free_list is at %08x\n", -+ list_entry(c->free_list.next, struct jffs2_eraseblock, list)->offset)); -+ } else { -+ D1(printk(KERN_DEBUG "Not rotating empty free_list\n")); -+ } - } -diff -Nurb linux-mips-2.4.27/fs/jffs2/super-v24.c linux/fs/jffs2/super-v24.c ---- linux-mips-2.4.27/fs/jffs2/super-v24.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/jffs2/super-v24.c 2004-11-19 10:25:12.126165288 +0100 -@@ -0,0 +1,167 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001-2003 Red Hat, Inc. -+ * -+ * Created by David Woodhouse <dwmw2@redhat.com> -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ * -+ * $Id$ -+ * -+ */ -+ -+#include <linux/config.h> -+#include <linux/kernel.h> -+#include <linux/module.h> -+#include <linux/version.h> -+#include <linux/slab.h> -+#include <linux/init.h> -+#include <linux/list.h> -+#include <linux/fs.h> -+#include <linux/jffs2.h> -+#include <linux/pagemap.h> -+#include <linux/mtd/mtd.h> -+#include "nodelist.h" -+ -+#ifndef MTD_BLOCK_MAJOR -+#define MTD_BLOCK_MAJOR 31 -+#endif -+ -+static void jffs2_put_super (struct super_block *); -+ -+static struct super_operations jffs2_super_operations = -+{ -+ .read_inode = jffs2_read_inode, -+ .put_super = jffs2_put_super, -+ .write_super = jffs2_write_super, -+ .statfs = jffs2_statfs, -+ .remount_fs = jffs2_remount_fs, -+ .clear_inode = jffs2_clear_inode, -+ .dirty_inode = jffs2_dirty_inode, -+}; -+ -+ -+static struct super_block *jffs2_read_super(struct super_block *sb, void *data, int silent) -+{ -+ struct jffs2_sb_info *c; -+ int ret; -+ -+ D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev))); -+ -+ if (major(sb->s_dev) != MTD_BLOCK_MAJOR) { -+ if (!silent) -+ printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev)); -+ return NULL; -+ } -+ -+ c = JFFS2_SB_INFO(sb); -+ memset(c, 0, sizeof(*c)); -+ -+ sb->s_op = &jffs2_super_operations; -+ -+ c->mtd = get_mtd_device(NULL, minor(sb->s_dev)); -+ if (!c->mtd) { -+ D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", minor(sb->s_dev))); -+ return NULL; -+ } -+ -+ ret = jffs2_do_fill_super(sb, data, silent); -+ if (ret) { -+ put_mtd_device(c->mtd); -+ return NULL; -+ } -+ -+ return sb; -+} -+ -+static void jffs2_put_super (struct super_block *sb) -+{ -+ struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); -+ -+ D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); -+ -+ -+ if (!(sb->s_flags & MS_RDONLY)) -+ jffs2_stop_garbage_collect_thread(c); -+ down(&c->alloc_sem); -+ jffs2_flush_wbuf_pad(c); -+ up(&c->alloc_sem); -+ jffs2_free_ino_caches(c); -+ jffs2_free_raw_node_refs(c); -+ kfree(c->blocks); -+ jffs2_nand_flash_cleanup(c); -+ kfree(c->inocache_list); -+ if (c->mtd->sync) -+ c->mtd->sync(c->mtd); -+ put_mtd_device(c->mtd); -+ -+ D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); -+} -+ -+static DECLARE_FSTYPE_DEV(jffs2_fs_type, "jffs2", jffs2_read_super); -+ -+static int __init init_jffs2_fs(void) -+{ -+ int ret; -+ -+ printk(KERN_INFO "JFFS2 version 2.2." -+#ifdef CONFIG_FS_JFFS2_NAND -+ " (NAND)" -+#endif -+ " (C) 2001-2003 Red Hat, Inc.\n"); -+ -+#ifdef JFFS2_OUT_OF_KERNEL -+ /* sanity checks. Could we do these at compile time? */ -+ if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) { -+ printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n", -+ sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u)); -+ return -EIO; -+ } -+ -+ if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) { -+ printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n", -+ sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u)); -+ return -EIO; -+ } -+#endif -+ ret = jffs2_zlib_init(); -+ if (ret) { -+ printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n"); -+ goto out; -+ } -+ ret = jffs2_create_slab_caches(); -+ if (ret) { -+ printk(KERN_ERR "JFFS2 error: Failed to initialise slab caches\n"); -+ goto out_zlib; -+ } -+ ret = register_filesystem(&jffs2_fs_type); -+ if (ret) { -+ printk(KERN_ERR "JFFS2 error: Failed to register filesystem\n"); -+ goto out_slab; -+ } -+ return 0; -+ -+ out_slab: -+ jffs2_destroy_slab_caches(); -+ out_zlib: -+ jffs2_zlib_exit(); -+ out: -+ -+ return ret; -+} -+ -+static void __exit exit_jffs2_fs(void) -+{ -+ jffs2_destroy_slab_caches(); -+ jffs2_zlib_exit(); -+ unregister_filesystem(&jffs2_fs_type); -+} -+ -+module_init(init_jffs2_fs); -+module_exit(exit_jffs2_fs); -+ -+MODULE_DESCRIPTION("The Journalling Flash File System, v2"); -+MODULE_AUTHOR("Red Hat, Inc."); -+MODULE_LICENSE("GPL"); // Actually dual-licensed, but it doesn't matter for -+ // the sake of this tag. It's Free Software. -diff -Nurb linux-mips-2.4.27/fs/jffs2/super.c linux/fs/jffs2/super.c ---- linux-mips-2.4.27/fs/jffs2/super.c 2003-01-11 18:53:17.000000000 +0100 -+++ linux/fs/jffs2/super.c 2004-11-19 10:25:12.127165136 +0100 -@@ -1,291 +1,257 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/config.h> - #include <linux/kernel.h> - #include <linux/module.h> --#include <linux/version.h> - #include <linux/slab.h> - #include <linux/init.h> - #include <linux/list.h> - #include <linux/fs.h> -+#include <linux/mount.h> - #include <linux/jffs2.h> - #include <linux/pagemap.h> - #include <linux/mtd/mtd.h> --#include <linux/interrupt.h> -+#include <linux/ctype.h> -+#include <linux/namei.h> - #include "nodelist.h" - --#ifndef MTD_BLOCK_MAJOR --#define MTD_BLOCK_MAJOR 31 --#endif -+static void jffs2_put_super(struct super_block *); -+ -+static kmem_cache_t *jffs2_inode_cachep; -+ -+static struct inode *jffs2_alloc_inode(struct super_block *sb) -+{ -+ struct jffs2_inode_info *ei; -+ ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, SLAB_KERNEL); -+ if (!ei) -+ return NULL; -+ return &ei->vfs_inode; -+} -+ -+static void jffs2_destroy_inode(struct inode *inode) -+{ -+ kmem_cache_free(jffs2_inode_cachep, JFFS2_INODE_INFO(inode)); -+} -+ -+static void jffs2_i_init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) -+{ -+ struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo; - --extern void jffs2_read_inode (struct inode *); --void jffs2_put_super (struct super_block *); --void jffs2_write_super (struct super_block *); --static int jffs2_statfs (struct super_block *, struct statfs *); --int jffs2_remount_fs (struct super_block *, int *, char *); --extern void jffs2_clear_inode (struct inode *); -+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == -+ SLAB_CTOR_CONSTRUCTOR) { -+ init_MUTEX_LOCKED(&ei->sem); -+ inode_init_once(&ei->vfs_inode); -+ } -+} - - static struct super_operations jffs2_super_operations = - { -- read_inode: jffs2_read_inode, --// delete_inode: jffs2_delete_inode, -- put_super: jffs2_put_super, -- write_super: jffs2_write_super, -- statfs: jffs2_statfs, -- remount_fs: jffs2_remount_fs, -- clear_inode: jffs2_clear_inode -+ .alloc_inode = jffs2_alloc_inode, -+ .destroy_inode =jffs2_destroy_inode, -+ .read_inode = jffs2_read_inode, -+ .put_super = jffs2_put_super, -+ .write_super = jffs2_write_super, -+ .statfs = jffs2_statfs, -+ .remount_fs = jffs2_remount_fs, -+ .clear_inode = jffs2_clear_inode, -+ .dirty_inode = jffs2_dirty_inode, - }; - --static int jffs2_statfs(struct super_block *sb, struct statfs *buf) -+static int jffs2_sb_compare(struct super_block *sb, void *data) - { -+ struct jffs2_sb_info *p = data; - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); -- unsigned long avail; - -- buf->f_type = JFFS2_SUPER_MAGIC; -- buf->f_bsize = 1 << PAGE_SHIFT; -- buf->f_blocks = c->flash_size >> PAGE_SHIFT; -- buf->f_files = 0; -- buf->f_ffree = 0; -- buf->f_namelen = JFFS2_MAX_NAME_LEN; -- -- spin_lock_bh(&c->erase_completion_lock); -- -- avail = c->dirty_size + c->free_size; -- if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE) -- avail -= c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE; -- else -- avail = 0; -- -- buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT; -- --#if CONFIG_JFFS2_FS_DEBUG > 0 -- printk(KERN_DEBUG "STATFS:\n"); -- printk(KERN_DEBUG "flash_size: %08x\n", c->flash_size); -- printk(KERN_DEBUG "used_size: %08x\n", c->used_size); -- printk(KERN_DEBUG "dirty_size: %08x\n", c->dirty_size); -- printk(KERN_DEBUG "free_size: %08x\n", c->free_size); -- printk(KERN_DEBUG "erasing_size: %08x\n", c->erasing_size); -- printk(KERN_DEBUG "bad_size: %08x\n", c->bad_size); -- printk(KERN_DEBUG "sector_size: %08x\n", c->sector_size); -- -- if (c->nextblock) { -- printk(KERN_DEBUG "nextblock: 0x%08x\n", c->nextblock->offset); -- } else { -- printk(KERN_DEBUG "nextblock: NULL\n"); -- } -- if (c->gcblock) { -- printk(KERN_DEBUG "gcblock: 0x%08x\n", c->gcblock->offset); -+ /* The superblocks are considered to be equivalent if the underlying MTD -+ device is the same one */ -+ if (c->mtd == p->mtd) { -+ D1(printk(KERN_DEBUG "jffs2_sb_compare: match on device %d (\"%s\")\n", p->mtd->index, p->mtd->name)); -+ return 1; - } else { -- printk(KERN_DEBUG "gcblock: NULL\n"); -+ D1(printk(KERN_DEBUG "jffs2_sb_compare: No match, device %d (\"%s\"), device %d (\"%s\")\n", -+ c->mtd->index, c->mtd->name, p->mtd->index, p->mtd->name)); -+ return 0; - } -- if (list_empty(&c->clean_list)) { -- printk(KERN_DEBUG "clean_list: empty\n"); -- } else { -- struct list_head *this; -+} - -- list_for_each(this, &c->clean_list) { -- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -- printk(KERN_DEBUG "clean_list: %08x\n", jeb->offset); -- } -- } -- if (list_empty(&c->dirty_list)) { -- printk(KERN_DEBUG "dirty_list: empty\n"); -- } else { -- struct list_head *this; -+static int jffs2_sb_set(struct super_block *sb, void *data) -+{ -+ struct jffs2_sb_info *p = data; - -- list_for_each(this, &c->dirty_list) { -- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -- printk(KERN_DEBUG "dirty_list: %08x\n", jeb->offset); -- } -- } -- if (list_empty(&c->erasing_list)) { -- printk(KERN_DEBUG "erasing_list: empty\n"); -- } else { -- struct list_head *this; -+ /* For persistence of NFS exports etc. we use the same s_dev -+ each time we mount the device, don't just use an anonymous -+ device */ -+ sb->s_fs_info = p; -+ p->os_priv = sb; -+ sb->s_dev = MKDEV(MTD_BLOCK_MAJOR, p->mtd->index); - -- list_for_each(this, &c->erasing_list) { -- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -- printk(KERN_DEBUG "erasing_list: %08x\n", jeb->offset); -- } -- } -- if (list_empty(&c->erase_pending_list)) { -- printk(KERN_DEBUG "erase_pending_list: empty\n"); -- } else { -- struct list_head *this; -+ return 0; -+} - -- list_for_each(this, &c->erase_pending_list) { -- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -- printk(KERN_DEBUG "erase_pending_list: %08x\n", jeb->offset); -- } -- } -- if (list_empty(&c->free_list)) { -- printk(KERN_DEBUG "free_list: empty\n"); -- } else { -- struct list_head *this; -+static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, -+ int flags, const char *dev_name, -+ void *data, struct mtd_info *mtd) -+{ -+ struct super_block *sb; -+ struct jffs2_sb_info *c; -+ int ret; - -- list_for_each(this, &c->free_list) { -- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -- printk(KERN_DEBUG "free_list: %08x\n", jeb->offset); -- } -- } -- if (list_empty(&c->bad_list)) { -- printk(KERN_DEBUG "bad_list: empty\n"); -- } else { -- struct list_head *this; -+ c = kmalloc(sizeof(*c), GFP_KERNEL); -+ if (!c) -+ return ERR_PTR(-ENOMEM); -+ memset(c, 0, sizeof(*c)); -+ c->mtd = mtd; - -- list_for_each(this, &c->bad_list) { -- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -- printk(KERN_DEBUG "bad_list: %08x\n", jeb->offset); -- } -- } -- if (list_empty(&c->bad_used_list)) { -- printk(KERN_DEBUG "bad_used_list: empty\n"); -- } else { -- struct list_head *this; -+ sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c); -+ -+ if (IS_ERR(sb)) -+ goto out_put; - -- list_for_each(this, &c->bad_used_list) { -- struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -- printk(KERN_DEBUG "bad_used_list: %08x\n", jeb->offset); -+ if (sb->s_root) { -+ /* New mountpoint for JFFS2 which is already mounted */ -+ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): Device %d (\"%s\") is already mounted\n", -+ mtd->index, mtd->name)); -+ goto out_put; - } -+ -+ D1(printk(KERN_DEBUG "jffs2_get_sb_mtd(): New superblock for device %d (\"%s\")\n", -+ mtd->index, mtd->name)); -+ -+ sb->s_op = &jffs2_super_operations; -+ -+ ret = jffs2_do_fill_super(sb, data, (flags&MS_VERBOSE)?1:0); -+ -+ if (ret) { -+ /* Failure case... */ -+ up_write(&sb->s_umount); -+ deactivate_super(sb); -+ return ERR_PTR(ret); - } --#endif /* CONFIG_JFFS2_FS_DEBUG */ - -- spin_unlock_bh(&c->erase_completion_lock); -+ sb->s_flags |= MS_ACTIVE; -+ return sb; - -+ out_put: -+ kfree(c); -+ put_mtd_device(mtd); - -- return 0; -+ return sb; - } - --static struct super_block *jffs2_read_super(struct super_block *sb, void *data, int silent) -+static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, -+ int flags, const char *dev_name, -+ void *data, int mtdnr) - { -- struct jffs2_sb_info *c; -- struct inode *root_i; -- int i; -- -- D1(printk(KERN_DEBUG "jffs2: read_super for device %s\n", kdevname(sb->s_dev))); -+ struct mtd_info *mtd; - -- if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) { -- if (!silent) -- printk(KERN_DEBUG "jffs2: attempt to mount non-MTD device %s\n", kdevname(sb->s_dev)); -- return NULL; -+ mtd = get_mtd_device(NULL, mtdnr); -+ if (!mtd) { -+ D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", mtdnr)); -+ return ERR_PTR(-EINVAL); - } - -- c = JFFS2_SB_INFO(sb); -- memset(c, 0, sizeof(*c)); -+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); -+} - -- c->mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); -- if (!c->mtd) { -- D1(printk(KERN_DEBUG "jffs2: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev))); -- return NULL; -+static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, -+ int flags, const char *dev_name, -+ void *data) -+{ -+ int err; -+ struct nameidata nd; -+ int mtdnr; -+ -+ if (!dev_name) -+ return ERR_PTR(-EINVAL); -+ -+ D1(printk(KERN_DEBUG "jffs2_get_sb(): dev_name \"%s\"\n", dev_name)); -+ -+ /* The preferred way of mounting in future; especially when -+ CONFIG_BLK_DEV is implemented - we specify the underlying -+ MTD device by number or by name, so that we don't require -+ block device support to be present in the kernel. */ -+ -+ /* FIXME: How to do the root fs this way? */ -+ -+ if (dev_name[0] == 'm' && dev_name[1] == 't' && dev_name[2] == 'd') { -+ /* Probably mounting without the blkdev crap */ -+ if (dev_name[3] == ':') { -+ struct mtd_info *mtd; -+ -+ /* Mount by MTD device name */ -+ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd:%%s, name \"%s\"\n", dev_name+4)); -+ for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) { -+ mtd = get_mtd_device(NULL, mtdnr); -+ if (mtd) { -+ if (!strcmp(mtd->name, dev_name+4)) -+ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); -+ put_mtd_device(mtd); - } -- c->sector_size = c->mtd->erasesize; -- c->free_size = c->flash_size = c->mtd->size; -- c->nr_blocks = c->mtd->size / c->mtd->erasesize; -- c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL); -- if (!c->blocks) -- goto out_mtd; -- for (i=0; i<c->nr_blocks; i++) { -- INIT_LIST_HEAD(&c->blocks[i].list); -- c->blocks[i].offset = i * c->sector_size; -- c->blocks[i].free_size = c->sector_size; -- c->blocks[i].dirty_size = 0; -- c->blocks[i].used_size = 0; -- c->blocks[i].first_node = NULL; -- c->blocks[i].last_node = NULL; -- } -- -- spin_lock_init(&c->nodelist_lock); -- init_MUTEX(&c->alloc_sem); -- init_waitqueue_head(&c->erase_wait); -- spin_lock_init(&c->erase_completion_lock); -- spin_lock_init(&c->inocache_lock); -- -- INIT_LIST_HEAD(&c->clean_list); -- INIT_LIST_HEAD(&c->dirty_list); -- INIT_LIST_HEAD(&c->erasing_list); -- INIT_LIST_HEAD(&c->erase_pending_list); -- INIT_LIST_HEAD(&c->erase_complete_list); -- INIT_LIST_HEAD(&c->free_list); -- INIT_LIST_HEAD(&c->bad_list); -- INIT_LIST_HEAD(&c->bad_used_list); -- c->highest_ino = 1; -- -- if (jffs2_build_filesystem(c)) { -- D1(printk(KERN_DEBUG "build_fs failed\n")); -- goto out_nodes; - } -+ printk(KERN_NOTICE "jffs2_get_sb(): MTD device with name \"%s\" not found.\n", dev_name+4); -+ } else if (isdigit(dev_name[3])) { -+ /* Mount by MTD device number name */ -+ char *endptr; - -- sb->s_op = &jffs2_super_operations; -+ mtdnr = simple_strtoul(dev_name+3, &endptr, 0); -+ if (!*endptr) { -+ /* It was a valid number */ -+ D1(printk(KERN_DEBUG "jffs2_get_sb(): mtd%%d, mtdnr %d\n", mtdnr)); -+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr); -+ } -+ } -+ } - -- D1(printk(KERN_DEBUG "jffs2_read_super(): Getting root inode\n")); -- root_i = iget(sb, 1); -- if (is_bad_inode(root_i)) { -- D1(printk(KERN_WARNING "get root inode failed\n")); -- goto out_nodes; -+ /* Try the old way - the hack where we allowed users to mount -+ /dev/mtdblock$(n) but didn't actually _use_ the blkdev */ -+ -+ err = path_lookup(dev_name, LOOKUP_FOLLOW, &nd); -+ -+ D1(printk(KERN_DEBUG "jffs2_get_sb(): path_lookup() returned %d, inode %p\n", -+ err, nd.dentry->d_inode)); -+ -+ if (err) -+ return ERR_PTR(err); -+ -+ err = -EINVAL; -+ -+ if (!S_ISBLK(nd.dentry->d_inode->i_mode)) -+ goto out; -+ -+ if (nd.mnt->mnt_flags & MNT_NODEV) { -+ err = -EACCES; -+ goto out; - } - -- D1(printk(KERN_DEBUG "jffs2_read_super(): d_alloc_root()\n")); -- sb->s_root = d_alloc_root(root_i); -- if (!sb->s_root) -- goto out_root_i; -+ if (imajor(nd.dentry->d_inode) != MTD_BLOCK_MAJOR) { -+ if (!(flags & MS_VERBOSE)) /* Yes I mean this. Strangely */ -+ printk(KERN_NOTICE "Attempt to mount non-MTD device \"%s\" as JFFS2\n", -+ dev_name); -+ goto out; -+ } - --#if LINUX_VERSION_CODE >= 0x20403 -- sb->s_maxbytes = 0xFFFFFFFF; --#endif -- sb->s_blocksize = PAGE_CACHE_SIZE; -- sb->s_blocksize_bits = PAGE_CACHE_SHIFT; -- sb->s_magic = JFFS2_SUPER_MAGIC; -- if (!(sb->s_flags & MS_RDONLY)) -- jffs2_start_garbage_collect_thread(c); -- return sb; -+ mtdnr = iminor(nd.dentry->d_inode); -+ path_release(&nd); - -- out_root_i: -- iput(root_i); -- out_nodes: -- jffs2_free_ino_caches(c); -- jffs2_free_raw_node_refs(c); -- kfree(c->blocks); -- out_mtd: -- put_mtd_device(c->mtd); -- return NULL; -+ return jffs2_get_sb_mtdnr(fs_type, flags, dev_name, data, mtdnr); -+ -+out: -+ path_release(&nd); -+ return ERR_PTR(err); - } - --void jffs2_put_super (struct super_block *sb) -+static void jffs2_put_super (struct super_block *sb) - { - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); - -@@ -293,74 +259,53 @@ - - if (!(sb->s_flags & MS_RDONLY)) - jffs2_stop_garbage_collect_thread(c); -+ down(&c->alloc_sem); -+ jffs2_flush_wbuf_pad(c); -+ up(&c->alloc_sem); - jffs2_free_ino_caches(c); - jffs2_free_raw_node_refs(c); - kfree(c->blocks); -+ jffs2_nand_flash_cleanup(c); -+ kfree(c->inocache_list); - if (c->mtd->sync) - c->mtd->sync(c->mtd); -- put_mtd_device(c->mtd); - - D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); - } - --int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) -+static void jffs2_kill_sb(struct super_block *sb) - { - struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); -- -- if (c->flags & JFFS2_SB_FLAG_RO && !(sb->s_flags & MS_RDONLY)) -- return -EROFS; -- -- /* We stop if it was running, then restart if it needs to. -- This also catches the case where it was stopped and this -- is just a remount to restart it */ -- if (!(sb->s_flags & MS_RDONLY)) -- jffs2_stop_garbage_collect_thread(c); -- -- if (!(*flags & MS_RDONLY)) -- jffs2_start_garbage_collect_thread(c); -- -- sb->s_flags = (sb->s_flags & ~MS_RDONLY)|(*flags & MS_RDONLY); -- -- return 0; --} -- --void jffs2_write_super (struct super_block *sb) --{ -- struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); -- sb->s_dirt = 0; -- -- if (sb->s_flags & MS_RDONLY) -- return; -- -- jffs2_garbage_collect_trigger(c); -- jffs2_erase_pending_blocks(c); -- jffs2_mark_erased_blocks(c); -+ generic_shutdown_super(sb); -+ put_mtd_device(c->mtd); -+ kfree(c); - } - -- --static DECLARE_FSTYPE_DEV(jffs2_fs_type, "jffs2", jffs2_read_super); -+static struct file_system_type jffs2_fs_type = { -+ .owner = THIS_MODULE, -+ .name = "jffs2", -+ .get_sb = jffs2_get_sb, -+ .kill_sb = jffs2_kill_sb, -+}; - - static int __init init_jffs2_fs(void) - { - int ret; - -- printk(KERN_NOTICE "JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.\n"); -- --#ifdef JFFS2_OUT_OF_KERNEL -- /* sanity checks. Could we do these at compile time? */ -- if (sizeof(struct jffs2_sb_info) > sizeof (((struct super_block *)NULL)->u)) { -- printk(KERN_ERR "JFFS2 error: struct jffs2_sb_info (%d bytes) doesn't fit in the super_block union (%d bytes)\n", -- sizeof(struct jffs2_sb_info), sizeof (((struct super_block *)NULL)->u)); -- return -EIO; -- } -- -- if (sizeof(struct jffs2_inode_info) > sizeof (((struct inode *)NULL)->u)) { -- printk(KERN_ERR "JFFS2 error: struct jffs2_inode_info (%d bytes) doesn't fit in the inode union (%d bytes)\n", -- sizeof(struct jffs2_inode_info), sizeof (((struct inode *)NULL)->u)); -- return -EIO; -- } -+ printk(KERN_INFO "JFFS2 version 2.2." -+#ifdef CONFIG_FS_JFFS2_NAND -+ " (NAND)" - #endif -+ " (C) 2001-2003 Red Hat, Inc.\n"); - -+ jffs2_inode_cachep = kmem_cache_create("jffs2_i", -+ sizeof(struct jffs2_inode_info), -+ 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, -+ jffs2_i_init_once, NULL); -+ if (!jffs2_inode_cachep) { -+ printk(KERN_ERR "JFFS2 error: Failed to initialise inode cache\n"); -+ return -ENOMEM; -+ } - ret = jffs2_zlib_init(); - if (ret) { - printk(KERN_ERR "JFFS2 error: Failed to initialise zlib workspaces\n"); -@@ -388,9 +333,10 @@ - - static void __exit exit_jffs2_fs(void) - { -+ unregister_filesystem(&jffs2_fs_type); - jffs2_destroy_slab_caches(); - jffs2_zlib_exit(); -- unregister_filesystem(&jffs2_fs_type); -+ kmem_cache_destroy(jffs2_inode_cachep); - } - - module_init(init_jffs2_fs); -diff -Nurb linux-mips-2.4.27/fs/jffs2/symlink.c linux/fs/jffs2/symlink.c ---- linux-mips-2.4.27/fs/jffs2/symlink.c 2002-06-27 00:36:20.000000000 +0200 -+++ linux/fs/jffs2/symlink.c 2004-11-19 10:25:12.129164832 +0100 -@@ -3,35 +3,11 @@ - * - * Copyright (C) 2001, 2002 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - -@@ -39,7 +15,6 @@ - #include <linux/kernel.h> - #include <linux/slab.h> - #include <linux/fs.h> --#include <linux/jffs2.h> - #include "nodelist.h" - - int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen); -@@ -47,45 +22,17 @@ - - struct inode_operations jffs2_symlink_inode_operations = - { -- readlink: jffs2_readlink, -- follow_link: jffs2_follow_link, -- setattr: jffs2_setattr -+ .readlink = jffs2_readlink, -+ .follow_link = jffs2_follow_link, -+ .setattr = jffs2_setattr - }; - --static char *jffs2_getlink(struct dentry *dentry) --{ -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode); -- char *buf; -- int ret; -- -- down(&f->sem); -- if (!f->metadata) { -- up(&f->sem); -- printk(KERN_NOTICE "No metadata for symlink inode #%lu\n", dentry->d_inode->i_ino); -- return ERR_PTR(-EINVAL); -- } -- buf = kmalloc(f->metadata->size+1, GFP_USER); -- if (!buf) { -- up(&f->sem); -- return ERR_PTR(-ENOMEM); -- } -- buf[f->metadata->size]=0; -- -- ret = jffs2_read_dnode(JFFS2_SB_INFO(dentry->d_inode->i_sb), f->metadata, buf, 0, f->metadata->size); -- up(&f->sem); -- if (ret) { -- kfree(buf); -- return ERR_PTR(ret); -- } -- return buf; -- --} - int jffs2_readlink(struct dentry *dentry, char *buffer, int buflen) - { - unsigned char *kbuf; - int ret; - -- kbuf = jffs2_getlink(dentry); -+ kbuf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); - -@@ -99,7 +46,7 @@ - unsigned char *buf; - int ret; - -- buf = jffs2_getlink(dentry); -+ buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode)); - - if (IS_ERR(buf)) - return PTR_ERR(buf); -diff -Nurb linux-mips-2.4.27/fs/jffs2/wbuf.c linux/fs/jffs2/wbuf.c ---- linux-mips-2.4.27/fs/jffs2/wbuf.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/jffs2/wbuf.c 2004-11-19 10:25:12.131164528 +0100 -@@ -0,0 +1,1156 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001-2003 Red Hat, Inc. -+ * -+ * Created by David Woodhouse <dwmw2@redhat.com> -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ * -+ * $Id$ -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/slab.h> -+#include <linux/mtd/mtd.h> -+#include <linux/crc32.h> -+#include <linux/mtd/nand.h> -+#include "nodelist.h" -+ -+/* For testing write failures */ -+#undef BREAKME -+#undef BREAKMEHEADER -+ -+#ifdef BREAKME -+static unsigned char *brokenbuf; -+#endif -+ -+/* max. erase failures before we mark a block bad */ -+#define MAX_ERASE_FAILURES 5 -+ -+/* two seconds timeout for timed wbuf-flushing */ -+#define WBUF_FLUSH_TIMEOUT 2 * HZ -+ -+struct jffs2_inodirty { -+ uint32_t ino; -+ struct jffs2_inodirty *next; -+}; -+ -+static struct jffs2_inodirty inodirty_nomem; -+ -+static int jffs2_wbuf_pending_for_ino(struct jffs2_sb_info *c, uint32_t ino) -+{ -+ struct jffs2_inodirty *this = c->wbuf_inodes; -+ -+ /* If a malloc failed, consider _everything_ dirty */ -+ if (this == &inodirty_nomem) -+ return 1; -+ -+ /* If ino == 0, _any_ non-GC writes mean 'yes' */ -+ if (this && !ino) -+ return 1; -+ -+ /* Look to see if the inode in question is pending in the wbuf */ -+ while (this) { -+ if (this->ino == ino) -+ return 1; -+ this = this->next; -+ } -+ return 0; -+} -+ -+static void jffs2_clear_wbuf_ino_list(struct jffs2_sb_info *c) -+{ -+ struct jffs2_inodirty *this; -+ -+ this = c->wbuf_inodes; -+ -+ if (this != &inodirty_nomem) { -+ while (this) { -+ struct jffs2_inodirty *next = this->next; -+ kfree(this); -+ this = next; -+ } -+ } -+ c->wbuf_inodes = NULL; -+} -+ -+static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino) -+{ -+ struct jffs2_inodirty *new; -+ -+ /* Mark the superblock dirty so that kupdated will flush... */ -+ OFNI_BS_2SFFJ(c)->s_dirt = 1; -+ -+ if (jffs2_wbuf_pending_for_ino(c, ino)) -+ return; -+ -+ new = kmalloc(sizeof(*new), GFP_KERNEL); -+ if (!new) { -+ D1(printk(KERN_DEBUG "No memory to allocate inodirty. Fallback to all considered dirty\n")); -+ jffs2_clear_wbuf_ino_list(c); -+ c->wbuf_inodes = &inodirty_nomem; -+ return; -+ } -+ new->ino = ino; -+ new->next = c->wbuf_inodes; -+ c->wbuf_inodes = new; -+ return; -+} -+ -+static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) -+{ -+ struct list_head *this, *next; -+ static int n; -+ -+ if (list_empty(&c->erasable_pending_wbuf_list)) -+ return; -+ -+ list_for_each_safe(this, next, &c->erasable_pending_wbuf_list) { -+ struct jffs2_eraseblock *jeb = list_entry(this, struct jffs2_eraseblock, list); -+ -+ D1(printk(KERN_DEBUG "Removing eraseblock at 0x%08x from erasable_pending_wbuf_list...\n", jeb->offset)); -+ list_del(this); -+ if ((jiffies + (n++)) & 127) { -+ /* Most of the time, we just erase it immediately. Otherwise we -+ spend ages scanning it on mount, etc. */ -+ D1(printk(KERN_DEBUG "...and adding to erase_pending_list\n")); -+ list_add_tail(&jeb->list, &c->erase_pending_list); -+ c->nr_erasing_blocks++; -+ jffs2_erase_pending_trigger(c); -+ } else { -+ /* Sometimes, however, we leave it elsewhere so it doesn't get -+ immediately reused, and we spread the load a bit. */ -+ D1(printk(KERN_DEBUG "...and adding to erasable_list\n")); -+ list_add_tail(&jeb->list, &c->erasable_list); -+ } -+ } -+} -+ -+/* Recover from failure to write wbuf. Recover the nodes up to the -+ * wbuf, not the one which we were starting to try to write. */ -+ -+static void jffs2_wbuf_recover(struct jffs2_sb_info *c) -+{ -+ struct jffs2_eraseblock *jeb, *new_jeb; -+ struct jffs2_raw_node_ref **first_raw, **raw; -+ size_t retlen; -+ int ret; -+ unsigned char *buf; -+ uint32_t start, end, ofs, len; -+ -+ spin_lock(&c->erase_completion_lock); -+ -+ jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; -+ -+ D1(printk("About to refile bad block at %08x\n", jeb->offset)); -+ -+ D2(jffs2_dump_block_lists(c)); -+ /* File the existing block on the bad_used_list.... */ -+ if (c->nextblock == jeb) -+ c->nextblock = NULL; -+ else /* Not sure this should ever happen... need more coffee */ -+ list_del(&jeb->list); -+ if (jeb->first_node) { -+ D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset)); -+ list_add(&jeb->list, &c->bad_used_list); -+ } else { -+ BUG(); -+ /* It has to have had some nodes or we couldn't be here */ -+ D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset)); -+ list_add(&jeb->list, &c->erase_pending_list); -+ c->nr_erasing_blocks++; -+ jffs2_erase_pending_trigger(c); -+ } -+ D2(jffs2_dump_block_lists(c)); -+ -+ /* Adjust its size counts accordingly */ -+ c->wasted_size += jeb->free_size; -+ c->free_size -= jeb->free_size; -+ jeb->wasted_size += jeb->free_size; -+ jeb->free_size = 0; -+ -+ ACCT_SANITY_CHECK(c,jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ -+ /* Find the first node to be recovered, by skipping over every -+ node which ends before the wbuf starts, or which is obsolete. */ -+ first_raw = &jeb->first_node; -+ while (*first_raw && -+ (ref_obsolete(*first_raw) || -+ (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { -+ D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", -+ ref_offset(*first_raw), ref_flags(*first_raw), -+ (ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw)), -+ c->wbuf_ofs)); -+ first_raw = &(*first_raw)->next_phys; -+ } -+ -+ if (!*first_raw) { -+ /* All nodes were obsolete. Nothing to recover. */ -+ D1(printk(KERN_DEBUG "No non-obsolete nodes to be recovered. Just filing block bad\n")); -+ spin_unlock(&c->erase_completion_lock); -+ return; -+ } -+ -+ start = ref_offset(*first_raw); -+ end = ref_offset(*first_raw) + ref_totlen(c, jeb, *first_raw); -+ -+ /* Find the last node to be recovered */ -+ raw = first_raw; -+ while ((*raw)) { -+ if (!ref_obsolete(*raw)) -+ end = ref_offset(*raw) + ref_totlen(c, jeb, *raw); -+ -+ raw = &(*raw)->next_phys; -+ } -+ spin_unlock(&c->erase_completion_lock); -+ -+ D1(printk(KERN_DEBUG "wbuf recover %08x-%08x\n", start, end)); -+ -+ buf = NULL; -+ if (start < c->wbuf_ofs) { -+ /* First affected node was already partially written. -+ * Attempt to reread the old data into our buffer. */ -+ -+ buf = kmalloc(end - start, GFP_KERNEL); -+ if (!buf) { -+ printk(KERN_CRIT "Malloc failure in wbuf recovery. Data loss ensues.\n"); -+ -+ goto read_failed; -+ } -+ -+ /* Do the read... */ -+ ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); -+ if (ret == -EIO && retlen == c->wbuf_ofs - start) { -+ /* ECC recovered */ -+ ret = 0; -+ } -+ if (ret || retlen != c->wbuf_ofs - start) { -+ printk(KERN_CRIT "Old data are already lost in wbuf recovery. Data loss ensues.\n"); -+ -+ kfree(buf); -+ buf = NULL; -+ read_failed: -+ first_raw = &(*first_raw)->next_phys; -+ /* If this was the only node to be recovered, give up */ -+ if (!(*first_raw)) -+ return; -+ -+ /* It wasn't. Go on and try to recover nodes complete in the wbuf */ -+ start = ref_offset(*first_raw); -+ } else { -+ /* Read succeeded. Copy the remaining data from the wbuf */ -+ memcpy(buf + (c->wbuf_ofs - start), c->wbuf, end - c->wbuf_ofs); -+ } -+ } -+ /* OK... we're to rewrite (end-start) bytes of data from first_raw onwards. -+ Either 'buf' contains the data, or we find it in the wbuf */ -+ -+ -+ /* ... and get an allocation of space from a shiny new block instead */ -+ ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); -+ if (ret) { -+ printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); -+ if (buf) -+ kfree(buf); -+ return; -+ } -+ if (end-start >= c->wbuf_pagesize) { -+ /* Need to do another write immediately. This, btw, -+ means that we'll be writing from 'buf' and not from -+ the wbuf. Since if we're writing from the wbuf there -+ won't be more than a wbuf full of data, now will -+ there? :) */ -+ -+ uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); -+ -+ D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", -+ towrite, ofs)); -+ -+#ifdef BREAKMEHEADER -+ static int breakme; -+ if (breakme++ == 20) { -+ printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs); -+ breakme = 0; -+ c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, -+ brokenbuf, NULL, c->oobinfo); -+ ret = -EIO; -+ } else -+#endif -+ ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, -+ buf, NULL, c->oobinfo); -+ -+ if (ret || retlen != towrite) { -+ /* Argh. We tried. Really we did. */ -+ printk(KERN_CRIT "Recovery of wbuf failed due to a second write error\n"); -+ kfree(buf); -+ -+ if (retlen) { -+ struct jffs2_raw_node_ref *raw2; -+ -+ raw2 = jffs2_alloc_raw_node_ref(); -+ if (!raw2) -+ return; -+ -+ raw2->flash_offset = ofs | REF_OBSOLETE; -+ raw2->__totlen = ref_totlen(c, jeb, *first_raw); -+ raw2->next_phys = NULL; -+ raw2->next_in_ino = NULL; -+ -+ jffs2_add_physical_node_ref(c, raw2); -+ } -+ return; -+ } -+ printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs); -+ -+ c->wbuf_len = (end - start) - towrite; -+ c->wbuf_ofs = ofs + towrite; -+ memcpy(c->wbuf, buf + towrite, c->wbuf_len); -+ /* Don't muck about with c->wbuf_inodes. False positives are harmless. */ -+ -+ kfree(buf); -+ } else { -+ /* OK, now we're left with the dregs in whichever buffer we're using */ -+ if (buf) { -+ memcpy(c->wbuf, buf, end-start); -+ kfree(buf); -+ } else { -+ memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start); -+ } -+ c->wbuf_ofs = ofs; -+ c->wbuf_len = end - start; -+ } -+ -+ /* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */ -+ new_jeb = &c->blocks[ofs / c->sector_size]; -+ -+ spin_lock(&c->erase_completion_lock); -+ if (new_jeb->first_node) { -+ /* Odd, but possible with ST flash later maybe */ -+ new_jeb->last_node->next_phys = *first_raw; -+ } else { -+ new_jeb->first_node = *first_raw; -+ } -+ -+ raw = first_raw; -+ while (*raw) { -+ uint32_t rawlen = ref_totlen(c, jeb, *raw); -+ -+ D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n", -+ rawlen, ref_offset(*raw), ref_flags(*raw), ofs)); -+ -+ if (ref_obsolete(*raw)) { -+ /* Shouldn't really happen much */ -+ new_jeb->dirty_size += rawlen; -+ new_jeb->free_size -= rawlen; -+ c->dirty_size += rawlen; -+ } else { -+ new_jeb->used_size += rawlen; -+ new_jeb->free_size -= rawlen; -+ jeb->dirty_size += rawlen; -+ jeb->used_size -= rawlen; -+ c->dirty_size += rawlen; -+ } -+ c->free_size -= rawlen; -+ (*raw)->flash_offset = ofs | ref_flags(*raw); -+ ofs += rawlen; -+ new_jeb->last_node = *raw; -+ -+ raw = &(*raw)->next_phys; -+ } -+ -+ /* Fix up the original jeb now it's on the bad_list */ -+ *first_raw = NULL; -+ if (first_raw == &jeb->first_node) { -+ jeb->last_node = NULL; -+ D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset)); -+ list_del(&jeb->list); -+ list_add(&jeb->list, &c->erase_pending_list); -+ c->nr_erasing_blocks++; -+ jffs2_erase_pending_trigger(c); -+ } -+ else -+ jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys); -+ -+ ACCT_SANITY_CHECK(c,jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ -+ ACCT_SANITY_CHECK(c,new_jeb); -+ D1(ACCT_PARANOIA_CHECK(new_jeb)); -+ -+ spin_unlock(&c->erase_completion_lock); -+ -+ D1(printk(KERN_DEBUG "wbuf recovery completed OK\n")); -+} -+ -+/* Meaning of pad argument: -+ 0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway. -+ 1: Pad, do not adjust nextblock free_size -+ 2: Pad, adjust nextblock free_size -+*/ -+static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) -+{ -+ int ret; -+ size_t retlen; -+ -+ /* Nothing to do if not NAND flash. In particular, we shouldn't -+ del_timer() the timer we never initialised. */ -+ if (jffs2_can_mark_obsolete(c)) -+ return 0; -+ -+ if (!down_trylock(&c->alloc_sem)) { -+ up(&c->alloc_sem); -+ printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n"); -+ BUG(); -+ } -+ -+ if(!c->wbuf || !c->wbuf_len) -+ return 0; -+ -+ /* claim remaining space on the page -+ this happens, if we have a change to a new block, -+ or if fsync forces us to flush the writebuffer. -+ if we have a switch to next page, we will not have -+ enough remaining space for this. -+ */ -+ if (pad) { -+ c->wbuf_len = PAD(c->wbuf_len); -+ -+ if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) { -+ struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len); -+ padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING); -+ padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len); -+ padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4)); -+ } -+ } -+ /* else jffs2_flash_writev has actually filled in the rest of the -+ buffer for us, and will deal with the node refs etc. later. */ -+ -+#ifdef BREAKME -+ static int breakme; -+ if (breakme++ == 20) { -+ printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs); -+ breakme = 0; -+ c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, -+ &retlen, brokenbuf, NULL, c->oobinfo); -+ ret = -EIO; -+ } else -+#endif -+ ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); -+ -+ -+ if (ret || retlen != c->wbuf_pagesize) { -+ if (ret) -+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret); -+ else { -+ printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", -+ retlen, c->wbuf_pagesize); -+ ret = -EIO; -+ } -+ -+ jffs2_wbuf_recover(c); -+ -+ return ret; -+ } -+ -+ /* Adjusting free size of next block only, if it's called from fsync ! */ -+ if (pad == 2) { -+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of c->nextblock\n")); -+ spin_lock(&c->erase_completion_lock); -+ if (!c->nextblock) -+ BUG(); -+ /* wbuf_pagesize - wbuf_len is the amount of space that's to be -+ padded. If there is less free space in the block than that, -+ something screwed up */ -+ if (c->nextblock->free_size < (c->wbuf_pagesize - c->wbuf_len)) { -+ printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n", -+ c->wbuf_ofs, c->wbuf_len, c->wbuf_pagesize-c->wbuf_len); -+ printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n", -+ c->nextblock->offset, c->nextblock->free_size); -+ BUG(); -+ } -+ c->nextblock->free_size -= (c->wbuf_pagesize - c->wbuf_len); -+ c->free_size -= (c->wbuf_pagesize - c->wbuf_len); -+ c->nextblock->wasted_size += (c->wbuf_pagesize - c->wbuf_len); -+ c->wasted_size += (c->wbuf_pagesize - c->wbuf_len); -+ spin_unlock(&c->erase_completion_lock); -+ } -+ -+ /* Stick any now-obsoleted blocks on the erase_pending_list */ -+ spin_lock(&c->erase_completion_lock); -+ jffs2_refile_wbuf_blocks(c); -+ jffs2_clear_wbuf_ino_list(c); -+ spin_unlock(&c->erase_completion_lock); -+ -+ memset(c->wbuf,0xff,c->wbuf_pagesize); -+ /* adjust write buffer offset, else we get a non contiguous write bug */ -+ c->wbuf_ofs += c->wbuf_pagesize; -+ c->wbuf_len = 0; -+ return 0; -+} -+ -+/* Trigger garbage collection to flush the write-buffer. -+ If ino arg is zero, do it if _any_ real (i.e. not GC) writes are -+ outstanding. If ino arg non-zero, do it only if a write for the -+ given inode is outstanding. */ -+int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino) -+{ -+ uint32_t old_wbuf_ofs; -+ uint32_t old_wbuf_len; -+ int ret = 0; -+ -+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino)); -+ -+ down(&c->alloc_sem); -+ if (!jffs2_wbuf_pending_for_ino(c, ino)) { -+ D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino)); -+ up(&c->alloc_sem); -+ return 0; -+ } -+ -+ old_wbuf_ofs = c->wbuf_ofs; -+ old_wbuf_len = c->wbuf_len; -+ -+ if (c->unchecked_size) { -+ /* GC won't make any progress for a while */ -+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n")); -+ ret = __jffs2_flush_wbuf(c, 2); -+ } else while (old_wbuf_len && -+ old_wbuf_ofs == c->wbuf_ofs) { -+ -+ up(&c->alloc_sem); -+ -+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n")); -+ -+ ret = jffs2_garbage_collect_pass(c); -+ if (ret) { -+ /* GC failed. Flush it with padding instead */ -+ down(&c->alloc_sem); -+ ret = __jffs2_flush_wbuf(c, 2); -+ break; -+ } -+ down(&c->alloc_sem); -+ } -+ -+ D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n")); -+ -+ up(&c->alloc_sem); -+ return ret; -+} -+ -+/* Pad write-buffer to end and write it, wasting space. */ -+int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) -+{ -+ return __jffs2_flush_wbuf(c, 1); -+} -+ -+ -+#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) -+#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) -+int jffs2_flash_writev(struct jffs2_sb_info *c, const struct iovec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) -+{ -+ struct iovec outvecs[3]; -+ uint32_t totlen = 0; -+ uint32_t split_ofs = 0; -+ uint32_t old_totlen; -+ int ret, splitvec = -1; -+ int invec, outvec; -+ size_t wbuf_retlen; -+ unsigned char *wbuf_ptr; -+ size_t donelen = 0; -+ uint32_t outvec_to = to; -+ -+ /* If not NAND flash, don't bother */ -+ if (!c->wbuf) -+ return jffs2_flash_direct_writev(c, invecs, count, to, retlen); -+ -+ /* If wbuf_ofs is not initialized, set it to target address */ -+ if (c->wbuf_ofs == 0xFFFFFFFF) { -+ c->wbuf_ofs = PAGE_DIV(to); -+ c->wbuf_len = PAGE_MOD(to); -+ memset(c->wbuf,0xff,c->wbuf_pagesize); -+ } -+ -+ /* Sanity checks on target address. -+ It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), -+ and it's permitted to write at the beginning of a new -+ erase block. Anything else, and you die. -+ New block starts at xxx000c (0-b = block header) -+ */ -+ if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) { -+ /* It's a write to a new block */ -+ if (c->wbuf_len) { -+ D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); -+ ret = jffs2_flush_wbuf_pad(c); -+ if (ret) { -+ /* the underlying layer has to check wbuf_len to do the cleanup */ -+ D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret)); -+ *retlen = 0; -+ return ret; -+ } -+ } -+ /* set pointer to new block */ -+ c->wbuf_ofs = PAGE_DIV(to); -+ c->wbuf_len = PAGE_MOD(to); -+ } -+ -+ if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { -+ /* We're not writing immediately after the writebuffer. Bad. */ -+ printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lx\n", (unsigned long)to); -+ if (c->wbuf_len) -+ printk(KERN_CRIT "wbuf was previously %08x-%08x\n", -+ c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len); -+ BUG(); -+ } -+ -+ /* Note outvecs[3] above. We know count is never greater than 2 */ -+ if (count > 2) { -+ printk(KERN_CRIT "jffs2_flash_writev(): count is %ld\n", count); -+ BUG(); -+ } -+ -+ invec = 0; -+ outvec = 0; -+ -+ -+ /* Fill writebuffer first, if already in use */ -+ if (c->wbuf_len) { -+ uint32_t invec_ofs = 0; -+ -+ /* adjust alignment offset */ -+ if (c->wbuf_len != PAGE_MOD(to)) { -+ c->wbuf_len = PAGE_MOD(to); -+ /* take care of alignment to next page */ -+ if (!c->wbuf_len) -+ c->wbuf_len = c->wbuf_pagesize; -+ } -+ -+ while(c->wbuf_len < c->wbuf_pagesize) { -+ uint32_t thislen; -+ -+ if (invec == count) -+ goto alldone; -+ -+ thislen = c->wbuf_pagesize - c->wbuf_len; -+ -+ if (thislen >= invecs[invec].iov_len) -+ thislen = invecs[invec].iov_len; -+ -+ invec_ofs = thislen; -+ -+ memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen); -+ c->wbuf_len += thislen; -+ donelen += thislen; -+ /* Get next invec, if actual did not fill the buffer */ -+ if (c->wbuf_len < c->wbuf_pagesize) -+ invec++; -+ } -+ -+ /* write buffer is full, flush buffer */ -+ ret = __jffs2_flush_wbuf(c, 0); -+ if (ret) { -+ /* the underlying layer has to check wbuf_len to do the cleanup */ -+ D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret)); -+ /* Retlen zero to make sure our caller doesn't mark the space dirty. -+ We've already done everything that's necessary */ -+ *retlen = 0; -+ return ret; -+ } -+ outvec_to += donelen; -+ c->wbuf_ofs = outvec_to; -+ -+ /* All invecs done ? */ -+ if (invec == count) -+ goto alldone; -+ -+ /* Set up the first outvec, containing the remainder of the -+ invec we partially used */ -+ if (invecs[invec].iov_len > invec_ofs) { -+ outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs; -+ totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs; -+ if (totlen > c->wbuf_pagesize) { -+ splitvec = outvec; -+ split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen); -+ } -+ outvec++; -+ } -+ invec++; -+ } -+ -+ /* OK, now we've flushed the wbuf and the start of the bits -+ we have been asked to write, now to write the rest.... */ -+ -+ /* totlen holds the amount of data still to be written */ -+ old_totlen = totlen; -+ for ( ; invec < count; invec++,outvec++ ) { -+ outvecs[outvec].iov_base = invecs[invec].iov_base; -+ totlen += outvecs[outvec].iov_len = invecs[invec].iov_len; -+ if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) { -+ splitvec = outvec; -+ split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen); -+ old_totlen = totlen; -+ } -+ } -+ -+ /* Now the outvecs array holds all the remaining data to write */ -+ /* Up to splitvec,split_ofs is to be written immediately. The rest -+ goes into the (now-empty) wbuf */ -+ -+ if (splitvec != -1) { -+ uint32_t remainder; -+ int ret; -+ -+ remainder = outvecs[splitvec].iov_len - split_ofs; -+ outvecs[splitvec].iov_len = split_ofs; -+ -+ /* We did cross a page boundary, so we write some now */ -+ ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); -+ if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { -+ /* At this point we have no problem, -+ c->wbuf is empty. -+ */ -+ *retlen = donelen; -+ return ret; -+ } -+ -+ donelen += wbuf_retlen; -+ c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); -+ -+ if (remainder) { -+ outvecs[splitvec].iov_base += split_ofs; -+ outvecs[splitvec].iov_len = remainder; -+ } else { -+ splitvec++; -+ } -+ -+ } else { -+ splitvec = 0; -+ } -+ -+ /* Now splitvec points to the start of the bits we have to copy -+ into the wbuf */ -+ wbuf_ptr = c->wbuf; -+ -+ for ( ; splitvec < outvec; splitvec++) { -+ /* Don't copy the wbuf into itself */ -+ if (outvecs[splitvec].iov_base == c->wbuf) -+ continue; -+ memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len); -+ wbuf_ptr += outvecs[splitvec].iov_len; -+ donelen += outvecs[splitvec].iov_len; -+ } -+ c->wbuf_len = wbuf_ptr - c->wbuf; -+ -+ /* If there's a remainder in the wbuf and it's a non-GC write, -+ remember that the wbuf affects this ino */ -+alldone: -+ *retlen = donelen; -+ -+ if (c->wbuf_len && ino) -+ jffs2_wbuf_dirties_inode(c, ino); -+ -+ return 0; -+} -+ -+/* -+ * This is the entry for flash write. -+ * Check, if we work on NAND FLASH, if so build an iovec and write it via vritev -+*/ -+int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) -+{ -+ struct iovec vecs[1]; -+ -+ if (jffs2_can_mark_obsolete(c)) -+ return c->mtd->write(c->mtd, ofs, len, retlen, buf); -+ -+ vecs[0].iov_base = (unsigned char *) buf; -+ vecs[0].iov_len = len; -+ return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0); -+} -+ -+/* -+ Handle readback from writebuffer and ECC failure return -+*/ -+int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf) -+{ -+ loff_t orbf = 0, owbf = 0, lwbf = 0; -+ int ret; -+ -+ /* Read flash */ -+ if (!jffs2_can_mark_obsolete(c)) { -+ ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); -+ -+ if ( (ret == -EIO) && (*retlen == len) ) { -+ printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", -+ len, ofs); -+ /* -+ * We have the raw data without ECC correction in the buffer, maybe -+ * we are lucky and all data or parts are correct. We check the node. -+ * If data are corrupted node check will sort it out. -+ * We keep this block, it will fail on write or erase and the we -+ * mark it bad. Or should we do that now? But we should give him a chance. -+ * Maybe we had a system crash or power loss before the ecc write or -+ * a erase was completed. -+ * So we return success. :) -+ */ -+ ret = 0; -+ } -+ } else -+ return c->mtd->read(c->mtd, ofs, len, retlen, buf); -+ -+ /* if no writebuffer available or write buffer empty, return */ -+ if (!c->wbuf_pagesize || !c->wbuf_len) -+ return ret; -+ -+ /* if we read in a different block, return */ -+ if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) -+ return ret; -+ -+ if (ofs >= c->wbuf_ofs) { -+ owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ -+ if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ -+ return ret; -+ lwbf = c->wbuf_len - owbf; /* number of bytes to copy */ -+ if (lwbf > len) -+ lwbf = len; -+ } else { -+ orbf = (c->wbuf_ofs - ofs); /* offset in read buffer */ -+ if (orbf > len) /* is write beyond write buffer ? */ -+ return ret; -+ lwbf = len - orbf; /* number of bytes to copy */ -+ if (lwbf > c->wbuf_len) -+ lwbf = c->wbuf_len; -+ } -+ if (lwbf > 0) -+ memcpy(buf+orbf,c->wbuf+owbf,lwbf); -+ -+ return ret; -+} -+ -+/* -+ * Check, if the out of band area is empty -+ */ -+int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int mode) -+{ -+ unsigned char *buf; -+ int ret = 0; -+ int i,len,page; -+ size_t retlen; -+ int oob_size; -+ -+ oob_size = c->mtd->oobsize; -+ -+ /* allocate a buffer for all oob data in this sector */ -+ len = 4 * oob_size; -+ buf = kmalloc(len, GFP_KERNEL); -+ if (!buf) { -+ printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n"); -+ return -ENOMEM; -+ } -+ /* -+ * if mode = 0, we scan for a total empty oob area, else we have -+ * to take care of the cleanmarker in the first page of the block -+ */ -+ ret = jffs2_flash_read_oob(c, jeb->offset, len , &retlen, buf); -+ if (ret) { -+ D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); -+ goto out; -+ } -+ -+ if (retlen < len) { -+ D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " -+ "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); -+ ret = -EIO; -+ goto out; -+ } -+ -+ /* Special check for first two pages */ -+ for (page = 0; page < 2 * oob_size; page += oob_size) { -+ /* Check for bad block marker */ -+ if (buf[page+c->badblock_pos] != 0xff) { -+ D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Bad or failed block at %08x\n",jeb->offset)); -+ /* Return 2 for bad and 3 for failed block -+ bad goes to list_bad and failed to list_erase */ -+ ret = (!page) ? 2 : 3; -+ goto out; -+ } -+ for(i = 0; i < oob_size ; i++) { -+ /* Yeah, we know about the cleanmarker. */ -+ if (mode && i >= c->fsdata_pos && -+ i < c->fsdata_pos+c->fsdata_len) -+ continue; -+ -+ if (buf[page+i] != 0xFF) { -+ D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n", -+ buf[page+i], page+i, jeb->offset)); -+ ret = 1; -+ goto out; -+ } -+ } -+ /* only the first page can contain a cleanmarker !*/ -+ mode = 0; -+ } -+ -+ /* we know, we are aligned :) */ -+ for (; page < len; page += sizeof(long)) { -+ unsigned long dat = *(unsigned long *)(&buf[page]); -+ if(dat != -1) { -+ ret = 1; -+ goto out; -+ } -+ } -+ -+out: -+ kfree(buf); -+ -+ return ret; -+} -+ -+/* -+* Scan for a valid cleanmarker and for bad blocks -+* For virtual blocks (concatenated physical blocks) check the cleanmarker -+* only in the first page of the first physical block, but scan for bad blocks in all -+* physical blocks -+*/ -+int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) -+{ -+ struct jffs2_unknown_node n; -+ unsigned char buf[32]; -+ unsigned char *p; -+ int ret, i, cnt, retval = 0; -+ size_t retlen, offset; -+ int oob_size; -+ -+ offset = jeb->offset; -+ oob_size = c->mtd->oobsize; -+ -+ /* Loop through the physical blocks */ -+ for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) { -+ /* -+ * We read oob data from page 0 and 1 of the block. -+ * page 0 contains cleanmarker and badblock info -+ * page 1 contains failure count of this block -+ */ -+ ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf); -+ -+ if (ret) { -+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); -+ return ret; -+ } -+ if (retlen < (oob_size << 1)) { -+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset)); -+ return -EIO; -+ } -+ -+ /* Check for bad block marker */ -+ if (buf[c->badblock_pos] != 0xff) { -+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x (has %02x %02x in badblock_pos %d\n", -+ jeb->offset, buf[c->badblock_pos], buf[c->badblock_pos + oob_size], c->badblock_pos)); -+ return 2; -+ } -+ -+ /* Check for failure counter in the second page */ -+ if (buf[c->badblock_pos + oob_size] != 0xff) { -+ D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[c->badblock_pos + oob_size])); -+ return 3; -+ } -+ -+ /* Check cleanmarker only on the first physical block */ -+ if (!cnt) { -+ n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); -+ n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); -+ n.totlen = cpu_to_je32 (8); -+ p = (unsigned char *) &n; -+ -+ for (i = 0; i < c->fsdata_len; i++) { -+ if (buf[c->fsdata_pos + i] != p[i]) { -+ retval = 1; -+ } -+ } -+ D1(if (retval == 1) { -+ printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset); -+ printk(KERN_WARNING "OOB at %08x was ", offset); -+ for (i=0; i < oob_size; i++) { -+ printk("%02x ", buf[i]); -+ } -+ printk("\n"); -+ }) -+ } -+ offset += c->mtd->erasesize; -+ } -+ return retval; -+} -+ -+int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) -+{ -+ struct jffs2_unknown_node n; -+ int ret; -+ size_t retlen; -+ -+ n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); -+ n.totlen = cpu_to_je32(8); -+ -+ ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n); -+ -+ if (ret) { -+ D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); -+ return ret; -+ } -+ if (retlen != c->fsdata_len) { -+ D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len)); -+ return ret; -+ } -+ return 0; -+} -+ -+/* -+ * We try to get the failure count of this block. -+ */ -+int jffs2_nand_read_failcnt(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { -+ -+ unsigned char buf[16]; -+ int ret; -+ size_t retlen; -+ int oob_size; -+ -+ oob_size = c->mtd->oobsize; -+ -+ ret = c->mtd->read_oob(c->mtd, jeb->offset + c->mtd->oobblock, oob_size , &retlen, buf); -+ -+ if (ret) { -+ D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); -+ return ret; -+ } -+ -+ if (retlen < oob_size) { -+ D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset)); -+ return -EIO; -+ } -+ -+ jeb->bad_count = buf[c->badblock_pos]; -+ return 0; -+} -+ -+/* -+ * On NAND we try to mark this block bad. We try to write how often -+ * the block was erased and mark it finaly bad, if the count -+ * is > MAX_ERASE_FAILURES. We read this information on mount ! -+ * jeb->bad_count contains the count before this erase. -+ * Don't care about failures. This block remains on the erase-pending -+ * or badblock list as long as nobody manipulates the flash with -+ * a bootloader or something like that. -+ */ -+ -+int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) -+{ -+ unsigned char buf = 0x0; -+ int ret; -+ size_t retlen; -+ -+ /* if the count is < max, we try to write the counter to the 2nd page oob area */ -+ if( ++jeb->bad_count < MAX_ERASE_FAILURES) { -+ buf = (unsigned char)jeb->bad_count; -+ c->badblock_pos += c->mtd->oobblock; -+ } -+ -+ ret = jffs2_flash_write_oob(c, jeb->offset + c->badblock_pos, 1, &retlen, &buf); -+ -+ if (ret) { -+ D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); -+ return ret; -+ } -+ if (retlen != 1) { -+ D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %zd not 1\n", jeb->offset, retlen)); -+ return ret; -+ } -+ return 0; -+} -+ -+#define JFFS2_OOB_ECCPOS0 0 -+#define JFFS2_OOB_ECCPOS1 1 -+#define JFFS2_OOB_ECCPOS2 2 -+#define JFFS2_OOB_ECCPOS3 3 -+#define JFFS2_OOB_ECCPOS4 6 -+#define JFFS2_OOB_ECCPOS5 7 -+ -+#define NAND_JFFS2_OOB8_FSDAPOS 6 -+#define NAND_JFFS2_OOB16_FSDAPOS 8 -+#define NAND_JFFS2_OOB8_FSDALEN 2 -+#define NAND_JFFS2_OOB16_FSDALEN 8 -+ -+static struct nand_oobinfo jffs2_oobinfo_swecc = { -+ .useecc = 1, -+ .eccpos = {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2, -+ JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5} -+}; -+ -+static struct nand_oobinfo jffs2_oobinfo_docecc = { -+ .useecc = 1, -+ .eccpos = {0,1,2,3,4,5} -+}; -+ -+ -+ -+int jffs2_nand_flash_setup(struct jffs2_sb_info *c) -+{ -+ /* Cleanmarker is out-of-band, so inline size zero */ -+ c->cleanmarker_size = 0; -+ -+ /* Initialise write buffer */ -+ c->wbuf_pagesize = c->mtd->oobblock; -+ c->wbuf_ofs = 0xFFFFFFFF; -+ -+ /* FIXME: If we had a generic way of describing the hardware's -+ use of OOB area, we could perhaps make this generic too. */ -+ switch(c->mtd->ecctype) { -+ case MTD_ECC_SW: -+ D1(printk(KERN_DEBUG "JFFS2 using software ECC\n")); -+ c->oobinfo = &jffs2_oobinfo_swecc; -+ if (c->mtd->oobsize == 8) { -+ c->fsdata_pos = NAND_JFFS2_OOB8_FSDAPOS; -+ c->fsdata_len = NAND_JFFS2_OOB8_FSDALEN; -+ } else { -+ c->fsdata_pos = NAND_JFFS2_OOB16_FSDAPOS; -+ c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN; -+ } -+ c->badblock_pos = NAND_BADBLOCK_POS; -+ break; -+ -+ case MTD_ECC_RS_DiskOnChip: -+ D1(printk(KERN_DEBUG "JFFS2 using DiskOnChip hardware ECC\n")); -+ c->oobinfo = &jffs2_oobinfo_docecc; -+ c->fsdata_pos = 6; -+ c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN; -+ c->badblock_pos = 15; -+ break; -+ -+ default: -+ printk("JFFS2 doesn't yet know how to handle ECC type %d\n", -+ c->mtd->ecctype); -+ return -EINVAL; -+ } -+ -+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); -+ if (!c->wbuf) -+ return -ENOMEM; -+ -+#ifdef BREAKME -+ if (!brokenbuf) -+ brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); -+ if (!brokenbuf) { -+ kfree(c->wbuf); -+ return -ENOMEM; -+ } -+ memset(brokenbuf, 0xdb, c->wbuf_pagesize); -+#endif -+ return 0; -+} -+ -+void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) -+{ -+ kfree(c->wbuf); -+} -diff -Nurb linux-mips-2.4.27/fs/jffs2/write.c linux/fs/jffs2/write.c ---- linux-mips-2.4.27/fs/jffs2/write.c 2003-11-17 02:07:44.000000000 +0100 -+++ linux/fs/jffs2/write.c 2004-11-19 10:25:12.132164376 +0100 -@@ -1,154 +1,70 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in this directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #include <linux/kernel.h> - #include <linux/fs.h> --#include <linux/jffs2.h> -+#include <linux/crc32.h> -+#include <linux/slab.h> -+#include <linux/pagemap.h> - #include <linux/mtd/mtd.h> - #include "nodelist.h" --#include <linux/crc32.h> - --/* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, -- fill in the raw_inode while you're at it. */ --struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri) -+ -+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri) - { -- struct inode *inode; -- struct super_block *sb = dir_i->i_sb; - struct jffs2_inode_cache *ic; -- struct jffs2_sb_info *c; -- struct jffs2_inode_info *f; -- -- D1(printk(KERN_DEBUG "jffs2_new_inode(): dir_i %ld, mode 0x%x\n", dir_i->i_ino, mode)); -- -- c = JFFS2_SB_INFO(sb); -- memset(ri, 0, sizeof(*ri)); - - ic = jffs2_alloc_inode_cache(); - if (!ic) { -- return ERR_PTR(-ENOMEM); -+ return -ENOMEM; - } -- memset(ic, 0, sizeof(*ic)); -- -- inode = new_inode(sb); - -- if (!inode) { -- jffs2_free_inode_cache(ic); -- return ERR_PTR(-ENOMEM); -- } -- -- /* Alloc jffs2_inode_info when that's split in 2.5 */ -+ memset(ic, 0, sizeof(*ic)); - -- f = JFFS2_INODE_INFO(inode); -- memset(f, 0, sizeof(*f)); - init_MUTEX_LOCKED(&f->sem); - f->inocache = ic; -- inode->i_nlink = f->inocache->nlink = 1; -+ f->inocache->nlink = 1; - f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; -- f->inocache->ino = ri->ino = inode->i_ino = ++c->highest_ino; -- D1(printk(KERN_DEBUG "jffs2_new_inode(): Assigned ino# %d\n", ri->ino)); -- jffs2_add_ino_cache(c, f->inocache); -+ f->inocache->ino = ++c->highest_ino; -+ f->inocache->state = INO_STATE_PRESENT; - -- ri->magic = JFFS2_MAGIC_BITMASK; -- ri->nodetype = JFFS2_NODETYPE_INODE; -- ri->totlen = PAD(sizeof(*ri)); -- ri->hdr_crc = crc32(0, ri, sizeof(struct jffs2_unknown_node)-4); -- ri->mode = mode; -- f->highest_version = ri->version = 1; -- ri->uid = current->fsuid; -- if (dir_i->i_mode & S_ISGID) { -- ri->gid = dir_i->i_gid; -- if (S_ISDIR(mode)) -- ri->mode |= S_ISGID; -- } else { -- ri->gid = current->fsgid; -- } -- inode->i_mode = ri->mode; -- inode->i_gid = ri->gid; -- inode->i_uid = ri->uid; -- inode->i_atime = inode->i_ctime = inode->i_mtime = -- ri->atime = ri->mtime = ri->ctime = CURRENT_TIME; -- inode->i_blksize = PAGE_SIZE; -- inode->i_blocks = 0; -- inode->i_size = 0; -+ ri->ino = cpu_to_je32(f->inocache->ino); - -- insert_inode_hash(inode); -+ D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino)); -+ jffs2_add_ino_cache(c, f->inocache); - -- return inode; --} -+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri->totlen = cpu_to_je32(PAD(sizeof(*ri))); -+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); -+ ri->mode = cpu_to_jemode(mode); - --/* This ought to be in core MTD code. All registered MTD devices -- without writev should have this put in place. Bug the MTD -- maintainer */ --static int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen) --{ -- unsigned long i; -- size_t totlen = 0, thislen; -- int ret = 0; -+ f->highest_version = 1; -+ ri->version = cpu_to_je32(f->highest_version); - -- for (i=0; i<count; i++) { -- ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base); -- totlen += thislen; -- if (ret || thislen != vecs[i].iov_len) -- break; -- to += vecs[i].iov_len; -- } -- if (retlen) -- *retlen = totlen; -- return ret; --} -- -- --static inline int mtd_writev(struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen) --{ -- if (mtd->writev) -- return mtd->writev(mtd,vecs,count,to,retlen); -- else -- return mtd_fake_writev(mtd, vecs, count, to, retlen); -+ return 0; - } - --static void writecheck(struct mtd_info *mtd, __u32 ofs) -+#if CONFIG_JFFS2_FS_DEBUG > 0 -+static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) - { - unsigned char buf[16]; -- ssize_t retlen; -+ size_t retlen; - int ret, i; - -- ret = mtd->read(mtd, ofs, 16, &retlen, buf); -- if (ret && retlen != 16) { -- D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen)); -+ ret = jffs2_flash_read(c, ofs, 16, &retlen, buf); -+ if (ret || (retlen != 16)) { -+ D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen)); - return; - } - ret = 0; -@@ -157,32 +73,31 @@ - ret = 1; - } - if (ret) { -- printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there's data already there:\n", ofs); -+ printk(KERN_WARNING "ARGH. About to write node to 0x%08x on flash, but there are data already there:\n", ofs); - printk(KERN_WARNING "0x%08x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", - ofs, - buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], - buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); - } - } -- -- -+#endif - - - /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, - write it to the flash, link it into the existing inode/fragment list */ - --struct jffs2_full_dnode *jffs2_write_dnode(struct inode *inode, struct jffs2_raw_inode *ri, const unsigned char *data, __u32 datalen, __u32 flash_ofs, __u32 *writelen) -+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) - - { -- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_raw_node_ref *raw; - struct jffs2_full_dnode *fn; -- ssize_t retlen; -+ size_t retlen; - struct iovec vecs[2]; - int ret; -+ int retried = 0; -+ unsigned long cnt = 2; - -- D1(if(ri->hdr_crc != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { -+ D1(if(je32_to_cpu(ri->hdr_crc) != crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)) { - printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dnode()\n"); - BUG(); - } -@@ -192,10 +107,10 @@ - vecs[1].iov_base = (unsigned char *)data; - vecs[1].iov_len = datalen; - -- writecheck(c->mtd, flash_ofs); -+ D1(writecheck(c, flash_ofs)); - -- if (ri->totlen != sizeof(*ri) + datalen) { -- printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", ri->totlen, sizeof(*ri), datalen); -+ if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { -+ 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); - } - raw = jffs2_alloc_raw_node_ref(); - if (!raw) -@@ -206,19 +121,28 @@ - jffs2_free_raw_node_ref(raw); - return ERR_PTR(-ENOMEM); - } -- raw->flash_offset = flash_ofs; -- raw->totlen = PAD(ri->totlen); -- raw->next_phys = NULL; - -- fn->ofs = ri->offset; -- fn->size = ri->dsize; -+ fn->ofs = je32_to_cpu(ri->offset); -+ fn->size = je32_to_cpu(ri->dsize); - fn->frags = 0; -+ -+ /* check number of valid vecs */ -+ if (!datalen || !data) -+ cnt = 1; -+ retry: - fn->raw = raw; - -- ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen); -+ raw->flash_offset = flash_ofs; -+ raw->__totlen = PAD(sizeof(*ri)+datalen); -+ raw->next_phys = NULL; -+ -+ ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen, -+ (alloc_mode==ALLOC_GC)?0:f->inocache->ino); -+ - if (ret || (retlen != sizeof(*ri) + datalen)) { -- printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", -+ printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", - sizeof(*ri)+datalen, flash_ofs, ret, retlen); -+ - /* Mark the space as dirtied */ - if (retlen) { - /* Doesn't belong to any inode */ -@@ -229,48 +153,96 @@ - seem corrupted, in which case the scan would skip over - any node we write before the original intended end of - this node */ -- jffs2_add_physical_node_ref(c, raw, sizeof(*ri)+datalen, 1); -+ raw->flash_offset |= REF_OBSOLETE; -+ jffs2_add_physical_node_ref(c, raw); - jffs2_mark_node_obsolete(c, raw); - } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); - jffs2_free_raw_node_ref(raw); - } -+ if (!retried && alloc_mode != ALLOC_NORETRY && (raw = jffs2_alloc_raw_node_ref())) { -+ /* Try to reallocate space and retry */ -+ uint32_t dummy; -+ struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; -+ -+ retried = 1; -+ -+ D1(printk(KERN_DEBUG "Retrying failed write.\n")); -+ -+ ACCT_SANITY_CHECK(c,jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ -+ if (alloc_mode == ALLOC_GC) { -+ ret = jffs2_reserve_space_gc(c, sizeof(*ri) + datalen, &flash_ofs, &dummy); -+ } else { -+ /* Locking pain */ -+ up(&f->sem); -+ jffs2_complete_reservation(c); -+ -+ ret = jffs2_reserve_space(c, sizeof(*ri) + datalen, &flash_ofs, &dummy, alloc_mode); -+ down(&f->sem); -+ } -+ -+ if (!ret) { -+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); -+ -+ ACCT_SANITY_CHECK(c,jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); - -+ goto retry; -+ } -+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); -+ jffs2_free_raw_node_ref(raw); -+ } - /* Release the full_dnode which is now useless, and return */ - jffs2_free_full_dnode(fn); -- if (writelen) -- *writelen = retlen; - return ERR_PTR(ret?ret:-EIO); - } - /* Mark the space used */ -- jffs2_add_physical_node_ref(c, raw, retlen, 0); -+ /* If node covers at least a whole page, or if it starts at the -+ beginning of a page and runs to the end of the file, or if -+ it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. -+ */ -+ if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || -+ ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && -+ (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) { -+ raw->flash_offset |= REF_PRISTINE; -+ } else { -+ raw->flash_offset |= REF_NORMAL; -+ } -+ jffs2_add_physical_node_ref(c, raw); - - /* Link into per-inode list */ - raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; - -- D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", flash_ofs, ri->dsize, ri->csize, ri->node_crc, ri->data_crc, ri->totlen)); -- if (writelen) -- *writelen = retlen; -+ D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", -+ flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), -+ je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), -+ je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); -+ -+ if (retried) { -+ ACCT_SANITY_CHECK(c,NULL); -+ } - -- f->inocache->nodes = raw; - return fn; - } - --struct jffs2_full_dirent *jffs2_write_dirent(struct inode *inode, struct jffs2_raw_dirent *rd, const unsigned char *name, __u32 namelen, __u32 flash_ofs, __u32 *writelen) -+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) - { -- struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); -- struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); - struct jffs2_raw_node_ref *raw; - struct jffs2_full_dirent *fd; -- ssize_t retlen; -+ size_t retlen; - struct iovec vecs[2]; -+ int retried = 0; - int ret; - -- D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", rd->pino, name, name, rd->ino, rd->name_crc)); -- writecheck(c->mtd, flash_ofs); -+ D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", -+ je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), -+ je32_to_cpu(rd->name_crc))); -+ D1(writecheck(c, flash_ofs)); - -- D1(if(rd->hdr_crc != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { -+ D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { - printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); - BUG(); - } -@@ -291,44 +263,414 @@ - jffs2_free_raw_node_ref(raw); - return ERR_PTR(-ENOMEM); - } -- raw->flash_offset = flash_ofs; -- raw->totlen = PAD(rd->totlen); -- raw->next_in_ino = f->inocache->nodes; -- f->inocache->nodes = raw; -- raw->next_phys = NULL; - -- fd->version = rd->version; -- fd->ino = rd->ino; -+ fd->version = je32_to_cpu(rd->version); -+ fd->ino = je32_to_cpu(rd->ino); - fd->nhash = full_name_hash(name, strlen(name)); - fd->type = rd->type; - memcpy(fd->name, name, namelen); - fd->name[namelen]=0; -+ -+ retry: - fd->raw = raw; - -- ret = mtd_writev(c->mtd, vecs, 2, flash_ofs, &retlen); -+ raw->flash_offset = flash_ofs; -+ raw->__totlen = PAD(sizeof(*rd)+namelen); -+ raw->next_phys = NULL; -+ -+ ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen, -+ (alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino)); - if (ret || (retlen != sizeof(*rd) + namelen)) { -- printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", -+ printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", - sizeof(*rd)+namelen, flash_ofs, ret, retlen); - /* Mark the space as dirtied */ - if (retlen) { -- jffs2_add_physical_node_ref(c, raw, sizeof(*rd)+namelen, 1); -+ raw->next_in_ino = NULL; -+ raw->flash_offset |= REF_OBSOLETE; -+ jffs2_add_physical_node_ref(c, raw); - jffs2_mark_node_obsolete(c, raw); - } else { - printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", raw->flash_offset); - jffs2_free_raw_node_ref(raw); - } -+ if (!retried && (raw = jffs2_alloc_raw_node_ref())) { -+ /* Try to reallocate space and retry */ -+ uint32_t dummy; -+ struct jffs2_eraseblock *jeb = &c->blocks[flash_ofs / c->sector_size]; -+ -+ retried = 1; -+ -+ D1(printk(KERN_DEBUG "Retrying failed write.\n")); -+ -+ ACCT_SANITY_CHECK(c,jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ -+ if (alloc_mode == ALLOC_GC) { -+ ret = jffs2_reserve_space_gc(c, sizeof(*rd) + namelen, &flash_ofs, &dummy); -+ } else { -+ /* Locking pain */ -+ up(&f->sem); -+ jffs2_complete_reservation(c); -+ -+ ret = jffs2_reserve_space(c, sizeof(*rd) + namelen, &flash_ofs, &dummy, alloc_mode); -+ down(&f->sem); -+ } - -+ if (!ret) { -+ D1(printk(KERN_DEBUG "Allocated space at 0x%08x to retry failed write.\n", flash_ofs)); -+ ACCT_SANITY_CHECK(c,jeb); -+ D1(ACCT_PARANOIA_CHECK(jeb)); -+ goto retry; -+ } -+ D1(printk(KERN_DEBUG "Failed to allocate space to retry failed write: %d!\n", ret)); -+ jffs2_free_raw_node_ref(raw); -+ } - /* Release the full_dnode which is now useless, and return */ - jffs2_free_full_dirent(fd); -- if (writelen) -- *writelen = retlen; - return ERR_PTR(ret?ret:-EIO); - } - /* Mark the space used */ -- jffs2_add_physical_node_ref(c, raw, retlen, 0); -- if (writelen) -- *writelen = retlen; -+ raw->flash_offset |= REF_PRISTINE; -+ jffs2_add_physical_node_ref(c, raw); - -+ raw->next_in_ino = f->inocache->nodes; - f->inocache->nodes = raw; -+ -+ if (retried) { -+ ACCT_SANITY_CHECK(c,NULL); -+ } -+ - return fd; - } -+ -+/* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that -+ we don't have to go digging in struct inode or its equivalent. It should set: -+ mode, uid, gid, (starting)isize, atime, ctime, mtime */ -+int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f, -+ struct jffs2_raw_inode *ri, unsigned char *buf, -+ uint32_t offset, uint32_t writelen, uint32_t *retlen) -+{ -+ int ret = 0; -+ uint32_t writtenlen = 0; -+ -+ D1(printk(KERN_DEBUG "jffs2_write_inode_range(): Ino #%u, ofs 0x%x, len 0x%x\n", -+ f->inocache->ino, offset, writelen)); -+ -+ while(writelen) { -+ struct jffs2_full_dnode *fn; -+ unsigned char *comprbuf = NULL; -+ unsigned char comprtype = JFFS2_COMPR_NONE; -+ uint32_t phys_ofs, alloclen; -+ uint32_t datalen, cdatalen; -+ int retried = 0; -+ -+ retry: -+ D2(printk(KERN_DEBUG "jffs2_commit_write() loop: 0x%x to write to 0x%x\n", writelen, offset)); -+ -+ ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen, ALLOC_NORMAL); -+ if (ret) { -+ D1(printk(KERN_DEBUG "jffs2_reserve_space returned %d\n", ret)); -+ break; -+ } -+ down(&f->sem); -+ datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1))); -+ cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen); -+ -+ comprtype = jffs2_compress(buf, &comprbuf, &datalen, &cdatalen); -+ -+ ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); -+ ri->totlen = cpu_to_je32(sizeof(*ri) + cdatalen); -+ ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); -+ -+ ri->ino = cpu_to_je32(f->inocache->ino); -+ ri->version = cpu_to_je32(++f->highest_version); -+ ri->isize = cpu_to_je32(max(je32_to_cpu(ri->isize), offset + datalen)); -+ ri->offset = cpu_to_je32(offset); -+ ri->csize = cpu_to_je32(cdatalen); -+ ri->dsize = cpu_to_je32(datalen); -+ ri->compr = comprtype; -+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); -+ ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen)); -+ -+ fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, phys_ofs, ALLOC_NORETRY); -+ -+ jffs2_free_comprbuf(comprbuf, buf); -+ -+ if (IS_ERR(fn)) { -+ ret = PTR_ERR(fn); -+ up(&f->sem); -+ jffs2_complete_reservation(c); -+ if (!retried) { -+ /* Write error to be retried */ -+ retried = 1; -+ D1(printk(KERN_DEBUG "Retrying node write in jffs2_write_inode_range()\n")); -+ goto retry; -+ } -+ break; -+ } -+ ret = jffs2_add_full_dnode_to_inode(c, f, fn); -+ if (f->metadata) { -+ jffs2_mark_node_obsolete(c, f->metadata->raw); -+ jffs2_free_full_dnode(f->metadata); -+ f->metadata = NULL; -+ } -+ if (ret) { -+ /* Eep */ -+ D1(printk(KERN_DEBUG "Eep. add_full_dnode_to_inode() failed in commit_write, returned %d\n", ret)); -+ jffs2_mark_node_obsolete(c, fn->raw); -+ jffs2_free_full_dnode(fn); -+ -+ up(&f->sem); -+ jffs2_complete_reservation(c); -+ break; -+ } -+ up(&f->sem); -+ jffs2_complete_reservation(c); -+ if (!datalen) { -+ printk(KERN_WARNING "Eep. We didn't actually write any data in jffs2_write_inode_range()\n"); -+ ret = -EIO; -+ break; -+ } -+ D1(printk(KERN_DEBUG "increasing writtenlen by %d\n", datalen)); -+ writtenlen += datalen; -+ offset += datalen; -+ writelen -= datalen; -+ buf += datalen; -+ } -+ *retlen = writtenlen; -+ return ret; -+} -+ -+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) -+{ -+ struct jffs2_raw_dirent *rd; -+ struct jffs2_full_dnode *fn; -+ struct jffs2_full_dirent *fd; -+ uint32_t alloclen, phys_ofs; -+ int ret; -+ -+ /* Try to reserve enough space for both node and dirent. -+ * Just the node will do for now, though -+ */ -+ ret = jffs2_reserve_space(c, sizeof(*ri), &phys_ofs, &alloclen, ALLOC_NORMAL); -+ D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen)); -+ if (ret) { -+ up(&f->sem); -+ return ret; -+ } -+ -+ ri->data_crc = cpu_to_je32(0); -+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8)); -+ -+ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, ALLOC_NORMAL); -+ -+ D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n", -+ jemode_to_cpu(ri->mode))); -+ -+ if (IS_ERR(fn)) { -+ D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); -+ /* Eeek. Wave bye bye */ -+ up(&f->sem); -+ jffs2_complete_reservation(c); -+ return PTR_ERR(fn); -+ } -+ /* No data here. Only a metadata node, which will be -+ obsoleted by the first data write -+ */ -+ f->metadata = fn; -+ -+ up(&f->sem); -+ jffs2_complete_reservation(c); -+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); -+ -+ if (ret) { -+ /* Eep. */ -+ D1(printk(KERN_DEBUG "jffs2_reserve_space() for dirent failed\n")); -+ return ret; -+ } -+ -+ rd = jffs2_alloc_raw_dirent(); -+ if (!rd) { -+ /* Argh. Now we treat it like a normal delete */ -+ jffs2_complete_reservation(c); -+ return -ENOMEM; -+ } -+ -+ down(&dir_f->sem); -+ -+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); -+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); -+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); -+ -+ rd->pino = cpu_to_je32(dir_f->inocache->ino); -+ rd->version = cpu_to_je32(++dir_f->highest_version); -+ rd->ino = ri->ino; -+ rd->mctime = ri->ctime; -+ rd->nsize = namelen; -+ rd->type = DT_REG; -+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); -+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); -+ -+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); -+ -+ jffs2_free_raw_dirent(rd); -+ -+ if (IS_ERR(fd)) { -+ /* dirent failed to write. Delete the inode normally -+ as if it were the final unlink() */ -+ jffs2_complete_reservation(c); -+ up(&dir_f->sem); -+ return PTR_ERR(fd); -+ } -+ -+ /* Link the fd into the inode's list, obsoleting an old -+ one if necessary. */ -+ jffs2_add_fd_to_list(c, fd, &dir_f->dents); -+ -+ jffs2_complete_reservation(c); -+ up(&dir_f->sem); -+ -+ return 0; -+} -+ -+ -+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) -+{ -+ struct jffs2_raw_dirent *rd; -+ struct jffs2_full_dirent *fd; -+ uint32_t alloclen, phys_ofs; -+ int ret; -+ -+ rd = jffs2_alloc_raw_dirent(); -+ if (!rd) -+ return -ENOMEM; -+ -+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_DELETION); -+ if (ret) { -+ jffs2_free_raw_dirent(rd); -+ return ret; -+ } -+ -+ down(&dir_f->sem); -+ -+ /* Build a deletion node */ -+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); -+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); -+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); -+ -+ rd->pino = cpu_to_je32(dir_f->inocache->ino); -+ rd->version = cpu_to_je32(++dir_f->highest_version); -+ rd->ino = cpu_to_je32(0); -+ rd->mctime = cpu_to_je32(get_seconds()); -+ rd->nsize = namelen; -+ rd->type = DT_UNKNOWN; -+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); -+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); -+ -+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_DELETION); -+ -+ jffs2_free_raw_dirent(rd); -+ -+ if (IS_ERR(fd)) { -+ jffs2_complete_reservation(c); -+ up(&dir_f->sem); -+ return PTR_ERR(fd); -+ } -+ -+ /* File it. This will mark the old one obsolete. */ -+ jffs2_add_fd_to_list(c, fd, &dir_f->dents); -+ -+ up(&dir_f->sem); -+ -+ /* dead_f is NULL if this was a rename not a real unlink */ -+ /* Also catch the !f->inocache case, where there was a dirent -+ pointing to an inode which didn't exist. */ -+ if (dead_f && dead_f->inocache) { -+ -+ down(&dead_f->sem); -+ -+ while (dead_f->dents) { -+ /* There can be only deleted ones */ -+ fd = dead_f->dents; -+ -+ dead_f->dents = fd->next; -+ -+ if (fd->ino) { -+ printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n", -+ dead_f->inocache->ino, fd->name, fd->ino); -+ } else { -+ D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino)); -+ } -+ jffs2_mark_node_obsolete(c, fd->raw); -+ jffs2_free_full_dirent(fd); -+ } -+ -+ dead_f->inocache->nlink--; -+ /* NB: Caller must set inode nlink if appropriate */ -+ up(&dead_f->sem); -+ } -+ -+ jffs2_complete_reservation(c); -+ -+ return 0; -+} -+ -+ -+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) -+{ -+ struct jffs2_raw_dirent *rd; -+ struct jffs2_full_dirent *fd; -+ uint32_t alloclen, phys_ofs; -+ int ret; -+ -+ rd = jffs2_alloc_raw_dirent(); -+ if (!rd) -+ return -ENOMEM; -+ -+ ret = jffs2_reserve_space(c, sizeof(*rd)+namelen, &phys_ofs, &alloclen, ALLOC_NORMAL); -+ if (ret) { -+ jffs2_free_raw_dirent(rd); -+ return ret; -+ } -+ -+ down(&dir_f->sem); -+ -+ /* Build a deletion node */ -+ rd->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); -+ rd->nodetype = cpu_to_je16(JFFS2_NODETYPE_DIRENT); -+ rd->totlen = cpu_to_je32(sizeof(*rd) + namelen); -+ rd->hdr_crc = cpu_to_je32(crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)); -+ -+ rd->pino = cpu_to_je32(dir_f->inocache->ino); -+ rd->version = cpu_to_je32(++dir_f->highest_version); -+ rd->ino = cpu_to_je32(ino); -+ rd->mctime = cpu_to_je32(get_seconds()); -+ rd->nsize = namelen; -+ -+ rd->type = type; -+ -+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8)); -+ rd->name_crc = cpu_to_je32(crc32(0, name, namelen)); -+ -+ fd = jffs2_write_dirent(c, dir_f, rd, name, namelen, phys_ofs, ALLOC_NORMAL); -+ -+ jffs2_free_raw_dirent(rd); -+ -+ if (IS_ERR(fd)) { -+ jffs2_complete_reservation(c); -+ up(&dir_f->sem); -+ return PTR_ERR(fd); -+ } -+ -+ /* File it. This will mark the old one obsolete. */ -+ jffs2_add_fd_to_list(c, fd, &dir_f->dents); -+ -+ jffs2_complete_reservation(c); -+ up(&dir_f->sem); -+ -+ return 0; -+} -diff -Nurb linux-mips-2.4.27/fs/jffs2/writev.c linux/fs/jffs2/writev.c ---- linux-mips-2.4.27/fs/jffs2/writev.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux/fs/jffs2/writev.c 2004-11-19 10:25:12.134164072 +0100 -@@ -0,0 +1,50 @@ -+/* -+ * JFFS2 -- Journalling Flash File System, Version 2. -+ * -+ * Copyright (C) 2001, 2002 Red Hat, Inc. -+ * -+ * Created by David Woodhouse <dwmw2@redhat.com> -+ * -+ * For licensing information, see the file 'LICENCE' in this directory. -+ * -+ * $Id$ -+ * -+ */ -+ -+#include <linux/kernel.h> -+#include <linux/mtd/mtd.h> -+#include "nodelist.h" -+ -+/* This ought to be in core MTD code. All registered MTD devices -+ without writev should have this put in place. Bug the MTD -+ maintainer */ -+static inline int mtd_fake_writev(struct mtd_info *mtd, const struct iovec *vecs, -+ unsigned long count, loff_t to, size_t *retlen) -+{ -+ unsigned long i; -+ size_t totlen = 0, thislen; -+ int ret = 0; -+ -+ for (i=0; i<count; i++) { -+ if (!vecs[i].iov_len) -+ continue; -+ ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base); -+ totlen += thislen; -+ if (ret || thislen != vecs[i].iov_len) -+ break; -+ to += vecs[i].iov_len; -+ } -+ if (retlen) -+ *retlen = totlen; -+ return ret; -+} -+ -+int jffs2_flash_direct_writev(struct jffs2_sb_info *c, const struct iovec *vecs, -+ unsigned long count, loff_t to, size_t *retlen) -+{ -+ if (c->mtd->writev) -+ return c->mtd->writev(c->mtd, vecs, count, to, retlen); -+ else -+ return mtd_fake_writev(c->mtd, vecs, count, to, retlen); -+} -+ -diff -Nurb linux-mips-2.4.27/include/linux/jffs2.h linux/include/linux/jffs2.h ---- linux-mips-2.4.27/include/linux/jffs2.h 2002-06-27 00:36:46.000000000 +0200 -+++ linux/include/linux/jffs2.h 2004-11-19 10:25:12.139163312 +0100 -@@ -1,50 +1,30 @@ - /* - * JFFS2 -- Journalling Flash File System, Version 2. - * -- * Copyright (C) 2001 Red Hat, Inc. -+ * Copyright (C) 2001-2003 Red Hat, Inc. - * -- * Created by David Woodhouse <dwmw2@cambridge.redhat.com> -+ * Created by David Woodhouse <dwmw2@redhat.com> - * -- * The original JFFS, from which the design for JFFS2 was derived, -- * was designed and implemented by Axis Communications AB. -+ * For licensing information, see the file 'LICENCE' in the -+ * jffs2 directory. - * -- * The contents of this file are subject to the Red Hat eCos Public -- * License Version 1.1 (the "Licence"); you may not use this file -- * except in compliance with the Licence. You may obtain a copy of -- * the Licence at http://www.redhat.com/ -- * -- * Software distributed under the Licence is distributed on an "AS IS" -- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. -- * See the Licence for the specific language governing rights and -- * limitations under the Licence. -- * -- * The Original Code is JFFS2 - Journalling Flash File System, version 2 -- * -- * Alternatively, the contents of this file may be used under the -- * terms of the GNU General Public License version 2 (the "GPL"), in -- * which case the provisions of the GPL are applicable instead of the -- * above. If you wish to allow the use of your version of this file -- * only under the terms of the GPL and not to allow others to use your -- * version of this file under the RHEPL, indicate your decision by -- * deleting the provisions above and replace them with the notice and -- * other provisions required by the GPL. If you do not delete the -- * provisions above, a recipient may use your version of this file -- * under either the RHEPL or the GPL. -- * -- * $Id$ -+ * $Id$ - * - */ - - #ifndef __LINUX_JFFS2_H__ - #define __LINUX_JFFS2_H__ - --#include <asm/types.h> -+/* You must include something which defines the C99 uintXX_t types. -+ We don't do it from here because this file is used in too many -+ different environments. */ -+ - #define JFFS2_SUPER_MAGIC 0x72b6 - - /* Values we may expect to find in the 'magic' field */ - #define JFFS2_OLD_MAGIC_BITMASK 0x1984 - #define JFFS2_MAGIC_BITMASK 0x1985 --#define KSAMTIB_CIGAM_2SFFJ 0x5981 /* For detecting wrong-endian fs */ -+#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ - #define JFFS2_EMPTY_BITMASK 0xffff - #define JFFS2_DIRTY_BITMASK 0x0000 - -@@ -78,16 +58,12 @@ - #define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) - #define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) - #define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) -+#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) - - // Maybe later... - //#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) - //#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) - --/* Same as the non_ECC versions, but with extra space for real -- * ECC instead of just the checksum. For use on NAND flash -- */ --//#define JFFS2_NODETYPE_DIRENT_ECC (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 5) --//#define JFFS2_NODETYPE_INODE_ECC (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 6) - - #define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at - mount time, don't wait for it to -@@ -96,31 +72,79 @@ - compression type */ - - -+/* These can go once we've made sure we've caught all uses without -+ byteswapping */ -+ -+typedef struct { -+ uint32_t v32; -+} __attribute__((packed)) jint32_t; -+ -+typedef struct { -+ uint32_t m; -+} __attribute__((packed)) jmode_t; -+ -+typedef struct { -+ uint16_t v16; -+} __attribute__((packed)) jint16_t; -+ -+#define JFFS2_NATIVE_ENDIAN -+ -+/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from -+ whatever OS we're actually running on here too. */ -+ -+#if defined(JFFS2_NATIVE_ENDIAN) -+#define cpu_to_je16(x) ((jint16_t){x}) -+#define cpu_to_je32(x) ((jint32_t){x}) -+#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)}) -+ -+#define je16_to_cpu(x) ((x).v16) -+#define je32_to_cpu(x) ((x).v32) -+#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m)) -+#elif defined(JFFS2_BIG_ENDIAN) -+#define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)}) -+#define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)}) -+#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))}) -+ -+#define je16_to_cpu(x) (be16_to_cpu(x.v16)) -+#define je32_to_cpu(x) (be32_to_cpu(x.v32)) -+#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m))) -+#elif defined(JFFS2_LITTLE_ENDIAN) -+#define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)}) -+#define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)}) -+#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))}) -+ -+#define je16_to_cpu(x) (le16_to_cpu(x.v16)) -+#define je32_to_cpu(x) (le32_to_cpu(x.v32)) -+#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) -+#else -+#error wibble -+#endif -+ - struct jffs2_unknown_node - { - /* All start like this */ -- __u16 magic; -- __u16 nodetype; -- __u32 totlen; /* So we can skip over nodes we don't grok */ -- __u32 hdr_crc; -+ jint16_t magic; -+ jint16_t nodetype; -+ jint32_t totlen; /* So we can skip over nodes we don't grok */ -+ jint32_t hdr_crc; - } __attribute__((packed)); - - struct jffs2_raw_dirent - { -- __u16 magic; -- __u16 nodetype; /* == JFFS_NODETYPE_DIRENT */ -- __u32 totlen; -- __u32 hdr_crc; -- __u32 pino; -- __u32 version; -- __u32 ino; /* == zero for unlink */ -- __u32 mctime; -- __u8 nsize; -- __u8 type; -- __u8 unused[2]; -- __u32 node_crc; -- __u32 name_crc; -- __u8 name[0]; -+ jint16_t magic; -+ jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */ -+ jint32_t totlen; -+ jint32_t hdr_crc; -+ jint32_t pino; -+ jint32_t version; -+ jint32_t ino; /* == zero for unlink */ -+ jint32_t mctime; -+ uint8_t nsize; -+ uint8_t type; -+ uint8_t unused[2]; -+ jint32_t node_crc; -+ jint32_t name_crc; -+ uint8_t name[0]; - } __attribute__((packed)); - - /* The JFFS2 raw inode structure: Used for storage on physical media. */ -@@ -131,28 +155,28 @@ - */ - struct jffs2_raw_inode - { -- __u16 magic; /* A constant magic number. */ -- __u16 nodetype; /* == JFFS_NODETYPE_INODE */ -- __u32 totlen; /* Total length of this node (inc data, etc.) */ -- __u32 hdr_crc; -- __u32 ino; /* Inode number. */ -- __u32 version; /* Version number. */ -- __u32 mode; /* The file's type or mode. */ -- __u16 uid; /* The file's owner. */ -- __u16 gid; /* The file's group. */ -- __u32 isize; /* Total resultant size of this inode (used for truncations) */ -- __u32 atime; /* Last access time. */ -- __u32 mtime; /* Last modification time. */ -- __u32 ctime; /* Change time. */ -- __u32 offset; /* Where to begin to write. */ -- __u32 csize; /* (Compressed) data size */ -- __u32 dsize; /* Size of the node's data. (after decompression) */ -- __u8 compr; /* Compression algorithm used */ -- __u8 usercompr; /* Compression algorithm requested by the user */ -- __u16 flags; /* See JFFS2_INO_FLAG_* */ -- __u32 data_crc; /* CRC for the (compressed) data. */ -- __u32 node_crc; /* CRC for the raw inode (excluding data) */ --// __u8 data[dsize]; -+ jint16_t magic; /* A constant magic number. */ -+ jint16_t nodetype; /* == JFFS_NODETYPE_INODE */ -+ jint32_t totlen; /* Total length of this node (inc data, etc.) */ -+ jint32_t hdr_crc; -+ jint32_t ino; /* Inode number. */ -+ jint32_t version; /* Version number. */ -+ jmode_t mode; /* The file's type or mode. */ -+ jint16_t uid; /* The file's owner. */ -+ jint16_t gid; /* The file's group. */ -+ jint32_t isize; /* Total resultant size of this inode (used for truncations) */ -+ jint32_t atime; /* Last access time. */ -+ jint32_t mtime; /* Last modification time. */ -+ jint32_t ctime; /* Change time. */ -+ jint32_t offset; /* Where to begin to write. */ -+ jint32_t csize; /* (Compressed) data size */ -+ jint32_t dsize; /* Size of the node's data. (after decompression) */ -+ uint8_t compr; /* Compression algorithm used */ -+ uint8_t usercompr; /* Compression algorithm requested by the user */ -+ jint16_t flags; /* See JFFS2_INO_FLAG_* */ -+ jint32_t data_crc; /* CRC for the (compressed) data. */ -+ jint32_t node_crc; /* CRC for the raw inode (excluding data) */ -+ uint8_t data[0]; - } __attribute__((packed)); - - union jffs2_node_union { -diff -Nurb linux-mips-2.4.27/include/linux/jffs2_fs_i.h linux/include/linux/jffs2_fs_i.h ---- linux-mips-2.4.27/include/linux/jffs2_fs_i.h 2001-10-19 03:25:03.000000000 +0200 -+++ linux/include/linux/jffs2_fs_i.h 2004-11-19 10:25:12.141163008 +0100 -@@ -1,22 +1,12 @@ --/* $Id$ */ -+/* $Id$ */ - - #ifndef _JFFS2_FS_I - #define _JFFS2_FS_I - --/* Include the pipe_inode_info at the beginning so that we can still -- use the storage space in the inode when we have a pipe inode. -- This sucks. --*/ -- --#undef THISSUCKS /* Only for 2.2 */ --#ifdef THISSUCKS --#include <linux/pipe_fs_i.h> --#endif -+#include <linux/version.h> -+#include <linux/rbtree.h> - - struct jffs2_inode_info { --#ifdef THISSUCKS -- struct pipe_inode_info pipecrap; --#endif - /* We need an internal semaphore similar to inode->i_sem. - Unfortunately, we can't used the existing one, because - either the GC would deadlock, or we'd have to release it -@@ -26,10 +16,10 @@ - struct semaphore sem; - - /* The highest (datanode) version number used for this ino */ -- __u32 highest_version; -+ uint32_t highest_version; - - /* List of data fragments which make up the file */ -- struct jffs2_node_frag *fraglist; -+ struct rb_root fragtree; - - /* There may be one datanode which isn't referenced by any of the - above fragments, if it contains a metadata update but no actual -@@ -44,19 +34,13 @@ - /* Some stuff we just have to keep in-core at all times, for each inode. */ - struct jffs2_inode_cache *inocache; - -- /* Keep a pointer to the last physical node in the list. We don't -- use the doubly-linked lists because we don't want to increase -- the memory usage that much. This is simpler */ -- // struct jffs2_raw_node_ref *lastnode; -- __u16 flags; -- __u8 usercompr; --}; -- --#ifdef JFFS2_OUT_OF_KERNEL --#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u) --#else --#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i) -+ uint16_t flags; -+ uint8_t usercompr; -+#if !defined (__ECOS) -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) -+ struct inode vfs_inode; - #endif -+#endif -+}; - - #endif /* _JFFS2_FS_I */ -- -diff -Nurb linux-mips-2.4.27/include/linux/jffs2_fs_sb.h linux/include/linux/jffs2_fs_sb.h ---- linux-mips-2.4.27/include/linux/jffs2_fs_sb.h 2002-06-27 00:36:46.000000000 +0200 -+++ linux/include/linux/jffs2_fs_sb.h 2004-11-19 10:25:12.142162856 +0100 -@@ -1,19 +1,22 @@ --/* $Id$ */ -+/* $Id$ */ - - #ifndef _JFFS2_FS_SB - #define _JFFS2_FS_SB - - #include <linux/types.h> - #include <linux/spinlock.h> -+#include <linux/workqueue.h> - #include <linux/completion.h> - #include <asm/semaphore.h> -+#include <linux/timer.h> -+#include <linux/wait.h> - #include <linux/list.h> - --#define INOCACHE_HASHSIZE 1 -- - #define JFFS2_SB_FLAG_RO 1 - #define JFFS2_SB_FLAG_MOUNTING 2 - -+struct jffs2_inodirty; -+ - /* A struct for the overall file system control. Pointers to - jffs2_sb_info structs are named `c' in the source code. - Nee jffs_control -@@ -21,36 +24,46 @@ - struct jffs2_sb_info { - struct mtd_info *mtd; - -- __u32 highest_ino; -+ uint32_t highest_ino; -+ uint32_t checked_ino; -+ - unsigned int flags; -- spinlock_t nodelist_lock; - -- // pid_t thread_pid; /* GC thread's PID */ - struct task_struct *gc_task; /* GC task struct */ - struct semaphore gc_thread_start; /* GC thread start mutex */ - struct completion gc_thread_exit; /* GC thread exit completion port */ -- // __u32 gc_minfree_threshold; /* GC trigger thresholds */ -- // __u32 gc_maxdirty_threshold; - - struct semaphore alloc_sem; /* Used to protect all the following - fields, and also to protect against - out-of-order writing of nodes. - And GC. - */ -- __u32 flash_size; -- __u32 used_size; -- __u32 dirty_size; -- __u32 free_size; -- __u32 erasing_size; -- __u32 bad_size; -- __u32 sector_size; -- // __u32 min_free_size; -- // __u32 max_chunk_size; -+ uint32_t cleanmarker_size; /* Size of an _inline_ CLEANMARKER -+ (i.e. zero for OOB CLEANMARKER */ -+ -+ uint32_t flash_size; -+ uint32_t used_size; -+ uint32_t dirty_size; -+ uint32_t wasted_size; -+ uint32_t free_size; -+ uint32_t erasing_size; -+ uint32_t bad_size; -+ uint32_t sector_size; -+ uint32_t unchecked_size; -+ -+ uint32_t nr_free_blocks; -+ uint32_t nr_erasing_blocks; -+ -+ /* Number of free blocks there must be before we... */ -+ uint8_t resv_blocks_write; /* ... allow a normal filesystem write */ -+ uint8_t resv_blocks_deletion; /* ... allow a normal filesystem deletion */ -+ uint8_t resv_blocks_gctrigger; /* ... wake up the GC thread */ -+ uint8_t resv_blocks_gcbad; /* ... pick a block from the bad_list to GC */ -+ uint8_t resv_blocks_gcmerge; /* ... merge pages when garbage collecting */ - -- __u32 nr_free_blocks; -- __u32 nr_erasing_blocks; -+ uint32_t nospc_dirty_size; - -- __u32 nr_blocks; -+ uint32_t nr_blocks; - struct jffs2_eraseblock *blocks; /* The whole array of blocks. Used for getting blocks - * from the offset (blocks[ofs / sector_size]) */ - struct jffs2_eraseblock *nextblock; /* The block we're currently filling */ -@@ -58,9 +71,12 @@ - struct jffs2_eraseblock *gcblock; /* The block we're currently garbage-collecting */ - - struct list_head clean_list; /* Blocks 100% full of clean data */ -+ struct list_head very_dirty_list; /* Blocks with lots of dirty space */ - struct list_head dirty_list; /* Blocks with some dirty space */ -+ struct list_head erasable_list; /* Blocks which are completely dirty, and need erasing */ -+ struct list_head erasable_pending_wbuf_list; /* Blocks which need erasing but only after the current wbuf is flushed */ - struct list_head erasing_list; /* Blocks which are currently erasing */ -- struct list_head erase_pending_list; /* Blocks which need erasing */ -+ struct list_head erase_pending_list; /* Blocks which need erasing now */ - struct list_head erase_complete_list; /* Blocks which are erased and need the clean marker written to them */ - struct list_head free_list; /* Blocks which are free and ready to be used */ - struct list_head bad_list; /* Bad blocks. */ -@@ -69,16 +85,33 @@ - spinlock_t erase_completion_lock; /* Protect free_list and erasing_list - against erase completion handler */ - wait_queue_head_t erase_wait; /* For waiting for erases to complete */ -- struct jffs2_inode_cache *inocache_list[INOCACHE_HASHSIZE]; -+ -+ wait_queue_head_t inocache_wq; -+ struct jffs2_inode_cache **inocache_list; - spinlock_t inocache_lock; --}; - --#ifdef JFFS2_OUT_OF_KERNEL --#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u) --#else --#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb) -+ /* Sem to allow jffs2_garbage_collect_deletion_dirent to -+ drop the erase_completion_lock while it's holding a pointer -+ to an obsoleted node. I don't like this. Alternatives welcomed. */ -+ struct semaphore erase_free_sem; -+ -+#ifdef CONFIG_JFFS2_FS_NAND -+ /* Write-behind buffer for NAND flash */ -+ unsigned char *wbuf; -+ uint32_t wbuf_ofs; -+ uint32_t wbuf_len; -+ uint32_t wbuf_pagesize; -+ struct jffs2_inodirty *wbuf_inodes; -+ -+ /* Information about out-of-band area usage... */ -+ struct nand_oobinfo *oobinfo; -+ uint32_t badblock_pos; -+ uint32_t fsdata_pos; -+ uint32_t fsdata_len; - #endif - --#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) ) -+ /* OS-private pointer for getting back to master superblock info */ -+ void *os_priv; -+}; - - #endif /* _JFFS2_FB_SB */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/blktrans.h linux/include/linux/mtd/blktrans.h ---- linux-mips-2.4.27/include/linux/mtd/blktrans.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/include/linux/mtd/blktrans.h 2004-11-19 10:25:12.037178816 +0100 -@@ -0,0 +1,72 @@ -+/* -+ * $Id$ -+ * -+ * (C) 2003 David Woodhouse <dwmw2@infradead.org> -+ * -+ * Interface to Linux block layer for MTD 'translation layers'. -+ * -+ */ -+ -+#ifndef __MTD_TRANS_H__ -+#define __MTD_TRANS_H__ -+ -+#include <asm/semaphore.h> -+ -+struct hd_geometry; -+struct mtd_info; -+struct mtd_blktrans_ops; -+struct file; -+struct inode; -+ -+struct mtd_blktrans_dev { -+ struct mtd_blktrans_ops *tr; -+ struct list_head list; -+ struct mtd_info *mtd; -+ struct semaphore sem; -+ int devnum; -+ int blksize; -+ unsigned long size; -+ int readonly; -+ void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */ -+}; -+ -+struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */ -+ -+struct mtd_blktrans_ops { -+ char *name; -+ int major; -+ int part_bits; -+ -+ /* Access functions */ -+ int (*readsect)(struct mtd_blktrans_dev *dev, -+ unsigned long block, char *buffer); -+ int (*writesect)(struct mtd_blktrans_dev *dev, -+ unsigned long block, char *buffer); -+ -+ /* Block layer ioctls */ -+ int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo); -+ int (*flush)(struct mtd_blktrans_dev *dev); -+ -+ /* Called with mtd_table_mutex held; no race with add/remove */ -+ int (*open)(struct mtd_blktrans_dev *dev); -+ int (*release)(struct mtd_blktrans_dev *dev); -+ -+ /* Called on {de,}registration and on subsequent addition/removal -+ of devices, with mtd_table_mutex held. */ -+ void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd); -+ void (*remove_dev)(struct mtd_blktrans_dev *dev); -+ -+ struct list_head devs; -+ struct list_head list; -+ struct module *owner; -+ -+ struct mtd_blkcore_priv *blkcore_priv; -+}; -+ -+extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr); -+extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); -+extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); -+extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); -+ -+ -+#endif /* __MTD_TRANS_H__ */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/cfi.h linux/include/linux/mtd/cfi.h ---- linux-mips-2.4.27/include/linux/mtd/cfi.h 2003-02-26 01:53:51.000000000 +0100 -+++ linux/include/linux/mtd/cfi.h 2004-11-19 10:25:12.038178664 +0100 -@@ -1,13 +1,14 @@ - - /* Common Flash Interface structures - * See http://support.intel.com/design/flash/technote/index.htm -- * $Id$ -+ * $Id$ - */ - - #ifndef __MTD_CFI_H__ - #define __MTD_CFI_H__ - - #include <linux/config.h> -+#include <linux/version.h> - #include <linux/delay.h> - #include <linux/types.h> - #include <linux/interrupt.h> -@@ -260,7 +261,8 @@ - __u8 pri[3]; - __u8 MajorVersion; - __u8 MinorVersion; -- __u32 FeatureSupport; -+ __u32 FeatureSupport; /* if bit 31 is set then an additional __u32 feature -+ block follows - FIXME - not currently supported */ - __u8 SuspendCmdSupport; - __u16 BlkStatusRegMask; - __u8 VccOptimal; -@@ -271,6 +273,25 @@ - __u8 UserProtRegSize; - } __attribute__((packed)); - -+/* Vendor-Specific PRI for AMD/Fujitsu Extended Command Set (0x0002) */ -+ -+struct cfi_pri_amdstd { -+ __u8 pri[3]; -+ __u8 MajorVersion; -+ __u8 MinorVersion; -+ __u8 SiliconRevision; /* bits 1-0: Address Sensitive Unlock */ -+ __u8 EraseSuspend; -+ __u8 BlkProt; -+ __u8 TmpBlkUnprotect; -+ __u8 BlkProtUnprot; -+ __u8 SimultaneousOps; -+ __u8 BurstMode; -+ __u8 PageMode; -+ __u8 VppMin; -+ __u8 VppMax; -+ __u8 TopBottom; -+} __attribute__((packed)); -+ - struct cfi_pri_query { - __u8 NumFields; - __u32 ProtField[1]; /* Not host ordered */ -@@ -314,8 +335,6 @@ - struct flchip chips[0]; /* per-chip data structure for each chip */ - }; - --#define MAX_CFI_CHIPS 8 /* Entirely arbitrary to avoid realloc() */ -- - /* - * Returns the command address according to the given geometry. - */ -@@ -387,13 +406,13 @@ - static inline cfi_word cfi_read(struct map_info *map, __u32 addr) - { - if (cfi_buswidth_is_1()) { -- return map->read8(map, addr); -+ return map_read8(map, addr); - } else if (cfi_buswidth_is_2()) { -- return map->read16(map, addr); -+ return map_read16(map, addr); - } else if (cfi_buswidth_is_4()) { -- return map->read32(map, addr); -+ return map_read32(map, addr); - } else if (cfi_buswidth_is_8()) { -- return map->read64(map, addr); -+ return map_read64(map, addr); - } else { - return 0; - } -@@ -406,13 +425,13 @@ - static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr) - { - if (cfi_buswidth_is_1()) { -- map->write8(map, val, addr); -+ map_write8(map, val, addr); - } else if (cfi_buswidth_is_2()) { -- map->write16(map, val, addr); -+ map_write16(map, val, addr); - } else if (cfi_buswidth_is_4()) { -- map->write32(map, val, addr); -+ map_write32(map, val, addr); - } else if (cfi_buswidth_is_8()) { -- map->write64(map, val, addr); -+ map_write64(map, val, addr); - } - } - -@@ -443,13 +462,13 @@ - static inline __u8 cfi_read_query(struct map_info *map, __u32 addr) - { - if (cfi_buswidth_is_1()) { -- return map->read8(map, addr); -+ return map_read8(map, addr); - } else if (cfi_buswidth_is_2()) { -- return cfi16_to_cpu(map->read16(map, addr)); -+ return cfi16_to_cpu(map_read16(map, addr)); - } else if (cfi_buswidth_is_4()) { -- return cfi32_to_cpu(map->read32(map, addr)); -+ return cfi32_to_cpu(map_read32(map, addr)); - } else if (cfi_buswidth_is_8()) { -- return cfi64_to_cpu(map->read64(map, addr)); -+ return cfi64_to_cpu(map_read64(map, addr)); - } else { - return 0; - } -@@ -479,5 +498,19 @@ - spin_unlock_bh(mutex); - } - -+struct cfi_extquery *cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, -+ const char* name); -+ -+struct cfi_fixup { -+ __u16 mfr; -+ __u16 id; -+ void (*fixup)(struct map_info *map, void* param); -+ void* param; -+}; -+ -+#define CFI_MFR_ANY 0xffff -+#define CFI_ID_ANY 0xffff -+ -+void cfi_fixup(struct map_info *map, struct cfi_fixup* fixups); - - #endif /* __MTD_CFI_H__ */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/compatmac.h linux/include/linux/mtd/compatmac.h ---- linux-mips-2.4.27/include/linux/mtd/compatmac.h 2003-02-26 01:53:51.000000000 +0100 -+++ linux/include/linux/mtd/compatmac.h 2004-11-19 10:25:12.041178208 +0100 -@@ -1,573 +1,152 @@ -- - /* -- * mtd/include/compatmac.h -- * -- * $Id$ -+ * $Id$ - * - * Extensions and omissions from the normal 'linux/compatmac.h' - * files. hopefully this will end up empty as the 'real' one - * becomes fully-featured. - */ - -- --/* First, include the parts which the kernel is good enough to provide -- * to us -- */ -- - #ifndef __LINUX_MTD_COMPATMAC_H__ - #define __LINUX_MTD_COMPATMAC_H__ - --#include <linux/config.h> --#include <linux/module.h> --#ifndef LINUX_VERSION_CODE - #include <linux/version.h> --#endif -- --#ifndef VERSION_CODE --# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) ) --#endif --#ifndef KERNEL_VERSION --# define KERNEL_VERSION(a,b,c) VERSION_CODE(a,b,c) --#endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0) --# error "This kernel is too old: not supported by this file" --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) --#include <linux/types.h> /* used later in this header */ -- --#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c)) --#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c)) -- --typedef struct wait_queue * wait_queue_head_t; -- --#define DECLARE_WAITQUEUE(x,y) struct wait_queue x = {y,NULL} --#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL --#define init_waitqueue_head init_waitqueue --#define DECLARE_MUTEX(x) struct semaphore x = MUTEX --#define DECLARE_MUTEX_LOCKED(x) struct semaphore x = MUTEX_LOCKED -- --/* from sysdep-2.1.h */ --# include <asm/segment.h> --# define access_ok(t,a,sz) (verify_area((t),(a),(sz)) ? 0 : 1) --# define verify_area_20 verify_area --# define copy_to_user(t,f,n) (memcpy_tofs(t,f,n), 0) --# define __copy_to_user(t,f,n) copy_to_user((t),(f),(n)) --# define copy_to_user_ret(t,f,n,r) copy_to_user((t),(f),(n)) --# define copy_from_user(t,f,n) (memcpy_fromfs((t),(f),(n)), 0) --# define __copy_from_user(t,f,n) copy_from_user((t),(f),(n)) --# define copy_from_user_ret(t,f,n,r) copy_from_user((t),(f),(n)) --//xxx # define PUT_USER(val,add) (put_user((val),(add)), 0) --# define Put_user(val,add) (put_user((val),(add)), 0) --# define __PUT_USER(val,add) PUT_USER((val),(add)) --# define PUT_USER_RET(val,add,ret) PUT_USER((val),(add)) --# define GET_USER(dest,add) ((dest)=get_user((add)), 0) --# define __GET_USER(dest,add) GET_USER((dest),(add)) --# define GET_USER_RET(dest,add,ret) GET_USER((dest),(add)) -- --#define ioremap(offset,size) vremap(offset,size) --#define iounmap(adr) /* */ -- --#define EXPORT_SYMBOL(s) /* */ --#define EXPORT_SYMBOL_NOVERS(s) /* */ -- --/* 2.1.10 and 2.1.43 introduced new functions. They are worth using */ -- --#if LINUX_VERSION_CODE < VERSION_CODE(2,1,10) -- --# include <asm/byteorder.h> --# ifdef __LITTLE_ENDIAN --# define cpu_to_le16(x) (x) --# define cpu_to_le32(x) (x) --# define cpu_to_be16(x) htons((x)) --# define cpu_to_be32(x) htonl((x)) --# else --# define cpu_to_be16(x) (x) --# define cpu_to_be32(x) (x) -- extern inline __u16 cpu_to_le16(__u16 x) { return (x<<8) | (x>>8);} -- extern inline __u32 cpu_to_le32(__u32 x) { return((x>>24) | -- ((x>>8)&0xff00) | ((x<<8)&0xff0000) | (x<<24));} --# endif -- --# define le16_to_cpu(x) cpu_to_le16(x) --# define le32_to_cpu(x) cpu_to_le32(x) --# define be16_to_cpu(x) cpu_to_be16(x) --# define be32_to_cpu(x) cpu_to_be32(x) -- --#endif -- --#if LINUX_VERSION_CODE < VERSION_CODE(2,1,43) --# define cpu_to_le16p(addr) (cpu_to_le16(*(addr))) --# define cpu_to_le32p(addr) (cpu_to_le32(*(addr))) --# define cpu_to_be16p(addr) (cpu_to_be16(*(addr))) --# define cpu_to_be32p(addr) (cpu_to_be32(*(addr))) -- -- extern inline void cpu_to_le16s(__u16 *a) {*a = cpu_to_le16(*a);} -- extern inline void cpu_to_le32s(__u16 *a) {*a = cpu_to_le32(*a);} -- extern inline void cpu_to_be16s(__u16 *a) {*a = cpu_to_be16(*a);} -- extern inline void cpu_to_be32s(__u16 *a) {*a = cpu_to_be32(*a);} -- --# define le16_to_cpup(x) cpu_to_le16p(x) --# define le32_to_cpup(x) cpu_to_le32p(x) --# define be16_to_cpup(x) cpu_to_be16p(x) --# define be32_to_cpup(x) cpu_to_be32p(x) -- --# define le16_to_cpus(x) cpu_to_le16s(x) --# define le32_to_cpus(x) cpu_to_le32s(x) --# define be16_to_cpus(x) cpu_to_be16s(x) --# define be32_to_cpus(x) cpu_to_be32s(x) --#endif -- --// from 2.2, linux/types.h --#ifndef __BIT_TYPES_DEFINED__ --#define __BIT_TYPES_DEFINED__ -- --typedef __u8 u_int8_t; --typedef __s8 int8_t; --typedef __u16 u_int16_t; --typedef __s16 int16_t; --typedef __u32 u_int32_t; --typedef __s32 int32_t; -- --#endif /* !(__BIT_TYPES_DEFINED__) */ -- --#if (__GNUC__ > 2) || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8) -- typedef struct { } spinlock_t; -- #define SPIN_LOCK_UNLOCKED (spinlock_t) { } --#else -- typedef struct { int gcc_is_buggy; } spinlock_t; -- #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } --#endif -- --#define spin_lock_init(lock) do { } while(0) --#define spin_lock(lock) (void)(lock) /* Not "unused variable". */ --#define spin_trylock(lock) (1) --#define spin_unlock_wait(lock) do { } while(0) --#define spin_unlock(lock) do { } while(0) --#define spin_lock_irq(lock) cli() --#define spin_unlock_irq(lock) sti() -- --#define spin_lock_irqsave(lock, flags) \ -- do { save_flags(flags); cli(); } while (0) --#define spin_unlock_irqrestore(lock, flags) \ -- restore_flags(flags) -- --// Doesn't work when tqueue.h is included. --// #define queue_task queue_task_irq_off --#define tty_flip_buffer_push(tty) queue_task_irq_off(&tty->flip.tqueue, &tq_timer) --#define signal_pending(current) (current->signal & ~current->blocked) --#define schedule_timeout(to) do {current->timeout = jiffies + (to);schedule ();} while (0) --#define time_after(t1,t2) (((long)t1-t2) > 0) -- --#else -- #include <linux/compatmac.h> --#endif // LINUX_VERSION_CODE < 0x020100 -- -- --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) --#include <linux/vmalloc.h> --#endif -- --/* Modularization issues */ --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18) --# define __USE_OLD_SYMTAB__ --# define EXPORT_NO_SYMBOLS register_symtab(NULL); --# define REGISTER_SYMTAB(tab) register_symtab(tab) --#else --# define REGISTER_SYMTAB(tab) /* nothing */ --#endif -- --#ifdef __USE_OLD_SYMTAB__ --# define __MODULE_STRING(s) /* nothing */ --# define MODULE_PARM(v,t) /* nothing */ --# define MODULE_PARM_DESC(v,t) /* nothing */ --# define MODULE_AUTHOR(n) /* nothing */ --# define MODULE_DESCRIPTION(d) /* nothing */ --# define MODULE_SUPPORTED_DEVICE(n) /* nothing */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) -+#error "This kernel is too old: not supported by this file" - #endif - --/* -- * "select" changed in 2.1.23. The implementation is twin, but this -- * header is new -- */ --#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,22) --# include <linux/poll.h> --#else --# define __USE_OLD_SELECT__ --#endif -+ /* O(1) scheduler stuff. */ - --/* Other change in the fops are solved using pseudo-types */ --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) --# define lseek_t long long --# define lseek_off_t long long --#else --# define lseek_t int --# define lseek_off_t off_t --#endif -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) && !defined(__rh_config_h__) -+#include <linux/sched.h> -+static inline void __recalc_sigpending(void) -+{ -+ recalc_sigpending(current); -+} -+#undef recalc_sigpending -+#define recalc_sigpending() __recalc_sigpending () - --/* changed the prototype of read/write */ -+#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0) - --#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) || defined(__alpha__) --# define count_t unsigned long --# define read_write_t long --#else --# define count_t int --# define read_write_t int - #endif - - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,31) --# define release_t void --# define release_return(x) return --#else --# define release_t int --# define release_return(x) return (x) --#endif -- --#if LINUX_VERSION_CODE < 0x20300 --#define __exit --#endif --#if LINUX_VERSION_CODE < 0x20200 --#define __init --#else --#include <linux/init.h> --#endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) --#define init_MUTEX(x) do {*(x) = MUTEX;} while (0) --#define init_MUTEX_LOCKED(x) do {*(x) = MUTEX_LOCKED;} while (0) --#endif -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,20) - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) --#define RQFUNC_ARG void --#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0) --#else --#define RQFUNC_ARG request_queue_t *q -+#ifndef yield -+#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0) - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,32) --#define blk_cleanup_queue(nr) do {blk_dev[nr].request_fn = 0;} while(0) --#define BLK_DEFAULT_QUEUE(nr) (blk_dev[nr].request_fn) --#define blk_init_queue(q, rq) do {q = rq;} while(0) -+#ifndef minor -+#define major(d) (MAJOR(to_kdev_t(d))) -+#define minor(d) (MINOR(to_kdev_t(d))) - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) --#ifdef CONFIG_MODULES --#define __MOD_INC_USE_COUNT(mod) \ -- (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE) --#define __MOD_DEC_USE_COUNT(mod) \ -- (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED) --#else --#define __MOD_INC_USE_COUNT(mod) --#define __MOD_DEC_USE_COUNT(mod) --#endif -+#ifndef mk_kdev -+#define mk_kdev(ma,mi) MKDEV(ma,mi) -+#define kdev_t_to_nr(x) (x) - #endif - -+#define need_resched() (current->need_resched) -+#define cond_resched() do { if need_resched() { yield(); } } while(0) - --#ifndef HAVE_INTER_MODULE --static inline void *inter_module_get(char *x) {return NULL;} --static inline void *inter_module_get_request(char *x, char *y) {return NULL;} --static inline void inter_module_put(const char *x) {} --static inline void inter_module_register(const char *x, struct module *y, const void *z) {} --static inline void inter_module_unregister(const char *x) {} -+#endif /* < 2.4.20 */ -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73) -+#define iminor(i) minor((i)->i_rdev) -+#define imajor(i) major((i)->i_rdev) -+#define old_encode_dev(d) ( (major(d)<<8) | minor(d) ) -+#define old_decode_dev(rdev) (kdev_t_to_nr(mk_kdev((rdev)>>8, (rdev)&0xff))) -+#define old_valid_dev(d) (1) - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61) - --#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL --#define init_waitqueue_head init_waitqueue -+#include <linux/sched.h> - -+#ifdef __rh_config_h__ -+#define sigmask_lock sighand->siglock -+#define sig sighand - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -- --static inline int try_inc_mod_count(struct module *mod) -+static inline void __daemonize_modvers(void) - { --#ifdef CONFIG_MODULES -- if (mod) -- __MOD_INC_USE_COUNT(mod); --#endif -- return 1; --} --#endif -+ daemonize(); - -+ spin_lock_irq(¤t->sigmask_lock); -+ sigfillset(¤t->blocked); -+ recalc_sigpending(); -+ spin_unlock_irq(¤t->sigmask_lock); -+} -+#undef daemonize -+#define daemonize(fmt, ...) do { \ -+ snprintf(current->comm, sizeof(current->comm), fmt ,##__VA_ARGS__); \ -+ __daemonize_modvers(); \ -+ } while(0) - --/* Yes, I'm aware that it's a fairly ugly hack. -- Until the __constant_* macros appear in Linus' own kernels, this is -- the way it has to be done. -- DW 19/1/00 -- */ -- --#include <asm/byteorder.h> -- --#ifndef __constant_cpu_to_le16 -- --#ifdef __BIG_ENDIAN --#define __constant_cpu_to_le64(x) ___swab64((x)) --#define __constant_le64_to_cpu(x) ___swab64((x)) --#define __constant_cpu_to_le32(x) ___swab32((x)) --#define __constant_le32_to_cpu(x) ___swab32((x)) --#define __constant_cpu_to_le16(x) ___swab16((x)) --#define __constant_le16_to_cpu(x) ___swab16((x)) --#define __constant_cpu_to_be64(x) ((__u64)(x)) --#define __constant_be64_to_cpu(x) ((__u64)(x)) --#define __constant_cpu_to_be32(x) ((__u32)(x)) --#define __constant_be32_to_cpu(x) ((__u32)(x)) --#define __constant_cpu_to_be16(x) ((__u16)(x)) --#define __constant_be16_to_cpu(x) ((__u16)(x)) --#else --#ifdef __LITTLE_ENDIAN --#define __constant_cpu_to_le64(x) ((__u64)(x)) --#define __constant_le64_to_cpu(x) ((__u64)(x)) --#define __constant_cpu_to_le32(x) ((__u32)(x)) --#define __constant_le32_to_cpu(x) ((__u32)(x)) --#define __constant_cpu_to_le16(x) ((__u16)(x)) --#define __constant_le16_to_cpu(x) ((__u16)(x)) --#define __constant_cpu_to_be64(x) ___swab64((x)) --#define __constant_be64_to_cpu(x) ___swab64((x)) --#define __constant_cpu_to_be32(x) ___swab32((x)) --#define __constant_be32_to_cpu(x) ___swab32((x)) --#define __constant_cpu_to_be16(x) ___swab16((x)) --#define __constant_be16_to_cpu(x) ___swab16((x)) --#else --#error No (recognised) endianness defined (unless it,s PDP) --#endif /* __LITTLE_ENDIAN */ --#endif /* __BIG_ENDIAN */ -- --#endif /* ifndef __constant_cpu_to_le16 */ -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -- #define mod_init_t int __init -- #define mod_exit_t void --#else -- #define mod_init_t static int __init -- #define mod_exit_t static void __exit --#endif -- --#ifndef THIS_MODULE --#ifdef MODULE --#define THIS_MODULE (&__this_module) --#else --#define THIS_MODULE (NULL) --#endif --#endif -- --#if LINUX_VERSION_CODE < 0x20300 --#include <linux/interrupt.h> --#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);}while(0) --#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();}while(0) --#else --#include <asm/softirq.h> --#include <linux/spinlock.h> --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) --#define set_current_state(state_value) \ -- do { current->state = (state_value); } while (0) --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) --static inline int invalidate_device(kdev_t dev, int do_sync) { -+static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) -+{ -+ unsigned long flags; -+ unsigned long ret; - -- if (do_sync) -- fsync_dev(dev); -+ spin_lock_irqsave(¤t->sigmask_lock, flags); -+ ret = dequeue_signal(mask, info); -+ spin_unlock_irqrestore(¤t->sigmask_lock, flags); - -- invalidate_buffers(dev); -- return 0; -+ return ret; - } --#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,5) --static inline int invalidate_device(kdev_t dev, int do_sync) { -- struct super_block *sb = get_super(dev); -- int res = 0; - -- if (do_sync) -- fsync_dev(dev); -- -- if (sb) -- res = invalidate_inodes(sb); -+static inline int allow_signal(int sig) -+{ -+ if (sig < 1 || sig > _NSIG) -+ return -EINVAL; - -- invalidate_buffers(dev); -- return res; -+ spin_lock_irq(¤t->sigmask_lock); -+ sigdelset(¤t->blocked, sig); -+ recalc_sigpending(); -+ /* Make sure the kernel neither eats it now converts to SIGKILL */ -+ current->sig->action[sig-1].sa.sa_handler = (void *)2; -+ spin_unlock_irq(¤t->sigmask_lock); -+ return 0; - } --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) --#undef min --#undef max --#undef min_t --#undef max_t --/* -- * min()/max() macros that also do -- * strict type-checking.. See the -- * "unnecessary" pointer comparison. -- */ --#define min(x,y) ({ \ -- const typeof(x) _x = (x); \ -- const typeof(y) _y = (y); \ -- (void) (&_x == &_y); \ -- _x < _y ? _x : _y; }) -- --#define max(x,y) ({ \ -- const typeof(x) _x = (x); \ -- const typeof(y) _y = (y); \ -- (void) (&_x == &_y); \ -- _x > _y ? _x : _y; }) -- --/* -- * ..and if you can't take the strict -- * types, you can specify one yourself. -- * -- * Or not use min/max at all, of course. -- */ --#define min_t(type,x,y) \ -- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; }) --#define max_t(type,x,y) \ -- ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; }) --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,7) --struct completion { -- struct semaphore s; --}; -- --#define complete(c) up(&(c)->s) --#define wait_for_completion(c) down(&(c)->s) --#define init_completion(c) init_MUTEX_LOCKED(&(c)->s); -- --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) --/* This came later */ --#define complete_and_exit(c, r) do { complete(c); do_exit(r); } while(0) --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \ -- (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__)) -+static inline int disallow_signal(int sig) -+{ -+ if (sig < 1 || sig > _NSIG) -+ return -EINVAL; - --#include <linux/genhd.h> -+ spin_lock_irq(¤t->sigmask_lock); -+ sigaddset(¤t->blocked, sig); -+ recalc_sigpending(); - --static inline void add_gendisk(struct gendisk *gp) --{ -- gp->next = gendisk_head; -- gendisk_head = gp; -+ current->sig->action[sig-1].sa.sa_handler = SIG_DFL; -+ spin_unlock_irq(¤t->sigmask_lock); -+ return 0; - } - --static inline void del_gendisk(struct gendisk *gp) --{ -- struct gendisk *gd, **gdp; -+#undef sighand -+#undef sigmask_lock - -- for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) -- if (*gdp == gp) { -- gd = *gdp; *gdp = gd->next; -- break; -- } --} -+#define PF_FREEZE 0 -+#define refrigerator(x) do { ; } while(0) - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,18) && defined(MODULE) -+ /* Module bits */ - --#define module_init(func) \ --mod_init_t init_module(void) { \ -- return func(); \ --} - --#define module_exit(func) \ --mod_exit_t cleanup_module(void) { \ -- return func(); \ --} -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) -+#define try_module_get(m) try_inc_mod_count(m) -+#define __module_get(m) do { if (!try_inc_mod_count(m)) BUG(); } while(0) -+#define module_put(m) do { if (m) __MOD_DEC_USE_COUNT((struct module *)(m)); } while(0) -+#define set_module_owner(x) do { x->owner = THIS_MODULE; } while(0) - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9) || \ -- (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) && !defined(__rh_config_h__)) --#define MODULE_LICENSE(x) /* */ --#endif - --/* Removed for 2.4.21 kernel. This really should have been renamed -- when it was changed -- this is a PITA */ --#if 0 && LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) --#include <linux/sched.h> --static inline void __recalc_sigpending(void) --{ -- recalc_sigpending(current); --} --#undef recalc_sigpending --#define recalc_sigpending() __recalc_sigpending () --#endif -+ /* Random filesystem stuff, only for JFFS2 really */ - - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,5) - #define parent_ino(d) ((d)->d_parent->d_inode->i_ino) - #endif - --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,3) --#define need_resched() (current->need_resched) --#define cond_resched() do { if need_resched() schedule(); } while(0) --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,19) --#ifndef yield --#define yield() do { set_current_state(TASK_RUNNING); schedule(); } while(0) --#endif --#ifndef minor --#define major(d) (MAJOR(to_kdev_t(d))) --#define minor(d) (MINOR(to_kdev_t(d))) --#endif --#ifndef mk_kdev --#define mk_kdev(ma,mi) MKDEV(ma,mi) --#define kdev_t_to_nr(x) (x) --#endif --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) -- /* Is this right? */ --#define set_user_nice(tsk, n) do { (tsk)->priority = 20-(n); } while(0) --#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) && !defined(RED_HAT_LINUX_KERNEL) --#define set_user_nice(tsk, n) do { (tsk)->nice = n; } while(0) --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,21) --#define rq_data_dir(x) ((x)->cmd) --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -- --#define IS_REQ_CMD(req) (1) -- --#define QUEUE_LOCK(q) (&io_request_lock) -- --#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req)) -- --#else /* > 2.5.0 */ -- --#define IS_REQ_CMD(req) ((req)->flags & REQ_CMD) -- --#define QUEUE_LOCK(q) ((q)->queue_lock) -- --#define BLK_INIT_QUEUE(q, req, lock) blk_init_queue((q), (req), (lock)) -- --#endif -- --/* Removed cos it broke stuff. Where is this required anyway? -- * #ifndef QUEUE_EMPTY -- * #define QUEUE_EMPTY (!CURRENT) -- * #endif -- */ --#if LINUX_VERSION_CODE < 0x20300 --#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync) --#elif LINUX_VERSION_CODE < 0x20500 //FIXME (Si) --#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged) --#else --#define QUEUE_PLUGGED (blk_queue_plugged(QUEUE)) --#endif -- --#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14) --#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT --#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT --#else --#define BLK_INC_USE_COUNT do {} while(0) --#define BLK_DEC_USE_COUNT do {} while(0) --#endif -- - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,12) - #define PageUptodate(x) Page_Uptodate(x) - #endif -@@ -580,4 +159,31 @@ - #define generic_file_readonly_mmap generic_file_mmap - #endif - -+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,70) -+ -+#include <linux/kmod.h> -+#include <linux/string.h> -+ -+static inline char *strlcpy(char *dest, const char *src, int len) -+{ -+ dest[len-1] = 0; -+ return strncpy(dest, src, len-1); -+} -+ -+static inline int do_old_request_module(const char *mod) -+{ -+ return request_module(mod); -+} -+#undef request_module -+#define request_module(fmt, ...) \ -+ ({ char modname[32]; snprintf(modname, 31, fmt ,##__VA_ARGS__); do_old_request_module(modname); }) -+ -+#endif /* 2.5.70 */ -+ -+#ifndef container_of -+#define container_of(ptr, type, member) ({ \ -+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ -+ (type *)( (char *)__mptr - offsetof(type,member) );}) -+#endif -+ - #endif /* __LINUX_MTD_COMPATMAC_H__ */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/doc2000.h linux/include/linux/mtd/doc2000.h ---- linux-mips-2.4.27/include/linux/mtd/doc2000.h 2001-11-05 21:16:30.000000000 +0100 -+++ linux/include/linux/mtd/doc2000.h 2004-11-19 10:25:12.044177752 +0100 -@@ -1,13 +1,21 @@ -- --/* Linux driver for Disk-On-Chip 2000 */ --/* (c) 1999 Machine Vision Holdings, Inc. */ --/* Author: David Woodhouse <dwmw2@mvhi.com> */ --/* $Id$ */ -+/* -+ * Linux driver for Disk-On-Chip devices -+ * -+ * Copyright (C) 1999 Machine Vision Holdings, Inc. -+ * Copyright (C) 2001-2003 David Woodhouse <dwmw2@infradead.org> -+ * Copyright (C) 2002-2003 Greg Ungerer <gerg@snapgear.com> -+ * Copyright (C) 2002-2003 SnapGear Inc -+ * -+ * $Id$ -+ * -+ * Released under GPL -+ */ - - #ifndef __MTD_DOC2000_H__ - #define __MTD_DOC2000_H__ - - #include <linux/mtd/mtd.h> -+#include <asm/semaphore.h> - - #define DoC_Sig1 0 - #define DoC_Sig2 1 -@@ -38,18 +46,47 @@ - #define DoC_Mil_CDSN_IO 0x0800 - #define DoC_2k_CDSN_IO 0x1800 - -+#define DoC_Mplus_NOP 0x1002 -+#define DoC_Mplus_AliasResolution 0x1004 -+#define DoC_Mplus_DOCControl 0x1006 -+#define DoC_Mplus_AccessStatus 0x1008 -+#define DoC_Mplus_DeviceSelect 0x1008 -+#define DoC_Mplus_Configuration 0x100a -+#define DoC_Mplus_OutputControl 0x100c -+#define DoC_Mplus_FlashControl 0x1020 -+#define DoC_Mplus_FlashSelect 0x1022 -+#define DoC_Mplus_FlashCmd 0x1024 -+#define DoC_Mplus_FlashAddress 0x1026 -+#define DoC_Mplus_FlashData0 0x1028 -+#define DoC_Mplus_FlashData1 0x1029 -+#define DoC_Mplus_ReadPipeInit 0x102a -+#define DoC_Mplus_LastDataRead 0x102c -+#define DoC_Mplus_LastDataRead1 0x102d -+#define DoC_Mplus_WritePipeTerm 0x102e -+#define DoC_Mplus_ECCSyndrome0 0x1040 -+#define DoC_Mplus_ECCSyndrome1 0x1041 -+#define DoC_Mplus_ECCSyndrome2 0x1042 -+#define DoC_Mplus_ECCSyndrome3 0x1043 -+#define DoC_Mplus_ECCSyndrome4 0x1044 -+#define DoC_Mplus_ECCSyndrome5 0x1045 -+#define DoC_Mplus_ECCConf 0x1046 -+#define DoC_Mplus_Toggle 0x1046 -+#define DoC_Mplus_DownloadStatus 0x1074 -+#define DoC_Mplus_CtrlConfirm 0x1076 -+#define DoC_Mplus_Power 0x1fff -+ - /* How to access the device? - * On ARM, it'll be mmap'd directly with 32-bit wide accesses. - * On PPC, it's mmap'd and 16-bit wide. - * Others use readb/writeb - */ - #if defined(__arm__) --#define ReadDOC_(adr, reg) ((unsigned char)(*(__u32 *)(((unsigned long)adr)+((reg)<<2)))) --#define WriteDOC_(d, adr, reg) do{ *(__u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) -+#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)))) -+#define WriteDOC_(d, adr, reg) do{ *(volatile __u32 *)(((unsigned long)adr)+((reg)<<2)) = (__u32)d; wmb();} while(0) - #define DOC_IOREMAP_LEN 0x8000 - #elif defined(__ppc__) --#define ReadDOC_(adr, reg) ((unsigned char)(*(__u16 *)(((unsigned long)adr)+((reg)<<1)))) --#define WriteDOC_(d, adr, reg) do{ *(__u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) -+#define ReadDOC_(adr, reg) ((unsigned char)(*(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)))) -+#define WriteDOC_(d, adr, reg) do{ *(volatile __u16 *)(((unsigned long)adr)+((reg)<<1)) = (__u16)d; wmb();} while(0) - #define DOC_IOREMAP_LEN 0x4000 - #else - #define ReadDOC_(adr, reg) readb(((unsigned long)adr) + (reg)) -@@ -71,13 +108,21 @@ - #define DOC_MODE_RESERVED1 2 - #define DOC_MODE_RESERVED2 3 - --#define DOC_MODE_MDWREN 4 - #define DOC_MODE_CLR_ERR 0x80 -+#define DOC_MODE_RST_LAT 0x10 -+#define DOC_MODE_BDECT 0x08 -+#define DOC_MODE_MDWREN 0x04 - - #define DOC_ChipID_Doc2k 0x20 -+#define DOC_ChipID_Doc2kTSOP 0x21 /* internal number for MTD */ - #define DOC_ChipID_DocMil 0x30 -+#define DOC_ChipID_DocMilPlus32 0x40 -+#define DOC_ChipID_DocMilPlus16 0x41 - - #define CDSN_CTRL_FR_B 0x80 -+#define CDSN_CTRL_FR_B0 0x40 -+#define CDSN_CTRL_FR_B1 0x80 -+ - #define CDSN_CTRL_ECC_IO 0x20 - #define CDSN_CTRL_FLASH_IO 0x10 - #define CDSN_CTRL_WP 0x08 -@@ -93,6 +138,10 @@ - #define DOC_ECC_RESV 0x02 - #define DOC_ECC_IGNORE 0x01 - -+#define DOC_FLASH_CE 0x80 -+#define DOC_FLASH_WP 0x40 -+#define DOC_FLASH_BANK 0x02 -+ - /* We have to also set the reserved bit 1 for enable */ - #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV) - #define DOC_ECC_DIS (DOC_ECC_RESV) -@@ -107,9 +156,12 @@ - #define MAX_FLOORS 4 - #define MAX_CHIPS 4 - --#define MAX_FLOORS_MIL 4 -+#define MAX_FLOORS_MIL 1 - #define MAX_CHIPS_MIL 1 - -+#define MAX_FLOORS_MPLUS 2 -+#define MAX_CHIPS_MPLUS 1 -+ - #define ADDR_COLUMN 1 - #define ADDR_PAGE 2 - #define ADDR_COLUMN_PAGE 3 -@@ -118,7 +170,7 @@ - unsigned long physadr; - unsigned long virtadr; - unsigned long totlen; -- char ChipID; /* Type of DiskOnChip */ -+ unsigned char ChipID; /* Type of DiskOnChip */ - int ioreg; - - unsigned long mfr; /* Flash IDs - only one type of flash per device */ -@@ -126,6 +178,7 @@ - int chipshift; - char page256; - char pageadrlen; -+ char interleave; /* Internal interleaving - Millennium Plus style */ - unsigned long erasesize; - - int curfloor; -diff -Nurb linux-mips-2.4.27/include/linux/mtd/flashchip.h linux/include/linux/mtd/flashchip.h ---- linux-mips-2.4.27/include/linux/mtd/flashchip.h 2003-02-26 01:53:51.000000000 +0100 -+++ linux/include/linux/mtd/flashchip.h 2004-11-19 10:25:12.045177600 +0100 -@@ -6,7 +6,7 @@ - * - * (C) 2000 Red Hat. GPLd. - * -- * $Id$ -+ * $Id$ - * - */ - -@@ -58,6 +58,11 @@ - int ref_point_counter; - flstate_t state; - flstate_t oldstate; -+ -+ int write_suspended:1; -+ int erase_suspended:1; -+ unsigned long in_progress_block_addr; -+ - spinlock_t *mutex; - spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */ - wait_queue_head_t wq; /* Wait on here when we're waiting for the chip -diff -Nurb linux-mips-2.4.27/include/linux/mtd/gen_probe.h linux/include/linux/mtd/gen_probe.h ---- linux-mips-2.4.27/include/linux/mtd/gen_probe.h 2001-11-05 21:16:30.000000000 +0100 -+++ linux/include/linux/mtd/gen_probe.h 2004-11-19 10:25:12.048177144 +0100 -@@ -1,7 +1,7 @@ - /* - * (C) 2001, 2001 Red Hat, Inc. - * GPL'd -- * $Id$ -+ * $Id$ - */ - - #ifndef __LINUX_MTD_GEN_PROBE_H__ -@@ -10,12 +10,12 @@ - #include <linux/mtd/flashchip.h> - #include <linux/mtd/map.h> - #include <linux/mtd/cfi.h> -+#include <asm/bitops.h> - - struct chip_probe { - char *name; - int (*probe_chip)(struct map_info *map, __u32 base, -- struct flchip *chips, struct cfi_private *cfi); -- -+ unsigned long *chip_map, struct cfi_private *cfi); - }; - - struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp); -diff -Nurb linux-mips-2.4.27/include/linux/mtd/inftl.h linux/include/linux/mtd/inftl.h ---- linux-mips-2.4.27/include/linux/mtd/inftl.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/include/linux/mtd/inftl.h 2004-11-19 10:25:12.051176688 +0100 -@@ -0,0 +1,129 @@ -+/* -+ * inftl.h -- defines to support the Inverse NAND Flash Translation Layer -+ * -+ * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) -+ * -+ * $Id$ -+ */ -+ -+#ifndef __MTD_INFTL_H__ -+#define __MTD_INFTL_H__ -+ -+#include <linux/mtd/blktrans.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/nftl.h> -+ -+#define OSAK_VERSION 0x5120 -+#define PERCENTUSED 98 -+ -+#define SECTORSIZE 512 -+ -+#ifndef INFTL_MAJOR -+#define INFTL_MAJOR 94 -+#endif -+#define INFTL_PARTN_BITS 4 -+ -+/* Block Control Information */ -+ -+struct inftl_bci { -+ __u8 ECCsig[6]; -+ __u8 Status; -+ __u8 Status1; -+} __attribute__((packed)); -+ -+struct inftl_unithead1 { -+ __u16 virtualUnitNo; -+ __u16 prevUnitNo; -+ __u8 ANAC; -+ __u8 NACs; -+ __u8 parityPerField; -+ __u8 discarded; -+} __attribute__((packed)); -+ -+struct inftl_unithead2 { -+ __u8 parityPerField; -+ __u8 ANAC; -+ __u16 prevUnitNo; -+ __u16 virtualUnitNo; -+ __u8 NACs; -+ __u8 discarded; -+} __attribute__((packed)); -+ -+struct inftl_unittail { -+ __u8 Reserved[4]; -+ __u16 EraseMark; -+ __u16 EraseMark1; -+} __attribute__((packed)); -+ -+union inftl_uci { -+ struct inftl_unithead1 a; -+ struct inftl_unithead2 b; -+ struct inftl_unittail c; -+}; -+ -+struct inftl_oob { -+ struct inftl_bci b; -+ union inftl_uci u; -+}; -+ -+ -+/* INFTL Media Header */ -+ -+struct INFTLPartition { -+ __u32 virtualUnits; -+ __u32 firstUnit; -+ __u32 lastUnit; -+ __u32 flags; -+ __u32 spareUnits; -+ __u32 Reserved0; -+ __u32 Reserved1; -+} __attribute__((packed)); -+ -+struct INFTLMediaHeader { -+ char bootRecordID[8]; -+ __u32 NoOfBootImageBlocks; -+ __u32 NoOfBinaryPartitions; -+ __u32 NoOfBDTLPartitions; -+ __u32 BlockMultiplierBits; -+ __u32 FormatFlags; -+ __u32 OsakVersion; -+ __u32 PercentUsed; -+ struct INFTLPartition Partitions[4]; -+} __attribute__((packed)); -+ -+/* Partition flag types */ -+#define INFTL_BINARY 0x20000000 -+#define INFTL_BDTL 0x40000000 -+#define INFTL_LAST 0x80000000 -+ -+ -+#ifdef __KERNEL__ -+ -+struct INFTLrecord { -+ struct mtd_blktrans_dev mbd; -+ __u16 MediaUnit, SpareMediaUnit; -+ __u32 EraseSize; -+ struct INFTLMediaHeader MediaHdr; -+ int usecount; -+ unsigned char heads; -+ unsigned char sectors; -+ unsigned short cylinders; -+ __u16 numvunits; -+ __u16 firstEUN; -+ __u16 lastEUN; -+ __u16 numfreeEUNs; -+ __u16 LastFreeEUN; /* To speed up finding a free EUN */ -+ int head,sect,cyl; -+ __u16 *PUtable; /* Physical Unit Table */ -+ __u16 *VUtable; /* Virtual Unit Table */ -+ unsigned int nb_blocks; /* number of physical blocks */ -+ unsigned int nb_boot_blocks; /* number of blocks used by the bios */ -+ struct erase_info instr; -+}; -+ -+int INFTL_mount(struct INFTLrecord *s); -+int INFTL_formatblock(struct INFTLrecord *s, int block); -+ -+#endif /* __KERNEL__ */ -+ -+#endif /* __MTD_INFTL_H__ */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/jedec.h linux/include/linux/mtd/jedec.h ---- linux-mips-2.4.27/include/linux/mtd/jedec.h 2001-12-02 12:35:00.000000000 +0100 -+++ linux/include/linux/mtd/jedec.h 2004-11-19 10:25:12.052176536 +0100 -@@ -7,14 +7,13 @@ - * - * See the AMD flash databook for information on how to operate the interface. - * -- * $Id$ -+ * $Id$ - */ - - #ifndef __LINUX_MTD_JEDEC_H__ - #define __LINUX_MTD_JEDEC_H__ - - #include <linux/types.h> --#include <linux/mtd/map.h> - - #define MAX_JEDEC_CHIPS 16 - -diff -Nurb linux-mips-2.4.27/include/linux/mtd/map.h linux/include/linux/mtd/map.h ---- linux-mips-2.4.27/include/linux/mtd/map.h 2003-02-26 01:53:51.000000000 +0100 -+++ linux/include/linux/mtd/map.h 2004-11-19 10:25:12.054176232 +0100 -@@ -1,14 +1,15 @@ - - /* Overhauled routines for dealing with different mmap regions of flash */ --/* $Id$ */ -+/* $Id$ */ - - #ifndef __LINUX_MTD_MAP_H__ - #define __LINUX_MTD_MAP_H__ - - #include <linux/config.h> - #include <linux/types.h> --#include <linux/mtd/mtd.h> --#include <linux/slab.h> -+#include <linux/list.h> -+#include <asm/system.h> -+#include <asm/io.h> - - /* The map stuff is very simple. You fill in your struct map_info with - a handful of routines for accessing the device, making sure they handle -@@ -29,39 +30,44 @@ - struct map_info { - char *name; - unsigned long size; -+ unsigned long phys; -+#define NO_XIP (-1UL) -+ -+ unsigned long virt; -+ void *cached; -+ - int buswidth; /* in octets */ -- __u8 (*read8)(struct map_info *, unsigned long); -- __u16 (*read16)(struct map_info *, unsigned long); -- __u32 (*read32)(struct map_info *, unsigned long); -- __u64 (*read64)(struct map_info *, unsigned long); -+ -+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS -+ u8 (*read8)(struct map_info *, unsigned long); -+ u16 (*read16)(struct map_info *, unsigned long); -+ u32 (*read32)(struct map_info *, unsigned long); -+ u64 (*read64)(struct map_info *, unsigned long); - /* If it returned a 'long' I'd call it readl. - * It doesn't. - * I won't. - * dwmw2 */ - - void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); -- void (*write8)(struct map_info *, __u8, unsigned long); -- void (*write16)(struct map_info *, __u16, unsigned long); -- void (*write32)(struct map_info *, __u32, unsigned long); -- void (*write64)(struct map_info *, __u64, unsigned long); -+ void (*write8)(struct map_info *, u8, unsigned long); -+ void (*write16)(struct map_info *, u16, unsigned long); -+ void (*write32)(struct map_info *, u32, unsigned long); -+ void (*write64)(struct map_info *, u64, unsigned long); - void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); - -- u_char * (*point) (struct map_info *, loff_t, size_t); -- void (*unpoint) (struct map_info *, u_char *, loff_t, size_t); -- -+ /* We can perhaps put in 'point' and 'unpoint' methods, if we really -+ want to enable XIP for non-linear mappings. Not yet though. */ -+#endif -+ /* set_vpp() must handle being reentered -- enable, enable, disable -+ must leave it enabled. */ - void (*set_vpp)(struct map_info *, int); -- /* We put these two here rather than a single void *map_priv, -- because we want mappers to be able to have quickly-accessible -- cache for the 'currently-mapped page' without the _extra_ -- redirection that would be necessary. If you need more than -- two longs, turn the second into a pointer. dwmw2 */ -+ - unsigned long map_priv_1; - unsigned long map_priv_2; - void *fldrv_priv; - struct mtd_chip_driver *fldrv; - }; - -- - struct mtd_chip_driver { - struct mtd_info *(*probe)(struct map_info *map); - void (*destroy)(struct mtd_info *); -@@ -74,26 +80,93 @@ - void unregister_mtd_chip_driver(struct mtd_chip_driver *); - - struct mtd_info *do_map_probe(const char *name, struct map_info *map); -+void map_destroy(struct mtd_info *mtd); -+ -+#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) -+#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) -+ -+#ifdef CONFIG_MTD_COMPLEX_MAPPINGS -+#define map_read8(map, ofs) (map)->read8(map, ofs) -+#define map_read16(map, ofs) (map)->read16(map, ofs) -+#define map_read32(map, ofs) (map)->read32(map, ofs) -+#define map_read64(map, ofs) (map)->read64(map, ofs) -+#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len) -+#define map_write8(map, datum, ofs) (map)->write8(map, datum, ofs) -+#define map_write16(map, datum, ofs) (map)->write16(map, datum, ofs) -+#define map_write32(map, datum, ofs) (map)->write32(map, datum, ofs) -+#define map_write64(map, datum, ofs) (map)->write64(map, datum, ofs) -+#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len) - -+extern void simple_map_init(struct map_info *); -+#define map_is_linear(map) (map->phys != NO_XIP) - --/* -- * Destroy an MTD device which was created for a map device. -- * Make sure the MTD device is already unregistered before calling this -- */ --static inline void map_destroy(struct mtd_info *mtd) --{ -- struct map_info *map = mtd->priv; -- -- if (map->fldrv->destroy) -- map->fldrv->destroy(mtd); --#ifdef CONFIG_MODULES -- if (map->fldrv->module) -- __MOD_DEC_USE_COUNT(map->fldrv->module); -+#else -+static inline u8 map_read8(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readb(map->virt + ofs); -+} -+ -+static inline u16 map_read16(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readw(map->virt + ofs); -+} -+ -+static inline u32 map_read32(struct map_info *map, unsigned long ofs) -+{ -+ return __raw_readl(map->virt + ofs); -+} -+ -+static inline u64 map_read64(struct map_info *map, unsigned long ofs) -+{ -+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ -+ BUG(); -+ return 0; -+#else -+ return __raw_readll(map->virt + ofs); - #endif -- kfree(mtd); - } - --#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) --#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) -+static inline void map_write8(struct map_info *map, u8 datum, unsigned long ofs) -+{ -+ __raw_writeb(datum, map->virt + ofs); -+ mb(); -+} -+ -+static inline void map_write16(struct map_info *map, u16 datum, unsigned long ofs) -+{ -+ __raw_writew(datum, map->virt + ofs); -+ mb(); -+} -+ -+static inline void map_write32(struct map_info *map, u32 datum, unsigned long ofs) -+{ -+ __raw_writel(datum, map->virt + ofs); -+ mb(); -+} -+ -+static inline void map_write64(struct map_info *map, u64 datum, unsigned long ofs) -+{ -+#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ -+ BUG(); -+#else -+ __raw_writell(datum, map->virt + ofs); -+ mb(); -+#endif /* CFI_B8 */ -+} -+ -+static inline void map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -+{ -+ memcpy_fromio(to, map->virt + from, len); -+} -+ -+static inline void map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -+{ -+ memcpy_toio(map->virt + to, from, len); -+} -+ -+#define simple_map_init(map) do { } while (0) -+#define map_is_linear(map) (1) -+ -+#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ - - #endif /* __LINUX_MTD_MAP_H__ */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/mtd.h linux/include/linux/mtd/mtd.h ---- linux-mips-2.4.27/include/linux/mtd/mtd.h 2003-08-13 19:19:29.000000000 +0200 -+++ linux/include/linux/mtd/mtd.h 2004-11-19 10:25:12.055176080 +0100 -@@ -1,5 +1,10 @@ -- --/* $Id$ */ -+/* -+ * $Id$ -+ * -+ * Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al. -+ * -+ * Released under GPL -+ */ - - #ifndef __MTD_MTD_H__ - #define __MTD_MTD_H__ -@@ -9,7 +14,6 @@ - #include <linux/config.h> - #include <linux/version.h> - #include <linux/types.h> --#include <linux/mtd/compatmac.h> - #include <linux/module.h> - #include <linux/uio.h> - -@@ -26,7 +30,6 @@ - unsigned char *ptr; - }; - -- - #define MTD_CHAR_MAJOR 90 - #define MTD_BLOCK_MAJOR 31 - #define MAX_MTD_DEVICES 16 -@@ -93,18 +96,23 @@ - #define MEMUNLOCK _IOW('M', 6, struct erase_info_user) - #define MEMGETREGIONCOUNT _IOR('M', 7, int) - #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) --#define MEMREADDATA _IOWR('M', 9, struct mtd_oob_buf) --#define MEMWRITEDATA _IOWR('M', 10, struct mtd_oob_buf) -+#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) -+ -+struct nand_oobinfo { -+ int useecc; -+ int eccpos[6]; -+}; -+ - - #ifndef __KERNEL__ - - typedef struct mtd_info_user mtd_info_t; - typedef struct erase_info_user erase_info_t; - typedef struct region_info_user region_info_t; -+typedef struct nand_oobinfo nand_oobinfo_t; - - /* User-space ioctl definitions */ - -- - #else /* __KERNEL__ */ - - -@@ -150,10 +158,14 @@ - u_int32_t ecctype; - u_int32_t eccsize; - -+ - // Kernel-only stuff starts here. - char *name; - int index; - -+ // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) -+ struct nand_oobinfo oobinfo; -+ - /* Data for variable erase regions. If numeraseregions is zero, - * it means that the whole device has erasesize as given above. - */ -@@ -163,7 +175,6 @@ - /* This really shouldn't be here. It can go away in 2.5 */ - u_int32_t bank_size; - -- struct module *module; - int (*erase) (struct mtd_info *mtd, struct erase_info *instr); - - /* This stuff for eXecute-In-Place */ -@@ -176,8 +187,8 @@ - int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - -- int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel); -- int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel); -+ int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); -+ int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); - - int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); -@@ -201,10 +212,10 @@ - */ - int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen); - int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, -- size_t *retlen, u_char *eccbuf, int oobsel); -+ size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); - int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen); - int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, -- size_t *retlen, u_char *eccbuf, int oobsel); -+ size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); - - /* Sync */ - void (*sync) (struct mtd_info *mtd); -@@ -218,6 +229,9 @@ - void (*resume) (struct mtd_info *mtd); - - void *priv; -+ -+ struct module *owner; -+ int usecount; - }; - - -@@ -226,31 +240,15 @@ - extern int add_mtd_device(struct mtd_info *mtd); - extern int del_mtd_device (struct mtd_info *mtd); - --extern struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num); -- --static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) --{ -- struct mtd_info *ret; -+extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); - -- ret = __get_mtd_device(mtd, num); -- -- if (ret && ret->module && !try_inc_mod_count(ret->module)) -- return NULL; -- -- return ret; --} -- --static inline void put_mtd_device(struct mtd_info *mtd) --{ -- if (mtd->module) -- __MOD_DEC_USE_COUNT(mtd->module); --} -+extern void put_mtd_device(struct mtd_info *mtd); - - - struct mtd_notifier { - void (*add)(struct mtd_info *mtd); - void (*remove)(struct mtd_info *mtd); -- struct mtd_notifier *next; -+ struct list_head list; - }; - - -@@ -263,7 +261,6 @@ - int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs, - unsigned long count, loff_t from, size_t *retlen); - --#ifndef MTDC - #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args) - #define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d)) - #define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg) -@@ -276,7 +273,6 @@ - #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) - #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) - #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) --#endif /* MTDC */ - - /* - * Debugging macro and defines -@@ -293,7 +289,8 @@ - printk(KERN_INFO args); \ - } while(0) - #else /* CONFIG_MTD_DEBUG */ --#define DEBUG(n, args...) -+#define DEBUG(n, args...) do { } while(0) -+ - #endif /* CONFIG_MTD_DEBUG */ - - #endif /* __KERNEL__ */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/nand.h linux/include/linux/mtd/nand.h ---- linux-mips-2.4.27/include/linux/mtd/nand.h 2003-02-26 01:53:51.000000000 +0100 -+++ linux/include/linux/mtd/nand.h 2004-11-19 10:25:12.057175776 +0100 -@@ -2,10 +2,10 @@ - * linux/include/linux/mtd/nand.h - * - * Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com> -- * Steven J. Hill <sjhill@cotw.com> -+ * Steven J. Hill <sjhill@realitydiluted.com> - * Thomas Gleixner <tglx@linutronix.de> - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -49,12 +49,14 @@ - #define __LINUX_MTD_NAND_H - - #include <linux/config.h> --#include <linux/sched.h> -+#include <linux/wait.h> -+#include <linux/spinlock.h> - -+struct mtd_info; - /* - * Searches for a NAND device - */ --extern int nand_scan (struct mtd_info *mtd); -+extern int nand_scan (struct mtd_info *mtd, int max_chips); - - /* - * Constants for hardware specific CLE/ALE/NCE function -@@ -65,6 +67,8 @@ - #define NAND_CTL_CLRCLE 4 - #define NAND_CTL_SETALE 5 - #define NAND_CTL_CLRALE 6 -+#define NAND_CTL_SETWP 7 -+#define NAND_CTL_CLRWP 8 - - /* - * Standard NAND flash commands -@@ -160,24 +164,33 @@ - struct nand_chip { - unsigned long IO_ADDR_R; - unsigned long IO_ADDR_W; -- void (*hwcontrol)(int cmd); -- int (*dev_ready)(void); -+ -+ u_char (*read_byte)(struct mtd_info *mtd); -+ void (*write_byte)(struct mtd_info *mtd, u_char byte); -+ -+ void (*write_buf)(struct mtd_info *mtd, const u_char *buf, int len); -+ void (*read_buf)(struct mtd_info *mtd, u_char *buf, int len); -+ int (*verify_buf)(struct mtd_info *mtd, const u_char *buf, int len); -+ void (*select_chip)(struct mtd_info *mtd, int chip); -+ int (*block_bad)(struct mtd_info *mtd, unsigned long pos); -+ void (*hwcontrol)(struct mtd_info *mtd, int cmd); -+ int (*dev_ready)(struct mtd_info *mtd); - void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); - int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); -- void (*calculate_ecc)(const u_char *dat, u_char *ecc_code); -- int (*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc); -- void (*enable_hwecc)(int mode); -+ void (*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); -+ int (*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); -+ void (*enable_hwecc)(struct mtd_info *mtd, int mode); - int eccmode; - int eccsize; - int chip_delay; -+ int chipshift; - spinlock_t chip_lock; - wait_queue_head_t wq; - nand_state_t state; - int page_shift; - u_char *data_buf; - u_char *data_poi; -- u_char *data_cache; -- int cache_page; -+ void *priv; - }; - - /* -@@ -241,34 +254,4 @@ - */ - #define NAND_BADBLOCK_POS 5 - --#define NAND_NONE_OOB 0 --#define NAND_JFFS2_OOB 1 --#define NAND_YAFFS_OOB 2 -- --#define NAND_NOOB_ECCPOS0 0 --#define NAND_NOOB_ECCPOS1 1 --#define NAND_NOOB_ECCPOS2 2 --#define NAND_NOOB_ECCPOS3 3 --#define NAND_NOOB_ECCPOS4 6 --#define NAND_NOOB_ECCPOS5 7 -- --#define NAND_JFFS2_OOB_ECCPOS0 0 --#define NAND_JFFS2_OOB_ECCPOS1 1 --#define NAND_JFFS2_OOB_ECCPOS2 2 --#define NAND_JFFS2_OOB_ECCPOS3 3 --#define NAND_JFFS2_OOB_ECCPOS4 6 --#define NAND_JFFS2_OOB_ECCPOS5 7 -- --#define NAND_YAFFS_OOB_ECCPOS0 8 --#define NAND_YAFFS_OOB_ECCPOS1 9 --#define NAND_YAFFS_OOB_ECCPOS2 10 --#define NAND_YAFFS_OOB_ECCPOS3 13 --#define NAND_YAFFS_OOB_ECCPOS4 14 --#define NAND_YAFFS_OOB_ECCPOS5 15 -- --#define NAND_JFFS2_OOB8_FSDAPOS 6 --#define NAND_JFFS2_OOB16_FSDAPOS 8 --#define NAND_JFFS2_OOB8_FSDALEN 2 --#define NAND_JFFS2_OOB16_FSDALEN 8 -- - #endif /* __LINUX_MTD_NAND_H */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/nand_ecc.h linux/include/linux/mtd/nand_ecc.h ---- linux-mips-2.4.27/include/linux/mtd/nand_ecc.h 2001-08-22 05:25:12.000000000 +0200 -+++ linux/include/linux/mtd/nand_ecc.h 2004-11-19 10:25:12.058175624 +0100 -@@ -1,9 +1,9 @@ - /* - * drivers/mtd/nand_ecc.h - * -- * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) -+ * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) - * -- * $Id$ -+ * $Id$ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as -@@ -12,17 +12,19 @@ - * This file is the header for the ECC algorithm. - */ - --/* -- * Creates non-inverted ECC code from line parity -- */ --void nand_trans_result(u_char reg2, u_char reg3, u_char *ecc_code); -+#ifndef __MTD_NAND_ECC_H__ -+#define __MTD_NAND_ECC_H__ -+ -+struct mtd_info; - - /* - * Calculate 3 byte ECC code for 256 byte block - */ --void nand_calculate_ecc (const u_char *dat, u_char *ecc_code); -+void nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code); - - /* - * Detect and correct a 1 bit error for 256 byte block - */ --int nand_correct_data (u_char *dat, u_char *read_ecc, u_char *calc_ecc); -+int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc); -+ -+#endif /* __MTD_NAND_ECC_H__ */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/nftl.h linux/include/linux/mtd/nftl.h ---- linux-mips-2.4.27/include/linux/mtd/nftl.h 2003-02-26 01:53:51.000000000 +0100 -+++ linux/include/linux/mtd/nftl.h 2004-11-19 10:25:12.060175320 +0100 -@@ -1,15 +1,14 @@ -- --/* Defines for NAND Flash Translation Layer */ --/* (c) 1999 Machine Vision Holdings, Inc. */ --/* Author: David Woodhouse <dwmw2@mvhi.com> */ --/* $Id$ */ -+/* -+ * $Id$ -+ * -+ * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> -+ */ - - #ifndef __MTD_NFTL_H__ - #define __MTD_NFTL_H__ - --#ifndef __BOOT__ - #include <linux/mtd/mtd.h> --#endif -+#include <linux/mtd/blktrans.h> - - /* Block Control Information */ - -@@ -84,8 +83,7 @@ - #define BLOCK_RESERVED 0xfffc /* bios block or bad block */ - - struct NFTLrecord { -- struct mtd_info *mtd; -- struct semaphore mutex; -+ struct mtd_blktrans_dev mbd; - __u16 MediaUnit, SpareMediaUnit; - __u32 EraseSize; - struct NFTLMediaHeader MediaHdr; -@@ -97,7 +95,6 @@ - __u16 lastEUN; /* should be suppressed */ - __u16 numfreeEUNs; - __u16 LastFreeEUN; /* To speed up finding a free EUN */ -- __u32 nr_sects; - int head,sect,cyl; - __u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */ - __u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */ -@@ -114,7 +111,7 @@ - #endif - - #define MAX_NFTLS 16 --#define MAX_SECTORS_PER_UNIT 32 -+#define MAX_SECTORS_PER_UNIT 64 - #define NFTL_PARTN_BITS 4 - - #endif /* __KERNEL__ */ -diff -Nurb linux-mips-2.4.27/include/linux/mtd/partitions.h linux/include/linux/mtd/partitions.h ---- linux-mips-2.4.27/include/linux/mtd/partitions.h 2002-06-27 00:36:47.000000000 +0200 -+++ linux/include/linux/mtd/partitions.h 2004-11-19 10:25:12.061175168 +0100 -@@ -5,7 +5,7 @@ - * - * This code is GPL - * -- * $Id$ -+ * $Id$ - */ - - #ifndef MTD_PARTITIONS_H -@@ -41,6 +41,7 @@ - u_int32_t size; /* partition size */ - u_int32_t offset; /* offset within the master MTD space */ - u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ -+ struct nand_oobinfo *oobsel; /* out of band layout for this partition (NAND only)*/ - struct mtd_info **mtdp; /* pointer to store the MTD object */ - }; - -@@ -49,8 +50,27 @@ - #define MTDPART_SIZ_FULL (0) - - --int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int); -+int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int); - int del_mtd_partitions(struct mtd_info *); - -+/* -+ * Functions dealing with the various ways of partitioning the space -+ */ -+ -+struct mtd_part_parser { -+ struct list_head list; -+ struct module *owner; -+ const char *name; -+ int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long); -+}; -+ -+extern struct mtd_part_parser *get_partition_parser(const char *name); -+extern int register_mtd_parser(struct mtd_part_parser *parser); -+extern int deregister_mtd_parser(struct mtd_part_parser *parser); -+extern int parse_mtd_partitions(struct mtd_info *master, const char **types, -+ struct mtd_partition **pparts, unsigned long origin); -+ -+#define put_partition_parser(p) do { module_put((p)->owner); } while(0) -+ - #endif - -diff -Nurb linux-mips-2.4.27/include/linux/mtd/physmap.h linux/include/linux/mtd/physmap.h ---- linux-mips-2.4.27/include/linux/mtd/physmap.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/include/linux/mtd/physmap.h 2004-11-19 10:25:12.062175016 +0100 -@@ -0,0 +1,59 @@ -+/* -+ * For boards with physically mapped flash and using -+ * drivers/mtd/maps/physmap.c mapping driver. -+ * -+ * Copyright (C) 2003 MontaVista Software Inc. -+ * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net -+ * -+ * This program is free software; you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation; either version 2 of the License, or (at your -+ * option) any later version. -+ * -+ */ -+ -+#ifndef __LINUX_MTD_PHYSMAP__ -+ -+#include <linux/config.h> -+ -+#if defined(CONFIG_MTD_PHYSMAP) -+ -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/map.h> -+#include <linux/mtd/partitions.h> -+ -+/* -+ * The map_info for physmap. Board can override size, buswidth, phys, -+ * (*set_vpp)(), etc in their initial setup routine. -+ */ -+extern struct map_info physmap_map; -+ -+/* -+ * Board needs to specify the exact mapping during their setup time. -+ */ -+static inline void physmap_configure(unsigned long addr, unsigned long size, int buswidth, void (*set_vpp)(struct map_info *, int) ) -+{ -+ physmap_map.phys = addr; -+ physmap_map.size = size; -+ physmap_map.buswidth = buswidth; -+ physmap_map.set_vpp = set_vpp; -+} -+ -+#if defined(CONFIG_MTD_PARTITIONS) -+ -+/* -+ * Machines that wish to do flash partition may want to call this function in -+ * their setup routine. -+ * -+ * physmap_set_partitions(mypartitions, num_parts); -+ * -+ * Note that one can always override this hard-coded partition with -+ * command line partition (you need to enable CONFIG_MTD_CMDLINE_PARTS). -+ */ -+void physmap_set_partitions(struct mtd_partition *parts, int num_parts); -+ -+#endif /* defined(CONFIG_MTD_PARTITIONS) */ -+#endif /* defined(CONFIG_MTD) */ -+ -+#endif /* __LINUX_MTD_PHYSMAP__ */ -+ -diff -Nurb linux-mips-2.4.27/include/linux/rbtree-24.h linux/include/linux/rbtree-24.h ---- linux-mips-2.4.27/include/linux/rbtree-24.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/include/linux/rbtree-24.h 2004-11-19 10:25:12.143162704 +0100 -@@ -0,0 +1,133 @@ -+/* -+ Red Black Trees -+ (C) 1999 Andrea Arcangeli <andrea@suse.de> -+ -+ This program is free software; you can redistribute it and/or modify -+ it under the terms of the GNU General Public License as published by -+ the Free Software Foundation; either version 2 of the License, or -+ (at your option) any later version. -+ -+ This program is distributed in the hope that it will be useful, -+ but WITHOUT ANY WARRANTY; without even the implied warranty of -+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ GNU General Public License for more details. -+ -+ You should have received a copy of the GNU General Public License -+ along with this program; if not, write to the Free Software -+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -+ -+ linux/include/linux/rbtree.h -+ -+ To use rbtrees you'll have to implement your own insert and search cores. -+ This will avoid us to use callbacks and to drop drammatically performances. -+ I know it's not the cleaner way, but in C (not in C++) to get -+ performances and genericity... -+ -+ Some example of insert and search follows here. The search is a plain -+ normal search over an ordered tree. The insert instead must be implemented -+ int two steps: as first thing the code must insert the element in -+ order as a red leaf in the tree, then the support library function -+ rb_insert_color() must be called. Such function will do the -+ not trivial work to rebalance the rbtree if necessary. -+ -+----------------------------------------------------------------------- -+static inline struct page * rb_search_page_cache(struct inode * inode, -+ unsigned long offset) -+{ -+ rb_node_t * n = inode->i_rb_page_cache.rb_node; -+ struct page * page; -+ -+ while (n) -+ { -+ page = rb_entry(n, struct page, rb_page_cache); -+ -+ if (offset < page->offset) -+ n = n->rb_left; -+ else if (offset > page->offset) -+ n = n->rb_right; -+ else -+ return page; -+ } -+ return NULL; -+} -+ -+static inline struct page * __rb_insert_page_cache(struct inode * inode, -+ unsigned long offset, -+ rb_node_t * node) -+{ -+ rb_node_t ** p = &inode->i_rb_page_cache.rb_node; -+ rb_node_t * parent = NULL; -+ struct page * page; -+ -+ while (*p) -+ { -+ parent = *p; -+ page = rb_entry(parent, struct page, rb_page_cache); -+ -+ if (offset < page->offset) -+ p = &(*p)->rb_left; -+ else if (offset > page->offset) -+ p = &(*p)->rb_right; -+ else -+ return page; -+ } -+ -+ rb_link_node(node, parent, p); -+ -+ return NULL; -+} -+ -+static inline struct page * rb_insert_page_cache(struct inode * inode, -+ unsigned long offset, -+ rb_node_t * node) -+{ -+ struct page * ret; -+ if ((ret = __rb_insert_page_cache(inode, offset, node))) -+ goto out; -+ rb_insert_color(node, &inode->i_rb_page_cache); -+ out: -+ return ret; -+} -+----------------------------------------------------------------------- -+*/ -+ -+#ifndef _LINUX_RBTREE_H -+#define _LINUX_RBTREE_H -+ -+#include <linux/kernel.h> -+#include <linux/stddef.h> -+ -+typedef struct rb_node_s -+{ -+ struct rb_node_s * rb_parent; -+ int rb_color; -+#define RB_RED 0 -+#define RB_BLACK 1 -+ struct rb_node_s * rb_right; -+ struct rb_node_s * rb_left; -+} -+rb_node_t; -+ -+typedef struct rb_root_s -+{ -+ struct rb_node_s * rb_node; -+} -+rb_root_t; -+ -+#define RB_ROOT (rb_root_t) { NULL, } -+#define rb_entry(ptr, type, member) \ -+ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) -+ -+extern void rb_insert_color(rb_node_t *, rb_root_t *); -+extern void rb_erase(rb_node_t *, rb_root_t *); -+ -+static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link) -+{ -+ node->rb_parent = parent; -+ node->rb_color = RB_RED; -+ node->rb_left = node->rb_right = NULL; -+ -+ *rb_link = node; -+} -+ -+#endif /* _LINUX_RBTREE_H */ -diff -Nurb linux-mips-2.4.27/include/linux/rbtree.h linux/include/linux/rbtree.h ---- linux-mips-2.4.27/include/linux/rbtree.h 2001-10-19 03:25:03.000000000 +0200 -+++ linux/include/linux/rbtree.h 2004-11-19 10:25:12.148161944 +0100 -@@ -1,133 +1,25 @@ - /* -- Red Black Trees -- (C) 1999 Andrea Arcangeli <andrea@suse.de> -+ * 2.5 compatibility -+ * $Id$ -+ */ -+ -+#ifndef __MTD_COMPAT_RBTREE_H__ -+#define __MTD_COMPAT_RBTREE_H__ -+ -+#include <linux/version.h> -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,40) -+#include_next <linux/rbtree.h> -+#else -+#define rb_node_s rb_node -+#define rb_root_s rb_root -+ -+#include <linux/rbtree-24.h> -+ -+/* Find logical next and previous nodes in a tree */ -+extern struct rb_node *rb_next(struct rb_node *); -+extern struct rb_node *rb_prev(struct rb_node *); -+extern struct rb_node *rb_first(struct rb_root *); -+#endif - -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- -- linux/include/linux/rbtree.h -- -- To use rbtrees you'll have to implement your own insert and search cores. -- This will avoid us to use callbacks and to drop drammatically performances. -- I know it's not the cleaner way, but in C (not in C++) to get -- performances and genericity... -- -- Some example of insert and search follows here. The search is a plain -- normal search over an ordered tree. The insert instead must be implemented -- int two steps: as first thing the code must insert the element in -- order as a red leaf in the tree, then the support library function -- rb_insert_color() must be called. Such function will do the -- not trivial work to rebalance the rbtree if necessary. -- ------------------------------------------------------------------------- --static inline struct page * rb_search_page_cache(struct inode * inode, -- unsigned long offset) --{ -- rb_node_t * n = inode->i_rb_page_cache.rb_node; -- struct page * page; -- -- while (n) -- { -- page = rb_entry(n, struct page, rb_page_cache); -- -- if (offset < page->offset) -- n = n->rb_left; -- else if (offset > page->offset) -- n = n->rb_right; -- else -- return page; -- } -- return NULL; --} -- --static inline struct page * __rb_insert_page_cache(struct inode * inode, -- unsigned long offset, -- rb_node_t * node) --{ -- rb_node_t ** p = &inode->i_rb_page_cache.rb_node; -- rb_node_t * parent = NULL; -- struct page * page; -- -- while (*p) -- { -- parent = *p; -- page = rb_entry(parent, struct page, rb_page_cache); -- -- if (offset < page->offset) -- p = &(*p)->rb_left; -- else if (offset > page->offset) -- p = &(*p)->rb_right; -- else -- return page; -- } -- -- rb_link_node(node, parent, p); -- -- return NULL; --} -- --static inline struct page * rb_insert_page_cache(struct inode * inode, -- unsigned long offset, -- rb_node_t * node) --{ -- struct page * ret; -- if ((ret = __rb_insert_page_cache(inode, offset, node))) -- goto out; -- rb_insert_color(node, &inode->i_rb_page_cache); -- out: -- return ret; --} ------------------------------------------------------------------------- --*/ -- --#ifndef _LINUX_RBTREE_H --#define _LINUX_RBTREE_H -- --#include <linux/kernel.h> --#include <linux/stddef.h> -- --typedef struct rb_node_s --{ -- struct rb_node_s * rb_parent; -- int rb_color; --#define RB_RED 0 --#define RB_BLACK 1 -- struct rb_node_s * rb_right; -- struct rb_node_s * rb_left; --} --rb_node_t; -- --typedef struct rb_root_s --{ -- struct rb_node_s * rb_node; --} --rb_root_t; -- --#define RB_ROOT (rb_root_t) { NULL, } --#define rb_entry(ptr, type, member) \ -- ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) -- --extern void rb_insert_color(rb_node_t *, rb_root_t *); --extern void rb_erase(rb_node_t *, rb_root_t *); -- --static inline void rb_link_node(rb_node_t * node, rb_node_t * parent, rb_node_t ** rb_link) --{ -- node->rb_parent = parent; -- node->rb_color = RB_RED; -- node->rb_left = node->rb_right = NULL; -- -- *rb_link = node; --} -- --#endif /* _LINUX_RBTREE_H */ -+#endif /* __MTD_COMPAT_RBTREE_H__ */ -diff -Nurb linux-mips-2.4.27/include/linux/suspend.h linux/include/linux/suspend.h ---- linux-mips-2.4.27/include/linux/suspend.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/include/linux/suspend.h 2004-11-19 10:25:12.150161640 +0100 -@@ -0,0 +1,10 @@ -+/* $Id$ */ -+ -+#ifndef __MTD_COMPAT_VERSION_H__ -+#include <linux/version.h> -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -+#include_next <linux/suspend.h> -+#endif -+ -+#endif /* __MTD_COMPAT_VERSION_H__ */ -diff -Nurb linux-mips-2.4.27/include/linux/workqueue.h linux/include/linux/workqueue.h ---- linux-mips-2.4.27/include/linux/workqueue.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux/include/linux/workqueue.h 2004-11-19 10:25:12.152161336 +0100 -@@ -0,0 +1,21 @@ -+/* -+ * 2.5 compatibility -+ * $Id$ -+ */ -+ -+#ifndef __MTD_COMPAT_WORKQUEUE_H__ -+#define __MTD_COMPAT_WORKQUEUE_H__ -+ -+#include <linux/version.h> -+ -+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,40) -+#include_next <linux/workqueue.h> -+#else -+#include <linux/tqueue.h> -+#define work_struct tq_struct -+#define schedule_work(x) schedule_task(x) -+#define flush_scheduled_work flush_scheduled_tasks -+#define INIT_WORK(x,y,z) INIT_TQUEUE(x,y,z) -+#endif -+ -+#endif /* __MTD_COMPAT_WORKQUEUE_H__ */ |