From e51f65a440ab6e044a5a4c8abcbcb132615bf001 Mon Sep 17 00:00:00 2001 From: Giacomo Travaglini Date: Fri, 17 Jul 2020 13:25:04 +0100 Subject: [PATCH] dev-arm: Implement LevelSensitive SPIs in GICv3 Change-Id: If918a8aea934f0037818cc64bf458076bfd0251d Signed-off-by: Giacomo Travaglini Reviewed-by: Nikos Nikoleris Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31515 Reviewed-by: Andreas Sandberg Maintainer: Andreas Sandberg Tested-by: kokoro --- src/dev/arm/gic_v3.cc | 5 +++-- src/dev/arm/gic_v3_distributor.cc | 23 ++++++++++++++++++++--- src/dev/arm/gic_v3_distributor.hh | 27 +++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/dev/arm/gic_v3.cc b/src/dev/arm/gic_v3.cc index 575194004..8e75b1c5b 100644 --- a/src/dev/arm/gic_v3.cc +++ b/src/dev/arm/gic_v3.cc @@ -177,9 +177,10 @@ Gicv3::sendInt(uint32_t int_id) } void -Gicv3::clearInt(uint32_t number) +Gicv3::clearInt(uint32_t int_id) { - distributor->deassertSPI(number); + DPRINTF(Interrupt, "Gicv3::clearInt(): received SPI %d\n", int_id); + distributor->clearInt(int_id); } void diff --git a/src/dev/arm/gic_v3_distributor.cc b/src/dev/arm/gic_v3_distributor.cc index f8605da27..27f404b2b 100644 --- a/src/dev/arm/gic_v3_distributor.cc +++ b/src/dev/arm/gic_v3_distributor.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 @@ -74,6 +74,7 @@ Gicv3Distributor::Gicv3Distributor(Gicv3 * gic, uint32_t it_lines) irqGroup(it_lines, 0), irqEnabled(it_lines, false), irqPending(it_lines, false), + irqPendingIspendr(it_lines, false), irqActive(it_lines, false), irqPriority(it_lines, 0xAA), irqConfig(it_lines, Gicv3::INT_LEVEL_SENSITIVE), @@ -608,6 +609,7 @@ Gicv3Distributor::write(Addr addr, uint64_t data, size_t size, DPRINTF(GIC, "Gicv3Distributor::write() (GICD_ISPENDR): " "int_id %d (SPI) pending bit set\n", int_id); irqPending[int_id] = true; + irqPendingIspendr[int_id] = true; } } @@ -634,7 +636,7 @@ Gicv3Distributor::write(Addr addr, uint64_t data, size_t size, bool clear = data & (1 << i) ? 1 : 0; - if (clear) { + if (clear && treatAsEdgeTriggered(int_id)) { irqPending[int_id] = false; clearIrqCpuInterface(int_id); } @@ -1000,11 +1002,22 @@ Gicv3Distributor::sendInt(uint32_t int_id) panic_if(int_id < Gicv3::SGI_MAX + Gicv3::PPI_MAX, "Invalid SPI!"); panic_if(int_id > itLines, "Invalid SPI!"); irqPending[int_id] = true; + irqPendingIspendr[int_id] = false; DPRINTF(GIC, "Gicv3Distributor::sendInt(): " "int_id %d (SPI) pending bit set\n", int_id); update(); } +void +Gicv3Distributor::clearInt(uint32_t int_id) +{ + // Edge-triggered interrupts remain pending until software + // writes GICD_ICPENDR, GICD_CLRSPI_* or activates them via ICC_IAR + if (isLevelSensitive(int_id)) { + deassertSPI(int_id); + } +} + void Gicv3Distributor::deassertSPI(uint32_t int_id) { @@ -1145,7 +1158,9 @@ Gicv3Distributor::getIntGroup(int int_id) const void Gicv3Distributor::activateIRQ(uint32_t int_id) { - irqPending[int_id] = false; + if (treatAsEdgeTriggered(int_id)) { + irqPending[int_id] = false; + } irqActive[int_id] = true; } @@ -1166,6 +1181,7 @@ Gicv3Distributor::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); @@ -1185,6 +1201,7 @@ Gicv3Distributor::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_distributor.hh b/src/dev/arm/gic_v3_distributor.hh index 62bed186d..99b65ed9a 100644 --- a/src/dev/arm/gic_v3_distributor.hh +++ b/src/dev/arm/gic_v3_distributor.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 @@ -151,6 +151,7 @@ class Gicv3Distributor : public Serializable std::vector irqGroup; std::vector irqEnabled; std::vector irqPending; + std::vector irqPendingIspendr; std::vector irqActive; std::vector irqPriority; std::vector irqConfig; @@ -222,6 +223,27 @@ class Gicv3Distributor : public Serializable } } + 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]; + } + inline bool nsAccessToSecInt(uint32_t int_id, bool is_secure_access) const { return !DS && !is_secure_access && getIntGroup(int_id) != Gicv3::G1NS; @@ -236,11 +258,12 @@ class Gicv3Distributor : public Serializable Gicv3Distributor(Gicv3 * gic, uint32_t it_lines); + void sendInt(uint32_t int_id); + void clearInt(uint32_t int_id); void deassertSPI(uint32_t int_id); void clearIrqCpuInterface(uint32_t int_id); void init(); uint64_t read(Addr addr, size_t size, bool is_secure_access); - void sendInt(uint32_t int_id); void write(Addr addr, uint64_t data, size_t size, bool is_secure_access); }; -- 2.30.2