aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Pitre <nico@cam.org>2005-08-06 00:46:59 -0400
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-11-06 14:12:48 -0500
commite102d54abf6806b95c89142cd0b7e94d709ebcd7 (patch)
treeec4f6fde798cd6f3b8f5771631f07b6a2980b6d1
parent638d983840bb64e02c29bdd6160bb9963f4090f7 (diff)
[MTD] writev support for cfi-cmdset-0001
While this might be useful for all supported flash types, it is mandatory for proper JFFS2 support with Sibley flash. Signed-off-by: Nicolas Pitre <nico@cam.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c125
1 files changed, 75 insertions, 50 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index 10c50604bcd5..adaad7c8fd46 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -4,7 +4,7 @@
4 * 4 *
5 * (C) 2000 Red Hat. GPL'd 5 * (C) 2000 Red Hat. GPL'd
6 * 6 *
7 * $Id: cfi_cmdset_0001.c,v 1.182 2005/08/06 04:40:41 nico Exp $ 7 * $Id: cfi_cmdset_0001.c,v 1.183 2005/08/06 04:46:56 nico Exp $
8 * 8 *
9 * 9 *
10 * 10/10/2000 Nicolas Pitre <nico@cam.org> 10 * 10/10/2000 Nicolas Pitre <nico@cam.org>
@@ -51,6 +51,7 @@
51static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 51static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
52static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 52static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
53static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 53static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
54static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *);
54static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); 55static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
55static void cfi_intelext_sync (struct mtd_info *); 56static void cfi_intelext_sync (struct mtd_info *);
56static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); 57static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
@@ -215,6 +216,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd, void *param)
215 if (cfi->cfiq->BufWriteTimeoutTyp) { 216 if (cfi->cfiq->BufWriteTimeoutTyp) {
216 printk(KERN_INFO "Using buffer write method\n" ); 217 printk(KERN_INFO "Using buffer write method\n" );
217 mtd->write = cfi_intelext_write_buffers; 218 mtd->write = cfi_intelext_write_buffers;
219 mtd->writev = cfi_intelext_writev;
218 } 220 }
219} 221}
220 222
@@ -1445,12 +1447,15 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
1445 1447
1446 1448
1447static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, 1449static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
1448 unsigned long adr, const u_char *buf, int len) 1450 unsigned long adr, const struct kvec **pvec,
1451 unsigned long *pvec_seek, int len)
1449{ 1452{
1450 struct cfi_private *cfi = map->fldrv_priv; 1453 struct cfi_private *cfi = map->fldrv_priv;
1451 map_word status, status_OK, write_cmd; 1454 map_word status, status_OK, write_cmd, datum;
1452 unsigned long cmd_adr, timeo; 1455 unsigned long cmd_adr, timeo;
1453 int wbufsize, z, ret=0, bytes, words; 1456 int wbufsize, z, ret=0, word_gap, words;
1457 const struct kvec *vec;
1458 unsigned long vec_seek;
1454 1459
1455 wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; 1460 wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
1456 adr += chip->start; 1461 adr += chip->start;
@@ -1515,28 +1520,53 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
1515 } 1520 }
1516 } 1521 }
1517 1522
1523 /* Figure out the number of words to write */
1524 word_gap = (-adr & (map_bankwidth(map)-1));
1525 words = (len - word_gap + map_bankwidth(map) - 1) / map_bankwidth(map);
1526 if (!word_gap) {
1527 words--;
1528 } else {
1529 word_gap = map_bankwidth(map) - word_gap;
1530 adr -= word_gap;
1531 datum = map_word_ff(map);
1532 }
1533
1518 /* Write length of data to come */ 1534 /* Write length of data to come */
1519 bytes = len & (map_bankwidth(map)-1); 1535 map_write(map, CMD(words), cmd_adr );
1520 words = len / map_bankwidth(map);
1521 map_write(map, CMD(words - !bytes), cmd_adr );
1522 1536
1523 /* Write data */ 1537 /* Write data */
1524 z = 0; 1538 vec = *pvec;
1525 while(z < words * map_bankwidth(map)) { 1539 vec_seek = *pvec_seek;
1526 map_word datum = map_word_load(map, buf); 1540 do {
1527 map_write(map, datum, adr+z); 1541 int n = map_bankwidth(map) - word_gap;
1528 1542 if (n > vec->iov_len - vec_seek)
1529 z += map_bankwidth(map); 1543 n = vec->iov_len - vec_seek;
1530 buf += map_bankwidth(map); 1544 if (n > len)
1531 } 1545 n = len;
1546
1547 if (!word_gap && len < map_bankwidth(map))
1548 datum = map_word_ff(map);
1549
1550 datum = map_word_load_partial(map, datum,
1551 vec->iov_base + vec_seek,
1552 word_gap, n);
1532 1553
1533 if (bytes) { 1554 len -= n;
1534 map_word datum; 1555 word_gap += n;
1556 if (!len || word_gap == map_bankwidth(map)) {
1557 map_write(map, datum, adr);
1558 adr += map_bankwidth(map);
1559 word_gap = 0;
1560 }
1535 1561
1536 datum = map_word_ff(map); 1562 vec_seek += n;
1537 datum = map_word_load_partial(map, datum, buf, 0, bytes); 1563 if (vec_seek == vec->iov_len) {
1538 map_write(map, datum, adr+z); 1564 vec++;
1539 } 1565 vec_seek = 0;
1566 }
1567 } while (len);
1568 *pvec = vec;
1569 *pvec_seek = vec_seek;
1540 1570
1541 /* GO GO GO */ 1571 /* GO GO GO */
1542 map_write(map, CMD(0xd0), cmd_adr); 1572 map_write(map, CMD(0xd0), cmd_adr);
@@ -1619,57 +1649,40 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
1619 return ret; 1649 return ret;
1620} 1650}
1621 1651
1622static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, 1652static int cfi_intelext_writev (struct mtd_info *mtd, const struct kvec *vecs,
1623 size_t len, size_t *retlen, const u_char *buf) 1653 unsigned long count, loff_t to, size_t *retlen)
1624{ 1654{
1625 struct map_info *map = mtd->priv; 1655 struct map_info *map = mtd->priv;
1626 struct cfi_private *cfi = map->fldrv_priv; 1656 struct cfi_private *cfi = map->fldrv_priv;
1627 int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize; 1657 int wbufsize = cfi_interleave(cfi) << cfi->cfiq->MaxBufWriteSize;
1628 int ret = 0; 1658 int ret = 0;
1629 int chipnum; 1659 int chipnum;
1630 unsigned long ofs; 1660 unsigned long ofs, vec_seek, i;
1661 size_t len = 0;
1662
1663 for (i = 0; i < count; i++)
1664 len += vecs[i].iov_len;
1631 1665
1632 *retlen = 0; 1666 *retlen = 0;
1633 if (!len) 1667 if (!len)
1634 return 0; 1668 return 0;
1635 1669
1636 chipnum = to >> cfi->chipshift; 1670 chipnum = to >> cfi->chipshift;
1637 ofs = to - (chipnum << cfi->chipshift); 1671 ofs = to - (chipnum << cfi->chipshift);
1672 vec_seek = 0;
1638 1673
1639 /* If it's not bus-aligned, do the first word write */ 1674 do {
1640 if (ofs & (map_bankwidth(map)-1)) {
1641 size_t local_len = (-ofs)&(map_bankwidth(map)-1);
1642 if (local_len > len)
1643 local_len = len;
1644 ret = cfi_intelext_write_words(mtd, to, local_len,
1645 retlen, buf);
1646 if (ret)
1647 return ret;
1648 ofs += local_len;
1649 buf += local_len;
1650 len -= local_len;
1651
1652 if (ofs >> cfi->chipshift) {
1653 chipnum ++;
1654 ofs = 0;
1655 if (chipnum == cfi->numchips)
1656 return 0;
1657 }
1658 }
1659
1660 while(len) {
1661 /* We must not cross write block boundaries */ 1675 /* We must not cross write block boundaries */
1662 int size = wbufsize - (ofs & (wbufsize-1)); 1676 int size = wbufsize - (ofs & (wbufsize-1));
1663 1677
1664 if (size > len) 1678 if (size > len)
1665 size = len; 1679 size = len;
1666 ret = do_write_buffer(map, &cfi->chips[chipnum], 1680 ret = do_write_buffer(map, &cfi->chips[chipnum],
1667 ofs, buf, size); 1681 ofs, &vecs, &vec_seek, size);
1668 if (ret) 1682 if (ret)
1669 return ret; 1683 return ret;
1670 1684
1671 ofs += size; 1685 ofs += size;
1672 buf += size;
1673 (*retlen) += size; 1686 (*retlen) += size;
1674 len -= size; 1687 len -= size;
1675 1688
@@ -1679,10 +1692,22 @@ static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
1679 if (chipnum == cfi->numchips) 1692 if (chipnum == cfi->numchips)
1680 return 0; 1693 return 0;
1681 } 1694 }
1682 } 1695 } while (len);
1696
1683 return 0; 1697 return 0;
1684} 1698}
1685 1699
1700static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to,
1701 size_t len, size_t *retlen, const u_char *buf)
1702{
1703 struct kvec vec;
1704
1705 vec.iov_base = (void *) buf;
1706 vec.iov_len = len;
1707
1708 return cfi_intelext_writev(mtd, &vec, 1, to, retlen);
1709}
1710
1686static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, 1711static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
1687 unsigned long adr, int len, void *thunk) 1712 unsigned long adr, int len, void *thunk)
1688{ 1713{