* [PATCH v1 1/2] dmaengine: tegra-apb: Don't save/restore IRQ flags in interrupt handler
@ 2020-03-19 20:52 Dmitry Osipenko
2020-03-19 20:52 ` [PATCH v1 2/2] dmaengine: tegra-apb: Improve DMA synchronization Dmitry Osipenko
0 siblings, 1 reply; 2+ messages in thread
From: Dmitry Osipenko @ 2020-03-19 20:52 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Laxman Dewangan, Vinod Koul,
Dan Williams
Cc: Wolfram Sang, linux-i2c, linux-tegra, dmaengine, linux-kernel
The interrupt is already disabled while interrupt handler is running, and
thus, there is no need to save/restore the IRQ flags within the spinlock.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
drivers/dma/tegra20-apb-dma.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 4e295d121be6..26f427e02369 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -672,10 +672,9 @@ static void tegra_dma_tasklet(unsigned long data)
static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
{
struct tegra_dma_channel *tdc = dev_id;
- unsigned long flags;
u32 status;
- spin_lock_irqsave(&tdc->lock, flags);
+ spin_lock(&tdc->lock);
trace_tegra_dma_isr(&tdc->dma_chan, irq);
status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
@@ -683,11 +682,11 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
tdc->isr_handler(tdc, false);
tasklet_schedule(&tdc->tasklet);
- spin_unlock_irqrestore(&tdc->lock, flags);
+ spin_unlock(&tdc->lock);
return IRQ_HANDLED;
}
- spin_unlock_irqrestore(&tdc->lock, flags);
+ spin_unlock(&tdc->lock);
dev_info(tdc2dev(tdc), "Interrupt already served status 0x%08x\n",
status);
--
2.25.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* [PATCH v1 2/2] dmaengine: tegra-apb: Improve DMA synchronization
2020-03-19 20:52 [PATCH v1 1/2] dmaengine: tegra-apb: Don't save/restore IRQ flags in interrupt handler Dmitry Osipenko
@ 2020-03-19 20:52 ` Dmitry Osipenko
0 siblings, 0 replies; 2+ messages in thread
From: Dmitry Osipenko @ 2020-03-19 20:52 UTC (permalink / raw)
To: Thierry Reding, Jonathan Hunter, Laxman Dewangan, Vinod Koul,
Dan Williams
Cc: Wolfram Sang, linux-i2c, linux-tegra, dmaengine, linux-kernel
Boot CPU0 always handles DMA interrupts and under some rare circumstances
it could stuck in uninterruptible state for a significant time (like in a
case of KASAN + NFS root). In this case sibling CPU, which waits for DMA
transfer completion, will get a DMA transfer timeout. In order to handle
this rare condition, interrupt status needs to be polled until interrupt
is handled.
Signed-off-by: Dmitry Osipenko <digetx@gmail.com>
---
drivers/dma/tegra20-apb-dma.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 26f427e02369..d4a92714740c 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -24,6 +24,7 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>
#include <linux/slab.h>
+#include <linux/wait.h>
#include "dmaengine.h"
@@ -202,6 +203,8 @@ struct tegra_dma_channel {
unsigned int slave_id;
struct dma_slave_config dma_sconfig;
struct tegra_dma_channel_regs channel_reg;
+
+ struct wait_queue_head wq;
};
/* tegra_dma: Tegra DMA specific information */
@@ -682,6 +685,7 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
tdc->isr_handler(tdc, false);
tasklet_schedule(&tdc->tasklet);
+ wake_up_all(&tdc->wq);
spin_unlock(&tdc->lock);
return IRQ_HANDLED;
}
@@ -798,10 +802,29 @@ static int tegra_dma_terminate_all(struct dma_chan *dc)
return 0;
}
+static bool tegra_dma_eoc_interrupt_deasserted(struct tegra_dma_channel *tdc)
+{
+ unsigned long flags;
+ u32 status;
+
+ spin_lock_irqsave(&tdc->lock, flags);
+ status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+ spin_unlock_irqrestore(&tdc->lock, flags);
+
+ return !(status & TEGRA_APBDMA_STATUS_ISE_EOC);
+}
+
static void tegra_dma_synchronize(struct dma_chan *dc)
{
struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
+ /*
+ * CPU, which handles interrupt, could be busy in
+ * uninterruptible state, in this case sibling CPU
+ * should wait until interrupt is handled.
+ */
+ wait_event(tdc->wq, tegra_dma_eoc_interrupt_deasserted(tdc));
+
tasklet_kill(&tdc->tasklet);
}
@@ -1495,6 +1518,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
tasklet_init(&tdc->tasklet, tegra_dma_tasklet,
(unsigned long)tdc);
spin_lock_init(&tdc->lock);
+ init_waitqueue_head(&tdc->wq);
INIT_LIST_HEAD(&tdc->pending_sg_req);
INIT_LIST_HEAD(&tdc->free_sg_req);
--
2.25.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-03-19 20:53 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-03-19 20:52 [PATCH v1 1/2] dmaengine: tegra-apb: Don't save/restore IRQ flags in interrupt handler Dmitry Osipenko
2020-03-19 20:52 ` [PATCH v1 2/2] dmaengine: tegra-apb: Improve DMA synchronization Dmitry Osipenko
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.