summaryrefslogtreecommitdiff
path: root/src/cpu
diff options
context:
space:
mode:
authorMitch Hayenga <mitch.hayenga@arm.com>2015-09-30 11:14:19 -0500
committerMitch Hayenga <mitch.hayenga@arm.com>2015-09-30 11:14:19 -0500
commita5c4eb3de9deb3a71a6a5230a25ff5962e584980 (patch)
tree874b659c6a5eaa1316cde9eb82ec7d08badf638a /src/cpu
parente255fa053f8d105de8d188077a318124a3aad9ce (diff)
downloadgem5-a5c4eb3de9deb3a71a6a5230a25ff5962e584980.tar.xz
isa,cpu: Add support for FS SMT Interrupts
Adds per-thread interrupt controllers and thread/context logic so that interrupts properly get routed in SMT systems.
Diffstat (limited to 'src/cpu')
-rw-r--r--src/cpu/BaseCPU.py40
-rw-r--r--src/cpu/base.cc17
-rw-r--r--src/cpu/base.hh24
-rw-r--r--src/cpu/dummy_checker.cc1
-rw-r--r--src/cpu/intr_control.cc4
-rw-r--r--src/cpu/kvm/x86_cpu.cc12
-rw-r--r--src/cpu/minor/execute.cc6
-rw-r--r--src/cpu/o3/checker.cc1
-rw-r--r--src/cpu/o3/cpu.cc6
-rw-r--r--src/cpu/simple/base.cc4
10 files changed, 61 insertions, 54 deletions
diff --git a/src/cpu/BaseCPU.py b/src/cpu/BaseCPU.py
index 9aa24c97b..a54a63b46 100644
--- a/src/cpu/BaseCPU.py
+++ b/src/cpu/BaseCPU.py
@@ -149,40 +149,40 @@ class BaseCPU(MemObject):
if buildEnv['TARGET_ISA'] == 'sparc':
dtb = Param.SparcTLB(SparcTLB(), "Data TLB")
itb = Param.SparcTLB(SparcTLB(), "Instruction TLB")
- interrupts = Param.SparcInterrupts(
- NULL, "Interrupt Controller")
+ interrupts = VectorParam.SparcInterrupts(
+ [], "Interrupt Controller")
isa = VectorParam.SparcISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'alpha':
dtb = Param.AlphaTLB(AlphaDTB(), "Data TLB")
itb = Param.AlphaTLB(AlphaITB(), "Instruction TLB")
- interrupts = Param.AlphaInterrupts(
- NULL, "Interrupt Controller")
+ interrupts = VectorParam.AlphaInterrupts(
+ [], "Interrupt Controller")
isa = VectorParam.AlphaISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'x86':
dtb = Param.X86TLB(X86TLB(), "Data TLB")
itb = Param.X86TLB(X86TLB(), "Instruction TLB")
- interrupts = Param.X86LocalApic(NULL, "Interrupt Controller")
+ interrupts = VectorParam.X86LocalApic([], "Interrupt Controller")
isa = VectorParam.X86ISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'mips':
dtb = Param.MipsTLB(MipsTLB(), "Data TLB")
itb = Param.MipsTLB(MipsTLB(), "Instruction TLB")
- interrupts = Param.MipsInterrupts(
- NULL, "Interrupt Controller")
+ interrupts = VectorParam.MipsInterrupts(
+ [], "Interrupt Controller")
isa = VectorParam.MipsISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'arm':
dtb = Param.ArmTLB(ArmTLB(), "Data TLB")
itb = Param.ArmTLB(ArmTLB(), "Instruction TLB")
istage2_mmu = Param.ArmStage2MMU(ArmStage2IMMU(), "Stage 2 trans")
dstage2_mmu = Param.ArmStage2MMU(ArmStage2DMMU(), "Stage 2 trans")
- interrupts = Param.ArmInterrupts(
- NULL, "Interrupt Controller")
+ interrupts = VectorParam.ArmInterrupts(
+ [], "Interrupt Controller")
isa = VectorParam.ArmISA([ isa_class() ], "ISA instance")
elif buildEnv['TARGET_ISA'] == 'power':
UnifiedTLB = Param.Bool(True, "Is this a Unified TLB?")
dtb = Param.PowerTLB(PowerTLB(), "Data TLB")
itb = Param.PowerTLB(PowerTLB(), "Instruction TLB")
- interrupts = Param.PowerInterrupts(
- NULL, "Interrupt Controller")
+ interrupts = VectorParam.PowerInterrupts(
+ [], "Interrupt Controller")
isa = VectorParam.PowerISA([ isa_class() ], "ISA instance")
else:
print "Don't know what TLB to use for ISA %s" % \
@@ -218,27 +218,29 @@ class BaseCPU(MemObject):
_uncached_slave_ports = []
_uncached_master_ports = []
if buildEnv['TARGET_ISA'] == 'x86':
- _uncached_slave_ports += ["interrupts.pio", "interrupts.int_slave"]
- _uncached_master_ports += ["interrupts.int_master"]
+ _uncached_slave_ports += ["interrupts[0].pio",
+ "interrupts[0].int_slave"]
+ _uncached_master_ports += ["interrupts[0].int_master"]
def createInterruptController(self):
if buildEnv['TARGET_ISA'] == 'sparc':
- self.interrupts = SparcInterrupts()
+ self.interrupts = [SparcInterrupts() for i in xrange(self.numThreads)]
elif buildEnv['TARGET_ISA'] == 'alpha':
- self.interrupts = AlphaInterrupts()
+ self.interrupts = [AlphaInterrupts() for i in xrange(self.numThreads)]
elif buildEnv['TARGET_ISA'] == 'x86':
self.apic_clk_domain = DerivedClockDomain(clk_domain =
Parent.clk_domain,
clk_divider = 16)
- self.interrupts = X86LocalApic(clk_domain = self.apic_clk_domain,
+ self.interrupts = [X86LocalApic(clk_domain = self.apic_clk_domain,
pio_addr=0x2000000000000000)
+ for i in xrange(self.numThreads)]
_localApic = self.interrupts
elif buildEnv['TARGET_ISA'] == 'mips':
- self.interrupts = MipsInterrupts()
+ self.interrupts = [MipsInterrupts() for i in xrange(self.numThreads)]
elif buildEnv['TARGET_ISA'] == 'arm':
- self.interrupts = ArmInterrupts()
+ self.interrupts = [ArmInterrupts() for i in xrange(self.numThreads)]
elif buildEnv['TARGET_ISA'] == 'power':
- self.interrupts = PowerInterrupts()
+ self.interrupts = [PowerInterrupts() for i in xrange(self.numThreads)]
else:
print "Don't know what Interrupt Controller to use for ISA %s" % \
buildEnv['TARGET_ISA']
diff --git a/src/cpu/base.cc b/src/cpu/base.cc
index 3b0809d09..a1dfa42ce 100644
--- a/src/cpu/base.cc
+++ b/src/cpu/base.cc
@@ -237,8 +237,10 @@ BaseCPU::BaseCPU(Params *p, bool is_checker)
// The interrupts should always be present unless this CPU is
// switched in later or in case it is a checker CPU
if (!params()->switched_out && !is_checker) {
- if (interrupts) {
- interrupts->setCPU(this);
+ if (!interrupts.empty()) {
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
+ interrupts[tid]->setCPU(this);
+ }
} else {
fatal("CPU %s has no interrupt controller.\n"
"Ensure createInterruptController() is called.\n", name());
@@ -583,8 +585,10 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
}
interrupts = oldCPU->interrupts;
- interrupts->setCPU(this);
- oldCPU->interrupts = NULL;
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
+ interrupts[tid]->setCPU(this);
+ }
+ oldCPU->interrupts.clear();
if (FullSystem) {
for (ThreadID i = 0; i < size; ++i)
@@ -656,11 +660,10 @@ BaseCPU::serialize(CheckpointOut &cp) const
* system. */
SERIALIZE_SCALAR(_pid);
- interrupts->serialize(cp);
-
// Serialize the threads, this is done by the CPU implementation.
for (ThreadID i = 0; i < numThreads; ++i) {
ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
+ interrupts[i]->serialize(cp);
serializeThread(cp, i);
}
}
@@ -673,11 +676,11 @@ BaseCPU::unserialize(CheckpointIn &cp)
if (!_switchedOut) {
UNSERIALIZE_SCALAR(_pid);
- interrupts->unserialize(cp);
// Unserialize the threads, this is done by the CPU implementation.
for (ThreadID i = 0; i < numThreads; ++i) {
ScopedCheckpointSection sec(cp, csprintf("xc.%i", i));
+ interrupts[i]->unserialize(cp);
unserializeThread(cp, i);
}
}
diff --git a/src/cpu/base.hh b/src/cpu/base.hh
index 0286ac45b..2a57c01ba 100644
--- a/src/cpu/base.hh
+++ b/src/cpu/base.hh
@@ -207,41 +207,45 @@ class BaseCPU : public MemObject
TheISA::MicrocodeRom microcodeRom;
protected:
- TheISA::Interrupts *interrupts;
+ std::vector<TheISA::Interrupts*> interrupts;
public:
TheISA::Interrupts *
- getInterruptController()
+ getInterruptController(ThreadID tid)
{
- return interrupts;
+ if (interrupts.empty())
+ return NULL;
+
+ assert(interrupts.size() > tid);
+ return interrupts[tid];
}
virtual void wakeup() = 0;
void
- postInterrupt(int int_num, int index)
+ postInterrupt(ThreadID tid, int int_num, int index)
{
- interrupts->post(int_num, index);
+ interrupts[tid]->post(int_num, index);
if (FullSystem)
wakeup();
}
void
- clearInterrupt(int int_num, int index)
+ clearInterrupt(ThreadID tid, int int_num, int index)
{
- interrupts->clear(int_num, index);
+ interrupts[tid]->clear(int_num, index);
}
void
- clearInterrupts()
+ clearInterrupts(ThreadID tid)
{
- interrupts->clearAll();
+ interrupts[tid]->clearAll();
}
bool
checkInterrupts(ThreadContext *tc) const
{
- return FullSystem && interrupts->checkInterrupts(tc);
+ return FullSystem && interrupts[tc->threadId()]->checkInterrupts(tc);
}
class ProfileEvent : public Event
diff --git a/src/cpu/dummy_checker.cc b/src/cpu/dummy_checker.cc
index bbd905492..aa4d45e2f 100644
--- a/src/cpu/dummy_checker.cc
+++ b/src/cpu/dummy_checker.cc
@@ -73,7 +73,6 @@ DummyCheckerParams::create()
params->system = system;
params->cpu_id = cpu_id;
params->profile = profile;
- params->interrupts = NULL;
params->workload = workload;
DummyChecker *cpu = new DummyChecker(params);
diff --git a/src/cpu/intr_control.cc b/src/cpu/intr_control.cc
index 8f3808889..ca24495f4 100644
--- a/src/cpu/intr_control.cc
+++ b/src/cpu/intr_control.cc
@@ -51,7 +51,7 @@ IntrControl::post(int cpu_id, int int_num, int index)
DPRINTF(IntrControl, "post %d:%d (cpu %d)\n", int_num, index, cpu_id);
std::vector<ThreadContext *> &tcvec = sys->threadContexts;
BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
- cpu->postInterrupt(int_num, index);
+ cpu->postInterrupt(tcvec[cpu_id]->threadId(), int_num, index);
}
void
@@ -60,7 +60,7 @@ IntrControl::clear(int cpu_id, int int_num, int index)
DPRINTF(IntrControl, "clear %d:%d (cpu %d)\n", int_num, index, cpu_id);
std::vector<ThreadContext *> &tcvec = sys->threadContexts;
BaseCPU *cpu = tcvec[cpu_id]->getCpuPtr();
- cpu->clearInterrupt(int_num, index);
+ cpu->clearInterrupt(tcvec[cpu_id]->threadId(), int_num, index);
}
IntrControl *
diff --git a/src/cpu/kvm/x86_cpu.cc b/src/cpu/kvm/x86_cpu.cc
index cd46370a4..5312ca55a 100644
--- a/src/cpu/kvm/x86_cpu.cc
+++ b/src/cpu/kvm/x86_cpu.cc
@@ -1142,9 +1142,9 @@ X86KvmCPU::deliverInterrupts()
// call across threads, we might still lose interrupts unless
// they are getInterrupt() and updateIntrInfo() are called
// atomically.
- EventQueue::ScopedMigration migrate(interrupts->eventQueue());
- fault = interrupts->getInterrupt(tc);
- interrupts->updateIntrInfo(tc);
+ EventQueue::ScopedMigration migrate(interrupts[0]->eventQueue());
+ fault = interrupts[0]->getInterrupt(tc);
+ interrupts[0]->updateIntrInfo(tc);
}
X86Interrupt *x86int(dynamic_cast<X86Interrupt *>(fault.get()));
@@ -1187,8 +1187,8 @@ X86KvmCPU::kvmRun(Tick ticks)
{
struct kvm_run &kvm_run(*getKvmRunState());
- if (interrupts->checkInterruptsRaw()) {
- if (interrupts->hasPendingUnmaskable()) {
+ if (interrupts[0]->checkInterruptsRaw()) {
+ if (interrupts[0]->hasPendingUnmaskable()) {
DPRINTF(KvmInt,
"Delivering unmaskable interrupt.\n");
syncThreadContext();
@@ -1200,7 +1200,7 @@ X86KvmCPU::kvmRun(Tick ticks)
// the thread context and check if there are /really/
// interrupts that should be delivered now.
syncThreadContext();
- if (interrupts->checkInterrupts(tc)) {
+ if (interrupts[0]->checkInterrupts(tc)) {
DPRINTF(KvmInt,
"M5 has pending interrupts, delivering interrupt.\n");
diff --git a/src/cpu/minor/execute.cc b/src/cpu/minor/execute.cc
index 001515eff..0a2c4b8c8 100644
--- a/src/cpu/minor/execute.cc
+++ b/src/cpu/minor/execute.cc
@@ -403,12 +403,12 @@ Execute::takeInterrupt(ThreadID thread_id, BranchData &branch)
DPRINTF(MinorInterrupt, "Considering interrupt status from PC: %s\n",
cpu.getContext(thread_id)->pcState());
- Fault interrupt = cpu.getInterruptController()->getInterrupt
+ Fault interrupt = cpu.getInterruptController(thread_id)->getInterrupt
(cpu.getContext(thread_id));
if (interrupt != NoFault) {
/* The interrupt *must* set pcState */
- cpu.getInterruptController()->updateIntrInfo
+ cpu.getInterruptController(thread_id)->updateIntrInfo
(cpu.getContext(thread_id));
interrupt->invoke(cpu.getContext(thread_id));
@@ -1391,7 +1391,7 @@ Execute::evaluate()
/* If there was an interrupt signalled, was it acted on now? */
bool took_interrupt = false;
- if (cpu.getInterruptController()) {
+ if (cpu.getInterruptController(0)) {
/* This is here because it seems that after drainResume the
* interrupt controller isn't always set */
interrupted = drainState == NotDraining && isInterrupted(0);
diff --git a/src/cpu/o3/checker.cc b/src/cpu/o3/checker.cc
index ce7a99f0f..be685d7c2 100644
--- a/src/cpu/o3/checker.cc
+++ b/src/cpu/o3/checker.cc
@@ -86,7 +86,6 @@ O3CheckerParams::create()
params->system = system;
params->cpu_id = cpu_id;
params->profile = profile;
- params->interrupts = NULL;
params->workload = workload;
O3Checker *cpu = new O3Checker(params);
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index 4ab004817..d4ee5ffe7 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -392,7 +392,7 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
}
// FullO3CPU always requires an interrupt controller.
- if (!params->switched_out && !interrupts) {
+ if (!params->switched_out && interrupts.empty()) {
fatal("FullO3CPU %s has no interrupt controller.\n"
"Ensure createInterruptController() is called.\n", name());
}
@@ -935,7 +935,7 @@ Fault
FullO3CPU<Impl>::getInterrupts()
{
// Check if there are any outstanding interrupts
- return this->interrupts->getInterrupt(this->threadContexts[0]);
+ return this->interrupts[0]->getInterrupt(this->threadContexts[0]);
}
template <class Impl>
@@ -949,7 +949,7 @@ FullO3CPU<Impl>::processInterrupts(const Fault &interrupt)
// @todo: Allow other threads to handle interrupts.
assert(interrupt != NoFault);
- this->interrupts->updateIntrInfo(this->threadContexts[0]);
+ this->interrupts[0]->updateIntrInfo(this->threadContexts[0]);
DPRINTF(O3CPU, "Interrupt %s being handled\n", interrupt->name());
this->trap(interrupt, 0, nullptr);
diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc
index 6e8845bf7..b0810517f 100644
--- a/src/cpu/simple/base.cc
+++ b/src/cpu/simple/base.cc
@@ -435,11 +435,11 @@ BaseSimpleCPU::checkForInterrupts()
ThreadContext* tc = thread->getTC();
if (checkInterrupts(tc)) {
- Fault interrupt = interrupts->getInterrupt(tc);
+ Fault interrupt = interrupts[curThread]->getInterrupt(tc);
if (interrupt != NoFault) {
t_info.fetchOffset = 0;
- interrupts->updateIntrInfo(tc);
+ interrupts[curThread]->updateIntrInfo(tc);
interrupt->invoke(tc);
thread->decoder.reset();
}