| .. | .. |
|---|
| 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)) { |
|---|