ppc/xive2: split tctx presentation processing from set CPPR
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 <npiggin@gmail.com> Reviewed-by: Glenn Miles <milesg@linux.ibm.com> Reviewed-by: Michael Kowal <kowal@linux.ibm.com> Tested-by: Gautam Menghani <gautam@linux.ibm.com> Link: https://lore.kernel.org/qemu-devel/20250512031100.439842-37-npiggin@gmail.com Signed-off-by: Cédric Le Goater <clg@redhat.com>
This commit is contained in:
parent
64a18e0c37
commit
384f0365ab
1 changed files with 76 additions and 61 deletions
137
hw/intc/xive2.c
137
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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue