aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2009-09-11 15:44:05 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-09-23 11:35:43 -0400
commita78b3bb2f3ab9afcf78dbcff18fd7bf900c7c27e (patch)
tree708cf458e4b2c97c26fad18aea8693599723212c
parent90c215c47675be42f164a4bac282666753e09225 (diff)
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: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/b43/b43.h19
-rw-r--r--drivers/net/wireless/b43/leds.c259
-rw-r--r--drivers/net/wireless/b43/leds.h28
-rw-r--r--drivers/net/wireless/b43/main.c100
4 files changed, 233 insertions, 173 deletions
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index 09cfe68537b6..89ccf0d50f33 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -629,13 +629,6 @@ struct b43_wl {
629 * from the mac80211 subsystem. */ 629 * from the mac80211 subsystem. */
630 u16 mac80211_initially_registered_queues; 630 u16 mac80211_initially_registered_queues;
631 631
632 /* R/W lock for data transmission.
633 * Transmissions on 2+ queues can run concurrently, but somebody else
634 * might sync with TX by write_lock_irqsave()'ing. */
635 rwlock_t tx_lock;
636 /* Lock for LEDs access. */
637 spinlock_t leds_lock;
638
639 /* We can only have one operating interface (802.11 core) 632 /* We can only have one operating interface (802.11 core)
640 * at a time. General information about this interface follows. 633 * at a time. General information about this interface follows.
641 */ 634 */
@@ -686,6 +679,9 @@ struct b43_wl {
686 struct work_struct tx_work; 679 struct work_struct tx_work;
687 /* Queue of packets to be transmitted. */ 680 /* Queue of packets to be transmitted. */
688 struct sk_buff_head tx_queue; 681 struct sk_buff_head tx_queue;
682
683 /* The device LEDs. */
684 struct b43_leds leds;
689}; 685};
690 686
691/* The type of the firmware file. */ 687/* The type of the firmware file. */
@@ -768,13 +764,10 @@ struct b43_wldev {
768 /* The device initialization status. 764 /* The device initialization status.
769 * Use b43_status() to query. */ 765 * Use b43_status() to query. */
770 atomic_t __init_status; 766 atomic_t __init_status;
771 /* Saved init status for handling suspend. */
772 int suspend_init_status;
773 767
774 bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ 768 bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */
775 bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ 769 bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */
776 bool radio_hw_enable; /* saved state of radio hardware enabled state */ 770 bool radio_hw_enable; /* saved state of radio hardware enabled state */
777 bool suspend_in_progress; /* TRUE, if we are in a suspend/resume cycle */
778 bool qos_enabled; /* TRUE, if QoS is used. */ 771 bool qos_enabled; /* TRUE, if QoS is used. */
779 bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */ 772 bool hwcrypto_enabled; /* TRUE, if HW crypto acceleration is enabled. */
780 773
@@ -794,12 +787,6 @@ struct b43_wldev {
794 /* Various statistics about the physical device. */ 787 /* Various statistics about the physical device. */
795 struct b43_stats stats; 788 struct b43_stats stats;
796 789
797 /* The device LEDs. */
798 struct b43_led led_tx;
799 struct b43_led led_rx;
800 struct b43_led led_assoc;
801 struct b43_led led_radio;
802
803 /* Reason code of the last interrupt. */ 790 /* Reason code of the last interrupt. */
804 u32 irq_reason; 791 u32 irq_reason;
805 u32 dma_reason[6]; 792 u32 dma_reason[6];
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c
index c8b317094c31..ac5a322c84b7 100644
--- a/drivers/net/wireless/b43/leds.c
+++ b/drivers/net/wireless/b43/leds.c
@@ -34,57 +34,91 @@
34static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, 34static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index,
35 bool activelow) 35 bool activelow)
36{ 36{
37 struct b43_wl *wl = dev->wl;
38 unsigned long flags;
39 u16 ctl; 37 u16 ctl;
40 38
41 spin_lock_irqsave(&wl->leds_lock, flags);
42 ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); 39 ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
43 if (activelow) 40 if (activelow)
44 ctl &= ~(1 << led_index); 41 ctl &= ~(1 << led_index);
45 else 42 else
46 ctl |= (1 << led_index); 43 ctl |= (1 << led_index);
47 b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); 44 b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
48 spin_unlock_irqrestore(&wl->leds_lock, flags);
49} 45}
50 46
51static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index, 47static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index,
52 bool activelow) 48 bool activelow)
53{ 49{
54 struct b43_wl *wl = dev->wl;
55 unsigned long flags;
56 u16 ctl; 50 u16 ctl;
57 51
58 spin_lock_irqsave(&wl->leds_lock, flags);
59 ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); 52 ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
60 if (activelow) 53 if (activelow)
61 ctl |= (1 << led_index); 54 ctl |= (1 << led_index);
62 else 55 else
63 ctl &= ~(1 << led_index); 56 ctl &= ~(1 << led_index);
64 b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); 57 b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
65 spin_unlock_irqrestore(&wl->leds_lock, flags);
66} 58}
67 59
68/* Callback from the LED subsystem. */ 60static void b43_led_update(struct b43_wldev *dev,
69static void b43_led_brightness_set(struct led_classdev *led_dev, 61 struct b43_led *led)
70 enum led_brightness brightness)
71{ 62{
72 struct b43_led *led = container_of(led_dev, struct b43_led, led_dev);
73 struct b43_wldev *dev = led->dev;
74 bool radio_enabled; 63 bool radio_enabled;
64 bool turn_on;
75 65
76 if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) 66 if (!led->wl)
77 return; 67 return;
78 68
79 /* Checking the radio-enabled status here is slightly racy,
80 * but we want to avoid the locking overhead and we don't care
81 * whether the LED has the wrong state for a second. */
82 radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable); 69 radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
83 70
84 if (brightness == LED_OFF || !radio_enabled) 71 /* The led->state read is racy, but we don't care. In case we raced
85 b43_led_turn_off(dev, led->index, led->activelow); 72 * with the brightness_set handler, we will be called again soon
73 * to fixup our state. */
74 if (radio_enabled)
75 turn_on = atomic_read(&led->state) != LED_OFF;
86 else 76 else
77 turn_on = 0;
78 if (turn_on == led->hw_state)
79 return;
80 led->hw_state = turn_on;
81
82 if (turn_on)
87 b43_led_turn_on(dev, led->index, led->activelow); 83 b43_led_turn_on(dev, led->index, led->activelow);
84 else
85 b43_led_turn_off(dev, led->index, led->activelow);
86}
87
88static void b43_leds_work(struct work_struct *work)
89{
90 struct b43_leds *leds = container_of(work, struct b43_leds, work);
91 struct b43_wl *wl = container_of(leds, struct b43_wl, leds);
92 struct b43_wldev *dev;
93
94 mutex_lock(&wl->mutex);
95 dev = wl->current_dev;
96 if (unlikely(!dev || b43_status(dev) < B43_STAT_STARTED))
97 goto out_unlock;
98
99 b43_led_update(dev, &wl->leds.led_tx);
100 b43_led_update(dev, &wl->leds.led_rx);
101 b43_led_update(dev, &wl->leds.led_radio);
102 b43_led_update(dev, &wl->leds.led_assoc);
103
104out_unlock:
105 mutex_unlock(&wl->mutex);
106}
107
108/* Callback from the LED subsystem. */
109static void b43_led_brightness_set(struct led_classdev *led_dev,
110 enum led_brightness brightness)
111{
112 struct b43_led *led = container_of(led_dev, struct b43_led, led_dev);
113 struct b43_wl *wl = led->wl;
114
115 /* The check for current_dev is only needed while unregistering,
116 * so it is sequencial and does not race. But we must not dereference
117 * current_dev here. */
118 if (likely(wl->current_dev)) {
119 atomic_set(&led->state, brightness);
120 ieee80211_queue_work(wl->hw, &wl->leds.work);
121 }
88} 122}
89 123
90static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, 124static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
@@ -93,15 +127,15 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
93{ 127{
94 int err; 128 int err;
95 129
96 b43_led_turn_off(dev, led_index, activelow); 130 if (led->wl)
97 if (led->dev)
98 return -EEXIST; 131 return -EEXIST;
99 if (!default_trigger) 132 if (!default_trigger)
100 return -EINVAL; 133 return -EINVAL;
101 led->dev = dev; 134 led->wl = dev->wl;
102 led->index = led_index; 135 led->index = led_index;
103 led->activelow = activelow; 136 led->activelow = activelow;
104 strncpy(led->name, name, sizeof(led->name)); 137 strncpy(led->name, name, sizeof(led->name));
138 atomic_set(&led->state, 0);
105 139
106 led->led_dev.name = led->name; 140 led->led_dev.name = led->name;
107 led->led_dev.default_trigger = default_trigger; 141 led->led_dev.default_trigger = default_trigger;
@@ -110,19 +144,19 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
110 err = led_classdev_register(dev->dev->dev, &led->led_dev); 144 err = led_classdev_register(dev->dev->dev, &led->led_dev);
111 if (err) { 145 if (err) {
112 b43warn(dev->wl, "LEDs: Failed to register %s\n", name); 146 b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
113 led->dev = NULL; 147 led->wl = NULL;
114 return err; 148 return err;
115 } 149 }
150
116 return 0; 151 return 0;
117} 152}
118 153
119static void b43_unregister_led(struct b43_led *led) 154static void b43_unregister_led(struct b43_led *led)
120{ 155{
121 if (!led->dev) 156 if (!led->wl)
122 return; 157 return;
123 led_classdev_unregister(&led->led_dev); 158 led_classdev_unregister(&led->led_dev);
124 b43_led_turn_off(led->dev, led->index, led->activelow); 159 led->wl = NULL;
125 led->dev = NULL;
126} 160}
127 161
128static void b43_map_led(struct b43_wldev *dev, 162static void b43_map_led(struct b43_wldev *dev,
@@ -137,24 +171,20 @@ static void b43_map_led(struct b43_wldev *dev,
137 * generic LED triggers. */ 171 * generic LED triggers. */
138 switch (behaviour) { 172 switch (behaviour) {
139 case B43_LED_INACTIVE: 173 case B43_LED_INACTIVE:
140 break;
141 case B43_LED_OFF: 174 case B43_LED_OFF:
142 b43_led_turn_off(dev, led_index, activelow);
143 break;
144 case B43_LED_ON: 175 case B43_LED_ON:
145 b43_led_turn_on(dev, led_index, activelow);
146 break; 176 break;
147 case B43_LED_ACTIVITY: 177 case B43_LED_ACTIVITY:
148 case B43_LED_TRANSFER: 178 case B43_LED_TRANSFER:
149 case B43_LED_APTRANSFER: 179 case B43_LED_APTRANSFER:
150 snprintf(name, sizeof(name), 180 snprintf(name, sizeof(name),
151 "b43-%s::tx", wiphy_name(hw->wiphy)); 181 "b43-%s::tx", wiphy_name(hw->wiphy));
152 b43_register_led(dev, &dev->led_tx, name, 182 b43_register_led(dev, &dev->wl->leds.led_tx, name,
153 ieee80211_get_tx_led_name(hw), 183 ieee80211_get_tx_led_name(hw),
154 led_index, activelow); 184 led_index, activelow);
155 snprintf(name, sizeof(name), 185 snprintf(name, sizeof(name),
156 "b43-%s::rx", wiphy_name(hw->wiphy)); 186 "b43-%s::rx", wiphy_name(hw->wiphy));
157 b43_register_led(dev, &dev->led_rx, name, 187 b43_register_led(dev, &dev->wl->leds.led_rx, name,
158 ieee80211_get_rx_led_name(hw), 188 ieee80211_get_rx_led_name(hw),
159 led_index, activelow); 189 led_index, activelow);
160 break; 190 break;
@@ -164,18 +194,15 @@ static void b43_map_led(struct b43_wldev *dev,
164 case B43_LED_MODE_BG: 194 case B43_LED_MODE_BG:
165 snprintf(name, sizeof(name), 195 snprintf(name, sizeof(name),
166 "b43-%s::radio", wiphy_name(hw->wiphy)); 196 "b43-%s::radio", wiphy_name(hw->wiphy));
167 b43_register_led(dev, &dev->led_radio, name, 197 b43_register_led(dev, &dev->wl->leds.led_radio, name,
168 ieee80211_get_radio_led_name(hw), 198 ieee80211_get_radio_led_name(hw),
169 led_index, activelow); 199 led_index, activelow);
170 /* Sync the RF-kill LED state with radio and switch states. */
171 if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev))
172 b43_led_turn_on(dev, led_index, activelow);
173 break; 200 break;
174 case B43_LED_WEIRD: 201 case B43_LED_WEIRD:
175 case B43_LED_ASSOC: 202 case B43_LED_ASSOC:
176 snprintf(name, sizeof(name), 203 snprintf(name, sizeof(name),
177 "b43-%s::assoc", wiphy_name(hw->wiphy)); 204 "b43-%s::assoc", wiphy_name(hw->wiphy));
178 b43_register_led(dev, &dev->led_assoc, name, 205 b43_register_led(dev, &dev->wl->leds.led_assoc, name,
179 ieee80211_get_assoc_led_name(hw), 206 ieee80211_get_assoc_led_name(hw),
180 led_index, activelow); 207 led_index, activelow);
181 break; 208 break;
@@ -186,58 +213,140 @@ static void b43_map_led(struct b43_wldev *dev,
186 } 213 }
187} 214}
188 215
189void b43_leds_init(struct b43_wldev *dev) 216static void b43_led_get_sprominfo(struct b43_wldev *dev,
217 unsigned int led_index,
218 enum b43_led_behaviour *behaviour,
219 bool *activelow)
190{ 220{
191 struct ssb_bus *bus = dev->dev->bus; 221 struct ssb_bus *bus = dev->dev->bus;
192 u8 sprom[4]; 222 u8 sprom[4];
193 int i;
194 enum b43_led_behaviour behaviour;
195 bool activelow;
196 223
197 sprom[0] = bus->sprom.gpio0; 224 sprom[0] = bus->sprom.gpio0;
198 sprom[1] = bus->sprom.gpio1; 225 sprom[1] = bus->sprom.gpio1;
199 sprom[2] = bus->sprom.gpio2; 226 sprom[2] = bus->sprom.gpio2;
200 sprom[3] = bus->sprom.gpio3; 227 sprom[3] = bus->sprom.gpio3;
201 228
202 for (i = 0; i < 4; i++) { 229 if (sprom[led_index] == 0xFF) {
203 if (sprom[i] == 0xFF) { 230 /* There is no LED information in the SPROM
204 /* There is no LED information in the SPROM 231 * for this LED. Hardcode it here. */
205 * for this LED. Hardcode it here. */ 232 *activelow = 0;
206 activelow = 0; 233 switch (led_index) {
207 switch (i) { 234 case 0:
208 case 0: 235 *behaviour = B43_LED_ACTIVITY;
209 behaviour = B43_LED_ACTIVITY; 236 *activelow = 1;
210 activelow = 1; 237 if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
211 if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) 238 *behaviour = B43_LED_RADIO_ALL;
212 behaviour = B43_LED_RADIO_ALL; 239 break;
213 break; 240 case 1:
214 case 1: 241 *behaviour = B43_LED_RADIO_B;
215 behaviour = B43_LED_RADIO_B; 242 if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
216 if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) 243 *behaviour = B43_LED_ASSOC;
217 behaviour = B43_LED_ASSOC; 244 break;
218 break; 245 case 2:
219 case 2: 246 *behaviour = B43_LED_RADIO_A;
220 behaviour = B43_LED_RADIO_A; 247 break;
221 break; 248 case 3:
222 case 3: 249 *behaviour = B43_LED_OFF;
223 behaviour = B43_LED_OFF; 250 break;
224 break; 251 default:
225 default: 252 B43_WARN_ON(1);
226 B43_WARN_ON(1); 253 return;
227 return; 254 }
228 } 255 } else {
256 *behaviour = sprom[led_index] & B43_LED_BEHAVIOUR;
257 *activelow = !!(sprom[led_index] & B43_LED_ACTIVELOW);
258 }
259}
260
261void b43_leds_init(struct b43_wldev *dev)
262{
263 struct b43_led *led;
264 unsigned int i;
265 enum b43_led_behaviour behaviour;
266 bool activelow;
267
268 /* Sync the RF-kill LED state (if we have one) with radio and switch states. */
269 led = &dev->wl->leds.led_radio;
270 if (led->wl) {
271 if (dev->phy.radio_on && b43_is_hw_radio_enabled(dev)) {
272 b43_led_turn_on(dev, led->index, led->activelow);
273 led->hw_state = 1;
274 atomic_set(&led->state, 1);
229 } else { 275 } else {
230 behaviour = sprom[i] & B43_LED_BEHAVIOUR; 276 b43_led_turn_off(dev, led->index, led->activelow);
231 activelow = !!(sprom[i] & B43_LED_ACTIVELOW); 277 led->hw_state = 0;
278 atomic_set(&led->state, 0);
279 }
280 }
281
282 /* Initialize TX/RX/ASSOC leds */
283 led = &dev->wl->leds.led_tx;
284 if (led->wl) {
285 b43_led_turn_off(dev, led->index, led->activelow);
286 led->hw_state = 0;
287 atomic_set(&led->state, 0);
288 }
289 led = &dev->wl->leds.led_rx;
290 if (led->wl) {
291 b43_led_turn_off(dev, led->index, led->activelow);
292 led->hw_state = 0;
293 atomic_set(&led->state, 0);
294 }
295 led = &dev->wl->leds.led_assoc;
296 if (led->wl) {
297 b43_led_turn_off(dev, led->index, led->activelow);
298 led->hw_state = 0;
299 atomic_set(&led->state, 0);
300 }
301
302 /* Initialize other LED states. */
303 for (i = 0; i < B43_MAX_NR_LEDS; i++) {
304 b43_led_get_sprominfo(dev, i, &behaviour, &activelow);
305 switch (behaviour) {
306 case B43_LED_OFF:
307 b43_led_turn_off(dev, i, activelow);
308 break;
309 case B43_LED_ON:
310 b43_led_turn_on(dev, i, activelow);
311 break;
312 default:
313 /* Leave others as-is. */
314 break;
232 } 315 }
233 b43_map_led(dev, i, behaviour, activelow);
234 } 316 }
235} 317}
236 318
237void b43_leds_exit(struct b43_wldev *dev) 319void b43_leds_exit(struct b43_wldev *dev)
238{ 320{
239 b43_unregister_led(&dev->led_tx); 321 struct b43_leds *leds = &dev->wl->leds;
240 b43_unregister_led(&dev->led_rx); 322
241 b43_unregister_led(&dev->led_assoc); 323 b43_led_turn_off(dev, leds->led_tx.index, leds->led_tx.activelow);
242 b43_unregister_led(&dev->led_radio); 324 b43_led_turn_off(dev, leds->led_rx.index, leds->led_rx.activelow);
325 b43_led_turn_off(dev, leds->led_assoc.index, leds->led_assoc.activelow);
326 b43_led_turn_off(dev, leds->led_radio.index, leds->led_radio.activelow);
327}
328
329void b43_leds_register(struct b43_wldev *dev)
330{
331 unsigned int i;
332 enum b43_led_behaviour behaviour;
333 bool activelow;
334
335 INIT_WORK(&dev->wl->leds.work, b43_leds_work);
336
337 /* Register the LEDs to the LED subsystem. */
338 for (i = 0; i < B43_MAX_NR_LEDS; i++) {
339 b43_led_get_sprominfo(dev, i, &behaviour, &activelow);
340 b43_map_led(dev, i, behaviour, activelow);
341 }
342}
343
344void b43_leds_unregister(struct b43_wldev *dev)
345{
346 struct b43_leds *leds = &dev->wl->leds;
347
348 b43_unregister_led(&leds->led_tx);
349 b43_unregister_led(&leds->led_rx);
350 b43_unregister_led(&leds->led_assoc);
351 b43_unregister_led(&leds->led_radio);
243} 352}
diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h
index b8b1dd521243..c4a58a0fc1d5 100644
--- a/drivers/net/wireless/b43/leds.h
+++ b/drivers/net/wireless/b43/leds.h
@@ -7,12 +7,13 @@ struct b43_wldev;
7 7
8#include <linux/types.h> 8#include <linux/types.h>
9#include <linux/leds.h> 9#include <linux/leds.h>
10#include <linux/workqueue.h>
10 11
11 12
12#define B43_LED_MAX_NAME_LEN 31 13#define B43_LED_MAX_NAME_LEN 31
13 14
14struct b43_led { 15struct b43_led {
15 struct b43_wldev *dev; 16 struct b43_wl *wl;
16 /* The LED class device */ 17 /* The LED class device */
17 struct led_classdev led_dev; 18 struct led_classdev led_dev;
18 /* The index number of the LED. */ 19 /* The index number of the LED. */
@@ -22,8 +23,23 @@ struct b43_led {
22 bool activelow; 23 bool activelow;
23 /* The unique name string for this LED device. */ 24 /* The unique name string for this LED device. */
24 char name[B43_LED_MAX_NAME_LEN + 1]; 25 char name[B43_LED_MAX_NAME_LEN + 1];
26 /* The current status of the LED. This is updated locklessly. */
27 atomic_t state;
28 /* The active state in hardware. */
29 bool hw_state;
25}; 30};
26 31
32struct b43_leds {
33 struct b43_led led_tx;
34 struct b43_led led_rx;
35 struct b43_led led_radio;
36 struct b43_led led_assoc;
37
38 struct work_struct work;
39};
40
41#define B43_MAX_NR_LEDS 4
42
27#define B43_LED_BEHAVIOUR 0x7F 43#define B43_LED_BEHAVIOUR 0x7F
28#define B43_LED_ACTIVELOW 0x80 44#define B43_LED_ACTIVELOW 0x80
29/* LED behaviour values */ 45/* LED behaviour values */
@@ -42,6 +58,8 @@ enum b43_led_behaviour {
42 B43_LED_INACTIVE, 58 B43_LED_INACTIVE,
43}; 59};
44 60
61void b43_leds_register(struct b43_wldev *dev);
62void b43_leds_unregister(struct b43_wldev *dev);
45void b43_leds_init(struct b43_wldev *dev); 63void b43_leds_init(struct b43_wldev *dev);
46void b43_leds_exit(struct b43_wldev *dev); 64void b43_leds_exit(struct b43_wldev *dev);
47 65
@@ -49,10 +67,16 @@ void b43_leds_exit(struct b43_wldev *dev);
49#else /* CONFIG_B43_LEDS */ 67#else /* CONFIG_B43_LEDS */
50/* LED support disabled */ 68/* LED support disabled */
51 69
52struct b43_led { 70struct b43_leds {
53 /* empty */ 71 /* empty */
54}; 72};
55 73
74static inline void b43_leds_register(struct b43_wldev *dev)
75{
76}
77static inline void b43_leds_unregister(struct b43_wldev *dev)
78{
79}
56static inline void b43_leds_init(struct b43_wldev *dev) 80static inline void b43_leds_init(struct b43_wldev *dev)
57{ 81{
58} 82}
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e789792a36bc..2984a915f8b1 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3002,14 +3002,18 @@ static void b43_security_init(struct b43_wldev *dev)
3002static int b43_rng_read(struct hwrng *rng, u32 *data) 3002static int b43_rng_read(struct hwrng *rng, u32 *data)
3003{ 3003{
3004 struct b43_wl *wl = (struct b43_wl *)rng->priv; 3004 struct b43_wl *wl = (struct b43_wl *)rng->priv;
3005 struct b43_wldev *dev;
3006 int count = -ENODEV;
3005 3007
3006 /* FIXME: We need to take wl->mutex here to make sure the device 3008 mutex_lock(&wl->mutex);
3007 * is not going away from under our ass. However it could deadlock 3009 dev = wl->current_dev;
3008 * with hwrng internal locking. */ 3010 if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) {
3009 3011 *data = b43_read16(dev, B43_MMIO_RNG);
3010 *data = b43_read16(wl->current_dev, B43_MMIO_RNG); 3012 count = sizeof(u16);
3013 }
3014 mutex_unlock(&wl->mutex);
3011 3015
3012 return (sizeof(u16)); 3016 return count;
3013} 3017}
3014#endif /* CONFIG_B43_HWRNG */ 3018#endif /* CONFIG_B43_HWRNG */
3015 3019
@@ -3851,6 +3855,7 @@ redo:
3851 3855
3852 b43_mac_suspend(dev); 3856 b43_mac_suspend(dev);
3853 free_irq(dev->dev->irq, dev); 3857 free_irq(dev->dev->irq, dev);
3858 b43_leds_exit(dev);
3854 b43dbg(wl, "Wireless interface stopped\n"); 3859 b43dbg(wl, "Wireless interface stopped\n");
3855 3860
3856 return dev; 3861 return dev;
@@ -3882,8 +3887,10 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
3882 /* Start maintainance work */ 3887 /* Start maintainance work */
3883 b43_periodic_tasks_setup(dev); 3888 b43_periodic_tasks_setup(dev);
3884 3889
3890 b43_leds_init(dev);
3891
3885 b43dbg(dev->wl, "Wireless interface started\n"); 3892 b43dbg(dev->wl, "Wireless interface started\n");
3886 out: 3893out:
3887 return err; 3894 return err;
3888} 3895}
3889 3896
@@ -4160,10 +4167,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
4160 macctl |= B43_MACCTL_PSM_JMP0; 4167 macctl |= B43_MACCTL_PSM_JMP0;
4161 b43_write32(dev, B43_MMIO_MACCTL, macctl); 4168 b43_write32(dev, B43_MMIO_MACCTL, macctl);
4162 4169
4163 if (!dev->suspend_in_progress) {
4164 b43_leds_exit(dev);
4165 b43_rng_exit(dev->wl);
4166 }
4167 b43_dma_free(dev); 4170 b43_dma_free(dev);
4168 b43_pio_free(dev); 4171 b43_pio_free(dev);
4169 b43_chip_exit(dev); 4172 b43_chip_exit(dev);
@@ -4180,7 +4183,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
4180/* Initialize a wireless core */ 4183/* Initialize a wireless core */
4181static int b43_wireless_core_init(struct b43_wldev *dev) 4184static int b43_wireless_core_init(struct b43_wldev *dev)
4182{ 4185{
4183 struct b43_wl *wl = dev->wl;
4184 struct ssb_bus *bus = dev->dev->bus; 4186 struct ssb_bus *bus = dev->dev->bus;
4185 struct ssb_sprom *sprom = &bus->sprom; 4187 struct ssb_sprom *sprom = &bus->sprom;
4186 struct b43_phy *phy = &dev->phy; 4188 struct b43_phy *phy = &dev->phy;
@@ -4280,15 +4282,11 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
4280 ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)); 4282 ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
4281 b43_upload_card_macaddress(dev); 4283 b43_upload_card_macaddress(dev);
4282 b43_security_init(dev); 4284 b43_security_init(dev);
4283 if (!dev->suspend_in_progress)
4284 b43_rng_init(wl);
4285 4285
4286 ieee80211_wake_queues(dev->wl->hw); 4286 ieee80211_wake_queues(dev->wl->hw);
4287 4287
4288 b43_set_status(dev, B43_STAT_INITIALIZED); 4288 b43_set_status(dev, B43_STAT_INITIALIZED);
4289 4289
4290 if (!dev->suspend_in_progress)
4291 b43_leds_init(dev);
4292out: 4290out:
4293 return err; 4291 return err;
4294 4292
@@ -4837,7 +4835,6 @@ static int b43_wireless_init(struct ssb_device *dev)
4837 4835
4838 /* Initialize struct b43_wl */ 4836 /* Initialize struct b43_wl */
4839 wl->hw = hw; 4837 wl->hw = hw;
4840 spin_lock_init(&wl->leds_lock);
4841 mutex_init(&wl->mutex); 4838 mutex_init(&wl->mutex);
4842 spin_lock_init(&wl->hardirq_lock); 4839 spin_lock_init(&wl->hardirq_lock);
4843 INIT_LIST_HEAD(&wl->devlist); 4840 INIT_LIST_HEAD(&wl->devlist);
@@ -4878,6 +4875,8 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
4878 err = ieee80211_register_hw(wl->hw); 4875 err = ieee80211_register_hw(wl->hw);
4879 if (err) 4876 if (err)
4880 goto err_one_core_detach; 4877 goto err_one_core_detach;
4878 b43_leds_register(wl->current_dev);
4879 b43_rng_init(wl);
4881 } 4880 }
4882 4881
4883 out: 4882 out:
@@ -4906,12 +4905,16 @@ static void b43_remove(struct ssb_device *dev)
4906 * might have modified it. Restoring is important, so the networking 4905 * might have modified it. Restoring is important, so the networking
4907 * stack can properly free resources. */ 4906 * stack can properly free resources. */
4908 wl->hw->queues = wl->mac80211_initially_registered_queues; 4907 wl->hw->queues = wl->mac80211_initially_registered_queues;
4908 wl->current_dev = NULL;
4909 cancel_work_sync(&wl->leds.work);
4909 ieee80211_unregister_hw(wl->hw); 4910 ieee80211_unregister_hw(wl->hw);
4910 } 4911 }
4911 4912
4912 b43_one_core_detach(dev); 4913 b43_one_core_detach(dev);
4913 4914
4914 if (list_empty(&wl->devlist)) { 4915 if (list_empty(&wl->devlist)) {
4916 b43_rng_exit(wl);
4917 b43_leds_unregister(wldev);
4915 /* Last core on the chip unregistered. 4918 /* Last core on the chip unregistered.
4916 * We can destroy common struct b43_wl. 4919 * We can destroy common struct b43_wl.
4917 */ 4920 */
@@ -4929,74 +4932,11 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
4929 ieee80211_queue_work(dev->wl->hw, &dev->restart_work); 4932 ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
4930} 4933}
4931 4934
4932#ifdef CONFIG_PM
4933
4934static int b43_suspend(struct ssb_device *dev, pm_message_t state)
4935{
4936 struct b43_wldev *wldev = ssb_get_drvdata(dev);
4937 struct b43_wl *wl = wldev->wl;
4938
4939 b43dbg(wl, "Suspending...\n");
4940
4941 mutex_lock(&wl->mutex);
4942 wldev->suspend_in_progress = true;
4943 wldev->suspend_init_status = b43_status(wldev);
4944 if (wldev->suspend_init_status >= B43_STAT_STARTED)
4945 wldev = b43_wireless_core_stop(wldev);
4946 if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED)
4947 b43_wireless_core_exit(wldev);
4948 mutex_unlock(&wl->mutex);
4949
4950 b43dbg(wl, "Device suspended.\n");
4951
4952 return 0;
4953}
4954
4955static int b43_resume(struct ssb_device *dev)
4956{
4957 struct b43_wldev *wldev = ssb_get_drvdata(dev);
4958 struct b43_wl *wl = wldev->wl;
4959 int err = 0;
4960
4961 b43dbg(wl, "Resuming...\n");
4962
4963 mutex_lock(&wl->mutex);
4964 if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
4965 err = b43_wireless_core_init(wldev);
4966 if (err) {
4967 b43err(wl, "Resume failed at core init\n");
4968 goto out;
4969 }
4970 }
4971 if (wldev->suspend_init_status >= B43_STAT_STARTED) {
4972 err = b43_wireless_core_start(wldev);
4973 if (err) {
4974 b43_leds_exit(wldev);
4975 b43_rng_exit(wldev->wl);
4976 b43_wireless_core_exit(wldev);
4977 b43err(wl, "Resume failed at core start\n");
4978 goto out;
4979 }
4980 }
4981 b43dbg(wl, "Device resumed.\n");
4982 out:
4983 wldev->suspend_in_progress = false;
4984 mutex_unlock(&wl->mutex);
4985 return err;
4986}
4987
4988#else /* CONFIG_PM */
4989# define b43_suspend NULL
4990# define b43_resume NULL
4991#endif /* CONFIG_PM */
4992
4993static struct ssb_driver b43_ssb_driver = { 4935static struct ssb_driver b43_ssb_driver = {
4994 .name = KBUILD_MODNAME, 4936 .name = KBUILD_MODNAME,
4995 .id_table = b43_ssb_tbl, 4937 .id_table = b43_ssb_tbl,
4996 .probe = b43_probe, 4938 .probe = b43_probe,
4997 .remove = b43_remove, 4939 .remove = b43_remove,
4998 .suspend = b43_suspend,
4999 .resume = b43_resume,
5000}; 4940};
5001 4941
5002static void b43_print_driverinfo(void) 4942static void b43_print_driverinfo(void)