3.4-stable review patch. If anyone has any objections, please let me know. ------------------ From: Felix Fietkau <nbd@xxxxxxxxxxx> commit e96542e55a2aacf4bdeccfe2f17b77c4895b4df2 upstream. Similar to a race condition that exists in the tx path, the hardware might re-read the 'next' pointer of a descriptor of the last completed frame. This only affects non-EDMA (pre-AR93xx) devices. To deal with this race, defer clearing and re-linking a completed rx descriptor until the next one has been processed. Signed-off-by: Felix Fietkau <nbd@xxxxxxxxxxx> Signed-off-by: John W. Linville <linville@xxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/net/wireless/ath/ath9k/ath9k.h | 5 +---- drivers/net/wireless/ath/ath9k/recv.c | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -78,10 +78,6 @@ struct ath_config { sizeof(struct ath_buf_state)); \ } while (0) -#define ATH_RXBUF_RESET(_bf) do { \ - (_bf)->bf_stale = false; \ - } while (0) - /** * enum buffer_type - Buffer type flags * @@ -314,6 +310,7 @@ struct ath_rx { struct ath_buf *rx_bufptr; struct ath_rx_edma rx_edma[ATH9K_RX_QUEUE_MAX]; + struct ath_buf *buf_hold; struct sk_buff *frag; }; --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -78,8 +78,6 @@ static void ath_rx_buf_link(struct ath_s struct ath_desc *ds; struct sk_buff *skb; - ATH_RXBUF_RESET(bf); - ds = bf->bf_desc; ds->ds_link = 0; /* link to null */ ds->ds_data = bf->bf_buf_addr; @@ -106,6 +104,14 @@ static void ath_rx_buf_link(struct ath_s sc->rx.rxlink = &ds->ds_link; } +static void ath_rx_buf_relink(struct ath_softc *sc, struct ath_buf *bf) +{ + if (sc->rx.buf_hold) + ath_rx_buf_link(sc, sc->rx.buf_hold); + + sc->rx.buf_hold = bf; +} + static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) { /* XXX block beacon interrupts */ @@ -153,7 +159,6 @@ static bool ath_rx_edma_buf_link(struct skb = bf->bf_mpdu; - ATH_RXBUF_RESET(bf); memset(skb->data, 0, ah->caps.rx_status_len); dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, ah->caps.rx_status_len, DMA_TO_DEVICE); @@ -485,6 +490,7 @@ int ath_startrecv(struct ath_softc *sc) if (list_empty(&sc->rx.rxbuf)) goto start_recv; + 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); @@ -734,6 +740,9 @@ static struct ath_buf *ath_get_next_rx_b } bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); + if (bf == sc->rx.buf_hold) + return NULL; + ds = bf->bf_desc; /* @@ -1974,7 +1983,7 @@ requeue: if (edma) { ath_rx_edma_buf_link(sc, qtype); } else { - ath_rx_buf_link(sc, bf); + ath_rx_buf_relink(sc, bf); ath9k_hw_rxena(ah); } } while (1); -- To unsubscribe from this list: send the line "unsubscribe stable" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html