packet_queue.cc revision 12637:bfc3cb9c7e6c
114184Sgabeblack@google.com/* 214184Sgabeblack@google.com * Copyright (c) 2012,2015 ARM Limited 314184Sgabeblack@google.com * All rights reserved. 414184Sgabeblack@google.com * 514184Sgabeblack@google.com * The license below extends only to copyright in the software and shall 614184Sgabeblack@google.com * not be construed as granting a license to any other intellectual 714184Sgabeblack@google.com * property including but not limited to intellectual property relating 814184Sgabeblack@google.com * to a hardware implementation of the functionality of the software 914184Sgabeblack@google.com * licensed hereunder. You may use the software subject to the license 1014184Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated 1114184Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software, 1214184Sgabeblack@google.com * modified or unmodified, in source code or in binary form. 1314184Sgabeblack@google.com * 1414184Sgabeblack@google.com * Copyright (c) 2006 The Regents of The University of Michigan 1514184Sgabeblack@google.com * All rights reserved. 1614184Sgabeblack@google.com * 1714184Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without 1814184Sgabeblack@google.com * modification, are permitted provided that the following conditions are 1914184Sgabeblack@google.com * met: redistributions of source code must retain the above copyright 2014184Sgabeblack@google.com * notice, this list of conditions and the following disclaimer; 2114184Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright 2214184Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the 2314184Sgabeblack@google.com * documentation and/or other materials provided with the distribution; 2414184Sgabeblack@google.com * neither the name of the copyright holders nor the names of its 2514184Sgabeblack@google.com * contributors may be used to endorse or promote products derived from 2614184Sgabeblack@google.com * this software without specific prior written permission. 2714184Sgabeblack@google.com * 2814184Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2914184Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3014184Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3114184Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3214184Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3314184Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3414184Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3514184Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3614184Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3714184Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3814184Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3914184Sgabeblack@google.com * 4014184Sgabeblack@google.com * Authors: Ali Saidi 4114184Sgabeblack@google.com * Andreas Hansson 4214184Sgabeblack@google.com */ 4314184Sgabeblack@google.com 4414184Sgabeblack@google.com#include "mem/packet_queue.hh" 4514184Sgabeblack@google.com 4614184Sgabeblack@google.com#include "base/trace.hh" 4714184Sgabeblack@google.com#include "debug/Drain.hh" 4814184Sgabeblack@google.com#include "debug/PacketQueue.hh" 4914184Sgabeblack@google.com 5014184Sgabeblack@google.comPacketQueue::PacketQueue(EventManager& _em, const std::string& _label, 5114184Sgabeblack@google.com const std::string& _sendEventName, 5214184Sgabeblack@google.com bool disable_sanity_check) 5314184Sgabeblack@google.com : em(_em), sendEvent([this]{ processSendEvent(); }, _sendEventName), 5414184Sgabeblack@google.com _disableSanityCheck(disable_sanity_check), 5514184Sgabeblack@google.com label(_label), waitingOnRetry(false) 5614184Sgabeblack@google.com{ 5714184Sgabeblack@google.com} 5814184Sgabeblack@google.com 5914184Sgabeblack@google.comPacketQueue::~PacketQueue() 6014184Sgabeblack@google.com{ 6114184Sgabeblack@google.com} 6214184Sgabeblack@google.com 6314184Sgabeblack@google.comvoid 6414184Sgabeblack@google.comPacketQueue::retry() 6514184Sgabeblack@google.com{ 6614184Sgabeblack@google.com DPRINTF(PacketQueue, "Queue %s received retry\n", name()); 6714184Sgabeblack@google.com assert(waitingOnRetry); 6814184Sgabeblack@google.com waitingOnRetry = false; 6914184Sgabeblack@google.com sendDeferredPacket(); 7014184Sgabeblack@google.com} 7114184Sgabeblack@google.com 7214184Sgabeblack@google.combool 7314184Sgabeblack@google.comPacketQueue::hasAddr(Addr addr) const 7414184Sgabeblack@google.com{ 7514184Sgabeblack@google.com // caller is responsible for ensuring that all packets have the 7614184Sgabeblack@google.com // same alignment 7714184Sgabeblack@google.com for (const auto& p : transmitList) { 7814184Sgabeblack@google.com if (p.pkt->getAddr() == addr) 7914184Sgabeblack@google.com return true; 8014184Sgabeblack@google.com } 8114184Sgabeblack@google.com return false; 8214184Sgabeblack@google.com} 8314184Sgabeblack@google.com 8414184Sgabeblack@google.combool 8514184Sgabeblack@google.comPacketQueue::checkFunctional(PacketPtr pkt) 8614184Sgabeblack@google.com{ 8714184Sgabeblack@google.com pkt->pushLabel(label); 8814184Sgabeblack@google.com 8914184Sgabeblack@google.com auto i = transmitList.begin(); 9014184Sgabeblack@google.com bool found = false; 9114184Sgabeblack@google.com 9214184Sgabeblack@google.com while (!found && i != transmitList.end()) { 9314184Sgabeblack@google.com // If the buffered packet contains data, and it overlaps the 9414184Sgabeblack@google.com // current packet, then update data 9514184Sgabeblack@google.com found = pkt->checkFunctional(i->pkt); 9614184Sgabeblack@google.com ++i; 9714184Sgabeblack@google.com } 9814184Sgabeblack@google.com 9914184Sgabeblack@google.com pkt->popLabel(); 10014184Sgabeblack@google.com 10114184Sgabeblack@google.com return found; 10214184Sgabeblack@google.com} 10314184Sgabeblack@google.com 10414184Sgabeblack@google.comvoid 10514184Sgabeblack@google.comPacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool force_order) 10614184Sgabeblack@google.com{ 10714184Sgabeblack@google.com DPRINTF(PacketQueue, "%s for %s address %x size %d when %lu ord: %i\n", 10814184Sgabeblack@google.com __func__, pkt->cmdString(), pkt->getAddr(), pkt->getSize(), when, 10914184Sgabeblack@google.com force_order); 11014184Sgabeblack@google.com 11114184Sgabeblack@google.com // we can still send a packet before the end of this tick 11214184Sgabeblack@google.com assert(when >= curTick()); 11314184Sgabeblack@google.com 11414184Sgabeblack@google.com // express snoops should never be queued 11514184Sgabeblack@google.com assert(!pkt->isExpressSnoop()); 11614184Sgabeblack@google.com 11714184Sgabeblack@google.com // add a very basic sanity check on the port to ensure the 11814184Sgabeblack@google.com // invisible buffer is not growing beyond reasonable limits 11914184Sgabeblack@google.com if (!_disableSanityCheck && transmitList.size() > 100) { 12014184Sgabeblack@google.com panic("Packet queue %s has grown beyond 100 packets\n", 12114184Sgabeblack@google.com name()); 12214184Sgabeblack@google.com } 12314184Sgabeblack@google.com 12414184Sgabeblack@google.com // nothing on the list 12514184Sgabeblack@google.com if (transmitList.empty()) { 12614184Sgabeblack@google.com transmitList.emplace_front(when, pkt); 12714184Sgabeblack@google.com schedSendEvent(when); 12814184Sgabeblack@google.com return; 12914184Sgabeblack@google.com } 13014184Sgabeblack@google.com 13114184Sgabeblack@google.com // we should either have an outstanding retry, or a send event 13214184Sgabeblack@google.com // scheduled, but there is an unfortunate corner case where the 13314184Sgabeblack@google.com // x86 page-table walker and timing CPU send out a new request as 13414184Sgabeblack@google.com // part of the receiving of a response (called by 13514184Sgabeblack@google.com // PacketQueue::sendDeferredPacket), in which we end up calling 13614184Sgabeblack@google.com // ourselves again before we had a chance to update waitingOnRetry 13714184Sgabeblack@google.com // assert(waitingOnRetry || sendEvent.scheduled()); 13814184Sgabeblack@google.com 13914184Sgabeblack@google.com // this belongs in the middle somewhere, so search from the end to 14014184Sgabeblack@google.com // order by tick; however, if force_order is set, also make sure 14114184Sgabeblack@google.com // not to re-order in front of some existing packet with the same 14214184Sgabeblack@google.com // address 14314184Sgabeblack@google.com auto i = transmitList.end(); 14414184Sgabeblack@google.com --i; 14514184Sgabeblack@google.com while (i != transmitList.begin() && when < i->tick && 14614184Sgabeblack@google.com !(force_order && i->pkt->getAddr() == pkt->getAddr())) 14714184Sgabeblack@google.com --i; 14814184Sgabeblack@google.com 14914184Sgabeblack@google.com // emplace inserts the element before the position pointed to by 15014184Sgabeblack@google.com // the iterator, so advance it one step 15114184Sgabeblack@google.com transmitList.emplace(++i, when, pkt); 15214184Sgabeblack@google.com} 15314184Sgabeblack@google.com 15414184Sgabeblack@google.comvoid 15514184Sgabeblack@google.comPacketQueue::schedSendEvent(Tick when) 15614184Sgabeblack@google.com{ 15714184Sgabeblack@google.com // if we are waiting on a retry just hold off 15814184Sgabeblack@google.com if (waitingOnRetry) { 15914184Sgabeblack@google.com DPRINTF(PacketQueue, "Not scheduling send as waiting for retry\n"); 16014184Sgabeblack@google.com assert(!sendEvent.scheduled()); 16114184Sgabeblack@google.com return; 16214184Sgabeblack@google.com } 16314184Sgabeblack@google.com 16414184Sgabeblack@google.com if (when != MaxTick) { 16514184Sgabeblack@google.com // we cannot go back in time, and to be consistent we stick to 16614184Sgabeblack@google.com // one tick in the future 16714184Sgabeblack@google.com when = std::max(when, curTick() + 1); 16814184Sgabeblack@google.com // @todo Revisit the +1 16914184Sgabeblack@google.com 17014184Sgabeblack@google.com if (!sendEvent.scheduled()) { 17114184Sgabeblack@google.com em.schedule(&sendEvent, when); 17214184Sgabeblack@google.com } else if (when < sendEvent.when()) { 17314184Sgabeblack@google.com // if the new time is earlier than when the event 17414184Sgabeblack@google.com // currently is scheduled, move it forward 17514184Sgabeblack@google.com em.reschedule(&sendEvent, when); 17614184Sgabeblack@google.com } 17714184Sgabeblack@google.com } else { 17814184Sgabeblack@google.com // we get a MaxTick when there is no more to send, so if we're 17914184Sgabeblack@google.com // draining, we may be done at this point 18014184Sgabeblack@google.com if (drainState() == DrainState::Draining && 18114184Sgabeblack@google.com transmitList.empty() && !sendEvent.scheduled()) { 18214184Sgabeblack@google.com 18314184Sgabeblack@google.com DPRINTF(Drain, "PacketQueue done draining," 18414184Sgabeblack@google.com "processing drain event\n"); 18514184Sgabeblack@google.com signalDrainDone(); 18614184Sgabeblack@google.com } 18714184Sgabeblack@google.com } 18814184Sgabeblack@google.com} 18914184Sgabeblack@google.com 19014184Sgabeblack@google.comvoid 19114184Sgabeblack@google.comPacketQueue::sendDeferredPacket() 19214184Sgabeblack@google.com{ 19314184Sgabeblack@google.com // sanity checks 19414184Sgabeblack@google.com assert(!waitingOnRetry); 19514184Sgabeblack@google.com assert(deferredPacketReady()); 19614184Sgabeblack@google.com 19714184Sgabeblack@google.com DeferredPacket dp = transmitList.front(); 19814184Sgabeblack@google.com 19914184Sgabeblack@google.com // take the packet of the list before sending it, as sending of 20014184Sgabeblack@google.com // the packet in some cases causes a new packet to be enqueued 20114184Sgabeblack@google.com // (most notaly when responding to the timing CPU, leading to a 20214184Sgabeblack@google.com // new request hitting in the L1 icache, leading to a new 20314184Sgabeblack@google.com // response) 20414184Sgabeblack@google.com transmitList.pop_front(); 20514184Sgabeblack@google.com 20614184Sgabeblack@google.com // use the appropriate implementation of sendTiming based on the 20714184Sgabeblack@google.com // type of queue 20814184Sgabeblack@google.com waitingOnRetry = !sendTiming(dp.pkt); 20914184Sgabeblack@google.com 21014184Sgabeblack@google.com // if we succeeded and are not waiting for a retry, schedule the 21114184Sgabeblack@google.com // next send 21214184Sgabeblack@google.com if (!waitingOnRetry) { 21314184Sgabeblack@google.com schedSendEvent(deferredPacketReadyTime()); 21414184Sgabeblack@google.com } else { 21514184Sgabeblack@google.com // put the packet back at the front of the list 21614184Sgabeblack@google.com transmitList.emplace_front(dp); 21714184Sgabeblack@google.com } 21814184Sgabeblack@google.com} 21914184Sgabeblack@google.com 22014184Sgabeblack@google.comvoid 22114184Sgabeblack@google.comPacketQueue::processSendEvent() 22214184Sgabeblack@google.com{ 22314184Sgabeblack@google.com assert(!waitingOnRetry); 22414184Sgabeblack@google.com sendDeferredPacket(); 22514184Sgabeblack@google.com} 22614184Sgabeblack@google.com 22714184Sgabeblack@google.comDrainState 22814184Sgabeblack@google.comPacketQueue::drain() 22914184Sgabeblack@google.com{ 23014184Sgabeblack@google.com if (transmitList.empty()) { 23114184Sgabeblack@google.com return DrainState::Drained; 23214184Sgabeblack@google.com } else { 23314184Sgabeblack@google.com DPRINTF(Drain, "PacketQueue not drained\n"); 23414184Sgabeblack@google.com return DrainState::Draining; 23514184Sgabeblack@google.com } 23614184Sgabeblack@google.com} 23714184Sgabeblack@google.com 23814184Sgabeblack@google.comReqPacketQueue::ReqPacketQueue(EventManager& _em, MasterPort& _masterPort, 23914184Sgabeblack@google.com const std::string _label) 24014184Sgabeblack@google.com : PacketQueue(_em, _label, name(_masterPort, _label)), 24114184Sgabeblack@google.com masterPort(_masterPort) 24214184Sgabeblack@google.com{ 24314184Sgabeblack@google.com} 24414184Sgabeblack@google.com 24514184Sgabeblack@google.combool 24614184Sgabeblack@google.comReqPacketQueue::sendTiming(PacketPtr pkt) 24714184Sgabeblack@google.com{ 24814184Sgabeblack@google.com return masterPort.sendTimingReq(pkt); 24914184Sgabeblack@google.com} 25014184Sgabeblack@google.com 25114184Sgabeblack@google.comSnoopRespPacketQueue::SnoopRespPacketQueue(EventManager& _em, 25214184Sgabeblack@google.com MasterPort& _masterPort, 25314184Sgabeblack@google.com const std::string _label) 25414184Sgabeblack@google.com : PacketQueue(_em, _label, name(_masterPort, _label)), 25514184Sgabeblack@google.com masterPort(_masterPort) 25614184Sgabeblack@google.com{ 25714184Sgabeblack@google.com} 25814184Sgabeblack@google.com 25914184Sgabeblack@google.combool 26014184Sgabeblack@google.comSnoopRespPacketQueue::sendTiming(PacketPtr pkt) 26114184Sgabeblack@google.com{ 26214184Sgabeblack@google.com return masterPort.sendTimingSnoopResp(pkt); 26314184Sgabeblack@google.com} 26414184Sgabeblack@google.com 26514184Sgabeblack@google.comRespPacketQueue::RespPacketQueue(EventManager& _em, SlavePort& _slavePort, 26614184Sgabeblack@google.com const std::string _label) 26714184Sgabeblack@google.com : PacketQueue(_em, _label, name(_slavePort, _label)), 26814184Sgabeblack@google.com slavePort(_slavePort) 26914184Sgabeblack@google.com{ 27014184Sgabeblack@google.com} 27114184Sgabeblack@google.com 27214184Sgabeblack@google.combool 27314184Sgabeblack@google.comRespPacketQueue::sendTiming(PacketPtr pkt) 27414184Sgabeblack@google.com{ 27514184Sgabeblack@google.com return slavePort.sendTimingResp(pkt); 27614184Sgabeblack@google.com} 27714184Sgabeblack@google.com