summary refs log tree commit diff stats
path: root/hw/intc
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-06-17 15:23:47 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-06-17 15:23:51 +0100
commitc84428b33fc2d88f17c3f599a9e5d17ae23422c1 (patch)
tree7b90ac41e1d64014bbf87d6afd7065f6ccd03560 /hw/intc
parent287c181ae4132d7cc75ea422051f2c90e90b6493 (diff)
downloadfocaccia-qemu-c84428b33fc2d88f17c3f599a9e5d17ae23422c1.tar.gz
focaccia-qemu-c84428b33fc2d88f17c3f599a9e5d17ae23422c1.zip
hw/intc/arm_gicv3: Implement gicv3_set_irq()
Implement the code which updates the GIC state when an interrupt
input into the GIC is asserted.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Tested-by: Shannon Zhao <shannon.zhao@linaro.org>
Message-id: 1465915112-29272-15-git-send-email-peter.maydell@linaro.org
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/arm_gicv3.c20
-rw-r--r--hw/intc/arm_gicv3_dist.c21
-rw-r--r--hw/intc/arm_gicv3_redist.c21
-rw-r--r--hw/intc/gicv3_internal.h2
4 files changed, 63 insertions, 1 deletions
diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index 4c1fbb6850..65ebca2e0a 100644
--- a/hw/intc/arm_gicv3.c
+++ b/hw/intc/arm_gicv3.c
@@ -311,7 +311,25 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
      *  [N+32..N+63] : PPI (internal interrupts for CPU 1
      *  ...
      */
-    /* Do nothing for now */
+    GICv3State *s = opaque;
+
+    if (irq < (s->num_irq - GIC_INTERNAL)) {
+        /* external interrupt (SPI) */
+        gicv3_dist_set_irq(s, irq + GIC_INTERNAL, level);
+    } else {
+        /* per-cpu interrupt (PPI) */
+        int cpu;
+
+        irq -= (s->num_irq - GIC_INTERNAL);
+        cpu = irq / GIC_INTERNAL;
+        irq %= GIC_INTERNAL;
+        assert(cpu < s->num_cpu);
+        /* Raising SGIs via this function would be a bug in how the board
+         * model wires up interrupts.
+         */
+        assert(irq >= GIC_NR_SGIS);
+        gicv3_redist_set_irq(&s->cpu[cpu], irq, level);
+    }
 }
 
 static void arm_gicv3_post_load(GICv3State *s)
diff --git a/hw/intc/arm_gicv3_dist.c b/hw/intc/arm_gicv3_dist.c
index 881d5556c1..b977ae5984 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -856,3 +856,24 @@ MemTxResult gicv3_dist_write(void *opaque, hwaddr offset, uint64_t data,
     }
     return r;
 }
+
+void gicv3_dist_set_irq(GICv3State *s, int irq, int level)
+{
+    /* Update distributor state for a change in an external SPI input line */
+    if (level == gicv3_gicd_level_test(s, irq)) {
+        return;
+    }
+
+    trace_gicv3_dist_set_irq(irq, level);
+
+    gicv3_gicd_level_replace(s, irq, level);
+
+    if (level) {
+        /* 0->1 edges latch the pending bit for edge-triggered interrupts */
+        if (gicv3_gicd_edge_trigger_test(s, irq)) {
+            gicv3_gicd_pending_set(s, irq);
+        }
+    }
+
+    gicv3_update(s, irq, 1);
+}
diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
index e0f23e150a..1130eee988 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -499,3 +499,24 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
     }
     return r;
 }
+
+void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
+{
+    /* Update redistributor state for a change in an external PPI input line */
+    if (level == extract32(cs->level, irq, 1)) {
+        return;
+    }
+
+    trace_gicv3_redist_set_irq(gicv3_redist_affid(cs), irq, level);
+
+    cs->level = deposit32(cs->level, irq, 1, level);
+
+    if (level) {
+        /* 0->1 edges latch the pending bit for edge-triggered interrupts */
+        if (extract32(cs->edge_trigger, irq, 1)) {
+            cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 1);
+        }
+    }
+
+    gicv3_redist_update(cs);
+}
diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
index b70e052ddf..a6f443cef6 100644
--- a/hw/intc/gicv3_internal.h
+++ b/hw/intc/gicv3_internal.h
@@ -209,6 +209,8 @@ MemTxResult gicv3_redist_read(void *opaque, hwaddr offset, uint64_t *data,
                               unsigned size, MemTxAttrs attrs);
 MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
                                unsigned size, MemTxAttrs attrs);
+void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
+void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
 
 /**
  * gicv3_cpuif_update: