wlan_bearer/wlanldd/wlan_common/umac_common/src/umacpacketscheduler.cpp
changeset 0 c40eb8fe8501
equal deleted inserted replaced
-1:000000000000 0:c40eb8fe8501
       
     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     }