mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	Documentation: dmaengine: Add a documentation for the dma controller API
The dmaengine is neither trivial nor properly documented at the moment, which means a lot of trial and error development, which is not that good for such a central piece of the system. Attempt at making such a documentation. Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> [fixed some minor typos] Signed-off-by: Vinod Koul <vinod.koul@intel.com>
This commit is contained in:
		
							parent
							
								
									f36d2e6752
								
							
						
					
					
						commit
						c4d2ae967c
					
				
					 1 changed files with 366 additions and 0 deletions
				
			
		
							
								
								
									
										366
									
								
								Documentation/dmaengine/provider.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										366
									
								
								Documentation/dmaengine/provider.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,366 @@
 | 
			
		|||
DMAengine controller documentation
 | 
			
		||||
==================================
 | 
			
		||||
 | 
			
		||||
Hardware Introduction
 | 
			
		||||
+++++++++++++++++++++
 | 
			
		||||
 | 
			
		||||
Most of the Slave DMA controllers have the same general principles of
 | 
			
		||||
operations.
 | 
			
		||||
 | 
			
		||||
They have a given number of channels to use for the DMA transfers, and
 | 
			
		||||
a given number of requests lines.
 | 
			
		||||
 | 
			
		||||
Requests and channels are pretty much orthogonal. Channels can be used
 | 
			
		||||
to serve several to any requests. To simplify, channels are the
 | 
			
		||||
entities that will be doing the copy, and requests what endpoints are
 | 
			
		||||
involved.
 | 
			
		||||
 | 
			
		||||
The request lines actually correspond to physical lines going from the
 | 
			
		||||
DMA-eligible devices to the controller itself. Whenever the device
 | 
			
		||||
will want to start a transfer, it will assert a DMA request (DRQ) by
 | 
			
		||||
asserting that request line.
 | 
			
		||||
 | 
			
		||||
A very simple DMA controller would only take into account a single
 | 
			
		||||
parameter: the transfer size. At each clock cycle, it would transfer a
 | 
			
		||||
byte of data from one buffer to another, until the transfer size has
 | 
			
		||||
been reached.
 | 
			
		||||
 | 
			
		||||
That wouldn't work well in the real world, since slave devices might
 | 
			
		||||
require a specific number of bits to be transferred in a single
 | 
			
		||||
cycle. For example, we may want to transfer as much data as the
 | 
			
		||||
physical bus allows to maximize performances when doing a simple
 | 
			
		||||
memory copy operation, but our audio device could have a narrower FIFO
 | 
			
		||||
that requires data to be written exactly 16 or 24 bits at a time. This
 | 
			
		||||
is why most if not all of the DMA controllers can adjust this, using a
 | 
			
		||||
parameter called the transfer width.
 | 
			
		||||
 | 
			
		||||
Moreover, some DMA controllers, whenever the RAM is used as a source
 | 
			
		||||
or destination, can group the reads or writes in memory into a buffer,
 | 
			
		||||
so instead of having a lot of small memory accesses, which is not
 | 
			
		||||
really efficient, you'll get several bigger transfers. This is done
 | 
			
		||||
using a parameter called the burst size, that defines how many single
 | 
			
		||||
reads/writes it's allowed to do without the controller splitting the
 | 
			
		||||
transfer into smaller sub-transfers.
 | 
			
		||||
 | 
			
		||||
Our theoretical DMA controller would then only be able to do transfers
 | 
			
		||||
that involve a single contiguous block of data. However, some of the
 | 
			
		||||
transfers we usually have are not, and want to copy data from
 | 
			
		||||
non-contiguous buffers to a contiguous buffer, which is called
 | 
			
		||||
scatter-gather.
 | 
			
		||||
 | 
			
		||||
DMAEngine, at least for mem2dev transfers, require support for
 | 
			
		||||
scatter-gather. So we're left with two cases here: either we have a
 | 
			
		||||
quite simple DMA controller that doesn't support it, and we'll have to
 | 
			
		||||
implement it in software, or we have a more advanced DMA controller,
 | 
			
		||||
that implements in hardware scatter-gather.
 | 
			
		||||
 | 
			
		||||
The latter are usually programmed using a collection of chunks to
 | 
			
		||||
transfer, and whenever the transfer is started, the controller will go
 | 
			
		||||
over that collection, doing whatever we programmed there.
 | 
			
		||||
 | 
			
		||||
This collection is usually either a table or a linked list. You will
 | 
			
		||||
then push either the address of the table and its number of elements,
 | 
			
		||||
or the first item of the list to one channel of the DMA controller,
 | 
			
		||||
and whenever a DRQ will be asserted, it will go through the collection
 | 
			
		||||
to know where to fetch the data from.
 | 
			
		||||
 | 
			
		||||
Either way, the format of this collection is completely dependent on
 | 
			
		||||
your hardware. Each DMA controller will require a different structure,
 | 
			
		||||
but all of them will require, for every chunk, at least the source and
 | 
			
		||||
destination addresses, whether it should increment these addresses or
 | 
			
		||||
not and the three parameters we saw earlier: the burst size, the
 | 
			
		||||
transfer width and the transfer size.
 | 
			
		||||
 | 
			
		||||
The one last thing is that usually, slave devices won't issue DRQ by
 | 
			
		||||
default, and you have to enable this in your slave device driver first
 | 
			
		||||
whenever you're willing to use DMA.
 | 
			
		||||
 | 
			
		||||
These were just the general memory-to-memory (also called mem2mem) or
 | 
			
		||||
memory-to-device (mem2dev) kind of transfers. Most devices often
 | 
			
		||||
support other kind of transfers or memory operations that dmaengine
 | 
			
		||||
support and will be detailed later in this document.
 | 
			
		||||
 | 
			
		||||
DMA Support in Linux
 | 
			
		||||
++++++++++++++++++++
 | 
			
		||||
 | 
			
		||||
Historically, DMA controller drivers have been implemented using the
 | 
			
		||||
async TX API, to offload operations such as memory copy, XOR,
 | 
			
		||||
cryptography, etc., basically any memory to memory operation.
 | 
			
		||||
 | 
			
		||||
Over time, the need for memory to device transfers arose, and
 | 
			
		||||
dmaengine was extended. Nowadays, the async TX API is written as a
 | 
			
		||||
layer on top of dmaengine, and acts as a client. Still, dmaengine
 | 
			
		||||
accommodates that API in some cases, and made some design choices to
 | 
			
		||||
ensure that it stayed compatible.
 | 
			
		||||
 | 
			
		||||
For more information on the Async TX API, please look the relevant
 | 
			
		||||
documentation file in Documentation/crypto/async-tx-api.txt.
 | 
			
		||||
 | 
			
		||||
DMAEngine Registration
 | 
			
		||||
++++++++++++++++++++++
 | 
			
		||||
 | 
			
		||||
struct dma_device Initialization
 | 
			
		||||
--------------------------------
 | 
			
		||||
 | 
			
		||||
Just like any other kernel framework, the whole DMAEngine registration
 | 
			
		||||
relies on the driver filling a structure and registering against the
 | 
			
		||||
framework. In our case, that structure is dma_device.
 | 
			
		||||
 | 
			
		||||
The first thing you need to do in your driver is to allocate this
 | 
			
		||||
structure. Any of the usual memory allocators will do, but you'll also
 | 
			
		||||
need to initialize a few fields in there:
 | 
			
		||||
 | 
			
		||||
  * channels:	should be initialized as a list using the
 | 
			
		||||
		INIT_LIST_HEAD macro for example
 | 
			
		||||
 | 
			
		||||
  * dev: 	should hold the pointer to the struct device associated
 | 
			
		||||
		to your current driver instance.
 | 
			
		||||
 | 
			
		||||
Supported transaction types
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
The next thing you need is to set which transaction types your device
 | 
			
		||||
(and driver) supports.
 | 
			
		||||
 | 
			
		||||
Our dma_device structure has a field called cap_mask that holds the
 | 
			
		||||
various types of transaction supported, and you need to modify this
 | 
			
		||||
mask using the dma_cap_set function, with various flags depending on
 | 
			
		||||
transaction types you support as an argument.
 | 
			
		||||
 | 
			
		||||
All those capabilities are defined in the dma_transaction_type enum,
 | 
			
		||||
in include/linux/dmaengine.h
 | 
			
		||||
 | 
			
		||||
Currently, the types available are:
 | 
			
		||||
  * DMA_MEMCPY
 | 
			
		||||
    - The device is able to do memory to memory copies
 | 
			
		||||
 | 
			
		||||
  * DMA_XOR
 | 
			
		||||
    - The device is able to perform XOR operations on memory areas
 | 
			
		||||
    - Used to accelerate XOR intensive tasks, such as RAID5
 | 
			
		||||
 | 
			
		||||
  * DMA_XOR_VAL
 | 
			
		||||
    - The device is able to perform parity check using the XOR
 | 
			
		||||
      algorithm against a memory buffer.
 | 
			
		||||
 | 
			
		||||
  * DMA_PQ
 | 
			
		||||
    - The device is able to perform RAID6 P+Q computations, P being a
 | 
			
		||||
      simple XOR, and Q being a Reed-Solomon algorithm.
 | 
			
		||||
 | 
			
		||||
  * DMA_PQ_VAL
 | 
			
		||||
    - The device is able to perform parity check using RAID6 P+Q
 | 
			
		||||
      algorithm against a memory buffer.
 | 
			
		||||
 | 
			
		||||
  * DMA_INTERRUPT
 | 
			
		||||
    - The device is able to trigger a dummy transfer that will
 | 
			
		||||
      generate periodic interrupts
 | 
			
		||||
    - Used by the client drivers to register a callback that will be
 | 
			
		||||
      called on a regular basis through the DMA controller interrupt
 | 
			
		||||
 | 
			
		||||
  * DMA_SG
 | 
			
		||||
    - The device supports memory to memory scatter-gather
 | 
			
		||||
      transfers.
 | 
			
		||||
    - Even though a plain memcpy can look like a particular case of a
 | 
			
		||||
      scatter-gather transfer, with a single chunk to transfer, it's a
 | 
			
		||||
      distinct transaction type in the mem2mem transfers case
 | 
			
		||||
 | 
			
		||||
  * DMA_PRIVATE
 | 
			
		||||
    - The devices only supports slave transfers, and as such isn't
 | 
			
		||||
      available for async transfers.
 | 
			
		||||
 | 
			
		||||
  * DMA_ASYNC_TX
 | 
			
		||||
    - Must not be set by the device, and will be set by the framework
 | 
			
		||||
      if needed
 | 
			
		||||
    - /* TODO: What is it about? */
 | 
			
		||||
 | 
			
		||||
  * DMA_SLAVE
 | 
			
		||||
    - The device can handle device to memory transfers, including
 | 
			
		||||
      scatter-gather transfers.
 | 
			
		||||
    - While in the mem2mem case we were having two distinct types to
 | 
			
		||||
      deal with a single chunk to copy or a collection of them, here,
 | 
			
		||||
      we just have a single transaction type that is supposed to
 | 
			
		||||
      handle both.
 | 
			
		||||
    - If you want to transfer a single contiguous memory buffer,
 | 
			
		||||
      simply build a scatter list with only one item.
 | 
			
		||||
 | 
			
		||||
  * DMA_CYCLIC
 | 
			
		||||
    - The device can handle cyclic transfers.
 | 
			
		||||
    - A cyclic transfer is a transfer where the chunk collection will
 | 
			
		||||
      loop over itself, with the last item pointing to the first.
 | 
			
		||||
    - It's usually used for audio transfers, where you want to operate
 | 
			
		||||
      on a single ring buffer that you will fill with your audio data.
 | 
			
		||||
 | 
			
		||||
  * DMA_INTERLEAVE
 | 
			
		||||
    - The device supports interleaved transfer.
 | 
			
		||||
    - These transfers can transfer data from a non-contiguous buffer
 | 
			
		||||
      to a non-contiguous buffer, opposed to DMA_SLAVE that can
 | 
			
		||||
      transfer data from a non-contiguous data set to a continuous
 | 
			
		||||
      destination buffer.
 | 
			
		||||
    - It's usually used for 2d content transfers, in which case you
 | 
			
		||||
      want to transfer a portion of uncompressed data directly to the
 | 
			
		||||
      display to print it
 | 
			
		||||
 | 
			
		||||
These various types will also affect how the source and destination
 | 
			
		||||
addresses change over time.
 | 
			
		||||
 | 
			
		||||
Addresses pointing to RAM are typically incremented (or decremented)
 | 
			
		||||
after each transfer. In case of a ring buffer, they may loop
 | 
			
		||||
(DMA_CYCLIC). Addresses pointing to a device's register (e.g. a FIFO)
 | 
			
		||||
are typically fixed.
 | 
			
		||||
 | 
			
		||||
Device operations
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
Our dma_device structure also requires a few function pointers in
 | 
			
		||||
order to implement the actual logic, now that we described what
 | 
			
		||||
operations we were able to perform.
 | 
			
		||||
 | 
			
		||||
The functions that we have to fill in there, and hence have to
 | 
			
		||||
implement, obviously depend on the transaction types you reported as
 | 
			
		||||
supported.
 | 
			
		||||
 | 
			
		||||
   * device_alloc_chan_resources
 | 
			
		||||
   * device_free_chan_resources
 | 
			
		||||
     - These functions will be called whenever a driver will call
 | 
			
		||||
       dma_request_channel or dma_release_channel for the first/last
 | 
			
		||||
       time on the channel associated to that driver.
 | 
			
		||||
     - They are in charge of allocating/freeing all the needed
 | 
			
		||||
       resources in order for that channel to be useful for your
 | 
			
		||||
       driver.
 | 
			
		||||
     - These functions can sleep.
 | 
			
		||||
 | 
			
		||||
   * device_prep_dma_*
 | 
			
		||||
     - These functions are matching the capabilities you registered
 | 
			
		||||
       previously.
 | 
			
		||||
     - These functions all take the buffer or the scatterlist relevant
 | 
			
		||||
       for the transfer being prepared, and should create a hardware
 | 
			
		||||
       descriptor or a list of hardware descriptors from it
 | 
			
		||||
     - These functions can be called from an interrupt context
 | 
			
		||||
     - Any allocation you might do should be using the GFP_NOWAIT
 | 
			
		||||
       flag, in order not to potentially sleep, but without depleting
 | 
			
		||||
       the emergency pool either.
 | 
			
		||||
     - Drivers should try to pre-allocate any memory they might need
 | 
			
		||||
       during the transfer setup at probe time to avoid putting to
 | 
			
		||||
       much pressure on the nowait allocator.
 | 
			
		||||
 | 
			
		||||
     - It should return a unique instance of the
 | 
			
		||||
       dma_async_tx_descriptor structure, that further represents this
 | 
			
		||||
       particular transfer.
 | 
			
		||||
 | 
			
		||||
     - This structure can be initialized using the function
 | 
			
		||||
       dma_async_tx_descriptor_init.
 | 
			
		||||
     - You'll also need to set two fields in this structure:
 | 
			
		||||
       + flags:
 | 
			
		||||
		TODO: Can it be modified by the driver itself, or
 | 
			
		||||
		should it be always the flags passed in the arguments
 | 
			
		||||
 | 
			
		||||
       + tx_submit:	A pointer to a function you have to implement,
 | 
			
		||||
			that is supposed to push the current
 | 
			
		||||
			transaction descriptor to a pending queue, waiting
 | 
			
		||||
			for issue_pending to be called.
 | 
			
		||||
 | 
			
		||||
   * device_issue_pending
 | 
			
		||||
     - Takes the first transaction descriptor in the pending queue,
 | 
			
		||||
       and starts the transfer. Whenever that transfer is done, it
 | 
			
		||||
       should move to the next transaction in the list.
 | 
			
		||||
     - This function can be called in an interrupt context
 | 
			
		||||
 | 
			
		||||
   * device_tx_status
 | 
			
		||||
     - Should report the bytes left to go over on the given channel
 | 
			
		||||
     - Should only care about the transaction descriptor passed as
 | 
			
		||||
       argument, not the currently active one on a given channel
 | 
			
		||||
     - The tx_state argument might be NULL
 | 
			
		||||
     - Should use dma_set_residue to report it
 | 
			
		||||
     - In the case of a cyclic transfer, it should only take into
 | 
			
		||||
       account the current period.
 | 
			
		||||
     - This function can be called in an interrupt context.
 | 
			
		||||
 | 
			
		||||
   * device_control
 | 
			
		||||
     - Used by client drivers to control and configure the channel it
 | 
			
		||||
       has a handle on.
 | 
			
		||||
     - Called with a command and an argument
 | 
			
		||||
       + The command is one of the values listed by the enum
 | 
			
		||||
         dma_ctrl_cmd. The valid commands are:
 | 
			
		||||
         + DMA_PAUSE
 | 
			
		||||
           + Pauses a transfer on the channel
 | 
			
		||||
           + This command should operate synchronously on the channel,
 | 
			
		||||
             pausing right away the work of the given channel
 | 
			
		||||
         + DMA_RESUME
 | 
			
		||||
           + Restarts a transfer on the channel
 | 
			
		||||
           + This command should operate synchronously on the channel,
 | 
			
		||||
             resuming right away the work of the given channel
 | 
			
		||||
         + DMA_TERMINATE_ALL
 | 
			
		||||
           + Aborts all the pending and ongoing transfers on the
 | 
			
		||||
             channel
 | 
			
		||||
           + This command should operate synchronously on the channel,
 | 
			
		||||
             terminating right away all the channels
 | 
			
		||||
         + DMA_SLAVE_CONFIG
 | 
			
		||||
           + Reconfigures the channel with passed configuration
 | 
			
		||||
           + This command should NOT perform synchronously, or on any
 | 
			
		||||
             currently queued transfers, but only on subsequent ones
 | 
			
		||||
           + In this case, the function will receive a
 | 
			
		||||
             dma_slave_config structure pointer as an argument, that
 | 
			
		||||
             will detail which configuration to use.
 | 
			
		||||
           + Even though that structure contains a direction field,
 | 
			
		||||
             this field is deprecated in favor of the direction
 | 
			
		||||
             argument given to the prep_* functions
 | 
			
		||||
         + FSLDMA_EXTERNAL_START
 | 
			
		||||
           + TODO: Why does that even exist?
 | 
			
		||||
       + The argument is an opaque unsigned long. This actually is a
 | 
			
		||||
         pointer to a struct dma_slave_config that should be used only
 | 
			
		||||
         in the DMA_SLAVE_CONFIG.
 | 
			
		||||
 | 
			
		||||
  * device_slave_caps
 | 
			
		||||
    - Called through the framework by client drivers in order to have
 | 
			
		||||
      an idea of what are the properties of the channel allocated to
 | 
			
		||||
      them.
 | 
			
		||||
    - Such properties are the buswidth, available directions, etc.
 | 
			
		||||
    - Required for every generic layer doing DMA transfers, such as
 | 
			
		||||
      ASoC.
 | 
			
		||||
 | 
			
		||||
Misc notes (stuff that should be documented, but don't really know
 | 
			
		||||
where to put them)
 | 
			
		||||
------------------------------------------------------------------
 | 
			
		||||
  * dma_run_dependencies
 | 
			
		||||
    - Should be called at the end of an async TX transfer, and can be
 | 
			
		||||
      ignored in the slave transfers case.
 | 
			
		||||
    - Makes sure that dependent operations are run before marking it
 | 
			
		||||
      as complete.
 | 
			
		||||
 | 
			
		||||
  * dma_cookie_t
 | 
			
		||||
    - it's a DMA transaction ID that will increment over time.
 | 
			
		||||
    - Not really relevant any more since the introduction of virt-dma
 | 
			
		||||
      that abstracts it away.
 | 
			
		||||
 | 
			
		||||
  * DMA_CTRL_ACK
 | 
			
		||||
    - Undocumented feature
 | 
			
		||||
    - No one really has an idea of what it's about, besides being
 | 
			
		||||
      related to reusing the DMA transaction descriptors or having
 | 
			
		||||
      additional transactions added to it in the async-tx API
 | 
			
		||||
    - Useless in the case of the slave API
 | 
			
		||||
 | 
			
		||||
General Design Notes
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
Most of the DMAEngine drivers you'll see are based on a similar design
 | 
			
		||||
that handles the end of transfer interrupts in the handler, but defer
 | 
			
		||||
most work to a tasklet, including the start of a new transfer whenever
 | 
			
		||||
the previous transfer ended.
 | 
			
		||||
 | 
			
		||||
This is a rather inefficient design though, because the inter-transfer
 | 
			
		||||
latency will be not only the interrupt latency, but also the
 | 
			
		||||
scheduling latency of the tasklet, which will leave the channel idle
 | 
			
		||||
in between, which will slow down the global transfer rate.
 | 
			
		||||
 | 
			
		||||
You should avoid this kind of practice, and instead of electing a new
 | 
			
		||||
transfer in your tasklet, move that part to the interrupt handler in
 | 
			
		||||
order to have a shorter idle window (that we can't really avoid
 | 
			
		||||
anyway).
 | 
			
		||||
 | 
			
		||||
Glossary
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
Burst: 		A number of consecutive read or write operations
 | 
			
		||||
		that can be queued to buffers before being flushed to
 | 
			
		||||
		memory.
 | 
			
		||||
Chunk:		A contiguous collection of bursts
 | 
			
		||||
Transfer:	A collection of chunks (be it contiguous or not)
 | 
			
		||||
		Loading…
	
		Reference in a new issue