From ff39988abd70bcd1b14a4c81f2d102e67b8db580 Mon Sep 17 00:00:00 2001 From: Siva Yerramreddy Date: Tue, 29 Sep 2015 18:09:37 -0700 Subject: [PATCH] dma: Add support to program MIC x100 status descriptiors The MIC X100 DMA engine has a special status descriptor which writes an 8 byte value to a destination location. This is used to signal completion of all DMA descriptors prior to the status descriptor. This patch add a new DMA engine API which enables updating a destination address with an 8 byte immediate data value. Reviewed-by: Nikhil Rao Reviewed-by: Ashutosh Dixit Signed-off-by: Lawrynowicz, Jacek Signed-off-by: Sudeep Dutt Signed-off-by: Siva Yerramreddy Signed-off-by: Greg Kroah-Hartman --- drivers/dma/mic_x100_dma.c | 39 +++++++++++++++++++++++++++++++++++++- include/linux/dmaengine.h | 4 ++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c index 74d9db05a5ad..068e920ecb68 100644 --- a/drivers/dma/mic_x100_dma.c +++ b/drivers/dma/mic_x100_dma.c @@ -193,8 +193,16 @@ static void mic_dma_prog_intr(struct mic_dma_chan *ch) static int mic_dma_do_dma(struct mic_dma_chan *ch, int flags, dma_addr_t src, dma_addr_t dst, size_t len) { - if (-ENOMEM == mic_dma_prog_memcpy_desc(ch, src, dst, len)) + if (len && -ENOMEM == mic_dma_prog_memcpy_desc(ch, src, dst, len)) { return -ENOMEM; + } else { + /* 3 is the maximum number of status descriptors */ + int ret = mic_dma_avail_desc_ring_space(ch, 3); + + if (ret < 0) + return ret; + } + /* Above mic_dma_prog_memcpy_desc() makes sure we have enough space */ if (flags & DMA_PREP_FENCE) { mic_dma_prep_status_desc(&ch->desc_ring[ch->head], 0, @@ -270,6 +278,33 @@ allocate_tx(struct mic_dma_chan *ch) return tx; } +/* Program a status descriptor with dst as address and value to be written */ +static struct dma_async_tx_descriptor * +mic_dma_prep_status_lock(struct dma_chan *ch, dma_addr_t dst, u64 src_val, + unsigned long flags) +{ + struct mic_dma_chan *mic_ch = to_mic_dma_chan(ch); + int result; + + spin_lock(&mic_ch->prep_lock); + result = mic_dma_avail_desc_ring_space(mic_ch, 4); + if (result < 0) + goto error; + mic_dma_prep_status_desc(&mic_ch->desc_ring[mic_ch->head], src_val, dst, + false); + mic_dma_hw_ring_inc_head(mic_ch); + result = mic_dma_do_dma(mic_ch, flags, 0, 0, 0); + if (result < 0) + goto error; + + return allocate_tx(mic_ch); +error: + dev_err(mic_dma_ch_to_device(mic_ch), + "Error enqueueing dma status descriptor, error=%d\n", result); + spin_unlock(&mic_ch->prep_lock); + return NULL; +} + /* * Prepare a memcpy descriptor to be added to the ring. * Note that the temporary descriptor adds an extra overhead of copying the @@ -587,6 +622,8 @@ static int mic_dma_register_dma_device(struct mic_dma_device *mic_dma_dev, mic_dma_free_chan_resources; mic_dma_dev->dma_dev.device_tx_status = mic_dma_tx_status; mic_dma_dev->dma_dev.device_prep_dma_memcpy = mic_dma_prep_memcpy_lock; + mic_dma_dev->dma_dev.device_prep_dma_imm_data = + mic_dma_prep_status_lock; mic_dma_dev->dma_dev.device_prep_dma_interrupt = mic_dma_prep_interrupt_lock; mic_dma_dev->dma_dev.device_issue_pending = mic_dma_issue_pending; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 7ea9184eaa13..c47c68e535e8 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -645,6 +645,7 @@ enum dmaengine_alignment { * The function takes a buffer of size buf_len. The callback function will * be called after period_len bytes have been transferred. * @device_prep_interleaved_dma: Transfer expression in a generic way. + * @device_prep_dma_imm_data: DMA's 8 byte immediate data to the dst address * @device_config: Pushes a new configuration to a channel, return 0 or an error * code * @device_pause: Pauses any transfer happening on a channel. Returns @@ -727,6 +728,9 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)( struct dma_chan *chan, struct dma_interleaved_template *xt, unsigned long flags); + struct dma_async_tx_descriptor *(*device_prep_dma_imm_data)( + struct dma_chan *chan, dma_addr_t dst, u64 data, + unsigned long flags); int (*device_config)(struct dma_chan *chan, struct dma_slave_config *config); -- 2.20.1