dma_device.cc revision 12680
1545SN/A/*
211896Ssudhanshu.jha@arm.com * Copyright (c) 2012, 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 *
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"
5311896Ssudhanshu.jha@arm.com#include "mem/port_proxy.hh"
542901SN/A#include "sim/system.hh"
55545SN/A
569165Sandreas.hansson@arm.comDmaPort::DmaPort(MemObject *dev, System *s)
5711010Sandreas.sandberg@arm.com    : MasterPort(dev->name() + ".dma", dev),
5812680Sgiacomo.travaglini@arm.com      device(dev), sys(s), masterId(s->getMasterId(dev)),
5912087Sspwilson2@wisc.edu      sendEvent([this]{ sendDma(); }, dev->name()),
6012087Sspwilson2@wisc.edu      pendingCount(0), inRetry(false)
612489SN/A{ }
622489SN/A
639166Sandreas.hansson@arm.comvoid
649166Sandreas.hansson@arm.comDmaPort::handleResp(PacketPtr pkt, Tick delay)
659166Sandreas.hansson@arm.com{
669166Sandreas.hansson@arm.com    // should always see a response with a sender state
679166Sandreas.hansson@arm.com    assert(pkt->isResponse());
689166Sandreas.hansson@arm.com
699166Sandreas.hansson@arm.com    // get the DMA sender state
709166Sandreas.hansson@arm.com    DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
719166Sandreas.hansson@arm.com    assert(state);
729166Sandreas.hansson@arm.com
739166Sandreas.hansson@arm.com    DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d,"  \
749166Sandreas.hansson@arm.com            " tot: %d sched %d\n",
759166Sandreas.hansson@arm.com            pkt->cmdString(), pkt->getAddr(), pkt->req->getSize(),
769166Sandreas.hansson@arm.com            state->numBytes, state->totBytes,
779166Sandreas.hansson@arm.com            state->completionEvent ?
789166Sandreas.hansson@arm.com            state->completionEvent->scheduled() : 0);
799166Sandreas.hansson@arm.com
809166Sandreas.hansson@arm.com    assert(pendingCount != 0);
819166Sandreas.hansson@arm.com    pendingCount--;
829166Sandreas.hansson@arm.com
839166Sandreas.hansson@arm.com    // update the number of bytes received based on the request rather
849166Sandreas.hansson@arm.com    // than the packet as the latter could be rounded up to line sizes
859166Sandreas.hansson@arm.com    state->numBytes += pkt->req->getSize();
869166Sandreas.hansson@arm.com    assert(state->totBytes >= state->numBytes);
879166Sandreas.hansson@arm.com
889166Sandreas.hansson@arm.com    // if we have reached the total number of bytes for this DMA
899166Sandreas.hansson@arm.com    // request, then signal the completion and delete the sate
909166Sandreas.hansson@arm.com    if (state->totBytes == state->numBytes) {
919166Sandreas.hansson@arm.com        if (state->completionEvent) {
929166Sandreas.hansson@arm.com            delay += state->delay;
939452SAndreas.Sandberg@ARM.com            device->schedule(state->completionEvent, curTick() + delay);
949166Sandreas.hansson@arm.com        }
959166Sandreas.hansson@arm.com        delete state;
969166Sandreas.hansson@arm.com    }
979166Sandreas.hansson@arm.com
989166Sandreas.hansson@arm.com    // delete the request that we created and also the packet
999166Sandreas.hansson@arm.com    delete pkt->req;
1009166Sandreas.hansson@arm.com    delete pkt;
1019166Sandreas.hansson@arm.com
1029166Sandreas.hansson@arm.com    // we might be drained at this point, if so signal the drain event
10310913Sandreas.sandberg@arm.com    if (pendingCount == 0)
10410913Sandreas.sandberg@arm.com        signalDrainDone();
1059166Sandreas.hansson@arm.com}
1069166Sandreas.hansson@arm.com
1072489SN/Abool
1088975SN/ADmaPort::recvTimingResp(PacketPtr pkt)
1092384SN/A{
11011284Sandreas.hansson@arm.com    // We shouldn't ever get a cacheable block in Modified state
11110821Sandreas.hansson@arm.com    assert(pkt->req->isUncacheable() ||
11211284Sandreas.hansson@arm.com           !(pkt->cacheResponding() && !pkt->hasSharers()));
1134435SN/A
1149166Sandreas.hansson@arm.com    handleResp(pkt);
1152569SN/A
1162657SN/A    return true;
1172384SN/A}
118679SN/A
1194762SN/ADmaDevice::DmaDevice(const Params *p)
1209165Sandreas.hansson@arm.com    : PioDevice(p), dmaPort(this, sys)
1212565SN/A{ }
1222384SN/A
1238851SN/Avoid
1248851SN/ADmaDevice::init()
1258851SN/A{
1268851SN/A    if (!dmaPort.isConnected())
1278851SN/A        panic("DMA port of %s not connected to anything!", name());
1288851SN/A    PioDevice::init();
1298851SN/A}
1308851SN/A
13110913Sandreas.sandberg@arm.comDrainState
13210913Sandreas.sandberg@arm.comDmaPort::drain()
1332901SN/A{
13410913Sandreas.sandberg@arm.com    if (pendingCount == 0) {
13510913Sandreas.sandberg@arm.com        return DrainState::Drained;
13610913Sandreas.sandberg@arm.com    } else {
13710913Sandreas.sandberg@arm.com        DPRINTF(Drain, "DmaPort not drained\n");
13810913Sandreas.sandberg@arm.com        return DrainState::Draining;
13910913Sandreas.sandberg@arm.com    }
1402901SN/A}
1412901SN/A
1422384SN/Avoid
14310713Sandreas.hansson@arm.comDmaPort::recvReqRetry()
1442489SN/A{
1454435SN/A    assert(transmitList.size());
1469307Sandreas.hansson@arm.com    trySendTimingReq();
1472489SN/A}
1482641SN/A
14910621SCurtis.Dunham@arm.comRequestPtr
1502641SN/ADmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
1517607SN/A                   uint8_t *data, Tick delay, Request::Flags flag)
1522384SN/A{
1539166Sandreas.hansson@arm.com    // one DMA request sender state for every action, that is then
1549166Sandreas.hansson@arm.com    // split into many requests and packets based on the block size,
1559166Sandreas.hansson@arm.com    // i.e. cache line size
1569016Sandreas.hansson@arm.com    DmaReqState *reqState = new DmaReqState(event, size, delay);
1572384SN/A
15810621SCurtis.Dunham@arm.com    // (functionality added for Table Walker statistics)
15910621SCurtis.Dunham@arm.com    // We're only interested in this when there will only be one request.
16010621SCurtis.Dunham@arm.com    // For simplicity, we return the last request, which would also be
16110621SCurtis.Dunham@arm.com    // the only request in that case.
16210621SCurtis.Dunham@arm.com    RequestPtr req = NULL;
16310621SCurtis.Dunham@arm.com
1644451SN/A    DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
1659166Sandreas.hansson@arm.com            event ? event->scheduled() : -1);
1669814Sandreas.hansson@arm.com    for (ChunkGenerator gen(addr, size, sys->cacheLineSize());
1672406SN/A         !gen.done(); gen.next()) {
16810621SCurtis.Dunham@arm.com        req = new Request(gen.addr(), gen.size(), flag, masterId);
16910024Sdam.sunwoo@arm.com        req->taskId(ContextSwitchTaskId::DMA);
1709166Sandreas.hansson@arm.com        PacketPtr pkt = new Packet(req, cmd);
1712641SN/A
1729166Sandreas.hansson@arm.com        // Increment the data pointer on a write
1739166Sandreas.hansson@arm.com        if (data)
1749166Sandreas.hansson@arm.com            pkt->dataStatic(data + gen.complete());
1752641SN/A
1769166Sandreas.hansson@arm.com        pkt->senderState = reqState;
1772641SN/A
1789166Sandreas.hansson@arm.com        DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
1799166Sandreas.hansson@arm.com                gen.size());
1809166Sandreas.hansson@arm.com        queueDma(pkt);
1812384SN/A    }
1829307Sandreas.hansson@arm.com
1839307Sandreas.hansson@arm.com    // in zero time also initiate the sending of the packets we have
1849307Sandreas.hansson@arm.com    // just created, for atomic this involves actually completing all
1859307Sandreas.hansson@arm.com    // the requests
1869307Sandreas.hansson@arm.com    sendDma();
18710621SCurtis.Dunham@arm.com
18810621SCurtis.Dunham@arm.com    return req;
1892384SN/A}
1902384SN/A
1914435SN/Avoid
1929166Sandreas.hansson@arm.comDmaPort::queueDma(PacketPtr pkt)
1934435SN/A{
1949166Sandreas.hansson@arm.com    transmitList.push_back(pkt);
1954435SN/A
1969166Sandreas.hansson@arm.com    // remember that we have another packet pending, this will only be
1979166Sandreas.hansson@arm.com    // decremented once a response comes back
1989166Sandreas.hansson@arm.com    pendingCount++;
1999307Sandreas.hansson@arm.com}
2009166Sandreas.hansson@arm.com
2019307Sandreas.hansson@arm.comvoid
2029307Sandreas.hansson@arm.comDmaPort::trySendTimingReq()
2039307Sandreas.hansson@arm.com{
2049307Sandreas.hansson@arm.com    // send the first packet on the transmit list and schedule the
2059307Sandreas.hansson@arm.com    // following send if it is successful
2069307Sandreas.hansson@arm.com    PacketPtr pkt = transmitList.front();
2079307Sandreas.hansson@arm.com
2089307Sandreas.hansson@arm.com    DPRINTF(DMA, "Trying to send %s addr %#x\n", pkt->cmdString(),
2099307Sandreas.hansson@arm.com            pkt->getAddr());
2109307Sandreas.hansson@arm.com
2119307Sandreas.hansson@arm.com    inRetry = !sendTimingReq(pkt);
2129307Sandreas.hansson@arm.com    if (!inRetry) {
2139307Sandreas.hansson@arm.com        transmitList.pop_front();
2149307Sandreas.hansson@arm.com        DPRINTF(DMA, "-- Done\n");
2159307Sandreas.hansson@arm.com        // if there is more to do, then do so
2169307Sandreas.hansson@arm.com        if (!transmitList.empty())
2179307Sandreas.hansson@arm.com            // this should ultimately wait for as many cycles as the
2189307Sandreas.hansson@arm.com            // device needs to send the packet, but currently the port
2199307Sandreas.hansson@arm.com            // does not have any known width so simply wait a single
2209307Sandreas.hansson@arm.com            // cycle
2219307Sandreas.hansson@arm.com            device->schedule(sendEvent, device->clockEdge(Cycles(1)));
2229307Sandreas.hansson@arm.com    } else {
2239307Sandreas.hansson@arm.com        DPRINTF(DMA, "-- Failed, waiting for retry\n");
2249307Sandreas.hansson@arm.com    }
2259307Sandreas.hansson@arm.com
2269307Sandreas.hansson@arm.com    DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n",
2279307Sandreas.hansson@arm.com            transmitList.size(), inRetry);
2284435SN/A}
2294435SN/A
2302384SN/Avoid
2314435SN/ADmaPort::sendDma()
2322384SN/A{
2339166Sandreas.hansson@arm.com    // some kind of selcetion between access methods
2342901SN/A    // more work is going to have to be done to make
2352901SN/A    // switching actually work
2364435SN/A    assert(transmitList.size());
2372902SN/A
2389524SAndreas.Sandberg@ARM.com    if (sys->isTimingMode()) {
2399307Sandreas.hansson@arm.com        // if we are either waiting for a retry or are still waiting
2409307Sandreas.hansson@arm.com        // after sending the last packet, then do not proceed
2419307Sandreas.hansson@arm.com        if (inRetry || sendEvent.scheduled()) {
2429307Sandreas.hansson@arm.com            DPRINTF(DMA, "Can't send immediately, waiting to send\n");
2434435SN/A            return;
2444435SN/A        }
2454435SN/A
2469307Sandreas.hansson@arm.com        trySendTimingReq();
2479524SAndreas.Sandberg@ARM.com    } else if (sys->isAtomicMode()) {
2489307Sandreas.hansson@arm.com        // send everything there is to send in zero time
2499307Sandreas.hansson@arm.com        while (!transmitList.empty()) {
2509307Sandreas.hansson@arm.com            PacketPtr pkt = transmitList.front();
2519307Sandreas.hansson@arm.com            transmitList.pop_front();
2524435SN/A
2539307Sandreas.hansson@arm.com            DPRINTF(DMA, "Sending  DMA for addr: %#x size: %d\n",
2549307Sandreas.hansson@arm.com                    pkt->req->getPaddr(), pkt->req->getSize());
2559307Sandreas.hansson@arm.com            Tick lat = sendAtomic(pkt);
2564435SN/A
2579307Sandreas.hansson@arm.com            handleResp(pkt, lat);
2589307Sandreas.hansson@arm.com        }
2599166Sandreas.hansson@arm.com    } else
2609166Sandreas.hansson@arm.com        panic("Unknown memory mode.");
261545SN/A}
2628598SN/A
2639294Sandreas.hansson@arm.comBaseMasterPort &
2649294Sandreas.hansson@arm.comDmaDevice::getMasterPort(const std::string &if_name, PortID idx)
2658598SN/A{
2668598SN/A    if (if_name == "dma") {
2678922SN/A        return dmaPort;
2688598SN/A    }
2698922SN/A    return PioDevice::getMasterPort(if_name, idx);
2708598SN/A}
27111010Sandreas.sandberg@arm.com
27211010Sandreas.sandberg@arm.com
27311010Sandreas.sandberg@arm.com
27411010Sandreas.sandberg@arm.com
27511010Sandreas.sandberg@arm.com
27611010Sandreas.sandberg@arm.comDmaReadFifo::DmaReadFifo(DmaPort &_port, size_t size,
27711010Sandreas.sandberg@arm.com                         unsigned max_req_size,
27811010Sandreas.sandberg@arm.com                         unsigned max_pending,
27911010Sandreas.sandberg@arm.com                         Request::Flags flags)
28011010Sandreas.sandberg@arm.com    : maxReqSize(max_req_size), fifoSize(size),
28111010Sandreas.sandberg@arm.com      reqFlags(flags), port(_port),
28211010Sandreas.sandberg@arm.com      buffer(size),
28311010Sandreas.sandberg@arm.com      nextAddr(0), endAddr(0)
28411010Sandreas.sandberg@arm.com{
28511010Sandreas.sandberg@arm.com    freeRequests.resize(max_pending);
28611010Sandreas.sandberg@arm.com    for (auto &e : freeRequests)
28711010Sandreas.sandberg@arm.com        e.reset(new DmaDoneEvent(this, max_req_size));
28811010Sandreas.sandberg@arm.com
28911010Sandreas.sandberg@arm.com}
29011010Sandreas.sandberg@arm.com
29111010Sandreas.sandberg@arm.comDmaReadFifo::~DmaReadFifo()
29211010Sandreas.sandberg@arm.com{
29311010Sandreas.sandberg@arm.com    for (auto &p : pendingRequests) {
29411010Sandreas.sandberg@arm.com        DmaDoneEvent *e(p.release());
29511010Sandreas.sandberg@arm.com
29611010Sandreas.sandberg@arm.com        if (e->done()) {
29711010Sandreas.sandberg@arm.com            delete e;
29811010Sandreas.sandberg@arm.com        } else {
29911010Sandreas.sandberg@arm.com            // We can't kill in-flight DMAs, so we'll just transfer
30011010Sandreas.sandberg@arm.com            // ownership to the event queue so that they get freed
30111010Sandreas.sandberg@arm.com            // when they are done.
30211010Sandreas.sandberg@arm.com            e->kill();
30311010Sandreas.sandberg@arm.com        }
30411010Sandreas.sandberg@arm.com    }
30511010Sandreas.sandberg@arm.com}
30611010Sandreas.sandberg@arm.com
30711010Sandreas.sandberg@arm.comvoid
30811010Sandreas.sandberg@arm.comDmaReadFifo::serialize(CheckpointOut &cp) const
30911010Sandreas.sandberg@arm.com{
31011010Sandreas.sandberg@arm.com    assert(pendingRequests.empty());
31111010Sandreas.sandberg@arm.com
31211010Sandreas.sandberg@arm.com    SERIALIZE_CONTAINER(buffer);
31311010Sandreas.sandberg@arm.com    SERIALIZE_SCALAR(endAddr);
31411010Sandreas.sandberg@arm.com    SERIALIZE_SCALAR(nextAddr);
31511010Sandreas.sandberg@arm.com}
31611010Sandreas.sandberg@arm.com
31711010Sandreas.sandberg@arm.comvoid
31811010Sandreas.sandberg@arm.comDmaReadFifo::unserialize(CheckpointIn &cp)
31911010Sandreas.sandberg@arm.com{
32011010Sandreas.sandberg@arm.com    UNSERIALIZE_CONTAINER(buffer);
32111010Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(endAddr);
32211010Sandreas.sandberg@arm.com    UNSERIALIZE_SCALAR(nextAddr);
32311010Sandreas.sandberg@arm.com}
32411010Sandreas.sandberg@arm.com
32511010Sandreas.sandberg@arm.combool
32611010Sandreas.sandberg@arm.comDmaReadFifo::tryGet(uint8_t *dst, size_t len)
32711010Sandreas.sandberg@arm.com{
32811010Sandreas.sandberg@arm.com    if (buffer.size() >= len) {
32911010Sandreas.sandberg@arm.com        buffer.read(dst, len);
33011010Sandreas.sandberg@arm.com        resumeFill();
33111010Sandreas.sandberg@arm.com        return true;
33211010Sandreas.sandberg@arm.com    } else {
33311010Sandreas.sandberg@arm.com        return false;
33411010Sandreas.sandberg@arm.com    }
33511010Sandreas.sandberg@arm.com}
33611010Sandreas.sandberg@arm.com
33711010Sandreas.sandberg@arm.comvoid
33811010Sandreas.sandberg@arm.comDmaReadFifo::get(uint8_t *dst, size_t len)
33911010Sandreas.sandberg@arm.com{
34011010Sandreas.sandberg@arm.com    const bool success(tryGet(dst, len));
34111010Sandreas.sandberg@arm.com    panic_if(!success, "Buffer underrun in DmaReadFifo::get()\n");
34211010Sandreas.sandberg@arm.com}
34311010Sandreas.sandberg@arm.com
34411010Sandreas.sandberg@arm.comvoid
34511010Sandreas.sandberg@arm.comDmaReadFifo::startFill(Addr start, size_t size)
34611010Sandreas.sandberg@arm.com{
34711010Sandreas.sandberg@arm.com    assert(atEndOfBlock());
34811010Sandreas.sandberg@arm.com
34911010Sandreas.sandberg@arm.com    nextAddr = start;
35011010Sandreas.sandberg@arm.com    endAddr = start + size;
35111010Sandreas.sandberg@arm.com    resumeFill();
35211010Sandreas.sandberg@arm.com}
35311010Sandreas.sandberg@arm.com
35411010Sandreas.sandberg@arm.comvoid
35511010Sandreas.sandberg@arm.comDmaReadFifo::stopFill()
35611010Sandreas.sandberg@arm.com{
35711010Sandreas.sandberg@arm.com    // Prevent new DMA requests by setting the next address to the end
35811010Sandreas.sandberg@arm.com    // address. Pending requests will still complete.
35911010Sandreas.sandberg@arm.com    nextAddr = endAddr;
36011010Sandreas.sandberg@arm.com
36111010Sandreas.sandberg@arm.com    // Flag in-flight accesses as canceled. This prevents their data
36211010Sandreas.sandberg@arm.com    // from being written to the FIFO.
36311010Sandreas.sandberg@arm.com    for (auto &p : pendingRequests)
36411010Sandreas.sandberg@arm.com        p->cancel();
36511010Sandreas.sandberg@arm.com}
36611010Sandreas.sandberg@arm.com
36711010Sandreas.sandberg@arm.comvoid
36811010Sandreas.sandberg@arm.comDmaReadFifo::resumeFill()
36911010Sandreas.sandberg@arm.com{
37011010Sandreas.sandberg@arm.com    // Don't try to fetch more data if we are draining. This ensures
37111010Sandreas.sandberg@arm.com    // that the DMA engine settles down before we checkpoint it.
37211010Sandreas.sandberg@arm.com    if (drainState() == DrainState::Draining)
37311010Sandreas.sandberg@arm.com        return;
37411010Sandreas.sandberg@arm.com
37511010Sandreas.sandberg@arm.com    const bool old_eob(atEndOfBlock());
37611896Ssudhanshu.jha@arm.com
37711896Ssudhanshu.jha@arm.com    if (port.sys->bypassCaches())
37811896Ssudhanshu.jha@arm.com        resumeFillFunctional();
37911896Ssudhanshu.jha@arm.com    else
38011896Ssudhanshu.jha@arm.com        resumeFillTiming();
38111896Ssudhanshu.jha@arm.com
38211896Ssudhanshu.jha@arm.com    if (!old_eob && atEndOfBlock())
38311896Ssudhanshu.jha@arm.com        onEndOfBlock();
38411896Ssudhanshu.jha@arm.com}
38511896Ssudhanshu.jha@arm.com
38611896Ssudhanshu.jha@arm.comvoid
38711896Ssudhanshu.jha@arm.comDmaReadFifo::resumeFillFunctional()
38811896Ssudhanshu.jha@arm.com{
38911896Ssudhanshu.jha@arm.com    const size_t fifo_space = buffer.capacity() - buffer.size();
39011896Ssudhanshu.jha@arm.com    const size_t kvm_watermark = port.sys->cacheLineSize();
39111896Ssudhanshu.jha@arm.com    if (fifo_space >= kvm_watermark || buffer.capacity() < kvm_watermark) {
39211896Ssudhanshu.jha@arm.com        const size_t block_remaining = endAddr - nextAddr;
39311896Ssudhanshu.jha@arm.com        const size_t xfer_size = std::min(fifo_space, block_remaining);
39411896Ssudhanshu.jha@arm.com        std::vector<uint8_t> tmp_buffer(xfer_size);
39511896Ssudhanshu.jha@arm.com
39611896Ssudhanshu.jha@arm.com        assert(pendingRequests.empty());
39711896Ssudhanshu.jha@arm.com        DPRINTF(DMA, "KVM Bypassing startAddr=%#x xfer_size=%#x " \
39811896Ssudhanshu.jha@arm.com                "fifo_space=%#x block_remaining=%#x\n",
39911896Ssudhanshu.jha@arm.com                nextAddr, xfer_size, fifo_space, block_remaining);
40011896Ssudhanshu.jha@arm.com
40111896Ssudhanshu.jha@arm.com        port.sys->physProxy.readBlob(nextAddr, tmp_buffer.data(), xfer_size);
40211896Ssudhanshu.jha@arm.com        buffer.write(tmp_buffer.begin(), xfer_size);
40311896Ssudhanshu.jha@arm.com        nextAddr += xfer_size;
40411896Ssudhanshu.jha@arm.com    }
40511896Ssudhanshu.jha@arm.com}
40611896Ssudhanshu.jha@arm.com
40711896Ssudhanshu.jha@arm.comvoid
40811896Ssudhanshu.jha@arm.comDmaReadFifo::resumeFillTiming()
40911896Ssudhanshu.jha@arm.com{
41011010Sandreas.sandberg@arm.com    size_t size_pending(0);
41111010Sandreas.sandberg@arm.com    for (auto &e : pendingRequests)
41211010Sandreas.sandberg@arm.com        size_pending += e->requestSize();
41311010Sandreas.sandberg@arm.com
41411010Sandreas.sandberg@arm.com    while (!freeRequests.empty() && !atEndOfBlock()) {
41511010Sandreas.sandberg@arm.com        const size_t req_size(std::min(maxReqSize, endAddr - nextAddr));
41611010Sandreas.sandberg@arm.com        if (buffer.size() + size_pending + req_size > fifoSize)
41711010Sandreas.sandberg@arm.com            break;
41811010Sandreas.sandberg@arm.com
41911010Sandreas.sandberg@arm.com        DmaDoneEventUPtr event(std::move(freeRequests.front()));
42011010Sandreas.sandberg@arm.com        freeRequests.pop_front();
42111010Sandreas.sandberg@arm.com        assert(event);
42211010Sandreas.sandberg@arm.com
42311010Sandreas.sandberg@arm.com        event->reset(req_size);
42411010Sandreas.sandberg@arm.com        port.dmaAction(MemCmd::ReadReq, nextAddr, req_size, event.get(),
42511010Sandreas.sandberg@arm.com                       event->data(), 0, reqFlags);
42611010Sandreas.sandberg@arm.com        nextAddr += req_size;
42711010Sandreas.sandberg@arm.com        size_pending += req_size;
42811010Sandreas.sandberg@arm.com
42911010Sandreas.sandberg@arm.com        pendingRequests.emplace_back(std::move(event));
43011010Sandreas.sandberg@arm.com    }
43111010Sandreas.sandberg@arm.com}
43211010Sandreas.sandberg@arm.com
43311010Sandreas.sandberg@arm.comvoid
43411010Sandreas.sandberg@arm.comDmaReadFifo::dmaDone()
43511010Sandreas.sandberg@arm.com{
43611010Sandreas.sandberg@arm.com    const bool old_active(isActive());
43711010Sandreas.sandberg@arm.com
43811010Sandreas.sandberg@arm.com    handlePending();
43911010Sandreas.sandberg@arm.com    resumeFill();
44011010Sandreas.sandberg@arm.com
44112115Srohit.kurup@arm.com    if (old_active && !isActive())
44211010Sandreas.sandberg@arm.com        onIdle();
44311010Sandreas.sandberg@arm.com}
44411010Sandreas.sandberg@arm.com
44511010Sandreas.sandberg@arm.comvoid
44611010Sandreas.sandberg@arm.comDmaReadFifo::handlePending()
44711010Sandreas.sandberg@arm.com{
44811010Sandreas.sandberg@arm.com    while (!pendingRequests.empty() && pendingRequests.front()->done()) {
44911010Sandreas.sandberg@arm.com        // Get the first finished pending request
45011010Sandreas.sandberg@arm.com        DmaDoneEventUPtr event(std::move(pendingRequests.front()));
45111010Sandreas.sandberg@arm.com        pendingRequests.pop_front();
45211010Sandreas.sandberg@arm.com
45311010Sandreas.sandberg@arm.com        if (!event->canceled())
45411010Sandreas.sandberg@arm.com            buffer.write(event->data(), event->requestSize());
45511010Sandreas.sandberg@arm.com
45611010Sandreas.sandberg@arm.com        // Move the event to the list of free requests
45711010Sandreas.sandberg@arm.com        freeRequests.emplace_back(std::move(event));
45811010Sandreas.sandberg@arm.com    }
45911010Sandreas.sandberg@arm.com
46011010Sandreas.sandberg@arm.com    if (pendingRequests.empty())
46111010Sandreas.sandberg@arm.com        signalDrainDone();
46211010Sandreas.sandberg@arm.com}
46311010Sandreas.sandberg@arm.com
46411010Sandreas.sandberg@arm.comDrainState
46511010Sandreas.sandberg@arm.comDmaReadFifo::drain()
46611010Sandreas.sandberg@arm.com{
46711010Sandreas.sandberg@arm.com    return pendingRequests.empty() ? DrainState::Drained : DrainState::Draining;
46811010Sandreas.sandberg@arm.com}
46911010Sandreas.sandberg@arm.com
47011010Sandreas.sandberg@arm.com
47111010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::DmaDoneEvent(DmaReadFifo *_parent,
47211010Sandreas.sandberg@arm.com                                        size_t max_size)
47311010Sandreas.sandberg@arm.com    : parent(_parent), _done(false), _canceled(false), _data(max_size, 0)
47411010Sandreas.sandberg@arm.com{
47511010Sandreas.sandberg@arm.com}
47611010Sandreas.sandberg@arm.com
47711010Sandreas.sandberg@arm.comvoid
47811010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::kill()
47911010Sandreas.sandberg@arm.com{
48011010Sandreas.sandberg@arm.com    parent = nullptr;
48111010Sandreas.sandberg@arm.com    setFlags(AutoDelete);
48211010Sandreas.sandberg@arm.com}
48311010Sandreas.sandberg@arm.com
48411010Sandreas.sandberg@arm.comvoid
48511010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::cancel()
48611010Sandreas.sandberg@arm.com{
48711010Sandreas.sandberg@arm.com    _canceled = true;
48811010Sandreas.sandberg@arm.com}
48911010Sandreas.sandberg@arm.com
49011010Sandreas.sandberg@arm.comvoid
49111010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::reset(size_t size)
49211010Sandreas.sandberg@arm.com{
49311010Sandreas.sandberg@arm.com    assert(size <= _data.size());
49411010Sandreas.sandberg@arm.com    _done = false;
49511010Sandreas.sandberg@arm.com    _canceled = false;
49611010Sandreas.sandberg@arm.com    _requestSize = size;
49711010Sandreas.sandberg@arm.com}
49811010Sandreas.sandberg@arm.com
49911010Sandreas.sandberg@arm.comvoid
50011010Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::process()
50111010Sandreas.sandberg@arm.com{
50211010Sandreas.sandberg@arm.com    if (!parent)
50311010Sandreas.sandberg@arm.com        return;
50411010Sandreas.sandberg@arm.com
50511010Sandreas.sandberg@arm.com    assert(!_done);
50611010Sandreas.sandberg@arm.com    _done = true;
50711010Sandreas.sandberg@arm.com    parent->dmaDone();
50811010Sandreas.sandberg@arm.com}
509