]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - queue-4.4/dmaengine-at_xdmac-fix-wrongfull-report-of-a-channel.patch
drop perf-trace-support-multiple-vfs_getname-probes.patch from 4.4 and 4.9 queues
[thirdparty/kernel/stable-queue.git] / queue-4.4 / dmaengine-at_xdmac-fix-wrongfull-report-of-a-channel.patch
CommitLineData
1981af9d
SL
1From 6ee0b2d89a3e17e4f545ca6515f62b5f81870090 Mon Sep 17 00:00:00 2001
2From: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
3Date: Wed, 23 Jan 2019 16:33:47 +0000
4Subject: dmaengine: at_xdmac: Fix wrongfull report of a channel as in use
5
6[ Upstream commit dc3f595b6617ebc0307e0ce151e8f2f2b2489b95 ]
7
8atchan->status variable is used to store two different information:
9 - pass channel interrupts status from interrupt handler to tasklet;
10 - channel information like whether it is cyclic or paused;
11
12This causes a bug when device_terminate_all() is called,
13(AT_XDMAC_CHAN_IS_CYCLIC cleared on atchan->status) and then a late End
14of Block interrupt arrives (AT_XDMAC_CIS_BIS), which sets bit 0 of
15atchan->status. Bit 0 is also used for AT_XDMAC_CHAN_IS_CYCLIC, so when
16a new descriptor for a cyclic transfer is created, the driver reports
17the channel as in use:
18
19if (test_and_set_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status)) {
20 dev_err(chan2dev(chan), "channel currently used\n");
21 return NULL;
22}
23
24This patch fixes the bug by adding a different struct member to keep
25the interrupts status separated from the channel status bits.
26
27Fixes: e1f7c9eee707 ("dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver")
28Signed-off-by: Codrin Ciubotariu <codrin.ciubotariu@microchip.com>
29Acked-by: Ludovic Desroches <ludovic.desroches@microchip.com>
30Signed-off-by: Vinod Koul <vkoul@kernel.org>
31Signed-off-by: Sasha Levin <sashal@kernel.org>
32---
33 drivers/dma/at_xdmac.c | 19 ++++++++++---------
34 1 file changed, 10 insertions(+), 9 deletions(-)
35
36diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
37index 82a7c89caae2..af24c5bf32d6 100644
38--- a/drivers/dma/at_xdmac.c
39+++ b/drivers/dma/at_xdmac.c
40@@ -203,6 +203,7 @@ struct at_xdmac_chan {
41 u32 save_cim;
42 u32 save_cnda;
43 u32 save_cndc;
44+ u32 irq_status;
45 unsigned long status;
46 struct tasklet_struct tasklet;
47 struct dma_slave_config sconfig;
48@@ -1582,8 +1583,8 @@ static void at_xdmac_tasklet(unsigned long data)
49 struct at_xdmac_desc *desc;
50 u32 error_mask;
51
52- dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08lx\n",
53- __func__, atchan->status);
54+ dev_dbg(chan2dev(&atchan->chan), "%s: status=0x%08x\n",
55+ __func__, atchan->irq_status);
56
57 error_mask = AT_XDMAC_CIS_RBEIS
58 | AT_XDMAC_CIS_WBEIS
59@@ -1591,15 +1592,15 @@ static void at_xdmac_tasklet(unsigned long data)
60
61 if (at_xdmac_chan_is_cyclic(atchan)) {
62 at_xdmac_handle_cyclic(atchan);
63- } else if ((atchan->status & AT_XDMAC_CIS_LIS)
64- || (atchan->status & error_mask)) {
65+ } else if ((atchan->irq_status & AT_XDMAC_CIS_LIS)
66+ || (atchan->irq_status & error_mask)) {
67 struct dma_async_tx_descriptor *txd;
68
69- if (atchan->status & AT_XDMAC_CIS_RBEIS)
70+ if (atchan->irq_status & AT_XDMAC_CIS_RBEIS)
71 dev_err(chan2dev(&atchan->chan), "read bus error!!!");
72- if (atchan->status & AT_XDMAC_CIS_WBEIS)
73+ if (atchan->irq_status & AT_XDMAC_CIS_WBEIS)
74 dev_err(chan2dev(&atchan->chan), "write bus error!!!");
75- if (atchan->status & AT_XDMAC_CIS_ROIS)
76+ if (atchan->irq_status & AT_XDMAC_CIS_ROIS)
77 dev_err(chan2dev(&atchan->chan), "request overflow error!!!");
78
79 spin_lock_bh(&atchan->lock);
80@@ -1654,7 +1655,7 @@ static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
81 atchan = &atxdmac->chan[i];
82 chan_imr = at_xdmac_chan_read(atchan, AT_XDMAC_CIM);
83 chan_status = at_xdmac_chan_read(atchan, AT_XDMAC_CIS);
84- atchan->status = chan_status & chan_imr;
85+ atchan->irq_status = chan_status & chan_imr;
86 dev_vdbg(atxdmac->dma.dev,
87 "%s: chan%d: imr=0x%x, status=0x%x\n",
88 __func__, i, chan_imr, chan_status);
89@@ -1668,7 +1669,7 @@ static irqreturn_t at_xdmac_interrupt(int irq, void *dev_id)
90 at_xdmac_chan_read(atchan, AT_XDMAC_CDA),
91 at_xdmac_chan_read(atchan, AT_XDMAC_CUBC));
92
93- if (atchan->status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
94+ if (atchan->irq_status & (AT_XDMAC_CIS_RBEIS | AT_XDMAC_CIS_WBEIS))
95 at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
96
97 tasklet_schedule(&atchan->tasklet);
98--
992.19.1
100