Commit 28405d8d authored by Dan Williams's avatar Dan Williams

async_tx, dmaengine: document channel allocation and api rework

"Wouldn't it be better if the dmaengine layer made sure it didn't pass
the same channel several times to a client?

I mean, you seem concerned that the memcpy() API should be transparent
and easy to use, but the whole registration interface is just
ridiculously complicated..."
	- Haavard

The dmaengine and async_tx registration/allocation interface is indeed
needlessly complicated.  This redesign has the following goals:

1/ Simplify reference counting: dma channels are not something one would
   expect to be hotplugged, it should be an exceptional event handled by
   drivers not something clients should be mandated to handle in a
   callback.  The common case channel removal event is 'rmmod <dma driver>',
   which for simplicity should be disallowed if the channel is in use.
2/ Add an interface for requesting exclusive access to a channel
   suitable to device-to-memory users.
3/ Convert all memory-to-memory users over to a common allocator, the goal
   here is to not have competing channel allocation schemes.  The only
   competition should be between device-to-memory exclusive allocations and
   the memory-to-memory usage case where channels are shared between
   multiple "clients".

Cc: Haavard Skinnemoen <haavard.skinnemoen@atmel.com>
Cc: Neil Brown <neilb@suse.de>
Cc: Jeff Garzik <jeff@garzik.org>
Reviewed-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent fe0bdec6
...@@ -13,9 +13,9 @@ ...@@ -13,9 +13,9 @@
3.6 Constraints 3.6 Constraints
3.7 Example 3.7 Example
4 DRIVER DEVELOPER NOTES 4 DMAENGINE DRIVER DEVELOPER NOTES
4.1 Conformance points 4.1 Conformance points
4.2 "My application needs finer control of hardware channels" 4.2 "My application needs exclusive control of hardware channels"
5 SOURCE 5 SOURCE
...@@ -150,6 +150,7 @@ ops_run_* and ops_complete_* routines in drivers/md/raid5.c for more ...@@ -150,6 +150,7 @@ ops_run_* and ops_complete_* routines in drivers/md/raid5.c for more
implementation examples. implementation examples.
4 DRIVER DEVELOPMENT NOTES 4 DRIVER DEVELOPMENT NOTES
4.1 Conformance points: 4.1 Conformance points:
There are a few conformance points required in dmaengine drivers to There are a few conformance points required in dmaengine drivers to
accommodate assumptions made by applications using the async_tx API: accommodate assumptions made by applications using the async_tx API:
...@@ -158,58 +159,49 @@ accommodate assumptions made by applications using the async_tx API: ...@@ -158,58 +159,49 @@ accommodate assumptions made by applications using the async_tx API:
3/ Use async_tx_run_dependencies() in the descriptor clean up path to 3/ Use async_tx_run_dependencies() in the descriptor clean up path to
handle submission of dependent operations handle submission of dependent operations
4.2 "My application needs finer control of hardware channels" 4.2 "My application needs exclusive control of hardware channels"
This requirement seems to arise from cases where a DMA engine driver is Primarily this requirement arises from cases where a DMA engine driver
trying to support device-to-memory DMA. The dmaengine and async_tx is being used to support device-to-memory operations. A channel that is
implementations were designed for offloading memory-to-memory performing these operations cannot, for many platform specific reasons,
operations; however, there are some capabilities of the dmaengine layer be shared. For these cases the dma_request_channel() interface is
that can be used for platform-specific channel management. provided.
Platform-specific constraints can be handled by registering the
application as a 'dma_client' and implementing a 'dma_event_callback' to The interface is:
apply a filter to the available channels in the system. Before showing struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
how to implement a custom dma_event callback some background of dma_filter_fn filter_fn,
dmaengine's client support is required. void *filter_param);
The following routines in dmaengine support multiple clients requesting Where dma_filter_fn is defined as:
use of a channel: typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
- dma_async_client_register(struct dma_client *client)
- dma_async_client_chan_request(struct dma_client *client) When the optional 'filter_fn' parameter is set to NULL
dma_request_channel simply returns the first channel that satisfies the
dma_async_client_register takes a pointer to an initialized dma_client capability mask. Otherwise, when the mask parameter is insufficient for
structure. It expects that the 'event_callback' and 'cap_mask' fields specifying the necessary channel, the filter_fn routine can be used to
are already initialized. disposition the available channels in the system. The filter_fn routine
is called once for each free channel in the system. Upon seeing a
dma_async_client_chan_request triggers dmaengine to notify the client of suitable channel filter_fn returns DMA_ACK which flags that channel to
all channels that satisfy the capability mask. It is up to the client's be the return value from dma_request_channel. A channel allocated via
event_callback routine to track how many channels the client needs and this interface is exclusive to the caller, until dma_release_channel()
how many it is currently using. The dma_event_callback routine returns a is called.
dma_state_client code to let dmaengine know the status of the
allocation. 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
Below is the example of how to extend this functionality for initialization time if it is known that a channel will always be
platform-specific filtering of the available channels beyond the private. Alternatively, it is set when dma_request_channel() finds an
standard capability mask: unused "public" channel.
static enum dma_state_client A couple caveats to note when implementing a driver and consumer:
my_dma_client_callback(struct dma_client *client, 1/ Once a channel has been privately allocated it will no longer be
struct dma_chan *chan, enum dma_state state) considered by the general-purpose allocator even after a call to
{ dma_release_channel().
struct dma_device *dma_dev; 2/ Since capabilities are specified at the device level a dma_device
struct my_platform_specific_dma *plat_dma_dev; with multiple channels will either have all channels public, or all
channels private.
dma_dev = chan->device;
plat_dma_dev = container_of(dma_dev,
struct my_platform_specific_dma,
dma_dev);
if (!plat_dma_dev->platform_specific_capability)
return DMA_DUP;
. . .
}
5 SOURCE 5 SOURCE
include/linux/dmaengine.h: core header file for DMA drivers and clients
include/linux/dmaengine.h: core header file for DMA drivers and api users
drivers/dma/dmaengine.c: offload engine channel management routines drivers/dma/dmaengine.c: offload engine channel management routines
drivers/dma/: location for offload engine drivers drivers/dma/: location for offload engine drivers
include/linux/async_tx.h: core header file for the async_tx api include/linux/async_tx.h: core header file for the async_tx api
......
See Documentation/crypto/async-tx-api.txt
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment