aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>2013-10-21 23:01:12 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-05-06 16:32:46 -0400
commitbd3398e2864e264842f5f702e5a69e30582a4d18 (patch)
treef977a2dc62827f6efe1d8094c77c18bb18d3dfe0 /drivers/net/wireless/iwlwifi
parent9256c2051d39ac5a56685b70b8dfaf87be59cb28 (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.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c12
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c44
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c2
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 */
120enum iwl_ucode_tlv_api { 121enum 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
2384static 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
2399out_unlock:
2400 mutex_unlock(&mvm->mutex);
2401}
2402
2363const struct ieee80211_ops iwl_mvm_hw_ops = { 2403const 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),