qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Frederic Barrat <fbarrat@linux.ibm.com>
To: clg@kaod.org, danielhb413@gmail.com, qemu-ppc@nongnu.org,
	qemu-devel@nongnu.org
Cc: npiggin@gmail.com
Subject: [PATCH] ppc/xive: Save/restore state of the External interrupt
Date: Tue, 26 Apr 2022 12:11:25 +0200	[thread overview]
Message-ID: <20220426101125.297064-1-fbarrat@linux.ibm.com> (raw)

When pulling an OS context from a vcpu, we should lower the External
interrupt if it is pending. Otherwise, it may be delivered in the
hypervisor context, which is unexpected. It can lead to an infinite
loop where the hypervisor catches the External exception, looks for an
interrupt, doesn't find any, exits the exception handler, repeat...

It also means that when pushing a new OS context on a vcpu, we need to
always check the restored Interrupt Pending Buffer (IPB), potentially
merge it with any escalation interrupt, and re-apply the External
interrupt signal if needed.

Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com>
---

Cedric: I'm wondering the reason behind commit
8256870ada9379abfd1f5b2c209ad01092dd0904, which makes the PIPR field
of the OS context read-only. The comment says it is re-evaluated from
the IPB when pushing a context, but I don't think it's true on P9
if there's no escalation. It's not a problem on P10 because we always
re-evaluate the PIPR if CPPR>0.
In any case, it's no longer an issue with this patch, but I'm
curious as to why restoring the PIPR was a problem in the first place.


 hw/intc/xive.c        | 26 +++++++++++++++++++++++---
 hw/intc/xive2.c       | 14 ++++++++------
 include/hw/ppc/xive.h |  1 +
 3 files changed, 32 insertions(+), 9 deletions(-)

diff --git a/hw/intc/xive.c b/hw/intc/xive.c
index b8e4c7294d..8430db687f 100644
--- a/hw/intc/xive.c
+++ b/hw/intc/xive.c
@@ -114,6 +114,21 @@ static void xive_tctx_notify(XiveTCTX *tctx, uint8_t ring)
     }
 }
 
+void xive_tctx_eval_ext_signal(XiveTCTX *tctx)
+{
+    uint8_t *regs = &tctx->regs[TM_QW1_OS];
+
+    /*
+     * Used when pulling an OS context.
+     * Lower the External interrupt if it's pending. It is necessary
+     * to avoid catching it in the hypervisor context. It should be
+     * raised again when re-pushing the OS context.
+     */
+    if (regs[TM_PIPR] < regs[TM_CPPR]) {
+        qemu_irq_lower(xive_tctx_output(tctx, TM_QW1_OS));
+    }
+}
+
 static void xive_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
 {
     uint8_t *regs = &tctx->regs[ring];
@@ -388,6 +403,8 @@ static uint64_t xive_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
     /* Invalidate CAM line */
     qw1w2_new = xive_set_field32(TM_QW1W2_VO, qw1w2, 0);
     xive_tctx_set_os_cam(tctx, qw1w2_new);
+
+    xive_tctx_eval_ext_signal(tctx);
     return qw1w2;
 }
 
@@ -413,10 +430,13 @@ static void xive_tctx_need_resend(XiveRouter *xrtr, XiveTCTX *tctx,
         /* Reset the NVT value */
         nvt.w4 = xive_set_field32(NVT_W4_IPB, nvt.w4, 0);
         xive_router_write_nvt(xrtr, nvt_blk, nvt_idx, &nvt, 4);
-
-        /* Merge in current context */
-        xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb);
     }
+    /*
+     * Always merge in current context. Even if there's no escalation,
+     * it will check with the IPB value restored before pushing the OS
+     * context and set the External interrupt signal if needed.
+     */
+    xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb);
 }
 
 /*
diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c
index 3aff42a69e..b7f1917cd2 100644
--- a/hw/intc/xive2.c
+++ b/hw/intc/xive2.c
@@ -269,6 +269,7 @@ uint64_t xive2_tm_pull_os_ctx(XivePresenter *xptr, XiveTCTX *tctx,
         xive2_tctx_save_os_ctx(xrtr, tctx, nvp_blk, nvp_idx);
     }
 
+    xive_tctx_eval_ext_signal(tctx);
     return qw1w2;
 }
 
@@ -316,7 +317,6 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx,
 {
     Xive2Nvp nvp;
     uint8_t ipb;
-    uint8_t cppr = 0;
 
     /*
      * Grab the associated thread interrupt context registers in the
@@ -337,7 +337,7 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx,
     /* Automatically restore thread context registers */
     if (xive2_router_get_config(xrtr) & XIVE2_VP_SAVE_RESTORE &&
         do_restore) {
-        cppr = xive2_tctx_restore_os_ctx(xrtr, tctx, nvp_blk, nvp_idx, &nvp);
+        xive2_tctx_restore_os_ctx(xrtr, tctx, nvp_blk, nvp_idx, &nvp);
     }
 
     ipb = xive_get_field32(NVP2_W2_IPB, nvp.w2);
@@ -346,10 +346,12 @@ static void xive2_tctx_need_resend(Xive2Router *xrtr, XiveTCTX *tctx,
         xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, &nvp, 2);
     }
 
-    /* An IPB or CPPR change can trigger a resend */
-    if (ipb || cppr) {
-        xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb);
-    }
+    /*
+     * Always merge in current context. Even if there's no escalation,
+     * it will check with the IPB value restored and set the External
+     * interrupt signal if needed.
+     */
+    xive_tctx_ipb_update(tctx, TM_QW1_OS, ipb);
 }
 
 /*
diff --git a/include/hw/ppc/xive.h b/include/hw/ppc/xive.h
index 126e4e2c3a..91512ed5e6 100644
--- a/include/hw/ppc/xive.h
+++ b/include/hw/ppc/xive.h
@@ -527,6 +527,7 @@ Object *xive_tctx_create(Object *cpu, XivePresenter *xptr, Error **errp);
 void xive_tctx_reset(XiveTCTX *tctx);
 void xive_tctx_destroy(XiveTCTX *tctx);
 void xive_tctx_ipb_update(XiveTCTX *tctx, uint8_t ring, uint8_t ipb);
+void xive_tctx_eval_ext_signal(XiveTCTX *tctx);
 
 /*
  * KVM XIVE device helpers
-- 
2.35.1



             reply	other threads:[~2022-04-26 10:22 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-26 10:11 Frederic Barrat [this message]
2022-04-26 12:35 ` [PATCH] ppc/xive: Save/restore state of the External interrupt Cédric Le Goater
2022-04-26 14:49   ` Frederic Barrat
2022-04-26 15:24     ` Cédric Le Goater
2022-04-28  8:04       ` Frederic Barrat
2022-04-26 13:54 ` Cédric Le Goater

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=20220426101125.297064-1-fbarrat@linux.ibm.com \
    --to=fbarrat@linux.ibm.com \
    --cc=clg@kaod.org \
    --cc=danielhb413@gmail.com \
    --cc=npiggin@gmail.com \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-ppc@nongnu.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).