diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-07-13 15:57:29 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-07-13 15:57:29 -0400 |
commit | e300d955debdadf599c36e47eb0bc16f5976215c (patch) | |
tree | 8fafcc789dc06e90665e6eee6388af228bbd2fd7 /drivers/net/wireless/rt2x00/rt2x00dev.c | |
parent | 242647bcf8464860f173f3d4d4ab3490d3558518 (diff) | |
parent | 815868e7b5c207ba42d5b317ccc51f8112732268 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6 into for-davem
Conflicts:
drivers/net/wireless/wl12xx/wl1271_cmd.h
Diffstat (limited to 'drivers/net/wireless/rt2x00/rt2x00dev.c')
-rw-r--r-- | drivers/net/wireless/rt2x00/rt2x00dev.c | 96 |
1 files changed, 83 insertions, 13 deletions
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 12ee7bdedd02..f59b9f7226a8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c | |||
@@ -70,6 +70,11 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) | |||
70 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); | 70 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); |
71 | 71 | ||
72 | /* | 72 | /* |
73 | * Start watchdog monitoring. | ||
74 | */ | ||
75 | rt2x00link_start_watchdog(rt2x00dev); | ||
76 | |||
77 | /* | ||
73 | * Start the TX queues. | 78 | * Start the TX queues. |
74 | */ | 79 | */ |
75 | ieee80211_wake_queues(rt2x00dev->hw); | 80 | ieee80211_wake_queues(rt2x00dev->hw); |
@@ -89,6 +94,11 @@ void rt2x00lib_disable_radio(struct rt2x00_dev *rt2x00dev) | |||
89 | rt2x00queue_stop_queues(rt2x00dev); | 94 | rt2x00queue_stop_queues(rt2x00dev); |
90 | 95 | ||
91 | /* | 96 | /* |
97 | * Stop watchdog monitoring. | ||
98 | */ | ||
99 | rt2x00link_stop_watchdog(rt2x00dev); | ||
100 | |||
101 | /* | ||
92 | * Disable RX. | 102 | * Disable RX. |
93 | */ | 103 | */ |
94 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); | 104 | rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); |
@@ -168,10 +178,32 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work) | |||
168 | /* | 178 | /* |
169 | * Interrupt context handlers. | 179 | * Interrupt context handlers. |
170 | */ | 180 | */ |
171 | static void rt2x00lib_beacondone_iter(void *data, u8 *mac, | 181 | static void rt2x00lib_bc_buffer_iter(void *data, u8 *mac, |
172 | struct ieee80211_vif *vif) | 182 | struct ieee80211_vif *vif) |
173 | { | 183 | { |
174 | struct rt2x00_intf *intf = vif_to_intf(vif); | 184 | struct rt2x00_dev *rt2x00dev = data; |
185 | struct sk_buff *skb; | ||
186 | |||
187 | /* | ||
188 | * Only AP mode interfaces do broad- and multicast buffering | ||
189 | */ | ||
190 | if (vif->type != NL80211_IFTYPE_AP) | ||
191 | return; | ||
192 | |||
193 | /* | ||
194 | * Send out buffered broad- and multicast frames | ||
195 | */ | ||
196 | skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); | ||
197 | while (skb) { | ||
198 | rt2x00mac_tx(rt2x00dev->hw, skb); | ||
199 | skb = ieee80211_get_buffered_bc(rt2x00dev->hw, vif); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static void rt2x00lib_beaconupdate_iter(void *data, u8 *mac, | ||
204 | struct ieee80211_vif *vif) | ||
205 | { | ||
206 | struct rt2x00_dev *rt2x00dev = data; | ||
175 | 207 | ||
176 | if (vif->type != NL80211_IFTYPE_AP && | 208 | if (vif->type != NL80211_IFTYPE_AP && |
177 | vif->type != NL80211_IFTYPE_ADHOC && | 209 | vif->type != NL80211_IFTYPE_ADHOC && |
@@ -179,9 +211,7 @@ static void rt2x00lib_beacondone_iter(void *data, u8 *mac, | |||
179 | vif->type != NL80211_IFTYPE_WDS) | 211 | vif->type != NL80211_IFTYPE_WDS) |
180 | return; | 212 | return; |
181 | 213 | ||
182 | spin_lock(&intf->lock); | 214 | rt2x00queue_update_beacon(rt2x00dev, vif, true); |
183 | intf->delayed_flags |= DELAYED_UPDATE_BEACON; | ||
184 | spin_unlock(&intf->lock); | ||
185 | } | 215 | } |
186 | 216 | ||
187 | void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) | 217 | void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) |
@@ -189,14 +219,37 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev) | |||
189 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | 219 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) |
190 | return; | 220 | return; |
191 | 221 | ||
192 | ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw, | 222 | /* send buffered bc/mc frames out for every bssid */ |
193 | rt2x00lib_beacondone_iter, | 223 | ieee80211_iterate_active_interfaces(rt2x00dev->hw, |
194 | rt2x00dev); | 224 | rt2x00lib_bc_buffer_iter, |
225 | rt2x00dev); | ||
226 | /* | ||
227 | * Devices with pre tbtt interrupt don't need to update the beacon | ||
228 | * here as they will fetch the next beacon directly prior to | ||
229 | * transmission. | ||
230 | */ | ||
231 | if (test_bit(DRIVER_SUPPORT_PRE_TBTT_INTERRUPT, &rt2x00dev->flags)) | ||
232 | return; | ||
195 | 233 | ||
196 | ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); | 234 | /* fetch next beacon */ |
235 | ieee80211_iterate_active_interfaces(rt2x00dev->hw, | ||
236 | rt2x00lib_beaconupdate_iter, | ||
237 | rt2x00dev); | ||
197 | } | 238 | } |
198 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); | 239 | EXPORT_SYMBOL_GPL(rt2x00lib_beacondone); |
199 | 240 | ||
241 | void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev) | ||
242 | { | ||
243 | if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) | ||
244 | return; | ||
245 | |||
246 | /* fetch next beacon */ | ||
247 | ieee80211_iterate_active_interfaces(rt2x00dev->hw, | ||
248 | rt2x00lib_beaconupdate_iter, | ||
249 | rt2x00dev); | ||
250 | } | ||
251 | EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt); | ||
252 | |||
200 | void rt2x00lib_txdone(struct queue_entry *entry, | 253 | void rt2x00lib_txdone(struct queue_entry *entry, |
201 | struct txdone_entry_desc *txdesc) | 254 | struct txdone_entry_desc *txdesc) |
202 | { | 255 | { |
@@ -330,9 +383,17 @@ void rt2x00lib_txdone(struct queue_entry *entry, | |||
330 | * send the status report back. | 383 | * send the status report back. |
331 | */ | 384 | */ |
332 | if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) | 385 | if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) |
333 | ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); | 386 | /* |
387 | * Only PCI and SOC devices process the tx status in process | ||
388 | * context. Hence use ieee80211_tx_status for PCI and SOC | ||
389 | * devices and stick to ieee80211_tx_status_irqsafe for USB. | ||
390 | */ | ||
391 | if (rt2x00_is_usb(rt2x00dev)) | ||
392 | ieee80211_tx_status_irqsafe(rt2x00dev->hw, entry->skb); | ||
393 | else | ||
394 | ieee80211_tx_status(rt2x00dev->hw, entry->skb); | ||
334 | else | 395 | else |
335 | dev_kfree_skb_irq(entry->skb); | 396 | dev_kfree_skb_any(entry->skb); |
336 | 397 | ||
337 | /* | 398 | /* |
338 | * Make this entry available for reuse. | 399 | * Make this entry available for reuse. |
@@ -479,7 +540,16 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, | |||
479 | */ | 540 | */ |
480 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); | 541 | rt2x00debug_dump_frame(rt2x00dev, DUMP_FRAME_RXDONE, entry->skb); |
481 | memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); | 542 | memcpy(IEEE80211_SKB_RXCB(entry->skb), rx_status, sizeof(*rx_status)); |
482 | ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); | 543 | |
544 | /* | ||
545 | * Currently only PCI and SOC devices handle rx interrupts in process | ||
546 | * context. Hence, use ieee80211_rx_irqsafe for USB and ieee80211_rx_ni | ||
547 | * for PCI and SOC devices. | ||
548 | */ | ||
549 | if (rt2x00_is_usb(rt2x00dev)) | ||
550 | ieee80211_rx_irqsafe(rt2x00dev->hw, entry->skb); | ||
551 | else | ||
552 | ieee80211_rx_ni(rt2x00dev->hw, entry->skb); | ||
483 | 553 | ||
484 | /* | 554 | /* |
485 | * Replace the skb with the freshly allocated one. | 555 | * Replace the skb with the freshly allocated one. |