packet_queue.cc revision 11793
12391SN/A/* 22391SN/A * Copyright (c) 2012,2015 ARM Limited 32391SN/A * All rights reserved. 42391SN/A * 52391SN/A * The license below extends only to copyright in the software and shall 62391SN/A * not be construed as granting a license to any other intellectual 72391SN/A * property including but not limited to intellectual property relating 82391SN/A * to a hardware implementation of the functionality of the software 92391SN/A * licensed hereunder. You may use the software subject to the license 102391SN/A * terms below provided that you ensure that this notice is replicated 112391SN/A * unmodified and in its entirety in all distributions of the software, 122391SN/A * modified or unmodified, in source code or in binary form. 132391SN/A * 142391SN/A * Copyright (c) 2006 The Regents of The University of Michigan 152391SN/A * All rights reserved. 162391SN/A * 172391SN/A * Redistribution and use in source and binary forms, with or without 182391SN/A * modification, are permitted provided that the following conditions are 192391SN/A * met: redistributions of source code must retain the above copyright 202391SN/A * notice, this list of conditions and the following disclaimer; 212391SN/A * redistributions in binary form must reproduce the above copyright 222391SN/A * notice, this list of conditions and the following disclaimer in the 232391SN/A * documentation and/or other materials provided with the distribution; 242391SN/A * neither the name of the copyright holders nor the names of its 252391SN/A * contributors may be used to endorse or promote products derived from 262391SN/A * this software without specific prior written permission. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 292391SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 302391SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 312391SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 322391SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 332391SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 342391SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 352391SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 362391SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 374762Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 384762Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 394762Snate@binkert.org * 402391SN/A * Authors: Ali Saidi 412462SN/A * Andreas Hansson 422414SN/A */ 432914Ssaidi@eecs.umich.edu 444762Snate@binkert.org#include "mem/packet_queue.hh" 452415SN/A 462462SN/A#include "base/trace.hh" 472391SN/A#include "debug/Drain.hh" 482391SN/A#include "debug/PacketQueue.hh" 492391SN/A 502462SN/Ausing namespace std; 512391SN/A 526107Ssteve.reinhardt@amd.comPacketQueue::PacketQueue(EventManager& _em, const std::string& _label, 536107Ssteve.reinhardt@amd.com bool disable_sanity_check) 542914Ssaidi@eecs.umich.edu : em(_em), sendEvent(this), _disableSanityCheck(disable_sanity_check), 552413SN/A label(_label), waitingOnRetry(false) 562413SN/A{ 572413SN/A} 582413SN/A 592413SN/APacketQueue::~PacketQueue() 602640Sstever@eecs.umich.edu{ 612413SN/A} 622413SN/A 632413SN/Avoid 643349Sbinkertn@umich.eduPacketQueue::retry() 652413SN/A{ 663349Sbinkertn@umich.edu DPRINTF(PacketQueue, "Queue %s received retry\n", name()); 672413SN/A assert(waitingOnRetry); 682413SN/A waitingOnRetry = false; 692413SN/A sendDeferredPacket(); 702521SN/A} 714475Sstever@eecs.umich.edu 722413SN/Abool 736227Snate@binkert.orgPacketQueue::hasAddr(Addr addr) const 742413SN/A{ 752413SN/A // caller is responsible for ensuring that all packets have the 762416SN/A // same alignment 772416SN/A for (const auto& p : transmitList) { 782413SN/A if (p.pkt->getAddr() == addr) 792391SN/A return true; 802391SN/A } 812391SN/A return false; 822391SN/A} 832391SN/A 842391SN/Abool 853170Sstever@eecs.umich.eduPacketQueue::checkFunctional(PacketPtr pkt) 863170Sstever@eecs.umich.edu{ 873170Sstever@eecs.umich.edu pkt->pushLabel(label); 883170Sstever@eecs.umich.edu 893170Sstever@eecs.umich.edu auto i = transmitList.begin(); 903170Sstever@eecs.umich.edu bool found = false; 913170Sstever@eecs.umich.edu 923170Sstever@eecs.umich.edu while (!found && i != transmitList.end()) { 933170Sstever@eecs.umich.edu // If the buffered packet contains data, and it overlaps the 945543Ssaidi@eecs.umich.edu // current packet, then update data 955714Shsul@eecs.umich.edu found = pkt->checkFunctional(i->pkt); 963170Sstever@eecs.umich.edu ++i; 973170Sstever@eecs.umich.edu } 983170Sstever@eecs.umich.edu 993170Sstever@eecs.umich.edu pkt->popLabel(); 1005714Shsul@eecs.umich.edu 1013170Sstever@eecs.umich.edu return found; 1023170Sstever@eecs.umich.edu} 1033170Sstever@eecs.umich.edu 1043170Sstever@eecs.umich.eduvoid 1055714Shsul@eecs.umich.eduPacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool force_order) 1063170Sstever@eecs.umich.edu{ 1073170Sstever@eecs.umich.edu DPRINTF(PacketQueue, "%s for %s address %x size %d when %lu ord: %i\n", 1083170Sstever@eecs.umich.edu __func__, pkt->cmdString(), pkt->getAddr(), pkt->getSize(), when, 1093170Sstever@eecs.umich.edu force_order); 1103170Sstever@eecs.umich.edu 1113170Sstever@eecs.umich.edu // we can still send a packet before the end of this tick 1123170Sstever@eecs.umich.edu assert(when >= curTick()); 1133170Sstever@eecs.umich.edu 1143170Sstever@eecs.umich.edu // express snoops should never be queued 1153170Sstever@eecs.umich.edu assert(!pkt->isExpressSnoop()); 1164626Sstever@eecs.umich.edu 1173170Sstever@eecs.umich.edu // add a very basic sanity check on the port to ensure the 1183170Sstever@eecs.umich.edu // invisible buffer is not growing beyond reasonable limits 1193170Sstever@eecs.umich.edu if (!_disableSanityCheck && transmitList.size() > 100) { 1203170Sstever@eecs.umich.edu panic("Packet queue %s has grown beyond 100 packets\n", 1214626Sstever@eecs.umich.edu name()); 1223170Sstever@eecs.umich.edu } 1233170Sstever@eecs.umich.edu 1243170Sstever@eecs.umich.edu // nothing on the list 1253170Sstever@eecs.umich.edu if (transmitList.empty()) { 1263170Sstever@eecs.umich.edu transmitList.emplace_front(when, pkt); 1273170Sstever@eecs.umich.edu schedSendEvent(when); 1283170Sstever@eecs.umich.edu return; 1293170Sstever@eecs.umich.edu } 1304626Sstever@eecs.umich.edu 1314626Sstever@eecs.umich.edu // we should either have an outstanding retry, or a send event 1323170Sstever@eecs.umich.edu // scheduled, but there is an unfortunate corner case where the 1333170Sstever@eecs.umich.edu // x86 page-table walker and timing CPU send out a new request as 1346102Sgblack@eecs.umich.edu // part of the receiving of a response (called by 1356102Sgblack@eecs.umich.edu // PacketQueue::sendDeferredPacket), in which we end up calling 1364040Ssaidi@eecs.umich.edu // ourselves again before we had a chance to update waitingOnRetry 1373170Sstever@eecs.umich.edu // assert(waitingOnRetry || sendEvent.scheduled()); 1386102Sgblack@eecs.umich.edu 1393170Sstever@eecs.umich.edu // this belongs in the middle somewhere, so search from the end to 1403170Sstever@eecs.umich.edu // order by tick; however, if force_order is set, also make sure 1414626Sstever@eecs.umich.edu // not to re-order in front of some existing packet with the same 1423170Sstever@eecs.umich.edu // address 1433170Sstever@eecs.umich.edu auto i = transmitList.end(); 1443170Sstever@eecs.umich.edu --i; 1453012Ssaidi@eecs.umich.edu while (i != transmitList.begin() && when < i->tick && 1463012Ssaidi@eecs.umich.edu !(force_order && i->pkt->getAddr() == pkt->getAddr())) 1472565SN/A --i; 1485399Ssaidi@eecs.umich.edu 1494467Sstever@eecs.umich.edu // emplace inserts the element before the position pointed to by 1504467Sstever@eecs.umich.edu // the iterator, so advance it one step 1512391SN/A transmitList.emplace(++i, when, pkt); 1525275Ssaidi@eecs.umich.edu} 1535275Ssaidi@eecs.umich.edu 1542391SN/Avoid 1552391SN/APacketQueue::schedSendEvent(Tick when) 1565275Ssaidi@eecs.umich.edu{ 1575275Ssaidi@eecs.umich.edu // if we are waiting on a retry just hold off 1582391SN/A if (waitingOnRetry) { 1592391SN/A DPRINTF(PacketQueue, "Not scheduling send as waiting for retry\n"); 1604762Snate@binkert.org assert(!sendEvent.scheduled()); 1614762Snate@binkert.org return; 1622391SN/A } 1632391SN/A 1644762Snate@binkert.org if (when != MaxTick) { 1654762Snate@binkert.org // we cannot go back in time, and to be consistent we stick to 1664762Snate@binkert.org // one tick in the future 1674762Snate@binkert.org when = std::max(when, curTick() + 1); 1684762Snate@binkert.org // @todo Revisit the +1 1694762Snate@binkert.org 1702391SN/A if (!sendEvent.scheduled()) { 1716227Snate@binkert.org em.schedule(&sendEvent, when); 1724475Sstever@eecs.umich.edu } else if (when < sendEvent.when()) { 1732738Sstever@eecs.umich.edu // if the new time is earlier than when the event 1742541SN/A // currently is scheduled, move it forward 1752914Ssaidi@eecs.umich.edu em.reschedule(&sendEvent, when); 1762391SN/A } 1773012Ssaidi@eecs.umich.edu } else { 1784626Sstever@eecs.umich.edu // we get a MaxTick when there is no more to send, so if we're 1793349Sbinkertn@umich.edu // draining, we may be done at this point 1803349Sbinkertn@umich.edu if (drainState() == DrainState::Draining && 1812413SN/A transmitList.empty() && !sendEvent.scheduled()) { 1822391SN/A 1832391SN/A DPRINTF(Drain, "PacketQueue done draining," 1842391SN/A "processing drain event\n"); 1852391SN/A signalDrainDone(); 1862497SN/A } 1872391SN/A } 1882391SN/A} 1892391SN/A 190void 191PacketQueue::sendDeferredPacket() 192{ 193 // sanity checks 194 assert(!waitingOnRetry); 195 assert(deferredPacketReady()); 196 197 DeferredPacket dp = transmitList.front(); 198 199 // take the packet of the list before sending it, as sending of 200 // the packet in some cases causes a new packet to be enqueued 201 // (most notaly when responding to the timing CPU, leading to a 202 // new request hitting in the L1 icache, leading to a new 203 // response) 204 transmitList.pop_front(); 205 206 // use the appropriate implementation of sendTiming based on the 207 // type of queue 208 waitingOnRetry = !sendTiming(dp.pkt); 209 210 // if we succeeded and are not waiting for a retry, schedule the 211 // next send 212 if (!waitingOnRetry) { 213 schedSendEvent(deferredPacketReadyTime()); 214 } else { 215 // put the packet back at the front of the list 216 transmitList.emplace_front(dp); 217 } 218} 219 220void 221PacketQueue::processSendEvent() 222{ 223 assert(!waitingOnRetry); 224 sendDeferredPacket(); 225} 226 227DrainState 228PacketQueue::drain() 229{ 230 if (transmitList.empty()) { 231 return DrainState::Drained; 232 } else { 233 DPRINTF(Drain, "PacketQueue not drained\n"); 234 return DrainState::Draining; 235 } 236} 237 238ReqPacketQueue::ReqPacketQueue(EventManager& _em, MasterPort& _masterPort, 239 const std::string _label) 240 : PacketQueue(_em, _label), masterPort(_masterPort) 241{ 242} 243 244bool 245ReqPacketQueue::sendTiming(PacketPtr pkt) 246{ 247 return masterPort.sendTimingReq(pkt); 248} 249 250SnoopRespPacketQueue::SnoopRespPacketQueue(EventManager& _em, 251 MasterPort& _masterPort, 252 const std::string _label) 253 : PacketQueue(_em, _label), masterPort(_masterPort) 254{ 255} 256 257bool 258SnoopRespPacketQueue::sendTiming(PacketPtr pkt) 259{ 260 return masterPort.sendTimingSnoopResp(pkt); 261} 262 263RespPacketQueue::RespPacketQueue(EventManager& _em, SlavePort& _slavePort, 264 const std::string _label) 265 : PacketQueue(_em, _label), slavePort(_slavePort) 266{ 267} 268 269bool 270RespPacketQueue::sendTiming(PacketPtr pkt) 271{ 272 return slavePort.sendTimingResp(pkt); 273} 274