aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/nand_base.c
diff options
context:
space:
mode:
authorKamal Dasu <kdasu.kdev@gmail.com>2014-05-01 20:51:19 -0400
committerBrian Norris <computersforpeace@gmail.com>2014-05-20 19:35:32 -0400
commit66507c7bc8895f0da6b4ad87e96d61a9f7d7a118 (patch)
treea011e33764deec5b848280f3f2ed386f60967929 /drivers/mtd/nand/nand_base.c
parent6e5221558d35563dc656833a021543fba8185c41 (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.c37
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
1529read_retry: 1542read_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);