summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAllen Xu <b45815@freescale.com>2015-01-13 06:32:49 +0800
committerJason Liu <r64343@freescale.com>2015-02-02 14:17:16 +0800
commit28a6e3238bd6c4cca05bae600db3f5d84702613e (patch)
treeeea26f7eacba62a9c580e0645f37a8248a67d757 /drivers
parent696aea41f01cd58f44b630d1b18d718f17712d58 (diff)
MLK-10028 QSPI dynamically alloc memory for AHB read
QSPI may failed to alloc enough memory (256MB) for AHB read in previous implementation, especially in 3G/1G memory layout kernel. Dynamically alloc memory to avoid such issue. This implementation generally alloc 4MB memory for AHB read, it should be enough for common scenarios, and the side effect (0.6% performance drop) is minor. Previous implementation root@imx6qdlsolo:~# dd if=/dev/mtd0 of=/dev/null bs=1K count=32K 32768+0 records in 32768+0 records out 33554432 bytes (34 MB) copied, 2.16006 s, 15.5 MB/s root@imx6qdlsolo:~# dd if=/dev/mtd0 of=/dev/null bs=32M count=1 1+0 records in 1+0 records out 33554432 bytes (34 MB) copied, 1.43149 s, 23.4 MB/s After applied the patch root@imx6qdlsolo:~# dd if=/dev/mtd0 of=/dev/null bs=1K count=32K 32768+0 records in 32768+0 records out 33554432 bytes (34 MB) copied, 2.1743 s, 15.4 MB/s root@imx6qdlsolo:~# dd if=/dev/mtd0 of=/dev/null bs=32M count=1 1+0 records in 1+0 records out 33554432 bytes (34 MB) copied, 1.43158 s, 23.4 MB/s Signed-off-by: Allen Xu <b45815@freescale.com> (cherry picked from commit ebcd4437450c4f0075988ef9c8824e837546c70b)
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c53
1 files changed, 42 insertions, 11 deletions
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 3f6018d6833f..f04e8285b4eb 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -1,7 +1,7 @@
/*
* Freescale QuadSPI driver.
*
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
+ * Copyright (C) 2014-2015 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -230,8 +230,10 @@ struct fsl_qspi {
struct mtd_info mtd[FSL_QSPI_MAX_CHIP];
struct spi_nor nor[FSL_QSPI_MAX_CHIP];
void __iomem *iobase;
- void __iomem *ahb_base; /* Used when read from AHB bus */
+ void __iomem *ahb_addr;
u32 memmap_phy;
+ u32 memmap_offs;
+ u32 memmap_len;
struct clk *clk, *clk_en;
struct device *dev;
struct completion c;
@@ -867,18 +869,49 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
u8 cmd = nor->read_opcode;
int ret;
- dev_dbg(q->dev, "cmd [%x],read from (0x%p, 0x%.8x, 0x%.8x),len:%d\n",
- cmd, q->ahb_base, q->chip_base_addr, (unsigned int)from, len);
-
/* Wait until the previous command is finished. */
ret = nor->wait_till_ready(nor);
if (ret)
return ret;
+ /* if necessary,ioremap buffer before AHB read, */
+ /* generally 4MB should be large enough */
+ if (!q->ahb_addr) {
+ q->ahb_addr = ioremap_nocache(
+ q->memmap_phy + q->chip_base_addr + from,
+ len > SZ_4M ? len : SZ_4M);
+ if (!q->ahb_addr) {
+ dev_err(q->dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+ q->memmap_offs = q->chip_base_addr + from;
+ q->memmap_len = len > SZ_4M ? len : SZ_4M;
+ /* ioremap if the data requested is out of range */
+ } else if (q->chip_base_addr + from < q->memmap_offs
+ || q->chip_base_addr + from + len >
+ q->memmap_offs + q->memmap_len) {
+ iounmap(q->ahb_addr);
+ q->ahb_addr = ioremap_nocache(
+ q->memmap_phy + q->chip_base_addr + from,
+ len > SZ_4M ? len : SZ_4M);
+ if (!q->ahb_addr) {
+ dev_err(q->dev, "ioremap failed\n");
+ return -ENOMEM;
+ }
+ q->memmap_offs = q->chip_base_addr + from;
+ q->memmap_len = len > SZ_4M ? len : SZ_4M;
+ }
+
+ dev_dbg(q->dev, "cmd [%x],read from 0x%p, len:%d\n",
+ cmd, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
+ len);
+
/* Read out the data directly from the AHB buffer.*/
- memcpy(buf, q->ahb_base + q->chip_base_addr + from, len);
+ memcpy(buf, q->ahb_addr + q->chip_base_addr + from - q->memmap_offs,
+ len);
*retlen += len;
+
return 0;
}
@@ -964,11 +997,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory");
- q->ahb_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(q->ahb_base)) {
- ret = PTR_ERR(q->ahb_base);
- goto map_failed;
- }
q->memmap_phy = res->start;
/* find the clocks */
@@ -1143,6 +1171,9 @@ static int fsl_qspi_remove(struct platform_device *pdev)
writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
writel(0x0, q->iobase + QUADSPI_RSER);
+ if (q->ahb_addr)
+ iounmap(q->ahb_addr);
+
return 0;
}