diff mbox series

[v2,04/19] spapr: add support for the LSI interrupt sources

Message ID 20171209084338.29395-5-clg@kaod.org
State New
Headers show
Series spapr: Guest exploitation of the XIVE interrupt controller (POWER9) | expand

Commit Message

Cédric Le Goater Dec. 9, 2017, 8:43 a.m. UTC
The 'sent' status of the LSI interrupt source is modeled with the 'P'
bit of the ESB and the assertion status of the source is maintained in
an array under the main sPAPRXive object. The type of the source is
stored in the same array for practical reasons.

The OS will use the H_INT_GET_SOURCE_INFO hcall to determine the type
of an interrupt source.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/intc/spapr_xive.c        | 54 +++++++++++++++++++++++++++++++++++++++++----
 include/hw/ppc/spapr_xive.h | 10 ++++++++-
 2 files changed, 59 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index 43df6814619d..c772c726667f 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -144,6 +144,21 @@  static bool spapr_xive_pq_trigger(sPAPRXive *xive, uint32_t lisn)
 }
 
 /*
+ * LSI interrupt sources use the P bit and a custom assertion flag
+ */
+static bool spapr_xive_lsi_trigger(sPAPRXive *xive, uint32_t lisn)
+{
+    uint8_t old_pq = spapr_xive_pq_get(xive, lisn);
+
+    if  (old_pq == XIVE_ESB_RESET &&
+         xive->status[lisn] & XIVE_STATUS_ASSERTED) {
+        spapr_xive_pq_set(xive, lisn, XIVE_ESB_PENDING);
+        return true;
+    }
+    return false;
+}
+
+/*
  * XIVE Interrupt Source MMIOs
  */
 
@@ -165,6 +180,14 @@  static uint64_t spapr_xive_esb_read(void *opaque, hwaddr addr, unsigned size)
          * XIVE_ESB_STORE_EOI support for the interrupt sources
          */
         ret = spapr_xive_pq_eoi(xive, lisn);
+
+        /* If the LSI source is still asserted, forward a new source
+         * event notification */
+        if (spapr_xive_irq_is_lsi(xive, lisn)) {
+            if (spapr_xive_lsi_trigger(xive, lisn)) {
+                spapr_xive_irq(xive, lisn);
+            }
+        }
         break;
 
     case XIVE_ESB_GET:
@@ -201,6 +224,14 @@  static void spapr_xive_esb_write(void *opaque, hwaddr addr,
          * notification
          */
         notify = spapr_xive_pq_eoi(xive, lisn);
+
+        /* LSI sources do not set the Q bit but they can still be
+         * asserted, in which case we should forward a new source
+         * event notification
+         */
+        if (spapr_xive_irq_is_lsi(xive, lisn)) {
+            notify = spapr_xive_lsi_trigger(xive, lisn);
+        }
         break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR, "XIVE: invalid ESB write addr %d\n",
@@ -233,8 +264,17 @@  static void spapr_xive_source_set_irq(void *opaque, int lisn, int val)
     sPAPRXive *xive = SPAPR_XIVE(opaque);
     bool notify = false;
 
-    if (val) {
-        notify = spapr_xive_pq_trigger(xive, lisn);
+    if (spapr_xive_irq_is_lsi(xive, lisn)) {
+        if (val) {
+            xive->status[lisn] |= XIVE_STATUS_ASSERTED;
+        } else {
+            xive->status[lisn] &= ~XIVE_STATUS_ASSERTED;
+        }
+        notify = spapr_xive_lsi_trigger(xive, lisn);
+    } else {
+        if (val) {
+            notify = spapr_xive_pq_trigger(xive, lisn);
+        }
     }
 
     /* Forward the source event notification for routing */
@@ -260,7 +300,8 @@  void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon)
 
         pq = spapr_xive_pq_get(xive, i);
 
-        monitor_printf(mon, "  %4x %s %c%c %08x %08x\n", i,
+        monitor_printf(mon, "  %4x %s %s %c%c %08x %08x\n", i,
+                       spapr_xive_irq_is_lsi(xive, i) ? "LSI" : "MSI",
                        ive->w & IVE_MASKED ? "M" : " ",
                        pq & XIVE_ESB_VAL_P ? 'P' : '-',
                        pq & XIVE_ESB_VAL_Q ? 'Q' : '-',
@@ -274,6 +315,8 @@  static void spapr_xive_reset(DeviceState *dev)
     sPAPRXive *xive = SPAPR_XIVE(dev);
     int i;
 
+    /* Do not clear IRQ's status */
+
     /* Mask all valid IVEs in the IRQ number space. */
     for (i = 0; i < xive->nr_irqs; i++) {
         XiveIVE *ive = &xive->ivt[i];
@@ -301,6 +344,7 @@  static void spapr_xive_realize(DeviceState *dev, Error **errp)
     /* QEMU IRQs */
     xive->qirqs = qemu_allocate_irqs(spapr_xive_source_set_irq, xive,
                                      xive->nr_irqs);
+    xive->status = g_malloc0(xive->nr_irqs);
 
     /* Allocate SBEs (State Bit Entry). 2 bits, so 4 entries per byte */
     xive->sbe_size = DIV_ROUND_UP(xive->nr_irqs, 4);
@@ -381,7 +425,7 @@  XiveIVE *spapr_xive_get_ive(sPAPRXive *xive, uint32_t lisn)
     return lisn < xive->nr_irqs ? &xive->ivt[lisn] : NULL;
 }
 
-bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn)
+bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi)
 {
     XiveIVE *ive = spapr_xive_get_ive(xive, lisn);
 
@@ -390,6 +434,7 @@  bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn)
     }
 
     ive->w |= IVE_VALID;
+    xive->status[lisn] |= lsi ? XIVE_STATUS_LSI : 0;
     return true;
 }
 
@@ -402,5 +447,6 @@  bool spapr_xive_irq_disable(sPAPRXive *xive, uint32_t lisn)
     }
 
     ive->w &= ~IVE_VALID;
+    xive->status[lisn] = 0;
     return true;
 }
diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h
index ecc15d889b74..a7e59fd601d7 100644
--- a/include/hw/ppc/spapr_xive.h
+++ b/include/hw/ppc/spapr_xive.h
@@ -23,6 +23,9 @@  struct sPAPRXive {
 
     /* Properties */
     uint32_t     nr_irqs;
+#define XIVE_STATUS_LSI                0x1
+#define XIVE_STATUS_ASSERTED           0x2
+    uint8_t      *status;
 
     /* IRQ */
     qemu_irq     *qirqs;
@@ -37,7 +40,12 @@  struct sPAPRXive {
     MemoryRegion esb_iomem;
 };
 
-bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn);
+static inline bool spapr_xive_irq_is_lsi(sPAPRXive *xive, int lisn)
+{
+    return xive->status[lisn] & XIVE_STATUS_LSI;
+}
+
+bool spapr_xive_irq_enable(sPAPRXive *xive, uint32_t lisn, bool lsi);
 bool spapr_xive_irq_disable(sPAPRXive *xive, uint32_t lisn);
 void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon);