summaryrefslogtreecommitdiff
path: root/src/dev/dma_device.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev/dma_device.cc')
-rw-r--r--src/dev/dma_device.cc175
1 files changed, 80 insertions, 95 deletions
diff --git a/src/dev/dma_device.cc b/src/dev/dma_device.cc
index 80253129f..c64694315 100644
--- a/src/dev/dma_device.cc
+++ b/src/dev/dma_device.cc
@@ -39,6 +39,7 @@
*
* Authors: Ali Saidi
* Nathan Binkert
+ * Andreas Hansson
*/
#include "base/chunk_generator.hh"
@@ -54,45 +55,62 @@ DmaPort::DmaPort(MemObject *dev, System *s)
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;
}
@@ -112,8 +130,7 @@ DmaDevice::init()
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
@@ -124,7 +141,7 @@ DmaDevice::drain(Event *de)
unsigned int
DmaPort::drain(Event *de)
{
- if (transmitList.empty() && pendingCount == 0)
+ if (pendingCount == 0)
return 0;
drainEvent = de;
DPRINTF(Drain, "DmaPort not drained\n");
@@ -159,46 +176,46 @@ void
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());
@@ -228,45 +245,13 @@ DmaPort::sendDma()
} 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 &