*
* Authors: Ali Saidi
* Nathan Binkert
+ * Andreas Hansson
*/
#include "base/chunk_generator.hh"
inRetry(false)
{ }
-bool
-DmaPort::recvTimingResp(PacketPtr pkt)
+void
+DmaPort::handleResp(PacketPtr pkt, Tick delay)
{
- if (pkt->senderState) {
- DmaReqState *state;
-
- DPRINTF(DMA, "Received response %s addr %#x size %#x\n",
- pkt->cmdString(), pkt->getAddr(), pkt->req->getSize());
- state = dynamic_cast<DmaReqState*>(pkt->senderState);
- pendingCount--;
-
- assert(pendingCount >= 0);
- assert(state);
-
- // We shouldn't ever get a block in ownership state
- assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
-
- state->numBytes += pkt->req->getSize();
- assert(state->totBytes >= state->numBytes);
- if (state->totBytes == state->numBytes) {
- if (state->completionEvent) {
- if (state->delay)
- device->schedule(state->completionEvent,
- curTick() + state->delay);
- else
- state->completionEvent->process();
- }
- delete state;
+ // should always see a response with a sender state
+ assert(pkt->isResponse());
+
+ // get the DMA sender state
+ DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
+ assert(state);
+
+ DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d," \
+ " tot: %d sched %d\n",
+ pkt->cmdString(), pkt->getAddr(), pkt->req->getSize(),
+ state->numBytes, state->totBytes,
+ state->completionEvent ?
+ state->completionEvent->scheduled() : 0);
+
+ assert(pendingCount != 0);
+ pendingCount--;
+
+ // update the number of bytes received based on the request rather
+ // than the packet as the latter could be rounded up to line sizes
+ state->numBytes += pkt->req->getSize();
+ assert(state->totBytes >= state->numBytes);
+
+ // if we have reached the total number of bytes for this DMA
+ // request, then signal the completion and delete the sate
+ if (state->totBytes == state->numBytes) {
+ if (state->completionEvent) {
+ delay += state->delay;
+ if (delay)
+ device->schedule(state->completionEvent, curTick() + delay);
+ else
+ state->completionEvent->process();
}
- delete pkt->req;
- delete pkt;
+ delete state;
+ }
- if (pendingCount == 0 && transmitList.empty() && drainEvent) {
- drainEvent->process();
- drainEvent = NULL;
- }
- } else {
- panic("Got packet without sender state... huh?\n");
+ // delete the request that we created and also the packet
+ delete pkt->req;
+ delete pkt;
+
+ // we might be drained at this point, if so signal the drain event
+ if (pendingCount == 0 && drainEvent) {
+ drainEvent->process();
+ drainEvent = NULL;
}
+}
+
+bool
+DmaPort::recvTimingResp(PacketPtr pkt)
+{
+ // We shouldn't ever get a block in ownership state
+ assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
+
+ handleResp(pkt);
return true;
}
unsigned int
DmaDevice::drain(Event *de)
{
- unsigned int count;
- count = pioPort.drain(de) + dmaPort.drain(de);
+ unsigned int count = pioPort.drain(de) + dmaPort.drain(de);
if (count)
changeState(Draining);
else
unsigned int
DmaPort::drain(Event *de)
{
- if (transmitList.empty() && pendingCount == 0)
+ if (pendingCount == 0)
return 0;
drainEvent = de;
DPRINTF(Drain, "DmaPort not drained\n");
DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
uint8_t *data, Tick delay, Request::Flags flag)
{
+ // one DMA request sender state for every action, that is then
+ // split into many requests and packets based on the block size,
+ // i.e. cache line size
DmaReqState *reqState = new DmaReqState(event, size, delay);
-
DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
- event ? event->scheduled() : -1 );
+ event ? event->scheduled() : -1);
for (ChunkGenerator gen(addr, size, peerBlockSize());
!gen.done(); gen.next()) {
- Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
- PacketPtr pkt = new Packet(req, cmd);
+ Request *req = new Request(gen.addr(), gen.size(), flag, masterId);
+ PacketPtr pkt = new Packet(req, cmd);
- // Increment the data pointer on a write
- if (data)
- pkt->dataStatic(data + gen.complete());
+ // Increment the data pointer on a write
+ if (data)
+ pkt->dataStatic(data + gen.complete());
- pkt->senderState = reqState;
+ pkt->senderState = reqState;
- assert(pendingCount >= 0);
- pendingCount++;
- DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
- gen.size());
- queueDma(pkt);
+ DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
+ gen.size());
+ queueDma(pkt);
}
-
}
void
-DmaPort::queueDma(PacketPtr pkt, bool front)
+DmaPort::queueDma(PacketPtr pkt)
{
+ transmitList.push_back(pkt);
+
+ // remember that we have another packet pending, this will only be
+ // decremented once a response comes back
+ pendingCount++;
- if (front)
- transmitList.push_front(pkt);
- else
- transmitList.push_back(pkt);
sendDma();
}
void
DmaPort::sendDma()
{
- // some kind of selction between access methods
+ // some kind of selcetion between access methods
// more work is going to have to be done to make
// switching actually work
assert(transmitList.size());
} else if (state == Enums::atomic) {
transmitList.pop_front();
- Tick lat;
- DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n",
+ DPRINTF(DMA, "Sending DMA for addr: %#x size: %d\n",
pkt->req->getPaddr(), pkt->req->getSize());
- lat = sendAtomic(pkt);
- assert(pkt->senderState);
- DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
- assert(state);
- state->numBytes += pkt->req->getSize();
-
- DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n",
- pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes,
- state->totBytes,
- state->completionEvent ? state->completionEvent->scheduled() : 0 );
-
- if (state->totBytes == state->numBytes) {
- if (state->completionEvent) {
- assert(!state->completionEvent->scheduled());
- device->schedule(state->completionEvent,
- curTick() + lat + state->delay);
- }
- delete state;
- delete pkt->req;
- }
- pendingCount--;
- assert(pendingCount >= 0);
- delete pkt;
-
- if (pendingCount == 0 && transmitList.empty() && drainEvent) {
- DPRINTF(Drain, "DmaPort done draining, processing drain event\n");
- drainEvent->process();
- drainEvent = NULL;
- }
+ Tick lat = sendAtomic(pkt);
- } else
- panic("Unknown memory command state.");
-}
-
-DmaDevice::~DmaDevice()
-{
+ handleResp(pkt, lat);
+ } else
+ panic("Unknown memory mode.");
}
MasterPort &
#ifndef __DEV_DMA_DEVICE_HH__
#define __DEV_DMA_DEVICE_HH__
+#include <deque>
+
#include "dev/io_device.hh"
#include "params/DmaDevice.hh"
};
MemObject *device;
- std::list<PacketPtr> transmitList;
+
+ /** Use a deque as we never to any insertion or removal in the middle */
+ std::deque<PacketPtr> transmitList;
/** The system that device/port are in. This is used to select which mode
* we are currently operating in. */
MasterID masterId;
/** Number of outstanding packets the dma port has. */
- int pendingCount;
+ uint32_t pendingCount;
/** If we need to drain, keep the drain event around until we're done
* here.*/
Event *drainEvent;
- /** If the port is currently waiting for a retry before it can send whatever
- * it is that it's sending. */
+ /** If the port is currently waiting for a retry before it can
+ * send whatever it is that it's sending. */
bool inRetry;
- virtual bool recvTimingResp(PacketPtr pkt);
-
- virtual void recvRetry() ;
-
- void queueDma(PacketPtr pkt, bool front = false);
+ /**
+ * Handle a response packet by updating the corresponding DMA
+ * request state to reflect the bytes received, and also update
+ * the pending request counter. If the DMA request that this
+ * packet is part of is complete, then signal the completion event
+ * if present, potentially with a delay added to it.
+ *
+ * @param pkt Response packet to handler
+ * @param delay Additional delay for scheduling the completion event
+ */
+ void handleResp(PacketPtr pkt, Tick delay = 0);
+
+ bool recvTimingResp(PacketPtr pkt);
+ void recvRetry() ;
+
+ void queueDma(PacketPtr pkt);
void sendDma();
public:
void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
uint8_t *data, Tick delay, Request::Flags flag = 0);
- bool dmaPending() { return pendingCount > 0; }
+ bool dmaPending() const { return pendingCount > 0; }
unsigned cacheBlockSize() const { return peerBlockSize(); }
unsigned int drain(Event *de);
public:
typedef DmaDeviceParams Params;
DmaDevice(const Params *p);
- virtual ~DmaDevice();
-
- const Params *
- params() const
- {
- return dynamic_cast<const Params *>(_params);
- }
+ virtual ~DmaDevice() { }
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data,
Tick delay = 0)