diff mbox

[v4,4/9] Add virt-v3 machine that uses GIC-500

Message ID 7301d5cb99fe7d96090333fc697c8b1b2d6514a6.1435844519.git.p.fedin@samsung.com
State New
Headers show

Commit Message

Pavel Fedin July 2, 2015, 2:14 p.m. UTC
Instead of adding gic-version option, it is much easier to create a new machine
type. The problem is mc->max_cpus. I tried to change this value inside property
handling code, but it simply did not work, and i still got " Maximum CPUs
greater than specified machine type limit" error from qemu. It looks like CPU
number limitation is evaluated before machine is instantiated and properties
are evaluated. It is possible to make a workaround, of course, but it seems to
require much more changes than simply subclassing a machine.

This patch also introduces kernel_irqchip_type member in Machine class.
Currently it it used only by virt machine for its internal purposes, however in
future it is to be passed to KVM in kvm_irqchip_create(). The variable is
defined as int in order to be architecture agnostic, for potential future
users.

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
---
 hw/arm/virt.c         | 141 ++++++++++++++++++++++++++++++++++++++++++--------
 include/hw/arm/fdt.h  |   2 +-
 include/hw/arm/virt.h |   6 ++-
 include/hw/boards.h   |   1 +
 4 files changed, 126 insertions(+), 24 deletions(-)

Comments

Daniel P. Berrangé July 2, 2015, 2:25 p.m. UTC | #1
On Thu, Jul 02, 2015 at 05:14:02PM +0300, Pavel Fedin wrote:
> Instead of adding gic-version option, it is much easier to create a new machine
> type. The problem is mc->max_cpus. I tried to change this value inside property
> handling code, but it simply did not work, and i still got " Maximum CPUs
> greater than specified machine type limit" error from qemu. It looks like CPU
> number limitation is evaluated before machine is instantiated and properties
> are evaluated. It is possible to make a workaround, of course, but it seems to
> require much more changes than simply subclassing a machine.
> 
> This patch also introduces kernel_irqchip_type member in Machine class.
> Currently it it used only by virt machine for its internal purposes, however in
> future it is to be passed to KVM in kvm_irqchip_create(). The variable is
> defined as int in order to be architecture agnostic, for potential future
> users.
> 
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>

As mentioned in previous postings, this should be done as a property on
the existing machine type, not a new machine type.

Regards,
Daniel
Pavel Fedin July 2, 2015, 2:47 p.m. UTC | #2
Hello!

 I already explained this earlier: http://lists.nongnu.org/archive/html/qemu-devel/2015-05/msg04842.html, and i tried to explain this in commit message. Current qemu architecture does not allow doing this in a clean way.
 I can simply change mc->max_cpus for 'virt' machine to 64 (always), and then check user-supplied value against GIC limitation by myself. And produce error. This will be code duplication. Do you think it is better?
 Anybody else (Peter, Cristoffer ?), please vote.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Christoffer Dall July 2, 2015, 3:06 p.m. UTC | #3
On Thu, Jul 2, 2015 at 4:47 PM, Pavel Fedin <p.fedin@samsung.com> wrote:
>  Hello!
>
>  I already explained this earlier: http://lists.nongnu.org/archive/html/qemu-devel/2015-05/msg04842.html, and i tried to explain this in commit message. Current qemu architecture does not allow doing this in a clean way.
>  I can simply change mc->max_cpus for 'virt' machine to 64 (always), and then check user-supplied value against GIC limitation by myself. And produce error. This will be code duplication. Do you think it is better?
>  Anybody else (Peter, Cristoffer ?), please vote.
>
We definitely need a single virt machine, not multiple machines.  I
don't know enough about the QEMU internals as to how to accomplish
this in detail.

-Christoffer
Pavel Fedin July 2, 2015, 3:30 p.m. UTC | #4
> We definitely need a single virt machine, not multiple machines.  I
> don't know enough about the QEMU internals as to how to accomplish
> this in detail.

 Two beat one... Okay, i surrender. :)
 I will respin this, hopefully tomorrow. I will change to machine option, and i will likely leave out software GIC emulation. Everyone okay with this? Peter?

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Christoffer Dall July 2, 2015, 3:54 p.m. UTC | #5
On Thu, Jul 2, 2015 at 5:30 PM, Pavel Fedin <p.fedin@samsung.com> wrote:
>> We definitely need a single virt machine, not multiple machines.  I
>> don't know enough about the QEMU internals as to how to accomplish
>> this in detail.
>
>  Two beat one... Okay, i surrender. :)
>  I will respin this, hopefully tomorrow. I will change to machine option, and i will likely leave out software GIC emulation. Everyone okay with this? Peter?
>
I think you should leave out the software emulation part for this
series and let's concentrate on getting this in first.

Also, you should make sure you have an agreement with Shlomo about
taking over his patches before doing so (maybe you are already?).

Thanks,
-Christoffer
Daniel P. Berrangé July 2, 2015, 4:21 p.m. UTC | #6
On Thu, Jul 02, 2015 at 05:47:04PM +0300, Pavel Fedin wrote:
>  Hello!
> 
>  I already explained this earlier: http://lists.nongnu.org/archive/html/qemu-devel/2015-05/msg04842.html, and i tried to explain this in commit message. Current qemu architecture does not allow doing this in a clean way.
>  I can simply change mc->max_cpus for 'virt' machine to 64 (always), and
>  then check user-supplied value against GIC limitation by myself. And
>  produce error. This will be code duplication. Do you think it is better?
>  Anybody else (Peter, Cristoffer ?), please vote.

Yes, just increase the declared max cpus to the larger of the two values,
and do a manual check at time of use

Regards,
Daniel
Pavel Fedin July 3, 2015, 6:52 a.m. UTC | #7
Hi!

> I think you should leave out the software emulation part for this
> series and let's concentrate on getting this in first.

 Ok.

> Also, you should make sure you have an agreement with Shlomo about
> taking over his patches before doing so (maybe you are already?).

 Shlomo has posted his work here, doesn't this automatically mean that he is sharing it with the community? Additionally, i do not drop his authorship.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Christoffer Dall July 3, 2015, 7:42 a.m. UTC | #8
On Fri, Jul 3, 2015 at 8:52 AM, Pavel Fedin <p.fedin@samsung.com> wrote:
>  Hi!
>
>> I think you should leave out the software emulation part for this
>> series and let's concentrate on getting this in first.
>
>  Ok.
>
>> Also, you should make sure you have an agreement with Shlomo about
>> taking over his patches before doing so (maybe you are already?).
>
>  Shlomo has posted his work here, doesn't this automatically mean that he is sharing it with the community? Additionally, i do not drop his authorship.
>
Well, it can become a little messy for everyone if Shlomo is working
on refactoring and respinning his patches, and meanwhile new versions
of his patches go out embedded as part of another patch set.  It's not
exactly harmful, but usually doesn't happen without prior agreement
amongst the involved parties, I would say.

-Christoffer
Pavel Fedin July 3, 2015, 8:47 a.m. UTC | #9
Hi!

> Well, it can become a little messy for everyone if Shlomo is working
> on refactoring and respinning his patches, and meanwhile new versions
> of his patches go out embedded as part of another patch set

 Exactly for this reason i refactor his code as little as possible, so that he can merge things easily, if he is around. But looks like he become upset and gone, we haven't seen him around for several weeks.
 Meanwhile i'll try to incorporate SW emulation too, because i also may need it. Just needs more time, and yes, ITS is a separate thing (by the way i even have the code, just without LPIs). So yes, i'll split it up a bit more.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Christoffer Dall July 3, 2015, 10:23 a.m. UTC | #10
On Fri, Jul 3, 2015 at 10:47 AM, Pavel Fedin <p.fedin@samsung.com> wrote:
>  Hi!
>
>> Well, it can become a little messy for everyone if Shlomo is working
>> on refactoring and respinning his patches, and meanwhile new versions
>> of his patches go out embedded as part of another patch set
>
>  Exactly for this reason i refactor his code as little as possible, so that he can merge things easily, if he is around. But looks like he become upset and gone, we haven't seen him around for several weeks.

I don't think you should put words in other people's mouth.  He may be
on vacation or awaiting approval for submitting this stuff or
something like that.

That said, Shlomo, what is your status?

>  Meanwhile i'll try to incorporate SW emulation too, because i also may need it. Just needs more time, and yes, ITS is a separate thing (by the way i even have the code, just without LPIs). So yes, i'll split it up a bit more.
>

I *really* think we should try to *agree* on who does what here, so
that we don't have more copies of the same work etc. on the list.

-Christoffer
diff mbox

Patch

diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 4846892..5c07d07 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -48,6 +48,7 @@ 
 #include "hw/arm/sysbus-fdt.h"
 #include "hw/platform-bus.h"
 #include "hw/arm/fdt.h"
+#include "linux/kvm.h" /* For KVM_DEV_TYPE_ARM_VGIC_V{2|3} */
 
 /* Number of external interrupt lines to configure the GIC with */
 #define NUM_IRQS 256
@@ -67,6 +68,7 @@  typedef struct VirtBoardInfo {
     uint32_t clock_phandle;
     uint32_t gic_phandle;
     uint32_t v2m_phandle;
+    const char *class_name;
 } VirtBoardInfo;
 
 typedef struct {
@@ -80,6 +82,7 @@  typedef struct {
 } VirtMachineState;
 
 #define TYPE_VIRT_MACHINE   "virt"
+#define TYPE_VIRTV3_MACHINE   "virt-v3"
 #define VIRT_MACHINE(obj) \
     OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
 #define VIRT_MACHINE_GET_CLASS(obj) \
@@ -106,7 +109,12 @@  static const MemMapEntry a15memmap[] = {
     /* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
     [VIRT_GIC_DIST] =           { 0x08000000, 0x00010000 },
     [VIRT_GIC_CPU] =            { 0x08010000, 0x00010000 },
-    [VIRT_GIC_V2M] =            { 0x08020000, 0x00001000 },
+    [VIRT_GIC_V2M] =            { 0x08020000, 0x00010000 },
+    /* On v3 VIRT_GIC_DIST_MBI and VIRT_ITS_CONTROL take place of
+     * VIRT_GIC_CPU and VIRT_GIC_V2M respectively
+     */
+    [VIRT_ITS_TRANSLATION] =    { 0x08030000, 0x00010000 },
+    [VIRT_LPI] =                { 0x08040000, 0x00800000 },
     [VIRT_UART] =               { 0x09000000, 0x00001000 },
     [VIRT_RTC] =                { 0x09010000, 0x00001000 },
     [VIRT_FW_CFG] =             { 0x09020000, 0x0000000a },
@@ -138,16 +146,25 @@  static VirtBoardInfo machines[] = {
         .cpu_model = "cortex-a53",
         .memmap = a15memmap,
         .irqmap = a15irqmap,
+        .class_name = TYPE_ARM_CPU,
+    },
+    {
+        .cpu_model = "cortex-a53",
+        .memmap = a15memmap,
+        .irqmap = a15irqmap,
+        .class_name = TYPE_AARCH64_CPU,
     },
     {
         .cpu_model = "cortex-a57",
         .memmap = a15memmap,
         .irqmap = a15irqmap,
+        .class_name = TYPE_AARCH64_CPU,
     },
     {
         .cpu_model = "host",
         .memmap = a15memmap,
         .irqmap = a15irqmap,
+        .class_name = TYPE_ARM_CPU,
     },
 };
 
@@ -256,10 +271,13 @@  static void fdt_add_timer_nodes(const VirtBoardInfo *vbi)
      * they are edge-triggered.
      */
     ARMCPU *armcpu;
+    uint32_t max;
     uint32_t irqflags = GIC_FDT_IRQ_FLAGS_EDGE_LO_HI;
 
+    /* Argument is 32 bit but 8 bits are reserved for flags */
+    max = (vbi->smp_cpus >= 24) ? 24 : vbi->smp_cpus;
     irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
-                         GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << vbi->smp_cpus) - 1);
+                         GIC_FDT_IRQ_PPI_CPU_WIDTH, (1 << max) - 1);
 
     qemu_fdt_add_subnode(vbi->fdt, "/timer");
 
@@ -283,6 +301,18 @@  static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
 {
     int cpu;
 
+    /*
+     * From Documentation/devicetree/bindings/arm/cpus.txt
+     *  On ARM v8 64-bit systems value should be set to 2,
+     *  that corresponds to the MPIDR_EL1 register size.
+     *  If MPIDR_EL1[63:32] value is equal to 0 on all CPUs
+     *  in the system, #address-cells can be set to 1, since
+     *  MPIDR_EL1[63:32] bits are not used for CPUs
+     *  identification.
+     *
+     *  Now GIC500 doesn't support affinities 2 & 3 so currently
+     *  #address-cells can stay 1 until future GIC
+     */
     qemu_fdt_add_subnode(vbi->fdt, "/cpus");
     qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#address-cells", 0x1);
     qemu_fdt_setprop_cell(vbi->fdt, "/cpus", "#size-cells", 0x0);
@@ -319,25 +349,36 @@  static void fdt_add_v2m_gic_node(VirtBoardInfo *vbi)
     qemu_fdt_setprop_cell(vbi->fdt, "/intc/v2m", "phandle", vbi->v2m_phandle);
 }
 
-static void fdt_add_gic_node(VirtBoardInfo *vbi)
+static void fdt_add_gic_node(VirtBoardInfo *vbi, int type)
 {
     vbi->gic_phandle = qemu_fdt_alloc_phandle(vbi->fdt);
     qemu_fdt_setprop_cell(vbi->fdt, "/", "interrupt-parent", vbi->gic_phandle);
 
     qemu_fdt_add_subnode(vbi->fdt, "/intc");
-    /* 'cortex-a15-gic' means 'GIC v2' */
-    qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
-                            "arm,cortex-a15-gic");
     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#interrupt-cells", 3);
     qemu_fdt_setprop(vbi->fdt, "/intc", "interrupt-controller", NULL, 0);
-    qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
-                                     2, vbi->memmap[VIRT_GIC_DIST].base,
-                                     2, vbi->memmap[VIRT_GIC_DIST].size,
-                                     2, vbi->memmap[VIRT_GIC_CPU].base,
-                                     2, vbi->memmap[VIRT_GIC_CPU].size);
     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#address-cells", 0x2);
     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "#size-cells", 0x2);
     qemu_fdt_setprop(vbi->fdt, "/intc", "ranges", NULL, 0);
+    if (type == KVM_DEV_TYPE_ARM_VGIC_V3) {
+        qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
+                                "arm,gic-v3");
+        qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
+                                     2, vbi->memmap[VIRT_GIC_DIST].base,
+                                     2, vbi->memmap[VIRT_GIC_DIST].size,
+                                     2, vbi->memmap[VIRT_LPI].base,
+                                     2, vbi->memmap[VIRT_LPI].size);
+    } else {
+        /* 'cortex-a15-gic' means 'GIC v2' */
+        qemu_fdt_setprop_string(vbi->fdt, "/intc", "compatible",
+                                "arm,cortex-a15-gic");
+        qemu_fdt_setprop_sized_cells(vbi->fdt, "/intc", "reg",
+                                      2, vbi->memmap[VIRT_GIC_DIST].base,
+                                      2, vbi->memmap[VIRT_GIC_DIST].size,
+                                      2, vbi->memmap[VIRT_GIC_CPU].base,
+                                      2, vbi->memmap[VIRT_GIC_CPU].size);
+    }
+ 
     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle);
 }
 
@@ -360,20 +401,32 @@  static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
     fdt_add_v2m_gic_node(vbi);
 }
 
-static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
+static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type)
 {
     /* We create a standalone GIC v2 */
     DeviceState *gicdev;
     SysBusDevice *gicbusdev;
-    const char *gictype = "arm_gic";
+    const char *gictype;
     int i;
 
-    if (kvm_irqchip_in_kernel()) {
+    if (type == KVM_DEV_TYPE_ARM_VGIC_V3) {
+        gictype = "arm_gicv3";
+    } else if (kvm_irqchip_in_kernel()) {
         gictype = "kvm-arm-gic";
+    } else {
+        gictype = "arm_gic";
     }
 
     gicdev = qdev_create(NULL, gictype);
-    qdev_prop_set_uint32(gicdev, "revision", 2);
+ 
+    for (i = 0; i < vbi->smp_cpus; i++) {
+        CPUState *cpu = qemu_get_cpu(i);
+        CPUARMState *env = cpu->env_ptr;
+        env->nvic = gicdev;
+    }
+
+    qdev_prop_set_uint32(gicdev, "revision",
+                         type == KVM_DEV_TYPE_ARM_VGIC_V3 ? 3 : 2);
     qdev_prop_set_uint32(gicdev, "num-cpu", smp_cpus);
     /* Note that the num-irq property counts both internal and external
      * interrupts; there are always 32 of the former (mandated by GIC spec).
@@ -383,6 +436,11 @@  static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
     gicbusdev = SYS_BUS_DEVICE(gicdev);
     sysbus_mmio_map(gicbusdev, 0, vbi->memmap[VIRT_GIC_DIST].base);
     sysbus_mmio_map(gicbusdev, 1, vbi->memmap[VIRT_GIC_CPU].base);
+    if (type == KVM_DEV_TYPE_ARM_VGIC_V3) {
+        sysbus_mmio_map(gicbusdev, 2, vbi->memmap[VIRT_ITS_CONTROL].base);
+        sysbus_mmio_map(gicbusdev, 3, vbi->memmap[VIRT_ITS_TRANSLATION].base);
+        sysbus_mmio_map(gicbusdev, 4, vbi->memmap[VIRT_LPI].base);
+    }
 
     /* Wire the outputs from each CPU's generic timer to the
      * appropriate GIC PPI inputs, and the GIC's IRQ output to
@@ -409,9 +467,11 @@  static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic)
         pic[i] = qdev_get_gpio_in(gicdev, i);
     }
 
-    fdt_add_gic_node(vbi);
+    fdt_add_gic_node(vbi, type);
 
-    create_v2m(vbi, pic);
+    if (type == KVM_DEV_TYPE_ARM_VGIC_V2) {
+        create_v2m(vbi, pic);
+    }
 }
 
 static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
@@ -825,7 +885,7 @@  static void machvirt_init(MachineState *machine)
     create_fdt(vbi);
 
     for (n = 0; n < smp_cpus; n++) {
-        ObjectClass *oc = cpu_class_by_name(TYPE_ARM_CPU, cpustr[0]);
+        ObjectClass *oc = cpu_class_by_name(vbi->class_name, cpustr[0]);
         CPUClass *cc = CPU_CLASS(oc);
         Object *cpuobj;
         Error *err = NULL;
@@ -875,7 +935,7 @@  static void machvirt_init(MachineState *machine)
 
     create_flash(vbi);
 
-    create_gic(vbi, pic);
+    create_gic(vbi, pic, machine->kernel_irqchip_type);
 
     create_uart(vbi, pic);
 
@@ -933,7 +993,7 @@  static void virt_set_secure(Object *obj, bool value, Error **errp)
     vms->secure = value;
 }
 
-static void virt_instance_init(Object *obj)
+static void virt_instance_init_common(Object *obj)
 {
     VirtMachineState *vms = VIRT_MACHINE(obj);
 
@@ -947,6 +1007,14 @@  static void virt_instance_init(Object *obj)
                                     NULL);
 }
 
+static void virt_instance_init(Object *obj)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->kernel_irqchip_type = KVM_DEV_TYPE_ARM_VGIC_V2;
+    virt_instance_init_common(obj);
+}
+
 static void virt_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -969,9 +1037,38 @@  static const TypeInfo machvirt_info = {
     .class_init = virt_class_init,
 };
 
+static void virtv3_instance_init(Object *obj)
+{
+    MachineState *ms = MACHINE(obj);
+
+    ms->kernel_irqchip_type = KVM_DEV_TYPE_ARM_VGIC_V3;
+    virt_instance_init_common(obj);
+}
+
+static void virtv3_class_init(ObjectClass *oc, void *data)
+{
+    MachineClass *mc = MACHINE_CLASS(oc);
+
+    mc->name = TYPE_VIRTV3_MACHINE;
+    mc->desc = "ARM Virtual Machine with GICv3",
+    mc->init = machvirt_init;
+    /* With gic3 full implementation (with bitops) rase the lmit to 128 */
+    mc->max_cpus = 64;
+}
+
+static const TypeInfo machvirtv3_info = {
+    .name = TYPE_VIRTV3_MACHINE,
+    .parent = TYPE_VIRT_MACHINE,
+    .instance_size = sizeof(VirtMachineState),
+    .instance_init = virtv3_instance_init,
+    .class_size = sizeof(VirtMachineClass),
+    .class_init = virtv3_class_init,
+};
+
 static void machvirt_machine_init(void)
 {
     type_register_static(&machvirt_info);
+    type_register_static(&machvirtv3_info);
 }
 
 machine_init(machvirt_machine_init);
diff --git a/include/hw/arm/fdt.h b/include/hw/arm/fdt.h
index c3d5015..dd794dd 100644
--- a/include/hw/arm/fdt.h
+++ b/include/hw/arm/fdt.h
@@ -29,6 +29,6 @@ 
 #define GIC_FDT_IRQ_FLAGS_LEVEL_LO 8
 
 #define GIC_FDT_IRQ_PPI_CPU_START 8
-#define GIC_FDT_IRQ_PPI_CPU_WIDTH 8
+#define GIC_FDT_IRQ_PPI_CPU_WIDTH 24
 
 #endif
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index d22fd8e..852efb9 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -46,6 +46,11 @@  enum {
     VIRT_CPUPERIPHS,
     VIRT_GIC_DIST,
     VIRT_GIC_CPU,
+    VIRT_GIC_V2M,
+    VIRT_GIC_DIST_MBI = VIRT_GIC_CPU,
+    VIRT_ITS_CONTROL = VIRT_GIC_V2M,
+    VIRT_ITS_TRANSLATION,
+    VIRT_LPI,
     VIRT_UART,
     VIRT_MMIO,
     VIRT_RTC,
@@ -54,7 +59,6 @@  enum {
     VIRT_PCIE_MMIO,
     VIRT_PCIE_PIO,
     VIRT_PCIE_ECAM,
-    VIRT_GIC_V2M,
     VIRT_PLATFORM_BUS,
 };
 
diff --git a/include/hw/boards.h b/include/hw/boards.h
index 6379901..6e42cf2 100644
--- a/include/hw/boards.h
+++ b/include/hw/boards.h
@@ -126,6 +126,7 @@  struct MachineState {
     char *accel;
     bool kernel_irqchip_allowed;
     bool kernel_irqchip_required;
+    int kernel_irqchip_type;
     int kvm_shadow_mem;
     char *dtb;
     char *dumpdtb;