1 |
From 91ea99070aba39173f56281703b885d0c86f76d9 Mon Sep 17 00:00:00 2001 |
2 |
From: Ping-Ke Shih <pkshih@realtek.com> |
3 |
Date: Fri, 8 Oct 2021 11:56:11 +0800 |
4 |
Subject: [PATCH 08/24] rtw89: implement mac80211 ops |
5 |
|
6 |
Implement ops to interactive with mac80211. The ops contain start/stop, |
7 |
TX, add/remove vif, config, sta state, key, ampdu action, |
8 |
sw_scan_start/complete, and so on. To avoid racing between ieee80211 |
9 |
delayed work and ioctl, all of them are protected by rtwdev->mutex. |
10 |
To yield better TX performance, wake TX queue is implemented. |
11 |
|
12 |
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com> |
13 |
Signed-off-by: Kalle Valo <kvalo@codeaurora.org> |
14 |
Link: https://lore.kernel.org/r/20211008035627.19463-9-pkshih@realtek.com |
15 |
--- |
16 |
drivers/net/wireless/realtek/rtw89/mac80211.c | 676 ++++++++++++++++++ |
17 |
1 file changed, 676 insertions(+) |
18 |
create mode 100644 drivers/net/wireless/realtek/rtw89/mac80211.c |
19 |
|
20 |
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c |
21 |
new file mode 100644 |
22 |
index 000000000000..16dc6fb7dbb0 |
23 |
--- /dev/null |
24 |
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c |
25 |
@@ -0,0 +1,676 @@ |
26 |
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
27 |
+/* Copyright(c) 2019-2020 Realtek Corporation |
28 |
+ */ |
29 |
+ |
30 |
+#include "cam.h" |
31 |
+#include "coex.h" |
32 |
+#include "debug.h" |
33 |
+#include "fw.h" |
34 |
+#include "mac.h" |
35 |
+#include "phy.h" |
36 |
+#include "ps.h" |
37 |
+#include "reg.h" |
38 |
+#include "sar.h" |
39 |
+#include "ser.h" |
40 |
+ |
41 |
+static void rtw89_ops_tx(struct ieee80211_hw *hw, |
42 |
+ struct ieee80211_tx_control *control, |
43 |
+ struct sk_buff *skb) |
44 |
+{ |
45 |
+ struct rtw89_dev *rtwdev = hw->priv; |
46 |
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
47 |
+ struct ieee80211_vif *vif = info->control.vif; |
48 |
+ struct ieee80211_sta *sta = control->sta; |
49 |
+ int ret, qsel; |
50 |
+ |
51 |
+ ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, &qsel); |
52 |
+ if (ret) { |
53 |
+ rtw89_err(rtwdev, "failed to transmit skb: %d\n", ret); |
54 |
+ ieee80211_free_txskb(hw, skb); |
55 |
+ } |
56 |
+ rtw89_core_tx_kick_off(rtwdev, qsel); |
57 |
+} |
58 |
+ |
59 |
+static void rtw89_ops_wake_tx_queue(struct ieee80211_hw *hw, |
60 |
+ struct ieee80211_txq *txq) |
61 |
+{ |
62 |
+ struct rtw89_dev *rtwdev = hw->priv; |
63 |
+ |
64 |
+ ieee80211_schedule_txq(hw, txq); |
65 |
+ queue_work(rtwdev->txq_wq, &rtwdev->txq_work); |
66 |
+} |
67 |
+ |
68 |
+static int rtw89_ops_start(struct ieee80211_hw *hw) |
69 |
+{ |
70 |
+ struct rtw89_dev *rtwdev = hw->priv; |
71 |
+ int ret; |
72 |
+ |
73 |
+ mutex_lock(&rtwdev->mutex); |
74 |
+ ret = rtw89_core_start(rtwdev); |
75 |
+ mutex_unlock(&rtwdev->mutex); |
76 |
+ |
77 |
+ return ret; |
78 |
+} |
79 |
+ |
80 |
+static void rtw89_ops_stop(struct ieee80211_hw *hw) |
81 |
+{ |
82 |
+ struct rtw89_dev *rtwdev = hw->priv; |
83 |
+ |
84 |
+ mutex_lock(&rtwdev->mutex); |
85 |
+ rtw89_core_stop(rtwdev); |
86 |
+ mutex_unlock(&rtwdev->mutex); |
87 |
+} |
88 |
+ |
89 |
+static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) |
90 |
+{ |
91 |
+ struct rtw89_dev *rtwdev = hw->priv; |
92 |
+ |
93 |
+ mutex_lock(&rtwdev->mutex); |
94 |
+ rtw89_leave_ps_mode(rtwdev); |
95 |
+ |
96 |
+ if ((changed & IEEE80211_CONF_CHANGE_IDLE) && |
97 |
+ !(hw->conf.flags & IEEE80211_CONF_IDLE)) |
98 |
+ rtw89_leave_ips(rtwdev); |
99 |
+ |
100 |
+ if (changed & IEEE80211_CONF_CHANGE_PS) { |
101 |
+ if (hw->conf.flags & IEEE80211_CONF_PS) { |
102 |
+ rtwdev->lps_enabled = true; |
103 |
+ } else { |
104 |
+ rtw89_leave_lps(rtwdev); |
105 |
+ rtwdev->lps_enabled = false; |
106 |
+ } |
107 |
+ } |
108 |
+ |
109 |
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) |
110 |
+ rtw89_set_channel(rtwdev); |
111 |
+ |
112 |
+ if ((changed & IEEE80211_CONF_CHANGE_IDLE) && |
113 |
+ (hw->conf.flags & IEEE80211_CONF_IDLE)) |
114 |
+ rtw89_enter_ips(rtwdev); |
115 |
+ |
116 |
+ mutex_unlock(&rtwdev->mutex); |
117 |
+ |
118 |
+ return 0; |
119 |
+} |
120 |
+ |
121 |
+static int rtw89_ops_add_interface(struct ieee80211_hw *hw, |
122 |
+ struct ieee80211_vif *vif) |
123 |
+{ |
124 |
+ struct rtw89_dev *rtwdev = hw->priv; |
125 |
+ struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
126 |
+ int ret = 0; |
127 |
+ |
128 |
+ mutex_lock(&rtwdev->mutex); |
129 |
+ list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list); |
130 |
+ rtw89_leave_ps_mode(rtwdev); |
131 |
+ |
132 |
+ rtw89_traffic_stats_init(rtwdev, &rtwvif->stats); |
133 |
+ rtw89_vif_type_mapping(vif, false); |
134 |
+ rtwvif->port = rtw89_core_acquire_bit_map(rtwdev->hw_port, |
135 |
+ RTW89_MAX_HW_PORT_NUM); |
136 |
+ if (rtwvif->port == RTW89_MAX_HW_PORT_NUM) { |
137 |
+ ret = -ENOSPC; |
138 |
+ goto out; |
139 |
+ } |
140 |
+ |
141 |
+ rtwvif->bcn_hit_cond = 0; |
142 |
+ rtwvif->mac_idx = RTW89_MAC_0; |
143 |
+ rtwvif->phy_idx = RTW89_PHY_0; |
144 |
+ rtwvif->hit_rule = 0; |
145 |
+ ether_addr_copy(rtwvif->mac_addr, vif->addr); |
146 |
+ |
147 |
+ ret = rtw89_mac_add_vif(rtwdev, rtwvif); |
148 |
+ if (ret) { |
149 |
+ rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); |
150 |
+ goto out; |
151 |
+ } |
152 |
+ |
153 |
+ rtw89_core_txq_init(rtwdev, vif->txq); |
154 |
+ |
155 |
+ rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_START); |
156 |
+out: |
157 |
+ mutex_unlock(&rtwdev->mutex); |
158 |
+ |
159 |
+ return ret; |
160 |
+} |
161 |
+ |
162 |
+static void rtw89_ops_remove_interface(struct ieee80211_hw *hw, |
163 |
+ struct ieee80211_vif *vif) |
164 |
+{ |
165 |
+ struct rtw89_dev *rtwdev = hw->priv; |
166 |
+ struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
167 |
+ |
168 |
+ mutex_lock(&rtwdev->mutex); |
169 |
+ rtw89_leave_ps_mode(rtwdev); |
170 |
+ rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, BTC_ROLE_STOP); |
171 |
+ rtw89_mac_remove_vif(rtwdev, rtwvif); |
172 |
+ rtw89_core_release_bit_map(rtwdev->hw_port, rtwvif->port); |
173 |
+ list_del_init(&rtwvif->list); |
174 |
+ mutex_unlock(&rtwdev->mutex); |
175 |
+} |
176 |
+ |
177 |
+static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, |
178 |
+ unsigned int changed_flags, |
179 |
+ unsigned int *new_flags, |
180 |
+ u64 multicast) |
181 |
+{ |
182 |
+ struct rtw89_dev *rtwdev = hw->priv; |
183 |
+ |
184 |
+ mutex_lock(&rtwdev->mutex); |
185 |
+ rtw89_leave_ps_mode(rtwdev); |
186 |
+ |
187 |
+ *new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL | |
188 |
+ FIF_BCN_PRBRESP_PROMISC; |
189 |
+ |
190 |
+ if (changed_flags & FIF_ALLMULTI) { |
191 |
+ if (*new_flags & FIF_ALLMULTI) |
192 |
+ rtwdev->hal.rx_fltr &= ~B_AX_A_MC; |
193 |
+ else |
194 |
+ rtwdev->hal.rx_fltr |= B_AX_A_MC; |
195 |
+ } |
196 |
+ if (changed_flags & FIF_FCSFAIL) { |
197 |
+ if (*new_flags & FIF_FCSFAIL) |
198 |
+ rtwdev->hal.rx_fltr |= B_AX_A_CRC32_ERR; |
199 |
+ else |
200 |
+ rtwdev->hal.rx_fltr &= ~B_AX_A_CRC32_ERR; |
201 |
+ } |
202 |
+ if (changed_flags & FIF_OTHER_BSS) { |
203 |
+ if (*new_flags & FIF_OTHER_BSS) |
204 |
+ rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH; |
205 |
+ else |
206 |
+ rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; |
207 |
+ } |
208 |
+ if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { |
209 |
+ if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { |
210 |
+ rtwdev->hal.rx_fltr &= ~B_AX_A_BCN_CHK_EN; |
211 |
+ rtwdev->hal.rx_fltr &= ~B_AX_A_BC; |
212 |
+ rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH; |
213 |
+ } else { |
214 |
+ rtwdev->hal.rx_fltr |= B_AX_A_BCN_CHK_EN; |
215 |
+ rtwdev->hal.rx_fltr |= B_AX_A_BC; |
216 |
+ rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; |
217 |
+ } |
218 |
+ } |
219 |
+ |
220 |
+ rtw89_write32_mask(rtwdev, |
221 |
+ rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_0), |
222 |
+ B_AX_RX_FLTR_CFG_MASK, |
223 |
+ rtwdev->hal.rx_fltr); |
224 |
+ if (!rtwdev->dbcc_en) |
225 |
+ goto out; |
226 |
+ rtw89_write32_mask(rtwdev, |
227 |
+ rtw89_mac_reg_by_idx(R_AX_RX_FLTR_OPT, RTW89_MAC_1), |
228 |
+ B_AX_RX_FLTR_CFG_MASK, |
229 |
+ rtwdev->hal.rx_fltr); |
230 |
+ |
231 |
+out: |
232 |
+ mutex_unlock(&rtwdev->mutex); |
233 |
+} |
234 |
+ |
235 |
+static const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = { |
236 |
+ [IEEE80211_AC_VO] = 3, |
237 |
+ [IEEE80211_AC_VI] = 2, |
238 |
+ [IEEE80211_AC_BE] = 0, |
239 |
+ [IEEE80211_AC_BK] = 1, |
240 |
+}; |
241 |
+ |
242 |
+static u8 rtw89_aifsn_to_aifs(struct rtw89_dev *rtwdev, |
243 |
+ struct rtw89_vif *rtwvif, u8 aifsn) |
244 |
+{ |
245 |
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); |
246 |
+ u8 slot_time; |
247 |
+ u8 sifs; |
248 |
+ |
249 |
+ slot_time = vif->bss_conf.use_short_slot ? 9 : 20; |
250 |
+ sifs = rtwdev->hal.current_band_type == RTW89_BAND_5G ? 16 : 10; |
251 |
+ |
252 |
+ return aifsn * slot_time + sifs; |
253 |
+} |
254 |
+ |
255 |
+static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev, |
256 |
+ struct rtw89_vif *rtwvif, u16 ac) |
257 |
+{ |
258 |
+ struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; |
259 |
+ u32 val; |
260 |
+ u8 ecw_max, ecw_min; |
261 |
+ u8 aifs; |
262 |
+ |
263 |
+ /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ |
264 |
+ ecw_max = ilog2(params->cw_max + 1); |
265 |
+ ecw_min = ilog2(params->cw_min + 1); |
266 |
+ aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif, params->aifs); |
267 |
+ val = FIELD_PREP(FW_EDCA_PARAM_TXOPLMT_MSK, params->txop) | |
268 |
+ FIELD_PREP(FW_EDCA_PARAM_CWMAX_MSK, ecw_max) | |
269 |
+ FIELD_PREP(FW_EDCA_PARAM_CWMIN_MSK, ecw_min) | |
270 |
+ FIELD_PREP(FW_EDCA_PARAM_AIFS_MSK, aifs); |
271 |
+ rtw89_fw_h2c_set_edca(rtwdev, rtwvif, ac_to_fw_idx[ac], val); |
272 |
+} |
273 |
+ |
274 |
+static const u32 ac_to_mu_edca_param[IEEE80211_NUM_ACS] = { |
275 |
+ [IEEE80211_AC_VO] = R_AX_MUEDCA_VO_PARAM_0, |
276 |
+ [IEEE80211_AC_VI] = R_AX_MUEDCA_VI_PARAM_0, |
277 |
+ [IEEE80211_AC_BE] = R_AX_MUEDCA_BE_PARAM_0, |
278 |
+ [IEEE80211_AC_BK] = R_AX_MUEDCA_BK_PARAM_0, |
279 |
+}; |
280 |
+ |
281 |
+static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, |
282 |
+ struct rtw89_vif *rtwvif, u16 ac) |
283 |
+{ |
284 |
+ struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; |
285 |
+ struct ieee80211_he_mu_edca_param_ac_rec *mu_edca; |
286 |
+ u8 aifs, aifsn; |
287 |
+ u16 timer_32us; |
288 |
+ u32 reg; |
289 |
+ u32 val; |
290 |
+ |
291 |
+ if (!params->mu_edca) |
292 |
+ return; |
293 |
+ |
294 |
+ mu_edca = ¶ms->mu_edca_param_rec; |
295 |
+ aifsn = FIELD_GET(GENMASK(3, 0), mu_edca->aifsn); |
296 |
+ aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif, aifsn) : 0; |
297 |
+ timer_32us = mu_edca->mu_edca_timer << 8; |
298 |
+ |
299 |
+ val = FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_TIMER_MASK, timer_32us) | |
300 |
+ FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_CW_MASK, mu_edca->ecw_min_max) | |
301 |
+ FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_AIFS_MASK, aifs); |
302 |
+ reg = rtw89_mac_reg_by_idx(ac_to_mu_edca_param[ac], rtwvif->mac_idx); |
303 |
+ rtw89_write32(rtwdev, reg, val); |
304 |
+ |
305 |
+ rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, true); |
306 |
+} |
307 |
+ |
308 |
+static void __rtw89_conf_tx(struct rtw89_dev *rtwdev, |
309 |
+ struct rtw89_vif *rtwvif, u16 ac) |
310 |
+{ |
311 |
+ ____rtw89_conf_tx_edca(rtwdev, rtwvif, ac); |
312 |
+ ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif, ac); |
313 |
+} |
314 |
+ |
315 |
+static void rtw89_conf_tx(struct rtw89_dev *rtwdev, |
316 |
+ struct rtw89_vif *rtwvif) |
317 |
+{ |
318 |
+ u16 ac; |
319 |
+ |
320 |
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
321 |
+ __rtw89_conf_tx(rtwdev, rtwvif, ac); |
322 |
+} |
323 |
+ |
324 |
+static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, |
325 |
+ struct ieee80211_vif *vif, |
326 |
+ struct ieee80211_bss_conf *conf) |
327 |
+{ |
328 |
+ struct ieee80211_sta *sta; |
329 |
+ |
330 |
+ if (vif->type != NL80211_IFTYPE_STATION) |
331 |
+ return; |
332 |
+ |
333 |
+ sta = ieee80211_find_sta(vif, conf->bssid); |
334 |
+ if (!sta) { |
335 |
+ rtw89_err(rtwdev, "can't find sta to set sta_assoc state\n"); |
336 |
+ return; |
337 |
+ } |
338 |
+ rtw89_core_sta_assoc(rtwdev, vif, sta); |
339 |
+} |
340 |
+ |
341 |
+static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, |
342 |
+ struct ieee80211_vif *vif, |
343 |
+ struct ieee80211_bss_conf *conf, |
344 |
+ u32 changed) |
345 |
+{ |
346 |
+ struct rtw89_dev *rtwdev = hw->priv; |
347 |
+ struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
348 |
+ |
349 |
+ mutex_lock(&rtwdev->mutex); |
350 |
+ rtw89_leave_ps_mode(rtwdev); |
351 |
+ |
352 |
+ if (changed & BSS_CHANGED_ASSOC) { |
353 |
+ if (conf->assoc) { |
354 |
+ rtw89_station_mode_sta_assoc(rtwdev, vif, conf); |
355 |
+ rtw89_phy_set_bss_color(rtwdev, vif); |
356 |
+ rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); |
357 |
+ rtw89_mac_port_update(rtwdev, rtwvif); |
358 |
+ } |
359 |
+ } |
360 |
+ |
361 |
+ if (changed & BSS_CHANGED_BSSID) { |
362 |
+ ether_addr_copy(rtwvif->bssid, conf->bssid); |
363 |
+ rtw89_cam_bssid_changed(rtwdev, rtwvif); |
364 |
+ rtw89_fw_h2c_cam(rtwdev, rtwvif); |
365 |
+ } |
366 |
+ |
367 |
+ if (changed & BSS_CHANGED_ERP_SLOT) |
368 |
+ rtw89_conf_tx(rtwdev, rtwvif); |
369 |
+ |
370 |
+ if (changed & BSS_CHANGED_HE_BSS_COLOR) |
371 |
+ rtw89_phy_set_bss_color(rtwdev, vif); |
372 |
+ |
373 |
+ if (changed & BSS_CHANGED_MU_GROUPS) |
374 |
+ rtw89_mac_bf_set_gid_table(rtwdev, vif, conf); |
375 |
+ |
376 |
+ mutex_unlock(&rtwdev->mutex); |
377 |
+} |
378 |
+ |
379 |
+static int rtw89_ops_conf_tx(struct ieee80211_hw *hw, |
380 |
+ struct ieee80211_vif *vif, u16 ac, |
381 |
+ const struct ieee80211_tx_queue_params *params) |
382 |
+{ |
383 |
+ struct rtw89_dev *rtwdev = hw->priv; |
384 |
+ struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
385 |
+ |
386 |
+ mutex_lock(&rtwdev->mutex); |
387 |
+ rtw89_leave_ps_mode(rtwdev); |
388 |
+ rtwvif->tx_params[ac] = *params; |
389 |
+ __rtw89_conf_tx(rtwdev, rtwvif, ac); |
390 |
+ mutex_unlock(&rtwdev->mutex); |
391 |
+ |
392 |
+ return 0; |
393 |
+} |
394 |
+ |
395 |
+static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, |
396 |
+ struct ieee80211_vif *vif, |
397 |
+ struct ieee80211_sta *sta, |
398 |
+ enum ieee80211_sta_state old_state, |
399 |
+ enum ieee80211_sta_state new_state) |
400 |
+{ |
401 |
+ struct rtw89_dev *rtwdev = hw->priv; |
402 |
+ |
403 |
+ if (old_state == IEEE80211_STA_NOTEXIST && |
404 |
+ new_state == IEEE80211_STA_NONE) |
405 |
+ return rtw89_core_sta_add(rtwdev, vif, sta); |
406 |
+ |
407 |
+ if (old_state == IEEE80211_STA_AUTH && |
408 |
+ new_state == IEEE80211_STA_ASSOC) { |
409 |
+ if (vif->type == NL80211_IFTYPE_STATION) |
410 |
+ return 0; /* defer to bss_info_changed to have vif info */ |
411 |
+ return rtw89_core_sta_assoc(rtwdev, vif, sta); |
412 |
+ } |
413 |
+ |
414 |
+ if (old_state == IEEE80211_STA_ASSOC && |
415 |
+ new_state == IEEE80211_STA_AUTH) |
416 |
+ return rtw89_core_sta_disassoc(rtwdev, vif, sta); |
417 |
+ |
418 |
+ if (old_state == IEEE80211_STA_AUTH && |
419 |
+ new_state == IEEE80211_STA_NONE) |
420 |
+ return rtw89_core_sta_disconnect(rtwdev, vif, sta); |
421 |
+ |
422 |
+ if (old_state == IEEE80211_STA_NONE && |
423 |
+ new_state == IEEE80211_STA_NOTEXIST) |
424 |
+ return rtw89_core_sta_remove(rtwdev, vif, sta); |
425 |
+ |
426 |
+ return 0; |
427 |
+} |
428 |
+ |
429 |
+static int rtw89_ops_sta_state(struct ieee80211_hw *hw, |
430 |
+ struct ieee80211_vif *vif, |
431 |
+ struct ieee80211_sta *sta, |
432 |
+ enum ieee80211_sta_state old_state, |
433 |
+ enum ieee80211_sta_state new_state) |
434 |
+{ |
435 |
+ struct rtw89_dev *rtwdev = hw->priv; |
436 |
+ int ret; |
437 |
+ |
438 |
+ mutex_lock(&rtwdev->mutex); |
439 |
+ rtw89_leave_ps_mode(rtwdev); |
440 |
+ ret = __rtw89_ops_sta_state(hw, vif, sta, old_state, new_state); |
441 |
+ mutex_unlock(&rtwdev->mutex); |
442 |
+ |
443 |
+ return ret; |
444 |
+} |
445 |
+ |
446 |
+static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
447 |
+ struct ieee80211_vif *vif, |
448 |
+ struct ieee80211_sta *sta, |
449 |
+ struct ieee80211_key_conf *key) |
450 |
+{ |
451 |
+ struct rtw89_dev *rtwdev = hw->priv; |
452 |
+ int ret = 0; |
453 |
+ |
454 |
+ mutex_lock(&rtwdev->mutex); |
455 |
+ rtw89_leave_ps_mode(rtwdev); |
456 |
+ |
457 |
+ switch (cmd) { |
458 |
+ case SET_KEY: |
459 |
+ rtw89_btc_ntfy_specific_packet(rtwdev, PACKET_EAPOL_END); |
460 |
+ ret = rtw89_cam_sec_key_add(rtwdev, vif, sta, key); |
461 |
+ if (ret && ret != -EOPNOTSUPP) { |
462 |
+ rtw89_err(rtwdev, "failed to add key to sec cam\n"); |
463 |
+ goto out; |
464 |
+ } |
465 |
+ break; |
466 |
+ case DISABLE_KEY: |
467 |
+ rtw89_hci_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, |
468 |
+ false); |
469 |
+ rtw89_mac_flush_txq(rtwdev, BIT(rtwdev->hw->queues) - 1, false); |
470 |
+ ret = rtw89_cam_sec_key_del(rtwdev, vif, sta, key, true); |
471 |
+ if (ret) { |
472 |
+ rtw89_err(rtwdev, "failed to remove key from sec cam\n"); |
473 |
+ goto out; |
474 |
+ } |
475 |
+ break; |
476 |
+ } |
477 |
+ |
478 |
+out: |
479 |
+ mutex_unlock(&rtwdev->mutex); |
480 |
+ |
481 |
+ return ret; |
482 |
+} |
483 |
+ |
484 |
+static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, |
485 |
+ struct ieee80211_vif *vif, |
486 |
+ struct ieee80211_ampdu_params *params) |
487 |
+{ |
488 |
+ struct rtw89_dev *rtwdev = hw->priv; |
489 |
+ struct ieee80211_sta *sta = params->sta; |
490 |
+ struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
491 |
+ u16 tid = params->tid; |
492 |
+ struct ieee80211_txq *txq = sta->txq[tid]; |
493 |
+ struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; |
494 |
+ |
495 |
+ switch (params->action) { |
496 |
+ case IEEE80211_AMPDU_TX_START: |
497 |
+ return IEEE80211_AMPDU_TX_START_IMMEDIATE; |
498 |
+ case IEEE80211_AMPDU_TX_STOP_CONT: |
499 |
+ case IEEE80211_AMPDU_TX_STOP_FLUSH: |
500 |
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
501 |
+ mutex_lock(&rtwdev->mutex); |
502 |
+ clear_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); |
503 |
+ rtw89_fw_h2c_ba_cam(rtwdev, false, rtwsta->mac_id, params); |
504 |
+ mutex_unlock(&rtwdev->mutex); |
505 |
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
506 |
+ break; |
507 |
+ case IEEE80211_AMPDU_TX_OPERATIONAL: |
508 |
+ mutex_lock(&rtwdev->mutex); |
509 |
+ set_bit(RTW89_TXQ_F_AMPDU, &rtwtxq->flags); |
510 |
+ rtwsta->ampdu_params[tid].agg_num = params->buf_size; |
511 |
+ rtwsta->ampdu_params[tid].amsdu = params->amsdu; |
512 |
+ rtw89_leave_ps_mode(rtwdev); |
513 |
+ rtw89_fw_h2c_ba_cam(rtwdev, true, rtwsta->mac_id, params); |
514 |
+ mutex_unlock(&rtwdev->mutex); |
515 |
+ break; |
516 |
+ case IEEE80211_AMPDU_RX_START: |
517 |
+ case IEEE80211_AMPDU_RX_STOP: |
518 |
+ break; |
519 |
+ default: |
520 |
+ WARN_ON(1); |
521 |
+ return -ENOTSUPP; |
522 |
+ } |
523 |
+ |
524 |
+ return 0; |
525 |
+} |
526 |
+ |
527 |
+static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) |
528 |
+{ |
529 |
+ struct rtw89_dev *rtwdev = hw->priv; |
530 |
+ |
531 |
+ mutex_lock(&rtwdev->mutex); |
532 |
+ rtw89_leave_ps_mode(rtwdev); |
533 |
+ if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) |
534 |
+ rtw89_mac_update_rts_threshold(rtwdev, RTW89_MAC_0); |
535 |
+ mutex_unlock(&rtwdev->mutex); |
536 |
+ |
537 |
+ return 0; |
538 |
+} |
539 |
+ |
540 |
+static void rtw89_ops_sta_statistics(struct ieee80211_hw *hw, |
541 |
+ struct ieee80211_vif *vif, |
542 |
+ struct ieee80211_sta *sta, |
543 |
+ struct station_info *sinfo) |
544 |
+{ |
545 |
+ struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
546 |
+ |
547 |
+ sinfo->txrate = rtwsta->ra_report.txrate; |
548 |
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); |
549 |
+} |
550 |
+ |
551 |
+static void rtw89_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
552 |
+ u32 queues, bool drop) |
553 |
+{ |
554 |
+ struct rtw89_dev *rtwdev = hw->priv; |
555 |
+ |
556 |
+ mutex_lock(&rtwdev->mutex); |
557 |
+ rtw89_leave_lps(rtwdev); |
558 |
+ rtw89_hci_flush_queues(rtwdev, queues, drop); |
559 |
+ rtw89_mac_flush_txq(rtwdev, queues, drop); |
560 |
+ mutex_unlock(&rtwdev->mutex); |
561 |
+} |
562 |
+ |
563 |
+struct rtw89_iter_bitrate_mask_data { |
564 |
+ struct rtw89_dev *rtwdev; |
565 |
+ struct ieee80211_vif *vif; |
566 |
+ const struct cfg80211_bitrate_mask *mask; |
567 |
+}; |
568 |
+ |
569 |
+static void rtw89_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) |
570 |
+{ |
571 |
+ struct rtw89_iter_bitrate_mask_data *br_data = data; |
572 |
+ struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
573 |
+ struct ieee80211_vif *vif = rtwvif_to_vif(rtwsta->rtwvif); |
574 |
+ |
575 |
+ if (vif != br_data->vif) |
576 |
+ return; |
577 |
+ |
578 |
+ rtwsta->use_cfg_mask = true; |
579 |
+ rtwsta->mask = *br_data->mask; |
580 |
+ rtw89_phy_ra_updata_sta(br_data->rtwdev, sta); |
581 |
+} |
582 |
+ |
583 |
+static void rtw89_ra_mask_info_update(struct rtw89_dev *rtwdev, |
584 |
+ struct ieee80211_vif *vif, |
585 |
+ const struct cfg80211_bitrate_mask *mask) |
586 |
+{ |
587 |
+ struct rtw89_iter_bitrate_mask_data br_data = { .rtwdev = rtwdev, |
588 |
+ .vif = vif, |
589 |
+ .mask = mask}; |
590 |
+ |
591 |
+ ieee80211_iterate_stations_atomic(rtwdev->hw, rtw89_ra_mask_info_update_iter, |
592 |
+ &br_data); |
593 |
+} |
594 |
+ |
595 |
+static int rtw89_ops_set_bitrate_mask(struct ieee80211_hw *hw, |
596 |
+ struct ieee80211_vif *vif, |
597 |
+ const struct cfg80211_bitrate_mask *mask) |
598 |
+{ |
599 |
+ struct rtw89_dev *rtwdev = hw->priv; |
600 |
+ |
601 |
+ mutex_lock(&rtwdev->mutex); |
602 |
+ rtw89_phy_rate_pattern_vif(rtwdev, vif, mask); |
603 |
+ rtw89_ra_mask_info_update(rtwdev, vif, mask); |
604 |
+ mutex_unlock(&rtwdev->mutex); |
605 |
+ |
606 |
+ return 0; |
607 |
+} |
608 |
+ |
609 |
+static |
610 |
+int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) |
611 |
+{ |
612 |
+ struct rtw89_dev *rtwdev = hw->priv; |
613 |
+ struct rtw89_hal *hal = &rtwdev->hal; |
614 |
+ |
615 |
+ if (rx_ant != hw->wiphy->available_antennas_rx) |
616 |
+ return -EINVAL; |
617 |
+ |
618 |
+ mutex_lock(&rtwdev->mutex); |
619 |
+ hal->antenna_tx = tx_ant; |
620 |
+ hal->antenna_rx = rx_ant; |
621 |
+ mutex_unlock(&rtwdev->mutex); |
622 |
+ |
623 |
+ return 0; |
624 |
+} |
625 |
+ |
626 |
+static |
627 |
+int rtw89_ops_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) |
628 |
+{ |
629 |
+ struct rtw89_dev *rtwdev = hw->priv; |
630 |
+ struct rtw89_hal *hal = &rtwdev->hal; |
631 |
+ |
632 |
+ *tx_ant = hal->antenna_tx; |
633 |
+ *rx_ant = hal->antenna_rx; |
634 |
+ |
635 |
+ return 0; |
636 |
+} |
637 |
+ |
638 |
+static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, |
639 |
+ struct ieee80211_vif *vif, |
640 |
+ const u8 *mac_addr) |
641 |
+{ |
642 |
+ struct rtw89_dev *rtwdev = hw->priv; |
643 |
+ struct rtw89_hal *hal = &rtwdev->hal; |
644 |
+ |
645 |
+ mutex_lock(&rtwdev->mutex); |
646 |
+ rtwdev->scanning = true; |
647 |
+ rtw89_leave_lps(rtwdev); |
648 |
+ rtw89_btc_ntfy_scan_start(rtwdev, RTW89_PHY_0, hal->current_band_type); |
649 |
+ rtw89_chip_rfk_scan(rtwdev, true); |
650 |
+ rtw89_hci_recalc_int_mit(rtwdev); |
651 |
+ mutex_unlock(&rtwdev->mutex); |
652 |
+} |
653 |
+ |
654 |
+static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, |
655 |
+ struct ieee80211_vif *vif) |
656 |
+{ |
657 |
+ struct rtw89_dev *rtwdev = hw->priv; |
658 |
+ |
659 |
+ mutex_lock(&rtwdev->mutex); |
660 |
+ rtw89_chip_rfk_scan(rtwdev, false); |
661 |
+ rtw89_btc_ntfy_scan_finish(rtwdev, RTW89_PHY_0); |
662 |
+ rtwdev->scanning = false; |
663 |
+ rtwdev->dig.bypass_dig = true; |
664 |
+ mutex_unlock(&rtwdev->mutex); |
665 |
+} |
666 |
+ |
667 |
+static void rtw89_ops_reconfig_complete(struct ieee80211_hw *hw, |
668 |
+ enum ieee80211_reconfig_type reconfig_type) |
669 |
+{ |
670 |
+ struct rtw89_dev *rtwdev = hw->priv; |
671 |
+ |
672 |
+ if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART) |
673 |
+ rtw89_ser_recfg_done(rtwdev); |
674 |
+} |
675 |
+ |
676 |
+const struct ieee80211_ops rtw89_ops = { |
677 |
+ .tx = rtw89_ops_tx, |
678 |
+ .wake_tx_queue = rtw89_ops_wake_tx_queue, |
679 |
+ .start = rtw89_ops_start, |
680 |
+ .stop = rtw89_ops_stop, |
681 |
+ .config = rtw89_ops_config, |
682 |
+ .add_interface = rtw89_ops_add_interface, |
683 |
+ .remove_interface = rtw89_ops_remove_interface, |
684 |
+ .configure_filter = rtw89_ops_configure_filter, |
685 |
+ .bss_info_changed = rtw89_ops_bss_info_changed, |
686 |
+ .conf_tx = rtw89_ops_conf_tx, |
687 |
+ .sta_state = rtw89_ops_sta_state, |
688 |
+ .set_key = rtw89_ops_set_key, |
689 |
+ .ampdu_action = rtw89_ops_ampdu_action, |
690 |
+ .set_rts_threshold = rtw89_ops_set_rts_threshold, |
691 |
+ .sta_statistics = rtw89_ops_sta_statistics, |
692 |
+ .flush = rtw89_ops_flush, |
693 |
+ .set_bitrate_mask = rtw89_ops_set_bitrate_mask, |
694 |
+ .set_antenna = rtw89_ops_set_antenna, |
695 |
+ .get_antenna = rtw89_ops_get_antenna, |
696 |
+ .sw_scan_start = rtw89_ops_sw_scan_start, |
697 |
+ .sw_scan_complete = rtw89_ops_sw_scan_complete, |
698 |
+ .reconfig_complete = rtw89_ops_reconfig_complete, |
699 |
+ .set_sar_specs = rtw89_ops_set_sar_specs, |
700 |
+}; |
701 |
+EXPORT_SYMBOL(rtw89_ops); |
702 |
-- |
703 |
2.33.0 |
704 |
|