mtd: spi-nor: fix DMA unsafe buffer issue in spi_nor_read_sfdp()

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Tue Sep 19 13:59:01 PDT 2017


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=bfa4133795e5a0badd402dd3f58b13b3cec64a4b
Commit:     bfa4133795e5a0badd402dd3f58b13b3cec64a4b
Parent:     b8f3911610529ba531b99d1e109c7a40fb071f0a
Author:     Cyrille Pitchen <cyrille.pitchen at wedev4u.fr>
AuthorDate: Wed Sep 6 23:45:02 2017 +0200
Committer:  Boris Brezillon <boris.brezillon at free-electrons.com>
CommitDate: Mon Sep 18 09:53:27 2017 +0200

    mtd: spi-nor: fix DMA unsafe buffer issue in spi_nor_read_sfdp()
    
    spi_nor_read_sfdp() calls nor->read() to read the SFDP data.
    When the m25p80 driver is used (pretty common case), nor->read() is then
    implemented by the m25p80_read() function, which is likely to initialize a
    'struct spi_transfer' from its buf argument before appending this
    structure inside the 'struct spi_message' argument of spi_sync().
    
    Besides the SPI sub-system states that both .tx_buf and .rx_buf members of
    'struct spi_transfer' must point into dma-safe memory. However, two of the
    three calls of spi_nor_read_sfdp() were given pointers to stack allocated
    memory as buf argument, hence not in a dma-safe area.
    Hopefully, the third and last call of spi_nor_read_sfdp() was already
    given a kmalloc'ed buffer argument, hence dma-safe.
    
    So this patch fixes this issue by introducing a
    spi_nor_read_sfdp_dma_unsafe() function which simply wraps the existing
    spi_nor_read_sfdp() function and uses some kmalloc'ed memory as a bounce
    buffer.
    
    Fixes: f384b352cbf0 ("mtd: spi-nor: parse Serial Flash Discoverable Parameters (SFDP) tables")
    Reported-by: Geert Uytterhoeven <geert at linux-m68k.org>
    Signed-off-by: Cyrille Pitchen <cyrille.pitchen at wedev4u.fr>
    Signed-off-by: Boris Brezillon <boris.brezillon at free-electrons.com>
---
 drivers/mtd/spi-nor/spi-nor.c | 36 +++++++++++++++++++++++++++++++++---
 1 file changed, 33 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 4425b02..19c00072 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -1784,7 +1784,7 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
  * @nor:	pointer to a 'struct spi_nor'
  * @addr:	offset in the SFDP area to start reading data from
  * @len:	number of bytes to read
- * @buf:	buffer where the SFDP data are copied into
+ * @buf:	buffer where the SFDP data are copied into (dma-safe memory)
  *
  * Whatever the actual numbers of bytes for address and dummy cycles are
  * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always
@@ -1829,6 +1829,36 @@ read_err:
 	return ret;
 }
 
+/**
+ * spi_nor_read_sfdp_dma_unsafe() - read Serial Flash Discoverable Parameters.
+ * @nor:	pointer to a 'struct spi_nor'
+ * @addr:	offset in the SFDP area to start reading data from
+ * @len:	number of bytes to read
+ * @buf:	buffer where the SFDP data are copied into
+ *
+ * Wrap spi_nor_read_sfdp() using a kmalloc'ed bounce buffer as @buf is now not
+ * guaranteed to be dma-safe.
+ *
+ * Return: -ENOMEM if kmalloc() fails, the return code of spi_nor_read_sfdp()
+ *          otherwise.
+ */
+static int spi_nor_read_sfdp_dma_unsafe(struct spi_nor *nor, u32 addr,
+					size_t len, void *buf)
+{
+	void *dma_safe_buf;
+	int ret;
+
+	dma_safe_buf = kmalloc(len, GFP_KERNEL);
+	if (!dma_safe_buf)
+		return -ENOMEM;
+
+	ret = spi_nor_read_sfdp(nor, addr, len, dma_safe_buf);
+	memcpy(buf, dma_safe_buf, len);
+	kfree(dma_safe_buf);
+
+	return ret;
+}
+
 struct sfdp_parameter_header {
 	u8		id_lsb;
 	u8		minor;
@@ -2101,7 +2131,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
 		    bfpt_header->length * sizeof(u32));
 	addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
 	memset(&bfpt, 0, sizeof(bfpt));
-	err = spi_nor_read_sfdp(nor,  addr, len, &bfpt);
+	err = spi_nor_read_sfdp_dma_unsafe(nor,  addr, len, &bfpt);
 	if (err < 0)
 		return err;
 
@@ -2252,7 +2282,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
 	int i, err;
 
 	/* Get the SFDP header. */
-	err = spi_nor_read_sfdp(nor, 0, sizeof(header), &header);
+	err = spi_nor_read_sfdp_dma_unsafe(nor, 0, sizeof(header), &header);
 	if (err < 0)
 		return err;
 



More information about the linux-mtd-cvs mailing list