diff options
author | Kamal Dasu <kdasu.kdev@gmail.com> | 2014-05-01 20:51:19 -0400 |
---|---|---|
committer | Brian Norris <computersforpeace@gmail.com> | 2014-05-20 19:35:32 -0400 |
commit | 66507c7bc8895f0da6b4ad87e96d61a9f7d7a118 (patch) | |
tree | a011e33764deec5b848280f3f2ed386f60967929 /drivers/mtd/nand/nand_base.c | |
parent | 6e5221558d35563dc656833a021543fba8185c41 (diff) |
mtd: nand: Add support to use nand_base poi databuf as bounce buffer
nand_base can be passed a kmap()'d buffers from highmem by
filesystems like jffs2. This results in failure to map the
physical address of the DMA buffer on various contoller
driver on different platforms. This change adds a chip option
to use preallocated databuf as bounce buffers used in
nand_do_read_ops() and nand_do_write_ops().
This allows for specific nand controller driver to set this
option as needed.
Signed-off-by: Kamal Dasu <kdasu.kdev@gmail.com>
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 37 |
1 files changed, 31 insertions, 6 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 7853b9b0a05e..1b844b8c621f 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/err.h> | 37 | #include <linux/err.h> |
38 | #include <linux/sched.h> | 38 | #include <linux/sched.h> |
39 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
40 | #include <linux/mm.h> | ||
40 | #include <linux/types.h> | 41 | #include <linux/types.h> |
41 | #include <linux/mtd/mtd.h> | 42 | #include <linux/mtd/mtd.h> |
42 | #include <linux/mtd/nand.h> | 43 | #include <linux/mtd/nand.h> |
@@ -1500,6 +1501,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
1500 | mtd->oobavail : mtd->oobsize; | 1501 | mtd->oobavail : mtd->oobsize; |
1501 | 1502 | ||
1502 | uint8_t *bufpoi, *oob, *buf; | 1503 | uint8_t *bufpoi, *oob, *buf; |
1504 | int use_bufpoi; | ||
1503 | unsigned int max_bitflips = 0; | 1505 | unsigned int max_bitflips = 0; |
1504 | int retry_mode = 0; | 1506 | int retry_mode = 0; |
1505 | bool ecc_fail = false; | 1507 | bool ecc_fail = false; |
@@ -1522,9 +1524,20 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, | |||
1522 | bytes = min(mtd->writesize - col, readlen); | 1524 | bytes = min(mtd->writesize - col, readlen); |
1523 | aligned = (bytes == mtd->writesize); | 1525 | aligned = (bytes == mtd->writesize); |
1524 | 1526 | ||
1527 | if (!aligned) | ||
1528 | use_bufpoi = 1; | ||
1529 | else if (chip->options & NAND_USE_BOUNCE_BUFFER) | ||
1530 | use_bufpoi = !virt_addr_valid(buf); | ||
1531 | else | ||
1532 | use_bufpoi = 0; | ||
1533 | |||
1525 | /* Is the current page in the buffer? */ | 1534 | /* Is the current page in the buffer? */ |
1526 | if (realpage != chip->pagebuf || oob) { | 1535 | if (realpage != chip->pagebuf || oob) { |
1527 | bufpoi = aligned ? buf : chip->buffers->databuf; | 1536 | bufpoi = use_bufpoi ? chip->buffers->databuf : buf; |
1537 | |||
1538 | if (use_bufpoi && aligned) | ||
1539 | pr_debug("%s: using read bounce buffer for buf@%p\n", | ||
1540 | __func__, buf); | ||
1528 | 1541 | ||
1529 | read_retry: | 1542 | read_retry: |
1530 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); | 1543 | chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); |
@@ -1546,7 +1559,7 @@ read_retry: | |||
1546 | ret = chip->ecc.read_page(mtd, chip, bufpoi, | 1559 | ret = chip->ecc.read_page(mtd, chip, bufpoi, |
1547 | oob_required, page); | 1560 | oob_required, page); |
1548 | if (ret < 0) { | 1561 | if (ret < 0) { |
1549 | if (!aligned) | 1562 | if (use_bufpoi) |
1550 | /* Invalidate page cache */ | 1563 | /* Invalidate page cache */ |
1551 | chip->pagebuf = -1; | 1564 | chip->pagebuf = -1; |
1552 | break; | 1565 | break; |
@@ -1555,7 +1568,7 @@ read_retry: | |||
1555 | max_bitflips = max_t(unsigned int, max_bitflips, ret); | 1568 | max_bitflips = max_t(unsigned int, max_bitflips, ret); |
1556 | 1569 | ||
1557 | /* Transfer not aligned data */ | 1570 | /* Transfer not aligned data */ |
1558 | if (!aligned) { | 1571 | if (use_bufpoi) { |
1559 | if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && | 1572 | if (!NAND_HAS_SUBPAGE_READ(chip) && !oob && |
1560 | !(mtd->ecc_stats.failed - ecc_failures) && | 1573 | !(mtd->ecc_stats.failed - ecc_failures) && |
1561 | (ops->mode != MTD_OPS_RAW)) { | 1574 | (ops->mode != MTD_OPS_RAW)) { |
@@ -2375,11 +2388,23 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
2375 | int bytes = mtd->writesize; | 2388 | int bytes = mtd->writesize; |
2376 | int cached = writelen > bytes && page != blockmask; | 2389 | int cached = writelen > bytes && page != blockmask; |
2377 | uint8_t *wbuf = buf; | 2390 | uint8_t *wbuf = buf; |
2391 | int use_bufpoi; | ||
2392 | int part_pagewr = (column || writelen < (mtd->writesize - 1)); | ||
2393 | |||
2394 | if (part_pagewr) | ||
2395 | use_bufpoi = 1; | ||
2396 | else if (chip->options & NAND_USE_BOUNCE_BUFFER) | ||
2397 | use_bufpoi = !virt_addr_valid(buf); | ||
2398 | else | ||
2399 | use_bufpoi = 0; | ||
2378 | 2400 | ||
2379 | /* Partial page write? */ | 2401 | /* Partial page write?, or need to use bounce buffer */ |
2380 | if (unlikely(column || writelen < (mtd->writesize - 1))) { | 2402 | if (use_bufpoi) { |
2403 | pr_debug("%s: using write bounce buffer for buf@%p\n", | ||
2404 | __func__, buf); | ||
2381 | cached = 0; | 2405 | cached = 0; |
2382 | bytes = min_t(int, bytes - column, (int) writelen); | 2406 | if (part_pagewr) |
2407 | bytes = min_t(int, bytes - column, writelen); | ||
2383 | chip->pagebuf = -1; | 2408 | chip->pagebuf = -1; |
2384 | memset(chip->buffers->databuf, 0xff, mtd->writesize); | 2409 | memset(chip->buffers->databuf, 0xff, mtd->writesize); |
2385 | memcpy(&chip->buffers->databuf[column], buf, bytes); | 2410 | memcpy(&chip->buffers->databuf[column], buf, bytes); |