dma_device.hh revision 12131
1545SN/A/* 211896Ssudhanshu.jha@arm.com * Copyright (c) 2012-2013, 2015, 2017 ARM Limited 38948SN/A * All rights reserved. 48948SN/A * 58948SN/A * The license below extends only to copyright in the software and shall 68948SN/A * not be construed as granting a license to any other intellectual 78948SN/A * property including but not limited to intellectual property relating 88948SN/A * to a hardware implementation of the functionality of the software 98948SN/A * licensed hereunder. You may use the software subject to the license 108948SN/A * terms below provided that you ensure that this notice is replicated 118948SN/A * unmodified and in its entirety in all distributions of the software, 128948SN/A * modified or unmodified, in source code or in binary form. 138948SN/A * 141762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 15545SN/A * All rights reserved. 16545SN/A * 17545SN/A * Redistribution and use in source and binary forms, with or without 18545SN/A * modification, are permitted provided that the following conditions are 19545SN/A * met: redistributions of source code must retain the above copyright 20545SN/A * notice, this list of conditions and the following disclaimer; 21545SN/A * redistributions in binary form must reproduce the above copyright 22545SN/A * notice, this list of conditions and the following disclaimer in the 23545SN/A * documentation and/or other materials provided with the distribution; 24545SN/A * neither the name of the copyright holders nor the names of its 25545SN/A * contributors may be used to endorse or promote products derived from 26545SN/A * this software without specific prior written permission. 27545SN/A * 28545SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29545SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30545SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31545SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32545SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33545SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34545SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35545SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36545SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37545SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38545SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 392665SN/A * 402665SN/A * Authors: Ali Saidi 412665SN/A * Nathan Binkert 4211010Sandreas.sandberg@arm.com * Andreas Sandberg 43545SN/A */ 44545SN/A 459016Sandreas.hansson@arm.com#ifndef __DEV_DMA_DEVICE_HH__ 469016Sandreas.hansson@arm.com#define __DEV_DMA_DEVICE_HH__ 47545SN/A 489166Sandreas.hansson@arm.com#include <deque> 4911010Sandreas.sandberg@arm.com#include <memory> 509166Sandreas.hansson@arm.com 5111010Sandreas.sandberg@arm.com#include "base/circlebuf.hh" 529016Sandreas.hansson@arm.com#include "dev/io_device.hh" 534762SN/A#include "params/DmaDevice.hh" 549342SAndreas.Sandberg@arm.com#include "sim/drain.hh" 559814Sandreas.hansson@arm.com#include "sim/system.hh" 562565SN/A 5710912Sandreas.sandberg@arm.comclass DmaPort : public MasterPort, public Drainable 582384SN/A{ 599307Sandreas.hansson@arm.com private: 602784SN/A 619307Sandreas.hansson@arm.com /** 629307Sandreas.hansson@arm.com * Take the first packet of the transmit list and attempt to send 639307Sandreas.hansson@arm.com * it as a timing request. If it is successful, schedule the 649307Sandreas.hansson@arm.com * sending of the next packet, otherwise remember that we are 659307Sandreas.hansson@arm.com * waiting for a retry. 669307Sandreas.hansson@arm.com */ 679307Sandreas.hansson@arm.com void trySendTimingReq(); 682784SN/A 699307Sandreas.hansson@arm.com /** 709307Sandreas.hansson@arm.com * For timing, attempt to send the first item on the transmit 719307Sandreas.hansson@arm.com * list, and if it is successful and there are more packets 729307Sandreas.hansson@arm.com * waiting, then schedule the sending of the next packet. For 739307Sandreas.hansson@arm.com * atomic, simply send and process everything on the transmit 749307Sandreas.hansson@arm.com * list. 759307Sandreas.hansson@arm.com */ 769307Sandreas.hansson@arm.com void sendDma(); 774435SN/A 789166Sandreas.hansson@arm.com /** 799166Sandreas.hansson@arm.com * Handle a response packet by updating the corresponding DMA 809166Sandreas.hansson@arm.com * request state to reflect the bytes received, and also update 819166Sandreas.hansson@arm.com * the pending request counter. If the DMA request that this 829166Sandreas.hansson@arm.com * packet is part of is complete, then signal the completion event 839166Sandreas.hansson@arm.com * if present, potentially with a delay added to it. 849166Sandreas.hansson@arm.com * 859166Sandreas.hansson@arm.com * @param pkt Response packet to handler 869166Sandreas.hansson@arm.com * @param delay Additional delay for scheduling the completion event 879166Sandreas.hansson@arm.com */ 889166Sandreas.hansson@arm.com void handleResp(PacketPtr pkt, Tick delay = 0); 898948SN/A 909307Sandreas.hansson@arm.com struct DmaReqState : public Packet::SenderState 919307Sandreas.hansson@arm.com { 929307Sandreas.hansson@arm.com /** Event to call on the device when this transaction (all packets) 939307Sandreas.hansson@arm.com * complete. */ 949307Sandreas.hansson@arm.com Event *completionEvent; 959307Sandreas.hansson@arm.com 969307Sandreas.hansson@arm.com /** Total number of bytes that this transaction involves. */ 979307Sandreas.hansson@arm.com const Addr totBytes; 989307Sandreas.hansson@arm.com 999307Sandreas.hansson@arm.com /** Number of bytes that have been acked for this transaction. */ 1009307Sandreas.hansson@arm.com Addr numBytes; 1019307Sandreas.hansson@arm.com 1029307Sandreas.hansson@arm.com /** Amount to delay completion of dma by */ 1039307Sandreas.hansson@arm.com const Tick delay; 1049307Sandreas.hansson@arm.com 1059307Sandreas.hansson@arm.com DmaReqState(Event *ce, Addr tb, Tick _delay) 1069307Sandreas.hansson@arm.com : completionEvent(ce), totBytes(tb), numBytes(0), delay(_delay) 1079307Sandreas.hansson@arm.com {} 1089307Sandreas.hansson@arm.com }; 1099307Sandreas.hansson@arm.com 11011010Sandreas.sandberg@arm.com public: 1119307Sandreas.hansson@arm.com /** The device that owns this port. */ 11211010Sandreas.sandberg@arm.com MemObject *const device; 1139307Sandreas.hansson@arm.com 11411010Sandreas.sandberg@arm.com /** The system that device/port are in. This is used to select which mode 11511010Sandreas.sandberg@arm.com * we are currently operating in. */ 11611010Sandreas.sandberg@arm.com System *const sys; 11711010Sandreas.sandberg@arm.com 11811010Sandreas.sandberg@arm.com /** Id for all requests */ 11911010Sandreas.sandberg@arm.com const MasterID masterId; 12011010Sandreas.sandberg@arm.com 12111010Sandreas.sandberg@arm.com protected: 1229307Sandreas.hansson@arm.com /** Use a deque as we never do any insertion or removal in the middle */ 1239307Sandreas.hansson@arm.com std::deque<PacketPtr> transmitList; 1249307Sandreas.hansson@arm.com 1259307Sandreas.hansson@arm.com /** Event used to schedule a future sending from the transmit list. */ 12612087Sspwilson2@wisc.edu EventFunctionWrapper sendEvent; 1279307Sandreas.hansson@arm.com 1289307Sandreas.hansson@arm.com /** Number of outstanding packets the dma port has. */ 1299307Sandreas.hansson@arm.com uint32_t pendingCount; 1309307Sandreas.hansson@arm.com 1319307Sandreas.hansson@arm.com /** If the port is currently waiting for a retry before it can 1329307Sandreas.hansson@arm.com * send whatever it is that it's sending. */ 1339307Sandreas.hansson@arm.com bool inRetry; 1349307Sandreas.hansson@arm.com 1359307Sandreas.hansson@arm.com protected: 1369307Sandreas.hansson@arm.com 13711169Sandreas.hansson@arm.com bool recvTimingResp(PacketPtr pkt) override; 13811169Sandreas.hansson@arm.com void recvReqRetry() override; 1392384SN/A 1409166Sandreas.hansson@arm.com void queueDma(PacketPtr pkt); 1414435SN/A 1429165Sandreas.hansson@arm.com public: 1432489SN/A 1449165Sandreas.hansson@arm.com DmaPort(MemObject *dev, System *s); 1452565SN/A 14610621SCurtis.Dunham@arm.com RequestPtr dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 14710621SCurtis.Dunham@arm.com uint8_t *data, Tick delay, Request::Flags flag = 0); 1482565SN/A 1499166Sandreas.hansson@arm.com bool dmaPending() const { return pendingCount > 0; } 1502384SN/A 15111168Sandreas.hansson@arm.com DrainState drain() override; 1522384SN/A}; 1532384SN/A 154545SN/Aclass DmaDevice : public PioDevice 155545SN/A{ 1564435SN/A protected: 1578851SN/A DmaPort dmaPort; 158545SN/A 159545SN/A public: 1604762SN/A typedef DmaDeviceParams Params; 1614762SN/A DmaDevice(const Params *p); 1629166Sandreas.hansson@arm.com virtual ~DmaDevice() { } 1634762SN/A 1648851SN/A void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, 1658851SN/A Tick delay = 0) 1664022SN/A { 1678851SN/A dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, delay); 1684022SN/A } 1692565SN/A 1708851SN/A void dmaRead(Addr addr, int size, Event *event, uint8_t *data, 1718851SN/A Tick delay = 0) 1724263SN/A { 1738851SN/A dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, delay); 1744263SN/A } 1752565SN/A 1769307Sandreas.hansson@arm.com bool dmaPending() const { return dmaPort.dmaPending(); } 1778851SN/A 17811169Sandreas.hansson@arm.com void init() override; 1792565SN/A 1809814Sandreas.hansson@arm.com unsigned int cacheBlockSize() const { return sys->cacheLineSize(); } 1814263SN/A 18211169Sandreas.hansson@arm.com BaseMasterPort &getMasterPort(const std::string &if_name, 18311169Sandreas.hansson@arm.com PortID idx = InvalidPortID) override; 1842489SN/A 185545SN/A}; 186545SN/A 18711010Sandreas.sandberg@arm.com/** 18811625Smichael.lebeane@amd.com * DMA callback class. 18911625Smichael.lebeane@amd.com * 19011625Smichael.lebeane@amd.com * Allows one to register for a callback event after a sequence of (potentially 19111625Smichael.lebeane@amd.com * non-contiguous) DMA transfers on a DmaPort completes. Derived classes must 19211625Smichael.lebeane@amd.com * implement the process() method and use getChunkEvent() to allocate a 19311625Smichael.lebeane@amd.com * callback event for each participating DMA. 19411625Smichael.lebeane@amd.com */ 19511625Smichael.lebeane@amd.comclass DmaCallback : public Drainable 19611625Smichael.lebeane@amd.com{ 19711625Smichael.lebeane@amd.com public: 19811625Smichael.lebeane@amd.com virtual const std::string name() const { return "DmaCallback"; } 19911625Smichael.lebeane@amd.com 20011625Smichael.lebeane@amd.com /** 20111625Smichael.lebeane@amd.com * DmaPort ensures that all oustanding DMA accesses have completed before 20211625Smichael.lebeane@amd.com * it finishes draining. However, DmaChunkEvents scheduled with a delay 20311625Smichael.lebeane@amd.com * might still be sitting on the event queue. Therefore, draining is not 20411625Smichael.lebeane@amd.com * complete until count is 0, which ensures that all outstanding 20511625Smichael.lebeane@amd.com * DmaChunkEvents associated with this DmaCallback have fired. 20611625Smichael.lebeane@amd.com */ 20711625Smichael.lebeane@amd.com DrainState drain() override 20811625Smichael.lebeane@amd.com { 20911625Smichael.lebeane@amd.com return count ? DrainState::Draining : DrainState::Drained; 21011625Smichael.lebeane@amd.com } 21111625Smichael.lebeane@amd.com 21211625Smichael.lebeane@amd.com protected: 21311625Smichael.lebeane@amd.com int count; 21411625Smichael.lebeane@amd.com 21511625Smichael.lebeane@amd.com DmaCallback() 21611625Smichael.lebeane@amd.com : count(0) 21711625Smichael.lebeane@amd.com { } 21811625Smichael.lebeane@amd.com 21911625Smichael.lebeane@amd.com virtual ~DmaCallback() { } 22011625Smichael.lebeane@amd.com 22111625Smichael.lebeane@amd.com /** 22211625Smichael.lebeane@amd.com * Callback function invoked on completion of all chunks. 22311625Smichael.lebeane@amd.com */ 22411625Smichael.lebeane@amd.com virtual void process() = 0; 22511625Smichael.lebeane@amd.com 22611625Smichael.lebeane@amd.com private: 22711625Smichael.lebeane@amd.com /** 22811625Smichael.lebeane@amd.com * Called by DMA engine completion event on each chunk completion. 22911625Smichael.lebeane@amd.com * Since the object may delete itself here, callers should not use 23011625Smichael.lebeane@amd.com * the object pointer after calling this function. 23111625Smichael.lebeane@amd.com */ 23211625Smichael.lebeane@amd.com void chunkComplete() 23311625Smichael.lebeane@amd.com { 23411625Smichael.lebeane@amd.com if (--count == 0) { 23511625Smichael.lebeane@amd.com process(); 23611625Smichael.lebeane@amd.com // Need to notify DrainManager that this object is finished 23711625Smichael.lebeane@amd.com // draining, even though it is immediately deleted. 23811625Smichael.lebeane@amd.com signalDrainDone(); 23911625Smichael.lebeane@amd.com delete this; 24011625Smichael.lebeane@amd.com } 24111625Smichael.lebeane@amd.com } 24211625Smichael.lebeane@amd.com 24311625Smichael.lebeane@amd.com public: 24411625Smichael.lebeane@amd.com 24511625Smichael.lebeane@amd.com /** 24611625Smichael.lebeane@amd.com * Request a chunk event. Chunks events should be provided to each DMA 24711625Smichael.lebeane@amd.com * request that wishes to participate in this DmaCallback. 24811625Smichael.lebeane@amd.com */ 24911625Smichael.lebeane@amd.com Event *getChunkEvent() 25011625Smichael.lebeane@amd.com { 25111625Smichael.lebeane@amd.com ++count; 25212131Sspwilson2@wisc.edu return new EventFunctionWrapper([this]{ chunkComplete(); }, name(), 25312131Sspwilson2@wisc.edu true); 25411625Smichael.lebeane@amd.com } 25511625Smichael.lebeane@amd.com}; 25611625Smichael.lebeane@amd.com 25711625Smichael.lebeane@amd.com/** 25811010Sandreas.sandberg@arm.com * Buffered DMA engine helper class 25911010Sandreas.sandberg@arm.com * 26011010Sandreas.sandberg@arm.com * This class implements a simple DMA engine that feeds a FIFO 26111010Sandreas.sandberg@arm.com * buffer. The size of the buffer, the maximum number of pending 26211010Sandreas.sandberg@arm.com * requests and the maximum request size are all set when the engine 26311010Sandreas.sandberg@arm.com * is instantiated. 26411010Sandreas.sandberg@arm.com * 26511010Sandreas.sandberg@arm.com * An <i>asynchronous</i> transfer of a <i>block</i> of data 26611010Sandreas.sandberg@arm.com * (designated by a start address and a size) is started by calling 26711010Sandreas.sandberg@arm.com * the startFill() method. The DMA engine will aggressively try to 26811010Sandreas.sandberg@arm.com * keep the internal FIFO full. As soon as there is room in the FIFO 26911010Sandreas.sandberg@arm.com * for more data <i>and</i> there are free request slots, a new fill 27011010Sandreas.sandberg@arm.com * will be started. 27111010Sandreas.sandberg@arm.com * 27211010Sandreas.sandberg@arm.com * Data in the FIFO can be read back using the get() and tryGet() 27311010Sandreas.sandberg@arm.com * methods. Both request a block of data from the FIFO. However, get() 27411010Sandreas.sandberg@arm.com * panics if the block cannot be satisfied, while tryGet() simply 27511010Sandreas.sandberg@arm.com * returns false. The latter call makes it possible to implement 27611010Sandreas.sandberg@arm.com * custom buffer underrun handling. 27711010Sandreas.sandberg@arm.com * 27811010Sandreas.sandberg@arm.com * A simple use case would be something like this: 27911010Sandreas.sandberg@arm.com * \code{.cpp} 28011010Sandreas.sandberg@arm.com * // Create a DMA engine with a 1KiB buffer. Issue up to 8 concurrent 28111010Sandreas.sandberg@arm.com * // uncacheable 64 byte (maximum) requests. 28211010Sandreas.sandberg@arm.com * DmaReadFifo *dma = new DmaReadFifo(port, 1024, 64, 8, 28311010Sandreas.sandberg@arm.com * Request::UNCACHEABLE); 28411010Sandreas.sandberg@arm.com * 28511010Sandreas.sandberg@arm.com * // Start copying 4KiB data from 0xFF000000 28611010Sandreas.sandberg@arm.com * dma->startFill(0xFF000000, 0x1000); 28711010Sandreas.sandberg@arm.com * 28811010Sandreas.sandberg@arm.com * // Some time later when there is data in the FIFO. 28911010Sandreas.sandberg@arm.com * uint8_t data[8]; 29011010Sandreas.sandberg@arm.com * dma->get(data, sizeof(data)) 29111010Sandreas.sandberg@arm.com * \endcode 29211010Sandreas.sandberg@arm.com * 29311010Sandreas.sandberg@arm.com * 29411010Sandreas.sandberg@arm.com * The DMA engine allows new blocks to be requested as soon as the 29511010Sandreas.sandberg@arm.com * last request for a block has been sent (i.e., there is no need to 29611010Sandreas.sandberg@arm.com * wait for pending requests to complete). This can be queried with 29711010Sandreas.sandberg@arm.com * the atEndOfBlock() method and more advanced implementations may 29811010Sandreas.sandberg@arm.com * override the onEndOfBlock() callback. 29911010Sandreas.sandberg@arm.com */ 30011010Sandreas.sandberg@arm.comclass DmaReadFifo : public Drainable, public Serializable 30111010Sandreas.sandberg@arm.com{ 30211010Sandreas.sandberg@arm.com public: 30311010Sandreas.sandberg@arm.com DmaReadFifo(DmaPort &port, size_t size, 30411010Sandreas.sandberg@arm.com unsigned max_req_size, 30511010Sandreas.sandberg@arm.com unsigned max_pending, 30611010Sandreas.sandberg@arm.com Request::Flags flags = 0); 30711010Sandreas.sandberg@arm.com 30811010Sandreas.sandberg@arm.com ~DmaReadFifo(); 30911010Sandreas.sandberg@arm.com 31011010Sandreas.sandberg@arm.com public: // Serializable 31111168Sandreas.hansson@arm.com void serialize(CheckpointOut &cp) const override; 31211168Sandreas.hansson@arm.com void unserialize(CheckpointIn &cp) override; 31311010Sandreas.sandberg@arm.com 31411010Sandreas.sandberg@arm.com public: // Drainable 31511168Sandreas.hansson@arm.com DrainState drain() override; 31611010Sandreas.sandberg@arm.com 31711010Sandreas.sandberg@arm.com public: // FIFO access 31811010Sandreas.sandberg@arm.com /** 31911010Sandreas.sandberg@arm.com * @{ 32011010Sandreas.sandberg@arm.com * @name FIFO access 32111010Sandreas.sandberg@arm.com */ 32211010Sandreas.sandberg@arm.com /** 32311010Sandreas.sandberg@arm.com * Try to read data from the FIFO. 32411010Sandreas.sandberg@arm.com * 32511010Sandreas.sandberg@arm.com * This method reads len bytes of data from the FIFO and stores 32611010Sandreas.sandberg@arm.com * them in the memory location pointed to by dst. The method 32711010Sandreas.sandberg@arm.com * fails, and no data is written to the buffer, if the FIFO 32811010Sandreas.sandberg@arm.com * doesn't contain enough data to satisfy the request. 32911010Sandreas.sandberg@arm.com * 33011010Sandreas.sandberg@arm.com * @param dst Pointer to a destination buffer 33111010Sandreas.sandberg@arm.com * @param len Amount of data to read. 33211010Sandreas.sandberg@arm.com * @return true on success, false otherwise. 33311010Sandreas.sandberg@arm.com */ 33411010Sandreas.sandberg@arm.com bool tryGet(uint8_t *dst, size_t len); 33511010Sandreas.sandberg@arm.com 33611010Sandreas.sandberg@arm.com template<typename T> 33711010Sandreas.sandberg@arm.com bool tryGet(T &value) { 33811010Sandreas.sandberg@arm.com return tryGet(static_cast<T *>(&value), sizeof(T)); 33911010Sandreas.sandberg@arm.com }; 34011010Sandreas.sandberg@arm.com 34111010Sandreas.sandberg@arm.com /** 34211010Sandreas.sandberg@arm.com * Read data from the FIFO and panic on failure. 34311010Sandreas.sandberg@arm.com * 34411010Sandreas.sandberg@arm.com * @see tryGet() 34511010Sandreas.sandberg@arm.com * 34611010Sandreas.sandberg@arm.com * @param dst Pointer to a destination buffer 34711010Sandreas.sandberg@arm.com * @param len Amount of data to read. 34811010Sandreas.sandberg@arm.com */ 34911010Sandreas.sandberg@arm.com void get(uint8_t *dst, size_t len); 35011010Sandreas.sandberg@arm.com 35111010Sandreas.sandberg@arm.com template<typename T> 35211010Sandreas.sandberg@arm.com T get() { 35311010Sandreas.sandberg@arm.com T value; 35411010Sandreas.sandberg@arm.com get(static_cast<uint8_t *>(&value), sizeof(T)); 35511010Sandreas.sandberg@arm.com return value; 35611010Sandreas.sandberg@arm.com }; 35711010Sandreas.sandberg@arm.com 35811010Sandreas.sandberg@arm.com /** Get the amount of data stored in the FIFO */ 35911010Sandreas.sandberg@arm.com size_t size() const { return buffer.size(); } 36011010Sandreas.sandberg@arm.com /** Flush the FIFO */ 36111010Sandreas.sandberg@arm.com void flush() { buffer.flush(); } 36211010Sandreas.sandberg@arm.com 36311010Sandreas.sandberg@arm.com /** @} */ 36411010Sandreas.sandberg@arm.com public: // FIFO fill control 36511010Sandreas.sandberg@arm.com /** 36611010Sandreas.sandberg@arm.com * @{ 36711010Sandreas.sandberg@arm.com * @name FIFO fill control 36811010Sandreas.sandberg@arm.com */ 36911010Sandreas.sandberg@arm.com /** 37011010Sandreas.sandberg@arm.com * Start filling the FIFO. 37111010Sandreas.sandberg@arm.com * 37211010Sandreas.sandberg@arm.com * @warn It's considered an error to call start on an active DMA 37311010Sandreas.sandberg@arm.com * engine unless the last request from the active block has been 37411010Sandreas.sandberg@arm.com * sent (i.e., atEndOfBlock() is true). 37511010Sandreas.sandberg@arm.com * 37611010Sandreas.sandberg@arm.com * @param start Physical address to copy from. 37711010Sandreas.sandberg@arm.com * @param size Size of the block to copy. 37811010Sandreas.sandberg@arm.com */ 37911010Sandreas.sandberg@arm.com void startFill(Addr start, size_t size); 38011010Sandreas.sandberg@arm.com 38111010Sandreas.sandberg@arm.com /** 38211010Sandreas.sandberg@arm.com * Stop the DMA engine. 38311010Sandreas.sandberg@arm.com * 38411010Sandreas.sandberg@arm.com * Stop filling the FIFO and ignore incoming responses for pending 38511010Sandreas.sandberg@arm.com * requests. The onEndOfBlock() callback will not be called after 38611010Sandreas.sandberg@arm.com * this method has been invoked. However, once the last response 38711010Sandreas.sandberg@arm.com * has been received, the onIdle() callback will still be called. 38811010Sandreas.sandberg@arm.com */ 38911010Sandreas.sandberg@arm.com void stopFill(); 39011010Sandreas.sandberg@arm.com 39111010Sandreas.sandberg@arm.com /** 39211010Sandreas.sandberg@arm.com * Has the DMA engine sent out the last request for the active 39311010Sandreas.sandberg@arm.com * block? 39411010Sandreas.sandberg@arm.com */ 39511010Sandreas.sandberg@arm.com bool atEndOfBlock() const { 39611010Sandreas.sandberg@arm.com return nextAddr == endAddr; 39711010Sandreas.sandberg@arm.com } 39811010Sandreas.sandberg@arm.com 39911010Sandreas.sandberg@arm.com /** 40011010Sandreas.sandberg@arm.com * Is the DMA engine active (i.e., are there still in-flight 40111010Sandreas.sandberg@arm.com * accesses)? 40211010Sandreas.sandberg@arm.com */ 40311010Sandreas.sandberg@arm.com bool isActive() const { 40411010Sandreas.sandberg@arm.com return !(pendingRequests.empty() && atEndOfBlock()); 40511010Sandreas.sandberg@arm.com } 40611010Sandreas.sandberg@arm.com 40711010Sandreas.sandberg@arm.com /** @} */ 40811010Sandreas.sandberg@arm.com protected: // Callbacks 40911010Sandreas.sandberg@arm.com /** 41011010Sandreas.sandberg@arm.com * @{ 41111010Sandreas.sandberg@arm.com * @name Callbacks 41211010Sandreas.sandberg@arm.com */ 41311010Sandreas.sandberg@arm.com /** 41411010Sandreas.sandberg@arm.com * End of block callback 41511010Sandreas.sandberg@arm.com * 41611010Sandreas.sandberg@arm.com * This callback is called <i>once</i> after the last access in a 41711010Sandreas.sandberg@arm.com * block has been sent. It is legal for a derived class to call 41811010Sandreas.sandberg@arm.com * startFill() from this method to initiate a transfer. 41911010Sandreas.sandberg@arm.com */ 42011010Sandreas.sandberg@arm.com virtual void onEndOfBlock() {}; 42111010Sandreas.sandberg@arm.com 42211010Sandreas.sandberg@arm.com /** 42311010Sandreas.sandberg@arm.com * Last response received callback 42411010Sandreas.sandberg@arm.com * 42511010Sandreas.sandberg@arm.com * This callback is called when the DMA engine becomes idle (i.e., 42611010Sandreas.sandberg@arm.com * there are no pending requests). 42711010Sandreas.sandberg@arm.com * 42811010Sandreas.sandberg@arm.com * It is possible for a DMA engine to reach the end of block and 42911010Sandreas.sandberg@arm.com * become idle at the same tick. In such a case, the 43011010Sandreas.sandberg@arm.com * onEndOfBlock() callback will be called first. This callback 43111010Sandreas.sandberg@arm.com * will <i>NOT</i> be called if that callback initiates a new DMA transfer. 43211010Sandreas.sandberg@arm.com */ 43311010Sandreas.sandberg@arm.com virtual void onIdle() {}; 43411010Sandreas.sandberg@arm.com 43511010Sandreas.sandberg@arm.com /** @} */ 43611010Sandreas.sandberg@arm.com private: // Configuration 43711010Sandreas.sandberg@arm.com /** Maximum request size in bytes */ 43811010Sandreas.sandberg@arm.com const Addr maxReqSize; 43911010Sandreas.sandberg@arm.com /** Maximum FIFO size in bytes */ 44011010Sandreas.sandberg@arm.com const size_t fifoSize; 44111010Sandreas.sandberg@arm.com /** Request flags */ 44211010Sandreas.sandberg@arm.com const Request::Flags reqFlags; 44311010Sandreas.sandberg@arm.com 44411010Sandreas.sandberg@arm.com DmaPort &port; 44511010Sandreas.sandberg@arm.com 44611010Sandreas.sandberg@arm.com private: 44711010Sandreas.sandberg@arm.com class DmaDoneEvent : public Event 44811010Sandreas.sandberg@arm.com { 44911010Sandreas.sandberg@arm.com public: 45011010Sandreas.sandberg@arm.com DmaDoneEvent(DmaReadFifo *_parent, size_t max_size); 45111010Sandreas.sandberg@arm.com 45211010Sandreas.sandberg@arm.com void kill(); 45311010Sandreas.sandberg@arm.com void cancel(); 45411010Sandreas.sandberg@arm.com bool canceled() const { return _canceled; } 45511010Sandreas.sandberg@arm.com void reset(size_t size); 45611010Sandreas.sandberg@arm.com void process(); 45711010Sandreas.sandberg@arm.com 45811010Sandreas.sandberg@arm.com bool done() const { return _done; } 45911010Sandreas.sandberg@arm.com size_t requestSize() const { return _requestSize; } 46011010Sandreas.sandberg@arm.com const uint8_t *data() const { return _data.data(); } 46111010Sandreas.sandberg@arm.com uint8_t *data() { return _data.data(); } 46211010Sandreas.sandberg@arm.com 46311010Sandreas.sandberg@arm.com private: 46411010Sandreas.sandberg@arm.com DmaReadFifo *parent; 46511010Sandreas.sandberg@arm.com bool _done; 46611010Sandreas.sandberg@arm.com bool _canceled; 46711010Sandreas.sandberg@arm.com size_t _requestSize; 46811010Sandreas.sandberg@arm.com std::vector<uint8_t> _data; 46911010Sandreas.sandberg@arm.com }; 47011010Sandreas.sandberg@arm.com 47111010Sandreas.sandberg@arm.com typedef std::unique_ptr<DmaDoneEvent> DmaDoneEventUPtr; 47211010Sandreas.sandberg@arm.com 47311010Sandreas.sandberg@arm.com /** 47411010Sandreas.sandberg@arm.com * DMA request done, handle incoming data and issue new 47511010Sandreas.sandberg@arm.com * request. 47611010Sandreas.sandberg@arm.com */ 47711010Sandreas.sandberg@arm.com void dmaDone(); 47811010Sandreas.sandberg@arm.com 47911010Sandreas.sandberg@arm.com /** Handle pending requests that have been flagged as done. */ 48011010Sandreas.sandberg@arm.com void handlePending(); 48111010Sandreas.sandberg@arm.com 48211896Ssudhanshu.jha@arm.com /** Try to issue new DMA requests or bypass DMA requests*/ 48311010Sandreas.sandberg@arm.com void resumeFill(); 48411010Sandreas.sandberg@arm.com 48511896Ssudhanshu.jha@arm.com /** Try to issue new DMA requests during normal execution*/ 48611896Ssudhanshu.jha@arm.com void resumeFillTiming(); 48711896Ssudhanshu.jha@arm.com 48811896Ssudhanshu.jha@arm.com /** Try to bypass DMA requests in KVM execution mode */ 48911896Ssudhanshu.jha@arm.com void resumeFillFunctional(); 49011896Ssudhanshu.jha@arm.com 49111010Sandreas.sandberg@arm.com private: // Internal state 49211010Sandreas.sandberg@arm.com Fifo<uint8_t> buffer; 49311010Sandreas.sandberg@arm.com 49411010Sandreas.sandberg@arm.com Addr nextAddr; 49511010Sandreas.sandberg@arm.com Addr endAddr; 49611010Sandreas.sandberg@arm.com 49711010Sandreas.sandberg@arm.com std::deque<DmaDoneEventUPtr> pendingRequests; 49811010Sandreas.sandberg@arm.com std::deque<DmaDoneEventUPtr> freeRequests; 49911010Sandreas.sandberg@arm.com}; 50011010Sandreas.sandberg@arm.com 5019016Sandreas.hansson@arm.com#endif // __DEV_DMA_DEVICE_HH__ 502