packet_queue.cc revision 13565:fe1169a7502d
14348Sgblack@eecs.umich.edu/*
24348Sgblack@eecs.umich.edu * Copyright (c) 2012,2015,2018 ARM Limited
34348Sgblack@eecs.umich.edu * All rights reserved.
44348Sgblack@eecs.umich.edu *
54348Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
64348Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
74348Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
84348Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
94348Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
104348Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
114348Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
124348Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
134348Sgblack@eecs.umich.edu *
144348Sgblack@eecs.umich.edu * Copyright (c) 2006 The Regents of The University of Michigan
154348Sgblack@eecs.umich.edu * All rights reserved.
164348Sgblack@eecs.umich.edu *
174348Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
184348Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
194348Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
204348Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
214348Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
224348Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
234348Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
244348Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
254348Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
264348Sgblack@eecs.umich.edu * this software without specific prior written permission.
274348Sgblack@eecs.umich.edu *
284348Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
294348Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
304348Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
314348Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
324348Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
334348Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
344348Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
354348Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
364348Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
374348Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
384348Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
394348Sgblack@eecs.umich.edu *
404348Sgblack@eecs.umich.edu * Authors: Ali Saidi
414348Sgblack@eecs.umich.edu *          Andreas Hansson
424348Sgblack@eecs.umich.edu */
434348Sgblack@eecs.umich.edu
444348Sgblack@eecs.umich.edu#include "mem/packet_queue.hh"
454348Sgblack@eecs.umich.edu
464348Sgblack@eecs.umich.edu#include "base/trace.hh"
474348Sgblack@eecs.umich.edu#include "debug/Drain.hh"
484348Sgblack@eecs.umich.edu#include "debug/PacketQueue.hh"
494348Sgblack@eecs.umich.edu
504348Sgblack@eecs.umich.eduPacketQueue::PacketQueue(EventManager& _em, const std::string& _label,
514348Sgblack@eecs.umich.edu                         const std::string& _sendEventName,
524348Sgblack@eecs.umich.edu                         bool force_order,
534348Sgblack@eecs.umich.edu                         bool disable_sanity_check)
544348Sgblack@eecs.umich.edu    : em(_em), sendEvent([this]{ processSendEvent(); }, _sendEventName),
554348Sgblack@eecs.umich.edu      _disableSanityCheck(disable_sanity_check),
564348Sgblack@eecs.umich.edu      forceOrder(force_order),
574348Sgblack@eecs.umich.edu      label(_label), waitingOnRetry(false)
584348Sgblack@eecs.umich.edu{
594348Sgblack@eecs.umich.edu}
604348Sgblack@eecs.umich.edu
614348Sgblack@eecs.umich.eduPacketQueue::~PacketQueue()
624348Sgblack@eecs.umich.edu{
634348Sgblack@eecs.umich.edu}
644348Sgblack@eecs.umich.edu
654348Sgblack@eecs.umich.eduvoid
664348Sgblack@eecs.umich.eduPacketQueue::retry()
674609Sgblack@eecs.umich.edu{
684609Sgblack@eecs.umich.edu    DPRINTF(PacketQueue, "Queue %s received retry\n", name());
694609Sgblack@eecs.umich.edu    assert(waitingOnRetry);
704542Sgblack@eecs.umich.edu    waitingOnRetry = false;
714542Sgblack@eecs.umich.edu    sendDeferredPacket();
724348Sgblack@eecs.umich.edu}
734609Sgblack@eecs.umich.edu
744542Sgblack@eecs.umich.edubool
754542Sgblack@eecs.umich.eduPacketQueue::hasAddr(Addr addr) const
764542Sgblack@eecs.umich.edu{
774348Sgblack@eecs.umich.edu    // caller is responsible for ensuring that all packets have the
784609Sgblack@eecs.umich.edu    // same alignment
794542Sgblack@eecs.umich.edu    for (const auto& p : transmitList) {
804542Sgblack@eecs.umich.edu        if (p.pkt->getAddr() == addr)
814542Sgblack@eecs.umich.edu            return true;
824542Sgblack@eecs.umich.edu    }
834542Sgblack@eecs.umich.edu    return false;
844348Sgblack@eecs.umich.edu}
854348Sgblack@eecs.umich.edu
864348Sgblack@eecs.umich.edubool
874609Sgblack@eecs.umich.eduPacketQueue::trySatisfyFunctional(PacketPtr pkt)
884609Sgblack@eecs.umich.edu{
894609Sgblack@eecs.umich.edu    pkt->pushLabel(label);
904609Sgblack@eecs.umich.edu
914609Sgblack@eecs.umich.edu    auto i = transmitList.begin();
924609Sgblack@eecs.umich.edu    bool found = false;
934609Sgblack@eecs.umich.edu
944609Sgblack@eecs.umich.edu    while (!found && i != transmitList.end()) {
954609Sgblack@eecs.umich.edu        // If the buffered packet contains data, and it overlaps the
964609Sgblack@eecs.umich.edu        // current packet, then update data
974609Sgblack@eecs.umich.edu        found = pkt->trySatisfyFunctional(i->pkt);
984609Sgblack@eecs.umich.edu        ++i;
994609Sgblack@eecs.umich.edu    }
1004609Sgblack@eecs.umich.edu
1014609Sgblack@eecs.umich.edu    pkt->popLabel();
1024609Sgblack@eecs.umich.edu
1034609Sgblack@eecs.umich.edu    return found;
1044609Sgblack@eecs.umich.edu}
1054609Sgblack@eecs.umich.edu
1064609Sgblack@eecs.umich.eduvoid
1074609Sgblack@eecs.umich.eduPacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
1084348Sgblack@eecs.umich.edu{
1094601Sgblack@eecs.umich.edu    DPRINTF(PacketQueue, "%s for %s address %x size %d when %lu ord: %i\n",
1104348Sgblack@eecs.umich.edu            __func__, pkt->cmdString(), pkt->getAddr(), pkt->getSize(), when,
1114348Sgblack@eecs.umich.edu            forceOrder);
1124348Sgblack@eecs.umich.edu
1134348Sgblack@eecs.umich.edu    // we can still send a packet before the end of this tick
1144348Sgblack@eecs.umich.edu    assert(when >= curTick());
1154348Sgblack@eecs.umich.edu
1164348Sgblack@eecs.umich.edu    // express snoops should never be queued
1174528Sgblack@eecs.umich.edu    assert(!pkt->isExpressSnoop());
1184348Sgblack@eecs.umich.edu
1194548Sgblack@eecs.umich.edu    // add a very basic sanity check on the port to ensure the
1204548Sgblack@eecs.umich.edu    // invisible buffer is not growing beyond reasonable limits
1214548Sgblack@eecs.umich.edu    if (!_disableSanityCheck && transmitList.size() > 100) {
1224348Sgblack@eecs.umich.edu        panic("Packet queue %s has grown beyond 100 packets\n",
1234528Sgblack@eecs.umich.edu              name());
1244528Sgblack@eecs.umich.edu    }
1254568Sgblack@eecs.umich.edu
1264348Sgblack@eecs.umich.edu    // we should either have an outstanding retry, or a send event
1274528Sgblack@eecs.umich.edu    // scheduled, but there is an unfortunate corner case where the
1284542Sgblack@eecs.umich.edu    // x86 page-table walker and timing CPU send out a new request as
1294601Sgblack@eecs.umich.edu    // part of the receiving of a response (called by
1304348Sgblack@eecs.umich.edu    // PacketQueue::sendDeferredPacket), in which we end up calling
1314348Sgblack@eecs.umich.edu    // ourselves again before we had a chance to update waitingOnRetry
1324348Sgblack@eecs.umich.edu    // assert(waitingOnRetry || sendEvent.scheduled());
1334528Sgblack@eecs.umich.edu
1344542Sgblack@eecs.umich.edu    // this belongs in the middle somewhere, so search from the end to
1354601Sgblack@eecs.umich.edu    // order by tick; however, if forceOrder is set, also make sure
1364542Sgblack@eecs.umich.edu    // not to re-order in front of some existing packet with the same
1374601Sgblack@eecs.umich.edu    // address
1384528Sgblack@eecs.umich.edu    auto it = transmitList.end();
1394528Sgblack@eecs.umich.edu    while (it != transmitList.begin()) {
1404528Sgblack@eecs.umich.edu        --it;
1414528Sgblack@eecs.umich.edu        if ((forceOrder && it->pkt->getAddr() == pkt->getAddr()) ||
1424528Sgblack@eecs.umich.edu            it->tick <= when) {
1434528Sgblack@eecs.umich.edu            // emplace inserts the element before the position pointed to by
1444528Sgblack@eecs.umich.edu            // the iterator, so advance it one step
1454575Sgblack@eecs.umich.edu            transmitList.emplace(++it, when, pkt);
1464601Sgblack@eecs.umich.edu            return;
1474601Sgblack@eecs.umich.edu        }
1484601Sgblack@eecs.umich.edu    }
1494601Sgblack@eecs.umich.edu    // either the packet list is empty or this has to be inserted
1504601Sgblack@eecs.umich.edu    // before every other packet
1514348Sgblack@eecs.umich.edu    transmitList.emplace_front(when, pkt);
1524348Sgblack@eecs.umich.edu    schedSendEvent(when);
1534348Sgblack@eecs.umich.edu}
1544348Sgblack@eecs.umich.edu
1554548Sgblack@eecs.umich.eduvoid
1564575Sgblack@eecs.umich.eduPacketQueue::schedSendEvent(Tick when)
1574348Sgblack@eecs.umich.edu{
1584348Sgblack@eecs.umich.edu    // if we are waiting on a retry just hold off
1594348Sgblack@eecs.umich.edu    if (waitingOnRetry) {
1604528Sgblack@eecs.umich.edu        DPRINTF(PacketQueue, "Not scheduling send as waiting for retry\n");
1614548Sgblack@eecs.umich.edu        assert(!sendEvent.scheduled());
1624601Sgblack@eecs.umich.edu        return;
1634601Sgblack@eecs.umich.edu    }
1644528Sgblack@eecs.umich.edu
1654601Sgblack@eecs.umich.edu    if (when != MaxTick) {
1664609Sgblack@eecs.umich.edu        // we cannot go back in time, and to be consistent we stick to
1674609Sgblack@eecs.umich.edu        // one tick in the future
1684609Sgblack@eecs.umich.edu        when = std::max(when, curTick() + 1);
1694348Sgblack@eecs.umich.edu        // @todo Revisit the +1
1704532Sgblack@eecs.umich.edu
1714575Sgblack@eecs.umich.edu        if (!sendEvent.scheduled()) {
1724348Sgblack@eecs.umich.edu            em.schedule(&sendEvent, when);
1734601Sgblack@eecs.umich.edu        } else if (when < sendEvent.when()) {
1744548Sgblack@eecs.umich.edu            // if the new time is earlier than when the event
1754575Sgblack@eecs.umich.edu            // currently is scheduled, move it forward
1764348Sgblack@eecs.umich.edu            em.reschedule(&sendEvent, when);
1774348Sgblack@eecs.umich.edu        }
1784348Sgblack@eecs.umich.edu    } else {
1794532Sgblack@eecs.umich.edu        // we get a MaxTick when there is no more to send, so if we're
1804559Sgblack@eecs.umich.edu        // draining, we may be done at this point
1814528Sgblack@eecs.umich.edu        if (drainState() == DrainState::Draining &&
1824348Sgblack@eecs.umich.edu            transmitList.empty() && !sendEvent.scheduled()) {
183
184            DPRINTF(Drain, "PacketQueue done draining,"
185                    "processing drain event\n");
186            signalDrainDone();
187        }
188    }
189}
190
191void
192PacketQueue::sendDeferredPacket()
193{
194    // sanity checks
195    assert(!waitingOnRetry);
196    assert(deferredPacketReady());
197
198    DeferredPacket dp = transmitList.front();
199
200    // take the packet of the list before sending it, as sending of
201    // the packet in some cases causes a new packet to be enqueued
202    // (most notaly when responding to the timing CPU, leading to a
203    // new request hitting in the L1 icache, leading to a new
204    // response)
205    transmitList.pop_front();
206
207    // use the appropriate implementation of sendTiming based on the
208    // type of queue
209    waitingOnRetry = !sendTiming(dp.pkt);
210
211    // if we succeeded and are not waiting for a retry, schedule the
212    // next send
213    if (!waitingOnRetry) {
214        schedSendEvent(deferredPacketReadyTime());
215    } else {
216        // put the packet back at the front of the list
217        transmitList.emplace_front(dp);
218    }
219}
220
221void
222PacketQueue::processSendEvent()
223{
224    assert(!waitingOnRetry);
225    sendDeferredPacket();
226}
227
228DrainState
229PacketQueue::drain()
230{
231    if (transmitList.empty()) {
232        return DrainState::Drained;
233    } else {
234        DPRINTF(Drain, "PacketQueue not drained\n");
235        return DrainState::Draining;
236    }
237}
238
239ReqPacketQueue::ReqPacketQueue(EventManager& _em, MasterPort& _masterPort,
240                               const std::string _label)
241    : PacketQueue(_em, _label, name(_masterPort, _label)),
242      masterPort(_masterPort)
243{
244}
245
246bool
247ReqPacketQueue::sendTiming(PacketPtr pkt)
248{
249    return masterPort.sendTimingReq(pkt);
250}
251
252SnoopRespPacketQueue::SnoopRespPacketQueue(EventManager& _em,
253                                           MasterPort& _masterPort,
254                                           bool force_order,
255                                           const std::string _label)
256    : PacketQueue(_em, _label, name(_masterPort, _label), force_order),
257      masterPort(_masterPort)
258{
259}
260
261bool
262SnoopRespPacketQueue::sendTiming(PacketPtr pkt)
263{
264    return masterPort.sendTimingSnoopResp(pkt);
265}
266
267RespPacketQueue::RespPacketQueue(EventManager& _em, SlavePort& _slavePort,
268                                 bool force_order,
269                                 const std::string _label)
270    : PacketQueue(_em, _label, name(_slavePort, _label), force_order),
271      slavePort(_slavePort)
272{
273}
274
275bool
276RespPacketQueue::sendTiming(PacketPtr pkt)
277{
278    return slavePort.sendTimingResp(pkt);
279}
280