From 28a48de72b876af794853593cc1412119ada9efc Mon Sep 17 00:00:00 2001 From: "David A. Marlin" Date: Mon, 17 Jan 2005 18:29:21 +0000 Subject: [MTD] NAND extended commands, badb block table autorefresh Added extended commands for AG-AND device and added option for BBT_AUTO_REFRESH. Signed-off-by: David A. Marlin Signed-off-by: Thomas Gleixner --- include/linux/mtd/nand.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 9a19c65abd74..0118128ae384 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -5,7 +5,7 @@ * Steven J. Hill * Thomas Gleixner * - * $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $ + * $Id: nand.h,v 1.69 2005/01/17 18:29:18 dmarlin Exp $ * * 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 @@ -48,6 +48,8 @@ * 02-08-2004 tglx added option field to nand structure for chip anomalities * 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id * update of nand_chip structure description + * 01-17-2005 dmarlin added extended commands for AG-AND device and added option + * for BBT_AUTO_REFRESH. */ #ifndef __LINUX_MTD_NAND_H #define __LINUX_MTD_NAND_H @@ -115,6 +117,25 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ #define NAND_CMD_READSTART 0x30 #define NAND_CMD_CACHEDPROG 0x15 +/* Extended commands for AG-AND device */ +/* + * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but + * there is no way to distinguish that from NAND_CMD_READ0 + * until the remaining sequence of commands has been completed + * so add a high order bit and mask it off in the command. + */ +#define NAND_CMD_DEPLETE1 0x100 +#define NAND_CMD_DEPLETE2 0x38 +#define NAND_CMD_STATUS_MULTI 0x71 +#define NAND_CMD_STATUS_ERROR 0x72 +/* multi-bank error status (banks 0-3) */ +#define NAND_CMD_STATUS_ERROR0 0x73 +#define NAND_CMD_STATUS_ERROR1 0x74 +#define NAND_CMD_STATUS_ERROR2 0x75 +#define NAND_CMD_STATUS_ERROR3 0x76 +#define NAND_CMD_STATUS_RESET 0x7f +#define NAND_CMD_STATUS_CLEAR 0xff + /* Status bits */ #define NAND_STATUS_FAIL 0x01 #define NAND_STATUS_FAIL_N1 0x02 @@ -170,6 +191,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ /* Chip has a array of 4 pages which can be read without * additional ready /busy waits */ #define NAND_4PAGE_ARRAY 0x00000040 +/* Chip requires that BBT is periodically rewritten to prevent + * bits from adjacent blocks from 'leaking' in altering data. + * This happens with the Renesas AG-AND chips, possibly others. */ +#define BBT_AUTO_REFRESH 0x00000080 /* Options valid for Samsung large page devices */ #define NAND_SAMSUNG_LP_OPTIONS \ -- cgit v1.2.3 From 99f2a8aea18c9779c141050c6f95a8f1da63bbe4 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 24 Jan 2005 00:37:04 +0000 Subject: [MTD] Platform RAM Driver Driver for generic RAM blocks which are exported by an platform_device from the device driver system. Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- drivers/mtd/maps/Kconfig | 12 +- drivers/mtd/maps/Makefile | 3 +- drivers/mtd/maps/plat-ram.c | 286 +++++++++++++++++++++++++++++++++++++++++++ include/linux/mtd/plat-ram.h | 35 ++++++ 4 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 drivers/mtd/maps/plat-ram.c create mode 100644 include/linux/mtd/plat-ram.h (limited to 'include/linux') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index 8480057eadb4..7d21d432f380 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/maps/Kconfig -# $Id: Kconfig,v 1.42 2005/01/05 16:59:50 dwmw2 Exp $ +# $Id: Kconfig,v 1.43 2005/01/24 00:35:21 bjd Exp $ menu "Mapping drivers for chip access" depends on MTD!=n @@ -659,5 +659,15 @@ config MTD_SHARP_SL help This enables access to the flash chip on the Sharp SL Series of PDAs. +config MTD_PLATRAM + tristate "Map driver for platfrom device RAM (mtd-ram)" + depends on MTD + select MTD_RAM + help + Map driver for RAM areas described via the platform device + system. + + This selection automatically selects the map_ram driver. + endmenu diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile index 7ffe02b85301..d2e6dcc87059 100644 --- a/drivers/mtd/maps/Makefile +++ b/drivers/mtd/maps/Makefile @@ -1,7 +1,7 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile.common,v 1.23 2005/01/05 17:06:36 dwmw2 Exp $ +# $Id: Makefile.common,v 1.24 2005/01/24 00:35:21 bjd Exp $ ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) obj-$(CONFIG_MTD) += map_funcs.o @@ -71,3 +71,4 @@ obj-$(CONFIG_MTD_IXP2000) += ixp2000.o obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o obj-$(CONFIG_MTD_DMV182) += dmv182.o obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o +obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c new file mode 100644 index 000000000000..808f94346add --- /dev/null +++ b/drivers/mtd/maps/plat-ram.c @@ -0,0 +1,286 @@ +/* drivers/mtd/maps/plat-ram.c + * + * (c) 2004-2005 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks + * + * Generic platfrom device based RAM map + * + * $Id: plat-ram.c,v 1.1 2005/01/24 00:37:02 bjd Exp $ + * + * 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 +*/ + +#define DEBUG + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +/* private structure for each mtd platform ram device created */ + +struct platram_info { + struct device *dev; + struct mtd_info *mtd; + struct map_info map; + struct mtd_partition *partitions; + struct resource *area; + struct platdata_mtd_ram *pdata; +}; + +/* to_platram_info() + * + * device private data to struct platram_info conversion +*/ + +static inline struct platram_info *to_platram_info(struct device *dev) +{ + return (struct platram_info *)dev_get_drvdata(dev); +} + +/* platram_setrw + * + * call the platform device's set rw/ro control + * + * to = 0 => read-only + * = 1 => read-write +*/ + +static inline void platram_setrw(struct platram_info *info, int to) +{ + if (info->pdata == NULL) + return; + + if (info->pdata->set_rw != NULL) + (info->pdata->set_rw)(info->dev, to); +} + +/* platram_remove + * + * called to remove the device from the driver's control +*/ + +static int platram_remove(struct device *dev) +{ + struct platram_info *info = to_platram_info(dev); + + dev_set_drvdata(dev, NULL); + + dev_dbg(dev, "removing device\n"); + + if (info == NULL) + return 0; + + if (info->mtd) { +#ifdef CONFIG_MTD_PARTITIONS + if (info->partitions) { + del_mtd_partitions(info->mtd); + kfree(info->partitions); + } +#endif + del_mtd_device(info->mtd); + map_destroy(info->mtd); + } + + /* ensure ram is left read-only */ + + platram_setrw(info, PLATRAM_RO); + + /* release resources */ + + if (info->area) { + release_resource(info->area); + kfree(info->area); + } + + if (info->map.virt != NULL) + iounmap(info->map.virt); + + kfree(info); + + return 0; +} + +/* platram_probe + * + * called from device drive system when a device matching our + * driver is found. +*/ + +static int platram_probe(struct device *dev) +{ + struct platform_device *pd = to_platform_device(dev); + struct platdata_mtd_ram *pdata; + struct platram_info *info; + struct resource *res; + int err = 0; + + dev_dbg(dev, "probe entered\n"); + + if (dev->platform_data == NULL) { + dev_err(dev, "no platform data supplied\n"); + err = -ENOENT; + goto exit_error; + } + + pdata = dev->platform_data; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (info == NULL) { + dev_err(dev, "no memory for flash info\n"); + err = -ENOMEM; + goto exit_error; + } + + memzero(info, sizeof(*info)); + dev_set_drvdata(dev, info); + + info->dev = dev; + info->pdata = pdata; + + /* get the resource for the memory mapping */ + + res = platform_get_resource(pd, IORESOURCE_MEM, 0); + + if (res == NULL) { + dev_err(dev, "no memory resource specified\n"); + err = -ENOENT; + goto exit_free; + } + + dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start); + + /* setup map parameters */ + + info->map.phys = res->start; + info->map.size = (res->end - res->start) + 1; + info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name; + info->map.bankwidth = pdata->bankwidth; + + /* register our usage of the memory area */ + + info->area = request_mem_region(res->start, info->map.size, pd->name); + if (info->area == NULL) { + dev_err(dev, "failed to request memory region\n"); + err = -EIO; + goto exit_free; + } + + /* remap the memory area */ + + info->map.virt = ioremap(res->start, info->map.size); + dev_dbg(dev, "virt %p, %d bytes\n", info->map.virt, info->map.size); + + if (info->map.virt == NULL) { + dev_err(dev, "failed to ioremap() region\n"); + err = -EIO; + goto exit_free; + } + + { + unsigned int *p = (unsigned int *)info->map.virt; + printk("%08x %08x %08x %08x\n", + readl(p), readl(p+1), readl(p+2), readl(p+3)); + } + + simple_map_init(&info->map); + + dev_dbg(dev, "initialised map, probing for mtd\n"); + + /* probe for the right mtd map driver */ + + info->mtd = do_map_probe("map_ram" , &info->map); + if (info->mtd == NULL) { + dev_err(dev, "failed to probe for map_ram\n"); + err = -ENOMEM; + goto exit_free; + } + + info->mtd->owner = THIS_MODULE; + + platram_setrw(info, PLATRAM_RW); + + /* check to see if there are any available partitions, or wether + * to add this device whole */ + +#ifdef CONFIG_MTD_PARTITIONS + if (pdata->nr_partitions > 0) { + const char **probes = { NULL }; + + if (pdata->probes) + probes = (const char **)pdata->probes; + + err = parse_mtd_partitions(info->mtd, probes, + &info->partitions, 0); + if (err > 0) { + err = add_mtd_partitions(info->mtd, info->partitions, + err); + } + } +#endif /* CONFIG_MTD_PARTITIONS */ + + if (add_mtd_device(info->mtd)) { + dev_err(dev, "add_mtd_device() failed\n"); + err = -ENOMEM; + } + + dev_info(dev, "registered mtd device\n"); + return err; + + exit_free: + platram_remove(dev); + exit_error: + return err; +} + +/* device driver info */ + +static struct device_driver platram_driver = { + .name = "mtd-ram", + .bus = &platform_bus_type, + .probe = platram_probe, + .remove = platram_remove, +}; + +/* module init/exit */ + +static int __init platram_init(void) +{ + printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n"); + return driver_register(&platram_driver); +} + +static void __exit platram_exit(void) +{ + driver_unregister(&platram_driver); +} + +module_init(platram_init); +module_exit(platram_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Ben Dooks "); +MODULE_DESCRIPTION("MTD platform RAM map driver"); diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h new file mode 100644 index 000000000000..2332eda07e0e --- /dev/null +++ b/include/linux/mtd/plat-ram.h @@ -0,0 +1,35 @@ +/* linux/include/mtd/plat-ram.h + * + * (c) 2004 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * Ben Dooks + * + * Generic platform device based RAM map + * + * $Id: plat-ram.h,v 1.2 2005/01/24 00:37:40 bjd Exp $ + * + * 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. + * + */ + +#ifndef __LINUX_MTD_PLATRAM_H +#define __LINUX_MTD_PLATRAM_H __FILE__ + +#define PLATRAM_RO (0) +#define PLATRAM_RW (1) + +struct platdata_mtd_ram { + char *mapname; + char **probes; + struct mtd_partition *partitions; + int nr_partitions; + int bankwidth; + + /* control callbacks */ + + void (*set_rw)(struct device *dev, int to); +}; + +#endif /* __LINUX_MTD_PLATRAM_H */ -- cgit v1.2.3 From 068e3c0a002c79a5e3cc7c42cb749c4bb126288c Mon Sep 17 00:00:00 2001 From: "David A. Marlin" Date: Mon, 24 Jan 2005 03:07:46 +0000 Subject: [MTD] NAND Add optional ECC status check callback Add optional hardware specific callback routine to perform extra error status checks on erase and write failures for devices with hardware ECC. Signed-off-by: David A. Marlin Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 65 ++++++++++++++++++++++++++++++++++++-------- include/linux/mtd/nand.h | 16 +++++++++-- 2 files changed, 68 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 9f7c42ceecfa..7094dd5716dc 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -42,6 +42,10 @@ * a "device recovery" operation must be performed when power is restored * to ensure correct operation. * + * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to + * perform extra error status checks on erase and write failures. This required + * adding a wrapper function for nand_read_ecc. + * * Credits: * David Woodhouse for adding multichip support * @@ -55,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.129 2005/01/23 18:30:50 dmarlin Exp $ + * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $ * * 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 @@ -896,6 +900,12 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa if (!cached) { /* call wait ready function */ status = this->waitfunc (mtd, this, FL_WRITING); + + /* See if operation failed and additional status checks are available */ + if ((status & NAND_STATUS_FAIL) && (this->errstat)) { + status = this->errstat(mtd, this, FL_WRITING, status, page); + } + /* See if device thinks it succeeded */ if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); @@ -1022,23 +1032,24 @@ out: #endif /** - * nand_read - [MTD Interface] MTD compability function for nand_read_ecc + * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read * @retlen: pointer to variable to store the number of read bytes * @buf: the databuffer to put data * - * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL -*/ + * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL + * and flags = 0xff + */ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { - return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); + return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff); } /** - * nand_read_ecc - [MTD Interface] Read data with ECC + * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd: MTD device structure * @from: offset to read from * @len: number of bytes to read @@ -1047,10 +1058,34 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re * @oob_buf: filesystem supplied oob data buffer * @oobsel: oob selection structure * - * NAND read with ECC + * This function simply calls nand_do_read_ecc with flags = 0xff */ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) +{ + return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff); +} + + +/** + * nand_do_read_ecc - [MTD Interface] Read data with ECC + * @mtd: MTD device structure + * @from: offset to read from + * @len: number of bytes to read + * @retlen: pointer to variable to store the number of read bytes + * @buf: the databuffer to put data + * @oob_buf: filesystem supplied oob data buffer + * @oobsel: oob selection structure + * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed + * and how many corrected error bits are acceptable: + * bits 0..7 - number of tolerable errors + * bit 8 - 0 == do not get/release chip, 1 == get/release chip + * + * NAND read with ECC + */ +int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags) { int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; @@ -1076,7 +1111,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Grab the lock and see if the device is available */ - nand_get_device (this, mtd, FL_READING); + if (flags & NAND_GET_DEVICE) + nand_get_device (this, mtd, FL_READING); /* use userspace supplied oobinfo, if zero */ if (oobsel == NULL) @@ -1180,7 +1216,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, /* We calc error correction directly, it checks the hw * generator for an error, reads back the syndrome and * does the error correction on the fly */ - if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { + ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); + if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); ecc_failed++; @@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, p[i] = ecc_status; } - if (ecc_status == -1) { + if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); ecc_failed++; } @@ -1289,7 +1326,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, } /* Deselect and wake up anyone waiting on the device */ - nand_release_device(mtd); + if (flags & NAND_GET_DEVICE) + nand_release_device(mtd); /* * Return success, if no ECC failures, else -EBADMSG @@ -2103,6 +2141,11 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb status = this->waitfunc (mtd, this, FL_ERASING); + /* See if operation failed and additional status checks are available */ + if ((status & NAND_STATUS_FAIL) && (this->errstat)) { + status = this->errstat(mtd, this, FL_ERASING, status, page); + } + /* See if block erase succeeded */ if (status & NAND_STATUS_FAIL) { DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 0118128ae384..cf52f20c6de2 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -5,7 +5,7 @@ * Steven J. Hill * Thomas Gleixner * - * $Id: nand.h,v 1.69 2005/01/17 18:29:18 dmarlin Exp $ + * $Id: nand.h,v 1.70 2005/01/24 03:07:42 dmarlin Exp $ * * 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 @@ -50,6 +50,8 @@ * update of nand_chip structure description * 01-17-2005 dmarlin added extended commands for AG-AND device and added option * for BBT_AUTO_REFRESH. + * 01-20-2005 dmarlin added optional pointer to hardware specific callback for + * extra error status checks. */ #ifndef __LINUX_MTD_NAND_H #define __LINUX_MTD_NAND_H @@ -164,7 +166,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ /* * Constants for Hardware ECC -*/ + */ /* Reset Hardware ECC for read */ #define NAND_ECC_READ 0 /* Reset Hardware ECC for write */ @@ -172,6 +174,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ /* Enable Hardware ECC before syndrom is read back from flash */ #define NAND_ECC_READSYN 2 +/* Bit mask for flags passed to do_nand_read_ecc */ +#define NAND_GET_DEVICE 0x80 + + /* Option constants for bizarre disfunctionality and real * features */ @@ -308,6 +314,8 @@ struct nand_hw_control { * @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan * @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices * @priv: [OPTIONAL] pointer to private chip date + * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks + * (determine if errors are correctable) */ struct nand_chip { @@ -363,6 +371,7 @@ struct nand_chip { struct nand_bbt_descr *badblock_pattern; struct nand_hw_control *controller; void *priv; + int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); }; /* @@ -484,6 +493,9 @@ extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs); extern int nand_default_bbt (struct mtd_info *mtd); extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt); extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt); +extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t * retlen, u_char * buf, u_char * oob_buf, + struct nand_oobinfo *oobsel, int flags); /* * Constants for oob configuration -- cgit v1.2.3 From 72b56a2d7dccd9ea90f34f6ddb653086a3f3bd2e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Sat, 5 Feb 2005 02:06:19 +0000 Subject: [MTD] Add OTP basisc add structure definition for OTP region info Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 8 +++++--- include/linux/mtd/cfi.h | 10 +++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c268bcd71720..c630d7532f7a 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.164 2004/11/16 18:29:00 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.165 2005/02/05 02:06:15 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -252,7 +252,8 @@ read_pri_intelext(struct map_info *map, __u16 adr) int nb_parts, i; /* Protection Register info */ - extra_size += (extp->NumProtectionFields - 1) * (4 + 6); + extra_size += (extp->NumProtectionFields - 1) * + sizeof(struct cfi_intelext_otpinfo); /* Burst Read info */ extra_size += 6; @@ -471,7 +472,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, int offs, numregions, numparts, partshift, numvirtchips, i, j; /* Protection Register info */ - offs = (extp->NumProtectionFields - 1) * (4 + 6); + offs = (extp->NumProtectionFields - 1) * + sizeof(struct cfi_intelext_otpinfo); /* Burst Read info */ offs += 6; diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 2ed8c585021e..d87dc3fbd4ba 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -1,7 +1,7 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.50 2004/11/20 12:46:51 dwmw2 Exp $ + * $Id: cfi.h,v 1.51 2005/02/05 02:06:16 nico Exp $ */ #ifndef __MTD_CFI_H__ @@ -148,6 +148,14 @@ struct cfi_pri_intelext { uint8_t extra[0]; } __attribute__((packed)); +struct cfi_intelext_otpinfo { + uint32_t ProtRegAddr; + uint16_t FactGroups; + uint8_t FactProtRegSize; + uint16_t UserGroups; + uint8_t UserProtRegSize; +} __attribute__((packed)); + struct cfi_intelext_blockinfo { uint16_t NumIdentBlocks; uint16_t BlockSize; -- cgit v1.2.3 From f77814dd5728edaf1239d19755d2aa0d8c33d861 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 8 Feb 2005 17:11:19 +0000 Subject: [MTD] Support for protection register support on Intel FLASH chips This enables support for reading, writing and locking so called "Protection Registers" present on some flash chips. A subset of them are pre-programmed at the factory with a unique set of values. The rest is user-programmable. Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/Kconfig | 27 ++- drivers/mtd/chips/cfi_cmdset_0001.c | 401 +++++++++++++++++++++++++----------- drivers/mtd/mtdpart.c | 28 ++- include/linux/mtd/cfi.h | 4 +- include/linux/mtd/flashchip.h | 3 +- include/linux/mtd/map.h | 15 +- include/linux/mtd/mtd.h | 10 +- include/mtd/mtd-abi.h | 8 +- 8 files changed, 369 insertions(+), 127 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index d682dbc8157e..f4eda1e40d51 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/chips/Kconfig -# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $ +# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $ menu "RAM/ROM/Flash chip drivers" depends on MTD!=n @@ -155,6 +155,31 @@ config MTD_CFI_I8 If your flash chips are interleaved in eights - i.e. you have eight flash chips addressed by each bus cycle, then say 'Y'. +config MTD_OTP + bool "Protection Registers aka one-time programmable (OTP) bits" + depends on MTD_CFI_ADV_OPTIONS + default n + help + This enables support for reading, writing and locking so called + "Protection Registers" present on some flash chips. + A subset of them are pre-programmed at the factory with a + unique set of values. The rest is user-programmable. + + The user-programmable Protection Registers contain one-time + programmable (OTP) bits; when programmed, register bits cannot be + erased. Each Protection Register can be accessed multiple times to + program individual bits, as long as the register remains unlocked. + + Each Protection Register has an associated Lock Register bit. When a + Lock Register bit is programmed, the associated Protection Register + can only be read; it can no longer be programmed. Additionally, + because the Lock Register bits themselves are OTP, when programmed, + Lock Register bits cannot be erased. Therefore, when a Protection + Register is locked, it cannot be unlocked. + + This feature should therefore be used with extreme care. Any mistake + in the programming of OTP bits will waste them. + config MTD_CFI_INTELEXT tristate "Support for Intel/Sharp flash chips" depends on MTD_GEN_PROBE diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index c630d7532f7a..b3f5acf0760c 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.165 2005/02/05 02:06:15 nico Exp $ + * $Id: cfi_cmdset_0001.c,v 1.167 2005/02/08 17:11:15 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -48,14 +48,20 @@ #define M50LPW080 0x002F 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 *); -//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_intelext_sync (struct mtd_info *); static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_intelext_read_fact_prot_reg (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 *); +static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t); +static int cfi_intelext_get_fact_prot_info (struct mtd_info *, + struct otp_info *, size_t); +static int cfi_intelext_get_user_prot_info (struct mtd_info *, + struct otp_info *, size_t); static int cfi_intelext_suspend (struct mtd_info *); static void cfi_intelext_resume (struct mtd_info *); @@ -423,9 +429,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) mtd->eraseregions[i].numblocks); } -#if 0 - mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; +#ifdef CONFIG_MTD_OTP mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg; + mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; + mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg; + mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg; + mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info; + mtd->get_user_prot_info = cfi_intelext_get_user_prot_info; #endif /* This function has the potential to distort the reality @@ -565,7 +575,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr resettime: timeo = jiffies + HZ; retry: - if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) { + if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) { /* * OK. We have possibility for contension on the write/erase * operations which are global to the real chip and not per @@ -1178,111 +1188,11 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz return ret; } -#if 0 -static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd, - loff_t from, size_t len, - size_t *retlen, - u_char *buf, - int base_offst, int reg_sz) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp = cfi->cmdset_priv; - struct flchip *chip; - int ofs_factor = cfi->interleave * cfi->device_type; - int count = len; - int chip_num, offst; - int ret; - - chip_num = ((unsigned int)from/reg_sz); - offst = from - (reg_sz*chip_num)+base_offst; - - while (count) { - /* Calculate which chip & protection register offset we need */ - - if (chip_num >= cfi->numchips) - goto out; - - chip = &cfi->chips[chip_num]; - - spin_lock(chip->mutex); - ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); - if (ret) { - spin_unlock(chip->mutex); - return (len-count)?:ret; - } - - xip_disable(map, chip, chip->start); - - if (chip->state != FL_JEDEC_QUERY) { - map_write(map, CMD(0x90), chip->start); - chip->state = FL_JEDEC_QUERY; - } - - while (count && ((offst-base_offst) < reg_sz)) { - *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); - buf++; - offst++; - count--; - } - - xip_enable(map, chip, chip->start); - put_chip(map, chip, chip->start); - spin_unlock(chip->mutex); - - /* Move on to the next chip */ - chip_num++; - offst = base_offst; - } - - out: - return len-count; -} - -static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp=cfi->cmdset_priv; - int base_offst,reg_sz; - - /* Check that we actually have some protection registers */ - if(!extp || !(extp->FeatureSupport&64)){ - printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); - return 0; - } - - base_offst=(1<FactProtRegSize); - reg_sz=(1<UserProtRegSize); - - return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz); -} - -static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - struct cfi_pri_intelext *extp=cfi->cmdset_priv; - int base_offst,reg_sz; - - /* Check that we actually have some protection registers */ - if(!extp || !(extp->FeatureSupport&64)){ - printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); - return 0; - } - - base_offst=0; - reg_sz=(1<FactProtRegSize); - - return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz); -} -#endif - static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, - unsigned long adr, map_word datum) + unsigned long adr, map_word datum, int mode) { struct cfi_private *cfi = map->fldrv_priv; - map_word status, status_OK; + map_word status, status_OK, write_cmd; unsigned long timeo; int z, ret=0; @@ -1290,9 +1200,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); + switch (mode) { + case FL_WRITING: write_cmd = CMD(0x40); break; + case FL_OTP_WRITE: write_cmd = CMD(0xc0); break; + default: return -EINVAL; + } spin_lock(chip->mutex); - ret = get_chip(map, chip, adr, FL_WRITING); + ret = get_chip(map, chip, adr, mode); if (ret) { spin_unlock(chip->mutex); return ret; @@ -1301,9 +1216,9 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); ENABLE_VPP(map); xip_disable(map, chip, adr); - map_write(map, CMD(0x40), adr); + map_write(map, write_cmd, adr); map_write(map, datum, adr); - chip->state = FL_WRITING; + chip->state = mode; spin_unlock(chip->mutex); INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map)); @@ -1313,7 +1228,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, timeo = jiffies + (HZ/2); z = 0; for (;;) { - if (chip->state != FL_WRITING) { + if (chip->state != mode) { /* Someone's suspended the write. Sleep */ DECLARE_WAITQUEUE(wait, current); @@ -1401,7 +1316,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le datum = map_word_load_partial(map, datum, buf, gap, n); ret = do_write_oneword(map, &cfi->chips[chipnum], - bus_ofs, datum); + bus_ofs, datum, FL_WRITING); if (ret) return ret; @@ -1422,7 +1337,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le map_word datum = map_word_load(map, buf); ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum); + ofs, datum, FL_WRITING); if (ret) return ret; @@ -1446,7 +1361,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le datum = map_word_load_partial(map, datum, buf, 0, len); ret = do_write_oneword(map, &cfi->chips[chipnum], - ofs, datum); + ofs, datum, FL_WRITING); if (ret) return ret; @@ -2036,6 +1951,262 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) return ret; } +#ifdef CONFIG_MTD_OTP + +typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip, + u_long data_offset, u_char *buf, u_int size, + u_long prot_offset, u_int groupno, u_int groupsize); + +static int __xipram +do_otp_read(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + struct cfi_private *cfi = map->fldrv_priv; + int ret; + + spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + /* let's ensure we're not reading back cached data from array mode */ + if (map->inval_cache) + map->inval_cache(map, chip->start + offset, size); + + xip_disable(map, chip, chip->start); + if (chip->state != FL_JEDEC_QUERY) { + map_write(map, CMD(0x90), chip->start); + chip->state = FL_JEDEC_QUERY; + } + map_copy_from(map, buf, chip->start + offset, size); + xip_enable(map, chip, chip->start); + + /* then ensure we don't keep OTP data in the cache */ + if (map->inval_cache) + map->inval_cache(map, chip->start + offset, size); + + put_chip(map, chip, chip->start); + spin_unlock(chip->mutex); + return 0; +} + +static int +do_otp_write(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + int ret; + + while (size) { + unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1); + int gap = offset - bus_ofs; + int n = min_t(int, size, map_bankwidth(map)-gap); + map_word datum = map_word_ff(map); + + datum = map_word_load_partial(map, datum, buf, gap, n); + ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE); + if (ret) + return ret; + + offset += n; + buf += n; + size -= n; + } + + return 0; +} + +static int +do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset, + u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz) +{ + struct cfi_private *cfi = map->fldrv_priv; + map_word datum; + + /* make sure area matches group boundaries */ + if (offset != 0 || size != grpsz) + return -EXDEV; + + datum = map_word_ff(map); + datum = map_word_clr(map, datum, CMD(1 << grpno)); + return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE); +} + +static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, + otp_op_t action, int user_regs) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + struct cfi_pri_intelext *extp = cfi->cmdset_priv; + struct flchip *chip; + struct cfi_intelext_otpinfo *otp; + u_long devsize, reg_prot_offset, data_offset; + u_int chip_num, chip_step, field, reg_fact_size, reg_user_size; + u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups; + int ret; + + *retlen = 0; + + /* Check that we actually have some OTP registers */ + if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields) + return -ENODATA; + + /* we need real chips here not virtual ones */ + devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave; + chip_step = devsize >> cfi->chipshift; + + for (chip_num = 0; chip_num < cfi->numchips; chip_num += chip_step) { + chip = &cfi->chips[chip_num]; + otp = (struct cfi_intelext_otpinfo *)&extp->extra[0]; + + /* first OTP region */ + field = 0; + reg_prot_offset = extp->ProtRegAddr; + reg_fact_groups = 1; + reg_fact_size = 1 << extp->FactProtRegSize; + reg_user_groups = 1; + reg_user_size = 1 << extp->UserProtRegSize; + + while (len > 0) { + /* flash geometry fixup */ + data_offset = reg_prot_offset + 1; + data_offset *= cfi->interleave * cfi->device_type; + reg_prot_offset *= cfi->interleave * cfi->device_type; + reg_fact_size *= cfi->interleave; + reg_user_size *= cfi->interleave; + + if (user_regs) { + groups = reg_user_groups; + groupsize = reg_user_size; + /* skip over factory reg area */ + groupno = reg_fact_groups; + data_offset += reg_fact_groups * reg_fact_size; + } else { + groups = reg_fact_groups; + groupsize = reg_fact_size; + groupno = 0; + } + + while (groups > 0) { + if (!action) { + /* + * Special case: if action is NULL + * we fill buf with otp_info records. + */ + struct otp_info *otpinfo; + map_word lockword; + len -= sizeof(struct otp_info); + if (len <= 0) + return -ENOSPC; + ret = do_otp_read(map, chip, + reg_prot_offset, + (u_char *)&lockword, + map_bankwidth(map), + 0, 0, 0); + if (ret) + return ret; + otpinfo = (struct otp_info *)buf; + otpinfo->start = from; + otpinfo->length = groupsize; + otpinfo->locked = + !map_word_bitsset(map, lockword, + CMD(1 << groupno)); + from += groupsize; + buf += sizeof(*otpinfo); + *retlen += sizeof(*otpinfo); + } else if (from >= groupsize) { + from -= groupsize; + } else { + int size = groupsize; + data_offset += from; + size -= from; + from = 0; + if (size > len) + size = len; + ret = action(map, chip, data_offset, + buf, size, reg_prot_offset, + groupno, groupsize); + if (ret < 0) + return ret; + buf += size; + len -= size; + *retlen += size; + } + groupno++; + groups--; + } + + /* next OTP region */ + if (++field == extp->NumProtectionFields) + break; + reg_prot_offset = otp->ProtRegAddr; + reg_fact_groups = otp->FactGroups; + reg_fact_size = 1 << otp->FactProtRegSize; + reg_user_groups = otp->UserGroups; + reg_user_size = 1 << otp->UserProtRegSize; + otp++; + } + } + + return 0; +} + +static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_read, 0); +} + +static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_read, 1); +} + +static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, + u_char *buf) +{ + return cfi_intelext_otp_walk(mtd, from, len, retlen, + buf, do_otp_write, 1); +} + +static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd, + loff_t from, size_t len) +{ + size_t retlen; + return cfi_intelext_otp_walk(mtd, from, len, &retlen, + NULL, do_otp_lock, 1); +} + +static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + size_t retlen; + int ret; + + ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0); + return ret ? : retlen; +} + +static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + size_t retlen; + int ret; + + ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1); + return ret ? : retlen; +} + +#endif + static int cfi_intelext_suspend(struct mtd_info *mtd) { struct map_info *map = mtd->priv; diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 96ebb52f24b1..b92e6bfffaf2 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $ + * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $ * * 02-21-2002 Thomas Gleixner * added support for read_oob, write_oob @@ -116,6 +116,13 @@ static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t le len, retlen, buf); } +static int part_get_user_prot_info (struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->get_user_prot_info (part->master, buf, len); +} + static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) { @@ -124,6 +131,13 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le len, retlen, buf); } +static int part_get_fact_prot_info (struct mtd_info *mtd, + struct otp_info *buf, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->get_fact_prot_info (part->master, buf, len); +} + static int part_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { @@ -182,6 +196,12 @@ static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t l len, retlen, buf); } +static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len) +{ + struct mtd_part *part = PART(mtd); + return part->master->lock_user_prot_reg (part->master, from, len); +} + static int part_writev (struct mtd_info *mtd, const struct kvec *vecs, unsigned long count, loff_t to, size_t *retlen) { @@ -409,6 +429,12 @@ int add_mtd_partitions(struct mtd_info *master, slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; if(master->write_user_prot_reg) slave->mtd.write_user_prot_reg = part_write_user_prot_reg; + if(master->lock_user_prot_reg) + slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg; + if(master->get_user_prot_info) + slave->mtd.get_user_prot_info = part_get_user_prot_info; + if(master->get_fact_prot_info) + slave->mtd.get_fact_prot_info = part_get_fact_prot_info; if (master->sync) slave->mtd.sync = part_sync; if (!i && master->suspend && master->resume) { diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index d87dc3fbd4ba..76255474a27c 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -1,7 +1,7 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.51 2005/02/05 02:06:16 nico Exp $ + * $Id: cfi.h,v 1.52 2005/02/08 17:11:15 nico Exp $ */ #ifndef __MTD_CFI_H__ @@ -252,7 +252,7 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int * It looks too long to be inline, but in the common case it should almost all * get optimised away. */ -static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi) +static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi) { map_word val = { {0} }; int wordwidth, words_per_bus, chip_mode, chips_per_word; diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h index c66ba812bf90..e778a1ab23c4 100644 --- a/include/linux/mtd/flashchip.h +++ b/include/linux/mtd/flashchip.h @@ -6,7 +6,7 @@ * * (C) 2000 Red Hat. GPLd. * - * $Id: flashchip.h,v 1.15 2004/11/05 22:41:06 nico Exp $ + * $Id: flashchip.h,v 1.16 2005/02/08 17:11:15 nico Exp $ * */ @@ -29,6 +29,7 @@ typedef enum { FL_ERASE_SUSPENDED, FL_WRITING, FL_WRITING_TO_BUFFER, + FL_OTP_WRITE, FL_WRITE_SUSPENDING, FL_WRITE_SUSPENDED, FL_PM_SUSPENDED, diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index f0268b99c900..8fc6679aa9b1 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -1,6 +1,6 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.46 2005/01/05 17:09:44 dwmw2 Exp $ */ +/* $Id: map.h,v 1.47 2005/02/08 17:11:15 nico Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ @@ -263,6 +263,17 @@ static inline map_word map_word_and(struct map_info *map, map_word val1, map_wor return r; } +static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2) +{ + map_word r; + int i; + + for (i=0; i et al. * @@ -113,12 +113,12 @@ struct mtd_info { * flash devices. The user data is one time programmable but the * factory data is read only. */ - int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - + int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); - - /* This function is not yet implemented */ + int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len); + int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len); /* kvec-based read/write methods. We need these especially for NAND flash, with its limited number of write cycles per erase. diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index a76ab898f445..091eb571e993 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -1,5 +1,5 @@ /* - * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $ + * $Id: mtd-abi.h,v 1.8 2005/02/08 17:11:16 nico Exp $ * * Portions of MTD ABI definition which are shared by kernel and user space */ @@ -80,6 +80,12 @@ struct region_info_user { uint32_t regionindex; }; +struct otp_info { + uint32_t start; + uint32_t length; + uint32_t locked; +}; + #define MEMGETINFO _IOR('M', 1, struct mtd_info_user) #define MEMERASE _IOW('M', 2, struct erase_info_user) #define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf) -- cgit v1.2.3 From 8f15fd55f9bf266139b10850947e19c4e3f4e9b7 Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Wed, 9 Feb 2005 09:17:45 +0000 Subject: [JFFS2] Add support for JFFS2-on-Dataflash devices. For Dataflash, can_mark_obsolete = false and the NAND write buffering code (wbuf.c) is used. Since the DataFlash chip will automatically erase pages when writing, the cleanmarkers are not needed - so cleanmarker_oob = false and cleanmarker_size = 0 DataFlash page-sizes are not a power of two (they're multiples of 528 bytes). The SECTOR_ADDR macro (added in the previous core patch) is replaced with a (slower) div/mod version if CONFIG_JFFS2_FS_DATAFLASH is selected. Signed-off-by: Andrew Victor Signed-off-by: Thomas Gleixner --- fs/Kconfig | 7 +++++++ fs/jffs2/Makefile | 3 ++- fs/jffs2/erase.c | 13 ++++++++++--- fs/jffs2/fs.c | 21 ++++++++++++++++++++- fs/jffs2/os-linux.h | 18 ++++++++++++++++-- fs/jffs2/scan.c | 11 +++++++---- fs/jffs2/wbuf.c | 35 ++++++++++++++++++++++++++++++++--- include/linux/jffs2_fs_sb.h | 4 ++-- include/mtd/mtd-abi.h | 3 ++- 9 files changed, 98 insertions(+), 17 deletions(-) (limited to 'include/linux') diff --git a/fs/Kconfig b/fs/Kconfig index 6a4ad4bb7a54..07835d24c785 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1084,6 +1084,13 @@ config JFFS2_FS_NOR_ECC ECC for JFFS2. This type of flash chip is not common, however it is available from ST Microelectronics. +config JFFS2_FS_DATAFLASH + bool "JFFS2 support for DataFlash (EXPERIMENTAL)" + depends on JFFS2_FS && EXPERIMENTAL + default n + help + This enables the experimental support for JFFS2 on DataFlash devices. + config JFFS2_COMPRESSION_OPTIONS bool "Advanced compression options for JFFS2" depends on JFFS2_FS diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index e3c38ccf9c7d..6c2ebe176b40 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -1,7 +1,7 @@ # # Makefile for the Linux Journalling Flash File System v2 (JFFS2) # -# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $ +# $Id: Makefile.common,v 1.8 2005/02/09 09:17:40 pavlov Exp $ # obj-$(CONFIG_JFFS2_FS) += jffs2.o @@ -13,6 +13,7 @@ jffs2-y += super.o jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o +jffs2-$(CONFIG_JFFS2_FS_DATAFLASH) += wbuf.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index ae858f878875..a3c6cc150497 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.70 2005/02/09 09:09:01 pavlov Exp $ + * $Id: erase.c,v 1.71 2005/02/09 09:17:40 pavlov Exp $ * */ @@ -310,7 +310,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb int ret; uint32_t bad_offset; - if (!jffs2_cleanmarker_oob(c)) { + if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) { marker_ref = jffs2_alloc_raw_node_ref(); if (!marker_ref) { printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); @@ -351,7 +351,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb bad_offset += i; printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset); bad: - if (!jffs2_cleanmarker_oob(c)) + if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) jffs2_free_raw_node_ref(marker_ref); kfree(ebuf); bad2: @@ -383,6 +383,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb 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 if (c->cleanmarker_size == 0) { + jeb->first_node = jeb->last_node = NULL; + jeb->free_size = c->sector_size; jeb->used_size = 0; jeb->dirty_size = 0; diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 30ab233fe423..5b7c960a0475 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $ + * $Id: fs.c,v 1.52 2005/02/09 09:17:40 pavlov Exp $ * */ @@ -456,6 +456,12 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) return -EINVAL; } #endif +#ifndef CONFIG_JFFS2_FS_DATAFLASH + if (c->mtd->type == MTD_DATAFLASH) { + printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n"); + return -EINVAL; + } +#endif c->flash_size = c->mtd->size; @@ -661,6 +667,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) { if (ret) return ret; } + + /* and Dataflash */ + if (jffs2_dataflash(c)) { + ret = jffs2_dataflash_setup(c); + if (ret) + return ret; + } + return ret; } @@ -674,4 +688,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) { if (jffs2_nor_ecc(c)) { jffs2_nor_ecc_flash_cleanup(c); } + + /* and DataFlash */ + if (jffs2_dataflash(c)) { + jffs2_dataflash_cleanup(c); + } } diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 0412416d1f2d..af27b84007a1 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.52 2005/02/09 09:09:01 pavlov Exp $ + * $Id: os-linux.h,v 1.53 2005/02/09 09:17:41 pavlov Exp $ * */ @@ -97,12 +97,16 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #endif } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) +#else #define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) +#endif #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) #define jffs2_is_writebuffered(c) (c->wbuf != NULL) -#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC) +#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC && !defined CONFIG_JFFS2_FS_DATAFLASH) #define jffs2_can_mark_obsolete(c) (1) #define jffs2_cleanmarker_oob(c) (0) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) @@ -119,6 +123,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #define jffs2_wbuf_timeout NULL #define jffs2_wbuf_process NULL #define jffs2_nor_ecc(c) (0) +#define jffs2_dataflash(c) (0) #define jffs2_nor_ecc_flash_setup(c) (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) @@ -154,6 +159,15 @@ void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); #define jffs2_nor_ecc_flash_setup(c) (0) #define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) #endif /* NOR ECC */ +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH) +int jffs2_dataflash_setup(struct jffs2_sb_info *c); +void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); +#else +#define jffs2_dataflash(c) (0) +#define jffs2_dataflash_setup(c) (0) +#define jffs2_dataflash_cleanup(c) do {} while (0) +#endif /* DATAFLASH */ #endif /* NAND */ /* erase.c */ diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index 76859ff53437..e8c43746c82e 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.116 2005/02/09 09:09:02 pavlov Exp $ + * $Id: scan.c,v 1.117 2005/02/09 09:17:41 pavlov Exp $ * */ #include @@ -68,7 +68,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo static inline int min_free(struct jffs2_sb_info *c) { uint32_t min = 2 * sizeof(struct jffs2_raw_inode); -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) return c->wbuf_pagesize; #endif @@ -228,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) c->dirty_size -= c->nextblock->dirty_size; c->nextblock->dirty_size = 0; } -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH 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, @@ -351,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo } #endif D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset)); - return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */ + if (c->cleanmarker_size == 0) + return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */ + else + 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, diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 894dea88678d..a35e007e5bf8 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -9,7 +9,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.87 2005/02/09 09:09:02 pavlov Exp $ + * $Id: wbuf.c,v 1.88 2005/02/09 09:17:41 pavlov Exp $ * */ @@ -435,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) if we have a switch to next page, we will not have enough remaining space for this. */ - if (pad) { + if (pad && !jffs2_dataflash(c)) { c->wbuf_len = PAD(c->wbuf_len); /* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR @@ -486,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) spin_lock(&c->erase_completion_lock); /* Adjust free size of the block if we padded. */ - if (pad) { + if (pad && !jffs2_dataflash(c)) { struct jffs2_eraseblock *jeb; jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; @@ -604,8 +604,14 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) return ret; } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) +#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) +#else #define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) #define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) +#endif + int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) { struct kvec outvecs[3]; @@ -1192,6 +1198,29 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) kfree(c->wbuf); } +#ifdef CONFIG_JFFS2_FS_DATAFLASH +int jffs2_dataflash_setup(struct jffs2_sb_info *c) { + c->cleanmarker_size = 0; /* No cleanmarkers needed */ + + /* Initialize write buffer */ + init_rwsem(&c->wbuf_sem); + c->wbuf_pagesize = c->sector_size; + c->wbuf_ofs = 0xFFFFFFFF; + + c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); + if (!c->wbuf) + return -ENOMEM; + + printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize); + + return 0; +} + +void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { + kfree(c->wbuf); +} +#endif + #ifdef CONFIG_JFFS2_FS_NOR_ECC int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { /* Cleanmarker is actually larger on the flashes */ diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h index 4afc8d8c2e9e..faec29559fed 100644 --- a/include/linux/jffs2_fs_sb.h +++ b/include/linux/jffs2_fs_sb.h @@ -1,4 +1,4 @@ -/* $Id: jffs2_fs_sb.h,v 1.48 2004/11/20 10:41:12 dwmw2 Exp $ */ +/* $Id: jffs2_fs_sb.h,v 1.49 2005/02/09 09:17:41 pavlov Exp $ */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB @@ -94,7 +94,7 @@ struct jffs2_sb_info { to an obsoleted node. I don't like this. Alternatives welcomed. */ struct semaphore erase_free_sem; -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC +#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH /* Write-behind buffer for NAND flash */ unsigned char *wbuf; uint32_t wbuf_ofs; diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h index c984cb2c9413..cacb9842b195 100644 --- a/include/mtd/mtd-abi.h +++ b/include/mtd/mtd-abi.h @@ -1,5 +1,5 @@ /* - * $Id: mtd-abi.h,v 1.9 2005/02/08 17:45:52 nico Exp $ + * $Id: mtd-abi.h,v 1.10 2005/02/09 09:17:42 pavlov Exp $ * * Portions of MTD ABI definition which are shared by kernel and user space */ @@ -29,6 +29,7 @@ struct mtd_oob_buf { #define MTD_NORFLASH 3 #define MTD_NANDFLASH 4 #define MTD_PEROM 5 +#define MTD_DATAFLASH 6 #define MTD_OTHER 14 #define MTD_UNKNOWN 15 -- cgit v1.2.3 From 2f82ce1eb637c06dfc60f095cd1891ae0ba4894c Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Wed, 9 Feb 2005 09:24:26 +0000 Subject: [JFFS2] Use a single config option for write buffer support This patch replaces the current CONFIG_JFFS2_FS_NAND, CONFIG_JFFS2_FS_NOR_ECC and CONFIG_JFFS2_FS_DATAFLASH with a single configuration option - CONFIG_JFFS2_FS_WRITEBUFFER. The only functional change of this patch is that the slower div/mod calculations for SECTOR_ADDR(), PAGE_DIV() and PAGE_MOD() are now always used when CONFIG_JFFS2_FS_WRITEBUFFER is enabled. Signed-off-by: Andrew Victor Signed-off-by: Thomas Gleixner --- fs/Kconfig | 33 +++++++++------------------------ fs/jffs2/Makefile | 6 ++---- fs/jffs2/fs.c | 6 ++---- fs/jffs2/nodelist.h | 4 ++-- fs/jffs2/os-linux.h | 28 ++++++++-------------------- fs/jffs2/scan.c | 12 ++++++------ fs/jffs2/super.c | 4 ++-- fs/jffs2/wbuf.c | 8 ++------ include/linux/jffs2_fs_sb.h | 4 ++-- 9 files changed, 35 insertions(+), 70 deletions(-) (limited to 'include/linux') diff --git a/fs/Kconfig b/fs/Kconfig index 07835d24c785..475769c25d64 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1063,33 +1063,18 @@ config JFFS2_FS_DEBUG If reporting bugs, please try to have available a full dump of the messages at debug level 1 while the misbehaviour was occurring. -config JFFS2_FS_NAND - bool "JFFS2 support for NAND flash" +config JFFS2_FS_WRITEBUFFER + bool "JFFS2 write-buffering support" depends on JFFS2_FS - default n + default y help - This enables the support for NAND flash in JFFS2. NAND is a newer - type of flash chip design than the traditional NOR flash, with - higher density but a handful of characteristics which make it more - interesting for the file system to use. + This enables the write-buffering support in JFFS2. - Say 'N' unless you have NAND flash. - -config JFFS2_FS_NOR_ECC - bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)" - depends on JFFS2_FS && EXPERIMENTAL - default n - help - This enables the experimental support for NOR flash with transparent - ECC for JFFS2. This type of flash chip is not common, however it is - available from ST Microelectronics. - -config JFFS2_FS_DATAFLASH - bool "JFFS2 support for DataFlash (EXPERIMENTAL)" - depends on JFFS2_FS && EXPERIMENTAL - default n - help - This enables the experimental support for JFFS2 on DataFlash devices. + This functionality is required to support JFFS2 on the following + types of flash devices: + - NAND flash + - NOR flash with transparent ECC + - DataFlash config JFFS2_COMPRESSION_OPTIONS bool "Advanced compression options for JFFS2" diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile index 6c2ebe176b40..f1afe681ecd6 100644 --- a/fs/jffs2/Makefile +++ b/fs/jffs2/Makefile @@ -1,7 +1,7 @@ # # Makefile for the Linux Journalling Flash File System v2 (JFFS2) # -# $Id: Makefile.common,v 1.8 2005/02/09 09:17:40 pavlov Exp $ +# $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $ # obj-$(CONFIG_JFFS2_FS) += jffs2.o @@ -11,9 +11,7 @@ jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o jffs2-y += super.o -jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o -jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o -jffs2-$(CONFIG_JFFS2_FS_DATAFLASH) += wbuf.o +jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 5b7c960a0475..c91c66e5e869 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.52 2005/02/09 09:17:40 pavlov Exp $ + * $Id: fs.c,v 1.53 2005/02/09 09:23:53 pavlov Exp $ * */ @@ -450,13 +450,11 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent) c = JFFS2_SB_INFO(sb); -#ifndef CONFIG_JFFS2_FS_NAND +#ifndef CONFIG_JFFS2_FS_WRITEBUFFER if (c->mtd->type == MTD_NANDFLASH) { printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n"); return -EINVAL; } -#endif -#ifndef CONFIG_JFFS2_FS_DATAFLASH if (c->mtd->type == MTD_DATAFLASH) { printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n"); return -EINVAL; diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index a4864d05ea92..8c122838bf6d 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $ + * $Id: nodelist.h,v 1.127 2005/02/09 09:23:53 pavlov Exp $ * */ @@ -462,7 +462,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c); /* erase.c */ void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count); -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER /* 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); diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index af27b84007a1..8989cd685e46 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.53 2005/02/09 09:17:41 pavlov Exp $ + * $Id: os-linux.h,v 1.54 2005/02/09 09:23:53 pavlov Exp $ * */ @@ -97,16 +97,12 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #endif } -#ifdef CONFIG_JFFS2_FS_DATAFLASH -#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) -#else -#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) -#endif #define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY) #define jffs2_is_writebuffered(c) (c->wbuf != NULL) -#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC && !defined CONFIG_JFFS2_FS_DATAFLASH) +#ifndef CONFIG_JFFS2_FS_WRITEBUFFER +#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) ) #define jffs2_can_mark_obsolete(c) (1) #define jffs2_cleanmarker_oob(c) (0) #define jffs2_write_nand_cleanmarker(c,jeb) (-EIO) @@ -129,6 +125,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) #else /* NAND and/or ECC'd NOR support present */ +#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size ) #define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM) #define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH) @@ -150,25 +147,16 @@ 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_nand_flash_setup(struct jffs2_sb_info *c); void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c); -#ifdef CONFIG_JFFS2_FS_NOR_ECC + #define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC)) int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c); void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c); -#else -#define jffs2_nor_ecc(c) (0) -#define jffs2_nor_ecc_flash_setup(c) (0) -#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0) -#endif /* NOR ECC */ -#ifdef CONFIG_JFFS2_FS_DATAFLASH + #define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH) int jffs2_dataflash_setup(struct jffs2_sb_info *c); void jffs2_dataflash_cleanup(struct jffs2_sb_info *c); -#else -#define jffs2_dataflash(c) (0) -#define jffs2_dataflash_setup(c) (0) -#define jffs2_dataflash_cleanup(c) do {} while (0) -#endif /* DATAFLASH */ -#endif /* NAND */ + +#endif /* WRITEBUFFER */ /* erase.c */ static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c) diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c index e8c43746c82e..bc6c99980026 100644 --- a/fs/jffs2/scan.c +++ b/fs/jffs2/scan.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.117 2005/02/09 09:17:41 pavlov Exp $ + * $Id: scan.c,v 1.118 2005/02/09 09:23:53 pavlov Exp $ * */ #include @@ -68,7 +68,7 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo static inline int min_free(struct jffs2_sb_info *c) { uint32_t min = 2 * sizeof(struct jffs2_raw_inode); -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize) return c->wbuf_pagesize; #endif @@ -228,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c) c->dirty_size -= c->nextblock->dirty_size; c->nextblock->dirty_size = 0; } -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 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, @@ -294,7 +294,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo uint32_t hdr_crc, buf_ofs, buf_len; int err; int noise = 0; -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER int cleanmarkerfound = 0; #endif @@ -303,7 +303,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs)); -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER 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)); @@ -338,7 +338,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo ofs += 4; if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) { -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER if (jffs2_cleanmarker_oob(c)) { /* scan oob, take care of cleanmarker */ int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound); diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 6b2a441d2766..3bfc121a4674 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.104 2004/11/23 15:37:31 gleixner Exp $ + * $Id: super.c,v 1.105 2005/02/09 09:23:54 pavlov Exp $ * */ @@ -309,7 +309,7 @@ static int __init init_jffs2_fs(void) int ret; printk(KERN_INFO "JFFS2 version 2.2." -#ifdef CONFIG_JFFS2_FS_NAND +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER " (NAND)" #endif " (C) 2001-2003 Red Hat, Inc.\n"); diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index a35e007e5bf8..890258505a7f 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -9,7 +9,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.88 2005/02/09 09:17:41 pavlov Exp $ + * $Id: wbuf.c,v 1.89 2005/02/09 09:23:54 pavlov Exp $ * */ @@ -604,7 +604,7 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) return ret; } -#ifdef CONFIG_JFFS2_FS_DATAFLASH +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER #define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) #define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) #else @@ -1198,7 +1198,6 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) kfree(c->wbuf); } -#ifdef CONFIG_JFFS2_FS_DATAFLASH int jffs2_dataflash_setup(struct jffs2_sb_info *c) { c->cleanmarker_size = 0; /* No cleanmarkers needed */ @@ -1219,9 +1218,7 @@ int jffs2_dataflash_setup(struct jffs2_sb_info *c) { void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { kfree(c->wbuf); } -#endif -#ifdef CONFIG_JFFS2_FS_NOR_ECC int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { /* Cleanmarker is actually larger on the flashes */ c->cleanmarker_size = 16; @@ -1241,4 +1238,3 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { kfree(c->wbuf); } -#endif diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h index faec29559fed..1bd6cdfb7d78 100644 --- a/include/linux/jffs2_fs_sb.h +++ b/include/linux/jffs2_fs_sb.h @@ -1,4 +1,4 @@ -/* $Id: jffs2_fs_sb.h,v 1.49 2005/02/09 09:17:41 pavlov Exp $ */ +/* $Id: jffs2_fs_sb.h,v 1.50 2005/02/09 09:23:55 pavlov Exp $ */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB @@ -94,7 +94,7 @@ struct jffs2_sb_info { to an obsoleted node. I don't like this. Alternatives welcomed. */ struct semaphore erase_free_sem; -#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC || defined CONFIG_JFFS2_FS_DATAFLASH +#ifdef CONFIG_JFFS2_FS_WRITEBUFFER /* Write-behind buffer for NAND flash */ unsigned char *wbuf; uint32_t wbuf_ofs; -- cgit v1.2.3 From 0040bf382c77414739c933e4d2ee35ff817d0b99 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Wed, 9 Feb 2005 12:20:00 +0000 Subject: [MTD] NAND: Skip bad block table scan on request Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 6 +++++- include/linux/mtd/nand.h | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7094dd5716dc..99abd615a467 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $ + * $Id: nand_base.c,v 1.131 2005/02/09 12:19:56 gleixner Exp $ * * 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 @@ -2631,6 +2631,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips) memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo)); mtd->owner = THIS_MODULE; + + /* Check, if we should skip the bad block table scan */ + if (this->options & NAND_SKIP_BBTSCAN) + return 0; /* Build bad block table */ return this->scan_bbt (mtd); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index cf52f20c6de2..cf25c7cfd0ba 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -5,7 +5,7 @@ * Steven J. Hill * Thomas Gleixner * - * $Id: nand.h,v 1.70 2005/01/24 03:07:42 dmarlin Exp $ + * $Id: nand.h,v 1.71 2005/02/09 12:12:59 gleixner Exp $ * * 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 @@ -223,7 +223,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_ * This can only work if we have the ecc bytes directly behind the * data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */ #define NAND_HWECC_SYNDROME 0x00020000 - +/* This option skips the bbt scan during initialization. */ +#define NAND_SKIP_BBTSCAN 0x00040000 /* Options set by nand scan */ /* Nand scan has allocated oob_buf */ -- cgit v1.2.3 From f16407d73effc59e1e9f88e45a3dc53cacbb8264 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Wed, 16 Feb 2005 15:55:03 +0000 Subject: [MTD] Quiet unused variable warning Signed-off-by: Nioclas Pitre Signed-off-by: Thomas Gleixner --- include/linux/mtd/map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 8fc6679aa9b1..115b14a634da 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -1,6 +1,6 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.47 2005/02/08 17:11:15 nico Exp $ */ +/* $Id: map.h,v 1.48 2005/02/16 15:54:59 nico Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ @@ -418,7 +418,7 @@ extern void simple_map_init(struct map_info *); #define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth)) -#define map_is_linear(map) (1) +#define map_is_linear(map) ({ (void)(map); 1; }) #endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ -- cgit v1.2.3 From 31fbdf7aa5aac8a2a34f180a25deb157297a10c9 Mon Sep 17 00:00:00 2001 From: "Artem B. Bityuckiy" Date: Mon, 28 Feb 2005 08:21:09 +0000 Subject: [JFFS2] Fix NOR specific scan BUG Fix fairly sad NOR-specific bug - during FS building ic->scan_dents isn't zero, but jffs2_mark_node_obsolete() migt be called it tries to finde the ic corresponding to ref - this requires ic->scan_dents = 0. Signed-off-by: Artem B. Bityuckiy Signed-off-by: Thomas Gleixner --- fs/jffs2/build.c | 9 ++++++--- fs/jffs2/nodemgmt.c | 11 ++++++----- include/linux/jffs2_fs_sb.h | 5 +++-- 3 files changed, 15 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index a01dd5fdbb95..3dd5394921c9 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $ + * $Id: build.c,v 1.70 2005/02/28 08:21:05 dedekind Exp $ * */ @@ -97,14 +97,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) /* First, scan the medium and build all the inode caches with lists of physical nodes */ - c->flags |= JFFS2_SB_FLAG_MOUNTING; + c->flags |= JFFS2_SB_FLAG_SCANNING; ret = jffs2_scan_medium(c); + c->flags &= ~JFFS2_SB_FLAG_SCANNING; if (ret) goto exit; D1(printk(KERN_DEBUG "Scanned flash completely\n")); D2(jffs2_dump_block_lists(c)); + c->flags |= JFFS2_SB_FLAG_BUILDING; /* 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)); @@ -116,7 +118,6 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) cond_resched(); } } - c->flags &= ~JFFS2_SB_FLAG_MOUNTING; D1(printk(KERN_DEBUG "Pass 1 complete\n")); @@ -164,6 +165,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c) ic->scan_dents = NULL; cond_resched(); } + c->flags &= ~JFFS2_SB_FLAG_BUILDING; + D1(printk(KERN_DEBUG "Pass 3 complete\n")); D2(jffs2_dump_block_lists(c)); diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c index f9dcac1415ac..456adf020f22 100644 --- a/fs/jffs2/nodemgmt.c +++ b/fs/jffs2/nodemgmt.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.118 2005/02/27 23:01:32 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.119 2005/02/28 08:21:05 dedekind Exp $ * */ @@ -403,7 +403,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref jeb = &c->blocks[blocknr]; if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) && - !(c->flags & JFFS2_SB_FLAG_MOUNTING)) { + !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) { /* Hm. This may confuse static lock analysis. If any of the above three conditions is false, we're going to return from this function without actually obliterating any nodes or freeing @@ -470,8 +470,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref D1(ACCT_PARANOIA_CHECK(jeb)); - if (c->flags & JFFS2_SB_FLAG_MOUNTING) { - /* Mount in progress. Don't muck about with the block + if (c->flags & JFFS2_SB_FLAG_SCANNING) { + /* Flash scanning is in progress. Don't muck about with the block lists because they're not ready yet, and don't actually obliterate nodes that look obsolete. If they weren't marked obsolete on the flash at the time they _became_ @@ -530,7 +530,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref spin_unlock(&c->erase_completion_lock); - if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) { + if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) || + (c->flags & JFFS2_SB_FLAG_BUILDING)) { /* We didn't lock the erase_free_sem */ return; } diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h index 1bd6cdfb7d78..350b82bd6529 100644 --- a/include/linux/jffs2_fs_sb.h +++ b/include/linux/jffs2_fs_sb.h @@ -1,4 +1,4 @@ -/* $Id: jffs2_fs_sb.h,v 1.50 2005/02/09 09:23:55 pavlov Exp $ */ +/* $Id: jffs2_fs_sb.h,v 1.51 2005/02/28 08:21:06 dedekind Exp $ */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB @@ -14,7 +14,8 @@ #include #define JFFS2_SB_FLAG_RO 1 -#define JFFS2_SB_FLAG_MOUNTING 2 +#define JFFS2_SB_FLAG_SCANNING 2 /* Flash scanning is in progress */ +#define JFFS2_SB_FLAG_BUILDING 4 /* File system building is in progress */ struct jffs2_inodirty; -- cgit v1.2.3 From 0514cd938009de1d6b3239d98c3cf2a67b620103 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Mon, 14 Mar 2005 18:27:18 +0000 Subject: [MTD] Fixed signed 1bit bitfield Signed-off-by: Ben Dooks Signed-off-by: Thomas Gleixner --- include/linux/mtd/flashchip.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h index e778a1ab23c4..675776fa3e27 100644 --- a/include/linux/mtd/flashchip.h +++ b/include/linux/mtd/flashchip.h @@ -6,7 +6,7 @@ * * (C) 2000 Red Hat. GPLd. * - * $Id: flashchip.h,v 1.16 2005/02/08 17:11:15 nico Exp $ + * $Id: flashchip.h,v 1.17 2005/03/14 18:27:15 bjd Exp $ * */ @@ -63,8 +63,8 @@ struct flchip { flstate_t state; flstate_t oldstate; - int write_suspended:1; - int erase_suspended:1; + unsigned int write_suspended:1; + unsigned int erase_suspended:1; unsigned long in_progress_block_addr; spinlock_t *mutex; -- cgit v1.2.3 From c927cd3a226bed5cf063cdf04de13cef51144cef Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 15 Mar 2005 19:03:16 +0000 Subject: [MTD] Add the reverse operation of cfi_build_cmd() This is necessary to fix the broken status check in cfi_cmdset_0001 Signed-off-by: Thomas Gleixner --- include/linux/mtd/cfi.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 76255474a27c..66e0a32efbac 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -1,7 +1,7 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.52 2005/02/08 17:11:15 nico Exp $ + * $Id: cfi.h,v 1.53 2005/03/15 19:03:13 gleixner Exp $ */ #ifndef __MTD_CFI_H__ @@ -315,6 +315,69 @@ static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cf } #define CMD(x) cfi_build_cmd((x), map, cfi) + +static inline unsigned char cfi_merge_status(map_word val, struct map_info *map, + struct cfi_private *cfi) +{ + int wordwidth, words_per_bus, chip_mode, chips_per_word; + unsigned long onestat, res = 0; + int i; + + /* We do it this way to give the compiler a fighting chance + of optimising away all the crap for 'bankwidth' larger than + an unsigned long, in the common case where that support is + disabled */ + if (map_bankwidth_is_large(map)) { + wordwidth = sizeof(unsigned long); + words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1 + } else { + wordwidth = map_bankwidth(map); + words_per_bus = 1; + } + + chip_mode = map_bankwidth(map) / cfi_interleave(cfi); + chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map); + + onestat = val.x[0]; + /* Or all status words together */ + for (i=1; i < words_per_bus; i++) { + onestat |= val.x[i]; + } + + res = onestat; + switch(chips_per_word) { + default: BUG(); +#if BITS_PER_LONG >= 64 + case 8: + res |= (onestat >> (chip_mode * 32)); +#endif + case 4: + res |= (onestat >> (chip_mode * 16)); + case 2: + res |= (onestat >> (chip_mode * 8)); + case 1: + ; + } + + /* Last, determine what the bit-pattern should be for a single + device, according to chip mode and endianness... */ + switch (chip_mode) { + case 1: + break; + case 2: + res = cfi16_to_cpu(res); + break; + case 4: + res = cfi32_to_cpu(res); + break; + default: BUG(); + } + return res; +} + +#define MERGESTATUS(x) cfi_merge_status((x), map, cfi) + + /* * Sends a CFI command to a bank of flash for the given geometry. * -- cgit v1.2.3 From 963a6fb0a0d336d0513083b7e4b5c3ff9d6d2061 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 1 Apr 2005 02:59:56 +0100 Subject: [MTD] Add reboot notifier to Intel NOR flash driver to make sure the flash is in array mode whenever we're about to reboot. This is especially useful to allow "soft" reboot to work which consists of branching back into the bootloader. Signed-off-by: Nicolas Pitre Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 45 +++++++++++++++++++++++++++++++++++-- include/linux/mtd/mtd.h | 5 ++++- 2 files changed, 47 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index b482a4e48e48..dc257eb6932f 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.173 2005/03/30 23:57:30 tpoynor Exp $ + * $Id: cfi_cmdset_0001.c,v 1.174 2005/04/01 01:59:52 nico Exp $ * * * 10/10/2000 Nicolas Pitre @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,7 @@ static int cfi_intelext_get_user_prot_info (struct mtd_info *, #endif static int cfi_intelext_suspend (struct mtd_info *); static void cfi_intelext_resume (struct mtd_info *); +static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *); static void cfi_intelext_destroy(struct mtd_info *); @@ -333,7 +335,9 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary) mtd->resume = cfi_intelext_resume; mtd->flags = MTD_CAP_NORFLASH; mtd->name = map->name; - + + mtd->reboot_notifier.notifier_call = cfi_intelext_reboot; + if (cfi->cfi_mode == CFI_MODE_CFI) { /* * It's a real CFI chip, not one for which the probe @@ -446,6 +450,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd) goto setup_err; __module_get(THIS_MODULE); + register_reboot_notifier(&mtd->reboot_notifier); return mtd; setup_err: @@ -2301,10 +2306,46 @@ static void cfi_intelext_resume(struct mtd_info *mtd) } } +static int cfi_intelext_reset(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int i, ret; + + for (i=0; i < cfi->numchips; i++) { + struct flchip *chip = &cfi->chips[i]; + + /* force the completion of any ongoing operation + and switch to array mode so any bootloader in + flash is accessible for soft reboot. */ + spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_SYNCING); + if (!ret) { + map_write(map, CMD(0xff), chip->start); + chip->state = FL_READY; + } + spin_unlock(chip->mutex); + } + + return 0; +} + +static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val, + void *v) +{ + struct mtd_info *mtd; + + mtd = container_of(nb, struct mtd_info, reboot_notifier); + cfi_intelext_reset(mtd); + return NOTIFY_DONE; +} + static void cfi_intelext_destroy(struct mtd_info *mtd) { struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; + cfi_intelext_reset(mtd); + unregister_reboot_notifier(&mtd->reboot_notifier); kfree(cfi->cmdset_priv); kfree(cfi->cfiq); kfree(cfi->chips[0].priv); diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 3aab1b8729e0..f574cd498816 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -1,5 +1,5 @@ /* - * $Id: mtd.h,v 1.57 2005/02/08 17:11:15 nico Exp $ + * $Id: mtd.h,v 1.58 2005/04/01 01:59:54 nico Exp $ * * Copyright (C) 1999-2003 David Woodhouse et al. * @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -147,6 +148,8 @@ struct mtd_info { int (*block_isbad) (struct mtd_info *mtd, loff_t ofs); int (*block_markbad) (struct mtd_info *mtd, loff_t ofs); + struct notifier_block reboot_notifier; /* default mode before reboot */ + void *priv; struct module *owner; -- cgit v1.2.3 From 65c6e0a657012d104fe42be5f01a7b9b451b687c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 11 Apr 2005 11:19:05 +0100 Subject: [MTD] Fix broken user ABI Move kernel data where it belongs. Previous change broke user abi. Signed-off-by: Thomas Gleixner --- include/linux/mtd/mtd.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index f574cd498816..c50c3f3927d9 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -1,5 +1,5 @@ /* - * $Id: mtd.h,v 1.58 2005/04/01 01:59:54 nico Exp $ + * $Id: mtd.h,v 1.59 2005/04/11 10:19:02 gleixner Exp $ * * Copyright (C) 1999-2003 David Woodhouse et al. * @@ -70,7 +70,6 @@ struct mtd_info { u_int32_t oobblock; // Size of OOB blocks (e.g. 512) u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) - u_int32_t oobavail; // Number of bytes in OOB area available for fs u_int32_t ecctype; u_int32_t eccsize; @@ -81,6 +80,7 @@ struct mtd_info { // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) struct nand_oobinfo oobinfo; + u_int32_t oobavail; // Number of bytes in OOB area available for fs /* Data for variable erase regions. If numeraseregions is zero, * it means that the whole device has erasesize as given above. -- cgit v1.2.3 From fff7afd791f6a685b3ddedb8cfb152aed85f3cf8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 19 May 2005 17:18:11 +0100 Subject: [JFFS2] Convert thread start semaphore to completion Signed-off-by: Thomas Gleixner --- fs/jffs2/background.c | 8 ++++---- include/linux/jffs2_fs_sb.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 1be6de27dd81..5548749bacb6 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $ + * $Id: background.c,v 1.52 2005/05/19 16:18:08 gleixner Exp $ * */ @@ -37,7 +37,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) if (c->gc_task) BUG(); - init_MUTEX_LOCKED(&c->gc_thread_start); + init_completion(&c->gc_thread_start); init_completion(&c->gc_thread_exit); pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES); @@ -48,7 +48,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c) } else { /* Wait for it... */ D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid)); - down(&c->gc_thread_start); + wait_for_completion(&c->gc_thread_start); } return ret; @@ -75,7 +75,7 @@ static int jffs2_garbage_collect_thread(void *_c) allow_signal(SIGCONT); c->gc_task = current; - up(&c->gc_thread_start); + complete(&c->gc_thread_start); set_user_nice(current, 10); diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h index 350b82bd6529..1e21546622de 100644 --- a/include/linux/jffs2_fs_sb.h +++ b/include/linux/jffs2_fs_sb.h @@ -1,4 +1,4 @@ -/* $Id: jffs2_fs_sb.h,v 1.51 2005/02/28 08:21:06 dedekind Exp $ */ +/* $Id: jffs2_fs_sb.h,v 1.52 2005/05/19 16:12:17 gleixner Exp $ */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB @@ -32,7 +32,7 @@ struct jffs2_sb_info { unsigned int flags; struct task_struct *gc_task; /* GC task struct */ - struct semaphore gc_thread_start; /* GC thread start mutex */ + struct completion gc_thread_start; /* GC thread start completion */ struct completion gc_thread_exit; /* GC thread exit completion port */ struct semaphore alloc_sem; /* Used to protect all the following -- cgit v1.2.3 From 3a3ab48c68de656736f091c6ed768fa8c110a7ab Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 24 May 2005 20:50:18 +0200 Subject: [MTD] Make map_word_ff ware of the flash buswidth map_word_ff() was setting the mapword to ~0UL regardless of the buswidth of the mapped flash chip. The read_map functions are buswidth aware and therefor the map_word_equal function failed. Signed-off-by: Thomas Gleixner --- include/linux/mtd/map.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index 115b14a634da..dd36d9433f00 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -1,6 +1,6 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.48 2005/02/16 15:54:59 nico Exp $ */ +/* $Id: map.h,v 1.49 2005/05/24 18:45:15 gleixner Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ @@ -340,13 +340,22 @@ static inline map_word map_word_load_partial(struct map_info *map, map_word orig return orig; } +#if BITS_PER_LONG < 64 +#define MAP_FF_LIMIT 4 +#else +#define MAP_FF_LIMIT 8 +#endif + static inline map_word map_word_ff(struct map_info *map) { map_word r; int i; - - for (i=0; i Date: Wed, 25 May 2005 12:20:29 +0200 Subject: [MTD] map.h Use the correct macro and fix the resulting compiler warning Signed-off-by: Thomas Gleixner --- include/linux/mtd/map.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index dd36d9433f00..dbd7b9b510d3 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -1,6 +1,6 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.49 2005/05/24 18:45:15 gleixner Exp $ */ +/* $Id: map.h,v 1.51 2005/05/25 10:15:29 gleixner Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ @@ -351,8 +351,9 @@ static inline map_word map_word_ff(struct map_info *map) map_word r; int i; - if (map_bank_width(map) < MAP_FF_LIMIT) { - r.x[0] = (1 << (8*map_bank_width(map))) - 1; + if (map_bankwidth(map) < MAP_FF_LIMIT) { + int bw = 8 * map_bankwidth; + r.x[0] = (1 << bw) - 1; } else { for (i=0; i Date: Wed, 25 May 2005 12:32:37 +0200 Subject: [MTD] Fix it really tglx declares him self to be the idiot of the day. Signed-off-by: Thomas Gleixner --- include/linux/mtd/map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h index dbd7b9b510d3..142963f01d29 100644 --- a/include/linux/mtd/map.h +++ b/include/linux/mtd/map.h @@ -1,6 +1,6 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.51 2005/05/25 10:15:29 gleixner Exp $ */ +/* $Id: map.h,v 1.52 2005/05/25 10:29:41 gleixner Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ @@ -352,7 +352,7 @@ static inline map_word map_word_ff(struct map_info *map) int i; if (map_bankwidth(map) < MAP_FF_LIMIT) { - int bw = 8 * map_bankwidth; + int bw = 8 * map_bankwidth(map); r.x[0] = (1 << bw) - 1; } else { for (i=0; i Date: Tue, 24 May 2005 01:46:34 -0700 Subject: [MTD] NAND: Add Hynix to manufacturer list Signed-off-by: Nicolas S. Dade Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_ids.c | 1 + include/linux/mtd/nand.h | 1 + 2 files changed, 2 insertions(+) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 79945e6ce2b9..4b2bfae6f501 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -116,6 +116,7 @@ struct nand_manufacturers nand_manuf_ids[] = { {NAND_MFR_NATIONAL, "National"}, {NAND_MFR_RENESAS, "Renesas"}, {NAND_MFR_STMICRO, "ST Micro"}, + {NAND_MFR_HYNIX, "Hynix"}, {0x0, "Unknown"} }; diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index cf25c7cfd0ba..bee78969cb21 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -384,6 +384,7 @@ struct nand_chip { #define NAND_MFR_NATIONAL 0x8f #define NAND_MFR_RENESAS 0x07 #define NAND_MFR_STMICRO 0x20 +#define NAND_MFR_HYNIX 0xad /** * struct nand_flash_dev - NAND Flash Device ID Structure -- cgit v1.2.3 From 0dfc62465ef92c7ddcb1ba223bf062453566fd0f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 31 May 2005 20:39:20 +0100 Subject: [MTD] NAND: Reorganize chip locking The code was wrong in several aspects. The locking order was inconsistent, the device aquire code did not reset a variable after a wakeup and the wakeup handling was not working for applications where multiple chips are sharing a single hardware controller. When a hardware controller is available the locking is now reduced to the hardware controller lock and the waitqueue is moved to the hardware controller structure in order to avoid a wake_up_all(). The problem was pointed out by Ben Dooks, who also found the missing variable reset as main cause for his deadlock problem. Signed-off-by: Thomas Gleixner --- drivers/mtd/nand/nand_base.c | 57 ++++++++++++++++++++++---------------------- include/linux/mtd/nand.h | 5 +++- 2 files changed, 33 insertions(+), 29 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index f1db0bf9306b..bbe0283433d2 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -59,7 +59,7 @@ * The AG-AND chips have nice features for speed improvement, * which are not supported yet. Read / program 4 pages in one go. * - * $Id: nand_base.c,v 1.143 2005/05/19 16:10:22 gleixner Exp $ + * $Id: nand_base.c,v 1.145 2005/05/31 20:32:53 gleixner Exp $ * * 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 @@ -167,17 +167,21 @@ static void nand_release_device (struct mtd_info *mtd) /* De-select the NAND device */ this->select_chip(mtd, -1); - /* Do we have a hardware controller ? */ + if (this->controller) { + /* Release the controller and the chip */ spin_lock(&this->controller->lock); this->controller->active = NULL; + this->state = FL_READY; + wake_up(&this->controller->wq); spin_unlock(&this->controller->lock); + } else { + /* Release the chip */ + spin_lock(&this->chip_lock); + this->state = FL_READY; + wake_up(&this->wq); + spin_unlock(&this->chip_lock); } - /* Release the chip */ - spin_lock (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock (&this->chip_lock); } /** @@ -753,37 +757,34 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column, */ static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state) { - struct nand_chip *active = this; - + struct nand_chip *active; + spinlock_t *lock; + wait_queue_head_t *wq; DECLARE_WAITQUEUE (wait, current); - /* - * Grab the lock and see if the device is available - */ + lock = (this->controller) ? &this->controller->lock : &this->chip_lock; + wq = (this->controller) ? &this->controller->wq : &this->wq; retry: + active = this; + spin_lock(lock); + /* Hardware controller shared among independend devices */ if (this->controller) { - spin_lock (&this->controller->lock); if (this->controller->active) active = this->controller->active; else this->controller->active = this; - spin_unlock (&this->controller->lock); } - - if (active == this) { - spin_lock (&this->chip_lock); - if (this->state == FL_READY) { - this->state = new_state; - spin_unlock (&this->chip_lock); - return; - } - } - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&active->wq, &wait); - spin_unlock (&active->chip_lock); - schedule (); - remove_wait_queue (&active->wq, &wait); + if (active == this && this->state == FL_READY) { + this->state = new_state; + spin_unlock(lock); + return; + } + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(wq, &wait); + spin_unlock(lock); + schedule(); + remove_wait_queue(wq, &wait); goto retry; } diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index bee78969cb21..9b5b76217584 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -5,7 +5,7 @@ * Steven J. Hill * Thomas Gleixner * - * $Id: nand.h,v 1.71 2005/02/09 12:12:59 gleixner Exp $ + * $Id: nand.h,v 1.73 2005/05/31 19:39:17 gleixner Exp $ * * 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 @@ -253,10 +253,13 @@ struct nand_chip; * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices * @lock: protection lock * @active: the mtd device which holds the controller currently + * @wq: wait queue to sleep on if a NAND operation is in progress + * used instead of the per chip wait queue when a hw controller is available */ struct nand_hw_control { spinlock_t lock; struct nand_chip *active; + wait_queue_head_t wq; }; /** -- cgit v1.2.3 From 02b15e343aeefb49f8cac949be599d78250a568f Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Tue, 7 Jun 2005 00:04:39 +0100 Subject: [MTD] XIP for AMD CFI flash. Author: Vitaly Wool Signed-off-by: Todd Poynor Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/Kconfig | 4 +- drivers/mtd/chips/cfi_cmdset_0002.c | 402 ++++++++++++++++++++++++++++-------- drivers/mtd/chips/fwh_lock.h | 6 +- drivers/mtd/maps/map_funcs.c | 11 +- include/linux/mtd/cfi.h | 12 +- 5 files changed, 324 insertions(+), 111 deletions(-) (limited to 'include/linux') diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig index f4eda1e40d51..b5dc59389bb3 100644 --- a/drivers/mtd/chips/Kconfig +++ b/drivers/mtd/chips/Kconfig @@ -1,5 +1,5 @@ # drivers/mtd/chips/Kconfig -# $Id: Kconfig,v 1.14 2005/02/08 17:11:15 nico Exp $ +# $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $ menu "RAM/ROM/Flash chip drivers" depends on MTD!=n @@ -300,7 +300,7 @@ config MTD_JEDEC config MTD_XIP bool "XIP aware MTD support" - depends on !SMP && MTD_CFI_INTELEXT && EXPERIMENTAL + depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL default y if XIP_KERNEL help This allows MTD support to work with flash memory which is also diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 49cd81207137..e42eefbda0e1 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -4,16 +4,20 @@ * * Copyright (C) 2000 Crossnet Co. * Copyright (C) 2004 Arcom Control Systems Ltd + * Copyright (C) 2005 MontaVista Software Inc. * * 2_by_8 routines added by Simon Munton * * 4_by_16 work by Carolyn J. Smith * + * XIP support hooks by Vitaly Wool (based on code for Intel flash + * by Nicolas Pitre) + * * Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.116 2005/05/24 13:29:42 gleixner Exp $ + * $Id: cfi_cmdset_0002.c,v 1.117 2005/06/06 23:04:35 tpoynor Exp $ * */ @@ -34,6 +38,7 @@ #include #include #include +#include #define AMD_BOOTLOC_BUG #define FORCE_WORD_WRITE 0 @@ -393,7 +398,7 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd) * correctly and is therefore not done (particulary with interleaved chips * as each chip must be checked independantly of the others). */ -static int chip_ready(struct map_info *map, unsigned long addr) +static int __xipram chip_ready(struct map_info *map, unsigned long addr) { map_word d, t; @@ -418,7 +423,7 @@ static int chip_ready(struct map_info *map, unsigned long addr) * as each chip must be checked independantly of the others). * */ -static int chip_good(struct map_info *map, unsigned long addr, map_word expected) +static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected) { map_word oldd, curd; @@ -448,12 +453,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr if (time_after(jiffies, timeo)) { printk(KERN_ERR "Waiting for chip to be ready timed out.\n"); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return -EIO; } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); cfi_udelay(1); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); /* Someone else might have been playing with it. */ goto retry; } @@ -501,15 +506,23 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr return -EIO; } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); cfi_udelay(1); - cfi_spin_lock(chip->mutex); + 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_XIP_WHILE_ERASING: + if (mode != FL_READY && mode != FL_POINT && + (!cfip || !(cfip->EraseSuspend&2))) + goto sleep; + chip->oldstate = chip->state; + chip->state = FL_READY; + return 0; + case FL_POINT: /* Only if there's no operation suspended... */ if (mode == FL_READY && chip->oldstate == FL_READY) @@ -519,10 +532,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr sleep: set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); goto resettime; } } @@ -540,6 +553,11 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad chip->state = FL_ERASING; break; + case FL_XIP_WHILE_ERASING: + chip->state = chip->oldstate; + chip->oldstate = FL_READY; + break; + case FL_READY: case FL_STATUS: /* We should really make set_vpp() count, rather than doing this */ @@ -551,6 +569,198 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad wake_up(&chip->wq); } +#ifdef CONFIG_MTD_XIP + +/* + * No interrupt what so ever can be serviced while the flash isn't in array + * mode. This is ensured by the xip_disable() and xip_enable() functions + * enclosing any code path where the flash is known not to be in array mode. + * And within a XIP disabled code path, only functions marked with __xipram + * may be called and nothing else (it's a good thing to inspect generated + * assembly to make sure inline functions were actually inlined and that gcc + * didn't emit calls to its own support functions). Also configuring MTD CFI + * support to a single buswidth and a single interleave is also recommended. + */ +#include +static void xip_disable(struct map_info *map, struct flchip *chip, + unsigned long adr) +{ + /* TODO: chips with no XIP use should ignore and return */ + (void) map_read(map, adr); /* ensure mmu mapping is up to date */ + local_irq_disable(); +} + +static void __xipram xip_enable(struct map_info *map, struct flchip *chip, + unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + + if (chip->state != FL_POINT && chip->state != FL_READY) { + map_write(map, CMD(0xf0), adr); + chip->state = FL_READY; + } + (void) map_read(map, adr); + asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */ + local_irq_enable(); +} + +/* + * When a delay is required for the flash operation to complete, the + * xip_udelay() function is polling for both the given timeout and pending + * (but still masked) hardware interrupts. Whenever there is an interrupt + * pending then the flash erase operation is suspended, array mode restored + * and interrupts unmasked. Task scheduling might also happen at that + * point. The CPU eventually returns from the interrupt or the call to + * schedule() and the suspended flash operation is resumed for the remaining + * of the delay period. + * + * Warning: this function _will_ fool interrupt latency tracing tools. + */ + +static void __xipram xip_udelay(struct map_info *map, struct flchip *chip, + unsigned long adr, int usec) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct cfi_pri_amdstd *extp = cfi->cmdset_priv; + map_word status, OK = CMD(0x80); + unsigned long suspended, start = xip_currtime(); + flstate_t oldstate; + + do { + cpu_relax(); + if (xip_irqpending() && extp && + ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) && + (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) { + /* + * Let's suspend the erase operation when supported. + * Note that we currently don't try to suspend + * interleaved chips if there is already another + * operation suspended (imagine what happens + * when one chip was already done with the current + * operation while another chip suspended it, then + * we resume the whole thing at once). Yes, it + * can happen! + */ + map_write(map, CMD(0xb0), adr); + usec -= xip_elapsed_since(start); + suspended = xip_currtime(); + do { + if (xip_elapsed_since(suspended) > 100000) { + /* + * The chip doesn't want to suspend + * after waiting for 100 msecs. + * This is a critical error but there + * is not much we can do here. + */ + return; + } + status = map_read(map, adr); + } while (!map_word_andequal(map, status, OK, OK)); + + /* Suspend succeeded */ + oldstate = chip->state; + if (!map_word_bitsset(map, status, CMD(0x40))) + break; + chip->state = FL_XIP_WHILE_ERASING; + chip->erase_suspended = 1; + map_write(map, CMD(0xf0), adr); + (void) map_read(map, adr); + asm volatile (".rep 8; nop; .endr"); + local_irq_enable(); + spin_unlock(chip->mutex); + asm volatile (".rep 8; nop; .endr"); + cond_resched(); + + /* + * We're back. However someone else might have + * decided to go write to the chip if we are in + * a suspended erase state. If so let's wait + * until it's done. + */ + spin_lock(chip->mutex); + while (chip->state != FL_XIP_WHILE_ERASING) { + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + spin_lock(chip->mutex); + } + /* Disallow XIP again */ + local_irq_disable(); + + /* Resume the write or erase operation */ + map_write(map, CMD(0x30), adr); + chip->state = oldstate; + start = xip_currtime(); + } else if (usec >= 1000000/HZ) { + /* + * Try to save on CPU power when waiting delay + * is at least a system timer tick period. + * No need to be extremely accurate here. + */ + xip_cpu_idle(); + } + status = map_read(map, adr); + } while (!map_word_andequal(map, status, OK, OK) + && xip_elapsed_since(start) < usec); +} + +#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec) + +/* + * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while + * the flash is actively programming or erasing since we have to poll for + * the operation to complete anyway. We can't do that in a generic way with + * a XIP setup so do it before the actual flash operation in this case + * and stub it out from INVALIDATE_CACHE_UDELAY. + */ +#define XIP_INVAL_CACHED_RANGE(map, from, size) \ + INVALIDATE_CACHED_RANGE(map, from, size) + +#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \ + UDELAY(map, chip, adr, usec) + +/* + * Extra notes: + * + * Activating this XIP support changes the way the code works a bit. For + * example the code to suspend the current process when concurrent access + * happens is never executed because xip_udelay() will always return with the + * same chip state as it was entered with. This is why there is no care for + * the presence of add_wait_queue() or schedule() calls from within a couple + * xip_disable()'d areas of code, like in do_erase_oneblock for example. + * The queueing and scheduling are always happening within xip_udelay(). + * + * Similarly, get_chip() and put_chip() just happen to always be executed + * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state + * is in array mode, therefore never executing many cases therein and not + * causing any problem with XIP. + */ + +#else + +#define xip_disable(map, chip, adr) +#define xip_enable(map, chip, adr) +#define XIP_INVAL_CACHED_RANGE(x...) + +#define UDELAY(map, chip, adr, usec) \ +do { \ + spin_unlock(chip->mutex); \ + cfi_udelay(usec); \ + spin_lock(chip->mutex); \ +} while (0) + +#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \ +do { \ + spin_unlock(chip->mutex); \ + INVALIDATE_CACHED_RANGE(map, adr, len); \ + cfi_udelay(usec); \ + spin_lock(chip->mutex); \ +} while (0) + +#endif static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) { @@ -563,10 +773,10 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof /* Ensure cmd read/writes are aligned. */ cmd_addr = adr & ~(map_bankwidth(map)-1); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, cmd_addr, FL_READY); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -579,7 +789,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof put_chip(map, chip, cmd_addr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return 0; } @@ -633,7 +843,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi struct cfi_private *cfi = map->fldrv_priv; retry: - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); if (chip->state != FL_READY){ #if 0 @@ -642,7 +852,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); @@ -671,7 +881,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); wake_up(&chip->wq); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return 0; } @@ -720,7 +930,7 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len, } -static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum) +static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -740,10 +950,10 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned adr += chip->start; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_WRITING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -763,7 +973,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned goto op_done; } + XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map)); ENABLE_VPP(map); + xip_disable(map, chip, adr); retry: 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); @@ -771,9 +983,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned map_write(map, datum, adr); chip->state = FL_WRITING; - cfi_spin_unlock(chip->mutex); - cfi_udelay(chip->word_write_time); - cfi_spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + adr, map_bankwidth(map), + chip->word_write_time); /* See comment above for timeout value. */ timeo = jiffies + uWriteTimeout; @@ -784,11 +996,11 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + (HZ / 2); /* FIXME */ - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); continue; } @@ -796,14 +1008,14 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned break; if (time_after(jiffies, timeo)) { + xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); + xip_disable(map, chip, adr); break; } /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); - cfi_udelay(1); - cfi_spin_lock(chip->mutex); + UDELAY(map, chip, adr, 1); } /* Did we succeed? */ if (!chip_good(map, adr, datum)) { @@ -816,10 +1028,11 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned ret = -EIO; } + xip_enable(map, chip, adr); op_done: chip->state = FL_READY; put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -851,7 +1064,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, map_word tmp_buf; retry: - cfi_spin_lock(cfi->chips[chipnum].mutex); + spin_lock(cfi->chips[chipnum].mutex); if (cfi->chips[chipnum].state != FL_READY) { #if 0 @@ -860,7 +1073,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&cfi->chips[chipnum].wq, &wait); - cfi_spin_unlock(cfi->chips[chipnum].mutex); + spin_unlock(cfi->chips[chipnum].mutex); schedule(); remove_wait_queue(&cfi->chips[chipnum].wq, &wait); @@ -874,7 +1087,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, /* Load 'tmp_buf' with old contents of flash */ tmp_buf = map_read(map, bus_ofs+chipstart); - cfi_spin_unlock(cfi->chips[chipnum].mutex); + spin_unlock(cfi->chips[chipnum].mutex); /* Number of bytes to copy from buffer */ n = min_t(int, len, map_bankwidth(map)-i); @@ -929,7 +1142,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, map_word tmp_buf; retry1: - cfi_spin_lock(cfi->chips[chipnum].mutex); + spin_lock(cfi->chips[chipnum].mutex); if (cfi->chips[chipnum].state != FL_READY) { #if 0 @@ -938,7 +1151,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&cfi->chips[chipnum].wq, &wait); - cfi_spin_unlock(cfi->chips[chipnum].mutex); + spin_unlock(cfi->chips[chipnum].mutex); schedule(); remove_wait_queue(&cfi->chips[chipnum].wq, &wait); @@ -951,7 +1164,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, tmp_buf = map_read(map, ofs + chipstart); - cfi_spin_unlock(cfi->chips[chipnum].mutex); + spin_unlock(cfi->chips[chipnum].mutex); tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len); @@ -970,8 +1183,9 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len, /* * 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) +static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, + unsigned long adr, const u_char *buf, + int len) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -985,10 +1199,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, adr += chip->start; cmd_adr = adr; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_WRITING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -997,7 +1211,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n", __func__, adr, datum.x[0] ); + XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); + xip_disable(map, chip, cmd_adr); + 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(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1027,9 +1244,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, map_write(map, CMD(0x29), cmd_adr); chip->state = FL_WRITING; - cfi_spin_unlock(chip->mutex); - cfi_udelay(chip->buffer_write_time); - cfi_spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + adr, map_bankwidth(map), + chip->word_write_time); timeo = jiffies + uWriteTimeout; @@ -1040,38 +1257,39 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + (HZ / 2); /* FIXME */ - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); continue; } - if (chip_ready(map, adr)) + if (chip_ready(map, adr)) { + xip_enable(map, chip, adr); goto op_done; + } if( 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); + UDELAY(map, chip, adr, 1); } - printk(KERN_WARNING "MTD %s(): software timeout\n", - __func__ ); - /* reset on all failures. */ map_write( map, CMD(0xF0), chip->start ); + xip_enable(map, chip, adr); /* FIXME - should have reset delay before continuing */ + printk(KERN_WARNING "MTD %s(): software timeout\n", + __func__ ); + ret = -EIO; op_done: chip->state = FL_READY; put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -1161,7 +1379,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len, * 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) +static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -1171,17 +1389,20 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) adr = cfi->addr_unlock1; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_WRITING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", __func__, chip->start ); + XIP_INVAL_CACHED_RANGE(map, adr, map->size); ENABLE_VPP(map); + xip_disable(map, chip, adr); + 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(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1193,9 +1414,9 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) chip->erase_suspended = 0; chip->in_progress_block_addr = adr; - cfi_spin_unlock(chip->mutex); - msleep(chip->erase_time/2); - cfi_spin_lock(chip->mutex); + INVALIDATE_CACHE_UDELAY(map, chip, + adr, map->size, + chip->erase_time*500); timeo = jiffies + (HZ*20); @@ -1204,10 +1425,10 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) /* Someone's suspended the erase. Sleep */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); continue; } if (chip->erase_suspended) { @@ -1227,10 +1448,7 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) } /* 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); + UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ if (!chip_good(map, adr, map_word_ff(map))) { @@ -1242,14 +1460,15 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip) } chip->state = FL_READY; + xip_enable(map, chip, adr); put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } -static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) +static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; unsigned long timeo = jiffies + HZ; @@ -1258,17 +1477,20 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u adr += chip->start; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_ERASING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", __func__, adr ); + XIP_INVAL_CACHED_RANGE(map, adr, len); ENABLE_VPP(map); + xip_disable(map, chip, adr); + 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(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); @@ -1279,10 +1501,10 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u chip->state = FL_ERASING; chip->erase_suspended = 0; chip->in_progress_block_addr = adr; - - cfi_spin_unlock(chip->mutex); - msleep(chip->erase_time/2); - cfi_spin_lock(chip->mutex); + + INVALIDATE_CACHE_UDELAY(map, chip, + adr, len, + chip->erase_time*500); timeo = jiffies + (HZ*20); @@ -1291,10 +1513,10 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u /* Someone's suspended the erase. Sleep */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); continue; } if (chip->erase_suspended) { @@ -1304,20 +1526,20 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u chip->erase_suspended = 0; } - if (chip_ready(map, adr)) + if (chip_ready(map, adr)) { + xip_enable(map, chip, adr); break; + } if (time_after(jiffies, timeo)) { + xip_enable(map, chip, adr); printk(KERN_WARNING "MTD %s(): software timeout\n", __func__ ); 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); + UDELAY(map, chip, adr, 1000000/HZ); } /* Did we succeed? */ if (!chip_good(map, adr, map_word_ff(map))) { @@ -1330,7 +1552,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u chip->state = FL_READY; put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -1390,7 +1612,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) chip = &cfi->chips[i]; retry: - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); switch(chip->state) { case FL_READY: @@ -1404,14 +1626,14 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) * with the chip now anyway. */ case FL_SYNCING: - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); break; default: /* Not an idle state */ add_wait_queue(&chip->wq, &wait); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); schedule(); @@ -1426,13 +1648,13 @@ static void cfi_amdstd_sync (struct mtd_info *mtd) for (i--; i >=0; i--) { chip = &cfi->chips[i]; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; wake_up(&chip->wq); } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); } } @@ -1448,7 +1670,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) for (i=0; !ret && inumchips; i++) { chip = &cfi->chips[i]; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); switch(chip->state) { case FL_READY: @@ -1468,7 +1690,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) ret = -EAGAIN; break; } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); } /* Unlock the chips again */ @@ -1477,13 +1699,13 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd) for (i--; i >=0; i--) { chip = &cfi->chips[i]; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { chip->state = chip->oldstate; wake_up(&chip->wq); } - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); } } @@ -1502,7 +1724,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) chip = &cfi->chips[i]; - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { chip->state = FL_READY; @@ -1512,7 +1734,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd) else printk(KERN_ERR "Argh. Chip not in PM_SUSPENDED state upon resume()\n"); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); } } diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h index fbf44708a861..e1a5b76596c5 100644 --- a/drivers/mtd/chips/fwh_lock.h +++ b/drivers/mtd/chips/fwh_lock.h @@ -58,10 +58,10 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, * to flash memory - that means that we don't have to check status * and timeout. */ - cfi_spin_lock(chip->mutex); + spin_lock(chip->mutex); ret = get_chip(map, chip, adr, FL_LOCKING); if (ret) { - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return ret; } @@ -71,7 +71,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip, /* Done and happy. */ chip->state = FL_READY; put_chip(map, chip, adr); - cfi_spin_unlock(chip->mutex); + spin_unlock(chip->mutex); return 0; } diff --git a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c index 38f6a7af53f8..9105e6ca0aa6 100644 --- a/drivers/mtd/maps/map_funcs.c +++ b/drivers/mtd/maps/map_funcs.c @@ -1,5 +1,5 @@ /* - * $Id: map_funcs.c,v 1.9 2004/07/13 22:33:15 dwmw2 Exp $ + * $Id: map_funcs.c,v 1.10 2005/06/06 23:04:36 tpoynor Exp $ * * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS * is enabled. @@ -9,23 +9,24 @@ #include #include +#include -static map_word simple_map_read(struct map_info *map, unsigned long ofs) +static map_word __xipram simple_map_read(struct map_info *map, unsigned long ofs) { return inline_map_read(map, ofs); } -static void simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs) +static void __xipram simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs) { inline_map_write(map, datum, ofs); } -static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +static void __xipram simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) { inline_map_copy_from(map, to, from, len); } -static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +static void __xipram simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) { inline_map_copy_to(map, to, from, len); } diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h index 66e0a32efbac..e6b6a1c66bd5 100644 --- a/include/linux/mtd/cfi.h +++ b/include/linux/mtd/cfi.h @@ -1,7 +1,7 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.53 2005/03/15 19:03:13 gleixner Exp $ + * $Id: cfi.h,v 1.54 2005/06/06 23:04:36 tpoynor Exp $ */ #ifndef __MTD_CFI_H__ @@ -428,16 +428,6 @@ static inline void cfi_udelay(int us) } } -static inline void cfi_spin_lock(spinlock_t *mutex) -{ - spin_lock_bh(mutex); -} - -static inline void cfi_spin_unlock(spinlock_t *mutex) -{ - spin_unlock_bh(mutex); -} - struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size, const char* name); struct cfi_fixup { -- cgit v1.2.3 From bfabb98688e7089381baa0974f7ff6786ce2a2d0 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 13 Jun 2005 14:08:48 +0100 Subject: [MTD] Use correct major number for INFTL inftl was assigned new major number 96, 94 is in use by dasd. See: http://www.ussg.iu.edu/hypermail/linux/kernel/0409.2/1220.html Signed-off-by: Sean Young Signed-off-by: Thomas Gleixner --- include/linux/mtd/inftl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h index b52c8cbd235c..0268125a6271 100644 --- a/include/linux/mtd/inftl.h +++ b/include/linux/mtd/inftl.h @@ -3,7 +3,7 @@ * * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) * - * $Id: inftl.h,v 1.6 2004/06/30 14:49:00 dbrown Exp $ + * $Id: inftl.h,v 1.7 2005/06/13 13:08:45 sean Exp $ */ #ifndef __MTD_INFTL_H__ @@ -20,7 +20,7 @@ #include #ifndef INFTL_MAJOR -#define INFTL_MAJOR 94 +#define INFTL_MAJOR 96 #endif #define INFTL_PARTN_BITS 4 -- cgit v1.2.3 From 97f927a4d7dbccde0a854a62c3ea54d90bae8679 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 7 Jul 2005 16:50:16 +0200 Subject: [MTD] XIP cleanup Move the architecture dependend code into include/asm/mtd-xip.h Signed-off-by: Thomas Gleixner --- drivers/mtd/chips/cfi_cmdset_0001.c | 2 +- drivers/mtd/chips/cfi_cmdset_0002.c | 2 +- include/asm-arm/arch-pxa/mtd-xip.h | 37 +++++++++++++++++++++++++++++++++++ include/asm-arm/arch-sa1100/mtd-xip.h | 26 ++++++++++++++++++++++++ include/asm-arm/mtd-xip.h | 26 ++++++++++++++++++++++++ include/linux/mtd/xip.h | 31 ++++++++++++----------------- 6 files changed, 104 insertions(+), 20 deletions(-) create mode 100644 include/asm-arm/arch-pxa/mtd-xip.h create mode 100644 include/asm-arm/arch-sa1100/mtd-xip.h create mode 100644 include/asm-arm/mtd-xip.h (limited to 'include/linux') diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 8b1304531d8f..0cfcd88468e0 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c @@ -845,7 +845,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, chip->state = FL_READY; } (void) map_read(map, adr); - asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */ + xip_iprefetch(); local_irq_enable(); } diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index c76c30de48fb..8505f118f2db 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -600,7 +600,7 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip, chip->state = FL_READY; } (void) map_read(map, adr); - asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */ + xip_iprefetch(); local_irq_enable(); } diff --git a/include/asm-arm/arch-pxa/mtd-xip.h b/include/asm-arm/arch-pxa/mtd-xip.h new file mode 100644 index 000000000000..8704dbceb432 --- /dev/null +++ b/include/asm-arm/arch-pxa/mtd-xip.h @@ -0,0 +1,37 @@ +/* + * MTD primitives for XIP support. Architecture specific functions + * + * Do not include this file directly. It's included from linux/mtd/xip.h + * + * Author: Nicolas Pitre + * Created: Nov 2, 2004 + * Copyright: (C) 2004 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. + * + * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $ + */ + +#ifndef __ARCH_PXA_MTD_XIP_H__ +#define __ARCH_PXA_MTD_XIP_H__ + +#include + +#define xip_irqpending() (ICIP & ICMR) + +/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */ +#define xip_currtime() (OSCR) +#define xip_elapsed_since(x) (signed)((OSCR - (x)) / 4) + +/* + * xip_cpu_idle() is used when waiting for a delay equal or larger than + * the system timer tick period. This should put the CPU into idle mode + * to save power and to be woken up only when some interrupts are pending. + * As above, this should not rely upon standard kernel code. + */ + +#define xip_cpu_idle() asm volatile ("mcr p14, 0, %0, c7, c0, 0" :: "r" (1)) + +#endif /* __ARCH_PXA_MTD_XIP_H__ */ diff --git a/include/asm-arm/arch-sa1100/mtd-xip.h b/include/asm-arm/arch-sa1100/mtd-xip.h new file mode 100644 index 000000000000..80cfdac2b944 --- /dev/null +++ b/include/asm-arm/arch-sa1100/mtd-xip.h @@ -0,0 +1,26 @@ +/* + * MTD primitives for XIP support. Architecture specific functions + * + * Do not include this file directly. It's included from linux/mtd/xip.h + * + * Author: Nicolas Pitre + * Created: Nov 2, 2004 + * Copyright: (C) 2004 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. + * + * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $ + */ + +#ifndef __ARCH_SA1100_MTD_XIP_H__ +#define __ARCH_SA1100_MTD_XIP_H__ + +#define xip_irqpending() (ICIP & ICMR) + +/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */ +#define xip_currtime() (OSCR) +#define xip_elapsed_since(x) (signed)((OSCR - (x)) / 4) + +#endif /* __ARCH_SA1100_MTD_XIP_H__ */ diff --git a/include/asm-arm/mtd-xip.h b/include/asm-arm/mtd-xip.h new file mode 100644 index 000000000000..9eb127cc7db2 --- /dev/null +++ b/include/asm-arm/mtd-xip.h @@ -0,0 +1,26 @@ +/* + * MTD primitives for XIP support. Architecture specific functions + * + * Do not include this file directly. It's included from linux/mtd/xip.h + * + * Author: Nicolas Pitre + * Created: Nov 2, 2004 + * Copyright: (C) 2004 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. + * + * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $ + */ + +#ifndef __ARM_MTD_XIP_H__ +#define __ARM_MTD_XIP_H__ + +#include +#include + +/* fill instruction prefetch */ +#define xip_iprefetch() do { asm volatile (".rep 8; nop; .endr"); } while (0) + +#endif /* __ARM_MTD_XIP_H__ */ diff --git a/include/linux/mtd/xip.h b/include/linux/mtd/xip.h index fc071125cbcc..7b7deef6b180 100644 --- a/include/linux/mtd/xip.h +++ b/include/linux/mtd/xip.h @@ -58,22 +58,16 @@ * returned value is <= the real elapsed time. * note 2: this should be able to cope with a few seconds without * overflowing. + * + * xip_iprefetch() + * + * Macro to fill instruction prefetch + * e.g. a series of nops: asm volatile (".rep 8; nop; .endr"); */ -#if defined(CONFIG_ARCH_SA1100) || defined(CONFIG_ARCH_PXA) - -#include -#ifdef CONFIG_ARCH_PXA -#include -#endif - -#define xip_irqpending() (ICIP & ICMR) - -/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */ -#define xip_currtime() (OSCR) -#define xip_elapsed_since(x) (signed)((OSCR - (x)) / 4) +#include -#else +#ifndef xip_irqpending #warning "missing IRQ and timer primitives for XIP MTD support" #warning "some of the XIP MTD support code will be disabled" @@ -85,16 +79,17 @@ #endif +#ifndef xip_iprefetch +#define xip_iprefetch() do { } while (0) +#endif + /* * xip_cpu_idle() is used when waiting for a delay equal or larger than * the system timer tick period. This should put the CPU into idle mode * to save power and to be woken up only when some interrupts are pending. - * As above, this should not rely upon standard kernel code. + * This should not rely upon standard kernel code. */ - -#if defined(CONFIG_CPU_XSCALE) -#define xip_cpu_idle() asm volatile ("mcr p14, 0, %0, c7, c0, 0" :: "r" (1)) -#else +#ifndef xip_cpu_idle #define xip_cpu_idle() do { } while (0) #endif -- cgit v1.2.3