diff options
author | Michael Buesch <mb@bu3sch.de> | 2009-09-11 15:44:05 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-09-23 11:35:43 -0400 |
commit | a78b3bb2f3ab9afcf78dbcff18fd7bf900c7c27e (patch) | |
tree | 708cf458e4b2c97c26fad18aea8693599723212c | |
parent | 90c215c47675be42f164a4bac282666753e09225 (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.h | 19 | ||||
-rw-r--r-- | drivers/net/wireless/b43/leds.c | 259 | ||||
-rw-r--r-- | drivers/net/wireless/b43/leds.h | 28 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 100 |
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 @@ | |||
34 | static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, | 34 | static 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 | ||
51 | static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index, | 47 | static 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. */ | 60 | static void b43_led_update(struct b43_wldev *dev, |
69 | static 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 | |||
88 | static 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 | |||
104 | out_unlock: | ||
105 | mutex_unlock(&wl->mutex); | ||
106 | } | ||
107 | |||
108 | /* Callback from the LED subsystem. */ | ||
109 | static 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 | ||
90 | static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, | 124 | static 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 | ||
119 | static void b43_unregister_led(struct b43_led *led) | 154 | static 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 | ||
128 | static void b43_map_led(struct b43_wldev *dev, | 162 | static 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 | ||
189 | void b43_leds_init(struct b43_wldev *dev) | 216 | static 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 | |||
261 | void 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 | ||
237 | void b43_leds_exit(struct b43_wldev *dev) | 319 | void 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 | |||
329 | void 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 | |||
344 | void 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 | ||
14 | struct b43_led { | 15 | struct 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 | ||
32 | struct 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 | ||
61 | void b43_leds_register(struct b43_wldev *dev); | ||
62 | void b43_leds_unregister(struct b43_wldev *dev); | ||
45 | void b43_leds_init(struct b43_wldev *dev); | 63 | void b43_leds_init(struct b43_wldev *dev); |
46 | void b43_leds_exit(struct b43_wldev *dev); | 64 | void 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 | ||
52 | struct b43_led { | 70 | struct b43_leds { |
53 | /* empty */ | 71 | /* empty */ |
54 | }; | 72 | }; |
55 | 73 | ||
74 | static inline void b43_leds_register(struct b43_wldev *dev) | ||
75 | { | ||
76 | } | ||
77 | static inline void b43_leds_unregister(struct b43_wldev *dev) | ||
78 | { | ||
79 | } | ||
56 | static inline void b43_leds_init(struct b43_wldev *dev) | 80 | static 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) | |||
3002 | static int b43_rng_read(struct hwrng *rng, u32 *data) | 3002 | static 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: | 3893 | out: |
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 */ |
4181 | static int b43_wireless_core_init(struct b43_wldev *dev) | 4184 | static 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); | ||
4292 | out: | 4290 | out: |
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 | |||
4934 | static 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 | |||
4955 | static 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 | |||
4993 | static struct ssb_driver b43_ssb_driver = { | 4935 | static 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 | ||
5002 | static void b43_print_driverinfo(void) | 4942 | static void b43_print_driverinfo(void) |