[PATCH v2 1/1] dmaengine: qcom: bam_dma: Add support for metadata

From: Sireesh Kodali
Date: Thu Oct 27 2022 - 01:20:59 EST


From: Vladimir Lypak <vladimir.lypak@xxxxxxxxx>

Add client metadata support for receiving information about transfers.
Only type of metadata implemented is amount of transferred bytes. This
can be used to know how much data is actually received if information
transferred doesn't contain header with size or is aggregated.

Signed-off-by: Vladimir Lypak <vladimir.lypak@xxxxxxxxx>
Signed-off-by: Sireesh Kodali <sireeshkodali1@xxxxxxxxx>
---
drivers/dma/qcom/bam_dma.c | 57 ++++++++++++++++++++++++++++++++
include/linux/dma/qcom_bam_dma.h | 8 +++++
2 files changed, 65 insertions(+)

diff --git a/drivers/dma/qcom/bam_dma.c b/drivers/dma/qcom/bam_dma.c
index 3135a3e4a167..264a9a2e199f 100644
--- a/drivers/dma/qcom/bam_dma.c
+++ b/drivers/dma/qcom/bam_dma.c
@@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
+#include <linux/dma/qcom_bam_dma.h>
#include <linux/scatterlist.h>
#include <linux/device.h>
#include <linux/platform_device.h>
@@ -70,6 +71,7 @@ struct bam_async_desc {
u16 flags;

struct bam_desc_hw *curr_desc;
+ struct bam_dma_metadata *metadata;

/* list node for the desc in the bam_chan list of descriptors */
struct list_head desc_node;
@@ -418,6 +420,52 @@ static inline void __iomem *bam_addr(struct bam_device *bdev, u32 pipe,
r.ee_mult * bdev->ee;
}

+/**
+ * bam_update_metadata - update metadata buffer
+ * @bchan: BAM channel to read metadata from
+ * @async_desc: BAM async descriptior
+ *
+ * Updates metadata buffer (transfer size) based on values
+ * read from FIFO descriptors at bchan->head
+ */
+
+static inline void bam_update_metadata(struct bam_chan *bchan,
+ struct bam_async_desc *async_desc)
+{
+ unsigned int i, e, len = 0;
+ struct bam_desc_hw *fifo;
+
+ if (!async_desc->metadata)
+ return;
+
+ fifo = PTR_ALIGN(bchan->fifo_virt, sizeof(struct bam_desc_hw));
+ for (i = bchan->head, e = i + async_desc->xfer_len; i < e; i++)
+ len += fifo[i % MAX_DESCRIPTORS].size;
+
+ async_desc->metadata->xfer_len_bytes += len;
+}
+
+/**
+ * bam_attach_metadata - attach metadata buffer to the async descriptor
+ * @desc: async descriptor
+ * @data: buffer pointer
+ * @len: length of passed buffer
+ */
+static int bam_attach_metadata(struct dma_async_tx_descriptor *desc, void *data,
+ size_t len)
+{
+ struct bam_async_desc *async_desc;
+
+ if (!data || len != sizeof(struct bam_dma_metadata))
+ return -EINVAL;
+
+ async_desc = container_of(desc, struct bam_async_desc, vd.tx);
+ async_desc->metadata = data;
+ async_desc->metadata->xfer_len_bytes = 0;
+
+ return 0;
+}
+
/**
* bam_reset() - reset and initialize BAM registers
* @bdev: bam device
@@ -456,6 +504,10 @@ static void bam_reset(struct bam_device *bdev)
writel_relaxed(BAM_IRQ_MSK, bam_addr(bdev, 0, BAM_IRQ_SRCS_MSK_EE));
}

+static struct dma_descriptor_metadata_ops metadata_ops = {
+ .attach = bam_attach_metadata,
+};
+
/**
* bam_reset_channel - Reset individual BAM DMA channel
* @bchan: bam channel
@@ -714,6 +766,8 @@ static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
} while (remainder > 0);
}

+ async_desc->vd.tx.metadata_ops = &metadata_ops;
+
return vchan_tx_prep(&bchan->vc, &async_desc->vd, flags);
}

@@ -867,6 +921,8 @@ static u32 process_channel_irqs(struct bam_device *bdev)
if (avail < async_desc->xfer_len)
break;

+ bam_update_metadata(bchan, async_desc);
+
/* manage FIFO */
bchan->head += async_desc->xfer_len;
bchan->head %= MAX_DESCRIPTORS;
@@ -1347,6 +1403,7 @@ static int bam_dma_probe(struct platform_device *pdev)
bdev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
bdev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
bdev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ bdev->common.desc_metadata_modes = DESC_METADATA_CLIENT;
bdev->common.device_alloc_chan_resources = bam_alloc_chan;
bdev->common.device_free_chan_resources = bam_free_chan;
bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
diff --git a/include/linux/dma/qcom_bam_dma.h b/include/linux/dma/qcom_bam_dma.h
index 68fc0e643b1b..8168b0573f45 100644
--- a/include/linux/dma/qcom_bam_dma.h
+++ b/include/linux/dma/qcom_bam_dma.h
@@ -8,6 +8,14 @@

#include <asm/byteorder.h>

+/*
+ * This data type is used as client metadata buffer in bam driver.
+ */
+struct bam_dma_metadata {
+ /* Actual number of bytes transferred by hardware */
+ size_t xfer_len_bytes;
+};
+
/*
* This data type corresponds to the native Command Element
* supported by BAM DMA Engine.
--
2.38.1