packet_queue.cc (10423:cc7f3988c5a9) packet_queue.cc (10713:eddb533708cb)
1/*
1/*
2 * Copyright (c) 2012 ARM Limited
2 * Copyright (c) 2012,2015 ARM Limited
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated

--- 47 unchanged lines hidden (view full) ---

58{
59}
60
61void
62PacketQueue::retry()
63{
64 DPRINTF(PacketQueue, "Queue %s received retry\n", name());
65 assert(waitingOnRetry);
3 * All rights reserved.
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated

--- 47 unchanged lines hidden (view full) ---

58{
59}
60
61void
62PacketQueue::retry()
63{
64 DPRINTF(PacketQueue, "Queue %s received retry\n", name());
65 assert(waitingOnRetry);
66 waitingOnRetry = false;
66 sendDeferredPacket();
67}
68
69bool
67 sendDeferredPacket();
68}
69
70bool
71PacketQueue::hasAddr(Addr addr) const
72{
73 // caller is responsible for ensuring that all packets have the
74 // same alignment
75 for (const auto& p : transmitList) {
76 if (p.pkt->getAddr() == addr)
77 return true;
78 }
79 return false;
80}
81
82bool
70PacketQueue::checkFunctional(PacketPtr pkt)
71{
72 pkt->pushLabel(label);
73
74 auto i = transmitList.begin();
75 bool found = false;
76
77 while (!found && i != transmitList.end()) {

--- 4 unchanged lines hidden (view full) ---

82 }
83
84 pkt->popLabel();
85
86 return found;
87}
88
89void
83PacketQueue::checkFunctional(PacketPtr pkt)
84{
85 pkt->pushLabel(label);
86
87 auto i = transmitList.begin();
88 bool found = false;
89
90 while (!found && i != transmitList.end()) {

--- 4 unchanged lines hidden (view full) ---

95 }
96
97 pkt->popLabel();
98
99 return found;
100}
101
102void
90PacketQueue::schedSendEvent(Tick when)
103PacketQueue::schedSendTiming(PacketPtr pkt, Tick when)
91{
104{
92 // if we are waiting on a retry, do not schedule a send event, and
93 // instead rely on retry being called
94 if (waitingOnRetry) {
95 assert(!sendEvent.scheduled());
96 return;
97 }
98
99 if (!sendEvent.scheduled()) {
100 em.schedule(&sendEvent, when);
101 } else if (sendEvent.when() > when) {
102 em.reschedule(&sendEvent, when);
103 }
104}
105
106void
107PacketQueue::schedSendTiming(PacketPtr pkt, Tick when, bool send_as_snoop)
108{
109 DPRINTF(PacketQueue, "%s for %s address %x size %d\n", __func__,
110 pkt->cmdString(), pkt->getAddr(), pkt->getSize());
105 DPRINTF(PacketQueue, "%s for %s address %x size %d\n", __func__,
106 pkt->cmdString(), pkt->getAddr(), pkt->getSize());
107
111 // we can still send a packet before the end of this tick
112 assert(when >= curTick());
113
114 // express snoops should never be queued
115 assert(!pkt->isExpressSnoop());
116
117 // add a very basic sanity check on the port to ensure the
118 // invisible buffer is not growing beyond reasonable limits
119 if (transmitList.size() > 100) {
120 panic("Packet queue %s has grown beyond 100 packets\n",
121 name());
122 }
123
124 // nothing on the list, or earlier than current front element,
125 // schedule an event
126 if (transmitList.empty() || when < transmitList.front().tick) {
127 // note that currently we ignore a potentially outstanding retry
128 // and could in theory put a new packet at the head of the
129 // transmit list before retrying the existing packet
108 // we can still send a packet before the end of this tick
109 assert(when >= curTick());
110
111 // express snoops should never be queued
112 assert(!pkt->isExpressSnoop());
113
114 // add a very basic sanity check on the port to ensure the
115 // invisible buffer is not growing beyond reasonable limits
116 if (transmitList.size() > 100) {
117 panic("Packet queue %s has grown beyond 100 packets\n",
118 name());
119 }
120
121 // nothing on the list, or earlier than current front element,
122 // schedule an event
123 if (transmitList.empty() || when < transmitList.front().tick) {
124 // note that currently we ignore a potentially outstanding retry
125 // and could in theory put a new packet at the head of the
126 // transmit list before retrying the existing packet
130 transmitList.push_front(DeferredPacket(when, pkt, send_as_snoop));
127 transmitList.push_front(DeferredPacket(when, pkt));
131 schedSendEvent(when);
132 return;
133 }
134
128 schedSendEvent(when);
129 return;
130 }
131
132 // we should either have an outstanding retry, or a send event
133 // scheduled, but there is an unfortunate corner case where the
134 // x86 page-table walker and timing CPU send out a new request as
135 // part of the receiving of a response (called by
136 // PacketQueue::sendDeferredPacket), in which we end up calling
137 // ourselves again before we had a chance to update waitingOnRetry
138 // assert(waitingOnRetry || sendEvent.scheduled());
139
135 // list is non-empty and this belongs at the end
136 if (when >= transmitList.back().tick) {
140 // list is non-empty and this belongs at the end
141 if (when >= transmitList.back().tick) {
137 transmitList.push_back(DeferredPacket(when, pkt, send_as_snoop));
142 transmitList.push_back(DeferredPacket(when, pkt));
138 return;
139 }
140
141 // this belongs in the middle somewhere, insertion sort
142 auto i = transmitList.begin();
143 ++i; // already checked for insertion at front
144 while (i != transmitList.end() && when >= i->tick)
145 ++i;
143 return;
144 }
145
146 // this belongs in the middle somewhere, insertion sort
147 auto i = transmitList.begin();
148 ++i; // already checked for insertion at front
149 while (i != transmitList.end() && when >= i->tick)
150 ++i;
146 transmitList.insert(i, DeferredPacket(when, pkt, send_as_snoop));
151 transmitList.insert(i, DeferredPacket(when, pkt));
147}
148
152}
153
149void PacketQueue::trySendTiming()
154void
155PacketQueue::schedSendEvent(Tick when)
150{
156{
151 assert(deferredPacketReady());
152
153 DeferredPacket dp = transmitList.front();
154
155 // use the appropriate implementation of sendTiming based on the
156 // type of port associated with the queue, and whether the packet
157 // is to be sent as a snoop or not
158 waitingOnRetry = !sendTiming(dp.pkt, dp.sendAsSnoop);
159
160 if (!waitingOnRetry) {
161 // take the packet off the list
162 transmitList.pop_front();
157 // if we are waiting on a retry just hold off
158 if (waitingOnRetry) {
159 DPRINTF(PacketQueue, "Not scheduling send as waiting for retry\n");
160 assert(!sendEvent.scheduled());
161 return;
163 }
162 }
164}
165
163
166void
167PacketQueue::scheduleSend(Tick time)
168{
169 // the next ready time is either determined by the next deferred packet,
170 // or in the cache through the MSHR ready time
171 Tick nextReady = std::max(std::min(deferredPacketReadyTime(), time),
172 curTick() + 1);
164 if (when != MaxTick) {
165 // we cannot go back in time, and to be consistent we stick to
166 // one tick in the future
167 when = std::max(when, curTick() + 1);
168 // @todo Revisit the +1
173
169
174 if (nextReady != MaxTick) {
175 // if the sendTiming caused someone else to call our
176 // recvTiming we could already have an event scheduled, check
177 if (!sendEvent.scheduled()) {
170 if (!sendEvent.scheduled()) {
178 em.schedule(&sendEvent, nextReady);
179 } else if (nextReady < sendEvent.when()) {
171 em.schedule(&sendEvent, when);
172 } else if (when < sendEvent.when()) {
180 // if the new time is earlier than when the event
181 // currently is scheduled, move it forward
173 // if the new time is earlier than when the event
174 // currently is scheduled, move it forward
182 em.reschedule(&sendEvent, nextReady);
175 em.reschedule(&sendEvent, when);
183 }
184 } else {
176 }
177 } else {
185 // no more to send, so if we're draining, we may be done
178 // we get a MaxTick when there is no more to send, so if we're
179 // draining, we may be done at this point
186 if (drainManager && transmitList.empty() && !sendEvent.scheduled()) {
187 DPRINTF(Drain, "PacketQueue done draining,"
188 "processing drain event\n");
189 drainManager->signalDrainDone();
190 drainManager = NULL;
191 }
192 }
193}
194
195void
196PacketQueue::sendDeferredPacket()
197{
180 if (drainManager && transmitList.empty() && !sendEvent.scheduled()) {
181 DPRINTF(Drain, "PacketQueue done draining,"
182 "processing drain event\n");
183 drainManager->signalDrainDone();
184 drainManager = NULL;
185 }
186 }
187}
188
189void
190PacketQueue::sendDeferredPacket()
191{
198 // try to send what is on the list, this will set waitingOnRetry
199 // accordingly
200 trySendTiming();
192 // sanity checks
193 assert(!waitingOnRetry);
194 assert(deferredPacketReady());
201
195
196 DeferredPacket dp = transmitList.front();
197
198 // take the packet of the list before sending it, as sending of
199 // the packet in some cases causes a new packet to be enqueued
200 // (most notaly when responding to the timing CPU, leading to a
201 // new request hitting in the L1 icache, leading to a new
202 // response)
203 transmitList.pop_front();
204
205 // use the appropriate implementation of sendTiming based on the
206 // type of queue
207 waitingOnRetry = !sendTiming(dp.pkt);
208
202 // if we succeeded and are not waiting for a retry, schedule the
203 // next send
204 if (!waitingOnRetry) {
209 // if we succeeded and are not waiting for a retry, schedule the
210 // next send
211 if (!waitingOnRetry) {
205 scheduleSend();
212 schedSendEvent(deferredPacketReadyTime());
213 } else {
214 // put the packet back at the front of the list
215 transmitList.push_front(dp);
206 }
207}
208
209void
210PacketQueue::processSendEvent()
211{
212 assert(!waitingOnRetry);
213 sendDeferredPacket();

--- 4 unchanged lines hidden (view full) ---

218{
219 if (transmitList.empty())
220 return 0;
221 DPRINTF(Drain, "PacketQueue not drained\n");
222 drainManager = dm;
223 return 1;
224}
225
216 }
217}
218
219void
220PacketQueue::processSendEvent()
221{
222 assert(!waitingOnRetry);
223 sendDeferredPacket();

--- 4 unchanged lines hidden (view full) ---

228{
229 if (transmitList.empty())
230 return 0;
231 DPRINTF(Drain, "PacketQueue not drained\n");
232 drainManager = dm;
233 return 1;
234}
235
226MasterPacketQueue::MasterPacketQueue(EventManager& _em, MasterPort& _masterPort,
227 const std::string _label)
236ReqPacketQueue::ReqPacketQueue(EventManager& _em, MasterPort& _masterPort,
237 const std::string _label)
228 : PacketQueue(_em, _label), masterPort(_masterPort)
229{
230}
231
232bool
238 : PacketQueue(_em, _label), masterPort(_masterPort)
239{
240}
241
242bool
233MasterPacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
243ReqPacketQueue::sendTiming(PacketPtr pkt)
234{
244{
235 // attempt to send the packet and return according to the outcome
236 if (!send_as_snoop)
237 return masterPort.sendTimingReq(pkt);
238 else
239 return masterPort.sendTimingSnoopResp(pkt);
245 return masterPort.sendTimingReq(pkt);
240}
241
246}
247
242SlavePacketQueue::SlavePacketQueue(EventManager& _em, SlavePort& _slavePort,
243 const std::string _label)
248SnoopRespPacketQueue::SnoopRespPacketQueue(EventManager& _em,
249 MasterPort& _masterPort,
250 const std::string _label)
251 : PacketQueue(_em, _label), masterPort(_masterPort)
252{
253}
254
255bool
256SnoopRespPacketQueue::sendTiming(PacketPtr pkt)
257{
258 return masterPort.sendTimingSnoopResp(pkt);
259}
260
261RespPacketQueue::RespPacketQueue(EventManager& _em, SlavePort& _slavePort,
262 const std::string _label)
244 : PacketQueue(_em, _label), slavePort(_slavePort)
245{
246}
247
248bool
263 : PacketQueue(_em, _label), slavePort(_slavePort)
264{
265}
266
267bool
249SlavePacketQueue::sendTiming(PacketPtr pkt, bool send_as_snoop)
268RespPacketQueue::sendTiming(PacketPtr pkt)
250{
269{
251 // we should never have queued snoop requests
252 assert(!send_as_snoop);
253 return slavePort.sendTimingResp(pkt);
254}
270 return slavePort.sendTimingResp(pkt);
271}