12fc4c9ffSLee Jones /* 2dad0d04fSFariya Fatima * Copyright (c) 2014 Redpine Signals Inc. 3dad0d04fSFariya Fatima * 4dad0d04fSFariya Fatima * Permission to use, copy, modify, and/or distribute this software for any 5dad0d04fSFariya Fatima * purpose with or without fee is hereby granted, provided that the above 6dad0d04fSFariya Fatima * copyright notice and this permission notice appear in all copies. 7dad0d04fSFariya Fatima * 8dad0d04fSFariya Fatima * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9dad0d04fSFariya Fatima * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10dad0d04fSFariya Fatima * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11dad0d04fSFariya Fatima * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12dad0d04fSFariya Fatima * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13dad0d04fSFariya Fatima * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14dad0d04fSFariya Fatima * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15dad0d04fSFariya Fatima */ 16dad0d04fSFariya Fatima 17dad0d04fSFariya Fatima #include "rsi_mgmt.h" 18dad0d04fSFariya Fatima #include "rsi_common.h" 19d26a9559SPrameela Rani Garnepudi #include "rsi_hal.h" 20716b840cSSiva Rebbagondla #include "rsi_coex.h" 21dad0d04fSFariya Fatima 22dad0d04fSFariya Fatima /** 23dad0d04fSFariya Fatima * rsi_determine_min_weight_queue() - This function determines the queue with 24dad0d04fSFariya Fatima * the min weight. 25dad0d04fSFariya Fatima * @common: Pointer to the driver private structure. 26dad0d04fSFariya Fatima * 27dad0d04fSFariya Fatima * Return: q_num: Corresponding queue number. 28dad0d04fSFariya Fatima */ 29dad0d04fSFariya Fatima static u8 rsi_determine_min_weight_queue(struct rsi_common *common) 30dad0d04fSFariya Fatima { 31dad0d04fSFariya Fatima struct wmm_qinfo *tx_qinfo = common->tx_qinfo; 32dad0d04fSFariya Fatima u32 q_len = 0; 33dad0d04fSFariya Fatima u8 ii = 0; 34dad0d04fSFariya Fatima 35dad0d04fSFariya Fatima for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { 36dad0d04fSFariya Fatima q_len = skb_queue_len(&common->tx_queue[ii]); 37dad0d04fSFariya Fatima if ((tx_qinfo[ii].pkt_contended) && q_len) { 38dad0d04fSFariya Fatima common->min_weight = tx_qinfo[ii].weight; 39dad0d04fSFariya Fatima break; 40dad0d04fSFariya Fatima } 41dad0d04fSFariya Fatima } 42dad0d04fSFariya Fatima return ii; 43dad0d04fSFariya Fatima } 44dad0d04fSFariya Fatima 45dad0d04fSFariya Fatima /** 46dad0d04fSFariya Fatima * rsi_recalculate_weights() - This function recalculates the weights 47dad0d04fSFariya Fatima * corresponding to each queue. 48dad0d04fSFariya Fatima * @common: Pointer to the driver private structure. 49dad0d04fSFariya Fatima * 50dad0d04fSFariya Fatima * Return: recontend_queue bool variable 51dad0d04fSFariya Fatima */ 52dad0d04fSFariya Fatima static bool rsi_recalculate_weights(struct rsi_common *common) 53dad0d04fSFariya Fatima { 54dad0d04fSFariya Fatima struct wmm_qinfo *tx_qinfo = common->tx_qinfo; 55dad0d04fSFariya Fatima bool recontend_queue = false; 56dad0d04fSFariya Fatima u8 ii = 0; 57dad0d04fSFariya Fatima u32 q_len = 0; 58dad0d04fSFariya Fatima 59dad0d04fSFariya Fatima for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { 60dad0d04fSFariya Fatima q_len = skb_queue_len(&common->tx_queue[ii]); 61dad0d04fSFariya Fatima /* Check for the need of contention */ 62dad0d04fSFariya Fatima if (q_len) { 63dad0d04fSFariya Fatima if (tx_qinfo[ii].pkt_contended) { 64dad0d04fSFariya Fatima tx_qinfo[ii].weight = 65dad0d04fSFariya Fatima ((tx_qinfo[ii].weight > common->min_weight) ? 66dad0d04fSFariya Fatima tx_qinfo[ii].weight - common->min_weight : 0); 67dad0d04fSFariya Fatima } else { 68dad0d04fSFariya Fatima tx_qinfo[ii].pkt_contended = 1; 69dad0d04fSFariya Fatima tx_qinfo[ii].weight = tx_qinfo[ii].wme_params; 70dad0d04fSFariya Fatima recontend_queue = true; 71dad0d04fSFariya Fatima } 72dad0d04fSFariya Fatima } else { /* No packets so no contention */ 73dad0d04fSFariya Fatima tx_qinfo[ii].weight = 0; 74dad0d04fSFariya Fatima tx_qinfo[ii].pkt_contended = 0; 75dad0d04fSFariya Fatima } 76dad0d04fSFariya Fatima } 77dad0d04fSFariya Fatima 78dad0d04fSFariya Fatima return recontend_queue; 79dad0d04fSFariya Fatima } 80dad0d04fSFariya Fatima 81dad0d04fSFariya Fatima /** 82360accb0SJahnavi Meher * rsi_get_num_pkts_dequeue() - This function determines the number of 83360accb0SJahnavi Meher * packets to be dequeued based on the number 84360accb0SJahnavi Meher * of bytes calculated using txop. 85360accb0SJahnavi Meher * 86360accb0SJahnavi Meher * @common: Pointer to the driver private structure. 87360accb0SJahnavi Meher * @q_num: the queue from which pkts have to be dequeued 88360accb0SJahnavi Meher * 89360accb0SJahnavi Meher * Return: pkt_num: Number of pkts to be dequeued. 90360accb0SJahnavi Meher */ 91360accb0SJahnavi Meher static u32 rsi_get_num_pkts_dequeue(struct rsi_common *common, u8 q_num) 92360accb0SJahnavi Meher { 93360accb0SJahnavi Meher struct rsi_hw *adapter = common->priv; 94360accb0SJahnavi Meher struct sk_buff *skb; 95360accb0SJahnavi Meher u32 pkt_cnt = 0; 96360accb0SJahnavi Meher s16 txop = common->tx_qinfo[q_num].txop * 32; 97d51193d4SJahnavi Meher __le16 r_txop; 98360accb0SJahnavi Meher struct ieee80211_rate rate; 99eac4eed3SPrameela Rani Garnepudi struct ieee80211_hdr *wh; 100eac4eed3SPrameela Rani Garnepudi struct ieee80211_vif *vif; 101360accb0SJahnavi Meher 102360accb0SJahnavi Meher rate.bitrate = RSI_RATE_MCS0 * 5 * 10; /* Convert to Kbps */ 103360accb0SJahnavi Meher if (q_num == VI_Q) 104360accb0SJahnavi Meher txop = ((txop << 5) / 80); 105360accb0SJahnavi Meher 106360accb0SJahnavi Meher if (skb_queue_len(&common->tx_queue[q_num])) 107360accb0SJahnavi Meher skb = skb_peek(&common->tx_queue[q_num]); 108360accb0SJahnavi Meher else 109360accb0SJahnavi Meher return 0; 110360accb0SJahnavi Meher 111360accb0SJahnavi Meher do { 112eac4eed3SPrameela Rani Garnepudi wh = (struct ieee80211_hdr *)skb->data; 113eac4eed3SPrameela Rani Garnepudi vif = rsi_get_vif(adapter, wh->addr2); 114d51193d4SJahnavi Meher r_txop = ieee80211_generic_frame_duration(adapter->hw, 115eac4eed3SPrameela Rani Garnepudi vif, 116360accb0SJahnavi Meher common->band, 117360accb0SJahnavi Meher skb->len, &rate); 118d51193d4SJahnavi Meher txop -= le16_to_cpu(r_txop); 119360accb0SJahnavi Meher pkt_cnt += 1; 120360accb0SJahnavi Meher /*checking if pkts are still there*/ 121360accb0SJahnavi Meher if (skb_queue_len(&common->tx_queue[q_num]) - pkt_cnt) 122360accb0SJahnavi Meher skb = skb->next; 123360accb0SJahnavi Meher else 124360accb0SJahnavi Meher break; 125360accb0SJahnavi Meher 126360accb0SJahnavi Meher } while (txop > 0); 127360accb0SJahnavi Meher 128360accb0SJahnavi Meher return pkt_cnt; 129360accb0SJahnavi Meher } 130360accb0SJahnavi Meher 131360accb0SJahnavi Meher /** 132dad0d04fSFariya Fatima * rsi_core_determine_hal_queue() - This function determines the queue from 133dad0d04fSFariya Fatima * which packet has to be dequeued. 134dad0d04fSFariya Fatima * @common: Pointer to the driver private structure. 135dad0d04fSFariya Fatima * 136dad0d04fSFariya Fatima * Return: q_num: Corresponding queue number on success. 137dad0d04fSFariya Fatima */ 138dad0d04fSFariya Fatima static u8 rsi_core_determine_hal_queue(struct rsi_common *common) 139dad0d04fSFariya Fatima { 140dad0d04fSFariya Fatima bool recontend_queue = false; 141dad0d04fSFariya Fatima u32 q_len = 0; 142dad0d04fSFariya Fatima u8 q_num = INVALID_QUEUE; 143360accb0SJahnavi Meher u8 ii = 0; 144dad0d04fSFariya Fatima 145d26a9559SPrameela Rani Garnepudi if (skb_queue_len(&common->tx_queue[MGMT_BEACON_Q])) { 146d26a9559SPrameela Rani Garnepudi q_num = MGMT_BEACON_Q; 147d26a9559SPrameela Rani Garnepudi return q_num; 148d26a9559SPrameela Rani Garnepudi } 149dad0d04fSFariya Fatima if (skb_queue_len(&common->tx_queue[MGMT_SOFT_Q])) { 150dad0d04fSFariya Fatima if (!common->mgmt_q_block) 151dad0d04fSFariya Fatima q_num = MGMT_SOFT_Q; 152dad0d04fSFariya Fatima return q_num; 153dad0d04fSFariya Fatima } 154dad0d04fSFariya Fatima 155360accb0SJahnavi Meher if (common->hw_data_qs_blocked) 156360accb0SJahnavi Meher return q_num; 157360accb0SJahnavi Meher 158dad0d04fSFariya Fatima if (common->pkt_cnt != 0) { 159dad0d04fSFariya Fatima --common->pkt_cnt; 160dad0d04fSFariya Fatima return common->selected_qnum; 161dad0d04fSFariya Fatima } 162dad0d04fSFariya Fatima 163dad0d04fSFariya Fatima get_queue_num: 164dad0d04fSFariya Fatima recontend_queue = false; 165dad0d04fSFariya Fatima 166dad0d04fSFariya Fatima q_num = rsi_determine_min_weight_queue(common); 1675156fd24SFariya Fatima 168dad0d04fSFariya Fatima ii = q_num; 169dad0d04fSFariya Fatima 170dad0d04fSFariya Fatima /* Selecting the queue with least back off */ 171dad0d04fSFariya Fatima for (; ii < NUM_EDCA_QUEUES; ii++) { 172360accb0SJahnavi Meher q_len = skb_queue_len(&common->tx_queue[ii]); 173dad0d04fSFariya Fatima if (((common->tx_qinfo[ii].pkt_contended) && 174360accb0SJahnavi Meher (common->tx_qinfo[ii].weight < common->min_weight)) && 175360accb0SJahnavi Meher q_len) { 176360accb0SJahnavi Meher common->min_weight = common->tx_qinfo[ii].weight; 177dad0d04fSFariya Fatima q_num = ii; 178dad0d04fSFariya Fatima } 179dad0d04fSFariya Fatima } 180dad0d04fSFariya Fatima 1815156fd24SFariya Fatima if (q_num < NUM_EDCA_QUEUES) 182dad0d04fSFariya Fatima common->tx_qinfo[q_num].pkt_contended = 0; 1835156fd24SFariya Fatima 184dad0d04fSFariya Fatima /* Adjust the back off values for all queues again */ 185dad0d04fSFariya Fatima recontend_queue = rsi_recalculate_weights(common); 186dad0d04fSFariya Fatima 187dad0d04fSFariya Fatima q_len = skb_queue_len(&common->tx_queue[q_num]); 188dad0d04fSFariya Fatima if (!q_len) { 189dad0d04fSFariya Fatima /* If any queues are freshly contended and the selected queue 190dad0d04fSFariya Fatima * doesn't have any packets 191dad0d04fSFariya Fatima * then get the queue number again with fresh values 192dad0d04fSFariya Fatima */ 193dad0d04fSFariya Fatima if (recontend_queue) 194dad0d04fSFariya Fatima goto get_queue_num; 195dad0d04fSFariya Fatima 196*d48aea60Swengjianfeng return INVALID_QUEUE; 197dad0d04fSFariya Fatima } 198dad0d04fSFariya Fatima 199dad0d04fSFariya Fatima common->selected_qnum = q_num; 200dad0d04fSFariya Fatima q_len = skb_queue_len(&common->tx_queue[q_num]); 201dad0d04fSFariya Fatima 202360accb0SJahnavi Meher if (q_num == VO_Q || q_num == VI_Q) { 203360accb0SJahnavi Meher common->pkt_cnt = rsi_get_num_pkts_dequeue(common, q_num); 204360accb0SJahnavi Meher common->pkt_cnt -= 1; 205d51193d4SJahnavi Meher } 206dad0d04fSFariya Fatima 207dad0d04fSFariya Fatima return q_num; 208dad0d04fSFariya Fatima } 209dad0d04fSFariya Fatima 210dad0d04fSFariya Fatima /** 211dad0d04fSFariya Fatima * rsi_core_queue_pkt() - This functions enqueues the packet to the queue 212dad0d04fSFariya Fatima * specified by the queue number. 213dad0d04fSFariya Fatima * @common: Pointer to the driver private structure. 214dad0d04fSFariya Fatima * @skb: Pointer to the socket buffer structure. 215dad0d04fSFariya Fatima * 216dad0d04fSFariya Fatima * Return: None. 217dad0d04fSFariya Fatima */ 218dad0d04fSFariya Fatima static void rsi_core_queue_pkt(struct rsi_common *common, 219dad0d04fSFariya Fatima struct sk_buff *skb) 220dad0d04fSFariya Fatima { 221dad0d04fSFariya Fatima u8 q_num = skb->priority; 222dad0d04fSFariya Fatima if (q_num >= NUM_SOFT_QUEUES) { 223dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n", 224dad0d04fSFariya Fatima __func__, q_num); 225dad0d04fSFariya Fatima dev_kfree_skb(skb); 226dad0d04fSFariya Fatima return; 227dad0d04fSFariya Fatima } 228dad0d04fSFariya Fatima 229dad0d04fSFariya Fatima skb_queue_tail(&common->tx_queue[q_num], skb); 230dad0d04fSFariya Fatima } 231dad0d04fSFariya Fatima 232dad0d04fSFariya Fatima /** 233dad0d04fSFariya Fatima * rsi_core_dequeue_pkt() - This functions dequeues the packet from the queue 234dad0d04fSFariya Fatima * specified by the queue number. 235dad0d04fSFariya Fatima * @common: Pointer to the driver private structure. 236dad0d04fSFariya Fatima * @q_num: Queue number. 237dad0d04fSFariya Fatima * 238dad0d04fSFariya Fatima * Return: Pointer to sk_buff structure. 239dad0d04fSFariya Fatima */ 240dad0d04fSFariya Fatima static struct sk_buff *rsi_core_dequeue_pkt(struct rsi_common *common, 241dad0d04fSFariya Fatima u8 q_num) 242dad0d04fSFariya Fatima { 243dad0d04fSFariya Fatima if (q_num >= NUM_SOFT_QUEUES) { 244dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Invalid Queue Number: q_num = %d\n", 245dad0d04fSFariya Fatima __func__, q_num); 246dad0d04fSFariya Fatima return NULL; 247dad0d04fSFariya Fatima } 248dad0d04fSFariya Fatima 249dad0d04fSFariya Fatima return skb_dequeue(&common->tx_queue[q_num]); 250dad0d04fSFariya Fatima } 251dad0d04fSFariya Fatima 252dad0d04fSFariya Fatima /** 253dad0d04fSFariya Fatima * rsi_core_qos_processor() - This function is used to determine the wmm queue 254dad0d04fSFariya Fatima * based on the backoff procedure. Data packets are 255dad0d04fSFariya Fatima * dequeued from the selected hal queue and sent to 256dad0d04fSFariya Fatima * the below layers. 257dad0d04fSFariya Fatima * @common: Pointer to the driver private structure. 258dad0d04fSFariya Fatima * 259dad0d04fSFariya Fatima * Return: None. 260dad0d04fSFariya Fatima */ 261dad0d04fSFariya Fatima void rsi_core_qos_processor(struct rsi_common *common) 262dad0d04fSFariya Fatima { 263dad0d04fSFariya Fatima struct rsi_hw *adapter = common->priv; 264dad0d04fSFariya Fatima struct sk_buff *skb; 265dad0d04fSFariya Fatima unsigned long tstamp_1, tstamp_2; 266dad0d04fSFariya Fatima u8 q_num; 267dad0d04fSFariya Fatima int status; 268dad0d04fSFariya Fatima 269dad0d04fSFariya Fatima tstamp_1 = jiffies; 270dad0d04fSFariya Fatima while (1) { 271dad0d04fSFariya Fatima q_num = rsi_core_determine_hal_queue(common); 272dad0d04fSFariya Fatima rsi_dbg(DATA_TX_ZONE, 273dad0d04fSFariya Fatima "%s: Queue number = %d\n", __func__, q_num); 274dad0d04fSFariya Fatima 275dad0d04fSFariya Fatima if (q_num == INVALID_QUEUE) { 276dad0d04fSFariya Fatima rsi_dbg(DATA_TX_ZONE, "%s: No More Pkt\n", __func__); 277dad0d04fSFariya Fatima break; 278dad0d04fSFariya Fatima } 279b6c8d06cSKarun Eagalapati if (common->hibernate_resume) 280b6c8d06cSKarun Eagalapati break; 281dad0d04fSFariya Fatima 282cb164535SKarun Eagalapati mutex_lock(&common->tx_lock); 283dad0d04fSFariya Fatima 284dad0d04fSFariya Fatima status = adapter->check_hw_queue_status(adapter, q_num); 285dad0d04fSFariya Fatima if ((status <= 0)) { 286cb164535SKarun Eagalapati mutex_unlock(&common->tx_lock); 287dad0d04fSFariya Fatima break; 288dad0d04fSFariya Fatima } 289dad0d04fSFariya Fatima 290dad0d04fSFariya Fatima if ((q_num < MGMT_SOFT_Q) && 291dad0d04fSFariya Fatima ((skb_queue_len(&common->tx_queue[q_num])) <= 292dad0d04fSFariya Fatima MIN_DATA_QUEUE_WATER_MARK)) { 293dad0d04fSFariya Fatima if (ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) 294dad0d04fSFariya Fatima ieee80211_wake_queue(adapter->hw, 295dad0d04fSFariya Fatima WME_AC(q_num)); 296dad0d04fSFariya Fatima } 297dad0d04fSFariya Fatima 298dad0d04fSFariya Fatima skb = rsi_core_dequeue_pkt(common, q_num); 299dad0d04fSFariya Fatima if (skb == NULL) { 300258587f9SJahnavi Meher rsi_dbg(ERR_ZONE, "skb null\n"); 301cb164535SKarun Eagalapati mutex_unlock(&common->tx_lock); 302dad0d04fSFariya Fatima break; 303dad0d04fSFariya Fatima } 304716b840cSSiva Rebbagondla if (q_num == MGMT_BEACON_Q) { 305d26a9559SPrameela Rani Garnepudi status = rsi_send_pkt_to_bus(common, skb); 306d26a9559SPrameela Rani Garnepudi dev_kfree_skb(skb); 307d26a9559SPrameela Rani Garnepudi } else { 308716b840cSSiva Rebbagondla #ifdef CONFIG_RSI_COEX 309716b840cSSiva Rebbagondla if (common->coex_mode > 1) { 310716b840cSSiva Rebbagondla status = rsi_coex_send_pkt(common, skb, 311716b840cSSiva Rebbagondla RSI_WLAN_Q); 312716b840cSSiva Rebbagondla } else { 313716b840cSSiva Rebbagondla #endif 314716b840cSSiva Rebbagondla if (q_num == MGMT_SOFT_Q) 315716b840cSSiva Rebbagondla status = rsi_send_mgmt_pkt(common, skb); 316716b840cSSiva Rebbagondla else 317dad0d04fSFariya Fatima status = rsi_send_data_pkt(common, skb); 318716b840cSSiva Rebbagondla #ifdef CONFIG_RSI_COEX 319716b840cSSiva Rebbagondla } 320716b840cSSiva Rebbagondla #endif 321d26a9559SPrameela Rani Garnepudi } 322dad0d04fSFariya Fatima 323dad0d04fSFariya Fatima if (status) { 324cb164535SKarun Eagalapati mutex_unlock(&common->tx_lock); 325dad0d04fSFariya Fatima break; 326dad0d04fSFariya Fatima } 327dad0d04fSFariya Fatima 328dad0d04fSFariya Fatima common->tx_stats.total_tx_pkt_send[q_num]++; 329dad0d04fSFariya Fatima 330dad0d04fSFariya Fatima tstamp_2 = jiffies; 331cb164535SKarun Eagalapati mutex_unlock(&common->tx_lock); 332dad0d04fSFariya Fatima 333c07036f1SKarim Eshapa if (time_after(tstamp_2, tstamp_1 + (300 * HZ) / 1000)) 334dad0d04fSFariya Fatima schedule(); 335dad0d04fSFariya Fatima } 336dad0d04fSFariya Fatima } 337dad0d04fSFariya Fatima 33819844c0aSPrameela Rani Garnepudi struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr) 33919844c0aSPrameela Rani Garnepudi { 34019844c0aSPrameela Rani Garnepudi int i; 34119844c0aSPrameela Rani Garnepudi 34219844c0aSPrameela Rani Garnepudi for (i = 0; i < common->max_stations; i++) { 34319844c0aSPrameela Rani Garnepudi if (!common->stations[i].sta) 34419844c0aSPrameela Rani Garnepudi continue; 34519844c0aSPrameela Rani Garnepudi if (!(memcmp(common->stations[i].sta->addr, 34619844c0aSPrameela Rani Garnepudi mac_addr, ETH_ALEN))) 34719844c0aSPrameela Rani Garnepudi return &common->stations[i]; 34819844c0aSPrameela Rani Garnepudi } 34919844c0aSPrameela Rani Garnepudi return NULL; 35019844c0aSPrameela Rani Garnepudi } 35119844c0aSPrameela Rani Garnepudi 352df771911SPrameela Rani Garnepudi struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac) 353df771911SPrameela Rani Garnepudi { 354df771911SPrameela Rani Garnepudi struct ieee80211_vif *vif; 355df771911SPrameela Rani Garnepudi int i; 356df771911SPrameela Rani Garnepudi 357df771911SPrameela Rani Garnepudi for (i = 0; i < RSI_MAX_VIFS; i++) { 358df771911SPrameela Rani Garnepudi vif = adapter->vifs[i]; 359df771911SPrameela Rani Garnepudi if (!vif) 360df771911SPrameela Rani Garnepudi continue; 361df771911SPrameela Rani Garnepudi if (!memcmp(vif->addr, mac, ETH_ALEN)) 362df771911SPrameela Rani Garnepudi return vif; 363df771911SPrameela Rani Garnepudi } 364df771911SPrameela Rani Garnepudi return NULL; 365df771911SPrameela Rani Garnepudi } 366df771911SPrameela Rani Garnepudi 367dad0d04fSFariya Fatima /** 368dad0d04fSFariya Fatima * rsi_core_xmit() - This function transmits the packets received from mac80211 369dad0d04fSFariya Fatima * @common: Pointer to the driver private structure. 370dad0d04fSFariya Fatima * @skb: Pointer to the socket buffer structure. 371dad0d04fSFariya Fatima * 372dad0d04fSFariya Fatima * Return: None. 373dad0d04fSFariya Fatima */ 374dad0d04fSFariya Fatima void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) 375dad0d04fSFariya Fatima { 376dad0d04fSFariya Fatima struct rsi_hw *adapter = common->priv; 377dad0d04fSFariya Fatima struct ieee80211_tx_info *info; 378dad0d04fSFariya Fatima struct skb_info *tx_params; 3794671c209SPrameela Rani Garnepudi struct ieee80211_hdr *wh = NULL; 3804671c209SPrameela Rani Garnepudi struct ieee80211_vif *vif; 381dad0d04fSFariya Fatima u8 q_num, tid = 0; 38219844c0aSPrameela Rani Garnepudi struct rsi_sta *rsta = NULL; 383dad0d04fSFariya Fatima 384dad0d04fSFariya Fatima if ((!skb) || (!skb->len)) { 385dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Null skb/zero Length packet\n", 386dad0d04fSFariya Fatima __func__); 387dad0d04fSFariya Fatima goto xmit_fail; 388dad0d04fSFariya Fatima } 389dad0d04fSFariya Fatima if (common->fsm_state != FSM_MAC_INIT_DONE) { 390dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: FSM state not open\n", __func__); 391dad0d04fSFariya Fatima goto xmit_fail; 392dad0d04fSFariya Fatima } 393f3ac4e73SKarun Eagalapati if (common->wow_flags & RSI_WOW_ENABLED) { 394f3ac4e73SKarun Eagalapati rsi_dbg(ERR_ZONE, 395f3ac4e73SKarun Eagalapati "%s: Blocking Tx_packets when WOWLAN is enabled\n", 396f3ac4e73SKarun Eagalapati __func__); 397f3ac4e73SKarun Eagalapati goto xmit_fail; 398f3ac4e73SKarun Eagalapati } 399dad0d04fSFariya Fatima 40019844c0aSPrameela Rani Garnepudi info = IEEE80211_SKB_CB(skb); 40119844c0aSPrameela Rani Garnepudi tx_params = (struct skb_info *)info->driver_data; 40219844c0aSPrameela Rani Garnepudi wh = (struct ieee80211_hdr *)&skb->data[0]; 40319844c0aSPrameela Rani Garnepudi tx_params->sta_id = 0; 40419844c0aSPrameela Rani Garnepudi 4054671c209SPrameela Rani Garnepudi vif = rsi_get_vif(adapter, wh->addr2); 4064671c209SPrameela Rani Garnepudi if (!vif) 4074671c209SPrameela Rani Garnepudi goto xmit_fail; 4084671c209SPrameela Rani Garnepudi tx_params->vif = vif; 4094671c209SPrameela Rani Garnepudi tx_params->vap_id = ((struct vif_priv *)vif->drv_priv)->vap_id; 41019844c0aSPrameela Rani Garnepudi if ((ieee80211_is_mgmt(wh->frame_control)) || 41119844c0aSPrameela Rani Garnepudi (ieee80211_is_ctl(wh->frame_control)) || 41219844c0aSPrameela Rani Garnepudi (ieee80211_is_qos_nullfunc(wh->frame_control))) { 4134fd6c476SPrameela Rani Garnepudi if (ieee80211_is_assoc_req(wh->frame_control) || 4144fd6c476SPrameela Rani Garnepudi ieee80211_is_reassoc_req(wh->frame_control)) { 4154fd6c476SPrameela Rani Garnepudi struct ieee80211_bss_conf *bss = &vif->bss_conf; 4164fd6c476SPrameela Rani Garnepudi 4174fd6c476SPrameela Rani Garnepudi common->eapol4_confirm = false; 4184fd6c476SPrameela Rani Garnepudi rsi_hal_send_sta_notify_frame(common, 4194fd6c476SPrameela Rani Garnepudi RSI_IFTYPE_STATION, 4204fd6c476SPrameela Rani Garnepudi STA_CONNECTED, bss->bssid, 4214fd6c476SPrameela Rani Garnepudi bss->qos, bss->aid, 0, 4224fd6c476SPrameela Rani Garnepudi vif); 4234fd6c476SPrameela Rani Garnepudi } 4244fd6c476SPrameela Rani Garnepudi 425dad0d04fSFariya Fatima q_num = MGMT_SOFT_Q; 426dad0d04fSFariya Fatima skb->priority = q_num; 4271be05eb5SPrameela Rani Garnepudi 4281be05eb5SPrameela Rani Garnepudi if (rsi_prepare_mgmt_desc(common, skb)) { 4291be05eb5SPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "Failed to prepare desc\n"); 4301be05eb5SPrameela Rani Garnepudi goto xmit_fail; 4311be05eb5SPrameela Rani Garnepudi } 432dad0d04fSFariya Fatima } else { 43319844c0aSPrameela Rani Garnepudi if (ieee80211_is_data_qos(wh->frame_control)) { 4343334306aSAmitkumar Karwar u8 *qos = ieee80211_get_qos_ctl(wh); 4353334306aSAmitkumar Karwar 4363334306aSAmitkumar Karwar tid = *qos & IEEE80211_QOS_CTL_TID_MASK; 437dad0d04fSFariya Fatima skb->priority = TID_TO_WME_AC(tid); 438dad0d04fSFariya Fatima } else { 439dad0d04fSFariya Fatima tid = IEEE80211_NONQOS_TID; 440dad0d04fSFariya Fatima skb->priority = BE_Q; 441dad0d04fSFariya Fatima } 44219844c0aSPrameela Rani Garnepudi 443dad0d04fSFariya Fatima q_num = skb->priority; 444dad0d04fSFariya Fatima tx_params->tid = tid; 44519844c0aSPrameela Rani Garnepudi 446eac4eed3SPrameela Rani Garnepudi if (((vif->type == NL80211_IFTYPE_AP) || 447eac4eed3SPrameela Rani Garnepudi (vif->type == NL80211_IFTYPE_P2P_GO)) && 44819844c0aSPrameela Rani Garnepudi (!is_broadcast_ether_addr(wh->addr1)) && 44919844c0aSPrameela Rani Garnepudi (!is_multicast_ether_addr(wh->addr1))) { 45019844c0aSPrameela Rani Garnepudi rsta = rsi_find_sta(common, wh->addr1); 45119844c0aSPrameela Rani Garnepudi if (!rsta) 45219844c0aSPrameela Rani Garnepudi goto xmit_fail; 45319844c0aSPrameela Rani Garnepudi tx_params->sta_id = rsta->sta_id; 4541be05eb5SPrameela Rani Garnepudi } else { 4551be05eb5SPrameela Rani Garnepudi tx_params->sta_id = 0; 45619844c0aSPrameela Rani Garnepudi } 45719844c0aSPrameela Rani Garnepudi 45819844c0aSPrameela Rani Garnepudi if (rsta) { 45919844c0aSPrameela Rani Garnepudi /* Start aggregation if not done for this tid */ 46019844c0aSPrameela Rani Garnepudi if (!rsta->start_tx_aggr[tid]) { 46119844c0aSPrameela Rani Garnepudi rsta->start_tx_aggr[tid] = true; 46219844c0aSPrameela Rani Garnepudi ieee80211_start_tx_ba_session(rsta->sta, 46319844c0aSPrameela Rani Garnepudi tid, 0); 46419844c0aSPrameela Rani Garnepudi } 46519844c0aSPrameela Rani Garnepudi } 4664fd6c476SPrameela Rani Garnepudi if (skb->protocol == cpu_to_be16(ETH_P_PAE)) { 4674fd6c476SPrameela Rani Garnepudi q_num = MGMT_SOFT_Q; 4684fd6c476SPrameela Rani Garnepudi skb->priority = q_num; 4694fd6c476SPrameela Rani Garnepudi } 4701be05eb5SPrameela Rani Garnepudi if (rsi_prepare_data_desc(common, skb)) { 4711be05eb5SPrameela Rani Garnepudi rsi_dbg(ERR_ZONE, "Failed to prepare data desc\n"); 4721be05eb5SPrameela Rani Garnepudi goto xmit_fail; 4731be05eb5SPrameela Rani Garnepudi } 474dad0d04fSFariya Fatima } 475dad0d04fSFariya Fatima 476d26a9559SPrameela Rani Garnepudi if ((q_num < MGMT_SOFT_Q) && 477dad0d04fSFariya Fatima ((skb_queue_len(&common->tx_queue[q_num]) + 1) >= 478dad0d04fSFariya Fatima DATA_QUEUE_WATER_MARK)) { 479258587f9SJahnavi Meher rsi_dbg(ERR_ZONE, "%s: sw queue full\n", __func__); 480dad0d04fSFariya Fatima if (!ieee80211_queue_stopped(adapter->hw, WME_AC(q_num))) 481dad0d04fSFariya Fatima ieee80211_stop_queue(adapter->hw, WME_AC(q_num)); 482dad0d04fSFariya Fatima rsi_set_event(&common->tx_thread.event); 483dad0d04fSFariya Fatima goto xmit_fail; 484dad0d04fSFariya Fatima } 485dad0d04fSFariya Fatima 486dad0d04fSFariya Fatima rsi_core_queue_pkt(common, skb); 487b41c3936SColin Ian King rsi_dbg(DATA_TX_ZONE, "%s: ===> Scheduling TX thread <===\n", __func__); 488dad0d04fSFariya Fatima rsi_set_event(&common->tx_thread.event); 489dad0d04fSFariya Fatima 490dad0d04fSFariya Fatima return; 491dad0d04fSFariya Fatima 492dad0d04fSFariya Fatima xmit_fail: 493dad0d04fSFariya Fatima rsi_dbg(ERR_ZONE, "%s: Failed to queue packet\n", __func__); 494dad0d04fSFariya Fatima /* Dropping pkt here */ 495dad0d04fSFariya Fatima ieee80211_free_txskb(common->priv->hw, skb); 496dad0d04fSFariya Fatima } 497