summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAdrien Pesle <adrien.pesle@arm.com>2018-09-03 16:43:24 +0200
committerGiacomo Travaglini <giacomo.travaglini@arm.com>2018-10-01 08:28:51 +0000
commit058e2cec7c56bf0549efff1df5974799c41cd1be (patch)
tree0be3f4915fae6c32e017735bb4bd36cd34c6e2d4 /src
parentcf20e8211e2c3f1b2085c949a1e992a1f5d1071c (diff)
downloadgem5-058e2cec7c56bf0549efff1df5974799c41cd1be.tar.xz
dev-arm: Add basic support for level sensitive SPIs in GICv2
For level sensitive interrupt IRQ line must be cleared when interrupt is deasserted. This is not the case for edge-trigerred interrupt. Change-Id: Ib1660da74a296750c0eb9e20878d4ee64bd23130 Reviewed-on: https://gem5-review.googlesource.com/12944 Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com> Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Diffstat (limited to 'src')
-rw-r--r--src/dev/arm/gic_v2.cc32
-rw-r--r--src/dev/arm/gic_v2.hh18
2 files changed, 45 insertions, 5 deletions
diff --git a/src/dev/arm/gic_v2.cc b/src/dev/arm/gic_v2.cc
index fe5e1eac8..fd846387c 100644
--- a/src/dev/arm/gic_v2.cc
+++ b/src/dev/arm/gic_v2.cc
@@ -346,8 +346,10 @@ GicV2::readCpu(ContextID ctx, Addr daddr)
uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx]);
getActiveInt(ctx, intNumToWord(cpuHighestInt[ctx])) |= int_num;
updateRunPri();
- getPendingInt(ctx, intNumToWord(cpuHighestInt[ctx]))
- &= ~int_num;
+ if (!isLevelSensitive(ctx, active_int)) {
+ getPendingInt(ctx, intNumToWord(cpuHighestInt[ctx]))
+ &= ~int_num;
+ }
}
DPRINTF(Interrupt,
@@ -783,10 +785,17 @@ GicV2::updateIntState(int hint)
}
}
+ uint32_t prev_highest = cpuHighestInt[cpu];
cpuHighestInt[cpu] = highest_int;
- if (highest_int == SPURIOUS_INT)
+ if (highest_int == SPURIOUS_INT) {
+ if (isLevelSensitive(cpu, prev_highest)) {
+
+ DPRINTF(Interrupt, "Clear IRQ for cpu%d\n", cpu);
+ platform->intrctrl->clear(cpu, ArmISA::INT_IRQ, 0);
+ }
continue;
+ }
/* @todo make this work for more than one cpu, need to handle 1:N, N:N
* models */
@@ -855,9 +864,22 @@ GicV2::sendPPInt(uint32_t num, uint32_t cpu)
}
void
-GicV2::clearInt(uint32_t number)
+GicV2::clearInt(uint32_t num)
{
- /* @todo assume edge triggered only at the moment. Nothing to do. */
+ if (isLevelSensitive(0, num)) {
+ uint8_t target = getCpuTarget(0, num);
+
+ DPRINTF(Interrupt,
+ "Received Clear interrupt number %d, cpuTarget %#x:\n",
+ num, target);
+
+ getPendingInt(target, intNumToWord(num)) &= ~(1 << intNumToBit(num));
+ updateIntState(intNumToWord(num));
+ } else {
+ /* Nothing to do :
+ * Edge-triggered interrupt remain pending until software
+ * writes GICD_ICPENDR or reads GICC_IAR */
+ }
}
void
diff --git a/src/dev/arm/gic_v2.hh b/src/dev/arm/gic_v2.hh
index 5791250d1..352b108d0 100644
--- a/src/dev/arm/gic_v2.hh
+++ b/src/dev/arm/gic_v2.hh
@@ -262,6 +262,16 @@ class GicV2 : public BaseGic, public BaseGicRegisters
}
}
+ /** GICD_ICFGRn
+ * get 2 bit config associated to an interrupt.
+ */
+ uint8_t getIntConfig(ContextID ctx, uint32_t ix) {
+ assert(ix < INT_LINES_MAX);
+ const uint8_t cfg_low = intNumToBit(ix * 2);
+ const uint8_t cfg_hi = cfg_low + 1;
+ return bits(intConfig[intNumToWord(ix * 2)], cfg_hi, cfg_low);
+ }
+
/** GICD_ITARGETSR{8..255}
* an 8 bit cpu target id for each global interrupt.
*/
@@ -291,6 +301,14 @@ class GicV2 : public BaseGic, public BaseGicRegisters
* and if it is 1:N or N:N */
uint32_t intConfig[INT_BITS_MAX*2];
+ bool isLevelSensitive(ContextID ctx, uint32_t ix) {
+ if (ix == SPURIOUS_INT) {
+ return false;
+ } else {
+ return bits(getIntConfig(ctx, ix), 1) == 0;
+ }
+ }
+
/** CPU enabled */
bool cpuEnabled[CPU_MAX];