bridge.cc revision 5314
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 "mem/bridge.hh" 43#include "params/Bridge.hh" 44 45Bridge::BridgePort::BridgePort(const std::string &_name, 46 Bridge *_bridge, BridgePort *_otherPort, 47 int _delay, int _nack_delay, int _req_limit, 48 int _resp_limit, 49 std::vector<Range<Addr> > filter_ranges) 50 : Port(_name), bridge(_bridge), otherPort(_otherPort), 51 delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges), 52 outstandingResponses(0), queuedRequests(0), inRetry(false), 53 reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) 54{ 55} 56 57Bridge::Bridge(Params *p) 58 : MemObject(p), 59 portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay, 60 p->req_size_a, p->resp_size_a, p->filter_ranges_a), 61 portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay, 62 p->req_size_b, p->resp_size_b, p->filter_ranges_b), 63 ackWrites(p->write_ack), _params(p) 64{ 65 if (ackWrites) 66 panic("No support for acknowledging writes\n"); 67} 68 69Port * 70Bridge::getPort(const std::string &if_name, int idx) 71{ 72 BridgePort *port; 73 74 if (if_name == "side_a") 75 port = &portA; 76 else if (if_name == "side_b") 77 port = &portB; 78 else 79 return NULL; 80 81 if (port->getPeer() != NULL && !port->getPeer()->isDefaultPort()) 82 panic("bridge side %s already connected to %s.", 83 if_name, port->getPeer()->name()); 84 return port; 85} 86 87 88void 89Bridge::init() 90{ 91 // Make sure that both sides are connected to. 92 if (portA.getPeer() == NULL || portB.getPeer() == NULL) 93 fatal("Both ports of bus bridge are not connected to a bus.\n"); 94 95 if (portA.peerBlockSize() != portB.peerBlockSize()) 96 fatal("Busses don't have the same block size... Not supported.\n"); 97} 98 99bool 100Bridge::BridgePort::respQueueFull() 101{ 102 assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit); 103 return outstandingResponses >= respQueueLimit; 104} 105 106bool 107Bridge::BridgePort::reqQueueFull() 108{ 109 assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit); 110 return queuedRequests >= reqQueueLimit; 111} 112 113/** Function called by the port when the bus is receiving a Timing 114 * transaction.*/ 115bool 116Bridge::BridgePort::recvTiming(PacketPtr pkt) 117{ 118 DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", 119 pkt->getSrc(), pkt->getDest(), pkt->getAddr()); 120 121 DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n", 122 sendQueue.size(), queuedRequests, outstandingResponses); 123 DPRINTF(BusBridge, "Remote queue size: %d outreq: %d outresp: %d\n", 124 otherPort->sendQueue.size(), otherPort->queuedRequests, 125 otherPort->outstandingResponses); 126 127 if (pkt->isRequest() && otherPort->reqQueueFull()) { 128 DPRINTF(BusBridge, "Remote queue full, nacking\n"); 129 nackRequest(pkt); 130 return true; 131 } 132 133 if (pkt->needsResponse()) 134 if (respQueueFull()) { 135 DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n"); 136 DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n", 137 sendQueue.size(), queuedRequests, outstandingResponses); 138 nackRequest(pkt); 139 return true; 140 } else { 141 DPRINTF(BusBridge, "Request Needs response, reserving space\n"); 142 ++outstandingResponses; 143 } 144 145 otherPort->queueForSendTiming(pkt); 146 147 return true; 148} 149 150void 151Bridge::BridgePort::nackRequest(PacketPtr pkt) 152{ 153 // Nack the packet 154 pkt->makeTimingResponse(); 155 pkt->setNacked(); 156 157 //put it on the list to send 158 Tick readyTime = curTick + nackDelay; 159 PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true); 160 161 // nothing on the list, add it and we're done 162 if (sendQueue.empty()) { 163 assert(!sendEvent.scheduled()); 164 sendEvent.schedule(readyTime); 165 sendQueue.push_back(buf); 166 return; 167 } 168 169 assert(sendEvent.scheduled() || inRetry); 170 171 // does it go at the end? 172 if (readyTime >= sendQueue.back()->ready) { 173 sendQueue.push_back(buf); 174 return; 175 } 176 177 // ok, somewhere in the middle, fun 178 std::list<PacketBuffer*>::iterator i = sendQueue.begin(); 179 std::list<PacketBuffer*>::iterator end = sendQueue.end(); 180 std::list<PacketBuffer*>::iterator begin = sendQueue.begin(); 181 bool done = false; 182 183 while (i != end && !done) { 184 if (readyTime < (*i)->ready) { 185 if (i == begin) 186 sendEvent.reschedule(readyTime); 187 sendQueue.insert(i,buf); 188 done = true; 189 } 190 i++; 191 } 192 assert(done); 193} 194 195 196void 197Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) 198{ 199 if (pkt->isResponse()) { 200 // This is a response for a request we forwarded earlier. The 201 // corresponding PacketBuffer should be stored in the packet's 202 // senderState field. 203 204 PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState); 205 assert(buf != NULL); 206 // set up new packet dest & senderState based on values saved 207 // from original request 208 buf->fixResponse(pkt); 209 210 DPRINTF(BusBridge, "response, new dest %d\n", pkt->getDest()); 211 delete buf; 212 } 213 214 215 if (pkt->isRequest()) { 216 ++queuedRequests; 217 } 218 219 220 221 Tick readyTime = curTick + delay; 222 PacketBuffer *buf = new PacketBuffer(pkt, readyTime); 223 224 // If we're about to put this packet at the head of the queue, we 225 // need to schedule an event to do the transmit. Otherwise there 226 // should already be an event scheduled for sending the head 227 // packet. 228 if (sendQueue.empty()) { 229 sendEvent.schedule(readyTime); 230 } 231 sendQueue.push_back(buf); 232} 233 234void 235Bridge::BridgePort::trySend() 236{ 237 assert(!sendQueue.empty()); 238 239 PacketBuffer *buf = sendQueue.front(); 240 241 assert(buf->ready <= curTick); 242 243 PacketPtr pkt = buf->pkt; 244 245 DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", 246 buf->origSrc, pkt->getDest(), pkt->getAddr()); 247 248 bool wasReq = pkt->isRequest(); 249 bool was_nacked_here = buf->nackedHere; 250 251 // If the send was successful, make sure sender state was set to NULL 252 // otherwise we could get a NACK back of a packet that didn't expect a 253 // response and we would try to use freed memory. 254 255 Packet::SenderState *old_sender_state = pkt->senderState; 256 if (pkt->isRequest() && !buf->expectResponse) 257 pkt->senderState = NULL; 258 259 if (sendTiming(pkt)) { 260 // send successful 261 sendQueue.pop_front(); 262 buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it 263 264 if (buf->expectResponse) { 265 // Must wait for response 266 DPRINTF(BusBridge, " successful: awaiting response (%d)\n", 267 outstandingResponses); 268 } else { 269 // no response expected... deallocate packet buffer now. 270 DPRINTF(BusBridge, " successful: no response expected\n"); 271 delete buf; 272 } 273 274 if (wasReq) 275 --queuedRequests; 276 else if (!was_nacked_here) 277 --outstandingResponses; 278 279 // If there are more packets to send, schedule event to try again. 280 if (!sendQueue.empty()) { 281 buf = sendQueue.front(); 282 DPRINTF(BusBridge, "Scheduling next send\n"); 283 sendEvent.schedule(std::max(buf->ready, curTick + 1)); 284 } 285 } else { 286 DPRINTF(BusBridge, " unsuccessful\n"); 287 pkt->senderState = old_sender_state; 288 inRetry = true; 289 } 290 291 DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", 292 sendQueue.size(), queuedRequests, outstandingResponses); 293} 294 295 296void 297Bridge::BridgePort::recvRetry() 298{ 299 inRetry = false; 300 Tick nextReady = sendQueue.front()->ready; 301 if (nextReady <= curTick) 302 trySend(); 303 else 304 sendEvent.schedule(nextReady); 305} 306 307/** Function called by the port when the bus is receiving a Atomic 308 * transaction.*/ 309Tick 310Bridge::BridgePort::recvAtomic(PacketPtr pkt) 311{ 312 return delay + otherPort->sendAtomic(pkt); 313} 314 315/** Function called by the port when the bus is receiving a Functional 316 * transaction.*/ 317void 318Bridge::BridgePort::recvFunctional(PacketPtr pkt) 319{ 320 std::list<PacketBuffer*>::iterator i; 321 322 pkt->pushLabel(name()); 323 324 for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { 325 if (pkt->checkFunctional((*i)->pkt)) 326 return; 327 } 328 329 pkt->popLabel(); 330 331 // fall through if pkt still not satisfied 332 otherPort->sendFunctional(pkt); 333} 334 335/** Function called by the port when the bus is receiving a status change.*/ 336void 337Bridge::BridgePort::recvStatusChange(Port::Status status) 338{ 339 otherPort->sendStatusChange(status); 340} 341 342void 343Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, 344 bool &snoop) 345{ 346 otherPort->getPeerAddressRanges(resp, snoop); 347 FilterRangeList(filterRanges, resp); 348 // we don't allow snooping across bridges 349 snoop = false; 350} 351 352Bridge * 353BridgeParams::create() 354{ 355 return new Bridge(this); 356} 357