|
@@ -70,9 +70,16 @@
|
|
|
|
|
|
#define IWL_PLCP_QUIET_THRESH 1
|
|
#define IWL_PLCP_QUIET_THRESH 1
|
|
#define IWL_ACTIVE_QUIET_TIME 10
|
|
#define IWL_ACTIVE_QUIET_TIME 10
|
|
-#define LONG_OUT_TIME_PERIOD 600
|
|
|
|
-#define SHORT_OUT_TIME_PERIOD 200
|
|
|
|
-#define SUSPEND_TIME_PERIOD 100
|
|
|
|
|
|
+
|
|
|
|
+struct iwl_mvm_scan_params {
|
|
|
|
+ u32 max_out_time;
|
|
|
|
+ u32 suspend_time;
|
|
|
|
+ bool passive_fragmented;
|
|
|
|
+ struct _dwell {
|
|
|
|
+ u16 passive;
|
|
|
|
+ u16 active;
|
|
|
|
+ } dwell[IEEE80211_NUM_BANDS];
|
|
|
|
+};
|
|
|
|
|
|
static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
|
|
static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
|
|
{
|
|
{
|
|
@@ -90,24 +97,6 @@ static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
|
|
return cpu_to_le16(rx_chain);
|
|
return cpu_to_le16(rx_chain);
|
|
}
|
|
}
|
|
|
|
|
|
-static inline __le32 iwl_mvm_scan_max_out_time(struct ieee80211_vif *vif,
|
|
|
|
- u32 flags, bool is_assoc)
|
|
|
|
-{
|
|
|
|
- if (!is_assoc)
|
|
|
|
- return 0;
|
|
|
|
- if (flags & NL80211_SCAN_FLAG_LOW_PRIORITY)
|
|
|
|
- return cpu_to_le32(ieee80211_tu_to_usec(SHORT_OUT_TIME_PERIOD));
|
|
|
|
- return cpu_to_le32(ieee80211_tu_to_usec(LONG_OUT_TIME_PERIOD));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-static inline __le32 iwl_mvm_scan_suspend_time(struct ieee80211_vif *vif,
|
|
|
|
- bool is_assoc)
|
|
|
|
-{
|
|
|
|
- if (!is_assoc)
|
|
|
|
- return 0;
|
|
|
|
- return cpu_to_le32(ieee80211_tu_to_usec(SUSPEND_TIME_PERIOD));
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static inline __le32
|
|
static inline __le32
|
|
iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req)
|
|
iwl_mvm_scan_rxon_flags(struct cfg80211_scan_request *req)
|
|
{
|
|
{
|
|
@@ -181,15 +170,14 @@ static u16 iwl_mvm_get_passive_dwell(enum ieee80211_band band)
|
|
|
|
|
|
static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
|
|
static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
|
|
struct cfg80211_scan_request *req,
|
|
struct cfg80211_scan_request *req,
|
|
- bool basic_ssid)
|
|
|
|
|
|
+ bool basic_ssid,
|
|
|
|
+ struct iwl_mvm_scan_params *params)
|
|
{
|
|
{
|
|
- u16 passive_dwell = iwl_mvm_get_passive_dwell(req->channels[0]->band);
|
|
|
|
- u16 active_dwell = iwl_mvm_get_active_dwell(req->channels[0]->band,
|
|
|
|
- req->n_ssids);
|
|
|
|
struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
|
|
struct iwl_scan_channel *chan = (struct iwl_scan_channel *)
|
|
(cmd->data + le16_to_cpu(cmd->tx_cmd.len));
|
|
(cmd->data + le16_to_cpu(cmd->tx_cmd.len));
|
|
int i;
|
|
int i;
|
|
int type = BIT(req->n_ssids) - 1;
|
|
int type = BIT(req->n_ssids) - 1;
|
|
|
|
+ enum ieee80211_band band = req->channels[0]->band;
|
|
|
|
|
|
if (!basic_ssid)
|
|
if (!basic_ssid)
|
|
type |= BIT(req->n_ssids);
|
|
type |= BIT(req->n_ssids);
|
|
@@ -199,8 +187,8 @@ static void iwl_mvm_scan_fill_channels(struct iwl_scan_cmd *cmd,
|
|
chan->type = cpu_to_le32(type);
|
|
chan->type = cpu_to_le32(type);
|
|
if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
|
|
if (req->channels[i]->flags & IEEE80211_CHAN_NO_IR)
|
|
chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
|
|
chan->type &= cpu_to_le32(~SCAN_CHANNEL_TYPE_ACTIVE);
|
|
- chan->active_dwell = cpu_to_le16(active_dwell);
|
|
|
|
- chan->passive_dwell = cpu_to_le16(passive_dwell);
|
|
|
|
|
|
+ chan->active_dwell = cpu_to_le16(params->dwell[band].active);
|
|
|
|
+ chan->passive_dwell = cpu_to_le16(params->dwell[band].passive);
|
|
chan->iteration_count = cpu_to_le16(1);
|
|
chan->iteration_count = cpu_to_le16(1);
|
|
chan++;
|
|
chan++;
|
|
}
|
|
}
|
|
@@ -267,13 +255,76 @@ static u16 iwl_mvm_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
|
|
return (u16)len;
|
|
return (u16)len;
|
|
}
|
|
}
|
|
|
|
|
|
-static void iwl_mvm_vif_assoc_iterator(void *data, u8 *mac,
|
|
|
|
- struct ieee80211_vif *vif)
|
|
|
|
|
|
+static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
|
|
|
|
+ struct ieee80211_vif *vif)
|
|
{
|
|
{
|
|
- bool *is_assoc = data;
|
|
|
|
|
|
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
|
|
|
+ bool *global_bound = data;
|
|
|
|
|
|
- if (vif->bss_conf.assoc)
|
|
|
|
- *is_assoc = true;
|
|
|
|
|
|
+ if (mvmvif->phy_ctxt && mvmvif->phy_ctxt->id < MAX_PHYS)
|
|
|
|
+ *global_bound = true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
|
|
|
|
+ struct ieee80211_vif *vif,
|
|
|
|
+ int n_ssids,
|
|
|
|
+ struct iwl_mvm_scan_params *params)
|
|
|
|
+{
|
|
|
|
+ bool global_bound = false;
|
|
|
|
+ enum ieee80211_band band;
|
|
|
|
+
|
|
|
|
+ ieee80211_iterate_active_interfaces_atomic(mvm->hw,
|
|
|
|
+ IEEE80211_IFACE_ITER_NORMAL,
|
|
|
|
+ iwl_mvm_scan_condition_iterator,
|
|
|
|
+ &global_bound);
|
|
|
|
+ /*
|
|
|
|
+ * Under low latency traffic passive scan is fragmented meaning
|
|
|
|
+ * that dwell on a particular channel will be fragmented. Each fragment
|
|
|
|
+ * dwell time is 20ms and fragments period is 105ms. Skipping to next
|
|
|
|
+ * channel will be delayed by the same period - 105ms. So suspend_time
|
|
|
|
+ * parameter describing both fragments and channels skipping periods is
|
|
|
|
+ * set to 105ms. This value is chosen so that overall passive scan
|
|
|
|
+ * duration will not be too long. Max_out_time in this case is set to
|
|
|
|
+ * 70ms, so for active scanning operating channel will be left for 70ms
|
|
|
|
+ * while for passive still for 20ms (fragment dwell).
|
|
|
|
+ */
|
|
|
|
+ if (global_bound) {
|
|
|
|
+ if (!iwl_mvm_low_latency(mvm)) {
|
|
|
|
+ params->suspend_time = ieee80211_tu_to_usec(100);
|
|
|
|
+ params->max_out_time = ieee80211_tu_to_usec(600);
|
|
|
|
+ } else {
|
|
|
|
+ params->suspend_time = ieee80211_tu_to_usec(105);
|
|
|
|
+ /* P2P doesn't support fragmented passive scan, so
|
|
|
|
+ * configure max_out_time to be at least longest dwell
|
|
|
|
+ * time for passive scan.
|
|
|
|
+ */
|
|
|
|
+ if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p) {
|
|
|
|
+ params->max_out_time = ieee80211_tu_to_usec(70);
|
|
|
|
+ params->passive_fragmented = true;
|
|
|
|
+ } else {
|
|
|
|
+ u32 passive_dwell;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Use band G so that passive channel dwell time
|
|
|
|
+ * will be assigned with maximum value.
|
|
|
|
+ */
|
|
|
|
+ band = IEEE80211_BAND_2GHZ;
|
|
|
|
+ passive_dwell = iwl_mvm_get_passive_dwell(band);
|
|
|
|
+ params->max_out_time =
|
|
|
|
+ ieee80211_tu_to_usec(passive_dwell);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
|
|
|
|
+ if (params->passive_fragmented)
|
|
|
|
+ params->dwell[band].passive = 20;
|
|
|
|
+ else
|
|
|
|
+ params->dwell[band].passive =
|
|
|
|
+ iwl_mvm_get_passive_dwell(band);
|
|
|
|
+ params->dwell[band].active = iwl_mvm_get_active_dwell(band,
|
|
|
|
+ n_ssids);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|
int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|
@@ -288,13 +339,13 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|
.dataflags = { IWL_HCMD_DFL_NOCOPY, },
|
|
.dataflags = { IWL_HCMD_DFL_NOCOPY, },
|
|
};
|
|
};
|
|
struct iwl_scan_cmd *cmd = mvm->scan_cmd;
|
|
struct iwl_scan_cmd *cmd = mvm->scan_cmd;
|
|
- bool is_assoc = false;
|
|
|
|
int ret;
|
|
int ret;
|
|
u32 status;
|
|
u32 status;
|
|
int ssid_len = 0;
|
|
int ssid_len = 0;
|
|
u8 *ssid = NULL;
|
|
u8 *ssid = NULL;
|
|
bool basic_ssid = !(mvm->fw->ucode_capa.flags &
|
|
bool basic_ssid = !(mvm->fw->ucode_capa.flags &
|
|
IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
|
|
IWL_UCODE_TLV_FLAGS_NO_BASIC_SSID);
|
|
|
|
+ struct iwl_mvm_scan_params params = {};
|
|
|
|
|
|
lockdep_assert_held(&mvm->mutex);
|
|
lockdep_assert_held(&mvm->mutex);
|
|
BUG_ON(mvm->scan_cmd == NULL);
|
|
BUG_ON(mvm->scan_cmd == NULL);
|
|
@@ -304,17 +355,18 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|
memset(cmd, 0, sizeof(struct iwl_scan_cmd) +
|
|
memset(cmd, 0, sizeof(struct iwl_scan_cmd) +
|
|
mvm->fw->ucode_capa.max_probe_length +
|
|
mvm->fw->ucode_capa.max_probe_length +
|
|
(MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)));
|
|
(MAX_NUM_SCAN_CHANNELS * sizeof(struct iwl_scan_channel)));
|
|
- ieee80211_iterate_active_interfaces_atomic(mvm->hw,
|
|
|
|
- IEEE80211_IFACE_ITER_NORMAL,
|
|
|
|
- iwl_mvm_vif_assoc_iterator,
|
|
|
|
- &is_assoc);
|
|
|
|
|
|
+
|
|
cmd->channel_count = (u8)req->n_channels;
|
|
cmd->channel_count = (u8)req->n_channels;
|
|
cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
|
|
cmd->quiet_time = cpu_to_le16(IWL_ACTIVE_QUIET_TIME);
|
|
cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
|
|
cmd->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
|
|
cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm);
|
|
cmd->rxchain_sel_flags = iwl_mvm_scan_rx_chain(mvm);
|
|
- cmd->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags,
|
|
|
|
- is_assoc);
|
|
|
|
- cmd->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc);
|
|
|
|
|
|
+
|
|
|
|
+ iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, ¶ms);
|
|
|
|
+ cmd->max_out_time = cpu_to_le32(params.max_out_time);
|
|
|
|
+ cmd->suspend_time = cpu_to_le32(params.suspend_time);
|
|
|
|
+ if (params.passive_fragmented)
|
|
|
|
+ cmd->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
|
|
|
|
+
|
|
cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req);
|
|
cmd->rxon_flags = iwl_mvm_scan_rxon_flags(req);
|
|
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
|
|
cmd->filter_flags = cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
|
|
MAC_FILTER_IN_BEACON);
|
|
MAC_FILTER_IN_BEACON);
|
|
@@ -360,7 +412,7 @@ int iwl_mvm_scan_request(struct iwl_mvm *mvm,
|
|
req->ie, req->ie_len,
|
|
req->ie, req->ie_len,
|
|
mvm->fw->ucode_capa.max_probe_length));
|
|
mvm->fw->ucode_capa.max_probe_length));
|
|
|
|
|
|
- iwl_mvm_scan_fill_channels(cmd, req, basic_ssid);
|
|
|
|
|
|
+ iwl_mvm_scan_fill_channels(cmd, req, basic_ssid, ¶ms);
|
|
|
|
|
|
cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) +
|
|
cmd->len = cpu_to_le16(sizeof(struct iwl_scan_cmd) +
|
|
le16_to_cpu(cmd->tx_cmd.len) +
|
|
le16_to_cpu(cmd->tx_cmd.len) +
|
|
@@ -402,10 +454,13 @@ int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
|
|
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
|
struct iwl_rx_packet *pkt = rxb_addr(rxb);
|
|
struct iwl_scan_complete_notif *notif = (void *)pkt->data;
|
|
struct iwl_scan_complete_notif *notif = (void *)pkt->data;
|
|
|
|
|
|
|
|
+ lockdep_assert_held(&mvm->mutex);
|
|
|
|
+
|
|
IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n",
|
|
IWL_DEBUG_SCAN(mvm, "Scan complete: status=0x%x scanned channels=%d\n",
|
|
notif->status, notif->scanned_channels);
|
|
notif->status, notif->scanned_channels);
|
|
|
|
|
|
- mvm->scan_status = IWL_MVM_SCAN_NONE;
|
|
|
|
|
|
+ if (mvm->scan_status == IWL_MVM_SCAN_OS)
|
|
|
|
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
|
|
ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK);
|
|
ieee80211_scan_completed(mvm->hw, notif->status != SCAN_COMP_STATUS_OK);
|
|
|
|
|
|
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
|
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
|
@@ -466,7 +521,7 @@ static bool iwl_mvm_scan_abort_notif(struct iwl_notif_wait_data *notif_wait,
|
|
};
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
-void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
|
|
|
|
|
|
+int iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
|
|
{
|
|
{
|
|
struct iwl_notification_wait wait_scan_abort;
|
|
struct iwl_notification_wait wait_scan_abort;
|
|
static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
|
|
static const u8 scan_abort_notif[] = { SCAN_ABORT_CMD,
|
|
@@ -474,13 +529,13 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
if (mvm->scan_status == IWL_MVM_SCAN_NONE)
|
|
if (mvm->scan_status == IWL_MVM_SCAN_NONE)
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
|
|
|
|
if (iwl_mvm_is_radio_killed(mvm)) {
|
|
if (iwl_mvm_is_radio_killed(mvm)) {
|
|
ieee80211_scan_completed(mvm->hw, true);
|
|
ieee80211_scan_completed(mvm->hw, true);
|
|
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
|
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
|
|
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
|
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
|
|
iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
|
|
@@ -495,14 +550,11 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
|
|
goto out_remove_notif;
|
|
goto out_remove_notif;
|
|
}
|
|
}
|
|
|
|
|
|
- ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, 1 * HZ);
|
|
|
|
- if (ret)
|
|
|
|
- IWL_ERR(mvm, "%s - failed on timeout\n", __func__);
|
|
|
|
-
|
|
|
|
- return;
|
|
|
|
|
|
+ return iwl_wait_notification(&mvm->notif_wait, &wait_scan_abort, HZ);
|
|
|
|
|
|
out_remove_notif:
|
|
out_remove_notif:
|
|
iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
|
|
iwl_remove_notification(&mvm->notif_wait, &wait_scan_abort);
|
|
|
|
+ return ret;
|
|
}
|
|
}
|
|
|
|
|
|
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
|
|
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
|
|
@@ -519,10 +571,11 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
|
|
scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
|
|
scan_notif->status == IWL_SCAN_OFFLOAD_COMPLETED ?
|
|
"completed" : "aborted");
|
|
"completed" : "aborted");
|
|
|
|
|
|
- /* might already be something else again, don't reset if so */
|
|
|
|
- if (mvm->scan_status == IWL_MVM_SCAN_SCHED)
|
|
|
|
|
|
+ /* only call mac80211 completion if the stop was initiated by FW */
|
|
|
|
+ if (mvm->scan_status == IWL_MVM_SCAN_SCHED) {
|
|
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
|
mvm->scan_status = IWL_MVM_SCAN_NONE;
|
|
- ieee80211_sched_scan_stopped(mvm->hw);
|
|
|
|
|
|
+ ieee80211_sched_scan_stopped(mvm->hw);
|
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -553,14 +606,9 @@ static void iwl_scan_offload_build_tx_cmd(struct iwl_mvm *mvm,
|
|
static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
|
|
static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
|
|
struct ieee80211_vif *vif,
|
|
struct ieee80211_vif *vif,
|
|
struct cfg80211_sched_scan_request *req,
|
|
struct cfg80211_sched_scan_request *req,
|
|
- struct iwl_scan_offload_cmd *scan)
|
|
|
|
|
|
+ struct iwl_scan_offload_cmd *scan,
|
|
|
|
+ struct iwl_mvm_scan_params *params)
|
|
{
|
|
{
|
|
- bool is_assoc = false;
|
|
|
|
-
|
|
|
|
- ieee80211_iterate_active_interfaces_atomic(mvm->hw,
|
|
|
|
- IEEE80211_IFACE_ITER_NORMAL,
|
|
|
|
- iwl_mvm_vif_assoc_iterator,
|
|
|
|
- &is_assoc);
|
|
|
|
scan->channel_count =
|
|
scan->channel_count =
|
|
mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +
|
|
mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels +
|
|
mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
|
|
mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
|
|
@@ -568,13 +616,17 @@ static void iwl_build_scan_cmd(struct iwl_mvm *mvm,
|
|
scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
|
|
scan->quiet_plcp_th = cpu_to_le16(IWL_PLCP_QUIET_THRESH);
|
|
scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT;
|
|
scan->good_CRC_th = IWL_GOOD_CRC_TH_DEFAULT;
|
|
scan->rx_chain = iwl_mvm_scan_rx_chain(mvm);
|
|
scan->rx_chain = iwl_mvm_scan_rx_chain(mvm);
|
|
- scan->max_out_time = iwl_mvm_scan_max_out_time(vif, req->flags,
|
|
|
|
- is_assoc);
|
|
|
|
- scan->suspend_time = iwl_mvm_scan_suspend_time(vif, is_assoc);
|
|
|
|
|
|
+
|
|
|
|
+ scan->max_out_time = cpu_to_le32(params->max_out_time);
|
|
|
|
+ scan->suspend_time = cpu_to_le32(params->suspend_time);
|
|
|
|
+
|
|
scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
|
|
scan->filter_flags |= cpu_to_le32(MAC_FILTER_ACCEPT_GRP |
|
|
MAC_FILTER_IN_BEACON);
|
|
MAC_FILTER_IN_BEACON);
|
|
scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND);
|
|
scan->scan_type = cpu_to_le32(SCAN_TYPE_BACKGROUND);
|
|
scan->rep_count = cpu_to_le32(1);
|
|
scan->rep_count = cpu_to_le32(1);
|
|
|
|
+
|
|
|
|
+ if (params->passive_fragmented)
|
|
|
|
+ scan->scan_flags |= SCAN_FLAGS_FRAGMENTED_SCAN;
|
|
}
|
|
}
|
|
|
|
|
|
static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
|
|
static int iwl_ssid_exist(u8 *ssid, u8 ssid_len, struct iwl_ssid_ie *ssid_list)
|
|
@@ -639,12 +691,11 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
|
|
struct iwl_scan_channel_cfg *channels,
|
|
struct iwl_scan_channel_cfg *channels,
|
|
enum ieee80211_band band,
|
|
enum ieee80211_band band,
|
|
int *head, int *tail,
|
|
int *head, int *tail,
|
|
- u32 ssid_bitmap)
|
|
|
|
|
|
+ u32 ssid_bitmap,
|
|
|
|
+ struct iwl_mvm_scan_params *params)
|
|
{
|
|
{
|
|
struct ieee80211_supported_band *s_band;
|
|
struct ieee80211_supported_band *s_band;
|
|
- int n_probes = req->n_ssids;
|
|
|
|
int n_channels = req->n_channels;
|
|
int n_channels = req->n_channels;
|
|
- u8 active_dwell, passive_dwell;
|
|
|
|
int i, j, index = 0;
|
|
int i, j, index = 0;
|
|
bool partial;
|
|
bool partial;
|
|
|
|
|
|
@@ -654,8 +705,6 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
|
|
* to scan. So add requested channels to head of the list and others to
|
|
* to scan. So add requested channels to head of the list and others to
|
|
* the end.
|
|
* the end.
|
|
*/
|
|
*/
|
|
- active_dwell = iwl_mvm_get_active_dwell(band, n_probes);
|
|
|
|
- passive_dwell = iwl_mvm_get_passive_dwell(band);
|
|
|
|
s_band = &mvm->nvm_data->bands[band];
|
|
s_band = &mvm->nvm_data->bands[band];
|
|
|
|
|
|
for (i = 0; i < s_band->n_channels && *head <= *tail; i++) {
|
|
for (i = 0; i < s_band->n_channels && *head <= *tail; i++) {
|
|
@@ -679,8 +728,8 @@ static void iwl_build_channel_cfg(struct iwl_mvm *mvm,
|
|
channels->channel_number[index] =
|
|
channels->channel_number[index] =
|
|
cpu_to_le16(ieee80211_frequency_to_channel(
|
|
cpu_to_le16(ieee80211_frequency_to_channel(
|
|
s_band->channels[i].center_freq));
|
|
s_band->channels[i].center_freq));
|
|
- channels->dwell_time[index][0] = active_dwell;
|
|
|
|
- channels->dwell_time[index][1] = passive_dwell;
|
|
|
|
|
|
+ channels->dwell_time[index][0] = params->dwell[band].active;
|
|
|
|
+ channels->dwell_time[index][1] = params->dwell[band].passive;
|
|
|
|
|
|
channels->iter_count[index] = cpu_to_le16(1);
|
|
channels->iter_count[index] = cpu_to_le16(1);
|
|
channels->iter_interval[index] = 0;
|
|
channels->iter_interval[index] = 0;
|
|
@@ -709,7 +758,6 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
|
|
struct cfg80211_sched_scan_request *req,
|
|
struct cfg80211_sched_scan_request *req,
|
|
struct ieee80211_sched_scan_ies *ies)
|
|
struct ieee80211_sched_scan_ies *ies)
|
|
{
|
|
{
|
|
- int supported_bands = 0;
|
|
|
|
int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
|
|
int band_2ghz = mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels;
|
|
int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
|
|
int band_5ghz = mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels;
|
|
int head = 0;
|
|
int head = 0;
|
|
@@ -723,22 +771,19 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
|
|
.id = SCAN_OFFLOAD_CONFIG_CMD,
|
|
.id = SCAN_OFFLOAD_CONFIG_CMD,
|
|
.flags = CMD_SYNC,
|
|
.flags = CMD_SYNC,
|
|
};
|
|
};
|
|
|
|
+ struct iwl_mvm_scan_params params = {};
|
|
|
|
|
|
lockdep_assert_held(&mvm->mutex);
|
|
lockdep_assert_held(&mvm->mutex);
|
|
|
|
|
|
- if (band_2ghz)
|
|
|
|
- supported_bands++;
|
|
|
|
- if (band_5ghz)
|
|
|
|
- supported_bands++;
|
|
|
|
-
|
|
|
|
cmd_len = sizeof(struct iwl_scan_offload_cfg) +
|
|
cmd_len = sizeof(struct iwl_scan_offload_cfg) +
|
|
- supported_bands * SCAN_OFFLOAD_PROBE_REQ_SIZE;
|
|
|
|
|
|
+ 2 * SCAN_OFFLOAD_PROBE_REQ_SIZE;
|
|
|
|
|
|
scan_cfg = kzalloc(cmd_len, GFP_KERNEL);
|
|
scan_cfg = kzalloc(cmd_len, GFP_KERNEL);
|
|
if (!scan_cfg)
|
|
if (!scan_cfg)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
|
|
|
|
- iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd);
|
|
|
|
|
|
+ iwl_mvm_scan_calc_params(mvm, vif, req->n_ssids, ¶ms);
|
|
|
|
+ iwl_build_scan_cmd(mvm, vif, req, &scan_cfg->scan_cmd, ¶ms);
|
|
scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
|
|
scan_cfg->scan_cmd.len = cpu_to_le16(cmd_len);
|
|
|
|
|
|
iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap);
|
|
iwl_scan_offload_build_ssid(req, &scan_cfg->scan_cmd, &ssid_bitmap);
|
|
@@ -750,7 +795,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
|
|
scan_cfg->data);
|
|
scan_cfg->data);
|
|
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
|
|
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
|
|
IEEE80211_BAND_2GHZ, &head, &tail,
|
|
IEEE80211_BAND_2GHZ, &head, &tail,
|
|
- ssid_bitmap);
|
|
|
|
|
|
+ ssid_bitmap, ¶ms);
|
|
}
|
|
}
|
|
if (band_5ghz) {
|
|
if (band_5ghz) {
|
|
iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
|
|
iwl_scan_offload_build_tx_cmd(mvm, vif, ies,
|
|
@@ -760,7 +805,7 @@ int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
|
|
SCAN_OFFLOAD_PROBE_REQ_SIZE);
|
|
SCAN_OFFLOAD_PROBE_REQ_SIZE);
|
|
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
|
|
iwl_build_channel_cfg(mvm, req, &scan_cfg->channel_cfg,
|
|
IEEE80211_BAND_5GHZ, &head, &tail,
|
|
IEEE80211_BAND_5GHZ, &head, &tail,
|
|
- ssid_bitmap);
|
|
|
|
|
|
+ ssid_bitmap, ¶ms);
|
|
}
|
|
}
|
|
|
|
|
|
cmd.data[0] = scan_cfg;
|
|
cmd.data[0] = scan_cfg;
|
|
@@ -900,26 +945,49 @@ static int iwl_mvm_send_sched_scan_abort(struct iwl_mvm *mvm)
|
|
* microcode has notified us that a scan is completed.
|
|
* microcode has notified us that a scan is completed.
|
|
*/
|
|
*/
|
|
IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status);
|
|
IWL_DEBUG_SCAN(mvm, "SCAN OFFLOAD ABORT ret %d.\n", status);
|
|
- ret = -EIO;
|
|
|
|
|
|
+ ret = -ENOENT;
|
|
}
|
|
}
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-void iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm)
|
|
|
|
|
|
+int iwl_mvm_sched_scan_stop(struct iwl_mvm *mvm)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
|
|
+ struct iwl_notification_wait wait_scan_done;
|
|
|
|
+ static const u8 scan_done_notif[] = { SCAN_OFFLOAD_COMPLETE, };
|
|
|
|
|
|
lockdep_assert_held(&mvm->mutex);
|
|
lockdep_assert_held(&mvm->mutex);
|
|
|
|
|
|
if (mvm->scan_status != IWL_MVM_SCAN_SCHED) {
|
|
if (mvm->scan_status != IWL_MVM_SCAN_SCHED) {
|
|
IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n");
|
|
IWL_DEBUG_SCAN(mvm, "No offloaded scan to stop\n");
|
|
- return;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_done,
|
|
|
|
+ scan_done_notif,
|
|
|
|
+ ARRAY_SIZE(scan_done_notif),
|
|
|
|
+ NULL, NULL);
|
|
|
|
+
|
|
ret = iwl_mvm_send_sched_scan_abort(mvm);
|
|
ret = iwl_mvm_send_sched_scan_abort(mvm);
|
|
- if (ret)
|
|
|
|
|
|
+ if (ret) {
|
|
IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret);
|
|
IWL_DEBUG_SCAN(mvm, "Send stop offload scan failed %d\n", ret);
|
|
- else
|
|
|
|
- IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n");
|
|
|
|
|
|
+ iwl_remove_notification(&mvm->notif_wait, &wait_scan_done);
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ IWL_DEBUG_SCAN(mvm, "Successfully sent stop offload scan\n");
|
|
|
|
+
|
|
|
|
+ ret = iwl_wait_notification(&mvm->notif_wait, &wait_scan_done, 1 * HZ);
|
|
|
|
+ if (ret)
|
|
|
|
+ return ret;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Clear the scan status so the next scan requests will succeed. This
|
|
|
|
+ * also ensures the Rx handler doesn't do anything, as the scan was
|
|
|
|
+ * stopped from above.
|
|
|
|
+ */
|
|
|
|
+ mvm->scan_status = IWL_MVM_SCAN_NONE;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
}
|
|
}
|