[PATCH v2 1/1] mtd: spi-nor: fsl-qspi: dynamically map memory space for AHB read

Han Xu xhnjupt at gmail.com
Fri Jul 24 08:36:43 PDT 2015


On Thu, Jul 23, 2015 at 3:52 PM,  <Frank.Li at freescale.com> wrote:
> From: Allen Xu <b45815 at freescale.com>
>
> 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 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: Allen Xu <b45815 at freescale.com>
> Signed-off-by: Frank Li <Frank.Li at freescale.com>

Acked-by: Han Xu <han.xu at freescale.com>

> ---
>
> Change from v1 to v2:
>    rebase to last l2-mtd
>
>  drivers/mtd/spi-nor/fsl-quadspi.c | 48 ++++++++++++++++++++++++++++++++-------
>  1 file changed, 40 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
> index 1946c6d..e854004 100644
> --- a/drivers/mtd/spi-nor/fsl-quadspi.c
> +++ b/drivers/mtd/spi-nor/fsl-quadspi.c
> @@ -223,8 +223,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 +734,41 @@ 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, */
> +       /* 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;
> @@ -821,10 +853,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))
> -               return PTR_ERR(q->ahb_base);
> -
>         q->memmap_phy = res->start;
>
>         /* find the clocks */
> @@ -989,6 +1017,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;
>  }
>
> --
> 1.9.1
>
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/



More information about the linux-mtd mailing list