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 {
* from the mac80211 subsystem. */
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)
* at a time. General information about this interface follows.
*/
......@@ -686,6 +679,9 @@ struct b43_wl {
struct work_struct tx_work;
/* Queue of packets to be transmitted. */
struct sk_buff_head tx_queue;
/* The device LEDs. */
struct b43_leds leds;
};
/* The type of the firmware file. */
......@@ -768,13 +764,10 @@ struct b43_wldev {
/* The device initialization status.
* Use b43_status() to query. */
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 dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */
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 hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */
......@@ -794,12 +787,6 @@ struct b43_wldev {
/* Various statistics about the physical device. */
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. */
u32 irq_reason;
u32 dma_reason[6];
......
This diff is collapsed.
......@@ -7,12 +7,13 @@ struct b43_wldev;
#include <linux/types.h>
#include <linux/leds.h>
#include <linux/workqueue.h>
#define B43_LED_MAX_NAME_LEN 31
struct b43_led {
struct b43_wldev *dev;
struct b43_wl *wl;
/* The LED class device */
struct led_classdev led_dev;
/* The index number of the LED. */
......@@ -22,8 +23,23 @@ struct b43_led {
bool activelow;
/* The unique name string for this LED device. */
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_ACTIVELOW 0x80
/* LED behaviour values */
......@@ -42,6 +58,8 @@ enum b43_led_behaviour {
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_exit(struct b43_wldev *dev);
......@@ -49,10 +67,16 @@ void b43_leds_exit(struct b43_wldev *dev);
#else /* CONFIG_B43_LEDS */
/* LED support disabled */
struct b43_led {
struct b43_leds {
/* 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)
{
}
......
......@@ -3002,14 +3002,18 @@ static void b43_security_init(struct b43_wldev *dev)
static int b43_rng_read(struct hwrng *rng, u32 *data)
{
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
* is not going away from under our ass. However it could deadlock
* with hwrng internal locking. */
*data = b43_read16(wl->current_dev, B43_MMIO_RNG);
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) {
*data = b43_read16(dev, B43_MMIO_RNG);
count = sizeof(u16);
}
mutex_unlock(&wl->mutex);
return (sizeof(u16));
return count;
}
#endif /* CONFIG_B43_HWRNG */
......@@ -3851,6 +3855,7 @@ redo:
b43_mac_suspend(dev);
free_irq(dev->dev->irq, dev);
b43_leds_exit(dev);
b43dbg(wl, "Wireless interface stopped\n");
return dev;
......@@ -3882,8 +3887,10 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
/* Start maintainance work */
b43_periodic_tasks_setup(dev);
b43_leds_init(dev);
b43dbg(dev->wl, "Wireless interface started\n");
out:
out:
return err;
}
......@@ -4160,10 +4167,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
macctl |= B43_MACCTL_PSM_JMP0;
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_pio_free(dev);
b43_chip_exit(dev);
......@@ -4180,7 +4183,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
/* Initialize a wireless core */
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_sprom *sprom = &bus->sprom;
struct b43_phy *phy = &dev->phy;
......@@ -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));
b43_upload_card_macaddress(dev);
b43_security_init(dev);
if (!dev->suspend_in_progress)
b43_rng_init(wl);
ieee80211_wake_queues(dev->wl->hw);
b43_set_status(dev, B43_STAT_INITIALIZED);
if (!dev->suspend_in_progress)
b43_leds_init(dev);
out:
return err;
......@@ -4837,7 +4835,6 @@ static int b43_wireless_init(struct ssb_device *dev)
/* Initialize struct b43_wl */
wl->hw = hw;
spin_lock_init(&wl->leds_lock);
mutex_init(&wl->mutex);
spin_lock_init(&wl->hardirq_lock);
INIT_LIST_HEAD(&wl->devlist);
......@@ -4878,6 +4875,8 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
err = ieee80211_register_hw(wl->hw);
if (err)
goto err_one_core_detach;
b43_leds_register(wl->current_dev);
b43_rng_init(wl);
}
out:
......@@ -4906,12 +4905,16 @@ static void b43_remove(struct ssb_device *dev)
* might have modified it. Restoring is important, so the networking
* stack can properly free resources. */
wl->hw->queues = wl->mac80211_initially_registered_queues;
wl->current_dev = NULL;
cancel_work_sync(&wl->leds.work);
ieee80211_unregister_hw(wl->hw);
}
b43_one_core_detach(dev);
if (list_empty(&wl->devlist)) {
b43_rng_exit(wl);
b43_leds_unregister(wldev);
/* Last core on the chip unregistered.
* We can destroy common struct b43_wl.
*/
......@@ -4929,74 +4932,11 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
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 = {
.name = KBUILD_MODNAME,
.id_table = b43_ssb_tbl,
.probe = b43_probe,
.remove = b43_remove,
.suspend = b43_suspend,
.resume = b43_resume,
};
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