mac80211: add support for per-chain signal strength reporting
authorFelix Fietkau <nbd@openwrt.org>
Mon, 22 Apr 2013 14:29:31 +0000 (16:29 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 16 May 2013 20:39:38 +0000 (22:39 +0200)
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
[fix unit documentation]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
include/net/mac80211.h
net/mac80211/cfg.c
net/mac80211/rx.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h

index 04c2d46..5953f25 100644 (file)
@@ -850,6 +850,10 @@ enum mac80211_rx_flags {
  * @signal: signal strength when receiving this frame, either in dBm, in dB or
  *     unspecified depending on the hardware capabilities flags
  *     @IEEE80211_HW_SIGNAL_*
+ * @chains: bitmask of receive chains for which separate signal strength
+ *     values were filled.
+ * @chain_signal: per-chain signal strength, in dBm (unlike @signal, doesn't
+ *     support dB or unspecified units)
  * @antenna: antenna used
  * @rate_idx: index of data rate into band's supported rates or MCS index if
  *     HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
@@ -881,6 +885,8 @@ struct ieee80211_rx_status {
        u8 band;
        u8 antenna;
        s8 signal;
+       u8 chains;
+       s8 chain_signal[IEEE80211_MAX_CHAINS];
        u8 ampdu_delimiter_crc;
        u8 vendor_radiotap_align;
        u8 vendor_radiotap_oui[3];
index 1a89c80..1f51bdf 100644 (file)
@@ -444,7 +444,7 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        struct ieee80211_local *local = sdata->local;
        struct timespec uptime;
        u64 packets = 0;
-       int ac;
+       int i, ac;
 
        sinfo->generation = sdata->local->sta_generation;
 
@@ -488,6 +488,17 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                        sinfo->signal = (s8)sta->last_signal;
                sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal);
        }
+       if (sta->chains) {
+               sinfo->filled |= STATION_INFO_CHAIN_SIGNAL |
+                                STATION_INFO_CHAIN_SIGNAL_AVG;
+
+               sinfo->chains = sta->chains;
+               for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) {
+                       sinfo->chain_signal[i] = sta->chain_signal_last[i];
+                       sinfo->chain_signal_avg[i] =
+                               (s8) -ewma_read(&sta->chain_signal_avg[i]);
+               }
+       }
 
        sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
        sta_set_rate_info_rx(sta, &sinfo->rxrate);
index c8447af..22e412b 100644 (file)
@@ -1372,6 +1372,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        struct sk_buff *skb = rx->skb;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       int i;
 
        if (!sta)
                return RX_CONTINUE;
@@ -1422,6 +1423,19 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                ewma_add(&sta->avg_signal, -status->signal);
        }
 
+       if (status->chains) {
+               sta->chains = status->chains;
+               for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) {
+                       int signal = status->chain_signal[i];
+
+                       if (!(status->chains & BIT(i)))
+                               continue;
+
+                       sta->chain_signal_last[i] = signal;
+                       ewma_add(&sta->chain_signal_avg[i], -signal);
+               }
+       }
+
        /*
         * Change STA power saving mode only at the end of a frame
         * exchange sequence.
index 11216bc..a04c567 100644 (file)
@@ -358,6 +358,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        do_posix_clock_monotonic_gettime(&uptime);
        sta->last_connected = uptime.tv_sec;
        ewma_init(&sta->avg_signal, 1024, 8);
+       for (i = 0; i < ARRAY_SIZE(sta->chain_signal_avg); i++)
+               ewma_init(&sta->chain_signal_avg[i], 1024, 8);
 
        if (sta_prepare_rate_control(local, sta, gfp)) {
                kfree(sta);
index adc3004..41c28b9 100644 (file)
@@ -344,6 +344,11 @@ struct sta_info {
        int last_signal;
        struct ewma avg_signal;
        int last_ack_signal;
+
+       u8 chains;
+       s8 chain_signal_last[IEEE80211_MAX_CHAINS];
+       struct ewma chain_signal_avg[IEEE80211_MAX_CHAINS];
+
        /* Plus 1 for non-QoS frames */
        __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];