.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * VHT handling |
---|
3 | 4 | * |
---|
4 | 5 | * Portions of this file |
---|
5 | 6 | * Copyright(c) 2015 - 2016 Intel Deutschland GmbH |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License version 2 as |
---|
9 | | - * published by the Free Software Foundation. |
---|
| 7 | + * Copyright (C) 2018 - 2020 Intel Corporation |
---|
10 | 8 | */ |
---|
11 | 9 | |
---|
12 | 10 | #include <linux/ieee80211.h> |
---|
.. | .. |
---|
231 | 229 | memcpy(&vht_cap->vht_mcs, &vht_cap_ie->supp_mcs, |
---|
232 | 230 | sizeof(struct ieee80211_vht_mcs_info)); |
---|
233 | 231 | |
---|
| 232 | + /* copy EXT_NSS_BW Support value or remove the capability */ |
---|
| 233 | + if (ieee80211_hw_check(&sdata->local->hw, SUPPORTS_VHT_EXT_NSS_BW)) |
---|
| 234 | + vht_cap->cap |= (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK); |
---|
| 235 | + else |
---|
| 236 | + vht_cap->vht_mcs.tx_highest &= |
---|
| 237 | + ~cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE); |
---|
| 238 | + |
---|
234 | 239 | /* but also restrict MCSes */ |
---|
235 | 240 | for (i = 0; i < 8; i++) { |
---|
236 | 241 | u16 own_rx, own_tx, peer_rx, peer_tx; |
---|
.. | .. |
---|
294 | 299 | break; |
---|
295 | 300 | default: |
---|
296 | 301 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; |
---|
| 302 | + |
---|
| 303 | + if (!(vht_cap->vht_mcs.tx_highest & |
---|
| 304 | + cpu_to_le16(IEEE80211_VHT_EXT_NSS_BW_CAPABLE))) |
---|
| 305 | + break; |
---|
| 306 | + |
---|
| 307 | + /* |
---|
| 308 | + * If this is non-zero, then it does support 160 MHz after all, |
---|
| 309 | + * in one form or the other. We don't distinguish here (or even |
---|
| 310 | + * above) between 160 and 80+80 yet. |
---|
| 311 | + */ |
---|
| 312 | + if (cap_info & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) |
---|
| 313 | + sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; |
---|
297 | 314 | } |
---|
298 | 315 | |
---|
299 | 316 | sta->sta.bandwidth = ieee80211_sta_cur_vht_bw(sta); |
---|
300 | | - |
---|
301 | | - /* If HT IE reported 3839 bytes only, stay with that size. */ |
---|
302 | | - if (sta->sta.max_amsdu_len == IEEE80211_MAX_MPDU_LEN_HT_3839) |
---|
303 | | - return; |
---|
304 | 317 | |
---|
305 | 318 | switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { |
---|
306 | 319 | case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: |
---|
.. | .. |
---|
316 | 329 | } |
---|
317 | 330 | } |
---|
318 | 331 | |
---|
| 332 | +/* FIXME: move this to some better location - parses HE now */ |
---|
319 | 333 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cap_rx_bw(struct sta_info *sta) |
---|
320 | 334 | { |
---|
321 | 335 | struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; |
---|
| 336 | + struct ieee80211_sta_he_cap *he_cap = &sta->sta.he_cap; |
---|
322 | 337 | u32 cap_width; |
---|
| 338 | + |
---|
| 339 | + if (he_cap->has_he) { |
---|
| 340 | + u8 info = he_cap->he_cap_elem.phy_cap_info[0]; |
---|
| 341 | + |
---|
| 342 | + if (sta->sdata->vif.bss_conf.chandef.chan->band == |
---|
| 343 | + NL80211_BAND_2GHZ) { |
---|
| 344 | + if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) |
---|
| 345 | + return IEEE80211_STA_RX_BW_40; |
---|
| 346 | + else |
---|
| 347 | + return IEEE80211_STA_RX_BW_20; |
---|
| 348 | + } |
---|
| 349 | + |
---|
| 350 | + if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G || |
---|
| 351 | + info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) |
---|
| 352 | + return IEEE80211_STA_RX_BW_160; |
---|
| 353 | + else if (info & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G) |
---|
| 354 | + return IEEE80211_STA_RX_BW_80; |
---|
| 355 | + |
---|
| 356 | + return IEEE80211_STA_RX_BW_20; |
---|
| 357 | + } |
---|
323 | 358 | |
---|
324 | 359 | if (!vht_cap->vht_supported) |
---|
325 | 360 | return sta->sta.ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? |
---|
.. | .. |
---|
330 | 365 | |
---|
331 | 366 | if (cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ || |
---|
332 | 367 | cap_width == IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) |
---|
| 368 | + return IEEE80211_STA_RX_BW_160; |
---|
| 369 | + |
---|
| 370 | + /* |
---|
| 371 | + * If this is non-zero, then it does support 160 MHz after all, |
---|
| 372 | + * in one form or the other. We don't distinguish here (or even |
---|
| 373 | + * above) between 160 and 80+80 yet. |
---|
| 374 | + */ |
---|
| 375 | + if (vht_cap->cap & IEEE80211_VHT_CAP_EXT_NSS_BW_MASK) |
---|
333 | 376 | return IEEE80211_STA_RX_BW_160; |
---|
334 | 377 | |
---|
335 | 378 | return IEEE80211_STA_RX_BW_80; |
---|
.. | .. |
---|
408 | 451 | } |
---|
409 | 452 | } |
---|
410 | 453 | |
---|
| 454 | +/* FIXME: rename/move - this deals with everything not just VHT */ |
---|
411 | 455 | enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) |
---|
412 | 456 | { |
---|
413 | 457 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
---|
.. | .. |
---|
439 | 483 | |
---|
440 | 484 | void ieee80211_sta_set_rx_nss(struct sta_info *sta) |
---|
441 | 485 | { |
---|
442 | | - u8 ht_rx_nss = 0, vht_rx_nss = 0; |
---|
| 486 | + u8 ht_rx_nss = 0, vht_rx_nss = 0, he_rx_nss = 0, rx_nss; |
---|
443 | 487 | |
---|
444 | 488 | /* if we received a notification already don't overwrite it */ |
---|
445 | 489 | if (sta->sta.rx_nss) |
---|
446 | 490 | return; |
---|
| 491 | + |
---|
| 492 | + if (sta->sta.he_cap.has_he) { |
---|
| 493 | + int i; |
---|
| 494 | + u8 rx_mcs_80 = 0, rx_mcs_160 = 0; |
---|
| 495 | + const struct ieee80211_sta_he_cap *he_cap = &sta->sta.he_cap; |
---|
| 496 | + u16 mcs_160_map = |
---|
| 497 | + le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); |
---|
| 498 | + u16 mcs_80_map = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80); |
---|
| 499 | + |
---|
| 500 | + for (i = 7; i >= 0; i--) { |
---|
| 501 | + u8 mcs_160 = (mcs_160_map >> (2 * i)) & 3; |
---|
| 502 | + |
---|
| 503 | + if (mcs_160 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { |
---|
| 504 | + rx_mcs_160 = i + 1; |
---|
| 505 | + break; |
---|
| 506 | + } |
---|
| 507 | + } |
---|
| 508 | + for (i = 7; i >= 0; i--) { |
---|
| 509 | + u8 mcs_80 = (mcs_80_map >> (2 * i)) & 3; |
---|
| 510 | + |
---|
| 511 | + if (mcs_80 != IEEE80211_VHT_MCS_NOT_SUPPORTED) { |
---|
| 512 | + rx_mcs_80 = i + 1; |
---|
| 513 | + break; |
---|
| 514 | + } |
---|
| 515 | + } |
---|
| 516 | + |
---|
| 517 | + he_rx_nss = min(rx_mcs_80, rx_mcs_160); |
---|
| 518 | + } |
---|
447 | 519 | |
---|
448 | 520 | if (sta->sta.ht_cap.ht_supported) { |
---|
449 | 521 | if (sta->sta.ht_cap.mcs.rx_mask[0]) |
---|
.. | .. |
---|
474 | 546 | /* FIXME: consider rx_highest? */ |
---|
475 | 547 | } |
---|
476 | 548 | |
---|
477 | | - ht_rx_nss = max(ht_rx_nss, vht_rx_nss); |
---|
478 | | - sta->sta.rx_nss = max_t(u8, 1, ht_rx_nss); |
---|
| 549 | + rx_nss = max(vht_rx_nss, ht_rx_nss); |
---|
| 550 | + rx_nss = max(he_rx_nss, rx_nss); |
---|
| 551 | + sta->sta.rx_nss = max_t(u8, 1, rx_nss); |
---|
479 | 552 | } |
---|
480 | 553 | |
---|
481 | 554 | u32 __ieee80211_vht_handle_opmode(struct ieee80211_sub_if_data *sdata, |
---|
.. | .. |
---|
504 | 577 | |
---|
505 | 578 | switch (opmode & IEEE80211_OPMODE_NOTIF_CHANWIDTH_MASK) { |
---|
506 | 579 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_20MHZ: |
---|
| 580 | + /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ |
---|
507 | 581 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_20; |
---|
508 | 582 | break; |
---|
509 | 583 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_40MHZ: |
---|
| 584 | + /* ignore IEEE80211_OPMODE_NOTIF_BW_160_80P80 must not be set */ |
---|
510 | 585 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_40; |
---|
511 | 586 | break; |
---|
512 | 587 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_80MHZ: |
---|
513 | | - sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; |
---|
| 588 | + if (opmode & IEEE80211_OPMODE_NOTIF_BW_160_80P80) |
---|
| 589 | + sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; |
---|
| 590 | + else |
---|
| 591 | + sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_80; |
---|
514 | 592 | break; |
---|
515 | 593 | case IEEE80211_OPMODE_NOTIF_CHANWIDTH_160MHZ: |
---|
| 594 | + /* legacy only, no longer used by newer spec */ |
---|
516 | 595 | sta->cur_max_bandwidth = IEEE80211_STA_RX_BW_160; |
---|
517 | 596 | break; |
---|
518 | 597 | } |
---|