ath9k: add some rx path fixes

Signed-off-by: Felix Fietkau <nbd@openwrt.org>

SVN-Revision: 40780
This commit is contained in:
Felix Fietkau 2014-05-19 19:51:45 +00:00
parent 15ff368d5f
commit acf1c98271
5 changed files with 181 additions and 13 deletions

View file

@ -1,3 +1,26 @@
commit 230ab8c1880266c9cfceac962e2d48309dea79a7
Author: Felix Fietkau <nbd@openwrt.org>
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 <nbd@openwrt.org>
commit 27647baeaee1b12bc3c57ccf1c7eba53bcd7fe53
Author: Felix Fietkau <nbd@openwrt.org>
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 <nbd@openwrt.org>
commit 92e9dd662542683856e62a5e7e43fcf5b9da5c4a commit 92e9dd662542683856e62a5e7e43fcf5b9da5c4a
Author: Henning Rogge <hrogge@gmail.com> Author: Henning Rogge <hrogge@gmail.com>
Date: Thu May 1 10:03:46 2014 +0200 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); __skb_queue_head_init(&tid->retry_q);
--- a/drivers/net/wireless/ath/ath9k/recv.c --- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/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; u64 tsf = 0;
unsigned long flags; unsigned long flags;
dma_addr_t new_buf_addr; dma_addr_t new_buf_addr;
@ -367,7 +480,7 @@ Date: Sun Apr 6 23:35:28 2014 +0200
if (edma) if (edma)
dma_type = DMA_BIDIRECTIONAL; dma_type = DMA_BIDIRECTIONAL;
@@ -1113,15 +1114,17 @@ requeue_drop_frag: @@ -1113,15 +1117,17 @@ requeue_drop_frag:
} }
requeue: requeue:
list_add_tail(&bf->list, &sc->rx.rxbuf); list_add_tail(&bf->list, &sc->rx.rxbuf);
@ -375,10 +488,12 @@ Date: Sun Apr 6 23:35:28 2014 +0200
- continue; - continue;
if (edma) { 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 { } else {
ath_rx_buf_relink(sc, bf); - ath_rx_buf_relink(sc, bf);
- ath9k_hw_rxena(ah); - ath9k_hw_rxena(ah);
+ ath_rx_buf_relink(sc, bf, flush);
+ if (!flush) + if (!flush)
+ ath9k_hw_rxena(ah); + ath9k_hw_rxena(ah);
} }
@ -388,6 +503,13 @@ Date: Sun Apr 6 23:35:28 2014 +0200
} while (1); } while (1);
if (!(ah->imask & ATH9K_INT_RXEOL)) { 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 --- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/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 @@ -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_idx = status->rate_idx;
sta->last_rx_rate_flag = status->flag; sta->last_rx_rate_flag = status->flag;
sta->last_rx_rate_vht_flag = status->vht_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;

View file

@ -14,7 +14,7 @@
out: out:
spin_unlock_bh(&sc->sc_pcu_lock); 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; sc->config.txpowlimit = 2 * conf->power_level;
ath9k_cmn_update_txpow(ah, sc->curtxpow, ath9k_cmn_update_txpow(ah, sc->curtxpow,
sc->config.txpowlimit, &sc->curtxpow); sc->config.txpowlimit, &sc->curtxpow);

View file

@ -21,7 +21,7 @@
if (ant_gain > max_gain) if (ant_gain > max_gain)
--- a/drivers/net/wireless/ath/ath9k/main.c --- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/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) { if (changed & IEEE80211_CONF_CHANGE_POWER) {

View file

@ -125,7 +125,7 @@
REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON); REG_SET_BIT(ah, AR_BTCOEX_WL_LNADIV, AR_BTCOEX_WL_LNADIV_FORCE_ON);
--- a/drivers/net/wireless/ath/ath9k/main.c --- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/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); ath9k_debug_sync_cause(sc, sync_cause);
status &= ah->imask; /* discard unasked-for bits */ status &= ah->imask; /* discard unasked-for bits */

View file

@ -27,7 +27,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
return true; 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)) if (ath9k_uses_beacons(vif->type))
ath9k_beacon_assign_slot(sc, vif); ath9k_beacon_assign_slot(sc, vif);
@ -36,7 +36,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
an->sc = sc; an->sc = sc;
an->sta = NULL; an->sta = NULL;
an->vif = vif; 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; return 0;
} }
@ -66,7 +66,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
static void ath9k_remove_interface(struct ieee80211_hw *hw, static void ath9k_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif) 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); mutex_lock(&sc->mutex);
@ -80,7 +80,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
sc->nvifs--; sc->nvifs--;
sc->tx99_vif = NULL; 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); ath9k_set_assoc_state(sc, vif);
} }
@ -153,7 +153,7 @@ Signed-off-by: Felix Fietkau <nbd@openwrt.org>
static void ath9k_bss_info_changed(struct ieee80211_hw *hw, static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf, 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 <nbd@openwrt.org>
for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
--- a/drivers/net/wireless/ath/ath9k/recv.c --- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/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, ath_dbg(common, PS,
"Reconfigure beacon timers based on synchronized timestamp\n"); "Reconfigure beacon timers based on synchronized timestamp\n");
ath9k_set_beacon(sc); ath9k_set_beacon(sc);