mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-18 23:18:20 +00:00
MTD: mtdconcat NAND/Sibley support (rev.2)
There is a second revision of "mtdconcat NAND/Sibley" patch. I hope the patch will not get damaged as I'm posting it from gmail account, thanks to Jorn. The patch adds previously missing concat_writev(), concat_writev_ecc(), concat_block_isbad(), concat_block_markbad() functions to make concatenation layer compatible with Sibley and NAND chips. Patch has been cleared from whitespaces, fixed some lines of code as requested. Also I have added code for alignment check that should support Jorn's "writesize" patch. Signed-off-by: Alexander Belyakov <alexander.belyakov@intel.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
This commit is contained in:
parent
ceb31db11f
commit
e8d32937d9
@ -250,6 +250,106 @@ concat_write_ecc(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
concat_writev_ecc(struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t * retlen,
|
||||
u_char *eccbuf, struct nand_oobinfo *oobsel)
|
||||
{
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
struct kvec *vecs_copy;
|
||||
unsigned long entry_low, entry_high;
|
||||
size_t total_len = 0;
|
||||
int i;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (!(mtd->flags & MTD_WRITEABLE))
|
||||
return -EROFS;
|
||||
|
||||
*retlen = 0;
|
||||
|
||||
/* Calculate total length of data */
|
||||
for (i = 0; i < count; i++)
|
||||
total_len += vecs[i].iov_len;
|
||||
|
||||
/* Do not allow write past end of device */
|
||||
if ((to + total_len) > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
/* Check alignment */
|
||||
if (mtd->writesize > 1)
|
||||
if ((to % mtd->writesize) || (total_len % mtd->writesize))
|
||||
return -EINVAL;
|
||||
|
||||
/* make a copy of vecs */
|
||||
vecs_copy = kmalloc(sizeof(struct kvec) * count, GFP_KERNEL);
|
||||
if (!vecs_copy)
|
||||
return -ENOMEM;
|
||||
memcpy(vecs_copy, vecs, sizeof(struct kvec) * count);
|
||||
|
||||
entry_low = 0;
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
size_t size, wsize, retsize, old_iov_len;
|
||||
|
||||
if (to >= subdev->size) {
|
||||
to -= subdev->size;
|
||||
continue;
|
||||
}
|
||||
|
||||
size = min(total_len, (size_t)(subdev->size - to));
|
||||
wsize = size; /* store for future use */
|
||||
|
||||
entry_high = entry_low;
|
||||
while (entry_high < count) {
|
||||
if (size <= vecs_copy[entry_high].iov_len)
|
||||
break;
|
||||
size -= vecs_copy[entry_high++].iov_len;
|
||||
}
|
||||
|
||||
old_iov_len = vecs_copy[entry_high].iov_len;
|
||||
vecs_copy[entry_high].iov_len = size;
|
||||
|
||||
if (!(subdev->flags & MTD_WRITEABLE))
|
||||
err = -EROFS;
|
||||
else if (eccbuf)
|
||||
err = subdev->writev_ecc(subdev, &vecs_copy[entry_low],
|
||||
entry_high - entry_low + 1, to, &retsize,
|
||||
eccbuf, oobsel);
|
||||
else
|
||||
err = subdev->writev(subdev, &vecs_copy[entry_low],
|
||||
entry_high - entry_low + 1, to, &retsize);
|
||||
|
||||
vecs_copy[entry_high].iov_len = old_iov_len - size;
|
||||
vecs_copy[entry_high].iov_base += size;
|
||||
|
||||
entry_low = entry_high;
|
||||
|
||||
if (err)
|
||||
break;
|
||||
|
||||
*retlen += retsize;
|
||||
total_len -= wsize;
|
||||
if (concat->mtd.type == MTD_NANDFLASH && eccbuf)
|
||||
eccbuf += mtd->oobavail * (wsize / mtd->oobblock);
|
||||
|
||||
if (total_len == 0)
|
||||
break;
|
||||
|
||||
err = -EINVAL;
|
||||
to = 0;
|
||||
}
|
||||
|
||||
kfree(vecs_copy);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
concat_writev(struct mtd_info *mtd, const struct kvec *vecs,
|
||||
unsigned long count, loff_t to, size_t * retlen)
|
||||
{
|
||||
return concat_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
concat_read_oob(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t * retlen, u_char * buf)
|
||||
@ -636,6 +736,58 @@ static void concat_resume(struct mtd_info *mtd)
|
||||
}
|
||||
}
|
||||
|
||||
static int concat_block_isbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
int i, res = 0;
|
||||
|
||||
if (!concat->subdev[0]->block_isbad)
|
||||
return res;
|
||||
|
||||
if (ofs > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
|
||||
if (ofs >= subdev->size) {
|
||||
ofs -= subdev->size;
|
||||
continue;
|
||||
}
|
||||
|
||||
res = subdev->block_isbad(subdev, ofs);
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int concat_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct mtd_concat *concat = CONCAT(mtd);
|
||||
int i, err = -EINVAL;
|
||||
|
||||
if (!concat->subdev[0]->block_markbad)
|
||||
return 0;
|
||||
|
||||
if (ofs > mtd->size)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < concat->num_subdev; i++) {
|
||||
struct mtd_info *subdev = concat->subdev[i];
|
||||
|
||||
if (ofs >= subdev->size) {
|
||||
ofs -= subdev->size;
|
||||
continue;
|
||||
}
|
||||
|
||||
err = subdev->block_markbad(subdev, ofs);
|
||||
break;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function constructs a virtual MTD device by concatenating
|
||||
* num_devs MTD devices. A pointer to the new device object is
|
||||
@ -685,10 +837,18 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||
concat->mtd.read_ecc = concat_read_ecc;
|
||||
if (subdev[0]->write_ecc)
|
||||
concat->mtd.write_ecc = concat_write_ecc;
|
||||
if (subdev[0]->writev)
|
||||
concat->mtd.writev = concat_writev;
|
||||
if (subdev[0]->writev_ecc)
|
||||
concat->mtd.writev_ecc = concat_writev_ecc;
|
||||
if (subdev[0]->read_oob)
|
||||
concat->mtd.read_oob = concat_read_oob;
|
||||
if (subdev[0]->write_oob)
|
||||
concat->mtd.write_oob = concat_write_oob;
|
||||
if (subdev[0]->block_isbad)
|
||||
concat->mtd.block_isbad = concat_block_isbad;
|
||||
if (subdev[0]->block_markbad)
|
||||
concat->mtd.block_markbad = concat_block_markbad;
|
||||
|
||||
concat->subdev[0] = subdev[0];
|
||||
|
||||
@ -734,14 +894,13 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||
|
||||
}
|
||||
|
||||
if(concat->mtd.type == MTD_NANDFLASH)
|
||||
memcpy(&concat->mtd.oobinfo, &subdev[0]->oobinfo,
|
||||
sizeof(struct nand_oobinfo));
|
||||
|
||||
concat->num_subdev = num_devs;
|
||||
concat->mtd.name = name;
|
||||
|
||||
/*
|
||||
* NOTE: for now, we do not provide any readv()/writev() methods
|
||||
* because they are messy to implement and they are not
|
||||
* used to a great extent anyway.
|
||||
*/
|
||||
concat->mtd.erase = concat_erase;
|
||||
concat->mtd.read = concat_read;
|
||||
concat->mtd.write = concat_write;
|
||||
|
Loading…
Reference in New Issue
Block a user