build/patch/kernel/archive/sunxi-5.10/megous/bus-sunxi-rsb-Make-interrupt-handling-more-robust.patch

75 lines
2.7 KiB
Diff
Raw Normal View History

From 4a45831e4fc5204f7d72c5628a1b0167f78a94ce Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Mon, 30 Dec 2019 22:58:21 -0600
Subject: [PATCH 157/351] bus: sunxi-rsb: Make interrupt handling more robust
The RSB controller has two registers for controlling interrupt inputs:
RSB_INTE, which has bits for each possible interrupt, and the global
interrupt enable bit in RSB_CTRL.
Currently, we enable the bits in RSB_INTE before each transfer, but this
is unnecessary because we never disable them. Move the initialization of
RSB_INTE so it is done only once.
We also set the global interrupt enable bit before each transfer. Unlike
other bits in RSB_CTRL, this bit is cleared by writing a zero. Thus, we
clear the bit in the post-timeout cleanup code, but that is not
documented, so note that in the comment. However, in the success/error
path (when an IRQ is received), we do not disable further interrupts.
Add a register write to do just that.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
drivers/bus/sunxi-rsb.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/bus/sunxi-rsb.c b/drivers/bus/sunxi-rsb.c
index cbfbee32e15e..edb5f338f494 100644
--- a/drivers/bus/sunxi-rsb.c
+++ b/drivers/bus/sunxi-rsb.c
@@ -276,8 +276,6 @@ static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
reinit_completion(&rsb->complete);
- writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER,
- rsb->regs + RSB_INTE);
writel(RSB_CTRL_START_TRANS | RSB_CTRL_GLOBAL_INT_ENB,
rsb->regs + RSB_CTRL);
@@ -285,7 +283,7 @@ static int _sunxi_rsb_run_xfer(struct sunxi_rsb *rsb)
msecs_to_jiffies(100))) {
dev_dbg(rsb->dev, "RSB timeout\n");
- /* abort the transfer */
+ /* abort the transfer and disable interrupts */
writel(RSB_CTRL_ABORT_TRANS, rsb->regs + RSB_CTRL);
/* clear any interrupt flags */
@@ -460,7 +458,8 @@ static irqreturn_t sunxi_rsb_irq(int irq, void *dev_id)
status = readl(rsb->regs + RSB_INTS);
rsb->status = status;
- /* Clear interrupts */
+ /* Disable and clear interrupts */
+ writel(0, rsb->regs + RSB_CTRL);
status &= (RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR |
RSB_INTS_TRANS_OVER);
writel(status, rsb->regs + RSB_INTS);
@@ -640,6 +639,13 @@ static int sunxi_rsb_init_controller(struct sunxi_rsb *rsb)
writel(RSB_CCR_SDA_OUT_DELAY(clk_delay) | RSB_CCR_CLK_DIV(clk_div - 1),
rsb->regs + RSB_CCR);
+ /*
+ * Select the interrupts we care about. They will not actually fire
+ * until the RSB_CTRL_GLOBAL_INT_ENB bit is set.
+ */
+ writel(RSB_INTS_LOAD_BSY | RSB_INTS_TRANS_ERR | RSB_INTS_TRANS_OVER,
+ rsb->regs + RSB_INTE);
+
return 0;
err_clk_disable:
--
2.34.0