Skip to content

Commit 17fb5e3

Browse files
shashi-jpm215
authored andcommitted
hw/intc: GICv3 redistributor ITS processing
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 <[email protected]> Tested-by: Neil Armstrong <[email protected]> Reviewed-by: Peter Maydell <[email protected]> Message-id: [email protected] Signed-off-by: Peter Maydell <[email protected]>
1 parent ac30dec commit 17fb5e3

File tree

7 files changed

+200
-2
lines changed

7 files changed

+200
-2
lines changed

hw/intc/arm_gicv3.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,16 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
165165
cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
166166
}
167167

168+
if ((cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) && cs->gic->lpi_enable &&
169+
(cs->hpplpi.prio != 0xff)) {
170+
if (irqbetter(cs, cs->hpplpi.irq, cs->hpplpi.prio)) {
171+
cs->hppi.irq = cs->hpplpi.irq;
172+
cs->hppi.prio = cs->hpplpi.prio;
173+
cs->hppi.grp = cs->hpplpi.grp;
174+
seenbetter = true;
175+
}
176+
}
177+
168178
/* If the best interrupt we just found would preempt whatever
169179
* was the previous best interrupt before this update, then
170180
* we know it's definitely the best one now.
@@ -339,9 +349,13 @@ static void gicv3_set_irq(void *opaque, int irq, int level)
339349

340350
static void arm_gicv3_post_load(GICv3State *s)
341351
{
352+
int i;
342353
/* Recalculate our cached idea of the current highest priority
343354
* pending interrupt, but don't set IRQ or FIQ lines.
344355
*/
356+
for (i = 0; i < s->num_cpu; i++) {
357+
gicv3_redist_update_lpi(&s->cpu[i]);
358+
}
345359
gicv3_full_update_noirqset(s);
346360
/* Repopulate the cache of GICv3CPUState pointers for target CPUs */
347361
gicv3_cache_all_target_cpustates(s);

hw/intc/arm_gicv3_common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ static void arm_gicv3_common_reset(DeviceState *dev)
435435
memset(cs->gicr_ipriorityr, 0, sizeof(cs->gicr_ipriorityr));
436436

437437
cs->hppi.prio = 0xff;
438+
cs->hpplpi.prio = 0xff;
438439

439440
/* State in the CPU interface must *not* be reset here, because it
440441
* is part of the CPU's reset domain, not the GIC device's.

hw/intc/arm_gicv3_cpuif.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -899,10 +899,12 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
899899
cs->gicr_iactiver0 = deposit32(cs->gicr_iactiver0, irq, 1, 1);
900900
cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0);
901901
gicv3_redist_update(cs);
902-
} else {
902+
} else if (irq < GICV3_LPI_INTID_START) {
903903
gicv3_gicd_active_set(cs->gic, irq);
904904
gicv3_gicd_pending_clear(cs->gic, irq);
905905
gicv3_update(cs->gic, irq, 1);
906+
} else {
907+
gicv3_redist_lpi_pending(cs, irq, 0);
906908
}
907909
}
908910

@@ -1318,7 +1320,8 @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
13181320
trace_gicv3_icc_eoir_write(is_eoir0 ? 0 : 1,
13191321
gicv3_redist_affid(cs), value);
13201322

1321-
if (irq >= cs->gic->num_irq) {
1323+
if ((irq >= cs->gic->num_irq) &&
1324+
!(cs->gic->lpi_enable && (irq >= GICV3_LPI_INTID_START))) {
13221325
/* This handles two cases:
13231326
* 1. If software writes the ID of a spurious interrupt [ie 1020-1023]
13241327
* to the GICC_EOIR, the GIC ignores that write.

hw/intc/arm_gicv3_its.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ static bool process_its_cmd(GICv3ITSState *s, uint64_t value, uint32_t offset,
233233
uint64_t cte = 0;
234234
bool cte_valid = false;
235235
bool result = false;
236+
uint64_t rdbase;
236237

237238
if (cmd == NONE) {
238239
devid = offset;
@@ -293,6 +294,18 @@ static bool process_its_cmd(GICv3ITSState *s, uint64_t value, uint32_t offset,
293294
* Current implementation only supports rdbase == procnum
294295
* Hence rdbase physical address is ignored
295296
*/
297+
rdbase = (cte & GITS_CTE_RDBASE_PROCNUM_MASK) >> 1U;
298+
299+
if (rdbase > s->gicv3->num_cpu) {
300+
return result;
301+
}
302+
303+
if ((cmd == CLEAR) || (cmd == DISCARD)) {
304+
gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 0);
305+
} else {
306+
gicv3_redist_process_lpi(&s->gicv3->cpu[rdbase], pIntid, 1);
307+
}
308+
296309
if (cmd == DISCARD) {
297310
IteEntry ite = {};
298311
/* remove mapping from interrupt translation table */
@@ -621,6 +634,7 @@ static void process_cmdq(GICv3ITSState *s)
621634
MemTxResult res = MEMTX_OK;
622635
bool result = true;
623636
uint8_t cmd;
637+
int i;
624638

625639
if (!(s->ctlr & ITS_CTLR_ENABLED)) {
626640
return;
@@ -685,6 +699,15 @@ static void process_cmdq(GICv3ITSState *s)
685699
break;
686700
case GITS_CMD_INV:
687701
case GITS_CMD_INVALL:
702+
/*
703+
* Current implementation doesn't cache any ITS tables,
704+
* but the calculated lpi priority information. We only
705+
* need to trigger lpi priority re-calculation to be in
706+
* sync with LPI config table or pending table changes.
707+
*/
708+
for (i = 0; i < s->gicv3->num_cpu; i++) {
709+
gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
710+
}
688711
break;
689712
default:
690713
break;

hw/intc/arm_gicv3_redist.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,9 @@ static MemTxResult gicr_writel(GICv3CPUState *cs, hwaddr offset,
254254
if (cs->gicr_typer & GICR_TYPER_PLPIS) {
255255
if (value & GICR_CTLR_ENABLE_LPIS) {
256256
cs->gicr_ctlr |= GICR_CTLR_ENABLE_LPIS;
257+
/* Check for any pending interr in pending table */
258+
gicv3_redist_update_lpi(cs);
259+
gicv3_redist_update(cs);
257260
} else {
258261
cs->gicr_ctlr &= ~GICR_CTLR_ENABLE_LPIS;
259262
}
@@ -532,6 +535,144 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
532535
return r;
533536
}
534537

538+
static void gicv3_redist_check_lpi_priority(GICv3CPUState *cs, int irq)
539+
{
540+
AddressSpace *as = &cs->gic->dma_as;
541+
uint64_t lpict_baddr;
542+
uint8_t lpite;
543+
uint8_t prio;
544+
545+
lpict_baddr = cs->gicr_propbaser & R_GICR_PROPBASER_PHYADDR_MASK;
546+
547+
address_space_read(as, lpict_baddr + ((irq - GICV3_LPI_INTID_START) *
548+
sizeof(lpite)), MEMTXATTRS_UNSPECIFIED, &lpite,
549+
sizeof(lpite));
550+
551+
if (!(lpite & LPI_CTE_ENABLED)) {
552+
return;
553+
}
554+
555+
if (cs->gic->gicd_ctlr & GICD_CTLR_DS) {
556+
prio = lpite & LPI_PRIORITY_MASK;
557+
} else {
558+
prio = ((lpite & LPI_PRIORITY_MASK) >> 1) | 0x80;
559+
}
560+
561+
if ((prio < cs->hpplpi.prio) ||
562+
((prio == cs->hpplpi.prio) && (irq <= cs->hpplpi.irq))) {
563+
cs->hpplpi.irq = irq;
564+
cs->hpplpi.prio = prio;
565+
/* LPIs are always non-secure Grp1 interrupts */
566+
cs->hpplpi.grp = GICV3_G1NS;
567+
}
568+
}
569+
570+
void gicv3_redist_update_lpi(GICv3CPUState *cs)
571+
{
572+
/*
573+
* This function scans the LPI pending table and for each pending
574+
* LPI, reads the corresponding entry from LPI configuration table
575+
* to extract the priority info and determine if the current LPI
576+
* priority is lower than the last computed high priority lpi interrupt.
577+
* If yes, replace current LPI as the new high priority lpi interrupt.
578+
*/
579+
AddressSpace *as = &cs->gic->dma_as;
580+
uint64_t lpipt_baddr;
581+
uint32_t pendt_size = 0;
582+
uint8_t pend;
583+
int i, bit;
584+
uint64_t idbits;
585+
586+
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
587+
GICD_TYPER_IDBITS);
588+
589+
if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
590+
!cs->gicr_pendbaser) {
591+
return;
592+
}
593+
594+
cs->hpplpi.prio = 0xff;
595+
596+
lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
597+
598+
/* Determine the highest priority pending interrupt among LPIs */
599+
pendt_size = (1ULL << (idbits + 1));
600+
601+
for (i = GICV3_LPI_INTID_START / 8; i < pendt_size / 8; i++) {
602+
address_space_read(as, lpipt_baddr + i, MEMTXATTRS_UNSPECIFIED, &pend,
603+
sizeof(pend));
604+
605+
while (pend) {
606+
bit = ctz32(pend);
607+
gicv3_redist_check_lpi_priority(cs, i * 8 + bit);
608+
pend &= ~(1 << bit);
609+
}
610+
}
611+
}
612+
613+
void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level)
614+
{
615+
/*
616+
* This function updates the pending bit in lpi pending table for
617+
* the irq being activated or deactivated.
618+
*/
619+
AddressSpace *as = &cs->gic->dma_as;
620+
uint64_t lpipt_baddr;
621+
bool ispend = false;
622+
uint8_t pend;
623+
624+
/*
625+
* get the bit value corresponding to this irq in the
626+
* lpi pending table
627+
*/
628+
lpipt_baddr = cs->gicr_pendbaser & R_GICR_PENDBASER_PHYADDR_MASK;
629+
630+
address_space_read(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
631+
MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
632+
633+
ispend = extract32(pend, irq % 8, 1);
634+
635+
/* no change in the value of pending bit, return */
636+
if (ispend == level) {
637+
return;
638+
}
639+
pend = deposit32(pend, irq % 8, 1, level ? 1 : 0);
640+
641+
address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
642+
MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
643+
644+
/*
645+
* check if this LPI is better than the current hpplpi, if yes
646+
* just set hpplpi.prio and .irq without doing a full rescan
647+
*/
648+
if (level) {
649+
gicv3_redist_check_lpi_priority(cs, irq);
650+
} else {
651+
if (irq == cs->hpplpi.irq) {
652+
gicv3_redist_update_lpi(cs);
653+
}
654+
}
655+
}
656+
657+
void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
658+
{
659+
uint64_t idbits;
660+
661+
idbits = MIN(FIELD_EX64(cs->gicr_propbaser, GICR_PROPBASER, IDBITS),
662+
GICD_TYPER_IDBITS);
663+
664+
if (!(cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
665+
!cs->gicr_pendbaser || (irq > (1ULL << (idbits + 1)) - 1) ||
666+
irq < GICV3_LPI_INTID_START) {
667+
return;
668+
}
669+
670+
/* set/clear the pending bit for this irq */
671+
gicv3_redist_lpi_pending(cs, irq, level);
672+
673+
gicv3_redist_update(cs);
674+
}
675+
535676
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level)
536677
{
537678
/* Update redistributor state for a change in an external PPI input line */

hw/intc/gicv3_internal.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ FIELD(GICR_PENDBASER, PHYADDR, 16, 36)
140140
FIELD(GICR_PENDBASER, OUTERCACHE, 56, 3)
141141
FIELD(GICR_PENDBASER, PTZ, 62, 1)
142142

143+
#define GICR_PROPBASER_IDBITS_THRESHOLD 0xd
144+
143145
#define ICC_CTLR_EL1_CBPR (1U << 0)
144146
#define ICC_CTLR_EL1_EOIMODE (1U << 1)
145147
#define ICC_CTLR_EL1_PMHE (1U << 6)
@@ -305,6 +307,9 @@ FIELD(GITS_TYPER, CIL, 36, 1)
305307

306308
#define L1TABLE_ENTRY_SIZE 8
307309

310+
#define LPI_CTE_ENABLED TABLE_ENTRY_VALID_MASK
311+
#define LPI_PRIORITY_MASK 0xfc
312+
308313
#define GITS_CMDQ_ENTRY_SIZE 32
309314
#define NUM_BYTES_IN_DW 8
310315

@@ -397,6 +402,7 @@ FIELD(MAPC, RDBASE, 16, 32)
397402
* Valid = 1 bit,RDBase = 36 bits(considering max RDBASE)
398403
*/
399404
#define GITS_CTE_SIZE (0x8ULL)
405+
#define GITS_CTE_RDBASE_PROCNUM_MASK MAKE_64BIT_MASK(1, RDBASE_PROCNUM_LENGTH)
400406

401407
/* Special interrupt IDs */
402408
#define INTID_SECURE 1020
@@ -455,6 +461,9 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
455461
unsigned size, MemTxAttrs attrs);
456462
void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
457463
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
464+
void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level);
465+
void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level);
466+
void gicv3_redist_update_lpi(GICv3CPUState *cs);
458467
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
459468
void gicv3_init_cpuif(GICv3State *s);
460469

include/hw/intc/arm_gicv3_common.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,13 @@ struct GICv3CPUState {
204204
* real state above; it doesn't need to be migrated.
205205
*/
206206
PendingIrq hppi;
207+
208+
/*
209+
* Cached information recalculated from LPI tables
210+
* in guest memory
211+
*/
212+
PendingIrq hpplpi;
213+
207214
/* This is temporary working state, to avoid a malloc in gicv3_update() */
208215
bool seenbetter;
209216
};

0 commit comments

Comments
 (0)