| /********************************************************************** |
| * LEAKYBUCKET.C |
| * This file contains the routines related to Leaky Bucket Algorithm. |
| ***********************************************************************/ |
| #include "headers.h" |
| |
| /********************************************************************* |
| * Function - UpdateTokenCount() |
| * |
| * Description - This function calculates the token count for each |
| * channel and updates the same in Adapter strucuture. |
| * |
| * Parameters - Adapter: Pointer to the Adapter structure. |
| * |
| * Returns - None |
| **********************************************************************/ |
| |
| static VOID UpdateTokenCount(register struct bcm_mini_adapter *Adapter) |
| { |
| ULONG liCurrentTime; |
| INT i = 0; |
| struct timeval tv; |
| |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "=====>\n"); |
| if(NULL == Adapter) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Adapter found NULL!\n"); |
| return; |
| } |
| |
| do_gettimeofday(&tv); |
| for(i = 0; i < NO_OF_QUEUES; i++) |
| { |
| if(TRUE == Adapter->PackInfo[i].bValid && |
| (1 == Adapter->PackInfo[i].ucDirection)) |
| { |
| liCurrentTime = ((tv.tv_sec- |
| Adapter->PackInfo[i].stLastUpdateTokenAt.tv_sec)*1000 + |
| (tv.tv_usec-Adapter->PackInfo[i].stLastUpdateTokenAt.tv_usec)/ |
| 1000); |
| if(0!=liCurrentTime) |
| { |
| Adapter->PackInfo[i].uiCurrentTokenCount += (ULONG) |
| ((Adapter->PackInfo[i].uiMaxAllowedRate) * |
| ((ULONG)((liCurrentTime)))/1000); |
| memcpy(&Adapter->PackInfo[i].stLastUpdateTokenAt, |
| &tv, sizeof(struct timeval)); |
| Adapter->PackInfo[i].liLastUpdateTokenAt = liCurrentTime; |
| if((Adapter->PackInfo[i].uiCurrentTokenCount) >= |
| Adapter->PackInfo[i].uiMaxBucketSize) |
| { |
| Adapter->PackInfo[i].uiCurrentTokenCount = |
| Adapter->PackInfo[i].uiMaxBucketSize; |
| } |
| } |
| } |
| } |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "<=====\n"); |
| return; |
| |
| } |
| |
| |
| /********************************************************************* |
| * Function - IsPacketAllowedForFlow() |
| * |
| * Description - This function checks whether the given packet from the |
| * specified queue can be allowed for transmission by |
| * checking the token count. |
| * |
| * Parameters - Adapter : Pointer to the Adpater structure. |
| * - iQIndex : The queue Identifier. |
| * - ulPacketLength: Number of bytes to be transmitted. |
| * |
| * Returns - The number of bytes allowed for transmission. |
| * |
| ***********************************************************************/ |
| static ULONG GetSFTokenCount(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>"); |
| /* Validate the parameters */ |
| if(NULL == Adapter || (psSF < Adapter->PackInfo && |
| (uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority])) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo)); |
| return 0; |
| } |
| |
| if(FALSE != psSF->bValid && psSF->ucDirection) |
| { |
| if(0 != psSF->uiCurrentTokenCount) |
| { |
| return psSF->uiCurrentTokenCount; |
| } |
| else |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n", |
| psSF-Adapter->PackInfo, psSF->uiCurrentTokenCount); |
| psSF->uiPendedLast = 1; |
| } |
| } |
| else |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo); |
| } |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <==="); |
| return 0; |
| } |
| |
| /** |
| @ingroup tx_functions |
| This function despatches packet from the specified queue. |
| @return Zero(success) or Negative value(failure) |
| */ |
| static INT SendPacketFromQueue(struct bcm_mini_adapter *Adapter,/**<Logical Adapter*/ |
| struct bcm_packet_info *psSF, /**<Queue identifier*/ |
| struct sk_buff* Packet) /**<Pointer to the packet to be sent*/ |
| { |
| INT Status=STATUS_FAILURE; |
| UINT uiIndex =0,PktLen = 0; |
| |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "=====>"); |
| if(!Adapter || !Packet || !psSF) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "Got NULL Adapter or Packet"); |
| return -EINVAL; |
| } |
| |
| if(psSF->liDrainCalculated==0) |
| { |
| psSF->liDrainCalculated = jiffies; |
| } |
| ///send the packet to the fifo.. |
| PktLen = Packet->len; |
| Status = SetupNextSend(Adapter, Packet, psSF->usVCID_Value); |
| if(Status == 0) |
| { |
| for(uiIndex = 0 ; uiIndex < MIBS_MAX_HIST_ENTRIES ; uiIndex++) |
| { if((PktLen <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) && (PktLen > MIBS_PKTSIZEHIST_RANGE*(uiIndex))) |
| Adapter->aTxPktSizeHist[uiIndex]++; |
| } |
| } |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "<====="); |
| return Status; |
| } |
| |
| /************************************************************************ |
| * Function - CheckAndSendPacketFromIndex() |
| * |
| * Description - This function dequeues the data/control packet from the |
| * specified queue for transmission. |
| * |
| * Parameters - Adapter : Pointer to the driver control structure. |
| * - iQIndex : The queue Identifier. |
| * |
| * Returns - None. |
| * |
| ****************************************************************************/ |
| static VOID CheckAndSendPacketFromIndex(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF) |
| { |
| struct sk_buff *QueuePacket=NULL; |
| char *pControlPacket = NULL; |
| INT Status=0; |
| int iPacketLen=0; |
| |
| |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo)); |
| if((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount))//Get data packet |
| { |
| if(!psSF->ucDirection ) |
| return; |
| |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount "); |
| if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode) |
| return; /* in idle mode */ |
| |
| // Check for Free Descriptors |
| if(atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " No Free Tx Descriptor(%d) is available for Data pkt..",atomic_read(&Adapter->CurrNumFreeTxDesc)); |
| return ; |
| } |
| |
| spin_lock_bh(&psSF->SFQueueLock); |
| QueuePacket=psSF->FirstTxQueue; |
| |
| if(QueuePacket) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Dequeuing Data Packet"); |
| |
| if(psSF->bEthCSSupport) |
| iPacketLen = QueuePacket->len; |
| else |
| iPacketLen = QueuePacket->len-ETH_HLEN; |
| |
| iPacketLen<<=3; |
| if(iPacketLen <= GetSFTokenCount(Adapter, psSF)) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Allowed bytes %d", |
| (iPacketLen >> 3)); |
| |
| DEQUEUEPACKET(psSF->FirstTxQueue,psSF->LastTxQueue); |
| psSF->uiCurrentBytesOnHost -= (QueuePacket->len); |
| psSF->uiCurrentPacketsOnHost--; |
| atomic_dec(&Adapter->TotalPacketCount); |
| spin_unlock_bh(&psSF->SFQueueLock); |
| |
| Status = SendPacketFromQueue(Adapter, psSF, QueuePacket); |
| psSF->uiPendedLast = FALSE; |
| } |
| else |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo); |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n", |
| psSF->uiCurrentTokenCount, iPacketLen); |
| //this part indicates that because of non-availability of the tokens |
| //pkt has not been send out hence setting the pending flag indicating the host to send it out |
| //first next iteration . |
| psSF->uiPendedLast = TRUE; |
| spin_unlock_bh(&psSF->SFQueueLock); |
| } |
| } |
| else |
| { |
| spin_unlock_bh(&psSF->SFQueueLock); |
| } |
| } |
| else |
| { |
| |
| if((atomic_read(&Adapter->CurrNumFreeTxDesc) > 0 ) && |
| (atomic_read(&Adapter->index_rd_txcntrlpkt) != |
| atomic_read(&Adapter->index_wr_txcntrlpkt)) |
| ) |
| { |
| pControlPacket = Adapter->txctlpacket |
| [(atomic_read(&Adapter->index_rd_txcntrlpkt)%MAX_CNTRL_PKTS)]; |
| if(pControlPacket) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Sending Control packet"); |
| Status = SendControlPacket(Adapter, pControlPacket); |
| if(STATUS_SUCCESS==Status) |
| { |
| spin_lock_bh(&psSF->SFQueueLock); |
| psSF->NumOfPacketsSent++; |
| psSF->uiSentBytes+=((struct bcm_leader *)pControlPacket)->PLength; |
| psSF->uiSentPackets++; |
| atomic_dec(&Adapter->TotalPacketCount); |
| psSF->uiCurrentBytesOnHost -= ((struct bcm_leader *)pControlPacket)->PLength; |
| psSF->uiCurrentPacketsOnHost--; |
| atomic_inc(&Adapter->index_rd_txcntrlpkt); |
| spin_unlock_bh(&psSF->SFQueueLock); |
| } |
| else |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "SendControlPacket Failed\n"); |
| } |
| else |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " Control Pkt is not available, Indexing is wrong...."); |
| } |
| } |
| } |
| } |
| |
| |
| /******************************************************************* |
| * Function - transmit_packets() |
| * |
| * Description - This function transmits the packets from different |
| * queues, if free descriptors are available on target. |
| * |
| * Parameters - Adapter: Pointer to the Adapter structure. |
| * |
| * Returns - None. |
| ********************************************************************/ |
| VOID transmit_packets(struct bcm_mini_adapter *Adapter) |
| { |
| UINT uiPrevTotalCount = 0; |
| int iIndex = 0; |
| |
| BOOLEAN exit_flag = TRUE ; |
| |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "=====>"); |
| |
| if(NULL == Adapter) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX,TX_PACKETS, DBG_LVL_ALL, "Got NULL Adapter"); |
| return; |
| } |
| if(Adapter->device_removed == TRUE) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device removed"); |
| return; |
| } |
| |
| BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nUpdateTokenCount ====>\n"); |
| |
| UpdateTokenCount(Adapter); |
| |
| BCM_DEBUG_PRINT (Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nPruneQueueAllSF ====>\n"); |
| |
| PruneQueueAllSF(Adapter); |
| |
| uiPrevTotalCount = atomic_read(&Adapter->TotalPacketCount); |
| |
| for(iIndex=HiPriority;iIndex>=0;iIndex--) |
| { |
| if( !uiPrevTotalCount || (TRUE == Adapter->device_removed)) |
| break; |
| |
| if(Adapter->PackInfo[iIndex].bValid && |
| Adapter->PackInfo[iIndex].uiPendedLast && |
| Adapter->PackInfo[iIndex].uiCurrentBytesOnHost) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex.."); |
| CheckAndSendPacketFromIndex(Adapter, &Adapter->PackInfo[iIndex]); |
| uiPrevTotalCount--; |
| } |
| } |
| |
| while(uiPrevTotalCount > 0 && !Adapter->device_removed) |
| { |
| exit_flag = TRUE ; |
| //second iteration to parse non-pending queues |
| for(iIndex=HiPriority;iIndex>=0;iIndex--) |
| { |
| if( !uiPrevTotalCount || (TRUE == Adapter->device_removed)) |
| break; |
| |
| if(Adapter->PackInfo[iIndex].bValid && |
| Adapter->PackInfo[iIndex].uiCurrentBytesOnHost && |
| !Adapter->PackInfo[iIndex].uiPendedLast ) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex.."); |
| CheckAndSendPacketFromIndex(Adapter, &Adapter->PackInfo[iIndex]); |
| uiPrevTotalCount--; |
| exit_flag = FALSE; |
| } |
| } |
| |
| if(Adapter->IdleMode || Adapter->bPreparingForLowPowerMode) |
| { |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "In Idle Mode\n"); |
| break; |
| } |
| if(exit_flag == TRUE ) |
| break ; |
| }/* end of inner while loop */ |
| |
| update_per_cid_rx (Adapter); |
| Adapter->txtransmit_running = 0; |
| BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======"); |
| } |