/*
- * Copyright (c) 2012-2013, 2015 ARM Limited
+ * Copyright (c) 2012-2013, 2015, 2017, 2019 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- * Nathan Binkert
- * Andreas Sandberg
*/
#ifndef __DEV_DMA_DEVICE_HH__
#include "sim/drain.hh"
#include "sim/system.hh"
-class DmaPort : public MasterPort, public Drainable
+class ClockedObject;
+
+class DmaPort : public RequestPort, public Drainable
{
private:
public:
/** The device that owns this port. */
- MemObject *const device;
+ ClockedObject *const device;
/** The system that device/port are in. This is used to select which mode
* we are currently operating in. */
std::deque<PacketPtr> transmitList;
/** Event used to schedule a future sending from the transmit list. */
- EventWrapper<DmaPort, &DmaPort::sendDma> sendEvent;
+ EventFunctionWrapper sendEvent;
/** Number of outstanding packets the dma port has. */
uint32_t pendingCount;
* send whatever it is that it's sending. */
bool inRetry;
+ /** Default streamId */
+ const uint32_t defaultSid;
+
+ /** Default substreamId */
+ const uint32_t defaultSSid;
+
protected:
bool recvTimingResp(PacketPtr pkt) override;
public:
- DmaPort(MemObject *dev, System *s);
+ DmaPort(ClockedObject *dev, System *s,
+ uint32_t sid = 0, uint32_t ssid = 0);
+
+ RequestPtr
+ dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
+ uint8_t *data, Tick delay, Request::Flags flag = 0);
- RequestPtr dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
- uint8_t *data, Tick delay, Request::Flags flag = 0);
+ RequestPtr
+ dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
+ uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay,
+ Request::Flags flag = 0);
bool dmaPending() const { return pendingCount > 0; }
DmaDevice(const Params *p);
virtual ~DmaDevice() { }
+ void dmaWrite(Addr addr, int size, Event *event, uint8_t *data,
+ uint32_t sid, uint32_t ssid, Tick delay = 0)
+ {
+ dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data,
+ sid, ssid, delay);
+ }
+
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data,
Tick delay = 0)
{
dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, delay);
}
+ void dmaRead(Addr addr, int size, Event *event, uint8_t *data,
+ uint32_t sid, uint32_t ssid, Tick delay = 0)
+ {
+ dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data,
+ sid, ssid, delay);
+ }
+
void dmaRead(Addr addr, int size, Event *event, uint8_t *data,
Tick delay = 0)
{
unsigned int cacheBlockSize() const { return sys->cacheLineSize(); }
- BaseMasterPort &getMasterPort(const std::string &if_name,
- PortID idx = InvalidPortID) override;
+ Port &getPort(const std::string &if_name,
+ PortID idx=InvalidPortID) override;
};
+/**
+ * DMA callback class.
+ *
+ * Allows one to register for a callback event after a sequence of (potentially
+ * non-contiguous) DMA transfers on a DmaPort completes. Derived classes must
+ * implement the process() method and use getChunkEvent() to allocate a
+ * callback event for each participating DMA.
+ */
+class DmaCallback : public Drainable
+{
+ public:
+ virtual const std::string name() const { return "DmaCallback"; }
+
+ /**
+ * DmaPort ensures that all oustanding DMA accesses have completed before
+ * it finishes draining. However, DmaChunkEvents scheduled with a delay
+ * might still be sitting on the event queue. Therefore, draining is not
+ * complete until count is 0, which ensures that all outstanding
+ * DmaChunkEvents associated with this DmaCallback have fired.
+ */
+ DrainState drain() override
+ {
+ return count ? DrainState::Draining : DrainState::Drained;
+ }
+
+ protected:
+ int count;
+
+ DmaCallback()
+ : count(0)
+ { }
+
+ virtual ~DmaCallback() { }
+
+ /**
+ * Callback function invoked on completion of all chunks.
+ */
+ virtual void process() = 0;
+
+ private:
+ /**
+ * Called by DMA engine completion event on each chunk completion.
+ * Since the object may delete itself here, callers should not use
+ * the object pointer after calling this function.
+ */
+ void chunkComplete()
+ {
+ if (--count == 0) {
+ process();
+ // Need to notify DrainManager that this object is finished
+ // draining, even though it is immediately deleted.
+ signalDrainDone();
+ delete this;
+ }
+ }
+
+ public:
+
+ /**
+ * Request a chunk event. Chunks events should be provided to each DMA
+ * request that wishes to participate in this DmaCallback.
+ */
+ Event *getChunkEvent()
+ {
+ ++count;
+ return new EventFunctionWrapper([this]{ chunkComplete(); }, name(),
+ true);
+ }
+};
+
/**
* Buffered DMA engine helper class
*
/** Handle pending requests that have been flagged as done. */
void handlePending();
- /** Try to issue new DMA requests */
+ /** Try to issue new DMA requests or bypass DMA requests*/
void resumeFill();
+ /** Try to issue new DMA requests during normal execution*/
+ void resumeFillTiming();
+
+ /** Try to bypass DMA requests in KVM execution mode */
+ void resumeFillFunctional();
+
private: // Internal state
Fifo<uint8_t> buffer;