Commit | Line | Data |
---|---|---|
04b8e659 RL |
1 | // SPDX-License-Identifier: ISC |
2 | /* Copyright (C) 2019 MediaTek Inc. | |
3 | * | |
4 | * Author: Roy Luo <royluo@google.com> | |
5 | * Ryder Lee <ryder.lee@mediatek.com> | |
6 | * Felix Fietkau <nbd@nbd.name> | |
7 | */ | |
8 | ||
9 | #include <linux/etherdevice.h> | |
10 | #include <linux/platform_device.h> | |
11 | #include <linux/pci.h> | |
12 | #include <linux/module.h> | |
13 | #include "mt7615.h" | |
14 | ||
15 | static int mt7615_start(struct ieee80211_hw *hw) | |
16 | { | |
17 | struct mt7615_dev *dev = hw->priv; | |
18 | ||
75601194 LB |
19 | mt7615_mac_reset_counters(dev); |
20 | ||
863c15a1 | 21 | dev->mt76.survey_time = ktime_get_boottime(); |
04b8e659 RL |
22 | set_bit(MT76_STATE_RUNNING, &dev->mt76.state); |
23 | ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, | |
24 | MT7615_WATCHDOG_TIME); | |
25 | ||
26 | return 0; | |
27 | } | |
28 | ||
29 | static void mt7615_stop(struct ieee80211_hw *hw) | |
30 | { | |
31 | struct mt7615_dev *dev = hw->priv; | |
32 | ||
33 | clear_bit(MT76_STATE_RUNNING, &dev->mt76.state); | |
34 | cancel_delayed_work_sync(&dev->mt76.mac_work); | |
35 | } | |
36 | ||
37 | static int get_omac_idx(enum nl80211_iftype type, u32 mask) | |
38 | { | |
39 | int i; | |
40 | ||
41 | switch (type) { | |
42 | case NL80211_IFTYPE_AP: | |
f4ec7fdf | 43 | case NL80211_IFTYPE_MESH_POINT: |
7f4b7920 | 44 | case NL80211_IFTYPE_ADHOC: |
04b8e659 RL |
45 | /* ap use hw bssid 0 and ext bssid */ |
46 | if (~mask & BIT(HW_BSSID_0)) | |
47 | return HW_BSSID_0; | |
48 | ||
49 | for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++) | |
50 | if (~mask & BIT(i)) | |
51 | return i; | |
52 | ||
53 | break; | |
54 | case NL80211_IFTYPE_STATION: | |
55 | /* sta use hw bssid other than 0 */ | |
56 | for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++) | |
57 | if (~mask & BIT(i)) | |
58 | return i; | |
59 | ||
60 | break; | |
61 | default: | |
62 | WARN_ON(1); | |
63 | break; | |
5d1ad7d7 | 64 | } |
04b8e659 RL |
65 | |
66 | return -1; | |
67 | } | |
68 | ||
69 | static int mt7615_add_interface(struct ieee80211_hw *hw, | |
70 | struct ieee80211_vif *vif) | |
71 | { | |
72 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
73 | struct mt7615_dev *dev = hw->priv; | |
74 | struct mt76_txq *mtxq; | |
75 | int idx, ret = 0; | |
76 | ||
77 | mutex_lock(&dev->mt76.mutex); | |
78 | ||
79 | mvif->idx = ffs(~dev->vif_mask) - 1; | |
80 | if (mvif->idx >= MT7615_MAX_INTERFACES) { | |
81 | ret = -ENOSPC; | |
82 | goto out; | |
83 | } | |
84 | ||
b1571a0e DC |
85 | idx = get_omac_idx(vif->type, dev->omac_mask); |
86 | if (idx < 0) { | |
04b8e659 RL |
87 | ret = -ENOSPC; |
88 | goto out; | |
89 | } | |
b1571a0e | 90 | mvif->omac_idx = idx; |
04b8e659 | 91 | |
49f1132c | 92 | /* TODO: DBDC support. Use band 0 for now */ |
04b8e659 | 93 | mvif->band_idx = 0; |
49f1132c | 94 | mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS; |
04b8e659 RL |
95 | |
96 | ret = mt7615_mcu_set_dev_info(dev, vif, 1); | |
97 | if (ret) | |
98 | goto out; | |
99 | ||
100 | dev->vif_mask |= BIT(mvif->idx); | |
101 | dev->omac_mask |= BIT(mvif->omac_idx); | |
fe559aed | 102 | idx = MT7615_WTBL_RESERVED - mvif->idx; |
b2c2f029 LB |
103 | |
104 | INIT_LIST_HEAD(&mvif->sta.poll_list); | |
04b8e659 RL |
105 | mvif->sta.wcid.idx = idx; |
106 | mvif->sta.wcid.hw_key_idx = -1; | |
b2c2f029 LB |
107 | mt7615_mac_wtbl_update(dev, idx, |
108 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); | |
04b8e659 RL |
109 | |
110 | rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); | |
111 | mtxq = (struct mt76_txq *)vif->txq->drv_priv; | |
112 | mtxq->wcid = &mvif->sta.wcid; | |
113 | mt76_txq_init(&dev->mt76, vif->txq); | |
114 | ||
115 | out: | |
116 | mutex_unlock(&dev->mt76.mutex); | |
117 | ||
118 | return ret; | |
119 | } | |
120 | ||
121 | static void mt7615_remove_interface(struct ieee80211_hw *hw, | |
122 | struct ieee80211_vif *vif) | |
123 | { | |
124 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
b2c2f029 | 125 | struct mt7615_sta *msta = &mvif->sta; |
04b8e659 | 126 | struct mt7615_dev *dev = hw->priv; |
b2c2f029 | 127 | int idx = msta->wcid.idx; |
04b8e659 RL |
128 | |
129 | /* TODO: disable beacon for the bss */ | |
130 | ||
131 | mt7615_mcu_set_dev_info(dev, vif, 0); | |
132 | ||
133 | rcu_assign_pointer(dev->mt76.wcid[idx], NULL); | |
134 | mt76_txq_remove(&dev->mt76, vif->txq); | |
135 | ||
136 | mutex_lock(&dev->mt76.mutex); | |
137 | dev->vif_mask &= ~BIT(mvif->idx); | |
138 | dev->omac_mask &= ~BIT(mvif->omac_idx); | |
139 | mutex_unlock(&dev->mt76.mutex); | |
b2c2f029 LB |
140 | |
141 | spin_lock_bh(&dev->sta_poll_lock); | |
142 | if (!list_empty(&msta->poll_list)) | |
143 | list_del_init(&msta->poll_list); | |
144 | spin_unlock_bh(&dev->sta_poll_lock); | |
04b8e659 RL |
145 | } |
146 | ||
07d557f6 | 147 | static int mt7615_set_channel(struct mt7615_dev *dev) |
04b8e659 RL |
148 | { |
149 | int ret; | |
150 | ||
151 | cancel_delayed_work_sync(&dev->mt76.mac_work); | |
7fe96541 LB |
152 | |
153 | mutex_lock(&dev->mt76.mutex); | |
04b8e659 RL |
154 | set_bit(MT76_RESET, &dev->mt76.state); |
155 | ||
d67a6646 LB |
156 | mt7615_dfs_check_channel(dev); |
157 | ||
04b8e659 RL |
158 | mt76_set_channel(&dev->mt76); |
159 | ||
160 | ret = mt7615_mcu_set_channel(dev); | |
161 | if (ret) | |
7fe96541 | 162 | goto out; |
04b8e659 | 163 | |
d67a6646 | 164 | ret = mt7615_dfs_init_radar_detector(dev); |
49de79ad | 165 | mt7615_mac_cca_stats_reset(dev); |
863c15a1 | 166 | dev->mt76.survey_time = ktime_get_boottime(); |
6bfa6e38 LB |
167 | |
168 | mt7615_mac_reset_counters(dev); | |
d67a6646 | 169 | |
7fe96541 | 170 | out: |
04b8e659 | 171 | clear_bit(MT76_RESET, &dev->mt76.state); |
7fe96541 | 172 | mutex_unlock(&dev->mt76.mutex); |
04b8e659 RL |
173 | |
174 | mt76_txq_schedule_all(&dev->mt76); | |
175 | ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, | |
176 | MT7615_WATCHDOG_TIME); | |
7fe96541 | 177 | return ret; |
04b8e659 RL |
178 | } |
179 | ||
180 | static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, | |
181 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, | |
182 | struct ieee80211_key_conf *key) | |
183 | { | |
184 | struct mt7615_dev *dev = hw->priv; | |
185 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
186 | struct mt7615_sta *msta = sta ? (struct mt7615_sta *)sta->drv_priv : | |
187 | &mvif->sta; | |
188 | struct mt76_wcid *wcid = &msta->wcid; | |
189 | int idx = key->keyidx; | |
190 | ||
191 | /* The hardware does not support per-STA RX GTK, fallback | |
192 | * to software mode for these. | |
193 | */ | |
194 | if ((vif->type == NL80211_IFTYPE_ADHOC || | |
195 | vif->type == NL80211_IFTYPE_MESH_POINT) && | |
196 | (key->cipher == WLAN_CIPHER_SUITE_TKIP || | |
197 | key->cipher == WLAN_CIPHER_SUITE_CCMP) && | |
198 | !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) | |
199 | return -EOPNOTSUPP; | |
200 | ||
4a926e30 LB |
201 | /* fall back to sw encryption for unsupported ciphers */ |
202 | switch (key->cipher) { | |
01cfc1b4 LB |
203 | case WLAN_CIPHER_SUITE_AES_CMAC: |
204 | key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; | |
205 | break; | |
4a926e30 LB |
206 | case WLAN_CIPHER_SUITE_WEP40: |
207 | case WLAN_CIPHER_SUITE_WEP104: | |
208 | case WLAN_CIPHER_SUITE_TKIP: | |
209 | case WLAN_CIPHER_SUITE_CCMP: | |
210 | case WLAN_CIPHER_SUITE_CCMP_256: | |
211 | case WLAN_CIPHER_SUITE_GCMP: | |
212 | case WLAN_CIPHER_SUITE_GCMP_256: | |
213 | case WLAN_CIPHER_SUITE_SMS4: | |
214 | break; | |
215 | default: | |
216 | return -EOPNOTSUPP; | |
217 | } | |
218 | ||
04b8e659 RL |
219 | if (cmd == SET_KEY) { |
220 | key->hw_key_idx = wcid->idx; | |
221 | wcid->hw_key_idx = idx; | |
27b8a900 LB |
222 | } else if (idx == wcid->hw_key_idx) { |
223 | wcid->hw_key_idx = -1; | |
04b8e659 | 224 | } |
27b8a900 LB |
225 | mt76_wcid_key_setup(&dev->mt76, wcid, |
226 | cmd == SET_KEY ? key : NULL); | |
04b8e659 | 227 | |
27b8a900 | 228 | return mt7615_mac_wtbl_set_key(dev, wcid, key, cmd); |
04b8e659 RL |
229 | } |
230 | ||
231 | static int mt7615_config(struct ieee80211_hw *hw, u32 changed) | |
232 | { | |
233 | struct mt7615_dev *dev = hw->priv; | |
234 | int ret = 0; | |
235 | ||
892fe32b | 236 | if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { |
04b8e659 | 237 | ieee80211_stop_queues(hw); |
07d557f6 | 238 | ret = mt7615_set_channel(dev); |
04b8e659 | 239 | ieee80211_wake_queues(hw); |
04b8e659 RL |
240 | } |
241 | ||
7fe96541 LB |
242 | mutex_lock(&dev->mt76.mutex); |
243 | ||
61d36824 LB |
244 | if (changed & IEEE80211_CONF_CHANGE_POWER) |
245 | ret = mt7615_mcu_set_tx_power(dev); | |
246 | ||
04b8e659 | 247 | if (changed & IEEE80211_CONF_CHANGE_MONITOR) { |
04b8e659 RL |
248 | if (!(hw->conf.flags & IEEE80211_CONF_MONITOR)) |
249 | dev->mt76.rxfilter |= MT_WF_RFCR_DROP_OTHER_UC; | |
250 | else | |
251 | dev->mt76.rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC; | |
252 | ||
253 | mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter); | |
04b8e659 | 254 | } |
892fe32b LB |
255 | |
256 | mutex_unlock(&dev->mt76.mutex); | |
257 | ||
04b8e659 RL |
258 | return ret; |
259 | } | |
260 | ||
261 | static int | |
262 | mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, | |
263 | const struct ieee80211_tx_queue_params *params) | |
264 | { | |
49f1132c | 265 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; |
04b8e659 | 266 | struct mt7615_dev *dev = hw->priv; |
04b8e659 | 267 | |
49f1132c RL |
268 | queue += mvif->wmm_idx * MT7615_MAX_WMM_SETS; |
269 | ||
270 | return mt7615_mcu_set_wmm(dev, queue, params); | |
04b8e659 RL |
271 | } |
272 | ||
273 | static void mt7615_configure_filter(struct ieee80211_hw *hw, | |
274 | unsigned int changed_flags, | |
275 | unsigned int *total_flags, | |
276 | u64 multicast) | |
277 | { | |
278 | struct mt7615_dev *dev = hw->priv; | |
b4124a5b FF |
279 | u32 ctl_flags = MT_WF_RFCR1_DROP_ACK | |
280 | MT_WF_RFCR1_DROP_BF_POLL | | |
281 | MT_WF_RFCR1_DROP_BA | | |
282 | MT_WF_RFCR1_DROP_CFEND | | |
283 | MT_WF_RFCR1_DROP_CFACK; | |
04b8e659 RL |
284 | u32 flags = 0; |
285 | ||
286 | #define MT76_FILTER(_flag, _hw) do { \ | |
287 | flags |= *total_flags & FIF_##_flag; \ | |
288 | dev->mt76.rxfilter &= ~(_hw); \ | |
289 | dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \ | |
290 | } while (0) | |
291 | ||
292 | dev->mt76.rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS | | |
293 | MT_WF_RFCR_DROP_OTHER_BEACON | | |
294 | MT_WF_RFCR_DROP_FRAME_REPORT | | |
295 | MT_WF_RFCR_DROP_PROBEREQ | | |
296 | MT_WF_RFCR_DROP_MCAST_FILTERED | | |
297 | MT_WF_RFCR_DROP_MCAST | | |
298 | MT_WF_RFCR_DROP_BCAST | | |
299 | MT_WF_RFCR_DROP_DUPLICATE | | |
300 | MT_WF_RFCR_DROP_A2_BSSID | | |
301 | MT_WF_RFCR_DROP_UNWANTED_CTL | | |
302 | MT_WF_RFCR_DROP_STBC_MULTI); | |
303 | ||
304 | MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM | | |
305 | MT_WF_RFCR_DROP_A3_MAC | | |
306 | MT_WF_RFCR_DROP_A3_BSSID); | |
307 | ||
308 | MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL); | |
309 | ||
310 | MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS | | |
311 | MT_WF_RFCR_DROP_RTS | | |
312 | MT_WF_RFCR_DROP_CTL_RSV | | |
313 | MT_WF_RFCR_DROP_NDPA); | |
314 | ||
315 | *total_flags = flags; | |
316 | mt76_wr(dev, MT_WF_RFCR, dev->mt76.rxfilter); | |
b4124a5b FF |
317 | |
318 | if (*total_flags & FIF_CONTROL) | |
319 | mt76_clear(dev, MT_WF_RFCR1, ctl_flags); | |
320 | else | |
321 | mt76_set(dev, MT_WF_RFCR1, ctl_flags); | |
04b8e659 RL |
322 | } |
323 | ||
324 | static void mt7615_bss_info_changed(struct ieee80211_hw *hw, | |
325 | struct ieee80211_vif *vif, | |
326 | struct ieee80211_bss_conf *info, | |
327 | u32 changed) | |
328 | { | |
329 | struct mt7615_dev *dev = hw->priv; | |
330 | ||
331 | mutex_lock(&dev->mt76.mutex); | |
332 | ||
e991c4c2 RL |
333 | if (changed & BSS_CHANGED_ASSOC) |
334 | mt7615_mcu_set_bss_info(dev, vif, info->assoc); | |
04b8e659 RL |
335 | |
336 | /* TODO: update beacon content | |
337 | * BSS_CHANGED_BEACON | |
338 | */ | |
339 | ||
340 | if (changed & BSS_CHANGED_BEACON_ENABLED) { | |
598a4434 LB |
341 | mt7615_mcu_set_bss_info(dev, vif, info->enable_beacon); |
342 | mt7615_mcu_wtbl_bmc(dev, vif, info->enable_beacon); | |
343 | mt7615_mcu_set_sta_rec_bmc(dev, vif, info->enable_beacon); | |
344 | mt7615_mcu_set_bcn(dev, vif, info->enable_beacon); | |
04b8e659 RL |
345 | } |
346 | ||
347 | mutex_unlock(&dev->mt76.mutex); | |
348 | } | |
349 | ||
5ec87dc8 LB |
350 | static void |
351 | mt7615_channel_switch_beacon(struct ieee80211_hw *hw, | |
352 | struct ieee80211_vif *vif, | |
353 | struct cfg80211_chan_def *chandef) | |
354 | { | |
355 | struct mt7615_dev *dev = hw->priv; | |
356 | ||
357 | mutex_lock(&dev->mt76.mutex); | |
358 | mt7615_mcu_set_bcn(dev, vif, true); | |
359 | mutex_unlock(&dev->mt76.mutex); | |
360 | } | |
361 | ||
04b8e659 RL |
362 | int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, |
363 | struct ieee80211_sta *sta) | |
364 | { | |
365 | struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); | |
366 | struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; | |
367 | struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; | |
368 | int idx; | |
369 | ||
370 | idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7615_WTBL_STA - 1); | |
371 | if (idx < 0) | |
372 | return -ENOSPC; | |
373 | ||
b2c2f029 | 374 | INIT_LIST_HEAD(&msta->poll_list); |
04b8e659 RL |
375 | msta->vif = mvif; |
376 | msta->wcid.sta = 1; | |
377 | msta->wcid.idx = idx; | |
b2c2f029 LB |
378 | mt7615_mac_wtbl_update(dev, idx, |
379 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); | |
04b8e659 RL |
380 | |
381 | mt7615_mcu_add_wtbl(dev, vif, sta); | |
382 | mt7615_mcu_set_sta_rec(dev, vif, sta, 1); | |
383 | ||
384 | return 0; | |
385 | } | |
386 | ||
387 | void mt7615_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif, | |
388 | struct ieee80211_sta *sta) | |
389 | { | |
390 | struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); | |
391 | ||
392 | if (sta->ht_cap.ht_supported) | |
393 | mt7615_mcu_set_ht_cap(dev, vif, sta); | |
394 | } | |
395 | ||
396 | void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, | |
397 | struct ieee80211_sta *sta) | |
398 | { | |
399 | struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76); | |
b2c2f029 | 400 | struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; |
04b8e659 RL |
401 | |
402 | mt7615_mcu_set_sta_rec(dev, vif, sta, 0); | |
b1722925 | 403 | mt7615_mcu_del_wtbl(dev, sta); |
b2c2f029 LB |
404 | |
405 | mt7615_mac_wtbl_update(dev, msta->wcid.idx, | |
406 | MT_WTBL_UPDATE_ADM_COUNT_CLEAR); | |
407 | ||
408 | spin_lock_bh(&dev->sta_poll_lock); | |
409 | if (!list_empty(&msta->poll_list)) | |
410 | list_del_init(&msta->poll_list); | |
411 | spin_unlock_bh(&dev->sta_poll_lock); | |
04b8e659 RL |
412 | } |
413 | ||
414 | static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw, | |
415 | struct ieee80211_vif *vif, | |
416 | struct ieee80211_sta *sta) | |
417 | { | |
418 | struct mt7615_dev *dev = hw->priv; | |
419 | struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; | |
420 | struct ieee80211_sta_rates *sta_rates = rcu_dereference(sta->rates); | |
421 | int i; | |
422 | ||
423 | spin_lock_bh(&dev->mt76.lock); | |
424 | for (i = 0; i < ARRAY_SIZE(msta->rates); i++) { | |
425 | msta->rates[i].idx = sta_rates->rate[i].idx; | |
426 | msta->rates[i].count = sta_rates->rate[i].count; | |
427 | msta->rates[i].flags = sta_rates->rate[i].flags; | |
428 | ||
429 | if (msta->rates[i].idx < 0 || !msta->rates[i].count) | |
430 | break; | |
431 | } | |
432 | msta->n_rates = i; | |
592ed85d | 433 | mt7615_mac_set_rates(dev, msta, NULL, msta->rates); |
04b8e659 RL |
434 | msta->rate_probe = false; |
435 | spin_unlock_bh(&dev->mt76.lock); | |
436 | } | |
437 | ||
438 | static void mt7615_tx(struct ieee80211_hw *hw, | |
439 | struct ieee80211_tx_control *control, | |
440 | struct sk_buff *skb) | |
441 | { | |
442 | struct mt7615_dev *dev = hw->priv; | |
443 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | |
444 | struct ieee80211_vif *vif = info->control.vif; | |
445 | struct mt76_wcid *wcid = &dev->mt76.global_wcid; | |
446 | ||
447 | if (control->sta) { | |
448 | struct mt7615_sta *sta; | |
449 | ||
450 | sta = (struct mt7615_sta *)control->sta->drv_priv; | |
451 | wcid = &sta->wcid; | |
452 | } | |
453 | ||
454 | if (vif && !control->sta) { | |
455 | struct mt7615_vif *mvif; | |
456 | ||
457 | mvif = (struct mt7615_vif *)vif->drv_priv; | |
458 | wcid = &mvif->sta.wcid; | |
459 | } | |
460 | ||
461 | mt76_tx(&dev->mt76, control->sta, wcid, skb); | |
462 | } | |
463 | ||
464 | static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) | |
465 | { | |
466 | struct mt7615_dev *dev = hw->priv; | |
467 | ||
468 | mutex_lock(&dev->mt76.mutex); | |
469 | mt7615_mcu_set_rts_thresh(dev, val); | |
470 | mutex_unlock(&dev->mt76.mutex); | |
471 | ||
472 | return 0; | |
473 | } | |
474 | ||
475 | static int | |
476 | mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, | |
477 | struct ieee80211_ampdu_params *params) | |
478 | { | |
479 | enum ieee80211_ampdu_mlme_action action = params->action; | |
480 | struct mt7615_dev *dev = hw->priv; | |
481 | struct ieee80211_sta *sta = params->sta; | |
482 | struct ieee80211_txq *txq = sta->txq[params->tid]; | |
483 | struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv; | |
484 | u16 tid = params->tid; | |
3d1e5cdd | 485 | u16 ssn = params->ssn; |
04b8e659 | 486 | struct mt76_txq *mtxq; |
05d6c8cf | 487 | int ret = 0; |
04b8e659 RL |
488 | |
489 | if (!txq) | |
490 | return -EINVAL; | |
491 | ||
492 | mtxq = (struct mt76_txq *)txq->drv_priv; | |
493 | ||
1a817fa7 | 494 | mutex_lock(&dev->mt76.mutex); |
04b8e659 RL |
495 | switch (action) { |
496 | case IEEE80211_AMPDU_RX_START: | |
3d1e5cdd | 497 | mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn, |
04b8e659 RL |
498 | params->buf_size); |
499 | mt7615_mcu_set_rx_ba(dev, params, 1); | |
500 | break; | |
501 | case IEEE80211_AMPDU_RX_STOP: | |
502 | mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid); | |
503 | mt7615_mcu_set_rx_ba(dev, params, 0); | |
504 | break; | |
505 | case IEEE80211_AMPDU_TX_OPERATIONAL: | |
506 | mtxq->aggr = true; | |
507 | mtxq->send_bar = false; | |
508 | mt7615_mcu_set_tx_ba(dev, params, 1); | |
509 | break; | |
510 | case IEEE80211_AMPDU_TX_STOP_FLUSH: | |
511 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: | |
512 | mtxq->aggr = false; | |
04b8e659 RL |
513 | mt7615_mcu_set_tx_ba(dev, params, 0); |
514 | break; | |
515 | case IEEE80211_AMPDU_TX_START: | |
3d1e5cdd | 516 | mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); |
05d6c8cf MT |
517 | ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; |
518 | break; | |
04b8e659 RL |
519 | case IEEE80211_AMPDU_TX_STOP_CONT: |
520 | mtxq->aggr = false; | |
521 | mt7615_mcu_set_tx_ba(dev, params, 0); | |
522 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | |
523 | break; | |
524 | } | |
1a817fa7 | 525 | mutex_unlock(&dev->mt76.mutex); |
04b8e659 | 526 | |
05d6c8cf | 527 | return ret; |
04b8e659 RL |
528 | } |
529 | ||
04b8e659 RL |
530 | const struct ieee80211_ops mt7615_ops = { |
531 | .tx = mt7615_tx, | |
532 | .start = mt7615_start, | |
533 | .stop = mt7615_stop, | |
534 | .add_interface = mt7615_add_interface, | |
535 | .remove_interface = mt7615_remove_interface, | |
536 | .config = mt7615_config, | |
537 | .conf_tx = mt7615_conf_tx, | |
538 | .configure_filter = mt7615_configure_filter, | |
539 | .bss_info_changed = mt7615_bss_info_changed, | |
540 | .sta_state = mt76_sta_state, | |
541 | .set_key = mt7615_set_key, | |
542 | .ampdu_action = mt7615_ampdu_action, | |
543 | .set_rts_threshold = mt7615_set_rts_threshold, | |
544 | .wake_tx_queue = mt76_wake_tx_queue, | |
545 | .sta_rate_tbl_update = mt7615_sta_rate_tbl_update, | |
8b8ab5c2 LB |
546 | .sw_scan_start = mt76_sw_scan, |
547 | .sw_scan_complete = mt76_sw_scan_complete, | |
04b8e659 | 548 | .release_buffered_frames = mt76_release_buffered_frames, |
2fccf4f0 | 549 | .get_txpower = mt76_get_txpower, |
5ec87dc8 | 550 | .channel_switch_beacon = mt7615_channel_switch_beacon, |
863c15a1 | 551 | .get_survey = mt76_get_survey, |
e49c76d4 | 552 | .get_antenna = mt76_get_antenna, |
04b8e659 | 553 | }; |