Reviewed-by: Glenn Miles <mil...@linux.ibm.com>

On Mon, 2025-05-12 at 13:10 +1000, Nicholas Piggin wrote:
> In preparation to implement POOL context push, add support for POOL
> NVP context save/restore.
> 
> The NVP p bit is defined in the spec as follows:
> 
>     If TRUE, the CPPR of a Pool VP in the NVP is updated during store of
>     the context with the CPPR of the Hard context it was running under.
> 
> It's not clear whether non-pool VPs always or never get CPPR updated.
> Before this patch, OS contexts always save CPPR, so we will assume that
> is the behaviour.
> 
> Signed-off-by: Nicholas Piggin <npig...@gmail.com>
> ---
>  hw/intc/xive2.c             | 51 +++++++++++++++++++++++++------------
>  include/hw/ppc/xive2_regs.h |  1 +
>  2 files changed, 36 insertions(+), 16 deletions(-)
> 
> diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c
> index e3060810d3..d899c1fb14 100644
> --- a/hw/intc/xive2.c
> +++ b/hw/intc/xive2.c
> @@ -512,12 +512,13 @@ static void xive2_presenter_backlog_decr(XivePresenter 
> *xptr,
>   */
>  
>  static void xive2_tctx_save_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
> -                                uint8_t nvp_blk, uint32_t nvp_idx,
> -                                uint8_t ring)
> +                                uint8_t ring,
> +                                uint8_t nvp_blk, uint32_t nvp_idx)
>  {
>      CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
>      uint32_t pir = env->spr_cb[SPR_PIR].default_value;
>      Xive2Nvp nvp;
> +    uint8_t *sig_regs = xive_tctx_signal_regs(tctx, ring);
>      uint8_t *regs = &tctx->regs[ring];
>  
>      if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) {
> @@ -553,7 +554,14 @@ static void xive2_tctx_save_ctx(Xive2Router *xrtr, 
> XiveTCTX *tctx,
>      }
>  
>      nvp.w2 = xive_set_field32(NVP2_W2_IPB, nvp.w2, regs[TM_IPB]);
> -    nvp.w2 = xive_set_field32(NVP2_W2_CPPR, nvp.w2, regs[TM_CPPR]);
> +
> +    if ((nvp.w0 & NVP2_W0_P) || ring != TM_QW2_HV_POOL) {
> +        /*
> +         * Non-pool contexts always save CPPR (ignore p bit). XXX: Clarify
> +         * whether that is the correct behaviour.
> +         */
> +        nvp.w2 = xive_set_field32(NVP2_W2_CPPR, nvp.w2, sig_regs[TM_CPPR]);
> +    }
>      if (nvp.w0 & NVP2_W0_L) {
>          /*
>           * Typically not used. If LSMFB is restored with 0, it will
> @@ -722,7 +730,7 @@ static uint64_t xive2_tm_pull_ctx(XivePresenter *xptr, 
> XiveTCTX *tctx,
>      }
>  
>      if (xive2_router_get_config(xrtr) & XIVE2_VP_SAVE_RESTORE && do_save) {
> -        xive2_tctx_save_ctx(xrtr, tctx, nvp_blk, nvp_idx, ring);
> +        xive2_tctx_save_ctx(xrtr, tctx, ring, nvp_blk, nvp_idx);
>      }
>  
>      /*
> @@ -863,12 +871,15 @@ void xive2_tm_pull_phys_ctx_ol(XivePresenter *xptr, 
> XiveTCTX *tctx,
>      xive2_tm_pull_ctx_ol(xptr, tctx, offset, value, size, TM_QW3_HV_PHYS);
>  }
>  
> -static uint8_t xive2_tctx_restore_os_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
> -                                        uint8_t nvp_blk, uint32_t nvp_idx,
> -                                        Xive2Nvp *nvp)
> +static uint8_t xive2_tctx_restore_ctx(Xive2Router *xrtr, XiveTCTX *tctx,
> +                                      uint8_t ring,
> +                                      uint8_t nvp_blk, uint32_t nvp_idx,
> +                                      Xive2Nvp *nvp)
>  {
>      CPUPPCState *env = &POWERPC_CPU(tctx->cs)->env;
>      uint32_t pir = env->spr_cb[SPR_PIR].default_value;
> +    uint8_t *sig_regs = xive_tctx_signal_regs(tctx, ring);
> +    uint8_t *regs = &tctx->regs[ring];
>      uint8_t cppr;
>  
>      if (!xive2_nvp_is_hw(nvp)) {
> @@ -881,10 +892,10 @@ static uint8_t xive2_tctx_restore_os_ctx(Xive2Router 
> *xrtr, XiveTCTX *tctx,
>      nvp->w2 = xive_set_field32(NVP2_W2_CPPR, nvp->w2, 0);
>      xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, nvp, 2);
>  
> -    tctx->regs[TM_QW1_OS + TM_CPPR] = cppr;
> -    tctx->regs[TM_QW1_OS + TM_LSMFB] = xive_get_field32(NVP2_W2_LSMFB, 
> nvp->w2);
> -    tctx->regs[TM_QW1_OS + TM_LGS] = xive_get_field32(NVP2_W2_LGS, nvp->w2);
> -    tctx->regs[TM_QW1_OS + TM_T] = xive_get_field32(NVP2_W2_T, nvp->w2);
> +    sig_regs[TM_CPPR] = cppr;
> +    regs[TM_LSMFB] = xive_get_field32(NVP2_W2_LSMFB, nvp->w2);
> +    regs[TM_LGS] = xive_get_field32(NVP2_W2_LGS, nvp->w2);
> +    regs[TM_T] = xive_get_field32(NVP2_W2_T, nvp->w2);
>  
>      nvp->w1 = xive_set_field32(NVP2_W1_CO, nvp->w1, 1);
>      nvp->w1 = xive_set_field32(NVP2_W1_CO_THRID_VALID, nvp->w1, 1);
> @@ -893,9 +904,18 @@ static uint8_t xive2_tctx_restore_os_ctx(Xive2Router 
> *xrtr, XiveTCTX *tctx,
>      /*
>       * Checkout privilege: 0:OS, 1:Pool, 2:Hard
>       *
> -     * TODO: we only support OS push/pull
> +     * TODO: we don't support hard push/pull
>       */
> -    nvp->w1 = xive_set_field32(NVP2_W1_CO_PRIV, nvp->w1, 0);
> +    switch (ring) {
> +    case TM_QW1_OS:
> +        nvp->w1 = xive_set_field32(NVP2_W1_CO_PRIV, nvp->w1, 0);
> +        break;
> +    case TM_QW2_HV_POOL:
> +        nvp->w1 = xive_set_field32(NVP2_W1_CO_PRIV, nvp->w1, 1);
> +        break;
> +    default:
> +        g_assert_not_reached();
> +    }
>  
>      xive2_router_write_nvp(xrtr, nvp_blk, nvp_idx, nvp, 1);
>  
> @@ -930,9 +950,8 @@ 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) {
> -        xive2_tctx_restore_os_ctx(xrtr, tctx, nvp_blk, nvp_idx, &nvp);
> +    if (xive2_router_get_config(xrtr) & XIVE2_VP_SAVE_RESTORE && do_restore) 
> {
> +        xive2_tctx_restore_ctx(xrtr, tctx, TM_QW1_OS, nvp_blk, nvp_idx, 
> &nvp);
>      }
>  
>      ipb = xive_get_field32(NVP2_W2_IPB, nvp.w2);
> diff --git a/include/hw/ppc/xive2_regs.h b/include/hw/ppc/xive2_regs.h
> index f82054661b..2a3e60abad 100644
> --- a/include/hw/ppc/xive2_regs.h
> +++ b/include/hw/ppc/xive2_regs.h
> @@ -158,6 +158,7 @@ typedef struct Xive2Nvp {
>  #define NVP2_W0_L                  PPC_BIT32(8)
>  #define NVP2_W0_G                  PPC_BIT32(9)
>  #define NVP2_W0_T                  PPC_BIT32(10)
> +#define NVP2_W0_P                  PPC_BIT32(11)
>  #define NVP2_W0_ESC_END            PPC_BIT32(25) /* 'N' bit 0:ESB  1:END */
>  #define NVP2_W0_PGOFIRST           PPC_BITMASK32(26, 31)
>          uint32_t       w1;


Reply via email to