[RFC,v5,5/7] hw/intc/arm_gicv3_its: Implement support for in-kernel ITS emulation
diff mbox

Message ID 1470161247-10251-6-git-send-email-eric.auger@redhat.com
State New
Headers show

Commit Message

Auger Eric Aug. 2, 2016, 6:07 p.m. UTC
From: Pavel Fedin <p.fedin@samsung.com>

The ITS control frame is in-kernel emulated while accesses to the
GITS_TRANSLATER are mediated through the KVM_SIGNAL_MSI ioctl (MSI
direct MSI injection advertised by the CAP_SIGNAL_MSI capability)

the kvm_gsi_direct_mapping is explicitly set to false to emphasize the
difference with GICv2M. Direct mapping cannot work with ITS since
the content of the MSI data is not the target interrupt ID but an
eventd id.

GSI routing is advertised (kvm_gsi_routing_allowed) as well as
msi/irqfd signaling (kvm_msi_via_irqfd_allowed).

Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
Signed-off-by: Eric Auger <eric.auger@redhat.com>

---

v3 -> v4:
- include "qemu/osdep.h" and  "qapi/error.h"
- rename KVM_VGIC_V3_ADDR_TYPE_ITS into KVM_VGIC_ITS_ADDR_TYPE
- reword commit message
- change kvm_msi_via_irqfd_allowed definition (attached to irqfd dynamic
  availability + MSI controller availability)
- create the ITS KVM device (previously abstracted by the GICv3 KVM device)
- init sequence changed
- absolute GITS_TRANSLATER GPA stored
---
 hw/intc/Makefile.objs       |   1 +
 hw/intc/arm_gicv3_its_kvm.c | 145 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 146 insertions(+)
 create mode 100644 hw/intc/arm_gicv3_its_kvm.c

Comments

Peter Maydell Aug. 12, 2016, 2:03 p.m. UTC | #1
On 2 August 2016 at 19:07, Eric Auger <eric.auger@redhat.com> wrote:
> From: Pavel Fedin <p.fedin@samsung.com>
>
> The ITS control frame is in-kernel emulated while accesses to the
> GITS_TRANSLATER are mediated through the KVM_SIGNAL_MSI ioctl (MSI
> direct MSI injection advertised by the CAP_SIGNAL_MSI capability)
>
> the kvm_gsi_direct_mapping is explicitly set to false to emphasize the
> difference with GICv2M. Direct mapping cannot work with ITS since
> the content of the MSI data is not the target interrupt ID but an
> eventd id.
>
> GSI routing is advertised (kvm_gsi_routing_allowed) as well as
> msi/irqfd signaling (kvm_msi_via_irqfd_allowed).
>
> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>
> ---
>
> v3 -> v4:
> - include "qemu/osdep.h" and  "qapi/error.h"
> - rename KVM_VGIC_V3_ADDR_TYPE_ITS into KVM_VGIC_ITS_ADDR_TYPE
> - reword commit message
> - change kvm_msi_via_irqfd_allowed definition (attached to irqfd dynamic
>   availability + MSI controller availability)
> - create the ITS KVM device (previously abstracted by the GICv3 KVM device)
> - init sequence changed
> - absolute GITS_TRANSLATER GPA stored
> ---
>  hw/intc/Makefile.objs       |   1 +
>  hw/intc/arm_gicv3_its_kvm.c | 145 ++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 146 insertions(+)
>  create mode 100644 hw/intc/arm_gicv3_its_kvm.c
>
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index 23a39f7..9cca280 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -22,6 +22,7 @@ common-obj-$(CONFIG_OPENPIC) += openpic.o
>  obj-$(CONFIG_APIC) += apic.o apic_common.o
>  obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
>  obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
> +obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_its_kvm.o
>  obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
>  obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
>  obj-$(CONFIG_GRLIB) += grlib_irqmp.o
> diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
> new file mode 100644
> index 0000000..b6d92aa
> --- /dev/null
> +++ b/hw/intc/arm_gicv3_its_kvm.c
> @@ -0,0 +1,145 @@
> +/*
> + * KVM-based ITS implementation for a GICv3-based system
> + *
> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
> + * Written by Pavel Fedin <p.fedin@samsung.com>
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library 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
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "hw/intc/arm_gicv3_its_common.h"
> +#include "sysemu/sysemu.h"
> +#include "sysemu/kvm.h"
> +#include "kvm_arm.h"
> +
> +#define TYPE_KVM_ARM_ITS "arm-its-kvm"
> +#define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS)
> +
> +static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
> +{
> +    struct kvm_msi msi;
> +
> +    msi.address_lo = s->gits_translater_gpa & 0xFFFFFFFFULL;
> +    msi.address_hi = s->gits_translater_gpa >> 32;

extract64() might be preferable?

> +    msi.data = value;
> +    msi.flags = KVM_MSI_VALID_DEVID;
> +    msi.devid = devid;
> +    memset(msi.pad, 0, sizeof(msi.pad));
> +
> +    return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi);
> +}
> +
> +typedef struct ItsInitNotifierParams {
> +    Notifier notifier;
> +    GICv3ITSState *s;
> +} ItsInitNotifierParams;
> +
> +/**
> + *
> + * We currently do not use kvm_arm_register_device to provide
> + * the kernel with the vITS control frame base address since the
> + * KVM_DEV_ARM_VGIC_CTRL_INIT init MUST be called after the
> + * KVM_ARM_SET_DEVICE_ADDR and the kvm_arm_register_device
> + * infra does not allow this.
> + */

I thought we'd fixed the kernel API so we didn't need to
have this workaround?

> +static void its_notify(Notifier *notifier, void *data)
> +{
> +    ItsInitNotifierParams *p = DO_UPCAST(ItsInitNotifierParams,
> +                                         notifier, notifier);
> +    GICv3ITSState *s = p->s;
> +    MemoryRegion *mr = &s->iomem_its_cntrl;
> +    MemoryRegionSection mrs;
> +    struct kvm_device_attr attr;
> +    uint64_t addr;
> +    int ret;
> +
> +    mrs = memory_region_find(mr, 0, 1);
> +    addr = mrs.offset_within_address_space;
> +
> +    attr.flags = 0;
> +    attr.group = KVM_DEV_ARM_VGIC_GRP_ADDR;
> +    attr.attr = KVM_VGIC_ITS_ADDR_TYPE;
> +    attr.addr =  (uintptr_t)&addr;
> +
> +    s->gits_translater_gpa = addr + ITS_CONTROL_SIZE + 0x40;
> +
> +    ret = kvm_device_ioctl(s->dev_fd, KVM_SET_DEVICE_ATTR, attr);
> +    if (ret) {
> +        error_setg_errno(&error_fatal, -ret,
> +                         "not able to set base address for vITS ctrl frame");
> +    }
> +
> +    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
> +                      KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
> +}

thanks
-- PMM
Auger Eric Aug. 17, 2016, 3:59 p.m. UTC | #2
Hi Peter,

On 12/08/2016 16:03, Peter Maydell wrote:
> On 2 August 2016 at 19:07, Eric Auger <eric.auger@redhat.com> wrote:
>> From: Pavel Fedin <p.fedin@samsung.com>
>>
>> The ITS control frame is in-kernel emulated while accesses to the
>> GITS_TRANSLATER are mediated through the KVM_SIGNAL_MSI ioctl (MSI
>> direct MSI injection advertised by the CAP_SIGNAL_MSI capability)
>>
>> the kvm_gsi_direct_mapping is explicitly set to false to emphasize the
>> difference with GICv2M. Direct mapping cannot work with ITS since
>> the content of the MSI data is not the target interrupt ID but an
>> eventd id.
>>
>> GSI routing is advertised (kvm_gsi_routing_allowed) as well as
>> msi/irqfd signaling (kvm_msi_via_irqfd_allowed).
>>
>> Signed-off-by: Pavel Fedin <p.fedin@samsung.com>
>> Signed-off-by: Eric Auger <eric.auger@redhat.com>
>>
>> ---
>>
>> v3 -> v4:
>> - include "qemu/osdep.h" and  "qapi/error.h"
>> - rename KVM_VGIC_V3_ADDR_TYPE_ITS into KVM_VGIC_ITS_ADDR_TYPE
>> - reword commit message
>> - change kvm_msi_via_irqfd_allowed definition (attached to irqfd dynamic
>>   availability + MSI controller availability)
>> - create the ITS KVM device (previously abstracted by the GICv3 KVM device)
>> - init sequence changed
>> - absolute GITS_TRANSLATER GPA stored
>> ---
>>  hw/intc/Makefile.objs       |   1 +
>>  hw/intc/arm_gicv3_its_kvm.c | 145 ++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 146 insertions(+)
>>  create mode 100644 hw/intc/arm_gicv3_its_kvm.c
>>
>> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
>> index 23a39f7..9cca280 100644
>> --- a/hw/intc/Makefile.objs
>> +++ b/hw/intc/Makefile.objs
>> @@ -22,6 +22,7 @@ common-obj-$(CONFIG_OPENPIC) += openpic.o
>>  obj-$(CONFIG_APIC) += apic.o apic_common.o
>>  obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
>>  obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
>> +obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_its_kvm.o
>>  obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
>>  obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
>>  obj-$(CONFIG_GRLIB) += grlib_irqmp.o
>> diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
>> new file mode 100644
>> index 0000000..b6d92aa
>> --- /dev/null
>> +++ b/hw/intc/arm_gicv3_its_kvm.c
>> @@ -0,0 +1,145 @@
>> +/*
>> + * KVM-based ITS implementation for a GICv3-based system
>> + *
>> + * Copyright (c) 2015 Samsung Electronics Co., Ltd.
>> + * Written by Pavel Fedin <p.fedin@samsung.com>
>> + *
>> + * This library is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2 of the License, or (at your option) any later version.
>> + *
>> + * This library 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
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with this library; if not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qapi/error.h"
>> +#include "hw/intc/arm_gicv3_its_common.h"
>> +#include "sysemu/sysemu.h"
>> +#include "sysemu/kvm.h"
>> +#include "kvm_arm.h"
>> +
>> +#define TYPE_KVM_ARM_ITS "arm-its-kvm"
>> +#define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS)
>> +
>> +static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
>> +{
>> +    struct kvm_msi msi;
>> +
>> +    msi.address_lo = s->gits_translater_gpa & 0xFFFFFFFFULL;
>> +    msi.address_hi = s->gits_translater_gpa >> 32;
> 
> extract64() might be preferable?
> 
>> +    msi.data = value;
>> +    msi.flags = KVM_MSI_VALID_DEVID;
>> +    msi.devid = devid;
>> +    memset(msi.pad, 0, sizeof(msi.pad));
>> +
>> +    return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi);
>> +}
>> +
>> +typedef struct ItsInitNotifierParams {
>> +    Notifier notifier;
>> +    GICv3ITSState *s;
>> +} ItsInitNotifierParams;
>> +
>> +/**
>> + *
>> + * We currently do not use kvm_arm_register_device to provide
>> + * the kernel with the vITS control frame base address since the
>> + * KVM_DEV_ARM_VGIC_CTRL_INIT init MUST be called after the
>> + * KVM_ARM_SET_DEVICE_ADDR and the kvm_arm_register_device
>> + * infra does not allow this.
>> + */
> 
> I thought we'd fixed the kernel API so we didn't need to
> have this workaround?
The kernel fixes landed in kvmarm/master so I will respin the series
accordingly.

Thanks

Eric
> 
>> +static void its_notify(Notifier *notifier, void *data)
>> +{
>> +    ItsInitNotifierParams *p = DO_UPCAST(ItsInitNotifierParams,
>> +                                         notifier, notifier);
>> +    GICv3ITSState *s = p->s;
>> +    MemoryRegion *mr = &s->iomem_its_cntrl;
>> +    MemoryRegionSection mrs;
>> +    struct kvm_device_attr attr;
>> +    uint64_t addr;
>> +    int ret;
>> +
>> +    mrs = memory_region_find(mr, 0, 1);
>> +    addr = mrs.offset_within_address_space;
>> +
>> +    attr.flags = 0;
>> +    attr.group = KVM_DEV_ARM_VGIC_GRP_ADDR;
>> +    attr.attr = KVM_VGIC_ITS_ADDR_TYPE;
>> +    attr.addr =  (uintptr_t)&addr;
>> +
>> +    s->gits_translater_gpa = addr + ITS_CONTROL_SIZE + 0x40;
>> +
>> +    ret = kvm_device_ioctl(s->dev_fd, KVM_SET_DEVICE_ATTR, attr);
>> +    if (ret) {
>> +        error_setg_errno(&error_fatal, -ret,
>> +                         "not able to set base address for vITS ctrl frame");
>> +    }
>> +
>> +    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
>> +                      KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
>> +}
> 
> thanks
> -- PMM
>

Patch
diff mbox

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 23a39f7..9cca280 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -22,6 +22,7 @@  common-obj-$(CONFIG_OPENPIC) += openpic.o
 obj-$(CONFIG_APIC) += apic.o apic_common.o
 obj-$(CONFIG_ARM_GIC_KVM) += arm_gic_kvm.o
 obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_kvm.o
+obj-$(call land,$(CONFIG_ARM_GIC_KVM),$(TARGET_AARCH64)) += arm_gicv3_its_kvm.o
 obj-$(CONFIG_STELLARIS) += armv7m_nvic.o
 obj-$(CONFIG_EXYNOS4) += exynos4210_gic.o exynos4210_combiner.o
 obj-$(CONFIG_GRLIB) += grlib_irqmp.o
diff --git a/hw/intc/arm_gicv3_its_kvm.c b/hw/intc/arm_gicv3_its_kvm.c
new file mode 100644
index 0000000..b6d92aa
--- /dev/null
+++ b/hw/intc/arm_gicv3_its_kvm.c
@@ -0,0 +1,145 @@ 
+/*
+ * KVM-based ITS implementation for a GICv3-based system
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Written by Pavel Fedin <p.fedin@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/intc/arm_gicv3_its_common.h"
+#include "sysemu/sysemu.h"
+#include "sysemu/kvm.h"
+#include "kvm_arm.h"
+
+#define TYPE_KVM_ARM_ITS "arm-its-kvm"
+#define KVM_ARM_ITS(obj) OBJECT_CHECK(GICv3ITSState, (obj), TYPE_KVM_ARM_ITS)
+
+static int kvm_its_send_msi(GICv3ITSState *s, uint32_t value, uint16_t devid)
+{
+    struct kvm_msi msi;
+
+    msi.address_lo = s->gits_translater_gpa & 0xFFFFFFFFULL;
+    msi.address_hi = s->gits_translater_gpa >> 32;
+    msi.data = value;
+    msi.flags = KVM_MSI_VALID_DEVID;
+    msi.devid = devid;
+    memset(msi.pad, 0, sizeof(msi.pad));
+
+    return kvm_vm_ioctl(kvm_state, KVM_SIGNAL_MSI, &msi);
+}
+
+typedef struct ItsInitNotifierParams {
+    Notifier notifier;
+    GICv3ITSState *s;
+} ItsInitNotifierParams;
+
+/**
+ *
+ * We currently do not use kvm_arm_register_device to provide
+ * the kernel with the vITS control frame base address since the
+ * KVM_DEV_ARM_VGIC_CTRL_INIT init MUST be called after the
+ * KVM_ARM_SET_DEVICE_ADDR and the kvm_arm_register_device
+ * infra does not allow this.
+ */
+static void its_notify(Notifier *notifier, void *data)
+{
+    ItsInitNotifierParams *p = DO_UPCAST(ItsInitNotifierParams,
+                                         notifier, notifier);
+    GICv3ITSState *s = p->s;
+    MemoryRegion *mr = &s->iomem_its_cntrl;
+    MemoryRegionSection mrs;
+    struct kvm_device_attr attr;
+    uint64_t addr;
+    int ret;
+
+    mrs = memory_region_find(mr, 0, 1);
+    addr = mrs.offset_within_address_space;
+
+    attr.flags = 0;
+    attr.group = KVM_DEV_ARM_VGIC_GRP_ADDR;
+    attr.attr = KVM_VGIC_ITS_ADDR_TYPE;
+    attr.addr =  (uintptr_t)&addr;
+
+    s->gits_translater_gpa = addr + ITS_CONTROL_SIZE + 0x40;
+
+    ret = kvm_device_ioctl(s->dev_fd, KVM_SET_DEVICE_ATTR, attr);
+    if (ret) {
+        error_setg_errno(&error_fatal, -ret,
+                         "not able to set base address for vITS ctrl frame");
+    }
+
+    kvm_device_access(s->dev_fd, KVM_DEV_ARM_VGIC_GRP_CTRL,
+                      KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true);
+}
+
+static void kvm_arm_its_realize(DeviceState *dev, Error **errp)
+{
+    GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
+    ItsInitNotifierParams *p = g_new(ItsInitNotifierParams, 1);
+
+    s->dev_fd = kvm_create_device(kvm_state, KVM_DEV_TYPE_ARM_VGIC_ITS, false);
+    if (s->dev_fd < 0) {
+        error_setg_errno(errp, -s->dev_fd, "error creating in-kernel ITS");
+        return;
+    }
+
+    gicv3_its_init_mmio(s, NULL);
+
+    p->notifier.notify = its_notify;
+    p->s = s;
+    qemu_add_machine_init_done_notifier(&p->notifier);
+
+    kvm_arm_msi_use_devid = true;
+    kvm_gsi_routing_allowed = kvm_has_gsi_routing();
+    kvm_gsi_direct_mapping = false;
+    kvm_msi_via_irqfd_allowed = kvm_irqfds_enabled();
+}
+
+static void kvm_arm_its_init(Object *obj)
+{
+    GICv3ITSState *s = KVM_ARM_ITS(obj);
+
+    object_property_add_link(obj, "parent-gicv3",
+                             "kvm-arm-gicv3", (Object **)&s->gicv3,
+                             object_property_allow_set_link,
+                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
+                             &error_abort);
+}
+
+static void kvm_arm_its_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
+
+    dc->realize = kvm_arm_its_realize;
+    icc->send_msi = kvm_its_send_msi;
+}
+
+static const TypeInfo kvm_arm_its_info = {
+    .name = TYPE_KVM_ARM_ITS,
+    .parent = TYPE_ARM_GICV3_ITS_COMMON,
+    .instance_size = sizeof(GICv3ITSState),
+    .instance_init = kvm_arm_its_init,
+    .class_init = kvm_arm_its_class_init,
+};
+
+static void kvm_arm_its_register_types(void)
+{
+    type_register_static(&kvm_arm_its_info);
+}
+
+type_init(kvm_arm_its_register_types)