diff options
author | David S. Miller <davem@davemloft.net> | 2021-06-25 11:50:02 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-06-25 11:50:02 -0700 |
commit | 4e3db44a242a4e2afe33b59793898ecbb61d478e (patch) | |
tree | 44066da9f4d2bacfa5b26ac71d2bf263dfa9a7cf /drivers/net/wireless/intel/iwlwifi/mvm | |
parent | ac53c26433b51f1835ce5a935970e427d83e3ec5 (diff) | |
parent | c2a3823dad4988943c0b0f61af9336301e30d4e5 (diff) |
Merge tag 'wireless-drivers-next-2021-06-25' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next
Kalle Valo says:
====================
wireless-drivers-next patches for v5.14
Second, and most likely the last, set of patches for v5.14. mt76 and
iwlwifi have most patches in this round, but rtw88 also has some new
features. Nothing special really standing out.
mt76
* mt7915 MSI support
* disable ASPM on mt7915
* mt7915 tx status reporting
* mt7921 decap offload
rtw88
* beacon filter support
* path diversity support
* firmware crash information via devcoredump
* quirks for disabling pci capabilities
mt7601u
* add USB ID for a XiaoDu WiFi Dongle
ath11k
* enable support for QCN9074 PCI devices
brcmfmac
* support parse country code map from DeviceTree
iwlwifi
* support for new hardware
* support for BIOS control of 11ax enablement in Russia
* support UNII4 band enablement from BIOS
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 118 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c | 9 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 44 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 25 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 20 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/offloading.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/ops.c | 40 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 10 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 14 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 8 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/time-event.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 357 |
15 files changed, 322 insertions, 428 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 2e28cf299ef4..6a259d867d90 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -104,7 +104,7 @@ static const u8 *iwl_mvm_find_max_pn(struct ieee80211_key_conf *key, struct wowlan_key_data { struct iwl_wowlan_rsc_tsc_params_cmd *rsc_tsc; struct iwl_wowlan_tkip_params_cmd *tkip; - struct iwl_wowlan_kek_kck_material_cmd_v3 *kek_kck_cmd; + struct iwl_wowlan_kek_kck_material_cmd_v4 *kek_kck_cmd; bool error, use_rsc_tsc, use_tkip, configure_keys; int wep_key_idx; }; @@ -393,14 +393,19 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm, } static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, struct cfg80211_wowlan *wowlan) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_wowlan_patterns_cmd *pattern_cmd; struct iwl_host_cmd cmd = { .id = WOWLAN_PATTERNS, .dataflags[0] = IWL_HCMD_DFL_NOCOPY, }; int i, err; + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_PATTERNS, + IWL_FW_CMD_VER_UNKNOWN); if (!wowlan->n_patterns) return 0; @@ -408,11 +413,13 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, cmd.len[0] = sizeof(*pattern_cmd) + wowlan->n_patterns * sizeof(struct iwl_wowlan_pattern_v2); - pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL); + pattern_cmd = kzalloc(cmd.len[0], GFP_KERNEL); if (!pattern_cmd) return -ENOMEM; - pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns); + pattern_cmd->n_patterns = wowlan->n_patterns; + if (ver >= 3) + pattern_cmd->sta_id = mvmvif->ap_sta_id; for (i = 0; i < wowlan->n_patterns; i++) { int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); @@ -636,7 +643,6 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, struct ieee80211_sta *ap_sta) { - int ret; struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta); /* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */ @@ -646,12 +652,16 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING; - /* Query the last used seqno and set it */ - ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); - if (ret < 0) - return ret; + if (iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_CONFIGURATION, 0) < 6) { + /* Query the last used seqno and set it */ + int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); - wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); + if (ret < 0) + return ret; + + wowlan_config_cmd->non_qos_seq = cpu_to_le16(ret); + } iwl_mvm_set_wowlan_qos_seq(mvm_ap_sta, wowlan_config_cmd); @@ -706,7 +716,8 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u32 cmd_flags) { - struct iwl_wowlan_kek_kck_material_cmd_v3 kek_kck_cmd = {}; + struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; + struct iwl_wowlan_kek_kck_material_cmd_v4 *_kek_kck_cmd = &kek_kck_cmd; struct iwl_wowlan_tkip_params_cmd tkip_cmd = {}; bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); @@ -715,7 +726,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, .use_rsc_tsc = false, .tkip = &tkip_cmd, .use_tkip = false, - .kek_kck_cmd = &kek_kck_cmd, + .kek_kck_cmd = _kek_kck_cmd, }; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; @@ -809,13 +820,9 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, IWL_ALWAYS_LONG_GROUP, WOWLAN_KEK_KCK_MATERIAL, IWL_FW_CMD_VER_UNKNOWN); - if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && + if (WARN_ON(cmd_ver != 2 && cmd_ver != 3 && cmd_ver != 4 && cmd_ver != IWL_FW_CMD_VER_UNKNOWN)) return -EINVAL; - if (cmd_ver == 3) - cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3); - else - cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2); memcpy(kek_kck_cmd.kck, mvmvif->rekey_data.kck, mvmvif->rekey_data.kck_len); @@ -825,6 +832,21 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len); kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr; kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm); + kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->ap_sta_id); + + if (cmd_ver == 4) { + cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4); + } else { + if (cmd_ver == 3) + cmd_size = + sizeof(struct iwl_wowlan_kek_kck_material_cmd_v3); + else + cmd_size = + sizeof(struct iwl_wowlan_kek_kck_material_cmd_v2); + /* skip the sta_id at the beginning */ + _kek_kck_cmd = (void *) + ((u8 *)_kek_kck_cmd) + sizeof(kek_kck_cmd.sta_id); + } IWL_DEBUG_WOWLAN(mvm, "setting akm %d\n", mvmvif->rekey_data.akm); @@ -832,7 +854,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_KEK_KCK_MATERIAL, cmd_flags, cmd_size, - &kek_kck_cmd); + _kek_kck_cmd); if (ret) goto out; } @@ -884,7 +906,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE)) - ret = iwl_mvm_send_patterns(mvm, wowlan); + ret = iwl_mvm_send_patterns(mvm, vif, wowlan); else ret = iwl_mvm_send_patterns_v1(mvm, wowlan); if (ret) @@ -1534,9 +1556,12 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, } out: - mvmvif->seqno_valid = true; - /* +0x10 because the set API expects next-to-use, not last-used */ - mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10; + if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, 0) < 10) { + mvmvif->seqno_valid = true; + /* +0x10 because the set API expects next-to-use, not last-used */ + mvmvif->seqno = le16_to_cpu(status->non_qos_seq_ctr) + 0x10; + } return true; } @@ -1587,15 +1612,27 @@ iwl_mvm_parse_wowlan_status_common(v6) iwl_mvm_parse_wowlan_status_common(v7) iwl_mvm_parse_wowlan_status_common(v9) -struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) +static struct iwl_wowlan_status * +iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) { struct iwl_wowlan_status *status; + struct iwl_wowlan_get_status_cmd get_status_cmd = { + .sta_id = cpu_to_le32(sta_id), + }; struct iwl_host_cmd cmd = { .id = WOWLAN_GET_STATUSES, .flags = CMD_WANT_SKB, + .data = { &get_status_cmd, }, + .len = { sizeof(get_status_cmd), }, }; int ret, len; u8 notif_ver; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, + IWL_FW_CMD_VER_UNKNOWN); + + if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) + cmd.len[0] = 0; lockdep_assert_held(&mvm->mutex); @@ -1608,8 +1645,11 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) len = iwl_rx_packet_payload_len(cmd.resp_pkt); /* default to 7 (when we have IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL) */ - notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - WOWLAN_GET_STATUSES, 7); + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, + WOWLAN_GET_STATUSES, 0); + if (!notif_ver) + notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + WOWLAN_GET_STATUSES, 7); if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_KEY_MATERIAL)) { @@ -1654,7 +1694,7 @@ struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm) status->gtk[0] = v7->gtk[0]; status->igtk[0] = v7->igtk[0]; - } else if (notif_ver == 9) { + } else if (notif_ver == 9 || notif_ver == 10) { struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; status = iwl_mvm_parse_wowlan_status_common_v9(mvm, @@ -1680,29 +1720,37 @@ out_free_resp: } static struct iwl_wowlan_status * -iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm) +iwl_mvm_get_wakeup_status(struct iwl_mvm *mvm, u8 sta_id) { - int ret; - - /* only for tracing for now */ - ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, 0, NULL); - if (ret) - IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + OFFLOADS_QUERY_CMD, + IWL_FW_CMD_VER_UNKNOWN); + __le32 station_id = cpu_to_le32(sta_id); + u32 cmd_size = cmd_ver != IWL_FW_CMD_VER_UNKNOWN ? sizeof(station_id) : 0; + + if (!mvm->net_detect) { + /* only for tracing for now */ + int ret = iwl_mvm_send_cmd_pdu(mvm, OFFLOADS_QUERY_CMD, 0, + cmd_size, &station_id); + if (ret) + IWL_ERR(mvm, "failed to query offload statistics (%d)\n", ret); + } - return iwl_mvm_send_wowlan_get_status(mvm); + return iwl_mvm_send_wowlan_get_status(mvm, sta_id); } /* releases the MVM mutex */ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_wowlan_status_data status; struct iwl_wowlan_status *fw_status; int i; bool keep; struct iwl_mvm_sta *mvm_ap_sta; - fw_status = iwl_mvm_get_wakeup_status(mvm); + fw_status = iwl_mvm_get_wakeup_status(mvm, mvmvif->ap_sta_id); if (IS_ERR_OR_NULL(fw_status)) goto out_unlock; @@ -1880,7 +1928,7 @@ static void iwl_mvm_query_netdetect_reasons(struct iwl_mvm *mvm, u32 reasons = 0; int i, n_matches, ret; - fw_status = iwl_mvm_get_wakeup_status(mvm); + fw_status = iwl_mvm_get_wakeup_status(mvm, IWL_MVM_INVALID_STA); if (!IS_ERR_OR_NULL(fw_status)) { reasons = le32_to_cpu(fw_status->wakeup_reasons); kfree(fw_status); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index 38d0bfb649cc..7d9faeffd154 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -460,7 +460,7 @@ static ssize_t iwl_dbgfs_os_device_timediff_read(struct file *file, int pos = 0; mutex_lock(&mvm->mutex); - iwl_mvm_get_sync_time(mvm, &curr_gp2, &curr_os); + iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, &curr_os, NULL); mutex_unlock(&mvm->mutex); do_div(curr_os, NSEC_PER_USEC); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 63d65018d098..95f883aba148 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1023,7 +1023,9 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, mvm->fw_restart++; /* take the return value to make compiler happy - it will fail anyway */ - ret = iwl_mvm_send_cmd_pdu(mvm, REPLY_ERROR, 0, 0, NULL); + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(LONG_GROUP, REPLY_ERROR), + 0, 0, NULL); mutex_unlock(&mvm->mutex); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index a456b8a0ae58..59cef0d89a6d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020 Intel Corporation + * Copyright (C) 2018-2021 Intel Corporation */ #include <linux/etherdevice.h> #include <linux/math64.h> @@ -430,6 +430,10 @@ iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm, FTM_PUT_FLAG(TB); else if (peer->ftm.non_trigger_based) FTM_PUT_FLAG(NON_TB); + + if ((peer->ftm.trigger_based || peer->ftm.non_trigger_based) && + peer->ftm.lmr_feedback) + FTM_PUT_FLAG(LMR_FEEDBACK); } static int @@ -879,7 +883,8 @@ static u64 iwl_mvm_ftm_get_host_time(struct iwl_mvm *mvm, __le32 fw_gp2_ts) u32 curr_gp2, diff; u64 now_from_boot_ns; - iwl_mvm_get_sync_time(mvm, &curr_gp2, &now_from_boot_ns); + iwl_mvm_get_sync_time(mvm, CLOCK_BOOTTIME, &curr_gp2, + &now_from_boot_ns, NULL); if (curr_gp2 >= gp2_ts) diff = curr_gp2 - gp2_ts; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 8aa5f1a2c58c..38fd5886af2d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -1139,19 +1139,34 @@ static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { - int cmd_ret; - struct iwl_lari_config_change_cmd_v3 cmd = {}; + int ret; + u32 value; + struct iwl_lari_config_change_cmd_v4 cmd = {}; cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt); + ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, DSM_FUNC_11AX_ENABLEMENT, + &iwl_guid, &value); + if (!ret) + cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); /* apply more config masks here */ - if (cmd.config_bitmap) { + ret = iwl_acpi_get_dsm_u32((&mvm->fwrt)->dev, 0, + DSM_FUNC_ENABLE_UNII4_CHAN, + &iwl_guid, &value); + if (!ret) + cmd.oem_unii4_allow_bitmap = cpu_to_le32(value); + + if (cmd.config_bitmap || + cmd.oem_11ax_allow_bitmap || + cmd.oem_unii4_allow_bitmap) { size_t cmd_size; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, REGULATORY_AND_NVM_GROUP, LARI_CONFIG_CHANGE, 1); - if (cmd_ver == 3) + if (cmd_ver == 4) + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4); + else if (cmd_ver == 3) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3); else if (cmd_ver == 2) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2); @@ -1159,16 +1174,21 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); IWL_DEBUG_RADIO(mvm, - "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x\n", - le32_to_cpu(cmd.config_bitmap)); - cmd_ret = iwl_mvm_send_cmd_pdu(mvm, - WIDE_ID(REGULATORY_AND_NVM_GROUP, - LARI_CONFIG_CHANGE), - 0, cmd_size, &cmd); - if (cmd_ret < 0) + "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", + le32_to_cpu(cmd.config_bitmap), + le32_to_cpu(cmd.oem_11ax_allow_bitmap)); + IWL_DEBUG_RADIO(mvm, + "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, cmd_ver=%d\n", + le32_to_cpu(cmd.oem_unii4_allow_bitmap), + cmd_ver); + ret = iwl_mvm_send_cmd_pdu(mvm, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), + 0, cmd_size, &cmd); + if (ret < 0) IWL_DEBUG_RADIO(mvm, "Failed to send LARI_CONFIG_CHANGE (%d)\n", - cmd_ret); + ret); } } #else /* CONFIG_ACPI */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 607d5d564928..bafff5f2c638 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -3800,6 +3800,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct cfg80211_chan_def chandef; struct iwl_mvm_phy_ctxt *phy_ctxt; + bool band_change_removal; int ret, i; IWL_DEBUG_MAC80211(mvm, "enter (%d, %d, %d)\n", channel->hw_value, @@ -3880,19 +3881,30 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, cfg80211_chandef_create(&chandef, channel, NL80211_CHAN_NO_HT); /* - * Change the PHY context configuration as it is currently referenced - * only by the P2P Device MAC + * Check if the remain-on-channel is on a different band and that + * requires context removal, see iwl_mvm_phy_ctxt_changed(). If + * so, we'll need to release and then re-configure here, since we + * must not remove a PHY context that's part of a binding. */ - if (mvmvif->phy_ctxt->ref == 1) { + band_change_removal = + fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && + mvmvif->phy_ctxt->channel->band != chandef.chan->band; + + if (mvmvif->phy_ctxt->ref == 1 && !band_change_removal) { + /* + * Change the PHY context configuration as it is currently + * referenced only by the P2P Device MAC (and we can modify it) + */ ret = iwl_mvm_phy_ctxt_changed(mvm, mvmvif->phy_ctxt, &chandef, 1, 1); if (ret) goto out_unlock; } else { /* - * The PHY context is shared with other MACs. Need to remove the - * P2P Device from the binding, allocate an new PHY context and - * create a new binding + * The PHY context is shared with other MACs (or we're trying to + * switch bands), so remove the P2P Device from the binding, + * allocate an new PHY context and create a new binding. */ phy_ctxt = iwl_mvm_get_free_phy_ctxt(mvm); if (!phy_ctxt) { @@ -4211,7 +4223,6 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, struct ieee80211_vif *disabled_vif = NULL; lockdep_assert_held(&mvm->mutex); - iwl_mvm_remove_time_event(mvm, mvmvif, &mvmvif->time_event_data); switch (vif->type) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index 4d9d4d6892fc..b50942f28bb7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -16,6 +16,8 @@ #include <linux/thermal.h> #endif +#include <linux/ktime.h> + #include "iwl-op-mode.h" #include "iwl-trans.h" #include "fw/notif-wait.h" @@ -195,6 +197,7 @@ enum iwl_mvm_smps_type_request { IWL_MVM_SMPS_REQ_BT_COEX, IWL_MVM_SMPS_REQ_TT, IWL_MVM_SMPS_REQ_PROT, + IWL_MVM_SMPS_REQ_FW, NUM_IWL_MVM_SMPS_REQ, }; @@ -991,6 +994,8 @@ struct iwl_mvm { */ bool temperature_test; /* Debug test temperature is enabled */ + bool fw_static_smps_request; + unsigned long bt_coex_last_tcm_ts; struct iwl_mvm_tcm tcm; @@ -1447,10 +1452,16 @@ void iwl_mvm_hwrate_to_tx_rate(u32 rate_n_flags, struct ieee80211_tx_rate *r); u8 iwl_mvm_mac80211_idx_to_hwrate(int rate_idx); u8 iwl_mvm_mac80211_ac_to_ucode_ac(enum ieee80211_ac_numbers ac); -void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm); + +static inline void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) +{ + iwl_fwrt_dump_error_logs(&mvm->fwrt); +} + u8 first_antenna(u8 mask); u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx); -void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime); +void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, u32 *gp2, + u64 *boottime, ktime_t *realtime); u32 iwl_mvm_get_systime(struct iwl_mvm *mvm); /* Tx / Host Commands */ @@ -1769,7 +1780,6 @@ void iwl_mvm_ipv6_addr_change(struct ieee80211_hw *hw, void iwl_mvm_set_default_unicast_key(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx); extern const struct file_operations iwl_dbgfs_d3_test_ops; -struct iwl_wowlan_status *iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm); #ifdef CONFIG_PM void iwl_mvm_set_last_nonqos_seq(struct iwl_mvm *mvm, struct ieee80211_vif *vif); @@ -1827,7 +1837,9 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm, void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum iwl_mvm_smps_type_request req_type, enum ieee80211_smps_mode smps_request); -bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm); +bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt); +void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif); /* Low latency */ int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c index 1cc90e61367b..41880517e8bb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/offloading.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2012-2014, 2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 Intel Deutschland GmbH */ @@ -36,7 +36,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct iwl_proto_offload_cmd_v1 v1; struct iwl_proto_offload_cmd_v2 v2; struct iwl_proto_offload_cmd_v3_small v3s; - struct iwl_proto_offload_cmd_v3_large v3l; + struct iwl_proto_offload_cmd_v4 v4; } cmd = {}; struct iwl_host_cmd hcmd = { .id = PROT_OFFLOAD_CONFIG_CMD, @@ -47,6 +47,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, struct iwl_proto_offload_cmd_common *common; u32 enabled = 0, size; u32 capa_flags = mvm->fw->ucode_capa.flags; + int ver = iwl_fw_lookup_cmd_ver(mvm->fw, LONG_GROUP, + PROT_OFFLOAD_CONFIG_CMD, 0); + #if IS_ENABLED(CONFIG_IPV6) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int i; @@ -72,9 +75,9 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, addrs = cmd.v3s.targ_addrs; n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3S; } else { - nsc = cmd.v3l.ns_config; + nsc = cmd.v4.ns_config; n_nsc = IWL_PROTO_OFFLOAD_NUM_NS_CONFIG_V3L; - addrs = cmd.v3l.targ_addrs; + addrs = cmd.v4.targ_addrs; n_addrs = IWL_PROTO_OFFLOAD_NUM_IPV6_ADDRS_V3L; } @@ -116,7 +119,7 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, cmd.v3s.num_valid_ipv6_addrs = cpu_to_le32(i - num_skipped); else - cmd.v3l.num_valid_ipv6_addrs = + cmd.v4.num_valid_ipv6_addrs = cpu_to_le32(i - num_skipped); } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { bool found = false; @@ -171,8 +174,17 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, common = &cmd.v3s.common; size = sizeof(cmd.v3s); } else if (capa_flags & IWL_UCODE_TLV_FLAGS_NEW_NSOFFL_LARGE) { - common = &cmd.v3l.common; - size = sizeof(cmd.v3l); + common = &cmd.v4.common; + size = sizeof(cmd.v4); + if (ver < 4) { + /* + * This basically uses iwl_proto_offload_cmd_v3_large + * which doesn't have the sta_id parameter before the + * common part. + */ + size -= sizeof(cmd.v4.sta_id); + hcmd.data[0] = common; + } } else if (capa_flags & IWL_UCODE_TLV_FLAGS_D3_6_IPV6_ADDRS) { common = &cmd.v2.common; size = sizeof(cmd.v2); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index ebed82c590e5..20e8d343a950 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -210,6 +210,39 @@ static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, ieee80211_disconnect(vif, true); } +void iwl_mvm_apply_fw_smps_request(struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + + iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_FW, + mvm->fw_static_smps_request ? + IEEE80211_SMPS_STATIC : + IEEE80211_SMPS_AUTOMATIC); +} + +static void iwl_mvm_intf_dual_chain_req(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + iwl_mvm_apply_fw_smps_request(vif); +} + +static void iwl_mvm_rx_thermal_dual_chain_req(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + struct iwl_thermal_dual_chain_request *req = (void *)pkt->data; + + /* + * We could pass it to the iterator data, but also need to remember + * it for new interfaces that are added while in this state. + */ + mvm->fw_static_smps_request = + req->event == cpu_to_le32(THERMAL_DUAL_CHAIN_REQ_DISABLE); + ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_intf_dual_chain_req, NULL); +} + /** * enum iwl_rx_handler_context context for Rx handler * @RX_HANDLER_SYNC : this means that it will be called in the Rx path @@ -358,6 +391,11 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF, iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED, struct iwl_datapath_monitor_notif), + + RX_HANDLER_GRP(DATA_PATH_GROUP, THERMAL_DUAL_CHAIN_REQUEST, + iwl_mvm_rx_thermal_dual_chain_req, + RX_HANDLER_ASYNC_LOCKED, + struct iwl_thermal_dual_chain_request), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -445,7 +483,6 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = { HCMD_NAME(D3_CONFIG_CMD), HCMD_NAME(PROT_OFFLOAD_CONFIG_CMD), HCMD_NAME(OFFLOADS_QUERY_CMD), - HCMD_NAME(REMOTE_WAKE_CONFIG_CMD), HCMD_NAME(MATCH_FOUND_NOTIFICATION), HCMD_NAME(DTS_MEASUREMENT_NOTIFICATION), HCMD_NAME(WOWLAN_PATTERNS), @@ -503,6 +540,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(TLC_MNG_CONFIG_CMD), HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD), HCMD_NAME(MONITOR_NOTIF), + HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST), HCMD_NAME(STA_PM_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c index 0fd51f6aa206..035336a9e755 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/phy-ctxt.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH */ @@ -76,6 +76,7 @@ static void iwl_mvm_phy_ctxt_cmd_hdr(struct iwl_mvm_phy_ctxt *ctxt, } static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, __le32 *rxchain_info, u8 chains_static, u8 chains_dynamic) @@ -93,11 +94,22 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, * between the two antennas is sufficiently different to impact * performance. */ - if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm)) { + if (active_cnt == 1 && iwl_mvm_rx_diversity_allowed(mvm, ctxt)) { idle_cnt = 2; active_cnt = 2; } + /* + * If the firmware requested it, then we know that it supports + * getting zero for the values to indicate "use one, but pick + * which one yourself", which means it can dynamically pick one + * that e.g. has better RSSI. + */ + if (mvm->fw_static_smps_request && active_cnt == 1 && idle_cnt == 1) { + idle_cnt = 0; + active_cnt = 0; + } + *rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) << PHY_RX_CHAIN_VALID_POS); *rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS); @@ -113,6 +125,7 @@ static void iwl_mvm_phy_ctxt_set_rxchain(struct iwl_mvm *mvm, * Add the phy configuration to the PHY context command */ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, struct iwl_phy_context_cmd_v1 *cmd, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) @@ -123,7 +136,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); - iwl_mvm_phy_ctxt_set_rxchain(mvm, &tail->rxchain_info, + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &tail->rxchain_info, chains_static, chains_dynamic); tail->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm)); @@ -133,6 +146,7 @@ static void iwl_mvm_phy_ctxt_cmd_data_v1(struct iwl_mvm *mvm, * Add the phy configuration to the PHY context command */ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt, struct iwl_phy_context_cmd *cmd, struct cfg80211_chan_def *chandef, u8 chains_static, u8 chains_dynamic) @@ -143,7 +157,7 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm, /* Set the channel info data */ iwl_mvm_set_chan_info_chandef(mvm, &cmd->ci, chandef); - iwl_mvm_phy_ctxt_set_rxchain(mvm, &cmd->rxchain_info, + iwl_mvm_phy_ctxt_set_rxchain(mvm, ctxt, &cmd->rxchain_info, chains_static, chains_dynamic); } @@ -170,7 +184,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, iwl_mvm_phy_ctxt_cmd_hdr(ctxt, &cmd, action); /* Set the command data */ - iwl_mvm_phy_ctxt_cmd_data(mvm, &cmd, chandef, + iwl_mvm_phy_ctxt_cmd_data(mvm, ctxt, &cmd, chandef, chains_static, chains_dynamic); @@ -186,7 +200,7 @@ static int iwl_mvm_phy_ctxt_apply(struct iwl_mvm *mvm, action); /* Set the command data */ - iwl_mvm_phy_ctxt_cmd_data_v1(mvm, &cmd, chandef, + iwl_mvm_phy_ctxt_cmd_data_v1(mvm, ctxt, &cmd, chandef, chains_static, chains_dynamic); ret = iwl_mvm_send_cmd_pdu(mvm, PHY_CONTEXT_CMD, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 8e26422ca326..c0babb8d5b5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -2001,8 +2001,10 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, struct sk_buff *skb; u8 channel, energy_a, energy_b; struct iwl_mvm_rx_phy_data phy_data = { + .info_type = le32_get_bits(desc->phy_info[1], + IWL_RX_PHY_DATA1_INFO_TYPE_MASK), .d0 = desc->phy_info[0], - .info_type = IWL_RX_PHY_INFO_TYPE_NONE, + .d1 = desc->phy_info[1], }; if (unlikely(iwl_rx_packet_payload_len(pkt) < sizeof(*desc))) @@ -2015,10 +2017,6 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, 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; - phy_data.info_type = - le32_get_bits(desc->phy_info[1], - IWL_RX_PHY_DATA1_INFO_TYPE_MASK); - /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 5a0696c44f6d..0368b7101222 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -2327,9 +2327,9 @@ static int iwl_mvm_scan_umac_v12(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &scan_p->general_params, gen_flags); - ret = iwl_mvm_fill_scan_sched_params(params, - scan_p->periodic_params.schedule, - &scan_p->periodic_params.delay); + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); if (ret) return ret; @@ -2362,9 +2362,9 @@ static int iwl_mvm_scan_umac_v14(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &scan_p->general_params, gen_flags); - ret = iwl_mvm_fill_scan_sched_params(params, - scan_p->periodic_params.schedule, - &scan_p->periodic_params.delay); + ret = iwl_mvm_fill_scan_sched_params(params, + scan_p->periodic_params.schedule, + &scan_p->periodic_params.delay); if (ret) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index f618368eda83..9c45a64c5009 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -3794,8 +3794,12 @@ void iwl_mvm_sta_modify_disable_tx_ap(struct iwl_mvm *mvm, mvm_sta->disable_tx = disable; - /* Tell mac80211 to start/stop queuing tx for this station */ - ieee80211_sta_block_awake(mvm->hw, sta, disable); + /* + * If sta PS state is handled by mac80211, tell it to start/stop + * queuing tx for this station. + */ + if (!ieee80211_hw_check(mvm->hw, AP_LINK_PS)) + ieee80211_sta_block_awake(mvm->hw, sta, disable); iwl_mvm_sta_modify_disable_tx(mvm, mvm_sta, disable); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 83342a6a6d5b..d3307a11fcac 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -31,6 +31,13 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, return; list_del(&te_data->list); + + /* + * the list is only used for AUX ROC events so make sure it is always + * initialized + */ + INIT_LIST_HEAD(&te_data->list); + te_data->running = false; te_data->uid = 0; te_data->id = TE_MAX; @@ -310,6 +317,8 @@ static void iwl_mvm_te_handle_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, te_data->vif, + !te_data->vif->bss_conf.assoc ? + "Not associated and the time event is over already..." : "No beacon heard and the time event is over already..."); break; default: @@ -607,14 +616,15 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm, } static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif) + struct iwl_mvm_vif *mvmvif, + u32 id) { struct iwl_mvm_session_prot_cmd cmd = { .id_and_color = cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color)), .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), - .conf_id = cpu_to_le32(mvmvif->time_event_data.id), + .conf_id = cpu_to_le32(id), }; int ret; @@ -632,6 +642,12 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, { u32 id; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif); + enum nl80211_iftype iftype; + + if (!te_data->vif) + return false; + + iftype = te_data->vif->type; /* * It is possible that by the time we got to this point the time @@ -656,8 +672,8 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm, IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) { /* Session protection is still ongoing. Cancel it */ - iwl_mvm_cancel_session_protection(mvm, mvmvif); - if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) { + iwl_mvm_cancel_session_protection(mvm, mvmvif, id); + if (iftype == NL80211_IFTYPE_P2P_DEVICE) { set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); iwl_mvm_roc_finished(mvm); } @@ -738,11 +754,6 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm, IWL_ERR(mvm, "Couldn't remove the time event\n"); } -/* - * When the firmware supports the session protection API, - * this is not needed since it'll automatically remove the - * session protection after association + beacon reception. - */ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -756,7 +767,15 @@ void iwl_mvm_stop_session_protection(struct iwl_mvm *mvm, id = te_data->id; spin_unlock_bh(&mvm->time_event_lock); - if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) { + if (fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD)) { + if (id != SESSION_PROTECT_CONF_ASSOC) { + IWL_DEBUG_TE(mvm, + "don't remove session protection id=%u\n", + id); + return; + } + } else if (id != TE_BSS_STA_AGGRESSIVE_ASSOC) { IWL_DEBUG_TE(mvm, "don't remove TE with id=%u (not session protection)\n", id); @@ -808,6 +827,8 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, * and know the dtim period. */ iwl_mvm_te_check_disconnect(mvm, vif, + !vif->bss_conf.assoc ? + "Not associated and the session protection is over already..." : "No beacon heard and the session protection is over already..."); spin_lock_bh(&mvm->time_event_lock); iwl_mvm_te_clear_data(mvm, te_data); @@ -981,7 +1002,8 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif) mvmvif = iwl_mvm_vif_from_mac80211(vif); if (vif->type == NL80211_IFTYPE_P2P_DEVICE) { - iwl_mvm_cancel_session_protection(mvm, mvmvif); + iwl_mvm_cancel_session_protection(mvm, mvmvif, + mvmvif->time_event_data.id); set_bit(IWL_MVM_STATUS_NEED_FLUSH_P2P, &mvm->status); } else { iwl_mvm_remove_aux_roc_te(mvm, mvmvif, @@ -1141,6 +1163,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm, iwl_mvm_te_clear_data(mvm, te_data); te_data->duration = le32_to_cpu(cmd.duration_tu); + te_data->vif = vif; spin_unlock_bh(&mvm->time_event_lock); IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index c566be99a4c7..4a3d2971a98b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -238,316 +238,6 @@ u8 iwl_mvm_next_antenna(struct iwl_mvm *mvm, u8 valid, u8 last_idx) return last_idx; } -/* - * Note: This structure is read from the device with IO accesses, - * and the reading already does the endian conversion. As it is - * read with u32-sized accesses, any members with a different size - * need to be ordered correctly though! - */ -struct iwl_error_event_table_v1 { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 pc; /* program counter */ - u32 blink1; /* branch link */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 bcon_time; /* beacon timer */ - u32 tsf_low; /* network timestamp function timer */ - u32 tsf_hi; /* network timestamp function timer */ - u32 gp1; /* GP1 timer register */ - u32 gp2; /* GP2 timer register */ - u32 gp3; /* GP3 timer register */ - u32 ucode_ver; /* uCode version */ - u32 hw_ver; /* HW Silicon version */ - u32 brd_ver; /* HW board version */ - u32 log_pc; /* log program counter */ - u32 frame_ptr; /* frame pointer */ - u32 stack_ptr; /* stack pointer */ - u32 hcmd; /* last host command header */ - u32 isr0; /* isr status register LMPM_NIC_ISR0: - * rxtx_flag */ - u32 isr1; /* isr status register LMPM_NIC_ISR1: - * host_flag */ - u32 isr2; /* isr status register LMPM_NIC_ISR2: - * enc_flag */ - u32 isr3; /* isr status register LMPM_NIC_ISR3: - * time_flag */ - u32 isr4; /* isr status register LMPM_NIC_ISR4: - * wico interrupt */ - u32 isr_pref; /* isr status register LMPM_NIC_PREF_STAT */ - u32 wait_event; /* wait event() caller address */ - u32 l2p_control; /* L2pControlField */ - u32 l2p_duration; /* L2pDurationField */ - u32 l2p_mhvalid; /* L2pMhValidBits */ - u32 l2p_addr_match; /* L2pAddrMatchStat */ - u32 lmpm_pmg_sel; /* indicate which clocks are turned on - * (LMPM_PMG_SEL) */ - u32 u_timestamp; /* indicate when the date and time of the - * compilation */ - u32 flow_handler; /* FH read/write pointers, RX credit */ -} __packed /* LOG_ERROR_TABLE_API_S_VER_1 */; - -struct iwl_error_event_table { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 trm_hw_status0; /* TRM HW status */ - u32 trm_hw_status1; /* TRM HW status */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 bcon_time; /* beacon timer */ - u32 tsf_low; /* network timestamp function timer */ - u32 tsf_hi; /* network timestamp function timer */ - u32 gp1; /* GP1 timer register */ - u32 gp2; /* GP2 timer register */ - u32 fw_rev_type; /* firmware revision type */ - u32 major; /* uCode version major */ - u32 minor; /* uCode version minor */ - u32 hw_ver; /* HW Silicon version */ - u32 brd_ver; /* HW board version */ - u32 log_pc; /* log program counter */ - u32 frame_ptr; /* frame pointer */ - u32 stack_ptr; /* stack pointer */ - u32 hcmd; /* last host command header */ - u32 isr0; /* isr status register LMPM_NIC_ISR0: - * rxtx_flag */ - u32 isr1; /* isr status register LMPM_NIC_ISR1: - * host_flag */ - u32 isr2; /* isr status register LMPM_NIC_ISR2: - * enc_flag */ - u32 isr3; /* isr status register LMPM_NIC_ISR3: - * time_flag */ - u32 isr4; /* isr status register LMPM_NIC_ISR4: - * wico interrupt */ - u32 last_cmd_id; /* last HCMD id handled by the firmware */ - u32 wait_event; /* wait event() caller address */ - u32 l2p_control; /* L2pControlField */ - u32 l2p_duration; /* L2pDurationField */ - u32 l2p_mhvalid; /* L2pMhValidBits */ - u32 l2p_addr_match; /* L2pAddrMatchStat */ - u32 lmpm_pmg_sel; /* indicate which clocks are turned on - * (LMPM_PMG_SEL) */ - u32 u_timestamp; /* indicate when the date and time of the - * compilation */ - u32 flow_handler; /* FH read/write pointers, RX credit */ -} __packed /* LOG_ERROR_TABLE_API_S_VER_3 */; - -/* - * UMAC error struct - relevant starting from family 8000 chip. - * Note: This structure is read from the device with IO accesses, - * and the reading already does the endian conversion. As it is - * read with u32-sized accesses, any members with a different size - * need to be ordered correctly though! - */ -struct iwl_umac_error_event_table { - u32 valid; /* (nonzero) valid, (0) log is empty */ - u32 error_id; /* type of error */ - u32 blink1; /* branch link */ - u32 blink2; /* branch link */ - u32 ilink1; /* interrupt link */ - u32 ilink2; /* interrupt link */ - u32 data1; /* error-specific data */ - u32 data2; /* error-specific data */ - u32 data3; /* error-specific data */ - u32 umac_major; - u32 umac_minor; - u32 frame_pointer; /* core register 27*/ - u32 stack_pointer; /* core register 28 */ - u32 cmd_header; /* latest host cmd sent to UMAC */ - u32 nic_isr_pref; /* ISR status register */ -} __packed; - -#define ERROR_START_OFFSET (1 * sizeof(u32)) -#define ERROR_ELEM_SIZE (7 * sizeof(u32)) - -static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm) -{ - struct iwl_trans *trans = mvm->trans; - struct iwl_umac_error_event_table table = {}; - u32 base = mvm->trans->dbg.umac_error_event_table; - - if (!base && - !(mvm->trans->dbg.error_event_table_tlv_status & - IWL_ERROR_EVENT_TABLE_UMAC)) - return; - - iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - - if (table.valid) - mvm->fwrt.dump.umac_err_id = table.error_id; - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(trans, "Start IWL Error Log Dump:\n"); - IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", - mvm->status, table.valid); - } - - IWL_ERR(mvm, "0x%08X | %s\n", table.error_id, - iwl_fw_lookup_assert_desc(table.error_id)); - IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1); - IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2); - IWL_ERR(mvm, "0x%08X | umac interruptlink1\n", table.ilink1); - IWL_ERR(mvm, "0x%08X | umac interruptlink2\n", table.ilink2); - IWL_ERR(mvm, "0x%08X | umac data1\n", table.data1); - IWL_ERR(mvm, "0x%08X | umac data2\n", table.data2); - IWL_ERR(mvm, "0x%08X | umac data3\n", table.data3); - IWL_ERR(mvm, "0x%08X | umac major\n", table.umac_major); - IWL_ERR(mvm, "0x%08X | umac minor\n", table.umac_minor); - IWL_ERR(mvm, "0x%08X | frame pointer\n", table.frame_pointer); - IWL_ERR(mvm, "0x%08X | stack pointer\n", table.stack_pointer); - IWL_ERR(mvm, "0x%08X | last host cmd\n", table.cmd_header); - IWL_ERR(mvm, "0x%08X | isr status reg\n", table.nic_isr_pref); -} - -static void iwl_mvm_dump_lmac_error_log(struct iwl_mvm *mvm, u8 lmac_num) -{ - struct iwl_trans *trans = mvm->trans; - struct iwl_error_event_table table = {}; - u32 val, base = mvm->trans->dbg.lmac_error_event_table[lmac_num]; - - if (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) { - if (!base) - base = mvm->fw->init_errlog_ptr; - } else { - if (!base) - base = mvm->fw->inst_errlog_ptr; - } - - if (base < 0x400000) { - IWL_ERR(mvm, - "Not valid error log pointer 0x%08X for %s uCode\n", - base, - (mvm->fwrt.cur_fw_img == IWL_UCODE_INIT) - ? "Init" : "RT"); - return; - } - - /* check if there is a HW error */ - val = iwl_trans_read_mem32(trans, base); - if (((val & ~0xf) == 0xa5a5a5a0) || ((val & ~0xf) == 0x5a5a5a50)) { - int err; - - IWL_ERR(trans, "HW error, resetting before reading\n"); - - /* reset the device */ - iwl_trans_sw_reset(trans); - - err = iwl_finish_nic_init(trans, trans->trans_cfg); - if (err) - return; - } - - iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - - if (table.valid) - mvm->fwrt.dump.lmac_err_id[lmac_num] = table.error_id; - - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { - IWL_ERR(trans, "Start IWL Error Log Dump:\n"); - IWL_ERR(trans, "Status: 0x%08lX, count: %d\n", - mvm->status, table.valid); - } - - /* Do not change this output - scripts rely on it */ - - IWL_ERR(mvm, "Loaded firmware version: %s\n", mvm->fw->fw_version); - - IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id, - iwl_fw_lookup_assert_desc(table.error_id)); - IWL_ERR(mvm, "0x%08X | trm_hw_status0\n", table.trm_hw_status0); - IWL_ERR(mvm, "0x%08X | trm_hw_status1\n", table.trm_hw_status1); - IWL_ERR(mvm, "0x%08X | branchlink2\n", table.blink2); - IWL_ERR(mvm, "0x%08X | interruptlink1\n", table.ilink1); - IWL_ERR(mvm, "0x%08X | interruptlink2\n", table.ilink2); - IWL_ERR(mvm, "0x%08X | data1\n", table.data1); - IWL_ERR(mvm, "0x%08X | data2\n", table.data2); - IWL_ERR(mvm, "0x%08X | data3\n", table.data3); - IWL_ERR(mvm, "0x%08X | beacon time\n", table.bcon_time); - IWL_ERR(mvm, "0x%08X | tsf low\n", table.tsf_low); - IWL_ERR(mvm, "0x%08X | tsf hi\n", table.tsf_hi); - IWL_ERR(mvm, "0x%08X | time gp1\n", table.gp1); - IWL_ERR(mvm, "0x%08X | time gp2\n", table.gp2); - IWL_ERR(mvm, "0x%08X | uCode revision type\n", table.fw_rev_type); - IWL_ERR(mvm, "0x%08X | uCode version major\n", table.major); - IWL_ERR(mvm, "0x%08X | uCode version minor\n", table.minor); - IWL_ERR(mvm, "0x%08X | hw version\n", table.hw_ver); - IWL_ERR(mvm, "0x%08X | board version\n", table.brd_ver); - IWL_ERR(mvm, "0x%08X | hcmd\n", table.hcmd); - IWL_ERR(mvm, "0x%08X | isr0\n", table.isr0); - IWL_ERR(mvm, "0x%08X | isr1\n", table.isr1); - IWL_ERR(mvm, "0x%08X | isr2\n", table.isr2); - IWL_ERR(mvm, "0x%08X | isr3\n", table.isr3); - IWL_ERR(mvm, "0x%08X | isr4\n", table.isr4); - IWL_ERR(mvm, "0x%08X | last cmd Id\n", table.last_cmd_id); - IWL_ERR(mvm, "0x%08X | wait_event\n", table.wait_event); - IWL_ERR(mvm, "0x%08X | l2p_control\n", table.l2p_control); - IWL_ERR(mvm, "0x%08X | l2p_duration\n", table.l2p_duration); - IWL_ERR(mvm, "0x%08X | l2p_mhvalid\n", table.l2p_mhvalid); - IWL_ERR(mvm, "0x%08X | l2p_addr_match\n", table.l2p_addr_match); - IWL_ERR(mvm, "0x%08X | lmpm_pmg_sel\n", table.lmpm_pmg_sel); - IWL_ERR(mvm, "0x%08X | timestamp\n", table.u_timestamp); - IWL_ERR(mvm, "0x%08X | flow_handler\n", table.flow_handler); -} - -static void iwl_mvm_dump_iml_error_log(struct iwl_mvm *mvm) -{ - struct iwl_trans *trans = mvm->trans; - u32 error, data1; - - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) { - error = UMAG_SB_CPU_2_STATUS; - data1 = UMAG_SB_CPU_1_STATUS; - } else if (mvm->trans->trans_cfg->device_family >= - IWL_DEVICE_FAMILY_8000) { - error = SB_CPU_2_STATUS; - data1 = SB_CPU_1_STATUS; - } else { - return; - } - - error = iwl_read_umac_prph(trans, UMAG_SB_CPU_2_STATUS); - - IWL_ERR(trans, "IML/ROM dump:\n"); - - if (error & 0xFFFF0000) - IWL_ERR(trans, "0x%04X | IML/ROM SYSASSERT\n", error >> 16); - - IWL_ERR(mvm, "0x%08X | IML/ROM error/state\n", error); - IWL_ERR(mvm, "0x%08X | IML/ROM data1\n", - iwl_read_umac_prph(trans, data1)); - - if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_22000) - IWL_ERR(mvm, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n", - iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG)); -} - -void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm) -{ - if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) { - IWL_ERR(mvm, - "DEVICE_ENABLED bit is not set. Aborting dump.\n"); - return; - } - - iwl_mvm_dump_lmac_error_log(mvm, 0); - - if (mvm->trans->dbg.lmac_error_event_table[1]) - iwl_mvm_dump_lmac_error_log(mvm, 1); - - iwl_mvm_dump_umac_error_log(mvm); - - iwl_mvm_dump_iml_error_log(mvm); - - iwl_fw_error_print_fseq_regs(&mvm->fwrt); -} - int iwl_mvm_reconfig_scd(struct iwl_mvm *mvm, int queue, int fifo, int sta_id, int tid, int frame_limit, u16 ssn) { @@ -621,7 +311,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_request) { struct iwl_mvm_vif *mvmvif; - enum ieee80211_smps_mode smps_mode; + enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC; int i; lockdep_assert_held(&mvm->mutex); @@ -630,10 +320,8 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1) return; - if (vif->type == NL80211_IFTYPE_AP) - smps_mode = IEEE80211_SMPS_OFF; - else - smps_mode = IEEE80211_SMPS_AUTOMATIC; + if (vif->type != NL80211_IFTYPE_STATION) + return; mvmvif = iwl_mvm_vif_from_mac80211(vif); mvmvif->smps_requests[req_type] = smps_request; @@ -683,23 +371,37 @@ void iwl_mvm_accu_radio_stats(struct iwl_mvm *mvm) mvm->accu_radio_stats.on_time_scan += mvm->radio_stats.on_time_scan; } +struct iwl_mvm_diversity_iter_data { + struct iwl_mvm_phy_ctxt *ctxt; + bool result; +}; + static void iwl_mvm_diversity_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool *result = _data; + struct iwl_mvm_diversity_iter_data *data = _data; int i; + if (mvmvif->phy_ctxt != data->ctxt) + return; + for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) { if (mvmvif->smps_requests[i] == IEEE80211_SMPS_STATIC || - mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) - *result = false; + mvmvif->smps_requests[i] == IEEE80211_SMPS_DYNAMIC) { + data->result = false; + break; + } } } -bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) +bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm, + struct iwl_mvm_phy_ctxt *ctxt) { - bool result = true; + struct iwl_mvm_diversity_iter_data data = { + .ctxt = ctxt, + .result = true, + }; lockdep_assert_held(&mvm->mutex); @@ -711,9 +413,9 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm) ieee80211_iterate_active_interfaces_atomic( mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_diversity_iter, &result); + iwl_mvm_diversity_iter, &data); - return result; + return data.result; } void iwl_mvm_send_low_latency_cmd(struct iwl_mvm *mvm, @@ -1398,7 +1100,8 @@ u32 iwl_mvm_get_systime(struct iwl_mvm *mvm) return iwl_read_prph(mvm->trans, reg_addr); } -void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) +void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, + u32 *gp2, u64 *boottime, ktime_t *realtime) { bool ps_disabled; @@ -1412,7 +1115,11 @@ void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, u32 *gp2, u64 *boottime) } *gp2 = iwl_mvm_get_systime(mvm); - *boottime = ktime_get_boottime_ns(); + + if (clock_type == CLOCK_BOOTTIME && boottime) + *boottime = ktime_get_boottime_ns(); + else if (clock_type == CLOCK_REALTIME && realtime) + *realtime = ktime_get_real(); if (!ps_disabled) { mvm->ps_disabled = ps_disabled; |