From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
To: "Nícolas F. R. A. Prado" <nfraprado@collabora.com>,
"Catalin Marinas" <catalin.marinas@arm.com>
Cc: Mark Brown <broonie@kernel.org>,
linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [PATCH v1 1/1] spi: Remove unneded check for orig_nents
Date: Fri, 17 May 2024 18:40:22 +0300 [thread overview]
Message-ID: <Zkd6Znvh3-AZROS4@smile.fi.intel.com> (raw)
In-Reply-To: <038b55ec-9cbc-4303-a962-906f073892b8@notapiano>
On Thu, May 16, 2024 at 05:11:21PM -0400, Nícolas F. R. A. Prado wrote:
> On Thu, May 16, 2024 at 08:46:23PM +0300, Andy Shevchenko wrote:
> > On Thu, May 16, 2024 at 12:25:19PM -0400, Nícolas F. R. A. Prado wrote:
> > > On Thu, May 16, 2024 at 04:25:35PM +0300, Andy Shevchenko wrote:
> > > > On Thu, May 16, 2024 at 01:18:04PM +0300, Andy Shevchenko wrote:
> > > > > On Wed, May 15, 2024 at 05:09:33PM -0400, Nícolas F. R. A. Prado wrote:
> > > > > > On Tue, May 07, 2024 at 11:10:27PM +0300, Andy Shevchenko wrote:
> > > > > > > Both dma_unmap_sgtable() and sg_free_table() in spi_unmap_buf_attrs()
> > > > > > > have checks for orig_nents against 0. No need to duplicate this.
> > > > > > > All the same applies to other DMA mapping API calls.
> > > > > > >
> > > > > > > Also note, there is no other user in the kernel that does this kind of
> > > > > > > checks.
> > > > > > >
> > > > > > > Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > > > > >
> > > > > > this commit caused a regression which I reported here:
> > > > > >
> > > > > > https://lore.kernel.org/all/d3679496-2e4e-4a7c-97ed-f193bd53af1d@notapiano
> > > > > >
> > > > > > along with some thoughts on the cause and a possible solution, though I'm not
> > > > > > familiar with this code base at all and would really appreciate any feedback you
> > > > > > may have.
> > > > >
> > > > > Thanks for the report and preliminary analysis!
> > > > > I'll look at it hopefully sooner than later.
> > > > >
> > > > > But at least what I think now is that my change revealed a problem somewhere
> > > > > else, because that's how DMA mapping / streaming APIs designed, it's extremely
> > > > > rare to check orig_nents field.
> > > >
> > > > Can you test the below patch?
> > > >
> > > > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> > > > index b2efd4964f7c..51811f04e463 100644
> > > > --- a/drivers/spi/spi.c
> > > > +++ b/drivers/spi/spi.c
> > > > @@ -1243,6 +1243,7 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
> > > > else
> > > > rx_dev = ctlr->dev.parent;
> > > >
> > > > + ret = -ENOMSG;
> > > > list_for_each_entry(xfer, &msg->transfers, transfer_list) {
> > > > /* The sync is done before each transfer. */
> > > > unsigned long attrs = DMA_ATTR_SKIP_CPU_SYNC;
> > > > @@ -1272,6 +1273,9 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
> > > > }
> > > > }
> > > > }
> > > > + /* No transfer has been mapped, bail out with success */
> > > > + if (ret)
> > > > + return 0;
> > > >
> > > > ctlr->cur_rx_dma_dev = rx_dev;
> > > > ctlr->cur_tx_dma_dev = tx_dev;
> > >
> > > Hi Andy,
> > >
> > > thank you for the patch. Unfortunately it didn't completely solve the issue. Now
> > > the stack trace is slightly different and points at the next line:
> > >
> > > dma_sync_sgtable_for_device(rx_dev, &xfer->rx_sg, DMA_FROM_DEVICE);
> > >
> > > So now we're hitting the case where only the tx buffer was DMA mapped, but the
> > > rx is still uninitialized, though the cur_msg_mapped flag is set to true, since
> > > it is shared between them. The original code checked for the initialization of
> > > each scatterlist individually, which is why it worked.
(So the above patch is okay, the below is wrong, but read at the bottom as well)
> > I was kinda expecting that, and already have another patch to try (should
> > applied on top):
> >
> > diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
> > index 51811f04e463..5c607dd21fe7 100644
> > --- a/drivers/spi/spi.c
> > +++ b/drivers/spi/spi.c
> > @@ -1258,6 +1258,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
> > attrs);
> > if (ret != 0)
> > return ret;
> > + } else {
> > + memset(&xfer->tx_sg, 0, sizeof(xfer->tx_sg));
> > }
> >
> > if (xfer->rx_buf != NULL) {
> > @@ -1271,6 +1273,8 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
> >
> > return ret;
> > }
> > + } else {
> > + memset(&xfer->rx_sg, 0, sizeof(xfer->rx_sg));
> > }
> > }
> > /* No transfer has been mapped, bail out with success */
>
> Still the same issue. I've attached the backtrace at the end for reference. But
> I don't see how a memset would help here. As far as I can see, there's nothing
> in the DMA API protecting it from a null pointer to be passed in. So when
>
> dma_sync_sgtable_for_device(tx_dev, &xfer->tx_sg, DMA_TO_DEVICE);
>
> is called with xfer->tx_sg.sgl being null, that will get passed all the way to
> iommu_dma_sync_sg_for_device() and sg_dma_is_swiotlb(), where it'll be
> dereferenced and cause the issue.
Right, sorry I was missing that piece.
> So it seems to me that either the DMA API
> functions should check for the null pointer, or if the API doesn't want to
> handle those cases (like sync being called before the buffer has been mapped),
> then the caller needs to do the check, as was done in the original code.
The dma-api.rst seems to imply that sync calls done after the mapping:
"With the sync_sg API, all the parameters must be the same as those
passed into the sg mapping API."
The dma-api-howto.rst is clearer on this:
"So, firstly, just map it with dma_map_{single,sg}(), and after each DMA
transfer call either::
dma_sync_single_for_cpu(dev, dma_handle, size, direction);
or::
dma_sync_sg_for_cpu(dev, sglist, nents, direction);
as appropriate."
So, it means the calling sync APIs on unprepared resources is a shooting in
a foot. OTOH
> The same applies for the change in spi_unmap_buf_attrs(). I see sg_free_table()
> does handle a null sgl, but dma_unmap_sgtable() doesn't (and indeed I verified
> null pointer dereference happens there too if I avoid this one).
Taking into account the above, I think those memset()'s has actually to be
paired with a dummy SG table, which is empty.
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1220,6 +1220,11 @@ void spi_unmap_buf(struct spi_controller *ctlr, struct device *dev,
spi_unmap_buf_attrs(ctlr, dev, sgt, dir, 0);
}
+/* Dummy SG for unidirect transfers */
+static struct scatterlist dummy_sg = {
+ .page_link = SG_END,
+};
+
static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
{
struct device *tx_dev, *rx_dev;
@@ -1260,6 +1265,7 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
return ret;
} else {
memset(&xfer->tx_sg, 0, sizeof(xfer->tx_sg));
+ xfer->tx_sg.sgl = &dummy_sg;
}
if (xfer->rx_buf != NULL) {
@@ -1275,6 +1281,7 @@ static int __spi_map_msg(struct spi_controller *ctlr, struct spi_message *msg)
}
} else {
memset(&xfer->rx_sg, 0, sizeof(xfer->rx_sg));
+ xfer->rx_sg.sgl = &dummy_sg;
}
}
/* No transfer has been mapped, bail out with success */
But the best shot is to fix IOMMU for nents == 0 case in my opinion. Neglecting
nents before accessing the SG is not a good idea. Catalin?
The commit in question here is this one 861370f49ce4 ("iommu/dma: force
bouncing if the size is not cacheline-aligned").
--
With Best Regards,
Andy Shevchenko
next prev parent reply other threads:[~2024-05-17 15:40 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-07 20:10 [PATCH v1 1/1] spi: Remove unneded check for orig_nents Andy Shevchenko
2024-05-08 12:08 ` Mark Brown
2024-05-16 11:28 ` [PATCH] spi: Remove unneeded " Markus Elfring
2024-05-15 21:09 ` [PATCH v1 1/1] spi: Remove unneded " Nícolas F. R. A. Prado
2024-05-16 10:18 ` Andy Shevchenko
2024-05-16 13:25 ` Andy Shevchenko
2024-05-16 16:25 ` Nícolas F. R. A. Prado
2024-05-16 17:46 ` Andy Shevchenko
2024-05-16 21:11 ` Nícolas F. R. A. Prado
2024-05-17 15:40 ` Andy Shevchenko [this message]
2024-05-22 10:03 ` Neil Armstrong
2024-05-22 11:33 ` Andy Shevchenko
2024-05-22 11:53 ` Neil Armstrong
2024-05-22 13:18 ` Neil Armstrong
2024-05-22 14:24 ` Andy Shevchenko
2024-05-22 15:12 ` Nícolas F. R. A. Prado
2024-05-22 15:24 ` Andy Shevchenko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Zkd6Znvh3-AZROS4@smile.fi.intel.com \
--to=andriy.shevchenko@linux.intel.com \
--cc=broonie@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-spi@vger.kernel.org \
--cc=nfraprado@collabora.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.