diff options
author | Nicolas Pitre <nico@cam.org> | 2005-08-06 00:46:59 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-11-06 14:12:48 -0500 |
commit | e102d54abf6806b95c89142cd0b7e94d709ebcd7 (patch) | |
tree | ec4f6fde798cd6f3b8f5771631f07b6a2980b6d1 /drivers | |
parent | 638d983840bb64e02c29bdd6160bb9963f4090f7 (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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 125 |
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 @@ | |||
51 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 51 | static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
52 | static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 52 | static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
53 | static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 53 | static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); |
54 | static int cfi_intelext_writev(struct mtd_info *, const struct kvec *, unsigned long, loff_t, size_t *); | ||
54 | static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); | 55 | static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); |
55 | static void cfi_intelext_sync (struct mtd_info *); | 56 | static void cfi_intelext_sync (struct mtd_info *); |
56 | static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len); | 57 | static 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 | ||
1447 | static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip, | 1449 | static 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 | ||
1622 | static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, | 1652 | static 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 | ||
1700 | static 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 | |||
1686 | static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, | 1711 | static 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 | { |