[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v4 42/42] xen/riscv: drive the line of a virtual vAPLIC source



The line of a virtual vAPLIC source is driven by the emulator of a device
in Xen, but nothing lets such an emulator do it yet: vaplic_source.level is
never set.

Introduce vintc_set_irq_level(), which an emulator calls whenever the level
of its interrupt line changes, and implement it for vAPLIC as a new
vintc_ops.set_irq_level callback.

vAPLIC supports MSI delivery mode only, where, according to the AIA spec, a
low-to-high transition of the rectified input value of a source makes it
pending, whether it is edge- or level-sensitive, and the pending bit of a
level-sensitive source is cleared whenever the value is low. A source made
pending and enabled gets its MSI right away, through vaplic_forward_msis().

Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
---
All the patches connected to virtual interrupts support for vAPLIC/vIMSIC
were tested on [1]. This branch is based on Denis M's framework which should
be soon sent to ML. Note that in [1] RISC-V is only draft version and
it has been ported in a quick way just to verify virtual interrupts are
working.

[1] 
https://gitlab.com/xen-project/people/olkur/xen/-/tree/riscv-vuart-support-wip?ref_type=heads
---
Changes in v4:
 - New patch.
---
---
 xen/arch/riscv/include/asm/intc.h   |  9 +++++
 xen/arch/riscv/include/asm/vaplic.h |  8 ++---
 xen/arch/riscv/intc.c               | 14 ++++++++
 xen/arch/riscv/vaplic.c             | 51 +++++++++++++++++++++++++++++
 4 files changed, 77 insertions(+), 5 deletions(-)

diff --git a/xen/arch/riscv/include/asm/intc.h 
b/xen/arch/riscv/include/asm/intc.h
index d188a45b3fe1..a332838bea17 100644
--- a/xen/arch/riscv/include/asm/intc.h
+++ b/xen/arch/riscv/include/asm/intc.h
@@ -8,6 +8,8 @@
 #ifndef RISCV_INTC_H
 #define RISCV_INTC_H
 
+#include <xen/types.h>
+
 struct dt_device_node;
 
 enum intc_variant {
@@ -79,6 +81,10 @@ struct vintc_ops {
      * guest.
      */
     void (*enter_guest)(struct vcpu *v);
+
+    /* Set the level of the line of a virtual source */
+    void (*set_irq_level)(const struct domain *d, unsigned int virq,
+                          bool level);
 };
 
 struct vintc {
@@ -114,4 +120,7 @@ void vintc_ctxt_switch_to(struct vcpu *n);
 
 void vintc_enter_guest(struct vcpu *v);
 
+void vintc_set_irq_level(const struct domain *d, unsigned int virq,
+                         bool level);
+
 #endif /* RISCV_INTC_H */
diff --git a/xen/arch/riscv/include/asm/vaplic.h 
b/xen/arch/riscv/include/asm/vaplic.h
index f2c768e84b11..1d5b9840be6c 100644
--- a/xen/arch/riscv/include/asm/vaplic.h
+++ b/xen/arch/riscv/include/asm/vaplic.h
@@ -41,11 +41,9 @@ struct vaplic_source {
     uint32_t sourcecfg;
 
     /*
-     * Level of the line of a virtual source, protected by vaplic->lock.
-     *
-     * TODO: nothing drives it yet. The emulator of a device with an interrupt
-     * line will have to, and to call vaplic_forward_msis() for a source a
-     * change of the level makes pending.
+     * Level of the line of a virtual source, as the emulator of the device
+     * in Xen drives it through vintc_set_irq_level(). Protected by
+     * vaplic->lock.
      */
     bool level;
 };
diff --git a/xen/arch/riscv/intc.c b/xen/arch/riscv/intc.c
index 449f6b252414..630c6d2ae730 100644
--- a/xen/arch/riscv/intc.c
+++ b/xen/arch/riscv/intc.c
@@ -224,3 +224,17 @@ void vintc_enter_guest(struct vcpu *v)
     if ( ops->enter_guest )
         ops->enter_guest(v);
 }
+
+/*
+ * Set the level of the line of virtual source @virq of @d. To be used by the
+ * emulator of a device in Xen, the line of which is connected to @virq: such
+ * a source has to be reserved with vintc_reserve_virq(), and no h/w IRQ may be
+ * routed to it.
+ */
+void vintc_set_irq_level(const struct domain *d, unsigned int virq,
+                         bool level)
+{
+    const struct vintc_ops *ops = d->arch.vintc->ops;
+
+    ops->set_irq_level(d, virq, level);
+}
diff --git a/xen/arch/riscv/vaplic.c b/xen/arch/riscv/vaplic.c
index ba0a867f6988..023f5116ec93 100644
--- a/xen/arch/riscv/vaplic.c
+++ b/xen/arch/riscv/vaplic.c
@@ -779,6 +779,56 @@ static void vaplic_ip_write(const struct domain *d, 
unsigned int word_idx,
     spin_unlock_irqrestore(&vaplic->lock, flags);
 }
 
+/*
+ * Set the level of the line of virtual source @virq of @d, as the emulator of
+ * the device in Xen driving it does.
+ */
+static void cf_check vaplic_set_irq_level(const struct domain *d,
+                                          unsigned int virq, bool level)
+{
+    struct vaplic *vaplic = to_vaplic(d);
+    struct vaplic_source *src;
+    unsigned int word_idx;
+    unsigned long flags;
+    uint32_t bit;
+    bool was_high;
+
+    /* Only a virtual source of @d has its line driven by an emulator. */
+    if ( !vaplic_is_assigned(d, virq) || vaplic_is_hw_source(d, virq) )
+    {
+        ASSERT_UNREACHABLE();
+        return;
+    }
+
+    virq = array_index_nospec(virq, d->arch.vintc->nr_virqs);
+    src = &vaplic->regs.sources[virq];
+    word_idx = virq / IRQS_PER_WORD;
+    bit = BIT(virq % IRQS_PER_WORD, U);
+
+    spin_lock_irqsave(&vaplic->lock, flags);
+
+    was_high = vaplic_rectified_input(src);
+    src->level = level;
+
+    /*
+     * According to the AIA spec, in MSI delivery mode a low-to-high
+     * transition of the rectified input value sets the pending bit of an
+     * edge- as well as of a level-sensitive source, and the pending bit of a
+     * level-sensitive one is cleared whenever the value is low. Neither
+     * happens to an inactive or a Detached source, whose rectified input
+     * value is always low.
+     */
+    if ( !was_high && vaplic_rectified_input(src) )
+        vaplic->regs.ip[word_idx] |= bit;
+    else if ( vaplic_is_level(src) && !vaplic_rectified_input(src) )
+        vaplic->regs.ip[word_idx] &= ~bit;
+
+    /* An enabled source the new level has made pending gets its MSI now. */
+    vaplic_forward_msis(d, word_idx, bit);
+
+    spin_unlock_irqrestore(&vaplic->lock, flags);
+}
+
 static uint32_t vaplic_genmsi_read(const struct domain *d)
 {
     /*
@@ -1189,6 +1239,7 @@ static const struct vintc_ops vintc_ops = {
      * by the vCPU itself. It moves it on its way to the guest instead.
      */
     .enter_guest = imsic_migrate_vcpu,
+    .set_irq_level = vaplic_set_irq_level,
 };
 
 int domain_vaplic_init(struct domain *d)
-- 
2.56.1




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.