From c23c6ff50a860c7ae245304f3a3530a71e6bf9f7 Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Fri, 17 Jul 2020 13:40:01 +0100 Subject: [PATCH] dev-arm: Implement LevelSensitive PPIs in GICv3 Change-Id: I7f28408eff7d502427c4486518c83506893f4a7a Signed-off-by: Giacomo Travaglini Reviewed-by: Nikos Nikoleris Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31516 Reviewed-by: Andreas Sandberg Maintainer: Andreas Sandberg Tested-by: kokoro --- src/dev/arm/gic_v3.cc | 6 +++++- src/dev/arm/gic_v3_redistributor.cc | 25 ++++++++++++++++++++++--- src/dev/arm/gic_v3_redistributor.hh | 27 ++++++++++++++++++++++++++- 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/dev/arm/gic_v3.cc b/src/dev/arm/gic_v3.cc index 8e75b1c5b..83f2c8321 100644 --- a/src/dev/arm/gic_v3.cc +++ b/src/dev/arm/gic_v3.cc @@ -193,8 +193,12 @@ Gicv3::sendPPInt(uint32_t int_id, uint32_t cpu) } void -Gicv3::clearPPInt(uint32_t num, uint32_t cpu) +Gicv3::clearPPInt(uint32_t int_id, uint32_t cpu) { + panic_if(cpu >= redistributors.size(), "Invalid cpuID clearing PPI!"); + DPRINTF(Interrupt, "Gicv3::clearPPInt(): received PPI %d cpuTarget %#x\n", + int_id, cpu); + redistributors[cpu]->clearPPInt(int_id); } void diff --git a/src/dev/arm/gic_v3_redistributor.cc b/src/dev/arm/gic_v3_redistributor.cc index 5fceed573..339039308 100644 --- a/src/dev/arm/gic_v3_redistributor.cc +++ b/src/dev/arm/gic_v3_redistributor.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 ARM Limited + * Copyright (c) 2019-2020 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -58,6 +58,7 @@ Gicv3Redistributor::Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id) irqGroup(Gicv3::SGI_MAX + Gicv3::PPI_MAX, 0), irqEnabled(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false), irqPending(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false), + irqPendingIspendr(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false), irqActive(Gicv3::SGI_MAX + Gicv3::PPI_MAX, false), irqPriority(Gicv3::SGI_MAX + Gicv3::PPI_MAX, 0), irqConfig(Gicv3::SGI_MAX + Gicv3::PPI_MAX, Gicv3::INT_EDGE_TRIGGERED), @@ -509,6 +510,7 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size, "(GICR_ISPENDR0): int_id %d (PPI) " "pending bit set\n", int_id); irqPending[int_id] = true; + irqPendingIspendr[int_id] = true; } } @@ -526,7 +528,7 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size, bool clear = data & (1 << int_id) ? 1 : 0; - if (clear) { + if (clear && treatAsEdgeTriggered(int_id)) { irqPending[int_id] = false; } } @@ -710,11 +712,23 @@ Gicv3Redistributor::sendPPInt(uint32_t int_id) assert((int_id >= Gicv3::SGI_MAX) && (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX)); irqPending[int_id] = true; + irqPendingIspendr[int_id] = false; DPRINTF(GIC, "Gicv3Redistributor::sendPPInt(): " "int_id %d (PPI) pending bit set\n", int_id); updateDistributor(); } +void +Gicv3Redistributor::clearPPInt(uint32_t int_id) +{ + assert((int_id >= Gicv3::SGI_MAX) && + (int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX)); + + if (isLevelSensitive(int_id)) { + irqPending[int_id] = false; + } +} + void Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns) { @@ -747,6 +761,7 @@ Gicv3Redistributor::sendSGI(uint32_t int_id, Gicv3::GroupId group, bool ns) if (!forward) return; irqPending[int_id] = true; + irqPendingIspendr[int_id] = false; DPRINTF(GIC, "Gicv3ReDistributor::sendSGI(): " "int_id %d (SGI) pending bit set\n", int_id); updateDistributor(); @@ -977,7 +992,9 @@ Gicv3Redistributor::getIntGroup(int int_id) const void Gicv3Redistributor::activateIRQ(uint32_t int_id) { - irqPending[int_id] = false; + if (treatAsEdgeTriggered(int_id)) { + irqPending[int_id] = false; + } irqActive[int_id] = true; } @@ -1037,6 +1054,7 @@ Gicv3Redistributor::serialize(CheckpointOut & cp) const SERIALIZE_CONTAINER(irqGroup); SERIALIZE_CONTAINER(irqEnabled); SERIALIZE_CONTAINER(irqPending); + SERIALIZE_CONTAINER(irqPendingIspendr); SERIALIZE_CONTAINER(irqActive); SERIALIZE_CONTAINER(irqPriority); SERIALIZE_CONTAINER(irqConfig); @@ -1058,6 +1076,7 @@ Gicv3Redistributor::unserialize(CheckpointIn & cp) UNSERIALIZE_CONTAINER(irqGroup); UNSERIALIZE_CONTAINER(irqEnabled); UNSERIALIZE_CONTAINER(irqPending); + UNSERIALIZE_CONTAINER(irqPendingIspendr); UNSERIALIZE_CONTAINER(irqActive); UNSERIALIZE_CONTAINER(irqPriority); UNSERIALIZE_CONTAINER(irqConfig); diff --git a/src/dev/arm/gic_v3_redistributor.hh b/src/dev/arm/gic_v3_redistributor.hh index ee92bc792..7def1a285 100644 --- a/src/dev/arm/gic_v3_redistributor.hh +++ b/src/dev/arm/gic_v3_redistributor.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 ARM Limited + * Copyright (c) 2019-2020 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -153,6 +153,7 @@ class Gicv3Redistributor : public Serializable std::vector irqGroup; std::vector irqEnabled; std::vector irqPending; + std::vector irqPendingIspendr; std::vector irqActive; std::vector irqPriority; std::vector irqConfig; @@ -221,6 +222,29 @@ class Gicv3Redistributor : public Serializable void update(); void updateDistributor(); + protected: + + bool isLevelSensitive(uint32_t int_id) const + { + return irqConfig[int_id] == Gicv3::INT_LEVEL_SENSITIVE; + } + + /** + * This helper is used to check if an interrupt should be treated as + * edge triggered in the following scenarios: + * + * a) While activating the interrupt + * b) While clearing an interrupt via ICPENDR + * + * In fact, in these two situations, a level sensitive interrupt + * which had been made pending via a write to ISPENDR, will be + * treated as it if was edge triggered. + */ + bool treatAsEdgeTriggered(uint32_t int_id) const + { + return !isLevelSensitive(int_id) || irqPendingIspendr[int_id]; + } + public: Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id); @@ -228,6 +252,7 @@ class Gicv3Redistributor : public Serializable void init(); uint64_t read(Addr addr, size_t size, bool is_secure_access); void sendPPInt(uint32_t int_id); + void clearPPInt(uint32_t int_id); void write(Addr addr, uint64_t data, size_t size, bool is_secure_access); }; -- 2.30.2