Skip to content
This repository has been archived by the owner on Dec 14, 2022. It is now read-only.

Commit

Permalink
iwlwifi: mvm: Add support for two scheduled scan plans
Browse files Browse the repository at this point in the history
Add support for two scan plans for scheduled scan. The first plan
will run for a limited number of iterations, then the second plan
will run infinitely.

Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Emmanuel Grumbach <[email protected]>
  • Loading branch information
AviStern authored and egrumbach committed Oct 25, 2015
1 parent 5888a40 commit cd55cce
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 42 deletions.
5 changes: 3 additions & 2 deletions drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ struct iwl_ssid_ie {

#define IWL_FULL_SCAN_MULTIPLIER 5
#define IWL_FAST_SCHED_SCAN_ITERATIONS 3
#define IWL_MAX_SCHED_SCAN_PLANS 2

enum scan_framework_client {
SCAN_CLIENT_SCHED_SCAN = BIT(0),
Expand Down Expand Up @@ -359,7 +360,7 @@ struct iwl_scan_req_lmac {
/* SCAN_REQ_PERIODIC_PARAMS_API_S */
__le32 iter_num;
__le32 delay;
struct iwl_scan_schedule_lmac schedule[2];
struct iwl_scan_schedule_lmac schedule[IWL_MAX_SCHED_SCAN_PLANS];
struct iwl_scan_channel_opt channel_opt[2];
u8 data[];
} __packed;
Expand Down Expand Up @@ -582,7 +583,7 @@ struct iwl_scan_umac_schedule {
*/
struct iwl_scan_req_umac_tail {
/* SCAN_PERIODIC_PARAMS_API_S_VER_1 */
struct iwl_scan_umac_schedule schedule[2];
struct iwl_scan_umac_schedule schedule[IWL_MAX_SCHED_SCAN_PLANS];
__le16 delay;
__le16 reserved;
/* SCAN_PROBE_PARAMS_API_S_VER_1 */
Expand Down
8 changes: 8 additions & 0 deletions drivers/net/wireless/iwlwifi/mvm/mac80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,14 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
/* we create the 802.11 header and zero length SSID IE. */
hw->wiphy->max_sched_scan_ie_len =
SCAN_OFFLOAD_PROBE_REQ_SIZE - 24 - 2;
hw->wiphy->max_sched_scan_plans = IWL_MAX_SCHED_SCAN_PLANS;
hw->wiphy->max_sched_scan_plan_interval = U16_MAX;

/*
* the firmware uses u8 for num of iterations, but 0xff is saved for
* infinite loop, so the maximum number of iterations is actually 254.
*/
hw->wiphy->max_sched_scan_plan_iterations = 254;

hw->wiphy->features |= NL80211_FEATURE_P2P_GO_CTWIN |
NL80211_FEATURE_LOW_PRIORITY_SCAN |
Expand Down
116 changes: 76 additions & 40 deletions drivers/net/wireless/iwlwifi/mvm/scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ struct iwl_mvm_scan_params {
int n_ssids;
struct cfg80211_ssid *ssids;
struct ieee80211_channel **channels;
u16 interval; /* interval between scans (in secs) */
u32 flags;
u8 *mac_addr;
u8 *mac_addr_mask;
Expand All @@ -140,7 +139,8 @@ struct iwl_mvm_scan_params {
int n_match_sets;
struct iwl_scan_probe_req preq;
struct cfg80211_match_set *match_sets;
u8 iterations[2];
int n_scan_plans;
struct cfg80211_sched_scan_plan *scan_plans;
};

static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
Expand Down Expand Up @@ -737,8 +737,7 @@ static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids,
}

static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
int n_iterations)
struct ieee80211_vif *vif)
{
const struct iwl_ucode_capabilities *capa = &mvm->fw->ucode_capa;

Expand All @@ -753,11 +752,6 @@ static inline bool iwl_mvm_scan_use_ebs(struct iwl_mvm *mvm,
vif->type != NL80211_IFTYPE_P2P_DEVICE);
}

static int iwl_mvm_scan_total_iterations(struct iwl_mvm_scan_params *params)
{
return params->iterations[0] + params->iterations[1];
}

static int iwl_mvm_scan_lmac_flags(struct iwl_mvm *mvm,
struct iwl_mvm_scan_params *params)
{
Expand Down Expand Up @@ -796,12 +790,15 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
(void *)(cmd->data + sizeof(struct iwl_scan_channel_cfg_lmac) *
mvm->fw->ucode_capa.n_scan_channels);
u32 ssid_bitmap = 0;
int n_iterations = iwl_mvm_scan_total_iterations(params);
int i;

lockdep_assert_held(&mvm->mutex);

memset(cmd, 0, ksize(cmd));

if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS))
return -EINVAL;

iwl_mvm_scan_lmac_dwell(mvm, cmd, params);

cmd->rx_chain_select = iwl_mvm_scan_rx_chain(mvm);
Expand All @@ -821,14 +818,33 @@ static int iwl_mvm_scan_lmac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
/* this API uses bits 1-20 instead of 0-19 */
ssid_bitmap <<= 1;

cmd->schedule[0].delay = cpu_to_le16(params->interval);
cmd->schedule[0].iterations = params->iterations[0];
cmd->schedule[0].full_scan_mul = 1;
cmd->schedule[1].delay = cpu_to_le16(params->interval);
cmd->schedule[1].iterations = params->iterations[1];
cmd->schedule[1].full_scan_mul = 1;
for (i = 0; i < params->n_scan_plans; i++) {
struct wiphy *wiphy = mvm->hw->wiphy;
struct cfg80211_sched_scan_plan *scan_plan =
&params->scan_plans[i];

if (WARN_ON(scan_plan->iterations >
wiphy->max_sched_scan_plan_iterations ||
scan_plan->interval >
wiphy->max_sched_scan_plan_interval))
return -EINVAL;

cmd->schedule[i].delay =
cpu_to_le16(scan_plan->interval);
cmd->schedule[i].iterations = scan_plan->iterations;
cmd->schedule[i].full_scan_mul = 1;
}

/*
* If the number of iterations of the last scan plan is set to
* zero, it should run infinitely. However, this is not always the case.
* For example, when regular scan is requested the driver sets one scan
* plan with one iteration.
*/
if (!cmd->schedule[i - 1].iterations)
cmd->schedule[i - 1].iterations = 0xff;

if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations)) {
if (iwl_mvm_scan_use_ebs(mvm, vif)) {
cmd->channel_opt[0].flags =
cpu_to_le16(IWL_SCAN_CHANNEL_FLAG_EBS |
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
Expand Down Expand Up @@ -968,6 +984,12 @@ static int iwl_mvm_scan_uid_by_status(struct iwl_mvm *mvm, int status)
return -ENOENT;
}

static inline bool iwl_mvm_is_regular_scan(struct iwl_mvm_scan_params *params)
{
return params->n_scan_plans == 1 &&
params->scan_plans[0].iterations == 1;
}

static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
struct iwl_scan_req_umac *cmd,
struct iwl_mvm_scan_params *params)
Expand All @@ -980,7 +1002,7 @@ static void iwl_mvm_scan_umac_dwell(struct iwl_mvm *mvm,
cmd->scan_priority =
iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);

if (iwl_mvm_scan_total_iterations(params) == 1)
if (iwl_mvm_is_regular_scan(params))
cmd->ooc_priority =
iwl_mvm_scan_priority(mvm, IWL_SCAN_PRIORITY_EXT_6);
else
Expand Down Expand Up @@ -1027,7 +1049,7 @@ static u32 iwl_mvm_scan_umac_flags(struct iwl_mvm *mvm,
else
flags |= IWL_UMAC_SCAN_GEN_FLAGS_MATCH;

if (iwl_mvm_scan_total_iterations(params) > 1)
if (!iwl_mvm_is_regular_scan(params))
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PERIODIC;

#ifdef CONFIG_IWLWIFI_DEBUGFS
Expand All @@ -1045,12 +1067,14 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_scan_req_umac_tail *sec_part = (void *)&cmd->data +
sizeof(struct iwl_scan_channel_cfg_umac) *
mvm->fw->ucode_capa.n_scan_channels;
int uid;
int uid, i;
u32 ssid_bitmap = 0;
int n_iterations = iwl_mvm_scan_total_iterations(params);

lockdep_assert_held(&mvm->mutex);

if (WARN_ON(params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS))
return -EINVAL;

uid = iwl_mvm_scan_uid_by_status(mvm, 0);
if (uid < 0)
return uid;
Expand All @@ -1067,7 +1091,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (type == IWL_MVM_SCAN_SCHED)
cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);

if (iwl_mvm_scan_use_ebs(mvm, vif, n_iterations))
if (iwl_mvm_scan_use_ebs(mvm, vif))
cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
Expand All @@ -1079,12 +1103,30 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_umac_scan_cfg_channels(mvm, params->channels,
params->n_channels, ssid_bitmap, cmd);

/* With UMAC we use only one schedule for now, so use the sum
* of the iterations (with a a maximum of 255).
for (i = 0; i < params->n_scan_plans; i++) {
struct wiphy *wiphy = mvm->hw->wiphy;
struct cfg80211_sched_scan_plan *scan_plan =
&params->scan_plans[i];

if (WARN_ON(scan_plan->iterations >
wiphy->max_sched_scan_plan_iterations ||
scan_plan->interval >
wiphy->max_sched_scan_plan_interval))
return -EINVAL;

sec_part->schedule[i].iter_count = scan_plan->iterations;
sec_part->schedule[i].interval =
cpu_to_le16(scan_plan->interval);
}

/*
* If the number of iterations of the last scan plan is set to
* zero, it should run infinitely. However, this is not always the case.
* For example, when regular scan is requested the driver sets one scan
* plan with one iteration.
*/
sec_part->schedule[0].iter_count =
(n_iterations > 255) ? 255 : n_iterations;
sec_part->schedule[0].interval = cpu_to_le16(params->interval);
if (!sec_part->schedule[i - 1].iter_count)
sec_part->schedule[i - 1].iter_count = 0xff;

sec_part->delay = cpu_to_le16(params->delay);
sec_part->preq = params->preq;
Expand Down Expand Up @@ -1150,6 +1192,7 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
};
struct iwl_mvm_scan_params params = {};
int ret;
struct cfg80211_sched_scan_plan scan_plan = { .iterations = 1 };

lockdep_assert_held(&mvm->mutex);

Expand All @@ -1175,7 +1218,6 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
params.flags = req->flags;
params.n_channels = req->n_channels;
params.delay = 0;
params.interval = 0;
params.ssids = req->ssids;
params.channels = req->channels;
params.mac_addr = req->mac_addr;
Expand All @@ -1185,8 +1227,8 @@ int iwl_mvm_reg_scan_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
params.n_match_sets = 0;
params.match_sets = NULL;

params.iterations[0] = 1;
params.iterations[1] = 0;
params.scan_plans = &scan_plan;
params.n_scan_plans = 1;

params.type = iwl_mvm_get_scan_type(mvm, vif, &params);

Expand Down Expand Up @@ -1265,20 +1307,14 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
params.pass_all = iwl_mvm_scan_pass_all(mvm, req);
params.n_match_sets = req->n_match_sets;
params.match_sets = req->match_sets;
if (!req->n_scan_plans)
return -EINVAL;

params.iterations[0] = 0;
params.iterations[1] = 0xff;
params.n_scan_plans = req->n_scan_plans;
params.scan_plans = req->scan_plans;

params.type = iwl_mvm_get_scan_type(mvm, vif, &params);

if (req->scan_plans[0].interval > U16_MAX) {
IWL_DEBUG_SCAN(mvm,
"interval value is > 16-bits, set to max possible\n");
params.interval = U16_MAX;
} else {
params.interval = req->scan_plans[0].interval;
}

/* In theory, LMAC scans can handle a 32-bit delay, but since
* waiting for over 18 hours to start the scan is a bit silly
* and to keep it aligned with UMAC scans (which only support
Expand Down

0 comments on commit cd55cce

Please sign in to comment.