Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755278AbdIGLiL (ORCPT ); Thu, 7 Sep 2017 07:38:11 -0400 Received: from mail.free-electrons.com ([62.4.15.54]:32833 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754219AbdIGLiJ (ORCPT ); Thu, 7 Sep 2017 07:38:09 -0400 Date: Thu, 7 Sep 2017 13:37:56 +0200 From: Boris Brezillon To: Geert Uytterhoeven Cc: Cyrille Pitchen , Marek Vasut , MTD Maling List , Brian Norris , David Woodhouse , Richard Weinberger , "linux-kernel@vger.kernel.org" , Linux-Renesas , Mark Brown Subject: Re: [PATCH] mtd: spi-nor: fix DMA unsafe buffer issue in spi_nor_read_sfdp() Message-ID: <20170907133756.6c1f02f6@bbrezillon> In-Reply-To: References: <20170906214502.26748-1-cyrille.pitchen@wedev4u.fr> X-Mailer: Claws Mail 3.14.1 (GTK+ 2.24.31; x86_64-pc-linux-gnu) MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5253 Lines: 122 On Thu, 7 Sep 2017 10:00:50 +0200 Geert Uytterhoeven wrote: > Hi Cyrille, > > On Wed, Sep 6, 2017 at 11:45 PM, Cyrille Pitchen > wrote: > > 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. > > > > Reported-by: Geert Uytterhoeven > > Signed-off-by: Cyrille Pitchen > > While this patch got rid of the warning, it does not fix the SPI FLASH > identification > issue: > > m25p80 spi0.0: s25fl512s (0 Kbytes) > 3 ofpart partitions found on MTD device spi0.0 > Creating 3 MTD partitions on "spi0.0": > 0x000000000000-0x000000040000 : "loader" > mtd: partition "loader" is out of reach -- disabled > 0x000000040000-0x000000080000 : "system" > mtd: partition "system" is out of reach -- disabled > 0x000000080000-0x000004000000 : "user" > mtd: partition "user" is out of reach -- disabled > > I noticed there's still one direct call to spi_nor_read_sfdp() left in > spi_nor_parse_sfdp(). > I tried changing that to spi_nor_read_sfdp_dma_unsafe(), but that didn't help. > > > --- 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 @@ static int spi_nor_read_sfdp(struct spi_nor *nor, u32 addr, > > 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; > > > > @@ -2243,7 +2273,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; > > > > Instead of having buffers on the stack, passing them around through multiple > call levels, and then kmalloc()ing a buffer, what about using the helpers in > instead, which take care of the issue through the > static bounce > buffer or kmalloc() themselves? Are you referring to spi_write_then_read()? If this is the case, I'm not sure we can use this because m25p80_read/write() can have more than 2 transfers.