| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * HT handling |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 8 | 9 | * Copyright 2007, Michael Wu <flamingice@sourmilk.net> |
|---|
| 9 | 10 | * Copyright 2007-2010, Intel Corporation |
|---|
| 10 | 11 | * Copyright 2017 Intel Deutschland GmbH |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 13 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 14 | | - * published by the Free Software Foundation. |
|---|
| 12 | + * Copyright(c) 2020 Intel Corporation |
|---|
| 15 | 13 | */ |
|---|
| 16 | 14 | |
|---|
| 17 | 15 | #include <linux/ieee80211.h> |
|---|
| .. | .. |
|---|
| 107 | 105 | __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap, |
|---|
| 108 | 106 | IEEE80211_HT_CAP_40MHZ_INTOLERANT); |
|---|
| 109 | 107 | |
|---|
| 108 | + /* Allow user to enable TX STBC bit */ |
|---|
| 109 | + __check_htcap_enable(ht_capa, ht_capa_mask, ht_cap, |
|---|
| 110 | + IEEE80211_HT_CAP_TX_STBC); |
|---|
| 111 | + |
|---|
| 112 | + /* Allow user to configure RX STBC bits */ |
|---|
| 113 | + if (ht_capa_mask->cap_info & cpu_to_le16(IEEE80211_HT_CAP_RX_STBC)) |
|---|
| 114 | + ht_cap->cap |= le16_to_cpu(ht_capa->cap_info) & |
|---|
| 115 | + IEEE80211_HT_CAP_RX_STBC; |
|---|
| 116 | + |
|---|
| 110 | 117 | /* Allow user to decrease AMPDU factor */ |
|---|
| 111 | 118 | if (ht_capa_mask->ampdu_params_info & |
|---|
| 112 | 119 | IEEE80211_HT_AMPDU_PARM_FACTOR) { |
|---|
| .. | .. |
|---|
| 138 | 145 | int i, max_tx_streams; |
|---|
| 139 | 146 | bool changed; |
|---|
| 140 | 147 | enum ieee80211_sta_rx_bandwidth bw; |
|---|
| 141 | | - enum ieee80211_smps_mode smps_mode; |
|---|
| 142 | 148 | |
|---|
| 143 | 149 | memset(&ht_cap, 0, sizeof(ht_cap)); |
|---|
| 144 | 150 | |
|---|
| .. | .. |
|---|
| 244 | 250 | switch (sdata->vif.bss_conf.chandef.width) { |
|---|
| 245 | 251 | default: |
|---|
| 246 | 252 | WARN_ON_ONCE(1); |
|---|
| 247 | | - /* fall through */ |
|---|
| 253 | + fallthrough; |
|---|
| 248 | 254 | case NL80211_CHAN_WIDTH_20_NOHT: |
|---|
| 249 | 255 | case NL80211_CHAN_WIDTH_20: |
|---|
| 250 | 256 | bw = IEEE80211_STA_RX_BW_20; |
|---|
| .. | .. |
|---|
| 264 | 270 | ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 ? |
|---|
| 265 | 271 | IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20; |
|---|
| 266 | 272 | |
|---|
| 267 | | - switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS) |
|---|
| 268 | | - >> IEEE80211_HT_CAP_SM_PS_SHIFT) { |
|---|
| 269 | | - case WLAN_HT_CAP_SM_PS_INVALID: |
|---|
| 270 | | - case WLAN_HT_CAP_SM_PS_STATIC: |
|---|
| 271 | | - smps_mode = IEEE80211_SMPS_STATIC; |
|---|
| 272 | | - break; |
|---|
| 273 | | - case WLAN_HT_CAP_SM_PS_DYNAMIC: |
|---|
| 274 | | - smps_mode = IEEE80211_SMPS_DYNAMIC; |
|---|
| 275 | | - break; |
|---|
| 276 | | - case WLAN_HT_CAP_SM_PS_DISABLED: |
|---|
| 277 | | - smps_mode = IEEE80211_SMPS_OFF; |
|---|
| 278 | | - break; |
|---|
| 273 | + if (sta->sdata->vif.type == NL80211_IFTYPE_AP || |
|---|
| 274 | + sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { |
|---|
| 275 | + enum ieee80211_smps_mode smps_mode; |
|---|
| 276 | + |
|---|
| 277 | + switch ((ht_cap.cap & IEEE80211_HT_CAP_SM_PS) |
|---|
| 278 | + >> IEEE80211_HT_CAP_SM_PS_SHIFT) { |
|---|
| 279 | + case WLAN_HT_CAP_SM_PS_INVALID: |
|---|
| 280 | + case WLAN_HT_CAP_SM_PS_STATIC: |
|---|
| 281 | + smps_mode = IEEE80211_SMPS_STATIC; |
|---|
| 282 | + break; |
|---|
| 283 | + case WLAN_HT_CAP_SM_PS_DYNAMIC: |
|---|
| 284 | + smps_mode = IEEE80211_SMPS_DYNAMIC; |
|---|
| 285 | + break; |
|---|
| 286 | + case WLAN_HT_CAP_SM_PS_DISABLED: |
|---|
| 287 | + smps_mode = IEEE80211_SMPS_OFF; |
|---|
| 288 | + break; |
|---|
| 289 | + } |
|---|
| 290 | + |
|---|
| 291 | + if (smps_mode != sta->sta.smps_mode) |
|---|
| 292 | + changed = true; |
|---|
| 293 | + sta->sta.smps_mode = smps_mode; |
|---|
| 294 | + } else { |
|---|
| 295 | + sta->sta.smps_mode = IEEE80211_SMPS_OFF; |
|---|
| 279 | 296 | } |
|---|
| 280 | | - |
|---|
| 281 | | - if (smps_mode != sta->sta.smps_mode) |
|---|
| 282 | | - changed = true; |
|---|
| 283 | | - sta->sta.smps_mode = smps_mode; |
|---|
| 284 | | - |
|---|
| 285 | 297 | return changed; |
|---|
| 286 | 298 | } |
|---|
| 287 | 299 | |
|---|
| .. | .. |
|---|
| 353 | 365 | sta->ampdu_mlme.tid_rx_manage_offl)) |
|---|
| 354 | 366 | ___ieee80211_start_rx_ba_session(sta, 0, 0, 0, 1, tid, |
|---|
| 355 | 367 | IEEE80211_MAX_AMPDU_BUF_HT, |
|---|
| 356 | | - false, true); |
|---|
| 368 | + false, true, NULL); |
|---|
| 357 | 369 | |
|---|
| 358 | 370 | if (test_and_clear_bit(tid + IEEE80211_NUM_TIDS, |
|---|
| 359 | 371 | sta->ampdu_mlme.tid_rx_manage_offl)) |
|---|
| .. | .. |
|---|
| 505 | 517 | case IEEE80211_SMPS_AUTOMATIC: |
|---|
| 506 | 518 | case IEEE80211_SMPS_NUM_MODES: |
|---|
| 507 | 519 | WARN_ON(1); |
|---|
| 508 | | - /* fall through */ |
|---|
| 520 | + fallthrough; |
|---|
| 509 | 521 | case IEEE80211_SMPS_OFF: |
|---|
| 510 | 522 | action_frame->u.action.u.ht_smps.smps_control = |
|---|
| 511 | 523 | WLAN_HT_SMPS_CONTROL_DISABLED; |
|---|
| .. | .. |
|---|
| 538 | 550 | sdata_unlock(sdata); |
|---|
| 539 | 551 | } |
|---|
| 540 | 552 | |
|---|
| 541 | | -void ieee80211_request_smps_ap_work(struct work_struct *work) |
|---|
| 542 | | -{ |
|---|
| 543 | | - struct ieee80211_sub_if_data *sdata = |
|---|
| 544 | | - container_of(work, struct ieee80211_sub_if_data, |
|---|
| 545 | | - u.ap.request_smps_work); |
|---|
| 546 | | - |
|---|
| 547 | | - sdata_lock(sdata); |
|---|
| 548 | | - if (sdata_dereference(sdata->u.ap.beacon, sdata)) |
|---|
| 549 | | - __ieee80211_request_smps_ap(sdata, |
|---|
| 550 | | - sdata->u.ap.driver_smps_mode); |
|---|
| 551 | | - sdata_unlock(sdata); |
|---|
| 552 | | -} |
|---|
| 553 | | - |
|---|
| 554 | 553 | void ieee80211_request_smps(struct ieee80211_vif *vif, |
|---|
| 555 | 554 | enum ieee80211_smps_mode smps_mode) |
|---|
| 556 | 555 | { |
|---|
| .. | .. |
|---|
| 566 | 565 | sdata->u.mgd.driver_smps_mode = smps_mode; |
|---|
| 567 | 566 | ieee80211_queue_work(&sdata->local->hw, |
|---|
| 568 | 567 | &sdata->u.mgd.request_smps_work); |
|---|
| 569 | | - } else { |
|---|
| 570 | | - /* AUTOMATIC is meaningless in AP mode */ |
|---|
| 571 | | - if (WARN_ON_ONCE(smps_mode == IEEE80211_SMPS_AUTOMATIC)) |
|---|
| 572 | | - return; |
|---|
| 573 | | - if (sdata->u.ap.driver_smps_mode == smps_mode) |
|---|
| 574 | | - return; |
|---|
| 575 | | - sdata->u.ap.driver_smps_mode = smps_mode; |
|---|
| 576 | | - ieee80211_queue_work(&sdata->local->hw, |
|---|
| 577 | | - &sdata->u.ap.request_smps_work); |
|---|
| 578 | 568 | } |
|---|
| 579 | 569 | } |
|---|
| 580 | 570 | /* this might change ... don't want non-open drivers using it */ |
|---|