[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
- Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files,
Pavel Fedin <=
- Message not available
- Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files, Pavel Fedin, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files, Shlomo Pongratz, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files, Pavel Fedin, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files, Shlomo Pongratz, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files, Pavel Fedin, 2015/10/21
- Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files, Shlomo Pongratz, 2015/10/21