diff options
-rw-r--r-- | src/dev/arm/gic_v2.cc | 21 | ||||
-rw-r--r-- | src/dev/arm/gic_v2.hh | 33 |
2 files changed, 50 insertions, 4 deletions
diff --git a/src/dev/arm/gic_v2.cc b/src/dev/arm/gic_v2.cc index 7bbc89e74..99124b08c 100644 --- a/src/dev/arm/gic_v2.cc +++ b/src/dev/arm/gic_v2.cc @@ -364,7 +364,7 @@ GicV2::readCpu(ContextID ctx, Addr daddr) ctx, iar.ack_id, iar.cpu_id, iar); cpuHighestInt[ctx] = SPURIOUS_INT; updateIntState(-1); - platform->intrctrl->clear(ctx, ArmISA::INT_IRQ, 0); + clearInt(ctx, active_int); return iar; } else { return SPURIOUS_INT; @@ -802,7 +802,7 @@ GicV2::updateIntState(int hint) if (isLevelSensitive(cpu, prev_highest)) { DPRINTF(Interrupt, "Clear IRQ for cpu%d\n", cpu); - platform->intrctrl->clear(cpu, ArmISA::INT_IRQ, 0); + clearInt(cpu, prev_highest); } continue; } @@ -816,7 +816,12 @@ GicV2::updateIntState(int hint) DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int, cpu); - postInt(cpu, curTick() + intLatency); + + if (isFiq(cpu, highest_int)) { + postFiq(cpu, curTick() + intLatency); + } else { + postInt(cpu, curTick() + intLatency); + } } } } @@ -902,6 +907,16 @@ GicV2::clearPPInt(uint32_t num, uint32_t cpu) } void +GicV2::clearInt(ContextID ctx, uint32_t int_num) +{ + if (isFiq(ctx, int_num)) { + platform->intrctrl->clear(ctx, ArmISA::INT_FIQ, 0); + } else { + platform->intrctrl->clear(ctx, ArmISA::INT_IRQ, 0); + } +} + +void GicV2::postInt(uint32_t cpu, Tick when) { if (!(postIntEvent[cpu]->scheduled())) { diff --git a/src/dev/arm/gic_v2.hh b/src/dev/arm/gic_v2.hh index 4f30b00e6..c9c1a4715 100644 --- a/src/dev/arm/gic_v2.hh +++ b/src/dev/arm/gic_v2.hh @@ -334,7 +334,35 @@ class GicV2 : public BaseGic, public BaseGicRegisters } } - /** CPU enabled */ + bool isGroup0(ContextID ctx, uint32_t int_num) { + const uint32_t group_reg = getIntGroup(ctx, intNumToWord(int_num)); + return bits(group_reg, intNumToBit(int_num)); + } + + /** + * This method checks if an interrupt ID must be signaled or has been + * signaled as a FIQ to the cpu. It does that by reading: + * + * 1) GICD_IGROUPR: controls if the interrupt is part of group0 or + * group1. Only group0 interrupts can be signaled as FIQs. + * + * 2) GICC_CTLR.FIQEn: controls whether the CPU interface signals Group 0 + * interrupts to a target processor using the FIQ or the IRQ signal + */ + bool isFiq(ContextID ctx, uint32_t int_num) { + const bool is_group0 = isGroup0(ctx, int_num); + const bool use_fiq = cpuControl[ctx].fiqEn; + + if (is_group0 && use_fiq) { + return true; + } else { + return false; + } + } + + /** CPU enabled: + * Checks if GICC_CTLR.EnableGrp0 or EnableGrp1 are set + */ bool cpuEnabled(ContextID ctx) const { return cpuControl[ctx].enableGrp0 || cpuControl[ctx].enableGrp1; @@ -393,6 +421,9 @@ class GicV2 : public BaseGic, public BaseGicRegisters int intNumToWord(int num) const { return num >> 5; } int intNumToBit(int num) const { return num % 32; } + /** Clears a cpu IRQ or FIQ signal */ + void clearInt(ContextID ctx, uint32_t int_num); + /** * Post an interrupt to a CPU with a delay */ |