Commit 1c66c552 authored by David Woodhouse's avatar David Woodhouse

Merge shinybook.infradead.org:/home/dwmw2/bk/linus-2.6

into shinybook.infradead.org:/home/dwmw2/bk/mtd-2.6
parents 5c4ac43f 0d0f130f
......@@ -3578,7 +3578,6 @@ S: The Netherlands
N: David Woodhouse
E: dwmw2@infradead.org
E: dwmw2@redhat.com
D: ARCnet stuff, Applicom board driver, SO_BINDTODEVICE,
D: some Alpha platform porting from 2.0, Memory Technology Devices,
D: Acquire watchdog timer, PC speaker driver maintenance,
......
......@@ -1450,7 +1450,7 @@ S: Maintained
MEMORY TECHNOLOGY DEVICES
P: David Woodhouse
M: dwmw2@redhat.com
M: dwmw2@infradead.org
W: http://www.linux-mtd.infradead.org/
L: linux-mtd@lists.infradead.org
S: Maintained
......
/* Derived from Applicom driver ac.c for SCO Unix */
/* Ported by David Woodhouse, Axiom (Cambridge) Ltd. */
/* dwmw2@redhat.com 30/8/98 */
/* dwmw2@infradead.org 30/8/98 */
/* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $ */
/* This module is for Linux 2.1 and 2.2 series kernels. */
/*****************************************************************************/
......
# $Id: Kconfig,v 1.6 2004/08/09 13:19:42 dwmw2 Exp $
# $Id: Kconfig,v 1.7 2004/11/22 11:33:56 ijc Exp $
menu "Memory Technology Devices (MTD)"
......@@ -54,8 +54,8 @@ config MTD_REDBOOT_PARTS
depends on MTD_PARTITIONS
---help---
RedBoot is a ROM monitor and bootloader which deals with multiple
'images' in flash devices by putting a table in the last erase
block of the device, similar to a partition table, which gives
'images' in flash devices by putting a table one of the erase
blocks on the device, similar to a partition table, which gives
the offsets, lengths and names of all the images stored in the
flash.
......@@ -68,6 +68,23 @@ config MTD_REDBOOT_PARTS
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
config MTD_REDBOOT_DIRECTORY_BLOCK
int "Location of RedBoot partition table"
depends on MTD_REDBOOT_PARTS
default "-1"
---help---
This option is the Linux counterpart to the
CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time
option.
The option specifies which Flash sectors holds the RedBoot
partition table. A zero or positive value gives an absolete
erase block number. A negative value specifies a number of
sectors before the end of the device.
For example "2" means block number 2, "-1" means the last
block and "-2" means the penultimate block.
config MTD_REDBOOT_PARTS_UNALLOCATED
bool " Include unallocated flash regions"
depends on MTD_REDBOOT_PARTS
......
# drivers/mtd/chips/Kconfig
# $Id: Kconfig,v 1.9 2004/07/16 15:32:14 dwmw2 Exp $
# $Id: Kconfig,v 1.11 2004/11/29 22:40:44 dwmw2 Exp $
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
......@@ -7,6 +7,7 @@ menu "RAM/ROM/Flash chip drivers"
config MTD_CFI
tristate "Detect flash chips by Common Flash Interface (CFI) probe"
depends on MTD
select MTD_GEN_PROBE
help
The Common Flash Interface specification was developed by Intel,
AMD and other flash manufactures that provides a universal method
......@@ -18,6 +19,7 @@ config MTD_CFI
config MTD_JEDECPROBE
tristate "Detect non-CFI AMD/JEDEC-compatible flash chips"
depends on MTD
select MTD_GEN_PROBE
help
This option enables JEDEC-style probing of flash chips which are not
compatible with the Common Flash Interface, but will use the common
......@@ -29,8 +31,6 @@ config MTD_JEDECPROBE
config MTD_GEN_PROBE
tristate
default m if MTD_CFI!=y && !MTD_INTELPROBE && MTD_JEDECPROBE!=y && (MTD_CFI=m || MTD_JEDECPROBE=m)
default y if MTD_CFI=y || MTD_INTELPROBE || MTD_JEDECPROBE=y
config MTD_CFI_ADV_OPTIONS
bool "Flash chip driver advanced configuration options"
......@@ -158,6 +158,7 @@ config MTD_CFI_I8
config MTD_CFI_INTELEXT
tristate "Support for Intel/Sharp flash chips"
depends on MTD_GEN_PROBE
select MTD_CFI_UTIL
help
The Common Flash Interface defines a number of different command
sets which a CFI-compliant chip may claim to implement. This code
......@@ -167,6 +168,7 @@ config MTD_CFI_INTELEXT
config MTD_CFI_AMDSTD
tristate "Support for AMD/Fujitsu flash chips"
depends on MTD_GEN_PROBE
select MTD_CFI_UTIL
help
The Common Flash Interface defines a number of different command
sets which a CFI-compliant chip may claim to implement. This code
......@@ -197,6 +199,7 @@ config MTD_CFI_AMDSTD_RETRY_MAX
config MTD_CFI_STAA
tristate "Support for ST (Advanced Architecture) flash chips"
depends on MTD_GEN_PROBE
select MTD_CFI_UTIL
help
The Common Flash Interface defines a number of different command
sets which a CFI-compliant chip may claim to implement. This code
......@@ -204,8 +207,6 @@ config MTD_CFI_STAA
config MTD_CFI_UTIL
tristate
default y if MTD_CFI_INTELEXT=y || MTD_CFI_AMDSTD=y || MTD_CFI_STAA=y
default m if MTD_CFI_INTELEXT=m || MTD_CFI_AMDSTD=m || MTD_CFI_STAA=m
config MTD_RAM
tristate "Support for RAM chips in bus mapping"
......@@ -272,5 +273,14 @@ config MTD_JEDEC
<http://www.jedec.org/> distributes the identification codes for the
chips.
config MTD_XIP
bool "XIP aware MTD support"
depends on !SMP && MTD_CFI_INTELEXT && EXPERIMENTAL
default y if XIP_KERNEL
help
This allows MTD support to work with flash memory which is also
used for XIP purposes. If you're not sure what this is all about
then say N.
endmenu
......@@ -3,7 +3,7 @@
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
* $Id: amd_flash.c,v 1.25 2004/08/09 13:19:43 dwmw2 Exp $
* $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
......@@ -1122,7 +1122,7 @@ static inline int erase_one_block(struct map_info *map, struct flchip *chip,
timeo = jiffies + (HZ * 20);
spin_unlock_bh(chip->mutex);
schedule_timeout(HZ);
msleep(1000);
spin_lock_bh(chip->mutex);
while (flash_is_busy(map, adr, private->interleave)) {
......
This diff is collapsed.
......@@ -13,7 +13,7 @@
*
* This code is GPL
*
* $Id: cfi_cmdset_0002.c,v 1.111 2004/11/16 18:29:00 dwmw2 Exp $
* $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $
*
*/
......@@ -707,7 +707,7 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
*/
unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
int ret = 0;
map_word oldd, curd;
map_word oldd;
int retry_cnt = 0;
adr += chip->start;
......@@ -764,23 +764,11 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
continue;
}
/* Test to see if toggling has stopped. */
oldd = map_read(map, adr);
curd = map_read(map, adr);
if (map_word_equal(map, curd, oldd)) {
/* Do we have the correct value? */
if (map_word_equal(map, curd, datum)) {
goto op_done;
}
/* Nope something has gone wrong. */
break;
}
if (chip_ready(map, adr))
goto op_done;
if (time_after(jiffies, timeo)) {
printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
break;
}
if (time_after(jiffies, timeo))
break;
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
......@@ -788,6 +776,8 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
cfi_spin_lock(chip->mutex);
}
printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
/* FIXME - should have reset delay before continuing */
......@@ -1173,8 +1163,7 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
chip->in_progress_block_addr = adr;
cfi_spin_unlock(chip->mutex);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((chip->erase_time*HZ)/(2*1000));
msleep(chip->erase_time/2);
cfi_spin_lock(chip->mutex);
timeo = jiffies + (HZ*20);
......@@ -1259,8 +1248,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
chip->in_progress_block_addr = adr;
cfi_spin_unlock(chip->mutex);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout((chip->erase_time*HZ)/(2*1000));
msleep(chip->erase_time/2);
cfi_spin_lock(chip->mutex);
timeo = jiffies + (HZ*20);
......
......@@ -4,7 +4,7 @@
*
* (C) 2000 Red Hat. GPL'd
*
* $Id: cfi_cmdset_0020.c,v 1.16 2004/11/16 18:29:00 dwmw2 Exp $
* $Id: cfi_cmdset_0020.c,v 1.17 2004/11/20 12:49:04 dwmw2 Exp $
*
* 10/10/2000 Nicolas Pitre <nico@cam.org>
* - completely revamped method functions so they are aware and
......@@ -788,7 +788,7 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
chip->state = FL_ERASING;
spin_unlock_bh(chip->mutex);
schedule_timeout(HZ);
msleep(1000);
spin_lock_bh(chip->mutex);
/* FIXME. Use a timer to check this, and return immediately. */
......@@ -1087,7 +1087,7 @@ static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, un
chip->state = FL_LOCKING;
spin_unlock_bh(chip->mutex);
schedule_timeout(HZ);
msleep(1000);
spin_lock_bh(chip->mutex);
/* FIXME. Use a timer to check this, and return immediately. */
......@@ -1236,7 +1236,7 @@ static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip,
chip->state = FL_UNLOCKING;
spin_unlock_bh(chip->mutex);
schedule_timeout(HZ);
msleep(1000);
spin_lock_bh(chip->mutex);
/* FIXME. Use a timer to check this, and return immediately. */
......
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
$Id: cfi_probe.c,v 1.79 2004/10/20 23:04:01 dwmw2 Exp $
$Id: cfi_probe.c,v 1.83 2004/11/16 18:19:02 nico Exp $
*/
#include <linux/config.h>
......@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/mtd/xip.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/gen_probe.h>
......@@ -31,11 +32,47 @@ static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi);
struct mtd_info *cfi_probe(struct map_info *map);
#ifdef CONFIG_MTD_XIP
/* only needed for short periods, so this is rather simple */
#define xip_disable() local_irq_disable()
#define xip_allowed(base, map) \
do { \
(void) map_read(map, base); \
asm volatile (".rep 8; nop; .endr"); \
local_irq_enable(); \
} while (0)
#define xip_enable(base, map, cfi) \
do { \
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
xip_allowed(base, map); \
} while (0)
#define xip_disable_qry(base, map, cfi) \
do { \
xip_disable(); \
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); \
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); \
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); \
} while (0)
#else
#define xip_disable() do { } while (0)
#define xip_allowed(base, map) do { } while (0)
#define xip_enable(base, map, cfi) do { } while (0)
#define xip_disable_qry(base, map, cfi) do { } while (0)
#endif
/* check for QRY.
in: interleave,type,mode
ret: table index, <0 for error
*/
static int qry_present(struct map_info *map, __u32 base,
static int __xipram qry_present(struct map_info *map, __u32 base,
struct cfi_private *cfi)
{
int osf = cfi->interleave * cfi->device_type; // scale factor
......@@ -59,11 +96,11 @@ static int qry_present(struct map_info *map, __u32 base,
if (!map_word_equal(map, qry[2], val[2]))
return 0;
return 1; // nothing found
return 1; // "QRY" found
}
static int cfi_probe_chip(struct map_info *map, __u32 base,
unsigned long *chip_map, struct cfi_private *cfi)
static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
unsigned long *chip_map, struct cfi_private *cfi)
{
int i;
......@@ -79,12 +116,16 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
(unsigned long)base + 0x55, map->size -1);
return 0;
}
xip_disable();
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
if (!qry_present(map,base,cfi))
if (!qry_present(map,base,cfi)) {
xip_enable(base, map, cfi);
return 0;
}
if (!cfi->numchips) {
/* This is the first time we're called. Set up the CFI
......@@ -110,6 +151,7 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
/* If the QRY marker goes away, it's an alias */
if (!qry_present(map, start, cfi)) {
xip_allowed(base, map);
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
map->name, base, start);
return 0;
......@@ -122,6 +164,7 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
cfi_send_gen_cmd(0xFF, 0, start, map, cfi, cfi->device_type, NULL);
if (qry_present(map, base, cfi)) {
xip_allowed(base, map);
printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n",
map->name, base, start);
return 0;
......@@ -137,6 +180,7 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
xip_allowed(base, map);
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
map->name, cfi->interleave, cfi->device_type*8, base,
......@@ -145,14 +189,15 @@ static int cfi_probe_chip(struct map_info *map, __u32 base,
return 1;
}
static int cfi_chip_setup(struct map_info *map,
struct cfi_private *cfi)
static int __xipram cfi_chip_setup(struct map_info *map,
struct cfi_private *cfi)
{
int ofs_factor = cfi->interleave*cfi->device_type;
__u32 base = 0;
int num_erase_regions = cfi_read_query(map, base + (0x10 + 28)*ofs_factor);
int i;
xip_enable(base, map, cfi);
#ifdef DEBUG_CFI
printk("Number of erase regions: %d\n", num_erase_regions);
#endif
......@@ -170,13 +215,33 @@ static int cfi_chip_setup(struct map_info *map,
cfi->cfi_mode = CFI_MODE_CFI;
/* Read the CFI info structure */
for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++) {
xip_disable_qry(base, map, cfi);
for (i=0; i<(sizeof(struct cfi_ident) + num_erase_regions * 4); i++)
((unsigned char *)cfi->cfiq)[i] = cfi_read_query(map,base + (0x10 + i)*ofs_factor);
}
/* Note we put the device back into Read Mode BEFORE going into Auto
* Select Mode, as some devices support nesting of modes, others
* don't. This way should always work.
* On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
* so should be treated as nops or illegal (and so put the device
* back into Read Mode, which is a nop in this case).
*/
cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
cfi->mfr = cfi_read_query(map, base);
cfi->id = cfi_read_query(map, base + ofs_factor);
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
/* ... even if it's an Intel chip */
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
xip_allowed(base, map);
/* Do any necessary byteswapping */
cfi->cfiq->P_ID = le16_to_cpu(cfi->cfiq->P_ID);
cfi->cfiq->P_ADR = le16_to_cpu(cfi->cfiq->P_ADR);
cfi->cfiq->A_ID = le16_to_cpu(cfi->cfiq->A_ID);
cfi->cfiq->A_ADR = le16_to_cpu(cfi->cfiq->A_ADR);
......@@ -198,25 +263,6 @@ static int cfi_chip_setup(struct map_info *map,
#endif
}
/* Note we put the device back into Read Mode BEFORE going into Auto
* Select Mode, as some devices support nesting of modes, others
* don't. This way should always work.
* On cmdset 0001 the writes of 0xaa and 0x55 are not needed, and
* so should be treated as nops or illegal (and so put the device
* back into Read Mode, which is a nop in this case).
*/
cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL);
cfi->mfr = cfi_read_query(map, base);
cfi->id = cfi_read_query(map, base + ofs_factor);
/* Put it back into Read Mode */
cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL);
/* ... even if it's an Intel chip */
cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL);
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank\n",
map->name, cfi->interleave, cfi->device_type*8, base,
map->bankwidth*8);
......
......@@ -7,7 +7,7 @@
*
* This code is covered by the GPL.
*
* $Id: cfi_util.c,v 1.5 2004/08/12 06:40:23 eric Exp $
* $Id: cfi_util.c,v 1.8 2004/12/14 19:55:56 nico Exp $
*
*/
......@@ -22,13 +22,14 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/mtd/xip.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/compatmac.h>
struct cfi_extquery *
cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
__xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
{
struct cfi_private *cfi = map->fldrv_priv;
__u32 base = 0; // cfi->chips[0].start;
......@@ -40,21 +41,35 @@ cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
if (!adr)
goto out;
/* Switch it into Query Mode */
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
extp = kmalloc(size, GFP_KERNEL);
if (!extp) {
printk(KERN_ERR "Failed to allocate memory\n");
goto out;
}
#ifdef CONFIG_MTD_XIP
local_irq_disable();
#endif
/* Switch it into Query Mode */
cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL);
/* Read in the Extended Query Table */
for (i=0; i<size; i++) {
((unsigned char *)extp)[i] =
cfi_read_query(map, base+((adr+i)*ofs_factor));
}
/* Make sure it returns to read mode */
cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
#ifdef CONFIG_MTD_XIP
(void) map_read(map, base);
asm volatile (".rep 8; nop; .endr");
local_irq_enable();
#endif
if (extp->MajorVersion != '1' ||
(extp->MinorVersion < '0' || extp->MinorVersion > '3')) {
printk(KERN_WARNING " Unknown %s Extended Query "
......@@ -62,15 +77,9 @@ cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* name)
extp->MinorVersion);
kfree(extp);
extp = NULL;
goto out;
}
out:
/* Make sure it's in read mode */
cfi_send_gen_cmd(0xf0, 0, base, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0xff, 0, base, map, cfi, cfi->device_type, NULL);
return extp;
out: return extp;
}
EXPORT_SYMBOL(cfi_read_pri);
......@@ -156,7 +165,6 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
i=first;
while(len) {
unsigned long chipmask;
int size = regions[i].erasesize;
ret = (*frob)(map, &cfi->chips[chipnum], adr, size, thunk);
......@@ -165,10 +173,10 @@ int cfi_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob,
return ret;
adr += size;
ofs += size;
len -= size;
chipmask = (1 << cfi->chipshift) - 1;
if ((adr & chipmask) == ((regions[i].offset + size * regions[i].numblocks) & chipmask))
if (ofs == regions[i].offset + size * regions[i].numblocks)
i++;
if (adr >> cfi->chipshift) {
......
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
$Id: jedec_probe.c,v 1.58 2004/11/16 18:29:00 dwmw2 Exp $
$Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
for the standard this probe goes back to.
......@@ -227,6 +227,11 @@ static const struct unlock_addr unlock_addrs[] = {
[MTD_UADDR_DONT_CARE] = {
.addr1 = 0x0000, /* Doesn't matter which address */
.addr2 = 0x0000 /* is used - must be last entry */
},
[MTD_UADDR_UNNECESSARY] = {
.addr1 = 0x0000,
.addr2 = 0x0000
}
};
......@@ -514,15 +519,20 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x10000,8),
}
}, {
mfr_id: MANUFACTURER_AMD,
dev_id: AM29F002T,
name: "AMD AM29F002T",
DevSize: SIZE_256KiB,
NumEraseRegions: 4,
regions: {ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1)
.mfr_id = MANUFACTURER_AMD,
.dev_id = AM29F002T,
.name = "AMD AM29F002T",
.uaddr = {
[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
},
.DevSize = SIZE_256KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_ATMEL,
......@@ -770,15 +780,20 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x04000,1)
}
}, {
mfr_id: MANUFACTURER_HYUNDAI,
dev_id: HY29F002T,
name: "Hyundai HY29F002T",
DevSize: SIZE_256KiB,
NumEraseRegions: 4,
regions: {ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1)
.mfr_id = MANUFACTURER_HYUNDAI,
.dev_id = HY29F002T,
.name = "Hyundai HY29F002T",
.uaddr = {
[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
},
.DevSize = SIZE_256KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_INTEL,
......@@ -1177,15 +1192,20 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x10000,7),
}
}, {
mfr_id: MANUFACTURER_MACRONIX,
dev_id: MX29F002T,
name: "Macronix MX29F002T",
DevSize: SIZE_256KiB,
NumEraseRegions: 4,
regions: {ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1)
.mfr_id = MANUFACTURER_MACRONIX,
.dev_id = MX29F002T,
.name = "Macronix MX29F002T",
.uaddr = {
[0] = MTD_UADDR_0x0555_0x02AA /* x8 */
},
.DevSize = SIZE_256KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 4,
.regions = {
ERASEINFO(0x10000,3),
ERASEINFO(0x08000,1),
ERASEINFO(0x02000,2),
ERASEINFO(0x04000,1),
}
}, {
.mfr_id = MANUFACTURER_PMC,
......@@ -1780,7 +1800,6 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
return 0;
}
/* Mask out address bits which are smaller than the device type */
p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1;
p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2;
......@@ -1923,7 +1942,6 @@ static int jedec_probe_chip(struct map_info *map, __u32 base,
if (MTD_UADDR_UNNECESSARY == uaddr_idx)
return 0;
/* Mask out address bits which are smaller than the device type */
cfi->addr_unlock1 = unlock_addrs[uaddr_idx].addr1;
cfi->addr_unlock2 = unlock_addrs[uaddr_idx].addr2;
}
......
/*
* $Id: cmdlinepart.c,v 1.16 2004/11/16 18:28:59 dwmw2 Exp $
* $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
*
* Read flash partition table from command line
*
......@@ -338,8 +338,10 @@ static int parse_cmdline_partitions(struct mtd_info *master,
* This is the handler for our kernel parameter, called from
* main.c::checksetup(). Note that we can not yet kmalloc() anything,
* so we only save the commandline for later processing.
*
* This function needs to be visible for bootloaders.
*/
static int mtdpart_setup(char *s)
int mtdpart_setup(char *s)
{
cmdline = s;
return 1;
......
# drivers/mtd/maps/Kconfig
# $Id: Kconfig,v 1.13 2004/10/01 21:47:13 gleixner Exp $
# $Id: Kconfig,v 1.14 2004/11/29 22:40:45 dwmw2 Exp $
menu "Self-contained MTD device drivers"
depends on MTD!=n
......@@ -130,6 +130,8 @@ comment "Disk-On-Chip Device Drivers"
config MTD_DOC2000
tristate "M-Systems Disk-On-Chip 2000 and Millennium (DEPRECATED)"
depends on MTD
select MTD_DOCPROBE
select MTD_NAND_IDS
---help---
This provides an MTD device driver for the M-Systems DiskOnChip
2000 and Millennium devices. Originally designed for the DiskOnChip
......@@ -151,6 +153,8 @@ config MTD_DOC2000
config MTD_DOC2001
tristate "M-Systems Disk-On-Chip Millennium-only alternative driver (DEPRECATED)"
depends on MTD
select MTD_DOCPROBE
select MTD_NAND_IDS
---help---
This provides an alternative MTD device driver for the M-Systems
DiskOnChip Millennium devices. Use this if you have problems with
......@@ -171,6 +175,8 @@ config MTD_DOC2001
config MTD_DOC2001PLUS
tristate "M-Systems Disk-On-Chip Millennium Plus"
depends on MTD
select MTD_DOCPROBE
select MTD_NAND_IDS
---help---
This provides an MTD device driver for the M-Systems DiskOnChip
Millennium Plus devices.
......@@ -186,17 +192,10 @@ config MTD_DOC2001PLUS
config MTD_DOCPROBE
tristate
default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MTD_DOC2001PLUS=m)
default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y
help
This isn't a real config option; it's derived.
select MTD_DOCECC
config MTD_DOCECC
tristate
default m if MTD_DOCPROBE=m
default y if MTD_DOCPROBE=y
help
This isn't a real config option; it's derived.
config MTD_DOCPROBE_ADVANCED
bool "Advanced detection options for DiskOnChip"
......
/**
* $Id: phram.c,v 1.10 2004/12/10 17:53:13 joern Exp $
*
* $Id: phram.c,v 1.3 2004/11/16 18:29:01 dwmw2 Exp $
*
* Copyright (c) Jochen Schaeuble <psionic@psionic.de>
* 07/2003 rewritten by Joern Engel <joern@wh.fh-wedel.de>
*
* DISCLAIMER: This driver makes use of Rusty's excellent module code,
* so it will not work for 2.4 without changes and it wont work for 2.4
* as a module without major changes. Oh well!
* Copyright (c) ???? Jochen Schuble <psionic@psionic.de>
* Copyright (c) 2003-2004 Jrn Engel <joern@wh.fh-wedel.de>
*
* Usage:
*
......@@ -15,9 +10,12 @@
* phram=<name>,<start>,<len>
* <name> may be up to 63 characters.
* <start> and <len> can be octal, decimal or hexadecimal. If followed
* by "k", "M" or "G", the numbers will be interpreted as kilo, mega or
* by "ki", "Mi" or "Gi", the numbers will be interpreted as kilo, mega or
* gigabytes.
*
* Example:
* phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
*
*/
#include <asm/io.h>
......@@ -31,8 +29,8 @@
#define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args)
struct phram_mtd_list {
struct mtd_info mtd;
struct list_head list;
struct mtd_info *mtdinfo;
};
static LIST_HEAD(phram_list);
......@@ -112,9 +110,8 @@ static void unregister_devices(void)
struct phram_mtd_list *this;
list_for_each_entry(this, &phram_list, list) {
del_mtd_device(this->mtdinfo);
iounmap(this->mtdinfo->priv);
kfree(this->mtdinfo);
del_mtd_device(&this->mtd);
iounmap(this->mtd.priv);
kfree(this);
}
}
......@@ -128,45 +125,39 @@ static int register_device(char *name, unsigned long start, unsigned long len)
if (!new)
goto out0;
new->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
if (!new->mtdinfo)
goto out1;
memset(new->mtdinfo, 0, sizeof(struct mtd_info));
memset(new, 0, sizeof(*new));
ret = -EIO;
new->mtdinfo->priv = ioremap(start, len);
if (!new->mtdinfo->priv) {
new->mtd.priv = ioremap(start, len);
if (!new->mtd.priv) {
ERROR("ioremap failed\n");
goto out2;
goto out1;
}
new->mtdinfo->name = name;
new->mtdinfo->size = len;
new->mtdinfo->flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
new->mtdinfo->erase = phram_erase;
new->mtdinfo->point = phram_point;
new->mtdinfo->unpoint = phram_unpoint;
new->mtdinfo->read = phram_read;
new->mtdinfo->write = phram_write;
new->mtdinfo->owner = THIS_MODULE;
new->mtdinfo->type = MTD_RAM;
new->mtdinfo->erasesize = 0x0;
new->mtd.name = name;
new->mtd.size = len;
new->mtd.flags = MTD_CAP_RAM | MTD_ERASEABLE | MTD_VOLATILE;
new->mtd.erase = phram_erase;
new->mtd.point = phram_point;
new->mtd.unpoint = phram_unpoint;
new->mtd.read = phram_read;
new->mtd.write = phram_write;
new->mtd.owner = THIS_MODULE;
new->mtd.type = MTD_RAM;
new->mtd.erasesize = 0;
ret = -EAGAIN;
if (add_mtd_device(new->mtdinfo)) {
if (add_mtd_device(&new->mtd)) {
ERROR("Failed to register new device\n");
goto out3;
goto out2;
}
list_add_tail(&new->list, &phram_list);
return 0;
out3:
iounmap(new->mtdinfo->priv);
out2:
kfree(new->mtdinfo);
iounmap(new->mtd.priv);
out1:
kfree(new);
out0:
......@@ -184,7 +175,9 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
result *= 1024;
case 'k':
result *= 1024;
endp++;
/* By dwmw2 editorial decree, "ki", "Mi" or "Gi" are to be used. */
if ((*endp)[1] == 'i')
(*endp) += 2;
}
return result;
}
......@@ -235,7 +228,7 @@ static int phram_setup(const char *val, struct kernel_param *kp)
uint32_t len;
int i, ret;
if (strnlen(val, sizeof(str)) >= sizeof(str))
if (strnlen(val, sizeof(buf)) >= sizeof(buf))
parse_err("parameter too long\n");
strcpy(str, val);
......@@ -271,78 +264,11 @@ static int phram_setup(const char *val, struct kernel_param *kp)
}
module_param_call(phram, phram_setup, NULL, NULL, 000);
MODULE_PARM_DESC(phram, "Memory region to map. \"map=<name>,<start><length>\"");
/*
* Just for compatibility with slram, this is horrible and should go someday.
*/
static int __init slram_setup(const char *val, struct kernel_param *kp)
{
char buf[256], *str = buf;
if (!val || !val[0])
parse_err("no arguments to \"slram=\"\n");
if (strnlen(val, sizeof(str)) >= sizeof(str))
parse_err("parameter too long\n");
strcpy(str, val);
while (str) {
char *token[3];
char *name;
uint32_t start;
uint32_t len;
int i, ret;
for (i=0; i<3; i++) {
token[i] = strsep(&str, ",");
if (token[i])
continue;
parse_err("wrong number of arguments to \"slram=\"\n");
}
/* name */
ret = parse_name(&name, token[0]);
if (ret == -ENOMEM)
parse_err("of memory\n");
if (ret == -ENOSPC)
parse_err("too long\n");
if (ret)
return 1;
/* start */
ret = parse_num32(&start, token[1]);
if (ret)
parse_err("illegal start address\n");
/* len */
if (token[2][0] == '+')
ret = parse_num32(&len, token[2] + 1);
else
ret = parse_num32(&len, token[2]);
if (ret)
parse_err("illegal device length\n");
if (token[2][0] != '+') {
if (len < start)
parse_err("end < start\n");
len -= start;
}
register_device(name, start, len);
}
return 1;
}
module_param_call(slram, slram_setup, NULL, NULL, 000);
MODULE_PARM_DESC(slram, "List of memory regions to map. \"map=<name>,<start><length/end>\"");
MODULE_PARM_DESC(phram,"Memory region to map. \"map=<name>,<start>,<length>\"");
static int __init init_phram(void)
{
printk(KERN_ERR "phram loaded\n");
return 0;
}
......
......@@ -8,7 +8,7 @@
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
* Copyright (C) 2000 Netgem S.A.
*
* $Id: inftlmount.c,v 1.15 2004/11/05 21:55:55 kalev Exp $
* $Id: inftlmount.c,v 1.16 2004/11/22 13:50:53 kalev 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
......@@ -41,7 +41,7 @@
#include <linux/mtd/inftl.h>
#include <linux/mtd/compatmac.h>
char inftlmountrev[]="$Revision: 1.15 $";
char inftlmountrev[]="$Revision: 1.16 $";
/*
* find_boot_record: Find the INFTL Media Header and its Spare copy which
......@@ -389,8 +389,6 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
struct erase_info *instr = &inftl->instr;
int physblock;
instr->mtd = inftl->mbd.mtd;
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=%p,"
"block=%d)\n", inftl, block);
......@@ -400,6 +398,7 @@ int INFTL_formatblock(struct INFTLrecord *inftl, int block)
_first_? */
/* Use async erase interface, test return code */
instr->mtd = inftl->mbd.mtd;
instr->addr = block * inftl->EraseSize;
instr->len = inftl->mbd.mtd->erasesize;
/* Erase one physical eraseblock at a time, even though the NAND api
......
# drivers/mtd/maps/Kconfig
# $Id: Kconfig,v 1.37 2004/10/20 22:57:18 dwmw2 Exp $
# $Id: Kconfig,v 1.40 2004/12/09 20:01:05 holindho Exp $
menu "Mapping drivers for chip access"
depends on MTD!=n
......@@ -373,9 +373,17 @@ config MTD_ARCTIC
Arctic board. If you have one of these boards and would like to
use the flash chips on it, say 'Y'.
config MTD_WALNUT
tristate "Flash device mapped on IBM 405GP Walnut"
depends on MTD_JEDECPROBE && PPC32 && 40x && WALNUT
help
This enables access routines for the flash chips on the IBM 405GP
Walnut board. If you have one of these boards and would like to
use the flash chips on it, say 'Y'.
config MTD_EBONY
tristate "Flash devices mapped on IBM 440GP Ebony"
depends on MTD_CFI && PPC32 && 44x && EBONY
depends on MTD_JEDECPROBE && PPC32 && 44x && EBONY
help
This enables access routines for the flash chips on the IBM 440GP
Ebony board. If you have one of these boards and would like to
......@@ -653,5 +661,11 @@ config MTD_BAST_MAXSIZE
depends on MTD_BAST
default "4"
config MTD_SHARP_SL
bool "ROM maped on Sharp SL Series"
depends on MTD && ARCH_PXA
help
This enables access to the flash chip on the Sharp SL Series of PDAs.
endmenu
#
# linux/drivers/maps/Makefile
#
# $Id: Makefile.common,v 1.19 2004/09/21 14:27:16 bjd Exp $
# $Id: Makefile.common,v 1.21 2004/12/09 20:01:05 holindho Exp $
ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
obj-$(CONFIG_MTD) += map_funcs.o
......@@ -62,6 +62,7 @@ obj-$(CONFIG_MTD_EBONY) += ebony.o
obj-$(CONFIG_MTD_OCOTEA) += ocotea.o
obj-$(CONFIG_MTD_BEECH) += beech-mtd.o
obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o
obj-$(CONFIG_MTD_WALNUT) += walnut.o
obj-$(CONFIG_MTD_H720X) += h720x-flash.o
obj-$(CONFIG_MTD_SBC8240) += sbc8240.o
obj-$(CONFIG_MTD_NOR_TOTO) += omap-toto-flash.o
......@@ -70,3 +71,4 @@ obj-$(CONFIG_MTD_IXP4XX) += ixp4xx.o
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
......@@ -2,7 +2,7 @@
* amd76xrom.c
*
* Normal mappings of chips in physical memory
* $Id: amd76xrom.c,v 1.18 2004/11/16 18:29:02 dwmw2 Exp $
* $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $
*/
#include <linux/module.h>
......
......@@ -14,7 +14,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id: dilnetpc.c,v 1.16 2004/11/04 13:24:14 gleixner Exp $
* $Id: dilnetpc.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $
*
* The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems
* featuring the AMD Elan SC410 processor. There are two variants of this
......
/*
* $Id: ebony.c,v 1.13 2004/11/04 13:24:14 gleixner Exp $
* $Id: ebony.c,v 1.15 2004/12/09 18:39:54 holindho Exp $
*
* Mapping for Ebony user flash
*
......@@ -103,7 +103,7 @@ int __init init_ebony(void)
simple_map_init(&ebony_small_map);
flash = do_map_probe("map_rom", &ebony_small_map);
flash = do_map_probe("jedec_probe", &ebony_small_map);
if (flash) {
flash->owner = THIS_MODULE;
add_mtd_partitions(flash, ebony_small_partitions,
......@@ -124,7 +124,7 @@ int __init init_ebony(void)
simple_map_init(&ebony_large_map);
flash = do_map_probe("cfi_probe", &ebony_large_map);
flash = do_map_probe("jedec_probe", &ebony_large_map);
if (flash) {
flash->owner = THIS_MODULE;
add_mtd_partitions(flash, ebony_large_partitions,
......
......@@ -16,7 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
$Id: elan-104nc.c,v 1.24 2004/11/16 18:29:02 dwmw2 Exp $
$Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $
The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
mode. This drivers uses the CFI probe and Intel Extended Command Set drivers.
......
......@@ -2,7 +2,7 @@
* ichxrom.c
*
* Normal mappings of chips in physical memory
* $Id: ichxrom.c,v 1.15 2004/11/16 18:29:02 dwmw2 Exp $
* $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $
*/
#include <linux/module.h>
......
/*
* $Id: l440gx.c,v 1.16 2004/11/16 18:29:02 dwmw2 Exp $
* $Id: l440gx.c,v 1.17 2004/11/28 09:40:39 dwmw2 Exp $
*
* BIOS Flash chip on Intel 440GX board.
*
......
......@@ -3,7 +3,7 @@
* Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com)
* based on sc520cdp.c by Sysgo Real-Time Solutions GmbH
*
* $Id: netsc520.c,v 1.12 2004/11/04 13:24:15 gleixner Exp $
* $Id: netsc520.c,v 1.13 2004/11/28 09:40:40 dwmw2 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
......
......@@ -6,7 +6,7 @@
* (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com)
* (C) Copyright 2001-2002, SnapGear (www.snapgear.com)
*
* $Id: nettel.c,v 1.8 2004/11/04 13:24:15 gleixner Exp $
* $Id: nettel.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
*/
/****************************************************************************/
......
......@@ -7,7 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* $Id: pci.c,v 1.8 2004/07/12 22:38:29 dwmw2 Exp $
* $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
*
* Generic PCI memory map driver. We support the following boards:
* - Intel IQ80310 ATU.
......
/*
* $Id: physmap.c,v 1.36 2004/11/04 13:24:15 gleixner Exp $
* $Id: physmap.c,v 1.37 2004/11/28 09:40:40 dwmw2 Exp $
*
* Normal mappings of chips in physical memory
*
......
......@@ -17,7 +17,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
$Id: sbc_gxx.c,v 1.32 2004/11/16 18:29:02 dwmw2 Exp $
$Id: sbc_gxx.c,v 1.33 2004/11/28 09:40:40 dwmw2 Exp $
The SBC-MediaGX / SBC-GXx has up to 16 MiB of
Intel StrataFlash (28F320/28F640) in x8 mode.
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
* $Id: sc520cdp.c,v 1.18 2004/11/04 13:24:15 gleixner Exp $
* $Id: sc520cdp.c,v 1.19 2004/11/28 09:40:40 dwmw2 Exp $
*
*
* The SC520CDP is an evaluation board for the Elan SC520 processor available
......
/*
* MTD map driver for BIOS Flash on Intel SCB2 boards
* $Id: scb2_flash.c,v 1.10 2004/11/16 18:29:02 dwmw2 Exp $
* $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $
* Copyright (C) 2002 Sun Microsystems, Inc.
* Tim Hockin <thockin@sun.com>
*
......
......@@ -2,7 +2,7 @@
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
$Id: scx200_docflash.c,v 1.9 2004/11/16 18:29:02 dwmw2 Exp $
$Id: scx200_docflash.c,v 1.10 2004/11/28 09:40:40 dwmw2 Exp $
National Semiconductor SCx200 flash mapped with DOCCS
*/
......
/*
* sharpsl-flash.c
*
* Copyright (C) 2001 Lineo Japan, Inc.
* Copyright (C) 2002 SHARP
*
* $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $
*
* based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp
* Handle mapping of the flash on the RPX Lite and CLLF boards
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#define WINDOW_ADDR 0x00000000
#define WINDOW_SIZE 0x01000000
#define BANK_WIDTH 2
static struct mtd_info *mymtd;
struct map_info sharpsl_map = {
.name = "sharpsl-flash",
.size = WINDOW_SIZE,
.bankwidth = BANK_WIDTH,
.phys = WINDOW_ADDR
};
static struct mtd_partition sharpsl_partitions[1] = {
{
name: "Filesystem",
size: 0x006d0000,
offset: 0x00120000
}
};
#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
int __init init_sharpsl(void)
{
struct mtd_partition *parts;
int nb_parts = 0;
char *part_type = "static";
printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!sharpsl_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
mymtd = do_map_probe("map_rom", &sharpsl_map);
if (!mymtd) {
iounmap(sharpsl_map.virt);
return -ENXIO;
}
mymtd->owner = THIS_MODULE;
parts = sharpsl_partitions;
nb_parts = NB_OF(sharpsl_partitions);
printk(KERN_NOTICE "Using %s partision definition\n", part_type);
add_mtd_partitions(mymtd, parts, nb_parts);
return 0;
}
static void __exit cleanup_sharpsl(void)
{
if (mymtd) {
del_mtd_partitions(mymtd);
map_destroy(mymtd);
}
if (sharpsl_map.virt) {
iounmap(sharpsl_map.virt);
sharpsl_map.virt = 0;
}
}
module_init(init_sharpsl);
module_exit(cleanup_sharpsl);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SHARP (Original: Arnold Christensen <AKC@pel.dk>)");
MODULE_DESCRIPTION("MTD map driver for SHARP SL series");
......@@ -25,7 +25,7 @@
* - If you have created your own jffs file system and the bios overwrites
* it during boot, try disabling Drive A: and B: in the boot order.
*
* $Id: ts5500_flash.c,v 1.1 2004/09/20 15:33:26 sean Exp $
* $Id: ts5500_flash.c,v 1.2 2004/11/28 09:40:40 dwmw2 Exp $
*/
#include <linux/config.h>
......
/*
* $Id: walnut.c,v 1.2 2004/12/10 12:07:42 holindho Exp $
*
* Mapping for Walnut flash
* (used ebony.c as a "framework")
*
* Heikki Lindholm <holindho@infradead.org>
*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/config.h>
#include <linux/version.h>
#include <asm/io.h>
#include <asm/ibm4xx.h>
#include <platforms/4xx/walnut.h>
/* these should be in platforms/4xx/walnut.h ? */
#define WALNUT_FLASH_ONBD_N(x) (x & 0x02)
#define WALNUT_FLASH_SRAM_SEL(x) (x & 0x01)
#define WALNUT_FLASH_LOW 0xFFF00000
#define WALNUT_FLASH_HIGH 0xFFF80000
#define WALNUT_FLASH_SIZE 0x80000
static struct mtd_info *flash;
static struct map_info walnut_map = {
.name = "Walnut flash",
.size = WALNUT_FLASH_SIZE,
.bankwidth = 1,
};
/* Actually, OpenBIOS is the last 128 KiB of the flash - better
* partitioning could be made */
static struct mtd_partition walnut_partitions[] = {
{
.name = "OpenBIOS",
.offset = 0x0,
.size = WALNUT_FLASH_SIZE,
/*.mask_flags = MTD_WRITEABLE, */ /* force read-only */
}
};
int __init init_walnut(void)
{
u8 fpga_brds1;
void *fpga_brds1_adr;
void *fpga_status_adr;
unsigned long flash_base;
/* this should already be mapped (platform/4xx/walnut.c) */
fpga_status_adr = ioremap(WALNUT_FPGA_BASE, 8);
if (!fpga_status_adr)
return -ENOMEM;
fpga_brds1_adr = fpga_status_adr+5;
fpga_brds1 = readb(fpga_brds1_adr);
/* iounmap(fpga_status_adr); */
if (WALNUT_FLASH_ONBD_N(fpga_brds1)) {
printk("The on-board flash is disabled (U79 sw 5)!");
return -EIO;
}
if (WALNUT_FLASH_SRAM_SEL(fpga_brds1))
flash_base = WALNUT_FLASH_LOW;
else
flash_base = WALNUT_FLASH_HIGH;
walnut_map.phys = flash_base;
walnut_map.virt =
(void __iomem *)ioremap(flash_base, walnut_map.size);
if (!walnut_map.virt) {
printk("Failed to ioremap flash.\n");
return -EIO;
}
simple_map_init(&walnut_map);
flash = do_map_probe("jedec_probe", &walnut_map);
if (flash) {
flash->owner = THIS_MODULE;
add_mtd_partitions(flash, walnut_partitions,
ARRAY_SIZE(walnut_partitions));
} else {
printk("map probe failed for flash\n");
return -ENXIO;
}
return 0;
}
static void __exit cleanup_walnut(void)
{
if (flash) {
del_mtd_partitions(flash);
map_destroy(flash);
}
if (walnut_map.virt) {
iounmap((void *)walnut_map.virt);
walnut_map.virt = 0;
}
}
module_init(init_walnut);
module_exit(cleanup_walnut);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Heikki Lindholm <holindho@infradead.org>");
MODULE_DESCRIPTION("MTD map and partitions for IBM 405GP Walnut boards");
/*
* Direct MTD block device access
*
* $Id: mtdblock.c,v 1.65 2004/11/16 18:28:59 dwmw2 Exp $
* $Id: mtdblock.c,v 1.66 2004/11/25 13:52:52 joern Exp $
*
* (C) 2000-2003 Nicolas Pitre <nico@cam.org>
* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org>
......@@ -248,7 +248,7 @@ static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
unsigned long block, char *buf)
{
struct mtdblk_dev *mtdblk = mtdblks[dev->devnum];
if (unlikely(!mtdblk->cache_data)) {
if (unlikely(!mtdblk->cache_data && mtdblk->cache_size)) {
mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);
if (!mtdblk->cache_data)
return -EINTR;
......
# drivers/mtd/nand/Kconfig
# $Id: Kconfig,v 1.22 2004/10/05 22:11:46 gleixner Exp $
# $Id: Kconfig,v 1.25 2004/11/29 22:40:45 dwmw2 Exp $
menu "NAND Flash Device Drivers"
depends on MTD!=n
......@@ -7,6 +7,7 @@ menu "NAND Flash Device Drivers"
config MTD_NAND
tristate "NAND Device Support"
depends on MTD
select MTD_NAND_IDS
help
This enables support for accessing all type of NAND flash
devices. For further information see
......@@ -56,8 +57,6 @@ config MTD_NAND_TOTO
config MTD_NAND_IDS
tristate
default y if MTD_NAND = y || MTD_DOC2000 = y || MTD_DOC2001 = y || MTD_DOC2001PLUS = y
default m if MTD_NAND = m || MTD_DOC2000 = m || MTD_DOC2001 = m || MTD_DOC2001PLUS = m
config MTD_NAND_TX4925NDFMC
tristate "SmartMedia Card on Toshiba RBTX4925 reference board"
......@@ -192,4 +191,17 @@ config MTD_NAND_DISKONCHIP_BBTWRITE
Even if you leave this disabled, you can enable BBT writes at module
load time (assuming you build diskonchip as a module) with the module
parameter "inftl_bbt_write=1".
config MTD_NAND_SHARPSL
bool "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on MTD_NAND && ARCH_PXA
config MTD_NAND_NANDSIM
bool "Support for NAND Flash Simulator"
depends on MTD_NAND
help
The simulator may simulate verious NAND flash chips for the
MTD nand layer.
endmenu
#
# linux/drivers/nand/Makefile
#
# $Id: Makefile.common,v 1.13 2004/09/28 22:04:23 bjd Exp $
# $Id: Makefile.common,v 1.15 2004/11/26 12:28:22 dedekind Exp $
obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
......@@ -18,5 +18,7 @@ obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o
obj-$(CONFIG_MTD_NAND_H1900) += h1910.o
obj-$(CONFIG_MTD_NAND_RTC_FROM4) += rtc_from4.o
obj-$(CONFIG_MTD_NAND_SHARPSL) += sharpsl.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
nand-objs = nand_base.o nand_bbt.o
......@@ -41,7 +41,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.121 2004/10/06 19:53:11 gleixner Exp $
* $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen 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
......@@ -810,7 +810,7 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
u_char *oob_buf, struct nand_oobinfo *oobsel, int cached)
{
int i, status;
u_char ecc_code[8];
u_char ecc_code[32];
int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
int *oob_config = oobsel->eccpos;
int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
......@@ -840,18 +840,8 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
}
this->write_buf(mtd, this->data_poi, mtd->oobblock);
break;
/* Hardware ecc 8 byte / 512 byte data */
case NAND_ECC_HW8_512:
eccbytes += 2;
/* Hardware ecc 6 byte / 512 byte data */
case NAND_ECC_HW6_512:
eccbytes += 3;
/* Hardware ecc 3 byte / 256 data */
/* Hardware ecc 3 byte / 512 byte data */
case NAND_ECC_HW3_256:
case NAND_ECC_HW3_512:
eccbytes += 3;
default:
eccbytes = this->eccbytes;
for (; eccsteps; eccsteps--) {
/* enable hardware ecc logic for write */
this->enable_hwecc(mtd, NAND_ECC_WRITE);
......@@ -864,14 +854,9 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
* the data bytes (words) */
if (this->options & NAND_HWECC_SYNDROME)
this->write_buf(mtd, ecc_code, eccbytes);
datidx += this->eccsize;
}
break;
default:
printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
BUG();
}
/* Write out OOB data */
......@@ -1051,7 +1036,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
int eccmode, eccsteps;
int *oob_config, datidx;
int blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
int eccbytes = 3;
int eccbytes;
int compareecc = 1;
int oobreadlen;
......@@ -1092,19 +1077,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
end = mtd->oobblock;
ecc = this->eccsize;
switch (eccmode) {
case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data */
eccbytes = 6;
break;
case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data */
eccbytes = 8;
break;
case NAND_ECC_NONE:
compareecc = 0;
break;
}
if (this->options & NAND_HWECC_SYNDROME)
eccbytes = this->eccbytes;
if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
compareecc = 0;
oobreadlen = mtd->oobsize;
......@@ -1164,13 +1139,10 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc)
this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
break;
case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data */
case NAND_ECC_HW3_512: /* Hardware ECC 3 byte /512 byte data */
case NAND_ECC_HW6_512: /* Hardware ECC 6 byte / 512 byte data */
case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data */
default:
for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {
this->enable_hwecc(mtd, NAND_ECC_READ);
this->enable_hwecc(mtd, NAND_ECC_READ);
this->read_buf(mtd, &data_poi[datidx], ecc);
/* HW ecc with syndrome calculation must read the
......@@ -1193,10 +1165,6 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
}
break;
default:
printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
BUG();
}
/* read oobdata */
......@@ -2433,8 +2401,19 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
* fallback to software ECC
*/
this->eccsize = 256; /* set default eccsize */
this->eccbytes = 3;
switch (this->eccmode) {
case NAND_ECC_HW12_2048:
if (mtd->oobblock < 2048) {
printk(KERN_WARNING "2048 byte HW ECC not possible on %d byte page size, fallback to SW ECC\n",
mtd->oobblock);
this->eccmode = NAND_ECC_SOFT;
this->calculate_ecc = nand_calculate_ecc;
this->correct_data = nand_correct_data;
} else
this->eccsize = 2048;
break;
case NAND_ECC_HW3_512:
case NAND_ECC_HW6_512:
......@@ -2444,16 +2423,13 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
this->eccmode = NAND_ECC_SOFT;
this->calculate_ecc = nand_calculate_ecc;
this->correct_data = nand_correct_data;
break;
} else
this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
this->eccsize = 512; /* set eccsize to 512 */
break;
case NAND_ECC_HW3_256:
if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
break;
printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
BUG();
break;
case NAND_ECC_NONE:
printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n");
this->eccmode = NAND_ECC_NONE;
......@@ -2468,11 +2444,32 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode);
BUG();
}
/* Check hardware ecc function availability and adjust number of ecc bytes per
* calculation step
*/
switch (this->eccmode) {
case NAND_ECC_HW12_2048:
this->eccbytes += 4;
case NAND_ECC_HW8_512:
this->eccbytes += 2;
case NAND_ECC_HW6_512:
this->eccbytes += 3;
case NAND_ECC_HW3_512:
case NAND_ECC_HW3_256:
if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
break;
printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
BUG();
}
mtd->eccsize = this->eccsize;
/* Set the number of read / write steps for one page to ensure ECC generation */
switch (this->eccmode) {
case NAND_ECC_HW12_2048:
this->eccsteps = mtd->oobblock / 2048;
break;
case NAND_ECC_HW3_512:
case NAND_ECC_HW6_512:
case NAND_ECC_HW8_512:
......
......@@ -6,7 +6,7 @@
*
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
*
* $Id: nand_bbt.c,v 1.26 2004/10/05 13:50:20 gleixner Exp $
* $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 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
......@@ -1001,25 +1001,27 @@ int nand_default_bbt (struct mtd_info *mtd)
return nand_scan_bbt (mtd, &agand_flashbased);
}
/* Is a flash based bad block table requested ? */
if (this->options & NAND_USE_FLASH_BBT) {
/* Use the default pattern descriptors */
if (!this->bbt_td) {
this->bbt_td = &bbt_main_descr;
this->bbt_md = &bbt_mirror_descr;
}
if (mtd->oobblock > 512)
return nand_scan_bbt (mtd, &largepage_flashbased);
else
return nand_scan_bbt (mtd, &smallpage_flashbased);
}
if (!this->badblock_pattern) {
this->badblock_pattern = (mtd->oobblock > 512) ?
&largepage_flashbased : &smallpage_flashbased;
}
} else {
this->bbt_td = NULL;
this->bbt_md = NULL;
if (mtd->oobblock > 512)
return nand_scan_bbt (mtd, &largepage_memorybased);
else
return nand_scan_bbt (mtd, &smallpage_memorybased);
if (!this->badblock_pattern) {
this->badblock_pattern = (mtd->oobblock > 512) ?
&largepage_memorybased : &smallpage_memorybased;
}
}
return nand_scan_bbt (mtd, this->badblock_pattern);
}
/**
......
This diff is collapsed.
......@@ -11,7 +11,7 @@
* 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
* 12-Oct-2004 BJD Fixed errors in use of platform data
*
* $Id: s3c2410.c,v 1.5 2004/10/12 10:10:15 bjd Exp $
* $Id: s3c2410.c,v 1.6 2004/11/24 12:25:48 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
......@@ -167,7 +167,7 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
if (plat != NULL) {
tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8);
twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
twrph1 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
} else {
/* default timings */
tacls = 8;
......
/*
* drivers/mtd/nand/sharpsl.c
*
* Copyright (C) 2004 Richard Purdie
*
* $Id: sharpsl.c,v 1.2 2004/11/24 20:38:07 rpurdie Exp $
*
* Based on Sharp's NAND driver sharp_sl.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/genhd.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/partitions.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/hardware.h>
static void __iomem *sharpsl_io_base;
static int sharpsl_phys_base = 0x0C000000;
/* register offset */
#define ECCLPLB sharpsl_io_base+0x00 /* line parity 7 - 0 bit */
#define ECCLPUB sharpsl_io_base+0x04 /* line parity 15 - 8 bit */
#define ECCCP sharpsl_io_base+0x08 /* column parity 5 - 0 bit */
#define ECCCNTR sharpsl_io_base+0x0C /* ECC byte counter */
#define ECCCLRR sharpsl_io_base+0x10 /* cleare ECC */
#define FLASHIO sharpsl_io_base+0x14 /* Flash I/O */
#define FLASHCTL sharpsl_io_base+0x18 /* Flash Control */
/* Flash control bit */
#define FLRYBY (1 << 5)
#define FLCE1 (1 << 4)
#define FLWP (1 << 3)
#define FLALE (1 << 2)
#define FLCLE (1 << 1)
#define FLCE0 (1 << 0)
/*
* MTD structure for SharpSL
*/
static struct mtd_info *sharpsl_mtd = NULL;
/*
* Define partitions for flash device
*/
#define DEFAULT_NUM_PARTITIONS 3
#if defined CONFIG_MACH_POODLE
#define SHARPSL_ROOTFS_SIZE 22
#define SHARPSL_FLASH_SIZE 64
#elif defined CONFIG_MACH_CORGI
#define SHARPSL_ROOTFS_SIZE 25
#define SHARPSL_FLASH_SIZE 32
#elif defined CONFIG_MACH_SHEPHERD
#define SHARPSL_ROOTFS_SIZE 25
#define SHARPSL_FLASH_SIZE 64
#elif defined CONFIG_MACH_HUSKY
#define SHARPSL_ROOTFS_SIZE 53
#define SHARPSL_FLASH_SIZE 128
#elif defined CONFIG_MACH_TOSA
#define SHARPSL_ROOTFS_SIZE 28
#define SHARPSL_FLASH_SIZE 64
#else
#define SHARPSL_ROOTFS_SIZE 30
#define SHARPSL_FLASH_SIZE 64
#endif
static int nr_partitions;
static struct mtd_partition sharpsl_nand_default_partition_info[] = {
{
.name = "NAND flash partition 0",
.offset = 0,
.size = 7 * 1024 * 1024,
},
{
.name = "NAND flash partition 1",
.offset = 7 * 1024 * 1024,
.size = SHARPSL_ROOTFS_SIZE * 1024 * 1024,
},
{
.name = "NAND flash partition 2",
.offset = (SHARPSL_ROOTFS_SIZE+7) * 1024 * 1024,
.size = (SHARPSL_FLASH_SIZE - SHARPSL_ROOTFS_SIZE - 7) * 1024 * 1024,
},
};
/*
* hardware specific access to control-lines
*/
static void
sharpsl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
{
switch (cmd) {
case NAND_CTL_SETCLE:
writeb(readb(FLASHCTL) | FLCLE, FLASHCTL);
break;
case NAND_CTL_CLRCLE:
writeb(readb(FLASHCTL) & ~FLCLE, FLASHCTL);
break;
case NAND_CTL_SETALE:
writeb(readb(FLASHCTL) | FLALE, FLASHCTL);
break;
case NAND_CTL_CLRALE:
writeb(readb(FLASHCTL) & ~FLALE, FLASHCTL);
break;
case NAND_CTL_SETNCE:
writeb(readb(FLASHCTL) & ~(FLCE0|FLCE1), FLASHCTL);
break;
case NAND_CTL_CLRNCE:
writeb(readb(FLASHCTL) | (FLCE0|FLCE1), FLASHCTL);
break;
}
}
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
static struct nand_bbt_descr sharpsl_bbt = {
.options = 0,
.offs = 4,
.len = 2,
.pattern = scan_ff_pattern
};
static int
sharpsl_nand_dev_ready(struct mtd_info* mtd)
{
return !((readb(FLASHCTL) & FLRYBY) == 0);
}
static void
sharpsl_nand_enable_hwecc(struct mtd_info* mtd, int mode)
{
writeb(0 ,ECCCLRR);
}
static int
sharpsl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat,
u_char* ecc_code)
{
ecc_code[0] = ~readb(ECCLPUB);
ecc_code[1] = ~readb(ECCLPLB);
ecc_code[2] = (~readb(ECCCP) << 2) | 0x03;
return readb(ECCCNTR) != 0;
}
#ifdef CONFIG_MTD_PARTITIONS
const char *part_probes[] = { "cmdlinepart", NULL };
#endif
/*
* Main initialization routine
*/
int __init
sharpsl_nand_init(void)
{
struct nand_chip *this;
struct mtd_partition* sharpsl_partition_info;
int err = 0;
/* Allocate memory for MTD device structure and private data */
sharpsl_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
GFP_KERNEL);
if (!sharpsl_mtd) {
printk ("Unable to allocate SharpSL NAND MTD device structure.\n");
return -ENOMEM;
}
/* map physical adress */
sharpsl_io_base = ioremap(sharpsl_phys_base, 0x1000);
if(!sharpsl_io_base){
printk("ioremap to access Sharp SL NAND chip failed\n");
kfree(sharpsl_mtd);
return -EIO;
}
/* Get pointer to private data */
this = (struct nand_chip *) (&sharpsl_mtd[1]);
/* Initialize structures */
memset((char *) sharpsl_mtd, 0, sizeof(struct mtd_info));
memset((char *) this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
sharpsl_mtd->priv = this;
/*
* PXA initialize
*/
writeb(readb(FLASHCTL) | FLWP, FLASHCTL);
/* Set address of NAND IO lines */
this->IO_ADDR_R = FLASHIO;
this->IO_ADDR_W = FLASHIO;
/* Set address of hardware control function */
this->hwcontrol = sharpsl_nand_hwcontrol;
this->dev_ready = sharpsl_nand_dev_ready;
/* 15 us command delay time */
this->chip_delay = 15;
/* set eccmode using hardware ECC */
this->eccmode = NAND_ECC_HW3_256;
this->enable_hwecc = sharpsl_nand_enable_hwecc;
this->calculate_ecc = sharpsl_nand_calculate_ecc;
this->correct_data = nand_correct_data;
this->badblock_pattern = &sharpsl_bbt;
/* Scan to find existence of the device */
err=nand_scan(sharpsl_mtd,1);
if (err) {
iounmap(sharpsl_io_base);
kfree(sharpsl_mtd);
return err;
}
/* Register the partitions */
sharpsl_mtd->name = "sharpsl-nand";
nr_partitions = parse_mtd_partitions(sharpsl_mtd, part_probes,
&sharpsl_partition_info, 0);
if (nr_partitions <= 0) {
nr_partitions = DEFAULT_NUM_PARTITIONS;
sharpsl_partition_info = sharpsl_nand_default_partition_info;
}
#ifdef CONFIG_MACH_HUSKY
/* Need to use small eraseblock size for backward compatibility */
sharpsl_mtd->flags |= MTD_NO_VIRTBLOCKS;
#endif
add_mtd_partitions(sharpsl_mtd, sharpsl_partition_info, nr_partitions);
/* Return happy */
return 0;
}
module_init(sharpsl_nand_init);
/*
* Clean up routine
*/
#ifdef MODULE
static void __exit sharpsl_nand_cleanup(void)
{
struct nand_chip *this = (struct nand_chip *) &sharpsl_mtd[1];
/* Release resources, unregister device */
nand_release(sharpsl_mtd);
iounmap(sharpsl_io_base);
/* Free the MTD device structure */
kfree(sharpsl_mtd);
}
module_exit(sharpsl_nand_cleanup);
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");
......@@ -4,7 +4,7 @@
* Author: Fabrice Bellard (fabrice.bellard@netgem.com)
* Copyright (C) 2000 Netgem S.A.
*
* $Id: nftlmount.c,v 1.39 2004/11/05 22:51:41 kalev Exp $
* $Id: nftlmount.c,v 1.40 2004/11/22 14:38:29 kalev 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
......@@ -31,7 +31,7 @@
#define SECTORSIZE 512
char nftlmountrev[]="$Revision: 1.39 $";
char nftlmountrev[]="$Revision: 1.40 $";
/* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the
* various device information of the NFTL partition and Bad Unit Table. Update
......@@ -302,8 +302,6 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
struct nftl_uci1 uci;
struct erase_info *instr = &nftl->instr;
instr->mtd = nftl->mbd.mtd;
/* Read the Unit Control Information #1 for Wear-Leveling */
if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8,
8, &retlen, (char *)&uci) < 0)
......@@ -320,6 +318,7 @@ int NFTL_formatblock(struct NFTLrecord *nftl, int block)
memset(instr, 0, sizeof(struct erase_info));
/* XXX: use async erase interface, XXX: test return code */
instr->mtd = nftl->mbd.mtd;
instr->addr = block * nftl->EraseSize;
instr->len = nftl->EraseSize;
MTD_ERASE(nftl->mbd.mtd, instr);
......
/*
* $Id: redboot.c,v 1.15 2004/08/10 07:55:16 dwmw2 Exp $
* $Id: redboot.c,v 1.17 2004/11/22 11:33:56 ijc Exp $
*
* Parse RedBoot-style Flash Image System (FIS) tables and
* produce a Linux partition array to match.
......@@ -30,6 +30,9 @@ struct fis_list {
struct fis_list *next;
};
static int directory = CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK;
module_param(directory, int, 0);
static inline int redboot_checksum(struct fis_image_desc *img)
{
/* RedBoot doesn't actually write the desc_cksum field yet AFAICT */
......@@ -50,6 +53,8 @@ static int parse_redboot_partitions(struct mtd_info *master,
char *nullname;
int namelen = 0;
int nulllen = 0;
int numslots;
unsigned long offset;
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
static char nullstring[] = "unallocated";
#endif
......@@ -59,8 +64,15 @@ static int parse_redboot_partitions(struct mtd_info *master,
if (!buf)
return -ENOMEM;
/* Read the start of the last erase block */
ret = master->read(master, master->size - master->erasesize,
if ( directory < 0 )
offset = master->size + directory*master->erasesize;
else
offset = directory*master->erasesize;
printk(KERN_NOTICE "Searching for RedBoot partition table in %s at offset 0x%lx\n",
master->name, offset);
ret = master->read(master, offset,
master->erasesize, &retlen, (void *)buf);
if (ret)
......@@ -71,12 +83,16 @@ static int parse_redboot_partitions(struct mtd_info *master,
goto out;
}
/* RedBoot image could appear in any of the first three slots */
for (i = 0; i < 3; i++) {
if (!memcmp(buf[i].name, "RedBoot", 8))
numslots = (master->erasesize / sizeof(struct fis_image_desc));
for (i = 0; i < numslots; i++) {
if (buf[i].name[0] == 0xff) {
i = numslots;
break;
}
if (!memcmp(buf[i].name, "FIS directory", 14))
break;
}
if (i == 3) {
if (i == numslots) {
/* Didn't find it */
printk(KERN_NOTICE "No RedBoot partition table detected in %s\n",
master->name);
......@@ -84,7 +100,7 @@ static int parse_redboot_partitions(struct mtd_info *master,
goto out;
}
for (i = 0; i < master->erasesize / sizeof(struct fis_image_desc); i++) {
for (i = 0; i < numslots; i++) {
struct fis_list *new_fl, **prev;
if (buf[i].name[0] == 0xff)
......
......@@ -1179,6 +1179,15 @@ config JFFS2_FS_NAND
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_COMPRESSION_OPTIONS
bool "Advanced compression options for JFFS2"
depends on JFFS2_FS
......
#
# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
#
# $Id: Makefile.common,v 1.6 2004/07/16 15:17:57 dwmw2 Exp $
# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $
#
obj-$(CONFIG_JFFS2_FS) += jffs2.o
......@@ -12,6 +12,7 @@ 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_RUBIN) += compr_rubin.o
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
$Id: README.Locking,v 1.4 2002/03/08 16:20:06 dwmw2 Exp $
$Id: README.Locking,v 1.9 2004/11/20 10:35:40 dwmw2 Exp $
JFFS2 LOCKING DOCUMENTATION
---------------------------
......@@ -80,10 +80,10 @@ per-eraseblock lists of physical jffs2_raw_node_ref structures, and
(NB) the per-inode list of physical nodes. The latter is a special
case - see below.
As the MTD API permits erase-completion callback functions to be
called from bottom-half (timer) context, and these functions access
the data structures protected by this lock, it must be locked with
spin_lock_bh().
As the MTD API no longer permits erase-completion callback functions
to be called from bottom-half (timer) context (on the basis that nobody
ever actually implemented such a thing), it's now sufficient to use
a simple spin_lock() rather than spin_lock_bh().
Note that the per-inode list of physical nodes (f->nodes) is a special
case. Any changes to _valid_ nodes (i.e. ->flash_offset & 1 == 0) in
......@@ -99,8 +99,27 @@ pointer when the garbage collection thread exits. The code to kill the
GC thread locks it, sends the signal, then unlocks it - while the GC
thread itself locks it, zeroes c->gc_task, then unlocks on the exit path.
node_free_sem
-------------
inocache_lock spinlock
----------------------
This spinlock protects the hashed list (c->inocache_list) of the
in-core jffs2_inode_cache objects (each inode in JFFS2 has the
correspondent jffs2_inode_cache object). So, the inocache_lock
has to be locked while walking the c->inocache_list hash buckets.
Note, the f->sem guarantees that the correspondent jffs2_inode_cache
will not be removed. So, it is allowed to access it without locking
the inocache_lock spinlock.
Ordering constraints:
If both erase_completion_lock and inocache_lock are needed, the
c->erase_completion has to be acquired first.
erase_free_sem
--------------
This semaphore is only used by the erase code which frees obsolete
node references and the jffs2_garbage_collect_deletion_dirent()
......@@ -114,3 +133,16 @@ the jffs2_raw_node_ref structures in question while the garbage
collection code is looking at them.
Suggestions for alternative solutions to this problem would be welcomed.
wbuf_sem
--------
This read/write semaphore protects against concurrent access to the
write-behind buffer ('wbuf') used for flash chips where we must write
in blocks. It protects both the contents of the wbuf and the metadata
which indicates which flash region (if any) is currently covered by
the buffer.
Ordering constraints:
Lock wbuf_sem last, after the alloc_sem or and f->sem.
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: background.c,v 1.49 2004/07/13 08:56:40 dwmw2 Exp $
* $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $
*
*/
......
......@@ -3,17 +3,19 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: build.c,v 1.55 2003/10/28 17:02:44 dwmw2 Exp $
* $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $
*
*/
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mtd/mtd.h>
#include "nodelist.h"
static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *, struct jffs2_full_dirent **);
......@@ -62,6 +64,7 @@ static inline void jffs2_build_inode_pass1(struct jffs2_sb_info *c, struct jffs2
if (!child_ic) {
printk(KERN_NOTICE "Eep. Child \"%s\" (ino #%u) of dir ino #%u doesn't exist!\n",
fd->name, fd->ino, ic->ino);
jffs2_mark_node_obsolete(c, fd->raw);
continue;
}
......@@ -88,6 +91,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
int ret;
int i;
struct jffs2_inode_cache *ic;
struct jffs2_full_dirent *fd;
struct jffs2_full_dirent *dead_fds = NULL;
/* First, scan the medium and build all the inode caches with
......@@ -95,13 +99,11 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
c->flags |= JFFS2_SB_FLAG_MOUNTING;
ret = jffs2_scan_medium(c);
c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
if (ret)
return ret;
goto exit;
D1(printk(KERN_DEBUG "Scanned flash completely\n"));
D1(jffs2_dump_block_lists(c));
D2(jffs2_dump_block_lists(c));
/* Now scan the directory tree, increasing nlink according to every dirent found. */
for_each_inode(i, c, ic) {
......@@ -114,6 +116,8 @@ 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"));
/* Next, scan for inodes with nlink == 0 and remove them. If
......@@ -135,9 +139,7 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
D1(printk(KERN_DEBUG "Pass 2a starting\n"));
while (dead_fds) {
struct jffs2_inode_cache *ic;
struct jffs2_full_dirent *fd = dead_fds;
fd = dead_fds;
dead_fds = fd->next;
ic = jffs2_get_ino_cache(c, fd->ino);
......@@ -152,7 +154,6 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
/* Finally, we can scan again and free the dirent structs */
for_each_inode(i, c, ic) {
struct jffs2_full_dirent *fd;
D1(printk(KERN_DEBUG "Pass 3: ino #%u, ic %p, nodes %p\n", ic->ino, ic, ic->nodes));
while(ic->scan_dents) {
......@@ -164,11 +165,24 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
cond_resched();
}
D1(printk(KERN_DEBUG "Pass 3 complete\n"));
D1(jffs2_dump_block_lists(c));
D2(jffs2_dump_block_lists(c));
/* Rotate the lists by some number to ensure wear levelling */
jffs2_rotate_lists(c);
ret = 0;
exit:
if (ret) {
for_each_inode(i, c, ic) {
while(ic->scan_dents) {
fd = ic->scan_dents;
ic->scan_dents = fd->next;
jffs2_free_full_dirent(fd);
}
}
}
return ret;
}
......@@ -179,9 +193,12 @@ static void jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *c, struct jf
D1(printk(KERN_DEBUG "JFFS2: Removing ino #%u with nlink == zero.\n", ic->ino));
for (raw = ic->nodes; raw != (void *)ic; raw = raw->next_in_ino) {
raw = ic->nodes;
while (raw != (void *)ic) {
struct jffs2_raw_node_ref *next = raw->next_in_ino;
D1(printk(KERN_DEBUG "obsoleting node at 0x%08x\n", ref_offset(raw)));
jffs2_mark_node_obsolete(c, raw);
raw = next;
}
if (ic->scan_dents) {
......@@ -297,7 +314,10 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
c->free_size = c->flash_size;
c->nr_blocks = c->flash_size / c->sector_size;
c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
c->blocks = vmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks);
else
c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
if (!c->blocks)
return -ENOMEM;
for (i=0; i<c->nr_blocks; i++) {
......@@ -310,6 +330,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
c->blocks[i].used_size = 0;
c->blocks[i].first_node = NULL;
c->blocks[i].last_node = NULL;
c->blocks[i].bad_count = 0;
}
init_MUTEX(&c->alloc_sem);
......@@ -336,7 +357,11 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c)
D1(printk(KERN_DEBUG "build_fs failed\n"));
jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c);
kfree(c->blocks);
if (c->mtd->flags & MTD_NO_VIRTBLOCKS) {
vfree(c->blocks);
} else {
kfree(c->blocks);
}
return -EIO;
}
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: compr_zlib.c,v 1.28 2004/06/23 16:34:40 havasi Exp $
* $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $
*
*/
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: dir.c,v 1.83 2004/10/19 07:48:44 havasi Exp $
* $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $
*
*/
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: erase.c,v 1.61 2004/10/20 23:59:49 dwmw2 Exp $
* $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $
*
*/
......@@ -43,6 +43,7 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
jffs2_erase_succeeded(c, jeb);
return;
}
bad_offset = jeb->offset;
#else /* Linux */
struct erase_info *instr;
......@@ -386,6 +387,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
jeb->dirty_size = 0;
jeb->wasted_size = 0;
} else {
struct kvec vecs[1];
struct jffs2_unknown_node marker = {
.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),
......@@ -394,8 +396,10 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
/* We only write the header; the rest was noise or padding anyway */
ret = jffs2_flash_write(c, jeb->offset, sizeof(marker), &retlen, (char *)&marker);
vecs[0].iov_base = (unsigned char *) &marker;
vecs[0].iov_len = sizeof(marker);
ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen);
if (ret) {
printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
jeb->offset, ret);
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: file.c,v 1.98 2004/03/19 16:41:09 dwmw2 Exp $
* $Id: file.c,v 1.99 2004/11/16 20:36:11 dwmw2 Exp $
*
*/
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: fs.c,v 1.46 2004/07/13 08:56:54 dwmw2 Exp $
* $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $
*
*/
......@@ -20,6 +20,7 @@
#include <linux/mtd/mtd.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/vfs.h>
#include <linux/crc32.h>
#include "nodelist.h"
......@@ -202,7 +203,7 @@ int jffs2_statfs(struct super_block *sb, struct kstatfs *buf)
buf->f_bavail = buf->f_bfree = avail >> PAGE_SHIFT;
D1(jffs2_dump_block_lists(c));
D2(jffs2_dump_block_lists(c));
spin_unlock(&c->erase_completion_lock);
......@@ -463,11 +464,13 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
*/
c->sector_size = c->mtd->erasesize;
blocks = c->flash_size / c->sector_size;
while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
blocks >>= 1;
c->sector_size <<= 1;
}
if (!(c->mtd->flags & MTD_NO_VIRTBLOCKS)) {
while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
blocks >>= 1;
c->sector_size <<= 1;
}
}
/*
* Size alignment check
*/
......@@ -533,7 +536,10 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
out_nodes:
jffs2_free_ino_caches(c);
jffs2_free_raw_node_refs(c);
kfree(c->blocks);
if (c->mtd->flags & MTD_NO_VIRTBLOCKS)
vfree(c->blocks);
else
kfree(c->blocks);
out_inohash:
kfree(c->inocache_list);
out_wbuf:
......@@ -649,6 +655,11 @@ int jffs2_flash_setup(struct jffs2_sb_info *c) {
}
/* add setups for other bizarre flashes here... */
if (jffs2_nor_ecc(c)) {
ret = jffs2_nor_ecc_flash_setup(c);
if (ret)
return ret;
}
return ret;
}
......@@ -659,4 +670,7 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
}
/* add cleanups for other bizarre flashes here... */
if (jffs2_nor_ecc(c)) {
jffs2_nor_ecc_flash_cleanup(c);
}
}
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: gc.c,v 1.140 2004/11/13 10:59:22 dedekind Exp $
* $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $
*
*/
......@@ -103,7 +103,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
ret->wasted_size = 0;
}
D1(jffs2_dump_block_lists(c));
D2(jffs2_dump_block_lists(c));
return ret;
}
......@@ -134,7 +134,7 @@ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c)
if (c->checked_ino > c->highest_ino) {
printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n",
c->unchecked_size);
D1(jffs2_dump_block_lists(c));
D2(jffs2_dump_block_lists(c));
spin_unlock(&c->erase_completion_lock);
BUG();
}
......@@ -602,7 +602,7 @@ static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c,
printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset);
jffs2_free_raw_node_ref(nraw);
}
if (!retried && (nraw == jffs2_alloc_raw_node_ref())) {
if (!retried && (nraw = jffs2_alloc_raw_node_ref())) {
/* Try to reallocate space and retry */
uint32_t dummy;
struct jffs2_eraseblock *jeb = &c->blocks[phys_ofs / c->sector_size];
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: ioctl.c,v 1.8 2003/10/28 16:16:28 dwmw2 Exp $
* $Id: ioctl.c,v 1.9 2004/11/16 20:36:11 dwmw2 Exp $
*
*/
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: malloc.c,v 1.27 2003/10/28 17:14:58 dwmw2 Exp $
* $Id: malloc.c,v 1.28 2004/11/16 20:36:11 dwmw2 Exp $
*
*/
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: nodelist.c,v 1.87 2004/11/14 17:07:07 dedekind Exp $
* $Id: nodelist.c,v 1.90 2004/12/08 17:59:20 dwmw2 Exp $
*
*/
......@@ -92,6 +92,17 @@ static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
}
}
/* Returns first valid node after 'ref'. May return 'ref' */
static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_ref *ref)
{
while (ref && ref->next_in_ino) {
if (!ref_obsolete(ref))
return ref;
D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
ref = ref->next_in_ino;
}
return NULL;
}
/* Get tmp_dnode_info and full_dirent for all non-obsolete nodes associated
with this ino, returning the former in order of version */
......@@ -101,7 +112,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
uint32_t *highest_version, uint32_t *latest_mctime,
uint32_t *mctime_ver)
{
struct jffs2_raw_node_ref *ref = f->inocache->nodes;
struct jffs2_raw_node_ref *ref, *valid_ref;
struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
struct jffs2_full_dirent *fd, *ret_fd = NULL;
union jffs2_node_union node;
......@@ -111,22 +122,23 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
*mctime_ver = 0;
D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%u\n", f->inocache->ino));
if (!f->inocache->nodes) {
printk(KERN_WARNING "Eep. no nodes for ino #%u\n", f->inocache->ino);
}
spin_lock(&c->erase_completion_lock);
for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) {
/* Work out whether it's a data node or a dirent node */
if (ref_obsolete(ref)) {
/* FIXME: On NAND flash we may need to read these */
D1(printk(KERN_DEBUG "node at 0x%08x is obsoleted. Ignoring.\n", ref_offset(ref)));
continue;
}
valid_ref = jffs2_first_valid_node(f->inocache->nodes);
if (!valid_ref)
printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
while (valid_ref) {
/* We can hold a pointer to a non-obsolete node without the spinlock,
but _obsolete_ nodes may disappear at any time, if the block
they're in gets erased */
they're in gets erased. So if we mark 'ref' obsolete while we're
not holding the lock, it can go away immediately. For that reason,
we find the next valid node first, before processing 'ref'.
*/
ref = valid_ref;
valid_ref = jffs2_first_valid_node(ref->next_in_ino);
spin_unlock(&c->erase_completion_lock);
cond_resched();
......@@ -182,7 +194,6 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
err = -ENOMEM;
goto free_out;
}
memset(fd,0,sizeof(struct jffs2_full_dirent) + node.d.nsize+1);
fd->raw = ref;
fd->version = je32_to_cpu(node.d.version);
fd->ino = je32_to_cpu(node.d.ino);
......@@ -220,6 +231,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
}
fd->nhash = full_name_hash(fd->name, node.d.nsize);
fd->next = NULL;
fd->name[node.d.nsize] = '\0';
/* Wheee. We now have a complete jffs2_full_dirent structure, with
the name in it and everything. Link it into the list
*/
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: nodelist.h,v 1.121 2004/11/14 17:07:07 dedekind Exp $
* $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $
*
*/
......@@ -107,16 +107,6 @@ struct jffs2_raw_node_ref
#define ref_obsolete(ref) (((ref)->flash_offset & 3) == REF_OBSOLETE)
#define mark_ref_normal(ref) do { (ref)->flash_offset = ref_offset(ref) | REF_NORMAL; } while(0)
/*
Used for keeping track of deletion nodes &c, which can only be marked
as obsolete when the node which they mark as deleted has actually been
removed from the flash.
*/
struct jffs2_raw_node_ref_list {
struct jffs2_raw_node_ref *rew;
struct jffs2_raw_node_ref_list *next;
};
/* For each inode in the filesystem, we need to keep a record of
nlink, because it would be a PITA to scan the whole directory tree
at read_inode() time to calculate it, and to keep sufficient information
......@@ -148,13 +138,6 @@ struct jffs2_inode_cache {
#define INOCACHE_HASHSIZE 128
struct jffs2_scan_info {
struct jffs2_full_dirent *dents;
struct jffs2_tmp_dnode_info *tmpnodes;
/* Latest i_size info */
uint32_t version;
uint32_t isize;
};
/*
Larger representation of a raw node, kept in-core only when the
struct inode for this particular ino is instantiated.
......@@ -163,12 +146,11 @@ struct jffs2_scan_info {
struct jffs2_full_dnode
{
struct jffs2_raw_node_ref *raw;
uint32_t ofs; /* Don't really need this, but optimisation */
uint32_t ofs; /* The offset to which the data of this node belongs */
uint32_t size;
uint32_t frags; /* Number of fragments which currently refer
to this node. When this reaches zero,
the node is obsolete.
*/
the node is obsolete. */
};
/*
......@@ -193,6 +175,7 @@ struct jffs2_full_dirent
unsigned char type;
unsigned char name[0];
};
/*
Fragments - used to build a map of which raw node to obtain
data from for each part of the ino
......@@ -202,7 +185,7 @@ struct jffs2_node_frag
struct rb_node rb;
struct jffs2_full_dnode *node; /* NULL for holes */
uint32_t size;
uint32_t ofs; /* Don't really need this, but optimisation */
uint32_t ofs; /* The offset to which this fragment belongs */
};
struct jffs2_eraseblock
......@@ -221,14 +204,6 @@ struct jffs2_eraseblock
struct jffs2_raw_node_ref *last_node;
struct jffs2_raw_node_ref *gc_node; /* Next node to be garbage collected */
/* For deletia. When a dirent node in this eraseblock is
deleted by a node elsewhere, that other node can only
be marked as obsolete when this block is actually erased.
So we keep a list of the nodes to mark as obsolete when
the erase is completed.
*/
// MAYBE struct jffs2_raw_node_ref_list *deletia;
};
#define ACCT_SANITY_CHECK(c, jeb) do { \
......@@ -396,7 +371,7 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
#define frag_erase(frag, list) rb_erase(&frag->rb, list);
/* nodelist.c */
D1(void jffs2_print_frag_list(struct jffs2_inode_info *f));
D2(void jffs2_print_frag_list(struct jffs2_inode_info *f));
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
......
This diff is collapsed.
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2002-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: os-linux.h,v 1.47 2004/07/14 13:20:23 dwmw2 Exp $
* $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $
*
*/
......@@ -99,7 +99,7 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
#ifndef CONFIG_JFFS2_FS_NAND
#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
#define jffs2_can_mark_obsolete(c) (1)
#define jffs2_cleanmarker_oob(c) (0)
#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
......@@ -115,10 +115,13 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#define jffs2_flash_writev(a,b,c,d,e,f) jffs2_flash_direct_writev(a,b,c,d,e)
#define jffs2_wbuf_timeout NULL
#define jffs2_wbuf_process NULL
#define jffs2_nor_ecc(c) (0)
#define jffs2_nor_ecc_flash_setup(c) (0)
#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
#else /* NAND support present */
#else /* NAND and/or ECC'd NOR support present */
#define jffs2_can_mark_obsolete(c) (c->mtd->type == MTD_NORFLASH || c->mtd->type == MTD_RAM)
#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)
#define jffs2_flash_write_oob(c, ofs, len, retlen, buf) ((c)->mtd->write_oob((c)->mtd, ofs, len, retlen, buf))
......@@ -135,8 +138,19 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc
int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset);
void jffs2_wbuf_timeout(unsigned long data);
void jffs2_wbuf_process(void *data);
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 */
#endif /* NAND */
/* erase.c */
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: pushpull.h,v 1.9 2003/10/04 08:33:06 dwmw2 Exp $
* $Id: pushpull.h,v 1.10 2004/11/16 20:36:11 dwmw2 Exp $
*
*/
......
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: read.c,v 1.36 2004/05/25 11:12:32 havasi Exp $
* $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $
*
*/
......@@ -174,7 +174,7 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
if (frag) {
D1(printk(KERN_NOTICE "Eep. Hole in ino #%u fraglist. frag->ofs = 0x%08x, offset = 0x%08x\n", f->inocache->ino, frag->ofs, offset));
holesize = min(holesize, frag->ofs - offset);
D1(jffs2_print_frag_list(f));
D2(jffs2_print_frag_list(f));
}
D1(printk(KERN_DEBUG "Filling non-frag hole from %d-%d\n", offset, offset+holesize));
memset(buf, 0, holesize);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -3,11 +3,11 @@
*
* Copyright (C) 2001, 2002 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@redhat.com>
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* $Id: symlink.c,v 1.13 2004/07/13 08:59:04 dwmw2 Exp $
* $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $
*
*/
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
* Derived from the taskqueue/keventd code by:
*
* David Woodhouse <dwmw2@redhat.com>
* David Woodhouse <dwmw2@infradead.org>
* Andrew Morton <andrewm@uow.edu.au>
* Kai Petzke <wpp@marie.physik.tu-berlin.de>
* Theodore Ts'o <tytso@mit.edu>
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment