/********************************************************************** * LEAKYBUCKET.C * This file contains the routines related to Leaky Bucket Algorithm. ***********************************************************************/ #include "headers.h" /** * UpdateTokenCount() - Calculates the token count for each channel * and updates the same in Adapter structure * @Adapter: Pointer to the Adapter structure. * * Return: None */ static VOID UpdateTokenCount(register struct bcm_mini_adapter *Adapter) { ULONG liCurrentTime; INT i = 0; struct timeval tv; struct bcm_packet_info *curr_pi; 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++) { curr_pi = &Adapter->PackInfo[i]; if (TRUE == curr_pi->bValid && (1 == curr_pi->ucDirection)) { liCurrentTime = ((tv.tv_sec - curr_pi->stLastUpdateTokenAt.tv_sec)*1000 + (tv.tv_usec - curr_pi->stLastUpdateTokenAt.tv_usec) / 1000); if (0 != liCurrentTime) { curr_pi->uiCurrentTokenCount += (ULONG) ((curr_pi->uiMaxAllowedRate) * ((ULONG)((liCurrentTime)))/1000); memcpy(&curr_pi->stLastUpdateTokenAt, &tv, sizeof(struct timeval)); curr_pi->liLastUpdateTokenAt = liCurrentTime; if (curr_pi->uiCurrentTokenCount >= curr_pi->uiMaxBucketSize) { curr_pi->uiCurrentTokenCount = curr_pi->uiMaxBucketSize; } } } } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "<=====\n"); } /** * IsPacketAllowedForFlow() - This function checks whether the given * packet from the specified queue can be allowed for transmission by * checking the token count. * @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; } static void get_data_packet(struct bcm_mini_adapter *ad, struct bcm_packet_info *ps_sf) { int packet_len; struct sk_buff *qpacket; if (!ps_sf->ucDirection) return; BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount "); if (ad->IdleMode || ad->bPreparingForLowPowerMode) return; /* in idle mode */ /* Check for Free Descriptors */ if (atomic_read(&ad->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS) { BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " No Free Tx Descriptor(%d) is available for Data pkt..", atomic_read(&ad->CurrNumFreeTxDesc)); return; } spin_lock_bh(&ps_sf->SFQueueLock); qpacket = ps_sf->FirstTxQueue; if (qpacket) { BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Dequeuing Data Packet"); if (ps_sf->bEthCSSupport) packet_len = qpacket->len; else packet_len = qpacket->len - ETH_HLEN; packet_len <<= 3; if (packet_len <= GetSFTokenCount(ad, ps_sf)) { BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Allowed bytes %d", (packet_len >> 3)); DEQUEUEPACKET(ps_sf->FirstTxQueue, ps_sf->LastTxQueue); ps_sf->uiCurrentBytesOnHost -= (qpacket->len); ps_sf->uiCurrentPacketsOnHost--; atomic_dec(&ad->TotalPacketCount); spin_unlock_bh(&ps_sf->SFQueueLock); SendPacketFromQueue(ad, ps_sf, qpacket); ps_sf->uiPendedLast = false; } else { BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", ps_sf - ad->PackInfo); BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n", ps_sf->uiCurrentTokenCount, packet_len); /* 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. */ ps_sf->uiPendedLast = TRUE; spin_unlock_bh(&ps_sf->SFQueueLock); } } else { spin_unlock_bh(&ps_sf->SFQueueLock); } } static void send_control_packet(struct bcm_mini_adapter *ad, struct bcm_packet_info *ps_sf) { char *ctrl_packet = NULL; INT status = 0; if ((atomic_read(&ad->CurrNumFreeTxDesc) > 0) && (atomic_read(&ad->index_rd_txcntrlpkt) != atomic_read(&ad->index_wr_txcntrlpkt))) { ctrl_packet = ad->txctlpacket [(atomic_read(&ad->index_rd_txcntrlpkt)%MAX_CNTRL_PKTS)]; if (ctrl_packet) { BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Sending Control packet"); status = SendControlPacket(ad, ctrl_packet); if (STATUS_SUCCESS == status) { spin_lock_bh(&ps_sf->SFQueueLock); ps_sf->NumOfPacketsSent++; ps_sf->uiSentBytes += ((struct bcm_leader *)ctrl_packet)->PLength; ps_sf->uiSentPackets++; atomic_dec(&ad->TotalPacketCount); ps_sf->uiCurrentBytesOnHost -= ((struct bcm_leader *)ctrl_packet)->PLength; ps_sf->uiCurrentPacketsOnHost--; atomic_inc(&ad->index_rd_txcntrlpkt); spin_unlock_bh(&ps_sf->SFQueueLock); } else { BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "SendControlPacket Failed\n"); } } else { BCM_DEBUG_PRINT(ad, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " Control Pkt is not available, Indexing is wrong...."); } } } /** * CheckAndSendPacketFromIndex() - This function dequeues the * data/control packet from the specified queue for transmission. * @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) { 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 */ get_data_packet(Adapter, psSF); } else { send_control_packet(Adapter, psSF); } } /** * transmit_packets() - This function transmits the packets from * different queues, if free descriptors are available on target. * @Adapter: Pointer to the Adapter structure. * * Returns: None. */ VOID transmit_packets(struct bcm_mini_adapter *Adapter) { UINT uiPrevTotalCount = 0; int iIndex = 0; bool 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, "<======"); }