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