aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Spinadel <david.spinadel@intel.com>2013-08-28 02:29:43 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-10-02 12:00:39 -0400
commit35a000b7c1bbd81631097539567f24a272a2fa0f (patch)
tree7194fb17baac16320fd90f150f8d3838022d2a64
parent20f1a5deb67f00cef89d63fb957a940c7f976cf3 (diff)
iwlwifi: mvm: support sched scan if supported by the fw
Add support for scheduled scan according to firmware support. Signed-off-by: David Spinadel <david.spinadel@intel.com> Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h5
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h34
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c58
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h18
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c8
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c418
7 files changed, 538 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index d2f0381d2abd..0d609ce0a7c6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -75,6 +75,8 @@
75 * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P. 75 * @IWL_UCODE_TLV_FLAGS_P2P: This uCode image supports P2P.
76 * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS 76 * @IWL_UCODE_TLV_FLAGS_DW_BC_TABLE: The SCD byte count table is in DWORDS
77 * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD 77 * @IWL_UCODE_TLV_FLAGS_UAPSD: This uCode image supports uAPSD
78 * @IWL_UCODE_TLV_FLAGS_SHORT_BL: 16 entries of black list instead of 64 in scan
79 * offload profile config command.
78 * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api 80 * @IWL_UCODE_TLV_FLAGS_RX_ENERGY_API: supports rx signal strength api
79 * @IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API. 81 * @IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2: using the new time event API.
80 * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six 82 * @IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS: D3 image supports up to six
@@ -82,6 +84,7 @@
82 * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API 84 * @IWL_UCODE_TLV_FLAGS_BF_UPDATED: new beacon filtering API
83 * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element 85 * @IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID: not sending a probe with the SSID element
84 * from the probe request template. 86 * from the probe request template.
87 * @IWL_UCODE_TLV_FLAGS_SCHED_SCAN: this uCode image supports scheduled scan.
85 * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API 88 * @IWL_UCODE_TLV_FLAGS_STA_KEY_CMD: new ADD_STA and ADD_STA_KEY command API
86 */ 89 */
87enum iwl_ucode_tlv_flag { 90enum iwl_ucode_tlv_flag {
@@ -91,11 +94,13 @@ enum iwl_ucode_tlv_flag {
91 IWL_UCODE_TLV_FLAGS_P2P = BIT(3), 94 IWL_UCODE_TLV_FLAGS_P2P = BIT(3),
92 IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4), 95 IWL_UCODE_TLV_FLAGS_DW_BC_TABLE = BIT(4),
93 IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6), 96 IWL_UCODE_TLV_FLAGS_UAPSD = BIT(6),
97 IWL_UCODE_TLV_FLAGS_SHORT_BL = BIT(7),
94 IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8), 98 IWL_UCODE_TLV_FLAGS_RX_ENERGY_API = BIT(8),
95 IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = BIT(9), 99 IWL_UCODE_TLV_FLAGS_TIME_EVENT_API_V2 = BIT(9),
96 IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10), 100 IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS = BIT(10),
97 IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11), 101 IWL_UCODE_TLV_FLAGS_BF_UPDATED = BIT(11),
98 IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12), 102 IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID = BIT(12),
103 IWL_UCODE_TLV_FLAGS_SCHED_SCAN = BIT(17),
99 IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19), 104 IWL_UCODE_TLV_FLAGS_STA_KEY_CMD = BIT(19),
100}; 105};
101 106
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
index 83cb9b992ea4..c3782b48ded1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
@@ -356,6 +356,7 @@ struct iwl_scan_complete_notif {
356/* scan offload */ 356/* scan offload */
357#define IWL_MAX_SCAN_CHANNELS 40 357#define IWL_MAX_SCAN_CHANNELS 40
358#define IWL_SCAN_MAX_BLACKLIST_LEN 64 358#define IWL_SCAN_MAX_BLACKLIST_LEN 64
359#define IWL_SCAN_SHORT_BLACKLIST_LEN 16
359#define IWL_SCAN_MAX_PROFILES 11 360#define IWL_SCAN_MAX_PROFILES 11
360#define SCAN_OFFLOAD_PROBE_REQ_SIZE 512 361#define SCAN_OFFLOAD_PROBE_REQ_SIZE 512
361 362
@@ -368,6 +369,12 @@ struct iwl_scan_complete_notif {
368#define IWL_FULL_SCAN_MULTIPLIER 5 369#define IWL_FULL_SCAN_MULTIPLIER 5
369#define IWL_FAST_SCHED_SCAN_ITERATIONS 3 370#define IWL_FAST_SCHED_SCAN_ITERATIONS 3
370 371
372enum scan_framework_client {
373 SCAN_CLIENT_SCHED_SCAN = BIT(0),
374 SCAN_CLIENT_NETDETECT = BIT(1),
375 SCAN_CLIENT_ASSET_TRACKING = BIT(2),
376};
377
371/** 378/**
372 * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6 379 * struct iwl_scan_offload_cmd - SCAN_REQUEST_FIXED_PART_API_S_VER_6
373 * @scan_flags: see enum iwl_scan_flags 380 * @scan_flags: see enum iwl_scan_flags
@@ -449,11 +456,12 @@ struct iwl_scan_offload_cfg {
449 * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S 456 * iwl_scan_offload_blacklist - SCAN_OFFLOAD_BLACKLIST_S
450 * @ssid: MAC address to filter out 457 * @ssid: MAC address to filter out
451 * @reported_rssi: AP rssi reported to the host 458 * @reported_rssi: AP rssi reported to the host
459 * @client_bitmap: clients ignore this entry - enum scan_framework_client
452 */ 460 */
453struct iwl_scan_offload_blacklist { 461struct iwl_scan_offload_blacklist {
454 u8 ssid[ETH_ALEN]; 462 u8 ssid[ETH_ALEN];
455 u8 reported_rssi; 463 u8 reported_rssi;
456 u8 reserved; 464 u8 client_bitmap;
457} __packed; 465} __packed;
458 466
459enum iwl_scan_offload_network_type { 467enum iwl_scan_offload_network_type {
@@ -475,6 +483,7 @@ enum iwl_scan_offload_band_selection {
475 * @aut_alg: authentication olgorithm to match - bitmap 483 * @aut_alg: authentication olgorithm to match - bitmap
476 * @network_type: enum iwl_scan_offload_network_type 484 * @network_type: enum iwl_scan_offload_network_type
477 * @band_selection: enum iwl_scan_offload_band_selection 485 * @band_selection: enum iwl_scan_offload_band_selection
486 * @client_bitmap: clients waiting for match - enum scan_framework_client
478 */ 487 */
479struct iwl_scan_offload_profile { 488struct iwl_scan_offload_profile {
480 u8 ssid_index; 489 u8 ssid_index;
@@ -482,7 +491,8 @@ struct iwl_scan_offload_profile {
482 u8 auth_alg; 491 u8 auth_alg;
483 u8 network_type; 492 u8 network_type;
484 u8 band_selection; 493 u8 band_selection;
485 u8 reserved[3]; 494 u8 client_bitmap;
495 u8 reserved[2];
486} __packed; 496} __packed;
487 497
488/** 498/**
@@ -491,13 +501,18 @@ struct iwl_scan_offload_profile {
491 * @profiles: profiles to search for match 501 * @profiles: profiles to search for match
492 * @blacklist_len: length of blacklist 502 * @blacklist_len: length of blacklist
493 * @num_profiles: num of profiles in the list 503 * @num_profiles: num of profiles in the list
504 * @match_notify: clients waiting for match found notification
505 * @pass_match: clients waiting for the results
506 * @active_clients: active clients bitmap - enum scan_framework_client
494 */ 507 */
495struct iwl_scan_offload_profile_cfg { 508struct iwl_scan_offload_profile_cfg {
496 struct iwl_scan_offload_blacklist blacklist[IWL_SCAN_MAX_BLACKLIST_LEN];
497 struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES]; 509 struct iwl_scan_offload_profile profiles[IWL_SCAN_MAX_PROFILES];
498 u8 blacklist_len; 510 u8 blacklist_len;
499 u8 num_profiles; 511 u8 num_profiles;
500 u8 reserved[2]; 512 u8 match_notify;
513 u8 pass_match;
514 u8 active_clients;
515 u8 reserved[3];
501} __packed; 516} __packed;
502 517
503/** 518/**
@@ -560,4 +575,15 @@ struct iwl_scan_offload_complete {
560 u8 reserved; 575 u8 reserved;
561} __packed; 576} __packed;
562 577
578/**
579 * iwl_sched_scan_results - SCAN_OFFLOAD_MATCH_FOUND_NTF_API_S_VER_1
580 * @ssid_bitmap: SSIDs indexes found in this iteration
581 * @client_bitmap: clients that are active and wait for this notification
582 */
583struct iwl_sched_scan_results {
584 __le16 ssid_bitmap;
585 u8 client_bitmap;
586 u8 reserved;
587};
588
563#endif 589#endif
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 3c833acad686..c28af8ac3d5f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -132,6 +132,7 @@ enum {
132 SCAN_OFFLOAD_COMPLETE = 0x6D, 132 SCAN_OFFLOAD_COMPLETE = 0x6D,
133 SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, 133 SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E,
134 SCAN_OFFLOAD_CONFIG_CMD = 0x6f, 134 SCAN_OFFLOAD_CONFIG_CMD = 0x6f,
135 MATCH_FOUND_NOTIFICATION = 0xd9,
135 136
136 /* Phy */ 137 /* Phy */
137 PHY_CONFIGURATION_CMD = 0x6a, 138 PHY_CONFIGURATION_CMD = 0x6a,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 0340299b4b63..8c619151c467 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -239,6 +239,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
239 else 239 else
240 hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; 240 hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
241 241
242 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SCHED_SCAN) {
243 hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
244 hw->wiphy->max_sched_scan_ssids = PROBE_OPTION_MAX;
245 hw->wiphy->max_match_sets = IWL_SCAN_MAX_PROFILES;
246 /* we create the 802.11 header and zero length SSID IE. */
247 hw->wiphy->max_sched_scan_ie_len =
248 SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
249 }
250
242 hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN | 251 hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
243 NL80211_FEATURE_P2P_GO_OPPPS; 252 NL80211_FEATURE_P2P_GO_OPPPS;
244 253
@@ -1202,6 +1211,53 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
1202 mutex_unlock(&mvm->mutex); 1211 mutex_unlock(&mvm->mutex);
1203} 1212}
1204 1213
1214static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw,
1215 struct ieee80211_vif *vif,
1216 struct cfg80211_sched_scan_request *req,
1217 struct ieee80211_sched_scan_ies *ies)
1218{
1219 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1220 int ret;
1221
1222 mutex_lock(&mvm->mutex);
1223
1224 if (mvm->scan_status != IWL_MVM_SCAN_NONE) {
1225 IWL_DEBUG_SCAN(mvm,
1226 "SCHED SCAN request during internal scan - abort\n");
1227 ret = -EBUSY;
1228 goto out;
1229 }
1230
1231 mvm->scan_status = IWL_MVM_SCAN_SCHED;
1232
1233 ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
1234 if (ret)
1235 goto err;
1236
1237 ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
1238 if (ret)
1239 goto err;
1240
1241 ret = iwl_mvm_sched_scan_start(mvm, req);
1242 if (!ret)
1243 goto out;
1244err:
1245 mvm->scan_status = IWL_MVM_SCAN_NONE;
1246out:
1247 mutex_unlock(&mvm->mutex);
1248 return ret;
1249}
1250
1251static void iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw,
1252 struct ieee80211_vif *vif)
1253{
1254 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
1255
1256 mutex_lock(&mvm->mutex);
1257 iwl_mvm_sched_scan_stop(mvm);
1258 mutex_unlock(&mvm->mutex);
1259}
1260
1205static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, 1261static int iwl_mvm_mac_set_key(struct ieee80211_hw *hw,
1206 enum set_key_cmd cmd, 1262 enum set_key_cmd cmd,
1207 struct ieee80211_vif *vif, 1263 struct ieee80211_vif *vif,
@@ -1671,6 +1727,8 @@ struct ieee80211_ops iwl_mvm_hw_ops = {
1671 .set_rts_threshold = iwl_mvm_mac_set_rts_threshold, 1727 .set_rts_threshold = iwl_mvm_mac_set_rts_threshold,
1672 .conf_tx = iwl_mvm_mac_conf_tx, 1728 .conf_tx = iwl_mvm_mac_conf_tx,
1673 .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx, 1729 .mgd_prepare_tx = iwl_mvm_mac_mgd_prepare_tx,
1730 .sched_scan_start = iwl_mvm_mac_sched_scan_start,
1731 .sched_scan_stop = iwl_mvm_mac_sched_scan_stop,
1674 .set_key = iwl_mvm_mac_set_key, 1732 .set_key = iwl_mvm_mac_set_key,
1675 .update_tkip_key = iwl_mvm_mac_update_tkip_key, 1733 .update_tkip_key = iwl_mvm_mac_update_tkip_key,
1676 .remain_on_channel = iwl_mvm_roc, 1734 .remain_on_channel = iwl_mvm_roc,
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index d7b0aeea380c..a56c1b8f5493 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -339,6 +339,7 @@ iwl_mvm_vif_from_mac80211(struct ieee80211_vif *vif)
339enum iwl_scan_status { 339enum iwl_scan_status {
340 IWL_MVM_SCAN_NONE, 340 IWL_MVM_SCAN_NONE,
341 IWL_MVM_SCAN_OS, 341 IWL_MVM_SCAN_OS,
342 IWL_MVM_SCAN_SCHED,
342}; 343};
343 344
344/** 345/**
@@ -696,6 +697,23 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
696 struct iwl_device_cmd *cmd); 697 struct iwl_device_cmd *cmd);
697void iwl_mvm_cancel_scan(struct iwl_mvm *mvm); 698void iwl_mvm_cancel_scan(struct iwl_mvm *mvm);
698 699
700/* Scheduled scan */
701int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
702 struct iwl_rx_cmd_buffer *rxb,
703 struct iwl_device_cmd *cmd);
704int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
705 struct ieee80211_vif *vif,
706 struct cfg80211_sched_scan_request *req,
707 struct ieee80211_sched_scan_ies *ies);
708int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
709 struct cfg80211_sched_scan_request *req);
710int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
711 struct cfg80211_sched_scan_request *req);
712void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm);
713int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm,
714 struct iwl_rx_cmd_buffer *rxb,
715 struct iwl_device_cmd *cmd);
716
699/* MVM debugfs */ 717/* MVM debugfs */
700#ifdef CONFIG_IWLWIFI_DEBUGFS 718#ifdef CONFIG_IWLWIFI_DEBUGFS
701int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir); 719int 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 8cd5f32cfba3..a9ed45708bc2 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -224,6 +224,10 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
224 224
225 RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false), 225 RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
226 RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false), 226 RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, false),
227 RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
228 iwl_mvm_rx_scan_offload_complete_notif, false),
229 RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_sched_scan_results,
230 false),
227 231
228 RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false), 232 RX_HANDLER(RADIO_VERSION_NOTIFICATION, iwl_mvm_rx_radio_ver, false),
229 RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false), 233 RX_HANDLER(CARD_STATE_NOTIFICATION, iwl_mvm_rx_card_state_notif, false),
@@ -266,6 +270,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
266 CMD(REMOVE_STA), 270 CMD(REMOVE_STA),
267 CMD(LQ_CMD), 271 CMD(LQ_CMD),
268 CMD(SCAN_OFFLOAD_CONFIG_CMD), 272 CMD(SCAN_OFFLOAD_CONFIG_CMD),
273 CMD(MATCH_FOUND_NOTIFICATION),
269 CMD(SCAN_OFFLOAD_REQUEST_CMD), 274 CMD(SCAN_OFFLOAD_REQUEST_CMD),
270 CMD(SCAN_OFFLOAD_ABORT_CMD), 275 CMD(SCAN_OFFLOAD_ABORT_CMD),
271 CMD(SCAN_OFFLOAD_COMPLETE), 276 CMD(SCAN_OFFLOAD_COMPLETE),
@@ -717,6 +722,9 @@ static void iwl_mvm_nic_restart(struct iwl_mvm *mvm)
717 case IWL_MVM_SCAN_OS: 722 case IWL_MVM_SCAN_OS:
718 ieee80211_scan_completed(mvm->hw, true); 723 ieee80211_scan_completed(mvm->hw, true);
719 break; 724 break;
725 case IWL_MVM_SCAN_SCHED:
726 ieee80211_sched_scan_stopped(mvm->hw);
727 break;
720 } 728 }
721 729
722 if (mvm->restart_fw > 0) 730 if (mvm->restart_fw > 0)
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 0dc626f34927..778dcd9320fe 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -391,6 +391,21 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
391 return 0; 391 return 0;
392} 392}
393 393
394int iwl_mvm_rx_sched_scan_results(struct iwl_mvm *mvm,
395 struct iwl_rx_cmd_buffer *rxb,
396 struct iwl_device_cmd *cmd)
397{
398 struct iwl_rx_packet *pkt = rxb_addr(rxb);
399 struct iwl_sched_scan_results *notif = (void *)pkt->data;
400
401 if (notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN) {
402 IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
403 ieee80211_sched_scan_results(mvm->hw);
404 }
405
406 return 0;
407}
408
394static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait, 409static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
395 struct iwl_rx_packet *pkt, void *data) 410 struct iwl_rx_packet *pkt, void *data)
396{ 411{
@@ -451,3 +466,406 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
451out_remove_notif: 466out_remove_notif:
452 iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort); 467 iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
453} 468}
469
470int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
471 struct iwl_rx_cmd_buffer *rxb,
472 struct iwl_device_cmd *cmd)
473{
474 struct iwl_rx_packet *pkt = rxb_addr(rxb);
475 struct iwl_scan_offload_complete *scan_notif = (void *)pkt->data;
476
477 IWL_DEBUG_SCAN(mvm, "Scheduled scan completed, status %s\n",
478 scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
479 "completed" : "aborted");
480
481 mvm->scan_status = IWL_MVM_SCAN_NONE;
482 ieee80211_sched_scan_stopped(mvm->hw);
483
484 return 0;
485}
486
487static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
488 struct ieee80211_vif *vif,
489 struct ieee80211_sched_scan_ies *ies,
490 enum ieee80211_band band,
491 struct iwl_tx_cmd *cmd,
492 u8 *data)
493{
494 u16 cmd_len;
495
496 cmd->tx_flags = cpu_to_le32(TX_CMD_FLG_SEQ_CTL);
497 cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE);
498 cmd->sta_id = mvm->aux_sta.sta_id;
499
500 cmd->rate_n_flags = iwl_mvm_scan_rate_n_flags(mvm, band, false);
501
502 cmd_len = iwl_mvm_fill_probe_req((struct ieee80211_mgmt *)data,
503 vif->addr,
504 1, NULL, 0,
505 ies->ie[band], ies->len[band],
506 SCAN_OFFLOAD_PROBE_REQ_SIZE);
507 cmd->len = cpu_to_le16(cmd_len);
508}
509
510static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
511 struct ieee80211_vif *vif,
512 struct cfg80211_sched_scan_request *req,
513 struct iwl_scan_offload_cmd *scan)
514{
515 scan->channel_count =
516 mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +
517 mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
518 scan->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
519 scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
520 scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT;
521 scan->rx_chain = iwl_mvm_scan_rx_chain(mvm);
522 scan->max_out_time = cpu_to_le32(200 * 1024);
523 scan->suspend_time = iwl_mvm_scan_suspend_time(vif);
524 scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
525 MAC_FILTER_IN_BEACON);
526 scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND);
527 scan->rep_count = cpu_to_le32(1);
528}
529
530static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
531{
532 int i;
533
534 for (i = 0; i < PROBE_OPTION_MAX; i++) {
535 if (!ssid_list[i].len)
536 break;
537 if (ssid_list[i].len == ssid_len &&
538 !memcmp(ssid_list->ssid, ssid, ssid_len))
539 return i;
540 }
541 return -1;
542}
543
544static void iwl_scan_offload_build_ssid(struct cfg80211_sched_scan_request *req,
545 struct iwl_scan_offload_cmd *scan,
546 u32 *ssid_bitmap)
547{
548 int i, j;
549 int index;
550
551 /*
552 * copy SSIDs from match list.
553 * iwl_config_sched_scan_profiles() uses the order of these ssids to
554 * config match list.
555 */
556 for (i = 0; i < req->n_match_sets && i < PROBE_OPTION_MAX; i++) {
557 scan->direct_scan[i].id = WLAN_EID_SSID;
558 scan->direct_scan[i].len = req->match_sets[i].ssid.ssid_len;
559 memcpy(scan->direct_scan[i].ssid, req->match_sets[i].ssid.ssid,
560 scan->direct_scan[i].len);
561 }
562
563 /* add SSIDs from scan SSID list */
564 *ssid_bitmap = 0;
565 for (j = 0; j < req->n_ssids && i < PROBE_OPTION_MAX; j++) {
566 index = iwl_ssid_exist(req->ssids[j].ssid,
567 req->ssids[j].ssid_len,
568 scan->direct_scan);
569 if (index < 0) {
570 if (!req->ssids[j].ssid_len)
571 continue;
572 scan->direct_scan[i].id = WLAN_EID_SSID;
573 scan->direct_scan[i].len = req->ssids[j].ssid_len;
574 memcpy(scan->direct_scan[i].ssid, req->ssids[j].ssid,
575 scan->direct_scan[i].len);
576 *ssid_bitmap |= BIT(i + 1);
577 i++;
578 } else {
579 *ssid_bitmap |= BIT(index + 1);
580 }
581 }
582}
583
584static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
585 struct cfg80211_sched_scan_request *req,
586 struct iwl_scan_channel_cfg *channels,
587 enum ieee80211_band band,
588 int *head, int *tail,
589 u32 ssid_bitmap)
590{
591 struct ieee80211_supported_band *s_band;
592 int n_probes = req->n_ssids;
593 int n_channels = req->n_channels;
594 u8 active_dwell, passive_dwell;
595 int i, j, index = 0;
596 bool partial;
597
598 /*
599 * We have to configure all supported channels, even if we don't want to
600 * scan on them, but we have to send channels in the order that we want
601 * to scan. So add requested channels to head of the list and others to
602 * the end.
603 */
604 active_dwell = iwl_mvm_get_active_dwell(band, n_probes);
605 passive_dwell = iwl_mvm_get_passive_dwell(band);
606 s_band = &mvm->nvm_data->bands[band];
607
608 for (i = 0; i < s_band->n_channels && *head <= *tail; i++) {
609 partial = false;
610 for (j = 0; j < n_channels; j++)
611 if (s_band->channels[i].center_freq ==
612 req->channels[j]->center_freq) {
613 index = *head;
614 (*head)++;
615 /*
616 * Channels that came with the request will be
617 * in partial scan .
618 */
619 partial = true;
620 break;
621 }
622 if (!partial) {
623 index = *tail;
624 (*tail)--;
625 }
626 channels->channel_number[index] =
627 cpu_to_le16(ieee80211_frequency_to_channel(
628 s_band->channels[i].center_freq));
629 channels->dwell_time[index][0] = active_dwell;
630 channels->dwell_time[index][1] = passive_dwell;
631
632 channels->iter_count[index] = cpu_to_le16(1);
633 channels->iter_interval[index] = 0;
634
635 if (!(s_band->channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN))
636 channels->type[index] |=
637 cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_ACTIVE);
638
639 channels->type[index] |=
640 cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_FULL);
641 if (partial)
642 channels->type[index] |=
643 cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_PARTIAL);
644
645 if (s_band->channels[i].flags & IEEE80211_CHAN_NO_HT40)
646 channels->type[index] |=
647 cpu_to_le32(IWL_SCAN_OFFLOAD_CHANNEL_NARROW);
648
649 /* scan for all SSIDs from req->ssids */
650 channels->type[index] |= cpu_to_le32(ssid_bitmap);
651 }
652}
653
654int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
655 struct ieee80211_vif *vif,
656 struct cfg80211_sched_scan_request *req,
657 struct ieee80211_sched_scan_ies *ies)
658{
659 int supported_bands = 0;
660 int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
661 int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
662 int head = 0;
663 int tail = band_2ghz + band_5ghz;
664 u32 ssid_bitmap;
665 int cmd_len;
666 int ret;
667
668 struct iwl_scan_offload_cfg *scan_cfg;
669 struct iwl_host_cmd cmd = {
670 .id = SCAN_OFFLOAD_CONFIG_CMD,
671 .flags = CMD_SYNC,
672 };
673
674 lockdep_assert_held(&mvm->mutex);
675
676 if (band_2ghz)
677 supported_bands++;
678 if (band_5ghz)
679 supported_bands++;
680
681 cmd_len = sizeof(struct iwl_scan_offload_cfg) +
682 supported_bands * SCAN_OFFLOAD_PROBE_REQ_SIZE;
683
684 scan_cfg = kzalloc(cmd_len, GFP_KERNEL);
685 if (!scan_cfg)
686 return -ENOMEM;
687
688 iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd);
689 scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
690
691 iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap);
692 /* build tx frames for supported bands */
693 if (band_2ghz) {
694 iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
695 IEEE80211_BAND_2GHZ,
696 &scan_cfg->scan_cmd.tx_cmd[0],
697 scan_cfg->data);
698 iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
699 IEEE80211_BAND_2GHZ, &head, &tail,
700 ssid_bitmap);
701 }
702 if (band_5ghz) {
703 iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
704 IEEE80211_BAND_5GHZ,
705 &scan_cfg->scan_cmd.tx_cmd[1],
706 scan_cfg->data +
707 SCAN_OFFLOAD_PROBE_REQ_SIZE);
708 iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
709 IEEE80211_BAND_5GHZ, &head, &tail,
710 ssid_bitmap);
711 }
712
713 cmd.data[0] = scan_cfg;
714 cmd.len[0] = cmd_len;
715 cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
716
717 IWL_DEBUG_SCAN(mvm, "Sending scheduled scan config\n");
718
719 ret = iwl_mvm_send_cmd(mvm, &cmd);
720 kfree(scan_cfg);
721 return ret;
722}
723
724int iwl_mvm_config_sched_scan_profiles(struct iwl_mvm *mvm,
725 struct cfg80211_sched_scan_request *req)
726{
727 struct iwl_scan_offload_profile *profile;
728 struct iwl_scan_offload_profile_cfg *profile_cfg;
729 struct iwl_scan_offload_blacklist *blacklist;
730 struct iwl_host_cmd cmd = {
731 .id = SCAN_OFFLOAD_UPDATE_PROFILES_CMD,
732 .flags = CMD_SYNC,
733 .len[1] = sizeof(*profile_cfg),
734 .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
735 .dataflags[1] = IWL_HCMD_DFL_NOCOPY,
736 };
737 int blacklist_len;
738 int i;
739 int ret;
740
741 if (WARN_ON(req->n_match_sets > IWL_SCAN_MAX_PROFILES))
742 return -EIO;
743
744 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_SHORT_BL)
745 blacklist_len = IWL_SCAN_SHORT_BLACKLIST_LEN;
746 else
747 blacklist_len = IWL_SCAN_MAX_BLACKLIST_LEN;
748
749 blacklist = kzalloc(sizeof(*blacklist) * blacklist_len, GFP_KERNEL);
750 if (!blacklist)
751 return -ENOMEM;
752
753 profile_cfg = kzalloc(sizeof(*profile_cfg), GFP_KERNEL);
754 if (!profile_cfg) {
755 ret = -ENOMEM;
756 goto free_blacklist;
757 }
758
759 cmd.data[0] = blacklist;
760 cmd.len[0] = sizeof(*blacklist) * blacklist_len;
761 cmd.data[1] = profile_cfg;
762
763 /* No blacklist configuration */
764
765 profile_cfg->num_profiles = req->n_match_sets;
766 profile_cfg->active_clients = SCAN_CLIENT_SCHED_SCAN;
767 profile_cfg->pass_match = SCAN_CLIENT_SCHED_SCAN;
768 profile_cfg->match_notify = SCAN_CLIENT_SCHED_SCAN;
769
770 for (i = 0; i < req->n_match_sets; i++) {
771 profile = &profile_cfg->profiles[i];
772 profile->ssid_index = i;
773 /* Support any cipher and auth algorithm */
774 profile->unicast_cipher = 0xff;
775 profile->auth_alg = 0xff;
776 profile->network_type = IWL_NETWORK_TYPE_ANY;
777 profile->band_selection = IWL_SCAN_OFFLOAD_SELECT_ANY;
778 profile->client_bitmap = SCAN_CLIENT_SCHED_SCAN;
779 }
780
781 IWL_DEBUG_SCAN(mvm, "Sending scheduled scan profile config\n");
782
783 ret = iwl_mvm_send_cmd(mvm, &cmd);
784 kfree(profile_cfg);
785free_blacklist:
786 kfree(blacklist);
787
788 return ret;
789}
790
791int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
792 struct cfg80211_sched_scan_request *req)
793{
794 struct iwl_scan_offload_req scan_req = {
795 .watchdog = IWL_SCHED_SCAN_WATCHDOG,
796
797 .schedule_line[0].iterations = IWL_FAST_SCHED_SCAN_ITERATIONS,
798 .schedule_line[0].delay = req->interval / 1000,
799 .schedule_line[0].full_scan_mul = 1,
800
801 .schedule_line[1].iterations = 0xff,
802 .schedule_line[1].delay = req->interval / 1000,
803 .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER,
804 };
805
806 if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) {
807 IWL_DEBUG_SCAN(mvm,
808 "Sending scheduled scan with filtering, filter len %d\n",
809 req->n_match_sets);
810 scan_req.flags |=
811 cpu_to_le16(IWL_SCAN_OFFLOAD_FLAG_FILTER_SSID);
812 } else {
813 IWL_DEBUG_SCAN(mvm,
814 "Sending Scheduled scan without filtering\n");
815 }
816
817 return iwl_mvm_send_cmd_pdu(mvm, SCAN_OFFLOAD_REQUEST_CMD, CMD_SYNC,
818 sizeof(scan_req), &scan_req);
819}
820
821static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm)
822{
823 int ret;
824 struct iwl_host_cmd cmd = {
825 .id = SCAN_OFFLOAD_ABORT_CMD,
826 .flags = CMD_SYNC,
827 };
828 u32 status;
829
830 /* Exit instantly with error when device is not ready
831 * to receive scan abort command or it does not perform
832 * scheduled scan currently */
833 if (mvm->scan_status != IWL_MVM_SCAN_SCHED)
834 return -EIO;
835
836 ret = iwl_mvm_send_cmd_status(mvm, &cmd, &status);
837 if (ret)
838 return ret;
839
840 if (status != CAN_ABORT_STATUS) {
841 /*
842 * The scan abort will return 1 for success or
843 * 2 for "failure". A failure condition can be
844 * due to simply not being in an active scan which
845 * can occur if we send the scan abort before the
846 * microcode has notified us that a scan is completed.
847 */
848 IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status);
849 ret = -EIO;
850 }
851
852 return ret;
853}
854
855void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm)
856{
857 int ret;
858
859 lockdep_assert_held(&mvm->mutex);
860
861 if (mvm->scan_status != IWL_MVM_SCAN_SCHED) {
862 IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n");
863 return;
864 }
865
866 ret = iwl_mvm_send_sched_scan_abort(mvm);
867 if (ret)
868 IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret);
869 else
870 IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n");
871}