Commit b68bd2e3 authored by Ilan Peer's avatar Ilan Peer Committed by Luca Coelho

iwlwifi: mvm: Add FTM initiator RTT smoothing logic

The overcome instabilities in the RTT results add smoothing logic
to the reported results. In short, the smoothing logic tracks the
RTT average of each responder for a period of time, and in case
a new RTT results is found to be a spur, the tracked RTT average
is reported instead of the current RTT measurement.

Smooth logic debug configuration using iwl-dbg-cfg.ini:

- MVM_FTM_INITIATOR_ENABLE_SMOOTH: Set to 1 to enable smoothing logic
 (default=0).
- MVM_FTM_INITIATOR_SMOOTH_ALPHA: A value between 0 - 100, defining
  the weight of the current RTT results vs. the RTT average tracked
  based on the previous results. A value of 100 means use only the
  current RTT results.
- MVM_FTM_INITIATOR_SMOOTH_AGE_SEC: The maximal time in seconds in which
  the RTT average tracked based on previous results is considered valid.
- MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT: if the current RTT is positive
  and below the RTT average by at least this value, report the average
  RTT instead of the current one. In units of picoseconds.
- MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT: if the current RTT is positive
  and above the RTT average by at least this value, report the average
  RTT instead of the current one. In units of picoseconds.
Signed-off-by: default avatarIlan Peer <ilan.peer@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20200930161256.48a9cec2081b.Iaec1e29f738232adfe9e2ea8e9eb9b6ff0323ae1@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 3830a01c
...@@ -159,5 +159,11 @@ ...@@ -159,5 +159,11 @@
#define IWL_MVM_PHY_FILTER_CHAIN_B 0 #define IWL_MVM_PHY_FILTER_CHAIN_B 0
#define IWL_MVM_PHY_FILTER_CHAIN_C 0 #define IWL_MVM_PHY_FILTER_CHAIN_C 0
#define IWL_MVM_PHY_FILTER_CHAIN_D 0 #define IWL_MVM_PHY_FILTER_CHAIN_D 0
#define IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH false
#define IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA 40
/* 20016 pSec is 6 meter RTT, meaning 3 meter range */
#define IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT 20016
#define IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT 20016
#define IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC 2
#endif /* __MVM_CONSTANTS_H */ #endif /* __MVM_CONSTANTS_H */
...@@ -76,6 +76,13 @@ struct iwl_mvm_loc_entry { ...@@ -76,6 +76,13 @@ struct iwl_mvm_loc_entry {
u8 buf[]; u8 buf[];
}; };
struct iwl_mvm_smooth_entry {
struct list_head list;
u8 addr[ETH_ALEN];
s64 rtt_avg;
u64 host_time;
};
static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm) static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm)
{ {
struct iwl_mvm_loc_entry *e, *t; struct iwl_mvm_loc_entry *e, *t;
...@@ -84,6 +91,7 @@ static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm) ...@@ -84,6 +91,7 @@ static void iwl_mvm_ftm_reset(struct iwl_mvm *mvm)
mvm->ftm_initiator.req_wdev = NULL; mvm->ftm_initiator.req_wdev = NULL;
memset(mvm->ftm_initiator.responses, 0, memset(mvm->ftm_initiator.responses, 0,
sizeof(mvm->ftm_initiator.responses)); sizeof(mvm->ftm_initiator.responses));
list_for_each_entry_safe(e, t, &mvm->ftm_initiator.loc_list, list) { list_for_each_entry_safe(e, t, &mvm->ftm_initiator.loc_list, list) {
list_del(&e->list); list_del(&e->list);
kfree(e); kfree(e);
...@@ -120,6 +128,30 @@ void iwl_mvm_ftm_restart(struct iwl_mvm *mvm) ...@@ -120,6 +128,30 @@ void iwl_mvm_ftm_restart(struct iwl_mvm *mvm)
iwl_mvm_ftm_reset(mvm); iwl_mvm_ftm_reset(mvm);
} }
void iwl_mvm_ftm_initiator_smooth_config(struct iwl_mvm *mvm)
{
INIT_LIST_HEAD(&mvm->ftm_initiator.smooth.resp);
IWL_DEBUG_INFO(mvm,
"enable=%u, alpha=%u, age_jiffies=%u, thresh=(%u:%u)\n",
IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH,
IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA,
IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC * HZ,
IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT,
IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT);
}
void iwl_mvm_ftm_initiator_smooth_stop(struct iwl_mvm *mvm)
{
struct iwl_mvm_smooth_entry *se, *st;
list_for_each_entry_safe(se, st, &mvm->ftm_initiator.smooth.resp,
list) {
list_del(&se->list);
kfree(se);
}
}
static int static int
iwl_ftm_range_request_status_to_err(enum iwl_tof_range_request_status s) iwl_ftm_range_request_status_to_err(enum iwl_tof_range_request_status s)
{ {
...@@ -728,6 +760,95 @@ static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id, ...@@ -728,6 +760,95 @@ static int iwl_mvm_ftm_range_resp_valid(struct iwl_mvm *mvm, u8 request_id,
return 0; return 0;
} }
static void iwl_mvm_ftm_rtt_smoothing(struct iwl_mvm *mvm,
struct cfg80211_pmsr_result *res)
{
struct iwl_mvm_smooth_entry *resp;
s64 rtt_avg, rtt = res->ftm.rtt_avg;
u32 undershoot, overshoot;
u8 alpha;
bool found;
if (!IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH)
return;
WARN_ON(rtt < 0);
if (res->status != NL80211_PMSR_STATUS_SUCCESS) {
IWL_DEBUG_INFO(mvm,
": %pM: ignore failed measurement. Status=%u\n",
res->addr, res->status);
return;
}
found = false;
list_for_each_entry(resp, &mvm->ftm_initiator.smooth.resp, list) {
if (!memcmp(res->addr, resp->addr, ETH_ALEN)) {
found = true;
break;
}
}
if (!found) {
resp = kzalloc(sizeof(*resp), GFP_KERNEL);
if (!resp)
return;
memcpy(resp->addr, res->addr, ETH_ALEN);
list_add_tail(&resp->list, &mvm->ftm_initiator.smooth.resp);
resp->rtt_avg = rtt;
IWL_DEBUG_INFO(mvm, "new: %pM: rtt_avg=%lld\n",
resp->addr, resp->rtt_avg);
goto update_time;
}
if (res->host_time - resp->host_time >
IWL_MVM_FTM_INITIATOR_SMOOTH_AGE_SEC * 1000000000) {
resp->rtt_avg = rtt;
IWL_DEBUG_INFO(mvm, "expired: %pM: rtt_avg=%lld\n",
resp->addr, resp->rtt_avg);
goto update_time;
}
/* Smooth the results based on the tracked RTT average */
undershoot = IWL_MVM_FTM_INITIATOR_SMOOTH_UNDERSHOOT;
overshoot = IWL_MVM_FTM_INITIATOR_SMOOTH_OVERSHOOT;
alpha = IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA;
rtt_avg = (alpha * rtt + (100 - alpha) * resp->rtt_avg) / 100;
IWL_DEBUG_INFO(mvm,
"%pM: prev rtt_avg=%lld, new rtt_avg=%lld, rtt=%lld\n",
resp->addr, resp->rtt_avg, rtt_avg, rtt);
/*
* update the responder's average RTT results regardless of
* the under/over shoot logic below
*/
resp->rtt_avg = rtt_avg;
/* smooth the results */
if (rtt_avg > rtt && (rtt_avg - rtt) > undershoot) {
res->ftm.rtt_avg = rtt_avg;
IWL_DEBUG_INFO(mvm,
"undershoot: val=%lld\n",
(rtt_avg - rtt));
} else if (rtt_avg < rtt && (rtt - rtt_avg) >
overshoot) {
res->ftm.rtt_avg = rtt_avg;
IWL_DEBUG_INFO(mvm,
"overshoot: val=%lld\n",
(rtt - rtt_avg));
}
update_time:
resp->host_time = res->host_time;
}
static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index, static void iwl_mvm_debug_range_resp(struct iwl_mvm *mvm, u8 index,
struct cfg80211_pmsr_result *res) struct cfg80211_pmsr_result *res)
{ {
...@@ -865,6 +986,8 @@ void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) ...@@ -865,6 +986,8 @@ void iwl_mvm_ftm_range_resp(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb)
iwl_mvm_ftm_get_lci_civic(mvm, &result); iwl_mvm_ftm_get_lci_civic(mvm, &result);
iwl_mvm_ftm_rtt_smoothing(mvm, &result);
cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev, cfg80211_pmsr_report(mvm->ftm_initiator.req_wdev,
mvm->ftm_initiator.req, mvm->ftm_initiator.req,
&result, GFP_KERNEL); &result, GFP_KERNEL);
......
...@@ -1512,6 +1512,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -1512,6 +1512,8 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
iwl_mvm_tas_init(mvm); iwl_mvm_tas_init(mvm);
iwl_mvm_leds_sync(mvm); iwl_mvm_leds_sync(mvm);
iwl_mvm_ftm_initiator_smooth_config(mvm);
IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); IWL_DEBUG_INFO(mvm, "RT uCode started.\n");
return 0; return 0;
error: error:
......
...@@ -1211,6 +1211,8 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm) ...@@ -1211,6 +1211,8 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)
{ {
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
iwl_mvm_ftm_initiator_smooth_stop(mvm);
/* firmware counters are obviously reset now, but we shouldn't /* firmware counters are obviously reset now, but we shouldn't
* partially track so also clear the fw_reset_accu counters. * partially track so also clear the fw_reset_accu counters.
*/ */
......
...@@ -1107,6 +1107,9 @@ struct iwl_mvm { ...@@ -1107,6 +1107,9 @@ struct iwl_mvm {
struct wireless_dev *req_wdev; struct wireless_dev *req_wdev;
struct list_head loc_list; struct list_head loc_list;
int responses[IWL_MVM_TOF_MAX_APS]; int responses[IWL_MVM_TOF_MAX_APS];
struct {
struct list_head resp;
} smooth;
} ftm_initiator; } ftm_initiator;
struct list_head resp_pasn_list; struct list_head resp_pasn_list;
...@@ -2011,6 +2014,8 @@ void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm, ...@@ -2011,6 +2014,8 @@ void iwl_mvm_ftm_lc_notif(struct iwl_mvm *mvm,
int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct cfg80211_pmsr_request *request); struct cfg80211_pmsr_request *request);
void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req); void iwl_mvm_ftm_abort(struct iwl_mvm *mvm, struct cfg80211_pmsr_request *req);
void iwl_mvm_ftm_initiator_smooth_config(struct iwl_mvm *mvm);
void iwl_mvm_ftm_initiator_smooth_stop(struct iwl_mvm *mvm);
/* TDLS */ /* TDLS */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment