diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/mvm/mac80211.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 180 |
1 files changed, 157 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 7396b52262b5..302c8cc50f25 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -86,6 +86,7 @@ | |||
86 | #include "iwl-fw-error-dump.h" | 86 | #include "iwl-fw-error-dump.h" |
87 | #include "iwl-prph.h" | 87 | #include "iwl-prph.h" |
88 | #include "iwl-csr.h" | 88 | #include "iwl-csr.h" |
89 | #include "iwl-nvm-parse.h" | ||
89 | 90 | ||
90 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { | 91 | static const struct ieee80211_iface_limit iwl_mvm_limits[] = { |
91 | { | 92 | { |
@@ -301,6 +302,109 @@ static void iwl_mvm_reset_phy_ctxts(struct iwl_mvm *mvm) | |||
301 | } | 302 | } |
302 | } | 303 | } |
303 | 304 | ||
305 | struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, | ||
306 | const char *alpha2, | ||
307 | enum iwl_mcc_source src_id, | ||
308 | bool *changed) | ||
309 | { | ||
310 | struct ieee80211_regdomain *regd = NULL; | ||
311 | struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); | ||
312 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||
313 | struct iwl_mcc_update_resp *resp; | ||
314 | |||
315 | IWL_DEBUG_LAR(mvm, "Getting regdomain data for %s from FW\n", alpha2); | ||
316 | |||
317 | lockdep_assert_held(&mvm->mutex); | ||
318 | |||
319 | resp = iwl_mvm_update_mcc(mvm, alpha2, src_id); | ||
320 | if (IS_ERR_OR_NULL(resp)) { | ||
321 | IWL_DEBUG_LAR(mvm, "Could not get update from FW %d\n", | ||
322 | PTR_RET(resp)); | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | if (changed) | ||
327 | *changed = (resp->status == MCC_RESP_NEW_CHAN_PROFILE); | ||
328 | |||
329 | regd = iwl_parse_nvm_mcc_info(mvm->trans->dev, mvm->cfg, | ||
330 | __le32_to_cpu(resp->n_channels), | ||
331 | resp->channels, | ||
332 | __le16_to_cpu(resp->mcc)); | ||
333 | /* Store the return source id */ | ||
334 | src_id = resp->source_id; | ||
335 | kfree(resp); | ||
336 | if (IS_ERR_OR_NULL(regd)) { | ||
337 | IWL_DEBUG_LAR(mvm, "Could not get parse update from FW %d\n", | ||
338 | PTR_RET(regd)); | ||
339 | goto out; | ||
340 | } | ||
341 | |||
342 | IWL_DEBUG_LAR(mvm, "setting alpha2 from FW to %s (0x%x, 0x%x) src=%d\n", | ||
343 | regd->alpha2, regd->alpha2[0], regd->alpha2[1], src_id); | ||
344 | mvm->lar_regdom_set = true; | ||
345 | mvm->mcc_src = src_id; | ||
346 | |||
347 | out: | ||
348 | return regd; | ||
349 | } | ||
350 | |||
351 | void iwl_mvm_update_changed_regdom(struct iwl_mvm *mvm) | ||
352 | { | ||
353 | bool changed; | ||
354 | struct ieee80211_regdomain *regd; | ||
355 | |||
356 | if (!iwl_mvm_is_lar_supported(mvm)) | ||
357 | return; | ||
358 | |||
359 | regd = iwl_mvm_get_current_regdomain(mvm, &changed); | ||
360 | if (!IS_ERR_OR_NULL(regd)) { | ||
361 | /* only update the regulatory core if changed */ | ||
362 | if (changed) | ||
363 | regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); | ||
364 | |||
365 | kfree(regd); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | struct ieee80211_regdomain *iwl_mvm_get_current_regdomain(struct iwl_mvm *mvm, | ||
370 | bool *changed) | ||
371 | { | ||
372 | return iwl_mvm_get_regdomain(mvm->hw->wiphy, "ZZ", | ||
373 | iwl_mvm_is_wifi_mcc_supported(mvm) ? | ||
374 | MCC_SOURCE_GET_CURRENT : | ||
375 | MCC_SOURCE_OLD_FW, changed); | ||
376 | } | ||
377 | |||
378 | int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) | ||
379 | { | ||
380 | enum iwl_mcc_source used_src; | ||
381 | struct ieee80211_regdomain *regd; | ||
382 | const struct ieee80211_regdomain *r = | ||
383 | rtnl_dereference(mvm->hw->wiphy->regd); | ||
384 | |||
385 | if (!r) | ||
386 | return 0; | ||
387 | |||
388 | /* save the last source in case we overwrite it below */ | ||
389 | used_src = mvm->mcc_src; | ||
390 | if (iwl_mvm_is_wifi_mcc_supported(mvm)) { | ||
391 | /* Notify the firmware we support wifi location updates */ | ||
392 | regd = iwl_mvm_get_current_regdomain(mvm, NULL); | ||
393 | if (!IS_ERR_OR_NULL(regd)) | ||
394 | kfree(regd); | ||
395 | } | ||
396 | |||
397 | /* Now set our last stored MCC and source */ | ||
398 | regd = iwl_mvm_get_regdomain(mvm->hw->wiphy, r->alpha2, used_src, NULL); | ||
399 | if (IS_ERR_OR_NULL(regd)) | ||
400 | return -EIO; | ||
401 | |||
402 | regulatory_set_wiphy_regd(mvm->hw->wiphy, regd); | ||
403 | kfree(regd); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
304 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | 408 | int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) |
305 | { | 409 | { |
306 | struct ieee80211_hw *hw = mvm->hw; | 410 | struct ieee80211_hw *hw = mvm->hw; |
@@ -356,8 +460,12 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) | |||
356 | BIT(NL80211_IFTYPE_ADHOC); | 460 | BIT(NL80211_IFTYPE_ADHOC); |
357 | 461 | ||
358 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; | 462 | hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; |
359 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | | 463 | hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR; |
360 | REGULATORY_DISABLE_BEACON_HINTS; | 464 | if (iwl_mvm_is_lar_supported(mvm)) |
465 | hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; | ||
466 | else | ||
467 | hw->wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG | | ||
468 | REGULATORY_DISABLE_BEACON_HINTS; | ||
361 | 469 | ||
362 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) | 470 | if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_GO_UAPSD) |
363 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; | 471 | hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD; |
@@ -1193,7 +1301,7 @@ static void iwl_mvm_restart_complete(struct iwl_mvm *mvm) | |||
1193 | 1301 | ||
1194 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 1302 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
1195 | iwl_mvm_d0i3_enable_tx(mvm, NULL); | 1303 | iwl_mvm_d0i3_enable_tx(mvm, NULL); |
1196 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1304 | ret = iwl_mvm_update_quotas(mvm, false, NULL); |
1197 | if (ret) | 1305 | if (ret) |
1198 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", | 1306 | IWL_ERR(mvm, "Failed to update quotas after restart (%d)\n", |
1199 | ret); | 1307 | ret); |
@@ -1872,7 +1980,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
1872 | sizeof(mvmvif->beacon_stats)); | 1980 | sizeof(mvmvif->beacon_stats)); |
1873 | 1981 | ||
1874 | /* add quota for this interface */ | 1982 | /* add quota for this interface */ |
1875 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1983 | ret = iwl_mvm_update_quotas(mvm, true, NULL); |
1876 | if (ret) { | 1984 | if (ret) { |
1877 | IWL_ERR(mvm, "failed to update quotas\n"); | 1985 | IWL_ERR(mvm, "failed to update quotas\n"); |
1878 | return; | 1986 | return; |
@@ -1924,7 +2032,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
1924 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | 2032 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; |
1925 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 2033 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
1926 | /* remove quota for this interface */ | 2034 | /* remove quota for this interface */ |
1927 | ret = iwl_mvm_update_quotas(mvm, NULL); | 2035 | ret = iwl_mvm_update_quotas(mvm, false, NULL); |
1928 | if (ret) | 2036 | if (ret) |
1929 | IWL_ERR(mvm, "failed to update quotas\n"); | 2037 | IWL_ERR(mvm, "failed to update quotas\n"); |
1930 | 2038 | ||
@@ -2043,7 +2151,7 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, | |||
2043 | /* power updated needs to be done before quotas */ | 2151 | /* power updated needs to be done before quotas */ |
2044 | iwl_mvm_power_update_mac(mvm); | 2152 | iwl_mvm_power_update_mac(mvm); |
2045 | 2153 | ||
2046 | ret = iwl_mvm_update_quotas(mvm, NULL); | 2154 | ret = iwl_mvm_update_quotas(mvm, false, NULL); |
2047 | if (ret) | 2155 | if (ret) |
2048 | goto out_quota_failed; | 2156 | goto out_quota_failed; |
2049 | 2157 | ||
@@ -2109,7 +2217,7 @@ static void iwl_mvm_stop_ap_ibss(struct ieee80211_hw *hw, | |||
2109 | if (vif->p2p && mvm->p2p_device_vif) | 2217 | if (vif->p2p && mvm->p2p_device_vif) |
2110 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); | 2218 | iwl_mvm_mac_ctxt_changed(mvm, mvm->p2p_device_vif, false, NULL); |
2111 | 2219 | ||
2112 | iwl_mvm_update_quotas(mvm, NULL); | 2220 | iwl_mvm_update_quotas(mvm, false, NULL); |
2113 | iwl_mvm_send_rm_bcast_sta(mvm, vif); | 2221 | iwl_mvm_send_rm_bcast_sta(mvm, vif); |
2114 | iwl_mvm_binding_remove_vif(mvm, vif); | 2222 | iwl_mvm_binding_remove_vif(mvm, vif); |
2115 | 2223 | ||
@@ -2248,6 +2356,12 @@ static int iwl_mvm_mac_hw_scan(struct ieee80211_hw *hw, | |||
2248 | 2356 | ||
2249 | mutex_lock(&mvm->mutex); | 2357 | mutex_lock(&mvm->mutex); |
2250 | 2358 | ||
2359 | if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) { | ||
2360 | IWL_ERR(mvm, "scan while LAR regdomain is not set\n"); | ||
2361 | ret = -EBUSY; | ||
2362 | goto out; | ||
2363 | } | ||
2364 | |||
2251 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { | 2365 | if (mvm->scan_status != IWL_MVM_SCAN_NONE) { |
2252 | ret = -EBUSY; | 2366 | ret = -EBUSY; |
2253 | goto out; | 2367 | goto out; |
@@ -2328,25 +2442,35 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | |||
2328 | { | 2442 | { |
2329 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 2443 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
2330 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); | 2444 | struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); |
2445 | unsigned long txqs = 0, tids = 0; | ||
2331 | int tid; | 2446 | int tid; |
2332 | 2447 | ||
2448 | spin_lock_bh(&mvmsta->lock); | ||
2449 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { | ||
2450 | struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; | ||
2451 | |||
2452 | if (tid_data->state != IWL_AGG_ON && | ||
2453 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) | ||
2454 | continue; | ||
2455 | |||
2456 | __set_bit(tid_data->txq_id, &txqs); | ||
2457 | |||
2458 | if (iwl_mvm_tid_queued(tid_data) == 0) | ||
2459 | continue; | ||
2460 | |||
2461 | __set_bit(tid, &tids); | ||
2462 | } | ||
2463 | |||
2333 | switch (cmd) { | 2464 | switch (cmd) { |
2334 | case STA_NOTIFY_SLEEP: | 2465 | case STA_NOTIFY_SLEEP: |
2335 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) | 2466 | if (atomic_read(&mvm->pending_frames[mvmsta->sta_id]) > 0) |
2336 | ieee80211_sta_block_awake(hw, sta, true); | 2467 | ieee80211_sta_block_awake(hw, sta, true); |
2337 | spin_lock_bh(&mvmsta->lock); | ||
2338 | for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { | ||
2339 | struct iwl_mvm_tid_data *tid_data; | ||
2340 | 2468 | ||
2341 | tid_data = &mvmsta->tid_data[tid]; | 2469 | for_each_set_bit(tid, &tids, IWL_MAX_TID_COUNT) |
2342 | if (tid_data->state != IWL_AGG_ON && | ||
2343 | tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) | ||
2344 | continue; | ||
2345 | if (iwl_mvm_tid_queued(tid_data) == 0) | ||
2346 | continue; | ||
2347 | ieee80211_sta_set_buffered(sta, tid, true); | 2470 | ieee80211_sta_set_buffered(sta, tid, true); |
2348 | } | 2471 | |
2349 | spin_unlock_bh(&mvmsta->lock); | 2472 | if (txqs) |
2473 | iwl_trans_freeze_txq_timer(mvm->trans, txqs, true); | ||
2350 | /* | 2474 | /* |
2351 | * The fw updates the STA to be asleep. Tx packets on the Tx | 2475 | * The fw updates the STA to be asleep. Tx packets on the Tx |
2352 | * queues to this station will not be transmitted. The fw will | 2476 | * queues to this station will not be transmitted. The fw will |
@@ -2356,11 +2480,15 @@ static void iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw, | |||
2356 | case STA_NOTIFY_AWAKE: | 2480 | case STA_NOTIFY_AWAKE: |
2357 | if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) | 2481 | if (WARN_ON(mvmsta->sta_id == IWL_MVM_STATION_COUNT)) |
2358 | break; | 2482 | break; |
2483 | |||
2484 | if (txqs) | ||
2485 | iwl_trans_freeze_txq_timer(mvm->trans, txqs, false); | ||
2359 | iwl_mvm_sta_modify_ps_wake(mvm, sta); | 2486 | iwl_mvm_sta_modify_ps_wake(mvm, sta); |
2360 | break; | 2487 | break; |
2361 | default: | 2488 | default: |
2362 | break; | 2489 | break; |
2363 | } | 2490 | } |
2491 | spin_unlock_bh(&mvmsta->lock); | ||
2364 | } | 2492 | } |
2365 | 2493 | ||
2366 | static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, | 2494 | static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw, |
@@ -2598,6 +2726,12 @@ static int iwl_mvm_mac_sched_scan_start(struct ieee80211_hw *hw, | |||
2598 | 2726 | ||
2599 | mutex_lock(&mvm->mutex); | 2727 | mutex_lock(&mvm->mutex); |
2600 | 2728 | ||
2729 | if (iwl_mvm_is_lar_supported(mvm) && !mvm->lar_regdom_set) { | ||
2730 | IWL_ERR(mvm, "sched-scan while LAR regdomain is not set\n"); | ||
2731 | ret = -EBUSY; | ||
2732 | goto out; | ||
2733 | } | ||
2734 | |||
2601 | if (!vif->bss_conf.idle) { | 2735 | if (!vif->bss_conf.idle) { |
2602 | ret = -EBUSY; | 2736 | ret = -EBUSY; |
2603 | goto out; | 2737 | goto out; |
@@ -3159,14 +3293,14 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
3159 | */ | 3293 | */ |
3160 | if (vif->type == NL80211_IFTYPE_MONITOR) { | 3294 | if (vif->type == NL80211_IFTYPE_MONITOR) { |
3161 | mvmvif->monitor_active = true; | 3295 | mvmvif->monitor_active = true; |
3162 | ret = iwl_mvm_update_quotas(mvm, NULL); | 3296 | ret = iwl_mvm_update_quotas(mvm, false, NULL); |
3163 | if (ret) | 3297 | if (ret) |
3164 | goto out_remove_binding; | 3298 | goto out_remove_binding; |
3165 | } | 3299 | } |
3166 | 3300 | ||
3167 | /* Handle binding during CSA */ | 3301 | /* Handle binding during CSA */ |
3168 | if (vif->type == NL80211_IFTYPE_AP) { | 3302 | if (vif->type == NL80211_IFTYPE_AP) { |
3169 | iwl_mvm_update_quotas(mvm, NULL); | 3303 | iwl_mvm_update_quotas(mvm, false, NULL); |
3170 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); | 3304 | iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); |
3171 | } | 3305 | } |
3172 | 3306 | ||
@@ -3190,7 +3324,7 @@ static int __iwl_mvm_assign_vif_chanctx(struct iwl_mvm *mvm, | |||
3190 | 3324 | ||
3191 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); | 3325 | iwl_mvm_unref(mvm, IWL_MVM_REF_PROTECT_CSA); |
3192 | 3326 | ||
3193 | iwl_mvm_update_quotas(mvm, NULL); | 3327 | iwl_mvm_update_quotas(mvm, false, NULL); |
3194 | } | 3328 | } |
3195 | 3329 | ||
3196 | goto out; | 3330 | goto out; |
@@ -3263,7 +3397,7 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
3263 | break; | 3397 | break; |
3264 | } | 3398 | } |
3265 | 3399 | ||
3266 | iwl_mvm_update_quotas(mvm, disabled_vif); | 3400 | iwl_mvm_update_quotas(mvm, false, disabled_vif); |
3267 | iwl_mvm_binding_remove_vif(mvm, vif); | 3401 | iwl_mvm_binding_remove_vif(mvm, vif); |
3268 | 3402 | ||
3269 | out: | 3403 | out: |
@@ -3455,7 +3589,7 @@ static int __iwl_mvm_mac_testmode_cmd(struct iwl_mvm *mvm, | |||
3455 | mvm->noa_duration = noa_duration; | 3589 | mvm->noa_duration = noa_duration; |
3456 | mvm->noa_vif = vif; | 3590 | mvm->noa_vif = vif; |
3457 | 3591 | ||
3458 | return iwl_mvm_update_quotas(mvm, NULL); | 3592 | return iwl_mvm_update_quotas(mvm, false, NULL); |
3459 | case IWL_MVM_TM_CMD_SET_BEACON_FILTER: | 3593 | case IWL_MVM_TM_CMD_SET_BEACON_FILTER: |
3460 | /* must be associated client vif - ignore authorized */ | 3594 | /* must be associated client vif - ignore authorized */ |
3461 | if (!vif || vif->type != NL80211_IFTYPE_STATION || | 3595 | if (!vif || vif->type != NL80211_IFTYPE_STATION || |