1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
2 | /* Copyright(c) 2018-2019 Realtek Corporation |
3 | */ |
4 | |
5 | #include "main.h" |
6 | #include "tx.h" |
7 | #include "fw.h" |
8 | #include "ps.h" |
9 | #include "debug.h" |
10 | |
11 | static |
12 | void rtw_tx_stats(struct rtw_dev *rtwdev, struct ieee80211_vif *vif, |
13 | struct sk_buff *skb) |
14 | { |
15 | struct ieee80211_hdr *hdr; |
16 | struct rtw_vif *rtwvif; |
17 | |
18 | hdr = (struct ieee80211_hdr *)skb->data; |
19 | |
20 | if (!ieee80211_is_data(fc: hdr->frame_control)) |
21 | return; |
22 | |
23 | if (!is_broadcast_ether_addr(addr: hdr->addr1) && |
24 | !is_multicast_ether_addr(addr: hdr->addr1)) { |
25 | rtwdev->stats.tx_unicast += skb->len; |
26 | rtwdev->stats.tx_cnt++; |
27 | if (vif) { |
28 | rtwvif = (struct rtw_vif *)vif->drv_priv; |
29 | rtwvif->stats.tx_unicast += skb->len; |
30 | rtwvif->stats.tx_cnt++; |
31 | } |
32 | } |
33 | } |
34 | |
35 | void rtw_tx_fill_tx_desc(struct rtw_tx_pkt_info *pkt_info, struct sk_buff *skb) |
36 | { |
37 | struct rtw_tx_desc *tx_desc = (struct rtw_tx_desc *)skb->data; |
38 | bool more_data = false; |
39 | |
40 | if (pkt_info->qsel == TX_DESC_QSEL_HIGH) |
41 | more_data = true; |
42 | |
43 | tx_desc->w0 = le32_encode_bits(v: pkt_info->tx_pkt_size, RTW_TX_DESC_W0_TXPKTSIZE) | |
44 | le32_encode_bits(v: pkt_info->offset, RTW_TX_DESC_W0_OFFSET) | |
45 | le32_encode_bits(v: pkt_info->bmc, RTW_TX_DESC_W0_BMC) | |
46 | le32_encode_bits(v: pkt_info->ls, RTW_TX_DESC_W0_LS) | |
47 | le32_encode_bits(v: pkt_info->dis_qselseq, RTW_TX_DESC_W0_DISQSELSEQ); |
48 | |
49 | tx_desc->w1 = le32_encode_bits(v: pkt_info->qsel, RTW_TX_DESC_W1_QSEL) | |
50 | le32_encode_bits(v: pkt_info->rate_id, RTW_TX_DESC_W1_RATE_ID) | |
51 | le32_encode_bits(v: pkt_info->sec_type, RTW_TX_DESC_W1_SEC_TYPE) | |
52 | le32_encode_bits(v: pkt_info->pkt_offset, RTW_TX_DESC_W1_PKT_OFFSET) | |
53 | le32_encode_bits(v: more_data, RTW_TX_DESC_W1_MORE_DATA); |
54 | |
55 | tx_desc->w2 = le32_encode_bits(v: pkt_info->ampdu_en, RTW_TX_DESC_W2_AGG_EN) | |
56 | le32_encode_bits(v: pkt_info->report, RTW_TX_DESC_W2_SPE_RPT) | |
57 | le32_encode_bits(v: pkt_info->ampdu_density, RTW_TX_DESC_W2_AMPDU_DEN) | |
58 | le32_encode_bits(v: pkt_info->bt_null, RTW_TX_DESC_W2_BT_NULL); |
59 | |
60 | tx_desc->w3 = le32_encode_bits(v: pkt_info->hw_ssn_sel, RTW_TX_DESC_W3_HW_SSN_SEL) | |
61 | le32_encode_bits(v: pkt_info->use_rate, RTW_TX_DESC_W3_USE_RATE) | |
62 | le32_encode_bits(v: pkt_info->dis_rate_fallback, RTW_TX_DESC_W3_DISDATAFB) | |
63 | le32_encode_bits(v: pkt_info->rts, RTW_TX_DESC_W3_USE_RTS) | |
64 | le32_encode_bits(v: pkt_info->nav_use_hdr, RTW_TX_DESC_W3_NAVUSEHDR) | |
65 | le32_encode_bits(v: pkt_info->ampdu_factor, RTW_TX_DESC_W3_MAX_AGG_NUM); |
66 | |
67 | tx_desc->w4 = le32_encode_bits(v: pkt_info->rate, RTW_TX_DESC_W4_DATARATE); |
68 | |
69 | tx_desc->w5 = le32_encode_bits(v: pkt_info->short_gi, RTW_TX_DESC_W5_DATA_SHORT) | |
70 | le32_encode_bits(v: pkt_info->bw, RTW_TX_DESC_W5_DATA_BW) | |
71 | le32_encode_bits(v: pkt_info->ldpc, RTW_TX_DESC_W5_DATA_LDPC) | |
72 | le32_encode_bits(v: pkt_info->stbc, RTW_TX_DESC_W5_DATA_STBC); |
73 | |
74 | tx_desc->w6 = le32_encode_bits(v: pkt_info->sn, RTW_TX_DESC_W6_SW_DEFINE); |
75 | |
76 | tx_desc->w8 = le32_encode_bits(v: pkt_info->en_hwseq, RTW_TX_DESC_W8_EN_HWSEQ); |
77 | |
78 | tx_desc->w9 = le32_encode_bits(v: pkt_info->seq, RTW_TX_DESC_W9_SW_SEQ); |
79 | |
80 | if (pkt_info->rts) { |
81 | tx_desc->w4 |= le32_encode_bits(v: DESC_RATE24M, RTW_TX_DESC_W4_RTSRATE); |
82 | tx_desc->w5 |= le32_encode_bits(v: 1, RTW_TX_DESC_W5_DATA_RTS_SHORT); |
83 | } |
84 | |
85 | if (pkt_info->tim_offset) |
86 | tx_desc->w9 |= le32_encode_bits(v: 1, RTW_TX_DESC_W9_TIM_EN) | |
87 | le32_encode_bits(v: pkt_info->tim_offset, RTW_TX_DESC_W9_TIM_OFFSET); |
88 | } |
89 | EXPORT_SYMBOL(rtw_tx_fill_tx_desc); |
90 | |
91 | static u8 get_tx_ampdu_factor(struct ieee80211_sta *sta) |
92 | { |
93 | u8 exp = sta->deflink.ht_cap.ampdu_factor; |
94 | |
95 | /* the least ampdu factor is 8K, and the value in the tx desc is the |
96 | * max aggregation num, which represents val * 2 packets can be |
97 | * aggregated in an AMPDU, so here we should use 8/2=4 as the base |
98 | */ |
99 | return (BIT(2) << exp) - 1; |
100 | } |
101 | |
102 | static u8 get_tx_ampdu_density(struct ieee80211_sta *sta) |
103 | { |
104 | return sta->deflink.ht_cap.ampdu_density; |
105 | } |
106 | |
107 | static u8 get_highest_ht_tx_rate(struct rtw_dev *rtwdev, |
108 | struct ieee80211_sta *sta) |
109 | { |
110 | u8 rate; |
111 | |
112 | if (rtwdev->hal.rf_type == RF_2T2R && sta->deflink.ht_cap.mcs.rx_mask[1] != 0) |
113 | rate = DESC_RATEMCS15; |
114 | else |
115 | rate = DESC_RATEMCS7; |
116 | |
117 | return rate; |
118 | } |
119 | |
120 | static u8 get_highest_vht_tx_rate(struct rtw_dev *rtwdev, |
121 | struct ieee80211_sta *sta) |
122 | { |
123 | struct rtw_efuse *efuse = &rtwdev->efuse; |
124 | u8 rate; |
125 | u16 tx_mcs_map; |
126 | |
127 | tx_mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.tx_mcs_map); |
128 | if (efuse->hw_cap.nss == 1) { |
129 | switch (tx_mcs_map & 0x3) { |
130 | case IEEE80211_VHT_MCS_SUPPORT_0_7: |
131 | rate = DESC_RATEVHT1SS_MCS7; |
132 | break; |
133 | case IEEE80211_VHT_MCS_SUPPORT_0_8: |
134 | rate = DESC_RATEVHT1SS_MCS8; |
135 | break; |
136 | default: |
137 | case IEEE80211_VHT_MCS_SUPPORT_0_9: |
138 | rate = DESC_RATEVHT1SS_MCS9; |
139 | break; |
140 | } |
141 | } else if (efuse->hw_cap.nss >= 2) { |
142 | switch ((tx_mcs_map & 0xc) >> 2) { |
143 | case IEEE80211_VHT_MCS_SUPPORT_0_7: |
144 | rate = DESC_RATEVHT2SS_MCS7; |
145 | break; |
146 | case IEEE80211_VHT_MCS_SUPPORT_0_8: |
147 | rate = DESC_RATEVHT2SS_MCS8; |
148 | break; |
149 | default: |
150 | case IEEE80211_VHT_MCS_SUPPORT_0_9: |
151 | rate = DESC_RATEVHT2SS_MCS9; |
152 | break; |
153 | } |
154 | } else { |
155 | rate = DESC_RATEVHT1SS_MCS9; |
156 | } |
157 | |
158 | return rate; |
159 | } |
160 | |
161 | static void rtw_tx_report_enable(struct rtw_dev *rtwdev, |
162 | struct rtw_tx_pkt_info *pkt_info) |
163 | { |
164 | struct rtw_tx_report *tx_report = &rtwdev->tx_report; |
165 | |
166 | /* [11:8], reserved, fills with zero |
167 | * [7:2], tx report sequence number |
168 | * [1:0], firmware use, fills with zero |
169 | */ |
170 | pkt_info->sn = (atomic_inc_return(v: &tx_report->sn) << 2) & 0xfc; |
171 | pkt_info->report = true; |
172 | } |
173 | |
174 | void rtw_tx_report_purge_timer(struct timer_list *t) |
175 | { |
176 | struct rtw_dev *rtwdev = from_timer(rtwdev, t, tx_report.purge_timer); |
177 | struct rtw_tx_report *tx_report = &rtwdev->tx_report; |
178 | unsigned long flags; |
179 | |
180 | if (skb_queue_len(list_: &tx_report->queue) == 0) |
181 | return; |
182 | |
183 | rtw_warn(rtwdev, "failed to get tx report from firmware\n" ); |
184 | |
185 | spin_lock_irqsave(&tx_report->q_lock, flags); |
186 | skb_queue_purge(list: &tx_report->queue); |
187 | spin_unlock_irqrestore(lock: &tx_report->q_lock, flags); |
188 | } |
189 | |
190 | void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn) |
191 | { |
192 | struct rtw_tx_report *tx_report = &rtwdev->tx_report; |
193 | unsigned long flags; |
194 | u8 *drv_data; |
195 | |
196 | /* pass sn to tx report handler through driver data */ |
197 | drv_data = (u8 *)IEEE80211_SKB_CB(skb)->status.status_driver_data; |
198 | *drv_data = sn; |
199 | |
200 | spin_lock_irqsave(&tx_report->q_lock, flags); |
201 | __skb_queue_tail(list: &tx_report->queue, newsk: skb); |
202 | spin_unlock_irqrestore(lock: &tx_report->q_lock, flags); |
203 | |
204 | mod_timer(timer: &tx_report->purge_timer, expires: jiffies + RTW_TX_PROBE_TIMEOUT); |
205 | } |
206 | EXPORT_SYMBOL(rtw_tx_report_enqueue); |
207 | |
208 | static void rtw_tx_report_tx_status(struct rtw_dev *rtwdev, |
209 | struct sk_buff *skb, bool acked) |
210 | { |
211 | struct ieee80211_tx_info *info; |
212 | |
213 | info = IEEE80211_SKB_CB(skb); |
214 | ieee80211_tx_info_clear_status(info); |
215 | if (acked) |
216 | info->flags |= IEEE80211_TX_STAT_ACK; |
217 | else |
218 | info->flags &= ~IEEE80211_TX_STAT_ACK; |
219 | |
220 | ieee80211_tx_status_irqsafe(hw: rtwdev->hw, skb); |
221 | } |
222 | |
223 | void rtw_tx_report_handle(struct rtw_dev *rtwdev, struct sk_buff *skb, int src) |
224 | { |
225 | struct rtw_tx_report *tx_report = &rtwdev->tx_report; |
226 | struct rtw_c2h_cmd *c2h; |
227 | struct sk_buff *cur, *tmp; |
228 | unsigned long flags; |
229 | u8 sn, st; |
230 | u8 *n; |
231 | |
232 | c2h = get_c2h_from_skb(skb); |
233 | |
234 | if (src == C2H_CCX_TX_RPT) { |
235 | sn = GET_CCX_REPORT_SEQNUM_V0(c2h->payload); |
236 | st = GET_CCX_REPORT_STATUS_V0(c2h->payload); |
237 | } else { |
238 | sn = GET_CCX_REPORT_SEQNUM_V1(c2h->payload); |
239 | st = GET_CCX_REPORT_STATUS_V1(c2h->payload); |
240 | } |
241 | |
242 | spin_lock_irqsave(&tx_report->q_lock, flags); |
243 | skb_queue_walk_safe(&tx_report->queue, cur, tmp) { |
244 | n = (u8 *)IEEE80211_SKB_CB(skb: cur)->status.status_driver_data; |
245 | if (*n == sn) { |
246 | __skb_unlink(skb: cur, list: &tx_report->queue); |
247 | rtw_tx_report_tx_status(rtwdev, skb: cur, acked: st == 0); |
248 | break; |
249 | } |
250 | } |
251 | spin_unlock_irqrestore(lock: &tx_report->q_lock, flags); |
252 | } |
253 | |
254 | static u8 rtw_get_mgmt_rate(struct rtw_dev *rtwdev, struct sk_buff *skb, |
255 | u8 lowest_rate, bool ignore_rate) |
256 | { |
257 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
258 | struct ieee80211_vif *vif = tx_info->control.vif; |
259 | bool force_lowest = test_bit(RTW_FLAG_FORCE_LOWEST_RATE, rtwdev->flags); |
260 | |
261 | if (!vif || !vif->bss_conf.basic_rates || ignore_rate || force_lowest) |
262 | return lowest_rate; |
263 | |
264 | return __ffs(vif->bss_conf.basic_rates) + lowest_rate; |
265 | } |
266 | |
267 | static void rtw_tx_pkt_info_update_rate(struct rtw_dev *rtwdev, |
268 | struct rtw_tx_pkt_info *pkt_info, |
269 | struct sk_buff *skb, |
270 | bool ignore_rate) |
271 | { |
272 | if (rtwdev->hal.current_band_type == RTW_BAND_2G) { |
273 | pkt_info->rate_id = RTW_RATEID_B_20M; |
274 | pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, lowest_rate: DESC_RATE1M, |
275 | ignore_rate); |
276 | } else { |
277 | pkt_info->rate_id = RTW_RATEID_G; |
278 | pkt_info->rate = rtw_get_mgmt_rate(rtwdev, skb, lowest_rate: DESC_RATE6M, |
279 | ignore_rate); |
280 | } |
281 | |
282 | pkt_info->use_rate = true; |
283 | pkt_info->dis_rate_fallback = true; |
284 | } |
285 | |
286 | static void rtw_tx_pkt_info_update_sec(struct rtw_dev *rtwdev, |
287 | struct rtw_tx_pkt_info *pkt_info, |
288 | struct sk_buff *skb) |
289 | { |
290 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
291 | u8 sec_type = 0; |
292 | |
293 | if (info && info->control.hw_key) { |
294 | struct ieee80211_key_conf *key = info->control.hw_key; |
295 | |
296 | switch (key->cipher) { |
297 | case WLAN_CIPHER_SUITE_WEP40: |
298 | case WLAN_CIPHER_SUITE_WEP104: |
299 | case WLAN_CIPHER_SUITE_TKIP: |
300 | sec_type = 0x01; |
301 | break; |
302 | case WLAN_CIPHER_SUITE_CCMP: |
303 | sec_type = 0x03; |
304 | break; |
305 | default: |
306 | break; |
307 | } |
308 | } |
309 | |
310 | pkt_info->sec_type = sec_type; |
311 | } |
312 | |
313 | static void rtw_tx_mgmt_pkt_info_update(struct rtw_dev *rtwdev, |
314 | struct rtw_tx_pkt_info *pkt_info, |
315 | struct ieee80211_sta *sta, |
316 | struct sk_buff *skb) |
317 | { |
318 | rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, ignore_rate: false); |
319 | pkt_info->dis_qselseq = true; |
320 | pkt_info->en_hwseq = true; |
321 | pkt_info->hw_ssn_sel = 0; |
322 | /* TODO: need to change hw port and hw ssn sel for multiple vifs */ |
323 | } |
324 | |
325 | static void rtw_tx_data_pkt_info_update(struct rtw_dev *rtwdev, |
326 | struct rtw_tx_pkt_info *pkt_info, |
327 | struct ieee80211_sta *sta, |
328 | struct sk_buff *skb) |
329 | { |
330 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
331 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
332 | struct ieee80211_hw *hw = rtwdev->hw; |
333 | struct rtw_dm_info *dm_info = &rtwdev->dm_info; |
334 | struct rtw_sta_info *si; |
335 | u8 fix_rate; |
336 | u16 seq; |
337 | u8 ampdu_factor = 0; |
338 | u8 ampdu_density = 0; |
339 | bool ampdu_en = false; |
340 | u8 rate = DESC_RATE6M; |
341 | u8 rate_id = 6; |
342 | u8 bw = RTW_CHANNEL_WIDTH_20; |
343 | bool stbc = false; |
344 | bool ldpc = false; |
345 | |
346 | seq = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4; |
347 | |
348 | /* for broadcast/multicast, use default values */ |
349 | if (!sta) |
350 | goto out; |
351 | |
352 | if (info->flags & IEEE80211_TX_CTL_AMPDU) { |
353 | ampdu_en = true; |
354 | ampdu_factor = get_tx_ampdu_factor(sta); |
355 | ampdu_density = get_tx_ampdu_density(sta); |
356 | } |
357 | |
358 | if (info->control.use_rts || skb->len > hw->wiphy->rts_threshold) |
359 | pkt_info->rts = true; |
360 | |
361 | if (sta->deflink.vht_cap.vht_supported) |
362 | rate = get_highest_vht_tx_rate(rtwdev, sta); |
363 | else if (sta->deflink.ht_cap.ht_supported) |
364 | rate = get_highest_ht_tx_rate(rtwdev, sta); |
365 | else if (sta->deflink.supp_rates[0] <= 0xf) |
366 | rate = DESC_RATE11M; |
367 | else |
368 | rate = DESC_RATE54M; |
369 | |
370 | si = (struct rtw_sta_info *)sta->drv_priv; |
371 | |
372 | bw = si->bw_mode; |
373 | rate_id = si->rate_id; |
374 | stbc = rtwdev->hal.txrx_1ss ? false : si->stbc_en; |
375 | ldpc = si->ldpc_en; |
376 | |
377 | out: |
378 | pkt_info->seq = seq; |
379 | pkt_info->ampdu_factor = ampdu_factor; |
380 | pkt_info->ampdu_density = ampdu_density; |
381 | pkt_info->ampdu_en = ampdu_en; |
382 | pkt_info->rate = rate; |
383 | pkt_info->rate_id = rate_id; |
384 | pkt_info->bw = bw; |
385 | pkt_info->stbc = stbc; |
386 | pkt_info->ldpc = ldpc; |
387 | |
388 | fix_rate = dm_info->fix_rate; |
389 | if (fix_rate < DESC_RATE_MAX) { |
390 | pkt_info->rate = fix_rate; |
391 | pkt_info->dis_rate_fallback = true; |
392 | pkt_info->use_rate = true; |
393 | } |
394 | } |
395 | |
396 | void rtw_tx_pkt_info_update(struct rtw_dev *rtwdev, |
397 | struct rtw_tx_pkt_info *pkt_info, |
398 | struct ieee80211_sta *sta, |
399 | struct sk_buff *skb) |
400 | { |
401 | const struct rtw_chip_info *chip = rtwdev->chip; |
402 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
403 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
404 | struct rtw_sta_info *si; |
405 | struct ieee80211_vif *vif = NULL; |
406 | __le16 fc = hdr->frame_control; |
407 | bool bmc; |
408 | |
409 | if (sta) { |
410 | si = (struct rtw_sta_info *)sta->drv_priv; |
411 | vif = si->vif; |
412 | } |
413 | |
414 | if (ieee80211_is_mgmt(fc) || ieee80211_is_nullfunc(fc)) |
415 | rtw_tx_mgmt_pkt_info_update(rtwdev, pkt_info, sta, skb); |
416 | else if (ieee80211_is_data(fc)) |
417 | rtw_tx_data_pkt_info_update(rtwdev, pkt_info, sta, skb); |
418 | |
419 | bmc = is_broadcast_ether_addr(addr: hdr->addr1) || |
420 | is_multicast_ether_addr(addr: hdr->addr1); |
421 | |
422 | if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) |
423 | rtw_tx_report_enable(rtwdev, pkt_info); |
424 | |
425 | pkt_info->bmc = bmc; |
426 | rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); |
427 | pkt_info->tx_pkt_size = skb->len; |
428 | pkt_info->offset = chip->tx_pkt_desc_sz; |
429 | pkt_info->qsel = skb->priority; |
430 | pkt_info->ls = true; |
431 | |
432 | /* maybe merge with tx status ? */ |
433 | rtw_tx_stats(rtwdev, vif, skb); |
434 | } |
435 | |
436 | void rtw_tx_rsvd_page_pkt_info_update(struct rtw_dev *rtwdev, |
437 | struct rtw_tx_pkt_info *pkt_info, |
438 | struct sk_buff *skb, |
439 | enum rtw_rsvd_packet_type type) |
440 | { |
441 | const struct rtw_chip_info *chip = rtwdev->chip; |
442 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
443 | bool bmc; |
444 | |
445 | /* A beacon or dummy reserved page packet indicates that it is the first |
446 | * reserved page, and the qsel of it will be set in each hci. |
447 | */ |
448 | if (type != RSVD_BEACON && type != RSVD_DUMMY) |
449 | pkt_info->qsel = TX_DESC_QSEL_MGMT; |
450 | |
451 | rtw_tx_pkt_info_update_rate(rtwdev, pkt_info, skb, ignore_rate: true); |
452 | |
453 | bmc = is_broadcast_ether_addr(addr: hdr->addr1) || |
454 | is_multicast_ether_addr(addr: hdr->addr1); |
455 | pkt_info->bmc = bmc; |
456 | pkt_info->tx_pkt_size = skb->len; |
457 | pkt_info->offset = chip->tx_pkt_desc_sz; |
458 | pkt_info->ls = true; |
459 | if (type == RSVD_PS_POLL) { |
460 | pkt_info->nav_use_hdr = true; |
461 | } else { |
462 | pkt_info->dis_qselseq = true; |
463 | pkt_info->en_hwseq = true; |
464 | pkt_info->hw_ssn_sel = 0; |
465 | } |
466 | if (type == RSVD_QOS_NULL) |
467 | pkt_info->bt_null = true; |
468 | |
469 | if (type == RSVD_BEACON) { |
470 | struct rtw_rsvd_page *rsvd_pkt; |
471 | int hdr_len; |
472 | |
473 | rsvd_pkt = list_first_entry_or_null(&rtwdev->rsvd_page_list, |
474 | struct rtw_rsvd_page, |
475 | build_list); |
476 | if (rsvd_pkt && rsvd_pkt->tim_offset != 0) { |
477 | hdr_len = sizeof(struct ieee80211_hdr_3addr); |
478 | pkt_info->tim_offset = rsvd_pkt->tim_offset - hdr_len; |
479 | } |
480 | } |
481 | |
482 | rtw_tx_pkt_info_update_sec(rtwdev, pkt_info, skb); |
483 | |
484 | /* TODO: need to change hw port and hw ssn sel for multiple vifs */ |
485 | } |
486 | |
487 | struct sk_buff * |
488 | rtw_tx_write_data_rsvd_page_get(struct rtw_dev *rtwdev, |
489 | struct rtw_tx_pkt_info *pkt_info, |
490 | u8 *buf, u32 size) |
491 | { |
492 | const struct rtw_chip_info *chip = rtwdev->chip; |
493 | struct sk_buff *skb; |
494 | u32 tx_pkt_desc_sz; |
495 | u32 length; |
496 | |
497 | tx_pkt_desc_sz = chip->tx_pkt_desc_sz; |
498 | length = size + tx_pkt_desc_sz; |
499 | skb = dev_alloc_skb(length); |
500 | if (!skb) { |
501 | rtw_err(rtwdev, "failed to alloc write data rsvd page skb\n" ); |
502 | return NULL; |
503 | } |
504 | |
505 | skb_reserve(skb, len: tx_pkt_desc_sz); |
506 | skb_put_data(skb, data: buf, len: size); |
507 | rtw_tx_rsvd_page_pkt_info_update(rtwdev, pkt_info, skb, type: RSVD_BEACON); |
508 | |
509 | return skb; |
510 | } |
511 | EXPORT_SYMBOL(rtw_tx_write_data_rsvd_page_get); |
512 | |
513 | struct sk_buff * |
514 | rtw_tx_write_data_h2c_get(struct rtw_dev *rtwdev, |
515 | struct rtw_tx_pkt_info *pkt_info, |
516 | u8 *buf, u32 size) |
517 | { |
518 | const struct rtw_chip_info *chip = rtwdev->chip; |
519 | struct sk_buff *skb; |
520 | u32 tx_pkt_desc_sz; |
521 | u32 length; |
522 | |
523 | tx_pkt_desc_sz = chip->tx_pkt_desc_sz; |
524 | length = size + tx_pkt_desc_sz; |
525 | skb = dev_alloc_skb(length); |
526 | if (!skb) { |
527 | rtw_err(rtwdev, "failed to alloc write data h2c skb\n" ); |
528 | return NULL; |
529 | } |
530 | |
531 | skb_reserve(skb, len: tx_pkt_desc_sz); |
532 | skb_put_data(skb, data: buf, len: size); |
533 | pkt_info->tx_pkt_size = size; |
534 | |
535 | return skb; |
536 | } |
537 | EXPORT_SYMBOL(rtw_tx_write_data_h2c_get); |
538 | |
539 | void rtw_tx(struct rtw_dev *rtwdev, |
540 | struct ieee80211_tx_control *control, |
541 | struct sk_buff *skb) |
542 | { |
543 | struct rtw_tx_pkt_info pkt_info = {0}; |
544 | int ret; |
545 | |
546 | rtw_tx_pkt_info_update(rtwdev, pkt_info: &pkt_info, sta: control->sta, skb); |
547 | ret = rtw_hci_tx_write(rtwdev, pkt_info: &pkt_info, skb); |
548 | if (ret) { |
549 | rtw_err(rtwdev, "failed to write TX skb to HCI\n" ); |
550 | goto out; |
551 | } |
552 | |
553 | rtw_hci_tx_kick_off(rtwdev); |
554 | |
555 | return; |
556 | |
557 | out: |
558 | ieee80211_free_txskb(hw: rtwdev->hw, skb); |
559 | } |
560 | |
561 | static void rtw_txq_check_agg(struct rtw_dev *rtwdev, |
562 | struct rtw_txq *rtwtxq, |
563 | struct sk_buff *skb) |
564 | { |
565 | struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); |
566 | struct ieee80211_tx_info *info; |
567 | struct rtw_sta_info *si; |
568 | |
569 | if (test_bit(RTW_TXQ_AMPDU, &rtwtxq->flags)) { |
570 | info = IEEE80211_SKB_CB(skb); |
571 | info->flags |= IEEE80211_TX_CTL_AMPDU; |
572 | return; |
573 | } |
574 | |
575 | if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO) |
576 | return; |
577 | |
578 | if (test_bit(RTW_TXQ_BLOCK_BA, &rtwtxq->flags)) |
579 | return; |
580 | |
581 | if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))) |
582 | return; |
583 | |
584 | if (!txq->sta) |
585 | return; |
586 | |
587 | si = (struct rtw_sta_info *)txq->sta->drv_priv; |
588 | set_bit(nr: txq->tid, addr: si->tid_ba); |
589 | |
590 | ieee80211_queue_work(hw: rtwdev->hw, work: &rtwdev->ba_work); |
591 | } |
592 | |
593 | static int rtw_txq_push_skb(struct rtw_dev *rtwdev, |
594 | struct rtw_txq *rtwtxq, |
595 | struct sk_buff *skb) |
596 | { |
597 | struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); |
598 | struct rtw_tx_pkt_info pkt_info = {0}; |
599 | int ret; |
600 | |
601 | rtw_txq_check_agg(rtwdev, rtwtxq, skb); |
602 | |
603 | rtw_tx_pkt_info_update(rtwdev, pkt_info: &pkt_info, sta: txq->sta, skb); |
604 | ret = rtw_hci_tx_write(rtwdev, pkt_info: &pkt_info, skb); |
605 | if (ret) { |
606 | rtw_err(rtwdev, "failed to write TX skb to HCI\n" ); |
607 | return ret; |
608 | } |
609 | return 0; |
610 | } |
611 | |
612 | static struct sk_buff *rtw_txq_dequeue(struct rtw_dev *rtwdev, |
613 | struct rtw_txq *rtwtxq) |
614 | { |
615 | struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); |
616 | struct sk_buff *skb; |
617 | |
618 | skb = ieee80211_tx_dequeue(hw: rtwdev->hw, txq); |
619 | if (!skb) |
620 | return NULL; |
621 | |
622 | return skb; |
623 | } |
624 | |
625 | static void rtw_txq_push(struct rtw_dev *rtwdev, |
626 | struct rtw_txq *rtwtxq, |
627 | unsigned long frames) |
628 | { |
629 | struct sk_buff *skb; |
630 | int ret; |
631 | int i; |
632 | |
633 | rcu_read_lock(); |
634 | |
635 | for (i = 0; i < frames; i++) { |
636 | skb = rtw_txq_dequeue(rtwdev, rtwtxq); |
637 | if (!skb) |
638 | break; |
639 | |
640 | ret = rtw_txq_push_skb(rtwdev, rtwtxq, skb); |
641 | if (ret) { |
642 | rtw_err(rtwdev, "failed to pusk skb, ret %d\n" , ret); |
643 | break; |
644 | } |
645 | } |
646 | |
647 | rcu_read_unlock(); |
648 | } |
649 | |
650 | void __rtw_tx_work(struct rtw_dev *rtwdev) |
651 | { |
652 | struct rtw_txq *rtwtxq, *tmp; |
653 | |
654 | spin_lock_bh(lock: &rtwdev->txq_lock); |
655 | |
656 | list_for_each_entry_safe(rtwtxq, tmp, &rtwdev->txqs, list) { |
657 | struct ieee80211_txq *txq = rtwtxq_to_txq(rtwtxq); |
658 | unsigned long frame_cnt; |
659 | |
660 | ieee80211_txq_get_depth(txq, frame_cnt: &frame_cnt, NULL); |
661 | rtw_txq_push(rtwdev, rtwtxq, frames: frame_cnt); |
662 | |
663 | list_del_init(entry: &rtwtxq->list); |
664 | } |
665 | |
666 | rtw_hci_tx_kick_off(rtwdev); |
667 | |
668 | spin_unlock_bh(lock: &rtwdev->txq_lock); |
669 | } |
670 | |
671 | void rtw_tx_work(struct work_struct *w) |
672 | { |
673 | struct rtw_dev *rtwdev = container_of(w, struct rtw_dev, tx_work); |
674 | |
675 | __rtw_tx_work(rtwdev); |
676 | } |
677 | |
678 | void rtw_txq_init(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) |
679 | { |
680 | struct rtw_txq *rtwtxq; |
681 | |
682 | if (!txq) |
683 | return; |
684 | |
685 | rtwtxq = (struct rtw_txq *)txq->drv_priv; |
686 | INIT_LIST_HEAD(list: &rtwtxq->list); |
687 | } |
688 | |
689 | void rtw_txq_cleanup(struct rtw_dev *rtwdev, struct ieee80211_txq *txq) |
690 | { |
691 | struct rtw_txq *rtwtxq; |
692 | |
693 | if (!txq) |
694 | return; |
695 | |
696 | rtwtxq = (struct rtw_txq *)txq->drv_priv; |
697 | spin_lock_bh(lock: &rtwdev->txq_lock); |
698 | if (!list_empty(head: &rtwtxq->list)) |
699 | list_del_init(entry: &rtwtxq->list); |
700 | spin_unlock_bh(lock: &rtwdev->txq_lock); |
701 | } |
702 | |
703 | static const enum rtw_tx_queue_type ac_to_hwq[] = { |
704 | [IEEE80211_AC_VO] = RTW_TX_QUEUE_VO, |
705 | [IEEE80211_AC_VI] = RTW_TX_QUEUE_VI, |
706 | [IEEE80211_AC_BE] = RTW_TX_QUEUE_BE, |
707 | [IEEE80211_AC_BK] = RTW_TX_QUEUE_BK, |
708 | }; |
709 | |
710 | static_assert(ARRAY_SIZE(ac_to_hwq) == IEEE80211_NUM_ACS); |
711 | |
712 | enum rtw_tx_queue_type rtw_tx_ac_to_hwq(enum ieee80211_ac_numbers ac) |
713 | { |
714 | if (WARN_ON(unlikely(ac >= IEEE80211_NUM_ACS))) |
715 | return RTW_TX_QUEUE_BE; |
716 | |
717 | return ac_to_hwq[ac]; |
718 | } |
719 | EXPORT_SYMBOL(rtw_tx_ac_to_hwq); |
720 | |
721 | enum rtw_tx_queue_type rtw_tx_queue_mapping(struct sk_buff *skb) |
722 | { |
723 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
724 | __le16 fc = hdr->frame_control; |
725 | u8 q_mapping = skb_get_queue_mapping(skb); |
726 | enum rtw_tx_queue_type queue; |
727 | |
728 | if (unlikely(ieee80211_is_beacon(fc))) |
729 | queue = RTW_TX_QUEUE_BCN; |
730 | else if (unlikely(ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))) |
731 | queue = RTW_TX_QUEUE_MGMT; |
732 | else if (is_broadcast_ether_addr(addr: hdr->addr1) || |
733 | is_multicast_ether_addr(addr: hdr->addr1)) |
734 | queue = RTW_TX_QUEUE_HI0; |
735 | else if (WARN_ON_ONCE(q_mapping >= ARRAY_SIZE(ac_to_hwq))) |
736 | queue = ac_to_hwq[IEEE80211_AC_BE]; |
737 | else |
738 | queue = ac_to_hwq[q_mapping]; |
739 | |
740 | return queue; |
741 | } |
742 | EXPORT_SYMBOL(rtw_tx_queue_mapping); |
743 | |