bridge.cc revision 8232:b28d06a175be
1 2/* 3 * Copyright (c) 2006 The Regents of The University of Michigan 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer; 10 * redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution; 13 * neither the name of the copyright holders nor the names of its 14 * contributors may be used to endorse or promote products derived from 15 * this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * Authors: Ali Saidi 30 * Steve Reinhardt 31 */ 32 33/** 34 * @file 35 * Definition of a simple bus bridge without buffering. 36 */ 37 38#include <algorithm> 39 40#include "base/range_ops.hh" 41#include "base/trace.hh" 42#include "debug/BusBridge.hh" 43#include "mem/bridge.hh" 44#include "params/Bridge.hh" 45 46Bridge::BridgePort::BridgePort(const std::string &_name, 47 Bridge *_bridge, BridgePort *_otherPort, 48 int _delay, int _nack_delay, int _req_limit, 49 int _resp_limit, 50 std::vector<Range<Addr> > filter_ranges) 51 : Port(_name, _bridge), bridge(_bridge), otherPort(_otherPort), 52 delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges), 53 outstandingResponses(0), queuedRequests(0), inRetry(false), 54 reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) 55{ 56} 57 58Bridge::Bridge(Params *p) 59 : MemObject(p), 60 portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay, 61 p->req_size_a, p->resp_size_a, p->filter_ranges_a), 62 portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay, 63 p->req_size_b, p->resp_size_b, p->filter_ranges_b), 64 ackWrites(p->write_ack), _params(p) 65{ 66 if (ackWrites) 67 panic("No support for acknowledging writes\n"); 68} 69 70Port * 71Bridge::getPort(const std::string &if_name, int idx) 72{ 73 BridgePort *port; 74 75 if (if_name == "side_a") 76 port = &portA; 77 else if (if_name == "side_b") 78 port = &portB; 79 else 80 return NULL; 81 82 if (port->getPeer() != NULL && !port->getPeer()->isDefaultPort()) 83 panic("bridge side %s already connected to %s.", 84 if_name, port->getPeer()->name()); 85 return port; 86} 87 88 89void 90Bridge::init() 91{ 92 // Make sure that both sides are connected to. 93 if (!portA.isConnected() || !portB.isConnected()) 94 fatal("Both ports of bus bridge are not connected to a bus.\n"); 95 96 if (portA.peerBlockSize() != portB.peerBlockSize()) 97 fatal("port A size %d, port B size %d \n " \ 98 "Busses don't have the same block size... Not supported.\n", 99 portA.peerBlockSize(), portB.peerBlockSize()); 100} 101 102bool 103Bridge::BridgePort::respQueueFull() 104{ 105 assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit); 106 return outstandingResponses >= respQueueLimit; 107} 108 109bool 110Bridge::BridgePort::reqQueueFull() 111{ 112 assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit); 113 return queuedRequests >= reqQueueLimit; 114} 115 116/** Function called by the port when the bus is receiving a Timing 117 * transaction.*/ 118bool 119Bridge::BridgePort::recvTiming(PacketPtr pkt) 120{ 121 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", 122 pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 123 124 DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n", 125 sendQueue.size(), queuedRequests, outstandingResponses); 126 DPRINTF(BusBridge, "Remote queue size: %d outreq: %d outresp: %d\n", 127 otherPort->sendQueue.size(), otherPort->queuedRequests, 128 otherPort->outstandingResponses); 129 130 if (pkt->isRequest() && otherPort->reqQueueFull()) { 131 DPRINTF(BusBridge, "Remote queue full, nacking\n"); 132 nackRequest(pkt); 133 return true; 134 } 135 136 if (pkt->needsResponse()) { 137 if (respQueueFull()) { 138 DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); 139 DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", 140 sendQueue.size(), queuedRequests, outstandingResponses); 141 nackRequest(pkt); 142 return true; 143 } else { 144 DPRINTF(BusBridge, "Request Needs response, reserving space\n"); 145 ++outstandingResponses; 146 } 147 } 148 149 otherPort->queueForSendTiming(pkt); 150 151 return true; 152} 153 154void 155Bridge::BridgePort::nackRequest(PacketPtr pkt) 156{ 157 // Nack the packet 158 pkt->makeTimingResponse(); 159 pkt->setNacked(); 160 161 //put it on the list to send 162 Tick readyTime = curTick() + nackDelay; 163 PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true); 164 165 // nothing on the list, add it and we're done 166 if (sendQueue.empty()) { 167 assert(!sendEvent.scheduled()); 168 schedule(sendEvent, readyTime); 169 sendQueue.push_back(buf); 170 return; 171 } 172 173 assert(sendEvent.scheduled() || inRetry); 174 175 // does it go at the end? 176 if (readyTime >= sendQueue.back()->ready) { 177 sendQueue.push_back(buf); 178 return; 179 } 180 181 // ok, somewhere in the middle, fun 182 std::list<PacketBuffer*>::iterator i = sendQueue.begin(); 183 std::list<PacketBuffer*>::iterator end = sendQueue.end(); 184 std::list<PacketBuffer*>::iterator begin = sendQueue.begin(); 185 bool done = false; 186 187 while (i != end && !done) { 188 if (readyTime < (*i)->ready) { 189 if (i == begin) 190 reschedule(sendEvent, readyTime); 191 sendQueue.insert(i,buf); 192 done = true; 193 } 194 i++; 195 } 196 assert(done); 197} 198 199 200void 201Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 202{ 203 if (pkt->isResponse()) { 204 // This is a response for a request we forwarded earlier. The 205 // corresponding PacketBuffer should be stored in the packet's 206 // senderState field. 207 208 PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 209 assert(buf != NULL); 210 // set up new packet dest & senderState based on values saved 211 // from original request 212 buf->fixResponse(pkt); 213 214 DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest()); 215 delete buf; 216 } 217 218 219 if (pkt->isRequest()) { 220 ++queuedRequests; 221 } 222 223 224 225 Tick readyTime = curTick() + delay; 226 PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 227 228 // If we're about to put this packet at the head of the queue, we 229 // need to schedule an event to do the transmit. Otherwise there 230 // should already be an event scheduled for sending the head 231 // packet. 232 if (sendQueue.empty()) { 233 schedule(sendEvent, readyTime); 234 } 235 sendQueue.push_back(buf); 236} 237 238void 239Bridge::BridgePort::trySend() 240{ 241 assert(!sendQueue.empty()); 242 243 PacketBuffer *buf = sendQueue.front(); 244 245 assert(buf->ready <= curTick()); 246 247 PacketPtr pkt = buf->pkt; 248 249 DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 250 buf->origSrc, pkt->getDest(), pkt->getAddr()); 251 252 bool wasReq = pkt->isRequest(); 253 bool was_nacked_here = buf->nackedHere; 254 255 // If the send was successful, make sure sender state was set to NULL 256 // otherwise we could get a NACK back of a packet that didn't expect a 257 // response and we would try to use freed memory. 258 259 Packet::SenderState *old_sender_state = pkt->senderState; 260 if (pkt->isRequest() && !buf->expectResponse) 261 pkt->senderState = NULL; 262 263 if (sendTiming(pkt)) { 264 // send successful 265 sendQueue.pop_front(); 266 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 267 268 if (buf->expectResponse) { 269 // Must wait for response 270 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 271 outstandingResponses); 272 } else { 273 // no response expected... deallocate packet buffer now. 274 DPRINTF(BusBridge, " successful: no response expected\n"); 275 delete buf; 276 } 277 278 if (wasReq) 279 --queuedRequests; 280 else if (!was_nacked_here) 281 --outstandingResponses; 282 283 // If there are more packets to send, schedule event to try again. 284 if (!sendQueue.empty()) { 285 buf = sendQueue.front(); 286 DPRINTF(BusBridge, "Scheduling next send\n"); 287 schedule(sendEvent, std::max(buf->ready, curTick() + 1)); 288 } 289 } else { 290 DPRINTF(BusBridge, " unsuccessful\n"); 291 pkt->senderState = old_sender_state; 292 inRetry = true; 293 } 294 295 DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", 296 sendQueue.size(), queuedRequests, outstandingResponses); 297} 298 299 300void 301Bridge::BridgePort::recvRetry() 302{ 303 inRetry = false; 304 Tick nextReady = sendQueue.front()->ready; 305 if (nextReady <= curTick()) 306 trySend(); 307 else 308 schedule(sendEvent, nextReady); 309} 310 311/** Function called by the port when the bus is receiving a Atomic 312 * transaction.*/ 313Tick 314Bridge::BridgePort::recvAtomic(PacketPtr pkt) 315{ 316 return delay + otherPort->sendAtomic(pkt); 317} 318 319/** Function called by the port when the bus is receiving a Functional 320 * transaction.*/ 321void 322Bridge::BridgePort::recvFunctional(PacketPtr pkt) 323{ 324 std::list<PacketBuffer*>::iterator i; 325 326 pkt->pushLabel(name()); 327 328 for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { 329 if (pkt->checkFunctional((*i)->pkt)) { 330 pkt->makeResponse(); 331 return; 332 } 333 } 334 335 pkt->popLabel(); 336 337 // fall through if pkt still not satisfied 338 otherPort->sendFunctional(pkt); 339} 340 341/** Function called by the port when the bus is receiving a status change.*/ 342void 343Bridge::BridgePort::recvStatusChange(Port::Status status) 344{ 345 otherPort->sendStatusChange(status); 346} 347 348void 349Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, 350 bool &snoop) 351{ 352 otherPort->getPeerAddressRanges(resp, snoop); 353 FilterRangeList(filterRanges, resp); 354 // we don't allow snooping across bridges 355 snoop = false; 356} 357 358Bridge * 359BridgeParams::create() 360{ 361 return new Bridge(this); 362} 363