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;
 
 
        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;
 
        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;
 
        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;
 
 }
 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);
 
                             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);
 
 
                        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);
 
 
        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 */
 }
 
        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;
 
                      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,
 
 }
 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;
 
  * 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);
 
 
        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;
 
 
  * @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
                             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);
 
                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);
 }
 
 
 {
        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,
 
        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;
 
                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);
                }
        }
 
 
        /* 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)
 
        /* 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);
        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,
 
         */
        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) {
                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);
 
        /* flush out all packets */
        synchronize_net();
 
-       drv_flush(local, false);
+       ieee80211_flush_queues(local, NULL);
 
        local->quiescing = true;
        /* make quiescing visible to timers everywhere */
 
        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);
 
        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;
 
 );
 
 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
        )
 );
 
 
 }
 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,