dma_device.cc revision 9133
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" 469016Sandreas.hansson@arm.com#include "dev/dma_device.hh" 472901SN/A#include "sim/system.hh" 48545SN/A 499015SN/ADmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff) 509095Sandreas.hansson@arm.com : MasterPort(dev->name() + ".dma", dev), device(dev), sys(s), 518832SN/A masterId(s->getMasterId(dev->name())), 529133Satgutier@umich.edu pendingCount(0), drainEvent(NULL), 537403SN/A backoffTime(0), minBackoffDelay(min_backoff), 549015SN/A maxBackoffDelay(max_backoff), inRetry(false), 558711SN/A backoffEvent(this) 562489SN/A{ } 572489SN/A 582489SN/Abool 598975SN/ADmaPort::recvTimingResp(PacketPtr pkt) 602384SN/A{ 614870SN/A if (pkt->wasNacked()) { 624739SN/A DPRINTF(DMA, "Received nacked %s addr %#x\n", 634739SN/A pkt->cmdString(), pkt->getAddr()); 644435SN/A 657403SN/A if (backoffTime < minBackoffDelay) 667403SN/A backoffTime = minBackoffDelay; 677403SN/A else if (backoffTime < maxBackoffDelay) 684435SN/A backoffTime <<= 1; 694435SN/A 708708SN/A device->reschedule(backoffEvent, curTick() + backoffTime, true); 714435SN/A 724435SN/A DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime); 734435SN/A 742685SN/A pkt->reinitNacked(); 754435SN/A queueDma(pkt, true); 762685SN/A } else if (pkt->senderState) { 772565SN/A DmaReqState *state; 784435SN/A backoffTime >>= 2; 794435SN/A 804739SN/A DPRINTF(DMA, "Received response %s addr %#x size %#x\n", 814739SN/A pkt->cmdString(), pkt->getAddr(), pkt->req->getSize()); 822641SN/A state = dynamic_cast<DmaReqState*>(pkt->senderState); 832685SN/A pendingCount--; 842685SN/A 852685SN/A assert(pendingCount >= 0); 862657SN/A assert(state); 872685SN/A 888134SN/A // We shouldn't ever get a block in ownership state 898134SN/A assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); 908134SN/A 912685SN/A state->numBytes += pkt->req->getSize(); 924435SN/A assert(state->totBytes >= state->numBytes); 932685SN/A if (state->totBytes == state->numBytes) { 947403SN/A if (state->completionEvent) { 957403SN/A if (state->delay) 968708SN/A device->schedule(state->completionEvent, 978708SN/A curTick() + state->delay); 987403SN/A else 997403SN/A state->completionEvent->process(); 1007403SN/A } 1012685SN/A delete state; 1022685SN/A } 1032630SN/A delete pkt->req; 1042630SN/A delete pkt; 1052901SN/A 1062901SN/A if (pendingCount == 0 && drainEvent) { 1072901SN/A drainEvent->process(); 1082901SN/A drainEvent = NULL; 1092901SN/A } 1102569SN/A } else { 1112685SN/A panic("Got packet without sender state... huh?\n"); 1122565SN/A } 1132569SN/A 1142657SN/A return true; 1152384SN/A} 116679SN/A 1174762SN/ADmaDevice::DmaDevice(const Params *p) 1188851SN/A : PioDevice(p), dmaPort(this, sys, params()->min_backoff_delay, 1198851SN/A params()->max_backoff_delay) 1202565SN/A{ } 1212384SN/A 1228851SN/Avoid 1238851SN/ADmaDevice::init() 1248851SN/A{ 1258851SN/A if (!dmaPort.isConnected()) 1268851SN/A panic("DMA port of %s not connected to anything!", name()); 1278851SN/A PioDevice::init(); 1288851SN/A} 1298851SN/A 1302901SN/Aunsigned int 1312901SN/ADmaDevice::drain(Event *de) 1322901SN/A{ 1332901SN/A unsigned int count; 1348851SN/A count = pioPort.drain(de) + dmaPort.drain(de); 1352901SN/A if (count) 1362901SN/A changeState(Draining); 1372901SN/A else 1382901SN/A changeState(Drained); 1392901SN/A return count; 1402901SN/A} 1412901SN/A 1422901SN/Aunsigned int 1432901SN/ADmaPort::drain(Event *de) 1442901SN/A{ 1452901SN/A if (pendingCount == 0) 1462901SN/A return 0; 1472901SN/A drainEvent = de; 1482901SN/A return 1; 1492901SN/A} 1502901SN/A 1512384SN/Avoid 1522489SN/ADmaPort::recvRetry() 1532489SN/A{ 1544435SN/A assert(transmitList.size()); 1552659SN/A bool result = true; 1564435SN/A do { 1575539SN/A PacketPtr pkt = transmitList.front(); 1584739SN/A DPRINTF(DMA, "Retry on %s addr %#x\n", 1594739SN/A pkt->cmdString(), pkt->getAddr()); 1608975SN/A result = sendTimingReq(pkt); 1612659SN/A if (result) { 1622659SN/A DPRINTF(DMA, "-- Done\n"); 1632659SN/A transmitList.pop_front(); 1644435SN/A inRetry = false; 1652659SN/A } else { 1664435SN/A inRetry = true; 1672659SN/A DPRINTF(DMA, "-- Failed, queued\n"); 1682659SN/A } 1694435SN/A } while (!backoffTime && result && transmitList.size()); 1704435SN/A 1714435SN/A if (transmitList.size() && backoffTime && !inRetry) { 1727823SN/A DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime); 1734435SN/A if (!backoffEvent.scheduled()) 1748708SN/A device->schedule(backoffEvent, backoffTime + curTick()); 1752657SN/A } 1764435SN/A DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", 1774435SN/A transmitList.size(), backoffTime, inRetry, 1784435SN/A backoffEvent.scheduled()); 1792489SN/A} 1802641SN/A 1812489SN/Avoid 1822641SN/ADmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 1837607SN/A uint8_t *data, Tick delay, Request::Flags flag) 1842384SN/A{ 1852901SN/A assert(device->getState() == SimObject::Running); 1862901SN/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 2902901SN/A if (pendingCount == 0 && drainEvent) { 2912901SN/A drainEvent->process(); 2922901SN/A drainEvent = NULL; 2932901SN/A } 2942901SN/A 2952384SN/A } else 2962384SN/A panic("Unknown memory command state."); 2972384SN/A} 298545SN/A 299545SN/ADmaDevice::~DmaDevice() 300545SN/A{ 301545SN/A} 3028598SN/A 3038922SN/AMasterPort & 3048922SN/ADmaDevice::getMasterPort(const std::string &if_name, int idx) 3058598SN/A{ 3068598SN/A if (if_name == "dma") { 3078922SN/A return dmaPort; 3088598SN/A } 3098922SN/A return PioDevice::getMasterPort(if_name, idx); 3108598SN/A} 311