mac80211: allow channel switch with multiple channel contexts

Channel switch with multiple channel contexts should now work fine.
Remove check that disallows switches when multiple contexts are in
use.

Signed-off-by: Luciano Coelho <luciano.coelho@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Luciano Coelho 2014-10-08 09:48:40 +03:00 committed by Johannes Berg
parent 0c21e6320f
commit 0f791eb47f
8 changed files with 34 additions and 40 deletions

View File

@ -6063,7 +6063,7 @@ il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
} }
void void
il4965_mac_channel_switch(struct ieee80211_hw *hw, il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch) struct ieee80211_channel_switch *ch_switch)
{ {
struct il_priv *il = hw->priv; struct il_priv *il = hw->priv;

View File

@ -187,8 +187,9 @@ int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u8 buf_size); u8 buf_size);
int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta); struct ieee80211_sta *sta);
void il4965_mac_channel_switch(struct ieee80211_hw *hw, void
struct ieee80211_channel_switch *ch_switch); il4965_mac_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch);
void il4965_led_enable(struct il_priv *il); void il4965_led_enable(struct il_priv *il);

View File

@ -941,6 +941,7 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw,
} }
static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw, static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch) struct ieee80211_channel_switch *ch_switch)
{ {
struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);

View File

@ -5177,10 +5177,11 @@ out:
} }
static void wl12xx_op_channel_switch(struct ieee80211_hw *hw, static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch) struct ieee80211_channel_switch *ch_switch)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
int ret; int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch"); wl1271_debug(DEBUG_MAC80211, "mac80211 channel switch");
@ -5190,14 +5191,8 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
mutex_lock(&wl->mutex); mutex_lock(&wl->mutex);
if (unlikely(wl->state == WLCORE_STATE_OFF)) { if (unlikely(wl->state == WLCORE_STATE_OFF)) {
wl12xx_for_each_wlvif_sta(wl, wlvif) { if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
continue;
ieee80211_chswitch_done(vif, false); ieee80211_chswitch_done(vif, false);
}
goto out; goto out;
} else if (unlikely(wl->state != WLCORE_STATE_ON)) { } else if (unlikely(wl->state != WLCORE_STATE_ON)) {
goto out; goto out;
@ -5208,11 +5203,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
goto out; goto out;
/* TODO: change mac80211 to pass vif as param */ /* TODO: change mac80211 to pass vif as param */
wl12xx_for_each_wlvif_sta(wl, wlvif) {
unsigned long delay_usec;
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
continue; unsigned long delay_usec;
ret = wl->ops->channel_switch(wl, wlvif, ch_switch); ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
if (ret) if (ret)
@ -5222,10 +5215,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
/* indicate failure 5 seconds after channel switch time */ /* indicate failure 5 seconds after channel switch time */
delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) * delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
ch_switch->count; ch_switch->count;
ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work, ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
usecs_to_jiffies(delay_usec) + usecs_to_jiffies(delay_usec) +
msecs_to_jiffies(5000)); msecs_to_jiffies(5000));
} }
out_sleep: out_sleep:

View File

@ -2969,6 +2969,7 @@ struct ieee80211_ops {
void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop); u32 queues, bool drop);
void (*channel_switch)(struct ieee80211_hw *hw, void (*channel_switch)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel_switch *ch_switch); struct ieee80211_channel_switch *ch_switch);
int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant);
int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);

View File

@ -764,12 +764,13 @@ static inline void drv_flush(struct ieee80211_local *local,
} }
static inline void drv_channel_switch(struct ieee80211_local *local, static inline void drv_channel_switch(struct ieee80211_local *local,
struct ieee80211_channel_switch *ch_switch) struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel_switch *ch_switch)
{ {
might_sleep(); might_sleep();
trace_drv_channel_switch(local, ch_switch); trace_drv_channel_switch(local, sdata, ch_switch);
local->ops->channel_switch(&local->hw, ch_switch); local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch);
trace_drv_return_void(local); trace_drv_return_void(local);
} }

View File

@ -1134,21 +1134,15 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
chanctx = container_of(conf, struct ieee80211_chanctx, conf); chanctx = container_of(conf, struct ieee80211_chanctx, conf);
if (local->use_chanctx) { if (local->use_chanctx &&
u32 num_chanctx = 0; !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
list_for_each_entry(chanctx, &local->chanctx_list, list) sdata_info(sdata,
num_chanctx++; "driver doesn't support chan-switch with channel contexts\n");
ieee80211_queue_work(&local->hw,
if (num_chanctx > 1 || &ifmgd->csa_connection_drop_work);
!(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) { mutex_unlock(&local->chanctx_mtx);
sdata_info(sdata, mutex_unlock(&local->mtx);
"not handling chan-switch with channel contexts\n"); return;
ieee80211_queue_work(&local->hw,
&ifmgd->csa_connection_drop_work);
mutex_unlock(&local->chanctx_mtx);
mutex_unlock(&local->mtx);
return;
}
} }
ch_switch.timestamp = timestamp; ch_switch.timestamp = timestamp;
@ -1192,7 +1186,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
if (local->ops->channel_switch) { if (local->ops->channel_switch) {
/* use driver's channel switch callback */ /* use driver's channel switch callback */
drv_channel_switch(local, &ch_switch); drv_channel_switch(local, sdata, &ch_switch);
return; return;
} }

View File

@ -987,12 +987,14 @@ TRACE_EVENT(drv_flush,
TRACE_EVENT(drv_channel_switch, TRACE_EVENT(drv_channel_switch,
TP_PROTO(struct ieee80211_local *local, TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
struct ieee80211_channel_switch *ch_switch), struct ieee80211_channel_switch *ch_switch),
TP_ARGS(local, ch_switch), TP_ARGS(local, sdata, ch_switch),
TP_STRUCT__entry( TP_STRUCT__entry(
LOCAL_ENTRY LOCAL_ENTRY
VIF_ENTRY
CHANDEF_ENTRY CHANDEF_ENTRY
__field(u64, timestamp) __field(u64, timestamp)
__field(u32, device_timestamp) __field(u32, device_timestamp)
@ -1002,6 +1004,7 @@ TRACE_EVENT(drv_channel_switch,
TP_fast_assign( TP_fast_assign(
LOCAL_ASSIGN; LOCAL_ASSIGN;
VIF_ASSIGN;
CHANDEF_ASSIGN(&ch_switch->chandef) CHANDEF_ASSIGN(&ch_switch->chandef)
__entry->timestamp = ch_switch->timestamp; __entry->timestamp = ch_switch->timestamp;
__entry->device_timestamp = ch_switch->device_timestamp; __entry->device_timestamp = ch_switch->device_timestamp;
@ -1010,8 +1013,8 @@ TRACE_EVENT(drv_channel_switch,
), ),
TP_printk( TP_printk(
LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d", LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count
) )
); );