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: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $ +# $Id: Config.in,v 1.75 2003/05/23 11:38:29 dwmw2 Exp $ 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: Makefile,v 1.65 2002/03/22 07:10:34 dwmw2 Exp $ - - -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: Makefile.common,v 1.2 2003/05/23 11:38:29 dwmw2 Exp $ # *** 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: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $ + $Id: afs.c,v 1.12 2003/06/13 15:31:06 rmk Exp $ ======================================================================*/ @@ -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: Config.in,v 1.16 2002/09/03 13:30:43 joern Exp $ +# $Id: Config.in,v 1.17 2003/09/25 14:40:34 thayne Exp $ 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: Makefile,v 1.8 2002/01/10 20:27:40 eric Exp $ +# $Id: Makefile.common,v 1.3 2003/09/25 14:40:34 thayne Exp $ +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 * - * $Id: amd_flash.c,v 1.19 2003/01/24 13:30:11 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.23 2003/06/12 09:24:13 dwmw2 Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -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: cfi_cmdset_0001.c,v 1.114 2003/03/18 12:28:40 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.132 2003/11/04 19:34:22 thayne Exp $ * * * 10/10/2000 Nicolas Pitre @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -29,10 +30,14 @@ #include #include #include -#include +#include #include +#include + +/* #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; iMajorVersion != '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)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 && inumchips; 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