123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- Asynchronous Transfers/Transforms API
- 1 INTRODUCTION
- 2 GENEALOGY
- 3 USAGE
- 3.1 General format of the API
- 3.2 Supported operations
- 3.3 Descriptor management
- 3.4 When does the operation execute?
- 3.5 When does the operation complete?
- 3.6 Constraints
- 3.7 Example
- 4 DMAENGINE DRIVER DEVELOPER NOTES
- 4.1 Conformance points
- 4.2 "My application needs exclusive control of hardware channels"
- 5 SOURCE
- ---
- 1 INTRODUCTION
- The async_tx API provides methods for describing a chain of asynchronous
- bulk memory transfers/transforms with support for inter-transactional
- dependencies. It is implemented as a dmaengine client that smooths over
- the details of different hardware offload engine implementations. Code
- that is written to the API can optimize for asynchronous operation and
- the API will fit the chain of operations to the available offload
- resources.
- 2 GENEALOGY
- The API was initially designed to offload the memory copy and
- xor-parity-calculations of the md-raid5 driver using the offload engines
- present in the Intel(R) Xscale series of I/O processors. It also built
- on the 'dmaengine' layer developed for offloading memory copies in the
- network stack using Intel(R) I/OAT engines. The following design
- features surfaced as a result:
- 1/ implicit synchronous path: users of the API do not need to know if
- the platform they are running on has offload capabilities. The
- operation will be offloaded when an engine is available and carried out
- in software otherwise.
- 2/ cross channel dependency chains: the API allows a chain of dependent
- operations to be submitted, like xor->copy->xor in the raid5 case. The
- API automatically handles cases where the transition from one operation
- to another implies a hardware channel switch.
- 3/ dmaengine extensions to support multiple clients and operation types
- beyond 'memcpy'
- 3 USAGE
- 3.1 General format of the API:
- struct dma_async_tx_descriptor *
- async_<operation>(<op specific parameters>, struct async_submit ctl *submit)
- 3.2 Supported operations:
- memcpy - memory copy between a source and a destination buffer
- memset - fill a destination buffer with a byte value
- xor - xor a series of source buffers and write the result to a
- destination buffer
- xor_val - xor a series of source buffers and set a flag if the
- result is zero. The implementation attempts to prevent
- writes to memory
- pq - generate the p+q (raid6 syndrome) from a series of source buffers
- pq_val - validate that a p and or q buffer are in sync with a given series of
- sources
- datap - (raid6_datap_recov) recover a raid6 data block and the p block
- from the given sources
- 2data - (raid6_2data_recov) recover 2 raid6 data blocks from the given
- sources
- 3.3 Descriptor management:
- The return value is non-NULL and points to a 'descriptor' when the operation
- has been queued to execute asynchronously. Descriptors are recycled
- resources, under control of the offload engine driver, to be reused as
- operations complete. When an application needs to submit a chain of
- operations it must guarantee that the descriptor is not automatically recycled
- before the dependency is submitted. This requires that all descriptors be
- acknowledged by the application before the offload engine driver is allowed to
- recycle (or free) the descriptor. A descriptor can be acked by one of the
- following methods:
- 1/ setting the ASYNC_TX_ACK flag if no child operations are to be submitted
- 2/ submitting an unacknowledged descriptor as a dependency to another
- async_tx call will implicitly set the acknowledged state.
- 3/ calling async_tx_ack() on the descriptor.
- 3.4 When does the operation execute?
- Operations do not immediately issue after return from the
- async_<operation> call. Offload engine drivers batch operations to
- improve performance by reducing the number of mmio cycles needed to
- manage the channel. Once a driver-specific threshold is met the driver
- automatically issues pending operations. An application can force this
- event by calling async_tx_issue_pending_all(). This operates on all
- channels since the application has no knowledge of channel to operation
- mapping.
- 3.5 When does the operation complete?
- There are two methods for an application to learn about the completion
- of an operation.
- 1/ Call dma_wait_for_async_tx(). This call causes the CPU to spin while
- it polls for the completion of the operation. It handles dependency
- chains and issuing pending operations.
- 2/ Specify a completion callback. The callback routine runs in tasklet
- context if the offload engine driver supports interrupts, or it is
- called in application context if the operation is carried out
- synchronously in software. The callback can be set in the call to
- async_<operation>, or when the application needs to submit a chain of
- unknown length it can use the async_trigger_callback() routine to set a
- completion interrupt/callback at the end of the chain.
- 3.6 Constraints:
- 1/ Calls to async_<operation> are not permitted in IRQ context. Other
- contexts are permitted provided constraint #2 is not violated.
- 2/ Completion callback routines cannot submit new operations. This
- results in recursion in the synchronous case and spin_locks being
- acquired twice in the asynchronous case.
- 3.7 Example:
- Perform a xor->copy->xor operation where each operation depends on the
- result from the previous operation:
- void callback(void *param)
- {
- struct completion *cmp = param;
- complete(cmp);
- }
- void run_xor_copy_xor(struct page **xor_srcs,
- int xor_src_cnt,
- struct page *xor_dest,
- size_t xor_len,
- struct page *copy_src,
- struct page *copy_dest,
- size_t copy_len)
- {
- struct dma_async_tx_descriptor *tx;
- addr_conv_t addr_conv[xor_src_cnt];
- struct async_submit_ctl submit;
- addr_conv_t addr_conv[NDISKS];
- struct completion cmp;
- init_async_submit(&submit, ASYNC_TX_XOR_DROP_DST, NULL, NULL, NULL,
- addr_conv);
- tx = async_xor(xor_dest, xor_srcs, 0, xor_src_cnt, xor_len, &submit)
- submit->depend_tx = tx;
- tx = async_memcpy(copy_dest, copy_src, 0, 0, copy_len, &submit);
- init_completion(&cmp);
- init_async_submit(&submit, ASYNC_TX_XOR_DROP_DST | ASYNC_TX_ACK, tx,
- callback, &cmp, addr_conv);
- tx = async_xor(xor_dest, xor_srcs, 0, xor_src_cnt, xor_len, &submit);
- async_tx_issue_pending_all();
- wait_for_completion(&cmp);
- }
- See include/linux/async_tx.h for more information on the flags. See the
- ops_run_* and ops_complete_* routines in drivers/md/raid5.c for more
- implementation examples.
- 4 DRIVER DEVELOPMENT NOTES
- 4.1 Conformance points:
- There are a few conformance points required in dmaengine drivers to
- accommodate assumptions made by applications using the async_tx API:
- 1/ Completion callbacks are expected to happen in tasklet context
- 2/ dma_async_tx_descriptor fields are never manipulated in IRQ context
- 3/ Use async_tx_run_dependencies() in the descriptor clean up path to
- handle submission of dependent operations
- 4.2 "My application needs exclusive control of hardware channels"
- Primarily this requirement arises from cases where a DMA engine driver
- is being used to support device-to-memory operations. A channel that is
- performing these operations cannot, for many platform specific reasons,
- be shared. For these cases the dma_request_channel() interface is
- provided.
- The interface is:
- struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
- dma_filter_fn filter_fn,
- void *filter_param);
- Where dma_filter_fn is defined as:
- typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
- When the optional 'filter_fn' parameter is set to NULL
- dma_request_channel simply returns the first channel that satisfies the
- capability mask. Otherwise, when the mask parameter is insufficient for
- specifying the necessary channel, the filter_fn routine can be used to
- disposition the available channels in the system. The filter_fn routine
- is called once for each free channel in the system. Upon seeing a
- suitable channel filter_fn returns DMA_ACK which flags that channel to
- be the return value from dma_request_channel. A channel allocated via
- this interface is exclusive to the caller, until dma_release_channel()
- is called.
- The DMA_PRIVATE capability flag is used to tag dma devices that should
- not be used by the general-purpose allocator. It can be set at
- initialization time if it is known that a channel will always be
- private. Alternatively, it is set when dma_request_channel() finds an
- unused "public" channel.
- A couple caveats to note when implementing a driver and consumer:
- 1/ Once a channel has been privately allocated it will no longer be
- considered by the general-purpose allocator even after a call to
- dma_release_channel().
- 2/ Since capabilities are specified at the device level a dma_device
- with multiple channels will either have all channels public, or all
- channels private.
- 5 SOURCE
- include/linux/dmaengine.h: core header file for DMA drivers and api users
- drivers/dma/dmaengine.c: offload engine channel management routines
- drivers/dma/: location for offload engine drivers
- include/linux/async_tx.h: core header file for the async_tx api
- crypto/async_tx/async_tx.c: async_tx interface to dmaengine and common code
- crypto/async_tx/async_memcpy.c: copy offload
- crypto/async_tx/async_xor.c: xor and xor zero sum offload
|