Common MTD:

* Add Kconfig option for keeping both the 'master' and 'partition' MTDs
    registered as devices. This would really make a better default if we could
    do it over, as it allows a lot more flexibility in (1) determining the flash
    topology of the system from user-space and (2) adding temporary partitions
    at runtime (ioctl(BLKPG)). Unfortunately, this would possibly cause
    user-space breakage, as it will cause renumbering of the /dev/mtdX devices.
    We'll see if we can change this in the future, as there have already been a
    few people looking for this feature, and I know others have just been
    working around our current limitations instead of fixing them this way.
  * Along with the previous change, add some additional information to sysfs, so
    user-space can read the offset of each partition within its master device
 
 SPI NOR:
  * add new device tree compatible binding to represent the mostly-compatible
    class of SPI NOR flash which can be detected by their extended JEDEC ID
    bytes, cutting down the duplication of our ID tables
  * misc. new IDs
 
 Various other miscellaneous fixes and changes
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJVN9ypAAoJEFySrpd9RFgtaUQQAKmlCVMrxAKtF6U5jpzf07hA
 7ZrcMdUTSwS++dBIAgDl6JSuSGT5KRLrS1FOp60p+VAjbD9VFcRLUUQxahXW1tAh
 Dr8a3Akwd+lgIp77bZhWBY35dXmjIJ1GSzo7jdbJMDwAeDd3gBeSFTDoePsrCt6K
 0/NPOsQzCFDDr1lwuQh1LzkLLQfVAC3ImNCBm5smvyEfhxXqzC02HOLf8Z9VMGnY
 OxM9i0T6Ik3xeaaP/vH91sApmdn598gP5DB5cNr61YrZeVZmEoI4EWlOmagcYVC2
 Tef9Ng4YmHGXo65k7XcKRykAVWECYAGr4HKCDZ8tsbvpfdbQMS5wHEgxMsAdvb01
 aChcBNxf4w/Mh49fzjZppTlPN25FERRMnXt7CkUqQkqet9uDkD/5RNPl65ermeC7
 EKx2MoxnpXrfZ0EkSxqrfdzP0oQx0AqAkbCyLIN42Vbxl7ckFMN3WAPQ2NR2Aaoh
 SUiKwwaFFiK+C9qEytj0s+cmKPzsTzeQVYgp9NX64EfVQumqpsfbu6XIPV+FGy2i
 DvHvmTEvm4SpqMPSnhkmZ6DFSjuzvQdqzKtDyZmRppxHKgWUsXYdftGPMG0+ZbaG
 t4zysWfJG897TMVYLKY9pGqvouMuAVJ4kX1+iZbJc8dr4bwIzXIYuEGPLVv58gUO
 KjjlYk91/jFNmBW5anxC
 =aIsV
 -----END PGP SIGNATURE-----

Merge tag 'for-linus-20150422' of git://git.infradead.org/linux-mtd

Pull MTD updates from Brian Norris:
 "Common MTD:

   - Add Kconfig option for keeping both the 'master' and 'partition'
     MTDs registered as devices.  This would really make a better
     default if we could do it over, as it allows a lot more flexibility
     in (1) determining the flash topology of the system from user-space
     and (2) adding temporary partitions at runtime (ioctl(BLKPG)).

     Unfortunately, this would possibly cause user-space breakage, as it
     will cause renumbering of the /dev/mtdX devices.  We'll see if we
     can change this in the future, as there have already been a few
     people looking for this feature, and I know others have just been
     working around our current limitations instead of fixing them this
     way.

   - Along with the previous change, add some additional information to
     sysfs, so user-space can read the offset of each partition within
     its master device

  SPI NOR:

   - add new device tree compatible binding to represent the
     mostly-compatible class of SPI NOR flash which can be detected by
     their extended JEDEC ID bytes, cutting down the duplication of our
     ID tables

   - misc.  new IDs

  Various other miscellaneous fixes and changes"

* tag 'for-linus-20150422' of git://git.infradead.org/linux-mtd: (53 commits)
  mtd: spi-nor: Add support for Macronix mx25u6435f serial flash
  mtd: spi-nor: Add support for Winbond w25q64dw serial flash
  mtd: spi-nor: add support for the Winbond W25X05 flash
  mtd: spi-nor: support en25s64 device
  mtd: m25p80: bind to "nor-jedec" ID, for auto-detection
  Documentation: devicetree: m25p80: add "nor-jedec" binding
  mtd: Make MTD tests cancelable
  mtd: mtd_oobtest: Fix bitflip_limit usage in test case 3
  mtd: docg3: remove invalid __exit annotations
  mtd: fsl_ifc_nand: use msecs_to_jiffies for time conversion
  mtd: atmel_nand: don't map the ROM table if no pmecc table offset in DT
  mtd: atmel_nand: add a definition for the oob reserved bytes
  mtd: part: Remove partition overlap checks
  mtd: part: Add sysfs variable for offset of partition
  mtd: part: Create the master device node when partitioned
  mtd: ts5500_flash: Fix typo in MODULE_DESCRIPTION in ts5500_flash.c
  mtd: denali: Disable sub-page writes in Denali NAND driver
  mtd: pxa3xx_nand: cleanup wait_for_completion handling
  mtd: nand: gpmi: Check for scan_bbt() error
  mtd: nand: gpmi: fixup return type of wait_for_completion_timeout
  ...
This commit is contained in:
Linus Torvalds 2015-04-22 12:00:44 -07:00
commit a62d016cec
42 changed files with 640 additions and 318 deletions

View File

@ -222,3 +222,13 @@ Description:
The number of blocks that are marked as reserved, if any, in
this partition. These are typically used to store the in-flash
bad block table (BBT).
What: /sys/class/mtd/mtdX/offset
Date: March 2015
KernelVersion: 4.1
Contact: linux-mtd@lists.infradead.org
Description:
For a partition, the offset of that partition from the start
of the master device in bytes. This attribute is absent on
main devices, so it can be used to distinguish between
partitions and devices that aren't partitions.

View File

@ -3,10 +3,13 @@
Required properties:
- #address-cells, #size-cells : Must be present if the device has sub-nodes
representing partitions.
- compatible : Should be the manufacturer and the name of the chip. Bear in mind
the DT binding is not Linux-only, but in case of Linux, see the
"spi_nor_ids" table in drivers/mtd/spi-nor/spi-nor.c for the list
of supported chips.
- compatible : May include a device-specific string consisting of the
manufacturer and name of the chip. Bear in mind the DT binding
is not Linux-only, but in case of Linux, see the "m25p_ids"
table in drivers/mtd/devices/m25p80.c for the list of supported
chips.
Must also include "nor-jedec" for any SPI NOR flash that can be
identified by the JEDEC READ ID opcode (0x9F).
- reg : Chip-Select number
- spi-max-frequency : Maximum frequency of the SPI bus the chip can operate at
@ -22,7 +25,7 @@ Example:
flash: m25p80@0 {
#address-cells = <1>;
#size-cells = <1>;
compatible = "spansion,m25p80";
compatible = "spansion,m25p80", "nor-jedec";
reg = <0>;
spi-max-frequency = <40000000>;
m25p,fast-read;

View File

@ -14,7 +14,7 @@ Optional properties:
- marvell,nand-enable-arbiter: Set to enable the bus arbiter
- marvell,nand-keep-config: Set to keep the NAND controller config as set
by the bootloader
- num-cs: Number of chipselect lines to usw
- num-cs: Number of chipselect lines to use
- nand-on-flash-bbt: boolean to enable on flash bbt option if
not present false
- nand-ecc-strength: number of bits to correct per ECC step

View File

@ -21,7 +21,7 @@ Optional properties:
- nand-ecc-mode : one of the supported ECC modes ("hw", "hw_syndrome", "soft",
"soft_bch" or "none")
see Documentation/devicetree/mtd/nand.txt for generic bindings.
see Documentation/devicetree/bindings/mtd/nand.txt for generic bindings.
Examples:

View File

@ -309,6 +309,19 @@ config MTD_SWAP
The driver provides wear leveling by storing erase counter into the
OOB.
config MTD_PARTITIONED_MASTER
bool "Retain master device when partitioned"
default n
depends on MTD
help
For historical reasons, by default, either a master is present or
several partitions are present, but not both. The concern was that
data listed in multiple partitions was dangerous; however, SCSI does
this and it is frequently useful for applications. This config option
leaves the master in even if the device is partitioned. It also makes
the parent of the partition device be the master device, rather than
what lies behind the master.
source "drivers/mtd/chips/Kconfig"
source "drivers/mtd/maps/Kconfig"

View File

@ -206,23 +206,23 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum;
}
offset += (ersize * ernum);
}
}
if (offset != devsize) {
/* Argh */
printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
kfree(mtd->eraseregions);
kfree(cfi->cmdset_priv);
kfree(mtd);
return NULL;
}
if (offset != devsize) {
/* Argh */
printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
kfree(mtd->eraseregions);
kfree(cfi->cmdset_priv);
kfree(mtd);
return NULL;
}
for (i=0; i<mtd->numeraseregions;i++){
printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n",
i, (unsigned long long)mtd->eraseregions[i].offset,
mtd->eraseregions[i].erasesize,
mtd->eraseregions[i].numblocks);
}
for (i=0; i<mtd->numeraseregions;i++){
printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n",
i, (unsigned long long)mtd->eraseregions[i].offset,
mtd->eraseregions[i].erasesize,
mtd->eraseregions[i].numblocks);
}
/* Also select the correct geometry setup too */
mtd->_erase = cfi_staa_erase_varsize;

View File

@ -9,7 +9,15 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
/*
* When the first attempt at device initialization fails, we may need to
* wait a little bit and retry. This timeout, by default 3 seconds, gives
* device time to start up. Required on BCM2708 and a few other chipsets.
*/
#define MTD_DEFAULT_TIMEOUT 3
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/bio.h>
@ -209,10 +217,14 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
}
static struct block2mtd_dev *add_device(char *devname, int erase_size)
static struct block2mtd_dev *add_device(char *devname, int erase_size,
int timeout)
{
#ifndef MODULE
int i;
#endif
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
struct block_device *bdev;
struct block_device *bdev = ERR_PTR(-ENODEV);
struct block2mtd_dev *dev;
char *name;
@ -225,15 +237,28 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
/* Get a handle on the device */
bdev = blkdev_get_by_path(devname, mode, dev);
#ifndef MODULE
if (IS_ERR(bdev)) {
/*
* We might not have the root device mounted at this point.
* Try to resolve the device name by other means.
*/
for (i = 0; IS_ERR(bdev) && i <= timeout; i++) {
dev_t devt;
/* We might not have rootfs mounted at this point. Try
to resolve the device name by other means. */
if (i)
/*
* Calling wait_for_device_probe in the first loop
* was not enough, sleep for a bit in subsequent
* go-arounds.
*/
msleep(1000);
wait_for_device_probe();
dev_t devt = name_to_dev_t(devname);
if (devt)
bdev = blkdev_get_by_dev(devt, mode, dev);
devt = name_to_dev_t(devname);
if (!devt)
continue;
bdev = blkdev_get_by_dev(devt, mode, dev);
}
#endif
@ -280,6 +305,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
/* Device didn't get added, so free the entry */
goto err_destroy_mutex;
}
list_add(&dev->list, &blkmtd_device_list);
pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
dev->mtd.index,
@ -348,16 +374,19 @@ static inline void kill_final_newline(char *str)
#ifndef MODULE
static int block2mtd_init_called = 0;
static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */
/* 80 for device, 12 for erase size */
static char block2mtd_paramline[80 + 12];
#endif
static int block2mtd_setup2(const char *val)
{
char buf[80 + 12]; /* 80 for device, 12 for erase size */
/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
char buf[80 + 12 + 80 + 8];
char *str = buf;
char *token[2];
char *name;
size_t erase_size = PAGE_SIZE;
unsigned long timeout = MTD_DEFAULT_TIMEOUT;
int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf)) {
@ -395,7 +424,7 @@ static int block2mtd_setup2(const char *val)
}
}
add_device(name, erase_size);
add_device(name, erase_size, timeout);
return 0;
}
@ -463,8 +492,7 @@ static void block2mtd_exit(void)
}
}
module_init(block2mtd_init);
late_initcall(block2mtd_init);
module_exit(block2mtd_exit);
MODULE_LICENSE("GPL");

View File

@ -1805,7 +1805,7 @@ static int __init doc_dbg_register(struct docg3 *docg3)
}
}
static void __exit doc_dbg_unregister(struct docg3 *docg3)
static void doc_dbg_unregister(struct docg3 *docg3)
{
debugfs_remove_recursive(docg3->debugfs_root);
}
@ -2033,7 +2033,7 @@ static int __init docg3_probe(struct platform_device *pdev)
struct mtd_info *mtd;
struct resource *ress;
void __iomem *base;
int ret, floor, found = 0;
int ret, floor;
struct docg3_cascade *cascade;
ret = -ENXIO;
@ -2073,14 +2073,11 @@ static int __init docg3_probe(struct platform_device *pdev)
0);
if (ret)
goto err_probe;
found++;
}
ret = doc_register_sysfs(pdev, cascade);
if (ret)
goto err_probe;
if (!found)
goto notfound;
platform_set_drvdata(pdev, cascade);
doc_dbg_register(cascade->floors[0]->priv);
@ -2103,7 +2100,7 @@ err_probe:
*
* Returns 0
*/
static int __exit docg3_release(struct platform_device *pdev)
static int docg3_release(struct platform_device *pdev)
{
struct docg3_cascade *cascade = platform_get_drvdata(pdev);
struct docg3 *docg3 = cascade->floors[0]->priv;
@ -2134,7 +2131,7 @@ static struct platform_driver g3_driver = {
},
.suspend = docg3_suspend,
.resume = docg3_resume,
.remove = __exit_p(docg3_release),
.remove = docg3_release,
};
module_platform_driver_probe(g3_driver, docg3_probe);

View File

@ -223,6 +223,8 @@ static int m25p_probe(struct spi_device *spi)
*/
if (data && data->type)
flash_name = data->type;
else if (!strcmp(spi->modalias, "nor-jedec"))
flash_name = NULL; /* auto-detect */
else
flash_name = spi->modalias;
@ -247,9 +249,16 @@ static int m25p_remove(struct spi_device *spi)
}
/*
* XXX This needs to be kept in sync with spi_nor_ids. We can't share
* it with spi-nor, because if this is built as a module then modpost
* won't be able to read it and add appropriate aliases.
* Do NOT add to this array without reading the following:
*
* Historically, many flash devices are bound to this driver by their name. But
* since most of these flash are compatible to some extent, and their
* differences can often be differentiated by the JEDEC read-ID command, we
* encourage new users to add support to the spi-nor library, and simply bind
* against a generic string here (e.g., "nor-jedec").
*
* Many flash names are kept here in this list (as well as in spi-nor.c) to
* keep them available as module aliases for existing platforms.
*/
static const struct spi_device_id m25p_ids[] = {
{"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"},
@ -291,6 +300,12 @@ static const struct spi_device_id m25p_ids[] = {
{"w25x64"}, {"w25q64"}, {"w25q80"}, {"w25q80bl"},
{"w25q128"}, {"w25q256"}, {"cat25c11"},
{"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"},
/*
* Generic support for SPI NOR that can be identified by the JEDEC READ
* ID opcode (0x9F). Use this, if possible.
*/
{"nor-jedec"},
{ },
};
MODULE_DEVICE_TABLE(spi, m25p_ids);

View File

@ -242,7 +242,7 @@ config MTD_L440GX
config MTD_CFI_FLAGADM
tristate "CFI Flash device mapping on FlagaDM"
depends on 8xx && MTD_CFI
depends on PPC_8xx && MTD_CFI
help
Mapping for the Flaga digital module. If you don't have one, ignore
this setting.

View File

@ -274,7 +274,7 @@ static int sa1100_mtd_probe(struct platform_device *pdev)
return err;
}
static int __exit sa1100_mtd_remove(struct platform_device *pdev)
static int sa1100_mtd_remove(struct platform_device *pdev)
{
struct sa_info *info = platform_get_drvdata(pdev);
struct flash_platform_data *plat = dev_get_platdata(&pdev->dev);
@ -286,7 +286,7 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev)
static struct platform_driver sa1100_mtd_driver = {
.probe = sa1100_mtd_probe,
.remove = __exit_p(sa1100_mtd_remove),
.remove = sa1100_mtd_remove,
.driver = {
.name = "sa1100-mtd",
},

View File

@ -117,5 +117,5 @@ module_exit(cleanup_ts5500_map);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sean Young <sean@mess.org>");
MODULE_DESCRIPTION("MTD map driver for Techology Systems TS-5500 board");
MODULE_DESCRIPTION("MTD map driver for Technology Systems TS-5500 board");

View File

@ -171,9 +171,6 @@ static void mtd_blktrans_work(struct work_struct *work)
background_done = 0;
}
if (req)
__blk_end_request_all(req, -EIO);
spin_unlock_irq(rq->queue_lock);
}

View File

@ -38,6 +38,7 @@
#include <linux/gfp.h>
#include <linux/slab.h>
#include <linux/reboot.h>
#include <linux/kconfig.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
@ -501,6 +502,29 @@ out_error:
return ret;
}
static int mtd_add_device_partitions(struct mtd_info *mtd,
struct mtd_partition *real_parts,
int nbparts)
{
int ret;
if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) {
ret = add_mtd_device(mtd);
if (ret == 1)
return -ENODEV;
}
if (nbparts > 0) {
ret = add_mtd_partitions(mtd, real_parts, nbparts);
if (ret && IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER))
del_mtd_device(mtd);
return ret;
}
return 0;
}
/**
* mtd_device_parse_register - parse partitions and register an MTD device.
*
@ -523,7 +547,8 @@ out_error:
* found this functions tries to fallback to information specified in
* @parts/@nr_parts.
* * If any partitioning info was found, this function registers the found
* partitions.
* partitions. If the MTD_PARTITIONED_MASTER option is set, then the device
* as a whole is registered first.
* * If no partitions were found this function just registers the MTD device
* @mtd and exits.
*
@ -534,27 +559,21 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
const struct mtd_partition *parts,
int nr_parts)
{
int err;
struct mtd_partition *real_parts;
int ret;
struct mtd_partition *real_parts = NULL;
err = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
if (err <= 0 && nr_parts && parts) {
ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data);
if (ret <= 0 && nr_parts && parts) {
real_parts = kmemdup(parts, sizeof(*parts) * nr_parts,
GFP_KERNEL);
if (!real_parts)
err = -ENOMEM;
ret = -ENOMEM;
else
err = nr_parts;
ret = nr_parts;
}
if (err > 0) {
err = add_mtd_partitions(mtd, real_parts, err);
kfree(real_parts);
} else if (err == 0) {
err = add_mtd_device(mtd);
if (err == 1)
err = -ENODEV;
}
if (ret >= 0)
ret = mtd_add_device_partitions(mtd, real_parts, ret);
/*
* FIXME: some drivers unfortunately call this function more than once.
@ -569,7 +588,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
register_reboot_notifier(&mtd->reboot_notifier);
}
return err;
kfree(real_parts);
return ret;
}
EXPORT_SYMBOL_GPL(mtd_device_parse_register);

View File

@ -30,6 +30,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/err.h>
#include <linux/kconfig.h>
#include "mtdcore.h"
@ -379,10 +380,17 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.name = name;
slave->mtd.owner = master->owner;
/* NOTE: we don't arrange MTDs as a tree; it'd be error-prone
* to have the same data be in two different partitions.
/* NOTE: Historically, we didn't arrange MTDs as a tree out of
* concern for showing the same data in multiple partitions.
* However, it is very useful to have the master node present,
* so the MTD_PARTITIONED_MASTER option allows that. The master
* will have device nodes etc only if this is set, so make the
* parent conditional on that option. Note, this is a way to
* distinguish between the master and the partition in sysfs.
*/
slave->mtd.dev.parent = master->dev.parent;
slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ?
&master->dev :
master->dev.parent;
slave->mtd._read = part_read;
slave->mtd._write = part_write;
@ -546,12 +554,35 @@ out_register:
return slave;
}
static ssize_t mtd_partition_offset_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
struct mtd_part *part = PART(mtd);
return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset);
}
static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL);
static const struct attribute *mtd_partition_attrs[] = {
&dev_attr_offset.attr,
NULL
};
static int mtd_add_partition_attrs(struct mtd_part *new)
{
int ret = sysfs_create_files(&new->mtd.dev.kobj, mtd_partition_attrs);
if (ret)
printk(KERN_WARNING
"mtd: failed to create partition attrs, err=%d\n", ret);
return ret;
}
int mtd_add_partition(struct mtd_info *master, const char *name,
long long offset, long long length)
{
struct mtd_partition part;
struct mtd_part *p, *new;
uint64_t start, end;
struct mtd_part *new;
int ret = 0;
/* the direct offset is expected */
@ -575,31 +606,15 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
if (IS_ERR(new))
return PTR_ERR(new);
start = offset;
end = offset + length;
mutex_lock(&mtd_partitions_mutex);
list_for_each_entry(p, &mtd_partitions, list)
if (p->master == master) {
if ((start >= p->offset) &&
(start < (p->offset + p->mtd.size)))
goto err_inv;
if ((end >= p->offset) &&
(end < (p->offset + p->mtd.size)))
goto err_inv;
}
list_add(&new->list, &mtd_partitions);
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&new->mtd);
mtd_add_partition_attrs(new);
return ret;
err_inv:
mutex_unlock(&mtd_partitions_mutex);
free_partition(new);
return -EINVAL;
}
EXPORT_SYMBOL_GPL(mtd_add_partition);
@ -612,6 +627,8 @@ int mtd_del_partition(struct mtd_info *master, int partno)
list_for_each_entry_safe(slave, next, &mtd_partitions, list)
if ((slave->master == master) &&
(slave->mtd.index == partno)) {
sysfs_remove_files(&slave->mtd.dev.kobj,
mtd_partition_attrs);
ret = del_mtd_device(&slave->mtd);
if (ret < 0)
break;
@ -631,8 +648,8 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
* and registers slave MTD objects which are bound to the master according to
* the partition definitions.
*
* We don't register the master, or expect the caller to have done so,
* for reasons of data integrity.
* For historical reasons, this function's caller only registers the master
* if the MTD_PARTITIONED_MASTER config option is set.
*/
int add_mtd_partitions(struct mtd_info *master,
@ -655,6 +672,7 @@ int add_mtd_partitions(struct mtd_info *master,
mutex_unlock(&mtd_partitions_mutex);
add_mtd_device(&slave->mtd);
mtd_add_partition_attrs(slave);
cur_offset = slave->offset + slave->mtd.size;
}

View File

@ -485,7 +485,7 @@ static void pmecc_config_ecc_layout(struct nand_ecclayout *layout,
for (i = 0; i < ecc_len; i++)
layout->eccpos[i] = oobsize - ecc_len + i;
layout->oobfree[0].offset = 2;
layout->oobfree[0].offset = PMECC_OOB_RESERVED_BYTES;
layout->oobfree[0].length =
oobsize - ecc_len - layout->oobfree[0].offset;
}
@ -1204,14 +1204,14 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
goto err;
}
regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom);
if (IS_ERR(host->pmecc_rom_base)) {
if (!host->has_no_lookup_table)
/* Don't display the information again */
if (!host->has_no_lookup_table) {
regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3);
host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev,
regs_rom);
if (IS_ERR(host->pmecc_rom_base)) {
dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n");
host->has_no_lookup_table = true;
host->has_no_lookup_table = true;
}
}
if (host->has_no_lookup_table) {
@ -1254,7 +1254,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
nand_chip->ecc.steps = mtd->writesize / sector_size;
nand_chip->ecc.total = nand_chip->ecc.bytes *
nand_chip->ecc.steps;
if (nand_chip->ecc.total > mtd->oobsize - 2) {
if (nand_chip->ecc.total >
mtd->oobsize - PMECC_OOB_RESERVED_BYTES) {
dev_err(host->dev, "No room for ECC bytes\n");
err_no = -EINVAL;
goto err;
@ -1719,7 +1720,7 @@ static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag)
comp[index++] = &host->nfc->comp_cmd_done;
if (index == 0) {
dev_err(host->dev, "Unkown interrupt flag: 0x%08x\n", flag);
dev_err(host->dev, "Unknown interrupt flag: 0x%08x\n", flag);
return -EINVAL;
}
@ -1752,11 +1753,10 @@ static int nfc_send_command(struct atmel_nand_host *host,
cmd, addr, cycle0);
timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS);
while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs)
& NFCADDR_CMD_NFCBUSY) {
while (nfc_readl(host->nfc->hsmc_regs, SR) & NFC_SR_BUSY) {
if (time_after(jiffies, timeout)) {
dev_err(host->dev,
"Time out to wait CMD_NFCBUSY ready!\n");
"Time out to wait for NFC ready!\n");
return -ETIMEDOUT;
}
}

View File

@ -152,4 +152,7 @@
/* Time out value for reading PMECC status register */
#define PMECC_MAX_TIMEOUT_MS 100
/* Reserved bytes in oob area */
#define PMECC_OOB_RESERVED_BYTES 2
#endif

View File

@ -35,6 +35,7 @@
#define NFC_CTRL_DISABLE (1 << 1)
#define ATMEL_HSMC_NFC_SR 0x08 /* NFC Status Register */
#define NFC_SR_BUSY (1 << 8)
#define NFC_SR_XFR_DONE (1 << 16)
#define NFC_SR_CMD_DONE (1 << 17)
#define NFC_SR_DTOE (1 << 20)

View File

@ -225,7 +225,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60};
uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15};
uint16_t TclsRising = 1;
uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid;
uint16_t dv_window = 0;
uint16_t en_lo, en_hi;
@ -276,8 +275,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali,
re_2_re = CEIL_DIV(Trhz[mode], CLK_X);
we_2_re = CEIL_DIV(Twhr[mode], CLK_X);
cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X);
if (!TclsRising)
cs_cnt = CEIL_DIV(Tcs[mode], CLK_X);
if (cs_cnt == 0)
cs_cnt = 1;
@ -1536,6 +1533,9 @@ int denali_init(struct denali_nand_info *denali)
denali->nand.options |= NAND_SKIP_BBTSCAN;
denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
/* no subpage writes on denali */
denali->nand.options |= NAND_NO_SUBPAGE_WRITE;
/*
* Denali Controller only support 15bit and 8bit ECC in MRST,
* so just let controller do 15bit ECC for MLC and 8bit ECC for

View File

@ -317,7 +317,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd)
/* wait for command complete flag or timeout */
wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
IFC_TIMEOUT_MSECS * HZ/1000);
msecs_to_jiffies(IFC_TIMEOUT_MSECS));
/* ctrl->nand_stat will be updated from IRQ context */
if (!ctrl->nand_stat)
@ -860,7 +860,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv)
/* wait for command complete flag or timeout */
wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat,
IFC_TIMEOUT_MSECS * HZ/1000);
msecs_to_jiffies(IFC_TIMEOUT_MSECS));
if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC)
printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n");

View File

@ -873,6 +873,7 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
{
struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
u32 val;
int ret;
/* Set default NAND width to 8 bits */
pdata->width = 8;
@ -891,8 +892,12 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
sizeof(*pdata->nand_timings), GFP_KERNEL);
if (!pdata->nand_timings)
return -ENOMEM;
of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
ret = of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
sizeof(*pdata->nand_timings));
if (ret) {
dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n");
pdata->nand_timings = NULL;
}
/* Set default NAND bank to 0 */
pdata->bank = 0;

View File

@ -446,7 +446,7 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this,
struct dma_async_tx_descriptor *desc)
{
struct completion *dma_c = &this->dma_done;
int err;
unsigned long timeout;
init_completion(dma_c);
@ -456,8 +456,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this,
dma_async_issue_pending(get_dma_chan(this));
/* Wait for the interrupt from the DMA block. */
err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
if (!err) {
timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
if (!timeout) {
dev_err(this->dev, "DMA timeout, last DMA :%d\n",
this->last_dma_type);
gpmi_dump_info(this);
@ -477,7 +477,7 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this,
struct dma_async_tx_descriptor *desc)
{
struct completion *bch_c = &this->bch_done;
int err;
unsigned long timeout;
/* Prepare to receive an interrupt from the BCH block. */
init_completion(bch_c);
@ -486,8 +486,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this,
start_dma_without_bch_irq(this, desc);
/* Wait for the interrupt from the BCH block. */
err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
if (!err) {
timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
if (!timeout) {
dev_err(this->dev, "BCH timeout, last DMA :%d\n",
this->last_dma_type);
gpmi_dump_info(this);
@ -1950,7 +1950,9 @@ static int gpmi_nand_init(struct gpmi_nand_data *this)
ret = nand_boot_init(this);
if (ret)
goto err_out;
chip->scan_bbt(mtd);
ret = chip->scan_bbt(mtd);
if (ret)
goto err_out;
ppdata.of_node = this->pdev->dev.of_node;
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);

View File

@ -386,26 +386,51 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id)
/* This function polls the NANDFC to wait for the basic operation to
* complete by checking the INT bit of config2 register.
*/
static void wait_op_done(struct mxc_nand_host *host, int useirq)
static int wait_op_done(struct mxc_nand_host *host, int useirq)
{
int max_retries = 8000;
int ret = 0;
/*
* If operation is already complete, don't bother to setup an irq or a
* loop.
*/
if (host->devtype_data->check_int(host))
return 0;
if (useirq) {
if (!host->devtype_data->check_int(host)) {
reinit_completion(&host->op_completion);
irq_control(host, 1);
wait_for_completion(&host->op_completion);
unsigned long timeout;
reinit_completion(&host->op_completion);
irq_control(host, 1);
timeout = wait_for_completion_timeout(&host->op_completion, HZ);
if (!timeout && !host->devtype_data->check_int(host)) {
dev_dbg(host->dev, "timeout waiting for irq\n");
ret = -ETIMEDOUT;
}
} else {
while (max_retries-- > 0) {
if (host->devtype_data->check_int(host))
int max_retries = 8000;
int done;
do {
udelay(1);
done = host->devtype_data->check_int(host);
if (done)
break;
udelay(1);
} while (--max_retries);
if (!done) {
dev_dbg(host->dev, "timeout polling for completion\n");
ret = -ETIMEDOUT;
}
if (max_retries < 0)
pr_debug("%s: INT not set\n", __func__);
}
WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq);
return ret;
}
static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq)
@ -527,30 +552,17 @@ static void send_page_v1(struct mtd_info *mtd, unsigned int ops)
static void send_read_id_v3(struct mxc_nand_host *host)
{
struct nand_chip *this = &host->nand;
/* Read ID into main buffer */
writel(NFC_ID, NFC_V3_LAUNCH);
wait_op_done(host, true);
memcpy32_fromio(host->data_buf, host->main_area0, 16);
if (this->options & NAND_BUSWIDTH_16) {
/* compress the ID info */
host->data_buf[1] = host->data_buf[2];
host->data_buf[2] = host->data_buf[4];
host->data_buf[3] = host->data_buf[6];
host->data_buf[4] = host->data_buf[8];
host->data_buf[5] = host->data_buf[10];
}
}
/* Request the NANDFC to perform a read of the NAND device ID. */
static void send_read_id_v1_v2(struct mxc_nand_host *host)
{
struct nand_chip *this = &host->nand;
/* NANDFC buffer 0 is used for device ID output */
writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR);
@ -560,15 +572,6 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host)
wait_op_done(host, true);
memcpy32_fromio(host->data_buf, host->main_area0, 16);
if (this->options & NAND_BUSWIDTH_16) {
/* compress the ID info */
host->data_buf[1] = host->data_buf[2];
host->data_buf[2] = host->data_buf[4];
host->data_buf[3] = host->data_buf[6];
host->data_buf[4] = host->data_buf[8];
host->data_buf[5] = host->data_buf[10];
}
}
static uint16_t get_dev_status_v3(struct mxc_nand_host *host)
@ -694,9 +697,17 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd)
if (host->status_request)
return host->devtype_data->get_dev_status(host) & 0xFF;
ret = *(uint8_t *)(host->data_buf + host->buf_start);
host->buf_start++;
if (nand_chip->options & NAND_BUSWIDTH_16) {
/* only take the lower byte of each word */
ret = *(uint16_t *)(host->data_buf + host->buf_start);
host->buf_start += 2;
} else {
ret = *(uint8_t *)(host->data_buf + host->buf_start);
host->buf_start++;
}
pr_debug("%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start);
return ret;
}
@ -825,6 +836,12 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom)
}
}
/*
* MXC NANDFC can only perform full page+spare or spare-only read/write. When
* the upper layers perform a read/write buf operation, the saved column address
* is used to index into the full page. So usually this function is called with
* column == 0 (unless no column cycle is needed indicated by column == -1)
*/
static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
{
struct nand_chip *nand_chip = mtd->priv;
@ -832,16 +849,13 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr)
/* Write out column address, if necessary */
if (column != -1) {
/*
* MXC NANDFC can only perform full page+spare or
* spare-only read/write. When the upper layers
* perform a read/write buf operation, the saved column
* address is used to index into the full page.
*/
host->devtype_data->send_addr(host, 0, page_addr == -1);
host->devtype_data->send_addr(host, column & 0xff,
page_addr == -1);
if (mtd->writesize > 512)
/* another col addr cycle for 2k page */
host->devtype_data->send_addr(host, 0, false);
host->devtype_data->send_addr(host,
(column >> 8) & 0xff,
false);
}
/* Write out page address, if necessary */
@ -903,7 +917,7 @@ static void preset_v1(struct mtd_info *mtd)
struct mxc_nand_host *host = nand_chip->priv;
uint16_t config1 = 0;
if (nand_chip->ecc.mode == NAND_ECC_HW)
if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize)
config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
if (!host->devtype_data->irqpending_quirk)
@ -931,9 +945,6 @@ static void preset_v2(struct mtd_info *mtd)
struct mxc_nand_host *host = nand_chip->priv;
uint16_t config1 = 0;
if (nand_chip->ecc.mode == NAND_ECC_HW)
config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
config1 |= NFC_V2_CONFIG1_FP_INT;
if (!host->devtype_data->irqpending_quirk)
@ -942,6 +953,9 @@ static void preset_v2(struct mtd_info *mtd)
if (mtd->writesize) {
uint16_t pages_per_block = mtd->erasesize / mtd->writesize;
if (nand_chip->ecc.mode == NAND_ECC_HW)
config1 |= NFC_V1_V2_CONFIG1_ECC_EN;
host->eccsize = get_eccsize(mtd);
if (host->eccsize == 4)
config1 |= NFC_V2_CONFIG1_ECC_MODE_4;
@ -999,9 +1013,6 @@ static void preset_v3(struct mtd_info *mtd)
NFC_V3_CONFIG2_INT_MSK |
NFC_V3_CONFIG2_NUM_ADDR_PHASE0;
if (chip->ecc.mode == NAND_ECC_HW)
config2 |= NFC_V3_CONFIG2_ECC_EN;
addr_phases = fls(chip->pagemask) >> 3;
if (mtd->writesize == 2048) {
@ -1016,6 +1027,9 @@ static void preset_v3(struct mtd_info *mtd)
}
if (mtd->writesize) {
if (chip->ecc.mode == NAND_ECC_HW)
config2 |= NFC_V3_CONFIG2_ECC_EN;
config2 |= NFC_V3_CONFIG2_PPB(
ffs(mtd->erasesize / mtd->writesize) - 6,
host->devtype_data->ppb_shift);
@ -1066,6 +1080,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
host->status_request = true;
host->devtype_data->send_cmd(host, command, true);
WARN_ONCE(column != -1 || page_addr != -1,
"Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
command, column, page_addr);
mxc_do_addr_cycle(mtd, column, page_addr);
break;
@ -1079,7 +1096,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
command = NAND_CMD_READ0; /* only READ0 is valid */
host->devtype_data->send_cmd(host, command, false);
mxc_do_addr_cycle(mtd, column, page_addr);
WARN_ONCE(column < 0,
"Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
command, column, page_addr);
mxc_do_addr_cycle(mtd, 0, page_addr);
if (mtd->writesize > 512)
host->devtype_data->send_cmd(host,
@ -1100,7 +1120,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
host->buf_start = column;
host->devtype_data->send_cmd(host, command, false);
mxc_do_addr_cycle(mtd, column, page_addr);
WARN_ONCE(column < -1,
"Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
command, column, page_addr);
mxc_do_addr_cycle(mtd, 0, page_addr);
break;
case NAND_CMD_PAGEPROG:
@ -1108,6 +1131,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
copy_spare(mtd, false);
host->devtype_data->send_page(mtd, NFC_INPUT);
host->devtype_data->send_cmd(host, command, true);
WARN_ONCE(column != -1 || page_addr != -1,
"Unexpected column/row value (cmd=%u, col=%d, row=%d)\n",
command, column, page_addr);
mxc_do_addr_cycle(mtd, column, page_addr);
break;
@ -1115,15 +1141,29 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command,
host->devtype_data->send_cmd(host, command, true);
mxc_do_addr_cycle(mtd, column, page_addr);
host->devtype_data->send_read_id(host);
host->buf_start = column;
host->buf_start = 0;
break;
case NAND_CMD_ERASE1:
case NAND_CMD_ERASE2:
host->devtype_data->send_cmd(host, command, false);
WARN_ONCE(column != -1,
"Unexpected column value (cmd=%u, col=%d)\n",
command, column);
mxc_do_addr_cycle(mtd, column, page_addr);
break;
case NAND_CMD_PARAM:
host->devtype_data->send_cmd(host, command, false);
mxc_do_addr_cycle(mtd, column, page_addr);
host->devtype_data->send_page(mtd, NFC_OUTPUT);
memcpy32_fromio(host->data_buf, host->main_area0, 512);
host->buf_start = 0;
break;
default:
WARN_ONCE(1, "Unimplemented command (cmd=%u)\n",
command);
break;
}
}

View File

@ -386,7 +386,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
uint8_t buf[2] = { 0, 0 };
int ret = 0, res, i = 0;
ops.datbuf = NULL;
memset(&ops, 0, sizeof(ops));
ops.oobbuf = buf;
ops.ooboffs = chip->badblockpos;
if (chip->options & NAND_BUSWIDTH_16) {
@ -565,6 +565,25 @@ void nand_wait_ready(struct mtd_info *mtd)
}
EXPORT_SYMBOL_GPL(nand_wait_ready);
/**
* nand_wait_status_ready - [GENERIC] Wait for the ready status after commands.
* @mtd: MTD device structure
* @timeo: Timeout in ms
*
* Wait for status ready (i.e. command done) or timeout.
*/
static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo)
{
register struct nand_chip *chip = mtd->priv;
timeo = jiffies + msecs_to_jiffies(timeo);
do {
if ((chip->read_byte(mtd) & NAND_STATUS_READY))
break;
touch_softlockup_watchdog();
} while (time_before(jiffies, timeo));
};
/**
* nand_command - [DEFAULT] Send command to NAND device
* @mtd: MTD device structure
@ -643,8 +662,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
NAND_CTRL_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd,
NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE);
while (!(chip->read_byte(mtd) & NAND_STATUS_READY))
;
/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
nand_wait_status_ready(mtd, 250);
return;
/* This applies to read commands */
@ -740,8 +759,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE);
chip->cmd_ctrl(mtd, NAND_CMD_NONE,
NAND_NCE | NAND_CTRL_CHANGE);
while (!(chip->read_byte(mtd) & NAND_STATUS_READY))
;
/* EZ-NAND can take upto 250ms as per ONFi v4.0 */
nand_wait_status_ready(mtd, 250);
return;
case NAND_CMD_RNDOUT:
@ -968,7 +987,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
__func__, (unsigned long long)ofs, len);
if (check_offs_len(mtd, ofs, len))
ret = -EINVAL;
return -EINVAL;
/* Align to last block address if size addresses end of the device */
if (ofs + len == mtd->size)
@ -1031,7 +1050,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
__func__, (unsigned long long)ofs, len);
if (check_offs_len(mtd, ofs, len))
ret = -EINVAL;
return -EINVAL;
nand_get_device(mtd, FL_LOCKING);
@ -1716,9 +1735,9 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
int ret;
nand_get_device(mtd, FL_READING);
memset(&ops, 0, sizeof(ops));
ops.len = len;
ops.datbuf = buf;
ops.oobbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_read_ops(mtd, from, &ops);
*retlen = ops.retlen;
@ -2124,7 +2143,7 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
/**
* nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write
* nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write
* @mtd: mtd info structure
* @chip: nand chip info structure
* @offset: column address of subpage within the page
@ -2508,9 +2527,9 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
/* Grab the device */
panic_nand_get_device(chip, mtd, FL_WRITING);
memset(&ops, 0, sizeof(ops));
ops.len = len;
ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_write_ops(mtd, to, &ops);
@ -2536,9 +2555,9 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len,
int ret;
nand_get_device(mtd, FL_WRITING);
memset(&ops, 0, sizeof(ops));
ops.len = len;
ops.datbuf = (uint8_t *)buf;
ops.oobbuf = NULL;
ops.mode = MTD_OPS_PLACE_OOB;
ret = nand_do_write_ops(mtd, to, &ops);
*retlen = ops.retlen;

View File

@ -38,8 +38,8 @@
#include <linux/platform_data/mtd-nand-pxa3xx.h>
#define CHIP_DELAY_TIMEOUT (2 * HZ/10)
#define NAND_STOP_DELAY (2 * HZ/50)
#define CHIP_DELAY_TIMEOUT msecs_to_jiffies(200)
#define NAND_STOP_DELAY msecs_to_jiffies(40)
#define PAGE_CHUNK_SIZE (2048)
/*
@ -605,11 +605,24 @@ static void start_data_dma(struct pxa3xx_nand_info *info)
{}
#endif
static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data)
{
struct pxa3xx_nand_info *info = data;
handle_data_pio(info);
info->state = STATE_CMD_DONE;
nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ);
return IRQ_HANDLED;
}
static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
{
struct pxa3xx_nand_info *info = devid;
unsigned int status, is_completed = 0, is_ready = 0;
unsigned int ready, cmd_done;
irqreturn_t ret = IRQ_HANDLED;
if (info->cs == 0) {
ready = NDSR_FLASH_RDY;
@ -651,7 +664,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
} else {
info->state = (status & NDSR_RDDREQ) ?
STATE_PIO_READING : STATE_PIO_WRITING;
handle_data_pio(info);
ret = IRQ_WAKE_THREAD;
goto NORMAL_IRQ_EXIT;
}
}
if (status & cmd_done) {
@ -692,7 +706,7 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
if (is_ready)
complete(&info->dev_ready);
NORMAL_IRQ_EXIT:
return IRQ_HANDLED;
return ret;
}
static inline int is_buf_blank(uint8_t *buf, size_t len)
@ -951,7 +965,7 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
{
struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
int ret, exec_cmd;
int exec_cmd;
/*
* if this is a x16 device ,then convert the input
@ -983,9 +997,8 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
info->need_wait = 1;
pxa3xx_nand_start(info);
ret = wait_for_completion_timeout(&info->cmd_complete,
CHIP_DELAY_TIMEOUT);
if (!ret) {
if (!wait_for_completion_timeout(&info->cmd_complete,
CHIP_DELAY_TIMEOUT)) {
dev_err(&info->pdev->dev, "Wait time out!!!\n");
/* Stop State Machine for next command cycle */
pxa3xx_nand_stop(info);
@ -1000,7 +1013,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
{
struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
int ret, exec_cmd, ext_cmd_type;
int exec_cmd, ext_cmd_type;
/*
* if this is a x16 device then convert the input
@ -1063,9 +1076,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd,
init_completion(&info->cmd_complete);
pxa3xx_nand_start(info);
ret = wait_for_completion_timeout(&info->cmd_complete,
CHIP_DELAY_TIMEOUT);
if (!ret) {
if (!wait_for_completion_timeout(&info->cmd_complete,
CHIP_DELAY_TIMEOUT)) {
dev_err(&info->pdev->dev, "Wait time out!!!\n");
/* Stop State Machine for next command cycle */
pxa3xx_nand_stop(info);
@ -1198,13 +1210,11 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
{
struct pxa3xx_nand_host *host = mtd->priv;
struct pxa3xx_nand_info *info = host->info_data;
int ret;
if (info->need_wait) {
ret = wait_for_completion_timeout(&info->dev_ready,
CHIP_DELAY_TIMEOUT);
info->need_wait = 0;
if (!ret) {
if (!wait_for_completion_timeout(&info->dev_ready,
CHIP_DELAY_TIMEOUT)) {
dev_err(&info->pdev->dev, "Ready time out!!!\n");
return NAND_STATUS_FAIL;
}
@ -1508,6 +1518,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
return ret;
}
memset(pxa3xx_flash_ids, 0, sizeof(pxa3xx_flash_ids));
pxa3xx_flash_ids[0].name = f->name;
pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff;
pxa3xx_flash_ids[0].pagesize = f->page_size;
@ -1710,7 +1722,9 @@ static int alloc_nand_resource(struct platform_device *pdev)
/* initialize all interrupts to be disabled */
disable_int(info, NDSR_MASK);
ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info);
ret = request_threaded_irq(irq, pxa3xx_nand_irq,
pxa3xx_nand_irq_thread, IRQF_ONESHOT,
pdev->name, info);
if (ret < 0) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto fail_free_buf;

View File

@ -948,8 +948,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
cpu_type = platform_get_device_id(pdev)->driver_data;
pr_debug("s3c2410_nand_probe(%p)\n", pdev);
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
err = -ENOMEM;
@ -1045,7 +1043,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND);
}
pr_debug("initialised ok\n");
return 0;
exit_error:

View File

@ -1743,7 +1743,6 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
struct onenand_chip *this = mtd->priv;
int column, subpage;
int written = 0;
int ret = 0;
if (this->state == FL_PM_SUSPENDED)
return -EBUSY;
@ -1786,15 +1785,10 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
onenand_panic_wait(mtd);
/* In partial page write we don't update bufferram */
onenand_update_bufferram(mtd, to, !ret && !subpage);
onenand_update_bufferram(mtd, to, !subpage);
if (ONENAND_IS_2PLANE(this)) {
ONENAND_SET_BUFFERRAM1(this);
onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage);
}
if (ret) {
printk(KERN_ERR "%s: write failed %d\n", __func__, ret);
break;
onenand_update_bufferram(mtd, to + this->writesize, !subpage);
}
written += thislen;
@ -1808,7 +1802,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
}
*retlen = written;
return ret;
return 0;
}
/**

View File

@ -460,8 +460,7 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len)
writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR);
/* Wait for the interrupt. */
err = wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000));
if (!err) {
if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) {
dev_err(q->dev,
"cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n",
cmd, addr, readl(base + QUADSPI_FR),
@ -830,27 +829,27 @@ static int fsl_qspi_probe(struct platform_device *pdev)
ret = clk_prepare_enable(q->clk_en);
if (ret) {
dev_err(dev, "can not enable the qspi_en clock\n");
dev_err(dev, "cannot enable the qspi_en clock: %d\n", ret);
return ret;
}
ret = clk_prepare_enable(q->clk);
if (ret) {
dev_err(dev, "can not enable the qspi clock\n");
dev_err(dev, "cannot enable the qspi clock: %d\n", ret);
goto clk_failed;
}
/* find the irq */
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(dev, "failed to get the irq\n");
dev_err(dev, "failed to get the irq: %d\n", ret);
goto irq_failed;
}
ret = devm_request_irq(dev, ret,
fsl_qspi_irq_handler, 0, pdev->name, q);
if (ret) {
dev_err(dev, "failed to request irq.\n");
dev_err(dev, "failed to request irq: %d\n", ret);
goto irq_failed;
}

View File

@ -369,17 +369,13 @@ erase_err:
return ret;
}
static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
struct mtd_info *mtd = nor->mtd;
uint32_t offset = ofs;
uint8_t status_old, status_new;
int ret = 0;
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK);
if (ret)
return ret;
status_old = read_sr(nor);
if (offset < mtd->size - (mtd->size / 2))
@ -402,26 +398,18 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
(status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
write_enable(nor);
ret = write_sr(nor, status_new);
if (ret)
goto err;
}
err:
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
return ret;
}
static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
struct mtd_info *mtd = nor->mtd;
uint32_t offset = ofs;
uint8_t status_old, status_new;
int ret = 0;
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
if (ret)
return ret;
status_old = read_sr(nor);
if (offset+len > mtd->size - (mtd->size / 64))
@ -444,15 +432,41 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
(status_old & (SR_BP2 | SR_BP1 | SR_BP0))) {
write_enable(nor);
ret = write_sr(nor, status_new);
if (ret)
goto err;
}
err:
return ret;
}
static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
int ret;
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK);
if (ret)
return ret;
ret = nor->flash_lock(nor, ofs, len);
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK);
return ret;
}
static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
{
struct spi_nor *nor = mtd_to_spi_nor(mtd);
int ret;
ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK);
if (ret)
return ret;
ret = nor->flash_unlock(nor, ofs, len);
spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK);
return ret;
}
/* Used when the "_ext_id" is two bytes at most */
#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \
((kernel_ulong_t)&(struct flash_info) { \
@ -524,6 +538,7 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
{ "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, 0) },
/* ESMT */
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
@ -553,6 +568,7 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) },
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) },
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
@ -648,6 +664,7 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) },
/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
{ "w25x05", INFO(0xef3010, 0, 64 * 1024, 1, SECT_4K) },
{ "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) },
{ "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) },
{ "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) },
@ -658,6 +675,7 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) },
{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K) },
{ "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
@ -1045,6 +1063,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
/* nor protection support for STmicro chips */
if (JEDEC_MFR(info) == CFI_MFR_ST) {
nor->flash_lock = stm_lock;
nor->flash_unlock = stm_unlock;
}
if (nor->flash_lock && nor->flash_unlock) {
mtd->_lock = spi_nor_lock;
mtd->_unlock = spi_nor_unlock;
}

View File

@ -9,6 +9,8 @@
#include <linux/slab.h>
#include <linux/mtd/nand_ecc.h>
#include "mtd_test.h"
/*
* Test the implementation for software ECC
*
@ -274,6 +276,10 @@ static int nand_ecc_test_run(const size_t size)
}
pr_info("ok - %s-%zd\n",
nand_ecc_test[i].name, size);
err = mtdtest_relax();
if (err)
break;
}
error:
kfree(error_data);

View File

@ -1,4 +1,16 @@
#include <linux/mtd/mtd.h>
#include <linux/sched.h>
static inline int mtdtest_relax(void)
{
cond_resched();
if (signal_pending(current)) {
pr_info("aborting test due to pending signal!\n");
return -EINTR;
}
return 0;
}
int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum);
int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt,

View File

@ -320,6 +320,10 @@ static int overwrite_test(void)
break;
}
err = mtdtest_relax();
if (err)
break;
opno++;
}

View File

@ -70,7 +70,7 @@ static int write_eraseblock(int ebnum)
int i;
struct mtd_oob_ops ops;
int err = 0;
loff_t addr = ebnum * mtd->erasesize;
loff_t addr = (loff_t)ebnum * mtd->erasesize;
prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt);
for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) {
@ -112,7 +112,10 @@ static int write_whole_device(void)
return err;
if (i % 256 == 0)
pr_info("written up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
return err;
}
pr_info("written %u eraseblocks\n", i);
return 0;
@ -141,6 +144,31 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou
return bitflips;
}
/*
* Compare with 0xff and show the address, offset and data bytes at
* comparison failure. Return number of bitflips encountered.
*/
static size_t memffshow(loff_t addr, loff_t offset, const void *cs,
size_t count)
{
const unsigned char *su1;
int res;
size_t i = 0;
size_t bitflips = 0;
for (su1 = cs; 0 < count; ++su1, count--, i++) {
res = *su1 ^ 0xff;
if (res) {
pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0xff diff 0x%x\n",
(unsigned long)addr, (unsigned long)offset + i,
*su1, res);
bitflips += hweight8(res);
}
}
return bitflips;
}
static int verify_eraseblock(int ebnum)
{
int i;
@ -203,6 +231,15 @@ static int verify_eraseblock(int ebnum)
bitflips = memcmpshow(addr, readbuf + use_offset,
writebuf + (use_len_max * i) + use_offset,
use_len);
/* verify pre-offset area for 0xff */
bitflips += memffshow(addr, 0, readbuf, use_offset);
/* verify post-(use_offset + use_len) area for 0xff */
k = use_offset + use_len;
bitflips += memffshow(addr, k, readbuf + k,
mtd->ecclayout->oobavail - k);
if (bitflips > bitflip_limit) {
pr_err("error: verify failed at %#llx\n",
(long long)addr);
@ -212,34 +249,8 @@ static int verify_eraseblock(int ebnum)
return -1;
}
} else if (bitflips) {
pr_info("ignoring error as within bitflip_limit\n");
pr_info("ignoring errors as within bitflip limit\n");
}
for (k = 0; k < use_offset; ++k)
if (readbuf[k] != 0xff) {
pr_err("error: verify 0xff "
"failed at %#llx\n",
(long long)addr);
errcnt += 1;
if (errcnt > 1000) {
pr_err("error: too "
"many errors\n");
return -1;
}
}
for (k = use_offset + use_len;
k < mtd->ecclayout->oobavail; ++k)
if (readbuf[k] != 0xff) {
pr_err("error: verify 0xff "
"failed at %#llx\n",
(long long)addr);
errcnt += 1;
if (errcnt > 1000) {
pr_err("error: too "
"many errors\n");
return -1;
}
}
}
if (vary_offset)
do_vary_offset();
@ -310,7 +321,10 @@ static int verify_all_eraseblocks(void)
return err;
if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
return err;
}
pr_info("verified %u eraseblocks\n", i);
return 0;
@ -421,7 +435,10 @@ static int __init mtd_oobtest_init(void)
goto out;
if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("verified %u eraseblocks\n", i);
@ -634,7 +651,11 @@ static int __init mtd_oobtest_init(void)
goto out;
if (i % 256 == 0)
pr_info("written up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
addr += mtd->writesize;
}
}
@ -672,7 +693,10 @@ static int __init mtd_oobtest_init(void)
}
if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("verified %u eraseblocks\n", i);

View File

@ -407,7 +407,10 @@ static int __init mtd_pagetest_init(void)
goto out;
if (i % 256 == 0)
pr_info("written up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("written %u eraseblocks\n", i);
@ -422,7 +425,10 @@ static int __init mtd_pagetest_init(void)
goto out;
if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("verified %u eraseblocks\n", i);

View File

@ -190,7 +190,10 @@ static int __init mtd_readtest_init(void)
if (!err)
err = ret;
}
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
if (err)

View File

@ -185,7 +185,7 @@ static long calc_speed(void)
(finish.tv_usec - start.tv_usec) / 1000;
if (ms == 0)
return 0;
k = goodebcnt * (mtd->erasesize / 1024) * 1000;
k = (uint64_t)goodebcnt * (mtd->erasesize / 1024) * 1000;
do_div(k, ms);
return k;
}
@ -269,7 +269,10 @@ static int __init mtd_speedtest_init(void)
err = write_eraseblock(i);
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
stop_timing();
speed = calc_speed();
@ -284,7 +287,10 @@ static int __init mtd_speedtest_init(void)
err = read_eraseblock(i);
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
stop_timing();
speed = calc_speed();
@ -303,7 +309,10 @@ static int __init mtd_speedtest_init(void)
err = write_eraseblock_by_page(i);
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
stop_timing();
speed = calc_speed();
@ -318,7 +327,10 @@ static int __init mtd_speedtest_init(void)
err = read_eraseblock_by_page(i);
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
stop_timing();
speed = calc_speed();
@ -337,7 +349,10 @@ static int __init mtd_speedtest_init(void)
err = write_eraseblock_by_2pages(i);
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
stop_timing();
speed = calc_speed();
@ -352,7 +367,10 @@ static int __init mtd_speedtest_init(void)
err = read_eraseblock_by_2pages(i);
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
stop_timing();
speed = calc_speed();
@ -385,7 +403,11 @@ static int __init mtd_speedtest_init(void)
err = multiblock_erase(i, j);
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
i += j;
}
stop_timing();

View File

@ -96,7 +96,7 @@ static int do_read(void)
if (offs + len > mtd->erasesize)
len = mtd->erasesize - offs;
}
addr = eb * mtd->erasesize + offs;
addr = (loff_t)eb * mtd->erasesize + offs;
return mtdtest_read(mtd, addr, len, readbuf);
}
@ -124,7 +124,7 @@ static int do_write(void)
offsets[eb + 1] = 0;
}
}
addr = eb * mtd->erasesize + offs;
addr = (loff_t)eb * mtd->erasesize + offs;
err = mtdtest_write(mtd, addr, len, writebuf);
if (unlikely(err))
return err;
@ -221,7 +221,10 @@ static int __init mtd_stresstest_init(void)
err = do_operation();
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("finished, %d operations done\n", op);

View File

@ -95,7 +95,7 @@ static int write_eraseblock2(int ebnum)
loff_t addr = (loff_t)ebnum * mtd->erasesize;
for (k = 1; k < 33; ++k) {
if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize)
break;
prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf);
@ -195,7 +195,7 @@ static int verify_eraseblock2(int ebnum)
loff_t addr = (loff_t)ebnum * mtd->erasesize;
for (k = 1; k < 33; ++k) {
if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize)
if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize)
break;
prandom_bytes_state(&rnd_state, writebuf, subpgsize * k);
clear_data(readbuf, subpgsize * k);
@ -269,7 +269,10 @@ static int verify_all_eraseblocks_ff(void)
return err;
if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
return err;
}
pr_info("verified %u eraseblocks\n", i);
return 0;
@ -346,7 +349,10 @@ static int __init mtd_subpagetest_init(void)
goto out;
if (i % 256 == 0)
pr_info("written up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("written %u eraseblocks\n", i);
@ -360,7 +366,10 @@ static int __init mtd_subpagetest_init(void)
goto out;
if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("verified %u eraseblocks\n", i);
@ -383,7 +392,10 @@ static int __init mtd_subpagetest_init(void)
goto out;
if (i % 256 == 0)
pr_info("written up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("written %u eraseblocks\n", i);
@ -398,7 +410,10 @@ static int __init mtd_subpagetest_init(void)
goto out;
if (i % 256 == 0)
pr_info("verified up to eraseblock %u\n", i);
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
pr_info("verified %u eraseblocks\n", i);

View File

@ -101,11 +101,11 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf)
{
int err, retries = 0;
size_t read;
loff_t addr = ebnum * mtd->erasesize;
loff_t addr = (loff_t)ebnum * mtd->erasesize;
size_t len = mtd->erasesize;
if (pgcnt) {
addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
addr = (loff_t)(ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
len = pgcnt * pgsize;
}
@ -155,11 +155,11 @@ static inline int write_pattern(int ebnum, void *buf)
{
int err;
size_t written;
loff_t addr = ebnum * mtd->erasesize;
loff_t addr = (loff_t)ebnum * mtd->erasesize;
size_t len = mtd->erasesize;
if (pgcnt) {
addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
addr = (loff_t)(ebnum + 1) * mtd->erasesize - pgcnt * pgsize;
len = pgcnt * pgsize;
}
err = mtd_write(mtd, addr, len, &written, buf);
@ -279,7 +279,10 @@ static int __init tort_init(void)
" for 0xFF... pattern\n");
goto out;
}
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
}
@ -294,7 +297,10 @@ static int __init tort_init(void)
err = write_pattern(i, patt);
if (err)
goto out;
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
/* Verify what we wrote */
@ -314,7 +320,10 @@ static int __init tort_init(void)
"0x55AA55..." : "0xAA55AA...");
goto out;
}
cond_resched();
err = mtdtest_relax();
if (err)
goto out;
}
}

View File

@ -1266,7 +1266,6 @@ int jffs2_garbage_collect_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_
if (rc) {
JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n",
__func__, rc, totlen);
rc = rc ? rc : -EBADFD;
goto out;
}
rc = save_xattr_ref(c, ref);

View File

@ -77,7 +77,7 @@
/* ensure we never evaluate anything shorted than an unsigned long
* to zero, and ensure we'll never miss the end of an comparison (bjd) */
#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1))/ sizeof(unsigned long))
#define map_calc_words(map) ((map_bankwidth(map) + (sizeof(unsigned long)-1)) / sizeof(unsigned long))
#ifdef CONFIG_MTD_MAP_BANK_WIDTH_8
# ifdef map_bankwidth
@ -181,7 +181,7 @@ static inline int map_bankwidth_supported(int w)
}
}
#define MAX_MAP_LONGS ( ((MAX_MAP_BANKWIDTH*8) + BITS_PER_LONG - 1) / BITS_PER_LONG )
#define MAX_MAP_LONGS (((MAX_MAP_BANKWIDTH * 8) + BITS_PER_LONG - 1) / BITS_PER_LONG)
typedef union {
unsigned long x[MAX_MAP_LONGS];
@ -264,20 +264,22 @@ void unregister_mtd_chip_driver(struct mtd_chip_driver *);
struct mtd_info *do_map_probe(const char *name, struct map_info *map);
void map_destroy(struct mtd_info *mtd);
#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0)
#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0)
#define ENABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 1); } while (0)
#define DISABLE_VPP(map) do { if (map->set_vpp) map->set_vpp(map, 0); } while (0)
#define INVALIDATE_CACHED_RANGE(map, from, size) \
do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
do { if (map->inval_cache) map->inval_cache(map, from, size); } while (0)
static inline int map_word_equal(struct map_info *map, map_word val1, map_word val2)
{
int i;
for (i=0; i<map_words(map); i++) {
for (i = 0; i < map_words(map); i++) {
if (val1.x[i] != val2.x[i])
return 0;
}
return 1;
}
@ -286,9 +288,9 @@ static inline map_word map_word_and(struct map_info *map, map_word val1, map_wor
map_word r;
int i;
for (i=0; i<map_words(map); i++) {
for (i = 0; i < map_words(map); i++)
r.x[i] = val1.x[i] & val2.x[i];
}
return r;
}
@ -297,9 +299,9 @@ static inline map_word map_word_clr(struct map_info *map, map_word val1, map_wor
map_word r;
int i;
for (i=0; i<map_words(map); i++) {
for (i = 0; i < map_words(map); i++)
r.x[i] = val1.x[i] & ~val2.x[i];
}
return r;
}
@ -308,22 +310,33 @@ static inline map_word map_word_or(struct map_info *map, map_word val1, map_word
map_word r;
int i;
for (i=0; i<map_words(map); i++) {
for (i = 0; i < map_words(map); i++)
r.x[i] = val1.x[i] | val2.x[i];
}
return r;
}
#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
static inline int map_word_andequal(struct map_info *map, map_word val1, map_word val2, map_word val3)
{
int i;
for (i = 0; i < map_words(map); i++) {
if ((val1.x[i] & val2.x[i]) != val3.x[i])
return 0;
}
return 1;
}
static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
{
int i;
for (i=0; i<map_words(map); i++) {
for (i = 0; i < map_words(map); i++) {
if (val1.x[i] & val2.x[i])
return 1;
}
return 0;
}
@ -355,14 +368,16 @@ static inline map_word map_word_load_partial(struct map_info *map, map_word orig
if (map_bankwidth_is_large(map)) {
char *dest = (char *)&orig;
memcpy(dest+start, buf, len);
} else {
for (i=start; i < start+len; i++) {
for (i = start; i < start+len; i++) {
int bitpos;
#ifdef __LITTLE_ENDIAN
bitpos = i*8;
bitpos = i * 8;
#else /* __BIG_ENDIAN */
bitpos = (map_bankwidth(map)-1-i)*8;
bitpos = (map_bankwidth(map) - 1 - i) * 8;
#endif
orig.x[0] &= ~(0xff << bitpos);
orig.x[0] |= (unsigned long)buf[i-start] << bitpos;
@ -384,9 +399,10 @@ static inline map_word map_word_ff(struct map_info *map)
if (map_bankwidth(map) < MAP_FF_LIMIT) {
int bw = 8 * map_bankwidth(map);
r.x[0] = (1UL << bw) - 1;
} else {
for (i=0; i<map_words(map); i++)
for (i = 0; i < map_words(map); i++)
r.x[i] = ~0UL;
}
return r;
@ -407,7 +423,7 @@ static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
r.x[0] = __raw_readq(map->virt + ofs);
#endif
else if (map_bankwidth_is_large(map))
memcpy_fromio(r.x, map->virt+ofs, map->bankwidth);
memcpy_fromio(r.x, map->virt + ofs, map->bankwidth);
else
BUG();

View File

@ -155,6 +155,8 @@ enum spi_nor_option_flags {
* @write: [DRIVER-SPECIFIC] write data to the SPI NOR
* @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR
* at the offset @offs
* @lock: [FLASH-SPECIFIC] lock a region of the SPI NOR
* @unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR
* @priv: the private data
*/
struct spi_nor {
@ -189,6 +191,9 @@ struct spi_nor {
size_t len, size_t *retlen, const u_char *write_buf);
int (*erase)(struct spi_nor *nor, loff_t offs);
int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len);
void *priv;
};