summaryrefslogtreecommitdiff
path: root/src/dev/arm
diff options
context:
space:
mode:
authorJairo Balart <jairo.balart@metempsy.com>2019-02-05 10:16:34 +0100
committerJairo Balart <jairo.balart@metempsy.com>2019-02-18 11:45:24 +0000
commit6a64cc100614f8325007e39a5defe88a2c3ba0b4 (patch)
tree70728cbc4082d60ef199c5ccd3c6935409faf7ee /src/dev/arm
parent3264c824894c81be3842824eee4de589ad72fbdc (diff)
downloadgem5-6a64cc100614f8325007e39a5defe88a2c3ba0b4.tar.xz
dev-arm: LPI support for GICv3. This doesn't include an ITS model.
Change-Id: Ia2c02cca4f95672d6361fba16201a56e2047ddb7 Reviewed-on: https://gem5-review.googlesource.com/c/16142 Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com> Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Diffstat (limited to 'src/dev/arm')
-rw-r--r--src/dev/arm/gic_v3_cpu_interface.cc8
-rw-r--r--src/dev/arm/gic_v3_distributor.cc4
-rw-r--r--src/dev/arm/gic_v3_redistributor.cc236
-rw-r--r--src/dev/arm/gic_v3_redistributor.hh36
4 files changed, 276 insertions, 8 deletions
diff --git a/src/dev/arm/gic_v3_cpu_interface.cc b/src/dev/arm/gic_v3_cpu_interface.cc
index 9bc8cbd93..1beceaca7 100644
--- a/src/dev/arm/gic_v3_cpu_interface.cc
+++ b/src/dev/arm/gic_v3_cpu_interface.cc
@@ -460,6 +460,14 @@ Gicv3CPUInterface::readMiscReg(int misc_reg)
if (int_id < Gicv3::INTID_SECURE) {
activateIRQ(int_id, hppi.group);
}
+
+ // LPIs are not activated and when acked their pending
+ // bit is cleared
+ if (int_id >= Gicv3Redistributor::SMALLEST_LPI_ID)
+ {
+ redistributor->setClrLPI(int_id, false);
+ }
+
} else {
int_id = Gicv3::INTID_SPURIOUS;
}
diff --git a/src/dev/arm/gic_v3_distributor.cc b/src/dev/arm/gic_v3_distributor.cc
index 00f29a74c..5eee07d87 100644
--- a/src/dev/arm/gic_v3_distributor.cc
+++ b/src/dev/arm/gic_v3_distributor.cc
@@ -451,7 +451,7 @@ Gicv3Distributor::read(Addr addr, size_t size, bool is_secure_access)
* DVIS [18] == 0
* (The implementation does not support Direct Virtual LPI
* injection)
- * LPIS [17] == 0
+ * LPIS [17] == 1
* (The implementation does not support LPIs)
* MBIS [16] == 0
* (The implementation does not support message-based interrupts
@@ -467,7 +467,7 @@ Gicv3Distributor::read(Addr addr, size_t size, bool is_secure_access)
int max_spi_int_id = itLines - 1;
int it_lines_number = ceil((max_spi_int_id + 1) / 32.0) - 1;
return (1 << 26) | (1 << 25) | (1 << 24) | (0xf << 19) |
- (gic->getSystem()->haveSecurity() << 10) |
+ (1 << 17) | (gic->getSystem()->haveSecurity() << 10) |
(it_lines_number << 0);
}
diff --git a/src/dev/arm/gic_v3_redistributor.cc b/src/dev/arm/gic_v3_redistributor.cc
index ec1e388c7..62565079b 100644
--- a/src/dev/arm/gic_v3_redistributor.cc
+++ b/src/dev/arm/gic_v3_redistributor.cc
@@ -34,6 +34,7 @@
#include "debug/GIC.hh"
#include "dev/arm/gic_v3_cpu_interface.hh"
#include "dev/arm/gic_v3_distributor.hh"
+#include "mem/fs_translating_port_proxy.hh"
const AddrRange Gicv3Redistributor::GICR_IPRIORITYR(SGI_base + 0x0400,
SGI_base + 0x041f);
@@ -91,6 +92,10 @@ Gicv3Redistributor::reset()
DPG1S = false;
DPG1NS = false;
DPG0 = false;
+ EnableLPIs = false;
+ lpiConfigurationTablePtr = 0;
+ lpiIDBits = 0;
+ lpiPendingTablePtr = 0;
}
uint64_t
@@ -135,6 +140,10 @@ Gicv3Redistributor::read(Addr addr, size_t size, bool is_secure_access)
value |= GICR_CTLR_DPG0;
}
+ if (EnableLPIs) {
+ value |= GICR_CTLR_ENABLE_LPIS;
+ }
+
return value;
}
@@ -156,17 +165,17 @@ Gicv3Redistributor::read(Addr addr, size_t size, bool is_secure_access)
* Last [4] == X
* (This Redistributor is the highest-numbered Redistributor in
* a series of contiguous Redistributor pages)
- * DirectLPI [3] == 0
- * (direct injection of LPIs not supported)
+ * DirectLPI [3] == 1
+ * (direct injection of LPIs supported)
* VLPIS [1] == 0
* (virtual LPIs not supported)
- * PLPIS [0] == 0
- * (physical LPIs not supported)
+ * PLPIS [0] == 1
+ * (physical LPIs supported)
*/
uint64_t affinity = getAffinity();
int last = cpuId == (gic->getSystem()->numContexts() - 1);
return (affinity << 32) | (1 << 24) | (cpuId << 8) |
- (1 << 5) | (last << 4);
+ (1 << 5) | (last << 4) | (1 << 3) | (1 << 0);
}
case GICR_WAKER: // Wake Register
@@ -346,6 +355,39 @@ Gicv3Redistributor::read(Addr addr, size_t size, bool is_secure_access)
return value;
}
+ case GICR_PROPBASER: // Redistributor Properties Base Address Register
+ // OuterCache, bits [58:56]
+ // 000 Memory type defined in InnerCache field
+ // Physical_Address, bits [51:12]
+ // Bits [51:12] of the physical address containing the LPI
+ // Configuration table
+ // Shareability, bits [11:10]
+ // 00 Non-shareable
+ // InnerCache, bits [9:7]
+ // 000 Device-nGnRnE
+ // IDbits, bits [4:0]
+ // limited by GICD_TYPER.IDbits
+ return lpiConfigurationTablePtr | lpiIDBits;
+
+ // Redistributor LPI Pending Table Base Address Register
+ case GICR_PENDBASER:
+ // PTZ, bit [62]
+ // Pending Table Zero
+ // OuterCache, bits [58:56]
+ // 000 Memory type defined in InnerCache field
+ // Physical_Address, bits [51:16]
+ // Bits [51:16] of the physical address containing the LPI Pending
+ // table
+ // Shareability, bits [11:10]
+ // 00 Non-shareable
+ // InnerCache, bits [9:7]
+ // 000 Device-nGnRnE
+ return lpiPendingTablePtr;
+
+ // Redistributor Synchronize Register
+ case GICR_SYNCR:
+ return 0;
+
default:
panic("Gicv3Redistributor::read(): invalid offset %#x\n", addr);
break;
@@ -382,7 +424,8 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
switch (addr) {
case GICR_CTLR: {
- // GICR_TYPER.LPIS is 0 so Enable_LPIs is RES0
+ // GICR_TYPER.LPIS is 0 so EnableLPIs is RES0
+ EnableLPIs = data & GICR_CTLR_ENABLE_LPIS;
DPG1S = data & GICR_CTLR_DPG1S;
DPG1NS = data & GICR_CTLR_DPG1NS;
DPG0 = data & GICR_CTLR_DPG0;
@@ -606,6 +649,81 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
break;
}
+ case GICR_SETLPIR: // Set LPI Pending Register
+ setClrLPI(data, true);
+ break;
+
+ case GICR_CLRLPIR: // Clear LPI Pending Register
+ setClrLPI(data, false);
+ break;
+
+ case GICR_PROPBASER: { // Redistributor Properties Base Address Register
+ // OuterCache, bits [58:56]
+ // 000 Memory type defined in InnerCache field
+ // Physical_Address, bits [51:12]
+ // Bits [51:12] of the physical address containing the LPI
+ // Configuration table
+ // Shareability, bits [11:10]
+ // 00 Non-shareable
+ // InnerCache, bits [9:7]
+ // 000 Device-nGnRnE
+ // IDbits, bits [4:0]
+ // limited by GICD_TYPER.IDbits (= 0xf)
+ lpiConfigurationTablePtr = data & 0xFFFFFFFFFF000;
+ lpiIDBits = data & 0x1f;
+
+ // 0xf here matches the value of GICD_TYPER.IDbits.
+ // TODO - make GICD_TYPER.IDbits a parameter instead of a hardcoded
+ // value
+ if (lpiIDBits > 0xf) {
+ lpiIDBits = 0xf;
+ }
+
+ uint32_t largest_lpi_id = 2 ^ (lpiIDBits + 1);
+ uint32_t number_lpis = largest_lpi_id - SMALLEST_LPI_ID + 1;
+ lpiConfigurationTable.resize(number_lpis);
+ break;
+ }
+
+ // Redistributor LPI Pending Table Base Address Register
+ case GICR_PENDBASER:
+ // PTZ, bit [62]
+ // Pending Table Zero
+ // OuterCache, bits [58:56]
+ // 000 Memory type defined in InnerCache field
+ // Physical_Address, bits [51:16]
+ // Bits [51:16] of the physical address containing the LPI Pending
+ // table
+ // Shareability, bits [11:10]
+ // 00 Non-shareable
+ // InnerCache, bits [9:7]
+ // 000 Device-nGnRnE
+ lpiPendingTablePtr = data & 0xFFFFFFFFF0000;
+ break;
+
+ case GICR_INVLPIR: { // Redistributor Invalidate LPI Register
+ uint32_t lpi_id = data & 0xffffffff;
+ uint32_t largest_lpi_id = 2 ^ (lpiIDBits + 1);
+
+ if (lpi_id > largest_lpi_id) {
+ return;
+ }
+
+ uint32_t lpi_table_entry_index = lpi_id - SMALLEST_LPI_ID;
+ invalLpiConfig(lpi_table_entry_index);
+ break;
+ }
+
+ case GICR_INVALLR: { // Redistributor Invalidate All Register
+ for (int lpi_table_entry_index = 0;
+ lpi_table_entry_index < lpiConfigurationTable.size();
+ lpi_table_entry_index++) {
+ invalLpiConfig(lpi_table_entry_index);
+ }
+
+ break;
+ }
+
default:
panic("Gicv3Redistributor::write(): invalid offset %#x\n", addr);
break;
@@ -613,6 +731,17 @@ Gicv3Redistributor::write(Addr addr, uint64_t data, size_t size,
}
void
+Gicv3Redistributor::invalLpiConfig(uint32_t lpi_entry_index)
+{
+ Addr lpi_table_entry_ptr = lpiConfigurationTablePtr +
+ lpi_entry_index * sizeof(LPIConfigurationTableEntry);
+ ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
+ tc->getVirtProxy().readBlob(lpi_table_entry_ptr,
+ (uint8_t*) &lpiConfigurationTable[lpi_entry_index],
+ sizeof(LPIConfigurationTableEntry));
+}
+
+void
Gicv3Redistributor::sendPPInt(uint32_t int_id)
{
assert((int_id >= Gicv3::SGI_MAX) &&
@@ -704,6 +833,42 @@ Gicv3Redistributor::update()
}
}
+ // Check LPIs
+ uint32_t largest_lpi_id = 2 ^ (lpiIDBits + 1);
+ char lpi_pending_table[largest_lpi_id / 8];
+ ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
+ tc->getVirtProxy().readBlob(lpiPendingTablePtr,
+ (uint8_t *) lpi_pending_table,
+ sizeof(lpi_pending_table));
+ for (int lpi_id = SMALLEST_LPI_ID; lpi_id < largest_lpi_id;
+ largest_lpi_id++) {
+ uint32_t lpi_pending_entry_byte = lpi_id / 8;
+ uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
+ bool lpi_is_pending = lpi_pending_table[lpi_pending_entry_byte] &
+ 1 << lpi_pending_entry_bit_position;
+ uint32_t lpi_configuration_entry_index = lpi_id - SMALLEST_LPI_ID;
+ bool lpi_is_enable =
+ lpiConfigurationTable[lpi_configuration_entry_index].enable;
+ // LPIs are always Non-secure Group 1 interrupts,
+ // in a system where two Security states are enabled.
+ Gicv3::GroupId lpi_group = Gicv3::G1NS;
+ bool group_enabled = distributor->groupEnabled(lpi_group);
+
+ if (lpi_is_pending && lpi_is_enable && group_enabled) {
+ uint8_t lpi_priority =
+ lpiConfigurationTable[lpi_configuration_entry_index].priority;
+
+ if ((lpi_priority < cpuInterface->hppi.prio) ||
+ (lpi_priority == cpuInterface->hppi.prio &&
+ lpi_id < cpuInterface->hppi.intid)) {
+ cpuInterface->hppi.intid = lpi_id;
+ cpuInterface->hppi.prio = lpi_priority;
+ cpuInterface->hppi.group = lpi_group;
+ new_hppi = true;
+ }
+ }
+ }
+
if (!new_hppi && cpuInterface->hppi.prio != 0xff &&
cpuInterface->hppi.intid < Gicv3::SGI_MAX + Gicv3::PPI_MAX) {
distributor->fullUpdate();
@@ -711,6 +876,57 @@ Gicv3Redistributor::update()
}
void
+Gicv3Redistributor::setClrLPI(uint64_t data, bool set)
+{
+ if (!EnableLPIs) {
+ // Writes to GICR_SETLPIR or GICR_CLRLPIR have not effect if
+ // GICR_CTLR.EnableLPIs == 0.
+ return;
+ }
+
+ uint32_t lpi_id = data & 0xffffffff;
+ uint32_t largest_lpi_id = 2 ^ (lpiIDBits + 1);
+
+ if (lpi_id > largest_lpi_id) {
+ // Writes to GICR_SETLPIR or GICR_CLRLPIR have not effect if
+ // pINTID value specifies an unimplemented LPI.
+ return;
+ }
+
+ Addr lpi_pending_entry_ptr = lpiPendingTablePtr + (lpi_id / 8);
+ uint8_t lpi_pending_entry;
+ ThreadContext * tc = gic->getSystem()->getThreadContext(cpuId);
+ tc->getVirtProxy().readBlob(lpi_pending_entry_ptr,
+ (uint8_t*) &lpi_pending_entry,
+ sizeof(lpi_pending_entry));
+ uint8_t lpi_pending_entry_bit_position = lpi_id % 8;
+ bool is_set = lpi_pending_entry & (1 << lpi_pending_entry_bit_position);
+
+ if (set) {
+ if (is_set) {
+ // Writes to GICR_SETLPIR have not effect if the pINTID field
+ // corresponds to an LPI that is already pending.
+ return;
+ }
+
+ lpi_pending_entry |= 1 << (lpi_pending_entry_bit_position);
+ } else {
+ if (!is_set) {
+ // Writes to GICR_SETLPIR have not effect if the pINTID field
+ // corresponds to an LPI that is not pending.
+ return;
+ }
+
+ lpi_pending_entry &= ~(1 << (lpi_pending_entry_bit_position));
+ }
+
+ tc->getVirtProxy().writeBlob(lpi_pending_entry_ptr,
+ (uint8_t*) &lpi_pending_entry,
+ sizeof(lpi_pending_entry));
+ updateAndInformCPUInterface();
+}
+
+void
Gicv3Redistributor::updateAndInformCPUInterface()
{
update();
@@ -814,6 +1030,10 @@ Gicv3Redistributor::serialize(CheckpointOut & cp) const
SERIALIZE_SCALAR(DPG1S);
SERIALIZE_SCALAR(DPG1NS);
SERIALIZE_SCALAR(DPG0);
+ SERIALIZE_SCALAR(EnableLPIs);
+ SERIALIZE_SCALAR(lpiConfigurationTablePtr);
+ SERIALIZE_SCALAR(lpiIDBits);
+ SERIALIZE_SCALAR(lpiPendingTablePtr);
}
void
@@ -831,4 +1051,8 @@ Gicv3Redistributor::unserialize(CheckpointIn & cp)
UNSERIALIZE_SCALAR(DPG1S);
UNSERIALIZE_SCALAR(DPG1NS);
UNSERIALIZE_SCALAR(DPG0);
+ UNSERIALIZE_SCALAR(EnableLPIs);
+ UNSERIALIZE_SCALAR(lpiConfigurationTablePtr);
+ UNSERIALIZE_SCALAR(lpiIDBits);
+ UNSERIALIZE_SCALAR(lpiPendingTablePtr);
}
diff --git a/src/dev/arm/gic_v3_redistributor.hh b/src/dev/arm/gic_v3_redistributor.hh
index 11553974a..664173641 100644
--- a/src/dev/arm/gic_v3_redistributor.hh
+++ b/src/dev/arm/gic_v3_redistributor.hh
@@ -119,6 +119,24 @@ class Gicv3Redistributor : public Serializable
// Interrupt Priority Registers
static const AddrRange GICR_IPRIORITYR;
+ // GIC physical LPI Redistributor register
+ enum {
+ // Set LPI Pending Register
+ GICR_SETLPIR = RD_base + 0x0040,
+ // Clear LPI Pending Register
+ GICR_CLRLPIR = RD_base + 0x0048,
+ //Redistributor Properties Base Address Register
+ GICR_PROPBASER = RD_base + 0x0070,
+ // Redistributor LPI Pending Table Base Address Register
+ GICR_PENDBASER = RD_base + 0x0078,
+ // Redistributor Invalidate LPI Register
+ GICR_INVLPIR = RD_base + 0x00A0,
+ // Redistributor Invalidate All Register
+ GICR_INVALLR = RD_base + 0x00B0,
+ // Redistributor Synchronize Register
+ GICR_SYNCR = RD_base + 0x00C0,
+ };
+
std::vector <uint8_t> irqGroup;
std::vector <bool> irqEnabled;
std::vector <bool> irqPending;
@@ -131,7 +149,21 @@ class Gicv3Redistributor : public Serializable
bool DPG1S;
bool DPG1NS;
bool DPG0;
+ bool EnableLPIs;
+
+ Addr lpiConfigurationTablePtr;
+ uint8_t lpiIDBits;
+ Addr lpiPendingTablePtr;
+ BitUnion8(LPIConfigurationTableEntry)
+ Bitfield<7, 2> priority;
+ Bitfield<1> res1;
+ Bitfield<0> enable;
+ EndBitUnion(LPIConfigurationTableEntry)
+
+ std::vector<LPIConfigurationTableEntry> lpiConfigurationTable;
+
+ static const uint32_t GICR_CTLR_ENABLE_LPIS = 1 << 0;
static const uint32_t GICR_CTLR_DPG0 = 1 << 24;
static const uint32_t GICR_CTLR_DPG1NS = 1 << 25;
static const uint32_t GICR_CTLR_DPG1S = 1 << 26;
@@ -147,6 +179,8 @@ class Gicv3Redistributor : public Serializable
*/
static const uint32_t ADDR_RANGE_SIZE = 0x40000;
+ static const uint32_t SMALLEST_LPI_ID = 8192;
+
Gicv3Redistributor(Gicv3 * gic, uint32_t cpu_id);
~Gicv3Redistributor();
void init();
@@ -168,6 +202,7 @@ class Gicv3Redistributor : public Serializable
}
bool canBeSelectedFor1toNInterrupt(Gicv3::GroupId group);
+ void setClrLPI(uint64_t data, bool set);
protected:
@@ -178,6 +213,7 @@ class Gicv3Redistributor : public Serializable
Gicv3::GroupId getIntGroup(int int_id);
void activateIRQ(uint32_t int_id);
void deactivateIRQ(uint32_t int_id);
+ void invalLpiConfig(uint32_t lpi_entry_index);
};
#endif //__DEV_ARM_GICV3_REDISTRIBUTOR_H__