diff options
author | Andrei Otcheretianski <andrei.otcheretianski@intel.com> | 2013-10-21 23:01:12 -0400 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-05-06 16:32:46 -0400 |
commit | bd3398e2864e264842f5f702e5a69e30582a4d18 (patch) | |
tree | f977a2dc62827f6efe1d8094c77c18bb18d3dfe0 /drivers/net/wireless/iwlwifi | |
parent | 9256c2051d39ac5a56685b70b8dfaf87be59cb28 (diff) |
iwlwifi:mvm: Add AP/GO channel switch support
Publish WIPHY_FLAG_HAS_CHANNEL_SWITCH if the fw supports
newly introduced IWL_UCODE_TLV_API_CSA_FLOW.
When CSA starts, save the switching vif inside mvm and during the CSA period
configure fw with a new beacon after each beacon transmission in order to
update the csa counters.
Also, handle correctly the CSA unbind-bind flow which is triggered by mac80211
when the actual channel switch happens.
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Reviewed-by: Luciano Coelho <luciano.coelho@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-fw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 12 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 44 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/ops.c | 2 |
5 files changed, 60 insertions, 2 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index f5927d0cf9b6..6fea27c0dd8e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -116,9 +116,11 @@ enum iwl_ucode_tlv_flag { | |||
116 | /** | 116 | /** |
117 | * enum iwl_ucode_tlv_api - ucode api | 117 | * enum iwl_ucode_tlv_api - ucode api |
118 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. | 118 | * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field. |
119 | * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA. | ||
119 | */ | 120 | */ |
120 | enum iwl_ucode_tlv_api { | 121 | enum iwl_ucode_tlv_api { |
121 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), | 122 | IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0), |
123 | IWL_UCODE_TLV_API_CSA_FLOW = BIT(4), | ||
122 | }; | 124 | }; |
123 | 125 | ||
124 | /** | 126 | /** |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index 7110ec2605d6..56cf58e95698 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -1237,11 +1237,23 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
1237 | u32 rate __maybe_unused = | 1237 | u32 rate __maybe_unused = |
1238 | le32_to_cpu(beacon->beacon_notify_hdr.initial_rate); | 1238 | le32_to_cpu(beacon->beacon_notify_hdr.initial_rate); |
1239 | 1239 | ||
1240 | lockdep_assert_held(&mvm->mutex); | ||
1241 | |||
1240 | IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n", | 1242 | IWL_DEBUG_RX(mvm, "beacon status %#x retries:%d tsf:0x%16llX rate:%d\n", |
1241 | status & TX_STATUS_MSK, | 1243 | status & TX_STATUS_MSK, |
1242 | beacon->beacon_notify_hdr.failure_frame, | 1244 | beacon->beacon_notify_hdr.failure_frame, |
1243 | le64_to_cpu(beacon->tsf), | 1245 | le64_to_cpu(beacon->tsf), |
1244 | rate); | 1246 | rate); |
1247 | |||
1248 | if (unlikely(mvm->csa_vif && mvm->csa_vif->csa_active)) { | ||
1249 | if (!ieee80211_csa_is_complete(mvm->csa_vif)) { | ||
1250 | iwl_mvm_mac_ctxt_beacon_changed(mvm, mvm->csa_vif); | ||
1251 | } else { | ||
1252 | ieee80211_csa_finish(mvm->csa_vif); | ||
1253 | mvm->csa_vif = NULL; | ||
1254 | } | ||
1255 | } | ||
1256 | |||
1245 | return 0; | 1257 | return 0; |
1246 | } | 1258 | } |
1247 | 1259 | ||
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index db55d670dce0..34626249c685 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -320,6 +320,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
320 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) | 320 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) |
321 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 321 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
322 | 322 | ||
323 | if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_CSA_FLOW) | ||
324 | hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; | ||
325 | |||
323 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; | 326 | hw->wiphy->iface_combinations = iwl_mvm_iface_combinations; |
324 | hw->wiphy->n_iface_combinations = | 327 | hw->wiphy->n_iface_combinations = |
325 | ARRAY_SIZE(iwl_mvm_iface_combinations); | 328 | ARRAY_SIZE(iwl_mvm_iface_combinations); |
@@ -2198,6 +2201,11 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
2198 | 2201 | ||
2199 | switch (vif->type) { | 2202 | switch (vif->type) { |
2200 | case NL80211_IFTYPE_AP: | 2203 | case NL80211_IFTYPE_AP: |
2204 | /* Unless it's a CSA flow we have nothing to do here */ | ||
2205 | if (vif->csa_active) { | ||
2206 | mvmvif->ap_ibss_active = true; | ||
2207 | break; | ||
2208 | } | ||
2201 | case NL80211_IFTYPE_ADHOC: | 2209 | case NL80211_IFTYPE_ADHOC: |
2202 | /* | 2210 | /* |
2203 | * The AP binding flow is handled as part of the start_ap flow | 2211 | * The AP binding flow is handled as part of the start_ap flow |
@@ -2234,6 +2242,12 @@ static int iwl_mvm_assign_vif_chanctx(struct ieee80211_hw *hw, | |||
2234 | goto out_remove_binding; | 2242 | goto out_remove_binding; |
2235 | } | 2243 | } |
2236 | 2244 | ||
2245 | /* Handle binding during CSA */ | ||
2246 | if (vif->type == NL80211_IFTYPE_AP) { | ||
2247 | iwl_mvm_update_quotas(mvm, vif); | ||
2248 | iwl_mvm_mac_ctxt_changed(mvm, vif); | ||
2249 | } | ||
2250 | |||
2237 | goto out_unlock; | 2251 | goto out_unlock; |
2238 | 2252 | ||
2239 | out_remove_binding: | 2253 | out_remove_binding: |
@@ -2258,13 +2272,20 @@ static void iwl_mvm_unassign_vif_chanctx(struct ieee80211_hw *hw, | |||
2258 | iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); | 2272 | iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); |
2259 | 2273 | ||
2260 | switch (vif->type) { | 2274 | switch (vif->type) { |
2261 | case NL80211_IFTYPE_AP: | ||
2262 | case NL80211_IFTYPE_ADHOC: | 2275 | case NL80211_IFTYPE_ADHOC: |
2263 | goto out_unlock; | 2276 | goto out_unlock; |
2264 | case NL80211_IFTYPE_MONITOR: | 2277 | case NL80211_IFTYPE_MONITOR: |
2265 | mvmvif->monitor_active = false; | 2278 | mvmvif->monitor_active = false; |
2266 | iwl_mvm_update_quotas(mvm, NULL); | 2279 | iwl_mvm_update_quotas(mvm, NULL); |
2267 | break; | 2280 | break; |
2281 | case NL80211_IFTYPE_AP: | ||
2282 | /* This part is triggered only during CSA */ | ||
2283 | if (!vif->csa_active || !mvmvif->ap_ibss_active) | ||
2284 | goto out_unlock; | ||
2285 | |||
2286 | mvmvif->ap_ibss_active = false; | ||
2287 | iwl_mvm_update_quotas(mvm, NULL); | ||
2288 | /*TODO: bt_coex notification here? */ | ||
2268 | default: | 2289 | default: |
2269 | break; | 2290 | break; |
2270 | } | 2291 | } |
@@ -2360,6 +2381,25 @@ static int iwl_mvm_mac_testmode_cmd(struct ieee80211_hw *hw, | |||
2360 | } | 2381 | } |
2361 | #endif | 2382 | #endif |
2362 | 2383 | ||
2384 | static void iwl_mvm_channel_switch_beacon(struct ieee80211_hw *hw, | ||
2385 | struct ieee80211_vif *vif, | ||
2386 | struct cfg80211_chan_def *chandef) | ||
2387 | { | ||
2388 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
2389 | |||
2390 | mutex_lock(&mvm->mutex); | ||
2391 | if (WARN(mvm->csa_vif && mvm->csa_vif->csa_active, | ||
2392 | "Another CSA is already in progress")) | ||
2393 | goto out_unlock; | ||
2394 | |||
2395 | IWL_DEBUG_MAC80211(mvm, "CSA started to freq %d\n", | ||
2396 | chandef->center_freq1); | ||
2397 | mvm->csa_vif = vif; | ||
2398 | |||
2399 | out_unlock: | ||
2400 | mutex_unlock(&mvm->mutex); | ||
2401 | } | ||
2402 | |||
2363 | const struct ieee80211_ops iwl_mvm_hw_ops = { | 2403 | const struct ieee80211_ops iwl_mvm_hw_ops = { |
2364 | .tx = iwl_mvm_mac_tx, | 2404 | .tx = iwl_mvm_mac_tx, |
2365 | .ampdu_action = iwl_mvm_mac_ampdu_action, | 2405 | .ampdu_action = iwl_mvm_mac_ampdu_action, |
@@ -2402,6 +2442,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { | |||
2402 | 2442 | ||
2403 | .set_tim = iwl_mvm_set_tim, | 2443 | .set_tim = iwl_mvm_set_tim, |
2404 | 2444 | ||
2445 | .channel_switch_beacon = iwl_mvm_channel_switch_beacon, | ||
2446 | |||
2405 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) | 2447 | CFG80211_TESTMODE_CMD(iwl_mvm_mac_testmode_cmd) |
2406 | 2448 | ||
2407 | #ifdef CONFIG_PM_SLEEP | 2449 | #ifdef CONFIG_PM_SLEEP |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 1575ac7c5864..1e468c3e8dea 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -644,6 +644,8 @@ struct iwl_mvm { | |||
644 | 644 | ||
645 | /* Indicate if device power save is allowed */ | 645 | /* Indicate if device power save is allowed */ |
646 | bool ps_disabled; | 646 | bool ps_disabled; |
647 | |||
648 | struct ieee80211_vif *csa_vif; | ||
647 | }; | 649 | }; |
648 | 650 | ||
649 | /* Extract MVM priv from op_mode and _hw */ | 651 | /* Extract MVM priv from op_mode and _hw */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index cd526e198ae2..f8530b329d17 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -220,7 +220,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { | |||
220 | RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), | 220 | RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), |
221 | 221 | ||
222 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), | 222 | RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_notif, true), |
223 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, false), | 223 | RX_HANDLER(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, true), |
224 | RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), | 224 | RX_HANDLER(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, true), |
225 | RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION, | 225 | RX_HANDLER(ANTENNA_COUPLING_NOTIFICATION, |
226 | iwl_mvm_rx_ant_coupling_notif, true), | 226 | iwl_mvm_rx_ant_coupling_notif, true), |