The virt board currently only supports either a GICv2 with a possible
GICv2m for handling MSI interrupts, or else a GICv3 with a possible
ITS for handling MSI interrupts. There is one board property, which
lets you say "its=(off|on)" and controls only whether there is an ITS
or not.
This is awkward for macOS HVF, where you get a GICv3
without ITS and MSI handling needs a GICv2m.
Create a new board property "msi" which gives the user clearer
control over how MSI interrupts are handled:
- msi=its : create an ITS
- msi=gicv2m : create a GICv2m
- msi=off : do not create any MSI handling device
- msi=auto : create the best MSI handling device available
for the GIC version and accelerator
The default is 'auto'.
The existing 'its' property becomes a deprecated property
kept for compatibility. Existing users of "its=on" should
prefer "msi=auto"; users of "its=off" should use "msi=off".
The backwards compatibility cases we need to support are:
(1) TCG, virt-6.1 and earlier: no_tcg_its is set
-- you can have a gicv2 (always with a gicv2m)
-- if you specify gic-version=3 you get a GICv3 without ITS
(2) TCG, virt-6.2 and later:
-- gic-version=2 still has gicv2m
-- gic-version=3 by default gives you an ITS; if you also
say its=off you get GICv3 with no ITS
-- there is no case where we provide a GICv3 and are
unable to provide an ITS for it
(3) KVM (any version):
-- gic-version=2 has a gicv2m
-- gic-version=3 gives you an ITS by default; its=off
will remove it
-- there is no case where we provide a GICv3 and are
unable to provide an ITS for it
(4) HVF:
-- only gic-version=2 works, you get a gicv2m
Signed-off-by: Peter Maydell <[email protected]>
---
docs/system/arm/virt.rst | 21 ++++++++++++-
hw/arm/virt.c | 64 +++++++++++++++++++++++++++++++++++++++-
include/hw/arm/virt.h | 1 +
3 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst
index e5570773ba..4cc54e38db 100644
--- a/docs/system/arm/virt.rst
+++ b/docs/system/arm/virt.rst
@@ -167,9 +167,28 @@ gic-version
with TCG this is currently ``3`` if ``virtualization`` is ``off`` and
``4`` if ``virtualization`` is ``on``, but this may change in future)
+msi
+ Specify the MSI controller to use to handle MSI and MSI-X interrupts
+ from PCI devices. Valid values are:
+
+ ``its``
+ ITS, which can be used with a GICv3 or better.
+ ``gicv2m``
+ The GICv2m; this is typically used with a GICv2, but it is possible
+ to use it with a GICv3.
+ ``none``
+ Do not provide any MSI controller. MSI and MSI-X interrupts will
+ not be supported.
+ ``auto``
+ Pick the best available controller. This will be an ITS if the
+ GIC and virtualization accelerator support it, and a GICv2m if not.
+ This is the default.
+
its
Set ``on``/``off`` to enable/disable ITS instantiation. The default is ``on``
- for machine types later than ``virt-2.7``.
+ for machine types later than ``virt-2.7``. This is a deprecated option;
+ instead of ``its=on`` use ``msi=its`` or ``msi=auto``, and instead of
+ ``its=off`` use ``msi=none``.
iommu
Set the IOMMU type to create for the guest. Valid values are:
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index b65f571532..471852e4b1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -957,6 +957,8 @@ static void create_gic(VirtMachineState *vms, MemoryRegion
*mem)
case VIRT_MSI_CTRL_GICV2M:
create_v2m(vms);
break;
+ default:
+ g_assert_not_reached();
}
}
@@ -2084,6 +2086,23 @@ static void finalize_msi_controller(VirtMachineState
*vms)
*/
VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms);
+ if (vms->msi_controller != VIRT_MSI_CTRL_NOSEL) {
+ /*
+ * User specified an "msi" option: check what they
+ * specified, and use it.
+ */
+ if (vms->msi_controller == VIRT_MSI_CTRL_ITS &&
+ vms->gic_version == VIRT_GIC_VERSION_2) {
+ error_report("A GICv2 cannot use an ITS");
+ exit(1);
+ }
+ return;
+ }
+
+ /*
+ * Pick a "best available" MSI controller, including handling
+ * the legacy "its" option and the no_tcg_its compat flag.
+ */
if (vms->gic_version != VIRT_GIC_VERSION_2 && vms->its) {
if (!kvm_irqchip_in_kernel() && vmc->no_tcg_its) {
vms->msi_controller = VIRT_MSI_CTRL_NONE;
@@ -2092,6 +2111,8 @@ static void finalize_msi_controller(VirtMachineState *vms)
}
} else if (vms->gic_version == VIRT_GIC_VERSION_2) {
vms->msi_controller = VIRT_MSI_CTRL_GICV2M;
+ } else {
+ vms->msi_controller = VIRT_MSI_CTRL_NONE;
}
}
@@ -2881,6 +2902,36 @@ static void virt_set_gic_version(Object *obj, const char
*value, Error **errp)
}
}
+static const char *msi_option_values[] = {
+ [VIRT_MSI_CTRL_NONE] = "off",
+ [VIRT_MSI_CTRL_GICV2M] = "gicv2m",
+ [VIRT_MSI_CTRL_ITS] = "its",
+ [VIRT_MSI_CTRL_NOSEL] = "auto",
+};
+
+static char *virt_get_msi(Object *obj, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ assert(vms->msi_controller >= 0 &&
+ vms->msi_controller < ARRAY_SIZE(msi_option_values));
+ return g_strdup(msi_option_values[vms->msi_controller]);
+}
+
+static void virt_set_msi(Object *obj, const char *value, Error **errp)
+{
+ VirtMachineState *vms = VIRT_MACHINE(obj);
+
+ for (int i = 0; i < ARRAY_SIZE(msi_option_values); i++) {
+ if (!strcmp(value, msi_option_values[i])) {
+ vms->msi_controller = i;
+ return;
+ }
+ }
+ error_setg(errp, "Invalid msi value");
+ error_append_hint(errp, "Valid values are off, its, gicv2m, auto.\n");
+}
+
static char *virt_get_iommu(Object *obj, Error **errp)
{
VirtMachineState *vms = VIRT_MACHINE(obj);
@@ -3056,6 +3107,8 @@ static void
virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
db_start = base_memmap[VIRT_GIC_V2M].base;
db_end = db_start + base_memmap[VIRT_GIC_V2M].size - 1;
break;
+ default:
+ g_assert_not_reached();
}
resv_prop_str = g_strdup_printf("0x%"PRIx64":0x%"PRIx64":%u",
db_start, db_end,
@@ -3454,7 +3507,13 @@ static void virt_machine_class_init(ObjectClass *oc,
const void *data)
virt_set_its);
object_class_property_set_description(oc, "its",
"Set on/off to enable/disable "
- "ITS instantiation");
+ "ITS instantiation. Deprecated; "
+ "use the msi option instead");
+
+ object_class_property_add_str(oc, "msi", virt_get_msi, virt_set_msi);
+ object_class_property_set_description(oc, "msi",
+ "Set to configure MSI handling. "
+ "Valid values are auto, its, gicv2m,
and off");
object_class_property_add_bool(oc, "dtb-randomness",
virt_get_dtb_randomness,
@@ -3514,6 +3573,9 @@ static void virt_instance_init(Object *obj)
/* Default allows ITS instantiation */
vms->its = true;
+ /* Default to autoselection of MSI controller */
+ vms->msi_controller = VIRT_MSI_CTRL_NOSEL;
+
/* Default disallows iommu instantiation */
vms->iommu = VIRT_IOMMU_NONE;
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 577b4b3362..53f1dc2199 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -103,6 +103,7 @@ typedef enum VirtMSIControllerType {
VIRT_MSI_CTRL_NONE,
VIRT_MSI_CTRL_GICV2M,
VIRT_MSI_CTRL_ITS,
+ VIRT_MSI_CTRL_NOSEL,
} VirtMSIControllerType;
typedef enum VirtGICType {
--
2.47.3