io_device.cc revision 2914
1/* 2 * Copyright (c) 2006 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Ali Saidi 29 * Nathan Binkert 30 */ 31 32#include "base/trace.hh" 33#include "dev/io_device.hh" 34#include "sim/builder.hh" 35#include "sim/system.hh" 36 37 38PioPort::PioPort(PioDevice *dev, System *s, std::string pname) 39 : SimpleTimingPort(dev->name() + pname), device(dev), sys(s) 40{ } 41 42 43Tick 44PioPort::recvAtomic(Packet *pkt) 45{ 46 return device->recvAtomic(pkt); 47} 48 49void 50PioPort::recvFunctional(Packet *pkt) 51{ 52 device->recvAtomic(pkt); 53} 54 55void 56PioPort::getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) 57{ 58 snoop.clear(); 59 device->addressRanges(resp); 60} 61 62 63bool 64PioPort::recvTiming(Packet *pkt) 65{ 66 if (pkt->result == Packet::Nacked) { 67 resendNacked(pkt); 68 } else { 69 Tick latency = device->recvAtomic(pkt); 70 // turn packet around to go back to requester 71 pkt->makeTimingResponse(); 72 sendTiming(pkt, latency); 73 } 74 return true; 75} 76 77PioDevice::~PioDevice() 78{ 79 if (pioPort) 80 delete pioPort; 81} 82 83void 84PioDevice::init() 85{ 86 if (!pioPort) 87 panic("Pio port not connected to anything!"); 88 pioPort->sendStatusChange(Port::RangeChange); 89} 90 91 92unsigned int 93PioDevice::drain(Event *de) 94{ 95 unsigned int count; 96 count = pioPort->drain(de); 97 if (count) 98 changeState(Draining); 99 else 100 changeState(Drained); 101 return count; 102} 103 104void 105BasicPioDevice::addressRanges(AddrRangeList &range_list) 106{ 107 assert(pioSize != 0); 108 range_list.clear(); 109 range_list.push_back(RangeSize(pioAddr, pioSize)); 110} 111 112 113DmaPort::DmaPort(DmaDevice *dev, System *s) 114 : Port(dev->name() + "-dmaport"), device(dev), sys(s), pendingCount(0), 115 actionInProgress(0), drainEvent(NULL) 116{ } 117 118bool 119DmaPort::recvTiming(Packet *pkt) 120{ 121 122 123 if (pkt->result == Packet::Nacked) { 124 DPRINTF(DMA, "Received nacked Pkt %#x with State: %#x Addr: %#x\n", 125 pkt, pkt->senderState, pkt->getAddr()); 126 pkt->reinitNacked(); 127 sendDma(pkt, true); 128 } else if (pkt->senderState) { 129 DmaReqState *state; 130 DPRINTF(DMA, "Received response Pkt %#x with State: %#x Addr: %#x\n", 131 pkt, pkt->senderState, pkt->getAddr()); 132 state = dynamic_cast<DmaReqState*>(pkt->senderState); 133 pendingCount--; 134 135 assert(pendingCount >= 0); 136 assert(state); 137 138 state->numBytes += pkt->req->getSize(); 139 if (state->totBytes == state->numBytes) { 140 state->completionEvent->process(); 141 delete state; 142 } 143 delete pkt->req; 144 delete pkt; 145 146 if (pendingCount == 0 && drainEvent) { 147 drainEvent->process(); 148 drainEvent = NULL; 149 } 150 } else { 151 panic("Got packet without sender state... huh?\n"); 152 } 153 154 return true; 155} 156 157DmaDevice::DmaDevice(Params *p) 158 : PioDevice(p), dmaPort(NULL) 159{ } 160 161 162unsigned int 163DmaDevice::drain(Event *de) 164{ 165 unsigned int count; 166 count = pioPort->drain(de) + dmaPort->drain(de); 167 if (count) 168 changeState(Draining); 169 else 170 changeState(Drained); 171 return count; 172} 173 174unsigned int 175DmaPort::drain(Event *de) 176{ 177 if (pendingCount == 0) 178 return 0; 179 drainEvent = de; 180 return 1; 181} 182 183 184void 185DmaPort::recvRetry() 186{ 187 Packet* pkt = transmitList.front(); 188 bool result = true; 189 while (result && transmitList.size()) { 190 DPRINTF(DMA, "Retry on Packet %#x with senderState: %#x\n", 191 pkt, pkt->senderState); 192 result = sendTiming(pkt); 193 if (result) { 194 DPRINTF(DMA, "-- Done\n"); 195 transmitList.pop_front(); 196 } else { 197 DPRINTF(DMA, "-- Failed, queued\n"); 198 } 199 } 200} 201 202 203void 204DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, 205 uint8_t *data) 206{ 207 assert(event); 208 209 assert(device->getState() == SimObject::Running); 210 211 DmaReqState *reqState = new DmaReqState(event, this, size); 212 213 for (ChunkGenerator gen(addr, size, peerBlockSize()); 214 !gen.done(); gen.next()) { 215 Request *req = new Request(gen.addr(), gen.size(), 0); 216 Packet *pkt = new Packet(req, cmd, Packet::Broadcast); 217 218 // Increment the data pointer on a write 219 if (data) 220 pkt->dataStatic(data + gen.complete()); 221 222 pkt->senderState = reqState; 223 224 assert(pendingCount >= 0); 225 pendingCount++; 226 sendDma(pkt); 227 } 228 229} 230 231 232void 233DmaPort::sendDma(Packet *pkt, bool front) 234{ 235 // some kind of selction between access methods 236 // more work is going to have to be done to make 237 // switching actually work 238 239 System::MemoryMode state = sys->getMemoryMode(); 240 if (state == System::Timing) { 241 DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n", 242 pkt, pkt->getAddr()); 243 if (transmitList.size() || !sendTiming(pkt)) { 244 if (front) 245 transmitList.push_front(pkt); 246 else 247 transmitList.push_back(pkt); 248 DPRINTF(DMA, "-- Failed: queued\n"); 249 } else { 250 DPRINTF(DMA, "-- Done\n"); 251 } 252 } else if (state == System::Atomic) { 253 Tick lat; 254 lat = sendAtomic(pkt); 255 assert(pkt->senderState); 256 DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState); 257 assert(state); 258 259 state->numBytes += pkt->req->getSize(); 260 if (state->totBytes == state->numBytes) { 261 state->completionEvent->schedule(curTick + lat); 262 delete state; 263 delete pkt->req; 264 } 265 pendingCount--; 266 assert(pendingCount >= 0); 267 delete pkt; 268 269 if (pendingCount == 0 && drainEvent) { 270 drainEvent->process(); 271 drainEvent = NULL; 272 } 273 274 } else 275 panic("Unknown memory command state."); 276} 277 278DmaDevice::~DmaDevice() 279{ 280 if (dmaPort) 281 delete dmaPort; 282} 283 284 285