Commit bfa41337 authored by Cyrille Pitchen's avatar Cyrille Pitchen Committed by Boris Brezillon

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: f384b352 ("mtd: spi-nor: parse Serial Flash Discoverable Parameters (SFDP) tables")
Reported-by: default avatarGeert Uytterhoeven <geert@linux-m68k.org>
Signed-off-by: default avatarCyrille Pitchen <cyrille.pitchen@wedev4u.fr>
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
parent b8f39116
...@@ -1784,7 +1784,7 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp, ...@@ -1784,7 +1784,7 @@ spi_nor_set_pp_settings(struct spi_nor_pp_command *pp,
* @nor: pointer to a 'struct spi_nor' * @nor: pointer to a 'struct spi_nor'
* @addr: offset in the SFDP area to start reading data from * @addr: offset in the SFDP area to start reading data from
* @len: number of bytes to read * @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 * Whatever the actual numbers of bytes for address and dummy cycles are
* for (Fast) Read commands, the Read SFDP (5Ah) instruction is always * for (Fast) Read commands, the Read SFDP (5Ah) instruction is always
...@@ -1829,6 +1829,36 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, ...@@ -1829,6 +1829,36 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr,
return ret; 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 { struct sfdp_parameter_header {
u8 id_lsb; u8 id_lsb;
u8 minor; u8 minor;
...@@ -2101,7 +2131,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor, ...@@ -2101,7 +2131,7 @@ static int spi_nor_parse_bfpt(struct spi_nor *nor,
bfpt_header->length * sizeof(u32)); bfpt_header->length * sizeof(u32));
addr = SFDP_PARAM_HEADER_PTP(bfpt_header); addr = SFDP_PARAM_HEADER_PTP(bfpt_header);
memset(&bfpt, 0, sizeof(bfpt)); 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) if (err < 0)
return err; return err;
...@@ -2252,7 +2282,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor, ...@@ -2252,7 +2282,7 @@ static int spi_nor_parse_sfdp(struct spi_nor *nor,
int i, err; int i, err;
/* Get the SFDP header. */ /* 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) if (err < 0)
return err; return err;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment