Skip to contentSkip to conversation

Xilinx Intc Fixes

PATCH Applied [email protected] 2 participants 10 messages Jun 7, 2013 – Jun 11, 2013 Arm/Zynq architecture

v1 of 2 Applied Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover Xilinx Intc Fixes

From: Peter Crosthwaite <[email protected]>

Various fixups to the Xilinx Interrupt controller following a review against TRM and RTL descriptions.

Tested as working for microblazeel Linux.

Peter Crosthwaite (5):
intc/xilinx_intc: Use qemu_set_irq intc/xilinx_intc: Don't clear level sens. IRQs without ACK intc/xilinx_intc: Handle level interrupt retriggering intc/xilinx_intc: Inhibit write to ISR when HIE intc/xilinx_intc: Dont lower IRQ when HIE cleared

 hw/intc/xilinx_intc.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)
Signature · 1 line
1.8.3.rc1.44.gb387c77.dirty
#1 lore raw

PATCH 1/5 intc/xilinx_intc: Use qemu_set_irq

From: Peter Crosthwaite <[email protected]>

Use qemu_set_irq rather than if-elsing qemu_irq_(lower|raise). No functional change, just reduces verbosity.

---

 hw/intc/xilinx_intc.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
hw/intc/xilinx_intc.c +1 -5
index b106e72..5df7008 100644
@@ -66,11 +66,7 @@ static void update_irq(struct xlx_pic *p)
         i = ~0;
 
     p->regs[R_IVR] = i;
-    if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
-        qemu_irq_raise(p->parent_irq);
-    } else {
-        qemu_irq_lower(p->parent_irq);
-    }
+    qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
 }
 
 static uint64_t
Signature · 1 line
1.8.3.rc1.44.gb387c77.dirty
#2 lore raw

Re: [Qemu-devel] [PATCH v1 1/5] intc/xilinx_intc: Use qemu_set_irq

email accidentally sent with cc supression, so cc qemu-trivial as intended.

Quoted 33 lines · On Fri, Jun 7, 2013 at 12:38 PM, <[email protected]> wrote:

From: Peter Crosthwaite <[email protected]>

Use qemu_set_irq rather than if-elsing qemu_irq_(lower|raise). No functional change, just reduces verbosity.

---

 hw/intc/xilinx_intc.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)
hw/intc/xilinx_intc.c +1 -6
index b106e72..5df7008 100644
@@ -66,11 +66,7 @@ static void update_irq(struct xlx_pic *p)
         i = ~0;
 
     p->regs[R_IVR] = i;
-    if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) {
-        qemu_irq_raise(p->parent_irq);
-    } else {
-        qemu_irq_lower(p->parent_irq);
-    }
+    qemu_set_irq(p->parent_irq, (p->regs[R_MER] & 1) && p->regs[R_IPR]);
 }
 
 static uint64_t
--

1.8.3.rc1.44.gb387c77.dirty

#3 lore raw

Re: [Qemu-devel] [Qemu-trivial] [PATCH v1 1/5] intc/xilinx_intc: Use qemu_set_irq

Quoted 2 lines · Peter Crosthwaite
Quoted 2 lines

Use qemu_set_irq rather than if-elsing qemu_irq_(lower|raise). No functional change, just reduces verbosity.

Thanks, applied to the trivial patches queue.

/mjt

#4 lore raw

Re: [Qemu-devel] [Qemu-trivial] [PATCH v1 1/5] intc/xilinx_intc: Use qemu_set_irq

Quoted 6 lines · Michael Tokarev
Quoted 2 lines · Peter Crosthwaite
Quoted 2 lines

Use qemu_set_irq rather than if-elsing qemu_irq_(lower|raise). No functional change, just reduces verbosity.

Thanks, applied to the trivial patches queue.

Thanks,

I need to respin the later patches in this series but as you have taken this ill drop it from the respin. No conflict issues.

Regards,
Peter

Quoted 2 lines

/mjt

#5 lore raw

Re: [Qemu-devel] [Qemu-trivial] [PATCH v1 1/5] intc/xilinx_intc: Use qemu_set_irq

Quoted 5 lines · Peter Crosthwaite
Quoted 1 line · Michael Tokarev

Thanks, applied to the trivial patches queue.

I need to respin the later patches in this series but as you have taken this ill drop it from the respin. No conflict issues.

heh. I haven't even noticed this is 1/5 ;)

Please don't send just some patches from a series for applying to other trees. Because if you do the respin, at least in some cases you'll have to wait for the applied bits to reach master first... ;)

It's as trivial to remove this one from -trivial as to keep it there, it's your call ;)

Thanks,

/mjt

#6 lore raw

PATCH 2/5 intc/xilinx_intc: Don't clear level sens. IRQs without ACK

In reply to [email protected]

From: Peter Crosthwaite <[email protected]>

For level sensitive interrupts, ISR bits are cleared when the input pin is lowered. This is incorrect. Only software can clear ISR bits (via IAR or direct write to ISR with !MER(2)).

---

 hw/intc/xilinx_intc.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)
hw/intc/xilinx_intc.c +1 -7
index 5df7008..d243a00 100644
@@ -135,13 +135,7 @@ static void irq_handler(void *opaque, int irq, int level)
         return;
     }
 
-    /* Update source flops. Don't clear unless level triggered.
-       Edge triggered interrupts only go away when explicitely acked to
-       the interrupt controller.  */
-    if (!(p->c_kind_of_intr & (1 << irq)) || level) {
-        p->regs[R_ISR] &= ~(1 << irq);
-        p->regs[R_ISR] |= (level << irq);
-    }
+    p->regs[R_ISR] |= (level << irq);
     update_irq(p);
 }
 
Signature · 1 line
1.8.3.rc1.44.gb387c77.dirty
#7 lore raw

PATCH 3/5 intc/xilinx_intc: Handle level interrupt retriggering

In reply to [email protected]

From: Peter Crosthwaite <[email protected]>

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.

---

 hw/intc/xilinx_intc.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)
hw/intc/xilinx_intc.c +15 -1
index d243a00..09b4453 100644
@@ -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];
 
@@ -135,7 +143,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);
 }
 
Signature · 1 line
1.8.3.rc1.44.gb387c77.dirty
#8 lore raw

PATCH 4/5 intc/xilinx_intc: Inhibit write to ISR when HIE

In reply to [email protected]

From: Peter Crosthwaite <[email protected]>

When the Hardware Interrupt Enable (HIE) bit is set, software cannot change ISR. Add write guard accordingly.

---

 hw/intc/xilinx_intc.c | 5 +++++
 1 file changed, 5 insertions(+)
hw/intc/xilinx_intc.c +5 -0
index 09b4453..ddedfa3 100644
@@ -116,6 +116,11 @@ pic_write(void *opaque, hwaddr addr,
         case R_CIE:
             p->regs[R_IER] &= ~value; /* Atomic clear ie.  */
             break;
+        case R_ISR:
+            if ((p->regs[R_MER] & 2)) {
+                break;
+            }
+            /* fallthrough */
         default:
             if (addr < ARRAY_SIZE(p->regs))
                 p->regs[addr] = value;
Signature · 1 line
1.8.3.rc1.44.gb387c77.dirty
#9 lore raw

PATCH 5/5 intc/xilinx_intc: Dont lower IRQ when HIE cleared

In reply to [email protected]

From: Peter Crosthwaite <[email protected]>

This is a little strange. It is lowering the parent IRQ pin on input when HIE is cleared. There is no such behaviour in the real hardware.

ISR changes based on interrupt pin state are already guarded on HIE being set. So we can just delete this if in its entirety.

---

 hw/intc/xilinx_intc.c | 5 -----
 1 file changed, 5 deletions(-)
hw/intc/xilinx_intc.c +0 -5
index ddedfa3..297f537 100644
@@ -143,11 +143,6 @@ static void irq_handler(void *opaque, int irq, int level)
 {
     struct xlx_pic *p = opaque;
 
-    if (!(p->regs[R_MER] & 2)) {
-        qemu_irq_lower(p->parent_irq);
-        return;
-    }
-
     /* edge triggered interrupt */
     if (p->c_kind_of_intr & (1 << irq) && p->regs[R_MER] & 2) {
         p->regs[R_ISR] |= (level << irq);
Signature · 1 line
1.8.3.rc1.44.gb387c77.dirty