aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h207
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c29
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h19
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c18
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c447
7 files changed, 653 insertions, 70 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index 79b0508fddef..1bb5193c5b1b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -124,6 +124,7 @@ enum iwl_ucode_tlv_flag {
124 * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex 124 * @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
125 * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. 125 * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
126 * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit. 126 * @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
127 * @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API.
127 */ 128 */
128enum iwl_ucode_tlv_api { 129enum iwl_ucode_tlv_api {
129 IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), 130 IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0),
@@ -131,6 +132,7 @@ enum iwl_ucode_tlv_api {
131 IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3), 132 IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
132 IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), 133 IWL_UCODE_TLV_API_CSA_FLOW = BIT(4),
133 IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5), 134 IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
135 IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6),
134}; 136};
135 137
136/** 138/**
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index 1d586923d5b7..48a1d8f5675d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -582,4 +582,211 @@ struct iwl_sched_scan_results {
582 u8 reserved; 582 u8 reserved;
583}; 583};
584 584
585/* Unified LMAC scan API */
586
587#define IWL_MVM_BASIC_PASSIVE_DWELL 110
588
589/**
590 * iwl_scan_req_tx_cmd - SCAN_REQ_TX_CMD_API_S
591 * @tx_flags: combination of TX_CMD_FLG_*
592 * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is
593 * cleared. Combination of RATE_MCS_*
594 * @sta_id: index of destination station in FW station table
595 * @reserved: for alignment and future use
596 */
597struct iwl_scan_req_tx_cmd {
598 __le32 tx_flags;
599 __le32 rate_n_flags;
600 u8 sta_id;
601 u8 reserved[3];
602} __packed;
603
604enum iwl_scan_channel_flags_lmac {
605 IWL_UNIFIED_SCAN_CHANNEL_FULL = BIT(27),
606 IWL_UNIFIED_SCAN_CHANNEL_PARTIAL = BIT(28),
607};
608
609/**
610 * iwl_scan_channel_cfg_lmac - SCAN_CHANNEL_CFG_S_VER2
611 * @flags: bits 1-20: directed scan to i'th ssid
612 * other bits &enum iwl_scan_channel_flags_lmac
613 * @channel_number: channel number 1-13 etc
614 * @iter_count: scan iteration on this channel
615 * @iter_interval: interval in seconds between iterations on one channel
616 */
617struct iwl_scan_channel_cfg_lmac {
618 __le32 flags;
619 __le16 channel_num;
620 __le16 iter_count;
621 __le32 iter_interval;
622} __packed;
623
624/*
625 * iwl_scan_probe_segment - PROBE_SEGMENT_API_S_VER_1
626 * @offset: offset in the data block
627 * @len: length of the segment
628 */
629struct iwl_scan_probe_segment {
630 __le16 offset;
631 __le16 len;
632} __packed;
633
634/* iwl_scan_probe_req - PROBE_REQUEST_FRAME_API_S_VER_2
635 * @mac_header: first (and common) part of the probe
636 * @band_data: band specific data
637 * @common_data: last (and common) part of the probe
638 * @buf: raw data block
639 */
640struct iwl_scan_probe_req {
641 struct iwl_scan_probe_segment mac_header;
642 struct iwl_scan_probe_segment band_data[2];
643 struct iwl_scan_probe_segment common_data;
644 u8 buf[SCAN_OFFLOAD_PROBE_REQ_SIZE];
645} __packed;
646
647enum iwl_scan_channel_flags {
648 IWL_SCAN_CHANNEL_FLAG_EBS = BIT(0),
649 IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE = BIT(1),
650 IWL_SCAN_CHANNEL_FLAG_CACHE_ADD = BIT(2),
651};
652
653/* iwl_scan_channel_opt - CHANNEL_OPTIMIZATION_API_S
654 * @flags: enum iwl_scan_channel_flgs
655 * @non_ebs_ratio: how many regular scan iteration before EBS
656 */
657struct iwl_scan_channel_opt {
658 __le16 flags;
659 __le16 non_ebs_ratio;
660} __packed;
661
662/**
663 * iwl_mvm_lmac_scan_flags
664 * @IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL: pass all beacons and probe responses
665 * without filtering.
666 * @IWL_MVM_LMAC_SCAN_FLAG_PASSIVE: force passive scan on all channels
667 * @IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION: single channel scan
668 * @IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE: send iteration complete notification
669 * @IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS multiple SSID matching
670 * @IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED: all passive scans will be fragmented
671 */
672enum iwl_mvm_lmac_scan_flags {
673 IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL = BIT(0),
674 IWL_MVM_LMAC_SCAN_FLAG_PASSIVE = BIT(1),
675 IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION = BIT(2),
676 IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE = BIT(3),
677 IWL_MVM_LMAC_SCAN_FLAG_MULTIPLE_SSIDS = BIT(4),
678 IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED = BIT(5),
679};
680
681enum iwl_scan_priority {
682 IWL_SCAN_PRIORITY_LOW,
683 IWL_SCAN_PRIORITY_MEDIUM,
684 IWL_SCAN_PRIORITY_HIGH,
685};
686
687/**
688 * iwl_scan_req_unified_lmac - SCAN_REQUEST_CMD_API_S_VER_1
689 * @reserved1: for alignment and future use
690 * @channel_num: num of channels to scan
691 * @active-dwell: dwell time for active channels
692 * @passive-dwell: dwell time for passive channels
693 * @fragmented-dwell: dwell time for fragmented passive scan
694 * @reserved2: for alignment and future use
695 * @rx_chain_selct: PHY_RX_CHAIN_* flags
696 * @scan_flags: &enum iwl_mvm_lmac_scan_flags
697 * @max_out_time: max time (in TU) to be out of associated channel
698 * @suspend_time: pause scan this long (TUs) when returning to service channel
699 * @flags: RXON flags
700 * @filter_flags: RXON filter
701 * @tx_cmd: tx command for active scan; for 2GHz and for 5GHz
702 * @direct_scan: list of SSIDs for directed active scan
703 * @scan_prio: enum iwl_scan_priority
704 * @iter_num: number of scan iterations
705 * @delay: delay in seconds before first iteration
706 * @schedule: two scheduling plans. The first one is finite, the second one can
707 * be infinite.
708 * @channel_opt: channel optimization options, for full and partial scan
709 * @data: channel configuration and probe request packet.
710 */
711struct iwl_scan_req_unified_lmac {
712 /* SCAN_REQUEST_FIXED_PART_API_S_VER_7 */
713 __le32 reserved1;
714 u8 n_channels;
715 u8 active_dwell;
716 u8 passive_dwell;
717 u8 fragmented_dwell;
718 __le16 reserved2;
719 __le16 rx_chain_select;
720 __le32 scan_flags;
721 __le32 max_out_time;
722 __le32 suspend_time;
723 /* RX_ON_FLAGS_API_S_VER_1 */
724 __le32 flags;
725 __le32 filter_flags;
726 struct iwl_scan_req_tx_cmd tx_cmd[2];
727 struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX];
728 __le32 scan_prio;
729 /* SCAN_REQ_PERIODIC_PARAMS_API_S */
730 __le32 iter_num;
731 __le32 delay;
732 struct iwl_scan_offload_schedule schedule[2];
733 struct iwl_scan_channel_opt channel_opt[2];
734 u8 data[];
735} __packed;
736
737/**
738 * struct iwl_lmac_scan_results_notif - scan results for one channel -
739 * SCAN_RESULT_NTF_API_S_VER_3
740 * @channel: which channel the results are from
741 * @band: 0 for 5.2 GHz, 1 for 2.4 GHz
742 * @probe_status: SCAN_PROBE_STATUS_*, indicates success of probe request
743 * @num_probe_not_sent: # of request that weren't sent due to not enough time
744 * @duration: duration spent in channel, in usecs
745 */
746struct iwl_lmac_scan_results_notif {
747 u8 channel;
748 u8 band;
749 u8 probe_status;
750 u8 num_probe_not_sent;
751 __le32 duration;
752} __packed;
753
754/**
755 * struct iwl_lmac_scan_complete_notif - notifies end of scanning (all channels)
756 * SCAN_COMPLETE_NTF_API_S_VER_3
757 * @scanned_channels: number of channels scanned (and number of valid results)
758 * @status: one of SCAN_COMP_STATUS_*
759 * @bt_status: BT on/off status
760 * @last_channel: last channel that was scanned
761 * @tsf_low: TSF timer (lower half) in usecs
762 * @tsf_high: TSF timer (higher half) in usecs
763 * @results: an array of scan results, only "scanned_channels" of them are valid
764 */
765struct iwl_lmac_scan_complete_notif {
766 u8 scanned_channels;
767 u8 status;
768 u8 bt_status;
769 u8 last_channel;
770 __le32 tsf_low;
771 __le32 tsf_high;
772 struct iwl_scan_results_notif results[];
773} __packed;
774
775/**
776 * iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2
777 * @last_schedule_line: last schedule line executed (fast or regular)
778 * @last_schedule_iteration: last scan iteration executed before scan abort
779 * @status: enum iwl_scan_offload_complete_status
780 * @ebs_status: EBS success status &enum iwl_scan_ebs_status
781 * @time_after_last_iter; time in seconds elapsed after last iteration
782 */
783struct iwl_periodic_scan_complete {
784 u8 last_schedule_line;
785 u8 last_schedule_iteration;
786 u8 status;
787 u8 ebs_status;
788 __le32 time_after_last_iter;
789 __le32 reserved;
790} __packed;
791
585#endif 792#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 3983a2beb246..6c479de3b8d4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -135,6 +135,7 @@ enum {
135 SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, 135 SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
136 SCAN_OFFLOAD_CONFIG_CMD = 0x6f, 136 SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
137 MATCH_FOUND_NOTIFICATION = 0xd9, 137 MATCH_FOUND_NOTIFICATION = 0xd9,
138 SCAN_ITERATION_COMPLETE = 0xe7,
138 139
139 /* Phy */ 140 /* Phy */
140 PHY_CONFIGURATION_CMD = 0x6a, 141 PHY_CONFIGURATION_CMD = 0x6a,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 7dde944a68fb..522aa039a490 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -327,6 +327,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
327 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; 327 hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
328 } 328 }
329 329
330 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
331 hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
332
330 hw->sta_data_size = sizeof(struct iwl_mvm_sta); 333 hw->sta_data_size = sizeof(struct iwl_mvm_sta);
331 hw->vif_data_size = sizeof(struct iwl_mvm_vif); 334 hw->vif_data_size = sizeof(struct iwl_mvm_vif);
332 hw->chanctx_data_size = sizeof(u16); 335 hw->chanctx_data_size = sizeof(u16);
@@ -1658,7 +1661,7 @@ static void iwl_mvm_bss_info_changed(struct ieee80211_hw *hw,
1658 mutex_lock(&mvm->mutex); 1661 mutex_lock(&mvm->mutex);
1659 1662
1660 if (changes & BSS_CHANGED_IDLE && !bss_conf->idle) 1663 if (changes & BSS_CHANGED_IDLE && !bss_conf->idle)
1661 iwl_mvm_sched_scan_stop(mvm, true); 1664 iwl_mvm_scan_offload_stop(mvm, true);
1662 1665
1663 switch (vif->type) { 1666 switch (vif->type) {
1664 case NL80211_IFTYPE_STATION: 1667 case NL80211_IFTYPE_STATION:
@@ -1692,7 +1695,7 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
1692 1695
1693 switch (mvm->scan_status) { 1696 switch (mvm->scan_status) {
1694 case IWL_MVM_SCAN_SCHED: 1697 case IWL_MVM_SCAN_SCHED:
1695 ret = iwl_mvm_sched_scan_stop(mvm, true); 1698 ret = iwl_mvm_scan_offload_stop(mvm, true);
1696 if (ret) { 1699 if (ret) {
1697 ret = -EBUSY; 1700 ret = -EBUSY;
1698 goto out; 1701 goto out;
@@ -1707,7 +1710,11 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw,
1707 1710
1708 iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN); 1711 iwl_mvm_ref(mvm, IWL_MVM_REF_SCAN);
1709 1712
1710 ret = iwl_mvm_scan_request(mvm, vif, req); 1713 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
1714 ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req);
1715 else
1716 ret = iwl_mvm_scan_request(mvm, vif, req);
1717
1711 if (ret) 1718 if (ret)
1712 iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); 1719 iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
1713out: 1720out:
@@ -2008,15 +2015,21 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
2008 2015
2009 mvm->scan_status = IWL_MVM_SCAN_SCHED; 2016 mvm->scan_status = IWL_MVM_SCAN_SCHED;
2010 2017
2011 ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); 2018 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
2012 if (ret) 2019 ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
2013 goto err; 2020 if (ret)
2021 goto err;
2022 }
2014 2023
2015 ret = iwl_mvm_config_sched_scan_profiles(mvm, req); 2024 ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
2016 if (ret) 2025 if (ret)
2017 goto err; 2026 goto err;
2018 2027
2019 ret = iwl_mvm_sched_scan_start(mvm, req); 2028 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
2029 ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
2030 else
2031 ret = iwl_mvm_sched_scan_start(mvm, req);
2032
2020 if (!ret) 2033 if (!ret)
2021 goto out; 2034 goto out;
2022err: 2035err:
@@ -2035,7 +2048,7 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
2035 int ret; 2048 int ret;
2036 2049
2037 mutex_lock(&mvm->mutex); 2050 mutex_lock(&mvm->mutex);
2038 ret = iwl_mvm_sched_scan_stop(mvm, false); 2051 ret = iwl_mvm_scan_offload_stop(mvm, false);
2039 mutex_unlock(&mvm->mutex); 2052 mutex_unlock(&mvm->mutex);
2040 iwl_mvm_wait_for_async_handlers(mvm); 2053 iwl_mvm_wait_for_async_handlers(mvm);
2041 2054
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index fbe93a1df93a..927346e1a6e5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -533,7 +533,7 @@ struct iwl_mvm {
533 533
534 /* Scan status, cmd (pre-allocated) and auxiliary station */ 534 /* Scan status, cmd (pre-allocated) and auxiliary station */
535 enum iwl_scan_status scan_status; 535 enum iwl_scan_status scan_status;
536 struct iwl_scan_cmd *scan_cmd; 536 void *scan_cmd;
537 struct iwl_mcast_filter_cmd *mcast_filter_cmd; 537 struct iwl_mcast_filter_cmd *mcast_filter_cmd;
538 538
539 /* rx chain antennas set through debugfs for the scan command */ 539 /* rx chain antennas set through debugfs for the scan command */
@@ -868,10 +868,19 @@ int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
868 struct cfg80211_sched_scan_request *req); 868 struct cfg80211_sched_scan_request *req);
869int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, 869int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
870 struct cfg80211_sched_scan_request *req); 870 struct cfg80211_sched_scan_request *req);
871int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify); 871int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify);
872int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, 872int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
873 struct iwl_rx_cmd_buffer *rxb, 873 struct iwl_rx_cmd_buffer *rxb,
874 struct iwl_device_cmd *cmd); 874 struct iwl_device_cmd *cmd);
875
876/* Unified scan */
877int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
878 struct ieee80211_vif *vif,
879 struct ieee80211_scan_request *req);
880int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
881 struct ieee80211_vif *vif,
882 struct cfg80211_sched_scan_request *req,
883 struct ieee80211_scan_ies *ies);
875 884
876/* MVM debugfs */ 885/* MVM debugfs */
877#ifdef CONFIG_IWLWIFI_DEBUGFS 886#ifdef CONFIG_IWLWIFI_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index b843870be8b7..4e2823faa5b9 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -233,7 +233,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
233 RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true), 233 RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true),
234 RX_HANDLER(SCAN_OFFLOAD_COMPLETE, 234 RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
235 iwl_mvm_rx_scan_offload_complete_notif, true), 235 iwl_mvm_rx_scan_offload_complete_notif, true),
236 RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results, 236 RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results,
237 false), 237 false),
238 238
239 RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), 239 RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
@@ -284,6 +284,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
284 CMD(SCAN_OFFLOAD_ABORT_CMD), 284 CMD(SCAN_OFFLOAD_ABORT_CMD),
285 CMD(SCAN_OFFLOAD_COMPLETE), 285 CMD(SCAN_OFFLOAD_COMPLETE),
286 CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), 286 CMD(SCAN_OFFLOAD_UPDATE_PROFILES_CMD),
287 CMD(SCAN_ITERATION_COMPLETE),
287 CMD(POWER_TABLE_CMD), 288 CMD(POWER_TABLE_CMD),
288 CMD(WEP_KEY), 289 CMD(WEP_KEY),
289 CMD(REPLY_RX_PHY_CMD), 290 CMD(REPLY_RX_PHY_CMD),
@@ -505,10 +506,17 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
505 } 506 }
506 } 507 }
507 508
508 scan_size = sizeof(struct iwl_scan_cmd) + 509 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
509 mvm->fw->ucode_capa.max_probe_length + 510 scan_size = sizeof(struct iwl_scan_req_unified_lmac) +
510 (mvm->fw->ucode_capa.n_scan_channels * 511 sizeof(struct iwl_scan_channel_cfg_lmac) *
511 sizeof(struct iwl_scan_channel)); 512 mvm->fw->ucode_capa.n_scan_channels +
513 sizeof(struct iwl_scan_probe_req);
514 else
515 scan_size = sizeof(struct iwl_scan_cmd) +
516 mvm->fw->ucode_capa.max_probe_length +
517 mvm->fw->ucode_capa.n_scan_channels *
518 sizeof(struct iwl_scan_channel);
519
512 mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); 520 mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL);
513 if (!mvm->scan_cmd) 521 if (!mvm->scan_cmd)
514 goto out_free; 522 goto out_free;
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index f2dde5604a80..919ed0e18bb0 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -97,10 +97,9 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
97 return cpu_to_le16(rx_chain); 97 return cpu_to_le16(rx_chain);
98} 98}
99 99
100static inline __le32 100static __le32 iwl_mvm_scan_rxon_flags(enum ieee80211_band band)
101iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req)
102{ 101{
103 if (req->channels[0]->band == IEEE80211_BAND_2GHZ) 102 if (band == IEEE80211_BAND_2GHZ)
104 return cpu_to_le32(PHY_BAND_24); 103 return cpu_to_le32(PHY_BAND_24);
105 else 104 else
106 return cpu_to_le32(PHY_BAND_5); 105 return cpu_to_le32(PHY_BAND_5);
@@ -130,19 +129,19 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
130 * request list, is not copied here, but inserted directly to the probe 129 * request list, is not copied here, but inserted directly to the probe
131 * request. 130 * request.
132 */ 131 */
133static void iwl_mvm_scan_fill_ssids(struct iwl_scan_cmd *cmd, 132static void iwl_mvm_scan_fill_ssids(struct iwl_ssid_ie *cmd_ssid,
134 struct cfg80211_scan_request *req, 133 struct cfg80211_ssid *ssids,
135 int first) 134 int n_ssids, int first)
136{ 135{
137 int fw_idx, req_idx; 136 int fw_idx, req_idx;
138 137
139 for (req_idx = req->n_ssids - 1, fw_idx = 0; req_idx >= first; 138 for (req_idx = n_ssids - 1, fw_idx = 0; req_idx >= first;
140 req_idx--, fw_idx++) { 139 req_idx--, fw_idx++) {
141 cmd->direct_scan[fw_idx].id = WLAN_EID_SSID; 140 cmd_ssid[fw_idx].id = WLAN_EID_SSID;
142 cmd->direct_scan[fw_idx].len = req->ssids[req_idx].ssid_len; 141 cmd_ssid[fw_idx].len = ssids[req_idx].ssid_len;
143 memcpy(cmd->direct_scan[fw_idx].ssid, 142 memcpy(cmd_ssid[fw_idx].ssid,
144 req->ssids[req_idx].ssid, 143 ssids[req_idx].ssid,
145 req->ssids[req_idx].ssid_len); 144 ssids[req_idx].ssid_len);
146 } 145 }
147} 146}
148 147
@@ -349,7 +348,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
349 if (params.passive_fragmented) 348 if (params.passive_fragmented)
350 cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN; 349 cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
351 350
352 cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req); 351 cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
353 cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP | 352 cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
354 MAC_FILTER_IN_BEACON); 353 MAC_FILTER_IN_BEACON);
355 354
@@ -376,7 +375,8 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
376 cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE; 375 cmd->scan_flags &= ~SCAN_FLAGS_PASSIVE2ACTIVE;
377 } 376 }
378 377
379 iwl_mvm_scan_fill_ssids(cmd, req, basic_ssid ? 1 : 0); 378 iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->ssids, req->n_ssids,
379 basic_ssid ? 1 : 0);
380 380
381 cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL | 381 cmd->tx_cmd.tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
382 TX_CMD_FLG_BT_DIS); 382 TX_CMD_FLG_BT_DIS);
@@ -450,16 +450,27 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
450 return 0; 450 return 0;
451} 451}
452 452
453int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm, 453int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
454 struct iwl_rx_cmd_buffer *rxb, 454 struct iwl_rx_cmd_buffer *rxb,
455 struct iwl_device_cmd *cmd) 455 struct iwl_device_cmd *cmd)
456{ 456{
457 struct iwl_rx_packet *pkt = rxb_addr(rxb); 457 struct iwl_rx_packet *pkt = rxb_addr(rxb);
458 struct iwl_sched_scan_results *notif = (void *)pkt->data; 458 u8 client_bitmap = 0;
459
460 if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
461 struct iwl_sched_scan_results *notif = (void *)pkt->data;
459 462
460 if (notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN) { 463 client_bitmap = notif->client_bitmap;
461 IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); 464 }
462 ieee80211_sched_scan_results(mvm->hw); 465
466 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN ||
467 client_bitmap & SCAN_CLIENT_SCHED_SCAN) {
468 if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
469 IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
470 ieee80211_sched_scan_results(mvm->hw);
471 } else {
472 IWL_DEBUG_SCAN(mvm, "Scan results\n");
473 }
463 } 474 }
464 475
465 return 0; 476 return 0;
@@ -503,7 +514,7 @@ static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
503 }; 514 };
504} 515}
505 516
506int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) 517static int iwl_mvm_cancel_regular_scan(struct iwl_mvm *mvm)
507{ 518{
508 struct iwl_notification_wait wait_scan_abort; 519 struct iwl_notification_wait wait_scan_abort;
509 static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD, 520 static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
@@ -544,26 +555,45 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
544 struct iwl_device_cmd *cmd) 555 struct iwl_device_cmd *cmd)
545{ 556{
546 struct iwl_rx_packet *pkt = rxb_addr(rxb); 557 struct iwl_rx_packet *pkt = rxb_addr(rxb);
547 struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data; 558 u8 status, ebs_status;
559
560 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) {
561 struct iwl_periodic_scan_complete *scan_notif;
548 562
563 scan_notif = (void *)pkt->data;
564 status = scan_notif->status;
565 ebs_status = scan_notif->ebs_status;
566 } else {
567 struct iwl_scan_offload_complete *scan_notif;
568
569 scan_notif = (void *)pkt->data;
570 status = scan_notif->status;
571 ebs_status = scan_notif->ebs_status;
572 }
549 /* scan status must be locked for proper checking */ 573 /* scan status must be locked for proper checking */
550 lockdep_assert_held(&mvm->mutex); 574 lockdep_assert_held(&mvm->mutex);
551 575
552 IWL_DEBUG_SCAN(mvm, 576 IWL_DEBUG_SCAN(mvm,
553 "Scheduled scan completed, status %s EBS status %s:%d\n", 577 "%s completed, status %s, EBS status %s\n",
554 scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? 578 mvm->scan_status == IWL_MVM_SCAN_SCHED ?
555 "completed" : "aborted", scan_notif->ebs_status == 579 "Scheduled scan" : "Scan",
556 IWL_SCAN_EBS_SUCCESS ? "success" : "failed", 580 status == IWL_SCAN_OFFLOAD_COMPLETED ?
557 scan_notif->ebs_status); 581 "completed" : "aborted",
582 ebs_status == IWL_SCAN_EBS_SUCCESS ?
583 "success" : "failed");
558 584
559 585
560 /* only call mac80211 completion if the stop was initiated by FW */ 586 /* only call mac80211 completion if the stop was initiated by FW */
561 if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { 587 if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
562 mvm->scan_status = IWL_MVM_SCAN_NONE; 588 mvm->scan_status = IWL_MVM_SCAN_NONE;
563 ieee80211_sched_scan_stopped(mvm->hw); 589 ieee80211_sched_scan_stopped(mvm->hw);
590 } else if (mvm->scan_status == IWL_MVM_SCAN_OS) {
591 mvm->scan_status = IWL_MVM_SCAN_NONE;
592 ieee80211_scan_completed(mvm->hw,
593 status == IWL_SCAN_OFFLOAD_ABORTED);
564 } 594 }
565 595
566 mvm->last_ebs_successful = !scan_notif->ebs_status; 596 mvm->last_ebs_successful = !ebs_status;
567 597
568 return 0; 598 return 0;
569} 599}
@@ -631,8 +661,8 @@ static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
631} 661}
632 662
633static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req, 663static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
634 struct iwl_scan_offload_cmd *scan, 664 struct iwl_ssid_ie *direct_scan,
635 u32 *ssid_bitmap) 665 u32 *ssid_bitmap, bool basic_ssid)
636{ 666{
637 int i, j; 667 int i, j;
638 int index; 668 int index;
@@ -646,10 +676,10 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
646 /* skip empty SSID matchsets */ 676 /* skip empty SSID matchsets */
647 if (!req->match_sets[i].ssid.ssid_len) 677 if (!req->match_sets[i].ssid.ssid_len)
648 continue; 678 continue;
649 scan->direct_scan[i].id = WLAN_EID_SSID; 679 direct_scan[i].id = WLAN_EID_SSID;
650 scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len; 680 direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
651 memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid, 681 memcpy(direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
652 scan->direct_scan[i].len); 682 direct_scan[i].len);
653 } 683 }
654 684
655 /* add SSIDs from scan SSID list */ 685 /* add SSIDs from scan SSID list */
@@ -657,14 +687,14 @@ static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
657 for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) { 687 for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) {
658 index = iwl_ssid_exist(req->ssids[j].ssid, 688 index = iwl_ssid_exist(req->ssids[j].ssid,
659 req->ssids[j].ssid_len, 689 req->ssids[j].ssid_len,
660 scan->direct_scan); 690 direct_scan);
661 if (index < 0) { 691 if (index < 0) {
662 if (!req->ssids[j].ssid_len) 692 if (!req->ssids[j].ssid_len && basic_ssid)
663 continue; 693 continue;
664 scan->direct_scan[i].id = WLAN_EID_SSID; 694 direct_scan[i].id = WLAN_EID_SSID;
665 scan->direct_scan[i].len = req->ssids[j].ssid_len; 695 direct_scan[i].len = req->ssids[j].ssid_len;
666 memcpy(scan->direct_scan[i].ssid, req->ssids[j].ssid, 696 memcpy(direct_scan[i].ssid, req->ssids[j].ssid,
667 scan->direct_scan[i].len); 697 direct_scan[i].len);
668 *ssid_bitmap |= BIT(i + 1); 698 *ssid_bitmap |= BIT(i + 1);
669 i++; 699 i++;
670 } else { 700 } else {
@@ -734,6 +764,8 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
734 int cmd_len; 764 int cmd_len;
735 int ret; 765 int ret;
736 u8 *probes; 766 u8 *probes;
767 bool basic_ssid = !(mvm->fw->ucode_capa.flags &
768 IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
737 769
738 struct iwl_scan_offload_cfg *scan_cfg; 770 struct iwl_scan_offload_cfg *scan_cfg;
739 struct iwl_host_cmd cmd = { 771 struct iwl_host_cmd cmd = {
@@ -758,7 +790,8 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
758 iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, &params); 790 iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, &params);
759 scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len); 791 scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
760 792
761 iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap); 793 iwl_scan_offload_build_ssid(req, scan_cfg->scan_cmd.direct_scan,
794 &ssid_bitmap, basic_ssid);
762 /* build tx frames for supported bands */ 795 /* build tx frames for supported bands */
763 if (band_2ghz) { 796 if (band_2ghz) {
764 iwl_scan_offload_build_tx_cmd(mvm, vif, ies, 797 iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
@@ -893,7 +926,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
893 sizeof(scan_req), &scan_req); 926 sizeof(scan_req), &scan_req);
894} 927}
895 928
896static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm) 929static int iwl_mvm_send_scan_offload_abort(struct iwl_mvm *mvm)
897{ 930{
898 int ret; 931 int ret;
899 struct iwl_host_cmd cmd = { 932 struct iwl_host_cmd cmd = {
@@ -904,7 +937,9 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm)
904 /* Exit instantly with error when device is not ready 937 /* Exit instantly with error when device is not ready
905 * to receive scan abort command or it does not perform 938 * to receive scan abort command or it does not perform
906 * scheduled scan currently */ 939 * scheduled scan currently */
907 if (mvm->scan_status != IWL_MVM_SCAN_SCHED) 940 if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
941 (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
942 mvm->scan_status != IWL_MVM_SCAN_OS))
908 return -EIO; 943 return -EIO;
909 944
910 ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status); 945 ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
@@ -926,16 +961,19 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm)
926 return ret; 961 return ret;
927} 962}
928 963
929int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify) 964int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
930{ 965{
931 int ret; 966 int ret;
932 struct iwl_notification_wait wait_scan_done; 967 struct iwl_notification_wait wait_scan_done;
933 static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, }; 968 static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };
969 bool sched = mvm->scan_status == IWL_MVM_SCAN_SCHED;
934 970
935 lockdep_assert_held(&mvm->mutex); 971 lockdep_assert_held(&mvm->mutex);
936 972
937 if (mvm->scan_status != IWL_MVM_SCAN_SCHED) { 973 if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
938 IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n"); 974 (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) ||
975 mvm->scan_status != IWL_MVM_SCAN_OS)) {
976 IWL_DEBUG_SCAN(mvm, "No scan to stop\n");
939 return 0; 977 return 0;
940 } 978 }
941 979
@@ -944,14 +982,16 @@ int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify)
944 ARRAY_SIZE(scan_done_notif), 982 ARRAY_SIZE(scan_done_notif),
945 NULL, NULL); 983 NULL, NULL);
946 984
947 ret = iwl_mvm_send_sched_scan_abort(mvm); 985 ret = iwl_mvm_send_scan_offload_abort(mvm);
948 if (ret) { 986 if (ret) {
949 IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret); 987 IWL_DEBUG_SCAN(mvm, "Send stop %sscan failed %d\n",
988 sched ? "offloaded " : "", ret);
950 iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); 989 iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
951 return ret; 990 return ret;
952 } 991 }
953 992
954 IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n"); 993 IWL_DEBUG_SCAN(mvm, "Successfully sent stop %sscan\n",
994 sched ? "offloaded " : "");
955 995
956 ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); 996 ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
957 if (ret) 997 if (ret)
@@ -964,8 +1004,311 @@ int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm, bool notify)
964 */ 1004 */
965 mvm->scan_status = IWL_MVM_SCAN_NONE; 1005 mvm->scan_status = IWL_MVM_SCAN_NONE;
966 1006
967 if (notify) 1007 if (notify) {
968 ieee80211_sched_scan_stopped(mvm->hw); 1008 if (sched)
1009 ieee80211_sched_scan_stopped(mvm->hw);
1010 else
1011 ieee80211_scan_completed(mvm->hw, true);
1012 }
969 1013
970 return 0; 1014 return 0;
971} 1015}
1016
1017static void iwl_mvm_unified_scan_fill_tx_cmd(struct iwl_mvm *mvm,
1018 struct iwl_scan_req_tx_cmd *tx_cmd,
1019 bool no_cck)
1020{
1021 tx_cmd[0].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
1022 TX_CMD_FLG_BT_DIS);
1023 tx_cmd[0].rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm,
1024 IEEE80211_BAND_2GHZ,
1025 no_cck);
1026 tx_cmd[0].sta_id = mvm->aux_sta.sta_id;
1027
1028 tx_cmd[1].tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL |
1029 TX_CMD_FLG_BT_DIS);
1030 tx_cmd[1].rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm,
1031 IEEE80211_BAND_5GHZ,
1032 no_cck);
1033 tx_cmd[1].sta_id = mvm->aux_sta.sta_id;
1034}
1035
1036static void
1037iwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm,
1038 struct ieee80211_channel **channels,
1039 int n_channels, u32 ssid_bitmap,
1040 struct iwl_scan_req_unified_lmac *cmd)
1041{
1042 struct iwl_scan_channel_cfg_lmac *channel_cfg = (void *)&cmd->data;
1043 int i;
1044
1045 for (i = 0; i < n_channels; i++) {
1046 channel_cfg[i].channel_num =
1047 cpu_to_le16(channels[i]->hw_value);
1048 channel_cfg[i].iter_count = cpu_to_le16(1);
1049 channel_cfg[i].iter_interval = 0;
1050 channel_cfg[i].flags =
1051 cpu_to_le32(IWL_UNIFIED_SCAN_CHANNEL_PARTIAL |
1052 ssid_bitmap);
1053 }
1054}
1055
1056static void
1057iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1058 struct ieee80211_scan_ies *ies,
1059 struct iwl_scan_req_unified_lmac *cmd)
1060{
1061 struct iwl_scan_probe_req *preq = (void *)(cmd->data +
1062 sizeof(struct iwl_scan_channel_cfg_lmac) *
1063 mvm->fw->ucode_capa.n_scan_channels);
1064 struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf;
1065 u8 *pos;
1066
1067 frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
1068 eth_broadcast_addr(frame->da);
1069 memcpy(frame->sa, vif->addr, ETH_ALEN);
1070 eth_broadcast_addr(frame->bssid);
1071 frame->seq_ctrl = 0;
1072
1073 pos = frame->u.probe_req.variable;
1074 *pos++ = WLAN_EID_SSID;
1075 *pos++ = 0;
1076
1077 preq->mac_header.offset = 0;
1078 preq->mac_header.len = cpu_to_le16(24 + 2);
1079
1080 memcpy(pos, ies->ies[IEEE80211_BAND_2GHZ],
1081 ies->len[IEEE80211_BAND_2GHZ]);
1082 preq->band_data[0].offset = cpu_to_le16(pos - preq->buf);
1083 preq->band_data[0].len = cpu_to_le16(ies->len[IEEE80211_BAND_2GHZ]);
1084 pos += ies->len[IEEE80211_BAND_2GHZ];
1085
1086 memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ],
1087 ies->len[IEEE80211_BAND_5GHZ]);
1088 preq->band_data[1].offset = cpu_to_le16(pos - preq->buf);
1089 preq->band_data[1].len = cpu_to_le16(ies->len[IEEE80211_BAND_5GHZ]);
1090 pos += ies->len[IEEE80211_BAND_5GHZ];
1091
1092 memcpy(pos, ies->common_ies, ies->common_ie_len);
1093 preq->common_data.offset = cpu_to_le16(pos - preq->buf);
1094 preq->common_data.len = cpu_to_le16(ies->common_ie_len);
1095}
1096
1097static void
1098iwl_mvm_build_generic_unified_scan_cmd(struct iwl_mvm *mvm,
1099 struct iwl_scan_req_unified_lmac *cmd,
1100 struct iwl_mvm_scan_params *params)
1101{
1102 cmd->active_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].active;
1103 cmd->passive_dwell = (u8)params->dwell[IEEE80211_BAND_2GHZ].passive;
1104 /* TODO: Use params; now fragmented isn't used. */
1105 cmd->fragmented_dwell = 0;
1106 cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
1107 cmd->max_out_time = cpu_to_le32(params->max_out_time);
1108 cmd->suspend_time = cpu_to_le32(params->suspend_time);
1109 cmd->scan_prio = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
1110 cmd->channel_opt[0].flags = mvm->last_ebs_successful ?
1111 cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS &
1112 IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE &
1113 IWL_SCAN_CHANNEL_FLAG_CACHE_ADD) :
1114 0;
1115 cmd->channel_opt[0].non_ebs_ratio = 0;
1116 cmd->iter_num = cpu_to_le32(1);
1117 cmd->delay = 0;
1118}
1119
1120int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
1121 struct ieee80211_vif *vif,
1122 struct ieee80211_scan_request *req)
1123{
1124 struct iwl_host_cmd hcmd = {
1125 .id = SCAN_OFFLOAD_REQUEST_CMD,
1126 .len = { sizeof(struct iwl_scan_req_unified_lmac) +
1127 sizeof(struct iwl_scan_channel_cfg_lmac) *
1128 mvm->fw->ucode_capa.n_scan_channels +
1129 sizeof(struct iwl_scan_probe_req), },
1130 .data = { mvm->scan_cmd, },
1131 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
1132 };
1133 struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
1134 struct iwl_mvm_scan_params params = {};
1135 u32 flags;
1136 int ssid_bitmap = 0;
1137 int ret, i;
1138
1139 lockdep_assert_held(&mvm->mutex);
1140
1141 /* we should have failed registration if scan_cmd was NULL */
1142 if (WARN_ON(mvm->scan_cmd == NULL))
1143 return -ENOMEM;
1144
1145 if (WARN_ON_ONCE(req->req.n_ssids > PROBE_OPTION_MAX ||
1146 req->ies.common_ie_len + req->ies.len[0] +
1147 req->ies.len[1] + 24 + 2 >
1148 SCAN_OFFLOAD_PROBE_REQ_SIZE ||
1149 req->req.n_channels >
1150 mvm->fw->ucode_capa.n_scan_channels))
1151 return -1;
1152
1153 mvm->scan_status = IWL_MVM_SCAN_OS;
1154
1155 iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags,
1156 &params);
1157
1158 iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, &params);
1159
1160 cmd->n_channels = (u8)req->req.n_channels;
1161
1162 flags = IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
1163
1164 if (req->req.n_ssids == 1 && req->req.ssids[0].ssid_len != 0)
1165 flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
1166
1167 if (params.passive_fragmented)
1168 flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
1169
1170 if (req->req.n_ssids == 0)
1171 flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
1172
1173 cmd->scan_flags = cpu_to_le32(flags);
1174
1175 cmd->flags = iwl_mvm_scan_rxon_flags(req->req.channels[0]->band);
1176 cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
1177 MAC_FILTER_IN_BEACON);
1178 iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, req->req.no_cck);
1179 iwl_mvm_scan_fill_ssids(cmd->direct_scan, req->req.ssids,
1180 req->req.n_ssids, 0);
1181
1182 cmd->schedule[0].delay = 0;
1183 cmd->schedule[0].iterations = 1;
1184 cmd->schedule[0].full_scan_mul = 0;
1185 cmd->schedule[1].delay = 0;
1186 cmd->schedule[1].iterations = 0;
1187 cmd->schedule[1].full_scan_mul = 0;
1188
1189 for (i = 1; i <= req->req.n_ssids; i++)
1190 ssid_bitmap |= BIT(i);
1191
1192 iwl_mvm_lmac_scan_cfg_channels(mvm, req->req.channels,
1193 req->req.n_channels, ssid_bitmap,
1194 cmd);
1195
1196 iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, cmd);
1197
1198 ret = iwl_mvm_send_cmd(mvm, &hcmd);
1199 if (!ret) {
1200 IWL_DEBUG_SCAN(mvm, "Scan request was sent successfully\n");
1201 } else {
1202 /*
1203 * If the scan failed, it usually means that the FW was unable
1204 * to allocate the time events. Warn on it, but maybe we
1205 * should try to send the command again with different params.
1206 */
1207 IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
1208 mvm->scan_status = IWL_MVM_SCAN_NONE;
1209 ret = -EIO;
1210 }
1211 return ret;
1212}
1213
1214int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
1215 struct ieee80211_vif *vif,
1216 struct cfg80211_sched_scan_request *req,
1217 struct ieee80211_scan_ies *ies)
1218{
1219 struct iwl_host_cmd hcmd = {
1220 .id = SCAN_OFFLOAD_REQUEST_CMD,
1221 .len = { sizeof(struct iwl_scan_req_unified_lmac) +
1222 sizeof(struct iwl_scan_channel_cfg_lmac) *
1223 mvm->fw->ucode_capa.n_scan_channels +
1224 sizeof(struct iwl_scan_probe_req), },
1225 .data = { mvm->scan_cmd, },
1226 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
1227 };
1228 struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
1229 struct iwl_mvm_scan_params params = {};
1230 int ret;
1231 u32 flags = 0, ssid_bitmap = 0;
1232
1233 lockdep_assert_held(&mvm->mutex);
1234
1235 /* we should have failed registration if scan_cmd was NULL */
1236 if (WARN_ON(mvm->scan_cmd == NULL))
1237 return -ENOMEM;
1238
1239 if (WARN_ON_ONCE(req->n_ssids > PROBE_OPTION_MAX ||
1240 ies->common_ie_len + ies->len[0] + ies->len[1] + 24 + 2
1241 > SCAN_OFFLOAD_PROBE_REQ_SIZE ||
1242 req->n_channels > mvm->fw->ucode_capa.n_scan_channels))
1243 return -ENOBUFS;
1244
1245 iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, 0, &params);
1246
1247 iwl_mvm_build_generic_unified_scan_cmd(mvm, cmd, &params);
1248
1249 cmd->n_channels = (u8)req->n_channels;
1250
1251 if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) {
1252 IWL_DEBUG_SCAN(mvm,
1253 "Sending scheduled scan with filtering, n_match_sets %d\n",
1254 req->n_match_sets);
1255 } else {
1256 IWL_DEBUG_SCAN(mvm,
1257 "Sending Scheduled scan without filtering\n");
1258 flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
1259 }
1260
1261 if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0)
1262 flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
1263
1264 if (params.passive_fragmented)
1265 flags |= IWL_MVM_LMAC_SCAN_FLAG_FRAGMENTED;
1266
1267 if (req->n_ssids == 0)
1268 flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
1269
1270 cmd->scan_flags = cpu_to_le32(flags);
1271
1272 cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
1273 cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
1274 MAC_FILTER_IN_BEACON);
1275 iwl_mvm_unified_scan_fill_tx_cmd(mvm, cmd->tx_cmd, false);
1276 iwl_scan_offload_build_ssid(req, cmd->direct_scan, &ssid_bitmap, false);
1277
1278 cmd->schedule[0].delay = req->interval / MSEC_PER_SEC;
1279 cmd->schedule[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS;
1280 cmd->schedule[0].full_scan_mul = 1;
1281
1282 cmd->schedule[1].delay = req->interval / MSEC_PER_SEC;
1283 cmd->schedule[1].iterations = 0xff;
1284 cmd->schedule[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER;
1285
1286 iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels,
1287 ssid_bitmap, cmd);
1288
1289 iwl_mvm_build_unified_scan_probe(mvm, vif, ies, cmd);
1290
1291 ret = iwl_mvm_send_cmd(mvm, &hcmd);
1292 if (!ret) {
1293 IWL_DEBUG_SCAN(mvm,
1294 "Sched scan request was sent successfully\n");
1295 } else {
1296 /*
1297 * If the scan failed, it usually means that the FW was unable
1298 * to allocate the time events. Warn on it, but maybe we
1299 * should try to send the command again with different params.
1300 */
1301 IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret);
1302 mvm->scan_status = IWL_MVM_SCAN_NONE;
1303 ret = -EIO;
1304 }
1305 return ret;
1306}
1307
1308
1309int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
1310{
1311 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
1312 return iwl_mvm_scan_offload_stop(mvm, true);
1313 return iwl_mvm_cancel_regular_scan(mvm);
1314}