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

On Mon, 2025-05-12 at 13:10 +1000, Nicholas Piggin wrote:
> The second part of the set CPPR operation is to process (or re-present)
> any pending interrupts after CPPR is adjusted.
> 
> Split this presentation processing out into a standalone function that
> can be used in other places.
> 
> Signed-off-by: Nicholas Piggin <npig...@gmail.com>
> ---
>  hw/intc/xive2.c | 137 +++++++++++++++++++++++++++---------------------
>  1 file changed, 76 insertions(+), 61 deletions(-)
> 
> diff --git a/hw/intc/xive2.c b/hw/intc/xive2.c
> index 8c8dab3aa2..aa06bfda77 100644
> --- a/hw/intc/xive2.c
> +++ b/hw/intc/xive2.c
> @@ -1098,66 +1098,19 @@ void xive2_tm_ack_os_el(XivePresenter *xptr, XiveTCTX 
> *tctx,
>      xive2_tctx_accept_el(xptr, tctx, TM_QW1_OS, TM_QW1_OS);
>  }
>  
> -/* NOTE: CPPR only exists for TM_QW1_OS and TM_QW3_HV_PHYS */
> -static void xive2_tctx_set_cppr(XiveTCTX *tctx, uint8_t ring, uint8_t cppr)
> +/* Re-calculate and present pending interrupts */
> +static void xive2_tctx_process_pending(XiveTCTX *tctx, uint8_t sig_ring)
>  {
> -    uint8_t *sig_regs = &tctx->regs[ring];
> +    uint8_t *sig_regs = &tctx->regs[sig_ring];
>      Xive2Router *xrtr = XIVE2_ROUTER(tctx->xptr);
> -    uint8_t old_cppr, backlog_prio, first_group, group_level;
> +    uint8_t backlog_prio, first_group, group_level;
>      uint8_t pipr_min, lsmfb_min, ring_min;
> +    uint8_t cppr = sig_regs[TM_CPPR];
>      bool group_enabled;
> -    uint8_t nvp_blk;
> -    uint32_t nvp_idx;
>      Xive2Nvp nvp;
>      int rc;
> -    uint8_t nsr = sig_regs[TM_NSR];
> -
> -    g_assert(ring == TM_QW1_OS || ring == TM_QW3_HV_PHYS);
> -
> -    g_assert(tctx->regs[TM_QW2_HV_POOL + TM_NSR] == 0);
> -    g_assert(tctx->regs[TM_QW2_HV_POOL + TM_PIPR] == 0);
> -    g_assert(tctx->regs[TM_QW2_HV_POOL + TM_CPPR] == 0);
> -
> -    /* XXX: should show pool IPB for PHYS ring */
> -    trace_xive_tctx_set_cppr(tctx->cs->cpu_index, ring,
> -                             sig_regs[TM_IPB], sig_regs[TM_PIPR],
> -                             cppr, nsr);
> -
> -    if (cppr > XIVE_PRIORITY_MAX) {
> -        cppr = 0xff;
> -    }
> -
> -    old_cppr = sig_regs[TM_CPPR];
> -    sig_regs[TM_CPPR] = cppr;
> -
> -    /* Handle increased CPPR priority (lower value) */
> -    if (cppr < old_cppr) {
> -        if (cppr <= sig_regs[TM_PIPR]) {
> -            /* CPPR lowered below PIPR, must un-present interrupt */
> -            if (xive_nsr_indicates_exception(ring, nsr)) {
> -                if (xive_nsr_indicates_group_exception(ring, nsr)) {
> -                    /* redistribute precluded active grp interrupt */
> -                    xive2_redistribute(xrtr, tctx,
> -                                       xive_nsr_exception_ring(ring, nsr));
> -                    return;
> -                }
> -            }
>  
> -            /* interrupt is VP directed, pending in IPB */
> -            xive_tctx_pipr_set(tctx, ring, cppr, 0);
> -            return;
> -        } else {
> -            /* CPPR was lowered, but still above PIPR. No action needed. */
> -            return;
> -        }
> -    }
> -
> -    /* CPPR didn't change, nothing needs to be done */
> -    if (cppr == old_cppr) {
> -        return;
> -    }
> -
> -    /* CPPR priority decreased (higher value) */
> +    g_assert(sig_ring == TM_QW3_HV_PHYS || sig_ring == TM_QW1_OS);
>  
>      /*
>       * Recompute the PIPR based on local pending interrupts. It will
> @@ -1167,11 +1120,11 @@ again:
>      pipr_min = xive_ipb_to_pipr(sig_regs[TM_IPB]);
>      group_enabled = !!sig_regs[TM_LGS];
>      lsmfb_min = group_enabled ? sig_regs[TM_LSMFB] : 0xff;
> -    ring_min = ring;
> +    ring_min = sig_ring;
>      group_level = 0;
>  
>      /* PHYS updates also depend on POOL values */
> -    if (ring == TM_QW3_HV_PHYS) {
> +    if (sig_ring == TM_QW3_HV_PHYS) {
>          uint8_t *pool_regs = &tctx->regs[TM_QW2_HV_POOL];
>  
>          /* POOL values only matter if POOL ctx is valid */
> @@ -1201,20 +1154,25 @@ again:
>          }
>      }
>  
> -    rc = xive2_tctx_get_nvp_indexes(tctx, ring_min, &nvp_blk, &nvp_idx);
> -    if (rc) {
> -        qemu_log_mask(LOG_GUEST_ERROR, "XIVE: set CPPR on invalid 
> context\n");
> -        return;
> -    }
> -
>      if (group_enabled &&
>          lsmfb_min < cppr &&
>          lsmfb_min < pipr_min) {
> +
> +        uint8_t nvp_blk;
> +        uint32_t nvp_idx;
> +
>          /*
>           * Thread has seen a group interrupt with a higher priority
>           * than the new cppr or pending local interrupt. Check the
>           * backlog
>           */
> +        rc = xive2_tctx_get_nvp_indexes(tctx, ring_min, &nvp_blk, &nvp_idx);
> +        if (rc) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "XIVE: set CPPR on invalid "
> +                                           "context\n");
> +            return;
> +        }
> +
>          if (xive2_router_get_nvp(xrtr, nvp_blk, nvp_idx, &nvp)) {
>              qemu_log_mask(LOG_GUEST_ERROR, "XIVE: No NVP %x/%x\n",
>                            nvp_blk, nvp_idx);
> @@ -1260,6 +1218,63 @@ again:
>      xive_tctx_pipr_set(tctx, ring_min, pipr_min, group_level);
>  }
>  
> +/* NOTE: CPPR only exists for TM_QW1_OS and TM_QW3_HV_PHYS */
> +static void xive2_tctx_set_cppr(XiveTCTX *tctx, uint8_t sig_ring, uint8_t 
> cppr)
> +{
> +    uint8_t *sig_regs = &tctx->regs[sig_ring];
> +    Xive2Router *xrtr = XIVE2_ROUTER(tctx->xptr);
> +    uint8_t old_cppr;
> +    uint8_t nsr = sig_regs[TM_NSR];
> +
> +    g_assert(sig_ring == TM_QW1_OS || sig_ring == TM_QW3_HV_PHYS);
> +
> +    g_assert(tctx->regs[TM_QW2_HV_POOL + TM_NSR] == 0);
> +    g_assert(tctx->regs[TM_QW2_HV_POOL + TM_PIPR] == 0);
> +    g_assert(tctx->regs[TM_QW2_HV_POOL + TM_CPPR] == 0);
> +
> +    /* XXX: should show pool IPB for PHYS ring */
> +    trace_xive_tctx_set_cppr(tctx->cs->cpu_index, sig_ring,
> +                             sig_regs[TM_IPB], sig_regs[TM_PIPR],
> +                             cppr, nsr);
> +
> +    if (cppr > XIVE_PRIORITY_MAX) {
> +        cppr = 0xff;
> +    }
> +
> +    old_cppr = sig_regs[TM_CPPR];
> +    sig_regs[TM_CPPR] = cppr;
> +
> +    /* Handle increased CPPR priority (lower value) */
> +    if (cppr < old_cppr) {
> +        if (cppr <= sig_regs[TM_PIPR]) {
> +            /* CPPR lowered below PIPR, must un-present interrupt */
> +            if (xive_nsr_indicates_exception(sig_ring, nsr)) {
> +                if (xive_nsr_indicates_group_exception(sig_ring, nsr)) {
> +                    /* redistribute precluded active grp interrupt */
> +                    xive2_redistribute(xrtr, tctx,
> +                                       xive_nsr_exception_ring(sig_ring, 
> nsr));
> +                    return;
> +                }
> +            }
> +
> +            /* interrupt is VP directed, pending in IPB */
> +            xive_tctx_pipr_set(tctx, sig_ring, cppr, 0);
> +            return;
> +        } else {
> +            /* CPPR was lowered, but still above PIPR. No action needed. */
> +            return;
> +        }
> +    }
> +
> +    /* CPPR didn't change, nothing needs to be done */
> +    if (cppr == old_cppr) {
> +        return;
> +    }
> +
> +    /* CPPR priority decreased (higher value) */
> +    xive2_tctx_process_pending(tctx, sig_ring);
> +}
> +
>  void xive2_tm_set_hv_cppr(XivePresenter *xptr, XiveTCTX *tctx,
>                            hwaddr offset, uint64_t value, unsigned size)
>  {


Reply via email to