qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 3/4] mips: add Global Interrupt Controller


From: Leon Alrae
Subject: Re: [Qemu-devel] [PATCH 3/4] mips: add Global Interrupt Controller
Date: Wed, 21 Oct 2015 16:49:08 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.2.0

On 16/10/15 00:52, Yongbok Kim wrote:
> The Global Interrupt Controller (GIC) is responsible for mapping each
> internal and external interrupt to the correct location for servicing.
> 
> Limitations:
> Level triggering only
> No User-Mode Visible Section
> GIC CounterHi not implemented (Countbits = 32bits)
> DINT not implemented
> Local WatchDog, Fast Debug Channel, Perf Counter not implemented
> 
> Signed-off-by: Yongbok Kim <address@hidden>
> ---
>  hw/mips/Makefile.objs |    2 +-
>  hw/mips/mips_gic.c    |  653 
> +++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/mips/mips_gic.h    |  298 ++++++++++++++++++++++

Files are in mips directory thus "mips_" prefix seems redundant.

>  3 files changed, 952 insertions(+), 1 deletions(-)
>  create mode 100644 hw/mips/mips_gic.c
>  create mode 100644 hw/mips/mips_gic.h
> 
> diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs
> index d247d95..6cd9d67 100644
> --- a/hw/mips/Makefile.objs
> +++ b/hw/mips/Makefile.objs
> @@ -1,5 +1,5 @@
>  obj-y += mips_r4k.o mips_malta.o mips_mipssim.o
> -obj-y += addr.o cputimer.o mips_int.o mips_gcr.o
> +obj-y += addr.o cputimer.o mips_int.o mips_gcr.o mips_gic.o
>  obj-$(CONFIG_JAZZ) += mips_jazz.o
>  obj-$(CONFIG_FULONG) += mips_fulong2e.o
>  obj-y += gt64xxx_pci.o
> diff --git a/hw/mips/mips_gic.c b/hw/mips/mips_gic.c
> new file mode 100644
> index 0000000..27ae7ab
> --- /dev/null
> +++ b/hw/mips/mips_gic.c
> @@ -0,0 +1,653 @@
> +/*
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License.  See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2012  MIPS Technologies, Inc.  All rights reserved.
> + * Authors: Sanjay Lal <address@hidden>
> + *
> + * Copyright (C) 2015 Imagination Technologies
> + */
> +
> +#include "hw/hw.h"
> +#include "hw/sysbus.h"
> +#include "qemu/bitmap.h"
> +#include "exec/memory.h"
> +#include "sysemu/sysemu.h"
> +#include "qom/cpu.h"
> +#include "exec/address-spaces.h"
> +
> +#ifdef CONFIG_KVM
> +#include "sysemu/kvm.h"
> +#include "kvm_mips.h"
> +#endif
> +
> +#include "hw/mips/mips_gic.h"
> +
> +#define TIMER_PERIOD 10 /* 10 ns period for 100 Mhz frequency */
> +
> +static inline int gic_get_current_cpu(MIPSGICState *g)
> +{
> +    if (g->num_cpu > 1) {
> +        return current_cpu->cpu_index;
> +    }
> +    return 0;
> +}
> +
> +static void gic_set_vp_irq(MIPSGICState *gic, int vpe, int pin, int level)
> +{
> +    int ored_level = level;
> +    int i;
> +    /* ORing pending registers sharing same pin */
> +    if (!ored_level) {
> +        for (i = 0; i < gic->num_irq; i++) {
> +            if ((gic->gic_irqs[i].map_pin & GIC_MAP_MSK) == pin &&
> +                    gic->gic_irqs[i].map_vpe == vpe &&
> +                    gic->gic_irqs[i].enabled) {
> +                ored_level |= gic->gic_irqs[i].pending;
> +            }
> +            if (ored_level) {
> +                /* no need to iterate all interrupts */
> +                break;
> +            }
> +        }

I think we should keep information which pins are shared, so we wouldn't
need to check all the gic pins every time.

> +        if (((gic->vps[vpe].compare_map & GIC_MAP_MSK) == pin) &&
> +                (gic->vps[vpe].mask & GIC_VPE_SMASK_CMP_MSK)) {
> +            /* ORing with local pending register (count/compare) */
> +            ored_level |= ((gic->vps[vpe].pend >> 1) & 1);
> +        }
> +    }
> +
> +#ifdef CONFIG_KVM
> +    if (kvm_enabled())  {
> +        kvm_mips_set_ipi_interrupt(gic->vps[vpe].env, pin + 
> GIC_CPU_PIN_OFFSET,
> +                                   ored_level);
> +    }
> +#endif
> +    qemu_set_irq(gic->vps[vpe].env->irq[pin + GIC_CPU_PIN_OFFSET], 
> ored_level);
> +}
> +
> +/* GIC VPE Local Timer */
> +static uint32_t gic_vpe_timer_update(MIPSGICState *gic, uint32_t vp_index)
> +{
> +    uint64_t now, next;
> +    uint32_t wait;
> +
> +    now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +    wait = gic->vps[vp_index].comparelo - gic->gic_sh_counterlo -
> +            (uint32_t)(now / TIMER_PERIOD);
> +    next = now + (uint64_t)wait * TIMER_PERIOD;
> +
> +    timer_mod(gic->vps[vp_index].gic_timer->qtimer , next);
> +    return wait;
> +}
> +
> +static void gic_vpe_timer_expire(MIPSGICState *gic, uint32_t vp_index)
> +{
> +    uint32_t pin;
> +    pin = (gic->vps[vp_index].compare_map & GIC_MAP_MSK);
> +    gic_vpe_timer_update(gic, vp_index);
> +    gic->vps[vp_index].pend |= (1 << 1);
> +
> +    if (gic->vps[vp_index].pend &
> +            (gic->vps[vp_index].mask & GIC_VPE_SMASK_CMP_MSK)) {
> +        if (gic->vps[vp_index].compare_map & 0x80000000) {
> +            /* it is safe to set the irq high regardless of other GIC IRQs */
> +            qemu_irq_raise(gic->vps[vp_index].env->irq
> +                           [pin + GIC_CPU_PIN_OFFSET]);
> +        }
> +    }
> +}
> +
> +static uint32_t gic_get_sh_count(MIPSGICState *gic)
> +{
> +    int i;
> +    if (gic->gic_sh_config & (1 << 28)) {
> +        return gic->gic_sh_counterlo;
> +    } else {
> +        uint64_t now;
> +        now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> +        for (i = 0; i < gic->num_cpu; i++) {
> +            if (timer_pending(gic->vps[i].gic_timer->qtimer)
> +                && timer_expired(gic->vps[i].gic_timer->qtimer , now)) {
> +                /* The timer has already expired.  */
> +                gic_vpe_timer_expire(gic, i);
> +            }
> +        }
> +        return gic->gic_sh_counterlo + (uint32_t)(now / TIMER_PERIOD);
> +    }
> +}
> +
> +static void gic_store_sh_count(MIPSGICState *gic, uint64_t count)
> +{
> +    int i;
> +
> +    if ((gic->gic_sh_config & 0x10000000) || !gic->vps[0].gic_timer) {
> +        gic->gic_sh_counterlo = count;
> +    } else {
> +        /* Store new count register */
> +        gic->gic_sh_counterlo = count -
> +            (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
> +        /* Update timer timer */
> +        for (i = 0; i < gic->num_cpu; i++) {
> +            gic_vpe_timer_update(gic, i);
> +        }
> +    }
> +}
> +
> +static void gic_store_vpe_compare(MIPSGICState *gic, uint32_t vp_index,
> +                                  uint64_t compare)
> +{
> +    uint32_t wait;
> +
> +    gic->vps[vp_index].comparelo = (uint32_t) compare;
> +    wait = gic_vpe_timer_update(gic, vp_index);

wait isn't used anywhere in this function.

> +
> +    gic->vps[vp_index].pend &= ~(1 << 1);
> +    if (gic->vps[vp_index].compare_map & 0x80000000) {
> +        uint32_t pin = (gic->vps[vp_index].compare_map & GIC_MAP_MSK);
> +        gic_set_vp_irq(gic, vp_index, pin, 0);
> +    }
> +}
> +
> +static void gic_vpe_timer_cb(void *opaque)
> +{
> +    MIPSGICTimerState *gic_timer = opaque;
> +    gic_timer->gic->gic_sh_counterlo++;
> +    gic_vpe_timer_expire(gic_timer->gic, gic_timer->vp_index);
> +    gic_timer->gic->gic_sh_counterlo--;
> +}
> +
> +static void gic_timer_start_count(MIPSGICState *gic)
> +{
> +    gic_store_sh_count(gic, gic->gic_sh_counterlo);
> +}
> +
> +static void gic_timer_stop_count(MIPSGICState *gic)
> +{
> +    int i;
> +
> +    /* Store the current value */
> +    gic->gic_sh_counterlo +=
> +        (uint32_t)(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / TIMER_PERIOD);
> +    for (i = 0; i < gic->num_cpu; i++) {
> +        timer_del(gic->vps[i].gic_timer->qtimer);
> +    }
> +}
> +
> +static void gic_timer_init(MIPSGICState *gic, uint32_t ncpus)
> +{
> +    int i;
> +    for (i = 0; i < ncpus; i++) {
> +        gic->vps[i].gic_timer = g_malloc0(sizeof(MIPSGICTimerState));
> +        gic->vps[i].gic_timer->gic = gic;
> +        gic->vps[i].gic_timer->vp_index = i;
> +        gic->vps[i].gic_timer->qtimer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
> +                                               &gic_vpe_timer_cb,
> +                                               gic->vps[i].gic_timer);
> +    }
> +    gic_store_sh_count(gic, gic->gic_sh_counterlo);
> +}

You could consider moving the gic timer stuff into a separate file.

> +
> +/* GIC Read VPE Local/Other Registers */
> +static uint64_t gic_read_vpe(MIPSGICState *gic, uint32_t vp_index, hwaddr 
> addr,
> +                             unsigned size)
> +{
> +    switch (addr) {
> +    case GIC_VPE_CTL_OFS:
> +        return gic->vps[vp_index].ctl;
> +    case GIC_VPE_PEND_OFS:
> +        gic_get_sh_count(gic);
> +        return gic->vps[vp_index].pend;
> +    case GIC_VPE_MASK_OFS:
> +        return gic->vps[vp_index].mask;
> +    case GIC_VPE_WD_MAP_OFS:
> +        return gic->vps[vp_index].wd_map;
> +    case GIC_VPE_COMPARE_MAP_OFS:
> +        return gic->vps[vp_index].compare_map;
> +    case GIC_VPE_TIMER_MAP_OFS:
> +        return gic->vps[vp_index].timer_map;
> +    case GIC_VPE_OTHER_ADDR_OFS:
> +        return gic->vps[vp_index].other_addr;
> +    case GIC_VPE_IDENT_OFS:
> +        return vp_index;
> +    case GIC_VPE_COMPARE_LO_OFS:
> +        return gic->vps[vp_index].comparelo;
> +    case GIC_VPE_COMPARE_HI_OFS:
> +        return gic->vps[vp_index].comparehi;
> +    default:
> +        qemu_log_mask(LOG_UNIMP,
> +                     "Warning *** read %d bytes at GIC offset LOCAL/OTHER 
> 0x%"
> +                     PRIx64 "\n",
> +                     size, addr);
> +        break;
> +    }
> +    return 0;
> +}
> +
> +static uint64_t gic_read(void *opaque, hwaddr addr, unsigned size)
> +{
> +    MIPSGICState *gic = (MIPSGICState *) opaque;
> +    uint32_t vp_index = gic_get_current_cpu(gic);
> +    uint64_t ret = 0;
> +    int i, base;

base is set in a few places below but isn't used anywhere.

> +
> +    switch (addr) {
> +    case GIC_SH_CONFIG_OFS:
> +        return gic->gic_sh_config;
> +    case GIC_SH_CONFIG_OFS + 4:
> +        /* do nothing */
> +        return 0;
> +    case GIC_SH_COUNTERLO_OFS:
> +        ret = gic_get_sh_count(gic);
> +        return ret;
> +    case GIC_SH_COUNTERHI_OFS:
> +        return 0;
> +    case GIC_SH_POL_31_0_OFS:
> +    case GIC_SH_POL_63_32_OFS:
> +    case GIC_SH_POL_95_64_OFS:
> +    case GIC_SH_POL_127_96_OFS:
> +    case GIC_SH_POL_159_128_OFS:
> +    case GIC_SH_POL_191_160_OFS:
> +    case GIC_SH_POL_223_192_OFS:
> +    case GIC_SH_POL_255_224_OFS:
> +        base = (addr - GIC_SH_POL_31_0_OFS) * 8;
> +        for (i = 0; i < size * 8; i++) {
> +            ret |= (gic->gic_irqs[i].polarity & 1) << i;
> +        }
> +        return ret;
> +    case GIC_SH_TRIG_31_0_OFS:
> +    case GIC_SH_TRIG_63_32_OFS:
> +    case GIC_SH_TRIG_95_64_OFS:
> +    case GIC_SH_TRIG_127_96_OFS:
> +    case GIC_SH_TRIG_159_128_OFS:
> +    case GIC_SH_TRIG_191_160_OFS:
> +    case GIC_SH_TRIG_223_192_OFS:
> +    case GIC_SH_TRIG_255_224_OFS:
> +        base = (addr - GIC_SH_TRIG_31_0_OFS) * 8;
> +        for (i = 0; i < size * 8; i++) {
> +            ret |= (gic->gic_irqs[i].trigger_type & 1) << i;
> +        }
> +        return ret;
> +    case GIC_SH_PEND_31_0_OFS:
> +    case GIC_SH_PEND_63_32_OFS:
> +    case GIC_SH_PEND_95_64_OFS:
> +    case GIC_SH_PEND_127_96_OFS:
> +    case GIC_SH_PEND_159_128_OFS:
> +    case GIC_SH_PEND_191_160_OFS:
> +    case GIC_SH_PEND_223_192_OFS:
> +    case GIC_SH_PEND_255_224_OFS:
> +        base = (addr - GIC_SH_PEND_31_0_OFS) * 8;
> +        for (i = 0; i < size * 8; i++) {
> +            ret |= (gic->gic_irqs[i].pending & 1) << i;
> +        }
> +        return ret;
> +    case GIC_SH_MASK_31_0_OFS:
> +    case GIC_SH_MASK_63_32_OFS:
> +    case GIC_SH_MASK_95_64_OFS:
> +    case GIC_SH_MASK_127_96_OFS:
> +    case GIC_SH_MASK_159_128_OFS:
> +    case GIC_SH_MASK_191_160_OFS:
> +    case GIC_SH_MASK_223_192_OFS:
> +    case GIC_SH_MASK_255_224_OFS:
> +        base = (addr - GIC_SH_MASK_31_0_OFS) * 8;
> +        for (i = 0; i < size * 8; i++) {
> +            ret |= (gic->gic_irqs[i].enabled & 1) << i;
> +        }
> +        return ret;
> +    default:
> +        if (addr < GIC_SH_MAP0_PIN_OFS) {
> +            qemu_log_mask(LOG_UNIMP,
> +                "Warning *** read %d bytes at GIC offset 0x%" PRIx64 "\n",
> +                size, addr);
> +        }
> +        break;
> +    }
> +
> +    /* Global Interrupt Map SrcX to Pin register */
> +    if (addr >= GIC_SH_MAP0_PIN_OFS && addr <= GIC_SH_MAP255_PIN_OFS) {
> +        int irq_src = (addr - GIC_SH_MAP0_PIN_OFS) / 4;
> +        ret = gic->gic_irqs[irq_src].map_pin;
> +        return ret;
> +    }
> +
> +    /* Global Interrupt Map SrcX to VPE register */
> +    if (addr >= GIC_SH_MAP0_VPE31_0_OFS && addr <= 
> GIC_SH_MAP255_VPE63_32_OFS) {
> +        int irq_src = (addr - GIC_SH_MAP0_VPE31_0_OFS) / 32;
> +        ret = 1 << (gic->gic_irqs[irq_src].map_vpe);
> +        return ret;
> +    }
> +
> +    /* VPE-Local Register */
> +    if (addr >= GIC_VPELOCAL_BASE_ADDR && addr < GIC_VPEOTHER_BASE_ADDR) {
> +        return gic_read_vpe(gic, vp_index, addr - GIC_VPELOCAL_BASE_ADDR, 
> size);
> +    }
> +
> +    /* VPE-Other Register */
> +    if (addr >= GIC_VPEOTHER_BASE_ADDR && addr < GIC_USERMODE_BASE_ADDR) {
> +        uint32_t other_index = gic->vps[vp_index].other_addr;
> +        return gic_read_vpe(gic, other_index, addr - GIC_VPEOTHER_BASE_ADDR,
> +                            size);
> +    }

Why these are coded in separate if statements instead of switch above?

> +
> +    qemu_log_mask(LOG_UNIMP, "GIC unimplemented register %" PRIx64 "\n", 
> addr);
> +    return 0ULL;

Why ULL suffix for 0?

> +}
> +
> +/* GIC Write VPE Local/Other Registers */
> +static void gic_write_vpe(MIPSGICState *gic, uint32_t vp_index, hwaddr addr,
> +                              uint64_t data, unsigned size)
> +{
> +    switch (addr) {
> +    case GIC_VPE_CTL_OFS:
> +        gic->vps[vp_index].ctl &= ~1;
> +        gic->vps[vp_index].ctl |= data & 1;
> +        break;
> +    case GIC_VPE_RMASK_OFS:
> +        gic->vps[vp_index].mask &= ~(data & 0x3f) & 0x3f;
> +        break;
> +    case GIC_VPE_SMASK_OFS:
> +        gic->vps[vp_index].mask |= (data & 0x3f);
> +        break;
> +    case GIC_VPE_WD_MAP_OFS:
> +        gic->vps[vp_index].wd_map = data & 0xE000003F;
> +        break;
> +    case GIC_VPE_COMPARE_MAP_OFS:
> +        gic->vps[vp_index].compare_map = data & 0xE000003F;
> +        break;
> +    case GIC_VPE_TIMER_MAP_OFS:
> +        gic->vps[vp_index].timer_map = data & 0xE000003F;
> +        break;
> +    case GIC_VPE_OTHER_ADDR_OFS:
> +        if (data < gic->num_cpu) {
> +            gic->vps[vp_index].other_addr = data;
> +        }
> +        break;
> +    case GIC_VPE_OTHER_ADDR_OFS + 4:
> +        /* do nothing */
> +        break;
> +    case GIC_VPE_COMPARE_LO_OFS:
> +        gic_store_vpe_compare(gic, vp_index, data);
> +        break;
> +    case GIC_VPE_COMPARE_HI_OFS:
> +        /* do nothing */
> +        break;
> +    default:
> +        qemu_log_mask(LOG_UNIMP,
> +                "Warning *** write %d bytes at GIC offset LOCAL/OTHER "
> +                "0x%" PRIx64" 0x%08lx\n", size, addr, data);
> +        break;
> +    }
> +}
> +
> +static void gic_write(void *opaque, hwaddr addr, uint64_t data, unsigned 
> size)
> +{
> +    int intr;
> +    MIPSGICState *gic = (MIPSGICState *) opaque;
> +    uint32_t vp_index = gic_get_current_cpu(gic);
> +    int i, base;
> +
> +    switch (addr) {
> +    case GIC_SH_CONFIG_OFS:
> +    {
> +        uint32_t pre = gic->gic_sh_config;
> +        gic->gic_sh_config = (gic->gic_sh_config & 0xEFFFFFFF) |
> +                             (data & 0x10000000);
> +        if (pre != gic->gic_sh_config) {
> +            if ((gic->gic_sh_config & 0x10000000)) {
> +                gic_timer_stop_count(gic);
> +            }
> +            if (!(gic->gic_sh_config & 0x10000000)) {
> +                gic_timer_start_count(gic);
> +            }
> +        }
> +    }
> +        break;
> +    case GIC_SH_CONFIG_OFS + 4:
> +        /* do nothing */
> +        break;
> +    case GIC_SH_COUNTERLO_OFS:
> +        if (gic->gic_sh_config & 0x10000000) {
> +            gic_store_sh_count(gic, data);
> +        }
> +        break;
> +    case GIC_SH_COUNTERHI_OFS:
> +        /* do nothing */
> +        break;
> +    case GIC_SH_POL_31_0_OFS:
> +    case GIC_SH_POL_63_32_OFS:
> +    case GIC_SH_POL_95_64_OFS:
> +    case GIC_SH_POL_127_96_OFS:
> +    case GIC_SH_POL_159_128_OFS:
> +    case GIC_SH_POL_191_160_OFS:
> +    case GIC_SH_POL_223_192_OFS:
> +    case GIC_SH_POL_255_224_OFS:
> +        base = (addr - GIC_SH_POL_31_0_OFS) * 8;
> +        for (i = 0; i < size * 8; i++) {
> +            gic->gic_irqs[base + i].polarity = (data >> i) & 1;
> +        }
> +        break;
> +    case GIC_SH_TRIG_31_0_OFS:
> +    case GIC_SH_TRIG_63_32_OFS:
> +    case GIC_SH_TRIG_95_64_OFS:
> +    case GIC_SH_TRIG_127_96_OFS:
> +    case GIC_SH_TRIG_159_128_OFS:
> +    case GIC_SH_TRIG_191_160_OFS:
> +    case GIC_SH_TRIG_223_192_OFS:
> +    case GIC_SH_TRIG_255_224_OFS:
> +        base = (addr - GIC_SH_TRIG_31_0_OFS) * 8;
> +        for (i = 0; i < size * 8; i++) {
> +            gic->gic_irqs[base + i].trigger_type = (data >> i) & 1;
> +        }
> +        break;
> +    case GIC_SH_RMASK_31_0_OFS:
> +    case GIC_SH_RMASK_63_32_OFS:
> +    case GIC_SH_RMASK_95_64_OFS:
> +    case GIC_SH_RMASK_127_96_OFS:
> +    case GIC_SH_RMASK_159_128_OFS:
> +    case GIC_SH_RMASK_191_160_OFS:
> +    case GIC_SH_RMASK_223_192_OFS:
> +    case GIC_SH_RMASK_255_224_OFS:
> +        base = (addr - GIC_SH_RMASK_31_0_OFS) * 8;
> +        for (i = 0; i < size * 8; i++) {
> +            gic->gic_irqs[base + i].enabled &= !((data >> i) & 1);
> +        }
> +        break;
> +    case GIC_SH_WEDGE_OFS:
> +        /* Figure out which VPE/HW Interrupt this maps to */
> +        intr = data & 0x7FFFFFFF;
> +        /* Mask/Enabled Checks */
> +        if (data & 0x80000000) {
> +            qemu_set_irq(gic->irqs[intr], 1);
> +        } else {
> +            qemu_set_irq(gic->irqs[intr], 0);
> +        }

This does not look correct. According to the spec interrupt asserted by
write edge register can be still masked. Probaly gic_set_irq() should be
used rather than changing the level directly.

> +        break;
> +    case GIC_SH_SMASK_31_0_OFS:
> +    case GIC_SH_SMASK_63_32_OFS:
> +    case GIC_SH_SMASK_95_64_OFS:
> +    case GIC_SH_SMASK_127_96_OFS:
> +    case GIC_SH_SMASK_159_128_OFS:
> +    case GIC_SH_SMASK_191_160_OFS:
> +    case GIC_SH_SMASK_223_192_OFS:
> +    case GIC_SH_SMASK_255_224_OFS:
> +        base = (addr - GIC_SH_SMASK_31_0_OFS) * 8;
> +        for (i = 0; i < size * 8; i++) {
> +            gic->gic_irqs[base + i].enabled |= (data >> i) & 1;
> +        }
> +        break;
> +
> +    default:
> +        if (addr < GIC_SH_MAP0_PIN_OFS) {
> +            qemu_log_mask(LOG_UNIMP,
> +                    "Warning *** write %d bytes at GIC offset 0x%" PRIx64
> +                    " 0x%08lx\n",
> +                    size, addr, data);
> +        }
> +        break;
> +    }
> +
> +    /* Other cases */
> +    if (addr >= GIC_SH_MAP0_PIN_OFS && addr <= GIC_SH_MAP255_PIN_OFS) {
> +        int irq_src = (addr - GIC_SH_MAP0_PIN_OFS) / 4;
> +        gic->gic_irqs[irq_src].map_pin = data;
> +    }
> +    if (addr >= GIC_SH_MAP0_VPE31_0_OFS && addr <= 
> GIC_SH_MAP255_VPE63_32_OFS) {
> +        int irq_src = (addr - GIC_SH_MAP0_VPE31_0_OFS) / 32;
> +        gic->gic_irqs[irq_src].map_vpe = (data) ? ctz64(data) : 0;
> +    }
> +
> +    /* VPE-Local Register */
> +    if (addr >= GIC_VPELOCAL_BASE_ADDR && addr < GIC_VPEOTHER_BASE_ADDR) {
> +        gic_write_vpe(gic, vp_index, addr - GIC_VPELOCAL_BASE_ADDR,
> +                      data, size);
> +    }
> +
> +    /* VPE-Other Register */
> +    if (addr >= GIC_VPEOTHER_BASE_ADDR && addr < GIC_USERMODE_BASE_ADDR) {
> +        uint32_t other_index = gic->vps[vp_index].other_addr;
> +        gic_write_vpe(gic, other_index, addr - GIC_VPEOTHER_BASE_ADDR,
> +                      data, size);
> +    }
> +}
> +
> +static void gic_set_irq(void *opaque, int n_IRQ, int level)
> +{
> +    int vpe = -1, pin = -1;

You can initialize them with the actual value here.

> +    MIPSGICState *gic = (MIPSGICState *) opaque;
> +
> +
> +    gic->gic_irqs[n_IRQ].pending = (bool) level;

How about (level != 0) instead of casting?

> +
> +    /* Mapping: assume MAP_TO_PIN */
> +    pin = gic->gic_irqs[n_IRQ].map_pin & GIC_MAP_MSK;
> +    vpe = gic->gic_irqs[n_IRQ].map_vpe;
> +
> +    if (vpe < 0 || vpe >= gic->num_cpu) {
> +        return;
> +    }
> +
> +    gic_set_vp_irq(gic, vpe, pin, level);
> +}
> +
> +static void gic_reset(void *opaque)
> +{
> +    int i;
> +    MIPSGICState *gic = (MIPSGICState *) opaque;
> +
> +    gic->gic_sh_config      = 0x100f0000 | gic->num_cpu;
> +    gic->gic_sh_counterlo   = 0;
> +
> +    for (i = 0; i < gic->num_cpu; i++) {
> +        gic->vps[i].ctl         = 0x0;
> +        gic->vps[i].pend        = 0x0;
> +        gic->vps[i].mask        = 0x1; /* COMPARE_MASK ONLY */
> +        gic->vps[i].wd_map      = GIC_MAP_TO_NMI_MSK;
> +        gic->vps[i].compare_map = GIC_MAP_TO_PIN_MSK;
> +        gic->vps[i].timer_map   = GIC_MAP_TO_PIN_MSK | 0x5;
> +        gic->vps[i].comparelo   = 0x0;
> +        gic->vps[i].comparehi   = 0x0;
> +        gic->vps[i].other_addr  = 0x0;
> +    }
> +
> +    for (i = 0; i < gic->num_irq; i++) {
> +        gic->gic_irqs[i].enabled        = false;
> +        gic->gic_irqs[i].pending        = false;
> +        gic->gic_irqs[i].polarity       = false;
> +        gic->gic_irqs[i].trigger_type   = false;
> +        gic->gic_irqs[i].dual_edge      = false;
> +        gic->gic_irqs[i].map_pin        = GIC_MAP_TO_PIN_MSK;
> +        gic->gic_irqs[i].map_vpe        = 0;
> +    }
> +}
> +
> +static const MemoryRegionOps gic_ops = {
> +    .read = gic_read,
> +    .write = gic_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .impl = {
> +        .max_access_size = 8,
> +    },
> +};
> +
> +static void mips_gic_init(Object *obj)
> +{
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> +    MIPSGICState *s = MIPS_GIC(obj);
> +
> +    memory_region_init_io(&s->gic_mem, OBJECT(s), &gic_ops, s,
> +                          "mips-gic", GIC_ADDRSPACE_SZ);
> +    sysbus_init_mmio(sbd, &s->gic_mem);
> +    qemu_register_reset(gic_reset, s);
> +}
> +
> +static void mips_gic_realize(DeviceState *dev, Error **errp)
> +{
> +    MIPSGICState *s = MIPS_GIC(dev);
> +    qemu_irq *irqs = g_new(qemu_irq, s->num_irq);
> +    CPUState *cs = first_cpu;
> +    int i;
> +
> +    if (s->num_cpu > GIC_MAX_VPS) {
> +        error_setg(errp, "Exceed maximum CPUs %d", s->num_cpu);
> +        return;
> +    }
> +    if (s->num_irq > GIC_MAX_INTRS) {
> +        error_setg(errp, "Exceed maximum GIC IRQs %d", s->num_irq);
> +        return;
> +    }
> +
> +    s->vps = g_new(MIPSGICVPState, s->num_cpu);
> +    s->gic_irqs = g_new(MIPSGICIRQState, s->num_irq);
> +
> +    /* Register the CPU env for all cpus with the GIC */
> +    for (i = 0; i < s->num_cpu; i++) {
> +        if (cs != NULL) {
> +            s->vps[i].env = cs->env_ptr;
> +            cs = CPU_NEXT(cs);
> +        } else {
> +            fprintf(stderr, "Unable to initialize GIC - CPUState for "
> +                    "CPU #%d not valid!", i);
> +            return;
> +        }
> +    }
> +
> +    gic_timer_init(s, s->num_cpu);
> +
> +    qdev_init_gpio_in(dev, gic_set_irq, s->num_irq);
> +    for (i = 0; i < s->num_irq; i++) {
> +        irqs[i] = qdev_get_gpio_in(dev, i);
> +
> +        s->gic_irqs[i].irq = (qemu_irq *) irqs[i];

For me this looks like the gic_irqs[i].irq has incorrect type. Need for
casting here doesn't look right.

> +    }
> +    s->irqs = irqs;

What are s->irqs for? The only place where they seem to be used is WEDGE
(where they actually shouldn't I think).

> +}
> +
> +static Property mips_gic_properties[] = {
> +    DEFINE_PROP_INT32("num-cpu", MIPSGICState, num_cpu, 1),
> +    DEFINE_PROP_INT32("num-irq", MIPSGICState, num_irq, 256),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void mips_gic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->props = mips_gic_properties;
> +    dc->realize = mips_gic_realize;
> +}
> +
> +static const TypeInfo mips_gic_info = {
> +    .name          = TYPE_MIPS_GIC,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(MIPSGICState),
> +    .instance_init = mips_gic_init,
> +    .class_init    = mips_gic_class_init,
> +};
> +
> +static void mips_gic_register_types(void)
> +{
> +    type_register_static(&mips_gic_info);
> +}
> +
> +type_init(mips_gic_register_types)
> diff --git a/hw/mips/mips_gic.h b/hw/mips/mips_gic.h
> new file mode 100644
> index 0000000..e5c9bf8
> --- /dev/null
> +++ b/hw/mips/mips_gic.h
> @@ -0,0 +1,298 @@
> +/*
> + * This file is subject to the terms and conditions of the GNU General Public
> + * License.  See the file "COPYING" in the main directory of this archive
> + * for more details.
> + *
> + * Copyright (C) 2000, 07 MIPS Technologies, Inc.
> + * Copyright (C) 2015 Imagination Technologies
> + *
> + */
> +#ifndef _MIPS_GIC_H
> +#define _MIPS_GIC_H
> +
> +/*
> + * GIC Specific definitions
> + */
> +
> +/* The MIPS default location */
> +#define GIC_BASE_ADDR           0x1bdc0000ULL
> +#define GIC_ADDRSPACE_SZ        (128 * 1024)
> +
> +/* GIC Address Space Offsets */
> +#define GIC_SHARED_BASE_ADDR    0x0000
> +#define GIC_VPELOCAL_BASE_ADDR  0x8000
> +#define GIC_VPEOTHER_BASE_ADDR  0xC000
> +#define GIC_USERMODE_BASE_ADDR  0x10000
> +
> +/* Constants */
> +#define GIC_POL_POS     1
> +#define GIC_POL_NEG     0
> +#define GIC_TRIG_EDGE   1
> +#define GIC_TRIG_LEVEL  0
> +
> +#define MSK(n)              ((1 << (n)) - 1)
> +
> +/* GIC Address Space */
> +#define SHARED_SECTION_OFS          0x0000
> +#define SHARED_SECTION_SIZE         0x8000
> +#define VPE_LOCAL_SECTION_OFS       0x8000
> +#define VPE_LOCAL_SECTION_SIZE      0x4000
> +#define VPE_OTHER_SECTION_OFS       0xc000
> +#define VPE_OTHER_SECTION_SIZE      0x4000
> +#define USM_VISIBLE_SECTION_OFS     0x10000
> +#define USM_VISIBLE_SECTION_SIZE    0x10000
> +
> +/* Register Map for Shared Section */
> +
> +#define GIC_SH_CONFIG_OFS           0x0000
> +
> +/* Shared Global Counter */
> +#define GIC_SH_COUNTERLO_OFS        0x0010
> +#define GIC_SH_COUNTERHI_OFS        0x0014
> +#define GIC_SH_REVISIONID_OFS       0x0020
> +
> +/* Interrupt Polarity */
> +#define GIC_SH_POL_31_0_OFS         0x0100
> +#define GIC_SH_POL_63_32_OFS        0x0104
> +#define GIC_SH_POL_95_64_OFS        0x0108
> +#define GIC_SH_POL_127_96_OFS       0x010c
> +#define GIC_SH_POL_159_128_OFS      0x0110
> +#define GIC_SH_POL_191_160_OFS      0x0114
> +#define GIC_SH_POL_223_192_OFS      0x0118
> +#define GIC_SH_POL_255_224_OFS      0x011c
> +
> +/* Edge/Level Triggering */
> +#define GIC_SH_TRIG_31_0_OFS        0x0180
> +#define GIC_SH_TRIG_63_32_OFS       0x0184
> +#define GIC_SH_TRIG_95_64_OFS       0x0188
> +#define GIC_SH_TRIG_127_96_OFS      0x018c
> +#define GIC_SH_TRIG_159_128_OFS     0x0190
> +#define GIC_SH_TRIG_191_160_OFS     0x0194
> +#define GIC_SH_TRIG_223_192_OFS     0x0198
> +#define GIC_SH_TRIG_255_224_OFS     0x019c
> +
> +/* Dual Edge Triggering */
> +#define GIC_SH_DUAL_31_0_OFS        0x0200
> +#define GIC_SH_DUAL_63_32_OFS       0x0204
> +#define GIC_SH_DUAL_95_64_OFS       0x0208
> +#define GIC_SH_DUAL_127_96_OFS      0x020c
> +#define GIC_SH_DUAL_159_128_OFS     0x0210
> +#define GIC_SH_DUAL_191_160_OFS     0x0214
> +#define GIC_SH_DUAL_223_192_OFS     0x0218
> +#define GIC_SH_DUAL_255_224_OFS     0x021c
> +
> +/* Set/Clear corresponding bit in Edge Detect Register */
> +#define GIC_SH_WEDGE_OFS            0x0280
> +
> +/* Reset Mask - Disables Interrupt */
> +#define GIC_SH_RMASK_31_0_OFS       0x0300
> +#define GIC_SH_RMASK_63_32_OFS      0x0304
> +#define GIC_SH_RMASK_95_64_OFS      0x0308
> +#define GIC_SH_RMASK_127_96_OFS     0x030c
> +#define GIC_SH_RMASK_159_128_OFS    0x0310
> +#define GIC_SH_RMASK_191_160_OFS    0x0314
> +#define GIC_SH_RMASK_223_192_OFS    0x0318
> +#define GIC_SH_RMASK_255_224_OFS    0x031c
> +
> +/* Set Mask (WO) - Enables Interrupt */
> +#define GIC_SH_SMASK_31_0_OFS       0x0380
> +#define GIC_SH_SMASK_63_32_OFS      0x0384
> +#define GIC_SH_SMASK_95_64_OFS      0x0388
> +#define GIC_SH_SMASK_127_96_OFS     0x038c
> +#define GIC_SH_SMASK_159_128_OFS    0x0390
> +#define GIC_SH_SMASK_191_160_OFS    0x0394
> +#define GIC_SH_SMASK_223_192_OFS    0x0398
> +#define GIC_SH_SMASK_255_224_OFS    0x039c
> +
> +/* Global Interrupt Mask Register (RO) - Bit Set == Interrupt enabled */
> +#define GIC_SH_MASK_31_0_OFS        0x0400
> +#define GIC_SH_MASK_63_32_OFS       0x0404
> +#define GIC_SH_MASK_95_64_OFS       0x0408
> +#define GIC_SH_MASK_127_96_OFS      0x040c
> +#define GIC_SH_MASK_159_128_OFS     0x0410
> +#define GIC_SH_MASK_191_160_OFS     0x0414
> +#define GIC_SH_MASK_223_192_OFS     0x0418
> +#define GIC_SH_MASK_255_224_OFS     0x041c
> +
> +/* Pending Global Interrupts (RO) */
> +#define GIC_SH_PEND_31_0_OFS        0x0480
> +#define GIC_SH_PEND_63_32_OFS       0x0484
> +#define GIC_SH_PEND_95_64_OFS       0x0488
> +#define GIC_SH_PEND_127_96_OFS      0x048c
> +#define GIC_SH_PEND_159_128_OFS     0x0490
> +#define GIC_SH_PEND_191_160_OFS     0x0494
> +#define GIC_SH_PEND_223_192_OFS     0x0498
> +#define GIC_SH_PEND_255_224_OFS     0x049c
> +
> +#define GIC_SH_MAP0_PIN_OFS         0x0500
> +#define GIC_SH_MAP255_PIN_OFS       0x08fc
> +
> +#define GIC_SH_MAP0_VPE31_0_OFS     0x2000
> +#define GIC_SH_MAP255_VPE63_32_OFS  0x3fe4
> +
> +/* Register Map for Local Section */
> +#define GIC_VPE_CTL_OFS                 0x0000
> +#define GIC_VPE_PEND_OFS                0x0004
> +#define GIC_VPE_MASK_OFS                0x0008
> +#define GIC_VPE_RMASK_OFS               0x000c
> +#define GIC_VPE_SMASK_OFS               0x0010
> +#define GIC_VPE_WD_MAP_OFS              0x0040
> +#define GIC_VPE_COMPARE_MAP_OFS         0x0044
> +#define GIC_VPE_TIMER_MAP_OFS           0x0048
> +#define GIC_VPE_PERFCTR_MAP_OFS         0x0050
> +#define GIC_VPE_SWINT0_MAP_OFS          0x0054
> +#define GIC_VPE_SWINT1_MAP_OFS          0x0058
> +#define GIC_VPE_OTHER_ADDR_OFS          0x0080
> +#define GIC_VPE_IDENT_OFS               0x0088
> +#define GIC_VPE_WD_CONFIG0_OFS          0x0090
> +#define GIC_VPE_WD_COUNT0_OFS           0x0094
> +#define GIC_VPE_WD_INITIAL0_OFS         0x0098
> +#define GIC_VPE_COMPARE_LO_OFS          0x00a0
> +#define GIC_VPE_COMPARE_HI_OFS          0x00a4
> +
> +/* Masks */
> +#define GIC_SH_CONFIG_COUNTSTOP_SHF     28
> +#define GIC_SH_CONFIG_COUNTSTOP_MSK     (MSK(1) << 
> GIC_SH_CONFIG_COUNTSTOP_SHF)
> +
> +#define GIC_SH_CONFIG_COUNTBITS_SHF     24
> +#define GIC_SH_CONFIG_COUNTBITS_MSK     (MSK(4) << 
> GIC_SH_CONFIG_COUNTBITS_SHF)
> +
> +#define GIC_SH_CONFIG_NUMINTRS_SHF      16
> +#define GIC_SH_CONFIG_NUMINTRS_MSK      (MSK(8) << 
> GIC_SH_CONFIG_NUMINTRS_SHF)
> +
> +#define GIC_SH_CONFIG_NUMVPES_SHF       0
> +#define GIC_SH_CONFIG_NUMVPES_MSK       (MSK(8) << GIC_SH_CONFIG_NUMVPES_SHF)
> +
> +#define GIC_SH_WEDGE_SET(intr)          ((intr) | (0x1 << 31))
> +#define GIC_SH_WEDGE_CLR(intr)          ((intr) & ~(0x1 << 31))
> +
> +#define GIC_MAP_TO_PIN_SHF              31
> +#define GIC_MAP_TO_PIN_MSK              (MSK(1) << GIC_MAP_TO_PIN_SHF)
> +#define GIC_MAP_TO_NMI_SHF              30
> +#define GIC_MAP_TO_NMI_MSK              (MSK(1) << GIC_MAP_TO_NMI_SHF)
> +#define GIC_MAP_TO_YQ_SHF               29
> +#define GIC_MAP_TO_YQ_MSK               (MSK(1) << GIC_MAP_TO_YQ_SHF)
> +#define GIC_MAP_SHF                     0
> +#define GIC_MAP_MSK                     (MSK(6) << GIC_MAP_SHF)
> +
> +/* GIC_VPE_CTL Masks */
> +#define GIC_VPE_CTL_PERFCNT_RTBL_SHF    2
> +#define GIC_VPE_CTL_PERFCNT_RTBL_MSK    (MSK(1) << 
> GIC_VPE_CTL_PERFCNT_RTBL_SHF)
> +#define GIC_VPE_CTL_TIMER_RTBL_SHF      1
> +#define GIC_VPE_CTL_TIMER_RTBL_MSK      (MSK(1) << 
> GIC_VPE_CTL_TIMER_RTBL_SHF)
> +#define GIC_VPE_CTL_EIC_MODE_SHF        0
> +#define GIC_VPE_CTL_EIC_MODE_MSK        (MSK(1) << GIC_VPE_CTL_EIC_MODE_SHF)
> +
> +/* GIC_VPE_PEND Masks */
> +#define GIC_VPE_PEND_WD_SHF         0
> +#define GIC_VPE_PEND_WD_MSK         (MSK(1) << GIC_VPE_PEND_WD_SHF)
> +#define GIC_VPE_PEND_CMP_SHF        1
> +#define GIC_VPE_PEND_CMP_MSK        (MSK(1) << GIC_VPE_PEND_CMP_SHF)
> +#define GIC_VPE_PEND_TIMER_SHF      2
> +#define GIC_VPE_PEND_TIMER_MSK      (MSK(1) << GIC_VPE_PEND_TIMER_SHF)
> +#define GIC_VPE_PEND_PERFCOUNT_SHF  3
> +#define GIC_VPE_PEND_PERFCOUNT_MSK  (MSK(1) << GIC_VPE_PEND_PERFCOUNT_SHF)
> +#define GIC_VPE_PEND_SWINT0_SHF     4
> +#define GIC_VPE_PEND_SWINT0_MSK     (MSK(1) << GIC_VPE_PEND_SWINT0_SHF)
> +#define GIC_VPE_PEND_SWINT1_SHF     5
> +#define GIC_VPE_PEND_SWINT1_MSK     (MSK(1) << GIC_VPE_PEND_SWINT1_SHF)
> +
> +/* GIC_VPE_RMASK Masks */
> +#define GIC_VPE_RMASK_WD_SHF        0
> +#define GIC_VPE_RMASK_WD_MSK        (MSK(1) << GIC_VPE_RMASK_WD_SHF)
> +#define GIC_VPE_RMASK_CMP_SHF       1
> +#define GIC_VPE_RMASK_CMP_MSK       (MSK(1) << GIC_VPE_RMASK_CMP_SHF)
> +#define GIC_VPE_RMASK_TIMER_SHF     2
> +#define GIC_VPE_RMASK_TIMER_MSK     (MSK(1) << GIC_VPE_RMASK_TIMER_SHF)
> +#define GIC_VPE_RMASK_PERFCNT_SHF   3
> +#define GIC_VPE_RMASK_PERFCNT_MSK   (MSK(1) << GIC_VPE_RMASK_PERFCNT_SHF)
> +#define GIC_VPE_RMASK_SWINT0_SHF    4
> +#define GIC_VPE_RMASK_SWINT0_MSK    (MSK(1) << GIC_VPE_RMASK_SWINT0_SHF)
> +#define GIC_VPE_RMASK_SWINT1_SHF    5
> +#define GIC_VPE_RMASK_SWINT1_MSK    (MSK(1) << GIC_VPE_RMASK_SWINT1_SHF)
> +
> +/* GIC_VPE_SMASK Masks */
> +#define GIC_VPE_SMASK_WD_SHF        0
> +#define GIC_VPE_SMASK_WD_MSK        (MSK(1) << GIC_VPE_SMASK_WD_SHF)
> +#define GIC_VPE_SMASK_CMP_SHF       1
> +#define GIC_VPE_SMASK_CMP_MSK       (MSK(1) << GIC_VPE_SMASK_CMP_SHF)
> +#define GIC_VPE_SMASK_TIMER_SHF     2
> +#define GIC_VPE_SMASK_TIMER_MSK     (MSK(1) << GIC_VPE_SMASK_TIMER_SHF)
> +#define GIC_VPE_SMASK_PERFCNT_SHF   3
> +#define GIC_VPE_SMASK_PERFCNT_MSK   (MSK(1) << GIC_VPE_SMASK_PERFCNT_SHF)
> +#define GIC_VPE_SMASK_SWINT0_SHF    4
> +#define GIC_VPE_SMASK_SWINT0_MSK    (MSK(1) << GIC_VPE_SMASK_SWINT0_SHF)
> +#define GIC_VPE_SMASK_SWINT1_SHF    5
> +#define GIC_VPE_SMASK_SWINT1_MSK    (MSK(1) << GIC_VPE_SMASK_SWINT1_SHF)
> +
> +#define GIC_CPU_PIN_OFFSET          2
> +
> +#define TYPE_MIPS_GIC "mips-gic"
> +#define MIPS_GIC(obj) OBJECT_CHECK(MIPSGICState, (obj), TYPE_MIPS_GIC)
> +
> +/* Support up to 32 VPEs and 256 IRQs */
> +#define GIC_MAX_VPS             32
> +#define GIC_MAX_INTRS           256
> +
> +typedef struct MIPSGICState MIPSGICState;
> +typedef struct MIPSGICTimerState MIPSGICTimerState;
> +typedef struct MIPSGICIRQState MIPSGICIRQState;
> +typedef struct MIPSGICVPState MIPSGICVPState;
> +
> +struct MIPSGICTimerState {
> +    QEMUTimer *qtimer;
> +    uint32_t vp_index;
> +    MIPSGICState *gic;
> +};
> +
> +struct MIPSGICIRQState {
> +    bool enabled;
> +    bool pending;
> +    bool polarity;
> +    bool trigger_type;
> +    bool dual_edge;
> +    uint32_t map_pin;
> +    uint64_t map_vpe;
> +    qemu_irq *irq;

This should represent just a single qemu_irq, thus why is this a pointer?

> +};
> +
> +struct MIPSGICVPState {
> +    uint32_t ctl;
> +    uint32_t pend;
> +    uint32_t mask;
> +    uint32_t wd_map;
> +    uint32_t compare_map;
> +    uint32_t timer_map;
> +    uint32_t comparelo;
> +    uint32_t comparehi;

comparehi is always zero, also description says that CompareHi is not
implemented. I think this field (as well as others which are not used if
there are more) should be just removed.

> +    uint32_t other_addr;
> +
> +    CPUMIPSState *env;
> +    MIPSGICTimerState *gic_timer;
> +};
> +
> +struct MIPSGICState {
> +    SysBusDevice parent_obj;
> +
> +    MemoryRegion gic_mem;

This is inside MIPSGICState, "gic_" prefix seems redundant.

> +    qemu_irq *irqs;

It's not clear to me why this is needed. External interrupt pins are
already represented by gic_irqs.irq.

> +
> +    /* Shared Section Registers */
> +    uint32_t gic_sh_config;
> +    uint32_t gic_sh_counterlo;
> +
> +    MIPSGICIRQState *gic_irqs;
> +
> +    /* VPE Local Section Registers */
> +    /* VPE Other Section Registers, aliased to local,
> +     * use the other addr to access the correct instance */
> +
> +    MIPSGICVPState *vps;
> +
> +    /* User Mode Visible Section Registers */

There are no User Mode Visible Section Registers, the comment is just
misleading.

Regards,
Leon

> +
> +    int32_t num_cpu;
> +    int32_t num_irq;
> +};
> +
> +#endif /* _MIPS_GIC_H */
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]