aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/mvm/scan.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-12-09 18:12:03 -0500
committerDavid S. Miller <davem@davemloft.net>2014-12-09 18:12:03 -0500
commitb5f185f33d0432cef6ff78765e033dfa8f4de068 (patch)
tree33179c016b8fc3b4d57ed7a7786079ba00b6ef4a /drivers/net/wireless/iwlwifi/mvm/scan.c
parent450fa21942fe2c37f0c9f52d1a33bbc081eee288 (diff)
parent81c412600f946fc1c8731685cb6c6fae8002043a (diff)
Merge tag 'master-2014-12-08' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next
John W. Linville says: ==================== pull request: wireless-next 2014-12-08 Please pull this last batch of pending wireless updates for the 3.19 tree... For the wireless bits, Johannes says: "This time I have Felix's no-status rate control work, which will allow drivers to work better with rate control even if they don't have perfect status reporting. In addition to this, a small hwsim fix from Patrik, one of the regulatory patches from Arik, and a number of cleanups and fixes I did myself. Of note is a patch where I disable CFG80211_WEXT so that compatibility is no longer selectable - this is intended as a wake-up call for anyone who's still using it, and is still easily worked around (it's a one-line patch) before we fully remove the code as well in the future." For the Bluetooth bits, Johan says: "Here's one more bluetooth-next pull request for 3.19: - Minor cleanups for ieee802154 & mac802154 - Fix for the kernel warning with !TASK_RUNNING reported by Kirill A. Shutemov - Support for another ath3k device - Fix for tracking link key based security level - Device tree bindings for btmrvl + a state update fix - Fix for wrong ACL flags on LE links" And... "In addition to the previous one this contains two more cleanups to mac802154 as well as support for some new HCI features from the Bluetooth 4.2 specification. From the original request: 'Here's what should be the last bluetooth-next pull request for 3.19. It's rather large but the majority of it is the Low Energy Secure Connections feature that's part of the Bluetooth 4.2 specification. The specification went public only this week so we couldn't publish the corresponding code before that. The code itself can nevertheless be considered fairly mature as it's been in development for over 6 months and gone through several interoperability test events. Besides LE SC the pull request contains an important fix for command complete events for mgmt sockets which also fixes some leaks of hci_conn objects when powering off or unplugging Bluetooth adapters. A smaller feature that's part of the pull request is service discovery support. This is like normal device discovery except that devices not matching specific UUIDs or strong enough RSSI are filtered out. Other changes that the pull request contains are firmware dump support to the btmrvl driver, firmware download support for Broadcom BCM20702A0 variants, as well as some coding style cleanups in 6lowpan & ieee802154/mac802154 code.'" For the NFC bits, Samuel says: "With this one we get: - NFC digital improvements for DEP support: Chaining, NACK and ATN support added. - NCI improvements: Support for p2p target, SE IO operand addition, SE operands extensions to support proprietary implementations, and a few fixes. - NFC HCI improvements: OPEN_PIPE and NOTIFY_ALL_CLEARED support, and SE IO operand addition. - A bunch of minor improvements and fixes for STMicro st21nfcb and st21nfca" For the iwlwifi bits, Emmanuel says: "Major works are CSA and TDLS. On top of that I have a new firmware API for scan and a few rate control improvements. Johannes find a few tricks to improve our CPU utilization and adds support for a new spin of 7265 called 7265D. Along with this a few random things that don't stand out." And... "I deprecate here -8.ucode since -9 has been published long ago. Along with that I have a new activity, we have now better a infrastructure for firmware debugging. This will allow to have configurable probes insides the firmware. Luca continues his work on NetDetect, this feature is now complete. All the rest is minor fixes here and there." For the Atheros bits, Kalle says: "Only ath10k changes this time and no major changes. Most visible are: o new debugfs interface for runtime firmware debugging (Yanbo) o fix shared WEP (Sujith) o don't rebuild whenever kernel version changes (Johannes) o lots of refactoring to make it easier to add new hw support (Michal) There's also smaller fixes and improvements with no point of listing here." In addition, there are a few last minute updates to ath5k, ath9k, brcmfmac, brcmsmac, mwifiex, rt2x00, rtlwifi, and wil6210. Also included is a pull of the wireless tree to pick-up the fixes originally included in "pull request: wireless 2014-12-03"... Please let me know if there are problems! ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/scan.c')
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c753
1 files changed, 707 insertions, 46 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index fb2a8628b8fc..e5294d01181e 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
86enum 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
93static int iwl_umac_scan_stop(struct iwl_mvm *mvm,
94 enum iwl_umac_scan_uid_type type, bool notify);
95
96static 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
86static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm) 103static 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;
@@ -366,6 +380,10 @@ static int iwl_mvm_max_scan_ie_fw_cmd_room(struct iwl_mvm *mvm,
366 !is_sched_scan) 380 !is_sched_scan)
367 max_probe_len -= 32; 381 max_probe_len -= 32;
368 382
383 /* DS parameter set element is added on 2.4GHZ band if required */
384 if (iwl_mvm_rrm_scan_needed(mvm))
385 max_probe_len -= 3;
386
369 return max_probe_len; 387 return max_probe_len;
370} 388}
371 389
@@ -537,23 +555,17 @@ int iwl_mvm_rx_scan_offload_results(struct iwl_mvm *mvm,
537 struct iwl_device_cmd *cmd) 555 struct iwl_device_cmd *cmd)
538{ 556{
539 struct iwl_rx_packet *pkt = rxb_addr(rxb); 557 struct iwl_rx_packet *pkt = rxb_addr(rxb);
540 u8 client_bitmap = 0;
541 558
542 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)) {
543 struct iwl_sched_scan_results *notif = (void *)pkt->data; 561 struct iwl_sched_scan_results *notif = (void *)pkt->data;
544 562
545 client_bitmap = notif->client_bitmap; 563 if (!(notif->client_bitmap & SCAN_CLIENT_SCHED_SCAN))
564 return 0;
546 } 565 }
547 566
548 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN || 567 IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
549 client_bitmap & SCAN_CLIENT_SCHED_SCAN) { 568 ieee80211_sched_scan_results(mvm->hw);
550 if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
551 IWL_DEBUG_SCAN(mvm, "Scheduled scan results\n");
552 ieee80211_sched_scan_results(mvm->hw);
553 } else {
554 IWL_DEBUG_SCAN(mvm, "Scan results\n");
555 }
556 }
557 569
558 return 0; 570 return 0;
559} 571}
@@ -965,6 +977,20 @@ free_blacklist:
965 return ret; 977 return ret;
966} 978}
967 979
980static 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
968int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, 994int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
969 struct cfg80211_sched_scan_request *req) 995 struct cfg80211_sched_scan_request *req)
970{ 996{
@@ -980,15 +1006,8 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
980 .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER, 1006 .schedule_line[1].full_scan_mul = IWL_FULL_SCAN_MULTIPLIER,
981 }; 1007 };
982 1008
983 if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { 1009 if (iwl_mvm_scan_pass_all(mvm, req))
984 IWL_DEBUG_SCAN(mvm,
985 "Sending scheduled scan with filtering, filter len %d\n",
986 req->n_match_sets);
987 } else {
988 IWL_DEBUG_SCAN(mvm,
989 "Sending Scheduled scan without filtering\n");
990 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);
991 }
992 1011
993 if (mvm->last_ebs_successful && 1012 if (mvm->last_ebs_successful &&
994 mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT) 1013 mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT)
@@ -1006,12 +1025,19 @@ int iwl_mvm_scan_offload_start(struct iwl_mvm *mvm,
1006{ 1025{
1007 int ret; 1026 int ret;
1008 1027
1009 if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) { 1028 if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
1029 ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
1030 if (ret)
1031 return ret;
1032 ret = iwl_mvm_sched_scan_umac(mvm, vif, req, ies);
1033 } else if ((mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)) {
1034 mvm->scan_status = IWL_MVM_SCAN_SCHED;
1010 ret = iwl_mvm_config_sched_scan_profiles(mvm, req); 1035 ret = iwl_mvm_config_sched_scan_profiles(mvm, req);
1011 if (ret) 1036 if (ret)
1012 return ret; 1037 return ret;
1013 ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies); 1038 ret = iwl_mvm_unified_sched_scan_lmac(mvm, vif, req, ies);
1014 } else { 1039 } else {
1040 mvm->scan_status = IWL_MVM_SCAN_SCHED;
1015 ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies); 1041 ret = iwl_mvm_config_sched_scan(mvm, vif, req, ies);
1016 if (ret) 1042 if (ret)
1017 return ret; 1043 return ret;
@@ -1068,6 +1094,10 @@ int iwl_mvm_scan_offload_stop(struct iwl_mvm *mvm, bool notify)
1068 1094
1069 lockdep_assert_held(&mvm->mutex); 1095 lockdep_assert_held(&mvm->mutex);
1070 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
1071 if (mvm->scan_status != IWL_MVM_SCAN_SCHED && 1101 if (mvm->scan_status != IWL_MVM_SCAN_SCHED &&
1072 (!(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) ||
1073 mvm->scan_status != IWL_MVM_SCAN_OS)) { 1103 mvm->scan_status != IWL_MVM_SCAN_OS)) {
@@ -1155,20 +1185,64 @@ iwl_mvm_lmac_scan_cfg_channels(struct iwl_mvm *mvm,
1155 } 1185 }
1156} 1186}
1157 1187
1188static u8 *iwl_mvm_copy_and_insert_ds_elem(struct iwl_mvm *mvm, const u8 *ies,
1189 size_t len, u8 *const pos)
1190{
1191 static const u8 before_ds_params[] = {
1192 WLAN_EID_SSID,
1193 WLAN_EID_SUPP_RATES,
1194 WLAN_EID_REQUEST,
1195 WLAN_EID_EXT_SUPP_RATES,
1196 };
1197 size_t offs;
1198 u8 *newpos = pos;
1199
1200 if (!iwl_mvm_rrm_scan_needed(mvm)) {
1201 memcpy(newpos, ies, len);
1202 return newpos + len;
1203 }
1204
1205 offs = ieee80211_ie_split(ies, len,
1206 before_ds_params,
1207 ARRAY_SIZE(before_ds_params),
1208 0);
1209
1210 memcpy(newpos, ies, offs);
1211 newpos += offs;
1212
1213 /* Add a placeholder for DS Parameter Set element */
1214 *newpos++ = WLAN_EID_DS_PARAMS;
1215 *newpos++ = 1;
1216 *newpos++ = 0;
1217
1218 memcpy(newpos, ies + offs, len - offs);
1219 newpos += len - offs;
1220
1221 return newpos;
1222}
1223
1158static void 1224static void
1159iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif, 1225iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1160 struct ieee80211_scan_ies *ies, 1226 struct ieee80211_scan_ies *ies,
1161 struct iwl_scan_req_unified_lmac *cmd) 1227 struct iwl_scan_probe_req *preq,
1228 const u8 *mac_addr, const u8 *mac_addr_mask)
1162{ 1229{
1163 struct iwl_scan_probe_req *preq = (void *)(cmd->data +
1164 sizeof(struct iwl_scan_channel_cfg_lmac) *
1165 mvm->fw->ucode_capa.n_scan_channels);
1166 struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf; 1230 struct ieee80211_mgmt *frame = (struct ieee80211_mgmt *)preq->buf;
1167 u8 *pos; 1231 u8 *pos, *newpos;
1232
1233 /*
1234 * Unfortunately, right now the offload scan doesn't support randomising
1235 * within the firmware, so until the firmware API is ready we implement
1236 * it in the driver. This means that the scan iterations won't really be
1237 * random, only when it's restarted, but at least that helps a bit.
1238 */
1239 if (mac_addr)
1240 get_random_mask_addr(frame->sa, mac_addr, mac_addr_mask);
1241 else
1242 memcpy(frame->sa, vif->addr, ETH_ALEN);
1168 1243
1169 frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); 1244 frame->frame_control = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ);
1170 eth_broadcast_addr(frame->da); 1245 eth_broadcast_addr(frame->da);
1171 memcpy(frame->sa, vif->addr, ETH_ALEN);
1172 eth_broadcast_addr(frame->bssid); 1246 eth_broadcast_addr(frame->bssid);
1173 frame->seq_ctrl = 0; 1247 frame->seq_ctrl = 0;
1174 1248
@@ -1179,11 +1253,14 @@ iwl_mvm_build_unified_scan_probe(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1179 preq->mac_header.offset = 0; 1253 preq->mac_header.offset = 0;
1180 preq->mac_header.len = cpu_to_le16(24 + 2); 1254 preq->mac_header.len = cpu_to_le16(24 + 2);
1181 1255
1182 memcpy(pos, ies->ies[IEEE80211_BAND_2GHZ], 1256 /* Insert ds parameter set element on 2.4 GHz band */
1183 ies->len[IEEE80211_BAND_2GHZ]); 1257 newpos = iwl_mvm_copy_and_insert_ds_elem(mvm,
1258 ies->ies[IEEE80211_BAND_2GHZ],
1259 ies->len[IEEE80211_BAND_2GHZ],
1260 pos);
1184 preq->band_data[0].offset = cpu_to_le16(pos - preq->buf); 1261 preq->band_data[0].offset = cpu_to_le16(pos - preq->buf);
1185 preq->band_data[0].len = cpu_to_le16(ies->len[IEEE80211_BAND_2GHZ]); 1262 preq->band_data[0].len = cpu_to_le16(newpos - pos);
1186 pos += ies->len[IEEE80211_BAND_2GHZ]; 1263 pos = newpos;
1187 1264
1188 memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ], 1265 memcpy(pos, ies->ies[IEEE80211_BAND_5GHZ],
1189 ies->len[IEEE80211_BAND_5GHZ]); 1266 ies->len[IEEE80211_BAND_5GHZ]);
@@ -1244,9 +1321,10 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
1244 .dataflags = { IWL_HCMD_DFL_NOCOPY, }, 1321 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
1245 }; 1322 };
1246 struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; 1323 struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
1324 struct iwl_scan_probe_req *preq;
1247 struct iwl_mvm_scan_params params = {}; 1325 struct iwl_mvm_scan_params params = {};
1248 u32 flags; 1326 u32 flags;
1249 int ssid_bitmap = 0; 1327 u32 ssid_bitmap = 0;
1250 int ret, i; 1328 int ret, i;
1251 1329
1252 lockdep_assert_held(&mvm->mutex); 1330 lockdep_assert_held(&mvm->mutex);
@@ -1305,7 +1383,13 @@ int iwl_mvm_unified_scan_lmac(struct iwl_mvm *mvm,
1305 req->req.n_channels, ssid_bitmap, 1383 req->req.n_channels, ssid_bitmap,
1306 cmd); 1384 cmd);
1307 1385
1308 iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, cmd); 1386 preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
1387 mvm->fw->ucode_capa.n_scan_channels);
1388
1389 iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, preq,
1390 req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
1391 req->req.mac_addr : NULL,
1392 req->req.mac_addr_mask);
1309 1393
1310 ret = iwl_mvm_send_cmd(mvm, &hcmd); 1394 ret = iwl_mvm_send_cmd(mvm, &hcmd);
1311 if (!ret) { 1395 if (!ret) {
@@ -1338,6 +1422,7 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
1338 .dataflags = { IWL_HCMD_DFL_NOCOPY, }, 1422 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
1339 }; 1423 };
1340 struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd; 1424 struct iwl_scan_req_unified_lmac *cmd = mvm->scan_cmd;
1425 struct iwl_scan_probe_req *preq;
1341 struct iwl_mvm_scan_params params = {}; 1426 struct iwl_mvm_scan_params params = {};
1342 int ret; 1427 int ret;
1343 u32 flags = 0, ssid_bitmap = 0; 1428 u32 flags = 0, ssid_bitmap = 0;
@@ -1361,15 +1446,8 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
1361 1446
1362 cmd->n_channels = (u8)req->n_channels; 1447 cmd->n_channels = (u8)req->n_channels;
1363 1448
1364 if (req->n_match_sets && req->match_sets[0].ssid.ssid_len) { 1449 if (iwl_mvm_scan_pass_all(mvm, req))
1365 IWL_DEBUG_SCAN(mvm,
1366 "Sending scheduled scan with filtering, n_match_sets %d\n",
1367 req->n_match_sets);
1368 } else {
1369 IWL_DEBUG_SCAN(mvm,
1370 "Sending Scheduled scan without filtering\n");
1371 flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL; 1450 flags |= IWL_MVM_LMAC_SCAN_FLAG_PASS_ALL;
1372 }
1373 1451
1374 if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0) 1452 if (req->n_ssids == 1 && req->ssids[0].ssid_len != 0)
1375 flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION; 1453 flags |= IWL_MVM_LMAC_SCAN_FLAG_PRE_CONNECTION;
@@ -1399,7 +1477,13 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
1399 iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels, 1477 iwl_mvm_lmac_scan_cfg_channels(mvm, req->channels, req->n_channels,
1400 ssid_bitmap, cmd); 1478 ssid_bitmap, cmd);
1401 1479
1402 iwl_mvm_build_unified_scan_probe(mvm, vif, ies, cmd); 1480 preq = (void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
1481 mvm->fw->ucode_capa.n_scan_channels);
1482
1483 iwl_mvm_build_unified_scan_probe(mvm, vif, ies, preq,
1484 req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
1485 req->mac_addr : NULL,
1486 req->mac_addr_mask);
1403 1487
1404 ret = iwl_mvm_send_cmd(mvm, &hcmd); 1488 ret = iwl_mvm_send_cmd(mvm, &hcmd);
1405 if (!ret) { 1489 if (!ret) {
@@ -1421,6 +1505,10 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
1421 1505
1422int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) 1506int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
1423{ 1507{
1508 if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
1509 return iwl_umac_scan_stop(mvm, IWL_UMAC_SCAN_UID_REG_SCAN,
1510 true);
1511
1424 if (mvm->scan_status == IWL_MVM_SCAN_NONE) 1512 if (mvm->scan_status == IWL_MVM_SCAN_NONE)
1425 return 0; 1513 return 0;
1426 1514
@@ -1435,3 +1523,576 @@ int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
1435 return iwl_mvm_scan_offload_stop(mvm, true); 1523 return iwl_mvm_scan_offload_stop(mvm, true);
1436 return iwl_mvm_cancel_regular_scan(mvm); 1524 return iwl_mvm_cancel_regular_scan(mvm);
1437} 1525}
1526
1527/* UMAC scan API */
1528
1529struct iwl_umac_scan_done {
1530 struct iwl_mvm *mvm;
1531 enum iwl_umac_scan_uid_type type;
1532};
1533
1534static int rate_to_scan_rate_flag(unsigned int rate)
1535{
1536 static const int rate_to_scan_rate[IWL_RATE_COUNT] = {
1537 [IWL_RATE_1M_INDEX] = SCAN_CONFIG_RATE_1M,
1538 [IWL_RATE_2M_INDEX] = SCAN_CONFIG_RATE_2M,
1539 [IWL_RATE_5M_INDEX] = SCAN_CONFIG_RATE_5M,
1540 [IWL_RATE_11M_INDEX] = SCAN_CONFIG_RATE_11M,
1541 [IWL_RATE_6M_INDEX] = SCAN_CONFIG_RATE_6M,
1542 [IWL_RATE_9M_INDEX] = SCAN_CONFIG_RATE_9M,
1543 [IWL_RATE_12M_INDEX] = SCAN_CONFIG_RATE_12M,
1544 [IWL_RATE_18M_INDEX] = SCAN_CONFIG_RATE_18M,
1545 [IWL_RATE_24M_INDEX] = SCAN_CONFIG_RATE_24M,
1546 [IWL_RATE_36M_INDEX] = SCAN_CONFIG_RATE_36M,
1547 [IWL_RATE_48M_INDEX] = SCAN_CONFIG_RATE_48M,
1548 [IWL_RATE_54M_INDEX] = SCAN_CONFIG_RATE_54M,
1549 };
1550
1551 return rate_to_scan_rate[rate];
1552}
1553
1554static __le32 iwl_mvm_scan_config_rates(struct iwl_mvm *mvm)
1555{
1556 struct ieee80211_supported_band *band;
1557 unsigned int rates = 0;
1558 int i;
1559
1560 band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
1561 for (i = 0; i < band->n_bitrates; i++)
1562 rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value);
1563 band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
1564 for (i = 0; i < band->n_bitrates; i++)
1565 rates |= rate_to_scan_rate_flag(band->bitrates[i].hw_value);
1566
1567 /* Set both basic rates and supported rates */
1568 rates |= SCAN_CONFIG_SUPPORTED_RATE(rates);
1569
1570 return cpu_to_le32(rates);
1571}
1572
1573int iwl_mvm_config_scan(struct iwl_mvm *mvm)
1574{
1575
1576 struct iwl_scan_config *scan_config;
1577 struct ieee80211_supported_band *band;
1578 int num_channels =
1579 mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +
1580 mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
1581 int ret, i, j = 0, cmd_size, data_size;
1582 struct iwl_host_cmd cmd = {
1583 .id = SCAN_CFG_CMD,
1584 };
1585
1586 if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels))
1587 return -ENOBUFS;
1588
1589 cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels;
1590
1591 scan_config = kzalloc(cmd_size, GFP_KERNEL);
1592 if (!scan_config)
1593 return -ENOMEM;
1594
1595 data_size = cmd_size - sizeof(struct iwl_mvm_umac_cmd_hdr);
1596 scan_config->hdr.size = cpu_to_le16(data_size);
1597 scan_config->flags = cpu_to_le32(SCAN_CONFIG_FLAG_ACTIVATE |
1598 SCAN_CONFIG_FLAG_ALLOW_CHUB_REQS |
1599 SCAN_CONFIG_FLAG_SET_TX_CHAINS |
1600 SCAN_CONFIG_FLAG_SET_RX_CHAINS |
1601 SCAN_CONFIG_FLAG_SET_ALL_TIMES |
1602 SCAN_CONFIG_FLAG_SET_LEGACY_RATES |
1603 SCAN_CONFIG_FLAG_SET_MAC_ADDR |
1604 SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS|
1605 SCAN_CONFIG_N_CHANNELS(num_channels));
1606 scan_config->tx_chains = cpu_to_le32(mvm->fw->valid_tx_ant);
1607 scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm));
1608 scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm);
1609 scan_config->out_of_channel_time = cpu_to_le32(170);
1610 scan_config->suspend_time = cpu_to_le32(30);
1611 scan_config->dwell_active = 20;
1612 scan_config->dwell_passive = 110;
1613 scan_config->dwell_fragmented = 20;
1614
1615 memcpy(&scan_config->mac_addr, &mvm->addresses[0].addr, ETH_ALEN);
1616
1617 scan_config->bcast_sta_id = mvm->aux_sta.sta_id;
1618 scan_config->channel_flags = IWL_CHANNEL_FLAG_EBS |
1619 IWL_CHANNEL_FLAG_ACCURATE_EBS |
1620 IWL_CHANNEL_FLAG_EBS_ADD |
1621 IWL_CHANNEL_FLAG_PRE_SCAN_PASSIVE2ACTIVE;
1622
1623 band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
1624 for (i = 0; i < band->n_channels; i++, j++)
1625 scan_config->channel_array[j] = band->channels[i].center_freq;
1626 band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
1627 for (i = 0; i < band->n_channels; i++, j++)
1628 scan_config->channel_array[j] = band->channels[i].center_freq;
1629
1630 cmd.data[0] = scan_config;
1631 cmd.len[0] = cmd_size;
1632 cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
1633
1634 IWL_DEBUG_SCAN(mvm, "Sending UMAC scan config\n");
1635
1636 ret = iwl_mvm_send_cmd(mvm, &cmd);
1637
1638 kfree(scan_config);
1639 return ret;
1640}
1641
1642static int iwl_mvm_find_scan_uid(struct iwl_mvm *mvm, u32 uid)
1643{
1644 int i;
1645
1646 for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
1647 if (mvm->scan_uid[i] == uid)
1648 return i;
1649
1650 return i;
1651}
1652
1653static int iwl_mvm_find_free_scan_uid(struct iwl_mvm *mvm)
1654{
1655 return iwl_mvm_find_scan_uid(mvm, 0);
1656}
1657
1658static bool iwl_mvm_find_scan_type(struct iwl_mvm *mvm,
1659 enum iwl_umac_scan_uid_type type)
1660{
1661 int i;
1662
1663 for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++)
1664 if (mvm->scan_uid[i] & type)
1665 return true;
1666
1667 return false;
1668}
1669
1670static u32 iwl_generate_scan_uid(struct iwl_mvm *mvm,
1671 enum iwl_umac_scan_uid_type type)
1672{
1673 u32 uid;
1674
1675 /* make sure exactly one bit is on in scan type */
1676 WARN_ON(hweight8(type) != 1);
1677
1678 /*
1679 * Make sure scan uids are unique. If one scan lasts long time while
1680 * others are completing frequently, the seq number will wrap up and
1681 * we may have more than one scan with the same uid.
1682 */
1683 do {
1684 uid = type | (mvm->scan_seq_num <<
1685 IWL_UMAC_SCAN_UID_SEQ_OFFSET);
1686 mvm->scan_seq_num++;
1687 } while (iwl_mvm_find_scan_uid(mvm, uid) <
1688 IWL_MVM_MAX_SIMULTANEOUS_SCANS);
1689
1690 IWL_DEBUG_SCAN(mvm, "Generated scan UID %u\n", uid);
1691
1692 return uid;
1693}
1694
1695static void
1696iwl_mvm_build_generic_umac_scan_cmd(struct iwl_mvm *mvm,
1697 struct iwl_scan_req_umac *cmd,
1698 struct iwl_mvm_scan_params *params)
1699{
1700 memset(cmd, 0, ksize(cmd));
1701 cmd->hdr.size = cpu_to_le16(iwl_mvm_scan_size(mvm) -
1702 sizeof(struct iwl_mvm_umac_cmd_hdr));
1703 cmd->active_dwell = params->dwell[IEEE80211_BAND_2GHZ].active;
1704 cmd->passive_dwell = params->dwell[IEEE80211_BAND_2GHZ].passive;
1705 if (params->passive_fragmented)
1706 cmd->fragmented_dwell =
1707 params->dwell[IEEE80211_BAND_2GHZ].passive;
1708 cmd->max_out_time = cpu_to_le32(params->max_out_time);
1709 cmd->suspend_time = cpu_to_le32(params->suspend_time);
1710 cmd->scan_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
1711}
1712
1713static void
1714iwl_mvm_umac_scan_cfg_channels(struct iwl_mvm *mvm,
1715 struct ieee80211_channel **channels,
1716 int n_channels, u32 ssid_bitmap,
1717 struct iwl_scan_req_umac *cmd)
1718{
1719 struct iwl_scan_channel_cfg_umac *channel_cfg = (void *)&cmd->data;
1720 int i;
1721
1722 for (i = 0; i < n_channels; i++) {
1723 channel_cfg[i].flags = cpu_to_le32(ssid_bitmap);
1724 channel_cfg[i].channel_num = channels[i]->hw_value;
1725 channel_cfg[i].iter_count = 1;
1726 channel_cfg[i].iter_interval = 0;
1727 }
1728}
1729
1730static u32 iwl_mvm_scan_umac_common_flags(struct iwl_mvm *mvm, int n_ssids,
1731 struct cfg80211_ssid *ssids,
1732 int fragmented)
1733{
1734 int flags = 0;
1735
1736 if (n_ssids == 0)
1737 flags = IWL_UMAC_SCAN_GEN_FLAGS_PASSIVE;
1738
1739 if (n_ssids == 1 && ssids[0].ssid_len != 0)
1740 flags |= IWL_UMAC_SCAN_GEN_FLAGS_PRE_CONNECT;
1741
1742 if (fragmented)
1743 flags |= IWL_UMAC_SCAN_GEN_FLAGS_FRAGMENTED;
1744
1745 if (iwl_mvm_rrm_scan_needed(mvm))
1746 flags |= IWL_UMAC_SCAN_GEN_FLAGS_RRM_ENABLED;
1747
1748 return flags;
1749}
1750
1751int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1752 struct ieee80211_scan_request *req)
1753{
1754 struct iwl_host_cmd hcmd = {
1755 .id = SCAN_REQ_UMAC,
1756 .len = { iwl_mvm_scan_size(mvm), },
1757 .data = { mvm->scan_cmd, },
1758 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
1759 };
1760 struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
1761 struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
1762 sizeof(struct iwl_scan_channel_cfg_umac) *
1763 mvm->fw->ucode_capa.n_scan_channels;
1764 struct iwl_mvm_scan_params params = {};
1765 u32 uid, flags;
1766 u32 ssid_bitmap = 0;
1767 int ret, i, uid_idx;
1768
1769 lockdep_assert_held(&mvm->mutex);
1770
1771 uid_idx = iwl_mvm_find_free_scan_uid(mvm);
1772 if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
1773 return -EBUSY;
1774
1775 /* we should have failed registration if scan_cmd was NULL */
1776 if (WARN_ON(mvm->scan_cmd == NULL))
1777 return -ENOMEM;
1778
1779 if (WARN_ON(req->req.n_ssids > PROBE_OPTION_MAX ||
1780 req->ies.common_ie_len +
1781 req->ies.len[NL80211_BAND_2GHZ] +
1782 req->ies.len[NL80211_BAND_5GHZ] + 24 + 2 >
1783 SCAN_OFFLOAD_PROBE_REQ_SIZE || req->req.n_channels >
1784 mvm->fw->ucode_capa.n_scan_channels))
1785 return -ENOBUFS;
1786
1787 iwl_mvm_scan_calc_params(mvm, vif, req->req.n_ssids, req->req.flags,
1788 &params);
1789
1790 iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, &params);
1791
1792 uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_REG_SCAN);
1793 mvm->scan_uid[uid_idx] = uid;
1794 cmd->uid = cpu_to_le32(uid);
1795
1796 cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_HIGH);
1797
1798 flags = iwl_mvm_scan_umac_common_flags(mvm, req->req.n_ssids,
1799 req->req.ssids,
1800 params.passive_fragmented);
1801
1802 flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
1803
1804 cmd->general_flags = cpu_to_le32(flags);
1805 cmd->n_channels = req->req.n_channels;
1806
1807 for (i = 0; i < req->req.n_ssids; i++)
1808 ssid_bitmap |= BIT(i);
1809
1810 iwl_mvm_umac_scan_cfg_channels(mvm, req->req.channels,
1811 req->req.n_channels, ssid_bitmap, cmd);
1812
1813 sec_part->schedule[0].iter_count = 1;
1814 sec_part->delay = 0;
1815
1816 iwl_mvm_build_unified_scan_probe(mvm, vif, &req->ies, &sec_part->preq,
1817 req->req.flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
1818 req->req.mac_addr : NULL,
1819 req->req.mac_addr_mask);
1820
1821 iwl_mvm_scan_fill_ssids(sec_part->direct_scan, req->req.ssids,
1822 req->req.n_ssids, 0);
1823
1824 ret = iwl_mvm_send_cmd(mvm, &hcmd);
1825 if (!ret) {
1826 IWL_DEBUG_SCAN(mvm,
1827 "Scan request was sent successfully\n");
1828 } else {
1829 /*
1830 * If the scan failed, it usually means that the FW was unable
1831 * to allocate the time events. Warn on it, but maybe we
1832 * should try to send the command again with different params.
1833 */
1834 IWL_ERR(mvm, "Scan failed! ret %d\n", ret);
1835 }
1836 return ret;
1837}
1838
1839int iwl_mvm_sched_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
1840 struct cfg80211_sched_scan_request *req,
1841 struct ieee80211_scan_ies *ies)
1842{
1843
1844 struct iwl_host_cmd hcmd = {
1845 .id = SCAN_REQ_UMAC,
1846 .len = { iwl_mvm_scan_size(mvm), },
1847 .data = { mvm->scan_cmd, },
1848 .dataflags = { IWL_HCMD_DFL_NOCOPY, },
1849 };
1850 struct iwl_scan_req_umac *cmd = mvm->scan_cmd;
1851 struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
1852 sizeof(struct iwl_scan_channel_cfg_umac) *
1853 mvm->fw->ucode_capa.n_scan_channels;
1854 struct iwl_mvm_scan_params params = {};
1855 u32 uid, flags;
1856 u32 ssid_bitmap = 0;
1857 int ret, uid_idx;
1858
1859 lockdep_assert_held(&mvm->mutex);
1860
1861 uid_idx = iwl_mvm_find_free_scan_uid(mvm);
1862 if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
1863 return -EBUSY;
1864
1865 /* we should have failed registration if scan_cmd was NULL */
1866 if (WARN_ON(mvm->scan_cmd == NULL))
1867 return -ENOMEM;
1868
1869 if (WARN_ON(req->n_ssids > PROBE_OPTION_MAX ||
1870 ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] +
1871 ies->len[NL80211_BAND_5GHZ] + 24 + 2 >
1872 SCAN_OFFLOAD_PROBE_REQ_SIZE || req->n_channels >
1873 mvm->fw->ucode_capa.n_scan_channels))
1874 return -ENOBUFS;
1875
1876 iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, req->flags,
1877 &params);
1878
1879 iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, &params);
1880
1881 cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
1882
1883 uid = iwl_generate_scan_uid(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN);
1884 mvm->scan_uid[uid_idx] = uid;
1885 cmd->uid = cpu_to_le32(uid);
1886
1887 cmd->ooc_priority = cpu_to_le32(IWL_SCAN_PRIORITY_LOW);
1888
1889 flags = iwl_mvm_scan_umac_common_flags(mvm, req->n_ssids, req->ssids,
1890 params.passive_fragmented);
1891
1892 flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;
1893
1894 if (iwl_mvm_scan_pass_all(mvm, req))
1895 flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
1896 else
1897 flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;
1898
1899 cmd->general_flags = cpu_to_le32(flags);
1900
1901 if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_EBS_SUPPORT &&
1902 mvm->last_ebs_successful)
1903 cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
1904 IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
1905 IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
1906
1907 cmd->n_channels = req->n_channels;
1908
1909 iwl_scan_offload_build_ssid(req, sec_part->direct_scan, &ssid_bitmap,
1910 false);
1911
1912 /* This API uses bits 0-19 instead of 1-20. */
1913 ssid_bitmap = ssid_bitmap >> 1;
1914
1915 iwl_mvm_umac_scan_cfg_channels(mvm, req->channels, req->n_channels,
1916 ssid_bitmap, cmd);
1917
1918 sec_part->schedule[0].interval =
1919 cpu_to_le16(req->interval / MSEC_PER_SEC);
1920 sec_part->schedule[0].iter_count = 0xff;
1921
1922 sec_part->delay = 0;
1923
1924 iwl_mvm_build_unified_scan_probe(mvm, vif, ies, &sec_part->preq,
1925 req->flags & NL80211_SCAN_FLAG_RANDOM_ADDR ?
1926 req->mac_addr : NULL,
1927 req->mac_addr_mask);
1928
1929 ret = iwl_mvm_send_cmd(mvm, &hcmd);
1930 if (!ret) {
1931 IWL_DEBUG_SCAN(mvm,
1932 "Sched scan request was sent successfully\n");
1933 } else {
1934 /*
1935 * If the scan failed, it usually means that the FW was unable
1936 * to allocate the time events. Warn on it, but maybe we
1937 * should try to send the command again with different params.
1938 */
1939 IWL_ERR(mvm, "Sched scan failed! ret %d\n", ret);
1940 }
1941 return ret;
1942}
1943
1944int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
1945 struct iwl_rx_cmd_buffer *rxb,
1946 struct iwl_device_cmd *cmd)
1947{
1948 struct iwl_rx_packet *pkt = rxb_addr(rxb);
1949 struct iwl_umac_scan_complete *notif = (void *)pkt->data;
1950 u32 uid = __le32_to_cpu(notif->uid);
1951 bool sched = !!(uid & IWL_UMAC_SCAN_UID_SCHED_SCAN);
1952 int uid_idx = iwl_mvm_find_scan_uid(mvm, uid);
1953
1954 /*
1955 * Scan uid may be set to zero in case of scan abort request from above.
1956 */
1957 if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
1958 return 0;
1959
1960 IWL_DEBUG_SCAN(mvm,
1961 "Scan completed, uid %u type %s, status %s, EBS status %s\n",
1962 uid, sched ? "sched" : "regular",
1963 notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
1964 "completed" : "aborted",
1965 notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
1966 "success" : "failed");
1967
1968 mvm->last_ebs_successful = !notif->ebs_status;
1969 mvm->scan_uid[uid_idx] = 0;
1970
1971 if (!sched) {
1972 ieee80211_scan_completed(mvm->hw,
1973 notif->status ==
1974 IWL_SCAN_OFFLOAD_ABORTED);
1975 iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
1976 } else if (!iwl_mvm_find_scan_type(mvm, IWL_UMAC_SCAN_UID_SCHED_SCAN)) {
1977 ieee80211_sched_scan_stopped(mvm->hw);
1978 } else {
1979 IWL_DEBUG_SCAN(mvm, "Another sched scan is running\n");
1980 }
1981
1982 return 0;
1983}
1984
1985static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait,
1986 struct iwl_rx_packet *pkt, void *data)
1987{
1988 struct iwl_umac_scan_done *scan_done = data;
1989 struct iwl_umac_scan_complete *notif = (void *)pkt->data;
1990 u32 uid = __le32_to_cpu(notif->uid);
1991 int uid_idx = iwl_mvm_find_scan_uid(scan_done->mvm, uid);
1992
1993 if (WARN_ON(pkt->hdr.cmd != SCAN_COMPLETE_UMAC))
1994 return false;
1995
1996 if (uid_idx >= IWL_MVM_MAX_SIMULTANEOUS_SCANS)
1997 return false;
1998
1999 /*
2000 * Clear scan uid of scans that was aborted from above and completed
2001 * in FW so the RX handler does nothing.
2002 */
2003 scan_done->mvm->scan_uid[uid_idx] = 0;
2004
2005 return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type);
2006}
2007
2008static int iwl_umac_scan_abort_one(struct iwl_mvm *mvm, u32 uid)
2009{
2010 struct iwl_umac_scan_abort cmd = {
2011 .hdr.size = cpu_to_le16(sizeof(struct iwl_umac_scan_abort) -
2012 sizeof(struct iwl_mvm_umac_cmd_hdr)),
2013 .uid = cpu_to_le32(uid),
2014 };
2015
2016 lockdep_assert_held(&mvm->mutex);
2017
2018 IWL_DEBUG_SCAN(mvm, "Sending scan abort, uid %u\n", uid);
2019
2020 return iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_UMAC, 0, sizeof(cmd), &cmd);
2021}
2022
2023static int iwl_umac_scan_stop(struct iwl_mvm *mvm,
2024 enum iwl_umac_scan_uid_type type, bool notify)
2025{
2026 struct iwl_notification_wait wait_scan_done;
2027 static const u8 scan_done_notif[] = { SCAN_COMPLETE_UMAC, };
2028 struct iwl_umac_scan_done scan_done = {
2029 .mvm = mvm,
2030 .type = type,
2031 };
2032 int i, ret = -EIO;
2033
2034 iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
2035 scan_done_notif,
2036 ARRAY_SIZE(scan_done_notif),
2037 iwl_scan_umac_done_check, &scan_done);
2038
2039 IWL_DEBUG_SCAN(mvm, "Preparing to stop scan, type %x\n", type);
2040
2041 for (i = 0; i < IWL_MVM_MAX_SIMULTANEOUS_SCANS; i++) {
2042 if (mvm->scan_uid[i] & type) {
2043 int err;
2044
2045 if (iwl_mvm_is_radio_killed(mvm) &&
2046 (type & IWL_UMAC_SCAN_UID_REG_SCAN)) {
2047 ieee80211_scan_completed(mvm->hw, true);
2048 iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
2049 break;
2050 }
2051
2052 err = iwl_umac_scan_abort_one(mvm, mvm->scan_uid[i]);
2053 if (!err)
2054 ret = 0;
2055 }
2056 }
2057
2058 if (ret) {
2059 IWL_DEBUG_SCAN(mvm, "Couldn't stop scan\n");
2060 iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
2061 return ret;
2062 }
2063
2064 ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
2065 if (ret)
2066 return ret;
2067
2068 if (notify) {
2069 if (type & IWL_UMAC_SCAN_UID_SCHED_SCAN)
2070 ieee80211_sched_scan_stopped(mvm->hw);
2071 if (type & IWL_UMAC_SCAN_UID_REG_SCAN) {
2072 ieee80211_scan_completed(mvm->hw, true);
2073 iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
2074 }
2075 }
2076
2077 return ret;
2078}
2079
2080int iwl_mvm_scan_size(struct iwl_mvm *mvm)
2081{
2082 if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN)
2083 return sizeof(struct iwl_scan_req_umac) +
2084 sizeof(struct iwl_scan_channel_cfg_umac) *
2085 mvm->fw->ucode_capa.n_scan_channels +
2086 sizeof(struct iwl_scan_req_umac_tail);
2087
2088 if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN)
2089 return sizeof(struct iwl_scan_req_unified_lmac) +
2090 sizeof(struct iwl_scan_channel_cfg_lmac) *
2091 mvm->fw->ucode_capa.n_scan_channels +
2092 sizeof(struct iwl_scan_probe_req);
2093
2094 return sizeof(struct iwl_scan_cmd) +
2095 mvm->fw->ucode_capa.max_probe_length +
2096 mvm->fw->ucode_capa.n_scan_channels *
2097 sizeof(struct iwl_scan_channel);
2098}