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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
Dan Williams 2009-01-05 17:14:31 -07:00
parent fe0bdec68b
commit 28405d8d9c
2 changed files with 40 additions and 47 deletions

View file

@ -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
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:
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
apply a filter to the available channels in the system. Before showing
how to implement a custom dma_event callback some background of
dmaengine's client support is required.
The following routines in dmaengine support multiple clients requesting The interface is:
use of a channel: struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
- dma_async_client_register(struct dma_client *client) dma_filter_fn filter_fn,
- dma_async_client_chan_request(struct dma_client *client) void *filter_param);
dma_async_client_register takes a pointer to an initialized dma_client Where dma_filter_fn is defined as:
structure. It expects that the 'event_callback' and 'cap_mask' fields typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
are already initialized.
dma_async_client_chan_request triggers dmaengine to notify the client of When the optional 'filter_fn' parameter is set to NULL
all channels that satisfy the capability mask. It is up to the client's dma_request_channel simply returns the first channel that satisfies the
event_callback routine to track how many channels the client needs and capability mask. Otherwise, when the mask parameter is insufficient for
how many it is currently using. The dma_event_callback routine returns a specifying the necessary channel, the filter_fn routine can be used to
dma_state_client code to let dmaengine know the status of the disposition the available channels in the system. The filter_fn routine
allocation. 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.
Below is the example of how to extend this functionality for The DMA_PRIVATE capability flag is used to tag dma devices that should
platform-specific filtering of the available channels beyond the not be used by the general-purpose allocator. It can be set at
standard capability mask: 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.
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

View file

@ -0,0 +1 @@
See Documentation/crypto/async-tx-api.txt