Patchwork [v2,3/5] intc/xilinx_intc: Handle level interrupt retriggering

login
register
mail settings
Submitter Peter Crosthwaite
Date June 11, 2013, 12:59 a.m.
Message ID <9c0ab49e759a7a55d17b5d7fa31052d6d6908671.1370911981.git.peter.crosthwaite@xilinx.com>
Download mbox | patch
Permalink /patch/250430/
State New
Headers show

Comments

Peter Crosthwaite - June 11, 2013, 12:59 a.m.
From: Peter Crosthwaite <peter.crosthwaite@xilinx.com>

Acking a level sensitive interrupt should have no effect if the
interrupt pin is still asserted. The current implementation requires
and edge condition to occur for setting a level sensitive IRQ, which
means an ACK can clear a level sensitive interrupt, until the original
source strobes the interrupt again.

Fix by keeping track of the interrupt pin state and setting ISR based
on this every time update_irq() is called.

Signed-off-by: Peter Crosthwaite <peter.crosthwaite@xilinx.com>
---

 hw/intc/xilinx_intc.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

Patch

diff --git a/hw/intc/xilinx_intc.c b/hw/intc/xilinx_intc.c
index a585ba1..010b080 100644
--- a/hw/intc/xilinx_intc.c
+++ b/hw/intc/xilinx_intc.c
@@ -49,11 +49,19 @@  struct xlx_pic
 
     /* Runtime control registers.  */
     uint32_t regs[R_MAX];
+    /* state of the interrupt input pins */
+    uint32_t irq_pin_state;
 };
 
 static void update_irq(struct xlx_pic *p)
 {
     uint32_t i;
+
+    /* level triggered interrupt */
+    if (p->regs[R_MER] & 2) {
+        p->regs[R_ISR] |= p->irq_pin_state & ~p->c_kind_of_intr;
+    }
+
     /* Update the pending register.  */
     p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER];
 
@@ -139,7 +147,13 @@  static void irq_handler(void *opaque, int irq, int level)
         return;
     }
 
-    p->regs[R_ISR] |= (level << irq);
+    /* edge triggered interrupt */
+    if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
+        p->regs[R_ISR] |= (level << irq);
+    }
+
+    p->irq_pin_state &= ~(1 << irq);
+    p->irq_pin_state |= level << irq;
     update_irq(p);
 }