]>
Commit | Line | Data |
---|---|---|
c378f247 SG |
1 | /* |
2 | * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> | |
3 | * Copyright (C) 2018 Stanislaw Gruszka <stf_xl@wp.pl> | |
4 | * | |
5 | * Permission to use, copy, modify, and/or distribute this software for any | |
6 | * purpose with or without fee is hereby granted, provided that the above | |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
7a07adcd | 18 | #include "mt76x02.h" |
3e2342ed | 19 | #include "mt76x02_trace.h" |
c378f247 | 20 | |
5567b373 | 21 | static enum mt76x02_cipher_type |
c378f247 SG |
22 | mt76x02_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) |
23 | { | |
24 | memset(key_data, 0, 32); | |
25 | if (!key) | |
26 | return MT_CIPHER_NONE; | |
27 | ||
28 | if (key->keylen > 32) | |
29 | return MT_CIPHER_NONE; | |
30 | ||
31 | memcpy(key_data, key->key, key->keylen); | |
32 | ||
33 | switch (key->cipher) { | |
34 | case WLAN_CIPHER_SUITE_WEP40: | |
35 | return MT_CIPHER_WEP40; | |
36 | case WLAN_CIPHER_SUITE_WEP104: | |
37 | return MT_CIPHER_WEP104; | |
38 | case WLAN_CIPHER_SUITE_TKIP: | |
39 | return MT_CIPHER_TKIP; | |
40 | case WLAN_CIPHER_SUITE_CCMP: | |
41 | return MT_CIPHER_AES_CCMP; | |
42 | default: | |
43 | return MT_CIPHER_NONE; | |
44 | } | |
45 | } | |
047aed1c | 46 | |
8d66af49 LB |
47 | int mt76x02_mac_shared_key_setup(struct mt76x02_dev *dev, u8 vif_idx, |
48 | u8 key_idx, struct ieee80211_key_conf *key) | |
047aed1c SG |
49 | { |
50 | enum mt76x02_cipher_type cipher; | |
51 | u8 key_data[32]; | |
52 | u32 val; | |
53 | ||
54 | cipher = mt76x02_mac_get_key_info(key, key_data); | |
55 | if (cipher == MT_CIPHER_NONE && key) | |
56 | return -EOPNOTSUPP; | |
57 | ||
8d66af49 | 58 | val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); |
047aed1c SG |
59 | val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); |
60 | val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); | |
8d66af49 | 61 | mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); |
047aed1c | 62 | |
8d66af49 LB |
63 | mt76_wr_copy(dev, MT_SKEY(vif_idx, key_idx), key_data, |
64 | sizeof(key_data)); | |
047aed1c SG |
65 | |
66 | return 0; | |
67 | } | |
68 | EXPORT_SYMBOL_GPL(mt76x02_mac_shared_key_setup); | |
46436b5e | 69 | |
00496042 FF |
70 | void mt76x02_mac_wcid_sync_pn(struct mt76x02_dev *dev, u8 idx, |
71 | struct ieee80211_key_conf *key) | |
72 | { | |
73 | enum mt76x02_cipher_type cipher; | |
74 | u8 key_data[32]; | |
75 | u32 iv, eiv; | |
76 | u64 pn; | |
77 | ||
78 | cipher = mt76x02_mac_get_key_info(key, key_data); | |
79 | iv = mt76_rr(dev, MT_WCID_IV(idx)); | |
80 | eiv = mt76_rr(dev, MT_WCID_IV(idx) + 4); | |
81 | ||
82 | pn = (u64)eiv << 16; | |
83 | if (cipher == MT_CIPHER_TKIP) { | |
84 | pn |= (iv >> 16) & 0xff; | |
85 | pn |= (iv & 0xff) << 8; | |
86 | } else if (cipher >= MT_CIPHER_AES_CCMP) { | |
87 | pn |= iv & 0xffff; | |
88 | } else { | |
89 | return; | |
90 | } | |
91 | ||
92 | atomic64_set(&key->tx_pn, pn); | |
93 | } | |
94 | ||
95 | ||
8d66af49 LB |
96 | int mt76x02_mac_wcid_set_key(struct mt76x02_dev *dev, u8 idx, |
97 | struct ieee80211_key_conf *key) | |
46436b5e SG |
98 | { |
99 | enum mt76x02_cipher_type cipher; | |
100 | u8 key_data[32]; | |
101 | u8 iv_data[8]; | |
de3c2af1 | 102 | u64 pn; |
46436b5e SG |
103 | |
104 | cipher = mt76x02_mac_get_key_info(key, key_data); | |
105 | if (cipher == MT_CIPHER_NONE && key) | |
106 | return -EOPNOTSUPP; | |
107 | ||
8d66af49 LB |
108 | mt76_wr_copy(dev, MT_WCID_KEY(idx), key_data, sizeof(key_data)); |
109 | mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PKEY_MODE, cipher); | |
46436b5e SG |
110 | |
111 | memset(iv_data, 0, sizeof(iv_data)); | |
112 | if (key) { | |
8d66af49 LB |
113 | mt76_rmw_field(dev, MT_WCID_ATTR(idx), MT_WCID_ATTR_PAIRWISE, |
114 | !!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)); | |
de3c2af1 FF |
115 | |
116 | pn = atomic64_read(&key->tx_pn); | |
117 | ||
46436b5e | 118 | iv_data[3] = key->keyidx << 6; |
de3c2af1 | 119 | if (cipher >= MT_CIPHER_TKIP) { |
46436b5e | 120 | iv_data[3] |= 0x20; |
de3c2af1 FF |
121 | put_unaligned_le32(pn >> 16, &iv_data[4]); |
122 | } | |
123 | ||
124 | if (cipher == MT_CIPHER_TKIP) { | |
125 | iv_data[0] = (pn >> 8) & 0xff; | |
126 | iv_data[1] = (iv_data[0] | 0x20) & 0x7f; | |
127 | iv_data[2] = pn & 0xff; | |
128 | } else if (cipher >= MT_CIPHER_AES_CCMP) { | |
129 | put_unaligned_le16((pn & 0xffff), &iv_data[0]); | |
130 | } | |
46436b5e SG |
131 | } |
132 | ||
8d66af49 | 133 | mt76_wr_copy(dev, MT_WCID_IV(idx), iv_data, sizeof(iv_data)); |
46436b5e SG |
134 | |
135 | return 0; | |
136 | } | |
32bb405f | 137 | |
8d66af49 LB |
138 | void mt76x02_mac_wcid_setup(struct mt76x02_dev *dev, u8 idx, |
139 | u8 vif_idx, u8 *mac) | |
32bb405f SG |
140 | { |
141 | struct mt76_wcid_addr addr = {}; | |
142 | u32 attr; | |
143 | ||
144 | attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | | |
145 | FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); | |
146 | ||
8d66af49 | 147 | mt76_wr(dev, MT_WCID_ATTR(idx), attr); |
32bb405f | 148 | |
32bb405f SG |
149 | if (idx >= 128) |
150 | return; | |
151 | ||
152 | if (mac) | |
153 | memcpy(addr.macaddr, mac, ETH_ALEN); | |
154 | ||
8d66af49 | 155 | mt76_wr_copy(dev, MT_WCID_ADDR(idx), &addr, sizeof(addr)); |
32bb405f SG |
156 | } |
157 | EXPORT_SYMBOL_GPL(mt76x02_mac_wcid_setup); | |
516ea2a2 | 158 | |
8d66af49 | 159 | void mt76x02_mac_wcid_set_drop(struct mt76x02_dev *dev, u8 idx, bool drop) |
516ea2a2 | 160 | { |
8d66af49 | 161 | u32 val = mt76_rr(dev, MT_WCID_DROP(idx)); |
516ea2a2 SG |
162 | u32 bit = MT_WCID_DROP_MASK(idx); |
163 | ||
164 | /* prevent unnecessary writes */ | |
165 | if ((val & bit) != (bit * drop)) | |
8d66af49 | 166 | mt76_wr(dev, MT_WCID_DROP(idx), (val & ~bit) | (bit * drop)); |
516ea2a2 | 167 | } |
f5a7f126 | 168 | |
c4ed5088 | 169 | static __le16 |
8d66af49 LB |
170 | mt76x02_mac_tx_rate_val(struct mt76x02_dev *dev, |
171 | const struct ieee80211_tx_rate *rate, u8 *nss_val) | |
5327b5ea | 172 | { |
c09f4d0a | 173 | u8 phy, rate_idx, nss, bw = 0; |
5327b5ea | 174 | u16 rateval; |
5327b5ea SG |
175 | |
176 | if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { | |
177 | rate_idx = rate->idx; | |
178 | nss = 1 + (rate->idx >> 4); | |
179 | phy = MT_PHY_TYPE_VHT; | |
180 | if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) | |
181 | bw = 2; | |
182 | else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | |
183 | bw = 1; | |
184 | } else if (rate->flags & IEEE80211_TX_RC_MCS) { | |
185 | rate_idx = rate->idx; | |
186 | nss = 1 + (rate->idx >> 3); | |
187 | phy = MT_PHY_TYPE_HT; | |
188 | if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) | |
189 | phy = MT_PHY_TYPE_HT_GF; | |
190 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) | |
191 | bw = 1; | |
192 | } else { | |
193 | const struct ieee80211_rate *r; | |
8d66af49 | 194 | int band = dev->mt76.chandef.chan->band; |
5327b5ea SG |
195 | u16 val; |
196 | ||
8d66af49 | 197 | r = &dev->mt76.hw->wiphy->bands[band]->bitrates[rate->idx]; |
5327b5ea SG |
198 | if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) |
199 | val = r->hw_value_short; | |
200 | else | |
201 | val = r->hw_value; | |
202 | ||
203 | phy = val >> 8; | |
204 | rate_idx = val & 0xff; | |
c09f4d0a | 205 | nss = 1; |
5327b5ea SG |
206 | } |
207 | ||
208 | rateval = FIELD_PREP(MT_RXWI_RATE_INDEX, rate_idx); | |
209 | rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); | |
210 | rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); | |
211 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) | |
212 | rateval |= MT_RXWI_RATE_SGI; | |
213 | ||
214 | *nss_val = nss; | |
215 | return cpu_to_le16(rateval); | |
216 | } | |
5327b5ea | 217 | |
8d66af49 LB |
218 | void mt76x02_mac_wcid_set_rate(struct mt76x02_dev *dev, struct mt76_wcid *wcid, |
219 | const struct ieee80211_tx_rate *rate) | |
5327b5ea | 220 | { |
8d66af49 | 221 | spin_lock_bh(&dev->mt76.lock); |
5327b5ea SG |
222 | wcid->tx_rate = mt76x02_mac_tx_rate_val(dev, rate, &wcid->tx_rate_nss); |
223 | wcid->tx_rate_set = true; | |
8d66af49 | 224 | spin_unlock_bh(&dev->mt76.lock); |
5327b5ea | 225 | } |
b490b1df | 226 | |
dd61100d LB |
227 | void mt76x02_mac_set_short_preamble(struct mt76x02_dev *dev, bool enable) |
228 | { | |
229 | if (enable) | |
230 | mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); | |
231 | else | |
232 | mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); | |
233 | } | |
dd61100d | 234 | |
8d66af49 LB |
235 | bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev, |
236 | struct mt76x02_tx_status *stat) | |
b490b1df SG |
237 | { |
238 | u32 stat1, stat2; | |
239 | ||
8d66af49 LB |
240 | stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); |
241 | stat1 = mt76_rr(dev, MT_TX_STAT_FIFO); | |
b490b1df SG |
242 | |
243 | stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID); | |
244 | if (!stat->valid) | |
245 | return false; | |
246 | ||
247 | stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS); | |
248 | stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR); | |
249 | stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ); | |
250 | stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1); | |
251 | stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1); | |
252 | ||
253 | stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2); | |
254 | stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2); | |
255 | ||
e0168dc6 LB |
256 | trace_mac_txstat_fetch(dev, stat); |
257 | ||
b490b1df SG |
258 | return true; |
259 | } | |
7c1f8881 SG |
260 | |
261 | static int | |
262 | mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, | |
263 | enum nl80211_band band) | |
264 | { | |
265 | u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); | |
266 | ||
267 | txrate->idx = 0; | |
268 | txrate->flags = 0; | |
269 | txrate->count = 1; | |
270 | ||
271 | switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { | |
272 | case MT_PHY_TYPE_OFDM: | |
273 | if (band == NL80211_BAND_2GHZ) | |
274 | idx += 4; | |
275 | ||
276 | txrate->idx = idx; | |
277 | return 0; | |
278 | case MT_PHY_TYPE_CCK: | |
279 | if (idx >= 8) | |
280 | idx -= 8; | |
281 | ||
282 | txrate->idx = idx; | |
283 | return 0; | |
284 | case MT_PHY_TYPE_HT_GF: | |
285 | txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; | |
286 | /* fall through */ | |
287 | case MT_PHY_TYPE_HT: | |
288 | txrate->flags |= IEEE80211_TX_RC_MCS; | |
289 | txrate->idx = idx; | |
290 | break; | |
291 | case MT_PHY_TYPE_VHT: | |
292 | txrate->flags |= IEEE80211_TX_RC_VHT_MCS; | |
293 | txrate->idx = idx; | |
294 | break; | |
295 | default: | |
296 | return -EINVAL; | |
297 | } | |
298 | ||
299 | switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { | |
300 | case MT_PHY_BW_20: | |
301 | break; | |
302 | case MT_PHY_BW_40: | |
303 | txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | |
304 | break; | |
305 | case MT_PHY_BW_80: | |
306 | txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; | |
307 | break; | |
308 | default: | |
309 | return -EINVAL; | |
310 | } | |
311 | ||
312 | if (rate & MT_RXWI_RATE_SGI) | |
313 | txrate->flags |= IEEE80211_TX_RC_SHORT_GI; | |
314 | ||
315 | return 0; | |
316 | } | |
317 | ||
8d66af49 | 318 | void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, |
427f9ebe LB |
319 | struct sk_buff *skb, struct mt76_wcid *wcid, |
320 | struct ieee80211_sta *sta, int len) | |
321 | { | |
320c85e6 | 322 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
427f9ebe LB |
323 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
324 | struct ieee80211_tx_rate *rate = &info->control.rates[0]; | |
325 | struct ieee80211_key_conf *key = info->control.hw_key; | |
326 | u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); | |
320c85e6 | 327 | u16 txwi_flags = 0; |
427f9ebe LB |
328 | u8 nss; |
329 | s8 txpwr_adj, max_txpwr_adj; | |
8d66af49 | 330 | u8 ccmp_pn[8], nstreams = dev->mt76.chainmask & 0xf; |
427f9ebe LB |
331 | |
332 | memset(txwi, 0, sizeof(*txwi)); | |
333 | ||
128b75bf FF |
334 | if (!info->control.hw_key && wcid && wcid->hw_key_idx != 0xff && |
335 | ieee80211_has_protected(hdr->frame_control)) { | |
336 | wcid = NULL; | |
337 | ieee80211_get_tx_rates(info->control.vif, sta, skb, | |
338 | info->control.rates, 1); | |
339 | } | |
340 | ||
427f9ebe LB |
341 | if (wcid) |
342 | txwi->wcid = wcid->idx; | |
343 | else | |
344 | txwi->wcid = 0xff; | |
345 | ||
427f9ebe LB |
346 | if (wcid && wcid->sw_iv && key) { |
347 | u64 pn = atomic64_inc_return(&key->tx_pn); | |
348 | ccmp_pn[0] = pn; | |
349 | ccmp_pn[1] = pn >> 8; | |
350 | ccmp_pn[2] = 0; | |
351 | ccmp_pn[3] = 0x20 | (key->keyidx << 6); | |
352 | ccmp_pn[4] = pn >> 16; | |
353 | ccmp_pn[5] = pn >> 24; | |
354 | ccmp_pn[6] = pn >> 32; | |
355 | ccmp_pn[7] = pn >> 40; | |
356 | txwi->iv = *((__le32 *)&ccmp_pn[0]); | |
906d2d3f | 357 | txwi->eiv = *((__le32 *)&ccmp_pn[4]); |
427f9ebe LB |
358 | } |
359 | ||
8d66af49 | 360 | spin_lock_bh(&dev->mt76.lock); |
427f9ebe LB |
361 | if (wcid && (rate->idx < 0 || !rate->count)) { |
362 | txwi->rate = wcid->tx_rate; | |
363 | max_txpwr_adj = wcid->max_txpwr_adj; | |
364 | nss = wcid->tx_rate_nss; | |
365 | } else { | |
366 | txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss); | |
91be8e8a | 367 | max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate); |
427f9ebe | 368 | } |
8d66af49 | 369 | spin_unlock_bh(&dev->mt76.lock); |
427f9ebe | 370 | |
91be8e8a | 371 | txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf, |
1ea0a1b1 LB |
372 | max_txpwr_adj); |
373 | txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); | |
427f9ebe | 374 | |
8d66af49 | 375 | if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E4) |
427f9ebe | 376 | txwi->txstream = 0x13; |
8d66af49 | 377 | else if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E3 && |
427f9ebe LB |
378 | !(txwi->rate & cpu_to_le16(rate_ht_mask))) |
379 | txwi->txstream = 0x93; | |
380 | ||
320c85e6 LB |
381 | if (is_mt76x2(dev) && (info->flags & IEEE80211_TX_CTL_LDPC)) |
382 | txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); | |
383 | if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) | |
384 | txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); | |
385 | if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) | |
386 | txwi_flags |= MT_TXWI_FLAGS_MMPS; | |
387 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | |
388 | txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; | |
389 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) | |
390 | txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; | |
320c85e6 LB |
391 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { |
392 | u8 ba_size = IEEE80211_MIN_AMPDU_BUF; | |
393 | ||
394 | ba_size <<= sta->ht_cap.ampdu_factor; | |
395 | ba_size = min_t(int, 63, ba_size - 1); | |
396 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) | |
397 | ba_size = 0; | |
398 | txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); | |
399 | ||
400 | txwi_flags |= MT_TXWI_FLAGS_AMPDU | | |
401 | FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, | |
402 | sta->ht_cap.ampdu_density); | |
403 | } | |
404 | ||
405 | if (ieee80211_is_probe_resp(hdr->frame_control) || | |
406 | ieee80211_is_beacon(hdr->frame_control)) | |
407 | txwi_flags |= MT_TXWI_FLAGS_TS; | |
408 | ||
409 | txwi->flags |= cpu_to_le16(txwi_flags); | |
410 | txwi->len_ctl = cpu_to_le16(len); | |
427f9ebe LB |
411 | } |
412 | EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi); | |
413 | ||
7c1f8881 | 414 | static void |
8d66af49 LB |
415 | mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, |
416 | struct ieee80211_tx_info *info, | |
417 | struct mt76x02_tx_status *st, int n_frames) | |
7c1f8881 SG |
418 | { |
419 | struct ieee80211_tx_rate *rate = info->status.rates; | |
420 | int cur_idx, last_rate; | |
421 | int i; | |
422 | ||
423 | if (!n_frames) | |
424 | return; | |
425 | ||
426 | last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); | |
427 | mt76x02_mac_process_tx_rate(&rate[last_rate], st->rate, | |
8d66af49 | 428 | dev->mt76.chandef.chan->band); |
7c1f8881 SG |
429 | if (last_rate < IEEE80211_TX_MAX_RATES - 1) |
430 | rate[last_rate + 1].idx = -1; | |
431 | ||
432 | cur_idx = rate[last_rate].idx + last_rate; | |
433 | for (i = 0; i <= last_rate; i++) { | |
434 | rate[i].flags = rate[last_rate].flags; | |
435 | rate[i].idx = max_t(int, 0, cur_idx - i); | |
436 | rate[i].count = 1; | |
437 | } | |
438 | rate[last_rate].count = st->retry + 1 - last_rate; | |
439 | ||
440 | info->status.ampdu_len = n_frames; | |
441 | info->status.ampdu_ack_len = st->success ? n_frames : 0; | |
442 | ||
7c1f8881 SG |
443 | if (st->aggr) |
444 | info->flags |= IEEE80211_TX_CTL_AMPDU | | |
445 | IEEE80211_TX_STAT_AMPDU; | |
446 | ||
447 | if (!st->ack_req) | |
448 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | |
449 | else if (st->success) | |
450 | info->flags |= IEEE80211_TX_STAT_ACK; | |
451 | } | |
452 | ||
8d66af49 LB |
453 | void mt76x02_send_tx_status(struct mt76x02_dev *dev, |
454 | struct mt76x02_tx_status *stat, u8 *update) | |
7c1f8881 SG |
455 | { |
456 | struct ieee80211_tx_info info = {}; | |
88046b2c FF |
457 | struct ieee80211_tx_status status = { |
458 | .info = &info | |
459 | }; | |
7c1f8881 SG |
460 | struct mt76_wcid *wcid = NULL; |
461 | struct mt76x02_sta *msta = NULL; | |
88046b2c | 462 | struct mt76_dev *mdev = &dev->mt76; |
79d1c94c | 463 | struct sk_buff_head list; |
88046b2c FF |
464 | |
465 | if (stat->pktid == MT_PACKET_ID_NO_ACK) | |
466 | return; | |
7c1f8881 SG |
467 | |
468 | rcu_read_lock(); | |
79d1c94c | 469 | mt76_tx_status_lock(mdev, &list); |
88046b2c | 470 | |
8d66af49 LB |
471 | if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid)) |
472 | wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]); | |
7c1f8881 | 473 | |
65b526a1 | 474 | if (wcid && wcid->sta) { |
7c1f8881 SG |
475 | void *priv; |
476 | ||
477 | priv = msta = container_of(wcid, struct mt76x02_sta, wcid); | |
88046b2c FF |
478 | status.sta = container_of(priv, struct ieee80211_sta, |
479 | drv_priv); | |
480 | } | |
481 | ||
482 | if (wcid) { | |
013b2dff | 483 | if (stat->pktid >= MT_PACKET_ID_FIRST) |
88046b2c | 484 | status.skb = mt76_tx_status_skb_get(mdev, wcid, |
79d1c94c | 485 | stat->pktid, &list); |
88046b2c FF |
486 | if (status.skb) |
487 | status.info = IEEE80211_SKB_CB(status.skb); | |
7c1f8881 SG |
488 | } |
489 | ||
88046b2c | 490 | if (msta && stat->aggr && !status.skb) { |
7c1f8881 SG |
491 | u32 stat_val, stat_cache; |
492 | ||
493 | stat_val = stat->rate; | |
494 | stat_val |= ((u32) stat->retry) << 16; | |
495 | stat_cache = msta->status.rate; | |
496 | stat_cache |= ((u32) msta->status.retry) << 16; | |
497 | ||
498 | if (*update == 0 && stat_val == stat_cache && | |
499 | stat->wcid == msta->status.wcid && msta->n_frames < 32) { | |
500 | msta->n_frames++; | |
501 | goto out; | |
502 | } | |
503 | ||
88046b2c | 504 | mt76x02_mac_fill_tx_status(dev, status.info, &msta->status, |
8d66af49 | 505 | msta->n_frames); |
7c1f8881 SG |
506 | |
507 | msta->status = *stat; | |
508 | msta->n_frames = 1; | |
509 | *update = 0; | |
510 | } else { | |
88046b2c | 511 | mt76x02_mac_fill_tx_status(dev, status.info, stat, 1); |
7c1f8881 SG |
512 | *update = 1; |
513 | } | |
514 | ||
88046b2c | 515 | if (status.skb) |
79d1c94c | 516 | mt76_tx_status_skb_done(mdev, status.skb, &list); |
88046b2c FF |
517 | else |
518 | ieee80211_tx_status_ext(mt76_hw(dev), &status); | |
7c1f8881 SG |
519 | |
520 | out: | |
79d1c94c | 521 | mt76_tx_status_unlock(mdev, &list); |
7c1f8881 SG |
522 | rcu_read_unlock(); |
523 | } | |
74ff4539 | 524 | |
1a4846fc | 525 | static int |
f832898d LB |
526 | mt76x02_mac_process_rate(struct mt76x02_dev *dev, |
527 | struct mt76_rx_status *status, | |
528 | u16 rate) | |
74ff4539 SG |
529 | { |
530 | u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); | |
531 | ||
532 | switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { | |
533 | case MT_PHY_TYPE_OFDM: | |
534 | if (idx >= 8) | |
535 | idx = 0; | |
536 | ||
537 | if (status->band == NL80211_BAND_2GHZ) | |
538 | idx += 4; | |
539 | ||
540 | status->rate_idx = idx; | |
541 | return 0; | |
542 | case MT_PHY_TYPE_CCK: | |
543 | if (idx >= 8) { | |
544 | idx -= 8; | |
545 | status->enc_flags |= RX_ENC_FLAG_SHORTPRE; | |
546 | } | |
547 | ||
548 | if (idx >= 4) | |
549 | idx = 0; | |
550 | ||
551 | status->rate_idx = idx; | |
552 | return 0; | |
553 | case MT_PHY_TYPE_HT_GF: | |
554 | status->enc_flags |= RX_ENC_FLAG_HT_GF; | |
555 | /* fall through */ | |
556 | case MT_PHY_TYPE_HT: | |
557 | status->encoding = RX_ENC_HT; | |
558 | status->rate_idx = idx; | |
559 | break; | |
f832898d LB |
560 | case MT_PHY_TYPE_VHT: { |
561 | u8 n_rxstream = dev->mt76.chainmask & 0xf; | |
562 | ||
74ff4539 SG |
563 | status->encoding = RX_ENC_VHT; |
564 | status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); | |
f832898d LB |
565 | status->nss = min_t(u8, n_rxstream, |
566 | FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1); | |
74ff4539 | 567 | break; |
f832898d | 568 | } |
74ff4539 SG |
569 | default: |
570 | return -EINVAL; | |
571 | } | |
572 | ||
573 | if (rate & MT_RXWI_RATE_LDPC) | |
574 | status->enc_flags |= RX_ENC_FLAG_LDPC; | |
575 | ||
576 | if (rate & MT_RXWI_RATE_SGI) | |
577 | status->enc_flags |= RX_ENC_FLAG_SHORT_GI; | |
578 | ||
579 | if (rate & MT_RXWI_RATE_STBC) | |
580 | status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; | |
581 | ||
582 | switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { | |
583 | case MT_PHY_BW_20: | |
584 | break; | |
585 | case MT_PHY_BW_40: | |
586 | status->bw = RATE_INFO_BW_40; | |
587 | break; | |
588 | case MT_PHY_BW_80: | |
589 | status->bw = RATE_INFO_BW_80; | |
590 | break; | |
591 | default: | |
592 | break; | |
593 | } | |
594 | ||
595 | return 0; | |
596 | } | |
89a8607c | 597 | |
0b2d27e5 | 598 | void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr) |
89a8607c | 599 | { |
0b2d27e5 SG |
600 | static const u8 null_addr[ETH_ALEN] = {}; |
601 | int i; | |
602 | ||
8d66af49 | 603 | ether_addr_copy(dev->mt76.macaddr, addr); |
89a8607c | 604 | |
8d66af49 LB |
605 | if (!is_valid_ether_addr(dev->mt76.macaddr)) { |
606 | eth_random_addr(dev->mt76.macaddr); | |
607 | dev_info(dev->mt76.dev, | |
89a8607c | 608 | "Invalid MAC address, using random address %pM\n", |
8d66af49 | 609 | dev->mt76.macaddr); |
89a8607c LB |
610 | } |
611 | ||
8d66af49 LB |
612 | mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr)); |
613 | mt76_wr(dev, MT_MAC_ADDR_DW1, | |
614 | get_unaligned_le16(dev->mt76.macaddr + 4) | | |
615 | FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); | |
0b2d27e5 SG |
616 | |
617 | mt76_wr(dev, MT_MAC_BSSID_DW0, | |
618 | get_unaligned_le32(dev->mt76.macaddr)); | |
619 | mt76_wr(dev, MT_MAC_BSSID_DW1, | |
620 | get_unaligned_le16(dev->mt76.macaddr + 4) | | |
621 | FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */ | |
622 | MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); | |
623 | ||
624 | for (i = 0; i < 16; i++) | |
625 | mt76x02_mac_set_bssid(dev, i, null_addr); | |
89a8607c LB |
626 | } |
627 | EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr); | |
d9f8934e LB |
628 | |
629 | static int | |
630 | mt76x02_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain) | |
631 | { | |
632 | struct mt76x02_rx_freq_cal *cal = &dev->cal.rx; | |
633 | ||
634 | rssi += cal->rssi_offset[chain]; | |
635 | rssi -= cal->lna_gain; | |
636 | ||
637 | return rssi; | |
638 | } | |
639 | ||
640 | int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, | |
641 | void *rxi) | |
642 | { | |
643 | struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; | |
644 | struct mt76x02_rxwi *rxwi = rxi; | |
645 | struct mt76x02_sta *sta; | |
646 | u32 rxinfo = le32_to_cpu(rxwi->rxinfo); | |
647 | u32 ctl = le32_to_cpu(rxwi->ctl); | |
648 | u16 rate = le16_to_cpu(rxwi->rate); | |
649 | u16 tid_sn = le16_to_cpu(rxwi->tid_sn); | |
650 | bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); | |
9f688473 | 651 | int pad_len = 0, nstreams = dev->mt76.chainmask & 0xf; |
d9f8934e LB |
652 | s8 signal; |
653 | u8 pn_len; | |
654 | u8 wcid; | |
655 | int len; | |
656 | ||
657 | if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) | |
658 | return -EINVAL; | |
659 | ||
660 | if (rxinfo & MT_RXINFO_L2PAD) | |
661 | pad_len += 2; | |
662 | ||
663 | if (rxinfo & MT_RXINFO_DECRYPT) { | |
664 | status->flag |= RX_FLAG_DECRYPTED; | |
665 | status->flag |= RX_FLAG_MMIC_STRIPPED; | |
666 | status->flag |= RX_FLAG_MIC_STRIPPED; | |
667 | status->flag |= RX_FLAG_IV_STRIPPED; | |
668 | } | |
669 | ||
670 | wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); | |
671 | sta = mt76x02_rx_get_sta(&dev->mt76, wcid); | |
672 | status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast); | |
673 | ||
674 | len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); | |
675 | pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); | |
676 | if (pn_len) { | |
677 | int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len; | |
678 | u8 *data = skb->data + offset; | |
679 | ||
680 | status->iv[0] = data[7]; | |
681 | status->iv[1] = data[6]; | |
682 | status->iv[2] = data[5]; | |
683 | status->iv[3] = data[4]; | |
684 | status->iv[4] = data[1]; | |
685 | status->iv[5] = data[0]; | |
686 | ||
687 | /* | |
688 | * Driver CCMP validation can't deal with fragments. | |
689 | * Let mac80211 take care of it. | |
690 | */ | |
691 | if (rxinfo & MT_RXINFO_FRAG) { | |
692 | status->flag &= ~RX_FLAG_IV_STRIPPED; | |
693 | } else { | |
694 | pad_len += pn_len << 2; | |
695 | len -= pn_len << 2; | |
696 | } | |
697 | } | |
698 | ||
699 | mt76x02_remove_hdr_pad(skb, pad_len); | |
700 | ||
701 | if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) | |
702 | status->aggr = true; | |
703 | ||
704 | if (WARN_ON_ONCE(len > skb->len)) | |
705 | return -EINVAL; | |
706 | ||
707 | pskb_trim(skb, len); | |
708 | ||
709 | status->chains = BIT(0); | |
710 | signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0); | |
9f688473 FF |
711 | status->chain_signal[0] = signal; |
712 | if (nstreams > 1) { | |
713 | status->chains |= BIT(1); | |
714 | status->chain_signal[1] = mt76x02_mac_get_rssi(dev, | |
715 | rxwi->rssi[1], | |
716 | 1); | |
717 | signal = max_t(s8, signal, status->chain_signal[1]); | |
d9f8934e LB |
718 | } |
719 | status->signal = signal; | |
720 | status->freq = dev->mt76.chandef.chan->center_freq; | |
721 | status->band = dev->mt76.chandef.chan->band; | |
722 | ||
723 | status->tid = FIELD_GET(MT_RXWI_TID, tid_sn); | |
724 | status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn); | |
725 | ||
f832898d | 726 | return mt76x02_mac_process_rate(dev, status, rate); |
d9f8934e | 727 | } |
3e2342ed LB |
728 | |
729 | void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq) | |
730 | { | |
731 | struct mt76x02_tx_status stat = {}; | |
732 | unsigned long flags; | |
733 | u8 update = 1; | |
734 | bool ret; | |
735 | ||
736 | if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) | |
737 | return; | |
738 | ||
739 | trace_mac_txstat_poll(dev); | |
740 | ||
741 | while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { | |
742 | spin_lock_irqsave(&dev->mt76.mmio.irq_lock, flags); | |
8d66af49 | 743 | ret = mt76x02_mac_load_tx_status(dev, &stat); |
3e2342ed LB |
744 | spin_unlock_irqrestore(&dev->mt76.mmio.irq_lock, flags); |
745 | ||
746 | if (!ret) | |
747 | break; | |
748 | ||
3e2342ed | 749 | if (!irq) { |
8d66af49 | 750 | mt76x02_send_tx_status(dev, &stat, &update); |
3e2342ed LB |
751 | continue; |
752 | } | |
753 | ||
754 | kfifo_put(&dev->txstatus_fifo, stat); | |
755 | } | |
756 | } | |
466495b1 | 757 | |
466495b1 LB |
758 | void mt76x02_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue *q, |
759 | struct mt76_queue_entry *e, bool flush) | |
760 | { | |
761 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); | |
88046b2c | 762 | struct mt76x02_txwi *txwi; |
466495b1 | 763 | |
88046b2c | 764 | if (!e->txwi) { |
466495b1 | 765 | dev_kfree_skb_any(e->skb); |
88046b2c FF |
766 | return; |
767 | } | |
768 | ||
769 | mt76x02_mac_poll_tx_status(dev, false); | |
770 | ||
771 | txwi = (struct mt76x02_txwi *) &e->txwi->txwi; | |
772 | trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); | |
773 | ||
774 | mt76_tx_complete_skb(mdev, e->skb); | |
466495b1 LB |
775 | } |
776 | EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); | |
62503186 | 777 | |
20ce270e | 778 | void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val) |
317ed42b LB |
779 | { |
780 | u32 data = 0; | |
781 | ||
782 | if (val != ~0) | |
783 | data = FIELD_PREP(MT_PROT_CFG_CTRL, 1) | | |
784 | MT_PROT_CFG_RTS_THRESH; | |
785 | ||
786 | mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, val); | |
787 | ||
788 | mt76_rmw(dev, MT_CCK_PROT_CFG, | |
789 | MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); | |
790 | mt76_rmw(dev, MT_OFDM_PROT_CFG, | |
791 | MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); | |
317ed42b LB |
792 | } |
793 | ||
26a7b547 SG |
794 | void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot, |
795 | int ht_mode) | |
796 | { | |
797 | int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; | |
798 | bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | |
799 | u32 prot[6]; | |
800 | u32 vht_prot[3]; | |
801 | int i; | |
802 | u16 rts_thr; | |
803 | ||
804 | for (i = 0; i < ARRAY_SIZE(prot); i++) { | |
805 | prot[i] = mt76_rr(dev, MT_CCK_PROT_CFG + i * 4); | |
806 | prot[i] &= ~MT_PROT_CFG_CTRL; | |
807 | if (i >= 2) | |
808 | prot[i] &= ~MT_PROT_CFG_RATE; | |
809 | } | |
810 | ||
811 | for (i = 0; i < ARRAY_SIZE(vht_prot); i++) { | |
812 | vht_prot[i] = mt76_rr(dev, MT_TX_PROT_CFG6 + i * 4); | |
813 | vht_prot[i] &= ~(MT_PROT_CFG_CTRL | MT_PROT_CFG_RATE); | |
814 | } | |
815 | ||
816 | rts_thr = mt76_get_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH); | |
817 | ||
818 | if (rts_thr != 0xffff) | |
819 | prot[0] |= MT_PROT_CTRL_RTS_CTS; | |
820 | ||
821 | if (legacy_prot) { | |
822 | prot[1] |= MT_PROT_CTRL_CTS2SELF; | |
823 | ||
824 | prot[2] |= MT_PROT_RATE_CCK_11; | |
825 | prot[3] |= MT_PROT_RATE_CCK_11; | |
826 | prot[4] |= MT_PROT_RATE_CCK_11; | |
827 | prot[5] |= MT_PROT_RATE_CCK_11; | |
828 | ||
829 | vht_prot[0] |= MT_PROT_RATE_CCK_11; | |
830 | vht_prot[1] |= MT_PROT_RATE_CCK_11; | |
831 | vht_prot[2] |= MT_PROT_RATE_CCK_11; | |
832 | } else { | |
833 | if (rts_thr != 0xffff) | |
834 | prot[1] |= MT_PROT_CTRL_RTS_CTS; | |
835 | ||
836 | prot[2] |= MT_PROT_RATE_OFDM_24; | |
837 | prot[3] |= MT_PROT_RATE_DUP_OFDM_24; | |
838 | prot[4] |= MT_PROT_RATE_OFDM_24; | |
839 | prot[5] |= MT_PROT_RATE_DUP_OFDM_24; | |
840 | ||
841 | vht_prot[0] |= MT_PROT_RATE_OFDM_24; | |
842 | vht_prot[1] |= MT_PROT_RATE_DUP_OFDM_24; | |
843 | vht_prot[2] |= MT_PROT_RATE_SGI_OFDM_24; | |
844 | } | |
845 | ||
846 | switch (mode) { | |
847 | case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: | |
848 | case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: | |
849 | prot[2] |= MT_PROT_CTRL_RTS_CTS; | |
850 | prot[3] |= MT_PROT_CTRL_RTS_CTS; | |
851 | prot[4] |= MT_PROT_CTRL_RTS_CTS; | |
852 | prot[5] |= MT_PROT_CTRL_RTS_CTS; | |
853 | vht_prot[0] |= MT_PROT_CTRL_RTS_CTS; | |
854 | vht_prot[1] |= MT_PROT_CTRL_RTS_CTS; | |
855 | vht_prot[2] |= MT_PROT_CTRL_RTS_CTS; | |
856 | break; | |
857 | case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: | |
858 | prot[3] |= MT_PROT_CTRL_RTS_CTS; | |
859 | prot[5] |= MT_PROT_CTRL_RTS_CTS; | |
860 | vht_prot[1] |= MT_PROT_CTRL_RTS_CTS; | |
861 | vht_prot[2] |= MT_PROT_CTRL_RTS_CTS; | |
862 | break; | |
863 | } | |
864 | ||
865 | if (non_gf) { | |
866 | prot[4] |= MT_PROT_CTRL_RTS_CTS; | |
867 | prot[5] |= MT_PROT_CTRL_RTS_CTS; | |
868 | } | |
869 | ||
870 | for (i = 0; i < ARRAY_SIZE(prot); i++) | |
871 | mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); | |
872 | ||
873 | for (i = 0; i < ARRAY_SIZE(vht_prot); i++) | |
874 | mt76_wr(dev, MT_TX_PROT_CFG6 + i * 4, vht_prot[i]); | |
875 | } | |
876 | ||
62503186 LB |
877 | void mt76x02_update_channel(struct mt76_dev *mdev) |
878 | { | |
879 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); | |
880 | struct mt76_channel_state *state; | |
881 | u32 active, busy; | |
882 | ||
883 | state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); | |
884 | ||
885 | busy = mt76_rr(dev, MT_CH_BUSY); | |
886 | active = busy + mt76_rr(dev, MT_CH_IDLE); | |
887 | ||
888 | spin_lock_bh(&dev->mt76.cc_lock); | |
889 | state->cc_busy += busy; | |
890 | state->cc_active += active; | |
891 | spin_unlock_bh(&dev->mt76.cc_lock); | |
892 | } | |
893 | EXPORT_SYMBOL_GPL(mt76x02_update_channel); | |
7dd73588 | 894 | |
73556561 LB |
895 | static void mt76x02_check_mac_err(struct mt76x02_dev *dev) |
896 | { | |
897 | u32 val = mt76_rr(dev, 0x10f4); | |
898 | ||
899 | if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) | |
900 | return; | |
901 | ||
902 | dev_err(dev->mt76.dev, "mac specific condition occurred\n"); | |
903 | ||
904 | mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); | |
905 | udelay(10); | |
374eb1b5 LB |
906 | mt76_wr(dev, MT_MAC_SYS_CTRL, |
907 | MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); | |
73556561 LB |
908 | } |
909 | ||
f82ce8d9 LB |
910 | static void |
911 | mt76x02_edcca_tx_enable(struct mt76x02_dev *dev, bool enable) | |
912 | { | |
913 | if (enable) { | |
914 | u32 data; | |
915 | ||
916 | mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); | |
917 | mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN); | |
918 | /* enable pa-lna */ | |
919 | data = mt76_rr(dev, MT_TX_PIN_CFG); | |
920 | data |= MT_TX_PIN_CFG_TXANT | | |
921 | MT_TX_PIN_CFG_RXANT | | |
922 | MT_TX_PIN_RFTR_EN | | |
923 | MT_TX_PIN_TRSW_EN; | |
924 | mt76_wr(dev, MT_TX_PIN_CFG, data); | |
925 | } else { | |
926 | mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); | |
927 | mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN); | |
928 | /* disable pa-lna */ | |
929 | mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT); | |
930 | mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_RXANT); | |
931 | } | |
932 | dev->ed_tx_blocked = !enable; | |
933 | } | |
934 | ||
20c06572 | 935 | void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable) |
f82ce8d9 LB |
936 | { |
937 | dev->ed_trigger = 0; | |
938 | dev->ed_silent = 0; | |
939 | ||
20c06572 | 940 | if (dev->ed_monitor && enable) { |
f82ce8d9 LB |
941 | struct ieee80211_channel *chan = dev->mt76.chandef.chan; |
942 | u8 ed_th = chan->band == NL80211_BAND_5GHZ ? 0x0e : 0x20; | |
943 | ||
944 | mt76_clear(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN); | |
945 | mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); | |
946 | mt76_rmw(dev, MT_BBP(AGC, 2), GENMASK(15, 0), | |
947 | ed_th << 8 | ed_th); | |
5c8b0a33 | 948 | mt76_set(dev, MT_TXOP_HLDR_ET, MT_TXOP_HLDR_TX40M_BLK_EN); |
f82ce8d9 LB |
949 | } else { |
950 | mt76_set(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN); | |
951 | mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); | |
952 | if (is_mt76x2(dev)) { | |
953 | mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); | |
5c8b0a33 FF |
954 | mt76_set(dev, MT_TXOP_HLDR_ET, |
955 | MT_TXOP_HLDR_TX40M_BLK_EN); | |
f82ce8d9 LB |
956 | } else { |
957 | mt76_wr(dev, MT_BBP(AGC, 2), 0x003a6464); | |
958 | mt76_clear(dev, MT_TXOP_HLDR_ET, | |
959 | MT_TXOP_HLDR_TX40M_BLK_EN); | |
960 | } | |
961 | } | |
962 | mt76x02_edcca_tx_enable(dev, true); | |
a0ac8061 | 963 | dev->ed_monitor_learning = true; |
c15b7cef FF |
964 | |
965 | /* clear previous CCA timer value */ | |
966 | mt76_rr(dev, MT_ED_CCA_TIMER); | |
ccdaf7b4 | 967 | dev->ed_time = ktime_get_boottime(); |
f82ce8d9 LB |
968 | } |
969 | EXPORT_SYMBOL_GPL(mt76x02_edcca_init); | |
970 | ||
f1906fb2 | 971 | #define MT_EDCCA_TH 92 |
f82ce8d9 | 972 | #define MT_EDCCA_BLOCK_TH 2 |
a0ac8061 FF |
973 | #define MT_EDCCA_LEARN_TH 50 |
974 | #define MT_EDCCA_LEARN_CCA 180 | |
975 | #define MT_EDCCA_LEARN_TIMEOUT (20 * HZ) | |
976 | ||
f82ce8d9 LB |
977 | static void mt76x02_edcca_check(struct mt76x02_dev *dev) |
978 | { | |
ccdaf7b4 FF |
979 | ktime_t cur_time; |
980 | u32 active, val, busy; | |
f82ce8d9 | 981 | |
ccdaf7b4 | 982 | cur_time = ktime_get_boottime(); |
f82ce8d9 | 983 | val = mt76_rr(dev, MT_ED_CCA_TIMER); |
ccdaf7b4 FF |
984 | |
985 | active = ktime_to_us(ktime_sub(cur_time, dev->ed_time)); | |
986 | dev->ed_time = cur_time; | |
987 | ||
988 | busy = (val * 100) / active; | |
f82ce8d9 LB |
989 | busy = min_t(u32, busy, 100); |
990 | ||
991 | if (busy > MT_EDCCA_TH) { | |
992 | dev->ed_trigger++; | |
993 | dev->ed_silent = 0; | |
994 | } else { | |
995 | dev->ed_silent++; | |
996 | dev->ed_trigger = 0; | |
997 | } | |
998 | ||
a0ac8061 FF |
999 | if (dev->cal.agc_lowest_gain && |
1000 | dev->cal.false_cca > MT_EDCCA_LEARN_CCA && | |
1001 | dev->ed_trigger > MT_EDCCA_LEARN_TH) { | |
1002 | dev->ed_monitor_learning = false; | |
1003 | dev->ed_trigger_timeout = jiffies + 20 * HZ; | |
1004 | } else if (!dev->ed_monitor_learning && | |
1005 | time_is_after_jiffies(dev->ed_trigger_timeout)) { | |
1006 | dev->ed_monitor_learning = true; | |
1007 | mt76x02_edcca_tx_enable(dev, true); | |
1008 | } | |
1009 | ||
1010 | if (dev->ed_monitor_learning) | |
1011 | return; | |
1012 | ||
1013 | if (dev->ed_trigger > MT_EDCCA_BLOCK_TH && !dev->ed_tx_blocked) | |
f82ce8d9 | 1014 | mt76x02_edcca_tx_enable(dev, false); |
a0ac8061 | 1015 | else if (dev->ed_silent > MT_EDCCA_BLOCK_TH && dev->ed_tx_blocked) |
f82ce8d9 LB |
1016 | mt76x02_edcca_tx_enable(dev, true); |
1017 | } | |
1018 | ||
7dd73588 LB |
1019 | void mt76x02_mac_work(struct work_struct *work) |
1020 | { | |
1021 | struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, | |
1022 | mac_work.work); | |
1023 | int i, idx; | |
1024 | ||
4989338e LB |
1025 | mutex_lock(&dev->mt76.mutex); |
1026 | ||
7dd73588 LB |
1027 | mt76x02_update_channel(&dev->mt76); |
1028 | for (i = 0, idx = 0; i < 16; i++) { | |
1029 | u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); | |
1030 | ||
1031 | dev->aggr_stats[idx++] += val & 0xffff; | |
1032 | dev->aggr_stats[idx++] += val >> 16; | |
1033 | } | |
1034 | ||
73556561 LB |
1035 | if (!dev->beacon_mask) |
1036 | mt76x02_check_mac_err(dev); | |
1037 | ||
f82ce8d9 LB |
1038 | if (dev->ed_monitor) |
1039 | mt76x02_edcca_check(dev); | |
1040 | ||
4989338e LB |
1041 | mutex_unlock(&dev->mt76.mutex); |
1042 | ||
79d1c94c | 1043 | mt76_tx_status_check(&dev->mt76, NULL, false); |
88046b2c | 1044 | |
7dd73588 | 1045 | ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mac_work, |
2e405024 | 1046 | MT_MAC_WORK_INTERVAL); |
7dd73588 | 1047 | } |
dc33b251 LB |
1048 | |
1049 | void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) | |
1050 | { | |
1051 | idx &= 7; | |
1052 | mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr)); | |
1053 | mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR, | |
1054 | get_unaligned_le16(addr + 4)); | |
1055 | } | |
dc33b251 LB |
1056 | |
1057 | static int | |
1058 | mt76x02_write_beacon(struct mt76x02_dev *dev, int offset, struct sk_buff *skb) | |
1059 | { | |
1060 | int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; | |
1061 | struct mt76x02_txwi txwi; | |
1062 | ||
1063 | if (WARN_ON_ONCE(beacon_len < skb->len + sizeof(struct mt76x02_txwi))) | |
1064 | return -ENOSPC; | |
1065 | ||
1066 | mt76x02_mac_write_txwi(dev, &txwi, skb, NULL, NULL, skb->len); | |
1067 | ||
1068 | mt76_wr_copy(dev, offset, &txwi, sizeof(txwi)); | |
1069 | offset += sizeof(txwi); | |
1070 | ||
1071 | mt76_wr_copy(dev, offset, skb->data, skb->len); | |
1072 | return 0; | |
1073 | } | |
1074 | ||
1075 | static int | |
1076 | __mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 bcn_idx, | |
1077 | struct sk_buff *skb) | |
1078 | { | |
1079 | int beacon_len = mt76x02_beacon_offsets[1] - mt76x02_beacon_offsets[0]; | |
1080 | int beacon_addr = mt76x02_beacon_offsets[bcn_idx]; | |
1081 | int ret = 0; | |
1082 | int i; | |
1083 | ||
1084 | /* Prevent corrupt transmissions during update */ | |
1085 | mt76_set(dev, MT_BCN_BYPASS_MASK, BIT(bcn_idx)); | |
1086 | ||
1087 | if (skb) { | |
1088 | ret = mt76x02_write_beacon(dev, beacon_addr, skb); | |
1089 | if (!ret) | |
1090 | dev->beacon_data_mask |= BIT(bcn_idx); | |
1091 | } else { | |
1092 | dev->beacon_data_mask &= ~BIT(bcn_idx); | |
1093 | for (i = 0; i < beacon_len; i += 4) | |
1094 | mt76_wr(dev, beacon_addr + i, 0); | |
1095 | } | |
1096 | ||
1097 | mt76_wr(dev, MT_BCN_BYPASS_MASK, 0xff00 | ~dev->beacon_data_mask); | |
1098 | ||
1099 | return ret; | |
1100 | } | |
1101 | ||
1102 | int mt76x02_mac_set_beacon(struct mt76x02_dev *dev, u8 vif_idx, | |
1103 | struct sk_buff *skb) | |
1104 | { | |
1105 | bool force_update = false; | |
1106 | int bcn_idx = 0; | |
1107 | int i; | |
1108 | ||
1109 | for (i = 0; i < ARRAY_SIZE(dev->beacons); i++) { | |
1110 | if (vif_idx == i) { | |
1111 | force_update = !!dev->beacons[i] ^ !!skb; | |
1112 | ||
1113 | if (dev->beacons[i]) | |
1114 | dev_kfree_skb(dev->beacons[i]); | |
1115 | ||
1116 | dev->beacons[i] = skb; | |
1117 | __mt76x02_mac_set_beacon(dev, bcn_idx, skb); | |
1118 | } else if (force_update && dev->beacons[i]) { | |
1119 | __mt76x02_mac_set_beacon(dev, bcn_idx, | |
1120 | dev->beacons[i]); | |
1121 | } | |
1122 | ||
1123 | bcn_idx += !!dev->beacons[i]; | |
1124 | } | |
1125 | ||
1126 | for (i = bcn_idx; i < ARRAY_SIZE(dev->beacons); i++) { | |
1127 | if (!(dev->beacon_data_mask & BIT(i))) | |
1128 | break; | |
1129 | ||
1130 | __mt76x02_mac_set_beacon(dev, i, NULL); | |
1131 | } | |
1132 | ||
1133 | mt76_rmw_field(dev, MT_MAC_BSSID_DW1, MT_MAC_BSSID_DW1_MBEACON_N, | |
1134 | bcn_idx - 1); | |
1135 | return 0; | |
1136 | } | |
dc33b251 | 1137 | |
dbb2b22b SG |
1138 | static void |
1139 | __mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, u8 vif_idx, | |
1140 | bool val, struct sk_buff *skb) | |
dc33b251 LB |
1141 | { |
1142 | u8 old_mask = dev->beacon_mask; | |
1143 | bool en; | |
1144 | u32 reg; | |
1145 | ||
1146 | if (val) { | |
1147 | dev->beacon_mask |= BIT(vif_idx); | |
dbb2b22b SG |
1148 | if (skb) |
1149 | mt76x02_mac_set_beacon(dev, vif_idx, skb); | |
dc33b251 LB |
1150 | } else { |
1151 | dev->beacon_mask &= ~BIT(vif_idx); | |
1152 | mt76x02_mac_set_beacon(dev, vif_idx, NULL); | |
1153 | } | |
1154 | ||
1155 | if (!!old_mask == !!dev->beacon_mask) | |
1156 | return; | |
1157 | ||
1158 | en = dev->beacon_mask; | |
1159 | ||
dc33b251 LB |
1160 | reg = MT_BEACON_TIME_CFG_BEACON_TX | |
1161 | MT_BEACON_TIME_CFG_TBTT_EN | | |
1162 | MT_BEACON_TIME_CFG_TIMER_EN; | |
1163 | mt76_rmw(dev, MT_BEACON_TIME_CFG, reg, reg * en); | |
1164 | ||
dbb2b22b SG |
1165 | if (mt76_is_usb(dev)) |
1166 | return; | |
1167 | ||
1168 | mt76_rmw_field(dev, MT_INT_TIMER_EN, MT_INT_TIMER_EN_PRE_TBTT_EN, en); | |
dc33b251 LB |
1169 | if (en) |
1170 | mt76x02_irq_enable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); | |
1171 | else | |
1172 | mt76x02_irq_disable(dev, MT_INT_PRE_TBTT | MT_INT_TBTT); | |
1173 | } | |
dbb2b22b SG |
1174 | |
1175 | void mt76x02_mac_set_beacon_enable(struct mt76x02_dev *dev, | |
1176 | struct ieee80211_vif *vif, bool val) | |
1177 | { | |
1178 | u8 vif_idx = ((struct mt76x02_vif *)vif->drv_priv)->idx; | |
1179 | struct sk_buff *skb = NULL; | |
1180 | ||
1181 | if (mt76_is_mmio(dev)) | |
1182 | tasklet_disable(&dev->pre_tbtt_tasklet); | |
1183 | else if (val) | |
1184 | skb = ieee80211_beacon_get(mt76_hw(dev), vif); | |
1185 | ||
90f42f2d FF |
1186 | if (!dev->beacon_mask) |
1187 | dev->tbtt_count = 0; | |
1188 | ||
dbb2b22b SG |
1189 | __mt76x02_mac_set_beacon_enable(dev, vif_idx, val, skb); |
1190 | ||
1191 | if (mt76_is_mmio(dev)) | |
1192 | tasklet_enable(&dev->pre_tbtt_tasklet); | |
1193 | } |