dma_device.cc revision 8708
12SN/A/* 21762SN/A * Copyright (c) 2006 The Regents of The University of Michigan 37897Shestness@cs.utexas.edu * All rights reserved. 42SN/A * 52SN/A * Redistribution and use in source and binary forms, with or without 62SN/A * modification, are permitted provided that the following conditions are 72SN/A * met: redistributions of source code must retain the above copyright 82SN/A * notice, this list of conditions and the following disclaimer; 92SN/A * redistributions in binary form must reproduce the above copyright 102SN/A * notice, this list of conditions and the following disclaimer in the 112SN/A * documentation and/or other materials provided with the distribution; 122SN/A * neither the name of the copyright holders nor the names of its 132SN/A * contributors may be used to endorse or promote products derived from 142SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272SN/A * 282665Ssaidi@eecs.umich.edu * Authors: Ali Saidi 292665Ssaidi@eecs.umich.edu * Nathan Binkert 302665Ssaidi@eecs.umich.edu */ 317897Shestness@cs.utexas.edu 322SN/A#include "base/chunk_generator.hh" 332SN/A#include "base/trace.hh" 341388SN/A#include "debug/BusAddrRanges.hh" 358229Snate@binkert.org#include "debug/DMA.hh" 362SN/A#include "dev/io_device.hh" 372SN/A#include "sim/system.hh" 387781SAli.Saidi@ARM.com 398229Snate@binkert.orgPioPort::PioPort(PioDevice *dev, System *s, std::string pname) 401191SN/A : SimpleTimingPort(dev->name() + pname, dev), device(dev) 411191SN/A{ } 421388SN/A 435529Snate@binkert.org 441717SN/ATick 452651Ssaidi@eecs.umich.eduPioPort::recvAtomic(PacketPtr pkt) 468229Snate@binkert.org{ 472680Sktlim@umich.edu return pkt->isRead() ? device->read(pkt) : device->write(pkt); 488232Snate@binkert.org} 495529Snate@binkert.org 502190SN/Avoid 5156SN/APioPort::getDeviceAddressRanges(AddrRangeList &resp, bool &snoop) 528229Snate@binkert.org{ 532190SN/A snoop = false; 542SN/A device->addressRanges(resp); 552359SN/A for (AddrRangeIter i = resp.begin(); i != resp.end(); i++) 562359SN/A DPRINTF(BusAddrRanges, "Adding Range %#x-%#x\n", i->start, i->end); 572359SN/A} 582SN/A 592SN/A 602SN/APioDevice::PioDevice(const Params *p) 612SN/A : MemObject(p), platform(p->platform), sys(p->system), pioPort(NULL) 622SN/A{} 632SN/A 642SN/APioDevice::~PioDevice() 652SN/A{ 662SN/A if (pioPort) 675606Snate@binkert.org delete pioPort; 686144Sksewell@umich.edu} 696144Sksewell@umich.edu 703126Sktlim@umich.eduvoid 716144Sksewell@umich.eduPioDevice::init() 727823Ssteve.reinhardt@amd.com{ 733126Sktlim@umich.edu if (!pioPort) 743126Sktlim@umich.edu panic("Pio port of %s not connected to anything!", name()); 752356SN/A pioPort->sendStatusChange(Port::RangeChange); 762356SN/A} 772356SN/A 782367SN/APort * 792356SN/APioDevice::getPort(const std::string &if_name, int idx) 806144Sksewell@umich.edu{ 812367SN/A if (if_name == "pio") { 826144Sksewell@umich.edu if (pioPort != NULL) 836144Sksewell@umich.edu fatal("%s: pio port already connected to %s", 846144Sksewell@umich.edu name(), pioPort->getPeer()->name()); 852356SN/A pioPort = new PioPort(this, sys); 862367SN/A return pioPort; 876144Sksewell@umich.edu } 887823Ssteve.reinhardt@amd.com return NULL; 896144Sksewell@umich.edu} 902367SN/A 912356SN/Aunsigned int 926144Sksewell@umich.eduPioDevice::drain(Event *de) 936144Sksewell@umich.edu{ 947823Ssteve.reinhardt@amd.com unsigned int count; 952356SN/A count = pioPort->drain(de); 962356SN/A if (count) 972356SN/A changeState(Draining); 985336Shines@cs.fsu.edu else 992356SN/A changeState(Drained); 1004873Sstever@eecs.umich.edu return count; 1012356SN/A} 1022356SN/A 1031400SN/ABasicPioDevice::BasicPioDevice(const Params *p) 1045712Shsul@eecs.umich.edu : PioDevice(p), pioAddr(p->pio_addr), pioSize(0), 1055712Shsul@eecs.umich.edu pioDelay(p->pio_latency) 1066221Snate@binkert.org{} 1073661Srdreslin@umich.edu 1082SN/Avoid 1097823Ssteve.reinhardt@amd.comBasicPioDevice::addressRanges(AddrRangeList &range_list) 1101062SN/A{ 1115712Shsul@eecs.umich.edu assert(pioSize != 0); 1125712Shsul@eecs.umich.edu range_list.clear(); 1135712Shsul@eecs.umich.edu DPRINTF(BusAddrRanges, "registering range: %#x-%#x\n", pioAddr, pioSize); 1145712Shsul@eecs.umich.edu range_list.push_back(RangeSize(pioAddr, pioSize)); 1155712Shsul@eecs.umich.edu} 1162SN/A 1172SN/A 1182SN/ADmaPort::DmaPort(MemObject *dev, System *s, Tick min_backoff, Tick max_backoff, 1195712Shsul@eecs.umich.edu bool recv_snoops) 1205712Shsul@eecs.umich.edu : Port(dev->name() + "-dmaport", dev), device(dev), sys(s), 1216221Snate@binkert.org pendingCount(0), actionInProgress(0), drainEvent(NULL), 1226221Snate@binkert.org backoffTime(0), minBackoffDelay(min_backoff), 1232SN/A maxBackoffDelay(max_backoff), inRetry(false), recvSnoops(recv_snoops), 1242SN/A snoopRangeSent(false), backoffEvent(this) 1256221Snate@binkert.org{ } 1266221Snate@binkert.org 1276221Snate@binkert.orgbool 1286221Snate@binkert.orgDmaPort::recvTiming(PacketPtr pkt) 1292SN/A{ 1302SN/A if (pkt->wasNacked()) { 1312SN/A DPRINTF(DMA, "Received nacked %s addr %#x\n", 1322SN/A pkt->cmdString(), pkt->getAddr()); 1335606Snate@binkert.org 1345606Snate@binkert.org if (backoffTime < minBackoffDelay) 1356221Snate@binkert.org backoffTime = minBackoffDelay; 1365606Snate@binkert.org else if (backoffTime < maxBackoffDelay) 1376221Snate@binkert.org backoffTime <<= 1; 1385606Snate@binkert.org 1395606Snate@binkert.org device->reschedule(backoffEvent, curTick() + backoffTime, true); 1402SN/A 1411400SN/A DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime); 1425606Snate@binkert.org 1435606Snate@binkert.org pkt->reinitNacked(); 1442SN/A queueDma(pkt, true); 1452SN/A } else if (pkt->isRequest() && recvSnoops) { 1462SN/A return true; 1472SN/A } else if (pkt->senderState) { 1486221Snate@binkert.org DmaReqState *state; 1496221Snate@binkert.org backoffTime >>= 2; 1505606Snate@binkert.org 1516670Shsul@eecs.umich.edu DPRINTF(DMA, "Received response %s addr %#x size %#x\n", 1525606Snate@binkert.org pkt->cmdString(), pkt->getAddr(), pkt->req->getSize()); 1532SN/A state = dynamic_cast<DmaReqState*>(pkt->senderState); 1542SN/A pendingCount--; 155124SN/A 1566221Snate@binkert.org assert(pendingCount >= 0); 1576221Snate@binkert.org assert(state); 1586221Snate@binkert.org 159124SN/A // We shouldn't ever get a block in ownership state 160124SN/A assert(!(pkt->memInhibitAsserted() && !pkt->sharedAsserted())); 161124SN/A 162124SN/A state->numBytes += pkt->req->getSize(); 1635606Snate@binkert.org assert(state->totBytes >= state->numBytes); 1645606Snate@binkert.org if (state->totBytes == state->numBytes) { 1656221Snate@binkert.org if (state->completionEvent) { 1665606Snate@binkert.org if (state->delay) 1676221Snate@binkert.org device->schedule(state->completionEvent, 1685606Snate@binkert.org curTick() + state->delay); 1695606Snate@binkert.org else 170124SN/A state->completionEvent->process(); 1711400SN/A } 1725606Snate@binkert.org delete state; 173124SN/A } 174124SN/A delete pkt->req; 175124SN/A delete pkt; 176124SN/A 1776221Snate@binkert.org if (pendingCount == 0 && drainEvent) { 1786221Snate@binkert.org drainEvent->process(); 1795606Snate@binkert.org drainEvent = NULL; 1806221Snate@binkert.org } 1815606Snate@binkert.org } else { 182124SN/A panic("Got packet without sender state... huh?\n"); 183124SN/A } 1841191SN/A 1855529Snate@binkert.org return true; 1861388SN/A} 1871191SN/A 1885529Snate@binkert.orgDmaDevice::DmaDevice(const Params *p) 1891191SN/A : PioDevice(p), dmaPort(NULL) 1905529Snate@binkert.org{ } 1911191SN/A 1921191SN/A 1935606Snate@binkert.orgunsigned int 1945606Snate@binkert.orgDmaDevice::drain(Event *de) 1955606Snate@binkert.org{ 1961191SN/A unsigned int count; 1971191SN/A count = pioPort->drain(de) + dmaPort->drain(de); 1985810Sgblack@eecs.umich.edu if (count) 1995810Sgblack@eecs.umich.edu changeState(Draining); 2008745Sgblack@eecs.umich.edu else 2011917SN/A changeState(Drained); 2025529Snate@binkert.org return count; 2035529Snate@binkert.org} 2041917SN/A 2055529Snate@binkert.orgunsigned int 2061917SN/ADmaPort::drain(Event *de) 2071191SN/A{ 2081191SN/A if (pendingCount == 0) 2091191SN/A return 0; 2101191SN/A drainEvent = de; 2111191SN/A return 1; 2121191SN/A} 2131191SN/A 2141191SN/A 2151191SN/Avoid 2161191SN/ADmaPort::recvRetry() 2171191SN/A{ 2181129SN/A assert(transmitList.size()); 2191129SN/A bool result = true; 2201129SN/A do { 2215529Snate@binkert.org PacketPtr pkt = transmitList.front(); 2222680Sktlim@umich.edu DPRINTF(DMA, "Retry on %s addr %#x\n", 2231129SN/A pkt->cmdString(), pkt->getAddr()); 224180SN/A result = sendTiming(pkt); 2252SN/A if (result) { 2261917SN/A DPRINTF(DMA, "-- Done\n"); 2271917SN/A transmitList.pop_front(); 2281917SN/A inRetry = false; 2295529Snate@binkert.org } else { 2307823Ssteve.reinhardt@amd.com inRetry = true; 2311917SN/A DPRINTF(DMA, "-- Failed, queued\n"); 2322356SN/A } 2335529Snate@binkert.org } while (!backoffTime && result && transmitList.size()); 2345606Snate@binkert.org 2356144Sksewell@umich.edu if (transmitList.size() && backoffTime && !inRetry) { 2366144Sksewell@umich.edu DPRINTF(DMA, "Scheduling backoff for %d\n", curTick()+backoffTime); 2376144Sksewell@umich.edu if (!backoffEvent.scheduled()) 2382356SN/A device->schedule(backoffEvent, backoffTime + curTick()); 2391917SN/A } 2401917SN/A DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", 2411917SN/A transmitList.size(), backoffTime, inRetry, 2421917SN/A backoffEvent.scheduled()); 2432SN/A} 2442SN/A 245729SN/A 246707SN/Avoid 247707SN/ADmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 248707SN/A uint8_t *data, Tick delay, Request::Flags flag) 249707SN/A{ 250707SN/A assert(device->getState() == SimObject::Running); 251707SN/A 2527914SBrad.Beckmann@amd.com DmaReqState *reqState = new DmaReqState(event, this, size, delay); 2537914SBrad.Beckmann@amd.com 2547914SBrad.Beckmann@amd.com 2557914SBrad.Beckmann@amd.com DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size, 2567914SBrad.Beckmann@amd.com event ? event->scheduled() : -1 ); 2577914SBrad.Beckmann@amd.com for (ChunkGenerator gen(addr, size, peerBlockSize()); 2587914SBrad.Beckmann@amd.com !gen.done(); gen.next()) { 2597914SBrad.Beckmann@amd.com Request *req = new Request(gen.addr(), gen.size(), flag); 2607914SBrad.Beckmann@amd.com PacketPtr pkt = new Packet(req, cmd, Packet::Broadcast); 2617914SBrad.Beckmann@amd.com 2622680Sktlim@umich.edu // Increment the data pointer on a write 2632SN/A if (data) 2642SN/A pkt->dataStatic(data + gen.complete()); 2652SN/A 2662SN/A pkt->senderState = reqState; 2672680Sktlim@umich.edu 2682SN/A assert(pendingCount >= 0); 2692SN/A pendingCount++; 2702680Sktlim@umich.edu DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), 2712190SN/A gen.size()); 2722190SN/A queueDma(pkt); 2732190SN/A } 2742SN/A 2752SN/A} 2763495Sktlim@umich.edu 2773495Sktlim@umich.eduvoid 2783495Sktlim@umich.eduDmaPort::queueDma(PacketPtr pkt, bool front) 2797823Ssteve.reinhardt@amd.com{ 2803495Sktlim@umich.edu 2813661Srdreslin@umich.edu if (front) 2823495Sktlim@umich.edu transmitList.push_front(pkt); 2833495Sktlim@umich.edu else 2843495Sktlim@umich.edu transmitList.push_back(pkt); 2853495Sktlim@umich.edu sendDma(); 2863495Sktlim@umich.edu} 2873495Sktlim@umich.edu 2883495Sktlim@umich.edu 2894599Sacolyte@umich.eduvoid 2904599Sacolyte@umich.eduDmaPort::sendDma() 2913661Srdreslin@umich.edu{ 2923495Sktlim@umich.edu // some kind of selction between access methods 2937823Ssteve.reinhardt@amd.com // more work is going to have to be done to make 2943495Sktlim@umich.edu // switching actually work 2953495Sktlim@umich.edu assert(transmitList.size()); 296180SN/A PacketPtr pkt = transmitList.front(); 297180SN/A 2982680Sktlim@umich.edu Enums::MemoryMode state = sys->getMemoryMode(); 299180SN/A if (state == Enums::timing) { 3006221Snate@binkert.org if (backoffEvent.scheduled() || inRetry) { 3016221Snate@binkert.org DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n"); 3026221Snate@binkert.org return; 3032378SN/A } 3045718Shsul@eecs.umich.edu 3055718Shsul@eecs.umich.edu DPRINTF(DMA, "Attempting to send %s addr %#x\n", 3065718Shsul@eecs.umich.edu pkt->cmdString(), pkt->getAddr()); 3075718Shsul@eecs.umich.edu 3085718Shsul@eecs.umich.edu bool result; 3095718Shsul@eecs.umich.edu do { 3105718Shsul@eecs.umich.edu result = sendTiming(pkt); 3116221Snate@binkert.org if (result) { 3125718Shsul@eecs.umich.edu transmitList.pop_front(); 3135718Shsul@eecs.umich.edu DPRINTF(DMA, "-- Done\n"); 3145718Shsul@eecs.umich.edu } else { 3155713Shsul@eecs.umich.edu inRetry = true; 3165714Shsul@eecs.umich.edu DPRINTF(DMA, "-- Failed: queued\n"); 317180SN/A } 318180SN/A } while (result && !backoffTime && transmitList.size()); 319180SN/A 320180SN/A if (transmitList.size() && backoffTime && !inRetry && 321180SN/A !backoffEvent.scheduled()) { 3224000Ssaidi@eecs.umich.edu DPRINTF(DMA, "-- Scheduling backoff timer for %d\n", 3234000Ssaidi@eecs.umich.edu backoffTime+curTick()); 3244000Ssaidi@eecs.umich.edu device->schedule(backoffEvent, backoffTime + curTick()); 3256221Snate@binkert.org } 3266221Snate@binkert.org } else if (state == Enums::atomic) { 3276221Snate@binkert.org transmitList.pop_front(); 3286221Snate@binkert.org 3294000Ssaidi@eecs.umich.edu Tick lat; 3304000Ssaidi@eecs.umich.edu DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n", 3314000Ssaidi@eecs.umich.edu pkt->req->getPaddr(), pkt->req->getSize()); 3324000Ssaidi@eecs.umich.edu lat = sendAtomic(pkt); 333180SN/A assert(pkt->senderState); 3342798Sktlim@umich.edu DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); 335180SN/A assert(state); 3362359SN/A state->numBytes += pkt->req->getSize(); 3372359SN/A 3382359SN/A DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n", 3395606Snate@binkert.org pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes, 3402359SN/A state->totBytes, 341180SN/A state->completionEvent ? state->completionEvent->scheduled() : 0 ); 342180SN/A 343180SN/A if (state->totBytes == state->numBytes) { 3444192Sktlim@umich.edu if (state->completionEvent) { 345180SN/A assert(!state->completionEvent->scheduled()); 3462680Sktlim@umich.edu device->schedule(state->completionEvent, 347180SN/A curTick() + lat + state->delay); 3485712Shsul@eecs.umich.edu } 3495712Shsul@eecs.umich.edu delete state; 3506221Snate@binkert.org delete pkt->req; 3516221Snate@binkert.org } 3522680Sktlim@umich.edu pendingCount--; 3532680Sktlim@umich.edu assert(pendingCount >= 0); 354180SN/A delete pkt; 3552680Sktlim@umich.edu 3562651Ssaidi@eecs.umich.edu if (pendingCount == 0 && drainEvent) { 3572680Sktlim@umich.edu drainEvent->process(); 3582651Ssaidi@eecs.umich.edu drainEvent = NULL; 3595714Shsul@eecs.umich.edu } 3605715Shsul@eecs.umich.edu 3615714Shsul@eecs.umich.edu } else 3622359SN/A panic("Unknown memory command state."); 3635875Ssteve.reinhardt@amd.com} 3645875Ssteve.reinhardt@amd.com 3655875Ssteve.reinhardt@amd.comDmaDevice::~DmaDevice() 3665875Ssteve.reinhardt@amd.com{ 3675217Ssaidi@eecs.umich.edu if (dmaPort) 3685875Ssteve.reinhardt@amd.com delete dmaPort; 3697781SAli.Saidi@ARM.com} 3707781SAli.Saidi@ARM.com 3717781SAli.Saidi@ARM.com 3727781SAli.Saidi@ARM.comPort * 3737781SAli.Saidi@ARM.comDmaDevice::getPort(const std::string &if_name, int idx) 3747781SAli.Saidi@ARM.com{ 3757781SAli.Saidi@ARM.com if (if_name == "dma") { 3767781SAli.Saidi@ARM.com if (dmaPort != NULL) 3777781SAli.Saidi@ARM.com fatal("%s: dma port already connected to %s", 3787781SAli.Saidi@ARM.com name(), dmaPort->getPeer()->name()); 3797781SAli.Saidi@ARM.com dmaPort = new DmaPort(this, sys, params()->min_backoff_delay, 3807781SAli.Saidi@ARM.com params()->max_backoff_delay); 3817781SAli.Saidi@ARM.com return dmaPort; 3827781SAli.Saidi@ARM.com } 3837781SAli.Saidi@ARM.com return PioDevice::getPort(if_name, idx); 3847781SAli.Saidi@ARM.com} 3857781SAli.Saidi@ARM.com 3867781SAli.Saidi@ARM.com