]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/b43/main.c
b43: avoid unregistering device objects during suspend
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / b43 / main.c
index 88d2c15d3fbeccc5332cf55e3582a71e5174e3ef..ef65c41af00fc022e4841baa843571f1ae107fda 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/wireless.h>
 #include <linux/workqueue.h>
 #include <linux/skbuff.h>
+#include <linux/io.h>
 #include <linux/dma-mapping.h>
 #include <asm/unaligned.h>
 
@@ -2554,10 +2555,10 @@ static int b43_rng_read(struct hwrng *rng, u32 * data)
        return (sizeof(u16));
 }
 
-static void b43_rng_exit(struct b43_wl *wl)
+static void b43_rng_exit(struct b43_wl *wl, bool suspended)
 {
        if (wl->rng_initialized)
-               hwrng_unregister(&wl->rng);
+               __hwrng_unregister(&wl->rng, suspended);
 }
 
 static int b43_rng_init(struct b43_wl *wl)
@@ -3417,8 +3418,10 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
        macctl |= B43_MACCTL_PSM_JMP0;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
-       b43_leds_exit(dev);
-       b43_rng_exit(dev->wl);
+       if (!dev->suspend_in_progress) {
+               b43_leds_exit(dev);
+               b43_rng_exit(dev->wl, false);
+       }
        b43_dma_free(dev);
        b43_chip_exit(dev);
        b43_radio_turn_off(dev, 1);
@@ -3532,15 +3535,15 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        b43_bluetooth_coext_enable(dev);
 
        ssb_bus_powerup(bus, 1);        /* Enable dynamic PCTL */
-       memset(wl->bssid, 0, ETH_ALEN);
-       memset(wl->mac_addr, 0, ETH_ALEN);
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
-       b43_rng_init(wl);
+       if (!dev->suspend_in_progress)
+               b43_rng_init(wl);
 
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
-       b43_leds_init(dev);
+       if (!dev->suspend_in_progress)
+               b43_leds_init(dev);
 out:
        return err;
 
@@ -3630,6 +3633,15 @@ static int b43_op_start(struct ieee80211_hw *hw)
        struct b43_wldev *dev = wl->current_dev;
        int did_init = 0;
        int err = 0;
+       bool do_rfkill_exit = 0;
+
+       /* Kill all old instance specific information to make sure
+        * the card won't use it in the short timeframe between start
+        * and mac80211 reconfiguring it. */
+       memset(wl->bssid, 0, ETH_ALEN);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       wl->filter_flags = 0;
+       wl->radiotap_enabled = 0;
 
        /* First register RFkill.
         * LEDs that are registered later depend on it. */
@@ -3639,8 +3651,10 @@ static int b43_op_start(struct ieee80211_hw *hw)
 
        if (b43_status(dev) < B43_STAT_INITIALIZED) {
                err = b43_wireless_core_init(dev);
-               if (err)
+               if (err) {
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
+               }
                did_init = 1;
        }
 
@@ -3649,6 +3663,7 @@ static int b43_op_start(struct ieee80211_hw *hw)
                if (err) {
                        if (did_init)
                                b43_wireless_core_exit(dev);
+                       do_rfkill_exit = 1;
                        goto out_mutex_unlock;
                }
        }
@@ -3656,6 +3671,9 @@ static int b43_op_start(struct ieee80211_hw *hw)
  out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
+       if (do_rfkill_exit)
+               b43_rfkill_exit(dev);
+
        return err;
 }
 
@@ -4122,6 +4140,7 @@ static int b43_suspend(struct ssb_device *dev, pm_message_t state)
        b43dbg(wl, "Suspending...\n");
 
        mutex_lock(&wl->mutex);
+       wldev->suspend_in_progress = true;
        wldev->suspend_init_status = b43_status(wldev);
        if (wldev->suspend_init_status >= B43_STAT_STARTED)
                b43_wireless_core_stop(wldev);
@@ -4153,15 +4172,17 @@ static int b43_resume(struct ssb_device *dev)
        if (wldev->suspend_init_status >= B43_STAT_STARTED) {
                err = b43_wireless_core_start(wldev);
                if (err) {
+                       b43_leds_exit(wldev);
+                       b43_rng_exit(wldev->wl, true);
                        b43_wireless_core_exit(wldev);
                        b43err(wl, "Resume failed at core start\n");
                        goto out;
                }
        }
-       mutex_unlock(&wl->mutex);
-
        b43dbg(wl, "Device resumed.\n");
-      out:
+ out:
+       wldev->suspend_in_progress = false;
+       mutex_unlock(&wl->mutex);
        return err;
 }