From: linux@armlinux.org.uk (Russell King - ARM Linux)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] ARM: dma-mapping: Fix dma_get_sgtable() for regions without struct page
Date: Wed, 22 Mar 2017 22:42:00 +0000 [thread overview]
Message-ID: <20170322224200.GH21222@n2100.armlinux.org.uk> (raw)
In-Reply-To: <CAKocOOMqWByyAotnjKM3Zqq9xUBNcBFMens5Rj08aiM99wxEzg@mail.gmail.com>
On Wed, Mar 22, 2017 at 02:29:09PM -0600, Shuah Khan wrote:
> On Wed, Mar 22, 2017 at 10:32 AM, Russell King - ARM Linux
> <linux@armlinux.org.uk> wrote:
> > Right - dma_to_pfn() will correctly translate the "handle" to a PFN
> > number, so we can just multiply that with PAGE_SIZE to get the physical
> > address, which if I'm interpreting your information above correctly,
> > would be 0x72d00000.
>
> Correct paddr is 0x72d00000. I forgot to add the allocation time debug dump:
>
> [ 154.619456] platform 11000000.codec:left: vb2_dc_alloc: buf
> ecdced80 cookie f2d00000 vaddr f2d00000 paddr 72d00000 dma_addr
> bca00000 size 946176 dc_cookie ecdced90 dma_to_pfn 772608
>
> > However, what you're saying is that there is no valid "struct page"
> > associated with that address.
>
> >From what I can tell from the data I have, dma_to_pfn(dev, handle);
> doesn't return valid page at arm_dma_get_sgtable(), even though
> dma_to_pfn(dev, handle); itself stays the same from alloc time, as you
> can see in the above dump from vb2_dc_alloc(): dma_to_pfn 772608
dma_to_pfn() returns the physical page frame number of the DMA address
in handle. It's page number 772608, which multiplying by the page size
gives us a physical address of 0xbca00000. So, it's correct in so far
as if the dma_addr (of 0xbca00000 above) is correct, then that
corresponds with a physical address of 0xbca00000.
I now think that 0xf2d00000 virtual is a remapped address, not part of
lowmem (it's within the vmalloc region) which will probably be confirmed
if you look in /proc/vmallocinfo. Since this address is remapped,
"__pa(buf->vaddr)" is invalid, it does not reference the physical page
at 0x72d00000 at all. __pa() is just doing a simple mathematical offset
translation, which is why it's undefined for remapped addresses.
So, I'll go with 0xbca00000 being the real physical address, not
0x72d00000.
> I am guessing page might not be valid, even at the alloc time. That is
> next on debug list.
If this is coming from dma_declare_coherent_memory() then it won't have
a struct page associated with it.
> Which is somewhat puzzling, because dma_attrs don't have the
> DMA_ATTR_NO_KERNEL_MAP set, __dma_alloc() passes in want_vaddr true.
> __alloc_from_contiguous() will map the page and return a valid vaddr
>
> __dma_alloc() then does
> *handle = pfn_to_dma(dev, page_to_pfn(page));
>
> to return the handle.
I think you're missing something, which is the code in
include/linux/dma-mapping.h - dma_alloc_attrs().
That calls dma_alloc_from_coherent() first, which is how memory provided
via dma_declare_coherent_memory() is allocated. This bypasses the
architecture code in arch/arm/mm/dma-mapping.c. This provides memory
which is _not_ backed by a valid "struct page".
> > The correct way to validate this is:
> >
> > unsigned long pfn = dma_to_pfn(dev, handle);
> > struct page *page;
> >
> > if (!pfn_valid(pfn))
> > return -ENXIO;
> >
> > page = pfn_to_page(pfn);
> >
> > However, I have a huge big problem with this - this can pass even for
> > memory obtained through the coherent allocator (because of the way CMA
> > works.)
>
> Right. DMA_ATTR_NO_KERNEL_MAP is another variable, if set, there won't
> be an kernel mapping.
Correct - which is why the above is probably the most correct way on
ARM (provided there is no IOMMU in the path) to get the corresponding
valid struct page pointer.
> > This can end up with the DMA streaming API kmapping memory using
> > cacheable attributes while CMA has it mapped with uncacheable attributes,
> > where (as mentioned on IRC this morning):
>
> Which irc channel?? I can get on there for the discussion if it makes
> it easier.
It was for an unrelated discussion.
> We can see some of the evidence here in this case. One driver allocates
> the buffer and another driber tries to import. After buffer is exported,
> there is a window between DQBUF and QBUF, DQBUF unmaps the buffers. Then
> the importer comes along referencing the sg_table and looks to map them.
> Before mapping, looks like D-cache clean has to occur and that would need
> vaddr if I understand correctly. So there a lot of places, it can trip
> all over.
This is wrong, and this is where I say that the dma_buf stuff is totally
broken.
DMA coherent memory must _never_ be passed to the streaming DMA API. No
exceptions.
However, the dma_buf stuff does not differentiate between DMA coherent
memory and streaming DMA memory - the model is purely around the exporter
creating a scatterlist, and the importer calling dma_map_sg() on the
scatterlist to obtain its own set of DMA addresses.
(sorry for the caps, but it's an important point) THIS DOES NOT WORK.
It is a violation of the DMA API.
> > I also think that the dma_get_sgtable() thing is a total trainwreck,
> > and we need to have a rethink about this.
>
> I don't think it works for the case I am running into.
This is the root cause - the idea that you can create a valid
scatterlist from a DMA coherent area is _just_ completely broken.
It's not possible. dma_get_sgtable() is _fundamentally_ broken in
its design.
> > This isn't a case of "something changed in the architecture that broke
> > dma_get_sgtable()" - this is a case that it's always been broken in
> > this way ever since dma_get_sgtable() was introduced, and dma_get_sgtable()
> > was never (properly?) reviewed with this kind of use-case in mind.
>
> I think the use-case I am debugging has always been broken.
It's _always_ been invalid to pass memory allocated from
dma_alloc_coherent() into the streaming API functions (like
dma_map_sg().) So, you are quite correct that this has _always_ been
broken.
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
next prev parent reply other threads:[~2017-03-22 22:42 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20170221131655eucas1p2f2ca6e3c819aeae227c5e5c5f2bc7d3f@eucas1p2.samsung.com>
2017-02-21 13:16 ` [PATCH] ARM: dma-mapping: Fix dma_get_sgtable() for regions without struct page Marek Szyprowski
2017-03-22 11:10 ` Russell King - ARM Linux
2017-03-22 15:46 ` Shuah Khan
2017-03-22 16:32 ` Russell King - ARM Linux
2017-03-22 20:29 ` Shuah Khan
2017-03-22 22:42 ` Russell King - ARM Linux [this message]
2017-03-29 16:33 ` Russell King - ARM Linux
2017-03-29 16:51 ` Shuah Khan
2017-03-29 17:03 ` Russell King - ARM Linux
2017-03-29 17:44 ` Shuah Khan
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=20170322224200.GH21222@n2100.armlinux.org.uk \
--to=linux@armlinux.org.uk \
--cc=linux-arm-kernel@lists.infradead.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).