aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-12-23 07:15:32 -0500
committerJohn W. Linville <linville@tuxdriver.com>2009-12-28 16:54:51 -0500
commita80f7c0b088187c8471b441d461e937991870661 (patch)
treef673c08009a03f2e988a638510b112a5584bea11
parent9607e6b66a0d25ca63b70d54a4283fa13d8f7c9d (diff)
mac80211: introduce flush operation
We've long lacked a good confirmation that frames have really gone out, e.g. before going off-channel for a scan. Add a flush() operation that drivers can implement to provide that confirmation, and use it in a few places: * before scanning sends the nullfunc frames * after scanning sends the nullfunc frames, if any * when going idle, to send any pending frames Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c11
-rw-r--r--include/net/mac80211.h5
-rw-r--r--net/mac80211/driver-ops.h7
-rw-r--r--net/mac80211/driver-trace.h21
-rw-r--r--net/mac80211/iface.c2
-rw-r--r--net/mac80211/scan.c13
6 files changed, 57 insertions, 2 deletions
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index 718a5f198c30..4dee69a38c1d 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -896,6 +896,16 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
896 return 0; 896 return 0;
897} 897}
898 898
899static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
900{
901 /*
902 * In this special case, there's nothing we need to
903 * do because hwsim does transmission synchronously.
904 * In the future, when it does transmissions via
905 * userspace, we may need to do something.
906 */
907}
908
899 909
900static const struct ieee80211_ops mac80211_hwsim_ops = 910static const struct ieee80211_ops mac80211_hwsim_ops =
901{ 911{
@@ -912,6 +922,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops =
912 .conf_tx = mac80211_hwsim_conf_tx, 922 .conf_tx = mac80211_hwsim_conf_tx,
913 CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd) 923 CFG80211_TESTMODE_CMD(mac80211_hwsim_testmode_cmd)
914 .ampdu_action = mac80211_hwsim_ampdu_action, 924 .ampdu_action = mac80211_hwsim_ampdu_action,
925 .flush = mac80211_hwsim_flush,
915}; 926};
916 927
917 928
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 494ac69ff477..77ea34b03285 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1545,6 +1545,10 @@ enum ieee80211_ampdu_mlme_action {
1545 * and need to call wiphy_rfkill_set_hw_state() in the callback. 1545 * and need to call wiphy_rfkill_set_hw_state() in the callback.
1546 * 1546 *
1547 * @testmode_cmd: Implement a cfg80211 test mode command. 1547 * @testmode_cmd: Implement a cfg80211 test mode command.
1548 *
1549 * @flush: Flush all pending frames from the hardware queue, making sure
1550 * that the hardware queues are empty. If the parameter @drop is set
1551 * to %true, pending frames may be dropped.
1548 */ 1552 */
1549struct ieee80211_ops { 1553struct ieee80211_ops {
1550 int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); 1554 int (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
@@ -1601,6 +1605,7 @@ struct ieee80211_ops {
1601#ifdef CONFIG_NL80211_TESTMODE 1605#ifdef CONFIG_NL80211_TESTMODE
1602 int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len); 1606 int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
1603#endif 1607#endif
1608 void (*flush)(struct ieee80211_hw *hw, bool drop);
1604}; 1609};
1605 1610
1606/** 1611/**
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 727e4cf7b8a6..cbe133bcdf34 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -259,4 +259,11 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
259 if (local->ops->rfkill_poll) 259 if (local->ops->rfkill_poll)
260 local->ops->rfkill_poll(&local->hw); 260 local->ops->rfkill_poll(&local->hw);
261} 261}
262
263static inline void drv_flush(struct ieee80211_local *local, bool drop)
264{
265 trace_drv_flush(local, drop);
266 if (local->ops->flush)
267 local->ops->flush(&local->hw, drop);
268}
262#endif /* __MAC80211_DRIVER_OPS */ 269#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 7a849b920165..977cc7528bc6 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -690,6 +690,27 @@ TRACE_EVENT(drv_ampdu_action,
690 LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret 690 LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->action, __entry->tid, __entry->ret
691 ) 691 )
692); 692);
693
694TRACE_EVENT(drv_flush,
695 TP_PROTO(struct ieee80211_local *local, bool drop),
696
697 TP_ARGS(local, drop),
698
699 TP_STRUCT__entry(
700 LOCAL_ENTRY
701 __field(bool, drop)
702 ),
703
704 TP_fast_assign(
705 LOCAL_ASSIGN;
706 __entry->drop = drop;
707 ),
708
709 TP_printk(
710 LOCAL_PR_FMT " drop:%d",
711 LOCAL_PR_ARG, __entry->drop
712 )
713);
693#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ 714#endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
694 715
695#undef TRACE_INCLUDE_PATH 716#undef TRACE_INCLUDE_PATH
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 1ceca14331d4..389dc8d880f3 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -917,6 +917,8 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
917 wiphy_name(local->hw.wiphy)); 917 wiphy_name(local->hw.wiphy));
918#endif 918#endif
919 919
920 drv_flush(local, false);
921
920 local->hw.conf.flags |= IEEE80211_CONF_IDLE; 922 local->hw.conf.flags |= IEEE80211_CONF_IDLE;
921 return IEEE80211_CONF_CHANGE_IDLE; 923 return IEEE80211_CONF_CHANGE_IDLE;
922} 924}
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index ae1830056521..d98c45e5528b 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -418,9 +418,10 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
418 local->next_scan_state = SCAN_DECISION; 418 local->next_scan_state = SCAN_DECISION;
419 local->scan_channel_idx = 0; 419 local->scan_channel_idx = 0;
420 420
421 drv_flush(local, false);
422
421 ieee80211_configure_filter(local); 423 ieee80211_configure_filter(local);
422 424
423 /* TODO: start scan as soon as all nullfunc frames are ACKed */
424 ieee80211_queue_delayed_work(&local->hw, 425 ieee80211_queue_delayed_work(&local->hw,
425 &local->scan_work, 426 &local->scan_work,
426 IEEE80211_CHANNEL_TIME); 427 IEEE80211_CHANNEL_TIME);
@@ -584,8 +585,16 @@ static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *loca
584 585
585 __set_bit(SCAN_OFF_CHANNEL, &local->scanning); 586 __set_bit(SCAN_OFF_CHANNEL, &local->scanning);
586 587
588 /*
589 * What if the nullfunc frames didn't arrive?
590 */
591 drv_flush(local, false);
592 if (local->ops->flush)
593 *next_delay = 0;
594 else
595 *next_delay = HZ / 10;
596
587 /* advance to the next channel to be scanned */ 597 /* advance to the next channel to be scanned */
588 *next_delay = HZ / 10;
589 local->next_scan_state = SCAN_SET_CHANNEL; 598 local->next_scan_state = SCAN_SET_CHANNEL;
590} 599}
591 600