1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
2 | /* Copyright(c) 2019-2020 Realtek Corporation |
3 | */ |
4 | |
5 | #include "cam.h" |
6 | #include "chan.h" |
7 | #include "coex.h" |
8 | #include "debug.h" |
9 | #include "fw.h" |
10 | #include "mac.h" |
11 | #include "phy.h" |
12 | #include "ps.h" |
13 | #include "reg.h" |
14 | #include "sar.h" |
15 | #include "ser.h" |
16 | #include "util.h" |
17 | #include "wow.h" |
18 | |
19 | static void rtw89_ops_tx(struct ieee80211_hw *hw, |
20 | struct ieee80211_tx_control *control, |
21 | struct sk_buff *skb) |
22 | { |
23 | struct rtw89_dev *rtwdev = hw->priv; |
24 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
25 | struct ieee80211_vif *vif = info->control.vif; |
26 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
27 | struct ieee80211_sta *sta = control->sta; |
28 | u32 flags = IEEE80211_SKB_CB(skb)->flags; |
29 | int ret, qsel; |
30 | |
31 | if (rtwvif->offchan && !(flags & IEEE80211_TX_CTL_TX_OFFCHAN) && sta) { |
32 | struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
33 | |
34 | rtw89_debug(rtwdev, mask: RTW89_DBG_TXRX, fmt: "ops_tx during offchan\n" ); |
35 | skb_queue_tail(list: &rtwsta->roc_queue, newsk: skb); |
36 | return; |
37 | } |
38 | |
39 | ret = rtw89_core_tx_write(rtwdev, vif, sta, skb, qsel: &qsel); |
40 | if (ret) { |
41 | rtw89_err(rtwdev, "failed to transmit skb: %d\n" , ret); |
42 | ieee80211_free_txskb(hw, skb); |
43 | return; |
44 | } |
45 | rtw89_core_tx_kick_off(rtwdev, qsel); |
46 | } |
47 | |
48 | static void rtw89_ops_wake_tx_queue(struct ieee80211_hw *hw, |
49 | struct ieee80211_txq *txq) |
50 | { |
51 | struct rtw89_dev *rtwdev = hw->priv; |
52 | |
53 | ieee80211_schedule_txq(hw, txq); |
54 | queue_work(wq: rtwdev->txq_wq, work: &rtwdev->txq_work); |
55 | } |
56 | |
57 | static int rtw89_ops_start(struct ieee80211_hw *hw) |
58 | { |
59 | struct rtw89_dev *rtwdev = hw->priv; |
60 | int ret; |
61 | |
62 | mutex_lock(&rtwdev->mutex); |
63 | ret = rtw89_core_start(rtwdev); |
64 | mutex_unlock(lock: &rtwdev->mutex); |
65 | |
66 | return ret; |
67 | } |
68 | |
69 | static void rtw89_ops_stop(struct ieee80211_hw *hw) |
70 | { |
71 | struct rtw89_dev *rtwdev = hw->priv; |
72 | |
73 | mutex_lock(&rtwdev->mutex); |
74 | rtw89_core_stop(rtwdev); |
75 | mutex_unlock(lock: &rtwdev->mutex); |
76 | } |
77 | |
78 | static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) |
79 | { |
80 | struct rtw89_dev *rtwdev = hw->priv; |
81 | |
82 | /* let previous ips work finish to ensure we don't leave ips twice */ |
83 | cancel_work_sync(work: &rtwdev->ips_work); |
84 | |
85 | mutex_lock(&rtwdev->mutex); |
86 | rtw89_leave_ps_mode(rtwdev); |
87 | |
88 | if ((changed & IEEE80211_CONF_CHANGE_IDLE) && |
89 | !(hw->conf.flags & IEEE80211_CONF_IDLE)) |
90 | rtw89_leave_ips(rtwdev); |
91 | |
92 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
93 | rtw89_config_entity_chandef(rtwdev, idx: RTW89_SUB_ENTITY_0, |
94 | chandef: &hw->conf.chandef); |
95 | rtw89_set_channel(rtwdev); |
96 | } |
97 | |
98 | if ((changed & IEEE80211_CONF_CHANGE_IDLE) && |
99 | (hw->conf.flags & IEEE80211_CONF_IDLE) && |
100 | !rtwdev->scanning) |
101 | rtw89_enter_ips(rtwdev); |
102 | |
103 | mutex_unlock(lock: &rtwdev->mutex); |
104 | |
105 | return 0; |
106 | } |
107 | |
108 | static int rtw89_ops_add_interface(struct ieee80211_hw *hw, |
109 | struct ieee80211_vif *vif) |
110 | { |
111 | struct rtw89_dev *rtwdev = hw->priv; |
112 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
113 | int ret = 0; |
114 | |
115 | rtw89_debug(rtwdev, mask: RTW89_DBG_STATE, fmt: "add vif %pM type %d, p2p %d\n" , |
116 | vif->addr, vif->type, vif->p2p); |
117 | |
118 | mutex_lock(&rtwdev->mutex); |
119 | |
120 | rtw89_leave_ips_by_hwflags(rtwdev); |
121 | |
122 | if (RTW89_CHK_FW_FEATURE(BEACON_FILTER, &rtwdev->fw)) |
123 | vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER | |
124 | IEEE80211_VIF_SUPPORTS_CQM_RSSI; |
125 | |
126 | rtwvif->rtwdev = rtwdev; |
127 | rtwvif->roc.state = RTW89_ROC_IDLE; |
128 | rtwvif->offchan = false; |
129 | list_add_tail(new: &rtwvif->list, head: &rtwdev->rtwvifs_list); |
130 | INIT_WORK(&rtwvif->update_beacon_work, rtw89_core_update_beacon_work); |
131 | INIT_DELAYED_WORK(&rtwvif->roc.roc_work, rtw89_roc_work); |
132 | rtw89_leave_ps_mode(rtwdev); |
133 | |
134 | rtw89_traffic_stats_init(rtwdev, stats: &rtwvif->stats); |
135 | rtw89_vif_type_mapping(vif, assoc: false); |
136 | rtwvif->port = rtw89_core_acquire_bit_map(addr: rtwdev->hw_port, |
137 | size: RTW89_PORT_NUM); |
138 | if (rtwvif->port == RTW89_PORT_NUM) { |
139 | ret = -ENOSPC; |
140 | list_del_init(entry: &rtwvif->list); |
141 | goto out; |
142 | } |
143 | |
144 | rtwvif->bcn_hit_cond = 0; |
145 | rtwvif->mac_idx = RTW89_MAC_0; |
146 | rtwvif->phy_idx = RTW89_PHY_0; |
147 | rtwvif->sub_entity_idx = RTW89_SUB_ENTITY_0; |
148 | rtwvif->chanctx_assigned = false; |
149 | rtwvif->hit_rule = 0; |
150 | rtwvif->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; |
151 | ether_addr_copy(dst: rtwvif->mac_addr, src: vif->addr); |
152 | INIT_LIST_HEAD(list: &rtwvif->general_pkt_list); |
153 | |
154 | ret = rtw89_mac_add_vif(rtwdev, vif: rtwvif); |
155 | if (ret) { |
156 | rtw89_core_release_bit_map(addr: rtwdev->hw_port, bit: rtwvif->port); |
157 | list_del_init(entry: &rtwvif->list); |
158 | goto out; |
159 | } |
160 | |
161 | rtw89_core_txq_init(rtwdev, txq: vif->txq); |
162 | |
163 | rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, state: BTC_ROLE_START); |
164 | |
165 | rtw89_recalc_lps(rtwdev); |
166 | out: |
167 | mutex_unlock(lock: &rtwdev->mutex); |
168 | |
169 | return ret; |
170 | } |
171 | |
172 | static void rtw89_ops_remove_interface(struct ieee80211_hw *hw, |
173 | struct ieee80211_vif *vif) |
174 | { |
175 | struct rtw89_dev *rtwdev = hw->priv; |
176 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
177 | |
178 | rtw89_debug(rtwdev, mask: RTW89_DBG_STATE, fmt: "remove vif %pM type %d p2p %d\n" , |
179 | vif->addr, vif->type, vif->p2p); |
180 | |
181 | cancel_work_sync(work: &rtwvif->update_beacon_work); |
182 | cancel_delayed_work_sync(dwork: &rtwvif->roc.roc_work); |
183 | |
184 | mutex_lock(&rtwdev->mutex); |
185 | rtw89_leave_ps_mode(rtwdev); |
186 | rtw89_btc_ntfy_role_info(rtwdev, rtwvif, NULL, state: BTC_ROLE_STOP); |
187 | rtw89_mac_remove_vif(rtwdev, vif: rtwvif); |
188 | rtw89_core_release_bit_map(addr: rtwdev->hw_port, bit: rtwvif->port); |
189 | list_del_init(entry: &rtwvif->list); |
190 | rtw89_recalc_lps(rtwdev); |
191 | rtw89_enter_ips_by_hwflags(rtwdev); |
192 | |
193 | mutex_unlock(lock: &rtwdev->mutex); |
194 | } |
195 | |
196 | static int rtw89_ops_change_interface(struct ieee80211_hw *hw, |
197 | struct ieee80211_vif *vif, |
198 | enum nl80211_iftype type, bool p2p) |
199 | { |
200 | struct rtw89_dev *rtwdev = hw->priv; |
201 | int ret; |
202 | |
203 | set_bit(nr: RTW89_FLAG_CHANGING_INTERFACE, addr: rtwdev->flags); |
204 | |
205 | rtw89_debug(rtwdev, mask: RTW89_DBG_STATE, fmt: "change vif %pM (%d)->(%d), p2p (%d)->(%d)\n" , |
206 | vif->addr, vif->type, type, vif->p2p, p2p); |
207 | |
208 | rtw89_ops_remove_interface(hw, vif); |
209 | |
210 | vif->type = type; |
211 | vif->p2p = p2p; |
212 | |
213 | ret = rtw89_ops_add_interface(hw, vif); |
214 | if (ret) |
215 | rtw89_warn(rtwdev, "failed to change interface %d\n" , ret); |
216 | |
217 | clear_bit(nr: RTW89_FLAG_CHANGING_INTERFACE, addr: rtwdev->flags); |
218 | |
219 | return ret; |
220 | } |
221 | |
222 | static void rtw89_ops_configure_filter(struct ieee80211_hw *hw, |
223 | unsigned int changed_flags, |
224 | unsigned int *new_flags, |
225 | u64 multicast) |
226 | { |
227 | struct rtw89_dev *rtwdev = hw->priv; |
228 | const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; |
229 | u32 rx_fltr; |
230 | |
231 | mutex_lock(&rtwdev->mutex); |
232 | rtw89_leave_ps_mode(rtwdev); |
233 | |
234 | *new_flags &= FIF_ALLMULTI | FIF_OTHER_BSS | FIF_FCSFAIL | |
235 | FIF_BCN_PRBRESP_PROMISC | FIF_PROBE_REQ; |
236 | |
237 | if (changed_flags & FIF_ALLMULTI) { |
238 | if (*new_flags & FIF_ALLMULTI) |
239 | rtwdev->hal.rx_fltr &= ~B_AX_A_MC; |
240 | else |
241 | rtwdev->hal.rx_fltr |= B_AX_A_MC; |
242 | } |
243 | if (changed_flags & FIF_FCSFAIL) { |
244 | if (*new_flags & FIF_FCSFAIL) |
245 | rtwdev->hal.rx_fltr |= B_AX_A_CRC32_ERR; |
246 | else |
247 | rtwdev->hal.rx_fltr &= ~B_AX_A_CRC32_ERR; |
248 | } |
249 | if (changed_flags & FIF_OTHER_BSS) { |
250 | if (*new_flags & FIF_OTHER_BSS) |
251 | rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH; |
252 | else |
253 | rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; |
254 | } |
255 | if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { |
256 | if (*new_flags & FIF_BCN_PRBRESP_PROMISC) { |
257 | rtwdev->hal.rx_fltr &= ~B_AX_A_BCN_CHK_EN; |
258 | rtwdev->hal.rx_fltr &= ~B_AX_A_BC; |
259 | rtwdev->hal.rx_fltr &= ~B_AX_A_A1_MATCH; |
260 | } else { |
261 | rtwdev->hal.rx_fltr |= B_AX_A_BCN_CHK_EN; |
262 | rtwdev->hal.rx_fltr |= B_AX_A_BC; |
263 | rtwdev->hal.rx_fltr |= B_AX_A_A1_MATCH; |
264 | } |
265 | } |
266 | if (changed_flags & FIF_PROBE_REQ) { |
267 | if (*new_flags & FIF_PROBE_REQ) { |
268 | rtwdev->hal.rx_fltr &= ~B_AX_A_BC_CAM_MATCH; |
269 | rtwdev->hal.rx_fltr &= ~B_AX_A_UC_CAM_MATCH; |
270 | } else { |
271 | rtwdev->hal.rx_fltr |= B_AX_A_BC_CAM_MATCH; |
272 | rtwdev->hal.rx_fltr |= B_AX_A_UC_CAM_MATCH; |
273 | } |
274 | } |
275 | |
276 | rx_fltr = rtwdev->hal.rx_fltr; |
277 | |
278 | /* mac80211 doesn't configure filter when HW scan, driver need to |
279 | * set by itself. However, during P2P scan might have configure |
280 | * filter to overwrite filter that HW scan needed, so we need to |
281 | * check scan and append related filter |
282 | */ |
283 | if (rtwdev->scanning) { |
284 | rx_fltr &= ~B_AX_A_BCN_CHK_EN; |
285 | rx_fltr &= ~B_AX_A_BC; |
286 | rx_fltr &= ~B_AX_A_A1_MATCH; |
287 | } |
288 | |
289 | rtw89_write32_mask(rtwdev, |
290 | addr: rtw89_mac_reg_by_idx(rtwdev, reg_base: mac->rx_fltr, band: RTW89_MAC_0), |
291 | B_AX_RX_FLTR_CFG_MASK, |
292 | data: rx_fltr); |
293 | if (!rtwdev->dbcc_en) |
294 | goto out; |
295 | rtw89_write32_mask(rtwdev, |
296 | addr: rtw89_mac_reg_by_idx(rtwdev, reg_base: mac->rx_fltr, band: RTW89_MAC_1), |
297 | B_AX_RX_FLTR_CFG_MASK, |
298 | data: rx_fltr); |
299 | |
300 | out: |
301 | mutex_unlock(lock: &rtwdev->mutex); |
302 | } |
303 | |
304 | static const u8 ac_to_fw_idx[IEEE80211_NUM_ACS] = { |
305 | [IEEE80211_AC_VO] = 3, |
306 | [IEEE80211_AC_VI] = 2, |
307 | [IEEE80211_AC_BE] = 0, |
308 | [IEEE80211_AC_BK] = 1, |
309 | }; |
310 | |
311 | static u8 rtw89_aifsn_to_aifs(struct rtw89_dev *rtwdev, |
312 | struct rtw89_vif *rtwvif, u8 aifsn) |
313 | { |
314 | struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); |
315 | const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, |
316 | idx: rtwvif->sub_entity_idx); |
317 | u8 slot_time; |
318 | u8 sifs; |
319 | |
320 | slot_time = vif->bss_conf.use_short_slot ? 9 : 20; |
321 | sifs = chan->band_type == RTW89_BAND_5G ? 16 : 10; |
322 | |
323 | return aifsn * slot_time + sifs; |
324 | } |
325 | |
326 | static void ____rtw89_conf_tx_edca(struct rtw89_dev *rtwdev, |
327 | struct rtw89_vif *rtwvif, u16 ac) |
328 | { |
329 | struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; |
330 | u32 val; |
331 | u8 ecw_max, ecw_min; |
332 | u8 aifs; |
333 | |
334 | /* 2^ecw - 1 = cw; ecw = log2(cw + 1) */ |
335 | ecw_max = ilog2(params->cw_max + 1); |
336 | ecw_min = ilog2(params->cw_min + 1); |
337 | aifs = rtw89_aifsn_to_aifs(rtwdev, rtwvif, aifsn: params->aifs); |
338 | val = FIELD_PREP(FW_EDCA_PARAM_TXOPLMT_MSK, params->txop) | |
339 | FIELD_PREP(FW_EDCA_PARAM_CWMAX_MSK, ecw_max) | |
340 | FIELD_PREP(FW_EDCA_PARAM_CWMIN_MSK, ecw_min) | |
341 | FIELD_PREP(FW_EDCA_PARAM_AIFS_MSK, aifs); |
342 | rtw89_fw_h2c_set_edca(rtwdev, rtwvif, ac: ac_to_fw_idx[ac], val); |
343 | } |
344 | |
345 | #define R_MUEDCA_ACS_PARAM(acs) {R_AX_MUEDCA_ ## acs ## _PARAM_0, \ |
346 | R_BE_MUEDCA_ ## acs ## _PARAM_0} |
347 | |
348 | static const u32 ac_to_mu_edca_param[IEEE80211_NUM_ACS][RTW89_CHIP_GEN_NUM] = { |
349 | [IEEE80211_AC_VO] = R_MUEDCA_ACS_PARAM(VO), |
350 | [IEEE80211_AC_VI] = R_MUEDCA_ACS_PARAM(VI), |
351 | [IEEE80211_AC_BE] = R_MUEDCA_ACS_PARAM(BE), |
352 | [IEEE80211_AC_BK] = R_MUEDCA_ACS_PARAM(BK), |
353 | }; |
354 | |
355 | static void ____rtw89_conf_tx_mu_edca(struct rtw89_dev *rtwdev, |
356 | struct rtw89_vif *rtwvif, u16 ac) |
357 | { |
358 | struct ieee80211_tx_queue_params *params = &rtwvif->tx_params[ac]; |
359 | struct ieee80211_he_mu_edca_param_ac_rec *mu_edca; |
360 | int gen = rtwdev->chip->chip_gen; |
361 | u8 aifs, aifsn; |
362 | u16 timer_32us; |
363 | u32 reg; |
364 | u32 val; |
365 | |
366 | if (!params->mu_edca) |
367 | return; |
368 | |
369 | mu_edca = ¶ms->mu_edca_param_rec; |
370 | aifsn = FIELD_GET(GENMASK(3, 0), mu_edca->aifsn); |
371 | aifs = aifsn ? rtw89_aifsn_to_aifs(rtwdev, rtwvif, aifsn) : 0; |
372 | timer_32us = mu_edca->mu_edca_timer << 8; |
373 | |
374 | val = FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_TIMER_MASK, timer_32us) | |
375 | FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_CW_MASK, mu_edca->ecw_min_max) | |
376 | FIELD_PREP(B_AX_MUEDCA_BE_PARAM_0_AIFS_MASK, aifs); |
377 | reg = rtw89_mac_reg_by_idx(rtwdev, reg_base: ac_to_mu_edca_param[ac][gen], band: rtwvif->mac_idx); |
378 | rtw89_write32(rtwdev, addr: reg, data: val); |
379 | |
380 | rtw89_mac_set_hw_muedca_ctrl(rtwdev, rtwvif, en: true); |
381 | } |
382 | |
383 | static void __rtw89_conf_tx(struct rtw89_dev *rtwdev, |
384 | struct rtw89_vif *rtwvif, u16 ac) |
385 | { |
386 | ____rtw89_conf_tx_edca(rtwdev, rtwvif, ac); |
387 | ____rtw89_conf_tx_mu_edca(rtwdev, rtwvif, ac); |
388 | } |
389 | |
390 | static void rtw89_conf_tx(struct rtw89_dev *rtwdev, |
391 | struct rtw89_vif *rtwvif) |
392 | { |
393 | u16 ac; |
394 | |
395 | for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) |
396 | __rtw89_conf_tx(rtwdev, rtwvif, ac); |
397 | } |
398 | |
399 | static void rtw89_station_mode_sta_assoc(struct rtw89_dev *rtwdev, |
400 | struct ieee80211_vif *vif, |
401 | struct ieee80211_bss_conf *conf) |
402 | { |
403 | struct ieee80211_sta *sta; |
404 | |
405 | if (vif->type != NL80211_IFTYPE_STATION) |
406 | return; |
407 | |
408 | sta = ieee80211_find_sta(vif, addr: conf->bssid); |
409 | if (!sta) { |
410 | rtw89_err(rtwdev, "can't find sta to set sta_assoc state\n" ); |
411 | return; |
412 | } |
413 | |
414 | rtw89_vif_type_mapping(vif, assoc: true); |
415 | |
416 | rtw89_core_sta_assoc(rtwdev, vif, sta); |
417 | } |
418 | |
419 | static void rtw89_ops_bss_info_changed(struct ieee80211_hw *hw, |
420 | struct ieee80211_vif *vif, |
421 | struct ieee80211_bss_conf *conf, |
422 | u64 changed) |
423 | { |
424 | struct rtw89_dev *rtwdev = hw->priv; |
425 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
426 | |
427 | mutex_lock(&rtwdev->mutex); |
428 | rtw89_leave_ps_mode(rtwdev); |
429 | |
430 | if (changed & BSS_CHANGED_ASSOC) { |
431 | if (vif->cfg.assoc) { |
432 | rtw89_station_mode_sta_assoc(rtwdev, vif, conf); |
433 | rtw89_phy_set_bss_color(rtwdev, vif); |
434 | rtw89_chip_cfg_txpwr_ul_tb_offset(rtwdev, vif); |
435 | rtw89_mac_port_update(rtwdev, rtwvif); |
436 | rtw89_mac_set_he_obss_narrow_bw_ru(rtwdev, vif); |
437 | |
438 | rtw89_queue_chanctx_work(rtwdev); |
439 | } else { |
440 | /* Abort ongoing scan if cancel_scan isn't issued |
441 | * when disconnected by peer |
442 | */ |
443 | if (rtwdev->scanning) |
444 | rtw89_hw_scan_abort(rtwdev, vif: rtwdev->scan_info.scanning_vif); |
445 | } |
446 | } |
447 | |
448 | if (changed & BSS_CHANGED_BSSID) { |
449 | ether_addr_copy(dst: rtwvif->bssid, src: conf->bssid); |
450 | rtw89_cam_bssid_changed(rtwdev, rtwvif); |
451 | rtw89_fw_h2c_cam(rtwdev, vif: rtwvif, NULL, NULL); |
452 | WRITE_ONCE(rtwvif->sync_bcn_tsf, 0); |
453 | } |
454 | |
455 | if (changed & BSS_CHANGED_BEACON) |
456 | rtw89_chip_h2c_update_beacon(rtwdev, rtwvif); |
457 | |
458 | if (changed & BSS_CHANGED_ERP_SLOT) |
459 | rtw89_conf_tx(rtwdev, rtwvif); |
460 | |
461 | if (changed & BSS_CHANGED_HE_BSS_COLOR) |
462 | rtw89_phy_set_bss_color(rtwdev, vif); |
463 | |
464 | if (changed & BSS_CHANGED_MU_GROUPS) |
465 | rtw89_mac_bf_set_gid_table(rtwdev, vif, conf); |
466 | |
467 | if (changed & BSS_CHANGED_P2P_PS) |
468 | rtw89_core_update_p2p_ps(rtwdev, vif); |
469 | |
470 | if (changed & BSS_CHANGED_CQM) |
471 | rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, vif, connect: true); |
472 | |
473 | if (changed & BSS_CHANGED_PS) |
474 | rtw89_recalc_lps(rtwdev); |
475 | |
476 | mutex_unlock(lock: &rtwdev->mutex); |
477 | } |
478 | |
479 | static int rtw89_ops_start_ap(struct ieee80211_hw *hw, |
480 | struct ieee80211_vif *vif, |
481 | struct ieee80211_bss_conf *link_conf) |
482 | { |
483 | struct rtw89_dev *rtwdev = hw->priv; |
484 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
485 | const struct rtw89_chan *chan; |
486 | |
487 | mutex_lock(&rtwdev->mutex); |
488 | |
489 | chan = rtw89_chan_get(rtwdev, idx: rtwvif->sub_entity_idx); |
490 | if (chan->band_type == RTW89_BAND_6G) { |
491 | mutex_unlock(lock: &rtwdev->mutex); |
492 | return -EOPNOTSUPP; |
493 | } |
494 | |
495 | if (rtwdev->scanning) |
496 | rtw89_hw_scan_abort(rtwdev, vif: rtwdev->scan_info.scanning_vif); |
497 | |
498 | ether_addr_copy(dst: rtwvif->bssid, src: vif->bss_conf.bssid); |
499 | rtw89_cam_bssid_changed(rtwdev, rtwvif); |
500 | rtw89_mac_port_update(rtwdev, rtwvif); |
501 | rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); |
502 | rtw89_fw_h2c_role_maintain(rtwdev, rtwvif, NULL, upd_mode: RTW89_ROLE_TYPE_CHANGE); |
503 | rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, dis_conn: true); |
504 | rtw89_fw_h2c_cam(rtwdev, vif: rtwvif, NULL, NULL); |
505 | rtw89_chip_rfk_channel(rtwdev); |
506 | |
507 | rtw89_queue_chanctx_work(rtwdev); |
508 | mutex_unlock(lock: &rtwdev->mutex); |
509 | |
510 | return 0; |
511 | } |
512 | |
513 | static |
514 | void rtw89_ops_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
515 | struct ieee80211_bss_conf *link_conf) |
516 | { |
517 | struct rtw89_dev *rtwdev = hw->priv; |
518 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
519 | |
520 | mutex_lock(&rtwdev->mutex); |
521 | rtw89_mac_stop_ap(rtwdev, rtwvif); |
522 | rtw89_chip_h2c_assoc_cmac_tbl(rtwdev, vif, NULL); |
523 | rtw89_fw_h2c_join_info(rtwdev, rtwvif, NULL, dis_conn: true); |
524 | mutex_unlock(lock: &rtwdev->mutex); |
525 | } |
526 | |
527 | static int rtw89_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, |
528 | bool set) |
529 | { |
530 | struct rtw89_dev *rtwdev = hw->priv; |
531 | struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
532 | struct rtw89_vif *rtwvif = rtwsta->rtwvif; |
533 | |
534 | ieee80211_queue_work(hw: rtwdev->hw, work: &rtwvif->update_beacon_work); |
535 | |
536 | return 0; |
537 | } |
538 | |
539 | static int rtw89_ops_conf_tx(struct ieee80211_hw *hw, |
540 | struct ieee80211_vif *vif, |
541 | unsigned int link_id, u16 ac, |
542 | const struct ieee80211_tx_queue_params *params) |
543 | { |
544 | struct rtw89_dev *rtwdev = hw->priv; |
545 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
546 | |
547 | mutex_lock(&rtwdev->mutex); |
548 | rtw89_leave_ps_mode(rtwdev); |
549 | rtwvif->tx_params[ac] = *params; |
550 | __rtw89_conf_tx(rtwdev, rtwvif, ac); |
551 | mutex_unlock(lock: &rtwdev->mutex); |
552 | |
553 | return 0; |
554 | } |
555 | |
556 | static int __rtw89_ops_sta_state(struct ieee80211_hw *hw, |
557 | struct ieee80211_vif *vif, |
558 | struct ieee80211_sta *sta, |
559 | enum ieee80211_sta_state old_state, |
560 | enum ieee80211_sta_state new_state) |
561 | { |
562 | struct rtw89_dev *rtwdev = hw->priv; |
563 | |
564 | if (old_state == IEEE80211_STA_NOTEXIST && |
565 | new_state == IEEE80211_STA_NONE) |
566 | return rtw89_core_sta_add(rtwdev, vif, sta); |
567 | |
568 | if (old_state == IEEE80211_STA_AUTH && |
569 | new_state == IEEE80211_STA_ASSOC) { |
570 | if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) |
571 | return 0; /* defer to bss_info_changed to have vif info */ |
572 | return rtw89_core_sta_assoc(rtwdev, vif, sta); |
573 | } |
574 | |
575 | if (old_state == IEEE80211_STA_ASSOC && |
576 | new_state == IEEE80211_STA_AUTH) |
577 | return rtw89_core_sta_disassoc(rtwdev, vif, sta); |
578 | |
579 | if (old_state == IEEE80211_STA_AUTH && |
580 | new_state == IEEE80211_STA_NONE) |
581 | return rtw89_core_sta_disconnect(rtwdev, vif, sta); |
582 | |
583 | if (old_state == IEEE80211_STA_NONE && |
584 | new_state == IEEE80211_STA_NOTEXIST) |
585 | return rtw89_core_sta_remove(rtwdev, vif, sta); |
586 | |
587 | return 0; |
588 | } |
589 | |
590 | static int rtw89_ops_sta_state(struct ieee80211_hw *hw, |
591 | struct ieee80211_vif *vif, |
592 | struct ieee80211_sta *sta, |
593 | enum ieee80211_sta_state old_state, |
594 | enum ieee80211_sta_state new_state) |
595 | { |
596 | struct rtw89_dev *rtwdev = hw->priv; |
597 | int ret; |
598 | |
599 | mutex_lock(&rtwdev->mutex); |
600 | rtw89_leave_ps_mode(rtwdev); |
601 | ret = __rtw89_ops_sta_state(hw, vif, sta, old_state, new_state); |
602 | mutex_unlock(lock: &rtwdev->mutex); |
603 | |
604 | return ret; |
605 | } |
606 | |
607 | static int rtw89_ops_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
608 | struct ieee80211_vif *vif, |
609 | struct ieee80211_sta *sta, |
610 | struct ieee80211_key_conf *key) |
611 | { |
612 | struct rtw89_dev *rtwdev = hw->priv; |
613 | int ret = 0; |
614 | |
615 | mutex_lock(&rtwdev->mutex); |
616 | rtw89_leave_ps_mode(rtwdev); |
617 | |
618 | switch (cmd) { |
619 | case SET_KEY: |
620 | rtw89_btc_ntfy_specific_packet(rtwdev, pkt_type: PACKET_EAPOL_END); |
621 | ret = rtw89_cam_sec_key_add(rtwdev, vif, sta, key); |
622 | if (ret && ret != -EOPNOTSUPP) { |
623 | rtw89_err(rtwdev, "failed to add key to sec cam\n" ); |
624 | goto out; |
625 | } |
626 | break; |
627 | case DISABLE_KEY: |
628 | rtw89_hci_flush_queues(rtwdev, BIT(rtwdev->hw->queues) - 1, |
629 | drop: false); |
630 | rtw89_mac_flush_txq(rtwdev, BIT(rtwdev->hw->queues) - 1, drop: false); |
631 | ret = rtw89_cam_sec_key_del(rtwdev, vif, sta, key, inform_fw: true); |
632 | if (ret) { |
633 | rtw89_err(rtwdev, "failed to remove key from sec cam\n" ); |
634 | goto out; |
635 | } |
636 | break; |
637 | } |
638 | |
639 | out: |
640 | mutex_unlock(lock: &rtwdev->mutex); |
641 | |
642 | return ret; |
643 | } |
644 | |
645 | static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, |
646 | struct ieee80211_vif *vif, |
647 | struct ieee80211_ampdu_params *params) |
648 | { |
649 | struct rtw89_dev *rtwdev = hw->priv; |
650 | struct ieee80211_sta *sta = params->sta; |
651 | struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
652 | u16 tid = params->tid; |
653 | struct ieee80211_txq *txq = sta->txq[tid]; |
654 | struct rtw89_txq *rtwtxq = (struct rtw89_txq *)txq->drv_priv; |
655 | |
656 | switch (params->action) { |
657 | case IEEE80211_AMPDU_TX_START: |
658 | return IEEE80211_AMPDU_TX_START_IMMEDIATE; |
659 | case IEEE80211_AMPDU_TX_STOP_CONT: |
660 | case IEEE80211_AMPDU_TX_STOP_FLUSH: |
661 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
662 | mutex_lock(&rtwdev->mutex); |
663 | clear_bit(nr: RTW89_TXQ_F_AMPDU, addr: &rtwtxq->flags); |
664 | clear_bit(nr: tid, addr: rtwsta->ampdu_map); |
665 | rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); |
666 | mutex_unlock(lock: &rtwdev->mutex); |
667 | ieee80211_stop_tx_ba_cb_irqsafe(vif, ra: sta->addr, tid); |
668 | break; |
669 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
670 | mutex_lock(&rtwdev->mutex); |
671 | set_bit(nr: RTW89_TXQ_F_AMPDU, addr: &rtwtxq->flags); |
672 | rtwsta->ampdu_params[tid].agg_num = params->buf_size; |
673 | rtwsta->ampdu_params[tid].amsdu = params->amsdu; |
674 | set_bit(nr: tid, addr: rtwsta->ampdu_map); |
675 | rtw89_leave_ps_mode(rtwdev); |
676 | rtw89_chip_h2c_ampdu_cmac_tbl(rtwdev, vif, sta); |
677 | mutex_unlock(lock: &rtwdev->mutex); |
678 | break; |
679 | case IEEE80211_AMPDU_RX_START: |
680 | mutex_lock(&rtwdev->mutex); |
681 | rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, valid: true, params); |
682 | mutex_unlock(lock: &rtwdev->mutex); |
683 | break; |
684 | case IEEE80211_AMPDU_RX_STOP: |
685 | mutex_lock(&rtwdev->mutex); |
686 | rtw89_chip_h2c_ba_cam(rtwdev, rtwsta, valid: false, params); |
687 | mutex_unlock(lock: &rtwdev->mutex); |
688 | break; |
689 | default: |
690 | WARN_ON(1); |
691 | return -ENOTSUPP; |
692 | } |
693 | |
694 | return 0; |
695 | } |
696 | |
697 | static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) |
698 | { |
699 | struct rtw89_dev *rtwdev = hw->priv; |
700 | |
701 | mutex_lock(&rtwdev->mutex); |
702 | rtw89_leave_ps_mode(rtwdev); |
703 | if (test_bit(RTW89_FLAG_POWERON, rtwdev->flags)) |
704 | rtw89_mac_update_rts_threshold(rtwdev, mac_idx: RTW89_MAC_0); |
705 | mutex_unlock(lock: &rtwdev->mutex); |
706 | |
707 | return 0; |
708 | } |
709 | |
710 | static void rtw89_ops_sta_statistics(struct ieee80211_hw *hw, |
711 | struct ieee80211_vif *vif, |
712 | struct ieee80211_sta *sta, |
713 | struct station_info *sinfo) |
714 | { |
715 | struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
716 | |
717 | sinfo->txrate = rtwsta->ra_report.txrate; |
718 | sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); |
719 | } |
720 | |
721 | static |
722 | void __rtw89_drop_packets(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif) |
723 | { |
724 | struct rtw89_vif *rtwvif; |
725 | |
726 | if (vif) { |
727 | rtwvif = (struct rtw89_vif *)vif->drv_priv; |
728 | rtw89_mac_pkt_drop_vif(rtwdev, rtwvif); |
729 | } else { |
730 | rtw89_for_each_rtwvif(rtwdev, rtwvif) |
731 | rtw89_mac_pkt_drop_vif(rtwdev, rtwvif); |
732 | } |
733 | } |
734 | |
735 | static void rtw89_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
736 | u32 queues, bool drop) |
737 | { |
738 | struct rtw89_dev *rtwdev = hw->priv; |
739 | |
740 | mutex_lock(&rtwdev->mutex); |
741 | rtw89_leave_lps(rtwdev); |
742 | rtw89_hci_flush_queues(rtwdev, queues, drop); |
743 | |
744 | if (drop && !RTW89_CHK_FW_FEATURE(NO_PACKET_DROP, &rtwdev->fw)) |
745 | __rtw89_drop_packets(rtwdev, vif); |
746 | else |
747 | rtw89_mac_flush_txq(rtwdev, queues, drop); |
748 | |
749 | mutex_unlock(lock: &rtwdev->mutex); |
750 | } |
751 | |
752 | struct rtw89_iter_bitrate_mask_data { |
753 | struct rtw89_dev *rtwdev; |
754 | struct ieee80211_vif *vif; |
755 | const struct cfg80211_bitrate_mask *mask; |
756 | }; |
757 | |
758 | static void rtw89_ra_mask_info_update_iter(void *data, struct ieee80211_sta *sta) |
759 | { |
760 | struct rtw89_iter_bitrate_mask_data *br_data = data; |
761 | struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
762 | struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif: rtwsta->rtwvif); |
763 | |
764 | if (vif != br_data->vif || vif->p2p) |
765 | return; |
766 | |
767 | rtwsta->use_cfg_mask = true; |
768 | rtwsta->mask = *br_data->mask; |
769 | rtw89_phy_ra_updata_sta(rtwdev: br_data->rtwdev, sta, changed: IEEE80211_RC_SUPP_RATES_CHANGED); |
770 | } |
771 | |
772 | static void rtw89_ra_mask_info_update(struct rtw89_dev *rtwdev, |
773 | struct ieee80211_vif *vif, |
774 | const struct cfg80211_bitrate_mask *mask) |
775 | { |
776 | struct rtw89_iter_bitrate_mask_data br_data = { .rtwdev = rtwdev, |
777 | .vif = vif, |
778 | .mask = mask}; |
779 | |
780 | ieee80211_iterate_stations_atomic(hw: rtwdev->hw, iterator: rtw89_ra_mask_info_update_iter, |
781 | data: &br_data); |
782 | } |
783 | |
784 | static int rtw89_ops_set_bitrate_mask(struct ieee80211_hw *hw, |
785 | struct ieee80211_vif *vif, |
786 | const struct cfg80211_bitrate_mask *mask) |
787 | { |
788 | struct rtw89_dev *rtwdev = hw->priv; |
789 | |
790 | mutex_lock(&rtwdev->mutex); |
791 | rtw89_phy_rate_pattern_vif(rtwdev, vif, mask); |
792 | rtw89_ra_mask_info_update(rtwdev, vif, mask); |
793 | mutex_unlock(lock: &rtwdev->mutex); |
794 | |
795 | return 0; |
796 | } |
797 | |
798 | static |
799 | int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) |
800 | { |
801 | struct rtw89_dev *rtwdev = hw->priv; |
802 | struct rtw89_hal *hal = &rtwdev->hal; |
803 | |
804 | if (hal->ant_diversity) { |
805 | if (tx_ant != rx_ant || hweight32(tx_ant) != 1) |
806 | return -EINVAL; |
807 | } else if (rx_ant != hw->wiphy->available_antennas_rx && rx_ant != hal->antenna_rx) { |
808 | return -EINVAL; |
809 | } |
810 | |
811 | mutex_lock(&rtwdev->mutex); |
812 | hal->antenna_tx = tx_ant; |
813 | hal->antenna_rx = rx_ant; |
814 | hal->tx_path_diversity = false; |
815 | hal->ant_diversity_fixed = true; |
816 | mutex_unlock(lock: &rtwdev->mutex); |
817 | |
818 | return 0; |
819 | } |
820 | |
821 | static |
822 | int rtw89_ops_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) |
823 | { |
824 | struct rtw89_dev *rtwdev = hw->priv; |
825 | struct rtw89_hal *hal = &rtwdev->hal; |
826 | |
827 | *tx_ant = hal->antenna_tx; |
828 | *rx_ant = hal->antenna_rx; |
829 | |
830 | return 0; |
831 | } |
832 | |
833 | static void rtw89_ops_sw_scan_start(struct ieee80211_hw *hw, |
834 | struct ieee80211_vif *vif, |
835 | const u8 *mac_addr) |
836 | { |
837 | struct rtw89_dev *rtwdev = hw->priv; |
838 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
839 | |
840 | mutex_lock(&rtwdev->mutex); |
841 | rtw89_core_scan_start(rtwdev, rtwvif, mac_addr, hw_scan: false); |
842 | mutex_unlock(lock: &rtwdev->mutex); |
843 | } |
844 | |
845 | static void rtw89_ops_sw_scan_complete(struct ieee80211_hw *hw, |
846 | struct ieee80211_vif *vif) |
847 | { |
848 | struct rtw89_dev *rtwdev = hw->priv; |
849 | |
850 | mutex_lock(&rtwdev->mutex); |
851 | rtw89_core_scan_complete(rtwdev, vif, hw_scan: false); |
852 | mutex_unlock(lock: &rtwdev->mutex); |
853 | } |
854 | |
855 | static void rtw89_ops_reconfig_complete(struct ieee80211_hw *hw, |
856 | enum ieee80211_reconfig_type reconfig_type) |
857 | { |
858 | struct rtw89_dev *rtwdev = hw->priv; |
859 | |
860 | if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART) |
861 | rtw89_ser_recfg_done(rtwdev); |
862 | } |
863 | |
864 | static int rtw89_ops_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
865 | struct ieee80211_scan_request *req) |
866 | { |
867 | struct rtw89_dev *rtwdev = hw->priv; |
868 | struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); |
869 | int ret = 0; |
870 | |
871 | if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) |
872 | return 1; |
873 | |
874 | if (rtwdev->scanning || rtwvif->offchan) |
875 | return -EBUSY; |
876 | |
877 | mutex_lock(&rtwdev->mutex); |
878 | rtw89_hw_scan_start(rtwdev, vif, req); |
879 | ret = rtw89_hw_scan_offload(rtwdev, vif, enable: true); |
880 | if (ret) { |
881 | rtw89_hw_scan_abort(rtwdev, vif); |
882 | rtw89_err(rtwdev, "HW scan failed with status: %d\n" , ret); |
883 | } |
884 | mutex_unlock(lock: &rtwdev->mutex); |
885 | |
886 | return ret; |
887 | } |
888 | |
889 | static void rtw89_ops_cancel_hw_scan(struct ieee80211_hw *hw, |
890 | struct ieee80211_vif *vif) |
891 | { |
892 | struct rtw89_dev *rtwdev = hw->priv; |
893 | |
894 | if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) |
895 | return; |
896 | |
897 | if (!rtwdev->scanning) |
898 | return; |
899 | |
900 | mutex_lock(&rtwdev->mutex); |
901 | rtw89_hw_scan_abort(rtwdev, vif); |
902 | mutex_unlock(lock: &rtwdev->mutex); |
903 | } |
904 | |
905 | static void rtw89_ops_sta_rc_update(struct ieee80211_hw *hw, |
906 | struct ieee80211_vif *vif, |
907 | struct ieee80211_sta *sta, u32 changed) |
908 | { |
909 | struct rtw89_dev *rtwdev = hw->priv; |
910 | |
911 | rtw89_phy_ra_updata_sta(rtwdev, sta, changed); |
912 | } |
913 | |
914 | static int rtw89_ops_add_chanctx(struct ieee80211_hw *hw, |
915 | struct ieee80211_chanctx_conf *ctx) |
916 | { |
917 | struct rtw89_dev *rtwdev = hw->priv; |
918 | int ret; |
919 | |
920 | mutex_lock(&rtwdev->mutex); |
921 | ret = rtw89_chanctx_ops_add(rtwdev, ctx); |
922 | mutex_unlock(lock: &rtwdev->mutex); |
923 | |
924 | return ret; |
925 | } |
926 | |
927 | static void rtw89_ops_remove_chanctx(struct ieee80211_hw *hw, |
928 | struct ieee80211_chanctx_conf *ctx) |
929 | { |
930 | struct rtw89_dev *rtwdev = hw->priv; |
931 | |
932 | mutex_lock(&rtwdev->mutex); |
933 | rtw89_chanctx_ops_remove(rtwdev, ctx); |
934 | mutex_unlock(lock: &rtwdev->mutex); |
935 | } |
936 | |
937 | static void rtw89_ops_change_chanctx(struct ieee80211_hw *hw, |
938 | struct ieee80211_chanctx_conf *ctx, |
939 | u32 changed) |
940 | { |
941 | struct rtw89_dev *rtwdev = hw->priv; |
942 | |
943 | mutex_lock(&rtwdev->mutex); |
944 | rtw89_chanctx_ops_change(rtwdev, ctx, changed); |
945 | mutex_unlock(lock: &rtwdev->mutex); |
946 | } |
947 | |
948 | static int rtw89_ops_assign_vif_chanctx(struct ieee80211_hw *hw, |
949 | struct ieee80211_vif *vif, |
950 | struct ieee80211_bss_conf *link_conf, |
951 | struct ieee80211_chanctx_conf *ctx) |
952 | { |
953 | struct rtw89_dev *rtwdev = hw->priv; |
954 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
955 | int ret; |
956 | |
957 | mutex_lock(&rtwdev->mutex); |
958 | ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif, ctx); |
959 | mutex_unlock(lock: &rtwdev->mutex); |
960 | |
961 | return ret; |
962 | } |
963 | |
964 | static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw, |
965 | struct ieee80211_vif *vif, |
966 | struct ieee80211_bss_conf *link_conf, |
967 | struct ieee80211_chanctx_conf *ctx) |
968 | { |
969 | struct rtw89_dev *rtwdev = hw->priv; |
970 | struct rtw89_vif *rtwvif = (struct rtw89_vif *)vif->drv_priv; |
971 | |
972 | mutex_lock(&rtwdev->mutex); |
973 | rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif, ctx); |
974 | mutex_unlock(lock: &rtwdev->mutex); |
975 | } |
976 | |
977 | static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, |
978 | struct ieee80211_vif *vif, |
979 | struct ieee80211_channel *chan, |
980 | int duration, |
981 | enum ieee80211_roc_type type) |
982 | { |
983 | struct rtw89_dev *rtwdev = hw->priv; |
984 | struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); |
985 | struct rtw89_roc *roc = &rtwvif->roc; |
986 | |
987 | if (!vif) |
988 | return -EINVAL; |
989 | |
990 | mutex_lock(&rtwdev->mutex); |
991 | |
992 | if (roc->state != RTW89_ROC_IDLE) { |
993 | mutex_unlock(lock: &rtwdev->mutex); |
994 | return -EBUSY; |
995 | } |
996 | |
997 | if (rtwdev->scanning) |
998 | rtw89_hw_scan_abort(rtwdev, vif: rtwdev->scan_info.scanning_vif); |
999 | |
1000 | if (type == IEEE80211_ROC_TYPE_MGMT_TX) |
1001 | roc->state = RTW89_ROC_MGMT; |
1002 | else |
1003 | roc->state = RTW89_ROC_NORMAL; |
1004 | |
1005 | roc->duration = duration; |
1006 | roc->chan = *chan; |
1007 | roc->type = type; |
1008 | |
1009 | rtw89_roc_start(rtwdev, rtwvif); |
1010 | |
1011 | mutex_unlock(lock: &rtwdev->mutex); |
1012 | |
1013 | return 0; |
1014 | } |
1015 | |
1016 | static int rtw89_ops_cancel_remain_on_channel(struct ieee80211_hw *hw, |
1017 | struct ieee80211_vif *vif) |
1018 | { |
1019 | struct rtw89_dev *rtwdev = hw->priv; |
1020 | struct rtw89_vif *rtwvif = vif_to_rtwvif_safe(vif); |
1021 | |
1022 | if (!rtwvif) |
1023 | return -EINVAL; |
1024 | |
1025 | cancel_delayed_work_sync(dwork: &rtwvif->roc.roc_work); |
1026 | |
1027 | mutex_lock(&rtwdev->mutex); |
1028 | rtw89_roc_end(rtwdev, rtwvif); |
1029 | mutex_unlock(lock: &rtwdev->mutex); |
1030 | |
1031 | return 0; |
1032 | } |
1033 | |
1034 | static void rtw89_set_tid_config_iter(void *data, struct ieee80211_sta *sta) |
1035 | { |
1036 | struct cfg80211_tid_config *tid_config = data; |
1037 | struct rtw89_sta *rtwsta = (struct rtw89_sta *)sta->drv_priv; |
1038 | struct rtw89_dev *rtwdev = rtwsta->rtwvif->rtwdev; |
1039 | |
1040 | rtw89_core_set_tid_config(rtwdev, sta, tid_config); |
1041 | } |
1042 | |
1043 | static int rtw89_ops_set_tid_config(struct ieee80211_hw *hw, |
1044 | struct ieee80211_vif *vif, |
1045 | struct ieee80211_sta *sta, |
1046 | struct cfg80211_tid_config *tid_config) |
1047 | { |
1048 | struct rtw89_dev *rtwdev = hw->priv; |
1049 | |
1050 | mutex_lock(&rtwdev->mutex); |
1051 | if (sta) |
1052 | rtw89_core_set_tid_config(rtwdev, sta, tid_config); |
1053 | else |
1054 | ieee80211_iterate_stations_atomic(hw: rtwdev->hw, |
1055 | iterator: rtw89_set_tid_config_iter, |
1056 | data: tid_config); |
1057 | mutex_unlock(lock: &rtwdev->mutex); |
1058 | |
1059 | return 0; |
1060 | } |
1061 | |
1062 | #ifdef CONFIG_PM |
1063 | static int rtw89_ops_suspend(struct ieee80211_hw *hw, |
1064 | struct cfg80211_wowlan *wowlan) |
1065 | { |
1066 | struct rtw89_dev *rtwdev = hw->priv; |
1067 | int ret; |
1068 | |
1069 | set_bit(nr: RTW89_FLAG_FORBIDDEN_TRACK_WROK, addr: rtwdev->flags); |
1070 | cancel_delayed_work_sync(dwork: &rtwdev->track_work); |
1071 | |
1072 | mutex_lock(&rtwdev->mutex); |
1073 | ret = rtw89_wow_suspend(rtwdev, wowlan); |
1074 | mutex_unlock(lock: &rtwdev->mutex); |
1075 | |
1076 | if (ret) { |
1077 | rtw89_warn(rtwdev, "failed to suspend for wow %d\n" , ret); |
1078 | clear_bit(nr: RTW89_FLAG_FORBIDDEN_TRACK_WROK, addr: rtwdev->flags); |
1079 | return 1; |
1080 | } |
1081 | |
1082 | return 0; |
1083 | } |
1084 | |
1085 | static int rtw89_ops_resume(struct ieee80211_hw *hw) |
1086 | { |
1087 | struct rtw89_dev *rtwdev = hw->priv; |
1088 | int ret; |
1089 | |
1090 | mutex_lock(&rtwdev->mutex); |
1091 | ret = rtw89_wow_resume(rtwdev); |
1092 | if (ret) |
1093 | rtw89_warn(rtwdev, "failed to resume for wow %d\n" , ret); |
1094 | mutex_unlock(lock: &rtwdev->mutex); |
1095 | |
1096 | clear_bit(nr: RTW89_FLAG_FORBIDDEN_TRACK_WROK, addr: rtwdev->flags); |
1097 | ieee80211_queue_delayed_work(hw: rtwdev->hw, dwork: &rtwdev->track_work, |
1098 | RTW89_TRACK_WORK_PERIOD); |
1099 | |
1100 | return ret ? 1 : 0; |
1101 | } |
1102 | |
1103 | static void rtw89_ops_set_wakeup(struct ieee80211_hw *hw, bool enabled) |
1104 | { |
1105 | struct rtw89_dev *rtwdev = hw->priv; |
1106 | |
1107 | device_set_wakeup_enable(dev: rtwdev->dev, enable: enabled); |
1108 | } |
1109 | #endif |
1110 | |
1111 | const struct ieee80211_ops rtw89_ops = { |
1112 | .tx = rtw89_ops_tx, |
1113 | .wake_tx_queue = rtw89_ops_wake_tx_queue, |
1114 | .start = rtw89_ops_start, |
1115 | .stop = rtw89_ops_stop, |
1116 | .config = rtw89_ops_config, |
1117 | .add_interface = rtw89_ops_add_interface, |
1118 | .change_interface = rtw89_ops_change_interface, |
1119 | .remove_interface = rtw89_ops_remove_interface, |
1120 | .configure_filter = rtw89_ops_configure_filter, |
1121 | .bss_info_changed = rtw89_ops_bss_info_changed, |
1122 | .start_ap = rtw89_ops_start_ap, |
1123 | .stop_ap = rtw89_ops_stop_ap, |
1124 | .set_tim = rtw89_ops_set_tim, |
1125 | .conf_tx = rtw89_ops_conf_tx, |
1126 | .sta_state = rtw89_ops_sta_state, |
1127 | .set_key = rtw89_ops_set_key, |
1128 | .ampdu_action = rtw89_ops_ampdu_action, |
1129 | .set_rts_threshold = rtw89_ops_set_rts_threshold, |
1130 | .sta_statistics = rtw89_ops_sta_statistics, |
1131 | .flush = rtw89_ops_flush, |
1132 | .set_bitrate_mask = rtw89_ops_set_bitrate_mask, |
1133 | .set_antenna = rtw89_ops_set_antenna, |
1134 | .get_antenna = rtw89_ops_get_antenna, |
1135 | .sw_scan_start = rtw89_ops_sw_scan_start, |
1136 | .sw_scan_complete = rtw89_ops_sw_scan_complete, |
1137 | .reconfig_complete = rtw89_ops_reconfig_complete, |
1138 | .hw_scan = rtw89_ops_hw_scan, |
1139 | .cancel_hw_scan = rtw89_ops_cancel_hw_scan, |
1140 | .add_chanctx = rtw89_ops_add_chanctx, |
1141 | .remove_chanctx = rtw89_ops_remove_chanctx, |
1142 | .change_chanctx = rtw89_ops_change_chanctx, |
1143 | .assign_vif_chanctx = rtw89_ops_assign_vif_chanctx, |
1144 | .unassign_vif_chanctx = rtw89_ops_unassign_vif_chanctx, |
1145 | .remain_on_channel = rtw89_ops_remain_on_channel, |
1146 | .cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel, |
1147 | .set_sar_specs = rtw89_ops_set_sar_specs, |
1148 | .sta_rc_update = rtw89_ops_sta_rc_update, |
1149 | .set_tid_config = rtw89_ops_set_tid_config, |
1150 | #ifdef CONFIG_PM |
1151 | .suspend = rtw89_ops_suspend, |
1152 | .resume = rtw89_ops_resume, |
1153 | .set_wakeup = rtw89_ops_set_wakeup, |
1154 | #endif |
1155 | }; |
1156 | EXPORT_SYMBOL(rtw89_ops); |
1157 | |