Commit a78b3bb2 authored by Michael Buesch's avatar Michael Buesch Committed by John W. Linville

b43: Rewrite suspend/resume code

This removes most of the b43 suspend/resume code (it's handled by mac80211)
and moves the registration of devices to the attachment phase. This is
required, because we must not register/unregister devices on suspend/resume.
Signed-off-by: default avatarMichael Buesch <mb@bu3sch.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 90c215c4
...@@ -629,13 +629,6 @@ struct b43_wl { ...@@ -629,13 +629,6 @@ struct b43_wl {
* from the mac80211 subsystem. */ * from the mac80211 subsystem. */
u16 mac80211_initially_registered_queues; u16 mac80211_initially_registered_queues;
/* R/W lock for data transmission.
* Transmissions on 2+ queues can run concurrently, but somebody else
* might sync with TX by write_lock_irqsave()'ing. */
rwlock_t tx_lock;
/* Lock for LEDs access. */
spinlock_t leds_lock;
/* We can only have one operating interface (802.11 core) /* We can only have one operating interface (802.11 core)
* at a time. General information about this interface follows. * at a time. General information about this interface follows.
*/ */
...@@ -686,6 +679,9 @@ struct b43_wl { ...@@ -686,6 +679,9 @@ struct b43_wl {
struct work_struct tx_work; struct work_struct tx_work;
/* Queue of packets to be transmitted. */ /* Queue of packets to be transmitted. */
struct sk_buff_head tx_queue; struct sk_buff_head tx_queue;
/* The device LEDs. */
struct b43_leds leds;
}; };
/* The type of the firmware file. */ /* The type of the firmware file. */
...@@ -768,13 +764,10 @@ struct b43_wldev { ...@@ -768,13 +764,10 @@ struct b43_wldev {
/* The device initialization status. /* The device initialization status.
* Use b43_status() to query. */ * Use b43_status() to query. */
atomic_t __init_status; atomic_t __init_status;
/* Saved init status for handling suspend. */
int suspend_init_status;
bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */
bool radio_hw_enable; /* saved state of radio hardware enabled state */ bool radio_hw_enable; /* saved state of radio hardware enabled state */
bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */
bool qos_enabled; /* TRUE, if QoS is used. */ bool qos_enabled; /* TRUE, if QoS is used. */
bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */
...@@ -794,12 +787,6 @@ struct b43_wldev { ...@@ -794,12 +787,6 @@ struct b43_wldev {
/* Various statistics about the physical device. */ /* Various statistics about the physical device. */
struct b43_stats stats; struct b43_stats stats;
/* The device LEDs. */
struct b43_led led_tx;
struct b43_led led_rx;
struct b43_led led_assoc;
struct b43_led led_radio;
/* Reason code of the last interrupt. */ /* Reason code of the last interrupt. */
u32 irq_reason; u32 irq_reason;
u32 dma_reason[6]; u32 dma_reason[6];
......
This diff is collapsed.
...@@ -7,12 +7,13 @@ struct b43_wldev; ...@@ -7,12 +7,13 @@ struct b43_wldev;
#include <linux/types.h> #include <linux/types.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/workqueue.h>
#define B43_LED_MAX_NAME_LEN 31 #define B43_LED_MAX_NAME_LEN 31
struct b43_led { struct b43_led {
struct b43_wldev *dev; struct b43_wl *wl;
/* The LED class device */ /* The LED class device */
struct led_classdev led_dev; struct led_classdev led_dev;
/* The index number of the LED. */ /* The index number of the LED. */
...@@ -22,8 +23,23 @@ struct b43_led { ...@@ -22,8 +23,23 @@ struct b43_led {
bool activelow; bool activelow;
/* The unique name string for this LED device. */ /* The unique name string for this LED device. */
char name[B43_LED_MAX_NAME_LEN + 1]; char name[B43_LED_MAX_NAME_LEN + 1];
/* The current status of the LED. This is updated locklessly. */
atomic_t state;
/* The active state in hardware. */
bool hw_state;
}; };
struct b43_leds {
struct b43_led led_tx;
struct b43_led led_rx;
struct b43_led led_radio;
struct b43_led led_assoc;
struct work_struct work;
};
#define B43_MAX_NR_LEDS 4
#define B43_LED_BEHAVIOUR 0x7F #define B43_LED_BEHAVIOUR 0x7F
#define B43_LED_ACTIVELOW 0x80 #define B43_LED_ACTIVELOW 0x80
/* LED behaviour values */ /* LED behaviour values */
...@@ -42,6 +58,8 @@ enum b43_led_behaviour { ...@@ -42,6 +58,8 @@ enum b43_led_behaviour {
B43_LED_INACTIVE, B43_LED_INACTIVE,
}; };
void b43_leds_register(struct b43_wldev *dev);
void b43_leds_unregister(struct b43_wldev *dev);
void b43_leds_init(struct b43_wldev *dev); void b43_leds_init(struct b43_wldev *dev);
void b43_leds_exit(struct b43_wldev *dev); void b43_leds_exit(struct b43_wldev *dev);
...@@ -49,10 +67,16 @@ void b43_leds_exit(struct b43_wldev *dev); ...@@ -49,10 +67,16 @@ void b43_leds_exit(struct b43_wldev *dev);
#else /* CONFIG_B43_LEDS */ #else /* CONFIG_B43_LEDS */
/* LED support disabled */ /* LED support disabled */
struct b43_led { struct b43_leds {
/* empty */ /* empty */
}; };
static inline void b43_leds_register(struct b43_wldev *dev)
{
}
static inline void b43_leds_unregister(struct b43_wldev *dev)
{
}
static inline void b43_leds_init(struct b43_wldev *dev) static inline void b43_leds_init(struct b43_wldev *dev)
{ {
} }
......
...@@ -3002,14 +3002,18 @@ static void b43_security_init(struct b43_wldev *dev) ...@@ -3002,14 +3002,18 @@ static void b43_security_init(struct b43_wldev *dev)
static int b43_rng_read(struct hwrng *rng, u32 *data) static int b43_rng_read(struct hwrng *rng, u32 *data)
{ {
struct b43_wl *wl = (struct b43_wl *)rng->priv; struct b43_wl *wl = (struct b43_wl *)rng->priv;
struct b43_wldev *dev;
int count = -ENODEV;
/* FIXME: We need to take wl->mutex here to make sure the device mutex_lock(&wl->mutex);
* is not going away from under our ass. However it could deadlock dev = wl->current_dev;
* with hwrng internal locking. */ if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) {
*data = b43_read16(dev, B43_MMIO_RNG);
*data = b43_read16(wl->current_dev, B43_MMIO_RNG); count = sizeof(u16);
}
mutex_unlock(&wl->mutex);
return (sizeof(u16)); return count;
} }
#endif /* CONFIG_B43_HWRNG */ #endif /* CONFIG_B43_HWRNG */
...@@ -3851,6 +3855,7 @@ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev) ...@@ -3851,6 +3855,7 @@ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
b43_mac_suspend(dev); b43_mac_suspend(dev);
free_irq(dev->dev->irq, dev); free_irq(dev->dev->irq, dev);
b43_leds_exit(dev);
b43dbg(wl, "Wireless interface stopped\n"); b43dbg(wl, "Wireless interface stopped\n");
return dev; return dev;
...@@ -3882,8 +3887,10 @@ static int b43_wireless_core_start(struct b43_wldev *dev) ...@@ -3882,8 +3887,10 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
/* Start maintainance work */ /* Start maintainance work */
b43_periodic_tasks_setup(dev); b43_periodic_tasks_setup(dev);
b43_leds_init(dev);
b43dbg(dev->wl, "Wireless interface started\n"); b43dbg(dev->wl, "Wireless interface started\n");
out: out:
return err; return err;
} }
...@@ -4160,10 +4167,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) ...@@ -4160,10 +4167,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
macctl |= B43_MACCTL_PSM_JMP0; macctl |= B43_MACCTL_PSM_JMP0;
b43_write32(dev, B43_MMIO_MACCTL, macctl); b43_write32(dev, B43_MMIO_MACCTL, macctl);
if (!dev->suspend_in_progress) {
b43_leds_exit(dev);
b43_rng_exit(dev->wl);
}
b43_dma_free(dev); b43_dma_free(dev);
b43_pio_free(dev); b43_pio_free(dev);
b43_chip_exit(dev); b43_chip_exit(dev);
...@@ -4180,7 +4183,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev) ...@@ -4180,7 +4183,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
/* Initialize a wireless core */ /* Initialize a wireless core */
static int b43_wireless_core_init(struct b43_wldev *dev) static int b43_wireless_core_init(struct b43_wldev *dev)
{ {
struct b43_wl *wl = dev->wl;
struct ssb_bus *bus = dev->dev->bus; struct ssb_bus *bus = dev->dev->bus;
struct ssb_sprom *sprom = &bus->sprom; struct ssb_sprom *sprom = &bus->sprom;
struct b43_phy *phy = &dev->phy; struct b43_phy *phy = &dev->phy;
...@@ -4280,15 +4282,11 @@ static int b43_wireless_core_init(struct b43_wldev *dev) ...@@ -4280,15 +4282,11 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)); ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
b43_upload_card_macaddress(dev); b43_upload_card_macaddress(dev);
b43_security_init(dev); b43_security_init(dev);
if (!dev->suspend_in_progress)
b43_rng_init(wl);
ieee80211_wake_queues(dev->wl->hw); ieee80211_wake_queues(dev->wl->hw);
b43_set_status(dev, B43_STAT_INITIALIZED); b43_set_status(dev, B43_STAT_INITIALIZED);
if (!dev->suspend_in_progress)
b43_leds_init(dev);
out: out:
return err; return err;
...@@ -4837,7 +4835,6 @@ static int b43_wireless_init(struct ssb_device *dev) ...@@ -4837,7 +4835,6 @@ static int b43_wireless_init(struct ssb_device *dev)
/* Initialize struct b43_wl */ /* Initialize struct b43_wl */
wl->hw = hw; wl->hw = hw;
spin_lock_init(&wl->leds_lock);
mutex_init(&wl->mutex); mutex_init(&wl->mutex);
spin_lock_init(&wl->hardirq_lock); spin_lock_init(&wl->hardirq_lock);
INIT_LIST_HEAD(&wl->devlist); INIT_LIST_HEAD(&wl->devlist);
...@@ -4878,6 +4875,8 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id) ...@@ -4878,6 +4875,8 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
err = ieee80211_register_hw(wl->hw); err = ieee80211_register_hw(wl->hw);
if (err) if (err)
goto err_one_core_detach; goto err_one_core_detach;
b43_leds_register(wl->current_dev);
b43_rng_init(wl);
} }
out: out:
...@@ -4906,12 +4905,16 @@ static void b43_remove(struct ssb_device *dev) ...@@ -4906,12 +4905,16 @@ static void b43_remove(struct ssb_device *dev)
* might have modified it. Restoring is important, so the networking * might have modified it. Restoring is important, so the networking
* stack can properly free resources. */ * stack can properly free resources. */
wl->hw->queues = wl->mac80211_initially_registered_queues; wl->hw->queues = wl->mac80211_initially_registered_queues;
wl->current_dev = NULL;
cancel_work_sync(&wl->leds.work);
ieee80211_unregister_hw(wl->hw); ieee80211_unregister_hw(wl->hw);
} }
b43_one_core_detach(dev); b43_one_core_detach(dev);
if (list_empty(&wl->devlist)) { if (list_empty(&wl->devlist)) {
b43_rng_exit(wl);
b43_leds_unregister(wldev);
/* Last core on the chip unregistered. /* Last core on the chip unregistered.
* We can destroy common struct b43_wl. * We can destroy common struct b43_wl.
*/ */
...@@ -4929,74 +4932,11 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason) ...@@ -4929,74 +4932,11 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
ieee80211_queue_work(dev->wl->hw, &dev->restart_work); ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
} }
#ifdef CONFIG_PM
static int b43_suspend(struct ssb_device *dev, pm_message_t state)
{
struct b43_wldev *wldev = ssb_get_drvdata(dev);
struct b43_wl *wl = wldev->wl;
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)
wldev = b43_wireless_core_stop(wldev);
if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED)
b43_wireless_core_exit(wldev);
mutex_unlock(&wl->mutex);
b43dbg(wl, "Device suspended.\n");
return 0;
}
static int b43_resume(struct ssb_device *dev)
{
struct b43_wldev *wldev = ssb_get_drvdata(dev);
struct b43_wl *wl = wldev->wl;
int err = 0;
b43dbg(wl, "Resuming...\n");
mutex_lock(&wl->mutex);
if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
err = b43_wireless_core_init(wldev);
if (err) {
b43err(wl, "Resume failed at core init\n");
goto out;
}
}
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);
b43_wireless_core_exit(wldev);
b43err(wl, "Resume failed at core start\n");
goto out;
}
}
b43dbg(wl, "Device resumed.\n");
out:
wldev->suspend_in_progress = false;
mutex_unlock(&wl->mutex);
return err;
}
#else /* CONFIG_PM */
# define b43_suspend NULL
# define b43_resume NULL
#endif /* CONFIG_PM */
static struct ssb_driver b43_ssb_driver = { static struct ssb_driver b43_ssb_driver = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.id_table = b43_ssb_tbl, .id_table = b43_ssb_tbl,
.probe = b43_probe, .probe = b43_probe,
.remove = b43_remove, .remove = b43_remove,
.suspend = b43_suspend,
.resume = b43_resume,
}; };
static void b43_print_driverinfo(void) static void b43_print_driverinfo(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment