dma_device.cc revision 10821
1545SN/A/* 28948SN/A * Copyright (c) 2012 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 43545SN/A */ 44545SN/A 453090SN/A#include "base/chunk_generator.hh" 468232SN/A#include "debug/DMA.hh" 479152Satgutier@umich.edu#include "debug/Drain.hh" 489016Sandreas.hansson@arm.com#include "dev/dma_device.hh" 492901SN/A#include "sim/system.hh" 50545SN/A 519165Sandreas.hansson@arm.comDmaPort::DmaPort(MemObject *dev, System *s) 529307Sandreas.hansson@arm.com : MasterPort(dev->name() + ".dma", dev), device(dev), sendEvent(this), 539307Sandreas.hansson@arm.com sys(s), masterId(s->getMasterId(dev->name())), 549342SAndreas.Sandberg@arm.com pendingCount(0), drainManager(NULL), 559165Sandreas.hansson@arm.com inRetry(false) 562489SN/A{ } 572489SN/A 589166Sandreas.hansson@arm.comvoid 599166Sandreas.hansson@arm.comDmaPort::handleResp(PacketPtr pkt, Tick delay) 609166Sandreas.hansson@arm.com{ 619166Sandreas.hansson@arm.com // should always see a response with a sender state 629166Sandreas.hansson@arm.com assert(pkt->isResponse()); 639166Sandreas.hansson@arm.com 649166Sandreas.hansson@arm.com // get the DMA sender state 659166Sandreas.hansson@arm.com DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); 669166Sandreas.hansson@arm.com assert(state); 679166Sandreas.hansson@arm.com 689166Sandreas.hansson@arm.com DPRINTF(DMA, "Received response %s for addr: %#x size: %d nb: %d," \ 699166Sandreas.hansson@arm.com " tot: %d sched %d\n", 709166Sandreas.hansson@arm.com pkt->cmdString(), pkt->getAddr(), pkt->req->getSize(), 719166Sandreas.hansson@arm.com state->numBytes, state->totBytes, 729166Sandreas.hansson@arm.com state->completionEvent ? 739166Sandreas.hansson@arm.com state->completionEvent->scheduled() : 0); 749166Sandreas.hansson@arm.com 759166Sandreas.hansson@arm.com assert(pendingCount != 0); 769166Sandreas.hansson@arm.com pendingCount--; 779166Sandreas.hansson@arm.com 789166Sandreas.hansson@arm.com // update the number of bytes received based on the request rather 799166Sandreas.hansson@arm.com // than the packet as the latter could be rounded up to line sizes 809166Sandreas.hansson@arm.com state->numBytes += pkt->req->getSize(); 819166Sandreas.hansson@arm.com assert(state->totBytes >= state->numBytes); 829166Sandreas.hansson@arm.com 839166Sandreas.hansson@arm.com // if we have reached the total number of bytes for this DMA 849166Sandreas.hansson@arm.com // request, then signal the completion and delete the sate 859166Sandreas.hansson@arm.com if (state->totBytes == state->numBytes) { 869166Sandreas.hansson@arm.com if (state->completionEvent) { 879166Sandreas.hansson@arm.com delay += state->delay; 889452SAndreas.Sandberg@ARM.com device->schedule(state->completionEvent, curTick() + delay); 899166Sandreas.hansson@arm.com } 909166Sandreas.hansson@arm.com delete state; 919166Sandreas.hansson@arm.com } 929166Sandreas.hansson@arm.com 939166Sandreas.hansson@arm.com // delete the request that we created and also the packet 949166Sandreas.hansson@arm.com delete pkt->req; 959166Sandreas.hansson@arm.com delete pkt; 969166Sandreas.hansson@arm.com 979166Sandreas.hansson@arm.com // we might be drained at this point, if so signal the drain event 989342SAndreas.Sandberg@arm.com if (pendingCount == 0 && drainManager) { 999342SAndreas.Sandberg@arm.com drainManager->signalDrainDone(); 1009342SAndreas.Sandberg@arm.com drainManager = NULL; 1019166Sandreas.hansson@arm.com } 1029166Sandreas.hansson@arm.com} 1039166Sandreas.hansson@arm.com 1042489SN/Abool 1058975SN/ADmaPort::recvTimingResp(PacketPtr pkt) 1062384SN/A{ 10710821Sandreas.hansson@arm.com // We shouldn't ever get a cacheable block in ownership state 10810821Sandreas.hansson@arm.com assert(pkt->req->isUncacheable() || 10910821Sandreas.hansson@arm.com !(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); 1104435SN/A 1119166Sandreas.hansson@arm.com handleResp(pkt); 1122569SN/A 1132657SN/A return true; 1142384SN/A} 115679SN/A 1164762SN/ADmaDevice::DmaDevice(const Params *p) 1179165Sandreas.hansson@arm.com : PioDevice(p), dmaPort(this, sys) 1182565SN/A{ } 1192384SN/A 1208851SN/Avoid 1218851SN/ADmaDevice::init() 1228851SN/A{ 1238851SN/A if (!dmaPort.isConnected()) 1248851SN/A panic("DMA port of %s not connected to anything!", name()); 1258851SN/A PioDevice::init(); 1268851SN/A} 1278851SN/A 1282901SN/Aunsigned int 1299342SAndreas.Sandberg@arm.comDmaDevice::drain(DrainManager *dm) 1302901SN/A{ 1319342SAndreas.Sandberg@arm.com unsigned int count = pioPort.drain(dm) + dmaPort.drain(dm); 1322901SN/A if (count) 1339342SAndreas.Sandberg@arm.com setDrainState(Drainable::Draining); 1342901SN/A else 1359342SAndreas.Sandberg@arm.com setDrainState(Drainable::Drained); 1362901SN/A return count; 1372901SN/A} 1382901SN/A 1392901SN/Aunsigned int 1409342SAndreas.Sandberg@arm.comDmaPort::drain(DrainManager *dm) 1412901SN/A{ 1429166Sandreas.hansson@arm.com if (pendingCount == 0) 1432901SN/A return 0; 1449342SAndreas.Sandberg@arm.com drainManager = dm; 1459152Satgutier@umich.edu DPRINTF(Drain, "DmaPort not drained\n"); 1462901SN/A return 1; 1472901SN/A} 1482901SN/A 1492384SN/Avoid 15010713Sandreas.hansson@arm.comDmaPort::recvReqRetry() 1512489SN/A{ 1524435SN/A assert(transmitList.size()); 1539307Sandreas.hansson@arm.com trySendTimingReq(); 1542489SN/A} 1552641SN/A 15610621SCurtis.Dunham@arm.comRequestPtr 1572641SN/ADmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 1587607SN/A uint8_t *data, Tick delay, Request::Flags flag) 1592384SN/A{ 1609166Sandreas.hansson@arm.com // one DMA request sender state for every action, that is then 1619166Sandreas.hansson@arm.com // split into many requests and packets based on the block size, 1629166Sandreas.hansson@arm.com // i.e. cache line size 1639016Sandreas.hansson@arm.com DmaReqState *reqState = new DmaReqState(event, size, delay); 1642384SN/A 16510621SCurtis.Dunham@arm.com // (functionality added for Table Walker statistics) 16610621SCurtis.Dunham@arm.com // We're only interested in this when there will only be one request. 16710621SCurtis.Dunham@arm.com // For simplicity, we return the last request, which would also be 16810621SCurtis.Dunham@arm.com // the only request in that case. 16910621SCurtis.Dunham@arm.com RequestPtr req = NULL; 17010621SCurtis.Dunham@arm.com 1714451SN/A DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size, 1729166Sandreas.hansson@arm.com event ? event->scheduled() : -1); 1739814Sandreas.hansson@arm.com for (ChunkGenerator gen(addr, size, sys->cacheLineSize()); 1742406SN/A !gen.done(); gen.next()) { 17510621SCurtis.Dunham@arm.com req = new Request(gen.addr(), gen.size(), flag, masterId); 17610024Sdam.sunwoo@arm.com req->taskId(ContextSwitchTaskId::DMA); 1779166Sandreas.hansson@arm.com PacketPtr pkt = new Packet(req, cmd); 1782641SN/A 1799166Sandreas.hansson@arm.com // Increment the data pointer on a write 1809166Sandreas.hansson@arm.com if (data) 1819166Sandreas.hansson@arm.com pkt->dataStatic(data + gen.complete()); 1822641SN/A 1839166Sandreas.hansson@arm.com pkt->senderState = reqState; 1842641SN/A 1859166Sandreas.hansson@arm.com DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), 1869166Sandreas.hansson@arm.com gen.size()); 1879166Sandreas.hansson@arm.com queueDma(pkt); 1882384SN/A } 1899307Sandreas.hansson@arm.com 1909307Sandreas.hansson@arm.com // in zero time also initiate the sending of the packets we have 1919307Sandreas.hansson@arm.com // just created, for atomic this involves actually completing all 1929307Sandreas.hansson@arm.com // the requests 1939307Sandreas.hansson@arm.com sendDma(); 19410621SCurtis.Dunham@arm.com 19510621SCurtis.Dunham@arm.com return req; 1962384SN/A} 1972384SN/A 1984435SN/Avoid 1999166Sandreas.hansson@arm.comDmaPort::queueDma(PacketPtr pkt) 2004435SN/A{ 2019166Sandreas.hansson@arm.com transmitList.push_back(pkt); 2024435SN/A 2039166Sandreas.hansson@arm.com // remember that we have another packet pending, this will only be 2049166Sandreas.hansson@arm.com // decremented once a response comes back 2059166Sandreas.hansson@arm.com pendingCount++; 2069307Sandreas.hansson@arm.com} 2079166Sandreas.hansson@arm.com 2089307Sandreas.hansson@arm.comvoid 2099307Sandreas.hansson@arm.comDmaPort::trySendTimingReq() 2109307Sandreas.hansson@arm.com{ 2119307Sandreas.hansson@arm.com // send the first packet on the transmit list and schedule the 2129307Sandreas.hansson@arm.com // following send if it is successful 2139307Sandreas.hansson@arm.com PacketPtr pkt = transmitList.front(); 2149307Sandreas.hansson@arm.com 2159307Sandreas.hansson@arm.com DPRINTF(DMA, "Trying to send %s addr %#x\n", pkt->cmdString(), 2169307Sandreas.hansson@arm.com pkt->getAddr()); 2179307Sandreas.hansson@arm.com 2189307Sandreas.hansson@arm.com inRetry = !sendTimingReq(pkt); 2199307Sandreas.hansson@arm.com if (!inRetry) { 2209307Sandreas.hansson@arm.com transmitList.pop_front(); 2219307Sandreas.hansson@arm.com DPRINTF(DMA, "-- Done\n"); 2229307Sandreas.hansson@arm.com // if there is more to do, then do so 2239307Sandreas.hansson@arm.com if (!transmitList.empty()) 2249307Sandreas.hansson@arm.com // this should ultimately wait for as many cycles as the 2259307Sandreas.hansson@arm.com // device needs to send the packet, but currently the port 2269307Sandreas.hansson@arm.com // does not have any known width so simply wait a single 2279307Sandreas.hansson@arm.com // cycle 2289307Sandreas.hansson@arm.com device->schedule(sendEvent, device->clockEdge(Cycles(1))); 2299307Sandreas.hansson@arm.com } else { 2309307Sandreas.hansson@arm.com DPRINTF(DMA, "-- Failed, waiting for retry\n"); 2319307Sandreas.hansson@arm.com } 2329307Sandreas.hansson@arm.com 2339307Sandreas.hansson@arm.com DPRINTF(DMA, "TransmitList: %d, inRetry: %d\n", 2349307Sandreas.hansson@arm.com transmitList.size(), inRetry); 2354435SN/A} 2364435SN/A 2372384SN/Avoid 2384435SN/ADmaPort::sendDma() 2392384SN/A{ 2409166Sandreas.hansson@arm.com // some kind of selcetion between access methods 2412901SN/A // more work is going to have to be done to make 2422901SN/A // switching actually work 2434435SN/A assert(transmitList.size()); 2442902SN/A 2459524SAndreas.Sandberg@ARM.com if (sys->isTimingMode()) { 2469307Sandreas.hansson@arm.com // if we are either waiting for a retry or are still waiting 2479307Sandreas.hansson@arm.com // after sending the last packet, then do not proceed 2489307Sandreas.hansson@arm.com if (inRetry || sendEvent.scheduled()) { 2499307Sandreas.hansson@arm.com DPRINTF(DMA, "Can't send immediately, waiting to send\n"); 2504435SN/A return; 2514435SN/A } 2524435SN/A 2539307Sandreas.hansson@arm.com trySendTimingReq(); 2549524SAndreas.Sandberg@ARM.com } else if (sys->isAtomicMode()) { 2559307Sandreas.hansson@arm.com // send everything there is to send in zero time 2569307Sandreas.hansson@arm.com while (!transmitList.empty()) { 2579307Sandreas.hansson@arm.com PacketPtr pkt = transmitList.front(); 2589307Sandreas.hansson@arm.com transmitList.pop_front(); 2594435SN/A 2609307Sandreas.hansson@arm.com DPRINTF(DMA, "Sending DMA for addr: %#x size: %d\n", 2619307Sandreas.hansson@arm.com pkt->req->getPaddr(), pkt->req->getSize()); 2629307Sandreas.hansson@arm.com Tick lat = sendAtomic(pkt); 2634435SN/A 2649307Sandreas.hansson@arm.com handleResp(pkt, lat); 2659307Sandreas.hansson@arm.com } 2669166Sandreas.hansson@arm.com } else 2679166Sandreas.hansson@arm.com panic("Unknown memory mode."); 268545SN/A} 2698598SN/A 2709294Sandreas.hansson@arm.comBaseMasterPort & 2719294Sandreas.hansson@arm.comDmaDevice::getMasterPort(const std::string &if_name, PortID idx) 2728598SN/A{ 2738598SN/A if (if_name == "dma") { 2748922SN/A return dmaPort; 2758598SN/A } 2768922SN/A return PioDevice::getMasterPort(if_name, idx); 2778598SN/A} 278