All of lore.kernel.org
 help / color / mirror / Atom feed
From: Heyi Guo <guoheyi@huawei.com>
To: <qemu-arm@nongnu.org>, <qemu-devel@nongnu.org>
Cc: Mark Rutland <mark.rutland@arm.com>,
	Peter Maydell <peter.maydell@linaro.org>,
	Marc Zyngier <marc.zyngier@arm.com>,
	James Morse <james.morse@arm.com>, Heyi Guo <guoheyi@huawei.com>,
	wanghaibin.wang@huawei.com, Dave Martin <Dave.Martin@arm.com>
Subject: [RFC v2 09/14] arm/sdei: override qemu_irq handler when binding interrupt
Date: Tue, 5 Nov 2019 17:10:51 +0800	[thread overview]
Message-ID: <20191105091056.9541-10-guoheyi@huawei.com> (raw)
In-Reply-To: <20191105091056.9541-1-guoheyi@huawei.com>

Override qemu_irq handler to support trigger SDEI event transparently
after guest binds interrupt to SDEI event. We don't have good way to
get GIC device and to guarantee SDEI device is initialized after GIC,
so we search GIC in system bus when the first SDEI request happens or
in VMSTATE post_load().

Signed-off-by: Heyi Guo <guoheyi@huawei.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Cc: Dave Martin <Dave.Martin@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: James Morse <james.morse@arm.com>
---
 target/arm/sdei.c     | 130 +++++++++++++++++++++++++++++++++++++++++-
 target/arm/sdei_int.h |   3 +
 2 files changed, 132 insertions(+), 1 deletion(-)

diff --git a/target/arm/sdei.c b/target/arm/sdei.c
index 713ac97775..529a06c1f6 100644
--- a/target/arm/sdei.c
+++ b/target/arm/sdei.c
@@ -88,6 +88,24 @@ static void qemu_sde_cpu_init(QemuSDEState *s)
     }
 }
 
+static int gic_int_to_irq(int num_irq, int intid, int cpu)
+{
+    if (intid >= GIC_INTERNAL) {
+        return intid - GIC_INTERNAL;
+    }
+    return num_irq - GIC_INTERNAL + cpu * GIC_INTERNAL + intid;
+}
+
+static int irq_to_gic_int(int num_irq, int irq, int *cpu)
+{
+    if (irq < num_irq - GIC_INTERNAL) {
+        return irq + GIC_INTERNAL;
+    }
+    irq -= num_irq - GIC_INTERNAL;
+    *cpu = irq / GIC_INTERNAL;
+    return irq % GIC_INTERNAL;
+}
+
 static inline QemuSDECpu *get_sde_cpu(QemuSDEState *s, CPUState *cs)
 {
     if (cs->cpu_index >= s->sdei_max_cpus) {
@@ -410,6 +428,74 @@ static void dispatch_cpu(QemuSDEState *s, CPUState *cs, bool is_critical)
     }
 }
 
+static void qemu_sdei_irq_handler(void *opaque, int irq, int level)
+{
+    int cpu = 0;
+
+    irq = irq_to_gic_int(sde_state->num_irq, irq, &cpu);
+    trigger_sdei_by_irq(cpu, irq);
+}
+
+static void override_qemu_irq(QemuSDEState *s, int32_t event, uint32_t intid)
+{
+    qemu_irq irq;
+    QemuSDE *sde;
+    CPUState *cs;
+
+    /* SPI */
+    if (intid >= GIC_INTERNAL) {
+        cs = first_cpu;
+        irq = qdev_get_gpio_in(s->gic_dev,
+                               gic_int_to_irq(s->num_irq, intid, 0));
+        if (irq) {
+            qemu_irq_intercept_in(&irq, qemu_sdei_irq_handler, 1);
+        }
+        sde = get_sde_no_check(s, event, cs);
+        sde->irq = irq;
+        put_sde(sde, cs);
+        return;
+    }
+    /* PPI */
+    CPU_FOREACH(cs) {
+        irq = qdev_get_gpio_in(
+            s->gic_dev,
+            gic_int_to_irq(s->num_irq, intid, cs->cpu_index));
+        if (irq) {
+            qemu_irq_intercept_in(&irq, qemu_sdei_irq_handler, 1);
+        }
+        sde = get_sde_no_check(s, event, cs);
+        sde->irq = irq;
+        put_sde(sde, cs);
+    }
+}
+
+static void restore_qemu_irq(QemuSDEState *s, int32_t event, uint32_t intid)
+{
+    QemuSDE *sde;
+    CPUState *cs;
+
+    /* SPI */
+    if (intid >= GIC_INTERNAL) {
+        cs = first_cpu;
+        sde = get_sde_no_check(s, event, cs);
+        if (sde->irq) {
+            qemu_irq_remove_intercept(&sde->irq, 1);
+            sde->irq = NULL;
+        }
+        put_sde(sde, cs);
+        return;
+    }
+    /* PPI */
+    CPU_FOREACH(cs) {
+        sde = get_sde_no_check(s, event, cs);
+        if (sde->irq) {
+            qemu_irq_remove_intercept(&sde->irq, 1);
+            sde->irq = NULL;
+        }
+        put_sde(sde, cs);
+    }
+}
+
 static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
                                     bool is_shared, int intid)
 {
@@ -443,6 +529,7 @@ static int32_t sdei_alloc_event_num(QemuSDEState *s, bool is_critical,
             sde_props[index].interrupt = intid;
             sde_props[index].is_shared = is_shared;
             sde_props[index].is_critical = is_critical;
+            override_qemu_irq(s, event, intid);
             s->irq_map[intid] = event;
             qemu_mutex_unlock(&sde_props[index].lock);
             qemu_mutex_unlock(&s->sdei_interrupt_bind_lock);
@@ -460,6 +547,7 @@ static int32_t sdei_free_event_num_locked(QemuSDEState *s, QemuSDEProp *prop)
         return SDEI_DENIED;
     }
 
+    restore_qemu_irq(s, prop->event_id, prop->interrupt);
     s->irq_map[prop->interrupt] = SDEI_INVALID_EVENT_ID;
     prop->event_id = SDEI_INVALID_EVENT_ID;
     prop->interrupt = SDEI_INVALID_INTERRUPT;
@@ -992,13 +1080,33 @@ static int64_t sdei_event_pe_unmask(QemuSDEState *s, CPUState *cs,
     return SDEI_SUCCESS;
 }
 
+static int dev_walkerfn(DeviceState *dev, void *opaque)
+{
+    QemuSDEState *s = opaque;
+
+    if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_GICV3_COMMON)) {
+        GICv3State *gic = ARM_GICV3_COMMON(dev);
+        s->num_irq = gic->num_irq;
+        s->gic_dev = dev;
+        return -1;
+    }
+
+    if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_GIC_COMMON)) {
+        GICState *gic = ARM_GIC_COMMON(dev);
+        s->num_irq = gic->num_irq;
+        s->gic_dev = dev;
+        return -1;
+    }
+    return 0;
+}
+
 static int64_t sdei_event_interrupt_bind(QemuSDEState *s, CPUState *cs,
                                          struct kvm_run *run)
 {
     uint64_t *args = (uint64_t *)(run->hypercall.args);
     uint32_t intid = args[1];
 
-    if (intid < GIC_NR_SGIS || intid >= GIC_MAXIRQ) {
+    if (intid < GIC_NR_SGIS || intid >= s->num_irq) {
         return SDEI_INVALID_PARAMETERS;
     }
     return sdei_alloc_event_num(s, false, intid >= GIC_INTERNAL, intid);
@@ -1112,6 +1220,17 @@ void sdei_handle_request(CPUState *cs, struct kvm_run *run)
         return;
     }
 
+    if (!sde_state->gic_dev) {
+        /* Search for ARM GIC device */
+        qbus_walk_children(sysbus_get_default(), dev_walkerfn,
+                           NULL, NULL, NULL, sde_state);
+        if (!sde_state->gic_dev) {
+            error_report("Cannot find ARM GIC device!");
+            run->hypercall.args[0] = SDEI_NOT_SUPPORTED;
+            return;
+        }
+    }
+
     if (func_id < SDEI_1_0_FN_BASE || func_id > SDEI_MAX_REQ) {
         error_report("Invalid SDEI function ID: 0x%x", func_id);
         run->hypercall.args[0] = SDEI_INVALID_PARAMETERS;
@@ -1259,11 +1378,20 @@ static int qemu_sdei_post_load(void *opaque, int version_id)
         }
     }
 
+    /* Search for ARM GIC device */
+    qbus_walk_children(sysbus_get_default(), dev_walkerfn,
+                       NULL, NULL, NULL, s);
+    if (!s->gic_dev) {
+        error_report("Cannot find ARM GIC device!");
+        return 0;
+    }
+
     for (i = 0; i < PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT; i++) {
         int intid = sde_props[i].interrupt;
 
         if (intid != SDEI_INVALID_INTERRUPT) {
             s->irq_map[intid] = sde_props[i].event_id;
+            override_qemu_irq(s, sde_props[i].event_id, intid);
         }
     }
 
diff --git a/target/arm/sdei_int.h b/target/arm/sdei_int.h
index d3fd7cbc10..a251b04ab5 100644
--- a/target/arm/sdei_int.h
+++ b/target/arm/sdei_int.h
@@ -63,6 +63,7 @@ typedef struct QemuSDEProp {
 typedef struct QemuSDE {
     QemuSDEProp     *prop;
     CPUState        *target_cpu;
+    qemu_irq        irq;
     QemuMutex       lock;
     bool            enabled;
     bool            running;
@@ -107,9 +108,11 @@ typedef struct QemuSDECpu {
 
 typedef struct QemuSDEState {
     DeviceState     parent_obj;
+    DeviceState     *gic_dev;
     QemuSDEProp     sde_props_state[PRIVATE_SLOT_COUNT + SHARED_SLOT_COUNT];
     QemuSDECpu      *sde_cpus;
     int             sdei_max_cpus;
+    int             num_irq;
     QemuSDE         *shared_sde_array[SHARED_SLOT_COUNT];
     int32_t         irq_map[GIC_MAXIRQ];
     QemuMutex       sdei_interrupt_bind_lock;
-- 
2.19.1



  parent reply	other threads:[~2019-11-05  9:23 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-05  9:10 [RFC v2 00/14] Add SDEI support for arm64 Heyi Guo
2019-11-05  9:10 ` [RFC v2 01/14] update-linux-headers.sh: import linux/arm_sdei.h to standard-headers Heyi Guo
2019-11-05  9:10 ` [RFC v2 02/14] standard-headers: import arm_sdei.h Heyi Guo
2019-11-06 17:52   ` Cornelia Huck
2019-11-07  1:40     ` Guoheyi
2019-11-07  8:50       ` Cornelia Huck
2019-11-07  8:55       ` Michael S. Tsirkin
2019-11-05  9:10 ` [RFC v2 03/14] arm/sdei: add virtual device framework Heyi Guo
2019-11-05  9:10 ` [RFC v2 04/14] arm: add CONFIG_SDEI build flag Heyi Guo
2019-11-05  9:10 ` [RFC v2 05/14] arm/sdei: add support to handle SDEI requests from guest Heyi Guo
2019-11-05  9:10 ` [RFC v2 06/14] arm/sdei: add system reset callback Heyi Guo
2019-11-05  9:10 ` [RFC v2 07/14] arm/sdei: add support to trigger event by GIC interrupt ID Heyi Guo
2019-11-05  9:10 ` [RFC v2 08/14] core/irq: add qemu_irq_remove_intercept interface Heyi Guo
2019-11-05  9:10 ` Heyi Guo [this message]
2019-11-05  9:10 ` [RFC v2 10/14] arm/sdei: add support to register interrupt bind notifier Heyi Guo
2019-11-05  9:10 ` [RFC v2 11/14] linux-headers/kvm.h: add capability to forward hypercall Heyi Guo
2019-11-06 17:55   ` Cornelia Huck
2019-11-07  1:44     ` Guoheyi
2019-11-07  8:57       ` Michael S. Tsirkin
2019-11-07 11:57         ` Guoheyi
2019-11-07 12:12           ` Cornelia Huck
2019-11-08  1:54             ` Guoheyi
2019-11-05  9:10 ` [RFC v2 12/14] arm/sdei: add stub to fix build failure when SDEI is not enabled Heyi Guo
2019-11-05  9:10 ` [RFC v2 13/14] arm/kvm: handle guest exit of hypercall Heyi Guo
2019-11-05  9:10 ` [RFC v2 14/14] virt/acpi: add SDEI table if SDEI is enabled Heyi Guo
2019-11-12 14:52   ` Igor Mammedov
2019-11-18  6:44     ` Guoheyi
2019-11-05  9:15 ` [RFC v2 00/14] Add SDEI support for arm64 Guoheyi
2019-11-05  9:36 ` no-reply
2019-11-05  9:38 ` no-reply
2019-11-18  6:55 ` Guoheyi
2019-11-18 13:35   ` Peter Maydell
2019-11-18 14:04     ` Guoheyi
2019-12-20 13:44 ` Peter Maydell
2019-12-23  8:20   ` Guoheyi
2020-02-04  8:26     ` Heyi Guo
2020-02-05 13:15       ` Marc Zyngier
2020-02-06  1:20         ` Heyi Guo
2020-02-06 17:30           ` Marc Zyngier
2020-02-07 10:52             ` James Morse
2020-02-07 11:08               ` Peter Maydell
2020-02-07 13:45               ` Heyi Guo
2020-02-07 13:17             ` Heyi Guo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191105091056.9541-10-guoheyi@huawei.com \
    --to=guoheyi@huawei.com \
    --cc=Dave.Martin@arm.com \
    --cc=james.morse@arm.com \
    --cc=marc.zyngier@arm.com \
    --cc=mark.rutland@arm.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=wanghaibin.wang@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.