arm: refactor packet processing in Pl390 GIC

Change-Id: I696703418506522ba90df5c2c4ca45c95a6efbea
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/2441
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Weiping Liao <weipingliao@google.com>
This commit is contained in:
Curtis Dunham 2017-01-27 20:16:23 +00:00 committed by Andreas Sandberg
parent 3384caf0fe
commit bbdd34d628
2 changed files with 138 additions and 117 deletions

View file

@ -129,46 +129,64 @@ Pl390::readDistributor(PacketPtr pkt)
DPRINTF(GIC, "gic distributor read register %#x\n", daddr);
const uint32_t resp = readDistributor(ctx, daddr, pkt->getSize());
switch (pkt->getSize()) {
case 1:
pkt->set<uint8_t>(resp);
break;
case 2:
pkt->set<uint16_t>(resp);
break;
case 4:
pkt->set<uint32_t>(resp);
break;
default:
panic("Invalid size while reading Distributor regs in GIC: %d\n",
pkt->getSize());
}
pkt->makeAtomicResponse();
return distPioDelay;
}
uint32_t
Pl390::readDistributor(ContextID ctx, Addr daddr, size_t resp_sz)
{
if (GICD_ISENABLER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getIntEnabled(ctx, ix));
goto done;
return getIntEnabled(ctx, ix);
}
if (GICD_ICENABLER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getIntEnabled(ctx, ix));
goto done;
return getIntEnabled(ctx, ix);
}
if (GICD_ISPENDR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getPendingInt(ctx, ix));
goto done;
return getPendingInt(ctx, ix);
}
if (GICD_ICPENDR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getPendingInt(ctx, ix));
goto done;
return getPendingInt(ctx, ix);
}
if (GICD_ISACTIVER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getActiveInt(ctx, ix));
goto done;
return getActiveInt(ctx, ix);
}
if (GICD_ICACTIVER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
assert(ix < 32);
pkt->set<uint32_t>(getActiveInt(ctx, ix));
goto done;
return getActiveInt(ctx, ix);
}
if (GICD_IPRIORITYR.contains(daddr)) {
@ -176,27 +194,21 @@ Pl390::readDistributor(PacketPtr pkt)
assert(int_num < INT_LINES_MAX);
DPRINTF(Interrupt, "Reading interrupt priority at int# %#x \n",int_num);
switch (pkt->getSize()) {
switch (resp_sz) {
default: // will panic() after return to caller anyway
case 1:
pkt->set<uint8_t>(getIntPriority(ctx, int_num));
break;
return getIntPriority(ctx, int_num);
case 2:
assert((int_num + 1) < INT_LINES_MAX);
pkt->set<uint16_t>(getIntPriority(ctx, int_num) |
getIntPriority(ctx, int_num+1) << 8);
break;
return (getIntPriority(ctx, int_num) |
getIntPriority(ctx, int_num+1) << 8);
case 4:
assert((int_num + 3) < INT_LINES_MAX);
pkt->set<uint32_t>(getIntPriority(ctx, int_num) |
getIntPriority(ctx, int_num+1) << 8 |
getIntPriority(ctx, int_num+2) << 16 |
getIntPriority(ctx, int_num+3) << 24);
break;
default:
panic("Invalid size while reading priority regs in GIC: %d\n",
pkt->getSize());
return (getIntPriority(ctx, int_num) |
getIntPriority(ctx, int_num+1) << 8 |
getIntPriority(ctx, int_num+2) << 16 |
getIntPriority(ctx, int_num+3) << 24);
}
goto done;
}
if (GICD_ITARGETSR.contains(daddr)) {
@ -207,15 +219,15 @@ Pl390::readDistributor(PacketPtr pkt)
// First 31 interrupts only target single processor (SGI)
if (int_num > 31) {
if (pkt->getSize() == 1) {
pkt->set<uint8_t>(cpuTarget[int_num]);
if (resp_sz == 1) {
return cpuTarget[int_num];
} else {
assert(pkt->getSize() == 4);
assert(resp_sz == 4);
int_num = mbits(int_num, 31, 2);
pkt->set<uint32_t>(cpuTarget[int_num] |
cpuTarget[int_num+1] << 8 |
cpuTarget[int_num+2] << 16 |
cpuTarget[int_num+3] << 24) ;
return (cpuTarget[int_num] |
cpuTarget[int_num+1] << 8 |
cpuTarget[int_num+2] << 16 |
cpuTarget[int_num+3] << 24) ;
}
} else {
assert(ctx < sys->numRunningContexts());
@ -229,9 +241,8 @@ Pl390::readDistributor(PacketPtr pkt)
// replicate the 8-bit mask 4 times in a 32-bit word
ctx_mask |= ctx_mask << 8;
ctx_mask |= ctx_mask << 16;
pkt->set<uint32_t>(ctx_mask);
return ctx_mask;
}
goto done;
}
if (GICD_ICFGR.contains(daddr)) {
@ -239,30 +250,23 @@ Pl390::readDistributor(PacketPtr pkt)
assert(ix < 64);
/** @todo software generated interrupts and PPIs
* can't be configured in some ways */
pkt->set<uint32_t>(intConfig[ix]);
goto done;
return intConfig[ix];
}
switch(daddr) {
case GICD_CTLR:
pkt->set<uint32_t>(enabled);
break;
case GICD_TYPER: {
return enabled;
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. */
uint32_t tmp = ((sys->numRunningContexts() - 1) << 5) |
(itLines/INT_BITS_MAX -1) |
(haveGem5Extensions ? 0x100 : 0x0);
pkt->set<uint32_t>(tmp);
} break;
return (((sys->numRunningContexts() - 1) << 5) |
(itLines/INT_BITS_MAX -1) |
(haveGem5Extensions ? 0x100 : 0x0));
default:
panic("Tried to read Gic distributor at offset %#x\n", daddr);
break;
}
done:
pkt->makeAtomicResponse();
return distPioDelay;
}
Tick
@ -277,19 +281,24 @@ Pl390::readCpu(PacketPtr pkt)
DPRINTF(GIC, "gic cpu read register %#x cpu context: %d\n", daddr,
ctx);
pkt->set<uint32_t>(readCpu(ctx, daddr));
pkt->makeAtomicResponse();
return cpuPioDelay;
}
uint32_t
Pl390::readCpu(ContextID ctx, Addr daddr)
{
switch(daddr) {
case GICC_IIDR:
pkt->set<uint32_t>(0);
break;
return 0;
case GICC_CTLR:
pkt->set<uint32_t>(cpuEnabled[ctx]);
break;
return cpuEnabled[ctx];
case GICC_PMR:
pkt->set<uint32_t>(cpuPriority[ctx]);
break;
return cpuPriority[ctx];
case GICC_BPR:
pkt->set<uint32_t>(cpuBpr[ctx]);
break;
return cpuBpr[ctx];
case GICC_IAR:
if (enabled && cpuEnabled[ctx]) {
int active_int = cpuHighestInt[ctx];
@ -337,26 +346,22 @@ Pl390::readCpu(PacketPtr pkt)
ctx, iar.ack_id, iar.cpu_id, iar);
cpuHighestInt[ctx] = SPURIOUS_INT;
updateIntState(-1);
pkt->set<uint32_t>(iar);
platform->intrctrl->clear(ctx, ArmISA::INT_IRQ, 0);
return iar;
} else {
pkt->set<uint32_t>(SPURIOUS_INT);
return SPURIOUS_INT;
}
break;
case GICC_RPR:
pkt->set<uint32_t>(iccrpr[0]);
break;
return iccrpr[0];
case GICC_HPPIR:
pkt->set<uint32_t>(0);
panic("Need to implement HPIR");
break;
default:
panic("Tried to read Gic cpu at offset %#x\n", daddr);
break;
}
pkt->makeAtomicResponse();
return cpuPioDelay;
}
Tick
@ -366,9 +371,10 @@ Pl390::writeDistributor(PacketPtr pkt)
assert(pkt->req->hasContextId());
const ContextID ctx = pkt->req->contextId();
const size_t data_sz = pkt->getSize();
uint32_t pkt_data M5_VAR_USED;
switch (pkt->getSize())
switch (data_sz)
{
case 1:
pkt_data = pkt->get<uint8_t>();
@ -381,97 +387,104 @@ Pl390::writeDistributor(PacketPtr pkt)
break;
default:
panic("Invalid size when writing to priority regs in Gic: %d\n",
pkt->getSize());
data_sz);
}
DPRINTF(GIC, "gic distributor write register %#x size %#x value %#x \n",
daddr, pkt->getSize(), pkt_data);
daddr, data_sz, pkt_data);
writeDistributor(ctx, daddr, pkt_data, data_sz);
pkt->makeAtomicResponse();
return distPioDelay;
}
void
Pl390::writeDistributor(ContextID ctx, Addr daddr, uint32_t data,
size_t data_sz)
{
if (GICD_ISENABLER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISENABLER.start()) >> 2;
assert(ix < 32);
getIntEnabled(ctx, ix) |= pkt->get<uint32_t>();
goto done;
getIntEnabled(ctx, ix) |= data;
return;
}
if (GICD_ICENABLER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICENABLER.start()) >> 2;
assert(ix < 32);
getIntEnabled(ctx, ix) &= ~pkt->get<uint32_t>();
goto done;
getIntEnabled(ctx, ix) &= ~data;
return;
}
if (GICD_ISPENDR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISPENDR.start()) >> 2;
auto mask = pkt->get<uint32_t>();
auto mask = data;
if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
getPendingInt(ctx, ix) |= mask;
updateIntState(ix);
goto done;
return;
}
if (GICD_ICPENDR.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICPENDR.start()) >> 2;
auto mask = pkt->get<uint32_t>();
auto mask = data;
if (ix == 0) mask &= SGI_MASK; // Don't allow SGIs to be changed
getPendingInt(ctx, ix) &= ~mask;
updateIntState(ix);
goto done;
return;
}
if (GICD_ISACTIVER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ISACTIVER.start()) >> 2;
getActiveInt(ctx, ix) |= pkt->get<uint32_t>();
goto done;
getActiveInt(ctx, ix) |= data;
return;
}
if (GICD_ICACTIVER.contains(daddr)) {
uint32_t ix = (daddr - GICD_ICACTIVER.start()) >> 2;
getActiveInt(ctx, ix) &= ~pkt->get<uint32_t>();
goto done;
getActiveInt(ctx, ix) &= ~data;
return;
}
if (GICD_IPRIORITYR.contains(daddr)) {
Addr int_num = daddr - GICD_IPRIORITYR.start();
switch(pkt->getSize()) {
switch(data_sz) {
case 1:
getIntPriority(ctx, int_num) = pkt->get<uint8_t>();
getIntPriority(ctx, int_num) = data;
break;
case 2: {
auto tmp16 = pkt->get<uint16_t>();
getIntPriority(ctx, int_num) = bits(tmp16, 7, 0);
getIntPriority(ctx, int_num + 1) = bits(tmp16, 15, 8);
getIntPriority(ctx, int_num) = bits(data, 7, 0);
getIntPriority(ctx, int_num + 1) = bits(data, 15, 8);
break;
}
case 4: {
auto tmp32 = pkt->get<uint32_t>();
getIntPriority(ctx, int_num) = bits(tmp32, 7, 0);
getIntPriority(ctx, int_num + 1) = bits(tmp32, 15, 8);
getIntPriority(ctx, int_num + 2) = bits(tmp32, 23, 16);
getIntPriority(ctx, int_num + 3) = bits(tmp32, 31, 24);
getIntPriority(ctx, int_num) = bits(data, 7, 0);
getIntPriority(ctx, int_num + 1) = bits(data, 15, 8);
getIntPriority(ctx, int_num + 2) = bits(data, 23, 16);
getIntPriority(ctx, int_num + 3) = bits(data, 31, 24);
break;
}
default:
panic("Invalid size when writing to priority regs in Gic: %d\n",
pkt->getSize());
data_sz);
}
updateIntState(-1);
updateRunPri();
goto done;
return;
}
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) {
uint8_t tmp = pkt->get<uint8_t>();
cpuTarget[int_num] = tmp & 0xff;
if (data_sz == 1) {
cpuTarget[int_num] = data & 0xff;
} else {
assert (pkt->getSize() == 4);
assert (data_sz == 4);
int_num = mbits(int_num, 31, 2);
uint32_t tmp = pkt->get<uint32_t>();
uint32_t tmp = data;
cpuTarget[int_num] = bits(tmp, 7, 0);
cpuTarget[int_num+1] = bits(tmp, 15, 8);
cpuTarget[int_num+2] = bits(tmp, 23, 16);
@ -479,43 +492,38 @@ Pl390::writeDistributor(PacketPtr pkt)
}
updateIntState(int_num >> 2);
}
goto done;
return;
}
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)
intConfig[ix] = data;
if (data & NN_CONFIG_MASK)
warn("GIC N:N mode selected and not supported at this time\n");
goto done;
return;
}
switch(daddr) {
case GICD_CTLR:
enabled = pkt->get<uint32_t>();
enabled = data;
DPRINTF(Interrupt, "Distributor enable flag set to = %d\n", enabled);
break;
case GICD_TYPER:
/* 0x200 is a made-up flag to enable gem5 extension functionality.
* This reg is not normally written.
*/
gem5ExtensionsEnabled = (
(pkt->get<uint32_t>() & 0x200) && haveGem5Extensions);
gem5ExtensionsEnabled = (data & 0x200) && haveGem5Extensions;
DPRINTF(GIC, "gem5 extensions %s\n",
gem5ExtensionsEnabled ? "enabled" : "disabled");
break;
case GICD_SGIR:
softInt(ctx, pkt->get<uint32_t>());
softInt(ctx, data);
break;
default:
panic("Tried to write Gic distributor at offset %#x\n", daddr);
break;
}
done:
pkt->makeAtomicResponse();
return distPioDelay;
}
Tick
@ -525,23 +533,32 @@ Pl390::writeCpu(PacketPtr pkt)
assert(pkt->req->hasContextId());
const ContextID ctx = pkt->req->contextId();
IAR iar;
const uint32_t data = pkt->get<uint32_t>();
DPRINTF(GIC, "gic cpu write register cpu:%d %#x val: %#x\n",
ctx, daddr, pkt->get<uint32_t>());
ctx, daddr, data);
writeCpu(ctx, daddr, data);
pkt->makeAtomicResponse();
return cpuPioDelay;
}
void
Pl390::writeCpu(ContextID ctx, Addr daddr, uint32_t data)
{
switch(daddr) {
case GICC_CTLR:
cpuEnabled[ctx] = pkt->get<uint32_t>();
cpuEnabled[ctx] = data;
break;
case GICC_PMR:
cpuPriority[ctx] = pkt->get<uint32_t>();
cpuPriority[ctx] = data;
break;
case GICC_BPR:
cpuBpr[ctx] = pkt->get<uint32_t>();
cpuBpr[ctx] = data;
break;
case GICC_EOIR:
iar = pkt->get<uint32_t>();
case GICC_EOIR: {
const IAR iar = data;
if (iar.ack_id < SGI_MAX) {
// Clear out the bit that corresponds to the cleared int
uint64_t clr_int = ULL(1) << (ctx + 8 * iar.cpu_id);
@ -569,13 +586,12 @@ Pl390::writeCpu(PacketPtr pkt)
DPRINTF(Interrupt, "CPU %d done handling intr IAR = %d from cpu %d\n",
ctx, iar.ack_id, iar.cpu_id);
break;
}
default:
panic("Tried to write Gic cpu at offset %#x\n", daddr);
break;
}
if (cpuEnabled[ctx]) updateIntState(-1);
pkt->makeAtomicResponse();
return cpuPioDelay;
}
Pl390::BankedRegs&

View file

@ -393,21 +393,26 @@ class Pl390 : public BaseGic
* @param pkt packet to respond to
*/
Tick readDistributor(PacketPtr pkt);
uint32_t readDistributor(ContextID ctx, Addr daddr, size_t resp_sz);
/** Handle a read to the cpu portion of the GIC
* @param pkt packet to respond to
*/
Tick readCpu(PacketPtr pkt);
uint32_t readCpu(ContextID ctx, Addr daddr);
/** Handle a write to the distributor portion of the GIC
* @param pkt packet to respond to
*/
Tick writeDistributor(PacketPtr pkt);
void writeDistributor(ContextID ctx, Addr daddr, uint32_t data,
size_t data_sz);
/** Handle a write to the cpu portion of the GIC
* @param pkt packet to respond to
*/
Tick writeCpu(PacketPtr pkt);
void writeCpu(ContextID ctx, Addr daddr, uint32_t data);
};
#endif //__DEV_ARM_GIC_H__