hw/intc/arm_gicv3_redist: Factor out "update hpplpi for one LPI" logic

Currently the functions which update the highest priority pending LPI
information by looking at the LPI Pending and Configuration tables
are hard-coded to use the physical LPI tables addressed by
GICR_PENDBASER and GICR_PROPBASER.  To support virtual LPIs we will
need to do essentially the same job, but looking at the current
virtual LPI Pending and Configuration tables and updating cs->hppvlpi
instead of cs->hpplpi.

Factor out the common part of the gicv3_redist_check_lpi_priority()
function into a new update_for_one_lpi() function, which updates
a PendingIrq struct if the specified LPI is higher priority than
what is currently recorded there.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20220408141550.1271295-28-peter.maydell@linaro.org
This commit is contained in:
Peter Maydell 2022-04-08 15:15:36 +01:00
parent 189d1d9d57
commit e97be73c97
1 changed files with 47 additions and 27 deletions

View File

@ -60,6 +60,49 @@ static uint32_t gicr_read_bitmap_reg(GICv3CPUState *cs, MemTxAttrs attrs,
return reg;
}
/**
* update_for_one_lpi: Update pending information if this LPI is better
*
* @cs: GICv3CPUState
* @irq: interrupt to look up in the LPI Configuration table
* @ctbase: physical address of the LPI Configuration table to use
* @ds: true if priority value should not be shifted
* @hpp: points to pending information to update
*
* Look up @irq in the Configuration table specified by @ctbase
* to see if it is enabled and what its priority is. If it is an
* enabled interrupt with a higher priority than that currently
* recorded in @hpp, update @hpp.
*/
static void update_for_one_lpi(GICv3CPUState *cs, int irq,
uint64_t ctbase, bool ds, PendingIrq *hpp)
{
uint8_t lpite;
uint8_t prio;
address_space_read(&cs->gic->dma_as,
ctbase + ((irq - GICV3_LPI_INTID_START) * sizeof(lpite)),
MEMTXATTRS_UNSPECIFIED, &lpite, sizeof(lpite));
if (!(lpite & LPI_CTE_ENABLED)) {
return;
}
if (ds) {
prio = lpite & LPI_PRIORITY_MASK;
} else {
prio = ((lpite & LPI_PRIORITY_MASK) >> 1) | 0x80;
}
if ((prio < hpp->prio) ||
((prio == hpp->prio) && (irq <= hpp->irq))) {
hpp->irq = irq;
hpp->prio = prio;
/* LPIs and vLPIs are always non-secure Grp1 interrupts */
hpp->grp = GICV3_G1NS;
}
}
static uint8_t gicr_read_ipriorityr(GICv3CPUState *cs, MemTxAttrs attrs,
int irq)
{
@ -598,34 +641,11 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
static void gicv3_redist_check_lpi_priority(GICv3CPUState *cs, int irq)
{
AddressSpace *as = &cs->gic->dma_as;
uint64_t lpict_baddr;
uint8_t lpite;
uint8_t prio;
uint64_t lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK;
lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK;
address_space_read(as, lpict_baddr + ((irq - GICV3_LPI_INTID_START) *
sizeof(lpite)), MEMTXATTRS_UNSPECIFIED, &lpite,
sizeof(lpite));
if (!(lpite & LPI_CTE_ENABLED)) {
return;
}
if (cs->gic->gicd_ctlr & GICD_CTLR_DS) {
prio = lpite & LPI_PRIORITY_MASK;
} else {
prio = ((lpite & LPI_PRIORITY_MASK) >> 1) | 0x80;
}
if ((prio < cs->hpplpi.prio) ||
((prio == cs->hpplpi.prio) && (irq <= cs->hpplpi.irq))) {
cs->hpplpi.irq = irq;
cs->hpplpi.prio = prio;
/* LPIs are always non-secure Grp1 interrupts */
cs->hpplpi.grp = GICV3_G1NS;
}
update_for_one_lpi(cs, irq, lpict_baddr,
cs->gic->gicd_ctlr & GICD_CTLR_DS,
&cs->hpplpi);
}
void gicv3_redist_update_lpi_only(GICv3CPUState *cs)