diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2019-03-30 09:37:38 +0300 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2019-03-30 09:37:38 +0300 |
commit | 8db32fa400916333c20184793d1400bd74e1f740 (patch) | |
tree | ec458234f2515e5e2f5f83dc8e087f5ec0d35ecd /drivers/net/wireless/intel/iwlwifi/mvm | |
parent | 35f861e3c58e128f0ecb5669c43159285ea5254a (diff) | |
parent | fe63f21b20df1adaab90c1839d36ee7c6e4b6ac0 (diff) | |
download | linux-8db32fa400916333c20184793d1400bd74e1f740.tar.xz |
Merge tag 'iwlwifi-next-for-kalle-2019-03-22' of git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
First batch of patches intended for v5.2
* Send NO_DATA events so they can be captured in radiotap;
* Some channel-switch changes;
* Support for multiple BSSID;
* Continued work and bugfixes for the new debugging infra;
* Support for some new FW API versions;
* Some work to support new hardware;
* General bugfixes;
* Other cleanups;
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 90 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 202 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 24 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 44 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 31 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 5 |
10 files changed, 321 insertions, 117 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 808bc6f363d0..83fd7f93d9f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1728,9 +1728,12 @@ void iwl_mvm_d0i3_update_keys(struct iwl_mvm *mvm, iwl_mvm_iter_d0i3_ap_keys(mvm, vif, iwl_mvm_d3_update_keys, >kdata); } +#define ND_QUERY_BUF_LEN (sizeof(struct iwl_scan_offload_profile_match) * \ + IWL_SCAN_MAX_PROFILES) + struct iwl_mvm_nd_query_results { u32 matched_profiles; - struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES]; + u8 matches[ND_QUERY_BUF_LEN]; }; static int @@ -1743,6 +1746,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, .flags = CMD_WANT_SKB, }; int ret, len; + size_t query_len, matches_len; ret = iwl_mvm_send_cmd(mvm, &cmd); if (ret) { @@ -1750,8 +1754,19 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, return ret; } + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + query_len = sizeof(struct iwl_scan_offload_profiles_query); + matches_len = sizeof(struct iwl_scan_offload_profile_match) * + IWL_SCAN_MAX_PROFILES; + } else { + query_len = sizeof(struct iwl_scan_offload_profiles_query_v1); + matches_len = sizeof(struct iwl_scan_offload_profile_match_v1) * + IWL_SCAN_MAX_PROFILES; + } + len = iwl_rx_packet_payload_len(cmd.resp_pkt); - if (len < sizeof(*query)) { + if (len < query_len) { IWL_ERR(mvm, "Invalid scan offload profiles query response!\n"); ret = -EIO; goto out_free_resp; @@ -1760,7 +1775,7 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, query = (void *)cmd.resp_pkt->data; results->matched_profiles = le32_to_cpu(query->matched_profiles); - memcpy(results->matches, query->matches, sizeof(results->matches)); + memcpy(results->matches, query->matches, matches_len); #ifdef CONFIG_IWLWIFI_DEBUGFS mvm->last_netdetect_scans = le32_to_cpu(query->n_scans_done); @@ -1771,6 +1786,57 @@ out_free_resp: return ret; } +static int iwl_mvm_query_num_match_chans(struct iwl_mvm *mvm, + struct iwl_mvm_nd_query_results *query, + int idx) +{ + int n_chans = 0, i; + + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + struct iwl_scan_offload_profile_match *matches = + (struct iwl_scan_offload_profile_match *)query->matches; + + for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; i++) + n_chans += hweight8(matches[idx].matching_channels[i]); + } else { + struct iwl_scan_offload_profile_match_v1 *matches = + (struct iwl_scan_offload_profile_match_v1 *)query->matches; + + for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1; i++) + n_chans += hweight8(matches[idx].matching_channels[i]); + } + + return n_chans; +} + +static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm, + struct iwl_mvm_nd_query_results *query, + struct cfg80211_wowlan_nd_match *match, + int idx) +{ + int i; + + if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + struct iwl_scan_offload_profile_match *matches = + (struct iwl_scan_offload_profile_match *)query->matches; + + for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; i++) + if (matches[idx].matching_channels[i / 8] & (BIT(i % 8))) + match->channels[match->n_channels++] = + mvm->nd_channels[i]->center_freq; + } else { + struct iwl_scan_offload_profile_match_v1 *matches = + (struct iwl_scan_offload_profile_match_v1 *)query->matches; + + for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8; i++) + if (matches[idx].matching_channels[i / 8] & (BIT(i % 8))) + match->channels[match->n_channels++] = + mvm->nd_channels[i]->center_freq; + } +} + static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -1783,7 +1849,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, struct iwl_wowlan_status *fw_status; unsigned long matched_profiles; u32 reasons = 0; - int i, j, n_matches, ret; + int i, n_matches, ret; fw_status = iwl_mvm_get_wakeup_status(mvm); if (!IS_ERR_OR_NULL(fw_status)) { @@ -1817,14 +1883,10 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, goto out_report_nd; for_each_set_bit(i, &matched_profiles, mvm->n_nd_match_sets) { - struct iwl_scan_offload_profile_match *fw_match; struct cfg80211_wowlan_nd_match *match; int idx, n_channels = 0; - fw_match = &query.matches[i]; - - for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; j++) - n_channels += hweight8(fw_match->matching_channels[j]); + n_channels = iwl_mvm_query_num_match_chans(mvm, &query, i); match = kzalloc(struct_size(match, channels, n_channels), GFP_KERNEL); @@ -1844,10 +1906,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, if (mvm->n_nd_channels < n_channels) continue; - for (j = 0; j < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; j++) - if (fw_match->matching_channels[j / 8] & (BIT(j % 8))) - match->channels[match->n_channels++] = - mvm->nd_channels[j]->center_freq; + iwl_mvm_query_set_freqs(mvm, &query, match, i); } out_report_nd: @@ -2030,7 +2089,6 @@ out: * 2. We are using a unified image but had an error while exiting D3 */ set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); - set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status); /* * When switching images we return 1, which causes mac80211 * to do a reconfig with IEEE80211_RECONFIG_TYPE_RESTART. diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 776b24f54200..472d330661d3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1349,7 +1349,7 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, return 0; iwl_fw_dbg_collect(&mvm->fwrt, FW_DBG_TRIGGER_USER, buf, - (count - 1)); + (count - 1), NULL); iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 6a70dece447d..f24d73700ad6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1573,6 +1573,7 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, rcu_read_lock(); vif = rcu_dereference(mvm->vif_id_to_mac[mac_id]); + mvmvif = iwl_mvm_vif_from_mac80211(vif); switch (vif->type) { case NL80211_IFTYPE_AP: @@ -1581,7 +1582,6 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, csa_vif != vif)) goto out_unlock; - mvmvif = iwl_mvm_vif_from_mac80211(csa_vif); csa_id = FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color); if (WARN(csa_id != id_n_color, "channel switch noa notification on unexpected vif (csa_vif=%d, notif=%d)", @@ -1602,6 +1602,7 @@ void iwl_mvm_channel_switch_noa_notif(struct iwl_mvm *mvm, return; case NL80211_IFTYPE_STATION: iwl_mvm_csa_client_absent(mvm, vif); + cancel_delayed_work_sync(&mvmvif->csa_work); ieee80211_chswitch_done(vif, true); break; default: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 3a92c09d4692..1cad9238e45a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -420,6 +420,7 @@ int iwl_mvm_init_fw_regd(struct iwl_mvm *mvm) const static u8 he_if_types_ext_capa_sta[] = { [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, [9] = WLAN_EXT_CAPA10_TWT_REQUESTER_SUPPORT, }; @@ -597,6 +598,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + hw->wiphy->features |= NL80211_FEATURE_HT_IBSS; + hw->wiphy->regulatory_flags |= REGULATORY_ENABLE_RELAX_NO_IR; if (iwl_mvm_is_lar_supported(mvm)) hw->wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED; @@ -732,6 +736,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->iftype_ext_capab = he_iftypes_ext_capa; hw->wiphy->num_iftype_ext_capab = ARRAY_SIZE(he_iftypes_ext_capa); + + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); + ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); } mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; @@ -1191,15 +1198,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) { - /* clear the D3 reconfig, we only need it to avoid dumping a - * firmware coredump on reconfiguration, we shouldn't do that - * on D3->D0 transition - */ - if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status)) { - mvm->fwrt.dump.desc = &iwl_dump_desc_assert; - iwl_fw_error_dump(&mvm->fwrt); - } - /* cleanup all stale references (scan, roc), but keep the * ucode_down ref until reconfig is complete */ @@ -1500,6 +1498,91 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } +static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + int ret; + + mutex_lock(&mvm->mutex); + + if (mvmvif->csa_failed) { + mvmvif->csa_failed = false; + ret = -EIO; + goto out_unlock; + } + + if (vif->type == NL80211_IFTYPE_STATION) { + struct iwl_mvm_sta *mvmsta; + + mvmvif->csa_bcn_pending = false; + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, + mvmvif->ap_sta_id); + + if (WARN_ON(!mvmsta)) { + ret = -EIO; + goto out_unlock; + } + + iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false); + + iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); + + ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); + if (ret) + goto out_unlock; + + iwl_mvm_stop_session_protection(mvm, vif); + } + + mvmvif->ps_disabled = false; + + ret = iwl_mvm_power_update_ps(mvm); + +out_unlock: + mutex_unlock(&mvm->mutex); + + return ret; +} + +static void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_chan_switch_te_cmd cmd = { + .mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), + }; + + IWL_DEBUG_MAC80211(mvm, "Abort CSA on mac %d\n", mvmvif->id); + + mutex_lock(&mvm->mutex); + WARN_ON(iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(MAC_CONF_GROUP, + CHANNEL_SWITCH_TIME_EVENT_CMD), + 0, sizeof(cmd), &cmd)); + mutex_unlock(&mvm->mutex); + + WARN_ON(iwl_mvm_post_channel_switch(hw, vif)); +} + +static void iwl_mvm_channel_switch_disconnect_wk(struct work_struct *wk) +{ + struct iwl_mvm *mvm; + struct iwl_mvm_vif *mvmvif; + struct ieee80211_vif *vif; + + mvmvif = container_of(wk, struct iwl_mvm_vif, csa_work.work); + vif = container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); + mvm = mvmvif->mvm; + + iwl_mvm_abort_channel_switch(mvm->hw, vif); + ieee80211_chswitch_done(vif, false); +} + static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1626,6 +1709,8 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, } iwl_mvm_tcm_add_vif(mvm, vif); + INIT_DELAYED_WORK(&mvmvif->csa_work, + iwl_mvm_channel_switch_disconnect_wk); if (vif->type == NL80211_IFTYPE_MONITOR) mvm->monitor_on = true; @@ -2308,7 +2393,11 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm, (vif->bss_conf.uora_ocw_range >> 3) & 0x7; } - /* TODO: support Multi BSSID IE */ + if (vif->bss_conf.nontransmitted) { + flags |= STA_CTXT_HE_REF_BSSID_VALID; + ether_addr_copy(sta_ctxt_cmd.ref_bssid_addr, + vif->bss_conf.transmitter_bssid); + } sta_ctxt_cmd.flags = cpu_to_le32(flags); @@ -4469,16 +4558,22 @@ static int iwl_mvm_schedule_client_csa(struct iwl_mvm *mvm, .action = cpu_to_le32(FW_CTXT_ACTION_ADD), .tsf = cpu_to_le32(chsw->timestamp), .cs_count = chsw->count, + .cs_mode = chsw->block_tx, }; lockdep_assert_held(&mvm->mutex); + if (chsw->delay) + cmd.cs_delayed_bcn_count = + DIV_ROUND_UP(chsw->delay, vif->bss_conf.beacon_int); + return iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, CHANNEL_SWITCH_TIME_EVENT_CMD), 0, sizeof(cmd), &cmd); } +#define IWL_MAX_CSA_BLOCK_TX 1500 static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel_switch *chsw) @@ -4543,8 +4638,18 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, ((vif->bss_conf.beacon_int * (chsw->count - 1) - IWL_MVM_CHANNEL_SWITCH_TIME_CLIENT) * 1024); - if (chsw->block_tx) + if (chsw->block_tx) { iwl_mvm_csa_client_absent(mvm, vif); + /* + * In case of undetermined / long time with immediate + * quiet monitor status to gracefully disconnect + */ + if (!chsw->count || + chsw->count * vif->bss_conf.beacon_int > + IWL_MAX_CSA_BLOCK_TX) + schedule_delayed_work(&mvmvif->csa_work, + msecs_to_jiffies(IWL_MAX_CSA_BLOCK_TX)); + } if (mvmvif->bf_data.bf_enabled) { ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); @@ -4559,6 +4664,9 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, iwl_mvm_schedule_csa_period(mvm, vif, vif->bss_conf.beacon_int, apply_time); + + mvmvif->csa_count = chsw->count; + mvmvif->csa_misbehave = false; break; default: break; @@ -4579,52 +4687,42 @@ out_unlock: return ret; } -static int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void iwl_mvm_channel_switch_rx_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - int ret; - - mutex_lock(&mvm->mutex); - - if (mvmvif->csa_failed) { - mvmvif->csa_failed = false; - ret = -EIO; - goto out_unlock; - } - - if (vif->type == NL80211_IFTYPE_STATION) { - struct iwl_mvm_sta *mvmsta; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_chan_switch_te_cmd cmd = { + .mac_id = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)), + .action = cpu_to_le32(FW_CTXT_ACTION_MODIFY), + .tsf = cpu_to_le32(chsw->timestamp), + .cs_count = chsw->count, + .cs_mode = chsw->block_tx, + }; - mvmvif->csa_bcn_pending = false; - mvmsta = iwl_mvm_sta_from_staid_protected(mvm, - mvmvif->ap_sta_id); + if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CS_MODIFY)) + return; - if (WARN_ON(!mvmsta)) { - ret = -EIO; - goto out_unlock; + if (chsw->count >= mvmvif->csa_count && chsw->block_tx) { + if (mvmvif->csa_misbehave) { + /* Second time, give up on this AP*/ + iwl_mvm_abort_channel_switch(hw, vif); + ieee80211_chswitch_done(vif, false); + mvmvif->csa_misbehave = false; + return; } - - iwl_mvm_sta_modify_disable_tx(mvm, mvmsta, false); - - iwl_mvm_mac_ctxt_changed(mvm, vif, false, NULL); - - ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); - if (ret) - goto out_unlock; - - iwl_mvm_stop_session_protection(mvm, vif); + mvmvif->csa_misbehave = true; } + mvmvif->csa_count = chsw->count; - mvmvif->ps_disabled = false; - - ret = iwl_mvm_power_update_ps(mvm); - -out_unlock: - mutex_unlock(&mvm->mutex); + IWL_DEBUG_MAC80211(mvm, "Modify CSA on mac %d\n", mvmvif->id); - return ret; + WARN_ON(iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(MAC_CONF_GROUP, + CHANNEL_SWITCH_TIME_EVENT_CMD), + CMD_ASYNC, sizeof(cmd), &cmd)); } static void iwl_mvm_flush_no_vif(struct iwl_mvm *mvm, u32 queues, bool drop) @@ -5083,6 +5181,8 @@ const struct ieee80211_ops iwl_mvm_hw_ops = { .channel_switch = iwl_mvm_channel_switch, .pre_channel_switch = iwl_mvm_pre_channel_switch, .post_channel_switch = iwl_mvm_post_channel_switch, + .abort_channel_switch = iwl_mvm_abort_channel_switch, + .channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon, .tdls_channel_switch = iwl_mvm_tdls_channel_switch, .tdls_cancel_channel_switch = iwl_mvm_tdls_cancel_channel_switch, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index bca6f6b536d9..61b6dbc83600 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -490,6 +490,9 @@ struct iwl_mvm_vif { bool csa_countdown; bool csa_failed; u16 csa_target_freq; + u16 csa_count; + u16 csa_misbehave; + struct delayed_work csa_work; /* Indicates that we are waiting for a beacon on a new channel */ bool csa_bcn_pending; @@ -1200,7 +1203,6 @@ struct iwl_mvm { * @IWL_MVM_STATUS_IN_HW_RESTART: HW restart is active * @IWL_MVM_STATUS_IN_D0I3: NIC is in D0i3 * @IWL_MVM_STATUS_ROC_AUX_RUNNING: AUX remain-on-channel is running - * @IWL_MVM_STATUS_D3_RECONFIG: D3 reconfiguration is being done * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running * @IWL_MVM_STATUS_NEED_FLUSH_P2P: need to flush P2P bcast STA */ @@ -1212,7 +1214,6 @@ enum iwl_mvm_status { IWL_MVM_STATUS_IN_HW_RESTART, IWL_MVM_STATUS_IN_D0I3, IWL_MVM_STATUS_ROC_AUX_RUNNING, - IWL_MVM_STATUS_D3_RECONFIG, IWL_MVM_STATUS_FIRMWARE_RUNNING, IWL_MVM_STATUS_NEED_FLUSH_P2P, }; @@ -1650,8 +1651,8 @@ void iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); -void iwl_mvm_rx_monitor_ndp(struct iwl_mvm *mvm, struct napi_struct *napi, - struct iwl_rx_cmd_buffer *rxb, int queue); +void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb, int queue); void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, int queue); int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, @@ -2024,17 +2025,6 @@ static inline u32 iwl_mvm_flushable_queues(struct iwl_mvm *mvm) static inline void iwl_mvm_stop_device(struct iwl_mvm *mvm) { lockdep_assert_held(&mvm->mutex); - /* If IWL_MVM_STATUS_HW_RESTART_REQUESTED bit is set then we received - * an assert. Since we failed to bring the interface up, mac80211 - * will not attempt to reconfig the device, - * which handles the dump collection in assert flow, - * so trigger dump collection here. - */ - if (test_and_clear_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, - &mvm->status)) - iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, - false, 0); - iwl_fw_cancel_timestamp(&mvm->fwrt); clear_bit(IWL_MVM_STATUS_FIRMWARE_RUNNING, &mvm->status); iwl_fwrt_stop_device(&mvm->fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ba27dce4c2bb..3cc6048d6a10 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1105,7 +1105,7 @@ static void iwl_mvm_rx_mq(struct iwl_op_mode *op_mode, else if (cmd == WIDE_ID(LEGACY_GROUP, FRAME_RELEASE)) iwl_mvm_rx_frame_release(mvm, napi, rxb, 0); else if (cmd == WIDE_ID(DATA_PATH_GROUP, RX_NO_DATA_NOTIF)) - iwl_mvm_rx_monitor_ndp(mvm, napi, rxb, 0); + iwl_mvm_rx_monitor_no_data(mvm, napi, rxb, 0); else iwl_mvm_rx_common(mvm, rxb, pkt); } @@ -1340,6 +1340,8 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) } } + iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, + false, 0); if (fw_error && mvm->fw_restart > 0) mvm->fw_restart--; set_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c index a28283ff7295..79f9eaf8dd1b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c @@ -6,7 +6,7 @@ * GPL LICENSE SUMMARY * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -27,7 +27,7 @@ * BSD LICENSE * * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -345,6 +345,37 @@ out: rcu_read_unlock(); } +static u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta) +{ + const struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; + const struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap; + + if (vht_cap && vht_cap->vht_supported) { + switch (vht_cap->cap & IEEE80211_VHT_CAP_MAX_MPDU_MASK) { + case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454: + return IEEE80211_MAX_MPDU_LEN_VHT_11454; + case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991: + return IEEE80211_MAX_MPDU_LEN_VHT_7991; + default: + return IEEE80211_MAX_MPDU_LEN_VHT_3895; + } + + } else if (ht_cap && ht_cap->ht_supported) { + if (ht_cap->cap & IEEE80211_HT_CAP_MAX_AMSDU) + /* + * agg is offloaded so we need to assume that agg + * are enabled and max mpdu in ampdu is 4095 + * (spec 802.11-2016 9.3.2.1) + */ + return IEEE80211_MAX_MPDU_LEN_HT_BA; + else + return IEEE80211_MAX_MPDU_LEN_HT_3839; + } + + /* in legacy mode no amsdu is enabled so return zero */ + return 0; +} + void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, enum nl80211_band band, bool update) { @@ -353,14 +384,15 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->lq_sta.rs_fw; u32 cmd_id = iwl_cmd_id(TLC_MNG_CONFIG_CMD, DATA_PATH_GROUP, 0); struct ieee80211_supported_band *sband; + u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta); struct iwl_tlc_config_cmd cfg_cmd = { .sta_id = mvmsta->sta_id, .max_ch_width = update ? rs_fw_bw_from_sta_bw(sta) : RATE_MCS_CHAN_WIDTH_20, .flags = cpu_to_le16(rs_fw_set_config_flags(mvm, sta)), .chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)), - .max_mpdu_len = cpu_to_le16(sta->max_amsdu_len), .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta), + .max_mpdu_len = cpu_to_le16(max_amsdu_len), .amsdu = iwl_mvm_is_csum_supported(mvm), }; int ret; @@ -373,6 +405,12 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta, sband = hw->wiphy->bands[band]; rs_fw_set_supp_rates(sta, sband, &cfg_cmd); + /* + * since TLC offload works with one mode we can assume + * that only vht/ht is used and also set it as station max amsdu + */ + sta->max_amsdu_len = max_amsdu_len; + ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cfg_cmd), &cfg_cmd); if (ret) IWL_ERR(mvm, "Failed to send rate scale config (%d)\n", ret); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 1e03acf30762..0b1b208de767 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -1679,8 +1679,8 @@ out: rcu_read_unlock(); } -void iwl_mvm_rx_monitor_ndp(struct iwl_mvm *mvm, struct napi_struct *napi, - struct iwl_rx_cmd_buffer *rxb, int queue) +void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, + struct iwl_rx_cmd_buffer *rxb, int queue) { struct ieee80211_rx_status *rx_status; struct iwl_rx_packet *pkt = rxb_addr(rxb); @@ -1701,10 +1701,6 @@ void iwl_mvm_rx_monitor_ndp(struct iwl_mvm *mvm, struct napi_struct *napi, if (unlikely(test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))) return; - /* Currently only NDP type is supported */ - if (info_type != RX_NO_DATA_INFO_TYPE_NDP) - return; - energy_a = (rssi & RX_NO_DATA_CHAIN_A_MSK) >> RX_NO_DATA_CHAIN_A_POS; energy_b = (rssi & RX_NO_DATA_CHAIN_B_MSK) >> RX_NO_DATA_CHAIN_B_POS; channel = (rssi & RX_NO_DATA_CHANNEL_MSK) >> RX_NO_DATA_CHANNEL_POS; @@ -1726,9 +1722,22 @@ void iwl_mvm_rx_monitor_ndp(struct iwl_mvm *mvm, struct napi_struct *napi, /* 0-length PSDU */ rx_status->flag |= RX_FLAG_NO_PSDU; - /* currently this is the only type for which we get this notif */ - rx_status->zero_length_psdu_type = - IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING; + + switch (info_type) { + case RX_NO_DATA_INFO_TYPE_NDP: + rx_status->zero_length_psdu_type = + IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING; + break; + case RX_NO_DATA_INFO_TYPE_MU_UNMATCHED: + case RX_NO_DATA_INFO_TYPE_HE_TB_UNMATCHED: + rx_status->zero_length_psdu_type = + IEEE80211_RADIOTAP_ZERO_LEN_PSDU_NOT_CAPTURED; + break; + default: + rx_status->zero_length_psdu_type = + IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR; + break; + } /* This may be overridden by iwl_mvm_rx_he() to HE_RU */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 78694bc38e76..d9ddf9ff6428 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1082,21 +1082,23 @@ static void iwl_mvm_fill_scan_dwell(struct iwl_mvm *mvm, dwell->extended = IWL_SCAN_DWELL_EXTENDED; } -static void iwl_mvm_fill_channels(struct iwl_mvm *mvm, u8 *channels) +static void iwl_mvm_fill_channels(struct iwl_mvm *mvm, u8 *channels, + u32 max_channels) { struct ieee80211_supported_band *band; int i, j = 0; band = &mvm->nvm_data->bands[NL80211_BAND_2GHZ]; - for (i = 0; i < band->n_channels; i++, j++) + for (i = 0; i < band->n_channels && j < max_channels; i++, j++) channels[j] = band->channels[i].hw_value; band = &mvm->nvm_data->bands[NL80211_BAND_5GHZ]; - for (i = 0; i < band->n_channels; i++, j++) + for (i = 0; i < band->n_channels && j < max_channels; i++, j++) channels[j] = band->channels[i].hw_value; } static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config, - u32 flags, u8 channel_flags) + u32 flags, u8 channel_flags, + u32 max_channels) { enum iwl_mvm_scan_type type = iwl_mvm_get_scan_type(mvm, NULL); struct iwl_scan_config_v1 *cfg = config; @@ -1115,11 +1117,12 @@ static void iwl_mvm_fill_scan_config_v1(struct iwl_mvm *mvm, void *config, cfg->bcast_sta_id = mvm->aux_sta.sta_id; cfg->channel_flags = channel_flags; - iwl_mvm_fill_channels(mvm, cfg->channel_array); + iwl_mvm_fill_channels(mvm, cfg->channel_array, max_channels); } static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config, - u32 flags, u8 channel_flags) + u32 flags, u8 channel_flags, + u32 max_channels) { struct iwl_scan_config *cfg = config; @@ -1162,7 +1165,7 @@ static void iwl_mvm_fill_scan_config(struct iwl_mvm *mvm, void *config, cfg->bcast_sta_id = mvm->aux_sta.sta_id; cfg->channel_flags = channel_flags; - iwl_mvm_fill_channels(mvm, cfg->channel_array); + iwl_mvm_fill_channels(mvm, cfg->channel_array, max_channels); } int iwl_mvm_config_scan(struct iwl_mvm *mvm) @@ -1181,7 +1184,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) u8 channel_flags; if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels)) - return -ENOBUFS; + num_channels = mvm->fw->ucode_capa.n_scan_channels; if (iwl_mvm_is_cdb_supported(mvm)) { type = iwl_mvm_get_scan_type_band(mvm, NULL, @@ -1234,9 +1237,11 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm) flags |= (iwl_mvm_is_scan_fragmented(hb_type)) ? SCAN_CONFIG_FLAG_SET_LMAC2_FRAGMENTED : SCAN_CONFIG_FLAG_CLEAR_LMAC2_FRAGMENTED; - iwl_mvm_fill_scan_config(mvm, cfg, flags, channel_flags); + iwl_mvm_fill_scan_config(mvm, cfg, flags, channel_flags, + num_channels); } else { - iwl_mvm_fill_scan_config_v1(mvm, cfg, flags, channel_flags); + iwl_mvm_fill_scan_config_v1(mvm, cfg, flags, channel_flags, + num_channels); } cmd.data[0] = cfg; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 9693fa4cdc39..50314018d157 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -8,7 +8,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -31,7 +31,7 @@ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2017 Intel Deutschland GmbH - * Copyright(c) 2018 Intel Corporation + * Copyright(c) 2018 - 2019 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -234,6 +234,7 @@ iwl_mvm_te_handle_notify_csa(struct iwl_mvm *mvm, break; } iwl_mvm_csa_client_absent(mvm, te_data->vif); + cancel_delayed_work_sync(&mvmvif->csa_work); ieee80211_chswitch_done(te_data->vif, true); break; default: |