aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBob Copeland <me@bobcopeland.com>2008-10-16 11:02:06 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-10-22 18:09:32 -0400
commit8bdd5b9c6bd53add260756b6673a0545fbdbba21 (patch)
treea35a59e657422a8577103fff8a34f8b2d8f79440
parent75e3d8db531b462b875c1adb13eeb6b0be7374c0 (diff)
ath5k: fix suspend-related oops on rmmod
Based on a patch by Elias Oltmanns, we call ath5k_init in resume even if we didn't previously open the device. Besides starting up the device unnecessarily, this also causes an oops on rmmod because mac80211 will not invoke ath5k_stop and softirqs are left running after the module has been unloaded. Add a new state bit, ATH_STAT_STARTED, to indicate that we have been started up. Reported-by: Toralf Förster <toralf.foerster@gmx.de> Signed-off-by: Elias Oltmanns <eo@nebensachen.de> Signed-off-by: Bob Copeland <me@bobcopeland.com> Cc: stable@kernel.org Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath5k/base.c27
-rw-r--r--drivers/net/wireless/ath5k/base.h3
2 files changed, 21 insertions, 9 deletions
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index 9b95c4049b31..0f1d6bdd51a2 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -340,9 +340,9 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
340} 340}
341 341
342/* Interrupt handling */ 342/* Interrupt handling */
343static int ath5k_init(struct ath5k_softc *sc); 343static int ath5k_init(struct ath5k_softc *sc, bool is_resume);
344static int ath5k_stop_locked(struct ath5k_softc *sc); 344static int ath5k_stop_locked(struct ath5k_softc *sc);
345static int ath5k_stop_hw(struct ath5k_softc *sc); 345static int ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend);
346static irqreturn_t ath5k_intr(int irq, void *dev_id); 346static irqreturn_t ath5k_intr(int irq, void *dev_id);
347static void ath5k_tasklet_reset(unsigned long data); 347static void ath5k_tasklet_reset(unsigned long data);
348 348
@@ -646,7 +646,7 @@ ath5k_pci_suspend(struct pci_dev *pdev, pm_message_t state)
646 646
647 ath5k_led_off(sc); 647 ath5k_led_off(sc);
648 648
649 ath5k_stop_hw(sc); 649 ath5k_stop_hw(sc, true);
650 650
651 free_irq(pdev->irq, sc); 651 free_irq(pdev->irq, sc);
652 pci_save_state(pdev); 652 pci_save_state(pdev);
@@ -683,7 +683,7 @@ ath5k_pci_resume(struct pci_dev *pdev)
683 goto err_no_irq; 683 goto err_no_irq;
684 } 684 }
685 685
686 err = ath5k_init(sc); 686 err = ath5k_init(sc, true);
687 if (err) 687 if (err)
688 goto err_irq; 688 goto err_irq;
689 ath5k_led_enable(sc); 689 ath5k_led_enable(sc);
@@ -2200,12 +2200,17 @@ ath5k_beacon_config(struct ath5k_softc *sc)
2200\********************/ 2200\********************/
2201 2201
2202static int 2202static int
2203ath5k_init(struct ath5k_softc *sc) 2203ath5k_init(struct ath5k_softc *sc, bool is_resume)
2204{ 2204{
2205 int ret; 2205 int ret;
2206 2206
2207 mutex_lock(&sc->lock); 2207 mutex_lock(&sc->lock);
2208 2208
2209 if (is_resume && !test_bit(ATH_STAT_STARTED, sc->status))
2210 goto out_ok;
2211
2212 __clear_bit(ATH_STAT_STARTED, sc->status);
2213
2209 ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode); 2214 ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "mode %d\n", sc->opmode);
2210 2215
2211 /* 2216 /*
@@ -2230,12 +2235,15 @@ ath5k_init(struct ath5k_softc *sc)
2230 if (ret) 2235 if (ret)
2231 goto done; 2236 goto done;
2232 2237
2238 __set_bit(ATH_STAT_STARTED, sc->status);
2239
2233 /* Set ack to be sent at low bit-rates */ 2240 /* Set ack to be sent at low bit-rates */
2234 ath5k_hw_set_ack_bitrate_high(sc->ah, false); 2241 ath5k_hw_set_ack_bitrate_high(sc->ah, false);
2235 2242
2236 mod_timer(&sc->calib_tim, round_jiffies(jiffies + 2243 mod_timer(&sc->calib_tim, round_jiffies(jiffies +
2237 msecs_to_jiffies(ath5k_calinterval * 1000))); 2244 msecs_to_jiffies(ath5k_calinterval * 1000)));
2238 2245
2246out_ok:
2239 ret = 0; 2247 ret = 0;
2240done: 2248done:
2241 mmiowb(); 2249 mmiowb();
@@ -2290,7 +2298,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
2290 * stop is preempted). 2298 * stop is preempted).
2291 */ 2299 */
2292static int 2300static int
2293ath5k_stop_hw(struct ath5k_softc *sc) 2301ath5k_stop_hw(struct ath5k_softc *sc, bool is_suspend)
2294{ 2302{
2295 int ret; 2303 int ret;
2296 2304
@@ -2321,6 +2329,9 @@ ath5k_stop_hw(struct ath5k_softc *sc)
2321 } 2329 }
2322 } 2330 }
2323 ath5k_txbuf_free(sc, sc->bbuf); 2331 ath5k_txbuf_free(sc, sc->bbuf);
2332 if (!is_suspend)
2333 __clear_bit(ATH_STAT_STARTED, sc->status);
2334
2324 mmiowb(); 2335 mmiowb();
2325 mutex_unlock(&sc->lock); 2336 mutex_unlock(&sc->lock);
2326 2337
@@ -2718,12 +2729,12 @@ ath5k_reset_wake(struct ath5k_softc *sc)
2718 2729
2719static int ath5k_start(struct ieee80211_hw *hw) 2730static int ath5k_start(struct ieee80211_hw *hw)
2720{ 2731{
2721 return ath5k_init(hw->priv); 2732 return ath5k_init(hw->priv, false);
2722} 2733}
2723 2734
2724static void ath5k_stop(struct ieee80211_hw *hw) 2735static void ath5k_stop(struct ieee80211_hw *hw)
2725{ 2736{
2726 ath5k_stop_hw(hw->priv); 2737 ath5k_stop_hw(hw->priv, false);
2727} 2738}
2728 2739
2729static int ath5k_add_interface(struct ieee80211_hw *hw, 2740static int ath5k_add_interface(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/ath5k/base.h b/drivers/net/wireless/ath5k/base.h
index 9d0b728928e3..06d1054ca94b 100644
--- a/drivers/net/wireless/ath5k/base.h
+++ b/drivers/net/wireless/ath5k/base.h
@@ -128,11 +128,12 @@ struct ath5k_softc {
128 size_t desc_len; /* size of TX/RX descriptors */ 128 size_t desc_len; /* size of TX/RX descriptors */
129 u16 cachelsz; /* cache line size */ 129 u16 cachelsz; /* cache line size */
130 130
131 DECLARE_BITMAP(status, 4); 131 DECLARE_BITMAP(status, 5);
132#define ATH_STAT_INVALID 0 /* disable hardware accesses */ 132#define ATH_STAT_INVALID 0 /* disable hardware accesses */
133#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */ 133#define ATH_STAT_MRRETRY 1 /* multi-rate retry support */
134#define ATH_STAT_PROMISC 2 134#define ATH_STAT_PROMISC 2
135#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */ 135#define ATH_STAT_LEDSOFT 3 /* enable LED gpio status */
136#define ATH_STAT_STARTED 4 /* opened & irqs enabled */
136 137
137 unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */ 138 unsigned int filter_flags; /* HW flags, AR5K_RX_FILTER_* */
138 unsigned int curmode; /* current phy mode */ 139 unsigned int curmode; /* current phy mode */