Patchwork [v5,2/5] arm: make the number of GIC interrupts configurable

login
register
mail settings
Submitter Mark Langsdorf
Date Jan. 5, 2012, 8:02 p.m.
Message ID <1325793761-10249-3-git-send-email-mark.langsdorf@calxeda.com>
Download mbox | patch
Permalink /patch/134544/
State New
Headers show

Comments

Mark Langsdorf - Jan. 5, 2012, 8:02 p.m.
Increase the maximum number of GIC interrupts for a9mp and a11mp to 256,
and create a configurable property for each defaulting to 96 and 64
(respectively) so that device modelers can set the value appropriately
for their SoC. Other ARM processors also set their maximum number of
used IRQs appropriately.

Set the maximum theoretically number of GIC interrupts to 1020 and
update the save/restore code to only use the appropriate number for
each SoC.

Signed-off-by: Mark Langsdorf <mark.langsdorf@calxeda.com>
---
Changes from v4, v5
        None
Changes from v3
        Increase maximum number of GIC interrupts to 1020
        Remove SoC/implementation specific GIC_NIRQ #defs
        Added properties code to arm11mp
        Changed error handling for too many interrupts
        Redid save/load handling
Changes from v2
        Skipped
Changes from v1
        Increase the number of a9mp interrupts to 192
        Add a property defaulting to 96
        Add a num_irq member in the gic state structure
        Use the num_irq value as appropriate
        Add num_irq argument to gic_init()
        Add num_irq to various CPU calls to gic_init

 hw/a9mpcore.c     |    7 +++--
 hw/arm11mpcore.c  |   14 +++++++-----
 hw/arm_gic.c      |   57 +++++++++++++++++++++++++++++-----------------------
 hw/armv7m_nvic.c  |    7 ++---
 hw/realview_gic.c |    3 +-
 5 files changed, 48 insertions(+), 40 deletions(-)
Peter Maydell - Jan. 6, 2012, 3:37 p.m.
On 5 January 2012 20:02, Mark Langsdorf <mark.langsdorf@calxeda.com> wrote:
> Increase the maximum number of GIC interrupts for a9mp and a11mp to 256,
> and create a configurable property for each defaulting to 96 and 64
> (respectively) so that device modelers can set the value appropriately
> for their SoC. Other ARM processors also set their maximum number of
> used IRQs appropriately.
>
> Set the maximum theoretically number of GIC interrupts to 1020 and
> update the save/restore code to only use the appropriate number for
> each SoC.

This commit message is a bit out of sync with the actual changes.
The first line says "increase the maximum to 256", but actually the
maximum has been set to 1020 (as you say later in the message).

> @@ -216,6 +216,7 @@ static SysBusDeviceInfo a9mp_priv_info = {
>     .qdev.reset = a9mp_priv_reset,
>     .qdev.props = (Property[]) {
>         DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
> +        DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 256),

The default should stay the same as the old hard-coded value, ie 96.
(256 is the A9 hardware maximum. In theory we could stick a check in
that the property was <256, but I don't think there's any point.)
We can throw in this comment, mostly for consistency with the one in
the 11MPCore sources (see below):

/* The Cortex-A9MP may have anything from 0 to 224 external interrupt IRQ
 * lines (+ 32 internal). We default to 64+32, which is the number provided
 * by the Cortex-A9MP test chip in the Realview PBX-A9 and Versatile
 * Express A9 development boards. Other boards may differ and should set
 * this property appropriately.
 */

> @@ -221,6 +217,12 @@ static SysBusDeviceInfo mpcore_priv_info = {
>     .qdev.size  = sizeof(mpcore_priv_state),
>     .qdev.props = (Property[]) {
>         DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
> +        /* The MPCore TRM says the on-chip controller has 224 external
> +         * IRQ lines (+ 32 internal).  Some test chips only
> +         * expose/report 32. More importantly Linux falls over if more
> +         * than 32 are present!  Set the default to 64 and let chips
> +         * with more working lines set it higher */

Let's fix the inaccuracy in this comment while we're moving it around.

/* The ARM11 MPCore TRM says the on-chip controller may have anything
 * from 0 to 224 external interrupt IRQ lines (+ 32 internal). We default
 * to 32+32, which is the number provided by the ARM11 MPCore test
 * chip in the Realview Versatile EB coretile. Other boards may have
 * 11MPCores with different hardware config and should set this
 * property appropriately -- some Linux kernels may not boot if the hardware
 * has more IRQ lines than they expect.
 */

> diff --git a/hw/arm_gic.c b/hw/arm_gic.c
> index 0339cf5..5bfb01f 100644
> --- a/hw/arm_gic.c
> +++ b/hw/arm_gic.c
> @@ -11,6 +11,7 @@
>    controller, MPCore distributed interrupt controller and ARMv7-M
>    Nested Vectored Interrupt Controller.  */
>
> +#define GIC_NIRQ 1020

Having looked at the code that we get after this patch, I think it would be
a good idea to rename this macro now:

/* Maximum possible number of interrupts (this limit is imposed by
 * the GIC architecture)
 */
#define GIC_MAXIRQ 1020

(the renaming won't bloat the patch much as the macro's only used in
half a dozen places).

I think that will help to avoid confusion in future about the difference
between this and num_irq.

>  //#define DEBUG_GIC
>
>  #ifdef DEBUG_GIC
> @@ -111,6 +112,7 @@ typedef struct gic_state
>     struct gic_state *backref[NCPU];
>     MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
>  #endif
> +    int num_irq;

It seems a little inconsistent that we use a uint32_t in the properties
but a plain int in the gic_init() prototype and here. Does using uint32_t
throughout cause any problems?

> @@ -295,7 +297,7 @@ static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
>         else
>             irq = (offset - 0x180) * 8;
>         irq += GIC_BASE_IRQ;
> -        if (irq >= GIC_NIRQ)
> +        if (irq >= s->num_irq)
>             goto bad_reg;

If you like you can add the extra braces that will shut checkpatch up
about these hunks, but I'm not going to insist on it. (I waver back and
forth about how much I care about this particular CODING_STYLE
shibboleth. This file is one of the older ones that was written before
we decided we loved braces.)

> @@ -808,7 +810,12 @@ static void gic_init(gic_state *s)
>  #if NCPU > 1
>     s->num_cpu = num_cpu;
>  #endif
> -    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
> +    s->num_irq = num_irq;

For the benefit of M profile (see below for further explanation)
this should be
   s->num_irq = num_irq + GIC_BASE_IRQ;

> +    if (s->num_irq > GIC_NIRQ) {
> +        hw_error("device requested %u out of %u interrupt lines, failing\n",
> +                 num_irq, GIC_NIRQ);

"requested number of interrupt lines %d exceeds GIC maximum of %d"

(you can drop the "failing" bit because hw_error() prefixes the string
with "hardware error" and we end up saying "Aborted", so the fact
we're failing is pretty clear anyway :-))

> @@ -384,7 +381,9 @@ static int armv7m_nvic_init(SysBusDevice *dev)
>  {
>     nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
>
> -    gic_init(&s->gic);
> +   /* 32 internal lines (16 used for system exceptions) plus 64 external
> +    * interrupt lines.  */
> +    gic_init(&s->gic, 96);

This should have a property as well; the v7M architecture allows anything
up to 496 external interrupts. The default for the property should be 64,
meaning 64 external interrupts. (Not 96, because we'll add GIC_BASE_IRQ
to it in gic_init().)

The reason for this GIC_BASE_IRQ addition is that the M profile
specification doesn't consider the lines used for system exceptions
to be interrupts (they don't appear in the enable/set/clear register interfaces,
for example). Moreover, even where the architecture does consider
exceptions+interrupts as a continuous set, it goes 0..15 [exceptions]
and then 16 is external interrupt 0. The spacing of 32 is purely a QEMU
internal thing for implementation convenience, so we want to hide it from
the board-level users of armv7m_init() etc.

> @@ -37,7 +36,7 @@ static int realview_gic_init(SysBusDevice *dev)
>  {
>     RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
>
> -    gic_init(&s->gic);

You can add a comment here:
/* The GICs on the RealView boards have a fixed nonconfigurable
 * number of interrupt lines, so we don't need to expose this as
 * a qdev property.
 */

just to explain why this one's different to the others.

-- PMM

Patch

diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 3ef0e13..8c8b72b 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -11,9 +11,8 @@ 
 #include "sysbus.h"
 
 /* Configuration for arm_gic.c:
- * number of external IRQ lines, max number of CPUs, how to ID current CPU
+ * max number of CPUs, how to ID current CPU
  */
-#define GIC_NIRQ 96
 #define NCPU 4
 
 static inline int
@@ -37,6 +36,7 @@  typedef struct a9mp_priv_state {
     MemoryRegion ptimer_iomem;
     MemoryRegion container;
     DeviceState *mptimer;
+    uint32_t num_irq;
 } a9mp_priv_state;
 
 static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
@@ -153,7 +153,7 @@  static int a9mp_priv_init(SysBusDevice *dev)
         hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
     }
 
-    gic_init(&s->gic, s->num_cpu);
+    gic_init(&s->gic, s->num_cpu, s->num_irq);
 
     s->mptimer = qdev_create(NULL, "arm_mptimer");
     qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
@@ -216,6 +216,7 @@  static SysBusDeviceInfo a9mp_priv_info = {
     .qdev.reset = a9mp_priv_reset,
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
+        DEFINE_PROP_UINT32("num-irq", a9mp_priv_state, num_irq, 256),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index bc0457e..e4e4bb3 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -10,11 +10,6 @@ 
 #include "sysbus.h"
 #include "qemu-timer.h"
 
-/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
-   (+ 32 internal).  However my test chip only exposes/reports 32.
-   More importantly Linux falls over if more than 32 are present!  */
-#define GIC_NIRQ 64
-
 #define NCPU 4
 
 static inline int
@@ -37,6 +32,7 @@  typedef struct mpcore_priv_state {
     MemoryRegion iomem;
     MemoryRegion container;
     DeviceState *mptimer;
+    uint32_t num_irq;
 } mpcore_priv_state;
 
 /* Per-CPU private memory mapped IO.  */
@@ -132,7 +128,7 @@  static int mpcore_priv_init(SysBusDevice *dev)
 {
     mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
 
-    gic_init(&s->gic, s->num_cpu);
+    gic_init(&s->gic, s->num_cpu, GIC_NIRQ);
     s->mptimer = qdev_create(NULL, "arm_mptimer");
     qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
     qdev_init_nofail(s->mptimer);
@@ -221,6 +217,12 @@  static SysBusDeviceInfo mpcore_priv_info = {
     .qdev.size  = sizeof(mpcore_priv_state),
     .qdev.props = (Property[]) {
         DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+        /* The MPCore TRM says the on-chip controller has 224 external
+         * IRQ lines (+ 32 internal).  Some test chips only
+         * expose/report 32. More importantly Linux falls over if more
+         * than 32 are present!  Set the default to 64 and let chips
+         * with more working lines set it higher */
+        DEFINE_PROP_UINT32("num-irq", mpcore_priv_state, num_irq, 64),
         DEFINE_PROP_END_OF_LIST(),
     }
 };
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 0339cf5..5bfb01f 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -11,6 +11,7 @@ 
    controller, MPCore distributed interrupt controller and ARMv7-M
    Nested Vectored Interrupt Controller.  */
 
+#define GIC_NIRQ 1020
 //#define DEBUG_GIC
 
 #ifdef DEBUG_GIC
@@ -111,6 +112,7 @@  typedef struct gic_state
     struct gic_state *backref[NCPU];
     MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
 #endif
+    int num_irq;
 } gic_state;
 
 /* TODO: Many places that call this routine could be optimized.  */
@@ -133,7 +135,7 @@  static void gic_update(gic_state *s)
         }
         best_prio = 0x100;
         best_irq = 1023;
-        for (irq = 0; irq < GIC_NIRQ; irq++) {
+        for (irq = 0; irq < s->num_irq; irq++) {
             if (GIC_TEST_ENABLED(irq, cm) && GIC_TEST_PENDING(irq, cm)) {
                 if (GIC_GET_PRIORITY(irq, cpu) < best_prio) {
                     best_prio = GIC_GET_PRIORITY(irq, cpu);
@@ -222,7 +224,7 @@  static void gic_complete_irq(gic_state * s, int cpu, int irq)
     int update = 0;
     int cm = 1 << cpu;
     DPRINTF("EOI %d\n", irq);
-    if (irq >= GIC_NIRQ) {
+    if (irq >= s->num_irq) {
         /* This handles two cases:
          * 1. If software writes the ID of a spurious interrupt [ie 1023]
          * to the GICC_EOIR, the GIC ignores that write.
@@ -279,7 +281,7 @@  static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
         if (offset == 0)
             return s->enabled;
         if (offset == 4)
-            return ((GIC_NIRQ / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
+            return ((s->num_irq / 32) - 1) | ((NUM_CPU(s) - 1) << 5);
         if (offset < 0x08)
             return 0;
         if (offset >= 0x80) {
@@ -295,7 +297,7 @@  static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
         else
             irq = (offset - 0x180) * 8;
         irq += GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = 0;
         for (i = 0; i < 8; i++) {
@@ -310,7 +312,7 @@  static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
         else
             irq = (offset - 0x280) * 8;
         irq += GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = 0;
         mask = (irq < 32) ?  cm : ALL_CPU_MASK;
@@ -322,7 +324,7 @@  static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
     } else if (offset < 0x400) {
         /* Interrupt Active.  */
         irq = (offset - 0x300) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = 0;
         mask = (irq < 32) ?  cm : ALL_CPU_MASK;
@@ -334,14 +336,14 @@  static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
     } else if (offset < 0x800) {
         /* Interrupt Priority.  */
         irq = (offset - 0x400) + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = GIC_GET_PRIORITY(irq, cpu);
 #ifndef NVIC
     } else if (offset < 0xc00) {
         /* Interrupt CPU Target.  */
         irq = (offset - 0x800) + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq >= 29 && irq <= 31) {
             res = cm;
@@ -351,7 +353,7 @@  static uint32_t gic_dist_readb(void *opaque, target_phys_addr_t offset)
     } else if (offset < 0xf00) {
         /* Interrupt Configuration.  */
         irq = (offset - 0xc00) * 2 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         res = 0;
         for (i = 0; i < 4; i++) {
@@ -426,7 +428,7 @@  static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x180) {
         /* Interrupt Set Enable.  */
         irq = (offset - 0x100) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 16)
           value = 0xff;
@@ -451,7 +453,7 @@  static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x200) {
         /* Interrupt Clear Enable.  */
         irq = (offset - 0x180) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 16)
           value = 0;
@@ -468,7 +470,7 @@  static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x280) {
         /* Interrupt Set Pending.  */
         irq = (offset - 0x200) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 16)
           irq = 0;
@@ -481,7 +483,7 @@  static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x300) {
         /* Interrupt Clear Pending.  */
         irq = (offset - 0x280) * 8 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         for (i = 0; i < 8; i++) {
             /* ??? This currently clears the pending bit for all CPUs, even
@@ -497,7 +499,7 @@  static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0x800) {
         /* Interrupt Priority.  */
         irq = (offset - 0x400) + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 32) {
             s->priority1[irq][cpu] = value;
@@ -508,7 +510,7 @@  static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0xc00) {
         /* Interrupt CPU Target.  */
         irq = (offset - 0x800) + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 29)
             value = 0;
@@ -518,7 +520,7 @@  static void gic_dist_writeb(void *opaque, target_phys_addr_t offset,
     } else if (offset < 0xf00) {
         /* Interrupt Configuration.  */
         irq = (offset - 0xc00) * 4 + GIC_BASE_IRQ;
-        if (irq >= GIC_NIRQ)
+        if (irq >= s->num_irq)
             goto bad_reg;
         if (irq < 32)
             value |= 0xaa;
@@ -735,17 +737,17 @@  static void gic_save(QEMUFile *f, void *opaque)
         qemu_put_be32(f, s->cpu_enabled[i]);
         for (j = 0; j < 32; j++)
             qemu_put_be32(f, s->priority1[j][i]);
-        for (j = 0; j < GIC_NIRQ; j++)
+        for (j = 0; j < s->num_irq; j++)
             qemu_put_be32(f, s->last_active[j][i]);
         qemu_put_be32(f, s->priority_mask[i]);
         qemu_put_be32(f, s->running_irq[i]);
         qemu_put_be32(f, s->running_priority[i]);
         qemu_put_be32(f, s->current_pending[i]);
     }
-    for (i = 0; i < GIC_NIRQ - 32; i++) {
+    for (i = 0; i < s->num_irq - 32; i++) {
         qemu_put_be32(f, s->priority2[i]);
     }
-    for (i = 0; i < GIC_NIRQ; i++) {
+    for (i = 0; i < s->num_irq; i++) {
 #ifndef NVIC
         qemu_put_be32(f, s->irq_target[i]);
 #endif
@@ -772,17 +774,17 @@  static int gic_load(QEMUFile *f, void *opaque, int version_id)
         s->cpu_enabled[i] = qemu_get_be32(f);
         for (j = 0; j < 32; j++)
             s->priority1[j][i] = qemu_get_be32(f);
-        for (j = 0; j < GIC_NIRQ; j++)
+        for (j = 0; j < s->num_irq; j++)
             s->last_active[j][i] = qemu_get_be32(f);
         s->priority_mask[i] = qemu_get_be32(f);
         s->running_irq[i] = qemu_get_be32(f);
         s->running_priority[i] = qemu_get_be32(f);
         s->current_pending[i] = qemu_get_be32(f);
     }
-    for (i = 0; i < GIC_NIRQ - 32; i++) {
+    for (i = 0; i < s->num_irq - 32; i++) {
         s->priority2[i] = qemu_get_be32(f);
     }
-    for (i = 0; i < GIC_NIRQ; i++) {
+    for (i = 0; i < s->num_irq; i++) {
 #ifndef NVIC
         s->irq_target[i] = qemu_get_be32(f);
 #endif
@@ -798,9 +800,9 @@  static int gic_load(QEMUFile *f, void *opaque, int version_id)
 }
 
 #if NCPU > 1
-static void gic_init(gic_state *s, int num_cpu)
+static void gic_init(gic_state *s, int num_cpu, int num_irq)
 #else
-static void gic_init(gic_state *s)
+static void gic_init(gic_state *s, int num_irq)
 #endif
 {
     int i;
@@ -808,7 +810,12 @@  static void gic_init(gic_state *s)
 #if NCPU > 1
     s->num_cpu = num_cpu;
 #endif
-    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, GIC_NIRQ - 32);
+    s->num_irq = num_irq;
+    if (s->num_irq > GIC_NIRQ) {
+        hw_error("device requested %u out of %u interrupt lines, failing\n",
+                 num_irq, GIC_NIRQ);
+    }
+    qdev_init_gpio_in(&s->busdev.qdev, gic_set_irq, s->num_irq - 32);
     for (i = 0; i < NUM_CPU(s); i++) {
         sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
     }
diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c
index bf8c3c5..0de51f4 100644
--- a/hw/armv7m_nvic.c
+++ b/hw/armv7m_nvic.c
@@ -15,9 +15,6 @@ 
 #include "arm-misc.h"
 #include "exec-memory.h"
 
-/* 32 internal lines (16 used for system exceptions) plus 64 external
-   interrupt lines.  */
-#define GIC_NIRQ 96
 #define NCPU 1
 #define NVIC 1
 
@@ -384,7 +381,9 @@  static int armv7m_nvic_init(SysBusDevice *dev)
 {
     nvic_state *s= FROM_SYSBUSGIC(nvic_state, dev);
 
-    gic_init(&s->gic);
+   /* 32 internal lines (16 used for system exceptions) plus 64 external
+    * interrupt lines.  */
+    gic_init(&s->gic, 96);
     memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->gic.iomem);
     s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s);
     vmstate_register(&dev->qdev, -1, &vmstate_nvic, s);
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 8c4d509..cd7e53d 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -9,7 +9,6 @@ 
 
 #include "sysbus.h"
 
-#define GIC_NIRQ 96
 #define NCPU 1
 
 /* Only a single "CPU" interface is present.  */
@@ -37,7 +36,7 @@  static int realview_gic_init(SysBusDevice *dev)
 {
     RealViewGICState *s = FROM_SYSBUSGIC(RealViewGICState, dev);
 
-    gic_init(&s->gic);
+    gic_init(&s->gic, 96);
     realview_gic_map_setup(s);
     sysbus_init_mmio(dev, &s->container);
     return 0;