diff options
author | Luis R. Rodriguez <lrodriguez@atheros.com> | 2010-10-20 19:07:03 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-10-27 15:41:14 -0400 |
commit | 1e450285281bdf766272c181ecd43d4f2f0711ce (patch) | |
tree | c7c8cd58d3f08af970e93f3489450886e4489bec /drivers | |
parent | 822395b591db32ad3cf8a5b57b0fe30fb8d12c37 (diff) |
ath9k: add locking for stopping RX
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: stable@kernel.org
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fe73fc50082a..e581b1f6c40c 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -306,10 +306,8 @@ static void ath_edma_start_recv(struct ath_softc *sc) | |||
306 | 306 | ||
307 | static void ath_edma_stop_recv(struct ath_softc *sc) | 307 | static void ath_edma_stop_recv(struct ath_softc *sc) |
308 | { | 308 | { |
309 | spin_lock_bh(&sc->rx.rxbuflock); | ||
310 | ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); | 309 | ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP); |
311 | ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); | 310 | ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP); |
312 | spin_unlock_bh(&sc->rx.rxbuflock); | ||
313 | } | 311 | } |
314 | 312 | ||
315 | int ath_rx_init(struct ath_softc *sc, int nbufs) | 313 | int ath_rx_init(struct ath_softc *sc, int nbufs) |
@@ -518,6 +516,7 @@ bool ath_stoprecv(struct ath_softc *sc) | |||
518 | struct ath_hw *ah = sc->sc_ah; | 516 | struct ath_hw *ah = sc->sc_ah; |
519 | bool stopped; | 517 | bool stopped; |
520 | 518 | ||
519 | spin_lock_bh(&sc->rx.rxbuflock); | ||
521 | ath9k_hw_stoppcurecv(ah); | 520 | ath9k_hw_stoppcurecv(ah); |
522 | ath9k_hw_setrxfilter(ah, 0); | 521 | ath9k_hw_setrxfilter(ah, 0); |
523 | stopped = ath9k_hw_stopdmarecv(ah); | 522 | stopped = ath9k_hw_stopdmarecv(ah); |
@@ -526,6 +525,7 @@ bool ath_stoprecv(struct ath_softc *sc) | |||
526 | ath_edma_stop_recv(sc); | 525 | ath_edma_stop_recv(sc); |
527 | else | 526 | else |
528 | sc->rx.rxlink = NULL; | 527 | sc->rx.rxlink = NULL; |
528 | spin_unlock_bh(&sc->rx.rxbuflock); | ||
529 | 529 | ||
530 | return stopped; | 530 | return stopped; |
531 | } | 531 | } |