diff mbox

[v2,14/22] hw/intc/arm_gicv3: Implement gicv3_set_irq()

Message ID 1464274540-19693-15-git-send-email-peter.maydell@linaro.org
State New
Headers show

Commit Message

Peter Maydell May 26, 2016, 2:55 p.m. UTC
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>
---
 hw/intc/arm_gicv3.c        | 20 +++++++++++++++++++-
 hw/intc/arm_gicv3_dist.c   | 21 +++++++++++++++++++++
 hw/intc/arm_gicv3_redist.c | 21 +++++++++++++++++++++
 hw/intc/gicv3_internal.h   |  2 ++
 trace-events               |  2 ++
 5 files changed, 65 insertions(+), 1 deletion(-)

Comments

Shannon Zhao June 13, 2016, 7:49 a.m. UTC | #1
On 2016/5/26 22:55, Peter Maydell wrote:
> 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>
> ---
>  hw/intc/arm_gicv3.c        | 20 +++++++++++++++++++-
>  hw/intc/arm_gicv3_dist.c   | 21 +++++++++++++++++++++
>  hw/intc/arm_gicv3_redist.c | 21 +++++++++++++++++++++
>  hw/intc/gicv3_internal.h   |  2 ++
>  trace-events               |  2 ++
>  5 files changed, 65 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
> index e8f6766..e770409 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 >= 16 && irq < 32);
Nit: Use GIC_NR_SGIS instead and irq < 32 is unnecessary.

Reviewed-by: Shannon Zhao <shannon.zhao@linaro.org>
Peter Maydell June 13, 2016, 9:07 a.m. UTC | #2
On 13 June 2016 at 08:49, Shannon Zhao <zhaoshenglong@huawei.com> wrote:
>
>
> On 2016/5/26 22:55, Peter Maydell wrote:
>> 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>
>> ---
>>  hw/intc/arm_gicv3.c        | 20 +++++++++++++++++++-
>>  hw/intc/arm_gicv3_dist.c   | 21 +++++++++++++++++++++
>>  hw/intc/arm_gicv3_redist.c | 21 +++++++++++++++++++++
>>  hw/intc/gicv3_internal.h   |  2 ++
>>  trace-events               |  2 ++
>>  5 files changed, 65 insertions(+), 1 deletion(-)
>>
>> diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
>> index e8f6766..e770409 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 >= 16 && irq < 32);
> Nit: Use GIC_NR_SGIS instead and irq < 32 is unnecessary.

Fixed, thanks.

-- PMM
diff mbox

Patch

diff --git a/hw/intc/arm_gicv3.c b/hw/intc/arm_gicv3.c
index e8f6766..e770409 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 >= 16 && irq < 32);
+        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 6ccb4d9..1634974 100644
--- a/hw/intc/arm_gicv3_dist.c
+++ b/hw/intc/arm_gicv3_dist.c
@@ -850,3 +850,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 18dc0c8..16b3422 100644
--- a/hw/intc/arm_gicv3_redist.c
+++ b/hw/intc/arm_gicv3_redist.c
@@ -493,3 +493,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 39196fa..8ae6d66 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:
diff --git a/trace-events b/trace-events
index 308d458..c006723 100644
--- a/trace-events
+++ b/trace-events
@@ -1922,9 +1922,11 @@  gicv3_dist_read(uint64_t offset, uint64_t data, unsigned size, bool secure) "GIC
 gicv3_dist_badread(uint64_t offset, unsigned size, bool secure) "GICv3 distributor read: offset 0x%" PRIx64 " size %u secure %d: error"
 gicv3_dist_write(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_dist_badwrite(uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 distributor write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
+gicv3_dist_set_irq(int irq, int level) "GICv3 distributor interrupt %d level changed to %d"
 
 # hw/intc/arm_gicv3_redist.c
 gicv3_redist_read(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_redist_badread(uint32_t cpu, uint64_t offset, unsigned size, bool secure) "GICv3 redistributor %x read: offset 0x%" PRIx64 " size %u secure %d: error"
 gicv3_redist_write(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d"
 gicv3_redist_badwrite(uint32_t cpu, uint64_t offset, uint64_t data, unsigned size, bool secure) "GICv3 redistributor %x write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u secure %d: error"
+gicv3_redist_set_irq(uint32_t cpu, int irq, int level) "GICv3 redistributor %x interrupt %d level changed to %d"