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:
committed by
Giacomo Travaglini
parent
cf20e8211e
commit
058e2cec7c
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user