|
1 /* |
|
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: The one and only packet scheduler |
|
15 * |
|
16 */ |
|
17 |
|
18 /* |
|
19 * %version: 28 % |
|
20 */ |
|
21 |
|
22 #include "config.h" |
|
23 #include "umacpacketscheduler.h" |
|
24 #include "umacpacketschedulerclient.h" |
|
25 #include "UmacContextImpl.h" |
|
26 |
|
27 |
|
28 // ======== MEMBER FUNCTIONS ======== |
|
29 |
|
30 // --------------------------------------------------------------------------- |
|
31 // |
|
32 // --------------------------------------------------------------------------- |
|
33 // |
|
34 WlanPacketScheduler::WlanPacketScheduler( |
|
35 MWlanPacketSchedulerClient& aWlanPacketSchedulerClient ) |
|
36 : iPacketSchedulerClient(aWlanPacketSchedulerClient), |
|
37 iCurrent( NULL ), |
|
38 iTxPipelineActive( ETrue ), |
|
39 iNumOfPackets( 0 ), |
|
40 iNumOfNotCompletedPackets( 0 ), |
|
41 iFlags( 0 ) |
|
42 { |
|
43 // initially mark all as free |
|
44 for ( TPacketIdCntxs::iterator pos = iPacketIdCntxs.begin() |
|
45 ; pos != iPacketIdCntxs.end() ; ++pos ) |
|
46 { |
|
47 pos->iFree = ETrue; |
|
48 } |
|
49 // initially mark all as free |
|
50 for ( TPacketElements::iterator pos = iPacketElements.begin() |
|
51 ; pos != iPacketElements.end() ; ++pos ) |
|
52 { |
|
53 pos->iFree = ETrue; |
|
54 } |
|
55 // initially mark all as free |
|
56 fill( iQueueStates.begin(), iQueueStates.end(), EQueueNotFull ); |
|
57 } |
|
58 |
|
59 // --------------------------------------------------------------------------- |
|
60 // |
|
61 // --------------------------------------------------------------------------- |
|
62 // |
|
63 TBool WlanPacketScheduler::Push( |
|
64 WlanContextImpl& aCtxImpl, |
|
65 const TAny* aPacket, |
|
66 TUint32 aLength, |
|
67 WHA::TQueueId aQueueId, |
|
68 TUint32 aPacketId, |
|
69 const TDataBuffer* aMetaHeader, |
|
70 TBool aMore, |
|
71 TBool aMulticastData, |
|
72 TBool aUseSpecialRatePolicy ) |
|
73 { |
|
74 OsTracePrint( KPacketScheduler, (TUint8*) |
|
75 ("UMAC: WlanPacketScheduler::Push: aMulticastData: %d"), |
|
76 aMulticastData ); |
|
77 |
|
78 SElement* free_slot = FreeElementSlot(); |
|
79 if ( !free_slot ) |
|
80 { |
|
81 // no free element slot was found, |
|
82 // which means that all slots are in use |
|
83 // we do nothing else than silently fail the operation |
|
84 OsTracePrint( KPacketScheduler | KWarningLevel, (TUint8*) |
|
85 ("UMAC: packetscheduler Push: no free slot found -> fail") ); |
|
86 |
|
87 // packet push failure we must signal |
|
88 // set up a flag to signal client at later time to retry |
|
89 // this operation |
|
90 iFlags |= KSignalPushPacket; |
|
91 |
|
92 return EFalse; |
|
93 } |
|
94 |
|
95 // one more packet to schedule |
|
96 ++iNumOfPackets; |
|
97 |
|
98 // store packet send context |
|
99 free_slot->iFree = EFalse; // context is no longer free |
|
100 free_slot->iPacket = aPacket; |
|
101 free_slot->iLength = aLength; |
|
102 |
|
103 // extract a free packet ID context |
|
104 SPacketIdCntx* packet_id_cnxt = FreePacketIdCntx(); |
|
105 if ( !packet_id_cnxt ) |
|
106 { |
|
107 // no free element was found |
|
108 // we should allways enough of elements available |
|
109 // so this issue means that we have either: |
|
110 // 1) programming error |
|
111 // 2) too small element storage |
|
112 // in any case the issue must be solved at compile time not runtime |
|
113 OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ ); |
|
114 return EFalse; |
|
115 } |
|
116 |
|
117 ++iNumOfNotCompletedPackets; |
|
118 OsTracePrint( KPacketScheduler, (TUint8*) |
|
119 ("UMAC: WlanPacketScheduler::Push: the nbr of packets not yet completed by WHA layer is now: %d"), |
|
120 iNumOfNotCompletedPackets ); |
|
121 |
|
122 // store packet ID context |
|
123 packet_id_cnxt->iQueueId = aQueueId; |
|
124 packet_id_cnxt->iFrameId = aPacketId; |
|
125 packet_id_cnxt->iMetaHeader = aMetaHeader; |
|
126 packet_id_cnxt->iFree = EFalse; // this id is no longer free |
|
127 packet_id_cnxt->iMulticastData = aMulticastData; |
|
128 packet_id_cnxt->iUseSpecialRatePolicy = aUseSpecialRatePolicy; |
|
129 |
|
130 // link packet element to packet id context |
|
131 free_slot->iPacketIdCntx = packet_id_cnxt; |
|
132 |
|
133 if ( iCurrent ) |
|
134 { |
|
135 if ( iTxPipelineActive ) |
|
136 { |
|
137 // it is not logical to have a valid current pointer |
|
138 // when the tx pipeline is active |
|
139 OsAssert( (TUint8*)("UMAC * panic"), |
|
140 (TUint8*)(WLAN_FILE), __LINE__ ); |
|
141 } |
|
142 |
|
143 // we have a existing current pointer |
|
144 // it means that the tx pipeline is stopped |
|
145 // lets see if the pushed packet has a |
|
146 // queue full status and proceed from that |
|
147 |
|
148 if ( iQueueStates[packet_id_cnxt->iQueueId] == EQueueNotFull ) |
|
149 { |
|
150 // as the pushed packet goes to non full queue let's |
|
151 // set the one with highest priority as the current packet to send |
|
152 if ( Priority( packet_id_cnxt->iQueueId ) > |
|
153 Priority( iCurrent->iPacketIdCntx->iQueueId ) ) |
|
154 { |
|
155 iCurrent = free_slot; |
|
156 } |
|
157 else |
|
158 { |
|
159 // no action |
|
160 } |
|
161 } |
|
162 else // --- != EQueueNotFull --- |
|
163 { |
|
164 // pushed packet queue is full -> no action |
|
165 OsTracePrint( |
|
166 KPacketScheduler, (TUint8*) |
|
167 ("UMAC: WlanPacketScheduler::Push: queue for the pushed packet is full, queue id: %d"), |
|
168 packet_id_cnxt->iQueueId ); |
|
169 } |
|
170 } |
|
171 else // --- iCurrent --- |
|
172 { |
|
173 // we do not have a valid current pointer, which means that all |
|
174 // the packets pending inside the scheduler have a queue full status |
|
175 // tough luck, but we can live with it... |
|
176 if ( iQueueStates[packet_id_cnxt->iQueueId] == EQueueNotFull ) |
|
177 { |
|
178 // the pushed packet queue is not full queue |
|
179 // so we shall mark it as the current one |
|
180 iCurrent = free_slot; |
|
181 } |
|
182 } |
|
183 |
|
184 if ( iTxPipelineActive && iCurrent ) |
|
185 { |
|
186 // packet scheduling feasible |
|
187 // as tx pipeline is active and we have a current packet to be send |
|
188 iPacketSchedulerClient.CallPacketSchedule( aCtxImpl, aMore ); |
|
189 } |
|
190 |
|
191 if ( |
|
192 // push packet signalling to client flagged |
|
193 iFlags & KSignalPushPacket |
|
194 // AND |
|
195 && |
|
196 // packet scheduler is not full |
|
197 !Full() ) |
|
198 { |
|
199 iFlags &= ~KSignalPushPacket; |
|
200 iPacketSchedulerClient.OnPacketPushPossible( aCtxImpl ); |
|
201 } |
|
202 |
|
203 return ETrue; |
|
204 } |
|
205 |
|
206 // --------------------------------------------------------------------------- |
|
207 // make internal state as empty |
|
208 // --------------------------------------------------------------------------- |
|
209 // |
|
210 void WlanPacketScheduler::Flush( WlanContextImpl& aCtxImpl ) |
|
211 { |
|
212 // remove all pending packet transmission entrys |
|
213 // and call correct completion method for user plane packets |
|
214 OsTracePrint( |
|
215 KPacketScheduler, |
|
216 (TUint8*)("UMAC: WlanPacketScheduler::Flush") ); |
|
217 |
|
218 for ( TPacketElements::iterator pos = iPacketElements.begin(); |
|
219 pos != iPacketElements.end(); |
|
220 ++pos ) |
|
221 { |
|
222 if ( pos->iFree == EFalse ) |
|
223 // slot in use -> complete the packet and release the slot |
|
224 { |
|
225 pos->iFree = ETrue; |
|
226 iPacketSchedulerClient.OnPacketFlushEvent( |
|
227 aCtxImpl, |
|
228 pos->iPacketIdCntx->iFrameId, |
|
229 const_cast<TDataBuffer*>(pos->iPacketIdCntx->iMetaHeader) ); |
|
230 |
|
231 // as we won't be getting a packet tx completion for this packet |
|
232 // mark also the corresponding packet context free |
|
233 pos->iPacketIdCntx->iFree = ETrue; |
|
234 --iNumOfNotCompletedPackets; |
|
235 } |
|
236 } |
|
237 |
|
238 // NOTE: we do not clear other packet ID contexts as there can be pending |
|
239 // packet transmissions, which means we should get packet transmission |
|
240 // callbacks and we must map the context then |
|
241 |
|
242 iCurrent = NULL; |
|
243 iNumOfPackets = 0; |
|
244 } |
|
245 |
|
246 // --------------------------------------------------------------------------- |
|
247 // |
|
248 // --------------------------------------------------------------------------- |
|
249 // |
|
250 void WlanPacketScheduler::SchedulePackets( |
|
251 WlanContextImpl& aCtxImpl, |
|
252 TBool aMore ) |
|
253 { |
|
254 if ( !(iTxPipelineActive && iCurrent) ) |
|
255 { |
|
256 // nothing to do |
|
257 return; |
|
258 } |
|
259 |
|
260 typedef |
|
261 Carray< |
|
262 SPacketIdCntx*, |
|
263 KNumOfElements, |
|
264 EFalse, // no delete pointees |
|
265 NoCopy<SPacketIdCntx*> // disallow copying |
|
266 > TPacketIdCntxsPtrs; |
|
267 |
|
268 // this critter stores the xferred packet id contexes in case of |
|
269 // synchronous xfer occurs and we must manullay call |
|
270 // completion method for the frame ids |
|
271 TPacketIdCntxsPtrs packetid_cntxs; |
|
272 TPacketIdCntxsPtrs::iterator pos( packetid_cntxs.begin() ); |
|
273 |
|
274 WHA::TStatus status ( WHA::KSuccess ); |
|
275 |
|
276 // send all packets that are feasible for sending |
|
277 // as long as the adpatation layer does not stop |
|
278 // the tx pipeline |
|
279 do |
|
280 { |
|
281 // store current packet id context |
|
282 *pos = iCurrent->iPacketIdCntx; |
|
283 |
|
284 |
|
285 // trace the frame critter |
|
286 OsTracePrint( KPacketScheduler, |
|
287 (TUint8*)("UMAC: scheduling dot11 packet for tx"), |
|
288 *(reinterpret_cast<const Sdot11MacHeader*>(iCurrent->iPacket)) ); |
|
289 OsTracePrint( KPacketScheduler, (TUint8*) |
|
290 ("UMAC: WlanPacketScheduler::SchedulePackets: queue ID: %d"), |
|
291 (*pos)->iQueueId ); |
|
292 OsTracePrint( KPacketScheduler, (TUint8*) |
|
293 ("UMAC: WlanPacketScheduler::SchedulePackets: frame ID: %d"), |
|
294 (*pos)->iFrameId ); |
|
295 OsTracePrint( KPacketScheduler, |
|
296 (TUint8*)("UMAC: WlanPacketScheduler::SchedulePackets: packet id: 0x%08x"), |
|
297 reinterpret_cast<WHA::TPacketId>(*pos) ); |
|
298 |
|
299 // are multiple packets ready for sending in the same context |
|
300 TBool morePackets ( aMore || MultipleReadyPacketsPending() ); |
|
301 |
|
302 OsTracePrint( KPacketScheduler, (TUint8*) |
|
303 ("UMAC: WlanPacketScheduler::SchedulePackets: more: %d"), |
|
304 morePackets ); |
|
305 |
|
306 // determine and store the current Tx rate & rate policy to be used |
|
307 // with the Tx queue in question |
|
308 // |
|
309 TUint8 txPolicyId ( 0 ); |
|
310 aCtxImpl.TxRatePolicy( |
|
311 iCurrent->iPacketIdCntx->iQueueId, |
|
312 iCurrent->iPacketIdCntx->iUseSpecialRatePolicy, |
|
313 iCurrent->iPacketIdCntx->iRequestedTxRate, |
|
314 txPolicyId ); |
|
315 |
|
316 OsTracePrint( KPacketScheduler, (TUint8*) |
|
317 ("UMAC: WlanPacketScheduler::SchedulePackets: txRate: 0x%08x"), |
|
318 iCurrent->iPacketIdCntx->iRequestedTxRate ); |
|
319 OsTracePrint( KPacketScheduler, (TUint8*) |
|
320 ("UMAC: WlanPacketScheduler::SchedulePackets: txPolicyId: %d"), |
|
321 txPolicyId ); |
|
322 |
|
323 const TUint8 KSizeOfTuint32 ( sizeof( TUint32 ) ); |
|
324 const TUint8 KOffBy ( |
|
325 reinterpret_cast<TUint32>(iCurrent->iPacket) % KSizeOfTuint32 ); |
|
326 |
|
327 if ( KOffBy ) |
|
328 { |
|
329 // The frame start address is not 32 bit aligned. This can |
|
330 // happen e.g. if the frame was left pending during |
|
331 // roaming, and we roamed from a non-QoS nw to a QoS nw, or vice |
|
332 // versa. That makes the alignment to be off by 2 bytes. The only |
|
333 // way to get the start address correctly aligned is to copy the |
|
334 // whole frame. Note, that we always leave enough empty space at |
|
335 // the end of the frame buffer to enable this |
|
336 OsTracePrint( KWsaTxDetails, (TUint8*) |
|
337 ("UMAC: WlanPacketScheduler::SchedulePackets: Frame start address 0x%08x not aligned; fixing it"), |
|
338 reinterpret_cast<TUint32>(iCurrent->iPacket) ); |
|
339 os_memcpy( |
|
340 reinterpret_cast<TUint8*>( |
|
341 const_cast<TAny*>(iCurrent->iPacket)) + |
|
342 ( KSizeOfTuint32 - KOffBy ), |
|
343 reinterpret_cast<const TUint8*>(iCurrent->iPacket), |
|
344 iCurrent->iLength ); |
|
345 |
|
346 iCurrent->iPacket = |
|
347 reinterpret_cast<const TUint8*>(iCurrent->iPacket) + |
|
348 ( KSizeOfTuint32 - KOffBy ); |
|
349 |
|
350 OsTracePrint( KWsaTxDetails, (TUint8*) |
|
351 ("UMAC: WlanPacketScheduler::SchedulePackets: New frame start address: 0x%08x"), |
|
352 reinterpret_cast<TUint32>(iCurrent->iPacket) ); |
|
353 } |
|
354 |
|
355 status = aCtxImpl.Wha().SendPacket( |
|
356 iCurrent->iPacket, |
|
357 iCurrent->iLength, |
|
358 iCurrent->iPacketIdCntx->iQueueId, |
|
359 txPolicyId, |
|
360 // note that this value is not relevant when autonomous rate |
|
361 // adaptation is being used |
|
362 iCurrent->iPacketIdCntx->iRequestedTxRate, |
|
363 morePackets, |
|
364 // packet id passed is used as an act to a complex type |
|
365 reinterpret_cast<WHA::TPacketId>(*pos), |
|
366 aCtxImpl.iWlanMib.dot11CurrentTxPowerLevel, |
|
367 aCtxImpl.iWlanMib.dot11MaxTransmitMSDULifetime[ |
|
368 iCurrent->iPacketIdCntx->iQueueId], |
|
369 NULL ); |
|
370 |
|
371 // store current time in packet context |
|
372 iCurrent->iPacketIdCntx->iSendReqTimeStamp = os_systemTime(); |
|
373 |
|
374 ++pos; // next free slot |
|
375 // for the possible following frame submissions within this Tx loop we |
|
376 // cannot use this indication of more frames in UMAC adaptation any more |
|
377 // as it is valid only for the first submission |
|
378 aMore = EFalse; |
|
379 |
|
380 OsTracePrint( |
|
381 KPacketScheduler, |
|
382 (TUint8*)("UMAC: WlanPacketScheduler::SchedulePackets: SendPacket status: %d"), |
|
383 status); |
|
384 |
|
385 if ( status == WHA::KPending ) |
|
386 { |
|
387 // stop the tx pipeline |
|
388 StopTxPipeLine(); |
|
389 // packet was accepted for delivery |
|
390 --iNumOfPackets; |
|
391 iCurrent->iFree = ETrue; // mark as free |
|
392 } |
|
393 else if ( status == WHA::KQueueFull ) |
|
394 { |
|
395 OsTracePrint( |
|
396 KPacketScheduler, (TUint8*) |
|
397 ("UMAC: WlanPacketScheduler::SchedulePackets: queue for the current packet is full, queue id: %d"), |
|
398 iCurrent->iPacketIdCntx->iQueueId ); |
|
399 |
|
400 // packet was discarded |
|
401 // we may schedule from another queue |
|
402 // this is done automatically as we are executing a loop |
|
403 TranmsitQueueFull( iCurrent->iPacketIdCntx->iQueueId ); |
|
404 |
|
405 // do not clear context as this packet needs to be resend |
|
406 // at some point |
|
407 } |
|
408 else if ( status == WHA::KSuccessXfer ) |
|
409 { |
|
410 // synchronous xfer occurred and no packet transfer |
|
411 // method gets called for the packets send in this context, |
|
412 // which means that we must manually call completion method |
|
413 // for all of those packets |
|
414 --iNumOfPackets; // packet was accepted for delivery |
|
415 iCurrent->iFree = ETrue; // mark as free |
|
416 |
|
417 // call completion method for all stacked packet id contexes |
|
418 // as they are part of a synchronous xfer |
|
419 for ( TPacketIdCntxsPtrs::iterator beg |
|
420 = packetid_cntxs.begin() |
|
421 ; beg != pos |
|
422 ; ++beg ) |
|
423 { |
|
424 iPacketSchedulerClient.OnPacketTransferComplete( |
|
425 aCtxImpl, |
|
426 (*beg)->iFrameId, |
|
427 const_cast<TDataBuffer*>((*beg)->iMetaHeader) ); |
|
428 } |
|
429 |
|
430 // now as all have been handled |
|
431 // clear the stack by resetting the position |
|
432 // to begin of the buffer |
|
433 pos = packetid_cntxs.begin(); |
|
434 } |
|
435 else if ( status == WHA::KSuccess ) |
|
436 { |
|
437 // this is the success scenario |
|
438 --iNumOfPackets; // packet was accepted for delivery |
|
439 iCurrent->iFree = ETrue; // mark as free |
|
440 } |
|
441 else if ( status == WHA::KSuccessQueueFull ) |
|
442 { |
|
443 // packet was accepted |
|
444 --iNumOfPackets; |
|
445 // ... but the destination queue is now full |
|
446 TranmsitQueueFull( iCurrent->iPacketIdCntx->iQueueId ); |
|
447 // we may schedule from another queue |
|
448 // this is done automatically as we are executing a loop |
|
449 |
|
450 iCurrent->iFree = ETrue; // mark as free |
|
451 } |
|
452 else |
|
453 { |
|
454 // adaptation programming error |
|
455 OsAssert( (TUint8*)("UMAC: panic"), (TUint8*)(WLAN_FILE), __LINE__ ); |
|
456 } |
|
457 |
|
458 // select new current packet that is to be transferred, |
|
459 // if such exists |
|
460 SetNextCurrent(); |
|
461 |
|
462 // stop packet sending if tx pipeleline is stopped or there |
|
463 // is no current packet to be xferred |
|
464 } while ( iCurrent && iTxPipelineActive ); |
|
465 } |
|
466 |
|
467 // --------------------------------------------------------------------------- |
|
468 // |
|
469 // --------------------------------------------------------------------------- |
|
470 // |
|
471 void WlanPacketScheduler::SendPacketTransfer( |
|
472 WlanContextImpl& aCtxImpl, |
|
473 WHA::TPacketId aPacketId ) |
|
474 { |
|
475 OsTracePrint( |
|
476 KPacketScheduler, (TUint8*) |
|
477 ("UMAC: WlanPacketScheduler::SendPacketTransfer: packet id: 0x%08x"), |
|
478 aPacketId); |
|
479 |
|
480 // tx pipeline is always activated by this method |
|
481 StartTxPipeLine(); |
|
482 |
|
483 if ( iCurrent ) |
|
484 { |
|
485 // current packet to be xferred exists |
|
486 // notify the client code of this |
|
487 iPacketSchedulerClient.CallPacketSchedule( aCtxImpl, EFalse ); |
|
488 } |
|
489 |
|
490 // call packet transfer completion method, |
|
491 // with client supplied frame id |
|
492 const SPacketIdCntx* packet_id_cnxt |
|
493 = reinterpret_cast<const SPacketIdCntx*>(aPacketId); |
|
494 iPacketSchedulerClient.OnPacketTransferComplete( |
|
495 aCtxImpl, |
|
496 packet_id_cnxt->iFrameId, |
|
497 const_cast<TDataBuffer*>(packet_id_cnxt->iMetaHeader) ); |
|
498 |
|
499 if ( // push packet signaling to client flagged |
|
500 iFlags & KSignalPushPacket |
|
501 // AND |
|
502 && |
|
503 // packet scheduler is not full |
|
504 !Full() ) |
|
505 { |
|
506 iFlags &= ~KSignalPushPacket; |
|
507 iPacketSchedulerClient.OnPacketPushPossible( aCtxImpl ); |
|
508 } |
|
509 |
|
510 if ( // someone is waiting for internal Tx buffer to become available |
|
511 aCtxImpl.InternalTxBufBeingWaited() |
|
512 // AND |
|
513 && |
|
514 // packet scheduler still is not full |
|
515 !Full() ) |
|
516 { |
|
517 aCtxImpl.ClearInternalTxBufBeingWaitedFlag(); |
|
518 iPacketSchedulerClient.OnPacketPushPossible( aCtxImpl ); |
|
519 } |
|
520 } |
|
521 |
|
522 // --------------------------------------------------------------------------- |
|
523 // |
|
524 // --------------------------------------------------------------------------- |
|
525 // |
|
526 void WlanPacketScheduler::SendPacketComplete( |
|
527 WlanContextImpl& aCtxImpl, |
|
528 WHA::TStatus aStatus, |
|
529 WHA::TPacketId aPacketId, |
|
530 WHA::TRate aRate, |
|
531 TUint32 aPacketQueueDelay, |
|
532 TUint32 aMediaDelay, |
|
533 TUint8 aAckFailures ) |
|
534 { |
|
535 OsTracePrint( KPacketScheduler, (TUint8*) |
|
536 ("UMAC: WlanPacketScheduler::SendPacketComplete: packet id: 0x%08x"), |
|
537 aPacketId); |
|
538 |
|
539 // determine the packet context related to this frame |
|
540 SPacketIdCntx* packet_id_cnxt |
|
541 = reinterpret_cast<SPacketIdCntx*>(aPacketId); |
|
542 |
|
543 // calculate Total Tx Delay for this frame. |
|
544 // Using the TUint type for the result is safe |
|
545 const TUint totalTxDelay = |
|
546 os_systemTime() - |
|
547 packet_id_cnxt->iSendReqTimeStamp; |
|
548 |
|
549 // as packet has been processed from device transmit queue |
|
550 // mark that queue as not full |
|
551 iQueueStates[packet_id_cnxt->iQueueId] = EQueueNotFull; |
|
552 |
|
553 // note the queue via which the packet was transmitted |
|
554 const WHA::TQueueId queueId ( packet_id_cnxt->iQueueId ); |
|
555 |
|
556 // note the originally requested Tx rate |
|
557 const WHA::TRate requestedTxRate( packet_id_cnxt->iRequestedTxRate ); |
|
558 |
|
559 // this context can now be reused |
|
560 packet_id_cnxt->iFree = ETrue; |
|
561 --iNumOfNotCompletedPackets; |
|
562 |
|
563 OsTracePrint( KPacketScheduler, (TUint8*) |
|
564 ("UMAC: WlanPacketScheduler::SendPacketComplete: the nbr of packets not yet completed by WHA layer is now: %d"), |
|
565 iNumOfNotCompletedPackets ); |
|
566 |
|
567 // adjust current packet pointer if needed |
|
568 SetCurrentPacket( *packet_id_cnxt ); |
|
569 |
|
570 if ( iTxPipelineActive && iCurrent ) |
|
571 { |
|
572 // packet scheduling feasible |
|
573 // as tx pipeline is active and we have a current packet to be sent |
|
574 iPacketSchedulerClient.CallPacketSchedule( aCtxImpl, EFalse ); |
|
575 } |
|
576 |
|
577 // notify client of event |
|
578 iPacketSchedulerClient.OnPacketSendComplete( |
|
579 aCtxImpl, |
|
580 aStatus, |
|
581 packet_id_cnxt->iFrameId, |
|
582 aRate, |
|
583 aPacketQueueDelay, |
|
584 aMediaDelay, |
|
585 totalTxDelay, |
|
586 aAckFailures, |
|
587 queueId, |
|
588 requestedTxRate, |
|
589 packet_id_cnxt->iMulticastData ); |
|
590 |
|
591 if ( |
|
592 // push packet signalling to client flagged |
|
593 iFlags & KSignalPushPacket |
|
594 // AND |
|
595 && |
|
596 // packet scheduler is not full |
|
597 !Full() ) |
|
598 { |
|
599 iFlags &= ~KSignalPushPacket; |
|
600 iPacketSchedulerClient.OnPacketPushPossible( aCtxImpl ); |
|
601 } |
|
602 } |
|
603 |
|
604 // --------------------------------------------------------------------------- |
|
605 // |
|
606 // --------------------------------------------------------------------------- |
|
607 // |
|
608 TBool WlanPacketScheduler::GetWhaTxStatus( |
|
609 const WlanContextImpl& aCtxImpl, |
|
610 TWhaTxQueueState& aTxQueueState ) const |
|
611 { |
|
612 if ( aCtxImpl.QosEnabled() ) |
|
613 { |
|
614 for ( TUint queueId = 0; queueId < EQueueIdMax; ++queueId ) |
|
615 { |
|
616 aTxQueueState[queueId] = |
|
617 static_cast<TTxQueueState>(iQueueStates[queueId]); |
|
618 } |
|
619 } |
|
620 else |
|
621 { |
|
622 for ( TUint queueId = 0; queueId < EQueueIdMax; ++queueId ) |
|
623 { |
|
624 aTxQueueState[queueId] = |
|
625 static_cast<TTxQueueState>(iQueueStates[ELegacy]); |
|
626 } |
|
627 } |
|
628 |
|
629 return iTxPipelineActive; |
|
630 } |
|
631 |
|
632 // --------------------------------------------------------------------------- |
|
633 // check do we have more than the current packet ready for transmit |
|
634 // --------------------------------------------------------------------------- |
|
635 // |
|
636 TBool WlanPacketScheduler::MultipleReadyPacketsPending() |
|
637 { |
|
638 TUint32 cntr( 0 ); |
|
639 |
|
640 for ( TPacketElements::iterator pos = iPacketElements.begin() |
|
641 ; pos != iPacketElements.end() |
|
642 ; ++pos ) |
|
643 { |
|
644 if ( pos->iFree == EFalse ) |
|
645 // element in use |
|
646 { |
|
647 if ( iQueueStates[pos->iPacketIdCntx->iQueueId] == EQueueNotFull ) |
|
648 // and in non empty queue |
|
649 { |
|
650 if ( ++cntr > 1 ) |
|
651 // multiple entries found |
|
652 { |
|
653 OsTracePrint( KPacketScheduler, (TUint8*) |
|
654 ("UMAC: WlanPacketScheduler::MultipleReadyPacketsPending: multiple pending entries exist for non-full queue(s)") ); |
|
655 |
|
656 // terminate the loop |
|
657 break; |
|
658 } |
|
659 } |
|
660 } |
|
661 } |
|
662 |
|
663 return (cntr > 1); |
|
664 } |
|
665 |
|
666 // --------------------------------------------------------------------------- |
|
667 // select new current packet to be transmitted if one exists |
|
668 // --------------------------------------------------------------------------- |
|
669 // |
|
670 void WlanPacketScheduler::SetNextCurrent() |
|
671 { |
|
672 // no current exist as we setting a new one |
|
673 iCurrent = NULL; |
|
674 |
|
675 if ( !iNumOfPackets ) |
|
676 { |
|
677 // as no packets exist there can not be a current one |
|
678 return; |
|
679 } |
|
680 |
|
681 TPacketElements::iterator pos( iPacketElements.begin() ); |
|
682 TUint cntr( iNumOfPackets ); |
|
683 while ( cntr ) |
|
684 { |
|
685 // process max amount of packets |
|
686 // we have pending inside the scheduler |
|
687 if ( pos->iFree == EFalse ) |
|
688 { |
|
689 // element in use -> process it |
|
690 |
|
691 if ( iCurrent ) |
|
692 { |
|
693 // a current packet exists |
|
694 if ( |
|
695 // packet is in non full queue |
|
696 iQueueStates[pos->iPacketIdCntx->iQueueId] |
|
697 == EQueueNotFull |
|
698 // AND |
|
699 && |
|
700 // has higher prioty than the current packet |
|
701 ( Priority( pos->iPacketIdCntx->iQueueId ) |
|
702 > Priority( iCurrent->iPacketIdCntx->iQueueId ) ) ) |
|
703 { |
|
704 // which means it is the new current packet |
|
705 iCurrent = pos; |
|
706 } |
|
707 } |
|
708 else // --- iCurrent --- |
|
709 { |
|
710 // there is no current packet |
|
711 |
|
712 if ( |
|
713 // packet is in non full queue |
|
714 iQueueStates[pos->iPacketIdCntx->iQueueId] |
|
715 == EQueueNotFull ) |
|
716 { |
|
717 // which means it is the new current packet |
|
718 iCurrent = pos; |
|
719 } |
|
720 } |
|
721 |
|
722 --cntr; |
|
723 } |
|
724 ++pos; |
|
725 } |
|
726 } |
|
727 |
|
728 // --------------------------------------------------------------------------- |
|
729 // |
|
730 // --------------------------------------------------------------------------- |
|
731 // |
|
732 WlanPacketScheduler::SPacketIdCntx* WlanPacketScheduler::FreePacketIdCntx() |
|
733 { |
|
734 const TPacketIdCntxsPredicate unary_predicate; |
|
735 |
|
736 // find first free element |
|
737 SPacketIdCntx* pos |
|
738 = find_if( |
|
739 iPacketIdCntxs.begin(), |
|
740 iPacketIdCntxs.end(), |
|
741 unary_predicate ); |
|
742 |
|
743 return (pos != iPacketIdCntxs.end() ? pos : NULL); |
|
744 } |
|
745 |
|
746 // --------------------------------------------------------------------------- |
|
747 // |
|
748 // --------------------------------------------------------------------------- |
|
749 // |
|
750 WlanPacketScheduler::SElement* WlanPacketScheduler::FreeElementSlot() |
|
751 { |
|
752 const TElementPredicate unary_predicate; |
|
753 |
|
754 // find first free element |
|
755 SElement* pos |
|
756 = find_if( |
|
757 iPacketElements.begin(), |
|
758 iPacketElements.end(), |
|
759 unary_predicate ); |
|
760 |
|
761 return (pos != iPacketElements.end() ? pos : NULL); |
|
762 } |
|
763 |
|
764 // --------------------------------------------------------------------------- |
|
765 // |
|
766 // --------------------------------------------------------------------------- |
|
767 // |
|
768 void WlanPacketScheduler::SetCurrentPacket( |
|
769 const SPacketIdCntx& aCompletedCntx ) |
|
770 { |
|
771 TBool skip_current( EFalse ); |
|
772 |
|
773 if ( iCurrent ) |
|
774 { |
|
775 // current packet to be scheduled exists |
|
776 |
|
777 if ( Priority( iCurrent->iPacketIdCntx->iQueueId ) >= |
|
778 Priority( aCompletedCntx.iQueueId ) ) |
|
779 { |
|
780 // the current packet has at least equal priority as the |
|
781 // processed one, which means that there is no need |
|
782 // to adjust the current pointer |
|
783 |
|
784 // skip setting current |
|
785 skip_current = ETrue; |
|
786 } |
|
787 else |
|
788 { |
|
789 // processed packet has a higher priority as the current one, |
|
790 // which means that we have to check do we have packets in that |
|
791 // queue as the new current packet have to be set from those |
|
792 // packets (as they have higher priority) |
|
793 } |
|
794 } |
|
795 else // --- iCurrent --- |
|
796 { |
|
797 // there is no current packet, which means that we have to check do we |
|
798 // have packets in the same queue as the processed one |
|
799 // as the current packet have to be set from those |
|
800 // packets (if any exists) |
|
801 } |
|
802 |
|
803 // check and adjust if needed the current packet pointer |
|
804 // to point to the highest prioriy packet in non full transmit queue |
|
805 |
|
806 if ( skip_current == EFalse ) |
|
807 { |
|
808 TPacketElements::iterator pos( iPacketElements.begin() ); |
|
809 TUint cntr( iNumOfPackets ); |
|
810 while ( cntr ) |
|
811 { |
|
812 // process max amount of packets |
|
813 // we have pending inside the scheduler |
|
814 if ( pos->iFree == EFalse ) |
|
815 { |
|
816 // element in use -> process it |
|
817 if ( iCurrent ) |
|
818 { |
|
819 // a current packet exists |
|
820 |
|
821 if ( // packet is in non full queue |
|
822 iQueueStates[pos->iPacketIdCntx->iQueueId] |
|
823 == EQueueNotFull |
|
824 // AND |
|
825 && |
|
826 // has higher prioty than the current packet |
|
827 ( Priority( pos->iPacketIdCntx->iQueueId ) |
|
828 > Priority( iCurrent->iPacketIdCntx->iQueueId ) ) ) |
|
829 { |
|
830 // which means it is the new current packet |
|
831 iCurrent = pos; |
|
832 } |
|
833 } |
|
834 else // --- iCurrent --- |
|
835 { |
|
836 // there is no current packet |
|
837 if ( // packet is in non full queue |
|
838 iQueueStates[pos->iPacketIdCntx->iQueueId] |
|
839 == EQueueNotFull ) |
|
840 { |
|
841 // which means it is the new current packet |
|
842 iCurrent = pos; |
|
843 } |
|
844 } |
|
845 |
|
846 --cntr; |
|
847 } |
|
848 ++pos; |
|
849 } |
|
850 } |
|
851 } |