mac80211: allow channel switch with multiple channel contexts
authorLuciano Coelho <luciano.coelho@intel.com>
Wed, 8 Oct 2014 06:48:40 +0000 (09:48 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 9 Oct 2014 09:30:09 +0000 (11:30 +0200)
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>
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/4965.h
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/ti/wlcore/main.c
include/net/mac80211.h
net/mac80211/driver-ops.h
net/mac80211/mlme.c
net/mac80211/trace.h

index 26fec54dcd0300a7f6ec5cc96267acc917de56ea..2748fde4b90c0fa5113240765b06aaceeeeeb331 100644 (file)
@@ -6063,7 +6063,7 @@ il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 }
 
 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 il_priv *il = hw->priv;
index 337dfcf3bbde7c58fe4681268f63b9d29ea8f5fa..3a57f71b8ed57fbb98761901968ee4e4cc0110f8 100644 (file)
@@ -187,8 +187,9 @@ int il4965_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            u8 buf_size);
 int il4965_mac_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta);
-void il4965_mac_channel_switch(struct ieee80211_hw *hw,
-                              struct ieee80211_channel_switch *ch_switch);
+void
+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);
 
index 2364a3c09b9eb8037ba6237112c679749a3ac94c..a967bf893a89a5417e16c1adeb8beedd2ce15e2f 100644 (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,
+                                     struct ieee80211_vif *vif,
                                      struct ieee80211_channel_switch *ch_switch)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
index 575c8f6d4009477dc6430b7eff91ab6d8a60e080..6ad3fcedab9b29fa92c9fb37eb65037a5b6d6f0f 100644 (file)
@@ -5177,10 +5177,11 @@ out:
 }
 
 static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
                                     struct ieee80211_channel_switch *ch_switch)
 {
        struct wl1271 *wl = hw->priv;
-       struct wl12xx_vif *wlvif;
+       struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
        int ret;
 
        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);
 
        if (unlikely(wl->state == WLCORE_STATE_OFF)) {
-               wl12xx_for_each_wlvif_sta(wl, wlvif) {
-                       struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
-
-                       if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
-                               continue;
-
+               if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
                        ieee80211_chswitch_done(vif, false);
-               }
                goto out;
        } else if (unlikely(wl->state != WLCORE_STATE_ON)) {
                goto out;
@@ -5208,11 +5203,9 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
                goto out;
 
        /* 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))
-                       continue;
+       if (test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) {
+               unsigned long delay_usec;
 
                ret = wl->ops->channel_switch(wl, wlvif, ch_switch);
                if (ret)
@@ -5222,10 +5215,10 @@ static void wl12xx_op_channel_switch(struct ieee80211_hw *hw,
 
                /* indicate failure 5 seconds after channel switch time */
                delay_usec = ieee80211_tu_to_usec(wlvif->beacon_int) *
-                            ch_switch->count;
+                       ch_switch->count;
                ieee80211_queue_delayed_work(hw, &wlvif->channel_switch_work,
-                               usecs_to_jiffies(delay_usec) +
-                               msecs_to_jiffies(5000));
+                                            usecs_to_jiffies(delay_usec) +
+                                            msecs_to_jiffies(5000));
        }
 
 out_sleep:
index 7861ed875c4db81c92c81cc1caca7064c6b66b4d..9bb2fc73aeaa92d8be60104bd0d71c21013c6c9e 100644 (file)
@@ -2969,6 +2969,7 @@ struct ieee80211_ops {
        void (*flush)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                      u32 queues, bool drop);
        void (*channel_switch)(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
                               struct ieee80211_channel_switch *ch_switch);
        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);
index 0a60906447698ab7f74471fc22e5f0d0086a3da6..1bbb0790264ffba09c3322f03700f52e17c014ec 100644 (file)
@@ -764,12 +764,13 @@ static inline void drv_flush(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();
 
-       trace_drv_channel_switch(local, ch_switch);
-       local->ops->channel_switch(&local->hw, ch_switch);
+       trace_drv_channel_switch(local, sdata, ch_switch);
+       local->ops->channel_switch(&local->hw, &sdata->vif, ch_switch);
        trace_drv_return_void(local);
 }
 
index 148253c1bd783f89a510471570df6b40db48aec6..fb6561509cafc1d0ded7fd0c1a4e4241abf4eac3 100644 (file)
@@ -1134,21 +1134,15 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        chanctx = container_of(conf, struct ieee80211_chanctx, conf);
 
-       if (local->use_chanctx) {
-               u32 num_chanctx = 0;
-               list_for_each_entry(chanctx, &local->chanctx_list, list)
-                      num_chanctx++;
-
-               if (num_chanctx > 1 ||
-                   !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
-                       sdata_info(sdata,
-                                  "not handling chan-switch with channel contexts\n");
-                       ieee80211_queue_work(&local->hw,
-                                            &ifmgd->csa_connection_drop_work);
-                       mutex_unlock(&local->chanctx_mtx);
-                       mutex_unlock(&local->mtx);
-                       return;
-               }
+       if (local->use_chanctx &&
+           !(local->hw.flags & IEEE80211_HW_CHANCTX_STA_CSA)) {
+               sdata_info(sdata,
+                          "driver doesn't support chan-switch with channel contexts\n");
+               ieee80211_queue_work(&local->hw,
+                                    &ifmgd->csa_connection_drop_work);
+               mutex_unlock(&local->chanctx_mtx);
+               mutex_unlock(&local->mtx);
+               return;
        }
 
        ch_switch.timestamp = timestamp;
@@ -1192,7 +1186,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
 
        if (local->ops->channel_switch) {
                /* use driver's channel switch callback */
-               drv_channel_switch(local, &ch_switch);
+               drv_channel_switch(local, sdata, &ch_switch);
                return;
        }
 
index ca0e12dd23c0a6e4882517296dba68b6d907e7c0..976606aebac972b55be40ca1b188dbdbf830f21b 100644 (file)
@@ -987,12 +987,14 @@ TRACE_EVENT(drv_flush,
 
 TRACE_EVENT(drv_channel_switch,
        TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
                 struct ieee80211_channel_switch *ch_switch),
 
-       TP_ARGS(local, ch_switch),
+       TP_ARGS(local, sdata, ch_switch),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                CHANDEF_ENTRY
                __field(u64, timestamp)
                __field(u32, device_timestamp)
@@ -1002,6 +1004,7 @@ TRACE_EVENT(drv_channel_switch,
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                CHANDEF_ASSIGN(&ch_switch->chandef)
                __entry->timestamp = ch_switch->timestamp;
                __entry->device_timestamp = ch_switch->device_timestamp;
@@ -1010,8 +1013,8 @@ TRACE_EVENT(drv_channel_switch,
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
-               LOCAL_PR_ARG, CHANDEF_PR_ARG, __entry->count
+               LOCAL_PR_FMT VIF_PR_FMT " new " CHANDEF_PR_FMT " count:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, CHANDEF_PR_ARG, __entry->count
        )
 );