aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-08-17 10:16:53 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-08-20 11:35:58 -0400
commit3ac64beecd27400d12cc7afb4108eef26c499f6a (patch)
treeda0220085f68e30fe61ba9b8833dc6311d6dc25e /net/mac80211
parentea416a793d2b611f22b42ba094fd2e5bd30fff43 (diff)
mac80211: allow configure_filter callback to sleep
Over time, a whole bunch of drivers have come up with their own scheme to delay the configure_filter operation to a workqueue. To be able to simplify things, allow configure_filter to sleep, and add a new prepare_multicast callback that drivers that need the multicast address list implement. This new callback must be atomic, but most drivers either don't care or just calculate a hash which can be done atomically and then uploaded to the hardware non-atomically. A cursory look suggests that at76c50x-usb, ar9170, mwl8k (which is actually very broken now), rt2x00, wl1251, wl1271 and zd1211 should make use of this new capability. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/driver-ops.h24
-rw-r--r--net/mac80211/driver-trace.h36
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/iface.c15
-rw-r--r--net/mac80211/main.c24
-rw-r--r--net/mac80211/scan.c16
-rw-r--r--net/mac80211/util.c2
7 files changed, 77 insertions, 43 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 4100c361a99d..d231c9323ad1 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -55,16 +55,32 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
55 trace_drv_bss_info_changed(local, vif, info, changed); 55 trace_drv_bss_info_changed(local, vif, info, changed);
56} 56}
57 57
58static inline u64 drv_prepare_multicast(struct ieee80211_local *local,
59 int mc_count,
60 struct dev_addr_list *mc_list)
61{
62 u64 ret = 0;
63
64 if (local->ops->prepare_multicast)
65 ret = local->ops->prepare_multicast(&local->hw, mc_count,
66 mc_list);
67
68 trace_drv_prepare_multicast(local, mc_count, ret);
69
70 return ret;
71}
72
58static inline void drv_configure_filter(struct ieee80211_local *local, 73static inline void drv_configure_filter(struct ieee80211_local *local,
59 unsigned int changed_flags, 74 unsigned int changed_flags,
60 unsigned int *total_flags, 75 unsigned int *total_flags,
61 int mc_count, 76 u64 multicast)
62 struct dev_addr_list *mc_list)
63{ 77{
78 might_sleep();
79
64 local->ops->configure_filter(&local->hw, changed_flags, total_flags, 80 local->ops->configure_filter(&local->hw, changed_flags, total_flags,
65 mc_count, mc_list); 81 multicast);
66 trace_drv_configure_filter(local, changed_flags, total_flags, 82 trace_drv_configure_filter(local, changed_flags, total_flags,
67 mc_count); 83 multicast);
68} 84}
69 85
70static inline int drv_set_tim(struct ieee80211_local *local, 86static inline int drv_set_tim(struct ieee80211_local *local,
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 5a10da2d70fd..37b9051afcf3 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -191,31 +191,55 @@ TRACE_EVENT(drv_bss_info_changed,
191 ) 191 )
192); 192);
193 193
194TRACE_EVENT(drv_prepare_multicast,
195 TP_PROTO(struct ieee80211_local *local, int mc_count, u64 ret),
196
197 TP_ARGS(local, mc_count, ret),
198
199 TP_STRUCT__entry(
200 LOCAL_ENTRY
201 __field(int, mc_count)
202 __field(u64, ret)
203 ),
204
205 TP_fast_assign(
206 LOCAL_ASSIGN;
207 __entry->mc_count = mc_count;
208 __entry->ret = ret;
209 ),
210
211 TP_printk(
212 LOCAL_PR_FMT " prepare mc (%d): %llx",
213 LOCAL_PR_ARG, __entry->mc_count,
214 (unsigned long long) __entry->ret
215 )
216);
217
194TRACE_EVENT(drv_configure_filter, 218TRACE_EVENT(drv_configure_filter,
195 TP_PROTO(struct ieee80211_local *local, 219 TP_PROTO(struct ieee80211_local *local,
196 unsigned int changed_flags, 220 unsigned int changed_flags,
197 unsigned int *total_flags, 221 unsigned int *total_flags,
198 int mc_count), 222 u64 multicast),
199 223
200 TP_ARGS(local, changed_flags, total_flags, mc_count), 224 TP_ARGS(local, changed_flags, total_flags, multicast),
201 225
202 TP_STRUCT__entry( 226 TP_STRUCT__entry(
203 LOCAL_ENTRY 227 LOCAL_ENTRY
204 __field(unsigned int, changed) 228 __field(unsigned int, changed)
205 __field(unsigned int, total) 229 __field(unsigned int, total)
206 __field(int, mc) 230 __field(u64, multicast)
207 ), 231 ),
208 232
209 TP_fast_assign( 233 TP_fast_assign(
210 LOCAL_ASSIGN; 234 LOCAL_ASSIGN;
211 __entry->changed = changed_flags; 235 __entry->changed = changed_flags;
212 __entry->total = *total_flags; 236 __entry->total = *total_flags;
213 __entry->mc = mc_count; 237 __entry->multicast = multicast;
214 ), 238 ),
215 239
216 TP_printk( 240 TP_printk(
217 LOCAL_PR_FMT " changed:%#x total:%#x mc:%d", 241 LOCAL_PR_FMT " changed:%#x total:%#x",
218 LOCAL_PR_ARG, __entry->changed, __entry->total, __entry->mc 242 LOCAL_PR_ARG, __entry->changed, __entry->total
219 ) 243 )
220); 244);
221 245
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a6abc7dfd903..a07f01736a91 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -636,6 +636,9 @@ struct ieee80211_local {
636 /* protects the aggregated multicast list and filter calls */ 636 /* protects the aggregated multicast list and filter calls */
637 spinlock_t filter_lock; 637 spinlock_t filter_lock;
638 638
639 /* used for uploading changed mc list */
640 struct work_struct reconfig_filter;
641
639 /* aggregated multicast list */ 642 /* aggregated multicast list */
640 struct dev_addr_list *mc_list; 643 struct dev_addr_list *mc_list;
641 int mc_count; 644 int mc_count;
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e8fb03b91a44..b161301056df 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -227,9 +227,7 @@ static int ieee80211_open(struct net_device *dev)
227 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) 227 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
228 local->fif_other_bss++; 228 local->fif_other_bss++;
229 229
230 spin_lock_bh(&local->filter_lock);
231 ieee80211_configure_filter(local); 230 ieee80211_configure_filter(local);
232 spin_unlock_bh(&local->filter_lock);
233 break; 231 break;
234 default: 232 default:
235 conf.vif = &sdata->vif; 233 conf.vif = &sdata->vif;
@@ -241,17 +239,13 @@ static int ieee80211_open(struct net_device *dev)
241 239
242 if (ieee80211_vif_is_mesh(&sdata->vif)) { 240 if (ieee80211_vif_is_mesh(&sdata->vif)) {
243 local->fif_other_bss++; 241 local->fif_other_bss++;
244 spin_lock_bh(&local->filter_lock);
245 ieee80211_configure_filter(local); 242 ieee80211_configure_filter(local);
246 spin_unlock_bh(&local->filter_lock);
247 243
248 ieee80211_start_mesh(sdata); 244 ieee80211_start_mesh(sdata);
249 } else if (sdata->vif.type == NL80211_IFTYPE_AP) { 245 } else if (sdata->vif.type == NL80211_IFTYPE_AP) {
250 local->fif_pspoll++; 246 local->fif_pspoll++;
251 247
252 spin_lock_bh(&local->filter_lock);
253 ieee80211_configure_filter(local); 248 ieee80211_configure_filter(local);
254 spin_unlock_bh(&local->filter_lock);
255 } 249 }
256 250
257 changed |= ieee80211_reset_erp_info(sdata); 251 changed |= ieee80211_reset_erp_info(sdata);
@@ -404,10 +398,11 @@ static int ieee80211_stop(struct net_device *dev)
404 spin_lock_bh(&local->filter_lock); 398 spin_lock_bh(&local->filter_lock);
405 __dev_addr_unsync(&local->mc_list, &local->mc_count, 399 __dev_addr_unsync(&local->mc_list, &local->mc_count,
406 &dev->mc_list, &dev->mc_count); 400 &dev->mc_list, &dev->mc_count);
407 ieee80211_configure_filter(local);
408 spin_unlock_bh(&local->filter_lock); 401 spin_unlock_bh(&local->filter_lock);
409 netif_addr_unlock_bh(dev); 402 netif_addr_unlock_bh(dev);
410 403
404 ieee80211_configure_filter(local);
405
411 del_timer_sync(&local->dynamic_ps_timer); 406 del_timer_sync(&local->dynamic_ps_timer);
412 cancel_work_sync(&local->dynamic_ps_enable_work); 407 cancel_work_sync(&local->dynamic_ps_enable_work);
413 408
@@ -458,9 +453,7 @@ static int ieee80211_stop(struct net_device *dev)
458 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS) 453 if (sdata->u.mntr_flags & MONITOR_FLAG_OTHER_BSS)
459 local->fif_other_bss--; 454 local->fif_other_bss--;
460 455
461 spin_lock_bh(&local->filter_lock);
462 ieee80211_configure_filter(local); 456 ieee80211_configure_filter(local);
463 spin_unlock_bh(&local->filter_lock);
464 break; 457 break;
465 case NL80211_IFTYPE_STATION: 458 case NL80211_IFTYPE_STATION:
466 del_timer_sync(&sdata->u.mgd.chswitch_timer); 459 del_timer_sync(&sdata->u.mgd.chswitch_timer);
@@ -503,9 +496,7 @@ static int ieee80211_stop(struct net_device *dev)
503 local->fif_other_bss--; 496 local->fif_other_bss--;
504 atomic_dec(&local->iff_allmultis); 497 atomic_dec(&local->iff_allmultis);
505 498
506 spin_lock_bh(&local->filter_lock);
507 ieee80211_configure_filter(local); 499 ieee80211_configure_filter(local);
508 spin_unlock_bh(&local->filter_lock);
509 500
510 ieee80211_stop_mesh(sdata); 501 ieee80211_stop_mesh(sdata);
511 } 502 }
@@ -622,8 +613,8 @@ static void ieee80211_set_multicast_list(struct net_device *dev)
622 spin_lock_bh(&local->filter_lock); 613 spin_lock_bh(&local->filter_lock);
623 __dev_addr_sync(&local->mc_list, &local->mc_count, 614 __dev_addr_sync(&local->mc_list, &local->mc_count,
624 &dev->mc_list, &dev->mc_count); 615 &dev->mc_list, &dev->mc_count);
625 ieee80211_configure_filter(local);
626 spin_unlock_bh(&local->filter_lock); 616 spin_unlock_bh(&local->filter_lock);
617 ieee80211_queue_work(&local->hw, &local->reconfig_filter);
627} 618}
628 619
629/* 620/*
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index b03fd84777fa..05f923575fee 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -50,9 +50,9 @@ struct ieee80211_tx_status_rtap_hdr {
50} __attribute__ ((packed)); 50} __attribute__ ((packed));
51 51
52 52
53/* must be called under mdev tx lock */
54void ieee80211_configure_filter(struct ieee80211_local *local) 53void ieee80211_configure_filter(struct ieee80211_local *local)
55{ 54{
55 u64 mc;
56 unsigned int changed_flags; 56 unsigned int changed_flags;
57 unsigned int new_flags = 0; 57 unsigned int new_flags = 0;
58 58
@@ -62,7 +62,7 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
62 if (atomic_read(&local->iff_allmultis)) 62 if (atomic_read(&local->iff_allmultis))
63 new_flags |= FIF_ALLMULTI; 63 new_flags |= FIF_ALLMULTI;
64 64
65 if (local->monitors) 65 if (local->monitors || local->scanning)
66 new_flags |= FIF_BCN_PRBRESP_PROMISC; 66 new_flags |= FIF_BCN_PRBRESP_PROMISC;
67 67
68 if (local->fif_fcsfail) 68 if (local->fif_fcsfail)
@@ -80,20 +80,30 @@ void ieee80211_configure_filter(struct ieee80211_local *local)
80 if (local->fif_pspoll) 80 if (local->fif_pspoll)
81 new_flags |= FIF_PSPOLL; 81 new_flags |= FIF_PSPOLL;
82 82
83 spin_lock_bh(&local->filter_lock);
83 changed_flags = local->filter_flags ^ new_flags; 84 changed_flags = local->filter_flags ^ new_flags;
84 85
86 mc = drv_prepare_multicast(local, local->mc_count, local->mc_list);
87 spin_unlock_bh(&local->filter_lock);
88
85 /* be a bit nasty */ 89 /* be a bit nasty */
86 new_flags |= (1<<31); 90 new_flags |= (1<<31);
87 91
88 drv_configure_filter(local, changed_flags, &new_flags, 92 drv_configure_filter(local, changed_flags, &new_flags, mc);
89 local->mc_count,
90 local->mc_list);
91 93
92 WARN_ON(new_flags & (1<<31)); 94 WARN_ON(new_flags & (1<<31));
93 95
94 local->filter_flags = new_flags & ~(1<<31); 96 local->filter_flags = new_flags & ~(1<<31);
95} 97}
96 98
99static void ieee80211_reconfig_filter(struct work_struct *work)
100{
101 struct ieee80211_local *local =
102 container_of(work, struct ieee80211_local, reconfig_filter);
103
104 ieee80211_configure_filter(local);
105}
106
97int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) 107int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
98{ 108{
99 struct ieee80211_channel *chan, *scan_chan; 109 struct ieee80211_channel *chan, *scan_chan;
@@ -692,6 +702,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
692 702
693 INIT_WORK(&local->restart_work, ieee80211_restart_work); 703 INIT_WORK(&local->restart_work, ieee80211_restart_work);
694 704
705 INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
706
695 INIT_WORK(&local->dynamic_ps_enable_work, 707 INIT_WORK(&local->dynamic_ps_enable_work,
696 ieee80211_dynamic_ps_enable_work); 708 ieee80211_dynamic_ps_enable_work);
697 INIT_WORK(&local->dynamic_ps_disable_work, 709 INIT_WORK(&local->dynamic_ps_disable_work,
@@ -946,6 +958,8 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
946 958
947 rtnl_unlock(); 959 rtnl_unlock();
948 960
961 cancel_work_sync(&local->reconfig_filter);
962
949 ieee80211_clear_tx_pending(local); 963 ieee80211_clear_tx_pending(local);
950 sta_info_stop(local); 964 sta_info_stop(local);
951 rate_control_deinitialize(local); 965 rate_control_deinitialize(local);
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index e091cbc3434f..1e04be6b9129 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -292,13 +292,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
292 if (was_hw_scan) 292 if (was_hw_scan)
293 goto done; 293 goto done;
294 294
295 spin_lock_bh(&local->filter_lock); 295 ieee80211_configure_filter(local);
296 local->filter_flags &= ~FIF_BCN_PRBRESP_PROMISC;
297 drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
298 &local->filter_flags,
299 local->mc_count,
300 local->mc_list);
301 spin_unlock_bh(&local->filter_lock);
302 296
303 drv_sw_scan_complete(local); 297 drv_sw_scan_complete(local);
304 298
@@ -376,13 +370,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
376 local->next_scan_state = SCAN_DECISION; 370 local->next_scan_state = SCAN_DECISION;
377 local->scan_channel_idx = 0; 371 local->scan_channel_idx = 0;
378 372
379 spin_lock_bh(&local->filter_lock); 373 ieee80211_configure_filter(local);
380 local->filter_flags |= FIF_BCN_PRBRESP_PROMISC;
381 drv_configure_filter(local, FIF_BCN_PRBRESP_PROMISC,
382 &local->filter_flags,
383 local->mc_count,
384 local->mc_list);
385 spin_unlock_bh(&local->filter_lock);
386 374
387 /* TODO: start scan as soon as all nullfunc frames are ACKed */ 375 /* TODO: start scan as soon as all nullfunc frames are ACKed */
388 ieee80211_queue_delayed_work(&local->hw, 376 ieee80211_queue_delayed_work(&local->hw,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e55d57f559ec..5eb306377c63 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1076,9 +1076,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
1076 /* reconfigure hardware */ 1076 /* reconfigure hardware */
1077 ieee80211_hw_config(local, ~0); 1077 ieee80211_hw_config(local, ~0);
1078 1078
1079 spin_lock_bh(&local->filter_lock);
1080 ieee80211_configure_filter(local); 1079 ieee80211_configure_filter(local);
1081 spin_unlock_bh(&local->filter_lock);
1082 1080
1083 /* Finally also reconfigure all the BSS information */ 1081 /* Finally also reconfigure all the BSS information */
1084 list_for_each_entry(sdata, &local->interfaces, list) { 1082 list_for_each_entry(sdata, &local->interfaces, list) {