[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v5 06/10] hw/intc: GICv3 redistributor ITS processing
From: |
Peter Maydell |
Subject: |
Re: [PATCH v5 06/10] hw/intc: GICv3 redistributor ITS processing |
Date: |
Mon, 5 Jul 2021 15:43:33 +0100 |
On Wed, 30 Jun 2021 at 16:32, Shashi Mallela <shashi.mallela@linaro.org> wrote:
>
> Implemented lpi processing at redistributor to get lpi config info
> from lpi configuration table,determine priority,set pending state in
> lpi pending table and forward the lpi to cpuif.Added logic to invoke
> redistributor lpi processing with translated LPI which set/clear LPI
> from ITS device as part of ITS INT,CLEAR,DISCARD command and
> GITS_TRANSLATER processing.
>
> Signed-off-by: Shashi Mallela <shashi.mallela@linaro.org>
> ---
> hw/intc/arm_gicv3.c | 14 +++
> hw/intc/arm_gicv3_common.c | 1 +
> hw/intc/arm_gicv3_cpuif.c | 7 +-
> hw/intc/arm_gicv3_its.c | 24 ++++-
> hw/intc/arm_gicv3_redist.c | 142 +++++++++++++++++++++++++++++
> hw/intc/gicv3_internal.h | 8 ++
> include/hw/intc/arm_gicv3_common.h | 7 ++
> 7 files changed, 197 insertions(+), 6 deletions(-)
> diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
> index adaee72c1f..5adb55a01a 100644
> --- a/hw/intc/arm_gicv3_its.c
> +++ b/hw/intc/arm_gicv3_its.c
> @@ -225,6 +225,7 @@ static MemTxResult process_its_cmd(GICv3ITSState *s,
> uint64_t value,
> bool ite_valid = false;
> uint64_t cte = 0;
> bool cte_valid = false;
> + uint64_t rdbase;
> IteEntry ite;
>
> if (cmd == NONE) {
> @@ -282,10 +283,18 @@ static MemTxResult process_its_cmd(GICv3ITSState *s,
> uint64_t value,
> * command in the queue
> */
> } else {
> - /*
> - * Current implementation only supports rdbase == procnum
> - * Hence rdbase physical address is ignored
> - */
This change doesn't make us start handling the "is a physical address"
case, so why delete the comment?
> + rdbase = (cte >> 1U) & RDBASE_PROCNUM_MASK;
> +
> + if (rdbase > s->gicv3->num_cpu) {
> + return res;
> + }
> +
> + if ((cmd == CLEAR) || (cmd == DISCARD)) {
> + gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 0);
> + } else {
> + gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 1);
> + }
> +
> if (cmd == DISCARD) {
> memset(&ite, 0 , sizeof(ite));
> /* remove mapping from interrupt translation table */
> @@ -672,6 +681,13 @@ static void process_cmdq(GICv3ITSState *s)
> break;
> case GITS_CMD_INV:
> case GITS_CMD_INVALL:
> + /*
> + * Current implementation doesn't cache any ITS tables,
> + * but the calculated lpi priority information.We only
Missing space after "."
> + * need to trigger lpi priority re-calculation to be in
> + * sync with LPI config table or pending table changes.
> + */
> + gicv3_redist_update_lpi(s->gicv3->cpu);
I think we need to recalculate for all redistributors, not just the first one.
> break;
> default:
> break;
> diff --git a/hw/intc/arm_gicv3_redist.c b/hw/intc/arm_gicv3_redist.c
> index fc3d95dcc6..97553e6ada 100644
> --- a/hw/intc/arm_gicv3_redist.c
> +++ b/hw/intc/arm_gicv3_redist.c
> @@ -254,6 +254,9 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr
> offset,
> if (cs->gicr_typer & GICR_TYPER_PLPIS) {
> if (value & GICR_CTLR_ENABLE_LPIS) {
> cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS;
> + /* Check for any pending interr in pending table */
> + gicv3_redist_update_lpi(cs);
> + gicv3_redist_update(cs);
> } else {
> cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS;
> }
> @@ -532,6 +535,145 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr
> offset, uint64_t data,
> return r;
> }
>
> +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;
> +
> + 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;
Need to OR with 0x80, not AND.
> + }
> +
> + 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;
> + }
> +}
> +
> +void gicv3_redist_update_lpi(GICv3CPUState *cs)
> +{
> + /*
> + * This function scans the LPI pending table and for each pending
> + * LPI, reads the corresponding entry from LPI configuration table
> + * to extract the priority info and determine if the current LPI
> + * priority is lower than the last computed high priority lpi interrupt.
> + * If yes, replace current LPI as the new high priority lpi interrupt.
> + */
> + AddressSpace *as = &cs->gic->dma_as;
> + uint64_t lpipt_baddr;
> + uint32_t pendt_size = 0;
> + uint8_t pend;
> + int i;
> + uint64_t idbits;
> +
> + idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
> + GICD_TYPER_IDBITS);
> +
> + if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
> + !cs->gicr_pendbaser || (idbits < GICR_PROPBASER_IDBITS_THRESHOLD)) {
> + return;
> + }
> +
> + cs->hpplpi.prio = 0xff;
> +
> + lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
> +
> + /* Determine the highest priority pending interrupt among LPIs */
> + pendt_size = (1ULL << (idbits + 1));
> +
> + for (i = 0; i < pendt_size / 8; i++) {
> + address_space_read(as, lpipt_baddr +
> + (((GICV3_LPI_INTID_START + i) / 8) * sizeof(pend)),
> + MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
> +
> + if (!((1 << ((GICV3_LPI_INTID_START + i) % 8)) & pend)) {
> + continue;
> + }
> +
> + gicv3_redist_check_lpi_priority(cs, GICV3_LPI_INTID_START + i);
> + }
> +}
> +
> +void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level)
> +{
> + /*
> + * This function updates the pending bit in lpi pending table for
> + * the irq being activated or deactivated.
> + */
> + AddressSpace *as = &cs->gic->dma_as;
> + uint64_t lpipt_baddr;
> + bool ispend = false;
> + uint8_t pend;
> +
> + /*
> + * get the bit value corresponding to this irq in the
> + * lpi pending table
> + */
> + lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
> +
> + address_space_read(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
> + MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
> +
> + /*
> + * check if this LPI is better than the current hpplpi, if yes
> + * just set hpplpi.prio and .irq without doing a full rescan
> + */
> + if (level) {
> + gicv3_redist_check_lpi_priority(cs, irq);
> + }
> +
> + ispend = extract32(pend, irq % 8, 1);
> +
> + /* no change in the value of pending bit,return */
Missing space after comma.
> + if (ispend == level) {
> + return;
> + }
I would put the "is the level same as it already was" check before
we go off and do the priority-check, not after. Then you can do all
the handling of "the level changed" at the end, with
if (level) {
gicv3_redist_check_lpi_priority(...);
} else {
gicv3_redist_update_lpi(...);
}
Also, if this is a level == 0, you don't need to do the full rescan
of the LPI table unless the LPI being deactivated is the current
highest priority LPI.
> + pend = deposit32(pend, irq % 8, 1, level ? 1 : 0);
> +
> + address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
> + MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
> +
> + if (!level) {
> + gicv3_redist_update_lpi(cs);
> + }
> +}
> +
> +void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
> +{
> + uint64_t idbits;
> +
> + idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
> + GICD_TYPER_IDBITS);
> +
> + if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
> + !cs->gicr_pendbaser || (idbits < GICR_PROPBASER_IDBITS_THRESHOLD) ||
> + (irq > (1ULL << (idbits + 1)))) {
> + return;
> + }
> +
> + /* set/clear the pending bit for this irq */
> + gicv3_redist_lpi_pending(cs, irq, level);
> +
> + gicv3_redist_update(cs);
> +}
> +
> void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
> {
> /* Update redistributor state for a change in an external PPI input line
> */
> diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h
> index 43ce4a8a95..c0ec1d9a66 100644
> --- a/hw/intc/gicv3_internal.h
> +++ b/hw/intc/gicv3_internal.h
> @@ -308,6 +308,11 @@ FIELD(GITS_TYPER, CIL, 36, 1)
>
> #define L1TABLE_ENTRY_SIZE 8
>
> +#define LPI_CTE_ENABLED TABLE_ENTRY_VALID_MASK
> +#define LPI_CTE_PRIORITY_OFFSET 2
> +#define LPI_CTE_PRIORITY_MASK ((1U << 6) - 1)
These aren't using the standard naming convention (_SHIFT for the
bitshift, and the _MASK should be in-place, not in the ls bits).
But you don't use the defines anyway, so you could just not bother
defining them.
thanks
-- PMM
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: [PATCH v5 06/10] hw/intc: GICv3 redistributor ITS processing,
Peter Maydell <=