sim: Move the draining interface into a separate base class

This patch moves the draining interface from SimObject to a separate
class that can be used by any object needing draining. However,
objects not visible to the Python code (i.e., objects not deriving
from SimObject) still depend on their parents informing them when to
drain. This patch also gets rid of the CountedDrainEvent (which isn't
really an event) and replaces it with a DrainManager.
This commit is contained in:
Andreas Sandberg
2012-11-02 11:32:01 -05:00
parent eb703a4b4e
commit b81a977e6a
64 changed files with 691 additions and 444 deletions

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), drainEvent(NULL),
completionDataReg(0), nextState(Idle), drainManager(NULL),
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->getState() == SimObject::Running)
if (ce->getDrainState() == Drainable::Running)
fetchDescriptor(cr.descChainAddr);
} else if (cr.command.append_dma()) {
if (!busy) {
nextState = AddressFetch;
if (ce->getState() == SimObject::Running)
if (ce->getDrainState() == Drainable::Running)
fetchNextAddr(lastDescriptorAddr);
} else
refreshNext = true;
@@ -637,41 +637,41 @@ CopyEngine::CopyEngineChannel::fetchAddrComplete()
bool
CopyEngine::CopyEngineChannel::inDrain()
{
if (ce->getState() == SimObject::Draining) {
if (ce->getDrainState() == Drainable::Draining) {
DPRINTF(Drain, "CopyEngine done draining, processing drain event\n");
assert(drainEvent);
drainEvent->process();
drainEvent = NULL;
assert(drainManager);
drainManager->signalDrainDone();
drainManager = NULL;
}
return ce->getState() != SimObject::Running;
return ce->getDrainState() != Drainable::Running;
}
unsigned int
CopyEngine::CopyEngineChannel::drain(Event *de)
CopyEngine::CopyEngineChannel::drain(DrainManager *dm)
{
if (nextState == Idle || ce->getState() != SimObject::Running)
if (nextState == Idle || ce->getDrainState() != Drainable::Running)
return 0;
unsigned int count = 1;
count += cePort.drain(de);
count += cePort.drain(dm);
DPRINTF(Drain, "CopyEngineChannel not drained\n");
drainEvent = de;
this->drainManager = dm;
return count;
}
unsigned int
CopyEngine::drain(Event *de)
CopyEngine::drain(DrainManager *dm)
{
unsigned int count;
count = pioPort.drain(de) + dmaPort.drain(de) + configPort.drain(de);
count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
for (int x = 0;x < chan.size(); x++)
count += chan[x]->drain(de);
count += chan[x]->drain(dm);
if (count)
changeState(Draining);
setDrainState(Draining);
else
changeState(Drained);
setDrainState(Drained);
DPRINTF(Drain, "CopyEngine not drained\n");
return count;
@@ -760,16 +760,16 @@ CopyEngine::CopyEngineChannel::restartStateMachine()
}
void
CopyEngine::resume()
CopyEngine::drainResume()
{
SimObject::resume();
Drainable::drainResume();
for (int x = 0;x < chan.size(); x++)
chan[x]->resume();
chan[x]->drainResume();
}
void
CopyEngine::CopyEngineChannel::resume()
CopyEngine::CopyEngineChannel::drainResume()
{
DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
restartStateMachine();

View File

@@ -55,11 +55,12 @@
#include "dev/copy_engine_defs.hh"
#include "dev/pcidev.hh"
#include "params/CopyEngine.hh"
#include "sim/drain.hh"
#include "sim/eventq.hh"
class CopyEngine : public PciDev
{
class CopyEngineChannel
class CopyEngineChannel : public Drainable
{
private:
DmaPort cePort;
@@ -91,7 +92,7 @@ class CopyEngine : public PciDev
ChannelState nextState;
Event *drainEvent;
DrainManager *drainManager;
public:
CopyEngineChannel(CopyEngine *_ce, int cid);
virtual ~CopyEngineChannel();
@@ -106,8 +107,9 @@ class CopyEngine : public PciDev
void channelRead(PacketPtr pkt, Addr daddr, int size);
void channelWrite(PacketPtr pkt, Addr daddr, int size);
unsigned int drain(Event *de);
void resume();
unsigned int drain(DrainManager *drainManger);
void drainResume();
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
@@ -205,8 +207,9 @@ class CopyEngine : public PciDev
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual unsigned int drain(Event *de);
virtual void resume();
unsigned int drain(DrainManager *drainManger);
void drainResume();
};
#endif //__DEV_COPY_ENGINE_HH__

View File

@@ -51,7 +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), drainEvent(NULL),
pendingCount(0), drainManager(NULL),
inRetry(false)
{ }
@@ -98,9 +98,9 @@ DmaPort::handleResp(PacketPtr pkt, Tick delay)
delete pkt;
// we might be drained at this point, if so signal the drain event
if (pendingCount == 0 && drainEvent) {
drainEvent->process();
drainEvent = NULL;
if (pendingCount == 0 && drainManager) {
drainManager->signalDrainDone();
drainManager = NULL;
}
}
@@ -128,22 +128,22 @@ DmaDevice::init()
}
unsigned int
DmaDevice::drain(Event *de)
DmaDevice::drain(DrainManager *dm)
{
unsigned int count = pioPort.drain(de) + dmaPort.drain(de);
unsigned int count = pioPort.drain(dm) + dmaPort.drain(dm);
if (count)
changeState(Draining);
setDrainState(Drainable::Draining);
else
changeState(Drained);
setDrainState(Drainable::Drained);
return count;
}
unsigned int
DmaPort::drain(Event *de)
DmaPort::drain(DrainManager *dm)
{
if (pendingCount == 0)
return 0;
drainEvent = de;
drainManager = dm;
DPRINTF(Drain, "DmaPort not drained\n");
return 1;
}

View File

@@ -48,6 +48,7 @@
#include "dev/io_device.hh"
#include "params/DmaDevice.hh"
#include "sim/drain.hh"
class DmaPort : public MasterPort
{
@@ -123,7 +124,7 @@ class DmaPort : public MasterPort
/** If we need to drain, keep the drain event around until we're done
* here.*/
Event *drainEvent;
DrainManager *drainManager;
/** If the port is currently waiting for a retry before it can
* send whatever it is that it's sending. */
@@ -146,7 +147,7 @@ class DmaPort : public MasterPort
bool dmaPending() const { return pendingCount > 0; }
unsigned cacheBlockSize() const { return peerBlockSize(); }
unsigned int drain(Event *de);
unsigned int drain(DrainManager *drainManger);
};
class DmaDevice : public PioDevice
@@ -175,7 +176,7 @@ class DmaDevice : public PioDevice
virtual void init();
virtual unsigned int drain(Event *de);
unsigned int drain(DrainManager *drainManger);
unsigned cacheBlockSize() const { return dmaPort.cacheBlockSize(); }

View File

@@ -57,7 +57,7 @@ using namespace iGbReg;
using namespace Net;
IGbE::IGbE(const Params *p)
: EtherDevice(p), etherInt(NULL), drainEvent(NULL),
: EtherDevice(p), etherInt(NULL), drainManager(NULL),
useFlowControl(p->use_flow_control),
rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
@@ -588,7 +588,7 @@ IGbE::write(PacketPtr pkt)
case REG_RDT:
regs.rdt = val;
DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
if (getState() == SimObject::Running) {
if (getDrainState() == Drainable::Running) {
DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
rxDescCache.fetchDescriptors();
} else {
@@ -628,7 +628,7 @@ IGbE::write(PacketPtr pkt)
case REG_TDT:
regs.tdt = val;
DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
if (getState() == SimObject::Running) {
if (getDrainState() == Drainable::Running) {
DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
txDescCache.fetchDescriptors();
} else {
@@ -906,7 +906,7 @@ void
IGbE::DescCache<T>::writeback1()
{
// If we're draining delay issuing this DMA
if (igbe->getState() != SimObject::Running) {
if (igbe->getDrainState() != Drainable::Running) {
igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
return;
}
@@ -987,7 +987,7 @@ void
IGbE::DescCache<T>::fetchDescriptors1()
{
// If we're draining delay issuing this DMA
if (igbe->getState() != SimObject::Running) {
if (igbe->getDrainState() != Drainable::Running) {
igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
return;
}
@@ -1493,7 +1493,7 @@ IGbE::RxDescCache::pktComplete()
void
IGbE::RxDescCache::enableSm()
{
if (!igbe->drainEvent) {
if (!igbe->drainManager) {
igbe->rxTick = true;
igbe->restartClock();
}
@@ -2029,7 +2029,7 @@ IGbE::TxDescCache::packetAvailable()
void
IGbE::TxDescCache::enableSm()
{
if (!igbe->drainEvent) {
if (!igbe->drainManager) {
igbe->txTick = true;
igbe->restartClock();
}
@@ -2049,19 +2049,19 @@ void
IGbE::restartClock()
{
if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
getState() == SimObject::Running)
getDrainState() == Drainable::Running)
schedule(tickEvent, clockEdge(Cycles(1)));
}
unsigned int
IGbE::drain(Event *de)
IGbE::drain(DrainManager *dm)
{
unsigned int count;
count = pioPort.drain(de) + dmaPort.drain(de);
count = pioPort.drain(dm) + dmaPort.drain(dm);
if (rxDescCache.hasOutstandingEvents() ||
txDescCache.hasOutstandingEvents()) {
count++;
drainEvent = de;
drainManager = dm;
}
txFifoTick = false;
@@ -2073,17 +2073,17 @@ IGbE::drain(Event *de)
if (count) {
DPRINTF(Drain, "IGbE not drained\n");
changeState(Draining);
setDrainState(Drainable::Draining);
} else
changeState(Drained);
setDrainState(Drainable::Drained);
return count;
}
void
IGbE::resume()
IGbE::drainResume()
{
SimObject::resume();
Drainable::drainResume();
txFifoTick = true;
txTick = true;
@@ -2096,7 +2096,7 @@ IGbE::resume()
void
IGbE::checkDrain()
{
if (!drainEvent)
if (!drainManager)
return;
txFifoTick = false;
@@ -2105,8 +2105,8 @@ IGbE::checkDrain()
if (!rxDescCache.hasOutstandingEvents() &&
!txDescCache.hasOutstandingEvents()) {
DPRINTF(Drain, "IGbE done draining, processing drain event\n");
drainEvent->process();
drainEvent = NULL;
drainManager->signalDrainDone();
drainManager = NULL;
}
}
@@ -2130,7 +2130,7 @@ IGbE::txStateMachine()
bool success =
#endif
txFifo.push(txPacket);
txFifoTick = true && !drainEvent;
txFifoTick = true && !drainManager;
assert(success);
txPacket = NULL;
anBegin("TXS", "Desc Writeback");
@@ -2229,7 +2229,7 @@ IGbE::ethRxPkt(EthPacketPtr pkt)
}
// restart the state machines if they are stopped
rxTick = true && !drainEvent;
rxTick = true && !drainManager;
if ((rxTick || txTick) && !tickEvent.scheduled()) {
DPRINTF(EthernetSM,
"RXS: received packet into fifo, starting ticking\n");
@@ -2442,8 +2442,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 && !drainEvent;
if (txDescCache.descLeft() != 0 && !drainEvent)
txFifoTick = true && !drainManager;
if (txDescCache.descLeft() != 0 && !drainManager)
txTick = true;
restartClock();

View File

@@ -68,7 +68,7 @@ class IGbE : public EtherDevice
uint16_t flash[iGbReg::EEPROM_SIZE];
// The drain event if we have one
Event *drainEvent;
DrainManager *drainManager;
// cached parameters from params struct
bool useFlowControl;
@@ -347,7 +347,7 @@ class IGbE : public EtherDevice
virtual void updateHead(long h) { igbe->regs.rdh(h); }
virtual void enableSm();
virtual void fetchAfterWb() {
if (!igbe->rxTick && igbe->getState() == SimObject::Running)
if (!igbe->rxTick && igbe->getDrainState() == Drainable::Running)
fetchDescriptors();
}
@@ -409,7 +409,7 @@ class IGbE : public EtherDevice
virtual void enableSm();
virtual void actionAfterWb();
virtual void fetchAfterWb() {
if (!igbe->txTick && igbe->getState() == SimObject::Running)
if (!igbe->txTick && igbe->getDrainState() == Drainable::Running)
fetchDescriptors();
}
@@ -535,8 +535,9 @@ class IGbE : public EtherDevice
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual unsigned int drain(Event *de);
virtual void resume();
unsigned int drain(DrainManager *dm);
void drainResume();
};

View File

@@ -323,7 +323,7 @@ IdeDisk::doDmaTransfer()
panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
dmaState, devState);
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
if (ctrl->dmaPending() || ctrl->getDrainState() != Drainable::Running) {
schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
return;
} else
@@ -404,7 +404,7 @@ IdeDisk::doDmaRead()
curPrd.getByteCount(), TheISA::PageBytes);
}
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
if (ctrl->dmaPending() || ctrl->getDrainState() != Drainable::Running) {
schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
return;
} else if (!dmaReadCG->done()) {
@@ -481,7 +481,7 @@ IdeDisk::doDmaWrite()
dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
curPrd.getByteCount(), TheISA::PageBytes);
}
if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
if (ctrl->dmaPending() || ctrl->getDrainState() != Drainable::Running) {
schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
return;

View File

@@ -89,14 +89,14 @@ PioDevice::getSlavePort(const std::string &if_name, PortID idx)
}
unsigned int
PioDevice::drain(Event *de)
PioDevice::drain(DrainManager *dm)
{
unsigned int count;
count = pioPort.drain(de);
count = pioPort.drain(dm);
if (count)
changeState(Draining);
setDrainState(Drainable::Draining);
else
changeState(Drained);
setDrainState(Drainable::Drained);
return count;
}

View File

@@ -125,7 +125,7 @@ class PioDevice : public MemObject
virtual void init();
virtual unsigned int drain(Event *de);
unsigned int drain(DrainManager *drainManger);
virtual BaseSlavePort &getSlavePort(const std::string &if_name,
PortID idx = InvalidPortID);

View File

@@ -1069,7 +1069,7 @@ NSGigE::doRxDmaRead()
assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
rxDmaState = dmaReading;
if (dmaPending() || getState() != Running)
if (dmaPending() || getDrainState() != Drainable::Running)
rxDmaState = dmaReadWaiting;
else
dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
@@ -1100,7 +1100,7 @@ NSGigE::doRxDmaWrite()
assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
rxDmaState = dmaWriting;
if (dmaPending() || getState() != Running)
if (dmaPending() || getDrainState() != Running)
rxDmaState = dmaWriteWaiting;
else
dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
@@ -1518,7 +1518,7 @@ NSGigE::doTxDmaRead()
assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
txDmaState = dmaReading;
if (dmaPending() || getState() != Running)
if (dmaPending() || getDrainState() != Running)
txDmaState = dmaReadWaiting;
else
dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
@@ -1549,7 +1549,7 @@ NSGigE::doTxDmaWrite()
assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
txDmaState = dmaWriting;
if (dmaPending() || getState() != Running)
if (dmaPending() || getDrainState() != Running)
txDmaState = dmaWriteWaiting;
else
dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
@@ -2112,9 +2112,9 @@ NSGigE::recvPacket(EthPacketPtr packet)
void
NSGigE::resume()
NSGigE::drainResume()
{
SimObject::resume();
Drainable::drainResume();
// During drain we could have left the state machines in a waiting state and
// they wouldn't get out until some other event occured to kick them.

View File

@@ -369,7 +369,7 @@ class NSGigE : public EtherDevBase
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual void resume();
void drainResume();
};
/*

View File

@@ -157,14 +157,14 @@ PciDev::init()
}
unsigned int
PciDev::drain(Event *de)
PciDev::drain(DrainManager *dm)
{
unsigned int count;
count = pioPort.drain(de) + dmaPort.drain(de) + configPort.drain(de);
count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
if (count)
changeState(Draining);
setDrainState(Drainable::Draining);
else
changeState(Drained);
setDrainState(Drainable::Drained);
return count;
}

View File

@@ -216,7 +216,7 @@ class PciDev : public DmaDevice
virtual void unserialize(Checkpoint *cp, const std::string &section);
virtual unsigned int drain(Event *de);
virtual unsigned int drain(DrainManager *dm);
virtual BaseSlavePort &getSlavePort(const std::string &if_name,
PortID idx = InvalidPortID)

View File

@@ -870,7 +870,7 @@ Device::rxKick()
break;
case rxBeginCopy:
if (dmaPending() || getState() != Running)
if (dmaPending() || getDrainState() != Drainable::Running)
goto exit;
rxDmaAddr = params()->platform->pciToDma(
@@ -1070,7 +1070,7 @@ Device::txKick()
break;
case txBeginCopy:
if (dmaPending() || getState() != Running)
if (dmaPending() || getDrainState() != Drainable::Running)
goto exit;
txDmaAddr = params()->platform->pciToDma(
@@ -1246,9 +1246,9 @@ Device::recvPacket(EthPacketPtr packet)
}
void
Device::resume()
Device::drainResume()
{
SimObject::resume();
Drainable::drainResume();
// During drain we could have left the state machines in a waiting state and
// they wouldn't get out until some other event occured to kick them.

View File

@@ -271,7 +271,7 @@ class Device : public Base
public:
virtual Tick read(PacketPtr pkt);
virtual Tick write(PacketPtr pkt);
virtual void resume();
virtual void drainResume();
void prepareIO(int cpu, int index);
void prepareRead(int cpu, int index);