1 | /* |
2 | * Copyright (c) 2014 Redpine Signals Inc. |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include "rsi_mgmt.h" |
18 | #include "rsi_common.h" |
19 | #include "rsi_hal.h" |
20 | #include "rsi_coex.h" |
21 | |
22 | /** |
23 | * rsi_determine_min_weight_queue() - This function determines the queue with |
24 | * the min weight. |
25 | * @common: Pointer to the driver private structure. |
26 | * |
27 | * Return: q_num: Corresponding queue number. |
28 | */ |
29 | static u8 rsi_determine_min_weight_queue(struct rsi_common *common) |
30 | { |
31 | struct wmm_qinfo *tx_qinfo = common->tx_qinfo; |
32 | u32 q_len = 0; |
33 | u8 ii = 0; |
34 | |
35 | for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { |
36 | q_len = skb_queue_len(list_: &common->tx_queue[ii]); |
37 | if ((tx_qinfo[ii].pkt_contended) && q_len) { |
38 | common->min_weight = tx_qinfo[ii].weight; |
39 | break; |
40 | } |
41 | } |
42 | return ii; |
43 | } |
44 | |
45 | /** |
46 | * rsi_recalculate_weights() - This function recalculates the weights |
47 | * corresponding to each queue. |
48 | * @common: Pointer to the driver private structure. |
49 | * |
50 | * Return: recontend_queue bool variable |
51 | */ |
52 | static bool rsi_recalculate_weights(struct rsi_common *common) |
53 | { |
54 | struct wmm_qinfo *tx_qinfo = common->tx_qinfo; |
55 | bool recontend_queue = false; |
56 | u8 ii = 0; |
57 | u32 q_len = 0; |
58 | |
59 | for (ii = 0; ii < NUM_EDCA_QUEUES; ii++) { |
60 | q_len = skb_queue_len(list_: &common->tx_queue[ii]); |
61 | /* Check for the need of contention */ |
62 | if (q_len) { |
63 | if (tx_qinfo[ii].pkt_contended) { |
64 | tx_qinfo[ii].weight = |
65 | ((tx_qinfo[ii].weight > common->min_weight) ? |
66 | tx_qinfo[ii].weight - common->min_weight : 0); |
67 | } else { |
68 | tx_qinfo[ii].pkt_contended = 1; |
69 | tx_qinfo[ii].weight = tx_qinfo[ii].wme_params; |
70 | recontend_queue = true; |
71 | } |
72 | } else { /* No packets so no contention */ |
73 | tx_qinfo[ii].weight = 0; |
74 | tx_qinfo[ii].pkt_contended = 0; |
75 | } |
76 | } |
77 | |
78 | return recontend_queue; |
79 | } |
80 | |
81 | /** |
82 | * rsi_get_num_pkts_dequeue() - This function determines the number of |
83 | * packets to be dequeued based on the number |
84 | * of bytes calculated using txop. |
85 | * |
86 | * @common: Pointer to the driver private structure. |
87 | * @q_num: the queue from which pkts have to be dequeued |
88 | * |
89 | * Return: pkt_num: Number of pkts to be dequeued. |
90 | */ |
91 | static u32 rsi_get_num_pkts_dequeue(struct rsi_common *common, u8 q_num) |
92 | { |
93 | struct rsi_hw *adapter = common->priv; |
94 | struct sk_buff *skb; |
95 | u32 pkt_cnt = 0; |
96 | s16 txop = common->tx_qinfo[q_num].txop * 32; |
97 | __le16 r_txop; |
98 | struct ieee80211_rate rate; |
99 | struct ieee80211_hdr *wh; |
100 | struct ieee80211_vif *vif; |
101 | |
102 | rate.bitrate = RSI_RATE_MCS0 * 5 * 10; /* Convert to Kbps */ |
103 | if (q_num == VI_Q) |
104 | txop = ((txop << 5) / 80); |
105 | |
106 | if (skb_queue_len(list_: &common->tx_queue[q_num])) |
107 | skb = skb_peek(list_: &common->tx_queue[q_num]); |
108 | else |
109 | return 0; |
110 | |
111 | do { |
112 | wh = (struct ieee80211_hdr *)skb->data; |
113 | vif = rsi_get_vif(adapter, mac: wh->addr2); |
114 | r_txop = ieee80211_generic_frame_duration(hw: adapter->hw, |
115 | vif, |
116 | band: common->band, |
117 | frame_len: skb->len, rate: &rate); |
118 | txop -= le16_to_cpu(r_txop); |
119 | pkt_cnt += 1; |
120 | /*checking if pkts are still there*/ |
121 | if (skb_queue_len(list_: &common->tx_queue[q_num]) - pkt_cnt) |
122 | skb = skb->next; |
123 | else |
124 | break; |
125 | |
126 | } while (txop > 0); |
127 | |
128 | return pkt_cnt; |
129 | } |
130 | |
131 | /** |
132 | * rsi_core_determine_hal_queue() - This function determines the queue from |
133 | * which packet has to be dequeued. |
134 | * @common: Pointer to the driver private structure. |
135 | * |
136 | * Return: q_num: Corresponding queue number on success. |
137 | */ |
138 | static u8 rsi_core_determine_hal_queue(struct rsi_common *common) |
139 | { |
140 | bool recontend_queue = false; |
141 | u32 q_len = 0; |
142 | u8 q_num = INVALID_QUEUE; |
143 | u8 ii = 0; |
144 | |
145 | if (skb_queue_len(list_: &common->tx_queue[MGMT_BEACON_Q])) { |
146 | q_num = MGMT_BEACON_Q; |
147 | return q_num; |
148 | } |
149 | if (skb_queue_len(list_: &common->tx_queue[MGMT_SOFT_Q])) { |
150 | if (!common->mgmt_q_block) |
151 | q_num = MGMT_SOFT_Q; |
152 | return q_num; |
153 | } |
154 | |
155 | if (common->hw_data_qs_blocked) |
156 | return q_num; |
157 | |
158 | if (common->pkt_cnt != 0) { |
159 | --common->pkt_cnt; |
160 | return common->selected_qnum; |
161 | } |
162 | |
163 | get_queue_num: |
164 | recontend_queue = false; |
165 | |
166 | q_num = rsi_determine_min_weight_queue(common); |
167 | |
168 | ii = q_num; |
169 | |
170 | /* Selecting the queue with least back off */ |
171 | for (; ii < NUM_EDCA_QUEUES; ii++) { |
172 | q_len = skb_queue_len(list_: &common->tx_queue[ii]); |
173 | if (((common->tx_qinfo[ii].pkt_contended) && |
174 | (common->tx_qinfo[ii].weight < common->min_weight)) && |
175 | q_len) { |
176 | common->min_weight = common->tx_qinfo[ii].weight; |
177 | q_num = ii; |
178 | } |
179 | } |
180 | |
181 | if (q_num < NUM_EDCA_QUEUES) |
182 | common->tx_qinfo[q_num].pkt_contended = 0; |
183 | |
184 | /* Adjust the back off values for all queues again */ |
185 | recontend_queue = rsi_recalculate_weights(common); |
186 | |
187 | q_len = skb_queue_len(list_: &common->tx_queue[q_num]); |
188 | if (!q_len) { |
189 | /* If any queues are freshly contended and the selected queue |
190 | * doesn't have any packets |
191 | * then get the queue number again with fresh values |
192 | */ |
193 | if (recontend_queue) |
194 | goto get_queue_num; |
195 | |
196 | return INVALID_QUEUE; |
197 | } |
198 | |
199 | common->selected_qnum = q_num; |
200 | q_len = skb_queue_len(list_: &common->tx_queue[q_num]); |
201 | |
202 | if (q_num == VO_Q || q_num == VI_Q) { |
203 | common->pkt_cnt = rsi_get_num_pkts_dequeue(common, q_num); |
204 | common->pkt_cnt -= 1; |
205 | } |
206 | |
207 | return q_num; |
208 | } |
209 | |
210 | /** |
211 | * rsi_core_queue_pkt() - This functions enqueues the packet to the queue |
212 | * specified by the queue number. |
213 | * @common: Pointer to the driver private structure. |
214 | * @skb: Pointer to the socket buffer structure. |
215 | * |
216 | * Return: None. |
217 | */ |
218 | static void rsi_core_queue_pkt(struct rsi_common *common, |
219 | struct sk_buff *skb) |
220 | { |
221 | u8 q_num = skb->priority; |
222 | if (q_num >= NUM_SOFT_QUEUES) { |
223 | rsi_dbg(ERR_ZONE, fmt: "%s: Invalid Queue Number: q_num = %d\n" , |
224 | __func__, q_num); |
225 | dev_kfree_skb(skb); |
226 | return; |
227 | } |
228 | |
229 | skb_queue_tail(list: &common->tx_queue[q_num], newsk: skb); |
230 | } |
231 | |
232 | /** |
233 | * rsi_core_dequeue_pkt() - This functions dequeues the packet from the queue |
234 | * specified by the queue number. |
235 | * @common: Pointer to the driver private structure. |
236 | * @q_num: Queue number. |
237 | * |
238 | * Return: Pointer to sk_buff structure. |
239 | */ |
240 | static struct sk_buff *rsi_core_dequeue_pkt(struct rsi_common *common, |
241 | u8 q_num) |
242 | { |
243 | if (q_num >= NUM_SOFT_QUEUES) { |
244 | rsi_dbg(ERR_ZONE, fmt: "%s: Invalid Queue Number: q_num = %d\n" , |
245 | __func__, q_num); |
246 | return NULL; |
247 | } |
248 | |
249 | return skb_dequeue(list: &common->tx_queue[q_num]); |
250 | } |
251 | |
252 | /** |
253 | * rsi_core_qos_processor() - This function is used to determine the wmm queue |
254 | * based on the backoff procedure. Data packets are |
255 | * dequeued from the selected hal queue and sent to |
256 | * the below layers. |
257 | * @common: Pointer to the driver private structure. |
258 | * |
259 | * Return: None. |
260 | */ |
261 | void rsi_core_qos_processor(struct rsi_common *common) |
262 | { |
263 | struct rsi_hw *adapter = common->priv; |
264 | struct sk_buff *skb; |
265 | unsigned long tstamp_1, tstamp_2; |
266 | u8 q_num; |
267 | int status; |
268 | |
269 | tstamp_1 = jiffies; |
270 | while (1) { |
271 | q_num = rsi_core_determine_hal_queue(common); |
272 | rsi_dbg(DATA_TX_ZONE, |
273 | fmt: "%s: Queue number = %d\n" , __func__, q_num); |
274 | |
275 | if (q_num == INVALID_QUEUE) { |
276 | rsi_dbg(DATA_TX_ZONE, fmt: "%s: No More Pkt\n" , __func__); |
277 | break; |
278 | } |
279 | if (common->hibernate_resume) |
280 | break; |
281 | |
282 | mutex_lock(&common->tx_lock); |
283 | |
284 | status = adapter->check_hw_queue_status(adapter, q_num); |
285 | if ((status <= 0)) { |
286 | mutex_unlock(lock: &common->tx_lock); |
287 | break; |
288 | } |
289 | |
290 | if ((q_num < MGMT_SOFT_Q) && |
291 | ((skb_queue_len(list_: &common->tx_queue[q_num])) <= |
292 | MIN_DATA_QUEUE_WATER_MARK)) { |
293 | if (ieee80211_queue_stopped(hw: adapter->hw, WME_AC(q_num))) |
294 | ieee80211_wake_queue(hw: adapter->hw, |
295 | WME_AC(q_num)); |
296 | } |
297 | |
298 | skb = rsi_core_dequeue_pkt(common, q_num); |
299 | if (skb == NULL) { |
300 | rsi_dbg(ERR_ZONE, fmt: "skb null\n" ); |
301 | mutex_unlock(lock: &common->tx_lock); |
302 | break; |
303 | } |
304 | if (q_num == MGMT_BEACON_Q) { |
305 | status = rsi_send_pkt_to_bus(common, skb); |
306 | dev_kfree_skb(skb); |
307 | } else { |
308 | #ifdef CONFIG_RSI_COEX |
309 | if (common->coex_mode > 1) { |
310 | status = rsi_coex_send_pkt(priv: common, skb, |
311 | RSI_WLAN_Q); |
312 | } else { |
313 | #endif |
314 | if (q_num == MGMT_SOFT_Q) |
315 | status = rsi_send_mgmt_pkt(common, skb); |
316 | else |
317 | status = rsi_send_data_pkt(common, skb); |
318 | #ifdef CONFIG_RSI_COEX |
319 | } |
320 | #endif |
321 | } |
322 | |
323 | if (status) { |
324 | mutex_unlock(lock: &common->tx_lock); |
325 | break; |
326 | } |
327 | |
328 | common->tx_stats.total_tx_pkt_send[q_num]++; |
329 | |
330 | tstamp_2 = jiffies; |
331 | mutex_unlock(lock: &common->tx_lock); |
332 | |
333 | if (time_after(tstamp_2, tstamp_1 + (300 * HZ) / 1000)) |
334 | schedule(); |
335 | } |
336 | } |
337 | |
338 | struct rsi_sta *rsi_find_sta(struct rsi_common *common, u8 *mac_addr) |
339 | { |
340 | int i; |
341 | |
342 | for (i = 0; i < common->max_stations; i++) { |
343 | if (!common->stations[i].sta) |
344 | continue; |
345 | if (!(memcmp(p: common->stations[i].sta->addr, |
346 | q: mac_addr, ETH_ALEN))) |
347 | return &common->stations[i]; |
348 | } |
349 | return NULL; |
350 | } |
351 | |
352 | struct ieee80211_vif *rsi_get_vif(struct rsi_hw *adapter, u8 *mac) |
353 | { |
354 | struct ieee80211_vif *vif; |
355 | int i; |
356 | |
357 | for (i = 0; i < RSI_MAX_VIFS; i++) { |
358 | vif = adapter->vifs[i]; |
359 | if (!vif) |
360 | continue; |
361 | if (!memcmp(p: vif->addr, q: mac, ETH_ALEN)) |
362 | return vif; |
363 | } |
364 | return NULL; |
365 | } |
366 | |
367 | /** |
368 | * rsi_core_xmit() - This function transmits the packets received from mac80211 |
369 | * @common: Pointer to the driver private structure. |
370 | * @skb: Pointer to the socket buffer structure. |
371 | * |
372 | * Return: None. |
373 | */ |
374 | void rsi_core_xmit(struct rsi_common *common, struct sk_buff *skb) |
375 | { |
376 | struct rsi_hw *adapter = common->priv; |
377 | struct ieee80211_tx_info *info; |
378 | struct skb_info *tx_params; |
379 | struct ieee80211_hdr *wh = NULL; |
380 | struct ieee80211_vif *vif; |
381 | u8 q_num, tid = 0; |
382 | struct rsi_sta *rsta = NULL; |
383 | |
384 | if ((!skb) || (!skb->len)) { |
385 | rsi_dbg(ERR_ZONE, fmt: "%s: Null skb/zero Length packet\n" , |
386 | __func__); |
387 | goto xmit_fail; |
388 | } |
389 | if (common->fsm_state != FSM_MAC_INIT_DONE) { |
390 | rsi_dbg(ERR_ZONE, fmt: "%s: FSM state not open\n" , __func__); |
391 | goto xmit_fail; |
392 | } |
393 | if (common->wow_flags & RSI_WOW_ENABLED) { |
394 | rsi_dbg(ERR_ZONE, |
395 | fmt: "%s: Blocking Tx_packets when WOWLAN is enabled\n" , |
396 | __func__); |
397 | goto xmit_fail; |
398 | } |
399 | |
400 | info = IEEE80211_SKB_CB(skb); |
401 | tx_params = (struct skb_info *)info->driver_data; |
402 | /* info->driver_data and info->control part of union so make copy */ |
403 | tx_params->have_key = !!info->control.hw_key; |
404 | wh = (struct ieee80211_hdr *)&skb->data[0]; |
405 | tx_params->sta_id = 0; |
406 | |
407 | vif = rsi_get_vif(adapter, mac: wh->addr2); |
408 | if (!vif) |
409 | goto xmit_fail; |
410 | tx_params->vif = vif; |
411 | tx_params->vap_id = ((struct vif_priv *)vif->drv_priv)->vap_id; |
412 | if ((ieee80211_is_mgmt(fc: wh->frame_control)) || |
413 | (ieee80211_is_ctl(fc: wh->frame_control)) || |
414 | (ieee80211_is_qos_nullfunc(fc: wh->frame_control))) { |
415 | if (ieee80211_is_assoc_req(fc: wh->frame_control) || |
416 | ieee80211_is_reassoc_req(fc: wh->frame_control)) { |
417 | struct ieee80211_bss_conf *bss = &vif->bss_conf; |
418 | |
419 | common->eapol4_confirm = false; |
420 | rsi_hal_send_sta_notify_frame(common, |
421 | RSI_IFTYPE_STATION, |
422 | notify_event: STA_CONNECTED, bssid: bss->bssid, |
423 | qos_enable: bss->qos, aid: vif->cfg.aid, |
424 | sta_id: 0, |
425 | vif); |
426 | } |
427 | |
428 | q_num = MGMT_SOFT_Q; |
429 | skb->priority = q_num; |
430 | |
431 | if (rsi_prepare_mgmt_desc(common, skb)) { |
432 | rsi_dbg(ERR_ZONE, fmt: "Failed to prepare desc\n" ); |
433 | goto xmit_fail; |
434 | } |
435 | } else { |
436 | if (ieee80211_is_data_qos(fc: wh->frame_control)) { |
437 | u8 *qos = ieee80211_get_qos_ctl(hdr: wh); |
438 | |
439 | tid = *qos & IEEE80211_QOS_CTL_TID_MASK; |
440 | skb->priority = TID_TO_WME_AC(tid); |
441 | } else { |
442 | tid = IEEE80211_NONQOS_TID; |
443 | skb->priority = BE_Q; |
444 | } |
445 | |
446 | q_num = skb->priority; |
447 | tx_params->tid = tid; |
448 | |
449 | if (((vif->type == NL80211_IFTYPE_AP) || |
450 | (vif->type == NL80211_IFTYPE_P2P_GO)) && |
451 | (!is_broadcast_ether_addr(addr: wh->addr1)) && |
452 | (!is_multicast_ether_addr(addr: wh->addr1))) { |
453 | rsta = rsi_find_sta(common, mac_addr: wh->addr1); |
454 | if (!rsta) |
455 | goto xmit_fail; |
456 | tx_params->sta_id = rsta->sta_id; |
457 | } else { |
458 | tx_params->sta_id = 0; |
459 | } |
460 | |
461 | if (rsta) { |
462 | /* Start aggregation if not done for this tid */ |
463 | if (!rsta->start_tx_aggr[tid]) { |
464 | rsta->start_tx_aggr[tid] = true; |
465 | ieee80211_start_tx_ba_session(sta: rsta->sta, |
466 | tid, timeout: 0); |
467 | } |
468 | } |
469 | |
470 | if (IEEE80211_SKB_CB(skb)->control.flags & |
471 | IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { |
472 | q_num = MGMT_SOFT_Q; |
473 | skb->priority = q_num; |
474 | } |
475 | if (rsi_prepare_data_desc(common, skb)) { |
476 | rsi_dbg(ERR_ZONE, fmt: "Failed to prepare data desc\n" ); |
477 | goto xmit_fail; |
478 | } |
479 | } |
480 | |
481 | if ((q_num < MGMT_SOFT_Q) && |
482 | ((skb_queue_len(list_: &common->tx_queue[q_num]) + 1) >= |
483 | DATA_QUEUE_WATER_MARK)) { |
484 | rsi_dbg(ERR_ZONE, fmt: "%s: sw queue full\n" , __func__); |
485 | if (!ieee80211_queue_stopped(hw: adapter->hw, WME_AC(q_num))) |
486 | ieee80211_stop_queue(hw: adapter->hw, WME_AC(q_num)); |
487 | rsi_set_event(event: &common->tx_thread.event); |
488 | goto xmit_fail; |
489 | } |
490 | |
491 | rsi_core_queue_pkt(common, skb); |
492 | rsi_dbg(DATA_TX_ZONE, fmt: "%s: ===> Scheduling TX thread <===\n" , __func__); |
493 | rsi_set_event(event: &common->tx_thread.event); |
494 | |
495 | return; |
496 | |
497 | xmit_fail: |
498 | rsi_dbg(ERR_ZONE, fmt: "%s: Failed to queue packet\n" , __func__); |
499 | /* Dropping pkt here */ |
500 | ieee80211_free_txskb(hw: common->priv->hw, skb); |
501 | } |
502 | |