1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org> |
4 | * Copyright (C) 2015 Jakub Kicinski <kubakici@wp.pl> |
5 | */ |
6 | |
7 | #include "mt7601u.h" |
8 | #include "trace.h" |
9 | #include <linux/etherdevice.h> |
10 | |
11 | void mt7601u_set_macaddr(struct mt7601u_dev *dev, const u8 *addr) |
12 | { |
13 | ether_addr_copy(dst: dev->macaddr, src: addr); |
14 | |
15 | if (!is_valid_ether_addr(addr: dev->macaddr)) { |
16 | eth_random_addr(addr: dev->macaddr); |
17 | dev_info(dev->dev, |
18 | "Invalid MAC address, using random address %pM\n" , |
19 | dev->macaddr); |
20 | } |
21 | |
22 | mt76_wr(dev, MT_MAC_ADDR_DW0, val: get_unaligned_le32(p: dev->macaddr)); |
23 | mt76_wr(dev, MT_MAC_ADDR_DW1, val: get_unaligned_le16(p: dev->macaddr + 4) | |
24 | FIELD_PREP(MT_MAC_ADDR_DW1_U2ME_MASK, 0xff)); |
25 | } |
26 | |
27 | static void |
28 | mt76_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate) |
29 | { |
30 | u8 idx = FIELD_GET(MT_TXWI_RATE_MCS, rate); |
31 | |
32 | txrate->idx = 0; |
33 | txrate->flags = 0; |
34 | txrate->count = 1; |
35 | |
36 | switch (FIELD_GET(MT_TXWI_RATE_PHY_MODE, rate)) { |
37 | case MT_PHY_TYPE_OFDM: |
38 | txrate->idx = idx + 4; |
39 | return; |
40 | case MT_PHY_TYPE_CCK: |
41 | if (idx >= 8) |
42 | idx -= 8; |
43 | |
44 | txrate->idx = idx; |
45 | return; |
46 | case MT_PHY_TYPE_HT_GF: |
47 | txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; |
48 | fallthrough; |
49 | case MT_PHY_TYPE_HT: |
50 | txrate->flags |= IEEE80211_TX_RC_MCS; |
51 | txrate->idx = idx; |
52 | break; |
53 | default: |
54 | WARN_ON(1); |
55 | return; |
56 | } |
57 | |
58 | if (FIELD_GET(MT_TXWI_RATE_BW, rate) == MT_PHY_BW_40) |
59 | txrate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; |
60 | |
61 | if (rate & MT_TXWI_RATE_SGI) |
62 | txrate->flags |= IEEE80211_TX_RC_SHORT_GI; |
63 | } |
64 | |
65 | static void |
66 | mt76_mac_fill_tx_status(struct mt7601u_dev *dev, struct ieee80211_tx_info *info, |
67 | struct mt76_tx_status *st) |
68 | { |
69 | struct ieee80211_tx_rate *rate = info->status.rates; |
70 | int cur_idx, last_rate; |
71 | int i; |
72 | |
73 | last_rate = min_t(int, st->retry, IEEE80211_TX_MAX_RATES - 1); |
74 | mt76_mac_process_tx_rate(txrate: &rate[last_rate], rate: st->rate); |
75 | if (last_rate < IEEE80211_TX_MAX_RATES - 1) |
76 | rate[last_rate + 1].idx = -1; |
77 | |
78 | cur_idx = rate[last_rate].idx + st->retry; |
79 | for (i = 0; i <= last_rate; i++) { |
80 | rate[i].flags = rate[last_rate].flags; |
81 | rate[i].idx = max_t(int, 0, cur_idx - i); |
82 | rate[i].count = 1; |
83 | } |
84 | |
85 | if (last_rate > 0) |
86 | rate[last_rate - 1].count = st->retry + 1 - last_rate; |
87 | |
88 | info->status.ampdu_len = 1; |
89 | info->status.ampdu_ack_len = st->success; |
90 | |
91 | if (st->is_probe) |
92 | info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; |
93 | |
94 | if (st->aggr) |
95 | info->flags |= IEEE80211_TX_CTL_AMPDU | |
96 | IEEE80211_TX_STAT_AMPDU; |
97 | |
98 | if (!st->ack_req) |
99 | info->flags |= IEEE80211_TX_CTL_NO_ACK; |
100 | else if (st->success) |
101 | info->flags |= IEEE80211_TX_STAT_ACK; |
102 | } |
103 | |
104 | u16 mt76_mac_tx_rate_val(struct mt7601u_dev *dev, |
105 | const struct ieee80211_tx_rate *rate, u8 *nss_val) |
106 | { |
107 | u16 rateval; |
108 | u8 phy, rate_idx; |
109 | u8 nss = 1; |
110 | u8 bw = 0; |
111 | |
112 | if (rate->flags & IEEE80211_TX_RC_MCS) { |
113 | rate_idx = rate->idx; |
114 | nss = 1 + (rate->idx >> 3); |
115 | phy = MT_PHY_TYPE_HT; |
116 | if (rate->flags & IEEE80211_TX_RC_GREEN_FIELD) |
117 | phy = MT_PHY_TYPE_HT_GF; |
118 | if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) |
119 | bw = 1; |
120 | } else { |
121 | const struct ieee80211_rate *r; |
122 | int band = dev->chandef.chan->band; |
123 | u16 val; |
124 | |
125 | r = &dev->hw->wiphy->bands[band]->bitrates[rate->idx]; |
126 | if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) |
127 | val = r->hw_value_short; |
128 | else |
129 | val = r->hw_value; |
130 | |
131 | phy = val >> 8; |
132 | rate_idx = val & 0xff; |
133 | bw = 0; |
134 | } |
135 | |
136 | rateval = FIELD_PREP(MT_RXWI_RATE_MCS, rate_idx); |
137 | rateval |= FIELD_PREP(MT_RXWI_RATE_PHY, phy); |
138 | rateval |= FIELD_PREP(MT_RXWI_RATE_BW, bw); |
139 | if (rate->flags & IEEE80211_TX_RC_SHORT_GI) |
140 | rateval |= MT_RXWI_RATE_SGI; |
141 | |
142 | *nss_val = nss; |
143 | return rateval; |
144 | } |
145 | |
146 | void mt76_mac_wcid_set_rate(struct mt7601u_dev *dev, struct mt76_wcid *wcid, |
147 | const struct ieee80211_tx_rate *rate) |
148 | { |
149 | unsigned long flags; |
150 | |
151 | spin_lock_irqsave(&dev->lock, flags); |
152 | wcid->tx_rate = mt76_mac_tx_rate_val(dev, rate, nss_val: &wcid->tx_rate_nss); |
153 | wcid->tx_rate_set = true; |
154 | spin_unlock_irqrestore(lock: &dev->lock, flags); |
155 | } |
156 | |
157 | struct mt76_tx_status mt7601u_mac_fetch_tx_status(struct mt7601u_dev *dev) |
158 | { |
159 | struct mt76_tx_status stat = {}; |
160 | u32 val; |
161 | |
162 | val = mt7601u_rr(dev, MT_TX_STAT_FIFO); |
163 | stat.valid = !!(val & MT_TX_STAT_FIFO_VALID); |
164 | stat.success = !!(val & MT_TX_STAT_FIFO_SUCCESS); |
165 | stat.aggr = !!(val & MT_TX_STAT_FIFO_AGGR); |
166 | stat.ack_req = !!(val & MT_TX_STAT_FIFO_ACKREQ); |
167 | stat.pktid = FIELD_GET(MT_TX_STAT_FIFO_PID_TYPE, val); |
168 | stat.wcid = FIELD_GET(MT_TX_STAT_FIFO_WCID, val); |
169 | stat.rate = FIELD_GET(MT_TX_STAT_FIFO_RATE, val); |
170 | |
171 | return stat; |
172 | } |
173 | |
174 | void mt76_send_tx_status(struct mt7601u_dev *dev, struct mt76_tx_status *stat) |
175 | { |
176 | struct ieee80211_tx_info info = {}; |
177 | struct ieee80211_sta *sta = NULL; |
178 | struct mt76_wcid *wcid = NULL; |
179 | void *msta; |
180 | |
181 | rcu_read_lock(); |
182 | if (stat->wcid < ARRAY_SIZE(dev->wcid)) |
183 | wcid = rcu_dereference(dev->wcid[stat->wcid]); |
184 | |
185 | if (wcid) { |
186 | msta = container_of(wcid, struct mt76_sta, wcid); |
187 | sta = container_of(msta, struct ieee80211_sta, |
188 | drv_priv); |
189 | } |
190 | |
191 | mt76_mac_fill_tx_status(dev, info: &info, st: stat); |
192 | |
193 | spin_lock_bh(lock: &dev->mac_lock); |
194 | ieee80211_tx_status_noskb(hw: dev->hw, sta, info: &info); |
195 | spin_unlock_bh(lock: &dev->mac_lock); |
196 | |
197 | rcu_read_unlock(); |
198 | } |
199 | |
200 | void mt7601u_mac_set_protection(struct mt7601u_dev *dev, bool legacy_prot, |
201 | int ht_mode) |
202 | { |
203 | int mode = ht_mode & IEEE80211_HT_OP_MODE_PROTECTION; |
204 | bool non_gf = !!(ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); |
205 | u32 prot[6]; |
206 | bool ht_rts[4] = {}; |
207 | int i; |
208 | |
209 | prot[0] = MT_PROT_NAV_SHORT | |
210 | MT_PROT_TXOP_ALLOW_ALL | |
211 | MT_PROT_RTS_THR_EN; |
212 | prot[1] = prot[0]; |
213 | if (legacy_prot) |
214 | prot[1] |= MT_PROT_CTRL_CTS2SELF; |
215 | |
216 | prot[2] = prot[4] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_BW20; |
217 | prot[3] = prot[5] = MT_PROT_NAV_SHORT | MT_PROT_TXOP_ALLOW_ALL; |
218 | |
219 | if (legacy_prot) { |
220 | prot[2] |= MT_PROT_RATE_CCK_11; |
221 | prot[3] |= MT_PROT_RATE_CCK_11; |
222 | prot[4] |= MT_PROT_RATE_CCK_11; |
223 | prot[5] |= MT_PROT_RATE_CCK_11; |
224 | } else { |
225 | prot[2] |= MT_PROT_RATE_OFDM_24; |
226 | prot[3] |= MT_PROT_RATE_DUP_OFDM_24; |
227 | prot[4] |= MT_PROT_RATE_OFDM_24; |
228 | prot[5] |= MT_PROT_RATE_DUP_OFDM_24; |
229 | } |
230 | |
231 | switch (mode) { |
232 | case IEEE80211_HT_OP_MODE_PROTECTION_NONE: |
233 | break; |
234 | |
235 | case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: |
236 | ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; |
237 | break; |
238 | |
239 | case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: |
240 | ht_rts[1] = ht_rts[3] = true; |
241 | break; |
242 | |
243 | case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: |
244 | ht_rts[0] = ht_rts[1] = ht_rts[2] = ht_rts[3] = true; |
245 | break; |
246 | } |
247 | |
248 | if (non_gf) |
249 | ht_rts[2] = ht_rts[3] = true; |
250 | |
251 | for (i = 0; i < 4; i++) |
252 | if (ht_rts[i]) |
253 | prot[i + 2] |= MT_PROT_CTRL_RTS_CTS; |
254 | |
255 | for (i = 0; i < 6; i++) |
256 | mt7601u_wr(dev, MT_CCK_PROT_CFG + i * 4, val: prot[i]); |
257 | } |
258 | |
259 | void mt7601u_mac_set_short_preamble(struct mt7601u_dev *dev, bool short_preamb) |
260 | { |
261 | if (short_preamb) |
262 | mt76_set(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); |
263 | else |
264 | mt76_clear(dev, MT_AUTO_RSP_CFG, MT_AUTO_RSP_PREAMB_SHORT); |
265 | } |
266 | |
267 | void mt7601u_mac_config_tsf(struct mt7601u_dev *dev, bool enable, int interval) |
268 | { |
269 | u32 val = mt7601u_rr(dev, MT_BEACON_TIME_CFG); |
270 | |
271 | val &= ~(MT_BEACON_TIME_CFG_TIMER_EN | |
272 | MT_BEACON_TIME_CFG_SYNC_MODE | |
273 | MT_BEACON_TIME_CFG_TBTT_EN); |
274 | |
275 | if (!enable) { |
276 | mt7601u_wr(dev, MT_BEACON_TIME_CFG, val); |
277 | return; |
278 | } |
279 | |
280 | val &= ~MT_BEACON_TIME_CFG_INTVAL; |
281 | val |= FIELD_PREP(MT_BEACON_TIME_CFG_INTVAL, interval << 4) | |
282 | MT_BEACON_TIME_CFG_TIMER_EN | |
283 | MT_BEACON_TIME_CFG_SYNC_MODE | |
284 | MT_BEACON_TIME_CFG_TBTT_EN; |
285 | } |
286 | |
287 | static void mt7601u_check_mac_err(struct mt7601u_dev *dev) |
288 | { |
289 | u32 val = mt7601u_rr(dev, offset: 0x10f4); |
290 | |
291 | if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5)))) |
292 | return; |
293 | |
294 | dev_err(dev->dev, "Error: MAC specific condition occurred\n" ); |
295 | |
296 | mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); |
297 | udelay(10); |
298 | mt76_clear(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR); |
299 | } |
300 | |
301 | void mt7601u_mac_work(struct work_struct *work) |
302 | { |
303 | struct mt7601u_dev *dev = container_of(work, struct mt7601u_dev, |
304 | mac_work.work); |
305 | struct { |
306 | u32 addr_base; |
307 | u32 span; |
308 | u64 *stat_base; |
309 | } spans[] = { |
310 | { MT_RX_STA_CNT0, 3, dev->stats.rx_stat }, |
311 | { MT_TX_STA_CNT0, 3, dev->stats.tx_stat }, |
312 | { MT_TX_AGG_STAT, 1, dev->stats.aggr_stat }, |
313 | { MT_MPDU_DENSITY_CNT, 1, dev->stats.zero_len_del }, |
314 | { MT_TX_AGG_CNT_BASE0, 8, &dev->stats.aggr_n[0] }, |
315 | { MT_TX_AGG_CNT_BASE1, 8, &dev->stats.aggr_n[16] }, |
316 | }; |
317 | u32 sum, n; |
318 | int i, j, k; |
319 | |
320 | /* Note: using MCU_RANDOM_READ is actually slower then reading all the |
321 | * registers by hand. MCU takes ca. 20ms to complete read of 24 |
322 | * registers while reading them one by one will takes roughly |
323 | * 24*200us =~ 5ms. |
324 | */ |
325 | |
326 | k = 0; |
327 | n = 0; |
328 | sum = 0; |
329 | for (i = 0; i < ARRAY_SIZE(spans); i++) |
330 | for (j = 0; j < spans[i].span; j++) { |
331 | u32 val = mt7601u_rr(dev, offset: spans[i].addr_base + j * 4); |
332 | |
333 | spans[i].stat_base[j * 2] += val & 0xffff; |
334 | spans[i].stat_base[j * 2 + 1] += val >> 16; |
335 | |
336 | /* Calculate average AMPDU length */ |
337 | if (spans[i].addr_base != MT_TX_AGG_CNT_BASE0 && |
338 | spans[i].addr_base != MT_TX_AGG_CNT_BASE1) |
339 | continue; |
340 | |
341 | n += (val >> 16) + (val & 0xffff); |
342 | sum += (val & 0xffff) * (1 + k * 2) + |
343 | (val >> 16) * (2 + k * 2); |
344 | k++; |
345 | } |
346 | |
347 | atomic_set(v: &dev->avg_ampdu_len, i: n ? DIV_ROUND_CLOSEST(sum, n) : 1); |
348 | |
349 | mt7601u_check_mac_err(dev); |
350 | |
351 | ieee80211_queue_delayed_work(hw: dev->hw, dwork: &dev->mac_work, delay: 10 * HZ); |
352 | } |
353 | |
354 | void |
355 | mt7601u_mac_wcid_setup(struct mt7601u_dev *dev, u8 idx, u8 vif_idx, u8 *mac) |
356 | { |
357 | u8 zmac[ETH_ALEN] = {}; |
358 | u32 attr; |
359 | |
360 | attr = FIELD_PREP(MT_WCID_ATTR_BSS_IDX, vif_idx & 7) | |
361 | FIELD_PREP(MT_WCID_ATTR_BSS_IDX_EXT, !!(vif_idx & 8)); |
362 | |
363 | mt76_wr(dev, MT_WCID_ATTR(idx), val: attr); |
364 | |
365 | if (mac) |
366 | memcpy(zmac, mac, sizeof(zmac)); |
367 | |
368 | mt7601u_addr_wr(dev, MT_WCID_ADDR(idx), addr: zmac); |
369 | } |
370 | |
371 | void mt7601u_mac_set_ampdu_factor(struct mt7601u_dev *dev) |
372 | { |
373 | struct ieee80211_sta *sta; |
374 | struct mt76_wcid *wcid; |
375 | void *msta; |
376 | u8 min_factor = 3; |
377 | int i; |
378 | |
379 | rcu_read_lock(); |
380 | for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { |
381 | wcid = rcu_dereference(dev->wcid[i]); |
382 | if (!wcid) |
383 | continue; |
384 | |
385 | msta = container_of(wcid, struct mt76_sta, wcid); |
386 | sta = container_of(msta, struct ieee80211_sta, drv_priv); |
387 | |
388 | min_factor = min(min_factor, sta->deflink.ht_cap.ampdu_factor); |
389 | } |
390 | rcu_read_unlock(); |
391 | |
392 | mt7601u_wr(dev, MT_MAX_LEN_CFG, val: 0xa0fff | |
393 | FIELD_PREP(MT_MAX_LEN_CFG_AMPDU, min_factor)); |
394 | } |
395 | |
396 | static void |
397 | mt76_mac_process_rate(struct ieee80211_rx_status *status, u16 rate) |
398 | { |
399 | u8 idx = FIELD_GET(MT_RXWI_RATE_MCS, rate); |
400 | |
401 | switch (FIELD_GET(MT_RXWI_RATE_PHY, rate)) { |
402 | case MT_PHY_TYPE_OFDM: |
403 | if (WARN_ON(idx >= 8)) |
404 | idx = 0; |
405 | idx += 4; |
406 | |
407 | status->rate_idx = idx; |
408 | return; |
409 | case MT_PHY_TYPE_CCK: |
410 | if (idx >= 8) { |
411 | idx -= 8; |
412 | status->enc_flags |= RX_ENC_FLAG_SHORTPRE; |
413 | } |
414 | |
415 | if (WARN_ON(idx >= 4)) |
416 | idx = 0; |
417 | |
418 | status->rate_idx = idx; |
419 | return; |
420 | case MT_PHY_TYPE_HT_GF: |
421 | status->enc_flags |= RX_ENC_FLAG_HT_GF; |
422 | fallthrough; |
423 | case MT_PHY_TYPE_HT: |
424 | status->encoding = RX_ENC_HT; |
425 | status->rate_idx = idx; |
426 | break; |
427 | default: |
428 | WARN_ON(1); |
429 | return; |
430 | } |
431 | |
432 | if (rate & MT_RXWI_RATE_SGI) |
433 | status->enc_flags |= RX_ENC_FLAG_SHORT_GI; |
434 | |
435 | if (rate & MT_RXWI_RATE_STBC) |
436 | status->enc_flags |= 1 << RX_ENC_FLAG_STBC_SHIFT; |
437 | |
438 | if (rate & MT_RXWI_RATE_BW) |
439 | status->bw = RATE_INFO_BW_40; |
440 | } |
441 | |
442 | static void |
443 | mt7601u_rx_monitor_beacon(struct mt7601u_dev *dev, struct mt7601u_rxwi *rxwi, |
444 | u16 rate, int ) |
445 | { |
446 | dev->bcn_freq_off = rxwi->freq_off; |
447 | dev->bcn_phy_mode = FIELD_GET(MT_RXWI_RATE_PHY, rate); |
448 | ewma_rssi_add(e: &dev->avg_rssi, val: -rssi); |
449 | } |
450 | |
451 | static int |
452 | mt7601u_rx_is_our_beacon(struct mt7601u_dev *dev, u8 *data) |
453 | { |
454 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)data; |
455 | |
456 | return ieee80211_is_beacon(fc: hdr->frame_control) && |
457 | ether_addr_equal(addr1: hdr->addr2, addr2: dev->ap_bssid); |
458 | } |
459 | |
460 | u32 mt76_mac_process_rx(struct mt7601u_dev *dev, struct sk_buff *skb, |
461 | u8 *data, void *rxi) |
462 | { |
463 | struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); |
464 | struct mt7601u_rxwi *rxwi = rxi; |
465 | u32 len, ctl = le32_to_cpu(rxwi->ctl); |
466 | u16 rate = le16_to_cpu(rxwi->rate); |
467 | int ; |
468 | |
469 | len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); |
470 | if (len < 10) |
471 | return 0; |
472 | |
473 | if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_DECRYPT)) { |
474 | status->flag |= RX_FLAG_DECRYPTED; |
475 | status->flag |= RX_FLAG_MMIC_STRIPPED; |
476 | status->flag |= RX_FLAG_MIC_STRIPPED; |
477 | status->flag |= RX_FLAG_ICV_STRIPPED; |
478 | status->flag |= RX_FLAG_IV_STRIPPED; |
479 | } |
480 | /* let mac80211 take care of PN validation since apparently |
481 | * the hardware does not support it |
482 | */ |
483 | if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_PN_LEN)) |
484 | status->flag &= ~RX_FLAG_IV_STRIPPED; |
485 | |
486 | status->chains = BIT(0); |
487 | rssi = mt7601u_phy_get_rssi(dev, rxwi, rate); |
488 | status->chain_signal[0] = status->signal = rssi; |
489 | status->freq = dev->chandef.chan->center_freq; |
490 | status->band = dev->chandef.chan->band; |
491 | |
492 | mt76_mac_process_rate(status, rate); |
493 | |
494 | spin_lock_bh(lock: &dev->con_mon_lock); |
495 | if (mt7601u_rx_is_our_beacon(dev, data)) |
496 | mt7601u_rx_monitor_beacon(dev, rxwi, rate, rssi); |
497 | else if (rxwi->rxinfo & cpu_to_le32(MT_RXINFO_U2M)) |
498 | ewma_rssi_add(e: &dev->avg_rssi, val: -rssi); |
499 | spin_unlock_bh(lock: &dev->con_mon_lock); |
500 | |
501 | return len; |
502 | } |
503 | |
504 | static enum mt76_cipher_type |
505 | mt76_mac_get_key_info(struct ieee80211_key_conf *key, u8 *key_data) |
506 | { |
507 | memset(key_data, 0, 32); |
508 | if (!key) |
509 | return MT_CIPHER_NONE; |
510 | |
511 | if (key->keylen > 32) |
512 | return MT_CIPHER_NONE; |
513 | |
514 | memcpy(key_data, key->key, key->keylen); |
515 | |
516 | switch (key->cipher) { |
517 | case WLAN_CIPHER_SUITE_WEP40: |
518 | return MT_CIPHER_WEP40; |
519 | case WLAN_CIPHER_SUITE_WEP104: |
520 | return MT_CIPHER_WEP104; |
521 | case WLAN_CIPHER_SUITE_TKIP: |
522 | return MT_CIPHER_TKIP; |
523 | case WLAN_CIPHER_SUITE_CCMP: |
524 | return MT_CIPHER_AES_CCMP; |
525 | default: |
526 | return MT_CIPHER_NONE; |
527 | } |
528 | } |
529 | |
530 | int mt76_mac_wcid_set_key(struct mt7601u_dev *dev, u8 idx, |
531 | struct ieee80211_key_conf *key) |
532 | { |
533 | enum mt76_cipher_type cipher; |
534 | u8 key_data[32]; |
535 | u8 iv_data[8]; |
536 | u32 val; |
537 | |
538 | cipher = mt76_mac_get_key_info(key, key_data); |
539 | if (cipher == MT_CIPHER_NONE && key) |
540 | return -EINVAL; |
541 | |
542 | trace_set_key(dev, val: idx); |
543 | |
544 | mt7601u_wr_copy(dev, MT_WCID_KEY(idx), data: key_data, len: sizeof(key_data)); |
545 | |
546 | memset(iv_data, 0, sizeof(iv_data)); |
547 | if (key) { |
548 | iv_data[3] = key->keyidx << 6; |
549 | if (cipher >= MT_CIPHER_TKIP) { |
550 | /* Note: start with 1 to comply with spec, |
551 | * (see comment on common/cmm_wpa.c:4291). |
552 | */ |
553 | iv_data[0] |= 1; |
554 | iv_data[3] |= 0x20; |
555 | } |
556 | } |
557 | mt7601u_wr_copy(dev, MT_WCID_IV(idx), data: iv_data, len: sizeof(iv_data)); |
558 | |
559 | val = mt7601u_rr(dev, MT_WCID_ATTR(idx)); |
560 | val &= ~MT_WCID_ATTR_PKEY_MODE & ~MT_WCID_ATTR_PKEY_MODE_EXT; |
561 | val |= FIELD_PREP(MT_WCID_ATTR_PKEY_MODE, cipher & 7) | |
562 | FIELD_PREP(MT_WCID_ATTR_PKEY_MODE_EXT, cipher >> 3); |
563 | val &= ~MT_WCID_ATTR_PAIRWISE; |
564 | val |= MT_WCID_ATTR_PAIRWISE * |
565 | !!(key && key->flags & IEEE80211_KEY_FLAG_PAIRWISE); |
566 | mt7601u_wr(dev, MT_WCID_ATTR(idx), val); |
567 | |
568 | return 0; |
569 | } |
570 | |
571 | int mt76_mac_shared_key_setup(struct mt7601u_dev *dev, u8 vif_idx, u8 key_idx, |
572 | struct ieee80211_key_conf *key) |
573 | { |
574 | enum mt76_cipher_type cipher; |
575 | u8 key_data[32]; |
576 | u32 val; |
577 | |
578 | cipher = mt76_mac_get_key_info(key, key_data); |
579 | if (cipher == MT_CIPHER_NONE && key) |
580 | return -EINVAL; |
581 | |
582 | trace_set_shared_key(dev, vid: vif_idx, key: key_idx); |
583 | |
584 | mt7601u_wr_copy(dev, MT_SKEY(vif_idx, key_idx), |
585 | data: key_data, len: sizeof(key_data)); |
586 | |
587 | val = mt76_rr(dev, MT_SKEY_MODE(vif_idx)); |
588 | val &= ~(MT_SKEY_MODE_MASK << MT_SKEY_MODE_SHIFT(vif_idx, key_idx)); |
589 | val |= cipher << MT_SKEY_MODE_SHIFT(vif_idx, key_idx); |
590 | mt76_wr(dev, MT_SKEY_MODE(vif_idx), val); |
591 | |
592 | return 0; |
593 | } |
594 | |