diff options
author | Jiri Slaby <jirislaby@gmail.com> | 2008-08-18 15:45:27 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-08-26 20:06:31 -0400 |
commit | 004829730cb1b03abe7555e1c1faadec62cbcf6f (patch) | |
tree | 414985c79061809ddfdd72ba138a5402b3cbe978 | |
parent | d0c2912fe8df81a8b723fb6ec4d4cdf523cbaff7 (diff) |
Ath5k: lock beacons
Beacons setup and config was racy with beacon send. Ensure that
ISR and reset functions see consistent state of bbuf.
Use also dev_kfree_skb_any in ath5k_txbuf_free since we call it
from atomic now.
Signed-off-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Nick Kossifidis <mickflemm@gmail.com>
Cc: Luis R. Rodriguez <mcgrof@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath5k/base.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/ath5k/base.h | 1 |
2 files changed, 13 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index b20a45aa8680..7bc012fca059 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c | |||
@@ -251,7 +251,7 @@ static inline void ath5k_txbuf_free(struct ath5k_softc *sc, | |||
251 | return; | 251 | return; |
252 | pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, | 252 | pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len, |
253 | PCI_DMA_TODEVICE); | 253 | PCI_DMA_TODEVICE); |
254 | dev_kfree_skb(bf->skb); | 254 | dev_kfree_skb_any(bf->skb); |
255 | bf->skb = NULL; | 255 | bf->skb = NULL; |
256 | } | 256 | } |
257 | 257 | ||
@@ -466,6 +466,7 @@ ath5k_pci_probe(struct pci_dev *pdev, | |||
466 | mutex_init(&sc->lock); | 466 | mutex_init(&sc->lock); |
467 | spin_lock_init(&sc->rxbuflock); | 467 | spin_lock_init(&sc->rxbuflock); |
468 | spin_lock_init(&sc->txbuflock); | 468 | spin_lock_init(&sc->txbuflock); |
469 | spin_lock_init(&sc->block); | ||
469 | 470 | ||
470 | /* Set private data */ | 471 | /* Set private data */ |
471 | pci_set_drvdata(pdev, hw); | 472 | pci_set_drvdata(pdev, hw); |
@@ -2179,8 +2180,11 @@ ath5k_beacon_config(struct ath5k_softc *sc) | |||
2179 | 2180 | ||
2180 | sc->imask |= AR5K_INT_SWBA; | 2181 | sc->imask |= AR5K_INT_SWBA; |
2181 | 2182 | ||
2182 | if (ath5k_hw_hasveol(ah)) | 2183 | if (ath5k_hw_hasveol(ah)) { |
2184 | spin_lock(&sc->block); | ||
2183 | ath5k_beacon_send(sc); | 2185 | ath5k_beacon_send(sc); |
2186 | spin_unlock(&sc->block); | ||
2187 | } | ||
2184 | } | 2188 | } |
2185 | /* TODO else AP */ | 2189 | /* TODO else AP */ |
2186 | 2190 | ||
@@ -2403,7 +2407,9 @@ ath5k_intr(int irq, void *dev_id) | |||
2403 | TSF_TO_TU(tsf), | 2407 | TSF_TO_TU(tsf), |
2404 | (unsigned long long) tsf); | 2408 | (unsigned long long) tsf); |
2405 | } else { | 2409 | } else { |
2410 | spin_lock(&sc->block); | ||
2406 | ath5k_beacon_send(sc); | 2411 | ath5k_beacon_send(sc); |
2412 | spin_unlock(&sc->block); | ||
2407 | } | 2413 | } |
2408 | } | 2414 | } |
2409 | if (status & AR5K_INT_RXEOL) { | 2415 | if (status & AR5K_INT_RXEOL) { |
@@ -3050,6 +3056,7 @@ static int | |||
3050 | ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) | 3056 | ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) |
3051 | { | 3057 | { |
3052 | struct ath5k_softc *sc = hw->priv; | 3058 | struct ath5k_softc *sc = hw->priv; |
3059 | unsigned long flags; | ||
3053 | int ret; | 3060 | int ret; |
3054 | 3061 | ||
3055 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); | 3062 | ath5k_debug_dump_skb(sc, skb, "BC ", 1); |
@@ -3059,12 +3066,14 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) | |||
3059 | goto end; | 3066 | goto end; |
3060 | } | 3067 | } |
3061 | 3068 | ||
3069 | spin_lock_irqsave(&sc->block, flags); | ||
3062 | ath5k_txbuf_free(sc, sc->bbuf); | 3070 | ath5k_txbuf_free(sc, sc->bbuf); |
3063 | sc->bbuf->skb = skb; | 3071 | sc->bbuf->skb = skb; |
3064 | ret = ath5k_beacon_setup(sc, sc->bbuf); | 3072 | ret = ath5k_beacon_setup(sc, sc->bbuf); |
3065 | if (ret) | 3073 | if (ret) |
3066 | sc->bbuf->skb = NULL; | 3074 | sc->bbuf->skb = NULL; |
3067 | else { | 3075 | spin_unlock_irqrestore(&sc->block, flags); |
3076 | if (!ret) { | ||
3068 | ath5k_beacon_config(sc); | 3077 | ath5k_beacon_config(sc); |
3069 | mmiowb(); | 3078 | mmiowb(); |
3070 | } | 3079 | } |
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h index d7e03e6b8271..7ec2f377d5c7 100644 --- a/drivers/net/wireless/ath5k/base.h +++ b/drivers/net/wireless/ath5k/base.h | |||
@@ -172,6 +172,7 @@ struct ath5k_softc { | |||
172 | struct tasklet_struct txtq; /* tx intr tasklet */ | 172 | struct tasklet_struct txtq; /* tx intr tasklet */ |
173 | struct ath5k_led tx_led; /* tx led */ | 173 | struct ath5k_led tx_led; /* tx led */ |
174 | 174 | ||
175 | spinlock_t block; /* protects beacon */ | ||
175 | struct ath5k_buf *bbuf; /* beacon buffer */ | 176 | struct ath5k_buf *bbuf; /* beacon buffer */ |
176 | unsigned int bhalq, /* SW q for outgoing beacons */ | 177 | unsigned int bhalq, /* SW q for outgoing beacons */ |
177 | bmisscount, /* missed beacon transmits */ | 178 | bmisscount, /* missed beacon transmits */ |