@@ -4869,9 +4869,32 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- if (mvmsta->avg_energy) {
- sinfo->signal_avg = -(s8)mvmsta->avg_energy;
+ if (iwl_mvm_has_new_rx_api(mvm)) { /* rxmq logic */
+ /* Grab chain signal avg, mac80211 cannot do it because
+ * this driver uses RSS. Grab signal_avg here too because firmware
+ * appears go not do DB summing and/or has other bugs. --Ben
+ */
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
+ sinfo->signal_avg = -ewma_signal_read(&mvmsta->rx_avg_signal);
+
+ if (!mvmvif->bf_data.bf_enabled) {
+ /* The firmware reliably reports different signal (2db weaker in my case)
+ * than if I calculate it from the rx-status. So, fill that here.
+ * Beacons are only received if you turn off beacon filtering, however.
+ */
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
+ sinfo->rx_beacon_signal_avg = -ewma_signal_read(&mvmsta->rx_avg_beacon_signal);
+ }
+
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL_AVG);
+ sinfo->chain_signal_avg[0] = -ewma_signal_read(&mvmsta->rx_avg_chain_signal[0]);
+ sinfo->chain_signal_avg[1] = -ewma_signal_read(&mvmsta->rx_avg_chain_signal[1]);
+ }
+ else {
+ if (mvmsta->avg_energy) {
+ sinfo->signal_avg = -(s8)mvmsta->avg_energy;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG);
+ }
}
if (iwl_mvm_has_tlc_offload(mvm)) {
@@ -4899,10 +4922,13 @@ static void iwl_mvm_mac_sta_statistics(struct ieee80211_hw *hw,
sinfo->rx_beacon = mvmvif->beacon_stats.num_beacons +
mvmvif->beacon_stats.accu_num_beacons;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_RX);
- if (mvmvif->beacon_stats.avg_signal) {
- /* firmware only reports a value after RXing a few beacons */
- sinfo->rx_beacon_signal_avg = mvmvif->beacon_stats.avg_signal;
- sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
+
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG))) {
+ if (mvmvif->beacon_stats.avg_signal) {
+ /* firmware only reports a value after RXing a few beacons */
+ sinfo->rx_beacon_signal_avg = mvmvif->beacon_stats.avg_signal;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_BEACON_SIGNAL_AVG);
+ }
}
unlock:
mutex_unlock(&mvm->mutex);
@@ -2150,4 +2150,38 @@ enum iwl_location_cipher iwl_mvm_cipher_to_location_cipher(u32 cipher)
return IWL_LOCATION_CIPHER_INVALID;
}
}
+
+static inline int iwl_mvm_sum_sigs_2(int a, int b)
+{
+ int diff;
+
+ /* S8_MIN means value-is-not-set */
+ if (b == S8_MIN)
+ return a;
+ if (a == S8_MIN)
+ return b;
+
+ if (a >= b) {
+ /* a is largest value, add to it. */
+ diff = a - b;
+ if (diff == 0)
+ return a + 3;
+ else if (diff <= 2)
+ return a + 2;
+ else if (diff <= 6)
+ return a + 1;
+ return a;
+ } else {
+ /* b is largest value, add to it. */
+ diff = b - a;
+ if (diff == 0)
+ return b + 3;
+ else if (diff <= 2)
+ return b + 2;
+ else if (diff <= 6)
+ return b + 1;
+ return b;
+ }
+}
+
#endif /* __IWL_MVM_H__ */
@@ -114,7 +114,9 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
energy_b = (val & IWL_RX_INFO_ENERGY_ANT_B_MSK) >>
IWL_RX_INFO_ENERGY_ANT_B_POS;
energy_b = energy_b ? -energy_b : S8_MIN;
- max_energy = max(energy_a, energy_b);
+
+ /* use DB summing to get better RSSI reporting */
+ max_energy = iwl_mvm_sum_sigs_2(energy_a, energy_b);
IWL_DEBUG_STATS(mvm, "energy In A %d B %d , and max %d\n",
energy_a, energy_b, max_energy);
@@ -278,14 +278,26 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
struct ieee80211_rx_status *rx_status,
u32 rate_n_flags, int energy_a,
- int energy_b)
+ int energy_b, struct ieee80211_sta *sta,
+ bool is_beacon, bool my_beacon)
{
int max_energy;
u32 rate_flags = rate_n_flags;
+ struct iwl_mvm_sta *mvmsta = NULL;
+
+ if (sta && !(is_beacon && !my_beacon)) {
+ mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ if (energy_a)
+ ewma_signal_add(&mvmsta->rx_avg_chain_signal[0], energy_a);
+ if (energy_b)
+ ewma_signal_add(&mvmsta->rx_avg_chain_signal[1], energy_b);
+ }
energy_a = energy_a ? -energy_a : S8_MIN;
energy_b = energy_b ? -energy_b : S8_MIN;
- max_energy = max(energy_a, energy_b);
+
+ /* use DB summing to get better RSSI reporting */
+ max_energy = iwl_mvm_sum_sigs_2(energy_a, energy_b);
IWL_DEBUG_STATS(mvm, "energy In A %d B %d, and max %d\n",
energy_a, energy_b, max_energy);
@@ -295,6 +307,15 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
(rate_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS;
rx_status->chain_signal[0] = energy_a;
rx_status->chain_signal[1] = energy_b;
+
+ if (mvmsta) {
+ if (is_beacon) {
+ if (my_beacon)
+ ewma_signal_add(&mvmsta->rx_avg_beacon_signal, -max_energy);
+ } else {
+ ewma_signal_add(&mvmsta->rx_avg_signal, -max_energy);
+ }
+ }
}
static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta,
@@ -1685,6 +1706,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
};
u32 format;
bool is_sgi;
+ bool is_beacon;
+ bool my_beacon = false;
if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)))
return;
@@ -1828,8 +1851,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
}
rx_status->freq = ieee80211_channel_to_frequency(channel,
rx_status->band);
- iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a,
- energy_b);
/* update aggregation data for monitor sake on default queue */
if (!queue && (phy_info & IWL_RX_MPDU_PHY_AMPDU)) {
@@ -1878,6 +1899,16 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
goto out;
}
+ is_beacon = ieee80211_is_beacon(hdr->frame_control);
+ if (is_beacon && sta) {
+ /* see if it is beacon destined for us */
+ if (memcmp(sta->addr, hdr->addr2, ETH_ALEN) == 0)
+ my_beacon = true;
+ }
+
+ iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a,
+ energy_b, sta, is_beacon, my_beacon);
+
if (sta) {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct ieee80211_vif *tx_blocked_vif =
@@ -2138,7 +2169,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi,
rx_status->freq = ieee80211_channel_to_frequency(channel,
rx_status->band);
iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, energy_a,
- energy_b);
+ energy_b, sta, false, false);
rcu_read_lock();
@@ -1577,6 +1577,11 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
spin_lock_init(&mvm_sta->lock);
+ ewma_signal_init(&mvm_sta->rx_avg_chain_signal[0]);
+ ewma_signal_init(&mvm_sta->rx_avg_chain_signal[1]);
+ ewma_signal_init(&mvm_sta->rx_avg_signal);
+ ewma_signal_init(&mvm_sta->rx_avg_beacon_signal);
+
/* if this is a HW restart re-alloc existing queues */
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
struct iwl_mvm_int_sta tmp_sta = {
@@ -10,6 +10,7 @@
#include <linux/spinlock.h>
#include <net/mac80211.h>
#include <linux/wait.h>
+#include <linux/average.h>
#include "iwl-trans.h" /* for IWL_MAX_TID_COUNT */
#include "fw-api.h" /* IWL_MVM_STATION_COUNT_MAX */
@@ -18,6 +19,9 @@
struct iwl_mvm;
struct iwl_mvm_vif;
+/* This makes us a 'struct ewma_signal {' object. */
+DECLARE_EWMA(signal, 10, 8);
+
/**
* DOC: DQA - Dynamic Queue Allocation -introduction
*
@@ -415,6 +419,9 @@ struct iwl_mvm_sta {
u8 sleep_tx_count;
u8 avg_energy;
u8 tx_ant;
+ struct ewma_signal rx_avg_chain_signal[2];
+ struct ewma_signal rx_avg_signal;
+ struct ewma_signal rx_avg_beacon_signal;
};
u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data);