cpuSgiPending {}, cpuSgiActive {},
cpuSgiPendingExt {}, cpuSgiActiveExt {},
cpuPpiPending {}, cpuPpiActive {},
- irqEnable(false)
+ irqEnable(false),
+ pendingDelayedInterrupts(0)
{
for (int x = 0; x < CPU_MAX; x++) {
iccrpr[x] = 0xff;
cpuBpr[x] = 0;
// Initialize cpu highest int
cpuHighestInt[x] = SPURIOUS_INT;
- postIntEvent[x] = new PostIntEvent(x, p->platform);
+ postIntEvent[x] = new PostIntEvent(*this, x);
}
DPRINTF(Interrupt, "cpuEnabled[0]=%d cpuEnabled[1]=%d\n", cpuEnabled[0],
cpuEnabled[1]);
void
Pl390::postInt(uint32_t cpu, Tick when)
{
- if (!(postIntEvent[cpu]->scheduled()))
+ if (!(postIntEvent[cpu]->scheduled())) {
+ ++pendingDelayedInterrupts;
eventq->schedule(postIntEvent[cpu], when);
+ }
}
+void
+Pl390::postDelayedInt(uint32_t cpu)
+{
+ platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);
+ --pendingDelayedInterrupts;
+ assert(pendingDelayedInterrupts >= 0);
+ if (pendingDelayedInterrupts == 0)
+ signalDrainDone();
+}
+
+DrainState
+Pl390::drain()
+{
+ if (pendingDelayedInterrupts == 0) {
+ return DrainState::Drained;
+ } else {
+ return DrainState::Draining;
+ }
+}
void
Pl390::serialize(CheckpointOut &cp) const
SERIALIZE_ARRAY(cpuPpiActive, CPU_MAX);
SERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
SERIALIZE_SCALAR(irqEnable);
- Tick interrupt_time[CPU_MAX];
- for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
- interrupt_time[cpu] = 0;
- if (postIntEvent[cpu]->scheduled()) {
- interrupt_time[cpu] = postIntEvent[cpu]->when();
- }
- }
- SERIALIZE_ARRAY(interrupt_time, CPU_MAX);
SERIALIZE_SCALAR(gem5ExtensionsEnabled);
for (uint32_t i=0; i < bankedRegs.size(); ++i) {
UNSERIALIZE_ARRAY(cpuPpiPending, CPU_MAX);
UNSERIALIZE_SCALAR(irqEnable);
- Tick interrupt_time[CPU_MAX];
- UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
+ // Handle checkpoints from before we drained the GIC to prevent
+ // in-flight interrupts.
+ if (cp.entryExists(Serializable::currentSection(), "interrupt_time")) {
+ Tick interrupt_time[CPU_MAX];
+ UNSERIALIZE_ARRAY(interrupt_time, CPU_MAX);
- for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
- if (interrupt_time[cpu])
- schedule(postIntEvent[cpu], interrupt_time[cpu]);
+ for (uint32_t cpu = 0; cpu < CPU_MAX; cpu++) {
+ if (interrupt_time[cpu])
+ schedule(postIntEvent[cpu], interrupt_time[cpu]);
+ }
}
+
if (!UNSERIALIZE_OPT_SCALAR(gem5ExtensionsEnabled))
gem5ExtensionsEnabled = false;
int intNumToWord(int num) const { return num >> 5; }
int intNumToBit(int num) const { return num % 32; }
- /** Post an interrupt to a CPU
+ /**
+ * Post an interrupt to a CPU with a delay
*/
void postInt(uint32_t cpu, Tick when);
+ /**
+ * Deliver a delayed interrupt to the target CPU
+ */
+ void postDelayedInt(uint32_t cpu);
+
/** Event definition to post interrupt to CPU after a delay
*/
class PostIntEvent : public Event
{
private:
+ Pl390 &parent;
uint32_t cpu;
- Platform *platform;
public:
- PostIntEvent( uint32_t c, Platform* p)
- : cpu(c), platform(p)
+ PostIntEvent(Pl390 &_parent, uint32_t _cpu)
+ : parent(_parent), cpu(_cpu)
{ }
- void process() { platform->intrctrl->post(cpu, ArmISA::INT_IRQ, 0);}
+ void process() { parent.postDelayedInt(cpu); }
const char *description() const { return "Post Interrupt to CPU"; }
};
PostIntEvent *postIntEvent[CPU_MAX];
+ int pendingDelayedInterrupts;
public:
typedef Pl390Params Params;
}
Pl390(const Params *p);
+ DrainState drain() override;
+
void serialize(CheckpointOut &cp) const override;
void unserialize(CheckpointIn &cp) override;