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 | { |
db9f11d3 FF |
221 | s8 max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate); |
222 | __le16 rateval; | |
223 | u32 tx_info; | |
224 | s8 nss; | |
225 | ||
226 | rateval = mt76x02_mac_tx_rate_val(dev, rate, &nss); | |
227 | tx_info = FIELD_PREP(MT_WCID_TX_INFO_RATE, rateval) | | |
228 | FIELD_PREP(MT_WCID_TX_INFO_NSS, nss) | | |
229 | FIELD_PREP(MT_WCID_TX_INFO_TXPWR_ADJ, max_txpwr_adj) | | |
230 | MT_WCID_TX_INFO_SET; | |
231 | wcid->tx_info = tx_info; | |
5327b5ea | 232 | } |
b490b1df | 233 | |
dd61100d LB |
234 | void mt76x02_mac_set_short_preamble(struct mt76x02_dev *dev, bool enable) |
235 | { | |
236 | if (enable) | |
237 | mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); | |
238 | else | |
239 | mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); | |
240 | } | |
dd61100d | 241 | |
8d66af49 LB |
242 | bool mt76x02_mac_load_tx_status(struct mt76x02_dev *dev, |
243 | struct mt76x02_tx_status *stat) | |
b490b1df SG |
244 | { |
245 | u32 stat1, stat2; | |
246 | ||
8d66af49 LB |
247 | stat2 = mt76_rr(dev, MT_TX_STAT_FIFO_EXT); |
248 | stat1 = mt76_rr(dev, MT_TX_STAT_FIFO); | |
b490b1df SG |
249 | |
250 | stat->valid = !!(stat1 & MT_TX_STAT_FIFO_VALID); | |
251 | if (!stat->valid) | |
252 | return false; | |
253 | ||
254 | stat->success = !!(stat1 & MT_TX_STAT_FIFO_SUCCESS); | |
255 | stat->aggr = !!(stat1 & MT_TX_STAT_FIFO_AGGR); | |
256 | stat->ack_req = !!(stat1 & MT_TX_STAT_FIFO_ACKREQ); | |
257 | stat->wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, stat1); | |
258 | stat->rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, stat1); | |
259 | ||
260 | stat->retry = FIELD_GET(MT_TX_STAT_FIFO_EXT_RETRY, stat2); | |
261 | stat->pktid = FIELD_GET(MT_TX_STAT_FIFO_EXT_PKTID, stat2); | |
262 | ||
e0168dc6 LB |
263 | trace_mac_txstat_fetch(dev, stat); |
264 | ||
b490b1df SG |
265 | return true; |
266 | } | |
7c1f8881 SG |
267 | |
268 | static int | |
269 | mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, | |
270 | enum nl80211_band band) | |
271 | { | |
272 | u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); | |
273 | ||
274 | txrate->idx = 0; | |
275 | txrate->flags = 0; | |
276 | txrate->count = 1; | |
277 | ||
278 | switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { | |
279 | case MT_PHY_TYPE_OFDM: | |
280 | if (band == NL80211_BAND_2GHZ) | |
281 | idx += 4; | |
282 | ||
283 | txrate->idx = idx; | |
284 | return 0; | |
285 | case MT_PHY_TYPE_CCK: | |
286 | if (idx >= 8) | |
287 | idx -= 8; | |
288 | ||
289 | txrate->idx = idx; | |
290 | return 0; | |
291 | case MT_PHY_TYPE_HT_GF: | |
292 | txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; | |
293 | /* fall through */ | |
294 | case MT_PHY_TYPE_HT: | |
295 | txrate->flags |= IEEE80211_TX_RC_MCS; | |
296 | txrate->idx = idx; | |
297 | break; | |
298 | case MT_PHY_TYPE_VHT: | |
299 | txrate->flags |= IEEE80211_TX_RC_VHT_MCS; | |
300 | txrate->idx = idx; | |
301 | break; | |
302 | default: | |
303 | return -EINVAL; | |
304 | } | |
305 | ||
306 | switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { | |
307 | case MT_PHY_BW_20: | |
308 | break; | |
309 | case MT_PHY_BW_40: | |
310 | txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | |
311 | break; | |
312 | case MT_PHY_BW_80: | |
313 | txrate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH; | |
314 | break; | |
315 | default: | |
316 | return -EINVAL; | |
317 | } | |
318 | ||
319 | if (rate & MT_RXWI_RATE_SGI) | |
320 | txrate->flags |= IEEE80211_TX_RC_SHORT_GI; | |
321 | ||
322 | return 0; | |
323 | } | |
324 | ||
8d66af49 | 325 | void mt76x02_mac_write_txwi(struct mt76x02_dev *dev, struct mt76x02_txwi *txwi, |
427f9ebe LB |
326 | struct sk_buff *skb, struct mt76_wcid *wcid, |
327 | struct ieee80211_sta *sta, int len) | |
328 | { | |
320c85e6 | 329 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
427f9ebe LB |
330 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
331 | struct ieee80211_tx_rate *rate = &info->control.rates[0]; | |
332 | struct ieee80211_key_conf *key = info->control.hw_key; | |
db9f11d3 | 333 | u32 wcid_tx_info; |
427f9ebe | 334 | u16 rate_ht_mask = FIELD_PREP(MT_RXWI_RATE_PHY, BIT(1) | BIT(2)); |
320c85e6 | 335 | u16 txwi_flags = 0; |
427f9ebe LB |
336 | u8 nss; |
337 | s8 txpwr_adj, max_txpwr_adj; | |
8d66af49 | 338 | u8 ccmp_pn[8], nstreams = dev->mt76.chainmask & 0xf; |
427f9ebe LB |
339 | |
340 | memset(txwi, 0, sizeof(*txwi)); | |
341 | ||
128b75bf FF |
342 | if (!info->control.hw_key && wcid && wcid->hw_key_idx != 0xff && |
343 | ieee80211_has_protected(hdr->frame_control)) { | |
344 | wcid = NULL; | |
345 | ieee80211_get_tx_rates(info->control.vif, sta, skb, | |
346 | info->control.rates, 1); | |
347 | } | |
348 | ||
427f9ebe LB |
349 | if (wcid) |
350 | txwi->wcid = wcid->idx; | |
351 | else | |
352 | txwi->wcid = 0xff; | |
353 | ||
427f9ebe LB |
354 | if (wcid && wcid->sw_iv && key) { |
355 | u64 pn = atomic64_inc_return(&key->tx_pn); | |
356 | ccmp_pn[0] = pn; | |
357 | ccmp_pn[1] = pn >> 8; | |
358 | ccmp_pn[2] = 0; | |
359 | ccmp_pn[3] = 0x20 | (key->keyidx << 6); | |
360 | ccmp_pn[4] = pn >> 16; | |
361 | ccmp_pn[5] = pn >> 24; | |
362 | ccmp_pn[6] = pn >> 32; | |
363 | ccmp_pn[7] = pn >> 40; | |
364 | txwi->iv = *((__le32 *)&ccmp_pn[0]); | |
906d2d3f | 365 | txwi->eiv = *((__le32 *)&ccmp_pn[4]); |
427f9ebe LB |
366 | } |
367 | ||
427f9ebe | 368 | if (wcid && (rate->idx < 0 || !rate->count)) { |
db9f11d3 FF |
369 | wcid_tx_info = wcid->tx_info; |
370 | txwi->rate = FIELD_GET(MT_WCID_TX_INFO_RATE, wcid_tx_info); | |
371 | max_txpwr_adj = FIELD_GET(MT_WCID_TX_INFO_TXPWR_ADJ, | |
372 | wcid_tx_info); | |
373 | nss = FIELD_GET(MT_WCID_TX_INFO_NSS, wcid_tx_info); | |
427f9ebe LB |
374 | } else { |
375 | txwi->rate = mt76x02_mac_tx_rate_val(dev, rate, &nss); | |
91be8e8a | 376 | max_txpwr_adj = mt76x02_tx_get_max_txpwr_adj(dev, rate); |
427f9ebe | 377 | } |
427f9ebe | 378 | |
91be8e8a | 379 | txpwr_adj = mt76x02_tx_get_txpwr_adj(dev, dev->mt76.txpower_conf, |
1ea0a1b1 LB |
380 | max_txpwr_adj); |
381 | txwi->ctl2 = FIELD_PREP(MT_TX_PWR_ADJ, txpwr_adj); | |
427f9ebe | 382 | |
8d66af49 | 383 | if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E4) |
427f9ebe | 384 | txwi->txstream = 0x13; |
8d66af49 | 385 | else if (nstreams > 1 && mt76_rev(&dev->mt76) >= MT76XX_REV_E3 && |
427f9ebe LB |
386 | !(txwi->rate & cpu_to_le16(rate_ht_mask))) |
387 | txwi->txstream = 0x93; | |
388 | ||
320c85e6 LB |
389 | if (is_mt76x2(dev) && (info->flags & IEEE80211_TX_CTL_LDPC)) |
390 | txwi->rate |= cpu_to_le16(MT_RXWI_RATE_LDPC); | |
391 | if ((info->flags & IEEE80211_TX_CTL_STBC) && nss == 1) | |
392 | txwi->rate |= cpu_to_le16(MT_RXWI_RATE_STBC); | |
393 | if (nss > 1 && sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC) | |
394 | txwi_flags |= MT_TXWI_FLAGS_MMPS; | |
395 | if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) | |
396 | txwi->ack_ctl |= MT_TXWI_ACK_CTL_REQ; | |
397 | if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) | |
398 | txwi->ack_ctl |= MT_TXWI_ACK_CTL_NSEQ; | |
320c85e6 LB |
399 | if ((info->flags & IEEE80211_TX_CTL_AMPDU) && sta) { |
400 | u8 ba_size = IEEE80211_MIN_AMPDU_BUF; | |
401 | ||
402 | ba_size <<= sta->ht_cap.ampdu_factor; | |
403 | ba_size = min_t(int, 63, ba_size - 1); | |
404 | if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) | |
405 | ba_size = 0; | |
406 | txwi->ack_ctl |= FIELD_PREP(MT_TXWI_ACK_CTL_BA_WINDOW, ba_size); | |
407 | ||
408 | txwi_flags |= MT_TXWI_FLAGS_AMPDU | | |
409 | FIELD_PREP(MT_TXWI_FLAGS_MPDU_DENSITY, | |
410 | sta->ht_cap.ampdu_density); | |
411 | } | |
412 | ||
413 | if (ieee80211_is_probe_resp(hdr->frame_control) || | |
414 | ieee80211_is_beacon(hdr->frame_control)) | |
415 | txwi_flags |= MT_TXWI_FLAGS_TS; | |
416 | ||
417 | txwi->flags |= cpu_to_le16(txwi_flags); | |
418 | txwi->len_ctl = cpu_to_le16(len); | |
427f9ebe LB |
419 | } |
420 | EXPORT_SYMBOL_GPL(mt76x02_mac_write_txwi); | |
421 | ||
7c1f8881 | 422 | static void |
8d66af49 LB |
423 | mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, |
424 | struct ieee80211_tx_info *info, | |
425 | struct mt76x02_tx_status *st, int n_frames) | |
7c1f8881 SG |
426 | { |
427 | struct ieee80211_tx_rate *rate = info->status.rates; | |
428 | int cur_idx, last_rate; | |
429 | int i; | |
430 | ||
431 | if (!n_frames) | |
432 | return; | |
433 | ||
434 | last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); | |
435 | mt76x02_mac_process_tx_rate(&rate[last_rate], st->rate, | |
8d66af49 | 436 | dev->mt76.chandef.chan->band); |
7c1f8881 SG |
437 | if (last_rate < IEEE80211_TX_MAX_RATES - 1) |
438 | rate[last_rate + 1].idx = -1; | |
439 | ||
440 | cur_idx = rate[last_rate].idx + last_rate; | |
441 | for (i = 0; i <= last_rate; i++) { | |
442 | rate[i].flags = rate[last_rate].flags; | |
443 | rate[i].idx = max_t(int, 0, cur_idx - i); | |
444 | rate[i].count = 1; | |
445 | } | |
446 | rate[last_rate].count = st->retry + 1 - last_rate; | |
447 | ||
448 | info->status.ampdu_len = n_frames; | |
449 | info->status.ampdu_ack_len = st->success ? n_frames : 0; | |
450 | ||
7c1f8881 SG |
451 | if (st->aggr) |
452 | info->flags |= IEEE80211_TX_CTL_AMPDU | | |
453 | IEEE80211_TX_STAT_AMPDU; | |
454 | ||
455 | if (!st->ack_req) | |
456 | info->flags |= IEEE80211_TX_CTL_NO_ACK; | |
457 | else if (st->success) | |
458 | info->flags |= IEEE80211_TX_STAT_ACK; | |
459 | } | |
460 | ||
8d66af49 LB |
461 | void mt76x02_send_tx_status(struct mt76x02_dev *dev, |
462 | struct mt76x02_tx_status *stat, u8 *update) | |
7c1f8881 SG |
463 | { |
464 | struct ieee80211_tx_info info = {}; | |
88046b2c FF |
465 | struct ieee80211_tx_status status = { |
466 | .info = &info | |
467 | }; | |
7c1f8881 SG |
468 | struct mt76_wcid *wcid = NULL; |
469 | struct mt76x02_sta *msta = NULL; | |
88046b2c | 470 | struct mt76_dev *mdev = &dev->mt76; |
79d1c94c | 471 | struct sk_buff_head list; |
88046b2c FF |
472 | |
473 | if (stat->pktid == MT_PACKET_ID_NO_ACK) | |
474 | return; | |
7c1f8881 SG |
475 | |
476 | rcu_read_lock(); | |
88046b2c | 477 | |
8d66af49 LB |
478 | if (stat->wcid < ARRAY_SIZE(dev->mt76.wcid)) |
479 | wcid = rcu_dereference(dev->mt76.wcid[stat->wcid]); | |
7c1f8881 | 480 | |
65b526a1 | 481 | if (wcid && wcid->sta) { |
7c1f8881 SG |
482 | void *priv; |
483 | ||
484 | priv = msta = container_of(wcid, struct mt76x02_sta, wcid); | |
88046b2c FF |
485 | status.sta = container_of(priv, struct ieee80211_sta, |
486 | drv_priv); | |
487 | } | |
488 | ||
bafdf85d SG |
489 | mt76_tx_status_lock(mdev, &list); |
490 | ||
88046b2c | 491 | if (wcid) { |
013b2dff | 492 | if (stat->pktid >= MT_PACKET_ID_FIRST) |
88046b2c | 493 | status.skb = mt76_tx_status_skb_get(mdev, wcid, |
79d1c94c | 494 | stat->pktid, &list); |
88046b2c FF |
495 | if (status.skb) |
496 | status.info = IEEE80211_SKB_CB(status.skb); | |
7c1f8881 SG |
497 | } |
498 | ||
88046b2c | 499 | if (msta && stat->aggr && !status.skb) { |
7c1f8881 SG |
500 | u32 stat_val, stat_cache; |
501 | ||
502 | stat_val = stat->rate; | |
503 | stat_val |= ((u32) stat->retry) << 16; | |
504 | stat_cache = msta->status.rate; | |
505 | stat_cache |= ((u32) msta->status.retry) << 16; | |
506 | ||
507 | if (*update == 0 && stat_val == stat_cache && | |
508 | stat->wcid == msta->status.wcid && msta->n_frames < 32) { | |
509 | msta->n_frames++; | |
bafdf85d SG |
510 | mt76_tx_status_unlock(mdev, &list); |
511 | rcu_read_unlock(); | |
512 | return; | |
7c1f8881 SG |
513 | } |
514 | ||
88046b2c | 515 | mt76x02_mac_fill_tx_status(dev, status.info, &msta->status, |
8d66af49 | 516 | msta->n_frames); |
7c1f8881 SG |
517 | |
518 | msta->status = *stat; | |
519 | msta->n_frames = 1; | |
520 | *update = 0; | |
521 | } else { | |
88046b2c | 522 | mt76x02_mac_fill_tx_status(dev, status.info, stat, 1); |
7c1f8881 SG |
523 | *update = 1; |
524 | } | |
525 | ||
88046b2c | 526 | if (status.skb) |
79d1c94c | 527 | mt76_tx_status_skb_done(mdev, status.skb, &list); |
79d1c94c | 528 | mt76_tx_status_unlock(mdev, &list); |
bafdf85d SG |
529 | |
530 | if (!status.skb) | |
531 | ieee80211_tx_status_ext(mt76_hw(dev), &status); | |
7c1f8881 SG |
532 | rcu_read_unlock(); |
533 | } | |
74ff4539 | 534 | |
1a4846fc | 535 | static int |
f832898d LB |
536 | mt76x02_mac_process_rate(struct mt76x02_dev *dev, |
537 | struct mt76_rx_status *status, | |
538 | u16 rate) | |
74ff4539 SG |
539 | { |
540 | u8 idx = FIELD_GET(MT_RXWI_RATE_INDEX, rate); | |
541 | ||
542 | switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { | |
543 | case MT_PHY_TYPE_OFDM: | |
544 | if (idx >= 8) | |
545 | idx = 0; | |
546 | ||
547 | if (status->band == NL80211_BAND_2GHZ) | |
548 | idx += 4; | |
549 | ||
550 | status->rate_idx = idx; | |
551 | return 0; | |
552 | case MT_PHY_TYPE_CCK: | |
553 | if (idx >= 8) { | |
554 | idx -= 8; | |
555 | status->enc_flags |= RX_ENC_FLAG_SHORTPRE; | |
556 | } | |
557 | ||
558 | if (idx >= 4) | |
559 | idx = 0; | |
560 | ||
561 | status->rate_idx = idx; | |
562 | return 0; | |
563 | case MT_PHY_TYPE_HT_GF: | |
564 | status->enc_flags |= RX_ENC_FLAG_HT_GF; | |
565 | /* fall through */ | |
566 | case MT_PHY_TYPE_HT: | |
567 | status->encoding = RX_ENC_HT; | |
568 | status->rate_idx = idx; | |
569 | break; | |
f832898d LB |
570 | case MT_PHY_TYPE_VHT: { |
571 | u8 n_rxstream = dev->mt76.chainmask & 0xf; | |
572 | ||
74ff4539 SG |
573 | status->encoding = RX_ENC_VHT; |
574 | status->rate_idx = FIELD_GET(MT_RATE_INDEX_VHT_IDX, idx); | |
f832898d LB |
575 | status->nss = min_t(u8, n_rxstream, |
576 | FIELD_GET(MT_RATE_INDEX_VHT_NSS, idx) + 1); | |
74ff4539 | 577 | break; |
f832898d | 578 | } |
74ff4539 SG |
579 | default: |
580 | return -EINVAL; | |
581 | } | |
582 | ||
583 | if (rate & MT_RXWI_RATE_LDPC) | |
584 | status->enc_flags |= RX_ENC_FLAG_LDPC; | |
585 | ||
586 | if (rate & MT_RXWI_RATE_SGI) | |
587 | status->enc_flags |= RX_ENC_FLAG_SHORT_GI; | |
588 | ||
589 | if (rate & MT_RXWI_RATE_STBC) | |
590 | status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; | |
591 | ||
592 | switch (FIELD_GET(MT_RXWI_RATE_BW, rate)) { | |
593 | case MT_PHY_BW_20: | |
594 | break; | |
595 | case MT_PHY_BW_40: | |
596 | status->bw = RATE_INFO_BW_40; | |
597 | break; | |
598 | case MT_PHY_BW_80: | |
599 | status->bw = RATE_INFO_BW_80; | |
600 | break; | |
601 | default: | |
602 | break; | |
603 | } | |
604 | ||
605 | return 0; | |
606 | } | |
89a8607c | 607 | |
0b2d27e5 | 608 | void mt76x02_mac_setaddr(struct mt76x02_dev *dev, const u8 *addr) |
89a8607c | 609 | { |
0b2d27e5 SG |
610 | static const u8 null_addr[ETH_ALEN] = {}; |
611 | int i; | |
612 | ||
8d66af49 | 613 | ether_addr_copy(dev->mt76.macaddr, addr); |
89a8607c | 614 | |
8d66af49 LB |
615 | if (!is_valid_ether_addr(dev->mt76.macaddr)) { |
616 | eth_random_addr(dev->mt76.macaddr); | |
617 | dev_info(dev->mt76.dev, | |
89a8607c | 618 | "Invalid MAC address, using random address %pM\n", |
8d66af49 | 619 | dev->mt76.macaddr); |
89a8607c LB |
620 | } |
621 | ||
8d66af49 LB |
622 | mt76_wr(dev, MT_MAC_ADDR_DW0, get_unaligned_le32(dev->mt76.macaddr)); |
623 | mt76_wr(dev, MT_MAC_ADDR_DW1, | |
624 | get_unaligned_le16(dev->mt76.macaddr + 4) | | |
625 | FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); | |
0b2d27e5 SG |
626 | |
627 | mt76_wr(dev, MT_MAC_BSSID_DW0, | |
628 | get_unaligned_le32(dev->mt76.macaddr)); | |
629 | mt76_wr(dev, MT_MAC_BSSID_DW1, | |
630 | get_unaligned_le16(dev->mt76.macaddr + 4) | | |
631 | FIELD_PREP(MT_MAC_BSSID_DW1_MBSS_MODE, 3) | /* 8 APs + 8 STAs */ | |
632 | MT_MAC_BSSID_DW1_MBSS_LOCAL_BIT); | |
633 | ||
634 | for (i = 0; i < 16; i++) | |
635 | mt76x02_mac_set_bssid(dev, i, null_addr); | |
89a8607c LB |
636 | } |
637 | EXPORT_SYMBOL_GPL(mt76x02_mac_setaddr); | |
d9f8934e LB |
638 | |
639 | static int | |
640 | mt76x02_mac_get_rssi(struct mt76x02_dev *dev, s8 rssi, int chain) | |
641 | { | |
642 | struct mt76x02_rx_freq_cal *cal = &dev->cal.rx; | |
643 | ||
644 | rssi += cal->rssi_offset[chain]; | |
645 | rssi -= cal->lna_gain; | |
646 | ||
647 | return rssi; | |
648 | } | |
649 | ||
650 | int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, | |
651 | void *rxi) | |
652 | { | |
653 | struct mt76_rx_status *status = (struct mt76_rx_status *) skb->cb; | |
654 | struct mt76x02_rxwi *rxwi = rxi; | |
655 | struct mt76x02_sta *sta; | |
656 | u32 rxinfo = le32_to_cpu(rxwi->rxinfo); | |
657 | u32 ctl = le32_to_cpu(rxwi->ctl); | |
658 | u16 rate = le16_to_cpu(rxwi->rate); | |
659 | u16 tid_sn = le16_to_cpu(rxwi->tid_sn); | |
660 | bool unicast = rxwi->rxinfo & cpu_to_le32(MT_RXINFO_UNICAST); | |
9f688473 | 661 | int pad_len = 0, nstreams = dev->mt76.chainmask & 0xf; |
d9f8934e LB |
662 | s8 signal; |
663 | u8 pn_len; | |
664 | u8 wcid; | |
665 | int len; | |
666 | ||
667 | if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) | |
668 | return -EINVAL; | |
669 | ||
670 | if (rxinfo & MT_RXINFO_L2PAD) | |
671 | pad_len += 2; | |
672 | ||
673 | if (rxinfo & MT_RXINFO_DECRYPT) { | |
674 | status->flag |= RX_FLAG_DECRYPTED; | |
675 | status->flag |= RX_FLAG_MMIC_STRIPPED; | |
676 | status->flag |= RX_FLAG_MIC_STRIPPED; | |
677 | status->flag |= RX_FLAG_IV_STRIPPED; | |
678 | } | |
679 | ||
680 | wcid = FIELD_GET(MT_RXWI_CTL_WCID, ctl); | |
681 | sta = mt76x02_rx_get_sta(&dev->mt76, wcid); | |
682 | status->wcid = mt76x02_rx_get_sta_wcid(sta, unicast); | |
683 | ||
684 | len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); | |
685 | pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); | |
686 | if (pn_len) { | |
687 | int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len; | |
688 | u8 *data = skb->data + offset; | |
689 | ||
690 | status->iv[0] = data[7]; | |
691 | status->iv[1] = data[6]; | |
692 | status->iv[2] = data[5]; | |
693 | status->iv[3] = data[4]; | |
694 | status->iv[4] = data[1]; | |
695 | status->iv[5] = data[0]; | |
696 | ||
697 | /* | |
698 | * Driver CCMP validation can't deal with fragments. | |
699 | * Let mac80211 take care of it. | |
700 | */ | |
701 | if (rxinfo & MT_RXINFO_FRAG) { | |
702 | status->flag &= ~RX_FLAG_IV_STRIPPED; | |
703 | } else { | |
704 | pad_len += pn_len << 2; | |
705 | len -= pn_len << 2; | |
706 | } | |
707 | } | |
708 | ||
709 | mt76x02_remove_hdr_pad(skb, pad_len); | |
710 | ||
711 | if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) | |
712 | status->aggr = true; | |
713 | ||
714 | if (WARN_ON_ONCE(len > skb->len)) | |
715 | return -EINVAL; | |
716 | ||
717 | pskb_trim(skb, len); | |
718 | ||
719 | status->chains = BIT(0); | |
720 | signal = mt76x02_mac_get_rssi(dev, rxwi->rssi[0], 0); | |
9f688473 FF |
721 | status->chain_signal[0] = signal; |
722 | if (nstreams > 1) { | |
723 | status->chains |= BIT(1); | |
724 | status->chain_signal[1] = mt76x02_mac_get_rssi(dev, | |
725 | rxwi->rssi[1], | |
726 | 1); | |
727 | signal = max_t(s8, signal, status->chain_signal[1]); | |
d9f8934e LB |
728 | } |
729 | status->signal = signal; | |
730 | status->freq = dev->mt76.chandef.chan->center_freq; | |
731 | status->band = dev->mt76.chandef.chan->band; | |
732 | ||
733 | status->tid = FIELD_GET(MT_RXWI_TID, tid_sn); | |
734 | status->seqno = FIELD_GET(MT_RXWI_SN, tid_sn); | |
735 | ||
f832898d | 736 | return mt76x02_mac_process_rate(dev, status, rate); |
d9f8934e | 737 | } |
3e2342ed LB |
738 | |
739 | void mt76x02_mac_poll_tx_status(struct mt76x02_dev *dev, bool irq) | |
740 | { | |
741 | struct mt76x02_tx_status stat = {}; | |
3e2342ed LB |
742 | u8 update = 1; |
743 | bool ret; | |
744 | ||
745 | if (!test_bit(MT76_STATE_RUNNING, &dev->mt76.state)) | |
746 | return; | |
747 | ||
748 | trace_mac_txstat_poll(dev); | |
749 | ||
750 | while (!irq || !kfifo_is_full(&dev->txstatus_fifo)) { | |
6fe53337 FF |
751 | if (!spin_trylock(&dev->txstatus_fifo_lock)) |
752 | break; | |
753 | ||
8d66af49 | 754 | ret = mt76x02_mac_load_tx_status(dev, &stat); |
6fe53337 | 755 | spin_unlock(&dev->txstatus_fifo_lock); |
3e2342ed LB |
756 | |
757 | if (!ret) | |
758 | break; | |
759 | ||
3e2342ed | 760 | if (!irq) { |
8d66af49 | 761 | mt76x02_send_tx_status(dev, &stat, &update); |
3e2342ed LB |
762 | continue; |
763 | } | |
764 | ||
765 | kfifo_put(&dev->txstatus_fifo, stat); | |
766 | } | |
767 | } | |
466495b1 | 768 | |
e226ba2e LB |
769 | void mt76x02_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid, |
770 | struct mt76_queue_entry *e) | |
466495b1 LB |
771 | { |
772 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); | |
88046b2c | 773 | struct mt76x02_txwi *txwi; |
f3950a41 | 774 | u8 *txwi_ptr; |
466495b1 | 775 | |
88046b2c | 776 | if (!e->txwi) { |
466495b1 | 777 | dev_kfree_skb_any(e->skb); |
88046b2c FF |
778 | return; |
779 | } | |
780 | ||
781 | mt76x02_mac_poll_tx_status(dev, false); | |
782 | ||
f3950a41 LB |
783 | txwi_ptr = mt76_get_txwi_ptr(mdev, e->txwi); |
784 | txwi = (struct mt76x02_txwi *)txwi_ptr; | |
88046b2c FF |
785 | trace_mac_txdone_add(dev, txwi->wcid, txwi->pktid); |
786 | ||
787 | mt76_tx_complete_skb(mdev, e->skb); | |
466495b1 LB |
788 | } |
789 | EXPORT_SYMBOL_GPL(mt76x02_tx_complete_skb); | |
62503186 | 790 | |
20ce270e | 791 | void mt76x02_mac_set_rts_thresh(struct mt76x02_dev *dev, u32 val) |
317ed42b LB |
792 | { |
793 | u32 data = 0; | |
794 | ||
795 | if (val != ~0) | |
796 | data = FIELD_PREP(MT_PROT_CFG_CTRL, 1) | | |
797 | MT_PROT_CFG_RTS_THRESH; | |
798 | ||
799 | mt76_rmw_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH, val); | |
800 | ||
801 | mt76_rmw(dev, MT_CCK_PROT_CFG, | |
802 | MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); | |
803 | mt76_rmw(dev, MT_OFDM_PROT_CFG, | |
804 | MT_PROT_CFG_CTRL | MT_PROT_CFG_RTS_THRESH, data); | |
317ed42b LB |
805 | } |
806 | ||
26a7b547 SG |
807 | void mt76x02_mac_set_tx_protection(struct mt76x02_dev *dev, bool legacy_prot, |
808 | int ht_mode) | |
809 | { | |
810 | int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; | |
811 | bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); | |
812 | u32 prot[6]; | |
813 | u32 vht_prot[3]; | |
814 | int i; | |
815 | u16 rts_thr; | |
816 | ||
817 | for (i = 0; i < ARRAY_SIZE(prot); i++) { | |
818 | prot[i] = mt76_rr(dev, MT_CCK_PROT_CFG + i * 4); | |
819 | prot[i] &= ~MT_PROT_CFG_CTRL; | |
820 | if (i >= 2) | |
821 | prot[i] &= ~MT_PROT_CFG_RATE; | |
822 | } | |
823 | ||
824 | for (i = 0; i < ARRAY_SIZE(vht_prot); i++) { | |
825 | vht_prot[i] = mt76_rr(dev, MT_TX_PROT_CFG6 + i * 4); | |
826 | vht_prot[i] &= ~(MT_PROT_CFG_CTRL | MT_PROT_CFG_RATE); | |
827 | } | |
828 | ||
829 | rts_thr = mt76_get_field(dev, MT_TX_RTS_CFG, MT_TX_RTS_CFG_THRESH); | |
830 | ||
831 | if (rts_thr != 0xffff) | |
832 | prot[0] |= MT_PROT_CTRL_RTS_CTS; | |
833 | ||
834 | if (legacy_prot) { | |
835 | prot[1] |= MT_PROT_CTRL_CTS2SELF; | |
836 | ||
837 | prot[2] |= MT_PROT_RATE_CCK_11; | |
838 | prot[3] |= MT_PROT_RATE_CCK_11; | |
839 | prot[4] |= MT_PROT_RATE_CCK_11; | |
840 | prot[5] |= MT_PROT_RATE_CCK_11; | |
841 | ||
842 | vht_prot[0] |= MT_PROT_RATE_CCK_11; | |
843 | vht_prot[1] |= MT_PROT_RATE_CCK_11; | |
844 | vht_prot[2] |= MT_PROT_RATE_CCK_11; | |
845 | } else { | |
846 | if (rts_thr != 0xffff) | |
847 | prot[1] |= MT_PROT_CTRL_RTS_CTS; | |
848 | ||
849 | prot[2] |= MT_PROT_RATE_OFDM_24; | |
850 | prot[3] |= MT_PROT_RATE_DUP_OFDM_24; | |
851 | prot[4] |= MT_PROT_RATE_OFDM_24; | |
852 | prot[5] |= MT_PROT_RATE_DUP_OFDM_24; | |
853 | ||
854 | vht_prot[0] |= MT_PROT_RATE_OFDM_24; | |
855 | vht_prot[1] |= MT_PROT_RATE_DUP_OFDM_24; | |
856 | vht_prot[2] |= MT_PROT_RATE_SGI_OFDM_24; | |
857 | } | |
858 | ||
859 | switch (mode) { | |
860 | case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: | |
861 | case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: | |
862 | prot[2] |= MT_PROT_CTRL_RTS_CTS; | |
863 | prot[3] |= MT_PROT_CTRL_RTS_CTS; | |
864 | prot[4] |= MT_PROT_CTRL_RTS_CTS; | |
865 | prot[5] |= MT_PROT_CTRL_RTS_CTS; | |
866 | vht_prot[0] |= MT_PROT_CTRL_RTS_CTS; | |
867 | vht_prot[1] |= MT_PROT_CTRL_RTS_CTS; | |
868 | vht_prot[2] |= MT_PROT_CTRL_RTS_CTS; | |
869 | break; | |
870 | case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: | |
871 | prot[3] |= MT_PROT_CTRL_RTS_CTS; | |
872 | prot[5] |= MT_PROT_CTRL_RTS_CTS; | |
873 | vht_prot[1] |= MT_PROT_CTRL_RTS_CTS; | |
874 | vht_prot[2] |= MT_PROT_CTRL_RTS_CTS; | |
875 | break; | |
876 | } | |
877 | ||
878 | if (non_gf) { | |
879 | prot[4] |= MT_PROT_CTRL_RTS_CTS; | |
880 | prot[5] |= MT_PROT_CTRL_RTS_CTS; | |
881 | } | |
882 | ||
883 | for (i = 0; i < ARRAY_SIZE(prot); i++) | |
884 | mt76_wr(dev, MT_CCK_PROT_CFG + i * 4, prot[i]); | |
885 | ||
886 | for (i = 0; i < ARRAY_SIZE(vht_prot); i++) | |
887 | mt76_wr(dev, MT_TX_PROT_CFG6 + i * 4, vht_prot[i]); | |
888 | } | |
889 | ||
62503186 LB |
890 | void mt76x02_update_channel(struct mt76_dev *mdev) |
891 | { | |
892 | struct mt76x02_dev *dev = container_of(mdev, struct mt76x02_dev, mt76); | |
893 | struct mt76_channel_state *state; | |
894 | u32 active, busy; | |
895 | ||
896 | state = mt76_channel_state(&dev->mt76, dev->mt76.chandef.chan); | |
897 | ||
898 | busy = mt76_rr(dev, MT_CH_BUSY); | |
899 | active = busy + mt76_rr(dev, MT_CH_IDLE); | |
900 | ||
901 | spin_lock_bh(&dev->mt76.cc_lock); | |
902 | state->cc_busy += busy; | |
903 | state->cc_active += active; | |
904 | spin_unlock_bh(&dev->mt76.cc_lock); | |
905 | } | |
906 | EXPORT_SYMBOL_GPL(mt76x02_update_channel); | |
7dd73588 | 907 | |
73556561 LB |
908 | static void mt76x02_check_mac_err(struct mt76x02_dev *dev) |
909 | { | |
910 | u32 val = mt76_rr(dev, 0x10f4); | |
911 | ||
912 | if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) | |
913 | return; | |
914 | ||
915 | dev_err(dev->mt76.dev, "mac specific condition occurred\n"); | |
916 | ||
917 | mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); | |
918 | udelay(10); | |
374eb1b5 LB |
919 | mt76_wr(dev, MT_MAC_SYS_CTRL, |
920 | MT_MAC_SYS_CTRL_ENABLE_TX | MT_MAC_SYS_CTRL_ENABLE_RX); | |
73556561 LB |
921 | } |
922 | ||
f82ce8d9 LB |
923 | static void |
924 | mt76x02_edcca_tx_enable(struct mt76x02_dev *dev, bool enable) | |
925 | { | |
926 | if (enable) { | |
927 | u32 data; | |
928 | ||
929 | mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); | |
930 | mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN); | |
931 | /* enable pa-lna */ | |
932 | data = mt76_rr(dev, MT_TX_PIN_CFG); | |
933 | data |= MT_TX_PIN_CFG_TXANT | | |
934 | MT_TX_PIN_CFG_RXANT | | |
935 | MT_TX_PIN_RFTR_EN | | |
936 | MT_TX_PIN_TRSW_EN; | |
937 | mt76_wr(dev, MT_TX_PIN_CFG, data); | |
938 | } else { | |
939 | mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_ENABLE_TX); | |
940 | mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_EN); | |
941 | /* disable pa-lna */ | |
942 | mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_TXANT); | |
943 | mt76_clear(dev, MT_TX_PIN_CFG, MT_TX_PIN_CFG_RXANT); | |
944 | } | |
945 | dev->ed_tx_blocked = !enable; | |
946 | } | |
947 | ||
20c06572 | 948 | void mt76x02_edcca_init(struct mt76x02_dev *dev, bool enable) |
f82ce8d9 LB |
949 | { |
950 | dev->ed_trigger = 0; | |
951 | dev->ed_silent = 0; | |
952 | ||
20c06572 | 953 | if (dev->ed_monitor && enable) { |
f82ce8d9 LB |
954 | struct ieee80211_channel *chan = dev->mt76.chandef.chan; |
955 | u8 ed_th = chan->band == NL80211_BAND_5GHZ ? 0x0e : 0x20; | |
956 | ||
957 | mt76_clear(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN); | |
958 | mt76_set(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); | |
959 | mt76_rmw(dev, MT_BBP(AGC, 2), GENMASK(15, 0), | |
960 | ed_th << 8 | ed_th); | |
5c8b0a33 | 961 | mt76_set(dev, MT_TXOP_HLDR_ET, MT_TXOP_HLDR_TX40M_BLK_EN); |
f82ce8d9 LB |
962 | } else { |
963 | mt76_set(dev, MT_TX_LINK_CFG, MT_TX_CFACK_EN); | |
964 | mt76_clear(dev, MT_TXOP_CTRL_CFG, MT_TXOP_ED_CCA_EN); | |
965 | if (is_mt76x2(dev)) { | |
966 | mt76_wr(dev, MT_BBP(AGC, 2), 0x00007070); | |
5c8b0a33 FF |
967 | mt76_set(dev, MT_TXOP_HLDR_ET, |
968 | MT_TXOP_HLDR_TX40M_BLK_EN); | |
f82ce8d9 LB |
969 | } else { |
970 | mt76_wr(dev, MT_BBP(AGC, 2), 0x003a6464); | |
971 | mt76_clear(dev, MT_TXOP_HLDR_ET, | |
972 | MT_TXOP_HLDR_TX40M_BLK_EN); | |
973 | } | |
974 | } | |
975 | mt76x02_edcca_tx_enable(dev, true); | |
a0ac8061 | 976 | dev->ed_monitor_learning = true; |
c15b7cef FF |
977 | |
978 | /* clear previous CCA timer value */ | |
979 | mt76_rr(dev, MT_ED_CCA_TIMER); | |
ccdaf7b4 | 980 | dev->ed_time = ktime_get_boottime(); |
f82ce8d9 LB |
981 | } |
982 | EXPORT_SYMBOL_GPL(mt76x02_edcca_init); | |
983 | ||
f1906fb2 | 984 | #define MT_EDCCA_TH 92 |
f82ce8d9 | 985 | #define MT_EDCCA_BLOCK_TH 2 |
a0ac8061 FF |
986 | #define MT_EDCCA_LEARN_TH 50 |
987 | #define MT_EDCCA_LEARN_CCA 180 | |
988 | #define MT_EDCCA_LEARN_TIMEOUT (20 * HZ) | |
989 | ||
f82ce8d9 LB |
990 | static void mt76x02_edcca_check(struct mt76x02_dev *dev) |
991 | { | |
ccdaf7b4 FF |
992 | ktime_t cur_time; |
993 | u32 active, val, busy; | |
f82ce8d9 | 994 | |
ccdaf7b4 | 995 | cur_time = ktime_get_boottime(); |
f82ce8d9 | 996 | val = mt76_rr(dev, MT_ED_CCA_TIMER); |
ccdaf7b4 FF |
997 | |
998 | active = ktime_to_us(ktime_sub(cur_time, dev->ed_time)); | |
999 | dev->ed_time = cur_time; | |
1000 | ||
1001 | busy = (val * 100) / active; | |
f82ce8d9 LB |
1002 | busy = min_t(u32, busy, 100); |
1003 | ||
1004 | if (busy > MT_EDCCA_TH) { | |
1005 | dev->ed_trigger++; | |
1006 | dev->ed_silent = 0; | |
1007 | } else { | |
1008 | dev->ed_silent++; | |
1009 | dev->ed_trigger = 0; | |
1010 | } | |
1011 | ||
a0ac8061 FF |
1012 | if (dev->cal.agc_lowest_gain && |
1013 | dev->cal.false_cca > MT_EDCCA_LEARN_CCA && | |
1014 | dev->ed_trigger > MT_EDCCA_LEARN_TH) { | |
1015 | dev->ed_monitor_learning = false; | |
1016 | dev->ed_trigger_timeout = jiffies + 20 * HZ; | |
1017 | } else if (!dev->ed_monitor_learning && | |
1018 | time_is_after_jiffies(dev->ed_trigger_timeout)) { | |
1019 | dev->ed_monitor_learning = true; | |
1020 | mt76x02_edcca_tx_enable(dev, true); | |
1021 | } | |
1022 | ||
1023 | if (dev->ed_monitor_learning) | |
1024 | return; | |
1025 | ||
1026 | if (dev->ed_trigger > MT_EDCCA_BLOCK_TH && !dev->ed_tx_blocked) | |
f82ce8d9 | 1027 | mt76x02_edcca_tx_enable(dev, false); |
a0ac8061 | 1028 | else if (dev->ed_silent > MT_EDCCA_BLOCK_TH && dev->ed_tx_blocked) |
f82ce8d9 LB |
1029 | mt76x02_edcca_tx_enable(dev, true); |
1030 | } | |
1031 | ||
7dd73588 LB |
1032 | void mt76x02_mac_work(struct work_struct *work) |
1033 | { | |
1034 | struct mt76x02_dev *dev = container_of(work, struct mt76x02_dev, | |
37426fb6 | 1035 | mt76.mac_work.work); |
7dd73588 LB |
1036 | int i, idx; |
1037 | ||
4989338e LB |
1038 | mutex_lock(&dev->mt76.mutex); |
1039 | ||
7dd73588 LB |
1040 | mt76x02_update_channel(&dev->mt76); |
1041 | for (i = 0, idx = 0; i < 16; i++) { | |
1042 | u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); | |
1043 | ||
1044 | dev->aggr_stats[idx++] += val & 0xffff; | |
1045 | dev->aggr_stats[idx++] += val >> 16; | |
1046 | } | |
1047 | ||
c8a04d98 | 1048 | if (!dev->mt76.beacon_mask) |
73556561 LB |
1049 | mt76x02_check_mac_err(dev); |
1050 | ||
f82ce8d9 LB |
1051 | if (dev->ed_monitor) |
1052 | mt76x02_edcca_check(dev); | |
1053 | ||
4989338e LB |
1054 | mutex_unlock(&dev->mt76.mutex); |
1055 | ||
79d1c94c | 1056 | mt76_tx_status_check(&dev->mt76, NULL, false); |
88046b2c | 1057 | |
37426fb6 | 1058 | ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work, |
2e405024 | 1059 | MT_MAC_WORK_INTERVAL); |
7dd73588 | 1060 | } |
dc33b251 LB |
1061 | |
1062 | void mt76x02_mac_set_bssid(struct mt76x02_dev *dev, u8 idx, const u8 *addr) | |
1063 | { | |
1064 | idx &= 7; | |
1065 | mt76_wr(dev, MT_MAC_APC_BSSID_L(idx), get_unaligned_le32(addr)); | |
1066 | mt76_rmw_field(dev, MT_MAC_APC_BSSID_H(idx), MT_MAC_APC_BSSID_H_ADDR, | |
1067 | get_unaligned_le16(addr + 4)); | |
1068 | } |