dev-arm: Implement LevelSensitive SPIs in GICv3

Change-Id: If918a8aea934f0037818cc64bf458076bfd0251d
Signed-off-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Reviewed-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/31515
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Giacomo Travaglini
2020-07-17 13:25:04 +01:00
parent f441a25204
commit e51f65a440
3 changed files with 48 additions and 7 deletions

View File

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

View File

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

View File

@@ -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 <uint8_t> irqGroup;
std::vector <bool> irqEnabled;
std::vector <bool> irqPending;
std::vector <bool> irqPendingIspendr;
std::vector <bool> irqActive;
std::vector <uint8_t> irqPriority;
std::vector <Gicv3::IntTriggerType> 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);
};