sim: Refactor and simplify the drain API

The drain() call currently passes around a DrainManager pointer, which
is now completely pointless since there is only ever one global
DrainManager in the system. It also contains vestiges from the time
when SimObjects had to keep track of their child objects that needed
draining.

This changeset moves all of the DrainState handling to the Drainable
base class and changes the drain() and drainResume() calls to reflect
this. Particularly, the drain() call has been updated to take no
parameters (the DrainManager argument isn't needed) and return a
DrainState instead of an unsigned integer (there is no point returning
anything other than 0 or 1 any more). Drainable objects should return
either DrainState::Draining (equivalent to returning 1 in the old
system) if they need more time to drain or DrainState::Drained
(equivalent to returning 0 in the old system) if they are already in a
consistent state. Returning DrainState::Running is considered an
error.

Drain done signalling is now done through the signalDrainDone() method
in the Drainable class instead of using the DrainManager directly. The
new call checks if the state of the object is DrainState::Draining
before notifying the drain manager. This means that it is safe to call
signalDrainDone() without first checking if the simulator has
requested draining. The intention here is to reduce the code needed to
implement draining in simple objects.
This commit is contained in:
Andreas Sandberg
2015-07-07 09:51:05 +01:00
parent f16c0a4a90
commit ed38e3432c
59 changed files with 346 additions and 538 deletions

View File

@@ -86,7 +86,6 @@ FlashDevice::FlashDevice(const FlashDeviceParams* p):
pagesPerDisk(0),
blocksPerDisk(0),
planeMask(numPlanes - 1),
drainManager(NULL),
planeEventQueue(numPlanes),
planeEvent(this)
{
@@ -587,26 +586,16 @@ FlashDevice::unserialize(CheckpointIn &cp)
* 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;
DPRINTF(Drain, "Flash device is draining...\n");
return DrainState::Draining;
} else {
DPRINTF(Drain, "Flash device in drained state\n");
return DrainState::Drained;
}
if (count) {
DPRINTF(Drain, "Flash device is draining...\n");
setDrainState(DrainState::Draining);
} else {
DPRINTF(Drain, "Flash device drained\n");
setDrainState(DrainState::Drained);
}
return count;
}
/**
@@ -616,15 +605,13 @@ FlashDevice::drain(DrainManager *dm)
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();
}
}

View File

@@ -62,7 +62,7 @@ class FlashDevice : public AbstractNVM
~FlashDevice();
/** Checkpoint functions*/
unsigned int drain(DrainManager *dm);
DrainState drain() M5_ATTR_OVERRIDE;
void checkDrain();
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
@@ -175,13 +175,6 @@ class FlashDevice : public AbstractNVM
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.

View File

@@ -733,7 +733,6 @@ UFSHostDevice::UFSHostDevice(const UFSHostDeviceParams* p) :
transferTrack(0),
taskCommandTrack(0),
idlePhaseStart(0),
drainManager(NULL),
SCSIResumeEvent(this),
UTPEvent(this)
{
@@ -2316,18 +2315,15 @@ UFSHostDevice::unserialize(CheckpointIn &cp)
* 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;
}
}
@@ -2338,16 +2334,14 @@ UFSHostDevice::drain(DrainManager *dm)
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();
}
}

View File

@@ -173,7 +173,7 @@ class UFSHostDevice : public DmaDevice
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;
@@ -1052,13 +1052,6 @@ class UFSHostDevice : public DmaDevice
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

View File

@@ -82,7 +82,7 @@ CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
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)
@@ -140,12 +140,12 @@ CopyEngine::CopyEngineChannel::recvCommand()
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;
@@ -635,25 +635,23 @@ CopyEngine::CopyEngineChannel::fetchAddrComplete()
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

View File

@@ -92,7 +92,6 @@ class CopyEngine : public PciDevice
ChannelState nextState;
DrainManager *drainManager;
public:
CopyEngineChannel(CopyEngine *_ce, int cid);
virtual ~CopyEngineChannel();
@@ -107,8 +106,8 @@ class CopyEngine : public PciDevice
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;

View File

@@ -51,8 +51,7 @@
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
@@ -95,10 +94,8 @@ DmaPort::handleResp(PacketPtr pkt, Tick delay)
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
@@ -125,14 +122,15 @@ DmaDevice::init()
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

View File

@@ -123,10 +123,6 @@ class DmaPort : public MasterPort, public Drainable
/** 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;
@@ -147,7 +143,7 @@ class DmaPort : public MasterPort, public Drainable
bool dmaPending() const { return pendingCount > 0; }
unsigned int drain(DrainManager *drainManger);
DrainState drain() M5_ATTR_OVERRIDE;
};
class DmaDevice : public PioDevice

View File

@@ -58,7 +58,7 @@ using namespace iGbReg;
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),
@@ -586,7 +586,7 @@ IGbE::write(PacketPtr pkt)
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 {
@@ -626,7 +626,7 @@ IGbE::write(PacketPtr pkt)
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 {
@@ -905,7 +905,7 @@ void
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;
}
@@ -986,7 +986,7 @@ void
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;
}
@@ -1492,7 +1492,7 @@ IGbE::RxDescCache::pktComplete()
void
IGbE::RxDescCache::enableSm()
{
if (!igbe->drainManager) {
if (igbe->drainState() != DrainState::Draining) {
igbe->rxTick = true;
igbe->restartClock();
}
@@ -2031,7 +2031,7 @@ IGbE::TxDescCache::packetAvailable()
void
IGbE::TxDescCache::enableSm()
{
if (!igbe->drainManager) {
if (igbe->drainState() != DrainState::Draining) {
igbe->txTick = true;
igbe->restartClock();
}
@@ -2051,18 +2051,17 @@ void
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;
@@ -2074,11 +2073,9 @@ IGbE::drain(DrainManager *dm)
if (count) {
DPRINTF(Drain, "IGbE not drained\n");
setDrainState(DrainState::Draining);
return DrainState::Draining;
} else
setDrainState(DrainState::Drained);
return count;
return DrainState::Drained;
}
void
@@ -2097,7 +2094,7 @@ IGbE::drainResume()
void
IGbE::checkDrain()
{
if (!drainManager)
if (drainState() != DrainState::Draining)
return;
txFifoTick = false;
@@ -2106,8 +2103,7 @@ IGbE::checkDrain()
if (!rxDescCache.hasOutstandingEvents() &&
!txDescCache.hasOutstandingEvents()) {
DPRINTF(Drain, "IGbE done draining, processing drain event\n");
drainManager->signalDrainDone();
drainManager = NULL;
signalDrainDone();
}
}
@@ -2131,7 +2127,7 @@ IGbE::txStateMachine()
bool success =
#endif
txFifo.push(txPacket);
txFifoTick = true && !drainManager;
txFifoTick = true && drainState() != DrainState::Draining;
assert(success);
txPacket = NULL;
anBegin("TXS", "Desc Writeback");
@@ -2230,7 +2226,7 @@ IGbE::ethRxPkt(EthPacketPtr pkt)
}
// 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");
@@ -2443,8 +2439,8 @@ IGbE::ethTxDone()
// 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();

View File

@@ -67,9 +67,6 @@ class IGbE : public EtherDevice
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;
@@ -352,7 +349,7 @@ class IGbE : public EtherDevice
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();
}
@@ -414,7 +411,7 @@ class IGbE : public EtherDevice
virtual void enableSm();
virtual void actionAfterWb();
virtual void fetchAfterWb() {
if (!igbe->txTick && igbe->getDrainState() == DrainState::Running)
if (!igbe->txTick && igbe->drainState() == DrainState::Running)
fetchDescriptors();
}
@@ -541,8 +538,8 @@ class IGbE : public EtherDevice
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;
};

View File

@@ -342,7 +342,7 @@ IdeDisk::doDmaTransfer()
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
@@ -436,7 +436,7 @@ IdeDisk::doDmaRead()
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()) {
@@ -518,7 +518,7 @@ IdeDisk::doDmaWrite()
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;

View File

@@ -1068,7 +1068,7 @@ NSGigE::doRxDmaRead()
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);
@@ -1099,7 +1099,7 @@ NSGigE::doRxDmaWrite()
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);
@@ -1515,7 +1515,7 @@ NSGigE::doTxDmaRead()
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);
@@ -1546,7 +1546,7 @@ NSGigE::doTxDmaWrite()
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);

View File

@@ -369,7 +369,7 @@ class NSGigE : public EtherDevBase
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
void drainResume();
void drainResume() M5_ATTR_OVERRIDE;
};
/*

View File

@@ -868,7 +868,7 @@ Device::rxKick()
break;
case rxBeginCopy:
if (dmaPending() || getDrainState() != DrainState::Running)
if (dmaPending() || drainState() != DrainState::Running)
goto exit;
rxDmaAddr = params()->platform->pciToDma(
@@ -1068,7 +1068,7 @@ Device::txKick()
break;
case txBeginCopy:
if (dmaPending() || getDrainState() != DrainState::Running)
if (dmaPending() || drainState() != DrainState::Running)
goto exit;
txDmaAddr = params()->platform->pciToDma(

View File

@@ -271,7 +271,7 @@ class Device : public Base
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);