dma_device.cc revision 11010
1545SN/A/*
211010Sandreas.sandberg@arm.com * Copyright (c) 2012, 2015 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 *
142512SN/A * Copyright (c) 2006 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
429166Sandreas.hansson@arm.com *          Andreas Hansson
4311010Sandreas.sandberg@arm.com *          Andreas Sandberg
44545SN/A */
45545SN/A
4611010Sandreas.sandberg@arm.com#include "dev/dma_device.hh"
4711010Sandreas.sandberg@arm.com
4811010Sandreas.sandberg@arm.com#include <utility>
4911010Sandreas.sandberg@arm.com
503090SN/A#include "base/chunk_generator.hh"
518232SN/A#include "debug/DMA.hh"
529152Satgutier@umich.edu#include "debug/Drain.hh"
532901SN/A#include "sim/system.hh"
54545SN/A
559165Sandreas.hansson@arm.comDmaPort::DmaPort(MemObject *dev, System *s)
5611010Sandreas.sandberg@arm.com    : MasterPort(dev->name() + ".dma", dev),
5711010Sandreas.sandberg@arm.com      device(dev), sys(s), masterId(s->getMasterId(dev->name())),
5811010Sandreas.sandberg@arm.com      sendEvent(this), pendingCount(0), inRetry(false)
592489SN/A{ }
602489SN/A
619166Sandreas.hansson@arm.comvoid
629166Sandreas.hansson@arm.comDmaPort::handleResp(PacketPtr pkt, Tick delay)
639166Sandreas.hansson@arm.com{
649166Sandreas.hansson@arm.com    // should always see a response with a sender state
659166Sandreas.hansson@arm.com    assert(pkt->isResponse());
669166Sandreas.hansson@arm.com
679166Sandreas.hansson@arm.com    // get the DMA sender state
689166Sandreas.hansson@arm.com    DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
699166Sandreas.hansson@arm.com    assert(state);
709166Sandreas.hansson@arm.com
719166Sandreas.hansson@arm.com    DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d,"  \
729166Sandreas.hansson@arm.com            " tot: %d sched %d\n",
739166Sandreas.hansson@arm.com            pkt->cmdString(), pkt->getAddr(), pkt->req->getSize(),
749166Sandreas.hansson@arm.com            state->numBytes, state->totBytes,
759166Sandreas.hansson@arm.com            state->completionEvent ?
769166Sandreas.hansson@arm.com            state->completionEvent->scheduled() : 0);
779166Sandreas.hansson@arm.com
789166Sandreas.hansson@arm.com    assert(pendingCount != 0);
799166Sandreas.hansson@arm.com    pendingCount--;
809166Sandreas.hansson@arm.com
819166Sandreas.hansson@arm.com    // update the number of bytes received based on the request rather
829166Sandreas.hansson@arm.com    // than the packet as the latter could be rounded up to line sizes
839166Sandreas.hansson@arm.com    state->numBytes += pkt->req->getSize();
849166Sandreas.hansson@arm.com    assert(state->totBytes >= state->numBytes);
859166Sandreas.hansson@arm.com
869166Sandreas.hansson@arm.com    // if we have reached the total number of bytes for this DMA
879166Sandreas.hansson@arm.com    // request, then signal the completion and delete the sate
889166Sandreas.hansson@arm.com    if (state->totBytes == state->numBytes) {
899166Sandreas.hansson@arm.com        if (state->completionEvent) {
909166Sandreas.hansson@arm.com            delay += state->delay;
919452SAndreas.Sandberg@ARM.com            device->schedule(state->completionEvent, curTick() + delay);
929166Sandreas.hansson@arm.com        }
939166Sandreas.hansson@arm.com        delete state;
949166Sandreas.hansson@arm.com    }
959166Sandreas.hansson@arm.com
969166Sandreas.hansson@arm.com    // delete the request that we created and also the packet
979166Sandreas.hansson@arm.com    delete pkt->req;
989166Sandreas.hansson@arm.com    delete pkt;
999166Sandreas.hansson@arm.com
1009166Sandreas.hansson@arm.com    // we might be drained at this point, if so signal the drain event
10110913Sandreas.sandberg@arm.com    if (pendingCount == 0)
10210913Sandreas.sandberg@arm.com        signalDrainDone();
1039166Sandreas.hansson@arm.com}
1049166Sandreas.hansson@arm.com
1052489SN/Abool
1068975SN/ADmaPort::recvTimingResp(PacketPtr pkt)
1072384SN/A{
10810821Sandreas.hansson@arm.com    // We shouldn't ever get a cacheable block in ownership state
10910821Sandreas.hansson@arm.com    assert(pkt->req->isUncacheable() ||
11010821Sandreas.hansson@arm.com           !(pkt->memInhibitAsserted() && !pkt->sharedAsserted()));
1114435SN/A
1129166Sandreas.hansson@arm.com    handleResp(pkt);
1132569SN/A
1142657SN/A    return true;
1152384SN/A}
116679SN/A
1174762SN/ADmaDevice::DmaDevice(const Params *p)
1189165Sandreas.hansson@arm.com    : PioDevice(p), dmaPort(this, sys)
1192565SN/A{ }
1202384SN/A
1218851SN/Avoid
1228851SN/ADmaDevice::init()
1238851SN/A{
1248851SN/A    if (!dmaPort.isConnected())
1258851SN/A        panic("DMA port of %s not connected to anything!", name());
1268851SN/A    PioDevice::init();
1278851SN/A}
1288851SN/A
12910913Sandreas.sandberg@arm.comDrainState
13010913Sandreas.sandberg@arm.comDmaPort::drain()
1312901SN/A{
13210913Sandreas.sandberg@arm.com    if (pendingCount == 0) {
13310913Sandreas.sandberg@arm.com        return DrainState::Drained;
13410913Sandreas.sandberg@arm.com    } else {
13510913Sandreas.sandberg@arm.com        DPRINTF(Drain, "DmaPort not drained\n");
13610913Sandreas.sandberg@arm.com        return DrainState::Draining;
13710913Sandreas.sandberg@arm.com    }
1382901SN/A}
1392901SN/A
1402384SN/Avoid
14110713Sandreas.hansson@arm.comDmaPort::recvReqRetry()
1422489SN/A{
1434435SN/A    assert(transmitList.size());
1449307Sandreas.hansson@arm.com    trySendTimingReq();
1452489SN/A}
1462641SN/A
14710621SCurtis.Dunham@arm.comRequestPtr
1482641SN/ADmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
1497607SN/A                   uint8_t *data, Tick delay, Request::Flags flag)
1502384SN/A{
1519166Sandreas.hansson@arm.com    // one DMA request sender state for every action, that is then
1529166Sandreas.hansson@arm.com    // split into many requests and packets based on the block size,
1539166Sandreas.hansson@arm.com    // i.e. cache line size
1549016Sandreas.hansson@arm.com    DmaReqState *reqState = new DmaReqState(event, size, delay);
1552384SN/A
15610621SCurtis.Dunham@arm.com    // (functionality added for Table Walker statistics)
15710621SCurtis.Dunham@arm.com    // We're only interested in this when there will only be one request.
15810621SCurtis.Dunham@arm.com    // For simplicity, we return the last request, which would also be
15910621SCurtis.Dunham@arm.com    // the only request in that case.
16010621SCurtis.Dunham@arm.com    RequestPtr req = NULL;
16110621SCurtis.Dunham@arm.com
1624451SN/A    DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
1639166Sandreas.hansson@arm.com            event ? event->scheduled() : -1);
1649814Sandreas.hansson@arm.com    for (ChunkGenerator gen(addr, size, sys->cacheLineSize());
1652406SN/A         !gen.done(); gen.next()) {
16610621SCurtis.Dunham@arm.com        req = new Request(gen.addr(), gen.size(), flag, masterId);
16710024Sdam.sunwoo@arm.com        req->taskId(ContextSwitchTaskId::DMA);
1689166Sandreas.hansson@arm.com        PacketPtr pkt = new Packet(req, cmd);
1692641SN/A
1709166Sandreas.hansson@arm.com        // Increment the data pointer on a write
1719166Sandreas.hansson@arm.com        if (data)
1729166Sandreas.hansson@arm.com            pkt->dataStatic(data + gen.complete());
1732641SN/A
1749166Sandreas.hansson@arm.com        pkt->senderState = reqState;
1752641SN/A
1769166Sandreas.hansson@arm.com        DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
1779166Sandreas.hansson@arm.com                gen.size());
1789166Sandreas.hansson@arm.com        queueDma(pkt);
1792384SN/A    }
1809307Sandreas.hansson@arm.com
1819307Sandreas.hansson@arm.com    // in zero time also initiate the sending of the packets we have
1829307Sandreas.hansson@arm.com    // just created, for atomic this involves actually completing all
1839307Sandreas.hansson@arm.com    // the requests
1849307Sandreas.hansson@arm.com    sendDma();
18510621SCurtis.Dunham@arm.com
18610621SCurtis.Dunham@arm.com    return req;
1872384SN/A}
1882384SN/A
1894435SN/Avoid
1909166Sandreas.hansson@arm.comDmaPort::queueDma(PacketPtr pkt)
1914435SN/A{
1929166Sandreas.hansson@arm.com    transmitList.push_back(pkt);
1934435SN/A
1949166Sandreas.hansson@arm.com    // remember that we have another packet pending, this will only be
1959166Sandreas.hansson@arm.com    // decremented once a response comes back
1969166Sandreas.hansson@arm.com    pendingCount++;
1979307Sandreas.hansson@arm.com}
1989166Sandreas.hansson@arm.com
1999307Sandreas.hansson@arm.comvoid
2009307Sandreas.hansson@arm.comDmaPort::trySendTimingReq()
2019307Sandreas.hansson@arm.com{
2029307Sandreas.hansson@arm.com    // send the first packet on the transmit list and schedule the
2039307Sandreas.hansson@arm.com    // following send if it is successful
2049307Sandreas.hansson@arm.com    PacketPtr pkt = transmitList.front();
2059307Sandreas.hansson@arm.com
2069307Sandreas.hansson@arm.com    DPRINTF(DMA, "Trying to send %s addr %#x\n", pkt->cmdString(),
2079307Sandreas.hansson@arm.com            pkt->getAddr());
2089307Sandreas.hansson@arm.com
2099307Sandreas.hansson@arm.com    inRetry = !sendTimingReq(pkt);
2109307Sandreas.hansson@arm.com    if (!inRetry) {
2119307Sandreas.hansson@arm.com        transmitList.pop_front();
2129307Sandreas.hansson@arm.com        DPRINTF(DMA, "-- Done\n");
2139307Sandreas.hansson@arm.com        // if there is more to do, then do so
2149307Sandreas.hansson@arm.com        if (!transmitList.empty())
2159307Sandreas.hansson@arm.com            // this should ultimately wait for as many cycles as the
2169307Sandreas.hansson@arm.com            // device needs to send the packet, but currently the port
2179307Sandreas.hansson@arm.com            // does not have any known width so simply wait a single
2189307Sandreas.hansson@arm.com            // cycle
2199307Sandreas.hansson@arm.com            device->schedule(sendEvent, device->clockEdge(Cycles(1)));
2209307Sandreas.hansson@arm.com    } else {
2219307Sandreas.hansson@arm.com        DPRINTF(DMA, "-- Failed, waiting for retry\n");
2229307Sandreas.hansson@arm.com    }
2239307Sandreas.hansson@arm.com
2249307Sandreas.hansson@arm.com    DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n",
2259307Sandreas.hansson@arm.com            transmitList.size(), inRetry);
2264435SN/A}
2274435SN/A
2282384SN/Avoid
2294435SN/ADmaPort::sendDma()
2302384SN/A{
2319166Sandreas.hansson@arm.com    // some kind of selcetion between access methods
2322901SN/A    // more work is going to have to be done to make
2332901SN/A    // switching actually work
2344435SN/A    assert(transmitList.size());
2352902SN/A
2369524SAndreas.Sandberg@ARM.com    if (sys->isTimingMode()) {
2379307Sandreas.hansson@arm.com        // if we are either waiting for a retry or are still waiting
2389307Sandreas.hansson@arm.com        // after sending the last packet, then do not proceed
2399307Sandreas.hansson@arm.com        if (inRetry || sendEvent.scheduled()) {
2409307Sandreas.hansson@arm.com            DPRINTF(DMA, "Can't send immediately, waiting to send\n");
2414435SN/A            return;
2424435SN/A        }
2434435SN/A
2449307Sandreas.hansson@arm.com        trySendTimingReq();
2459524SAndreas.Sandberg@ARM.com    } else if (sys->isAtomicMode()) {
2469307Sandreas.hansson@arm.com        // send everything there is to send in zero time
2479307Sandreas.hansson@arm.com        while (!transmitList.empty()) {
2489307Sandreas.hansson@arm.com            PacketPtr pkt = transmitList.front();
2499307Sandreas.hansson@arm.com            transmitList.pop_front();
2504435SN/A
2519307Sandreas.hansson@arm.com            DPRINTF(DMA, "Sending  DMA for addr: %#x size: %d\n",
2529307Sandreas.hansson@arm.com                    pkt->req->getPaddr(), pkt->req->getSize());
2539307Sandreas.hansson@arm.com            Tick lat = sendAtomic(pkt);
2544435SN/A
2559307Sandreas.hansson@arm.com            handleResp(pkt, lat);
2569307Sandreas.hansson@arm.com        }
2579166Sandreas.hansson@arm.com    } else
2589166Sandreas.hansson@arm.com        panic("Unknown memory mode.");
259545SN/A}
2608598SN/A
2619294Sandreas.hansson@arm.comBaseMasterPort &
2629294Sandreas.hansson@arm.comDmaDevice::getMasterPort(const std::string &if_name, PortID idx)
2638598SN/A{
2648598SN/A    if (if_name == "dma") {
2658922SN/A        return dmaPort;
2668598SN/A    }
2678922SN/A    return PioDevice::getMasterPort(if_name, idx);
2688598SN/A}
26911010Sandreas.sandberg@arm.com
27011010Sandreas.sandberg@arm.com
27111010Sandreas.sandberg@arm.com
27211010Sandreas.sandberg@arm.com
27311010Sandreas.sandberg@arm.com
27411010Sandreas.sandberg@arm.comDmaReadFifo::DmaReadFifo(DmaPort &_port, size_t size,
27511010Sandreas.sandberg@arm.com                         unsigned max_req_size,
27611010Sandreas.sandberg@arm.com                         unsigned max_pending,
27711010Sandreas.sandberg@arm.com                         Request::Flags flags)
27811010Sandreas.sandberg@arm.com    : maxReqSize(max_req_size), fifoSize(size),
27911010Sandreas.sandberg@arm.com      reqFlags(flags), port(_port),
28011010Sandreas.sandberg@arm.com      buffer(size),
28111010Sandreas.sandberg@arm.com      nextAddr(0), endAddr(0)
28211010Sandreas.sandberg@arm.com{
28311010Sandreas.sandberg@arm.com    freeRequests.resize(max_pending);
28411010Sandreas.sandberg@arm.com    for (auto &e : freeRequests)
28511010Sandreas.sandberg@arm.com        e.reset(new DmaDoneEvent(this, max_req_size));
28611010Sandreas.sandberg@arm.com
28711010Sandreas.sandberg@arm.com}
28811010Sandreas.sandberg@arm.com
28911010Sandreas.sandberg@arm.comDmaReadFifo::~DmaReadFifo()
29011010Sandreas.sandberg@arm.com{
29111010Sandreas.sandberg@arm.com    for (auto &p : pendingRequests) {
29211010Sandreas.sandberg@arm.com        DmaDoneEvent *e(p.release());
29311010Sandreas.sandberg@arm.com
29411010Sandreas.sandberg@arm.com        if (e->done()) {
29511010Sandreas.sandberg@arm.com            delete e;
29611010Sandreas.sandberg@arm.com        } else {
29711010Sandreas.sandberg@arm.com            // We can't kill in-flight DMAs, so we'll just transfer
29811010Sandreas.sandberg@arm.com            // ownership to the event queue so that they get freed
29911010Sandreas.sandberg@arm.com            // when they are done.
30011010Sandreas.sandberg@arm.com            e->kill();
30111010Sandreas.sandberg@arm.com        }
30211010Sandreas.sandberg@arm.com    }
30311010Sandreas.sandberg@arm.com}
30411010Sandreas.sandberg@arm.com
30511010Sandreas.sandberg@arm.comvoid
30611010Sandreas.sandberg@arm.comDmaReadFifo::serialize(CheckpointOut &cp) const
30711010Sandreas.sandberg@arm.com{
30811010Sandreas.sandberg@arm.com    assert(pendingRequests.empty());
30911010Sandreas.sandberg@arm.com
31011010Sandreas.sandberg@arm.com    SERIALIZE_CONTAINER(buffer);
31111010Sandreas.sandberg@arm.com    SERIALIZE_SCALAR(endAddr);
31211010Sandreas.sandberg@arm.com    SERIALIZE_SCALAR(nextAddr);
31311010Sandreas.sandberg@arm.com}
31411010Sandreas.sandberg@arm.com
31511010Sandreas.sandberg@arm.comvoid
31611010Sandreas.sandberg@arm.comDmaReadFifo::unserialize(CheckpointIn &cp)
31711010Sandreas.sandberg@arm.com{
31811010Sandreas.sandberg@arm.com    UNSERIALIZE_CONTAINER(buffer);
31911010Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(endAddr);
32011010Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(nextAddr);
32111010Sandreas.sandberg@arm.com}
32211010Sandreas.sandberg@arm.com
32311010Sandreas.sandberg@arm.combool
32411010Sandreas.sandberg@arm.comDmaReadFifo::tryGet(uint8_t *dst, size_t len)
32511010Sandreas.sandberg@arm.com{
32611010Sandreas.sandberg@arm.com    if (buffer.size() >= len) {
32711010Sandreas.sandberg@arm.com        buffer.read(dst, len);
32811010Sandreas.sandberg@arm.com        resumeFill();
32911010Sandreas.sandberg@arm.com        return true;
33011010Sandreas.sandberg@arm.com    } else {
33111010Sandreas.sandberg@arm.com        return false;
33211010Sandreas.sandberg@arm.com    }
33311010Sandreas.sandberg@arm.com}
33411010Sandreas.sandberg@arm.com
33511010Sandreas.sandberg@arm.comvoid
33611010Sandreas.sandberg@arm.comDmaReadFifo::get(uint8_t *dst, size_t len)
33711010Sandreas.sandberg@arm.com{
33811010Sandreas.sandberg@arm.com    const bool success(tryGet(dst, len));
33911010Sandreas.sandberg@arm.com    panic_if(!success, "Buffer underrun in DmaReadFifo::get()\n");
34011010Sandreas.sandberg@arm.com}
34111010Sandreas.sandberg@arm.com
34211010Sandreas.sandberg@arm.comvoid
34311010Sandreas.sandberg@arm.comDmaReadFifo::startFill(Addr start, size_t size)
34411010Sandreas.sandberg@arm.com{
34511010Sandreas.sandberg@arm.com    assert(atEndOfBlock());
34611010Sandreas.sandberg@arm.com
34711010Sandreas.sandberg@arm.com    nextAddr = start;
34811010Sandreas.sandberg@arm.com    endAddr = start + size;
34911010Sandreas.sandberg@arm.com    resumeFill();
35011010Sandreas.sandberg@arm.com}
35111010Sandreas.sandberg@arm.com
35211010Sandreas.sandberg@arm.comvoid
35311010Sandreas.sandberg@arm.comDmaReadFifo::stopFill()
35411010Sandreas.sandberg@arm.com{
35511010Sandreas.sandberg@arm.com    // Prevent new DMA requests by setting the next address to the end
35611010Sandreas.sandberg@arm.com    // address. Pending requests will still complete.
35711010Sandreas.sandberg@arm.com    nextAddr = endAddr;
35811010Sandreas.sandberg@arm.com
35911010Sandreas.sandberg@arm.com    // Flag in-flight accesses as canceled. This prevents their data
36011010Sandreas.sandberg@arm.com    // from being written to the FIFO.
36111010Sandreas.sandberg@arm.com    for (auto &p : pendingRequests)
36211010Sandreas.sandberg@arm.com        p->cancel();
36311010Sandreas.sandberg@arm.com}
36411010Sandreas.sandberg@arm.com
36511010Sandreas.sandberg@arm.comvoid
36611010Sandreas.sandberg@arm.comDmaReadFifo::resumeFill()
36711010Sandreas.sandberg@arm.com{
36811010Sandreas.sandberg@arm.com    // Don't try to fetch more data if we are draining. This ensures
36911010Sandreas.sandberg@arm.com    // that the DMA engine settles down before we checkpoint it.
37011010Sandreas.sandberg@arm.com    if (drainState() == DrainState::Draining)
37111010Sandreas.sandberg@arm.com        return;
37211010Sandreas.sandberg@arm.com
37311010Sandreas.sandberg@arm.com    const bool old_eob(atEndOfBlock());
37411010Sandreas.sandberg@arm.com    size_t size_pending(0);
37511010Sandreas.sandberg@arm.com    for (auto &e : pendingRequests)
37611010Sandreas.sandberg@arm.com        size_pending += e->requestSize();
37711010Sandreas.sandberg@arm.com
37811010Sandreas.sandberg@arm.com    while (!freeRequests.empty() && !atEndOfBlock()) {
37911010Sandreas.sandberg@arm.com        const size_t req_size(std::min(maxReqSize, endAddr - nextAddr));
38011010Sandreas.sandberg@arm.com        if (buffer.size() + size_pending + req_size > fifoSize)
38111010Sandreas.sandberg@arm.com            break;
38211010Sandreas.sandberg@arm.com
38311010Sandreas.sandberg@arm.com        DmaDoneEventUPtr event(std::move(freeRequests.front()));
38411010Sandreas.sandberg@arm.com        freeRequests.pop_front();
38511010Sandreas.sandberg@arm.com        assert(event);
38611010Sandreas.sandberg@arm.com
38711010Sandreas.sandberg@arm.com        event->reset(req_size);
38811010Sandreas.sandberg@arm.com        port.dmaAction(MemCmd::ReadReq, nextAddr, req_size, event.get(),
38911010Sandreas.sandberg@arm.com                       event->data(), 0, reqFlags);
39011010Sandreas.sandberg@arm.com        nextAddr += req_size;
39111010Sandreas.sandberg@arm.com        size_pending += req_size;
39211010Sandreas.sandberg@arm.com
39311010Sandreas.sandberg@arm.com        pendingRequests.emplace_back(std::move(event));
39411010Sandreas.sandberg@arm.com    }
39511010Sandreas.sandberg@arm.com
39611010Sandreas.sandberg@arm.com    // EOB can be set before a call to dmaDone() if in-flight accesses
39711010Sandreas.sandberg@arm.com    // have been canceled.
39811010Sandreas.sandberg@arm.com    if (!old_eob && atEndOfBlock())
39911010Sandreas.sandberg@arm.com        onEndOfBlock();
40011010Sandreas.sandberg@arm.com}
40111010Sandreas.sandberg@arm.com
40211010Sandreas.sandberg@arm.comvoid
40311010Sandreas.sandberg@arm.comDmaReadFifo::dmaDone()
40411010Sandreas.sandberg@arm.com{
40511010Sandreas.sandberg@arm.com    const bool old_active(isActive());
40611010Sandreas.sandberg@arm.com
40711010Sandreas.sandberg@arm.com    handlePending();
40811010Sandreas.sandberg@arm.com    resumeFill();
40911010Sandreas.sandberg@arm.com
41011010Sandreas.sandberg@arm.com    if (!old_active && isActive())
41111010Sandreas.sandberg@arm.com        onIdle();
41211010Sandreas.sandberg@arm.com}
41311010Sandreas.sandberg@arm.com
41411010Sandreas.sandberg@arm.comvoid
41511010Sandreas.sandberg@arm.comDmaReadFifo::handlePending()
41611010Sandreas.sandberg@arm.com{
41711010Sandreas.sandberg@arm.com    while (!pendingRequests.empty() && pendingRequests.front()->done()) {
41811010Sandreas.sandberg@arm.com        // Get the first finished pending request
41911010Sandreas.sandberg@arm.com        DmaDoneEventUPtr event(std::move(pendingRequests.front()));
42011010Sandreas.sandberg@arm.com        pendingRequests.pop_front();
42111010Sandreas.sandberg@arm.com
42211010Sandreas.sandberg@arm.com        if (!event->canceled())
42311010Sandreas.sandberg@arm.com            buffer.write(event->data(), event->requestSize());
42411010Sandreas.sandberg@arm.com
42511010Sandreas.sandberg@arm.com        // Move the event to the list of free requests
42611010Sandreas.sandberg@arm.com        freeRequests.emplace_back(std::move(event));
42711010Sandreas.sandberg@arm.com    }
42811010Sandreas.sandberg@arm.com
42911010Sandreas.sandberg@arm.com    if (pendingRequests.empty())
43011010Sandreas.sandberg@arm.com        signalDrainDone();
43111010Sandreas.sandberg@arm.com}
43211010Sandreas.sandberg@arm.com
43311010Sandreas.sandberg@arm.com
43411010Sandreas.sandberg@arm.com
43511010Sandreas.sandberg@arm.comDrainState
43611010Sandreas.sandberg@arm.comDmaReadFifo::drain()
43711010Sandreas.sandberg@arm.com{
43811010Sandreas.sandberg@arm.com    return pendingRequests.empty() ? DrainState::Drained : DrainState::Draining;
43911010Sandreas.sandberg@arm.com}
44011010Sandreas.sandberg@arm.com
44111010Sandreas.sandberg@arm.com
44211010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::DmaDoneEvent(DmaReadFifo *_parent,
44311010Sandreas.sandberg@arm.com                                        size_t max_size)
44411010Sandreas.sandberg@arm.com    : parent(_parent), _done(false), _canceled(false), _data(max_size, 0)
44511010Sandreas.sandberg@arm.com{
44611010Sandreas.sandberg@arm.com}
44711010Sandreas.sandberg@arm.com
44811010Sandreas.sandberg@arm.comvoid
44911010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::kill()
45011010Sandreas.sandberg@arm.com{
45111010Sandreas.sandberg@arm.com    parent = nullptr;
45211010Sandreas.sandberg@arm.com    setFlags(AutoDelete);
45311010Sandreas.sandberg@arm.com}
45411010Sandreas.sandberg@arm.com
45511010Sandreas.sandberg@arm.comvoid
45611010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::cancel()
45711010Sandreas.sandberg@arm.com{
45811010Sandreas.sandberg@arm.com    _canceled = true;
45911010Sandreas.sandberg@arm.com}
46011010Sandreas.sandberg@arm.com
46111010Sandreas.sandberg@arm.comvoid
46211010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::reset(size_t size)
46311010Sandreas.sandberg@arm.com{
46411010Sandreas.sandberg@arm.com    assert(size <= _data.size());
46511010Sandreas.sandberg@arm.com    _done = false;
46611010Sandreas.sandberg@arm.com    _canceled = false;
46711010Sandreas.sandberg@arm.com    _requestSize = size;
46811010Sandreas.sandberg@arm.com}
46911010Sandreas.sandberg@arm.com
47011010Sandreas.sandberg@arm.comvoid
47111010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::process()
47211010Sandreas.sandberg@arm.com{
47311010Sandreas.sandberg@arm.com    if (!parent)
47411010Sandreas.sandberg@arm.com        return;
47511010Sandreas.sandberg@arm.com
47611010Sandreas.sandberg@arm.com    assert(!_done);
47711010Sandreas.sandberg@arm.com    _done = true;
47811010Sandreas.sandberg@arm.com    parent->dmaDone();
47911010Sandreas.sandberg@arm.com}
480