summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/dev/arm/gic_v2.cc21
-rw-r--r--src/dev/arm/gic_v2.hh33
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
*/