qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support f


From: Pavel Fedin
Subject: Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files
Date: Thu, 22 Oct 2015 14:53:27 +0300

 Hello!

 Some more notes after more careful reviewing. Actually, i am working on v3 of 
live migration RFC, i will include some macros which
will help you to integrate better.

> -----Original Message-----
> From: Shlomo Pongratz [mailto:address@hidden
> Sent: Tuesday, October 20, 2015 8:22 PM
> To: address@hidden
> Cc: address@hidden; address@hidden; address@hidden;
> address@hidden; address@hidden; address@hidden; Shlomo Pongratz
> Subject: [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files
> 
> From: Shlomo Pongratz <address@hidden>
> 
> Add files need to maintain the GIC-500 state.
> Use bitmaps for managing per cpu flags.
> As the largest "atomic" data structure is uint64 supporting
> more than 64 cores requires to change some data structures
> to bitmap.
> 
> Add mp_affinity poroperty vector to hold a copy of the
> cpu's affinity.
> 
> Signed-off-by: Shlomo Pongratz <address@hidden>
> ---
>  hw/intc/arm_gicv3_common.c         | 251 
> ++++++++++++++++++++++++++++++++++++-
>  hw/intc/gicv3_internal.h           | 210 +++++++++++++++++++++++++++++++
>  include/hw/intc/arm_gicv3.h        |  44 +++++++
>  include/hw/intc/arm_gicv3_common.h |  78 +++++++++++-
>  4 files changed, 577 insertions(+), 6 deletions(-)
>  create mode 100644 hw/intc/gicv3_internal.h
>  create mode 100644 include/hw/intc/arm_gicv3.h
> 
> diff --git a/hw/intc/arm_gicv3_common.c b/hw/intc/arm_gicv3_common.c
> index 032ece2..3c9bd34 100644
> --- a/hw/intc/arm_gicv3_common.c
> +++ b/hw/intc/arm_gicv3_common.c
> @@ -21,6 +21,7 @@
>   */
> 
>  #include "hw/intc/arm_gicv3_common.h"
> +#include "gicv3_internal.h"
> 
>  static void gicv3_pre_save(void *opaque)
>  {
> @@ -43,11 +44,89 @@ static int gicv3_post_load(void *opaque, int version_id)
>      return 0;
>  }
> 
> +static const VMStateDescription vmstate_gicv3_irq_state = {
> +    .name = "arm_gicv3/arm_gicv3_irq_state",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_BITMAP(enabled, gicv3_irq_state, 0, num_cpu),
> +        VMSTATE_BITMAP(pending, gicv3_irq_state, 0, num_cpu),
> +        VMSTATE_BITMAP(active, gicv3_irq_state, 0, num_cpu),
> +        VMSTATE_BITMAP(level, gicv3_irq_state, 0, num_cpu),
> +        VMSTATE_BITMAP(group, gicv3_irq_state, 0, num_cpu),
> +        VMSTATE_BOOL(edge_trigger, gic_irq_state),
> +        VMSTATE_BITMAP(target, gicv3_irq_state, 0, num_cpu),
> +        VMSTATE_VARRAY_INT32(last_active, gicv3_irq_state, num_cpu,
> +                             0, vmstate_info_uint16, uint16_t),
> +        VMSTATE_INT32(num_cpu, gicv3_irq_state),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static const VMStateDescription vmstate_gicv3_Priority = {
> +    .name = "arm_gicv3/priority1",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_VARRAY_INT32(p, gicv3_Priority, num_cpu,
> +                             0, vmstate_info_uint8, uint8_t),
> +        VMSTATE_INT32(num_cpu, gicv3_Priority),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static const VMStateDescription vmstate_gicv3_sgi_state = {
> +    .name = "arm_gicv3/arm_gicv3_sgi/arm_gicv3_sgi_state",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_BITMAP(pending, gicv3_sgi_state, 0, num_cpu),
> +        VMSTATE_INT32(num_cpu, gicv3_sgi_state),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static const VMStateDescription vmstate_gicv3_sgi_vec = {
> +    .name = "arm_gicv3/arm_gicv3_sgi_vec",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_STRUCT_VARRAY_INT32(state, gicv3_sgi_vec, num_cpu,
> +                                    0, vmstate_gicv3_sgi_state, 
> gicv3_sgi_state),
> +        VMSTATE_INT32(num_cpu, gicv3_sgi_vec),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
>  static const VMStateDescription vmstate_gicv3 = {
>      .name = "arm_gicv3",
>      .unmigratable = 1,
>      .pre_save = gicv3_pre_save,
>      .post_load = gicv3_post_load,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT32(ctlr, GICv3State),
> +        VMSTATE_VARRAY_UINT32(cpu_ctlr, GICv3State, num_cpu,
> +                              0, vmstate_info_uint32, uint32_t),
> +        VMSTATE_STRUCT_ARRAY(irq_state, GICv3State, GICV3_MAXIRQ, 1,
> +                             vmstate_gicv3_irq_state, gicv3_irq_state),
> +        VMSTATE_STRUCT_ARRAY(priority1, GICv3State, GICV3_INTERNAL, 1,
> +                             vmstate_gicv3_Priority, gicv3_Priority),
> +        VMSTATE_UINT8_ARRAY(priority2, GICv3State, GICV3_MAXIRQ - 
> GICV3_INTERNAL),
> +        VMSTATE_STRUCT_ARRAY(sgi, GICv3State, GICV3_NR_SGIS, 1,
> +                             vmstate_gicv3_sgi_vec, gicv3_sgi_vec),
> +        VMSTATE_VARRAY_UINT32(priority_mask, GICv3State, num_cpu, 0,
> +                              vmstate_info_uint16, uint16_t),
> +        VMSTATE_VARRAY_UINT32(running_irq, GICv3State, num_cpu, 0,
> +                              vmstate_info_uint16, uint16_t),
> +        VMSTATE_VARRAY_UINT32(running_priority, GICv3State, num_cpu, 0,
> +                              vmstate_info_uint16, uint16_t),
> +        VMSTATE_VARRAY_UINT32(current_pending, GICv3State, num_cpu, 0,
> +                              vmstate_info_uint16, uint16_t),
> +        VMSTATE_VARRAY_UINT32(mp_affinity, GICv3State, num_mp_affinity, 0,
> +                              vmstate_info_uint64, uint64_t),
> +        VMSTATE_UINT32(num_cpu, GICv3State),
> +        VMSTATE_END_OF_LIST()
> +    }
>  };
> 
>  void gicv3_init_irqs_and_mmio(GICv3State *s, qemu_irq_handler handler,
> @@ -63,11 +142,11 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, 
> qemu_irq_handler handler,
>       *  [N+32..N+63] PPIs for CPU 1
>       *   ...
>       */
> -    i = s->num_irq - GIC_INTERNAL + GIC_INTERNAL * s->num_cpu;
> +    i = s->num_irq - GICV3_INTERNAL + GICV3_INTERNAL * s->num_cpu;
>      qdev_init_gpio_in(DEVICE(s), handler, i);
> 
> -    s->parent_irq = g_malloc(s->num_cpu * sizeof(qemu_irq));
> -    s->parent_fiq = g_malloc(s->num_cpu * sizeof(qemu_irq));
> +    s->parent_irq = g_new0(qemu_irq, s->num_cpu);
> +    s->parent_fiq = g_new0(qemu_irq, s->num_cpu);
> 
>      for (i = 0; i < s->num_cpu; i++) {
>          sysbus_init_irq(sbd, &s->parent_irq[i]);
> @@ -88,6 +167,10 @@ void gicv3_init_irqs_and_mmio(GICv3State *s, 
> qemu_irq_handler handler,
>  static void arm_gicv3_common_realize(DeviceState *dev, Error **errp)
>  {
>      GICv3State *s = ARM_GICV3_COMMON(dev);
> +    int num_irq = s->num_irq;
> +    gicv3_irq_state *irq_state;
> +    gicv3_sgi_vec *sgi_vec;
> +    int i;
> 
>      /* revision property is actually reserved and currently used only in 
> order
>       * to keep the interface compatible with GICv2 code, avoiding extra
> @@ -98,18 +181,176 @@ static void arm_gicv3_common_realize(DeviceState *dev, 
> Error **errp)
>          error_setg(errp, "unsupported GIC revision %d", s->revision);
>          return;
>      }
> +
> +    s->num_irq += GICV3_BASE_IRQ;
> +    if (s->num_irq > GICV3_MAXIRQ) {
> +        error_setg(errp,
> +                   "requested %u interrupt lines exceeds GIC maximum %d",
> +                   num_irq, GICV3_MAXIRQ);
> +        return;
> +    }
> +
> +    /* ITLinesNumber is represented as (N / 32) - 1 (see
> +     * gic_dist_readb) so this is an implementation imposed
> +     * restriction, not an architectural one:
> +     */
> +    if (s->num_irq < 32 || (s->num_irq % 32)) {
> +        error_setg(errp,
> +                   "%d interrupt lines unsupported: not divisible by 32",
> +                   num_irq);
> +        return;
> +    }
> +
> +    /* s->parent_irq and s->parent_fiq  are initialized in
> +     * gicv3_init_irqs_and_mmio
> +     */
> +    s->priority_mask = g_new0(uint16_t, s->num_cpu);
> +    s->current_pending = g_new(uint16_t, s->num_cpu);
> +    s->running_irq = g_new(uint16_t, s->num_cpu);
> +    s->running_priority = g_new(uint16_t, s->num_cpu);
> +    s->cpu_ctlr = g_new0(uint32_t, s->num_cpu);
> +    s->cpu_enabled = bitmap_new(s->num_cpu);
> +    bitmap_zero(s->cpu_enabled, s->num_cpu);
> +    /* Don't ovreride mp_affinity it is a prop */
> +
> +    for (i = 0; i < s->num_cpu; i++) {
> +        s->current_pending[i] = 1023;
> +        s->running_irq[i] = 1023;
> +        s->running_priority[i] = 0x100;
> +    }
> +
> +    irq_state = s->irq_state;
> +    for (i = 0; i < GICV3_MAXIRQ; i++) {
> +        irq_state->num_cpu = s->num_cpu;
> +        irq_state->enabled = bitmap_new(s->num_cpu);
> +        bitmap_zero(irq_state->enabled, s->num_cpu);
> +        irq_state->pending = bitmap_new(s->num_cpu);
> +        bitmap_zero(irq_state->pending, s->num_cpu);
> +        irq_state->active = bitmap_new(s->num_cpu);
> +        bitmap_zero(irq_state->active, s->num_cpu);
> +        irq_state->level = bitmap_new(s->num_cpu);
> +        bitmap_zero(irq_state->level, s->num_cpu);
> +        irq_state->group = bitmap_new(s->num_cpu);
> +        bitmap_zero(irq_state->group, s->num_cpu);
> +        irq_state->edge_trigger = false;
> +        irq_state->target = bitmap_new(s->num_cpu);
> +        bitmap_zero(irq_state->target, s->num_cpu);
> +        irq_state->last_active = g_new0(uint16_t, s->num_cpu);
> +        irq_state++;
> +    }
> +
> +    sgi_vec = s->sgi;
> +    for (i = 0; i < GICV3_NR_SGIS; i++) {
> +        int j;
> +        struct gicv3_sgi_state *sgi_state;
> +        sgi_vec->num_cpu = s->num_cpu;
> +        sgi_vec->state = g_new0(gicv3_sgi_state, s->num_cpu);
> +        sgi_state = sgi_vec->state;
> +        for (j = 0; j < s->num_cpu; j++) {
> +            sgi_state->num_cpu = s->num_cpu;
> +            sgi_state->pending = bitmap_new(s->num_cpu);
> +            bitmap_zero(sgi_state->pending, s->num_cpu);
> +            sgi_state++;
> +        }
> +        sgi_vec++;
> +    }
> +
> +    for (i = 0; i < GICV3_INTERNAL; i++) {
> +        s->priority1[i].num_cpu = s->num_cpu;
> +        s->priority1[i].p = g_new0(uint8_t, s->num_cpu);
> +    }
>  }
> 
>  static void arm_gicv3_common_reset(DeviceState *dev)
>  {
> -    /* TODO */
> +    GICv3State *s = ARM_GICV3_COMMON(dev);
> +    gicv3_irq_state *irq_state;
> +    gicv3_sgi_vec *sgi_vec;
> +    int i;
> +
> +    /* Note num_cpu and num_irq are properties */
> +
> +    /* Don't reset anything assigned in arm_gic_realize or any property */
> +
> +    /* No GICv2 backwards computability support */
> +    for (i = 0; i < s->num_cpu; i++) {
> +        s->priority_mask[i] = 0;
> +        s->current_pending[i] = 1023;
> +        s->running_irq[i] = 1023;
> +        s->running_priority[i] = 0x100;
> +        s->cpu_ctlr[i] = 0;
> +        /* Don't tuch mp_affinity set in virt.c */
> +    }
> +
> +    irq_state = s->irq_state;
> +    for (i = 0; i < GICV3_MAXIRQ; i++) {
> +        /* Reset every filed in irq_state */
> +        bitmap_zero(irq_state->enabled, s->num_cpu);
> +        bitmap_zero(irq_state->pending, s->num_cpu);
> +        bitmap_zero(irq_state->active, s->num_cpu);
> +        bitmap_zero(irq_state->level, s->num_cpu);
> +        bitmap_zero(irq_state->group, s->num_cpu);
> +        bitmap_zero(irq_state->target, s->num_cpu);
> +        memset(irq_state->last_active, 0,
> +               s->num_cpu * sizeof(*irq_state->last_active));
> +        irq_state->edge_trigger = 0;
> +        irq_state++;
> +    }
> +    /* GIC-500 comment 'j' SGI are always enabled */
> +    for (i = 0; i < GICV3_NR_SGIS; i++) {
> +        GIC_SET_ENABLED(i, ALL_CPU_MASK);
> +        GIC_SET_EDGE_TRIGGER(i);
> +    }
> +
> +    sgi_vec = s->sgi;
> +    for (i = 0; i < GICV3_NR_SGIS; i++) {
> +        struct gicv3_sgi_state *sgi_state = sgi_vec->state;
> +        int j;
> +        for (j = 0; j < s->num_cpu; j++) {
> +            bitmap_zero(sgi_state->pending, s->num_cpu);
> +            sgi_state++;
> +        }
> +        sgi_vec++;
> +    }
> +
> +    if (s->num_cpu == 1) {
> +        /* For uniprocessor GICs all interrupts always target the sole CPU */
> +        for (i = 0; i < GICV3_MAXIRQ; i++) {
> +            set_bit(0, s->irq_state[i].target);
> +        }
> +    }
> +
> +    for (i = 0; i < GICV3_INTERNAL; i++)
> +        memset(s->priority1[i].p, 0, s->num_cpu * 
> sizeof(*s->priority1[i].p));
> +    memset(s->priority2, 0, sizeof(s->priority2));
> +
> +    /* With all configuration we don't  support GICv2 backwards 
> computability */
> +    if (s->security_levels > 1) {
> +        /* GICv3 5.3.20 With two security So DS is RAZ/WI ARE_NS is RAO/WI
> +         * and ARE_S is RAO/WI
> +         */
> +         s->ctlr = GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS;
> +    } else {
> +        /* GICv3 5.3.20 With one security So DS is RAO/WI ARE is RAO/WI
> +         */
> +        s->ctlr = GICD_CTLR_DS | GICD_CTLR_ARE;
> +    }
> +    /* Workaround!
> +     * Linux (drivers/irqchip/irq-gic-v3.c) is enabling only group one,
> +     * in gic_cpu_sys_reg_init it calls gic_write_grpen1(1);
> +     * but it doesn't conigure any interrupt to be in group one
> +     */
> +    for (i = 0; i < s->num_irq; i++)
> +        GIC_SET_GROUP(i, ALL_CPU_MASK);
>  }
> 
>  static Property arm_gicv3_common_properties[] = {
>      DEFINE_PROP_UINT32("num-cpu", GICv3State, num_cpu, 1),
>      DEFINE_PROP_UINT32("num-irq", GICv3State, num_irq, 32),
>      DEFINE_PROP_UINT32("revision", GICv3State, revision, 3),
> -    DEFINE_PROP_BOOL("has-security-extensions", GICv3State, security_extn, 
> 0),
> +    DEFINE_PROP_UINT8("security-levels", GICv3State, security_levels, 0),
> +    DEFINE_PROP_ARRAY("mp-affinity", GICv3State, num_mp_affinity, 
> mp_affinity,
> +                      qdev_prop_uint64, uint64_t),
>      DEFINE_PROP_END_OF_LIST(),
>  };
> 
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> new file mode 100644
> index 0000000..e0b4a08
> --- /dev/null
> +++ b/hw/intc/gicv3_internal.h
> @@ -0,0 +1,210 @@
> +/*
> + * ARM GIC support - internal interfaces
> + *
> + * Copyright (c) 2012 Linaro Limited
> + * Copyright (c) 2015 Huawei.
> + * Written by Peter Maydell
> + * Extended to 64 cores by Shlomo Pongratz
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef QEMU_ARM_GICV3_INTERNAL_H
> +#define QEMU_ARM_GICV3_INTERNAL_H
> +
> +#include "hw/intc/arm_gicv3.h"
> +
> +/* Marks all CPUs  */
> +#define ALL_CPU_MASK ((int) -1)
> +#define ALL_CPU_MASK_COMPAT ((unsigned)(0xff))
> +
> +/* Keep this macro so it will be easy to compare the code to GICv2 code.
> + * The compiler will optimize any +/- operation involving this macro
> + */
> +#define GICV3_BASE_IRQ (0)

 Does it really worth that? IMHO it only pollutes the code and makes it less 
readable. If you ever want to compare this with GICv2
code, you should just know that there's no GICV3_BASE_IRQ. Actually, IIRC, it's 
not even GIC, but NVIC artifact.

> +
> +static inline void auto_or(GICv3State *s, unsigned long *target, unsigned 
> long *bm)
> +{
> +    bitmap_or(target, target, bm, s->num_cpu);
> +}
> +
> +static inline int auto_test(GICv3State *s, unsigned long *target, unsigned 
> long *bm)
> +{
> +    /* Result used for test */
> +    return bitmap_intersects(target, bm, s->num_cpu);
> +}
> +
> +static inline void auto_andnot(GICv3State *s, unsigned long *target, 
> unsigned long *bm)
> +{
> +    /* Ignore status */
> +    (void) bitmap_andnot(target, target, bm, s->num_cpu);
> +}
> +
> +static inline void gic_set(GICv3State *s, unsigned long *bm, int cpu)
> +{
> +    if (cpu < 0) /* All CPUs */
> +        bitmap_fill(bm, s->num_cpu);
> +    else
> +        set_bit(cpu, bm);
> +}
> +
> +static inline void gic_clr(GICv3State *s, unsigned long *bm, int cpu)
> +{
> +    if (cpu < 0) /* All CPUs */
> +        bitmap_zero(bm, s->num_cpu);
> +    else
> +        clear_bit(cpu, bm);
> +}
> +
> +static inline int gic_test(GICv3State *s, unsigned long *bm, int cpu)
> +{
> +    if (cpu < 0) /* ANY CPUs */
> +        return !bitmap_empty(bm, s->num_cpu);
> +    else
> +        return test_bit(cpu, bm);
> +}
> +
> +#define GIC_SET_ENABLED(irq, cm) gic_set(s, s->irq_state[irq].enabled, cm)
> +#define GIC_CLEAR_ENABLED(irq, cm) gic_clr(s, s->irq_state[irq].enabled, cm)
> +#define GIC_TEST_ENABLED(irq, cm) gic_test(s, s->irq_state[irq].enabled, cm)
> +#define GIC_SET_PENDING(irq, cm) gic_set(s, s->irq_state[irq].pending, cm)
> +#define GIC_SET_PENDING_MASK(irq, bm) auto_or(s, s->irq_state[irq].pending, 
> bm)
> +#define GIC_TEST_PENDING(irq, cm) gic_test(s, s->irq_state[irq].pending, cm)
> +#define GIC_CLEAR_PENDING(irq, cm) gic_clr(s, s->irq_state[irq].pending, cm)
> +#define GIC_SET_ACTIVE(irq, cm) gic_set(s, s->irq_state[irq].active, cm)
> +#define GIC_CLEAR_ACTIVE(irq, cm) gic_clr(s, s->irq_state[irq].active, cm)
> +#define GIC_TEST_ACTIVE(irq, cm) gic_test(s, s->irq_state[irq].active, cm)
> +#define GIC_SET_LEVEL(irq, cm) gic_set(s, s->irq_state[irq].level, cm)
> +#define GIC_CLEAR_LEVEL(irq, cm) gic_clr(s, s->irq_state[irq].level, cm)
> +#define GIC_SET_LEVEL_MASK(irq, bm) auto_or(s, s->irq_state[irq].level, bm)
> +#define GIC_CLEAR_LEVEL_MASK(irq, bm) auto_andnot(s, 
> s->irq_state[irq].level, bm)
> +#define GIC_TEST_LEVEL(irq, cm) gic_test(s, s->irq_state[irq].level, cm)
> +#define GIC_TEST_LEVEL_MASK(irq, bm) auto_test(s, s->irq_state[irq].level, 
> bm)
> +#define GIC_SET_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = true
> +#define GIC_CLEAR_EDGE_TRIGGER(irq) s->irq_state[irq].edge_trigger = false
> +#define GIC_TEST_EDGE_TRIGGER(irq) (s->irq_state[irq].edge_trigger)

 I know that GICv2 implements them this way. Not sure that it's correct, 
though. GICR_ICFGR description in the doc says:
--- cut ---
Configurations
A copy of this register is provided for each Redistributor.
--- cut ---
 So, i assume that these are per-CPU too, despite it really doesn't make sense 
to have different configs on different CPUs.
 My RFC implements per-CPU registers for SGI/PPIs.

> +#define GIC_GET_PRIORITY(irq, cpu) (((irq) < GICV3_INTERNAL) ?          \
> +                                    s->priority1[irq].p[cpu] :          \
> +                                    s->priority2[(irq) - GICV3_INTERNAL])
> +#define GIC_SET_TARGET(irq, cm) gic_set(s, s->irq_state[irq].target, cm)
> +#define GIC_CLEAR_TARGET(irq, cm) gic_clr(s, s->irq_state[irq].target, cm)
> +#define GIC_TEST_TARGET(irq, cm) gic_test(s, s->irq_state[irq].target, cm)
> +#define GIC_TARGET(irq) s->irq_state[irq].target
> +#define GIC_CLEAR_GROUP(irq, cm) gic_clr(s, s->irq_state[irq].group, cm)
> +#define GIC_SET_GROUP(irq, cm) gic_set(s, s->irq_state[irq].group, cm)
> +#define GIC_TEST_GROUP(irq, cm) gic_test(s, s->irq_state[irq].group, cm)
> +
> +/* The special cases for the revision property: */
> +#define REV_V3 3

 Does this make any sense? Value 3 is self-sufficient here, because it's just 
3. This reads like "#define NUM_3 3". Isn't it
ridiculous?

> +
> +static inline bool gic_test_pending(GICv3State *s, int irq, int cm)
> +{
> +    /* Edge-triggered interrupts are marked pending on a rising edge, but
> +     * level-triggered interrupts are either considered pending when the
> +     * level is active or if software has explicitly written to
> +     * GICD_ISPENDR to set the state pending.
> +     */
> +    return GIC_TEST_PENDING(irq, cm) ||
> +        (!GIC_TEST_EDGE_TRIGGER(irq) && GIC_TEST_LEVEL(irq, cm));
> +}
> +
> +#define GICD_CTLR            0x0000
> +#define GICD_TYPER           0x0004
> +#define GICD_IIDR            0x0008
> +#define GICD_STATUSR         0x0010
> +#define GICD_SETSPI_NSR      0x0040
> +#define GICD_CLRSPI_NSR      0x0048
> +#define GICD_SETSPI_SR       0x0050
> +#define GICD_CLRSPI_SR       0x0058
> +#define GICD_SEIR            0x0068
> +#define GICD_ISENABLER       0x0100
> +#define GICD_ICENABLER       0x0180
> +#define GICD_ISPENDR         0x0200
> +#define GICD_ICPENDR         0x0280
> +#define GICD_ISACTIVER       0x0300
> +#define GICD_ICACTIVER       0x0380
> +#define GICD_IPRIORITYR      0x0400
> +#define GICD_ICFGR           0x0C00
> +#define GICD_IROUTER         0x6000
> +#define GICD_PIDR2           0xFFE8
> +
> +/* GICD_CTLR fields  */
> +#define GICD_CTLR_EN_GRP0           (1U << 0)
> +#define GICD_CTLR_EN_GRP1NS         (1U << 1) /* GICv3 5.3.20 */
> +#define GICD_CTLR_EN_GRP1S          (1U << 2)
> +#define GICD_CTLR_EN_GRP1_ALL       (GICD_CTLR_EN_GRP1NS | 
> GICD_CTLR_EN_GRP1S)
> +#define GICD_CTLR_ARE               (1U << 4)
> +#define GICD_CTLR_ARE_S             (1U << 4)
> +#define GICD_CTLR_ARE_NS            (1U << 5)
> +#define GICD_CTLR_DS                (1U << 6)
> +#define GICD_CTLR_RWP               (1U << 31)
> +
> +
> +#define GICD_IROUTER_SPI_MODE_ONE    (0U << 31)
> +#define GICD_IROUTER_SPI_MODE_ANY    (1U << 31)
> +
> +#define GIC_PIDR2_ARCH_MASK   0xf0
> +#define GIC_PIDR2_ARCH_GICv3  0x30
> +#define GIC_PIDR2_ARCH_GICv4  0x40

 These three are not used anywhere.

> +
> +/*
> + * Re-Distributor registers, offsets from RD_base
> + */
> +#define GICR_CTLR             GICD_CTLR
> +#define GICR_IIDR             0x0004
> +#define GICR_TYPER            0x0008
> +#define GICR_STATUSR          GICD_STATUSR
> +#define GICR_WAKER            0x0014
> +#define GICR_SETLPIR          0x0040
> +#define GICR_CLRLPIR          0x0048
> +#define GICR_SEIR             GICD_SEIR
> +#define GICR_PROPBASER        0x0070
> +#define GICR_PENDBASER        0x0078
> +#define GICR_INVLPIR          0x00A0
> +#define GICR_INVALLR          0x00B0
> +#define GICR_SYNCR            0x00C0
> +#define GICR_MOVLPIR          0x0100
> +#define GICR_MOVALLR          0x0110
> +#define GICR_PIDR2            GICD_PIDR2
> +
> +#define GICR_WAKER_ProcessorSleep    (1U << 1)
> +#define GICR_WAKER_ChildrenAsleep    (1U << 2)
> +
> +/*
> + * Re-Distributor registers, offsets from SGI_base
> + */
> +#define GICR_ISENABLER0         GICD_ISENABLER
> +#define GICR_ICENABLER0         GICD_ICENABLER
> +#define GICR_ISPENDR0           GICD_ISPENDR
> +#define GICR_ICPENDR0           GICD_ICPENDR
> +#define GICR_ISACTIVER0         GICD_ISACTIVER
> +#define GICR_ICACTIVER0         GICD_ICACTIVER
> +#define GICR_IPRIORITYR0        GICD_IPRIORITYR
> +#define GICR_ICFGR0             GICD_ICFGR
> +
> +#define GICR_TYPER_VLPIS        (1U << 1)
> +#define GICR_TYPER_LAST         (1U << 4)
> +
> +/*
> + * Simulated used system registers
> + */
> +#define GICC_CTLR_EN_GRP0    (1U << 0)
> +#define GICC_CTLR_EN_GRP1    (1U << 1)
> +#define GICC_CTLR_ACK_CTL    (1U << 2)
> +#define GICC_CTLR_FIQ_EN     (1U << 3)
> +#define GICC_CTLR_CBPR       (1U << 4) /* GICv1: SBPR */
> +#define GICC_CTLR_EOIMODE    (1U << 9)
> +#define GICC_CTLR_EOIMODE_NS (1U << 10)
> +
> +#endif /* !QEMU_ARM_GIC_INTERNAL_H */
> diff --git a/include/hw/intc/arm_gicv3.h b/include/hw/intc/arm_gicv3.h
> new file mode 100644
> index 0000000..a03af35
> --- /dev/null
> +++ b/include/hw/intc/arm_gicv3.h
> @@ -0,0 +1,44 @@
> +/*
> + * ARM GIC support
> + *
> + * Copyright (c) 2012 Linaro Limited
> + * Copyright (c) 2015 Huawei.
> + * Written by Peter Maydell
> + * Extended to 64 cores by Shlomo Pongratz
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License along
> + * with this program; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef HW_ARM_GICV3_H
> +#define HW_ARM_GICV3_H
> +
> +#include "arm_gicv3_common.h"
> +
> +#define TYPE_ARM_GICV3 "arm_gicv3"
> +#define ARM_GICV3(obj) \
> +     OBJECT_CHECK(GICv3State, (obj), TYPE_ARM_GICV3)
> +#define ARM_GICV3_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(ARMGICv3Class, (klass), TYPE_ARM_GICV3)
> +#define ARM_GICV3_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(ARMGICv3Class, (obj), TYPE_ARM_GICV3)
> +
> +typedef struct ARMGICv3Class {
> +    /*< private >*/
> +    ARMGICv3CommonClass parent_class;
> +    /*< public >*/
> +
> +    DeviceRealize parent_realize;
> +} ARMGICv3Class;
> +
> +#endif
> diff --git a/include/hw/intc/arm_gicv3_common.h 
> b/include/hw/intc/arm_gicv3_common.h
> index c2fd8da..aa32229 100644
> --- a/include/hw/intc/arm_gicv3_common.h
> +++ b/include/hw/intc/arm_gicv3_common.h
> @@ -26,6 +26,51 @@
>  #include "hw/sysbus.h"
>  #include "hw/intc/arm_gic_common.h"
> 
> +/* Maximum number of possible interrupts, determined by the GIC architecture 
> */
> +#define GICV3_MAXIRQ 1020
> +/* First 32 are private to each CPU (SGIs and PPIs). */
> +#define GICV3_INTERNAL 32
> +#define GICV3_NR_SGIS 16
> +
> +#define ARM_AFF0_SHIFT 0
> +#define ARM_AFF0_MASK  (0xFFULL << ARM_AFF0_SHIFT)
> +#define ARM_AFF1_SHIFT 8
> +#define ARM_AFF1_MASK  (0xFFULL << ARM_AFF1_SHIFT)
> +#define ARM_AFF2_SHIFT 16
> +#define ARM_AFF2_MASK  (0xFFULL << ARM_AFF2_SHIFT)
> +#define ARM_AFF3_SHIFT 32
> +#define ARM_AFF3_MASK  (0xFFULL << ARM_AFF3_SHIFT)

 Actually, these are defined in target-arm/cpu-qom.h. Looks like it was my 
fault and they have to be moved to something like
include/hw/cpu/cpu_arm.h. I'll post some patches to move them, but not sure 
that Peter accepts them, just because "there are no
users for this yet".

> +
> +#define MAX_NR_GROUP_PRIO 128
> +
> +typedef struct gicv3_irq_state {
> +    /* The enable bits are only banked for per-cpu interrupts.  */
> +    unsigned long *enabled;
> +    unsigned long *pending;
> +    unsigned long *active;
> +    unsigned long *level;
> +    unsigned long *group;
> +    unsigned long *target;
> +    uint16_t *last_active;
> +    bool edge_trigger; /* true: edge-triggered, false: level-triggered  */
> +    int32_t num_cpu; /* For VMSTATE_BITMAP & VMSTATE_VARRAY */
> +} gicv3_irq_state;
> +
> +typedef struct gicv3_sgi_state {
> +    unsigned long *pending;
> +    int32_t num_cpu; /* For VMSTATE_BITMAP */
> +} gicv3_sgi_state;
> +
> +typedef struct gicv3_sgi_vec {
> +    struct gicv3_sgi_state *state;
> +    int32_t num_cpu; /* For VMSTATE_VARRAY */
> +} gicv3_sgi_vec;
> +
> +typedef struct gicv3_priority {
> +    uint8_t *p;
> +    int32_t num_cpu; /* For VMSTATE_VARRAY */
> +} gicv3_Priority;
> +
>  typedef struct GICv3State {
>      /*< private >*/
>      SysBusDevice parent_obj;
> @@ -33,14 +78,45 @@ typedef struct GICv3State {
> 
>      qemu_irq *parent_irq;
>      qemu_irq *parent_fiq;
> +    /* GICD_CTLR; for a GIC with the security extensions the NS banked 
> version
> +     * of this register is just an alias of bit 1 of the S banked version.
> +     */
> +    uint32_t ctlr;
> +    /* Sim GICC_CTLR; again, the NS banked version is just aliases of bits of
> +     * the S banked register, so our state only needs to store the S version.
> +     */
> +    uint32_t *cpu_ctlr;
> +    unsigned long *cpu_enabled;
> +
> +    gicv3_irq_state irq_state[GICV3_MAXIRQ];
> +    gicv3_Priority priority1[GICV3_INTERNAL];
> +    uint8_t priority2[GICV3_MAXIRQ - GICV3_INTERNAL];
> +    /* For each SGI on the target CPU, we store bitmap
> +     * indicating which source CPUs have made this SGI
> +     * pending on the target CPU. These correspond to
> +     * the bytes in the GIC_SPENDSGIR* registers as
> +     * read by the target CPU.
> +     */
> +    gicv3_sgi_vec sgi[GICV3_NR_SGIS];
> +
> +    uint16_t *priority_mask;
> +    uint16_t *running_irq;
> +    uint16_t *running_priority;
> +    uint16_t *current_pending;
> +    uint32_t num_mp_affinity;
> +    uint64_t *mp_affinity;
> 
>      MemoryRegion iomem_dist; /* Distributor */
> +    MemoryRegion iomem_spi;
> +    MemoryRegion iomem_its_cntrl;
> +    MemoryRegion iomem_its;
>      MemoryRegion iomem_redist; /* Redistributors */
> 
> +    uint32_t cpu_mask; /* For redistributer */
>      uint32_t num_cpu;
>      uint32_t num_irq;
>      uint32_t revision;
> -    bool security_extn;
> +    uint8_t security_levels; /* replace seurity extentions */
> 
>      int dev_fd; /* kvm device fd if backed by kvm vgic support */
>  } GICv3State;
> --
> 1.9.1

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia




reply via email to

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