mtd: spi-nor: fsl-quadspi: dynamically map memory space for AHB read

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Tue Sep 1 14:59:02 PDT 2015


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=49bd706aac8fe7fa90988ecd3fd5c276575b194e
Commit:     49bd706aac8fe7fa90988ecd3fd5c276575b194e
Parent:     43163022927b6e7d202a7e6f939c3f392465494d
Author:     Han Xu <han.xu at freescale.com>
AuthorDate: Tue Aug 4 10:25:22 2015 -0500
Committer:  Brian Norris <computersforpeace at gmail.com>
CommitDate: Thu Aug 6 10:07:39 2015 -0700

    mtd: spi-nor: fsl-quadspi: dynamically map memory space for AHB read
    
    QSPI may failed to map enough memory (256MB) for AHB read in
    previous implementation, especially in 3G/1G memory layout kernel.
    Dynamically map memory to avoid such issue.
    
    This implementation generally map QUADSPI_MAX_IOMAP (default 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 at 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 at 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 at 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 at 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: Han Xu <han.xu at freescale.com>
    Signed-off-by: Frank Li <Frank.Li at freescale.com>
    Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 drivers/mtd/spi-nor/fsl-quadspi.c | 55 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 1946c6d..2d46036 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -192,6 +192,8 @@
 #define SEQID_EN4B		10
 #define SEQID_BRWR		11
 
+#define QUADSPI_MIN_IOMAP SZ_4M
+
 enum fsl_qspi_devtype {
 	FSL_QUADSPI_VYBRID,
 	FSL_QUADSPI_IMX6SX,
@@ -223,8 +225,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;
@@ -732,11 +736,42 @@ static int fsl_qspi_read(struct spi_nor *nor, loff_t from,
 	struct fsl_qspi *q = nor->priv;
 	u8 cmd = nor->read_opcode;
 
-	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);
+	/* if necessary,ioremap buffer before AHB read, */
+	if (!q->ahb_addr) {
+		q->memmap_offs = q->chip_base_addr + from;
+		q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
+
+		q->ahb_addr = ioremap_nocache(
+				q->memmap_phy + q->memmap_offs,
+				q->memmap_len);
+		if (!q->ahb_addr) {
+			dev_err(q->dev, "ioremap failed\n");
+			return -ENOMEM;
+		}
+	/* 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->memmap_offs = q->chip_base_addr + from;
+		q->memmap_len = len > QUADSPI_MIN_IOMAP ? len : QUADSPI_MIN_IOMAP;
+		q->ahb_addr = ioremap_nocache(
+				q->memmap_phy + q->memmap_offs,
+				q->memmap_len);
+		if (!q->ahb_addr) {
+			dev_err(q->dev, "ioremap failed\n");
+			return -ENOMEM;
+		}
+	}
+
+	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;
@@ -821,9 +856,11 @@ 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))
-		return PTR_ERR(q->ahb_base);
+	if (!devm_request_mem_region(dev, res->start, resource_size(res),
+				     res->name)) {
+		dev_err(dev, "can't request region for resource %pR\n", res);
+		return -EBUSY;
+	}
 
 	q->memmap_phy = res->start;
 
@@ -989,6 +1026,10 @@ static int fsl_qspi_remove(struct platform_device *pdev)
 	mutex_destroy(&q->lock);
 	clk_unprepare(q->clk);
 	clk_unprepare(q->clk_en);
+
+	if (q->ahb_addr)
+		iounmap(q->ahb_addr);
+
 	return 0;
 }
 



More information about the linux-mtd-cvs mailing list