io_device.cc revision 4451
17087Snate@binkert.org/* 210959Sdavid.hashe@amd.com * Copyright (c) 2006 The Regents of The University of Michigan 37087Snate@binkert.org * All rights reserved. 47087Snate@binkert.org * 57087Snate@binkert.org * Redistribution and use in source and binary forms, with or without 67087Snate@binkert.org * modification, are permitted provided that the following conditions are 77087Snate@binkert.org * met: redistributions of source code must retain the above copyright 87087Snate@binkert.org * notice, this list of conditions and the following disclaimer; 97087Snate@binkert.org * redistributions in binary form must reproduce the above copyright 107087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 117087Snate@binkert.org * documentation and/or other materials provided with the distribution; 127087Snate@binkert.org * neither the name of the copyright holders nor the names of its 137087Snate@binkert.org * contributors may be used to endorse or promote products derived from 145331Sgblack@eecs.umich.edu * this software without specific prior written permission. 155331Sgblack@eecs.umich.edu * 165331Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175331Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185331Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195331Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205331Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215331Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225331Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235331Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245331Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255331Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265331Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275331Sgblack@eecs.umich.edu * 285331Sgblack@eecs.umich.edu * Authors: Ali Saidi 295331Sgblack@eecs.umich.edu * Nathan Binkert 305331Sgblack@eecs.umich.edu */ 315331Sgblack@eecs.umich.edu 325331Sgblack@eecs.umich.edu#include "base/chunk_generator.hh" 335331Sgblack@eecs.umich.edu#include "base/trace.hh" 345331Sgblack@eecs.umich.edu#include "dev/io_device.hh" 355331Sgblack@eecs.umich.edu#include "sim/builder.hh" 365331Sgblack@eecs.umich.edu#include "sim/system.hh" 375331Sgblack@eecs.umich.edu 385331Sgblack@eecs.umich.edu 395331Sgblack@eecs.umich.eduPioPort::PioPort(PioDevice *dev, System *s, std::string pname) 405331Sgblack@eecs.umich.edu : SimpleTimingPort(dev->name() + pname, dev), device(dev) 415331Sgblack@eecs.umich.edu{ } 424276Sgblack@eecs.umich.edu 434276Sgblack@eecs.umich.edu 444276Sgblack@eecs.umich.eduTick 454276Sgblack@eecs.umich.eduPioPort::recvAtomic(PacketPtr pkt) 4610593Sgabeblack@google.com{ 4710593Sgabeblack@google.com return pkt->isRead() ? device->read(pkt) : device->write(pkt); 4810593Sgabeblack@google.com} 4910593Sgabeblack@google.com 5010593Sgabeblack@google.comvoid 5110593Sgabeblack@google.comPioPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) 5210593Sgabeblack@google.com{ 5310593Sgabeblack@google.com snoop.clear(); 5410593Sgabeblack@google.com device->addressRanges(resp); 5510593Sgabeblack@google.com} 5610593Sgabeblack@google.com 5710593Sgabeblack@google.com 5810593Sgabeblack@google.comPioDevice::~PioDevice() 5910593Sgabeblack@google.com{ 6010593Sgabeblack@google.com if (pioPort) 6110593Sgabeblack@google.com delete pioPort; 6210593Sgabeblack@google.com} 6310593Sgabeblack@google.com 6410593Sgabeblack@google.comvoid 6510593Sgabeblack@google.comPioDevice::init() 6610593Sgabeblack@google.com{ 6710593Sgabeblack@google.com if (!pioPort) 6810593Sgabeblack@google.com panic("Pio port not connected to anything!"); 6910593Sgabeblack@google.com pioPort->sendStatusChange(Port::RangeChange); 7010593Sgabeblack@google.com} 715238Sgblack@eecs.umich.edu 7210593Sgabeblack@google.com 7310593Sgabeblack@google.comunsigned int 7410593Sgabeblack@google.comPioDevice::drain(Event *de) 7510593Sgabeblack@google.com{ 7610593Sgabeblack@google.com unsigned int count; 7710593Sgabeblack@google.com count = pioPort->drain(de); 7810593Sgabeblack@google.com if (count) 7910593Sgabeblack@google.com changeState(Draining); 8010593Sgabeblack@google.com else 8110593Sgabeblack@google.com changeState(Drained); 8210593Sgabeblack@google.com return count; 8310593Sgabeblack@google.com} 8410593Sgabeblack@google.com 8510593Sgabeblack@google.comvoid 8610593Sgabeblack@google.comBasicPioDevice::addressRanges(AddrRangeList &range_list) 8710593Sgabeblack@google.com{ 8810593Sgabeblack@google.com assert(pioSize != 0); 896611Sgblack@eecs.umich.edu range_list.clear(); 9010593Sgabeblack@google.com range_list.push_back(RangeSize(pioAddr, pioSize)); 9110593Sgabeblack@google.com} 9210593Sgabeblack@google.com 9310593Sgabeblack@google.com 9410593Sgabeblack@google.comDmaPort::DmaPort(DmaDevice *dev, System *s) 9510593Sgabeblack@google.com : Port(dev->name() + "-dmaport", dev), device(dev), sys(s), 966611Sgblack@eecs.umich.edu pendingCount(0), actionInProgress(0), drainEvent(NULL), 9710593Sgabeblack@google.com backoffTime(0), inRetry(false), backoffEvent(this) 9810593Sgabeblack@google.com{ } 9910593Sgabeblack@google.com 10010593Sgabeblack@google.combool 10110593Sgabeblack@google.comDmaPort::recvTiming(PacketPtr pkt) 10210593Sgabeblack@google.com{ 10310593Sgabeblack@google.com 1046611Sgblack@eecs.umich.edu 1056611Sgblack@eecs.umich.edu if (pkt->result == Packet::Nacked) { 10610593Sgabeblack@google.com DPRINTF(DMA, "Received nacked Pkt %#x with State: %#x Addr: %#x\n", 10710593Sgabeblack@google.com pkt, pkt->senderState, pkt->getAddr()); 10810593Sgabeblack@google.com 10910593Sgabeblack@google.com if (backoffTime < device->minBackoffDelay) 11010593Sgabeblack@google.com backoffTime = device->minBackoffDelay; 11110593Sgabeblack@google.com else if (backoffTime < device->maxBackoffDelay) 11210593Sgabeblack@google.com backoffTime <<= 1; 11310593Sgabeblack@google.com 11410593Sgabeblack@google.com backoffEvent.reschedule(curTick + backoffTime, true); 11510593Sgabeblack@google.com 11610593Sgabeblack@google.com DPRINTF(DMA, "Backoff time set to %d ticks\n", backoffTime); 11710593Sgabeblack@google.com 11810593Sgabeblack@google.com pkt->reinitNacked(); 11910593Sgabeblack@google.com queueDma(pkt, true); 12010593Sgabeblack@google.com } else if (pkt->senderState) { 12110593Sgabeblack@google.com DmaReqState *state; 12210593Sgabeblack@google.com backoffTime >>= 2; 12310593Sgabeblack@google.com 12410593Sgabeblack@google.com DPRINTF(DMA, "Received response Pkt %#x with State: %#x Addr: %#x size: %#x\n", 1255292Sgblack@eecs.umich.edu pkt, pkt->senderState, pkt->getAddr(), pkt->req->getSize()); 1266611Sgblack@eecs.umich.edu state = dynamic_cast<DmaReqState*>(pkt->senderState); 1275238Sgblack@eecs.umich.edu pendingCount--; 12810593Sgabeblack@google.com 12910593Sgabeblack@google.com assert(pendingCount >= 0); 13010593Sgabeblack@google.com assert(state); 13110593Sgabeblack@google.com 13210593Sgabeblack@google.com state->numBytes += pkt->req->getSize(); 13310593Sgabeblack@google.com assert(state->totBytes >= state->numBytes); 13410593Sgabeblack@google.com if (state->totBytes == state->numBytes) { 13510593Sgabeblack@google.com state->completionEvent->process(); 13610593Sgabeblack@google.com delete state; 1375789Sgblack@eecs.umich.edu } 1385789Sgblack@eecs.umich.edu delete pkt->req; 13910593Sgabeblack@google.com delete pkt; 1405908Sgblack@eecs.umich.edu 1414276Sgblack@eecs.umich.edu if (pendingCount == 0 && drainEvent) { 14210593Sgabeblack@google.com drainEvent->process(); 14310593Sgabeblack@google.com drainEvent = NULL; 14410593Sgabeblack@google.com } 14510593Sgabeblack@google.com } else { 14610593Sgabeblack@google.com panic("Got packet without sender state... huh?\n"); 14710593Sgabeblack@google.com } 14810593Sgabeblack@google.com 14910593Sgabeblack@google.com return true; 15010593Sgabeblack@google.com} 15110593Sgabeblack@google.com 15210593Sgabeblack@google.comDmaDevice::DmaDevice(Params *p) 15310593Sgabeblack@google.com : PioDevice(p), dmaPort(NULL), minBackoffDelay(p->min_backoff_delay), 15410593Sgabeblack@google.com maxBackoffDelay(p->max_backoff_delay) 15510593Sgabeblack@google.com{ } 15610593Sgabeblack@google.com 15710593Sgabeblack@google.com 15810593Sgabeblack@google.comunsigned int 15910593Sgabeblack@google.comDmaDevice::drain(Event *de) 16010593Sgabeblack@google.com{ 16110593Sgabeblack@google.com unsigned int count; 16210593Sgabeblack@google.com count = pioPort->drain(de) + dmaPort->drain(de); 16310593Sgabeblack@google.com if (count) 16410593Sgabeblack@google.com changeState(Draining); 16510593Sgabeblack@google.com else 16610593Sgabeblack@google.com changeState(Drained); 16710593Sgabeblack@google.com return count; 16810593Sgabeblack@google.com} 16910593Sgabeblack@google.com 17010593Sgabeblack@google.comunsigned int 17110593Sgabeblack@google.comDmaPort::drain(Event *de) 17210593Sgabeblack@google.com{ 17310593Sgabeblack@google.com if (pendingCount == 0) 17410593Sgabeblack@google.com return 0; 17510593Sgabeblack@google.com drainEvent = de; 17611289Sgabor.dozsa@arm.com return 1; 17710593Sgabeblack@google.com} 17810593Sgabeblack@google.com 17910593Sgabeblack@google.com 18010593Sgabeblack@google.comvoid 18110593Sgabeblack@google.comDmaPort::recvRetry() 18210593Sgabeblack@google.com{ 18310593Sgabeblack@google.com assert(transmitList.size()); 18410593Sgabeblack@google.com PacketPtr pkt = transmitList.front(); 18510593Sgabeblack@google.com bool result = true; 18610593Sgabeblack@google.com do { 18710593Sgabeblack@google.com DPRINTF(DMA, "Retry on Packet %#x with senderState: %#x\n", 18810593Sgabeblack@google.com pkt, pkt->senderState); 18910593Sgabeblack@google.com result = sendTiming(pkt); 19010593Sgabeblack@google.com if (result) { 19110593Sgabeblack@google.com DPRINTF(DMA, "-- Done\n"); 19210593Sgabeblack@google.com transmitList.pop_front(); 19310593Sgabeblack@google.com inRetry = false; 19410593Sgabeblack@google.com } else { 19510593Sgabeblack@google.com inRetry = true; 19610593Sgabeblack@google.com DPRINTF(DMA, "-- Failed, queued\n"); 19710593Sgabeblack@google.com } 19810593Sgabeblack@google.com } while (!backoffTime && result && transmitList.size()); 19910593Sgabeblack@google.com 20010593Sgabeblack@google.com if (transmitList.size() && backoffTime && !inRetry) { 20110593Sgabeblack@google.com DPRINTF(DMA, "Scheduling backoff for %d\n", curTick+backoffTime); 20210593Sgabeblack@google.com if (!backoffEvent.scheduled()) 20310593Sgabeblack@google.com backoffEvent.schedule(backoffTime+curTick); 20410593Sgabeblack@google.com } 20510593Sgabeblack@google.com DPRINTF(DMA, "TransmitList: %d, backoffTime: %d inRetry: %d es: %d\n", 20610593Sgabeblack@google.com transmitList.size(), backoffTime, inRetry, 20710593Sgabeblack@google.com backoffEvent.scheduled()); 20810593Sgabeblack@google.com} 20910593Sgabeblack@google.com 21010593Sgabeblack@google.com 21110593Sgabeblack@google.comvoid 21210593Sgabeblack@google.comDmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 21310593Sgabeblack@google.com uint8_t *data) 21410593Sgabeblack@google.com{ 21510593Sgabeblack@google.com assert(event); 21610593Sgabeblack@google.com 21710593Sgabeblack@google.com assert(device->getState() == SimObject::Running); 21810593Sgabeblack@google.com 21910593Sgabeblack@google.com DmaReqState *reqState = new DmaReqState(event, this, size); 22010593Sgabeblack@google.com 22110593Sgabeblack@google.com 22210593Sgabeblack@google.com DPRINTF(DMA, "Starting DMA for addr: %#x size: %d sched: %d\n", addr, size, 22310593Sgabeblack@google.com event->scheduled()); 22410593Sgabeblack@google.com for (ChunkGenerator gen(addr, size, peerBlockSize()); 22510593Sgabeblack@google.com !gen.done(); gen.next()) { 22610593Sgabeblack@google.com Request *req = new Request(gen.addr(), gen.size(), 0); 22710593Sgabeblack@google.com PacketPtr pkt = new Packet(req, cmd, Packet::Broadcast); 22810593Sgabeblack@google.com 22910593Sgabeblack@google.com // Increment the data pointer on a write 23010593Sgabeblack@google.com if (data) 23111703Smichael.lebeane@amd.com pkt->dataStatic(data + gen.complete()); 23211703Smichael.lebeane@amd.com 23311703Smichael.lebeane@amd.com pkt->senderState = reqState; 2346616Sgblack@eecs.umich.edu 2356616Sgblack@eecs.umich.edu assert(pendingCount >= 0); 2364276Sgblack@eecs.umich.edu pendingCount++; 23710593Sgabeblack@google.com DPRINTF(DMA, "--Queuing DMA for addr: %#x size: %d\n", gen.addr(), 23810593Sgabeblack@google.com gen.size()); 23910593Sgabeblack@google.com queueDma(pkt); 24010593Sgabeblack@google.com } 24110593Sgabeblack@google.com 24210593Sgabeblack@google.com} 24310593Sgabeblack@google.com 24410593Sgabeblack@google.comvoid 24510593Sgabeblack@google.comDmaPort::queueDma(PacketPtr pkt, bool front) 24610593Sgabeblack@google.com{ 24710593Sgabeblack@google.com 24810593Sgabeblack@google.com if (front) 24910593Sgabeblack@google.com transmitList.push_front(pkt); 25010593Sgabeblack@google.com else 25110593Sgabeblack@google.com transmitList.push_back(pkt); 25210593Sgabeblack@google.com sendDma(); 25310593Sgabeblack@google.com} 25410593Sgabeblack@google.com 25510593Sgabeblack@google.com 25610593Sgabeblack@google.comvoid 25710593Sgabeblack@google.comDmaPort::sendDma() 25810593Sgabeblack@google.com{ 25910593Sgabeblack@google.com // some kind of selction between access methods 26010593Sgabeblack@google.com // more work is going to have to be done to make 26110593Sgabeblack@google.com // switching actually work 26210593Sgabeblack@google.com assert(transmitList.size()); 26310593Sgabeblack@google.com PacketPtr pkt = transmitList.front(); 26410593Sgabeblack@google.com 26510593Sgabeblack@google.com System::MemoryMode state = sys->getMemoryMode(); 26610593Sgabeblack@google.com if (state == System::Timing) { 26710593Sgabeblack@google.com if (backoffEvent.scheduled() || inRetry) { 26810593Sgabeblack@google.com DPRINTF(DMA, "Can't send immediately, waiting for retry or backoff timer\n"); 26910593Sgabeblack@google.com return; 27010593Sgabeblack@google.com } 27110593Sgabeblack@google.com 27210593Sgabeblack@google.com DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", 27310593Sgabeblack@google.com pkt, pkt->getAddr()); 27410593Sgabeblack@google.com 27510593Sgabeblack@google.com bool result; 27610593Sgabeblack@google.com do { 27710593Sgabeblack@google.com result = sendTiming(pkt); 27810593Sgabeblack@google.com if (result) { 27910593Sgabeblack@google.com transmitList.pop_front(); 28010593Sgabeblack@google.com DPRINTF(DMA, "-- Done\n"); 28110593Sgabeblack@google.com } else { 28210593Sgabeblack@google.com inRetry = true; 28310593Sgabeblack@google.com DPRINTF(DMA, "-- Failed: queued\n"); 28410593Sgabeblack@google.com } 28510593Sgabeblack@google.com } while (result && !backoffTime && transmitList.size()); 28610593Sgabeblack@google.com 28710593Sgabeblack@google.com if (transmitList.size() && backoffTime && !inRetry && 28810593Sgabeblack@google.com !backoffEvent.scheduled()) { 28910593Sgabeblack@google.com DPRINTF(DMA, "-- Scheduling backoff timer for %d\n", 29010593Sgabeblack@google.com backoffTime+curTick); 29110593Sgabeblack@google.com backoffEvent.schedule(backoffTime+curTick); 29210593Sgabeblack@google.com } 29310593Sgabeblack@google.com } else if (state == System::Atomic) { 29410593Sgabeblack@google.com transmitList.pop_front(); 29510593Sgabeblack@google.com 29610593Sgabeblack@google.com Tick lat; 29710593Sgabeblack@google.com DPRINTF(DMA, "--Sending DMA for addr: %#x size: %d\n", 29810593Sgabeblack@google.com pkt->req->getPaddr(), pkt->req->getSize()); 29910593Sgabeblack@google.com lat = sendAtomic(pkt); 30010593Sgabeblack@google.com assert(pkt->senderState); 30110593Sgabeblack@google.com DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); 30210593Sgabeblack@google.com assert(state); 30310593Sgabeblack@google.com state->numBytes += pkt->req->getSize(); 30410593Sgabeblack@google.com 30510593Sgabeblack@google.com DPRINTF(DMA, "--Received response for DMA for addr: %#x size: %d nb: %d, tot: %d sched %d\n", 30610593Sgabeblack@google.com pkt->req->getPaddr(), pkt->req->getSize(), state->numBytes, 30710593Sgabeblack@google.com state->totBytes, state->completionEvent->scheduled()); 30810593Sgabeblack@google.com 30910593Sgabeblack@google.com if (state->totBytes == state->numBytes) { 31010593Sgabeblack@google.com assert(!state->completionEvent->scheduled()); 31110593Sgabeblack@google.com state->completionEvent->schedule(curTick + lat); 31210593Sgabeblack@google.com delete state; 31310593Sgabeblack@google.com delete pkt->req; 31410593Sgabeblack@google.com } 31510593Sgabeblack@google.com pendingCount--; 31610593Sgabeblack@google.com assert(pendingCount >= 0); 31710593Sgabeblack@google.com delete pkt; 31810593Sgabeblack@google.com 31910593Sgabeblack@google.com if (pendingCount == 0 && drainEvent) { 32010593Sgabeblack@google.com drainEvent->process(); 32110593Sgabeblack@google.com drainEvent = NULL; 32210593Sgabeblack@google.com } 32310593Sgabeblack@google.com 32410593Sgabeblack@google.com } else 32510593Sgabeblack@google.com panic("Unknown memory command state."); 32610593Sgabeblack@google.com} 32710593Sgabeblack@google.com 32810593Sgabeblack@google.comDmaDevice::~DmaDevice() 32910593Sgabeblack@google.com{ 33010593Sgabeblack@google.com if (dmaPort) 33110593Sgabeblack@google.com delete dmaPort; 33210593Sgabeblack@google.com} 33310593Sgabeblack@google.com 33410593Sgabeblack@google.com 33510593Sgabeblack@google.com