From 058e2cec7c56bf0549efff1df5974799c41cd1be Mon Sep 17 00:00:00 2001 From: Adrien Pesle Date: Mon, 3 Sep 2018 16:43:24 +0200 Subject: 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 Maintainer: Andreas Sandberg --- src/dev/arm/gic_v2.cc | 32 +++++++++++++++++++++++++++----- src/dev/arm/gic_v2.hh | 18 ++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) (limited to 'src/dev/arm') 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]; -- cgit v1.2.3