diff options
Diffstat (limited to 'drivers/net/wireless/uccp420wlan/src/tx.c')
-rw-r--r-- | drivers/net/wireless/uccp420wlan/src/tx.c | 1121 |
1 files changed, 754 insertions, 367 deletions
diff --git a/drivers/net/wireless/uccp420wlan/src/tx.c b/drivers/net/wireless/uccp420wlan/src/tx.c index 1d435788693..465d87de5dd 100644 --- a/drivers/net/wireless/uccp420wlan/src/tx.c +++ b/drivers/net/wireless/uccp420wlan/src/tx.c @@ -61,8 +61,7 @@ static void wait_for_tx_complete(struct tx_config *tx) } } - -static inline int tx_queue_map(int queue) +int tx_queue_map(int queue) { unsigned int ac[4] = {WLAN_AC_VO, WLAN_AC_VI, WLAN_AC_BE, WLAN_AC_BK}; @@ -72,8 +71,7 @@ static inline int tx_queue_map(int queue) return WLAN_AC_VO; } - -static inline int tx_queue_unmap(int queue) +int tx_queue_unmap(int queue) { unsigned int ac[4] = {3, 2, 1, 0}; @@ -105,6 +103,9 @@ static void tx_status(struct sk_buff *skb, int tx_fixed_mcs_idx = 0; int tx_fixed_rate = 0; struct ieee80211_supported_band *band = NULL; + struct umac_vif *uvif = NULL; + + uvif = (struct umac_vif *)(tx_info->control.vif->drv_priv); /* Rate info will be retained, except the count*/ ieee80211_tx_info_clear_status(tx_info); @@ -207,13 +208,18 @@ static void tx_status(struct sk_buff *skb, index++; } - if ((tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) && + if (((tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || + (uvif->chanctx && + (uvif->chanctx->index == dev->roc_off_chanctx_idx))) && (atomic_dec_return(&dev->roc_params.roc_mgmt_tx_count) == 0)) { - if (dev->roc_params.roc_in_progress) { - /* Reuse the delayed workqueue with 1ms delay */ - ieee80211_queue_delayed_work(dev->hw, - &dev->roc_complete_work, - msecs_to_jiffies(1)); + DEBUG_LOG("%s-UMACTX: TXDONE Frame: %d\n", + dev->name, + atomic_read(&dev->roc_params.roc_mgmt_tx_count)); + if (dev->roc_params.roc_in_progress && + dev->roc_params.roc_type == ROC_TYPE_OFFCHANNEL_TX) { + uccp420wlan_prog_roc(ROC_STOP, 0, 0, 0); + DEBUG_LOG("%s-UMACTX: all offchan pend frames clear\n", + dev->name); } } @@ -242,6 +248,7 @@ static int get_token(struct mac80211_dev *dev, if (!test_and_set_bit(curr_bit, &tx->buf_pool_bmp[pool_id])) { token_id = queue + (NUM_ACS * cnt); + tx->outstanding_tokens[queue]++; break; } } @@ -258,29 +265,40 @@ static int get_token(struct mac80211_dev *dev, /* Do not set, we will queue to the same token */ if (!test_and_set_bit(curr_bit, &tx->buf_pool_bmp[pool_id])) { + tx->outstanding_tokens[queue]++; break; } } } - if (token_id != NUM_TX_DESCS) { - tx->outstanding_tokens[queue]++; -#ifdef MULTI_CHAN_SUPPORT - tx->desc_chan_map[token_id] = curr_chanctx_idx; -#endif - } - return token_id; } +void free_token(struct mac80211_dev *dev, + int token_id, + int queue) +{ + struct tx_config *tx = &dev->tx; + int bit = -1; + int pool_id = -1; + + bit = (token_id % TX_DESC_BUCKET_BOUND); + pool_id = (token_id / TX_DESC_BUCKET_BOUND); -int get_curr_peer_opp(struct mac80211_dev *dev, + __clear_bit(bit, &tx->buf_pool_bmp[pool_id]); + + tx->outstanding_tokens[queue]--; +} + + +struct curr_peer_info get_curr_peer_opp(struct mac80211_dev *dev, #ifdef MULTI_CHAN_SUPPORT - int curr_chanctx_idx, + int curr_chanctx_idx, #endif - int queue) -{ + int ac) + { unsigned int curr_peer_opp = 0; + unsigned int curr_vif_op_chan = UMAC_VIF_CHANCTX_TYPE_OPER; unsigned int i = 0; struct tx_config *tx = NULL; #ifdef MULTI_CHAN_SUPPORT @@ -291,21 +309,28 @@ int get_curr_peer_opp(struct mac80211_dev *dev, int vif_index = -1; #endif unsigned int init_peer_opp = 0; + struct curr_peer_info peer_info; + unsigned int pend_q_len; + struct sk_buff_head *pend_q = NULL; tx = &dev->tx; #ifdef MULTI_CHAN_SUPPORT - init_peer_opp = tx->curr_peer_opp[curr_chanctx_idx][queue]; + init_peer_opp = tx->curr_peer_opp[curr_chanctx_idx][ac]; #else - init_peer_opp = tx->curr_peer_opp[queue]; + init_peer_opp = tx->curr_peer_opp[ac]; #endif - + /*TODO: Optimize this loop for BCN_Q + */ for (i = 0; i < MAX_PEND_Q_PER_AC; i++) { curr_peer_opp = (init_peer_opp + i) % MAX_PEND_Q_PER_AC; #ifdef MULTI_CHAN_SUPPORT rcu_read_lock(); + /* RoC Frame do not have a "sta" entry. + * so we need not handle RoC stuff here + */ if (curr_peer_opp < MAX_PEERS) { sta = rcu_dereference(dev->peers[curr_peer_opp]); @@ -316,16 +341,43 @@ int get_curr_peer_opp(struct mac80211_dev *dev, usta = (struct umac_sta *)(sta->drv_priv); - if (!usta->chanctx) { + vif = rcu_dereference(dev->vifs[usta->vif_index]); + + if (!vif) { rcu_read_unlock(); continue; } - if (usta->chanctx->index != curr_chanctx_idx) { + + uvif = (struct umac_vif *)(vif->drv_priv); + + if (!uvif->chanctx && !uvif->off_chanctx) { rcu_read_unlock(); continue; } + if ((uvif->chanctx && + (uvif->chanctx->index != curr_chanctx_idx)) || + !uvif->chanctx) { + if ((uvif->off_chanctx && + (uvif->off_chanctx->index != + curr_chanctx_idx)) || + !uvif->off_chanctx) { + rcu_read_unlock(); + continue; + } else { + curr_vif_op_chan = + UMAC_VIF_CHANCTX_TYPE_OFF; + } + } else { + if (dev->roc_params.roc_in_progress && + !dev->roc_params.need_offchan) + curr_vif_op_chan = + UMAC_VIF_CHANCTX_TYPE_OFF; + else + curr_vif_op_chan = + UMAC_VIF_CHANCTX_TYPE_OPER; + } } else { vif_index = (curr_peer_opp - MAX_PEERS); @@ -338,46 +390,177 @@ int get_curr_peer_opp(struct mac80211_dev *dev, uvif = (struct umac_vif *)(vif->drv_priv); - if (!uvif->chanctx) { + if (!uvif->chanctx && !uvif->off_chanctx) { rcu_read_unlock(); continue; } - if (uvif->chanctx->index != curr_chanctx_idx) { - rcu_read_unlock(); - continue; + /* For a beacon queue we will process the frames + * irrespective of the current channel context. + * The FW will take care of transmitting them in the + * appropriate channel. + */ + + if (ac != WLAN_AC_BCN && + ((uvif->chanctx && + (uvif->chanctx->index != curr_chanctx_idx)) || + !uvif->chanctx)) { + if ((uvif->off_chanctx && + (uvif->off_chanctx->index != + curr_chanctx_idx)) || + !uvif->off_chanctx) { + rcu_read_unlock(); + continue; + } else { + curr_vif_op_chan = + UMAC_VIF_CHANCTX_TYPE_OFF; + } + } else { + if (dev->roc_params.roc_in_progress && + !dev->roc_params.need_offchan) + curr_vif_op_chan = + UMAC_VIF_CHANCTX_TYPE_OFF; + else + curr_vif_op_chan = + UMAC_VIF_CHANCTX_TYPE_OPER; } } rcu_read_unlock(); #endif + pend_q = &tx->pending_pkt[curr_vif_op_chan][curr_peer_opp][ac]; + pend_q_len = skb_queue_len(pend_q); - if (skb_queue_len(&tx->pending_pkt[curr_peer_opp][queue])) { + if (pend_q_len) { #ifdef MULTI_CHAN_SUPPORT - tx->curr_peer_opp[curr_chanctx_idx][queue] = + tx->curr_peer_opp[curr_chanctx_idx][ac] = (curr_peer_opp + 1) % MAX_PEND_Q_PER_AC; #else - tx->curr_peer_opp[queue] = + tx->curr_peer_opp[ac] = (curr_peer_opp + 1) % MAX_PEND_Q_PER_AC; #endif break; } } - if (i == MAX_PEND_Q_PER_AC) - return -1; + if (i == MAX_PEND_Q_PER_AC) { + peer_info.id = -1; + peer_info.op_chan_idx = -1; + } else { + peer_info.id = curr_peer_opp; + peer_info.op_chan_idx = curr_vif_op_chan; + DEBUG_LOG("%s-UMACTX: Queue: %d Peer: %d op_chan: %d ", + dev->name, + ac, + curr_peer_opp, + curr_vif_op_chan); + DEBUG_LOG("chanctx: %d got opportunity, pending: %d\n", + curr_chanctx_idx, + pend_q_len); + } - return curr_peer_opp; + return peer_info; } -void uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev, - int queue, #ifdef MULTI_CHAN_SUPPORT - int curr_chanctx_idx, +void uccp420wlan_tx_proc_send_pend_frms_all(struct mac80211_dev *dev, + int ch_id) +{ + int txq_len = 0; + int i = 0, cnt = 0; + int queue = 0; + unsigned long flags = 0; + int curr_bit = 0; + int pool_id = 0; + int ret = 0; + int start_ac, end_ac; + unsigned int pkts_pend = 0; + struct tx_config *tx = NULL; + struct sk_buff_head *txq = NULL; + + tx = &dev->tx; + + for (i = 0; i < NUM_TX_DESCS; i++) { + spin_lock_irqsave(&tx->lock, flags); + + curr_bit = (i % TX_DESC_BUCKET_BOUND); + pool_id = (i / TX_DESC_BUCKET_BOUND); + + if (test_and_set_bit(curr_bit, &tx->buf_pool_bmp[pool_id])) { + spin_unlock_irqrestore(&tx->lock, flags); + continue; + } + + txq = &tx->pkt_info[ch_id][i].pkt; + txq_len = skb_queue_len(txq); + + /* Not valid when txq len is 0 */ + queue = tx->pkt_info[ch_id][i].queue; + + if (!txq_len) { + /* Reserved token */ + if (i < (NUM_TX_DESCS_PER_AC * NUM_ACS)) { + queue = (i % NUM_ACS); + start_ac = end_ac = queue; + } else { + /* Spare token: + * Loop through all AC's + */ + start_ac = WLAN_AC_VO; + end_ac = WLAN_AC_BK; + } + + for (cnt = start_ac; cnt >= end_ac; cnt--) { + pkts_pend = uccp420wlan_tx_proc_pend_frms(dev, + cnt, + ch_id, + i); + if (pkts_pend) { + queue = cnt; + break; + } + } + + if (pkts_pend == 0) { + __clear_bit(curr_bit, + &tx->buf_pool_bmp[pool_id]); + spin_unlock_irqrestore(&tx->lock, flags); + continue; + } + } + + tx->outstanding_tokens[queue]++; + spin_unlock_irqrestore(&tx->lock, flags); + + ret = __uccp420wlan_tx_frame(dev, + queue, + i, + ch_id, + 0, + 0); /* TODO: Currently sending 0 + since this param is not used + as expected in the orig + code for multiple frames etc + Need to set this + properly when the orig code + logic is corrected + */ + if (ret < 0) { + pr_err("%s: Queueing of TX frame to FW failed\n", + __func__); + } + } +} #endif - int peer_id, - int token_id) + + +int uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev, + int ac, +#ifdef MULTI_CHAN_SUPPORT + int curr_chanctx_idx, +#endif + int token_id) { struct tx_config *tx = &dev->tx; unsigned long ampdu_len = 0; @@ -394,8 +577,22 @@ void uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev, unsigned int max_tx_cmds = dev->params->max_tx_cmds; struct sk_buff_head *txq = NULL; struct sk_buff_head *pend_pkt_q = NULL; + unsigned int total_pending_processed = 0; + int pend_pkt_q_len = 0; + struct curr_peer_info peer_info; + + peer_info = get_curr_peer_opp(dev, +#ifdef MULTI_CHAN_SUPPORT + curr_chanctx_idx, +#endif + ac); - pend_pkt_q = &tx->pending_pkt[peer_id][queue]; + /* No pending frames for any peer in that AC. + */ + if (peer_info.id == -1) + return 0; + + pend_pkt_q = &tx->pending_pkt[peer_info.op_chan_idx][peer_info.id][ac]; #ifdef MULTI_CHAN_SUPPORT txq = &dev->tx.pkt_info[curr_chanctx_idx][token_id].pkt; @@ -405,6 +602,12 @@ void uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev, skb_first = skb_peek(pend_pkt_q); + if (skb_first == NULL) + pr_err("%s:%d Null SKB: peer: %d\n", + __func__, + __LINE__, + peer_info.id); + mac_hdr_first = (struct ieee80211_hdr *)skb_first->data; tx_info_first = IEEE80211_SKB_CB(skb_first); @@ -443,8 +646,18 @@ void uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev, IEEE80211_TX_MAX_RATES) != 0) || (tx_info_first->flags != tx_info->flags) || #endif + /* RPU has a limitation, it expects A1-A2-A3 to be same + * for all MPDU's within an AMPDU. This is a temporary + * solution, remove it when RPU has fix for this. + */ (memcmp(mac_hdr->addr1, mac_hdr_first->addr1, + ETH_ALEN) != 0) || + (memcmp(mac_hdr->addr2, + mac_hdr_first->addr2, + ETH_ALEN) != 0) || + (memcmp(mac_hdr->addr3, + mac_hdr_first->addr3, ETH_ALEN) != 0)) break; @@ -457,115 +670,120 @@ void uccp420wlan_tx_proc_pend_frms(struct mac80211_dev *dev, if (!skb_queue_len(txq)) skb_queue_tail(txq, skb_dequeue(pend_pkt_q)); - DEBUG_LOG("%s-UMACTX:Max_pkt_thresh: send spare: %d with %d\n", + total_pending_processed = skb_queue_len(txq); + + pend_pkt_q_len = skb_queue_len(pend_pkt_q); + if ((ac != WLAN_AC_BCN) && + (tx->queue_stopped_bmp & (1 << ac)) && + pend_pkt_q_len < (MAX_TX_QUEUE_LEN / 2)) { + ieee80211_wake_queue(dev->hw, tx_queue_unmap(ac)); + tx->queue_stopped_bmp &= ~(1 << (ac)); + } + + DEBUG_LOG("%s-UMACTX: token_id: %d total_pending_packets_process: %d\n", dev->name, token_id, skb_queue_len(txq)); + + return total_pending_processed; } -int uccp420wlan_tx_alloc_buff_req(struct mac80211_dev *dev, - int queue, +int uccp420wlan_tx_alloc_token(struct mac80211_dev *dev, + int ac, #ifdef MULTI_CHAN_SUPPORT - struct umac_vif *uvif, - int curr_chanctx_idx, + int off_chanctx_idx, + int curr_chanctx_idx, #endif - int peer_id, - struct sk_buff *skb) + int peer_id, + struct sk_buff *skb) { int token_id = NUM_TX_DESCS; struct tx_config *tx = &dev->tx; - struct sk_buff_head *txq = NULL; - unsigned long flags = 0; + unsigned long flags; struct sk_buff_head *pend_pkt_q = NULL; - int tx_peer_id = 0; - struct ieee80211_hdr *mac_hdr = NULL; + unsigned int pkts_pend = 0; spin_lock_irqsave(&tx->lock, flags); - pend_pkt_q = &tx->pending_pkt[peer_id][queue]; + pend_pkt_q = &tx->pending_pkt[off_chanctx_idx][peer_id][ac]; - DEBUG_LOG("%s-UMACTX:Alloc buf Req q = %d,\n", dev->name, queue); + DEBUG_LOG("%s-UMACTX:Alloc buf Req q = %d off_chan: %d peerid: %d,\n", + dev->name, + ac, + off_chanctx_idx, + peer_id); -#ifdef MULTI_CHAN_SUPPORT - if (uvif->chanctx->index == curr_chanctx_idx) - token_id = get_token(dev, - curr_chanctx_idx, - queue); -#else - token_id = get_token(dev, - queue); -#endif + /* Queue the frame to the pending frames queue */ + skb_queue_tail(pend_pkt_q, skb); + /* If the number of outstanding Tx tokens is greater than + * NUM_TX_DESCS_PER_AC we try and encourage aggregation to the max size + * supported (dev->params->max_tx_cmds) + */ + if (tx->outstanding_tokens[ac] >= NUM_TX_DESCS_PER_AC) { + if ((skb_queue_len(pend_pkt_q) < dev->params->max_tx_cmds) || + ac == WLAN_AC_BCN) + goto out; + } - /* If we got a reserved token, then queue frame to the Xmit queue */ - if (token_id < NUM_TX_DESCS_PER_AC * NUM_ACS) { - DEBUG_LOG("%s-UMACTX:Reserved Token, Sending single\n", - dev->name); + /* Take steps to stop the TX traffic if we have reached + * the queueing limit. + * We dont this for the ROC queue to avoid the case where we are in the + * OFF channel but there is lot of traffic for the operating channel on + * the shared ROC queue (which is VO right now), since this would block + * ROC traffic too. + */ + if (skb_queue_len(pend_pkt_q) >= MAX_TX_QUEUE_LEN) { + if ((!dev->roc_params.roc_in_progress) || + (dev->roc_params.roc_in_progress && + (ac != UMAC_ROC_AC))) { + ieee80211_stop_queue(dev->hw, + skb->queue_mapping); + tx->queue_stopped_bmp |= (1 << ac); + } + } + + token_id = get_token(dev, #ifdef MULTI_CHAN_SUPPORT - txq = &dev->tx.pkt_info[curr_chanctx_idx][token_id].pkt; -#else - txq = &dev->tx.pkt_info[token_id].pkt; + curr_chanctx_idx, #endif - skb_queue_tail(txq, skb); - } else { - /* A frame for a beacon queue should never get a reserved - * token - */ - mac_hdr = (struct ieee80211_hdr *)(skb->data); - - if ((queue == WLAN_AC_BCN) && - (ieee80211_is_beacon(mac_hdr->frame_control))) { - if (net_ratelimit()) - pr_warn("Did not get rsvd token for beacon\n"); - } + ac); - /* Queue the frame to the pending frames queue */ - skb_queue_tail(pend_pkt_q, skb); + DEBUG_LOG("%s-UMACTX:Alloc buf Result *id= %d q = %d peerid: %d,\n", + dev->name, + token_id, + ac, + peer_id); - if (queue != WLAN_AC_BCN) { - /* Take steps to stop the TX traffic if we have reached - * the queueing limit - */ - if (skb_queue_len(pend_pkt_q) >= MAX_TX_QUEUE_LEN) { - ieee80211_stop_queue(dev->hw, - skb->queue_mapping); - tx->queue_stopped_bmp |= (1 << queue); - } + if (token_id == NUM_TX_DESCS) + goto out; - /* If we got a spare token, try sending out pending - * frames - */ - if (token_id < NUM_TX_DESCS) { - tx_peer_id = get_curr_peer_opp(dev, + pkts_pend = uccp420wlan_tx_proc_pend_frms(dev, + ac, #ifdef MULTI_CHAN_SUPPORT - curr_chanctx_idx, + curr_chanctx_idx, #endif - queue); + token_id); - uccp420wlan_tx_proc_pend_frms(dev, - queue, -#ifdef MULTI_CHAN_SUPPORT - curr_chanctx_idx, -#endif - tx_peer_id, - token_id); - } - } - } + /* We have just added a frame to pending_q but channel context is + * mismatch. + */ - DEBUG_LOG("%s-UMACTX:Alloc buf Result *id = %d q = %d peer_id = %d\n", - dev->name, - token_id - queue, - peer_id); + if (!pkts_pend) { + free_token(dev, token_id, ac); + token_id = NUM_TX_DESCS; + } +out: spin_unlock_irqrestore(&tx->lock, flags); + DEBUG_LOG("%s-UMACTX:Alloc buf Result *id= %d\n", dev->name, token_id); /* If token is available, just return tokenid, list will be sent*/ return token_id; } + int get_band_chanctx(struct mac80211_dev *dev, struct umac_vif *uvif) { struct ieee80211_chanctx_conf *chanctx = NULL; @@ -586,9 +804,10 @@ int get_band_chanctx(struct mac80211_dev *dev, struct umac_vif *uvif) return band; } + int uccp420wlan_tx_free_buff_req(struct mac80211_dev *dev, struct umac_event_tx_done *tx_done, - unsigned char *queue, + unsigned char *ac, #ifdef MULTI_CHAN_SUPPORT int curr_chanctx_idx, #endif @@ -606,18 +825,15 @@ int uccp420wlan_tx_free_buff_req(struct mac80211_dev *dev, int vif_index = -1; unsigned int pkt = 0; int cnt = 0; - int bit = 0; - int pool_id = 0; unsigned int desc_id = tx_done->descriptor_id; - unsigned int max_tx_cmds = dev->params->max_tx_cmds; struct umac_vif *uvif = NULL; struct ieee80211_vif *ivif = NULL; unsigned long bcn_int = 0; - int pend_pkt_q_len = 0; - int peer_id = 0; #ifdef MULTI_CHAN_SUPPORT int chanctx_idx = 0; + struct tx_pkt_info *pkt_info = NULL; #endif + int start_ac, end_ac; skb_queue_head_init(&tx_done_list); @@ -628,67 +844,17 @@ int uccp420wlan_tx_free_buff_req(struct mac80211_dev *dev, spin_lock_irqsave(&tx->lock, flags); - tx->outstanding_tokens[tx_done->queue]--; - #ifdef MULTI_CHAN_SUPPORT chanctx_idx = tx->desc_chan_map[desc_id]; -#endif - - bit = (desc_id % TX_DESC_BUCKET_BOUND); - pool_id = (desc_id / TX_DESC_BUCKET_BOUND); - - /* Reserved token */ - if (desc_id < (NUM_TX_DESCS_PER_AC * NUM_ACS)) { - *queue = tx_done->queue; - - peer_id = get_curr_peer_opp(dev, -#ifdef MULTI_CHAN_SUPPORT - curr_chanctx_idx, -#endif - *queue); - - if (peer_id == -1) { - __clear_bit(bit, &tx->buf_pool_bmp[pool_id]); -#ifdef MULTI_CHAN_SUPPORT - tx->desc_chan_map[desc_id] = -1; -#endif - } - /* Spare token */ - } else { - for (cnt = WLAN_AC_VO; cnt >= 0; cnt--) { - peer_id = get_curr_peer_opp(dev, -#ifdef MULTI_CHAN_SUPPORT - curr_chanctx_idx, -#endif - cnt); - - if (peer_id != -1) { - *queue = cnt; - break; - } - } - - /* If beacon queue has pending and no other AC - * has pending - */ - if (peer_id == -1) { - __clear_bit(bit, &tx->buf_pool_bmp[pool_id]); -#ifdef MULTI_CHAN_SUPPORT - tx->desc_chan_map[desc_id] = -1; -#endif - } + if (chanctx_idx == -1) { + spin_unlock_irqrestore(&tx->lock, flags); + pr_err("%s: Unexpected channel context\n", __func__); + goto out; } + pkt_info = &dev->tx.pkt_info[chanctx_idx][desc_id]; +#endif - if (peer_id != -1) - pkts_pend = skb_queue_len(&tx->pending_pkt[peer_id][*queue]); - DEBUG_LOG("%s-UMACTX:%s pend_q = %d, sta_id = %d desc_id: %d pend:%d\n", - dev->name, - __func__, - *queue, - peer_id, - desc_id, - pkts_pend); /* Defer Tx Done Processsing */ #ifdef MULTI_CHAN_SUPPORT @@ -705,48 +871,28 @@ int uccp420wlan_tx_free_buff_req(struct mac80211_dev *dev, dev->name, skb_list); } - if (pkts_pend > 0) { - /* For a beacon queue we will process the frames irrespective - * of the current channel context. The FW will take care of - * transmitting them in the appropriate channel. Hence pass the - * interfaces channel context instead of the actual current - * channel context. + /* Reserved token */ + if (desc_id < (NUM_TX_DESCS_PER_AC * NUM_ACS)) { + start_ac = end_ac = tx_done->queue; + } else { + /* Spare token: + * Loop through all AC's */ - if (*queue == WLAN_AC_BCN) { - rcu_read_lock(); - - vif_index = (peer_id - MAX_PEERS); - ivif = rcu_dereference(dev->vifs[vif_index]); - uvif = (struct umac_vif *)(ivif->drv_priv); - curr_chanctx_idx = uvif->chanctx->index; - rcu_read_unlock(); - } - - uccp420wlan_tx_proc_pend_frms(dev, - *queue, + start_ac = WLAN_AC_VO; + end_ac = WLAN_AC_BK; + } + for (cnt = start_ac; cnt >= end_ac; cnt--) { + pkts_pend = uccp420wlan_tx_proc_pend_frms(dev, + cnt, #ifdef MULTI_CHAN_SUPPORT curr_chanctx_idx, #endif - peer_id, desc_id); - tx->outstanding_tokens[*queue]++; - - DEBUG_LOG("%s-UMACTX:Pending packets: %d, Total: %d\n", - dev->name, - pkts_pend, - skb_queue_len(skb_list)); - } else { - DEBUG_LOG("%s-UMACTX:No Pending Packets\n", dev->name); - } - - pend_pkt_q_len = skb_queue_len(&tx->pending_pkt[peer_id][*queue]); - - if ((*queue != WLAN_AC_BCN) && - (tx->queue_stopped_bmp & (1 << *queue)) && - pend_pkt_q_len < (MAX_TX_QUEUE_LEN / 2)) { - ieee80211_wake_queue(dev->hw, tx_queue_unmap(*queue)); - tx->queue_stopped_bmp &= ~(1 << (*queue)); + if (pkts_pend) { + *ac = cnt; + break; + } } /* Unmap here before release lock to avoid race */ @@ -879,35 +1025,81 @@ int uccp420wlan_tx_free_buff_req(struct mac80211_dev *dev, pkt++; } out: - return min(pkts_pend, max_tx_cmds); + return pkts_pend; } #ifdef MULTI_CHAN_SUPPORT -void uccp420wlan_proc_tx_discard_chsw(struct mac80211_dev *dev, - int curr_chanctx_idx, - struct umac_event_tx_done *tx_done) +void uccp420wlan_proc_ch_sw_event(struct umac_event_ch_switch *ch_sw_info, + void *context) +{ + struct mac80211_dev *dev = NULL; + int chan = 0; + int curr_freq = 0; + int chan_id = 0; + struct ieee80211_chanctx_conf *curr_chanctx = NULL; + int i = 0; + + if (!ch_sw_info || !context) { + pr_err("%s: Invalid Parameters:\n", __func__); + return; + } + + dev = (struct mac80211_dev *)context; + chan = ch_sw_info->chan; + + rcu_read_lock(); + + for (i = 0; i < MAX_CHANCTX; i++) { + curr_chanctx = rcu_dereference(dev->chanctx[i]); + + if (curr_chanctx) { + curr_freq = curr_chanctx->def.chan->center_freq; + + if (ieee80211_frequency_to_channel(curr_freq) == chan) { + chan_id = i; + break; + } + } + } + + rcu_read_unlock(); + + if (i == MAX_CHANCTX) { + pr_err("%s: Invalid Channel Context: chan: %d\n", + __func__, + chan); + return; + } + + /* Switch to the new channel context */ + spin_lock(&dev->chanctx_lock); + dev->curr_chanctx_idx = chan_id; + spin_unlock(&dev->chanctx_lock); + + /* We now try to xmit any frames whose xmission got cancelled due to a + * previous channel switch + */ + uccp420wlan_tx_proc_send_pend_frms_all(dev, chan_id); +} + + +unsigned int uccp420wlan_proc_tx_dscrd_chsw(struct mac80211_dev *dev, + int curr_chanctx_idx, + struct umac_event_tx_done *tx_done) { struct tx_config *tx = &dev->tx; - struct sk_buff_head *txq = NULL; - struct sk_buff_head tx_done_list; + struct sk_buff_head *txq = NULL, tx_done_list; int chanctx_idx = -1; int pkt = 0; -#ifdef notyet - int i = 0; -#endif unsigned long flags; int txq_len = 0; struct sk_buff *skb = NULL; struct sk_buff *skb_first = NULL; struct sk_buff *tmp = NULL; - int curr_bit = 0; - int pool_id = 0; int queue = 0; - int ret = 0; + int ret = 0, cnt = 0; unsigned int desc_id = 0; - int peer_id = -1; - int ac = -1; unsigned int *curr_retries = NULL; unsigned int max_retries = 0; struct ieee80211_tx_info tx_info_1st_mpdu; @@ -915,6 +1107,8 @@ void uccp420wlan_proc_tx_discard_chsw(struct mac80211_dev *dev, bool retries_exceeded = false; unsigned int *rate = NULL; unsigned int *retries = NULL; + int start_ac, end_ac; + unsigned int pkts_pend = 0; skb_queue_head_init(&tx_done_list); @@ -928,8 +1122,11 @@ void uccp420wlan_proc_tx_discard_chsw(struct mac80211_dev *dev, */ chanctx_idx = tx->desc_chan_map[desc_id]; - if (chanctx_idx == -1) { - pr_err("%s: Unexpected channel context\n", __func__); + if ((chanctx_idx == -1) || + (chanctx_idx > (MAX_CHANCTX + MAX_OFF_CHANCTX))) { + pr_err("%s: Unexpected channel context: %d\n", + __func__, + chanctx_idx); goto out; } @@ -937,7 +1134,10 @@ void uccp420wlan_proc_tx_discard_chsw(struct mac80211_dev *dev, txq_len = skb_queue_len(txq); if (!txq_len) { - pr_err("%s: TX_DONE received for empty queue\n", __func__); + pr_err("%s: TX_DONE received for empty queue: chan: %d desc_id: %d\n", + __func__, + chanctx_idx, + desc_id); goto out; } @@ -951,34 +1151,25 @@ void uccp420wlan_proc_tx_discard_chsw(struct mac80211_dev *dev, pkt = 0; skb_first = skb_peek(txq); + + if (!skb_first) { + pr_err("%s: Empty txq: chan: %d desc_id: %d\n", + __func__, + chanctx_idx, + desc_id); + goto out; + } + curr_retries = &tx->pkt_info[chanctx_idx][desc_id].curr_retries; max_retries = tx->pkt_info[chanctx_idx][desc_id].max_retries; retries = tx->pkt_info[chanctx_idx][desc_id].retries; rate = tx->pkt_info[chanctx_idx][desc_id].rate; tx->pkt_info[chanctx_idx][desc_id].adjusted_rates = true; - if ((tx_done->retries_num[0] + *curr_retries) > max_retries) { + if ((tx_done->retries_num[0] + *curr_retries) > max_retries) retries_exceeded = true; - } else { + else *curr_retries += tx_done->retries_num[0]; -#ifdef notyet - /* Adjust the counters here */ - for (i = 0; i < 4; i++) { - if (tx_done->rate[0] != rate[i]) - retries[i] = 0; - else - retries[i] -= tx_done->retries_num[0]; - - DEBUG_LOG("%s-UMACTX: %s: %d %s %d == %d retries\n", - dev->name, - __func__, - __LINE__, - "adjusted indices are", - i, - retries[i]); - } -#endif - } memcpy(&tx_info_1st_mpdu, (struct ieee80211_tx_info *)IEEE80211_SKB_CB(skb_first), @@ -1026,79 +1217,69 @@ void uccp420wlan_proc_tx_discard_chsw(struct mac80211_dev *dev, pkt++; } - if (chanctx_idx != curr_chanctx_idx) { - /* First check if there is a packet in the txq of the current - * chanctx that needs to be transmitted - */ - txq = &tx->pkt_info[curr_chanctx_idx][desc_id].pkt; - txq_len = skb_queue_len(txq); - queue = tx->pkt_info[curr_chanctx_idx][desc_id].queue; + /* First check if there is a packet in the txq of the current + * chanctx that needs to be transmitted + */ + txq = &tx->pkt_info[curr_chanctx_idx][desc_id].pkt; + txq_len = skb_queue_len(txq); + queue = tx->pkt_info[curr_chanctx_idx][desc_id].queue; + pkts_pend = txq_len; - if (txq_len) { - spin_unlock_irqrestore(&tx->lock, flags); + if (txq_len) { + spin_unlock_irqrestore(&tx->lock, flags); - /* TODO: Currently sending 0 since this param is not - * used as expected in the orig code for multiple - * frames etc Need to set this properly when the orig - * code logic is corrected + /* TODO: Currently sending 0 since this param is not + * used as expected in the orig code for multiple + * frames etc Need to set this properly when the orig + * code logic is corrected + */ + ret = __uccp420wlan_tx_frame(dev, + queue, + desc_id, + curr_chanctx_idx, + 0, + 1); + if (ret < 0) { + /* TODO: Check if we need to clear the TX bitmap + * and desc_chan_map here */ - ret = __uccp420wlan_tx_frame(dev, - queue, - desc_id, - curr_chanctx_idx, - 0, - 1); - if (ret < 0) { - /* TODO: Check if we need to clear the TX bitmap - * and desc_chan_map here - */ - pr_err("%s: Queueing of TX frame to FW failed\n", - __func__); - } else { - spin_lock_irqsave(&tx->lock, flags); - tx->desc_chan_map[desc_id] = curr_chanctx_idx; - spin_unlock_irqrestore(&tx->lock, flags); - } - - goto tx_done; - } else { - /* Check pending queue */ - /* Reserved token */ - if (desc_id < (NUM_TX_DESCS_PER_AC * NUM_ACS)) { - queue = (desc_id % NUM_ACS); - - peer_id = get_curr_peer_opp(dev, - curr_chanctx_idx, - queue); - - if (peer_id == -1) - goto done; + pr_err("%s: Queueing of TX frame to FW failed\n", + __func__); + } - /* Spare token */ - } else { - for (ac = WLAN_AC_VO; ac >= 0; ac--) { - peer_id = get_curr_peer_opp(dev, - curr_chanctx_idx, - ac); - - if (peer_id != -1) { - queue = ac; - break; - } - } + /* This is needed to avoid freeing up the token + */ + pkts_pend = 1; - if (ac < 0) - goto done; - } + goto tx_done; + } else { + /* Check pending queue */ + /* Reserved token */ + if (desc_id < (NUM_TX_DESCS_PER_AC * NUM_ACS)) { + queue = (desc_id % NUM_ACS); + start_ac = end_ac = queue; + } else { + /* Spare token: + * Loop through all AC's + */ + start_ac = WLAN_AC_VO; + end_ac = WLAN_AC_BK; + } - uccp420wlan_tx_proc_pend_frms(dev, - queue, + for (cnt = start_ac; cnt >= end_ac; cnt--) { + pkts_pend = uccp420wlan_tx_proc_pend_frms(dev, + cnt, curr_chanctx_idx, - peer_id, desc_id); + if (pkts_pend) { + queue = cnt; + break; + } + } - spin_unlock_irqrestore(&tx->lock, flags); + spin_unlock_irqrestore(&tx->lock, flags); + if (pkts_pend > 0) { /* TODO: Currently sending 0 since this param is not * used as expected in the orig code for multiple * frames etc. Need to set this properly when the orig @@ -1112,32 +1293,13 @@ void uccp420wlan_proc_tx_discard_chsw(struct mac80211_dev *dev, 0); if (ret < 0) { - /* SDK: Check if we need to clear the TX bitmap - * and desc_chan_map here - */ pr_err("%s: Queueing of TX frame to FW failed\n", __func__); - } else { - spin_lock_irqsave(&tx->lock, flags); - tx->desc_chan_map[desc_id] = curr_chanctx_idx; - spin_unlock_irqrestore(&tx->lock, flags); } - - goto tx_done; } + goto tx_done; } -done: - curr_bit = (desc_id % TX_DESC_BUCKET_BOUND); - pool_id = (desc_id / TX_DESC_BUCKET_BOUND); - - /* Mark the token as available */ - __clear_bit(curr_bit, &tx->buf_pool_bmp[pool_id]); - - tx->desc_chan_map[desc_id] = -1; - - tx->outstanding_tokens[tx_done->queue]--; - if (txq_len == 1) dev->stats->tx_cmd_send_count_single--; else @@ -1146,6 +1308,8 @@ done: out: spin_unlock_irqrestore(&tx->lock, flags); + return pkts_pend; + tx_done: skb_queue_walk_safe(&tx_done_list, skb, tmp) { tx_status(skb, @@ -1154,6 +1318,8 @@ tx_done: dev, tx_info_1st_mpdu); } + + return pkts_pend; } #endif @@ -1187,6 +1353,7 @@ void uccp420wlan_tx_init(struct mac80211_dev *dev) { int i = 0; int j = 0; + int k = 0; struct tx_config *tx = &dev->tx; memset(&tx->buf_pool_bmp, @@ -1197,8 +1364,10 @@ void uccp420wlan_tx_init(struct mac80211_dev *dev) tx->next_spare_token_ac = WLAN_AC_BE; for (i = 0; i < NUM_ACS; i++) { - for (j = 0; j < MAX_PEND_Q_PER_AC; j++) - skb_queue_head_init(&tx->pending_pkt[j][i]); + for (j = 0; j < MAX_PEND_Q_PER_AC; j++) { + for (k = 0; k < MAX_UMAC_VIF_CHANCTX_TYPES; k++) + skb_queue_head_init(&tx->pending_pkt[k][j][i]); + } tx->outstanding_tokens[i] = 0; } @@ -1207,7 +1376,7 @@ void uccp420wlan_tx_init(struct mac80211_dev *dev) #ifdef MULTI_CHAN_SUPPORT tx->desc_chan_map[i] = -1; - for (j = 0; j < MAX_CHANCTX; j++) + for (j = 0; j < MAX_CHANCTX + MAX_OFF_CHANCTX ; j++) skb_queue_head_init(&tx->pkt_info[j][i].pkt); #else skb_queue_head_init(&tx->pkt_info[i].pkt); @@ -1228,10 +1397,12 @@ void uccp420wlan_tx_init(struct mac80211_dev *dev) tx->persec_timer.function = print_persec_stats; mod_timer(&tx->persec_timer, jiffies + msecs_to_jiffies(1000)); #endif + dev->curr_chanctx_idx = -1; spin_lock_init(&tx->lock); ieee80211_wake_queues(dev->hw); - DEBUG_LOG("%s-UMACTX:Initialization successful\n", dev->name); + DEBUG_LOG("%s-UMACTX: initialization successful\n", + UMACTX_TO_MACDEV(tx)->name); } @@ -1239,9 +1410,12 @@ void uccp420wlan_tx_deinit(struct mac80211_dev *dev) { int i = 0; int j = 0; - unsigned long flags = 0; + int k = 0; + unsigned long flags; struct tx_config *tx = &dev->tx; - struct sk_buff *skb; + struct sk_buff *skb = NULL; + unsigned int qlen = 0; + struct sk_buff_head *pend_q = NULL; ieee80211_stop_queues(dev->hw); @@ -1251,10 +1425,17 @@ void uccp420wlan_tx_deinit(struct mac80211_dev *dev) for (i = 0; i < NUM_TX_DESCS; i++) { #ifdef MULTI_CHAN_SUPPORT - for (j = 0; j < MAX_CHANCTX; j++) - while ((skb = skb_dequeue(&tx->pkt_info[j][i].pkt)) != - NULL) - dev_kfree_skb_any(skb); + for (j = 0; j < MAX_CHANCTX + MAX_OFF_CHANCTX; j++) { + qlen = skb_queue_len(&tx->pkt_info[j][i].pkt); + + if (qlen) { + while ((skb = + skb_dequeue(&tx->pkt_info[j][i].pkt)) != + NULL) { + dev_kfree_skb_any(skb); + } + } + } #else while ((skb = skb_dequeue(&tx->pkt_info[i].pkt)) != NULL) dev_kfree_skb_any(skb); @@ -1263,16 +1444,19 @@ void uccp420wlan_tx_deinit(struct mac80211_dev *dev) for (i = 0; i < NUM_ACS; i++) { for (j = 0; j < MAX_PEND_Q_PER_AC; j++) { - while ((skb = - skb_dequeue(&tx->pending_pkt[j][i])) != - NULL) - dev_kfree_skb_any(skb); + for (k = 0; k < MAX_UMAC_VIF_CHANCTX_TYPES; k++) { + pend_q = &tx->pending_pkt[k][j][i]; + + while ((skb = skb_dequeue(pend_q)) != NULL) + dev_kfree_skb_any(skb); + } } } spin_unlock_irqrestore(&tx->lock, flags); - DEBUG_LOG("%s-UMACTX:Deinitialization successful\n", dev->name); + DEBUG_LOG("%s-UMACTX: deinitialization successful\n", + UMACTX_TO_MACDEV(tx)->name); } @@ -1304,6 +1488,7 @@ int __uccp420wlan_tx_frame(struct mac80211_dev *dev, tx_done.descriptor_id = token_id; tx_done.queue = queue; + dev->tx.desc_chan_map[token_id] = curr_chanctx_idx; #ifdef MULTI_CHAN_SUPPORT txq = &dev->tx.pkt_info[curr_chanctx_idx][token_id].pkt; @@ -1344,6 +1529,9 @@ int uccp420wlan_tx_frame(struct sk_buff *skb, struct umac_vif *uvif = NULL; struct umac_sta *usta = NULL; int peer_id = -1; +#ifdef MULTI_CHAN_SUPPORT + int off_chanctx_idx; +#endif uvif = (struct umac_vif *)(tx_info->control.vif->drv_priv); @@ -1357,21 +1545,27 @@ int uccp420wlan_tx_frame(struct sk_buff *skb, if (bcast == false) { queue = tx_queue_map(skb->queue_mapping); more_frames = 0; + dev->stats->tx_cmds_from_stack++; } else { queue = WLAN_AC_BCN; /* Hack: skb->priority is used to indicate more frames */ more_frames = skb->priority; } - dev->stats->tx_cmds_from_stack++; if (dev->params->production_test == 1) tx_info->flags |= IEEE80211_TX_CTL_AMPDU; - if (tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { - /* These are high priority frames, send them in VO */ - queue = WLAN_AC_VO; + if ((tx_info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || + (uvif->chanctx && + uvif->chanctx->index == dev->roc_off_chanctx_idx)) { atomic_inc(&dev->roc_params.roc_mgmt_tx_count); + off_chanctx_idx = UMAC_VIF_CHANCTX_TYPE_OFF; + DEBUG_LOG("%s-UMACTX: Sending OFFCHAN Frame: %d\n", + dev->name, + atomic_read(&dev->roc_params.roc_mgmt_tx_count)); + } else { + off_chanctx_idx = UMAC_VIF_CHANCTX_TYPE_OPER; } mac_hdr = (struct ieee80211_hdr *)(skb->data); @@ -1385,10 +1579,10 @@ int uccp420wlan_tx_frame(struct sk_buff *skb, skb->queue_mapping, ieee80211_is_beacon(mac_hdr->frame_control)); - token_id = uccp420wlan_tx_alloc_buff_req(dev, + token_id = uccp420wlan_tx_alloc_token(dev, queue, #ifdef MULTI_CHAN_SUPPORT - uvif, + off_chanctx_idx, curr_chanctx_idx, #endif peer_id, @@ -1465,19 +1659,23 @@ void uccp420wlan_tx_complete(struct umac_event_tx_done *tx_done, qlen = skb_queue_len(&dev->tx.pkt_info[token_id].pkt); #endif - DEBUG_LOG("%s-UMACTX:TX Done Rx for desc_id: %d qlen: %d\n", + DEBUG_LOG("%s-UMACTX:TX Done Rx for desc_id: %d Q: %d qlen: %d ", dev->name, tx_done->descriptor_id, - qlen); + tx_done->queue, qlen); + DEBUG_LOG("status: %d chactx: %d out_tok: %d\n", + tx_done->frm_status[0], + curr_chanctx_idx, + dev->tx.outstanding_tokens[tx_done->queue]); update_aux_adc_voltage(dev, tx_done->pdout_voltage); #ifdef MULTI_CHAN_SUPPORT if (tx_done->frm_status[0] == TX_DONE_STAT_DISCARD_CHSW) { - uccp420wlan_proc_tx_discard_chsw(dev, - curr_chanctx_idx, - tx_done); - return; + pkts_pending = uccp420wlan_proc_tx_dscrd_chsw(dev, + curr_chanctx_idx, + tx_done); + goto out; } #endif pkts_pending = uccp420wlan_tx_free_buff_req(dev, @@ -1490,12 +1688,6 @@ void uccp420wlan_tx_complete(struct umac_event_tx_done *tx_done, if (pkts_pending) { /*TODO..Do we need to check each skb for more_frames??*/ -#if 0 - if ((queue == WLAN_AC_BCN) && (skb->priority == 1)) - more_frames = 1; - else - more_frames = 0; -#endif more_frames = 0; DEBUG_LOG("%s-UMACTX:%s:%d Transfer Pending Frames:\n", @@ -1515,6 +1707,13 @@ void uccp420wlan_tx_complete(struct umac_event_tx_done *tx_done, DEBUG_LOG("%s-UMACTX:No Pending Packets\n", dev->name); } +out: + if (!pkts_pending) { + /* Mark the token as available */ + free_token(dev, token_id, tx_done->queue); + dev->tx.desc_chan_map[token_id] = -1; + } + for (vif_index = 0; vif_index < MAX_VIFS; vif_index++) { if (vif_index_bitmap & (1 << vif_index)) { memset(&noa_event, 0, sizeof(noa_event)); @@ -1526,3 +1725,191 @@ void uccp420wlan_tx_complete(struct umac_event_tx_done *tx_done, } } } + + +static int uccp420_flush_vif_all_pend_q(struct mac80211_dev *dev, + struct umac_vif *uvif, + unsigned int hw_queue_map, + enum UMAC_VIF_CHANCTX_TYPE chanctx_type) +{ + unsigned int pending = 0; + int count = 0; + int peer_id = -1; + unsigned int queue = 0; + int pend_q = 0; + unsigned long flags; + struct sk_buff_head *pend_pkt_q = NULL; + struct tx_config *tx = NULL; + struct ieee80211_sta *sta = NULL; + struct umac_sta *usta = NULL; + + tx = &dev->tx; + + if (!uvif->chanctx) { + DEBUG_LOG("%s-UMACTX: Chanctx NULL, returning\n", dev->name); + return -1; + } + + for (queue = 0; queue < NUM_ACS; queue++) { + if (!(BIT(queue) & hw_queue_map)) + continue; + + for (pend_q = 0; pend_q < MAX_PEND_Q_PER_AC; pend_q++) { + if (pend_q < MAX_PEERS) { + rcu_read_lock(); + sta = rcu_dereference(dev->peers[pend_q]); + + if (!sta) { + rcu_read_unlock(); + continue; + } + + usta = (struct umac_sta *)(sta->drv_priv); + + if (usta->vif_index == uvif->vif_index) + peer_id = pend_q; + else { + rcu_read_unlock(); + continue; + } + + rcu_read_unlock(); + } else if (pend_q == uvif->vif_index) + peer_id = uvif->vif_index; + else + continue; + + while (1) { + spin_lock_irqsave(&tx->lock, flags); + + pend_pkt_q = + &tx->pending_pkt[chanctx_type] + [peer_id] + [queue]; + + /* Assuming all packets for the peer have same + * channel context + */ + pending = skb_queue_len(pend_pkt_q); + + spin_unlock_irqrestore(&tx->lock, flags); + + if (!pending) + break; + + if (count >= QUEUE_FLUSH_TIMEOUT_TICKS) + break; + + current->state = TASK_INTERRUPTIBLE; + + if (0 == schedule_timeout(1)) + count++; + + } + + if (pending) { + pr_err("%s-UMACTX: Failed for VIF: %d and Queue: %d, pending: %d\n", + dev->name, + uvif->vif_index, + queue, + pending); + + return -1; + } + } + } + + DEBUG_LOG("%s-UMACTX: Success for VIF: %d and Queue: %d\n", + dev->name, + uvif->vif_index, + queue); + return 0; +} + + +static int uccp420_flush_vif_tx_queues(struct mac80211_dev *dev, + struct umac_vif *uvif, + int chanctx_idx, + unsigned int hw_queue_map) +{ + unsigned int tokens = 0; + unsigned int i = 0; + unsigned long buf_pool_bmp = 0; + unsigned long flags; + struct tx_pkt_info *pkt_info = NULL; + struct tx_config *tx = NULL; + int count = 0; + + tx = &dev->tx; + + spin_lock_irqsave(&tx->lock, flags); + + for (i = 0; i < NUM_TX_DESCS; i++) { + pkt_info = &tx->pkt_info[chanctx_idx][i]; + + if ((pkt_info->vif_index == uvif->vif_index) && + (BIT(pkt_info->queue) & hw_queue_map)) + tokens |= BIT(i); + } + + spin_unlock_irqrestore(&tx->lock, flags); + + if (!tokens) + return 0; + + while (1) { + spin_lock_irqsave(&tx->lock, flags); + buf_pool_bmp = tx->buf_pool_bmp[0]; + spin_unlock_irqrestore(&tx->lock, flags); + + if (!(buf_pool_bmp & tokens)) + break; + + if (count >= QUEUE_FLUSH_TIMEOUT_TICKS) + break; + + current->state = TASK_INTERRUPTIBLE; + + if (0 == schedule_timeout(1)) + count++; + } + + if (buf_pool_bmp & tokens) { + pr_err("%s-UMACTX: Failed for VIF: %d, buf_pool_bmp : 0x%lx\n", + dev->name, + uvif->vif_index, + buf_pool_bmp); + + return -1; + } + + DEBUG_LOG("%s-UMACTX: Success for VIF: %d, buf_pool_bmp : 0x%lx\n", + dev->name, + uvif->vif_index, + buf_pool_bmp); + return 0; +} + + +int uccp420_flush_vif_queues(struct mac80211_dev *dev, + struct umac_vif *uvif, + int chanctx_idx, + unsigned int hw_queue_map, + enum UMAC_VIF_CHANCTX_TYPE vif_chanctx_type) +{ + int result = -1; + + result = uccp420_flush_vif_all_pend_q(dev, + uvif, + hw_queue_map, + vif_chanctx_type); + + if (result == 0) { + result = uccp420_flush_vif_tx_queues(dev, + uvif, + chanctx_idx, + hw_queue_map); + } + + return result; +} |