* [1/5] dma: tegra: avoid overflow of byte tracking
From: Jon Hunter @ 2018-11-22 8:27 UTC (permalink / raw)
To: Ben Dooks, dan.j.williams, vkoul, dmaengine; +Cc: ldewangan, linux-tegra
On 21/11/2018 16:13, Ben Dooks wrote:
> The dma_desc->bytes_transferred counter tracks the number of bytes
> moved by the DMA channel. This is then used to calculate the information
> passed back in the in the tegra_dma_tx_status callback, which is usually
> fine.
>
> When the DMA channel is configured as continous, then the bytes_transferred
> counter will increase over time and eventually overflow to become negative
> so the residue count will become invalid and the ALSA sound-dma code will
> report invalid hardware pointer values to the application. This results in
> some users becoming confused about the playout position and putting audio
> data in the wrong place.
>
> To fix this issue, always ensure the bytes_transferred field is modulo the
> size of the request. We only do this for the case of the cyclic transfer
> done ISR as anyone attempting to move 2GiB of DMA data in one transfer
> is unlikely.
>
> Note, we don't fix the issue that we should /never/ transfer a negative
> number of bytes so we could make those fields unsigned.
>
> Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
> ---
> drivers/dma/tegra20-apb-dma.c | 5 ++++-
> 1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
> index 9a558e30c461..8219ab88a507 100644
> --- a/drivers/dma/tegra20-apb-dma.c
> +++ b/drivers/dma/tegra20-apb-dma.c
> @@ -636,7 +636,10 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc,
>
> sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node);
> dma_desc = sgreq->dma_desc;
> - dma_desc->bytes_transferred += sgreq->req_len;
> + /* if we dma for long enough the transfer count will wrap */
> + dma_desc->bytes_transferred =
> + (dma_desc->bytes_transferred + sgreq->req_len) %
> + dma_desc->bytes_requested;
>
> /* Callback need to be call */
> if (!dma_desc->cb_count)
Acked-by: Jon Hunter <jonathanh@nvidia.com>
Thanks!
Jon
^ permalink raw reply
* [5/5] dma: tegra: add tracepoints to driver
From: Steven Rostedt @ 2018-11-21 17:21 UTC (permalink / raw)
To: Ben Dooks
Cc: dan.j.williams, vkoul, dmaengine, ldewangan, linux-tegra,
jonathanh, Ingo Molnar
On Wed, 21 Nov 2018 16:13:23 +0000
Ben Dooks <ben.dooks@codethink.co.uk> wrote:
> Add some trace-points to the driver to allow for debuging via the
> trace pipe.
>
> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
From a tracing perspective I see nothing wrong with this patch.
Reviewed-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-- Steve
> ---
> Fixes since v1:
> - take copy of dmachan name instead of pointer to device
>
> Fixes since v2:
> - finish off Steven's review comments
> - fix saving the dma channel name
> - use txstate as argument to trace_tegra_dma_tx_status()
> - fix type of dma_cookie to dma_cookie_t
>
> Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
> Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
^ permalink raw reply
* [5/5] dma: tegra: add tracepoints to driver
From: Ben Dooks @ 2018-11-21 16:13 UTC (permalink / raw)
To: dan.j.williams, vkoul, dmaengine
Cc: ldewangan, linux-tegra, jonathanh, Ben Dooks, Ingo Molnar,
Steven Rostedt
Add some trace-points to the driver to allow for debuging via the
trace pipe.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
Fixes since v1:
- take copy of dmachan name instead of pointer to device
Fixes since v2:
- finish off Steven's review comments
- fix saving the dma channel name
- use txstate as argument to trace_tegra_dma_tx_status()
- fix type of dma_cookie to dma_cookie_t
Cc: Ingo Molnar <mingo@redhat.com> (maintainer:TRACING)
Cc: Steven Rostedt <rostedt@goodmis.org> (maintainer:TRACING)
---
drivers/dma/tegra20-apb-dma.c | 7 ++++
include/trace/events/tegra_apb_dma.h | 61 ++++++++++++++++++++++++++++
2 files changed, 68 insertions(+)
create mode 100644 include/trace/events/tegra_apb_dma.h
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index c60c3f7cad5f..659b49bf6fdb 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -38,6 +38,9 @@
#include "dmaengine.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/tegra_apb_dma.h>
+
#define TEGRA_APBDMA_GENERAL 0x0
#define TEGRA_APBDMA_GENERAL_ENABLE BIT(31)
@@ -672,6 +675,8 @@ static void tegra_dma_tasklet(unsigned long data)
dmaengine_desc_get_callback(&dma_desc->txd, &cb);
cb_count = dma_desc->cb_count;
dma_desc->cb_count = 0;
+ trace_tegra_dma_complete_cb(&tdc->dma_chan, cb_count,
+ cb.callback);
spin_unlock_irqrestore(&tdc->lock, flags);
while (cb_count--)
dmaengine_desc_callback_invoke(&cb, NULL);
@@ -688,6 +693,7 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
spin_lock_irqsave(&tdc->lock, flags);
+ trace_tegra_dma_isr(&tdc->dma_chan, irq);
status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
@@ -846,6 +852,7 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
dma_set_residue(txstate, residual);
}
+ trace_tegra_dma_tx_status(&tdc->dma_chan, cookie, txstate);
spin_unlock_irqrestore(&tdc->lock, flags);
return ret;
}
diff --git a/include/trace/events/tegra_apb_dma.h b/include/trace/events/tegra_apb_dma.h
new file mode 100644
index 000000000000..0818f6286110
--- /dev/null
+++ b/include/trace/events/tegra_apb_dma.h
@@ -0,0 +1,61 @@
+#if !defined(_TRACE_TEGRA_APB_DMA_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_TEGRA_APM_DMA_H
+
+#include <linux/tracepoint.h>
+#include <linux/dmaengine.h>
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM tegra_apb_dma
+
+TRACE_EVENT(tegra_dma_tx_status,
+ TP_PROTO(struct dma_chan *dc, dma_cookie_t cookie, struct dma_tx_state *state),
+ TP_ARGS(dc, cookie, state),
+ TP_STRUCT__entry(
+ __string(chan, dev_name(&dc->dev->device))
+ __field(dma_cookie_t, cookie)
+ __field(__u32, residue)
+ ),
+ TP_fast_assign(
+ __assign_str(chan, dev_name(&dc->dev->device));
+ __entry->cookie = cookie;
+ __entry->residue = state ? state->residue : (u32)-1;
+ ),
+ TP_printk("channel %s: dma cookie %d, residue %u",
+ __get_str(chan), __entry->cookie, __entry->residue)
+);
+
+TRACE_EVENT(tegra_dma_complete_cb,
+ TP_PROTO(struct dma_chan *dc, int count, void *ptr),
+ TP_ARGS(dc, count, ptr),
+ TP_STRUCT__entry(
+ __string(chan, dev_name(&dc->dev->device))
+ __field(int, count)
+ __field(void *, ptr)
+ ),
+ TP_fast_assign(
+ __assign_str(chan, dev_name(&dc->dev->device));
+ __entry->count = count;
+ __entry->ptr = ptr;
+ ),
+ TP_printk("channel %s: done %d, ptr %p",
+ __get_str(chan), __entry->count, __entry->ptr)
+);
+
+TRACE_EVENT(tegra_dma_isr,
+ TP_PROTO(struct dma_chan *dc, int irq),
+ TP_ARGS(dc, irq),
+ TP_STRUCT__entry(
+ __string(chan, dev_name(&dc->dev->device))
+ __field(int, irq)
+ ),
+ TP_fast_assign(
+ __assign_str(chan, dev_name(&dc->dev->device));
+ __entry->irq = irq;
+ ),
+ TP_printk("%s: irq %d\n", __get_str(chan), __entry->irq)
+);
+
+#endif /* _TRACE_TEGRADMA_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
^ permalink raw reply related
* [4/5] dma: tegra: reduce channel name field size
From: Ben Dooks @ 2018-11-21 16:13 UTC (permalink / raw)
To: dan.j.williams, vkoul, dmaengine
Cc: ldewangan, linux-tegra, jonathanh, Ben Dooks
The name field is used for "apbdma.%d" which is rarely going to be
more than 10 bytes, so reduce the size from 30 to 12. This is only
being used by the interrupt registration, so is not critical to the
operation of the driver either.
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/dma/tegra20-apb-dma.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index ec8938a2ecab..c60c3f7cad5f 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -186,7 +186,7 @@ typedef void (*dma_isr_handler)(struct tegra_dma_channel *tdc,
/* tegra_dma_channel: Channel specific information */
struct tegra_dma_channel {
struct dma_chan dma_chan;
- char name[30];
+ char name[12];
bool config_init;
int id;
int irq;
^ permalink raw reply related
* [3/5] dma: tegra: fix incorrect case of DMA
From: Ben Dooks @ 2018-11-21 16:13 UTC (permalink / raw)
To: dan.j.williams, vkoul, dmaengine
Cc: ldewangan, linux-tegra, jonathanh, Ben Dooks
The use of Dma is annoying, since it is an acronym so should be all
upper case. Fix this throughout the driver.
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
Fixes since v1:
- Missing cases fixed as pointed out by Dmitry Osipenko
---
drivers/dma/tegra20-apb-dma.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index adfd918baedc..ec8938a2ecab 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -146,7 +146,7 @@ struct tegra_dma_channel_regs {
};
/*
- * tegra_dma_sg_req: Dma request details to configure hardware. This
+ * tegra_dma_sg_req: DMA request details to configure hardware. This
* contains the details for one transfer to configure DMA hw.
* The client's request for data transfer can be broken into multiple
* sub-transfer as per requester details and hw support.
@@ -574,7 +574,7 @@ static bool handle_continuous_head_request(struct tegra_dma_channel *tdc,
struct tegra_dma_sg_req *hsgreq = NULL;
if (list_empty(&tdc->pending_sg_req)) {
- dev_err(tdc2dev(tdc), "Dma is running without req\n");
+ dev_err(tdc2dev(tdc), "DMA is running without req\n");
tegra_dma_stop(tdc);
return false;
}
@@ -587,7 +587,7 @@ static bool handle_continuous_head_request(struct tegra_dma_channel *tdc,
hsgreq = list_first_entry(&tdc->pending_sg_req, typeof(*hsgreq), node);
if (!hsgreq->configured) {
tegra_dma_stop(tdc);
- dev_err(tdc2dev(tdc), "Error in dma transfer, aborting dma\n");
+ dev_err(tdc2dev(tdc), "Error in DMA transfer, aborting DMA\n");
tegra_dma_abort_all(tdc);
return false;
}
@@ -922,7 +922,7 @@ static int get_transfer_param(struct tegra_dma_channel *tdc,
return 0;
default:
- dev_err(tdc2dev(tdc), "Dma direction is not supported\n");
+ dev_err(tdc2dev(tdc), "DMA direction is not supported\n");
return -EINVAL;
}
return -EINVAL;
@@ -955,7 +955,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
enum dma_slave_buswidth slave_bw;
if (!tdc->config_init) {
- dev_err(tdc2dev(tdc), "dma channel is not configured\n");
+ dev_err(tdc2dev(tdc), "DMA channel is not configured\n");
return NULL;
}
if (sg_len < 1) {
@@ -988,7 +988,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
dma_desc = tegra_dma_desc_get(tdc);
if (!dma_desc) {
- dev_err(tdc2dev(tdc), "Dma descriptors not available\n");
+ dev_err(tdc2dev(tdc), "DMA descriptors not available\n");
return NULL;
}
INIT_LIST_HEAD(&dma_desc->tx_list);
@@ -1008,14 +1008,14 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
if ((len & 3) || (mem & 3) ||
(len > tdc->tdma->chip_data->max_dma_count)) {
dev_err(tdc2dev(tdc),
- "Dma length/memory address is not supported\n");
+ "DMA length/memory address is not supported\n");
tegra_dma_desc_put(tdc, dma_desc);
return NULL;
}
sg_req = tegra_dma_sg_req_get(tdc);
if (!sg_req) {
- dev_err(tdc2dev(tdc), "Dma sg-req not available\n");
+ dev_err(tdc2dev(tdc), "DMA sg-req not available\n");
tegra_dma_desc_put(tdc, dma_desc);
return NULL;
}
@@ -1090,7 +1090,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
* terminating the DMA.
*/
if (tdc->busy) {
- dev_err(tdc2dev(tdc), "Request not allowed when dma running\n");
+ dev_err(tdc2dev(tdc), "Request not allowed when DMA running\n");
return NULL;
}
@@ -1147,7 +1147,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
while (remain_len) {
sg_req = tegra_dma_sg_req_get(tdc);
if (!sg_req) {
- dev_err(tdc2dev(tdc), "Dma sg-req not available\n");
+ dev_err(tdc2dev(tdc), "DMA sg-req not available\n");
tegra_dma_desc_put(tdc, dma_desc);
return NULL;
}
^ permalink raw reply related
* [2/5] dma: tegra: make byte counters unsigned int
From: Ben Dooks @ 2018-11-21 16:13 UTC (permalink / raw)
To: dan.j.williams, vkoul, dmaengine
Cc: ldewangan, linux-tegra, jonathanh, Ben Dooks
The buffer byte request length and counter are declared as signed integers
but the values should never be below zero, so make these unsigned integers
instead.
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/dma/tegra20-apb-dma.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 8219ab88a507..adfd918baedc 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -155,7 +155,7 @@ struct tegra_dma_channel_regs {
*/
struct tegra_dma_sg_req {
struct tegra_dma_channel_regs ch_regs;
- int req_len;
+ unsigned int req_len;
bool configured;
bool last_sg;
struct list_head node;
@@ -169,8 +169,8 @@ struct tegra_dma_sg_req {
*/
struct tegra_dma_desc {
struct dma_async_tx_descriptor txd;
- int bytes_requested;
- int bytes_transferred;
+ unsigned int bytes_requested;
+ unsigned int bytes_transferred;
enum dma_status dma_status;
struct list_head node;
struct list_head tx_list;
^ permalink raw reply related
* [1/5] dma: tegra: avoid overflow of byte tracking
From: Ben Dooks @ 2018-11-21 16:13 UTC (permalink / raw)
To: dan.j.williams, vkoul, dmaengine
Cc: ldewangan, linux-tegra, jonathanh, Ben Dooks
The dma_desc->bytes_transferred counter tracks the number of bytes
moved by the DMA channel. This is then used to calculate the information
passed back in the in the tegra_dma_tx_status callback, which is usually
fine.
When the DMA channel is configured as continous, then the bytes_transferred
counter will increase over time and eventually overflow to become negative
so the residue count will become invalid and the ALSA sound-dma code will
report invalid hardware pointer values to the application. This results in
some users becoming confused about the playout position and putting audio
data in the wrong place.
To fix this issue, always ensure the bytes_transferred field is modulo the
size of the request. We only do this for the case of the cyclic transfer
done ISR as anyone attempting to move 2GiB of DMA data in one transfer
is unlikely.
Note, we don't fix the issue that we should /never/ transfer a negative
number of bytes so we could make those fields unsigned.
Reviewed-by: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
drivers/dma/tegra20-apb-dma.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 9a558e30c461..8219ab88a507 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -636,7 +636,10 @@ static void handle_cont_sngl_cycle_dma_done(struct tegra_dma_channel *tdc,
sgreq = list_first_entry(&tdc->pending_sg_req, typeof(*sgreq), node);
dma_desc = sgreq->dma_desc;
- dma_desc->bytes_transferred += sgreq->req_len;
+ /* if we dma for long enough the transfer count will wrap */
+ dma_desc->bytes_transferred =
+ (dma_desc->bytes_transferred + sgreq->req_len) %
+ dma_desc->bytes_requested;
/* Callback need to be call */
if (!dma_desc->cb_count)
^ permalink raw reply related
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Aaro Koskinen @ 2018-11-20 21:04 UTC (permalink / raw)
To: Peter Ujfalusi
Cc: vkoul, dan.j.williams, dmaengine, linux-kernel, tony, linux-omap,
rmk+kernel
Hi,
On Tue, Nov 20, 2018 at 09:28:37AM +0200, Peter Ujfalusi wrote:
> On 19/11/2018 20.46, Aaro Koskinen wrote:
> > On Mon, Nov 19, 2018 at 12:40:40PM +0200, Peter Ujfalusi wrote:
> >> When the channel is configured for slave operation the LCH_TYPE needs to be
> >> set to LCh-P. For memcpy channels the LCH_TYPE must be set to LCh-2D.
> >>
> >> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
> >
> > I don't have the documentation, but based on what omap_udc driver (still
> > using the legacy OMAP DMA API) does this seems to be correct.
>
> They are hard to fine, true. From the omap1710 TRM:
>
> Logical channel types (LCh types) supported are:
> - LCh-2D for nonsynchronized transfers (memory transfers, 1D and 2D)
> - LCh-P for synchronized transfers (mostly peripheral transfers)
> - LCh-PD similar to LCh-P but runs on a dedicated physical channel
> - LCh-G for graphical transfers/operations
> - LCh-D for display transfers
(I found a public document "OMAP5912 Multimedia Processor Direct
Memory Access (DMA) Support Reference Guide", documenting these; easy
to confuse with "OMAP5910 Dual-Core Processor System DMA Controller
Reference Guide".)
> Looking at other part it looks like hat LCH-2D channel mode can happily
> service a peripheral. LCH-P supports the same features as LCH-2D, but it
> lacks support for Single/Double-indexed addressing mode on the
> peripheral port side.
>
> So, this patch might not be needed at all. Can you test the omap_udc
> with s/OMAP_DMA_LCH_P/OMAP_DMA_LCH_2D
>
> If USB works, then we can just drop this patch.
Unfortunately omap_udc does not seem to work at all anymore with DMA on
my 770 setup. :-(
I had switched to PIO mode in 2015 since the WARNs about legacy DMA
API were too annoying and flooding the console. And now that I tried
using DMA again with g_ether, it doesn't work anymore. The device get's
recognized on host side, but no traffic goes through. Switching back to
PIO makes it to work again.
A.
^ permalink raw reply
* dmaengine: fix dmaengine_desc_callback_valid() doesn't check for callback_result
From: Radhey Shyam Pandey @ 2018-11-20 17:24 UTC (permalink / raw)
To: Andrea Merello, vkoul@kernel.org, dan.j.williams@intel.com,
dmaengine@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
> -----Original Message-----
> From: Andrea Merello <andrea.merello@gmail.com>
> Sent: Friday, November 16, 2018 7:26 PM
> To: vkoul@kernel.org; dan.j.williams@intel.com; dmaengine@vger.kernel.org
> Cc: linux-kernel@vger.kernel.org; Radhey Shyam Pandey
> <radheys@xilinx.com>; Andrea Merello <andrea.merello@gmail.com>
> Subject: [PATCH] dmaengine: fix dmaengine_desc_callback_valid() doesn't
> check for callback_result
>
> There are two flavors of DMA completion callbacks: callback() and
> callback_result(); the latter takes an additional parameter that carries
> result information.
>
> Most dmaengine helper functions that work with callbacks take care of both
> flavors i.e. dmaengine_desc_get_callback_invoke() first checks for
> callback_result() to be not NULL, and eventually it calls this one;
> otherwise it goes on checking for callback().
>
> It seems however that dmaengine_desc_callback_valid() does not care about
> callback_result(), and it returns false in case callback() is NULL but
> callback_result() is not; unless there is a (hidden to me) reason for doing
> so then I'd say this is wrong.
>
> I've hit this by using a DMA controller driver (xilinx_dma) that doesn't
> trigger any callback invocation unless dmaengine_desc_callback_valid()
> returns true, while I had only callback_result() implemented in my client
> driver (which AFAICT is always fine since dmaengine documentation says that
> callback() will be deprecated).
Thanks for the patch. In xilinx_dma driver call to _desc_callback_valid
can be safely removed as callback ptrs are anyway checked in invoke().
There is no much benefit in having redundant checks.
Related to dmaengine_desc_callback_valid extension will let Vinod comment.
>
> This patch fixes this by making dmaengine_desc_callback_valid() to return
> true in the said scenario.
>
> Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
> ---
> drivers/dma/dmaengine.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/dma/dmaengine.h b/drivers/dma/dmaengine.h
> index 501c0b063f85..0ba2c1f3c55d 100644
> --- a/drivers/dma/dmaengine.h
> +++ b/drivers/dma/dmaengine.h
> @@ -168,7 +168,7 @@ dmaengine_desc_get_callback_invoke(struct
> dma_async_tx_descriptor *tx,
> static inline bool
> dmaengine_desc_callback_valid(struct dmaengine_desc_callback *cb)
> {
> - return (cb->callback) ? true : false;
> + return (cb->callback || cb->callback_result);
> }
>
> #endif
> --
> 2.17.1
^ permalink raw reply
* [v1] dmaengine: Add mailing list address to the documentation
From: Jonathan Corbet @ 2018-11-20 16:29 UTC (permalink / raw)
To: Andy Shevchenko; +Cc: Vinod Koul, dmaengine
On Tue, 20 Nov 2018 15:15:33 +0200
Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> It's not the first time I've got a private email in regard to
> dmatest.c module.
>
> Motivate people, by adding a note, to send their questions
> to the mailing list instead
>
> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Applied, thanks.
jon
^ permalink raw reply
* [v6,7/7] dmaengine: xilinx_dma: Drop SG support for VDMA IP
From: Andrea Merello @ 2018-11-20 15:31 UTC (permalink / raw)
To: vkoul, dan.j.williams, michal.simek, appana.durga.rao, dmaengine
Cc: linux-arm-kernel, linux-kernel, robh+dt, mark.rutland, devicetree,
radhey.shyam.pandey, Andrea Merello
xilinx_vdma_start_transfer() is used only for VDMA IP, still it contains
conditional code on has_sg variable. has_sg is set only whenever the HW
does support SG mode, that is never true for VDMA IP.
This patch drops the never-taken branches.
Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
---
Changes in V4: introduced this patch in series
Changes in v5:
None
Changes in v6:
None
---
drivers/dma/xilinx/xilinx_dma.c | 84 +++++++++++++--------------------
1 file changed, 32 insertions(+), 52 deletions(-)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 41bd8caca09e..a37e28a43885 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -1100,6 +1100,8 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
struct xilinx_dma_tx_descriptor *desc, *tail_desc;
u32 reg, j;
struct xilinx_vdma_tx_segment *tail_segment;
+ struct xilinx_vdma_tx_segment *segment, *last = NULL;
+ int i = 0;
/* This function was invoked with lock held */
if (chan->err)
@@ -1119,14 +1121,6 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
tail_segment = list_last_entry(&tail_desc->segments,
struct xilinx_vdma_tx_segment, node);
- /*
- * If hardware is idle, then all descriptors on the running lists are
- * done, start new transfers
- */
- if (chan->has_sg)
- dma_ctrl_write(chan, XILINX_DMA_REG_CURDESC,
- desc->async_tx.phys);
-
/* Configure the hardware using info in the config structure */
if (chan->has_vflip) {
reg = dma_read(chan, XILINX_VDMA_REG_ENABLE_VERTICAL_FLIP);
@@ -1143,15 +1137,11 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
else
reg &= ~XILINX_DMA_DMACR_FRAMECNT_EN;
- /*
- * With SG, start with circular mode, so that BDs can be fetched.
- * In direct register mode, if not parking, enable circular mode
- */
- if (chan->has_sg || !config->park)
- reg |= XILINX_DMA_DMACR_CIRC_EN;
-
+ /* If not parking, enable circular mode */
if (config->park)
reg &= ~XILINX_DMA_DMACR_CIRC_EN;
+ else
+ reg |= XILINX_DMA_DMACR_CIRC_EN;
dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg);
@@ -1173,48 +1163,38 @@ static void xilinx_vdma_start_transfer(struct xilinx_dma_chan *chan)
return;
/* Start the transfer */
- if (chan->has_sg) {
- dma_ctrl_write(chan, XILINX_DMA_REG_TAILDESC,
- tail_segment->phys);
- list_splice_tail_init(&chan->pending_list, &chan->active_list);
- chan->desc_pendingcount = 0;
- } else {
- struct xilinx_vdma_tx_segment *segment, *last = NULL;
- int i = 0;
-
- if (chan->desc_submitcount < chan->num_frms)
- i = chan->desc_submitcount;
-
- list_for_each_entry(segment, &desc->segments, node) {
- if (chan->ext_addr)
- vdma_desc_write_64(chan,
- XILINX_VDMA_REG_START_ADDRESS_64(i++),
- segment->hw.buf_addr,
- segment->hw.buf_addr_msb);
- else
- vdma_desc_write(chan,
+ if (chan->desc_submitcount < chan->num_frms)
+ i = chan->desc_submitcount;
+
+ list_for_each_entry(segment, &desc->segments, node) {
+ if (chan->ext_addr)
+ vdma_desc_write_64(chan,
+ XILINX_VDMA_REG_START_ADDRESS_64(i++),
+ segment->hw.buf_addr,
+ segment->hw.buf_addr_msb);
+ else
+ vdma_desc_write(chan,
XILINX_VDMA_REG_START_ADDRESS(i++),
segment->hw.buf_addr);
- last = segment;
- }
-
- if (!last)
- return;
+ last = segment;
+ }
- /* HW expects these parameters to be same for one transaction */
- vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize);
- vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE,
- last->hw.stride);
- vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
+ if (!last)
+ return;
- chan->desc_submitcount++;
- chan->desc_pendingcount--;
- list_del(&desc->node);
- list_add_tail(&desc->node, &chan->active_list);
- if (chan->desc_submitcount == chan->num_frms)
- chan->desc_submitcount = 0;
- }
+ /* HW expects these parameters to be same for one transaction */
+ vdma_desc_write(chan, XILINX_DMA_REG_HSIZE, last->hw.hsize);
+ vdma_desc_write(chan, XILINX_DMA_REG_FRMDLY_STRIDE,
+ last->hw.stride);
+ vdma_desc_write(chan, XILINX_DMA_REG_VSIZE, last->hw.vsize);
+
+ chan->desc_submitcount++;
+ chan->desc_pendingcount--;
+ list_del(&desc->node);
+ list_add_tail(&desc->node, &chan->active_list);
+ if (chan->desc_submitcount == chan->num_frms)
+ chan->desc_submitcount = 0;
chan->idle = false;
}
^ permalink raw reply related
* [v6,6/7] dt-bindings: dmaengine: xilinx_dma: drop include-sg property
From: Andrea Merello @ 2018-11-20 15:31 UTC (permalink / raw)
To: vkoul, dan.j.williams, michal.simek, appana.durga.rao, dmaengine
Cc: linux-arm-kernel, linux-kernel, robh+dt, mark.rutland, devicetree,
radhey.shyam.pandey, Andrea Merello
This property is not needed anymore, because the driver now autodetects it.
Delete references in documentation.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Cc: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Reviewed-by: Rob Herring <robh@kernel.org>
---
Changes in v2:
- cc DT maintainer
Changes in v3:
- cc DT maintainerS/ML
Changes in v4:
None
Changes in v5:
None
Changes in v6:
Fix wrong property name in commit title
---
Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt | 3 ---
1 file changed, 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
index 2fce9fb4b270..93b6d961dd4f 100644
--- a/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
+++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
@@ -37,9 +37,6 @@ Required properties:
Required properties for VDMA:
- xlnx,num-fstores: Should be the number of framebuffers as configured in h/w.
-Optional properties:
-- xlnx,include-sg: Tells configured for Scatter-mode in
- the hardware.
Optional properties for AXI DMA:
- xlnx,sg-length-width: Should be set to the width in bits of the length
register as configured in h/w. Takes values {8...26}. If the property
^ permalink raw reply related
* [v6,5/7] dmaengine: xilinx_dma: autodetect whether the HW supports scatter-gather
From: Andrea Merello @ 2018-11-20 15:31 UTC (permalink / raw)
To: vkoul, dan.j.williams, michal.simek, appana.durga.rao, dmaengine
Cc: linux-arm-kernel, linux-kernel, robh+dt, mark.rutland, devicetree,
radhey.shyam.pandey, Andrea Merello
The AXIDMA and CDMA HW can be either direct-access or scatter-gather
version. These are SW incompatible.
The driver can handle both versions: a DT property was used to
tell the driver whether to assume the HW is in scatter-gather mode.
This patch makes the driver to autodetect this information. The DT
property is not required anymore.
No changes for VDMA.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Cc: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
---
Changes in v2:
- autodetect only in !VDMA case
Changes in v3:
- cc DT maintainers/ML
Changes in v4:
- fix typos in commit message
Changes in v5:
None
Changes in v6:
None
---
drivers/dma/xilinx/xilinx_dma.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 0716db61f1d0..41bd8caca09e 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -86,6 +86,7 @@
#define XILINX_DMA_DMASR_DMA_DEC_ERR BIT(6)
#define XILINX_DMA_DMASR_DMA_SLAVE_ERR BIT(5)
#define XILINX_DMA_DMASR_DMA_INT_ERR BIT(4)
+#define XILINX_DMA_DMASR_SG_MASK BIT(3)
#define XILINX_DMA_DMASR_IDLE BIT(1)
#define XILINX_DMA_DMASR_HALTED BIT(0)
#define XILINX_DMA_DMASR_DELAY_MASK GENMASK(31, 24)
@@ -412,7 +413,6 @@ struct xilinx_dma_config {
* @dev: Device Structure
* @common: DMA device structure
* @chan: Driver specific DMA channel
- * @has_sg: Specifies whether Scatter-Gather is present or not
* @mcdma: Specifies whether Multi-Channel is present or not
* @flush_on_fsync: Flush on frame sync
* @ext_addr: Indicates 64 bit addressing is supported by dma device
@@ -432,7 +432,6 @@ struct xilinx_dma_device {
struct device *dev;
struct dma_device common;
struct xilinx_dma_chan *chan[XILINX_DMA_MAX_CHANS_PER_DEVICE];
- bool has_sg;
bool mcdma;
u32 flush_on_fsync;
bool ext_addr;
@@ -2417,7 +2416,6 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
chan->dev = xdev->dev;
chan->xdev = xdev;
- chan->has_sg = xdev->has_sg;
chan->desc_pendingcount = 0x0;
chan->ext_addr = xdev->ext_addr;
/* This variable ensures that descriptors are not
@@ -2517,6 +2515,15 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev,
chan->stop_transfer = xilinx_dma_stop_transfer;
}
+ /* check if SG is enabled (only for AXIDMA and CDMA) */
+ if (xdev->dma_config->dmatype != XDMA_TYPE_VDMA) {
+ if (dma_ctrl_read(chan, XILINX_DMA_REG_DMASR) &
+ XILINX_DMA_DMASR_SG_MASK)
+ chan->has_sg = true;
+ dev_dbg(chan->dev, "ch %d: SG %s\n", chan->id,
+ chan->has_sg ? "enabled" : "disabled");
+ }
+
/* Initialize the tasklet */
tasklet_init(&chan->tasklet, xilinx_dma_do_tasklet,
(unsigned long)chan);
@@ -2655,7 +2662,6 @@ static int xilinx_dma_probe(struct platform_device *pdev)
return PTR_ERR(xdev->regs);
/* Retrieve the DMA engine properties from the device tree */
- xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0);
if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
^ permalink raw reply related
* [v6,4/7] dmaengine: xilinx_dma: program hardware supported buffer length
From: Andrea Merello @ 2018-11-20 15:31 UTC (permalink / raw)
To: vkoul, dan.j.williams, michal.simek, appana.durga.rao, dmaengine
Cc: linux-arm-kernel, linux-kernel, robh+dt, mark.rutland, devicetree,
radhey.shyam.pandey, Andrea Merello
From: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
AXI-DMA IP supports configurable (c_sg_length_width) buffer length
register width, hence read buffer length (xlnx,sg-length-width) DT
property and ensure that driver doesn't program buffer length
exceeding the supported limit. For VDMA and CDMA there is no change.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Andrea Merello <andrea.merello@gmail.com> [rebase, reword]
---
Changes in v2:
- drop original patch and replace with the one in Xilinx tree
Changes in v3:
- cc DT maintainers/ML
Changes in v4:
- upper bound for the property should be 26, not 23
- add warn for width > 23 as per xilinx original patch
- rework due to changes introduced in 1/6
Changes in v5:
None
Changes in v6:
None
---
drivers/dma/xilinx/xilinx_dma.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index cbf34dd5e966..0716db61f1d0 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -161,7 +161,9 @@
#define XILINX_DMA_REG_BTT 0x28
/* AXI DMA Specific Masks/Bit fields */
-#define XILINX_DMA_MAX_TRANS_LEN GENMASK(22, 0)
+#define XILINX_DMA_MAX_TRANS_LEN_MIN 8
+#define XILINX_DMA_MAX_TRANS_LEN_MAX 23
+#define XILINX_DMA_V2_MAX_TRANS_LEN_MAX 26
#define XILINX_DMA_CR_COALESCE_MAX GENMASK(23, 16)
#define XILINX_DMA_CR_CYCLIC_BD_EN_MASK BIT(4)
#define XILINX_DMA_CR_COALESCE_SHIFT 16
@@ -2622,7 +2624,7 @@ static int xilinx_dma_probe(struct platform_device *pdev)
struct xilinx_dma_device *xdev;
struct device_node *child, *np = pdev->dev.of_node;
struct resource *io;
- u32 num_frames, addr_width;
+ u32 num_frames, addr_width, len_width;
int i, err;
/* Allocate and initialize the DMA engine structure */
@@ -2654,10 +2656,24 @@ static int xilinx_dma_probe(struct platform_device *pdev)
/* Retrieve the DMA engine properties from the device tree */
xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
- xdev->max_buffer_len = XILINX_DMA_MAX_TRANS_LEN;
+ xdev->max_buffer_len = GENMASK(XILINX_DMA_MAX_TRANS_LEN_MAX - 1, 0);
- if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
+ if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) {
xdev->mcdma = of_property_read_bool(node, "xlnx,mcdma");
+ if (!of_property_read_u32(node, "xlnx,sg-length-width",
+ &len_width)) {
+ if (len_width < XILINX_DMA_MAX_TRANS_LEN_MIN ||
+ len_width > XILINX_DMA_V2_MAX_TRANS_LEN_MAX) {
+ dev_warn(xdev->dev,
+ "invalid xlnx,sg-length-width property value. Using default width\n");
+ } else {
+ if (len_width > XILINX_DMA_MAX_TRANS_LEN_MAX)
+ dev_warn(xdev->dev, "Please ensure that IP supports buffer length > 23 bits\n");
+ xdev->max_buffer_len =
+ GENMASK(len_width - 1, 0);
+ }
+ }
+ }
if (xdev->dma_config->dmatype == XDMA_TYPE_VDMA) {
err = of_property_read_u32(node, "xlnx,num-fstores",
^ permalink raw reply related
* [v6,3/7] dt-bindings: dmaengine: xilinx_dma: add optional xlnx,sg-length-width property
From: Andrea Merello @ 2018-11-20 15:31 UTC (permalink / raw)
To: vkoul, dan.j.williams, michal.simek, appana.durga.rao, dmaengine
Cc: linux-arm-kernel, linux-kernel, robh+dt, mark.rutland, devicetree,
radhey.shyam.pandey, Andrea Merello
The width of the "length register" cannot be autodetected, and it is now
specified with a DT property. Add documentation for it.
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: devicetree@vger.kernel.org
Cc: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
---
Changes in v2:
- change property name
- property is now optional
- cc DT maintainer
Changes in v3:
- reword
- cc DT maintainerS and ML
Changes in v4:
- specify the unit, the valid range and the default value
Changes in v5:
- commit message trivial fix
- fix spaces before tab
Changes in v6:
None
---
Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
index 174af2c45e77..2fce9fb4b270 100644
--- a/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
+++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_dma.txt
@@ -41,6 +41,10 @@ Optional properties:
- xlnx,include-sg: Tells configured for Scatter-mode in
the hardware.
Optional properties for AXI DMA:
+- xlnx,sg-length-width: Should be set to the width in bits of the length
+ register as configured in h/w. Takes values {8...26}. If the property
+ is missing or invalid then the default value 23 is used. This is the
+ maximum value that is supported by all IP versions.
- xlnx,mcdma: Tells whether configured for multi-channel mode in the hardware.
Optional properties for VDMA:
- xlnx,flush-fsync: Tells which channel to Flush on Frame sync.
^ permalink raw reply related
* [v6,2/7] dmaengine: xilinx_dma: in axidma slave_sg and dma_cyclic mode align split descriptors
From: Andrea Merello @ 2018-11-20 15:31 UTC (permalink / raw)
To: vkoul, dan.j.williams, michal.simek, appana.durga.rao, dmaengine
Cc: linux-arm-kernel, linux-kernel, robh+dt, mark.rutland, devicetree,
radhey.shyam.pandey, Andrea Merello
Whenever a single or cyclic transaction is prepared, the driver
could eventually split it over several SG descriptors in order
to deal with the HW maximum transfer length.
This could end up in DMA operations starting from a misaligned
address. This seems fatal for the HW if DRE (Data Realignment Engine)
is not enabled.
This patch eventually adjusts the transfer size in order to make sure
all operations start from an aligned address.
Cc: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
---
Changes in v2:
- don't introduce copy_mask field, rather rely on already-esistent
copy_align field. Suggested by Radhey Shyam Pandey
- reword title
Changes in v3:
- fix bug introduced in v2: wrong copy size when DRE is enabled
- use implementation suggested by Radhey Shyam Pandey
Changes in v4:
- rework on the top of 1/6
Changes in v5:
- fix typo in commit title
- add hint about "DRE" meaning in commit message
Changes in v6:
None
---
drivers/dma/xilinx/xilinx_dma.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index 2c1db500284f..cbf34dd5e966 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -975,6 +975,15 @@ static int xilinx_dma_calc_copysize(struct xilinx_dma_chan *chan,
copy = min_t(size_t, size - done,
chan->xdev->max_buffer_len);
+ if ((copy + done < size) &&
+ chan->xdev->common.copy_align) {
+ /*
+ * If this is not the last descriptor, make sure
+ * the next one will be properly aligned
+ */
+ copy = rounddown(copy,
+ (1 << chan->xdev->common.copy_align));
+ }
return copy;
}
^ permalink raw reply related
* [v6,1/7] dmaengine: xilinx_dma: commonize DMA copy size calculation
From: Andrea Merello @ 2018-11-20 15:31 UTC (permalink / raw)
To: vkoul, dan.j.williams, michal.simek, appana.durga.rao, dmaengine
Cc: linux-arm-kernel, linux-kernel, robh+dt, mark.rutland, devicetree,
radhey.shyam.pandey, Andrea Merello
This patch removes a bit of duplicated code by introducing a new
function that implements calculations for DMA copy size, and
prepares for changes to the copy size calculation that will
happen in following patches.
Suggested-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
Reviewed-by: Radhey Shyam Pandey <radhey.shyam.pandey@xilinx.com>
---
Changes in v4:
- introduce this patch in the patch series
Changes in v5:
None
Changes in v6:
- 2/7 was basically redoing what done here. Anticipate
here the introduction of a local temporary variable
so that 2/7 just add stuff
- add dma chan ptr argument to xilinx_calc_cma_copysize()
to prepare for 2/7
- introduce max_buffer_len variable in advance, to prepare
for 4/7
- reword for above changes
---
drivers/dma/xilinx/xilinx_dma.c | 39 ++++++++++++++++++++++++++-------
1 file changed, 31 insertions(+), 8 deletions(-)
diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c
index c12442312595..2c1db500284f 100644
--- a/drivers/dma/xilinx/xilinx_dma.c
+++ b/drivers/dma/xilinx/xilinx_dma.c
@@ -423,6 +423,7 @@ struct xilinx_dma_config {
* @rxs_clk: DMA s2mm stream clock
* @nr_channels: Number of channels DMA device supports
* @chan_id: DMA channel identifier
+ * @max_buffer_len: Max buffer length
*/
struct xilinx_dma_device {
void __iomem *regs;
@@ -442,6 +443,7 @@ struct xilinx_dma_device {
struct clk *rxs_clk;
u32 nr_channels;
u32 chan_id;
+ u32 max_buffer_len;
};
/* Macros */
@@ -957,6 +959,25 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan)
return 0;
}
+/**
+ * xilinx_dma_calc_copysize - Calculate the amount of data to copy
+ * @chan: Driver specific DMA channel
+ * @size: Total data that needs to be copied
+ * @done: Amount of data that has been already copied
+ *
+ * Return: Amount of data that has to be copied
+ */
+static int xilinx_dma_calc_copysize(struct xilinx_dma_chan *chan,
+ int size, int done)
+{
+ size_t copy;
+
+ copy = min_t(size_t, size - done,
+ chan->xdev->max_buffer_len);
+
+ return copy;
+}
+
/**
* xilinx_dma_tx_status - Get DMA transaction status
* @dchan: DMA channel
@@ -990,7 +1011,7 @@ static enum dma_status xilinx_dma_tx_status(struct dma_chan *dchan,
list_for_each_entry(segment, &desc->segments, node) {
hw = &segment->hw;
residue += (hw->control - hw->status) &
- XILINX_DMA_MAX_TRANS_LEN;
+ chan->xdev->max_buffer_len;
}
}
spin_unlock_irqrestore(&chan->lock, flags);
@@ -1250,7 +1271,7 @@ static void xilinx_cdma_start_transfer(struct xilinx_dma_chan *chan)
/* Start the transfer */
dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
- hw->control & XILINX_DMA_MAX_TRANS_LEN);
+ hw->control & chan->xdev->max_buffer_len);
}
list_splice_tail_init(&chan->pending_list, &chan->active_list);
@@ -1353,7 +1374,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan)
/* Start the transfer */
dma_ctrl_write(chan, XILINX_DMA_REG_BTT,
- hw->control & XILINX_DMA_MAX_TRANS_LEN);
+ hw->control & chan->xdev->max_buffer_len);
}
list_splice_tail_init(&chan->pending_list, &chan->active_list);
@@ -1714,7 +1735,7 @@ xilinx_cdma_prep_memcpy(struct dma_chan *dchan, dma_addr_t dma_dst,
struct xilinx_cdma_tx_segment *segment;
struct xilinx_cdma_desc_hw *hw;
- if (!len || len > XILINX_DMA_MAX_TRANS_LEN)
+ if (!len || len > chan->xdev->max_buffer_len)
return NULL;
desc = xilinx_dma_alloc_tx_descriptor(chan);
@@ -1804,8 +1825,8 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_slave_sg(
* Calculate the maximum number of bytes to transfer,
* making sure it is less than the hw limit
*/
- copy = min_t(size_t, sg_dma_len(sg) - sg_used,
- XILINX_DMA_MAX_TRANS_LEN);
+ copy = xilinx_dma_calc_copysize(chan, sg_dma_len(sg),
+ sg_used);
hw = &segment->hw;
/* Fill in the descriptor */
@@ -1909,8 +1930,8 @@ static struct dma_async_tx_descriptor *xilinx_dma_prep_dma_cyclic(
* Calculate the maximum number of bytes to transfer,
* making sure it is less than the hw limit
*/
- copy = min_t(size_t, period_len - sg_used,
- XILINX_DMA_MAX_TRANS_LEN);
+ copy = xilinx_dma_calc_copysize(chan, period_len,
+ sg_used);
hw = &segment->hw;
xilinx_axidma_buf(chan, hw, buf_addr, sg_used,
period_len * i);
@@ -2624,6 +2645,8 @@ static int xilinx_dma_probe(struct platform_device *pdev)
/* Retrieve the DMA engine properties from the device tree */
xdev->has_sg = of_property_read_bool(node, "xlnx,include-sg");
+ xdev->max_buffer_len = XILINX_DMA_MAX_TRANS_LEN;
+
if (xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA)
xdev->mcdma = of_property_read_bool(node, "xlnx,mcdma");
^ permalink raw reply related
* [v1] dmaengine: Add mailing list address to the documentation
From: Andy Shevchenko @ 2018-11-20 13:15 UTC (permalink / raw)
To: Vinod Koul, dmaengine, Jonathan Corbet; +Cc: Andy Shevchenko
It's not the first time I've got a private email in regard to
dmatest.c module.
Motivate people, by adding a note, to send their questions
to the mailing list instead
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
Documentation/driver-api/dmaengine/dmatest.rst | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/driver-api/dmaengine/dmatest.rst b/Documentation/driver-api/dmaengine/dmatest.rst
index 7ce5e71c353e..49efebd2c043 100644
--- a/Documentation/driver-api/dmaengine/dmatest.rst
+++ b/Documentation/driver-api/dmaengine/dmatest.rst
@@ -11,6 +11,10 @@ This small document introduces how to test DMA drivers using dmatest module.
capability of the following: DMA_MEMCPY (memory-to-memory), DMA_MEMSET
(const-to-memory or memory-to-memory, when emulated), DMA_XOR, DMA_PQ.
+.. note::
+ In case of any related questions use the official mailing list
+ dmaengine@vger.kernel.org.
+
Part 1 - How to build the test module
=====================================
^ permalink raw reply related
* [3/5] dmaengine: imx-sdma: remove dma_slave_config direction usage
From: Robin Gong @ 2018-11-20 9:01 UTC (permalink / raw)
To: Vinod Koul; +Cc: dmaengine@vger.kernel.org
Hi Vinod,
Thanks for your kind reminding.
I have test your patch these days and unfortunately, found it breaks uart/spi
on i.mx6 boards. I identified the issue finally, could you please merge attached
patch into your patch set to ensure no any regression?
> -----Original Message-----
> From: Vinod Koul <vkoul@kernel.org>
> Sent: 2018年11月13日 2:10
> To: Robin Gong <yibin.gong@nxp.com>
> Cc: dmaengine@vger.kernel.org
> Subject: Re: [PATCH 3/5] dmaengine: imx-sdma: remove dma_slave_config
> direction usage
>
> On 12-11-18, 07:18, Robin Gong wrote:
> > Signed-off-by: Robin Gong <yibin.gong@nxp.com>
>
> You cannot sign off, but you may test this patch and provide Tested-by:.. or you
> may review the patch and provide Reviewed-by:... or if you agree you may also
> provide Acked-by: ...
>
> For more details, please see
> Documentation/process/submitting-patches.rst Section 13.
>
> Also, please do not top post you reply
>
> Thanks
>
> --
> ~Vinod
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Peter Ujfalusi @ 2018-11-20 7:28 UTC (permalink / raw)
To: Aaro Koskinen
Cc: vkoul, dan.j.williams, dmaengine, linux-kernel, tony, linux-omap,
rmk+kernel
Aaro,
On 19/11/2018 20.46, Aaro Koskinen wrote:
> Hi,
>
> On Mon, Nov 19, 2018 at 12:40:40PM +0200, Peter Ujfalusi wrote:
>> When the channel is configured for slave operation the LCH_TYPE needs to be
>> set to LCh-P. For memcpy channels the LCH_TYPE must be set to LCh-2D.
>>
>> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
>
> I don't have the documentation, but based on what omap_udc driver (still
> using the legacy OMAP DMA API) does this seems to be correct.
They are hard to fine, true. From the omap1710 TRM:
Logical channel types (LCh types) supported are:
- LCh-2D for nonsynchronized transfers (memory transfers, 1D and 2D)
- LCh-P for synchronized transfers (mostly peripheral transfers)
- LCh-PD similar to LCh-P but runs on a dedicated physical channel
- LCh-G for graphical transfers/operations
- LCh-D for display transfers
Looking at other part it looks like hat LCH-2D channel mode can happily
service a peripheral. LCH-P supports the same features as LCH-2D, but it
lacks support for Single/Double-indexed addressing mode on the
peripheral port side.
So, this patch might not be needed at all. Can you test the omap_udc
with s/OMAP_DMA_LCH_P/OMAP_DMA_LCH_2D
If USB works, then we can just drop this patch.
Note: if we ever need the port_window support in OMAP1 then we need
double indexing on the peripheral side.
> I tested the patch on Nokia 770 with MMC and couldn't see any negative
> impact.
>
> Tested-by: Aaro Koskinen <aaro.koskinen@iki.fi>
>
> A.
>
>> ---
>> drivers/dma/ti/omap-dma.c | 11 +++++++++++
>> 1 file changed, 11 insertions(+)
>>
>> diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
>> index a4a931ddf6f6..a18cfd497f04 100644
>> --- a/drivers/dma/ti/omap-dma.c
>> +++ b/drivers/dma/ti/omap-dma.c
>> @@ -185,6 +185,10 @@ enum {
>>
>> CLNK_CTRL_ENABLE_LNK = BIT(15),
>>
>> + /* OMAP1 only */
>> + LCH_CTRL_LCH_2D = 0,
>> + LCH_CTRL_LCH_P = 2,
>> +
>> CDP_DST_VALID_INC = 0 << 0,
>> CDP_DST_VALID_RELOAD = 1 << 0,
>> CDP_DST_VALID_REUSE = 2 << 0,
>> @@ -529,6 +533,7 @@ static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d)
>>
>> static void omap_dma_start_desc(struct omap_chan *c)
>> {
>> + struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device);
>> struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
>> struct omap_desc *d;
>> unsigned cxsa, cxei, cxfi;
>> @@ -570,6 +575,12 @@ static void omap_dma_start_desc(struct omap_chan *c)
>> omap_dma_chan_write(c, CSDP, d->csdp);
>> omap_dma_chan_write(c, CLNK_CTRL, d->clnk_ctrl);
>>
>> + if (dma_omap1() && !__dma_omap15xx(od->plat->dma_attr)) {
>> + if (is_slave_direction(d->dir))
>> + omap_dma_chan_write(c, LCH_CTRL, LCH_CTRL_LCH_P);
>> + else
>> + omap_dma_chan_write(c, LCH_CTRL, LCH_CTRL_LCH_2D);
>> + }
>> omap_dma_start_sg(c, d);
>> }
>>
>> --
>> Peter
>>
>> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
>> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
>>
- Péter
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
^ permalink raw reply
* [v2,1/2] firmware: add nowarn variant of request_firmware_nowait()
From: Luis R. Rodriguez @ 2018-11-19 20:07 UTC (permalink / raw)
To: Lucas Stach, Sebastian Reichel
Cc: Greg Kroah-Hartman, Kees Cook, mcgrof, Julia Lawall, linux-kernel,
dmaengine, Vinod Koul, kernel, patchwork-lst
On Mon, Nov 12, 2018 at 05:01:42PM +0100, Lucas Stach wrote:
> Device drivers with optional firmware may still want to use the
> asynchronous firmware loading interface. To avoid printing a
> warining into the kernel log when the optional firmware is
> absent, add a nowarn variant of this interface.
>
> Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Thanks for the patch Lucas!
> +EXPORT_SYMBOL(request_firmware_nowait_nowarn);
New symbols should use firmware_* prefix, so use:
* firmware_request_nowait_nowarn()
Also, please make new functionality EXPORT_SYMBOL_GPL(), the old functioanlity
must be kept as-is, so in this caseEXPORT_SYMBOL().
Other than this, you should be aware that there has been significant
discussion over how to properly evolve the API of the firmware API since
last year, you may want to read those threads. The short and skinny of
it though is that the firmware API has two main diverging modes of
operation:
o async
o sync
The async functionality diverges from the synchronous functionality in
that it is data driven. The synchronous functionality is functional, and
experience shows that while data driven can avoid collateral evolutions
we *don't prefer it in the kernel*. So we should break down the async
API to match the sync functional design.
Internally we can use flags for small modifications, as we use them now,
but since we don't expose flags for the sync case lets try to keep
parity for this API then.
A good example of what we need to do. The uevent flag is only set to
false by only two drivers:
o CONFIG_LEDS_LP55XX_COMMON
o CONFIG_DELL_RBU
As such, this functionality should just be wrapped into its own single
functional call eventually.
The conversion of the async API to functional does not need to happen
for your changes, but new async API should follow the functional driven
approach. So please make your call work as functional.
Please let me know if this makes sense or if you have any quetsions!
[0] https://lore.kernel.org/lkml/20180628031332.GE21242@wotan.suse.de/T/#u
[1] https://lkml.kernel.org/r/20180421173650.GW14440@wotan.suse.de
[2] https://lkml.kernel.org/r/20180422202609.GX14440@wotan.suse.de
Luis
^ permalink raw reply
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Aaro Koskinen @ 2018-11-19 18:46 UTC (permalink / raw)
To: Peter Ujfalusi
Cc: vkoul, dan.j.williams, dmaengine, linux-kernel, tony, linux-omap,
rmk+kernel
Hi,
On Mon, Nov 19, 2018 at 12:40:40PM +0200, Peter Ujfalusi wrote:
> When the channel is configured for slave operation the LCH_TYPE needs to be
> set to LCh-P. For memcpy channels the LCH_TYPE must be set to LCh-2D.
>
> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
I don't have the documentation, but based on what omap_udc driver (still
using the legacy OMAP DMA API) does this seems to be correct.
I tested the patch on Nokia 770 with MMC and couldn't see any negative
impact.
Tested-by: Aaro Koskinen <aaro.koskinen@iki.fi>
A.
> ---
> drivers/dma/ti/omap-dma.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
> index a4a931ddf6f6..a18cfd497f04 100644
> --- a/drivers/dma/ti/omap-dma.c
> +++ b/drivers/dma/ti/omap-dma.c
> @@ -185,6 +185,10 @@ enum {
>
> CLNK_CTRL_ENABLE_LNK = BIT(15),
>
> + /* OMAP1 only */
> + LCH_CTRL_LCH_2D = 0,
> + LCH_CTRL_LCH_P = 2,
> +
> CDP_DST_VALID_INC = 0 << 0,
> CDP_DST_VALID_RELOAD = 1 << 0,
> CDP_DST_VALID_REUSE = 2 << 0,
> @@ -529,6 +533,7 @@ static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d)
>
> static void omap_dma_start_desc(struct omap_chan *c)
> {
> + struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device);
> struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
> struct omap_desc *d;
> unsigned cxsa, cxei, cxfi;
> @@ -570,6 +575,12 @@ static void omap_dma_start_desc(struct omap_chan *c)
> omap_dma_chan_write(c, CSDP, d->csdp);
> omap_dma_chan_write(c, CLNK_CTRL, d->clnk_ctrl);
>
> + if (dma_omap1() && !__dma_omap15xx(od->plat->dma_attr)) {
> + if (is_slave_direction(d->dir))
> + omap_dma_chan_write(c, LCH_CTRL, LCH_CTRL_LCH_P);
> + else
> + omap_dma_chan_write(c, LCH_CTRL, LCH_CTRL_LCH_2D);
> + }
> omap_dma_start_sg(c, d);
> }
>
> --
> Peter
>
> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
> Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
>
^ permalink raw reply
* dmaengine: ep93xx_dma: fix misspell
From: Yangtao Li @ 2018-11-19 15:15 UTC (permalink / raw)
To: dan.j.williams, vkoul; +Cc: dmaengine, linux-kernel, Yangtao Li
couln't -> couldn't
Signed-off-by: Yangtao Li <tiny.windzz@gmail.com>
---
drivers/dma/ep93xx_dma.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index f674eb5fbbef..594a88f4f99c 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -997,7 +997,7 @@ ep93xx_dma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest,
for (offset = 0; offset < len; offset += bytes) {
desc = ep93xx_dma_desc_get(edmac);
if (!desc) {
- dev_warn(chan2dev(edmac), "couln't get descriptor\n");
+ dev_warn(chan2dev(edmac), "couldn't get descriptor\n");
goto fail;
}
@@ -1069,7 +1069,7 @@ ep93xx_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
desc = ep93xx_dma_desc_get(edmac);
if (!desc) {
- dev_warn(chan2dev(edmac), "couln't get descriptor\n");
+ dev_warn(chan2dev(edmac), "couldn't get descriptor\n");
goto fail;
}
@@ -1149,7 +1149,7 @@ ep93xx_dma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t dma_addr,
for (offset = 0; offset < buf_len; offset += period_len) {
desc = ep93xx_dma_desc_get(edmac);
if (!desc) {
- dev_warn(chan2dev(edmac), "couln't get descriptor\n");
+ dev_warn(chan2dev(edmac), "couldn't get descriptor\n");
goto fail;
}
^ permalink raw reply related
* dmaengine: ti: omap-dma: Configure LCH_TYPE for OMAP1
From: Peter Ujfalusi @ 2018-11-19 10:40 UTC (permalink / raw)
To: vkoul, dan.j.williams
Cc: dmaengine, linux-kernel, aaro.koskinen, tony, linux-omap,
rmk+kernel
When the channel is configured for slave operation the LCH_TYPE needs to be
set to LCh-P. For memcpy channels the LCH_TYPE must be set to LCh-2D.
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
---
drivers/dma/ti/omap-dma.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/dma/ti/omap-dma.c b/drivers/dma/ti/omap-dma.c
index a4a931ddf6f6..a18cfd497f04 100644
--- a/drivers/dma/ti/omap-dma.c
+++ b/drivers/dma/ti/omap-dma.c
@@ -185,6 +185,10 @@ enum {
CLNK_CTRL_ENABLE_LNK = BIT(15),
+ /* OMAP1 only */
+ LCH_CTRL_LCH_2D = 0,
+ LCH_CTRL_LCH_P = 2,
+
CDP_DST_VALID_INC = 0 << 0,
CDP_DST_VALID_RELOAD = 1 << 0,
CDP_DST_VALID_REUSE = 2 << 0,
@@ -529,6 +533,7 @@ static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d)
static void omap_dma_start_desc(struct omap_chan *c)
{
+ struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device);
struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
struct omap_desc *d;
unsigned cxsa, cxei, cxfi;
@@ -570,6 +575,12 @@ static void omap_dma_start_desc(struct omap_chan *c)
omap_dma_chan_write(c, CSDP, d->csdp);
omap_dma_chan_write(c, CLNK_CTRL, d->clnk_ctrl);
+ if (dma_omap1() && !__dma_omap15xx(od->plat->dma_attr)) {
+ if (is_slave_direction(d->dir))
+ omap_dma_chan_write(c, LCH_CTRL, LCH_CTRL_LCH_P);
+ else
+ omap_dma_chan_write(c, LCH_CTRL, LCH_CTRL_LCH_2D);
+ }
omap_dma_start_sg(c, d);
}
^ permalink raw reply related
* [v4,2/2] dmaengine: dw-dmac: implement dma protection control setting
From: Christian Lamparter @ 2018-11-17 16:17 UTC (permalink / raw)
To: dmaengine, devicetree
Cc: Dan Williams, Vinod Koul, Andy Shevchenko, Viresh Kumar,
Rob Herring, Mark Rutland
This patch adds a new device-tree property that allows to
specify the dma protection control bits for the all of the
DMA controller's channel uniformly.
Setting the "correct" bits can have a huge impact on the
PPC460EX and APM82181 that use this DMA engine in combination
with a DesignWare' SATA-II core (sata_dwc_460ex driver).
In the OpenWrt Forum, the user takimata reported that:
|It seems your patch unleashed the full power of the SATA port.
|Where I was previously hitting a really hard limit at around
|82 MB/s for reading and 27 MB/s for writing, I am now getting this:
|
|root@OpenWrt:/mnt# time dd if=/dev/zero of=tempfile bs=1M count=1024
|1024+0 records in
|1024+0 records out
|real 0m 13.65s
|user 0m 0.01s
|sys 0m 11.89s
|
|root@OpenWrt:/mnt# time dd if=tempfile of=/dev/null bs=1M count=1024
|1024+0 records in
|1024+0 records out
|real 0m 8.41s
|user 0m 0.01s
|sys 0m 4.70s
|
|This means: 121 MB/s reading and 75 MB/s writing!
|
|The drive is a WD Green WD10EARX taken from an older MBL Single.
|I repeated the test a few times with even larger files to rule out
|any caching, I'm still seeing the same great performance. OpenWrt is
|now completely on par with the original MBL firmware's performance.
Another user And.short reported:
|I can report that your fix worked! Boots up fine with two
|drives even with more partitions, and no more reboot on
|concurrent disk access!
A closer look into the sata_dwc_460ex code revealed that
the driver did initally set the correct protection control
bits. However, this feature was lost when the sata_dwc_460ex
driver was converted to the generic DMA driver framework.
BugLink: https://forum.openwrt.org/t/wd-mybook-live-duo-two-disks/16195/55
BugLink: https://forum.openwrt.org/t/wd-mybook-live-duo-two-disks/16195/50
Fixes: 8b3444852a2b ("sata_dwc_460ex: move to generic DMA driver")
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
---
I've included the "LGTM" from Andy from the v2 series and transformed
it into a reviewed-by tag.
---
drivers/dma/dw/core.c | 2 ++
drivers/dma/dw/platform.c | 6 ++++++
drivers/dma/dw/regs.h | 4 ++++
include/linux/platform_data/dma-dw.h | 6 ++++++
4 files changed, 18 insertions(+)
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index d0c3e50b39fb..2c5ca1961256 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -160,12 +160,14 @@ static void dwc_initialize_chan_idma32(struct dw_dma_chan *dwc)
static void dwc_initialize_chan_dw(struct dw_dma_chan *dwc)
{
+ struct dw_dma *dw = to_dw_dma(dwc->chan.device);
u32 cfghi = DWC_CFGH_FIFO_MODE;
u32 cfglo = DWC_CFGL_CH_PRIOR(dwc->priority);
bool hs_polarity = dwc->dws.hs_polarity;
cfghi |= DWC_CFGH_DST_PER(dwc->dws.dst_id);
cfghi |= DWC_CFGH_SRC_PER(dwc->dws.src_id);
+ cfghi |= DWC_CFGH_PROTCTL(dw->pdata->protctl);
/* Set polarity of handshake interface */
cfglo |= hs_polarity ? DWC_CFGL_HS_DST_POL | DWC_CFGL_HS_SRC_POL : 0;
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index f01b2c173fa6..31ff8113c3de 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -162,6 +162,12 @@ dw_dma_parse_dt(struct platform_device *pdev)
pdata->multi_block[tmp] = 1;
}
+ if (!of_property_read_u32(np, "snps,dma-protection-control", &tmp)) {
+ if (tmp > CHAN_PROTCTL_MASK)
+ return NULL;
+ pdata->protctl = tmp;
+ }
+
return pdata;
}
#else
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 09e7dfdbb790..646c9c960c07 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -200,6 +200,10 @@ enum dw_dma_msize {
#define DWC_CFGH_FCMODE (1 << 0)
#define DWC_CFGH_FIFO_MODE (1 << 1)
#define DWC_CFGH_PROTCTL(x) ((x) << 2)
+#define DWC_CFGH_PROTCTL_DATA (0 << 2) /* data access - always set */
+#define DWC_CFGH_PROTCTL_PRIV (1 << 2) /* privileged -> AHB HPROT[1] */
+#define DWC_CFGH_PROTCTL_BUFFER (2 << 2) /* bufferable -> AHB HPROT[2] */
+#define DWC_CFGH_PROTCTL_CACHE (4 << 2) /* cacheable -> AHB HPROT[3] */
#define DWC_CFGH_DS_UPD_EN (1 << 5)
#define DWC_CFGH_SS_UPD_EN (1 << 6)
#define DWC_CFGH_SRC_PER(x) ((x) << 7)
diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h
index 896cb71a382c..1a1d58ebffbf 100644
--- a/include/linux/platform_data/dma-dw.h
+++ b/include/linux/platform_data/dma-dw.h
@@ -49,6 +49,7 @@ struct dw_dma_slave {
* @data_width: Maximum data width supported by hardware per AHB master
* (in bytes, power of 2)
* @multi_block: Multi block transfers supported by hardware per channel.
+ * @protctl: Protection control signals setting per channel.
*/
struct dw_dma_platform_data {
unsigned int nr_channels;
@@ -65,6 +66,11 @@ struct dw_dma_platform_data {
unsigned char nr_masters;
unsigned char data_width[DW_DMA_MAX_NR_MASTERS];
unsigned char multi_block[DW_DMA_MAX_NR_CHANNELS];
+#define CHAN_PROTCTL_PRIVILEGED BIT(0)
+#define CHAN_PROTCTL_BUFFERABLE BIT(1)
+#define CHAN_PROTCTL_CACHEABLE BIT(2)
+#define CHAN_PROTCTL_MASK GENMASK(2, 0)
+ unsigned char protctl;
};
#endif /* _PLATFORM_DATA_DMA_DW_H */
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox