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>
This commit is contained in:
Jairo Balart
2019-02-05 10:16:34 +01:00
parent 3264c82489
commit 6a64cc1006
4 changed files with 276 additions and 8 deletions

View File

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

View File

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

View File

@@ -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,12 +649,98 @@ 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;
}
}
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)
{
@@ -704,12 +833,99 @@ 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();
}
}
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()
{
@@ -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);
}

View File

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