@@ -166,6 +166,12 @@ static void gicv3_redist_update_noirqset(GICv3CPUState *cs)
cs->hppi.grp = gicv3_irq_group(cs->gic, cs, cs->hppi.irq);
}
+ if (cs->gic->lpi_enable) {
+ if (gicv3_redist_update_lpi(cs)) {
+ seenbetter = true;
+ }
+ }
+
/* If the best interrupt we just found would preempt whatever
* was the previous best interrupt before this update, then
* we know it's definitely the best one now.
@@ -899,9 +899,14 @@ static void icc_activate_irq(GICv3CPUState *cs, int irq)
cs->gicr_ipendr0 = deposit32(cs->gicr_ipendr0, irq, 1, 0);
gicv3_redist_update(cs);
} else {
- gicv3_gicd_active_set(cs->gic, irq);
- gicv3_gicd_pending_clear(cs->gic, irq);
- gicv3_update(cs->gic, irq, 1);
+ if (irq >= GICV3_LPI_INTID_START) {
+ gicv3_redist_lpi_pending(cs, irq, 0);
+ gicv3_redist_update(cs);
+ } else {
+ gicv3_gicd_active_set(cs->gic, irq);
+ gicv3_gicd_pending_clear(cs->gic, irq);
+ gicv3_update(cs->gic, irq, 1);
+ }
}
}
@@ -1337,7 +1342,9 @@ static void icc_eoir_write(CPUARMState *env, const ARMCPRegInfo *ri,
* valid interrupt value read from the Interrupt Acknowledge
* register" and so this is UNPREDICTABLE. We choose to ignore it.
*/
- return;
+ if (!(cs->gic->lpi_enable && (irq >= GICV3_LPI_INTID_START))) {
+ return;
+ }
}
if (icc_highest_active_group(cs) != grp) {
@@ -262,6 +262,7 @@ static MemTxResult process_int(GICv3ITSState *s, uint64_t value,
bool ite_valid = false;
uint64_t cte = 0;
bool cte_valid = false;
+ uint64_t rdbase;
uint8_t buff[GITS_TYPER_ITT_ENTRY_SIZE];
uint64_t itt_addr;
@@ -315,12 +316,18 @@ static MemTxResult process_int(GICv3ITSState *s, uint64_t value,
* since with a physical address the target address must be
* 64KB aligned
*/
-
+ rdbase = (cte >> 1U) & RDBASE_MASK;
/*
* Current implementation only supports rdbase == procnum
* Hence rdbase physical address is ignored
*/
} else {
+ rdbase = (cte >> 1U) & RDBASE_PROCNUM_MASK;
+ 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) {
/* remove mapping from interrupt translation table */
@@ -549,6 +549,132 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
return r;
}
+bool gicv3_redist_update_lpi(GICv3CPUState *cs)
+{
+ AddressSpace *as = &cs->gic->sysmem_as;
+ uint64_t lpict_baddr, lpipt_baddr;
+ uint32_t pendt_size = 0;
+ uint8_t lpite;
+ uint8_t prio, pend;
+ int i;
+ bool seenbetter = false;
+
+ if ((!cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
+ !cs->gicr_pendbaser || cs->lpi_outofrange) {
+ return seenbetter;
+ }
+
+ lpict_baddr = (cs->gicr_propbaser >> GICR_PROPBASER_ADDR_OFFSET) &
+ GICR_PROPBASER_ADDR_MASK;
+ lpict_baddr <<= GICR_PROPBASER_ADDR_OFFSET;
+
+ lpipt_baddr = (cs->gicr_pendbaser >> GICR_PENDBASER_ADDR_OFFSET) &
+ GICR_PENDBASER_ADDR_MASK;
+ lpipt_baddr <<= GICR_PENDBASER_ADDR_OFFSET;
+
+ /* Determine the highest priority pending interrupt among LPIs */
+ pendt_size = (1UL << ((cs->gicr_propbaser &
+ GICR_PROPBASER_IDBITS_MASK) - 1));
+
+ for (i = 0; i < pendt_size; 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) {
+ address_space_read(as, lpict_baddr + (i * sizeof(lpite)),
+ MEMTXATTRS_UNSPECIFIED, &lpite, sizeof(lpite));
+
+ prio = ((lpite >> LPI_CTE_PRIORITY_OFFSET) &
+ LPI_CTE_PRIORITY_MASK);
+ prio &= LPI_PRIORITY_MASK;
+
+ if (prio < cs->hppi.prio) {
+ cs->hppi.irq = GICV3_LPI_INTID_START + i;
+ cs->hppi.prio = prio;
+ /* LPIs are always non-secure Grp1 interrupts */
+ cs->hppi.grp = GICV3_G1NS;
+ seenbetter = true;
+ }
+ }
+ }
+ return seenbetter;
+}
+
+void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level)
+{
+ AddressSpace *as = &cs->gic->sysmem_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 >> GICR_PENDBASER_ADDR_OFFSET) &
+ GICR_PENDBASER_ADDR_MASK;
+ lpipt_baddr <<= GICR_PENDBASER_ADDR_OFFSET;
+
+ address_space_read(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
+ MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
+ ispend = ((pend >> (irq % 8)) & 0x1);
+
+ if (ispend) {
+ if (!level) {
+ /*
+ * clear the pending bit and update the lpi pending table
+ */
+ pend &= ~(1 << (irq % 8));
+
+ address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
+ MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
+ }
+ } else {
+ if (level) {
+ /*
+ * if pending bit is not already set for this irq,turn-on the
+ * pending bit and update the lpi pending table
+ */
+ pend |= (1 << (irq % 8));
+
+ address_space_write(as, lpipt_baddr + ((irq / 8) * sizeof(pend)),
+ MEMTXATTRS_UNSPECIFIED, &pend, sizeof(pend));
+ }
+ }
+}
+
+void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level)
+{
+ AddressSpace *as = &cs->gic->sysmem_as;
+ uint64_t lpict_baddr;
+ uint8_t lpite;
+
+ if ((!cs->gicr_ctlr & GICR_CTLR_ENABLE_LPIS) || !cs->gicr_propbaser ||
+ !cs->gicr_pendbaser || cs->lpi_outofrange) {
+ return;
+ }
+
+ lpict_baddr = (cs->gicr_propbaser >> GICR_PROPBASER_ADDR_OFFSET) &
+ GICR_PROPBASER_ADDR_MASK;
+ lpict_baddr <<= GICR_PROPBASER_ADDR_OFFSET;
+
+ /* get the lpi config table entry corresponding to this irq */
+ address_space_read(as, lpict_baddr + ((irq - GICV3_LPI_INTID_START) *
+ sizeof(lpite)), MEMTXATTRS_UNSPECIFIED,
+ &lpite, sizeof(lpite));
+
+ /* check if this irq is enabled before proceeding further */
+ if (!(lpite & LPI_CTE_ENABLED)) {
+ 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 */
@@ -465,6 +465,9 @@ MemTxResult gicv3_redist_write(void *opaque, hwaddr offset, uint64_t data,
unsigned size, MemTxAttrs attrs);
void gicv3_dist_set_irq(GICv3State *s, int irq, int level);
void gicv3_redist_set_irq(GICv3CPUState *cs, int irq, int level);
+void gicv3_redist_process_lpi(GICv3CPUState *cs, int irq, int level);
+void gicv3_redist_lpi_pending(GICv3CPUState *cs, int irq, int level);
+bool gicv3_redist_update_lpi(GICv3CPUState *cs);
void gicv3_redist_send_sgi(GICv3CPUState *cs, int grp, int irq, bool ns);
void gicv3_init_cpuif(GICv3State *s);
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 | 6 + hw/intc/arm_gicv3_cpuif.c | 15 ++- hw/intc/arm_gicv3_its.c | 9 +- hw/intc/arm_gicv3_redist.c | 126 ++++++++++++++++++++ hw/intc/gicv3_internal.h | 3 + 5 files changed, 154 insertions(+), 5 deletions(-)