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