From 5ac34818f9c3ad46febc260f8ae348e05b9c8f00 Mon Sep 17 00:00:00 2001 From: Koen Vandeputte Date: Mon, 5 Nov 2018 11:31:12 +0100 Subject: [PATCH] ath9k: fix dynack in IBSS mode Currently, dynack was only tested upstream using AP/STA mode. Testing it on IBSS, showed that late-ack detection was broken. This is caused due to dynack using Association Request/Response frames for late-ack detection, which IBSS does not use. Also allowing Authentication frames here solves this. A second issue also got fixed, which was also seen AP/STA mode: When a station was added, the estimated value would be exponentially averaged using 0 as a starting point. This means that on larger distances, the ack timeout was still not high enough before synchronizing would run out of late-ack's for estimation. Fix this by using the initial estimated value as a baseline and only start averaging in the following estimation rounds. Test setup: - 2x identical devices: RB912UAG-5HPnD + 19dB sector - IBSS - 2x2 802.11an (ar9340), HT20, long GI - RSSI's -70 / -71 - Real distance: 23910 meter Results (60s iperf runs): Fixed coverage class 54 (up to 24300m): * 21.5 Mbits/sec Dynack: * 28.9 Mbits/sec Signed-off-by: Koen Vandeputte --- ...-authentication-messages-for-late-ac.patch | 27 ++++ ...ve-debug-log-after-buffer-increments.patch | 88 +++++++++++ ...ck-da-enabled-first-in-sampling-rout.patch | 33 +++++ ...k-dynack-make-ewma-estimation-faster.patch | 139 ++++++++++++++++++ ...ath9k-dynack-remove-experimental-tag.patch | 22 +++ 5 files changed, 309 insertions(+) create mode 100644 package/kernel/mac80211/patches/ath/553-ath9k-dynack-use-authentication-messages-for-late-ac.patch create mode 100644 package/kernel/mac80211/patches/ath/554-ath9k-dynack-move-debug-log-after-buffer-increments.patch create mode 100644 package/kernel/mac80211/patches/ath/555-ath9k-dynack-check-da-enabled-first-in-sampling-rout.patch create mode 100644 package/kernel/mac80211/patches/ath/556-ath9k-dynack-make-ewma-estimation-faster.patch create mode 100644 package/kernel/mac80211/patches/ath/557-ath9k-dynack-remove-experimental-tag.patch diff --git a/package/kernel/mac80211/patches/ath/553-ath9k-dynack-use-authentication-messages-for-late-ac.patch b/package/kernel/mac80211/patches/ath/553-ath9k-dynack-use-authentication-messages-for-late-ac.patch new file mode 100644 index 0000000000..831c534762 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/553-ath9k-dynack-use-authentication-messages-for-late-ac.patch @@ -0,0 +1,27 @@ +From: Lorenzo Bianconi +Date: Fri, 2 Nov 2018 21:49:55 +0100 +Subject: [PATCH] ath9k: dynack: use authentication messages for 'late' ack + +In order to properly support dynack in ad-hoc mode running +wpa_supplicant, take into account authentication frames for +'late ack' detection. This patch has been tested on devices +mounted on offshore high-voltage stations connected through +~24Km link + +Reported-by: Koen Vandeputte +Tested-by: Koen Vandeputte +Signed-off-by: Lorenzo Bianconi +--- + +--- a/drivers/net/wireless/ath/ath9k/dynack.c ++++ b/drivers/net/wireless/ath/ath9k/dynack.c +@@ -187,7 +187,8 @@ void ath_dynack_sample_tx_ts(struct ath_ + /* late ACK */ + if (ts->ts_status & ATH9K_TXERR_XRETRY) { + if (ieee80211_is_assoc_req(hdr->frame_control) || +- ieee80211_is_assoc_resp(hdr->frame_control)) { ++ ieee80211_is_assoc_resp(hdr->frame_control) || ++ ieee80211_is_auth(hdr->frame_control)) { + ath_dbg(common, DYNACK, "late ack\n"); + ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2); + ath9k_hw_set_ack_timeout(ah, LATEACK_TO); diff --git a/package/kernel/mac80211/patches/ath/554-ath9k-dynack-move-debug-log-after-buffer-increments.patch b/package/kernel/mac80211/patches/ath/554-ath9k-dynack-move-debug-log-after-buffer-increments.patch new file mode 100644 index 0000000000..a1d612660b --- /dev/null +++ b/package/kernel/mac80211/patches/ath/554-ath9k-dynack-move-debug-log-after-buffer-increments.patch @@ -0,0 +1,88 @@ +From: Lorenzo Bianconi +Date: Fri, 2 Nov 2018 21:49:56 +0100 +Subject: [PATCH] ath9k: dynack: move debug log after buffer increments + +Move debug log in ath_dynack_sample_tx_ts and ath_dynack_sample_ack_ts +after timestamp buffer head/tail increments in order to make debugging +more user friendly + +Tested-by: Koen Vandeputte +Signed-off-by: Lorenzo Bianconi +--- + +--- a/drivers/net/wireless/ath/ath9k/dynack.c ++++ b/drivers/net/wireless/ath/ath9k/dynack.c +@@ -171,11 +171,12 @@ static void ath_dynack_compute_to(struct + void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, + struct ath_tx_status *ts) + { +- u8 ridx; + struct ieee80211_hdr *hdr; + struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ u32 dur = ts->duration; ++ u8 ridx; + + if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled) + return; +@@ -203,14 +204,13 @@ void ath_dynack_sample_tx_ts(struct ath_ + ridx = ts->ts_rateindex; + + da->st_rbf.ts[da->st_rbf.t_rb].tstamp = ts->ts_tstamp; +- da->st_rbf.ts[da->st_rbf.t_rb].dur = ts->duration; + ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_dest, hdr->addr1); + ether_addr_copy(da->st_rbf.addr[da->st_rbf.t_rb].h_src, hdr->addr2); + + if (!(info->status.rates[ridx].flags & IEEE80211_TX_RC_MCS)) { +- u32 phy, sifs; + const struct ieee80211_rate *rate; + struct ieee80211_tx_rate *rates = info->status.rates; ++ u32 phy; + + rate = &common->sbands[info->band].bitrates[rates[ridx].idx]; + if (info->band == NL80211_BAND_2GHZ && +@@ -219,19 +219,18 @@ void ath_dynack_sample_tx_ts(struct ath_ + else + phy = WLAN_RC_PHY_OFDM; + +- sifs = ath_dynack_get_sifs(ah, phy); +- da->st_rbf.ts[da->st_rbf.t_rb].dur -= sifs; ++ dur -= ath_dynack_get_sifs(ah, phy); + } +- +- ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n", +- hdr->addr1, da->st_rbf.ts[da->st_rbf.t_rb].tstamp, +- da->st_rbf.ts[da->st_rbf.t_rb].dur, da->st_rbf.h_rb, +- (da->st_rbf.t_rb + 1) % ATH_DYN_BUF); ++ da->st_rbf.ts[da->st_rbf.t_rb].dur = dur; + + INCR(da->st_rbf.t_rb, ATH_DYN_BUF); + if (da->st_rbf.t_rb == da->st_rbf.h_rb) + INCR(da->st_rbf.h_rb, ATH_DYN_BUF); + ++ ath_dbg(common, DYNACK, "{%pM} tx sample %u [dur %u][h %u-t %u]\n", ++ hdr->addr1, ts->ts_tstamp, dur, da->st_rbf.h_rb, ++ da->st_rbf.t_rb); ++ + ath_dynack_compute_to(ah); + + spin_unlock_bh(&da->qlock); +@@ -258,14 +257,13 @@ void ath_dynack_sample_ack_ts(struct ath + spin_lock_bh(&da->qlock); + da->ack_rbf.tstamp[da->ack_rbf.t_rb] = ts; + +- ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n", +- da->ack_rbf.tstamp[da->ack_rbf.t_rb], +- da->ack_rbf.h_rb, (da->ack_rbf.t_rb + 1) % ATH_DYN_BUF); +- + INCR(da->ack_rbf.t_rb, ATH_DYN_BUF); + if (da->ack_rbf.t_rb == da->ack_rbf.h_rb) + INCR(da->ack_rbf.h_rb, ATH_DYN_BUF); + ++ ath_dbg(common, DYNACK, "rx sample %u [h %u-t %u]\n", ++ ts, da->ack_rbf.h_rb, da->ack_rbf.t_rb); ++ + ath_dynack_compute_to(ah); + + spin_unlock_bh(&da->qlock); diff --git a/package/kernel/mac80211/patches/ath/555-ath9k-dynack-check-da-enabled-first-in-sampling-rout.patch b/package/kernel/mac80211/patches/ath/555-ath9k-dynack-check-da-enabled-first-in-sampling-rout.patch new file mode 100644 index 0000000000..cc5cdf9233 --- /dev/null +++ b/package/kernel/mac80211/patches/ath/555-ath9k-dynack-check-da-enabled-first-in-sampling-rout.patch @@ -0,0 +1,33 @@ +From: Lorenzo Bianconi +Date: Fri, 2 Nov 2018 21:49:57 +0100 +Subject: [PATCH] ath9k: dynack: check da->enabled first in sampling + routines + +Check da->enabled flag first in ath_dynack_sample_tx_ts and +ath_dynack_sample_ack_ts routines in order to avoid useless +processing + +Tested-by: Koen Vandeputte +Signed-off-by: Lorenzo Bianconi +--- + +--- a/drivers/net/wireless/ath/ath9k/dynack.c ++++ b/drivers/net/wireless/ath/ath9k/dynack.c +@@ -178,7 +178,7 @@ void ath_dynack_sample_tx_ts(struct ath_ + u32 dur = ts->duration; + u8 ridx; + +- if ((info->flags & IEEE80211_TX_CTL_NO_ACK) || !da->enabled) ++ if (!da->enabled || (info->flags & IEEE80211_TX_CTL_NO_ACK)) + return; + + spin_lock_bh(&da->qlock); +@@ -251,7 +251,7 @@ void ath_dynack_sample_ack_ts(struct ath + struct ath_common *common = ath9k_hw_common(ah); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + +- if (!ath_dynack_bssidmask(ah, hdr->addr1) || !da->enabled) ++ if (!da->enabled || !ath_dynack_bssidmask(ah, hdr->addr1)) + return; + + spin_lock_bh(&da->qlock); diff --git a/package/kernel/mac80211/patches/ath/556-ath9k-dynack-make-ewma-estimation-faster.patch b/package/kernel/mac80211/patches/ath/556-ath9k-dynack-make-ewma-estimation-faster.patch new file mode 100644 index 0000000000..aaae8babcc --- /dev/null +++ b/package/kernel/mac80211/patches/ath/556-ath9k-dynack-make-ewma-estimation-faster.patch @@ -0,0 +1,139 @@ +From: Lorenzo Bianconi +Date: Fri, 2 Nov 2018 21:49:58 +0100 +Subject: [PATCH] ath9k: dynack: make ewma estimation faster + +In order to make propagation time estimation faster, +use current sample as ewma output value during 'late ack' +tracking + +Tested-by: Koen Vandeputte +Signed-off-by: Lorenzo Bianconi +--- + +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h +@@ -274,7 +274,7 @@ struct ath_node { + #endif + u8 key_idx[4]; + +- u32 ackto; ++ int ackto; + struct list_head list; + }; + +--- a/drivers/net/wireless/ath/ath9k/dynack.c ++++ b/drivers/net/wireless/ath/ath9k/dynack.c +@@ -29,9 +29,13 @@ + * ath_dynack_ewma - EWMA (Exponentially Weighted Moving Average) calculation + * + */ +-static inline u32 ath_dynack_ewma(u32 old, u32 new) ++static inline int ath_dynack_ewma(int old, int new) + { +- return (new * (EWMA_DIV - EWMA_LEVEL) + old * EWMA_LEVEL) / EWMA_DIV; ++ if (old > 0) ++ return (new * (EWMA_DIV - EWMA_LEVEL) + ++ old * EWMA_LEVEL) / EWMA_DIV; ++ else ++ return new; + } + + /** +@@ -82,10 +86,10 @@ static inline bool ath_dynack_bssidmask( + */ + static void ath_dynack_compute_ackto(struct ath_hw *ah) + { +- struct ath_node *an; +- u32 to = 0; +- struct ath_dynack *da = &ah->dynack; + struct ath_common *common = ath9k_hw_common(ah); ++ struct ath_dynack *da = &ah->dynack; ++ struct ath_node *an; ++ int to = 0; + + list_for_each_entry(an, &da->nodes, list) + if (an->ackto > to) +@@ -144,7 +148,8 @@ static void ath_dynack_compute_to(struct + an->ackto = ath_dynack_ewma(an->ackto, + ackto); + ath_dbg(ath9k_hw_common(ah), DYNACK, +- "%pM to %u\n", dst, an->ackto); ++ "%pM to %d [%u]\n", dst, ++ an->ackto, ackto); + if (time_is_before_jiffies(da->lto)) { + ath_dynack_compute_ackto(ah); + da->lto = jiffies + COMPUTE_TO; +@@ -166,10 +171,12 @@ static void ath_dynack_compute_to(struct + * @ah: ath hw + * @skb: socket buffer + * @ts: tx status info ++ * @sta: station pointer + * + */ + void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, +- struct ath_tx_status *ts) ++ struct ath_tx_status *ts, ++ struct ieee80211_sta *sta) + { + struct ieee80211_hdr *hdr; + struct ath_dynack *da = &ah->dynack; +@@ -191,9 +198,16 @@ void ath_dynack_sample_tx_ts(struct ath_ + ieee80211_is_assoc_resp(hdr->frame_control) || + ieee80211_is_auth(hdr->frame_control)) { + ath_dbg(common, DYNACK, "late ack\n"); ++ + ath9k_hw_setslottime(ah, (LATEACK_TO - 3) / 2); + ath9k_hw_set_ack_timeout(ah, LATEACK_TO); + ath9k_hw_set_cts_timeout(ah, LATEACK_TO); ++ if (sta) { ++ struct ath_node *an; ++ ++ an = (struct ath_node *)sta->drv_priv; ++ an->ackto = -1; ++ } + da->lto = jiffies + LATEACK_DELAY; + } + +--- a/drivers/net/wireless/ath/ath9k/dynack.h ++++ b/drivers/net/wireless/ath/ath9k/dynack.h +@@ -86,7 +86,8 @@ void ath_dynack_node_deinit(struct ath_h + void ath_dynack_init(struct ath_hw *ah); + void ath_dynack_sample_ack_ts(struct ath_hw *ah, struct sk_buff *skb, u32 ts); + void ath_dynack_sample_tx_ts(struct ath_hw *ah, struct sk_buff *skb, +- struct ath_tx_status *ts); ++ struct ath_tx_status *ts, ++ struct ieee80211_sta *sta); + #else + static inline void ath_dynack_init(struct ath_hw *ah) {} + static inline void ath_dynack_node_init(struct ath_hw *ah, +@@ -97,7 +98,8 @@ static inline void ath_dynack_sample_ack + struct sk_buff *skb, u32 ts) {} + static inline void ath_dynack_sample_tx_ts(struct ath_hw *ah, + struct sk_buff *skb, +- struct ath_tx_status *ts) {} ++ struct ath_tx_status *ts, ++ struct ieee80211_sta *sta) {} + #endif + + #endif /* DYNACK_H */ +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -629,7 +629,7 @@ static void ath_tx_complete_aggr(struct + if (bf == bf->bf_lastbf) + ath_dynack_sample_tx_ts(sc->sc_ah, + bf->bf_mpdu, +- ts); ++ ts, sta); + } + + ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts, +@@ -773,7 +773,8 @@ static void ath_tx_process_buffer(struct + memcpy(info->control.rates, bf->rates, + sizeof(info->control.rates)); + ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); +- ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts); ++ ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts, ++ sta); + } + ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok); + } else diff --git a/package/kernel/mac80211/patches/ath/557-ath9k-dynack-remove-experimental-tag.patch b/package/kernel/mac80211/patches/ath/557-ath9k-dynack-remove-experimental-tag.patch new file mode 100644 index 0000000000..2e4cffd1fa --- /dev/null +++ b/package/kernel/mac80211/patches/ath/557-ath9k-dynack-remove-experimental-tag.patch @@ -0,0 +1,22 @@ +From: Lorenzo Bianconi +Date: Fri, 2 Nov 2018 21:49:59 +0100 +Subject: [PATCH] ath9k: dynack: remove 'experimental' tag + +Remove experimental tag from dynack Kconfig entry since it has +been tested on outdoor 25Km links + +Tested-by: Koen Vandeputte +Signed-off-by: Lorenzo Bianconi +--- + +--- a/drivers/net/wireless/ath/ath9k/Kconfig ++++ b/drivers/net/wireless/ath/ath9k/Kconfig +@@ -132,7 +132,7 @@ config ATH9K_DFS_CERTIFIED + except increase code size. + + config ATH9K_DYNACK +- bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)" ++ bool "Atheros ath9k ACK timeout estimation algorithm" + depends on ATH9K + default n + ---help--- -- 2.30.2