Merge branch 'for-next/mtd'
This commit is contained in:
commit
251ae23e9f
|
@ -90,8 +90,13 @@ static int do_nand(int argc, char *argv[])
|
|||
}
|
||||
|
||||
ret = ioctl(fd, MEMSETBADBLOCK, &badblock);
|
||||
if (ret)
|
||||
perror("ioctl");
|
||||
if (ret) {
|
||||
if (ret == -EINVAL)
|
||||
printf("Maybe offset %lld is out of range.\n",
|
||||
badblock);
|
||||
else
|
||||
perror("ioctl");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return ret;
|
||||
|
|
|
@ -337,14 +337,14 @@ static int imx_bbu_write_firmware(struct mtd_info *mtd, unsigned block,
|
|||
return block;
|
||||
}
|
||||
|
||||
static int dbbt_data_create(struct mtd_info *mtd, void *buf, int block_last)
|
||||
static int dbbt_data_create(struct mtd_info *mtd, void *buf, int num_blocks)
|
||||
{
|
||||
int n;
|
||||
int n_bad_blocks = 0;
|
||||
uint32_t *bb = buf + 0x8;
|
||||
uint32_t *n_bad_blocksp = buf + 0x4;
|
||||
|
||||
for (n = 0; n <= block_last; n++) {
|
||||
for (n = 0; n < num_blocks; n++) {
|
||||
loff_t offset = n * mtd->erasesize;
|
||||
if (mtd_block_isbad(mtd, offset)) {
|
||||
n_bad_blocks++;
|
||||
|
@ -461,10 +461,6 @@ static int imx_bbu_nand_update(struct bbu_handler *handler, struct bbu_data *dat
|
|||
*/
|
||||
memset(fcb_raw_page + mtd->writesize, 0xFF, 2);
|
||||
|
||||
ret = raw_write_page(mtd, fcb_raw_page, mtd->erasesize);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
dbbt->Checksum = 0;
|
||||
dbbt->FingerPrint = 0x54424244;
|
||||
dbbt->Version = 0x01000000;
|
||||
|
|
|
@ -67,14 +67,13 @@ int mtd_all_ff(const void *buf, unsigned int len)
|
|||
}
|
||||
|
||||
static ssize_t mtd_op_read(struct cdev *cdev, void* buf, size_t count,
|
||||
loff_t _offset, ulong flags)
|
||||
loff_t offset, ulong flags)
|
||||
{
|
||||
struct mtd_info *mtd = cdev->priv;
|
||||
size_t retlen;
|
||||
int ret;
|
||||
unsigned long offset = _offset;
|
||||
|
||||
dev_dbg(cdev->dev, "read ofs: 0x%08lx count: 0x%08zx\n",
|
||||
dev_dbg(cdev->dev, "read ofs: 0x%08llx count: 0x%08zx\n",
|
||||
offset, count);
|
||||
|
||||
ret = mtd_read(mtd, offset, count, &retlen, buf);
|
||||
|
@ -115,13 +114,13 @@ static struct mtd_erase_region_info *mtd_find_erase_region(struct mtd_info *mtd,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int mtd_erase_align(struct mtd_info *mtd, size_t *count, loff_t *offset)
|
||||
static int mtd_erase_align(struct mtd_info *mtd, loff_t *count, loff_t *offset)
|
||||
{
|
||||
struct mtd_erase_region_info *e;
|
||||
loff_t ofs;
|
||||
|
||||
if (mtd->numeraseregions == 0) {
|
||||
ofs = *offset & ~(mtd->erasesize - 1);
|
||||
ofs = *offset & ~(loff_t)(mtd->erasesize - 1);
|
||||
*count += (*offset - ofs);
|
||||
*count = ALIGN(*count, mtd->erasesize);
|
||||
*offset = ofs;
|
||||
|
@ -145,11 +144,11 @@ static int mtd_erase_align(struct mtd_info *mtd, size_t *count, loff_t *offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset)
|
||||
static int mtd_op_erase(struct cdev *cdev, loff_t count, loff_t offset)
|
||||
{
|
||||
struct mtd_info *mtd = cdev->priv;
|
||||
struct erase_info erase;
|
||||
uint32_t addr;
|
||||
loff_t addr;
|
||||
int ret;
|
||||
|
||||
ret = mtd_erase_align(mtd, &count, &offset);
|
||||
|
@ -169,7 +168,7 @@ static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset)
|
|||
erase.len = mtd->erasesize;
|
||||
|
||||
while (count > 0) {
|
||||
dev_dbg(cdev->dev, "erase %d %d\n", addr, erase.len);
|
||||
dev_dbg(cdev->dev, "erase 0x%08llx len: 0x%08llx\n", addr, erase.len);
|
||||
|
||||
if (mtd->allow_erasebad || (mtd->master && mtd->master->allow_erasebad))
|
||||
ret = 0;
|
||||
|
@ -179,7 +178,7 @@ static int mtd_op_erase(struct cdev *cdev, size_t count, loff_t offset)
|
|||
erase.addr = addr;
|
||||
|
||||
if (ret > 0) {
|
||||
printf("Skipping bad block at 0x%08x\n", addr);
|
||||
printf("Skipping bad block at 0x%08llx\n", addr);
|
||||
} else {
|
||||
ret = mtd_erase(mtd, &erase);
|
||||
if (ret)
|
||||
|
@ -310,6 +309,9 @@ int mtd_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (ofs < 0 || ofs >= mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
if (mtd->block_markbad)
|
||||
ret = mtd->block_markbad(mtd, ofs);
|
||||
else
|
||||
|
@ -324,6 +326,11 @@ int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
|
|||
int ret_code;
|
||||
*retlen = 0;
|
||||
|
||||
if (from < 0 || from >= mtd->size || len > mtd->size - from)
|
||||
return -EINVAL;
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* In the absence of an error, drivers return a non-negative integer
|
||||
* representing the maximum number of bitflips that were corrected on
|
||||
|
@ -342,11 +349,28 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
|
|||
{
|
||||
*retlen = 0;
|
||||
|
||||
if (to < 0 || to >= mtd->size || len > mtd->size - to)
|
||||
return -EINVAL;
|
||||
if (!mtd->write || !(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
if (!len)
|
||||
return 0;
|
||||
|
||||
return mtd->write(mtd, to, len, retlen, buf);
|
||||
}
|
||||
|
||||
int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
{
|
||||
if (instr->addr >= mtd->size || instr->len > mtd->size - instr->addr)
|
||||
return -EINVAL;
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
instr->fail_addr = MTD_FAIL_ADDR_UNKNOWN;
|
||||
if (!instr->len) {
|
||||
instr->state = MTD_ERASE_DONE;
|
||||
mtd_erase_callback(instr);
|
||||
return 0;
|
||||
}
|
||||
return mtd->erase(mtd, instr);
|
||||
}
|
||||
|
||||
|
|
|
@ -297,6 +297,8 @@ static int m25p_probe(struct device_d *dev)
|
|||
static __maybe_unused struct of_device_id m25p80_dt_ids[] = {
|
||||
{
|
||||
.compatible = "m25p80",
|
||||
}, {
|
||||
.compatible = "jedec,spi-nor",
|
||||
}, {
|
||||
/* sentinel */
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ static int add_mtdoob_device(struct mtd_info *mtd, const char *devname, void **p
|
|||
mtdoob = xzalloc(sizeof(*mtdoob));
|
||||
mtdoob->cdev.ops = &mtd_ops_oob;
|
||||
mtdoob->cdev.size = mtd_div_by_wb(mtd->size, mtd) * mtd->oobsize;
|
||||
mtdoob->cdev.name = asprintf("%s_oob%d", devname, mtd->class_dev.id);
|
||||
mtdoob->cdev.name = asprintf("%s.oob", mtd->cdev.name);
|
||||
mtdoob->cdev.priv = mtdoob;
|
||||
mtdoob->cdev.dev = &mtd->class_dev;
|
||||
mtdoob->mtd = mtd;
|
||||
|
|
|
@ -83,6 +83,20 @@ static struct mtd_info *to_mtd(struct cdev *cdev)
|
|||
return mtdraw->mtd;
|
||||
}
|
||||
|
||||
static unsigned int mtdraw_offset_to_block(struct mtd_info *mtd, loff_t offset)
|
||||
{
|
||||
u64 ofs64 = offset;
|
||||
|
||||
do_div(ofs64, mtd->writesize + mtd->oobsize);
|
||||
|
||||
return ofs64;
|
||||
}
|
||||
|
||||
static loff_t mtdraw_raw_to_mtd_offset(struct mtd_info *mtd, loff_t offset)
|
||||
{
|
||||
return (loff_t)mtdraw_offset_to_block(mtd, offset) * mtd->writesize;
|
||||
}
|
||||
|
||||
static ssize_t mtdraw_read_unaligned(struct mtd_info *mtd, void *dst,
|
||||
size_t count, int skip, ulong offset)
|
||||
{
|
||||
|
@ -117,22 +131,21 @@ err:
|
|||
}
|
||||
|
||||
static ssize_t mtdraw_read(struct cdev *cdev, void *buf, size_t count,
|
||||
loff_t _offset, ulong flags)
|
||||
loff_t offset, ulong flags)
|
||||
{
|
||||
struct mtd_info *mtd = to_mtd(cdev);
|
||||
ssize_t retlen = 0, ret = 1, toread;
|
||||
ulong numpage;
|
||||
ulong numblock;
|
||||
int skip;
|
||||
unsigned long offset = _offset;
|
||||
|
||||
numpage = offset / (mtd->writesize + mtd->oobsize);
|
||||
skip = offset % (mtd->writesize + mtd->oobsize);
|
||||
numblock = mtdraw_offset_to_block(mtd, offset);
|
||||
skip = offset - numblock * (mtd->writesize + mtd->oobsize);
|
||||
|
||||
while (ret > 0 && count > 0) {
|
||||
toread = min_t(int, count,
|
||||
mtd->writesize + mtd->oobsize - skip);
|
||||
ret = mtdraw_read_unaligned(mtd, buf, toread,
|
||||
skip, numpage++ * mtd->writesize);
|
||||
skip, numblock++ * mtd->writesize);
|
||||
buf += ret;
|
||||
skip = 0;
|
||||
count -= ret;
|
||||
|
@ -171,20 +184,21 @@ static void mtdraw_fillbuf(struct mtdraw *mtdraw, const void *src, int nbbytes)
|
|||
}
|
||||
|
||||
static ssize_t mtdraw_write(struct cdev *cdev, const void *buf, size_t count,
|
||||
loff_t _offset, ulong flags)
|
||||
loff_t offset, ulong flags)
|
||||
{
|
||||
struct mtdraw *mtdraw = to_mtdraw(cdev);
|
||||
struct mtd_info *mtd = to_mtd(cdev);
|
||||
int bsz = mtd->writesize + mtd->oobsize;
|
||||
ulong numpage;
|
||||
ulong numblock;
|
||||
size_t retlen = 0, tofill;
|
||||
unsigned long offset = _offset;
|
||||
int ret = 0;
|
||||
|
||||
numblock = mtdraw_offset_to_block(mtd, offset);
|
||||
|
||||
if (mtdraw->write_fill &&
|
||||
mtdraw->write_ofs + mtdraw->write_fill != offset)
|
||||
return -EINVAL;
|
||||
if (mtdraw->write_fill == 0 && offset % bsz)
|
||||
if (mtdraw->write_fill == 0 && offset - numblock * mtd->writesize != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (mtdraw->write_fill) {
|
||||
|
@ -196,16 +210,16 @@ static ssize_t mtdraw_write(struct cdev *cdev, const void *buf, size_t count,
|
|||
}
|
||||
|
||||
if (mtdraw->write_fill == bsz) {
|
||||
numpage = mtdraw->write_ofs / (mtd->writesize + mtd->oobsize);
|
||||
numblock = mtdraw_offset_to_block(mtd, mtdraw->write_ofs);
|
||||
ret = mtdraw_blkwrite(mtd, mtdraw->writebuf,
|
||||
mtd->writesize * numpage);
|
||||
mtd->writesize * numblock);
|
||||
mtdraw->write_fill = 0;
|
||||
}
|
||||
|
||||
numpage = offset / (mtd->writesize + mtd->oobsize);
|
||||
numblock = mtdraw_offset_to_block(mtd, offset);
|
||||
while (ret >= 0 && count >= bsz) {
|
||||
ret = mtdraw_blkwrite(mtd, buf + retlen,
|
||||
mtd->writesize * numpage++);
|
||||
mtd->writesize * numblock++);
|
||||
count -= ret;
|
||||
retlen += ret;
|
||||
offset += ret;
|
||||
|
@ -225,15 +239,14 @@ static ssize_t mtdraw_write(struct cdev *cdev, const void *buf, size_t count,
|
|||
}
|
||||
}
|
||||
|
||||
static int mtdraw_erase(struct cdev *cdev, size_t count, loff_t _offset)
|
||||
static int mtdraw_erase(struct cdev *cdev, loff_t count, loff_t offset)
|
||||
{
|
||||
struct mtd_info *mtd = to_mtd(cdev);
|
||||
struct erase_info erase;
|
||||
unsigned long offset = _offset;
|
||||
int ret;
|
||||
|
||||
offset = offset / (mtd->writesize + mtd->oobsize) * mtd->writesize;
|
||||
count = count / (mtd->writesize + mtd->oobsize) * mtd->writesize;
|
||||
offset = mtdraw_raw_to_mtd_offset(mtd, offset);
|
||||
count = mtdraw_raw_to_mtd_offset(mtd, count);
|
||||
|
||||
memset(&erase, 0, sizeof(erase));
|
||||
erase.mtd = mtd;
|
||||
|
@ -241,7 +254,7 @@ static int mtdraw_erase(struct cdev *cdev, size_t count, loff_t _offset)
|
|||
erase.len = mtd->erasesize;
|
||||
|
||||
while (count > 0) {
|
||||
debug("erase %d %d\n", erase.addr, erase.len);
|
||||
debug("erase 0x%08llx len: 0x%08llx\n", erase.addr, erase.len);
|
||||
|
||||
if (!mtd->allow_erasebad)
|
||||
ret = mtd_block_isbad(mtd, erase.addr);
|
||||
|
@ -249,7 +262,7 @@ static int mtdraw_erase(struct cdev *cdev, size_t count, loff_t _offset)
|
|||
ret = 0;
|
||||
|
||||
if (ret > 0) {
|
||||
printf("Skipping bad block at 0x%08x\n", erase.addr);
|
||||
printf("Skipping bad block at 0x%08llx\n", erase.addr);
|
||||
} else {
|
||||
ret = mtd_erase(mtd, &erase);
|
||||
if (ret)
|
||||
|
|
|
@ -88,7 +88,7 @@ static ssize_t nand_bb_read(struct cdev *cdev, void *buf, size_t count,
|
|||
}
|
||||
|
||||
/* Must be a multiple of the largest NAND page size */
|
||||
#define BB_WRITEBUF_SIZE 4096
|
||||
#define BB_WRITEBUF_SIZE 8192
|
||||
|
||||
#ifdef CONFIG_MTD_WRITE
|
||||
static int nand_bb_write_buf(struct nand_bb *bb, size_t count)
|
||||
|
@ -157,7 +157,7 @@ static ssize_t nand_bb_write(struct cdev *cdev, const void *buf, size_t count,
|
|||
return bytes;
|
||||
}
|
||||
|
||||
static int nand_bb_erase(struct cdev *cdev, size_t count, loff_t offset)
|
||||
static int nand_bb_erase(struct cdev *cdev, loff_t count, loff_t offset)
|
||||
{
|
||||
struct nand_bb *bb = cdev->priv;
|
||||
struct erase_info erase = {};
|
||||
|
|
|
@ -3718,7 +3718,7 @@ int nand_scan_tail(struct mtd_info *mtd)
|
|||
* properly set.
|
||||
*/
|
||||
if (!mtd->bitflip_threshold)
|
||||
mtd->bitflip_threshold = mtd->ecc_strength;
|
||||
mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
|
||||
|
||||
/* Check, if we should skip the bad block table scan */
|
||||
if (chip->options & NAND_SKIP_BBTSCAN)
|
||||
|
|
|
@ -571,6 +571,7 @@ static const struct spi_device_id spi_nor_ids[] = {
|
|||
{ "s25fl008k", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) },
|
||||
{ "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) },
|
||||
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "s25fl116k", INFO(0x014015, 0, 64 * 1024, 32, SECT_4K) },
|
||||
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, 0) },
|
||||
{ "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K) },
|
||||
|
||||
|
|
|
@ -259,7 +259,7 @@ int cdev_ioctl(struct cdev *cdev, int request, void *buf)
|
|||
return cdev->ops->ioctl(cdev, request, buf);
|
||||
}
|
||||
|
||||
int cdev_erase(struct cdev *cdev, size_t count, loff_t offset)
|
||||
int cdev_erase(struct cdev *cdev, loff_t count, loff_t offset)
|
||||
{
|
||||
if (!cdev->ops->erase)
|
||||
return -ENOSYS;
|
||||
|
|
|
@ -66,7 +66,7 @@ static loff_t devfs_lseek(struct device_d *_dev, FILE *f, loff_t pos)
|
|||
return ret - cdev->offset;
|
||||
}
|
||||
|
||||
static int devfs_erase(struct device_d *_dev, FILE *f, size_t count, loff_t offset)
|
||||
static int devfs_erase(struct device_d *_dev, FILE *f, loff_t count, loff_t offset)
|
||||
{
|
||||
struct cdev *cdev = f->priv;
|
||||
|
||||
|
|
2
fs/fs.c
2
fs/fs.c
|
@ -924,7 +924,7 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL(lseek);
|
||||
|
||||
int erase(int fd, size_t count, loff_t offset)
|
||||
int erase(int fd, loff_t count, loff_t offset)
|
||||
{
|
||||
struct fs_driver_d *fsdrv;
|
||||
FILE *f;
|
||||
|
|
|
@ -431,7 +431,7 @@ struct file_operations {
|
|||
int (*open)(struct cdev*, unsigned long flags);
|
||||
int (*close)(struct cdev*);
|
||||
int (*flush)(struct cdev*);
|
||||
int (*erase)(struct cdev*, size_t count, loff_t offset);
|
||||
int (*erase)(struct cdev*, loff_t count, loff_t offset);
|
||||
int (*protect)(struct cdev*, size_t count, loff_t offset, int prot);
|
||||
int (*memmap)(struct cdev*, void **map, int flags);
|
||||
};
|
||||
|
@ -476,7 +476,7 @@ int cdev_flush(struct cdev *cdev);
|
|||
ssize_t cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags);
|
||||
ssize_t cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags);
|
||||
int cdev_ioctl(struct cdev *cdev, int cmd, void *buf);
|
||||
int cdev_erase(struct cdev *cdev, size_t count, loff_t offset);
|
||||
int cdev_erase(struct cdev *cdev, loff_t count, loff_t offset);
|
||||
|
||||
#define DEVFS_PARTITION_FIXED (1U << 0)
|
||||
#define DEVFS_PARTITION_READONLY (1U << 1)
|
||||
|
|
|
@ -70,7 +70,7 @@ struct fs_driver_d {
|
|||
int (*stat)(struct device_d *dev, const char *file, struct stat *stat);
|
||||
|
||||
int (*ioctl)(struct device_d *dev, FILE *f, int request, void *buf);
|
||||
int (*erase)(struct device_d *dev, FILE *f, size_t count,
|
||||
int (*erase)(struct device_d *dev, FILE *f, loff_t count,
|
||||
loff_t offset);
|
||||
int (*protect)(struct device_d *dev, FILE *f, size_t count,
|
||||
loff_t offset, int prot);
|
||||
|
@ -145,7 +145,7 @@ int mount (const char *device, const char *fsname, const char *path,
|
|||
int umount(const char *pathname);
|
||||
|
||||
/* not-so-standard functions */
|
||||
int erase(int fd, size_t count, loff_t offset);
|
||||
int erase(int fd, loff_t count, loff_t offset);
|
||||
int protect(int fd, size_t count, loff_t offset, int prot);
|
||||
int protect_file(const char *file, int prot);
|
||||
void *memmap(int fd, int flags);
|
||||
|
|
|
@ -10,13 +10,13 @@
|
|||
#include <asm-generic/div64.h>
|
||||
|
||||
struct erase_info_user {
|
||||
uint32_t start;
|
||||
uint32_t length;
|
||||
uint64_t start;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
struct mtd_oob_buf {
|
||||
uint32_t start;
|
||||
uint32_t length;
|
||||
uint64_t start;
|
||||
uint64_t length;
|
||||
unsigned char *ptr;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,14 +26,16 @@
|
|||
#define MTD_ERASE_DONE 0x08
|
||||
#define MTD_ERASE_FAILED 0x10
|
||||
|
||||
#define MTD_FAIL_ADDR_UNKNOWN -1LL
|
||||
|
||||
/* If the erase fails, fail_addr might indicate exactly which block failed. If
|
||||
fail_addr = 0xffffffff, the failure was not at the device level or was not
|
||||
specific to any particular block. */
|
||||
struct erase_info {
|
||||
struct mtd_info *mtd;
|
||||
u_int32_t addr;
|
||||
u_int32_t len;
|
||||
u_int32_t fail_addr;
|
||||
u_int64_t addr;
|
||||
u_int64_t len;
|
||||
u_int64_t fail_addr;
|
||||
u_long time;
|
||||
u_long retries;
|
||||
u_int dev;
|
||||
|
@ -45,7 +47,7 @@ struct erase_info {
|
|||
};
|
||||
|
||||
struct mtd_erase_region_info {
|
||||
u_int32_t offset; /* At which this region starts, from the beginning of the MTD */
|
||||
u_int64_t offset; /* At which this region starts, from the beginning of the MTD */
|
||||
u_int32_t erasesize; /* For this region */
|
||||
u_int32_t numblocks; /* Number of blocks of erasesize in this region */
|
||||
unsigned long *lockmap; /* If keeping bitmap of locks */
|
||||
|
|
Loading…
Reference in New Issue