dma_device.cc revision 11284:b3926db25371
18981Sandreas.hansson@arm.com/*
213573Ssascha.bischoff@arm.com * Copyright (c) 2012, 2015 ARM Limited
311804Srjthakur@google.com * All rights reserved.
411904Spierre-yves.peneau@lirmm.fr *
511804Srjthakur@google.com * The license below extends only to copyright in the software and shall
68981Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
78981Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
88981Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
98981Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
108981Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
118981Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
128981Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
138981Sandreas.hansson@arm.com *
148981Sandreas.hansson@arm.com * Copyright (c) 2006 The Regents of The University of Michigan
158981Sandreas.hansson@arm.com * All rights reserved.
168981Sandreas.hansson@arm.com *
178981Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
188981Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
198981Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
208981Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
218981Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
228981Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
238981Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
248981Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
258981Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
268981Sandreas.hansson@arm.com * this software without specific prior written permission.
278981Sandreas.hansson@arm.com *
288981Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
298981Sandreas.hansson@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
308981Sandreas.hansson@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
318981Sandreas.hansson@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
328981Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
338981Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
348981Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
358981Sandreas.hansson@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
368981Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
378981Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
388981Sandreas.hansson@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
398981Sandreas.hansson@arm.com *
408981Sandreas.hansson@arm.com * Authors: Ali Saidi
4111804Srjthakur@google.com *          Nathan Binkert
4211904Spierre-yves.peneau@lirmm.fr *          Andreas Hansson
438981Sandreas.hansson@arm.com *          Andreas Sandberg
448981Sandreas.hansson@arm.com */
458981Sandreas.hansson@arm.com
468981Sandreas.hansson@arm.com#include "dev/dma_device.hh"
478981Sandreas.hansson@arm.com
488981Sandreas.hansson@arm.com#include <utility>
498981Sandreas.hansson@arm.com
508981Sandreas.hansson@arm.com#include "base/chunk_generator.hh"
5110994Sandreas.sandberg@arm.com#include "debug/DMA.hh"
528981Sandreas.hansson@arm.com#include "debug/Drain.hh"
538981Sandreas.hansson@arm.com#include "sim/system.hh"
548981Sandreas.hansson@arm.com
558981Sandreas.hansson@arm.comDmaPort::DmaPort(MemObject *dev, System *s)
568981Sandreas.hansson@arm.com    : MasterPort(dev->name() + ".dma", dev),
578981Sandreas.hansson@arm.com      device(dev), sys(s), masterId(s->getMasterId(dev->name())),
588981Sandreas.hansson@arm.com      sendEvent(this), pendingCount(0), inRetry(false)
598981Sandreas.hansson@arm.com{ }
608981Sandreas.hansson@arm.com
618981Sandreas.hansson@arm.comvoid
628981Sandreas.hansson@arm.comDmaPort::handleResp(PacketPtr pkt, Tick delay)
638981Sandreas.hansson@arm.com{
648981Sandreas.hansson@arm.com    // should always see a response with a sender state
658981Sandreas.hansson@arm.com    assert(pkt->isResponse());
668981Sandreas.hansson@arm.com
6710902Sandreas.sandberg@arm.com    // get the DMA sender state
688981Sandreas.hansson@arm.com    DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
698981Sandreas.hansson@arm.com    assert(state);
708981Sandreas.hansson@arm.com
718981Sandreas.hansson@arm.com    DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d,"  \
728981Sandreas.hansson@arm.com            " tot: %d sched %d\n",
738981Sandreas.hansson@arm.com            pkt->cmdString(), pkt->getAddr(), pkt->req->getSize(),
748981Sandreas.hansson@arm.com            state->numBytes, state->totBytes,
758981Sandreas.hansson@arm.com            state->completionEvent ?
768981Sandreas.hansson@arm.com            state->completionEvent->scheduled() : 0);
778981Sandreas.hansson@arm.com
788981Sandreas.hansson@arm.com    assert(pendingCount != 0);
798981Sandreas.hansson@arm.com    pendingCount--;
808981Sandreas.hansson@arm.com
8111168Sandreas.hansson@arm.com    // update the number of bytes received based on the request rather
8211168Sandreas.hansson@arm.com    // than the packet as the latter could be rounded up to line sizes
8311168Sandreas.hansson@arm.com    state->numBytes += pkt->req->getSize();
8411168Sandreas.hansson@arm.com    assert(state->totBytes >= state->numBytes);
858981Sandreas.hansson@arm.com
8610902Sandreas.sandberg@arm.com    // if we have reached the total number of bytes for this DMA
8710902Sandreas.sandberg@arm.com    // request, then signal the completion and delete the sate
8811168Sandreas.hansson@arm.com    if (state->totBytes == state->numBytes) {
898981Sandreas.hansson@arm.com        if (state->completionEvent) {
9010902Sandreas.sandberg@arm.com            delay += state->delay;
9111168Sandreas.hansson@arm.com            device->schedule(state->completionEvent, curTick() + delay);
928981Sandreas.hansson@arm.com        }
938981Sandreas.hansson@arm.com        delete state;
948981Sandreas.hansson@arm.com    }
958981Sandreas.hansson@arm.com
968981Sandreas.hansson@arm.com    // delete the request that we created and also the packet
978981Sandreas.hansson@arm.com    delete pkt->req;
988981Sandreas.hansson@arm.com    delete pkt;
998981Sandreas.hansson@arm.com
1008981Sandreas.hansson@arm.com    // we might be drained at this point, if so signal the drain event
1018981Sandreas.hansson@arm.com    if (pendingCount == 0)
1028981Sandreas.hansson@arm.com        signalDrainDone();
1038981Sandreas.hansson@arm.com}
1048981Sandreas.hansson@arm.com
1059542Sandreas.hansson@arm.combool
1069542Sandreas.hansson@arm.comDmaPort::recvTimingResp(PacketPtr pkt)
1078981Sandreas.hansson@arm.com{
1088981Sandreas.hansson@arm.com    // We shouldn't ever get a cacheable block in Modified state
1098981Sandreas.hansson@arm.com    assert(pkt->req->isUncacheable() ||
1109542Sandreas.hansson@arm.com           !(pkt->cacheResponding() && !pkt->hasSharers()));
1119542Sandreas.hansson@arm.com
1128981Sandreas.hansson@arm.com    handleResp(pkt);
1138981Sandreas.hansson@arm.com
1148981Sandreas.hansson@arm.com    return true;
1158981Sandreas.hansson@arm.com}
1168981Sandreas.hansson@arm.com
1178981Sandreas.hansson@arm.comDmaDevice::DmaDevice(const Params *p)
1188981Sandreas.hansson@arm.com    : PioDevice(p), dmaPort(this, sys)
1198981Sandreas.hansson@arm.com{ }
1208981Sandreas.hansson@arm.com
1218981Sandreas.hansson@arm.comvoid
1228981Sandreas.hansson@arm.comDmaDevice::init()
1238981Sandreas.hansson@arm.com{
1248981Sandreas.hansson@arm.com    if (!dmaPort.isConnected())
1258981Sandreas.hansson@arm.com        panic("DMA port of %s not connected to anything!", name());
1268981Sandreas.hansson@arm.com    PioDevice::init();
1278981Sandreas.hansson@arm.com}
1288981Sandreas.hansson@arm.com
1298981Sandreas.hansson@arm.comDrainState
1308981Sandreas.hansson@arm.comDmaPort::drain()
1318981Sandreas.hansson@arm.com{
1328981Sandreas.hansson@arm.com    if (pendingCount == 0) {
1338981Sandreas.hansson@arm.com        return DrainState::Drained;
1348981Sandreas.hansson@arm.com    } else {
1358981Sandreas.hansson@arm.com        DPRINTF(Drain, "DmaPort not drained\n");
1368981Sandreas.hansson@arm.com        return DrainState::Draining;
1378981Sandreas.hansson@arm.com    }
1388981Sandreas.hansson@arm.com}
1398981Sandreas.hansson@arm.com
1408981Sandreas.hansson@arm.comvoid
1418981Sandreas.hansson@arm.comDmaPort::recvReqRetry()
1428981Sandreas.hansson@arm.com{
1438981Sandreas.hansson@arm.com    assert(transmitList.size());
1448981Sandreas.hansson@arm.com    trySendTimingReq();
1458981Sandreas.hansson@arm.com}
1468981Sandreas.hansson@arm.com
1478981Sandreas.hansson@arm.comRequestPtr
1488981Sandreas.hansson@arm.comDmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
1498981Sandreas.hansson@arm.com                   uint8_t *data, Tick delay, Request::Flags flag)
1508981Sandreas.hansson@arm.com{
1518981Sandreas.hansson@arm.com    // one DMA request sender state for every action, that is then
1528981Sandreas.hansson@arm.com    // split into many requests and packets based on the block size,
1538981Sandreas.hansson@arm.com    // i.e. cache line size
1548981Sandreas.hansson@arm.com    DmaReqState *reqState = new DmaReqState(event, size, delay);
1558981Sandreas.hansson@arm.com
1568981Sandreas.hansson@arm.com    // (functionality added for Table Walker statistics)
1578981Sandreas.hansson@arm.com    // We're only interested in this when there will only be one request.
1588981Sandreas.hansson@arm.com    // For simplicity, we return the last request, which would also be
1598981Sandreas.hansson@arm.com    // the only request in that case.
1608981Sandreas.hansson@arm.com    RequestPtr req = NULL;
1618981Sandreas.hansson@arm.com
1628981Sandreas.hansson@arm.com    DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size,
1638981Sandreas.hansson@arm.com            event ? event->scheduled() : -1);
1648981Sandreas.hansson@arm.com    for (ChunkGenerator gen(addr, size, sys->cacheLineSize());
1658981Sandreas.hansson@arm.com         !gen.done(); gen.next()) {
1668981Sandreas.hansson@arm.com        req = new Request(gen.addr(), gen.size(), flag, masterId);
1678981Sandreas.hansson@arm.com        req->taskId(ContextSwitchTaskId::DMA);
1688981Sandreas.hansson@arm.com        PacketPtr pkt = new Packet(req, cmd);
16910713Sandreas.hansson@arm.com
1708981Sandreas.hansson@arm.com        // Increment the data pointer on a write
17110713Sandreas.hansson@arm.com        if (data)
1728981Sandreas.hansson@arm.com            pkt->dataStatic(data + gen.complete());
1738981Sandreas.hansson@arm.com
17411173Sandreas.hansson@arm.com        pkt->senderState = reqState;
17511173Sandreas.hansson@arm.com
17611173Sandreas.hansson@arm.com        DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(),
17711173Sandreas.hansson@arm.com                gen.size());
17811173Sandreas.hansson@arm.com        queueDma(pkt);
1798981Sandreas.hansson@arm.com    }
1808981Sandreas.hansson@arm.com
1818981Sandreas.hansson@arm.com    // in zero time also initiate the sending of the packets we have
1828981Sandreas.hansson@arm.com    // just created, for atomic this involves actually completing all
1838981Sandreas.hansson@arm.com    // the requests
1848981Sandreas.hansson@arm.com    sendDma();
1858981Sandreas.hansson@arm.com
1868981Sandreas.hansson@arm.com    return req;
1878981Sandreas.hansson@arm.com}
1888981Sandreas.hansson@arm.com
1898981Sandreas.hansson@arm.comvoid
1908981Sandreas.hansson@arm.comDmaPort::queueDma(PacketPtr pkt)
1918981Sandreas.hansson@arm.com{
1928981Sandreas.hansson@arm.com    transmitList.push_back(pkt);
1938981Sandreas.hansson@arm.com
1948981Sandreas.hansson@arm.com    // remember that we have another packet pending, this will only be
1958981Sandreas.hansson@arm.com    // decremented once a response comes back
1968981Sandreas.hansson@arm.com    pendingCount++;
1978981Sandreas.hansson@arm.com}
1988981Sandreas.hansson@arm.com
1998981Sandreas.hansson@arm.comvoid
2008981Sandreas.hansson@arm.comDmaPort::trySendTimingReq()
2018981Sandreas.hansson@arm.com{
2028981Sandreas.hansson@arm.com    // send the first packet on the transmit list and schedule the
2038981Sandreas.hansson@arm.com    // following send if it is successful
2048981Sandreas.hansson@arm.com    PacketPtr pkt = transmitList.front();
2058981Sandreas.hansson@arm.com
2068981Sandreas.hansson@arm.com    DPRINTF(DMA, "Trying to send %s addr %#x\n", pkt->cmdString(),
2078981Sandreas.hansson@arm.com            pkt->getAddr());
2088981Sandreas.hansson@arm.com
2098981Sandreas.hansson@arm.com    inRetry = !sendTimingReq(pkt);
2108981Sandreas.hansson@arm.com    if (!inRetry) {
2118981Sandreas.hansson@arm.com        transmitList.pop_front();
2128981Sandreas.hansson@arm.com        DPRINTF(DMA, "-- Done\n");
2138981Sandreas.hansson@arm.com        // if there is more to do, then do so
2148981Sandreas.hansson@arm.com        if (!transmitList.empty())
2158981Sandreas.hansson@arm.com            // this should ultimately wait for as many cycles as the
2168981Sandreas.hansson@arm.com            // device needs to send the packet, but currently the port
2178981Sandreas.hansson@arm.com            // does not have any known width so simply wait a single
2188981Sandreas.hansson@arm.com            // cycle
2198981Sandreas.hansson@arm.com            device->schedule(sendEvent, device->clockEdge(Cycles(1)));
2208981Sandreas.hansson@arm.com    } else {
2218981Sandreas.hansson@arm.com        DPRINTF(DMA, "-- Failed, waiting for retry\n");
2228981Sandreas.hansson@arm.com    }
2238981Sandreas.hansson@arm.com
2248981Sandreas.hansson@arm.com    DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n",
2259090Sandreas.hansson@arm.com            transmitList.size(), inRetry);
2268981Sandreas.hansson@arm.com}
2278981Sandreas.hansson@arm.com
2288981Sandreas.hansson@arm.comvoid
2298981Sandreas.hansson@arm.comDmaPort::sendDma()
23010713Sandreas.hansson@arm.com{
2318981Sandreas.hansson@arm.com    // some kind of selcetion between access methods
23210713Sandreas.hansson@arm.com    // more work is going to have to be done to make
2338981Sandreas.hansson@arm.com    // switching actually work
2348981Sandreas.hansson@arm.com    assert(transmitList.size());
23513573Ssascha.bischoff@arm.com
23613573Ssascha.bischoff@arm.com    if (sys->isTimingMode()) {
23713573Ssascha.bischoff@arm.com        // if we are either waiting for a retry or are still waiting
23813573Ssascha.bischoff@arm.com        // after sending the last packet, then do not proceed
23913573Ssascha.bischoff@arm.com        if (inRetry || sendEvent.scheduled()) {
2408981Sandreas.hansson@arm.com            DPRINTF(DMA, "Can't send immediately, waiting to send\n");
2418981Sandreas.hansson@arm.com            return;
2428981Sandreas.hansson@arm.com        }
2438981Sandreas.hansson@arm.com
2448981Sandreas.hansson@arm.com        trySendTimingReq();
2458981Sandreas.hansson@arm.com    } else if (sys->isAtomicMode()) {
2468981Sandreas.hansson@arm.com        // send everything there is to send in zero time
2478981Sandreas.hansson@arm.com        while (!transmitList.empty()) {
2488981Sandreas.hansson@arm.com            PacketPtr pkt = transmitList.front();
2498981Sandreas.hansson@arm.com            transmitList.pop_front();
2508981Sandreas.hansson@arm.com
2518981Sandreas.hansson@arm.com            DPRINTF(DMA, "Sending  DMA for addr: %#x size: %d\n",
2528981Sandreas.hansson@arm.com                    pkt->req->getPaddr(), pkt->req->getSize());
2538981Sandreas.hansson@arm.com            Tick lat = sendAtomic(pkt);
2548981Sandreas.hansson@arm.com
2558981Sandreas.hansson@arm.com            handleResp(pkt, lat);
2568981Sandreas.hansson@arm.com        }
2578981Sandreas.hansson@arm.com    } else
2588981Sandreas.hansson@arm.com        panic("Unknown memory mode.");
2598981Sandreas.hansson@arm.com}
2608981Sandreas.hansson@arm.com
2618981Sandreas.hansson@arm.comBaseMasterPort &
2628981Sandreas.hansson@arm.comDmaDevice::getMasterPort(const std::string &if_name, PortID idx)
2638981Sandreas.hansson@arm.com{
2648981Sandreas.hansson@arm.com    if (if_name == "dma") {
26511173Sandreas.hansson@arm.com        return dmaPort;
26611173Sandreas.hansson@arm.com    }
2679090Sandreas.hansson@arm.com    return PioDevice::getMasterPort(if_name, idx);
2688981Sandreas.hansson@arm.com}
2698981Sandreas.hansson@arm.com
2708981Sandreas.hansson@arm.com
27110713Sandreas.hansson@arm.com
2728981Sandreas.hansson@arm.com
27310713Sandreas.hansson@arm.com
2748981Sandreas.hansson@arm.comDmaReadFifo::DmaReadFifo(DmaPort &_port, size_t size,
2758981Sandreas.hansson@arm.com                         unsigned max_req_size,
2768981Sandreas.hansson@arm.com                         unsigned max_pending,
27713573Ssascha.bischoff@arm.com                         Request::Flags flags)
27813573Ssascha.bischoff@arm.com    : maxReqSize(max_req_size), fifoSize(size),
2798981Sandreas.hansson@arm.com      reqFlags(flags), port(_port),
2808981Sandreas.hansson@arm.com      buffer(size),
2818981Sandreas.hansson@arm.com      nextAddr(0), endAddr(0)
2828981Sandreas.hansson@arm.com{
28311848Spierre-yves.peneau@lirmm.fr    freeRequests.resize(max_pending);
2848981Sandreas.hansson@arm.com    for (auto &e : freeRequests)
2858981Sandreas.hansson@arm.com        e.reset(new DmaDoneEvent(this, max_req_size));
2868981Sandreas.hansson@arm.com
2878981Sandreas.hansson@arm.com}
2888981Sandreas.hansson@arm.com
2898981Sandreas.hansson@arm.comDmaReadFifo::~DmaReadFifo()
2908981Sandreas.hansson@arm.com{
2918981Sandreas.hansson@arm.com    for (auto &p : pendingRequests) {
2928981Sandreas.hansson@arm.com        DmaDoneEvent *e(p.release());
2938981Sandreas.hansson@arm.com
2948981Sandreas.hansson@arm.com        if (e->done()) {
2958981Sandreas.hansson@arm.com            delete e;
2968981Sandreas.hansson@arm.com        } else {
2978981Sandreas.hansson@arm.com            // We can't kill in-flight DMAs, so we'll just transfer
2988981Sandreas.hansson@arm.com            // ownership to the event queue so that they get freed
2998981Sandreas.hansson@arm.com            // when they are done.
3008981Sandreas.hansson@arm.com            e->kill();
3018981Sandreas.hansson@arm.com        }
3028981Sandreas.hansson@arm.com    }
3038981Sandreas.hansson@arm.com}
3048981Sandreas.hansson@arm.com
3058981Sandreas.hansson@arm.comvoid
3068981Sandreas.hansson@arm.comDmaReadFifo::serialize(CheckpointOut &cp) const
3078981Sandreas.hansson@arm.com{
3088981Sandreas.hansson@arm.com    assert(pendingRequests.empty());
3098981Sandreas.hansson@arm.com
3108981Sandreas.hansson@arm.com    SERIALIZE_CONTAINER(buffer);
3118981Sandreas.hansson@arm.com    SERIALIZE_SCALAR(endAddr);
3128981Sandreas.hansson@arm.com    SERIALIZE_SCALAR(nextAddr);
3138981Sandreas.hansson@arm.com}
3148981Sandreas.hansson@arm.com
3158981Sandreas.hansson@arm.comvoid
3168981Sandreas.hansson@arm.comDmaReadFifo::unserialize(CheckpointIn &cp)
3178981Sandreas.hansson@arm.com{
3188981Sandreas.hansson@arm.com    UNSERIALIZE_CONTAINER(buffer);
3198981Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(endAddr);
3208981Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(nextAddr);
3218981Sandreas.hansson@arm.com}
3228981Sandreas.hansson@arm.com
3238981Sandreas.hansson@arm.combool
3248981Sandreas.hansson@arm.comDmaReadFifo::tryGet(uint8_t *dst, size_t len)
3258981Sandreas.hansson@arm.com{
3268981Sandreas.hansson@arm.com    if (buffer.size() >= len) {
3278981Sandreas.hansson@arm.com        buffer.read(dst, len);
3288981Sandreas.hansson@arm.com        resumeFill();
3298981Sandreas.hansson@arm.com        return true;
3308981Sandreas.hansson@arm.com    } else {
3318981Sandreas.hansson@arm.com        return false;
3328981Sandreas.hansson@arm.com    }
3338981Sandreas.hansson@arm.com}
3348981Sandreas.hansson@arm.com
3358981Sandreas.hansson@arm.comvoid
3368981Sandreas.hansson@arm.comDmaReadFifo::get(uint8_t *dst, size_t len)
3378981Sandreas.hansson@arm.com{
3388981Sandreas.hansson@arm.com    const bool success(tryGet(dst, len));
3398981Sandreas.hansson@arm.com    panic_if(!success, "Buffer underrun in DmaReadFifo::get()\n");
3408981Sandreas.hansson@arm.com}
3418981Sandreas.hansson@arm.com
3428981Sandreas.hansson@arm.comvoid
3438981Sandreas.hansson@arm.comDmaReadFifo::startFill(Addr start, size_t size)
3448981Sandreas.hansson@arm.com{
3458981Sandreas.hansson@arm.com    assert(atEndOfBlock());
3468981Sandreas.hansson@arm.com
3478981Sandreas.hansson@arm.com    nextAddr = start;
3488981Sandreas.hansson@arm.com    endAddr = start + size;
3498981Sandreas.hansson@arm.com    resumeFill();
3508981Sandreas.hansson@arm.com}
3518981Sandreas.hansson@arm.com
3528981Sandreas.hansson@arm.comvoid
3538981Sandreas.hansson@arm.comDmaReadFifo::stopFill()
3548981Sandreas.hansson@arm.com{
3558981Sandreas.hansson@arm.com    // Prevent new DMA requests by setting the next address to the end
3568981Sandreas.hansson@arm.com    // address. Pending requests will still complete.
3578981Sandreas.hansson@arm.com    nextAddr = endAddr;
3588981Sandreas.hansson@arm.com
3598981Sandreas.hansson@arm.com    // Flag in-flight accesses as canceled. This prevents their data
3608981Sandreas.hansson@arm.com    // from being written to the FIFO.
3618981Sandreas.hansson@arm.com    for (auto &p : pendingRequests)
3628981Sandreas.hansson@arm.com        p->cancel();
3638981Sandreas.hansson@arm.com}
3648981Sandreas.hansson@arm.com
3658981Sandreas.hansson@arm.comvoid
3668981Sandreas.hansson@arm.comDmaReadFifo::resumeFill()
3678981Sandreas.hansson@arm.com{
3688981Sandreas.hansson@arm.com    // Don't try to fetch more data if we are draining. This ensures
3698981Sandreas.hansson@arm.com    // that the DMA engine settles down before we checkpoint it.
3708981Sandreas.hansson@arm.com    if (drainState() == DrainState::Draining)
37111804Srjthakur@google.com        return;
37211804Srjthakur@google.com
37311804Srjthakur@google.com    const bool old_eob(atEndOfBlock());
37411804Srjthakur@google.com    size_t size_pending(0);
37511804Srjthakur@google.com    for (auto &e : pendingRequests)
37611804Srjthakur@google.com        size_pending += e->requestSize();
3778981Sandreas.hansson@arm.com
3788981Sandreas.hansson@arm.com    while (!freeRequests.empty() && !atEndOfBlock()) {
3798981Sandreas.hansson@arm.com        const size_t req_size(std::min(maxReqSize, endAddr - nextAddr));
3808981Sandreas.hansson@arm.com        if (buffer.size() + size_pending + req_size > fifoSize)
3818981Sandreas.hansson@arm.com            break;
3828981Sandreas.hansson@arm.com
3838981Sandreas.hansson@arm.com        DmaDoneEventUPtr event(std::move(freeRequests.front()));
3848981Sandreas.hansson@arm.com        freeRequests.pop_front();
3858981Sandreas.hansson@arm.com        assert(event);
3868981Sandreas.hansson@arm.com
3878981Sandreas.hansson@arm.com        event->reset(req_size);
3888981Sandreas.hansson@arm.com        port.dmaAction(MemCmd::ReadReq, nextAddr, req_size, event.get(),
3898981Sandreas.hansson@arm.com                       event->data(), 0, reqFlags);
3908981Sandreas.hansson@arm.com        nextAddr += req_size;
3918981Sandreas.hansson@arm.com        size_pending += req_size;
3928981Sandreas.hansson@arm.com
3938981Sandreas.hansson@arm.com        pendingRequests.emplace_back(std::move(event));
3948981Sandreas.hansson@arm.com    }
3958981Sandreas.hansson@arm.com
3968981Sandreas.hansson@arm.com    // EOB can be set before a call to dmaDone() if in-flight accesses
3978981Sandreas.hansson@arm.com    // have been canceled.
3988981Sandreas.hansson@arm.com    if (!old_eob && atEndOfBlock())
3998981Sandreas.hansson@arm.com        onEndOfBlock();
4008981Sandreas.hansson@arm.com}
4018981Sandreas.hansson@arm.com
4028981Sandreas.hansson@arm.comvoid
4038981Sandreas.hansson@arm.comDmaReadFifo::dmaDone()
4048981Sandreas.hansson@arm.com{
40511804Srjthakur@google.com    const bool old_active(isActive());
40611804Srjthakur@google.com
40711804Srjthakur@google.com    handlePending();
4088981Sandreas.hansson@arm.com    resumeFill();
4098981Sandreas.hansson@arm.com
41011804Srjthakur@google.com    if (!old_active && isActive())
41111804Srjthakur@google.com        onIdle();
41211804Srjthakur@google.com}
41311804Srjthakur@google.com
4148981Sandreas.hansson@arm.comvoid
4158981Sandreas.hansson@arm.comDmaReadFifo::handlePending()
4168981Sandreas.hansson@arm.com{
4178981Sandreas.hansson@arm.com    while (!pendingRequests.empty() && pendingRequests.front()->done()) {
4188981Sandreas.hansson@arm.com        // Get the first finished pending request
4198981Sandreas.hansson@arm.com        DmaDoneEventUPtr event(std::move(pendingRequests.front()));
42012084Sspwilson2@wisc.edu        pendingRequests.pop_front();
4218981Sandreas.hansson@arm.com
42210902Sandreas.sandberg@arm.com        if (!event->canceled())
42310902Sandreas.sandberg@arm.com            buffer.write(event->data(), event->requestSize());
42410902Sandreas.sandberg@arm.com
42510902Sandreas.sandberg@arm.com        // Move the event to the list of free requests
42610902Sandreas.sandberg@arm.com        freeRequests.emplace_back(std::move(event));
4278981Sandreas.hansson@arm.com    }
42810902Sandreas.sandberg@arm.com
42910902Sandreas.sandberg@arm.com    if (pendingRequests.empty())
43010902Sandreas.sandberg@arm.com        signalDrainDone();
4318981Sandreas.hansson@arm.com}
43210902Sandreas.sandberg@arm.com
43310902Sandreas.sandberg@arm.com
4348981Sandreas.hansson@arm.com
4358981Sandreas.hansson@arm.comDrainState
43610994Sandreas.sandberg@arm.comDmaReadFifo::drain()
43710994Sandreas.sandberg@arm.com{
43810994Sandreas.sandberg@arm.com    return pendingRequests.empty() ? DrainState::Drained : DrainState::Draining;
43910994Sandreas.sandberg@arm.com}
44010994Sandreas.sandberg@arm.com
44110994Sandreas.sandberg@arm.com
44210994Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::DmaDoneEvent(DmaReadFifo *_parent,
44310994Sandreas.sandberg@arm.com                                        size_t max_size)
44410994Sandreas.sandberg@arm.com    : parent(_parent), _done(false), _canceled(false), _data(max_size, 0)
44510994Sandreas.sandberg@arm.com{
44610994Sandreas.sandberg@arm.com}
44710994Sandreas.sandberg@arm.com
44810994Sandreas.sandberg@arm.comvoid
44910994Sandreas.sandberg@arm.comDmaReadFifo::DmaDoneEvent::kill()
4508981Sandreas.hansson@arm.com{
4518981Sandreas.hansson@arm.com    parent = nullptr;
4528981Sandreas.hansson@arm.com    setFlags(AutoDelete);
453}
454
455void
456DmaReadFifo::DmaDoneEvent::cancel()
457{
458    _canceled = true;
459}
460
461void
462DmaReadFifo::DmaDoneEvent::reset(size_t size)
463{
464    assert(size <= _data.size());
465    _done = false;
466    _canceled = false;
467    _requestSize = size;
468}
469
470void
471DmaReadFifo::DmaDoneEvent::process()
472{
473    if (!parent)
474        return;
475
476    assert(!_done);
477    _done = true;
478    parent->dmaDone();
479}
480