.. | .. |
---|
39 | 39 | .max_power = 25, \ |
---|
40 | 40 | } |
---|
41 | 41 | |
---|
42 | | -#define CHAN5G(_freq, _idx) { \ |
---|
| 42 | +#define CHAN5G(_freq, _idx, _phy_val) { \ |
---|
43 | 43 | .band = NL80211_BAND_5GHZ, \ |
---|
44 | 44 | .center_freq = (_freq), \ |
---|
45 | | - .hw_value = (_idx), \ |
---|
| 45 | + .hw_value = (_phy_val) << HW_VALUE_PHY_SHIFT | HW_VALUE_CHANNEL(_idx), \ |
---|
46 | 46 | .max_power = 25, \ |
---|
47 | 47 | } |
---|
48 | 48 | |
---|
.. | .. |
---|
67 | 67 | }; |
---|
68 | 68 | |
---|
69 | 69 | static struct ieee80211_channel wcn_5ghz_channels[] = { |
---|
70 | | - CHAN5G(5180, 36), |
---|
71 | | - CHAN5G(5200, 40), |
---|
72 | | - CHAN5G(5220, 44), |
---|
73 | | - CHAN5G(5240, 48), |
---|
74 | | - CHAN5G(5260, 52), |
---|
75 | | - CHAN5G(5280, 56), |
---|
76 | | - CHAN5G(5300, 60), |
---|
77 | | - CHAN5G(5320, 64), |
---|
78 | | - CHAN5G(5500, 100), |
---|
79 | | - CHAN5G(5520, 104), |
---|
80 | | - CHAN5G(5540, 108), |
---|
81 | | - CHAN5G(5560, 112), |
---|
82 | | - CHAN5G(5580, 116), |
---|
83 | | - CHAN5G(5600, 120), |
---|
84 | | - CHAN5G(5620, 124), |
---|
85 | | - CHAN5G(5640, 128), |
---|
86 | | - CHAN5G(5660, 132), |
---|
87 | | - CHAN5G(5700, 140), |
---|
88 | | - CHAN5G(5745, 149), |
---|
89 | | - CHAN5G(5765, 153), |
---|
90 | | - CHAN5G(5785, 157), |
---|
91 | | - CHAN5G(5805, 161), |
---|
92 | | - CHAN5G(5825, 165) |
---|
| 70 | + CHAN5G(5180, 36, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW), |
---|
| 71 | + CHAN5G(5200, 40, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW), |
---|
| 72 | + CHAN5G(5220, 44, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH), |
---|
| 73 | + CHAN5G(5240, 48, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH), |
---|
| 74 | + CHAN5G(5260, 52, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW), |
---|
| 75 | + CHAN5G(5280, 56, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW), |
---|
| 76 | + CHAN5G(5300, 60, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH), |
---|
| 77 | + CHAN5G(5320, 64, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH), |
---|
| 78 | + CHAN5G(5500, 100, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW), |
---|
| 79 | + CHAN5G(5520, 104, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW), |
---|
| 80 | + CHAN5G(5540, 108, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH), |
---|
| 81 | + CHAN5G(5560, 112, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH), |
---|
| 82 | + CHAN5G(5580, 116, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW), |
---|
| 83 | + CHAN5G(5600, 120, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW), |
---|
| 84 | + CHAN5G(5620, 124, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH), |
---|
| 85 | + CHAN5G(5640, 128, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH), |
---|
| 86 | + CHAN5G(5660, 132, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW), |
---|
| 87 | + CHAN5G(5700, 140, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH), |
---|
| 88 | + CHAN5G(5745, 149, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_LOW), |
---|
| 89 | + CHAN5G(5765, 153, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_LOW), |
---|
| 90 | + CHAN5G(5785, 157, PHY_QUADRUPLE_CHANNEL_20MHZ_LOW_40MHZ_HIGH), |
---|
| 91 | + CHAN5G(5805, 161, PHY_QUADRUPLE_CHANNEL_20MHZ_HIGH_40MHZ_HIGH), |
---|
| 92 | + CHAN5G(5825, 165, 0) |
---|
93 | 93 | }; |
---|
94 | 94 | |
---|
95 | 95 | #define RATE(_bitrate, _hw_rate, _flags) { \ |
---|
.. | .. |
---|
347 | 347 | |
---|
348 | 348 | wcn36xx_dbg(WCN36XX_DBG_MAC, "mac stop\n"); |
---|
349 | 349 | |
---|
350 | | - cancel_work_sync(&wcn->scan_work); |
---|
351 | | - |
---|
352 | 350 | mutex_lock(&wcn->scan_lock); |
---|
353 | 351 | if (wcn->scan_req) { |
---|
354 | 352 | struct cfg80211_scan_info scan_info = { |
---|
.. | .. |
---|
369 | 367 | wcn36xx_dxe_free_ctl_blks(wcn); |
---|
370 | 368 | } |
---|
371 | 369 | |
---|
| 370 | +static void wcn36xx_change_ps(struct wcn36xx *wcn, bool enable) |
---|
| 371 | +{ |
---|
| 372 | + struct ieee80211_vif *vif = NULL; |
---|
| 373 | + struct wcn36xx_vif *tmp; |
---|
| 374 | + |
---|
| 375 | + list_for_each_entry(tmp, &wcn->vif_list, list) { |
---|
| 376 | + vif = wcn36xx_priv_to_vif(tmp); |
---|
| 377 | + if (enable && !wcn->sw_scan) { |
---|
| 378 | + if (vif->bss_conf.ps) /* ps allowed ? */ |
---|
| 379 | + wcn36xx_pmc_enter_bmps_state(wcn, vif); |
---|
| 380 | + } else { |
---|
| 381 | + wcn36xx_pmc_exit_bmps_state(wcn, vif); |
---|
| 382 | + } |
---|
| 383 | + } |
---|
| 384 | +} |
---|
| 385 | + |
---|
| 386 | +static void wcn36xx_change_opchannel(struct wcn36xx *wcn, int ch) |
---|
| 387 | +{ |
---|
| 388 | + struct ieee80211_vif *vif = NULL; |
---|
| 389 | + struct wcn36xx_vif *tmp; |
---|
| 390 | + |
---|
| 391 | + list_for_each_entry(tmp, &wcn->vif_list, list) { |
---|
| 392 | + vif = wcn36xx_priv_to_vif(tmp); |
---|
| 393 | + wcn36xx_smd_switch_channel(wcn, vif, ch); |
---|
| 394 | + } |
---|
| 395 | +} |
---|
| 396 | + |
---|
372 | 397 | static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) |
---|
373 | 398 | { |
---|
374 | 399 | struct wcn36xx *wcn = hw->priv; |
---|
375 | | - struct ieee80211_vif *vif = NULL; |
---|
376 | | - struct wcn36xx_vif *tmp; |
---|
| 400 | + int ret; |
---|
377 | 401 | |
---|
378 | 402 | wcn36xx_dbg(WCN36XX_DBG_MAC, "mac config changed 0x%08x\n", changed); |
---|
379 | 403 | |
---|
.. | .. |
---|
383 | 407 | int ch = WCN36XX_HW_CHANNEL(wcn); |
---|
384 | 408 | wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n", |
---|
385 | 409 | ch); |
---|
386 | | - list_for_each_entry(tmp, &wcn->vif_list, list) { |
---|
387 | | - vif = wcn36xx_priv_to_vif(tmp); |
---|
388 | | - wcn36xx_smd_switch_channel(wcn, vif, ch); |
---|
| 410 | + |
---|
| 411 | + if (wcn->sw_scan_opchannel == ch && wcn->sw_scan_channel) { |
---|
| 412 | + /* If channel is the initial operating channel, we may |
---|
| 413 | + * want to receive/transmit regular data packets, then |
---|
| 414 | + * simply stop the scan session and exit PS mode. |
---|
| 415 | + */ |
---|
| 416 | + if (wcn->sw_scan_channel) |
---|
| 417 | + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); |
---|
| 418 | + if (wcn->sw_scan_init) { |
---|
| 419 | + wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, |
---|
| 420 | + wcn->sw_scan_vif); |
---|
| 421 | + } |
---|
| 422 | + } else if (wcn->sw_scan) { |
---|
| 423 | + /* A scan is ongoing, do not change the operating |
---|
| 424 | + * channel, but start a scan session on the channel. |
---|
| 425 | + */ |
---|
| 426 | + if (wcn->sw_scan_channel) |
---|
| 427 | + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); |
---|
| 428 | + if (!wcn->sw_scan_init) { |
---|
| 429 | + /* This can fail if we are unable to notify the |
---|
| 430 | + * operating channel. |
---|
| 431 | + */ |
---|
| 432 | + ret = wcn36xx_smd_init_scan(wcn, |
---|
| 433 | + HAL_SYS_MODE_SCAN, |
---|
| 434 | + wcn->sw_scan_vif); |
---|
| 435 | + if (ret) { |
---|
| 436 | + mutex_unlock(&wcn->conf_mutex); |
---|
| 437 | + return -EIO; |
---|
| 438 | + } |
---|
| 439 | + } |
---|
| 440 | + wcn36xx_smd_start_scan(wcn, ch); |
---|
| 441 | + } else { |
---|
| 442 | + wcn36xx_change_opchannel(wcn, ch); |
---|
389 | 443 | } |
---|
390 | 444 | } |
---|
391 | 445 | |
---|
392 | | - if (changed & IEEE80211_CONF_CHANGE_PS) { |
---|
393 | | - list_for_each_entry(tmp, &wcn->vif_list, list) { |
---|
394 | | - vif = wcn36xx_priv_to_vif(tmp); |
---|
395 | | - if (hw->conf.flags & IEEE80211_CONF_PS) { |
---|
396 | | - if (vif->bss_conf.ps) /* ps allowed ? */ |
---|
397 | | - wcn36xx_pmc_enter_bmps_state(wcn, vif); |
---|
398 | | - } else { |
---|
399 | | - wcn36xx_pmc_exit_bmps_state(wcn, vif); |
---|
400 | | - } |
---|
401 | | - } |
---|
402 | | - } |
---|
| 446 | + if (changed & IEEE80211_CONF_CHANGE_PS) |
---|
| 447 | + wcn36xx_change_ps(wcn, hw->conf.flags & IEEE80211_CONF_PS); |
---|
403 | 448 | |
---|
404 | 449 | mutex_unlock(&wcn->conf_mutex); |
---|
405 | 450 | |
---|
.. | .. |
---|
538 | 583 | if (IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags) { |
---|
539 | 584 | sta_priv->is_data_encrypted = true; |
---|
540 | 585 | /* Reconfigure bss with encrypt_type */ |
---|
541 | | - if (NL80211_IFTYPE_STATION == vif->type) |
---|
| 586 | + if (NL80211_IFTYPE_STATION == vif->type) { |
---|
542 | 587 | wcn36xx_smd_config_bss(wcn, |
---|
543 | 588 | vif, |
---|
544 | 589 | sta, |
---|
545 | 590 | sta->addr, |
---|
546 | 591 | true); |
---|
| 592 | + wcn36xx_smd_config_sta(wcn, vif, sta); |
---|
| 593 | + } |
---|
547 | 594 | |
---|
548 | 595 | wcn36xx_smd_set_stakey(wcn, |
---|
549 | 596 | vif_priv->encrypt_type, |
---|
.. | .. |
---|
605 | 652 | return ret; |
---|
606 | 653 | } |
---|
607 | 654 | |
---|
608 | | -static void wcn36xx_hw_scan_worker(struct work_struct *work) |
---|
609 | | -{ |
---|
610 | | - struct wcn36xx *wcn = container_of(work, struct wcn36xx, scan_work); |
---|
611 | | - struct cfg80211_scan_request *req = wcn->scan_req; |
---|
612 | | - u8 channels[WCN36XX_HAL_PNO_MAX_NETW_CHANNELS_EX]; |
---|
613 | | - struct cfg80211_scan_info scan_info = {}; |
---|
614 | | - bool aborted = false; |
---|
615 | | - int i; |
---|
616 | | - |
---|
617 | | - wcn36xx_dbg(WCN36XX_DBG_MAC, "mac80211 scan %d channels worker\n", req->n_channels); |
---|
618 | | - |
---|
619 | | - for (i = 0; i < req->n_channels; i++) |
---|
620 | | - channels[i] = req->channels[i]->hw_value; |
---|
621 | | - |
---|
622 | | - wcn36xx_smd_update_scan_params(wcn, channels, req->n_channels); |
---|
623 | | - |
---|
624 | | - wcn36xx_smd_init_scan(wcn, HAL_SYS_MODE_SCAN); |
---|
625 | | - for (i = 0; i < req->n_channels; i++) { |
---|
626 | | - mutex_lock(&wcn->scan_lock); |
---|
627 | | - aborted = wcn->scan_aborted; |
---|
628 | | - mutex_unlock(&wcn->scan_lock); |
---|
629 | | - |
---|
630 | | - if (aborted) |
---|
631 | | - break; |
---|
632 | | - |
---|
633 | | - wcn->scan_freq = req->channels[i]->center_freq; |
---|
634 | | - wcn->scan_band = req->channels[i]->band; |
---|
635 | | - |
---|
636 | | - wcn36xx_smd_start_scan(wcn, req->channels[i]->hw_value); |
---|
637 | | - msleep(30); |
---|
638 | | - wcn36xx_smd_end_scan(wcn, req->channels[i]->hw_value); |
---|
639 | | - |
---|
640 | | - wcn->scan_freq = 0; |
---|
641 | | - } |
---|
642 | | - wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN); |
---|
643 | | - |
---|
644 | | - scan_info.aborted = aborted; |
---|
645 | | - ieee80211_scan_completed(wcn->hw, &scan_info); |
---|
646 | | - |
---|
647 | | - mutex_lock(&wcn->scan_lock); |
---|
648 | | - wcn->scan_req = NULL; |
---|
649 | | - mutex_unlock(&wcn->scan_lock); |
---|
650 | | -} |
---|
651 | | - |
---|
652 | 655 | static int wcn36xx_hw_scan(struct ieee80211_hw *hw, |
---|
653 | 656 | struct ieee80211_vif *vif, |
---|
654 | 657 | struct ieee80211_scan_request *hw_req) |
---|
655 | 658 | { |
---|
656 | 659 | struct wcn36xx *wcn = hw->priv; |
---|
| 660 | + int i; |
---|
| 661 | + |
---|
| 662 | + if (!get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) { |
---|
| 663 | + /* fallback to mac80211 software scan */ |
---|
| 664 | + return 1; |
---|
| 665 | + } |
---|
| 666 | + |
---|
| 667 | + /* For unknown reason, the hardware offloaded scan only works with |
---|
| 668 | + * 2.4Ghz channels, fallback to software scan in other cases. |
---|
| 669 | + */ |
---|
| 670 | + for (i = 0; i < hw_req->req.n_channels; i++) { |
---|
| 671 | + if (hw_req->req.channels[i]->band != NL80211_BAND_2GHZ) |
---|
| 672 | + return 1; |
---|
| 673 | + } |
---|
| 674 | + |
---|
657 | 675 | mutex_lock(&wcn->scan_lock); |
---|
658 | 676 | if (wcn->scan_req) { |
---|
659 | 677 | mutex_unlock(&wcn->scan_lock); |
---|
.. | .. |
---|
664 | 682 | wcn->scan_req = &hw_req->req; |
---|
665 | 683 | |
---|
666 | 684 | mutex_unlock(&wcn->scan_lock); |
---|
667 | | - |
---|
668 | | - if (!get_feat_caps(wcn->fw_feat_caps, SCAN_OFFLOAD)) { |
---|
669 | | - /* legacy manual/sw scan */ |
---|
670 | | - schedule_work(&wcn->scan_work); |
---|
671 | | - return 0; |
---|
672 | | - } |
---|
673 | 685 | |
---|
674 | 686 | return wcn36xx_smd_start_hw_scan(wcn, vif, &hw_req->req); |
---|
675 | 687 | } |
---|
.. | .. |
---|
687 | 699 | /* ieee80211_scan_completed will be called on FW scan |
---|
688 | 700 | * indication */ |
---|
689 | 701 | wcn36xx_smd_stop_hw_scan(wcn); |
---|
690 | | - } else { |
---|
691 | | - struct cfg80211_scan_info scan_info = { |
---|
692 | | - .aborted = true, |
---|
693 | | - }; |
---|
694 | | - |
---|
695 | | - cancel_work_sync(&wcn->scan_work); |
---|
696 | | - ieee80211_scan_completed(wcn->hw, &scan_info); |
---|
697 | 702 | } |
---|
| 703 | +} |
---|
| 704 | + |
---|
| 705 | +static void wcn36xx_sw_scan_start(struct ieee80211_hw *hw, |
---|
| 706 | + struct ieee80211_vif *vif, |
---|
| 707 | + const u8 *mac_addr) |
---|
| 708 | +{ |
---|
| 709 | + struct wcn36xx *wcn = hw->priv; |
---|
| 710 | + struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif); |
---|
| 711 | + |
---|
| 712 | + wcn->sw_scan = true; |
---|
| 713 | + wcn->sw_scan_vif = vif; |
---|
| 714 | + wcn->sw_scan_channel = 0; |
---|
| 715 | + if (vif_priv->sta_assoc) |
---|
| 716 | + wcn->sw_scan_opchannel = WCN36XX_HW_CHANNEL(wcn); |
---|
| 717 | + else |
---|
| 718 | + wcn->sw_scan_opchannel = 0; |
---|
| 719 | +} |
---|
| 720 | + |
---|
| 721 | +static void wcn36xx_sw_scan_complete(struct ieee80211_hw *hw, |
---|
| 722 | + struct ieee80211_vif *vif) |
---|
| 723 | +{ |
---|
| 724 | + struct wcn36xx *wcn = hw->priv; |
---|
| 725 | + |
---|
| 726 | + /* ensure that any scan session is finished */ |
---|
| 727 | + if (wcn->sw_scan_channel) |
---|
| 728 | + wcn36xx_smd_end_scan(wcn, wcn->sw_scan_channel); |
---|
| 729 | + if (wcn->sw_scan_init) { |
---|
| 730 | + wcn36xx_smd_finish_scan(wcn, HAL_SYS_MODE_SCAN, |
---|
| 731 | + wcn->sw_scan_vif); |
---|
| 732 | + } |
---|
| 733 | + wcn->sw_scan = false; |
---|
| 734 | + wcn->sw_scan_opchannel = 0; |
---|
698 | 735 | } |
---|
699 | 736 | |
---|
700 | 737 | static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta, |
---|
.. | .. |
---|
736 | 773 | sta->ht_cap.mcs.rx_mask, |
---|
737 | 774 | sizeof(sta->ht_cap.mcs.rx_mask)); |
---|
738 | 775 | } |
---|
| 776 | + |
---|
| 777 | + if (sta->vht_cap.vht_supported) { |
---|
| 778 | + sta_priv->supported_rates.op_rate_mode = STA_11ac; |
---|
| 779 | + sta_priv->supported_rates.vht_rx_mcs_map = |
---|
| 780 | + sta->vht_cap.vht_mcs.rx_mcs_map; |
---|
| 781 | + sta_priv->supported_rates.vht_tx_mcs_map = |
---|
| 782 | + sta->vht_cap.vht_mcs.tx_mcs_map; |
---|
| 783 | + } |
---|
739 | 784 | } |
---|
| 785 | + |
---|
740 | 786 | void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates) |
---|
741 | 787 | { |
---|
742 | 788 | u16 ofdm_rates[WCN36XX_HAL_NUM_OFDM_RATES] = { |
---|
.. | .. |
---|
763 | 809 | sizeof(*ofdm_rates) * WCN36XX_HAL_NUM_OFDM_RATES); |
---|
764 | 810 | rates->supported_mcs_set[0] = 0xFF; |
---|
765 | 811 | } |
---|
| 812 | + |
---|
| 813 | +void wcn36xx_set_default_rates_v1(struct wcn36xx_hal_supported_rates_v1 *rates) |
---|
| 814 | +{ |
---|
| 815 | + rates->op_rate_mode = STA_11ac; |
---|
| 816 | + rates->vht_rx_mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9; |
---|
| 817 | + rates->vht_tx_mcs_map = IEEE80211_VHT_MCS_SUPPORT_0_9; |
---|
| 818 | +} |
---|
| 819 | + |
---|
766 | 820 | static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw, |
---|
767 | 821 | struct ieee80211_vif *vif, |
---|
768 | 822 | struct ieee80211_bss_conf *bss_conf, |
---|
.. | .. |
---|
926 | 980 | out: |
---|
927 | 981 | |
---|
928 | 982 | mutex_unlock(&wcn->conf_mutex); |
---|
929 | | - |
---|
930 | | - return; |
---|
931 | 983 | } |
---|
932 | 984 | |
---|
933 | 985 | /* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */ |
---|
.. | .. |
---|
1075 | 1127 | enum ieee80211_ampdu_mlme_action action = params->action; |
---|
1076 | 1128 | u16 tid = params->tid; |
---|
1077 | 1129 | u16 *ssn = ¶ms->ssn; |
---|
| 1130 | + int ret = 0; |
---|
| 1131 | + u8 session; |
---|
1078 | 1132 | |
---|
1079 | 1133 | wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n", |
---|
1080 | 1134 | action, tid); |
---|
.. | .. |
---|
1084 | 1138 | switch (action) { |
---|
1085 | 1139 | case IEEE80211_AMPDU_RX_START: |
---|
1086 | 1140 | sta_priv->tid = tid; |
---|
1087 | | - wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, |
---|
1088 | | - get_sta_index(vif, sta_priv)); |
---|
1089 | | - wcn36xx_smd_add_ba(wcn); |
---|
1090 | | - wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv)); |
---|
| 1141 | + session = wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 0, |
---|
| 1142 | + get_sta_index(vif, sta_priv)); |
---|
| 1143 | + wcn36xx_smd_add_ba(wcn, session); |
---|
| 1144 | + wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv), tid, |
---|
| 1145 | + session); |
---|
1091 | 1146 | break; |
---|
1092 | 1147 | case IEEE80211_AMPDU_RX_STOP: |
---|
1093 | 1148 | wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv)); |
---|
.. | .. |
---|
1097 | 1152 | sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START; |
---|
1098 | 1153 | spin_unlock_bh(&sta_priv->ampdu_lock); |
---|
1099 | 1154 | |
---|
1100 | | - ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
---|
| 1155 | + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; |
---|
1101 | 1156 | break; |
---|
1102 | 1157 | case IEEE80211_AMPDU_TX_OPERATIONAL: |
---|
1103 | 1158 | spin_lock_bh(&sta_priv->ampdu_lock); |
---|
.. | .. |
---|
1122 | 1177 | |
---|
1123 | 1178 | mutex_unlock(&wcn->conf_mutex); |
---|
1124 | 1179 | |
---|
1125 | | - return 0; |
---|
| 1180 | + return ret; |
---|
1126 | 1181 | } |
---|
1127 | 1182 | |
---|
1128 | 1183 | static const struct ieee80211_ops wcn36xx_ops = { |
---|
.. | .. |
---|
1141 | 1196 | .set_key = wcn36xx_set_key, |
---|
1142 | 1197 | .hw_scan = wcn36xx_hw_scan, |
---|
1143 | 1198 | .cancel_hw_scan = wcn36xx_cancel_hw_scan, |
---|
| 1199 | + .sw_scan_start = wcn36xx_sw_scan_start, |
---|
| 1200 | + .sw_scan_complete = wcn36xx_sw_scan_complete, |
---|
1144 | 1201 | .bss_info_changed = wcn36xx_bss_info_changed, |
---|
1145 | 1202 | .set_rts_threshold = wcn36xx_set_rts_threshold, |
---|
1146 | 1203 | .sta_add = wcn36xx_sta_add, |
---|
.. | .. |
---|
1149 | 1206 | |
---|
1150 | 1207 | CFG80211_TESTMODE_CMD(wcn36xx_tm_cmd) |
---|
1151 | 1208 | }; |
---|
| 1209 | + |
---|
| 1210 | +static void |
---|
| 1211 | +wcn36xx_set_ieee80211_vht_caps(struct ieee80211_sta_vht_cap *vht_cap) |
---|
| 1212 | +{ |
---|
| 1213 | + vht_cap->vht_supported = true; |
---|
| 1214 | + |
---|
| 1215 | + vht_cap->cap = (IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 | |
---|
| 1216 | + IEEE80211_VHT_CAP_SHORT_GI_80 | |
---|
| 1217 | + IEEE80211_VHT_CAP_RXSTBC_1 | |
---|
| 1218 | + IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | |
---|
| 1219 | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE | |
---|
| 1220 | + 3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT | |
---|
| 1221 | + 7 << IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT); |
---|
| 1222 | + |
---|
| 1223 | + vht_cap->vht_mcs.rx_mcs_map = |
---|
| 1224 | + cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_9 | |
---|
| 1225 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 2 | |
---|
| 1226 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 4 | |
---|
| 1227 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 6 | |
---|
| 1228 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 8 | |
---|
| 1229 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 10 | |
---|
| 1230 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 12 | |
---|
| 1231 | + IEEE80211_VHT_MCS_NOT_SUPPORTED << 14); |
---|
| 1232 | + |
---|
| 1233 | + vht_cap->vht_mcs.rx_highest = cpu_to_le16(433); |
---|
| 1234 | + vht_cap->vht_mcs.tx_highest = vht_cap->vht_mcs.rx_highest; |
---|
| 1235 | + |
---|
| 1236 | + vht_cap->vht_mcs.tx_mcs_map = vht_cap->vht_mcs.rx_mcs_map; |
---|
| 1237 | +} |
---|
1152 | 1238 | |
---|
1153 | 1239 | static int wcn36xx_init_ieee80211(struct wcn36xx *wcn) |
---|
1154 | 1240 | { |
---|
.. | .. |
---|
1161 | 1247 | |
---|
1162 | 1248 | ieee80211_hw_set(wcn->hw, TIMING_BEACON_ONLY); |
---|
1163 | 1249 | ieee80211_hw_set(wcn->hw, AMPDU_AGGREGATION); |
---|
1164 | | - ieee80211_hw_set(wcn->hw, CONNECTION_MONITOR); |
---|
1165 | 1250 | ieee80211_hw_set(wcn->hw, SUPPORTS_PS); |
---|
1166 | 1251 | ieee80211_hw_set(wcn->hw, SIGNAL_DBM); |
---|
1167 | 1252 | ieee80211_hw_set(wcn->hw, HAS_RATE_CONTROL); |
---|
1168 | 1253 | ieee80211_hw_set(wcn->hw, SINGLE_SCAN_ON_ALL_BANDS); |
---|
| 1254 | + ieee80211_hw_set(wcn->hw, REPORTS_TX_ACK_STATUS); |
---|
1169 | 1255 | |
---|
1170 | 1256 | wcn->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | |
---|
1171 | 1257 | BIT(NL80211_IFTYPE_AP) | |
---|
.. | .. |
---|
1175 | 1261 | wcn->hw->wiphy->bands[NL80211_BAND_2GHZ] = &wcn_band_2ghz; |
---|
1176 | 1262 | if (wcn->rf_id != RF_IRIS_WCN3620) |
---|
1177 | 1263 | wcn->hw->wiphy->bands[NL80211_BAND_5GHZ] = &wcn_band_5ghz; |
---|
| 1264 | + |
---|
| 1265 | + if (wcn->rf_id == RF_IRIS_WCN3680) |
---|
| 1266 | + wcn36xx_set_ieee80211_vht_caps(&wcn_band_5ghz.vht_cap); |
---|
1178 | 1267 | |
---|
1179 | 1268 | wcn->hw->wiphy->max_scan_ssids = WCN36XX_MAX_SCAN_SSIDS; |
---|
1180 | 1269 | wcn->hw->wiphy->max_scan_ie_len = WCN36XX_MAX_SCAN_IE_LEN; |
---|
.. | .. |
---|
1273 | 1362 | if (iris_node) { |
---|
1274 | 1363 | if (of_device_is_compatible(iris_node, "qcom,wcn3620")) |
---|
1275 | 1364 | wcn->rf_id = RF_IRIS_WCN3620; |
---|
| 1365 | + if (of_device_is_compatible(iris_node, "qcom,wcn3660") || |
---|
| 1366 | + of_device_is_compatible(iris_node, "qcom,wcn3660b")) |
---|
| 1367 | + wcn->rf_id = RF_IRIS_WCN3660; |
---|
| 1368 | + if (of_device_is_compatible(iris_node, "qcom,wcn3680")) |
---|
| 1369 | + wcn->rf_id = RF_IRIS_WCN3680; |
---|
1276 | 1370 | of_node_put(iris_node); |
---|
1277 | 1371 | } |
---|
1278 | 1372 | |
---|
.. | .. |
---|
1324 | 1418 | wcn36xx_err("failed to set DMA mask: %d\n", ret); |
---|
1325 | 1419 | goto out_wq; |
---|
1326 | 1420 | } |
---|
1327 | | - |
---|
1328 | | - INIT_WORK(&wcn->scan_work, wcn36xx_hw_scan_worker); |
---|
1329 | 1421 | |
---|
1330 | 1422 | wcn->smd_channel = qcom_wcnss_open_channel(wcnss, "WLAN_CTRL", wcn36xx_smd_rsp_process, hw); |
---|
1331 | 1423 | if (IS_ERR(wcn->smd_channel)) { |
---|