using namespace ArmISA;
TableWalker::TableWalker(const Params *p)
- : MemObject(p), drainManager(NULL),
+ : MemObject(p),
stage2Mmu(NULL), port(NULL), masterId(Request::invldMasterId),
isStage2(p->is_stage2), tlb(NULL),
currState(NULL), pending(false),
void
TableWalker::completeDrain()
{
- if (drainManager && stateQueues[L1].empty() && stateQueues[L2].empty() &&
+ if (drainState() == DrainState::Draining &&
+ stateQueues[L1].empty() && stateQueues[L2].empty() &&
pendingQueue.empty()) {
- setDrainState(DrainState::Drained);
+
DPRINTF(Drain, "TableWalker done draining, processing drain event\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
}
-unsigned int
-TableWalker::drain(DrainManager *dm)
+DrainState
+TableWalker::drain()
{
bool state_queues_not_empty = false;
}
if (state_queues_not_empty || pendingQueue.size()) {
- drainManager = dm;
- setDrainState(DrainState::Draining);
DPRINTF(Drain, "TableWalker not drained\n");
-
- // return port drain count plus the table walker itself needs to drain
- return 1;
+ return DrainState::Draining;
} else {
- setDrainState(DrainState::Drained);
DPRINTF(Drain, "TableWalker free, no need to drain\n");
-
- // table walker is drained, but its ports may still need to be drained
- return 0;
+ return DrainState::Drained;
}
}
void
TableWalker::drainResume()
{
- Drainable::drainResume();
if (params()->sys->isTimingMode() && currState) {
delete currState;
currState = NULL;
* currently busy. */
std::list<WalkerState *> pendingQueue;
- /** If we're draining keep the drain event around until we're drained */
- DrainManager *drainManager;
-
/** The MMU to forward second stage look upts to */
Stage2MMU *stage2Mmu;
bool haveLargeAsid64() const { return _haveLargeAsid64; }
/** Checks if all state is cleared and if so, completes drain */
void completeDrain();
- unsigned int drain(DrainManager *dm);
- virtual void drainResume();
+ DrainState drain() M5_ATTR_OVERRIDE;
+ virtual void drainResume() M5_ATTR_OVERRIDE;
virtual BaseMasterPort& getMasterPort(const std::string &if_name,
PortID idx = InvalidPortID);
bool callFromS2);
Fault finalizePhysical(RequestPtr req, ThreadContext *tc, Mode mode) const;
- void drainResume();
+ void drainResume() M5_ATTR_OVERRIDE;
// Checkpointing
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
activeInstPeriod(0),
perfControlledByTimer(params->usePerfOverflow),
hostFactor(params->hostFactor),
- drainManager(NULL),
ctrInsts(0)
{
if (pageSize == -1)
threadContextDirty = true;
}
-unsigned int
-BaseKvmCPU::drain(DrainManager *dm)
+DrainState
+BaseKvmCPU::drain()
{
if (switchedOut())
- return 0;
+ return DrainState::Drained;
DPRINTF(Drain, "BaseKvmCPU::drain\n");
switch (_status) {
// of a different opinion. This may happen when the CPU been
// notified of an event that hasn't been accepted by the vCPU
// yet.
- if (!archIsDrained()) {
- drainManager = dm;
- return 1;
- }
+ if (!archIsDrained())
+ return DrainState::Draining;
// The state of the CPU is consistent, so we don't need to do
// anything special to drain it. We simply de-schedule the
// switch CPUs or checkpoint the CPU.
syncThreadContext();
- return 0;
+ return DrainState::Drained;
case RunningServiceCompletion:
// The CPU has just requested a service that was handled in
// update the register state ourselves instead of letting KVM
// handle it, but that would be tricky. Instead, we enter KVM
// and let it do its stuff.
- drainManager = dm;
-
DPRINTF(Drain, "KVM CPU is waiting for service completion, "
"requesting drain.\n");
- return 1;
+ return DrainState::Draining;
case RunningService:
// We need to drain since the CPU is waiting for service (e.g., MMIOs)
- drainManager = dm;
-
DPRINTF(Drain, "KVM CPU is waiting for service, requesting drain.\n");
- return 1;
+ return DrainState::Draining;
default:
panic("KVM: Unhandled CPU state in drain()\n");
- return 0;
+ return DrainState::Drained;
}
}
setupInstStop();
DPRINTF(KvmRun, "Entering KVM...\n");
- if (drainManager) {
+ if (drainState() == DrainState::Draining) {
// Force an immediate exit from KVM after completing
// pending operations. The architecture-specific code
// takes care to run until it is in a state where it can
bool
BaseKvmCPU::tryDrain()
{
- if (!drainManager)
+ if (drainState() != DrainState::Draining)
return false;
if (!archIsDrained()) {
if (_status == Idle || _status == Running) {
DPRINTF(Drain,
"tryDrain: CPU transitioned into the Idle state, drain done\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
return true;
} else {
DPRINTF(Drain, "tryDrain: CPU not ready.\n");
void unserializeThread(CheckpointIn &cp,
ThreadID tid) M5_ATTR_OVERRIDE;
- unsigned int drain(DrainManager *dm);
- void drainResume();
+ DrainState drain() M5_ATTR_OVERRIDE;
+ void drainResume() M5_ATTR_OVERRIDE;
void switchOut();
void takeOverFrom(BaseCPU *cpu);
/** Host factor as specified in the configuration */
float hostFactor;
- /**
- * Drain manager to use when signaling drain completion
- *
- * This pointer is non-NULL when draining and NULL otherwise.
- */
- DrainManager *drainManager;
-
public:
/* @{ */
Stats::Scalar numInsts;
#include "debug/Quiesce.hh"
MinorCPU::MinorCPU(MinorCPUParams *params) :
- BaseCPU(params),
- drainManager(NULL)
+ BaseCPU(params)
{
/* This is only written for one thread at the moment */
Minor::MinorThread *thread;
activateContext(0);
}
-unsigned int
-MinorCPU::drain(DrainManager *drain_manager)
+DrainState
+MinorCPU::drain()
{
DPRINTF(Drain, "MinorCPU drain\n");
- drainManager = drain_manager;
-
/* Need to suspend all threads and wait for Execute to idle.
* Tell Fetch1 not to fetch */
- unsigned int ret = pipeline->drain(drain_manager);
-
- if (ret == 0)
+ if (pipeline->drain()) {
DPRINTF(Drain, "MinorCPU drained\n");
- else
+ return DrainState::Drained;
+ } else {
DPRINTF(Drain, "MinorCPU not finished draining\n");
-
- return ret;
+ return DrainState::Draining;
+ }
}
void
MinorCPU::signalDrainDone()
{
DPRINTF(Drain, "MinorCPU drain done\n");
- setDrainState(DrainState::Drained);
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
void
MinorCPU::drainResume()
{
- assert(getDrainState() == DrainState::Drained ||
- getDrainState() == DrainState::Running);
+ assert(drainState() == DrainState::Drained);
if (switchedOut()) {
DPRINTF(Drain, "drainResume while switched out. Ignoring\n");
wakeup();
pipeline->drainResume();
-
- setDrainState(DrainState::Running);
}
void
virtual void recvTimingSnoopReq(PacketPtr pkt) { }
};
- /** The DrainManager passed into drain that needs be signalled when
- * draining is complete */
- DrainManager *drainManager;
-
protected:
/** Return a reference to the data port. */
MasterPort &getDataPort();
void unserialize(CheckpointIn &cp);
/** Drain interface */
- unsigned int drain(DrainManager *drain_manager);
- void drainResume();
- /** Signal from Pipeline that MinorCPU should signal the DrainManager
- * that a drain is complete and set its drainState */
+ DrainState drain() M5_ATTR_OVERRIDE;
+ void drainResume() M5_ATTR_OVERRIDE;
+ /** Signal from Pipeline that MinorCPU should signal that a drain
+ * is complete and set its drainState */
void signalDrainDone();
void memWriteback();
execute.wakeupFetch();
}
-unsigned int
-Pipeline::drain(DrainManager *manager)
+bool
+Pipeline::drain()
{
DPRINTF(MinorCPU, "Draining pipeline by halting inst fetches. "
" Execution should drain naturally\n");
bool drained = isDrained();
needToSignalDrained = !drained;
- return (drained ? 0 : 1);
+ return drained;
}
void
void wakeupFetch();
/** Try to drain the CPU */
- unsigned int drain(DrainManager *manager);
+ bool drain();
void drainResume();
globalSeqNum(1),
system(params->system),
- drainManager(NULL),
lastRunningCycle(curCycle())
{
if (!params->switched_out) {
{
DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
assert(!switchedOut());
- assert(getDrainState() != DrainState::Drained);
+ assert(drainState() != DrainState::Drained);
++numCycles;
ppCycles->notify(1);
// We don't want to wake the CPU if it is drained. In that case,
// we just want to flag the thread as active and schedule the tick
// event from drainResume() instead.
- if (getDrainState() == DrainState::Drained)
+ if (drainState() == DrainState::Drained)
return;
// If we are time 0 or if the last activation time is in the past,
}
template <class Impl>
-unsigned int
-FullO3CPU<Impl>::drain(DrainManager *drain_manager)
+DrainState
+FullO3CPU<Impl>::drain()
{
// If the CPU isn't doing anything, then return immediately.
- if (switchedOut()) {
- setDrainState(DrainState::Drained);
- return 0;
- }
+ if (switchedOut())
+ return DrainState::Drained;
DPRINTF(Drain, "Draining...\n");
- setDrainState(DrainState::Draining);
// We only need to signal a drain to the commit stage as this
// initiates squashing controls the draining. Once the commit
// Wake the CPU and record activity so everything can drain out if
// the CPU was not able to immediately drain.
if (!isDrained()) {
- drainManager = drain_manager;
-
wakeCPU();
activityRec.activity();
DPRINTF(Drain, "CPU not drained\n");
- return 1;
+ return DrainState::Draining;
} else {
- setDrainState(DrainState::Drained);
DPRINTF(Drain, "CPU is already drained\n");
if (tickEvent.scheduled())
deschedule(tickEvent);
}
drainSanityCheck();
- return 0;
+ return DrainState::Drained;
}
}
bool
FullO3CPU<Impl>::tryDrain()
{
- if (!drainManager || !isDrained())
+ if (drainState() != DrainState::Draining || !isDrained())
return false;
if (tickEvent.scheduled())
deschedule(tickEvent);
DPRINTF(Drain, "CPU done draining, processing drain event\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
return true;
}
void
FullO3CPU<Impl>::drainResume()
{
- setDrainState(DrainState::Running);
if (switchedOut())
return;
}
/**
- * Check if the pipeline has drained and signal the DrainManager.
+ * Check if the pipeline has drained and signal drain done.
*
* This method checks if a drain has been requested and if the CPU
* has drained successfully (i.e., there are no instructions in
void updateThreadPriority();
/** Is the CPU draining? */
- bool isDraining() const { return getDrainState() == DrainState::Draining; }
+ bool isDraining() const { return drainState() == DrainState::Draining; }
void serializeThread(CheckpointOut &cp,
ThreadID tid) const M5_ATTR_OVERRIDE;
/** Starts draining the CPU's pipeline of all instructions in
* order to stop all memory accesses. */
- unsigned int drain(DrainManager *drain_manager);
+ DrainState drain() M5_ATTR_OVERRIDE;
/** Resumes execution after a drain. */
- void drainResume();
+ void drainResume() M5_ATTR_OVERRIDE;
/**
* Commit has reached a safe point to drain a thread.
/** Pointer to the system. */
System *system;
- /** DrainManager to notify when draining has completed. */
- DrainManager *drainManager;
-
/** Pointers to all of the threads in the CPU. */
std::vector<Thread *> thread;
: BaseSimpleCPU(p), tickEvent(this), width(p->width), locked(false),
simulate_data_stalls(p->simulate_data_stalls),
simulate_inst_stalls(p->simulate_inst_stalls),
- drain_manager(NULL),
icachePort(name() + ".icache_port", this),
dcachePort(name() + ".dcache_port", this),
fastmem(p->fastmem), dcache_access(false), dcache_latency(0),
}
}
-unsigned int
-AtomicSimpleCPU::drain(DrainManager *dm)
+DrainState
+AtomicSimpleCPU::drain()
{
- assert(!drain_manager);
if (switchedOut())
- return 0;
+ return DrainState::Drained;
if (!isDrained()) {
DPRINTF(Drain, "Requesting drain: %s\n", pcState());
- drain_manager = dm;
- return 1;
+ return DrainState::Draining;
} else {
if (tickEvent.scheduled())
deschedule(tickEvent);
DPRINTF(Drain, "Not executing microcode, no need to drain.\n");
- return 0;
+ return DrainState::Drained;
}
}
AtomicSimpleCPU::drainResume()
{
assert(!tickEvent.scheduled());
- assert(!drain_manager);
if (switchedOut())
return;
bool
AtomicSimpleCPU::tryCompleteDrain()
{
- if (!drain_manager)
+ if (drainState() != DrainState::Draining)
return false;
DPRINTF(Drain, "tryCompleteDrain: %s\n", pcState());
return false;
DPRINTF(Drain, "CPU done draining, processing drain event\n");
- drain_manager->signalDrainDone();
- drain_manager = NULL;
+ signalDrainDone();
return true;
}
const bool simulate_data_stalls;
const bool simulate_inst_stalls;
- /**
- * Drain manager to use when signaling drain completion
- *
- * This pointer is non-NULL when draining and NULL otherwise.
- */
- DrainManager *drain_manager;
-
// main simulation loop (one cycle)
void tick();
public:
- unsigned int drain(DrainManager *drain_manager);
- void drainResume();
+ DrainState drain() M5_ATTR_OVERRIDE;
+ void drainResume() M5_ATTR_OVERRIDE;
void switchOut();
void takeOverFrom(BaseCPU *oldCPU);
TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
: BaseSimpleCPU(p), fetchTranslation(this), icachePort(this),
dcachePort(this), ifetch_pkt(NULL), dcache_pkt(NULL), previousCycle(0),
- fetchEvent(this), drainManager(NULL)
+ fetchEvent(this)
{
_status = Idle;
}
{
}
-unsigned int
-TimingSimpleCPU::drain(DrainManager *drain_manager)
+DrainState
+TimingSimpleCPU::drain()
{
- assert(!drainManager);
if (switchedOut())
- return 0;
+ return DrainState::Drained;
if (_status == Idle ||
(_status == BaseSimpleCPU::Running && isDrained())) {
DPRINTF(Drain, "No need to drain.\n");
- return 0;
+ return DrainState::Drained;
} else {
- drainManager = drain_manager;
DPRINTF(Drain, "Requesting drain: %s\n", pcState());
// The fetch event can become descheduled if a drain didn't
if (_status == BaseSimpleCPU::Running && !fetchEvent.scheduled())
schedule(fetchEvent, clockEdge());
- return 1;
+ return DrainState::Draining;
}
}
TimingSimpleCPU::drainResume()
{
assert(!fetchEvent.scheduled());
- assert(!drainManager);
if (switchedOut())
return;
bool
TimingSimpleCPU::tryCompleteDrain()
{
- if (!drainManager)
+ if (drainState() != DrainState::Draining)
return false;
DPRINTF(Drain, "tryCompleteDrain: %s\n", pcState());
return false;
DPRINTF(Drain, "CPU done draining, processing drain event\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
return true;
}
public:
- unsigned int drain(DrainManager *drain_manager);
- void drainResume();
+ DrainState drain() M5_ATTR_OVERRIDE;
+ void drainResume() M5_ATTR_OVERRIDE;
void switchOut();
void takeOverFrom(BaseCPU *oldCPU);
* @returns true if the CPU is drained, false otherwise.
*/
bool tryCompleteDrain();
-
- /**
- * Drain manager to use when signaling drain completion
- *
- * This pointer is non-NULL when draining and NULL otherwise.
- */
- DrainManager *drainManager;
};
#endif // __CPU_SIMPLE_TIMING_HH__
port(name() + ".port", *this),
retryPkt(NULL),
retryPktTick(0),
- updateEvent(this),
- drainManager(NULL)
+ updateEvent(this)
{
}
}
}
-unsigned int
-TrafficGen::drain(DrainManager *dm)
+DrainState
+TrafficGen::drain()
{
if (!updateEvent.scheduled()) {
// no event has been scheduled yet (e.g. switched from atomic mode)
- return 0;
+ return DrainState::Drained;
}
if (retryPkt == NULL) {
nextPacketTick = MaxTick;
nextTransitionTick = MaxTick;
deschedule(updateEvent);
- return 0;
+ return DrainState::Drained;
} else {
- drainManager = dm;
- return 1;
+ return DrainState::Draining;
}
}
retryPktTick = 0;
retryTicks += delay;
- if (drainManager == NULL) {
+ if (drainState() != DrainState::Draining) {
// packet is sent, so find out when the next one is due
nextPacketTick = states[currState]->nextPacketTick(elasticReq,
delay);
// shut things down
nextPacketTick = MaxTick;
nextTransitionTick = MaxTick;
- drainManager->signalDrainDone();
- // Clear the drain event once we're done with it.
- drainManager = NULL;
+ signalDrainDone();
}
}
}
/** Event for scheduling updates */
EventWrapper<TrafficGen, &TrafficGen::update> updateEvent;
- /** Manager to signal when drained */
- DrainManager* drainManager;
-
/** Count the number of generated packets. */
Stats::Scalar numPackets;
void initState();
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
pagesPerDisk(0),
blocksPerDisk(0),
planeMask(numPlanes - 1),
- drainManager(NULL),
planeEventQueue(numPlanes),
planeEvent(this)
{
* Drain; needed to enable checkpoints
*/
-unsigned int
-FlashDevice::drain(DrainManager *dm)
+DrainState
+FlashDevice::drain()
{
- unsigned int count = 0;
-
if (planeEvent.scheduled()) {
- count = 1;
- drainManager = dm;
- } else {
- DPRINTF(Drain, "Flash device in drained state\n");
- }
-
- if (count) {
DPRINTF(Drain, "Flash device is draining...\n");
- setDrainState(DrainState::Draining);
+ return DrainState::Draining;
} else {
- DPRINTF(Drain, "Flash device drained\n");
- setDrainState(DrainState::Drained);
+ DPRINTF(Drain, "Flash device in drained state\n");
+ return DrainState::Drained;
}
- return count;
}
/**
void
FlashDevice::checkDrain()
{
- if (drainManager == NULL) {
+ if (drainState() == DrainState::Draining)
return;
- }
if (planeEvent.when() > curTick()) {
DPRINTF(Drain, "Flash device is still draining\n");
} else {
DPRINTF(Drain, "Flash device is done draining\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
}
~FlashDevice();
/** Checkpoint functions*/
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
void checkDrain();
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
uint32_t planeMask;
- /**
- * drain manager
- * Needed to be able to implement checkpoint functionality
- */
-
- DrainManager *drainManager;
-
/**
* when the disk is first started we are unsure of the number of
* used pages, this variable will help determining what we do know.
transferTrack(0),
taskCommandTrack(0),
idlePhaseStart(0),
- drainManager(NULL),
SCSIResumeEvent(this),
UTPEvent(this)
{
* Drain; needed to enable checkpoints
*/
-unsigned int
-UFSHostDevice::drain(DrainManager *dm)
+DrainState
+UFSHostDevice::drain()
{
if (UFSHCIMem.TRUTRLDBR) {
- drainManager = dm;
DPRINTF(UFSHostDevice, "UFSDevice is draining...\n");
- setDrainState(DrainState::Draining);
- return 1;
+ return DrainState::Draining;
} else {
DPRINTF(UFSHostDevice, "UFSDevice drained\n");
- setDrainState(DrainState::Drained);
- return 0;
+ return DrainState::Drained;
}
}
void
UFSHostDevice::checkDrain()
{
- if (drainManager == NULL) {
+ if (drainState() != DrainState::Draining)
return;
- }
if (UFSHCIMem.TRUTRLDBR) {
DPRINTF(UFSHostDevice, "UFSDevice is still draining; with %d active"
" doorbells\n", activeDoorbells);
} else {
DPRINTF(UFSHostDevice, "UFSDevice is done draining\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
}
UFSHostDevice(const UFSHostDeviceParams* p);
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
void checkDrain();
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
Tick transactionStart[32];
Tick idlePhaseStart;
- /**
- * drain manager
- * Needed to be able to implement checkpoint functionality
- */
-
- DrainManager *drainManager;
-
/**
* logic units connected to the UFS Host device
* Note again that the "device" as such is represented by one or multiple
ce(_ce), channelId(cid), busy(false), underReset(false),
refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
latAfterCompletion(ce->params()->latAfterCompletion),
- completionDataReg(0), nextState(Idle), drainManager(NULL),
+ completionDataReg(0), nextState(Idle),
fetchCompleteEvent(this), addrCompleteEvent(this),
readCompleteEvent(this), writeCompleteEvent(this),
statusCompleteEvent(this)
cr.status.dma_transfer_status(0);
nextState = DescriptorFetch;
fetchAddress = cr.descChainAddr;
- if (ce->getDrainState() == DrainState::Running)
+ if (ce->drainState() == DrainState::Running)
fetchDescriptor(cr.descChainAddr);
} else if (cr.command.append_dma()) {
if (!busy) {
nextState = AddressFetch;
- if (ce->getDrainState() == DrainState::Running)
+ if (ce->drainState() == DrainState::Running)
fetchNextAddr(lastDescriptorAddr);
} else
refreshNext = true;
bool
CopyEngine::CopyEngineChannel::inDrain()
{
- if (ce->getDrainState() == DrainState::Draining) {
+ if (drainState() == DrainState::Draining) {
DPRINTF(Drain, "CopyEngine done draining, processing drain event\n");
- assert(drainManager);
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
- return ce->getDrainState() != DrainState::Running;
+ return ce->drainState() != DrainState::Running;
}
-unsigned int
-CopyEngine::CopyEngineChannel::drain(DrainManager *dm)
+DrainState
+CopyEngine::CopyEngineChannel::drain()
{
- if (nextState == Idle || ce->getDrainState() != DrainState::Running)
- return 0;
-
- DPRINTF(Drain, "CopyEngineChannel not drained\n");
- this->drainManager = dm;
- return 1;
+ if (nextState == Idle || ce->drainState() != DrainState::Running) {
+ return DrainState::Drained;
+ } else {
+ DPRINTF(Drain, "CopyEngineChannel not drained\n");
+ return DrainState::Draining;
+ }
}
void
ChannelState nextState;
- DrainManager *drainManager;
public:
CopyEngineChannel(CopyEngine *_ce, int cid);
virtual ~CopyEngineChannel();
void channelRead(PacketPtr pkt, Addr daddr, int size);
void channelWrite(PacketPtr pkt, Addr daddr, int size);
- unsigned int drain(DrainManager *drainManger);
- void drainResume();
+ DrainState drain() M5_ATTR_OVERRIDE;
+ void drainResume() M5_ATTR_OVERRIDE;
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
DmaPort::DmaPort(MemObject *dev, System *s)
: MasterPort(dev->name() + ".dma", dev), device(dev), sendEvent(this),
sys(s), masterId(s->getMasterId(dev->name())),
- pendingCount(0), drainManager(NULL),
- inRetry(false)
+ pendingCount(0), inRetry(false)
{ }
void
delete pkt;
// we might be drained at this point, if so signal the drain event
- if (pendingCount == 0 && drainManager) {
- drainManager->signalDrainDone();
- drainManager = NULL;
- }
+ if (pendingCount == 0)
+ signalDrainDone();
}
bool
PioDevice::init();
}
-unsigned int
-DmaPort::drain(DrainManager *dm)
+DrainState
+DmaPort::drain()
{
- if (pendingCount == 0)
- return 0;
- drainManager = dm;
- DPRINTF(Drain, "DmaPort not drained\n");
- return 1;
+ if (pendingCount == 0) {
+ return DrainState::Drained;
+ } else {
+ DPRINTF(Drain, "DmaPort not drained\n");
+ return DrainState::Draining;
+ }
}
void
/** Number of outstanding packets the dma port has. */
uint32_t pendingCount;
- /** If we need to drain, keep the drain event around until we're done
- * here.*/
- DrainManager *drainManager;
-
/** If the port is currently waiting for a retry before it can
* send whatever it is that it's sending. */
bool inRetry;
bool dmaPending() const { return pendingCount > 0; }
- unsigned int drain(DrainManager *drainManger);
+ DrainState drain() M5_ATTR_OVERRIDE;
};
class DmaDevice : public PioDevice
using namespace Net;
IGbE::IGbE(const Params *p)
- : EtherDevice(p), etherInt(NULL), cpa(NULL), drainManager(NULL),
+ : EtherDevice(p), etherInt(NULL), cpa(NULL),
rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
fetchDelay(p->fetch_delay), wbDelay(p->wb_delay),
case REG_RDT:
regs.rdt = val;
DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
- if (getDrainState() == DrainState::Running) {
+ if (drainState() == DrainState::Running) {
DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
rxDescCache.fetchDescriptors();
} else {
case REG_TDT:
regs.tdt = val;
DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
- if (getDrainState() == DrainState::Running) {
+ if (drainState() == DrainState::Running) {
DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
txDescCache.fetchDescriptors();
} else {
IGbE::DescCache<T>::writeback1()
{
// If we're draining delay issuing this DMA
- if (igbe->getDrainState() != DrainState::Running) {
+ if (igbe->drainState() != DrainState::Running) {
igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
return;
}
IGbE::DescCache<T>::fetchDescriptors1()
{
// If we're draining delay issuing this DMA
- if (igbe->getDrainState() != DrainState::Running) {
+ if (igbe->drainState() != DrainState::Running) {
igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
return;
}
void
IGbE::RxDescCache::enableSm()
{
- if (!igbe->drainManager) {
+ if (igbe->drainState() != DrainState::Draining) {
igbe->rxTick = true;
igbe->restartClock();
}
void
IGbE::TxDescCache::enableSm()
{
- if (!igbe->drainManager) {
+ if (igbe->drainState() != DrainState::Draining) {
igbe->txTick = true;
igbe->restartClock();
}
IGbE::restartClock()
{
if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
- getDrainState() == DrainState::Running)
+ drainState() == DrainState::Running)
schedule(tickEvent, clockEdge(Cycles(1)));
}
-unsigned int
-IGbE::drain(DrainManager *dm)
+DrainState
+IGbE::drain()
{
unsigned int count(0);
if (rxDescCache.hasOutstandingEvents() ||
txDescCache.hasOutstandingEvents()) {
count++;
- drainManager = dm;
}
txFifoTick = false;
if (count) {
DPRINTF(Drain, "IGbE not drained\n");
- setDrainState(DrainState::Draining);
+ return DrainState::Draining;
} else
- setDrainState(DrainState::Drained);
-
- return count;
+ return DrainState::Drained;
}
void
void
IGbE::checkDrain()
{
- if (!drainManager)
+ if (drainState() != DrainState::Draining)
return;
txFifoTick = false;
if (!rxDescCache.hasOutstandingEvents() &&
!txDescCache.hasOutstandingEvents()) {
DPRINTF(Drain, "IGbE done draining, processing drain event\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
}
bool success =
#endif
txFifo.push(txPacket);
- txFifoTick = true && !drainManager;
+ txFifoTick = true && drainState() != DrainState::Draining;
assert(success);
txPacket = NULL;
anBegin("TXS", "Desc Writeback");
}
// restart the state machines if they are stopped
- rxTick = true && !drainManager;
+ rxTick = true && drainState() != DrainState::Draining;
if ((rxTick || txTick) && !tickEvent.scheduled()) {
DPRINTF(EthernetSM,
"RXS: received packet into fifo, starting ticking\n");
// restart the tx state machines if they are stopped
// fifo to send another packet
// tx sm to put more data into the fifo
- txFifoTick = true && !drainManager;
- if (txDescCache.descLeft() != 0 && !drainManager)
+ txFifoTick = true && drainState() != DrainState::Draining;
+ if (txDescCache.descLeft() != 0 && drainState() != DrainState::Draining)
txTick = true;
restartClock();
uint8_t eeOpcode, eeAddr;
uint16_t flash[iGbReg::EEPROM_SIZE];
- // The drain event if we have one
- DrainManager *drainManager;
-
// packet fifos
PacketFifo rxFifo;
PacketFifo txFifo;
virtual void updateHead(long h) { igbe->regs.rdh(h); }
virtual void enableSm();
virtual void fetchAfterWb() {
- if (!igbe->rxTick && igbe->getDrainState() == DrainState::Running)
+ if (!igbe->rxTick && igbe->drainState() == DrainState::Running)
fetchDescriptors();
}
virtual void enableSm();
virtual void actionAfterWb();
virtual void fetchAfterWb() {
- if (!igbe->txTick && igbe->getDrainState() == DrainState::Running)
+ if (!igbe->txTick && igbe->drainState() == DrainState::Running)
fetchDescriptors();
}
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
- unsigned int drain(DrainManager *dm);
- void drainResume();
+ DrainState drain() M5_ATTR_OVERRIDE;
+ void drainResume() M5_ATTR_OVERRIDE;
};
panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
dmaState, devState);
- if (ctrl->dmaPending() || ctrl->getDrainState() != DrainState::Running) {
+ if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
return;
} else
curPrd.getByteCount(), TheISA::PageBytes);
}
- if (ctrl->dmaPending() || ctrl->getDrainState() != DrainState::Running) {
+ if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
return;
} else if (!dmaReadCG->done()) {
dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
curPrd.getByteCount(), TheISA::PageBytes);
}
- if (ctrl->dmaPending() || ctrl->getDrainState() != DrainState::Running) {
+ if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
return;
assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
rxDmaState = dmaReading;
- if (dmaPending() || getDrainState() != DrainState::Running)
+ if (dmaPending() || drainState() != DrainState::Running)
rxDmaState = dmaReadWaiting;
else
dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
rxDmaState = dmaWriting;
- if (dmaPending() || getDrainState() != DrainState::Running)
+ if (dmaPending() || drainState() != DrainState::Running)
rxDmaState = dmaWriteWaiting;
else
dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
txDmaState = dmaReading;
- if (dmaPending() || getDrainState() != DrainState::Running)
+ if (dmaPending() || drainState() != DrainState::Running)
txDmaState = dmaReadWaiting;
else
dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
txDmaState = dmaWriting;
- if (dmaPending() || getDrainState() != DrainState::Running)
+ if (dmaPending() || drainState() != DrainState::Running)
txDmaState = dmaWriteWaiting;
else
dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
- void drainResume();
+ void drainResume() M5_ATTR_OVERRIDE;
};
/*
break;
case rxBeginCopy:
- if (dmaPending() || getDrainState() != DrainState::Running)
+ if (dmaPending() || drainState() != DrainState::Running)
goto exit;
rxDmaAddr = params()->platform->pciToDma(
break;
case txBeginCopy:
- if (dmaPending() || getDrainState() != DrainState::Running)
+ if (dmaPending() || drainState() != DrainState::Running)
goto exit;
txDmaAddr = params()->platform->pciToDma(
public:
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
- virtual void drainResume();
+ virtual void drainResume() M5_ATTR_OVERRIDE;
void prepareIO(int cpu, int index);
void prepareRead(int cpu, int index);
int _index)
: label(_label), numEntries(num_entries + reserve - 1),
numReserve(reserve), demandReserve(demand_reserve),
- registers(numEntries), drainManager(NULL), allocated(0),
+ registers(numEntries), allocated(0),
inServiceEntries(0), index(_index)
{
for (int i = 0; i < numEntries; ++i) {
readyList.erase(mshr->readyIter);
}
mshr->deallocate();
- if (drainManager && allocated == 0) {
+ if (drainState() == DrainState::Draining && allocated == 0) {
// Notify the drain manager that we have completed draining if
// there are no other outstanding requests in this MSHR queue.
DPRINTF(Drain, "MSHRQueue now empty, signalling drained\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
- setDrainState(DrainState::Drained);
+ signalDrainDone();
}
return retval;
}
}
}
-unsigned int
-MSHRQueue::drain(DrainManager *dm)
+DrainState
+MSHRQueue::drain()
{
- if (allocated == 0) {
- setDrainState(DrainState::Drained);
- return 0;
- } else {
- drainManager = dm;
- setDrainState(DrainState::Draining);
- return 1;
- }
+ return allocated == 0 ? DrainState::Drained : DrainState::Draining;
}
/** Holds non allocated entries. */
MSHR::List freeList;
- /** Drain manager to inform of a completed drain */
- DrainManager *drainManager;
-
MSHR::Iterator addToReadyList(MSHR *mshr);
return readyList.empty() ? MaxTick : readyList.front()->readyTime;
}
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
};
#endif //__MEM_CACHE_MSHR_QUEUE_HH__
retryRdReq(false), retryWrReq(false),
busState(READ),
nextReqEvent(this), respondEvent(this),
- drainManager(NULL),
deviceSize(p->device_size),
deviceBusWidth(p->device_bus_width), burstLength(p->burst_length),
deviceRowBufferSize(p->device_rowbuffer_size),
schedule(respondEvent, respQueue.front()->readyTime);
} else {
// if there is nothing left in any queue, signal a drain
- if (writeQueue.empty() && readQueue.empty() &&
- drainManager) {
+ if (drainState() == DrainState::Draining &&
+ writeQueue.empty() && readQueue.empty()) {
+
DPRINTF(Drain, "DRAM controller done draining\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
}
// trigger writes if we have passed the low threshold (or
// if we are draining)
if (!writeQueue.empty() &&
- (drainManager || writeQueue.size() > writeLowThreshold)) {
+ (drainState() == DrainState::Draining ||
+ writeQueue.size() > writeLowThreshold)) {
switch_to_writes = true;
} else {
// check if we are drained
- if (respQueue.empty () && drainManager) {
+ if (drainState() == DrainState::Draining &&
+ respQueue.empty()) {
+
DPRINTF(Drain, "DRAM controller done draining\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
// nothing to do, not even any point in scheduling an
// writes, then switch to reads.
if (writeQueue.empty() ||
(writeQueue.size() + minWritesPerSwitch < writeLowThreshold &&
- !drainManager) ||
+ drainState() != DrainState::Draining) ||
(!readQueue.empty() && writesThisTime >= minWritesPerSwitch)) {
// turn the bus back around for reads again
busState = WRITE_TO_READ;
}
}
-unsigned int
-DRAMCtrl::drain(DrainManager *dm)
+DrainState
+DRAMCtrl::drain()
{
// if there is anything in any of our internal queues, keep track
// of that as well
- if (!(writeQueue.empty() && readQueue.empty() &&
- respQueue.empty())) {
+ if (!(writeQueue.empty() && readQueue.empty() && respQueue.empty())) {
DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d,"
" resp: %d\n", writeQueue.size(), readQueue.size(),
respQueue.size());
- drainManager = dm;
// the only part that is not drained automatically over time
// is the write queue, thus kick things into action if needed
if (!writeQueue.empty() && !nextReqEvent.scheduled()) {
schedule(nextReqEvent, curTick());
}
- setDrainState(DrainState::Draining);
- return 1;
+ return DrainState::Draining;
} else {
- setDrainState(DrainState::Drained);
- return 0;
+ return DrainState::Drained;
}
}
*/
std::deque<DRAMPacket*> respQueue;
- /**
- * If we need to drain, keep the drain manager around until we're
- * done here.
- */
- DrainManager *drainManager;
-
/**
* Vector of ranks
*/
DRAMCtrl(const DRAMCtrlParams* p);
- unsigned int drain(DrainManager* dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
virtual BaseSlavePort& getSlavePort(const std::string& if_name,
PortID idx = InvalidPortID);
p->traceFile, p->range.size() / 1024 / 1024, p->enableDebug),
retryReq(false), retryResp(false), startTick(0),
nbrOutstandingReads(0), nbrOutstandingWrites(0),
- drainManager(NULL),
sendResponseEvent(this), tickEvent(this)
{
DPRINTF(DRAMSim2,
if (!responseQueue.empty() && !sendResponseEvent.scheduled())
schedule(sendResponseEvent, curTick());
- // check if we were asked to drain and if we are now done
- if (drainManager && nbrOutstanding() == 0) {
- drainManager->signalDrainDone();
- drainManager = NULL;
- }
+ if (nbrOutstanding() == 0)
+ signalDrainDone();
} else {
retryResp = true;
assert(nbrOutstandingWrites != 0);
--nbrOutstandingWrites;
- // check if we were asked to drain and if we are now done
- if (drainManager && nbrOutstanding() == 0) {
- drainManager->signalDrainDone();
- drainManager = NULL;
- }
+ if (nbrOutstanding() == 0)
+ signalDrainDone();
}
BaseSlavePort&
}
unsigned int
-DRAMSim2::drain(DrainManager* dm)
+DRAMSim2::drain()
{
// check our outstanding reads and writes and if any they need to
// drain
- if (nbrOutstanding() != 0) {
- setDrainState(DrainState::Draining);
- drainManager = dm;
- return 1;
- } else {
- setDrainState(DrainState::Drained);
- return 0;
- }
+ return nbrOutstanding() != 0 ? DrainState::Draining : DrainState::Drained;
}
DRAMSim2::MemoryPort::MemoryPort(const std::string& _name,
*/
std::deque<PacketPtr> responseQueue;
- /**
- * If we need to drain, keep the drain manager around until we're
- * done here.
- */
- DrainManager *drainManager;
-
unsigned int nbrOutstanding() const;
/**
*/
void writeComplete(unsigned id, uint64_t addr, uint64_t cycle);
- unsigned int drain(DrainManager* dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
virtual BaseSlavePort& getSlavePort(const std::string& if_name,
PortID idx = InvalidPortID);
using namespace std;
PacketQueue::PacketQueue(EventManager& _em, const std::string& _label)
- : em(_em), sendEvent(this), drainManager(NULL), label(_label),
+ : em(_em), sendEvent(this), label(_label),
waitingOnRetry(false)
{
}
} else {
// we get a MaxTick when there is no more to send, so if we're
// draining, we may be done at this point
- if (drainManager && transmitList.empty() && !sendEvent.scheduled()) {
+ if (drainState() == DrainState::Draining &&
+ transmitList.empty() && !sendEvent.scheduled()) {
+
DPRINTF(Drain, "PacketQueue done draining,"
"processing drain event\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ signalDrainDone();
}
}
}
sendDeferredPacket();
}
-unsigned int
-PacketQueue::drain(DrainManager *dm)
+DrainState
+PacketQueue::drain()
{
- if (transmitList.empty())
- return 0;
- DPRINTF(Drain, "PacketQueue not drained\n");
- drainManager = dm;
- return 1;
+ if (transmitList.empty()) {
+ return DrainState::Drained;
+ } else {
+ DPRINTF(Drain, "PacketQueue not drained\n");
+ return DrainState::Draining;
+ }
}
ReqPacketQueue::ReqPacketQueue(EventManager& _em, MasterPort& _masterPort,
/** Event used to call processSendEvent. */
EventWrapper<PacketQueue, &PacketQueue::processSendEvent> sendEvent;
- /** If we need to drain, keep the drain manager around until we're done
- * here.*/
- DrainManager *drainManager;
-
protected:
/** Label to use for print request packets label stack. */
*/
void retry();
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
};
class ReqPacketQueue : public PacketQueue
}
}
-unsigned int
-RubyMemoryControl::drain(DrainManager *dm)
+DrainState
+RubyMemoryControl::drain()
{
DPRINTF(RubyMemory, "MemoryController drain\n");
if(m_event.scheduled()) {
deschedule(m_event);
}
- return 0;
+ return DrainState::Drained;
}
// wakeup: This function is called once per memory controller clock cycle.
virtual BaseSlavePort& getSlavePort(const std::string& if_name,
PortID idx = InvalidPortID);
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
void wakeup();
void setDescription(const std::string& name) { m_description = name; };
m_mandatory_q_ptr(NULL), m_usingRubyTester(p->using_ruby_tester),
slave_port(csprintf("%s.slave", name()), this, 0, p->ruby_system,
p->ruby_system->getAccessBackingStore()),
- drainManager(NULL), system(p->system), retry(false)
+ system(p->system), retry(false)
{
assert(m_version != -1);
}
DMASequencer::testDrainComplete()
{
//If we weren't able to drain before, we might be able to now.
- if (drainManager != NULL) {
+ if (drainState() == DrainState::Draining) {
unsigned int drainCount = outstandingCount();
DPRINTF(Drain, "Drain count: %u\n", drainCount);
if (drainCount == 0) {
DPRINTF(Drain, "DMASequencer done draining, signaling drain done\n");
- drainManager->signalDrainDone();
- // Clear the drain manager once we're done with it.
- drainManager = NULL;
+ signalDrainDone();
}
}
}
-unsigned int
-DMASequencer::drain(DrainManager *dm)
+DrainState
+DMASequencer::drain()
{
if (isDeadlockEventScheduled()) {
descheduleDeadlockEvent();
}
// If the DMASequencer is not empty, then it needs to clear all outstanding
- // requests before it should call drainManager->signalDrainDone()
+ // requests before it should call signalDrainDone()
DPRINTF(Config, "outstanding count %d\n", outstandingCount());
- bool need_drain = outstandingCount() > 0;
-
// Set status
- if (need_drain) {
- drainManager = dm;
-
+ if (outstandingCount() > 0) {
DPRINTF(Drain, "DMASequencer not drained\n");
- setDrainState(DrainState::Draining);
- return 1;
+ return DrainState::Draining;
+ } else {
+ return DrainState::Drained;
}
-
- drainManager = NULL;
- setDrainState(DrainState::Drained);
- return 0;
}
void
// A pointer to the controller is needed for atomic support.
void setController(AbstractController* _cntrl) { m_controller = _cntrl; }
uint32_t getId() { return m_version; }
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
/* SLICC callback */
void dataCallback(const DataBlock & dblk);
* @return Whether successfully sent
*/
bool recvTimingResp(PacketPtr pkt, PortID master_port_id);
- unsigned int getChildDrainCount(DrainManager *dm);
+ unsigned int getChildDrainCount();
private:
uint32_t m_version;
MemSlavePort slave_port;
- DrainManager *drainManager;
System* system;
bool retry;
memMasterPort(csprintf("%s.mem-master-port", name()), this),
memSlavePort(csprintf("%s-mem-slave-port", name()), this,
p->ruby_system, p->ruby_system->getAccessBackingStore(), -1),
- gotAddrRanges(p->port_master_connection_count), drainManager(NULL)
+ gotAddrRanges(p->port_master_connection_count)
{
assert(m_version != -1);
RubyPort::testDrainComplete()
{
//If we weren't able to drain before, we might be able to now.
- if (drainManager != NULL) {
+ if (drainState() == DrainState::Draining) {
unsigned int drainCount = outstandingCount();
DPRINTF(Drain, "Drain count: %u\n", drainCount);
if (drainCount == 0) {
DPRINTF(Drain, "RubyPort done draining, signaling drain done\n");
- drainManager->signalDrainDone();
- // Clear the drain manager once we're done with it.
- drainManager = NULL;
+ signalDrainDone();
}
}
}
-unsigned int
-RubyPort::drain(DrainManager *dm)
+DrainState
+RubyPort::drain()
{
if (isDeadlockEventScheduled()) {
descheduleDeadlockEvent();
//
// If the RubyPort is not empty, then it needs to clear all outstanding
- // requests before it should call drainManager->signalDrainDone()
+ // requests before it should call signalDrainDone()
//
DPRINTF(Config, "outstanding count %d\n", outstandingCount());
- bool need_drain = outstandingCount() > 0;
-
- // Set status
- if (need_drain) {
- drainManager = dm;
-
+ if (outstandingCount() > 0) {
DPRINTF(Drain, "RubyPort not drained\n");
- setDrainState(DrainState::Draining);
- return 1;
+ return DrainState::Draining;
+ } else {
+ return DrainState::Drained;
}
-
- drainManager = NULL;
- setDrainState(DrainState::Drained);
- return 0;
}
void
//
void setController(AbstractController* _cntrl) { m_controller = _cntrl; }
uint32_t getId() { return m_version; }
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
protected:
void ruby_hit_callback(PacketPtr pkt);
std::vector<MemSlavePort *> slave_ports;
std::vector<PioMasterPort *> master_ports;
- DrainManager *drainManager;
-
//
// Based on similar code in the M5 bus. Stores pointers to those ports
// that should be called when the Sequencer becomes available after a stall.
void
Sequencer::wakeup()
{
- assert(getDrainState() != DrainState::Draining);
+ assert(drainState() != DrainState::Draining);
// Check for deadlock of any of the requests
Cycles current_time = curCycle();
// See if we should schedule a deadlock check
if (!deadlockCheckEvent.scheduled() &&
- getDrainState() != DrainState::Draining) {
+ drainState() != DrainState::Draining) {
schedule(deadlockCheckEvent, clockEdge(m_deadlock_threshold));
}
port(name() + ".port", *this), latency(p->latency),
latency_var(p->latency_var), bandwidth(p->bandwidth), isBusy(false),
retryReq(false), retryResp(false),
- releaseEvent(this), dequeueEvent(this), drainManager(NULL)
+ releaseEvent(this), dequeueEvent(this)
{
}
// already have an event scheduled, so use re-schedule
reschedule(dequeueEvent,
std::max(packetQueue.front().tick, curTick()), true);
- } else if (drainManager) {
- DPRINTF(Drain, "Drainng of SimpleMemory complete\n");
- drainManager->signalDrainDone();
- drainManager = NULL;
+ } else if (drainState() == DrainState::Draining) {
+ DPRINTF(Drain, "Draining of SimpleMemory complete\n");
+ signalDrainDone();
}
}
}
}
}
-unsigned int
-SimpleMemory::drain(DrainManager *dm)
+DrainState
+SimpleMemory::drain()
{
- int count = 0;
-
- // also track our internal queue
if (!packetQueue.empty()) {
- count += 1;
- drainManager = dm;
DPRINTF(Drain, "SimpleMemory Queue has requests, waiting to drain\n");
- }
-
- if (count)
- setDrainState(DrainState::Draining);
- else
- setDrainState(DrainState::Drained);
- return count;
+ return DrainState::Draining;
+ } else {
+ return DrainState::Drained;
+ }
}
SimpleMemory::MemoryPort::MemoryPort(const std::string& _name,
*/
std::vector<PacketPtr> pendingDelete;
- /**
- * If we need to drain, keep the drain manager around until we're
- * done here.
- */
- DrainManager *drainManager;
-
public:
SimpleMemory(const SimpleMemoryParams *p);
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
BaseSlavePort& getSlavePort(const std::string& if_name,
PortID idx = InvalidPortID);
template <typename SrcType, typename DstType>
BaseXBar::Layer<SrcType,DstType>::Layer(DstType& _port, BaseXBar& _xbar,
const std::string& _name) :
- port(_port), xbar(_xbar), _name(_name), state(IDLE), drainManager(NULL),
+ port(_port), xbar(_xbar), _name(_name), state(IDLE),
waitingForPeer(NULL), releaseEvent(this)
{
}
// waiting for the peer
if (waitingForPeer == NULL)
retryWaiting();
- } else if (waitingForPeer == NULL && drainManager) {
+ } else if (waitingForPeer == NULL && drainState() == DrainState::Draining) {
DPRINTF(Drain, "Crossbar done draining, signaling drain manager\n");
//If we weren't able to drain before, do it now.
- drainManager->signalDrainDone();
- // Clear the drain event once we're done with it.
- drainManager = NULL;
+ signalDrainDone();
}
}
}
template <typename SrcType, typename DstType>
-unsigned int
-BaseXBar::Layer<SrcType,DstType>::drain(DrainManager *dm)
+DrainState
+BaseXBar::Layer<SrcType,DstType>::drain()
{
//We should check that we're not "doing" anything, and that noone is
//waiting. We might be idle but have someone waiting if the device we
//contacted for a retry didn't actually retry.
if (state != IDLE) {
DPRINTF(Drain, "Crossbar not drained\n");
- drainManager = dm;
- return 1;
+ return DrainState::Draining;
+ } else {
+ return DrainState::Drained;
}
- return 0;
}
template <typename SrcType, typename DstType>
*
* @return 1 if busy or waiting to retry, or 0 if idle
*/
- unsigned int drain(DrainManager *dm);
+ DrainState drain() M5_ATTR_OVERRIDE;
/**
* Get the crossbar layer's name
/** track the state of the layer */
State state;
- /** manager to signal when drained */
- DrainManager *drainManager;
-
/**
* A deque of ports that retry should be called on because
* the original send was delayed due to a busy layer.
DPRINTF(Drain, "Trying to drain %u objects.\n", drainableCount());
_state = DrainState::Draining;
for (auto *obj : _allDrainable)
- _count += obj->drain(&_instance);
+ _count += obj->dmDrain() == DrainState::Drained ? 0 : 1;
if (_count == 0) {
DPRINTF(Drain, "Drain done.\n");
DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
_state = DrainState::Running;
for (auto *obj : _allDrainable)
- obj->drainResume();
+ obj->dmDrainResume();
}
void
_drainManager.unregisterDrainable(this);
}
+DrainState
+Drainable::dmDrain()
+{
+ _drainState = DrainState::Draining;
+ _drainState = drain();
+ assert(_drainState == DrainState::Draining ||
+ _drainState == DrainState::Drained);
+
+ return _drainState;
+}
+
void
-Drainable::drainResume()
+Drainable::dmDrainResume()
{
+ panic_if(_drainState != DrainState::Drained,
+ "Trying to resume an object that hasn't been drained\n");
+
_drainState = DrainState::Running;
+ drainResume();
}
* follows (see simulate.py for details):
*
* <ol>
- * <li>Call Drainable::drain() for every object in the
- * system. Draining has completed if all of them return
- * zero. Otherwise, the sum of the return values is loaded into
- * the counter of the DrainManager. A pointer to the drain
- * manager is passed as an argument to the drain() method.
+ * <li>DrainManager::tryDrain() calls Drainable::drain() for every
+ * object in the system. Draining has completed if all of them
+ * return true. Otherwise, the drain manager keeps track of the
+ * objects that requested draining and waits for them to signal
+ * that they are done draining using the signalDrainDone() method.
*
* <li>Continue simulation. When an object has finished draining its
* internal state, it calls DrainManager::signalDrainDone() on the
- * manager. When the counter in the manager reaches zero, the
- * simulation stops.
+ * manager. The drain manager keeps track of the objects that
+ * haven't drained yet, simulation stops when the set of
+ * non-drained objects becomes empty.
*
- * <li>Check if any object still needs draining, if so repeat the
- * process above.
+ * <li>Check if any object still needs draining
+ * (DrainManager::tryDrain()), if so repeat the process above.
*
* <li>Serialize objects, switch CPU model, or change timing model.
*
- * <li>Call Drainable::drainResume() and continue the simulation.
+ * <li>Call DrainManager::resume(), which intern calls
+ * Drainable::drainResume() for all objects, and continue the
+ * simulation.
* </ol>
*
*/
{
friend class DrainManager;
- public:
+ protected:
Drainable();
virtual ~Drainable();
* Determine if an object needs draining and register a
* DrainManager.
*
- * When draining the state of an object, the simulator calls drain
- * with a pointer to a drain manager. If the object does not need
- * further simulation to drain internal buffers, it switched to
- * the Drained state and returns 0, otherwise it switches to the
- * Draining state and returns the number of times that it will
- * call Event::process() on the drain event. Most objects are
- * expected to return either 0 or 1.
+ * If the object does not need further simulation to drain
+ * internal buffers, it returns true and automatically switches to
+ * the Drained state, otherwise it switches to the Draining state.
*
* @note An object that has entered the Drained state can be
* disturbed by other objects in the system and consequently be
- * forced to enter the Draining state again. The simulator
- * therefore repeats the draining process until all objects return
- * 0 on the first call to drain().
+ * being drained. These perturbations are not visible in the
+ * drain state. The simulator therefore repeats the draining
+ * process until all objects return DrainState::Drained on the
+ * first call to drain().
*
- * @param drainManager DrainManager to use to inform the simulator
- * when draining has completed.
- *
- * @return 0 if the object is ready for serialization now, >0 if
- * it needs further simulation.
+ * @return DrainState::Drained if the object is ready for
+ * serialization now, DrainState::Draining if it needs further
+ * simulation.
*/
- virtual unsigned int drain(DrainManager *drainManager) = 0;
+ virtual DrainState drain() = 0;
/**
* Resume execution after a successful drain.
- *
- * @note This method is normally only called from the simulation
- * scripts.
*/
- virtual void drainResume();
+ virtual void drainResume() {};
- DrainState getDrainState() const { return _drainState; }
+ /**
+ * Signal that an object is drained
+ *
+ * This method is designed to be called whenever an object enters
+ * into a state where it is ready to be drained. The method is
+ * safe to call multiple times and there is no need to check that
+ * draining has been requested before calling this method.
+ */
+ void signalDrainDone() const {
+ switch (_drainState) {
+ case DrainState::Running:
+ case DrainState::Drained:
+ return;
+ case DrainState::Draining:
+ _drainState = DrainState::Drained;
+ _drainManager.signalDrainDone();
+ return;
+ }
+ }
- protected:
- void setDrainState(DrainState new_state) { _drainState = new_state; }
+ public:
+ /** Return the current drain state of an object. */
+ DrainState drainState() const { return _drainState; }
private:
+ /** DrainManager interface to request a drain operation */
+ DrainState dmDrain();
+ /** DrainManager interface to request a resume operation */
+ void dmDrainResume();
+
+ /** Convenience reference to the drain manager */
DrainManager &_drainManager;
- DrainState _drainState;
+
+ /**
+ * Current drain state of the object. Needs to be mutable since
+ * objects need to be able to signal that they have transitioned
+ * into a Drained state even if the calling method is const.
+ */
+ mutable DrainState _drainState;
};
#endif
pTable->initState(tc);
}
-unsigned int
-Process::drain(DrainManager *dm)
+DrainState
+Process::drain()
{
find_file_offsets();
- return 0;
+ return DrainState::Drained;
}
// map simulator fd sim_fd to target fd tgt_fd
virtual void initState();
- unsigned int drain(DrainManager *dm) M5_ATTR_OVERRIDE;
+ DrainState drain() M5_ATTR_OVERRIDE;
public:
}
#endif
-unsigned int
-SimObject::drain(DrainManager *drain_manager)
-{
- setDrainState(DrainState::Drained);
- return 0;
-}
-
-
SimObject *
SimObject::find(const char *name)
{
virtual void startup();
/**
- * Provide a default implementation of the drain interface that
- * simply returns 0 (draining completed) and sets the drain state
- * to Drained.
+ * Provide a default implementation of the drain interface for
+ * objects that don't need draining.
*/
- unsigned int drain(DrainManager *drainManger);
+ DrainState drain() M5_ATTR_OVERRIDE { return DrainState::Drained; }
/**
* Write back dirty buffers to memory using functional writes.
void
System::setMemoryMode(Enums::MemoryMode mode)
{
- assert(getDrainState() == DrainState::Drained);
+ assert(drainState() == DrainState::Drained);
memoryMode = mode;
}
return physmem.isMemAddr(addr);
}
-unsigned int
-System::drain(DrainManager *dm)
-{
- setDrainState(DrainState::Drained);
- return 0;
-}
-
void
System::drainResume()
{
- Drainable::drainResume();
totalNumInsts = 0;
}
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
- unsigned int drain(DrainManager *dm);
- void drainResume();
+ void drainResume() M5_ATTR_OVERRIDE;
public:
Counter totalNumInsts;