io_device.cc revision 2902
12929Sktlim@umich.edu/* 22929Sktlim@umich.edu * Copyright (c) 2006 The Regents of The University of Michigan 32932Sktlim@umich.edu * All rights reserved. 42929Sktlim@umich.edu * 52929Sktlim@umich.edu * Redistribution and use in source and binary forms, with or without 62929Sktlim@umich.edu * modification, are permitted provided that the following conditions are 72929Sktlim@umich.edu * met: redistributions of source code must retain the above copyright 82929Sktlim@umich.edu * notice, this list of conditions and the following disclaimer; 92929Sktlim@umich.edu * redistributions in binary form must reproduce the above copyright 102929Sktlim@umich.edu * notice, this list of conditions and the following disclaimer in the 112929Sktlim@umich.edu * documentation and/or other materials provided with the distribution; 122929Sktlim@umich.edu * neither the name of the copyright holders nor the names of its 132929Sktlim@umich.edu * contributors may be used to endorse or promote products derived from 142929Sktlim@umich.edu * this software without specific prior written permission. 152929Sktlim@umich.edu * 162929Sktlim@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172929Sktlim@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182929Sktlim@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192929Sktlim@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202929Sktlim@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212929Sktlim@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222929Sktlim@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232929Sktlim@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242929Sktlim@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252929Sktlim@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262929Sktlim@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272929Sktlim@umich.edu * 282932Sktlim@umich.edu * Authors: Ali Saidi 292932Sktlim@umich.edu * Nathan Binkert 302932Sktlim@umich.edu */ 312929Sktlim@umich.edu 326007Ssteve.reinhardt@amd.com#include "base/trace.hh" 337735SAli.Saidi@ARM.com#include "dev/io_device.hh" 342929Sktlim@umich.edu#include "sim/builder.hh" 352929Sktlim@umich.edu#include "sim/system.hh" 362929Sktlim@umich.edu 372929Sktlim@umich.edu 382929Sktlim@umich.eduPioPort::PioPort(PioDevice *dev, System *s, std::string pname) 392929Sktlim@umich.edu : Port(dev->name() + pname), device(dev), sys(s), 402929Sktlim@umich.edu outTiming(0), drainEvent(NULL) 412929Sktlim@umich.edu{ } 422929Sktlim@umich.edu 432929Sktlim@umich.edu 442929Sktlim@umich.eduTick 452929Sktlim@umich.eduPioPort::recvAtomic(Packet *pkt) 462929Sktlim@umich.edu{ 476007Ssteve.reinhardt@amd.com return device->recvAtomic(pkt); 486007Ssteve.reinhardt@amd.com} 496007Ssteve.reinhardt@amd.com 506007Ssteve.reinhardt@amd.comvoid 516007Ssteve.reinhardt@amd.comPioPort::recvFunctional(Packet *pkt) 526007Ssteve.reinhardt@amd.com{ 536007Ssteve.reinhardt@amd.com device->recvAtomic(pkt); 546007Ssteve.reinhardt@amd.com} 556007Ssteve.reinhardt@amd.com 566007Ssteve.reinhardt@amd.comvoid 576007Ssteve.reinhardt@amd.comPioPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) 586007Ssteve.reinhardt@amd.com{ 596007Ssteve.reinhardt@amd.com snoop.clear(); 606007Ssteve.reinhardt@amd.com device->addressRanges(resp); 616007Ssteve.reinhardt@amd.com} 626007Ssteve.reinhardt@amd.com 636007Ssteve.reinhardt@amd.com 646007Ssteve.reinhardt@amd.comvoid 656007Ssteve.reinhardt@amd.comPioPort::recvRetry() 666007Ssteve.reinhardt@amd.com{ 676007Ssteve.reinhardt@amd.com bool result = true; 686007Ssteve.reinhardt@amd.com while (result && transmitList.size()) { 696007Ssteve.reinhardt@amd.com result = Port::sendTiming(transmitList.front()); 706007Ssteve.reinhardt@amd.com if (result) 716007Ssteve.reinhardt@amd.com transmitList.pop_front(); 726007Ssteve.reinhardt@amd.com } 736007Ssteve.reinhardt@amd.com if (transmitList.size() == 0 && drainEvent) { 746007Ssteve.reinhardt@amd.com drainEvent->process(); 756007Ssteve.reinhardt@amd.com drainEvent = NULL; 762929Sktlim@umich.edu } 772929Sktlim@umich.edu} 782929Sktlim@umich.edu 796007Ssteve.reinhardt@amd.comvoid 806007Ssteve.reinhardt@amd.comPioPort::SendEvent::process() 816007Ssteve.reinhardt@amd.com{ 826007Ssteve.reinhardt@amd.com port->outTiming--; 836007Ssteve.reinhardt@amd.com assert(port->outTiming >= 0); 846007Ssteve.reinhardt@amd.com if (port->Port::sendTiming(packet)) 852929Sktlim@umich.edu if (port->transmitList.size() == 0 && port->drainEvent) { 862929Sktlim@umich.edu port->drainEvent->process(); 872929Sktlim@umich.edu port->drainEvent = NULL; 882929Sktlim@umich.edu } 892929Sktlim@umich.edu return; 906011Ssteve.reinhardt@amd.com 916007Ssteve.reinhardt@amd.com port->transmitList.push_back(packet); 926007Ssteve.reinhardt@amd.com} 936007Ssteve.reinhardt@amd.com 946007Ssteve.reinhardt@amd.comvoid 956007Ssteve.reinhardt@amd.comPioPort::resendNacked(Packet *pkt) { 966007Ssteve.reinhardt@amd.com pkt->reinitNacked(); 976007Ssteve.reinhardt@amd.com if (transmitList.size()) { 986007Ssteve.reinhardt@amd.com transmitList.push_front(pkt); 996007Ssteve.reinhardt@amd.com } else { 1006007Ssteve.reinhardt@amd.com if (!Port::sendTiming(pkt)) 1016007Ssteve.reinhardt@amd.com transmitList.push_front(pkt); 1026007Ssteve.reinhardt@amd.com } 1036007Ssteve.reinhardt@amd.com}; 1046007Ssteve.reinhardt@amd.com 1057735SAli.Saidi@ARM.com 1066011Ssteve.reinhardt@amd.combool 1076007Ssteve.reinhardt@amd.comPioPort::recvTiming(Packet *pkt) 1086007Ssteve.reinhardt@amd.com{ 1096007Ssteve.reinhardt@amd.com if (pkt->result == Packet::Nacked) { 1106007Ssteve.reinhardt@amd.com resendNacked(pkt); 1117735SAli.Saidi@ARM.com } else { 1127735SAli.Saidi@ARM.com Tick latency = device->recvAtomic(pkt); 1137735SAli.Saidi@ARM.com // turn packet around to go back to requester 1147735SAli.Saidi@ARM.com pkt->makeTimingResponse(); 1157735SAli.Saidi@ARM.com sendTiming(pkt, latency); 1167735SAli.Saidi@ARM.com } 1177735SAli.Saidi@ARM.com return true; 1187735SAli.Saidi@ARM.com} 1197735SAli.Saidi@ARM.com 1207735SAli.Saidi@ARM.comunsigned int 1217735SAli.Saidi@ARM.comPioPort::drain(Event *de) 1227735SAli.Saidi@ARM.com{ 1237735SAli.Saidi@ARM.com if (outTiming == 0 && transmitList.size() == 0) 1247735SAli.Saidi@ARM.com return 0; 1256007Ssteve.reinhardt@amd.com drainEvent = de; 1267685Ssteve.reinhardt@amd.com return 1; 1276007Ssteve.reinhardt@amd.com} 1286011Ssteve.reinhardt@amd.com 1296007Ssteve.reinhardt@amd.comPioDevice::~PioDevice() 1306007Ssteve.reinhardt@amd.com{ 1316007Ssteve.reinhardt@amd.com if (pioPort) 1326007Ssteve.reinhardt@amd.com delete pioPort; 1336007Ssteve.reinhardt@amd.com} 1346007Ssteve.reinhardt@amd.com 1356011Ssteve.reinhardt@amd.comvoid 1366007Ssteve.reinhardt@amd.comPioDevice::init() 1376007Ssteve.reinhardt@amd.com{ 1386007Ssteve.reinhardt@amd.com if (!pioPort) 1396007Ssteve.reinhardt@amd.com panic("Pio port not connected to anything!"); 1406007Ssteve.reinhardt@amd.com pioPort->sendStatusChange(Port::RangeChange); 1416008Ssteve.reinhardt@amd.com} 1426007Ssteve.reinhardt@amd.com 1436008Ssteve.reinhardt@amd.com 1446008Ssteve.reinhardt@amd.comunsigned int 1456008Ssteve.reinhardt@amd.comPioDevice::drain(Event *de) 1466008Ssteve.reinhardt@amd.com{ 1476008Ssteve.reinhardt@amd.com unsigned int count; 1486008Ssteve.reinhardt@amd.com count = pioPort->drain(de); 1496008Ssteve.reinhardt@amd.com if (count) 1506007Ssteve.reinhardt@amd.com changeState(Draining); 1516007Ssteve.reinhardt@amd.com else 1526007Ssteve.reinhardt@amd.com changeState(Drained); 1536007Ssteve.reinhardt@amd.com return count; 1546007Ssteve.reinhardt@amd.com} 1552929Sktlim@umich.edu 1562929Sktlim@umich.eduvoid 1572929Sktlim@umich.eduBasicPioDevice::addressRanges(AddrRangeList &range_list) 1582929Sktlim@umich.edu{ 1596007Ssteve.reinhardt@amd.com assert(pioSize != 0); 1606007Ssteve.reinhardt@amd.com range_list.clear(); 1612929Sktlim@umich.edu range_list.push_back(RangeSize(pioAddr, pioSize)); 1622929Sktlim@umich.edu} 1632929Sktlim@umich.edu 1642929Sktlim@umich.edu 1656007Ssteve.reinhardt@amd.comDmaPort::DmaPort(DmaDevice *dev, System *s) 1666007Ssteve.reinhardt@amd.com : Port(dev->name() + "-dmaport"), device(dev), sys(s), pendingCount(0), 1672929Sktlim@umich.edu actionInProgress(0), drainEvent(NULL) 1682929Sktlim@umich.edu{ } 1696007Ssteve.reinhardt@amd.com 1702929Sktlim@umich.edubool 1712929Sktlim@umich.eduDmaPort::recvTiming(Packet *pkt) 1722929Sktlim@umich.edu{ 1732929Sktlim@umich.edu 1742929Sktlim@umich.edu 1752929Sktlim@umich.edu if (pkt->result == Packet::Nacked) { 1762929Sktlim@umich.edu DPRINTF(DMA, "Received nacked Pkt %#x with State: %#x Addr: %#x\n", 1774937Sstever@gmail.com pkt, pkt->senderState, pkt->getAddr()); 1784937Sstever@gmail.com pkt->reinitNacked(); 1794937Sstever@gmail.com sendDma(pkt, true); 1804937Sstever@gmail.com } else if (pkt->senderState) { 1814937Sstever@gmail.com DmaReqState *state; 1824937Sstever@gmail.com DPRINTF(DMA, "Received response Pkt %#x with State: %#x Addr: %#x\n", 1834937Sstever@gmail.com pkt, pkt->senderState, pkt->getAddr()); 1844937Sstever@gmail.com state = dynamic_cast<DmaReqState*>(pkt->senderState); 1854937Sstever@gmail.com pendingCount--; 1865773Snate@binkert.org 1874937Sstever@gmail.com assert(pendingCount >= 0); 1884937Sstever@gmail.com assert(state); 1894937Sstever@gmail.com 1902929Sktlim@umich.edu state->numBytes += pkt->req->getSize(); 1912929Sktlim@umich.edu if (state->totBytes == state->numBytes) { 1922929Sktlim@umich.edu state->completionEvent->process(); 1935773Snate@binkert.org delete state; 1942929Sktlim@umich.edu } 1952929Sktlim@umich.edu delete pkt->req; 1962929Sktlim@umich.edu delete pkt; 1972929Sktlim@umich.edu 1982929Sktlim@umich.edu if (pendingCount == 0 && drainEvent) { 1992929Sktlim@umich.edu drainEvent->process(); 2004937Sstever@gmail.com drainEvent = NULL; 2014937Sstever@gmail.com } 2024937Sstever@gmail.com } else { 2034937Sstever@gmail.com panic("Got packet without sender state... huh?\n"); 2044937Sstever@gmail.com } 2054937Sstever@gmail.com 2064937Sstever@gmail.com return true; 2074937Sstever@gmail.com} 2084937Sstever@gmail.com 2094937Sstever@gmail.comDmaDevice::DmaDevice(Params *p) 2104937Sstever@gmail.com : PioDevice(p), dmaPort(NULL) 2114937Sstever@gmail.com{ } 2124937Sstever@gmail.com 2134937Sstever@gmail.com 2144937Sstever@gmail.comunsigned int 2152929Sktlim@umich.eduDmaDevice::drain(Event *de) 2162929Sktlim@umich.edu{ 2172929Sktlim@umich.edu unsigned int count; 2182929Sktlim@umich.edu count = pioPort->drain(de) + dmaPort->drain(de); 2192929Sktlim@umich.edu if (count) 2202929Sktlim@umich.edu changeState(Draining); 2212929Sktlim@umich.edu else 2226011Ssteve.reinhardt@amd.com changeState(Drained); 2232929Sktlim@umich.edu return count; 2242929Sktlim@umich.edu} 2252929Sktlim@umich.edu 2262929Sktlim@umich.eduunsigned int 2272929Sktlim@umich.eduDmaPort::drain(Event *de) 2282929Sktlim@umich.edu{ 2292929Sktlim@umich.edu if (pendingCount == 0) 2302929Sktlim@umich.edu return 0; 2312997Sstever@eecs.umich.edu drainEvent = de; 2322997Sstever@eecs.umich.edu return 1; 2332929Sktlim@umich.edu} 2342997Sstever@eecs.umich.edu 2352997Sstever@eecs.umich.edu 2362929Sktlim@umich.eduvoid 2372997Sstever@eecs.umich.eduDmaPort::recvRetry() 2382997Sstever@eecs.umich.edu{ 2392997Sstever@eecs.umich.edu Packet* pkt = transmitList.front(); 2402929Sktlim@umich.edu bool result = true; 2412997Sstever@eecs.umich.edu while (result && transmitList.size()) { 2422997Sstever@eecs.umich.edu DPRINTF(DMA, "Retry on Packet %#x with senderState: %#x\n", 2432997Sstever@eecs.umich.edu pkt, pkt->senderState); 2442997Sstever@eecs.umich.edu result = sendTiming(pkt); 2455773Snate@binkert.org if (result) { 2465773Snate@binkert.org DPRINTF(DMA, "-- Done\n"); 2472997Sstever@eecs.umich.edu transmitList.pop_front(); 2482997Sstever@eecs.umich.edu } else { 2496007Ssteve.reinhardt@amd.com DPRINTF(DMA, "-- Failed, queued\n"); 2506007Ssteve.reinhardt@amd.com } 2512997Sstever@eecs.umich.edu } 2522929Sktlim@umich.edu} 2532997Sstever@eecs.umich.edu 2542997Sstever@eecs.umich.edu 2552997Sstever@eecs.umich.eduvoid 2562997Sstever@eecs.umich.eduDmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 2572997Sstever@eecs.umich.edu uint8_t *data) 2582997Sstever@eecs.umich.edu{ 2592997Sstever@eecs.umich.edu assert(event); 2602929Sktlim@umich.edu 2612997Sstever@eecs.umich.edu assert(device->getState() == SimObject::Running); 2622929Sktlim@umich.edu 2632929Sktlim@umich.edu DmaReqState *reqState = new DmaReqState(event, this, size); 2643005Sstever@eecs.umich.edu 2653005Sstever@eecs.umich.edu for (ChunkGenerator gen(addr, size, peerBlockSize()); 2663005Sstever@eecs.umich.edu !gen.done(); gen.next()) { 2673005Sstever@eecs.umich.edu Request *req = new Request(gen.addr(), gen.size(), 0); 2686025Snate@binkert.org Packet *pkt = new Packet(req, cmd, Packet::Broadcast); 2696025Snate@binkert.org 2706025Snate@binkert.org // Increment the data pointer on a write 2716025Snate@binkert.org if (data) 2726025Snate@binkert.org pkt->dataStatic(data + gen.complete()); 2736025Snate@binkert.org 2744130Ssaidi@eecs.umich.edu pkt->senderState = reqState; 2754130Ssaidi@eecs.umich.edu 2764130Ssaidi@eecs.umich.edu assert(pendingCount >= 0); 2777735SAli.Saidi@ARM.com pendingCount++; 2787735SAli.Saidi@ARM.com sendDma(pkt); 2797735SAli.Saidi@ARM.com } 2803691Shsul@eecs.umich.edu 2813005Sstever@eecs.umich.edu} 2825721Shsul@eecs.umich.edu 2836194Sksewell@umich.edu 2846928SBrad.Beckmann@amd.comvoid 2853005Sstever@eecs.umich.eduDmaPort::sendDma(Packet *pkt, bool front) 2866168Snate@binkert.org{ 2876928SBrad.Beckmann@amd.com // some kind of selction between access methods 2886928SBrad.Beckmann@amd.com // more work is going to have to be done to make 2896928SBrad.Beckmann@amd.com // switching actually work 2906928SBrad.Beckmann@amd.com 2916928SBrad.Beckmann@amd.com System::MemoryMode state = sys->getMemoryMode(); 2926928SBrad.Beckmann@amd.com if (state == System::Timing) { 2936928SBrad.Beckmann@amd.com DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", 2946928SBrad.Beckmann@amd.com pkt, pkt->getAddr()); 2956928SBrad.Beckmann@amd.com if (transmitList.size() || !sendTiming(pkt)) { 2966928SBrad.Beckmann@amd.com if (front) 2976928SBrad.Beckmann@amd.com transmitList.push_front(pkt); 2986928SBrad.Beckmann@amd.com else 2996928SBrad.Beckmann@amd.com transmitList.push_back(pkt); 3006928SBrad.Beckmann@amd.com DPRINTF(DMA, "-- Failed: queued\n"); 3016166Ssteve.reinhardt@amd.com } else { 3022929Sktlim@umich.edu DPRINTF(DMA, "-- Done\n"); 3032929Sktlim@umich.edu } 3043005Sstever@eecs.umich.edu } else if (state == System::Atomic) { 3052997Sstever@eecs.umich.edu Tick lat; 3062997Sstever@eecs.umich.edu lat = sendAtomic(pkt); 3076293Ssteve.reinhardt@amd.com assert(pkt->senderState); 3086293Ssteve.reinhardt@amd.com DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); 3092929Sktlim@umich.edu assert(state); 310 311 state->numBytes += pkt->req->getSize(); 312 if (state->totBytes == state->numBytes) { 313 state->completionEvent->schedule(curTick + lat); 314 delete state; 315 delete pkt->req; 316 } 317 pendingCount--; 318 assert(pendingCount >= 0); 319 delete pkt; 320 321 if (pendingCount == 0 && drainEvent) { 322 drainEvent->process(); 323 drainEvent = NULL; 324 } 325 326 } else 327 panic("Unknown memory command state."); 328} 329 330DmaDevice::~DmaDevice() 331{ 332 if (dmaPort) 333 delete dmaPort; 334} 335 336 337