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>
This commit is contained in:
Adrien Pesle
2018-09-03 16:43:24 +02:00
committed by Giacomo Travaglini
parent cf20e8211e
commit 058e2cec7c
2 changed files with 45 additions and 5 deletions

View File

@@ -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

View File

@@ -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];