arm: bank GIC registers per CPU

Updated according to GICv2 documentation.

Change-Id: I5d926d1abf665eecc43ff0f7d6e561e1ee1c390a
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
This commit is contained in:
Curtis Dunham 2016-08-02 13:35:45 +01:00
parent ae445c0348
commit fc8fd0fd18
3 changed files with 400 additions and 212 deletions

View file

@ -51,15 +51,29 @@
#include "mem/packet.hh"
#include "mem/packet_access.hh"
const AddrRange Pl390::GICD_ISENABLER (0x100, 0x17f);
const AddrRange Pl390::GICD_ICENABLER (0x180, 0x1ff);
const AddrRange Pl390::GICD_ISPENDR (0x200, 0x27f);
const AddrRange Pl390::GICD_ICPENDR (0x280, 0x2ff);
const AddrRange Pl390::GICD_ISACTIVER (0x300, 0x37f);
const AddrRange Pl390::GICD_ICACTIVER (0x380, 0x3ff);
const AddrRange Pl390::GICD_IPRIORITYR(0x400, 0x7ff);
const AddrRange Pl390::GICD_ITARGETSR (0x800, 0xbff);
const AddrRange Pl390::GICD_ICFGR (0xc00, 0xcff);
Pl390::Pl390(const Params *p)
: BaseGic(p), distAddr(p->dist_addr),
cpuAddr(p->cpu_addr), distPioDelay(p->dist_pio_delay),
cpuPioDelay(p->cpu_pio_delay), intLatency(p->int_latency),
enabled(false), itLines(p->it_lines),
haveGem5Extensions(p->gem5_extensions), irqEnable(false)
enabled(false), haveGem5Extensions(p->gem5_extensions),
itLines(p->it_lines),
intEnabled {}, pendingInt {}, activeInt {},
intPriority {}, cpuTarget {}, intConfig {},
cpuSgiPending {}, cpuSgiActive {},
cpuSgiPendingExt {}, cpuSgiActiveExt {},
cpuPpiPending {}, cpuPpiActive {},
irqEnable(false)
{
itLinesLog2 = ceilLog2(itLines);
for (int x = 0; x < CPU_MAX; x++) {
iccrpr[x] = 0xff;
cpuEnabled[x] = false;
@ -72,38 +86,6 @@ Pl390::Pl390(const Params *p)
DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
cpuEnabled[1]);
for (int x = 0; x < INT_BITS_MAX; x++) {
intEnabled[x] = 0;
pendingInt[x] = 0;
activeInt[x] = 0;
}
for (int x = 0; x < INT_LINES_MAX; x++) {
intPriority[x] = 0;
cpuTarget[x] = 0;
}
for (int x = 0; x < INT_BITS_MAX*2; x++) {
intConfig[x] = 0;
}
for (int x = 0; x < SGI_MAX; x++) {
cpuSgiActive[x] = 0;
cpuSgiPending[x] = 0;
}
for (int x = 0; x < CPU_MAX; x++) {
cpuPpiActive[x] = 0;
cpuPpiPending[x] = 0;
cpuSgiActiveExt[x] = 0;
cpuSgiPendingExt[x] = 0;
}
for (int i = 0; i < CPU_MAX; i++) {
for (int j = 0; j < (SGI_MAX + PPI_MAX); j++) {
bankedIntPriority[i][j] = 0;
}
}
gem5ExtensionsEnabled = false;
}
@ -145,63 +127,68 @@ Pl390::readDistributor(PacketPtr pkt)
DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
if (daddr >= GICD_ISENABLER_ST && daddr < GICD_ISENABLER_ED + 4) {
assert((daddr-GICD_ISENABLER_ST) >> 2 < 32);
pkt->set<uint32_t>(intEnabled[(daddr-GICD_ISENABLER_ST)>>2]);
if (GICD_ISENABLER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getIntEnabled(ctx_id, ix));
goto done;
}
if (daddr >= GICD_ICENABLER_ST && daddr < GICD_ICENABLER_ED + 4) {
assert((daddr-GICD_ICENABLER_ST) >> 2 < 32);
pkt->set<uint32_t>(intEnabled[(daddr-GICD_ICENABLER_ST)>>2]);
if (GICD_ICENABLER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getIntEnabled(ctx_id, ix));
goto done;
}
if (daddr >= GICD_ISPENDR_ST && daddr < GICD_ISPENDR_ED + 4) {
assert((daddr-GICD_ISPENDR_ST) >> 2 < 32);
pkt->set<uint32_t>(pendingInt[(daddr-GICD_ISPENDR_ST)>>2]);
if (GICD_ISPENDR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getPendingInt(ctx_id, ix));
goto done;
}
if (daddr >= GICD_ICPENDR_ST && daddr < GICD_ICPENDR_ED + 4) {
assert((daddr-GICD_ICPENDR_ST) >> 2 < 32);
pkt->set<uint32_t>(pendingInt[(daddr-GICD_ICPENDR_ST)>>2]);
if (GICD_ICPENDR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getPendingInt(ctx_id, ix));
goto done;
}
if (daddr >= GICD_ISACTIVER_ST && daddr < GICD_ISACTIVER_ED + 4) {
assert((daddr-GICD_ISACTIVER_ST) >> 2 < 32);
pkt->set<uint32_t>(activeInt[(daddr-GICD_ISACTIVER_ST)>>2]);
if (GICD_ISACTIVER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getPendingInt(ctx_id, ix));
goto done;
}
if (daddr >= GICD_IPRIORITYR_ST && daddr < GICD_IPRIORITYR_ED + 4) {
Addr int_num;
int_num = daddr - GICD_IPRIORITYR_ST;
if (GICD_ICACTIVER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getPendingInt(ctx_id, ix));
goto done;
}
if (GICD_IPRIORITYR.contains(daddr)) {
Addr int_num = daddr - GICD_IPRIORITYR.start();
assert(int_num < INT_LINES_MAX);
DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num);
uint8_t* int_p;
if (int_num < (SGI_MAX + PPI_MAX))
int_p = bankedIntPriority[ctx_id];
else
int_p = intPriority;
switch (pkt->getSize()) {
case 1:
pkt->set<uint8_t>(int_p[int_num]);
pkt->set<uint8_t>(getIntPriority(ctx_id, int_num));
break;
case 2:
assert((int_num + 1) < INT_LINES_MAX);
pkt->set<uint16_t>(int_p[int_num] |
int_p[int_num+1] << 8);
pkt->set<uint16_t>(getIntPriority(ctx_id, int_num) |
getIntPriority(ctx_id, int_num+1) << 8);
break;
case 4:
assert((int_num + 3) < INT_LINES_MAX);
pkt->set<uint32_t>(int_p[int_num] |
int_p[int_num+1] << 8 |
int_p[int_num+2] << 16 |
int_p[int_num+3] << 24);
pkt->set<uint32_t>(getIntPriority(ctx_id, int_num) |
getIntPriority(ctx_id, int_num+1) << 8 |
getIntPriority(ctx_id, int_num+2) << 16 |
getIntPriority(ctx_id, int_num+3) << 24);
break;
default:
panic("Invalid size while reading priority regs in GIC: %d\n",
@ -210,9 +197,8 @@ Pl390::readDistributor(PacketPtr pkt)
goto done;
}
if (daddr >= GICD_ITARGETSR_ST && daddr < GICD_ITARGETSR_ED + 4) {
Addr int_num;
int_num = (daddr-GICD_ITARGETSR_ST) ;
if (GICD_ITARGETSR.contains(daddr)) {
Addr int_num = daddr - GICD_ITARGETSR.start();
DPRINTF(GIC, "Reading processor target register for int# %#x \n",
int_num);
assert(int_num < INT_LINES_MAX);
@ -246,12 +232,12 @@ Pl390::readDistributor(PacketPtr pkt)
goto done;
}
if (daddr >= GICD_ICFGR_ST && daddr < GICD_ICFGR_ED + 4) {
assert((daddr-GICD_ICFGR_ST) >> 2 < 64);
/** @todo software generated interrutps and PPIs
* can't be configured in some ways
*/
pkt->set<uint32_t>(intConfig[(daddr-GICD_ICFGR_ST)>>2]);
if (GICD_ICFGR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
assert(ix < 64);
/** @todo software generated interrupts and PPIs
* can't be configured in some ways */
pkt->set<uint32_t>(intConfig[ix]);
goto done;
}
@ -262,8 +248,7 @@ Pl390::readDistributor(PacketPtr pkt)
case GICD_TYPER: {
/* The 0x100 is a made-up flag to show that gem5 extensions
* are available,
* write 0x200 to this register to enable it.
*/
* write 0x200 to this register to enable it. */
uint32_t tmp = ((sys->numRunningContexts() - 1) << 5) |
(itLines/INT_BITS_MAX -1) |
(haveGem5Extensions ? 0x100 : 0x0);
@ -342,7 +327,8 @@ Pl390::readCpu(PacketPtr pkt)
uint32_t int_num = 1 << intNumToBit(cpuHighestInt[ctx_id]);
activeInt[intNumToWord(cpuHighestInt[ctx_id])] |= int_num;
updateRunPri();
pendingInt[intNumToWord(cpuHighestInt[ctx_id])] &= ~int_num;
getPendingInt(ctx_id, intNumToWord(cpuHighestInt[ctx_id]))
&= ~int_num;
}
DPRINTF(Interrupt,"CPU %d reading IAR.id=%d IAR.cpu=%d, iar=0x%x\n",
@ -399,60 +385,70 @@ Pl390::writeDistributor(PacketPtr pkt)
DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
daddr, pkt->getSize(), pkt_data);
if (daddr >= GICD_ISENABLER_ST && daddr < GICD_ISENABLER_ED + 4) {
assert((daddr-GICD_ISENABLER_ST) >> 2 < 32);
intEnabled[(daddr-GICD_ISENABLER_ST) >> 2] |= pkt->get<uint32_t>();
if (GICD_ISENABLER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
assert(ix < 32);
getIntEnabled(ctx_id, ix) |= pkt->get<uint32_t>();
goto done;
}
if (daddr >= GICD_ICENABLER_ST && daddr < GICD_ICENABLER_ED + 4) {
assert((daddr-GICD_ICENABLER_ST) >> 2 < 32);
intEnabled[(daddr-GICD_ICENABLER_ST) >> 2] &= ~pkt->get<uint32_t>();
if (GICD_ICENABLER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
assert(ix < 32);
getIntEnabled(ctx_id, ix) &= ~pkt->get<uint32_t>();
goto done;
}
if (daddr >= GICD_ISPENDR_ST && daddr < GICD_ISPENDR_ED + 4) {
assert((daddr-GICD_ISPENDR_ST) >> 2 < 32);
pendingInt[(daddr-GICD_ISPENDR_ST) >> 2] |= pkt->get<uint32_t>();
pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
updateIntState((daddr-GICD_ISPENDR_ST) >> 2);
if (GICD_ISPENDR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
auto mask = pkt->get<uint32_t>();
if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
getPendingInt(ctx_id, ix) |= mask;
updateIntState(ix);
goto done;
}
if (daddr >= GICD_ICPENDR_ST && daddr < GICD_ICPENDR_ED + 4) {
assert((daddr-GICD_ICPENDR_ST) >> 2 < 32);
pendingInt[(daddr-GICD_ICPENDR_ST) >> 2] &= ~pkt->get<uint32_t>();
pendingInt[0] &= SGI_MASK; // Don't allow SGIs to be changed
updateIntState((daddr-GICD_ICPENDR_ST) >> 2);
if (GICD_ICPENDR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
auto mask = pkt->get<uint32_t>();
if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
getPendingInt(ctx_id, ix) &= ~mask;
updateIntState(ix);
goto done;
}
if (daddr >= GICD_IPRIORITYR_ST && daddr < GICD_IPRIORITYR_ED + 4) {
Addr int_num = daddr - GICD_IPRIORITYR_ST;
assert(int_num < INT_LINES_MAX);
uint8_t* int_p;
if (int_num < (SGI_MAX + PPI_MAX))
int_p = bankedIntPriority[ctx_id];
else
int_p = intPriority;
uint32_t tmp;
if (GICD_ISACTIVER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
getActiveInt(ctx_id, ix) |= pkt->get<uint32_t>();
goto done;
}
if (GICD_ICACTIVER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
getActiveInt(ctx_id, ix) &= ~pkt->get<uint32_t>();
goto done;
}
if (GICD_IPRIORITYR.contains(daddr)) {
Addr int_num = daddr - GICD_IPRIORITYR.start();
switch(pkt->getSize()) {
case 1:
tmp = pkt->get<uint8_t>();
int_p[int_num] = bits(tmp, 7, 0);
getIntPriority(ctx_id, int_num) = pkt->get<uint8_t>();
break;
case 2:
tmp = pkt->get<uint16_t>();
int_p[int_num] = bits(tmp, 7, 0);
int_p[int_num + 1] = bits(tmp, 15, 8);
case 2: {
auto tmp16 = pkt->get<uint16_t>();
getIntPriority(ctx_id, int_num) = bits(tmp16, 7, 0);
getIntPriority(ctx_id, int_num + 1) = bits(tmp16, 15, 8);
break;
case 4:
tmp = pkt->get<uint32_t>();
int_p[int_num] = bits(tmp, 7, 0);
int_p[int_num + 1] = bits(tmp, 15, 8);
int_p[int_num + 2] = bits(tmp, 23, 16);
int_p[int_num + 3] = bits(tmp, 31, 24);
}
case 4: {
auto tmp32 = pkt->get<uint32_t>();
getIntPriority(ctx_id, int_num) = bits(tmp32, 7, 0);
getIntPriority(ctx_id, int_num + 1) = bits(tmp32, 15, 8);
getIntPriority(ctx_id, int_num + 2) = bits(tmp32, 23, 16);
getIntPriority(ctx_id, int_num + 3) = bits(tmp32, 31, 24);
break;
}
default:
panic("Invalid size when writing to priority regs in Gic: %d\n",
pkt->getSize());
@ -463,9 +459,8 @@ Pl390::writeDistributor(PacketPtr pkt)
goto done;
}
if (daddr >= GICD_ITARGETSR_ST && daddr < GICD_ITARGETSR_ED + 4) {
Addr int_num = (daddr-GICD_ITARGETSR_ST) ;
assert(int_num < INT_LINES_MAX);
if (GICD_ITARGETSR.contains(daddr)) {
Addr int_num = daddr - GICD_ITARGETSR.start();
// First 31 interrupts only target single processor
if (int_num >= SGI_MAX) {
if (pkt->getSize() == 1) {
@ -480,14 +475,15 @@ Pl390::writeDistributor(PacketPtr pkt)
cpuTarget[int_num+2] = bits(tmp, 23, 16);
cpuTarget[int_num+3] = bits(tmp, 31, 24);
}
updateIntState((daddr-GICD_ITARGETSR_ST)>>2);
updateIntState(int_num >> 2);
}
goto done;
}
if (daddr >= GICD_ICFGR_ST && daddr < GICD_ICFGR_ED + 4) {
assert((daddr-GICD_ICFGR_ST) >> 2 < 64);
intConfig[(daddr-GICD_ICFGR_ST)>>2] = pkt->get<uint32_t>();
if (GICD_ICFGR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICFGR.start()) >> 2;
assert(ix < INT_BITS_MAX*2);
intConfig[ix] = pkt->get<uint32_t>();
if (pkt->get<uint32_t>() & NN_CONFIG_MASK)
warn("GIC N:N mode selected and not supported at this time\n");
goto done;
@ -562,10 +558,10 @@ Pl390::writeCpu(PacketPtr pkt)
cpuPpiActive[ctx_id] &= ~int_num;
} else {
uint32_t int_num = 1 << intNumToBit(iar.ack_id);
if (!(activeInt[intNumToWord(iar.ack_id)] & int_num))
if (!(getActiveInt(ctx_id, intNumToWord(iar.ack_id)) & int_num))
warn("Done handling interrupt that isn't active: %d\n",
intNumToBit(iar.ack_id));
activeInt[intNumToWord(iar.ack_id)] &= ~int_num;
getActiveInt(ctx_id, intNumToWord(iar.ack_id)) &= ~int_num;
}
updateRunPri();
DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
@ -580,6 +576,16 @@ Pl390::writeCpu(PacketPtr pkt)
return cpuPioDelay;
}
Pl390::BankedRegs&
Pl390::getBankedRegs(ContextID ctx_id) {
if (bankedRegs.size() <= ctx_id)
bankedRegs.resize(ctx_id + 1);
if (!bankedRegs[ctx_id])
bankedRegs[ctx_id] = new BankedRegs;
return *bankedRegs[ctx_id];
}
void
Pl390::softInt(ContextID ctx_id, SWI swi)
{
@ -676,8 +682,8 @@ Pl390::updateIntState(int hint)
continue;
if ((cpuSgiPending[swi] & genSwiMask(cpu)) ||
(cpuSgiPendingExt[cpu] & (1 << swi)))
if (highest_pri > bankedIntPriority[cpu][swi]) {
highest_pri = bankedIntPriority[cpu][swi];
if (highest_pri > getIntPriority(cpu, swi)) {
highest_pri = getIntPriority(cpu, swi);
highest_int = swi;
}
}
@ -686,8 +692,8 @@ Pl390::updateIntState(int hint)
if (cpuPpiPending[cpu]) {
for (int ppi = 0; ppi < PPI_MAX; ppi++) {
if (cpuPpiPending[cpu] & (1 << ppi))
if (highest_pri > bankedIntPriority[cpu][SGI_MAX + ppi]) {
highest_pri = bankedIntPriority[cpu][SGI_MAX + ppi];
if (highest_pri > getIntPriority(cpu, SGI_MAX + ppi)) {
highest_pri = getIntPriority(cpu, SGI_MAX + ppi);
highest_int = SGI_MAX + ppi;
}
}
@ -696,21 +702,22 @@ Pl390::updateIntState(int hint)
bool mp_sys = sys->numRunningContexts() > 1;
// Check other ints
for (int x = 0; x < (itLines/INT_BITS_MAX); x++) {
if (intEnabled[x] & pendingInt[x]) {
if (getIntEnabled(cpu, x) & getPendingInt(cpu, x)) {
for (int y = 0; y < INT_BITS_MAX; y++) {
uint32_t int_nm = x * INT_BITS_MAX + y;
DPRINTF(GIC, "Checking for interrupt# %d \n",int_nm);
/* Set current pending int as highest int for current cpu
if the interrupt's priority higher than current prioirty
if the interrupt's priority higher than current priority
and if currrent cpu is the target (for mp configs only)
*/
if ((bits(intEnabled[x], y) & bits(pendingInt[x], y)) &&
(intPriority[int_nm] < highest_pri))
if ( (!mp_sys) ||
(!gem5ExtensionsEnabled && (cpuTarget[int_nm] & (1 << cpu))) ||
(gem5ExtensionsEnabled && (cpuTarget[int_nm] == cpu))
) {
highest_pri = intPriority[int_nm];
if ((bits(getIntEnabled(cpu, x), y)
&bits(getPendingInt(cpu, x), y)) &&
(getIntPriority(cpu, int_nm) < highest_pri))
if ((!mp_sys) ||
(gem5ExtensionsEnabled
? (cpuTarget[int_nm] == cpu)
: (cpuTarget[int_nm] & (1 << cpu)))) {
highest_pri = getIntPriority(cpu, int_nm);
highest_int = int_nm;
}
}
@ -725,8 +732,8 @@ Pl390::updateIntState(int hint)
/* @todo make this work for more than one cpu, need to handle 1:N, N:N
* models */
if (enabled && cpuEnabled[cpu] && (highest_pri < cpuPriority[cpu]) &&
!(activeInt[intNumToWord(highest_int)]
& (1 << intNumToBit(highest_int)))) {
!(getActiveInt(cpu, intNumToWord(highest_int))
& (1 << intNumToBit(highest_int)))) {
DPRINTF(Interrupt, "Posting interrupt %d to cpu%d\n", highest_int,
cpu);
@ -742,21 +749,22 @@ Pl390::updateRunPri()
if (!cpuEnabled[cpu])
continue;
uint8_t maxPriority = 0xff;
for (int i = 0; i < itLines; i++){
for (int i = 0; i < itLines; i++) {
if (i < SGI_MAX) {
if (((cpuSgiActive[i] & genSwiMask(cpu)) ||
(cpuSgiActiveExt[cpu] & (1 << i))) &&
(bankedIntPriority[cpu][i] < maxPriority))
maxPriority = bankedIntPriority[cpu][i];
(getIntPriority(cpu, i) < maxPriority))
maxPriority = getIntPriority(cpu, i);
} else if (i < (SGI_MAX + PPI_MAX)) {
if ((cpuPpiActive[cpu] & ( 1 << (i - SGI_MAX))) &&
(bankedIntPriority[cpu][i] < maxPriority))
maxPriority = bankedIntPriority[cpu][i];
(getIntPriority(cpu, i) < maxPriority))
maxPriority = getIntPriority(cpu, i);
} else {
if (activeInt[intNumToWord(i)] & (1 << intNumToBit(i)))
if (intPriority[i] < maxPriority)
maxPriority = intPriority[i];
if (getActiveInt(cpu, intNumToWord(i))
& (1 << intNumToBit(i)))
if (getIntPriority(cpu, i) < maxPriority)
maxPriority = getIntPriority(cpu, i);
}
}
iccrpr[cpu] = maxPriority;
@ -770,9 +778,10 @@ Pl390::sendInt(uint32_t num)
num, cpuTarget[num]);
if ((cpuTarget[num] & (cpuTarget[num] - 1)) && !gem5ExtensionsEnabled)
panic("Multiple targets for peripheral interrupts is not supported\n");
pendingInt[intNumToWord(num)] |= 1 << intNumToBit(num);
panic_if(num < SGI_MAX + PPI_MAX,
"sentInt() must only be used for interrupts 32 and higher");
getPendingInt(cpuTarget[num], intNumToWord(num)) |= 1 << intNumToBit(num);
updateIntState(intNumToWord(num));
}
void
@ -827,13 +836,12 @@ Pl390::serialize(CheckpointOut &cp) const
SERIALIZE_SCALAR(cpuPioDelay);
SERIALIZE_SCALAR(enabled);
SERIALIZE_SCALAR(itLines);
SERIALIZE_SCALAR(itLinesLog2);
SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
SERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
SERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
SERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
SERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
SERIALIZE_ARRAY(iccrpr, CPU_MAX);
SERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
SERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
SERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
SERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
SERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
SERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
SERIALIZE_ARRAY(cpuPriority, CPU_MAX);
@ -845,7 +853,6 @@ Pl390::serialize(CheckpointOut &cp) const
SERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
SERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
SERIALIZE_SCALAR(irqEnable);
Tick interrupt_time[CPU_MAX];
for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
@ -856,6 +863,22 @@ Pl390::serialize(CheckpointOut &cp) const
}
SERIALIZE_ARRAY(interrupt_time, CPU_MAX);
SERIALIZE_SCALAR(gem5ExtensionsEnabled);
for (uint32_t i=0; i < bankedRegs.size(); ++i) {
if (!bankedRegs[i])
continue;
bankedRegs[i]->serializeSection(cp, csprintf("bankedRegs%i", i));
}
}
void
Pl390::BankedRegs::serialize(CheckpointOut &cp) const
{
SERIALIZE_SCALAR(intEnabled);
SERIALIZE_SCALAR(pendingInt);
SERIALIZE_SCALAR(activeInt);
SERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
SERIALIZE_ARRAY(cpuTarget, SGI_MAX + PPI_MAX);
}
void
@ -869,13 +892,12 @@ Pl390::unserialize(CheckpointIn &cp)
UNSERIALIZE_SCALAR(cpuPioDelay);
UNSERIALIZE_SCALAR(enabled);
UNSERIALIZE_SCALAR(itLines);
UNSERIALIZE_SCALAR(itLinesLog2);
UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX);
UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX);
UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX);
UNSERIALIZE_ARRAY(intEnabled, INT_BITS_MAX-1);
UNSERIALIZE_ARRAY(pendingInt, INT_BITS_MAX-1);
UNSERIALIZE_ARRAY(activeInt, INT_BITS_MAX-1);
UNSERIALIZE_ARRAY(iccrpr, CPU_MAX);
UNSERIALIZE_ARRAY(intPriority, INT_LINES_MAX);
UNSERIALIZE_ARRAY(cpuTarget, INT_LINES_MAX);
UNSERIALIZE_ARRAY(intPriority, GLOBAL_INT_LINES);
UNSERIALIZE_ARRAY(cpuTarget, GLOBAL_INT_LINES);
UNSERIALIZE_ARRAY(intConfig, INT_BITS_MAX * 2);
UNSERIALIZE_ARRAY(cpuEnabled, CPU_MAX);
UNSERIALIZE_ARRAY(cpuPriority, CPU_MAX);
@ -887,7 +909,6 @@ Pl390::unserialize(CheckpointIn &cp)
UNSERIALIZE_ARRAY(cpuSgiPendingExt, CPU_MAX);
UNSERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
UNSERIALIZE_ARRAY(*bankedIntPriority, CPU_MAX * (SGI_MAX + PPI_MAX));
UNSERIALIZE_SCALAR(irqEnable);
Tick interrupt_time[CPU_MAX];
@ -899,6 +920,23 @@ Pl390::unserialize(CheckpointIn &cp)
}
if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled))
gem5ExtensionsEnabled = false;
for (uint32_t i=0; i < CPU_MAX; ++i) {
ScopedCheckpointSection sec(cp, csprintf("bankedRegs%i", i));
if (cp.sectionExists(Serializable::currentSection())) {
getBankedRegs(i).unserialize(cp);
}
}
}
void
Pl390::BankedRegs::unserialize(CheckpointIn &cp)
{
UNSERIALIZE_SCALAR(intEnabled);
UNSERIALIZE_SCALAR(pendingInt);
UNSERIALIZE_SCALAR(activeInt);
UNSERIALIZE_ARRAY(intPriority, SGI_MAX + PPI_MAX);
UNSERIALIZE_ARRAY(cpuTarget, SGI_MAX + PPI_MAX);
}
Pl390 *
@ -909,10 +947,10 @@ Pl390Params::create()
/* Functions for debugging and testing */
void
Pl390::driveSPI(unsigned int spiVect)
Pl390::driveSPI(uint32_t spiVect)
{
DPRINTF(GIC, "Received SPI Vector:%x Enable: %d\n", spiVect, irqEnable);
pendingInt[1] |= spiVect;
getPendingInt(0, 1) |= spiVect;
if (irqEnable && enabled) {
updateIntState(-1);
}

View file

@ -42,12 +42,15 @@
/** @file
* Implementiation of a PL390 GIC
* Implementation of a PL390 GIC
*/
#ifndef __DEV_ARM_GIC_PL390_H__
#define __DEV_ARM_GIC_PL390_H__
#include <vector>
#include "base/addr_range.hh"
#include "base/bitunion.hh"
#include "cpu/intr_control.hh"
#include "dev/arm/base_gic.hh"
@ -55,12 +58,6 @@
#include "dev/platform.hh"
#include "params/Pl390.hh"
/** @todo this code only assumes one processor for now. Low word
* of intEnabled and pendingInt need to be replicated per CPU.
* bottom 31 interrupts (7 words) need to be replicated for
* for interrupt priority register, processor target registers
* interrupt config registers */
class Pl390 : public BaseGic
{
protected:
@ -69,28 +66,22 @@ class Pl390 : public BaseGic
GICD_CTLR = 0x000, // control register
GICD_TYPER = 0x004, // controller type
GICD_IIDR = 0x008, // implementer id
GICD_ISENABLER_ST = 0x100, // interrupt set enable
GICD_ISENABLER_ED = 0x17c,
GICD_ICENABLER_ST = 0x180, // interrupt clear enable
GICD_ICENABLER_ED = 0x1fc,
GICD_ISPENDR_ST = 0x200, // set pending interrupt
GICD_ISPENDR_ED = 0x27c,
GICD_ICPENDR_ST = 0x280, // clear pending interrupt
GICD_ICPENDR_ED = 0x2fc,
GICD_ISACTIVER_ST = 0x300, // active bit registers
GICD_ISACTIVER_ED = 0x37c,
GICD_IPRIORITYR_ST = 0x400, // interrupt priority registers
GICD_IPRIORITYR_ED = 0x7f8,
GICD_ITARGETSR_ST = 0x800, // processor target registers
GICD_ITARGETSR_ED = 0xbf8,
GICD_ICFGR_ST = 0xc00, // interrupt config registers
GICD_ICFGR_ED = 0xcfc,
GICD_SGIR = 0xf00, // software generated interrupt
DIST_SIZE = 0xfff
};
// cpu memory addressesa
static const AddrRange GICD_ISENABLER; // interrupt set enable
static const AddrRange GICD_ICENABLER; // interrupt clear enable
static const AddrRange GICD_ISPENDR; // set pending interrupt
static const AddrRange GICD_ICPENDR; // clear pending interrupt
static const AddrRange GICD_ISACTIVER; // active bit registers
static const AddrRange GICD_ICACTIVER; // clear bit registers
static const AddrRange GICD_IPRIORITYR; // interrupt priority registers
static const AddrRange GICD_ITARGETSR; // processor target registers
static const AddrRange GICD_ICFGR; // interrupt config registers
// cpu memory addresses
enum {
GICC_CTLR = 0x00, // CPU control register
GICC_PMR = 0x04, // Interrupt priority mask
@ -118,6 +109,7 @@ class Pl390 : public BaseGic
static const int SPURIOUS_INT = 1023;
static const int INT_BITS_MAX = 32;
static const int INT_LINES_MAX = 1020;
static const int GLOBAL_INT_LINES = INT_LINES_MAX - SGI_MAX - PPI_MAX;
BitUnion32(SWI)
Bitfield<3,0> sgi_id;
@ -149,41 +141,121 @@ class Pl390 : public BaseGic
/** Gic enabled */
bool enabled;
/** Are gem5 extensions available? */
const bool haveGem5Extensions;
/** gem5 many-core extension enabled by driver */
bool gem5ExtensionsEnabled;
/** Number of itLines enabled */
uint32_t itLines;
uint32_t itLinesLog2;
/** Registers "banked for each connected processor" per ARM IHI0048B */
struct BankedRegs : public Serializable {
/** GICD_I{S,C}ENABLER0
* interrupt enable bits for first 32 interrupts, 1b per interrupt */
uint32_t intEnabled;
/** Are gem5 extensions available? */
const bool haveGem5Extensions;
/** GICD_I{S,C}PENDR0
* interrupt pending bits for first 32 interrupts, 1b per interrupt */
uint32_t pendingInt;
/** interrupt enable bits for all possible 1020 interupts.
* one bit per interrupt, 32 bit per word = 32 words */
uint32_t intEnabled[INT_BITS_MAX];
/** GICD_I{S,C}ACTIVER0
* interrupt active bits for first 32 interrupts, 1b per interrupt */
uint32_t activeInt;
/** interrupt pending bits for all possible 1020 interupts.
* one bit per interrupt, 32 bit per word = 32 words */
uint32_t pendingInt[INT_BITS_MAX];
/** GICD_IPRIORITYR{0..7}
* interrupt priority for SGIs and PPIs */
uint8_t intPriority[SGI_MAX + PPI_MAX];
/** interrupt active bits for all possible 1020 interupts.
* one bit per interrupt, 32 bit per word = 32 words */
uint32_t activeInt[INT_BITS_MAX];
/** GICD_ITARGETSR{0..7}
* 8b CPU target ID for each SGI and PPI */
uint8_t cpuTarget[SGI_MAX + PPI_MAX];
/** read only running priroity register, 1 per cpu*/
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;
BankedRegs() :
intEnabled(0), pendingInt(0), activeInt(0),
intPriority {0}, cpuTarget {0}
{}
};
std::vector<BankedRegs*> bankedRegs;
BankedRegs& getBankedRegs(ContextID);
/** GICD_I{S,C}ENABLER{1..31}
* interrupt enable bits for global interrupts
* 1b per interrupt, 32 bits per word, 31 words */
uint32_t intEnabled[INT_BITS_MAX-1];
uint32_t& getIntEnabled(ContextID ctx_id, uint32_t ix) {
if (ix == 0) {
return getBankedRegs(ctx_id).intEnabled;
} else {
return intEnabled[ix - 1];
}
}
/** GICD_I{S,C}PENDR{1..31}
* interrupt pending bits for global interrupts
* 1b per interrupt, 32 bits per word, 31 words */
uint32_t pendingInt[INT_BITS_MAX-1];
uint32_t& getPendingInt(ContextID ctx_id, uint32_t ix) {
assert(ix < INT_BITS_MAX);
if (ix == 0) {
return getBankedRegs(ctx_id).pendingInt;
} else {
return pendingInt[ix - 1];
}
}
/** GICD_I{S,C}ACTIVER{1..31}
* interrupt active bits for global interrupts
* 1b per interrupt, 32 bits per word, 31 words */
uint32_t activeInt[INT_BITS_MAX-1];
uint32_t& getActiveInt(ContextID ctx_id, uint32_t ix) {
assert(ix < INT_BITS_MAX);
if (ix == 0) {
return getBankedRegs(ctx_id).activeInt;
} else {
return activeInt[ix - 1];
}
}
/** read only running priority register, 1 per cpu*/
uint32_t iccrpr[CPU_MAX];
/** an 8 bit priority (lower is higher priority) for each
* of the 1020 possible supported interrupts.
/** GICD_IPRIORITYR{8..255}
* an 8 bit priority (lower is higher priority) for each
* of the global (not replicated per CPU) interrupts.
*/
uint8_t intPriority[INT_LINES_MAX];
uint8_t intPriority[GLOBAL_INT_LINES];
/** an 8 bit cpu target id for each shared peripheral interrupt
* of the 1020 possible supported interrupts.
uint8_t& getIntPriority(ContextID ctx_id, uint32_t ix) {
assert(ix < INT_LINES_MAX);
if (ix < SGI_MAX + PPI_MAX) {
return getBankedRegs(ctx_id).intPriority[ix];
} else {
return intPriority[ix - (SGI_MAX + PPI_MAX)];
}
}
/** GICD_ITARGETSR{8..255}
* an 8 bit cpu target id for each global interrupt.
*/
uint8_t cpuTarget[INT_LINES_MAX];
uint8_t cpuTarget[GLOBAL_INT_LINES];
uint8_t& getCpuTarget(ContextID ctx_id, uint32_t ix) {
assert(ix < INT_LINES_MAX);
if (ix < SGI_MAX + PPI_MAX) {
return getBankedRegs(ctx_id).cpuTarget[ix];
} else {
return cpuTarget[ix - (SGI_MAX + PPI_MAX)];
}
}
/** 2 bit per interrupt signaling if it's level or edge sensitive
* and if it is 1:N or N:N */
@ -219,9 +291,6 @@ class Pl390 : public BaseGic
uint32_t cpuPpiPending[CPU_MAX];
uint32_t cpuPpiActive[CPU_MAX];
/** Banked interrupt prioirty registers for SGIs and PPIs */
uint8_t bankedIntPriority[CPU_MAX][SGI_MAX + PPI_MAX];
/** IRQ Enable Used for debug */
bool irqEnable;

View file

@ -0,0 +1,81 @@
# Copyright (c) 2016 ARM Limited
# All rights reserved
#
# The license below extends only to copyright in the software and shall
# not be construed as granting a license to any other intellectual
# property including but not limited to intellectual property relating
# to a hardware implementation of the functionality of the software
# licensed hereunder. You may use the software subject to the license
# terms below provided that you ensure that this notice is replicated
# unmodified and in its entirety in all distributions of the software,
# modified or unmodified, in source code or in binary form.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met: redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer;
# redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution;
# neither the name of the copyright holders nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# duplicate banked registers into new per-cpu arrays.
def upgrader(cpt):
if cpt.get('root','isa') == 'arm':
for sec in cpt.sections():
import re
if not re.search('\.gic$', sec):
continue
cpuEnabled = cpt.get(sec, 'cpuEnabled' ).split()
intEnabled = cpt.get(sec, 'intEnabled' ).split()
pendingInt = cpt.get(sec, 'pendingInt' ).split()
activeInt = cpt.get(sec, 'activeInt' ).split()
intPriority = cpt.get(sec, 'intPriority').split()
cpuTarget = cpt.get(sec, 'cpuTarget' ).split()
b_intEnabled = intEnabled[0]
b_pendingInt = pendingInt[0]
b_activeInt = activeInt[0]
b_cpuTarget = cpuTarget[0:32]
del intEnabled[0]
del pendingInt[0]
del activeInt[0]
del intPriority[0:32] # unused; overlapped with bankedIntPriority
del cpuTarget[0:32]
cpt.set(sec, 'intEnabled', ' '.join(intEnabled))
cpt.set(sec, 'pendingInt', ' '.join(pendingInt))
cpt.set(sec, 'activeInt', ' '.join(activeInt))
cpt.set(sec, 'intPriority',' '.join(intPriority))
cpt.set(sec, 'cpuTarget', ' '.join(cpuTarget))
b_intPriority = cpt.get(sec, '*bankedIntPriority').split()
cpt.remove_option(sec, '*bankedIntPriority')
for cpu in xrange(0, 255):
if cpuEnabled[cpu] == 'true':
intPriority = b_intPriority[cpu*32 : (cpu+1)*32]
new_sec = "%s.bankedRegs%u" % (sec, cpu)
cpt.add_section(new_sec)
cpt.set(new_sec, 'intEnabled', b_intEnabled)
cpt.set(new_sec, 'pendingInt', b_pendingInt)
cpt.set(new_sec, 'activeInt', b_activeInt)
cpt.set(new_sec, 'intPriority',' '.join(intPriority))
cpt.set(new_sec, 'cpuTarget', ' '.join(b_cpuTarget))