void vos_mem_clean() { v_SIZE_t listSize; hdd_list_size(&vosMemList, &listSize); if(listSize) { hdd_list_node_t* pNode; VOS_STATUS vosStatus; struct s_vos_mem_struct* memStruct; VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: List is not Empty. listSize %d ", __FUNCTION__, (int)listSize); do { spin_lock(&vosMemList.lock); vosStatus = hdd_list_remove_front(&vosMemList, &pNode); spin_unlock(&vosMemList.lock); if(VOS_STATUS_SUCCESS == vosStatus) { memStruct = (struct s_vos_mem_struct*)pNode; VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "Memory Leak@ File %s, @Line %d, size %d", memStruct->fileName, (int)memStruct->lineNum, memStruct->size); kfree((v_VOID_t*)memStruct); } }while(vosStatus == VOS_STATUS_SUCCESS); } }
static void vos_timer_clean() { v_SIZE_t listSize; unsigned long flags; hdd_list_size(&vosTimerList, &listSize); if (listSize) { hdd_list_node_t* pNode; VOS_STATUS vosStatus; timer_node_t *ptimerNode; VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: List is not Empty. listSize %d ", __func__, (int)listSize); do { spin_lock_irqsave(&vosTimerList.lock, flags); vosStatus = hdd_list_remove_front(&vosTimerList, &pNode); spin_unlock_irqrestore(&vosTimerList.lock, flags); if (VOS_STATUS_SUCCESS == vosStatus) { ptimerNode = (timer_node_t*)pNode; VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "Timer Leak@ File %s, @Line %d", ptimerNode->fileName, (int)ptimerNode->lineNum); vos_mem_free(ptimerNode); } } while (vosStatus == VOS_STATUS_SUCCESS); } }
/**============================================================================ @brief hdd_flush_tx_queues() - Utility function to flush the TX queues @param pAdapter : [in] pointer to adapter context @return : VOS_STATUS_E_FAILURE if any errors encountered : VOS_STATUS_SUCCESS otherwise ===========================================================================*/ static VOS_STATUS hdd_flush_tx_queues( hdd_adapter_t *pAdapter ) { VOS_STATUS status = VOS_STATUS_SUCCESS; v_SINT_t i = -1; hdd_list_node_t *anchor = NULL; skb_list_node_t *pktNode = NULL; struct sk_buff *skb = NULL; while (++i != NUM_TX_QUEUES) { //Free up any packets in the Tx queue spin_lock_bh(&pAdapter->wmm_tx_queue[i].lock); while (true) { status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[i], &anchor ); if(VOS_STATUS_E_EMPTY != status) { pktNode = list_entry(anchor, skb_list_node_t, anchor); skb = pktNode->skb; //TODO //++pAdapter->stats.tx_dropped; ++pAdapter->hdd_stats.hddTxRxStats.txFlushed; ++pAdapter->hdd_stats.hddTxRxStats.txFlushedAC[i]; kfree_skb(skb); continue; } break; } spin_unlock_bh(&pAdapter->wmm_tx_queue[i].lock); // backpressure is no longer in effect pAdapter->isTxSuspended[i] = VOS_FALSE; } return status; }
static struct sk_buff* hdd_mon_tx_fetch_pkt(hdd_adapter_t* pAdapter) { skb_list_node_t *pktNode = NULL; struct sk_buff *skb = NULL; v_SIZE_t size = 0; WLANTL_ACEnumType ac = 0; VOS_STATUS status = VOS_STATUS_E_FAILURE; hdd_list_node_t *anchor = NULL; if( NULL == pAdapter ) { VOS_ASSERT(0); return NULL; } // do we have any packets pending in this AC? hdd_list_size( &pAdapter->wmm_tx_queue[ac], &size ); if( size == 0 ) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: NO Packet Pending", __FUNCTION__); return NULL; } //Remove the packet from the queue spin_lock_bh(&pAdapter->wmm_tx_queue[ac].lock); status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[ac], &anchor ); spin_unlock_bh(&pAdapter->wmm_tx_queue[ac].lock); if(VOS_STATUS_SUCCESS == status) { //If success then we got a valid packet from some AC pktNode = list_entry(anchor, skb_list_node_t, anchor); skb = pktNode->skb; } else { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Not able to remove Packet from the list", __FUNCTION__); return NULL; } // if we are in a backpressure situation see if we can turn the hose back on if ( (pAdapter->isTxSuspended[ac]) && (size <= HDD_TX_QUEUE_LOW_WATER_MARK) ) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: TX queue[%d] re-enabled", __FUNCTION__, ac); pAdapter->isTxSuspended[ac] = VOS_FALSE; /* Enable Queues which we have disabled earlier */ netif_tx_start_all_queues( pAdapter->dev ); } return skb; }
void vos_mem_clean() { v_SIZE_t listSize; hdd_list_size(&vosMemList, &listSize); if(listSize) { hdd_list_node_t* pNode; VOS_STATUS vosStatus; struct s_vos_mem_struct* memStruct; const char *prev_mleak_file = ""; unsigned int prev_mleak_lineNum = 0; unsigned int prev_mleak_sz = 0; unsigned int mleak_cnt = 0; VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s: List is not Empty. listSize %d ", __func__, (int)listSize); do { spin_lock(&vosMemList.lock); vosStatus = hdd_list_remove_front(&vosMemList, &pNode); spin_unlock(&vosMemList.lock); if(VOS_STATUS_SUCCESS == vosStatus) { memStruct = (struct s_vos_mem_struct*)pNode; /* Take care to log only once multiple memory leaks from * the same place */ if(strcmp(prev_mleak_file, memStruct->fileName) || (prev_mleak_lineNum != memStruct->lineNum) || (prev_mleak_sz != memStruct->size)) { if(mleak_cnt != 0) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "%d Time Memory Leak@ File %s, @Line %d, size %d", mleak_cnt, prev_mleak_file, prev_mleak_lineNum, prev_mleak_sz); } prev_mleak_file = memStruct->fileName; prev_mleak_lineNum = memStruct->lineNum; prev_mleak_sz = memStruct->size; mleak_cnt = 0; } mleak_cnt++; vos_mem_print_stack_trace(memStruct); kfree((v_VOID_t*)memStruct); } }while(vosStatus == VOS_STATUS_SUCCESS); /* Print last memory leak from the module */ if(mleak_cnt) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_FATAL, "%d Time memory Leak@ File %s, @Line %d, size %d", mleak_cnt, prev_mleak_file, prev_mleak_lineNum, prev_mleak_sz); } #ifdef CONFIG_HALT_KMEMLEAK BUG_ON(0); #endif } dump_trace_usage(); }
/**============================================================================ @brief hdd_tx_fetch_packet_cbk() - Callback function invoked by TL to fetch a packet for transmission. @param vosContext : [in] pointer to VOS context @param staId : [in] Station for which TL is requesting a pkt @param ac : [in] access category requested by TL @param pVosPacket : [out] pointer to VOS packet packet pointer @param pPktMetaInfo : [out] pointer to meta info for the pkt @return : VOS_STATUS_E_EMPTY if no packets to transmit : VOS_STATUS_E_FAILURE if any errors encountered : VOS_STATUS_SUCCESS otherwise ===========================================================================*/ VOS_STATUS hdd_tx_fetch_packet_cbk( v_VOID_t *vosContext, v_U8_t *pStaId, WLANTL_ACEnumType ac, vos_pkt_t **ppVosPacket, WLANTL_MetaInfoType *pPktMetaInfo ) { VOS_STATUS status = VOS_STATUS_E_FAILURE; hdd_adapter_t *pAdapter = NULL; hdd_context_t *pHddCtx = NULL; hdd_list_node_t *anchor = NULL; skb_list_node_t *pktNode = NULL; struct sk_buff *skb = NULL; vos_pkt_t *pVosPacket = NULL; v_MACADDR_t* pDestMacAddress = NULL; v_TIME_t timestamp; WLANTL_ACEnumType newAc; v_SIZE_t size = 0; tANI_U8 acAdmitted, i; //Sanity check on inputs if ( ( NULL == vosContext ) || ( NULL == pStaId ) || ( NULL == ppVosPacket ) || ( NULL == pPktMetaInfo ) ) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Null Params being passed", __FUNCTION__); return VOS_STATUS_E_FAILURE; } //Get the HDD context. pHddCtx = (hdd_context_t *)vos_get_context( VOS_MODULE_ID_HDD, vosContext ); if(pHddCtx == NULL) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: HDD adapter context is Null", __FUNCTION__); return VOS_STATUS_E_FAILURE; } pAdapter = pHddCtx->sta_to_adapter[*pStaId]; if( NULL == pAdapter ) { VOS_ASSERT(0); return VOS_STATUS_E_FAILURE; } ++pAdapter->hdd_stats.hddTxRxStats.txFetched; *ppVosPacket = NULL; //Make sure the AC being asked for is sane if( ac >= WLANTL_MAX_AC || ac < 0) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR,"%s: Invalid AC %d passed by TL", __FUNCTION__, ac); return VOS_STATUS_E_FAILURE; } ++pAdapter->hdd_stats.hddTxRxStats.txFetchedAC[ac]; #ifdef HDD_WMM_DEBUG VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,"%s: AC %d passed by TL", __FUNCTION__, ac); #endif // HDD_WMM_DEBUG // We find an AC with packets // or we determine we have no more packets to send // HDD is not allowed to change AC. // has this AC been admitted? or // To allow EAPOL packets when not authenticated if (unlikely((0==pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessAllowed) && (WLAN_HDD_GET_STATION_CTX_PTR(pAdapter))->conn_info.uIsAuthenticated)) { ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty; #ifdef HDD_WMM_DEBUG VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: no packets pending", __FUNCTION__); #endif // HDD_WMM_DEBUG return VOS_STATUS_E_FAILURE; } // do we have any packets pending in this AC? hdd_list_size( &pAdapter->wmm_tx_queue[ac], &size ); if( size > 0 ) { // yes, so process it #ifdef HDD_WMM_DEBUG VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: AC %d has packets pending", __FUNCTION__, ac); #endif // HDD_WMM_DEBUG } else { ++pAdapter->hdd_stats.hddTxRxStats.txFetchEmpty; #ifdef HDD_WMM_DEBUG VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL, "%s: no packets pending", __FUNCTION__); #endif // HDD_WMM_DEBUG return VOS_STATUS_E_FAILURE; } //Get the vos packet. I don't want to dequeue and enqueue again if we are out of VOS resources //This simplifies the locking and unlocking of Tx queue status = vos_pkt_wrap_data_packet( &pVosPacket, VOS_PKT_TYPE_TX_802_3_DATA, NULL, //OS Pkt is not being passed hdd_tx_low_resource_cbk, pAdapter ); if (status == VOS_STATUS_E_ALREADY || status == VOS_STATUS_E_RESOURCES) { //Remember VOS is in a low resource situation pAdapter->isVosOutOfResource = VOS_TRUE; ++pAdapter->hdd_stats.hddTxRxStats.txFetchLowResources; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: VOSS in Low Resource scenario", __FUNCTION__); //TL will now think we have no more packets in this AC return VOS_STATUS_E_FAILURE; } //Remove the packet from the queue spin_lock_bh(&pAdapter->wmm_tx_queue[ac].lock); status = hdd_list_remove_front( &pAdapter->wmm_tx_queue[ac], &anchor ); spin_unlock_bh(&pAdapter->wmm_tx_queue[ac].lock); if(VOS_STATUS_SUCCESS == status) { //If success then we got a valid packet from some AC pktNode = list_entry(anchor, skb_list_node_t, anchor); skb = pktNode->skb; } else { ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: Error in de-queuing " "skb from Tx queue status = %d", __FUNCTION__, status ); vos_pkt_return_packet(pVosPacket); return VOS_STATUS_E_FAILURE; } //Attach skb to VOS packet. status = vos_pkt_set_os_packet( pVosPacket, skb ); if (status != VOS_STATUS_SUCCESS) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: Error attaching skb", __FUNCTION__); vos_pkt_return_packet(pVosPacket); ++pAdapter->stats.tx_dropped; ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError; kfree_skb(skb); return VOS_STATUS_E_FAILURE; } //Just being paranoid. To be removed later if(pVosPacket == NULL) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN,"%s: VOS packet returned by VOSS is NULL", __FUNCTION__); ++pAdapter->stats.tx_dropped; ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeueError; kfree_skb(skb); return VOS_STATUS_E_FAILURE; } //Return VOS packet to TL; *ppVosPacket = pVosPacket; //Fill out the meta information needed by TL //FIXME This timestamp is really the time stamp of wrap_data_packet vos_pkt_get_timestamp( pVosPacket, ×tamp ); pPktMetaInfo->usTimeStamp = (v_U16_t)timestamp; if(pAdapter->sessionCtx.station.conn_info.uIsAuthenticated == VOS_TRUE) pPktMetaInfo->ucIsEapol = 0; else pPktMetaInfo->ucIsEapol = hdd_IsEAPOLPacket( pVosPacket ) ? 1 : 0; #ifdef FEATURE_WLAN_WAPI // Override usIsEapol value when its zero for WAPI case pPktMetaInfo->ucIsWai = hdd_IsWAIPacket( pVosPacket ) ? 1 : 0; #endif /* FEATURE_WLAN_WAPI */ if ((HDD_WMM_USER_MODE_NO_QOS == pHddCtx->cfg_ini->WmmMode) || (!pAdapter->hddWmmStatus.wmmQap)) { // either we don't want QoS or the AP doesn't support QoS pPktMetaInfo->ucUP = 0; pPktMetaInfo->ucTID = 0; } else { /* 1. Check if ACM is set for this AC * 2. If set, check if this AC had already admitted * 3. If not already admitted, downgrade the UP to next best UP */ if(!pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcAccessRequired || pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid) { pPktMetaInfo->ucUP = pktNode->userPriority; pPktMetaInfo->ucTID = pPktMetaInfo->ucUP; } else { //Downgrade the UP acAdmitted = pAdapter->hddWmmStatus.wmmAcStatus[ac].wmmAcTspecValid; newAc = WLANTL_AC_BK; for (i=ac-1; i>0; i--) { if (pAdapter->hddWmmStatus.wmmAcStatus[i].wmmAcAccessRequired == 0) { newAc = i; break; } } pPktMetaInfo->ucUP = hddWmmAcToHighestUp[newAc]; pPktMetaInfo->ucTID = pPktMetaInfo->ucUP; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO_LOW,"Downgrading UP %d to UP %d ", pktNode->userPriority, pPktMetaInfo->ucUP); } } pPktMetaInfo->ucType = 0; //FIXME Don't know what this is pPktMetaInfo->ucDisableFrmXtl = 0; //802.3 frame so we need to xlate if ( 1 < size ) { pPktMetaInfo->bMorePackets = 1; //HDD has more packets to send } else { pPktMetaInfo->bMorePackets = 0; } //Extract the destination address from ethernet frame pDestMacAddress = (v_MACADDR_t*)skb->data; pPktMetaInfo->ucBcast = vos_is_macaddr_broadcast( pDestMacAddress ) ? 1 : 0; pPktMetaInfo->ucMcast = vos_is_macaddr_group( pDestMacAddress ) ? 1 : 0; // if we are in a backpressure situation see if we can turn the hose back on if ( (pAdapter->isTxSuspended[ac]) && (size <= HDD_TX_QUEUE_LOW_WATER_MARK) ) { ++pAdapter->hdd_stats.hddTxRxStats.txFetchDePressured; ++pAdapter->hdd_stats.hddTxRxStats.txFetchDePressuredAC[ac]; VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_WARN, "%s: TX queue[%d] re-enabled", __FUNCTION__, ac); pAdapter->isTxSuspended[ac] = VOS_FALSE; netif_tx_wake_queue(netdev_get_tx_queue(pAdapter->dev, skb_get_queue_mapping(skb) )); } // We're giving the packet to TL so consider it transmitted from // a statistics perspective. We account for it here instead of // when the packet is returned for two reasons. First, TL will // manipulate the skb to the point where the len field is not // accurate, leading to inaccurate byte counts if we account for // it later. Second, TL does not provide any feedback as to // whether or not the packet was successfully sent over the air, // so the packet counts will be the same regardless of where we // account for them pAdapter->stats.tx_bytes += skb->len; ++pAdapter->stats.tx_packets; ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeued; ++pAdapter->hdd_stats.hddTxRxStats.txFetchDequeuedAC[ac]; if(pHddCtx->cfg_ini->thermalMitigationEnable) { if(mutex_lock_interruptible(&pHddCtx->tmInfo.tmOperationLock)) { VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_ERROR, "%s: Tm Lock fail", __FUNCTION__); return VOS_STATUS_E_FAILURE; } if(WLAN_HDD_TM_LEVEL_1 < pHddCtx->tmInfo.currentTmLevel) { if(0 == pHddCtx->tmInfo.txFrameCount) { /* Just recovered from sleep timeout */ pHddCtx->tmInfo.lastOpenTs = timestamp; } if(((timestamp - pHddCtx->tmInfo.lastOpenTs) > (pHddCtx->tmInfo.tmAction.txOperationDuration / 10)) && (pHddCtx->tmInfo.txFrameCount >= pHddCtx->tmInfo.tmAction.txBlockFrameCountThreshold)) { spin_lock(&pAdapter->wmm_tx_queue[ac].lock); /* During TX open duration, TX frame count is larger than threshold * Block TX during Sleep time */ netif_tx_stop_all_queues(pAdapter->dev); spin_unlock(&pAdapter->wmm_tx_queue[ac].lock); pHddCtx->tmInfo.lastblockTs = timestamp; if(VOS_TIMER_STATE_STOPPED == vos_timer_getCurrentState(&pHddCtx->tmInfo.txSleepTimer)) { vos_timer_start(&pHddCtx->tmInfo.txSleepTimer, pHddCtx->tmInfo.tmAction.txSleepDuration); } } else if(((timestamp - pHddCtx->tmInfo.lastOpenTs) > (pHddCtx->tmInfo.tmAction.txOperationDuration / 10)) && (pHddCtx->tmInfo.txFrameCount < pHddCtx->tmInfo.tmAction.txBlockFrameCountThreshold)) { /* During TX open duration, TX frame count is less than threshold * Reset count and timestamp to prepare next cycle */ pHddCtx->tmInfo.lastOpenTs = timestamp; pHddCtx->tmInfo.txFrameCount = 0; } else { /* Do Nothing */ } pHddCtx->tmInfo.txFrameCount++; } mutex_unlock(&pHddCtx->tmInfo.tmOperationLock); } #ifdef HDD_WMM_DEBUG VOS_TRACE( VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_FATAL,"%s: Valid VOS PKT returned to TL", __FUNCTION__); #endif // HDD_WMM_DEBUG return status; }