dev-arm: Add a VExpress_GEM5_V2 platform with GICv3 support
[gem5.git] / src / dev / dma_device.cc
index 3515e70215f2c1e923cda355a2649d31acfd2e6c..c445fbc779758fc772bbe54058f806f4da07fc67 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015 ARM Limited
+ * Copyright (c) 2012, 2015, 2017 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
 #include "base/chunk_generator.hh"
 #include "debug/DMA.hh"
 #include "debug/Drain.hh"
+#include "mem/port_proxy.hh"
 #include "sim/system.hh"
 
 DmaPort::DmaPort(MemObject *dev, System *s)
     : MasterPort(dev->name() + ".dma", dev),
-      device(dev), sys(s), masterId(s->getMasterId(dev->name())),
-      sendEvent(this), pendingCount(0), inRetry(false)
+      device(dev), sys(s), masterId(s->getMasterId(dev)),
+      sendEvent([this]{ sendDma(); }, dev->name()),
+      pendingCount(0), inRetry(false)
 { }
 
 void
@@ -93,8 +95,7 @@ DmaPort::handleResp(PacketPtr pkt, Tick delay)
         delete state;
     }
 
-    // delete the request that we created and also the packet
-    delete pkt->req;
+    // delete the packet
     delete pkt;
 
     // we might be drained at this point, if so signal the drain event
@@ -163,7 +164,10 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
             event ? event->scheduled() : -1);
     for (ChunkGenerator gen(addr, size, sys->cacheLineSize());
          !gen.done(); gen.next()) {
-        req = new Request(gen.addr(), gen.size(), flag, masterId);
+
+        req = std::make_shared<Request>(
+            gen.addr(), gen.size(), flag, masterId);
+
         req->taskId(ContextSwitchTaskId::DMA);
         PacketPtr pkt = new Packet(req, cmd);
 
@@ -371,6 +375,40 @@ DmaReadFifo::resumeFill()
         return;
 
     const bool old_eob(atEndOfBlock());
+
+    if (port.sys->bypassCaches())
+        resumeFillFunctional();
+    else
+        resumeFillTiming();
+
+    if (!old_eob && atEndOfBlock())
+        onEndOfBlock();
+}
+
+void
+DmaReadFifo::resumeFillFunctional()
+{
+    const size_t fifo_space = buffer.capacity() - buffer.size();
+    const size_t kvm_watermark = port.sys->cacheLineSize();
+    if (fifo_space >= kvm_watermark || buffer.capacity() < kvm_watermark) {
+        const size_t block_remaining = endAddr - nextAddr;
+        const size_t xfer_size = std::min(fifo_space, block_remaining);
+        std::vector<uint8_t> tmp_buffer(xfer_size);
+
+        assert(pendingRequests.empty());
+        DPRINTF(DMA, "KVM Bypassing startAddr=%#x xfer_size=%#x " \
+                "fifo_space=%#x block_remaining=%#x\n",
+                nextAddr, xfer_size, fifo_space, block_remaining);
+
+        port.sys->physProxy.readBlob(nextAddr, tmp_buffer.data(), xfer_size);
+        buffer.write(tmp_buffer.begin(), xfer_size);
+        nextAddr += xfer_size;
+    }
+}
+
+void
+DmaReadFifo::resumeFillTiming()
+{
     size_t size_pending(0);
     for (auto &e : pendingRequests)
         size_pending += e->requestSize();
@@ -392,11 +430,6 @@ DmaReadFifo::resumeFill()
 
         pendingRequests.emplace_back(std::move(event));
     }
-
-    // EOB can be set before a call to dmaDone() if in-flight accesses
-    // have been canceled.
-    if (!old_eob && atEndOfBlock())
-        onEndOfBlock();
 }
 
 void
@@ -407,7 +440,7 @@ DmaReadFifo::dmaDone()
     handlePending();
     resumeFill();
 
-    if (!old_active && isActive())
+    if (old_active && !isActive())
         onIdle();
 }
 
@@ -430,8 +463,6 @@ DmaReadFifo::handlePending()
         signalDrainDone();
 }
 
-
-
 DrainState
 DmaReadFifo::drain()
 {