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} |