mac80211: pass queue bitmap to flush operation
authorJohannes Berg <johannes.berg@intel.com>
Wed, 13 Feb 2013 11:11:00 +0000 (12:11 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 18 Mar 2013 19:15:03 +0000 (20:15 +0100)
There are a number of situations in which mac80211 only
really needs to flush queues for one virtual interface,
and in fact during this frames might be transmitted on
other virtual interfaces. Calculate and pass a queue
bitmap to the driver so it knows which queues to flush.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
23 files changed:
drivers/net/wireless/ath/ar5523/ar5523.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/ti/wlcore/main.c
include/net/mac80211.h
net/mac80211/driver-ops.h
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/scan.c
net/mac80211/trace.h
net/mac80211/util.c

index 7157f7d311c5e001a2e071231d50755fc7a9c3cb..afd1e36d308faefdf20fd2f7f4b4c748ef72464a 100644 (file)
@@ -1091,7 +1091,7 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
        return ret;
 }
 
-static void ar5523_flush(struct ieee80211_hw *hw, bool drop)
+static void ar5523_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct ar5523 *ar = hw->priv;
 
index 6e66f9c6782b966ac249b4bd31ecc25e6a9456b2..24650fd4169466d37be5817fc33d55d0e6fa4c73 100644 (file)
@@ -1745,7 +1745,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
        mutex_unlock(&sc->mutex);
 }
 
-static void ath9k_flush(struct ieee80211_hw *hw, bool drop)
+static void ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
index f293b3ff475628a389c1337df81d24cb3b3b5640..08b193199946eb40235ce59dc3c1120a62f6be9e 100644 (file)
@@ -1703,7 +1703,7 @@ found:
        return 0;
 }
 
-static void carl9170_op_flush(struct ieee80211_hw *hw, bool drop)
+static void carl9170_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct ar9170 *ar = hw->priv;
        unsigned int vid;
index c6451c61407a8c4510c97056bde23ef1ee88c060..aa5f43fee5ed9889241872e4b0c1ce7fc3063789 100644 (file)
@@ -723,7 +723,7 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl)
        return result;
 }
 
-static void brcms_ops_flush(struct ieee80211_hw *hw, bool drop)
+static void brcms_ops_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct brcms_info *wl = hw->priv;
        int ret;
index e006ea831320ae5a3c3dd15f87a9c00a3eb4d3d8..722bfb57cfd5ebfed62e46f7f60e2f2792d7d44c 100644 (file)
@@ -4704,8 +4704,7 @@ out:
 }
 EXPORT_SYMBOL(il_mac_change_interface);
 
-void
-il_mac_flush(struct ieee80211_hw *hw, bool drop)
+void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct il_priv *il = hw->priv;
        unsigned long timeout = jiffies + msecs_to_jiffies(500);
index 73bd3ef316c8452858dfa75f60a837b00d0df8d1..728aa1306ab8956d19036836b2f4831b873ad7c0 100644 (file)
@@ -1720,7 +1720,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
                             struct ieee80211_vif *vif);
 int il_mac_change_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            enum nl80211_iftype newtype, bool newp2p);
-void il_mac_flush(struct ieee80211_hw *hw, bool drop);
+void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
 int il_alloc_txq_mem(struct il_priv *il);
 void il_free_txq_mem(struct il_priv *il);
 
index c7cd2dffa5cdbac4719cc9c0ec7431a218e743a2..a7294fa4d7e54851566c6560ffd7d825927b8f25 100644 (file)
@@ -1100,7 +1100,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
                        FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
 }
 
-static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
 
index 7490c4fc7177eb92efd619724a2a6804260ae268..3466f1a8a8d3b91ccfa58f9d2c065d7376d71f91 100644 (file)
@@ -1389,7 +1389,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
        return 0;
 }
 
-static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
+static void mac80211_hwsim_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        /* Not implemented, queues only on kernel side */
 }
index aadda99989c007838faf7eb5ca816d18904ea91c..ee654a691f388660c9f33ab6b0ea5538e532f694 100644 (file)
@@ -670,7 +670,7 @@ static unsigned int p54_flush_count(struct p54_common *priv)
        return total;
 }
 
-static void p54_flush(struct ieee80211_hw *dev, bool drop)
+static void p54_flush(struct ieee80211_hw *dev, u32 queues, bool drop)
 {
        struct p54_common *priv = dev->priv;
        unsigned int total, i;
index 086abb403a4f2085463da5a571505dbc040389cc..041b392f4f4780da1a36cdcb360678e72e4463f9 100644 (file)
@@ -1360,7 +1360,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
                      struct ieee80211_vif *vif, u16 queue,
                      const struct ieee80211_tx_queue_params *params);
 void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
-void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop);
+void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
 int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
 int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
 void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
index 20c6eccce5aa32004f5b8b5f2aacf5703903fc6c..9161c02d8ff9719f9a6702efec55fdc86b6401f2 100644 (file)
@@ -748,7 +748,7 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
 
-void rt2x00mac_flush(struct ieee80211_hw *hw, bool drop)
+void rt2x00mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        struct data_queue *queue;
index d3ce9fbef00ee0b8d3e88eefcfd7111d9d0080ae..b5a7a260bf631d2b04ad88a3158732936f3eb828 100644 (file)
@@ -1166,7 +1166,7 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
  * before switch channle or power save, or tx buffer packet
  * maybe send after offchannel or rf sleep, this may cause
  * dis-association by AP */
-static void rtl_op_flush(struct ieee80211_hw *hw, bool drop)
+static void rtl_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
index d7e306333f6cad9cc2a39644f234742b2a5a1ceb..a9f7041c719230d5d620764b7debb27b47e1cee9 100644 (file)
@@ -4946,7 +4946,7 @@ out:
        mutex_unlock(&wl->mutex);
 }
 
-static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop)
+static void wlcore_op_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
 {
        struct wl1271 *wl = hw->priv;
 
index 0b912d22f82d22a9e4641de6462b99572cd51404..4158da74e11b066c20687f85536de6561052698f 100644 (file)
@@ -2438,8 +2438,11 @@ enum ieee80211_roc_type {
  * @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep.
  *
  * @flush: Flush all pending frames from the hardware queue, making sure
- *     that the hardware queues are empty. If the parameter @drop is set
- *     to %true, pending frames may be dropped. The callback can sleep.
+ *     that the hardware queues are empty. The @queues parameter is a bitmap
+ *     of queues to flush, which is useful if different virtual interfaces
+ *     use different hardware queues; it may also indicate all queues.
+ *     If the parameter @drop is set to %true, pending frames may be dropped.
+ *     The callback can sleep.
  *
  * @channel_switch: Drivers that need (or want) to offload the channel
  *     switch operation for CSAs received from the AP may implement this
@@ -2687,7 +2690,7 @@ struct ieee80211_ops {
                             struct netlink_callback *cb,
                             void *data, int len);
 #endif
-       void (*flush)(struct ieee80211_hw *hw, bool drop);
+       void (*flush)(struct ieee80211_hw *hw, u32 queues, bool drop);
        void (*channel_switch)(struct ieee80211_hw *hw,
                               struct ieee80211_channel_switch *ch_switch);
        int (*napi_poll)(struct ieee80211_hw *hw, int budget);
index 7b9ff53bd2e99203e4fc22ef8d689bdae9f05b98..169664c122e23cbe80f89016714bdcdfec24dc6e 100644 (file)
@@ -720,13 +720,14 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
                local->ops->rfkill_poll(&local->hw);
 }
 
-static inline void drv_flush(struct ieee80211_local *local, bool drop)
+static inline void drv_flush(struct ieee80211_local *local,
+                            u32 queues, bool drop)
 {
        might_sleep();
 
-       trace_drv_flush(local, drop);
+       trace_drv_flush(local, queues, drop);
        if (local->ops->flush)
-               local->ops->flush(&local->hw, drop);
+               local->ops->flush(&local->hw, queues, drop);
        trace_drv_return_void(local);
 }
 
index d6e920609823c5723b6dda1c807288bdd5e7d5c5..b96c0e977752dd1d2cac14c7dc1f93c276b19001 100644 (file)
@@ -1540,6 +1540,8 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
 {
        ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
 }
+void ieee80211_flush_queues(struct ieee80211_local *local,
+                           struct ieee80211_sub_if_data *sdata);
 
 void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
                         u16 transaction, u16 auth_alg, u16 status,
index 80e838bc875dbd61bebb144e1cd1a4c86aa2a17c..d646e12e55a6ea3512efa0fc39caaffc2d69c7ba 100644 (file)
@@ -92,7 +92,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
        if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
                return 0;
 
-       drv_flush(local, false);
+       ieee80211_flush_queues(local, NULL);
 
        local->hw.conf.flags |= IEEE80211_CONF_IDLE;
        return IEEE80211_CONF_CHANGE_IDLE;
index fdc06e381c101c603a27f6001e04c9af42d0009b..65b38e13eb0c59a05f387b8de416673182bc7f1e 100644 (file)
@@ -1436,7 +1436,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
                else {
                        ieee80211_send_nullfunc(local, sdata, 1);
                        /* Flush to get the tx status of nullfunc frame */
-                       drv_flush(local, false);
+                       ieee80211_flush_queues(local, sdata);
                }
        }
 
@@ -1767,7 +1767,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
        if (tx)
-               drv_flush(local, false);
+               ieee80211_flush_queues(local, sdata);
 
        /* deauthenticate/disassociate now */
        if (tx || frame_buf)
@@ -1776,7 +1776,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        /* flush out frame */
        if (tx)
-               drv_flush(local, false);
+               ieee80211_flush_queues(local, sdata);
 
        /* clear bssid only after building the needed mgmt frames */
        memset(ifmgd->bssid, 0, ETH_ALEN);
@@ -1948,7 +1948,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
        ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
        run_again(ifmgd, ifmgd->probe_timeout);
        if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
-               drv_flush(sdata->local, false);
+               ieee80211_flush_queues(sdata->local, sdata);
 }
 
 static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
index db547fceaeb9cc68d7313aa004c25f8ac61d1389..d32f514074b962747f86d54cc9877b1d19479624 100644 (file)
@@ -120,7 +120,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
         */
        ieee80211_stop_queues_by_reason(&local->hw,
                                        IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
-       drv_flush(local, false);
+       ieee80211_flush_queues(local, NULL);
 
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
@@ -373,7 +373,7 @@ void ieee80211_sw_roc_work(struct work_struct *work)
                ieee80211_roc_notify_destroy(roc);
 
                if (started) {
-                       drv_flush(local, false);
+                       ieee80211_flush_queues(local, NULL);
 
                        local->tmp_channel = NULL;
                        ieee80211_hw_config(local, 0);
index b471a67f224d59b7a47b2b277761297353e208ce..497f21a0d1162d2e31ccc978ec8cf79308ca4723 100644 (file)
@@ -35,7 +35,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        /* flush out all packets */
        synchronize_net();
 
-       drv_flush(local, false);
+       ieee80211_flush_queues(local, NULL);
 
        local->quiescing = true;
        /* make quiescing visible to timers everywhere */
index 5dc17c623f72411b83106e5de6ebdb163481887b..cb34cbbaa20ce9f003b22f17e5def519d83873af 100644 (file)
@@ -332,7 +332,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        ieee80211_offchannel_stop_vifs(local);
 
        /* ensure nullfunc is transmitted before leaving operating channel */
-       drv_flush(local, false);
+       ieee80211_flush_queues(local, NULL);
 
        ieee80211_configure_filter(local);
 
@@ -668,7 +668,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local,
        ieee80211_offchannel_stop_vifs(local);
 
        if (local->ops->flush) {
-               drv_flush(local, false);
+               ieee80211_flush_queues(local, NULL);
                *next_delay = 0;
        } else
                *next_delay = HZ / 10;
index d97e4305cf1eef4200cfd5b8e459a441bc27ead4..c5899797a8d4b0f01da791da6e2b1be8a685627f 100644 (file)
@@ -964,23 +964,26 @@ TRACE_EVENT(drv_get_survey,
 );
 
 TRACE_EVENT(drv_flush,
-       TP_PROTO(struct ieee80211_local *local, bool drop),
+       TP_PROTO(struct ieee80211_local *local,
+                u32 queues, bool drop),
 
-       TP_ARGS(local, drop),
+       TP_ARGS(local, queues, drop),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
                __field(bool, drop)
+               __field(u32, queues)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
                __entry->drop = drop;
+               __entry->queues = queues;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " drop:%d",
-               LOCAL_PR_ARG, __entry->drop
+               LOCAL_PR_FMT " queues:0x%x drop:%d",
+               LOCAL_PR_ARG, __entry->queues, __entry->drop
        )
 );
 
index b7a856e3281bb1705e082ae9a57edd136a71cb91..f978ddd1bb43b22bb3645a505b369fa6324778e9 100644 (file)
@@ -511,6 +511,31 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_wake_queues);
 
+void ieee80211_flush_queues(struct ieee80211_local *local,
+                           struct ieee80211_sub_if_data *sdata)
+{
+       u32 queues;
+
+       if (!local->ops->flush)
+               return;
+
+       if (sdata && local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) {
+               int ac;
+
+               queues = 0;
+
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+                       queues |= BIT(sdata->vif.hw_queue[ac]);
+               if (sdata->vif.cab_queue != IEEE80211_INVAL_HW_QUEUE)
+                       queues |= BIT(sdata->vif.cab_queue);
+       } else {
+               /* all queues */
+               queues = BIT(local->hw.queues) - 1;
+       }
+
+       drv_flush(local, queues, false);
+}
+
 void ieee80211_iterate_active_interfaces(
        struct ieee80211_hw *hw, u32 iter_flags,
        void (*iterator)(void *data, u8 *mac,