diff options
author | David S. Miller <davem@davemloft.net> | 2014-12-09 18:12:03 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-12-09 18:12:03 -0500 |
commit | b5f185f33d0432cef6ff78765e033dfa8f4de068 (patch) | |
tree | 33179c016b8fc3b4d57ed7a7786079ba00b6ef4a /drivers/net/wireless/iwlwifi/mvm/scan.c | |
parent | 450fa21942fe2c37f0c9f52d1a33bbc081eee288 (diff) | |
parent | 81c412600f946fc1c8731685cb6c6fae8002043a (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.c | 753 |
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 | ||
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; |
@@ -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 | ||
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 | |||
968 | int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm, | 994 | int 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 | ||
1188 | static 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 | |||
1158 | static void | 1224 | static void |
1159 | 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, |
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 | ||
1422 | int iwl_mvm_cancel_scan(struct iwl_mvm *mvm) | 1506 | int 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 | |||
1529 | struct iwl_umac_scan_done { | ||
1530 | struct iwl_mvm *mvm; | ||
1531 | enum iwl_umac_scan_uid_type type; | ||
1532 | }; | ||
1533 | |||
1534 | static 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 | |||
1554 | static __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 | |||
1573 | int 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 | |||
1642 | static 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 | |||
1653 | static int iwl_mvm_find_free_scan_uid(struct iwl_mvm *mvm) | ||
1654 | { | ||
1655 | return iwl_mvm_find_scan_uid(mvm, 0); | ||
1656 | } | ||
1657 | |||
1658 | static 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 | |||
1670 | static 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 | |||
1695 | static void | ||
1696 | iwl_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 | |||
1713 | static void | ||
1714 | iwl_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 | |||
1730 | static 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 | |||
1751 | int 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 | ¶ms); | ||
1789 | |||
1790 | iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, ¶ms); | ||
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 | |||
1839 | int 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 | ¶ms); | ||
1878 | |||
1879 | iwl_mvm_build_generic_umac_scan_cmd(mvm, cmd, ¶ms); | ||
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 | |||
1944 | int 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 | |||
1985 | static 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 | |||
2008 | static 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 | |||
2023 | static 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 | |||
2080 | int 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 | } | ||