From fc8cbde216f2aca7a244c39e716c816f594f2d83 Mon Sep 17 00:00:00 2001 From: nbd Date: Mon, 19 May 2014 19:51:45 +0000 Subject: [PATCH] ath9k: add some rx path fixes Signed-off-by: Felix Fietkau git-svn-id: svn://svn.openwrt.org/openwrt/trunk@40780 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../kernel/mac80211/patches/300-pending_work.patch | 176 ++++++++++++++++++++- .../mac80211/patches/521-ath9k_cur_txpower.patch | 2 +- .../523-ath9k_use_configured_antenna_gain.patch | 2 +- .../mac80211/patches/542-ath9k_debugfs_diag.patch | 2 +- .../patches/552-ath9k_p2p_ps_support.patch | 12 +- 5 files changed, 181 insertions(+), 13 deletions(-) diff --git a/package/kernel/mac80211/patches/300-pending_work.patch b/package/kernel/mac80211/patches/300-pending_work.patch index ce19e7db5f..ef81721529 100644 --- a/package/kernel/mac80211/patches/300-pending_work.patch +++ b/package/kernel/mac80211/patches/300-pending_work.patch @@ -1,3 +1,26 @@ +commit 230ab8c1880266c9cfceac962e2d48309dea79a7 +Author: Felix Fietkau +Date: Mon May 19 21:48:56 2014 +0200 + + ath9k: re-schedule rx processing after budget exceeded + + Should improve rx stability under load + + Signed-off-by: Felix Fietkau + +commit 27647baeaee1b12bc3c57ccf1c7eba53bcd7fe53 +Author: Felix Fietkau +Date: Mon May 19 21:20:49 2014 +0200 + + ath9k: avoid passing buffers to the hardware during flush + + The commit "ath9k: fix possible hang on flush" changed the receive code + to always link rx descriptors of processed frames, even when flushing. + In some cases, this leads to flushed rx buffers being passed to the + hardware while rx is already stopped. + + Signed-off-by: Felix Fietkau + commit 92e9dd662542683856e62a5e7e43fcf5b9da5c4a Author: Henning Rogge Date: Thu May 1 10:03:46 2014 +0200 @@ -359,7 +382,97 @@ Date: Sun Apr 6 23:35:28 2014 +0200 __skb_queue_head_init(&tid->retry_q); --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c -@@ -975,6 +975,7 @@ int ath_rx_tasklet(struct ath_softc *sc, +@@ -34,7 +34,8 @@ static inline bool ath9k_check_auto_slee + * buffer (or rx fifo). This can incorrectly acknowledge packets + * to a sender if last desc is self-linked. + */ +-static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf) ++static void ath_rx_buf_link(struct ath_softc *sc, struct ath_rxbuf *bf, ++ bool flush) + { + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); +@@ -59,18 +60,19 @@ static void ath_rx_buf_link(struct ath_s + common->rx_bufsize, + 0); + +- if (sc->rx.rxlink == NULL) +- ath9k_hw_putrxbuf(ah, bf->bf_daddr); +- else ++ if (sc->rx.rxlink) + *sc->rx.rxlink = bf->bf_daddr; ++ else if (!flush) ++ ath9k_hw_putrxbuf(ah, bf->bf_daddr); + + sc->rx.rxlink = &ds->ds_link; + } + +-static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf) ++static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_rxbuf *bf, ++ bool flush) + { + if (sc->rx.buf_hold) +- ath_rx_buf_link(sc, sc->rx.buf_hold); ++ ath_rx_buf_link(sc, sc->rx.buf_hold, flush); + + sc->rx.buf_hold = bf; + } +@@ -106,7 +108,7 @@ static void ath_opmode_init(struct ath_s + } + + static bool ath_rx_edma_buf_link(struct ath_softc *sc, +- enum ath9k_rx_qtype qtype) ++ enum ath9k_rx_qtype qtype, bool flush) + { + struct ath_hw *ah = sc->sc_ah; + struct ath_rx_edma *rx_edma; +@@ -127,7 +129,8 @@ static bool ath_rx_edma_buf_link(struct + ah->caps.rx_status_len, DMA_TO_DEVICE); + + SKB_CB_ATHBUF(skb) = bf; +- ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype); ++ if (!flush) ++ ath9k_hw_addrxbuf_edma(ah, bf->bf_buf_addr, qtype); + __skb_queue_tail(&rx_edma->rx_fifo, skb); + + return true; +@@ -145,7 +148,7 @@ static void ath_rx_addbuffer_edma(struct + } + + list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) +- if (!ath_rx_edma_buf_link(sc, qtype)) ++ if (!ath_rx_edma_buf_link(sc, qtype, false)) + break; + + } +@@ -442,7 +445,7 @@ int ath_startrecv(struct ath_softc *sc) + sc->rx.buf_hold = NULL; + sc->rx.rxlink = NULL; + list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { +- ath_rx_buf_link(sc, bf); ++ ath_rx_buf_link(sc, bf, false); + } + + /* We could have deleted elements so the list may be empty now */ +@@ -636,7 +639,7 @@ static bool ath_edma_get_buffers(struct + if (ret == -EINVAL) { + /* corrupt descriptor, skip this one and the following one */ + list_add_tail(&bf->list, &sc->rx.rxbuf); +- ath_rx_edma_buf_link(sc, qtype); ++ ath_rx_edma_buf_link(sc, qtype, false); + + skb = skb_peek(&rx_edma->rx_fifo); + if (skb) { +@@ -645,7 +648,7 @@ static bool ath_edma_get_buffers(struct + + __skb_unlink(skb, &rx_edma->rx_fifo); + list_add_tail(&bf->list, &sc->rx.rxbuf); +- ath_rx_edma_buf_link(sc, qtype); ++ ath_rx_edma_buf_link(sc, qtype, false); + } + + bf = NULL; +@@ -975,6 +978,7 @@ int ath_rx_tasklet(struct ath_softc *sc, u64 tsf = 0; unsigned long flags; dma_addr_t new_buf_addr; @@ -367,7 +480,7 @@ Date: Sun Apr 6 23:35:28 2014 +0200 if (edma) dma_type = DMA_BIDIRECTIONAL; -@@ -1113,15 +1114,17 @@ requeue_drop_frag: +@@ -1113,15 +1117,17 @@ requeue_drop_frag: } requeue: list_add_tail(&bf->list, &sc->rx.rxbuf); @@ -375,10 +488,12 @@ Date: Sun Apr 6 23:35:28 2014 +0200 - continue; if (edma) { - ath_rx_edma_buf_link(sc, qtype); +- ath_rx_edma_buf_link(sc, qtype); ++ ath_rx_edma_buf_link(sc, qtype, flush); } else { - ath_rx_buf_relink(sc, bf); +- ath_rx_buf_relink(sc, bf); - ath9k_hw_rxena(ah); ++ ath_rx_buf_relink(sc, bf, flush); + if (!flush) + ath9k_hw_rxena(ah); } @@ -388,6 +503,13 @@ Date: Sun Apr 6 23:35:28 2014 +0200 } while (1); if (!(ah->imask & ATH9K_INT_RXEOL)) { +@@ -1129,5 +1135,5 @@ requeue: + ath9k_hw_set_interrupts(ah); + } + +- return 0; ++ return !budget; + } --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -86,7 +86,6 @@ static int ath_ahb_probe(struct platform @@ -565,3 +687,49 @@ Date: Sun Apr 6 23:35:28 2014 +0200 sta->last_rx_rate_idx = status->rate_idx; sta->last_rx_rate_flag = status->flag; sta->last_rx_rate_vht_flag = status->vht_flag; +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -442,6 +442,8 @@ void ath9k_tasklet(unsigned long data) + ath9k_ps_wakeup(sc); + spin_lock(&sc->sc_pcu_lock); + ++ sc->intrstatus = 0; ++ + if (status & ATH9K_INT_FATAL) { + type = RESET_TYPE_FATAL_INT; + ath9k_queue_reset(sc, type); +@@ -510,10 +512,12 @@ void ath9k_tasklet(unsigned long data) + if (status & rxmask) { + /* Check for high priority Rx first */ + if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && +- (status & ATH9K_INT_RXHP)) +- ath_rx_tasklet(sc, 0, true); ++ (status & ATH9K_INT_RXHP) && ++ ath_rx_tasklet(sc, 0, true)) ++ sc->intrstatus |= ATH9K_INT_RXHP; + +- ath_rx_tasklet(sc, 0, false); ++ if (ath_rx_tasklet(sc, 0, false)) ++ sc->intrstatus |= ATH9K_INT_RXLP; + } + + if (status & ATH9K_INT_TX) { +@@ -541,6 +545,9 @@ void ath9k_tasklet(unsigned long data) + + /* re-enable hardware interrupt */ + ath9k_hw_enable_interrupts(ah); ++ if (sc->intrstatus) ++ tasklet_schedule(&sc->intr_tq); ++ + out: + spin_unlock(&sc->sc_pcu_lock); + ath9k_ps_restore(sc); +@@ -607,7 +614,7 @@ irqreturn_t ath_isr(int irq, void *dev) + return IRQ_NONE; + + /* Cache the status */ +- sc->intrstatus = status; ++ sc->intrstatus |= status; + + if (status & SCHED_INTR) + sched = true; diff --git a/package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch b/package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch index 24bc0626ed..ebc3633f60 100644 --- a/package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch +++ b/package/kernel/mac80211/patches/521-ath9k_cur_txpower.patch @@ -14,7 +14,7 @@ out: spin_unlock_bh(&sc->sc_pcu_lock); -@@ -1370,6 +1374,7 @@ static int ath9k_config(struct ieee80211 +@@ -1377,6 +1381,7 @@ static int ath9k_config(struct ieee80211 sc->config.txpowlimit = 2 * conf->power_level; ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); diff --git a/package/kernel/mac80211/patches/523-ath9k_use_configured_antenna_gain.patch b/package/kernel/mac80211/patches/523-ath9k_use_configured_antenna_gain.patch index b84a99134a..2903bd9d14 100644 --- a/package/kernel/mac80211/patches/523-ath9k_use_configured_antenna_gain.patch +++ b/package/kernel/mac80211/patches/523-ath9k_use_configured_antenna_gain.patch @@ -21,7 +21,7 @@ if (ant_gain > max_gain) --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -1370,7 +1370,10 @@ static int ath9k_config(struct ieee80211 +@@ -1377,7 +1377,10 @@ static int ath9k_config(struct ieee80211 } if (changed & IEEE80211_CONF_CHANGE_POWER) { diff --git a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch index 44aa905649..419717ae0a 100644 --- a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch +++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch @@ -125,7 +125,7 @@ REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -603,6 +603,11 @@ irqreturn_t ath_isr(int irq, void *dev) +@@ -610,6 +610,11 @@ irqreturn_t ath_isr(int irq, void *dev) ath9k_debug_sync_cause(sc, sync_cause); status &= ah->imask; /* discard unasked-for bits */ diff --git a/package/kernel/mac80211/patches/552-ath9k_p2p_ps_support.patch b/package/kernel/mac80211/patches/552-ath9k_p2p_ps_support.patch index 8cf9e612c5..3b09aef608 100644 --- a/package/kernel/mac80211/patches/552-ath9k_p2p_ps_support.patch +++ b/package/kernel/mac80211/patches/552-ath9k_p2p_ps_support.patch @@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau return true; } -@@ -1128,6 +1130,8 @@ static int ath9k_add_interface(struct ie +@@ -1135,6 +1137,8 @@ static int ath9k_add_interface(struct ie if (ath9k_uses_beacons(vif->type)) ath9k_beacon_assign_slot(sc, vif); @@ -36,7 +36,7 @@ Signed-off-by: Felix Fietkau an->sc = sc; an->sta = NULL; an->vif = vif; -@@ -1172,6 +1176,29 @@ static int ath9k_change_interface(struct +@@ -1179,6 +1183,29 @@ static int ath9k_change_interface(struct return 0; } @@ -66,7 +66,7 @@ Signed-off-by: Felix Fietkau static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { -@@ -1183,6 +1210,13 @@ static void ath9k_remove_interface(struc +@@ -1190,6 +1217,13 @@ static void ath9k_remove_interface(struc mutex_lock(&sc->mutex); @@ -80,7 +80,7 @@ Signed-off-by: Felix Fietkau sc->nvifs--; sc->tx99_vif = NULL; -@@ -1649,6 +1683,72 @@ static void ath9k_bss_assoc_iter(void *d +@@ -1656,6 +1690,72 @@ static void ath9k_bss_assoc_iter(void *d ath9k_set_assoc_state(sc, vif); } @@ -153,7 +153,7 @@ Signed-off-by: Felix Fietkau static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, -@@ -1723,6 +1823,12 @@ static void ath9k_bss_info_changed(struc +@@ -1730,6 +1830,12 @@ static void ath9k_bss_info_changed(struc } } @@ -237,7 +237,7 @@ Signed-off-by: Felix Fietkau for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c -@@ -539,6 +539,9 @@ static void ath_rx_ps_beacon(struct ath_ +@@ -542,6 +542,9 @@ static void ath_rx_ps_beacon(struct ath_ ath_dbg(common, PS, "Reconfigure beacon timers based on synchronized timestamp\n"); ath9k_set_beacon(sc); -- 2.11.0