Thread (24 messages) 24 messages, 7 authors, 2012-05-29

[alsa-devel] [PATCH 2/4] ASoC: mmp: add audio dma support

From: Russell King - ARM Linux <hidden>
Date: 2012-05-29 13:46:32
Also in: alsa-devel

On Tue, May 29, 2012 at 02:14:11PM +0100, Mark Brown wrote:
On Tue, May 29, 2012 at 10:21:29AM +0100, Russell King - ARM Linux wrote:
quoted
On Tue, May 29, 2012 at 10:02:15AM +0100, Mark Brown wrote:
quoted
quoted
What is the issue with the current code - it *looks* like you want to
use the component device for the DMA as the struct device with dmaengine
but I don't understand the issue that's created if we don't (and why
things appear to be working for people as they are).
quoted
Look.  It's very very very very simple.
quoted
What does the DMA API take?  A struct device.  What struct device?  Some
random struct device for something in the system, or what?  No, it takes
the struct device for the _device_ in the system which is _performing_
the DMA.
I'm assuming that you mean the client rather than the DMA controller
itself (which we must already have found)?  That makes sense,
No, I mean the DMA controller *itself*.

DMA engines _can_ (and do - quite common on ARM platforms) have this setup:

                      CPU
                       |
               +-Bus switch matrix-+
     (RAM bus) |                   |
RAM------------+--DMA controller---+
                        |          |
                        |(rq+ack)  |(IO bus)
                        |          |
                        |          +-----------Peripheral 1
                        +--------- | ------------'
                                   +-----------Peripheral 2
                                  ...

So, the _peripherals_ themselves have no direct access to RAM at all.
These are totally and utterly incapable of any kind of DMA on their own.
They can only be _given_ data by some other agent in the system, that
being in the above case the CPU or the DMA controller.

When the DMA controller is setup, and asked to transfer data to a
peripheral device, it first starts by originating an access to RAM via
the RAM bus, and it loads the data into it's FIFO.  It then performs
accesses on the IO bus to _write_ the data into the peripheral just
as a CPU would under PIO.

So, to setup the _peripheral_ struct device with some nebulous "oh this
can access the whole of system memory and is DMA capable, let's allocate
DMA memory against it" is totally the wrong approach.  The peripheral
device can not know what the details are for some random DMA controller
elsewhere in the system.

Indeed, there are systems out there where the same peripheral can be
driven by more than one DMA controller.  What if each DMA controller
has different properties?

So, the struct device in the system representing the device which is
accessing memory is _the_ _DMA_ _controller_.

Why does this matter?  Consider this case:


                      CPU
                       |
     +-----------Bus switch matrix-+
     |                             |
RAM--+--IOMMU-----DMA controller---+
                        |          |
                        |(rq+ack)  |(IO bus)
                        |          |
                        |          +-----------Peripheral 1
                        +--------- | ------------'
                                   +-----------Peripheral 2
                                  ...

Now, for the DMA controller to access RAM, the IOMMU needs to be setup to
create mappings between the address space that the DMA controller can see,
and the RAM.  If there are no mappings setup, the DMA controller can't see
the RAM _at_ _all_ and DMA is not possible.  The IOMMU is managed via the
DMA API on many kernel architectures, x86 included.

If you use the peripheral struct device with the DMA API, how does the DMA
API know that it must setup some unknown DMA controller's IOMMU?

And why should the DMA API code even care about such complexities?

We don't do this on USB.  When a USB device wants to perform DMA, we map
its memory using the _host_ _controller_ struct device, not the USB
peripheral device's struct device.  It's exactly the same principle.
The struct device corresponding with whatever device is _actually_
accessing memory must be the struct device passed into the DMA API.
Currently we seem to have nobody actually working on this code in
mainline, as far as I can tell you and Vinod are the only people with
any active interest at a framework level (with Vinod's mostly being at
the dmaengine rather than ASoC level; I don't have any hardware with any
sort of dmaengine support) and because you have this out of tree
implementation you're working on you're mostly just offering feedback in
these driver review threads where apparently chunks of it are getting
missed.  Nobody else seems to be showing much inclination to get
involved so it seems unlikely to collide with other work.
That's partly because you took in soc-dmaengine.c, after you ridiculed
my version - mainly because it didn't support cyclic DMA at the time.
And so I assumed that you'd made up your mind, and just plain weren't
interested.  You have been very resistive towards discussing issues
coming up in this area, and in other areas I've raised with ASoC such
as the struct device lifetime issues - even when I've created patches
for you.

Moreover, because I don't see any hope for the SA11x0 PCM support going
in (it certainly won't support capture mode due to the need to run the
playback side to receive capture samples) I'm really not pushing it; it's
more my testbed for testing out my DMA engine work than serious ASoC
work.

So please excuse me if I'm not in a rush to post it to the list.  In the
mean time, it's viewable via:

http://ftp.arm.linux.org.uk/git/gitweb.cgi?p=linux-arm.git;a=commitdiff;h=76bc4eb916528ceef2609c22f949429e2322a331
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help