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: Wed, 21 Oct 2015 09:48:51 +0300

 Hello!

> -----Original Message-----
> From: Shlomo Pongratz [mailto:address@hidden
> Sent: Wednesday, October 21, 2015 6:09 AM
> 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()
> +    }
>  };

 If you look at our conversation with Peter, first i implemented similar data 
structures, and he disliked it. He suggested to
separate SPIs and PPIs. So, i came up with fixed-size bitmaps, and two 
structures: global data and per-CPU data. SPIs are stored in
global structure, SGIs/PPIs - in per-CPU one.
 I cc'ed all my patches to you, have you seen them?

> 
>  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;

 GICV3_INTERNAL was criticised long time ago, because kvm_arm_gic_set_irq(), 
used by both vGIC implementations, uses GIC_INTERNAL.
Anyway, these two constants are the same.

>      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),

 Why this change? Anyway, we either have or don't have trustzone support. So, 
what's wrong with "has-security-extensions" boolean?
It would be convenient to have the same interface for all GIC versions.

> +    DEFINE_PROP_ARRAY("mp-affinity", GICv3State, num_mp_affinity, 
> mp_affinity,
> +                      qdev_prop_uint64, uint64_t),

 Hmmm... Is it convenient to use? In my experimental code i added this property 
to CPU, iterated over CPUs and compared value of the
property with IROUTER.

>      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)
> +
> +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)
> +#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
> +
> +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
> +
> +/*
> + * 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)
> +
> +#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]