1 | // SPDX-License-Identifier: ISC |
2 | /* |
3 | * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> |
4 | * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> |
5 | */ |
6 | |
7 | #include <linux/module.h> |
8 | #include "mt76x02.h" |
9 | |
10 | #define MT76x02_CCK_RATE(_idx, _rate) { \ |
11 | .bitrate = _rate, \ |
12 | .flags = IEEE80211_RATE_SHORT_PREAMBLE, \ |
13 | .hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \ |
14 | .hw_value_short = (MT_PHY_TYPE_CCK << 8) | (8 + (_idx)), \ |
15 | } |
16 | |
17 | struct ieee80211_rate mt76x02_rates[] = { |
18 | MT76x02_CCK_RATE(0, 10), |
19 | MT76x02_CCK_RATE(1, 20), |
20 | MT76x02_CCK_RATE(2, 55), |
21 | MT76x02_CCK_RATE(3, 110), |
22 | OFDM_RATE(0, 60), |
23 | OFDM_RATE(1, 90), |
24 | OFDM_RATE(2, 120), |
25 | OFDM_RATE(3, 180), |
26 | OFDM_RATE(4, 240), |
27 | OFDM_RATE(5, 360), |
28 | OFDM_RATE(6, 480), |
29 | OFDM_RATE(7, 540), |
30 | }; |
31 | EXPORT_SYMBOL_GPL(mt76x02_rates); |
32 | |
33 | static const struct ieee80211_iface_limit mt76x02_if_limits[] = { |
34 | { |
35 | .max = 1, |
36 | .types = BIT(NL80211_IFTYPE_ADHOC) |
37 | }, { |
38 | .max = 8, |
39 | .types = BIT(NL80211_IFTYPE_STATION) | |
40 | #ifdef CONFIG_MAC80211_MESH |
41 | BIT(NL80211_IFTYPE_MESH_POINT) | |
42 | #endif |
43 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
44 | BIT(NL80211_IFTYPE_P2P_GO) | |
45 | BIT(NL80211_IFTYPE_AP) |
46 | }, |
47 | }; |
48 | |
49 | static const struct ieee80211_iface_limit mt76x02u_if_limits[] = { |
50 | { |
51 | .max = 1, |
52 | .types = BIT(NL80211_IFTYPE_ADHOC) |
53 | }, { |
54 | .max = 2, |
55 | .types = BIT(NL80211_IFTYPE_STATION) | |
56 | #ifdef CONFIG_MAC80211_MESH |
57 | BIT(NL80211_IFTYPE_MESH_POINT) | |
58 | #endif |
59 | BIT(NL80211_IFTYPE_P2P_CLIENT) | |
60 | BIT(NL80211_IFTYPE_P2P_GO) | |
61 | BIT(NL80211_IFTYPE_AP) |
62 | }, |
63 | }; |
64 | |
65 | static const struct ieee80211_iface_combination mt76x02_if_comb[] = { |
66 | { |
67 | .limits = mt76x02_if_limits, |
68 | .n_limits = ARRAY_SIZE(mt76x02_if_limits), |
69 | .max_interfaces = 8, |
70 | .num_different_channels = 1, |
71 | .beacon_int_infra_match = true, |
72 | .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | |
73 | BIT(NL80211_CHAN_WIDTH_20) | |
74 | BIT(NL80211_CHAN_WIDTH_40) | |
75 | BIT(NL80211_CHAN_WIDTH_80), |
76 | } |
77 | }; |
78 | |
79 | static const struct ieee80211_iface_combination mt76x02u_if_comb[] = { |
80 | { |
81 | .limits = mt76x02u_if_limits, |
82 | .n_limits = ARRAY_SIZE(mt76x02u_if_limits), |
83 | .max_interfaces = 2, |
84 | .num_different_channels = 1, |
85 | .beacon_int_infra_match = true, |
86 | } |
87 | }; |
88 | |
89 | static void |
90 | mt76x02_led_set_config(struct mt76_phy *mphy, u8 delay_on, u8 delay_off) |
91 | { |
92 | struct mt76x02_dev *dev = container_of(mphy->dev, struct mt76x02_dev, |
93 | mt76); |
94 | u32 val; |
95 | |
96 | val = FIELD_PREP(MT_LED_STATUS_DURATION, 0xff) | |
97 | FIELD_PREP(MT_LED_STATUS_OFF, delay_off) | |
98 | FIELD_PREP(MT_LED_STATUS_ON, delay_on); |
99 | |
100 | mt76_wr(dev, MT_LED_S0(mphy->leds.pin), val); |
101 | mt76_wr(dev, MT_LED_S1(mphy->leds.pin), val); |
102 | |
103 | val = MT_LED_CTRL_REPLAY(mphy->leds.pin) | |
104 | MT_LED_CTRL_KICK(mphy->leds.pin); |
105 | if (mphy->leds.al) |
106 | val |= MT_LED_CTRL_POLARITY(mphy->leds.pin); |
107 | mt76_wr(dev, MT_LED_CTRL, val); |
108 | } |
109 | |
110 | static int |
111 | mt76x02_led_set_blink(struct led_classdev *led_cdev, |
112 | unsigned long *delay_on, |
113 | unsigned long *delay_off) |
114 | { |
115 | struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, |
116 | leds.cdev); |
117 | u8 delta_on, delta_off; |
118 | |
119 | delta_off = max_t(u8, *delay_off / 10, 1); |
120 | delta_on = max_t(u8, *delay_on / 10, 1); |
121 | |
122 | mt76x02_led_set_config(mphy, delay_on: delta_on, delay_off: delta_off); |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | static void |
128 | mt76x02_led_set_brightness(struct led_classdev *led_cdev, |
129 | enum led_brightness brightness) |
130 | { |
131 | struct mt76_phy *mphy = container_of(led_cdev, struct mt76_phy, |
132 | leds.cdev); |
133 | |
134 | if (!brightness) |
135 | mt76x02_led_set_config(mphy, delay_on: 0, delay_off: 0xff); |
136 | else |
137 | mt76x02_led_set_config(mphy, delay_on: 0xff, delay_off: 0); |
138 | } |
139 | |
140 | int mt76x02_init_device(struct mt76x02_dev *dev) |
141 | { |
142 | struct ieee80211_hw *hw = mt76_hw(dev); |
143 | struct wiphy *wiphy = hw->wiphy; |
144 | |
145 | INIT_DELAYED_WORK(&dev->mphy.mac_work, mt76x02_mac_work); |
146 | |
147 | hw->queues = 4; |
148 | hw->max_rates = 1; |
149 | hw->max_report_rates = 7; |
150 | hw->max_rate_tries = 1; |
151 | hw->extra_tx_headroom = 2; |
152 | |
153 | if (mt76_is_usb(&dev->mt76)) { |
154 | hw->extra_tx_headroom += sizeof(struct mt76x02_txwi) + |
155 | MT_DMA_HDR_LEN; |
156 | wiphy->iface_combinations = mt76x02u_if_comb; |
157 | wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02u_if_comb); |
158 | } else { |
159 | INIT_DELAYED_WORK(&dev->wdt_work, mt76x02_wdt_work); |
160 | |
161 | mt76x02_dfs_init_detector(dev); |
162 | |
163 | wiphy->reg_notifier = mt76x02_regd_notifier; |
164 | wiphy->iface_combinations = mt76x02_if_comb; |
165 | wiphy->n_iface_combinations = ARRAY_SIZE(mt76x02_if_comb); |
166 | |
167 | /* init led callbacks */ |
168 | if (IS_ENABLED(CONFIG_MT76_LEDS)) { |
169 | dev->mphy.leds.cdev.brightness_set = |
170 | mt76x02_led_set_brightness; |
171 | dev->mphy.leds.cdev.blink_set = mt76x02_led_set_blink; |
172 | } |
173 | } |
174 | |
175 | wiphy_ext_feature_set(wiphy, ftidx: NL80211_EXT_FEATURE_VHT_IBSS); |
176 | |
177 | hw->sta_data_size = sizeof(struct mt76x02_sta); |
178 | hw->vif_data_size = sizeof(struct mt76x02_vif); |
179 | |
180 | ieee80211_hw_set(hw, SUPPORTS_HT_CCK_RATES); |
181 | ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); |
182 | ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR); |
183 | |
184 | dev->mt76.global_wcid.idx = 255; |
185 | dev->mt76.global_wcid.hw_key_idx = -1; |
186 | dev->slottime = 9; |
187 | |
188 | if (is_mt76x2(dev)) { |
189 | dev->mphy.sband_2g.sband.ht_cap.cap |= |
190 | IEEE80211_HT_CAP_LDPC_CODING; |
191 | dev->mphy.sband_5g.sband.ht_cap.cap |= |
192 | IEEE80211_HT_CAP_LDPC_CODING; |
193 | dev->mphy.chainmask = 0x202; |
194 | dev->mphy.antenna_mask = 3; |
195 | } else { |
196 | dev->mphy.chainmask = 0x101; |
197 | dev->mphy.antenna_mask = 1; |
198 | } |
199 | |
200 | return 0; |
201 | } |
202 | EXPORT_SYMBOL_GPL(mt76x02_init_device); |
203 | |
204 | void mt76x02_configure_filter(struct ieee80211_hw *hw, |
205 | unsigned int changed_flags, |
206 | unsigned int *total_flags, u64 multicast) |
207 | { |
208 | struct mt76x02_dev *dev = hw->priv; |
209 | u32 flags = 0; |
210 | |
211 | #define MT76_FILTER(_flag, _hw) do { \ |
212 | flags |= *total_flags & FIF_##_flag; \ |
213 | dev->mt76.rxfilter &= ~(_hw); \ |
214 | dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \ |
215 | } while (0) |
216 | |
217 | mutex_lock(&dev->mt76.mutex); |
218 | |
219 | dev->mt76.rxfilter &= ~MT_RX_FILTR_CFG_OTHER_BSS; |
220 | |
221 | MT76_FILTER(FCSFAIL, MT_RX_FILTR_CFG_CRC_ERR); |
222 | MT76_FILTER(PLCPFAIL, MT_RX_FILTR_CFG_PHY_ERR); |
223 | MT76_FILTER(CONTROL, MT_RX_FILTR_CFG_ACK | |
224 | MT_RX_FILTR_CFG_CTS | |
225 | MT_RX_FILTR_CFG_CFEND | |
226 | MT_RX_FILTR_CFG_CFACK | |
227 | MT_RX_FILTR_CFG_BA | |
228 | MT_RX_FILTR_CFG_CTRL_RSV); |
229 | MT76_FILTER(PSPOLL, MT_RX_FILTR_CFG_PSPOLL); |
230 | |
231 | *total_flags = flags; |
232 | mt76_wr(dev, MT_RX_FILTR_CFG, dev->mt76.rxfilter); |
233 | |
234 | mutex_unlock(lock: &dev->mt76.mutex); |
235 | } |
236 | EXPORT_SYMBOL_GPL(mt76x02_configure_filter); |
237 | |
238 | int mt76x02_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, |
239 | struct ieee80211_sta *sta) |
240 | { |
241 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); |
242 | struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; |
243 | struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; |
244 | int idx = 0; |
245 | |
246 | memset(msta, 0, sizeof(*msta)); |
247 | |
248 | idx = mt76_wcid_alloc(mask: dev->mt76.wcid_mask, MT76x02_N_WCIDS); |
249 | if (idx < 0) |
250 | return -ENOSPC; |
251 | |
252 | msta->vif = mvif; |
253 | msta->wcid.sta = 1; |
254 | msta->wcid.idx = idx; |
255 | msta->wcid.hw_key_idx = -1; |
256 | mt76x02_mac_wcid_setup(dev, idx, vif_idx: mvif->idx, mac: sta->addr); |
257 | mt76x02_mac_wcid_set_drop(dev, idx, drop: false); |
258 | ewma_pktlen_init(e: &msta->pktlen); |
259 | |
260 | if (vif->type == NL80211_IFTYPE_AP) |
261 | set_bit(nr: MT_WCID_FLAG_CHECK_PS, addr: &msta->wcid.flags); |
262 | |
263 | return 0; |
264 | } |
265 | EXPORT_SYMBOL_GPL(mt76x02_sta_add); |
266 | |
267 | void mt76x02_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, |
268 | struct ieee80211_sta *sta) |
269 | { |
270 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); |
271 | struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; |
272 | int idx = wcid->idx; |
273 | |
274 | mt76x02_mac_wcid_set_drop(dev, idx, drop: true); |
275 | mt76x02_mac_wcid_setup(dev, idx, vif_idx: 0, NULL); |
276 | } |
277 | EXPORT_SYMBOL_GPL(mt76x02_sta_remove); |
278 | |
279 | static void |
280 | mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif, |
281 | unsigned int idx) |
282 | { |
283 | struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; |
284 | struct mt76_txq *mtxq; |
285 | |
286 | memset(mvif, 0, sizeof(*mvif)); |
287 | |
288 | mvif->idx = idx; |
289 | mvif->group_wcid.idx = MT_VIF_WCID(idx); |
290 | mvif->group_wcid.hw_key_idx = -1; |
291 | mt76_wcid_init(wcid: &mvif->group_wcid); |
292 | |
293 | mtxq = (struct mt76_txq *)vif->txq->drv_priv; |
294 | rcu_assign_pointer(dev->mt76.wcid[MT_VIF_WCID(idx)], &mvif->group_wcid); |
295 | mtxq->wcid = MT_VIF_WCID(idx); |
296 | } |
297 | |
298 | int |
299 | mt76x02_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
300 | { |
301 | struct mt76x02_dev *dev = hw->priv; |
302 | unsigned int idx = 0; |
303 | |
304 | /* Allow to change address in HW if we create first interface. */ |
305 | if (!dev->mt76.vif_mask && |
306 | (((vif->addr[0] ^ dev->mphy.macaddr[0]) & ~GENMASK(4, 1)) || |
307 | memcmp(p: vif->addr + 1, q: dev->mphy.macaddr + 1, ETH_ALEN - 1))) |
308 | mt76x02_mac_setaddr(dev, addr: vif->addr); |
309 | |
310 | if (vif->addr[0] & BIT(1)) |
311 | idx = 1 + (((dev->mphy.macaddr[0] ^ vif->addr[0]) >> 2) & 7); |
312 | |
313 | /* |
314 | * Client mode typically only has one configurable BSSID register, |
315 | * which is used for bssidx=0. This is linked to the MAC address. |
316 | * Since mac80211 allows changing interface types, and we cannot |
317 | * force the use of the primary MAC address for a station mode |
318 | * interface, we need some other way of configuring a per-interface |
319 | * remote BSSID. |
320 | * The hardware provides an AP-Client feature, where bssidx 0-7 are |
321 | * used for AP mode and bssidx 8-15 for client mode. |
322 | * We shift the station interface bss index by 8 to force the |
323 | * hardware to recognize the BSSID. |
324 | * The resulting bssidx mismatch for unicast frames is ignored by hw. |
325 | */ |
326 | if (vif->type == NL80211_IFTYPE_STATION) |
327 | idx += 8; |
328 | |
329 | /* vif is already set or idx is 8 for AP/Mesh/... */ |
330 | if (dev->mt76.vif_mask & BIT_ULL(idx) || |
331 | (vif->type != NL80211_IFTYPE_STATION && idx > 7)) |
332 | return -EBUSY; |
333 | |
334 | dev->mt76.vif_mask |= BIT_ULL(idx); |
335 | |
336 | mt76x02_vif_init(dev, vif, idx); |
337 | return 0; |
338 | } |
339 | EXPORT_SYMBOL_GPL(mt76x02_add_interface); |
340 | |
341 | void mt76x02_remove_interface(struct ieee80211_hw *hw, |
342 | struct ieee80211_vif *vif) |
343 | { |
344 | struct mt76x02_dev *dev = hw->priv; |
345 | struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; |
346 | |
347 | dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx); |
348 | rcu_assign_pointer(dev->mt76.wcid[mvif->group_wcid.idx], NULL); |
349 | mt76_wcid_cleanup(dev: &dev->mt76, wcid: &mvif->group_wcid); |
350 | } |
351 | EXPORT_SYMBOL_GPL(mt76x02_remove_interface); |
352 | |
353 | int mt76x02_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
354 | struct ieee80211_ampdu_params *params) |
355 | { |
356 | enum ieee80211_ampdu_mlme_action action = params->action; |
357 | struct ieee80211_sta *sta = params->sta; |
358 | struct mt76x02_dev *dev = hw->priv; |
359 | struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; |
360 | struct ieee80211_txq *txq = sta->txq[params->tid]; |
361 | u16 tid = params->tid; |
362 | u16 ssn = params->ssn; |
363 | struct mt76_txq *mtxq; |
364 | int ret = 0; |
365 | |
366 | if (!txq) |
367 | return -EINVAL; |
368 | |
369 | mtxq = (struct mt76_txq *)txq->drv_priv; |
370 | |
371 | mutex_lock(&dev->mt76.mutex); |
372 | switch (action) { |
373 | case IEEE80211_AMPDU_RX_START: |
374 | mt76_rx_aggr_start(dev: &dev->mt76, wcid: &msta->wcid, tid, |
375 | ssn, size: params->buf_size); |
376 | mt76_set(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, BIT(16 + tid)); |
377 | break; |
378 | case IEEE80211_AMPDU_RX_STOP: |
379 | mt76_rx_aggr_stop(dev: &dev->mt76, wcid: &msta->wcid, tid); |
380 | mt76_clear(dev, MT_WCID_ADDR(msta->wcid.idx) + 4, |
381 | BIT(16 + tid)); |
382 | break; |
383 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
384 | mtxq->aggr = true; |
385 | mtxq->send_bar = false; |
386 | ieee80211_send_bar(vif, ra: sta->addr, tid, ssn: mtxq->agg_ssn); |
387 | break; |
388 | case IEEE80211_AMPDU_TX_STOP_FLUSH: |
389 | case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: |
390 | mtxq->aggr = false; |
391 | break; |
392 | case IEEE80211_AMPDU_TX_START: |
393 | mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn); |
394 | ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; |
395 | break; |
396 | case IEEE80211_AMPDU_TX_STOP_CONT: |
397 | mtxq->aggr = false; |
398 | ieee80211_stop_tx_ba_cb_irqsafe(vif, ra: sta->addr, tid); |
399 | break; |
400 | } |
401 | mutex_unlock(lock: &dev->mt76.mutex); |
402 | |
403 | return ret; |
404 | } |
405 | EXPORT_SYMBOL_GPL(mt76x02_ampdu_action); |
406 | |
407 | int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, |
408 | struct ieee80211_vif *vif, struct ieee80211_sta *sta, |
409 | struct ieee80211_key_conf *key) |
410 | { |
411 | struct mt76x02_dev *dev = hw->priv; |
412 | struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; |
413 | struct mt76x02_sta *msta; |
414 | struct mt76_wcid *wcid; |
415 | int idx = key->keyidx; |
416 | int ret; |
417 | |
418 | /* fall back to sw encryption for unsupported ciphers */ |
419 | switch (key->cipher) { |
420 | case WLAN_CIPHER_SUITE_WEP40: |
421 | case WLAN_CIPHER_SUITE_WEP104: |
422 | case WLAN_CIPHER_SUITE_TKIP: |
423 | case WLAN_CIPHER_SUITE_CCMP: |
424 | break; |
425 | default: |
426 | return -EOPNOTSUPP; |
427 | } |
428 | |
429 | /* |
430 | * The hardware does not support per-STA RX GTK, fall back |
431 | * to software mode for these. |
432 | */ |
433 | if ((vif->type == NL80211_IFTYPE_ADHOC || |
434 | vif->type == NL80211_IFTYPE_MESH_POINT) && |
435 | (key->cipher == WLAN_CIPHER_SUITE_TKIP || |
436 | key->cipher == WLAN_CIPHER_SUITE_CCMP) && |
437 | !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) |
438 | return -EOPNOTSUPP; |
439 | |
440 | /* |
441 | * In USB AP mode, broadcast/multicast frames are setup in beacon |
442 | * data registers and sent via HW beacons engine, they require to |
443 | * be already encrypted. |
444 | */ |
445 | if (mt76_is_usb(&dev->mt76) && |
446 | vif->type == NL80211_IFTYPE_AP && |
447 | !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) |
448 | return -EOPNOTSUPP; |
449 | |
450 | /* MT76x0 GTK offloading does not work with more than one VIF */ |
451 | if (is_mt76x0(dev) && !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) |
452 | return -EOPNOTSUPP; |
453 | |
454 | msta = sta ? (struct mt76x02_sta *)sta->drv_priv : NULL; |
455 | wcid = msta ? &msta->wcid : &mvif->group_wcid; |
456 | |
457 | if (cmd != SET_KEY) { |
458 | if (idx == wcid->hw_key_idx) { |
459 | wcid->hw_key_idx = -1; |
460 | wcid->sw_iv = false; |
461 | } |
462 | |
463 | return 0; |
464 | } |
465 | |
466 | key->hw_key_idx = wcid->idx; |
467 | wcid->hw_key_idx = idx; |
468 | if (key->flags & IEEE80211_KEY_FLAG_RX_MGMT) { |
469 | key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX; |
470 | wcid->sw_iv = true; |
471 | } |
472 | mt76_wcid_key_setup(dev: &dev->mt76, wcid, key); |
473 | |
474 | if (!msta) { |
475 | if (key || wcid->hw_key_idx == idx) { |
476 | ret = mt76x02_mac_wcid_set_key(dev, idx: wcid->idx, key); |
477 | if (ret) |
478 | return ret; |
479 | } |
480 | |
481 | return mt76x02_mac_shared_key_setup(dev, vif_idx: mvif->idx, key_idx: idx, key); |
482 | } |
483 | |
484 | return mt76x02_mac_wcid_set_key(dev, idx: msta->wcid.idx, key); |
485 | } |
486 | EXPORT_SYMBOL_GPL(mt76x02_set_key); |
487 | |
488 | int mt76x02_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
489 | unsigned int link_id, u16 queue, |
490 | const struct ieee80211_tx_queue_params *params) |
491 | { |
492 | struct mt76x02_dev *dev = hw->priv; |
493 | u8 cw_min = 5, cw_max = 10, qid; |
494 | u32 val; |
495 | |
496 | qid = dev->mphy.q_tx[queue]->hw_idx; |
497 | |
498 | if (params->cw_min) |
499 | cw_min = fls(x: params->cw_min); |
500 | if (params->cw_max) |
501 | cw_max = fls(x: params->cw_max); |
502 | |
503 | val = FIELD_PREP(MT_EDCA_CFG_TXOP, params->txop) | |
504 | FIELD_PREP(MT_EDCA_CFG_AIFSN, params->aifs) | |
505 | FIELD_PREP(MT_EDCA_CFG_CWMIN, cw_min) | |
506 | FIELD_PREP(MT_EDCA_CFG_CWMAX, cw_max); |
507 | mt76_wr(dev, MT_EDCA_CFG_AC(qid), val); |
508 | |
509 | val = mt76_rr(dev, MT_WMM_TXOP(qid)); |
510 | val &= ~(MT_WMM_TXOP_MASK << MT_WMM_TXOP_SHIFT(qid)); |
511 | val |= params->txop << MT_WMM_TXOP_SHIFT(qid); |
512 | mt76_wr(dev, MT_WMM_TXOP(qid), val); |
513 | |
514 | val = mt76_rr(dev, MT_WMM_AIFSN); |
515 | val &= ~(MT_WMM_AIFSN_MASK << MT_WMM_AIFSN_SHIFT(qid)); |
516 | val |= params->aifs << MT_WMM_AIFSN_SHIFT(qid); |
517 | mt76_wr(dev, MT_WMM_AIFSN, val); |
518 | |
519 | val = mt76_rr(dev, MT_WMM_CWMIN); |
520 | val &= ~(MT_WMM_CWMIN_MASK << MT_WMM_CWMIN_SHIFT(qid)); |
521 | val |= cw_min << MT_WMM_CWMIN_SHIFT(qid); |
522 | mt76_wr(dev, MT_WMM_CWMIN, val); |
523 | |
524 | val = mt76_rr(dev, MT_WMM_CWMAX); |
525 | val &= ~(MT_WMM_CWMAX_MASK << MT_WMM_CWMAX_SHIFT(qid)); |
526 | val |= cw_max << MT_WMM_CWMAX_SHIFT(qid); |
527 | mt76_wr(dev, MT_WMM_CWMAX, val); |
528 | |
529 | return 0; |
530 | } |
531 | EXPORT_SYMBOL_GPL(mt76x02_conf_tx); |
532 | |
533 | void mt76x02_set_tx_ackto(struct mt76x02_dev *dev) |
534 | { |
535 | u8 ackto, sifs, slottime = dev->slottime; |
536 | |
537 | /* As defined by IEEE 802.11-2007 17.3.8.6 */ |
538 | slottime += 3 * dev->coverage_class; |
539 | mt76_rmw_field(dev, MT_BKOFF_SLOT_CFG, |
540 | MT_BKOFF_SLOT_CFG_SLOTTIME, slottime); |
541 | |
542 | sifs = mt76_get_field(dev, MT_XIFS_TIME_CFG, |
543 | MT_XIFS_TIME_CFG_OFDM_SIFS); |
544 | |
545 | ackto = slottime + sifs; |
546 | mt76_rmw_field(dev, MT_TX_TIMEOUT_CFG, |
547 | MT_TX_TIMEOUT_CFG_ACKTO, ackto); |
548 | } |
549 | EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto); |
550 | |
551 | void mt76x02_set_coverage_class(struct ieee80211_hw *hw, |
552 | s16 coverage_class) |
553 | { |
554 | struct mt76x02_dev *dev = hw->priv; |
555 | |
556 | mutex_lock(&dev->mt76.mutex); |
557 | dev->coverage_class = max_t(s16, coverage_class, 0); |
558 | mt76x02_set_tx_ackto(dev); |
559 | mutex_unlock(lock: &dev->mt76.mutex); |
560 | } |
561 | EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class); |
562 | |
563 | int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) |
564 | { |
565 | struct mt76x02_dev *dev = hw->priv; |
566 | |
567 | if (val != ~0 && val > 0xffff) |
568 | return -EINVAL; |
569 | |
570 | mutex_lock(&dev->mt76.mutex); |
571 | mt76x02_mac_set_rts_thresh(dev, val); |
572 | mutex_unlock(lock: &dev->mt76.mutex); |
573 | |
574 | return 0; |
575 | } |
576 | EXPORT_SYMBOL_GPL(mt76x02_set_rts_threshold); |
577 | |
578 | void mt76x02_sta_rate_tbl_update(struct ieee80211_hw *hw, |
579 | struct ieee80211_vif *vif, |
580 | struct ieee80211_sta *sta) |
581 | { |
582 | struct mt76x02_dev *dev = hw->priv; |
583 | struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; |
584 | struct ieee80211_sta_rates *rates = rcu_dereference(sta->rates); |
585 | struct ieee80211_tx_rate rate = {}; |
586 | |
587 | if (!rates) |
588 | return; |
589 | |
590 | rate.idx = rates->rate[0].idx; |
591 | rate.flags = rates->rate[0].flags; |
592 | mt76x02_mac_wcid_set_rate(dev, wcid: &msta->wcid, rate: &rate); |
593 | } |
594 | EXPORT_SYMBOL_GPL(mt76x02_sta_rate_tbl_update); |
595 | |
596 | void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len) |
597 | { |
598 | int hdrlen; |
599 | |
600 | if (!len) |
601 | return; |
602 | |
603 | hdrlen = ieee80211_get_hdrlen_from_skb(skb); |
604 | memmove(skb->data + len, skb->data, hdrlen); |
605 | skb_pull(skb, len); |
606 | } |
607 | EXPORT_SYMBOL_GPL(mt76x02_remove_hdr_pad); |
608 | |
609 | void mt76x02_sw_scan_complete(struct ieee80211_hw *hw, |
610 | struct ieee80211_vif *vif) |
611 | { |
612 | struct mt76x02_dev *dev = hw->priv; |
613 | |
614 | clear_bit(nr: MT76_SCANNING, addr: &dev->mphy.state); |
615 | if (dev->cal.gain_init_done) { |
616 | /* Restore AGC gain and resume calibration after scanning. */ |
617 | dev->cal.low_gain = -1; |
618 | ieee80211_queue_delayed_work(hw, dwork: &dev->cal_work, delay: 0); |
619 | } |
620 | } |
621 | EXPORT_SYMBOL_GPL(mt76x02_sw_scan_complete); |
622 | |
623 | void mt76x02_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, |
624 | bool ps) |
625 | { |
626 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); |
627 | struct mt76x02_sta *msta = (struct mt76x02_sta *)sta->drv_priv; |
628 | int idx = msta->wcid.idx; |
629 | |
630 | mt76_stop_tx_queues(phy: &dev->mphy, sta, send_bar: true); |
631 | if (mt76_is_mmio(mdev)) |
632 | mt76x02_mac_wcid_set_drop(dev, idx, drop: ps); |
633 | } |
634 | EXPORT_SYMBOL_GPL(mt76x02_sta_ps); |
635 | |
636 | void mt76x02_bss_info_changed(struct ieee80211_hw *hw, |
637 | struct ieee80211_vif *vif, |
638 | struct ieee80211_bss_conf *info, |
639 | u64 changed) |
640 | { |
641 | struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv; |
642 | struct mt76x02_dev *dev = hw->priv; |
643 | |
644 | mutex_lock(&dev->mt76.mutex); |
645 | |
646 | if (changed & BSS_CHANGED_BSSID) |
647 | mt76x02_mac_set_bssid(dev, idx: mvif->idx, addr: info->bssid); |
648 | |
649 | if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) |
650 | mt76x02_mac_set_tx_protection(dev, legacy_prot: info->use_cts_prot, |
651 | ht_mode: info->ht_operation_mode); |
652 | |
653 | if (changed & BSS_CHANGED_BEACON_INT) { |
654 | mt76_rmw_field(dev, MT_BEACON_TIME_CFG, |
655 | MT_BEACON_TIME_CFG_INTVAL, |
656 | info->beacon_int << 4); |
657 | dev->mt76.beacon_int = info->beacon_int; |
658 | } |
659 | |
660 | if (changed & BSS_CHANGED_BEACON_ENABLED) |
661 | mt76x02_mac_set_beacon_enable(dev, vif, enable: info->enable_beacon); |
662 | |
663 | if (changed & BSS_CHANGED_ERP_PREAMBLE) |
664 | mt76x02_mac_set_short_preamble(dev, enable: info->use_short_preamble); |
665 | |
666 | if (changed & BSS_CHANGED_ERP_SLOT) { |
667 | int slottime = info->use_short_slot ? 9 : 20; |
668 | |
669 | dev->slottime = slottime; |
670 | mt76x02_set_tx_ackto(dev); |
671 | } |
672 | |
673 | mutex_unlock(lock: &dev->mt76.mutex); |
674 | } |
675 | EXPORT_SYMBOL_GPL(mt76x02_bss_info_changed); |
676 | |
677 | void mt76x02_config_mac_addr_list(struct mt76x02_dev *dev) |
678 | { |
679 | struct ieee80211_hw *hw = mt76_hw(dev); |
680 | struct wiphy *wiphy = hw->wiphy; |
681 | int i; |
682 | |
683 | for (i = 0; i < ARRAY_SIZE(dev->macaddr_list); i++) { |
684 | u8 *addr = dev->macaddr_list[i].addr; |
685 | |
686 | memcpy(addr, dev->mphy.macaddr, ETH_ALEN); |
687 | |
688 | if (!i) |
689 | continue; |
690 | |
691 | addr[0] |= BIT(1); |
692 | addr[0] ^= ((i - 1) << 2); |
693 | } |
694 | wiphy->addresses = dev->macaddr_list; |
695 | wiphy->n_addresses = ARRAY_SIZE(dev->macaddr_list); |
696 | } |
697 | EXPORT_SYMBOL_GPL(mt76x02_config_mac_addr_list); |
698 | |
699 | MODULE_DESCRIPTION("MediaTek MT76x02 helpers" ); |
700 | MODULE_LICENSE("Dual BSD/GPL" ); |
701 | |