qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH 06/10] ppc/xive: Provide escalation support


From: Cédric Le Goater
Subject: [Qemu-devel] [PATCH 06/10] ppc/xive: Provide escalation support
Date: Sun, 30 Jun 2019 22:45:57 +0200

If the XIVE presenter can not find the NVT dispatched on any of the HW
threads, it can not deliver the interrupt. XIVE offers a mechanism to
handle such scenarios and inform the hypervisor that an action should
be taken.

The first action is to keep track of the pending priority of the
missed event. It is recorded in the IPB field of the NVT for a later
resend if backlog is activated ('b' bit) on the END.

An END can also escalate if configured: 'e' bit and setting of the EAS
in word 4 & 5 to let the HW look for the escalation END on which to
trigger a new event. Escalation has its own options to program
different behaviors :

 - unconditional escalation ('u' bit) with which the ESe PQ bits are
   not used.
 - silent/gather escalation ('s' bit), the sequence skips the
   notification process and jumps directly to the escalation.

KVM uses a combination of these. The first level END is configured to
enqueue, unconditionally notify, backlog and escalate and points to an
escalation END which is configured to escalate silently.

Signed-off-by: Cédric Le Goater <address@hidden>
---
 include/hw/ppc/xive_regs.h |   4 ++
 hw/intc/xive.c             | 130 +++++++++++++++++++++++++++++++------
 2 files changed, 115 insertions(+), 19 deletions(-)

diff --git a/include/hw/ppc/xive_regs.h b/include/hw/ppc/xive_regs.h
index 1a8c5b5e64f0..69af326ebf2c 100644
--- a/include/hw/ppc/xive_regs.h
+++ b/include/hw/ppc/xive_regs.h
@@ -207,6 +207,10 @@ typedef struct XiveEND {
 #define xive_end_is_notify(end)   (be32_to_cpu((end)->w0) & 
END_W0_UCOND_NOTIFY)
 #define xive_end_is_backlog(end)  (be32_to_cpu((end)->w0) & END_W0_BACKLOG)
 #define xive_end_is_escalate(end) (be32_to_cpu((end)->w0) & 
END_W0_ESCALATE_CTL)
+#define xive_end_is_uncond_escalation(end)              \
+    (be32_to_cpu((end)->w0) & END_W0_UNCOND_ESCALATE)
+#define xive_end_is_silent_escalation(end)              \
+    (be32_to_cpu((end)->w0) & END_W0_SILENT_ESCALATE)
 
 static inline uint64_t xive_end_qaddr(XiveEND *end)
 {
diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index 592c0b70f197..3970999f4837 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -1389,7 +1389,7 @@ static bool xive_presenter_match(XiveRouter *xrtr, 
uint8_t format,
  *
  * The parameters represent what is sent on the PowerBus
  */
-static void xive_presenter_notify(XiveRouter *xrtr, uint8_t format,
+static bool xive_presenter_notify(XiveRouter *xrtr, uint8_t format,
                                   uint8_t nvt_blk, uint32_t nvt_idx,
                                   bool cam_ignore, uint8_t priority,
                                   uint32_t logic_serv)
@@ -1402,13 +1402,13 @@ static void xive_presenter_notify(XiveRouter *xrtr, 
uint8_t format,
     if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) {
         qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n",
                       nvt_blk, nvt_idx);
-        return;
+        return false;
     }
 
     if (!xive_nvt_is_valid(&nvt)) {
         qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n",
                       nvt_blk, nvt_idx);
-        return;
+        return false;
     }
 
     found = xive_presenter_match(xrtr, format, nvt_blk, nvt_idx, cam_ignore,
@@ -1416,19 +1416,55 @@ static void xive_presenter_notify(XiveRouter *xrtr, 
uint8_t format,
     if (found) {
         ipb_update(&match.tctx->regs[match.ring], priority);
         xive_tctx_notify(match.tctx, match.ring);
+    }
+
+    return found;
+}
+
+static void xive_router_end_backlog(XiveRouter *xrtr,
+                                    uint8_t nvt_blk, uint32_t nvt_idx,
+                                    uint8_t priority)
+{
+    XiveNVT nvt;
+
+    /* NVT cache lookup */
+    if (xive_router_get_nvt(xrtr, nvt_blk, nvt_idx, &nvt)) {
+        qemu_log_mask(LOG_GUEST_ERROR, "XIVE: no NVT %x/%x\n",
+                      nvt_blk, nvt_idx);
+        return;
+    }
+
+    if (!xive_nvt_is_valid(&nvt)) {
+        qemu_log_mask(LOG_GUEST_ERROR, "XIVE: NVT %x/%x is invalid\n",
+                      nvt_blk, nvt_idx);
         return;
     }
 
     /* Record the IPB in the associated NVT structure */
     ipb_update((uint8_t *) &nvt.w4, priority);
     xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4);
+}
 
-    /*
-     * If no matching NVT is dispatched on a HW thread :
-     * - update the NVT structure if backlog is activated
-     * - escalate (ESe PQ bits and EAS in w4-5) if escalation is
-     *   activated
-     */
+
+/*
+ * Notification using the END ESe/ESn bit (Event State Buffer for
+ * escalation and notification). Profide futher coalescing in the
+ * Router.
+ */
+static bool xive_router_end_es_notify(XiveRouter *xrtr, uint8_t end_blk,
+                                      uint32_t end_idx, XiveEND *end,
+                                      uint32_t end_esmask)
+{
+    uint8_t pq = xive_get_field32(end_esmask, end->w1);
+    bool notify = xive_esb_trigger(&pq);
+
+    if (pq != xive_get_field32(end_esmask, end->w1)) {
+        end->w1 = xive_set_field32(end_esmask, end->w1, pq);
+        xive_router_write_end(xrtr, end_blk, end_idx, end, 1);
+    }
+
+    /* ESe/n[Q]=1 : end of notification */
+    return notify;
 }
 
 /*
@@ -1442,6 +1478,7 @@ static void xive_router_end_notify(XiveRouter *xrtr, 
uint8_t end_blk,
     XiveEND end;
     uint8_t priority;
     uint8_t format;
+    bool found;
 
     /* END cache lookup */
     if (xive_router_get_end(xrtr, end_blk, end_idx, &end)) {
@@ -1462,6 +1499,13 @@ static void xive_router_end_notify(XiveRouter *xrtr, 
uint8_t end_blk,
         xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
     }
 
+    /*
+     * When the END is silent, we skip the notification part.
+     */
+    if (xive_end_is_silent_escalation(&end)) {
+        goto do_escalation;
+    }
+
     /*
      * The W7 format depends on the F bit in W6. It defines the type
      * of the notification :
@@ -1483,16 +1527,9 @@ static void xive_router_end_notify(XiveRouter *xrtr, 
uint8_t end_blk,
      * even futher coalescing in the Router
      */
     if (!xive_end_is_notify(&end)) {
-        uint8_t pq = xive_get_field32(END_W1_ESn, end.w1);
-        bool notify = xive_esb_trigger(&pq);
-
-        if (pq != xive_get_field32(END_W1_ESn, end.w1)) {
-            end.w1 = xive_set_field32(END_W1_ESn, end.w1, pq);
-            xive_router_write_end(xrtr, end_blk, end_idx, &end, 1);
-        }
-
         /* ESn[Q]=1 : end of notification */
-        if (!notify) {
+        if (!xive_router_end_es_notify(xrtr, end_blk, end_idx,
+                                       &end, END_W1_ESn)) {
             return;
         }
     }
@@ -1500,7 +1537,7 @@ static void xive_router_end_notify(XiveRouter *xrtr, 
uint8_t end_blk,
     /*
      * Follows IVPE notification
      */
-    xive_presenter_notify(xrtr, format,
+    found = xive_presenter_notify(xrtr, format,
                           xive_get_field32(END_W6_NVT_BLOCK, end.w6),
                           xive_get_field32(END_W6_NVT_INDEX, end.w6),
                           xive_get_field32(END_W7_F0_IGNORE, end.w7),
@@ -1508,6 +1545,61 @@ static void xive_router_end_notify(XiveRouter *xrtr, 
uint8_t end_blk,
                           xive_get_field32(END_W7_F1_LOG_SERVER_ID, end.w7));
 
     /* TODO: Auto EOI. */
+
+    if (found) {
+        return;
+    }
+
+    /*
+     * If no matching NVT is dispatched on a HW thread :
+     * - specific VP: update the NVT structure if backlog is activated
+     * - logical server : forward request to IVPE (not supported)
+     */
+    if (xive_end_is_backlog(&end)) {
+        if (format == 1) {
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "XIVE: END %x/%x invalid config: F1 & backlog\n",
+                          end_blk, end_idx);
+            return;
+        }
+        xive_router_end_backlog(xrtr,
+                                xive_get_field32(END_W6_NVT_BLOCK, end.w6),
+                                xive_get_field32(END_W6_NVT_INDEX, end.w6),
+                                priority);
+
+        /*
+         * On HW, follows a "Broadcast Backlog" to IVPEs
+         */
+    }
+
+do_escalation:
+    /*
+     * If activated, escalate notification using the ESe PQ bits and
+     * the EAS in w4-5
+     */
+    if (!xive_end_is_escalate(&end)) {
+        return;
+    }
+
+    /*
+     * Check the END ESe (Event State Buffer for escalation) for even
+     * futher coalescing in the Router
+     */
+    if (!xive_end_is_uncond_escalation(&end)) {
+        /* ESe[Q]=1 : end of notification */
+        if (!xive_router_end_es_notify(xrtr, end_blk, end_idx,
+                                       &end, END_W1_ESe)) {
+            return;
+        }
+    }
+
+    /*
+     * The END trigger becomes an Escalation trigger
+     */
+    xive_router_end_notify(xrtr,
+                           xive_get_field32(END_W4_ESC_END_BLOCK, end.w4),
+                           xive_get_field32(END_W4_ESC_END_INDEX, end.w4),
+                           xive_get_field32(END_W5_ESC_END_DATA,  end.w5));
 }
 
 void xive_router_notify(XiveNotifier *xn, uint32_t lisn)
-- 
2.21.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]