Merge branch 'for-linus-1' of git://git.infradead.org/mtd-2.6

* 'for-linus-1' of git://git.infradead.org/mtd-2.6: (49 commits)
  mtd: mtdswap: fix compilation warning
  mtdswap: kill strict error handling option
  mtd: nand: enable software BCH ECC in nand simulator
  mtd: nand: add software BCH ECC support
  mtd: fix printf format warnings, mostly lack of %zd for size_t, in mtdswap
  mtd: sm_rtl: check kmalloc return value
  mtd: cfi: add support for AMIC flashes (e.g. A29L160AT)
  lib: add shared BCH ECC library
  mtd: mxc_nand: fix OOB corruption when page size > 2KiB
  mtd: DaVinci: Removed header file that is not required
  mtd: pxa3xx_nand: clean the keep configure code
  mtd: pxa3xx_nand: mtd scan id process could be defined by driver itself
  mtd: pxa3xx_nand: unify prepare command
  mtd: pxa3xx_nand: discard wait_for_event,write_cmd,__readid function
  mtd: pxa3xx_nand: rework irq logic
  mtd: pxa3xx_nand: make scan procedure more clear
  mtd: speedtest: fix integer overflow
  mtd: mxc_nand: fix read past buffer end
  mtd: omap3: nand: report corrected ecc errors
  jffs2: remove a trailing white space in commentaries
  ...
This commit is contained in:
Linus Torvalds 2011-03-27 19:40:56 -07:00
commit a17d47300b
55 changed files with 4678 additions and 671 deletions

View File

@ -32,6 +32,7 @@ struct omap_onenand_platform_data {
int dma_channel;
u8 flags;
u8 regulator_can_sleep;
u8 skip_initial_unlocking;
};
#define ONENAND_MAX_PARTITIONS 8

View File

@ -30,6 +30,7 @@ struct pxa3xx_nand_cmdset {
};
struct pxa3xx_nand_flash {
char *name;
uint32_t chip_id;
unsigned int page_per_block; /* Pages per block (PG_PER_BLK) */
unsigned int page_size; /* Page size in bytes (PAGE_SZ) */
@ -37,7 +38,6 @@ struct pxa3xx_nand_flash {
unsigned int dfc_width; /* Width of flash controller(DWIDTH_C) */
unsigned int num_blocks; /* Number of physical blocks in Flash */
struct pxa3xx_nand_cmdset *cmdset; /* NAND command set */
struct pxa3xx_nand_timing *timing; /* NAND Flash timing */
};

View File

@ -276,7 +276,6 @@ config ETRAX_AXISFLASHMAP
select MTD_CHAR
select MTD_BLOCK
select MTD_PARTITIONS
select MTD_CONCAT
select MTD_COMPLEX_MAPPINGS
help
This option enables MTD mapping of flash devices. Needed to use

View File

@ -234,7 +234,6 @@ static struct mtd_info *flash_probe(void)
}
if (mtd_cse0 && mtd_cse1) {
#ifdef CONFIG_MTD_CONCAT
struct mtd_info *mtds[] = { mtd_cse0, mtd_cse1 };
/* Since the concatenation layer adds a small overhead we
@ -246,11 +245,6 @@ static struct mtd_info *flash_probe(void)
*/
mtd_cse = mtd_concat_create(mtds, ARRAY_SIZE(mtds),
"cse0+cse1");
#else
printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
"(mis)configuration!\n", map_cse0.name, map_cse1.name);
mtd_cse = NULL;
#endif
if (!mtd_cse) {
printk(KERN_ERR "%s and %s: Concatenation failed!\n",
map_cse0.name, map_cse1.name);

View File

@ -406,7 +406,6 @@ config ETRAX_AXISFLASHMAP
select MTD_CHAR
select MTD_BLOCK
select MTD_PARTITIONS
select MTD_CONCAT
select MTD_COMPLEX_MAPPINGS
help
This option enables MTD mapping of flash devices. Needed to use

View File

@ -275,7 +275,6 @@ static struct mtd_info *flash_probe(void)
}
if (count > 1) {
#ifdef CONFIG_MTD_CONCAT
/* Since the concatenation layer adds a small overhead we
* could try to figure out if the chips in cse0 and cse1 are
* identical and reprobe the whole cse0+cse1 window. But since
@ -284,11 +283,6 @@ static struct mtd_info *flash_probe(void)
* complicating the probing procedure.
*/
mtd_total = mtd_concat_create(mtds, count, "cse0+cse1");
#else
printk(KERN_ERR "%s and %s: Cannot concatenate due to kernel "
"(mis)configuration!\n", map_cse0.name, map_cse1.name);
mtd_toal = NULL;
#endif
if (!mtd_total) {
printk(KERN_ERR "%s and %s: Concatenation failed!\n",
map_cse0.name, map_cse1.name);

View File

@ -33,14 +33,6 @@ config MTD_TESTS
should normally be compiled as kernel modules. The modules perform
various checks and verifications when loaded.
config MTD_CONCAT
tristate "MTD concatenating support"
help
Support for concatenating several MTD devices into a single
(virtual) one. This allows you to have -for example- a JFFS(2)
file system spanning multiple physical flash chips. If unsure,
say 'Y'.
config MTD_PARTITIONS
bool "MTD partitioning support"
help
@ -333,6 +325,16 @@ config MTD_OOPS
To use, add console=ttyMTDx to the kernel command line,
where x is the MTD device number to use.
config MTD_SWAP
tristate "Swap on MTD device support"
depends on MTD && SWAP
select MTD_BLKDEVS
help
Provides volatile block device driver on top of mtd partition
suitable for swapping. The mapping of written blocks is not saved.
The driver provides wear leveling by storing erase counter into the
OOB.
source "drivers/mtd/chips/Kconfig"
source "drivers/mtd/maps/Kconfig"

View File

@ -4,11 +4,10 @@
# Core functionality.
obj-$(CONFIG_MTD) += mtd.o
mtd-y := mtdcore.o mtdsuper.o
mtd-y := mtdcore.o mtdsuper.o mtdconcat.o
mtd-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
mtd-$(CONFIG_MTD_OF_PARTS) += ofpart.o
obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
@ -26,6 +25,7 @@ obj-$(CONFIG_RFD_FTL) += rfd_ftl.o
obj-$(CONFIG_SSFDC) += ssfdc.o
obj-$(CONFIG_SM_FTL) += sm_ftl.o
obj-$(CONFIG_MTD_OOPS) += mtdoops.o
obj-$(CONFIG_MTD_SWAP) += mtdswap.o
nftl-objs := nftlcore.o nftlmount.o
inftl-objs := inftlcore.o inftlmount.o

View File

@ -455,7 +455,7 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->writesize = 1;
mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;

View File

@ -349,6 +349,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
{ CFI_MFR_ATMEL, CFI_ID_ANY, fixup_convert_atmel_pri },
#ifdef AMD_BOOTLOC_BUG
{ CFI_MFR_AMD, CFI_ID_ANY, fixup_amd_bootblock },
{ CFI_MFR_AMIC, CFI_ID_ANY, fixup_amd_bootblock },
{ CFI_MFR_MACRONIX, CFI_ID_ANY, fixup_amd_bootblock },
#endif
{ CFI_MFR_AMD, 0x0050, fixup_use_secsi },
@ -440,7 +441,7 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
mtd->writesize = 1;
mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
DEBUG(MTD_DEBUG_LEVEL3, "MTD %s(): write buffer size %d\n",
__func__, mtd->writebufsize);

View File

@ -238,7 +238,7 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
mtd->resume = cfi_staa_resume;
mtd->flags = MTD_CAP_NORFLASH & ~MTD_BIT_WRITEABLE;
mtd->writesize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */
mtd->writebufsize = 1 << cfi->cfiq->MaxBufWriteSize;
mtd->writebufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
map->fldrv = &cfi_staa_chipdrv;
__module_get(THIS_MODULE);
mtd->name = map->name;

View File

@ -655,7 +655,8 @@ static const struct spi_device_id m25p_ids[] = {
{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
{ "at26df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
/* EON -- en25pxx */
/* EON -- en25xxx */
{ "en25f32", INFO(0x1c3116, 0, 64 * 1024, 64, SECT_4K) },
{ "en25p32", INFO(0x1c2016, 0, 64 * 1024, 64, 0) },
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
@ -728,6 +729,8 @@ static const struct spi_device_id m25p_ids[] = {
{ "m25pe80", INFO(0x208014, 0, 64 * 1024, 16, 0) },
{ "m25pe16", INFO(0x208015, 0, 64 * 1024, 32, SECT_4K) },
{ "m25px64", INFO(0x207117, 0, 64 * 1024, 128, 0) },
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
{ "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) },
{ "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) },

View File

@ -121,6 +121,7 @@ int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
mtd->flags = MTD_CAP_RAM;
mtd->size = size;
mtd->writesize = 1;
mtd->writebufsize = 64; /* Mimic CFI NOR flashes */
mtd->erasesize = MTDRAM_ERASE_SIZE;
mtd->priv = mapped_address;

View File

@ -117,6 +117,7 @@ static void unregister_devices(void)
list_for_each_entry_safe(this, safe, &phram_list, list) {
del_mtd_device(&this->mtd);
iounmap(this->mtd.priv);
kfree(this->mtd.name);
kfree(this);
}
}
@ -275,6 +276,8 @@ static int phram_setup(const char *val, struct kernel_param *kp)
ret = register_device(name, start, len);
if (!ret)
pr_info("%s device: %#x at %#x\n", name, len, start);
else
kfree(name);
return ret;
}

View File

@ -114,7 +114,7 @@ config MTD_SUN_UFLASH
config MTD_SC520CDP
tristate "CFI Flash device mapped on AMD SC520 CDP"
depends on X86 && MTD_CFI && MTD_CONCAT
depends on X86 && MTD_CFI
help
The SC520 CDP board has two banks of CFI-compliant chips and one
Dual-in-line JEDEC chip. This 'mapping' driver supports that
@ -262,7 +262,7 @@ config MTD_BCM963XX
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
depends on X86 && MTD_PARTITIONS && MTD_CFI_INTELEXT && BROKEN
help
MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP".
For details, see <http://www.ssv-embedded.de/ssv/pc104/p169.htm>
@ -552,4 +552,13 @@ config MTD_PISMO
When built as a module, it will be called pismo.ko
config MTD_LATCH_ADDR
tristate "Latch-assisted Flash Chip Support"
depends on MTD_COMPLEX_MAPPINGS
help
Map driver which allows flashes to be partially physically addressed
and have the upper address lines set by a board specific code.
If compiled as a module, it will be called latch-addr-flash.
endmenu

View File

@ -59,3 +59,4 @@ obj-$(CONFIG_MTD_RBTX4939) += rbtx4939-flash.o
obj-$(CONFIG_MTD_VMU) += vmu-flash.o
obj-$(CONFIG_MTD_GPIO_ADDR) += gpio-addr-flash.o
obj-$(CONFIG_MTD_BCM963XX) += bcm963xx-flash.o
obj-$(CONFIG_MTD_LATCH_ADDR) += latch-addr-flash.o

View File

@ -194,16 +194,10 @@ static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info
* We detected multiple devices. Concatenate
* them together.
*/
#ifdef CONFIG_MTD_CONCAT
*rmtd = mtd_concat_create(subdev, found,
"clps flash");
if (*rmtd == NULL)
ret = -ENXIO;
#else
printk(KERN_ERR "clps flash: multiple devices "
"found but MTD concat support disabled.\n");
ret = -ENXIO;
#endif
}
}

View File

@ -202,7 +202,6 @@ static int armflash_probe(struct platform_device *dev)
if (info->nr_subdev == 1)
info->mtd = info->subdev[0].mtd;
else if (info->nr_subdev > 1) {
#ifdef CONFIG_MTD_CONCAT
struct mtd_info *cdev[info->nr_subdev];
/*
@ -215,11 +214,6 @@ static int armflash_probe(struct platform_device *dev)
dev_name(&dev->dev));
if (info->mtd == NULL)
err = -ENXIO;
#else
printk(KERN_ERR "armflash: multiple devices found but "
"MTD concat support disabled.\n");
err = -ENXIO;
#endif
}
if (err < 0)
@ -244,10 +238,8 @@ static int armflash_probe(struct platform_device *dev)
cleanup:
if (info->mtd) {
del_mtd_partitions(info->mtd);
#ifdef CONFIG_MTD_CONCAT
if (info->mtd != info->subdev[0].mtd)
mtd_concat_destroy(info->mtd);
#endif
}
kfree(info->parts);
subdev_err:
@ -272,10 +264,8 @@ static int armflash_remove(struct platform_device *dev)
if (info) {
if (info->mtd) {
del_mtd_partitions(info->mtd);
#ifdef CONFIG_MTD_CONCAT
if (info->mtd != info->subdev[0].mtd)
mtd_concat_destroy(info->mtd);
#endif
}
kfree(info->parts);

View File

@ -0,0 +1,272 @@
/*
* Interface for NOR flash driver whose high address lines are latched
*
* Copyright © 2000 Nicolas Pitre <nico@cam.org>
* Copyright © 2005-2008 Analog Devices Inc.
* Copyright © 2008 MontaVista Software, Inc. <source@mvista.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
#include <linux/platform_device.h>
#include <linux/mtd/latch-addr-flash.h>
#include <linux/slab.h>
#define DRIVER_NAME "latch-addr-flash"
struct latch_addr_flash_info {
struct mtd_info *mtd;
struct map_info map;
struct resource *res;
void (*set_window)(unsigned long offset, void *data);
void *data;
/* cache; could be found out of res */
unsigned long win_mask;
int nr_parts;
struct mtd_partition *parts;
spinlock_t lock;
};
static map_word lf_read(struct map_info *map, unsigned long ofs)
{
struct latch_addr_flash_info *info;
map_word datum;
info = (struct latch_addr_flash_info *)map->map_priv_1;
spin_lock(&info->lock);
info->set_window(ofs, info->data);
datum = inline_map_read(map, info->win_mask & ofs);
spin_unlock(&info->lock);
return datum;
}
static void lf_write(struct map_info *map, map_word datum, unsigned long ofs)
{
struct latch_addr_flash_info *info;
info = (struct latch_addr_flash_info *)map->map_priv_1;
spin_lock(&info->lock);
info->set_window(ofs, info->data);
inline_map_write(map, datum, info->win_mask & ofs);
spin_unlock(&info->lock);
}
static void lf_copy_from(struct map_info *map, void *to,
unsigned long from, ssize_t len)
{
struct latch_addr_flash_info *info =
(struct latch_addr_flash_info *) map->map_priv_1;
unsigned n;
while (len > 0) {
n = info->win_mask + 1 - (from & info->win_mask);
if (n > len)
n = len;
spin_lock(&info->lock);
info->set_window(from, info->data);
memcpy_fromio(to, map->virt + (from & info->win_mask), n);
spin_unlock(&info->lock);
to += n;
from += n;
len -= n;
}
}
static char *rom_probe_types[] = { "cfi_probe", NULL };
static char *part_probe_types[] = { "cmdlinepart", NULL };
static int latch_addr_flash_remove(struct platform_device *dev)
{
struct latch_addr_flash_info *info;
struct latch_addr_flash_data *latch_addr_data;
info = platform_get_drvdata(dev);
if (info == NULL)
return 0;
platform_set_drvdata(dev, NULL);
latch_addr_data = dev->dev.platform_data;
if (info->mtd != NULL) {
if (mtd_has_partitions()) {
if (info->nr_parts) {
del_mtd_partitions(info->mtd);
kfree(info->parts);
} else if (latch_addr_data->nr_parts) {
del_mtd_partitions(info->mtd);
} else {
del_mtd_device(info->mtd);
}
} else {
del_mtd_device(info->mtd);
}
map_destroy(info->mtd);
}
if (info->map.virt != NULL)
iounmap(info->map.virt);
if (info->res != NULL)
release_mem_region(info->res->start, resource_size(info->res));
kfree(info);
if (latch_addr_data->done)
latch_addr_data->done(latch_addr_data->data);
return 0;
}
static int __devinit latch_addr_flash_probe(struct platform_device *dev)
{
struct latch_addr_flash_data *latch_addr_data;
struct latch_addr_flash_info *info;
resource_size_t win_base = dev->resource->start;
resource_size_t win_size = resource_size(dev->resource);
char **probe_type;
int chipsel;
int err;
latch_addr_data = dev->dev.platform_data;
if (latch_addr_data == NULL)
return -ENODEV;
pr_notice("latch-addr platform flash device: %#llx byte "
"window at %#.8llx\n",
(unsigned long long)win_size, (unsigned long long)win_base);
chipsel = dev->id;
if (latch_addr_data->init) {
err = latch_addr_data->init(latch_addr_data->data, chipsel);
if (err != 0)
return err;
}
info = kzalloc(sizeof(struct latch_addr_flash_info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
goto done;
}
platform_set_drvdata(dev, info);
info->res = request_mem_region(win_base, win_size, DRIVER_NAME);
if (info->res == NULL) {
dev_err(&dev->dev, "Could not reserve memory region\n");
err = -EBUSY;
goto free_info;
}
info->map.name = DRIVER_NAME;
info->map.size = latch_addr_data->size;
info->map.bankwidth = latch_addr_data->width;
info->map.phys = NO_XIP;
info->map.virt = ioremap(win_base, win_size);
if (!info->map.virt) {
err = -ENOMEM;
goto free_res;
}
info->map.map_priv_1 = (unsigned long)info;
info->map.read = lf_read;
info->map.copy_from = lf_copy_from;
info->map.write = lf_write;
info->set_window = latch_addr_data->set_window;
info->data = latch_addr_data->data;
info->win_mask = win_size - 1;
spin_lock_init(&info->lock);
for (probe_type = rom_probe_types; !info->mtd && *probe_type;
probe_type++)
info->mtd = do_map_probe(*probe_type, &info->map);
if (info->mtd == NULL) {
dev_err(&dev->dev, "map_probe failed\n");
err = -ENODEV;
goto iounmap;
}
info->mtd->owner = THIS_MODULE;
if (mtd_has_partitions()) {
err = parse_mtd_partitions(info->mtd,
(const char **)part_probe_types,
&info->parts, 0);
if (err > 0) {
add_mtd_partitions(info->mtd, info->parts, err);
return 0;
}
if (latch_addr_data->nr_parts) {
pr_notice("Using latch-addr-flash partition information\n");
add_mtd_partitions(info->mtd, latch_addr_data->parts,
latch_addr_data->nr_parts);
return 0;
}
}
add_mtd_device(info->mtd);
return 0;
iounmap:
iounmap(info->map.virt);
free_res:
release_mem_region(info->res->start, resource_size(info->res));
free_info:
kfree(info);
done:
if (latch_addr_data->done)
latch_addr_data->done(latch_addr_data->data);
return err;
}
static struct platform_driver latch_addr_flash_driver = {
.probe = latch_addr_flash_probe,
.remove = __devexit_p(latch_addr_flash_remove),
.driver = {
.name = DRIVER_NAME,
},
};
static int __init latch_addr_flash_init(void)
{
return platform_driver_register(&latch_addr_flash_driver);
}
module_init(latch_addr_flash_init);
static void __exit latch_addr_flash_exit(void)
{
platform_driver_unregister(&latch_addr_flash_driver);
}
module_exit(latch_addr_flash_exit);
MODULE_AUTHOR("David Griego <dgriego@mvista.com>");
MODULE_DESCRIPTION("MTD map driver for flashes addressed physically with upper "
"address lines being set board specifically");
MODULE_LICENSE("GPL v2");

View File

@ -59,10 +59,8 @@ static int physmap_flash_remove(struct platform_device *dev)
#else
del_mtd_device(info->cmtd);
#endif
#ifdef CONFIG_MTD_CONCAT
if (info->cmtd != info->mtd[0])
mtd_concat_destroy(info->cmtd);
#endif
}
for (i = 0; i < MAX_RESOURCES; i++) {
@ -159,15 +157,9 @@ static int physmap_flash_probe(struct platform_device *dev)
/*
* We detected multiple devices. Concatenate them together.
*/
#ifdef CONFIG_MTD_CONCAT
info->cmtd = mtd_concat_create(info->mtd, devices_found, dev_name(&dev->dev));
if (info->cmtd == NULL)
err = -ENXIO;
#else
printk(KERN_ERR "physmap-flash: multiple devices "
"found but MTD concat support disabled.\n");
err = -ENXIO;
#endif
}
if (err)
goto err_out;

View File

@ -104,12 +104,10 @@ static int of_flash_remove(struct platform_device *dev)
return 0;
dev_set_drvdata(&dev->dev, NULL);
#ifdef CONFIG_MTD_CONCAT
if (info->cmtd != info->list[0].mtd) {
del_mtd_device(info->cmtd);
mtd_concat_destroy(info->cmtd);
}
#endif
if (info->cmtd) {
if (OF_FLASH_PARTS(info)) {
@ -337,16 +335,10 @@ static int __devinit of_flash_probe(struct platform_device *dev)
/*
* We detected multiple devices. Concatenate them together.
*/
#ifdef CONFIG_MTD_CONCAT
info->cmtd = mtd_concat_create(mtd_list, info->list_size,
dev_name(&dev->dev));
if (info->cmtd == NULL)
err = -ENXIO;
#else
printk(KERN_ERR "physmap_of: multiple devices "
"found but MTD concat support disabled.\n");
err = -ENXIO;
#endif
}
if (err)
goto err_out;

View File

@ -232,10 +232,8 @@ static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *pla
else
del_mtd_partitions(info->mtd);
#endif
#ifdef CONFIG_MTD_CONCAT
if (info->mtd != info->subdev[0].mtd)
mtd_concat_destroy(info->mtd);
#endif
}
kfree(info->parts);
@ -321,7 +319,6 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
info->mtd = info->subdev[0].mtd;
ret = 0;
} else if (info->num_subdev > 1) {
#ifdef CONFIG_MTD_CONCAT
struct mtd_info *cdev[nr];
/*
* We detected multiple devices. Concatenate them together.
@ -333,11 +330,6 @@ sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
plat->name);
if (info->mtd == NULL)
ret = -ENXIO;
#else
printk(KERN_ERR "SA1100 flash: multiple devices "
"found but MTD concat support disabled.\n");
ret = -ENXIO;
#endif
}
if (ret == 0)

View File

@ -94,7 +94,6 @@ static int __init init_ts5500_map(void)
return 0;
err1:
map_destroy(mymtd);
iounmap(ts5500_map.virt);
err2:
return rc;

View File

@ -40,7 +40,7 @@
static LIST_HEAD(blktrans_majors);
static DEFINE_MUTEX(blktrans_ref_mutex);
void blktrans_dev_release(struct kref *kref)
static void blktrans_dev_release(struct kref *kref)
{
struct mtd_blktrans_dev *dev =
container_of(kref, struct mtd_blktrans_dev, ref);
@ -67,7 +67,7 @@ unlock:
return dev;
}
void blktrans_dev_put(struct mtd_blktrans_dev *dev)
static void blktrans_dev_put(struct mtd_blktrans_dev *dev)
{
mutex_lock(&blktrans_ref_mutex);
kref_put(&dev->ref, blktrans_dev_release);
@ -119,18 +119,43 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
}
}
int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev)
{
if (kthread_should_stop())
return 1;
return dev->bg_stop;
}
EXPORT_SYMBOL_GPL(mtd_blktrans_cease_background);
static int mtd_blktrans_thread(void *arg)
{
struct mtd_blktrans_dev *dev = arg;
struct mtd_blktrans_ops *tr = dev->tr;
struct request_queue *rq = dev->rq;
struct request *req = NULL;
int background_done = 0;
spin_lock_irq(rq->queue_lock);
while (!kthread_should_stop()) {
int res;
dev->bg_stop = false;
if (!req && !(req = blk_fetch_request(rq))) {
if (tr->background && !background_done) {
spin_unlock_irq(rq->queue_lock);
mutex_lock(&dev->lock);
tr->background(dev);
mutex_unlock(&dev->lock);
spin_lock_irq(rq->queue_lock);
/*
* Do background processing just once per idle
* period.
*/
background_done = !dev->bg_stop;
continue;
}
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_should_stop())
@ -152,6 +177,8 @@ static int mtd_blktrans_thread(void *arg)
if (!__blk_end_request_cur(req, res))
req = NULL;
background_done = 0;
}
if (req)
@ -172,8 +199,10 @@ static void mtd_blktrans_request(struct request_queue *rq)
if (!dev)
while ((req = blk_fetch_request(rq)) != NULL)
__blk_end_request_all(req, -ENODEV);
else
else {
dev->bg_stop = true;
wake_up_process(dev->thread);
}
}
static int blktrans_open(struct block_device *bdev, fmode_t mode)
@ -379,9 +408,10 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new)
new->rq->queuedata = new;
blk_queue_logical_block_size(new->rq, tr->blksize);
if (tr->discard)
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
new->rq);
if (tr->discard) {
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq);
new->rq->limits.max_discard_sectors = UINT_MAX;
}
gd->queue = new->rq;

View File

@ -750,6 +750,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
struct mtd_concat *concat;
uint32_t max_erasesize, curr_erasesize;
int num_erase_region;
int max_writebufsize = 0;
printk(KERN_NOTICE "Concatenating MTD devices:\n");
for (i = 0; i < num_devs; i++)
@ -776,7 +777,12 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.size = subdev[0]->size;
concat->mtd.erasesize = subdev[0]->erasesize;
concat->mtd.writesize = subdev[0]->writesize;
concat->mtd.writebufsize = subdev[0]->writebufsize;
for (i = 0; i < num_devs; i++)
if (max_writebufsize < subdev[i]->writebufsize)
max_writebufsize = subdev[i]->writebufsize;
concat->mtd.writebufsize = max_writebufsize;
concat->mtd.subpage_sft = subdev[0]->subpage_sft;
concat->mtd.oobsize = subdev[0]->oobsize;
concat->mtd.oobavail = subdev[0]->oobavail;

View File

@ -43,7 +43,7 @@
* backing device capabilities for non-mappable devices (such as NAND flash)
* - permits private mappings, copies are taken of the data
*/
struct backing_dev_info mtd_bdi_unmappable = {
static struct backing_dev_info mtd_bdi_unmappable = {
.capabilities = BDI_CAP_MAP_COPY,
};
@ -52,7 +52,7 @@ struct backing_dev_info mtd_bdi_unmappable = {
* - permits private mappings, copies are taken of the data
* - permits non-writable shared mappings
*/
struct backing_dev_info mtd_bdi_ro_mappable = {
static struct backing_dev_info mtd_bdi_ro_mappable = {
.capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP),
};
@ -62,7 +62,7 @@ struct backing_dev_info mtd_bdi_ro_mappable = {
* - permits private mappings, copies are taken of the data
* - permits non-writable shared mappings
*/
struct backing_dev_info mtd_bdi_rw_mappable = {
static struct backing_dev_info mtd_bdi_rw_mappable = {
.capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP |
BDI_CAP_WRITE_MAP),

1587
drivers/mtd/mtdswap.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,21 @@ config MTD_NAND_VERIFY_WRITE
device thinks the write was successful, a bit could have been
flipped accidentally due to device wear or something else.
config MTD_NAND_BCH
tristate
select BCH
depends on MTD_NAND_ECC_BCH
default MTD_NAND
config MTD_NAND_ECC_BCH
bool "Support software BCH ECC"
default n
help
This enables support for software BCH error correction. Binary BCH
codes are more powerful and cpu intensive than traditional Hamming
ECC codes. They are used with NAND devices requiring more than 1 bit
of error correction.
config MTD_SM_COMMON
tristate
default n

View File

@ -4,6 +4,7 @@
obj-$(CONFIG_MTD_NAND) += nand.o
obj-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o
obj-$(CONFIG_MTD_NAND_BCH) += nand_bch.o
obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o
obj-$(CONFIG_MTD_SM_COMMON) += sm_common.o

View File

@ -48,6 +48,9 @@
#define no_ecc 0
#endif
static int use_dma = 1;
module_param(use_dma, int, 0);
static int on_flash_bbt = 0;
module_param(on_flash_bbt, int, 0);
@ -89,11 +92,20 @@ struct atmel_nand_host {
struct nand_chip nand_chip;
struct mtd_info mtd;
void __iomem *io_base;
dma_addr_t io_phys;
struct atmel_nand_data *board;
struct device *dev;
void __iomem *ecc;
struct completion comp;
struct dma_chan *dma_chan;
};
static int cpu_has_dma(void)
{
return cpu_is_at91sam9rl() || cpu_is_at91sam9g45();
}
/*
* Enable NAND.
*/
@ -150,7 +162,7 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
/*
* Minimal-overhead PIO for data access.
*/
static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
static void atmel_read_buf8(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *nand_chip = mtd->priv;
@ -164,7 +176,7 @@ static void atmel_read_buf16(struct mtd_info *mtd, u8 *buf, int len)
__raw_readsw(nand_chip->IO_ADDR_R, buf, len / 2);
}
static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
static void atmel_write_buf8(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *nand_chip = mtd->priv;
@ -178,6 +190,121 @@ static void atmel_write_buf16(struct mtd_info *mtd, const u8 *buf, int len)
__raw_writesw(nand_chip->IO_ADDR_W, buf, len / 2);
}
static void dma_complete_func(void *completion)
{
complete(completion);
}
static int atmel_nand_dma_op(struct mtd_info *mtd, void *buf, int len,
int is_read)
{
struct dma_device *dma_dev;
enum dma_ctrl_flags flags;
dma_addr_t dma_src_addr, dma_dst_addr, phys_addr;
struct dma_async_tx_descriptor *tx = NULL;
dma_cookie_t cookie;
struct nand_chip *chip = mtd->priv;
struct atmel_nand_host *host = chip->priv;
void *p = buf;
int err = -EIO;
enum dma_data_direction dir = is_read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
if (buf >= high_memory) {
struct page *pg;
if (((size_t)buf & PAGE_MASK) !=
((size_t)(buf + len - 1) & PAGE_MASK)) {
dev_warn(host->dev, "Buffer not fit in one page\n");
goto err_buf;
}
pg = vmalloc_to_page(buf);
if (pg == 0) {
dev_err(host->dev, "Failed to vmalloc_to_page\n");
goto err_buf;
}
p = page_address(pg) + ((size_t)buf & ~PAGE_MASK);
}
dma_dev = host->dma_chan->device;
flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP |
DMA_COMPL_SKIP_DEST_UNMAP;
phys_addr = dma_map_single(dma_dev->dev, p, len, dir);
if (dma_mapping_error(dma_dev->dev, phys_addr)) {
dev_err(host->dev, "Failed to dma_map_single\n");
goto err_buf;
}
if (is_read) {
dma_src_addr = host->io_phys;
dma_dst_addr = phys_addr;
} else {
dma_src_addr = phys_addr;
dma_dst_addr = host->io_phys;
}
tx = dma_dev->device_prep_dma_memcpy(host->dma_chan, dma_dst_addr,
dma_src_addr, len, flags);
if (!tx) {
dev_err(host->dev, "Failed to prepare DMA memcpy\n");
goto err_dma;
}
init_completion(&host->comp);
tx->callback = dma_complete_func;
tx->callback_param = &host->comp;
cookie = tx->tx_submit(tx);
if (dma_submit_error(cookie)) {
dev_err(host->dev, "Failed to do DMA tx_submit\n");
goto err_dma;
}
dma_async_issue_pending(host->dma_chan);
wait_for_completion(&host->comp);
err = 0;
err_dma:
dma_unmap_single(dma_dev->dev, phys_addr, len, dir);
err_buf:
if (err != 0)
dev_warn(host->dev, "Fall back to CPU I/O\n");
return err;
}
static void atmel_read_buf(struct mtd_info *mtd, u8 *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct atmel_nand_host *host = chip->priv;
if (use_dma && len >= mtd->oobsize)
if (atmel_nand_dma_op(mtd, buf, len, 1) == 0)
return;
if (host->board->bus_width_16)
atmel_read_buf16(mtd, buf, len);
else
atmel_read_buf8(mtd, buf, len);
}
static void atmel_write_buf(struct mtd_info *mtd, const u8 *buf, int len)
{
struct nand_chip *chip = mtd->priv;
struct atmel_nand_host *host = chip->priv;
if (use_dma && len >= mtd->oobsize)
if (atmel_nand_dma_op(mtd, (void *)buf, len, 0) == 0)
return;
if (host->board->bus_width_16)
atmel_write_buf16(mtd, buf, len);
else
atmel_write_buf8(mtd, buf, len);
}
/*
* Calculate HW ECC
*
@ -398,6 +525,8 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
return -ENOMEM;
}
host->io_phys = (dma_addr_t)mem->start;
host->io_base = ioremap(mem->start, mem->end - mem->start + 1);
if (host->io_base == NULL) {
printk(KERN_ERR "atmel_nand: ioremap failed\n");
@ -448,14 +577,11 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
nand_chip->chip_delay = 20; /* 20us command delay time */
if (host->board->bus_width_16) { /* 16-bit bus width */
if (host->board->bus_width_16) /* 16-bit bus width */
nand_chip->options |= NAND_BUSWIDTH_16;
nand_chip->read_buf = atmel_read_buf16;
nand_chip->write_buf = atmel_write_buf16;
} else {
nand_chip->read_buf = atmel_read_buf;
nand_chip->write_buf = atmel_write_buf;
}
nand_chip->read_buf = atmel_read_buf;
nand_chip->write_buf = atmel_write_buf;
platform_set_drvdata(pdev, host);
atmel_nand_enable(host);
@ -473,6 +599,22 @@ static int __init atmel_nand_probe(struct platform_device *pdev)
nand_chip->options |= NAND_USE_FLASH_BBT;
}
if (cpu_has_dma() && use_dma) {
dma_cap_mask_t mask;
dma_cap_zero(mask);
dma_cap_set(DMA_MEMCPY, mask);
host->dma_chan = dma_request_channel(mask, 0, NULL);
if (!host->dma_chan) {
dev_err(host->dev, "Failed to request DMA channel\n");
use_dma = 0;
}
}
if (use_dma)
dev_info(host->dev, "Using DMA for NAND access.\n");
else
dev_info(host->dev, "No DMA support for NAND access.\n");
/* first scan to find the device and get the page size */
if (nand_scan_ident(mtd, 1, NULL)) {
res = -ENXIO;
@ -555,6 +697,8 @@ err_scan_ident:
err_no_card:
atmel_nand_disable(host);
platform_set_drvdata(pdev, NULL);
if (host->dma_chan)
dma_release_channel(host->dma_chan);
if (host->ecc)
iounmap(host->ecc);
err_ecc_ioremap:
@ -578,6 +722,10 @@ static int __exit atmel_nand_remove(struct platform_device *pdev)
if (host->ecc)
iounmap(host->ecc);
if (host->dma_chan)
dma_release_channel(host->dma_chan);
iounmap(host->io_base);
kfree(host);

View File

@ -37,9 +37,6 @@
#include <mach/nand.h>
#include <mach/aemif.h>
#include <asm/mach-types.h>
/*
* This is a device driver for the NAND flash controller found on the
* various DaVinci family chips. It handles up to four SoC chipselects,

View File

@ -29,6 +29,7 @@
#include <linux/clk.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
@ -757,9 +758,9 @@ static int __devinit mpc5121_nfc_probe(struct platform_device *op)
/* Enable NFC clock */
prv->clk = clk_get(dev, "nfc_clk");
if (!prv->clk) {
if (IS_ERR(prv->clk)) {
dev_err(dev, "Unable to acquire NFC clock!\n");
retval = -ENODEV;
retval = PTR_ERR(prv->clk);
goto error;
}

View File

@ -211,6 +211,31 @@ static struct nand_ecclayout nandv2_hw_eccoob_largepage = {
}
};
/* OOB description for 4096 byte pages with 128 byte OOB */
static struct nand_ecclayout nandv2_hw_eccoob_4k = {
.eccbytes = 8 * 9,
.eccpos = {
7, 8, 9, 10, 11, 12, 13, 14, 15,
23, 24, 25, 26, 27, 28, 29, 30, 31,
39, 40, 41, 42, 43, 44, 45, 46, 47,
55, 56, 57, 58, 59, 60, 61, 62, 63,
71, 72, 73, 74, 75, 76, 77, 78, 79,
87, 88, 89, 90, 91, 92, 93, 94, 95,
103, 104, 105, 106, 107, 108, 109, 110, 111,
119, 120, 121, 122, 123, 124, 125, 126, 127,
},
.oobfree = {
{.offset = 2, .length = 4},
{.offset = 16, .length = 7},
{.offset = 32, .length = 7},
{.offset = 48, .length = 7},
{.offset = 64, .length = 7},
{.offset = 80, .length = 7},
{.offset = 96, .length = 7},
{.offset = 112, .length = 7},
}
};
#ifdef CONFIG_MTD_PARTITIONS
static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
#endif
@ -641,9 +666,9 @@ static void mxc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
n = min(n, len);
memcpy(buf, host->data_buf + col, len);
memcpy(buf, host->data_buf + col, n);
host->buf_start += len;
host->buf_start += n;
}
/* Used by the upper layer to verify the data in NAND Flash
@ -1185,6 +1210,8 @@ static int __init mxcnd_probe(struct platform_device *pdev)
if (mtd->writesize == 2048)
this->ecc.layout = oob_largepage;
if (nfc_is_v21() && mtd->writesize == 4096)
this->ecc.layout = &nandv2_hw_eccoob_4k;
/* second phase scan */
if (nand_scan_tail(mtd)) {

View File

@ -42,6 +42,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <linux/mtd/nand_bch.h>
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/leds.h>
@ -2377,7 +2378,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
return -EINVAL;
}
/* Do not allow reads past end of device */
/* Do not allow write past end of device */
if (unlikely(to >= mtd->size ||
ops->ooboffs + ops->ooblen >
((mtd->size >> chip->page_shift) -
@ -3248,7 +3249,7 @@ int nand_scan_tail(struct mtd_info *mtd)
/*
* If no default placement scheme is given, select an appropriate one
*/
if (!chip->ecc.layout) {
if (!chip->ecc.layout && (chip->ecc.mode != NAND_ECC_SOFT_BCH)) {
switch (mtd->oobsize) {
case 8:
chip->ecc.layout = &nand_oob_8;
@ -3351,6 +3352,40 @@ int nand_scan_tail(struct mtd_info *mtd)
chip->ecc.bytes = 3;
break;
case NAND_ECC_SOFT_BCH:
if (!mtd_nand_has_bch()) {
printk(KERN_WARNING "CONFIG_MTD_ECC_BCH not enabled\n");
BUG();
}
chip->ecc.calculate = nand_bch_calculate_ecc;
chip->ecc.correct = nand_bch_correct_data;
chip->ecc.read_page = nand_read_page_swecc;
chip->ecc.read_subpage = nand_read_subpage;
chip->ecc.write_page = nand_write_page_swecc;
chip->ecc.read_page_raw = nand_read_page_raw;
chip->ecc.write_page_raw = nand_write_page_raw;
chip->ecc.read_oob = nand_read_oob_std;
chip->ecc.write_oob = nand_write_oob_std;
/*
* Board driver should supply ecc.size and ecc.bytes values to
* select how many bits are correctable; see nand_bch_init()
* for details.
* Otherwise, default to 4 bits for large page devices
*/
if (!chip->ecc.size && (mtd->oobsize >= 64)) {
chip->ecc.size = 512;
chip->ecc.bytes = 7;
}
chip->ecc.priv = nand_bch_init(mtd,
chip->ecc.size,
chip->ecc.bytes,
&chip->ecc.layout);
if (!chip->ecc.priv) {
printk(KERN_WARNING "BCH ECC initialization failed!\n");
BUG();
}
break;
case NAND_ECC_NONE:
printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
"This is not recommended !!\n");
@ -3501,6 +3536,9 @@ void nand_release(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
if (chip->ecc.mode == NAND_ECC_SOFT_BCH)
nand_bch_free((struct nand_bch_control *)chip->ecc.priv);
#ifdef CONFIG_MTD_PARTITIONS
/* Deregister partitions */
del_mtd_partitions(mtd);

View File

@ -1101,12 +1101,16 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)
static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
u32 pattern_len = bd->len;
u32 bits = bd->options & NAND_BBT_NRBITS_MSK;
u32 pattern_len;
u32 bits;
u32 table_size;
if (!bd)
return;
pattern_len = bd->len;
bits = bd->options & NAND_BBT_NRBITS_MSK;
BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) &&
!(this->options & NAND_USE_FLASH_BBT));
BUG_ON(!bits);

243
drivers/mtd/nand/nand_bch.c Normal file
View File

@ -0,0 +1,243 @@
/*
* This file provides ECC correction for more than 1 bit per block of data,
* using binary BCH codes. It relies on the generic BCH library lib/bch.c.
*
* Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
*
* This file 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 or (at your option) any
* later version.
*
* This file is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this file; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_bch.h>
#include <linux/bch.h>
/**
* struct nand_bch_control - private NAND BCH control structure
* @bch: BCH control structure
* @ecclayout: private ecc layout for this BCH configuration
* @errloc: error location array
* @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
*/
struct nand_bch_control {
struct bch_control *bch;
struct nand_ecclayout ecclayout;
unsigned int *errloc;
unsigned char *eccmask;
};
/**
* nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
* @mtd: MTD block structure
* @buf: input buffer with raw data
* @code: output buffer with ECC
*/
int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf,
unsigned char *code)
{
const struct nand_chip *chip = mtd->priv;
struct nand_bch_control *nbc = chip->ecc.priv;
unsigned int i;
memset(code, 0, chip->ecc.bytes);
encode_bch(nbc->bch, buf, chip->ecc.size, code);
/* apply mask so that an erased page is a valid codeword */
for (i = 0; i < chip->ecc.bytes; i++)
code[i] ^= nbc->eccmask[i];
return 0;
}
EXPORT_SYMBOL(nand_bch_calculate_ecc);
/**
* nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s)
* @mtd: MTD block structure
* @buf: raw data read from the chip
* @read_ecc: ECC from the chip
* @calc_ecc: the ECC calculated from raw data
*
* Detect and correct bit errors for a data byte block
*/
int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
const struct nand_chip *chip = mtd->priv;
struct nand_bch_control *nbc = chip->ecc.priv;
unsigned int *errloc = nbc->errloc;
int i, count;
count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
NULL, errloc);
if (count > 0) {
for (i = 0; i < count; i++) {
if (errloc[i] < (chip->ecc.size*8))
/* error is located in data, correct it */
buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
/* else error in ecc, no action needed */
DEBUG(MTD_DEBUG_LEVEL0, "%s: corrected bitflip %u\n",
__func__, errloc[i]);
}
} else if (count < 0) {
printk(KERN_ERR "ecc unrecoverable error\n");
count = -1;
}
return count;
}
EXPORT_SYMBOL(nand_bch_correct_data);
/**
* nand_bch_init - [NAND Interface] Initialize NAND BCH error correction
* @mtd: MTD block structure
* @eccsize: ecc block size in bytes
* @eccbytes: ecc length in bytes
* @ecclayout: output default layout
*
* Returns:
* a pointer to a new NAND BCH control structure, or NULL upon failure
*
* Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
* are used to compute BCH parameters m (Galois field order) and t (error
* correction capability). @eccbytes should be equal to the number of bytes
* required to store m*t bits, where m is such that 2^m-1 > @eccsize*8.
*
* Example: to configure 4 bit correction per 512 bytes, you should pass
* @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
* @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
*/
struct nand_bch_control *
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize, unsigned int eccbytes,
struct nand_ecclayout **ecclayout)
{
unsigned int m, t, eccsteps, i;
struct nand_ecclayout *layout;
struct nand_bch_control *nbc = NULL;
unsigned char *erased_page;
if (!eccsize || !eccbytes) {
printk(KERN_WARNING "ecc parameters not supplied\n");
goto fail;
}
m = fls(1+8*eccsize);
t = (eccbytes*8)/m;
nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
if (!nbc)
goto fail;
nbc->bch = init_bch(m, t, 0);
if (!nbc->bch)
goto fail;
/* verify that eccbytes has the expected value */
if (nbc->bch->ecc_bytes != eccbytes) {
printk(KERN_WARNING "invalid eccbytes %u, should be %u\n",
eccbytes, nbc->bch->ecc_bytes);
goto fail;
}
eccsteps = mtd->writesize/eccsize;
/* if no ecc placement scheme was provided, build one */
if (!*ecclayout) {
/* handle large page devices only */
if (mtd->oobsize < 64) {
printk(KERN_WARNING "must provide an oob scheme for "
"oobsize %d\n", mtd->oobsize);
goto fail;
}
layout = &nbc->ecclayout;
layout->eccbytes = eccsteps*eccbytes;
/* reserve 2 bytes for bad block marker */
if (layout->eccbytes+2 > mtd->oobsize) {
printk(KERN_WARNING "no suitable oob scheme available "
"for oobsize %d eccbytes %u\n", mtd->oobsize,
eccbytes);
goto fail;
}
/* put ecc bytes at oob tail */
for (i = 0; i < layout->eccbytes; i++)
layout->eccpos[i] = mtd->oobsize-layout->eccbytes+i;
layout->oobfree[0].offset = 2;
layout->oobfree[0].length = mtd->oobsize-2-layout->eccbytes;
*ecclayout = layout;
}
/* sanity checks */
if (8*(eccsize+eccbytes) >= (1 << m)) {
printk(KERN_WARNING "eccsize %u is too large\n", eccsize);
goto fail;
}
if ((*ecclayout)->eccbytes != (eccsteps*eccbytes)) {
printk(KERN_WARNING "invalid ecc layout\n");
goto fail;
}
nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL);
nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL);
if (!nbc->eccmask || !nbc->errloc)
goto fail;
/*
* compute and store the inverted ecc of an erased ecc block
*/
erased_page = kmalloc(eccsize, GFP_KERNEL);
if (!erased_page)
goto fail;
memset(erased_page, 0xff, eccsize);
memset(nbc->eccmask, 0, eccbytes);
encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask);
kfree(erased_page);
for (i = 0; i < eccbytes; i++)
nbc->eccmask[i] ^= 0xff;
return nbc;
fail:
nand_bch_free(nbc);
return NULL;
}
EXPORT_SYMBOL(nand_bch_init);
/**
* nand_bch_free - [NAND Interface] Release NAND BCH ECC resources
* @nbc: NAND BCH control structure
*/
void nand_bch_free(struct nand_bch_control *nbc)
{
if (nbc) {
free_bch(nbc->bch);
kfree(nbc->errloc);
kfree(nbc->eccmask);
kfree(nbc);
}
}
EXPORT_SYMBOL(nand_bch_free);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
MODULE_DESCRIPTION("NAND software BCH ECC support");

View File

@ -34,6 +34,7 @@
#include <linux/string.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_bch.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/list.h>
@ -108,6 +109,7 @@ static unsigned int rptwear = 0;
static unsigned int overridesize = 0;
static char *cache_file = NULL;
static unsigned int bbt;
static unsigned int bch;
module_param(first_id_byte, uint, 0400);
module_param(second_id_byte, uint, 0400);
@ -132,6 +134,7 @@ module_param(rptwear, uint, 0400);
module_param(overridesize, uint, 0400);
module_param(cache_file, charp, 0400);
module_param(bbt, uint, 0400);
module_param(bch, uint, 0400);
MODULE_PARM_DESC(first_id_byte, "The first byte returned by NAND Flash 'read ID' command (manufacturer ID)");
MODULE_PARM_DESC(second_id_byte, "The second byte returned by NAND Flash 'read ID' command (chip ID)");
@ -165,6 +168,8 @@ MODULE_PARM_DESC(overridesize, "Specifies the NAND Flash size overriding the I
" e.g. 5 means a size of 32 erase blocks");
MODULE_PARM_DESC(cache_file, "File to use to cache nand pages instead of memory");
MODULE_PARM_DESC(bbt, "0 OOB, 1 BBT with marker in OOB, 2 BBT with marker in data area");
MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
"be correctable in 512-byte blocks");
/* The largest possible page size */
#define NS_LARGEST_PAGE_SIZE 4096
@ -2309,7 +2314,43 @@ static int __init ns_init_module(void)
if ((retval = parse_gravepages()) != 0)
goto error;
if ((retval = nand_scan(nsmtd, 1)) != 0) {
retval = nand_scan_ident(nsmtd, 1, NULL);
if (retval) {
NS_ERR("cannot scan NAND Simulator device\n");
if (retval > 0)
retval = -ENXIO;
goto error;
}
if (bch) {
unsigned int eccsteps, eccbytes;
if (!mtd_nand_has_bch()) {
NS_ERR("BCH ECC support is disabled\n");
retval = -EINVAL;
goto error;
}
/* use 512-byte ecc blocks */
eccsteps = nsmtd->writesize/512;
eccbytes = (bch*13+7)/8;
/* do not bother supporting small page devices */
if ((nsmtd->oobsize < 64) || !eccsteps) {
NS_ERR("bch not available on small page devices\n");
retval = -EINVAL;
goto error;
}
if ((eccbytes*eccsteps+2) > nsmtd->oobsize) {
NS_ERR("invalid bch value %u\n", bch);
retval = -EINVAL;
goto error;
}
chip->ecc.mode = NAND_ECC_SOFT_BCH;
chip->ecc.size = 512;
chip->ecc.bytes = eccbytes;
NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
}
retval = nand_scan_tail(nsmtd);
if (retval) {
NS_ERR("can't register NAND Simulator\n");
if (retval > 0)
retval = -ENXIO;

View File

@ -668,6 +668,8 @@ static void gen_true_ecc(u8 *ecc_buf)
*
* This function compares two ECC's and indicates if there is an error.
* If the error can be corrected it will be corrected to the buffer.
* If there is no error, %0 is returned. If there is an error but it
* was corrected, %1 is returned. Otherwise, %-1 is returned.
*/
static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
u8 *ecc_data2, /* read from register */
@ -773,7 +775,7 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
page_data[find_byte] ^= (1 << find_bit);
return 0;
return 1;
default:
if (isEccFF) {
if (ecc_data2[0] == 0 &&
@ -794,8 +796,11 @@ static int omap_compare_ecc(u8 *ecc_data1, /* read from NAND memory */
* @calc_ecc: ecc read from HW ECC registers
*
* Compares the ecc read from nand spare area with ECC registers values
* and if ECC's mismached, it will call 'omap_compare_ecc' for error detection
* and correction.
* and if ECC's mismatched, it will call 'omap_compare_ecc' for error
* detection and correction. If there are no errors, %0 is returned. If
* there were errors and all of the errors were corrected, the number of
* corrected errors is returned. If uncorrectable errors exist, %-1 is
* returned.
*/
static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
u_char *read_ecc, u_char *calc_ecc)
@ -803,6 +808,7 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
mtd);
int blockCnt = 0, i = 0, ret = 0;
int stat = 0;
/* Ex NAND_ECC_HW12_2048 */
if ((info->nand.ecc.mode == NAND_ECC_HW) &&
@ -816,12 +822,14 @@ static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
if (ret < 0)
return ret;
/* keep track of the number of corrected errors */
stat += ret;
}
read_ecc += 3;
calc_ecc += 3;
dat += 512;
}
return 0;
return stat;
}
/**

File diff suppressed because it is too large Load Diff

View File

@ -629,6 +629,7 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
{
struct omap_onenand_platform_data *pdata;
struct omap2_onenand *c;
struct onenand_chip *this;
int r;
pdata = pdev->dev.platform_data;
@ -726,9 +727,8 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
c->mtd.dev.parent = &pdev->dev;
this = &c->onenand;
if (c->dma_channel >= 0) {
struct onenand_chip *this = &c->onenand;
this->wait = omap2_onenand_wait;
if (cpu_is_omap34xx()) {
this->read_bufferram = omap3_onenand_read_bufferram;
@ -749,6 +749,9 @@ static int __devinit omap2_onenand_probe(struct platform_device *pdev)
c->onenand.disable = omap2_onenand_disable;
}
if (pdata->skip_initial_unlocking)
this->options |= ONENAND_SKIP_INITIAL_UNLOCKING;
if ((r = onenand_scan(&c->mtd, 1)) < 0)
goto err_release_regulator;

View File

@ -1132,6 +1132,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
onenand_update_bufferram(mtd, from, !ret);
if (ret == -EBADMSG)
ret = 0;
if (ret)
break;
}
this->read_bufferram(mtd, ONENAND_DATARAM, buf, column, thislen);
@ -1646,11 +1648,10 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
int ret = 0;
int thislen, column;
column = addr & (this->writesize - 1);
while (len != 0) {
thislen = min_t(int, this->writesize, len);
column = addr & (this->writesize - 1);
if (column + thislen > this->writesize)
thislen = this->writesize - column;
thislen = min_t(int, this->writesize - column, len);
this->command(mtd, ONENAND_CMD_READ, addr, this->writesize);
@ -1664,12 +1665,13 @@ static int onenand_verify(struct mtd_info *mtd, const u_char *buf, loff_t addr,
this->read_bufferram(mtd, ONENAND_DATARAM, this->verify_buf, 0, mtd->writesize);
if (memcmp(buf, this->verify_buf, thislen))
if (memcmp(buf, this->verify_buf + column, thislen))
return -EBADMSG;
len -= thislen;
buf += thislen;
addr += thislen;
column = 0;
}
return 0;
@ -4083,7 +4085,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->writebufsize = mtd->writesize;
/* Unlock whole block */
this->unlock_all(mtd);
if (!(this->options & ONENAND_SKIP_INITIAL_UNLOCKING))
this->unlock_all(mtd);
ret = this->scan_bbt(mtd);
if ((!FLEXONENAND(this)) || ret)

View File

@ -64,12 +64,16 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET);
char *vendor = kmalloc(vendor_len, GFP_KERNEL);
if (!vendor)
goto error1;
memcpy(vendor, ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, vendor_len);
vendor[vendor_len] = 0;
/* Initialize sysfs attributes */
vendor_attribute =
kzalloc(sizeof(struct sm_sysfs_attribute), GFP_KERNEL);
if (!vendor_attribute)
goto error2;
sysfs_attr_init(&vendor_attribute->dev_attr.attr);
@ -83,12 +87,24 @@ struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
/* Create array of pointers to the attributes */
attributes = kzalloc(sizeof(struct attribute *) * (NUM_ATTRIBUTES + 1),
GFP_KERNEL);
if (!attributes)
goto error3;
attributes[0] = &vendor_attribute->dev_attr.attr;
/* Finally create the attribute group */
attr_group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
if (!attr_group)
goto error4;
attr_group->attrs = attributes;
return attr_group;
error4:
kfree(attributes);
error3:
kfree(vendor_attribute);
error2:
kfree(vendor);
error1:
return NULL;
}
void sm_delete_sysfs_attributes(struct sm_ftl *ftl)
@ -1178,6 +1194,8 @@ static void sm_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd)
}
ftl->disk_attributes = sm_create_sysfs_attributes(ftl);
if (!ftl->disk_attributes)
goto error6;
trans->disk_attributes = ftl->disk_attributes;
sm_printk("Found %d MiB xD/SmartMedia FTL on mtd%d",

View File

@ -16,7 +16,7 @@
*
* Test read and write speed of a MTD device.
*
* Author: Adrian Hunter <ext-adrian.hunter@nokia.com>
* Author: Adrian Hunter <adrian.hunter@nokia.com>
*/
#include <linux/init.h>
@ -33,6 +33,11 @@ static int dev;
module_param(dev, int, S_IRUGO);
MODULE_PARM_DESC(dev, "MTD device number to use");
static int count;
module_param(count, int, S_IRUGO);
MODULE_PARM_DESC(count, "Maximum number of eraseblocks to use "
"(0 means use all)");
static struct mtd_info *mtd;
static unsigned char *iobuf;
static unsigned char *bbt;
@ -89,6 +94,33 @@ static int erase_eraseblock(int ebnum)
return 0;
}
static int multiblock_erase(int ebnum, int blocks)
{
int err;
struct erase_info ei;
loff_t addr = ebnum * mtd->erasesize;
memset(&ei, 0, sizeof(struct erase_info));
ei.mtd = mtd;
ei.addr = addr;
ei.len = mtd->erasesize * blocks;
err = mtd->erase(mtd, &ei);
if (err) {
printk(PRINT_PREF "error %d while erasing EB %d, blocks %d\n",
err, ebnum, blocks);
return err;
}
if (ei.state == MTD_ERASE_FAILED) {
printk(PRINT_PREF "some erase error occurred at EB %d,"
"blocks %d\n", ebnum, blocks);
return -EIO;
}
return 0;
}
static int erase_whole_device(void)
{
int err;
@ -282,13 +314,16 @@ static inline void stop_timing(void)
static long calc_speed(void)
{
long ms, k, speed;
uint64_t k;
long ms;
ms = (finish.tv_sec - start.tv_sec) * 1000 +
(finish.tv_usec - start.tv_usec) / 1000;
k = goodebcnt * mtd->erasesize / 1024;
speed = (k * 1000) / ms;
return speed;
if (ms == 0)
return 0;
k = goodebcnt * (mtd->erasesize / 1024) * 1000;
do_div(k, ms);
return k;
}
static int scan_for_bad_eraseblocks(void)
@ -320,13 +355,16 @@ out:
static int __init mtd_speedtest_init(void)
{
int err, i;
int err, i, blocks, j, k;
long speed;
uint64_t tmp;
printk(KERN_INFO "\n");
printk(KERN_INFO "=================================================\n");
printk(PRINT_PREF "MTD device: %d\n", dev);
if (count)
printk(PRINT_PREF "MTD device: %d count: %d\n", dev, count);
else
printk(PRINT_PREF "MTD device: %d\n", dev);
mtd = get_mtd_device(NULL, dev);
if (IS_ERR(mtd)) {
@ -353,6 +391,9 @@ static int __init mtd_speedtest_init(void)
(unsigned long long)mtd->size, mtd->erasesize,
pgsize, ebcnt, pgcnt, mtd->oobsize);
if (count > 0 && count < ebcnt)
ebcnt = count;
err = -ENOMEM;
iobuf = kmalloc(mtd->erasesize, GFP_KERNEL);
if (!iobuf) {
@ -484,6 +525,31 @@ static int __init mtd_speedtest_init(void)
speed = calc_speed();
printk(PRINT_PREF "erase speed is %ld KiB/s\n", speed);
/* Multi-block erase all eraseblocks */
for (k = 1; k < 7; k++) {
blocks = 1 << k;
printk(PRINT_PREF "Testing %dx multi-block erase speed\n",
blocks);
start_timing();
for (i = 0; i < ebcnt; ) {
for (j = 0; j < blocks && (i + j) < ebcnt; j++)
if (bbt[i + j])
break;
if (j < 1) {
i++;
continue;
}
err = multiblock_erase(i, j);
if (err)
goto out;
cond_resched();
i += j;
}
stop_timing();
speed = calc_speed();
printk(PRINT_PREF "%dx multi-block erase speed is %ld KiB/s\n",
blocks, speed);
}
printk(PRINT_PREF "finished\n");
out:
kfree(iobuf);

View File

@ -394,6 +394,11 @@ static int __init mtd_subpagetest_init(void)
}
subpgsize = mtd->writesize >> mtd->subpage_sft;
tmp = mtd->size;
do_div(tmp, mtd->erasesize);
ebcnt = tmp;
pgcnt = mtd->erasesize / mtd->writesize;
printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, "
"page size %u, subpage size %u, count of eraseblocks %u, "
"pages per eraseblock %u, OOB size %u\n",
@ -413,11 +418,6 @@ static int __init mtd_subpagetest_init(void)
goto out;
}
tmp = mtd->size;
do_div(tmp, mtd->erasesize);
ebcnt = tmp;
pgcnt = mtd->erasesize / mtd->writesize;
err = scan_for_bad_eraseblocks();
if (err)
goto out;

79
include/linux/bch.h Normal file
View File

@ -0,0 +1,79 @@
/*
* Generic binary BCH encoding/decoding library
*
* 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.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright © 2011 Parrot S.A.
*
* Author: Ivan Djelic <ivan.djelic@parrot.com>
*
* Description:
*
* This library provides runtime configurable encoding/decoding of binary
* Bose-Chaudhuri-Hocquenghem (BCH) codes.
*/
#ifndef _BCH_H
#define _BCH_H
#include <linux/types.h>
/**
* struct bch_control - BCH control structure
* @m: Galois field order
* @n: maximum codeword size in bits (= 2^m-1)
* @t: error correction capability in bits
* @ecc_bits: ecc exact size in bits, i.e. generator polynomial degree (<=m*t)
* @ecc_bytes: ecc max size (m*t bits) in bytes
* @a_pow_tab: Galois field GF(2^m) exponentiation lookup table
* @a_log_tab: Galois field GF(2^m) log lookup table
* @mod8_tab: remainder generator polynomial lookup tables
* @ecc_buf: ecc parity words buffer
* @ecc_buf2: ecc parity words buffer
* @xi_tab: GF(2^m) base for solving degree 2 polynomial roots
* @syn: syndrome buffer
* @cache: log-based polynomial representation buffer
* @elp: error locator polynomial
* @poly_2t: temporary polynomials of degree 2t
*/
struct bch_control {
unsigned int m;
unsigned int n;
unsigned int t;
unsigned int ecc_bits;
unsigned int ecc_bytes;
/* private: */
uint16_t *a_pow_tab;
uint16_t *a_log_tab;
uint32_t *mod8_tab;
uint32_t *ecc_buf;
uint32_t *ecc_buf2;
unsigned int *xi_tab;
unsigned int *syn;
int *cache;
struct gf_poly *elp;
struct gf_poly *poly_2t[4];
};
struct bch_control *init_bch(int m, int t, unsigned int prim_poly);
void free_bch(struct bch_control *bch);
void encode_bch(struct bch_control *bch, const uint8_t *data,
unsigned int len, uint8_t *ecc);
int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len,
const uint8_t *recv_ecc, const uint8_t *calc_ecc,
const unsigned int *syn, unsigned int *errloc);
#endif /* _BCH_H */

View File

@ -36,6 +36,7 @@ struct mtd_blktrans_dev {
struct mtd_info *mtd;
struct mutex lock;
int devnum;
bool bg_stop;
unsigned long size;
int readonly;
int open;
@ -62,6 +63,7 @@ struct mtd_blktrans_ops {
unsigned long block, char *buffer);
int (*discard)(struct mtd_blktrans_dev *dev,
unsigned long block, unsigned nr_blocks);
void (*background)(struct mtd_blktrans_dev *dev);
/* Block layer ioctls */
int (*getgeo)(struct mtd_blktrans_dev *dev, struct hd_geometry *geo);
@ -85,6 +87,7 @@ extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr);
extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr);
extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev);
extern int mtd_blktrans_cease_background(struct mtd_blktrans_dev *dev);
#endif /* __MTD_TRANS_H__ */

View File

@ -535,6 +535,7 @@ struct cfi_fixup {
#define CFI_MFR_CONTINUATION 0x007F
#define CFI_MFR_AMD 0x0001
#define CFI_MFR_AMIC 0x0037
#define CFI_MFR_ATMEL 0x001F
#define CFI_MFR_EON 0x001C
#define CFI_MFR_FUJITSU 0x0004

View File

@ -0,0 +1,29 @@
/*
* Interface for NOR flash driver whose high address lines are latched
*
* Copyright © 2008 MontaVista Software, Inc. <source@mvista.com>
*
* This file is licensed under the terms of the GNU General Public License
* version 2. This program is licensed "as is" without any warranty of any
* kind, whether express or implied.
*/
#ifndef __LATCH_ADDR_FLASH__
#define __LATCH_ADDR_FLASH__
struct map_info;
struct mtd_partition;
struct latch_addr_flash_data {
unsigned int width;
unsigned int size;
int (*init)(void *data, int cs);
void (*done)(void *data);
void (*set_window)(unsigned long offset, void *data);
void *data;
unsigned int nr_parts;
struct mtd_partition *parts;
};
#endif

View File

@ -140,6 +140,7 @@ typedef enum {
NAND_ECC_HW,
NAND_ECC_HW_SYNDROME,
NAND_ECC_HW_OOB_FIRST,
NAND_ECC_SOFT_BCH,
} nand_ecc_modes_t;
/*
@ -339,6 +340,7 @@ struct nand_hw_control {
* @prepad: padding information for syndrome based ecc generators
* @postpad: padding information for syndrome based ecc generators
* @layout: ECC layout control struct pointer
* @priv: pointer to private ecc control data
* @hwctl: function to control hardware ecc generator. Must only
* be provided if an hardware ECC is available
* @calculate: function for ecc calculation or readback from ecc hardware
@ -362,6 +364,7 @@ struct nand_ecc_ctrl {
int prepad;
int postpad;
struct nand_ecclayout *layout;
void *priv;
void (*hwctl)(struct mtd_info *mtd, int mode);
int (*calculate)(struct mtd_info *mtd, const uint8_t *dat,
uint8_t *ecc_code);

View File

@ -0,0 +1,72 @@
/*
* Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.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.
*
* This file is the header for the NAND BCH ECC implementation.
*/
#ifndef __MTD_NAND_BCH_H__
#define __MTD_NAND_BCH_H__
struct mtd_info;
struct nand_bch_control;
#if defined(CONFIG_MTD_NAND_ECC_BCH)
static inline int mtd_nand_has_bch(void) { return 1; }
/*
* Calculate BCH ecc code
*/
int nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code);
/*
* Detect and correct bit errors
*/
int nand_bch_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc,
u_char *calc_ecc);
/*
* Initialize BCH encoder/decoder
*/
struct nand_bch_control *
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
unsigned int eccbytes, struct nand_ecclayout **ecclayout);
/*
* Release BCH encoder/decoder resources
*/
void nand_bch_free(struct nand_bch_control *nbc);
#else /* !CONFIG_MTD_NAND_ECC_BCH */
static inline int mtd_nand_has_bch(void) { return 0; }
static inline int
nand_bch_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
u_char *ecc_code)
{
return -1;
}
static inline int
nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc)
{
return -1;
}
static inline struct nand_bch_control *
nand_bch_init(struct mtd_info *mtd, unsigned int eccsize,
unsigned int eccbytes, struct nand_ecclayout **ecclayout)
{
return NULL;
}
static inline void nand_bch_free(struct nand_bch_control *nbc) {}
#endif /* CONFIG_MTD_NAND_ECC_BCH */
#endif /* __MTD_NAND_BCH_H__ */

View File

@ -198,6 +198,7 @@ struct onenand_chip {
#define ONENAND_SKIP_UNLOCK_CHECK (0x0100)
#define ONENAND_PAGEBUF_ALLOC (0x1000)
#define ONENAND_OOBBUF_ALLOC (0x2000)
#define ONENAND_SKIP_INITIAL_UNLOCKING (0x4000)
#define ONENAND_IS_4KB_PAGE(this) \
(this->options & ONENAND_HAS_4KB_PAGE)

View File

@ -157,6 +157,45 @@ config REED_SOLOMON_ENC16
config REED_SOLOMON_DEC16
boolean
#
# BCH support is selected if needed
#
config BCH
tristate
config BCH_CONST_PARAMS
boolean
help
Drivers may select this option to force specific constant
values for parameters 'm' (Galois field order) and 't'
(error correction capability). Those specific values must
be set by declaring default values for symbols BCH_CONST_M
and BCH_CONST_T.
Doing so will enable extra compiler optimizations,
improving encoding and decoding performance up to 2x for
usual (m,t) values (typically such that m*t < 200).
When this option is selected, the BCH library supports
only a single (m,t) configuration. This is mainly useful
for NAND flash board drivers requiring known, fixed BCH
parameters.
config BCH_CONST_M
int
range 5 15
help
Constant value for Galois field order 'm'. If 'k' is the
number of data bits to protect, 'm' should be chosen such
that (k + m*t) <= 2**m - 1.
Drivers should declare a default value for this symbol if
they select option BCH_CONST_PARAMS.
config BCH_CONST_T
int
help
Constant value for error correction capability in bits 't'.
Drivers should declare a default value for this symbol if
they select option BCH_CONST_PARAMS.
#
# Textsearch support is select'ed if needed
#

View File

@ -69,6 +69,7 @@ obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_LZO_COMPRESS) += lzo/
obj-$(CONFIG_LZO_DECOMPRESS) += lzo/
obj-$(CONFIG_XZ_DEC) += xz/

1368
lib/bch.c Normal file

File diff suppressed because it is too large Load Diff