From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:44811) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZpER9-0006xW-Dm for qemu-devel@nongnu.org; Thu, 22 Oct 2015 07:53:43 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZpER4-0003tZ-BM for qemu-devel@nongnu.org; Thu, 22 Oct 2015 07:53:39 -0400 Received: from mailout3.w1.samsung.com ([210.118.77.13]:40665) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZpER3-0003rt-VN for qemu-devel@nongnu.org; Thu, 22 Oct 2015 07:53:34 -0400 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout3.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0NWM001JZED5GM00@mailout3.w1.samsung.com> for qemu-devel@nongnu.org; Thu, 22 Oct 2015 12:53:29 +0100 (BST) From: Pavel Fedin References: <1445361732-16257-1-git-send-email-shlomopongratz@gmail.com> <1445361732-16257-2-git-send-email-shlomopongratz@gmail.com> In-reply-to: <1445361732-16257-2-git-send-email-shlomopongratz@gmail.com> Date: Thu, 22 Oct 2015 14:53:27 +0300 Message-id: <010601d10cc0$43ed14c0$cbc73e40$@samsung.com> MIME-version: 1.0 Content-type: text/plain; charset=us-ascii Content-transfer-encoding: 7bit Content-language: ru Subject: Re: [Qemu-devel] [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: 'Shlomo Pongratz' , qemu-devel@nongnu.org Cc: peter.maydell@linaro.org, eric.auger@linaro.org, 'Shlomo Pongratz' , shannon.zhao@linaro.org, ashoks@broadcom.com, imammedo@redhat.com 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:shlomopongratz@gmail.com] > Sent: Tuesday, October 20, 2015 8:22 PM > To: qemu-devel@nongnu.org > Cc: p.fedin@samsung.com; peter.maydell@linaro.org; eric.auger@linaro.org; > shannon.zhao@linaro.org; imammedo@redhat.com; ashoks@broadcom.com; Shlomo Pongratz > Subject: [PATCH RFC V5 1/9] hw/intc: Implement GIC-500 support files > > From: Shlomo Pongratz > > 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 > --- > 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 . > + */ > + > +#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 . > + */ > + > +#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