dma_device.cc revision 9152
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 42545SN/A */ 43545SN/A 443090SN/A#include "base/chunk_generator.hh" 458232SN/A#include "debug/DMA.hh" 469152Satgutier@umich.edu#include "debug/Drain.hh" 479016Sandreas.hansson@arm.com#include "dev/dma_device.hh" 482901SN/A#include "sim/system.hh" 49545SN/A 509015SN/ADmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff) 519095Sandreas.hansson@arm.com : MasterPort(dev->name() + ".dma", dev), device(dev), sys(s), 528832SN/A masterId(s->getMasterId(dev->name())), 539133Satgutier@umich.edu pendingCount(0), drainEvent(NULL), 547403SN/A backoffTime(0), minBackoffDelay(min_backoff), 559015SN/A maxBackoffDelay(max_backoff), inRetry(false), 568711SN/A backoffEvent(this) 572489SN/A{ } 582489SN/A 592489SN/Abool 608975SN/ADmaPort::recvTimingResp(PacketPtr pkt) 612384SN/A{ 624870SN/A if (pkt->wasNacked()) { 634739SN/A DPRINTF(DMA, "Received nacked %s addr %#x\n", 644739SN/A pkt->cmdString(), pkt->getAddr()); 654435SN/A 667403SN/A if (backoffTime < minBackoffDelay) 677403SN/A backoffTime = minBackoffDelay; 687403SN/A else if (backoffTime < maxBackoffDelay) 694435SN/A backoffTime <<= 1; 704435SN/A 718708SN/A device->reschedule(backoffEvent, curTick() + backoffTime, true); 724435SN/A 734435SN/A DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime); 744435SN/A 752685SN/A pkt->reinitNacked(); 764435SN/A queueDma(pkt, true); 772685SN/A } else if (pkt->senderState) { 782565SN/A DmaReqState *state; 794435SN/A backoffTime >>= 2; 804435SN/A 814739SN/A DPRINTF(DMA, "Received response %s addr %#x size %#x\n", 824739SN/A pkt->cmdString(), pkt->getAddr(), pkt->req->getSize()); 832641SN/A state = dynamic_cast<DmaReqState*>(pkt->senderState); 842685SN/A pendingCount--; 852685SN/A 862685SN/A assert(pendingCount >= 0); 872657SN/A assert(state); 882685SN/A 898134SN/A // We shouldn't ever get a block in ownership state 908134SN/A assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); 918134SN/A 922685SN/A state->numBytes += pkt->req->getSize(); 934435SN/A assert(state->totBytes >= state->numBytes); 942685SN/A if (state->totBytes == state->numBytes) { 957403SN/A if (state->completionEvent) { 967403SN/A if (state->delay) 978708SN/A device->schedule(state->completionEvent, 988708SN/A curTick() + state->delay); 997403SN/A else 1007403SN/A state->completionEvent->process(); 1017403SN/A } 1022685SN/A delete state; 1032685SN/A } 1042630SN/A delete pkt->req; 1052630SN/A delete pkt; 1062901SN/A 1079152Satgutier@umich.edu if (pendingCount == 0 && transmitList.empty() && drainEvent) { 1082901SN/A drainEvent->process(); 1092901SN/A drainEvent = NULL; 1102901SN/A } 1112569SN/A } else { 1122685SN/A panic("Got packet without sender state... huh?\n"); 1132565SN/A } 1142569SN/A 1152657SN/A return true; 1162384SN/A} 117679SN/A 1184762SN/ADmaDevice::DmaDevice(const Params *p) 1198851SN/A : PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay, 1208851SN/A params()->max_backoff_delay) 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 1312901SN/Aunsigned int 1322901SN/ADmaDevice::drain(Event *de) 1332901SN/A{ 1342901SN/A unsigned int count; 1358851SN/A count = pioPort.drain(de) + dmaPort.drain(de); 1362901SN/A if (count) 1372901SN/A changeState(Draining); 1382901SN/A else 1392901SN/A changeState(Drained); 1402901SN/A return count; 1412901SN/A} 1422901SN/A 1432901SN/Aunsigned int 1442901SN/ADmaPort::drain(Event *de) 1452901SN/A{ 1469152Satgutier@umich.edu if (transmitList.empty() && pendingCount == 0) 1472901SN/A return 0; 1482901SN/A drainEvent = de; 1499152Satgutier@umich.edu DPRINTF(Drain, "DmaPort not drained\n"); 1502901SN/A return 1; 1512901SN/A} 1522901SN/A 1532384SN/Avoid 1542489SN/ADmaPort::recvRetry() 1552489SN/A{ 1564435SN/A assert(transmitList.size()); 1572659SN/A bool result = true; 1584435SN/A do { 1595539SN/A PacketPtr pkt = transmitList.front(); 1604739SN/A DPRINTF(DMA, "Retry on %s addr %#x\n", 1614739SN/A pkt->cmdString(), pkt->getAddr()); 1628975SN/A result = sendTimingReq(pkt); 1632659SN/A if (result) { 1642659SN/A DPRINTF(DMA, "-- Done\n"); 1652659SN/A transmitList.pop_front(); 1664435SN/A inRetry = false; 1672659SN/A } else { 1684435SN/A inRetry = true; 1692659SN/A DPRINTF(DMA, "-- Failed, queued\n"); 1702659SN/A } 1714435SN/A } while (!backoffTime && result && transmitList.size()); 1724435SN/A 1734435SN/A if (transmitList.size() && backoffTime && !inRetry) { 1747823SN/A DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime); 1754435SN/A if (!backoffEvent.scheduled()) 1768708SN/A device->schedule(backoffEvent, backoffTime + curTick()); 1772657SN/A } 1784435SN/A DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", 1794435SN/A transmitList.size(), backoffTime, inRetry, 1804435SN/A backoffEvent.scheduled()); 1812489SN/A} 1822641SN/A 1832489SN/Avoid 1842641SN/ADmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 1857607SN/A uint8_t *data, Tick delay, Request::Flags flag) 1862384SN/A{ 1879016Sandreas.hansson@arm.com DmaReqState *reqState = new DmaReqState(event, size, delay); 1882384SN/A 1894451SN/A 1904451SN/A DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size, 1917607SN/A event ? event->scheduled() : -1 ); 1922406SN/A for (ChunkGenerator gen(addr, size, peerBlockSize()); 1932406SN/A !gen.done(); gen.next()) { 1948832SN/A Request *req = new Request(gen.addr(), gen.size(), flag, masterId); 1958949SN/A PacketPtr pkt = new Packet(req, cmd); 1962641SN/A 1972384SN/A // Increment the data pointer on a write 1982566SN/A if (data) 1992685SN/A pkt->dataStatic(data + gen.complete()); 2002641SN/A 2012685SN/A pkt->senderState = reqState; 2022641SN/A 2032565SN/A assert(pendingCount >= 0); 2042565SN/A pendingCount++; 2054451SN/A DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), 2064451SN/A gen.size()); 2074435SN/A queueDma(pkt); 2082384SN/A } 2092901SN/A 2102384SN/A} 2112384SN/A 2124435SN/Avoid 2134435SN/ADmaPort::queueDma(PacketPtr pkt, bool front) 2144435SN/A{ 2154435SN/A 2164435SN/A if (front) 2174435SN/A transmitList.push_front(pkt); 2184435SN/A else 2194435SN/A transmitList.push_back(pkt); 2204435SN/A sendDma(); 2214435SN/A} 2224435SN/A 2232384SN/Avoid 2244435SN/ADmaPort::sendDma() 2252384SN/A{ 2262901SN/A // some kind of selction between access methods 2272901SN/A // more work is going to have to be done to make 2282901SN/A // switching actually work 2294435SN/A assert(transmitList.size()); 2304435SN/A PacketPtr pkt = transmitList.front(); 2312902SN/A 2324762SN/A Enums::MemoryMode state = sys->getMemoryMode(); 2334762SN/A if (state == Enums::timing) { 2344435SN/A if (backoffEvent.scheduled() || inRetry) { 2354435SN/A DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n"); 2364435SN/A return; 2374435SN/A } 2384435SN/A 2394739SN/A DPRINTF(DMA, "Attempting to send %s addr %#x\n", 2404739SN/A pkt->cmdString(), pkt->getAddr()); 2414435SN/A 2424435SN/A bool result; 2434435SN/A do { 2448975SN/A result = sendTimingReq(pkt); 2454435SN/A if (result) { 2464435SN/A transmitList.pop_front(); 2474435SN/A DPRINTF(DMA, "-- Done\n"); 2484435SN/A } else { 2494435SN/A inRetry = true; 2504435SN/A DPRINTF(DMA, "-- Failed: queued\n"); 2514435SN/A } 2524435SN/A } while (result && !backoffTime && transmitList.size()); 2534435SN/A 2544435SN/A if (transmitList.size() && backoffTime && !inRetry && 2554435SN/A !backoffEvent.scheduled()) { 2564451SN/A DPRINTF(DMA, "-- Scheduling backoff timer for %d\n", 2577823SN/A backoffTime+curTick()); 2588708SN/A device->schedule(backoffEvent, backoffTime + curTick()); 2592901SN/A } 2604762SN/A } else if (state == Enums::atomic) { 2614435SN/A transmitList.pop_front(); 2624435SN/A 2632902SN/A Tick lat; 2644451SN/A DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n", 2654451SN/A pkt->req->getPaddr(), pkt->req->getSize()); 2662902SN/A lat = sendAtomic(pkt); 2672901SN/A assert(pkt->senderState); 2682901SN/A DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); 2692901SN/A assert(state); 2704451SN/A state->numBytes += pkt->req->getSize(); 2712384SN/A 2724451SN/A DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n", 2734451SN/A pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes, 2747403SN/A state->totBytes, 2757403SN/A state->completionEvent ? state->completionEvent->scheduled() : 0 ); 2764451SN/A 2772901SN/A if (state->totBytes == state->numBytes) { 2787403SN/A if (state->completionEvent) { 2797403SN/A assert(!state->completionEvent->scheduled()); 2808708SN/A device->schedule(state->completionEvent, 2818708SN/A curTick() + lat + state->delay); 2827403SN/A } 2832901SN/A delete state; 2842901SN/A delete pkt->req; 2852901SN/A } 2862901SN/A pendingCount--; 2872901SN/A assert(pendingCount >= 0); 2882901SN/A delete pkt; 2892566SN/A 2909152Satgutier@umich.edu if (pendingCount == 0 && transmitList.empty() && drainEvent) { 2919152Satgutier@umich.edu DPRINTF(Drain, "DmaPort done draining, processing drain event\n"); 2922901SN/A drainEvent->process(); 2932901SN/A drainEvent = NULL; 2942901SN/A } 2952901SN/A 2962384SN/A } else 2972384SN/A panic("Unknown memory command state."); 2982384SN/A} 299545SN/A 300545SN/ADmaDevice::~DmaDevice() 301545SN/A{ 302545SN/A} 3038598SN/A 3048922SN/AMasterPort & 3058922SN/ADmaDevice::getMasterPort(const std::string &if_name, int idx) 3068598SN/A{ 3078598SN/A if (if_name == "dma") { 3088922SN/A return dmaPort; 3098598SN/A } 3108922SN/A return PioDevice::getMasterPort(if_name, idx); 3118598SN/A} 312