Skip to content

Commit 4db8fd3

Browse files
Peter Ujfalusivinodkoul
authored andcommitted
dmaengine: Add metadata_ops for dma_async_tx_descriptor
The metadata is best described as side band data or parameters traveling alongside the data DMAd by the DMA engine. It is data which is understood by the peripheral and the peripheral driver only, the DMA engine see it only as data block and it is not interpreting it in any way. The metadata can be different per descriptor as it is a parameter for the data being transferred. If the DMA supports per descriptor metadata it can implement the attach, get_ptr/set_len callbacks. Client drivers must only use either attach or get_ptr/set_len to avoid misconfiguration. Client driver can check if a given metadata mode is supported by the channel during probe time with dmaengine_is_metadata_mode_supported(chan, DESC_METADATA_CLIENT); dmaengine_is_metadata_mode_supported(chan, DESC_METADATA_ENGINE); and based on this information can use either mode. Wrappers are also added for the metadata_ops. To be used in DESC_METADATA_CLIENT mode: dmaengine_desc_attach_metadata() To be used in DESC_METADATA_ENGINE mode: dmaengine_desc_get_metadata_ptr() dmaengine_desc_set_metadata_len() Signed-off-by: Peter Ujfalusi <[email protected]> Reviewed-by: Tero Kristo <[email protected]> Tested-by: Keerthy <[email protected]> Reviewed-by: Grygorii Strashko <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Vinod Koul <[email protected]>
1 parent 7d083ae commit 4db8fd3

File tree

2 files changed

+185
-0
lines changed

2 files changed

+185
-0
lines changed

drivers/dma/dmaengine.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,79 @@ void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx,
13481348
}
13491349
EXPORT_SYMBOL(dma_async_tx_descriptor_init);
13501350

1351+
static inline int desc_check_and_set_metadata_mode(
1352+
struct dma_async_tx_descriptor *desc, enum dma_desc_metadata_mode mode)
1353+
{
1354+
/* Make sure that the metadata mode is not mixed */
1355+
if (!desc->desc_metadata_mode) {
1356+
if (dmaengine_is_metadata_mode_supported(desc->chan, mode))
1357+
desc->desc_metadata_mode = mode;
1358+
else
1359+
return -ENOTSUPP;
1360+
} else if (desc->desc_metadata_mode != mode) {
1361+
return -EINVAL;
1362+
}
1363+
1364+
return 0;
1365+
}
1366+
1367+
int dmaengine_desc_attach_metadata(struct dma_async_tx_descriptor *desc,
1368+
void *data, size_t len)
1369+
{
1370+
int ret;
1371+
1372+
if (!desc)
1373+
return -EINVAL;
1374+
1375+
ret = desc_check_and_set_metadata_mode(desc, DESC_METADATA_CLIENT);
1376+
if (ret)
1377+
return ret;
1378+
1379+
if (!desc->metadata_ops || !desc->metadata_ops->attach)
1380+
return -ENOTSUPP;
1381+
1382+
return desc->metadata_ops->attach(desc, data, len);
1383+
}
1384+
EXPORT_SYMBOL_GPL(dmaengine_desc_attach_metadata);
1385+
1386+
void *dmaengine_desc_get_metadata_ptr(struct dma_async_tx_descriptor *desc,
1387+
size_t *payload_len, size_t *max_len)
1388+
{
1389+
int ret;
1390+
1391+
if (!desc)
1392+
return ERR_PTR(-EINVAL);
1393+
1394+
ret = desc_check_and_set_metadata_mode(desc, DESC_METADATA_ENGINE);
1395+
if (ret)
1396+
return ERR_PTR(ret);
1397+
1398+
if (!desc->metadata_ops || !desc->metadata_ops->get_ptr)
1399+
return ERR_PTR(-ENOTSUPP);
1400+
1401+
return desc->metadata_ops->get_ptr(desc, payload_len, max_len);
1402+
}
1403+
EXPORT_SYMBOL_GPL(dmaengine_desc_get_metadata_ptr);
1404+
1405+
int dmaengine_desc_set_metadata_len(struct dma_async_tx_descriptor *desc,
1406+
size_t payload_len)
1407+
{
1408+
int ret;
1409+
1410+
if (!desc)
1411+
return -EINVAL;
1412+
1413+
ret = desc_check_and_set_metadata_mode(desc, DESC_METADATA_ENGINE);
1414+
if (ret)
1415+
return ret;
1416+
1417+
if (!desc->metadata_ops || !desc->metadata_ops->set_len)
1418+
return -ENOTSUPP;
1419+
1420+
return desc->metadata_ops->set_len(desc, payload_len);
1421+
}
1422+
EXPORT_SYMBOL_GPL(dmaengine_desc_set_metadata_len);
1423+
13511424
/* dma_wait_for_async_tx - spin wait for a transaction to complete
13521425
* @tx: in-flight transaction to wait on
13531426
*/

include/linux/dmaengine.h

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,62 @@ typedef struct { DECLARE_BITMAP(bits, DMA_TX_TYPE_END); } dma_cap_mask_t;
219219
* @bytes_transferred: byte counter
220220
*/
221221

222+
/**
223+
* enum dma_desc_metadata_mode - per descriptor metadata mode types supported
224+
* @DESC_METADATA_CLIENT - the metadata buffer is allocated/provided by the
225+
* client driver and it is attached (via the dmaengine_desc_attach_metadata()
226+
* helper) to the descriptor.
227+
*
228+
* Client drivers interested to use this mode can follow:
229+
* - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM:
230+
* 1. prepare the descriptor (dmaengine_prep_*)
231+
* construct the metadata in the client's buffer
232+
* 2. use dmaengine_desc_attach_metadata() to attach the buffer to the
233+
* descriptor
234+
* 3. submit the transfer
235+
* - DMA_DEV_TO_MEM:
236+
* 1. prepare the descriptor (dmaengine_prep_*)
237+
* 2. use dmaengine_desc_attach_metadata() to attach the buffer to the
238+
* descriptor
239+
* 3. submit the transfer
240+
* 4. when the transfer is completed, the metadata should be available in the
241+
* attached buffer
242+
*
243+
* @DESC_METADATA_ENGINE - the metadata buffer is allocated/managed by the DMA
244+
* driver. The client driver can ask for the pointer, maximum size and the
245+
* currently used size of the metadata and can directly update or read it.
246+
* dmaengine_desc_get_metadata_ptr() and dmaengine_desc_set_metadata_len() is
247+
* provided as helper functions.
248+
*
249+
* Note: the metadata area for the descriptor is no longer valid after the
250+
* transfer has been completed (valid up to the point when the completion
251+
* callback returns if used).
252+
*
253+
* Client drivers interested to use this mode can follow:
254+
* - DMA_MEM_TO_DEV / DEV_MEM_TO_MEM:
255+
* 1. prepare the descriptor (dmaengine_prep_*)
256+
* 2. use dmaengine_desc_get_metadata_ptr() to get the pointer to the engine's
257+
* metadata area
258+
* 3. update the metadata at the pointer
259+
* 4. use dmaengine_desc_set_metadata_len() to tell the DMA engine the amount
260+
* of data the client has placed into the metadata buffer
261+
* 5. submit the transfer
262+
* - DMA_DEV_TO_MEM:
263+
* 1. prepare the descriptor (dmaengine_prep_*)
264+
* 2. submit the transfer
265+
* 3. on transfer completion, use dmaengine_desc_get_metadata_ptr() to get the
266+
* pointer to the engine's metadata area
267+
* 4. Read out the metadata from the pointer
268+
*
269+
* Note: the two mode is not compatible and clients must use one mode for a
270+
* descriptor.
271+
*/
272+
enum dma_desc_metadata_mode {
273+
DESC_METADATA_NONE = 0,
274+
DESC_METADATA_CLIENT = BIT(0),
275+
DESC_METADATA_ENGINE = BIT(1),
276+
};
277+
222278
struct dma_chan_percpu {
223279
/* stats */
224280
unsigned long memcpy_count;
@@ -475,6 +531,18 @@ struct dmaengine_unmap_data {
475531
dma_addr_t addr[0];
476532
};
477533

534+
struct dma_async_tx_descriptor;
535+
536+
struct dma_descriptor_metadata_ops {
537+
int (*attach)(struct dma_async_tx_descriptor *desc, void *data,
538+
size_t len);
539+
540+
void *(*get_ptr)(struct dma_async_tx_descriptor *desc,
541+
size_t *payload_len, size_t *max_len);
542+
int (*set_len)(struct dma_async_tx_descriptor *desc,
543+
size_t payload_len);
544+
};
545+
478546
/**
479547
* struct dma_async_tx_descriptor - async transaction descriptor
480548
* ---dma generic offload fields---
@@ -488,6 +556,11 @@ struct dmaengine_unmap_data {
488556
* descriptor pending. To be pushed on .issue_pending() call
489557
* @callback: routine to call after this operation is complete
490558
* @callback_param: general parameter to pass to the callback routine
559+
* @desc_metadata_mode: core managed metadata mode to protect mixed use of
560+
* DESC_METADATA_CLIENT or DESC_METADATA_ENGINE. Otherwise
561+
* DESC_METADATA_NONE
562+
* @metadata_ops: DMA driver provided metadata mode ops, need to be set by the
563+
* DMA driver if metadata mode is supported with the descriptor
491564
* ---async_tx api specific fields---
492565
* @next: at completion submit this descriptor
493566
* @parent: pointer to the next level up in the dependency chain
@@ -504,6 +577,8 @@ struct dma_async_tx_descriptor {
504577
dma_async_tx_callback_result callback_result;
505578
void *callback_param;
506579
struct dmaengine_unmap_data *unmap;
580+
enum dma_desc_metadata_mode desc_metadata_mode;
581+
struct dma_descriptor_metadata_ops *metadata_ops;
507582
#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH
508583
struct dma_async_tx_descriptor *next;
509584
struct dma_async_tx_descriptor *parent;
@@ -666,6 +741,7 @@ struct dma_filter {
666741
* @global_node: list_head for global dma_device_list
667742
* @filter: information for device/slave to filter function/param mapping
668743
* @cap_mask: one or more dma_capability flags
744+
* @desc_metadata_modes: supported metadata modes by the DMA device
669745
* @max_xor: maximum number of xor sources, 0 if no capability
670746
* @max_pq: maximum number of PQ sources and PQ-continue capability
671747
* @copy_align: alignment shift for memcpy operations
@@ -733,6 +809,7 @@ struct dma_device {
733809
struct list_head global_node;
734810
struct dma_filter filter;
735811
dma_cap_mask_t cap_mask;
812+
enum dma_desc_metadata_mode desc_metadata_modes;
736813
unsigned short max_xor;
737814
unsigned short max_pq;
738815
enum dmaengine_alignment copy_align;
@@ -910,6 +987,41 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memcpy(
910987
len, flags);
911988
}
912989

990+
static inline bool dmaengine_is_metadata_mode_supported(struct dma_chan *chan,
991+
enum dma_desc_metadata_mode mode)
992+
{
993+
if (!chan)
994+
return false;
995+
996+
return !!(chan->device->desc_metadata_modes & mode);
997+
}
998+
999+
#ifdef CONFIG_DMA_ENGINE
1000+
int dmaengine_desc_attach_metadata(struct dma_async_tx_descriptor *desc,
1001+
void *data, size_t len);
1002+
void *dmaengine_desc_get_metadata_ptr(struct dma_async_tx_descriptor *desc,
1003+
size_t *payload_len, size_t *max_len);
1004+
int dmaengine_desc_set_metadata_len(struct dma_async_tx_descriptor *desc,
1005+
size_t payload_len);
1006+
#else /* CONFIG_DMA_ENGINE */
1007+
static inline int dmaengine_desc_attach_metadata(
1008+
struct dma_async_tx_descriptor *desc, void *data, size_t len)
1009+
{
1010+
return -EINVAL;
1011+
}
1012+
static inline void *dmaengine_desc_get_metadata_ptr(
1013+
struct dma_async_tx_descriptor *desc, size_t *payload_len,
1014+
size_t *max_len)
1015+
{
1016+
return NULL;
1017+
}
1018+
static inline int dmaengine_desc_set_metadata_len(
1019+
struct dma_async_tx_descriptor *desc, size_t payload_len)
1020+
{
1021+
return -EINVAL;
1022+
}
1023+
#endif /* CONFIG_DMA_ENGINE */
1024+
9131025
/**
9141026
* dmaengine_terminate_all() - Terminate all active DMA transfers
9151027
* @chan: The channel for which to terminate the transfers

0 commit comments

Comments
 (0)