Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+44 −52
Original line number Diff line number Diff line
@@ -13,9 +13,9 @@
3.6 Constraints
3.7 Example

4 DRIVER DEVELOPER NOTES
4 DMAENGINE DRIVER DEVELOPER NOTES
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

@@ -150,6 +150,7 @@ 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:
@@ -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
   handle submission of dependent operations

4.2 "My application needs finer control of hardware channels"
This requirement seems to arise from cases where a DMA engine driver is
trying to support device-to-memory DMA.  The dmaengine and async_tx
implementations were designed for offloading memory-to-memory
operations; however, there are some capabilities of the dmaengine layer
that can be used for platform-specific channel management.
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
use of a channel:
- dma_async_client_register(struct dma_client *client)
- dma_async_client_chan_request(struct dma_client *client)

dma_async_client_register takes a pointer to an initialized dma_client
structure.  It expects that the 'event_callback' and 'cap_mask' fields
are already initialized.

dma_async_client_chan_request triggers dmaengine to notify the client of
all channels that satisfy the capability mask.  It is up to the client's
event_callback routine to track how many channels the client needs and
how many it is currently using.  The dma_event_callback routine returns a
dma_state_client code to let dmaengine know the status of the
allocation.

Below is the example of how to extend this functionality for
platform-specific filtering of the available channels beyond the
standard capability mask:

static enum dma_state_client
my_dma_client_callback(struct dma_client *client,
			struct dma_chan *chan, enum dma_state state)
{
	struct dma_device *dma_dev;
	struct my_platform_specific_dma *plat_dma_dev;
	
	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;

	. . .
}
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 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/: location for offload engine drivers
include/linux/async_tx.h: core header file for the async_tx api
+1 −0
Original line number Diff line number Diff line
See Documentation/crypto/async-tx-api.txt