1545SN/A/* 213930Sgiacomo.travaglini@arm.com * Copyright (c) 2012-2013, 2015, 2017, 2019 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 5713892Sgabeblack@google.comclass ClockedObject; 5813892Sgabeblack@google.com 5910912Sandreas.sandberg@arm.comclass DmaPort : public MasterPort, public Drainable 602384SN/A{ 619307Sandreas.hansson@arm.com private: 622784SN/A 639307Sandreas.hansson@arm.com /** 649307Sandreas.hansson@arm.com * Take the first packet of the transmit list and attempt to send 659307Sandreas.hansson@arm.com * it as a timing request. If it is successful, schedule the 669307Sandreas.hansson@arm.com * sending of the next packet, otherwise remember that we are 679307Sandreas.hansson@arm.com * waiting for a retry. 689307Sandreas.hansson@arm.com */ 699307Sandreas.hansson@arm.com void trySendTimingReq(); 702784SN/A 719307Sandreas.hansson@arm.com /** 729307Sandreas.hansson@arm.com * For timing, attempt to send the first item on the transmit 739307Sandreas.hansson@arm.com * list, and if it is successful and there are more packets 749307Sandreas.hansson@arm.com * waiting, then schedule the sending of the next packet. For 759307Sandreas.hansson@arm.com * atomic, simply send and process everything on the transmit 769307Sandreas.hansson@arm.com * list. 779307Sandreas.hansson@arm.com */ 789307Sandreas.hansson@arm.com void sendDma(); 794435SN/A 809166Sandreas.hansson@arm.com /** 819166Sandreas.hansson@arm.com * Handle a response packet by updating the corresponding DMA 829166Sandreas.hansson@arm.com * request state to reflect the bytes received, and also update 839166Sandreas.hansson@arm.com * the pending request counter. If the DMA request that this 849166Sandreas.hansson@arm.com * packet is part of is complete, then signal the completion event 859166Sandreas.hansson@arm.com * if present, potentially with a delay added to it. 869166Sandreas.hansson@arm.com * 879166Sandreas.hansson@arm.com * @param pkt Response packet to handler 889166Sandreas.hansson@arm.com * @param delay Additional delay for scheduling the completion event 899166Sandreas.hansson@arm.com */ 909166Sandreas.hansson@arm.com void handleResp(PacketPtr pkt, Tick delay = 0); 918948SN/A 929307Sandreas.hansson@arm.com struct DmaReqState : public Packet::SenderState 939307Sandreas.hansson@arm.com { 949307Sandreas.hansson@arm.com /** Event to call on the device when this transaction (all packets) 959307Sandreas.hansson@arm.com * complete. */ 969307Sandreas.hansson@arm.com Event *completionEvent; 979307Sandreas.hansson@arm.com 989307Sandreas.hansson@arm.com /** Total number of bytes that this transaction involves. */ 999307Sandreas.hansson@arm.com const Addr totBytes; 1009307Sandreas.hansson@arm.com 1019307Sandreas.hansson@arm.com /** Number of bytes that have been acked for this transaction. */ 1029307Sandreas.hansson@arm.com Addr numBytes; 1039307Sandreas.hansson@arm.com 1049307Sandreas.hansson@arm.com /** Amount to delay completion of dma by */ 1059307Sandreas.hansson@arm.com const Tick delay; 1069307Sandreas.hansson@arm.com 1079307Sandreas.hansson@arm.com DmaReqState(Event *ce, Addr tb, Tick _delay) 1089307Sandreas.hansson@arm.com : completionEvent(ce), totBytes(tb), numBytes(0), delay(_delay) 1099307Sandreas.hansson@arm.com {} 1109307Sandreas.hansson@arm.com }; 1119307Sandreas.hansson@arm.com 11211010Sandreas.sandberg@arm.com public: 1139307Sandreas.hansson@arm.com /** The device that owns this port. */ 11413892Sgabeblack@google.com ClockedObject *const device; 1159307Sandreas.hansson@arm.com 11611010Sandreas.sandberg@arm.com /** The system that device/port are in. This is used to select which mode 11711010Sandreas.sandberg@arm.com * we are currently operating in. */ 11811010Sandreas.sandberg@arm.com System *const sys; 11911010Sandreas.sandberg@arm.com 12011010Sandreas.sandberg@arm.com /** Id for all requests */ 12111010Sandreas.sandberg@arm.com const MasterID masterId; 12211010Sandreas.sandberg@arm.com 12311010Sandreas.sandberg@arm.com protected: 1249307Sandreas.hansson@arm.com /** Use a deque as we never do any insertion or removal in the middle */ 1259307Sandreas.hansson@arm.com std::deque<PacketPtr> transmitList; 1269307Sandreas.hansson@arm.com 1279307Sandreas.hansson@arm.com /** Event used to schedule a future sending from the transmit list. */ 12812087Sspwilson2@wisc.edu EventFunctionWrapper sendEvent; 1299307Sandreas.hansson@arm.com 1309307Sandreas.hansson@arm.com /** Number of outstanding packets the dma port has. */ 1319307Sandreas.hansson@arm.com uint32_t pendingCount; 1329307Sandreas.hansson@arm.com 1339307Sandreas.hansson@arm.com /** If the port is currently waiting for a retry before it can 1349307Sandreas.hansson@arm.com * send whatever it is that it's sending. */ 1359307Sandreas.hansson@arm.com bool inRetry; 1369307Sandreas.hansson@arm.com 13713930Sgiacomo.travaglini@arm.com /** Default streamId */ 13813930Sgiacomo.travaglini@arm.com const uint32_t defaultSid; 13913930Sgiacomo.travaglini@arm.com 14013930Sgiacomo.travaglini@arm.com /** Default substreamId */ 14113930Sgiacomo.travaglini@arm.com const uint32_t defaultSSid; 14213930Sgiacomo.travaglini@arm.com 1439307Sandreas.hansson@arm.com protected: 1449307Sandreas.hansson@arm.com 14511169Sandreas.hansson@arm.com bool recvTimingResp(PacketPtr pkt) override; 14611169Sandreas.hansson@arm.com void recvReqRetry() override; 1472384SN/A 1489166Sandreas.hansson@arm.com void queueDma(PacketPtr pkt); 1494435SN/A 1509165Sandreas.hansson@arm.com public: 1512489SN/A 15213930Sgiacomo.travaglini@arm.com DmaPort(ClockedObject *dev, System *s, 15313930Sgiacomo.travaglini@arm.com uint32_t sid = 0, uint32_t ssid = 0); 1542565SN/A 15513930Sgiacomo.travaglini@arm.com RequestPtr 15613930Sgiacomo.travaglini@arm.com dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 15713930Sgiacomo.travaglini@arm.com uint8_t *data, Tick delay, Request::Flags flag = 0); 15813930Sgiacomo.travaglini@arm.com 15913930Sgiacomo.travaglini@arm.com RequestPtr 16013930Sgiacomo.travaglini@arm.com dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 16113930Sgiacomo.travaglini@arm.com uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay, 16213930Sgiacomo.travaglini@arm.com Request::Flags flag = 0); 1632565SN/A 1649166Sandreas.hansson@arm.com bool dmaPending() const { return pendingCount > 0; } 1652384SN/A 16611168Sandreas.hansson@arm.com DrainState drain() override; 1672384SN/A}; 1682384SN/A 169545SN/Aclass DmaDevice : public PioDevice 170545SN/A{ 1714435SN/A protected: 1728851SN/A DmaPort dmaPort; 173545SN/A 174545SN/A public: 1754762SN/A typedef DmaDeviceParams Params; 1764762SN/A DmaDevice(const Params *p); 1779166Sandreas.hansson@arm.com virtual ~DmaDevice() { } 1784762SN/A 1798851SN/A void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, 18013930Sgiacomo.travaglini@arm.com uint32_t sid, uint32_t ssid, Tick delay = 0) 18113930Sgiacomo.travaglini@arm.com { 18213930Sgiacomo.travaglini@arm.com dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, 18313930Sgiacomo.travaglini@arm.com sid, ssid, delay); 18413930Sgiacomo.travaglini@arm.com } 18513930Sgiacomo.travaglini@arm.com 18613930Sgiacomo.travaglini@arm.com void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, 1878851SN/A Tick delay = 0) 1884022SN/A { 1898851SN/A dmaPort.dmaAction(MemCmd::WriteReq, addr, size, event, data, delay); 1904022SN/A } 1912565SN/A 1928851SN/A void dmaRead(Addr addr, int size, Event *event, uint8_t *data, 19313930Sgiacomo.travaglini@arm.com uint32_t sid, uint32_t ssid, Tick delay = 0) 19413930Sgiacomo.travaglini@arm.com { 19513930Sgiacomo.travaglini@arm.com dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, 19613930Sgiacomo.travaglini@arm.com sid, ssid, delay); 19713930Sgiacomo.travaglini@arm.com } 19813930Sgiacomo.travaglini@arm.com 19913930Sgiacomo.travaglini@arm.com void dmaRead(Addr addr, int size, Event *event, uint8_t *data, 2008851SN/A Tick delay = 0) 2014263SN/A { 2028851SN/A dmaPort.dmaAction(MemCmd::ReadReq, addr, size, event, data, delay); 2034263SN/A } 2042565SN/A 2059307Sandreas.hansson@arm.com bool dmaPending() const { return dmaPort.dmaPending(); } 2068851SN/A 20711169Sandreas.hansson@arm.com void init() override; 2082565SN/A 2099814Sandreas.hansson@arm.com unsigned int cacheBlockSize() const { return sys->cacheLineSize(); } 2104263SN/A 21113784Sgabeblack@google.com Port &getPort(const std::string &if_name, 21213784Sgabeblack@google.com PortID idx=InvalidPortID) override; 2132489SN/A 214545SN/A}; 215545SN/A 21611010Sandreas.sandberg@arm.com/** 21711625Smichael.lebeane@amd.com * DMA callback class. 21811625Smichael.lebeane@amd.com * 21911625Smichael.lebeane@amd.com * Allows one to register for a callback event after a sequence of (potentially 22011625Smichael.lebeane@amd.com * non-contiguous) DMA transfers on a DmaPort completes. Derived classes must 22111625Smichael.lebeane@amd.com * implement the process() method and use getChunkEvent() to allocate a 22211625Smichael.lebeane@amd.com * callback event for each participating DMA. 22311625Smichael.lebeane@amd.com */ 22411625Smichael.lebeane@amd.comclass DmaCallback : public Drainable 22511625Smichael.lebeane@amd.com{ 22611625Smichael.lebeane@amd.com public: 22711625Smichael.lebeane@amd.com virtual const std::string name() const { return "DmaCallback"; } 22811625Smichael.lebeane@amd.com 22911625Smichael.lebeane@amd.com /** 23011625Smichael.lebeane@amd.com * DmaPort ensures that all oustanding DMA accesses have completed before 23111625Smichael.lebeane@amd.com * it finishes draining. However, DmaChunkEvents scheduled with a delay 23211625Smichael.lebeane@amd.com * might still be sitting on the event queue. Therefore, draining is not 23311625Smichael.lebeane@amd.com * complete until count is 0, which ensures that all outstanding 23411625Smichael.lebeane@amd.com * DmaChunkEvents associated with this DmaCallback have fired. 23511625Smichael.lebeane@amd.com */ 23611625Smichael.lebeane@amd.com DrainState drain() override 23711625Smichael.lebeane@amd.com { 23811625Smichael.lebeane@amd.com return count ? DrainState::Draining : DrainState::Drained; 23911625Smichael.lebeane@amd.com } 24011625Smichael.lebeane@amd.com 24111625Smichael.lebeane@amd.com protected: 24211625Smichael.lebeane@amd.com int count; 24311625Smichael.lebeane@amd.com 24411625Smichael.lebeane@amd.com DmaCallback() 24511625Smichael.lebeane@amd.com : count(0) 24611625Smichael.lebeane@amd.com { } 24711625Smichael.lebeane@amd.com 24811625Smichael.lebeane@amd.com virtual ~DmaCallback() { } 24911625Smichael.lebeane@amd.com 25011625Smichael.lebeane@amd.com /** 25111625Smichael.lebeane@amd.com * Callback function invoked on completion of all chunks. 25211625Smichael.lebeane@amd.com */ 25311625Smichael.lebeane@amd.com virtual void process() = 0; 25411625Smichael.lebeane@amd.com 25511625Smichael.lebeane@amd.com private: 25611625Smichael.lebeane@amd.com /** 25711625Smichael.lebeane@amd.com * Called by DMA engine completion event on each chunk completion. 25811625Smichael.lebeane@amd.com * Since the object may delete itself here, callers should not use 25911625Smichael.lebeane@amd.com * the object pointer after calling this function. 26011625Smichael.lebeane@amd.com */ 26111625Smichael.lebeane@amd.com void chunkComplete() 26211625Smichael.lebeane@amd.com { 26311625Smichael.lebeane@amd.com if (--count == 0) { 26411625Smichael.lebeane@amd.com process(); 26511625Smichael.lebeane@amd.com // Need to notify DrainManager that this object is finished 26611625Smichael.lebeane@amd.com // draining, even though it is immediately deleted. 26711625Smichael.lebeane@amd.com signalDrainDone(); 26811625Smichael.lebeane@amd.com delete this; 26911625Smichael.lebeane@amd.com } 27011625Smichael.lebeane@amd.com } 27111625Smichael.lebeane@amd.com 27211625Smichael.lebeane@amd.com public: 27311625Smichael.lebeane@amd.com 27411625Smichael.lebeane@amd.com /** 27511625Smichael.lebeane@amd.com * Request a chunk event. Chunks events should be provided to each DMA 27611625Smichael.lebeane@amd.com * request that wishes to participate in this DmaCallback. 27711625Smichael.lebeane@amd.com */ 27811625Smichael.lebeane@amd.com Event *getChunkEvent() 27911625Smichael.lebeane@amd.com { 28011625Smichael.lebeane@amd.com ++count; 28112131Sspwilson2@wisc.edu return new EventFunctionWrapper([this]{ chunkComplete(); }, name(), 28212131Sspwilson2@wisc.edu true); 28311625Smichael.lebeane@amd.com } 28411625Smichael.lebeane@amd.com}; 28511625Smichael.lebeane@amd.com 28611625Smichael.lebeane@amd.com/** 28711010Sandreas.sandberg@arm.com * Buffered DMA engine helper class 28811010Sandreas.sandberg@arm.com * 28911010Sandreas.sandberg@arm.com * This class implements a simple DMA engine that feeds a FIFO 29011010Sandreas.sandberg@arm.com * buffer. The size of the buffer, the maximum number of pending 29111010Sandreas.sandberg@arm.com * requests and the maximum request size are all set when the engine 29211010Sandreas.sandberg@arm.com * is instantiated. 29311010Sandreas.sandberg@arm.com * 29411010Sandreas.sandberg@arm.com * An <i>asynchronous</i> transfer of a <i>block</i> of data 29511010Sandreas.sandberg@arm.com * (designated by a start address and a size) is started by calling 29611010Sandreas.sandberg@arm.com * the startFill() method. The DMA engine will aggressively try to 29711010Sandreas.sandberg@arm.com * keep the internal FIFO full. As soon as there is room in the FIFO 29811010Sandreas.sandberg@arm.com * for more data <i>and</i> there are free request slots, a new fill 29911010Sandreas.sandberg@arm.com * will be started. 30011010Sandreas.sandberg@arm.com * 30111010Sandreas.sandberg@arm.com * Data in the FIFO can be read back using the get() and tryGet() 30211010Sandreas.sandberg@arm.com * methods. Both request a block of data from the FIFO. However, get() 30311010Sandreas.sandberg@arm.com * panics if the block cannot be satisfied, while tryGet() simply 30411010Sandreas.sandberg@arm.com * returns false. The latter call makes it possible to implement 30511010Sandreas.sandberg@arm.com * custom buffer underrun handling. 30611010Sandreas.sandberg@arm.com * 30711010Sandreas.sandberg@arm.com * A simple use case would be something like this: 30811010Sandreas.sandberg@arm.com * \code{.cpp} 30911010Sandreas.sandberg@arm.com * // Create a DMA engine with a 1KiB buffer. Issue up to 8 concurrent 31011010Sandreas.sandberg@arm.com * // uncacheable 64 byte (maximum) requests. 31111010Sandreas.sandberg@arm.com * DmaReadFifo *dma = new DmaReadFifo(port, 1024, 64, 8, 31211010Sandreas.sandberg@arm.com * Request::UNCACHEABLE); 31311010Sandreas.sandberg@arm.com * 31411010Sandreas.sandberg@arm.com * // Start copying 4KiB data from 0xFF000000 31511010Sandreas.sandberg@arm.com * dma->startFill(0xFF000000, 0x1000); 31611010Sandreas.sandberg@arm.com * 31711010Sandreas.sandberg@arm.com * // Some time later when there is data in the FIFO. 31811010Sandreas.sandberg@arm.com * uint8_t data[8]; 31911010Sandreas.sandberg@arm.com * dma->get(data, sizeof(data)) 32011010Sandreas.sandberg@arm.com * \endcode 32111010Sandreas.sandberg@arm.com * 32211010Sandreas.sandberg@arm.com * 32311010Sandreas.sandberg@arm.com * The DMA engine allows new blocks to be requested as soon as the 32411010Sandreas.sandberg@arm.com * last request for a block has been sent (i.e., there is no need to 32511010Sandreas.sandberg@arm.com * wait for pending requests to complete). This can be queried with 32611010Sandreas.sandberg@arm.com * the atEndOfBlock() method and more advanced implementations may 32711010Sandreas.sandberg@arm.com * override the onEndOfBlock() callback. 32811010Sandreas.sandberg@arm.com */ 32911010Sandreas.sandberg@arm.comclass DmaReadFifo : public Drainable, public Serializable 33011010Sandreas.sandberg@arm.com{ 33111010Sandreas.sandberg@arm.com public: 33211010Sandreas.sandberg@arm.com DmaReadFifo(DmaPort &port, size_t size, 33311010Sandreas.sandberg@arm.com unsigned max_req_size, 33411010Sandreas.sandberg@arm.com unsigned max_pending, 33511010Sandreas.sandberg@arm.com Request::Flags flags = 0); 33611010Sandreas.sandberg@arm.com 33711010Sandreas.sandberg@arm.com ~DmaReadFifo(); 33811010Sandreas.sandberg@arm.com 33911010Sandreas.sandberg@arm.com public: // Serializable 34011168Sandreas.hansson@arm.com void serialize(CheckpointOut &cp) const override; 34111168Sandreas.hansson@arm.com void unserialize(CheckpointIn &cp) override; 34211010Sandreas.sandberg@arm.com 34311010Sandreas.sandberg@arm.com public: // Drainable 34411168Sandreas.hansson@arm.com DrainState drain() override; 34511010Sandreas.sandberg@arm.com 34611010Sandreas.sandberg@arm.com public: // FIFO access 34711010Sandreas.sandberg@arm.com /** 34811010Sandreas.sandberg@arm.com * @{ 34911010Sandreas.sandberg@arm.com * @name FIFO access 35011010Sandreas.sandberg@arm.com */ 35111010Sandreas.sandberg@arm.com /** 35211010Sandreas.sandberg@arm.com * Try to read data from the FIFO. 35311010Sandreas.sandberg@arm.com * 35411010Sandreas.sandberg@arm.com * This method reads len bytes of data from the FIFO and stores 35511010Sandreas.sandberg@arm.com * them in the memory location pointed to by dst. The method 35611010Sandreas.sandberg@arm.com * fails, and no data is written to the buffer, if the FIFO 35711010Sandreas.sandberg@arm.com * doesn't contain enough data to satisfy the request. 35811010Sandreas.sandberg@arm.com * 35911010Sandreas.sandberg@arm.com * @param dst Pointer to a destination buffer 36011010Sandreas.sandberg@arm.com * @param len Amount of data to read. 36111010Sandreas.sandberg@arm.com * @return true on success, false otherwise. 36211010Sandreas.sandberg@arm.com */ 36311010Sandreas.sandberg@arm.com bool tryGet(uint8_t *dst, size_t len); 36411010Sandreas.sandberg@arm.com 36511010Sandreas.sandberg@arm.com template<typename T> 36611010Sandreas.sandberg@arm.com bool tryGet(T &value) { 36711010Sandreas.sandberg@arm.com return tryGet(static_cast<T *>(&value), sizeof(T)); 36811010Sandreas.sandberg@arm.com }; 36911010Sandreas.sandberg@arm.com 37011010Sandreas.sandberg@arm.com /** 37111010Sandreas.sandberg@arm.com * Read data from the FIFO and panic on failure. 37211010Sandreas.sandberg@arm.com * 37311010Sandreas.sandberg@arm.com * @see tryGet() 37411010Sandreas.sandberg@arm.com * 37511010Sandreas.sandberg@arm.com * @param dst Pointer to a destination buffer 37611010Sandreas.sandberg@arm.com * @param len Amount of data to read. 37711010Sandreas.sandberg@arm.com */ 37811010Sandreas.sandberg@arm.com void get(uint8_t *dst, size_t len); 37911010Sandreas.sandberg@arm.com 38011010Sandreas.sandberg@arm.com template<typename T> 38111010Sandreas.sandberg@arm.com T get() { 38211010Sandreas.sandberg@arm.com T value; 38311010Sandreas.sandberg@arm.com get(static_cast<uint8_t *>(&value), sizeof(T)); 38411010Sandreas.sandberg@arm.com return value; 38511010Sandreas.sandberg@arm.com }; 38611010Sandreas.sandberg@arm.com 38711010Sandreas.sandberg@arm.com /** Get the amount of data stored in the FIFO */ 38811010Sandreas.sandberg@arm.com size_t size() const { return buffer.size(); } 38911010Sandreas.sandberg@arm.com /** Flush the FIFO */ 39011010Sandreas.sandberg@arm.com void flush() { buffer.flush(); } 39111010Sandreas.sandberg@arm.com 39211010Sandreas.sandberg@arm.com /** @} */ 39311010Sandreas.sandberg@arm.com public: // FIFO fill control 39411010Sandreas.sandberg@arm.com /** 39511010Sandreas.sandberg@arm.com * @{ 39611010Sandreas.sandberg@arm.com * @name FIFO fill control 39711010Sandreas.sandberg@arm.com */ 39811010Sandreas.sandberg@arm.com /** 39911010Sandreas.sandberg@arm.com * Start filling the FIFO. 40011010Sandreas.sandberg@arm.com * 40111010Sandreas.sandberg@arm.com * @warn It's considered an error to call start on an active DMA 40211010Sandreas.sandberg@arm.com * engine unless the last request from the active block has been 40311010Sandreas.sandberg@arm.com * sent (i.e., atEndOfBlock() is true). 40411010Sandreas.sandberg@arm.com * 40511010Sandreas.sandberg@arm.com * @param start Physical address to copy from. 40611010Sandreas.sandberg@arm.com * @param size Size of the block to copy. 40711010Sandreas.sandberg@arm.com */ 40811010Sandreas.sandberg@arm.com void startFill(Addr start, size_t size); 40911010Sandreas.sandberg@arm.com 41011010Sandreas.sandberg@arm.com /** 41111010Sandreas.sandberg@arm.com * Stop the DMA engine. 41211010Sandreas.sandberg@arm.com * 41311010Sandreas.sandberg@arm.com * Stop filling the FIFO and ignore incoming responses for pending 41411010Sandreas.sandberg@arm.com * requests. The onEndOfBlock() callback will not be called after 41511010Sandreas.sandberg@arm.com * this method has been invoked. However, once the last response 41611010Sandreas.sandberg@arm.com * has been received, the onIdle() callback will still be called. 41711010Sandreas.sandberg@arm.com */ 41811010Sandreas.sandberg@arm.com void stopFill(); 41911010Sandreas.sandberg@arm.com 42011010Sandreas.sandberg@arm.com /** 42111010Sandreas.sandberg@arm.com * Has the DMA engine sent out the last request for the active 42211010Sandreas.sandberg@arm.com * block? 42311010Sandreas.sandberg@arm.com */ 42411010Sandreas.sandberg@arm.com bool atEndOfBlock() const { 42511010Sandreas.sandberg@arm.com return nextAddr == endAddr; 42611010Sandreas.sandberg@arm.com } 42711010Sandreas.sandberg@arm.com 42811010Sandreas.sandberg@arm.com /** 42911010Sandreas.sandberg@arm.com * Is the DMA engine active (i.e., are there still in-flight 43011010Sandreas.sandberg@arm.com * accesses)? 43111010Sandreas.sandberg@arm.com */ 43211010Sandreas.sandberg@arm.com bool isActive() const { 43311010Sandreas.sandberg@arm.com return !(pendingRequests.empty() && atEndOfBlock()); 43411010Sandreas.sandberg@arm.com } 43511010Sandreas.sandberg@arm.com 43611010Sandreas.sandberg@arm.com /** @} */ 43711010Sandreas.sandberg@arm.com protected: // Callbacks 43811010Sandreas.sandberg@arm.com /** 43911010Sandreas.sandberg@arm.com * @{ 44011010Sandreas.sandberg@arm.com * @name Callbacks 44111010Sandreas.sandberg@arm.com */ 44211010Sandreas.sandberg@arm.com /** 44311010Sandreas.sandberg@arm.com * End of block callback 44411010Sandreas.sandberg@arm.com * 44511010Sandreas.sandberg@arm.com * This callback is called <i>once</i> after the last access in a 44611010Sandreas.sandberg@arm.com * block has been sent. It is legal for a derived class to call 44711010Sandreas.sandberg@arm.com * startFill() from this method to initiate a transfer. 44811010Sandreas.sandberg@arm.com */ 44911010Sandreas.sandberg@arm.com virtual void onEndOfBlock() {}; 45011010Sandreas.sandberg@arm.com 45111010Sandreas.sandberg@arm.com /** 45211010Sandreas.sandberg@arm.com * Last response received callback 45311010Sandreas.sandberg@arm.com * 45411010Sandreas.sandberg@arm.com * This callback is called when the DMA engine becomes idle (i.e., 45511010Sandreas.sandberg@arm.com * there are no pending requests). 45611010Sandreas.sandberg@arm.com * 45711010Sandreas.sandberg@arm.com * It is possible for a DMA engine to reach the end of block and 45811010Sandreas.sandberg@arm.com * become idle at the same tick. In such a case, the 45911010Sandreas.sandberg@arm.com * onEndOfBlock() callback will be called first. This callback 46011010Sandreas.sandberg@arm.com * will <i>NOT</i> be called if that callback initiates a new DMA transfer. 46111010Sandreas.sandberg@arm.com */ 46211010Sandreas.sandberg@arm.com virtual void onIdle() {}; 46311010Sandreas.sandberg@arm.com 46411010Sandreas.sandberg@arm.com /** @} */ 46511010Sandreas.sandberg@arm.com private: // Configuration 46611010Sandreas.sandberg@arm.com /** Maximum request size in bytes */ 46711010Sandreas.sandberg@arm.com const Addr maxReqSize; 46811010Sandreas.sandberg@arm.com /** Maximum FIFO size in bytes */ 46911010Sandreas.sandberg@arm.com const size_t fifoSize; 47011010Sandreas.sandberg@arm.com /** Request flags */ 47111010Sandreas.sandberg@arm.com const Request::Flags reqFlags; 47211010Sandreas.sandberg@arm.com 47311010Sandreas.sandberg@arm.com DmaPort &port; 47411010Sandreas.sandberg@arm.com 47511010Sandreas.sandberg@arm.com private: 47611010Sandreas.sandberg@arm.com class DmaDoneEvent : public Event 47711010Sandreas.sandberg@arm.com { 47811010Sandreas.sandberg@arm.com public: 47911010Sandreas.sandberg@arm.com DmaDoneEvent(DmaReadFifo *_parent, size_t max_size); 48011010Sandreas.sandberg@arm.com 48111010Sandreas.sandberg@arm.com void kill(); 48211010Sandreas.sandberg@arm.com void cancel(); 48311010Sandreas.sandberg@arm.com bool canceled() const { return _canceled; } 48411010Sandreas.sandberg@arm.com void reset(size_t size); 48511010Sandreas.sandberg@arm.com void process(); 48611010Sandreas.sandberg@arm.com 48711010Sandreas.sandberg@arm.com bool done() const { return _done; } 48811010Sandreas.sandberg@arm.com size_t requestSize() const { return _requestSize; } 48911010Sandreas.sandberg@arm.com const uint8_t *data() const { return _data.data(); } 49011010Sandreas.sandberg@arm.com uint8_t *data() { return _data.data(); } 49111010Sandreas.sandberg@arm.com 49211010Sandreas.sandberg@arm.com private: 49311010Sandreas.sandberg@arm.com DmaReadFifo *parent; 49411010Sandreas.sandberg@arm.com bool _done; 49511010Sandreas.sandberg@arm.com bool _canceled; 49611010Sandreas.sandberg@arm.com size_t _requestSize; 49711010Sandreas.sandberg@arm.com std::vector<uint8_t> _data; 49811010Sandreas.sandberg@arm.com }; 49911010Sandreas.sandberg@arm.com 50011010Sandreas.sandberg@arm.com typedef std::unique_ptr<DmaDoneEvent> DmaDoneEventUPtr; 50111010Sandreas.sandberg@arm.com 50211010Sandreas.sandberg@arm.com /** 50311010Sandreas.sandberg@arm.com * DMA request done, handle incoming data and issue new 50411010Sandreas.sandberg@arm.com * request. 50511010Sandreas.sandberg@arm.com */ 50611010Sandreas.sandberg@arm.com void dmaDone(); 50711010Sandreas.sandberg@arm.com 50811010Sandreas.sandberg@arm.com /** Handle pending requests that have been flagged as done. */ 50911010Sandreas.sandberg@arm.com void handlePending(); 51011010Sandreas.sandberg@arm.com 51111896Ssudhanshu.jha@arm.com /** Try to issue new DMA requests or bypass DMA requests*/ 51211010Sandreas.sandberg@arm.com void resumeFill(); 51311010Sandreas.sandberg@arm.com 51411896Ssudhanshu.jha@arm.com /** Try to issue new DMA requests during normal execution*/ 51511896Ssudhanshu.jha@arm.com void resumeFillTiming(); 51611896Ssudhanshu.jha@arm.com 51711896Ssudhanshu.jha@arm.com /** Try to bypass DMA requests in KVM execution mode */ 51811896Ssudhanshu.jha@arm.com void resumeFillFunctional(); 51911896Ssudhanshu.jha@arm.com 52011010Sandreas.sandberg@arm.com private: // Internal state 52111010Sandreas.sandberg@arm.com Fifo<uint8_t> buffer; 52211010Sandreas.sandberg@arm.com 52311010Sandreas.sandberg@arm.com Addr nextAddr; 52411010Sandreas.sandberg@arm.com Addr endAddr; 52511010Sandreas.sandberg@arm.com 52611010Sandreas.sandberg@arm.com std::deque<DmaDoneEventUPtr> pendingRequests; 52711010Sandreas.sandberg@arm.com std::deque<DmaDoneEventUPtr> freeRequests; 52811010Sandreas.sandberg@arm.com}; 52911010Sandreas.sandberg@arm.com 5309016Sandreas.hansson@arm.com#endif // __DEV_DMA_DEVICE_HH__ 531