aboutsummaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch')
-rw-r--r--package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch384
1 files changed, 384 insertions, 0 deletions
diff --git a/package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch b/package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch
new file mode 100644
index 000000000..8b26a50b3
--- /dev/null
+++ b/package/mac80211/patches/522-ath9k_per_chain_signal_strength.patch
@@ -0,0 +1,384 @@
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -729,6 +729,9 @@ 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, same format as @signal
+ * @antenna: antenna used
+ * @rate_idx: index of data rate into band's supported rates or MCS index if
+ * HT rates are use (RX_FLAG_HT)
+@@ -749,6 +752,8 @@ struct ieee80211_rx_status {
+ u8 band;
+ u8 antenna;
+ s8 signal;
++ u8 chains;
++ s8 chain_signal[4];
+ u8 ampdu_delimiter_crc;
+ };
+
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -325,6 +325,11 @@ struct sta_info {
+ unsigned long rx_dropped;
+ int last_signal;
+ struct ewma avg_signal;
++
++ u8 chains;
++ s8 chain_signal_last[4];
++ struct ewma chain_signal_avg[4];
++
+ /* Plus 1 for non-QoS frames */
+ __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1];
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -1271,6 +1271,7 @@ ieee80211_rx_h_sta_process(struct ieee80
+ 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;
+@@ -1315,6 +1316,19 @@ ieee80211_rx_h_sta_process(struct ieee80
+ ewma_add(&sta->avg_signal, -status->signal);
+ }
+
++ if (status->chains) {
++ sta->chains = status->chains;
++ for (i = 0; i < 4; 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.
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -254,6 +254,8 @@ struct sta_info *sta_info_alloc(struct i
+ 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);
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -549,6 +549,8 @@ struct station_parameters {
+ * @STATION_INFO_STA_FLAGS: @sta_flags filled
+ * @STATION_INFO_BEACON_LOSS_COUNT: @beacon_loss_count filled
+ * @STATION_INFO_T_OFFSET: @t_offset filled
++ * @STATION_INFO_CHAIN_SIGNAL: @chain_signal filled
++ * @STATION_INFO_CHAIN_SIGNAL_AVG: @chain_signal_avg filled
+ */
+ enum station_info_flags {
+ STATION_INFO_INACTIVE_TIME = 1<<0,
+@@ -572,6 +574,8 @@ enum station_info_flags {
+ STATION_INFO_STA_FLAGS = 1<<18,
+ STATION_INFO_BEACON_LOSS_COUNT = 1<<19,
+ STATION_INFO_T_OFFSET = 1<<20,
++ STATION_INFO_CHAIN_SIGNAL = 1<<21,
++ STATION_INFO_CHAIN_SIGNAL_AVG = 1<<22,
+ };
+
+ /**
+@@ -655,6 +659,9 @@ struct sta_bss_parameters {
+ * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
+ * @signal_avg: Average signal strength, type depends on the wiphy's signal_type.
+ * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_.
++ * @chains: bitmask for filled values in @chain_signal, @chain_signal_avg
++ * @chain_signal: per-chain signal strength of last received packet in dBm
++ * @chain_signal_avg: per-chain signal strength average in dBm
+ * @txrate: current unicast bitrate from this station
+ * @rxrate: current unicast bitrate to this station
+ * @rx_packets: packets received from this station
+@@ -687,6 +694,11 @@ struct station_info {
+ u8 plink_state;
+ s8 signal;
+ s8 signal_avg;
++
++ u8 chains;
++ s8 chain_signal[4];
++ s8 chain_signal_avg[4];
++
+ struct rate_info txrate;
+ struct rate_info rxrate;
+ u32 rx_packets;
+--- a/drivers/net/wireless/ath/ath9k/mac.h
++++ b/drivers/net/wireless/ath/ath9k/mac.h
+@@ -133,12 +133,8 @@ struct ath_rx_status {
+ u8 rs_rate;
+ u8 rs_antenna;
+ u8 rs_more;
+- int8_t rs_rssi_ctl0;
+- int8_t rs_rssi_ctl1;
+- int8_t rs_rssi_ctl2;
+- int8_t rs_rssi_ext0;
+- int8_t rs_rssi_ext1;
+- int8_t rs_rssi_ext2;
++ int8_t rs_rssi_ctl[3];
++ int8_t rs_rssi_ext[3];
+ u8 rs_isaggr;
+ u8 rs_moreaggr;
+ u8 rs_num_delims;
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -955,6 +955,7 @@ static int ath9k_rx_skb_preprocess(struc
+ bool *decrypt_error)
+ {
+ struct ath_hw *ah = common->ah;
++ int i, j;
+
+ /*
+ * everything but the rate is checked here, the rate check is done
+@@ -980,6 +981,20 @@ static int ath9k_rx_skb_preprocess(struc
+ if (rx_stats->rs_moreaggr)
+ rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+
++ for (i = 0, j = 0; i < ARRAY_SIZE(rx_stats->rs_rssi_ctl); i++) {
++ s8 rssi;
++
++ if (!(ah->rxchainmask & BIT(i)))
++ continue;
++
++ rssi = rx_stats->rs_rssi_ctl[i];
++ if (rssi != ATH9K_RSSI_BAD) {
++ rx_status->chains |= BIT(j);
++ rx_status->chain_signal[j] = ah->noise + rssi;
++ }
++ j++;
++ }
++
+ return 0;
+ }
+
+--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
++++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+@@ -458,12 +458,12 @@ int ath9k_hw_process_rxdesc_edma(struct
+
+ /* XXX: Keycache */
+ rxs->rs_rssi = MS(rxsp->status5, AR_RxRSSICombined);
+- rxs->rs_rssi_ctl0 = MS(rxsp->status1, AR_RxRSSIAnt00);
+- rxs->rs_rssi_ctl1 = MS(rxsp->status1, AR_RxRSSIAnt01);
+- rxs->rs_rssi_ctl2 = MS(rxsp->status1, AR_RxRSSIAnt02);
+- rxs->rs_rssi_ext0 = MS(rxsp->status5, AR_RxRSSIAnt10);
+- rxs->rs_rssi_ext1 = MS(rxsp->status5, AR_RxRSSIAnt11);
+- rxs->rs_rssi_ext2 = MS(rxsp->status5, AR_RxRSSIAnt12);
++ rxs->rs_rssi_ctl[0] = MS(rxsp->status1, AR_RxRSSIAnt00);
++ rxs->rs_rssi_ctl[1] = MS(rxsp->status1, AR_RxRSSIAnt01);
++ rxs->rs_rssi_ctl[2] = MS(rxsp->status1, AR_RxRSSIAnt02);
++ rxs->rs_rssi_ext[0] = MS(rxsp->status5, AR_RxRSSIAnt10);
++ rxs->rs_rssi_ext[1] = MS(rxsp->status5, AR_RxRSSIAnt11);
++ rxs->rs_rssi_ext[2] = MS(rxsp->status5, AR_RxRSSIAnt12);
+
+ if (rxsp->status11 & AR_RxKeyIdxValid)
+ rxs->rs_keyix = MS(rxsp->status11, AR_KeyIdx);
+--- a/drivers/net/wireless/ath/ath9k/mac.c
++++ b/drivers/net/wireless/ath/ath9k/mac.c
+@@ -553,25 +553,25 @@ int ath9k_hw_rxprocdesc(struct ath_hw *a
+
+ if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) {
+ rs->rs_rssi = ATH9K_RSSI_BAD;
+- rs->rs_rssi_ctl0 = ATH9K_RSSI_BAD;
+- rs->rs_rssi_ctl1 = ATH9K_RSSI_BAD;
+- rs->rs_rssi_ctl2 = ATH9K_RSSI_BAD;
+- rs->rs_rssi_ext0 = ATH9K_RSSI_BAD;
+- rs->rs_rssi_ext1 = ATH9K_RSSI_BAD;
+- rs->rs_rssi_ext2 = ATH9K_RSSI_BAD;
++ rs->rs_rssi_ctl[0] = ATH9K_RSSI_BAD;
++ rs->rs_rssi_ctl[1] = ATH9K_RSSI_BAD;
++ rs->rs_rssi_ctl[2] = ATH9K_RSSI_BAD;
++ rs->rs_rssi_ext[0] = ATH9K_RSSI_BAD;
++ rs->rs_rssi_ext[1] = ATH9K_RSSI_BAD;
++ rs->rs_rssi_ext[2] = ATH9K_RSSI_BAD;
+ } else {
+ rs->rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined);
+- rs->rs_rssi_ctl0 = MS(ads.ds_rxstatus0,
++ rs->rs_rssi_ctl[0] = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt00);
+- rs->rs_rssi_ctl1 = MS(ads.ds_rxstatus0,
++ rs->rs_rssi_ctl[1] = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt01);
+- rs->rs_rssi_ctl2 = MS(ads.ds_rxstatus0,
++ rs->rs_rssi_ctl[2] = MS(ads.ds_rxstatus0,
+ AR_RxRSSIAnt02);
+- rs->rs_rssi_ext0 = MS(ads.ds_rxstatus4,
++ rs->rs_rssi_ext[0] = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt10);
+- rs->rs_rssi_ext1 = MS(ads.ds_rxstatus4,
++ rs->rs_rssi_ext[1] = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt11);
+- rs->rs_rssi_ext2 = MS(ads.ds_rxstatus4,
++ rs->rs_rssi_ext[2] = MS(ads.ds_rxstatus4,
+ AR_RxRSSIAnt12);
+ }
+ if (ads.ds_rxstatus8 & AR_RxKeyIdxValid)
+--- a/drivers/net/wireless/ath/ath9k/debug.c
++++ b/drivers/net/wireless/ath/ath9k/debug.c
+@@ -997,12 +997,12 @@ void ath_debug_stat_rx(struct ath_softc
+ #ifdef CONFIG_ATH9K_MAC_DEBUG
+ spin_lock(&sc->debug.samp_lock);
+ RX_SAMP_DBG(jiffies) = jiffies;
+- RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl0;
+- RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl1;
+- RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl2;
+- RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext0;
+- RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext1;
+- RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext2;
++ RX_SAMP_DBG(rssi_ctl0) = rs->rs_rssi_ctl[0];
++ RX_SAMP_DBG(rssi_ctl1) = rs->rs_rssi_ctl[1];
++ RX_SAMP_DBG(rssi_ctl2) = rs->rs_rssi_ctl[2];
++ RX_SAMP_DBG(rssi_ext0) = rs->rs_rssi_ext[0];
++ RX_SAMP_DBG(rssi_ext1) = rs->rs_rssi_ext[1];
++ RX_SAMP_DBG(rssi_ext2) = rs->rs_rssi_ext[2];
+ RX_SAMP_DBG(antenna) = rs->rs_antenna;
+ RX_SAMP_DBG(rssi) = rs->rs_rssi;
+ RX_SAMP_DBG(rate) = rs->rs_rate;
+--- a/include/linux/nl80211.h
++++ b/include/linux/nl80211.h
+@@ -1760,6 +1760,8 @@ enum nl80211_sta_bss_param {
+ * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
+ * @NL80211_STA_INFO_BEACON_LOSS: count of times beacon loss was detected (u32)
+ * @NL80211_STA_INFO_T_OFFSET: timing offset with respect to this STA (s64)
++ * @NL80211_STA_INFO_CHAIN_SIGNAL: per-chain signal strength of last PPDU
++ * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ */
+@@ -1784,6 +1786,8 @@ enum nl80211_sta_info {
+ NL80211_STA_INFO_STA_FLAGS,
+ NL80211_STA_INFO_BEACON_LOSS,
+ NL80211_STA_INFO_T_OFFSET,
++ NL80211_STA_INFO_CHAIN_SIGNAL,
++ NL80211_STA_INFO_CHAIN_SIGNAL_AVG,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -2769,6 +2769,32 @@ nla_put_failure:
+ return false;
+ }
+
++static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
++ int id)
++{
++ void *attr;
++ int i = 0;
++
++ if (!mask)
++ return true;
++
++ attr = nla_nest_start(msg, id);
++ if (!attr)
++ return false;
++
++ for (i = 0; i < 4; i++) {
++ if (!(mask & BIT(i)))
++ continue;
++
++ if (nla_put_u8(msg, i, signal[i]))
++ return false;
++ }
++
++ nla_nest_end(msg, attr);
++
++ return true;
++}
++
+ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
+ int flags,
+ struct cfg80211_registered_device *rdev,
+@@ -2830,6 +2856,18 @@ static int nl80211_send_station(struct s
+ default:
+ break;
+ }
++ if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) {
++ if (!nl80211_put_signal(msg, sinfo->chains,
++ sinfo->chain_signal,
++ NL80211_STA_INFO_CHAIN_SIGNAL))
++ goto nla_put_failure;
++ }
++ if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) {
++ if (!nl80211_put_signal(msg, sinfo->chains,
++ sinfo->chain_signal_avg,
++ NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
++ goto nla_put_failure;
++ }
+ if (sinfo->filled & STATION_INFO_TX_BITRATE) {
+ if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
+ NL80211_STA_INFO_TX_BITRATE))
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -367,6 +367,7 @@ static void sta_set_sinfo(struct sta_inf
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ struct ieee80211_local *local = sdata->local;
+ struct timespec uptime;
++ int i;
+
+ sinfo->generation = sdata->local->sta_generation;
+
+@@ -406,6 +407,17 @@ static void sta_set_sinfo(struct sta_inf
+ 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);
+
+--- a/drivers/net/wireless/ath/ath9k/dfs.c
++++ b/drivers/net/wireless/ath/ath9k/dfs.c
+@@ -164,8 +164,8 @@ void ath9k_dfs_process_phyerr(struct ath
+ return;
+ }
+
+- ard.rssi = rs->rs_rssi_ctl0;
+- ard.ext_rssi = rs->rs_rssi_ext0;
++ ard.rssi = rs->rs_rssi_ctl[0];
++ ard.ext_rssi = rs->rs_rssi_ext[0];
+
+ /*
+ * hardware stores this as 8 bit signed value.
+--- a/drivers/net/wireless/ath/ath9k/antenna.c
++++ b/drivers/net/wireless/ath/ath9k/antenna.c
+@@ -529,14 +529,14 @@ void ath_ant_comb_scan(struct ath_softc
+ struct ath_ant_comb *antcomb = &sc->ant_comb;
+ int alt_ratio = 0, alt_rssi_avg = 0, main_rssi_avg = 0, curr_alt_set;
+ int curr_main_set;
+- int main_rssi = rs->rs_rssi_ctl0;
+- int alt_rssi = rs->rs_rssi_ctl1;
++ int main_rssi = rs->rs_rssi_ctl[0];
++ int alt_rssi = rs->rs_rssi_ctl[1];
+ int rx_ant_conf, main_ant_conf;
+ bool short_scan = false;
+
+- rx_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_CURRENT_SHIFT) &
++ rx_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_CURRENT_SHIFT) &
+ ATH_ANT_RX_MASK;
+- main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
++ main_ant_conf = (rs->rs_rssi_ctl[2] >> ATH_ANT_RX_MAIN_SHIFT) &
+ ATH_ANT_RX_MASK;
+
+ /* Record packet only when both main_rssi and alt_rssi is positive */