diff options
author | David Spinadel <david.spinadel@intel.com> | 2014-05-20 05:46:37 -0400 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-11-23 13:02:43 -0500 |
commit | d24962214dd5930aa713213654721fe1fd7ed844 (patch) | |
tree | cd5fd7f8ddcd49aac5f5ee1cfcf487a4efe0c0e7 | |
parent | 5387b348b7af299c2aa8e0318498fa7d889da4fd (diff) |
iwlwifi: mvm: implement UMAC scan API
This API uses second CPU scan commands, and can support multiple
simultaneous scans.
Adding the new API, and adding new mechanisms to deal with up to
8 simultaneous scans instead of the old scan status.
New scan API requires scan configuration for default scan parameters,
adding it in _up flow. Also updating scan configuration after updating
valid scan antennas via debugfs.
Signed-off-by: David Spinadel <david.spinadel@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-fw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/debugfs.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | 253 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw-api.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/fw.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 16 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/ops.c | 17 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/scan.c | 669 |
9 files changed, 942 insertions, 58 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 598065b053de..133022a7bf6f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -145,6 +145,7 @@ enum iwl_ucode_tlv_api { | |||
145 | /** | 145 | /** |
146 | * enum iwl_ucode_tlv_capa - ucode capabilities | 146 | * enum iwl_ucode_tlv_capa - ucode capabilities |
147 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 | 147 | * @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3 |
148 | * @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan. | ||
148 | * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current | 149 | * @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current |
149 | * tx power value into TPC Report action frame and Link Measurement Report | 150 | * tx power value into TPC Report action frame and Link Measurement Report |
150 | * action frame | 151 | * action frame |
@@ -158,6 +159,7 @@ enum iwl_ucode_tlv_api { | |||
158 | */ | 159 | */ |
159 | enum iwl_ucode_tlv_capa { | 160 | enum iwl_ucode_tlv_capa { |
160 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | 161 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), |
162 | IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2), | ||
161 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), | 163 | IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8), |
162 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), | 164 | IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9), |
163 | IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), | 165 | IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), |
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index 51b7116965ed..8212b00096f9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c | |||
@@ -936,7 +936,11 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, | |||
936 | if (scan_rx_ant & ~mvm->fw->valid_rx_ant) | 936 | if (scan_rx_ant & ~mvm->fw->valid_rx_ant) |
937 | return -EINVAL; | 937 | return -EINVAL; |
938 | 938 | ||
939 | mvm->scan_rx_ant = scan_rx_ant; | 939 | if (mvm->scan_rx_ant != scan_rx_ant) { |
940 | mvm->scan_rx_ant = scan_rx_ant; | ||
941 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
942 | iwl_mvm_config_scan(mvm); | ||
943 | } | ||
940 | 944 | ||
941 | return count; | 945 | return count; |
942 | } | 946 | } |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index 1354c68f6468..7163eb391826 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h | |||
@@ -794,4 +794,257 @@ struct iwl_periodic_scan_complete { | |||
794 | __le32 reserved; | 794 | __le32 reserved; |
795 | } __packed; | 795 | } __packed; |
796 | 796 | ||
797 | /* UMAC Scan API */ | ||
798 | |||
799 | /** | ||
800 | * struct iwl_mvm_umac_cmd_hdr - Command header for UMAC commands | ||
801 | * @size: size of the command (not including header) | ||
802 | * @reserved0: for future use and alignment | ||
803 | * @ver: API version number | ||
804 | */ | ||
805 | struct iwl_mvm_umac_cmd_hdr { | ||
806 | __le16 size; | ||
807 | u8 reserved0; | ||
808 | u8 ver; | ||
809 | } __packed; | ||
810 | |||
811 | #define IWL_MVM_MAX_SIMULTANEOUS_SCANS 8 | ||
812 | |||
813 | enum scan_config_flags { | ||
814 | SCAN_CONFIG_FLAG_ACTIVATE = BIT(0), | ||
815 | SCAN_CONFIG_FLAG_DEACTIVATE = BIT(1), | ||
816 | SCAN_CONFIG_FLAG_FORBID_CHUB_REQS = BIT(2), | ||
817 | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS = BIT(3), | ||
818 | SCAN_CONFIG_FLAG_SET_TX_CHAINS = BIT(8), | ||
819 | SCAN_CONFIG_FLAG_SET_RX_CHAINS = BIT(9), | ||
820 | SCAN_CONFIG_FLAG_SET_AUX_STA_ID = BIT(10), | ||
821 | SCAN_CONFIG_FLAG_SET_ALL_TIMES = BIT(11), | ||
822 | SCAN_CONFIG_FLAG_SET_EFFECTIVE_TIMES = BIT(12), | ||
823 | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS = BIT(13), | ||
824 | SCAN_CONFIG_FLAG_SET_LEGACY_RATES = BIT(14), | ||
825 | SCAN_CONFIG_FLAG_SET_MAC_ADDR = BIT(15), | ||
826 | SCAN_CONFIG_FLAG_SET_FRAGMENTED = BIT(16), | ||
827 | SCAN_CONFIG_FLAG_CLEAR_FRAGMENTED = BIT(17), | ||
828 | SCAN_CONFIG_FLAG_SET_CAM_MODE = BIT(18), | ||
829 | SCAN_CONFIG_FLAG_CLEAR_CAM_MODE = BIT(19), | ||
830 | SCAN_CONFIG_FLAG_SET_PROMISC_MODE = BIT(20), | ||
831 | SCAN_CONFIG_FLAG_CLEAR_PROMISC_MODE = BIT(21), | ||
832 | |||
833 | /* Bits 26-31 are for num of channels in channel_array */ | ||
834 | #define SCAN_CONFIG_N_CHANNELS(n) ((n) << 26) | ||
835 | }; | ||
836 | |||
837 | enum scan_config_rates { | ||
838 | /* OFDM basic rates */ | ||
839 | SCAN_CONFIG_RATE_6M = BIT(0), | ||
840 | SCAN_CONFIG_RATE_9M = BIT(1), | ||
841 | SCAN_CONFIG_RATE_12M = BIT(2), | ||
842 | SCAN_CONFIG_RATE_18M = BIT(3), | ||
843 | SCAN_CONFIG_RATE_24M = BIT(4), | ||
844 | SCAN_CONFIG_RATE_36M = BIT(5), | ||
845 | SCAN_CONFIG_RATE_48M = BIT(6), | ||
846 | SCAN_CONFIG_RATE_54M = BIT(7), | ||
847 | /* CCK basic rates */ | ||
848 | SCAN_CONFIG_RATE_1M = BIT(8), | ||
849 | SCAN_CONFIG_RATE_2M = BIT(9), | ||
850 | SCAN_CONFIG_RATE_5M = BIT(10), | ||
851 | SCAN_CONFIG_RATE_11M = BIT(11), | ||
852 | |||
853 | /* Bits 16-27 are for supported rates */ | ||
854 | #define SCAN_CONFIG_SUPPORTED_RATE(rate) ((rate) << 16) | ||
855 | }; | ||
856 | |||
857 | enum iwl_channel_flags { | ||
858 | IWL_CHANNEL_FLAG_EBS = BIT(0), | ||
859 | IWL_CHANNEL_FLAG_ACCURATE_EBS = BIT(1), | ||
860 | IWL_CHANNEL_FLAG_EBS_ADD = BIT(2), | ||
861 | IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE = BIT(3), | ||
862 | }; | ||
863 | |||
864 | /** | ||
865 | * struct iwl_scan_config | ||
866 | * @hdr: umac command header | ||
867 | * @flags: enum scan_config_flags | ||
868 | * @tx_chains: valid_tx antenna - ANT_* definitions | ||
869 | * @rx_chains: valid_rx antenna - ANT_* definitions | ||
870 | * @legacy_rates: default legacy rates - enum scan_config_rates | ||
871 | * @out_of_channel_time: default max out of serving channel time | ||
872 | * @suspend_time: default max suspend time | ||
873 | * @dwell_active: default dwell time for active scan | ||
874 | * @dwell_passive: default dwell time for passive scan | ||
875 | * @dwell_fragmented: default dwell time for fragmented scan | ||
876 | * @reserved: for future use and alignment | ||
877 | * @mac_addr: default mac address to be used in probes | ||
878 | * @bcast_sta_id: the index of the station in the fw | ||
879 | * @channel_flags: default channel flags - enum iwl_channel_flags | ||
880 | * scan_config_channel_flag | ||
881 | * @channel_array: default supported channels | ||
882 | */ | ||
883 | struct iwl_scan_config { | ||
884 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
885 | __le32 flags; | ||
886 | __le32 tx_chains; | ||
887 | __le32 rx_chains; | ||
888 | __le32 legacy_rates; | ||
889 | __le32 out_of_channel_time; | ||
890 | __le32 suspend_time; | ||
891 | u8 dwell_active; | ||
892 | u8 dwell_passive; | ||
893 | u8 dwell_fragmented; | ||
894 | u8 reserved; | ||
895 | u8 mac_addr[ETH_ALEN]; | ||
896 | u8 bcast_sta_id; | ||
897 | u8 channel_flags; | ||
898 | u8 channel_array[]; | ||
899 | } __packed; /* SCAN_CONFIG_DB_CMD_API_S */ | ||
900 | |||
901 | /** | ||
902 | * iwl_umac_scan_flags | ||
903 | *@IWL_UMAC_SCAN_FLAG_PREEMPTIVE: scan process triggered by this scan request | ||
904 | * can be preempted by other scan requests with higher priority. | ||
905 | * The low priority scan is aborted. | ||
906 | *@IWL_UMAC_SCAN_FLAG_START_NOTIF: notification will be sent to the driver | ||
907 | * when scan starts. | ||
908 | */ | ||
909 | enum iwl_umac_scan_flags { | ||
910 | IWL_UMAC_SCAN_FLAG_PREEMPTIVE = BIT(0), | ||
911 | IWL_UMAC_SCAN_FLAG_START_NOTIF = BIT(1), | ||
912 | }; | ||
913 | |||
914 | enum iwl_umac_scan_uid_offsets { | ||
915 | IWL_UMAC_SCAN_UID_TYPE_OFFSET = 0, | ||
916 | IWL_UMAC_SCAN_UID_SEQ_OFFSET = 8, | ||
917 | }; | ||
918 | |||
919 | enum iwl_umac_scan_general_flags { | ||
920 | IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC = BIT(0), | ||
921 | IWL_UMAC_SCAN_GEN_FLAGS_OVER_BT = BIT(1), | ||
922 | IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL = BIT(2), | ||
923 | IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE = BIT(3), | ||
924 | IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT = BIT(4), | ||
925 | IWL_UMAC_SCAN_GEN_FLAGS_ITER_COMPLETE = BIT(5), | ||
926 | IWL_UMAC_SCAN_GEN_FLAGS_MULTIPLE_SSID = BIT(6), | ||
927 | IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED = BIT(7), | ||
928 | IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED = BIT(8), | ||
929 | IWL_UMAC_SCAN_GEN_FLAGS_MATCH = BIT(9) | ||
930 | }; | ||
931 | |||
932 | /** | ||
933 | * struct iwl_scan_channel_cfg_umac | ||
934 | * @flags: bitmap - 0-19: directed scan to i'th ssid. | ||
935 | * @channel_num: channel number 1-13 etc. | ||
936 | * @iter_count: repetition count for the channel. | ||
937 | * @iter_interval: interval between two scan interations on one channel. | ||
938 | */ | ||
939 | struct iwl_scan_channel_cfg_umac { | ||
940 | __le32 flags; | ||
941 | u8 channel_num; | ||
942 | u8 iter_count; | ||
943 | __le16 iter_interval; | ||
944 | } __packed; /* SCAN_CHANNEL_CFG_S_VER2 */ | ||
945 | |||
946 | /** | ||
947 | * struct iwl_scan_umac_schedule | ||
948 | * @interval: interval in seconds between scan iterations | ||
949 | * @iter_count: num of scan iterations for schedule plan, 0xff for infinite loop | ||
950 | * @reserved: for alignment and future use | ||
951 | */ | ||
952 | struct iwl_scan_umac_schedule { | ||
953 | __le16 interval; | ||
954 | u8 iter_count; | ||
955 | u8 reserved; | ||
956 | } __packed; /* SCAN_SCHED_PARAM_API_S_VER_1 */ | ||
957 | |||
958 | /** | ||
959 | * struct iwl_scan_req_umac_tail - the rest of the UMAC scan request command | ||
960 | * parameters following channels configuration array. | ||
961 | * @schedule: two scheduling plans. | ||
962 | * @delay: delay in TUs before starting the first scan iteration | ||
963 | * @reserved: for future use and alignment | ||
964 | * @preq: probe request with IEs blocks | ||
965 | * @direct_scan: list of SSIDs for directed active scan | ||
966 | */ | ||
967 | struct iwl_scan_req_umac_tail { | ||
968 | /* SCAN_PERIODIC_PARAMS_API_S_VER_1 */ | ||
969 | struct iwl_scan_umac_schedule schedule[2]; | ||
970 | __le16 delay; | ||
971 | __le16 reserved; | ||
972 | /* SCAN_PROBE_PARAMS_API_S_VER_1 */ | ||
973 | struct iwl_scan_probe_req preq; | ||
974 | struct iwl_ssid_ie direct_scan[PROBE_OPTION_MAX]; | ||
975 | } __packed; | ||
976 | |||
977 | /** | ||
978 | * struct iwl_scan_req_umac | ||
979 | * @hdr: umac command header | ||
980 | * @flags: &enum iwl_umac_scan_flags | ||
981 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
982 | * @ooc_priority: out of channel priority - &enum iwl_scan_priority | ||
983 | * @general_flags: &enum iwl_umac_scan_general_flags | ||
984 | * @reserved1: for future use and alignment | ||
985 | * @active_dwell: dwell time for active scan | ||
986 | * @passive_dwell: dwell time for passive scan | ||
987 | * @fragmented_dwell: dwell time for fragmented passive scan | ||
988 | * @max_out_time: max out of serving channel time | ||
989 | * @suspend_time: max suspend time | ||
990 | * @scan_priority: scan internal prioritization &enum iwl_scan_priority | ||
991 | * @channel_flags: &enum iwl_scan_channel_flags | ||
992 | * @n_channels: num of channels in scan request | ||
993 | * @reserved2: for future use and alignment | ||
994 | * @data: &struct iwl_scan_channel_cfg_umac and | ||
995 | * &struct iwl_scan_req_umac_tail | ||
996 | */ | ||
997 | struct iwl_scan_req_umac { | ||
998 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
999 | __le32 flags; | ||
1000 | __le32 uid; | ||
1001 | __le32 ooc_priority; | ||
1002 | /* SCAN_GENERAL_PARAMS_API_S_VER_1 */ | ||
1003 | __le32 general_flags; | ||
1004 | u8 reserved1; | ||
1005 | u8 active_dwell; | ||
1006 | u8 passive_dwell; | ||
1007 | u8 fragmented_dwell; | ||
1008 | __le32 max_out_time; | ||
1009 | __le32 suspend_time; | ||
1010 | __le32 scan_priority; | ||
1011 | /* SCAN_CHANNEL_PARAMS_API_S_VER_1 */ | ||
1012 | u8 channel_flags; | ||
1013 | u8 n_channels; | ||
1014 | __le16 reserved2; | ||
1015 | u8 data[]; | ||
1016 | } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_1 */ | ||
1017 | |||
1018 | /** | ||
1019 | * struct iwl_umac_scan_abort | ||
1020 | * @hdr: umac command header | ||
1021 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
1022 | * @flags: reserved | ||
1023 | */ | ||
1024 | struct iwl_umac_scan_abort { | ||
1025 | struct iwl_mvm_umac_cmd_hdr hdr; | ||
1026 | __le32 uid; | ||
1027 | __le32 flags; | ||
1028 | } __packed; /* SCAN_ABORT_CMD_UMAC_API_S_VER_1 */ | ||
1029 | |||
1030 | /** | ||
1031 | * struct iwl_umac_scan_complete | ||
1032 | * @uid: scan id, &enum iwl_umac_scan_uid_offsets | ||
1033 | * @last_schedule: last scheduling line | ||
1034 | * @last_iter: last scan iteration number | ||
1035 | * @scan status: &enum iwl_scan_offload_complete_status | ||
1036 | * @ebs_status: &enum iwl_scan_ebs_status | ||
1037 | * @time_from_last_iter: time elapsed from last iteration | ||
1038 | * @reserved: for future use | ||
1039 | */ | ||
1040 | struct iwl_umac_scan_complete { | ||
1041 | __le32 uid; | ||
1042 | u8 last_schedule; | ||
1043 | u8 last_iter; | ||
1044 | u8 status; | ||
1045 | u8 ebs_status; | ||
1046 | __le32 time_from_last_iter; | ||
1047 | __le32 reserved; | ||
1048 | } __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */ | ||
1049 | |||
797 | #endif | 1050 | #endif |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index c62575d86bcd..1a67788e55f5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h | |||
@@ -106,6 +106,12 @@ enum { | |||
106 | DBG_CFG = 0x9, | 106 | DBG_CFG = 0x9, |
107 | ANTENNA_COUPLING_NOTIFICATION = 0xa, | 107 | ANTENNA_COUPLING_NOTIFICATION = 0xa, |
108 | 108 | ||
109 | /* UMAC scan commands */ | ||
110 | SCAN_CFG_CMD = 0xc, | ||
111 | SCAN_REQ_UMAC = 0xd, | ||
112 | SCAN_ABORT_UMAC = 0xe, | ||
113 | SCAN_COMPLETE_UMAC = 0xf, | ||
114 | |||
109 | /* station table */ | 115 | /* station table */ |
110 | ADD_STA_KEY = 0x17, | 116 | ADD_STA_KEY = 0x17, |
111 | ADD_STA = 0x18, | 117 | ADD_STA = 0x18, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index f12b43d65f66..b4f244f510ed 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c | |||
@@ -505,6 +505,12 @@ int iwl_mvm_up(struct iwl_mvm *mvm) | |||
505 | if (ret) | 505 | if (ret) |
506 | goto error; | 506 | goto error; |
507 | 507 | ||
508 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | ||
509 | ret = iwl_mvm_config_scan(mvm); | ||
510 | if (ret) | ||
511 | goto error; | ||
512 | } | ||
513 | |||
508 | /* allow FW/transport low power modes if not during restart */ | 514 | /* allow FW/transport low power modes if not during restart */ |
509 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) | 515 | if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) |
510 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); | 516 | iwl_mvm_unref(mvm, IWL_MVM_REF_UCODE_DOWN); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index e3259b61b9e8..79ad6958255c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -343,7 +343,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
343 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; | 343 | hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP; |
344 | } | 344 | } |
345 | 345 | ||
346 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 346 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || |
347 | mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
347 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; | 348 | hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS; |
348 | 349 | ||
349 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); | 350 | hw->sta_data_size = sizeof(struct iwl_mvm_sta); |
@@ -1935,9 +1936,11 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1935 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) | 1936 | req->n_channels > mvm->fw->ucode_capa.n_scan_channels) |
1936 | return -EINVAL; | 1937 | return -EINVAL; |
1937 | 1938 | ||
1938 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); | 1939 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { |
1939 | if (ret) | 1940 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_SCHED); |
1940 | return ret; | 1941 | if (ret) |
1942 | return ret; | ||
1943 | } | ||
1941 | 1944 | ||
1942 | mutex_lock(&mvm->mutex); | 1945 | mutex_lock(&mvm->mutex); |
1943 | 1946 | ||
@@ -1950,6 +1953,8 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
1950 | 1953 | ||
1951 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 1954 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) |
1952 | ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); | 1955 | ret = iwl_mvm_unified_scan_lmac(mvm, vif, hw_req); |
1956 | else if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
1957 | ret = iwl_mvm_scan_umac(mvm, vif, hw_req); | ||
1953 | else | 1958 | else |
1954 | ret = iwl_mvm_scan_request(mvm, vif, req); | 1959 | ret = iwl_mvm_scan_request(mvm, vif, req); |
1955 | 1960 | ||
@@ -2247,9 +2252,11 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
2247 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2252 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2248 | int ret; | 2253 | int ret; |
2249 | 2254 | ||
2250 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); | 2255 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)) { |
2251 | if (ret) | 2256 | ret = iwl_mvm_cancel_scan_wait_notif(mvm, IWL_MVM_SCAN_OS); |
2252 | return ret; | 2257 | if (ret) |
2258 | return ret; | ||
2259 | } | ||
2253 | 2260 | ||
2254 | mutex_lock(&mvm->mutex); | 2261 | mutex_lock(&mvm->mutex); |
2255 | 2262 | ||
@@ -2269,11 +2276,10 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
2269 | goto out; | 2276 | goto out; |
2270 | } | 2277 | } |
2271 | 2278 | ||
2272 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
2273 | |||
2274 | ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies); | 2279 | ret = iwl_mvm_scan_offload_start(mvm, vif, req, ies); |
2275 | if (ret) | 2280 | if (ret) |
2276 | mvm->scan_status = IWL_MVM_SCAN_NONE; | 2281 | mvm->scan_status = IWL_MVM_SCAN_NONE; |
2282 | |||
2277 | out: | 2283 | out: |
2278 | mutex_unlock(&mvm->mutex); | 2284 | mutex_unlock(&mvm->mutex); |
2279 | return ret; | 2285 | return ret; |
@@ -2291,6 +2297,7 @@ static int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, | |||
2291 | iwl_mvm_wait_for_async_handlers(mvm); | 2297 | iwl_mvm_wait_for_async_handlers(mvm); |
2292 | 2298 | ||
2293 | return ret; | 2299 | return ret; |
2300 | |||
2294 | } | 2301 | } |
2295 | 2302 | ||
2296 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, | 2303 | static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 09b49b407a5b..cbfba80a0e2f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -588,6 +588,10 @@ struct iwl_mvm { | |||
588 | void *scan_cmd; | 588 | void *scan_cmd; |
589 | struct iwl_mcast_filter_cmd *mcast_filter_cmd; | 589 | struct iwl_mcast_filter_cmd *mcast_filter_cmd; |
590 | 590 | ||
591 | /* UMAC scan tracking */ | ||
592 | u32 scan_uid[IWL_MVM_MAX_SIMULTANEOUS_SCANS]; | ||
593 | u8 scan_seq_num, sched_scan_seq_num; | ||
594 | |||
591 | /* rx chain antennas set through debugfs for the scan command */ | 595 | /* rx chain antennas set through debugfs for the scan command */ |
592 | u8 scan_rx_ant; | 596 | u8 scan_rx_ant; |
593 | 597 | ||
@@ -943,6 +947,7 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm, | |||
943 | struct ieee80211_vif *disabled_vif); | 947 | struct ieee80211_vif *disabled_vif); |
944 | 948 | ||
945 | /* Scanning */ | 949 | /* Scanning */ |
950 | int iwl_mvm_scan_size(struct iwl_mvm *mvm); | ||
946 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, | 951 | int iwl_mvm_scan_request(struct iwl_mvm *mvm, |
947 | struct ieee80211_vif *vif, | 952 | struct ieee80211_vif *vif, |
948 | struct cfg80211_scan_request *req); | 953 | struct cfg80211_scan_request *req); |
@@ -983,6 +988,17 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
983 | struct cfg80211_sched_scan_request *req, | 988 | struct cfg80211_sched_scan_request *req, |
984 | struct ieee80211_scan_ies *ies); | 989 | struct ieee80211_scan_ies *ies); |
985 | 990 | ||
991 | /* UMAC scan */ | ||
992 | int iwl_mvm_config_scan(struct iwl_mvm *mvm); | ||
993 | int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
994 | struct ieee80211_scan_request *req); | ||
995 | int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
996 | struct cfg80211_sched_scan_request *req, | ||
997 | struct ieee80211_scan_ies *ies); | ||
998 | int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, | ||
999 | struct iwl_rx_cmd_buffer *rxb, | ||
1000 | struct iwl_device_cmd *cmd); | ||
1001 | |||
986 | /* MVM debugfs */ | 1002 | /* MVM debugfs */ |
987 | #ifdef CONFIG_IWLWIFI_DEBUGFS | 1003 | #ifdef CONFIG_IWLWIFI_DEBUGFS |
988 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); | 1004 | int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 53a5a29897b4..5ab10fb9d672 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -244,6 +244,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
244 | iwl_mvm_rx_scan_offload_complete_notif, true), | 244 | iwl_mvm_rx_scan_offload_complete_notif, true), |
245 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, | 245 | RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results, |
246 | false), | 246 | false), |
247 | RX_HANDLER(SCAN_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_complete_notif, | ||
248 | true), | ||
247 | 249 | ||
248 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), | 250 | RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), |
249 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), | 251 | RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), |
@@ -346,6 +348,10 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
346 | CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), | 348 | CMD(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), |
347 | CMD(ANTENNA_COUPLING_NOTIFICATION), | 349 | CMD(ANTENNA_COUPLING_NOTIFICATION), |
348 | CMD(SCD_QUEUE_CFG), | 350 | CMD(SCD_QUEUE_CFG), |
351 | CMD(SCAN_CFG_CMD), | ||
352 | CMD(SCAN_REQ_UMAC), | ||
353 | CMD(SCAN_ABORT_UMAC), | ||
354 | CMD(SCAN_COMPLETE_UMAC), | ||
349 | }; | 355 | }; |
350 | #undef CMD | 356 | #undef CMD |
351 | 357 | ||
@@ -537,16 +543,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
537 | } | 543 | } |
538 | } | 544 | } |
539 | 545 | ||
540 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | 546 | scan_size = iwl_mvm_scan_size(mvm); |
541 | scan_size = sizeof(struct iwl_scan_req_unified_lmac) + | ||
542 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
543 | mvm->fw->ucode_capa.n_scan_channels + | ||
544 | sizeof(struct iwl_scan_probe_req); | ||
545 | else | ||
546 | scan_size = sizeof(struct iwl_scan_cmd) + | ||
547 | mvm->fw->ucode_capa.max_probe_length + | ||
548 | mvm->fw->ucode_capa.n_scan_channels * | ||
549 | sizeof(struct iwl_scan_channel); | ||
550 | 547 | ||
551 | mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); | 548 | mvm->scan_cmd = kmalloc(scan_size, GFP_KERNEL); |
552 | if (!mvm->scan_cmd) | 549 | if (!mvm->scan_cmd) |
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 8a1f4a8e80e7..c440b7b3ea4f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c | |||
@@ -83,15 +83,29 @@ struct iwl_mvm_scan_params { | |||
83 | } dwell[IEEE80211_NUM_BANDS]; | 83 | } dwell[IEEE80211_NUM_BANDS]; |
84 | }; | 84 | }; |
85 | 85 | ||
86 | enum iwl_umac_scan_uid_type { | ||
87 | IWL_UMAC_SCAN_UID_REG_SCAN = BIT(0), | ||
88 | IWL_UMAC_SCAN_UID_SCHED_SCAN = BIT(1), | ||
89 | IWL_UMAC_SCAN_UID_ALL = IWL_UMAC_SCAN_UID_REG_SCAN | | ||
90 | IWL_UMAC_SCAN_UID_SCHED_SCAN, | ||
91 | }; | ||
92 | |||
93 | static int iwl_umac_scan_stop(struct iwl_mvm *mvm, | ||
94 | enum iwl_umac_scan_uid_type type, bool notify); | ||
95 | |||
96 | static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm) | ||
97 | { | ||
98 | if (mvm->scan_rx_ant != ANT_NONE) | ||
99 | return mvm->scan_rx_ant; | ||
100 | return mvm->fw->valid_rx_ant; | ||
101 | } | ||
102 | |||
86 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) | 103 | static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) |
87 | { | 104 | { |
88 | u16 rx_chain; | 105 | u16 rx_chain; |
89 | u8 rx_ant; | 106 | u8 rx_ant; |
90 | 107 | ||
91 | if (mvm->scan_rx_ant != ANT_NONE) | 108 | rx_ant = iwl_mvm_scan_rx_ant(mvm); |
92 | rx_ant = mvm->scan_rx_ant; | ||
93 | else | ||
94 | rx_ant = mvm->fw->valid_rx_ant; | ||
95 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; | 109 | rx_chain = rx_ant << PHY_RX_CHAIN_VALID_POS; |
96 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; | 110 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_MIMO_SEL_POS; |
97 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; | 111 | rx_chain |= rx_ant << PHY_RX_CHAIN_FORCE_SEL_POS; |
@@ -541,23 +555,17 @@ int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm, | |||
541 | struct iwl_device_cmd *cmd) | 555 | struct iwl_device_cmd *cmd) |
542 | { | 556 | { |
543 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | 557 | struct iwl_rx_packet *pkt = rxb_addr(rxb); |
544 | u8 client_bitmap = 0; | ||
545 | 558 | ||
546 | if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | 559 | if (!(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) && |
560 | !(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | ||
547 | struct iwl_sched_scan_results *notif = (void *)pkt->data; | 561 | struct iwl_sched_scan_results *notif = (void *)pkt->data; |
548 | 562 | ||
549 | client_bitmap = notif->client_bitmap; | 563 | if (!(notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN)) |
564 | return 0; | ||
550 | } | 565 | } |
551 | 566 | ||
552 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || | 567 | IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); |
553 | client_bitmap & SCAN_CLIENT_SCHED_SCAN) { | 568 | ieee80211_sched_scan_results(mvm->hw); |
554 | if (mvm->scan_status == IWL_MVM_SCAN_SCHED) { | ||
555 | IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n"); | ||
556 | ieee80211_sched_scan_results(mvm->hw); | ||
557 | } else { | ||
558 | IWL_DEBUG_SCAN(mvm, "Scan results\n"); | ||
559 | } | ||
560 | } | ||
561 | 569 | ||
562 | return 0; | 570 | return 0; |
563 | } | 571 | } |
@@ -969,6 +977,20 @@ free_blacklist: | |||
969 | return ret; | 977 | return ret; |
970 | } | 978 | } |
971 | 979 | ||
980 | static bool iwl_mvm_scan_pass_all(struct iwl_mvm *mvm, | ||
981 | struct cfg80211_sched_scan_request *req) | ||
982 | { | ||
983 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | ||
984 | IWL_DEBUG_SCAN(mvm, | ||
985 | "Sending scheduled scan with filtering, n_match_sets %d\n", | ||
986 | req->n_match_sets); | ||
987 | return false; | ||
988 | } | ||
989 | |||
990 | IWL_DEBUG_SCAN(mvm, "Sending Scheduled scan without filtering\n"); | ||
991 | return true; | ||
992 | } | ||
993 | |||
972 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | 994 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, |
973 | struct cfg80211_sched_scan_request *req) | 995 | struct cfg80211_sched_scan_request *req) |
974 | { | 996 | { |
@@ -984,15 +1006,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | |||
984 | .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, | 1006 | .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, |
985 | }; | 1007 | }; |
986 | 1008 | ||
987 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | 1009 | if (iwl_mvm_scan_pass_all(mvm, req)) |
988 | IWL_DEBUG_SCAN(mvm, | ||
989 | "Sending scheduled scan with filtering, filter len %d\n", | ||
990 | req->n_match_sets); | ||
991 | } else { | ||
992 | IWL_DEBUG_SCAN(mvm, | ||
993 | "Sending Scheduled scan without filtering\n"); | ||
994 | scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); | 1010 | scan_req.flags |= cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_PASS_ALL); |
995 | } | ||
996 | 1011 | ||
997 | if (mvm->last_ebs_successful && | 1012 | if (mvm->last_ebs_successful && |
998 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) | 1013 | mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) |
@@ -1011,11 +1026,18 @@ int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm, | |||
1011 | int ret; | 1026 | int ret; |
1012 | 1027 | ||
1013 | if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { | 1028 | if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { |
1029 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
1014 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | 1030 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); |
1015 | if (ret) | 1031 | if (ret) |
1016 | return ret; | 1032 | return ret; |
1017 | ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); | 1033 | ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); |
1034 | } else if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) { | ||
1035 | ret = iwl_mvm_config_sched_scan_profiles(mvm, req); | ||
1036 | if (ret) | ||
1037 | return ret; | ||
1038 | ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies); | ||
1018 | } else { | 1039 | } else { |
1040 | mvm->scan_status = IWL_MVM_SCAN_SCHED; | ||
1019 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); | 1041 | ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); |
1020 | if (ret) | 1042 | if (ret) |
1021 | return ret; | 1043 | return ret; |
@@ -1072,6 +1094,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify) | |||
1072 | 1094 | ||
1073 | lockdep_assert_held(&mvm->mutex); | 1095 | lockdep_assert_held(&mvm->mutex); |
1074 | 1096 | ||
1097 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
1098 | return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN, | ||
1099 | notify); | ||
1100 | |||
1075 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED && | 1101 | if (mvm->scan_status != IWL_MVM_SCAN_SCHED && |
1076 | (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || | 1102 | (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) || |
1077 | mvm->scan_status != IWL_MVM_SCAN_OS)) { | 1103 | mvm->scan_status != IWL_MVM_SCAN_OS)) { |
@@ -1198,11 +1224,8 @@ static u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies, | |||
1198 | static void | 1224 | static void |
1199 | iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | 1225 | iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, |
1200 | struct ieee80211_scan_ies *ies, | 1226 | struct ieee80211_scan_ies *ies, |
1201 | struct iwl_scan_req_unified_lmac *cmd) | 1227 | struct iwl_scan_probe_req *preq) |
1202 | { | 1228 | { |
1203 | struct iwl_scan_probe_req *preq = (void *)(cmd->data + | ||
1204 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
1205 | mvm->fw->ucode_capa.n_scan_channels); | ||
1206 | struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf; | 1229 | struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf; |
1207 | u8 *pos, *newpos; | 1230 | u8 *pos, *newpos; |
1208 | 1231 | ||
@@ -1287,6 +1310,7 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | |||
1287 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | 1310 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
1288 | }; | 1311 | }; |
1289 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; | 1312 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; |
1313 | struct iwl_scan_probe_req *preq; | ||
1290 | struct iwl_mvm_scan_params params = {}; | 1314 | struct iwl_mvm_scan_params params = {}; |
1291 | u32 flags; | 1315 | u32 flags; |
1292 | int ssid_bitmap = 0; | 1316 | int ssid_bitmap = 0; |
@@ -1348,7 +1372,10 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm, | |||
1348 | req->req.n_channels, ssid_bitmap, | 1372 | req->req.n_channels, ssid_bitmap, |
1349 | cmd); | 1373 | cmd); |
1350 | 1374 | ||
1351 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, cmd); | 1375 | preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) * |
1376 | mvm->fw->ucode_capa.n_scan_channels); | ||
1377 | |||
1378 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, preq); | ||
1352 | 1379 | ||
1353 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | 1380 | ret = iwl_mvm_send_cmd(mvm, &hcmd); |
1354 | if (!ret) { | 1381 | if (!ret) { |
@@ -1381,6 +1408,7 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
1381 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | 1408 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, |
1382 | }; | 1409 | }; |
1383 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; | 1410 | struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; |
1411 | struct iwl_scan_probe_req *preq; | ||
1384 | struct iwl_mvm_scan_params params = {}; | 1412 | struct iwl_mvm_scan_params params = {}; |
1385 | int ret; | 1413 | int ret; |
1386 | u32 flags = 0, ssid_bitmap = 0; | 1414 | u32 flags = 0, ssid_bitmap = 0; |
@@ -1404,15 +1432,8 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
1404 | 1432 | ||
1405 | cmd->n_channels = (u8)req->n_channels; | 1433 | cmd->n_channels = (u8)req->n_channels; |
1406 | 1434 | ||
1407 | if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { | 1435 | if (iwl_mvm_scan_pass_all(mvm, req)) |
1408 | IWL_DEBUG_SCAN(mvm, | ||
1409 | "Sending scheduled scan with filtering, n_match_sets %d\n", | ||
1410 | req->n_match_sets); | ||
1411 | } else { | ||
1412 | IWL_DEBUG_SCAN(mvm, | ||
1413 | "Sending Scheduled scan without filtering\n"); | ||
1414 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; | 1436 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; |
1415 | } | ||
1416 | 1437 | ||
1417 | if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0) | 1438 | if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0) |
1418 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; | 1439 | flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; |
@@ -1442,7 +1463,10 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
1442 | iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, | 1463 | iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, |
1443 | ssid_bitmap, cmd); | 1464 | ssid_bitmap, cmd); |
1444 | 1465 | ||
1445 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, cmd); | 1466 | preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) * |
1467 | mvm->fw->ucode_capa.n_scan_channels); | ||
1468 | |||
1469 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, preq); | ||
1446 | 1470 | ||
1447 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | 1471 | ret = iwl_mvm_send_cmd(mvm, &hcmd); |
1448 | if (!ret) { | 1472 | if (!ret) { |
@@ -1464,6 +1488,10 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm, | |||
1464 | 1488 | ||
1465 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | 1489 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) |
1466 | { | 1490 | { |
1491 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
1492 | return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_REG_SCAN, | ||
1493 | true); | ||
1494 | |||
1467 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) | 1495 | if (mvm->scan_status == IWL_MVM_SCAN_NONE) |
1468 | return 0; | 1496 | return 0; |
1469 | 1497 | ||
@@ -1478,3 +1506,568 @@ int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | |||
1478 | return iwl_mvm_scan_offload_stop(mvm, true); | 1506 | return iwl_mvm_scan_offload_stop(mvm, true); |
1479 | return iwl_mvm_cancel_regular_scan(mvm); | 1507 | return iwl_mvm_cancel_regular_scan(mvm); |
1480 | } | 1508 | } |
1509 | |||
1510 | /* UMAC scan API */ | ||
1511 | |||
1512 | struct iwl_umac_scan_done { | ||
1513 | struct iwl_mvm *mvm; | ||
1514 | enum iwl_umac_scan_uid_type type; | ||
1515 | }; | ||
1516 | |||
1517 | static int rate_to_scan_rate_flag(unsigned int rate) | ||
1518 | { | ||
1519 | static const int rate_to_scan_rate[IWL_RATE_COUNT] = { | ||
1520 | [IWL_RATE_1M_INDEX] = SCAN_CONFIG_RATE_1M, | ||
1521 | [IWL_RATE_2M_INDEX] = SCAN_CONFIG_RATE_2M, | ||
1522 | [IWL_RATE_5M_INDEX] = SCAN_CONFIG_RATE_5M, | ||
1523 | [IWL_RATE_11M_INDEX] = SCAN_CONFIG_RATE_11M, | ||
1524 | [IWL_RATE_6M_INDEX] = SCAN_CONFIG_RATE_6M, | ||
1525 | [IWL_RATE_9M_INDEX] = SCAN_CONFIG_RATE_9M, | ||
1526 | [IWL_RATE_12M_INDEX] = SCAN_CONFIG_RATE_12M, | ||
1527 | [IWL_RATE_18M_INDEX] = SCAN_CONFIG_RATE_18M, | ||
1528 | [IWL_RATE_24M_INDEX] = SCAN_CONFIG_RATE_24M, | ||
1529 | [IWL_RATE_36M_INDEX] = SCAN_CONFIG_RATE_36M, | ||
1530 | [IWL_RATE_48M_INDEX] = SCAN_CONFIG_RATE_48M, | ||
1531 | [IWL_RATE_54M_INDEX] = SCAN_CONFIG_RATE_54M, | ||
1532 | }; | ||
1533 | |||
1534 | return rate_to_scan_rate[rate]; | ||
1535 | } | ||
1536 | |||
1537 | static __le32 iwl_mvm_scan_config_rates(struct iwl_mvm *mvm) | ||
1538 | { | ||
1539 | struct ieee80211_supported_band *band; | ||
1540 | unsigned int rates = 0; | ||
1541 | int i; | ||
1542 | |||
1543 | band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | ||
1544 | for (i = 0; i < band->n_bitrates; i++) | ||
1545 | rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value); | ||
1546 | band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | ||
1547 | for (i = 0; i < band->n_bitrates; i++) | ||
1548 | rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value); | ||
1549 | |||
1550 | /* Set both basic rates and supported rates */ | ||
1551 | rates |= SCAN_CONFIG_SUPPORTED_RATE(rates); | ||
1552 | |||
1553 | return cpu_to_le32(rates); | ||
1554 | } | ||
1555 | |||
1556 | int iwl_mvm_config_scan(struct iwl_mvm *mvm) | ||
1557 | { | ||
1558 | |||
1559 | struct iwl_scan_config *scan_config; | ||
1560 | struct ieee80211_supported_band *band; | ||
1561 | int num_channels = | ||
1562 | mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels + | ||
1563 | mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels; | ||
1564 | int ret, i, j = 0, cmd_size, data_size; | ||
1565 | struct iwl_host_cmd cmd = { | ||
1566 | .id = SCAN_CFG_CMD, | ||
1567 | }; | ||
1568 | |||
1569 | if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) | ||
1570 | return -ENOBUFS; | ||
1571 | |||
1572 | cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels; | ||
1573 | |||
1574 | scan_config = kzalloc(cmd_size, GFP_KERNEL); | ||
1575 | if (!scan_config) | ||
1576 | return -ENOMEM; | ||
1577 | |||
1578 | data_size = cmd_size - sizeof(struct iwl_mvm_umac_cmd_hdr); | ||
1579 | scan_config->hdr.size = cpu_to_le16(data_size); | ||
1580 | scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE | | ||
1581 | SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS | | ||
1582 | SCAN_CONFIG_FLAG_SET_TX_CHAINS | | ||
1583 | SCAN_CONFIG_FLAG_SET_RX_CHAINS | | ||
1584 | SCAN_CONFIG_FLAG_SET_ALL_TIMES | | ||
1585 | SCAN_CONFIG_FLAG_SET_LEGACY_RATES | | ||
1586 | SCAN_CONFIG_FLAG_SET_MAC_ADDR | | ||
1587 | SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS| | ||
1588 | SCAN_CONFIG_N_CHANNELS(num_channels)); | ||
1589 | scan_config->tx_chains = cpu_to_le32(mvm->fw->valid_tx_ant); | ||
1590 | scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm)); | ||
1591 | scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm); | ||
1592 | scan_config->out_of_channel_time = cpu_to_le32(170); | ||
1593 | scan_config->suspend_time = cpu_to_le32(30); | ||
1594 | scan_config->dwell_active = 20; | ||
1595 | scan_config->dwell_passive = 110; | ||
1596 | scan_config->dwell_fragmented = 20; | ||
1597 | |||
1598 | memcpy(&scan_config->mac_addr, &mvm->addresses[0].addr, ETH_ALEN); | ||
1599 | |||
1600 | scan_config->bcast_sta_id = mvm->aux_sta.sta_id; | ||
1601 | scan_config->channel_flags = IWL_CHANNEL_FLAG_EBS | | ||
1602 | IWL_CHANNEL_FLAG_ACCURATE_EBS | | ||
1603 | IWL_CHANNEL_FLAG_EBS_ADD | | ||
1604 | IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE; | ||
1605 | |||
1606 | band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ]; | ||
1607 | for (i = 0; i < band->n_channels; i++, j++) | ||
1608 | scan_config->channel_array[j] = band->channels[i].center_freq; | ||
1609 | band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ]; | ||
1610 | for (i = 0; i < band->n_channels; i++, j++) | ||
1611 | scan_config->channel_array[j] = band->channels[i].center_freq; | ||
1612 | |||
1613 | cmd.data[0] = scan_config; | ||
1614 | cmd.len[0] = cmd_size; | ||
1615 | cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY; | ||
1616 | |||
1617 | IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n"); | ||
1618 | |||
1619 | ret = iwl_mvm_send_cmd(mvm, &cmd); | ||
1620 | |||
1621 | kfree(scan_config); | ||
1622 | return ret; | ||
1623 | } | ||
1624 | |||
1625 | static int iwl_mvm_find_scan_uid(struct iwl_mvm *mvm, u32 uid) | ||
1626 | { | ||
1627 | int i; | ||
1628 | |||
1629 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) | ||
1630 | if (mvm->scan_uid[i] == uid) | ||
1631 | return i; | ||
1632 | |||
1633 | return i; | ||
1634 | } | ||
1635 | |||
1636 | static int iwl_mvm_find_free_scan_uid(struct iwl_mvm *mvm) | ||
1637 | { | ||
1638 | return iwl_mvm_find_scan_uid(mvm, 0); | ||
1639 | } | ||
1640 | |||
1641 | static bool iwl_mvm_find_scan_type(struct iwl_mvm *mvm, | ||
1642 | enum iwl_umac_scan_uid_type type) | ||
1643 | { | ||
1644 | int i; | ||
1645 | |||
1646 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) | ||
1647 | if (mvm->scan_uid[i] & type) | ||
1648 | return true; | ||
1649 | |||
1650 | return false; | ||
1651 | } | ||
1652 | |||
1653 | static u32 iwl_generate_scan_uid(struct iwl_mvm *mvm, | ||
1654 | enum iwl_umac_scan_uid_type type) | ||
1655 | { | ||
1656 | u32 uid; | ||
1657 | |||
1658 | /* make sure exactly one bit is on in scan type */ | ||
1659 | WARN_ON(hweight8(type) != 1); | ||
1660 | |||
1661 | /* | ||
1662 | * Make sure scan uids are unique. If one scan lasts long time while | ||
1663 | * others are completing frequently, the seq number will wrap up and | ||
1664 | * we may have more than one scan with the same uid. | ||
1665 | */ | ||
1666 | do { | ||
1667 | uid = type | (mvm->scan_seq_num << | ||
1668 | IWL_UMAC_SCAN_UID_SEQ_OFFSET); | ||
1669 | mvm->scan_seq_num++; | ||
1670 | } while (iwl_mvm_find_scan_uid(mvm, uid) < | ||
1671 | IWL_MVM_MAX_SIMULTANEOUS_SCANS); | ||
1672 | |||
1673 | IWL_DEBUG_SCAN(mvm, "Generated scan UID %u\n", uid); | ||
1674 | |||
1675 | return uid; | ||
1676 | } | ||
1677 | |||
1678 | static void | ||
1679 | iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm, | ||
1680 | struct iwl_scan_req_umac *cmd, | ||
1681 | struct iwl_mvm_scan_params *params) | ||
1682 | { | ||
1683 | memset(cmd, 0, ksize(cmd)); | ||
1684 | cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) - | ||
1685 | sizeof(struct iwl_mvm_umac_cmd_hdr)); | ||
1686 | cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active; | ||
1687 | cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive; | ||
1688 | if (params->passive_fragmented) | ||
1689 | cmd->fragmented_dwell = | ||
1690 | params->dwell[IEEE80211_BAND_2GHZ].passive; | ||
1691 | cmd->max_out_time = cpu_to_le32(params->max_out_time); | ||
1692 | cmd->suspend_time = cpu_to_le32(params->suspend_time); | ||
1693 | cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); | ||
1694 | } | ||
1695 | |||
1696 | static void | ||
1697 | iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm, | ||
1698 | struct ieee80211_channel **channels, | ||
1699 | int n_channels, u32 ssid_bitmap, | ||
1700 | struct iwl_scan_req_umac *cmd) | ||
1701 | { | ||
1702 | struct iwl_scan_channel_cfg_umac *channel_cfg = (void *)&cmd->data; | ||
1703 | int i; | ||
1704 | |||
1705 | for (i = 0; i < n_channels; i++) { | ||
1706 | channel_cfg[i].flags = cpu_to_le32(ssid_bitmap); | ||
1707 | channel_cfg[i].channel_num = channels[i]->hw_value; | ||
1708 | channel_cfg[i].iter_count = 1; | ||
1709 | channel_cfg[i].iter_interval = 0; | ||
1710 | } | ||
1711 | } | ||
1712 | |||
1713 | static u32 iwl_mvm_scan_umac_common_flags(struct iwl_mvm *mvm, int n_ssids, | ||
1714 | struct cfg80211_ssid *ssids, | ||
1715 | int fragmented) | ||
1716 | { | ||
1717 | int flags = 0; | ||
1718 | |||
1719 | if (n_ssids == 0) | ||
1720 | flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE; | ||
1721 | |||
1722 | if (n_ssids == 1 && ssids[0].ssid_len != 0) | ||
1723 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT; | ||
1724 | |||
1725 | if (fragmented) | ||
1726 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED; | ||
1727 | |||
1728 | if (iwl_mvm_rrm_scan_needed(mvm)) | ||
1729 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED; | ||
1730 | |||
1731 | return flags; | ||
1732 | } | ||
1733 | |||
1734 | int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
1735 | struct ieee80211_scan_request *req) | ||
1736 | { | ||
1737 | struct iwl_host_cmd hcmd = { | ||
1738 | .id = SCAN_REQ_UMAC, | ||
1739 | .len = { iwl_mvm_scan_size(mvm), }, | ||
1740 | .data = { mvm->scan_cmd, }, | ||
1741 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
1742 | }; | ||
1743 | struct iwl_scan_req_umac *cmd = mvm->scan_cmd; | ||
1744 | struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data + | ||
1745 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
1746 | mvm->fw->ucode_capa.n_scan_channels; | ||
1747 | struct iwl_mvm_scan_params params = {}; | ||
1748 | u32 uid, flags; | ||
1749 | int ssid_bitmap = 0; | ||
1750 | int ret, i, uid_idx; | ||
1751 | |||
1752 | lockdep_assert_held(&mvm->mutex); | ||
1753 | |||
1754 | uid_idx = iwl_mvm_find_free_scan_uid(mvm); | ||
1755 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
1756 | return -EBUSY; | ||
1757 | |||
1758 | /* we should have failed registration if scan_cmd was NULL */ | ||
1759 | if (WARN_ON(mvm->scan_cmd == NULL)) | ||
1760 | return -ENOMEM; | ||
1761 | |||
1762 | if (WARN_ON(req->req.n_ssids > PROBE_OPTION_MAX || | ||
1763 | req->ies.common_ie_len + | ||
1764 | req->ies.len[NL80211_BAND_2GHZ] + | ||
1765 | req->ies.len[NL80211_BAND_5GHZ] + 24 + 2 > | ||
1766 | SCAN_OFFLOAD_PROBE_REQ_SIZE || req->req.n_channels > | ||
1767 | mvm->fw->ucode_capa.n_scan_channels)) | ||
1768 | return -ENOBUFS; | ||
1769 | |||
1770 | iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags, | ||
1771 | ¶ms); | ||
1772 | |||
1773 | iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, ¶ms); | ||
1774 | |||
1775 | uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_REG_SCAN); | ||
1776 | mvm->scan_uid[uid_idx] = uid; | ||
1777 | cmd->uid = cpu_to_le32(uid); | ||
1778 | |||
1779 | cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH); | ||
1780 | |||
1781 | flags = iwl_mvm_scan_umac_common_flags(mvm, req->req.n_ssids, | ||
1782 | req->req.ssids, | ||
1783 | params.passive_fragmented); | ||
1784 | |||
1785 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; | ||
1786 | |||
1787 | cmd->general_flags = cpu_to_le32(flags); | ||
1788 | cmd->n_channels = req->req.n_channels; | ||
1789 | |||
1790 | for (i = 0; i < req->req.n_ssids; i++) | ||
1791 | ssid_bitmap |= BIT(i); | ||
1792 | |||
1793 | iwl_mvm_umac_scan_cfg_channels(mvm, req->req.channels, | ||
1794 | req->req.n_channels, ssid_bitmap, cmd); | ||
1795 | |||
1796 | sec_part->schedule[0].iter_count = 1; | ||
1797 | sec_part->delay = 0; | ||
1798 | |||
1799 | iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, &sec_part->preq); | ||
1800 | |||
1801 | iwl_mvm_scan_fill_ssids(sec_part->direct_scan, req->req.ssids, | ||
1802 | req->req.n_ssids, 0); | ||
1803 | |||
1804 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | ||
1805 | if (!ret) { | ||
1806 | IWL_DEBUG_SCAN(mvm, | ||
1807 | "Scan request was sent successfully\n"); | ||
1808 | } else { | ||
1809 | /* | ||
1810 | * If the scan failed, it usually means that the FW was unable | ||
1811 | * to allocate the time events. Warn on it, but maybe we | ||
1812 | * should try to send the command again with different params. | ||
1813 | */ | ||
1814 | IWL_ERR(mvm, "Scan failed! ret %d\n", ret); | ||
1815 | } | ||
1816 | return ret; | ||
1817 | } | ||
1818 | |||
1819 | int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif, | ||
1820 | struct cfg80211_sched_scan_request *req, | ||
1821 | struct ieee80211_scan_ies *ies) | ||
1822 | { | ||
1823 | |||
1824 | struct iwl_host_cmd hcmd = { | ||
1825 | .id = SCAN_REQ_UMAC, | ||
1826 | .len = { iwl_mvm_scan_size(mvm), }, | ||
1827 | .data = { mvm->scan_cmd, }, | ||
1828 | .dataflags = { IWL_HCMD_DFL_NOCOPY, }, | ||
1829 | }; | ||
1830 | struct iwl_scan_req_umac *cmd = mvm->scan_cmd; | ||
1831 | struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data + | ||
1832 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
1833 | mvm->fw->ucode_capa.n_scan_channels; | ||
1834 | struct iwl_mvm_scan_params params = {}; | ||
1835 | u32 uid, flags; | ||
1836 | int ssid_bitmap = 0; | ||
1837 | int ret, uid_idx; | ||
1838 | |||
1839 | lockdep_assert_held(&mvm->mutex); | ||
1840 | |||
1841 | uid_idx = iwl_mvm_find_free_scan_uid(mvm); | ||
1842 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
1843 | return -EBUSY; | ||
1844 | |||
1845 | /* we should have failed registration if scan_cmd was NULL */ | ||
1846 | if (WARN_ON(mvm->scan_cmd == NULL)) | ||
1847 | return -ENOMEM; | ||
1848 | |||
1849 | if (WARN_ON(req->n_ssids > PROBE_OPTION_MAX || | ||
1850 | ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] + | ||
1851 | ies->len[NL80211_BAND_5GHZ] + 24 + 2 > | ||
1852 | SCAN_OFFLOAD_PROBE_REQ_SIZE || req->n_channels > | ||
1853 | mvm->fw->ucode_capa.n_scan_channels)) | ||
1854 | return -ENOBUFS; | ||
1855 | |||
1856 | iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags, | ||
1857 | ¶ms); | ||
1858 | |||
1859 | iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, ¶ms); | ||
1860 | |||
1861 | cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE); | ||
1862 | |||
1863 | uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN); | ||
1864 | mvm->scan_uid[uid_idx] = uid; | ||
1865 | cmd->uid = cpu_to_le32(uid); | ||
1866 | |||
1867 | cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_LOW); | ||
1868 | |||
1869 | flags = iwl_mvm_scan_umac_common_flags(mvm, req->n_ssids, req->ssids, | ||
1870 | params.passive_fragmented); | ||
1871 | |||
1872 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC; | ||
1873 | |||
1874 | if (iwl_mvm_scan_pass_all(mvm, req)) | ||
1875 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL; | ||
1876 | else | ||
1877 | flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH; | ||
1878 | |||
1879 | cmd->general_flags = cpu_to_le32(flags); | ||
1880 | |||
1881 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT && | ||
1882 | mvm->last_ebs_successful) | ||
1883 | cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS | | ||
1884 | IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE | | ||
1885 | IWL_SCAN_CHANNEL_FLAG_CACHE_ADD; | ||
1886 | |||
1887 | cmd->n_channels = req->n_channels; | ||
1888 | |||
1889 | iwl_scan_offload_build_ssid(req, sec_part->direct_scan, &ssid_bitmap, | ||
1890 | false); | ||
1891 | |||
1892 | /* This API uses bits 0-19 instead of 1-20. */ | ||
1893 | ssid_bitmap = ssid_bitmap >> 1; | ||
1894 | |||
1895 | iwl_mvm_umac_scan_cfg_channels(mvm, req->channels, req->n_channels, | ||
1896 | ssid_bitmap, cmd); | ||
1897 | |||
1898 | sec_part->schedule[0].interval = | ||
1899 | cpu_to_le16(req->interval / MSEC_PER_SEC); | ||
1900 | sec_part->schedule[0].iter_count = 0xff; | ||
1901 | |||
1902 | sec_part->delay = 0; | ||
1903 | |||
1904 | iwl_mvm_build_unified_scan_probe(mvm, vif, ies, &sec_part->preq); | ||
1905 | |||
1906 | ret = iwl_mvm_send_cmd(mvm, &hcmd); | ||
1907 | if (!ret) { | ||
1908 | IWL_DEBUG_SCAN(mvm, | ||
1909 | "Sched scan request was sent successfully\n"); | ||
1910 | } else { | ||
1911 | /* | ||
1912 | * If the scan failed, it usually means that the FW was unable | ||
1913 | * to allocate the time events. Warn on it, but maybe we | ||
1914 | * should try to send the command again with different params. | ||
1915 | */ | ||
1916 | IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret); | ||
1917 | } | ||
1918 | return ret; | ||
1919 | } | ||
1920 | |||
1921 | int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, | ||
1922 | struct iwl_rx_cmd_buffer *rxb, | ||
1923 | struct iwl_device_cmd *cmd) | ||
1924 | { | ||
1925 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1926 | struct iwl_umac_scan_complete *notif = (void *)pkt->data; | ||
1927 | u32 uid = __le32_to_cpu(notif->uid); | ||
1928 | bool sched = !!(uid & IWL_UMAC_SCAN_UID_SCHED_SCAN); | ||
1929 | int uid_idx = iwl_mvm_find_scan_uid(mvm, uid); | ||
1930 | |||
1931 | if (WARN(uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS, | ||
1932 | "Scan notification for uknown scan ID\n")) | ||
1933 | return 0; | ||
1934 | |||
1935 | IWL_DEBUG_SCAN(mvm, | ||
1936 | "Scan completed, uid %u type %s, status %s, EBS status %s\n", | ||
1937 | uid, sched ? "sched" : "regular", | ||
1938 | notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? | ||
1939 | "completed" : "aborted", | ||
1940 | notif->ebs_status == IWL_SCAN_EBS_SUCCESS ? | ||
1941 | "success" : "failed"); | ||
1942 | |||
1943 | mvm->last_ebs_successful = !notif->ebs_status; | ||
1944 | mvm->scan_uid[uid_idx] = 0; | ||
1945 | |||
1946 | if (!sched) { | ||
1947 | ieee80211_scan_completed(mvm->hw, | ||
1948 | notif->status == | ||
1949 | IWL_SCAN_OFFLOAD_ABORTED); | ||
1950 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
1951 | } else if (!iwl_mvm_find_scan_type(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN)) { | ||
1952 | ieee80211_sched_scan_stopped(mvm->hw); | ||
1953 | } else { | ||
1954 | IWL_DEBUG_SCAN(mvm, "Another sched scan is running\n"); | ||
1955 | } | ||
1956 | |||
1957 | return 0; | ||
1958 | } | ||
1959 | |||
1960 | static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait, | ||
1961 | struct iwl_rx_packet *pkt, void *data) | ||
1962 | { | ||
1963 | struct iwl_umac_scan_done *scan_done = data; | ||
1964 | struct iwl_umac_scan_complete *notif = (void *)pkt->data; | ||
1965 | u32 uid = __le32_to_cpu(notif->uid); | ||
1966 | int uid_idx = iwl_mvm_find_scan_uid(scan_done->mvm, uid); | ||
1967 | |||
1968 | if (WARN_ON(pkt->hdr.cmd != SCAN_COMPLETE_UMAC)) | ||
1969 | return false; | ||
1970 | |||
1971 | if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS) | ||
1972 | return false; | ||
1973 | |||
1974 | /* | ||
1975 | * Clear scan uid of scans that was aborted from above and completed | ||
1976 | * in FW so the RX handler does nothing. | ||
1977 | */ | ||
1978 | scan_done->mvm->scan_uid[uid_idx] = 0; | ||
1979 | |||
1980 | return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type); | ||
1981 | } | ||
1982 | |||
1983 | static int iwl_umac_scan_abort_one(struct iwl_mvm *mvm, u32 uid) | ||
1984 | { | ||
1985 | struct iwl_umac_scan_abort cmd = { | ||
1986 | .hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) - | ||
1987 | sizeof(struct iwl_mvm_umac_cmd_hdr)), | ||
1988 | .uid = cpu_to_le32(uid), | ||
1989 | }; | ||
1990 | |||
1991 | lockdep_assert_held(&mvm->mutex); | ||
1992 | |||
1993 | IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid); | ||
1994 | |||
1995 | return iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd); | ||
1996 | } | ||
1997 | |||
1998 | static int iwl_umac_scan_stop(struct iwl_mvm *mvm, | ||
1999 | enum iwl_umac_scan_uid_type type, bool notify) | ||
2000 | { | ||
2001 | struct iwl_notification_wait wait_scan_done; | ||
2002 | static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, }; | ||
2003 | struct iwl_umac_scan_done scan_done = { | ||
2004 | .mvm = mvm, | ||
2005 | .type = type, | ||
2006 | }; | ||
2007 | int i, ret = -EIO; | ||
2008 | |||
2009 | iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done, | ||
2010 | scan_done_notif, | ||
2011 | ARRAY_SIZE(scan_done_notif), | ||
2012 | iwl_scan_umac_done_check, &scan_done); | ||
2013 | |||
2014 | IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type); | ||
2015 | |||
2016 | for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) { | ||
2017 | if (mvm->scan_uid[i] & type) { | ||
2018 | int err; | ||
2019 | |||
2020 | if (iwl_mvm_is_radio_killed(mvm) && | ||
2021 | (type & IWL_UMAC_SCAN_UID_REG_SCAN)) { | ||
2022 | ieee80211_scan_completed(mvm->hw, true); | ||
2023 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
2024 | break; | ||
2025 | } | ||
2026 | |||
2027 | err = iwl_umac_scan_abort_one(mvm, mvm->scan_uid[i]); | ||
2028 | if (!err) | ||
2029 | ret = 0; | ||
2030 | } | ||
2031 | } | ||
2032 | |||
2033 | if (ret) { | ||
2034 | IWL_DEBUG_SCAN(mvm, "Couldn't stop scan\n"); | ||
2035 | iwl_remove_notification(&mvm->notif_wait, &wait_scan_done); | ||
2036 | return ret; | ||
2037 | } | ||
2038 | |||
2039 | ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ); | ||
2040 | if (ret) | ||
2041 | return ret; | ||
2042 | |||
2043 | if (notify) { | ||
2044 | if (type & IWL_UMAC_SCAN_UID_SCHED_SCAN) | ||
2045 | ieee80211_sched_scan_stopped(mvm->hw); | ||
2046 | if (type & IWL_UMAC_SCAN_UID_REG_SCAN) { | ||
2047 | ieee80211_scan_completed(mvm->hw, true); | ||
2048 | iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN); | ||
2049 | } | ||
2050 | } | ||
2051 | |||
2052 | return ret; | ||
2053 | } | ||
2054 | |||
2055 | int iwl_mvm_scan_size(struct iwl_mvm *mvm) | ||
2056 | { | ||
2057 | if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) | ||
2058 | return sizeof(struct iwl_scan_req_umac) + | ||
2059 | sizeof(struct iwl_scan_channel_cfg_umac) * | ||
2060 | mvm->fw->ucode_capa.n_scan_channels + | ||
2061 | sizeof(struct iwl_scan_req_umac_tail); | ||
2062 | |||
2063 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN) | ||
2064 | return sizeof(struct iwl_scan_req_unified_lmac) + | ||
2065 | sizeof(struct iwl_scan_channel_cfg_lmac) * | ||
2066 | mvm->fw->ucode_capa.n_scan_channels + | ||
2067 | sizeof(struct iwl_scan_probe_req); | ||
2068 | |||
2069 | return sizeof(struct iwl_scan_cmd) + | ||
2070 | mvm->fw->ucode_capa.max_probe_length + | ||
2071 | mvm->fw->ucode_capa.n_scan_channels * | ||
2072 | sizeof(struct iwl_scan_channel); | ||
2073 | } | ||