mac80211: pass queue bitmap to flush operation
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>
This commit is contained in:
parent
a0ca796c46
commit
39ecc01d1b
@ -1091,7 +1091,7 @@ static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
|
|||||||
return ret;
|
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;
|
struct ar5523 *ar = hw->priv;
|
||||||
|
|
||||||
|
@ -1745,7 +1745,7 @@ static void ath9k_set_coverage_class(struct ieee80211_hw *hw, u8 coverage_class)
|
|||||||
mutex_unlock(&sc->mutex);
|
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_softc *sc = hw->priv;
|
||||||
struct ath_hw *ah = sc->sc_ah;
|
struct ath_hw *ah = sc->sc_ah;
|
||||||
|
@ -1703,7 +1703,7 @@ found:
|
|||||||
return 0;
|
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;
|
struct ar9170 *ar = hw->priv;
|
||||||
unsigned int vid;
|
unsigned int vid;
|
||||||
|
@ -723,7 +723,7 @@ static bool brcms_tx_flush_completed(struct brcms_info *wl)
|
|||||||
return result;
|
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;
|
struct brcms_info *wl = hw->priv;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -4704,8 +4704,7 @@ out:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(il_mac_change_interface);
|
EXPORT_SYMBOL(il_mac_change_interface);
|
||||||
|
|
||||||
void
|
void il_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
|
||||||
il_mac_flush(struct ieee80211_hw *hw, bool drop)
|
|
||||||
{
|
{
|
||||||
struct il_priv *il = hw->priv;
|
struct il_priv *il = hw->priv;
|
||||||
unsigned long timeout = jiffies + msecs_to_jiffies(500);
|
unsigned long timeout = jiffies + msecs_to_jiffies(500);
|
||||||
|
@ -1720,7 +1720,7 @@ void il_mac_remove_interface(struct ieee80211_hw *hw,
|
|||||||
struct ieee80211_vif *vif);
|
struct ieee80211_vif *vif);
|
||||||
int il_mac_change_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);
|
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);
|
int il_alloc_txq_mem(struct il_priv *il);
|
||||||
void il_free_txq_mem(struct il_priv *il);
|
void il_free_txq_mem(struct il_priv *il);
|
||||||
|
|
||||||
|
@ -1100,7 +1100,7 @@ static void iwlagn_configure_filter(struct ieee80211_hw *hw,
|
|||||||
FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
|
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);
|
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
|
||||||
|
|
||||||
|
@ -1389,7 +1389,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
|
|||||||
return 0;
|
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 */
|
/* Not implemented, queues only on kernel side */
|
||||||
}
|
}
|
||||||
|
@ -670,7 +670,7 @@ static unsigned int p54_flush_count(struct p54_common *priv)
|
|||||||
return total;
|
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;
|
struct p54_common *priv = dev->priv;
|
||||||
unsigned int total, i;
|
unsigned int total, i;
|
||||||
|
@ -1360,7 +1360,7 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw,
|
|||||||
struct ieee80211_vif *vif, u16 queue,
|
struct ieee80211_vif *vif, u16 queue,
|
||||||
const struct ieee80211_tx_queue_params *params);
|
const struct ieee80211_tx_queue_params *params);
|
||||||
void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw);
|
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_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);
|
int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
|
||||||
void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
|
void rt2x00mac_get_ringparam(struct ieee80211_hw *hw,
|
||||||
|
@ -748,7 +748,7 @@ void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll);
|
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 rt2x00_dev *rt2x00dev = hw->priv;
|
||||||
struct data_queue *queue;
|
struct data_queue *queue;
|
||||||
|
@ -1166,7 +1166,7 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw)
|
|||||||
* before switch channle or power save, or tx buffer packet
|
* before switch channle or power save, or tx buffer packet
|
||||||
* maybe send after offchannel or rf sleep, this may cause
|
* maybe send after offchannel or rf sleep, this may cause
|
||||||
* dis-association by AP */
|
* 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);
|
struct rtl_priv *rtlpriv = rtl_priv(hw);
|
||||||
|
|
||||||
|
@ -4946,7 +4946,7 @@ out:
|
|||||||
mutex_unlock(&wl->mutex);
|
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;
|
struct wl1271 *wl = hw->priv;
|
||||||
|
|
||||||
|
@ -2438,8 +2438,11 @@ enum ieee80211_roc_type {
|
|||||||
* @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep.
|
* @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep.
|
||||||
*
|
*
|
||||||
* @flush: Flush all pending frames from the hardware queue, making sure
|
* @flush: Flush all pending frames from the hardware queue, making sure
|
||||||
* that the hardware queues are empty. If the parameter @drop is set
|
* that the hardware queues are empty. The @queues parameter is a bitmap
|
||||||
* to %true, pending frames may be dropped. The callback can sleep.
|
* 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
|
* @channel_switch: Drivers that need (or want) to offload the channel
|
||||||
* switch operation for CSAs received from the AP may implement this
|
* switch operation for CSAs received from the AP may implement this
|
||||||
@ -2687,7 +2690,7 @@ struct ieee80211_ops {
|
|||||||
struct netlink_callback *cb,
|
struct netlink_callback *cb,
|
||||||
void *data, int len);
|
void *data, int len);
|
||||||
#endif
|
#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,
|
void (*channel_switch)(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_channel_switch *ch_switch);
|
struct ieee80211_channel_switch *ch_switch);
|
||||||
int (*napi_poll)(struct ieee80211_hw *hw, int budget);
|
int (*napi_poll)(struct ieee80211_hw *hw, int budget);
|
||||||
|
@ -720,13 +720,14 @@ static inline void drv_rfkill_poll(struct ieee80211_local *local)
|
|||||||
local->ops->rfkill_poll(&local->hw);
|
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();
|
might_sleep();
|
||||||
|
|
||||||
trace_drv_flush(local, drop);
|
trace_drv_flush(local, queues, drop);
|
||||||
if (local->ops->flush)
|
if (local->ops->flush)
|
||||||
local->ops->flush(&local->hw, drop);
|
local->ops->flush(&local->hw, queues, drop);
|
||||||
trace_drv_return_void(local);
|
trace_drv_return_void(local);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1540,6 +1540,8 @@ static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
|
|||||||
{
|
{
|
||||||
ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
|
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,
|
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
||||||
u16 transaction, u16 auth_alg, u16 status,
|
u16 transaction, u16 auth_alg, u16 status,
|
||||||
|
@ -92,7 +92,7 @@ static u32 ieee80211_idle_on(struct ieee80211_local *local)
|
|||||||
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
|
if (local->hw.conf.flags & IEEE80211_CONF_IDLE)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
drv_flush(local, false);
|
ieee80211_flush_queues(local, NULL);
|
||||||
|
|
||||||
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
|
local->hw.conf.flags |= IEEE80211_CONF_IDLE;
|
||||||
return IEEE80211_CONF_CHANGE_IDLE;
|
return IEEE80211_CONF_CHANGE_IDLE;
|
||||||
|
@ -1436,7 +1436,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
|
|||||||
else {
|
else {
|
||||||
ieee80211_send_nullfunc(local, sdata, 1);
|
ieee80211_send_nullfunc(local, sdata, 1);
|
||||||
/* Flush to get the tx status of nullfunc frame */
|
/* 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 */
|
/* flush out any pending frame (e.g. DELBA) before deauth/disassoc */
|
||||||
if (tx)
|
if (tx)
|
||||||
drv_flush(local, false);
|
ieee80211_flush_queues(local, sdata);
|
||||||
|
|
||||||
/* deauthenticate/disassociate now */
|
/* deauthenticate/disassociate now */
|
||||||
if (tx || frame_buf)
|
if (tx || frame_buf)
|
||||||
@ -1776,7 +1776,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
|
|||||||
|
|
||||||
/* flush out frame */
|
/* flush out frame */
|
||||||
if (tx)
|
if (tx)
|
||||||
drv_flush(local, false);
|
ieee80211_flush_queues(local, sdata);
|
||||||
|
|
||||||
/* clear bssid only after building the needed mgmt frames */
|
/* clear bssid only after building the needed mgmt frames */
|
||||||
memset(ifmgd->bssid, 0, ETH_ALEN);
|
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);
|
ifmgd->probe_timeout = jiffies + msecs_to_jiffies(probe_wait_ms);
|
||||||
run_again(ifmgd, ifmgd->probe_timeout);
|
run_again(ifmgd, ifmgd->probe_timeout);
|
||||||
if (sdata->local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS)
|
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,
|
static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata,
|
||||||
|
@ -120,7 +120,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local)
|
|||||||
*/
|
*/
|
||||||
ieee80211_stop_queues_by_reason(&local->hw,
|
ieee80211_stop_queues_by_reason(&local->hw,
|
||||||
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
|
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL);
|
||||||
drv_flush(local, false);
|
ieee80211_flush_queues(local, NULL);
|
||||||
|
|
||||||
mutex_lock(&local->iflist_mtx);
|
mutex_lock(&local->iflist_mtx);
|
||||||
list_for_each_entry(sdata, &local->interfaces, list) {
|
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);
|
ieee80211_roc_notify_destroy(roc);
|
||||||
|
|
||||||
if (started) {
|
if (started) {
|
||||||
drv_flush(local, false);
|
ieee80211_flush_queues(local, NULL);
|
||||||
|
|
||||||
local->tmp_channel = NULL;
|
local->tmp_channel = NULL;
|
||||||
ieee80211_hw_config(local, 0);
|
ieee80211_hw_config(local, 0);
|
||||||
|
@ -35,7 +35,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
|
|||||||
/* flush out all packets */
|
/* flush out all packets */
|
||||||
synchronize_net();
|
synchronize_net();
|
||||||
|
|
||||||
drv_flush(local, false);
|
ieee80211_flush_queues(local, NULL);
|
||||||
|
|
||||||
local->quiescing = true;
|
local->quiescing = true;
|
||||||
/* make quiescing visible to timers everywhere */
|
/* make quiescing visible to timers everywhere */
|
||||||
|
@ -332,7 +332,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
|
|||||||
ieee80211_offchannel_stop_vifs(local);
|
ieee80211_offchannel_stop_vifs(local);
|
||||||
|
|
||||||
/* ensure nullfunc is transmitted before leaving operating channel */
|
/* ensure nullfunc is transmitted before leaving operating channel */
|
||||||
drv_flush(local, false);
|
ieee80211_flush_queues(local, NULL);
|
||||||
|
|
||||||
ieee80211_configure_filter(local);
|
ieee80211_configure_filter(local);
|
||||||
|
|
||||||
@ -668,7 +668,7 @@ static void ieee80211_scan_state_resume(struct ieee80211_local *local,
|
|||||||
ieee80211_offchannel_stop_vifs(local);
|
ieee80211_offchannel_stop_vifs(local);
|
||||||
|
|
||||||
if (local->ops->flush) {
|
if (local->ops->flush) {
|
||||||
drv_flush(local, false);
|
ieee80211_flush_queues(local, NULL);
|
||||||
*next_delay = 0;
|
*next_delay = 0;
|
||||||
} else
|
} else
|
||||||
*next_delay = HZ / 10;
|
*next_delay = HZ / 10;
|
||||||
|
@ -964,23 +964,26 @@ TRACE_EVENT(drv_get_survey,
|
|||||||
);
|
);
|
||||||
|
|
||||||
TRACE_EVENT(drv_flush,
|
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(
|
TP_STRUCT__entry(
|
||||||
LOCAL_ENTRY
|
LOCAL_ENTRY
|
||||||
__field(bool, drop)
|
__field(bool, drop)
|
||||||
|
__field(u32, queues)
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
LOCAL_ASSIGN;
|
LOCAL_ASSIGN;
|
||||||
__entry->drop = drop;
|
__entry->drop = drop;
|
||||||
|
__entry->queues = queues;
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk(
|
TP_printk(
|
||||||
LOCAL_PR_FMT " drop:%d",
|
LOCAL_PR_FMT " queues:0x%x drop:%d",
|
||||||
LOCAL_PR_ARG, __entry->drop
|
LOCAL_PR_ARG, __entry->queues, __entry->drop
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -511,6 +511,31 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ieee80211_wake_queues);
|
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(
|
void ieee80211_iterate_active_interfaces(
|
||||||
struct ieee80211_hw *hw, u32 iter_flags,
|
struct ieee80211_hw *hw, u32 iter_flags,
|
||||||
void (*iterator)(void *data, u8 *mac,
|
void (*iterator)(void *data, u8 *mac,
|
||||||
|
Loading…
Reference in New Issue
Block a user