123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- ====================
- DMA Engine API Guide
- ====================
- Vinod Koul <vinod dot koul at intel.com>
- .. note:: For DMA Engine usage in async_tx please see:
- ``Documentation/crypto/async-tx-api.rst``
- Below is a guide to device driver writers on how to use the Slave-DMA API of the
- DMA Engine. This is applicable only for slave DMA usage only.
- DMA usage
- =========
- The slave DMA usage consists of following steps:
- - Allocate a DMA slave channel
- - Set slave and controller specific parameters
- - Get a descriptor for transaction
- - Submit the transaction
- - Issue pending requests and wait for callback notification
- The details of these operations are:
- 1. Allocate a DMA slave channel
- Channel allocation is slightly different in the slave DMA context,
- client drivers typically need a channel from a particular DMA
- controller only and even in some cases a specific channel is desired.
- To request a channel dma_request_chan() API is used.
- Interface:
- .. code-block:: c
- struct dma_chan *dma_request_chan(struct device *dev, const char *name);
- Which will find and return the ``name`` DMA channel associated with the 'dev'
- device. The association is done via DT, ACPI or board file based
- dma_slave_map matching table.
- A channel allocated via this interface is exclusive to the caller,
- until dma_release_channel() is called.
- 2. Set slave and controller specific parameters
- Next step is always to pass some specific information to the DMA
- driver. Most of the generic information which a slave DMA can use
- is in struct dma_slave_config. This allows the clients to specify
- DMA direction, DMA addresses, bus widths, DMA burst lengths etc
- for the peripheral.
- If some DMA controllers have more parameters to be sent then they
- should try to embed struct dma_slave_config in their controller
- specific structure. That gives flexibility to client to pass more
- parameters, if required.
- Interface:
- .. code-block:: c
- int dmaengine_slave_config(struct dma_chan *chan,
- struct dma_slave_config *config)
- Please see the dma_slave_config structure definition in dmaengine.h
- for a detailed explanation of the struct members. Please note
- that the 'direction' member will be going away as it duplicates the
- direction given in the prepare call.
- 3. Get a descriptor for transaction
- For slave usage the various modes of slave transfers supported by the
- DMA-engine are:
- - slave_sg: DMA a list of scatter gather buffers from/to a peripheral
- - dma_cyclic: Perform a cyclic DMA operation from/to a peripheral till the
- operation is explicitly stopped.
- - interleaved_dma: This is common to Slave as well as M2M clients. For slave
- address of devices' fifo could be already known to the driver.
- Various types of operations could be expressed by setting
- appropriate values to the 'dma_interleaved_template' members. Cyclic
- interleaved DMA transfers are also possible if supported by the channel by
- setting the DMA_PREP_REPEAT transfer flag.
- A non-NULL return of this transfer API represents a "descriptor" for
- the given transaction.
- Interface:
- .. code-block:: c
- struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(
- struct dma_chan *chan, struct scatterlist *sgl,
- unsigned int sg_len, enum dma_data_direction direction,
- unsigned long flags);
- struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(
- struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
- size_t period_len, enum dma_data_direction direction);
- struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma(
- struct dma_chan *chan, struct dma_interleaved_template *xt,
- unsigned long flags);
- The peripheral driver is expected to have mapped the scatterlist for
- the DMA operation prior to calling dmaengine_prep_slave_sg(), and must
- keep the scatterlist mapped until the DMA operation has completed.
- The scatterlist must be mapped using the DMA struct device.
- If a mapping needs to be synchronized later, dma_sync_*_for_*() must be
- called using the DMA struct device, too.
- So, normal setup should look like this:
- .. code-block:: c
- struct device *dma_dev = dmaengine_get_dma_device(chan);
- nr_sg = dma_map_sg(dma_dev, sgl, sg_len);
- if (nr_sg == 0)
- /* error */
- desc = dmaengine_prep_slave_sg(chan, sgl, nr_sg, direction, flags);
- Once a descriptor has been obtained, the callback information can be
- added and the descriptor must then be submitted. Some DMA engine
- drivers may hold a spinlock between a successful preparation and
- submission so it is important that these two operations are closely
- paired.
- .. note::
- Although the async_tx API specifies that completion callback
- routines cannot submit any new operations, this is not the
- case for slave/cyclic DMA.
- For slave DMA, the subsequent transaction may not be available
- for submission prior to callback function being invoked, so
- slave DMA callbacks are permitted to prepare and submit a new
- transaction.
- For cyclic DMA, a callback function may wish to terminate the
- DMA via dmaengine_terminate_async().
- Therefore, it is important that DMA engine drivers drop any
- locks before calling the callback function which may cause a
- deadlock.
- Note that callbacks will always be invoked from the DMA
- engines tasklet, never from interrupt context.
- **Optional: per descriptor metadata**
- DMAengine provides two ways for metadata support.
- DESC_METADATA_CLIENT
- The metadata buffer is allocated/provided by the client driver and it is
- attached to the descriptor.
- .. code-block:: c
- int dmaengine_desc_attach_metadata(struct dma_async_tx_descriptor *desc,
- void *data, size_t len);
- DESC_METADATA_ENGINE
- The metadata buffer is allocated/managed by the DMA driver. The client
- driver can ask for the pointer, maximum size and the currently used size of
- the metadata and can directly update or read it.
- Becasue the DMA driver manages the memory area containing the metadata,
- clients must make sure that they do not try to access or get the pointer
- after their transfer completion callback has run for the descriptor.
- If no completion callback has been defined for the transfer, then the
- metadata must not be accessed after issue_pending.
- In other words: if the aim is to read back metadata after the transfer is
- completed, then the client must use completion callback.
- .. code-block:: c
- void *dmaengine_desc_get_metadata_ptr(struct dma_async_tx_descriptor *desc,
- size_t *payload_len, size_t *max_len);
- int dmaengine_desc_set_metadata_len(struct dma_async_tx_descriptor *desc,
- size_t payload_len);
- Client drivers can query if a given mode is supported with:
- .. code-block:: c
- bool dmaengine_is_metadata_mode_supported(struct dma_chan *chan,
- enum dma_desc_metadata_mode mode);
- Depending on the used mode client drivers must follow different flow.
- DESC_METADATA_CLIENT
- - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM:
- 1. prepare the descriptor (dmaengine_prep_*)
- construct the metadata in the client's buffer
- 2. use dmaengine_desc_attach_metadata() to attach the buffer to the
- descriptor
- 3. submit the transfer
- - DMA_DEV_TO_MEM:
- 1. prepare the descriptor (dmaengine_prep_*)
- 2. use dmaengine_desc_attach_metadata() to attach the buffer to the
- descriptor
- 3. submit the transfer
- 4. when the transfer is completed, the metadata should be available in the
- attached buffer
- DESC_METADATA_ENGINE
- - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM:
- 1. prepare the descriptor (dmaengine_prep_*)
- 2. use dmaengine_desc_get_metadata_ptr() to get the pointer to the
- engine's metadata area
- 3. update the metadata at the pointer
- 4. use dmaengine_desc_set_metadata_len() to tell the DMA engine the
- amount of data the client has placed into the metadata buffer
- 5. submit the transfer
- - DMA_DEV_TO_MEM:
- 1. prepare the descriptor (dmaengine_prep_*)
- 2. submit the transfer
- 3. on transfer completion, use dmaengine_desc_get_metadata_ptr() to get
- the pointer to the engine's metadata area
- 4. read out the metadata from the pointer
- .. note::
- When DESC_METADATA_ENGINE mode is used the metadata area for the descriptor
- is no longer valid after the transfer has been completed (valid up to the
- point when the completion callback returns if used).
- Mixed use of DESC_METADATA_CLIENT / DESC_METADATA_ENGINE is not allowed,
- client drivers must use either of the modes per descriptor.
- 4. Submit the transaction
- Once the descriptor has been prepared and the callback information
- added, it must be placed on the DMA engine drivers pending queue.
- Interface:
- .. code-block:: c
- dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
- This returns a cookie can be used to check the progress of DMA engine
- activity via other DMA engine calls not covered in this document.
- dmaengine_submit() will not start the DMA operation, it merely adds
- it to the pending queue. For this, see step 5, dma_async_issue_pending.
- .. note::
- After calling ``dmaengine_submit()`` the submitted transfer descriptor
- (``struct dma_async_tx_descriptor``) belongs to the DMA engine.
- Consequently, the client must consider invalid the pointer to that
- descriptor.
- 5. Issue pending DMA requests and wait for callback notification
- The transactions in the pending queue can be activated by calling the
- issue_pending API. If channel is idle then the first transaction in
- queue is started and subsequent ones queued up.
- On completion of each DMA operation, the next in queue is started and
- a tasklet triggered. The tasklet will then call the client driver
- completion callback routine for notification, if set.
- Interface:
- .. code-block:: c
- void dma_async_issue_pending(struct dma_chan *chan);
- Further APIs
- ------------
- 1. Terminate APIs
- .. code-block:: c
- int dmaengine_terminate_sync(struct dma_chan *chan)
- int dmaengine_terminate_async(struct dma_chan *chan)
- int dmaengine_terminate_all(struct dma_chan *chan) /* DEPRECATED */
- This causes all activity for the DMA channel to be stopped, and may
- discard data in the DMA FIFO which hasn't been fully transferred.
- No callback functions will be called for any incomplete transfers.
- Two variants of this function are available.
- dmaengine_terminate_async() might not wait until the DMA has been fully
- stopped or until any running complete callbacks have finished. But it is
- possible to call dmaengine_terminate_async() from atomic context or from
- within a complete callback. dmaengine_synchronize() must be called before it
- is safe to free the memory accessed by the DMA transfer or free resources
- accessed from within the complete callback.
- dmaengine_terminate_sync() will wait for the transfer and any running
- complete callbacks to finish before it returns. But the function must not be
- called from atomic context or from within a complete callback.
- dmaengine_terminate_all() is deprecated and should not be used in new code.
- 2. Pause API
- .. code-block:: c
- int dmaengine_pause(struct dma_chan *chan)
- This pauses activity on the DMA channel without data loss.
- 3. Resume API
- .. code-block:: c
- int dmaengine_resume(struct dma_chan *chan)
- Resume a previously paused DMA channel. It is invalid to resume a
- channel which is not currently paused.
- 4. Check Txn complete
- .. code-block:: c
- enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
- dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
- This can be used to check the status of the channel. Please see
- the documentation in include/linux/dmaengine.h for a more complete
- description of this API.
- This can be used in conjunction with dma_async_is_complete() and
- the cookie returned from dmaengine_submit() to check for
- completion of a specific DMA transaction.
- .. note::
- Not all DMA engine drivers can return reliable information for
- a running DMA channel. It is recommended that DMA engine users
- pause or stop (via dmaengine_terminate_all()) the channel before
- using this API.
- 5. Synchronize termination API
- .. code-block:: c
- void dmaengine_synchronize(struct dma_chan *chan)
- Synchronize the termination of the DMA channel to the current context.
- This function should be used after dmaengine_terminate_async() to synchronize
- the termination of the DMA channel to the current context. The function will
- wait for the transfer and any running complete callbacks to finish before it
- returns.
- If dmaengine_terminate_async() is used to stop the DMA channel this function
- must be called before it is safe to free memory accessed by previously
- submitted descriptors or to free any resources accessed within the complete
- callback of previously submitted descriptors.
- The behavior of this function is undefined if dma_async_issue_pending() has
- been called between dmaengine_terminate_async() and this function.
|