提交 ebcccd14 编写于 作者: L Linus Torvalds

Merge git://git.infradead.org/mtd-2.6

* git://git.infradead.org/mtd-2.6: (84 commits)
  [JFFS2] debug.h: include <linux/sched.h> for current->pid
  [MTD] OneNAND: Handle DDP chip boundary during read-while-load
  [MTD] OneNAND: return ecc error code only when 2-bit ecc occurs
  [MTD] OneNAND: Implement read-while-load
  [MTD] OneNAND: fix onenand_wait bug in read ecc error
  [MTD] OneNAND: release CPU in cycles
  [MTD] OneNAND: add subpage write support
  [MTD] OneNAND: fix onenand_wait bug
  [JFFS2] use the ref_offset macro
  [JFFS2] Reschedule in loops
  [JFFS2] Fix error-path leak in summary scan
  [JFFS2] add cond_resched() when garbage collecting deletion dirent
  [MTD] Nuke IVR leftovers
  [MTD] OneNAND: fix oob handling in recent oob patch
  [MTD] Fix ssfdc blksize typo
  [JFFS2] replace kmalloc+memset with kzalloc
  [MTD] Fix SSFDC build for variable blocksize.
  [MTD] ESB2ROM uses PCI
  [MTD] of_device-based physmap driver
  [MTD] Support combined RedBoot FIS directory and configuration area
  ...
......@@ -358,13 +358,12 @@ ev64360_setup_mtd(void)
ptbl_entries = 3;
if ((ptbl = kmalloc(ptbl_entries * sizeof(struct mtd_partition),
if ((ptbl = kzalloc(ptbl_entries * sizeof(struct mtd_partition),
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING "Can't alloc MTD partition table\n");
return -ENOMEM;
}
memset(ptbl, 0, ptbl_entries * sizeof(struct mtd_partition));
ptbl[0].name = "reserved";
ptbl[0].offset = 0;
......
......@@ -164,9 +164,15 @@ config MTD_CHAR
memory chips, and also use ioctl() to obtain information about
the device, or to erase parts of it.
config MTD_BLKDEVS
tristate "Common interface to block layer for MTD 'translation layers'"
depends on MTD && BLOCK
default n
config MTD_BLOCK
tristate "Caching block device access to MTD devices"
depends on MTD && BLOCK
select MTD_BLKDEVS
---help---
Although most flash chips have an erase size too large to be useful
as block devices, it is possible to use MTD devices which are based
......@@ -189,6 +195,7 @@ config MTD_BLOCK
config MTD_BLOCK_RO
tristate "Readonly block device access to MTD devices"
depends on MTD_BLOCK!=y && MTD && BLOCK
select MTD_BLKDEVS
help
This allows you to mount read-only file systems (such as cramfs)
from an MTD device, without the overhead (and danger) of the caching
......@@ -200,6 +207,7 @@ config MTD_BLOCK_RO
config FTL
tristate "FTL (Flash Translation Layer) support"
depends on MTD && BLOCK
select MTD_BLKDEVS
---help---
This provides support for the original Flash Translation Layer which
is part of the PCMCIA specification. It uses a kind of pseudo-
......@@ -216,6 +224,7 @@ config FTL
config NFTL
tristate "NFTL (NAND Flash Translation Layer) support"
depends on MTD && BLOCK
select MTD_BLKDEVS
---help---
This provides support for the NAND Flash Translation Layer which is
used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
......@@ -239,6 +248,7 @@ config NFTL_RW
config INFTL
tristate "INFTL (Inverse NAND Flash Translation Layer) support"
depends on MTD && BLOCK
select MTD_BLKDEVS
---help---
This provides support for the Inverse NAND Flash Translation
Layer which is used on M-Systems' newer DiskOnChip devices. It
......@@ -256,6 +266,7 @@ config INFTL
config RFD_FTL
tristate "Resident Flash Disk (Flash Translation Layer) support"
depends on MTD && BLOCK
select MTD_BLKDEVS
---help---
This provides support for the flash translation layer known
as the Resident Flash Disk (RFD), as used by the Embedded BIOS
......@@ -265,8 +276,8 @@ config RFD_FTL
config SSFDC
tristate "NAND SSFDC (SmartMedia) read only translation layer"
depends on MTD
default n
depends on MTD && BLOCK
select MTD_BLKDEVS
help
This enables read only access to SmartMedia formatted NAND
flash. You can mount it with FAT file system.
......
......@@ -15,13 +15,14 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o
obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs.o
obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o
obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o
obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o
obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o
obj-$(CONFIG_RFD_FTL) += rfd_ftl.o mtd_blkdevs.o
obj-$(CONFIG_SSFDC) += ssfdc.o mtd_blkdevs.o
obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o
obj-$(CONFIG_FTL) += ftl.o
obj-$(CONFIG_NFTL) += nftl.o
obj-$(CONFIG_INFTL) += inftl.o
obj-$(CONFIG_RFD_FTL) += rfd_ftl.o
obj-$(CONFIG_SSFDC) += ssfdc.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o
......
......@@ -207,11 +207,10 @@ static int parse_afs_partitions(struct mtd_info *mtd,
if (!sz)
return ret;
parts = kmalloc(sz, GFP_KERNEL);
parts = kzalloc(sz, GFP_KERNEL);
if (!parts)
return -ENOMEM;
memset(parts, 0, sz);
str = (char *)(parts + idx);
/*
......
......@@ -643,13 +643,12 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
int reg_idx;
int offset;
mtd = (struct mtd_info*)kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
printk(KERN_WARNING
"%s: kmalloc failed for info structure\n", map->name);
return NULL;
}
memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
memset(&temp, 0, sizeof(temp));
......
......@@ -337,12 +337,11 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
struct mtd_info *mtd;
int i;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
printk(KERN_ERR "Failed to allocate memory for MTD device\n");
return NULL;
}
memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
mtd->type = MTD_NORFLASH;
......@@ -2224,6 +2223,8 @@ static int cfi_intelext_suspend(struct mtd_info *mtd)
case FL_CFI_QUERY:
case FL_JEDEC_QUERY:
if (chip->oldstate == FL_READY) {
/* place the chip in a known state before suspend */
map_write(map, CMD(0xFF), cfi->chips[i].start);
chip->oldstate = chip->state;
chip->state = FL_PM_SUSPENDED;
/* No need to wake_up() on this state change -
......
......@@ -48,6 +48,7 @@
#define MANUFACTURER_ATMEL 0x001F
#define MANUFACTURER_SST 0x00BF
#define SST49LF004B 0x0060
#define SST49LF040B 0x0050
#define SST49LF008A 0x005a
#define AT49BV6416 0x00d6
......@@ -233,6 +234,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
};
static struct cfi_fixup jedec_fixup_table[] = {
{ MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
{ MANUFACTURER_SST, SST49LF040B, fixup_use_fwh_lock, NULL, },
{ MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
{ 0, 0, NULL, NULL }
};
......@@ -255,12 +257,11 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
struct mtd_info *mtd;
int i;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
return NULL;
}
memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
mtd->type = MTD_NORFLASH;
......@@ -519,10 +520,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
if (mode == FL_WRITING) /* FIXME: Erase-suspend-program appears broken. */
goto sleep;
if (!(mode == FL_READY || mode == FL_POINT
if (!( mode == FL_READY
|| mode == FL_POINT
|| !cfip
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x1))))
|| (mode == FL_WRITING && (cfip->EraseSuspend & 0x1)
)))
goto sleep;
/* We could check to see if we're trying to access the sector
......
......@@ -172,7 +172,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
int i,j;
unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
//printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
if (!mtd) {
......@@ -181,7 +181,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
return NULL;
}
memset(mtd, 0, sizeof(*mtd));
mtd->priv = map;
mtd->type = MTD_NORFLASH;
mtd->size = devsize * cfi->numchips;
......
......@@ -40,7 +40,7 @@ struct mtd_info *mtd_do_chip_probe(struct map_info *map, struct chip_probe *cp)
if (mtd) {
if (mtd->size > map->size) {
printk(KERN_WARNING "Reducing visibility of %ldKiB chip to %ldKiB\n",
(unsigned long)mtd->size >> 10,
(unsigned long)mtd->size >> 10,
(unsigned long)map->size >> 10);
mtd->size = map->size;
}
......@@ -113,13 +113,12 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
}
mapsize = (max_chips + BITS_PER_LONG-1) / BITS_PER_LONG;
chip_map = kmalloc(mapsize, GFP_KERNEL);
chip_map = kzalloc(mapsize, GFP_KERNEL);
if (!chip_map) {
printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
kfree(cfi.cfiq);
return NULL;
}
memset (chip_map, 0, mapsize);
set_bit(0, chip_map); /* Mark first chip valid */
......
......@@ -116,11 +116,10 @@ static struct mtd_info *jedec_probe(struct map_info *map)
char Part[200];
memset(&priv,0,sizeof(priv));
MTD = kmalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
MTD = kzalloc(sizeof(struct mtd_info) + sizeof(struct jedec_private), GFP_KERNEL);
if (!MTD)
return NULL;
memset(MTD, 0, sizeof(struct mtd_info) + sizeof(struct jedec_private));
priv = (struct jedec_private *)&MTD[1];
my_bank_size = map->size;
......
......@@ -154,6 +154,7 @@
#define SST39SF010A 0x00B5
#define SST39SF020A 0x00B6
#define SST49LF004B 0x0060
#define SST49LF040B 0x0050
#define SST49LF008A 0x005a
#define SST49LF030A 0x001C
#define SST49LF040A 0x0051
......@@ -1400,6 +1401,20 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x01000,64),
}
}, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST49LF040B,
.name = "SST 49LF040B",
.uaddr = {
[0] = MTD_UADDR_0x5555_0x2AAA /* x8 */
},
.DevSize = SIZE_512KiB,
.CmdSet = P_ID_AMD_STD,
.NumEraseRegions= 1,
.regions = {
ERASEINFO(0x01000,128),
}
}, {
.mfr_id = MANUFACTURER_SST,
.dev_id = SST49LF004B,
.name = "SST 49LF004B",
......@@ -1874,7 +1889,7 @@ static int cfi_jedec_setup(struct cfi_private *p_cfi, int index)
/*
* There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing
* There is a BIG problem properly ID'ing the JEDEC device and guaranteeing
* the mapped address, unlock addresses, and proper chip ID. This function
* attempts to minimize errors. It is doubtfull that this probe will ever
* be perfect - consequently there should be some module parameters that
......
......@@ -47,13 +47,11 @@ static struct mtd_info *map_absent_probe(struct map_info *map)
{
struct mtd_info *mtd;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd) {
return NULL;
}
memset(mtd, 0, sizeof(*mtd));
map->fldrv = &map_absent_chipdrv;
mtd->priv = map;
mtd->name = map->name;
......
......@@ -55,12 +55,10 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
#endif
/* OK. It seems to be RAM. */
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd)
return NULL;
memset(mtd, 0, sizeof(*mtd));
map->fldrv = &mapram_chipdrv;
mtd->priv = map;
mtd->name = map->name;
......
......@@ -31,12 +31,10 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
{
struct mtd_info *mtd;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd)
return NULL;
memset(mtd, 0, sizeof(*mtd));
map->fldrv = &maprom_chipdrv;
mtd->priv = map;
mtd->name = map->name;
......
......@@ -112,18 +112,16 @@ static struct mtd_info *sharp_probe(struct map_info *map)
struct sharp_info *sharp = NULL;
int width;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if(!mtd)
return NULL;
sharp = kmalloc(sizeof(*sharp), GFP_KERNEL);
sharp = kzalloc(sizeof(*sharp), GFP_KERNEL);
if(!sharp) {
kfree(mtd);
return NULL;
}
memset(mtd, 0, sizeof(*mtd));
width = sharp_probe_map(map,mtd);
if(!width){
kfree(mtd);
......@@ -143,7 +141,6 @@ static struct mtd_info *sharp_probe(struct map_info *map)
mtd->writesize = 1;
mtd->name = map->name;
memset(sharp, 0, sizeof(*sharp));
sharp->chipshift = 23;
sharp->numchips = 1;
sharp->chips[0].start = 0;
......
......@@ -163,13 +163,12 @@ static struct mtd_partition * newpart(char *s,
*num_parts = this_part + 1;
alloc_size = *num_parts * sizeof(struct mtd_partition) +
extra_mem_size;
parts = kmalloc(alloc_size, GFP_KERNEL);
parts = kzalloc(alloc_size, GFP_KERNEL);
if (!parts)
{
printk(KERN_ERR ERRP "out of memory\n");
return NULL;
}
memset(parts, 0, alloc_size);
extra_mem = (unsigned char *)(parts + *num_parts);
}
/* enter this partition (offset will be calculated later if it is zero at this point) */
......@@ -346,7 +345,7 @@ static int parse_cmdline_partitions(struct mtd_info *master,
*
* This function needs to be visible for bootloaders.
*/
int mtdpart_setup(char *s)
static int mtdpart_setup(char *s)
{
cmdline = s;
return 1;
......
......@@ -295,10 +295,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
if (!devname)
return NULL;
dev = kmalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
if (!dev)
return NULL;
memset(dev, 0, sizeof(*dev));
/* Get a handle on the device */
bdev = open_bdev_excl(devname, O_RDWR, NULL);
......
......@@ -131,11 +131,10 @@ static int __init ms02nv_init_one(ulong addr)
int ret = -ENODEV;
/* The module decodes 8MiB of address space. */
mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL);
mod_res = kzalloc(sizeof(*mod_res), GFP_KERNEL);
if (!mod_res)
return -ENOMEM;
memset(mod_res, 0, sizeof(*mod_res));
mod_res->name = ms02nv_name;
mod_res->start = addr;
mod_res->end = addr + MS02NV_SLOT_SIZE - 1;
......@@ -153,24 +152,21 @@ static int __init ms02nv_init_one(ulong addr)
}
ret = -ENOMEM;
mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
if (!mtd)
goto err_out_mod_res_rel;
memset(mtd, 0, sizeof(*mtd));
mp = kmalloc(sizeof(*mp), GFP_KERNEL);
mp = kzalloc(sizeof(*mp), GFP_KERNEL);
if (!mp)
goto err_out_mtd;
memset(mp, 0, sizeof(*mp));
mtd->priv = mp;
mp->resource.module = mod_res;
/* Firmware's diagnostic NVRAM area. */
diag_res = kmalloc(sizeof(*diag_res), GFP_KERNEL);
diag_res = kzalloc(sizeof(*diag_res), GFP_KERNEL);
if (!diag_res)
goto err_out_mp;
memset(diag_res, 0, sizeof(*diag_res));
diag_res->name = ms02nv_res_diag_ram;
diag_res->start = addr;
diag_res->end = addr + MS02NV_RAM - 1;
......@@ -180,11 +176,10 @@ static int __init ms02nv_init_one(ulong addr)
mp->resource.diag_ram = diag_res;
/* User-available general-purpose NVRAM area. */
user_res = kmalloc(sizeof(*user_res), GFP_KERNEL);
user_res = kzalloc(sizeof(*user_res), GFP_KERNEL);
if (!user_res)
goto err_out_diag_res;
memset(user_res, 0, sizeof(*user_res));
user_res->name = ms02nv_res_user_ram;
user_res->start = addr + MS02NV_RAM;
user_res->end = addr + size - 1;
......@@ -194,11 +189,10 @@ static int __init ms02nv_init_one(ulong addr)
mp->resource.user_ram = user_res;
/* Control and status register. */
csr_res = kmalloc(sizeof(*csr_res), GFP_KERNEL);
csr_res = kzalloc(sizeof(*csr_res), GFP_KERNEL);
if (!csr_res)
goto err_out_user_res;
memset(csr_res, 0, sizeof(*csr_res));
csr_res->name = ms02nv_res_csr;
csr_res->start = addr + MS02NV_CSR;
csr_res->end = addr + MS02NV_CSR + 3;
......
......@@ -480,7 +480,7 @@ add_dataflash(struct spi_device *spi, char *name,
device->writesize = pagesize;
device->owner = THIS_MODULE;
device->type = MTD_DATAFLASH;
device->flags = MTD_CAP_NORFLASH;
device->flags = MTD_WRITEABLE;
device->erase = dataflash_erase;
device->read = dataflash_read;
device->write = dataflash_write;
......
......@@ -126,12 +126,10 @@ static int register_device(char *name, unsigned long start, unsigned long len)
struct phram_mtd_list *new;
int ret = -ENOMEM;
new = kmalloc(sizeof(*new), GFP_KERNEL);
new = kzalloc(sizeof(*new), GFP_KERNEL);
if (!new)
goto out0;
memset(new, 0, sizeof(*new));
ret = -EIO;
new->mtd.priv = ioremap(start, len);
if (!new->mtd.priv) {
......
......@@ -168,19 +168,16 @@ static int register_device(char *name, unsigned long start, unsigned long length
E("slram: Cannot allocate new MTD device.\n");
return(-ENOMEM);
}
(*curmtd)->mtdinfo = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
(*curmtd)->mtdinfo = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
(*curmtd)->next = NULL;
if ((*curmtd)->mtdinfo) {
memset((char *)(*curmtd)->mtdinfo, 0, sizeof(struct mtd_info));
(*curmtd)->mtdinfo->priv =
kmalloc(sizeof(slram_priv_t), GFP_KERNEL);
kzalloc(sizeof(slram_priv_t), GFP_KERNEL);
if (!(*curmtd)->mtdinfo->priv) {
kfree((*curmtd)->mtdinfo);
(*curmtd)->mtdinfo = NULL;
} else {
memset((*curmtd)->mtdinfo->priv,0,sizeof(slram_priv_t));
}
}
......
......@@ -1033,7 +1033,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
partition_t *partition;
partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
partition = kzalloc(sizeof(partition_t), GFP_KERNEL);
if (!partition) {
printk(KERN_WARNING "No memory to scan for FTL on %s\n",
......@@ -1041,8 +1041,6 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
return;
}
memset(partition, 0, sizeof(partition_t));
partition->mbd.mtd = mtd;
if ((scan_header(partition) == 0) &&
......@@ -1054,7 +1052,7 @@ static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
le32_to_cpu(partition->header.FormattedSize) >> 10);
#endif
partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9;
partition->mbd.blksize = SECTOR_SIZE;
partition->mbd.tr = tr;
partition->mbd.devnum = -1;
if (!add_mtd_blktrans_dev((void *)partition))
......@@ -1076,6 +1074,7 @@ struct mtd_blktrans_ops ftl_tr = {
.name = "ftl",
.major = FTL_MAJOR,
.part_bits = PART_BITS,
.blksize = SECTOR_SIZE,
.readsect = ftl_readsect,
.writesect = ftl_writesect,
.getgeo = ftl_getgeo,
......
......@@ -67,17 +67,16 @@ static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name);
inftl = kmalloc(sizeof(*inftl), GFP_KERNEL);
inftl = kzalloc(sizeof(*inftl), GFP_KERNEL);
if (!inftl) {
printk(KERN_WARNING "INFTL: Out of memory for data structures\n");
return;
}
memset(inftl, 0, sizeof(*inftl));
inftl->mbd.mtd = mtd;
inftl->mbd.devnum = -1;
inftl->mbd.blksize = 512;
inftl->mbd.tr = tr;
if (INFTL_mount(inftl) < 0) {
......@@ -163,10 +162,9 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;
res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
*retlen = ops.oobretlen;
return res;
}
......@@ -184,10 +182,9 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;
res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
*retlen = ops.oobretlen;
return res;
}
......@@ -945,6 +942,7 @@ static struct mtd_blktrans_ops inftl_tr = {
.name = "inftl",
.major = INFTL_MAJOR,
.part_bits = INFTL_PARTN_BITS,
.blksize = 512,
.getgeo = inftl_getgeo,
.readsect = inftl_readblock,
.writesect = inftl_writeblock,
......
......@@ -60,6 +60,15 @@ config MTD_PHYSMAP_BANKWIDTH
Ignore this option if you use run-time physmap configuration
(i.e., run-time calling physmap_configure()).
config MTD_PHYSMAP_OF
tristate "Flash device in physical memory map based on OF descirption"
depends on PPC_OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
help
This provides a 'mapping' driver which allows the NOR Flash and
ROM driver code to communicate with chips which are mapped
physically into the CPU's memory. The mapping description here is
taken from OF device tree.
config MTD_SUN_UFLASH
tristate "Sun Microsystems userflash support"
depends on SPARC && MTD_CFI
......@@ -184,6 +193,24 @@ config MTD_ICHXROM
BE VERY CAREFUL.
config MTD_ESB2ROM
tristate "BIOS flash chip on Intel ESB Controller Hub 2"
depends on X86 && MTD_JEDECPROBE && PCI
help
Support for treating the BIOS flash chip on ESB2 motherboards
as an MTD device - with this you can reprogram your BIOS.
BE VERY CAREFUL.
config MTD_CK804XROM
tristate "BIOS flash chip on Nvidia CK804"
depends on X86 && MTD_JEDECPROBE
help
Support for treating the BIOS flash chip on nvidia motherboards
as an MTD device - with this you can reprogram your BIOS.
BE VERY CAREFUL.
config MTD_SCB2_FLASH
tristate "BIOS flash chip on Intel SCB2 boards"
depends on X86 && MTD_JEDECPROBE
......@@ -355,50 +382,6 @@ config MTD_TQM834x
TQ Components TQM834x boards. If you have one of these boards
and would like to use the flash chips on it, say 'Y'.
config MTD_CSTM_MIPS_IXX
tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board"
depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS
help
This provides a mapping driver for the Integrated Technology
Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR
Reference Board. It provides the necessary addressing, length,
buswidth, vpp code and addition setup of the flash device for
these boards. In addition, this mapping driver can be used for
other boards via setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/
LEN/BUSWIDTH parameters. This mapping will provide one mtd device
using one partition. The start address can be offset from the
beginning of flash and the len can be less than the total flash
device size to allow a window into the flash. Both CFI and JEDEC
probes are called.
config MTD_CSTM_MIPS_IXX_START
hex "Physical start address of flash mapping"
depends on MTD_CSTM_MIPS_IXX
default "0x8000000"
help
This is the physical memory location that the MTD driver will
use for the flash chips on your particular target board.
Refer to the memory map which should hopefully be in the
documentation for your board.
config MTD_CSTM_MIPS_IXX_LEN
hex "Physical length of flash mapping"
depends on MTD_CSTM_MIPS_IXX
default "0x4000000"
help
This is the total length that the MTD driver will use for the
flash chips on your particular board. Refer to the memory
map which should hopefully be in the documentation for your
board.
config MTD_CSTM_MIPS_IXX_BUSWIDTH
int "Bus width in octets"
depends on MTD_CSTM_MIPS_IXX
default "2"
help
This is the total bus width of the mapping of the flash chips
on your particular board.
config MTD_OCELOT
tristate "Momenco Ocelot boot flash device"
depends on MIPS && MOMENCO_OCELOT
......
......@@ -12,12 +12,13 @@ obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
obj-$(CONFIG_MTD_BAST) += bast-flash.o
obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
obj-$(CONFIG_MTD_ESB2ROM) += esb2rom.o
obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
obj-$(CONFIG_MTD_CK804XROM) += ck804xrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o
......@@ -25,6 +26,7 @@ obj-$(CONFIG_MTD_MBX860) += mbx860.o
obj-$(CONFIG_MTD_CEIVA) += ceiva.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PHYSMAP_OF) += physmap_of.o
obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
......
......@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
......@@ -44,6 +45,23 @@ struct amd76xrom_map_info {
char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
};
/* The 2 bits controlling the window size are often set to allow reading
* the BIOS, but too small to allow writing, since the lock registers are
* 4MiB lower in the address space than the data.
*
* This is intended to prevent flashing the bios, perhaps accidentally.
*
* This parameter allows the normal driver to over-ride the BIOS settings.
*
* The bits are 6 and 7. If both bits are set, it is a 5MiB window.
* If only the 7 Bit is set, it is a 4MiB window. Otherwise, a
* 64KiB window.
*
*/
static uint win_size_bits;
module_param(win_size_bits, uint, 0);
MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x43 byte, normally set by BIOS.");
static struct amd76xrom_window amd76xrom_window = {
.maps = LIST_HEAD_INIT(amd76xrom_window.maps),
};
......@@ -95,6 +113,16 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
/* Remember the pci dev I find the window in - already have a ref */
window->pdev = pdev;
/* Enable the selected rom window. This is often incorrectly
* set up by the BIOS, and the 4MiB offset for the lock registers
* requires the full 5MiB of window space.
*
* This 'write, then read' approach leaves the bits for
* other uses of the hardware info.
*/
pci_read_config_byte(pdev, 0x43, &byte);
pci_write_config_byte(pdev, 0x43, byte | win_size_bits );
/* Assume the rom window is properly setup, and find it's size */
pci_read_config_byte(pdev, 0x43, &byte);
if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6))) {
......@@ -129,12 +157,6 @@ static int __devinit amd76xrom_init_one (struct pci_dev *pdev,
(unsigned long long)window->rsrc.end);
}
#if 0
/* Enable the selected rom window */
pci_read_config_byte(pdev, 0x43, &byte);
pci_write_config_byte(pdev, 0x43, byte | rwindow->segen_bits);
#endif
/* Enable writes through the rom window */
pci_read_config_byte(pdev, 0x40, &byte);
......
......@@ -131,7 +131,7 @@ static int bast_flash_probe(struct platform_device *pdev)
info->map.phys = res->start;
info->map.size = res->end - res->start + 1;
info->map.name = pdev->dev.bus_id;
info->map.name = pdev->dev.bus_id;
info->map.bankwidth = 2;
if (info->map.size > AREA_MAXSIZE)
......
......@@ -122,10 +122,9 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info
/*
* Allocate the map_info structs in one go.
*/
maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
maps = kzalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
if (!maps)
return -ENOMEM;
memset(maps, 0, sizeof(struct map_info) * nr);
/*
* Claim and then map the memory regions.
*/
......
/*
* ck804xrom.c
*
* Normal mappings of chips in physical memory
*
* Dave Olsen <dolsen@lnxi.com>
* Ryan Jackson <rjackson@lnxi.com>
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/flashchip.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/list.h>
#define MOD_NAME KBUILD_BASENAME
#define ADDRESS_NAME_LEN 18
#define ROM_PROBE_STEP_SIZE (64*1024)
struct ck804xrom_window {
void __iomem *virt;
unsigned long phys;
unsigned long size;
struct list_head maps;
struct resource rsrc;
struct pci_dev *pdev;
};
struct ck804xrom_map_info {
struct list_head list;
struct map_info map;
struct mtd_info *mtd;
struct resource rsrc;
char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
};
/* The 2 bits controlling the window size are often set to allow reading
* the BIOS, but too small to allow writing, since the lock registers are
* 4MiB lower in the address space than the data.
*
* This is intended to prevent flashing the bios, perhaps accidentally.
*
* This parameter allows the normal driver to override the BIOS settings.
*
* The bits are 6 and 7. If both bits are set, it is a 5MiB window.
* If only the 7 Bit is set, it is a 4MiB window. Otherwise, a
* 64KiB window.
*
*/
static uint win_size_bits = 0;
module_param(win_size_bits, uint, 0);
MODULE_PARM_DESC(win_size_bits, "ROM window size bits override for 0x88 byte, normally set by BIOS.");
static struct ck804xrom_window ck804xrom_window = {
.maps = LIST_HEAD_INIT(ck804xrom_window.maps),
};
static void ck804xrom_cleanup(struct ck804xrom_window *window)
{
struct ck804xrom_map_info *map, *scratch;
u8 byte;
if (window->pdev) {
/* Disable writes through the rom window */
pci_read_config_byte(window->pdev, 0x6d, &byte);
pci_write_config_byte(window->pdev, 0x6d, byte & ~1);
}
/* Free all of the mtd devices */
list_for_each_entry_safe(map, scratch, &window->maps, list) {
if (map->rsrc.parent)
release_resource(&map->rsrc);
del_mtd_device(map->mtd);
map_destroy(map->mtd);
list_del(&map->list);
kfree(map);
}
if (window->rsrc.parent)
release_resource(&window->rsrc);
if (window->virt) {
iounmap(window->virt);
window->virt = NULL;
window->phys = 0;
window->size = 0;
}
pci_dev_put(window->pdev);
}
static int __devinit ck804xrom_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
u8 byte;
struct ck804xrom_window *window = &ck804xrom_window;
struct ck804xrom_map_info *map = NULL;
unsigned long map_top;
/* Remember the pci dev I find the window in */
window->pdev = pci_dev_get(pdev);
/* Enable the selected rom window. This is often incorrectly
* set up by the BIOS, and the 4MiB offset for the lock registers
* requires the full 5MiB of window space.
*
* This 'write, then read' approach leaves the bits for
* other uses of the hardware info.
*/
pci_read_config_byte(pdev, 0x88, &byte);
pci_write_config_byte(pdev, 0x88, byte | win_size_bits );
/* Assume the rom window is properly setup, and find it's size */
pci_read_config_byte(pdev, 0x88, &byte);
if ((byte & ((1<<7)|(1<<6))) == ((1<<7)|(1<<6)))
window->phys = 0xffb00000; /* 5MiB */
else if ((byte & (1<<7)) == (1<<7))
window->phys = 0xffc00000; /* 4MiB */
else
window->phys = 0xffff0000; /* 64KiB */
window->size = 0xffffffffUL - window->phys + 1UL;
/*
* Try to reserve the window mem region. If this fails then
* it is likely due to a fragment of the window being
* "reserved" by the BIOS. In the case that the
* request_mem_region() fails then once the rom size is
* discovered we will try to reserve the unreserved fragment.
*/
window->rsrc.name = MOD_NAME;
window->rsrc.start = window->phys;
window->rsrc.end = window->phys + window->size - 1;
window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL;
printk(KERN_ERR MOD_NAME
" %s(): Unable to register resource"
" 0x%.016llx-0x%.016llx - kernel bug?\n",
__func__,
(unsigned long long)window->rsrc.start,
(unsigned long long)window->rsrc.end);
}
/* Enable writes through the rom window */
pci_read_config_byte(pdev, 0x6d, &byte);
pci_write_config_byte(pdev, 0x6d, byte | 1);
/* FIXME handle registers 0x80 - 0x8C the bios region locks */
/* For write accesses caches are useless */
window->virt = ioremap_nocache(window->phys, window->size);
if (!window->virt) {
printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
window->phys, window->size);
goto out;
}
/* Get the first address to look for a rom chip at */
map_top = window->phys;
#if 1
/* The probe sequence run over the firmware hub lock
* registers sets them to 0x7 (no access).
* Probe at most the last 4MiB of the address space.
*/
if (map_top < 0xffc00000)
map_top = 0xffc00000;
#endif
/* Loop through and look for rom chips. Since we don't know the
* starting address for each chip, probe every ROM_PROBE_STEP_SIZE
* bytes from the starting address of the window.
*/
while((map_top - 1) < 0xffffffffUL) {
struct cfi_private *cfi;
unsigned long offset;
int i;
if (!map)
map = kmalloc(sizeof(*map), GFP_KERNEL);
if (!map) {
printk(KERN_ERR MOD_NAME ": kmalloc failed");
goto out;
}
memset(map, 0, sizeof(*map));
INIT_LIST_HEAD(&map->list);
map->map.name = map->map_name;
map->map.phys = map_top;
offset = map_top - window->phys;
map->map.virt = (void __iomem *)
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
sprintf(map->map_name, "%s @%08lx",
MOD_NAME, map->map.phys);
/* There is no generic VPP support */
for(map->map.bankwidth = 32; map->map.bankwidth;
map->map.bankwidth >>= 1)
{
char **probe_type;
/* Skip bankwidths that are not supported */
if (!map_bankwidth_supported(map->map.bankwidth))
continue;
/* Setup the map methods */
simple_map_init(&map->map);
/* Try all of the probe methods */
probe_type = rom_probe_types;
for(; *probe_type; probe_type++) {
map->mtd = do_map_probe(*probe_type, &map->map);
if (map->mtd)
goto found;
}
}
map_top += ROM_PROBE_STEP_SIZE;
continue;
found:
/* Trim the size if we are larger than the map */
if (map->mtd->size > map->map.size) {
printk(KERN_WARNING MOD_NAME
" rom(%u) larger than window(%lu). fixing...\n",
map->mtd->size, map->map.size);
map->mtd->size = map->map.size;
}
if (window->rsrc.parent) {
/*
* Registering the MTD device in iomem may not be possible
* if there is a BIOS "reserved" and BUSY range. If this
* fails then continue anyway.
*/
map->rsrc.name = map->map_name;
map->rsrc.start = map->map.phys;
map->rsrc.end = map->map.phys + map->mtd->size - 1;
map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
if (request_resource(&window->rsrc, &map->rsrc)) {
printk(KERN_ERR MOD_NAME
": cannot reserve MTD resource\n");
map->rsrc.parent = NULL;
}
}
/* Make the whole region visible in the map */
map->map.virt = window->virt;
map->map.phys = window->phys;
cfi = map->map.fldrv_priv;
for(i = 0; i < cfi->numchips; i++)
cfi->chips[i].start += offset;
/* Now that the mtd devices is complete claim and export it */
map->mtd->owner = THIS_MODULE;
if (add_mtd_device(map->mtd)) {
map_destroy(map->mtd);
map->mtd = NULL;
goto out;
}
/* Calculate the new value of map_top */
map_top += map->mtd->size;
/* File away the map structure */
list_add(&map->list, &window->maps);
map = NULL;
}
out:
/* Free any left over map structures */
if (map)
kfree(map);
/* See if I have any map structures */
if (list_empty(&window->maps)) {
ck804xrom_cleanup(window);
return -ENODEV;
}
return 0;
}
static void __devexit ck804xrom_remove_one (struct pci_dev *pdev)
{
struct ck804xrom_window *window = &ck804xrom_window;
ck804xrom_cleanup(window);
}
static struct pci_device_id ck804xrom_pci_tbl[] = {
{ PCI_VENDOR_ID_NVIDIA, 0x0051,
PCI_ANY_ID, PCI_ANY_ID, }, /* nvidia ck804 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ck804xrom_pci_tbl);
#if 0
static struct pci_driver ck804xrom_driver = {
.name = MOD_NAME,
.id_table = ck804xrom_pci_tbl,
.probe = ck804xrom_init_one,
.remove = ck804xrom_remove_one,
};
#endif
static int __init init_ck804xrom(void)
{
struct pci_dev *pdev;
struct pci_device_id *id;
int retVal;
pdev = NULL;
for(id = ck804xrom_pci_tbl; id->vendor; id++) {
pdev = pci_find_device(id->vendor, id->device, NULL);
if (pdev)
break;
}
if (pdev) {
retVal = ck804xrom_init_one(pdev, &ck804xrom_pci_tbl[0]);
pci_dev_put(pdev);
return retVal;
}
return -ENXIO;
#if 0
return pci_module_init(&ck804xrom_driver);
#endif
}
static void __exit cleanup_ck804xrom(void)
{
ck804xrom_remove_one(ck804xrom_window.pdev);
}
module_init(init_ck804xrom);
module_exit(cleanup_ck804xrom);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>, Dave Olsen <dolsen@lnxi.com>");
MODULE_DESCRIPTION("MTD map driver for BIOS chips on the Nvidia ck804 southbridge");
/*
* $Id: cstm_mips_ixx.c,v 1.14 2005/11/07 11:14:26 gleixner Exp $
*
* Mapping of a custom board with both AMD CFI and JEDEC flash in partitions.
* Config with both CFI and JEDEC device support.
*
* Basically physmap.c with the addition of partitions and
* an array of mapping info to accomodate more than one flash type per board.
*
* Copyright 2000 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
#define CC_GCR 0xB4013818
#define CC_GPBCR 0xB401380A
#define CC_GPBDR 0xB4013808
#define CC_M68K_DEVICE 1
#define CC_M68K_FUNCTION 6
#define CC_CONFADDR 0xB8004000
#define CC_CONFDATA 0xB8004004
#define CC_FC_FCR 0xB8002004
#define CC_FC_DCR 0xB8002008
#define CC_GPACR 0xB4013802
#define CC_GPAICR 0xB4013804
#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp)
{
static DEFINE_SPINLOCK(vpp_lock);
static int vpp_count = 0;
unsigned long flags;
spin_lock_irqsave(&vpp_lock, flags);
if (vpp) {
if (!vpp_count++) {
__u16 data;
__u8 data1;
static u8 first = 1;
// Set GPIO port B pin3 to high
data = *(__u16 *)(CC_GPBCR);
data = (data & 0xff0f) | 0x0040;
*(__u16 *)CC_GPBCR = data;
*(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08;
if (first) {
first = 0;
/* need to have this delay for first
enabling vpp after powerup */
udelay(40);
}
}
} else {
if (!--vpp_count) {
__u16 data;
// Set GPIO port B pin3 to high
data = *(__u16 *)(CC_GPBCR);
data = (data & 0xff3f) | 0x0040;
*(__u16 *)CC_GPBCR = data;
*(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7;
}
}
spin_unlock_irqrestore(&vpp_lock, flags);
}
#endif
/* board and partition description */
#define MAX_PHYSMAP_PARTITIONS 8
struct cstm_mips_ixx_info {
char *name;
unsigned long window_addr;
unsigned long window_size;
int bankwidth;
int num_partitions;
};
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type
const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
{
{ // 28F128J3A in 2x16 configuration
"big flash", // name
0x08000000, // window_addr
0x02000000, // window_size
4, // bankwidth
1, // num_partitions
}
};
static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
{ // 28F128J3A in 2x16 configuration
{
.name = "main partition ",
.size = 0x02000000, // 128 x 2 x 128k byte sectors
.offset = 0,
},
},
};
#else /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
#define PHYSMAP_NUMBER 1 // number of board desc structs needed, one per contiguous flash type
const struct cstm_mips_ixx_info cstm_mips_ixx_board_desc[PHYSMAP_NUMBER] =
{
{
"MTD flash", // name
CONFIG_MTD_CSTM_MIPS_IXX_START, // window_addr
CONFIG_MTD_CSTM_MIPS_IXX_LEN, // window_size
CONFIG_MTD_CSTM_MIPS_IXX_BUSWIDTH, // bankwidth
1, // num_partitions
},
};
static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = {
{
{
.name = "main partition",
.size = CONFIG_MTD_CSTM_MIPS_IXX_LEN,
.offset = 0,
},
},
};
#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
struct map_info cstm_mips_ixx_map[PHYSMAP_NUMBER];
int __init init_cstm_mips_ixx(void)
{
int i;
int jedec;
struct mtd_info *mymtd;
struct mtd_partition *parts;
/* Initialize mapping */
for (i=0;i<PHYSMAP_NUMBER;i++) {
printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n",
cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr);
cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr;
cstm_mips_ixx_map[i].virt = ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size);
if (!cstm_mips_ixx_map[i].virt) {
int j = 0;
printk(KERN_WARNING "Failed to ioremap\n");
for (j = 0; j < i; j++) {
if (cstm_mips_ixx_map[j].virt) {
iounmap(cstm_mips_ixx_map[j].virt);
cstm_mips_ixx_map[j].virt = NULL;
}
}
return -EIO;
}
cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name;
cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size;
cstm_mips_ixx_map[i].bankwidth = cstm_mips_ixx_board_desc[i].bankwidth;
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp;
#endif
simple_map_init(&cstm_mips_ixx_map[i]);
//printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt));
}
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
setup_ITE_IVR_flash();
#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
for (i=0;i<PHYSMAP_NUMBER;i++) {
parts = &cstm_mips_ixx_partitions[i][0];
jedec = 0;
mymtd = (struct mtd_info *)do_map_probe("cfi_probe", &cstm_mips_ixx_map[i]);
//printk(KERN_NOTICE "phymap %d cfi_probe: mymtd is %x\n",i,(unsigned int)mymtd);
if (!mymtd) {
jedec = 1;
mymtd = (struct mtd_info *)do_map_probe("jedec", &cstm_mips_ixx_map[i]);
printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd);
}
if (mymtd) {
mymtd->owner = THIS_MODULE;
cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd;
add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions);
}
else {
for (i = 0; i < PHYSMAP_NUMBER; i++) {
if (cstm_mips_ixx_map[i].virt) {
iounmap(cstm_mips_ixx_map[i].virt);
cstm_mips_ixx_map[i].virt = NULL;
}
}
return -ENXIO;
}
}
return 0;
}
static void __exit cleanup_cstm_mips_ixx(void)
{
int i;
struct mtd_info *mymtd;
for (i=0;i<PHYSMAP_NUMBER;i++) {
mymtd = (struct mtd_info *)cstm_mips_ixx_map[i].map_priv_2;
if (mymtd) {
del_mtd_partitions(mymtd);
map_destroy(mymtd);
}
if (cstm_mips_ixx_map[i].virt) {
iounmap((void *)cstm_mips_ixx_map[i].virt);
cstm_mips_ixx_map[i].virt = 0;
}
}
}
#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR)
void PCISetULongByOffset(__u32 DevNumber, __u32 FuncNumber, __u32 Offset, __u32 data)
{
__u32 offset;
offset = ( unsigned long )( 0x80000000 | ( DevNumber << 11 ) + ( FuncNumber << 8 ) + Offset) ;
*(__u32 *)CC_CONFADDR = offset;
*(__u32 *)CC_CONFDATA = data;
}
void setup_ITE_IVR_flash()
{
__u32 size, base;
size = 0x0e000000; // 32MiB
base = (0x08000000) >> 8 >>1; // Bug: we must shift one more bit
/* need to set ITE flash to 32 bits instead of default 8 */
#ifdef CONFIG_MIPS_IVR
*(__u32 *)CC_FC_FCR = 0x55;
*(__u32 *)CC_GPACR = 0xfffc;
#else
*(__u32 *)CC_FC_FCR = 0x77;
#endif
/* turn bursting off */
*(__u32 *)CC_FC_DCR = 0x0;
/* setup for one chip 4 byte PCI access */
PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x60, size | base);
PCISetULongByOffset(CC_M68K_DEVICE, CC_M68K_FUNCTION, 0x64, 0x02);
}
#endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */
module_init(init_cstm_mips_ixx);
module_exit(cleanup_cstm_mips_ixx);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
MODULE_DESCRIPTION("MTD map driver for ITE 8172G and Globespan IVR boards");
/*
* esb2rom.c
*
* Normal mappings of flash chips in physical memory
* through the Intel ESB2 Southbridge.
*
* This was derived from ichxrom.c in May 2006 by
* Lew Glendenning <lglendenning@lnxi.com>
*
* Eric Biederman, of course, was a major help in this effort.
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/cfi.h>
#include <linux/mtd/flashchip.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/list.h>
#define MOD_NAME KBUILD_BASENAME
#define ADDRESS_NAME_LEN 18
#define ROM_PROBE_STEP_SIZE (64*1024) /* 64KiB */
#define BIOS_CNTL 0xDC
#define BIOS_LOCK_ENABLE 0x02
#define BIOS_WRITE_ENABLE 0x01
/* This became a 16-bit register, and EN2 has disappeared */
#define FWH_DEC_EN1 0xD8
#define FWH_F8_EN 0x8000
#define FWH_F0_EN 0x4000
#define FWH_E8_EN 0x2000
#define FWH_E0_EN 0x1000
#define FWH_D8_EN 0x0800
#define FWH_D0_EN 0x0400
#define FWH_C8_EN 0x0200
#define FWH_C0_EN 0x0100
#define FWH_LEGACY_F_EN 0x0080
#define FWH_LEGACY_E_EN 0x0040
/* reserved 0x0020 and 0x0010 */
#define FWH_70_EN 0x0008
#define FWH_60_EN 0x0004
#define FWH_50_EN 0x0002
#define FWH_40_EN 0x0001
/* these are 32-bit values */
#define FWH_SEL1 0xD0
#define FWH_SEL2 0xD4
#define FWH_8MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
FWH_70_EN | FWH_60_EN | FWH_50_EN | FWH_40_EN)
#define FWH_7MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
FWH_70_EN | FWH_60_EN | FWH_50_EN)
#define FWH_6MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
FWH_70_EN | FWH_60_EN)
#define FWH_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN | \
FWH_70_EN)
#define FWH_4MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
FWH_D8_EN | FWH_D0_EN | FWH_C8_EN | FWH_C0_EN)
#define FWH_3_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
FWH_D8_EN | FWH_D0_EN | FWH_C8_EN)
#define FWH_3MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
FWH_D8_EN | FWH_D0_EN)
#define FWH_2_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN | \
FWH_D8_EN)
#define FWH_2MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN | FWH_E0_EN)
#define FWH_1_5MiB (FWH_F8_EN | FWH_F0_EN | FWH_E8_EN)
#define FWH_1MiB (FWH_F8_EN | FWH_F0_EN)
#define FWH_0_5MiB (FWH_F8_EN)
struct esb2rom_window {
void __iomem* virt;
unsigned long phys;
unsigned long size;
struct list_head maps;
struct resource rsrc;
struct pci_dev *pdev;
};
struct esb2rom_map_info {
struct list_head list;
struct map_info map;
struct mtd_info *mtd;
struct resource rsrc;
char map_name[sizeof(MOD_NAME) + 2 + ADDRESS_NAME_LEN];
};
static struct esb2rom_window esb2rom_window = {
.maps = LIST_HEAD_INIT(esb2rom_window.maps),
};
static void esb2rom_cleanup(struct esb2rom_window *window)
{
struct esb2rom_map_info *map, *scratch;
u8 byte;
/* Disable writes through the rom window */
pci_read_config_byte(window->pdev, BIOS_CNTL, &byte);
pci_write_config_byte(window->pdev, BIOS_CNTL,
byte & ~BIOS_WRITE_ENABLE);
/* Free all of the mtd devices */
list_for_each_entry_safe(map, scratch, &window->maps, list) {
if (map->rsrc.parent)
release_resource(&map->rsrc);
del_mtd_device(map->mtd);
map_destroy(map->mtd);
list_del(&map->list);
kfree(map);
}
if (window->rsrc.parent)
release_resource(&window->rsrc);
if (window->virt) {
iounmap(window->virt);
window->virt = NULL;
window->phys = 0;
window->size = 0;
}
pci_dev_put(window->pdev);
}
static int __devinit esb2rom_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", NULL };
struct esb2rom_window *window = &esb2rom_window;
struct esb2rom_map_info *map = NULL;
unsigned long map_top;
u8 byte;
u16 word;
/* For now I just handle the ecb2 and I assume there
* are not a lot of resources up at the top of the address
* space. It is possible to handle other devices in the
* top 16MiB but it is very painful. Also since
* you can only really attach a FWH to an ICHX there
* a number of simplifications you can make.
*
* Also you can page firmware hubs if an 8MiB window isn't enough
* but don't currently handle that case either.
*/
window->pdev = pci_dev_get(pdev);
/* RLG: experiment 2. Force the window registers to the widest values */
/*
pci_read_config_word(pdev, FWH_DEC_EN1, &word);
printk(KERN_DEBUG "Original FWH_DEC_EN1 : %x\n", word);
pci_write_config_byte(pdev, FWH_DEC_EN1, 0xff);
pci_read_config_byte(pdev, FWH_DEC_EN1, &byte);
printk(KERN_DEBUG "New FWH_DEC_EN1 : %x\n", byte);
pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
printk(KERN_DEBUG "Original FWH_DEC_EN2 : %x\n", byte);
pci_write_config_byte(pdev, FWH_DEC_EN2, 0x0f);
pci_read_config_byte(pdev, FWH_DEC_EN2, &byte);
printk(KERN_DEBUG "New FWH_DEC_EN2 : %x\n", byte);
*/
/* Find a region continuous to the end of the ROM window */
window->phys = 0;
pci_read_config_word(pdev, FWH_DEC_EN1, &word);
printk(KERN_DEBUG "pci_read_config_byte : %x\n", word);
if ((word & FWH_8MiB) == FWH_8MiB)
window->phys = 0xff400000;
else if ((word & FWH_7MiB) == FWH_7MiB)
window->phys = 0xff500000;
else if ((word & FWH_6MiB) == FWH_6MiB)
window->phys = 0xff600000;
else if ((word & FWH_5MiB) == FWH_5MiB)
window->phys = 0xFF700000;
else if ((word & FWH_4MiB) == FWH_4MiB)
window->phys = 0xffc00000;
else if ((word & FWH_3_5MiB) == FWH_3_5MiB)
window->phys = 0xffc80000;
else if ((word & FWH_3MiB) == FWH_3MiB)
window->phys = 0xffd00000;
else if ((word & FWH_2_5MiB) == FWH_2_5MiB)
window->phys = 0xffd80000;
else if ((word & FWH_2MiB) == FWH_2MiB)
window->phys = 0xffe00000;
else if ((word & FWH_1_5MiB) == FWH_1_5MiB)
window->phys = 0xffe80000;
else if ((word & FWH_1MiB) == FWH_1MiB)
window->phys = 0xfff00000;
else if ((word & FWH_0_5MiB) == FWH_0_5MiB)
window->phys = 0xfff80000;
/* reserved 0x0020 and 0x0010 */
window->phys -= 0x400000UL;
window->size = (0xffffffffUL - window->phys) + 1UL;
/* Enable writes through the rom window */
pci_read_config_byte(pdev, BIOS_CNTL, &byte);
if (!(byte & BIOS_WRITE_ENABLE) && (byte & (BIOS_LOCK_ENABLE))) {
/* The BIOS will generate an error if I enable
* this device, so don't even try.
*/
printk(KERN_ERR MOD_NAME ": firmware access control, I can't enable writes\n");
goto out;
}
pci_write_config_byte(pdev, BIOS_CNTL, byte | BIOS_WRITE_ENABLE);
/*
* Try to reserve the window mem region. If this fails then
* it is likely due to the window being "reseved" by the BIOS.
*/
window->rsrc.name = MOD_NAME;
window->rsrc.start = window->phys;
window->rsrc.end = window->phys + window->size - 1;
window->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
if (request_resource(&iomem_resource, &window->rsrc)) {
window->rsrc.parent = NULL;
printk(KERN_DEBUG MOD_NAME
": %s(): Unable to register resource"
" 0x%.08llx-0x%.08llx - kernel bug?\n",
__func__,
(unsigned long long)window->rsrc.start,
(unsigned long long)window->rsrc.end);
}
/* Map the firmware hub into my address space. */
window->virt = ioremap_nocache(window->phys, window->size);
if (!window->virt) {
printk(KERN_ERR MOD_NAME ": ioremap(%08lx, %08lx) failed\n",
window->phys, window->size);
goto out;
}
/* Get the first address to look for an rom chip at */
map_top = window->phys;
if ((window->phys & 0x3fffff) != 0) {
/* if not aligned on 4MiB, look 4MiB lower in address space */
map_top = window->phys + 0x400000;
}
#if 1
/* The probe sequence run over the firmware hub lock
* registers sets them to 0x7 (no access).
* (Insane hardware design, but most copied Intel's.)
* ==> Probe at most the last 4M of the address space.
*/
if (map_top < 0xffc00000)
map_top = 0xffc00000;
#endif
/* Loop through and look for rom chips */
while ((map_top - 1) < 0xffffffffUL) {
struct cfi_private *cfi;
unsigned long offset;
int i;
if (!map)
map = kmalloc(sizeof(*map), GFP_KERNEL);
if (!map) {
printk(KERN_ERR MOD_NAME ": kmalloc failed");
goto out;
}
memset(map, 0, sizeof(*map));
INIT_LIST_HEAD(&map->list);
map->map.name = map->map_name;
map->map.phys = map_top;
offset = map_top - window->phys;
map->map.virt = (void __iomem *)
(((unsigned long)(window->virt)) + offset);
map->map.size = 0xffffffffUL - map_top + 1UL;
/* Set the name of the map to the address I am trying */
sprintf(map->map_name, "%s @%08lx",
MOD_NAME, map->map.phys);
/* Firmware hubs only use vpp when being programmed
* in a factory setting. So in-place programming
* needs to use a different method.
*/
for(map->map.bankwidth = 32; map->map.bankwidth;
map->map.bankwidth >>= 1) {
char **probe_type;
/* Skip bankwidths that are not supported */
if (!map_bankwidth_supported(map->map.bankwidth))
continue;
/* Setup the map methods */
simple_map_init(&map->map);
/* Try all of the probe methods */
probe_type = rom_probe_types;
for(; *probe_type; probe_type++) {
map->mtd = do_map_probe(*probe_type, &map->map);
if (map->mtd)
goto found;
}
}
map_top += ROM_PROBE_STEP_SIZE;
continue;
found:
/* Trim the size if we are larger than the map */
if (map->mtd->size > map->map.size) {
printk(KERN_WARNING MOD_NAME
" rom(%u) larger than window(%lu). fixing...\n",
map->mtd->size, map->map.size);
map->mtd->size = map->map.size;
}
if (window->rsrc.parent) {
/*
* Registering the MTD device in iomem may not be possible
* if there is a BIOS "reserved" and BUSY range. If this
* fails then continue anyway.
*/
map->rsrc.name = map->map_name;
map->rsrc.start = map->map.phys;
map->rsrc.end = map->map.phys + map->mtd->size - 1;
map->rsrc.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
if (request_resource(&window->rsrc, &map->rsrc)) {
printk(KERN_ERR MOD_NAME
": cannot reserve MTD resource\n");
map->rsrc.parent = NULL;
}
}
/* Make the whole region visible in the map */
map->map.virt = window->virt;
map->map.phys = window->phys;
cfi = map->map.fldrv_priv;
for(i = 0; i < cfi->numchips; i++)
cfi->chips[i].start += offset;
/* Now that the mtd devices is complete claim and export it */
map->mtd->owner = THIS_MODULE;
if (add_mtd_device(map->mtd)) {
map_destroy(map->mtd);
map->mtd = NULL;
goto out;
}
/* Calculate the new value of map_top */
map_top += map->mtd->size;
/* File away the map structure */
list_add(&map->list, &window->maps);
map = NULL;
}
out:
/* Free any left over map structures */
kfree(map);
/* See if I have any map structures */
if (list_empty(&window->maps)) {
esb2rom_cleanup(window);
return -ENODEV;
}
return 0;
}
static void __devexit esb2rom_remove_one (struct pci_dev *pdev)
{
struct esb2rom_window *window = &esb2rom_window;
esb2rom_cleanup(window);
}
static struct pci_device_id esb2rom_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0,
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0,
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0,
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1,
PCI_ANY_ID, PCI_ANY_ID, },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0,
PCI_ANY_ID, PCI_ANY_ID, },
{ 0, },
};
#if 0
MODULE_DEVICE_TABLE(pci, esb2rom_pci_tbl);
static struct pci_driver esb2rom_driver = {
.name = MOD_NAME,
.id_table = esb2rom_pci_tbl,
.probe = esb2rom_init_one,
.remove = esb2rom_remove_one,
};
#endif
static int __init init_esb2rom(void)
{
struct pci_dev *pdev;
struct pci_device_id *id;
int retVal;
pdev = NULL;
for (id = esb2rom_pci_tbl; id->vendor; id++) {
printk(KERN_DEBUG "device id = %x\n", id->device);
pdev = pci_get_device(id->vendor, id->device, NULL);
if (pdev) {
printk(KERN_DEBUG "matched device = %x\n", id->device);
break;
}
}
if (pdev) {
printk(KERN_DEBUG "matched device id %x\n", id->device);
retVal = esb2rom_init_one(pdev, &esb2rom_pci_tbl[0]);
pci_dev_put(pdev);
printk(KERN_DEBUG "retVal = %d\n", retVal);
return retVal;
}
return -ENXIO;
#if 0
return pci_register_driver(&esb2rom_driver);
#endif
}
static void __exit cleanup_esb2rom(void)
{
esb2rom_remove_one(esb2rom_window.pdev);
}
module_init(init_esb2rom);
module_exit(cleanup_esb2rom);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Lew Glendenning <lglendenning@lnxi.com>");
MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ESB2 southbridge");
......@@ -75,14 +75,12 @@ static int armflash_probe(struct platform_device *dev)
int err;
void __iomem *base;
info = kmalloc(sizeof(struct armflash_info), GFP_KERNEL);
info = kzalloc(sizeof(struct armflash_info), GFP_KERNEL);
if (!info) {
err = -ENOMEM;
goto out;
}
memset(info, 0, sizeof(struct armflash_info));
info->plat = plat;
if (plat && plat->init) {
err = plat->init();
......
......@@ -20,6 +20,7 @@
#include <linux/mtd/partitions.h>
#include <linux/mtd/cfi.h>
#include <linux/reboot.h>
#include <linux/err.h>
#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <asm/io.h>
......@@ -178,7 +179,7 @@ int nettel_eraseconfig(void)
init_waitqueue_head(&wait_q);
mtd = get_mtd_device(NULL, 2);
if (mtd) {
if (!IS_ERR(mtd)) {
nettel_erase.mtd = mtd;
nettel_erase.callback = nettel_erasecallback;
nettel_erase.callback = NULL;
......@@ -471,7 +472,7 @@ int __init nettel_init(void)
iounmap(nettel_amd_map.virt);
return(rc);
}
/****************************************************************************/
......
......@@ -78,12 +78,10 @@ static int __devinit omapflash_probe(struct platform_device *pdev)
struct resource *res = pdev->resource;
unsigned long size = res->end - res->start + 1;
info = kmalloc(sizeof(struct omapflash_info), GFP_KERNEL);
info = kzalloc(sizeof(struct omapflash_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
memset(info, 0, sizeof(struct omapflash_info));
if (!request_mem_region(res->start, size, "flash")) {
err = -EBUSY;
goto out_free_info;
......
......@@ -735,11 +735,10 @@ static int pcmciamtd_probe(struct pcmcia_device *link)
struct pcmciamtd_dev *dev;
/* Create new memory card device */
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) return -ENOMEM;
DEBUG(1, "dev=0x%p", dev);
memset(dev, 0, sizeof(*dev));
dev->p_dev = link;
link->priv = dev;
......
......@@ -89,15 +89,14 @@ static int physmap_flash_probe(struct platform_device *dev)
return -ENODEV;
printk(KERN_NOTICE "physmap platform flash device: %.8llx at %.8llx\n",
(unsigned long long)dev->resource->end - dev->resource->start + 1,
(unsigned long long)(dev->resource->end - dev->resource->start + 1),
(unsigned long long)dev->resource->start);
info = kmalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
goto err_out;
}
memset(info, 0, sizeof(*info));
platform_set_drvdata(dev, info);
......
/*
* Normal mappings of chips in physical memory for OF devices
*
* Copyright (C) 2006 MontaVista Software Inc.
* Author: Vitaly Wool <vwool@ru.mvista.com>
*
* 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/slab.h>
#include <linux/device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/of_device.h>
#include <asm/of_platform.h>
struct physmap_flash_info {
struct mtd_info *mtd;
struct map_info map;
struct resource *res;
#ifdef CONFIG_MTD_PARTITIONS
int nr_parts;
struct mtd_partition *parts;
#endif
};
static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", NULL };
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL };
#endif
#ifdef CONFIG_MTD_PARTITIONS
static int parse_flash_partitions(struct device_node *node,
struct mtd_partition **parts)
{
int i, plen, retval = -ENOMEM;
const u32 *part;
const char *name;
part = get_property(node, "partitions", &plen);
if (part == NULL)
goto err;
retval = plen / (2 * sizeof(u32));
*parts = kzalloc(retval * sizeof(struct mtd_partition), GFP_KERNEL);
if (*parts == NULL) {
printk(KERN_ERR "Can't allocate the flash partition data!\n");
goto err;
}
name = get_property(node, "partition-names", &plen);
for (i = 0; i < retval; i++) {
(*parts)[i].offset = *part++;
(*parts)[i].size = *part & ~1;
if (*part++ & 1) /* bit 0 set signifies read only partition */
(*parts)[i].mask_flags = MTD_WRITEABLE;
if (name != NULL && plen > 0) {
int len = strlen(name) + 1;
(*parts)[i].name = (char *)name;
plen -= len;
name += len;
} else
(*parts)[i].name = "unnamed";
}
err:
return retval;
}
#endif
static int of_physmap_remove(struct of_device *dev)
{
struct physmap_flash_info *info;
info = dev_get_drvdata(&dev->dev);
if (info == NULL)
return 0;
dev_set_drvdata(&dev->dev, NULL);
if (info->mtd != NULL) {
#ifdef CONFIG_MTD_PARTITIONS
if (info->nr_parts) {
del_mtd_partitions(info->mtd);
kfree(info->parts);
} else {
del_mtd_device(info->mtd);
}
#else
del_mtd_device(info->mtd);
#endif
map_destroy(info->mtd);
}
if (info->map.virt != NULL)
iounmap(info->map.virt);
if (info->res != NULL) {
release_resource(info->res);
kfree(info->res);
}
return 0;
}
static int __devinit of_physmap_probe(struct of_device *dev, const struct of_device_id *match)
{
struct device_node *dp = dev->node;
struct resource res;
struct physmap_flash_info *info;
const char **probe_type;
const char *of_probe;
const u32 *width;
int err;
if (of_address_to_resource(dp, 0, &res)) {
dev_err(&dev->dev, "Can't get the flash mapping!\n");
err = -EINVAL;
goto err_out;
}
dev_dbg(&dev->dev, "physmap flash device: %.8llx at %.8llx\n",
(unsigned long long)res.end - res.start + 1,
(unsigned long long)res.start);
info = kzalloc(sizeof(struct physmap_flash_info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
goto err_out;
}
memset(info, 0, sizeof(*info));
dev_set_drvdata(&dev->dev, info);
info->res = request_mem_region(res.start, res.end - res.start + 1,
dev->dev.bus_id);
if (info->res == NULL) {
dev_err(&dev->dev, "Could not reserve memory region\n");
err = -ENOMEM;
goto err_out;
}
width = get_property(dp, "bank-width", NULL);
if (width == NULL) {
dev_err(&dev->dev, "Can't get the flash bank width!\n");
err = -EINVAL;
goto err_out;
}
info->map.name = dev->dev.bus_id;
info->map.phys = res.start;
info->map.size = res.end - res.start + 1;
info->map.bankwidth = *width;
info->map.virt = ioremap(info->map.phys, info->map.size);
if (info->map.virt == NULL) {
dev_err(&dev->dev, "Failed to ioremap flash region\n");
err = EIO;
goto err_out;
}
simple_map_init(&info->map);
of_probe = get_property(dp, "probe-type", NULL);
if (of_probe == NULL) {
probe_type = rom_probe_types;
for (; info->mtd == NULL && *probe_type != NULL; probe_type++)
info->mtd = do_map_probe(*probe_type, &info->map);
} else if (!strcmp(of_probe, "CFI"))
info->mtd = do_map_probe("cfi_probe", &info->map);
else if (!strcmp(of_probe, "JEDEC"))
info->mtd = do_map_probe("jedec_probe", &info->map);
else {
if (strcmp(of_probe, "ROM"))
dev_dbg(&dev->dev, "map_probe: don't know probe type "
"'%s', mapping as rom\n");
info->mtd = do_map_probe("mtd_rom", &info->map);
}
if (info->mtd == NULL) {
dev_err(&dev->dev, "map_probe failed\n");
err = -ENXIO;
goto err_out;
}
info->mtd->owner = THIS_MODULE;
#ifdef CONFIG_MTD_PARTITIONS
err = parse_mtd_partitions(info->mtd, part_probe_types, &info->parts, 0);
if (err > 0) {
add_mtd_partitions(info->mtd, info->parts, err);
} else if ((err = parse_flash_partitions(dp, &info->parts)) > 0) {
dev_info(&dev->dev, "Using OF partition information\n");
add_mtd_partitions(info->mtd, info->parts, err);
info->nr_parts = err;
} else
#endif
add_mtd_device(info->mtd);
return 0;
err_out:
of_physmap_remove(dev);
return err;
return 0;
}
static struct of_device_id of_physmap_match[] = {
{
.type = "rom",
.compatible = "direct-mapped"
},
{ },
};
MODULE_DEVICE_TABLE(of, of_physmap_match);
static struct of_platform_driver of_physmap_flash_driver = {
.name = "physmap-flash",
.match_table = of_physmap_match,
.probe = of_physmap_probe,
.remove = of_physmap_remove,
};
static int __init of_physmap_init(void)
{
return of_register_platform_driver(&of_physmap_flash_driver);
}
static void __exit of_physmap_exit(void)
{
of_unregister_platform_driver(&of_physmap_flash_driver);
}
module_init(of_physmap_init);
module_exit(of_physmap_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
MODULE_DESCRIPTION("Configurable MTD map driver for OF");
......@@ -147,14 +147,13 @@ static int platram_probe(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
info = kmalloc(sizeof(*info), GFP_KERNEL);
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) {
dev_err(&pdev->dev, "no memory for flash info\n");
err = -ENOMEM;
goto exit_error;
}
memset(info, 0, sizeof(*info));
platform_set_drvdata(pdev, info);
info->dev = &pdev->dev;
......
......@@ -273,14 +273,12 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
/*
* Allocate the map_info structs in one go.
*/
info = kmalloc(size, GFP_KERNEL);
info = kzalloc(size, GFP_KERNEL);
if (!info) {
ret = -ENOMEM;
goto out;
}
memset(info, 0, size);
if (plat->init) {
ret = plat->init();
if (ret)
......
......@@ -132,20 +132,16 @@ static int __init init_tqm834x_mtd(void)
pr_debug("%s: chip probing count %d\n", __FUNCTION__, idx);
map_banks[idx] =
(struct map_info *)kmalloc(sizeof(struct map_info),
GFP_KERNEL);
map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
if (map_banks[idx] == NULL) {
ret = -ENOMEM;
goto error_mem;
}
memset((void *)map_banks[idx], 0, sizeof(struct map_info));
map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
map_banks[idx]->name = kzalloc(16, GFP_KERNEL);
if (map_banks[idx]->name == NULL) {
ret = -ENOMEM;
goto error_mem;
}
memset((void *)map_banks[idx]->name, 0, 16);
sprintf(map_banks[idx]->name, "TQM834x-%d", idx);
map_banks[idx]->size = flash_size;
......
......@@ -134,14 +134,13 @@ int __init init_tqm_mtd(void)
printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx);
map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL);
map_banks[idx] = kzalloc(sizeof(struct map_info), GFP_KERNEL);
if(map_banks[idx] == NULL) {
ret = -ENOMEM;
/* FIXME: What if some MTD devices were probed already? */
goto error_mem;
}
memset((void *)map_banks[idx], 0, sizeof(struct map_info));
map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL);
if (!map_banks[idx]->name) {
......
......@@ -42,19 +42,20 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
unsigned long block, nsect;
char *buf;
block = req->sector;
nsect = req->current_nr_sectors;
block = req->sector << 9 >> tr->blkshift;
nsect = req->current_nr_sectors << 9 >> tr->blkshift;
buf = req->buffer;
if (!blk_fs_request(req))
return 0;
if (block + nsect > get_capacity(req->rq_disk))
if (req->sector + req->current_nr_sectors > get_capacity(req->rq_disk))
return 0;
switch(rq_data_dir(req)) {
case READ:
for (; nsect > 0; nsect--, block++, buf += 512)
for (; nsect > 0; nsect--, block++, buf += tr->blksize)
if (tr->readsect(dev, block, buf))
return 0;
return 1;
......@@ -63,7 +64,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
if (!tr->writesect)
return 0;
for (; nsect > 0; nsect--, block++, buf += 512)
for (; nsect > 0; nsect--, block++, buf += tr->blksize)
if (tr->writesect(dev, block, buf))
return 0;
return 1;
......@@ -297,7 +298,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
/* 2.5 has capacity in units of 512 bytes while still
having BLOCK_SIZE_BITS set to 10. Just to keep us amused. */
set_capacity(gd, (new->size * new->blksize) >> 9);
set_capacity(gd, (new->size * tr->blksize) >> 9);
gd->private_data = new;
new->blkcore_priv = gd;
......@@ -372,12 +373,10 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
if (!blktrans_notifier.list.next)
register_mtd_user(&blktrans_notifier);
tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
tr->blkcore_priv = kzalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL);
if (!tr->blkcore_priv)
return -ENOMEM;
memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv));
mutex_lock(&mtd_table_mutex);
ret = register_blkdev(tr->major, tr->name);
......@@ -401,6 +400,8 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr)
}
tr->blkcore_priv->rq->queuedata = tr;
blk_queue_hardsect_size(tr->blkcore_priv->rq, tr->blksize);
tr->blkshift = ffs(tr->blksize) - 1;
ret = kernel_thread(mtd_blktrans_thread, tr, CLONE_KERNEL);
if (ret < 0) {
......
......@@ -278,11 +278,10 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
}
/* OK, it's not open. Create cache info for it */
mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
mtdblk = kzalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
if (!mtdblk)
return -ENOMEM;
memset(mtdblk, 0, sizeof(*mtdblk));
mtdblk->count = 1;
mtdblk->mtd = mtd;
......@@ -339,16 +338,14 @@ static int mtdblock_flush(struct mtd_blktrans_dev *dev)
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
struct mtd_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return;
memset(dev, 0, sizeof(*dev));
dev->mtd = mtd;
dev->devnum = mtd->index;
dev->blksize = 512;
dev->size = mtd->size >> 9;
dev->tr = tr;
......@@ -368,6 +365,7 @@ static struct mtd_blktrans_ops mtdblock_tr = {
.name = "mtdblock",
.major = 31,
.part_bits = 0,
.blksize = 512,
.open = mtdblock_open,
.flush = mtdblock_flush,
.release = mtdblock_release,
......
......@@ -33,16 +33,14 @@ static int mtdblock_writesect(struct mtd_blktrans_dev *dev,
static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
{
struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
struct mtd_blktrans_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return;
memset(dev, 0, sizeof(*dev));
dev->mtd = mtd;
dev->devnum = mtd->index;
dev->blksize = 512;
dev->size = mtd->size >> 9;
dev->tr = tr;
dev->readonly = 1;
......@@ -60,6 +58,7 @@ static struct mtd_blktrans_ops mtdblock_tr = {
.name = "mtdblock",
.major = 31,
.part_bits = 0,
.blksize = 512,
.readsect = mtdblock_readsect,
.writesect = mtdblock_writesect,
.add_mtd = mtdblock_add_mtd,
......
......@@ -7,6 +7,7 @@
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
......@@ -100,8 +101,8 @@ static int mtd_open(struct inode *inode, struct file *file)
mtd = get_mtd_device(NULL, devnum);
if (!mtd)
return -ENODEV;
if (IS_ERR(mtd))
return PTR_ERR(mtd);
if (MTD_ABSENT == mtd->type) {
put_mtd_device(mtd);
......@@ -431,7 +432,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if(!(file->f_mode & 2))
return -EPERM;
erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL);
erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL);
if (!erase)
ret = -ENOMEM;
else {
......@@ -440,7 +441,6 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
init_waitqueue_head(&waitq);
memset (erase,0,sizeof(struct erase_info));
if (copy_from_user(&erase->addr, argp,
sizeof(struct erase_info_user))) {
kfree(erase);
......@@ -499,13 +499,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (ret)
return ret;
ops.len = buf.length;
ops.ooblen = buf.length;
ops.ooboffs = buf.start & (mtd->oobsize - 1);
ops.datbuf = NULL;
ops.mode = MTD_OOB_PLACE;
if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs))
if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs))
return -EINVAL;
ops.oobbuf = kmalloc(buf.length, GFP_KERNEL);
......@@ -520,7 +519,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
buf.start &= ~(mtd->oobsize - 1);
ret = mtd->write_oob(mtd, buf.start, &ops);
if (copy_to_user(argp + sizeof(uint32_t), &ops.retlen,
if (copy_to_user(argp + sizeof(uint32_t), &ops.oobretlen,
sizeof(uint32_t)))
ret = -EFAULT;
......@@ -548,7 +547,6 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (ret)
return ret;
ops.len = buf.length;
ops.ooblen = buf.length;
ops.ooboffs = buf.start & (mtd->oobsize - 1);
ops.datbuf = NULL;
......@@ -564,10 +562,10 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
buf.start &= ~(mtd->oobsize - 1);
ret = mtd->read_oob(mtd, buf.start, &ops);
if (put_user(ops.retlen, (uint32_t __user *)argp))
if (put_user(ops.oobretlen, (uint32_t __user *)argp))
ret = -EFAULT;
else if (ops.retlen && copy_to_user(buf.ptr, ops.oobbuf,
ops.retlen))
else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf,
ops.oobretlen))
ret = -EFAULT;
kfree(ops.oobbuf);
......@@ -616,6 +614,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos));
memcpy(&oi.oobfree, mtd->ecclayout->oobfree,
sizeof(oi.oobfree));
oi.eccbytes = mtd->ecclayout->eccbytes;
if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo)))
return -EFAULT;
......@@ -715,7 +714,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
if (!mtd->ecclayout)
return -EOPNOTSUPP;
if (copy_to_user(argp, &mtd->ecclayout,
if (copy_to_user(argp, mtd->ecclayout,
sizeof(struct nand_ecclayout)))
return -EFAULT;
break;
......
......@@ -247,7 +247,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
struct mtd_oob_ops devops = *ops;
int i, err, ret = 0;
ops->retlen = 0;
ops->retlen = ops->oobretlen = 0;
for (i = 0; i < concat->num_subdev; i++) {
struct mtd_info *subdev = concat->subdev[i];
......@@ -263,6 +263,7 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
err = subdev->read_oob(subdev, from, &devops);
ops->retlen += devops.retlen;
ops->oobretlen += devops.oobretlen;
/* Save information about bitflips! */
if (unlikely(err)) {
......@@ -278,14 +279,18 @@ concat_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
return err;
}
devops.len = ops->len - ops->retlen;
if (!devops.len)
return ret;
if (devops.datbuf)
if (devops.datbuf) {
devops.len = ops->len - ops->retlen;
if (!devops.len)
return ret;
devops.datbuf += devops.retlen;
if (devops.oobbuf)
devops.oobbuf += devops.ooblen;
}
if (devops.oobbuf) {
devops.ooblen = ops->ooblen - ops->oobretlen;
if (!devops.ooblen)
return ret;
devops.oobbuf += ops->oobretlen;
}
from = 0;
}
......@@ -321,14 +326,18 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
if (err)
return err;
devops.len = ops->len - ops->retlen;
if (!devops.len)
return 0;
if (devops.datbuf)
if (devops.datbuf) {
devops.len = ops->len - ops->retlen;
if (!devops.len)
return 0;
devops.datbuf += devops.retlen;
if (devops.oobbuf)
devops.oobbuf += devops.ooblen;
}
if (devops.oobbuf) {
devops.ooblen = ops->ooblen - ops->oobretlen;
if (!devops.ooblen)
return 0;
devops.oobbuf += devops.oobretlen;
}
to = 0;
}
return -EINVAL;
......@@ -699,14 +708,13 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
/* allocate the device structure */
size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
concat = kmalloc(size, GFP_KERNEL);
concat = kzalloc(size, GFP_KERNEL);
if (!concat) {
printk
("memory allocation error while creating concatenated device \"%s\"\n",
name);
return NULL;
}
memset(concat, 0, size);
concat->subdev = (struct mtd_info **) (concat + 1);
/*
......@@ -764,6 +772,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.ecc_stats.badblocks +=
subdev[i]->ecc_stats.badblocks;
if (concat->mtd.writesize != subdev[i]->writesize ||
concat->mtd.subpage_sft != subdev[i]->subpage_sft ||
concat->mtd.oobsize != subdev[i]->oobsize ||
concat->mtd.ecctype != subdev[i]->ecctype ||
concat->mtd.eccsize != subdev[i]->eccsize ||
......
......@@ -15,6 +15,7 @@
#include <linux/timer.h>
#include <linux/major.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/ioctl.h>
#include <linux/init.h>
#include <linux/mtd/compatmac.h>
......@@ -192,14 +193,14 @@ int unregister_mtd_user (struct mtd_notifier *old)
* Given a number and NULL address, return the num'th entry in the device
* table, if any. Given an address and num == -1, search the device table
* for a device with that address and return if it's still present. Given
* both, return the num'th driver only if its address matches. Return NULL
* if not.
* both, return the num'th driver only if its address matches. Return
* error code if not.
*/
struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
{
struct mtd_info *ret = NULL;
int i;
int i, err = -ENODEV;
mutex_lock(&mtd_table_mutex);
......@@ -213,14 +214,73 @@ struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
ret = NULL;
}
if (ret && !try_module_get(ret->owner))
ret = NULL;
if (!ret)
goto out_unlock;
if (!try_module_get(ret->owner))
goto out_unlock;
if (ret)
ret->usecount++;
if (ret->get_device) {
err = ret->get_device(ret);
if (err)
goto out_put;
}
ret->usecount++;
mutex_unlock(&mtd_table_mutex);
return ret;
out_put:
module_put(ret->owner);
out_unlock:
mutex_unlock(&mtd_table_mutex);
return ERR_PTR(err);
}
/**
* get_mtd_device_nm - obtain a validated handle for an MTD device by
* device name
* @name: MTD device name to open
*
* This function returns MTD device description structure in case of
* success and an error code in case of failure.
*/
struct mtd_info *get_mtd_device_nm(const char *name)
{
int i, err = -ENODEV;
struct mtd_info *mtd = NULL;
mutex_lock(&mtd_table_mutex);
for (i = 0; i < MAX_MTD_DEVICES; i++) {
if (mtd_table[i] && !strcmp(name, mtd_table[i]->name)) {
mtd = mtd_table[i];
break;
}
}
if (!mtd)
goto out_unlock;
if (!try_module_get(mtd->owner))
goto out_unlock;
if (mtd->get_device) {
err = mtd->get_device(mtd);
if (err)
goto out_put;
}
mtd->usecount++;
mutex_unlock(&mtd_table_mutex);
return mtd;
out_put:
module_put(mtd->owner);
out_unlock:
mutex_unlock(&mtd_table_mutex);
return ERR_PTR(err);
}
void put_mtd_device(struct mtd_info *mtd)
......@@ -229,6 +289,8 @@ void put_mtd_device(struct mtd_info *mtd)
mutex_lock(&mtd_table_mutex);
c = --mtd->usecount;
if (mtd->put_device)
mtd->put_device(mtd);
mutex_unlock(&mtd_table_mutex);
BUG_ON(c < 0);
......@@ -236,7 +298,7 @@ void put_mtd_device(struct mtd_info *mtd)
}
/* default_mtd_writev - default mtd writev method for MTD devices that
* dont implement their own
* don't implement their own
*/
int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
......@@ -264,13 +326,14 @@ int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
return ret;
}
EXPORT_SYMBOL(add_mtd_device);
EXPORT_SYMBOL(del_mtd_device);
EXPORT_SYMBOL(get_mtd_device);
EXPORT_SYMBOL(put_mtd_device);
EXPORT_SYMBOL(register_mtd_user);
EXPORT_SYMBOL(unregister_mtd_user);
EXPORT_SYMBOL(default_mtd_writev);
EXPORT_SYMBOL_GPL(add_mtd_device);
EXPORT_SYMBOL_GPL(del_mtd_device);
EXPORT_SYMBOL_GPL(get_mtd_device);
EXPORT_SYMBOL_GPL(get_mtd_device_nm);
EXPORT_SYMBOL_GPL(put_mtd_device);
EXPORT_SYMBOL_GPL(register_mtd_user);
EXPORT_SYMBOL_GPL(unregister_mtd_user);
EXPORT_SYMBOL_GPL(default_mtd_writev);
#ifdef CONFIG_PROC_FS
......
......@@ -94,7 +94,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
if (from >= mtd->size)
return -EINVAL;
if (from + ops->len > mtd->size)
if (ops->datbuf && from + ops->len > mtd->size)
return -EINVAL;
res = part->master->read_oob(part->master, from + part->offset, ops);
......@@ -161,7 +161,7 @@ static int part_write_oob(struct mtd_info *mtd, loff_t to,
if (to >= mtd->size)
return -EINVAL;
if (to + ops->len > mtd->size)
if (ops->datbuf && to + ops->len > mtd->size)
return -EINVAL;
return part->master->write_oob(part->master, to + part->offset, ops);
}
......@@ -323,14 +323,13 @@ int add_mtd_partitions(struct mtd_info *master,
for (i = 0; i < nbparts; i++) {
/* allocate the partition structure */
slave = kmalloc (sizeof(*slave), GFP_KERNEL);
slave = kzalloc (sizeof(*slave), GFP_KERNEL);
if (!slave) {
printk ("memory allocation error while creating partitions for \"%s\"\n",
master->name);
del_mtd_partitions(master);
return -ENOMEM;
}
memset(slave, 0, sizeof(*slave));
list_add(&slave->list, &mtd_partitions);
/* set up the MTD object for this partition */
......@@ -341,6 +340,7 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.oobsize = master->oobsize;
slave->mtd.ecctype = master->ecctype;
slave->mtd.eccsize = master->eccsize;
slave->mtd.subpage_sft = master->subpage_sft;
slave->mtd.name = parts[i].name;
slave->mtd.bank_size = master->bank_size;
......
......@@ -90,6 +90,7 @@ config MTD_NAND_RTC_FROM4
depends on MTD_NAND && SH_SOLUTION_ENGINE
select REED_SOLOMON
select REED_SOLOMON_DEC8
select BITREVERSE
help
This enables the driver for the Renesas Technology AG-AND
flash interface board (FROM_BOARD4)
......@@ -132,6 +133,7 @@ config MTD_NAND_S3C2410_HWECC
config MTD_NAND_NDFC
tristate "NDFC NanD Flash Controller"
depends on MTD_NAND && 44x
select MTD_NAND_ECC_SMC
help
NDFC Nand Flash Controllers are integrated in EP44x SoCs
......@@ -219,6 +221,13 @@ config MTD_NAND_SHARPSL
tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
depends on MTD_NAND && ARCH_PXA
config MTD_NAND_CAFE
tristate "NAND support for OLPC CAFÉ chip"
depends on PCI
help
Use NAND flash attached to the CAFÉ chip designed for the $100
laptop.
config MTD_NAND_CS553X
tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)"
depends on MTD_NAND && X86_32 && (X86_PC || X86_GENERICARCH)
......@@ -232,6 +241,13 @@ config MTD_NAND_CS553X
If you say "m", the module will be called "cs553x_nand.ko".
config MTD_NAND_AT91
bool "Support for NAND Flash / SmartMedia on AT91"
depends on MTD_NAND && ARCH_AT91
help
Enables support for NAND Flash / Smart Media Card interface
on Atmel AT91 processors.
config MTD_NAND_NANDSIM
tristate "Support for NAND Flash Simulator"
depends on MTD_NAND && MTD_PARTITIONS
......
......@@ -6,6 +6,7 @@
obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_NAND_CAFE) += cafe_nand.o
obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o
obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
......@@ -22,5 +23,7 @@ obj-$(CONFIG_MTD_NAND_TS7250) += ts7250.o
obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
nand-objs = nand_base.o nand_bbt.o
nand-objs := nand_base.o nand_bbt.o
cafe_nand-objs := cafe.o cafe_ecc.o
/*
* drivers/mtd/nand/at91_nand.c
*
* Copyright (C) 2003 Rick Bronson
*
* Derived from drivers/mtd/nand/autcpu12.c
* Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
*
* Derived from drivers/mtd/spia.c
* Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
*
* 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/slab.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
#include <asm/sizes.h>
#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
struct at91_nand_host {
struct nand_chip nand_chip;
struct mtd_info mtd;
void __iomem *io_base;
struct at91_nand_data *board;
};
/*
* Hardware specific access to control-lines
*/
static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
{
struct nand_chip *nand_chip = mtd->priv;
struct at91_nand_host *host = nand_chip->priv;
if (cmd == NAND_CMD_NONE)
return;
if (ctrl & NAND_CLE)
writeb(cmd, host->io_base + (1 << host->board->cle));
else
writeb(cmd, host->io_base + (1 << host->board->ale));
}
/*
* Read the Device Ready pin.
*/
static int at91_nand_device_ready(struct mtd_info *mtd)
{
struct nand_chip *nand_chip = mtd->priv;
struct at91_nand_host *host = nand_chip->priv;
return at91_get_gpio_value(host->board->rdy_pin);
}
/*
* Enable NAND.
*/
static void at91_nand_enable(struct at91_nand_host *host)
{
if (host->board->enable_pin)
at91_set_gpio_value(host->board->enable_pin, 0);
}
/*
* Disable NAND.
*/
static void at91_nand_disable(struct at91_nand_host *host)
{
if (host->board->enable_pin)
at91_set_gpio_value(host->board->enable_pin, 1);
}
/*
* Probe for the NAND device.
*/
static int __init at91_nand_probe(struct platform_device *pdev)
{
struct at91_nand_host *host;
struct mtd_info *mtd;
struct nand_chip *nand_chip;
int res;
#ifdef CONFIG_MTD_PARTITIONS
struct mtd_partition *partitions = NULL;
int num_partitions = 0;
#endif
/* Allocate memory for the device structure (and zero it) */
host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL);
if (!host) {
printk(KERN_ERR "at91_nand: failed to allocate device structure.\n");
return -ENOMEM;
}
host->io_base = ioremap(pdev->resource[0].start,
pdev->resource[0].end - pdev->resource[0].start + 1);
if (host->io_base == NULL) {
printk(KERN_ERR "at91_nand: ioremap failed\n");
kfree(host);
return -EIO;
}
mtd = &host->mtd;
nand_chip = &host->nand_chip;
host->board = pdev->dev.platform_data;
nand_chip->priv = host; /* link the private data structures */
mtd->priv = nand_chip;
mtd->owner = THIS_MODULE;
/* Set address of NAND IO lines */
nand_chip->IO_ADDR_R = host->io_base;
nand_chip->IO_ADDR_W = host->io_base;
nand_chip->cmd_ctrl = at91_nand_cmd_ctrl;
nand_chip->dev_ready = at91_nand_device_ready;
nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
nand_chip->chip_delay = 20; /* 20us command delay time */
if (host->board->bus_width_16) /* 16-bit bus width */
nand_chip->options |= NAND_BUSWIDTH_16;
platform_set_drvdata(pdev, host);
at91_nand_enable(host);
if (host->board->det_pin) {
if (at91_get_gpio_value(host->board->det_pin)) {
printk ("No SmartMedia card inserted.\n");
res = ENXIO;
goto out;
}
}
/* Scan to find existance of the device */
if (nand_scan(mtd, 1)) {
res = -ENXIO;
goto out;
}
#ifdef CONFIG_MTD_PARTITIONS
if (host->board->partition_info)
partitions = host->board->partition_info(mtd->size, &num_partitions);
if ((!partitions) || (num_partitions == 0)) {
printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
res = ENXIO;
goto release;
}
res = add_mtd_partitions(mtd, partitions, num_partitions);
#else
res = add_mtd_device(mtd);
#endif
if (!res)
return res;
release:
nand_release(mtd);
out:
at91_nand_disable(host);
platform_set_drvdata(pdev, NULL);
iounmap(host->io_base);
kfree(host);
return res;
}
/*
* Remove a NAND device.
*/
static int __devexit at91_nand_remove(struct platform_device *pdev)
{
struct at91_nand_host *host = platform_get_drvdata(pdev);
struct mtd_info *mtd = &host->mtd;
nand_release(mtd);
at91_nand_disable(host);
iounmap(host->io_base);
kfree(host);
return 0;
}
static struct platform_driver at91_nand_driver = {
.probe = at91_nand_probe,
.remove = at91_nand_remove,
.driver = {
.name = "at91_nand",
.owner = THIS_MODULE,
},
};
static int __init at91_nand_init(void)
{
return platform_driver_register(&at91_nand_driver);
}
static void __exit at91_nand_exit(void)
{
platform_driver_unregister(&at91_nand_driver);
}
module_init(at91_nand_init);
module_exit(at91_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200");
此差异已折叠。
此差异已折叠。
......@@ -11,7 +11,7 @@
* published by the Free Software Foundation.
*
* Overview:
* This is a device driver for the NAND flash controller found on
* This is a device driver for the NAND flash controller found on
* the AMD CS5535/CS5536 companion chipsets for the Geode processor.
*
*/
......@@ -303,7 +303,7 @@ static int __init cs553x_init(void)
err = cs553x_init_one(i, !!(val & FLSH_MEM_IO), val & 0xFFFFFFFF);
}
/* Register all devices together here. This means we can easily hack it to
/* Register all devices together here. This means we can easily hack it to
do mtdconcat etc. if we want to. */
for (i = 0; i < NR_CS553X_CONTROLLERS; i++) {
if (cs553x_mtd[i]) {
......
......@@ -1635,13 +1635,12 @@ static int __init doc_probe(unsigned long physadr)
len = sizeof(struct mtd_info) +
sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
mtd = kmalloc(len, GFP_KERNEL);
mtd = kzalloc(len, GFP_KERNEL);
if (!mtd) {
printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
ret = -ENOMEM;
goto fail;
}
memset(mtd, 0, len);
nand = (struct nand_chip *) (mtd + 1);
doc = (struct doc_priv *) (nand + 1);
......
......@@ -362,7 +362,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
* access
*/
ofs += mtd->oobsize;
chip->ops.len = 2;
chip->ops.len = chip->ops.ooblen = 2;
chip->ops.datbuf = NULL;
chip->ops.oobbuf = buf;
chip->ops.ooboffs = chip->badblockpos & ~0x01;
......@@ -755,7 +755,7 @@ static int nand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
* nand_read_page_swecc - {REPLACABLE] software ecc based page read function
* nand_read_page_swecc - [REPLACABLE] software ecc based page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
......@@ -795,7 +795,7 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
* nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function
* nand_read_page_hwecc - [REPLACABLE] hardware ecc based page read function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
......@@ -839,7 +839,7 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
* nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
* nand_read_page_syndrome - [REPLACABLE] hardware ecc syndrom based page read
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: buffer to store read data
......@@ -897,12 +897,11 @@ static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
* @chip: nand chip structure
* @oob: oob destination address
* @ops: oob ops structure
* @len: size of oob to transfer
*/
static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
struct mtd_oob_ops *ops)
struct mtd_oob_ops *ops, size_t len)
{
size_t len = ops->ooblen;
switch(ops->mode) {
case MTD_OOB_PLACE:
......@@ -960,6 +959,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
int sndcmd = 1;
int ret = 0;
uint32_t readlen = ops->len;
uint32_t oobreadlen = ops->ooblen;
uint8_t *bufpoi, *oob, *buf;
stats = mtd->ecc_stats;
......@@ -971,7 +971,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
page = realpage & chip->pagemask;
col = (int)(from & (mtd->writesize - 1));
chip->oob_poi = chip->buffers->oobrbuf;
buf = ops->datbuf;
oob = ops->oobbuf;
......@@ -1007,10 +1006,17 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
if (unlikely(oob)) {
/* Raw mode does data:oob:data:oob */
if (ops->mode != MTD_OOB_RAW)
oob = nand_transfer_oob(chip, oob, ops);
else
buf = nand_transfer_oob(chip, buf, ops);
if (ops->mode != MTD_OOB_RAW) {
int toread = min(oobreadlen,
chip->ecc.layout->oobavail);
if (toread) {
oob = nand_transfer_oob(chip,
oob, ops, toread);
oobreadlen -= toread;
}
} else
buf = nand_transfer_oob(chip,
buf, ops, mtd->oobsize);
}
if (!(chip->options & NAND_NO_READRDY)) {
......@@ -1057,6 +1063,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
}
ops->retlen = ops->len - (size_t) readlen;
if (oob)
ops->oobretlen = ops->ooblen - oobreadlen;
if (ret)
return ret;
......@@ -1257,12 +1265,18 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
int page, realpage, chipnr, sndcmd = 1;
struct nand_chip *chip = mtd->priv;
int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
int readlen = ops->len;
int readlen = ops->ooblen;
int len;
uint8_t *buf = ops->oobbuf;
DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
(unsigned long long)from, readlen);
if (ops->mode == MTD_OOB_RAW)
len = mtd->oobsize;
else
len = chip->ecc.layout->oobavail;
chipnr = (int)(from >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
......@@ -1270,11 +1284,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
realpage = (int)(from >> chip->page_shift);
page = realpage & chip->pagemask;
chip->oob_poi = chip->buffers->oobrbuf;
while(1) {
sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
buf = nand_transfer_oob(chip, buf, ops);
len = min(len, readlen);
buf = nand_transfer_oob(chip, buf, ops, len);
if (!(chip->options & NAND_NO_READRDY)) {
/*
......@@ -1289,7 +1303,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
nand_wait_ready(mtd);
}
readlen -= ops->ooblen;
readlen -= len;
if (!readlen)
break;
......@@ -1311,7 +1325,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
sndcmd = 1;
}
ops->retlen = ops->len;
ops->oobretlen = ops->ooblen;
return 0;
}
......@@ -1332,7 +1346,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
ops->retlen = 0;
/* Do not allow reads past end of device */
if ((from + ops->len) > mtd->size) {
if (ops->datbuf && (from + ops->len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt read beyond end of device\n");
return -EINVAL;
......@@ -1375,7 +1389,7 @@ static void nand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
* nand_write_page_swecc - {REPLACABLE] software ecc based page write function
* nand_write_page_swecc - [REPLACABLE] software ecc based page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
......@@ -1401,7 +1415,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
* nand_write_page_hwecc - {REPLACABLE] hardware ecc based page write function
* nand_write_page_hwecc - [REPLACABLE] hardware ecc based page write function
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
......@@ -1429,7 +1443,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
}
/**
* nand_write_page_syndrome - {REPLACABLE] hardware ecc syndrom based page write
* nand_write_page_syndrome - [REPLACABLE] hardware ecc syndrom based page write
* @mtd: mtd info structure
* @chip: nand chip info structure
* @buf: data buffer
......@@ -1577,7 +1591,7 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
return NULL;
}
#define NOTALIGNED(x) (x & (mtd->writesize-1)) != 0
#define NOTALIGNED(x) (x & (chip->subpagesize - 1)) != 0
/**
* nand_do_write_ops - [Internal] NAND write with ECC
......@@ -1590,15 +1604,16 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob,
static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
int chipnr, realpage, page, blockmask;
int chipnr, realpage, page, blockmask, column;
struct nand_chip *chip = mtd->priv;
uint32_t writelen = ops->len;
uint8_t *oob = ops->oobbuf;
uint8_t *buf = ops->datbuf;
int bytes = mtd->writesize;
int ret;
int ret, subpage;
ops->retlen = 0;
if (!writelen)
return 0;
/* reject writes, which are not page aligned */
if (NOTALIGNED(to) || NOTALIGNED(ops->len)) {
......@@ -1607,8 +1622,11 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
return -EINVAL;
}
if (!writelen)
return 0;
column = to & (mtd->writesize - 1);
subpage = column || (writelen & (mtd->writesize - 1));
if (subpage && oob)
return -EINVAL;
chipnr = (int)(to >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
......@@ -1626,15 +1644,29 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
(chip->pagebuf << chip->page_shift) < (to + ops->len))
chip->pagebuf = -1;
chip->oob_poi = chip->buffers->oobwbuf;
/* If we're not given explicit OOB data, let it be 0xFF */
if (likely(!oob))
memset(chip->oob_poi, 0xff, mtd->oobsize);
while(1) {
int bytes = mtd->writesize;
int cached = writelen > bytes && page != blockmask;
uint8_t *wbuf = buf;
/* Partial page write ? */
if (unlikely(column || writelen < (mtd->writesize - 1))) {
cached = 0;
bytes = min_t(int, bytes - column, (int) writelen);
chip->pagebuf = -1;
memset(chip->buffers->databuf, 0xff, mtd->writesize);
memcpy(&chip->buffers->databuf[column], buf, bytes);
wbuf = chip->buffers->databuf;
}
if (unlikely(oob))
oob = nand_fill_oob(chip, oob, ops);
ret = chip->write_page(mtd, chip, buf, page, cached,
ret = chip->write_page(mtd, chip, wbuf, page, cached,
(ops->mode == MTD_OOB_RAW));
if (ret)
break;
......@@ -1643,6 +1675,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if (!writelen)
break;
column = 0;
buf += bytes;
realpage++;
......@@ -1655,10 +1688,9 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
}
}
if (unlikely(oob))
memset(chip->oob_poi, 0xff, mtd->oobsize);
ops->retlen = ops->len - writelen;
if (unlikely(oob))
ops->oobretlen = ops->ooblen;
return ret;
}
......@@ -1714,10 +1746,10 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
struct nand_chip *chip = mtd->priv;
DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
(unsigned int)to, (int)ops->len);
(unsigned int)to, (int)ops->ooblen);
/* Do not allow write past end of page */
if ((ops->ooboffs + ops->len) > mtd->oobsize) {
if ((ops->ooboffs + ops->ooblen) > mtd->oobsize) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
"Attempt to write past end of page\n");
return -EINVAL;
......@@ -1745,7 +1777,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
if (page == chip->pagebuf)
chip->pagebuf = -1;
chip->oob_poi = chip->buffers->oobwbuf;
memset(chip->oob_poi, 0xff, mtd->oobsize);
nand_fill_oob(chip, ops->oobbuf, ops);
status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
......@@ -1754,7 +1785,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
if (status)
return status;
ops->retlen = ops->len;
ops->oobretlen = ops->ooblen;
return 0;
}
......@@ -1774,7 +1805,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
ops->retlen = 0;
/* Do not allow writes past end of device */
if ((to + ops->len) > mtd->size) {
if (ops->datbuf && (to + ops->len) > mtd->size) {
DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
"Attempt read beyond end of device\n");
return -EINVAL;
......@@ -2188,8 +2219,8 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
/* Newer devices have all the information in additional id bytes */
if (!type->pagesize) {
int extid;
/* The 3rd id byte contains non relevant data ATM */
extid = chip->read_byte(mtd);
/* The 3rd id byte holds MLC / multichip data */
chip->cellinfo = chip->read_byte(mtd);
/* The 4th id byte is the important one */
extid = chip->read_byte(mtd);
/* Calc pagesize */
......@@ -2349,8 +2380,8 @@ int nand_scan_tail(struct mtd_info *mtd)
if (!chip->buffers)
return -ENOMEM;
/* Preset the internal oob write buffer */
memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize);
/* Set the internal oob buffer location, just after the page data */
chip->oob_poi = chip->buffers->databuf + mtd->writesize;
/*
* If no default placement scheme is given, select an appropriate one
......@@ -2469,6 +2500,24 @@ int nand_scan_tail(struct mtd_info *mtd)
}
chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
/*
* Allow subpage writes up to ecc.steps. Not possible for MLC
* FLASH.
*/
if (!(chip->options & NAND_NO_SUBPAGE_WRITE) &&
!(chip->cellinfo & NAND_CI_CELLTYPE_MSK)) {
switch(chip->ecc.steps) {
case 2:
mtd->subpage_sft = 1;
break;
case 4:
case 8:
mtd->subpage_sft = 2;
break;
}
}
chip->subpagesize = mtd->writesize >> mtd->subpage_sft;
/* Initialize state */
chip->state = FL_READY;
......
......@@ -333,7 +333,6 @@ static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,
struct mtd_oob_ops ops;
int j, ret;
ops.len = mtd->oobsize;
ops.ooblen = mtd->oobsize;
ops.oobbuf = buf;
ops.ooboffs = 0;
......@@ -676,10 +675,10 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
"bad block table\n");
}
/* Read oob data */
ops.len = (len >> this->page_shift) * mtd->oobsize;
ops.ooblen = (len >> this->page_shift) * mtd->oobsize;
ops.oobbuf = &buf[len];
res = mtd->read_oob(mtd, to + mtd->writesize, &ops);
if (res < 0 || ops.retlen != ops.len)
if (res < 0 || ops.oobretlen != ops.ooblen)
goto outerr;
/* Calc the byte offset in the buffer */
......@@ -961,14 +960,12 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
struct nand_bbt_descr *md = this->bbt_md;
len = mtd->size >> (this->bbt_erase_shift + 2);
/* Allocate memory (2bit per block) */
this->bbt = kmalloc(len, GFP_KERNEL);
/* Allocate memory (2bit per block) and clear the memory bad block table */
this->bbt = kzalloc(len, GFP_KERNEL);
if (!this->bbt) {
printk(KERN_ERR "nand_scan_bbt: Out of memory\n");
return -ENOMEM;
}
/* Clear the memory bad block table */
memset(this->bbt, 0x00, len);
/* If no primary table decriptor is given, scan the device
* to build a memory based bad block table
......
......@@ -112,7 +112,7 @@ int nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
tmp2 |= (reg2 & 0x01) << 0; /* B7 -> B0 */
/* Calculate final ECC code */
#ifdef CONFIG_NAND_ECC_SMC
#ifdef CONFIG_MTD_NAND_ECC_SMC
ecc_code[0] = ~tmp2;
ecc_code[1] = ~tmp1;
#else
......@@ -148,7 +148,7 @@ int nand_correct_data(struct mtd_info *mtd, u_char *dat,
{
uint8_t s0, s1, s2;
#ifdef CONFIG_NAND_ECC_SMC
#ifdef CONFIG_MTD_NAND_ECC_SMC
s0 = calc_ecc[0] ^ read_ecc[0];
s1 = calc_ecc[1] ^ read_ecc[1];
s2 = calc_ecc[2] ^ read_ecc[2];
......
......@@ -37,10 +37,6 @@
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#ifdef CONFIG_NS_ABS_POS
#include <asm/io.h>
#endif
/* Default simulator parameters values */
#if !defined(CONFIG_NANDSIM_FIRST_ID_BYTE) || \
......@@ -164,7 +160,7 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
/* After a command is input, the simulator goes to one of the following states */
#define STATE_CMD_READ0 0x00000001 /* read data from the beginning of page */
#define STATE_CMD_READ1 0x00000002 /* read data from the second half of page */
#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */
#define STATE_CMD_READSTART 0x00000003 /* read data second command (large page devices) */
#define STATE_CMD_PAGEPROG 0x00000004 /* start page programm */
#define STATE_CMD_READOOB 0x00000005 /* read OOB area */
#define STATE_CMD_ERASE1 0x00000006 /* sector erase first command */
......@@ -230,6 +226,14 @@ MODULE_PARM_DESC(dbg, "Output debug information if not zero");
*/
#define NS_MAX_PREVSTATES 1
/*
* A union to represent flash memory contents and flash buffer.
*/
union ns_mem {
u_char *byte; /* for byte access */
uint16_t *word; /* for 16-bit word access */
};
/*
* The structure which describes all the internal simulator data.
*/
......@@ -247,17 +251,11 @@ struct nandsim {
uint16_t npstates; /* number of previous states saved */
uint16_t stateidx; /* current state index */
/* The simulated NAND flash image */
union flash_media {
u_char *byte;
uint16_t *word;
} mem;
/* The simulated NAND flash pages array */
union ns_mem *pages;
/* Internal buffer of page + OOB size bytes */
union internal_buffer {
u_char *byte; /* for byte access */
uint16_t *word; /* for 16-bit word access */
} buf;
union ns_mem buf;
/* NAND flash "geometry" */
struct nandsin_geometry {
......@@ -345,13 +343,50 @@ static struct mtd_info *nsmtd;
static u_char ns_verify_buf[NS_LARGEST_PAGE_SIZE];
/*
* Allocate array of page pointers and initialize the array to NULL
* pointers.
*
* RETURNS: 0 if success, -ENOMEM if memory alloc fails.
*/
static int alloc_device(struct nandsim *ns)
{
int i;
ns->pages = vmalloc(ns->geom.pgnum * sizeof(union ns_mem));
if (!ns->pages) {
NS_ERR("alloc_map: unable to allocate page array\n");
return -ENOMEM;
}
for (i = 0; i < ns->geom.pgnum; i++) {
ns->pages[i].byte = NULL;
}
return 0;
}
/*
* Free any allocated pages, and free the array of page pointers.
*/
static void free_device(struct nandsim *ns)
{
int i;
if (ns->pages) {
for (i = 0; i < ns->geom.pgnum; i++) {
if (ns->pages[i].byte)
kfree(ns->pages[i].byte);
}
vfree(ns->pages);
}
}
/*
* Initialize the nandsim structure.
*
* RETURNS: 0 if success, -ERRNO if failure.
*/
static int
init_nandsim(struct mtd_info *mtd)
static int init_nandsim(struct mtd_info *mtd)
{
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
struct nandsim *ns = (struct nandsim *)(chip->priv);
......@@ -405,7 +440,7 @@ init_nandsim(struct mtd_info *mtd)
}
} else {
if (ns->geom.totsz <= (128 << 20)) {
ns->geom.pgaddrbytes = 5;
ns->geom.pgaddrbytes = 4;
ns->geom.secaddrbytes = 2;
} else {
ns->geom.pgaddrbytes = 5;
......@@ -439,23 +474,8 @@ init_nandsim(struct mtd_info *mtd)
printk("sector address bytes: %u\n", ns->geom.secaddrbytes);
printk("options: %#x\n", ns->options);
/* Map / allocate and initialize the flash image */
#ifdef CONFIG_NS_ABS_POS
ns->mem.byte = ioremap(CONFIG_NS_ABS_POS, ns->geom.totszoob);
if (!ns->mem.byte) {
NS_ERR("init_nandsim: failed to map the NAND flash image at address %p\n",
(void *)CONFIG_NS_ABS_POS);
return -ENOMEM;
}
#else
ns->mem.byte = vmalloc(ns->geom.totszoob);
if (!ns->mem.byte) {
NS_ERR("init_nandsim: unable to allocate %u bytes for flash image\n",
ns->geom.totszoob);
return -ENOMEM;
}
memset(ns->mem.byte, 0xFF, ns->geom.totszoob);
#endif
if (alloc_device(ns) != 0)
goto error;
/* Allocate / initialize the internal buffer */
ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
......@@ -474,11 +494,7 @@ init_nandsim(struct mtd_info *mtd)
return 0;
error:
#ifdef CONFIG_NS_ABS_POS
iounmap(ns->mem.byte);
#else
vfree(ns->mem.byte);
#endif
free_device(ns);
return -ENOMEM;
}
......@@ -486,16 +502,10 @@ init_nandsim(struct mtd_info *mtd)
/*
* Free the nandsim structure.
*/
static void
free_nandsim(struct nandsim *ns)
static void free_nandsim(struct nandsim *ns)
{
kfree(ns->buf.byte);
#ifdef CONFIG_NS_ABS_POS
iounmap(ns->mem.byte);
#else
vfree(ns->mem.byte);
#endif
free_device(ns);
return;
}
......@@ -503,8 +513,7 @@ free_nandsim(struct nandsim *ns)
/*
* Returns the string representation of 'state' state.
*/
static char *
get_state_name(uint32_t state)
static char *get_state_name(uint32_t state)
{
switch (NS_STATE(state)) {
case STATE_CMD_READ0:
......@@ -562,8 +571,7 @@ get_state_name(uint32_t state)
*
* RETURNS: 1 if wrong command, 0 if right.
*/
static int
check_command(int cmd)
static int check_command(int cmd)
{
switch (cmd) {
......@@ -589,8 +597,7 @@ check_command(int cmd)
/*
* Returns state after command is accepted by command number.
*/
static uint32_t
get_state_by_command(unsigned command)
static uint32_t get_state_by_command(unsigned command)
{
switch (command) {
case NAND_CMD_READ0:
......@@ -626,8 +633,7 @@ get_state_by_command(unsigned command)
/*
* Move an address byte to the correspondent internal register.
*/
static inline void
accept_addr_byte(struct nandsim *ns, u_char bt)
static inline void accept_addr_byte(struct nandsim *ns, u_char bt)
{
uint byte = (uint)bt;
......@@ -645,8 +651,7 @@ accept_addr_byte(struct nandsim *ns, u_char bt)
/*
* Switch to STATE_READY state.
*/
static inline void
switch_to_ready_state(struct nandsim *ns, u_char status)
static inline void switch_to_ready_state(struct nandsim *ns, u_char status)
{
NS_DBG("switch_to_ready_state: switch to %s state\n", get_state_name(STATE_READY));
......@@ -705,8 +710,7 @@ switch_to_ready_state(struct nandsim *ns, u_char status)
* -1 - several matches.
* 0 - operation is found.
*/
static int
find_operation(struct nandsim *ns, uint32_t flag)
static int find_operation(struct nandsim *ns, uint32_t flag)
{
int opsfound = 0;
int i, j, idx = 0;
......@@ -790,15 +794,94 @@ find_operation(struct nandsim *ns, uint32_t flag)
return -1;
}
/*
* Returns a pointer to the current page.
*/
static inline union ns_mem *NS_GET_PAGE(struct nandsim *ns)
{
return &(ns->pages[ns->regs.row]);
}
/*
* Retuns a pointer to the current byte, within the current page.
*/
static inline u_char *NS_PAGE_BYTE_OFF(struct nandsim *ns)
{
return NS_GET_PAGE(ns)->byte + ns->regs.column + ns->regs.off;
}
/*
* Fill the NAND buffer with data read from the specified page.
*/
static void read_page(struct nandsim *ns, int num)
{
union ns_mem *mypage;
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
NS_DBG("read_page: page %d not allocated\n", ns->regs.row);
memset(ns->buf.byte, 0xFF, num);
} else {
NS_DBG("read_page: page %d allocated, reading from %d\n",
ns->regs.row, ns->regs.column + ns->regs.off);
memcpy(ns->buf.byte, NS_PAGE_BYTE_OFF(ns), num);
}
}
/*
* Erase all pages in the specified sector.
*/
static void erase_sector(struct nandsim *ns)
{
union ns_mem *mypage;
int i;
mypage = NS_GET_PAGE(ns);
for (i = 0; i < ns->geom.pgsec; i++) {
if (mypage->byte != NULL) {
NS_DBG("erase_sector: freeing page %d\n", ns->regs.row+i);
kfree(mypage->byte);
mypage->byte = NULL;
}
mypage++;
}
}
/*
* Program the specified page with the contents from the NAND buffer.
*/
static int prog_page(struct nandsim *ns, int num)
{
int i;
union ns_mem *mypage;
u_char *pg_off;
mypage = NS_GET_PAGE(ns);
if (mypage->byte == NULL) {
NS_DBG("prog_page: allocating page %d\n", ns->regs.row);
mypage->byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL);
if (mypage->byte == NULL) {
NS_ERR("prog_page: error allocating memory for page %d\n", ns->regs.row);
return -1;
}
memset(mypage->byte, 0xFF, ns->geom.pgszoob);
}
pg_off = NS_PAGE_BYTE_OFF(ns);
for (i = 0; i < num; i++)
pg_off[i] &= ns->buf.byte[i];
return 0;
}
/*
* If state has any action bit, perform this action.
*
* RETURNS: 0 if success, -1 if error.
*/
static int
do_state_action(struct nandsim *ns, uint32_t action)
static int do_state_action(struct nandsim *ns, uint32_t action)
{
int i, num;
int num;
int busdiv = ns->busw == 8 ? 1 : 2;
action &= ACTION_MASK;
......@@ -822,7 +905,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
break;
}
num = ns->geom.pgszoob - ns->regs.off - ns->regs.column;
memcpy(ns->buf.byte, ns->mem.byte + NS_RAW_OFFSET(ns) + ns->regs.off, num);
read_page(ns, num);
NS_DBG("do_state_action: (ACTION_CPY:) copy %d bytes to int buf, raw offset %d\n",
num, NS_RAW_OFFSET(ns) + ns->regs.off);
......@@ -863,7 +946,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
ns->regs.row, NS_RAW_OFFSET(ns));
NS_LOG("erase sector %d\n", ns->regs.row >> (ns->geom.secshift - ns->geom.pgshift));
memset(ns->mem.byte + NS_RAW_OFFSET(ns), 0xFF, ns->geom.secszoob);
erase_sector(ns);
NS_MDELAY(erase_delay);
......@@ -886,8 +969,8 @@ do_state_action(struct nandsim *ns, uint32_t action)
return -1;
}
for (i = 0; i < num; i++)
ns->mem.byte[NS_RAW_OFFSET(ns) + ns->regs.off + i] &= ns->buf.byte[i];
if (prog_page(ns, num) == -1)
return -1;
NS_DBG("do_state_action: copy %d bytes from int buf to (%#x, %#x), raw off = %d\n",
num, ns->regs.row, ns->regs.column, NS_RAW_OFFSET(ns) + ns->regs.off);
......@@ -928,8 +1011,7 @@ do_state_action(struct nandsim *ns, uint32_t action)
/*
* Switch simulator's state.
*/
static void
switch_state(struct nandsim *ns)
static void switch_state(struct nandsim *ns)
{
if (ns->op) {
/*
......@@ -1070,8 +1152,7 @@ switch_state(struct nandsim *ns)
}
}
static u_char
ns_nand_read_byte(struct mtd_info *mtd)
static u_char ns_nand_read_byte(struct mtd_info *mtd)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
u_char outb = 0x00;
......@@ -1144,8 +1225,7 @@ ns_nand_read_byte(struct mtd_info *mtd)
return outb;
}
static void
ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
......@@ -1308,15 +1388,13 @@ static void ns_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int bitmask)
ns_nand_write_byte(mtd, cmd);
}
static int
ns_device_ready(struct mtd_info *mtd)
static int ns_device_ready(struct mtd_info *mtd)
{
NS_DBG("device_ready\n");
return 1;
}
static uint16_t
ns_nand_read_word(struct mtd_info *mtd)
static uint16_t ns_nand_read_word(struct mtd_info *mtd)
{
struct nand_chip *chip = (struct nand_chip *)mtd->priv;
......@@ -1325,8 +1403,7 @@ ns_nand_read_word(struct mtd_info *mtd)
return chip->read_byte(mtd) | (chip->read_byte(mtd) << 8);
}
static void
ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
static void ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
......@@ -1353,8 +1430,7 @@ ns_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
}
static void
ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
static void ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
struct nandsim *ns = (struct nandsim *)((struct nand_chip *)mtd->priv)->priv;
......@@ -1407,8 +1483,7 @@ ns_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
return;
}
static int
ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
static int ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
{
ns_nand_read_buf(mtd, (u_char *)&ns_verify_buf[0], len);
......@@ -1436,14 +1511,12 @@ static int __init ns_init_module(void)
}
/* Allocate and initialize mtd_info, nand_chip and nandsim structures */
nsmtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
nsmtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip)
+ sizeof(struct nandsim), GFP_KERNEL);
if (!nsmtd) {
NS_ERR("unable to allocate core structures.\n");
return -ENOMEM;
}
memset(nsmtd, 0, sizeof(struct mtd_info) + sizeof(struct nand_chip) +
sizeof(struct nandsim));
chip = (struct nand_chip *)(nsmtd + 1);
nsmtd->priv = (void *)chip;
nand = (struct nandsim *)(chip + 1);
......
......@@ -56,7 +56,7 @@ static void ndfc_select_chip(struct mtd_info *mtd, int chip)
ccr |= NDFC_CCR_BS(chip + pchip->chip_offset);
} else
ccr |= NDFC_CCR_RESET_CE;
writel(ccr, ndfc->ndfcbase + NDFC_CCR);
__raw_writel(ccr, ndfc->ndfcbase + NDFC_CCR);
}
static void ndfc_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
......
......@@ -24,6 +24,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/rslib.h>
#include <linux/bitrev.h>
#include <linux/module.h>
#include <linux/mtd/compatmac.h>
#include <linux/mtd/mtd.h>
......@@ -152,47 +153,6 @@ static struct nand_ecclayout rtc_from4_nand_oobinfo = {
.oobfree = {{32, 32}}
};
/* Aargh. I missed the reversed bit order, when I
* was talking to Renesas about the FPGA.
*
* The table is used for bit reordering and inversion
* of the ecc byte which we get from the FPGA
*/
static uint8_t revbits[256] = {
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
};
#endif
/*
......@@ -397,7 +357,7 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
/* Read the syndrom pattern from the FPGA and correct the bitorder */
rs_ecc = (volatile unsigned short *)(rtc_from4_fio_base + RTC_FROM4_RS_ECC);
for (i = 0; i < 8; i++) {
ecc[i] = revbits[(*rs_ecc) & 0xFF];
ecc[i] = bitrev8(*rs_ecc);
rs_ecc++;
}
......@@ -496,7 +456,7 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this,
rtn = nand_do_read(mtd, page, len, &retlen, buf);
/* if read failed or > 1-bit error corrected */
if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) {
if (rtn || (mtd->ecc_stats.corrected - corrected) > 1)
er_stat |= 1 << 1;
kfree(buf);
}
......
......@@ -283,7 +283,7 @@ static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd,
unsigned int ctrl)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
if (cmd == NAND_CMD_NONE)
return;
......
......@@ -57,17 +57,16 @@ static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name);
nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
nftl = kzalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
if (!nftl) {
printk(KERN_WARNING "NFTL: out of memory for data structures\n");
return;
}
memset(nftl, 0, sizeof(*nftl));
nftl->mbd.mtd = mtd;
nftl->mbd.devnum = -1;
nftl->mbd.blksize = 512;
nftl->mbd.tr = tr;
if (NFTL_mount(nftl) < 0) {
......@@ -147,10 +146,9 @@ int nftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;
res = mtd->read_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
*retlen = ops.oobretlen;
return res;
}
......@@ -168,10 +166,9 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
ops.ooblen = len;
ops.oobbuf = buf;
ops.datbuf = NULL;
ops.len = len;
res = mtd->write_oob(mtd, offs & ~(mtd->writesize - 1), &ops);
*retlen = ops.retlen;
*retlen = ops.oobretlen;
return res;
}
......@@ -797,6 +794,7 @@ static struct mtd_blktrans_ops nftl_tr = {
.name = "nftl",
.major = NFTL_MAJOR,
.part_bits = NFTL_PARTN_BITS,
.blksize = 512,
.getgeo = nftl_getgeo,
.readsect = nftl_readblock,
#ifdef CONFIG_NFTL_RW
......
......@@ -45,12 +45,10 @@ static int __devinit generic_onenand_probe(struct device *dev)
unsigned long size = res->end - res->start + 1;
int err;
info = kmalloc(sizeof(struct onenand_info), GFP_KERNEL);
info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
memset(info, 0, sizeof(struct onenand_info));
if (!request_mem_region(res->start, size, dev->driver->name)) {
err = -EBUSY;
goto out_free_info;
......@@ -63,6 +61,7 @@ static int __devinit generic_onenand_probe(struct device *dev)
}
info->onenand.mmcontrol = pdata->mmcontrol;
info->onenand.irq = platform_get_irq(pdev, 0);
info->mtd.name = pdev->dev.bus_id;
info->mtd.priv = &info->onenand;
......
此差异已折叠。
......@@ -93,13 +93,15 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
ret = onenand_do_read_oob(mtd, from + j * mtd->writesize + bd->offs,
readlen, &retlen, &buf[0]);
if (ret)
/* If it is a initial bad block, just ignore it */
if (ret && !(ret & ONENAND_CTRL_LOAD))
return ret;
if (check_short_pattern(&buf[j * scanlen], scanlen, mtd->writesize, bd)) {
bbm->bbt[i >> 3] |= 0x03 << (i & 0x6);
printk(KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
i >> 1, (unsigned int) from);
mtd->ecc_stats.badblocks++;
break;
}
}
......@@ -177,14 +179,12 @@ int onenand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)
int len, ret = 0;
len = mtd->size >> (this->erase_shift + 2);
/* Allocate memory (2bit per block) */
bbm->bbt = kmalloc(len, GFP_KERNEL);
/* Allocate memory (2bit per block) and clear the memory bad block table */
bbm->bbt = kzalloc(len, GFP_KERNEL);
if (!bbm->bbt) {
printk(KERN_ERR "onenand_scan_bbt: Out of memory\n");
return -ENOMEM;
}
/* Clear the memory bad block table */
memset(bbm->bbt, 0x00, len);
/* Set the bad block position */
bbm->badblockpos = ONENAND_BADBLOCK_POS;
......@@ -230,14 +230,12 @@ int onenand_default_bbt(struct mtd_info *mtd)
struct onenand_chip *this = mtd->priv;
struct bbm_info *bbm;
this->bbm = kmalloc(sizeof(struct bbm_info), GFP_KERNEL);
this->bbm = kzalloc(sizeof(struct bbm_info), GFP_KERNEL);
if (!this->bbm)
return -ENOMEM;
bbm = this->bbm;
memset(bbm, 0, sizeof(struct bbm_info));
/* 1KB page has same configuration as 2KB page */
if (!bbm->badblock_pattern)
bbm->badblock_pattern = &largepage_memorybased;
......
......@@ -96,7 +96,19 @@ static int parse_redboot_partitions(struct mtd_info *master,
*/
if (swab32(buf[i].size) == master->erasesize) {
int j;
for (j = 0; j < numslots && buf[j].name[0] != 0xff; ++j) {
for (j = 0; j < numslots; ++j) {
/* A single 0xff denotes a deleted entry.
* Two of them in a row is the end of the table.
*/
if (buf[j].name[0] == 0xff) {
if (buf[j].name[1] == 0xff) {
break;
} else {
continue;
}
}
/* The unsigned long fields were written with the
* wrong byte sex, name and pad have no byte sex.
*/
......@@ -110,6 +122,9 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
}
break;
} else {
/* re-calculate of real numslots */
numslots = buf[i].size / sizeof(struct fis_image_desc);
}
}
if (i == numslots) {
......@@ -123,8 +138,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
for (i = 0; i < numslots; i++) {
struct fis_list *new_fl, **prev;
if (buf[i].name[0] == 0xff)
continue;
if (buf[i].name[0] == 0xff) {
if (buf[i].name[1] == 0xff) {
break;
} else {
continue;
}
}
if (!redboot_checksum(&buf[i]))
break;
......@@ -165,15 +185,13 @@ static int parse_redboot_partitions(struct mtd_info *master,
}
}
#endif
parts = kmalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
if (!parts) {
ret = -ENOMEM;
goto out;
}
memset(parts, 0, sizeof(*parts)*nrparts + nulllen + namelen);
nullname = (char *)&parts[nrparts];
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if (nulllen > 0) {
......
......@@ -787,7 +787,6 @@ static void rfd_ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
if (scan_header(part) == 0) {
part->mbd.size = part->sector_count;
part->mbd.blksize = SECTOR_SIZE;
part->mbd.tr = tr;
part->mbd.devnum = -1;
if (!(mtd->flags & MTD_WRITEABLE))
......@@ -829,6 +828,8 @@ struct mtd_blktrans_ops rfd_ftl_tr = {
.name = "rfd",
.major = RFD_FTL_MAJOR,
.part_bits = PART_BITS,
.blksize = SECTOR_SIZE,
.readsect = rfd_ftl_readsect,
.writesect = rfd_ftl_writesect,
.getgeo = rfd_ftl_getgeo,
......
......@@ -172,13 +172,12 @@ static int read_raw_oob(struct mtd_info *mtd, loff_t offs, uint8_t *buf)
ops.mode = MTD_OOB_RAW;
ops.ooboffs = 0;
ops.ooblen = mtd->oobsize;
ops.len = OOB_SIZE;
ops.ooblen = OOB_SIZE;
ops.oobbuf = buf;
ops.datbuf = NULL;
ret = mtd->read_oob(mtd, offs, &ops);
if (ret < 0 || ops.retlen != OOB_SIZE)
if (ret < 0 || ops.oobretlen != OOB_SIZE)
return -1;
return 0;
......@@ -312,7 +311,6 @@ static void ssfdcr_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
ssfdc->mbd.mtd = mtd;
ssfdc->mbd.devnum = -1;
ssfdc->mbd.blksize = SECTOR_SIZE;
ssfdc->mbd.tr = tr;
ssfdc->mbd.readonly = 1;
......@@ -447,6 +445,7 @@ static struct mtd_blktrans_ops ssfdcr_tr = {
.name = "ssfdc",
.major = SSFDCR_MAJOR,
.part_bits = SSFDCR_PARTN_BITS,
.blksize = SECTOR_SIZE,
.getgeo = ssfdcr_getgeo,
.readsect = ssfdcr_readsect,
.add_mtd = ssfdcr_add_mtd,
......
......@@ -17,6 +17,7 @@
*
*/
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/blkdev.h>
#include <linux/jffs.h>
#include "jffs_fm.h"
......@@ -104,7 +105,7 @@ jffs_build_begin(struct jffs_control *c, int unit)
mtd = get_mtd_device(NULL, unit);
if (!mtd) {
if (IS_ERR(mtd)) {
kfree(fmc);
DJM(no_jffs_fmcontrol--);
return NULL;
......
......@@ -178,8 +178,8 @@ __jffs2_dbg_acct_paranoia_check_nolock(struct jffs2_sb_info *c,
while (ref2) {
uint32_t totlen = ref_totlen(c, jeb, ref2);
if (ref2->flash_offset < jeb->offset ||
ref2->flash_offset > jeb->offset + c->sector_size) {
if (ref_offset(ref2) < jeb->offset ||
ref_offset(ref2) > jeb->offset + c->sector_size) {
JFFS2_ERROR("node_ref %#08x shouldn't be in block at %#08x.\n",
ref_offset(ref2), jeb->offset);
goto error;
......
......@@ -13,6 +13,7 @@
#ifndef _JFFS2_DEBUG_H_
#define _JFFS2_DEBUG_H_
#include <linux/sched.h>
#ifndef CONFIG_JFFS2_FS_DEBUG
#define CONFIG_JFFS2_FS_DEBUG 0
......
......@@ -502,12 +502,11 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
if (ret)
return ret;
c->inocache_list = kmalloc(INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
c->inocache_list = kcalloc(INOCACHE_HASHSIZE, sizeof(struct jffs2_inode_cache *), GFP_KERNEL);
if (!c->inocache_list) {
ret = -ENOMEM;
goto out_wbuf;
}
memset(c->inocache_list, 0, INOCACHE_HASHSIZE * sizeof(struct jffs2_inode_cache *));
jffs2_init_xattr_subsystem(c);
......
......@@ -838,6 +838,8 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
for (raw = f->inocache->nodes; raw != (void *)f->inocache; raw = raw->next_in_ino) {
cond_resched();
/* We only care about obsolete ones */
if (!(ref_obsolete(raw)))
continue;
......
......@@ -294,23 +294,21 @@ static inline int jffs2_encode_dev(union jffs2_device_node *jdev, dev_t rdev)
static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
{
struct rb_node *node = root->rb_node;
struct rb_node *node = rb_first(root);
if (!node)
return NULL;
while(node->rb_left)
node = node->rb_left;
return rb_entry(node, struct jffs2_node_frag, rb);
}
static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
{
struct rb_node *node = root->rb_node;
struct rb_node *node = rb_last(root);
if (!node)
return NULL;
while(node->rb_right)
node = node->rb_right;
return rb_entry(node, struct jffs2_node_frag, rb);
}
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -51,7 +51,7 @@ static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
*/
if (!p) {
printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
printk(KERN_ERR "jffs2_follow_link(): can't find symlink target\n");
p = ERR_PTR(-EIO);
}
D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->target));
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册