| Date | Tue, 07 Dec 2010 16:56:48 -0800 | From | Greg KH <> | Subject | [031/289] ath9k: add locking for stopping RX |
| |
2.6.36-stable review patch. If anyone has any objections, please let us know.
------------------
From: Luis R. Rodriguez <lrodriguez@atheros.com>
commit 1e450285281bdf766272c181ecd43d4f2f0711ce upstream.
ath9k locks for starting RX but not for stopping RX. We could potentially run into a situation where tried to stop RX but immediately started RX. This allows for races on the the RX engine deciding what buffer we last left off on and could potentially cause ath9k to DMA into already free'd memory or in the worst case at a later time to already given memory to other drivers.
Fix this by locking stopping RX.
This is part of a series that will help resolve the bug:
https://bugzilla.kernel.org/show_bug.cgi?id=14624
For more details about this issue refer to:
http://marc.info/?l=linux-wireless&m=128629803703756&w=2
Cc: Ben Greear <greearb@candelatech.com> Cc: Kyungwan Nam <kyungwan.nam@atheros.com> Signed-off-by: Luis R. Rodriguez <lrodriguez@atheros.com> Tested-by: Ben Greear <greearb@candelatech.com> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
--- drivers/net/wireless/ath/ath9k/recv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -297,10 +297,8 @@ static void ath_edma_start_recv(struct a static void ath_edma_stop_recv(struct ath_softc *sc) { - spin_lock_bh(&sc->rx.rxbuflock); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); - spin_unlock_bh(&sc->rx.rxbuflock); } int ath_rx_init(struct ath_softc *sc, int nbufs) @@ -508,6 +506,7 @@ bool ath_stoprecv(struct ath_softc *sc) struct ath_hw *ah = sc->sc_ah; bool stopped; + spin_lock_bh(&sc->rx.rxbuflock); ath9k_hw_stoppcurecv(ah); ath9k_hw_setrxfilter(ah, 0); stopped = ath9k_hw_stopdmarecv(ah); @@ -516,6 +515,7 @@ bool ath_stoprecv(struct ath_softc *sc) ath_edma_stop_recv(sc); else sc->rx.rxlink = NULL; + spin_unlock_bh(&sc->rx.rxbuflock); return stopped; }
|