diff options
Diffstat (limited to 'drivers/net/wireless')
434 files changed, 13186 insertions, 6474 deletions
diff --git a/drivers/net/wireless/admtek/adm8211.c b/drivers/net/wireless/admtek/adm8211.c index a2d87c3ad196..e94a6b180314 100644 --- a/drivers/net/wireless/admtek/adm8211.c +++ b/drivers/net/wireless/admtek/adm8211.c @@ -1293,7 +1293,7 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) ADM8211_CSR_WRITE(ABDA1, reg); } -static int adm8211_config(struct ieee80211_hw *dev, u32 changed) +static int adm8211_config(struct ieee80211_hw *dev, int radio_idx, u32 changed) { struct adm8211_priv *priv = dev->priv; struct ieee80211_conf *conf = &dev->conf; diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 343c9de2749c..1230e6278f23 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -1083,7 +1083,8 @@ static void ar5523_stop(struct ieee80211_hw *hw, bool suspend) mutex_unlock(&ar->mutex); } -static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int ar5523_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct ar5523 *ar = hw->priv; int ret; @@ -1137,7 +1138,7 @@ static void ar5523_remove_interface(struct ieee80211_hw *hw, ar->vif = NULL; } -static int ar5523_hwconfig(struct ieee80211_hw *hw, u32 changed) +static int ar5523_hwconfig(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ar5523 *ar = hw->priv; diff --git a/drivers/net/wireless/ath/ath10k/bmi.c b/drivers/net/wireless/ath/ath10k/bmi.c index 48efdc71d54d..52118867ecde 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.c +++ b/drivers/net/wireless/ath/ath10k/bmi.c @@ -3,8 +3,10 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include "bmi.h" #include "hif.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index a89a7491a76c..7bbda46cfd93 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -4,8 +4,10 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018 The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include "hif.h" #include "ce.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index fe3a8f4a1cc1..6f78f1752cd6 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -4,8 +4,10 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include <linux/module.h> #include <linux/firmware.h> #include <linux/of.h> @@ -1563,7 +1565,7 @@ static int ath10k_core_create_board_name(struct ath10k *ar, char *name, bool with_chip_id) { /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ - char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; + char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = {}; if (with_variant && ar->id.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", @@ -2491,12 +2493,50 @@ static int ath10k_init_hw_params(struct ath10k *ar) return 0; } +static bool ath10k_core_needs_recovery(struct ath10k *ar) +{ + long time_left; + + /* Sometimes the recovery will fail and then the next all recovery fail, + * so avoid infinite recovery. + */ + if (atomic_read(&ar->fail_cont_count) >= ATH10K_RECOVERY_MAX_FAIL_COUNT) { + ath10k_err(ar, "consecutive fail %d times, will shutdown driver!", + atomic_read(&ar->fail_cont_count)); + ar->state = ATH10K_STATE_WEDGED; + return false; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "total recovery count: %d", ++ar->recovery_count); + + if (atomic_read(&ar->pending_recovery)) { + /* Sometimes it happened another recovery work before the previous one + * completed, then the second recovery work will destroy the previous + * one, thus below is to avoid that. + */ + time_left = wait_for_completion_timeout(&ar->driver_recovery, + ATH10K_RECOVERY_TIMEOUT_HZ); + if (time_left) { + ath10k_warn(ar, "previous recovery succeeded, skip this!\n"); + return false; + } + + /* Record the continuous recovery fail count when recovery failed. */ + atomic_inc(&ar->fail_cont_count); + + /* Avoid having multiple recoveries at the same time. */ + return false; + } + + atomic_inc(&ar->pending_recovery); + + return true; +} + void ath10k_core_start_recovery(struct ath10k *ar) { - if (test_and_set_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags)) { - ath10k_warn(ar, "already restarting\n"); + if (!ath10k_core_needs_recovery(ar)) return; - } queue_work(ar->workqueue, &ar->restart_work); } @@ -2532,6 +2572,8 @@ static void ath10k_core_restart(struct work_struct *work) struct ath10k *ar = container_of(work, struct ath10k, restart_work); int ret; + reinit_completion(&ar->driver_recovery); + set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags); /* Place a barrier to make sure the compiler doesn't reorder @@ -2596,8 +2638,6 @@ static void ath10k_core_restart(struct work_struct *work) if (ret) ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d", ret); - - complete(&ar->driver_recovery); } static void ath10k_core_set_coverage_class_work(struct work_struct *work) @@ -2606,7 +2646,7 @@ static void ath10k_core_set_coverage_class_work(struct work_struct *work) set_coverage_class_work); if (ar->hw_params.hw_ops->set_coverage_class) - ar->hw_params.hw_ops->set_coverage_class(ar, -1); + ar->hw_params.hw_ops->set_coverage_class(ar, -1, -1); } static int ath10k_core_init_firmware_features(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 446dca74f06a..8c72ed386edb 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -4,6 +4,7 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _CORE_H_ @@ -87,6 +88,8 @@ IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) #define ATH10K_ITER_RESUME_FLAGS (IEEE80211_IFACE_ITER_RESUME_ALL |\ IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER) +#define ATH10K_RECOVERY_TIMEOUT_HZ (5 * HZ) +#define ATH10K_RECOVERY_MAX_FAIL_COUNT 4 struct ath10k; @@ -779,7 +782,7 @@ enum ath10k_fw_features { /* Firmware supports bypassing PLL setting on init. */ ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9, - /* Raw mode support. If supported, FW supports receiving and trasmitting + /* Raw mode support. If supported, FW supports receiving and transmitting * frames in raw mode. */ ATH10K_FW_FEATURE_RAW_MODE_SUPPORT = 10, @@ -865,9 +868,6 @@ enum ath10k_dev_flags { /* Per Station statistics service */ ATH10K_FLAG_PEER_STATS, - /* Indicates that ath10k device is during recovery process and not complete */ - ATH10K_FLAG_RESTARTING, - /* protected by conf_mutex */ ATH10K_FLAG_NAPI_ENABLED, }; @@ -1211,6 +1211,11 @@ struct ath10k { struct work_struct bundle_tx_work; struct work_struct tx_complete_work; + atomic_t pending_recovery; + unsigned int recovery_count; + /* continuous recovery fail count */ + atomic_t fail_cont_count; + /* cycle count is reported twice for each visited channel during scan. * access protected by data_lock */ diff --git a/drivers/net/wireless/ath/ath10k/coredump.c b/drivers/net/wireless/ath/ath10k/coredump.c index bb3a276b7ed5..50d0c4213ecf 100644 --- a/drivers/net/wireless/ath/ath10k/coredump.c +++ b/drivers/net/wireless/ath/ath10k/coredump.c @@ -3,11 +3,13 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "coredump.h" #include <linux/devcoredump.h> +#include <linux/export.h> #include <linux/kernel.h> #include <linux/types.h> #include <linux/utsname.h> diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index a0c1afeda4dd..b7520220465a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -4,10 +4,12 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/module.h> #include <linux/debugfs.h> +#include <linux/export.h> #include <linux/vmalloc.h> #include <linux/crc32.h> #include <linux/firmware.h> @@ -545,7 +547,7 @@ static ssize_t ath10k_write_simulate_fw_crash(struct file *file, size_t count, loff_t *ppos) { struct ath10k *ar = file->private_data; - char buf[32] = {0}; + char buf[32] = {}; ssize_t rc; int ret; @@ -981,7 +983,7 @@ static ssize_t ath10k_write_htt_max_amsdu_ampdu(struct file *file, { struct ath10k *ar = file->private_data; int res; - char buf[64] = {0}; + char buf[64] = {}; unsigned int amsdu, ampdu; res = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, @@ -1037,7 +1039,7 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file, { struct ath10k *ar = file->private_data; int ret; - char buf[96] = {0}; + char buf[96] = {}; unsigned int log_level; u64 mask; diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c index 0f6de862c3a9..b9fb192e0b48 100644 --- a/drivers/net/wireless/ath/ath10k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c @@ -3,6 +3,7 @@ * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -244,7 +245,7 @@ static ssize_t ath10k_dbg_sta_write_addba(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, buf_size; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -295,7 +296,7 @@ static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, status; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -345,7 +346,7 @@ static ssize_t ath10k_dbg_sta_write_delba(struct file *file, struct ath10k *ar = arsta->arvif->ar; u32 tid, initiator, reason; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 2da08dfebd3e..ce9b248c12dc 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -3,8 +3,11 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> + #include "core.h" #include "hif.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index fb0d5d4cae3a..d7e429041065 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -4,8 +4,11 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> + #include "core.h" #include "htc.h" #include "htt.h" @@ -1881,7 +1884,7 @@ static bool ath10k_htt_rx_h_frag_pn_check(struct ath10k *ar, enum htt_rx_mpdu_encrypt_type enctype) { struct ath10k_peer *peer; - union htt_rx_pn_t *last_pn, new_pn = {0}; + union htt_rx_pn_t *last_pn, new_pn = {}; struct ieee80211_hdr *hdr; u8 tid, frag_number; u32 seq; @@ -2399,7 +2402,7 @@ static bool ath10k_htt_rx_pn_check_replay_hl(struct ath10k *ar, bool last_pn_valid, pn_invalid = false; enum htt_txrx_sec_cast_type sec_index; enum htt_security_types sec_type; - union htt_rx_pn_t new_pn = {0}; + union htt_rx_pn_t new_pn = {}; struct htt_hl_rx_desc *rx_desc; union htt_rx_pn_t *last_pn; u32 rx_desc_info, tid; @@ -2462,7 +2465,7 @@ static bool ath10k_htt_rx_proc_rx_ind_hl(struct ath10k_htt *htt, struct fw_rx_desc_hl *fw_desc; enum htt_txrx_sec_cast_type sec_index; enum htt_security_types sec_type; - union htt_rx_pn_t new_pn = {0}; + union htt_rx_pn_t new_pn = {}; struct htt_hl_rx_desc *rx_desc; struct ieee80211_hdr *hdr; struct ieee80211_rx_status *rx_status; @@ -2764,7 +2767,7 @@ static bool ath10k_htt_rx_proc_rx_frag_ind_hl(struct ath10k_htt *htt, struct htt_rx_indication_hl *rx_hl; enum htt_security_types sec_type; u32 tid, frag, seq, rx_desc_info; - union htt_rx_pn_t new_pn = {0}; + union htt_rx_pn_t new_pn = {}; struct htt_hl_rx_desc *rx_desc; u16 peer_id, sc, hdr_space; union htt_rx_pn_t *last_pn; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 9725feecefd6..d6f1d85ba871 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -3,8 +3,10 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include <linux/etherdevice.h> #include "htt.h" #include "mac.h" @@ -508,7 +510,7 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) { struct ath10k *ar = ctx; struct ath10k_htt *htt = &ar->htt; - struct htt_tx_done tx_done = {0}; + struct htt_tx_done tx_done = {}; ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %u\n", msdu_id); @@ -558,7 +560,7 @@ void ath10k_htt_op_ep_tx_credits(struct ath10k *ar) void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) { struct ath10k_htt *htt = &ar->htt; - struct htt_tx_done tx_done = {0}; + struct htt_tx_done tx_done = {}; struct htt_cmd_hdr *htt_hdr; struct htt_data_tx_desc *desc_hdr = NULL; u16 flags1 = 0; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 84b35a22fc23..59b6cebfdd8f 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -590,6 +590,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, * function monitors and modifies the corresponding MAC registers. */ static void ath10k_hw_qca988x_set_coverage_class(struct ath10k *ar, + int radio_idx, s16 value) { u32 slottime_reg; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 7ffa1fbe2874..da71dce9babf 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -473,8 +473,8 @@ enum ath10k_hw_cc_wraparound_type { */ ATH10K_HW_CC_WRAP_SHIFTED_ALL = 1, - /* Each hw counter wrapsaround independently. When the - * counter overflows the repestive counter is right shifted + /* Each hw counter wraps around independently. When the + * counter overflows the respective counter is right shifted * by 1, i.e reset to 0x7fffffff, and other counters will be * running unaffected. In this type of wraparound, it should * be possible to report accurate Rx busy time unlike the @@ -646,7 +646,7 @@ struct htt_rx_ring_rx_desc_offsets; /* Defines needed for Rx descriptor abstraction */ struct ath10k_hw_ops { - void (*set_coverage_class)(struct ath10k *ar, s16 value); + void (*set_coverage_class)(struct ath10k *ar, int radio_idx, s16 value); int (*enable_pll_clk)(struct ath10k *ar); int (*tx_data_rssi_pad_bytes)(struct htt_resp *htt); int (*is_rssi_enable)(struct htt_resp *resp); @@ -837,7 +837,7 @@ ath10k_is_rssi_enable(struct ath10k_hw_params *hw, #define TARGET_10_4_NUM_TDLS_BUFFER_STA 1 #define TARGET_10_4_NUM_TDLS_SLEEP_STA 1 -/* Maximum number of Copy Engine's supported */ +/* Maximum number of Copy Engines supported */ #define CE_COUNT_MAX 12 /* Number of Copy Engines supported */ @@ -1134,7 +1134,7 @@ ath10k_is_rssi_enable(struct ath10k_hw_params *hw, #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB) /* Register definitions for first generation ath10k cards. These cards include - * a mac thich has a register allocation similar to ath9k and at least some + * a mac which has a register allocation similar to ath9k and at least some * registers including the ones relevant for modifying the coverage class are * identical to the ath9k definitions. * These registers are usually managed by the ath10k firmware. However by diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 07fe05384cdf..24dd794e31ea 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -9,6 +9,7 @@ #include "mac.h" +#include <linux/export.h> #include <net/cfg80211.h> #include <net/mac80211.h> #include <linux/etherdevice.h> @@ -3384,7 +3385,7 @@ static int ath10k_update_channel_list(struct ath10k *ar) struct ieee80211_supported_band **bands; enum nl80211_band band; struct ieee80211_channel *channel; - struct wmi_scan_chan_list_arg arg = {0}; + struct wmi_scan_chan_list_arg arg = {}; struct wmi_channel_arg *ch; bool passive; int len; @@ -4820,7 +4821,8 @@ void ath10k_halt(struct ath10k *ar) spin_unlock_bh(&ar->data_lock); } -static int ath10k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +static int ath10k_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct ath10k *ar = hw->priv; @@ -4883,7 +4885,7 @@ static int ath10k_mac_get_vht_cap_bf_sound_dim(struct ath10k *ar) static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) { - struct ieee80211_sta_vht_cap vht_cap = {0}; + struct ieee80211_sta_vht_cap vht_cap = {}; struct ath10k_hw_params *hw = &ar->hw_params; u16 mcs_map; u32 val; @@ -4941,7 +4943,7 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar) { int i; - struct ieee80211_sta_ht_cap ht_cap = {0}; + struct ieee80211_sta_ht_cap ht_cap = {}; if (!(ar->ht_cap_info & WMI_HT_CAP_ENABLED)) return ht_cap; @@ -5067,7 +5069,8 @@ static int __ath10k_set_antenna(struct ath10k *ar, u32 tx_ant, u32 rx_ant) return 0; } -static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +static int ath10k_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct ath10k *ar = hw->priv; int ret; @@ -5172,7 +5175,7 @@ static int ath10k_start(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; u32 param; int ret = 0; - struct wmi_bb_timing_cfg_arg bb_timing = {0}; + struct wmi_bb_timing_cfg_arg bb_timing = {}; /* * This makes sense only when restarting hw. It is harmless to call @@ -5437,7 +5440,7 @@ static int ath10k_config_ps(struct ath10k *ar) return ret; } -static int ath10k_config(struct ieee80211_hw *hw, u32 changed) +static int ath10k_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ath10k *ar = hw->priv; struct ieee80211_conf *conf = &hw->conf; @@ -6336,7 +6339,8 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } -static void ath10k_mac_op_set_coverage_class(struct ieee80211_hw *hw, s16 value) +static void ath10k_mac_op_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, + s16 value) { struct ath10k *ar = hw->priv; @@ -6347,7 +6351,7 @@ static void ath10k_mac_op_set_coverage_class(struct ieee80211_hw *hw, s16 value) WARN_ON_ONCE(1); return; } - ar->hw_params.hw_ops->set_coverage_class(ar, value); + ar->hw_params.hw_ops->set_coverage_class(ar, -1, value); } struct ath10k_mac_tdls_iter_data { @@ -8035,7 +8039,8 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw, * in ath10k, but device-specific in mac80211. */ -static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct ath10k *ar = hw->priv; struct ath10k_vif *arvif; @@ -8058,7 +8063,8 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static int ath10k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +static int ath10k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { /* Even though there's a WMI enum for fragmentation threshold no known * firmware actually implements it. Moreover it is not possible to rely @@ -8156,7 +8162,12 @@ static void ath10k_reconfig_complete(struct ieee80211_hw *hw, ath10k_info(ar, "device successfully recovered\n"); ar->state = ATH10K_STATE_ON; ieee80211_wake_queues(ar->hw); - clear_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags); + + /* Clear recovery state. */ + complete(&ar->driver_recovery); + atomic_set(&ar->fail_cont_count, 0); + atomic_set(&ar->pending_recovery, 0); + if (ar->hw_params.hw_restart_disconnect) { list_for_each_entry(arvif, &ar->arvifs, list) { if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_STA) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1e6d43285138..97b49bf4ad80 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -3,6 +3,7 @@ * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/pci.h> @@ -63,7 +64,7 @@ static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA9984_1_0_DEVICE_ID) }, /* PCI-E QCA9984 V1 */ { PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */ { PCI_VDEVICE(ATHEROS, QCA9887_1_0_DEVICE_ID) }, /* PCI-E QCA9887 */ - {0} + {} }; static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c index d51f2e5a79a4..f0713bd36173 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -936,7 +936,7 @@ static int ath10k_snoc_hif_start(struct ath10k *ar) bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX); - dev_set_threaded(ar->napi_dev, true); + netif_threaded_enable(ar->napi_dev); ath10k_core_napi_enable(ar); /* IRQs are left enabled when we restart due to a firmware crash */ if (!test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags)) diff --git a/drivers/net/wireless/ath/ath10k/trace.c b/drivers/net/wireless/ath/ath10k/trace.c index c7d4c97e6079..421ec47c59bd 100644 --- a/drivers/net/wireless/ath/ath10k/trace.c +++ b/drivers/net/wireless/ath/ath10k/trace.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: ISC /* * Copyright (c) 2012 Qualcomm Atheros, Inc. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include <linux/module.h> #define CREATE_TRACE_POINTS diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index df6a24f8f8d5..cb8ae751eb31 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4,6 +4,7 @@ * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/skbuff.h> @@ -1941,6 +1942,11 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id) } wait_event_timeout(ar->wmi.tx_credits_wq, ({ + if (ar->state == ATH10K_STATE_WEDGED) { + ret = -ESHUTDOWN; + ath10k_dbg(ar, ATH10K_DBG_WMI, + "drop wmi command %d, hardware is wedged\n", cmd_id); + } /* try to send pending beacons first. they take priority */ ath10k_wmi_tx_beacons_nowait(ar); diff --git a/drivers/net/wireless/ath/ath11k/ahb.c b/drivers/net/wireless/ath/ath11k/ahb.c index fde1ce43c499..50809cc1dad4 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -988,7 +988,7 @@ static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab) { struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab); struct device *host_dev = ab->dev; - struct platform_device_info info = {0}; + struct platform_device_info info = {}; struct iommu_domain *iommu_dom; struct platform_device *pdev; struct device_node *node; diff --git a/drivers/net/wireless/ath/ath11k/ce.c b/drivers/net/wireless/ath/ath11k/ce.c index 746038006eb4..c65fc9fb539e 100644 --- a/drivers/net/wireless/ath/ath11k/ce.c +++ b/drivers/net/wireless/ath/ath11k/ce.c @@ -2,8 +2,10 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include "dp_rx.h" #include "debug.h" #include "hif.h" @@ -393,9 +395,6 @@ static int ath11k_ce_completed_recv_next(struct ath11k_ce_pipe *pipe, goto err; } - /* Make sure descriptor is read after the head pointer. */ - dma_rmb(); - *nbytes = ath11k_hal_ce_dst_status_get_length(desc); *skb = pipe->dest_ring->skb[sw_index]; @@ -555,7 +554,7 @@ static int ath11k_ce_init_ring(struct ath11k_base *ab, struct ath11k_ce_ring *ce_ring, int ce_id, enum hal_ring_type type) { - struct hal_srng_params params = { 0 }; + struct hal_srng_params params = {}; int ret; params.ring_base_paddr = ce_ring->base_addr_ce_space; diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c index 22a101136135..d49353b6b2e7 100644 --- a/drivers/net/wireless/ath/ath11k/core.c +++ b/drivers/net/wireless/ath/ath11k/core.c @@ -2,8 +2,10 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/remoteproc.h> @@ -1391,7 +1393,7 @@ static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name, enum ath11k_bdf_name_type name_type) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ - char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; + char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = {}; if (with_variant && ab->qmi.target.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", @@ -2581,10 +2583,15 @@ int ath11k_core_init(struct ath11k_base *ab) ret = ath11k_core_soc_create(ab); if (ret) { ath11k_err(ab, "failed to create soc core: %d\n", ret); - return ret; + goto err_unregister_pm_notifier; } return 0; + +err_unregister_pm_notifier: + ath11k_core_pm_notifier_unregister(ab); + + return ret; } EXPORT_SYMBOL(ath11k_core_init); diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h index 6b2f207975e3..220d69a7a429 100644 --- a/drivers/net/wireless/ath/ath11k/core.h +++ b/drivers/net/wireless/ath/ath11k/core.h @@ -17,6 +17,7 @@ #include <linux/average.h> #include <linux/firmware.h> #include <linux/suspend.h> +#include <linux/of.h> #include "qmi.h" #include "htc.h" @@ -1322,8 +1323,16 @@ static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab, const char *filename, void *buf, size_t buf_len) { - snprintf(buf, buf_len, "%s/%s/%s", ATH11K_FW_DIR, - ab->hw_params.fw.dir, filename); + const char *fw_name = NULL; + + of_property_read_string(ab->dev->of_node, "firmware-name", &fw_name); + + if (fw_name && strncmp(filename, "board", 5)) + snprintf(buf, buf_len, "%s/%s/%s/%s", ATH11K_FW_DIR, + ab->hw_params.fw.dir, fw_name, filename); + else + snprintf(buf, buf_len, "%s/%s/%s", ATH11K_FW_DIR, + ab->hw_params.fw.dir, filename); } static inline const char *ath11k_bus_str(enum ath11k_bus bus) diff --git a/drivers/net/wireless/ath/ath11k/coredump.c b/drivers/net/wireless/ath/ath11k/coredump.c index b8bad358cebe..1949d57b007a 100644 --- a/drivers/net/wireless/ath/ath11k/coredump.c +++ b/drivers/net/wireless/ath/ath11k/coredump.c @@ -2,8 +2,10 @@ /* * Copyright (c) 2020 The Linux Foundation. All rights reserved. * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/devcoredump.h> +#include <linux/export.h> #include "hif.h" #include "coredump.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath11k/dbring.c b/drivers/net/wireless/ath/ath11k/dbring.c index fbb6e8d8a476..520d8b8662a2 100644 --- a/drivers/net/wireless/ath/ath11k/dbring.c +++ b/drivers/net/wireless/ath/ath11k/dbring.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -153,7 +154,7 @@ int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar, struct ath11k_dbring *ring, enum wmi_direct_buffer_module id) { - struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {0}; + struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {}; int ret; if (id >= WMI_DIRECT_BUF_MAX) diff --git a/drivers/net/wireless/ath/ath11k/debug.c b/drivers/net/wireless/ath/ath11k/debug.c index 2b8544355fc1..37d23a559ba3 100644 --- a/drivers/net/wireless/ath/ath11k/debug.c +++ b/drivers/net/wireless/ath/ath11k/debug.c @@ -2,8 +2,10 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include <linux/vmalloc.h> #include "core.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath11k/debugfs.c b/drivers/net/wireless/ath/ath11k/debugfs.c index 5d46f8e4c231..977f945b6e66 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs.c +++ b/drivers/net/wireless/ath/ath11k/debugfs.c @@ -2,8 +2,10 @@ /* * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include <linux/vmalloc.h> #include "debugfs.h" @@ -373,7 +375,7 @@ static ssize_t ath11k_write_simulate_fw_crash(struct file *file, struct ath11k_base *ab = file->private_data; struct ath11k_pdev *pdev; struct ath11k *ar = ab->pdevs[0].ar; - char buf[32] = {0}; + char buf[32] = {}; ssize_t rc; int i, ret, radioup = 0; @@ -471,7 +473,7 @@ static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file, size_t count, loff_t *ppos) { - char buf[32] = {0}; + char buf[32] = {}; struct ath11k *ar = file->private_data; int len = 0; @@ -495,7 +497,7 @@ static ssize_t ath11k_write_extd_rx_stats(struct file *file, { struct ath11k *ar = file->private_data; struct ath11k_base *ab = ar->ab; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 enable, rx_filter = 0, ring_id; int i; int ret; @@ -735,7 +737,7 @@ static ssize_t ath11k_write_fw_dbglog(struct file *file, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; - char buf[128] = {0}; + char buf[128] = {}; struct ath11k_fw_dbglog dbglog; unsigned int param, mod_id_index, is_end; u64 value; @@ -948,9 +950,9 @@ static ssize_t ath11k_write_pktlog_filter(struct file *file, { struct ath11k *ar = file->private_data; struct ath11k_base *ab = ar->ab; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 rx_filter = 0, ring_id, filter, mode; - u8 buf[128] = {0}; + u8 buf[128] = {}; int i, ret, rx_buf_sz = 0; ssize_t rc; @@ -1079,7 +1081,7 @@ static ssize_t ath11k_read_pktlog_filter(struct file *file, size_t count, loff_t *ppos) { - char buf[32] = {0}; + char buf[32] = {}; struct ath11k *ar = file->private_data; int len = 0; @@ -1233,7 +1235,7 @@ static ssize_t ath11k_debugfs_write_enable_dbr_dbg(struct file *file, size_t count, loff_t *ppos) { struct ath11k *ar = file->private_data; - char buf[32] = {0}; + char buf[32] = {}; u32 dbr_id, enable; int ret; @@ -1471,7 +1473,7 @@ int ath11k_debugfs_register(struct ath11k *ar) { struct ath11k_base *ab = ar->ab; char pdev_name[10]; - char buf[100] = {0}; + char buf[100] = {}; snprintf(pdev_name, sizeof(pdev_name), "%s%u", "mac", ar->pdev_idx); @@ -1554,10 +1556,10 @@ static ssize_t ath11k_write_twt_add_dialog(struct file *file, size_t count, loff_t *ppos) { struct ath11k_vif *arvif = file->private_data; - struct wmi_twt_add_dialog_params params = { 0 }; - struct wmi_twt_enable_params twt_params = {0}; + struct wmi_twt_add_dialog_params params = {}; + struct wmi_twt_enable_params twt_params = {}; struct ath11k *ar = arvif->ar; - u8 buf[128] = {0}; + u8 buf[128] = {}; int ret; if (ar->twt_enabled == 0) { @@ -1630,10 +1632,10 @@ static ssize_t ath11k_write_twt_del_dialog(struct file *file, size_t count, loff_t *ppos) { struct ath11k_vif *arvif = file->private_data; - struct wmi_twt_del_dialog_params params = { 0 }; - struct wmi_twt_enable_params twt_params = {0}; + struct wmi_twt_del_dialog_params params = {}; + struct wmi_twt_enable_params twt_params = {}; struct ath11k *ar = arvif->ar; - u8 buf[64] = {0}; + u8 buf[64] = {}; int ret; if (ar->twt_enabled == 0) { @@ -1677,8 +1679,8 @@ static ssize_t ath11k_write_twt_pause_dialog(struct file *file, size_t count, loff_t *ppos) { struct ath11k_vif *arvif = file->private_data; - struct wmi_twt_pause_dialog_params params = { 0 }; - u8 buf[64] = {0}; + struct wmi_twt_pause_dialog_params params = {}; + u8 buf[64] = {}; int ret; if (arvif->ar->twt_enabled == 0) { @@ -1716,8 +1718,8 @@ static ssize_t ath11k_write_twt_resume_dialog(struct file *file, size_t count, loff_t *ppos) { struct ath11k_vif *arvif = file->private_data; - struct wmi_twt_resume_dialog_params params = { 0 }; - u8 buf[64] = {0}; + struct wmi_twt_resume_dialog_params params = {}; + u8 buf[64] = {}; int ret; if (arvif->ar->twt_enabled == 0) { diff --git a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c index 870e86a31bf8..11d28c42227e 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/vmalloc.h> @@ -375,7 +376,7 @@ static inline void htt_print_hw_stats_intr_misc_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char hw_intr_name[HTT_STATS_MAX_HW_INTR_NAME_LEN + 1] = {0}; + char hw_intr_name[HTT_STATS_MAX_HW_INTR_NAME_LEN + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_INTR_MISC_TLV:\n"); memcpy(hw_intr_name, &(htt_stats_buf->hw_intr_name[0]), @@ -402,7 +403,7 @@ htt_print_hw_stats_wd_timeout_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char hw_module_name[HTT_STATS_MAX_HW_MODULE_NAME_LEN + 1] = {0}; + char hw_module_name[HTT_STATS_MAX_HW_MODULE_NAME_LEN + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_HW_STATS_WD_TIMEOUT_TLV:\n"); memcpy(hw_module_name, &(htt_stats_buf->hw_module_name[0]), @@ -514,7 +515,7 @@ static inline void htt_print_tx_tid_stats_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + char tid_name[MAX_HTT_TID_NAME + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_TLV:\n"); memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); @@ -567,7 +568,7 @@ static inline void htt_print_tx_tid_stats_v1_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + char tid_name[MAX_HTT_TID_NAME + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_TX_TID_STATS_V1_TLV:\n"); memcpy(tid_name, &(htt_stats_buf->tid_name[0]), MAX_HTT_TID_NAME); @@ -624,7 +625,7 @@ static inline void htt_print_rx_tid_stats_tlv(const void *tag_buf, u8 *buf = stats_req->buf; u32 len = stats_req->buf_len; u32 buf_len = ATH11K_HTT_STATS_BUF_SIZE; - char tid_name[MAX_HTT_TID_NAME + 1] = {0}; + char tid_name[MAX_HTT_TID_NAME + 1] = {}; len += scnprintf(buf + len, buf_len - len, "HTT_RX_TID_STATS_TLV:\n"); len += scnprintf(buf + len, buf_len - len, "sw_peer_id = %lu\n", @@ -4712,7 +4713,7 @@ int ath11k_debugfs_htt_stats_req(struct ath11k *ar) u8 type = stats_req->type; u64 cookie = 0; int ret, pdev_id = ar->pdev->pdev_id; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; init_completion(&stats_req->cmpln); @@ -4852,7 +4853,7 @@ static ssize_t ath11k_write_htt_stats_reset(struct file *file, { struct ath11k *ar = file->private_data; u8 type; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; int ret; ret = kstrtou8_from_user(user_buf, count, 0, &type); diff --git a/drivers/net/wireless/ath/ath11k/debugfs_sta.c b/drivers/net/wireless/ath/ath11k/debugfs_sta.c index f56a24b6c8da..d89d0f28d890 100644 --- a/drivers/net/wireless/ath/ath11k/debugfs_sta.c +++ b/drivers/net/wireless/ath/ath11k/debugfs_sta.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/vmalloc.h> @@ -456,7 +457,7 @@ static ssize_t ath11k_dbg_sta_read_peer_pktlog(struct file *file, struct ieee80211_sta *sta = file->private_data; struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); struct ath11k *ar = arsta->arvif->ar; - char buf[32] = {0}; + char buf[32] = {}; int len; mutex_lock(&ar->conf_mutex); @@ -485,7 +486,7 @@ static ssize_t ath11k_dbg_sta_write_delba(struct file *file, struct ath11k *ar = arsta->arvif->ar; u32 tid, initiator, reason; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -536,7 +537,7 @@ static ssize_t ath11k_dbg_sta_write_addba_resp(struct file *file, struct ath11k *ar = arsta->arvif->ar; u32 tid, status; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -586,7 +587,7 @@ static ssize_t ath11k_dbg_sta_write_addba(struct file *file, struct ath11k *ar = arsta->arvif->ar; u32 tid, buf_size; int ret; - char buf[64] = {0}; + char buf[64] = {}; ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count); @@ -700,7 +701,7 @@ ath11k_write_htt_peer_stats_reset(struct file *file, struct ieee80211_sta *sta = file->private_data; struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); struct ath11k *ar = arsta->arvif->ar; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; int ret; u8 type; diff --git a/drivers/net/wireless/ath/ath11k/dp.c b/drivers/net/wireless/ath/ath11k/dp.c index bf3928ada995..56b1a657e0b0 100644 --- a/drivers/net/wireless/ath/ath11k/dp.c +++ b/drivers/net/wireless/ath/ath11k/dp.c @@ -2,9 +2,11 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <crypto/hash.h> +#include <linux/export.h> #include "core.h" #include "dp_tx.h" #include "hal_tx.h" @@ -223,7 +225,7 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, enum hal_ring_type type, int ring_num, int mac_id, int num_entries) { - struct hal_srng_params params = { 0 }; + struct hal_srng_params params = {}; int entry_sz = ath11k_hal_srng_get_entrysize(ab, type); int max_entries = ath11k_hal_srng_get_max_entries(ab, type); int ret; diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 9230a965f6f0..ffc7482c77b6 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -719,7 +719,7 @@ static void ath11k_dp_reo_cmd_free(struct ath11k_dp *dp, void *ctx, static void ath11k_dp_reo_cache_flush(struct ath11k_base *ab, struct dp_rx_tid *rx_tid) { - struct ath11k_hal_reo_cmd cmd = {0}; + struct ath11k_hal_reo_cmd cmd = {}; unsigned long tot_desc_sz, desc_sz; int ret; @@ -811,7 +811,7 @@ free_desc: void ath11k_peer_rx_tid_delete(struct ath11k *ar, struct ath11k_peer *peer, u8 tid) { - struct ath11k_hal_reo_cmd cmd = {0}; + struct ath11k_hal_reo_cmd cmd = {}; struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; int ret; @@ -938,7 +938,7 @@ static int ath11k_peer_rx_tid_reo_update(struct ath11k *ar, u32 ba_win_sz, u16 ssn, bool update_ssn) { - struct ath11k_hal_reo_cmd cmd = {0}; + struct ath11k_hal_reo_cmd cmd = {}; int ret; cmd.addr_lo = lower_32_bits(rx_tid->paddr); @@ -1157,7 +1157,7 @@ int ath11k_dp_peer_rx_pn_replay_config(struct ath11k_vif *arvif, { struct ath11k *ar = arvif->ar; struct ath11k_base *ab = ar->ab; - struct ath11k_hal_reo_cmd cmd = {0}; + struct ath11k_hal_reo_cmd cmd = {}; struct ath11k_peer *peer; struct dp_rx_tid *rx_tid; u8 tid; @@ -2591,7 +2591,7 @@ static void ath11k_dp_rx_process_received_packets(struct ath11k_base *ab, { struct sk_buff *msdu; struct ath11k *ar; - struct ieee80211_rx_status rx_status = {0}; + struct ieee80211_rx_status rx_status = {}; int ret; if (skb_queue_empty(msdu_list)) @@ -2626,7 +2626,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, { struct ath11k_dp *dp = &ab->dp; struct dp_rxdma_ring *rx_ring; - int num_buffs_reaped[MAX_RADIOS] = {0}; + int num_buffs_reaped[MAX_RADIOS] = {}; struct sk_buff_head msdu_list[MAX_RADIOS]; struct ath11k_skb_rxcb *rxcb; int total_msdu_reaped = 0; @@ -2637,7 +2637,7 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, struct ath11k *ar; struct hal_reo_dest_ring *desc; enum hal_reo_dest_ring_push_reason push_reason; - u32 cookie, info0, rx_msdu_info0, rx_mpdu_info0; + u32 cookie; int i; for (i = 0; i < MAX_RADIOS; i++) @@ -2650,14 +2650,11 @@ int ath11k_dp_process_rx(struct ath11k_base *ab, int ring_id, try_again: ath11k_hal_srng_access_begin(ab, srng); - /* Make sure descriptor is read after the head pointer. */ - dma_rmb(); - while (likely(desc = (struct hal_reo_dest_ring *)ath11k_hal_srng_dst_get_next_entry(ab, srng))) { cookie = FIELD_GET(BUFFER_ADDR_INFO1_SW_COOKIE, - READ_ONCE(desc->buf_addr_info.info1)); + desc->buf_addr_info.info1); buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie); mac_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_PDEV_ID, cookie); @@ -2686,9 +2683,8 @@ try_again: num_buffs_reaped[mac_id]++; - info0 = READ_ONCE(desc->info0); push_reason = FIELD_GET(HAL_REO_DEST_RING_INFO0_PUSH_REASON, - info0); + desc->info0); if (unlikely(push_reason != HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION)) { dev_kfree_skb_any(msdu); @@ -2696,21 +2692,18 @@ try_again: continue; } - rx_msdu_info0 = READ_ONCE(desc->rx_msdu_info.info0); - rx_mpdu_info0 = READ_ONCE(desc->rx_mpdu_info.info0); - - rxcb->is_first_msdu = !!(rx_msdu_info0 & + rxcb->is_first_msdu = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_FIRST_MSDU_IN_MPDU); - rxcb->is_last_msdu = !!(rx_msdu_info0 & + rxcb->is_last_msdu = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_LAST_MSDU_IN_MPDU); - rxcb->is_continuation = !!(rx_msdu_info0 & + rxcb->is_continuation = !!(desc->rx_msdu_info.info0 & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION); rxcb->peer_id = FIELD_GET(RX_MPDU_DESC_META_DATA_PEER_ID, - READ_ONCE(desc->rx_mpdu_info.meta_data)); + desc->rx_mpdu_info.meta_data); rxcb->seq_no = FIELD_GET(RX_MPDU_DESC_INFO0_SEQ_NUM, - rx_mpdu_info0); + desc->rx_mpdu_info.info0); rxcb->tid = FIELD_GET(HAL_REO_DEST_RING_INFO0_RX_QUEUE_NUM, - info0); + desc->info0); rxcb->mac_id = mac_id; __skb_queue_tail(&msdu_list[mac_id], msdu); @@ -3231,7 +3224,7 @@ static int ath11k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key, size_t data_len, u8 *mic) { SHASH_DESC_ON_STACK(desc, tfm); - u8 mic_hdr[16] = {0}; + u8 mic_hdr[16] = {}; u8 tid = 0; int ret; @@ -3825,7 +3818,7 @@ int ath11k_dp_process_rx_err(struct ath11k_base *ab, struct napi_struct *napi, struct dp_link_desc_bank *link_desc_banks; enum hal_rx_buf_return_buf_manager rbm; int tot_n_bufs_reaped, quota, ret, i; - int n_bufs_reaped[MAX_RADIOS] = {0}; + int n_bufs_reaped[MAX_RADIOS] = {}; struct dp_rxdma_ring *rx_ring; struct dp_srng *reo_except; u32 desc_bank, num_msdus; @@ -4106,7 +4099,7 @@ static void ath11k_dp_rx_wbm_err(struct ath11k *ar, struct sk_buff_head *msdu_list) { struct ath11k_skb_rxcb *rxcb = ATH11K_SKB_RXCB(msdu); - struct ieee80211_rx_status rxs = {0}; + struct ieee80211_rx_status rxs = {}; bool drop = true; switch (rxcb->err_rel_src) { @@ -4142,7 +4135,7 @@ int ath11k_dp_rx_process_wbm_err(struct ath11k_base *ab, struct ath11k_skb_rxcb *rxcb; u32 *rx_desc; int buf_id, mac_id; - int num_buffs_reaped[MAX_RADIOS] = {0}; + int num_buffs_reaped[MAX_RADIOS] = {}; int total_num_buffs_reaped = 0; int ret, i; diff --git a/drivers/net/wireless/ath/ath11k/dp_tx.c b/drivers/net/wireless/ath/ath11k/dp_tx.c index 8522c67baabf..562aba66582f 100644 --- a/drivers/net/wireless/ath/ath11k/dp_tx.c +++ b/drivers/net/wireless/ath/ath11k/dp_tx.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -84,7 +85,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, { struct ath11k_base *ab = ar->ab; struct ath11k_dp *dp = &ab->dp; - struct hal_tx_info ti = {0}; + struct hal_tx_info ti = {}; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath11k_skb_cb *skb_cb = ATH11K_SKB_CB(skb); struct hal_srng *tcl_ring; @@ -316,7 +317,7 @@ ath11k_dp_tx_htt_tx_complete_buf(struct ath11k_base *ab, struct dp_tx_ring *tx_ring, struct ath11k_dp_htt_wbm_tx_status *ts) { - struct ieee80211_tx_status status = { 0 }; + struct ieee80211_tx_status status = {}; struct sk_buff *msdu; struct ieee80211_tx_info *info; struct ath11k_skb_cb *skb_cb; @@ -391,7 +392,7 @@ ath11k_dp_tx_process_htt_tx_complete(struct ath11k_base *ab, u32 msdu_id, struct dp_tx_ring *tx_ring) { struct htt_tx_wbm_completion *status_desc; - struct ath11k_dp_htt_wbm_tx_status ts = {0}; + struct ath11k_dp_htt_wbm_tx_status ts = {}; enum hal_wbm_htt_tx_comp_status wbm_status; status_desc = desc + HTT_TX_WBM_COMP_STATUS_OFFSET; @@ -551,8 +552,8 @@ static void ath11k_dp_tx_complete_msdu(struct ath11k *ar, struct sk_buff *msdu, struct hal_tx_status *ts) { - struct ieee80211_tx_status status = { 0 }; - struct ieee80211_rate_status status_rate = { 0 }; + struct ieee80211_tx_status status = {}; + struct ieee80211_rate_status status_rate = {}; struct ath11k_base *ab = ar->ab; struct ieee80211_tx_info *info; struct ath11k_skb_cb *skb_cb; @@ -690,7 +691,7 @@ void ath11k_dp_tx_completion_handler(struct ath11k_base *ab, int ring_id) int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id; struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id]; struct sk_buff *msdu; - struct hal_tx_status ts = { 0 }; + struct hal_tx_status ts = {}; struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; u32 *desc; u32 msdu_id; @@ -1187,7 +1188,7 @@ int ath11k_dp_tx_htt_monitor_mode_ring_config(struct ath11k *ar, bool reset) { struct ath11k_pdev_dp *dp = &ar->dp; struct ath11k_base *ab = ar->ab; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; int ret = 0, ring_id = 0, i; if (ab->hw_params.full_monitor_mode) { diff --git a/drivers/net/wireless/ath/ath11k/fw.c b/drivers/net/wireless/ath/ath11k/fw.c index cbbd8e57119f..07d775a7b528 100644 --- a/drivers/net/wireless/ath/ath11k/fw.c +++ b/drivers/net/wireless/ath/ath11k/fw.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include "core.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath11k/hal.c b/drivers/net/wireless/ath/ath11k/hal.c index 8cb1505a5a0c..0c3ce7509ab8 100644 --- a/drivers/net/wireless/ath/ath11k/hal.c +++ b/drivers/net/wireless/ath/ath11k/hal.c @@ -2,8 +2,10 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/dma-mapping.h> +#include <linux/export.h> #include "hal_tx.h" #include "debug.h" #include "hal_desc.h" @@ -599,7 +601,7 @@ u32 ath11k_hal_ce_dst_status_get_length(void *buf) struct hal_ce_srng_dst_status_desc *desc = buf; u32 len; - len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, READ_ONCE(desc->flags)); + len = FIELD_GET(HAL_CE_DST_STATUS_DESC_FLAGS_LEN, desc->flags); desc->flags &= ~HAL_CE_DST_STATUS_DESC_FLAGS_LEN; return len; @@ -823,13 +825,23 @@ u32 *ath11k_hal_srng_src_peek(struct ath11k_base *ab, struct hal_srng *srng) void ath11k_hal_srng_access_begin(struct ath11k_base *ab, struct hal_srng *srng) { + u32 hp; + lockdep_assert_held(&srng->lock); if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.cached_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; } else { - srng->u.dst_ring.cached_hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + + if (hp != srng->u.dst_ring.cached_hp) { + srng->u.dst_ring.cached_hp = hp; + /* Make sure descriptor is read after the head + * pointer. + */ + dma_rmb(); + } /* Try to prefetch the next descriptor in the ring */ if (srng->flags & HAL_SRNG_FLAGS_CACHED) @@ -844,7 +856,6 @@ void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng) { lockdep_assert_held(&srng->lock); - /* TODO: See if we need a write memory barrier here */ if (srng->flags & HAL_SRNG_FLAGS_LMAC_RING) { /* For LMAC rings, ring pointer updates are done through FW and * hence written to a shared memory location that is read by FW @@ -852,21 +863,37 @@ void ath11k_hal_srng_access_end(struct ath11k_base *ab, struct hal_srng *srng) if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.last_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; - *srng->u.src_ring.hp_addr = srng->u.src_ring.hp; + /* Make sure descriptor is written before updating the + * head pointer. + */ + dma_wmb(); + WRITE_ONCE(*srng->u.src_ring.hp_addr, srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; - *srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp; + /* Make sure descriptor is read before updating the + * tail pointer. + */ + dma_mb(); + WRITE_ONCE(*srng->u.dst_ring.tp_addr, srng->u.dst_ring.tp); } } else { if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.last_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; + /* Assume implementation use an MMIO write accessor + * which has the required wmb() so that the descriptor + * is written before the updating the head pointer. + */ ath11k_hif_write32(ab, (unsigned long)srng->u.src_ring.hp_addr - (unsigned long)ab->mem, srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; + /* Make sure descriptor is read before updating the + * tail pointer. + */ + mb(); ath11k_hif_write32(ab, (unsigned long)srng->u.dst_ring.tp_addr - (unsigned long)ab->mem, @@ -1346,6 +1373,10 @@ EXPORT_SYMBOL(ath11k_hal_srng_init); void ath11k_hal_srng_deinit(struct ath11k_base *ab) { struct ath11k_hal *hal = &ab->hal; + int i; + + for (i = 0; i < HAL_SRNG_RING_ID_MAX; i++) + ab->hal.srng_list[i].initialized = 0; ath11k_hal_unregister_srng_key(ab); ath11k_hal_free_cont_rdp(ab); diff --git a/drivers/net/wireless/ath/ath11k/htc.c b/drivers/net/wireless/ath/ath11k/htc.c index 23054ab29a5e..4571d01cc33d 100644 --- a/drivers/net/wireless/ath/ath11k/htc.c +++ b/drivers/net/wireless/ath/ath11k/htc.c @@ -497,7 +497,7 @@ static u8 ath11k_htc_get_credit_allocation(struct ath11k_htc *htc, static int ath11k_htc_setup_target_buffer_assignments(struct ath11k_htc *htc) { struct ath11k_htc_svc_tx_credits *serv_entry; - u32 svc_id[] = { + static const u32 svc_id[] = { ATH11K_HTC_SVC_ID_WMI_CONTROL, ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC1, ATH11K_HTC_SVC_ID_WMI_CONTROL_MAC2, diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 13301ca317a5..1fadf5faafb8 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -1037,7 +1037,7 @@ static int ath11k_mac_monitor_vdev_create(struct ath11k *ar) struct ath11k_pdev *pdev = ar->pdev; struct vdev_create_params param = {}; int bit, ret; - u8 tmp_addr[6] = {0}; + u8 tmp_addr[6] = {}; u16 nss; lockdep_assert_held(&ar->conf_mutex); @@ -1283,7 +1283,7 @@ static int ath11k_mac_config_ps(struct ath11k *ar) return ret; } -static int ath11k_mac_op_config(struct ieee80211_hw *hw, u32 changed) +static int ath11k_mac_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ath11k *ar = hw->priv; struct ieee80211_conf *conf = &hw->conf; @@ -3026,7 +3026,7 @@ static bool ath11k_mac_vif_recalc_sta_he_txbf(struct ath11k *ar, struct ieee80211_sta_he_cap *he_cap) { struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ieee80211_he_cap_elem he_cap_elem = {0}; + struct ieee80211_he_cap_elem he_cap_elem = {}; struct ieee80211_sta_he_cap *cap_band = NULL; struct cfg80211_chan_def def; u32 param = WMI_VDEV_PARAM_SET_HEMU_MODE; @@ -3763,7 +3763,7 @@ static void ath11k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ath11k_recalculate_mgmt_rate(ar, vif, &def); if (changed & BSS_CHANGED_TWT) { - struct wmi_twt_enable_params twt_params = {0}; + struct wmi_twt_enable_params twt_params = {}; if (info->twt_requester || info->twt_responder) { ath11k_wmi_fill_default_twt_params(&twt_params); @@ -5323,7 +5323,7 @@ static struct ieee80211_sta_ht_cap ath11k_create_ht_cap(struct ath11k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask) { int i; - struct ieee80211_sta_ht_cap ht_cap = {0}; + struct ieee80211_sta_ht_cap ht_cap = {}; u32 ar_vht_cap = ar->pdev->cap.vht_cap; if (!(ar_ht_cap & WMI_HT_CAP_ENABLED)) @@ -5490,7 +5490,7 @@ static struct ieee80211_sta_vht_cap ath11k_create_vht_cap(struct ath11k *ar, u32 rate_cap_tx_chainmask, u32 rate_cap_rx_chainmask) { - struct ieee80211_sta_vht_cap vht_cap = {0}; + struct ieee80211_sta_vht_cap vht_cap = {}; u16 txmcs_map, rxmcs_map; int i; @@ -6159,7 +6159,7 @@ void ath11k_mac_drain_tx(struct ath11k *ar) static int ath11k_mac_config_mon_status_default(struct ath11k *ar, bool enable) { - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; struct ath11k_base *ab = ar->ab; int i, ret = 0; u32 ring_id; @@ -6678,7 +6678,7 @@ static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw, struct ath11k *ar = hw->priv; struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct vdev_create_params vdev_param = {0}; + struct vdev_create_params vdev_param = {}; struct peer_create_params peer_param; u32 param_id, param_value; u16 nss; @@ -7044,7 +7044,8 @@ static void ath11k_mac_op_configure_filter(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); } -static int ath11k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +static int ath11k_mac_op_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct ath11k *ar = hw->priv; @@ -7058,7 +7059,8 @@ static int ath11k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 * return 0; } -static int ath11k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +static int ath11k_mac_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct ath11k *ar = hw->priv; int ret; @@ -8182,7 +8184,8 @@ ath11k_set_vdev_param_to_all_vifs(struct ath11k *ar, int param, u32 value) /* mac80211 stores device specific RTS/Fragmentation threshold value, * this is set interface specific to firmware from ath11k driver */ -static int ath11k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int ath11k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { struct ath11k *ar = hw->priv; int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; @@ -8190,7 +8193,8 @@ static int ath11k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ath11k_set_vdev_param_to_all_vifs(ar, param_id, value); } -static int ath11k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +static int ath11k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { /* Even though there's a WMI vdev param for fragmentation threshold no * known firmware actually implements it. Moreover it is not possible to @@ -8740,9 +8744,9 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif->vdev_id, ret); return ret; } - ieee80211_iterate_stations_atomic(ar->hw, - ath11k_mac_disable_peer_fixed_rate, - arvif); + ieee80211_iterate_stations_mtx(ar->hw, + ath11k_mac_disable_peer_fixed_rate, + arvif); } else if (ath11k_mac_bitrate_mask_get_single_nss(ar, arvif, band, mask, &single_nss)) { rate = WMI_FIXED_RATE_NONE; @@ -8809,9 +8813,9 @@ ath11k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, } mutex_lock(&ar->conf_mutex); - ieee80211_iterate_stations_atomic(ar->hw, - ath11k_mac_disable_peer_fixed_rate, - arvif); + ieee80211_iterate_stations_mtx(ar->hw, + ath11k_mac_disable_peer_fixed_rate, + arvif); arvif->bitrate_mask = *mask; ieee80211_iterate_stations_atomic(ar->hw, @@ -10417,7 +10421,7 @@ int ath11k_mac_register(struct ath11k_base *ab) struct ath11k_pdev *pdev; int i; int ret; - u8 mac_addr[ETH_ALEN] = {0}; + u8 mac_addr[ETH_ALEN] = {}; if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)) return 0; diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c index 78444f8ea153..d8655badd96d 100644 --- a/drivers/net/wireless/ath/ath11k/pci.c +++ b/drivers/net/wireless/ath/ath11k/pci.c @@ -37,7 +37,7 @@ static const struct pci_device_id ath11k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCA6390_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN6855_DEVICE_ID) }, { PCI_VDEVICE(QCOM, QCN9074_DEVICE_ID) }, - {0} + {} }; MODULE_DEVICE_TABLE(pci, ath11k_pci_id_table); @@ -692,7 +692,7 @@ static void ath11k_pci_coredump_download(struct ath11k_base *ab) struct ath11k_tlv_dump_data *dump_tlv; size_t hdr_len = sizeof(*file_data); void *buf; - u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = { 0 }; + u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = {}; ath11k_mhi_coredump(mhi_ctrl, false); diff --git a/drivers/net/wireless/ath/ath11k/pcic.c b/drivers/net/wireless/ath/ath11k/pcic.c index 3fe77310c71f..fc6e7da05c60 100644 --- a/drivers/net/wireless/ath/ath11k/pcic.c +++ b/drivers/net/wireless/ath/ath11k/pcic.c @@ -2,8 +2,10 @@ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include "core.h" #include "pcic.h" #include "debug.h" diff --git a/drivers/net/wireless/ath/ath11k/qmi.c b/drivers/net/wireless/ath/ath11k/qmi.c index 2782f4723e41..378ac96b861b 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2,9 +2,11 @@ /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/elf.h> +#include <linux/export.h> #include "qmi.h" #include "core.h" diff --git a/drivers/net/wireless/ath/ath11k/spectral.c b/drivers/net/wireless/ath/ath11k/spectral.c index 79e091134515..b6b0516819a6 100644 --- a/drivers/net/wireless/ath/ath11k/spectral.c +++ b/drivers/net/wireless/ath/ath11k/spectral.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/relay.h> @@ -205,7 +206,7 @@ static int ath11k_spectral_scan_trigger(struct ath11k *ar) static int ath11k_spectral_scan_config(struct ath11k *ar, enum ath11k_spectral_mode mode) { - struct ath11k_wmi_vdev_spectral_conf_param param = { 0 }; + struct ath11k_wmi_vdev_spectral_conf_param param = {}; struct ath11k_vif *arvif; int ret, count; diff --git a/drivers/net/wireless/ath/ath11k/trace.c b/drivers/net/wireless/ath/ath11k/trace.c index 6620650d7845..44ff8e9eff5d 100644 --- a/drivers/net/wireless/ath/ath11k/trace.c +++ b/drivers/net/wireless/ath/ath11k/trace.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019 The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include <linux/module.h> #define CREATE_TRACE_POINTS diff --git a/drivers/net/wireless/ath/ath11k/wmi.c b/drivers/net/wireless/ath/ath11k/wmi.c index 56af2e9634f4..0491e3fd6b5e 100644 --- a/drivers/net/wireless/ath/ath11k/wmi.c +++ b/drivers/net/wireless/ath/ath11k/wmi.c @@ -7542,7 +7542,7 @@ static void ath11k_vdev_stopped_event(struct ath11k_base *ab, struct sk_buff *sk static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct mgmt_rx_event_params rx_ev = {0}; + struct mgmt_rx_event_params rx_ev = {}; struct ath11k *ar; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr; @@ -7657,7 +7657,7 @@ exit: static void ath11k_mgmt_tx_compl_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct wmi_mgmt_tx_compl_event tx_compl_param = {0}; + struct wmi_mgmt_tx_compl_event tx_compl_param = {}; struct ath11k *ar; if (ath11k_pull_mgmt_tx_compl_param_tlv(ab, skb, &tx_compl_param) != 0) { @@ -7712,7 +7712,7 @@ static struct ath11k *ath11k_get_ar_on_scan_state(struct ath11k_base *ab, static void ath11k_scan_event(struct ath11k_base *ab, struct sk_buff *skb) { struct ath11k *ar; - struct wmi_scan_event scan_ev = {0}; + struct wmi_scan_event scan_ev = {}; if (ath11k_pull_scan_ev(ab, skb, &scan_ev) != 0) { ath11k_warn(ab, "failed to extract scan event"); @@ -7884,7 +7884,7 @@ static void ath11k_roam_event(struct ath11k_base *ab, struct sk_buff *skb) static void ath11k_chan_info_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct wmi_chan_info_event ch_info_ev = {0}; + struct wmi_chan_info_event ch_info_ev = {}; struct ath11k *ar; struct survey_info *survey; int idx; @@ -8031,7 +8031,7 @@ exit: static void ath11k_vdev_install_key_compl_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct wmi_vdev_install_key_complete_arg install_key_compl = {0}; + struct wmi_vdev_install_key_complete_arg install_key_compl = {}; struct ath11k *ar; if (ath11k_pull_vdev_install_key_compl_ev(ab, skb, &install_key_compl) != 0) { @@ -8129,7 +8129,7 @@ static void ath11k_service_available_event(struct ath11k_base *ab, struct sk_buf static void ath11k_peer_assoc_conf_event(struct ath11k_base *ab, struct sk_buff *skb) { - struct wmi_peer_assoc_conf_arg peer_assoc_conf = {0}; + struct wmi_peer_assoc_conf_arg peer_assoc_conf = {}; struct ath11k *ar; if (ath11k_pull_peer_assoc_conf_ev(ab, skb, &peer_assoc_conf) != 0) { diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c index 8d1a86e420a4..3b983f4e3268 100644 --- a/drivers/net/wireless/ath/ath12k/ahb.c +++ b/drivers/net/wireless/ath/ath12k/ahb.c @@ -1022,6 +1022,7 @@ static int ath12k_ahb_probe(struct platform_device *pdev) ab->hif.ops = hif_ops; ab->pdev = pdev; ab->hw_rev = hw_rev; + ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; platform_set_drvdata(pdev, ab); ab_ahb = ath12k_ab_to_ahb(ab); ab_ahb->ab = ab; diff --git a/drivers/net/wireless/ath/ath12k/ce.c b/drivers/net/wireless/ath/ath12k/ce.c index 3f3439262cf4..f93a419abf65 100644 --- a/drivers/net/wireless/ath/ath12k/ce.c +++ b/drivers/net/wireless/ath/ath12k/ce.c @@ -433,9 +433,6 @@ static int ath12k_ce_completed_recv_next(struct ath12k_ce_pipe *pipe, goto err; } - /* Make sure descriptor is read after the head pointer. */ - dma_rmb(); - *nbytes = ath12k_hal_ce_dst_status_get_length(desc); *skb = pipe->dest_ring->skb[sw_index]; @@ -581,7 +578,7 @@ static int ath12k_ce_init_ring(struct ath12k_base *ab, struct ath12k_ce_ring *ce_ring, int ce_id, enum hal_ring_type type) { - struct hal_srng_params params = { 0 }; + struct hal_srng_params params = {}; int ret; params.ring_base_paddr = ce_ring->base_addr_ce_space; diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 89ae80934b30..5d494c5cdc0d 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.c @@ -2,8 +2,10 @@ /* * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ +#include <linux/export.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/remoteproc.h> @@ -35,6 +37,36 @@ static struct list_head ath12k_hw_group_list = LIST_HEAD_INIT(ath12k_hw_group_li static DEFINE_MUTEX(ath12k_hw_group_mutex); +static const struct +ath12k_mem_profile_based_param ath12k_mem_profile_based_param[] = { +[ATH12K_QMI_MEMORY_MODE_DEFAULT] = { + .num_vdevs = 17, + .max_client_single = 512, + .max_client_dbs = 128, + .max_client_dbs_sbs = 128, + .dp_params = { + .tx_comp_ring_size = 32768, + .rxdma_monitor_buf_ring_size = 4096, + .rxdma_monitor_dst_ring_size = 8092, + .num_pool_tx_desc = 32768, + .rx_desc_count = 12288, + }, + }, +[ATH12K_QMI_MEMORY_MODE_LOW_512_M] = { + .num_vdevs = 9, + .max_client_single = 128, + .max_client_dbs = 64, + .max_client_dbs_sbs = 64, + .dp_params = { + .tx_comp_ring_size = 16384, + .rxdma_monitor_buf_ring_size = 256, + .rxdma_monitor_dst_ring_size = 512, + .num_pool_tx_desc = 16384, + .rx_desc_count = 6144, + }, + }, +}; + static int ath12k_core_rfkill_config(struct ath12k_base *ab) { struct ath12k *ar; @@ -186,7 +218,7 @@ static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, bool bus_type_mode, bool with_default) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ - char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; + char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = {}; if (with_variant && ab->qmi.target.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", @@ -591,28 +623,15 @@ exit: u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab) { if (ab->num_radios == 2) - return TARGET_NUM_STATIONS_DBS; - else if (ab->num_radios == 3) - return TARGET_NUM_PEERS_PDEV_DBS_SBS; - return TARGET_NUM_STATIONS_SINGLE; + return TARGET_NUM_STATIONS(ab, DBS); + if (ab->num_radios == 3) + return TARGET_NUM_STATIONS(ab, DBS_SBS); + return TARGET_NUM_STATIONS(ab, SINGLE); } u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab) { - if (ab->num_radios == 2) - return TARGET_NUM_PEERS_PDEV_DBS; - else if (ab->num_radios == 3) - return TARGET_NUM_PEERS_PDEV_DBS_SBS; - return TARGET_NUM_PEERS_PDEV_SINGLE; -} - -u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab) -{ - if (ab->num_radios == 2) - return TARGET_NUM_TIDS(DBS); - else if (ab->num_radios == 3) - return TARGET_NUM_TIDS(DBS_SBS); - return TARGET_NUM_TIDS(SINGLE); + return ath12k_core_get_max_station_per_radio(ab) + TARGET_NUM_VDEVS(ab); } struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab, @@ -1330,7 +1349,7 @@ exit: static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab) { - int ret; + int ret, total_vdev; mutex_lock(&ab->core_lock); ath12k_dp_pdev_free(ab); @@ -1341,8 +1360,8 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab) ath12k_dp_free(ab); ath12k_hal_srng_deinit(ab); - - ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; + total_vdev = ab->num_radios * TARGET_NUM_VDEVS(ab); + ab->free_vdev_map = (1LL << total_vdev) - 1; ret = ath12k_hal_srng_init(ab); if (ret) @@ -1409,6 +1428,7 @@ void ath12k_core_halt(struct ath12k *ar) ath12k_mac_peer_cleanup_all(ar); cancel_delayed_work_sync(&ar->scan.timeout); cancel_work_sync(&ar->regd_update_work); + cancel_work_sync(&ar->regd_channel_update_work); cancel_work_sync(&ab->rfkill_work); cancel_work_sync(&ab->update_11d_work); @@ -1472,6 +1492,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) complete(&ar->vdev_setup_done); complete(&ar->vdev_delete_done); complete(&ar->bss_survey_done); + complete_all(&ar->regd_update_completed); wake_up(&ar->dp.tx_empty_waitq); idr_for_each(&ar->txmgmt_idr, @@ -1511,6 +1532,9 @@ static void ath12k_update_11d(struct work_struct *work) ar = pdev->ar; memcpy(&ar->alpha2, &arg.alpha2, 2); + + reinit_completion(&ar->regd_update_completed); + ret = ath12k_wmi_send_set_current_country_cmd(ar, &arg); if (ret) ath12k_warn(ar->ab, @@ -1704,8 +1728,23 @@ static void ath12k_core_reset(struct work_struct *work) mutex_unlock(&ag->mutex); } +enum ath12k_qmi_mem_mode ath12k_core_get_memory_mode(struct ath12k_base *ab) +{ + unsigned long total_ram; + struct sysinfo si; + + si_meminfo(&si); + total_ram = si.totalram * si.mem_unit; + + if (total_ram < SZ_512M) + return ATH12K_QMI_MEMORY_MODE_LOW_512_M; + + return ATH12K_QMI_MEMORY_MODE_DEFAULT; +} + int ath12k_core_pre_init(struct ath12k_base *ab) { + const struct ath12k_mem_profile_based_param *param; int ret; ret = ath12k_hw_init(ab); @@ -1714,6 +1753,8 @@ int ath12k_core_pre_init(struct ath12k_base *ab) return ret; } + param = &ath12k_mem_profile_based_param[ab->target_mem_mode]; + ab->profile_param = param; ath12k_fw_map(ab); return 0; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 7bcd9c70309f..519f826f56c8 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -116,6 +116,7 @@ static inline u64 ath12k_le32hilo_to_u64(__le32 hi, __le32 lo) enum ath12k_skb_flags { ATH12K_SKB_HW_80211_ENCAP = BIT(0), ATH12K_SKB_CIPHER_SET = BIT(1), + ATH12K_SKB_MLO_STA = BIT(2), }; struct ath12k_skb_cb { @@ -316,6 +317,7 @@ struct ath12k_link_vif { int bank_id; u8 vdev_id_check_en; + bool beacon_prot; struct wmi_wmm_params_all_arg wmm_params; struct list_head list; @@ -345,6 +347,11 @@ struct ath12k_link_vif { bool is_sta_assoc_link; struct ath12k_reg_tpc_power_info reg_tpc_info; + + bool group_key_valid; + struct wmi_vdev_install_key_arg group_key; + bool pairwise_key_done; + u16 num_stations; }; struct ath12k_vif { @@ -380,9 +387,7 @@ struct ath12k_vif { struct ath12k_link_vif __rcu *link[ATH12K_NUM_MAX_LINKS]; struct ath12k_vif_cache *cache[IEEE80211_MLD_MAX_NUM_LINKS]; /* indicates bitmap of link vif created in FW */ - u16 links_map; - u8 last_scan_link; - + u32 links_map; /* Must be last - ends in a flexible-array member. * * FIXME: Driver should not copy struct ieee80211_chanctx_conf, @@ -561,6 +566,8 @@ struct ath12k_link_sta { /* for firmware use only */ u8 link_idx; + u32 tx_retry_failed; + u32 tx_retry_count; }; struct ath12k_reoq_buf { @@ -672,6 +679,15 @@ struct ath12k_per_peer_tx_stats { bool is_ampdu; }; +struct ath12k_pdev_rssi_offsets { + s32 temp_offset; + s8 min_nf_dbm; + /* Cache the sum here to avoid calculating it every time in hot path + * noise_floor = min_nf_dbm + temp_offset + */ + s32 noise_floor; +}; + #define ATH12K_FLUSH_TIMEOUT (5 * HZ) #define ATH12K_VDEV_DELETE_TIMEOUT_HZ (5 * HZ) @@ -719,7 +735,7 @@ struct ath12k { /* protects the radio specific data like debug stats, ppdu_stats_info stats, * vdev_stop_status info, scan data, ath12k_sta info, ath12k_link_vif info, - * channel context data, survey info, test mode data. + * channel context data, survey info, test mode data, regd_channel_update_queue. */ spinlock_t data_lock; @@ -778,6 +794,8 @@ struct ath12k { struct completion bss_survey_done; struct work_struct regd_update_work; + struct work_struct regd_channel_update_work; + struct list_head regd_channel_update_queue; struct wiphy_work wmi_mgmt_tx_work; struct sk_buff_head wmi_mgmt_tx_queue; @@ -811,6 +829,7 @@ struct ath12k { enum ath12k_11d_state state_11d; u8 alpha2[REG_ALPHA2_LEN]; bool regdom_set_by_user; + struct completion regd_update_completed; struct completion fw_stats_complete; struct completion fw_stats_done; @@ -822,6 +841,7 @@ struct ath12k { unsigned long last_tx_power_update; s8 max_allowed_tx_power; + struct ath12k_pdev_rssi_offsets rssi_info; }; struct ath12k_hw { @@ -879,6 +899,8 @@ struct ath12k_pdev_cap { struct ath12k_band_cap band[NUM_NL80211_BANDS]; u32 eml_cap; u32 mld_cap; + bool nss_ratio_enabled; + u8 nss_ratio_info; }; struct mlo_timestamp { @@ -990,6 +1012,22 @@ struct ath12k_wsi_info { u32 hw_link_id_base; }; +struct ath12k_dp_profile_params { + u32 tx_comp_ring_size; + u32 rxdma_monitor_buf_ring_size; + u32 rxdma_monitor_dst_ring_size; + u32 num_pool_tx_desc; + u32 rx_desc_count; +}; + +struct ath12k_mem_profile_based_param { + u32 num_vdevs; + u32 max_client_single; + u32 max_client_dbs; + u32 max_client_dbs_sbs; + struct ath12k_dp_profile_params dp_params; +}; + /* Master structure to hold the hw data which may be used in core module */ struct ath12k_base { enum ath12k_hw_rev hw_rev; @@ -1193,6 +1231,8 @@ struct ath12k_base { struct ath12k_reg_freq reg_freq_2ghz; struct ath12k_reg_freq reg_freq_5ghz; struct ath12k_reg_freq reg_freq_6ghz; + const struct ath12k_mem_profile_based_param *profile_param; + enum ath12k_qmi_mem_mode target_mem_mode; /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); @@ -1319,7 +1359,6 @@ const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, const char *filename); u32 ath12k_core_get_max_station_per_radio(struct ath12k_base *ab); u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab); -u32 ath12k_core_get_max_num_tids(struct ath12k_base *ab); void ath12k_core_hw_group_set_mlo_capable(struct ath12k_hw_group *ag); void ath12k_fw_stats_init(struct ath12k *ar); @@ -1328,6 +1367,7 @@ void ath12k_fw_stats_free(struct ath12k_fw_stats *stats); void ath12k_fw_stats_reset(struct ath12k *ar); struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab, int index); +enum ath12k_qmi_mem_mode ath12k_core_get_memory_mode(struct ath12k_base *ab); static inline const char *ath12k_scan_state_str(enum ath12k_scan_state state) { @@ -1462,4 +1502,11 @@ static inline struct ath12k_base *ath12k_ag_to_ab(struct ath12k_hw_group *ag, return ag->ab[device_id]; } +static inline s32 ath12k_pdev_get_noise_floor(struct ath12k *ar) +{ + lockdep_assert_held(&ar->data_lock); + + return ar->rssi_info.noise_floor; +} + #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/dbring.c b/drivers/net/wireless/ath/ath12k/dbring.c index 788160c84c68..6604dacea2ae 100644 --- a/drivers/net/wireless/ath/ath12k/dbring.c +++ b/drivers/net/wireless/ath/ath12k/dbring.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "core.h" @@ -117,7 +118,7 @@ int ath12k_dbring_wmi_cfg_setup(struct ath12k *ar, struct ath12k_dbring *ring, enum wmi_direct_buffer_module id) { - struct ath12k_wmi_pdev_dma_ring_cfg_arg arg = {0}; + struct ath12k_wmi_pdev_dma_ring_cfg_arg arg = {}; int ret; if (id >= WMI_DIRECT_BUF_MAX) diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c index 23da93afaa5c..16601a8c3644 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs.c +++ b/drivers/net/wireless/ath/ath12k/debugfs.c @@ -52,7 +52,7 @@ ath12k_write_simulate_fw_crash(struct file *file, struct ath12k_base *ab = file->private_data; struct ath12k_pdev *pdev; struct ath12k *ar = NULL; - char buf[32] = {0}; + char buf[32] = {}; int i, ret; ssize_t rc; @@ -816,7 +816,7 @@ static ssize_t ath12k_write_extd_rx_stats(struct file *file, size_t count, loff_t *ppos) { struct ath12k *ar = file->private_data; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 ring_id, rx_filter = 0; bool enable; int ret, i; @@ -1217,7 +1217,7 @@ void ath12k_debugfs_pdev_create(struct ath12k_base *ab) void ath12k_debugfs_soc_create(struct ath12k_base *ab) { bool dput_needed; - char soc_name[64] = { 0 }; + char soc_name[64] = {}; struct dentry *debugfs_ath12k; debugfs_ath12k = debugfs_lookup("ath12k", NULL); @@ -1470,7 +1470,7 @@ void ath12k_debugfs_register(struct ath12k *ar) struct ath12k_base *ab = ar->ab; struct ieee80211_hw *hw = ar->ah->hw; char pdev_name[5]; - char buf[100] = {0}; + char buf[100] = {}; scnprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx); diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c index aeaf970339d4..48b010a1b756 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c @@ -2024,7 +2024,7 @@ ath12k_htt_print_stats_string_tlv(const void *tag_buf, u16 tag_len, u8 i; u16 index = 0; u32 datum; - char data[ATH12K_HTT_MAX_STRING_LEN] = {0}; + char data[ATH12K_HTT_MAX_STRING_LEN] = {}; tag_len = tag_len >> 2; @@ -3081,7 +3081,7 @@ ath12k_htt_print_ul_mumimo_trig_stats(const void *tag_buf, u16 tag_len, struct debug_htt_stats_req *stats_req) { const struct ath12k_htt_rx_ul_mumimo_trig_stats_tlv *htt_stats_buf = tag_buf; - char str_buf[ATH12K_HTT_MAX_STRING_LEN] = {0}; + char str_buf[ATH12K_HTT_MAX_STRING_LEN] = {}; u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; u32 len = stats_req->buf_len; u8 *buf = stats_req->buf; @@ -3642,7 +3642,7 @@ ath12k_htt_print_dlpager_stats_tlv(const void *tag_buf, u16 tag_len, u8 *buf = stats_req->buf; u8 pg_locked; u8 pg_unlock; - char str_buf[ATH12K_HTT_MAX_STRING_LEN] = {0}; + char str_buf[ATH12K_HTT_MAX_STRING_LEN] = {}; if (tag_len < sizeof(*stat_buf)) return; @@ -4720,7 +4720,38 @@ ath12k_htt_print_tx_pdev_rate_stats_tlv(const void *tag_buf, u16 tag_len, len += print_array_to_buf(buf, len, "tx_pream", htt_stats_buf->tx_pream, ATH12K_HTT_TX_PDEV_STATS_NUM_PREAMBLE_TYPES, "\n"); len += print_array_to_buf(buf, len, "tx_dcm", htt_stats_buf->tx_dcm, - ATH12K_HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS, "\n"); + ATH12K_HTT_TX_PDEV_STATS_NUM_DCM_COUNTERS, "\n\n"); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_histogram_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_tx_histogram_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "low_latency_rate_cnt = %u\n", + le32_to_cpu(stats_buf->low_latency_rate_cnt)); + len += scnprintf(buf + len, buf_len - len, "su_burst_rate_drop_cnt = %u\n", + le32_to_cpu(stats_buf->su_burst_rate_drop_cnt)); + len += scnprintf(buf + len, buf_len - len, "su_burst_rate_drop_fail_cnt = %u\n", + le32_to_cpu(stats_buf->su_burst_rate_drop_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "rate_retry_mcs_drop_cnt = %u\n", + le32_to_cpu(stats_buf->rate_retry_mcs_drop_cnt)); + + len += scnprintf(buf + len, buf_len - len, "\nPER_HISTOGRAM_STATS\n"); + len += print_array_to_buf(buf, len, "mcs_drop_rate", stats_buf->mcs_drop_rate, + ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_DROP_COUNTERS, "\n"); + len += print_array_to_buf(buf, len, "per_histogram_count", + stats_buf->per_histogram_cnt, + ATH12K_HTT_TX_PDEV_STATS_NUM_PER_COUNTERS, "\n\n"); stats_req->buf_len = len; } @@ -5015,6 +5046,497 @@ ath12k_htt_print_rx_pdev_rate_ext_stats_tlv(const void *tag_buf, u16 tag_len, stats_req->buf_len = len; } +static void +ath12k_htt_print_pdev_tdma_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_tdma_stats_tlv *htt_stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u32 mac_id_word; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + mac_id_word = le32_to_cpu(htt_stats_buf->mac_id__word); + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_TDMA_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n", + u32_get_bits(mac_id_word, ATH12K_HTT_STATS_MAC_ID)); + len += scnprintf(buf + len, buf_len - len, "num_tdma_active_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_active_schedules)); + len += scnprintf(buf + len, buf_len - len, "num_tdma_reserved_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_reserved_schedules)); + len += scnprintf(buf + len, buf_len - len, + "num_tdma_restricted_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_restricted_schedules)); + len += scnprintf(buf + len, buf_len - len, + "num_tdma_unconfigured_schedules = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_unconfigured_schedules)); + len += scnprintf(buf + len, buf_len - len, "num_tdma_slot_switches = %u\n", + le32_to_cpu(htt_stats_buf->num_tdma_slot_switches)); + len += scnprintf(buf + len, buf_len - len, "num_tdma_edca_switches = %u\n\n", + le32_to_cpu(htt_stats_buf->num_tdma_edca_switches)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_mlo_sched_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_mlo_sched_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_MLO_SCHED_STATS:\n"); + len += scnprintf(buf + len, buf_len - len, "num_sec_link_sched = %u\n", + le32_to_cpu(stats_buf->pref_link_num_sec_link_sched)); + len += scnprintf(buf + len, buf_len - len, "num_pref_link_timeout = %u\n", + le32_to_cpu(stats_buf->pref_link_num_pref_link_timeout)); + len += scnprintf(buf + len, buf_len - len, "num_pref_link_sch_delay_ipc = %u\n", + le32_to_cpu(stats_buf->pref_link_num_pref_link_sch_delay_ipc)); + len += scnprintf(buf + len, buf_len - len, "num_pref_link_timeout_ipc = %u\n\n", + le32_to_cpu(stats_buf->pref_link_num_pref_link_timeout_ipc)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_mlo_ipc_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_pdev_mlo_ipc_stats_tlv *stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + u8 i, j; + + if (tag_len < sizeof(*stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_MLO_IPC_STATS:\n"); + for (i = 0; i < ATH12K_HTT_HWMLO_MAX_LINKS; i++) { + len += scnprintf(buf + len, buf_len - len, "src_link: %u\n", i); + for (j = 0; j < ATH12K_HTT_MLO_MAX_IPC_RINGS; j++) + len += scnprintf(buf + len, buf_len - len, + "mlo_ipc_ring_full_cnt[%u]: %u\n", j, + le32_to_cpu(stats_buf->mlo_ipc_ring_cnt[i][j])); + len += scnprintf(buf + len, buf_len - len, "\n"); + } + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_resp_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_pdev_rtt_resp_stats_tlv *sbuf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*sbuf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_RTT_RESP_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", + le32_to_cpu(sbuf->pdev_id)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftm_suc = %u\n", + le32_to_cpu(sbuf->tx_11mc_ftm_suc)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftm_suc_retry = %u\n", + le32_to_cpu(sbuf->tx_11mc_ftm_suc_retry)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftm_fail = %u\n", + le32_to_cpu(sbuf->tx_11mc_ftm_fail)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_ftmr_cnt = %u\n", + le32_to_cpu(sbuf->rx_11mc_ftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_ftmr_dup_cnt = %u\n", + le32_to_cpu(sbuf->rx_11mc_ftmr_dup_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_iftmr_cnt = %u\n", + le32_to_cpu(sbuf->rx_11mc_iftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_iftmr_dup_cnt = %u\n", + le32_to_cpu(sbuf->rx_11mc_iftmr_dup_cnt)); + len += scnprintf(buf + len, buf_len - len, + "ftmr_drop_11mc_resp_role_not_enabled_cnt = %u\n", + le32_to_cpu(sbuf->ftmr_drop_11mc_resp_role_not_enabled_cnt)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftm_successful = %u\n", + le32_to_cpu(sbuf->tx_11az_ftm_successful)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftm_failed = %u\n", + le32_to_cpu(sbuf->tx_11az_ftm_failed)); + len += scnprintf(buf + len, buf_len - len, "rx_11az_ftmr_cnt = %u\n", + le32_to_cpu(sbuf->rx_11az_ftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11az_ftmr_dup_cnt = %u\n", + le32_to_cpu(sbuf->rx_11az_ftmr_dup_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11az_iftmr_dup_cnt = %u\n", + le32_to_cpu(sbuf->rx_11az_iftmr_dup_cnt)); + len += scnprintf(buf + len, buf_len - len, + "initiator_active_responder_rejected_cnt = %u\n", + le32_to_cpu(sbuf->initiator_active_responder_rejected_cnt)); + len += scnprintf(buf + len, buf_len - len, "malformed_ftmr = %u\n", + le32_to_cpu(sbuf->malformed_ftmr)); + len += scnprintf(buf + len, buf_len - len, + "ftmr_drop_ntb_resp_role_not_enabled_cnt = %u\n", + le32_to_cpu(sbuf->ftmr_drop_ntb_resp_role_not_enabled_cnt)); + len += scnprintf(buf + len, buf_len - len, + "ftmr_drop_tb_resp_role_not_enabled_cnt = %u\n", + le32_to_cpu(sbuf->ftmr_drop_tb_resp_role_not_enabled_cnt)); + len += scnprintf(buf + len, buf_len - len, "responder_alloc_cnt = %u\n", + le32_to_cpu(sbuf->responder_alloc_cnt)); + len += scnprintf(buf + len, buf_len - len, "responder_alloc_failure = %u\n", + le32_to_cpu(sbuf->responder_alloc_failure)); + len += scnprintf(buf + len, buf_len - len, "responder_terminate_cnt = %u\n", + le32_to_cpu(sbuf->responder_terminate_cnt)); + len += scnprintf(buf + len, buf_len - len, "active_rsta_open = %u\n", + le32_to_cpu(sbuf->active_rsta_open)); + len += scnprintf(buf + len, buf_len - len, "active_rsta_mac = %u\n", + le32_to_cpu(sbuf->active_rsta_mac)); + len += scnprintf(buf + len, buf_len - len, "active_rsta_mac_phy = %u\n", + le32_to_cpu(sbuf->active_rsta_mac_phy)); + len += scnprintf(buf + len, buf_len - len, "pn_check_failure_cnt = %u\n", + le32_to_cpu(sbuf->pn_check_failure_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_assoc_ranging_peers = %u\n", + le32_to_cpu(sbuf->num_assoc_ranging_peers)); + len += scnprintf(buf + len, buf_len - len, "num_unassoc_ranging_peers = %u\n", + le32_to_cpu(sbuf->num_unassoc_ranging_peers)); + len += scnprintf(buf + len, buf_len - len, "pasn_m1_auth_recv_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m1_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m1_auth_drop_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m1_auth_drop_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m2_auth_recv_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m2_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m2_auth_tx_fail_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m2_auth_tx_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m3_auth_recv_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m3_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m3_auth_drop_cnt = %u\n", + le32_to_cpu(sbuf->pasn_m3_auth_drop_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_create_request_cnt = %u\n", + le32_to_cpu(sbuf->pasn_peer_create_request_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_created_cnt = %u\n", + le32_to_cpu(sbuf->pasn_peer_created_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_create_timeout_cnt = %u\n", + le32_to_cpu(sbuf->pasn_peer_create_timeout_cnt)); + len += scnprintf(buf + len, buf_len - len, + "sec_ranging_not_supported_mfp_not_setup = %u\n", + le32_to_cpu(sbuf->sec_ranging_not_supported_mfp_not_setup)); + len += scnprintf(buf + len, buf_len - len, + "non_sec_ranging_discarded_for_assoc_peer_with_mfpr_set = %u\n", + le32_to_cpu(sbuf->non_sec_ranging_discarded_for_assoc_peer)); + len += scnprintf(buf + len, buf_len - len, + "open_ranging_discarded_with_URNM_MFPR_set_for_pasn_peer = %u\n", + le32_to_cpu(sbuf->open_ranging_discarded_set_for_pasn_peer)); + len += scnprintf(buf + len, buf_len - len, + "unassoc_non_pasn_ranging_not_supported_with_URNM_MFPR = %u\n", + le32_to_cpu(sbuf->unassoc_non_pasn_ranging_not_supported)); + len += scnprintf(buf + len, buf_len - len, "invalid_ftm_request_params = %u\n", + le32_to_cpu(sbuf->invalid_ftm_request_params)); + len += scnprintf(buf + len, buf_len - len, + "requested_bw_format_not_supported = %u\n", + le32_to_cpu(sbuf->requested_bw_format_not_supported)); + len += scnprintf(buf + len, buf_len - len, + "ntb_unsec_unassoc_mode_ranging_peer_alloc_failed = %u\n", + le32_to_cpu(sbuf->ntb_unsec_unassoc_ranging_peer_alloc_failed)); + len += scnprintf(buf + len, buf_len - len, + "tb_unassoc_unsec_mode_pasn_peer_creation_failed = %u\n", + le32_to_cpu(sbuf->tb_unassoc_unsec_pasn_peer_creation_failed)); + len += scnprintf(buf + len, buf_len - len, + "num_ranging_sequences_processed = %u\n", + le32_to_cpu(sbuf->num_ranging_sequences_processed)); + len += scnprintf(buf + len, buf_len - len, "ndp_rx_cnt = %u\n", + le32_to_cpu(sbuf->ndp_rx_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_req_bw_20_MHz = %u\n", + le32_to_cpu(sbuf->num_req_bw_20_mhz)); + len += scnprintf(buf + len, buf_len - len, "num_req_bw_40_MHz = %u\n", + le32_to_cpu(sbuf->num_req_bw_40_mhz)); + len += scnprintf(buf + len, buf_len - len, "num_req_bw_80_MHz = %u\n", + le32_to_cpu(sbuf->num_req_bw_80_mhz)); + len += scnprintf(buf + len, buf_len - len, "num_req_bw_160_MHz = %u\n", + le32_to_cpu(sbuf->num_req_bw_160_mhz)); + len += scnprintf(buf + len, buf_len - len, "ntb_tx_ndp = %u\n", + le32_to_cpu(sbuf->ntb_tx_ndp)); + len += scnprintf(buf + len, buf_len - len, "num_ntb_ranging_NDPAs_recv = %u\n", + le32_to_cpu(sbuf->num_ntb_ranging_ndpas_recv)); + len += scnprintf(buf + len, buf_len - len, "recv_lmr = %u\n", + le32_to_cpu(sbuf->recv_lmr)); + len += scnprintf(buf + len, buf_len - len, "invalid_ftmr_cnt = %u\n", + le32_to_cpu(sbuf->invalid_ftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "max_time_bw_meas_exp_cnt = %u\n\n", + le32_to_cpu(sbuf->max_time_bw_meas_exp_cnt)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_init_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_pdev_rtt_init_stats_tlv *htt_stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf, i; + __le32 sch_fail; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_PDEV_RTT_INIT_STATS_TLV:\n"); + len += scnprintf(buf + len, buf_len - len, "pdev_id = %u\n", + le32_to_cpu(htt_stats_buf->pdev_id)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftmr_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tx_11mc_ftmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftmr_fail = %u\n", + le32_to_cpu(htt_stats_buf->tx_11mc_ftmr_fail)); + len += scnprintf(buf + len, buf_len - len, "tx_11mc_ftmr_suc_retry = %u\n", + le32_to_cpu(htt_stats_buf->tx_11mc_ftmr_suc_retry)); + len += scnprintf(buf + len, buf_len - len, "rx_11mc_ftm_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rx_11mc_ftm_cnt)); + len += scnprintf(buf + len, buf_len - len, "rx_11az_ftm_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rx_11az_ftm_cnt)); + len += scnprintf(buf + len, buf_len - len, "initiator_terminate_cnt = %u\n", + le32_to_cpu(htt_stats_buf->initiator_terminate_cnt)); + len += scnprintf(buf + len, buf_len - len, "tx_meas_req_count = %u\n", + le32_to_cpu(htt_stats_buf->tx_meas_req_count)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftmr_start = %u\n", + le32_to_cpu(htt_stats_buf->tx_11az_ftmr_start)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftmr_stop = %u\n", + le32_to_cpu(htt_stats_buf->tx_11az_ftmr_stop)); + len += scnprintf(buf + len, buf_len - len, "tx_11az_ftmr_fail = %u\n", + le32_to_cpu(htt_stats_buf->tx_11az_ftmr_fail)); + len += scnprintf(buf + len, buf_len - len, + "ftmr_tx_failed_null_11az_peer = %u\n", + le32_to_cpu(htt_stats_buf->ftmr_tx_failed_null_11az_peer)); + len += scnprintf(buf + len, buf_len - len, "ftmr_retry_timeout = %u\n", + le32_to_cpu(htt_stats_buf->ftmr_retry_timeout)); + len += scnprintf(buf + len, buf_len - len, "ftm_parse_failure = %u\n", + le32_to_cpu(htt_stats_buf->ftm_parse_failure)); + len += scnprintf(buf + len, buf_len - len, "incompatible_ftm_params = %u\n", + le32_to_cpu(htt_stats_buf->incompatible_ftm_params)); + len += scnprintf(buf + len, buf_len - len, + "ranging_negotiation_successful_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ranging_negotiation_successful_cnt)); + len += scnprintf(buf + len, buf_len - len, "active_ista = %u\n", + le32_to_cpu(htt_stats_buf->active_ista)); + len += scnprintf(buf + len, buf_len - len, "init_role_not_enabled = %u\n", + le32_to_cpu(htt_stats_buf->init_role_not_enabled)); + len += scnprintf(buf + len, buf_len - len, "invalid_preamble = %u\n", + le32_to_cpu(htt_stats_buf->invalid_preamble)); + len += scnprintf(buf + len, buf_len - len, "invalid_chan_bw_format = %u\n", + le32_to_cpu(htt_stats_buf->invalid_chan_bw_format)); + len += scnprintf(buf + len, buf_len - len, "mgmt_buff_alloc_fail_cnt = %u\n", + le32_to_cpu(htt_stats_buf->mgmt_buff_alloc_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "sec_ranging_req_in_open_mode = %u\n", + le32_to_cpu(htt_stats_buf->sec_ranging_req_in_open_mode)); + len += scnprintf(buf + len, buf_len - len, "max_time_bw_meas_exp_cnt = %u\n", + le32_to_cpu(htt_stats_buf->max_time_bw_meas_exp_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_tb_ranging_requests = %u\n", + le32_to_cpu(htt_stats_buf->num_tb_ranging_requests)); + len += scnprintf(buf + len, buf_len - len, "tb_meas_duration_expiry_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_meas_duration_expiry_cnt)); + len += scnprintf(buf + len, buf_len - len, "ntbr_triggered_successfully = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_triggered_successfully)); + len += scnprintf(buf + len, buf_len - len, "ntbr_trigger_failed = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_trigger_failed)); + len += scnprintf(buf + len, buf_len - len, "invalid_or_no_vreg_idx = %u\n", + le32_to_cpu(htt_stats_buf->invalid_or_no_vreg_idx)); + len += scnprintf(buf + len, buf_len - len, "set_vreg_params_failed = %u\n", + le32_to_cpu(htt_stats_buf->set_vreg_params_failed)); + len += scnprintf(buf + len, buf_len - len, "sac_mismatch = %u\n", + le32_to_cpu(htt_stats_buf->sac_mismatch)); + len += scnprintf(buf + len, buf_len - len, "pasn_m1_auth_recv_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m1_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m1_auth_tx_fail_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m1_auth_tx_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m2_auth_recv_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m2_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m2_auth_drop_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m2_auth_drop_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m3_auth_recv_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m3_auth_recv_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_m3_auth_tx_fail_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_m3_auth_tx_fail_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_create_request_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_peer_create_request_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_created_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_peer_created_cnt)); + len += scnprintf(buf + len, buf_len - len, "pasn_peer_create_timeout_cnt = %u\n", + le32_to_cpu(htt_stats_buf->pasn_peer_create_timeout_cnt)); + len += scnprintf(buf + len, buf_len - len, "ntbr_ndpa_failed = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_ndpa_failed)); + len += scnprintf(buf + len, buf_len - len, "ntbr_sequence_successful = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_sequence_successful)); + len += scnprintf(buf + len, buf_len - len, "ntbr_ndp_failed = %u\n", + le32_to_cpu(htt_stats_buf->ntbr_ndp_failed)); + len += scnprintf(buf + len, buf_len - len, "num_tb_ranging_NDPAs_recv = %u\n", + le32_to_cpu(htt_stats_buf->num_tb_ranging_ndpas_recv)); + len += scnprintf(buf + len, buf_len - len, "ndp_rx_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ndp_rx_cnt)); + len += scnprintf(buf + len, buf_len - len, "num_trigger_frames_received = %u\n", + le32_to_cpu(htt_stats_buf->num_trigger_frames_received)); + for (i = 0; i < (ATH12K_HTT_SCH_CMD_STATUS_CNT - 1); i++) + len += scnprintf(buf + len, buf_len - len, + "num_sch_cmd_status_%d = %u\n", i, + le32_to_cpu(htt_stats_buf->sch_cmd_status_cnts[i])); + sch_fail = htt_stats_buf->sch_cmd_status_cnts[ATH12K_HTT_SCH_CMD_STATUS_CNT - 1]; + len += scnprintf(buf + len, buf_len - len, + "num_sch_cmd_status_other_failure = %u\n", + le32_to_cpu(sch_fail)); + len += scnprintf(buf + len, buf_len - len, "lmr_timeout = %u\n", + le32_to_cpu(htt_stats_buf->lmr_timeout)); + len += scnprintf(buf + len, buf_len - len, "lmr_recv = %u\n\n", + le32_to_cpu(htt_stats_buf->lmr_recv)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_hw_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_pdev_rtt_hw_stats_tlv *htt_stats_buf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf; + + if (tag_len < sizeof(*htt_stats_buf)) + return; + + len += scnprintf(buf + len, buf_len - len, "HTT_STATS_PDEV_RTT_HW_STATS_TAG:\n"); + len += scnprintf(buf + len, buf_len - len, "ista_ranging_ndpa_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ista_ranging_ndpa_cnt)); + len += scnprintf(buf + len, buf_len - len, "ista_ranging_ndp_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ista_ranging_ndp_cnt)); + len += scnprintf(buf + len, buf_len - len, "ista_ranging_i2r_lmr_cnt = %u\n", + le32_to_cpu(htt_stats_buf->ista_ranging_i2r_lmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "rtsa_ranging_resp_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rtsa_ranging_resp_cnt)); + len += scnprintf(buf + len, buf_len - len, "rtsa_ranging_ndp_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rtsa_ranging_ndp_cnt)); + len += scnprintf(buf + len, buf_len - len, "rsta_ranging_lmr_cnt = %u\n", + le32_to_cpu(htt_stats_buf->rsta_ranging_lmr_cnt)); + len += scnprintf(buf + len, buf_len - len, "tb_ranging_cts2s_rcvd_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_cts2s_rcvd_cnt)); + len += scnprintf(buf + len, buf_len - len, "tb_ranging_ndp_rcvd_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_ndp_rcvd_cnt)); + len += scnprintf(buf + len, buf_len - len, "tb_ranging_lmr_rcvd_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_lmr_rcvd_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tb_ranging_tf_poll_resp_sent_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_tf_poll_resp_sent_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tb_ranging_tf_sound_resp_sent_cnt = %u\n", + le32_to_cpu(htt_stats_buf->tb_ranging_tf_sound_resp_sent_cnt)); + len += scnprintf(buf + len, buf_len - len, + "tb_ranging_tf_report_resp_sent_cnt = %u\n\n", + le32_to_cpu(htt_stats_buf->tb_ranging_tf_report_resp_sent_cnt)); + + stats_req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_tbr_selfgen_queued_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *req) +{ + const struct ath12k_htt_stats_pdev_rtt_tbr_tlv *sbuf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = req->buf_len; + u8 *buf = req->buf; + + if (tag_len < sizeof(*sbuf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG:\n"); + len += scnprintf(buf + len, buf_len - len, "SU poll = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TF_POLL])); + len += scnprintf(buf + len, buf_len - len, "SU sound = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TF_SOUND])); + len += scnprintf(buf + len, buf_len - len, "SU NDPA = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TBR_NDPA])); + len += scnprintf(buf + len, buf_len - len, "SU NDP = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TBR_NDP])); + len += scnprintf(buf + len, buf_len - len, "SU LMR = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TBR_LMR])); + len += scnprintf(buf + len, buf_len - len, "SU TF_REPORT = %u\n", + le32_to_cpu(sbuf->su_ftype[ATH12K_HTT_FTYPE_TF_RPRT])); + len += scnprintf(buf + len, buf_len - len, "MU poll = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TF_POLL])); + len += scnprintf(buf + len, buf_len - len, "MU sound = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TF_SOUND])); + len += scnprintf(buf + len, buf_len - len, "MU NDPA = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TBR_NDPA])); + len += scnprintf(buf + len, buf_len - len, "MU NDP = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TBR_NDP])); + len += scnprintf(buf + len, buf_len - len, "MU LMR = %u\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TBR_LMR])); + len += scnprintf(buf + len, buf_len - len, "MU TF_REPORT = %u\n\n", + le32_to_cpu(sbuf->mu_ftype[ATH12K_HTT_FTYPE_TF_RPRT])); + + req->buf_len = len; +} + +static void +ath12k_htt_print_pdev_rtt_tbr_cmd_res_stats_tlv(const void *tag_buf, u16 tag_len, + struct debug_htt_stats_req *stats_req) +{ + const struct ath12k_htt_stats_pdev_rtt_tbr_cmd_result_stats_tlv *sbuf = tag_buf; + u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE; + u32 len = stats_req->buf_len; + u8 *buf = stats_req->buf, i; + + if (tag_len < sizeof(*sbuf)) + return; + + len += scnprintf(buf + len, buf_len - len, + "HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG:\n"); + for (i = 0; i < le32_to_cpu(sbuf->tbr_num_sch_cmd_result_buckets); i++) { + len += scnprintf(buf + len, buf_len - len, "num_sch_cmd_status_%u:\n", i); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TF_POLL = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TF_POLL][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TF_SOUND = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TF_SOUND][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TBR_NDPA = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TBR_NDPA][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TBR_NDP = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TBR_NDP][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TBR_LMR = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TBR_LMR][i])); + len += scnprintf(buf + len, buf_len - len, + "SU frame_SGEN_TF_REPORT = %u\n", + le32_to_cpu(sbuf->su_res[ATH12K_HTT_FTYPE_TF_RPRT][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TF_POLL = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TF_POLL][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TF_SOUND = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TF_SOUND][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TBR_NDPA = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TBR_NDPA][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TBR_NDP = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TBR_NDP][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TBR_LMR = %u\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TBR_LMR][i])); + len += scnprintf(buf + len, buf_len - len, + "MU frame_SGEN_TF_REPORT = %u\n\n", + le32_to_cpu(sbuf->mu_res[ATH12K_HTT_FTYPE_TF_RPRT][i])); + } + + stats_req->buf_len = len; +} + static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *tag_buf, void *user_data) @@ -5277,12 +5799,40 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab, case HTT_STATS_TX_PDEV_RATE_STATS_TAG: ath12k_htt_print_tx_pdev_rate_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_TX_PDEV_HISTOGRAM_STATS_TAG: + ath12k_htt_print_histogram_stats_tlv(tag_buf, len, stats_req); + break; case HTT_STATS_RX_PDEV_RATE_STATS_TAG: ath12k_htt_print_rx_pdev_rate_stats_tlv(tag_buf, len, stats_req); break; case HTT_STATS_RX_PDEV_RATE_EXT_STATS_TAG: ath12k_htt_print_rx_pdev_rate_ext_stats_tlv(tag_buf, len, stats_req); break; + case HTT_STATS_PDEV_TDMA_TAG: + ath12k_htt_print_pdev_tdma_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_MLO_SCHED_STATS_TAG: + ath12k_htt_print_mlo_sched_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_MLO_IPC_STATS_TAG: + ath12k_htt_print_mlo_ipc_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_RTT_RESP_STATS_TAG: + ath12k_htt_print_pdev_rtt_resp_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_RTT_INIT_STATS_TAG: + ath12k_htt_print_pdev_rtt_init_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_RTT_HW_STATS_TAG: + ath12k_htt_print_pdev_rtt_hw_stats_tlv(tag_buf, len, stats_req); + break; + case HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG: + ath12k_htt_print_pdev_rtt_tbr_selfgen_queued_stats_tlv(tag_buf, len, + stats_req); + break; + case HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG: + ath12k_htt_print_pdev_rtt_tbr_cmd_res_stats_tlv(tag_buf, len, stats_req); + break; default: break; } @@ -5373,7 +5923,7 @@ static ssize_t ath12k_write_htt_stats_type(struct file *file, { struct ath12k *ar = file->private_data; enum ath12k_dbg_htt_ext_stats_type type; - unsigned int cfg_param[4] = {0}; + unsigned int cfg_param[4] = {}; const int size = 32; int num_args; @@ -5423,7 +5973,7 @@ static int ath12k_debugfs_htt_stats_req(struct ath12k *ar) enum ath12k_dbg_htt_ext_stats_type type = stats_req->type; u64 cookie; int ret, pdev_id; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -5562,7 +6112,7 @@ static ssize_t ath12k_write_htt_stats_reset(struct file *file, { struct ath12k *ar = file->private_data; enum ath12k_dbg_htt_ext_stats_type type; - struct htt_ext_stats_cfg_params cfg_params = { 0 }; + struct htt_ext_stats_cfg_params cfg_params = {}; u8 param_pos; int ret; diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h index c2a02cf8a38b..9bd3a632b002 100644 --- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h +++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h @@ -155,6 +155,11 @@ enum ath12k_dbg_htt_ext_stats_type { ATH12K_DBG_HTT_EXT_STATS_PDEV_SCHED_ALGO = 49, ATH12K_DBG_HTT_EXT_STATS_MANDATORY_MUOFDMA = 51, ATH12K_DGB_HTT_EXT_STATS_PDEV_MBSSID_CTRL_FRAME = 54, + ATH12K_DBG_HTT_PDEV_TDMA_STATS = 57, + ATH12K_DBG_HTT_MLO_SCHED_STATS = 63, + ATH12K_DBG_HTT_PDEV_MLO_IPC_STATS = 64, + ATH12K_DBG_HTT_EXT_PDEV_RTT_RESP_STATS = 65, + ATH12K_DBG_HTT_EXT_PDEV_RTT_INITIATOR_STATS = 66, /* keep this last */ ATH12K_DBG_HTT_NUM_EXT_STATS, @@ -237,6 +242,7 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_TX_SELFGEN_BE_ERR_STATS_TAG = 137, HTT_STATS_TX_SELFGEN_BE_STATS_TAG = 138, HTT_STATS_TX_SELFGEN_BE_SCHED_STATUS_STATS_TAG = 139, + HTT_STATS_TX_PDEV_HISTOGRAM_STATS_TAG = 144, HTT_STATS_TXBF_OFDMA_AX_NDPA_STATS_TAG = 147, HTT_STATS_TXBF_OFDMA_AX_NDP_STATS_TAG = 148, HTT_STATS_TXBF_OFDMA_AX_BRP_STATS_TAG = 149, @@ -247,6 +253,14 @@ enum ath12k_dbg_htt_tlv_tag { HTT_STATS_PDEV_SCHED_ALGO_OFDMA_STATS_TAG = 165, HTT_STATS_TXBF_OFDMA_AX_STEER_MPDU_STATS_TAG = 172, HTT_STATS_PDEV_MBSSID_CTRL_FRAME_STATS_TAG = 176, + HTT_STATS_PDEV_TDMA_TAG = 187, + HTT_STATS_MLO_SCHED_STATS_TAG = 190, + HTT_STATS_PDEV_MLO_IPC_STATS_TAG = 191, + HTT_STATS_PDEV_RTT_RESP_STATS_TAG = 194, + HTT_STATS_PDEV_RTT_INIT_STATS_TAG = 195, + HTT_STATS_PDEV_RTT_HW_STATS_TAG = 196, + HTT_STATS_PDEV_RTT_TBR_SELFGEN_QUEUED_STATS_TAG = 197, + HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG = 198, HTT_STATS_MAX_TAG, }; @@ -418,6 +432,12 @@ struct ath12k_htt_tx_pdev_mu_ppdu_dist_stats_tlv { #define ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS 2 #define ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS 2 #define ATH12K_HTT_TX_PDEV_STATS_NUM_11AX_TRIGGER_TYPES 6 +#define ATH12K_HTT_TX_PDEV_STATS_NUM_PER_COUNTERS 101 + +#define ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_DROP_COUNTERS \ + (ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_COUNTERS + \ + ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS + \ + ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS) struct ath12k_htt_tx_pdev_rate_stats_tlv { __le32 mac_id_word; @@ -470,7 +490,16 @@ struct ath12k_htt_tx_pdev_rate_stats_tlv { [ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS]; __le32 tx_mcs_ext_2[ATH12K_HTT_TX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS]; __le32 tx_bw_320mhz; -}; +} __packed; + +struct ath12k_htt_tx_histogram_stats_tlv { + __le32 rate_retry_mcs_drop_cnt; + __le32 mcs_drop_rate[ATH12K_HTT_TX_PDEV_STATS_NUM_MCS_DROP_COUNTERS]; + __le32 per_histogram_cnt[ATH12K_HTT_TX_PDEV_STATS_NUM_PER_COUNTERS]; + __le32 low_latency_rate_cnt; + __le32 su_burst_rate_drop_cnt; + __le32 su_burst_rate_drop_fail_cnt; +} __packed; #define ATH12K_HTT_RX_PDEV_STATS_NUM_LEGACY_CCK_STATS 4 #define ATH12K_HTT_RX_PDEV_STATS_NUM_LEGACY_OFDM_STATS 8 @@ -550,7 +579,7 @@ struct ath12k_htt_rx_pdev_rate_stats_tlv { __le32 rx_ulofdma_non_data_nusers[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER]; __le32 rx_ulofdma_data_nusers[ATH12K_HTT_RX_PDEV_MAX_OFDMA_NUM_USER]; __le32 rx_mcs_ext[ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA_MCS_COUNTERS]; -}; +} __packed; #define ATH12K_HTT_RX_PDEV_STATS_NUM_BW_EXT_COUNTERS 4 #define ATH12K_HTT_RX_PDEV_STATS_NUM_MCS_COUNTERS_EXT 14 @@ -580,7 +609,7 @@ struct ath12k_htt_rx_pdev_rate_ext_stats_tlv { __le32 rx_gi_ext_2[ATH12K_HTT_RX_PDEV_STATS_NUM_GI_COUNTERS] [ATH12K_HTT_RX_PDEV_STATS_NUM_EXTRA2_MCS_COUNTERS]; __le32 rx_su_punctured_mode[ATH12K_HTT_RX_PDEV_STATS_NUM_PUNCTURED_MODE_COUNTERS]; -}; +} __packed; #define ATH12K_HTT_TX_PDEV_STATS_SCHED_PER_TXQ_MAC_ID GENMASK(7, 0) #define ATH12K_HTT_TX_PDEV_STATS_SCHED_PER_TXQ_ID GENMASK(15, 8) @@ -1872,4 +1901,176 @@ struct ath12k_htt_pdev_mbssid_ctrl_frame_tlv { __le32 ul_mumimo_trigger_within_bss; } __packed; +struct ath12k_htt_pdev_tdma_stats_tlv { + __le32 mac_id__word; + __le32 num_tdma_active_schedules; + __le32 num_tdma_reserved_schedules; + __le32 num_tdma_restricted_schedules; + __le32 num_tdma_unconfigured_schedules; + __le32 num_tdma_slot_switches; + __le32 num_tdma_edca_switches; +} __packed; + +struct ath12k_htt_mlo_sched_stats_tlv { + __le32 pref_link_num_sec_link_sched; + __le32 pref_link_num_pref_link_timeout; + __le32 pref_link_num_pref_link_sch_delay_ipc; + __le32 pref_link_num_pref_link_timeout_ipc; +} __packed; + +#define ATH12K_HTT_HWMLO_MAX_LINKS 6 +#define ATH12K_HTT_MLO_MAX_IPC_RINGS 7 + +struct ath12k_htt_pdev_mlo_ipc_stats_tlv { + __le32 mlo_ipc_ring_cnt[ATH12K_HTT_HWMLO_MAX_LINKS][ATH12K_HTT_MLO_MAX_IPC_RINGS]; +} __packed; + +struct ath12k_htt_stats_pdev_rtt_resp_stats_tlv { + __le32 pdev_id; + __le32 tx_11mc_ftm_suc; + __le32 tx_11mc_ftm_suc_retry; + __le32 tx_11mc_ftm_fail; + __le32 rx_11mc_ftmr_cnt; + __le32 rx_11mc_ftmr_dup_cnt; + __le32 rx_11mc_iftmr_cnt; + __le32 rx_11mc_iftmr_dup_cnt; + __le32 ftmr_drop_11mc_resp_role_not_enabled_cnt; + __le32 initiator_active_responder_rejected_cnt; + __le32 responder_terminate_cnt; + __le32 active_rsta_open; + __le32 active_rsta_mac; + __le32 active_rsta_mac_phy; + __le32 num_assoc_ranging_peers; + __le32 num_unassoc_ranging_peers; + __le32 responder_alloc_cnt; + __le32 responder_alloc_failure; + __le32 pn_check_failure_cnt; + __le32 pasn_m1_auth_recv_cnt; + __le32 pasn_m1_auth_drop_cnt; + __le32 pasn_m2_auth_recv_cnt; + __le32 pasn_m2_auth_tx_fail_cnt; + __le32 pasn_m3_auth_recv_cnt; + __le32 pasn_m3_auth_drop_cnt; + __le32 pasn_peer_create_request_cnt; + __le32 pasn_peer_create_timeout_cnt; + __le32 pasn_peer_created_cnt; + __le32 sec_ranging_not_supported_mfp_not_setup; + __le32 non_sec_ranging_discarded_for_assoc_peer; + __le32 open_ranging_discarded_set_for_pasn_peer; + __le32 unassoc_non_pasn_ranging_not_supported; + __le32 num_req_bw_20_mhz; + __le32 num_req_bw_40_mhz; + __le32 num_req_bw_80_mhz; + __le32 num_req_bw_160_mhz; + __le32 tx_11az_ftm_successful; + __le32 tx_11az_ftm_failed; + __le32 rx_11az_ftmr_cnt; + __le32 rx_11az_ftmr_dup_cnt; + __le32 rx_11az_iftmr_dup_cnt; + __le32 malformed_ftmr; + __le32 ftmr_drop_ntb_resp_role_not_enabled_cnt; + __le32 ftmr_drop_tb_resp_role_not_enabled_cnt; + __le32 invalid_ftm_request_params; + __le32 requested_bw_format_not_supported; + __le32 ntb_unsec_unassoc_ranging_peer_alloc_failed; + __le32 tb_unassoc_unsec_pasn_peer_creation_failed; + __le32 num_ranging_sequences_processed; + __le32 ntb_tx_ndp; + __le32 ndp_rx_cnt; + __le32 num_ntb_ranging_ndpas_recv; + __le32 recv_lmr; + __le32 invalid_ftmr_cnt; + __le32 max_time_bw_meas_exp_cnt; +} __packed; + +#define ATH12K_HTT_MAX_SCH_CMD_RESULT 25 +#define ATH12K_HTT_SCH_CMD_STATUS_CNT 9 + +struct ath12k_htt_stats_pdev_rtt_init_stats_tlv { + __le32 pdev_id; + __le32 tx_11mc_ftmr_cnt; + __le32 tx_11mc_ftmr_fail; + __le32 tx_11mc_ftmr_suc_retry; + __le32 rx_11mc_ftm_cnt; + __le32 tx_meas_req_count; + __le32 init_role_not_enabled; + __le32 initiator_terminate_cnt; + __le32 tx_11az_ftmr_fail; + __le32 tx_11az_ftmr_start; + __le32 tx_11az_ftmr_stop; + __le32 rx_11az_ftm_cnt; + __le32 active_ista; + __le32 invalid_preamble; + __le32 invalid_chan_bw_format; + __le32 mgmt_buff_alloc_fail_cnt; + __le32 ftm_parse_failure; + __le32 ranging_negotiation_successful_cnt; + __le32 incompatible_ftm_params; + __le32 sec_ranging_req_in_open_mode; + __le32 ftmr_tx_failed_null_11az_peer; + __le32 ftmr_retry_timeout; + __le32 max_time_bw_meas_exp_cnt; + __le32 tb_meas_duration_expiry_cnt; + __le32 num_tb_ranging_requests; + __le32 ntbr_triggered_successfully; + __le32 ntbr_trigger_failed; + __le32 invalid_or_no_vreg_idx; + __le32 set_vreg_params_failed; + __le32 sac_mismatch; + __le32 pasn_m1_auth_recv_cnt; + __le32 pasn_m1_auth_tx_fail_cnt; + __le32 pasn_m2_auth_recv_cnt; + __le32 pasn_m2_auth_drop_cnt; + __le32 pasn_m3_auth_recv_cnt; + __le32 pasn_m3_auth_tx_fail_cnt; + __le32 pasn_peer_create_request_cnt; + __le32 pasn_peer_create_timeout_cnt; + __le32 pasn_peer_created_cnt; + __le32 ntbr_ndpa_failed; + __le32 ntbr_sequence_successful; + __le32 ntbr_ndp_failed; + __le32 sch_cmd_status_cnts[ATH12K_HTT_SCH_CMD_STATUS_CNT]; + __le32 lmr_timeout; + __le32 lmr_recv; + __le32 num_trigger_frames_received; + __le32 num_tb_ranging_ndpas_recv; + __le32 ndp_rx_cnt; +} __packed; + +struct ath12k_htt_stats_pdev_rtt_hw_stats_tlv { + __le32 ista_ranging_ndpa_cnt; + __le32 ista_ranging_ndp_cnt; + __le32 ista_ranging_i2r_lmr_cnt; + __le32 rtsa_ranging_resp_cnt; + __le32 rtsa_ranging_ndp_cnt; + __le32 rsta_ranging_lmr_cnt; + __le32 tb_ranging_cts2s_rcvd_cnt; + __le32 tb_ranging_ndp_rcvd_cnt; + __le32 tb_ranging_lmr_rcvd_cnt; + __le32 tb_ranging_tf_poll_resp_sent_cnt; + __le32 tb_ranging_tf_sound_resp_sent_cnt; + __le32 tb_ranging_tf_report_resp_sent_cnt; +} __packed; + +enum ath12k_htt_stats_txsend_ftype { + ATH12K_HTT_FTYPE_TF_POLL, + ATH12K_HTT_FTYPE_TF_SOUND, + ATH12K_HTT_FTYPE_TBR_NDPA, + ATH12K_HTT_FTYPE_TBR_NDP, + ATH12K_HTT_FTYPE_TBR_LMR, + ATH12K_HTT_FTYPE_TF_RPRT, + ATH12K_HTT_FTYPE_MAX +}; + +struct ath12k_htt_stats_pdev_rtt_tbr_tlv { + __le32 su_ftype[ATH12K_HTT_FTYPE_MAX]; + __le32 mu_ftype[ATH12K_HTT_FTYPE_MAX]; +} __packed; + +struct ath12k_htt_stats_pdev_rtt_tbr_cmd_result_stats_tlv { + __le32 tbr_num_sch_cmd_result_buckets; + __le32 su_res[ATH12K_HTT_FTYPE_MAX][ATH12K_HTT_MAX_SCH_CMD_RESULT]; + __le32 mu_res[ATH12K_HTT_FTYPE_MAX][ATH12K_HTT_MAX_SCH_CMD_RESULT]; +} __packed; + #endif diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index 6317c6d4c043..f893fce6d9bd 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.c @@ -101,7 +101,7 @@ peer_clean: return -ENOENT; } - for (; tid >= 0; tid--) + for (tid--; tid >= 0; tid--) ath12k_dp_rx_peer_tid_delete(ar, peer, tid); spin_unlock_bh(&ab->base_lock); @@ -241,7 +241,7 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring, enum hal_ring_type type, int ring_num, int mac_id, int num_entries) { - struct hal_srng_params params = { 0 }; + struct hal_srng_params params = {}; int entry_sz = ath12k_hal_srng_get_entrysize(ab, type); int max_entries = ath12k_hal_srng_get_max_entries(ab, type); int ret; @@ -520,7 +520,7 @@ static int ath12k_dp_srng_common_setup(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_comp_ring, HAL_WBM2SW_RELEASE, tx_comp_ring_num, 0, - DP_TX_COMP_RING_SIZE); + DP_TX_COMP_RING_SIZE(ab)); if (ret) { ath12k_warn(ab, "failed to set up tcl_comp ring (%d) :%d\n", tx_comp_ring_num, ret); @@ -1083,8 +1083,8 @@ out: int ath12k_dp_htt_connect(struct ath12k_dp *dp) { - struct ath12k_htc_svc_conn_req conn_req = {0}; - struct ath12k_htc_svc_conn_resp conn_resp = {0}; + struct ath12k_htc_svc_conn_req conn_req = {}; + struct ath12k_htc_svc_conn_resp conn_resp = {}; int status; conn_req.ep_ops.ep_tx_complete = ath12k_dp_htt_htc_tx_complete; @@ -1163,31 +1163,36 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) /* RX Descriptor cleanup */ spin_lock_bh(&dp->rx_desc_lock); - for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - desc_info = dp->rxbaddr[i]; - - for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { - if (!desc_info[j].in_use) { - list_del(&desc_info[j].list); + if (dp->rxbaddr) { + for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES(ab); i++) { + if (!dp->rxbaddr[i]) continue; - } - skb = desc_info[j].skb; - if (!skb) - continue; + desc_info = dp->rxbaddr[i]; - dma_unmap_single(ab->dev, ATH12K_SKB_RXCB(skb)->paddr, - skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); - dev_kfree_skb_any(skb); - } - } + for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) { + if (!desc_info[j].in_use) { + list_del(&desc_info[j].list); + continue; + } - for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { - if (!dp->rxbaddr[i]) - continue; + skb = desc_info[j].skb; + if (!skb) + continue; + + dma_unmap_single(ab->dev, + ATH12K_SKB_RXCB(skb)->paddr, + skb->len + skb_tailroom(skb), + DMA_FROM_DEVICE); + dev_kfree_skb_any(skb); + } + + kfree(dp->rxbaddr[i]); + dp->rxbaddr[i] = NULL; + } - kfree(dp->rxbaddr[i]); - dp->rxbaddr[i] = NULL; + kfree(dp->rxbaddr); + dp->rxbaddr = NULL; } spin_unlock_bh(&dp->rx_desc_lock); @@ -1196,8 +1201,8 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) for (i = 0; i < ATH12K_HW_MAX_QUEUES; i++) { spin_lock_bh(&dp->tx_desc_lock[i]); - list_for_each_entry_safe(tx_desc_info, tmp1, &dp->tx_desc_used_list[i], - list) { + list_for_each_entry_safe(tx_desc_info, tmp1, + &dp->tx_desc_used_list[i], list) { list_del(&tx_desc_info->list); skb = tx_desc_info->skb; @@ -1231,19 +1236,25 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab) spin_unlock_bh(&dp->tx_desc_lock[i]); } - for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) { - spin_lock_bh(&dp->tx_desc_lock[pool_id]); + if (dp->txbaddr) { + for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) { + spin_lock_bh(&dp->tx_desc_lock[pool_id]); - for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) { - tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; - if (!dp->txbaddr[tx_spt_page]) - continue; + for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL(ab); i++) { + tx_spt_page = i + pool_id * + ATH12K_TX_SPT_PAGES_PER_POOL(ab); + if (!dp->txbaddr[tx_spt_page]) + continue; + + kfree(dp->txbaddr[tx_spt_page]); + dp->txbaddr[tx_spt_page] = NULL; + } - kfree(dp->txbaddr[tx_spt_page]); - dp->txbaddr[tx_spt_page] = NULL; + spin_unlock_bh(&dp->tx_desc_lock[pool_id]); } - spin_unlock_bh(&dp->tx_desc_lock[pool_id]); + kfree(dp->txbaddr); + dp->txbaddr = NULL; } /* unmap SPT pages */ @@ -1392,8 +1403,8 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT); spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT); - start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET; - end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES; + start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET(ab); + end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES(ab); if (ppt_idx < start_ppt_idx || ppt_idx >= end_ppt_idx || @@ -1417,7 +1428,7 @@ struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, start_ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET; end_ppt_idx = start_ppt_idx + - (ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES); + (ATH12K_TX_SPT_PAGES_PER_POOL(ab) * ATH12K_HW_MAX_QUEUES); if (ppt_idx < start_ppt_idx || ppt_idx >= end_ppt_idx || @@ -1434,13 +1445,24 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) struct ath12k_dp *dp = &ab->dp; struct ath12k_rx_desc_info *rx_descs, **rx_desc_addr; struct ath12k_tx_desc_info *tx_descs, **tx_desc_addr; + u32 num_rx_spt_pages = ATH12K_NUM_RX_SPT_PAGES(ab); u32 i, j, pool_id, tx_spt_page; u32 ppt_idx, cookie_ppt_idx; spin_lock_bh(&dp->rx_desc_lock); - /* First ATH12K_NUM_RX_SPT_PAGES of allocated SPT pages are used for RX */ - for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) { + dp->rxbaddr = kcalloc(num_rx_spt_pages, + sizeof(struct ath12k_rx_desc_info *), GFP_ATOMIC); + + if (!dp->rxbaddr) { + spin_unlock_bh(&dp->rx_desc_lock); + return -ENOMEM; + } + + /* First ATH12K_NUM_RX_SPT_PAGES(ab) of allocated SPT pages are used for + * RX + */ + for (i = 0; i < num_rx_spt_pages; i++) { rx_descs = kcalloc(ATH12K_MAX_SPT_ENTRIES, sizeof(*rx_descs), GFP_ATOMIC); @@ -1449,7 +1471,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } - ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET + i; + ppt_idx = ATH12K_RX_SPT_PAGE_OFFSET(ab) + i; cookie_ppt_idx = dp->rx_ppt_base + ppt_idx; dp->rxbaddr[i] = &rx_descs[0]; @@ -1467,9 +1489,15 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) spin_unlock_bh(&dp->rx_desc_lock); + dp->txbaddr = kcalloc(ATH12K_NUM_TX_SPT_PAGES(ab), + sizeof(struct ath12k_tx_desc_info *), GFP_ATOMIC); + + if (!dp->txbaddr) + return -ENOMEM; + for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) { spin_lock_bh(&dp->tx_desc_lock[pool_id]); - for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) { + for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL(ab); i++) { tx_descs = kcalloc(ATH12K_MAX_SPT_ENTRIES, sizeof(*tx_descs), GFP_ATOMIC); @@ -1479,7 +1507,8 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab) return -ENOMEM; } - tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL; + tx_spt_page = i + pool_id * + ATH12K_TX_SPT_PAGES_PER_POOL(ab); ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET + tx_spt_page; dp->txbaddr[tx_spt_page] = &tx_descs[0]; @@ -1513,12 +1542,12 @@ static int ath12k_dp_cmem_init(struct ath12k_base *ab, switch (type) { case ATH12K_DP_TX_DESC: start = ATH12K_TX_SPT_PAGE_OFFSET; - end = start + ATH12K_NUM_TX_SPT_PAGES; + end = start + ATH12K_NUM_TX_SPT_PAGES(ab); break; case ATH12K_DP_RX_DESC: cmem_base += ATH12K_PPT_ADDR_OFFSET(dp->rx_ppt_base); - start = ATH12K_RX_SPT_PAGE_OFFSET; - end = start + ATH12K_NUM_RX_SPT_PAGES; + start = ATH12K_RX_SPT_PAGE_OFFSET(ab); + end = start + ATH12K_NUM_RX_SPT_PAGES(ab); break; default: ath12k_err(ab, "invalid descriptor type %d in cmem init\n", type); @@ -1546,6 +1575,11 @@ void ath12k_dp_partner_cc_init(struct ath12k_base *ab) } } +static u32 ath12k_dp_get_num_spt_pages(struct ath12k_base *ab) +{ + return ATH12K_NUM_RX_SPT_PAGES(ab) + ATH12K_NUM_TX_SPT_PAGES(ab); +} + static int ath12k_dp_cc_init(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; @@ -1560,7 +1594,7 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) spin_lock_init(&dp->tx_desc_lock[i]); } - dp->num_spt_pages = ATH12K_NUM_SPT_PAGES; + dp->num_spt_pages = ath12k_dp_get_num_spt_pages(ab); if (dp->num_spt_pages > ATH12K_MAX_PPT_ENTRIES) dp->num_spt_pages = ATH12K_MAX_PPT_ENTRIES; @@ -1572,7 +1606,7 @@ static int ath12k_dp_cc_init(struct ath12k_base *ab) return -ENOMEM; } - dp->rx_ppt_base = ab->device_id * ATH12K_NUM_RX_SPT_PAGES; + dp->rx_ppt_base = ab->device_id * ATH12K_NUM_RX_SPT_PAGES(ab); for (i = 0; i < dp->num_spt_pages; i++) { dp->spt_info[i].vaddr = dma_alloc_coherent(ab->dev, @@ -1747,7 +1781,8 @@ int ath12k_dp_alloc(struct ath12k_base *ab) if (ret) goto fail_dp_bank_profiles_cleanup; - size = sizeof(struct hal_wbm_release_ring_tx) * DP_TX_COMP_RING_SIZE; + size = sizeof(struct hal_wbm_release_ring_tx) * + DP_TX_COMP_RING_SIZE(ab); ret = ath12k_dp_reoq_lut_setup(ab); if (ret) { @@ -1759,7 +1794,7 @@ int ath12k_dp_alloc(struct ath12k_base *ab) dp->tx_ring[i].tcl_data_ring_id = i; dp->tx_ring[i].tx_status_head = 0; - dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE - 1; + dp->tx_ring[i].tx_status_tail = DP_TX_COMP_RING_SIZE(ab) - 1; dp->tx_ring[i].tx_status = kmalloc(size, GFP_KERNEL); if (!dp->tx_ring[i].tx_status) { ret = -ENOMEM; diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index a353333f83b6..7baa48b86f7a 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.h @@ -46,7 +46,7 @@ struct dp_rxdma_ring { int bufs_max; }; -#define ATH12K_TX_COMPL_NEXT(x) (((x) + 1) % DP_TX_COMP_RING_SIZE) +#define ATH12K_TX_COMPL_NEXT(ab, x) (((x) + 1) % DP_TX_COMP_RING_SIZE(ab)) struct dp_tx_ring { u8 tcl_data_ring_id; @@ -174,8 +174,9 @@ struct ath12k_pdev_dp { #define DP_WBM_RELEASE_RING_SIZE 64 #define DP_TCL_DATA_RING_SIZE 512 -#define DP_TX_COMP_RING_SIZE 32768 -#define DP_TX_IDR_SIZE DP_TX_COMP_RING_SIZE +#define DP_TX_COMP_RING_SIZE(ab) \ + ((ab)->profile_param->dp_params.tx_comp_ring_size) +#define DP_TX_IDR_SIZE(ab) DP_TX_COMP_RING_SIZE(ab) #define DP_TCL_CMD_RING_SIZE 32 #define DP_TCL_STATUS_RING_SIZE 32 #define DP_REO_DST_RING_MAX 8 @@ -190,8 +191,10 @@ struct ath12k_pdev_dp { #define DP_RXDMA_REFILL_RING_SIZE 2048 #define DP_RXDMA_ERR_DST_RING_SIZE 1024 #define DP_RXDMA_MON_STATUS_RING_SIZE 1024 -#define DP_RXDMA_MONITOR_BUF_RING_SIZE 4096 -#define DP_RXDMA_MONITOR_DST_RING_SIZE 8092 +#define DP_RXDMA_MONITOR_BUF_RING_SIZE(ab) \ + ((ab)->profile_param->dp_params.rxdma_monitor_buf_ring_size) +#define DP_RXDMA_MONITOR_DST_RING_SIZE(ab) \ + ((ab)->profile_param->dp_params.rxdma_monitor_dst_ring_size) #define DP_RXDMA_MONITOR_DESC_RING_SIZE 4096 #define DP_TX_MONITOR_BUF_RING_SIZE 4096 #define DP_TX_MONITOR_DEST_RING_SIZE 2048 @@ -225,10 +228,11 @@ struct ath12k_pdev_dp { #define ATH12K_SHADOW_DP_TIMER_INTERVAL 20 #define ATH12K_SHADOW_CTRL_TIMER_INTERVAL 10 -#define ATH12K_NUM_POOL_TX_DESC 32768 - +#define ATH12K_NUM_POOL_TX_DESC(ab) \ + ((ab)->profile_param->dp_params.num_pool_tx_desc) /* TODO: revisit this count during testing */ -#define ATH12K_RX_DESC_COUNT (12288) +#define ATH12K_RX_DESC_COUNT(ab) \ + ((ab)->profile_param->dp_params.rx_desc_count) #define ATH12K_PAGE_SIZE PAGE_SIZE @@ -240,20 +244,21 @@ struct ath12k_pdev_dp { /* Total 512 entries in a SPT, i.e 4K Page/8 */ #define ATH12K_MAX_SPT_ENTRIES 512 -#define ATH12K_NUM_RX_SPT_PAGES ((ATH12K_RX_DESC_COUNT) / ATH12K_MAX_SPT_ENTRIES) +#define ATH12K_NUM_RX_SPT_PAGES(ab) ((ATH12K_RX_DESC_COUNT(ab)) / \ + ATH12K_MAX_SPT_ENTRIES) -#define ATH12K_TX_SPT_PAGES_PER_POOL (ATH12K_NUM_POOL_TX_DESC / \ +#define ATH12K_TX_SPT_PAGES_PER_POOL(ab) (ATH12K_NUM_POOL_TX_DESC(ab) / \ ATH12K_MAX_SPT_ENTRIES) -#define ATH12K_NUM_TX_SPT_PAGES (ATH12K_TX_SPT_PAGES_PER_POOL * ATH12K_HW_MAX_QUEUES) -#define ATH12K_NUM_SPT_PAGES (ATH12K_NUM_RX_SPT_PAGES + ATH12K_NUM_TX_SPT_PAGES) +#define ATH12K_NUM_TX_SPT_PAGES(ab) (ATH12K_TX_SPT_PAGES_PER_POOL(ab) * \ + ATH12K_HW_MAX_QUEUES) #define ATH12K_TX_SPT_PAGE_OFFSET 0 -#define ATH12K_RX_SPT_PAGE_OFFSET ATH12K_NUM_TX_SPT_PAGES +#define ATH12K_RX_SPT_PAGE_OFFSET(ab) ATH12K_NUM_TX_SPT_PAGES(ab) /* The SPT pages are divided for RX and TX, first block for RX * and remaining for TX */ -#define ATH12K_NUM_TX_SPT_PAGE_START ATH12K_NUM_RX_SPT_PAGES +#define ATH12K_NUM_TX_SPT_PAGE_START(ab) ATH12K_NUM_RX_SPT_PAGES(ab) #define ATH12K_DP_RX_DESC_MAGIC 0xBABABABA @@ -399,8 +404,8 @@ struct ath12k_dp { struct ath12k_spt_info *spt_info; u32 num_spt_pages; u32 rx_ppt_base; - struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES]; - struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES]; + struct ath12k_rx_desc_info **rxbaddr; + struct ath12k_tx_desc_info **txbaddr; struct list_head rx_desc_free_list; /* protects the free desc list */ spinlock_t rx_desc_lock; @@ -469,6 +474,7 @@ enum htt_h2t_msg_type { }; #define HTT_VER_REQ_INFO_MSG_ID GENMASK(7, 0) +#define HTT_OPTION_TCL_METADATA_VER_V1 1 #define HTT_OPTION_TCL_METADATA_VER_V2 2 #define HTT_OPTION_TAG GENMASK(7, 0) #define HTT_OPTION_LEN GENMASK(15, 8) @@ -703,7 +709,8 @@ struct htt_ppdu_stats_cfg_cmd { } __packed; #define HTT_PPDU_STATS_CFG_MSG_TYPE GENMASK(7, 0) -#define HTT_PPDU_STATS_CFG_PDEV_ID GENMASK(15, 8) +#define HTT_PPDU_STATS_CFG_SOC_STATS BIT(8) +#define HTT_PPDU_STATS_CFG_PDEV_ID GENMASK(15, 9) #define HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK GENMASK(31, 16) enum htt_ppdu_stats_tag_type { @@ -1559,6 +1566,8 @@ enum HTT_PPDU_STATS_PPDU_TYPE { #define HTT_PPDU_STATS_USER_RATE_FLAGS_DCM_M BIT(28) #define HTT_PPDU_STATS_USER_RATE_FLAGS_LDPC_M BIT(29) +#define HTT_USR_RATE_PPDU_TYPE(_val) \ + le32_get_bits(_val, HTT_PPDU_STATS_USER_RATE_INFO1_PPDU_TYPE_M) #define HTT_USR_RATE_PREAMBLE(_val) \ le32_get_bits(_val, HTT_PPDU_STATS_USER_RATE_FLAGS_PREAMBLE_M) #define HTT_USR_RATE_BW(_val) \ diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index 28cadc4167f7..8189e52ed007 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -2146,10 +2146,15 @@ static void ath12k_dp_mon_update_radiotap(struct ath12k *ar, struct ieee80211_rx_status *rxs) { struct ieee80211_supported_band *sband; + s32 noise_floor; u8 *ptr = NULL; + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + rxs->flag |= RX_FLAG_MACTIME_START; - rxs->signal = ppduinfo->rssi_comb + ATH12K_DEFAULT_NOISE_FLOOR; + rxs->signal = ppduinfo->rssi_comb + noise_floor; rxs->nss = ppduinfo->nss + 1; if (ppduinfo->userstats[ppduinfo->userid].ampdu_present) { @@ -3610,7 +3615,6 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar, struct hal_rx_mon_ppdu_info *ppdu_info, u32 uid) { - struct ath12k_sta *ahsta; struct ath12k_link_sta *arsta; struct ath12k_rx_peer_stats *rx_stats = NULL; struct hal_rx_user_status *user_stats = &ppdu_info->userstats[uid]; @@ -3628,8 +3632,13 @@ ath12k_dp_mon_rx_update_user_stats(struct ath12k *ar, return; } - ahsta = ath12k_sta_to_ahsta(peer->sta); - arsta = &ahsta->deflink; + arsta = ath12k_peer_get_link_sta(ar->ab, peer); + if (!arsta) { + ath12k_warn(ar->ab, "link sta not found on peer %pM id %d\n", + peer->addr, peer->peer_id); + return; + } + arsta->rssi_comb = ppdu_info->rssi_comb; ewma_avg_rssi_add(&arsta->avg_rssi, ppdu_info->rssi_comb); rx_stats = arsta->rx_stats; @@ -3742,7 +3751,6 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget, struct dp_srng *mon_dst_ring; struct hal_srng *srng; struct dp_rxdma_mon_ring *buf_ring; - struct ath12k_sta *ahsta = NULL; struct ath12k_link_sta *arsta; struct ath12k_peer *peer; struct sk_buff_head skb_list; @@ -3761,7 +3769,6 @@ int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget, ath12k_hal_srng_access_begin(ab, srng); while (likely(*budget)) { - *budget -= 1; mon_dst_desc = ath12k_hal_srng_dst_peek(ab, srng); if (unlikely(!mon_dst_desc)) break; @@ -3869,8 +3876,15 @@ move_next: } if (ppdu_info->reception_type == HAL_RX_RECEPTION_TYPE_SU) { - ahsta = ath12k_sta_to_ahsta(peer->sta); - arsta = &ahsta->deflink; + arsta = ath12k_peer_get_link_sta(ar->ab, peer); + if (!arsta) { + ath12k_warn(ar->ab, "link sta not found on peer %pM id %d\n", + peer->addr, peer->peer_id); + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + dev_kfree_skb_any(skb); + continue; + } ath12k_dp_mon_rx_update_peer_su_stats(ar, arsta, ppdu_info); } else if ((ppdu_info->fc_valid) && diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index bd95dc88f9b2..8ab91273592c 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -570,7 +570,7 @@ static int ath12k_dp_rx_pdev_srng_alloc(struct ath12k *ar) &dp->rxdma_mon_dst_ring[i], HAL_RXDMA_MONITOR_DST, 0, mac_id + i, - DP_RXDMA_MONITOR_DST_RING_SIZE); + DP_RXDMA_MONITOR_DST_RING_SIZE(ab)); if (ret) { ath12k_warn(ar->ab, "failed to setup HAL_RXDMA_MONITOR_DST\n"); @@ -671,7 +671,7 @@ static int ath12k_dp_reo_cmd_send(struct ath12k_base *ab, struct ath12k_dp_rx_ti static void ath12k_dp_reo_cache_flush(struct ath12k_base *ab, struct ath12k_dp_rx_tid *rx_tid) { - struct ath12k_hal_reo_cmd cmd = {0}; + struct ath12k_hal_reo_cmd cmd = {}; unsigned long tot_desc_sz, desc_sz; int ret; @@ -828,7 +828,7 @@ static void ath12k_peer_rx_tid_qref_reset(struct ath12k_base *ab, u16 peer_id, u void ath12k_dp_rx_peer_tid_delete(struct ath12k *ar, struct ath12k_peer *peer, u8 tid) { - struct ath12k_hal_reo_cmd cmd = {0}; + struct ath12k_hal_reo_cmd cmd = {}; struct ath12k_dp_rx_tid *rx_tid = &peer->rx_tid[tid]; int ret; @@ -939,7 +939,7 @@ static int ath12k_peer_rx_tid_reo_update(struct ath12k *ar, u32 ba_win_sz, u16 ssn, bool update_ssn) { - struct ath12k_hal_reo_cmd cmd = {0}; + struct ath12k_hal_reo_cmd cmd = {}; int ret; cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned); @@ -1204,7 +1204,7 @@ int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif, { struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ath12k_hal_reo_cmd cmd = {0}; + struct ath12k_hal_reo_cmd cmd = {}; struct ath12k_peer *peer; struct ath12k_dp_rx_tid *rx_tid; u8 tid; @@ -1418,27 +1418,33 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, { struct ath12k_base *ab = ar->ab; struct ath12k_peer *peer; - struct ieee80211_sta *sta; - struct ath12k_sta *ahsta; struct ath12k_link_sta *arsta; struct htt_ppdu_stats_user_rate *user_rate; struct ath12k_per_peer_tx_stats *peer_stats = &ar->peer_tx_stats; struct htt_ppdu_user_stats *usr_stats = &ppdu_stats->user_stats[user]; struct htt_ppdu_stats_common *common = &ppdu_stats->common; int ret; - u8 flags, mcs, nss, bw, sgi, dcm, rate_idx = 0; + u8 flags, mcs, nss, bw, sgi, dcm, ppdu_type, rate_idx = 0; u32 v, succ_bytes = 0; u16 tones, rate = 0, succ_pkts = 0; u32 tx_duration = 0; u8 tid = HTT_PPDU_STATS_NON_QOS_TID; - bool is_ampdu = false; + u16 tx_retry_failed = 0, tx_retry_count = 0; + bool is_ampdu = false, is_ofdma; if (!(usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_RATE))) return; - if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) + if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_COMMON)) { is_ampdu = HTT_USR_CMPLTN_IS_AMPDU(usr_stats->cmpltn_cmn.flags); + tx_retry_failed = + __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_tried) - + __le16_to_cpu(usr_stats->cmpltn_cmn.mpdu_success); + tx_retry_count = + HTT_USR_CMPLTN_LONG_RETRY(usr_stats->cmpltn_cmn.flags) + + HTT_USR_CMPLTN_SHORT_RETRY(usr_stats->cmpltn_cmn.flags); + } if (usr_stats->tlv_flags & BIT(HTT_PPDU_STATS_TAG_USR_COMPLTN_ACK_BA_STATUS)) { @@ -1460,6 +1466,10 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, sgi = HTT_USR_RATE_GI(user_rate->rate_flags); dcm = HTT_USR_RATE_DCM(user_rate->rate_flags); + ppdu_type = HTT_USR_RATE_PPDU_TYPE(user_rate->info1); + is_ofdma = (ppdu_type == HTT_PPDU_STATS_PPDU_TYPE_MU_OFDMA) || + (ppdu_type == HTT_PPDU_STATS_PPDU_TYPE_MU_MIMO_OFDMA); + /* Note: If host configured fixed rates and in some other special * cases, the broadcast/management frames are sent in different rates. * Firmware rate's control to be skipped for this? @@ -1500,12 +1510,17 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, return; } - sta = peer->sta; - ahsta = ath12k_sta_to_ahsta(sta); - arsta = &ahsta->deflink; + arsta = ath12k_peer_get_link_sta(ab, peer); + if (!arsta) { + spin_unlock_bh(&ab->base_lock); + rcu_read_unlock(); + return; + } memset(&arsta->txrate, 0, sizeof(arsta->txrate)); + arsta->txrate.bw = ath12k_mac_bw_to_mac80211_bw(bw); + switch (flags) { case WMI_RATE_PREAMBLE_OFDM: arsta->txrate.legacy = rate; @@ -1534,11 +1549,26 @@ ath12k_update_per_peer_tx_stats(struct ath12k *ar, le16_to_cpu(user_rate->ru_start) + 1; v = ath12k_he_ru_tones_to_nl80211_he_ru_alloc(tones); arsta->txrate.he_ru_alloc = v; + if (is_ofdma) + arsta->txrate.bw = RATE_INFO_BW_HE_RU; + break; + case WMI_RATE_PREAMBLE_EHT: + arsta->txrate.mcs = mcs; + arsta->txrate.flags = RATE_INFO_FLAGS_EHT_MCS; + arsta->txrate.he_dcm = dcm; + arsta->txrate.eht_gi = ath12k_mac_eht_gi_to_nl80211_eht_gi(sgi); + tones = le16_to_cpu(user_rate->ru_end) - + le16_to_cpu(user_rate->ru_start) + 1; + v = ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(tones); + arsta->txrate.eht_ru_alloc = v; + if (is_ofdma) + arsta->txrate.bw = RATE_INFO_BW_EHT_RU; break; } + arsta->tx_retry_failed += tx_retry_failed; + arsta->tx_retry_count += tx_retry_count; arsta->txrate.nss = nss; - arsta->txrate.bw = ath12k_mac_bw_to_mac80211_bw(bw); arsta->tx_duration += tx_duration; memcpy(&arsta->last_txrate, &arsta->txrate, sizeof(struct rate_info)); @@ -2534,31 +2564,15 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap struct ath12k_dp_rx_info *rx_info) { struct ath12k_base *ab = ar->ab; - static const struct ieee80211_radiotap_he known = { - .data1 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_DATA_MCS_KNOWN | - IEEE80211_RADIOTAP_HE_DATA1_BW_RU_ALLOC_KNOWN), - .data2 = cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA2_GI_KNOWN), - }; - struct ieee80211_radiotap_he *he; struct ieee80211_rx_status *rx_status; struct ieee80211_sta *pubsta; struct ath12k_peer *peer; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); struct ieee80211_rx_status *status = rx_info->rx_status; - u8 decap = DP_RX_DECAP_TYPE_RAW; + u8 decap = rx_info->decap_type; bool is_mcbc = rxcb->is_mcbc; bool is_eapol = rxcb->is_eapol; - if (status->encoding == RX_ENC_HE && !(status->flag & RX_FLAG_RADIOTAP_HE) && - !(status->flag & RX_FLAG_SKIP_MONITOR)) { - he = skb_push(msdu, sizeof(known)); - memcpy(he, &known, sizeof(known)); - status->flag |= RX_FLAG_RADIOTAP_HE; - } - - if (!(status->flag & RX_FLAG_ONLY_MONITOR)) - decap = rx_info->decap_type; - spin_lock_bh(&ab->base_lock); peer = ath12k_dp_rx_h_find_peer(ab, msdu, rx_info); @@ -2721,7 +2735,7 @@ static void ath12k_dp_rx_process_received_packets(struct ath12k_base *ab, int ring_id) { struct ath12k_hw_group *ag = ab->ag; - struct ieee80211_rx_status rx_status = {0}; + struct ieee80211_rx_status rx_status = {}; struct ath12k_skb_rxcb *rxcb; struct sk_buff *msdu; struct ath12k *ar; @@ -3016,7 +3030,7 @@ static int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key, size_t data_len, u8 *mic) { SHASH_DESC_ON_STACK(desc, tfm); - u8 mic_hdr[16] = {0}; + u8 mic_hdr[16] = {}; u8 tid = 0; int ret; @@ -3985,7 +3999,7 @@ static void ath12k_dp_rx_wbm_err(struct ath12k *ar, struct sk_buff_head *msdu_list) { struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - struct ieee80211_rx_status rxs = {0}; + struct ieee80211_rx_status rxs = {}; struct ath12k_dp_rx_info rx_info; bool drop = true; @@ -4009,6 +4023,8 @@ static void ath12k_dp_rx_wbm_err(struct ath12k *ar, return; } + rx_info.rx_status->flag |= RX_FLAG_SKIP_MONITOR; + ath12k_dp_rx_deliver_msdu(ar, napi, msdu, &rx_info); } @@ -4330,7 +4346,7 @@ void ath12k_dp_rx_pdev_free(struct ath12k_base *ab, int mac_id) int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 ring_id; int ret; u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; @@ -4371,7 +4387,7 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; u32 ring_id; int ret = 0; u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; @@ -4528,7 +4544,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->rxdma_mon_buf_ring.refill_buf_ring, HAL_RXDMA_MONITOR_BUF, 0, 0, - DP_RXDMA_MONITOR_BUF_RING_SIZE); + DP_RXDMA_MONITOR_BUF_RING_SIZE(ab)); if (ret) { ath12k_warn(ab, "failed to setup HAL_RXDMA_MONITOR_BUF\n"); return ret; diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index b6816b6c2c04..abc84ca8467a 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c @@ -13,10 +13,9 @@ #include "mac.h" static enum hal_tcl_encap_type -ath12k_dp_tx_get_encap_type(struct ath12k_link_vif *arvif, struct sk_buff *skb) +ath12k_dp_tx_get_encap_type(struct ath12k_base *ab, struct sk_buff *skb) { struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath12k_base *ab = arvif->ar->ab; if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) return HAL_TCL_ENCAP_TYPE_RAW; @@ -226,7 +225,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, { struct ath12k_base *ab = ar->ab; struct ath12k_dp *dp = &ab->dp; - struct hal_tx_info ti = {0}; + struct hal_tx_info ti = {}; struct ath12k_tx_desc_info *tx_desc; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); @@ -245,6 +244,8 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif, bool msdu_ext_desc = false; bool add_htt_metadata = false; u32 iova_mask = ab->hw_params->iova_mask; + bool is_diff_encap = false; + bool is_null_frame = false; if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ar->ab->dev_flags)) return -ESHUTDOWN; @@ -305,7 +306,7 @@ tcl_ring_sel: u32_encode_bits(mcbc_gsn, HTT_TCL_META_DATA_GLOBAL_SEQ_NUM); } - ti.encap_type = ath12k_dp_tx_get_encap_type(arvif, skb); + ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb); ti.addr_search_flags = arvif->hal_addr_search_flags; ti.search_type = arvif->search_type; ti.type = HAL_TCL_DESC_TYPE_BUFFER; @@ -335,7 +336,19 @@ tcl_ring_sel: switch (ti.encap_type) { case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI: - ath12k_dp_tx_encap_nwifi(skb); + is_null_frame = ieee80211_is_nullfunc(hdr->frame_control); + if (ahvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) { + if (skb->protocol == cpu_to_be16(ETH_P_PAE) || is_null_frame) + is_diff_encap = true; + + /* Firmware expects msdu ext descriptor for nwifi/raw packets + * received in ETH mode. Without this, observed tx fail for + * Multicast packets in ETH mode. + */ + msdu_ext_desc = true; + } else { + ath12k_dp_tx_encap_nwifi(skb); + } break; case HAL_TCL_ENCAP_TYPE_RAW: if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) { @@ -379,15 +392,25 @@ map: goto fail_remove_tx_buf; } - if (!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) && - !(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) && - !(skb_cb->flags & ATH12K_SKB_CIPHER_SET) && - ieee80211_has_protected(hdr->frame_control)) { - /* Add metadata for sw encrypted vlan group traffic */ + if ((!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) && + !(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) && + !(skb_cb->flags & ATH12K_SKB_CIPHER_SET) && + ieee80211_has_protected(hdr->frame_control)) || + is_diff_encap) { + /* Firmware is not expecting meta data for qos null + * nwifi packet received in ETH encap mode. + */ + if (is_null_frame && msdu_ext_desc) + goto skip_htt_meta; + + /* Add metadata for sw encrypted vlan group traffic + * and EAPOL nwifi packet received in ETH encap mode. + */ add_htt_metadata = true; msdu_ext_desc = true; - ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW); ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT; +skip_htt_meta: + ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW); ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW; ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN; } @@ -545,7 +568,8 @@ static void ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, struct ath12k_tx_desc_params *desc_params, struct dp_tx_ring *tx_ring, - struct ath12k_dp_htt_wbm_tx_status *ts) + struct ath12k_dp_htt_wbm_tx_status *ts, + u16 peer_id) { struct ieee80211_tx_info *info; struct ath12k_link_vif *arvif; @@ -554,6 +578,9 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, struct ath12k_vif *ahvif; struct ath12k *ar; struct sk_buff *msdu = desc_params->skb; + s32 noise_floor; + struct ieee80211_tx_status status = {}; + struct ath12k_peer *peer; skb_cb = ATH12K_SKB_CB(msdu); info = IEEE80211_SKB_CB(msdu); @@ -592,16 +619,38 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, info->status.ack_signal = ts->ack_rssi; if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, - ab->wmi_ab.svc_map)) - info->status.ack_signal += ATH12K_DEFAULT_NOISE_FLOOR; + ab->wmi_ab.svc_map)) { + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + + info->status.ack_signal += noise_floor; + } info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; } else { info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; } } + rcu_read_lock(); + spin_lock_bh(&ab->base_lock); + peer = ath12k_peer_find_by_id(ab, peer_id); + if (!peer || !peer->sta) { + ath12k_dbg(ab, ATH12K_DBG_DATA, + "dp_tx: failed to find the peer with peer_id %d\n", peer_id); + spin_unlock_bh(&ab->base_lock); + ieee80211_free_txskb(ath12k_ar_to_hw(ar), msdu); + goto exit; + } else { + status.sta = peer->sta; + } + spin_unlock_bh(&ab->base_lock); - ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu); + status.info = info; + status.skb = msdu; + ieee80211_tx_status_ext(ath12k_ar_to_hw(ar), &status); +exit: + rcu_read_unlock(); } static void @@ -610,8 +659,9 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, void *desc, struct ath12k_tx_desc_params *desc_params) { struct htt_tx_wbm_completion *status_desc; - struct ath12k_dp_htt_wbm_tx_status ts = {0}; + struct ath12k_dp_htt_wbm_tx_status ts = {}; enum hal_wbm_htt_tx_comp_status wbm_status; + u16 peer_id; status_desc = desc; @@ -624,7 +674,11 @@ ath12k_dp_tx_process_htt_tx_complete(struct ath12k_base *ab, void *desc, ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK); ts.ack_rssi = le32_get_bits(status_desc->info2, HTT_TX_WBM_COMP_INFO2_ACK_RSSI); - ath12k_dp_tx_htt_tx_complete_buf(ab, desc_params, tx_ring, &ts); + + peer_id = le32_get_bits(((struct hal_wbm_completion_ring_tx *)desc)-> + info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID); + + ath12k_dp_tx_htt_tx_complete_buf(ab, desc_params, tx_ring, &ts, peer_id); break; case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP: case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL: @@ -651,7 +705,7 @@ static void ath12k_dp_tx_update_txcompl(struct ath12k *ar, struct hal_tx_status struct ieee80211_sta *sta; struct ath12k_sta *ahsta; struct ath12k_link_sta *arsta; - struct rate_info txrate = {0}; + struct rate_info txrate = {}; u16 rate, ru_tones; u8 rate_idx = 0; int ret; @@ -775,6 +829,13 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, struct ieee80211_vif *vif; struct ath12k_vif *ahvif; struct sk_buff *msdu = desc_params->skb; + s32 noise_floor; + struct ieee80211_tx_status status = {}; + struct ieee80211_rate_status status_rate = {}; + struct ath12k_peer *peer; + struct ath12k_link_sta *arsta; + struct ath12k_sta *ahsta; + struct rate_info rate; if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) { /* Must not happen */ @@ -827,8 +888,13 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, info->status.ack_signal = ts->ack_rssi; if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, - ab->wmi_ab.svc_map)) - info->status.ack_signal += ATH12K_DEFAULT_NOISE_FLOOR; + ab->wmi_ab.svc_map)) { + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + + info->status.ack_signal += noise_floor; + } info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; } @@ -861,7 +927,32 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, ath12k_dp_tx_update_txcompl(ar, ts); - ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu); + spin_lock_bh(&ab->base_lock); + peer = ath12k_peer_find_by_id(ab, ts->peer_id); + if (!peer || !peer->sta) { + ath12k_err(ab, + "dp_tx: failed to find the peer with peer_id %d\n", + ts->peer_id); + spin_unlock_bh(&ab->base_lock); + ieee80211_free_txskb(ath12k_ar_to_hw(ar), msdu); + goto exit; + } + ahsta = ath12k_sta_to_ahsta(peer->sta); + arsta = &ahsta->deflink; + + spin_unlock_bh(&ab->base_lock); + + status.sta = peer->sta; + status.info = info; + status.skb = msdu; + rate = arsta->last_txrate; + + status_rate.rate_idx = rate; + status_rate.try_count = 1; + + status.rates = &status_rate; + status.n_rates = 1; + ieee80211_tx_status_ext(ath12k_ar_to_hw(ar), &status); exit: rcu_read_unlock(); @@ -890,6 +981,9 @@ static void ath12k_dp_tx_status_parse(struct ath12k_base *ab, ts->peer_id = le32_get_bits(desc->info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID); + ts->ack_rssi = le32_get_bits(desc->info2, + HAL_WBM_COMPL_TX_INFO2_ACK_FRAME_RSSI); + if (info0 & HAL_TX_RATE_STATS_INFO0_VALID) { ts->pkt_type = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_PKT_TYPE); ts->mcs = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_MCS); @@ -907,7 +1001,7 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id; struct hal_srng *status_ring = &ab->hal.srng_list[hal_ring_id]; struct ath12k_tx_desc_info *tx_desc = NULL; - struct hal_tx_status ts = { 0 }; + struct hal_tx_status ts = {}; struct ath12k_tx_desc_params desc_params; struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id]; struct hal_wbm_release_ring *desc; @@ -920,7 +1014,8 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) ath12k_hal_srng_access_begin(ab, status_ring); - while (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head) != tx_ring->tx_status_tail) { + while (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head) != + tx_ring->tx_status_tail) { desc = ath12k_hal_srng_dst_get_next_entry(ab, status_ring); if (!desc) break; @@ -928,11 +1023,12 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) memcpy(&tx_ring->tx_status[tx_ring->tx_status_head], desc, sizeof(*desc)); tx_ring->tx_status_head = - ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head); + ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head); } if (ath12k_hal_srng_dst_peek(ab, status_ring) && - (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_head) == tx_ring->tx_status_tail)) { + (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head) == + tx_ring->tx_status_tail)) { /* TODO: Process pending tx_status messages when kfifo_is_full() */ ath12k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n"); } @@ -941,12 +1037,13 @@ void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id) spin_unlock_bh(&status_ring->lock); - while (ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_tail) != tx_ring->tx_status_head) { + while (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_tail) != + tx_ring->tx_status_head) { struct hal_wbm_completion_ring_tx *tx_status; u32 desc_id; tx_ring->tx_status_tail = - ATH12K_TX_COMPL_NEXT(tx_ring->tx_status_tail); + ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_tail); tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail]; ath12k_dp_tx_status_parse(ab, tx_status, &ts); @@ -1183,6 +1280,7 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab) struct sk_buff *skb; struct htt_ver_req_cmd *cmd; int len = sizeof(*cmd); + u32 metadata_version; int ret; init_completion(&dp->htt_tgt_version_received); @@ -1195,12 +1293,14 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab) cmd = (struct htt_ver_req_cmd *)skb->data; cmd->ver_reg_info = le32_encode_bits(HTT_H2T_MSG_TYPE_VERSION_REQ, HTT_OPTION_TAG); + metadata_version = ath12k_ftm_mode ? HTT_OPTION_TCL_METADATA_VER_V1 : + HTT_OPTION_TCL_METADATA_VER_V2; cmd->tcl_metadata_version = le32_encode_bits(HTT_TAG_TCL_METADATA_VERSION, HTT_OPTION_TAG) | le32_encode_bits(HTT_TCL_METADATA_VER_SZ, HTT_OPTION_LEN) | - le32_encode_bits(HTT_OPTION_TCL_METADATA_VER_V2, + le32_encode_bits(metadata_version, HTT_OPTION_VALUE); ret = ath12k_htc_send(&ab->htc, dp->eid, skb); @@ -1246,7 +1346,7 @@ int ath12k_dp_tx_htt_h2t_ppdu_stats_req(struct ath12k *ar, u32 mask) cmd->msg = le32_encode_bits(HTT_H2T_MSG_TYPE_PPDU_STATS_CFG, HTT_PPDU_STATS_CFG_MSG_TYPE); - pdev_mask = 1 << (i + 1); + pdev_mask = 1 << (i + ar->pdev_idx); cmd->msg |= le32_encode_bits(pdev_mask, HTT_PPDU_STATS_CFG_PDEV_ID); cmd->msg |= le32_encode_bits(mask, HTT_PPDU_STATS_CFG_TLV_TYPE_BITMASK); @@ -1471,7 +1571,7 @@ int ath12k_dp_tx_htt_monitor_mode_ring_config(struct ath12k *ar, bool reset) int ath12k_dp_tx_htt_rx_monitor_mode_ring_config(struct ath12k *ar, bool reset) { struct ath12k_base *ab = ar->ab; - struct htt_rx_ring_tlv_filter tlv_filter = {0}; + struct htt_rx_ring_tlv_filter tlv_filter = {}; int ret, ring_id, i; tlv_filter.offset_valid = false; diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index a301898e5849..6406fcf5d69f 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -1950,7 +1950,7 @@ u32 ath12k_hal_ce_dst_status_get_length(struct hal_ce_srng_dst_status_desc *desc { u32 len; - len = le32_get_bits(READ_ONCE(desc->flags), HAL_CE_DST_STATUS_DESC_FLAGS_LEN); + len = le32_get_bits(desc->flags, HAL_CE_DST_STATUS_DESC_FLAGS_LEN); desc->flags &= ~cpu_to_le32(HAL_CE_DST_STATUS_DESC_FLAGS_LEN); return len; @@ -2143,13 +2143,24 @@ void *ath12k_hal_srng_src_get_next_reaped(struct ath12k_base *ab, void ath12k_hal_srng_access_begin(struct ath12k_base *ab, struct hal_srng *srng) { + u32 hp; + lockdep_assert_held(&srng->lock); - if (srng->ring_dir == HAL_SRNG_DIR_SRC) + if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.cached_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; - else - srng->u.dst_ring.cached_hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + } else { + hp = READ_ONCE(*srng->u.dst_ring.hp_addr); + + if (hp != srng->u.dst_ring.cached_hp) { + srng->u.dst_ring.cached_hp = hp; + /* Make sure descriptor is read after the head + * pointer. + */ + dma_rmb(); + } + } } /* Update cached ring head/tail pointers to HW. ath12k_hal_srng_access_begin() @@ -2159,7 +2170,6 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng) { lockdep_assert_held(&srng->lock); - /* TODO: See if we need a write memory barrier here */ if (srng->flags & HAL_SRNG_FLAGS_LMAC_RING) { /* For LMAC rings, ring pointer updates are done through FW and * hence written to a shared memory location that is read by FW @@ -2167,21 +2177,37 @@ void ath12k_hal_srng_access_end(struct ath12k_base *ab, struct hal_srng *srng) if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.last_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; - *srng->u.src_ring.hp_addr = srng->u.src_ring.hp; + /* Make sure descriptor is written before updating the + * head pointer. + */ + dma_wmb(); + WRITE_ONCE(*srng->u.src_ring.hp_addr, srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; - *srng->u.dst_ring.tp_addr = srng->u.dst_ring.tp; + /* Make sure descriptor is read before updating the + * tail pointer. + */ + dma_mb(); + WRITE_ONCE(*srng->u.dst_ring.tp_addr, srng->u.dst_ring.tp); } } else { if (srng->ring_dir == HAL_SRNG_DIR_SRC) { srng->u.src_ring.last_tp = *(volatile u32 *)srng->u.src_ring.tp_addr; + /* Assume implementation use an MMIO write accessor + * which has the required wmb() so that the descriptor + * is written before the updating the head pointer. + */ ath12k_hif_write32(ab, (unsigned long)srng->u.src_ring.hp_addr - (unsigned long)ab->mem, srng->u.src_ring.hp); } else { srng->u.dst_ring.last_hp = *srng->u.dst_ring.hp_addr; + /* Make sure descriptor is read before updating the + * tail pointer. + */ + mb(); ath12k_hif_write32(ab, (unsigned long)srng->u.dst_ring.tp_addr - (unsigned long)ab->mem, diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index 8254dc10b53b..6791ae1d64e5 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.c @@ -14,6 +14,7 @@ #include "hw.h" #include "mhi.h" #include "dp_rx.h" +#include "peer.h" static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec, 0x90, 0xd6, 0x02, 0x42, @@ -49,6 +50,12 @@ static bool ath12k_dp_srng_is_comp_ring_qcn9274(int ring_num) return false; } +static bool ath12k_is_frame_link_agnostic_qcn9274(struct ath12k_link_vif *arvif, + struct ieee80211_mgmt *mgmt) +{ + return ieee80211_is_action(mgmt->frame_control); +} + static int ath12k_hw_mac_id_to_pdev_id_wcn7850(const struct ath12k_hw_params *hw, int mac_id) { @@ -74,6 +81,52 @@ static bool ath12k_dp_srng_is_comp_ring_wcn7850(int ring_num) return false; } +static bool ath12k_is_addba_resp_action_code(struct ieee80211_mgmt *mgmt) +{ + if (!ieee80211_is_action(mgmt->frame_control)) + return false; + + if (mgmt->u.action.category != WLAN_CATEGORY_BACK) + return false; + + if (mgmt->u.action.u.addba_resp.action_code != WLAN_ACTION_ADDBA_RESP) + return false; + + return true; +} + +static bool ath12k_is_frame_link_agnostic_wcn7850(struct ath12k_link_vif *arvif, + struct ieee80211_mgmt *mgmt) +{ + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + struct ath12k_hw *ah = ath12k_ar_to_ah(arvif->ar); + struct ath12k_base *ab = arvif->ar->ab; + __le16 fc = mgmt->frame_control; + + spin_lock_bh(&ab->base_lock); + if (!ath12k_peer_find_by_addr(ab, mgmt->da) && + !ath12k_peer_ml_find(ah, mgmt->da)) { + spin_unlock_bh(&ab->base_lock); + return false; + } + spin_unlock_bh(&ab->base_lock); + + if (vif->type == NL80211_IFTYPE_STATION) + return arvif->is_up && + (vif->valid_links == vif->active_links) && + !ieee80211_is_probe_req(fc) && + !ieee80211_is_auth(fc) && + !ieee80211_is_deauth(fc) && + !ath12k_is_addba_resp_action_code(mgmt); + + if (vif->type == NL80211_IFTYPE_AP) + return !(ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) || + ieee80211_is_assoc_resp(fc) || ieee80211_is_reassoc_resp(fc) || + ath12k_is_addba_resp_action_code(mgmt)); + + return false; +} + static const struct ath12k_hw_ops qcn9274_ops = { .get_hw_mac_from_pdev_id = ath12k_hw_qcn9274_mac_from_pdev_id, .mac_id_to_pdev_id = ath12k_hw_mac_id_to_pdev_id_qcn9274, @@ -81,6 +134,7 @@ static const struct ath12k_hw_ops qcn9274_ops = { .rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_qcn9274, .get_ring_selector = ath12k_hw_get_ring_selector_qcn9274, .dp_srng_is_tx_comp_ring = ath12k_dp_srng_is_comp_ring_qcn9274, + .is_frame_link_agnostic = ath12k_is_frame_link_agnostic_qcn9274, }; static const struct ath12k_hw_ops wcn7850_ops = { @@ -90,6 +144,7 @@ static const struct ath12k_hw_ops wcn7850_ops = { .rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_wcn7850, .get_ring_selector = ath12k_hw_get_ring_selector_wcn7850, .dp_srng_is_tx_comp_ring = ath12k_dp_srng_is_comp_ring_wcn7850, + .is_frame_link_agnostic = ath12k_is_frame_link_agnostic_wcn7850, }; #define ATH12K_TX_RING_MASK_0 0x1 @@ -1478,7 +1533,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .download_calib = true, .supports_suspend = false, .tcl_ring_retry = true, - .reoq_lut_support = false, + .reoq_lut_support = true, .supports_shadow_regs = false, .num_tcl_banks = 48, diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index 0a75bc5abfa2..8ce11c3e6d5c 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.h @@ -16,37 +16,21 @@ /* Target configuration defines */ /* Num VDEVS per radio */ -#define TARGET_NUM_VDEVS (16 + 1) - -#define TARGET_NUM_PEERS_PDEV_SINGLE (TARGET_NUM_STATIONS_SINGLE + \ - TARGET_NUM_VDEVS) -#define TARGET_NUM_PEERS_PDEV_DBS (TARGET_NUM_STATIONS_DBS + \ - TARGET_NUM_VDEVS) -#define TARGET_NUM_PEERS_PDEV_DBS_SBS (TARGET_NUM_STATIONS_DBS_SBS + \ - TARGET_NUM_VDEVS) - -/* Num of peers for Single Radio mode */ -#define TARGET_NUM_PEERS_SINGLE (TARGET_NUM_PEERS_PDEV_SINGLE) - -/* Num of peers for DBS */ -#define TARGET_NUM_PEERS_DBS (2 * TARGET_NUM_PEERS_PDEV_DBS) - -/* Num of peers for DBS_SBS */ -#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV_DBS_SBS) +#define TARGET_NUM_VDEVS(ab) ((ab)->profile_param->num_vdevs) /* Max num of stations for Single Radio mode */ -#define TARGET_NUM_STATIONS_SINGLE 512 +#define TARGET_NUM_STATIONS_SINGLE(ab) ((ab)->profile_param->max_client_single) /* Max num of stations for DBS */ -#define TARGET_NUM_STATIONS_DBS 128 +#define TARGET_NUM_STATIONS_DBS(ab) ((ab)->profile_param->max_client_dbs) /* Max num of stations for DBS_SBS */ -#define TARGET_NUM_STATIONS_DBS_SBS 128 +#define TARGET_NUM_STATIONS_DBS_SBS(ab) \ + ((ab)->profile_param->max_client_dbs_sbs) + +#define TARGET_NUM_STATIONS(ab, x) TARGET_NUM_STATIONS_##x(ab) -#define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x #define TARGET_NUM_PEER_KEYS 2 -#define TARGET_NUM_TIDS(x) (2 * TARGET_NUM_PEERS(x) + \ - 4 * TARGET_NUM_VDEVS + 8) #define TARGET_AST_SKID_LIMIT 16 #define TARGET_NUM_OFFLD_PEERS 4 @@ -246,6 +230,8 @@ struct ath12k_hw_ops { int (*rxdma_ring_sel_config)(struct ath12k_base *ab); u8 (*get_ring_selector)(struct sk_buff *skb); bool (*dp_srng_is_tx_comp_ring)(int ring_num); + bool (*is_frame_link_agnostic)(struct ath12k_link_vif *arvif, + struct ieee80211_mgmt *mgmt); }; static inline diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index 59ec422992d3..bd1ec3b2c084 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -209,7 +209,7 @@ ath12k_phymodes[NUM_NL80211_BANDS][ATH12K_CHAN_WIDTH_NUM] = { [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40, [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80, [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160, - [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80, + [NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320, }, [NL80211_BAND_6GHZ] = { @@ -220,7 +220,7 @@ ath12k_phymodes[NUM_NL80211_BANDS][ATH12K_CHAN_WIDTH_NUM] = { [NL80211_CHAN_WIDTH_40] = MODE_11BE_EHT40, [NL80211_CHAN_WIDTH_80] = MODE_11BE_EHT80, [NL80211_CHAN_WIDTH_160] = MODE_11BE_EHT160, - [NL80211_CHAN_WIDTH_80P80] = MODE_11BE_EHT80_80, + [NL80211_CHAN_WIDTH_80P80] = MODE_UNKNOWN, [NL80211_CHAN_WIDTH_320] = MODE_11BE_EHT320, }, @@ -521,6 +521,18 @@ ath12k_mac_max_vht_nss(const u16 *vht_mcs_mask) return 1; } +static u32 +ath12k_mac_max_he_nss(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +{ + int nss; + + for (nss = NL80211_HE_NSS_MAX - 1; nss >= 0; nss--) + if (he_mcs_mask[nss]) + return nss + 1; + + return 1; +} + static u8 ath12k_parse_mpdudensity(u8 mpdudensity) { /* From IEEE Std 802.11-2020 defined values for "Minimum MPDU Start Spacing": @@ -602,6 +614,33 @@ ath12k_mac_get_tx_arvif(struct ath12k_link_vif *arvif, return NULL; } +static const u8 *ath12k_mac_get_tx_bssid(struct ath12k_link_vif *arvif) +{ + struct ieee80211_bss_conf *link_conf; + struct ath12k_link_vif *tx_arvif; + struct ath12k *ar = arvif->ar; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, + "unable to access bss link conf for link %u required to retrieve transmitting link conf\n", + arvif->link_id); + return NULL; + } + if (link_conf->vif->type == NL80211_IFTYPE_STATION) { + if (link_conf->nontransmitted) + return link_conf->transmitter_bssid; + } else { + tx_arvif = ath12k_mac_get_tx_arvif(arvif, link_conf); + if (tx_arvif) + return tx_arvif->bssid; + } + + return NULL; +} + struct ieee80211_bss_conf * ath12k_mac_get_link_bss_conf(struct ath12k_link_vif *arvif) { @@ -693,6 +732,9 @@ static void ath12k_get_arvif_iter(void *data, u8 *mac, if (WARN_ON(!arvif)) continue; + if (!arvif->is_created) + continue; + if (arvif->vdev_id == arvif_iter->vdev_id && arvif->ar == arvif_iter->ar) { arvif_iter->arvif = arvif; @@ -1392,7 +1434,7 @@ err: return ret; } -static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) +static int ath12k_mac_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { return 0; } @@ -1454,11 +1496,13 @@ static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, return 0; } -static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_buff *bcn, +static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, + struct ath12k_link_vif *tx_arvif, + struct sk_buff *bcn, u8 bssid_index, bool *nontx_profile_found) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)bcn->data; - const struct element *elem, *nontx, *index, *nie; + const struct element *elem, *nontx, *index, *nie, *ext_cap_ie; const u8 *start, *tail; u16 rem_len; u8 i; @@ -1476,6 +1520,11 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_bu start, rem_len)) arvif->wpaie_present = true; + ext_cap_ie = cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, start, rem_len); + if (ext_cap_ie && ext_cap_ie->datalen >= 11 && + (ext_cap_ie->data[10] & WLAN_EXT_CAPA11_BCN_PROTECT)) + tx_arvif->beacon_prot = true; + /* Return from here for the transmitted profile */ if (!bssid_index) return; @@ -1518,6 +1567,19 @@ static void ath12k_mac_set_arvif_ies(struct ath12k_link_vif *arvif, struct sk_bu if (index->data[0] == bssid_index) { *nontx_profile_found = true; + + /* Check if nontx BSS has beacon protection enabled */ + if (!tx_arvif->beacon_prot) { + ext_cap_ie = + cfg80211_find_elem(WLAN_EID_EXT_CAPABILITY, + nontx->data, + nontx->datalen); + if (ext_cap_ie && ext_cap_ie->datalen >= 11 && + (ext_cap_ie->data[10] & + WLAN_EXT_CAPA11_BCN_PROTECT)) + tx_arvif->beacon_prot = true; + } + if (cfg80211_find_ie(WLAN_EID_RSN, nontx->data, nontx->datalen)) { @@ -1566,11 +1628,11 @@ static int ath12k_mac_setup_bcn_tmpl_ema(struct ath12k_link_vif *arvif, } if (tx_arvif == arvif) - ath12k_mac_set_arvif_ies(arvif, beacons->bcn[0].skb, 0, NULL); + ath12k_mac_set_arvif_ies(arvif, tx_arvif, beacons->bcn[0].skb, 0, NULL); for (i = 0; i < beacons->cnt; i++) { if (tx_arvif != arvif && !nontx_profile_found) - ath12k_mac_set_arvif_ies(arvif, beacons->bcn[i].skb, + ath12k_mac_set_arvif_ies(arvif, tx_arvif, beacons->bcn[i].skb, bssid_index, &nontx_profile_found); @@ -1639,9 +1701,9 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_link_vif *arvif) } if (tx_arvif == arvif) { - ath12k_mac_set_arvif_ies(arvif, bcn, 0, NULL); + ath12k_mac_set_arvif_ies(arvif, tx_arvif, bcn, 0, NULL); } else { - ath12k_mac_set_arvif_ies(arvif, bcn, + ath12k_mac_set_arvif_ies(arvif, tx_arvif, bcn, link_conf->bssid_index, &nontx_profile_found); if (!nontx_profile_found) @@ -1688,8 +1750,6 @@ static void ath12k_control_beaconing(struct ath12k_link_vif *arvif, { struct ath12k_wmi_vdev_up_params params = {}; struct ath12k_vif *ahvif = arvif->ahvif; - struct ieee80211_bss_conf *link_conf; - struct ath12k_link_vif *tx_arvif; struct ath12k *ar = arvif->ar; int ret; @@ -1720,18 +1780,8 @@ static void ath12k_control_beaconing(struct ath12k_link_vif *arvif, params.vdev_id = arvif->vdev_id; params.aid = ahvif->aid; params.bssid = arvif->bssid; - - link_conf = ath12k_mac_get_link_bss_conf(arvif); - if (!link_conf) { - ath12k_warn(ar->ab, - "unable to access bss link conf for link %u required to retrieve transmitting link conf\n", - arvif->link_id); - return; - } - - tx_arvif = ath12k_mac_get_tx_arvif(arvif, link_conf); - if (tx_arvif) { - params.tx_bssid = tx_arvif->bssid; + params.tx_bssid = ath12k_mac_get_tx_bssid(arvif); + if (params.tx_bssid) { params.nontx_profile_idx = info->bssid_index; params.nontx_profile_cnt = 1 << info->bssid_indicator; } @@ -1755,7 +1805,7 @@ static void ath12k_mac_handle_beacon_iter(void *data, u8 *mac, struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_link_vif *arvif = &ahvif->deflink; - if (vif->type != NL80211_IFTYPE_STATION) + if (vif->type != NL80211_IFTYPE_STATION || !arvif->is_created) return; if (!ether_addr_equal(mgmt->bssid, vif->bss_conf.bssid)) @@ -1778,16 +1828,16 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac, u32 *vdev_id = data; struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_link_vif *arvif = &ahvif->deflink; - struct ath12k *ar = arvif->ar; - struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + struct ieee80211_hw *hw; - if (arvif->vdev_id != *vdev_id) + if (!arvif->is_created || arvif->vdev_id != *vdev_id) return; if (!arvif->is_up) return; ieee80211_beacon_loss(vif); + hw = ath12k_ar_to_hw(arvif->ar); /* Firmware doesn't report beacon loss events repeatedly. If AP probe * (done by mac80211) succeeds but beacons do not resume then it @@ -2053,9 +2103,15 @@ static void ath12k_peer_assoc_h_ht(struct ath12k *ar, arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG; } - if (arvif->bitrate_mask.control[band].gi != NL80211_TXRATE_FORCE_LGI) { - if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 | - IEEE80211_HT_CAP_SGI_40)) + /* As firmware handles these two flags (IEEE80211_HT_CAP_SGI_20 + * and IEEE80211_HT_CAP_SGI_40) for enabling SGI, reset both + * flags if guard interval is to force Long GI + */ + if (arvif->bitrate_mask.control[band].gi == NL80211_TXRATE_FORCE_LGI) { + arg->peer_ht_caps &= ~(IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40); + } else { + /* Enable SGI flag if either SGI_20 or SGI_40 is supported */ + if (ht_cap->cap & (IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40)) arg->peer_rate_caps |= WMI_HOST_RC_SGI_FLAG; } @@ -2167,6 +2223,34 @@ ath12k_peer_assoc_h_vht_limit(u16 tx_mcs_set, return tx_mcs_set; } +static u8 ath12k_get_nss_160mhz(struct ath12k *ar, + u8 max_nss) +{ + u8 nss_ratio_info = ar->pdev->cap.nss_ratio_info; + u8 max_sup_nss = 0; + + switch (nss_ratio_info) { + case WMI_NSS_RATIO_1BY2_NSS: + max_sup_nss = max_nss >> 1; + break; + case WMI_NSS_RATIO_3BY4_NSS: + ath12k_warn(ar->ab, "WMI_NSS_RATIO_3BY4_NSS not supported\n"); + break; + case WMI_NSS_RATIO_1_NSS: + max_sup_nss = max_nss; + break; + case WMI_NSS_RATIO_2_NSS: + ath12k_warn(ar->ab, "WMI_NSS_RATIO_2_NSS not supported\n"); + break; + default: + ath12k_warn(ar->ab, "invalid nss ratio received from fw: %d\n", + nss_ratio_info); + break; + } + + return max_sup_nss; +} + static void ath12k_peer_assoc_h_vht(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ath12k_link_sta *arsta, @@ -2178,11 +2262,13 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, struct ieee80211_link_sta *link_sta; struct cfg80211_chan_def def; enum nl80211_band band; - const u16 *vht_mcs_mask; + u16 *vht_mcs_mask; u16 tx_mcs_map; u8 ampdu_factor; u8 max_nss, vht_mcs; - int i; + int i, vht_nss, nss_idx; + bool user_rate_valid = true; + u32 rx_nss, tx_nss, nss_160; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -2235,6 +2321,25 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160) arg->bw_160 = true; + vht_nss = ath12k_mac_max_vht_nss(vht_mcs_mask); + + if (vht_nss > link_sta->rx_nss) { + user_rate_valid = false; + for (nss_idx = link_sta->rx_nss - 1; nss_idx >= 0; nss_idx--) { + if (vht_mcs_mask[nss_idx]) { + user_rate_valid = true; + break; + } + } + } + + if (!user_rate_valid) { + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "Setting vht range MCS value to peer supported nss:%d for peer %pM\n", + link_sta->rx_nss, arsta->addr); + vht_mcs_mask[link_sta->rx_nss - 1] = vht_mcs_mask[vht_nss - 1]; + } + /* Calculate peer NSS capability from VHT capabilities if STA * supports VHT. */ @@ -2268,10 +2373,90 @@ static void ath12k_peer_assoc_h_vht(struct ath12k *ar, /* TODO: Check */ arg->tx_max_mcs_nss = 0xFF; - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", - arsta->addr, arg->peer_max_mpdu, arg->peer_flags); + if (arg->peer_phymode == MODE_11AC_VHT160) { + tx_nss = ath12k_get_nss_160mhz(ar, max_nss); + rx_nss = min(arg->peer_nss, tx_nss); + arg->peer_bw_rxnss_override = ATH12K_BW_NSS_MAP_ENABLE; + + if (!rx_nss) { + ath12k_warn(ar->ab, "invalid max_nss\n"); + return; + } + + nss_160 = u32_encode_bits(rx_nss - 1, ATH12K_PEER_RX_NSS_160MHZ); + arg->peer_bw_rxnss_override |= nss_160; + } + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac vht peer %pM max_mpdu %d flags 0x%x nss_override 0x%x\n", + arsta->addr, arg->peer_max_mpdu, arg->peer_flags, + arg->peer_bw_rxnss_override); +} - /* TODO: rxnss_override */ +static int ath12k_mac_get_max_he_mcs_map(u16 mcs_map, int nss) +{ + switch ((mcs_map >> (2 * nss)) & 0x3) { + case IEEE80211_HE_MCS_SUPPORT_0_7: return BIT(8) - 1; + case IEEE80211_HE_MCS_SUPPORT_0_9: return BIT(10) - 1; + case IEEE80211_HE_MCS_SUPPORT_0_11: return BIT(12) - 1; + } + return 0; +} + +static u16 ath12k_peer_assoc_h_he_limit(u16 tx_mcs_set, + const u16 *he_mcs_limit) +{ + int idx_limit; + int nss; + u16 mcs_map; + u16 mcs; + + for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) { + mcs_map = ath12k_mac_get_max_he_mcs_map(tx_mcs_set, nss) & + he_mcs_limit[nss]; + + if (mcs_map) + idx_limit = fls(mcs_map) - 1; + else + idx_limit = -1; + + switch (idx_limit) { + case 0 ... 7: + mcs = IEEE80211_HE_MCS_SUPPORT_0_7; + break; + case 8: + case 9: + mcs = IEEE80211_HE_MCS_SUPPORT_0_9; + break; + case 10: + case 11: + mcs = IEEE80211_HE_MCS_SUPPORT_0_11; + break; + default: + WARN_ON(1); + fallthrough; + case -1: + mcs = IEEE80211_HE_MCS_NOT_SUPPORTED; + break; + } + + tx_mcs_set &= ~(0x3 << (nss * 2)); + tx_mcs_set |= mcs << (nss * 2); + } + + return tx_mcs_set; +} + +static bool +ath12k_peer_assoc_h_he_masked(const u16 he_mcs_mask[NL80211_HE_NSS_MAX]) +{ + int nss; + + for (nss = 0; nss < NL80211_HE_NSS_MAX; nss++) + if (he_mcs_mask[nss]) + return false; + + return true; } static void ath12k_peer_assoc_h_he(struct ath12k *ar, @@ -2284,18 +2469,29 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_bss_conf *link_conf; struct ieee80211_link_sta *link_sta; + struct cfg80211_chan_def def; int i; u8 ampdu_factor, max_nss; u8 rx_mcs_80 = IEEE80211_HE_MCS_NOT_SUPPORTED; u8 rx_mcs_160 = IEEE80211_HE_MCS_NOT_SUPPORTED; u16 mcs_160_map, mcs_80_map; + u8 link_id = arvif->link_id; bool support_160; - u16 v; + enum nl80211_band band; + u16 *he_mcs_mask; + u8 he_mcs; + u16 he_tx_mcs = 0, v = 0; + int he_nss, nss_idx; + bool user_rate_valid = true; + u32 rx_nss, tx_nss, nss_160; + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, link_id, &def))) + return; link_conf = ath12k_mac_get_link_bss_conf(arvif); if (!link_conf) { ath12k_warn(ar->ab, "unable to access bss link conf in peer assoc he for vif %pM link %u", - vif->addr, arvif->link_id); + vif->addr, link_id); return; } @@ -2310,6 +2506,12 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, if (!he_cap->has_he) return; + band = def.chan->band; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; + + if (ath12k_peer_assoc_h_he_masked(he_mcs_mask)) + return; + arg->he_flag = true; support_160 = !!(he_cap->he_cap_elem.phy_cap_info[0] & @@ -2415,25 +2617,36 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, if (he_cap->he_cap_elem.mac_cap_info[0] & IEEE80211_HE_MAC_CAP0_TWT_REQ) arg->twt_requester = true; - switch (link_sta->bandwidth) { - case IEEE80211_STA_RX_BW_160: - if (he_cap->he_cap_elem.phy_cap_info[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) { - v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80p80); - arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; - - v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80p80); - arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80_80] = v; + he_nss = ath12k_mac_max_he_nss(he_mcs_mask); - arg->peer_he_mcs_count++; + if (he_nss > link_sta->rx_nss) { + user_rate_valid = false; + for (nss_idx = link_sta->rx_nss - 1; nss_idx >= 0; nss_idx--) { + if (he_mcs_mask[nss_idx]) { + user_rate_valid = true; + break; + } } + } + + if (!user_rate_valid) { + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "Setting he range MCS value to peer supported nss:%d for peer %pM\n", + link_sta->rx_nss, arsta->addr); + he_mcs_mask[link_sta->rx_nss - 1] = he_mcs_mask[he_nss - 1]; + } + + switch (link_sta->bandwidth) { + case IEEE80211_STA_RX_BW_160: v = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; - v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_160); + v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_160] = v; arg->peer_he_mcs_count++; + if (!he_tx_mcs) + he_tx_mcs = v; fallthrough; default: @@ -2441,11 +2654,54 @@ static void ath12k_peer_assoc_h_he(struct ath12k *ar, arg->peer_he_rx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; v = le16_to_cpu(he_cap->he_mcs_nss_supp.tx_mcs_80); + v = ath12k_peer_assoc_h_he_limit(v, he_mcs_mask); arg->peer_he_tx_mcs_set[WMI_HECAP_TXRX_MCS_NSS_IDX_80] = v; arg->peer_he_mcs_count++; + if (!he_tx_mcs) + he_tx_mcs = v; break; } + + /* Calculate peer NSS capability from HE capabilities if STA + * supports HE. + */ + for (i = 0, max_nss = 0, he_mcs = 0; i < NL80211_HE_NSS_MAX; i++) { + he_mcs = he_tx_mcs >> (2 * i) & 3; + + /* In case of fixed rates, MCS Range in he_tx_mcs might have + * unsupported range, with he_mcs_mask set, so check either of them + * to find nss. + */ + if (he_mcs != IEEE80211_HE_MCS_NOT_SUPPORTED || + he_mcs_mask[i]) + max_nss = i + 1; + } + + max_nss = min(max_nss, ar->num_tx_chains); + arg->peer_nss = min(link_sta->rx_nss, max_nss); + + if (arg->peer_phymode == MODE_11AX_HE160) { + tx_nss = ath12k_get_nss_160mhz(ar, ar->num_tx_chains); + rx_nss = min(arg->peer_nss, tx_nss); + + arg->peer_nss = min(link_sta->rx_nss, ar->num_rx_chains); + arg->peer_bw_rxnss_override = ATH12K_BW_NSS_MAP_ENABLE; + + if (!rx_nss) { + ath12k_warn(ar->ab, "invalid max_nss\n"); + return; + } + + nss_160 = u32_encode_bits(rx_nss - 1, ATH12K_PEER_RX_NSS_160MHZ); + arg->peer_bw_rxnss_override |= nss_160; + } + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac he peer %pM nss %d mcs cnt %d nss_override 0x%x\n", + arsta->addr, arg->peer_nss, + arg->peer_he_mcs_count, + arg->peer_bw_rxnss_override); } static void ath12k_peer_assoc_h_he_6ghz(struct ath12k *ar, @@ -2686,16 +2942,14 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_vht(struct ath12k *ar, struct ieee80211_link_sta *link_sta) { if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160) { - switch (link_sta->vht_cap.cap & - IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) { - case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: - return MODE_11AC_VHT160; - case IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: - return MODE_11AC_VHT80_80; - default: - /* not sure if this is a valid case? */ + if (link_sta->vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | + IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)) return MODE_11AC_VHT160; - } + + /* Allow STA to connect even if it does not explicitly advertise 160 MHz + * support + */ + return MODE_11AC_VHT160; } if (link_sta->bandwidth == IEEE80211_STA_RX_BW_80) @@ -2717,11 +2971,8 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_he(struct ath12k *ar, if (link_sta->he_cap.he_cap_elem.phy_cap_info[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) return MODE_11AX_HE160; - else if (link_sta->he_cap.he_cap_elem.phy_cap_info[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) - return MODE_11AX_HE80_80; - /* not sure if this is a valid case? */ - return MODE_11AX_HE160; + + return MODE_UNKNOWN; } if (link_sta->bandwidth == IEEE80211_STA_RX_BW_80) @@ -2749,14 +3000,10 @@ static enum wmi_phy_mode ath12k_mac_get_phymode_eht(struct ath12k *ar, IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) return MODE_11BE_EHT160; - if (link_sta->he_cap.he_cap_elem.phy_cap_info[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G) - return MODE_11BE_EHT80_80; - ath12k_warn(ar->ab, "invalid EHT PHY capability info for 160 Mhz: %d\n", link_sta->he_cap.he_cap_elem.phy_cap_info[0]); - return MODE_11BE_EHT160; + return MODE_UNKNOWN; } if (link_sta->bandwidth == IEEE80211_STA_RX_BW_80) @@ -2781,6 +3028,7 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; + const u16 *he_mcs_mask; enum wmi_phy_mode phymode = MODE_UNKNOWN; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -2794,6 +3042,7 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, band = def.chan->band; ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; link_sta = ath12k_mac_get_link_sta(arsta); if (!link_sta) { @@ -2809,7 +3058,8 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, phymode = MODE_11BE_EHT40_2G; else phymode = MODE_11BE_EHT20_2G; - } else if (link_sta->he_cap.has_he) { + } else if (link_sta->he_cap.has_he && + !ath12k_peer_assoc_h_he_masked(he_mcs_mask)) { if (link_sta->bandwidth == IEEE80211_STA_RX_BW_80) phymode = MODE_11AX_HE80_2G; else if (link_sta->bandwidth == IEEE80211_STA_RX_BW_40) @@ -2839,7 +3089,8 @@ static void ath12k_peer_assoc_h_phymode(struct ath12k *ar, /* Check EHT first */ if (link_sta->eht_cap.has_eht) { phymode = ath12k_mac_get_phymode_eht(ar, link_sta); - } else if (link_sta->he_cap.has_he) { + } else if (link_sta->he_cap.has_he && + !ath12k_peer_assoc_h_he_masked(he_mcs_mask)) { phymode = ath12k_mac_get_phymode_he(ar, link_sta); } else if (link_sta->vht_cap.vht_supported && !ath12k_peer_assoc_h_vht_masked(vht_mcs_mask)) { @@ -3142,6 +3393,177 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_link_vif *arv ath12k_smps_map[smps]); } +static int ath12k_mac_set_he_txbf_conf(struct ath12k_link_vif *arvif) +{ + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k *ar = arvif->ar; + u32 param = WMI_VDEV_PARAM_SET_HEMU_MODE; + u32 value = 0; + int ret; + struct ieee80211_bss_conf *link_conf; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in txbf conf\n"); + return -EINVAL; + } + + if (!link_conf->he_support) + return 0; + + if (link_conf->he_su_beamformer) { + value |= u32_encode_bits(HE_SU_BFER_ENABLE, HE_MODE_SU_TX_BFER); + if (link_conf->he_mu_beamformer && + ahvif->vdev_type == WMI_VDEV_TYPE_AP) + value |= u32_encode_bits(HE_MU_BFER_ENABLE, HE_MODE_MU_TX_BFER); + } + + if (ahvif->vif->type != NL80211_IFTYPE_MESH_POINT) { + value |= u32_encode_bits(HE_DL_MUOFDMA_ENABLE, HE_MODE_DL_OFDMA) | + u32_encode_bits(HE_UL_MUOFDMA_ENABLE, HE_MODE_UL_OFDMA); + + if (link_conf->he_full_ul_mumimo) + value |= u32_encode_bits(HE_UL_MUMIMO_ENABLE, HE_MODE_UL_MUMIMO); + + if (link_conf->he_su_beamformee) + value |= u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE); + } + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, value); + if (ret) { + ath12k_warn(ar->ab, "failed to set vdev %d HE MU mode: %d\n", + arvif->vdev_id, ret); + return ret; + } + + param = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; + value = u32_encode_bits(HE_VHT_SOUNDING_MODE_ENABLE, HE_VHT_SOUNDING_MODE) | + u32_encode_bits(HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE, + HE_TRIG_NONTRIG_SOUNDING_MODE); + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + param, value); + if (ret) { + ath12k_warn(ar->ab, "failed to set vdev %d sounding mode: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath12k_mac_vif_recalc_sta_he_txbf(struct ath12k *ar, + struct ath12k_link_vif *arvif, + struct ieee80211_sta_he_cap *he_cap, + int *hemode) +{ + struct ieee80211_vif *vif = arvif->ahvif->vif; + struct ieee80211_he_cap_elem he_cap_elem = {}; + struct ieee80211_sta_he_cap *cap_band; + struct cfg80211_chan_def def; + u8 link_id = arvif->link_id; + struct ieee80211_bss_conf *link_conf; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in recalc txbf conf\n"); + return -EINVAL; + } + + if (!link_conf->he_support) + return 0; + + if (vif->type != NL80211_IFTYPE_STATION) + return -EINVAL; + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, link_id, &def))) + return -EINVAL; + + if (def.chan->band == NL80211_BAND_2GHZ) + cap_band = &ar->mac.iftype[NL80211_BAND_2GHZ][vif->type].he_cap; + else + cap_band = &ar->mac.iftype[NL80211_BAND_5GHZ][vif->type].he_cap; + + memcpy(&he_cap_elem, &cap_band->he_cap_elem, sizeof(he_cap_elem)); + + *hemode = 0; + if (HECAP_PHY_SUBFME_GET(he_cap_elem.phy_cap_info)) { + if (HECAP_PHY_SUBFMR_GET(he_cap->he_cap_elem.phy_cap_info)) + *hemode |= u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE); + if (HECAP_PHY_MUBFMR_GET(he_cap->he_cap_elem.phy_cap_info)) + *hemode |= u32_encode_bits(HE_MU_BFEE_ENABLE, HE_MODE_MU_TX_BFEE); + } + + if (vif->type != NL80211_IFTYPE_MESH_POINT) { + *hemode |= u32_encode_bits(HE_DL_MUOFDMA_ENABLE, HE_MODE_DL_OFDMA) | + u32_encode_bits(HE_UL_MUOFDMA_ENABLE, HE_MODE_UL_OFDMA); + + if (HECAP_PHY_ULMUMIMO_GET(he_cap_elem.phy_cap_info)) + if (HECAP_PHY_ULMUMIMO_GET(he_cap->he_cap_elem.phy_cap_info)) + *hemode |= u32_encode_bits(HE_UL_MUMIMO_ENABLE, + HE_MODE_UL_MUMIMO); + + if (u32_get_bits(*hemode, HE_MODE_MU_TX_BFEE)) + *hemode |= u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE); + + if (u32_get_bits(*hemode, HE_MODE_MU_TX_BFER)) + *hemode |= u32_encode_bits(HE_SU_BFER_ENABLE, HE_MODE_SU_TX_BFER); + } + + return 0; +} + +static int ath12k_mac_set_eht_txbf_conf(struct ath12k_link_vif *arvif) +{ + struct ath12k_vif *ahvif = arvif->ahvif; + struct ath12k *ar = arvif->ar; + u32 param = WMI_VDEV_PARAM_SET_EHT_MU_MODE; + u32 value = 0; + int ret; + struct ieee80211_bss_conf *link_conf; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in eht txbf conf\n"); + return -ENOENT; + } + + if (!link_conf->eht_support) + return 0; + + if (link_conf->eht_su_beamformer) { + value |= u32_encode_bits(EHT_SU_BFER_ENABLE, EHT_MODE_SU_TX_BFER); + if (link_conf->eht_mu_beamformer && + ahvif->vdev_type == WMI_VDEV_TYPE_AP) + value |= u32_encode_bits(EHT_MU_BFER_ENABLE, + EHT_MODE_MU_TX_BFER) | + u32_encode_bits(EHT_DL_MUOFDMA_ENABLE, + EHT_MODE_DL_OFDMA_MUMIMO) | + u32_encode_bits(EHT_UL_MUOFDMA_ENABLE, + EHT_MODE_UL_OFDMA_MUMIMO); + } + + if (ahvif->vif->type != NL80211_IFTYPE_MESH_POINT) { + value |= u32_encode_bits(EHT_DL_MUOFDMA_ENABLE, EHT_MODE_DL_OFDMA) | + u32_encode_bits(EHT_UL_MUOFDMA_ENABLE, EHT_MODE_UL_OFDMA); + + if (link_conf->eht_80mhz_full_bw_ul_mumimo) + value |= u32_encode_bits(EHT_UL_MUMIMO_ENABLE, EHT_MODE_MUMIMO); + + if (link_conf->eht_su_beamformee) + value |= u32_encode_bits(EHT_SU_BFEE_ENABLE, + EHT_MODE_SU_TX_BFEE); + } + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param, value); + if (ret) { + ath12k_warn(ar->ab, "failed to set vdev %d EHT MU mode: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar, struct ieee80211_link_sta *link_sta) { @@ -3187,6 +3609,7 @@ static void ath12k_bss_assoc(struct ath12k *ar, struct ath12k_sta *ahsta; struct ath12k_peer *peer; bool is_auth = false; + u32 hemode = 0; int ret; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -3230,8 +3653,27 @@ static void ath12k_bss_assoc(struct ath12k *ar, ath12k_peer_assoc_prepare(ar, arvif, arsta, peer_arg, false); + /* link_sta->he_cap must be protected by rcu_read_lock */ + ret = ath12k_mac_vif_recalc_sta_he_txbf(ar, arvif, &link_sta->he_cap, &hemode); + if (ret) { + ath12k_warn(ar->ab, "failed to recalc he txbf for vdev %i on bss %pM: %d\n", + arvif->vdev_id, bss_conf->bssid, ret); + rcu_read_unlock(); + return; + } + rcu_read_unlock(); + /* keep this before ath12k_wmi_send_peer_assoc_cmd() */ + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_SET_HEMU_MODE, hemode); + if (ret) { + ath12k_warn(ar->ab, "failed to submit vdev param txbf 0x%x: %d\n", + hemode, ret); + return; + } + + peer_arg->is_assoc = true; ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (ret) { ath12k_warn(ar->ab, "failed to run peer assoc for %pM vdev %i: %d\n", @@ -3261,6 +3703,11 @@ static void ath12k_bss_assoc(struct ath12k *ar, params.vdev_id = arvif->vdev_id; params.aid = ahvif->aid; params.bssid = arvif->bssid; + params.tx_bssid = ath12k_mac_get_tx_bssid(arvif); + if (params.tx_bssid) { + params.nontx_profile_idx = bss_conf->bssid_index; + params.nontx_profile_cnt = 1 << bss_conf->bssid_indicator; + } ret = ath12k_wmi_vdev_up(ar, ¶ms); if (ret) { ath12k_warn(ar->ab, "failed to set vdev %d up: %d\n", @@ -3431,12 +3878,17 @@ static void ath12k_mac_init_arvif(struct ath12k_vif *ahvif, INIT_DELAYED_WORK(&arvif->connection_loss_work, ath12k_mac_vif_sta_connection_loss_work); + arvif->num_stations = 0; + for (i = 0; i < ARRAY_SIZE(arvif->bitrate_mask.control); i++) { arvif->bitrate_mask.control[i].legacy = 0xffffffff; + arvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI; memset(arvif->bitrate_mask.control[i].ht_mcs, 0xff, sizeof(arvif->bitrate_mask.control[i].ht_mcs)); memset(arvif->bitrate_mask.control[i].vht_mcs, 0xff, sizeof(arvif->bitrate_mask.control[i].vht_mcs)); + memset(arvif->bitrate_mask.control[i].he_mcs, 0xff, + sizeof(arvif->bitrate_mask.control[i].he_mcs)); } /* Handle MLO related assignments */ @@ -3496,7 +3948,7 @@ static struct ath12k_link_vif *ath12k_mac_assign_link_vif(struct ath12k_hw *ah, /* If this is the first link arvif being created for an ML VIF * use the preallocated deflink memory except for scan arvifs */ - if (!ahvif->links_map && link_id != ATH12K_DEFAULT_SCAN_LINK) { + if (!ahvif->links_map && link_id < ATH12K_FIRST_SCAN_LINK) { arvif = &ahvif->deflink; if (vif->type == NL80211_IFTYPE_STATION) @@ -3752,13 +4204,13 @@ static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif) psmode, arvif->vdev_id, ret); } -static bool ath12k_mac_supports_station_tpc(struct ath12k *ar, - struct ath12k_vif *ahvif, - const struct cfg80211_chan_def *chandef) +static bool ath12k_mac_supports_tpc(struct ath12k *ar, struct ath12k_vif *ahvif, + const struct cfg80211_chan_def *chandef) { return ath12k_wmi_supports_6ghz_cc_ext(ar) && test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map) && - ahvif->vdev_type == WMI_VDEV_TYPE_STA && + (ahvif->vdev_type == WMI_VDEV_TYPE_STA || + ahvif->vdev_type == WMI_VDEV_TYPE_AP) && ahvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE && chandef->chan && chandef->chan->band == NL80211_BAND_6GHZ; @@ -3850,6 +4302,19 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, ether_addr_copy(arvif->bssid, info->bssid); if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (info->enable_beacon) { + ret = ath12k_mac_set_he_txbf_conf(arvif); + if (ret) + ath12k_warn(ar->ab, + "failed to set HE TXBF config for vdev: %d\n", + arvif->vdev_id); + + ret = ath12k_mac_set_eht_txbf_conf(arvif); + if (ret) + ath12k_warn(ar->ab, + "failed to set EHT TXBF config for vdev: %d\n", + arvif->vdev_id); + } ath12k_control_beaconing(arvif, info); if (arvif->is_up && info->he_support && @@ -4149,8 +4614,9 @@ ath12k_mac_select_scan_device(struct ieee80211_hw *hw, band = NL80211_BAND_6GHZ; for_each_ar(ah, ar, i) { - /* TODO 5 GHz low high split changes */ - if (ar->mac.sbands[band].channels) + if (ar->mac.sbands[band].channels && + center_freq >= KHZ_TO_MHZ(ar->freq_range.start_freq) && + center_freq <= KHZ_TO_MHZ(ar->freq_range.end_freq)) return ar; } @@ -4274,6 +4740,23 @@ static void ath12k_scan_timeout_work(struct work_struct *work) wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy); } +static void ath12k_mac_scan_send_complete(struct ath12k *ar, + struct cfg80211_scan_info *info) +{ + struct ath12k_hw *ah = ar->ah; + struct ath12k *partner_ar; + int i; + + lockdep_assert_wiphy(ah->hw->wiphy); + + for_each_ar(ah, partner_ar, i) + if (partner_ar != ar && + partner_ar->scan.state == ATH12K_SCAN_RUNNING) + return; + + ieee80211_scan_completed(ah->hw, info); +} + static void ath12k_scan_vdev_clean_work(struct wiphy *wiphy, struct wiphy_work *work) { struct ath12k *ar = container_of(work, struct ath12k, @@ -4312,7 +4795,7 @@ work_complete: ATH12K_SCAN_STARTING)), }; - ieee80211_scan_completed(ar->ah->hw, &info); + ath12k_mac_scan_send_complete(ar, &info); } ar->scan.state = ATH12K_SCAN_IDLE; @@ -4488,11 +4971,12 @@ ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar) struct ath12k_link_vif *arvif; struct ath12k_hw *ah = ahvif->ah; unsigned long links = ahvif->links_map; + unsigned long scan_links_map; u8 link_id; lockdep_assert_wiphy(ah->hw->wiphy); - for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + for_each_set_bit(link_id, &links, ATH12K_NUM_MAX_LINKS) { arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[link_id]); if (!arvif || !arvif->is_created) @@ -4502,18 +4986,30 @@ ath12k_mac_find_link_id_by_ar(struct ath12k_vif *ahvif, struct ath12k *ar) return link_id; } - /* input ar is not assigned to any of the links of ML VIF, use scan - * link (15) for scan vdev creation. + /* input ar is not assigned to any of the links of ML VIF, use next + * available scan link for scan vdev creation. There are cases where + * single scan req needs to be split in driver and initiate separate + * scan requests to firmware based on device. */ - return ATH12K_DEFAULT_SCAN_LINK; + + /* Unset all non-scan links (0-14) of scan_links_map so that ffs() will + * choose an available link among scan links (i.e link id >= 15) + */ + scan_links_map = ~ahvif->links_map & ATH12K_SCAN_LINKS_MASK; + if (scan_links_map) + return __ffs(scan_links_map); + + return ATH12K_FIRST_SCAN_LINK; } -static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_scan_request *hw_req) +static int ath12k_mac_initiate_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req, + int n_channels, + struct ieee80211_channel **chan_list, + struct ath12k *ar) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); - struct ath12k *ar; struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); struct ath12k_link_vif *arvif; struct cfg80211_scan_request *req = &hw_req->req; @@ -4527,18 +5023,18 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, arvif = &ahvif->deflink; - /* Since the targeted scan device could depend on the frequency - * requested in the hw_req, select the corresponding radio - */ - ar = ath12k_mac_select_scan_device(hw, vif, hw_req->req.channels[0]->center_freq); - if (!ar) - return -EINVAL; - /* check if any of the links of ML VIF is already started on * radio(ar) corresponding to given scan frequency and use it, - * if not use scan link (link 15) for scan purpose. + * if not use scan link (link id >= 15) for scan purpose. */ link_id = ath12k_mac_find_link_id_by_ar(ahvif, ar); + /* All scan links are occupied. ideally this shouldn't happen as + * mac80211 won't schedule scan for same band until ongoing scan is + * completed, don't try to exceed max links just in case if it happens. + */ + if (link_id >= ATH12K_NUM_MAX_LINKS) + return -EBUSY; + arvif = ath12k_mac_assign_link_vif(ah, vif, link_id); ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac link ID %d selected for scan", @@ -4629,8 +5125,8 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, arg->scan_f_passive = 1; } - if (req->n_channels) { - arg->num_chan = req->n_channels; + if (n_channels) { + arg->num_chan = n_channels; arg->chan_list = kcalloc(arg->num_chan, sizeof(*arg->chan_list), GFP_KERNEL); if (!arg->chan_list) { @@ -4639,7 +5135,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, } for (i = 0; i < arg->num_chan; i++) - arg->chan_list[i] = req->channels[i]->center_freq; + arg->chan_list[i] = chan_list[i]->center_freq; } ret = ath12k_start_scan(ar, arg); @@ -4658,13 +5154,6 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac scan started"); - /* As per cfg80211/mac80211 scan design, it allows only one - * scan at a time. Hence last_scan link id is used for - * tracking the link id on which the scan is been done on - * this vif. - */ - ahvif->last_scan_link = arvif->link_id; - /* Add a margin to account for event/command processing */ ieee80211_queue_delayed_work(ath12k_ar_to_hw(ar), &ar->scan.timeout, msecs_to_jiffies(arg->max_scan_time + @@ -4685,25 +5174,108 @@ exit: return ret; } +static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_scan_request *hw_req) +{ + struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); + struct ieee80211_channel **chan_list, *chan; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + unsigned long links_map, link_id; + struct ath12k_link_vif *arvif; + struct ath12k *ar, *scan_ar; + int i, j, ret = 0; + + lockdep_assert_wiphy(hw->wiphy); + + chan_list = kcalloc(hw_req->req.n_channels, sizeof(*chan_list), GFP_KERNEL); + if (!chan_list) + return -ENOMEM; + + /* There could be channels that belong to multiple underlying radio + * in same scan request as mac80211 sees it as single band. In that + * case split the hw_req based on frequency range and schedule scans to + * corresponding radio. + */ + for_each_ar(ah, ar, i) { + int n_chans = 0; + + for (j = 0; j < hw_req->req.n_channels; j++) { + chan = hw_req->req.channels[j]; + scan_ar = ath12k_mac_select_scan_device(hw, vif, + chan->center_freq); + if (!scan_ar) { + ath12k_hw_warn(ah, "unable to select scan device for freq %d\n", + chan->center_freq); + ret = -EINVAL; + goto abort; + } + if (ar != scan_ar) + continue; + + chan_list[n_chans++] = chan; + } + if (n_chans) { + ret = ath12k_mac_initiate_hw_scan(hw, vif, hw_req, n_chans, + chan_list, ar); + if (ret) + goto abort; + } + } +abort: + /* If any of the parallel scans initiated fails, abort all and + * remove the scan interfaces created. Return complete scan + * failure as mac80211 assumes this as single scan request. + */ + if (ret) { + ath12k_hw_warn(ah, "Scan failed %d , cleanup all scan vdevs\n", ret); + links_map = ahvif->links_map; + for_each_set_bit(link_id, &links_map, ATH12K_NUM_MAX_LINKS) { + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif) + continue; + + ar = arvif->ar; + if (ar->scan.arvif == arvif) { + wiphy_work_cancel(hw->wiphy, &ar->scan.vdev_clean_wk); + spin_lock_bh(&ar->data_lock); + ar->scan.arvif = NULL; + ar->scan.state = ATH12K_SCAN_IDLE; + ar->scan_channel = NULL; + ar->scan.roc_freq = 0; + spin_unlock_bh(&ar->data_lock); + } + if (link_id >= ATH12K_FIRST_SCAN_LINK) { + ath12k_mac_remove_link_interface(hw, arvif); + ath12k_mac_unassign_link_vif(arvif); + } + } + } + kfree(chan_list); + return ret; +} + static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); - u16 link_id = ahvif->last_scan_link; + unsigned long link_id, links_map = ahvif->links_map; struct ath12k_link_vif *arvif; struct ath12k *ar; lockdep_assert_wiphy(hw->wiphy); - arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); - if (!arvif || arvif->is_started) - return; + for_each_set_bit(link_id, &links_map, ATH12K_NUM_MAX_LINKS) { + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || arvif->is_started) + continue; - ar = arvif->ar; + ar = arvif->ar; - ath12k_scan_abort(ar); + ath12k_scan_abort(ar); - cancel_delayed_work_sync(&ar->scan.timeout); + cancel_delayed_work_sync(&ar->scan.timeout); + } } static int ath12k_install_key(struct ath12k_link_vif *arvif, @@ -4719,14 +5291,13 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif, .key_len = key->keylen, .key_data = key->key, .key_flags = flags, + .ieee80211_key_cipher = key->cipher, .macaddr = macaddr, }; struct ath12k_vif *ahvif = arvif->ahvif; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - reinit_completion(&ar->install_key_done); - if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) return 0; @@ -4735,7 +5306,7 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif, /* arg.key_cipher = WMI_CIPHER_NONE; */ arg.key_len = 0; arg.key_data = NULL; - goto install; + goto check_order; } switch (key->cipher) { @@ -4754,6 +5325,16 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif, arg.key_cipher = WMI_CIPHER_AES_GCM; key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT; break; + case WLAN_CIPHER_SUITE_AES_CMAC: + arg.key_cipher = WMI_CIPHER_AES_CMAC; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + arg.key_cipher = WMI_CIPHER_AES_GMAC; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + arg.key_cipher = WMI_CIPHER_AES_CMAC; + break; default: ath12k_warn(ar->ab, "cipher %d is not supported\n", key->cipher); return -EOPNOTSUPP; @@ -4763,19 +5344,82 @@ static int ath12k_install_key(struct ath12k_link_vif *arvif, key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV | IEEE80211_KEY_FLAG_RESERVE_TAILROOM; +check_order: + if (ahvif->vdev_type == WMI_VDEV_TYPE_STA && + arg.key_flags == WMI_KEY_GROUP) { + if (cmd == SET_KEY) { + if (arvif->pairwise_key_done) { + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "vdev %u pairwise key done, go install group key\n", + arg.vdev_id); + goto install; + } else { + /* WCN7850 firmware requires pairwise key to be installed + * before group key. In case group key comes first, cache + * it and return. Will revisit it once pairwise key gets + * installed. + */ + arvif->group_key = arg; + arvif->group_key_valid = true; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "vdev %u group key before pairwise key, cache and skip\n", + arg.vdev_id); + + ret = 0; + goto out; + } + } else { + arvif->group_key_valid = false; + } + } + install: - ret = ath12k_wmi_vdev_install_key(arvif->ar, &arg); + reinit_completion(&ar->install_key_done); + ret = ath12k_wmi_vdev_install_key(arvif->ar, &arg); if (ret) return ret; if (!wait_for_completion_timeout(&ar->install_key_done, 1 * HZ)) return -ETIMEDOUT; - if (ether_addr_equal(macaddr, arvif->bssid)) - ahvif->key_cipher = key->cipher; + if (ether_addr_equal(arg.macaddr, arvif->bssid)) + ahvif->key_cipher = arg.ieee80211_key_cipher; + + if (ar->install_key_status) { + ret = -EINVAL; + goto out; + } + + if (ahvif->vdev_type == WMI_VDEV_TYPE_STA && + arg.key_flags == WMI_KEY_PAIRWISE) { + if (cmd == SET_KEY) { + arvif->pairwise_key_done = true; + if (arvif->group_key_valid) { + /* Install cached GTK */ + arvif->group_key_valid = false; + arg = arvif->group_key; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "vdev %u pairwise key done, group key ready, go install\n", + arg.vdev_id); + goto install; + } + } else { + arvif->pairwise_key_done = false; + } + } + +out: + if (ret) { + /* In case of failure userspace may not do DISABLE_KEY + * but triggers re-connection directly, so manually reset + * status here. + */ + arvif->group_key_valid = false; + arvif->pairwise_key_done = false; + } - return ar->install_key_status ? -EINVAL : 0; + return ret; } static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif, @@ -4869,9 +5513,9 @@ static int ath12k_mac_set_key(struct ath12k *ar, enum set_key_cmd cmd, } if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) - flags |= WMI_KEY_PAIRWISE; + flags = WMI_KEY_PAIRWISE; else - flags |= WMI_KEY_GROUP; + flags = WMI_KEY_GROUP; ret = ath12k_install_key(arvif, key, cmd, peer_addr, flags); if (ret) { @@ -4985,13 +5629,9 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, lockdep_assert_wiphy(hw->wiphy); - /* BIP needs to be done in software */ - if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC || - key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 || - key->cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 || - key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) { + /* IGTK needs to be done in host software */ + if (key->keyidx == 4 || key->keyidx == 5) return 1; - } if (key->keyidx > WMI_MAX_KEY_INDEX) return -ENOSPC; @@ -5079,6 +5719,20 @@ ath12k_mac_bitrate_mask_num_vht_rates(struct ath12k *ar, } static int +ath12k_mac_bitrate_mask_num_he_rates(struct ath12k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int num_rates = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) + num_rates += hweight16(mask->control[band].he_mcs[i]); + + return num_rates; +} + +static int ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif, struct ath12k_link_sta *arsta, const struct cfg80211_bitrate_mask *mask, @@ -5124,6 +5778,60 @@ ath12k_mac_set_peer_vht_fixed_rate(struct ath12k_link_vif *arvif, return ret; } +static int +ath12k_mac_set_peer_he_fixed_rate(struct ath12k_link_vif *arvif, + struct ath12k_link_sta *arsta, + const struct cfg80211_bitrate_mask *mask, + enum nl80211_band band) +{ + struct ath12k *ar = arvif->ar; + u8 he_rate, nss; + u32 rate_code; + int ret, i; + struct ath12k_sta *ahsta = arsta->ahsta; + struct ieee80211_sta *sta; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + sta = ath12k_ahsta_to_sta(ahsta); + nss = 0; + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { + if (hweight16(mask->control[band].he_mcs[i]) == 1) { + nss = i + 1; + he_rate = ffs(mask->control[band].he_mcs[i]) - 1; + } + } + + if (!nss) { + ath12k_warn(ar->ab, "No single HE Fixed rate found to set for %pM", + arsta->addr); + return -EINVAL; + } + + /* Avoid updating invalid nss as fixed rate*/ + if (nss > sta->deflink.rx_nss) + return -EINVAL; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "Setting Fixed HE Rate for peer %pM. Device will not switch to any other selected rates", + arsta->addr); + + rate_code = ATH12K_HW_RATE_CODE(he_rate, nss - 1, + WMI_RATE_PREAMBLE_HE); + + ret = ath12k_wmi_set_peer_param(ar, arsta->addr, + arvif->vdev_id, + WMI_PEER_PARAM_FIXED_RATE, + rate_code); + if (ret) + ath12k_warn(ar->ab, + "failed to update STA %pM Fixed Rate %d: %d\n", + arsta->addr, rate_code, ret); + + return ret; +} + static int ath12k_mac_station_assoc(struct ath12k *ar, struct ath12k_link_vif *arvif, struct ath12k_link_sta *arsta, @@ -5136,7 +5844,7 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, struct cfg80211_chan_def def; enum nl80211_band band; struct cfg80211_bitrate_mask *mask; - u8 num_vht_rates; + u8 num_vht_rates, num_he_rates; u8 link_id = arvif->link_id; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -5162,6 +5870,8 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, "invalid peer NSS %d\n", peer_arg->peer_nss); return -EINVAL; } + + peer_arg->is_assoc = true; ret = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (ret) { ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", @@ -5176,9 +5886,10 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, } num_vht_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask); + num_he_rates = ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask); - /* If single VHT rate is configured (by set_bitrate_mask()), - * peer_assoc will disable VHT. This is now enabled by a peer specific + /* If single VHT/HE rate is configured (by set_bitrate_mask()), + * peer_assoc will disable VHT/HE. This is now enabled by a peer specific * fixed param. * Note that all other rates and NSS will be disabled for this peer. */ @@ -5194,8 +5905,9 @@ static int ath12k_mac_station_assoc(struct ath12k *ar, spin_unlock_bh(&ar->data_lock); if (link_sta->vht_cap.vht_supported && num_vht_rates == 1) { - ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, - band); + ret = ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, band); + } else if (link_sta->he_cap.has_he && num_he_rates == 1) { + ret = ath12k_mac_set_peer_he_fixed_rate(arvif, arsta, mask, band); if (ret) return ret; } @@ -5259,8 +5971,9 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; - u32 changed, bw, nss, smps, bw_prev; - int err, num_vht_rates; + const u16 *he_mcs_mask; + u32 changed, bw, nss, mac_nss, smps, bw_prev; + int err, num_vht_rates, num_he_rates; const struct cfg80211_bitrate_mask *mask; enum wmi_phy_mode peer_phymode; struct ath12k_link_sta *arsta; @@ -5280,6 +5993,7 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) band = def.chan->band; ht_mcs_mask = arvif->bitrate_mask.control[band].ht_mcs; vht_mcs_mask = arvif->bitrate_mask.control[band].vht_mcs; + he_mcs_mask = arvif->bitrate_mask.control[band].he_mcs; spin_lock_bh(&ar->data_lock); @@ -5294,8 +6008,10 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) spin_unlock_bh(&ar->data_lock); nss = max_t(u32, 1, nss); - nss = min(nss, max(ath12k_mac_max_ht_nss(ht_mcs_mask), - ath12k_mac_max_vht_nss(vht_mcs_mask))); + mac_nss = max3(ath12k_mac_max_ht_nss(ht_mcs_mask), + ath12k_mac_max_vht_nss(vht_mcs_mask), + ath12k_mac_max_he_nss(he_mcs_mask)); + nss = min(nss, mac_nss); struct ath12k_wmi_peer_assoc_arg *peer_arg __free(kfree) = kzalloc(sizeof(*peer_arg), GFP_KERNEL); @@ -5378,6 +6094,8 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) mask = &arvif->bitrate_mask; num_vht_rates = ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask); + num_he_rates = ath12k_mac_bitrate_mask_num_he_rates(ar, band, + mask); /* Peer_assoc_prepare will reject vht rates in * bitrate_mask if its not available in range format and @@ -5400,14 +6118,28 @@ static void ath12k_sta_rc_update_wk(struct wiphy *wiphy, struct wiphy_work *wk) if (link_sta->vht_cap.vht_supported && num_vht_rates == 1) { ath12k_mac_set_peer_vht_fixed_rate(arvif, arsta, mask, band); + } else if (link_sta->he_cap.has_he && num_he_rates == 1) { + ath12k_mac_set_peer_he_fixed_rate(arvif, arsta, mask, band); } else { - /* If the peer is non-VHT or no fixed VHT rate + /* If the peer is non-VHT/HE or no fixed VHT/HE rate * is provided in the new bitrate mask we set the - * other rates using peer_assoc command. + * other rates using peer_assoc command. Also clear + * the peer fixed rate settings as it has higher proprity + * than peer assoc */ + err = ath12k_wmi_set_peer_param(ar, arsta->addr, + arvif->vdev_id, + WMI_PEER_PARAM_FIXED_RATE, + WMI_FIXED_RATE_NONE); + if (err) + ath12k_warn(ar->ab, + "failed to disable peer fixed rate for STA %pM ret %d\n", + arsta->addr, err); + ath12k_peer_assoc_prepare(ar, arvif, arsta, peer_arg, true); + peer_arg->is_assoc = false; err = ath12k_wmi_send_peer_assoc_cmd(ar, peer_arg); if (err) ath12k_warn(ar->ab, "failed to run peer assoc for STA %pM vdev %i: %d\n", @@ -5464,6 +6196,11 @@ static int ath12k_mac_inc_num_stations(struct ath12k_link_vif *arvif, return -ENOBUFS; ar->num_stations++; + arvif->num_stations++; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac station %pM connected to vdev %u num_stations %u\n", + arsta->addr, arvif->vdev_id, arvif->num_stations); return 0; } @@ -5480,6 +6217,17 @@ static void ath12k_mac_dec_num_stations(struct ath12k_link_vif *arvif, return; ar->num_stations--; + + if (arvif->num_stations) { + arvif->num_stations--; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac station %pM disconnected from vdev %u num_stations %u\n", + arsta->addr, arvif->vdev_id, arvif->num_stations); + } else { + ath12k_warn(ar->ab, + "mac station %pM disconnect for vdev %u without any connected station\n", + arsta->addr, arvif->vdev_id); + } } static void ath12k_mac_station_post_remove(struct ath12k *ar, @@ -5627,7 +6375,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, struct ath12k_base *ab = ar->ab; struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); struct ieee80211_sta *sta = ath12k_ahsta_to_sta(arsta->ahsta); - struct ath12k_wmi_peer_create_arg peer_param = {0}; + struct ath12k_wmi_peer_create_arg peer_param = {}; int ret; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); @@ -5971,7 +6719,7 @@ static int ath12k_mac_mlo_sta_set_link_active(struct ath12k_base *ab, u8 *mlo_inactive_vdev_lst, u8 num_mlo_inactive_vdev) { - struct wmi_mlo_link_set_active_arg param = {0}; + struct wmi_mlo_link_set_active_arg param = {}; u32 entry_idx, entry_offset, vdev_idx; u8 vdev_id; @@ -6033,8 +6781,8 @@ static int ath12k_mac_mlo_sta_update_link_active(struct ath12k_base *ab, struct ieee80211_hw *hw, struct ath12k_vif *ahvif) { - u8 mlo_vdev_id_lst[IEEE80211_MLD_MAX_NUM_LINKS] = {0}; - u32 mlo_freq_list[IEEE80211_MLD_MAX_NUM_LINKS] = {0}; + u8 mlo_vdev_id_lst[IEEE80211_MLD_MAX_NUM_LINKS] = {}; + u32 mlo_freq_list[IEEE80211_MLD_MAX_NUM_LINKS] = {}; unsigned long links = ahvif->links_map; enum wmi_mlo_link_force_reason reason; struct ieee80211_chanctx_conf *conf; @@ -6771,7 +7519,7 @@ static struct ieee80211_sta_ht_cap ath12k_create_ht_cap(struct ath12k *ar, u32 ar_ht_cap, u32 rate_cap_rx_chainmask) { int i; - struct ieee80211_sta_ht_cap ht_cap = {0}; + struct ieee80211_sta_ht_cap ht_cap = {}; u32 ar_vht_cap = ar->pdev->cap.vht_cap; if (!(ar_ht_cap & WMI_HT_CAP_ENABLED)) @@ -6927,7 +7675,7 @@ static struct ieee80211_sta_vht_cap ath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, u32 rate_cap_rx_chainmask) { - struct ieee80211_sta_vht_cap vht_cap = {0}; + struct ieee80211_sta_vht_cap vht_cap = {}; u16 txmcs_map, rxmcs_map; int i; @@ -6936,10 +7684,8 @@ ath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, ath12k_set_vht_txbf_cap(ar, &vht_cap.cap); - /* TODO: Enable back VHT160 mode once association issues are fixed */ - /* Disabling VHT160 and VHT80+80 modes */ - vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK; - vht_cap.cap &= ~IEEE80211_VHT_CAP_SHORT_GI_160; + /* 80P80 is not supported */ + vht_cap.cap &= ~IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; rxmcs_map = 0; txmcs_map = 0; @@ -6961,6 +7707,12 @@ ath12k_create_vht_cap(struct ath12k *ar, u32 rate_cap_tx_chainmask, vht_cap.vht_mcs.rx_mcs_map = cpu_to_le16(rxmcs_map); vht_cap.vht_mcs.tx_mcs_map = cpu_to_le16(txmcs_map); + /* Check if the HW supports 1:1 NSS ratio and reset + * EXT NSS BW Support field to 0 to indicate 1:1 ratio + */ + if (ar->pdev->cap.nss_ratio_info == WMI_NSS_RATIO_1_NSS) + vht_cap.cap &= ~IEEE80211_VHT_CAP_EXT_NSS_BW_MASK; + return vht_cap; } @@ -7138,12 +7890,55 @@ static __le16 ath12k_mac_setup_he_6ghz_cap(struct ath12k_pdev_cap *pcap, return cpu_to_le16(bcap->he_6ghz_capa); } -static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, +static void ath12k_mac_set_hemcsmap(struct ath12k *ar, + struct ath12k_pdev_cap *cap, + struct ieee80211_sta_he_cap *he_cap) +{ + struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp; + u8 maxtxnss_160 = ath12k_get_nss_160mhz(ar, ar->num_tx_chains); + u8 maxrxnss_160 = ath12k_get_nss_160mhz(ar, ar->num_rx_chains); + u16 txmcs_map_160 = 0, rxmcs_map_160 = 0; + u16 txmcs_map = 0, rxmcs_map = 0; + u32 i; + + for (i = 0; i < 8; i++) { + if (i < ar->num_tx_chains && + (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + txmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + txmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + + if (i < ar->num_rx_chains && + (ar->cfg_rx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + rxmcs_map |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + rxmcs_map |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + + if (i < maxtxnss_160 && + (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + txmcs_map_160 |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + txmcs_map_160 |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + + if (i < maxrxnss_160 && + (ar->cfg_tx_chainmask >> cap->tx_chain_mask_shift) & BIT(i)) + rxmcs_map_160 |= IEEE80211_HE_MCS_SUPPORT_0_11 << (i * 2); + else + rxmcs_map_160 |= IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2); + } + + mcs_nss->rx_mcs_80 = cpu_to_le16(rxmcs_map & 0xffff); + mcs_nss->tx_mcs_80 = cpu_to_le16(txmcs_map & 0xffff); + mcs_nss->rx_mcs_160 = cpu_to_le16(rxmcs_map_160 & 0xffff); + mcs_nss->tx_mcs_160 = cpu_to_le16(txmcs_map_160 & 0xffff); +} + +static void ath12k_mac_copy_he_cap(struct ath12k *ar, + struct ath12k_band_cap *band_cap, int iftype, u8 num_tx_chains, struct ieee80211_sta_he_cap *he_cap) { struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem; - struct ieee80211_he_mcs_nss_supp *mcs_nss = &he_cap->he_mcs_nss_supp; he_cap->has_he = true; memcpy(he_cap_elem->mac_cap_info, band_cap->he_cap_info, @@ -7153,11 +7948,15 @@ static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, he_cap_elem->mac_cap_info[1] &= IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_MASK; - + he_cap_elem->phy_cap_info[0] &= + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G | + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + /* 80PLUS80 is not supported */ + he_cap_elem->phy_cap_info[0] &= + ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G; he_cap_elem->phy_cap_info[5] &= ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK; - he_cap_elem->phy_cap_info[5] &= - ~IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_ABOVE_80MHZ_MASK; he_cap_elem->phy_cap_info[5] |= num_tx_chains - 1; switch (iftype) { @@ -7180,13 +7979,7 @@ static void ath12k_mac_copy_he_cap(struct ath12k_band_cap *band_cap, break; } - mcs_nss->rx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); - mcs_nss->tx_mcs_80 = cpu_to_le16(band_cap->he_mcs & 0xffff); - mcs_nss->rx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->tx_mcs_160 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->rx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - mcs_nss->tx_mcs_80p80 = cpu_to_le16((band_cap->he_mcs >> 16) & 0xffff); - + ath12k_mac_set_hemcsmap(ar, &ar->pdev->cap, he_cap); memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres)); if (he_cap_elem->phy_cap_info[6] & IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) @@ -7376,7 +8169,7 @@ static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar, data[idx].types_mask = BIT(i); - ath12k_mac_copy_he_cap(band_cap, i, ar->num_tx_chains, he_cap); + ath12k_mac_copy_he_cap(ar, band_cap, i, ar->num_tx_chains, he_cap); if (band == NL80211_BAND_6GHZ) { data[idx].he_6ghz_capa.capa = ath12k_mac_setup_he_6ghz_cap(cap, band_cap); @@ -7584,7 +8377,7 @@ static int ath12k_mac_mgmt_tx_wmi(struct ath12k *ar, struct ath12k_link_vif *arv skb_cb->paddr = paddr; - ret = ath12k_wmi_mgmt_send(ar, arvif->vdev_id, buf_id, skb); + ret = ath12k_wmi_mgmt_send(arvif, buf_id, skb); if (ret) { ath12k_warn(ar->ab, "failed to send mgmt frame: %d\n", ret); goto err_unmap_buf; @@ -7611,6 +8404,174 @@ static void ath12k_mgmt_over_wmi_tx_purge(struct ath12k *ar) ath12k_mgmt_over_wmi_tx_drop(ar, skb); } +static int ath12k_mac_mgmt_action_frame_fill_elem_data(struct ath12k_link_vif *arvif, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + u8 category, *buf, iv_len, action_code, dialog_token; + struct ieee80211_bss_conf *link_conf; + struct ieee80211_chanctx_conf *conf; + int cur_tx_power, max_tx_power; + struct ath12k *ar = arvif->ar; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + struct wiphy *wiphy = hw->wiphy; + struct ath12k_skb_cb *skb_cb; + struct ieee80211_mgmt *mgmt; + unsigned int remaining_len; + bool has_protected; + + lockdep_assert_wiphy(wiphy); + + /* make sure category field is present */ + if (skb->len < IEEE80211_MIN_ACTION_SIZE) + return -EINVAL; + + remaining_len = skb->len - IEEE80211_MIN_ACTION_SIZE; + has_protected = ieee80211_has_protected(hdr->frame_control); + + /* In case of SW crypto and hdr protected (PMF), packet will already be encrypted, + * we can't put in data in this case + */ + if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) && + has_protected) + return 0; + + mgmt = (struct ieee80211_mgmt *)hdr; + buf = (u8 *)&mgmt->u.action; + + /* FCTL_PROTECTED frame might have extra space added for HDR_LEN. Offset that + * many bytes if it is there + */ + if (has_protected) { + skb_cb = ATH12K_SKB_CB(skb); + + switch (skb_cb->cipher) { + /* Cipher suite having flag %IEEE80211_KEY_FLAG_GENERATE_IV_MGMT set in + * key needs to be processed. See ath12k_install_key() + */ + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + iv_len = IEEE80211_CCMP_HDR_LEN; + break; + case WLAN_CIPHER_SUITE_TKIP: + iv_len = 0; + break; + default: + return -EINVAL; + } + + if (remaining_len < iv_len) + return -EINVAL; + + buf += iv_len; + remaining_len -= iv_len; + } + + category = *buf++; + /* category code is already taken care in %IEEE80211_MIN_ACTION_SIZE hence + * no need to adjust remaining_len + */ + + switch (category) { + case WLAN_CATEGORY_RADIO_MEASUREMENT: + /* need action code and dialog token */ + if (remaining_len < 2) + return -EINVAL; + + /* Packet Format: + * Action Code | Dialog Token | Variable Len (based on Action Code) + */ + action_code = *buf++; + dialog_token = *buf++; + remaining_len -= 2; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, + "failed to get bss link conf for vdev %d in RM handling\n", + arvif->vdev_id); + return -EINVAL; + } + + conf = wiphy_dereference(wiphy, link_conf->chanctx_conf); + if (!conf) + return -ENOENT; + + cur_tx_power = link_conf->txpower; + max_tx_power = min(conf->def.chan->max_reg_power, + (int)ar->max_tx_power / 2); + + ath12k_mac_op_get_txpower(hw, arvif->ahvif->vif, arvif->link_id, + &cur_tx_power); + + switch (action_code) { + case WLAN_RM_ACTION_LINK_MEASUREMENT_REQUEST: + /* need variable fields to be present in len */ + if (remaining_len < 2) + return -EINVAL; + + /* Variable length format as defined in IEEE 802.11-2024, + * Figure 9-1187-Link Measurement Request frame Action field + * format. + * Transmit Power | Max Tx Power + * We fill both of these. + */ + *buf++ = cur_tx_power; + *buf = max_tx_power; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "RRM: Link Measurement Req dialog_token %u cur_tx_power %d max_tx_power %d\n", + dialog_token, cur_tx_power, max_tx_power); + break; + case WLAN_RM_ACTION_LINK_MEASUREMENT_REPORT: + /* need variable fields to be present in len */ + if (remaining_len < 3) + return -EINVAL; + + /* Variable length format as defined in IEEE 802.11-2024, + * Figure 9-1188-Link Measurement Report frame Action field format + * TPC Report | Variable Fields + * + * TPC Report Format: + * Element ID | Len | Tx Power | Link Margin + * + * We fill Tx power in the TPC Report (2nd index) + */ + buf[2] = cur_tx_power; + + /* TODO: At present, Link margin data is not present so can't + * really fill it now. Once it is available, it can be added + * here + */ + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "RRM: Link Measurement Report dialog_token %u cur_tx_power %d\n", + dialog_token, cur_tx_power); + break; + default: + return -EINVAL; + } + break; + default: + /* nothing to fill */ + return 0; + } + + return 0; +} + +static int ath12k_mac_mgmt_frame_fill_elem_data(struct ath12k_link_vif *arvif, + struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (!ieee80211_is_action(hdr->frame_control)) + return 0; + + return ath12k_mac_mgmt_action_frame_fill_elem_data(arvif, skb); +} + static void ath12k_mgmt_over_wmi_tx_work(struct wiphy *wiphy, struct wiphy_work *work) { struct ath12k *ar = container_of(work, struct ath12k, wmi_mgmt_tx_work); @@ -7642,6 +8603,20 @@ static void ath12k_mgmt_over_wmi_tx_work(struct wiphy *wiphy, struct wiphy_work arvif = wiphy_dereference(ah->hw->wiphy, ahvif->link[skb_cb->link_id]); if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) { + /* Fill in the data which is required to be filled by the driver + * For example: Max Tx power in Link Measurement Request/Report + */ + ret = ath12k_mac_mgmt_frame_fill_elem_data(arvif, skb); + if (ret) { + /* If we couldn't fill the data due to any reason, + * let's not discard transmitting the packet. + * For example: Software crypto and PMF case + */ + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "Failed to fill the required data for the mgmt packet err %d\n", + ret); + } + ret = ath12k_mac_mgmt_tx_wmi(ar, arvif, skb); if (ret) { ath12k_warn(ar->ab, "failed to tx mgmt frame, vdev_id %d :%d\n", @@ -7896,6 +8871,9 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, skb_cb->flags |= ATH12K_SKB_HW_80211_ENCAP; } else if (ieee80211_is_mgmt(hdr->frame_control)) { + if (sta && sta->mlo) + skb_cb->flags |= ATH12K_SKB_MLO_STA; + ret = ath12k_mac_mgmt_tx(ar, skb, is_prb_rsp); if (ret) { ath12k_warn(ar->ab, "failed to queue management frame %d\n", @@ -7920,6 +8898,7 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, is_dvlan = true; if (!vif->valid_links || !is_mcast || is_dvlan || + (skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) || test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) { ret = ath12k_dp_tx(ar, arvif, skb, false, 0, is_mcast); if (unlikely(ret)) { @@ -8114,7 +9093,17 @@ static int ath12k_mac_start(struct ath12k *ar) /* TODO: Do we need to enable ANI? */ - ath12k_reg_update_chan_list(ar, false); + ret = ath12k_reg_update_chan_list(ar, false); + + /* The ar state alone can be turned off for non supported country + * without returning the error value. As we need to update the channel + * for the next ar. + */ + if (ret) { + if (ret == -EINVAL) + ret = 0; + goto err; + } ar->num_started_vdevs = 0; ar->num_created_vdevs = 0; @@ -8160,14 +9149,9 @@ err: static void ath12k_drain_tx(struct ath12k_hw *ah) { - struct ath12k *ar = ah->radio; + struct ath12k *ar; int i; - if (ath12k_ftm_mode) { - ath12k_err(ar->ab, "fail to start mac operations in ftm mode\n"); - return; - } - lockdep_assert_wiphy(ah->hw->wiphy); for_each_ar(ah, ar, i) @@ -8180,6 +9164,9 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) struct ath12k *ar; int ret, i; + if (ath12k_ftm_mode) + return -EPERM; + lockdep_assert_wiphy(hw->wiphy); ath12k_drain_tx(ah); @@ -8286,6 +9273,7 @@ static void ath12k_mac_stop(struct ath12k *ar) { struct ath12k_hw *ah = ar->ah; struct htt_ppdu_stats_info *ppdu_stats, *tmp; + struct ath12k_wmi_scan_chan_list_arg *arg; int ret; lockdep_assert_held(&ah->hw_mutex); @@ -8300,6 +9288,7 @@ static void ath12k_mac_stop(struct ath12k *ar) cancel_delayed_work_sync(&ar->scan.timeout); wiphy_work_cancel(ath12k_ar_to_hw(ar)->wiphy, &ar->scan.vdev_clean_wk); + cancel_work_sync(&ar->regd_channel_update_work); cancel_work_sync(&ar->regd_update_work); cancel_work_sync(&ar->ab->rfkill_work); cancel_work_sync(&ar->ab->update_11d_work); @@ -8307,10 +9296,18 @@ static void ath12k_mac_stop(struct ath12k *ar) complete(&ar->completed_11d_scan); spin_lock_bh(&ar->data_lock); + list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) { list_del(&ppdu_stats->list); kfree(ppdu_stats); } + + while ((arg = list_first_entry_or_null(&ar->regd_channel_update_queue, + struct ath12k_wmi_scan_chan_list_arg, + list))) { + list_del(&arg->list); + kfree(arg); + } spin_unlock_bh(&ar->data_lock); rcu_assign_pointer(ar->ab->pdevs_active[ar->pdev_idx], NULL); @@ -8456,72 +9453,6 @@ static int ath12k_mac_setup_vdev_create_arg(struct ath12k_link_vif *arvif, return 0; } -static u32 -ath12k_mac_prepare_he_mode(struct ath12k_pdev *pdev, u32 viftype) -{ - struct ath12k_pdev_cap *pdev_cap = &pdev->cap; - struct ath12k_band_cap *cap_band = NULL; - u32 *hecap_phy_ptr = NULL; - u32 hemode; - - if (pdev->cap.supported_bands & WMI_HOST_WLAN_2GHZ_CAP) - cap_band = &pdev_cap->band[NL80211_BAND_2GHZ]; - else - cap_band = &pdev_cap->band[NL80211_BAND_5GHZ]; - - hecap_phy_ptr = &cap_band->he_cap_phy_info[0]; - - hemode = u32_encode_bits(HE_SU_BFEE_ENABLE, HE_MODE_SU_TX_BFEE) | - u32_encode_bits(HECAP_PHY_SUBFMR_GET(hecap_phy_ptr), - HE_MODE_SU_TX_BFER) | - u32_encode_bits(HECAP_PHY_ULMUMIMO_GET(hecap_phy_ptr), - HE_MODE_UL_MUMIMO); - - /* TODO: WDS and other modes */ - if (viftype == NL80211_IFTYPE_AP) { - hemode |= u32_encode_bits(HECAP_PHY_MUBFMR_GET(hecap_phy_ptr), - HE_MODE_MU_TX_BFER) | - u32_encode_bits(HE_DL_MUOFDMA_ENABLE, HE_MODE_DL_OFDMA) | - u32_encode_bits(HE_UL_MUOFDMA_ENABLE, HE_MODE_UL_OFDMA); - } else { - hemode |= u32_encode_bits(HE_MU_BFEE_ENABLE, HE_MODE_MU_TX_BFEE); - } - - return hemode; -} - -static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, - struct ath12k_link_vif *arvif) -{ - u32 param_id, param_value; - struct ath12k_base *ab = ar->ab; - struct ath12k_vif *ahvif = arvif->ahvif; - int ret; - - param_id = WMI_VDEV_PARAM_SET_HEMU_MODE; - param_value = ath12k_mac_prepare_he_mode(ar->pdev, ahvif->vif->type); - ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, param_value); - if (ret) { - ath12k_warn(ab, "failed to set vdev %d HE MU mode: %d param_value %x\n", - arvif->vdev_id, ret, param_value); - return ret; - } - param_id = WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE; - param_value = - u32_encode_bits(HE_VHT_SOUNDING_MODE_ENABLE, HE_VHT_SOUNDING_MODE) | - u32_encode_bits(HE_TRIG_NONTRIG_SOUNDING_MODE_ENABLE, - HE_TRIG_NONTRIG_SOUNDING_MODE); - ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - param_id, param_value); - if (ret) { - ath12k_warn(ab, "failed to set vdev %d HE MU mode: %d\n", - arvif->vdev_id, ret); - return ret; - } - return ret; -} - static void ath12k_mac_update_vif_offload(struct ath12k_link_vif *arvif) { struct ath12k_vif *ahvif = arvif->ahvif; @@ -8751,8 +9682,8 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) struct ieee80211_hw *hw = ah->hw; struct ath12k_vif *ahvif = arvif->ahvif; struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); - struct ath12k_wmi_vdev_create_arg vdev_arg = {0}; - struct ath12k_wmi_peer_create_arg peer_param = {0}; + struct ath12k_wmi_vdev_create_arg vdev_arg = {}; + struct ath12k_wmi_peer_create_arg peer_param = {}; struct ieee80211_bss_conf *link_conf = NULL; u32 param_id, param_value; u16 nss; @@ -9055,7 +9986,8 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, struct ath12k_hw *ah = hw->priv; struct ath12k *ar; struct ath12k_base *ab; - u8 link_id = arvif->link_id; + u8 link_id = arvif->link_id, scan_link_id; + unsigned long scan_link_map; int ret; lockdep_assert_wiphy(hw->wiphy); @@ -9074,12 +10006,16 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, * and now we want to create for actual usage. */ if (ieee80211_vif_is_mld(vif)) { - scan_arvif = wiphy_dereference(hw->wiphy, - ahvif->link[ATH12K_DEFAULT_SCAN_LINK]); - if (scan_arvif && scan_arvif->ar == ar) { - ar->scan.arvif = NULL; - ath12k_mac_remove_link_interface(hw, scan_arvif); - ath12k_mac_unassign_link_vif(scan_arvif); + scan_link_map = ahvif->links_map & ATH12K_SCAN_LINKS_MASK; + for_each_set_bit(scan_link_id, &scan_link_map, ATH12K_NUM_MAX_LINKS) { + scan_arvif = wiphy_dereference(hw->wiphy, + ahvif->link[scan_link_id]); + if (scan_arvif && scan_arvif->ar == ar) { + ar->scan.arvif = NULL; + ath12k_mac_remove_link_interface(hw, scan_arvif); + ath12k_mac_unassign_link_vif(scan_arvif); + break; + } } } @@ -9121,9 +10057,9 @@ static struct ath12k *ath12k_mac_assign_vif_to_vdev(struct ieee80211_hw *hw, if (arvif->is_created) goto flush; - if (ar->num_created_vdevs > (TARGET_NUM_VDEVS - 1)) { + if (ar->num_created_vdevs > (TARGET_NUM_VDEVS(ab) - 1)) { ath12k_warn(ab, "failed to create vdev, reached max vdev limit %d\n", - TARGET_NUM_VDEVS); + TARGET_NUM_VDEVS(ab)); goto unlock; } @@ -9314,7 +10250,7 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, .aborted = true, }; - ieee80211_scan_completed(ar->ah->hw, &info); + ath12k_mac_scan_send_complete(ar, &info); } ar->scan.state = ATH12K_SCAN_IDLE; @@ -9354,7 +10290,8 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, ar->filter_flags = *total_flags; } -static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); int antennas_rx = 0, antennas_tx = 0; @@ -9374,7 +10311,8 @@ static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 * return 0; } -static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; @@ -9708,14 +10646,6 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, spin_unlock_bh(&ab->base_lock); /* TODO: Notify if secondary 80Mhz also needs radar detection */ - if (link_conf->he_support) { - ret = ath12k_set_he_mu_sounding_mode(ar, arvif); - if (ret) { - ath12k_warn(ar->ab, "failed to set he mode vdev %i\n", - arg.vdev_id); - return ret; - } - } } arg.passive |= !!(chandef->chan->flags & IEEE80211_CHAN_NO_IR); @@ -9745,7 +10675,7 @@ ath12k_mac_vdev_start_restart(struct ath12k_link_vif *arvif, /* TODO: For now we only set TPC power here. However when * channel changes, say CSA, it should be updated again. */ - if (ath12k_mac_supports_station_tpc(ar, ahvif, chandef)) { + if (ath12k_mac_supports_tpc(ar, ahvif, chandef)) { ath12k_mac_fill_reg_tpc_info(ar, arvif, ctx); ath12k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id, &arvif->reg_tpc_info); @@ -9818,7 +10748,7 @@ ath12k_mac_change_chanctx_cnt_iter(void *data, u8 *mac, if (WARN_ON(!arvif)) continue; - if (arvif->ar != arg->ar) + if (!arvif->is_created || arvif->ar != arg->ar) continue; link_conf = wiphy_dereference(ahvif->ah->hw->wiphy, @@ -9853,7 +10783,7 @@ ath12k_mac_change_chanctx_fill_iter(void *data, u8 *mac, if (WARN_ON(!arvif)) continue; - if (arvif->ar != arg->ar) + if (!arvif->is_created || arvif->ar != arg->ar) continue; link_conf = wiphy_dereference(ahvif->ah->hw->wiphy, @@ -9933,7 +10863,7 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, int n_vifs) { struct ath12k_wmi_vdev_up_params params = {}; - struct ath12k_link_vif *arvif, *tx_arvif; + struct ath12k_link_vif *arvif; struct ieee80211_bss_conf *link_conf; struct ath12k_base *ab = ar->ab; struct ieee80211_vif *vif; @@ -10005,10 +10935,8 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, params.vdev_id = arvif->vdev_id; params.aid = ahvif->aid; params.bssid = arvif->bssid; - - tx_arvif = ath12k_mac_get_tx_arvif(arvif, link_conf); - if (tx_arvif) { - params.tx_bssid = tx_arvif->bssid; + params.tx_bssid = ath12k_mac_get_tx_bssid(arvif); + if (params.tx_bssid) { params.nontx_profile_idx = link_conf->bssid_index; params.nontx_profile_cnt = 1 << link_conf->bssid_indicator; } @@ -10302,7 +11230,9 @@ void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar, bool is_psd_power = false, is_tpe_present = false; s8 max_tx_power[ATH12K_NUM_PWR_LEVELS], psd_power, tx_power, eirp_power; + struct ath12k_vif *ahvif = arvif->ahvif; u16 start_freq, center_freq; + u8 reg_6ghz_power_mode; chan = ctx->def.chan; start_freq = ath12k_mac_get_6ghz_start_frequency(&ctx->def); @@ -10458,8 +11388,14 @@ void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar, reg_tpc_info->num_pwr_levels = num_pwr_levels; reg_tpc_info->is_psd_power = is_psd_power; reg_tpc_info->eirp_power = eirp_power; + if (ahvif->vdev_type == WMI_VDEV_TYPE_STA) + reg_6ghz_power_mode = bss_conf->power_type; + else + /* For now, LPI is the only supported AP power mode */ + reg_6ghz_power_mode = IEEE80211_REG_LPI_AP; + reg_tpc_info->ap_power_type = - ath12k_reg_ap_pwr_convert(bss_conf->power_type); + ath12k_reg_ap_pwr_convert(reg_6ghz_power_mode); } static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar, @@ -10492,7 +11428,7 @@ static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar, "no transmit power envelope match client power type %d\n", client_type); return; - }; + } if (psd_valid) { tpc_info->is_psd_power = true; @@ -10735,7 +11671,8 @@ ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value) /* mac80211 stores device specific RTS/Fragmentation threshold value, * this is set interface specific to firmware from ath12k driver */ -static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { struct ath12k_hw *ah = ath12k_hw_to_ah(hw); struct ath12k *ar; @@ -10760,7 +11697,8 @@ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) return ret; } -static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { /* Even though there's a WMI vdev param for fragmentation threshold no * known firmware actually implements it. Moreover it is not possible to @@ -10880,19 +11818,36 @@ ath12k_mac_has_single_legacy_rate(struct ath12k *ar, if (ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask)) return false; + if (ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask)) + return false; + return num_rates == 1; } +static __le16 +ath12k_mac_get_tx_mcs_map(const struct ieee80211_sta_he_cap *he_cap) +{ + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) + return he_cap->he_mcs_nss_supp.tx_mcs_160; + + return he_cap->he_mcs_nss_supp.tx_mcs_80; +} + static bool ath12k_mac_bitrate_mask_get_single_nss(struct ath12k *ar, + struct ieee80211_vif *vif, enum nl80211_band band, const struct cfg80211_bitrate_mask *mask, int *nss) { struct ieee80211_supported_band *sband = &ar->mac.sbands[band]; u16 vht_mcs_map = le16_to_cpu(sband->vht_cap.vht_mcs.tx_mcs_map); + const struct ieee80211_sta_he_cap *he_cap; + u16 he_mcs_map = 0; u8 ht_nss_mask = 0; u8 vht_nss_mask = 0; + u8 he_nss_mask = 0; int i; /* No need to consider legacy here. Basic rates are always present @@ -10919,7 +11874,24 @@ ath12k_mac_bitrate_mask_get_single_nss(struct ath12k *ar, return false; } - if (ht_nss_mask != vht_nss_mask) + he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif); + if (!he_cap) + return false; + + he_mcs_map = le16_to_cpu(ath12k_mac_get_tx_mcs_map(he_cap)); + + for (i = 0; i < ARRAY_SIZE(mask->control[band].he_mcs); i++) { + if (mask->control[band].he_mcs[i] == 0) + continue; + + if (mask->control[band].he_mcs[i] == + ath12k_mac_get_max_he_mcs_map(he_mcs_map, i)) + he_nss_mask |= BIT(i); + else + return false; + } + + if (ht_nss_mask != vht_nss_mask || ht_nss_mask != he_nss_mask) return false; if (ht_nss_mask == 0) @@ -10966,54 +11938,182 @@ ath12k_mac_get_single_legacy_rate(struct ath12k *ar, return 0; } -static int ath12k_mac_set_fixed_rate_params(struct ath12k_link_vif *arvif, - u32 rate, u8 nss, u8 sgi, u8 ldpc) +static int +ath12k_mac_set_fixed_rate_gi_ltf(struct ath12k_link_vif *arvif, u8 he_gi, u8 he_ltf) { struct ath12k *ar = arvif->ar; - u32 vdev_param; int ret; lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02x nss %u sgi %u\n", - arvif->vdev_id, rate, nss, sgi); + /* 0.8 = 0, 1.6 = 2 and 3.2 = 3. */ + if (he_gi && he_gi != 0xFF) + he_gi += 1; - vdev_param = WMI_VDEV_PARAM_FIXED_RATE; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, rate); + WMI_VDEV_PARAM_SGI, he_gi); if (ret) { - ath12k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", - rate, ret); + ath12k_warn(ar->ab, "failed to set HE GI:%d, error:%d\n", + he_gi, ret); return ret; } + /* start from 1 */ + if (he_ltf != 0xFF) + he_ltf += 1; - vdev_param = WMI_VDEV_PARAM_NSS; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, nss); + WMI_VDEV_PARAM_HE_LTF, he_ltf); if (ret) { - ath12k_warn(ar->ab, "failed to set nss param %d: %d\n", - nss, ret); + ath12k_warn(ar->ab, "failed to set HE LTF:%d, error:%d\n", + he_ltf, ret); + return ret; + } + return 0; +} + +static int +ath12k_mac_set_auto_rate_gi_ltf(struct ath12k_link_vif *arvif, u16 he_gi, u8 he_ltf) +{ + struct ath12k *ar = arvif->ar; + int ret; + u32 he_ar_gi_ltf; + + if (he_gi != 0xFF) { + switch (he_gi) { + case NL80211_RATE_INFO_HE_GI_0_8: + he_gi = WMI_AUTORATE_800NS_GI; + break; + case NL80211_RATE_INFO_HE_GI_1_6: + he_gi = WMI_AUTORATE_1600NS_GI; + break; + case NL80211_RATE_INFO_HE_GI_3_2: + he_gi = WMI_AUTORATE_3200NS_GI; + break; + default: + ath12k_warn(ar->ab, "Invalid GI\n"); + return -EINVAL; + } + } + + if (he_ltf != 0xFF) { + switch (he_ltf) { + case NL80211_RATE_INFO_HE_1XLTF: + he_ltf = WMI_HE_AUTORATE_LTF_1X; + break; + case NL80211_RATE_INFO_HE_2XLTF: + he_ltf = WMI_HE_AUTORATE_LTF_2X; + break; + case NL80211_RATE_INFO_HE_4XLTF: + he_ltf = WMI_HE_AUTORATE_LTF_4X; + break; + default: + ath12k_warn(ar->ab, "Invalid LTF\n"); + return -EINVAL; + } + } + + he_ar_gi_ltf = he_gi | he_ltf; + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_AUTORATE_MISC_CFG, + he_ar_gi_ltf); + if (ret) { + ath12k_warn(ar->ab, + "failed to set HE autorate GI:%u, LTF:%u params, error:%d\n", + he_gi, he_ltf, ret); return ret; } - vdev_param = WMI_VDEV_PARAM_SGI; + return 0; +} + +static u32 ath12k_mac_nlgi_to_wmigi(enum nl80211_txrate_gi gi) +{ + switch (gi) { + case NL80211_TXRATE_DEFAULT_GI: + return WMI_GI_400_NS; + case NL80211_TXRATE_FORCE_LGI: + return WMI_GI_800_NS; + default: + return WMI_GI_400_NS; + } +} + +static int ath12k_mac_set_rate_params(struct ath12k_link_vif *arvif, + u32 rate, u8 nss, u8 sgi, u8 ldpc, + u8 he_gi, u8 he_ltf, bool he_fixed_rate) +{ + struct ieee80211_bss_conf *link_conf; + struct ath12k *ar = arvif->ar; + u32 vdev_param; + u32 param_value; + int ret; + bool he_support; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) + return -EINVAL; + + he_support = link_conf->he_support; + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "mac set rate params vdev %i rate 0x%02x nss 0x%02x sgi 0x%02x ldpc 0x%02x\n", + arvif->vdev_id, rate, nss, sgi, ldpc); + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "he_gi 0x%02x he_ltf 0x%02x he_fixed_rate %d\n", he_gi, + he_ltf, he_fixed_rate); + + if (!he_support) { + vdev_param = WMI_VDEV_PARAM_FIXED_RATE; + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + vdev_param, rate); + if (ret) { + ath12k_warn(ar->ab, "failed to set fixed rate param 0x%02x: %d\n", + rate, ret); + return ret; + } + } + + vdev_param = WMI_VDEV_PARAM_NSS; + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, sgi); + vdev_param, nss); if (ret) { - ath12k_warn(ar->ab, "failed to set sgi param %d: %d\n", - sgi, ret); + ath12k_warn(ar->ab, "failed to set nss param %d: %d\n", + nss, ret); return ret; } - vdev_param = WMI_VDEV_PARAM_LDPC; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, ldpc); + WMI_VDEV_PARAM_LDPC, ldpc); if (ret) { ath12k_warn(ar->ab, "failed to set ldpc param %d: %d\n", ldpc, ret); return ret; } + if (he_support) { + if (he_fixed_rate) + ret = ath12k_mac_set_fixed_rate_gi_ltf(arvif, he_gi, he_ltf); + else + ret = ath12k_mac_set_auto_rate_gi_ltf(arvif, he_gi, he_ltf); + if (ret) + return ret; + } else { + vdev_param = WMI_VDEV_PARAM_SGI; + param_value = ath12k_mac_nlgi_to_wmigi(sgi); + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + vdev_param, param_value); + if (ret) { + ath12k_warn(ar->ab, "failed to set sgi param %d: %d\n", + sgi, ret); + return ret; + } + } + return 0; } @@ -11042,6 +12142,31 @@ ath12k_mac_vht_mcs_range_present(struct ath12k *ar, return true; } +static bool +ath12k_mac_he_mcs_range_present(struct ath12k *ar, + enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask) +{ + int i; + u16 he_mcs; + + for (i = 0; i < NL80211_HE_NSS_MAX; i++) { + he_mcs = mask->control[band].he_mcs[i]; + + switch (he_mcs) { + case 0: + case BIT(8) - 1: + case BIT(10) - 1: + case BIT(12) - 1: + break; + default: + return false; + } + } + + return true; +} + static void ath12k_mac_set_bitrate_mask_iter(void *data, struct ieee80211_sta *sta) { @@ -11050,7 +12175,10 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data, struct ath12k_link_sta *arsta; struct ath12k *ar = arvif->ar; - arsta = rcu_dereference(ahsta->link[arvif->link_id]); + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy, + ahsta->link[arvif->link_id]); if (!arsta || arsta->arvif != arvif) return; @@ -11088,6 +12216,61 @@ static void ath12k_mac_disable_peer_fixed_rate(void *data, arsta->addr, ret); } +static bool +ath12k_mac_validate_fixed_rate_settings(struct ath12k *ar, enum nl80211_band band, + const struct cfg80211_bitrate_mask *mask, + unsigned int link_id) +{ + bool he_fixed_rate = false, vht_fixed_rate = false; + const u16 *vht_mcs_mask, *he_mcs_mask; + struct ieee80211_link_sta *link_sta; + struct ath12k_peer *peer, *tmp; + u8 vht_nss, he_nss; + int ret = true; + + vht_mcs_mask = mask->control[band].vht_mcs; + he_mcs_mask = mask->control[band].he_mcs; + + if (ath12k_mac_bitrate_mask_num_vht_rates(ar, band, mask) == 1) + vht_fixed_rate = true; + + if (ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask) == 1) + he_fixed_rate = true; + + if (!vht_fixed_rate && !he_fixed_rate) + return true; + + vht_nss = ath12k_mac_max_vht_nss(vht_mcs_mask); + he_nss = ath12k_mac_max_he_nss(he_mcs_mask); + + rcu_read_lock(); + spin_lock_bh(&ar->ab->base_lock); + list_for_each_entry_safe(peer, tmp, &ar->ab->peers, list) { + if (peer->sta) { + link_sta = rcu_dereference(peer->sta->link[link_id]); + if (!link_sta) { + ret = false; + goto exit; + } + + if (vht_fixed_rate && (!link_sta->vht_cap.vht_supported || + link_sta->rx_nss < vht_nss)) { + ret = false; + goto exit; + } + if (he_fixed_rate && (!link_sta->he_cap.has_he || + link_sta->rx_nss < he_nss)) { + ret = false; + goto exit; + } + } + } +exit: + spin_unlock_bh(&ar->ab->base_lock); + rcu_read_unlock(); + return ret; +} + static int ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -11100,13 +12283,17 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, enum nl80211_band band; const u8 *ht_mcs_mask; const u16 *vht_mcs_mask; + const u16 *he_mcs_mask; + u8 he_ltf = 0; + u8 he_gi = 0; u32 rate; - u8 nss; + u8 nss, mac_nss; u8 sgi; u8 ldpc; int single_nss; int ret; int num_rates; + bool he_fixed_rate = false; lockdep_assert_wiphy(hw->wiphy); @@ -11121,14 +12308,18 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, band = def.chan->band; ht_mcs_mask = mask->control[band].ht_mcs; vht_mcs_mask = mask->control[band].vht_mcs; + he_mcs_mask = mask->control[band].he_mcs; ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); sgi = mask->control[band].gi; - if (sgi == NL80211_TXRATE_FORCE_LGI) { + if (sgi == NL80211_TXRATE_FORCE_SGI) { ret = -EINVAL; goto out; } + he_gi = mask->control[band].he_gi; + he_ltf = mask->control[band].he_ltf; + /* mac80211 doesn't support sending a fixed HT/VHT MCS alone, rather it * requires passing at least one of used basic rates along with them. * Fixed rate setting across different preambles(legacy, HT, VHT) is @@ -11145,18 +12336,31 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif->vdev_id, ret); goto out; } + ieee80211_iterate_stations_mtx(hw, ath12k_mac_disable_peer_fixed_rate, arvif); - } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, band, mask, + } else if (ath12k_mac_bitrate_mask_get_single_nss(ar, vif, band, mask, &single_nss)) { rate = WMI_FIXED_RATE_NONE; nss = single_nss; + arvif->bitrate_mask = *mask; + + ieee80211_iterate_stations_atomic(hw, + ath12k_mac_set_bitrate_mask_iter, + arvif); } else { rate = WMI_FIXED_RATE_NONE; - nss = min_t(u32, ar->num_tx_chains, - max(ath12k_mac_max_ht_nss(ht_mcs_mask), - ath12k_mac_max_vht_nss(vht_mcs_mask))); + + if (!ath12k_mac_validate_fixed_rate_settings(ar, band, + mask, arvif->link_id)) + ath12k_warn(ar->ab, + "failed to update fixed rate settings due to mcs/nss incompatibility\n"); + + mac_nss = max3(ath12k_mac_max_ht_nss(ht_mcs_mask), + ath12k_mac_max_vht_nss(vht_mcs_mask), + ath12k_mac_max_he_nss(he_mcs_mask)); + nss = min_t(u32, ar->num_tx_chains, mac_nss); /* If multiple rates across different preambles are given * we can reconfigure this info with all peers using PEER_ASSOC @@ -11188,9 +12392,21 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, */ ath12k_warn(ar->ab, "Setting more than one MCS Value in bitrate mask not supported\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } + num_rates = ath12k_mac_bitrate_mask_num_he_rates(ar, band, mask); + if (num_rates == 1) + he_fixed_rate = true; + + if (!ath12k_mac_he_mcs_range_present(ar, band, mask) && + num_rates > 1) { + ath12k_warn(ar->ab, + "Setting more than one HE MCS Value in bitrate mask not supported\n"); + ret = -EINVAL; + goto out; + } ieee80211_iterate_stations_mtx(hw, ath12k_mac_disable_peer_fixed_rate, arvif); @@ -11201,9 +12417,10 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, arvif); } - ret = ath12k_mac_set_fixed_rate_params(arvif, rate, nss, sgi, ldpc); + ret = ath12k_mac_set_rate_params(arvif, rate, nss, sgi, ldpc, he_gi, + he_ltf, he_fixed_rate); if (ret) { - ath12k_warn(ar->ab, "failed to set fixed rate params on vdev %i: %d\n", + ath12k_warn(ar->ab, "failed to set rate params on vdev %i: %d\n", arvif->vdev_id, ret); } @@ -11246,6 +12463,7 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, struct wmi_set_current_country_arg arg = {}; memcpy(&arg.alpha2, ar->alpha2, 2); + reinit_completion(&ar->regd_update_completed); ath12k_wmi_send_set_current_country_cmd(ar, &arg); } @@ -11388,8 +12606,8 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta); struct ath12k_fw_stats_req_params params = {}; struct ath12k_link_sta *arsta; + s8 signal, noise_floor; struct ath12k *ar; - s8 signal; bool db2dbm; lockdep_assert_wiphy(hw->wiphy); @@ -11437,17 +12655,108 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, !(ath12k_mac_get_fw_stats(ar, ¶ms))) signal = arsta->rssi_beacon; + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + if (signal) { - sinfo->signal = db2dbm ? signal : signal + ATH12K_DEFAULT_NOISE_FLOOR; + sinfo->signal = db2dbm ? signal : signal + noise_floor; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi); if (!db2dbm) - sinfo->signal_avg += ATH12K_DEFAULT_NOISE_FLOOR; + sinfo->signal_avg += noise_floor; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); + + sinfo->tx_retries = arsta->tx_retry_count; + sinfo->tx_failed = arsta->tx_retry_failed; + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); +} + +static void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct link_station_info *link_sinfo) +{ + struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta); + struct ath12k_fw_stats_req_params params = {}; + struct ath12k_link_sta *arsta; + struct ath12k *ar; + s8 signal; + bool db2dbm; + + lockdep_assert_wiphy(hw->wiphy); + + arsta = wiphy_dereference(hw->wiphy, ahsta->link[link_sta->link_id]); + + if (!arsta) + return; + + ar = ath12k_get_ar_by_vif(hw, vif, arsta->link_id); + if (!ar) + return; + + db2dbm = test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, + ar->ab->wmi_ab.svc_map); + + link_sinfo->rx_duration = arsta->rx_duration; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION); + + link_sinfo->tx_duration = arsta->tx_duration; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION); + + if (arsta->txrate.legacy || arsta->txrate.nss) { + if (arsta->txrate.legacy) { + link_sinfo->txrate.legacy = arsta->txrate.legacy; + } else { + link_sinfo->txrate.mcs = arsta->txrate.mcs; + link_sinfo->txrate.nss = arsta->txrate.nss; + link_sinfo->txrate.bw = arsta->txrate.bw; + link_sinfo->txrate.he_gi = arsta->txrate.he_gi; + link_sinfo->txrate.he_dcm = arsta->txrate.he_dcm; + link_sinfo->txrate.he_ru_alloc = + arsta->txrate.he_ru_alloc; + link_sinfo->txrate.eht_gi = arsta->txrate.eht_gi; + link_sinfo->txrate.eht_ru_alloc = + arsta->txrate.eht_ru_alloc; + } + link_sinfo->txrate.flags = arsta->txrate.flags; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); + } + + /* TODO: Use real NF instead of default one. */ + signal = arsta->rssi_comb; + + params.pdev_id = ar->pdev->pdev_id; + params.vdev_id = 0; + params.stats_id = WMI_REQUEST_VDEV_STAT; + + if (!signal && + ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && + !(ath12k_mac_get_fw_stats(ar, ¶ms))) + signal = arsta->rssi_beacon; + + if (signal) { + link_sinfo->signal = + db2dbm ? signal : signal + ATH12K_DEFAULT_NOISE_FLOOR; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); + } + + link_sinfo->signal_avg = ewma_avg_rssi_read(&arsta->avg_rssi); + + if (!db2dbm) + link_sinfo->signal_avg += ATH12K_DEFAULT_NOISE_FLOOR; + + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL_AVG); + + link_sinfo->tx_retries = arsta->tx_retry_count; + link_sinfo->tx_failed = arsta->tx_retry_failed; + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES); + link_sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); } static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, @@ -11685,6 +12994,7 @@ static const struct ieee80211_ops ath12k_ops = { .get_survey = ath12k_mac_op_get_survey, .flush = ath12k_mac_op_flush, .sta_statistics = ath12k_mac_op_sta_statistics, + .link_sta_statistics = ath12k_mac_op_link_sta_statistics, .remain_on_channel = ath12k_mac_op_remain_on_channel, .cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel, .change_sta_links = ath12k_mac_op_change_sta_links, @@ -11757,6 +13067,32 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) return 0; } +static int ath12k_mac_update_band(struct ath12k *ar, + struct ieee80211_supported_band *orig_band, + struct ieee80211_supported_band *new_band) +{ + int i; + + if (!orig_band || !new_band) + return -EINVAL; + + if (orig_band->band != new_band->band) + return -EINVAL; + + for (i = 0; i < new_band->n_channels; i++) { + if (new_band->channels[i].flags & IEEE80211_CHAN_DISABLED) + continue; + /* An enabled channel in new_band should not be already enabled + * in the orig_band + */ + if (WARN_ON(!(orig_band->channels[i].flags & + IEEE80211_CHAN_DISABLED))) + return -EINVAL; + orig_band->channels[i].flags &= ~IEEE80211_CHAN_DISABLED; + } + return 0; +} + static int ath12k_mac_setup_channels_rates(struct ath12k *ar, u32 supported_bands, struct ieee80211_supported_band *bands[]) @@ -11767,6 +13103,7 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, u32 phy_id, freq_low, freq_high; struct ath12k_hw *ah = ar->ah; void *channels; + int ret; BUILD_BUG_ON((ARRAY_SIZE(ath12k_2ghz_channels) + ARRAY_SIZE(ath12k_5ghz_channels) + @@ -11788,7 +13125,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_g_rates_size; band->bitrates = ath12k_g_rates; - bands[NL80211_BAND_2GHZ] = band; if (ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2GHZ_CAP); @@ -11805,6 +13141,22 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, reg_cap->high_2ghz_chan); ath12k_mac_update_freq_range(ar, freq_low, freq_high); + + if (!bands[NL80211_BAND_2GHZ]) { + bands[NL80211_BAND_2GHZ] = band; + } else { + /* Split mac in same band under same wiphy */ + ret = ath12k_mac_update_band(ar, bands[NL80211_BAND_2GHZ], band); + if (ret) { + kfree(channels); + band->channels = NULL; + return ret; + } + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 2 GHz split mac with start freq %d end freq %d", + ar->pdev->pdev_id, + KHZ_TO_MHZ(ar->freq_range.start_freq), + KHZ_TO_MHZ(ar->freq_range.end_freq)); + } } if (supported_bands & WMI_HOST_WLAN_5GHZ_CAP) { @@ -11823,7 +13175,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - bands[NL80211_BAND_6GHZ] = band; freq_low = max(reg_cap->low_5ghz_chan, ab->reg_freq_6ghz.start_freq); @@ -11836,6 +13187,26 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, ath12k_mac_update_freq_range(ar, freq_low, freq_high); ah->use_6ghz_regd = true; + + if (!bands[NL80211_BAND_6GHZ]) { + bands[NL80211_BAND_6GHZ] = band; + } else { + /* Split mac in same band under same wiphy */ + ret = ath12k_mac_update_band(ar, + bands[NL80211_BAND_6GHZ], + band); + if (ret) { + kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); + ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL; + kfree(channels); + band->channels = NULL; + return ret; + } + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 6 GHz split mac with start freq %d end freq %d", + ar->pdev->pdev_id, + KHZ_TO_MHZ(ar->freq_range.start_freq), + KHZ_TO_MHZ(ar->freq_range.end_freq)); + } } if (reg_cap->low_5ghz_chan < ATH12K_MIN_6GHZ_FREQ) { @@ -11854,7 +13225,6 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, band->channels = channels; band->n_bitrates = ath12k_a_rates_size; band->bitrates = ath12k_a_rates; - bands[NL80211_BAND_5GHZ] = band; if (ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5GHZ_CAP); @@ -11871,6 +13241,28 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, reg_cap->high_5ghz_chan); ath12k_mac_update_freq_range(ar, freq_low, freq_high); + + if (!bands[NL80211_BAND_5GHZ]) { + bands[NL80211_BAND_5GHZ] = band; + } else { + /* Split mac in same band under same wiphy */ + ret = ath12k_mac_update_band(ar, + bands[NL80211_BAND_5GHZ], + band); + if (ret) { + kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); + ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL; + kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); + ar->mac.sbands[NL80211_BAND_2GHZ].channels = NULL; + kfree(channels); + band->channels = NULL; + return ret; + } + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac pdev %u identified as 5 GHz split mac with start freq %d end freq %d", + ar->pdev->pdev_id, + KHZ_TO_MHZ(ar->freq_range.start_freq), + KHZ_TO_MHZ(ar->freq_range.end_freq)); + } } } @@ -11973,15 +13365,12 @@ ath12k_mac_setup_radio_iface_comb(struct ath12k *ar, comb[0].beacon_int_infra_match = true; comb[0].beacon_int_min_gcd = 100; - if (ar->ab->hw_params->single_pdev_only) { - comb[0].num_different_channels = 2; - } else { - comb[0].num_different_channels = 1; - comb[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | - BIT(NL80211_CHAN_WIDTH_20) | - BIT(NL80211_CHAN_WIDTH_40) | - BIT(NL80211_CHAN_WIDTH_80); - } + comb[0].num_different_channels = 1; + comb[0].radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160); return 0; } @@ -12064,25 +13453,42 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) struct ieee80211_iface_combination *combinations, *comb; struct wiphy *wiphy = ah->hw->wiphy; struct wiphy_radio *radio; + int n_combinations = 1; struct ath12k *ar; int i, ret; - combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); - if (!combinations) - return -ENOMEM; - if (ah->num_radio == 1) { - ret = ath12k_mac_setup_radio_iface_comb(&ah->radio[0], - combinations); + ar = &ah->radio[0]; + + if (ar->ab->hw_params->single_pdev_only) + n_combinations = 2; + + combinations = kcalloc(n_combinations, sizeof(*combinations), + GFP_KERNEL); + if (!combinations) + return -ENOMEM; + + ret = ath12k_mac_setup_radio_iface_comb(ar, combinations); if (ret) { ath12k_hw_warn(ah, "failed to setup radio interface combinations for one radio: %d", ret); goto err_free_combinations; } + if (ar->ab->hw_params->single_pdev_only) { + comb = combinations + 1; + memcpy(comb, combinations, sizeof(*comb)); + comb->num_different_channels = 2; + comb->radar_detect_widths = 0; + } + goto out; } + combinations = kcalloc(n_combinations, sizeof(*combinations), GFP_KERNEL); + if (!combinations) + return -ENOMEM; + /* there are multiple radios */ radio = kcalloc(ah->num_radio, sizeof(*radio), GFP_KERNEL); @@ -12125,7 +13531,7 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) out: wiphy->iface_combinations = combinations; - wiphy->n_iface_combinations = 1; + wiphy->n_iface_combinations = n_combinations; return 0; @@ -12204,6 +13610,7 @@ static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) int i; for_each_ar(ah, ar, i) { + cancel_work_sync(&ar->regd_channel_update_work); cancel_work_sync(&ar->regd_update_work); ath12k_debugfs_unregister(ar); ath12k_fw_stats_reset(ar); @@ -12244,6 +13651,10 @@ static int ath12k_mac_setup_register(struct ath12k *ar, ar->max_num_stations = ath12k_core_get_max_station_per_radio(ar->ab); ar->max_num_peers = ath12k_core_get_max_peers_per_radio(ar->ab); + ar->rssi_info.min_nf_dbm = ATH12K_DEFAULT_NOISE_FLOOR; + ar->rssi_info.temp_offset = 0; + ar->rssi_info.noise_floor = ar->rssi_info.min_nf_dbm + ar->rssi_info.temp_offset; + return 0; } @@ -12318,7 +13729,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) else mac_addr = ab->mac_addr; - mbssid_max_interfaces += TARGET_NUM_VDEVS; + mbssid_max_interfaces += TARGET_NUM_VDEVS(ar->ab); } wiphy->available_antennas_rx = antennas_rx; @@ -12357,6 +13768,14 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) ieee80211_hw_set(hw, REPORTS_LOW_ACK); ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); + if (test_bit(WMI_TLV_SERVICE_ETH_OFFLOAD, ar->wmi->wmi_ab->svc_map)) { + ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); + ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); + } + + if (cap->nss_ratio_enabled) + ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); + if ((ht_cap & WMI_HT_CAP_ENABLED) || is_6ghz) { ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW); @@ -12389,6 +13808,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; + wiphy->features |= NL80211_FEATURE_TX_POWER_INSERTION; + /* MLO is not yet supported so disable Wireless Extensions for now * to make sure ath12k users don't use it. This flag can be removed * once WIPHY_FLAG_SUPPORTS_MLO is enabled. @@ -12417,6 +13838,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STA_TX_PWR); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); wiphy->cipher_suites = cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); @@ -12426,6 +13848,7 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) wiphy->mbssid_max_interfaces = mbssid_max_interfaces; wiphy->ema_max_profile_periodicity = TARGET_EMA_MAX_PROFILE_PERIOD; + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); if (is_6ghz) { wiphy_ext_feature_set(wiphy, @@ -12435,6 +13858,8 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) } wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT); + if (test_bit(WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT, ab->wmi_ab.svc_map)) + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); ath12k_reg_init(hw); @@ -12462,6 +13887,16 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) goto err_cleanup_if_combs; } + /* Boot-time regulatory updates have already been processed. + * Mark them as complete now, because after registration, + * cfg80211 will notify us again if there are any pending hints. + * We need to wait for those hints to be processed, so it's + * important to mark the boot-time updates as complete before + * proceeding with registration. + */ + for_each_ar(ah, ar, i) + complete_all(&ar->regd_update_completed); + ret = ieee80211_register_hw(hw); if (ret) { ath12k_err(ab, "ieee80211 registration failed: %d\n", ret); @@ -12489,6 +13924,9 @@ static int ath12k_mac_hw_register(struct ath12k_hw *ah) memcpy(¤t_cc.alpha2, ab->new_alpha2, 2); memcpy(&ar->alpha2, ab->new_alpha2, 2); + + reinit_completion(&ar->regd_update_completed); + ret = ath12k_wmi_send_set_current_country_cmd(ar, ¤t_cc); if (ret) ath12k_warn(ar->ab, @@ -12561,9 +13999,12 @@ static void ath12k_mac_setup(struct ath12k *ar) init_completion(&ar->scan.on_channel); init_completion(&ar->mlo_setup_done); init_completion(&ar->completed_11d_scan); + init_completion(&ar->regd_update_completed); INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); wiphy_work_init(&ar->scan.vdev_clean_wk, ath12k_scan_vdev_clean_work); + INIT_WORK(&ar->regd_channel_update_work, ath12k_regd_update_chan_list_work); + INIT_LIST_HEAD(&ar->regd_channel_update_queue); INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); wiphy_work_init(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); @@ -12850,9 +14291,12 @@ void ath12k_mac_destroy(struct ath12k_hw_group *ag) static void ath12k_mac_set_device_defaults(struct ath12k_base *ab) { + int total_vdev; + /* Initialize channel counters frequency value in hertz */ ab->cc_freq_hz = 320000; - ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; + total_vdev = ab->num_radios * TARGET_NUM_VDEVS(ab); + ab->free_vdev_map = (1LL << total_vdev) - 1; } int ath12k_mac_allocate(struct ath12k_hw_group *ag) diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index cc81b1f5680f..18c79d4002cb 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.h @@ -41,6 +41,8 @@ struct ath12k_generic_iter { #define IEEE80211_DISABLE_VHT_MCS_SUPPORT_0_11 BIT(24) #define ATH12K_CHAN_WIDTH_NUM 14 +#define ATH12K_BW_NSS_MAP_ENABLE BIT(31) +#define ATH12K_PEER_RX_NSS_160MHZ GENMASK(2, 0) #define ATH12K_TX_POWER_MAX_VAL 70 #define ATH12K_TX_POWER_MIN_VAL 0 @@ -51,11 +53,29 @@ struct ath12k_generic_iter { /* Default link after the IEEE802.11 defined Max link id limit * for driver usage purpose. */ -#define ATH12K_DEFAULT_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS -#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + 1) +#define ATH12K_FIRST_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS +#define ATH12K_SCAN_MAX_LINKS ATH12K_GROUP_MAX_RADIO +/* Define 1 scan link for each radio for parallel scan purposes */ +#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + ATH12K_SCAN_MAX_LINKS) +#define ATH12K_SCAN_LINKS_MASK GENMASK(ATH12K_NUM_MAX_LINKS, IEEE80211_MLD_MAX_NUM_LINKS) #define ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE 2 +#define HECAP_PHY_SUBFMR_GET(hecap_phy) \ + u8_get_bits(hecap_phy[3], IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER) + +#define HECAP_PHY_SUBFME_GET(hecap_phy) \ + u8_get_bits(hecap_phy[4], IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE) + +#define HECAP_PHY_MUBFMR_GET(hecap_phy) \ + u8_get_bits(hecap_phy[4], IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER) + +#define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \ + u8_get_bits(hecap_phy[2], IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO) + +#define HECAP_PHY_ULOFDMA_GET(hecap_phy) \ + u8_get_bits(hecap_phy[2], IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO) + enum ath12k_supported_bw { ATH12K_BW_20 = 0, ATH12K_BW_40 = 1, diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c index 84cccf7d91e7..59589748f1a8 100644 --- a/drivers/net/wireless/ath/ath12k/p2p.c +++ b/drivers/net/wireless/ath/ath12k/p2p.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <net/mac80211.h> @@ -124,7 +125,7 @@ static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac, WARN_ON(!rcu_read_lock_any_held()); arvif = &ahvif->deflink; - if (arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id) + if (!arvif->is_created || arvif->ar != arg->ar || arvif->vdev_id != arg->vdev_id) return; ath12k_p2p_noa_update(arvif, arg->noa); diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 1f3cfd9b89fd..c729d5526c75 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -48,7 +48,7 @@ static const struct pci_device_id ath12k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) }, - {0} + {} }; MODULE_DEVICE_TABLE(pci, ath12k_pci_id_table); @@ -1353,7 +1353,7 @@ static void ath12k_pci_coredump_download(struct ath12k_base *ab) struct ath12k_tlv_dump_data *dump_tlv; size_t hdr_len = sizeof(*file_data); void *buf; - u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = { 0 }; + u32 dump_seg_sz[FW_CRASH_DUMP_TYPE_MAX] = {}; ath12k_mhi_coredump(mhi_ctrl, false); @@ -1595,6 +1595,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab->hal_rx_ops = &hal_rx_qcn9274_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); + ab->target_mem_mode = ath12k_core_get_memory_mode(ab); switch (soc_hw_version_major) { case ATH12K_PCI_SOC_HW_VERSION_2: ab->hw_rev = ATH12K_HW_QCN9274_HW20; @@ -1618,6 +1619,7 @@ static int ath12k_pci_probe(struct pci_dev *pdev, ab->hal_rx_ops = &hal_rx_wcn7850_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); + ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT; switch (soc_hw_version_major) { case ATH12K_PCI_SOC_HW_VERSION_2: ab->hw_rev = ATH12K_HW_WCN7850_HW20; diff --git a/drivers/net/wireless/ath/ath12k/peer.c b/drivers/net/wireless/ath/ath12k/peer.c index ec7236bbccc0..f1ae9e5b5af7 100644 --- a/drivers/net/wireless/ath/ath12k/peer.c +++ b/drivers/net/wireless/ath/ath12k/peer.c @@ -8,7 +8,7 @@ #include "peer.h" #include "debug.h" -static struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, const u8 *addr) +struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, const u8 *addr) { struct ath12k_ml_peer *ml_peer; @@ -100,6 +100,9 @@ struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab, lockdep_assert_held(&ab->base_lock); + if (peer_id == HAL_INVALID_PEERID) + return NULL; + if (peer_id & ATH12K_PEER_ML_ID_VALID) return ath12k_peer_find_by_ml_id(ab, peer_id); diff --git a/drivers/net/wireless/ath/ath12k/peer.h b/drivers/net/wireless/ath/ath12k/peer.h index f3a5e054d2b5..44afc0b7dd53 100644 --- a/drivers/net/wireless/ath/ath12k/peer.h +++ b/drivers/net/wireless/ath/ath12k/peer.h @@ -91,5 +91,33 @@ struct ath12k_peer *ath12k_peer_find_by_ast(struct ath12k_base *ab, int ast_hash int ath12k_peer_ml_create(struct ath12k_hw *ah, struct ieee80211_sta *sta); int ath12k_peer_ml_delete(struct ath12k_hw *ah, struct ieee80211_sta *sta); int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta); +struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, + const u8 *addr); +static inline +struct ath12k_link_sta *ath12k_peer_get_link_sta(struct ath12k_base *ab, + struct ath12k_peer *peer) +{ + struct ath12k_sta *ahsta; + struct ath12k_link_sta *arsta; + + if (!peer->sta) + return NULL; + + ahsta = ath12k_sta_to_ahsta(peer->sta); + if (peer->ml_id & ATH12K_PEER_ML_ID_VALID) { + if (!(ahsta->links_map & BIT(peer->link_id))) { + ath12k_warn(ab, "peer %pM id %d link_id %d can't found in STA link_map 0x%x\n", + peer->addr, peer->peer_id, peer->link_id, + ahsta->links_map); + return NULL; + } + arsta = rcu_dereference(ahsta->link[peer->link_id]); + if (!arsta) + return NULL; + } else { + arsta = &ahsta->deflink; + } + return arsta; +} #endif /* _PEER_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index 99e1fb2910d0..7c611a1fd6d0 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -3856,7 +3856,7 @@ int ath12k_qmi_init_service(struct ath12k_base *ab) memset(&ab->qmi.target_mem, 0, sizeof(struct target_mem_chunk)); ab->qmi.ab = ab; - ab->qmi.target_mem_mode = ATH12K_QMI_TARGET_MEM_MODE_DEFAULT; + ab->qmi.target_mem_mode = ab->target_mem_mode; ret = qmi_handle_init(&ab->qmi.handle, ATH12K_QMI_RESP_LEN_MAX, &ath12k_qmi_ops, ath12k_qmi_msg_handlers); if (ret < 0) { diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index 96e6c3daecfe..abdaade3b542 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.h @@ -37,7 +37,6 @@ #define QMI_WLANFW_MAX_DATA_SIZE_V01 6144 #define ATH12K_FIRMWARE_MODE_OFF 4 -#define ATH12K_QMI_TARGET_MEM_MODE_DEFAULT 0 #define ATH12K_BOARD_ID_DEFAULT 0xFF @@ -602,6 +601,11 @@ struct qmi_wlanfw_wlan_ini_resp_msg_v01 { struct qmi_response_type_v01 resp; }; +enum ath12k_qmi_mem_mode { + ATH12K_QMI_MEMORY_MODE_DEFAULT = 0, + ATH12K_QMI_MEMORY_MODE_LOW_512_M, +}; + static inline void ath12k_qmi_set_event_block(struct ath12k_qmi *qmi, bool block) { lockdep_assert_held(&qmi->event_lock); diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 2598b39d5d7e..7898f6981e5a 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.c @@ -65,7 +65,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) for_each_ar(ah, ar, i) { ret = ath12k_reg_update_chan_list(ar, true); - if (ret) { + if (ret && ret != -EINVAL) { ath12k_warn(ar->ab, "failed to update chan list for pdev %u, ret %d\n", i, ret); @@ -102,6 +102,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) /* Send the reg change request to all the radios */ for_each_ar(ah, ar, i) { + reinit_completion(&ar->regd_update_completed); + if (ar->ab->hw_params->current_cc_support) { memcpy(¤t_arg.alpha2, request->alpha2, 2); memcpy(&ar->alpha2, ¤t_arg.alpha2, 2); @@ -137,32 +139,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait) struct ath12k_wmi_channel_arg *ch; enum nl80211_band band; int num_channels = 0; - int i, ret, left; - - if (wait && ar->state_11d == ATH12K_11D_RUNNING) { - left = wait_for_completion_timeout(&ar->completed_11d_scan, - ATH12K_SCAN_TIMEOUT_HZ); - if (!left) { - ath12k_dbg(ar->ab, ATH12K_DBG_REG, - "failed to receive 11d scan complete: timed out\n"); - ar->state_11d = ATH12K_11D_IDLE; - } - ath12k_dbg(ar->ab, ATH12K_DBG_REG, - "reg 11d scan wait left time %d\n", left); - } - - if (wait && - (ar->scan.state == ATH12K_SCAN_STARTING || - ar->scan.state == ATH12K_SCAN_RUNNING)) { - left = wait_for_completion_timeout(&ar->scan.completed, - ATH12K_SCAN_TIMEOUT_HZ); - if (!left) - ath12k_dbg(ar->ab, ATH12K_DBG_REG, - "failed to receive hw scan complete: timed out\n"); - - ath12k_dbg(ar->ab, ATH12K_DBG_REG, - "reg hw scan wait left time %d\n", left); - } + int i, ret = 0; if (ar->ah->state == ATH12K_HW_STATE_RESTARTING) return 0; @@ -176,13 +153,22 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait) if (bands[band]->channels[i].flags & IEEE80211_CHAN_DISABLED) continue; + /* Skip Channels that are not in current radio's range */ + if (bands[band]->channels[i].center_freq < + KHZ_TO_MHZ(ar->freq_range.start_freq) || + bands[band]->channels[i].center_freq > + KHZ_TO_MHZ(ar->freq_range.end_freq)) + continue; num_channels++; } } - if (WARN_ON(!num_channels)) + if (!num_channels) { + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "pdev is not supported for this country\n"); return -EINVAL; + } arg = kzalloc(struct_size(arg, channel, num_channels), GFP_KERNEL); @@ -204,6 +190,13 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait) if (channel->flags & IEEE80211_CHAN_DISABLED) continue; + /* Skip Channels that are not in current radio's range */ + if (bands[band]->channels[i].center_freq < + KHZ_TO_MHZ(ar->freq_range.start_freq) || + bands[band]->channels[i].center_freq > + KHZ_TO_MHZ(ar->freq_range.end_freq)) + continue; + /* TODO: Set to true/false based on some condition? */ ch->allow_ht = true; ch->allow_vht = true; @@ -244,6 +237,16 @@ int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait) } } + if (wait) { + spin_lock_bh(&ar->data_lock); + list_add_tail(&arg->list, &ar->regd_channel_update_queue); + spin_unlock_bh(&ar->data_lock); + + queue_work(ar->ab->workqueue, &ar->regd_channel_update_work); + + return 0; + } + ret = ath12k_wmi_send_scan_chan_list_cmd(ar, arg); kfree(arg); @@ -272,9 +275,19 @@ int ath12k_regd_update(struct ath12k *ar, bool init) struct ieee80211_regdomain *regd, *regd_copy = NULL; int ret, regd_len, pdev_id; struct ath12k_base *ab; + long time_left; ab = ar->ab; + time_left = wait_for_completion_timeout(&ar->regd_update_completed, + ATH12K_REG_UPDATE_TIMEOUT_HZ); + if (time_left == 0) { + ath12k_warn(ab, "Timeout while waiting for regulatory update"); + /* Even though timeout has occurred, still continue since at least boot + * time data would be there to process + */ + } + supported_bands = ar->pdev->cap.supported_bands; reg_cap = &ab->hal_reg_cap[ar->pdev_idx]; @@ -413,6 +426,29 @@ ath12k_map_fw_dfs_region(enum ath12k_dfs_region dfs_region) } } +static u32 ath12k_get_bw_reg_flags(u16 max_bw) +{ + switch (max_bw) { + case 20: + return NL80211_RRF_NO_HT40 | + NL80211_RRF_NO_80MHZ | + NL80211_RRF_NO_160MHZ | + NL80211_RRF_NO_320MHZ; + case 40: + return NL80211_RRF_NO_80MHZ | + NL80211_RRF_NO_160MHZ | + NL80211_RRF_NO_320MHZ; + case 80: + return NL80211_RRF_NO_160MHZ | + NL80211_RRF_NO_320MHZ; + case 160: + return NL80211_RRF_NO_320MHZ; + case 320: + default: + return 0; + } +} + static u32 ath12k_map_fw_reg_flags(u16 reg_flags) { u32 flags = 0; @@ -691,7 +727,7 @@ ath12k_reg_build_regd(struct ath12k_base *ab, reg_rule = reg_info->reg_rules_2g_ptr + i; max_bw = min_t(u16, reg_rule->max_bw, reg_info->max_bw_2g); - flags = 0; + flags = ath12k_get_bw_reg_flags(reg_info->max_bw_2g); ath12k_reg_update_freq_range(&ab->reg_freq_2ghz, reg_rule); } else if (reg_info->num_5g_reg_rules && (j < reg_info->num_5g_reg_rules)) { @@ -705,13 +741,15 @@ ath12k_reg_build_regd(struct ath12k_base *ab, * BW correction if required and applies flags as * per other BW rule flags we pass from here */ - flags = NL80211_RRF_AUTO_BW; + flags = NL80211_RRF_AUTO_BW | + ath12k_get_bw_reg_flags(reg_info->max_bw_5g); ath12k_reg_update_freq_range(&ab->reg_freq_5ghz, reg_rule); } else if (reg_info->is_ext_reg_event && reg_6ghz_number && (k < reg_6ghz_number)) { reg_rule = reg_rule_6ghz + k++; max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz); - flags = NL80211_RRF_AUTO_BW; + flags = NL80211_RRF_AUTO_BW | + ath12k_get_bw_reg_flags(max_bw_6ghz); if (reg_rule->psd_flag) flags |= NL80211_RRF_PSD; ath12k_reg_update_freq_range(&ab->reg_freq_6ghz, reg_rule); @@ -764,6 +802,54 @@ ret: return new_regd; } +void ath12k_regd_update_chan_list_work(struct work_struct *work) +{ + struct ath12k *ar = container_of(work, struct ath12k, + regd_channel_update_work); + struct ath12k_wmi_scan_chan_list_arg *arg; + struct list_head local_update_list; + int left; + + INIT_LIST_HEAD(&local_update_list); + + spin_lock_bh(&ar->data_lock); + list_splice_tail_init(&ar->regd_channel_update_queue, &local_update_list); + spin_unlock_bh(&ar->data_lock); + + while ((arg = list_first_entry_or_null(&local_update_list, + struct ath12k_wmi_scan_chan_list_arg, + list))) { + if (ar->state_11d != ATH12K_11D_IDLE) { + left = wait_for_completion_timeout(&ar->completed_11d_scan, + ATH12K_SCAN_TIMEOUT_HZ); + if (!left) { + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "failed to receive 11d scan complete: timed out\n"); + ar->state_11d = ATH12K_11D_IDLE; + } + + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "reg 11d scan wait left time %d\n", left); + } + + if ((ar->scan.state == ATH12K_SCAN_STARTING || + ar->scan.state == ATH12K_SCAN_RUNNING)) { + left = wait_for_completion_timeout(&ar->scan.completed, + ATH12K_SCAN_TIMEOUT_HZ); + if (!left) + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "failed to receive hw scan complete: timed out\n"); + + ath12k_dbg(ar->ab, ATH12K_DBG_REG, + "reg hw scan wait left time %d\n", left); + } + + ath12k_wmi_send_scan_chan_list_cmd(ar, arg); + list_del(&arg->list); + kfree(arg); + } +} + void ath12k_regd_update_work(struct work_struct *work) { struct ath12k *ar = container_of(work, struct ath12k, diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h index 8af8e9ba462e..da5128b8c97f 100644 --- a/drivers/net/wireless/ath/ath12k/reg.h +++ b/drivers/net/wireless/ath/ath12k/reg.h @@ -13,6 +13,8 @@ struct ath12k_base; struct ath12k; +#define ATH12K_REG_UPDATE_TIMEOUT_HZ (3 * HZ) + #define ATH12K_2GHZ_MAX_FREQUENCY 2495 #define ATH12K_5GHZ_MAX_FREQUENCY 5920 @@ -113,6 +115,7 @@ int ath12k_reg_handle_chan_list(struct ath12k_base *ab, struct ath12k_reg_info *reg_info, enum wmi_vdev_type vdev_type, enum ieee80211_ap_reg_power power_type); +void ath12k_regd_update_chan_list_work(struct work_struct *work); enum wmi_reg_6g_ap_type ath12k_reg_ap_pwr_convert(enum ieee80211_ap_reg_power power_type); enum ath12k_reg_status ath12k_reg_validate_reg_info(struct ath12k_base *ab, diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 465f877fc0fb..da85c28ec355 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -201,10 +201,9 @@ static __le32 ath12k_wmi_tlv_cmd_hdr(u32 cmd, u32 len) void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config) { - config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS; + config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS(ab); config->num_peers = ab->num_radios * ath12k_core_get_max_peers_per_radio(ab); - config->num_tids = ath12k_core_get_max_num_tids(ab); config->num_offload_peers = TARGET_NUM_OFFLD_PEERS; config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS; config->num_peer_keys = TARGET_NUM_PEER_KEYS; @@ -537,6 +536,10 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, pdev_cap->he_mcs = le32_to_cpu(mac_caps->he_supp_mcs_5g); pdev_cap->tx_chain_mask = le32_to_cpu(mac_caps->tx_chain_mask_5g); pdev_cap->rx_chain_mask = le32_to_cpu(mac_caps->rx_chain_mask_5g); + pdev_cap->nss_ratio_enabled = + WMI_NSS_RATIO_EN_DIS_GET(mac_caps->nss_ratio); + pdev_cap->nss_ratio_info = + WMI_NSS_RATIO_INFO_GET(mac_caps->nss_ratio); } else { return -EINVAL; } @@ -782,20 +785,46 @@ struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_ab, u32 len) return skb; } -int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, +int ath12k_wmi_mgmt_send(struct ath12k_link_vif *arvif, u32 buf_id, struct sk_buff *frame) { + struct ath12k *ar = arvif->ar; struct ath12k_wmi_pdev *wmi = ar->wmi; struct wmi_mgmt_send_cmd *cmd; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(frame); - struct wmi_tlv *frame_tlv; + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)frame->data; + struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); + int cmd_len = sizeof(struct ath12k_wmi_mgmt_send_tx_params); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)hdr; + struct ath12k_wmi_mlo_mgmt_send_params *ml_params; + struct ath12k_base *ab = ar->ab; + struct wmi_tlv *frame_tlv, *tlv; + struct ath12k_skb_cb *skb_cb; + u32 buf_len, buf_len_aligned; + u32 vdev_id = arvif->vdev_id; + bool link_agnostic = false; struct sk_buff *skb; - u32 buf_len; int ret, len; + void *ptr; buf_len = min_t(int, frame->len, WMI_MGMT_SEND_DOWNLD_LEN); - len = sizeof(*cmd) + sizeof(*frame_tlv) + roundup(buf_len, 4); + buf_len_aligned = roundup(buf_len, sizeof(u32)); + + len = sizeof(*cmd) + sizeof(*frame_tlv) + buf_len_aligned; + + if (ieee80211_vif_is_mld(vif)) { + skb_cb = ATH12K_SKB_CB(frame); + if ((skb_cb->flags & ATH12K_SKB_MLO_STA) && + ab->hw_params->hw_ops->is_frame_link_agnostic && + ab->hw_params->hw_ops->is_frame_link_agnostic(arvif, mgmt)) { + len += cmd_len + TLV_HDR_SIZE + sizeof(*ml_params); + ath12k_generic_dbg(ATH12K_DBG_MGMT, + "Sending Mgmt Frame fc 0x%0x as link agnostic", + mgmt->frame_control); + link_agnostic = true; + } + } skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); if (!skb) @@ -818,6 +847,28 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, memcpy(frame_tlv->value, frame->data, buf_len); + if (!link_agnostic) + goto send; + + ptr = skb->data + sizeof(*cmd) + sizeof(*frame_tlv) + buf_len_aligned; + + tlv = ptr; + + /* Tx params not used currently */ + tlv->header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_TX_SEND_PARAMS, cmd_len); + ptr += cmd_len; + + tlv = ptr; + tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, sizeof(*ml_params)); + ptr += TLV_HDR_SIZE; + + ml_params = ptr; + ml_params->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_MLO_TX_SEND_PARAMS, + sizeof(*ml_params)); + + ml_params->hw_link_id = cpu_to_le32(WMI_MGMT_LINK_AGNOSTIC_ID); + +send: ret = ath12k_wmi_cmd_send(wmi, skb, WMI_MGMT_TX_SEND_CMDID); if (ret) { ath12k_warn(ar->ab, @@ -1059,15 +1110,14 @@ static void ath12k_wmi_put_wmi_channel(struct ath12k_wmi_channel_params *chan, chan->band_center_freq2 = cpu_to_le32(center_freq1); - } else if (arg->mode == MODE_11BE_EHT160) { + } else if (arg->mode == MODE_11BE_EHT160 || + arg->mode == MODE_11AX_HE160) { if (arg->freq > center_freq1) chan->band_center_freq1 = cpu_to_le32(center_freq1 + 40); else chan->band_center_freq1 = cpu_to_le32(center_freq1 - 40); chan->band_center_freq2 = cpu_to_le32(center_freq1); - } else if (arg->mode == MODE_11BE_EHT80_80) { - chan->band_center_freq2 = cpu_to_le32(arg->band_center_freq2); } else { chan->band_center_freq2 = 0; } @@ -2013,6 +2063,9 @@ int ath12k_wmi_bcn_tmpl(struct ath12k_link_vif *arvif, u32p_replace_bits(&ema_params, 1, WMI_EMA_BEACON_LAST); cmd->ema_params = cpu_to_le32(ema_params); } + cmd->feature_enable_bitmap = + cpu_to_le32(u32_encode_bits(arvif->beacon_prot, + WMI_BEACON_PROTECTION_EN_BIT)); ptr = skb->data + sizeof(*cmd); @@ -2152,7 +2205,7 @@ static void ath12k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, cmd->peer_flags |= cpu_to_le32(WMI_PEER_AUTH); if (arg->need_ptk_4_way) { cmd->peer_flags |= cpu_to_le32(WMI_PEER_NEED_PTK_4_WAY); - if (!hw_crypto_disabled) + if (!hw_crypto_disabled && arg->is_assoc) cmd->peer_flags &= cpu_to_le32(~WMI_PEER_AUTH); } if (arg->need_gtk_2_way) @@ -3880,7 +3933,8 @@ ath12k_wmi_copy_resource_config(struct ath12k_base *ab, wmi_cfg->max_bssid_rx_filters = cpu_to_le32(tg_cfg->max_bssid_rx_filters); wmi_cfg->use_pdev_id = cpu_to_le32(tg_cfg->use_pdev_id); wmi_cfg->flag1 = cpu_to_le32(tg_cfg->atf_config | - WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64); + WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 | + WMI_RSRC_CFG_FLAG1_ACK_RSSI); wmi_cfg->peer_map_unmap_version = cpu_to_le32(tg_cfg->peer_map_unmap_version); wmi_cfg->sched_params = cpu_to_le32(tg_cfg->sched_params); wmi_cfg->twt_ap_pdev_count = cpu_to_le32(tg_cfg->twt_ap_pdev_count); @@ -6116,7 +6170,7 @@ static int ath12k_pull_mgmt_rx_params_tlv(struct ath12k_base *ab, } static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, - u32 status) + u32 status, u32 ack_rssi) { struct sk_buff *msdu; struct ieee80211_tx_info *info; @@ -6140,8 +6194,16 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, dma_unmap_single(ar->ab->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); info = IEEE80211_SKB_CB(msdu); - if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) + memset(&info->status, 0, sizeof(info->status)); + + /* skip tx rate update from ieee80211_status*/ + info->status.rates[0].idx = -1; + + if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) { info->flags |= IEEE80211_TX_STAT_ACK; + info->status.ack_signal = ack_rssi; + info->status.flags |= IEEE80211_TX_STATUS_ACK_SIGNAL_VALID; + } if ((info->flags & IEEE80211_TX_CTL_NO_ACK) && !status) info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; @@ -6185,6 +6247,8 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, param->pdev_id = ev->pdev_id; param->desc_id = ev->desc_id; param->status = ev->status; + param->ppdu_id = ev->ppdu_id; + param->ack_rssi = ev->ack_rssi; kfree(tb); return 0; @@ -6445,9 +6509,16 @@ static int freq_to_idx(struct ath12k *ar, int freq) if (!sband) continue; - for (ch = 0; ch < sband->n_channels; ch++, idx++) + for (ch = 0; ch < sband->n_channels; ch++, idx++) { + if (sband->channels[ch].center_freq < + KHZ_TO_MHZ(ar->freq_range.start_freq) || + sband->channels[ch].center_freq > + KHZ_TO_MHZ(ar->freq_range.end_freq)) + continue; + if (sband->channels[ch].center_freq == freq) goto exit; + } } exit: @@ -6677,7 +6748,8 @@ static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab, static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb) { struct ath12k_reg_info *reg_info; - u8 pdev_idx; + struct ath12k *ar = NULL; + u8 pdev_idx = 255; int ret; reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC); @@ -6732,7 +6804,7 @@ mem_free: kfree(reg_info); if (ret == ATH12K_REG_STATUS_VALID) - return ret; + goto out; fallback: /* Fallback to older reg (by sending previous country setting @@ -6746,6 +6818,18 @@ fallback: WARN_ON(1); out: + /* In some error cases, even a valid pdev_idx might not be available */ + if (pdev_idx != 255) + ar = ab->pdevs[pdev_idx].ar; + + /* During the boot-time update, 'ar' might not be allocated, + * so the completion cannot be marked at that point. + * This boot-time update is handled in ath12k_mac_hw_register() + * before registering the hardware. + */ + if (ar) + complete_all(&ar->regd_update_completed); + return ret; } @@ -6955,12 +7039,13 @@ static void ath12k_vdev_stopped_event(struct ath12k_base *ab, struct sk_buff *sk static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct ath12k_wmi_mgmt_rx_arg rx_ev = {0}; + struct ath12k_wmi_mgmt_rx_arg rx_ev = {}; struct ath12k *ar; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_hdr *hdr; u16 fc; struct ieee80211_supported_band *sband; + s32 noise_floor; if (ath12k_pull_mgmt_rx_params_tlv(ab, skb, &rx_ev) != 0) { ath12k_warn(ab, "failed to extract mgmt rx event"); @@ -7022,7 +7107,11 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) status->freq = ieee80211_channel_to_frequency(rx_ev.channel, status->band); - status->signal = rx_ev.snr + ATH12K_DEFAULT_NOISE_FLOOR; + spin_lock_bh(&ar->data_lock); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + + status->signal = rx_ev.snr + noise_floor; status->rate_idx = ath12k_mac_bitrate_to_idx(sband, rx_ev.rate / 100); hdr = (struct ieee80211_hdr *)skb->data; @@ -7069,7 +7158,7 @@ exit: static void ath12k_mgmt_tx_compl_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct wmi_mgmt_tx_compl_event tx_compl_param = {0}; + struct wmi_mgmt_tx_compl_event tx_compl_param = {}; struct ath12k *ar; if (ath12k_pull_mgmt_tx_compl_param_tlv(ab, skb, &tx_compl_param) != 0) { @@ -7086,7 +7175,8 @@ static void ath12k_mgmt_tx_compl_event(struct ath12k_base *ab, struct sk_buff *s } wmi_process_mgmt_tx_comp(ar, le32_to_cpu(tx_compl_param.desc_id), - le32_to_cpu(tx_compl_param.status)); + le32_to_cpu(tx_compl_param.status), + le32_to_cpu(tx_compl_param.ack_rssi)); ath12k_dbg(ab, ATH12K_DBG_MGMT, "mgmt tx compl ev pdev_id %d, desc_id %d, status %d", @@ -7126,7 +7216,7 @@ static struct ath12k *ath12k_get_ar_on_scan_state(struct ath12k_base *ab, static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb) { struct ath12k *ar; - struct wmi_scan_event scan_ev = {0}; + struct wmi_scan_event scan_ev = {}; if (ath12k_pull_scan_ev(ab, skb, &scan_ev) != 0) { ath12k_warn(ab, "failed to extract scan event"); @@ -7303,7 +7393,7 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb) static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct wmi_chan_info_event ch_info_ev = {0}; + struct wmi_chan_info_event ch_info_ev = {}; struct ath12k *ar; struct survey_info *survey; int idx; @@ -7451,7 +7541,7 @@ exit: static void ath12k_vdev_install_key_compl_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct wmi_vdev_install_key_complete_arg install_key_compl = {0}; + struct wmi_vdev_install_key_complete_arg install_key_compl = {}; struct ath12k *ar; if (ath12k_pull_vdev_install_key_compl_ev(ab, skb, &install_key_compl) != 0) { @@ -7491,7 +7581,8 @@ static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, void *data) { const struct wmi_service_available_event *ev; - u32 *wmi_ext2_service_bitmap; + u16 wmi_ext2_service_words; + __le32 *wmi_ext2_service_bitmap; int i, j; u16 expected_len; @@ -7523,21 +7614,21 @@ static int ath12k_wmi_tlv_services_parser(struct ath12k_base *ab, ev->wmi_service_segment_bitmap[3]); break; case WMI_TAG_ARRAY_UINT32: - wmi_ext2_service_bitmap = (u32 *)ptr; + wmi_ext2_service_bitmap = (__le32 *)ptr; + wmi_ext2_service_words = len / sizeof(u32); for (i = 0, j = WMI_MAX_EXT_SERVICE; - i < WMI_SERVICE_SEGMENT_BM_SIZE32 && j < WMI_MAX_EXT2_SERVICE; + i < wmi_ext2_service_words && j < WMI_MAX_EXT2_SERVICE; i++) { do { - if (wmi_ext2_service_bitmap[i] & + if (__le32_to_cpu(wmi_ext2_service_bitmap[i]) & BIT(j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32)) set_bit(j, ab->wmi_ab.svc_map); } while (++j % WMI_AVAIL_SERVICE_BITS_IN_SIZE32); + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi_ext2_service bitmap 0x%08x\n", + __le32_to_cpu(wmi_ext2_service_bitmap[i])); } - ath12k_dbg(ab, ATH12K_DBG_WMI, - "wmi_ext2_service_bitmap 0x%04x 0x%04x 0x%04x 0x%04x", - wmi_ext2_service_bitmap[0], wmi_ext2_service_bitmap[1], - wmi_ext2_service_bitmap[2], wmi_ext2_service_bitmap[3]); break; } return 0; @@ -7555,7 +7646,7 @@ static int ath12k_service_available_event(struct ath12k_base *ab, struct sk_buff static void ath12k_peer_assoc_conf_event(struct ath12k_base *ab, struct sk_buff *skb) { - struct wmi_peer_assoc_conf_arg peer_assoc_conf = {0}; + struct wmi_peer_assoc_conf_arg peer_assoc_conf = {}; struct ath12k *ar; if (ath12k_pull_peer_assoc_conf_ev(ab, skb, &peer_assoc_conf) != 0) { @@ -8501,7 +8592,7 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab, struct sk_buff *skb) { struct ath12k *ar; - struct wmi_pdev_temperature_event ev = {0}; + struct wmi_pdev_temperature_event ev = {}; if (ath12k_pull_pdev_temp_ev(ab, skb, &ev) != 0) { ath12k_warn(ab, "failed to extract pdev temperature event"); @@ -9299,6 +9390,229 @@ static void ath12k_wmi_process_tpc_stats(struct ath12k_base *ab, } #endif +static int +ath12k_wmi_rssi_dbm_conv_info_evt_subtlv_parser(struct ath12k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + const struct ath12k_wmi_rssi_dbm_conv_temp_info_params *temp_info; + const struct ath12k_wmi_rssi_dbm_conv_info_params *param_info; + struct ath12k_wmi_rssi_dbm_conv_info_arg *rssi_info = data; + struct ath12k_wmi_rssi_dbm_conv_param_arg param_arg; + s32 nf_hw_dbm[ATH12K_MAX_NUM_NF_HW_DBM]; + u8 num_20mhz_segments; + s8 min_nf, *nf_ptr; + int i, j; + + switch (tag) { + case WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO: + if (len < sizeof(*param_info)) { + ath12k_warn(ab, + "RSSI dbm conv subtlv 0x%x invalid len %d rcvd", + tag, len); + return -EINVAL; + } + + param_info = ptr; + + param_arg.curr_bw = le32_to_cpu(param_info->curr_bw); + param_arg.curr_rx_chainmask = le32_to_cpu(param_info->curr_rx_chainmask); + + /* The received array is actually a 2D byte-array for per chain, + * per 20MHz subband. Convert to 2D byte-array + */ + nf_ptr = ¶m_arg.nf_hw_dbm[0][0]; + + for (i = 0; i < ATH12K_MAX_NUM_NF_HW_DBM; i++) { + nf_hw_dbm[i] = a_sle32_to_cpu(param_info->nf_hw_dbm[i]); + + for (j = 0; j < 4; j++) { + *nf_ptr = (nf_hw_dbm[i] >> (j * 8)) & 0xFF; + nf_ptr++; + } + } + + switch (param_arg.curr_bw) { + case WMI_CHAN_WIDTH_20: + num_20mhz_segments = 1; + break; + case WMI_CHAN_WIDTH_40: + num_20mhz_segments = 2; + break; + case WMI_CHAN_WIDTH_80: + num_20mhz_segments = 4; + break; + case WMI_CHAN_WIDTH_160: + num_20mhz_segments = 8; + break; + case WMI_CHAN_WIDTH_320: + num_20mhz_segments = 16; + break; + default: + ath12k_warn(ab, "Invalid current bandwidth %d in RSSI dbm event", + param_arg.curr_bw); + /* In error case, still consider the primary 20 MHz segment since + * that would be much better than instead of dropping the whole + * event + */ + num_20mhz_segments = 1; + } + + min_nf = ATH12K_DEFAULT_NOISE_FLOOR; + + for (i = 0; i < ATH12K_MAX_NUM_ANTENNA; i++) { + if (!(param_arg.curr_rx_chainmask & BIT(i))) + continue; + + for (j = 0; j < num_20mhz_segments; j++) { + if (param_arg.nf_hw_dbm[i][j] < min_nf) + min_nf = param_arg.nf_hw_dbm[i][j]; + } + } + + rssi_info->min_nf_dbm = min_nf; + rssi_info->nf_dbm_present = true; + break; + case WMI_TAG_RSSI_DBM_CONVERSION_TEMP_OFFSET_INFO: + if (len < sizeof(*temp_info)) { + ath12k_warn(ab, + "RSSI dbm conv subtlv 0x%x invalid len %d rcvd", + tag, len); + return -EINVAL; + } + + temp_info = ptr; + rssi_info->temp_offset = a_sle32_to_cpu(temp_info->offset); + rssi_info->temp_offset_present = true; + break; + default: + ath12k_dbg(ab, ATH12K_DBG_WMI, + "Unknown subtlv 0x%x in RSSI dbm conversion event\n", tag); + } + + return 0; +} + +static int +ath12k_wmi_rssi_dbm_conv_info_event_parser(struct ath12k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + int ret = 0; + + switch (tag) { + case WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO_FIXED_PARAM: + /* Fixed param is already processed*/ + break; + case WMI_TAG_ARRAY_STRUCT: + /* len 0 is expected for array of struct when there + * is no content of that type inside that tlv + */ + if (len == 0) + return 0; + + ret = ath12k_wmi_tlv_iter(ab, ptr, len, + ath12k_wmi_rssi_dbm_conv_info_evt_subtlv_parser, + data); + break; + default: + ath12k_dbg(ab, ATH12K_DBG_WMI, + "Received invalid tag 0x%x for RSSI dbm conv info event\n", + tag); + break; + } + + return ret; +} + +static int +ath12k_wmi_rssi_dbm_conv_info_process_fixed_param(struct ath12k_base *ab, u8 *ptr, + size_t len, int *pdev_id) +{ + struct ath12k_wmi_rssi_dbm_conv_info_fixed_params *fixed_param; + const struct wmi_tlv *tlv; + u16 tlv_tag; + + if (len < (sizeof(*fixed_param) + TLV_HDR_SIZE)) { + ath12k_warn(ab, "invalid RSSI dbm conv event size %zu\n", len); + return -EINVAL; + } + + tlv = (struct wmi_tlv *)ptr; + tlv_tag = le32_get_bits(tlv->header, WMI_TLV_TAG); + ptr += sizeof(*tlv); + + if (tlv_tag != WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO_FIXED_PARAM) { + ath12k_warn(ab, "RSSI dbm conv event received without fixed param tlv\n"); + return -EINVAL; + } + + fixed_param = (struct ath12k_wmi_rssi_dbm_conv_info_fixed_params *)ptr; + *pdev_id = le32_to_cpu(fixed_param->pdev_id); + + return 0; +} + +static void +ath12k_wmi_update_rssi_offsets(struct ath12k *ar, + struct ath12k_wmi_rssi_dbm_conv_info_arg *rssi_info) +{ + struct ath12k_pdev_rssi_offsets *info = &ar->rssi_info; + + lockdep_assert_held(&ar->data_lock); + + if (rssi_info->temp_offset_present) + info->temp_offset = rssi_info->temp_offset; + + if (rssi_info->nf_dbm_present) + info->min_nf_dbm = rssi_info->min_nf_dbm; + + info->noise_floor = info->min_nf_dbm + info->temp_offset; +} + +static void +ath12k_wmi_rssi_dbm_conversion_params_info_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + struct ath12k_wmi_rssi_dbm_conv_info_arg rssi_info; + struct ath12k *ar; + s32 noise_floor; + u32 pdev_id; + int ret; + + ret = ath12k_wmi_rssi_dbm_conv_info_process_fixed_param(ab, skb->data, skb->len, + &pdev_id); + if (ret) { + ath12k_warn(ab, "failed to parse fixed param in RSSI dbm conv event: %d\n", + ret); + return; + } + + rcu_read_lock(); + ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id); + /* If pdev is not active, ignore the event */ + if (!ar) + goto out_unlock; + + ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len, + ath12k_wmi_rssi_dbm_conv_info_event_parser, + &rssi_info); + if (ret) { + ath12k_warn(ab, "unable to parse RSSI dbm conversion event\n"); + goto out_unlock; + } + + spin_lock_bh(&ar->data_lock); + ath12k_wmi_update_rssi_offsets(ar, &rssi_info); + noise_floor = ath12k_pdev_get_noise_floor(ar); + spin_unlock_bh(&ar->data_lock); + + ath12k_dbg(ab, ATH12K_DBG_WMI, + "RSSI noise floor updated, new value is %d dbm\n", noise_floor); +out_unlock: + rcu_read_unlock(); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -9430,6 +9744,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_11D_NEW_COUNTRY_EVENTID: ath12k_reg_11d_new_cc_event(ab, skb); break; + case WMI_PDEV_RSSI_DBM_CONVERSION_PARAMS_INFO_EVENTID: + ath12k_wmi_rssi_dbm_conversion_params_info_event(ab, skb); + break; /* add Unsupported events (rare) here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index c640ffa180c8..f3b0a6f57ec2 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.h @@ -222,6 +222,22 @@ enum WMI_HOST_WLAN_BAND { WMI_HOST_WLAN_2GHZ_5GHZ_CAP = 3, }; +/* Parameters used for WMI_VDEV_PARAM_AUTORATE_MISC_CFG command. + * Used only for HE auto rate mode. + */ +enum { + /* HE LTF related configuration */ + WMI_HE_AUTORATE_LTF_1X = BIT(0), + WMI_HE_AUTORATE_LTF_2X = BIT(1), + WMI_HE_AUTORATE_LTF_4X = BIT(2), + + /* HE GI related configuration */ + WMI_AUTORATE_400NS_GI = BIT(8), + WMI_AUTORATE_800NS_GI = BIT(9), + WMI_AUTORATE_1600NS_GI = BIT(10), + WMI_AUTORATE_3200NS_GI = BIT(11), +}; + enum wmi_cmd_group { /* 0 to 2 are reserved */ WMI_GRP_START = 0x3, @@ -734,6 +750,8 @@ enum wmi_tlv_event_id { WMI_SERVICE_READY_EXT2_EVENTID, WMI_PDEV_GET_HALPHY_CAL_STATUS_EVENTID = WMI_SERVICE_READY_EXT2_EVENTID + 4, + WMI_PDEV_RSSI_DBM_CONVERSION_PARAMS_INFO_EVENTID = + WMI_PDEV_GET_HALPHY_CAL_STATUS_EVENTID + 5, WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV), WMI_VDEV_STOPPED_EVENTID, WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, @@ -1169,13 +1187,16 @@ enum wmi_tlv_vdev_param { WMI_VDEV_PARAM_HE_RANGE_EXT, WMI_VDEV_PARAM_ENABLE_BCAST_PROBE_RESPONSE, WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, + WMI_VDEV_PARAM_HE_LTF = 0x74, WMI_VDEV_PARAM_BA_MODE = 0x7e, + WMI_VDEV_PARAM_AUTORATE_MISC_CFG = 0x80, WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87, WMI_VDEV_PARAM_6GHZ_PARAMS = 0x99, WMI_VDEV_PARAM_PROTOTYPE = 0x8000, WMI_VDEV_PARAM_BSS_COLOR, WMI_VDEV_PARAM_SET_HEMU_MODE, WMI_VDEV_PARAM_HEOPS_0_31 = 0x8003, + WMI_VDEV_PARAM_SET_EHT_MU_MODE = 0x8005, }; enum wmi_tlv_peer_flags { @@ -1992,6 +2013,9 @@ enum wmi_tlv_tag { WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD = 0x3D8, WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD = 0x3D9, WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD = 0x3FB, + WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO_FIXED_PARAM = 0x427, + WMI_TAG_RSSI_DBM_CONVERSION_PARAMS_INFO, + WMI_TAG_RSSI_DBM_CONVERSION_TEMP_OFFSET_INFO, WMI_TAG_HALPHY_CTRL_PATH_CMD_FIXED_PARAM = 0x442, WMI_TAG_HALPHY_CTRL_PATH_EVENT_FIXED_PARAM, WMI_TAG_MAX @@ -2217,6 +2241,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213, WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219, WMI_TLV_SERVICE_EXT2_MSG = 220, + WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT = 244, WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253, WMI_MAX_EXT_SERVICE = 256, @@ -2230,6 +2255,7 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361, WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, + WMI_TLV_SERVICE_ETH_OFFLOAD = 461, WMI_MAX_EXT2_SERVICE, }; @@ -2309,6 +2335,21 @@ enum wmi_direct_buffer_module { WMI_DIRECT_BUF_MAX }; +/** + * enum wmi_nss_ratio - NSS ratio received from FW during service ready ext event + * @WMI_NSS_RATIO_1BY2_NSS: Max nss of 160MHz is equals to half of the max nss of 80MHz + * @WMI_NSS_RATIO_3BY4_NSS: Max nss of 160MHz is equals to 3/4 of the max nss of 80MHz + * @WMI_NSS_RATIO_1_NSS: Max nss of 160MHz is equals to the max nss of 80MHz + * @WMI_NSS_RATIO_2_NSS: Max nss of 160MHz is equals to two times the max nss of 80MHz + */ + +enum wmi_nss_ratio { + WMI_NSS_RATIO_1BY2_NSS, + WMI_NSS_RATIO_3BY4_NSS, + WMI_NSS_RATIO_1_NSS, + WMI_NSS_RATIO_2_NSS +}; + struct ath12k_wmi_pdev_band_arg { u32 pdev_id; u32 start_freq; @@ -2487,6 +2528,7 @@ struct wmi_init_cmd { #define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) #define WMI_RSRC_CFG_FLAG1_BSS_CHANNEL_INFO_64 BIT(5) #define WMI_RSRC_CFG_FLAGS2_CALC_NEXT_DTIM_COUNT_SET BIT(9) +#define WMI_RSRC_CFG_FLAG1_ACK_RSSI BIT(18) struct ath12k_wmi_resource_config_params { __le32 tlv_header; @@ -2628,6 +2670,12 @@ struct ath12k_wmi_hw_mode_cap_params { } __packed; #define WMI_MAX_HECAP_PHY_SIZE (3) +#define WMI_NSS_RATIO_EN_DIS_BITPOS BIT(0) +#define WMI_NSS_RATIO_EN_DIS_GET(_val) \ + le32_get_bits(_val, WMI_NSS_RATIO_EN_DIS_BITPOS) +#define WMI_NSS_RATIO_INFO_BITPOS GENMASK(4, 1) +#define WMI_NSS_RATIO_INFO_GET(_val) \ + le32_get_bits(_val, WMI_NSS_RATIO_INFO_BITPOS) /* pdev_id is present in lower 16 bits of pdev_and_hw_link_ids in * ath12k_wmi_mac_phy_caps_params & ath12k_wmi_caps_ext_params. @@ -3131,31 +3179,6 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg { #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFER BIT(3) -#define HECAP_PHYDWORD_0 0 -#define HECAP_PHYDWORD_1 1 -#define HECAP_PHYDWORD_2 2 - -#define HECAP_PHY_SU_BFER BIT(31) -#define HECAP_PHY_SU_BFEE BIT(0) -#define HECAP_PHY_MU_BFER BIT(1) -#define HECAP_PHY_UL_MUMIMO BIT(22) -#define HECAP_PHY_UL_MUOFDMA BIT(23) - -#define HECAP_PHY_SUBFMR_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_0], HECAP_PHY_SU_BFER) - -#define HECAP_PHY_SUBFME_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_1], HECAP_PHY_SU_BFEE) - -#define HECAP_PHY_MUBFMR_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_1], HECAP_PHY_MU_BFER) - -#define HECAP_PHY_ULMUMIMO_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_0], HECAP_PHY_UL_MUMIMO) - -#define HECAP_PHY_ULOFDMA_GET(hecap_phy) \ - u32_get_bits(hecap_phy[HECAP_PHYDWORD_0], HECAP_PHY_UL_MUOFDMA) - #define HE_MODE_SU_TX_BFEE BIT(0) #define HE_MODE_SU_TX_BFER BIT(1) #define HE_MODE_MU_TX_BFEE BIT(2) @@ -3167,8 +3190,31 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg { #define HE_DL_MUOFDMA_ENABLE 1 #define HE_UL_MUOFDMA_ENABLE 1 #define HE_DL_MUMIMO_ENABLE 1 +#define HE_UL_MUMIMO_ENABLE 1 #define HE_MU_BFEE_ENABLE 1 #define HE_SU_BFEE_ENABLE 1 +#define HE_MU_BFER_ENABLE 1 +#define HE_SU_BFER_ENABLE 1 + +#define EHT_MODE_SU_TX_BFEE BIT(0) +#define EHT_MODE_SU_TX_BFER BIT(1) +#define EHT_MODE_MU_TX_BFEE BIT(2) +#define EHT_MODE_MU_TX_BFER BIT(3) +#define EHT_MODE_DL_OFDMA BIT(4) +#define EHT_MODE_UL_OFDMA BIT(5) +#define EHT_MODE_MUMIMO BIT(6) +#define EHT_MODE_DL_OFDMA_TXBF BIT(7) +#define EHT_MODE_DL_OFDMA_MUMIMO BIT(8) +#define EHT_MODE_UL_OFDMA_MUMIMO BIT(9) + +#define EHT_DL_MUOFDMA_ENABLE 1 +#define EHT_UL_MUOFDMA_ENABLE 1 +#define EHT_DL_MUMIMO_ENABLE 1 +#define EHT_UL_MUMIMO_ENABLE 1 +#define EHT_MU_BFEE_ENABLE 1 +#define EHT_SU_BFEE_ENABLE 1 +#define EHT_MU_BFER_ENABLE 1 +#define EHT_SU_BFER_ENABLE 1 #define HE_VHT_SOUNDING_MODE_ENABLE 1 #define HE_SU_MU_SOUNDING_MODE_ENABLE 1 @@ -3632,6 +3678,15 @@ struct wmi_force_fw_hang_cmd { __le32 delay_time_ms; } __packed; +/* Param values to be sent for WMI_VDEV_PARAM_SGI param_id + * which are used in 11n, 11ac systems + * @WMI_GI_800_NS - Always uses 0.8us (Long GI) + * @WMI_GI_400_NS - Firmware switches between 0.4us (Short GI) + * and 0.8us (Long GI) based on packet error rate. + */ +#define WMI_GI_800_NS 0 +#define WMI_GI_400_NS 1 + struct wmi_vdev_set_param_cmd { __le32 tlv_header; __le32 vdev_id; @@ -3703,6 +3758,8 @@ struct ath12k_wmi_ftm_event { #define WMI_EMA_BEACON_FIRST GENMASK(23, 16) #define WMI_EMA_BEACON_LAST GENMASK(31, 24) +#define WMI_BEACON_PROTECTION_EN_BIT BIT(0) + struct ath12k_wmi_bcn_tmpl_ema_arg { u8 bcn_cnt; u8 bcn_index; @@ -3760,6 +3817,7 @@ struct wmi_vdev_install_key_arg { u32 key_idx; u32 key_flags; u32 key_cipher; + u32 ieee80211_key_cipher; u32 key_len; u32 key_txmic_len; u32 key_rxmic_len; @@ -3772,7 +3830,6 @@ struct wmi_vdev_install_key_arg { #define WMI_HOST_MAX_HE_RATE_SET 3 #define WMI_HECAP_TXRX_MCS_NSS_IDX_80 0 #define WMI_HECAP_TXRX_MCS_NSS_IDX_160 1 -#define WMI_HECAP_TXRX_MCS_NSS_IDX_80_80 2 #define ATH12K_WMI_MLO_MAX_PARTNER_LINKS \ (ATH12K_WMI_MLO_MAX_LINKS + ATH12K_MAX_NUM_BRIDGE_LINKS - 1) @@ -3948,6 +4005,7 @@ struct wmi_stop_scan_cmd { } __packed; struct ath12k_wmi_scan_chan_list_arg { + struct list_head list; u32 pdev_id; u16 nallchans; struct ath12k_wmi_channel_arg channel[]; @@ -3961,6 +4019,7 @@ struct wmi_scan_chan_list_cmd { } __packed; #define WMI_MGMT_SEND_DOWNLD_LEN 64 +#define WMI_MGMT_LINK_AGNOSTIC_ID 0xFFFFFFFF #define WMI_TX_PARAMS_DWORD0_POWER GENMASK(7, 0) #define WMI_TX_PARAMS_DWORD0_MCS_MASK GENMASK(19, 8) @@ -3986,7 +4045,18 @@ struct wmi_mgmt_send_cmd { /* This TLV is followed by struct wmi_mgmt_frame */ - /* Followed by struct wmi_mgmt_send_params */ + /* Followed by struct ath12k_wmi_mlo_mgmt_send_params */ +} __packed; + +struct ath12k_wmi_mlo_mgmt_send_params { + __le32 tlv_header; + __le32 hw_link_id; +} __packed; + +struct ath12k_wmi_mgmt_send_tx_params { + __le32 tlv_header; + __le32 tx_param_dword0; + __le32 tx_param_dword1; } __packed; struct wmi_sta_powersave_mode_cmd { @@ -4459,6 +4529,8 @@ struct wmi_mgmt_tx_compl_event { __le32 desc_id; __le32 status; __le32 pdev_id; + __le32 ppdu_id; + __le32 ack_rssi; } __packed; struct wmi_scan_event { @@ -4670,7 +4742,7 @@ enum wmi_ap_ps_peer_param { #define DISABLE_SIFS_RESPONSE_TRIGGER 0 -#define WMI_MAX_KEY_INDEX 3 +#define WMI_MAX_KEY_INDEX 7 #define WMI_MAX_KEY_LEN 32 enum wmi_key_type { @@ -6174,6 +6246,43 @@ struct wmi_mlo_link_set_active_arg { struct wmi_ml_disallow_mode_bmap_arg disallow_bmap[WMI_ML_MAX_DISALLOW_BMAP_COMB]; }; +#define ATH12K_MAX_20MHZ_SEGMENTS 16 +#define ATH12K_MAX_NUM_ANTENNA 8 +#define ATH12K_MAX_NUM_NF_HW_DBM 32 + +struct ath12k_wmi_rssi_dbm_conv_info_fixed_params { + __le32 pdev_id; +} __packed; + +struct ath12k_wmi_rssi_dbm_conv_info_params { + __le32 curr_bw; + __le32 curr_rx_chainmask; + __le32 xbar_config; + a_sle32 xlna_bypass_offset; + a_sle32 xlna_bypass_threshold; + a_sle32 nf_hw_dbm[ATH12K_MAX_NUM_NF_HW_DBM]; +} __packed; + +struct ath12k_wmi_rssi_dbm_conv_temp_info_params { + a_sle32 offset; +} __packed; + +struct ath12k_wmi_rssi_dbm_conv_param_arg { + u32 curr_bw; + u32 curr_rx_chainmask; + u32 xbar_config; + s32 xlna_bypass_offset; + s32 xlna_bypass_threshold; + s8 nf_hw_dbm[ATH12K_MAX_NUM_ANTENNA][ATH12K_MAX_20MHZ_SEGMENTS]; +}; + +struct ath12k_wmi_rssi_dbm_conv_info_arg { + bool temp_offset_present; + s32 temp_offset; + bool nf_dbm_present; + s8 min_nf_dbm; +}; + void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, struct ath12k_wmi_resource_config_arg *config); void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -6181,7 +6290,7 @@ void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb, u32 cmd_id); struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len); -int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, +int ath12k_wmi_mgmt_send(struct ath12k_link_vif *arvif, u32 buf_id, struct sk_buff *frame); int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, const u8 *p2p_ie); diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index d81b2ad0b095..eca8145d3874 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -192,7 +192,7 @@ ath5k_remove_interface(struct ieee80211_hw *hw, * TODO: Phy disable/diversity etc */ static int -ath5k_config(struct ieee80211_hw *hw, u32 changed) +ath5k_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ath5k_hw *ah = hw->priv; struct ieee80211_conf *conf = &hw->conf; @@ -686,6 +686,7 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) * ath5k_set_coverage_class - Set IEEE 802.11 coverage class * * @hw: struct ieee80211_hw pointer + * @radio_idx: Radio index * @coverage_class: IEEE 802.11 coverage class number * * Mac80211 callback. Sets slot time, ACK timeout and CTS timeout for given @@ -693,7 +694,8 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) * reset. */ static void -ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +ath5k_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, + s16 coverage_class) { struct ath5k_hw *ah = hw->priv; @@ -704,7 +706,8 @@ ath5k_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) static int -ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +ath5k_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, + u32 rx_ant) { struct ath5k_hw *ah = hw->priv; @@ -721,7 +724,8 @@ ath5k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) static int -ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +ath5k_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct ath5k_hw *ah = hw->priv; diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index 4825f9cb9cb8..66b2dee39155 100644 --- a/drivers/net/wireless/ath/ath5k/phy.c +++ b/drivers/net/wireless/ath/ath5k/phy.c @@ -3116,10 +3116,7 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, pd_gain_overlap; /* Force each power step to be at least 0.5 dB */ - if ((pdadc_tmp[1] - pdadc_tmp[0]) > 1) - pwr_step = pdadc_tmp[1] - pdadc_tmp[0]; - else - pwr_step = 1; + pwr_step = max(pdadc_tmp[1] - pdadc_tmp[0], 1); /* If pdadc_0 is negative, we need to extrapolate * below this pdgain by a number of pwr_steps */ @@ -3144,11 +3141,8 @@ ath5k_combine_pwr_to_pdadc_curves(struct ath5k_hw *ah, continue; /* Force each power step to be at least 0.5 dB */ - if ((pdadc_tmp[table_size - 1] - pdadc_tmp[table_size - 2]) > 1) - pwr_step = pdadc_tmp[table_size - 1] - - pdadc_tmp[table_size - 2]; - else - pwr_step = 1; + pwr_step = max(pdadc_tmp[table_size - 1] - + pdadc_tmp[table_size - 2], 1); /* Extrapolate above */ while ((pdadc_0 < (s16) pdadc_n) && diff --git a/drivers/net/wireless/ath/ath5k/reg.h b/drivers/net/wireless/ath/ath5k/reg.h index 0ea1608b47fd..22101c96713f 100644 --- a/drivers/net/wireless/ath/ath5k/reg.h +++ b/drivers/net/wireless/ath/ath5k/reg.h @@ -543,7 +543,7 @@ * Queue control unit (QCU) registers [5211+] * * Card has 12 TX Queues but i see that only 0-9 are used (?) - * both in binary HAL (see ah.h) and ar5k. Each queue has it's own + * both in binary HAL (see ah.h) and ar5k. Each queue has its own * TXDP at addresses 0x0800 - 0x082c, a CBR (Constant Bit Rate) * configuration register (0x08c0 - 0x08ec), a ready time configuration * register (0x0900 - 0x092c), a misc configuration register (0x09c0 - diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 8c2e8081112e..88f0197fc041 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -1376,7 +1376,8 @@ void ath6kl_cfg80211_tkip_micerr_event(struct ath6kl_vif *vif, u8 keyid, GFP_KERNEL); } -static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx, + u32 changed) { struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy); struct ath6kl_vif *vif; @@ -1405,6 +1406,7 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, + int radio_idx, enum nl80211_tx_power_setting type, int mbm) { @@ -1441,6 +1443,7 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy, static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, struct wireless_dev *wdev, + int radio_idx, unsigned int link_id, int *dbm) { @@ -3242,7 +3245,7 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, wait, buf, len, no_cck); } -static int ath6kl_get_antenna(struct wiphy *wiphy, +static int ath6kl_get_antenna(struct wiphy *wiphy, int radio_idx, u32 *tx_ant, u32 *rx_ant) { struct ath6kl *ar = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 4f0a7a185fc9..830350bda531 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -91,7 +91,7 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) /* * Turn on power to get hardware (target) version and leave power - * on delibrately as we will boot the hardware anyway within few + * on deliberately as we will boot the hardware anyway within few * seconds. */ ret = ath6kl_hif_power_on(ar); diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c index d1942537ea10..c693783bb9de 100644 --- a/drivers/net/wireless/ath/ath6kl/hif.c +++ b/drivers/net/wireless/ath/ath6kl/hif.c @@ -513,7 +513,7 @@ static int proc_pending_irqs(struct ath6kl_device *dev, bool *done) out: /* * An optimization to bypass reading the IRQ status registers - * unecessarily which can re-wake the target, if upper layers + * unnecessarily which can re-wake the target, if upper layers * determine that we are in a low-throughput mode, we can rely on * taking another interrupt rather than re-checking the status * registers which can re-wake the target. diff --git a/drivers/net/wireless/ath/ath6kl/htc.h b/drivers/net/wireless/ath/ath6kl/htc.h index d3534a29c4f0..d61be202677c 100644 --- a/drivers/net/wireless/ath/ath6kl/htc.h +++ b/drivers/net/wireless/ath/ath6kl/htc.h @@ -485,7 +485,7 @@ struct htc_endpoint_stats { /* count of credits received via another endpoint */ u32 cred_from_ep0; - /* count of consummed credits */ + /* count of consumed credits */ u32 cred_cosumd; /* count of credits returned */ @@ -596,7 +596,7 @@ struct htc_target { /* protects free_ctrl_txbuf and free_ctrl_rxbuf */ spinlock_t htc_lock; - /* FIXME: does this protext rx_bufq and endpoint structures or what? */ + /* FIXME: does this protect rx_bufq and endpoint structures or what? */ spinlock_t rx_lock; /* protects endpoint->txq */ @@ -624,7 +624,7 @@ struct htc_target { int chk_irq_status_cnt; - /* counts the number of Tx without bundling continously per AC */ + /* counts the number of Tx without bundling continuously per AC */ u32 ac_tx_count[WMM_NUM_AC]; struct { diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index f8a94d764be6..122e07ef3965 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -938,7 +938,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, /* * if an AC has bundling disabled and no tx bundling - * has occured continously for a certain number of TX, + * has occurred continuously for a certain number of TX, * enable tx bundling for this AC */ if (!bundle_sent) { diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index 2f2edfe43761..7b823be9d846 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -718,7 +718,7 @@ static struct htc_packet *htc_lookup_tx_packet(struct htc_target *target, spin_lock_bh(&target->tx_lock); /* - * interate from the front of tx lookup queue + * iterate from the front of tx lookup queue * this lookup should be fast since lower layers completes in-order and * so the completed packet should be at the head of the list generally */ diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 9b100ee2ebc3..782209dcb782 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -207,7 +207,7 @@ static const struct ath6kl_hw hw_list[] = { /* * This configuration item sets the value of disconnect timeout - * Firmware delays sending the disconnec event to the host for this + * Firmware delays sending the disconnect event to the host for this * timeout after is gets disconnected from the current AP. * If the firmware successly roams within the disconnect timeout * it sends a new connect event @@ -221,7 +221,7 @@ struct sk_buff *ath6kl_buf_alloc(int size) struct sk_buff *skb; u16 reserved; - /* Add chacheline space at front and back of buffer */ + /* Add cacheline space at front and back of buffer */ reserved = roundup((2 * L1_CACHE_BYTES) + ATH6KL_DATA_OFFSET + sizeof(struct htc_packet) + ATH6KL_HTC_ALIGN_BYTES, 4); skb = dev_alloc_skb(size + reserved); diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index d62b96459751..59068ea3879b 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -583,7 +583,7 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) switch (vif->nw_type) { case AP_NETWORK: /* - * reconfigure any saved RSN IE capabilites in the beacon / + * reconfigure any saved RSN IE capabilities in the beacon / * probe response to stay in sync with the supplicant. */ if (vif->rsn_capab && diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 9ab091044706..83de40bc4445 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -486,7 +486,7 @@ static void ath6kl_sdio_irq_handler(struct sdio_func *func) ar_sdio = sdio_get_drvdata(func); atomic_set(&ar_sdio->irq_handling, 1); /* - * Release the host during interrups so we can pick it back up when + * Release the host during interrupts so we can pick it back up when * we process commands. */ sdio_release_host(ar_sdio->func); diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 5220809841a6..38bb501fc553 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -93,7 +93,7 @@ struct ath6kl_urb_context { #define ATH6KL_USB_EP_ADDR_APP_DATA_MP_OUT 0x03 #define ATH6KL_USB_EP_ADDR_APP_DATA_HP_OUT 0x04 -/* diagnostic command defnitions */ +/* diagnostic command definitions */ #define ATH6KL_USB_CONTROL_REQ_SEND_BMI_CMD 1 #define ATH6KL_USB_CONTROL_REQ_RECV_BMI_RESP 2 #define ATH6KL_USB_CONTROL_REQ_DIAG_CMD 3 @@ -882,7 +882,7 @@ static int ath6kl_usb_submit_ctrl_out(struct ath6kl_usb *ar_usb, return -ENOMEM; } - /* note: if successful returns number of bytes transfered */ + /* note: if successful returns number of bytes transferred */ ret = usb_control_msg(ar_usb->udev, usb_sndctrlpipe(ar_usb->udev, 0), req, @@ -914,7 +914,7 @@ static int ath6kl_usb_submit_ctrl_in(struct ath6kl_usb *ar_usb, return -ENOMEM; } - /* note: if successful returns number of bytes transfered */ + /* note: if successful returns number of bytes transferred */ ret = usb_control_msg(ar_usb->udev, usb_rcvctrlpipe(ar_usb->udev, 0), req, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 84317afe4651..08a154bce139 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -2601,7 +2601,7 @@ int ath6kl_wmi_create_pstream_cmd(struct wmi *wmi, u8 if_idx, } /* - * Indicate activty change to driver layer only if this is the + * Indicate activity change to driver layer only if this is the * first TSID to get created in this AC explicitly or an implicit * fat pipe is getting created. */ diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 68384159870b..3080d82e25cc 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -655,7 +655,7 @@ enum wmi_mgmt_frame_type { enum wmi_ie_field_type { WMI_RSN_IE_CAPB = 0x1, - WMI_IE_FULL = 0xFF, /* indicats full IE */ + WMI_IE_FULL = 0xFF, /* indicates full IE */ }; /* WMI_CONNECT_CMDID */ @@ -1178,10 +1178,10 @@ struct wmi_create_pstream_cmd { __le32 sba; __le32 medium_time; - /* in octects */ + /* in octets */ __le16 nominal_msdu; - /* in octects */ + /* in octets */ __le16 max_msdu; u8 traffic_class; @@ -1742,7 +1742,7 @@ struct wmi_scan_complete_event { /* * Special frame receive Event. - * Mechanism used to inform host of the receiption of the special frames. + * Mechanism used to inform host of the reception of the special frames. * Consists of special frame info header followed by special frame body. * The 802.11 header is not included. */ @@ -1860,7 +1860,7 @@ struct wmi_target_stats { /* * WMI_RSSI_THRESHOLD_EVENTID. * Indicate the RSSI events to host. Events are indicated when we breach a - * thresold value. + * threshold value. */ enum wmi_rssi_threshold_val { WMI_RSSI_THRESHOLD1_ABOVE = 0, diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 49b7ab26c477..802e6596a6a8 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -16,37 +16,21 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/nl80211.h> +#include <linux/of.h> #include <linux/platform_device.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> + #include "ath9k.h" -static const struct platform_device_id ath9k_platform_id_table[] = { - { - .name = "ath9k", - .driver_data = AR5416_AR9100_DEVID, - }, - { - .name = "ar933x_wmac", - .driver_data = AR9300_DEVID_AR9330, - }, - { - .name = "ar934x_wmac", - .driver_data = AR9300_DEVID_AR9340, - }, - { - .name = "qca955x_wmac", - .driver_data = AR9300_DEVID_QCA955X, - }, - { - .name = "qca953x_wmac", - .driver_data = AR9300_DEVID_AR953X, - }, - { - .name = "qca956x_wmac", - .driver_data = AR9300_DEVID_QCA956X, - }, +static const struct of_device_id ath9k_of_match_table[] = { + { .compatible = "qca,ar9130-wifi", .data = (void *)AR5416_AR9100_DEVID }, + { .compatible = "qca,ar9330-wifi", .data = (void *)AR9300_DEVID_AR9330 }, + { .compatible = "qca,ar9340-wifi", .data = (void *)AR9300_DEVID_AR9340 }, + { .compatible = "qca,qca9530-wifi", .data = (void *)AR9300_DEVID_AR953X }, + { .compatible = "qca,qca9550-wifi", .data = (void *)AR9300_DEVID_QCA955X }, + { .compatible = "qca,qca9560-wifi", .data = (void *)AR9300_DEVID_QCA956X }, {}, }; @@ -71,19 +55,14 @@ static const struct ath_bus_ops ath_ahb_bus_ops = { static int ath_ahb_probe(struct platform_device *pdev) { - void __iomem *mem; - struct ath_softc *sc; struct ieee80211_hw *hw; - const struct platform_device_id *id = platform_get_device_id(pdev); - int irq; - int ret = 0; + struct ath_softc *sc; struct ath_hw *ah; + void __iomem *mem; char hw_name[64]; - - if (!dev_get_platdata(&pdev->dev)) { - dev_err(&pdev->dev, "no platform data specified\n"); - return -EINVAL; - } + u16 dev_id; + int irq; + int ret; mem = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(mem)) { @@ -117,7 +96,8 @@ static int ath_ahb_probe(struct platform_device *pdev) goto err_free_hw; } - ret = ath9k_init_device(id->driver_data, sc, &ath_ahb_bus_ops); + dev_id = (u16)(kernel_ulong_t)of_device_get_match_data(&pdev->dev); + ret = ath9k_init_device(dev_id, sc, &ath_ahb_bus_ops); if (ret) { dev_err(&pdev->dev, "failed to initialize device\n"); goto err_irq; @@ -155,11 +135,11 @@ static struct platform_driver ath_ahb_driver = { .remove = ath_ahb_remove, .driver = { .name = "ath9k", + .of_match_table = ath9k_of_match_table, }, - .id_table = ath9k_platform_id_table, }; -MODULE_DEVICE_TABLE(platform, ath9k_platform_id_table); +MODULE_DEVICE_TABLE(of, ath9k_of_match_table); int ath_ahb_init(void) { diff --git a/drivers/net/wireless/ath/ath9k/common-beacon.c b/drivers/net/wireless/ath/ath9k/common-beacon.c index 01d6d3205a65..e4df89f2fa03 100644 --- a/drivers/net/wireless/ath/ath9k/common-beacon.c +++ b/drivers/net/wireless/ath/ath9k/common-beacon.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include "common.h" #define FUDGE 2 diff --git a/drivers/net/wireless/ath/ath9k/common-debug.c b/drivers/net/wireless/ath/ath9k/common-debug.c index 7aefb79f6bed..1ea070200e4a 100644 --- a/drivers/net/wireless/ath/ath9k/common-debug.c +++ b/drivers/net/wireless/ath/ath9k/common-debug.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include "common.h" static ssize_t read_file_modal_eeprom(struct file *file, char __user *user_buf, diff --git a/drivers/net/wireless/ath/ath9k/common-init.c b/drivers/net/wireless/ath/ath9k/common-init.c index 7c13a1deb3ac..da102c791712 100644 --- a/drivers/net/wireless/ath/ath9k/common-init.c +++ b/drivers/net/wireless/ath/ath9k/common-init.c @@ -16,6 +16,7 @@ /* We use the hw_value as an index into our private channel structure */ +#include <linux/export.h> #include "common.h" #define CHAN2G(_freq, _idx) { \ diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 300d178830ad..ca01a07f6630 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include <linux/relay.h> #include <linux/random.h> #include "ath9k.h" diff --git a/drivers/net/wireless/ath/ath9k/common.c b/drivers/net/wireless/ath/ath9k/common.c index 099f3d45c594..ffcf2276eb92 100644 --- a/drivers/net/wireless/ath/ath9k/common.c +++ b/drivers/net/wireless/ath/ath9k/common.c @@ -18,6 +18,7 @@ * Module for common driver code between ath9k and ath9k_htc */ +#include <linux/export.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/net/wireless/ath/ath9k/dynack.c b/drivers/net/wireless/ath/ath9k/dynack.c index 321ff54fdb42..598b3a2ad818 100644 --- a/drivers/net/wireless/ath/ath9k/dynack.c +++ b/drivers/net/wireless/ath/ath9k/dynack.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include "ath9k.h" #include "hw.h" #include "dynack.h" diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 19600018e562..0d6272ac0dac 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1172,7 +1172,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } -static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) +static int ath9k_htc_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); @@ -1737,12 +1737,14 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw, mutex_unlock(&priv->mutex); } -static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int ath9k_htc_set_rts_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { return 0; } static void ath9k_htc_set_coverage_class(struct ieee80211_hw *hw, + int radio_idx, s16 coverage_class) { struct ath9k_htc_priv *priv = hw->priv; @@ -1841,8 +1843,8 @@ struct base_eep_header *ath9k_htc_get_eeprom_base(struct ath9k_htc_priv *priv) } -static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, - u32 *rx_ant) +static int ath9k_htc_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct ath9k_htc_priv *priv = hw->priv; struct base_eep_header *pBase = ath9k_htc_get_eeprom_base(priv); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f9a774bd0e13..14de62c1a32b 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <linux/export.h> #include <linux/io.h> #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c56f4f3b8990..740a6fc7b067 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -1484,7 +1484,7 @@ static void ath9k_disable_ps(struct ath_softc *sc) ath_dbg(common, PS, "PowerSave disabled\n"); } -static int ath9k_config(struct ieee80211_hw *hw, u32 changed) +static int ath9k_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; @@ -2114,6 +2114,7 @@ static void ath9k_enable_dynack(struct ath_softc *sc) } static void ath9k_set_coverage_class(struct ieee80211_hw *hw, + int radio_idx, s16 coverage_class) { struct ath_softc *sc = hw->priv; @@ -2338,7 +2339,8 @@ static bool validate_antenna_mask(struct ath_hw *ah, u32 val) } } -static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +static int ath9k_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; @@ -2367,7 +2369,8 @@ static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) return 0; } -static int ath9k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +static int ath9k_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct ath_softc *sc = hw->priv; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 755c068e4197..a7a9345f3483 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -890,7 +890,7 @@ static void carl9170_stat_work(struct work_struct *work) round_jiffies(msecs_to_jiffies(CARL9170_STAT_WORK))); } -static int carl9170_op_config(struct ieee80211_hw *hw, u32 changed) +static int carl9170_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ar9170 *ar = hw->priv; int err = 0; diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c index 89f4b0513946..d79d73738a81 100644 --- a/drivers/net/wireless/ath/main.c +++ b/drivers/net/wireless/ath/main.c @@ -16,6 +16,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/export.h> #include <linux/kernel.h> #include <linux/module.h> diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c index 94d08d6ae1a3..02a525645bfa 100644 --- a/drivers/net/wireless/ath/wcn36xx/main.c +++ b/drivers/net/wireless/ath/wcn36xx/main.c @@ -361,7 +361,7 @@ static void wcn36xx_change_opchannel(struct wcn36xx *wcn, int ch) return; } -static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed) +static int wcn36xx_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct wcn36xx *wcn = hw->priv; int ret; @@ -965,7 +965,8 @@ out: } /* this is required when using IEEE80211_HW_HAS_RATE_CONTROL */ -static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int wcn36xx_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct wcn36xx *wcn = hw->priv; wcn36xx_dbg(WCN36XX_DBG_MAC, "mac set RTS threshold %d\n", value); diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index 5473c01cbe66..7703a0933a14 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -1408,7 +1408,8 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy, return rc; } -static int wil_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +static int wil_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx, + u32 changed) { struct wil6210_priv *wil = wiphy_to_wil(wiphy); int rc; diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c index 74edd007cd8d..6d376f85fbde 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.c +++ b/drivers/net/wireless/ath/wil6210/wmi.c @@ -53,7 +53,7 @@ MODULE_PARM_DESC(led_id, * * There are several buses present on the WIL6210 card. * Same memory areas are visible at different address on - * the different busses. There are 3 main bus masters: + * the different buses. There are 3 main bus masters: * - MAC CPU (ucode) * - User CPU (firmware) * - AHB (host) diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h index 38f64524019e..a6761a1e9d7d 100644 --- a/drivers/net/wireless/ath/wil6210/wmi.h +++ b/drivers/net/wireless/ath/wil6210/wmi.h @@ -3495,7 +3495,7 @@ struct wmi_aoa_meas_event { u8 channel; /* enum wmi_aoa_meas_type */ u8 aoa_meas_type; - /* Measurments are from RFs, defined by the mask */ + /* Measurements are from RFs, defined by the mask */ __le32 meas_rf_mask; /* enum wmi_aoa_meas_status */ u8 meas_status; @@ -3634,7 +3634,7 @@ struct wmi_tof_ftm_per_dest_res_event { __le32 tsf_sync; /* actual received ftm per burst */ u8 actual_ftm_per_burst; - /* Measurments are from RFs, defined by the mask */ + /* Measurements are from RFs, defined by the mask */ __le32 meas_rf_mask; u8 reserved0[3]; struct wmi_responder_ftm_res responder_ftm_res[]; diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c index 6842c2b02b39..aa683eacaf38 100644 --- a/drivers/net/wireless/atmel/at76c50x-usb.c +++ b/drivers/net/wireless/atmel/at76c50x-usb.c @@ -2002,7 +2002,7 @@ exit: return 0; } -static int at76_config(struct ieee80211_hw *hw, u32 changed) +static int at76_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct at76_priv *priv = hw->priv; diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c index 7529afd24aed..f1a77c4c445f 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -3975,7 +3975,7 @@ static void b43_set_retry_limits(struct b43_wldev *dev, long_retry); } -static int b43_op_config(struct ieee80211_hw *hw, u32 changed) +static int b43_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev = wl->current_dev; @@ -5073,7 +5073,7 @@ static int b43_op_start(struct ieee80211_hw *hw) * may hang the system. */ if (!err) - b43_op_config(hw, ~0); + b43_op_config(hw, -1, ~0); return err; } @@ -5248,7 +5248,7 @@ out: } /* reload configuration */ - b43_op_config(wl->hw, ~0); + b43_op_config(wl->hw, -1, ~0); if (wl->vif) b43_op_bss_info_changed(wl->hw, wl->vif, &wl->vif->bss_conf, ~0); diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c index 2370a2e6a2e3..aada342e0b80 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c @@ -2662,7 +2662,7 @@ static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); } -static int b43legacy_op_dev_config(struct ieee80211_hw *hw, +static int b43legacy_op_dev_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index 6bc107476a2a..8ab7d1e34a6e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -996,6 +996,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354, WCC), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356, WCC), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359, WCC), + BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43751, WCC), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373, CYW), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43012, CYW), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752, CYW), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index b94c3619526c..8af402555b5e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -1043,6 +1043,21 @@ void brcmf_set_mpc(struct brcmf_if *ifp, int mpc) } } +bool brcmf_is_apmode_operating(struct wiphy *wiphy) +{ + struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); + struct brcmf_cfg80211_vif *vif; + bool ret = false; + + list_for_each_entry(vif, &cfg->vif_list, list) { + if (brcmf_is_apmode(vif) && + test_bit(BRCMF_VIF_STATUS_AP_CREATED, &vif->sme_state)) + ret = true; + } + + return ret; +} + static void brcmf_scan_params_v2_to_v1(struct brcmf_scan_params_v2_le *params_v2_le, struct brcmf_scan_params_le *params_le) { @@ -1544,10 +1559,6 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) return -EAGAIN; } - /* If scan req comes for p2p0, send it over primary I/F */ - if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) - vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; - brcmf_dbg(SCAN, "START ESCAN\n"); cfg->scan_request = request; @@ -1563,6 +1574,10 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) if (err) goto scan_out; + /* If scan req comes for p2p0, send it over primary I/F */ + if (vif == cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif) + vif = cfg->p2p.bss_idx[P2PAPI_BSSCFG_PRIMARY].vif; + err = brcmf_do_escan(vif->ifp, request); if (err) goto scan_out; @@ -1622,7 +1637,8 @@ static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l) return err; } -static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +static s32 brcmf_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx, + u32 changed) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = cfg_to_ndev(cfg); @@ -2630,7 +2646,8 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, static s32 brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, s32 mbm) + int radio_idx, enum nl80211_tx_power_setting type, + s32 mbm) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct net_device *ndev = cfg_to_ndev(cfg); @@ -2681,7 +2698,7 @@ done: static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - unsigned int link_id, s32 *dbm) + int radio_idx, unsigned int link_id, s32 *dbm) { struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_cfg80211_vif *vif = wdev_to_vif(wdev); @@ -3861,7 +3878,7 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp, brcmf_dbg(SCAN, "Enter\n"); if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } @@ -4029,7 +4046,7 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e, brcmf_dbg(SCAN, "Enter\n"); if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } @@ -4291,7 +4308,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy, brcmf_set_mpc(ifp, 1); } else { - /* Configure WOWL paramaters */ + /* Configure WOWL parameters */ brcmf_configure_wowl(cfg, ifp, wowl); /* Prevent disassociation due to inactivity with keep-alive */ @@ -5416,8 +5433,8 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev, bphy_err(drvr, "bss_enable config failed %d\n", err); } brcmf_set_mpc(ifp, 1); - brcmf_configure_arp_nd_offload(ifp, true); clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state); + brcmf_configure_arp_nd_offload(ifp, true); brcmf_net_setcarrier(ifp, false); return err; @@ -5527,8 +5544,7 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct brcmf_fil_action_frame_le *action_frame; struct brcmf_fil_af_params_le *af_params; bool ack; - s32 chan_nr; - u32 freq; + __le32 hw_ch; brcmf_dbg(TRACE, "Enter\n"); @@ -5589,25 +5605,34 @@ brcmf_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, /* Add the channel. Use the one specified as parameter if any or * the current one (got from the firmware) otherwise */ - if (chan) - freq = chan->center_freq; - else - brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL, - &freq); - chan_nr = ieee80211_frequency_to_channel(freq); - af_params->channel = cpu_to_le32(chan_nr); + if (chan) { + hw_ch = cpu_to_le32(chan->hw_value); + } else { + err = brcmf_fil_cmd_data_get(vif->ifp, + BRCMF_C_GET_CHANNEL, + &hw_ch, sizeof(hw_ch)); + if (err) { + bphy_err(drvr, + "unable to get current hw channel\n"); + goto free; + } + } + af_params->channel = hw_ch; + af_params->dwell_time = cpu_to_le32(params->wait); memcpy(action_frame->data, &buf[DOT11_MGMT_HDR_LEN], le16_to_cpu(action_frame->len)); - brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, freq=%d\n", - *cookie, le16_to_cpu(action_frame->len), freq); + brcmf_dbg(TRACE, "Action frame, cookie=%lld, len=%d, channel=%d\n", + *cookie, le16_to_cpu(action_frame->len), + le32_to_cpu(af_params->channel)); ack = brcmf_p2p_send_action_frame(cfg, cfg_to_ndev(cfg), af_params); cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, GFP_KERNEL); +free: kfree(af_params); } else { brcmf_dbg(TRACE, "Unhandled, fc=%04x!!\n", mgmt->frame_control); @@ -8313,7 +8338,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, cfg->d11inf.io_type = (u8)io_type; brcmu_d11_attach(&cfg->d11inf); - /* regulatory notifer below needs access to cfg so + /* regulatory notifier below needs access to cfg so * assign it now. */ drvr->config = cfg; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h index b83485ec7b87..273c80f2d483 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.h @@ -487,6 +487,7 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp, bool aborted, bool fw_abort); void brcmf_set_mpc(struct brcmf_if *ndev, int mpc); +bool brcmf_is_apmode_operating(struct wiphy *wiphy); void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); void brcmf_cfg80211_free_netdev(struct net_device *ndev); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c index 2ef92ef25517..9074ab49e806 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -739,6 +739,7 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case CY_CC_4373_CHIP_ID: return 0x160000; case CY_CC_43752_CHIP_ID: + case BRCM_CC_43751_CHIP_ID: case BRCM_CC_4377_CHIP_ID: return 0x170000; case BRCM_CC_4378_CHIP_ID: @@ -1450,6 +1451,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) reg = chip->ops->read32(chip->ctx, addr); return (reg & CC_SR_CTL0_ENABLE_MASK) != 0; case BRCM_CC_4359_CHIP_ID: + case BRCM_CC_43751_CHIP_ID: case CY_CC_43752_CHIP_ID: case CY_CC_43012_CHIP_ID: addr = CORE_CC_REG(pmu->base, retention_ctl); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c index 75f101622db1..688f16c51319 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -525,7 +525,7 @@ struct brcmf_mp_device *brcmf_get_module_param(struct device *dev, if (!settings) return NULL; - /* start by using the module paramaters */ + /* start by using the module parameters */ settings->p2p_enable = !!brcmf_p2p_enable; settings->feature_disable = brcmf_feature_disable; settings->fcmode = brcmf_fcmode; @@ -612,7 +612,7 @@ static int __init brcmfmac_module_init(void) if (err == -ENODEV) brcmf_dbg(INFO, "No platform data available.\n"); - /* Initialize global module paramaters */ + /* Initialize global module parameters */ brcmf_mp_attach(); /* Continue the initialization by registering the different busses */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h index 2be2986d2110..3bdb6984b2dd 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h @@ -20,7 +20,7 @@ */ /** - * struct brcmf_mp_global_t - Global module paramaters. + * struct brcmf_mp_global_t - Global module parameters. * * @firmware_path: Alternative firmware path. */ @@ -31,7 +31,7 @@ struct brcmf_mp_global_t { extern struct brcmf_mp_global_t brcmf_mp_global; /** - * struct brcmf_mp_device - Device module paramaters. + * struct brcmf_mp_device - Device module parameters. * * @p2p_enable: Legacy P2P0 enable (old wpa_supplicant). * @feature_disable: Feature_disable bitmask. diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index 04f41c09deca..862a0336a0b5 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -98,6 +98,11 @@ void brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable) s32 err; u32 mode; + if (enable && brcmf_is_apmode_operating(ifp->drvr->wiphy)) { + brcmf_dbg(TRACE, "Skip ARP/ND offload enable when soft AP is running\n"); + return; + } + if (enable) mode = BRCMF_ARP_OL_AGENT | BRCMF_ARP_OL_PEER_AUTO_REPLY; else diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h index d53839f855d7..399b6810e394 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -67,7 +67,7 @@ struct brcmf_ampdu_rx_reorder { /* Forward decls for struct brcmf_pub (see below) */ struct brcmf_proto; /* device communication protocol info */ struct brcmf_fws_info; /* firmware signalling info */ -struct brcmf_mp_device; /* module paramateres, device specific */ +struct brcmf_mp_device; /* module parameters, device specific */ /* * struct brcmf_rev_info diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index c9537fb597ce..4f0ea4347840 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -112,8 +112,7 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct brcmf_cfg80211_vif *vif; s32 err = 0; bool ack = false; - s32 chan_nr; - u32 freq; + __le16 hw_ch; struct brcmf_mf_params_le *mf_params; u32 mf_params_len; s32 ready; @@ -143,13 +142,18 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, mf_params->len = cpu_to_le16(len - DOT11_MGMT_HDR_LEN); mf_params->frame_control = mgmt->frame_control; - if (chan) - freq = chan->center_freq; - else - brcmf_fil_cmd_int_get(vif->ifp, BRCMF_C_GET_CHANNEL, - &freq); - chan_nr = ieee80211_frequency_to_channel(freq); - mf_params->channel = cpu_to_le16(chan_nr); + if (chan) { + hw_ch = cpu_to_le16(chan->hw_value); + } else { + err = brcmf_fil_cmd_data_get(vif->ifp, BRCMF_C_GET_CHANNEL, + &hw_ch, sizeof(hw_ch)); + if (err) { + bphy_err(drvr, "unable to get current hw channel\n"); + goto free; + } + } + mf_params->channel = hw_ch; + memcpy(&mf_params->da[0], &mgmt->da[0], ETH_ALEN); memcpy(&mf_params->bssid[0], &mgmt->bssid[0], ETH_ALEN); mf_params->packet_id = cpu_to_le32(*cookie); @@ -159,7 +163,8 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, brcmf_dbg(TRACE, "Auth frame, cookie=%d, fc=%04x, len=%d, channel=%d\n", le32_to_cpu(mf_params->packet_id), le16_to_cpu(mf_params->frame_control), - le16_to_cpu(mf_params->len), chan_nr); + le16_to_cpu(mf_params->len), + le16_to_cpu(mf_params->channel)); vif->mgmt_tx_id = le32_to_cpu(mf_params->packet_id); set_bit(BRCMF_MGMT_TX_SEND_FRAME, &vif->mgmt_tx_status); @@ -185,6 +190,7 @@ int brcmf_cyw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, tx_status: cfg80211_mgmt_tx_status(wdev, *cookie, buf, len, ack, GFP_KERNEL); +free: kfree(mf_params); return err; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h index 08c69142495a..669564382e32 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/fwil_types.h @@ -80,7 +80,7 @@ struct brcmf_mf_params_le { u8 da[ETH_ALEN]; u8 bssid[ETH_ALEN]; __le32 packet_id; - u8 data[] __counted_by(len); + u8 data[] __counted_by_le(len); }; #endif /* CYW_FWIL_TYPES_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c index 6e0c90f4718b..0dc9d28cd77b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c @@ -1403,7 +1403,7 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp, u8 action; if (e->datalen < sizeof(*rxframe)) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } @@ -1949,7 +1949,7 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp, e->reason); if (e->datalen < sizeof(*rxframe)) { - brcmf_dbg(SCAN, "Event data to small. Ignore\n"); + brcmf_dbg(SCAN, "Event data too small. Ignore\n"); return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 8f97562811d7..6327f4eca500 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -71,6 +71,7 @@ BRCMF_FW_CLM_DEF(4377B3, "brcmfmac4377b3-pcie"); BRCMF_FW_CLM_DEF(4378B1, "brcmfmac4378b1-pcie"); BRCMF_FW_CLM_DEF(4378B3, "brcmfmac4378b3-pcie"); BRCMF_FW_CLM_DEF(4387C2, "brcmfmac4387c2-pcie"); +BRCMF_FW_CLM_DEF(54591, "brcmfmac54591-pcie"); /* firmware config files */ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-pcie.txt"); @@ -88,6 +89,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_4350_CHIP_ID, 0xFFFFFF00, 4350), BRCMF_FW_ENTRY(BRCM_CC_43525_CHIP_ID, 0xFFFFFFF0, 4365C), BRCMF_FW_ENTRY(BRCM_CC_4355_CHIP_ID, 0x000007FF, 4355), + BRCMF_FW_ENTRY(BRCM_CC_4355_CHIP_ID, 0x00002000, 54591), BRCMF_FW_ENTRY(BRCM_CC_4355_CHIP_ID, 0xFFFFF800, 4355C1), /* rev ID 12/C2 seen */ BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_ENTRY(BRCM_CC_43567_CHIP_ID, 0xFFFFFFFF, 43570), @@ -654,17 +656,19 @@ brcmf_pcie_select_core(struct brcmf_pciedev_info *devinfo, u16 coreid) static void brcmf_pcie_reset_device(struct brcmf_pciedev_info *devinfo) { struct brcmf_core *core; - u16 cfg_offset[] = { BRCMF_PCIE_CFGREG_STATUS_CMD, - BRCMF_PCIE_CFGREG_PM_CSR, - BRCMF_PCIE_CFGREG_MSI_CAP, - BRCMF_PCIE_CFGREG_MSI_ADDR_L, - BRCMF_PCIE_CFGREG_MSI_ADDR_H, - BRCMF_PCIE_CFGREG_MSI_DATA, - BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL2, - BRCMF_PCIE_CFGREG_RBAR_CTRL, - BRCMF_PCIE_CFGREG_PML1_SUB_CTRL1, - BRCMF_PCIE_CFGREG_REG_BAR2_CONFIG, - BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG }; + static const u16 cfg_offset[] = { + BRCMF_PCIE_CFGREG_STATUS_CMD, + BRCMF_PCIE_CFGREG_PM_CSR, + BRCMF_PCIE_CFGREG_MSI_CAP, + BRCMF_PCIE_CFGREG_MSI_ADDR_L, + BRCMF_PCIE_CFGREG_MSI_ADDR_H, + BRCMF_PCIE_CFGREG_MSI_DATA, + BRCMF_PCIE_CFGREG_LINK_STATUS_CTRL2, + BRCMF_PCIE_CFGREG_RBAR_CTRL, + BRCMF_PCIE_CFGREG_PML1_SUB_CTRL1, + BRCMF_PCIE_CFGREG_REG_BAR2_CONFIG, + BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG + }; u32 i; u32 val; u32 lsc; @@ -2520,10 +2524,19 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (ret) goto fail_bus; - ret = brcmf_pcie_read_otp(devinfo); - if (ret) { - brcmf_err(bus, "failed to parse OTP\n"); - goto fail_brcmf; + /* otp read operation */ + switch (bus->fwvid) { + case BRCMF_FWVENDOR_WCC: + case BRCMF_FWVENDOR_BCA: + ret = brcmf_pcie_read_otp(devinfo); + if (ret) { + brcmf_err(bus, "failed to parse OTP\n"); + goto fail_brcmf; + } + break; + case BRCMF_FWVENDOR_CYW: + default: + break; } #ifdef DEBUG @@ -2738,7 +2751,7 @@ static const struct pci_device_id brcmf_pcie_devid_table[] = { BRCMF_PCIE_DEVICE(BRCM_PCIE_4378_DEVICE_ID, WCC_SEED), BRCMF_PCIE_DEVICE(BRCM_PCIE_4387_DEVICE_ID, WCC_SEED), BRCMF_PCIE_DEVICE(BRCM_PCIE_43752_DEVICE_ID, WCC_SEED), - + BRCMF_PCIE_DEVICE(CY_PCIE_54591_DEVICE_ID, CYW), { /* end: all zeroes */ } }; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c index cf26ab15ee0c..8a0bad5119a0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -654,6 +654,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), + BRCMF_FW_ENTRY(BRCM_CC_43751_CHIP_ID, 0xFFFFFFFF, 43752), BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373), BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012), BRCMF_FW_ENTRY(CY_CC_43439_CHIP_ID, 0xFFFFFFFF, 43439), @@ -3424,7 +3425,8 @@ err: static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus) { - if (bus->ci->chip == CY_CC_43012_CHIP_ID || + if (bus->ci->chip == BRCM_CC_43751_CHIP_ID || + bus->ci->chip == CY_CC_43012_CHIP_ID || bus->ci->chip == CY_CC_43752_CHIP_ID) return true; else @@ -4275,6 +4277,7 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, bus->hostintmask, NULL); switch (sdiod->func1->device) { + case SDIO_DEVICE_ID_BROADCOM_43751: case SDIO_DEVICE_ID_BROADCOM_CYPRESS_4373: case SDIO_DEVICE_ID_BROADCOM_CYPRESS_43752: brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c index b056336d5da6..f0129d10d2b9 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c @@ -927,10 +927,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen) /* Wait until the usb device reports it received all * the bytes we sent */ if ((rdlbytes == sent) && (rdlbytes != dllen)) { - if ((dllen-sent) < TRX_RDL_CHUNK) - sendlen = dllen-sent; - else - sendlen = TRX_RDL_CHUNK; + sendlen = min(dllen - sent, TRX_RDL_CHUNK); /* simply avoid having to send a ZLP by ensuring we * never have an even diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 1c3d29dca424..aadcff1e2b5d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -24,6 +24,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/bcma/bcma.h> +#include <linux/string_choices.h> #include <net/mac80211.h> #include <defs.h> #include "phy/phy_int.h" @@ -525,7 +526,8 @@ brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) spin_unlock_bh(&wl->lock); } -static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) +static int brcms_ops_config(struct ieee80211_hw *hw, int radio_idx, + u32 changed) { struct ieee80211_conf *conf = &hw->conf; struct brcms_info *wl = hw->priv; @@ -539,13 +541,13 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed) conf->listen_interval); } if (changed & IEEE80211_CONF_CHANGE_MONITOR) - brcms_dbg_info(core, "%s: change monitor mode: %s\n", - __func__, conf->flags & IEEE80211_CONF_MONITOR ? - "true" : "false"); + brcms_dbg_info(core, "%s: change monitor mode: %s\n", __func__, + str_true_false(conf->flags & + IEEE80211_CONF_MONITOR)); if (changed & IEEE80211_CONF_CHANGE_PS) brcms_err(core, "%s: change power-save mode: %s (implement)\n", - __func__, conf->flags & IEEE80211_CONF_PS ? - "true" : "false"); + __func__, + str_true_false(conf->flags & IEEE80211_CONF_PS)); if (changed & IEEE80211_CONF_CHANGE_POWER) { err = brcms_c_set_tx_power(wl->wlc, conf->power_level); @@ -696,7 +698,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_BEACON_ENABLED) { /* Beaconing should be enabled/disabled (beaconing modes) */ brcms_err(core, "%s: Beacon enabled: %s\n", __func__, - info->enable_beacon ? "true" : "false"); + str_true_false(info->enable_beacon)); if (info->enable_beacon && hw->wiphy->flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD) { brcms_c_enable_probe_resp(wl->wlc, true); @@ -715,7 +717,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_IBSS) { /* IBSS join status changed */ brcms_err(core, "%s: IBSS joined: %s (implement)\n", - __func__, vif->cfg.ibss_joined ? "true" : "false"); + __func__, str_true_false(vif->cfg.ibss_joined)); } if (changed & BSS_CHANGED_ARP_FILTER) { @@ -730,7 +732,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw, * Note that it is only ever disabled for station mode. */ brcms_err(core, "%s: qos enabled: %s (implement)\n", - __func__, info->qos ? "true" : "false"); + __func__, str_true_false(info->qos)); } return; } @@ -907,7 +909,7 @@ static void brcms_ops_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct brcms_info *wl = hw->priv; int ret; - no_printk("%s: drop = %s\n", __func__, drop ? "true" : "false"); + no_printk("%s: drop = %s\n", __func__, str_true_false(drop)); ret = wait_event_timeout(wl->tx_flush_wq, brcms_tx_flush_completed(wl), diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c index c3d7aa570b4e..ce6ce2dea39c 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_cmn.c @@ -127,23 +127,6 @@ void wlc_phyreg_exit(struct brcms_phy_pub *pih) wlapi_bmac_ucode_wake_override_phyreg_clear(pi->sh->physhim); } -void wlc_radioreg_enter(struct brcms_phy_pub *pih) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, MCTL_LOCK_RADIO); - - udelay(10); -} - -void wlc_radioreg_exit(struct brcms_phy_pub *pih) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - - (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); - pi->phy_wreg = 0; - wlapi_bmac_mctrl(pi->sh->physhim, MCTL_LOCK_RADIO, 0); -} - u16 read_radio_reg(struct brcms_phy *pi, u16 addr) { u16 data; @@ -263,11 +246,6 @@ void mod_radio_reg(struct brcms_phy *pi, u16 addr, u16 mask, u16 val) write_radio_reg(pi, addr, (rval & ~mask) | (val & mask)); } -void write_phy_channel_reg(struct brcms_phy *pi, uint val) -{ - bcma_write16(pi->d11core, D11REGOFFS(phychannel), val); -} - u16 read_phy_reg(struct brcms_phy *pi, u16 addr) { bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); @@ -692,18 +670,6 @@ void wlc_phy_por_inform(struct brcms_phy_pub *ppi) pi->phy_init_por = true; } -void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - - pi->edcrs_threshold_lock = lock; - - write_phy_reg(pi, 0x22c, 0x46b); - write_phy_reg(pi, 0x22d, 0x46b); - write_phy_reg(pi, 0x22e, 0x3c0); - write_phy_reg(pi, 0x22f, 0x3c0); -} - void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal) { struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); @@ -1083,20 +1049,6 @@ void wlc_phy_mute_upd(struct brcms_phy_pub *pih, bool mute, u32 flags) return; } -void wlc_phy_clear_tssi(struct brcms_phy_pub *pih) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - - if (ISNPHY(pi)) { - return; - } else { - wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_0, NULL_TSSI_W); - wlapi_bmac_write_shm(pi->sh->physhim, M_B_TSSI_1, NULL_TSSI_W); - wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_0, NULL_TSSI_W); - wlapi_bmac_write_shm(pi->sh->physhim, M_G_TSSI_1, NULL_TSSI_W); - } -} - static bool wlc_phy_cal_txpower_recalc_sw(struct brcms_phy *pi) { return false; @@ -1136,13 +1088,6 @@ void wlc_phy_switch_radio(struct brcms_phy_pub *pih, bool on) } } -u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - return pi->bw; -} - void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -1182,36 +1127,6 @@ void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec) } -int wlc_phy_chanspec_freq2bandrange_lpssn(uint freq) -{ - int range = -1; - - if (freq < 2500) - range = WL_CHAN_FREQ_RANGE_2G; - else if (freq <= 5320) - range = WL_CHAN_FREQ_RANGE_5GL; - else if (freq <= 5700) - range = WL_CHAN_FREQ_RANGE_5GM; - else - range = WL_CHAN_FREQ_RANGE_5GH; - - return range; -} - -int wlc_phy_chanspec_bandrange_get(struct brcms_phy *pi, u16 chanspec) -{ - int range = -1; - uint channel = CHSPEC_CHANNEL(chanspec); - uint freq = wlc_phy_channel2freq(channel); - - if (ISNPHY(pi)) - range = wlc_phy_get_chan_freq_range_nphy(pi, channel); - else if (ISLCNPHY(pi)) - range = wlc_phy_chanspec_freq2bandrange_lpssn(freq); - - return range; -} - void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, bool wide_filter) { @@ -1254,50 +1169,6 @@ wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, } } -u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - uint i; - uint channel; - u16 chspec; - - for (i = 0; i < ARRAY_SIZE(chan_info_all); i++) { - channel = chan_info_all[i].chan; - - if (ISNPHY(pi) && pi->bw == WL_CHANSPEC_BW_40) { - uint j; - - for (j = 0; j < ARRAY_SIZE(chan_info_all); j++) { - if (chan_info_all[j].chan == - channel + CH_10MHZ_APART) - break; - } - - if (j == ARRAY_SIZE(chan_info_all)) - continue; - - channel = upper_20_sb(channel); - chspec = channel | WL_CHANSPEC_BW_40 | - WL_CHANSPEC_CTL_SB_LOWER; - if (band == BRCM_BAND_2G) - chspec |= WL_CHANSPEC_BAND_2G; - else - chspec |= WL_CHANSPEC_BAND_5G; - } else - chspec = ch20mhz_chspec(channel); - - if ((pi->a_band_high_disable) && (channel >= FIRST_REF5_CHANNUM) - && (channel <= LAST_REF5_CHANNUM)) - continue; - - if ((band == BRCM_BAND_2G && channel <= CH_MAX_2G_CHANNEL) || - (band == BRCM_BAND_5G && channel > CH_MAX_2G_CHANNEL)) - return chspec; - } - - return (u16) INVCHANSPEC; -} - int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -1308,56 +1179,6 @@ int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override) return 0; } -void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, - struct txpwr_limits *txpwr) -{ - bool mac_enabled = false; - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - memcpy(&pi->tx_user_target[TXP_FIRST_CCK], - &txpwr->cck[0], BRCMS_NUM_RATES_CCK); - - memcpy(&pi->tx_user_target[TXP_FIRST_OFDM], - &txpwr->ofdm[0], BRCMS_NUM_RATES_OFDM); - memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_20_CDD], - &txpwr->ofdm_cdd[0], BRCMS_NUM_RATES_OFDM); - - memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_SISO], - &txpwr->ofdm_40_siso[0], BRCMS_NUM_RATES_OFDM); - memcpy(&pi->tx_user_target[TXP_FIRST_OFDM_40_CDD], - &txpwr->ofdm_40_cdd[0], BRCMS_NUM_RATES_OFDM); - - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SISO], - &txpwr->mcs_20_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_CDD], - &txpwr->mcs_20_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_STBC], - &txpwr->mcs_20_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_20_SDM], - &txpwr->mcs_20_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); - - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SISO], - &txpwr->mcs_40_siso[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_CDD], - &txpwr->mcs_40_cdd[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_STBC], - &txpwr->mcs_40_stbc[0], BRCMS_NUM_RATES_MCS_1_STREAM); - memcpy(&pi->tx_user_target[TXP_FIRST_MCS_40_SDM], - &txpwr->mcs_40_mimo[0], BRCMS_NUM_RATES_MCS_2_STREAM); - - if (bcma_read32(pi->d11core, D11REGOFFS(maccontrol)) & MCTL_EN_MAC) - mac_enabled = true; - - if (mac_enabled) - wlapi_suspend_mac_and_wait(pi->sh->physhim); - - wlc_phy_txpower_recalc_target(pi); - wlc_phy_cal_txpower_recalc_sw(pi); - - if (mac_enabled) - wlapi_enable_mac(pi->sh->physhim); -} - int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -1441,59 +1262,6 @@ wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint channel, u8 *min_pwr, } } -void -wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, - u8 *max_txpwr, u8 *min_txpwr) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - u8 tx_pwr_max = 0; - u8 tx_pwr_min = 255; - u8 max_num_rate; - u8 maxtxpwr, mintxpwr, rate, pactrl; - - pactrl = 0; - - max_num_rate = ISNPHY(pi) ? TXP_NUM_RATES : - ISLCNPHY(pi) ? (TXP_LAST_SISO_MCS_20 + - 1) : (TXP_LAST_OFDM + 1); - - for (rate = 0; rate < max_num_rate; rate++) { - - wlc_phy_txpower_sromlimit(ppi, chan, &mintxpwr, &maxtxpwr, - rate); - - maxtxpwr = (maxtxpwr > pactrl) ? (maxtxpwr - pactrl) : 0; - - maxtxpwr = (maxtxpwr > 6) ? (maxtxpwr - 6) : 0; - - tx_pwr_max = max(tx_pwr_max, maxtxpwr); - tx_pwr_min = min(tx_pwr_min, maxtxpwr); - } - *max_txpwr = tx_pwr_max; - *min_txpwr = tx_pwr_min; -} - -void -wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint bandunit, - s32 *max_pwr, s32 *min_pwr, u32 *step_pwr) -{ - return; -} - -u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - return pi->tx_power_min; -} - -u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - return pi->tx_power_max; -} - static s8 wlc_phy_env_measure_vbat(struct brcms_phy *pi) { if (ISLCNPHY(pi)) @@ -1797,13 +1565,6 @@ wlc_phy_txpower_reg_limit_calc(struct brcms_phy *pi, struct txpwr_limits *txpwr, } } -void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - pi->txpwr_percent = txpwr_percent; -} - void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -1811,35 +1572,6 @@ void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap) pi->sh->machwcap = machwcap; } -void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - u16 rxc; - rxc = 0; - - if (start_end == ON) { - if (!ISNPHY(pi)) - return; - - if (NREV_IS(pi->pubpi.phy_rev, 3) - || NREV_IS(pi->pubpi.phy_rev, 4)) { - bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), - 0xa0); - bcma_set16(pi->d11core, D11REGOFFS(phyregdata), - 0x1 << 15); - } - } else { - if (NREV_IS(pi->pubpi.phy_rev, 3) - || NREV_IS(pi->pubpi.phy_rev, 4)) { - bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), - 0xa0); - bcma_write16(pi->d11core, D11REGOFFS(phyregdata), rxc); - } - - wlc_phy_por_inform(ppi); - } -} - void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *txpwr, u16 chanspec) @@ -1940,37 +1672,6 @@ bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi) return pi->hwpwrctrl; } -void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - bool suspend; - - if (!pi->hwpwrctrl_capable) - return; - - pi->hwpwrctrl = hwpwrctrl; - pi->nphy_txpwrctrl = hwpwrctrl; - pi->txpwrctrl = hwpwrctrl; - - if (ISNPHY(pi)) { - suspend = (0 == (bcma_read32(pi->d11core, - D11REGOFFS(maccontrol)) & - MCTL_EN_MAC)); - if (!suspend) - wlapi_suspend_mac_and_wait(pi->sh->physhim); - - wlc_phy_txpwrctrl_enable_nphy(pi, pi->nphy_txpwrctrl); - if (pi->nphy_txpwrctrl == PHY_TPC_HW_OFF) - wlc_phy_txpwr_fixpower_nphy(pi); - else - mod_phy_reg(pi, 0x1e7, (0x7f << 0), - pi->saved_txpwr_idx); - - if (!suspend) - wlapi_enable_mac(pi->sh->physhim); - } -} - void wlc_phy_txpower_ipa_upd(struct brcms_phy *pi) { @@ -2128,13 +1829,6 @@ void wlc_phy_antsel_type_set(struct brcms_phy_pub *ppi, u8 antsel_type) pi->antsel_type = antsel_type; } -bool wlc_phy_test_ison(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - return pi->phytest_on; -} - void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val) { struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); @@ -2448,15 +2142,6 @@ done: } -void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *pih) -{ - u8 channel; - - channel = CHSPEC_CHANNEL(wlc_phy_chanspec_get(pih)); - - wlc_phy_noise_sample_request(pih, PHY_NOISE_SAMPLE_EXTERNAL, channel); -} - static const s8 lcnphy_gain_index_offset_for_pkt_rssi[] = { 8, 8, @@ -2555,27 +2240,6 @@ end: return rssi; } -void wlc_phy_freqtrack_start(struct brcms_phy_pub *pih) -{ - return; -} - -void wlc_phy_freqtrack_end(struct brcms_phy_pub *pih) -{ - return; -} - -void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag) -{ - struct brcms_phy *pi; - pi = (struct brcms_phy *) ppi; - - if (ISLCNPHY(pi)) - wlc_lcnphy_deaf_mode(pi, true); - else if (ISNPHY(pi)) - wlc_nphy_deaf_mode(pi, true); -} - void wlc_phy_watchdog(struct brcms_phy_pub *pih) { struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); @@ -2636,28 +2300,6 @@ void wlc_phy_watchdog(struct brcms_phy_pub *pih) } } -void wlc_phy_BSSinit(struct brcms_phy_pub *pih, bool bonlyap, int rssi) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - uint i; - uint k; - - for (i = 0; i < MA_WINDOW_SZ; i++) - pi->sh->phy_noise_window[i] = (s8) (rssi & 0xff); - if (ISLCNPHY(pi)) { - for (i = 0; i < MA_WINDOW_SZ; i++) - pi->sh->phy_noise_window[i] = - PHY_NOISE_FIXED_VAL_LCNPHY; - } - pi->sh->phy_noise_index = 0; - - for (i = 0; i < PHY_NOISE_WINDOW_SZ; i++) { - for (k = WL_ANT_IDX_1; k < WL_ANT_RX_MAX; k++) - pi->nphy_noise_win[k][i] = PHY_NOISE_FIXED_VAL_NPHY; - } - pi->nphy_noise_index = 0; -} - void wlc_phy_papd_decode_epsilon(u32 epsilon, s32 *eps_real, s32 *eps_imag) { @@ -2812,14 +2454,6 @@ void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain) pi->pubpi.phy_corenum = (u8)hweight8(pi->sh->phyrxchain); } -void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - - *txchain = pi->sh->phytxchain; - *rxchain = pi->sh->phyrxchain; -} - u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) { s16 nphy_currtemp; @@ -2852,89 +2486,12 @@ u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih) return active_bitmap; } -s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec) -{ - struct brcms_phy *pi = container_of(pih, struct brcms_phy, pubpi_ro); - u8 siso_mcs_id, cdd_mcs_id; - - siso_mcs_id = - (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_SISO : - TXP_FIRST_MCS_20_SISO; - cdd_mcs_id = - (CHSPEC_IS40(chanspec)) ? TXP_FIRST_MCS_40_CDD : - TXP_FIRST_MCS_20_CDD; - - if (pi->tx_power_target[siso_mcs_id] > - (pi->tx_power_target[cdd_mcs_id] + 12)) - return PHY_TXC1_MODE_SISO; - else - return PHY_TXC1_MODE_CDD; -} - const u8 *wlc_phy_get_ofdm_rate_lookup(void) { return ofdm_rate_lookup; } -void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) -{ - if ((pi->sh->chip == BCMA_CHIP_ID_BCM4313) && - (pi->sh->boardflags & BFL_FEM)) { - if (mode) { - u16 txant = 0; - txant = wlapi_bmac_get_txant(pi->sh->physhim); - if (txant == 1) { - mod_phy_reg(pi, 0x44d, (0x1 << 2), (1) << 2); - - mod_phy_reg(pi, 0x44c, (0x1 << 2), (1) << 2); - - } - - bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc, - 0x0, 0x0); - bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc, - ~0x40, 0x40); - bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc, - ~0x40, 0x40); - } else { - mod_phy_reg(pi, 0x44c, (0x1 << 2), (0) << 2); - - mod_phy_reg(pi, 0x44d, (0x1 << 2), (0) << 2); - - bcma_chipco_gpio_out(&pi->d11core->bus->drv_cc, - ~0x40, 0x00); - bcma_chipco_gpio_outen(&pi->d11core->bus->drv_cc, - ~0x40, 0x00); - bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc, - 0x0, 0x40); - } - } -} - void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool ldpc) { return; } - -void -wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, s8 *ofdmoffset) -{ - *cckoffset = 0; - *ofdmoffset = 0; -} - -s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec) -{ - - return rssi; -} - -bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *ppi) -{ - struct brcms_phy *pi = container_of(ppi, struct brcms_phy, pubpi_ro); - - if (ISNPHY(pi)) - return wlc_phy_n_txpower_ipa_ison(pi); - else - return false; -} diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h index 1efc92fd1671..cab08f0669d1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_hal.h @@ -186,7 +186,6 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init); void wlc_phy_chanspec_set(struct brcms_phy_pub *ppi, u16 chanspec); u16 wlc_phy_chanspec_get(struct brcms_phy_pub *ppi); void wlc_phy_chanspec_radio_set(struct brcms_phy_pub *ppi, u16 newch); -u16 wlc_phy_bw_state_get(struct brcms_phy_pub *ppi); void wlc_phy_bw_state_set(struct brcms_phy_pub *ppi, u16 bw); int wlc_phy_rssi_compute(struct brcms_phy_pub *pih, struct d11rxhdr *rxh); @@ -194,26 +193,16 @@ void wlc_phy_por_inform(struct brcms_phy_pub *ppi); void wlc_phy_noise_sample_intr(struct brcms_phy_pub *ppi); bool wlc_phy_bist_check_phy(struct brcms_phy_pub *ppi); -void wlc_phy_set_deaf(struct brcms_phy_pub *ppi, bool user_flag); - void wlc_phy_switch_radio(struct brcms_phy_pub *ppi, bool on); void wlc_phy_anacore(struct brcms_phy_pub *ppi, bool on); - -void wlc_phy_BSSinit(struct brcms_phy_pub *ppi, bool bonlyap, int rssi); - void wlc_phy_chanspec_ch14_widefilter_set(struct brcms_phy_pub *ppi, bool wide_filter); void wlc_phy_chanspec_band_validch(struct brcms_phy_pub *ppi, uint band, struct brcms_chanvec *channels); -u16 wlc_phy_chanspec_band_firstch(struct brcms_phy_pub *ppi, uint band); void wlc_phy_txpower_sromlimit(struct brcms_phy_pub *ppi, uint chan, u8 *_min_, u8 *_max_, int rate); -void wlc_phy_txpower_sromlimit_max_get(struct brcms_phy_pub *ppi, uint chan, - u8 *_max_, u8 *_min_); -void wlc_phy_txpower_boardlimit_band(struct brcms_phy_pub *ppi, uint band, - s32 *, s32 *, u32 *); void wlc_phy_txpower_limit_set(struct brcms_phy_pub *ppi, struct txpwr_limits *, u16 chanspec); int wlc_phy_txpower_get(struct brcms_phy_pub *ppi, uint *qdbm, bool *override); @@ -221,25 +210,16 @@ int wlc_phy_txpower_set(struct brcms_phy_pub *ppi, uint qdbm, bool override); void wlc_phy_txpower_target_set(struct brcms_phy_pub *ppi, struct txpwr_limits *); bool wlc_phy_txpower_hw_ctrl_get(struct brcms_phy_pub *ppi); -void wlc_phy_txpower_hw_ctrl_set(struct brcms_phy_pub *ppi, bool hwpwrctrl); -u8 wlc_phy_txpower_get_target_min(struct brcms_phy_pub *ppi); -u8 wlc_phy_txpower_get_target_max(struct brcms_phy_pub *ppi); -bool wlc_phy_txpower_ipa_ison(struct brcms_phy_pub *pih); void wlc_phy_stf_chain_init(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain); void wlc_phy_stf_chain_set(struct brcms_phy_pub *pih, u8 txchain, u8 rxchain); -void wlc_phy_stf_chain_get(struct brcms_phy_pub *pih, u8 *txchain, u8 *rxchain); u8 wlc_phy_stf_chain_active_get(struct brcms_phy_pub *pih); -s8 wlc_phy_stf_ssmode_get(struct brcms_phy_pub *pih, u16 chanspec); void wlc_phy_ldpc_override_set(struct brcms_phy_pub *ppi, bool val); void wlc_phy_cal_perical(struct brcms_phy_pub *ppi, u8 reason); -void wlc_phy_noise_sample_request_external(struct brcms_phy_pub *ppi); -void wlc_phy_edcrs_lock(struct brcms_phy_pub *pih, bool lock); void wlc_phy_cal_papd_recal(struct brcms_phy_pub *ppi); void wlc_phy_ant_rxdiv_set(struct brcms_phy_pub *ppi, u8 val); -void wlc_phy_clear_tssi(struct brcms_phy_pub *ppi); void wlc_phy_hold_upd(struct brcms_phy_pub *ppi, u32 id, bool val); void wlc_phy_mute_upd(struct brcms_phy_pub *ppi, bool val, u32 flags); @@ -249,17 +229,10 @@ void wlc_phy_txpower_get_current(struct brcms_phy_pub *ppi, struct tx_power *power, uint channel); void wlc_phy_initcal_enable(struct brcms_phy_pub *pih, bool initcal); -bool wlc_phy_test_ison(struct brcms_phy_pub *ppi); -void wlc_phy_txpwr_percent_set(struct brcms_phy_pub *ppi, u8 txpwr_percent); void wlc_phy_ofdm_rateset_war(struct brcms_phy_pub *pih, bool war); void wlc_phy_bf_preempt_enable(struct brcms_phy_pub *pih, bool bf_preempt); void wlc_phy_machwcap_set(struct brcms_phy_pub *ppi, u32 machwcap); -void wlc_phy_runbist_config(struct brcms_phy_pub *ppi, bool start_end); - -void wlc_phy_freqtrack_start(struct brcms_phy_pub *ppi); -void wlc_phy_freqtrack_end(struct brcms_phy_pub *ppi); - const u8 *wlc_phy_get_ofdm_rate_lookup(void); s8 wlc_phy_get_tx_power_offset_by_mcs(struct brcms_phy_pub *ppi, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h index 70a9ec050717..4e80f4d27949 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_int.h @@ -908,8 +908,6 @@ void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val); void wlc_phyreg_enter(struct brcms_phy_pub *pih); void wlc_phyreg_exit(struct brcms_phy_pub *pih); -void wlc_radioreg_enter(struct brcms_phy_pub *pih); -void wlc_radioreg_exit(struct brcms_phy_pub *pih); void wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, @@ -921,7 +919,6 @@ void wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, u16 tblAddr, u16 tblDataHi, u16 tblDataLo); void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val); -void write_phy_channel_reg(struct brcms_phy *pi, uint val); void wlc_phy_txpower_update_shm(struct brcms_phy *pi); u8 wlc_phy_nbits(s32 value); @@ -985,7 +982,6 @@ s8 wlc_lcnphy_tempsense_degree(struct brcms_phy *pi, bool mode); s8 wlc_lcnphy_vbatsense(struct brcms_phy *pi, bool mode); void wlc_phy_carrier_suppress_lcnphy(struct brcms_phy *pi); void wlc_lcnphy_crsuprs(struct brcms_phy *pi, int channel); -void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode); void wlc_2064_vco_cal(struct brcms_phy *pi); void wlc_phy_txpower_recalc_target(struct brcms_phy *pi); @@ -1031,7 +1027,6 @@ struct phy_iq_est { }; void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable); -void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode); #define wlc_phy_write_table_nphy(pi, pti) \ wlc_phy_write_table(pi, pti, 0x72, 0x74, 0x73) @@ -1115,10 +1110,4 @@ int wlc_phy_rssi_compute_nphy(struct brcms_phy *pi, struct d11rxhdr *rxh); #define NPHY_TESTPATTERN_BPHY_RFCS 1 void wlc_phy_nphy_tkip_rifs_war(struct brcms_phy *pi, u8 rifs); - -void wlc_phy_get_pwrdet_offsets(struct brcms_phy *pi, s8 *cckoffset, - s8 *ofdmoffset); -s8 wlc_phy_upd_rssi_offset(struct brcms_phy *pi, s8 rssi, u16 chanspec); - -bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pih); #endif /* _BRCM_PHY_INT_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c index d0faba240561..b4bba67a45ec 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_lcn.c @@ -919,7 +919,7 @@ void wlc_lcnphy_read_table(struct brcms_phy *pi, struct phytbl_info *pti) static void wlc_lcnphy_common_read_table(struct brcms_phy *pi, u32 tbl_id, - const u16 *tbl_ptr, u32 tbl_len, + u16 *tbl_ptr, u32 tbl_len, u32 tbl_width, u32 tbl_offset) { struct phytbl_info tab; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c index d362c4337616..b03d5a1f1a93 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/phy/phy_n.c @@ -19713,11 +19713,6 @@ u8 wlc_phy_rxcore_getstate_nphy(struct brcms_phy_pub *pih) return (u8) rxen_bits; } -bool wlc_phy_n_txpower_ipa_ison(struct brcms_phy *pi) -{ - return PHY_IPA(pi); -} - void wlc_phy_cal_init_nphy(struct brcms_phy *pi) { } @@ -25825,10 +25820,8 @@ wlc_phy_cal_txiqlo_nphy(struct brcms_phy *pi, struct nphy_txgains target_gain, if (mphase) { cal_cnt = pi->mphase_txcal_cmdidx; - if ((cal_cnt + pi->mphase_txcal_numcmds) < max_cal_cmds) - num_cals = cal_cnt + pi->mphase_txcal_numcmds; - else - num_cals = max_cal_cmds; + num_cals = min(cal_cnt + pi->mphase_txcal_numcmds, + max_cal_cmds); } else { cal_cnt = 0; num_cals = max_cal_cmds; @@ -28577,17 +28570,3 @@ void wlc_phy_stay_in_carriersearch_nphy(struct brcms_phy *pi, bool enable) } } } - -void wlc_nphy_deaf_mode(struct brcms_phy *pi, bool mode) -{ - wlapi_suspend_mac_and_wait(pi->sh->physhim); - - if (mode) { - if (pi->nphy_deaf_count == 0) - wlc_phy_stay_in_carriersearch_nphy(pi, true); - } else if (pi->nphy_deaf_count > 0) { - wlc_phy_stay_in_carriersearch_nphy(pi, false); - } - - wlapi_enable_mac(pi->sh->physhim); -} diff --git a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h index c1e22c589d85..b39c5c1ee18b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/broadcom/brcm80211/include/brcm_hw_ids.h @@ -52,6 +52,7 @@ #define BRCM_CC_43664_CHIP_ID 43664 #define BRCM_CC_43666_CHIP_ID 43666 #define BRCM_CC_4371_CHIP_ID 0x4371 +#define BRCM_CC_43751_CHIP_ID 43751 #define BRCM_CC_43752_CHIP_ID 43752 #define BRCM_CC_4377_CHIP_ID 0x4377 #define BRCM_CC_4378_CHIP_ID 0x4378 @@ -99,6 +100,7 @@ #define BRCM_PCIE_4377_DEVICE_ID 0x4488 #define BRCM_PCIE_4378_DEVICE_ID 0x4425 #define BRCM_PCIE_4387_DEVICE_ID 0x4433 +#define CY_PCIE_54591_DEVICE_ID 0x4417 /* brcmsmac IDs */ #define BCM4313_D11N2G_ID 0x4727 /* 4313 802.11n 2.4G device */ diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c index 0a16127bfd68..2ad085b1f492 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c @@ -83,7 +83,7 @@ void libipw_networks_age(struct libipw_device *ieee, { struct libipw_network *network = NULL; unsigned long flags; - unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC); + unsigned long age_jiffies = secs_to_jiffies(age_secs); spin_lock_irqsave(&ieee->lock, flags); list_for_each_entry(network, &ieee->network_list, list) { diff --git a/drivers/net/wireless/intel/iwlegacy/4965-mac.c b/drivers/net/wireless/intel/iwlegacy/4965-mac.c index 8e58e97a148f..3588dec75ebd 100644 --- a/drivers/net/wireless/intel/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/intel/iwlegacy/4965-mac.c @@ -1382,7 +1382,7 @@ il4965_hdl_stats(struct il_priv *il, struct il_rx_buf *rxb) * we get a thermal update even if the uCode doesn't give us one */ mod_timer(&il->stats_periodic, - jiffies + msecs_to_jiffies(recalib_seconds * 1000)); + jiffies + secs_to_jiffies(recalib_seconds)); if (unlikely(!test_bit(S_SCANNING, &il->status)) && (pkt->hdr.cmd == N_STATS)) { @@ -1575,8 +1575,11 @@ il4965_tx_cmd_build_rate(struct il_priv *il, || rate_idx > RATE_COUNT_LEGACY) rate_idx = rate_lowest_index(&il->bands[info->band], sta); /* For 5 GHZ band, remap mac80211 rate indices into driver indices */ - if (info->band == NL80211_BAND_5GHZ) + if (info->band == NL80211_BAND_5GHZ) { rate_idx += IL_FIRST_OFDM_RATE; + if (rate_idx > IL_LAST_OFDM_RATE) + rate_idx = IL_LAST_OFDM_RATE; + } /* Get PLCP rate for tx_cmd->rate_n_flags */ rate_plcp = il_rates[rate_idx].plcp; /* Zero out flags for this packet */ diff --git a/drivers/net/wireless/intel/iwlegacy/commands.h b/drivers/net/wireless/intel/iwlegacy/commands.h index 4a9fa8b83f0f..b61b8f377702 100644 --- a/drivers/net/wireless/intel/iwlegacy/commands.h +++ b/drivers/net/wireless/intel/iwlegacy/commands.h @@ -2229,7 +2229,7 @@ struct il_spectrum_notification { u8 channel; u8 type; /* see enum il_measurement_type */ u8 reserved1; - /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only + /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only * valid if applicable for measurement type requested. */ __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */ __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */ diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 9a86688aea67..b7bd3ec4cc50 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -4990,7 +4990,7 @@ il_update_qos(struct il_priv *il) * il_mac_config - mac80211 config callback */ int -il_mac_config(struct ieee80211_hw *hw, u32 changed) +il_mac_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct il_priv *il = hw->priv; const struct il_channel_info *ch_info; diff --git a/drivers/net/wireless/intel/iwlegacy/common.h b/drivers/net/wireless/intel/iwlegacy/common.h index 52610f5e57a3..4c9836ab11dd 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.h +++ b/drivers/net/wireless/intel/iwlegacy/common.h @@ -1956,7 +1956,7 @@ il_get_hw_mode(struct il_priv *il, enum nl80211_band band) } /* mac80211 handlers */ -int il_mac_config(struct ieee80211_hw *hw, u32 changed); +int il_mac_config(struct ieee80211_hw *hw, int radio_idx, u32 changed); void il_mac_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u64 changes); diff --git a/drivers/net/wireless/intel/iwlwifi/Kconfig b/drivers/net/wireless/intel/iwlwifi/Kconfig index 82f577da1a8b..153a8368b412 100644 --- a/drivers/net/wireless/intel/iwlwifi/Kconfig +++ b/drivers/net/wireless/intel/iwlwifi/Kconfig @@ -97,6 +97,7 @@ config IWLWIFI_OPMODE_MODULAR default y if IWLDVM=m default y if IWLMVM=m default y if IWLMLD=m + default y if IWLWIFI_KUNIT_TESTS=m comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM or IWLMLD" depends on IWLDVM=n && IWLMVM=n && IWLMLD=n diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 3f476e333726..941257b811b4 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -7,9 +7,11 @@ iwlwifi-objs += iwl-debug.o iwlwifi-objs += iwl-nvm-utils.o iwlwifi-objs += iwl-utils.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o -iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o -iwlwifi-objs += pcie/ctxt-info.o pcie/ctxt-info-v2.o -iwlwifi-objs += pcie/trans-gen2.o pcie/tx-gen2.o + +# Bus +iwlwifi-objs += pcie/ctxt-info.o pcie/ctxt-info-v2.o pcie/drv.o pcie/utils.o +iwlwifi-objs += pcie/gen1_2/rx.o pcie/gen1_2/tx.o pcie/gen1_2/trans.o +iwlwifi-objs += pcie/gen1_2/trans-gen2.o pcie/gen1_2/tx-gen2.o CFLAGS_pcie/drv.o += -Wno-override-init @@ -20,6 +22,7 @@ iwlwifi-$(CONFIG_IWLMVM) += cfg/7000.o cfg/8000.o # MAC configurations iwlwifi-$(CONFIG_IWLMVM) += cfg/9000.o cfg/22000.o iwlwifi-$(CONFIG_IWLMVM) += cfg/ax210.o +iwlwifi-$(CONFIG_IWLMVM) += cfg/bz.o cfg/sc.o iwlwifi-$(CONFIG_IWLMLD) += cfg/bz.o cfg/sc.o cfg/dr.o # RF configurations iwlwifi-$(CONFIG_IWLMVM) += cfg/rf-jf.o cfg/rf-hr.o cfg/rf-gf.o diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c index 52e0beebf9ce..ca488931a33c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c @@ -19,26 +19,8 @@ #define IWL_22000_SMEM_OFFSET 0x400000 #define IWL_22000_SMEM_LEN 0xD0000 -#define IWL_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0" -#define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0" -#define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0" -#define IWL_QU_C_JF_B_FW_PRE "iwlwifi-Qu-c0-jf-b0" -#define IWL_QUZ_A_HR_B_FW_PRE "iwlwifi-QuZ-a0-hr-b0" -#define IWL_QUZ_A_JF_B_FW_PRE "iwlwifi-QuZ-a0-jf-b0" #define IWL_CC_A_FW_PRE "iwlwifi-cc-a0" -#define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ - IWL_QU_B_HR_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_QUZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_QUZ_A_JF_B_MODULE_FIRMWARE(api) \ - IWL_QUZ_A_JF_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_QU_C_HR_B_MODULE_FIRMWARE(api) \ - IWL_QU_C_HR_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \ - IWL_QU_B_JF_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_QU_C_JF_B_MODULE_FIRMWARE(api) \ - IWL_QU_C_JF_B_FW_PRE "-" __stringify(api) ".ucode" #define IWL_CC_A_MODULE_FIRMWARE(api) \ IWL_CC_A_FW_PRE "-" __stringify(api) ".ucode" @@ -132,10 +114,4 @@ const char iwl_ax201_killer_1650s_name[] = const char iwl_ax201_killer_1650i_name[] = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)"; -MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QU_C_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c index 3bf9fdbe01c6..ddf3d313da5a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c @@ -13,33 +13,12 @@ #define IWL_AX210_UCODE_API_MAX 89 /* Lowest firmware API version supported */ -#define IWL_AX210_UCODE_API_MIN 77 +#define IWL_AX210_UCODE_API_MIN 89 /* Memory offsets and lengths */ #define IWL_AX210_SMEM_OFFSET 0x400000 #define IWL_AX210_SMEM_LEN 0xD0000 -#define IWL_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0" -#define IWL_SO_A_HR_B_FW_PRE "iwlwifi-so-a0-hr-b0" -#define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0" -#define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0" -#define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0" -#define IWL_MA_A_HR_B_FW_PRE "iwlwifi-ma-a0-hr-b0" -#define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0" -#define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0" -#define IWL_MA_B_HR_B_FW_PRE "iwlwifi-ma-b0-hr-b0" -#define IWL_MA_B_GF_A_FW_PRE "iwlwifi-ma-b0-gf-a0" -#define IWL_MA_B_GF4_A_FW_PRE "iwlwifi-ma-b0-gf4-a0" - -#define IWL_SO_A_JF_B_MODULE_FIRMWARE(api) \ - IWL_SO_A_JF_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_SO_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_SO_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_MA_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_MA_B_HR_B_FW_PRE "-" __stringify(api) ".ucode" - static const struct iwl_family_base_params iwl_ax210_base = { .num_of_queues = 512, .max_tfd_queue_size = 65536, @@ -143,14 +122,3 @@ const struct iwl_mac_cfg iwl_ma_mac_cfg = { .integrated = true, .umac_prph_offset = 0x300000 }; - -MODULE_FIRMWARE(IWL_SO_A_JF_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -IWL_FW_AND_PNVM(IWL_SO_A_GF_A_FW_PRE, IWL_AX210_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_TY_A_GF_A_FW_PRE, IWL_AX210_UCODE_API_MAX); -MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -IWL_FW_AND_PNVM(IWL_MA_A_GF_A_FW_PRE, IWL_AX210_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_MA_A_GF4_A_FW_PRE, IWL_AX210_UCODE_API_MAX); -MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); -IWL_FW_AND_PNVM(IWL_MA_B_GF_A_FW_PRE, IWL_AX210_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_MA_B_GF4_A_FW_PRE, IWL_AX210_UCODE_API_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 05e45fff8b36..9f543946b285 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,27 +10,21 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 99 +#define IWL_BZ_UCODE_API_MAX 102 /* Lowest firmware API version supported */ -#define IWL_BZ_UCODE_API_MIN 93 +#define IWL_BZ_UCODE_API_MIN 98 /* Memory offsets and lengths */ #define IWL_BZ_SMEM_OFFSET 0x400000 #define IWL_BZ_SMEM_LEN 0xD0000 -#define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0" -#define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0" -#define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0" #define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" #define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" #define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" #define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" #define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" -#define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \ - IWL_BZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" - static const struct iwl_family_base_params iwl_bz_base = { .num_of_queues = 512, .max_tfd_queue_size = 65536, @@ -107,9 +101,6 @@ const struct iwl_mac_cfg iwl_gl_mac_cfg = { .low_latency_xtal = true, }; -MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); -IWL_FW_AND_PNVM(IWL_BZ_A_GF_A_FW_PRE, IWL_BZ_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_BZ_A_GF4_A_FW_PRE, IWL_BZ_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_API_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index 45e55cef42ea..807f4e29d55a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c @@ -9,10 +9,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_DR_UCODE_API_MAX 99 +#define IWL_DR_UCODE_API_MAX 102 /* Lowest firmware API version supported */ -#define IWL_DR_UCODE_API_MIN 97 +#define IWL_DR_UCODE_API_MIN 98 /* Memory offsets and lengths */ #define IWL_DR_SMEM_OFFSET 0x400000 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c index f55c286e83be..7ff5170faaa9 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c @@ -5,6 +5,24 @@ */ #include "iwl-config.h" +/* Highest firmware API version supported */ +#define IWL_GF_UCODE_API_MAX 100 + +/* Lowest firmware API version supported */ +#define IWL_GF_UCODE_API_MIN 98 + +#define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0" +#define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0" +#define IWL_MA_A_GF_A_FW_PRE "iwlwifi-ma-a0-gf-a0" +#define IWL_MA_B_GF_A_FW_PRE "iwlwifi-ma-b0-gf-a0" +#define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0" +#define IWL_MA_A_GF4_A_FW_PRE "iwlwifi-ma-a0-gf4-a0" +#define IWL_MA_B_GF4_A_FW_PRE "iwlwifi-ma-b0-gf4-a0" +#define IWL_BZ_A_GF_A_FW_PRE "iwlwifi-bz-a0-gf-a0" +#define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0" +#define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0" +#define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0" + /* NVM versions */ #define IWL_GF_NVM_VERSION 0x0a1d @@ -22,6 +40,8 @@ const struct iwl_rf_cfg iwl_rf_gf = { .nvm_ver = IWL_GF_NVM_VERSION, .nvm_type = IWL_NVM_EXT, .num_rbds = IWL_NUM_RBDS_HE, + .ucode_api_min = IWL_GF_UCODE_API_MIN, + .ucode_api_max = IWL_GF_UCODE_API_MAX, }; const char iwl_ax210_killer_1675w_name[] = @@ -40,3 +60,14 @@ const char iwl_ax411_killer_1690i_name[] = const char iwl_ax210_name[] = "Intel(R) Wi-Fi 6E AX210 160MHz"; const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz"; + +IWL_FW_AND_PNVM(IWL_SO_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_TY_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_MA_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_MA_B_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_MA_A_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_MA_B_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_BZ_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_BZ_A_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_SC_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX); +IWL_FW_AND_PNVM(IWL_SC_A_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c index db02664e3917..9f408d276ce9 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c @@ -5,6 +5,41 @@ */ #include "iwl-config.h" +/* Highest firmware API version supported */ +#define IWL_HR_UCODE_API_MAX 100 + +/* Lowest firmware API version supported */ +#define IWL_HR_UCODE_API_MIN 98 + +#define IWL_QU_B_HR_B_FW_PRE "iwlwifi-Qu-b0-hr-b0" +#define IWL_QU_C_HR_B_FW_PRE "iwlwifi-Qu-c0-hr-b0" +#define IWL_QUZ_A_HR_B_FW_PRE "iwlwifi-QuZ-a0-hr-b0" +#define IWL_SO_A_HR_B_FW_PRE "iwlwifi-so-a0-hr-b0" +#define IWL_MA_A_HR_B_FW_PRE "iwlwifi-ma-a0-hr-b0" +#define IWL_MA_B_HR_B_FW_PRE "iwlwifi-ma-b0-hr-b0" +#define IWL_BZ_A_HR_B_FW_PRE "iwlwifi-bz-a0-hr-b0" +#define IWL_SC_A_HR_A_FW_PRE "iwlwifi-sc-a0-hr-b0" +#define IWL_SC_A_HR_B_FW_PRE "iwlwifi-sc-a0-hr-b0" + +#define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ + IWL_QU_B_HR_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_QUZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_QU_C_HR_B_MODULE_FIRMWARE(api) \ + IWL_QU_C_HR_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SO_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_SO_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(api) \ + IWL_MA_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(api) \ + IWL_MA_B_HR_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_BZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_HR_A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(api) \ + IWL_SC_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" + /* NVM versions */ #define IWL_HR_NVM_VERSION 0x0a1d @@ -20,7 +55,9 @@ }, \ .num_rbds = IWL_NUM_RBDS_HE, \ .nvm_ver = IWL_HR_NVM_VERSION, \ - .nvm_type = IWL_NVM_EXT + .nvm_type = IWL_NVM_EXT, \ + .ucode_api_min = IWL_HR_UCODE_API_MIN, \ + .ucode_api_max = IWL_HR_UCODE_API_MAX const struct iwl_rf_cfg iwl_rf_hr1 = { IWL_DEVICE_HR, @@ -40,3 +77,13 @@ const char iwl_ax101_name[] = "Intel(R) Wi-Fi 6 AX101"; const char iwl_ax200_name[] = "Intel(R) Wi-Fi 6 AX200 160MHz"; const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz"; const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203"; + +MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-jf.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-jf.c index 467eaeae6deb..0a074e0a3bc6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-jf.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-jf.c @@ -5,6 +5,26 @@ */ #include "iwl-config.h" +/* Highest firmware API version supported */ +#define IWL_JF_UCODE_API_MAX 77 + +/* Lowest firmware API version supported */ +#define IWL_JF_UCODE_API_MIN 77 + +#define IWL_QU_B_JF_B_FW_PRE "iwlwifi-Qu-b0-jf-b0" +#define IWL_QU_C_JF_B_FW_PRE "iwlwifi-Qu-c0-jf-b0" +#define IWL_QUZ_A_JF_B_FW_PRE "iwlwifi-QuZ-a0-jf-b0" +#define IWL_SO_A_JF_B_FW_PRE "iwlwifi-so-a0-jf-b0" + +#define IWL_QUZ_A_JF_B_MODULE_FIRMWARE(api) \ + IWL_QUZ_A_JF_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_QU_B_JF_B_MODULE_FIRMWARE(api) \ + IWL_QU_B_JF_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_QU_C_JF_B_MODULE_FIRMWARE(api) \ + IWL_QU_C_JF_B_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SO_A_JF_B_MODULE_FIRMWARE(api) \ + IWL_SO_A_JF_B_FW_PRE "-" __stringify(api) ".ucode" + /* NVM versions */ #define IWL_JF_NVM_VERSION 0x0a1d @@ -56,7 +76,9 @@ static const struct iwl_tt_params iwl_jf_tt_params = { BIT(NL80211_BAND_5GHZ), \ }, \ .nvm_ver = IWL_JF_NVM_VERSION, \ - .nvm_type = IWL_NVM_EXT + .nvm_type = IWL_NVM_EXT, \ + .ucode_api_min = IWL_JF_UCODE_API_MIN, \ + .ucode_api_max = IWL_JF_UCODE_API_MAX const struct iwl_rf_cfg iwl_rf_jf = { IWL_DEVICE_JF, @@ -82,3 +104,8 @@ const char iwl9560_killer_1550i_name[] = "Killer(R) Wireless-AC 1550i Wireless Network Adapter (9560NGW) 160MHz"; const char iwl9560_killer_1550s_name[] = "Killer(R) Wireless-AC 1550s Wireless Network Adapter (9560D2W) 160MHz"; + +MODULE_FIRMWARE(IWL_QU_B_JF_B_MODULE_FIRMWARE(IWL_JF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QU_C_JF_B_MODULE_FIRMWARE(IWL_JF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_QUZ_A_JF_B_MODULE_FIRMWARE(IWL_JF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SO_A_JF_B_MODULE_FIRMWARE(IWL_JF_UCODE_API_MAX)); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index b2e4d4035296..6d4a3bce49b9 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,10 +10,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 99 +#define IWL_SC_UCODE_API_MAX 102 /* Lowest firmware API version supported */ -#define IWL_SC_UCODE_API_MIN 97 +#define IWL_SC_UCODE_API_MIN 98 /* NVM versions */ #define IWL_SC_NVM_VERSION 0x0a1d @@ -24,20 +24,9 @@ #define IWL_SC_A_FM_B_FW_PRE "iwlwifi-sc-a0-fm-b0" #define IWL_SC_A_FM_C_FW_PRE "iwlwifi-sc-a0-fm-c0" -#define IWL_SC_A_HR_A_FW_PRE "iwlwifi-sc-a0-hr-b0" -#define IWL_SC_A_HR_B_FW_PRE "iwlwifi-sc-a0-hr-b0" -#define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0" -#define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0" #define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0" #define IWL_SC2_A_FM_C_FW_PRE "iwlwifi-sc2-a0-fm-c0" #define IWL_SC2_A_WH_A_FW_PRE "iwlwifi-sc2-a0-wh-a0" -#define IWL_SC2F_A_FM_C_FW_PRE "iwlwifi-sc2f-a0-fm-c0" -#define IWL_SC2F_A_WH_A_FW_PRE "iwlwifi-sc2f-a0-wh-a0" - -#define IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_HR_A_FW_PRE "-" __stringify(api) ".ucode" -#define IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(api) \ - IWL_SC_A_HR_B_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_family_base_params iwl_sc_base = { .num_of_queues = 512, @@ -107,12 +96,6 @@ const struct iwl_mac_cfg iwl_sc_mac_cfg = { IWL_FW_AND_PNVM(IWL_SC_A_FM_B_FW_PRE, IWL_SC_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_SC_A_FM_C_FW_PRE, IWL_SC_UCODE_API_MAX); -MODULE_FIRMWARE(IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); -MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); -IWL_FW_AND_PNVM(IWL_SC_A_GF_A_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC_A_GF4_A_FW_PRE, IWL_SC_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_SC_A_WH_A_FW_PRE, IWL_SC_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_SC2_A_FM_C_FW_PRE, IWL_SC_UCODE_API_MAX); IWL_FW_AND_PNVM(IWL_SC2_A_WH_A_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC2F_A_FM_C_FW_PRE, IWL_SC_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_SC2F_A_WH_A_FW_PRE, IWL_SC_UCODE_API_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h index 1ebc7effcc2a..9d99374ee093 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/agn.h @@ -88,7 +88,7 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, int iwlagn_set_pan_params(struct iwl_priv *priv); int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx); void iwlagn_set_rxon_chain(struct iwl_priv *priv, struct iwl_rxon_context *ctx); -int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed); +int iwlagn_mac_config(struct ieee80211_hw *hw, int radio_idx, u32 changed); void iwlagn_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, @@ -388,7 +388,7 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state) /** * iwl_parse_eeprom_data - parse EEPROM data and return values * - * @trans: ransport we're parsing for, for debug only + * @trans: transport we're parsing for, for debug only * @cfg: device configuration for parsing and overrides * @eeprom: the EEPROM data * @eeprom_size: length of the EEPROM data @@ -397,6 +397,8 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state) * returns a (newly allocated) struct containing all the * relevant values for driver use. The struct must be freed * later with iwl_free_nvm_data(). + * + * Return: the parsed NVM data */ struct iwl_nvm_data * iwl_parse_eeprom_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h index 96ea6c8dfc89..138b11f51d00 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/commands.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2023-2024 Intel Corporation + * Copyright (C) 2005-2014, 2023-2025 Intel Corporation */ /* * Please use this file (commands.h) only for uCode API definitions. @@ -614,7 +614,7 @@ struct iwl_rxon_time_cmd { * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ /** - * struct iwl5000_channel_switch_cmd + * struct iwl5000_channel_switch_cmd - channel switch command (5000 series) * @band: 0- 5.2GHz, 1- 2.4GHz * @expect_beacon: 0- resume transmits after channel switch * 1- wait for beacon to resume transmits @@ -635,7 +635,7 @@ struct iwl5000_channel_switch_cmd { } __packed; /** - * struct iwl6000_channel_switch_cmd + * struct iwl6000_channel_switch_cmd - channel switch command (6000 series) * @band: 0- 5.2GHz, 1- 2.4GHz * @expect_beacon: 0- resume transmits after channel switch * 1- wait for beacon to resume transmits @@ -791,7 +791,7 @@ struct iwl_keyinfo { } __packed; /** - * struct sta_id_modify + * struct sta_id_modify - station modify command * @addr: station's MAC address * @reserved1: reserved for alignment * @sta_id: index of station in uCode's station table @@ -2026,7 +2026,7 @@ struct iwl_spectrum_notification { u8 channel; u8 type; /* see enum iwl_measurement_type */ u8 reserved1; - /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only + /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only * valid if applicable for measurement type requested. */ __le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */ __le32 cca_cck; /* cca fraction time in 44Mhz clock periods */ @@ -2992,7 +2992,7 @@ struct iwl_missed_beacon_notif { #define SENSITIVITY_CMD_CONTROL_WORK_TABLE cpu_to_le16(1) /** - * struct iwl_sensitivity_cmd + * struct iwl_sensitivity_cmd - sensitivity configuration command * @control: (1) updates working table, (0) updates default table * @table: energy threshold values, use HD_* as index into table * @@ -3848,7 +3848,7 @@ struct iwlagn_wowlan_status { #define IWL_MIN_SLOT_TIME 20 /** - * struct iwl_wipan_slot + * struct iwl_wipan_slot - WiPAN slot configuration * @width: Time in TU * @type: * 0 - BSS @@ -3868,7 +3868,7 @@ struct iwl_wipan_slot { #define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE BIT(5) /** - * struct iwl_wipan_params_cmd + * struct iwl_wipan_params_cmd - WiPAN parameters * @flags: * bit0: reserved * bit1: CP leave channel with CTS diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h index 25b24820466d..4d12bf901703 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/dev.h @@ -104,7 +104,7 @@ struct iwl_qos_info { }; /** - * enum iwl_agg_state + * enum iwl_agg_state - aggregation state * * The state machine of the BA agreement establishment / tear down. * These states relate to a specific RA / TID. @@ -519,7 +519,7 @@ enum iwl_scan_type { }; /** - * struct iwl_hw_params + * struct iwl_hw_params - HW parameters * * Holds the module parameters * diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/devices.c b/drivers/net/wireless/intel/iwlwifi/dvm/devices.c index 3447ae0b160a..be7e61e2b291 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/devices.c @@ -55,6 +55,7 @@ static void iwl1000_nic_config(struct iwl_priv *priv) * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time * @priv: pointer to iwl_priv data structure * @tsf_bits: number of bits need to shift for masking) + * Return: low 32 bits of beacon time mask */ static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv, u16 tsf_bits) @@ -66,6 +67,7 @@ static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv, * iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time * @priv: pointer to iwl_priv data structure * @tsf_bits: number of bits need to shift for masking) + * Return: high 32 bits of beacon time mask */ static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv, u16 tsf_bits) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c b/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c index 2423125e5284..9f8cdb027839 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c @@ -676,15 +676,14 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans) CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM, - IWL_EEPROM_SEM_TIMEOUT); - if (ret >= 0) { + ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM, + IWL_EEPROM_SEM_TIMEOUT); + if (!ret) { IWL_DEBUG_EEPROM(trans->dev, "Acquired semaphore after %d tries.\n", count+1); - return ret; + return 0; } } @@ -797,11 +796,10 @@ static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, iwl_write32(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { + ret = iwl_poll_bits(trans, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret) { IWL_ERR(trans, "Time out reading OTP[%d]\n", addr); return ret; } @@ -943,14 +941,14 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size) return -ENOMEM; ret = iwl_eeprom_verify_signature(trans, nvm_is_otp); - if (ret < 0) { + if (ret) { IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); goto err_free; } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ ret = iwl_eeprom_acquire_semaphore(trans); - if (ret < 0) { + if (ret) { IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n"); goto err_free; } @@ -993,11 +991,10 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size) iwl_write32(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { + ret = iwl_poll_bits(trans, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret) { IWL_ERR(trans, "Time out reading EEPROM[%d]\n", addr); goto err_unlock; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 1dc974e2c511..48711dbcfa5a 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -586,7 +586,7 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv, return false; } - ave_rssi = ieee80211_ave_rssi(ctx->vif); + ave_rssi = ieee80211_ave_rssi(ctx->vif, -1); if (!ave_rssi) { /* no rssi data, no changes to reduce tx power */ IWL_DEBUG_COEX(priv, "no rssi data available\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 66211426aa3a..2b4dbebc71c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1049,9 +1049,11 @@ static void iwl_bg_restart(struct work_struct *data) * *****************************************************************************/ -static void iwl_setup_deferred_work(struct iwl_priv *priv) +static int iwl_setup_deferred_work(struct iwl_priv *priv) { priv->workqueue = alloc_ordered_workqueue(DRV_NAME, 0); + if (!priv->workqueue) + return -ENOMEM; INIT_WORK(&priv->restart, iwl_bg_restart); INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); @@ -1068,6 +1070,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) timer_setup(&priv->statistics_periodic, iwl_bg_statistics_periodic, 0); timer_setup(&priv->ucode_trace, iwl_bg_ucode_trace, 0); + + return 0; } void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -1463,7 +1467,10 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, /******************** * 6. Setup services ********************/ - iwl_setup_deferred_work(priv); + err = iwl_setup_deferred_work(priv); + if (err) + goto out_uninit_drv; + iwl_setup_rx_handlers(priv); iwl_power_initialize(priv); @@ -1502,6 +1509,7 @@ out_destroy_workqueue: iwl_cancel_deferred_work(priv); destroy_workqueue(priv->workqueue); priv->workqueue = NULL; +out_uninit_drv: iwl_uninit_drv(priv); out_free_eeprom_blob: kfree(priv->eeprom_blob); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/power.h b/drivers/net/wireless/intel/iwlwifi/dvm/power.h index f38201ce1e99..1a688d942bca 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/power.h +++ b/drivers/net/wireless/intel/iwlwifi/dvm/power.h @@ -23,6 +23,4 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, int iwl_power_update_mode(struct iwl_priv *priv, bool force); void iwl_power_initialize(struct iwl_priv *priv); -extern bool no_sleep_autoadjust; - #endif /* __iwl_power_setting_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c index 8879e668ef0d..ed964103281e 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c @@ -2899,7 +2899,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, /* Repeat initial/next rate. * For legacy IWL_NUMBER_TRY == 1, this loop will not execute. * For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */ - while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) { + while (repeat_rate > 0 && index < (LINK_QUAL_MAX_RETRY_NUM - 1)) { if (is_legacy(tbl_type.lq_type)) { if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE) ant_toggle_cnt++; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index 5f8b60824043..b34ee68f3dce 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -429,7 +429,7 @@ static void iwlagn_rx_statistics(struct iwl_priv *priv, * thermal update even if the uCode doesn't give * us one */ mod_timer(&priv->statistics_periodic, jiffies + - msecs_to_jiffies(reg_recalib_period * 1000)); + secs_to_jiffies(reg_recalib_period)); if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) && (pkt->hdr.cmd == STATISTICS_NOTIFICATION)) { diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c index 2d3c1627f283..e08e44cae434 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rxon.c @@ -1149,7 +1149,7 @@ void iwlagn_config_ht40(struct ieee80211_conf *conf, } } -int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed) +int iwlagn_mac_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw); struct iwl_rxon_context *ctx; diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c index 24fefa0e8148..a7806776a51e 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c @@ -232,6 +232,8 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv, * that may be %NULL, for example during TX or key setup. In * that case, we need to use the broadcast station, so this * inline wraps that pattern. + * + * Return: station ID for mac80211 station (or broadcast if %NULL) */ static int iwl_sta_id_or_broadcast(struct iwl_rxon_context *context, struct ieee80211_sta *sta) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h index 3ce477c248ce..ad5b95cad0bf 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/alive.h @@ -82,21 +82,6 @@ struct iwl_alive_ntf_v3 { struct iwl_umac_alive umac_data; } __packed; /* UCODE_ALIVE_NTFY_API_S_VER_3 */ -struct iwl_alive_ntf_v4 { - __le16 status; - __le16 flags; - struct iwl_lmac_alive lmac_data[2]; - struct iwl_umac_alive umac_data; -} __packed; /* UCODE_ALIVE_NTFY_API_S_VER_4 */ - -struct iwl_alive_ntf_v5 { - __le16 status; - __le16 flags; - struct iwl_lmac_alive lmac_data[2]; - struct iwl_umac_alive umac_data; - struct iwl_sku_id sku_id; -} __packed; /* UCODE_ALIVE_NTFY_API_S_VER_5 */ - struct iwl_imr_alive_info { __le64 base_addr; __le32 size; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 1c86a858aaab..997b0c9ce984 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -573,9 +573,8 @@ enum iwl_legacy_cmds { WOWLAN_KEK_KCK_MATERIAL = 0xe4, /** - * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status_v6, - * &struct iwl_wowlan_status_v7, &struct iwl_wowlan_status_v9 or - * &struct iwl_wowlan_status_v12 + * @WOWLAN_GET_STATUSES: response in &struct iwl_wowlan_status_v6 or + * &struct iwl_wowlan_status_v7 */ WOWLAN_GET_STATUSES = 0xe5, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 9c271ea67155..53445087e9cb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -19,9 +19,11 @@ enum iwl_d0i3_flags { /** * enum iwl_d3_wakeup_flags - D3 manager wakeup flags * @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert + * @IWL_WAKEUP_D3_HOST_TIMER: wake up on host timer expiry */ enum iwl_d3_wakeup_flags { - IWL_WAKEUP_D3_CONFIG_FW_ERROR = BIT(0), + IWL_WAKEUP_D3_CONFIG_FW_ERROR = BIT(0), + IWL_WAKEUP_D3_HOST_TIMER = BIT(1), }; /* D3_MANAGER_WAKEUP_CONFIG_API_E_VER_3 */ /** @@ -454,11 +456,6 @@ struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 { union iwl_all_tsc_rsc all_tsc_rsc; } __packed; /* ALL_TSC_RSC_API_S_VER_2 */ -struct iwl_wowlan_rsc_tsc_params_cmd_v4 { - struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 params; - __le32 sta_id; -} __packed; /* ALL_TSC_RSC_API_S_VER_4 */ - struct iwl_wowlan_rsc_tsc_params_cmd { __le64 ucast_rsc[IWL_MAX_TID_COUNT]; __le64 mcast_rsc[WOWLAN_GTK_KEYS_NUM][IWL_MAX_TID_COUNT]; @@ -718,82 +715,6 @@ struct iwl_wowlan_status_v7 { } __packed; /* WOWLAN_STATUSES_API_S_VER_7 */ /** - * struct iwl_wowlan_status_v9 - WoWLAN status (versions 9 and 10) - * @gtk: GTK data - * @igtk: IGTK data - * @replay_ctr: GTK rekey replay counter - * @pattern_number: number of the matched pattern - * @non_qos_seq_ctr: non-QoS sequence counter to use next. - * Reserved if the struct has version >= 10. - * @qos_seq_ctr: QoS sequence counters to use next - * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason - * @num_of_gtk_rekeys: number of GTK rekeys - * @transmitted_ndps: number of transmitted neighbor discovery packets - * @received_beacons: number of received beacons - * @wake_packet_length: wakeup packet length - * @wake_packet_bufsize: wakeup packet buffer size - * @tid_tear_down: bit mask of tids whose BA sessions were closed - * in suspend state - * @reserved: unused - * @wake_packet: wakeup packet - */ -struct iwl_wowlan_status_v9 { - struct iwl_wowlan_gtk_status_v2 gtk[WOWLAN_GTK_KEYS_NUM]; - struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; - __le64 replay_ctr; - __le16 pattern_number; - __le16 non_qos_seq_ctr; - __le16 qos_seq_ctr[8]; - __le32 wakeup_reasons; - __le32 num_of_gtk_rekeys; - __le32 transmitted_ndps; - __le32 received_beacons; - __le32 wake_packet_length; - __le32 wake_packet_bufsize; - u8 tid_tear_down; - u8 reserved[3]; - u8 wake_packet[]; /* can be truncated from _length to _bufsize */ -} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_9 */ - -/** - * struct iwl_wowlan_status_v12 - WoWLAN status - * @gtk: GTK data - * @igtk: IGTK data - * @replay_ctr: GTK rekey replay counter - * @pattern_number: number of the matched pattern - * @non_qos_seq_ctr: non-QoS sequence counter to use next. - * Reserved if the struct has version >= 10. - * @qos_seq_ctr: QoS sequence counters to use next - * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason - * @num_of_gtk_rekeys: number of GTK rekeys - * @transmitted_ndps: number of transmitted neighbor discovery packets - * @received_beacons: number of received beacons - * @wake_packet_length: wakeup packet length - * @wake_packet_bufsize: wakeup packet buffer size - * @tid_tear_down: bit mask of tids whose BA sessions were closed - * in suspend state - * @reserved: unused - * @wake_packet: wakeup packet - */ -struct iwl_wowlan_status_v12 { - struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; - struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; - __le64 replay_ctr; - __le16 pattern_number; - __le16 non_qos_seq_ctr; - __le16 qos_seq_ctr[8]; - __le32 wakeup_reasons; - __le32 num_of_gtk_rekeys; - __le32 transmitted_ndps; - __le32 received_beacons; - __le32 wake_packet_length; - __le32 wake_packet_bufsize; - u8 tid_tear_down; - u8 reserved[3]; - u8 wake_packet[]; /* can be truncated from _length to _bufsize */ -} __packed; /* WOWLAN_STATUSES_RSP_API_S_VER_12 */ - -/** * struct iwl_wowlan_info_notif_v1 - WoWLAN information notification * @gtk: GTK data * @igtk: IGTK data @@ -830,39 +751,6 @@ struct iwl_wowlan_info_notif_v1 { u8 reserved2[2]; } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_1 */ -/** - * struct iwl_wowlan_info_notif_v2 - WoWLAN information notification - * @gtk: GTK data - * @igtk: IGTK data - * @replay_ctr: GTK rekey replay counter - * @pattern_number: number of the matched patterns - * @reserved1: reserved - * @qos_seq_ctr: QoS sequence counters to use next - * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason - * @num_of_gtk_rekeys: number of GTK rekeys - * @transmitted_ndps: number of transmitted neighbor discovery packets - * @received_beacons: number of received beacons - * @tid_tear_down: bit mask of tids whose BA sessions were closed - * in suspend state - * @station_id: station id - * @reserved2: reserved - */ -struct iwl_wowlan_info_notif_v2 { - struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; - struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; - __le64 replay_ctr; - __le16 pattern_number; - __le16 reserved1; - __le16 qos_seq_ctr[8]; - __le32 wakeup_reasons; - __le32 num_of_gtk_rekeys; - __le32 transmitted_ndps; - __le32 received_beacons; - u8 tid_tear_down; - u8 station_id; - u8 reserved2[2]; -} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_2 */ - /* MAX MLO keys of non-active links that can arrive in the notification */ #define WOWLAN_MAX_MLO_KEYS 18 @@ -910,7 +798,7 @@ struct iwl_wowlan_mlo_gtk { } __packed; /* WOWLAN_MLO_GTK_KEY_API_S_VER_1 */ /** - * struct iwl_wowlan_info_notif_v4 - WoWLAN information notification + * struct iwl_wowlan_info_notif_v3 - WoWLAN information notification * @gtk: GTK data * @igtk: IGTK data * @bigtk: BIGTK data @@ -925,12 +813,9 @@ struct iwl_wowlan_mlo_gtk { * @tid_tear_down: bit mask of tids whose BA sessions were closed * in suspend state * @station_id: station id - * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs - * following this notif, or reserved in version < 4 * @reserved2: reserved - * @mlo_gtks: array of GTKs of size num_mlo_link_keys for version >= 4 */ -struct iwl_wowlan_info_notif_v4 { +struct iwl_wowlan_info_notif_v3 { struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; @@ -944,10 +829,8 @@ struct iwl_wowlan_info_notif_v4 { __le32 received_beacons; u8 tid_tear_down; u8 station_id; - u8 num_mlo_link_keys; - u8 reserved2; - struct iwl_wowlan_mlo_gtk mlo_gtks[]; -} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */ + u8 reserved2[2]; +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3 */ /** * struct iwl_wowlan_info_notif - WoWLAN information notification diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index 9c88bb280609..b1c6ee8ae2df 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -91,12 +91,6 @@ enum iwl_data_path_subcmd_ids { SEC_KEY_CMD = 0x18, /** - * @OMI_SEND_STATUS_NOTIF: notification after OMI was sent - * uses &struct iwl_omi_send_status_notif - */ - OMI_SEND_STATUS_NOTIF = 0xF2, - - /** * @ESR_MODE_NOTIF: notification to recommend/force a wanted esr mode, * uses &struct iwl_esr_mode_notif or &struct iwl_esr_mode_notif_v1 */ @@ -125,6 +119,11 @@ enum iwl_data_path_subcmd_ids { TLC_MNG_UPDATE_NOTIF = 0xF7, /** + * @BEACON_FILTER_IN_NOTIF: &struct iwl_beacon_filter_notif + */ + BEACON_FILTER_IN_NOTIF = 0xF8, + + /** * @STA_PM_NOTIF: &struct iwl_mvm_pm_state_notification */ STA_PM_NOTIF = 0xFD, @@ -694,13 +693,4 @@ struct iwl_sec_key_cmd { } __packed u; /* SEC_KEY_OPERATION_API_U_VER_1 */ } __packed; /* SEC_KEY_CMD_API_S_VER_1 */ -/** - * struct iwl_omi_send_status_notif - OMI status notification - * @success: indicates that the OMI was sent successfully - * (currently always set) - */ -struct iwl_omi_send_status_notif { - __le32 success; -} __packed; /* OMI_SEND_STATUS_NTFY_API_S_VER_1 */ - #endif /* __iwl_fw_api_datapath_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h index 9b09b835560b..2a1c2b0f19e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h @@ -3,7 +3,7 @@ * Copyright (C) 2012-2014 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2021-2024 Intel Corporation + * Copyright (C) 2021-2025 Intel Corporation */ #ifndef __iwl_fw_api_offload_h__ #define __iwl_fw_api_offload_h__ @@ -19,7 +19,7 @@ enum iwl_prot_offload_subcmd_ids { /** * @WOWLAN_INFO_NOTIFICATION: Notification in - * &struct iwl_wowlan_info_notif_v1, &struct iwl_wowlan_info_notif_v2, + * &struct iwl_wowlan_info_notif_v1, iwl_wowlan_info_notif_v3, * or &struct iwl_wowlan_info_notif */ WOWLAN_INFO_NOTIFICATION = 0xFD, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 23140205ccb9..786b3bf4b448 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -255,19 +255,6 @@ struct iwl_uapsd_misbehaving_ap_notif { u8 reserved[3]; } __packed; -/** - * struct iwl_reduce_tx_power_cmd - TX power reduction command - * REDUCE_TX_POWER_CMD = 0x9f - * @flags: (reserved for future implementation) - * @mac_context_id: id of the mac ctx for which we are reducing TX power. - * @pwr_restriction: TX power restriction in dBms. - */ -struct iwl_reduce_tx_power_cmd { - u8 flags; - u8 mac_context_id; - __le16 pwr_restriction; -} __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ - enum iwl_dev_tx_power_cmd_mode { IWL_TX_POWER_MODE_SET_LINK = 0, IWL_TX_POWER_MODE_SET_DEVICE = 1, @@ -342,50 +329,6 @@ struct iwl_dev_tx_power_cmd_v5 { } __packed; /* TX_REDUCED_POWER_API_S_VER_5 */ /** - * struct iwl_dev_tx_power_cmd_v6 - TX power reduction command version 6 - * @per_chain: per chain restrictions - * @enable_ack_reduction: enable or disable close range ack TX power - * reduction. - * @per_chain_restriction_changed: is per_chain_restriction has changed - * from last command. used if set_mode is - * IWL_TX_POWER_MODE_SET_SAR_TIMER. - * note: if not changed, the command is used for keep alive only. - * @reserved: reserved (padding) - * @timer_period: timer in milliseconds. if expires FW will change to default - * BIOS values. relevant if setMode is IWL_TX_POWER_MODE_SET_SAR_TIMER - */ -struct iwl_dev_tx_power_cmd_v6 { - __le16 per_chain[IWL_NUM_CHAIN_TABLES_V2][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; - u8 enable_ack_reduction; - u8 per_chain_restriction_changed; - u8 reserved[2]; - __le32 timer_period; -} __packed; /* TX_REDUCED_POWER_API_S_VER_6 */ - -/** - * struct iwl_dev_tx_power_cmd_v7 - TX power reduction command version 7 - * @per_chain: per chain restrictions - * @enable_ack_reduction: enable or disable close range ack TX power - * reduction. - * @per_chain_restriction_changed: is per_chain_restriction has changed - * from last command. used if set_mode is - * IWL_TX_POWER_MODE_SET_SAR_TIMER. - * note: if not changed, the command is used for keep alive only. - * @reserved: reserved (padding) - * @timer_period: timer in milliseconds. if expires FW will change to default - * BIOS values. relevant if setMode is IWL_TX_POWER_MODE_SET_SAR_TIMER - * @flags: reduce power flags. - */ -struct iwl_dev_tx_power_cmd_v7 { - __le16 per_chain[IWL_NUM_CHAIN_TABLES_V2][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; - u8 enable_ack_reduction; - u8 per_chain_restriction_changed; - u8 reserved[2]; - __le32 timer_period; - __le32 flags; -} __packed; /* TX_REDUCED_POWER_API_S_VER_7 */ - -/** * struct iwl_dev_tx_power_cmd_v8 - TX power reduction command version 8 * @per_chain: per chain restrictions * @enable_ack_reduction: enable or disable close range ack TX power @@ -429,8 +372,6 @@ struct iwl_dev_tx_power_cmd_per_band { * @v3: version 3 part of the command * @v4: version 4 part of the command * @v5: version 5 part of the command - * @v6: version 6 part of the command - * @v7: version 7 part of the command * @v8: version 8 part of the command */ struct iwl_dev_tx_power_cmd_v3_v8 { @@ -440,8 +381,6 @@ struct iwl_dev_tx_power_cmd_v3_v8 { struct iwl_dev_tx_power_cmd_v3 v3; struct iwl_dev_tx_power_cmd_v4 v4; struct iwl_dev_tx_power_cmd_v5 v5; - struct iwl_dev_tx_power_cmd_v6 v6; - struct iwl_dev_tx_power_cmd_v7 v7; struct iwl_dev_tx_power_cmd_v8 v8; }; }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 7cf6d6ac7430..d751789998ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -194,7 +194,9 @@ enum iwl_rx_mpdu_amsdu_info { }; enum iwl_rx_mpdu_mac_phy_band { + /* whether or not this is MAC or LINK depends on the API */ IWL_RX_MPDU_MAC_PHY_BAND_MAC_MASK = 0x0f, + IWL_RX_MPDU_MAC_PHY_BAND_LINK_MASK = 0x0f, IWL_RX_MPDU_MAC_PHY_BAND_PHY_MASK = 0x30, IWL_RX_MPDU_MAC_PHY_BAND_BAND_MASK = 0xc0, }; @@ -671,7 +673,7 @@ struct iwl_rx_mpdu_desc { */ __le16 phy_info; /** - * @mac_phy_band: MAC ID, PHY ID, band; + * @mac_phy_band: MAC/link ID, PHY ID, band; * see &enum iwl_rx_mpdu_mac_phy_band */ u8 mac_phy_band; @@ -1019,4 +1021,24 @@ struct iwl_rfh_queue_config { struct iwl_rfh_queue_data data[]; } __packed; /* RFH_QUEUE_CONFIG_API_S_VER_1 */ +/** + * struct iwl_beacon_filter_notif_v1 - beacon filter notification + * @average_energy: average energy for the received beacon + * @mac_id: MAC ID the beacon was received for + */ +struct iwl_beacon_filter_notif_v1 { + __le32 average_energy; + __le32 mac_id; +} __packed; /* BEACON_FILTER_IN_NTFY_API_S_VER_1 */ + +/** + * struct iwl_beacon_filter_notif - beacon filter notification + * @average_energy: average energy for the received beacon + * @link_id: link ID the beacon was received for + */ +struct iwl_beacon_filter_notif { + __le32 average_energy; + __le32 link_id; +} __packed; /* BEACON_FILTER_IN_NTFY_API_S_VER_2 */ + #endif /* __iwl_fw_api_rx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h index 58d5a6ef633e..08edd1d99992 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tdls.h @@ -50,7 +50,7 @@ struct iwl_tdls_channel_switch_timing { */ struct iwl_tdls_channel_switch_frame { __le32 switch_time_offset; - struct iwl_tx_cmd_v6 tx_cmd; + struct iwl_tx_cmd_v6_params tx_cmd; u8 data[IWL_TDLS_CH_SW_FRAME_MAX_SIZE]; } __packed; /* TDLS_STA_CHANNEL_SWITCH_FRAME_API_S_VER_1 */ @@ -131,7 +131,7 @@ struct iwl_tdls_config_cmd { struct iwl_tdls_sta_info sta_info[IWL_TDLS_STA_COUNT]; __le32 pti_req_data_offset; - struct iwl_tx_cmd_v6 pti_req_tx_cmd; + struct iwl_tx_cmd_v6_params pti_req_tx_cmd; u8 pti_req_template[]; } __packed; /* TDLS_CONFIG_CMD_API_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h index f586379d66dd..46d35ef4751e 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/time-event.h @@ -452,7 +452,7 @@ struct iwl_roc_notif { * listen mode. Will be fragmented. Valid only on the P2P Device MAC. * Valid only on the P2P Device MAC. The firmware will take into account * the duration, the interval and the repetition count. - * @SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION: Schedule the P2P Device to be be + * @SESSION_PROTECT_CONF_P2P_GO_NEGOTIATION: Schedule the P2P Device to be * able to run the GO Negotiation. Will not be fragmented and not * repetitive. Valid only on the P2P Device MAC. Only the duration will * be taken into account. diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 557832563f89..26d2013905ed 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -181,8 +181,8 @@ enum iwl_tx_offload_assist_flags_pos { /* TODO: complete documentation for try_cnt and btkill_cnt */ /** - * struct iwl_tx_cmd_v6 - TX command struct to FW - * ( TX_CMD = 0x1c ) + * struct iwl_tx_cmd_v6_params - parameters of the TX + * * @len: in bytes of the payload, see below for details * @offload_assist: TX offload configuration * @tx_flags: combination of TX_CMD_FLG_*, see &enum iwl_tx_flags @@ -205,8 +205,6 @@ enum iwl_tx_offload_assist_flags_pos { * @tid_tspec: TID/tspec * @pm_frame_timeout: PM TX frame timeout * @reserved4: reserved - * @payload: payload (same as @hdr) - * @hdr: 802.11 header (same as @payload) * * The byte count (both len and next_frame_len) includes MAC header * (24/26/30/32 bytes) @@ -217,11 +215,8 @@ enum iwl_tx_offload_assist_flags_pos { * It does not include post-MAC padding, i.e., * MIC (CCM) 8 bytes, ICV (WEP/TKIP/CKIP) 4 bytes, CRC 4 bytes. * Range of len: 14-2342 bytes. - * - * After the struct fields the MAC header is placed, plus any padding, - * and then the actial payload. */ -struct iwl_tx_cmd_v6 { +struct iwl_tx_cmd_v6_params { __le16 len; __le16 offload_assist; __le32 tx_flags; @@ -245,10 +240,20 @@ struct iwl_tx_cmd_v6 { u8 tid_tspec; __le16 pm_frame_timeout; __le16 reserved4; - union { - DECLARE_FLEX_ARRAY(u8, payload); - DECLARE_FLEX_ARRAY(struct ieee80211_hdr, hdr); - }; +} __packed; /* TX_CMD_API_S_VER_6 */ + +/** + * struct iwl_tx_cmd_v6 - TX command struct to FW + * ( TX_CMD = 0x1c ) + * @params: parameters of the TX, see &struct iwl_tx_cmd_v6_tx_params + * @hdr: 802.11 header + * + * After ¶ms, the MAC header is placed, plus any padding, + * and then the actual payload. + */ +struct iwl_tx_cmd_v6 { + struct iwl_tx_cmd_v6_params params; + struct ieee80211_hdr hdr[]; } __packed; /* TX_CMD_API_S_VER_6 */ struct iwl_dram_sec_info { @@ -748,7 +753,7 @@ struct iwl_compressed_ba_notif { * @frame: the template of the beacon frame */ struct iwl_mac_beacon_cmd_v6 { - struct iwl_tx_cmd_v6 tx; + struct iwl_tx_cmd_v6_params tx; __le32 template_id; __le32 tim_idx; __le32 tim_size; @@ -767,7 +772,7 @@ struct iwl_mac_beacon_cmd_v6 { * @frame: the template of the beacon frame */ struct iwl_mac_beacon_cmd_v7 { - struct iwl_tx_cmd_v6 tx; + struct iwl_tx_cmd_v6_params tx; __le32 template_id; __le32 tim_idx; __le32 tim_size; @@ -864,7 +869,7 @@ struct iwl_extended_beacon_notif { /** * enum iwl_dump_control - dump (flush) control flags - * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty + * @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the FIFO is empty * and the TFD queues are empty. */ enum iwl_dump_control { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index ea739ebe7cb0..2879be4b8fcb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -1106,6 +1106,7 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt, u32 prph_val; u32 dphy_state; u32 dphy_addr; + u32 prph_stts; int i; range->internal_base_addr = cpu_to_le32(addr); @@ -1133,6 +1134,21 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt, iwl_write_prph_no_grab(fwrt->trans, indirect_wr_addr, WMAL_INDRCT_CMD(addr + i)); + + if (fwrt->trans->info.hw_rf_id != IWL_CFG_RF_TYPE_JF1 && + fwrt->trans->info.hw_rf_id != IWL_CFG_RF_TYPE_JF2 && + fwrt->trans->info.hw_rf_id != IWL_CFG_RF_TYPE_HR1 && + fwrt->trans->info.hw_rf_id != IWL_CFG_RF_TYPE_HR2) { + udelay(2); + prph_stts = iwl_read_prph_no_grab(fwrt->trans, + WMAL_MRSPF_STTS); + + /* Abort dump if status is 0xA5A5A5A2 or FIFO1 empty */ + if (prph_stts == WMAL_TIMEOUT_VAL || + !WMAL_MRSPF_STTS_IS_FIFO1_NOT_EMPTY(prph_stts)) + break; + } + prph_val = iwl_read_prph_no_grab(fwrt->trans, indirect_rd_addr); *val++ = cpu_to_le32(prph_val); @@ -2962,7 +2978,7 @@ IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_desc); int iwl_fw_dbg_error_collect(struct iwl_fw_runtime *fwrt, enum iwl_fw_dbg_trigger trig_type) { - if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) + if (!iwl_trans_device_enabled(fwrt->trans)) return -EIO; if (iwl_trans_dbg_ini_valid(fwrt->trans)) { @@ -3008,6 +3024,7 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, struct iwl_fw_dump_desc *desc; unsigned int delay = 0; bool monitor_only = false; + int ret; if (trigger) { u16 occurrences = le16_to_cpu(trigger->occurrences) - 1; @@ -3038,7 +3055,11 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, desc->trig_desc.type = cpu_to_le32(trig); memcpy(desc->trig_desc.data, str, len); - return iwl_fw_dbg_collect_desc(fwrt, desc, monitor_only, delay); + ret = iwl_fw_dbg_collect_desc(fwrt, desc, monitor_only, delay); + if (ret) + kfree(desc); + + return ret; } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect); @@ -3046,7 +3067,7 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, struct iwl_fw_dbg_trigger_tlv *trigger, const char *fmt, ...) { - int ret, len = 0; + int len = 0; char buf[64]; if (iwl_trans_dbg_ini_valid(fwrt->trans)) @@ -3068,13 +3089,8 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt, len = strlen(buf) + 1; } - ret = iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len, - trigger); - - if (ret) - return ret; - - return 0; + return iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len, + trigger); } IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_trig); @@ -3164,13 +3180,13 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx) goto out; } - if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) { + if (!iwl_trans_device_enabled(fwrt->trans)) { IWL_ERR(fwrt, "Device is not enabled - cannot dump error\n"); goto out; } /* there's no point in fw dump if the bus is dead */ - if (test_bit(STATUS_TRANS_DEAD, &fwrt->trans->status)) { + if (iwl_trans_is_dead(fwrt->trans)) { IWL_ERR(fwrt, "Skip fw error dump since bus is dead\n"); goto out; } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c index c70f2a20f7d5..3b0e8c43ba4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/debugfs.c @@ -198,7 +198,7 @@ void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay) iwl_fw_cancel_timestamp(fwrt); - fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000); + fwrt->timestamp.delay = secs_to_jiffies(delay); schedule_delayed_work(&fwrt->timestamp.wk, round_jiffies_relative(fwrt->timestamp.delay)); @@ -389,6 +389,12 @@ static int iwl_dbgfs_fw_info_seq_show(struct seq_file *seq, void *v) " %d: %d\n", IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT, has_capa); + has_capa = fw_has_capa(&fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE) ? 1 : 0; + seq_printf(seq, + " %d: %d\n", + IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE, + has_capa); seq_puts(seq, "fw_api_ver:\n"); } diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index 3ec42a4ea801..f633124979ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -199,7 +199,7 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu IWL_ERR(trans, "HW error, resetting before reading\n"); /* reset the device */ - err = iwl_trans_sw_reset(trans, true); + err = iwl_trans_sw_reset(trans); if (err) return; @@ -490,7 +490,7 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) struct iwl_pc_data *pc_data; u8 count; - if (!test_bit(STATUS_DEVICE_ENABLED, &fwrt->trans->status)) { + if (!iwl_trans_device_enabled(fwrt->trans)) { IWL_ERR(fwrt, "DEVICE_ENABLED bit is not set. Aborting dump.\n"); return; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 5a1ec880ed72..b7c1ab7a3006 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -104,6 +104,9 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_CURRENT_PC = 68, IWL_UCODE_TLV_FSEQ_BIN_VERSION = 72, + /* contains sub-sections like PNVM file does (did) */ + IWL_UCODE_TLV_PNVM_DATA = 74, + IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0, IWL_UCODE_TLV_FW_NUM_LINKS = IWL_UCODE_TLV_CONST_BASE + 1, IWL_UCODE_TLV_FW_NUM_BEACONS = IWL_UCODE_TLV_CONST_BASE + 2, @@ -404,6 +407,8 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * for CA from BIOS. * @IWL_UCODE_TLV_CAPA_UHB_CANADA_TAS_SUPPORT: supports %TAS_UHB_ALLOWED_CANADA * @IWL_UCODE_TLV_CAPA_EXT_FSEQ_IMAGE_SUPPORT: external FSEQ image support + * @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware has capability of + * handling raw DSM table data. * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -514,6 +519,7 @@ enum iwl_ucode_tlv_capa { * during assert handling even if the dump isn't split */ IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0), + IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 1), NUM_IWL_UCODE_TLV_CAPA /* * This construction make both sparse (which cannot increment the previous diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index f9de139561a0..5256f20623e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -53,8 +53,8 @@ struct iwl_ucode_capabilities { u32 num_stations; u32 num_links; u32 num_beacons; - unsigned long _api[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_API)]; - unsigned long _capa[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_CAPA)]; + DECLARE_BITMAP(_api, NUM_IWL_UCODE_TLV_API); + DECLARE_BITMAP(_capa, NUM_IWL_UCODE_TLV_CAPA); const struct iwl_fw_cmd_version *cmd_versions; u32 n_cmd_versions; @@ -195,6 +195,8 @@ struct iwl_dump_exclude { * @phy_integration_ver_len: length of @phy_integration_ver * @dump_excl: image dump exclusion areas for RT image * @dump_excl_wowlan: image dump exclusion areas for WoWLAN image + * @pnvm_data: PNVM data embedded in the .ucode file, if any + * @pnvm_size: size of the embedded PNVM data */ struct iwl_fw { u32 ucode_ver; @@ -227,6 +229,9 @@ struct iwl_fw { u32 phy_integration_ver_len; struct iwl_dump_exclude dump_excl[2], dump_excl_wowlan[2]; + + const void *pnvm_data; + u32 pnvm_size; }; static inline const char *get_fw_dbg_mode_string(int mode) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 4f3c2f7f4f5b..4d91ae065c8d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -11,6 +11,7 @@ #include "fw/api/nvm-reg.h" #include "fw/api/alive.h" #include "fw/uefi.h" +#include "fw/img.h" #define IWL_PNVM_REDUCED_CAP_BIT BIT(25) @@ -264,8 +265,8 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) return 0; } -static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, - __le32 sku_id[3]) +static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, + __le32 sku_id[3], const struct iwl_fw *fw) { struct pnvm_sku_package *package; u8 *image = NULL; @@ -290,6 +291,12 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, } } + if (fw->pnvm_data) { + *len = fw->pnvm_size; + + return fw->pnvm_data; + } + /* If it's not available, or for Intel SKU, try from the filesystem */ if (iwl_pnvm_get_from_fs(trans_p, &image, len)) return NULL; @@ -298,11 +305,11 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, - const struct iwl_ucode_capabilities *capa, + const struct iwl_fw *fw, __le32 sku_id[3]) { struct iwl_pnvm_image *pnvm_data = NULL; - u8 *data = NULL; + const u8 *data = NULL; size_t length; int ret; @@ -313,7 +320,7 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, if (trans->pnvm_loaded) goto set; - data = iwl_get_pnvm_image(trans, &length, sku_id); + data = iwl_get_pnvm_image(trans, &length, sku_id, fw); if (!data) { trans->fail_to_parse_pnvm_image = true; return; @@ -329,15 +336,17 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, goto free; } - ret = iwl_trans_load_pnvm(trans, pnvm_data, capa); + ret = iwl_trans_load_pnvm(trans, pnvm_data, &fw->ucode_capa); if (ret) goto free; - IWL_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); + IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); set: - iwl_trans_set_pnvm(trans, capa); + iwl_trans_set_pnvm(trans, &fw->ucode_capa); free: - kvfree(data); + /* free only if it was allocated, i.e. not just embedded PNVM data */ + if (data != fw->pnvm_data) + kvfree(data); kfree(pnvm_data); } @@ -392,8 +401,7 @@ free: int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait, - const struct iwl_ucode_capabilities *capa, - __le32 sku_id[3]) + const struct iwl_fw *fw, __le32 sku_id[3]) { struct iwl_notification_wait pnvm_wait; static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, @@ -403,8 +411,8 @@ int iwl_pnvm_load(struct iwl_trans *trans, if (!sku_id[0] && !sku_id[1] && !sku_id[2]) return 0; - iwl_pnvm_load_pnvm_to_trans(trans, capa, sku_id); - iwl_pnvm_load_reduce_power_to_trans(trans, capa, sku_id); + iwl_pnvm_load_pnvm_to_trans(trans, fw, sku_id); + iwl_pnvm_load_reduce_power_to_trans(trans, &fw->ucode_capa, sku_id); iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index 9540926e8a0f..ad3b7e2423ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -7,6 +7,7 @@ #include "iwl-drv.h" #include "fw/notif-wait.h" +#include "fw/img.h" #define MVM_UCODE_PNVM_TIMEOUT (HZ / 4) @@ -14,8 +15,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait, - const struct iwl_ucode_capabilities *capa, - __le32 sku_id[3]); + const struct iwl_fw *fw, __le32 sku_id[3]); static inline void iwl_pnvm_get_fs_name(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index ebfba981cf89..3d6d1a85bb51 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -579,6 +579,8 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, { int ret; u32 value; + bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE); u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, WIDE_ID(REGULATORY_AND_NVM_GROUP, LARI_CONFIG_CHANGE), 1); @@ -593,17 +595,22 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt); ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); - if (!ret) + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_11AX_ALLOW_BITMAP; cmd->oem_11ax_allow_bitmap = cpu_to_le32(value); + } ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); if (!ret) { - value &= DSM_UNII4_ALLOW_BITMAP; + if (!has_raw_dsm_capa) + value &= DSM_UNII4_ALLOW_BITMAP; /* Since version 9, bits 4 and 5 are supported - * regardless of this capability. + * regardless of this capability, By pass this masking + * if firmware has capability of accepting raw DSM table. */ - if (cmd_ver < 9 && + if (!has_raw_dsm_capa && cmd_ver < 9 && !fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA)) value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK | @@ -614,14 +621,17 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); if (!ret) { - value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; - if (cmd_ver < 8) + if (!has_raw_dsm_capa) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; + + if (!has_raw_dsm_capa && cmd_ver < 8) value &= ~ACTIVATE_5G2_IN_WW_MASK; /* Since version 12, bits 5 and 6 are supported - * regardless of this capability. + * regardless of this capability, By pass this masking + * if firmware has capability of accepting raw DSM table. */ - if (cmd_ver < 12 && + if (!has_raw_dsm_capa && cmd_ver < 12 && !fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA)) value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V11; @@ -634,13 +644,19 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, cmd->oem_uhb_allow_bitmap = cpu_to_le32(value); ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); - if (!ret) + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP; cmd->force_disable_channels_bitmap = cpu_to_le32(value); + } ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, &value); - if (!ret) + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_EDT_ALLOWED_BITMAP; cmd->edt_bitmap = cpu_to_le32(value); + } ret = iwl_bios_get_wbem(fwrt, &value); if (!ret) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 9bed3d573b1e..a07c512b6ed4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -159,6 +159,10 @@ enum iwl_dsm_unii4_bitmap { DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK |\ DSM_VALUE_UNII4_CANADA_EN_MSK) +#define DSM_11AX_ALLOW_BITMAP 0xF +#define DSM_EDT_ALLOWED_BITMAP 0x7ffff0 +#define DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP 0x7FF + enum iwl_dsm_values_rfi { DSM_VALUE_RFI_DLVR_DISABLE = BIT(0), DSM_VALUE_RFI_DDR_DISABLE = BIT(1), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 91f22ce36d74..30e5f5a5cd89 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -488,8 +488,8 @@ struct iwl_dev_info { rf_type:9, match_bw_limit:1, bw_limit:1, - match_rf_step:1, - rf_step:4, + match_discrete:1, + discrete:1, match_rf_id:1, rf_id:4, match_cdb:1, @@ -499,12 +499,13 @@ struct iwl_dev_info { #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) extern const struct iwl_dev_info iwl_dev_info_table[]; extern const unsigned int iwl_dev_info_table_size; -const struct iwl_dev_info * -iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, - u8 rf_id, u8 bw_limit, u8 rf_step); extern const struct pci_device_id iwl_hw_card_ids[]; #endif +const struct iwl_dev_info * +iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, + u8 rf_id, u8 bw_limit, bool discrete); + /* * This list declares the config structures for all devices. */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index 0fd452cb94ae..f3fa37fee2e4 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -113,6 +113,7 @@ #define CSR_IPC_STATE_RESET_SW_READY 1 #define CSR_IPC_STATE_RESET_TOP_READY 2 #define CSR_IPC_STATE_RESET_TOP_FOLLOWER 3 +#define CSR_IPC_STATE_TOP_RESET_REQ BIT(6) #define CSR_IPC_SLEEP_CONTROL (CSR_BASE + 0x114) #define CSR_IPC_SLEEP_CONTROL_SUSPEND 0x3 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 9504a0cb8b13..28aad975434b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -136,6 +136,9 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) kfree(drv->fw.phy_integration_ver); kfree(drv->trans->dbg.pc_data); drv->trans->dbg.pc_data = NULL; + kvfree(drv->fw.pnvm_data); + drv->fw.pnvm_data = NULL; + drv->fw.pnvm_size = 0; for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) iwl_free_fw_img(drv, drv->fw.img + i); @@ -233,10 +236,9 @@ const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) mac = "sc"; break; case IWL_CFG_MAC_TYPE_SC2: - mac = "sc2"; - break; + /* Uses the same firmware as SC2 */ case IWL_CFG_MAC_TYPE_SC2F: - mac = "sc2f"; + mac = "sc2"; break; case IWL_CFG_MAC_TYPE_BR: mac = "br"; @@ -298,13 +300,17 @@ static void iwl_get_ucode_api_versions(struct iwl_trans *trans, const struct iwl_family_base_params *base = trans->mac_cfg->base; const struct iwl_rf_cfg *cfg = trans->cfg; - if (!base->ucode_api_max) { + /* if the MAC doesn't have range or if its range it higher than the RF's */ + if (!base->ucode_api_max || + (cfg->ucode_api_max && base->ucode_api_min > cfg->ucode_api_max)) { *api_min = cfg->ucode_api_min; *api_max = cfg->ucode_api_max; return; } - if (!cfg->ucode_api_max) { + /* if the RF doesn't have range or if its range it higher than the MAC's */ + if (!cfg->ucode_api_max || + (base->ucode_api_max && cfg->ucode_api_min > base->ucode_api_max)) { *api_min = base->ucode_api_min; *api_max = base->ucode_api_max; return; @@ -1276,8 +1282,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, if (tlv_len != sizeof(*fseq_ver)) goto invalid_tlv_len; - IWL_INFO(drv, "TLV_FW_FSEQ_VERSION: %.32s\n", - fseq_ver->version); + IWL_DEBUG_INFO(drv, "TLV_FW_FSEQ_VERSION: %.32s\n", + fseq_ver->version); } break; case IWL_UCODE_TLV_FW_NUM_STATIONS: @@ -1400,6 +1406,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, drv->trans->dbg.num_pc = tlv_len / sizeof(struct iwl_pc_data); break; + case IWL_UCODE_TLV_PNVM_DATA: + if (drv->fw.pnvm_data) + break; + drv->fw.pnvm_data = + kvmemdup(tlv_data, tlv_len, GFP_KERNEL); + if (!drv->fw.pnvm_data) + return -ENOMEM; + drv->fw.pnvm_size = tlv_len; + break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; @@ -1529,7 +1544,7 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op) if (!IS_ERR(op_mode)) return op_mode; - if (test_bit(STATUS_TRANS_DEAD, &drv->trans->status)) + if (iwl_trans_is_dead(drv->trans)) break; #ifdef CONFIG_IWLWIFI_DEBUGFS @@ -2037,8 +2052,6 @@ static int __init iwl_drv_init(void) for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv); - pr_info(DRV_DESCRIPTION "\n"); - #ifdef CONFIG_IWLWIFI_DEBUGFS /* Create the root of iwlwifi debugfs subsystem. */ iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 80591809164e..5e483a55a4ba 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -47,21 +47,21 @@ IWL_EXPORT_SYMBOL(iwl_read32); #define IWL_POLL_INTERVAL 10 /* microseconds */ -int iwl_poll_bit(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout) +int iwl_poll_bits_mask(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout) { int t = 0; do { if ((iwl_read32(trans, addr) & mask) == (bits & mask)) - return t; + return 0; udelay(IWL_POLL_INTERVAL); t += IWL_POLL_INTERVAL; } while (t < timeout); return -ETIMEDOUT; } -IWL_EXPORT_SYMBOL(iwl_poll_bit); +IWL_EXPORT_SYMBOL(iwl_poll_bits_mask); u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) { @@ -75,7 +75,6 @@ u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) /* return as if we have a HW timeout/failure */ return 0x5a5a5a5a; } -IWL_EXPORT_SYMBOL(iwl_read_direct32); void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) { @@ -93,7 +92,6 @@ void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value) iwl_trans_release_nic_access(trans); } } -IWL_EXPORT_SYMBOL(iwl_write_direct64); int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, int timeout) @@ -109,7 +107,6 @@ int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, return -ETIMEDOUT; } -IWL_EXPORT_SYMBOL(iwl_poll_direct_bit); u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) { @@ -117,14 +114,12 @@ u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); return val; } -IWL_EXPORT_SYMBOL(iwl_read_prph_no_grab); void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) { trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); iwl_trans_write_prph(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_write_prph_no_grab); void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) { @@ -132,7 +127,6 @@ void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff); iwl_write_prph_no_grab(trans, ofs + 4, val >> 32); } -IWL_EXPORT_SYMBOL(iwl_write_prph64_no_grab); u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) { @@ -477,7 +471,7 @@ int iwl_finish_nic_init(struct iwl_trans *trans) * device-internal resources is supported, e.g. iwl_write_prph() * and accesses to uCode SRAM. */ - err = iwl_poll_bit(trans, CSR_GP_CNTRL, poll_ready, poll_ready, 25000); + err = iwl_poll_bits(trans, CSR_GP_CNTRL, poll_ready, 25000); if (err < 0) { IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h index f4833c5fe86e..731cda1a4e66 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h @@ -23,8 +23,13 @@ static inline void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) iwl_trans_set_bits_mask(trans, reg, mask, 0); } -int iwl_poll_bit(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout); +int iwl_poll_bits_mask(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout); +static inline int iwl_poll_bits(struct iwl_trans *trans, u32 addr, u32 bits, + int timeout) +{ + return iwl_poll_bits_mask(trans, addr, bits, bits, timeout); +} int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, int timeout); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 0592f0f59d1c..a67b9572aac3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -5,6 +5,7 @@ * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #include <linux/types.h> +#include <linux/fips.h> #include <linux/slab.h> #include <linux/export.h> #include <linux/etherdevice.h> @@ -160,23 +161,26 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = { * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) * @NVM_CHANNEL_VLP: client support connection to UHB VLP AP * @NVM_CHANNEL_AFC: client support connection to UHB AFC AP + * @NVM_CHANNEL_VLP_AP_NOT_ALLOWED: UHB VLP AP not allowed, + * Valid only when %NVM_CHANNEL_VLP is enabled. */ enum iwl_nvm_channel_flags { - NVM_CHANNEL_VALID = BIT(0), - NVM_CHANNEL_IBSS = BIT(1), - NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY = BIT(2), - NVM_CHANNEL_ACTIVE = BIT(3), - NVM_CHANNEL_RADAR = BIT(4), - NVM_CHANNEL_INDOOR_ONLY = BIT(5), - NVM_CHANNEL_GO_CONCURRENT = BIT(6), - NVM_CHANNEL_UNIFORM = BIT(7), - NVM_CHANNEL_20MHZ = BIT(8), - NVM_CHANNEL_40MHZ = BIT(9), - NVM_CHANNEL_80MHZ = BIT(10), - NVM_CHANNEL_160MHZ = BIT(11), - NVM_CHANNEL_DC_HIGH = BIT(12), - NVM_CHANNEL_VLP = BIT(13), - NVM_CHANNEL_AFC = BIT(14), + NVM_CHANNEL_VALID = BIT(0), + NVM_CHANNEL_IBSS = BIT(1), + NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY = BIT(2), + NVM_CHANNEL_ACTIVE = BIT(3), + NVM_CHANNEL_RADAR = BIT(4), + NVM_CHANNEL_INDOOR_ONLY = BIT(5), + NVM_CHANNEL_GO_CONCURRENT = BIT(6), + NVM_CHANNEL_UNIFORM = BIT(7), + NVM_CHANNEL_20MHZ = BIT(8), + NVM_CHANNEL_40MHZ = BIT(9), + NVM_CHANNEL_80MHZ = BIT(10), + NVM_CHANNEL_160MHZ = BIT(11), + NVM_CHANNEL_DC_HIGH = BIT(12), + NVM_CHANNEL_VLP = BIT(13), + NVM_CHANNEL_AFC = BIT(14), + NVM_CHANNEL_VLP_AP_NOT_ALLOWED = BIT(15), }; /** @@ -540,16 +544,22 @@ static void iwl_init_vht_hw_capab(struct iwl_trans *trans, else vht_cap->cap |= IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN; + /* + * With fips_enabled crypto is done by software, so the HW cannot + * split up A-MSDUs and the real limit that was set applies. + * Note that EHT doesn't honour this (HE copies the VHT value), + * but EHT is also entirely disabled for fips_enabled. + */ switch (iwlwifi_mod_params.amsdu_size) { case IWL_AMSDU_DEF: - if (trans->mac_cfg->mq_rx_supported) + if (trans->mac_cfg->mq_rx_supported && !fips_enabled) vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; else vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895; break; case IWL_AMSDU_2K: - if (trans->mac_cfg->mq_rx_supported) + if (trans->mac_cfg->mq_rx_supported && !fips_enabled) vht_cap->cap |= IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454; else @@ -660,6 +670,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB | IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB | + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU | (IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED << IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS), .phy_cap_info[10] = @@ -688,44 +700,26 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { .has_eht = true, .eht_cap_elem = { .mac_cap_info[0] = - IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | - IEEE80211_EHT_MAC_CAP0_OM_CONTROL | - IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | - IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 | - IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC, - .mac_cap_info[1] = - IEEE80211_EHT_MAC_CAP1_UNSOL_EPCS_PRIO_ACCESS, + IEEE80211_EHT_MAC_CAP0_OM_CONTROL, .phy_cap_info[0] = IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | - IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE | IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK, .phy_cap_info[1] = IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK | IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK, .phy_cap_info[3] = - IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | - IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | - IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | - IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK, + IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK, .phy_cap_info[4] = - IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | - IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI, .phy_cap_info[5] = FIELD_PREP_CONST(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK, IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US) | - IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | - IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP, - .phy_cap_info[6] = - IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | - IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, + IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF, .phy_cap_info[8] = IEEE80211_EHT_PHY_CAP8_RX_1024QAM_WIDER_BW_DL_OFDMA | IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA, @@ -793,6 +787,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242, .phy_cap_info[9] = + IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_RESERVED << IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_POS, }, @@ -819,9 +814,7 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { .has_eht = true, .eht_cap_elem = { .mac_cap_info[0] = - IEEE80211_EHT_MAC_CAP0_OM_CONTROL | - IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | - IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2, + IEEE80211_EHT_MAC_CAP0_OM_CONTROL, .phy_cap_info[0] = IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI, @@ -923,7 +916,9 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, bool slow_pcie = (!trans->mac_cfg->integrated && trans->info.pcie_link_speed < PCI_EXP_LNKSTA_CLS_8_0GB); - if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be) + /* EHT needs WPA3/MFP so cannot do it for fips_enabled */ + if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be || + fips_enabled) iftype_data->eht_cap.has_eht = false; /* Advertise an A-MPDU exponent extension based on @@ -1036,47 +1031,17 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); } + /* prior RFs don't have HE, HR RF doesn't have this, later have it */ + if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_HR1 || + CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_HR2) + iftype_data->he_cap.he_cap_elem.phy_cap_info[9] &= + ~(IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | + IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU); + if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210 && !is_ap) iftype_data->he_cap.he_cap_elem.phy_cap_info[2] |= IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO; - switch (CSR_HW_RFID_TYPE(trans->info.hw_rf_id)) { - case IWL_CFG_RF_TYPE_GF: - case IWL_CFG_RF_TYPE_FM: - case IWL_CFG_RF_TYPE_WH: - iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= - IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; - if (!is_ap) - iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= - IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU; - break; - } - - if (CSR_HW_REV_TYPE(trans->info.hw_rev) == IWL_CFG_MAC_TYPE_GL && - iftype_data->eht_cap.has_eht) { - iftype_data->eht_cap.eht_cap_elem.mac_cap_info[0] &= - ~(IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | - IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2); - iftype_data->eht_cap.eht_cap_elem.phy_cap_info[3] &= - ~(IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | - IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK | - IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | - IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | - IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK); - iftype_data->eht_cap.eht_cap_elem.phy_cap_info[4] &= - ~(IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | - IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP); - iftype_data->eht_cap.eht_cap_elem.phy_cap_info[5] &= - ~IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK; - iftype_data->eht_cap.eht_cap_elem.phy_cap_info[6] &= - ~(IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | - IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP); - iftype_data->eht_cap.eht_cap_elem.phy_cap_info[5] |= - IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF; - } - if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_BROADCAST_TWT)) iftype_data->he_cap.he_cap_elem.mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BCAST_TWT; @@ -1241,11 +1206,19 @@ static void iwl_init_sbands(struct iwl_trans *trans, n_used += iwl_init_sband_channels(data, sband, n_channels, NL80211_BAND_6GHZ); - if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) + /* + * 6 GHz requires WPA3 which requires MFP, which FW cannot do + * when fips_enabled, so don't advertise any 6 GHz channels to + * avoid spending time on scanning those channels and perhaps + * even finding APs there that cannot be used. + */ + if (!fips_enabled && data->sku_cap_11ax_enable && + !iwlwifi_mod_params.disable_11ax) iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, fw); else sband->n_channels = 0; + if (n_channels != n_used) IWL_ERR_DEV(dev, "NVM: used only %d of %d channels\n", n_used, n_channels); @@ -1629,8 +1602,7 @@ IWL_EXPORT_SYMBOL(iwl_parse_nvm_data); static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, int ch_idx, u16 nvm_flags, - struct iwl_reg_capa reg_capa, - const struct iwl_rf_cfg *cfg) + struct iwl_reg_capa reg_capa) { u32 flags = NL80211_RRF_NO_HT40; @@ -1685,10 +1657,12 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, } /* Set the AP type for the UHB case. */ - if (nvm_flags & NVM_CHANNEL_VLP) - flags |= NL80211_RRF_ALLOW_6GHZ_VLP_AP; - else + if (nvm_flags & NVM_CHANNEL_VLP) { + if (!(nvm_flags & NVM_CHANNEL_VLP_AP_NOT_ALLOWED)) + flags |= NL80211_RRF_ALLOW_6GHZ_VLP_AP; + } else { flags |= NL80211_RRF_NO_6GHZ_VLP_CLIENT; + } if (!(nvm_flags & NVM_CHANNEL_AFC)) flags |= NL80211_RRF_NO_6GHZ_AFC_CLIENT; @@ -1815,8 +1789,8 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans, } reg_rule_flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx, - ch_flags, reg_capa, - cfg); + ch_flags, + reg_capa); /* we can't continue the same rule */ if (ch_idx == 0 || prev_reg_rule_flags != reg_rule_flags || diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h index 5dc299296d6d..a146d0e399f2 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-op-mode.h @@ -147,6 +147,8 @@ struct iwl_fw_error_dump_mode { * Op_mode needs to reset its internal state because the device did not * survive the system state transition. The firmware is no longer running, * etc... + * @dump: Op_mode needs to collect the firmware dump upon this handler + * being called. */ struct iwl_op_mode_ops { struct iwl_op_mode *(*start)(struct iwl_trans *trans, @@ -174,6 +176,7 @@ struct iwl_op_mode_ops { enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data); void (*device_powered_off)(struct iwl_op_mode *op_mode); + void (*dump)(struct iwl_op_mode *op_mode); }; int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops); @@ -286,4 +289,11 @@ static inline void iwl_op_mode_device_powered_off(struct iwl_op_mode *op_mode) op_mode->ops->device_powered_off(op_mode); } +static inline void iwl_op_mode_dump(struct iwl_op_mode *op_mode) +{ + if (!op_mode || !op_mode->ops || !op_mode->ops->dump) + return; + op_mode->ops->dump(op_mode); +} + #endif /* __iwl_op_mode_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h index 23b2009fbb28..a7214ddcfaf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2024 Intel Corporation + * Copyright (C) 2005-2014, 2018-2025 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -514,6 +514,14 @@ enum { #define WMAL_INDRCT_CMD(addr) \ ((WMAL_CMD_READ_BURST_ACCESS << WMAL_INDRCT_RD_CMD1_OPMOD_POS) | \ ((addr) & WMAL_INDRCT_RD_CMD1_BYTE_ADDRESS_MSK)) +#define WMAL_MRSPF_STTS 0xADFC24 +#define WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_POS 15 +#define WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_MSK 0x8000 +#define WMAL_TIMEOUT_VAL 0xA5A5A5A2 +#define WMAL_MRSPF_STTS_IS_FIFO1_NOT_EMPTY(val) \ + (((val) >> (WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_POS)) & \ + ((WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_MSK) >> \ + (WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_POS))) #define WFPM_LMAC1_PS_CTL_RW 0xA03380 #define WFPM_LMAC2_PS_CTL_RW 0xA033C0 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 8a40801cf0dd..3694b41d6621 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -14,8 +14,8 @@ #include "iwl-fh.h" #include <linux/dmapool.h> #include "fw/api/commands.h" -#include "pcie/internal.h" -#include "iwl-context-info-v2.h" +#include "pcie/gen1_2/internal.h" +#include "pcie/iwl-context-info-v2.h" struct iwl_trans_dev_restart_data { struct list_head list; @@ -268,7 +268,9 @@ static void iwl_trans_restart_wk(struct work_struct *wk) struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, - const struct iwl_mac_cfg *mac_cfg) + const struct iwl_mac_cfg *mac_cfg, + unsigned int txcmd_size, + unsigned int txcmd_align) { struct iwl_trans *trans; #ifdef CONFIG_LOCKDEP @@ -290,35 +292,6 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, INIT_DELAYED_WORK(&trans->restart.wk, iwl_trans_restart_wk); - return trans; -} - -int iwl_trans_init(struct iwl_trans *trans) -{ - int txcmd_size, txcmd_align; - - /* check if name/num_rx_queues were set as a proxy for info being set */ - if (WARN_ON(!trans->info.name || !trans->info.num_rxqs)) - return -EINVAL; - - if (!trans->mac_cfg->gen2) { - txcmd_size = sizeof(struct iwl_tx_cmd_v6); - txcmd_align = sizeof(void *); - } else if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { - txcmd_size = sizeof(struct iwl_tx_cmd_v9); - txcmd_align = 64; - } else { - txcmd_size = sizeof(struct iwl_tx_cmd); - txcmd_align = 128; - } - - txcmd_size += sizeof(struct iwl_cmd_header); - txcmd_size += 36; /* biggest possible 802.11 header */ - - /* Ensure device TX cmd cannot reach/cross a page boundary in gen2 */ - if (WARN_ON(trans->mac_cfg->gen2 && txcmd_size >= txcmd_align)) - return -EINVAL; - snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), "iwl_cmd_pool:%s", dev_name(trans->dev)); trans->dev_cmd_pool = @@ -326,9 +299,9 @@ int iwl_trans_init(struct iwl_trans *trans) txcmd_size, txcmd_align, SLAB_HWCACHE_ALIGN, NULL); if (!trans->dev_cmd_pool) - return -ENOMEM; + return NULL; - return 0; + return trans; } void iwl_trans_free(struct iwl_trans *trans) @@ -446,7 +419,10 @@ void iwl_trans_op_mode_leave(struct iwl_trans *trans) { might_sleep(); - iwl_trans_pcie_op_mode_leave(trans); + if (trans->mac_cfg->gen2) + iwl_trans_pcie_gen2_op_mode_leave(trans); + else + iwl_trans_pcie_op_mode_leave(trans); cancel_delayed_work_sync(&trans->restart.wk); @@ -461,31 +437,26 @@ void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) { iwl_trans_pcie_write8(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_trans_write8); void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val) { iwl_trans_pcie_write32(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_trans_write32); u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) { return iwl_trans_pcie_read32(trans, ofs); } -IWL_EXPORT_SYMBOL(iwl_trans_read32); u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs) { return iwl_trans_pcie_read_prph(trans, ofs); } -IWL_EXPORT_SYMBOL(iwl_trans_read_prph); void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) { return iwl_trans_pcie_write_prph(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_trans_write_prph); int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, void *buf, int dwords) @@ -497,7 +468,19 @@ IWL_EXPORT_SYMBOL(iwl_trans_read_mem); int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, const void *buf, int dwords) { - return iwl_trans_pcie_write_mem(trans, addr, buf, dwords); + int offs, ret = 0; + const u32 *vals = buf; + + if (iwl_trans_grab_nic_access(trans)) { + iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); + for (offs = 0; offs < dwords; offs++) + iwl_write32(trans, HBUS_TARG_MEM_WDAT, + vals ? vals[offs] : 0); + iwl_trans_release_nic_access(trans); + } else { + ret = -EBUSY; + } + return ret; } IWL_EXPORT_SYMBOL(iwl_trans_write_mem); @@ -510,11 +493,10 @@ void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) } IWL_EXPORT_SYMBOL(iwl_trans_set_pmi); -int iwl_trans_sw_reset(struct iwl_trans *trans, bool retake_ownership) +int iwl_trans_sw_reset(struct iwl_trans *trans) { - return iwl_trans_pcie_sw_reset(trans, retake_ownership); + return iwl_trans_pcie_sw_reset(trans, true); } -IWL_EXPORT_SYMBOL(iwl_trans_sw_reset); struct iwl_trans_dump_data * iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, @@ -524,7 +506,6 @@ iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, return iwl_trans_pcie_dump_data(trans, dump_mask, sanitize_ops, sanitize_ctx); } -IWL_EXPORT_SYMBOL(iwl_trans_dump_data); int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, bool reset) { @@ -560,20 +541,17 @@ void iwl_trans_interrupts(struct iwl_trans *trans, bool enable) { iwl_trans_pci_interrupts(trans, enable); } -IWL_EXPORT_SYMBOL(iwl_trans_interrupts); void iwl_trans_sync_nmi(struct iwl_trans *trans) { iwl_trans_pcie_sync_nmi(trans); } -IWL_EXPORT_SYMBOL(iwl_trans_sync_nmi); int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr, u64 src_addr, u32 byte_cnt) { return iwl_trans_pcie_copy_imr(trans, dst_addr, src_addr, byte_cnt); } -IWL_EXPORT_SYMBOL(iwl_trans_write_imr_mem); void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) @@ -587,7 +565,6 @@ int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs, { return iwl_trans_pcie_read_config32(trans, ofs, val); } -IWL_EXPORT_SYMBOL(iwl_trans_read_config32); bool _iwl_trans_grab_nic_access(struct iwl_trans *trans) { @@ -783,7 +760,6 @@ void iwl_trans_debugfs_cleanup(struct iwl_trans *trans) { iwl_trans_pcie_debugfs_cleanup(trans); } -IWL_EXPORT_SYMBOL(iwl_trans_debugfs_cleanup); #endif void iwl_trans_set_q_ptrs(struct iwl_trans *trans, int queue, int ptr) @@ -821,7 +797,6 @@ int iwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue, { return iwl_trans_pcie_rxq_dma_data(trans, queue, data); } -IWL_EXPORT_SYMBOL(iwl_trans_get_rxq_dma_data); int iwl_trans_load_pnvm(struct iwl_trans *trans, const struct iwl_pnvm_image *pnvm_data, @@ -836,7 +811,6 @@ void iwl_trans_set_pnvm(struct iwl_trans *trans, { iwl_trans_pcie_ctx_info_v2_set_pnvm(trans, capa); } -IWL_EXPORT_SYMBOL(iwl_trans_set_pnvm); int iwl_trans_load_reduce_power(struct iwl_trans *trans, const struct iwl_pnvm_image *payloads, @@ -845,11 +819,9 @@ int iwl_trans_load_reduce_power(struct iwl_trans *trans, return iwl_trans_pcie_ctx_info_v2_load_reduce_power(trans, payloads, capa); } -IWL_EXPORT_SYMBOL(iwl_trans_load_reduce_power); void iwl_trans_set_reduce_power(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa) { iwl_trans_pcie_ctx_info_v2_set_reduce_power(trans, capa); } -IWL_EXPORT_SYMBOL(iwl_trans_set_reduce_power); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 012b1e44bce3..d0e658801c2e 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1096,7 +1096,7 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr, void iwl_trans_set_pmi(struct iwl_trans *trans, bool state); -int iwl_trans_sw_reset(struct iwl_trans *trans, bool retake_ownership); +int iwl_trans_sw_reset(struct iwl_trans *trans); void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); @@ -1204,9 +1204,10 @@ static inline void iwl_trans_finish_sw_reset(struct iwl_trans *trans) * transport helper functions *****************************************************/ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, - struct device *dev, - const struct iwl_mac_cfg *cfg_trans); -int iwl_trans_init(struct iwl_trans *trans); + struct device *dev, + const struct iwl_mac_cfg *mac_cfg, + unsigned int txcmd_size, + unsigned int txcmd_align); void iwl_trans_free(struct iwl_trans *trans); static inline bool iwl_trans_is_hw_error_value(u32 val) @@ -1229,6 +1230,21 @@ static inline u16 iwl_trans_get_num_rbds(struct iwl_trans *trans) return result; } +static inline void iwl_trans_suppress_cmd_error_once(struct iwl_trans *trans) +{ + set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &trans->status); +} + +static inline bool iwl_trans_device_enabled(struct iwl_trans *trans) +{ + return test_bit(STATUS_DEVICE_ENABLED, &trans->status); +} + +static inline bool iwl_trans_is_dead(struct iwl_trans *trans) +{ + return test_bit(STATUS_TRANS_DEAD, &trans->status); +} + /***************************************************** * PCIe handling *****************************************************/ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-utils.c b/drivers/net/wireless/intel/iwlwifi/iwl-utils.c index c5b49851e4b9..d503544fda40 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-utils.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-utils.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation */ #include <net/gso.h> #include <linux/ieee80211.h> @@ -82,3 +82,114 @@ int iwl_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes, } IWL_EXPORT_SYMBOL(iwl_tx_tso_segment); #endif /* CONFIG_INET */ + +static u32 iwl_div_by_db(u32 value, u8 db) +{ + /* + * 2^32 * 10**(i / 10) for i = [1, 10], skipping 0 and simply stopping + * at 10 dB and looping instead of using a much larger table. + * + * Using 64 bit math is overkill, but means the helper does not require + * a limit on the input range. + */ + static const u32 db_to_val[] = { + 0xcb59185e, 0xa1866ba8, 0x804dce7a, 0x65ea59fe, 0x50f44d89, + 0x404de61f, 0x331426af, 0x2892c18b, 0x203a7e5b, 0x1999999a, + }; + + while (value && db > 0) { + u8 change = min_t(u8, db, ARRAY_SIZE(db_to_val)); + + value = (((u64)value) * db_to_val[change - 1]) >> 32; + + db -= change; + } + + return value; +} + +s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len) +{ + int average_magnitude; + u32 average_factor; + int sum_magnitude = -128; + u32 sum_factor = 0; + int i, count = 0; + + /* + * To properly average the decibel values (signal values given in dBm) + * we need to do the math in linear space. Doing a linear average of + * dB (dBm) values is a bit annoying though due to the large range of + * at least -10 to -110 dBm that will not fit into a 32 bit integer. + * + * A 64 bit integer should be sufficient, but then we still have the + * problem that there are no directly usable utility functions + * available. + * + * So, lets not deal with that and instead do much of the calculation + * with a 16.16 fixed point integer along with a base in dBm. 16.16 bit + * gives us plenty of head-room for adding up a few values and even + * doing some math on it. And the tail should be accurate enough too + * (1/2^16 is somewhere around -48 dB, so effectively zero). + * + * i.e. the real value of sum is: + * sum = sum_factor / 2^16 * 10^(sum_magnitude / 10) mW + * + * However, that does mean we need to be able to bring two values to + * a common base, so we need a helper for that. + * + * Note that this function takes an input with unsigned negative dBm + * values but returns a signed dBm (i.e. a negative value). + */ + + for (i = 0; i < len; i++) { + int val_magnitude; + u32 val_factor; + + /* Assume invalid */ + if (neg_dbm_values[i] == 0xff) + continue; + + val_factor = 0x10000; + val_magnitude = -neg_dbm_values[i]; + + if (val_magnitude <= sum_magnitude) { + u8 div_db = sum_magnitude - val_magnitude; + + val_factor = iwl_div_by_db(val_factor, div_db); + val_magnitude = sum_magnitude; + } else { + u8 div_db = val_magnitude - sum_magnitude; + + sum_factor = iwl_div_by_db(sum_factor, div_db); + sum_magnitude = val_magnitude; + } + + sum_factor += val_factor; + count++; + } + + /* No valid noise measurement, return a very high noise level */ + if (count == 0) + return 0; + + average_magnitude = sum_magnitude; + average_factor = sum_factor / count; + + /* + * average_factor will be a number smaller than 1.0 (0x10000) at this + * point. What we need to do now is to adjust average_magnitude so that + * average_factor is between -0.5 dB and 0.5 dB. + * + * Just do -1 dB steps and find the point where + * -0.5 dB * -i dB = 0x10000 * 10^(-0.5/10) / i dB + * = div_by_db(0xe429, i) + * is smaller than average_factor. + */ + for (i = 0; average_factor < iwl_div_by_db(0xe429, i); i++) { + /* nothing */ + } + + return clamp(average_magnitude - i, -128, 0); +} +IWL_EXPORT_SYMBOL(iwl_average_neg_dbm); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-utils.h b/drivers/net/wireless/intel/iwlwifi/iwl-utils.h index 8f1f11d06fbe..5172035e4d26 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-utils.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-utils.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation */ #ifndef __iwl_utils_h__ #define __iwl_utils_h__ @@ -53,4 +53,6 @@ u32 iwl_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size) return ie - beacon; } +s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len); + #endif /* __iwl_utils_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mei/sap.h b/drivers/net/wireless/intel/iwlwifi/mei/sap.h index 3b56637b9697..ba1f75f739c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mei/sap.h +++ b/drivers/net/wireless/intel/iwlwifi/mei/sap.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (C) 2021 - 2022 Intel Corporation + * Copyright (C) 2021 - 2022, 2025 Intel Corporation */ #ifndef __sap_h__ @@ -340,12 +340,12 @@ enum iwl_sap_wifi_auth_type { }; /** - * enum iwl_sap_wifi_cipher_alg - * @SAP_WIFI_CIPHER_ALG_NONE: TBD - * @SAP_WIFI_CIPHER_ALG_TKIP: TBD - * @SAP_WIFI_CIPHER_ALG_CCMP: TBD - * @SAP_WIFI_CIPHER_ALG_GCMP: TBD - * @SAP_WIFI_CIPHER_ALG_GCMP_256: TBD + * enum iwl_sap_wifi_cipher_alg - MEI WiFi cipher algorithm IDs + * @SAP_WIFI_CIPHER_ALG_NONE: No encryption + * @SAP_WIFI_CIPHER_ALG_TKIP: TKIPO + * @SAP_WIFI_CIPHER_ALG_CCMP: CCMP + * @SAP_WIFI_CIPHER_ALG_GCMP: GCMP-128 + * @SAP_WIFI_CIPHER_ALG_GCMP_256: GCMP-256 */ enum iwl_sap_wifi_cipher_alg { SAP_WIFI_CIPHER_ALG_NONE = IWL_MEI_CIPHER_NONE, @@ -601,7 +601,7 @@ enum iwl_sap_flex_filter_flags { }; /** - * struct iwl_sap_flex_filter - + * struct iwl_sap_flex_filter - filter configuration * @src_port: Source port in network format. * @dst_port: Destination port in network format. * @flags: Flags and protocol, see &enum iwl_sap_flex_filter_flags. @@ -633,7 +633,7 @@ enum iwl_sap_ipv4_filter_flags { }; /** - * struct iwl_sap_ipv4_filter- + * struct iwl_sap_ipv4_filter - IPv4 filter configuration * @ipv4_addr: The IP address to filer. * @flags: See &enum iwl_sap_ipv4_filter_flags. */ @@ -643,7 +643,7 @@ struct iwl_sap_ipv4_filter { } __packed; /** - * enum iwl_sap_ipv6_filter_flags - + * enum iwl_sap_ipv6_filter_flags - IPv6 filter flags * @SAP_IPV6_ADDR_FILTER_COPY: Pass packets to the host. * @SAP_IPV6_ADDR_FILTER_ENABLED: If false, the filter should be ignored. */ @@ -653,7 +653,7 @@ enum iwl_sap_ipv6_filter_flags { }; /** - * struct iwl_sap_ipv6_filter - + * struct iwl_sap_ipv6_filter - IPv6 filter configuration * @addr_lo24: Lowest 24 bits of the IPv6 address. * @flags: See &enum iwl_sap_ipv6_filter_flags. */ @@ -663,7 +663,7 @@ struct iwl_sap_ipv6_filter { } __packed; /** - * enum iwl_sap_icmpv6_filter_flags - + * enum iwl_sap_icmpv6_filter_flags - ICMPv6 filter flags * @SAP_ICMPV6_FILTER_ENABLED: If false, the filter should be ignored. * @SAP_ICMPV6_FILTER_COPY: Pass packets to the host. */ @@ -673,8 +673,8 @@ enum iwl_sap_icmpv6_filter_flags { }; /** - * enum iwl_sap_vlan_filter_flags - - * @SAP_VLAN_FILTER_VLAN_ID_MSK: TBD + * enum iwl_sap_vlan_filter_flags - VLAN filter flags + * @SAP_VLAN_FILTER_VLAN_ID_MSK: VLAN ID * @SAP_VLAN_FILTER_ENABLED: If false, the filter should be ignored. */ enum iwl_sap_vlan_filter_flags { @@ -751,7 +751,7 @@ struct iwl_sap_pldr_data { } __packed; /** - * enum iwl_sap_pldr_status - + * enum iwl_sap_pldr_status - product reset status * @SAP_PLDR_STATUS_SUCCESS: PLDR started/ended successfully * @SAP_PLDR_STATUS_FAILURE: PLDR failed to start/end */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/Makefile b/drivers/net/wireless/intel/iwlwifi/mld/Makefile index ece66e7a9be4..c966e573f430 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mld/Makefile @@ -9,8 +9,4 @@ iwlmld-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o iwlmld-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmld-$(CONFIG_PM_SLEEP) += d3.o -# non-upstream things -iwlmld-$(CONFIG_IWL_VENDOR_CMDS) += vendor-cmd.o -iwlmld-$(CONFIG_IWLMVM_AX_SOFTAP_TESTMODE) += ax-softap-testmode.o - subdir-ccflags-y += -I$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/agg.c b/drivers/net/wireless/intel/iwlwifi/mld/agg.c index 6b349270481d..3bf36f8f6874 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/agg.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/agg.c @@ -305,10 +305,15 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi, * already ahead and it will be dropped. * If the last sub-frame is not on this queue - we will get frame * release notification with up to date NSSN. + * If this is the first frame that is stored in the buffer, the head_sn + * may be outdated. Update it based on the last NSSN to make sure it + * will be released when the frame release notification arrives. */ if (!amsdu || last_subframe) iwl_mld_reorder_release_frames(mld, sta, napi, baid_data, buffer, nssn); + else if (buffer->num_stored == 1) + buffer->head_sn = nssn; return IWL_MLD_BUFFERED_SKB; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ap.c b/drivers/net/wireless/intel/iwlwifi/mld/ap.c index 26511b49d89a..5c59acc8c4c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ap.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ap.c @@ -294,9 +294,20 @@ int iwl_mld_start_ap_ibss(struct ieee80211_hw *hw, if (ret) return ret; + mld_vif->ap_ibss_active = true; + + if (vif->p2p && mld->p2p_device_vif) { + ret = iwl_mld_mac_fw_action(mld, mld->p2p_device_vif, + FW_CTXT_ACTION_MODIFY); + if (ret) { + mld_vif->ap_ibss_active = false; + goto rm_mcast; + } + } + ret = iwl_mld_add_bcast_sta(mld, vif, link); if (ret) - goto rm_mcast; + goto update_p2p_dev; /* Those keys were configured by the upper layers before starting the * AP. Now that it is started and the bcast and mcast sta were added to @@ -310,12 +321,6 @@ int iwl_mld_start_ap_ibss(struct ieee80211_hw *hw, iwl_mld_vif_update_low_latency(mld, vif, true, LOW_LATENCY_VIF_TYPE); - mld_vif->ap_ibss_active = true; - - if (vif->p2p && mld->p2p_device_vif) - return iwl_mld_mac_fw_action(mld, mld->p2p_device_vif, - FW_CTXT_ACTION_MODIFY); - /* When the channel context was added, the link is not yet active, so * min_def is always used. Update the PHY again here in case def should * actually be used. @@ -326,6 +331,11 @@ int iwl_mld_start_ap_ibss(struct ieee80211_hw *hw, return 0; rm_bcast: iwl_mld_remove_bcast_sta(mld, vif, link); +update_p2p_dev: + mld_vif->ap_ibss_active = false; + if (vif->p2p && mld->p2p_device_vif) + iwl_mld_mac_fw_action(mld, mld->p2p_device_vif, + FW_CTXT_ACTION_MODIFY); rm_mcast: iwl_mld_remove_mcast_sta(mld, vif, link); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/coex.c b/drivers/net/wireless/intel/iwlwifi/mld/coex.c index 32c727b3b391..5f262bd43f21 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/coex.c @@ -24,13 +24,17 @@ int iwl_mld_send_bt_init_conf(struct iwl_mld *mld) void iwl_mld_handle_bt_coex_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt) { - const struct iwl_bt_coex_profile_notif *notif = (const void *)pkt->data; + const struct iwl_bt_coex_profile_notif *notif = (void *)pkt->data; const struct iwl_bt_coex_profile_notif zero_notif = {}; /* zeroed structure means that BT is OFF */ bool bt_is_active = memcmp(notif, &zero_notif, sizeof(*notif)); - mld->last_bt_notif = *notif; + if (bt_is_active == mld->bt_is_active) + return; + IWL_DEBUG_INFO(mld, "BT was turned %s\n", bt_is_active ? "ON" : "OFF"); + mld->bt_is_active = bt_is_active; + iwl_mld_emlsr_check_bt(mld); } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/constants.h b/drivers/net/wireless/intel/iwlwifi/mld/constants.h index 2a59b29b75cb..49accf96f44b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/constants.h @@ -40,15 +40,6 @@ #define IWL_MLD_TPT_COUNT_WINDOW (5 * HZ) -/* OMI reduced BW thresholds (channel load percentage) */ -#define IWL_MLD_OMI_ENTER_CHAN_LOAD 10 -#define IWL_MLD_OMI_EXIT_CHAN_LOAD_160 20 -#define IWL_MLD_OMI_EXIT_CHAN_LOAD_320 30 -/* time (in milliseconds) to let AP "settle" the OMI */ -#define IWL_MLD_OMI_AP_SETTLE_DELAY 27 -/* time (in milliseconds) to not enter OMI reduced BW after leaving */ -#define IWL_MLD_OMI_EXIT_PROTECTION 5000 - #define IWL_MLD_DIS_RANDOM_FW_ID false #define IWL_MLD_D3_DEBUG false #define IWL_MLD_NON_TRANSMITTING_AP false diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index c776543cbba5..ed0a0f76f1c5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -204,66 +204,6 @@ void iwl_mld_ipv6_addr_change(struct ieee80211_hw *hw, } #endif -enum rt_status { - FW_ALIVE, - FW_NEEDS_RESET, - FW_ERROR, -}; - -static enum rt_status iwl_mld_check_err_tables(struct iwl_mld *mld, - struct ieee80211_vif *vif) -{ - u32 err_id; - - /* check for lmac1 error */ - if (iwl_fwrt_read_err_table(mld->trans, - mld->trans->dbg.lmac_error_event_table[0], - &err_id)) { - if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) { - struct cfg80211_wowlan_wakeup wakeup = { - .rfkill_release = true, - }; - ieee80211_report_wowlan_wakeup(vif, &wakeup, - GFP_KERNEL); - - return FW_NEEDS_RESET; - } - return FW_ERROR; - } - - /* check if we have lmac2 set and check for error */ - if (iwl_fwrt_read_err_table(mld->trans, - mld->trans->dbg.lmac_error_event_table[1], - NULL)) - return FW_ERROR; - - /* check for umac error */ - if (iwl_fwrt_read_err_table(mld->trans, - mld->trans->dbg.umac_error_event_table, - NULL)) - return FW_ERROR; - - return FW_ALIVE; -} - -static bool iwl_mld_fw_needs_restart(struct iwl_mld *mld, - struct ieee80211_vif *vif) -{ - enum rt_status rt_status = iwl_mld_check_err_tables(mld, vif); - - if (rt_status == FW_ALIVE) - return false; - - if (rt_status == FW_ERROR) { - IWL_ERR(mld, "FW Error occurred during suspend\n"); - iwl_fwrt_dump_error_logs(&mld->fwrt); - iwl_dbg_tlv_time_point(&mld->fwrt, - IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL); - } - - return true; -} - static int iwl_mld_netdetect_config(struct iwl_mld *mld, struct ieee80211_vif *vif, @@ -707,51 +647,6 @@ iwl_mld_set_key_rx_seq(struct ieee80211_key_conf *key, } static void -iwl_mld_d3_update_mcast_key(struct iwl_mld *mld, - struct ieee80211_vif *vif, - struct iwl_mld_wowlan_status *wowlan_status, - struct ieee80211_key_conf *key, - struct iwl_mld_mcast_key_data *key_data) -{ - if (key->keyidx != key_data->id && - (key->keyidx < 4 || key->keyidx > 5)) { - IWL_ERR(mld, - "Unexpected keyId mismatch. Old keyId:%d, New keyId:%d\n", - key->keyidx, key_data->id); - return; - } - - /* All installed keys are sent by the FW, even weren't - * rekeyed during D3. - * We remove an existing key if it has the same index as - * a new key and a rekey has occurred during d3 - */ - if (wowlan_status->num_of_gtk_rekeys && key_data->len) { - if (key->keyidx == 4 || key->keyidx == 5) { - struct iwl_mld_vif *mld_vif = - iwl_mld_vif_from_mac80211(vif); - struct iwl_mld_link *mld_link; - int link_id = vif->active_links ? - __ffs(vif->active_links) : 0; - - mld_link = iwl_mld_link_dereference_check(mld_vif, - link_id); - if (WARN_ON(!mld_link)) - return; - - if (mld_link->igtk == key) - mld_link->igtk = NULL; - mld->num_igtks--; - } - - ieee80211_remove_key(key); - return; - } - - iwl_mld_set_key_rx_seq(key, key_data); -} - -static void iwl_mld_update_ptk_rx_seq(struct iwl_mld *mld, struct iwl_mld_wowlan_status *wowlan_status, struct ieee80211_sta *sta, @@ -819,8 +714,7 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw, data->gtk_cipher = key->cipher; status_idx = key->keyidx == wowlan_status->gtk[1].id; - iwl_mld_d3_update_mcast_key(data->mld, vif, wowlan_status, key, - &wowlan_status->gtk[status_idx]); + iwl_mld_set_key_rx_seq(key, &wowlan_status->gtk[status_idx]); break; case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256: @@ -832,9 +726,8 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw, return; data->igtk_cipher = key->cipher; - iwl_mld_d3_update_mcast_key(data->mld, vif, - wowlan_status, - key, &wowlan_status->igtk); + if (key->keyidx == wowlan_status->igtk.id) + iwl_mld_set_key_rx_seq(key, &wowlan_status->igtk); } if (key->keyidx == 6 || key->keyidx == 7) { if (WARN_ON(data->bigtk_cipher && @@ -843,9 +736,7 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw, data->bigtk_cipher = key->cipher; status_idx = key->keyidx == wowlan_status->bigtk[1].id; - iwl_mld_d3_update_mcast_key(data->mld, vif, - wowlan_status, key, - &wowlan_status->bigtk[status_idx]); + iwl_mld_set_key_rx_seq(key, &wowlan_status->bigtk[status_idx]); } break; default: @@ -855,7 +746,7 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw, data->num_keys++; } -static bool +static void iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, struct iwl_mld *mld, struct iwl_mld_mcast_key_data *key_data, @@ -871,6 +762,7 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, .conf.keyidx = key_data->id, }; int link_id = vif->active_links ? __ffs(vif->active_links) : -1; + u8 key[WOWLAN_KEY_MAX_SIZE]; BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); @@ -882,7 +774,7 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); if (!key_data->len) - return true; + return; switch (cipher) { case WLAN_CIPHER_SUITE_CCMP: @@ -912,9 +804,13 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, } memcpy(conf.conf.key, key_data->key, conf.conf.keylen); - key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); + + memcpy(key, key_data->key, sizeof(key_data->key)); + + key_config = ieee80211_gtk_rekey_add(vif, key_data->id, key, + sizeof(key), link_id); if (IS_ERR(key_config)) - return false; + return; iwl_mld_set_key_rx_seq(key_config, key_data); @@ -922,13 +818,28 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif, if (key_config->keyidx == 4 || key_config->keyidx == 5) { struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf); - mld_link->igtk = key_config; - mld->num_igtks++; + + /* If we had more than one rekey, mac80211 will tell us to + * remove the old and add the new so we will update the IGTK in + * drv_set_key + */ + if (mld_link->igtk && mld_link->igtk != key_config) { + /* mark the old IGTK as not in FW */ + mld_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID; + mld_link->igtk = key_config; + } + } + + /* Also keep track of the new BIGTK */ + if ((key_config->keyidx == 6 || key_config->keyidx == 7) && + vif->type == NL80211_IFTYPE_STATION) { + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + + rcu_assign_pointer(mld_vif->bigtks[key_config->keyidx - 6], key_config); } - return true; } -static bool +static void iwl_mld_add_all_rekeys(struct ieee80211_vif *vif, struct iwl_mld_wowlan_status *wowlan_status, struct iwl_mld_resume_key_iter_data *key_iter_data, @@ -937,25 +848,20 @@ iwl_mld_add_all_rekeys(struct ieee80211_vif *vif, int i; for (i = 0; i < ARRAY_SIZE(wowlan_status->gtk); i++) - if (!iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, - &wowlan_status->gtk[i], - link_conf, - key_iter_data->gtk_cipher)) - return false; - - if (!iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, - &wowlan_status->igtk, - link_conf, key_iter_data->igtk_cipher)) - return false; + iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, + &wowlan_status->gtk[i], + link_conf, + key_iter_data->gtk_cipher); - for (i = 0; i < ARRAY_SIZE(wowlan_status->bigtk); i++) - if (!iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, - &wowlan_status->bigtk[i], - link_conf, - key_iter_data->bigtk_cipher)) - return false; + iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, + &wowlan_status->igtk, + link_conf, key_iter_data->igtk_cipher); - return true; + for (i = 0; i < ARRAY_SIZE(wowlan_status->bigtk); i++) + iwl_mld_add_mcast_rekey(vif, key_iter_data->mld, + &wowlan_status->bigtk[i], + link_conf, + key_iter_data->bigtk_cipher); } static bool @@ -1317,6 +1223,13 @@ int iwl_mld_no_wowlan_suspend(struct iwl_mld *mld) struct iwl_d3_manager_config d3_cfg_cmd_data = {}; int ret; + if (mld->debug_max_sleep) { + d3_cfg_cmd_data.wakeup_host_timer = + cpu_to_le32(mld->debug_max_sleep); + d3_cfg_cmd_data.wakeup_flags = + cpu_to_le32(IWL_WAKEUP_D3_HOST_TIMER); + } + lockdep_assert_wiphy(mld->wiphy); IWL_DEBUG_WOWLAN(mld, "Starting the no wowlan suspend flow\n"); @@ -1376,10 +1289,7 @@ int iwl_mld_no_wowlan_resume(struct iwl_mld *mld) mld->fw_status.in_d3 = false; iwl_fw_dbg_read_d3_debug_data(&mld->fwrt); - if (iwl_mld_fw_needs_restart(mld, NULL)) - ret = -ENODEV; - else - ret = iwl_mld_wait_d3_notif(mld, &resume_data, false); + ret = iwl_mld_wait_d3_notif(mld, &resume_data, false); if (!ret && (resume_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)) return -ENODEV; @@ -1909,6 +1819,7 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) goto err; } + mld->fw_status.resuming = true; mld->fw_status.in_d3 = false; mld->scan.last_start_time_jiffies = jiffies; @@ -1928,15 +1839,10 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) iwl_fw_dbg_read_d3_debug_data(&mld->fwrt); - if (iwl_mld_fw_needs_restart(mld, bss_vif)) { - fw_err = true; - goto err; - } - resume_data.wowlan_status = kzalloc(sizeof(*resume_data.wowlan_status), GFP_KERNEL); if (!resume_data.wowlan_status) - return -1; + return -ENOMEM; if (mld->netdetect) resume_data.notifs_expected |= IWL_D3_ND_MATCH_INFO; @@ -1989,6 +1895,8 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) mld->fw_status.in_hw_restart = true; ret = 1; out: + mld->fw_status.resuming = false; + if (resume_data.wowlan_status) { kfree(resume_data.wowlan_status->wake_packet); kfree(resume_data.wowlan_status); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c index 352da8aa7898..cc052b0aa53f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c @@ -86,7 +86,7 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mld *mld, char *buf, if (count == 6 && !strcmp(buf, "nolog\n")) { mld->fw_status.do_not_dump_once = true; - set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &mld->trans->status); + iwl_trans_suppress_cmd_error_once(mld->trans); } /* take the return value to make compiler happy - it will @@ -546,6 +546,11 @@ iwl_mld_add_debugfs_files(struct iwl_mld *mld, struct dentry *debugfs_dir) #endif MLD_DEBUGFS_ADD_FILE(inject_packet, debugfs_dir, 0200); +#ifdef CONFIG_PM_SLEEP + debugfs_create_u32("max_sleep", 0600, debugfs_dir, + &mld->debug_max_sleep); +#endif + debugfs_create_bool("rx_ts_ptp", 0600, debugfs_dir, &mld->monitor.ptp_time); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c index f77ba21a174d..3464b3268712 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c @@ -94,7 +94,7 @@ iwl_mld_ftm_set_target_chandef(struct iwl_mld *mld, IWL_ERR(mld, "Unsupported BW in FTM request (%d)\n", peer->chandef.width); return -EINVAL; -} + } /* non EDCA based measurement must use HE preamble */ if (peer->ftm.trigger_based || peer->ftm.non_trigger_based) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c index 9d2c087360e7..b372173c4a79 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c @@ -294,7 +294,7 @@ static int iwl_mld_run_fw_init_sequence(struct iwl_mld *mld) return ret; ret = iwl_pnvm_load(mld->trans, &mld->notif_wait, - &mld->fw->ucode_capa, alive_data.sku_id); + mld->fw, alive_data.sku_id); if (ret) { IWL_ERR(mld, "Timeout waiting for PNVM load %d\n", ret); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index 235b55e0fe59..38993d65c052 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -55,6 +55,8 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif) ieee80211_iter_keys(mld->hw, vif, iwl_mld_cleanup_keys_iter, NULL); + wiphy_delayed_work_cancel(mld->wiphy, &mld_vif->mlo_scan_start_wk); + CLEANUP_STRUCT(mld_vif); } @@ -385,6 +387,17 @@ int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif, return iwl_mld_send_mac_cmd(mld, &cmd); } +static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy, + struct wiphy_work *wk) +{ + struct iwl_mld_vif *mld_vif = container_of(wk, struct iwl_mld_vif, + mlo_scan_start_wk.work); + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + + iwl_mld_int_mlo_scan(mld, iwl_mld_vif_to_mac80211(mld_vif)); +} + IWL_MLD_ALLOC_FN(vif, vif) /* Constructor function for struct iwl_mld_vif */ @@ -412,6 +425,8 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) iwl_mld_emlsr_prevent_done_wk); wiphy_delayed_work_init(&mld_vif->emlsr.tmp_non_bss_done_wk, iwl_mld_emlsr_tmp_non_bss_done_wk); + wiphy_delayed_work_init(&mld_vif->mlo_scan_start_wk, + iwl_mld_mlo_scan_start_wk); } iwl_mld_init_internal_sta(&mld_vif->aux_sta); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h index 49e2ce65557d..05dcb63701b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h @@ -87,6 +87,8 @@ enum iwl_mld_emlsr_exit { * @last_exit_reason: Reason for the last EMLSR exit * @last_exit_ts: Time of the last EMLSR exit (if @last_exit_reason is non-zero) * @exit_repeat_count: Number of times EMLSR was exited for the same reason + * @last_entry_ts: the time of the last EMLSR entry (if iwl_mld_emlsr_active() + * is true) * @unblock_tpt_wk: Unblock EMLSR because the throughput limit was reached * @check_tpt_wk: a worker to check if IWL_MLD_EMLSR_BLOCKED_TPT should be * added, for example if there is no longer enough traffic. @@ -105,6 +107,7 @@ struct iwl_mld_emlsr { enum iwl_mld_emlsr_exit last_exit_reason; unsigned long last_exit_ts; u8 exit_repeat_count; + unsigned long last_entry_ts; ); struct wiphy_work unblock_tpt_wk; @@ -133,6 +136,8 @@ struct iwl_mld_emlsr { * @low_latency_causes: bit flags, indicating the causes for low-latency, * see @iwl_mld_low_latency_cause. * @ps_disabled: indicates that PS is disabled for this interface + * @last_link_activation_time: last time a link was activated, for + * deferring MLO scans (to make them more reliable) * @mld: pointer to the mld structure. * @deflink: default link data, for use in non-MLO, * @link: reference to link data for each valid link, for use in MLO. @@ -144,6 +149,7 @@ struct iwl_mld_emlsr { * @roc_activity: the id of the roc_activity running. Relevant for STA and * p2p device only. Set to %ROC_NUM_ACTIVITIES when not in use. * @aux_sta: station used for remain on channel. Used in P2P device. + * @mlo_scan_start_wk: worker to start a deferred MLO scan */ struct iwl_mld_vif { /* Add here fields that need clean up on restart */ @@ -161,6 +167,7 @@ struct iwl_mld_vif { #endif u8 low_latency_causes; bool ps_disabled; + time64_t last_link_activation_time; ); /* And here fields that survive a fw restart */ struct iwl_mld *mld; @@ -179,6 +186,8 @@ struct iwl_mld_vif { #endif enum iwl_roc_activity roc_activity; struct iwl_mld_int_sta aux_sta; + + struct wiphy_delayed_work mlo_scan_start_wk; }; static inline struct iwl_mld_vif * @@ -187,6 +196,12 @@ iwl_mld_vif_from_mac80211(struct ieee80211_vif *vif) return (void *)vif->drv_priv; } +static inline struct ieee80211_vif * +iwl_mld_vif_to_mac80211(struct iwl_mld_vif *mld_vif) +{ + return container_of((void *)mld_vif, struct ieee80211_vif, drv_priv); +} + #define iwl_mld_link_dereference_check(mld_vif, link_id) \ rcu_dereference_check((mld_vif)->link[link_id], \ lockdep_is_held(&mld_vif->mld->wiphy->mtx)) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.c b/drivers/net/wireless/intel/iwlwifi/mld/key.c index 0eff13e5ffd5..13462a5ad79a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/key.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/key.c @@ -129,6 +129,12 @@ static int iwl_mld_add_key_to_fw(struct iwl_mld *mld, u32 sta_mask, bool tkip = key->cipher == WLAN_CIPHER_SUITE_TKIP; int max_key_len = sizeof(cmd.u.add.key); +#ifdef CONFIG_PM_SLEEP + /* If there was a rekey in wowlan, FW already has the key */ + if (mld->fw_status.resuming) + return 0; +#endif + if (WARN_ON(!sta_mask)) return -EINVAL; @@ -160,6 +166,12 @@ static void iwl_mld_remove_key_from_fw(struct iwl_mld *mld, u32 sta_mask, .u.remove.key_flags = cpu_to_le32(key_flags), }; +#ifdef CONFIG_PM_SLEEP + /* If there was a rekey in wowlan, FW already removed the key */ + if (mld->fw_status.resuming) + return; +#endif + if (WARN_ON(!sta_mask)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index d0f56189ad3f..782fc41aa1c3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -242,27 +242,9 @@ static bool iwl_mld_fill_mu_edca(struct iwl_mld *mld, return true; } -static u8 iwl_mld_sta_rx_bw_to_fw(enum ieee80211_sta_rx_bandwidth bw) -{ - switch (bw) { - default: /* potential future values not supported by this hw/driver */ - case IEEE80211_STA_RX_BW_20: - return IWL_LINK_MODIFY_BW_20; - case IEEE80211_STA_RX_BW_40: - return IWL_LINK_MODIFY_BW_40; - case IEEE80211_STA_RX_BW_80: - return IWL_LINK_MODIFY_BW_80; - case IEEE80211_STA_RX_BW_160: - return IWL_LINK_MODIFY_BW_160; - case IEEE80211_STA_RX_BW_320: - return IWL_LINK_MODIFY_BW_320; - } -} - -static int _iwl_mld_change_link_in_fw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - enum ieee80211_sta_rx_bandwidth bw, - u32 changes) +int +iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link, + u32 changes) { struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); struct ieee80211_vif *vif = link->vif; @@ -318,9 +300,6 @@ static int _iwl_mld_change_link_in_fw(struct iwl_mld *mld, cmd.bi = cpu_to_le32(link->beacon_int); cmd.dtim_interval = cpu_to_le32(link->beacon_int * link->dtim_period); - if (changes & LINK_CONTEXT_MODIFY_BANDWIDTH) - cmd.modify_bandwidth = iwl_mld_sta_rx_bw_to_fw(bw); - /* Configure HE parameters only if HE is supported, and only after * the parameters are set in mac80211 (meaning after assoc) */ @@ -382,28 +361,11 @@ send_cmd: return iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_MODIFY); } -int iwl_mld_change_link_in_fw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - u32 changes) -{ - if (WARN_ON(changes & LINK_CONTEXT_MODIFY_BANDWIDTH)) - changes &= ~LINK_CONTEXT_MODIFY_BANDWIDTH; - - return _iwl_mld_change_link_in_fw(mld, link, 0, changes); -} - -int iwl_mld_change_link_omi_bw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - enum ieee80211_sta_rx_bandwidth bw) -{ - return _iwl_mld_change_link_in_fw(mld, link, bw, - LINK_CONTEXT_MODIFY_BANDWIDTH); -} - int iwl_mld_activate_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link) { struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(link->vif); int ret; lockdep_assert_wiphy(mld->wiphy); @@ -411,13 +373,15 @@ int iwl_mld_activate_link(struct iwl_mld *mld, if (WARN_ON(!mld_link || mld_link->active)) return -EINVAL; - mld_link->rx_omi.exit_ts = jiffies; mld_link->active = true; ret = iwl_mld_change_link_in_fw(mld, link, LINK_CONTEXT_MODIFY_ACTIVE); if (ret) mld_link->active = false; + else + mld_vif->last_link_activation_time = + ktime_get_boottime_seconds(); return ret; } @@ -473,303 +437,6 @@ iwl_mld_rm_link_from_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link) iwl_mld_send_link_cmd(mld, &cmd, FW_CTXT_ACTION_REMOVE); } -static void iwl_mld_omi_bw_update(struct iwl_mld *mld, - struct ieee80211_bss_conf *link_conf, - struct iwl_mld_link *mld_link, - struct ieee80211_link_sta *link_sta, - enum ieee80211_sta_rx_bandwidth bw, - bool ap_update) -{ - enum ieee80211_sta_rx_bandwidth apply_bw; - - mld_link->rx_omi.desired_bw = bw; - - /* Can't update OMI while already in progress, desired_bw was - * set so on FW notification the worker will see the change - * and apply new the new desired bw. - */ - if (mld_link->rx_omi.bw_in_progress) - return; - - if (bw == IEEE80211_STA_RX_BW_MAX) - apply_bw = ieee80211_chan_width_to_rx_bw(link_conf->chanreq.oper.width); - else - apply_bw = bw; - - if (!ap_update) { - /* The update isn't due to AP tracking after leaving OMI, - * where the AP could increase BW and then we must tell - * it that we can do the increased BW as well, if we did - * update the chandef. - * In this case, if we want MAX, then we will need to send - * a new OMI to the AP if it increases its own bandwidth as - * we can (due to internal and FW limitations, and being - * worried the AP might break) only send to what we're doing - * at the moment. In this case, set last_max_bw; otherwise - * if we really want to decrease our bandwidth set it to 0 - * to indicate no updates are needed if the AP changes. - */ - if (bw != IEEE80211_STA_RX_BW_MAX) - mld_link->rx_omi.last_max_bw = apply_bw; - else - mld_link->rx_omi.last_max_bw = 0; - } else { - /* Otherwise, if we're already trying to do maximum and - * the AP is changing, set last_max_bw to the new max the - * AP is using, we'll only get to this code path if the - * new bandwidth of the AP is bigger than what we sent it - * previously. This avoids repeatedly sending updates if - * it changes bandwidth, only doing it once on an increase. - */ - mld_link->rx_omi.last_max_bw = apply_bw; - } - - if (ieee80211_prepare_rx_omi_bw(link_sta, bw)) { - mld_link->rx_omi.bw_in_progress = apply_bw; - iwl_mld_change_link_omi_bw(mld, link_conf, apply_bw); - } -} - -static void iwl_mld_omi_bw_finished_work(struct wiphy *wiphy, - struct wiphy_work *work) -{ - struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); - struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); - struct iwl_mld_link *mld_link = - container_of(work, typeof(*mld_link), rx_omi.finished_work.work); - enum ieee80211_sta_rx_bandwidth desired_bw, switched_to_bw; - struct ieee80211_vif *vif = mld_link->vif; - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - struct ieee80211_bss_conf *link_conf; - struct ieee80211_link_sta *link_sta; - - if (!mld_vif->ap_sta) - return; - - link_sta = wiphy_dereference(mld->wiphy, - mld_vif->ap_sta->link[mld_link->link_id]); - if (WARN_ON_ONCE(!link_sta)) - return; - - link_conf = link_conf_dereference_protected(vif, link_sta->link_id); - if (WARN_ON_ONCE(!link_conf)) - return; - - if (WARN_ON(!mld_link->rx_omi.bw_in_progress)) - return; - - desired_bw = mld_link->rx_omi.desired_bw; - switched_to_bw = mld_link->rx_omi.bw_in_progress; - - ieee80211_finalize_rx_omi_bw(link_sta); - mld_link->rx_omi.bw_in_progress = 0; - - if (desired_bw != switched_to_bw) - iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, - desired_bw, false); -} - -static struct ieee80211_vif * -iwl_mld_get_omi_bw_reduction_pointers(struct iwl_mld *mld, - struct ieee80211_link_sta **link_sta, - struct iwl_mld_link **mld_link) -{ - struct iwl_mld_vif *mld_vif; - struct ieee80211_vif *vif; - int n_link_stas = 0; - - *link_sta = NULL; - - if (mld->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC) - return NULL; - - vif = iwl_mld_get_bss_vif(mld); - if (!vif) - return NULL; - - for (int i = 0; i < ARRAY_SIZE(mld->fw_id_to_link_sta); i++) { - struct ieee80211_link_sta *tmp; - - tmp = wiphy_dereference(mld->wiphy, mld->fw_id_to_link_sta[i]); - if (IS_ERR_OR_NULL(tmp)) - continue; - - n_link_stas++; - *link_sta = tmp; - } - - /* can't do anything if we have TDLS peers or EMLSR */ - if (n_link_stas != 1) - return NULL; - - mld_vif = iwl_mld_vif_from_mac80211(vif); - *mld_link = iwl_mld_link_dereference_check(mld_vif, - (*link_sta)->link_id); - if (WARN_ON(!*mld_link)) - return NULL; - - return vif; -} - -void iwl_mld_omi_ap_changed_bw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link_conf, - enum ieee80211_sta_rx_bandwidth bw) -{ - struct ieee80211_link_sta *link_sta; - struct iwl_mld_link *mld_link; - struct ieee80211_vif *vif; - - vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link); - if (!vif) - return; - - if (WARN_ON(link_conf->vif != vif)) - return; - - /* This is 0 if we requested an OMI BW reduction and don't want to - * be sending an OMI when the AP's bandwidth changes. - */ - if (!mld_link->rx_omi.last_max_bw) - return; - - /* We only need to tell the AP if it increases BW over what we last - * told it we were using, if it reduces then our last OMI to it will - * not get used anyway (e.g. we said we want 160 but it's doing 80.) - */ - if (bw < mld_link->rx_omi.last_max_bw) - return; - - iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, bw, true); -} - -void iwl_mld_handle_omi_status_notif(struct iwl_mld *mld, - struct iwl_rx_packet *pkt) -{ - struct ieee80211_link_sta *link_sta; - struct iwl_mld_link *mld_link; - struct ieee80211_vif *vif; - - vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link); - if (IWL_FW_CHECK(mld, !vif, "unexpected OMI notification\n")) - return; - - if (IWL_FW_CHECK(mld, !mld_link->rx_omi.bw_in_progress, - "OMI notification when not requested\n")) - return; - - wiphy_delayed_work_queue(mld->hw->wiphy, - &mld_link->rx_omi.finished_work, - msecs_to_jiffies(IWL_MLD_OMI_AP_SETTLE_DELAY)); -} - -void iwl_mld_leave_omi_bw_reduction(struct iwl_mld *mld) -{ - struct ieee80211_bss_conf *link_conf; - struct ieee80211_link_sta *link_sta; - struct iwl_mld_link *mld_link; - struct ieee80211_vif *vif; - - vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link); - if (!vif) - return; - - link_conf = link_conf_dereference_protected(vif, link_sta->link_id); - if (WARN_ON_ONCE(!link_conf)) - return; - - if (!link_conf->he_support) - return; - - mld_link->rx_omi.exit_ts = jiffies; - - iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, - IEEE80211_STA_RX_BW_MAX, false); -} - -void iwl_mld_check_omi_bw_reduction(struct iwl_mld *mld) -{ - enum ieee80211_sta_rx_bandwidth bw = IEEE80211_STA_RX_BW_MAX; - struct ieee80211_chanctx_conf *chanctx; - struct ieee80211_bss_conf *link_conf; - struct ieee80211_link_sta *link_sta; - struct cfg80211_chan_def chandef; - struct iwl_mld_link *mld_link; - struct iwl_mld_vif *mld_vif; - struct ieee80211_vif *vif; - struct iwl_mld_phy *phy; - u16 punctured; - int exit_thr; - - /* not allowed in CAM mode */ - if (iwlmld_mod_params.power_scheme == IWL_POWER_SCHEME_CAM) - return; - - /* must have one BSS connection (no P2P), no TDLS, nor EMLSR */ - vif = iwl_mld_get_omi_bw_reduction_pointers(mld, &link_sta, &mld_link); - if (!vif) - return; - - link_conf = link_conf_dereference_protected(vif, link_sta->link_id); - if (WARN_ON_ONCE(!link_conf)) - return; - - if (!link_conf->he_support) - return; - - chanctx = wiphy_dereference(mld->wiphy, mld_link->chan_ctx); - if (WARN_ON(!chanctx)) - return; - - mld_vif = iwl_mld_vif_from_mac80211(vif); - if (!mld_vif->authorized) - goto apply; - - /* must not be in low-latency mode */ - if (iwl_mld_vif_low_latency(mld_vif)) - goto apply; - - chandef = link_conf->chanreq.oper; - - switch (chandef.width) { - case NL80211_CHAN_WIDTH_320: - exit_thr = IWL_MLD_OMI_EXIT_CHAN_LOAD_320; - break; - case NL80211_CHAN_WIDTH_160: - exit_thr = IWL_MLD_OMI_EXIT_CHAN_LOAD_160; - break; - default: - /* since we reduce to 80 MHz, must have more to start with */ - goto apply; - } - - /* not to be done if primary 80 MHz is punctured */ - if (cfg80211_chandef_primary(&chandef, NL80211_CHAN_WIDTH_80, - &punctured) < 0 || - punctured != 0) - goto apply; - - phy = iwl_mld_phy_from_mac80211(chanctx); - - if (phy->channel_load_by_us > exit_thr) { - /* send OMI for max bandwidth */ - goto apply; - } - - if (phy->channel_load_by_us > IWL_MLD_OMI_ENTER_CHAN_LOAD) { - /* no changes between enter/exit thresholds */ - return; - } - - if (time_is_after_jiffies(mld_link->rx_omi.exit_ts + - msecs_to_jiffies(IWL_MLD_OMI_EXIT_PROTECTION))) - return; - - /* reduce bandwidth to 80 MHz to save power */ - bw = IEEE80211_STA_RX_BW_80; -apply: - iwl_mld_omi_bw_update(mld, link_conf, mld_link, link_sta, bw, false); -} - IWL_MLD_ALLOC_FN(link, bss_conf) /* Constructor function for struct iwl_mld_link */ @@ -777,17 +444,12 @@ static int iwl_mld_init_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link, struct iwl_mld_link *mld_link) { - mld_link->vif = link->vif; - mld_link->link_id = link->link_id; + mld_link->average_beacon_energy = 0; iwl_mld_init_internal_sta(&mld_link->bcast_sta); iwl_mld_init_internal_sta(&mld_link->mcast_sta); iwl_mld_init_internal_sta(&mld_link->mon_sta); - if (!mld->fw_status.in_hw_restart) - wiphy_delayed_work_init(&mld_link->rx_omi.finished_work, - iwl_mld_omi_bw_finished_work); - return iwl_mld_allocate_link_fw_id(mld, &mld_link->fw_id, link); } @@ -851,8 +513,6 @@ void iwl_mld_remove_link(struct iwl_mld *mld, RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL); - wiphy_delayed_work_cancel(mld->wiphy, &link->rx_omi.finished_work); - if (WARN_ON(link->fw_id >= mld->fw->ucode_capa.num_links)) return; @@ -864,21 +524,23 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, { const struct iwl_missed_beacons_notif *notif = (const void *)pkt->data; union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; - u32 link_id = le32_to_cpu(notif->link_id); + u32 fw_link_id = le32_to_cpu(notif->link_id); u32 missed_bcon = le32_to_cpu(notif->consec_missed_beacons); u32 missed_bcon_since_rx = le32_to_cpu(notif->consec_missed_beacons_since_last_rx); u32 scnd_lnk_bcn_lost = le32_to_cpu(notif->consec_missed_beacons_other_link); struct ieee80211_bss_conf *link_conf = - iwl_mld_fw_id_to_link_conf(mld, link_id); + iwl_mld_fw_id_to_link_conf(mld, fw_link_id); u32 bss_param_ch_cnt_link_id; struct ieee80211_vif *vif; + u8 link_id; if (WARN_ON(!link_conf)) return; vif = link_conf->vif; + link_id = link_conf->link_id; bss_param_ch_cnt_link_id = link_conf->bss_param_ch_cnt_link_id; IWL_DEBUG_INFO(mld, @@ -890,7 +552,7 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, mld->trans->dbg.dump_file_name_ext_valid = true; snprintf(mld->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "LinkId_%d_MacType_%d", link_id, + "LinkId_%d_MacType_%d", fw_link_id, iwl_mld_mac80211_iftype_to_fw(vif)); iwl_dbg_tlv_time_point(&mld->fwrt, @@ -1212,3 +874,22 @@ unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld, return grade; } EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_get_link_grade); + +void iwl_mld_handle_beacon_filter_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt) +{ + const struct iwl_beacon_filter_notif *notif = (const void *)pkt->data; + u32 link_id = le32_to_cpu(notif->link_id); + struct ieee80211_bss_conf *link_conf = + iwl_mld_fw_id_to_link_conf(mld, link_id); + struct iwl_mld_link *mld_link; + + if (IWL_FW_CHECK(mld, !link_conf, "invalid link ID %d\n", link_id)) + return; + + mld_link = iwl_mld_link_from_mac80211(link_conf); + if (WARN_ON_ONCE(!mld_link)) + return; + + mld_link->average_beacon_energy = le32_to_cpu(notif->average_energy); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.h b/drivers/net/wireless/intel/iwlwifi/mld/link.h index 39f04aae5579..cad2c9426349 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.h @@ -36,25 +36,17 @@ struct iwl_probe_resp_data { * @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked. * @igtk: fw can only have one IGTK at a time, whereas mac80211 can have two. * This tracks the one IGTK that currently exists in FW. - * @vif: the vif this link belongs to * @bcast_sta: station used for broadcast packets. Used in AP, GO and IBSS. * @mcast_sta: station used for multicast packets. Used in AP, GO and IBSS. * @mon_sta: station used for TX injection in monitor interface. - * @link_id: over the air link ID + * @average_beacon_energy: average beacon energy for beacons received during + * client connections * @ap_early_keys: The firmware cannot install keys before bcast/mcast STAs, * but higher layers work differently, so we store the keys here for * later installation. * @silent_deactivation: next deactivation needs to be silent. * @probe_resp_data: data from FW notification to store NOA related data to be * inserted into probe response. - * @rx_omi: data for BW reduction with OMI - * @rx_omi.bw_in_progress: update is in progress (indicates target BW) - * @rx_omi.exit_ts: timestamp of last exit - * @rx_omi.finished_work: work for the delayed reaction to the firmware saying - * the change was applied, and for then applying a new mode if it was - * updated while waiting for firmware/AP settle delay. - * @rx_omi.desired_bw: desired bandwidth - * @rx_omi.last_max_bw: last maximum BW used by firmware, for AP BW changes */ struct iwl_mld_link { struct rcu_head rcu_head; @@ -69,22 +61,13 @@ struct iwl_mld_link { struct ieee80211_key_conf *igtk; ); /* And here fields that survive a fw restart */ - struct ieee80211_vif *vif; struct iwl_mld_int_sta bcast_sta; struct iwl_mld_int_sta mcast_sta; struct iwl_mld_int_sta mon_sta; - u8 link_id; - - struct { - struct wiphy_delayed_work finished_work; - unsigned long exit_ts; - enum ieee80211_sta_rx_bandwidth bw_in_progress, - desired_bw, - last_max_bw; - } rx_omi; /* we can only have 2 GTK + 2 IGTK + 2 BIGTK active at a time */ struct ieee80211_key_conf *ap_early_keys[6]; + u32 average_beacon_energy; bool silent_deactivation; struct iwl_probe_resp_data __rcu *probe_resp_data; }; @@ -120,9 +103,6 @@ int iwl_mld_activate_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link); void iwl_mld_deactivate_link(struct iwl_mld *mld, struct ieee80211_bss_conf *link); -int iwl_mld_change_link_omi_bw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - enum ieee80211_sta_rx_bandwidth bw); int iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link, u32 changes); void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, @@ -142,12 +122,8 @@ unsigned int iwl_mld_get_chan_load(struct iwl_mld *mld, int iwl_mld_get_chan_load_by_others(struct iwl_mld *mld, struct ieee80211_bss_conf *link_conf, bool expect_active_link); -void iwl_mld_handle_omi_status_notif(struct iwl_mld *mld, - struct iwl_rx_packet *pkt); -void iwl_mld_leave_omi_bw_reduction(struct iwl_mld *mld); -void iwl_mld_check_omi_bw_reduction(struct iwl_mld *mld); -void iwl_mld_omi_ap_changed_bw(struct iwl_mld *mld, - struct ieee80211_bss_conf *link_conf, - enum ieee80211_sta_rx_bandwidth bw); + +void iwl_mld_handle_beacon_filter_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt); #endif /* __iwl_mld_link_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c b/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c index f7faa87b8ba6..23362867b400 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c @@ -224,9 +224,6 @@ void iwl_mld_vif_update_low_latency(struct iwl_mld *mld, return; } - if (low_latency) - iwl_mld_leave_omi_bw_reduction(mld); - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_P2P_CLIENT) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 4ba050397632..b0bd01914a91 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -4,6 +4,7 @@ */ #include <net/mac80211.h> +#include <linux/fips.h> #include <linux/ip.h> #include "mld.h" @@ -156,6 +157,9 @@ static void iwl_mld_hw_set_security(struct iwl_mld *mld) WLAN_CIPHER_SUITE_BIP_GMAC_256 }; + if (fips_enabled) + return; + hw->wiphy->n_cipher_suites = ARRAY_SIZE(mld_ciphers); hw->wiphy->cipher_suites = mld_ciphers; @@ -180,6 +184,9 @@ static void iwl_mld_hw_set_pm(struct iwl_mld *mld) if (!device_can_wakeup(mld->trans->dev)) return; + if (fips_enabled) + return; + mld->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | @@ -284,9 +291,11 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK; + /* For fips_enabled, don't support WiFi7 due to WPA3/MFP requirements */ if (mld->nvm_data->sku_cap_11be_enable && !iwlwifi_mod_params.disable_11ax && - !iwlwifi_mod_params.disable_11be) + !iwlwifi_mod_params.disable_11be && + !fips_enabled) wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO; /* the firmware uses u8 for num of iterations, but 0xff is saved for @@ -508,8 +517,15 @@ int iwl_mld_mac80211_start(struct ieee80211_hw *hw) if (in_d3) { /* mac80211 already cleaned up the state, no need for cleanup */ ret = iwl_mld_no_wowlan_resume(mld); - if (ret) + if (ret) { iwl_mld_stop_fw(mld); + /* We're not really restarting in the sense of + * in_hw_restart even if we got an error during + * this. We'll just start again below and have + * nothing to recover, mac80211 will do anyway. + */ + mld->fw_status.in_hw_restart = false; + } } #endif /* CONFIG_PM_SLEEP */ @@ -574,7 +590,8 @@ void iwl_mld_mac80211_stop(struct ieee80211_hw *hw, bool suspend) } static -int iwl_mld_mac80211_config(struct ieee80211_hw *hw, u32 changed) +int iwl_mld_mac80211_config(struct ieee80211_hw *hw, int radio_idx, + u32 changed) { return 0; } @@ -998,10 +1015,9 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw, if (n_active > 1) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - iwl_mld_leave_omi_bw_reduction(mld); - /* Indicate to mac80211 that EML is enabled */ vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE; + mld_vif->emlsr.last_entry_ts = jiffies; if (vif->active_links & BIT(mld_vif->emlsr.selected_links)) mld_vif->emlsr.primary = mld_vif->emlsr.selected_primary; @@ -1102,7 +1118,8 @@ void iwl_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, } static -int iwl_mld_mac80211_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +int iwl_mld_mac80211_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { return 0; } @@ -1193,20 +1210,6 @@ iwl_mld_mac80211_link_info_changed_sta(struct iwl_mld *mld, if (changes & (BSS_CHANGED_CQM | BSS_CHANGED_BEACON_INFO)) iwl_mld_enable_beacon_filter(mld, link_conf, false); - /* If we have used OMI before to reduce bandwidth to 80 MHz and then - * increased to 160 MHz again, and then the AP changes to 320 MHz, it - * will think that we're limited to 160 MHz right now. Update it by - * requesting a new OMI bandwidth. - */ - if (changes & BSS_CHANGED_BANDWIDTH) { - enum ieee80211_sta_rx_bandwidth bw; - - bw = ieee80211_chan_width_to_rx_bw(link_conf->chanreq.oper.width); - - iwl_mld_omi_ap_changed_bw(mld, link_conf, bw); - - } - if (changes & BSS_CHANGED_BANDWIDTH) iwl_mld_retry_emlsr(mld, vif); } @@ -1410,30 +1413,6 @@ iwl_mld_mac80211_sched_scan_stop(struct ieee80211_hw *hw, } static void -iwl_mld_restart_complete_vif(void *data, u8 *mac, struct ieee80211_vif *vif) -{ - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - struct ieee80211_bss_conf *link_conf; - struct iwl_mld *mld = data; - int link_id; - - for_each_vif_active_link(vif, link_conf, link_id) { - enum ieee80211_sta_rx_bandwidth bw; - struct iwl_mld_link *mld_link; - - mld_link = wiphy_dereference(mld->wiphy, - mld_vif->link[link_id]); - - if (WARN_ON_ONCE(!mld_link)) - continue; - - bw = mld_link->rx_omi.bw_in_progress; - if (bw) - iwl_mld_change_link_omi_bw(mld, link_conf, bw); - } -} - -static void iwl_mld_mac80211_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type) { @@ -1443,11 +1422,6 @@ iwl_mld_mac80211_reconfig_complete(struct ieee80211_hw *hw, case IEEE80211_RECONFIG_TYPE_RESTART: mld->fw_status.in_hw_restart = false; iwl_mld_send_recovery_cmd(mld, ERROR_RECOVERY_END_OF_RECOVERY); - - ieee80211_iterate_interfaces(mld->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mld_restart_complete_vif, mld); - iwl_trans_finish_sw_reset(mld->trans); /* no need to lock, adding in parallel would schedule too */ if (!list_empty(&mld->txqs_to_add)) @@ -1468,7 +1442,7 @@ void iwl_mld_mac80211_mgd_prepare_tx(struct ieee80211_hw *hw, struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); u32 duration = IWL_MLD_SESSION_PROTECTION_ASSOC_TIME_MS; - /* After a successful association the connection is etalibeshed + /* After a successful association the connection is established * and we can rely on the quota to send the disassociation frame. */ if (info->was_assoc) @@ -1671,18 +1645,6 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld, return -EBUSY; } - /* - * If this is the first STA (i.e. the AP) it won't do - * anything, otherwise must leave for any new STA on - * any other interface, or for TDLS, etc. - * Need to call this _before_ adding the STA so it can - * look up the one STA to use to ask mac80211 to leave - * OMI; in the unlikely event that adding the new STA - * then fails we'll just re-enter OMI later (via the - * statistics notification handling.) - */ - iwl_mld_leave_omi_bw_reduction(mld); - ret = iwl_mld_add_sta(mld, sta, vif, STATION_TYPE_PEER); if (ret) return ret; @@ -1908,6 +1870,10 @@ iwl_mld_mac80211_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: + if (!iwl_enable_rx_ampdu()) { + ret = -EINVAL; + break; + } ret = iwl_mld_ampdu_rx_start(mld, sta, tid, ssn, buf_size, timeout); break; @@ -2573,28 +2539,6 @@ static int iwl_mld_mac80211_tx_last_beacon(struct ieee80211_hw *hw) return mld->ibss_manager; } -#define IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS_TIMEOUT (5 * HZ) - -static void iwl_mld_vif_iter_emlsr_block_tmp_non_bss(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - int ret; - - if (!iwl_mld_vif_has_emlsr_cap(vif)) - return; - - ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif, - IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS, - iwl_mld_get_primary_link(vif)); - if (ret) - return; - - wiphy_delayed_work_queue(mld_vif->mld->wiphy, - &mld_vif->emlsr.tmp_non_bss_done_wk, - IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS_TIMEOUT); -} - static void iwl_mld_prep_add_interface(struct ieee80211_hw *hw, enum nl80211_iftype type) { @@ -2607,10 +2551,7 @@ static void iwl_mld_prep_add_interface(struct ieee80211_hw *hw, type == NL80211_IFTYPE_P2P_CLIENT)) return; - ieee80211_iterate_active_interfaces_mtx(mld->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mld_vif_iter_emlsr_block_tmp_non_bss, - NULL); + iwl_mld_emlsr_block_tmp_non_bss(mld); } static int iwl_mld_set_hw_timestamp(struct ieee80211_hw *hw, @@ -2640,6 +2581,23 @@ static int iwl_mld_start_pmsr(struct ieee80211_hw *hw, return iwl_mld_ftm_start(mld, vif, request); } +static enum ieee80211_neg_ttlm_res +iwl_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_neg_ttlm *neg_ttlm) +{ + u16 map; + + /* Verify all TIDs are mapped to the same links set */ + map = neg_ttlm->downlink[0]; + for (int i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) { + if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] || + neg_ttlm->uplink[i] != map) + return NEG_TTLM_RES_REJECT; + } + + return NEG_TTLM_RES_ACCEPT; +} + const struct ieee80211_ops iwl_mld_hw_ops = { .tx = iwl_mld_mac80211_tx, .start = iwl_mld_mac80211_start, @@ -2669,6 +2627,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = { .mgd_complete_tx = iwl_mld_mac_mgd_complete_tx, .sta_state = iwl_mld_mac80211_sta_state, .sta_statistics = iwl_mld_mac80211_sta_statistics, + .get_survey = iwl_mld_mac80211_get_survey, .flush = iwl_mld_mac80211_flush, .flush_sta = iwl_mld_mac80211_flush_sta, .ampdu_action = iwl_mld_mac80211_ampdu_action, @@ -2709,4 +2668,5 @@ const struct ieee80211_ops iwl_mld_hw_ops = { .prep_add_interface = iwl_mld_prep_add_interface, .set_hw_timestamp = iwl_mld_set_hw_timestamp, .start_pmsr = iwl_mld_start_pmsr, + .can_neg_ttlm = iwl_mld_can_neg_ttlm, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mcc.c b/drivers/net/wireless/intel/iwlwifi/mld/mcc.c index 19cb562e7a73..16bb1b4904f9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mcc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mcc.c @@ -15,7 +15,7 @@ /* It is the caller's responsibility to free the pointer returned here */ static struct iwl_mcc_update_resp_v8 * -iwl_mld_parse_mcc_update_resp_v8(const struct iwl_rx_packet *pkt) +iwl_mld_copy_mcc_resp(const struct iwl_rx_packet *pkt) { const struct iwl_mcc_update_resp_v8 *mcc_resp_v8 = (const void *)pkt->data; int n_channels = __le32_to_cpu(mcc_resp_v8->n_channels); @@ -34,41 +34,9 @@ iwl_mld_parse_mcc_update_resp_v8(const struct iwl_rx_packet *pkt) /* It is the caller's responsibility to free the pointer returned here */ static struct iwl_mcc_update_resp_v8 * -iwl_mld_parse_mcc_update_resp_v5_v6(const struct iwl_rx_packet *pkt) -{ - const struct iwl_mcc_update_resp_v4 *mcc_resp_v4 = (const void *)pkt->data; - struct iwl_mcc_update_resp_v8 *resp_cp; - int n_channels = __le32_to_cpu(mcc_resp_v4->n_channels); - int resp_len; - - if (iwl_rx_packet_payload_len(pkt) != - struct_size(mcc_resp_v4, channels, n_channels)) - return ERR_PTR(-EINVAL); - - resp_len = struct_size(resp_cp, channels, n_channels); - resp_cp = kzalloc(resp_len, GFP_KERNEL); - if (!resp_cp) - return ERR_PTR(-ENOMEM); - - resp_cp->status = mcc_resp_v4->status; - resp_cp->mcc = mcc_resp_v4->mcc; - resp_cp->cap = cpu_to_le32(le16_to_cpu(mcc_resp_v4->cap)); - resp_cp->source_id = mcc_resp_v4->source_id; - resp_cp->geo_info = mcc_resp_v4->geo_info; - resp_cp->n_channels = mcc_resp_v4->n_channels; - memcpy(resp_cp->channels, mcc_resp_v4->channels, - n_channels * sizeof(__le32)); - - return resp_cp; -} - -/* It is the caller's responsibility to free the pointer returned here */ -static struct iwl_mcc_update_resp_v8 * iwl_mld_update_mcc(struct iwl_mld *mld, const char *alpha2, enum iwl_mcc_source src_id) { - int resp_ver = iwl_fw_lookup_notif_ver(mld->fw, LONG_GROUP, - MCC_UPDATE_CMD, 0); struct iwl_mcc_update_cmd mcc_update_cmd = { .mcc = cpu_to_le16(alpha2[0] << 8 | alpha2[1]), .source_id = (u8)src_id, @@ -93,23 +61,7 @@ iwl_mld_update_mcc(struct iwl_mld *mld, const char *alpha2, pkt = cmd.resp_pkt; - /* For Wifi-7 radios, we get version 8 - * For Wifi-6E radios, we get version 6 - * For Wifi-6 radios, we get version 5, but 5, 6, and 4 are compatible. - */ - switch (resp_ver) { - case 5: - case 6: - resp_cp = iwl_mld_parse_mcc_update_resp_v5_v6(pkt); - break; - case 8: - resp_cp = iwl_mld_parse_mcc_update_resp_v8(pkt); - break; - default: - IWL_FW_CHECK_FAILED(mld, "Unknown MCC_UPDATE_CMD version %d\n", resp_ver); - resp_cp = ERR_PTR(-EINVAL); - } - + resp_cp = iwl_mld_copy_mcc_resp(pkt); if (IS_ERR(resp_cp)) goto exit; @@ -177,11 +129,15 @@ iwl_mld_get_regdomain(struct iwl_mld *mld, mld->mcc_src = resp->source_id; - if (!iwl_puncturing_is_allowed_in_bios(mld->bios_enable_puncturing, - le16_to_cpu(resp->mcc))) - ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING); - else - __clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING, mld->hw->flags); + /* FM is the earliest supported and later always do puncturing */ + if (CSR_HW_RFID_TYPE(mld->trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_FM) { + if (!iwl_puncturing_is_allowed_in_bios(mld->bios_enable_puncturing, + le16_to_cpu(resp->mcc))) + ieee80211_hw_set(mld->hw, DISALLOW_PUNCTURING); + else + __clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING, + mld->hw->flags); + } out: kfree(resp); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index 1774bb84dd3f..7b46ccc306ab 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -251,16 +251,23 @@ static const struct iwl_hcmd_names iwl_mld_data_path_names[] = { HCMD_NAME(TLC_MNG_CONFIG_CMD), HCMD_NAME(RX_BAID_ALLOCATION_CONFIG_CMD), HCMD_NAME(SCD_QUEUE_CONFIG_CMD), - HCMD_NAME(OMI_SEND_STATUS_NOTIF), HCMD_NAME(ESR_MODE_NOTIF), HCMD_NAME(MONITOR_NOTIF), HCMD_NAME(TLC_MNG_UPDATE_NOTIF), + HCMD_NAME(BEACON_FILTER_IN_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), }; /* Please keep this array *SORTED* by hex value. * Access is done through binary search */ +static const struct iwl_hcmd_names iwl_mld_scan_names[] = { + HCMD_NAME(CHANNEL_SURVEY_NOTIF), +}; + +/* Please keep this array *SORTED* by hex value. + * Access is done through binary search + */ static const struct iwl_hcmd_names iwl_mld_location_names[] = { HCMD_NAME(TOF_RANGE_REQ_CMD), HCMD_NAME(TOF_RANGE_RESPONSE_NOTIF), @@ -309,6 +316,7 @@ const struct iwl_hcmd_arr iwl_mld_groups[] = { [SYSTEM_GROUP] = HCMD_ARR(iwl_mld_system_names), [MAC_CONF_GROUP] = HCMD_ARR(iwl_mld_mac_conf_names), [DATA_PATH_GROUP] = HCMD_ARR(iwl_mld_data_path_names), + [SCAN_GROUP] = HCMD_ARR(iwl_mld_scan_names), [LOCATION_GROUP] = HCMD_ARR(iwl_mld_location_names), [REGULATORY_AND_NVM_GROUP] = HCMD_ARR(iwl_mld_reg_and_nvm_names), [DEBUG_GROUP] = HCMD_ARR(iwl_mld_debug_names), @@ -357,7 +365,7 @@ iwl_mld_configure_trans(struct iwl_op_mode *op_mode) trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds); trans->conf.rx_mpdu_cmd = REPLY_RX_MPDU_CMD; - trans->conf.rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start); + trans->conf.rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc); trans->conf.wide_cmd_header = true; iwl_trans_op_mode_enter(trans, op_mode); @@ -506,6 +514,7 @@ iwl_op_mode_mld_stop(struct iwl_op_mode *op_mode) kfree(mld->nvm_data); kfree(mld->scan.cmd); + kfree(mld->channel_survey); kfree(mld->error_recovery_buf); kfree(mld->mcast_filter_cmd); @@ -630,7 +639,7 @@ iwl_mld_nic_error(struct iwl_op_mode *op_mode, enum iwl_fw_error_type type) { struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode); - bool trans_dead = test_bit(STATUS_TRANS_DEAD, &mld->trans->status); + bool trans_dead = iwl_trans_is_dead(mld->trans); if (type == IWL_ERR_TYPE_CMD_QUEUE_FULL) IWL_ERR(mld, "Command queue full!\n"); @@ -725,6 +734,17 @@ static void iwl_mld_device_powered_off(struct iwl_op_mode *op_mode) {} #endif +static void iwl_mld_dump(struct iwl_op_mode *op_mode) +{ + struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode); + struct iwl_fw_runtime *fwrt = &mld->fwrt; + + if (!iwl_trans_fw_running(fwrt->trans)) + return; + + iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, NULL); +} + static const struct iwl_op_mode_ops iwl_mld_ops = { .start = iwl_op_mode_mld_start, .stop = iwl_op_mode_mld_stop, @@ -739,6 +759,7 @@ static const struct iwl_op_mode_ops iwl_mld_ops = { .sw_reset = iwl_mld_sw_reset, .time_point = iwl_mld_time_point, .device_powered_off = pm_sleep_ptr(iwl_mld_device_powered_off), + .dump = iwl_mld_dump, }; struct iwl_mld_mod_params iwlmld_mod_params = { diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index 1a2c44f44eff..94dc9da6360d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -127,6 +127,7 @@ * cleanup using iwl_mld_free_internal_sta * @netdetect: indicates the FW is in suspend mode with netdetect configured * @p2p_device_vif: points to the p2p device vif if exists + * @bt_is_active: indicates that BT is active * @dev: pointer to device struct. For printing purposes * @trans: pointer to the transport layer * @cfg: pointer to the device configuration @@ -149,6 +150,7 @@ * @running: true if the firmware is running * @do_not_dump_once: true if firmware dump must be prevented once * @in_d3: indicates FW is in suspend mode and should be resumed + * @resuming: indicates the driver is resuming from wowlan * @in_hw_restart: indicates that we are currently in restart flow. * rather than restarted. Should be unset upon restart. * @radio_kill: bitmap of radio kill status @@ -158,7 +160,9 @@ * device * @addresses: device MAC addresses. * @scan: instance of the scan object + * @channel_survey: channel survey information collected during scan * @wowlan: WoWLAN support data. + * @debug_max_sleep: maximum sleep time in D3 (for debug purposes) * @led: the led device * @mcc_src: the source id of the MCC, comes from the firmware * @bios_enable_puncturing: is puncturing enabled by bios @@ -187,7 +191,6 @@ * @ptp_data: data of the PTP clock * @time_sync: time sync data. * @ftm_initiator: FTM initiator data - * @last_bt_notif: last received BT Coex notif */ struct iwl_mld { /* Add here fields that need clean up on restart */ @@ -212,7 +215,7 @@ struct iwl_mld { bool netdetect; #endif /* CONFIG_PM_SLEEP */ struct ieee80211_vif *p2p_device_vif; - struct iwl_bt_coex_profile_notif last_bt_notif; + bool bt_is_active; ); struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX]; /* And here fields that survive a fw restart */ @@ -236,6 +239,7 @@ struct iwl_mld { do_not_dump_once:1, #ifdef CONFIG_PM_SLEEP in_d3:1, + resuming:1, #endif in_hw_restart:1; @@ -250,8 +254,10 @@ struct iwl_mld { struct mac_address addresses[IWL_MLD_MAX_ADDRESSES]; struct iwl_mld_scan scan; + struct iwl_mld_survey *channel_survey; #ifdef CONFIG_PM_SLEEP struct wiphy_wowlan_support wowlan; + u32 debug_max_sleep; #endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_IWLWIFI_LEDS struct led_classdev led; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index dba5379ed009..e57f5388fe77 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -287,6 +287,36 @@ int iwl_mld_block_emlsr_sync(struct iwl_mld *mld, struct ieee80211_vif *vif, return _iwl_mld_emlsr_block(mld, vif, reason, link_to_keep, true); } +#define IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS_TIMEOUT (10 * HZ) + +static void iwl_mld_vif_iter_emlsr_block_tmp_non_bss(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + int ret; + + if (!iwl_mld_vif_has_emlsr_cap(vif)) + return; + + ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif, + IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS, + iwl_mld_get_primary_link(vif)); + if (ret) + return; + + wiphy_delayed_work_queue(mld_vif->mld->wiphy, + &mld_vif->emlsr.tmp_non_bss_done_wk, + IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS_TIMEOUT); +} + +void iwl_mld_emlsr_block_tmp_non_bss(struct iwl_mld *mld) +{ + ieee80211_iterate_active_interfaces_mtx(mld->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mld_vif_iter_emlsr_block_tmp_non_bss, + NULL); +} + static void _iwl_mld_select_links(struct iwl_mld *mld, struct ieee80211_vif *vif); @@ -530,10 +560,12 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk) /* * TPT is unblocked, need to check if the TPT criteria is still met. * - * If EMLSR is active, then we also need to check the secondar link - * requirements. + * If EMLSR is active for at least 5 seconds, then we also + * need to check the secondary link requirements. */ - if (iwl_mld_emlsr_active(vif)) { + if (iwl_mld_emlsr_active(vif) && + time_is_before_jiffies(mld_vif->emlsr.last_entry_ts + + IWL_MLD_TPT_COUNT_WINDOW)) { sec_link_id = iwl_mld_get_other_link(vif, iwl_mld_get_primary_link(vif)); sec_link = iwl_mld_link_dereference_check(mld_vif, sec_link_id); if (WARN_ON_ONCE(!sec_link)) @@ -657,42 +689,6 @@ s8 iwl_mld_get_emlsr_rssi_thresh(struct iwl_mld *mld, #undef RSSI_THRESHOLD } -#define IWL_MLD_BT_COEX_DISABLE_EMLSR_RSSI_THRESH -69 -#define IWL_MLD_BT_COEX_ENABLE_EMLSR_RSSI_THRESH -63 -#define IWL_MLD_BT_COEX_WIFI_LOSS_THRESH 7 - -VISIBLE_IF_IWLWIFI_KUNIT -bool -iwl_mld_bt_allows_emlsr(struct iwl_mld *mld, struct ieee80211_bss_conf *link, - bool check_entry) -{ - int bt_penalty, rssi_thresh; - s32 link_rssi; - - if (WARN_ON_ONCE(!link->bss)) - return false; - - link_rssi = MBM_TO_DBM(link->bss->signal); - rssi_thresh = check_entry ? - IWL_MLD_BT_COEX_ENABLE_EMLSR_RSSI_THRESH : - IWL_MLD_BT_COEX_DISABLE_EMLSR_RSSI_THRESH; - /* No valid RSSI - force to take low rssi */ - if (!link_rssi) - link_rssi = rssi_thresh - 1; - - if (link_rssi > rssi_thresh) - bt_penalty = max(mld->last_bt_notif.wifi_loss_mid_high_rssi[PHY_BAND_24][0], - mld->last_bt_notif.wifi_loss_mid_high_rssi[PHY_BAND_24][1]); - else - bt_penalty = max(mld->last_bt_notif.wifi_loss_low_rssi[PHY_BAND_24][0], - mld->last_bt_notif.wifi_loss_low_rssi[PHY_BAND_24][1]); - - IWL_DEBUG_EHT(mld, "BT penalty for link-id %0X is %d\n", - link->link_id, bt_penalty); - return bt_penalty < IWL_MLD_BT_COEX_WIFI_LOSS_THRESH; -} -EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_bt_allows_emlsr); - static u32 iwl_mld_emlsr_disallowed_with_link(struct iwl_mld *mld, struct ieee80211_vif *vif, @@ -707,8 +703,7 @@ iwl_mld_emlsr_disallowed_with_link(struct iwl_mld *mld, if (WARN_ON_ONCE(!conf)) return IWL_MLD_EMLSR_EXIT_INVALID; - if (link->chandef->chan->band == NL80211_BAND_2GHZ && - !iwl_mld_bt_allows_emlsr(mld, conf, true)) + if (link->chandef->chan->band == NL80211_BAND_2GHZ && mld->bt_is_active) ret |= IWL_MLD_EMLSR_EXIT_BT_COEX; if (link->signal < @@ -1046,41 +1041,30 @@ static void iwl_mld_emlsr_check_bt_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - const struct iwl_bt_coex_profile_notif zero_notif = {}; struct iwl_mld *mld = mld_vif->mld; struct ieee80211_bss_conf *link; unsigned int link_id; - const struct iwl_bt_coex_profile_notif *notif = &mld->last_bt_notif; if (!iwl_mld_vif_has_emlsr_cap(vif)) return; - /* zeroed structure means that BT is OFF */ - if (!memcmp(notif, &zero_notif, sizeof(*notif))) { + if (!mld->bt_is_active) { iwl_mld_retry_emlsr(mld, vif); return; } - for_each_vif_active_link(vif, link, link_id) { - bool emlsr_active, emlsr_allowed; + /* BT is turned ON but we are not in EMLSR, nothing to do */ + if (!iwl_mld_emlsr_active(vif)) + return; - if (WARN_ON(!link->chanreq.oper.chan)) - continue; + /* In EMLSR and BT is turned ON */ - if (link->chanreq.oper.chan->band != NL80211_BAND_2GHZ) + for_each_vif_active_link(vif, link, link_id) { + if (WARN_ON(!link->chanreq.oper.chan)) continue; - emlsr_active = iwl_mld_emlsr_active(vif); - emlsr_allowed = iwl_mld_bt_allows_emlsr(mld, link, - !emlsr_active); - if (emlsr_allowed && !emlsr_active) { - iwl_mld_retry_emlsr(mld, vif); - return; - } - - if (!emlsr_allowed && emlsr_active) { - iwl_mld_exit_emlsr(mld, vif, - IWL_MLD_EMLSR_EXIT_BT_COEX, + if (link->chanreq.oper.chan->band == NL80211_BAND_2GHZ) { + iwl_mld_exit_emlsr(mld, vif, IWL_MLD_EMLSR_EXIT_BT_COEX, iwl_mld_get_primary_link(vif)); return; } @@ -1167,8 +1151,8 @@ void iwl_mld_retry_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - if (!iwl_mld_vif_has_emlsr_cap(vif) || iwl_mld_emlsr_active(vif) || - mld_vif->emlsr.blocked_reasons) + if (!IWL_MLD_AUTO_EML_ENABLE || !iwl_mld_vif_has_emlsr_cap(vif) || + iwl_mld_emlsr_active(vif) || mld_vif->emlsr.blocked_reasons) return; iwl_mld_int_mlo_scan(mld, vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.h b/drivers/net/wireless/intel/iwlwifi/mld/mlo.h index 9afa3d6ea649..d936589fe39d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.h @@ -157,14 +157,12 @@ struct iwl_mld_link_sel_data { u16 grade; }; +void iwl_mld_emlsr_block_tmp_non_bss(struct iwl_mld *mld); + #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) u32 iwl_mld_emlsr_pair_state(struct ieee80211_vif *vif, struct iwl_mld_link_sel_data *a, struct iwl_mld_link_sel_data *b); - -bool iwl_mld_bt_allows_emlsr(struct iwl_mld *mld, - struct ieee80211_bss_conf *link, - bool entry_criteria); #endif void iwl_mld_start_ignoring_tpt_updates(struct iwl_mld *mld); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index c0e62d46aba6..f17aeca4fae6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -78,13 +78,6 @@ static bool iwl_mld_cancel_##name##_notif(struct iwl_mld *mld, \ u8: (notif)->id_member); \ } -static bool iwl_mld_always_cancel(struct iwl_mld *mld, - struct iwl_rx_packet *pkt, - u32 obj_id) -{ - return true; -} - /* Currently only defined for the RX_HANDLER_SIZES options. Use this for * notifications that belong to a specific object, and that should be * canceled when the object is removed @@ -295,6 +288,8 @@ CMD_VERSIONS(scan_complete_notif, CMD_VER_ENTRY(1, iwl_umac_scan_complete)) CMD_VERSIONS(scan_iter_complete_notif, CMD_VER_ENTRY(2, iwl_umac_scan_iter_complete_notif)) +CMD_VERSIONS(channel_survey_notif, + CMD_VER_ENTRY(1, iwl_umac_scan_channel_survey_notif)) CMD_VERSIONS(mfuart_notif, CMD_VER_ENTRY(2, iwl_mfuart_load_notif)) CMD_VERSIONS(update_mcc, @@ -348,9 +343,8 @@ CMD_VERSIONS(time_msmt_notif, CMD_VER_ENTRY(1, iwl_time_msmt_notify)) CMD_VERSIONS(time_sync_confirm_notif, CMD_VER_ENTRY(1, iwl_time_msmt_cfm_notify)) -CMD_VERSIONS(omi_status_notif, - CMD_VER_ENTRY(1, iwl_omi_send_status_notif)) -CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(9, iwl_tof_range_rsp_ntfy)) +CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy)) +CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif)) DEFINE_SIMPLE_CANCELLATION(session_prot, iwl_session_prot_notif, mac_link_id) DEFINE_SIMPLE_CANCELLATION(tlc, iwl_tlc_update_notif, sta_id) @@ -366,8 +360,8 @@ DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif, mac_id) DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif, mac_id) -#define iwl_mld_cancel_omi_status_notif iwl_mld_always_cancel DEFINE_SIMPLE_CANCELLATION(ftm_resp, iwl_tof_range_rsp_ntfy, request_id) +DEFINE_SIMPLE_CANCELLATION(beacon_filter, iwl_beacon_filter_notif, link_id) /** * DOC: Handlers for fw notifications @@ -412,6 +406,10 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = { RX_HANDLER_NO_VAL(LEGACY_GROUP, MATCH_FOUND_NOTIFICATION, match_found_notif, RX_HANDLER_SYNC) + RX_HANDLER_NO_OBJECT(SCAN_GROUP, CHANNEL_SURVEY_NOTIF, + channel_survey_notif, + RX_HANDLER_ASYNC) + RX_HANDLER_NO_OBJECT(STATISTICS_GROUP, STATISTICS_OPER_NOTIF, stats_oper_notif, RX_HANDLER_ASYNC) RX_HANDLER_NO_OBJECT(STATISTICS_GROUP, STATISTICS_OPER_PART1_NOTIF, @@ -458,8 +456,8 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = { RX_HANDLER_NO_OBJECT(LEGACY_GROUP, WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION, time_sync_confirm_notif, RX_HANDLER_ASYNC) - RX_HANDLER_OF_LINK(DATA_PATH_GROUP, OMI_SEND_STATUS_NOTIF, - omi_status_notif) + RX_HANDLER_OF_LINK(DATA_PATH_GROUP, BEACON_FILTER_IN_NOTIF, + beacon_filter_notif) RX_HANDLER_OF_FTM_REQ(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF, ftm_resp_notif) }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/phy.c b/drivers/net/wireless/intel/iwlwifi/mld/phy.c index d5a32ee56b92..1d93fb9e4dbf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/phy.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/phy.c @@ -181,7 +181,7 @@ int iwl_mld_send_phy_cfg_cmd(struct iwl_mld *mld) .phy_specific_cfg = mld->fwrt.phy_filters, }; - IWL_INFO(mld, "Sending Phy CFG command: 0x%x\n", cmd.phy_cfg); + IWL_DEBUG_INFO(mld, "Sending Phy CFG command: 0x%x\n", cmd.phy_cfg); return iwl_mld_send_cmd_pdu(mld, PHY_CONFIGURATION_CMD, &cmd); } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/power.c b/drivers/net/wireless/intel/iwlwifi/mld/power.c index 8cc276041360..f664b277adf7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/power.c @@ -377,23 +377,15 @@ int iwl_mld_set_tx_power(struct iwl_mld *mld, u16 u_tx_power = tx_power == IWL_DEFAULT_MAX_TX_POWER ? IWL_DEV_MAX_TX_POWER : 8 * tx_power; struct iwl_dev_tx_power_cmd cmd = { - /* Those fields sit on the same place for v9 and v10 */ .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK), .common.pwr_restriction = cpu_to_le16(u_tx_power), }; - u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, - IWL_FW_CMD_VER_UNKNOWN); - int len = sizeof(cmd.common); + int len = sizeof(cmd.common) + sizeof(cmd.v10); if (WARN_ON(!mld_link)) return -ENODEV; cmd.common.link_id = cpu_to_le32(mld_link->fw_id); - if (cmd_ver == 10) - len += sizeof(cmd.v10); - else if (cmd_ver == 9) - len += sizeof(cmd.v9); - return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, len); } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c index 5ee38fc168c1..ffeb37a7f830 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c @@ -299,18 +299,18 @@ void iwl_mld_ptp_init(struct iwl_mld *mld) PTR_ERR(mld->ptp_data.ptp_clock)); mld->ptp_data.ptp_clock = NULL; } else { - IWL_INFO(mld, "Registered PHC clock: %s, with index: %d\n", - mld->ptp_data.ptp_clock_info.name, - ptp_clock_index(mld->ptp_data.ptp_clock)); + IWL_DEBUG_INFO(mld, "Registered PHC clock: %s, with index: %d\n", + mld->ptp_data.ptp_clock_info.name, + ptp_clock_index(mld->ptp_data.ptp_clock)); } } void iwl_mld_ptp_remove(struct iwl_mld *mld) { if (mld->ptp_data.ptp_clock) { - IWL_INFO(mld, "Unregistering PHC clock: %s, with index: %d\n", - mld->ptp_data.ptp_clock_info.name, - ptp_clock_index(mld->ptp_data.ptp_clock)); + IWL_DEBUG_INFO(mld, "Unregistering PHC clock: %s, with index: %d\n", + mld->ptp_data.ptp_clock_info.name, + ptp_clock_index(mld->ptp_data.ptp_clock)); ptp_clock_unregister(mld->ptp_data.ptp_clock); mld->ptp_data.ptp_clock = NULL; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index 436219d1ec5e..75d2f5cb23a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c @@ -71,40 +71,17 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld) static int iwl_mld_geo_sar_init(struct iwl_mld *mld) { u32 cmd_id = WIDE_ID(PHY_OPS_GROUP, PER_CHAIN_LIMIT_OFFSET_CMD); - union iwl_geo_tx_power_profiles_cmd cmd; - u16 len; - u32 n_bands; - __le32 sk = cpu_to_le32(0); - int ret; - u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, - IWL_FW_CMD_VER_UNKNOWN); - - BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, ops) != - offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, ops)); - - cmd.v4.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES); - /* Only set to South Korea if the table revision is 1 */ - if (mld->fwrt.geo_rev == 1) - sk = cpu_to_le32(1); - - if (cmd_ver == 5) { - len = sizeof(cmd.v5); - n_bands = ARRAY_SIZE(cmd.v5.table[0]); - cmd.v5.table_revision = sk; - } else if (cmd_ver == 4) { - len = sizeof(cmd.v4); - n_bands = ARRAY_SIZE(cmd.v4.table[0]); - cmd.v4.table_revision = sk; - } else { - return -EOPNOTSUPP; - } + __le32 sk = cpu_to_le32(mld->fwrt.geo_rev == 1 ? 1 : 0); + union iwl_geo_tx_power_profiles_cmd cmd = { + .v5.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES), + .v5.table_revision = sk, + }; + int ret; - BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) != - offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, table)); - /* the table is at the same position for all versions, so set use v4 */ - ret = iwl_sar_geo_fill_table(&mld->fwrt, &cmd.v4.table[0][0], - n_bands, BIOS_GEO_MAX_PROFILE_NUM); + ret = iwl_sar_geo_fill_table(&mld->fwrt, &cmd.v5.table[0][0], + ARRAY_SIZE(cmd.v5.table[0]), + BIOS_GEO_MAX_PROFILE_NUM); /* It is a valid scenario to not support SAR, or miss wgds table, * but in that case there is no need to send the command. @@ -112,7 +89,7 @@ static int iwl_mld_geo_sar_init(struct iwl_mld *mld) if (ret) return 0; - return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, len); + return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, sizeof(cmd.v5)); } int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b) @@ -120,37 +97,20 @@ int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b) u32 cmd_id = REDUCE_TX_POWER_CMD; struct iwl_dev_tx_power_cmd cmd = { .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), + .v10.flags = cpu_to_le32(mld->fwrt.reduced_power_flags), }; - __le16 *per_chain; int ret; - u16 len = sizeof(cmd.common); - u32 n_subbands; - u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, - IWL_FW_CMD_VER_UNKNOWN); - - if (cmd_ver == 10) { - len += sizeof(cmd.v10); - n_subbands = IWL_NUM_SUB_BANDS_V2; - per_chain = &cmd.v10.per_chain[0][0][0]; - cmd.v10.flags = - cpu_to_le32(mld->fwrt.reduced_power_flags); - } else if (cmd_ver == 9) { - len += sizeof(cmd.v9); - n_subbands = IWL_NUM_SUB_BANDS_V1; - per_chain = &cmd.v9.per_chain[0][0]; - } else { - return -EOPNOTSUPP; - } /* TODO: CDB - support IWL_NUM_CHAIN_TABLES_V2 */ - ret = iwl_sar_fill_profile(&mld->fwrt, per_chain, - IWL_NUM_CHAIN_TABLES, - n_subbands, prof_a, prof_b); + ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v10.per_chain[0][0][0], + IWL_NUM_CHAIN_TABLES, IWL_NUM_SUB_BANDS_V2, + prof_a, prof_b); /* return on error or if the profile is disabled (positive number) */ if (ret) return ret; - return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, len); + return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, + sizeof(cmd.common) + sizeof(cmd.v10)); } int iwl_mld_init_sar(struct iwl_mld *mld) @@ -238,21 +198,29 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) struct iwl_lari_config_change_cmd cmd = { .config_bitmap = iwl_get_lari_config_bitmap(fwrt), }; + bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE); int ret; u32 value; ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); - if (!ret) + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_11AX_ALLOW_BITMAP; cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); + } ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); - if (!ret) - cmd.oem_unii4_allow_bitmap = - cpu_to_le32(value &= DSM_UNII4_ALLOW_BITMAP); + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_UNII4_ALLOW_BITMAP; + cmd.oem_unii4_allow_bitmap = cpu_to_le32(value); + } ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); if (!ret) { - value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; + if (!has_raw_dsm_capa) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; cmd.chan_state_active_bitmap = cpu_to_le32(value); } @@ -261,13 +229,19 @@ void iwl_mld_configure_lari(struct iwl_mld *mld) cmd.oem_uhb_allow_bitmap = cpu_to_le32(value); ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); - if (!ret) + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP; cmd.force_disable_channels_bitmap = cpu_to_le32(value); + } ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, &value); - if (!ret) + if (!ret) { + if (!has_raw_dsm_capa) + value &= DSM_EDT_ALLOWED_BITMAP; cmd.edt_bitmap = cpu_to_le32(value); + } ret = iwl_bios_get_wbem(fwrt, &value); if (!ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index ce0093d5c638..b6dedd1ecd4d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -143,7 +143,55 @@ void iwl_mld_pass_packet_to_mac80211(struct iwl_mld *mld, } EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_pass_packet_to_mac80211); -static void iwl_mld_fill_signal(struct iwl_mld *mld, +static bool iwl_mld_used_average_energy(struct iwl_mld *mld, int link_id, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_bss_conf *link_conf; + struct iwl_mld_link *mld_link; + + if (unlikely(!hdr || link_id < 0)) + return false; + + if (likely(!ieee80211_is_beacon(hdr->frame_control))) + return false; + + /* + * if link ID is >= valid ones then that means the RX + * was on the AUX link and no correction is needed + */ + if (link_id >= mld->fw->ucode_capa.num_links) + return false; + + /* for the link conf lookup */ + guard(rcu)(); + + link_conf = rcu_dereference(mld->fw_id_to_bss_conf[link_id]); + if (!link_conf) + return false; + + mld_link = iwl_mld_link_from_mac80211(link_conf); + if (!mld_link) + return false; + + /* + * If we know the link by link ID then the frame was + * received for the link, so by filtering it means it + * was from the AP the link is connected to. + */ + + /* skip also in case we don't have it (yet) */ + if (!mld_link->average_beacon_energy) + return false; + + IWL_DEBUG_STATS(mld, "energy override by average %d\n", + mld_link->average_beacon_energy); + rx_status->signal = -mld_link->average_beacon_energy; + return true; +} + +static void iwl_mld_fill_signal(struct iwl_mld *mld, int link_id, + struct ieee80211_hdr *hdr, struct ieee80211_rx_status *rx_status, struct iwl_mld_rx_phy_data *phy_data) { @@ -159,9 +207,11 @@ static void iwl_mld_fill_signal(struct iwl_mld *mld, IWL_DEBUG_STATS(mld, "energy in A %d B %d, and max %d\n", energy_a, energy_b, max_energy); + if (iwl_mld_used_average_energy(mld, link_id, hdr, rx_status)) + return; + rx_status->signal = max_energy; - rx_status->chains = - (rate_n_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS; + rx_status->chains = u32_get_bits(rate_n_flags, RATE_MCS_ANT_AB_MSK); rx_status->chain_signal[0] = energy_a; rx_status->chain_signal[1] = energy_b; } @@ -1039,6 +1089,15 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; } + /* update aggregation data for monitor sake on default queue */ + if (!queue && (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) && + (phy_info & IWL_RX_MPDU_PHY_AMPDU) && phy_data->first_subframe) { + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT_KNOWN; + if (phy_data->data0 & + cpu_to_le32(IWL_RX_PHY_DATA0_EHT_DELIM_EOF)) + rx_status->flag |= RX_FLAG_AMPDU_EOF_BIT; + } + if (phy_info & IWL_RX_MPDU_PHY_TSF_OVERLOAD) iwl_mld_decode_eht_phy_data(mld, phy_data, rx_status, eht, usig); @@ -1160,7 +1219,10 @@ static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, } #endif -static void iwl_mld_rx_fill_status(struct iwl_mld *mld, struct sk_buff *skb, +/* Note: hdr can be NULL */ +static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, + struct ieee80211_hdr *hdr, + struct sk_buff *skb, struct iwl_mld_rx_phy_data *phy_data, int queue) { @@ -1182,7 +1244,7 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, struct sk_buff *skb, phy_data->phy_info & IWL_RX_MPDU_PHY_SHORT_PREAMBLE) rx_status->enc_flags |= RX_ENC_FLAG_SHORTPRE; - iwl_mld_fill_signal(mld, rx_status, phy_data); + iwl_mld_fill_signal(mld, link_id, hdr, rx_status, phy_data); /* This may be overridden by iwl_mld_rx_he() to HE_RU */ switch (rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK) { @@ -1733,7 +1795,7 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, struct sk_buff *skb; size_t mpdu_desc_size = sizeof(*mpdu_desc); bool drop = false; - u8 crypto_len = 0, band; + u8 crypto_len = 0, band, link_id; u32 pkt_len = iwl_rx_packet_payload_len(pkt); u32 mpdu_len; enum iwl_mld_reorder_result reorder_res; @@ -1822,7 +1884,10 @@ void iwl_mld_rx_mpdu(struct iwl_mld *mld, struct napi_struct *napi, SCHED_SCAN_PASS_ALL_STATE_FOUND; } - iwl_mld_rx_fill_status(mld, skb, &phy_data, queue); + link_id = u8_get_bits(mpdu_desc->mac_phy_band, + IWL_RX_MPDU_MAC_PHY_BAND_LINK_MASK); + + iwl_mld_rx_fill_status(mld, link_id, hdr, skb, &phy_data, queue); if (iwl_mld_rx_crypto(mld, sta, hdr, rx_status, mpdu_desc, queue, le32_to_cpu(pkt->len_n_flags), &crypto_len)) @@ -2035,7 +2100,8 @@ void iwl_mld_rx_monitor_no_data(struct iwl_mld *mld, struct napi_struct *napi, rx_status->freq = ieee80211_channel_to_frequency(channel, rx_status->band); - iwl_mld_rx_fill_status(mld, skb, &phy_data, queue); + /* link ID is ignored for NULL header */ + iwl_mld_rx_fill_status(mld, -1, NULL, skb, &phy_data, queue); /* No more radiotap info should be added after this point. * Mark it as mac header for upper layers to know where diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c index 3fce7cd2d512..62f97a18a16c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c @@ -4,6 +4,8 @@ */ #include <linux/crc32.h> +#include "iwl-utils.h" + #include "mld.h" #include "scan.h" #include "hcmd.h" @@ -359,7 +361,7 @@ iwl_mld_scan_fits(struct iwl_mld *mld, int n_ssids, struct ieee80211_scan_ies *ies, int n_channels) { return ((n_ssids <= PROBE_OPTION_MAX) && - (n_channels <= mld->fw->ucode_capa.n_scan_channels) & + (n_channels <= mld->fw->ucode_capa.n_scan_channels) && (ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] + ies->len[NL80211_BAND_5GHZ] + ies->len[NL80211_BAND_6GHZ] <= iwl_mld_scan_max_template_size())); @@ -482,7 +484,9 @@ iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld, static u8 iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld, struct iwl_mld_scan_params *params, - struct ieee80211_vif *vif, u16 gen_flags) + struct ieee80211_vif *vif, + enum iwl_mld_scan_status scan_status, + u16 gen_flags) { u8 flags = 0; @@ -494,6 +498,17 @@ iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld, if (params->scan_6ghz) flags |= IWL_UMAC_SCAN_GEN_PARAMS_FLAGS2_DONT_TOGGLE_ANT; + /* For AP interfaces, request survey data for regular scans and if + * it is supported. For non-AP interfaces, EBS will be enabled and + * the results may be missing information for some channels. + */ + if (scan_status == IWL_MLD_SCAN_REGULAR && + ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_AP && + gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE && + iwl_fw_lookup_notif_ver(mld->fw, SCAN_GROUP, + CHANNEL_SURVEY_NOTIF, 0) >= 1) + flags |= IWL_UMAC_SCAN_GEN_FLAGS2_COLLECT_CHANNEL_STATS; + return flags; } @@ -544,6 +559,7 @@ iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld, u16 gen_flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif, scan_status); u8 gen_flags2 = iwl_mld_scan_get_cmd_gen_flags2(mld, params, vif, + scan_status, gen_flags); IWL_DEBUG_SCAN(mld, "General: flags=0x%x, flags2=0x%x\n", @@ -1752,6 +1768,15 @@ int iwl_mld_regular_scan_start(struct iwl_mld *mld, struct ieee80211_vif *vif, struct cfg80211_scan_request *req, struct ieee80211_scan_ies *ies) { + /* Clear survey data when starting the first part of a regular scan */ + if (req->first_part && mld->channel_survey) + memset(mld->channel_survey->channels, 0, + sizeof(mld->channel_survey->channels[0]) * + mld->channel_survey->n_channels); + + if (vif->type == NL80211_IFTYPE_P2P_DEVICE) + iwl_mld_emlsr_block_tmp_non_bss(mld); + return _iwl_mld_single_scan_start(mld, vif, req, ies, IWL_MLD_SCAN_REGULAR); } @@ -1800,17 +1825,20 @@ static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld, IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret); } +#define IWL_MLD_MLO_SCAN_BLOCKOUT_TIME 5 /* seconds */ + void iwl_mld_int_mlo_scan(struct iwl_mld *mld, struct ieee80211_vif *vif) { struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS]; + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); unsigned long usable_links = ieee80211_vif_usable_links(vif); size_t n_channels = 0; u8 link_id; lockdep_assert_wiphy(mld->wiphy); - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) || - hweight16(vif->valid_links) == 1) + if (!IWL_MLD_AUTO_EML_ENABLE || !vif->cfg.assoc || + !ieee80211_vif_is_mld(vif) || hweight16(vif->valid_links) == 1) return; if (mld->scan.status & IWL_MLD_SCAN_INT_MLO) { @@ -1818,6 +1846,15 @@ void iwl_mld_int_mlo_scan(struct iwl_mld *mld, struct ieee80211_vif *vif) return; } + if (mld_vif->last_link_activation_time > ktime_get_boottime_seconds() - + IWL_MLD_MLO_SCAN_BLOCKOUT_TIME) { + /* timing doesn't matter much, so use the blockout time */ + wiphy_delayed_work_queue(mld->wiphy, + &mld_vif->mlo_scan_start_wk, + IWL_MLD_MLO_SCAN_BLOCKOUT_TIME); + return; + } + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct ieee80211_bss_conf *link_conf = link_conf_dereference_check(vif, link_id); @@ -2009,3 +2046,136 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld) return 0; } + +static int iwl_mld_chanidx_from_phy(struct iwl_mld *mld, + enum nl80211_band band, + u16 phy_chan_num) +{ + struct ieee80211_supported_band *sband = mld->wiphy->bands[band]; + + if (WARN_ON_ONCE(!sband)) + return -EINVAL; + + for (int chan_idx = 0; chan_idx < sband->n_channels; chan_idx++) { + struct ieee80211_channel *channel = &sband->channels[chan_idx]; + + if (channel->hw_value == phy_chan_num) + return chan_idx; + } + + return -EINVAL; +} + +void iwl_mld_handle_channel_survey_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt) +{ + const struct iwl_umac_scan_channel_survey_notif *notif = + (void *)pkt->data; + struct iwl_mld_survey_channel *info; + enum nl80211_band band; + int chan_idx; + + if (!mld->channel_survey) { + size_t n_channels = 0; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!mld->wiphy->bands[band]) + continue; + + n_channels += mld->wiphy->bands[band]->n_channels; + } + + mld->channel_survey = kzalloc(struct_size(mld->channel_survey, + channels, n_channels), + GFP_KERNEL); + + if (!mld->channel_survey) + return; + + mld->channel_survey->n_channels = n_channels; + n_channels = 0; + for (band = 0; band < NUM_NL80211_BANDS; band++) { + if (!mld->wiphy->bands[band]) + continue; + + mld->channel_survey->bands[band] = + &mld->channel_survey->channels[n_channels]; + n_channels += mld->wiphy->bands[band]->n_channels; + } + } + + band = iwl_mld_phy_band_to_nl80211(le32_to_cpu(notif->band)); + chan_idx = iwl_mld_chanidx_from_phy(mld, band, + le32_to_cpu(notif->channel)); + if (WARN_ON_ONCE(chan_idx < 0)) + return; + + IWL_DEBUG_SCAN(mld, "channel survey received for freq %d\n", + mld->wiphy->bands[band]->channels[chan_idx].center_freq); + + info = &mld->channel_survey->bands[band][chan_idx]; + + /* Times are all in ms */ + info->time = le32_to_cpu(notif->active_time); + info->time_busy = le32_to_cpu(notif->busy_time); + info->noise = + iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise)); +} + +int iwl_mld_mac80211_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw); + int curr_idx = 0; + + if (!mld->channel_survey) + return -ENOENT; + + /* Iterate bands/channels to find the requested index. + * Logically this returns the entry with index "idx" from a flattened + * survey result array that only contains channels with information. + * The current index into this flattened array is tracked in curr_idx. + */ + for (enum nl80211_band band = 0; band < NUM_NL80211_BANDS; band++) { + struct ieee80211_supported_band *sband = + mld->wiphy->bands[band]; + + if (!sband) + continue; + + for (int per_band_idx = 0; + per_band_idx < sband->n_channels; + per_band_idx++) { + struct iwl_mld_survey_channel *info = + &mld->channel_survey->bands[band][per_band_idx]; + + /* Skip entry entirely, it was not reported/scanned, + * do not increase curr_idx for this entry. + */ + if (!info->time) + continue; + + /* Search did not reach the requested entry yet, + * increment curr_idx and continue. + */ + if (idx != curr_idx) { + curr_idx++; + continue; + } + + /* Found (the next) channel to report */ + survey->channel = &sband->channels[per_band_idx]; + survey->filled = SURVEY_INFO_TIME | + SURVEY_INFO_TIME_BUSY; + survey->time = info->time; + survey->time_busy = info->time_busy; + survey->noise = info->noise; + if (survey->noise < 0) + survey->filled |= SURVEY_INFO_NOISE_DBM; + + return 0; + } + } + + return -ENOENT; +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h index 3ae940d55065..69110f0cfc8e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h @@ -30,6 +30,12 @@ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld, void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt); +int iwl_mld_mac80211_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey); + +void iwl_mld_handle_channel_survey_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt); + #define WFA_TPC_IE_LEN 9 static inline int iwl_mld_scan_max_template_size(void) @@ -130,7 +136,38 @@ struct iwl_mld_scan { void *cmd; unsigned long last_6ghz_passive_jiffies; unsigned long last_start_time_jiffies; - unsigned long last_mlo_scan_time; + u64 last_mlo_scan_time; +}; + +/** + * struct iwl_mld_survey_channel - per-channel survey information + * + * Driver version of &struct survey_info with just the data we want to report. + * + * @time: time in ms the radio was on the channel + * @time_busy: time in ms the channel was sensed busy + * @noise: channel noise in dBm + */ +struct iwl_mld_survey_channel { + u32 time; + u32 time_busy; + s8 noise; +}; + +/** + * struct iwl_mld_survey - survey information + * + * Survey information for all available channels. + * + * @bands: per-band array for per-channel survey data, points into @channels + * @n_channels: Number of @channels entries that are allocated + * @channels: per-channel information + */ +struct iwl_mld_survey { + struct iwl_mld_survey_channel *bands[NUM_NL80211_BANDS]; + + int n_channels; + struct iwl_mld_survey_channel channels[] __counted_by(n_channels); }; #endif /* __iwl_mld_scan_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/stats.c b/drivers/net/wireless/intel/iwlwifi/mld/stats.c index f633cb1cf510..cbc64db5eab6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/stats.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/stats.c @@ -508,8 +508,6 @@ void iwl_mld_handle_stats_oper_notif(struct iwl_mld *mld, iwl_mld_process_per_link_stats(mld, stats->per_link, curr_ts_usec); iwl_mld_process_per_sta_stats(mld, stats->per_sta); iwl_mld_process_per_phy_stats(mld, stats->per_phy); - - iwl_mld_check_omi_bw_reduction(mld); } void iwl_mld_handle_stats_oper_part1_notif(struct iwl_mld *mld, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/Makefile b/drivers/net/wireless/intel/iwlwifi/mld/tests/Makefile index 3e2ae6020613..36317feb923b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tests/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -iwlmld-tests-y += module.o hcmd.o utils.o link.o rx.o agg.o link-selection.o emlsr_with_bt.o +iwlmld-tests-y += module.o hcmd.o utils.o link.o rx.o agg.o link-selection.o ccflags-y += -I$(src)/../ obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += iwlmld-tests.o diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/emlsr_with_bt.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/emlsr_with_bt.c deleted file mode 100644 index 91556ee5c142..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/mld/tests/emlsr_with_bt.c +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* - * KUnit tests for link selection functions - * - * Copyright (C) 2025 Intel Corporation - */ -#include <kunit/static_stub.h> - -#include "utils.h" -#include "mld.h" -#include "mlo.h" - -static const struct emlsr_with_bt_test_case { - const char *desc; - struct { - struct iwl_bt_coex_profile_notif notif; - s32 signal; - bool check_entry; - } input; - bool emlsr_allowed; -} emlsr_with_bt_cases[] = { - { - .desc = "BT penalty(exit) with low rssi 4.5: emlsr allowed", - .input = { - .notif.wifi_loss_low_rssi[1] = {4, 5}, - .notif.wifi_loss_mid_high_rssi[1] = {7, 9}, - .signal = -69, - .check_entry = false, - }, - .emlsr_allowed = true, - }, - { - .desc = "BT penalty(exit) from high rssi 5: emlsr allowed", - .input = { - .notif.wifi_loss_low_rssi[1] = {7, 9}, - .notif.wifi_loss_mid_high_rssi[1] = {5, 5}, - .signal = -68, - .check_entry = false, - }, - .emlsr_allowed = true, - }, - { - .desc = "BT penalty(exit) with low rssi 8: emlsr not allowed", - .input = { - .notif.wifi_loss_low_rssi[1] = {7, 9}, - .notif.wifi_loss_mid_high_rssi[1] = {4, 5}, - .signal = -69, - .check_entry = false, - }, - .emlsr_allowed = false, - }, - { - .desc = "BT penalty(exit) from high rssi 9: emlsr not allowed", - .input = { - .notif.wifi_loss_low_rssi[1] = {4, 5}, - .notif.wifi_loss_mid_high_rssi[1] = {9, 9}, - .signal = -68, - .check_entry = false, - }, - .emlsr_allowed = false, - }, - { - .desc = "BT penalty(entry) with low rssi 4.5: emlsr allowed", - .input = { - .notif.wifi_loss_low_rssi[1] = {4, 5}, - .notif.wifi_loss_mid_high_rssi[1] = {7, 9}, - .signal = -63, - .check_entry = true, - }, - .emlsr_allowed = true, - }, - { - .desc = "BT penalty(entry) from high rssi 5: emlsr allowed", - .input = { - .notif.wifi_loss_low_rssi[1] = {7, 9}, - .notif.wifi_loss_mid_high_rssi[1] = {5, 5}, - .signal = -62, - .check_entry = false, - }, - .emlsr_allowed = true, - }, - { - .desc = "BT penalty(entry) with low rssi 8: emlsr not allowed", - .input = { - .notif.wifi_loss_low_rssi[1] = {7, 9}, - .notif.wifi_loss_mid_high_rssi[1] = {4, 5}, - .signal = -63, - .check_entry = false, - }, - .emlsr_allowed = true, - }, - { - .desc = "BT penalty(entry) from high rssi 9: emlsr not allowed", - .input = { - .notif.wifi_loss_low_rssi[1] = {4, 5}, - .notif.wifi_loss_mid_high_rssi[1] = {9, 9}, - .signal = -62, - .check_entry = true, - }, - .emlsr_allowed = false, - }, -}; - -KUNIT_ARRAY_PARAM_DESC(emlsr_with_bt, emlsr_with_bt_cases, desc); - -static void test_emlsr_with_bt(struct kunit *test) -{ - struct iwl_mld *mld = test->priv; - const struct emlsr_with_bt_test_case *test_param = - (const void *)(test->param_value); - struct ieee80211_vif *vif = - iwlmld_kunit_add_vif(true, NL80211_IFTYPE_STATION); - struct ieee80211_bss_conf *link = iwlmld_kunit_add_link(vif, 1); - bool actual_value = false; - - KUNIT_ALLOC_AND_ASSERT(test, link->bss); - - /* Extract test case parameters */ - link->bss->signal = DBM_TO_MBM(test_param->input.signal); - memcpy(&mld->last_bt_notif, &test_param->input.notif, - sizeof(struct iwl_bt_coex_profile_notif)); - - actual_value = iwl_mld_bt_allows_emlsr(mld, link, - test_param->input.check_entry); - /* Assert that the returned value matches the expected emlsr_allowed */ - KUNIT_EXPECT_EQ(test, actual_value, test_param->emlsr_allowed); -} - -static struct kunit_case emlsr_with_bt_test_cases[] = { - KUNIT_CASE_PARAM(test_emlsr_with_bt, emlsr_with_bt_gen_params), - {}, -}; - -static struct kunit_suite emlsr_with_bt = { - .name = "iwlmld-emlsr-with-bt-tests", - .test_cases = emlsr_with_bt_test_cases, - .init = iwlmld_kunit_test_init, -}; - -kunit_test_suite(emlsr_with_bt); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c index 94a037bec1fa..766c24db3613 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c @@ -287,7 +287,6 @@ static void test_iwl_mld_link_pair_allows_emlsr(struct kunit *test) const struct link_pair_case *params = test->param_value; struct iwl_mld *mld = test->priv; struct ieee80211_vif *vif; - struct ieee80211_bss_conf *link; /* link A is the primary and link B is the secondary */ struct iwl_mld_link_sel_data a = { .chandef = params->chandef_a, @@ -311,11 +310,6 @@ static void test_iwl_mld_link_pair_allows_emlsr(struct kunit *test) wiphy_lock(mld->wiphy); - link = wiphy_dereference(mld->wiphy, vif->link_conf[a.link_id]); - KUNIT_ALLOC_AND_ASSERT(test, link->bss); - link = wiphy_dereference(mld->wiphy, vif->link_conf[b.link_id]); - KUNIT_ALLOC_AND_ASSERT(test, link->bss); - /* Simulate channel load */ if (params->primary_link_active) { struct iwl_mld_phy *phy = diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 507c03198c92..029c846a236f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -120,19 +120,17 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */ - struct { - struct iwl_mvm_wep_key_cmd wep_key_cmd; - struct iwl_mvm_wep_key wep_key; - } __packed wkc = { - .wep_key_cmd.mac_id_n_color = - cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, - mvmvif->color)), - .wep_key_cmd.num_keys = 1, - /* firmware sets STA_KEY_FLG_WEP_13BYTES */ - .wep_key_cmd.decryption_type = STA_KEY_FLG_WEP, - .wep_key.key_index = key->keyidx, - .wep_key.key_size = key->keylen, - }; + DEFINE_RAW_FLEX(struct iwl_mvm_wep_key_cmd, wkc, wep_key, 1); + struct iwl_mvm_wep_key *wep_key = wkc->wep_key; + + wkc->mac_id_n_color = + cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, + mvmvif->color)); + wkc->num_keys = 1; + /* firmware sets STA_KEY_FLG_WEP_13BYTES */ + wkc->decryption_type = STA_KEY_FLG_WEP; + wep_key->key_index = key->keyidx; + wep_key->key_size = key->keylen; /* * This will fail -- the key functions don't set support @@ -142,18 +140,19 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) break; - memcpy(&wkc.wep_key.key[3], key->key, key->keylen); + memcpy(&wep_key->key[3], key->key, key->keylen); if (key->keyidx == mvmvif->tx_key_idx) { /* TX key must be at offset 0 */ - wkc.wep_key.key_offset = 0; + wep_key->key_offset = 0; } else { /* others start at 1 */ data->wep_key_idx++; - wkc.wep_key.key_offset = data->wep_key_idx; + wep_key->key_offset = data->wep_key_idx; } mutex_lock(&mvm->mutex); - ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, sizeof(wkc), &wkc); + ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, + __struct_size(wkc), wkc); data->error = ret != 0; mvm->ptk_ivlen = key->iv_len; @@ -212,7 +211,7 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw, } struct wowlan_key_rsc_tsc_data { - struct iwl_wowlan_rsc_tsc_params_cmd_v4 *rsc_tsc; + struct iwl_wowlan_rsc_tsc_params_cmd_ver_2 *rsc_tsc; bool have_rsc_tsc; }; @@ -237,21 +236,21 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw, u64 pn64; tkip_sc = - data->rsc_tsc->params.all_tsc_rsc.tkip.unicast_rsc; + data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc; tkip_tx_sc = - &data->rsc_tsc->params.all_tsc_rsc.tkip.tsc; + &data->rsc_tsc->all_tsc_rsc.tkip.tsc; pn64 = atomic64_read(&key->tx_pn); tkip_tx_sc->iv16 = cpu_to_le16(TKIP_PN_TO_IV16(pn64)); tkip_tx_sc->iv32 = cpu_to_le32(TKIP_PN_TO_IV32(pn64)); } else { tkip_sc = - data->rsc_tsc->params.all_tsc_rsc.tkip.multicast_rsc; + data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc; } /* * For non-QoS this relies on the fact that both the uCode and - * mac80211 use TID 0 (as they need to to avoid replay attacks) + * mac80211 use TID 0 (as they need to avoid replay attacks) * for checking the IV in the frames. */ for (i = 0; i < IWL_NUM_RSC; i++) { @@ -270,15 +269,15 @@ static void iwl_mvm_wowlan_get_rsc_tsc_data(struct ieee80211_hw *hw, u64 pn64; aes_sc = - data->rsc_tsc->params.all_tsc_rsc.aes.unicast_rsc; + data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc; aes_tx_sc = - &data->rsc_tsc->params.all_tsc_rsc.aes.tsc; + &data->rsc_tsc->all_tsc_rsc.aes.tsc; pn64 = atomic64_read(&key->tx_pn); aes_tx_sc->pn = cpu_to_le64(pn64); } else { aes_sc = - data->rsc_tsc->params.all_tsc_rsc.aes.multicast_rsc; + data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc; } /* @@ -387,7 +386,7 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw, /* * For non-QoS this relies on the fact that both the uCode and - * mac80211 use TID 0 (as they need to to avoid replay attacks) + * mac80211 use TID 0 (as they need to avoid replay attacks) * for checking the IV in the frames. */ for (i = 0; i < IWL_MAX_TID_COUNT; i++) { @@ -481,30 +480,21 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, else ret = 0; kfree(data.rsc); - } else if (ver == 4 || ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { + } else if (ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN) { struct wowlan_key_rsc_tsc_data data = {}; - int size; data.rsc_tsc = kzalloc(sizeof(*data.rsc_tsc), GFP_KERNEL); if (!data.rsc_tsc) return -ENOMEM; - if (ver == 4) { - size = sizeof(*data.rsc_tsc); - data.rsc_tsc->sta_id = - cpu_to_le32(mvm_link->ap_sta_id); - } else { - /* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */ - size = sizeof(data.rsc_tsc->params); - } - ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_rsc_tsc_data, &data); if (data.have_rsc_tsc) ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_TSC_RSC_PARAM, - CMD_ASYNC, size, + CMD_ASYNC, + sizeof(*data.rsc_tsc), data.rsc_tsc); else ret = 0; @@ -1475,9 +1465,6 @@ struct iwl_wowlan_status_data { struct iwl_multicast_key_data igtk; struct iwl_multicast_key_data bigtk[WOWLAN_BIGTK_KEYS_NUM]; - int num_mlo_keys; - struct iwl_wowlan_mlo_gtk mlo_keys[WOWLAN_MAX_MLO_KEYS]; - u8 *wake_packet; }; @@ -1693,7 +1680,7 @@ static void iwl_mvm_set_aes_ptk_rx_seq(struct iwl_mvm *mvm, } static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, - union iwl_all_tsc_rsc *sc) + union iwl_all_tsc_rsc *sc, u8 key_idx) { int i; @@ -1708,7 +1695,7 @@ static void iwl_mvm_convert_key_counters(struct iwl_wowlan_status_data *status, &status->gtk_seq[0].aes.seq[i]); } status->gtk_seq[0].valid = true; - status->gtk_seq[0].key_id = -1; + status->gtk_seq[0].key_id = key_idx; /* PTK TX counter */ status->ptk.tkip.tx_pn = (u64)le16_to_cpu(sc->tkip.tsc.iv16) | @@ -1791,8 +1778,7 @@ static void iwl_mvm_set_key_rx_seq_idx(struct ieee80211_key_conf *key, } static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, - struct iwl_wowlan_status_data *status, - bool installed) + struct iwl_wowlan_status_data *status) { int i; @@ -1800,23 +1786,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, if (!status->gtk_seq[i].valid) continue; - /* Handle the case where we know the key ID */ - if (status->gtk_seq[i].key_id == key->keyidx) { - s8 new_key_id = -1; - - if (status->num_of_gtk_rekeys) - new_key_id = status->gtk[0].flags & - IWL_WOWLAN_GTK_IDX_MASK; - - /* Don't install a new key's value to an old key */ - if (new_key_id != key->keyidx) - iwl_mvm_set_key_rx_seq_idx(key, status, i); - continue; - } - - /* handle the case where we didn't, last key only */ - if (status->gtk_seq[i].key_id == -1 && - (!status->num_of_gtk_rekeys || installed)) + if (status->gtk_seq[i].key_id == key->keyidx) iwl_mvm_set_key_rx_seq_idx(key, status, i); } } @@ -1906,17 +1876,10 @@ iwl_mvm_d3_update_igtk_bigtk(struct iwl_wowlan_status_data *status, struct ieee80211_key_conf *key, struct iwl_multicast_key_data *key_data) { - if (status->num_of_gtk_rekeys && key_data->len) { - /* remove rekeyed key */ - ieee80211_remove_key(key); - } else { - struct ieee80211_key_seq seq; + struct ieee80211_key_seq seq; - iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, - &seq, - key->cipher); - ieee80211_set_key_rx_seq(key, 0, &seq); - } + iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, key->cipher); + ieee80211_set_key_rx_seq(key, 0, &seq); } static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, @@ -1957,18 +1920,13 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, return; } keyidx = key->keyidx; - /* The current key is always sent by the FW, even if it wasn't - * rekeyed during D3. - * We remove an existing key if it has the same index as - * a new key + /* + * Update the seq even if there was a rekey. If there was a + * rekey, we will update again after replacing the key */ - if (status->num_of_gtk_rekeys && - ((status->gtk[0].len && keyidx == status->gtk[0].id) || - (status->gtk[1].len && keyidx == status->gtk[1].id))) { - ieee80211_remove_key(key); - } else { - iwl_mvm_set_key_rx_seq(key, data->status, false); - } + if ((status->gtk[0].len && keyidx == status->gtk[0].id) || + (status->gtk[1].len && keyidx == status->gtk[1].id)) + iwl_mvm_set_key_rx_seq(key, status); break; case WLAN_CIPHER_SUITE_BIP_GMAC_128: case WLAN_CIPHER_SUITE_BIP_GMAC_256: @@ -1987,199 +1945,35 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, } } -struct iwl_mvm_d3_mlo_old_keys { - u32 cipher[IEEE80211_MLD_MAX_NUM_LINKS][WOWLAN_MLO_GTK_KEY_NUM_TYPES]; - struct ieee80211_key_conf *key[IEEE80211_MLD_MAX_NUM_LINKS][8]; -}; - -static void iwl_mvm_mlo_key_ciphers(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - void *data) -{ - struct iwl_mvm_d3_mlo_old_keys *old_keys = data; - enum iwl_wowlan_mlo_gtk_type key_type; - - if (key->link_id < 0) - return; - - if (WARN_ON(key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS || - key->keyidx >= 8)) - return; - - if (WARN_ON(old_keys->key[key->link_id][key->keyidx])) - return; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - key_type = WOWLAN_MLO_GTK_KEY_TYPE_GTK; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - case WLAN_CIPHER_SUITE_AES_CMAC: - if (key->keyidx == 4 || key->keyidx == 5) { - key_type = WOWLAN_MLO_GTK_KEY_TYPE_IGTK; - break; - } else if (key->keyidx == 6 || key->keyidx == 7) { - key_type = WOWLAN_MLO_GTK_KEY_TYPE_BIGTK; - break; - } - return; - default: - /* ignore WEP/TKIP or unknown ciphers */ - return; - } - - old_keys->cipher[key->link_id][key_type] = key->cipher; - old_keys->key[key->link_id][key->keyidx] = key; -} - -static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status, - struct ieee80211_vif *vif, - struct iwl_mvm *mvm) -{ - int i; - struct iwl_mvm_d3_mlo_old_keys *old_keys; - bool ret = true; - - IWL_DEBUG_WOWLAN(mvm, "Num of MLO Keys: %d\n", status->num_mlo_keys); - if (!status->num_mlo_keys) - return true; - - old_keys = kzalloc(sizeof(*old_keys), GFP_KERNEL); - if (!old_keys) - return false; - - /* find the cipher for each mlo key */ - ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mlo_key_ciphers, old_keys); - - for (i = 0; i < status->num_mlo_keys; i++) { - struct iwl_wowlan_mlo_gtk *mlo_key = &status->mlo_keys[i]; - struct ieee80211_key_conf *key, *old_key; - struct ieee80211_key_seq seq; - struct { - struct ieee80211_key_conf conf; - u8 key[32]; - } conf = {}; - u16 flags = le16_to_cpu(mlo_key->flags); - int j, link_id, key_id, key_type; - - link_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK); - key_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK); - key_type = u16_get_bits(flags, - WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK); - - if (!(vif->valid_links & BIT(link_id))) - continue; - - if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS || - key_id >= 8 || - key_type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES)) - continue; - - conf.conf.cipher = old_keys->cipher[link_id][key_type]; - /* WARN_ON? */ - if (!conf.conf.cipher) - continue; - - conf.conf.keylen = 0; - switch (conf.conf.cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - conf.conf.keylen = WLAN_KEY_LEN_CCMP; - break; - case WLAN_CIPHER_SUITE_GCMP_256: - conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC; - break; - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256; - break; - } - - if (WARN_ON(!conf.conf.keylen || - conf.conf.keylen > sizeof(conf.key))) - continue; - - memcpy(conf.conf.key, mlo_key->key, conf.conf.keylen); - conf.conf.keyidx = key_id; - - old_key = old_keys->key[link_id][key_id]; - if (old_key) { - IWL_DEBUG_WOWLAN(mvm, - "Remove MLO key id %d, link id %d\n", - key_id, link_id); - ieee80211_remove_key(old_key); - } - - IWL_DEBUG_WOWLAN(mvm, "Add MLO key id %d, link id %d\n", - key_id, link_id); - key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); - if (WARN_ON(IS_ERR(key))) { - ret = false; - goto out; - } - - /* - * mac80211 expects the pn in big-endian - * also note that seq is a union of all cipher types - * (ccmp, gcmp, cmac, gmac), and they all have the same - * pn field (of length 6) so just copy it to ccmp.pn. - */ - for (j = 5; j >= 0; j--) - seq.ccmp.pn[5 - j] = mlo_key->pn[j]; - - /* group keys are non-QoS and use TID 0 */ - ieee80211_set_key_rx_seq(key, 0, &seq); - } - -out: - kfree(old_keys); - return ret; -} - static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, struct ieee80211_vif *vif, struct iwl_mvm *mvm, u32 gtk_cipher) { int i, j; struct ieee80211_key_conf *key; - struct { - struct ieee80211_key_conf conf; - u8 key[32]; - } conf = { - .conf.cipher = gtk_cipher, - }; + DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key, + WOWLAN_KEY_MAX_SIZE); int link_id = vif->active_links ? __ffs(vif->active_links) : -1; + u8 key_data[WOWLAN_KEY_MAX_SIZE]; + + conf->cipher = gtk_cipher; BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP); - BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk[0].key)); + BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_CCMP); + BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_GCMP_256); + BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_TKIP); + BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(status->gtk[0].key)); switch (gtk_cipher) { case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: - conf.conf.keylen = WLAN_KEY_LEN_CCMP; + conf->keylen = WLAN_KEY_LEN_CCMP; break; case WLAN_CIPHER_SUITE_GCMP_256: - conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; + conf->keylen = WLAN_KEY_LEN_GCMP_256; break; case WLAN_CIPHER_SUITE_TKIP: - conf.conf.keylen = WLAN_KEY_LEN_TKIP; + conf->keylen = WLAN_KEY_LEN_TKIP; break; default: WARN_ON(1); @@ -2189,16 +1983,22 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, if (!status->gtk[i].len) continue; - conf.conf.keyidx = status->gtk[i].id; + conf->keyidx = status->gtk[i].id; IWL_DEBUG_WOWLAN(mvm, "Received from FW GTK cipher %d, key index %d\n", - conf.conf.cipher, conf.conf.keyidx); - memcpy(conf.conf.key, status->gtk[i].key, + conf->cipher, conf->keyidx); + memcpy(conf->key, status->gtk[i].key, sizeof(status->gtk[i].key)); + memcpy(key_data, status->gtk[i].key, sizeof(status->gtk[i].key)); - key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); - if (IS_ERR(key)) + key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, key_data, + sizeof(key_data), link_id); + if (IS_ERR(key)) { + /* FW may send also the old keys */ + if (PTR_ERR(key) == -EALREADY) + continue; return false; + } for (j = 0; j < ARRAY_SIZE(status->gtk_seq); j++) { if (!status->gtk_seq[j].valid || @@ -2218,55 +2018,66 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, struct ieee80211_vif *vif, u32 cipher, struct iwl_multicast_key_data *key_data) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key, + WOWLAN_KEY_MAX_SIZE); struct ieee80211_key_conf *key_config; - struct { - struct ieee80211_key_conf conf; - u8 key[WOWLAN_KEY_MAX_SIZE]; - } conf = { - .conf.cipher = cipher, - .conf.keyidx = key_data->id, - }; struct ieee80211_key_seq seq; int link_id = vif->active_links ? __ffs(vif->active_links) : -1; + u8 key[WOWLAN_KEY_MAX_SIZE]; + s8 keyidx = key_data->id; + + conf->cipher = cipher; + conf->keyidx = keyidx; if (!key_data->len) return true; - iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher); + iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf->cipher); switch (cipher) { case WLAN_CIPHER_SUITE_BIP_GMAC_128: - conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128; + conf->keylen = WLAN_KEY_LEN_BIP_GMAC_128; break; case WLAN_CIPHER_SUITE_BIP_GMAC_256: - conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256; + conf->keylen = WLAN_KEY_LEN_BIP_GMAC_256; break; case WLAN_CIPHER_SUITE_AES_CMAC: - conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC; + conf->keylen = WLAN_KEY_LEN_AES_CMAC; break; case WLAN_CIPHER_SUITE_BIP_CMAC_256: - conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256; + conf->keylen = WLAN_KEY_LEN_BIP_CMAC_256; break; default: WARN_ON(1); } - BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); - memcpy(conf.conf.key, key_data->key, conf.conf.keylen); + BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(key_data->key)); + memcpy(conf->key, key_data->key, conf->keylen); - key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); - if (IS_ERR(key_config)) - return false; + memcpy(key, key_data->key, sizeof(key_data->key)); + + key_config = ieee80211_gtk_rekey_add(vif, keyidx, key, sizeof(key), + link_id); + if (IS_ERR(key_config)) { + /* FW may send also the old keys */ + return PTR_ERR(key_config) == -EALREADY; + } ieee80211_set_key_rx_seq(key_config, 0, &seq); - if (key_config->keyidx == 4 || key_config->keyidx == 5) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + if (keyidx == 4 || keyidx == 5) { struct iwl_mvm_vif_link_info *mvm_link; link_id = link_id < 0 ? 0 : link_id; mvm_link = mvmvif->link[link_id]; + if (mvm_link->igtk) + mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID; mvm_link->igtk = key_config; } + if (vif->type == NL80211_IFTYPE_STATION && (keyidx == 6 || keyidx == 7)) + rcu_assign_pointer(mvmvif->bcn_prot.keys[keyidx - 6], + key_config); + return true; } @@ -2353,9 +2164,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, return false; } - if (!iwl_mvm_mlo_gtk_rekey(status, vif, mvm)) - return false; - ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, (void *)&replay_ctr, GFP_KERNEL); } @@ -2385,6 +2193,7 @@ static void iwl_mvm_convert_gtk_v2(struct iwl_wowlan_status_data *status, status->gtk[0].len = data->key_len; status->gtk[0].flags = data->key_flags; + status->gtk[0].id = status->gtk[0].flags & IWL_WOWLAN_GTK_IDX_MASK; memcpy(status->gtk[0].key, data->key, sizeof(data->key)); @@ -2486,10 +2295,11 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, struct iwl_wowlan_status_data *status, u32 len) { - u32 expected_len = sizeof(*data) + - data->num_mlo_link_keys * sizeof(status->mlo_keys[0]); + if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys, + "MLO is not supported, shouldn't receive MLO keys\n")) + return; - if (len < expected_len) { + if (len < sizeof(*data)) { IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); status = NULL; return; @@ -2518,33 +2328,17 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, le32_to_cpu(data->num_of_gtk_rekeys); status->received_beacons = le32_to_cpu(data->received_beacons); status->tid_tear_down = data->tid_tear_down; - - if (data->num_mlo_link_keys) { - status->num_mlo_keys = data->num_mlo_link_keys; - if (IWL_FW_CHECK(mvm, - status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, - "Too many mlo keys: %d, max %d\n", - status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) - status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; - memcpy(status->mlo_keys, data->mlo_gtks, - status->num_mlo_keys * sizeof(status->mlo_keys[0])); - } } static void -iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm, - struct iwl_wowlan_info_notif_v4 *data, +iwl_mvm_parse_wowlan_info_notif_v3(struct iwl_mvm *mvm, + struct iwl_wowlan_info_notif_v3 *data, struct iwl_wowlan_status_data *status, - u32 len, bool has_mlo_keys) + u32 len) { u32 i; - u32 expected_len = sizeof(*data); - - if (has_mlo_keys) - expected_len += (data->num_mlo_link_keys * - sizeof(status->mlo_keys[0])); - if (len < expected_len) { + if (len < sizeof(*data)) { IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); status = NULL; return; @@ -2567,22 +2361,11 @@ iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm, le32_to_cpu(data->num_of_gtk_rekeys); status->received_beacons = le32_to_cpu(data->received_beacons); status->tid_tear_down = data->tid_tear_down; - - if (has_mlo_keys && data->num_mlo_link_keys) { - status->num_mlo_keys = data->num_mlo_link_keys; - if (IWL_FW_CHECK(mvm, - status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, - "Too many mlo keys: %d, max %d\n", - status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) - status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; - memcpy(status->mlo_keys, data->mlo_gtks, - status->num_mlo_keys * sizeof(status->mlo_keys[0])); - } } static void -iwl_mvm_parse_wowlan_info_notif_v2(struct iwl_mvm *mvm, - struct iwl_wowlan_info_notif_v2 *data, +iwl_mvm_parse_wowlan_info_notif_v1(struct iwl_mvm *mvm, + struct iwl_wowlan_info_notif_v1 *data, struct iwl_wowlan_status_data *status, u32 len) { @@ -2667,8 +2450,6 @@ iwl_mvm_parse_wowlan_status_common_ ## _ver(struct iwl_mvm *mvm, \ iwl_mvm_parse_wowlan_status_common(v6) iwl_mvm_parse_wowlan_status_common(v7) -iwl_mvm_parse_wowlan_status_common(v9) -iwl_mvm_parse_wowlan_status_common(v12) static struct iwl_wowlan_status_data * iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) @@ -2724,7 +2505,8 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) v6->gtk.tkip_mic_key, sizeof(v6->gtk.tkip_mic_key)); - iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc); + iwl_mvm_convert_key_counters(status, &v6->gtk.rsc.all_tsc_rsc, + v6->gtk.key_index); /* hardcode the key length to 16 since v6 only supports 16 */ status->gtk[0].len = 16; @@ -2735,6 +2517,7 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) * currently used key. */ status->gtk[0].flags = v6->gtk.key_index | BIT(7); + status->gtk[0].id = v6->gtk.key_index; } else if (notif_ver == 7) { struct iwl_wowlan_status_v7 *v7 = (void *)cmd.resp_pkt->data; @@ -2742,36 +2525,10 @@ iwl_mvm_send_wowlan_get_status(struct iwl_mvm *mvm, u8 sta_id) if (!status) goto out_free_resp; - iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc); + iwl_mvm_convert_key_counters(status, &v7->gtk[0].rsc.all_tsc_rsc, + v7->gtk[0].key_flags & IWL_WOWLAN_GTK_IDX_MASK); iwl_mvm_convert_gtk_v2(status, &v7->gtk[0]); iwl_mvm_convert_igtk(status, &v7->igtk[0]); - } else if (notif_ver == 9 || notif_ver == 10 || notif_ver == 11) { - struct iwl_wowlan_status_v9 *v9 = (void *)cmd.resp_pkt->data; - - /* these three command versions have same layout and size, the - * difference is only in a few not used (reserved) fields. - */ - status = iwl_mvm_parse_wowlan_status_common_v9(mvm, v9, len); - if (!status) - goto out_free_resp; - - iwl_mvm_convert_key_counters(status, &v9->gtk[0].rsc.all_tsc_rsc); - iwl_mvm_convert_gtk_v2(status, &v9->gtk[0]); - iwl_mvm_convert_igtk(status, &v9->igtk[0]); - - status->tid_tear_down = v9->tid_tear_down; - } else if (notif_ver == 12) { - struct iwl_wowlan_status_v12 *v12 = (void *)cmd.resp_pkt->data; - - status = iwl_mvm_parse_wowlan_status_common_v12(mvm, v12, len); - if (!status) - goto out_free_resp; - - iwl_mvm_convert_key_counters_v5(status, &v12->gtk[0].sc); - iwl_mvm_convert_gtk_v3(status, v12->gtk); - iwl_mvm_convert_igtk(status, &v12->igtk[0]); - - status->tid_tear_down = v12->tid_tear_down; } else { IWL_ERR(mvm, "Firmware advertises unknown WoWLAN status response %d!\n", @@ -3298,44 +3055,30 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, break; } - if (wowlan_info_ver < 2) { + if (wowlan_info_ver == 1) { struct iwl_wowlan_info_notif_v1 *notif_v1 = (void *)pkt->data; - struct iwl_wowlan_info_notif_v2 *notif_v2; - - notif_v2 = kmemdup(notif_v1, sizeof(*notif_v2), GFP_ATOMIC); - - if (!notif_v2) - return false; - - notif_v2->tid_tear_down = notif_v1->tid_tear_down; - notif_v2->station_id = notif_v1->station_id; - memset_after(notif_v2, 0, station_id); - iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, - d3_data->status, - len); - kfree(notif_v2); - - } else if (wowlan_info_ver == 2) { - struct iwl_wowlan_info_notif_v2 *notif_v2 = - (void *)pkt->data; - iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, + iwl_mvm_parse_wowlan_info_notif_v1(mvm, notif_v1, d3_data->status, len); - } else if (wowlan_info_ver < 5) { - struct iwl_wowlan_info_notif_v4 *notif = + } else if (wowlan_info_ver == 3) { + struct iwl_wowlan_info_notif_v3 *notif = (void *)pkt->data; - iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif, - d3_data->status, len, - wowlan_info_ver > 3); - } else { + iwl_mvm_parse_wowlan_info_notif_v3(mvm, notif, + d3_data->status, len); + } else if (wowlan_info_ver == 5) { struct iwl_wowlan_info_notif *notif = (void *)pkt->data; iwl_mvm_parse_wowlan_info_notif(mvm, notif, d3_data->status, len); + } else { + IWL_FW_CHECK(mvm, 1, + "Firmware advertises unknown WoWLAN info notification %d!\n", + wowlan_info_ver); + return false; } d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 86a87ea89916..f0e184c8a81a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -1134,7 +1134,7 @@ static ssize_t iwl_dbgfs_fw_restart_write(struct iwl_mvm *mvm, char *buf, if (count == 6 && !strcmp(buf, "nolog\n")) { set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); - set_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, &mvm->trans->status); + iwl_trans_suppress_cmd_error_once(mvm->trans); } /* take the return value to make compiler happy - it will fail anyway */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 819e3228462a..d931c6eaf12f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -121,6 +121,22 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, return false; palive = (void *)pkt->data; + + umac = &palive->umac_data; + lmac1 = &palive->lmac_data[0]; + lmac2 = &palive->lmac_data[1]; + status = le16_to_cpu(palive->status); + + BUILD_BUG_ON(sizeof(palive->sku_id.data) != + sizeof(alive_data->sku_id)); + memcpy(alive_data->sku_id, palive->sku_id.data, + sizeof(palive->sku_id.data)); + + IWL_DEBUG_FW(mvm, "Got sku_id: 0x0%x 0x0%x 0x0%x\n", + le32_to_cpu(alive_data->sku_id[0]), + le32_to_cpu(alive_data->sku_id[1]), + le32_to_cpu(alive_data->sku_id[2])); + mvm->trans->dbg.imr_data.imr_enable = le32_to_cpu(palive->imr.enabled); mvm->trans->dbg.imr_data.imr_size = @@ -168,40 +184,6 @@ static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, IWL_DEBUG_FW(mvm, "platform id: 0x%llx\n", palive_v8->platform_id); } - } - - if (version >= 5) { - struct iwl_alive_ntf_v5 *palive; - - if (pkt_len < sizeof(*palive)) - return false; - - palive = (void *)pkt->data; - umac = &palive->umac_data; - lmac1 = &palive->lmac_data[0]; - lmac2 = &palive->lmac_data[1]; - status = le16_to_cpu(palive->status); - - BUILD_BUG_ON(sizeof(palive->sku_id.data) != - sizeof(alive_data->sku_id)); - memcpy(alive_data->sku_id, palive->sku_id.data, - sizeof(palive->sku_id.data)); - - IWL_DEBUG_FW(mvm, "Got sku_id: 0x0%x 0x0%x 0x0%x\n", - le32_to_cpu(alive_data->sku_id[0]), - le32_to_cpu(alive_data->sku_id[1]), - le32_to_cpu(alive_data->sku_id[2])); - } else if (iwl_rx_packet_payload_len(pkt) == sizeof(struct iwl_alive_ntf_v4)) { - struct iwl_alive_ntf_v4 *palive; - - if (pkt_len < sizeof(*palive)) - return false; - - palive = (void *)pkt->data; - umac = &palive->umac_data; - lmac1 = &palive->lmac_data[0]; - lmac2 = &palive->lmac_data[1]; - status = le16_to_cpu(palive->status); } else if (iwl_rx_packet_payload_len(pkt) == sizeof(struct iwl_alive_ntf_v3)) { struct iwl_alive_ntf_v3 *palive3; @@ -432,7 +414,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, iwl_trans_fw_alive(mvm->trans); ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait, - &mvm->fw->ucode_capa, alive_data.sku_id); + mvm->fw, alive_data.sku_id); if (ret) { IWL_ERR(mvm, "Timeout waiting for PNVM load!\n"); iwl_fw_set_current_image(&mvm->fwrt, old_type); @@ -888,17 +870,11 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) len = sizeof(cmd_v9_v10.v9); n_subbands = IWL_NUM_SUB_BANDS_V1; per_chain = &cmd_v9_v10.v9.per_chain[0][0]; - } else if (cmd_ver >= 7) { - len = sizeof(cmd.v7); - n_subbands = IWL_NUM_SUB_BANDS_V2; - per_chain = cmd.v7.per_chain[0][0]; - cmd.v7.flags = cpu_to_le32(mvm->fwrt.reduced_power_flags); - if (cmd_ver == 8) - len = sizeof(cmd.v8); - } else if (cmd_ver == 6) { - len = sizeof(cmd.v6); + } else if (cmd_ver == 8) { + len = sizeof(cmd.v8); n_subbands = IWL_NUM_SUB_BANDS_V2; - per_chain = cmd.v6.per_chain[0][0]; + per_chain = cmd.v8.per_chain[0][0]; + cmd.v8.flags = cpu_to_le32(mvm->fwrt.reduced_power_flags); } else if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_REDUCE_TX_POWER)) { len = sizeof(cmd.v5); @@ -1462,9 +1438,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL); } - for (i = 0; i < IWL_FW_MAX_LINK_ID + 1; i++) - RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL); - mvm->tdls_cs.peer.sta_id = IWL_INVALID_STA; /* reset quota debouncing buffer - 0xff will yield invalid data */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c index 851869c0bd50..2269acc55c0e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -18,8 +18,7 @@ HOW(EXIT_COEX) \ HOW(EXIT_BANDWIDTH) \ HOW(EXIT_CSA) \ - HOW(EXIT_LINK_USAGE) \ - HOW(EXIT_FAIL_ENTRY) + HOW(EXIT_LINK_USAGE) static const char *const iwl_mvm_esr_states_names[] = { #define NAME_ENTRY(x) [ilog2(IWL_MVM_ESR_##x)] = #x, @@ -50,20 +49,6 @@ static void iwl_mvm_print_esr_state(struct iwl_mvm *mvm, u32 mask) #undef NAME_PR } -static u32 iwl_mvm_get_free_fw_link_id(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvm_vif) -{ - u32 i; - - lockdep_assert_held(&mvm->mutex); - - for (i = 0; i < ARRAY_SIZE(mvm->link_id_to_link_conf); i++) - if (!rcu_access_pointer(mvm->link_id_to_link_conf[i])) - return i; - - return IWL_MVM_FW_LINK_ID_INVALID; -} - static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm, struct iwl_link_config_cmd *cmd, enum iwl_ctxt_action action) @@ -80,25 +65,15 @@ static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm, return ret; } -int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf) +void iwl_mvm_set_link_fw_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_conf->link_id]; - if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) { - link_info->fw_link_id = iwl_mvm_get_free_fw_link_id(mvm, - mvmvif); - if (link_info->fw_link_id >= - ARRAY_SIZE(mvm->link_id_to_link_conf)) - return -EINVAL; - - rcu_assign_pointer(mvm->link_id_to_link_conf[link_info->fw_link_id], - link_conf); - } - - return 0; + if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) + link_info->fw_link_id = mvmvif->id; } int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -110,14 +85,11 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_link_config_cmd cmd = {}; unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD); u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1); - int ret; if (WARN_ON_ONCE(!link_info)) return -EINVAL; - ret = iwl_mvm_set_link_mapping(mvm, vif, link_conf); - if (ret) - return ret; + iwl_mvm_set_link_fw_id(mvm, vif, link_conf); /* Update SF - Disable if needed. if this fails, SF might still be on * while many macs are bound, which is forbidden - so fail the binding. @@ -374,24 +346,6 @@ send_cmd: return ret; } -int iwl_mvm_unset_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_vif_link_info *link_info = - mvmvif->link[link_conf->link_id]; - - /* mac80211 thought we have the link, but it was never configured */ - if (WARN_ON(!link_info || - link_info->fw_link_id >= - ARRAY_SIZE(mvm->link_id_to_link_conf))) - return -EINVAL; - - RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id], - NULL); - return 0; -} - int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { @@ -401,10 +355,6 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_link_config_cmd cmd = {}; int ret; - ret = iwl_mvm_unset_link_mapping(mvm, vif, link_conf); - if (ret) - return 0; - cmd.link_id = cpu_to_le32(link_info->fw_link_id); link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; cmd.spec_link_id = link_conf->link_id; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 9098a36530cc..8805ab344895 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -301,7 +301,7 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif) iwl_mvm_init_link(&mvmvif->deflink); - /* No need to allocate data queues to P2P Device MAC and NAN.*/ + /* No need to allocate data queues to P2P Device MAC */ if (vif->type == NL80211_IFTYPE_P2P_DEVICE) return 0; @@ -976,7 +976,7 @@ u8 iwl_mvm_mac_ctxt_get_beacon_rate(struct iwl_mvm *mvm, static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct sk_buff *beacon, - struct iwl_tx_cmd_v6 *tx) + struct iwl_tx_cmd_v6_params *tx_params) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_tx_info *info; @@ -986,30 +986,30 @@ static void iwl_mvm_mac_ctxt_set_tx(struct iwl_mvm *mvm, info = IEEE80211_SKB_CB(beacon); /* Set up TX command fields */ - tx->len = cpu_to_le16((u16)beacon->len); - tx->sta_id = mvmvif->deflink.bcast_sta.sta_id; - tx->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); + tx_params->len = cpu_to_le16((u16)beacon->len); + tx_params->sta_id = mvmvif->deflink.bcast_sta.sta_id; + tx_params->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); tx_flags = TX_CMD_FLG_SEQ_CTL | TX_CMD_FLG_TSF; tx_flags |= iwl_mvm_bt_coex_tx_prio(mvm, (void *)beacon->data, info, 0) << TX_CMD_FLG_BT_PRIO_POS; - tx->tx_flags = cpu_to_le32(tx_flags); + tx_params->tx_flags = cpu_to_le32(tx_flags); if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION)) { iwl_mvm_toggle_tx_ant(mvm, &mvm->mgmt_last_antenna_idx); - tx->rate_n_flags = + tx_params->rate_n_flags = cpu_to_le32(BIT(mvm->mgmt_last_antenna_idx) << RATE_MCS_ANT_POS); } rate = iwl_mvm_mac_ctxt_get_beacon_rate(mvm, info, vif); - tx->rate_n_flags |= + tx_params->rate_n_flags |= cpu_to_le32(iwl_mvm_mac80211_idx_to_hwrate(mvm->fw, rate)); if (rate == IWL_FIRST_CCK_RATE) - tx->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1); + tx_params->rate_n_flags |= cpu_to_le32(RATE_MCS_CCK_MSK_V1); } @@ -1586,7 +1586,7 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, u32 id = le32_to_cpu(mb->link_id); union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt }; u32 mac_type; - int link_id = -1; + int link_id; u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, MISSED_BEACONS_NOTIFICATION, 0); @@ -1602,20 +1602,6 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, if (new_notif_ver) notif_ver = new_notif_ver; - /* before version four the ID in the notification refers to mac ID */ - if (notif_ver < 4) { - vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false); - bss_conf = &vif->bss_conf; - } else { - bss_conf = iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, false); - - if (!bss_conf) - return; - - vif = bss_conf->vif; - link_id = bss_conf->link_id; - } - IWL_DEBUG_INFO(mvm, "missed bcn %s_id=%u, consecutive=%u (%u)\n", notif_ver < 4 ? "mac" : "link", @@ -1623,9 +1609,16 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, le32_to_cpu(mb->consec_missed_beacons), le32_to_cpu(mb->consec_missed_beacons_since_last_rx)); + /* + * starting from version 4 the ID is link ID, but driver + * uses link ID == MAC ID, so always treat as MAC ID + */ + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false); if (!vif) return; + bss_conf = &vif->bss_conf; + link_id = bss_conf->link_id; mac_type = iwl_mvm_get_mac_type(vif); IWL_DEBUG_INFO(mvm, "missed beacon mac_type=%u,\n", mac_type); @@ -1875,16 +1868,15 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, } else { struct iwl_channel_switch_start_notif *notif = (void *)pkt->data; u32 link_id = le32_to_cpu(notif->link_id); - struct ieee80211_bss_conf *bss_conf = - iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, link_id, true); - if (!bss_conf) + /* we use link ID == MAC ID */ + vif = iwl_mvm_rcu_dereference_vif_id(mvm, link_id, true); + if (!vif) goto out_unlock; id = link_id; - mac_link_id = bss_conf->link_id; - vif = bss_conf->vif; - csa_active = bss_conf->csa_active; + mac_link_id = vif->bss_conf.link_id; + csa_active = vif->bss_conf.csa_active; } mvmvif = iwl_mvm_vif_from_mac80211(vif); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 956b491ae5a4..4ad3d32683d8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -5,6 +5,7 @@ * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #include <linux/kernel.h> +#include <linux/fips.h> #include <linux/slab.h> #include <linux/skbuff.h> #include <linux/netdevice.h> @@ -165,12 +166,6 @@ struct ieee80211_regdomain *iwl_mvm_get_regdomain(struct wiphy *wiphy, mvm->lar_regdom_set = true; mvm->mcc_src = src_id; - if (!iwl_puncturing_is_allowed_in_bios(mvm->bios_enable_puncturing, - le16_to_cpu(resp->mcc))) - ieee80211_hw_set(mvm->hw, DISALLOW_PUNCTURING); - else - __clear_bit(IEEE80211_HW_DISALLOW_PUNCTURING, mvm->hw->flags); - iwl_mei_set_country_code(__le16_to_cpu(resp->mcc)); out: @@ -298,7 +293,8 @@ static const struct wiphy_iftype_ext_capab add_iftypes_ext_capa[] = { }, }; -int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); *tx_ant = iwl_mvm_get_valid_tx_ant(mvm); @@ -306,13 +302,15 @@ int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) return 0; } -int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, + u32 rx_ant) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); /* This has been tested on those devices only */ if (mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_9000 && - mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_22000) + mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_22000 && + mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_AX210) return -EOPNOTSUPP; if (!mvm->nvm_data) @@ -464,7 +462,9 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) IWL_ERR(mvm, "iwlmvm doesn't allow to disable BT Coex, check bt_coex_active module parameter\n"); - ieee80211_hw_set(hw, MFP_CAPABLE); + if (!fips_enabled) + ieee80211_hw_set(hw, MFP_CAPABLE); + mvm->ciphers[hw->wiphy->n_cipher_suites] = WLAN_CIPHER_SUITE_AES_CMAC; hw->wiphy->n_cipher_suites++; if (iwl_mvm_has_new_rx_api(mvm)) { @@ -488,12 +488,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) hw->wiphy->pmsr_capa = &iwl_mvm_pmsr_capa; } - if (sec_key_ver && + /* + * beacon protection must be handled by firmware, + * so cannot be done with fips_enabled + */ + if (!fips_enabled && sec_key_ver && fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BIGTK_TX_SUPPORT)) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); - else if (fw_has_capa(&mvm->fw->ucode_capa, + else if (!fips_enabled && + fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT)) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT); @@ -733,7 +738,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) #ifdef CONFIG_PM_SLEEP if ((unified || mvm->fw->img[IWL_UCODE_WOWLAN].num_sec) && - device_can_wakeup(mvm->trans->dev)) { + device_can_wakeup(mvm->trans->dev) && !fips_enabled) { mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_EAP_IDENTITY_REQ | @@ -1518,10 +1523,6 @@ int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, len = sizeof(cmd_v9_v10.v9); else if (cmd_ver == 8) len = sizeof(cmd.v8); - else if (cmd_ver == 7) - len = sizeof(cmd.v7); - else if (cmd_ver == 6) - len = sizeof(cmd.v6); else if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_REDUCE_TX_POWER)) len = sizeof(cmd.v5); @@ -1772,6 +1773,8 @@ void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) return; + mvmvif->deflink.average_beacon_energy = 0; + INIT_DELAYED_WORK(&mvmvif->csa_work, iwl_mvm_channel_switch_disconnect_wk); @@ -1809,9 +1812,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, vif->driver_flags = IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC; - ret = iwl_mvm_set_link_mapping(mvm, vif, &vif->bss_conf); - if (ret) - goto out; + iwl_mvm_set_link_fw_id(mvm, vif, &vif->bss_conf); /* * Not much to do here. The stack will not allow interface @@ -1832,12 +1833,6 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, rcu_assign_pointer(mvm->vif_id_to_mac[mvmvif->id], vif); - /* Currently not much to do for NAN */ - if (vif->type == NL80211_IFTYPE_NAN) { - ret = 0; - goto out; - } - /* * The AP binding flow can be done only after the beacon * template is configured (which happens only in the mac80211 @@ -2012,7 +2007,6 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw, mvm->monitor_on = false; out: - iwl_mvm_unset_link_mapping(mvm, vif, &vif->bss_conf); if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC) { iwl_mvm_dealloc_int_sta(mvm, &mvmvif->deflink.mcast_sta); @@ -3338,7 +3332,7 @@ void iwl_mvm_mac_cancel_hw_scan(struct ieee80211_hw *hw, * us to stop a hw_scan when it's already stopped. This can * happen, for instance, if we stopped the scan ourselves, * called ieee80211_scan_completed() and the userspace called - * cancel scan scan before ieee80211_scan_work() could run. + * cancel scan before ieee80211_scan_work() could run. * To handle that, simply return if the scan is not running. */ if (mvm->scan_status & IWL_MVM_SCAN_REGULAR) @@ -4249,7 +4243,8 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw, return ret; } -int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); @@ -4350,7 +4345,7 @@ int iwl_mvm_mac_sched_scan_stop(struct ieee80211_hw *hw, * us to stop a sched_scan when it's already stopped. This * can happen, for instance, if we stopped the scan ourselves, * called ieee80211_sched_scan_stopped() and the userspace called - * stop sched scan scan before ieee80211_sched_scan_stopped_work() + * stop sched scan before ieee80211_sched_scan_stopped_work() * could run. To handle this, simply return if the scan is * not running. */ @@ -4614,6 +4609,10 @@ int iwl_mvm_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); + /* When resuming from wowlan, FW already knows about the newest keys */ + if (test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) + return 0; + guard(mvm)(mvm); return __iwl_mvm_mac_set_key(hw, cmd, vif, sta, key); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c index 3f8b840871d3..2d116a41913c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c @@ -282,9 +282,6 @@ int iwl_mvm_mld_mac_ctxt_add(struct iwl_mvm *mvm, struct ieee80211_vif *vif) struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; - if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) - return -EOPNOTSUPP; - if (WARN_ONCE(mvmvif->uploaded, "Adding active MAC %pM/%d\n", vif->addr, ieee80211_vif_type_p2p(vif))) return -EIO; @@ -307,9 +304,6 @@ int iwl_mvm_mld_mac_ctxt_changed(struct iwl_mvm *mvm, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) - return -EOPNOTSUPP; - if (WARN_ONCE(!mvmvif->uploaded, "Changing inactive MAC %pM/%d\n", vif->addr, ieee80211_vif_type_p2p(vif))) return -EIO; @@ -327,9 +321,6 @@ int iwl_mvm_mld_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) }; int ret; - if (WARN_ON_ONCE(vif->type == NL80211_IFTYPE_NAN)) - return -EOPNOTSUPP; - if (WARN_ONCE(!mvmvif->uploaded, "Removing inactive MAC %pM/%d\n", vif->addr, ieee80211_vif_type_p2p(vif))) return -EIO; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index a4f412e750d0..fdaeefa305e1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -304,6 +304,8 @@ struct iwl_probe_resp_data { * @mcast_sta: multicast station * @phy_ctxt: phy context allocated to this link, if any * @bf_data: beacon filtering data + * @average_beacon_energy: average beacon energy for beacons received during + * client connections */ struct iwl_mvm_vif_link_info { u8 bssid[ETH_ALEN]; @@ -342,6 +344,7 @@ struct iwl_mvm_vif_link_info { u16 mgmt_queue; struct iwl_mvm_link_bf_data bf_data; + u32 average_beacon_energy; }; /** @@ -374,7 +377,6 @@ struct iwl_mvm_vif_link_info { * preventing the enablement of EMLSR * @IWL_MVM_ESR_EXIT_CSA: CSA happened, so exit EMLSR * @IWL_MVM_ESR_EXIT_LINK_USAGE: Exit EMLSR due to low tpt on secondary link - * @IWL_MVM_ESR_EXIT_FAIL_ENTRY: Exit EMLSR due to entry failure */ enum iwl_mvm_esr_state { IWL_MVM_ESR_BLOCKED_PREVENTION = 0x1, @@ -390,7 +392,6 @@ enum iwl_mvm_esr_state { IWL_MVM_ESR_EXIT_BANDWIDTH = 0x80000, IWL_MVM_ESR_EXIT_CSA = 0x100000, IWL_MVM_ESR_EXIT_LINK_USAGE = 0x200000, - IWL_MVM_ESR_EXIT_FAIL_ENTRY = 0x400000, }; #define IWL_MVM_BLOCK_ESR_REASONS 0xffff @@ -1179,8 +1180,6 @@ struct iwl_mvm { struct ieee80211_vif __rcu *vif_id_to_mac[NUM_MAC_INDEX_DRIVER]; - struct ieee80211_bss_conf __rcu *link_id_to_link_conf[IWL_FW_MAX_LINK_ID + 1]; - u8 *error_recovery_buf; #ifdef CONFIG_IWLWIFI_LEDS @@ -1326,7 +1325,6 @@ struct iwl_mvm { u8 range_resp; } cmd_ver; - struct ieee80211_vif *nan_vif; struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID]; /* @@ -1372,7 +1370,6 @@ struct iwl_mvm { struct iwl_mvm_acs_survey *acs_survey; bool statistics_clear; - u32 bios_enable_puncturing; }; /* Extract MVM priv from op_mode and _hw */ @@ -1488,20 +1485,6 @@ iwl_mvm_rcu_dereference_vif_id(struct iwl_mvm *mvm, u8 vif_id, bool rcu) lockdep_is_held(&mvm->mutex)); } -static inline struct ieee80211_bss_conf * -iwl_mvm_rcu_fw_link_id_to_link_conf(struct iwl_mvm *mvm, u8 link_id, bool rcu) -{ - if (IWL_FW_CHECK(mvm, link_id >= ARRAY_SIZE(mvm->link_id_to_link_conf), - "erroneous FW link ID: %d\n", link_id)) - return NULL; - - if (rcu) - return rcu_dereference(mvm->link_id_to_link_conf[link_id]); - - return rcu_dereference_protected(mvm->link_id_to_link_conf[link_id], - lockdep_is_held(&mvm->mutex)); -} - static inline bool iwl_mvm_is_adaptive_dwell_supported(struct iwl_mvm *mvm) { return fw_has_api(&mvm->fw->ucode_capa, @@ -1837,11 +1820,12 @@ int iwl_mvm_tx_skb_sta(struct iwl_mvm *mvm, struct sk_buff *skb, struct ieee80211_sta *sta); int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb); void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, - struct iwl_tx_cmd_v6 *tx_cmd, + struct iwl_tx_cmd_v6_params *tx_cmd_params, struct ieee80211_tx_info *info, u8 sta_id); -void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd_v6 *tx_cmd, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, __le16 fc); +void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, + struct iwl_tx_cmd_v6_params *tx_cmd_params, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, __le16 fc); void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq); unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm, struct ieee80211_sta *sta, @@ -1870,12 +1854,12 @@ int iwl_mvm_set_sta_pkt_ext(struct iwl_mvm *mvm, void iwl_mvm_async_handlers_purge(struct iwl_mvm *mvm); static inline void iwl_mvm_set_tx_cmd_ccmp(struct ieee80211_tx_info *info, - struct iwl_tx_cmd_v6 *tx_cmd) + struct iwl_tx_cmd_v6_params *tx_cmd_params) { struct ieee80211_key_conf *keyconf = info->control.hw_key; - tx_cmd->sec_ctl = TX_CMD_SEC_CCM; - memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); + tx_cmd_params->sec_ctl = TX_CMD_SEC_CCM; + memcpy(tx_cmd_params->key, keyconf->key, keyconf->keylen); } static inline void iwl_mvm_wait_for_async_handlers(struct iwl_mvm *mvm) @@ -2093,6 +2077,9 @@ void iwl_mvm_channel_switch_start_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_channel_switch_error_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); +void iwl_mvm_rx_beacon_filter_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb); + /* Bindings */ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); int iwl_mvm_binding_remove_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); @@ -2100,15 +2087,13 @@ u32 iwl_mvm_get_lmac_id(struct iwl_mvm *mvm, enum nl80211_band band); /* Links */ void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link); -int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf); +void iwl_mvm_set_link_fw_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf); int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, u32 changes, bool active); -int iwl_mvm_unset_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf); int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -2133,7 +2118,6 @@ bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif, s8 iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif); - extern const struct iwl_hcmd_arr iwl_mvm_groups[]; extern const unsigned int iwl_mvm_groups_size; #endif @@ -2866,13 +2850,16 @@ void iwl_mvm_mac_wake_tx_queue(struct ieee80211_hw *hw, int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params); -int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); -int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); +int iwl_mvm_op_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, + u32 *rx_ant); +int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, + u32 rx_ant); int iwl_mvm_mac_start(struct ieee80211_hw *hw); void iwl_mvm_mac_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type); void iwl_mvm_mac_stop(struct ieee80211_hw *hw, bool suspend); -static inline int iwl_mvm_mac_config(struct ieee80211_hw *hw, u32 changed) +static inline int iwl_mvm_mac_config(struct ieee80211_hw *hw, int radio_idx, + u32 changed) { return 0; } @@ -2905,7 +2892,8 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw, int num_frames, enum ieee80211_frame_release_type reason, bool more_data); -int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +int iwl_mvm_mac_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value); void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, u32 changed); void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index a2dc5c3b0596..c7f08cde1f72 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -61,8 +61,10 @@ static int __init iwl_mvm_init(void) } ret = iwl_opmode_register("iwlmvm", &iwl_mvm_ops); - if (ret) + if (ret) { pr_err("Unable to register MVM op_mode: %d\n", ret); + iwl_mvm_rate_control_unregister(); + } return ret; } @@ -159,43 +161,6 @@ static void iwl_mvm_rx_esr_mode_notif(struct iwl_mvm *mvm, iwl_mvm_get_primary_link(vif)); } -static void iwl_mvm_rx_esr_trans_fail_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_esr_trans_fail_notif *notif = (void *)pkt->data; - struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm); - u8 fw_link_id = le32_to_cpu(notif->link_id); - struct ieee80211_bss_conf *bss_conf; - - if (IS_ERR_OR_NULL(vif)) - return; - - IWL_DEBUG_INFO(mvm, "Failed to %s eSR on link %d, reason %d\n", - le32_to_cpu(notif->activation) ? "enter" : "exit", - le32_to_cpu(notif->link_id), - le32_to_cpu(notif->err_code)); - - /* we couldn't go back to single link, disconnect */ - if (!le32_to_cpu(notif->activation)) { - iwl_mvm_connection_loss(mvm, vif, "emlsr exit failed"); - return; - } - - bss_conf = iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, fw_link_id, false); - if (IWL_FW_CHECK(mvm, !bss_conf, - "FW reported failure to activate EMLSR on a non-existing link: %d\n", - fw_link_id)) - return; - - /* - * We failed to activate the second link and enter EMLSR, we need to go - * back to single link. - */ - iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_FAIL_ENTRY, - bss_conf->link_id); -} - static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { @@ -524,10 +489,11 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_GRP(SCAN_GROUP, CHANNEL_SURVEY_NOTIF, iwl_mvm_rx_channel_survey_notif, RX_HANDLER_ASYNC_LOCKED, struct iwl_umac_scan_channel_survey_notif), - RX_HANDLER_GRP(MAC_CONF_GROUP, EMLSR_TRANS_FAIL_NOTIF, - iwl_mvm_rx_esr_trans_fail_notif, - RX_HANDLER_ASYNC_LOCKED_WIPHY, - struct iwl_esr_trans_fail_notif), + RX_HANDLER_GRP(DATA_PATH_GROUP, BEACON_FILTER_IN_NOTIF, + iwl_mvm_rx_beacon_filter_notif, + RX_HANDLER_ASYNC_LOCKED, + /* same size as v1 */ + struct iwl_beacon_filter_notif), }; #undef RX_HANDLER #undef RX_HANDLER_GRP @@ -658,7 +624,6 @@ static const struct iwl_hcmd_names iwl_mvm_mac_conf_names[] = { HCMD_NAME(STA_REMOVE_CMD), HCMD_NAME(STA_DISABLE_TX_CMD), HCMD_NAME(ROC_CMD), - HCMD_NAME(EMLSR_TRANS_FAIL_NOTIF), HCMD_NAME(ROC_NOTIF), HCMD_NAME(CHANNEL_SWITCH_ERROR_NOTIF), HCMD_NAME(MISSED_VAP_NOTIF), @@ -699,6 +664,7 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(ESR_MODE_NOTIF), HCMD_NAME(MONITOR_NOTIF), HCMD_NAME(THERMAL_DUAL_CHAIN_REQUEST), + HCMD_NAME(BEACON_FILTER_IN_NOTIF), HCMD_NAME(STA_PM_NOTIF), HCMD_NAME(MU_GROUP_MGMT_NOTIF), HCMD_NAME(RX_QUEUES_NOTIFICATION), @@ -1395,8 +1361,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, } } - mvm->bios_enable_puncturing = iwl_uefi_get_puncturing(&mvm->fwrt); - if (iwl_mvm_has_new_tx_api(mvm)) { /* * If we have the new TX/queue allocation API initialize them @@ -2053,7 +2017,7 @@ static void iwl_mvm_nic_error(struct iwl_op_mode *op_mode, if (type == IWL_ERR_TYPE_CMD_QUEUE_FULL) IWL_ERR(mvm, "Command queue full!\n"); - else if (!test_bit(STATUS_TRANS_DEAD, &mvm->trans->status) && + else if (!iwl_trans_is_dead(mvm->trans) && !test_and_clear_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status)) iwl_mvm_dump_nic_error_log(mvm); @@ -2155,6 +2119,17 @@ static void iwl_op_mode_mvm_time_point(struct iwl_op_mode *op_mode, iwl_dbg_tlv_time_point(&mvm->fwrt, tp_id, tp_data); } +static void iwl_mvm_dump(struct iwl_op_mode *op_mode) +{ + struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); + struct iwl_fw_runtime *fwrt = &mvm->fwrt; + + if (!iwl_trans_fw_running(fwrt->trans)) + return; + + iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, NULL); +} + #ifdef CONFIG_PM_SLEEP static void iwl_op_mode_mvm_device_powered_off(struct iwl_op_mode *op_mode) { @@ -2217,4 +2192,5 @@ static const struct iwl_op_mode_ops iwl_mvm_ops_mq = { IWL_MVM_COMMON_OPS, .rx = iwl_mvm_rx_mq, .rx_rss = iwl_mvm_rx_mq_rss, + .dump = iwl_mvm_dump, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c index 0057fddf88f0..610de29b7be0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c @@ -231,7 +231,6 @@ static void iwl_mvm_allow_uapsd_iterator(void *_data, u8 *mac, switch (vif->type) { case NL80211_IFTYPE_AP: case NL80211_IFTYPE_ADHOC: - case NL80211_IFTYPE_NAN: data->allow_uapsd = false; break; case NL80211_IFTYPE_STATION: diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index e89259de6f4c..06a4c9f74797 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2021 - 2023 Intel Corporation + * Copyright (C) 2021 - 2023, 2025 Intel Corporation */ #include "mvm.h" @@ -298,9 +298,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm) PTR_ERR(mvm->ptp_data.ptp_clock)); mvm->ptp_data.ptp_clock = NULL; } else if (mvm->ptp_data.ptp_clock) { - IWL_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", - mvm->ptp_data.ptp_clock_info.name, - ptp_clock_index(mvm->ptp_data.ptp_clock)); + IWL_DEBUG_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", + mvm->ptp_data.ptp_clock_info.name, + ptp_clock_index(mvm->ptp_data.ptp_clock)); } } @@ -312,9 +312,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm) void iwl_mvm_ptp_remove(struct iwl_mvm *mvm) { if (mvm->ptp_data.ptp_clock) { - IWL_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n", - mvm->ptp_data.ptp_clock_info.name, - ptp_clock_index(mvm->ptp_data.ptp_clock)); + IWL_DEBUG_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n", + mvm->ptp_data.ptp_clock_info.name, + ptp_clock_index(mvm->ptp_data.ptp_clock)); ptp_clock_unregister(mvm->ptp_data.ptp_clock); mvm->ptp_data.ptp_clock = NULL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h index 69259ebb966b..dfb062b7c5c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h @@ -411,6 +411,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta, * with the mac80211 subsystem. This should be performed prior to calling * ieee80211_register_hw * + * Return: negative error code, or 0 on success */ int iwl_mvm_rate_control_register(void); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c index 8eb0aa448c85..8fae0d41b119 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -877,28 +877,28 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, u32 rx_bytes[MAC_INDEX_AUX] = {}; int fw_link_id; - for (fw_link_id = 0; fw_link_id < ARRAY_SIZE(mvm->link_id_to_link_conf); + /* driver uses link ID == MAC ID */ + for (fw_link_id = 0; fw_link_id < ARRAY_SIZE(mvm->vif_id_to_mac); fw_link_id++) { struct iwl_stats_ntfy_per_link *link_stats; - struct ieee80211_bss_conf *bss_conf; - struct iwl_mvm_vif *mvmvif; struct iwl_mvm_vif_link_info *link_info; + struct iwl_mvm_vif *mvmvif; + struct ieee80211_vif *vif; int link_id; int sig; - bss_conf = iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, fw_link_id, - false); - if (!bss_conf) + vif = iwl_mvm_rcu_dereference_vif_id(mvm, fw_link_id, false); + if (!vif) continue; - if (bss_conf->vif->type != NL80211_IFTYPE_STATION) + if (vif->type != NL80211_IFTYPE_STATION) continue; - link_id = bss_conf->link_id; + link_id = vif->bss_conf.link_id; if (link_id >= ARRAY_SIZE(mvmvif->link)) continue; - mvmvif = iwl_mvm_vif_from_mac80211(bss_conf->vif); + mvmvif = iwl_mvm_vif_from_mac80211(vif); link_info = mvmvif->link[link_id]; if (!link_info) continue; @@ -916,8 +916,7 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, if (link_info->phy_ctxt && link_info->phy_ctxt->channel->band == NL80211_BAND_2GHZ) - iwl_mvm_bt_coex_update_link_esr(mvm, bss_conf->vif, - link_id); + iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id); /* make sure that beacon statistics don't go backwards with TCM * request to clear statistics @@ -927,8 +926,7 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, mvmvif->link[link_id]->beacon_stats.num_beacons; sig = -le32_to_cpu(link_stats->beacon_filter_average_energy); - iwl_mvm_update_link_sig(bss_conf->vif, sig, link_info, - bss_conf); + iwl_mvm_update_link_sig(vif, sig, link_info, &vif->bss_conf); if (WARN_ONCE(mvmvif->id >= MAC_INDEX_AUX, "invalid mvmvif id: %d", mvmvif->id)) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 077aadbf95db..62e76a79f621 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -246,13 +246,62 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, ieee80211_rx_napi(mvm->hw, sta, skb, napi); } +static bool iwl_mvm_used_average_energy(struct iwl_mvm *mvm, + struct iwl_rx_mpdu_desc *desc, + struct ieee80211_hdr *hdr, + struct ieee80211_rx_status *rx_status) +{ + struct iwl_mvm_vif *mvm_vif; + struct ieee80211_vif *vif; + u32 id; + + if (unlikely(!hdr || !desc)) + return false; + + if (likely(!ieee80211_is_beacon(hdr->frame_control))) + return false; + + /* for the link conf lookup */ + guard(rcu)(); + + /* MAC or link ID depending on FW, but driver has them equal */ + id = u8_get_bits(desc->mac_phy_band, + IWL_RX_MPDU_MAC_PHY_BAND_MAC_MASK); + + /* >= means AUX MAC/link ID, no energy correction needed then */ + if (id >= ARRAY_SIZE(mvm->vif_id_to_mac)) + return false; + + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); + if (!vif) + return false; + + mvm_vif = iwl_mvm_vif_from_mac80211(vif); + + /* + * If we know the MAC by MAC or link ID then the frame was + * received for the link, so by filtering it means it was + * from the AP the link is connected to. + */ + + /* skip also in case we don't have it (yet) */ + if (!mvm_vif->deflink.average_beacon_energy) + return false; + + IWL_DEBUG_STATS(mvm, "energy override by average %d\n", + mvm_vif->deflink.average_beacon_energy); + rx_status->signal = -mvm_vif->deflink.average_beacon_energy; + return true; +} + static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, + struct iwl_rx_mpdu_desc *desc, + struct ieee80211_hdr *hdr, struct ieee80211_rx_status *rx_status, u32 rate_n_flags, int energy_a, int energy_b) { int max_energy; - u32 rate_flags = rate_n_flags; energy_a = energy_a ? -energy_a : S8_MIN; energy_b = energy_b ? -energy_b : S8_MIN; @@ -261,9 +310,11 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm, IWL_DEBUG_STATS(mvm, "energy In A %d B %d, and max %d\n", energy_a, energy_b, max_energy); + if (iwl_mvm_used_average_energy(mvm, desc, hdr, rx_status)) + return; + rx_status->signal = max_energy; - rx_status->chains = - (rate_flags & RATE_MCS_ANT_AB_MSK) >> RATE_MCS_ANT_POS; + rx_status->chains = u32_get_bits(rate_n_flags, RATE_MCS_ANT_AB_MSK); rx_status->chain_signal[0] = energy_a; rx_status->chain_signal[1] = energy_b; } @@ -854,10 +905,15 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, * already ahead and it will be dropped. * If the last sub-frame is not on this queue - we will get frame * release notification with up to date NSSN. + * If this is the first frame that is stored in the buffer, the head_sn + * may be outdated. Update it based on the last NSSN to make sure it + * will be released when the frame release notification arrives. */ if (!amsdu || last_subframe) iwl_mvm_release_frames(mvm, sta, napi, baid_data, buffer, nssn); + else if (buffer->num_stored == 1) + buffer->head_sn = nssn; spin_unlock_bh(&buffer->lock); return true; @@ -1906,8 +1962,11 @@ static void iwl_mvm_rx_get_sta_block_tx(void *data, struct ieee80211_sta *sta) /* * Note: requires also rx_status->band to be prefilled, as well * as phy_data (apart from phy_data->info_type) + * Note: desc/hdr may be NULL */ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm, + struct iwl_rx_mpdu_desc *desc, + struct ieee80211_hdr *hdr, struct sk_buff *skb, struct iwl_mvm_rx_phy_data *phy_data, int queue) @@ -1962,7 +2021,7 @@ static void iwl_mvm_rx_fill_status(struct iwl_mvm *mvm, rx_status->freq = ieee80211_channel_to_frequency(phy_data->channel, rx_status->band); - iwl_mvm_get_signal_strength(mvm, rx_status, rate_n_flags, + iwl_mvm_get_signal_strength(mvm, desc, hdr, rx_status, rate_n_flags, phy_data->energy_a, phy_data->energy_b); /* using TLV format and must be after all fixed len fields */ @@ -2215,7 +2274,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, goto out; } - iwl_mvm_rx_fill_status(mvm, skb, &phy_data, queue); + iwl_mvm_rx_fill_status(mvm, desc, hdr, skb, &phy_data, queue); if (sta) { struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); @@ -2445,7 +2504,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, rx_status->band = phy_data.channel > 14 ? NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; - iwl_mvm_rx_fill_status(mvm, skb, &phy_data, queue); + iwl_mvm_rx_fill_status(mvm, NULL, NULL, skb, &phy_data, queue); /* no more radio tap info should be put after this point. * @@ -2548,3 +2607,28 @@ void iwl_mvm_rx_bar_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, out: rcu_read_unlock(); } + +void iwl_mvm_rx_beacon_filter_notif(struct iwl_mvm *mvm, + struct iwl_rx_cmd_buffer *rxb) +{ + struct iwl_rx_packet *pkt = rxb_addr(rxb); + /* MAC or link ID in v1/v2, but driver has the IDs equal */ + struct iwl_beacon_filter_notif *notif = (void *)pkt->data; + u32 id = le32_to_cpu(notif->link_id); + struct iwl_mvm_vif *mvm_vif; + struct ieee80211_vif *vif; + + /* >= means AUX MAC/link ID, no energy correction needed then */ + if (IWL_FW_CHECK(mvm, id >= ARRAY_SIZE(mvm->vif_id_to_mac), + "invalid link ID %d\n", id)) + return; + + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, false); + if (!vif) + return; + + mvm_vif = iwl_mvm_vif_from_mac80211(vif); + + mvm_vif->deflink.average_beacon_energy = + le32_to_cpu(notif->average_energy); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 60bd9c7e5f03..9ce1ce0dab34 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-2024 Intel Corporation + * Copyright (C) 2012-2014, 2018-2025 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -11,6 +11,7 @@ #include "mvm.h" #include "fw/api/scan.h" #include "iwl-io.h" +#include "iwl-utils.h" #define IWL_DENSE_EBS_SCAN_RATIO 5 #define IWL_SPARSE_EBS_SCAN_RATIO 1 @@ -835,7 +836,7 @@ static inline bool iwl_mvm_scan_fits(struct iwl_mvm *mvm, int n_ssids, int n_channels) { return ((n_ssids <= PROBE_OPTION_MAX) && - (n_channels <= mvm->fw->ucode_capa.n_scan_channels) & + (n_channels <= mvm->fw->ucode_capa.n_scan_channels) && (ies->common_ie_len + ies->len[NL80211_BAND_2GHZ] + ies->len[NL80211_BAND_5GHZ] + ies->len[NL80211_BAND_6GHZ] <= @@ -3546,7 +3547,7 @@ int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify) if (!(mvm->scan_status & type)) return 0; - if (!test_bit(STATUS_DEVICE_ENABLED, &mvm->trans->status)) { + if (!iwl_trans_device_enabled(mvm->trans)) { ret = 0; goto out; } @@ -3685,117 +3686,6 @@ static int iwl_mvm_chanidx_from_phy(struct iwl_mvm *mvm, return -EINVAL; } -static u32 iwl_mvm_div_by_db(u32 value, u8 db) -{ - /* - * 2^32 * 10**(i / 10) for i = [1, 10], skipping 0 and simply stopping - * at 10 dB and looping instead of using a much larger table. - * - * Using 64 bit math is overkill, but means the helper does not require - * a limit on the input range. - */ - static const u32 db_to_val[] = { - 0xcb59185e, 0xa1866ba8, 0x804dce7a, 0x65ea59fe, 0x50f44d89, - 0x404de61f, 0x331426af, 0x2892c18b, 0x203a7e5b, 0x1999999a, - }; - - while (value && db > 0) { - u8 change = min_t(u8, db, ARRAY_SIZE(db_to_val)); - - value = (((u64)value) * db_to_val[change - 1]) >> 32; - - db -= change; - } - - return value; -} - -VISIBLE_IF_IWLWIFI_KUNIT s8 -iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif) -{ - s8 average_magnitude; - u32 average_factor; - s8 sum_magnitude = -128; - u32 sum_factor = 0; - int i, count = 0; - - /* - * To properly average the decibel values (signal values given in dBm) - * we need to do the math in linear space. Doing a linear average of - * dB (dBm) values is a bit annoying though due to the large range of - * at least -10 to -110 dBm that will not fit into a 32 bit integer. - * - * A 64 bit integer should be sufficient, but then we still have the - * problem that there are no directly usable utility functions - * available. - * - * So, lets not deal with that and instead do much of the calculation - * with a 16.16 fixed point integer along with a base in dBm. 16.16 bit - * gives us plenty of head-room for adding up a few values and even - * doing some math on it. And the tail should be accurate enough too - * (1/2^16 is somewhere around -48 dB, so effectively zero). - * - * i.e. the real value of sum is: - * sum = sum_factor / 2^16 * 10^(sum_magnitude / 10) mW - * - * However, that does mean we need to be able to bring two values to - * a common base, so we need a helper for that. - * - * Note that this function takes an input with unsigned negative dBm - * values but returns a signed dBm (i.e. a negative value). - */ - - for (i = 0; i < ARRAY_SIZE(notif->noise); i++) { - s8 val_magnitude; - u32 val_factor; - - if (notif->noise[i] == 0xff) - continue; - - val_factor = 0x10000; - val_magnitude = -notif->noise[i]; - - if (val_magnitude <= sum_magnitude) { - u8 div_db = sum_magnitude - val_magnitude; - - val_factor = iwl_mvm_div_by_db(val_factor, div_db); - val_magnitude = sum_magnitude; - } else { - u8 div_db = val_magnitude - sum_magnitude; - - sum_factor = iwl_mvm_div_by_db(sum_factor, div_db); - sum_magnitude = val_magnitude; - } - - sum_factor += val_factor; - count++; - } - - /* No valid noise measurement, return a very high noise level */ - if (count == 0) - return 0; - - average_magnitude = sum_magnitude; - average_factor = sum_factor / count; - - /* - * average_factor will be a number smaller than 1.0 (0x10000) at this - * point. What we need to do now is to adjust average_magnitude so that - * average_factor is between -0.5 dB and 0.5 dB. - * - * Just do -1 dB steps and find the point where - * -0.5 dB * -i dB = 0x10000 * 10^(-0.5/10) / i dB - * = div_by_db(0xe429, i) - * is smaller than average_factor. - */ - for (i = 0; average_factor < iwl_mvm_div_by_db(0xe429, i); i++) { - /* nothing */ - } - - return average_magnitude - i; -} -EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_average_dbm_values); - void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { @@ -3853,5 +3743,6 @@ void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm, info->time_busy = le32_to_cpu(notif->busy_time); info->time_rx = le32_to_cpu(notif->rx_time); info->time_tx = le32_to_cpu(notif->tx_time); - info->noise = iwl_mvm_average_dbm_values(notif); + info->noise = + iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise)); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 5f6797598998..11c6b86db4ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -2461,7 +2461,7 @@ void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm, mvmvif->deflink.bcast_sta.tfd_queue_msk &= ~BIT(queue); } -/* Send the FW a request to remove the station from it's internal data +/* Send the FW a request to remove the station from its internal data * structures, but DO NOT remove the entry from the local data structures. */ int iwl_mvm_send_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -2524,7 +2524,7 @@ void iwl_mvm_dealloc_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) } /* - * Send the FW a request to remove the station from it's internal data + * Send the FW a request to remove the station from its internal data * structures, and in addition remove it from the local data structure. */ int iwl_mvm_rm_p2p_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) @@ -2677,7 +2677,7 @@ static int __iwl_mvm_remove_sta_key(struct iwl_mvm *mvm, u8 sta_id, } /* - * Send the FW a request to remove the station from it's internal data + * Send the FW a request to remove the station from its internal data * structures, and in addition remove it from the local data structure. */ int iwl_mvm_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 6b183f5e9bbc..f6906061510b 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h @@ -214,7 +214,7 @@ struct iwl_mvm_vif; */ /** - * enum iwl_mvm_agg_state + * enum iwl_mvm_agg_state - aggregation session state * * The state machine of the BA agreement establishment / tear down. * These states relate to a specific RA / TID. @@ -483,6 +483,7 @@ struct iwl_mvm_int_sta { * about. Otherwise (if this is a new STA), this should be false. * @flags: if update==true, this marks what is being changed via ORs of values * from enum iwl_sta_modify_flag. Otherwise, this is ignored. + * Return: negative error code or 0 on success */ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta, bool update, unsigned int flags); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile index 895d53f223e9..bb33f4a06f1c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile @@ -1,3 +1,3 @@ -iwlmvm-tests-y += module.o links.o scan.o hcmd.o +iwlmvm-tests-y += module.o links.o hcmd.o obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += iwlmvm-tests.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 478408f802d9..aa653782d6d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -958,40 +958,19 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_session_prot_notif *notif = (void *)pkt->data; - unsigned int ver = - iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, - SESSION_PROTECTION_NOTIF, 2); int id = le32_to_cpu(notif->mac_link_id); struct ieee80211_vif *vif; struct iwl_mvm_vif *mvmvif; - unsigned int notif_link_id; rcu_read_lock(); - if (ver <= 2) { - vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); - } else { - struct ieee80211_bss_conf *link_conf = - iwl_mvm_rcu_fw_link_id_to_link_conf(mvm, id, true); - - if (!link_conf) - goto out_unlock; - - notif_link_id = link_conf->link_id; - vif = link_conf->vif; - } - + /* note we use link ID == MAC ID */ + vif = iwl_mvm_rcu_dereference_vif_id(mvm, id, true); if (!vif) goto out_unlock; mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (WARN(ver > 2 && mvmvif->time_event_data.link_id >= 0 && - mvmvif->time_event_data.link_id != notif_link_id, - "SESSION_PROTECTION_NOTIF was received for link %u, while the current time event is on link %u\n", - notif_link_id, mvmvif->time_event_data.link_id)) - goto out_unlock; - /* The vif is not a P2P_DEVICE, maintain its time_event_data */ if (vif->type != NL80211_IFTYPE_P2P_DEVICE) { struct iwl_mvm_time_event_data *te_data = diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h index 49256ba4cf58..1ef8768756db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2019-2020, 2023 Intel Corporation + * Copyright (C) 2012-2014, 2019-2020, 2023, 2025 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH */ #ifndef __time_event_h__ @@ -124,6 +124,8 @@ void iwl_mvm_rx_roc_notif(struct iwl_mvm *mvm, * ROC request, it will issue a notification to the driver that it is on the * requested channel. Once the FW completes the ROC request it will issue * another notification to the driver. + * + * Return: negative error code or 0 on success */ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif, int duration, enum ieee80211_roc_type type); @@ -179,6 +181,8 @@ void iwl_mvm_remove_csa_period(struct iwl_mvm *mvm, * * This function is used to schedule NoA time event and is used to perform * the channel switch flow. + * + * Return: negative error code or 0 on success */ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -188,7 +192,7 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm, * iwl_mvm_te_scheduled - check if the fw received the TE cmd * @te_data: the time event data that corresponds to that time event * - * This function returns true iff this TE is added to the fw. + * Return: %true if this TE is added to the fw, %false otherwise */ static inline bool iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c index ac2cf1b8ce23..25d1a882a6a0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c @@ -148,12 +148,12 @@ out: * Sets most of the Tx cmd's fields */ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, - struct iwl_tx_cmd_v6 *tx_cmd, + struct iwl_tx_cmd_v6_params *tx_cmd_params, struct ieee80211_tx_info *info, u8 sta_id) { struct ieee80211_hdr *hdr = (void *)skb->data; __le16 fc = hdr->frame_control; - u32 tx_flags = le32_to_cpu(tx_cmd->tx_flags); + u32 tx_flags = le32_to_cpu(tx_cmd_params->tx_flags); u32 len = skb->len + FCS_LEN; bool amsdu = false; u8 ac; @@ -173,7 +173,7 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, if (ieee80211_is_data_qos(fc)) { u8 *qc = ieee80211_get_qos_ctl(hdr); - tx_cmd->tid_tspec = qc[0] & 0xf; + tx_cmd_params->tid_tspec = qc[0] & 0xf; tx_flags &= ~TX_CMD_FLG_SEQ_CTL; amsdu = *qc & IEEE80211_QOS_CTL_A_MSDU_PRESENT; } else if (ieee80211_is_back_req(fc)) { @@ -182,17 +182,17 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, u16 ssn = le16_to_cpu(bar->start_seq_num); tx_flags |= TX_CMD_FLG_ACK | TX_CMD_FLG_BAR; - tx_cmd->tid_tspec = (control & + tx_cmd_params->tid_tspec = (control & IEEE80211_BAR_CTRL_TID_INFO_MASK) >> IEEE80211_BAR_CTRL_TID_INFO_SHIFT; - WARN_ON_ONCE(tx_cmd->tid_tspec >= IWL_MAX_TID_COUNT); - iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd->tid_tspec, + WARN_ON_ONCE(tx_cmd_params->tid_tspec >= IWL_MAX_TID_COUNT); + iwl_mvm_bar_check_trigger(mvm, bar->ra, tx_cmd_params->tid_tspec, ssn); } else { if (ieee80211_is_data(fc)) - tx_cmd->tid_tspec = IWL_TID_NON_QOS; + tx_cmd_params->tid_tspec = IWL_TID_NON_QOS; else - tx_cmd->tid_tspec = IWL_MAX_TID_COUNT; + tx_cmd_params->tid_tspec = IWL_MAX_TID_COUNT; if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) tx_flags |= TX_CMD_FLG_SEQ_CTL; @@ -201,8 +201,8 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, } /* Default to 0 (BE) when tid_spec is set to IWL_MAX_TID_COUNT */ - if (tx_cmd->tid_tspec < IWL_MAX_TID_COUNT) - ac = tid_to_mac80211_ac[tx_cmd->tid_tspec]; + if (tx_cmd_params->tid_tspec < IWL_MAX_TID_COUNT) + ac = tid_to_mac80211_ac[tx_cmd_params->tid_tspec]; else ac = tid_to_mac80211_ac[0]; @@ -211,20 +211,20 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, if (ieee80211_is_mgmt(fc)) { if (ieee80211_is_assoc_req(fc) || ieee80211_is_reassoc_req(fc)) - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_ASSOC); else if (ieee80211_is_action(fc)) - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); else - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); /* The spec allows Action frames in A-MPDU, we don't support * it */ WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_AMPDU); } else if (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) { - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_MGMT); } else { - tx_cmd->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); + tx_cmd_params->pm_frame_timeout = cpu_to_le16(PM_FRAME_NONE); } if (ieee80211_is_data(fc) && len > mvm->rts_threshold && @@ -236,13 +236,13 @@ void iwl_mvm_set_tx_cmd(struct iwl_mvm *mvm, struct sk_buff *skb, ieee80211_action_contains_tpc(skb)) tx_flags |= TX_CMD_FLG_WRITE_TX_POWER; - tx_cmd->tx_flags = cpu_to_le32(tx_flags); + tx_cmd_params->tx_flags = cpu_to_le32(tx_flags); /* Total # bytes to be transmitted - PCIe code will adjust for A-MSDU */ - tx_cmd->len = cpu_to_le16((u16)skb->len); - tx_cmd->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); - tx_cmd->sta_id = sta_id; + tx_cmd_params->len = cpu_to_le16((u16)skb->len); + tx_cmd_params->life_time = cpu_to_le32(TX_CMD_LIFE_TIME_INFINITE); + tx_cmd_params->sta_id = sta_id; - tx_cmd->offload_assist = + tx_cmd_params->offload_assist = cpu_to_le16(iwl_mvm_tx_csum(mvm, skb, info, amsdu)); } @@ -395,22 +395,23 @@ static __le32 iwl_mvm_get_tx_rate_n_flags(struct iwl_mvm *mvm, /* * Sets the fields in the Tx cmd that are rate related */ -void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd_v6 *tx_cmd, - struct ieee80211_tx_info *info, - struct ieee80211_sta *sta, __le16 fc) +void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, + struct iwl_tx_cmd_v6_params *tx_cmd_params, + struct ieee80211_tx_info *info, + struct ieee80211_sta *sta, __le16 fc) { /* Set retry limit on RTS packets */ - tx_cmd->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT; + tx_cmd_params->rts_retry_limit = IWL_RTS_DFAULT_RETRY_LIMIT; /* Set retry limit on DATA packets and Probe Responses*/ if (ieee80211_is_probe_resp(fc)) { - tx_cmd->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT; - tx_cmd->rts_retry_limit = - min(tx_cmd->data_retry_limit, tx_cmd->rts_retry_limit); + tx_cmd_params->data_retry_limit = IWL_MGMT_DFAULT_RETRY_LIMIT; + tx_cmd_params->rts_retry_limit = + min(tx_cmd_params->data_retry_limit, tx_cmd_params->rts_retry_limit); } else if (ieee80211_is_back_req(fc)) { - tx_cmd->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT; + tx_cmd_params->data_retry_limit = IWL_BAR_DFAULT_RETRY_LIMIT; } else { - tx_cmd->data_retry_limit = IWL_DEFAULT_TX_RETRY; + tx_cmd_params->data_retry_limit = IWL_DEFAULT_TX_RETRY; } /* @@ -423,17 +424,17 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd_v6 *tx_cmd, struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); if (mvmsta->sta_state >= IEEE80211_STA_AUTHORIZED) { - tx_cmd->initial_rate_index = 0; - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); + tx_cmd_params->initial_rate_index = 0; + tx_cmd_params->tx_flags |= cpu_to_le32(TX_CMD_FLG_STA_RATE); return; } } else if (ieee80211_is_back_req(fc)) { - tx_cmd->tx_flags |= + tx_cmd_params->tx_flags |= cpu_to_le32(TX_CMD_FLG_ACK | TX_CMD_FLG_BAR); } /* Set the rate in the TX cmd */ - tx_cmd->rate_n_flags = iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, fc); + tx_cmd_params->rate_n_flags = iwl_mvm_get_tx_rate_n_flags(mvm, info, sta, fc); } static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info, @@ -458,7 +459,7 @@ static inline void iwl_mvm_set_tx_cmd_pn(struct ieee80211_tx_info *info, */ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, struct ieee80211_tx_info *info, - struct iwl_tx_cmd_v6 *tx_cmd, + struct iwl_tx_cmd_v6_params *tx_cmd_params, struct sk_buff *skb_frag, int hdrlen) { @@ -469,26 +470,26 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, switch (keyconf->cipher) { case WLAN_CIPHER_SUITE_CCMP: - iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd); + iwl_mvm_set_tx_cmd_ccmp(info, tx_cmd_params); iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; case WLAN_CIPHER_SUITE_TKIP: - tx_cmd->sec_ctl = TX_CMD_SEC_TKIP; + tx_cmd_params->sec_ctl = TX_CMD_SEC_TKIP; pn = atomic64_inc_return(&keyconf->tx_pn); ieee80211_tkip_add_iv(crypto_hdr, keyconf, pn); - ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd->key); + ieee80211_get_tkip_p2k(keyconf, skb_frag, tx_cmd_params->key); break; case WLAN_CIPHER_SUITE_WEP104: - tx_cmd->sec_ctl |= TX_CMD_SEC_KEY128; + tx_cmd_params->sec_ctl |= TX_CMD_SEC_KEY128; fallthrough; case WLAN_CIPHER_SUITE_WEP40: - tx_cmd->sec_ctl |= TX_CMD_SEC_WEP | + tx_cmd_params->sec_ctl |= TX_CMD_SEC_WEP | ((keyconf->keyidx << TX_CMD_SEC_WEP_KEY_IDX_POS) & TX_CMD_SEC_WEP_KEY_IDX_MSK); - memcpy(&tx_cmd->key[3], keyconf->key, keyconf->keylen); + memcpy(&tx_cmd_params->key[3], keyconf->key, keyconf->keylen); break; case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_GCMP_256: @@ -501,12 +502,12 @@ static void iwl_mvm_set_tx_cmd_crypto(struct iwl_mvm *mvm, * one. * Need to handle this. */ - tx_cmd->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; - tx_cmd->key[0] = keyconf->hw_key_idx; + tx_cmd_params->sec_ctl |= type | TX_CMD_SEC_KEY_FROM_TABLE; + tx_cmd_params->key[0] = keyconf->hw_key_idx; iwl_mvm_set_tx_cmd_pn(info, crypto_hdr); break; default: - tx_cmd->sec_ctl |= TX_CMD_SEC_EXT; + tx_cmd_params->sec_ctl |= TX_CMD_SEC_EXT; } } @@ -636,11 +637,11 @@ iwl_mvm_set_tx_params(struct iwl_mvm *mvm, struct sk_buff *skb, tx_cmd = (struct iwl_tx_cmd_v6 *)dev_cmd->payload; if (info->control.hw_key) - iwl_mvm_set_tx_cmd_crypto(mvm, info, tx_cmd, skb, hdrlen); + iwl_mvm_set_tx_cmd_crypto(mvm, info, &tx_cmd->params, skb, hdrlen); - iwl_mvm_set_tx_cmd(mvm, skb, tx_cmd, info, sta_id); + iwl_mvm_set_tx_cmd(mvm, skb, &tx_cmd->params, info, sta_id); - iwl_mvm_set_tx_cmd_rate(mvm, tx_cmd, info, sta, hdr->frame_control); + iwl_mvm_set_tx_cmd_rate(mvm, &tx_cmd->params, info, sta, hdr->frame_control); /* Copy MAC header from skb into command buffer */ iwl_mvm_copy_hdr(tx_cmd->hdr, hdr, hdrlen, addr3_override); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-v2.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-v2.c index 976fd1f58da4..06be929a3ca5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-v2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-v2.c @@ -6,7 +6,7 @@ #include "iwl-trans.h" #include "iwl-fh.h" #include "iwl-context-info-v2.h" -#include "internal.h" +#include "gen1_2/internal.h" #include "iwl-prph.h" static const struct dmi_system_id dmi_force_scu_active_approved_list[] = { @@ -391,13 +391,13 @@ static int iwl_pcie_load_payloads_segments { struct iwl_dram_data *cur_payload_dram = &dram_regions->drams[0]; struct iwl_dram_data *desc_dram = &dram_regions->prph_scratch_mem_desc; - struct iwl_prph_scrath_mem_desc_addr_array *addresses; + struct iwl_prph_scratch_mem_desc_addr_array *addresses; const void *data; u32 len; int i; /* allocate and init DRAM descriptors array */ - len = sizeof(struct iwl_prph_scrath_mem_desc_addr_array); + len = sizeof(struct iwl_prph_scratch_mem_desc_addr_array); desc_dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent (trans, len, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 4f2be0c1bd97..0957223c776d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -6,7 +6,7 @@ #include "iwl-trans.h" #include "iwl-fh.h" #include "iwl-context-info.h" -#include "internal.h" +#include "gen1_2/internal.h" #include "iwl-prph.h" static void *_iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 0a9e0dbb58fb..b7add05f7a85 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -15,7 +15,7 @@ #include "iwl-trans.h" #include "iwl-drv.h" #include "iwl-prph.h" -#include "internal.h" +#include "gen1_2/internal.h" #define _IS_A(cfg, _struct) __builtin_types_compatible_p(typeof(cfg), \ struct _struct) @@ -501,7 +501,7 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x2729, PCI_ANY_ID, iwl_ma_mac_cfg)}, {IWL_PCI_DEVICE(0x7E40, PCI_ANY_ID, iwl_ma_mac_cfg)}, #endif /* CONFIG_IWLMVM */ -#if IS_ENABLED(CONFIG_IWLMLD) +#if IS_ENABLED(CONFIG_IWLMVM) || IS_ENABLED(CONFIG_IWLMLD) /* Bz devices */ {IWL_PCI_DEVICE(0x272b, PCI_ANY_ID, iwl_gl_mac_cfg)}, {IWL_PCI_DEVICE(0xA840, 0x0000, iwl_bz_mac_cfg)}, @@ -545,7 +545,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0xE340, PCI_ANY_ID, iwl_sc_mac_cfg)}, {IWL_PCI_DEVICE(0xD340, PCI_ANY_ID, iwl_sc_mac_cfg)}, {IWL_PCI_DEVICE(0x6E70, PCI_ANY_ID, iwl_sc_mac_cfg)}, -#endif /* CONFIG_IWLMLD */ + {IWL_PCI_DEVICE(0xD240, PCI_ANY_ID, iwl_sc_mac_cfg)}, +#endif /* CONFIG_IWLMVM || CONFIG_IWLMLD */ {0} }; @@ -576,8 +577,10 @@ EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_hw_card_ids); .subdevice_m_h = _HIGHEST_BIT(m) #define RF_TYPE(n) .match_rf_type = 1, \ .rf_type = IWL_CFG_RF_TYPE_##n -#define RF_STEP(n) .match_rf_step = 1, \ - .rf_step = SILICON_##n##_STEP +#define DISCRETE .match_discrete = 1, \ + .discrete = 1 +#define INTEGRATED .match_discrete = 1, \ + .discrete = 0 #define RF_ID(n) .match_rf_id = 1, \ .rf_id = IWL_CFG_RF_ID_##n #define NO_CDB .match_cdb = 1, .cdb = 0 @@ -1031,9 +1034,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { /* FM RF */ IWL_DEV_INFO(iwl_rf_fm, iwl_be201_name, RF_TYPE(FM)), IWL_DEV_INFO(iwl_rf_fm, iwl_be401_name, RF_TYPE(FM), CDB), - /* the discrete NICs got the RF B0, it's only for the name anyway */ IWL_DEV_INFO(iwl_rf_fm, iwl_be200_name, RF_TYPE(FM), - DEVICE(0x272B), RF_STEP(B)), + DEVICE(0x272B), DISCRETE), IWL_DEV_INFO(iwl_rf_fm_160mhz, iwl_be202_name, RF_TYPE(FM), BW_LIMITED), @@ -1073,149 +1075,12 @@ const unsigned int iwl_dev_info_table_size = ARRAY_SIZE(iwl_dev_info_table); EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_dev_info_table_size); #endif -/* - * Read rf id and cdb info from prph register and store it - */ -static void get_crf_id(struct iwl_trans *iwl_trans, - struct iwl_trans_info *info) -{ - u32 sd_reg_ver_addr; - u32 hw_wfpm_id; - u32 val = 0; - u8 step; - - if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - sd_reg_ver_addr = SD_REG_VER_GEN2; - else - sd_reg_ver_addr = SD_REG_VER; - - /* Enable access to peripheral registers */ - val = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG); - val |= WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK; - iwl_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val); - - /* Read crf info */ - info->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr); - - /* Read cnv info */ - info->hw_cnv_id = iwl_read_prph_no_grab(iwl_trans, CNVI_AUX_MISC_CHIP); - - /* For BZ-W, take B step also when A step is indicated */ - if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) - step = SILICON_B_STEP; - - /* In BZ, the MAC step must be read from the CNVI aux register */ - if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ) { - step = CNVI_AUX_MISC_CHIP_MAC_STEP(info->hw_cnv_id); - - /* For BZ-U, take B step also when A step is indicated */ - if ((CNVI_AUX_MISC_CHIP_PROD_TYPE(info->hw_cnv_id) == - CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U) && - step == SILICON_A_STEP) - step = SILICON_B_STEP; - } - - if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ || - CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) { - info->hw_rev_step = step; - info->hw_rev |= step; - } - - /* Read cdb info (also contains the jacket info if needed in the future */ - hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); - IWL_INFO(iwl_trans, "Detected crf-id 0x%x, cnv-id 0x%x wfpm id 0x%x\n", - info->hw_crf_id, info->hw_cnv_id, hw_wfpm_id); -} - -/* - * In case that there is no OTP on the NIC, map the rf id and cdb info - * from the prph registers. - */ -static int map_crf_id(struct iwl_trans *iwl_trans, - struct iwl_trans_info *info) -{ - int ret = 0; - u32 val = info->hw_crf_id; - u32 step_id = REG_CRF_ID_STEP(val); - u32 slave_id = REG_CRF_ID_SLAVE(val); - u32 jacket_id_cnv = REG_CRF_ID_SLAVE(info->hw_cnv_id); - u32 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, - WFPM_OTP_CFG1_ADDR); - u32 jacket_id_wfpm = WFPM_OTP_CFG1_IS_JACKET(hw_wfpm_id); - u32 cdb_id_wfpm = WFPM_OTP_CFG1_IS_CDB(hw_wfpm_id); - - /* Map between crf id to rf id */ - switch (REG_CRF_ID_TYPE(val)) { - case REG_CRF_ID_TYPE_JF_1: - info->hw_rf_id = (IWL_CFG_RF_TYPE_JF1 << 12); - break; - case REG_CRF_ID_TYPE_JF_2: - info->hw_rf_id = (IWL_CFG_RF_TYPE_JF2 << 12); - break; - case REG_CRF_ID_TYPE_HR_NONE_CDB_1X1: - info->hw_rf_id = (IWL_CFG_RF_TYPE_HR1 << 12); - break; - case REG_CRF_ID_TYPE_HR_NONE_CDB: - info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12); - break; - case REG_CRF_ID_TYPE_HR_CDB: - info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12); - break; - case REG_CRF_ID_TYPE_GF: - info->hw_rf_id = (IWL_CFG_RF_TYPE_GF << 12); - break; - case REG_CRF_ID_TYPE_FM: - info->hw_rf_id = (IWL_CFG_RF_TYPE_FM << 12); - break; - case REG_CRF_ID_TYPE_WHP: - info->hw_rf_id = (IWL_CFG_RF_TYPE_WH << 12); - break; - case REG_CRF_ID_TYPE_PE: - info->hw_rf_id = (IWL_CFG_RF_TYPE_PE << 12); - break; - default: - ret = -EIO; - IWL_ERR(iwl_trans, - "Can't find a correct rfid for crf id 0x%x\n", - REG_CRF_ID_TYPE(val)); - goto out; - - } - - /* Set Step-id */ - info->hw_rf_id |= (step_id << 8); - - /* Set CDB capabilities */ - if (cdb_id_wfpm || slave_id) { - info->hw_rf_id += BIT(28); - IWL_INFO(iwl_trans, "Adding cdb to rf id\n"); - } - - /* Set Jacket capabilities */ - if (jacket_id_wfpm || jacket_id_cnv) { - info->hw_rf_id += BIT(29); - IWL_INFO(iwl_trans, "Adding jacket to rf id\n"); - } - - IWL_INFO(iwl_trans, - "Detected rf-type 0x%x step-id 0x%x slave-id 0x%x from crf id 0x%x\n", - REG_CRF_ID_TYPE(val), step_id, slave_id, info->hw_rf_id); - IWL_INFO(iwl_trans, - "Detected cdb-id 0x%x jacket-id 0x%x from wfpm id 0x%x\n", - cdb_id_wfpm, jacket_id_wfpm, hw_wfpm_id); - IWL_INFO(iwl_trans, "Detected jacket-id 0x%x from cnvi id 0x%x\n", - jacket_id_cnv, info->hw_cnv_id); - -out: - return ret; -} - /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 -VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info * +const struct iwl_dev_info * iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, - u8 rf_id, u8 bw_limit, u8 rf_step) + u8 rf_id, u8 bw_limit, bool discrete) { int num_devices = ARRAY_SIZE(iwl_dev_info_table); int i; @@ -1250,7 +1115,7 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, if (dev_info->match_bw_limit && dev_info->bw_limit != bw_limit) continue; - if (dev_info->match_rf_step && dev_info->rf_step != rf_step) + if (dev_info->match_discrete && dev_info->discrete != discrete) continue; return dev_info; @@ -1260,193 +1125,47 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, } EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_pci_find_dev_info); -static void iwl_pcie_recheck_me_status(struct work_struct *wk) -{ - struct iwl_trans_pcie *trans_pcie = container_of(wk, - typeof(*trans_pcie), - me_recheck_wk.work); - u32 val; - - val = iwl_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG); - trans_pcie->me_present = !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP); -} - -static void iwl_pcie_check_me_status(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 val; - - trans_pcie->me_present = -1; - - INIT_DELAYED_WORK(&trans_pcie->me_recheck_wk, - iwl_pcie_recheck_me_status); - - /* we don't have a good way of determining this until BZ */ - if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ) - return; - - val = iwl_read_prph(trans, CNVI_SCU_REG_FOR_ECO_1); - if (val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN) { - trans_pcie->me_present = - !!(val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT); - return; - } - - val = iwl_read32(trans, CSR_HW_IF_CONFIG_REG); - if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN | - CSR_HW_IF_CONFIG_REG_IAMT_UP)) { - trans_pcie->me_present = 1; - return; - } - - /* recheck again later, ME might still be initializing */ - schedule_delayed_work(&trans_pcie->me_recheck_wk, HZ); -} - static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - const struct iwl_mac_cfg *trans; - const struct iwl_dev_info *dev_info; - struct iwl_trans_info info = { - .hw_id = (pdev->device << 16) + pdev->subsystem_device, - }; - struct iwl_trans *iwl_trans; - struct iwl_trans_pcie *trans_pcie; + const struct iwl_mac_cfg *mac_cfg = (void *)ent->driver_data; + u8 __iomem *hw_base; + u32 bar0, hw_rev; int ret; - trans = (void *)ent->driver_data; - - iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info); - if (IS_ERR(iwl_trans)) - return PTR_ERR(iwl_trans); - - trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); - - iwl_trans_pcie_check_product_reset_status(pdev); - iwl_trans_pcie_check_product_reset_mode(pdev); - - /* set the things we know so far for the grab NIC access */ - iwl_trans_set_info(iwl_trans, &info); - - /* - * Let's try to grab NIC access early here. Sometimes, NICs may - * fail to initialize, and if that happens it's better if we see - * issues early on (and can reprobe, per the logic inside), than - * first trying to load the firmware etc. and potentially only - * detecting any problems when the first interface is brought up. - */ - ret = iwl_pcie_prepare_card_hw(iwl_trans); - if (!ret) { - ret = iwl_finish_nic_init(iwl_trans); + /* reassign our BAR 0 if invalid due to possible runtime PM races */ + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0); + if (bar0 == PCI_BASE_ADDRESS_MEM_TYPE_64) { + ret = pci_assign_resource(pdev, 0); if (ret) - goto out_free_trans; - if (iwl_trans_grab_nic_access(iwl_trans)) { - get_crf_id(iwl_trans, &info); - /* all good */ - iwl_trans_release_nic_access(iwl_trans); - } else { - ret = -EIO; - goto out_free_trans; - } - } - - info.hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID); - - /* - * The RF_ID is set to zero in blank OTP so read version to - * extract the RF_ID. - * This is relevant only for family 9000 and up. - */ - if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000 && - !CSR_HW_RFID_TYPE(info.hw_rf_id) && map_crf_id(iwl_trans, &info)) { - ret = -EINVAL; - goto out_free_trans; - } - - IWL_INFO(iwl_trans, "PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", - pdev->device, pdev->subsystem_device, - info.hw_rev, info.hw_rf_id); - - dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device, - CSR_HW_RFID_TYPE(info.hw_rf_id), - CSR_HW_RFID_IS_CDB(info.hw_rf_id), - IWL_SUBDEVICE_RF_ID(pdev->subsystem_device), - IWL_SUBDEVICE_BW_LIM(pdev->subsystem_device), - CSR_HW_RFID_STEP(info.hw_rf_id)); - if (dev_info) { - iwl_trans->cfg = dev_info->cfg; - info.name = dev_info->name; + return ret; } -#if IS_ENABLED(CONFIG_IWLMVM) - /* - * special-case 7265D, it has the same PCI IDs. - * - * Note that because we already pass the cfg to the transport above, - * all the parameters that the transport uses must, until that is - * changed, be identical to the ones in the 7265D configuration. - */ - if (iwl_trans->cfg == &iwl7265_cfg && - (info.hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) - iwl_trans->cfg = &iwl7265d_cfg; -#endif - if (!iwl_trans->cfg) { - pr_err("No config found for PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", - pdev->device, pdev->subsystem_device, - info.hw_rev, info.hw_rf_id); - ret = -EINVAL; - goto out_free_trans; - } + ret = pcim_enable_device(pdev); + if (ret) + return ret; - IWL_INFO(iwl_trans, "Detected %s\n", info.name); + pci_set_master(pdev); - if (iwl_trans->mac_cfg->mq_rx_supported) { - if (WARN_ON(!iwl_trans->cfg->num_rbds)) { - ret = -EINVAL; - goto out_free_trans; - } - trans_pcie->num_rx_bufs = iwl_trans_get_num_rbds(iwl_trans); - } else { - trans_pcie->num_rx_bufs = RX_QUEUE_SIZE; + ret = pcim_request_all_regions(pdev, DRV_NAME); + if (ret) { + dev_err(&pdev->dev, "Requesting all PCI BARs failed.\n"); + return ret; } - if (!iwl_trans->mac_cfg->integrated) { - u16 link_status; - - pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &link_status); - - info.pcie_link_speed = - u16_get_bits(link_status, PCI_EXP_LNKSTA_CLS); + hw_base = pcim_iomap(pdev, 0, 0); + if (!hw_base) { + dev_err(&pdev->dev, "Failed to map BAR 0.\n"); + return -ENOMEM; } - iwl_trans_set_info(iwl_trans, &info); - - ret = iwl_trans_init(iwl_trans); - if (ret) - goto out_free_trans; - - pci_set_drvdata(pdev, iwl_trans); - - iwl_pcie_check_me_status(iwl_trans); - - /* try to get ownership so that we'll know if we don't own it */ - iwl_pcie_prepare_card_hw(iwl_trans); - - iwl_trans->drv = iwl_drv_start(iwl_trans); - - if (IS_ERR(iwl_trans->drv)) { - ret = PTR_ERR(iwl_trans->drv); - goto out_free_trans; + /* We can't use iwl_read32 because trans wasn't allocated */ + hw_rev = readl(hw_base + CSR_HW_REV); + if (hw_rev == 0xffffffff) { + dev_err(&pdev->dev, "HW_REV=0xFFFFFFFF, PCI issues?\n"); + return -EIO; } - /* register transport layer debugfs here */ - iwl_trans_pcie_dbgfs_register(iwl_trans); - - return 0; - -out_free_trans: - iwl_trans_pcie_free(iwl_trans); - return ret; + return iwl_pci_gen1_2_probe(pdev, ent, mac_cfg, hw_base, hw_rev); } static void iwl_pci_remove(struct pci_dev *pdev) @@ -1580,12 +1299,21 @@ static const struct dev_pm_ops iwl_dev_pm_ops = { #endif /* CONFIG_PM_SLEEP */ +static void iwl_pci_dump(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct iwl_trans *trans = pci_get_drvdata(pdev); + + iwl_op_mode_dump(trans->op_mode); +} + static struct pci_driver iwl_pci_driver = { .name = DRV_NAME, .id_table = iwl_hw_card_ids, .probe = iwl_pci_probe, .remove = iwl_pci_remove, .driver.pm = IWL_PM_OPS, + .driver.coredump = iwl_pci_dump, }; int __must_check iwl_pci_register_driver(void) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h index 3b7c12fc4f9e..f48aeebb151c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h @@ -22,7 +22,7 @@ #include "iwl-io.h" #include "iwl-op-mode.h" #include "iwl-drv.h" -#include "iwl-context-info.h" +#include "pcie/iwl-context-info.h" /* * RX related structures and functions @@ -39,7 +39,7 @@ struct iwl_host_cmd; * trans_pcie layer */ /** - * struct iwl_rx_mem_buffer + * struct iwl_rx_mem_buffer - driver-side RX buffer descriptor * @page_dma: bus address of rxb page * @page: driver's pointer to the rxb page * @list: list entry for the membuffer @@ -190,6 +190,7 @@ struct iwl_rb_allocator { * iwl_get_closed_rb_stts - get closed rb stts from different structs * @trans: transport pointer (for configuration) * @rxq: the rxq to get the rb stts from + * Return: last closed RB index */ static inline u16 iwl_get_closed_rb_stts(struct iwl_trans *trans, struct iwl_rxq *rxq) @@ -382,8 +383,7 @@ struct iwl_pcie_txqs { * @irq_lock: lock to synchronize IRQ handling * @txq_memory: TXQ allocation array * @sx_waitq: waitqueue for Sx transitions - * @sx_complete: completion for Sx transitions - * @pcie_dbg_dumped_once: indicates PCIe regs were dumped already + * @sx_state: state tracking Sx transitions * @opmode_down: indicates opmode went away * @num_rx_bufs: number of RX buffers to allocate/use * @affinity_mask: IRQ affinity mask for each RX queue @@ -448,13 +448,17 @@ struct iwl_trans_pcie { u8 __iomem *hw_base; bool ucode_write_complete; - bool sx_complete; + enum { + IWL_SX_INVALID = 0, + IWL_SX_WAITING, + IWL_SX_ERROR, + IWL_SX_COMPLETE, + } sx_state; wait_queue_head_t ucode_write_waitq; wait_queue_head_t sx_waitq; u16 num_rx_bufs; - bool pcie_dbg_dumped_once; u32 rx_page_order; u32 rx_buf_bytes; u32 supported_dma_mask; @@ -534,10 +538,6 @@ iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie) * Convention: trans API functions: iwl_trans_pcie_XXX * Other functions: iwl_pcie_XXX */ -struct iwl_trans -*iwl_trans_pcie_alloc(struct pci_dev *pdev, - const struct iwl_mac_cfg *mac_cfg, - struct iwl_trans_info *info); void iwl_trans_pcie_free(struct iwl_trans *trans); void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions, struct device *dev); @@ -698,6 +698,7 @@ static inline void iwl_txq_stop(struct iwl_trans *trans, struct iwl_txq *txq) * iwl_txq_inc_wrap - increment queue index, wrap back to beginning * @trans: the transport (for configuration data) * @index: current index + * Return: the queue index incremented, subject to wrapping */ static inline int iwl_txq_inc_wrap(struct iwl_trans *trans, int index) { @@ -709,6 +710,7 @@ static inline int iwl_txq_inc_wrap(struct iwl_trans *trans, int index) * iwl_txq_dec_wrap - decrement queue index, wrap back to end * @trans: the transport (for configuration data) * @index: current index + * Return: the queue index decremented, subject to wrapping */ static inline int iwl_txq_dec_wrap(struct iwl_trans *trans, int index) { @@ -1028,40 +1030,12 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); } -static inline void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, - u32 reg, u32 mask, u32 value) -{ - u32 v; - -#ifdef CONFIG_IWLWIFI_DEBUG - WARN_ON_ONCE(value & ~mask); -#endif - - v = iwl_read32(trans, reg); - v &= ~mask; - v |= value; - iwl_write32(trans, reg, v); -} - -static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans, - u32 reg, u32 mask) -{ - __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0); -} - -static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, - u32 reg, u32 mask) -{ - __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); -} - static inline bool iwl_pcie_dbg_on(struct iwl_trans *trans) { return (trans->dbg.dest_tlv || iwl_trans_dbg_ini_valid(trans)); } void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq); -void iwl_trans_pcie_dump_regs(struct iwl_trans *trans); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans); @@ -1074,6 +1048,7 @@ void iwl_pcie_rx_allocator_work(struct work_struct *data); /* common trans ops for all generations transports */ void iwl_trans_pcie_op_mode_enter(struct iwl_trans *trans); +int _iwl_trans_pcie_start_hw(struct iwl_trans *trans); int iwl_trans_pcie_start_hw(struct iwl_trans *trans); void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans); void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val); @@ -1083,8 +1058,6 @@ u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg); void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, u32 val); int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, void *buf, int dwords); -int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, - const void *buf, int dwords); int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership); struct iwl_trans_dump_data * iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask, @@ -1104,6 +1077,10 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); void __releases(nic_access_nobh) iwl_trans_pcie_release_nic_access(struct iwl_trans *trans); void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power); +int iwl_pci_gen1_2_probe(struct pci_dev *pdev, + const struct pci_device_id *ent, + const struct iwl_mac_cfg *mac_cfg, + u8 __iomem *hw_base, u32 hw_rev); /* transport gen 1 exported functions */ void iwl_trans_pcie_fw_alive(struct iwl_trans *trans); @@ -1114,6 +1091,7 @@ int iwl_trans_pcie_start_fw(struct iwl_trans *trans, void iwl_trans_pcie_stop_device(struct iwl_trans *trans); /* common functions that are used by gen2 transport */ +void iwl_trans_pcie_gen2_op_mode_leave(struct iwl_trans *trans); int iwl_pcie_gen2_apm_init(struct iwl_trans *trans); void iwl_pcie_apm_config(struct iwl_trans *trans); int iwl_pcie_prepare_card_hw(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/rx.c index f0405eddc367..619a9505e6d9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/rx.c @@ -12,7 +12,7 @@ #include "iwl-io.h" #include "internal.h" #include "iwl-op-mode.h" -#include "iwl-context-info-v2.h" +#include "pcie/iwl-context-info-v2.h" #include "fw/dbg.h" /****************************************************************************** @@ -1700,6 +1700,15 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) timer_delete(&trans_pcie->txqs.txq[i]->stuck_timer); } + if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) { + u32 val = iwl_read32(trans, CSR_IPC_STATE); + + if (val & CSR_IPC_STATE_TOP_RESET_REQ) { + IWL_ERR(trans, "FW requested TOP reset for FSEQ\n"); + trans->do_top_reset = 1; + } + } + /* The STATUS_FW_ERROR bit is set in this function. This must happen * before we wake up the command caller, to ensure a proper cleanup. */ iwl_trans_fw_error(trans, IWL_ERR_TYPE_IRQ); @@ -1852,7 +1861,12 @@ static void iwl_trans_pcie_handle_reset_interrupt(struct iwl_trans *trans) } fallthrough; case CSR_IPC_STATE_RESET_TOP_READY: - /* FIXME: handle this case when requesting TOP reset */ + if (trans_pcie->fw_reset_state == FW_RESET_TOP_REQUESTED) { + IWL_DEBUG_ISR(trans, "TOP Reset continues\n"); + trans_pcie->fw_reset_state = FW_RESET_OK; + wake_up(&trans_pcie->fw_reset_waitq); + break; + } fallthrough; case CSR_IPC_STATE_RESET_NONE: IWL_FW_CHECK_FAILED(trans, @@ -2380,6 +2394,11 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) } else { iwl_pcie_irq_handle_error(trans); } + + if (trans_pcie->sx_state == IWL_SX_WAITING) { + trans_pcie->sx_state = IWL_SX_ERROR; + wake_up(&trans_pcie->sx_waitq); + } } /* After checking FH register check HW register */ @@ -2414,13 +2433,20 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) if (inta_hw & MSIX_HW_INT_CAUSES_REG_WAKEUP && trans_pcie->prph_info) { u32 sleep_notif = le32_to_cpu(trans_pcie->prph_info->sleep_notif); + if (sleep_notif == IWL_D3_SLEEP_STATUS_SUSPEND || sleep_notif == IWL_D3_SLEEP_STATUS_RESUME) { IWL_DEBUG_ISR(trans, "Sx interrupt: sleep notification = 0x%x\n", sleep_notif); - trans_pcie->sx_complete = true; - wake_up(&trans_pcie->sx_waitq); + if (trans_pcie->sx_state == IWL_SX_WAITING) { + trans_pcie->sx_state = IWL_SX_COMPLETE; + wake_up(&trans_pcie->sx_waitq); + } else { + IWL_ERR(trans, + "unexpected Sx interrupt (0x%x)\n", + sleep_notif); + } } else { /* uCode wakes up after power-down sleep */ IWL_DEBUG_ISR(trans, "Wakeup interrupt\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c index 5a9c3b7976a1..1951be3a30b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c @@ -5,8 +5,8 @@ */ #include "iwl-trans.h" #include "iwl-prph.h" -#include "iwl-context-info.h" -#include "iwl-context-info-v2.h" +#include "pcie/iwl-context-info.h" +#include "pcie/iwl-context-info-v2.h" #include "internal.h" #include "fw/dbg.h" @@ -612,6 +612,11 @@ again: msleep(10); IWL_INFO(trans, "TOP reset successful, reinit now\n"); /* now load the firmware again properly */ + ret = _iwl_trans_pcie_start_hw(trans); + if (ret) { + IWL_ERR(trans, "failed to start HW after TOP reset\n"); + goto out; + } trans_pcie->prph_scratch->ctrl_cfg.control.control_flags &= ~cpu_to_le32(IWL_PRPH_SCRATCH_TOP_RESET); top_reset_done = true; @@ -627,3 +632,23 @@ out: mutex_unlock(&trans_pcie->mutex); return ret; } + +void iwl_trans_pcie_gen2_op_mode_leave(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + mutex_lock(&trans_pcie->mutex); + + /* disable interrupts - don't enable HW RF kill interrupt */ + iwl_disable_interrupts(trans); + + iwl_pcie_gen2_apm_stop(trans, true); + + iwl_disable_interrupts(trans); + + iwl_pcie_disable_ict(trans); + + mutex_unlock(&trans_pcie->mutex); + + iwl_pcie_synchronize_irqs(trans); +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index cc4d289b110d..327366bf87de 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -25,109 +25,17 @@ #include "fw/dbg.h" #include "fw/api/tx.h" #include "fw/acpi.h" +#include "fw/api/tx.h" #include "mei/iwl-mei.h" #include "internal.h" #include "iwl-fh.h" -#include "iwl-context-info-v2.h" +#include "pcie/iwl-context-info-v2.h" +#include "pcie/utils.h" /* extended range in FW SRAM */ #define IWL_FW_MEM_EXTENDED_START 0x40000 #define IWL_FW_MEM_EXTENDED_END 0x57FFF -void iwl_trans_pcie_dump_regs(struct iwl_trans *trans) -{ -#define PCI_DUMP_SIZE 352 -#define PCI_MEM_DUMP_SIZE 64 -#define PCI_PARENT_DUMP_SIZE 524 -#define PREFIX_LEN 32 - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct pci_dev *pdev = trans_pcie->pci_dev; - u32 i, pos, alloc_size, *ptr, *buf; - char *prefix; - - if (trans_pcie->pcie_dbg_dumped_once) - return; - - /* Should be a multiple of 4 */ - BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3); - BUILD_BUG_ON(PCI_MEM_DUMP_SIZE > 4096 || PCI_MEM_DUMP_SIZE & 0x3); - BUILD_BUG_ON(PCI_PARENT_DUMP_SIZE > 4096 || PCI_PARENT_DUMP_SIZE & 0x3); - - /* Alloc a max size buffer */ - alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN; - alloc_size = max_t(u32, alloc_size, PCI_DUMP_SIZE + PREFIX_LEN); - alloc_size = max_t(u32, alloc_size, PCI_MEM_DUMP_SIZE + PREFIX_LEN); - alloc_size = max_t(u32, alloc_size, PCI_PARENT_DUMP_SIZE + PREFIX_LEN); - - buf = kmalloc(alloc_size, GFP_ATOMIC); - if (!buf) - return; - prefix = (char *)buf + alloc_size - PREFIX_LEN; - - IWL_ERR(trans, "iwlwifi transaction failed, dumping registers\n"); - - /* Print wifi device registers */ - sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); - IWL_ERR(trans, "iwlwifi device config registers:\n"); - for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++) - if (pci_read_config_dword(pdev, i, ptr)) - goto err_read; - print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); - - IWL_ERR(trans, "iwlwifi device memory mapped registers:\n"); - for (i = 0, ptr = buf; i < PCI_MEM_DUMP_SIZE; i += 4, ptr++) - *ptr = iwl_read32(trans, i); - print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); - - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); - if (pos) { - IWL_ERR(trans, "iwlwifi device AER capability structure:\n"); - for (i = 0, ptr = buf; i < PCI_ERR_ROOT_COMMAND; i += 4, ptr++) - if (pci_read_config_dword(pdev, pos + i, ptr)) - goto err_read; - print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, - 32, 4, buf, i, 0); - } - - /* Print parent device registers next */ - if (!pdev->bus->self) - goto out; - - pdev = pdev->bus->self; - sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); - - IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n", - pci_name(pdev)); - for (i = 0, ptr = buf; i < PCI_PARENT_DUMP_SIZE; i += 4, ptr++) - if (pci_read_config_dword(pdev, i, ptr)) - goto err_read; - print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); - - /* Print root port AER registers */ - pos = 0; - pdev = pcie_find_root_port(pdev); - if (pdev) - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); - if (pos) { - IWL_ERR(trans, "iwlwifi root port (%s) AER cap structure:\n", - pci_name(pdev)); - sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); - for (i = 0, ptr = buf; i <= PCI_ERR_ROOT_ERR_SRC; i += 4, ptr++) - if (pci_read_config_dword(pdev, pos + i, ptr)) - goto err_read; - print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, - 4, buf, i, 0); - } - goto out; - -err_read: - print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); - IWL_ERR(trans, "Read failed at 0x%X\n", i); -out: - trans_pcie->pcie_dbg_dumped_once = 1; - kfree(buf); -} - int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership) { /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ @@ -387,8 +295,8 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) u32 dl_cfg_reg; /* Force XTAL ON */ - __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); ret = iwl_trans_pcie_sw_reset(trans, true); @@ -397,8 +305,8 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) if (WARN_ON(ret)) { /* Release XTAL ON request */ - __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); return; } @@ -449,12 +357,12 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* Activates XTAL resources monitor */ - __iwl_trans_pcie_set_bit(trans, CSR_MONITOR_CFG_REG, - CSR_MONITOR_XTAL_RESOURCES); + iwl_trans_set_bit(trans, CSR_MONITOR_CFG_REG, + CSR_MONITOR_XTAL_RESOURCES); /* Release XTAL ON request */ - __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); udelay(10); /* Release APMG XTAL */ @@ -473,20 +381,18 @@ void iwl_pcie_apm_stop_master(struct iwl_trans *trans) iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ); - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, - CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, - 100); + ret = iwl_poll_bits(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + 100); usleep_range(10000, 20000); } else { iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(trans, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + ret = iwl_poll_bits(trans, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); } - if (ret < 0) + if (ret) IWL_WARN(trans, "Master Disable Timed Out, 100 usec\n"); IWL_DEBUG_INFO(trans, "stop master\n"); @@ -585,15 +491,14 @@ static int iwl_pcie_set_hw_ready(struct iwl_trans *trans) CSR_HW_IF_CONFIG_REG_PCI_OWN_SET); /* See if we got it */ - ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_PCI_OWN_SET, - CSR_HW_IF_CONFIG_REG_PCI_OWN_SET, - HW_READY_TIMEOUT); + ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PCI_OWN_SET, + HW_READY_TIMEOUT); - if (ret >= 0) + if (!ret) iwl_set_bit(trans, CSR_MBOX_SET_REG, CSR_MBOX_SET_REG_OS_ALIVE); - IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : ""); + IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret ? " not" : ""); return ret; } @@ -607,7 +512,7 @@ int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) ret = iwl_pcie_set_hw_ready(trans); /* If the card is ready, exit 0 */ - if (ret >= 0) { + if (!ret) { trans->csme_own = false; return 0; } @@ -625,7 +530,7 @@ int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) do { ret = iwl_pcie_set_hw_ready(trans); - if (ret >= 0) { + if (!ret) { trans->csme_own = false; return 0; } @@ -704,7 +609,7 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, trans_pcie->ucode_write_complete, 5 * HZ); if (!ret) { IWL_ERR(trans, "Failed to load firmware chunk!\n"); - iwl_trans_pcie_dump_regs(trans); + iwl_trans_pcie_dump_regs(trans, trans_pcie->pci_dev); return -ETIMEDOUT; } @@ -1536,30 +1441,41 @@ static int iwl_pcie_d3_handshake(struct iwl_trans *trans, bool suspend) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; + if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return 0; + + trans_pcie->sx_state = IWL_SX_WAITING; + if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_AX210) iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, suspend ? UREG_DOORBELL_TO_ISR6_SUSPEND : UREG_DOORBELL_TO_ISR6_RESUME); - else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + else iwl_write32(trans, CSR_IPC_SLEEP_CONTROL, suspend ? CSR_IPC_SLEEP_CONTROL_SUSPEND : CSR_IPC_SLEEP_CONTROL_RESUME); - else - return 0; ret = wait_event_timeout(trans_pcie->sx_waitq, - trans_pcie->sx_complete, 2 * HZ); - - /* Invalidate it toward next suspend or resume */ - trans_pcie->sx_complete = false; - + trans_pcie->sx_state != IWL_SX_WAITING, + 2 * HZ); if (!ret) { IWL_ERR(trans, "Timeout %s D3\n", suspend ? "entering" : "exiting"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + } else { + ret = 0; } - return 0; + if (trans_pcie->sx_state == IWL_SX_ERROR) { + IWL_ERR(trans, "FW error while %s D3\n", + suspend ? "entering" : "exiting"); + ret = -EIO; + } + + /* Invalidate it toward next suspend or resume */ + trans_pcie->sx_state = IWL_SX_INVALID; + + return ret; } int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset) @@ -1845,7 +1761,7 @@ static int iwl_pcie_gen2_force_power_gating(struct iwl_trans *trans) return iwl_trans_pcie_sw_reset(trans, true); } -static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans) +int _iwl_trans_pcie_start_hw(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int err; @@ -2412,7 +2328,7 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) } /* this bit wakes up the NIC */ - __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, write); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, write); if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); @@ -2436,8 +2352,8 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) * 5000 series and later (including 1000 series) have non-volatile SRAM, * and do not save/restore SRAM when power cycling. */ - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, poll, mask, 15000); - if (unlikely(ret < 0)) { + ret = iwl_poll_bits_mask(trans, CSR_GP_CNTRL, poll, mask, 15000); + if (unlikely(ret)) { u32 cntrl = iwl_read32(trans, CSR_GP_CNTRL); if (silent) { @@ -2449,7 +2365,7 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) "Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n", cntrl); - iwl_trans_pcie_dump_regs(trans); + iwl_trans_pcie_dump_regs(trans, trans_pcie->pci_dev); if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U) iwl_trans_pcie_reset(trans, @@ -2501,11 +2417,11 @@ iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) if (trans_pcie->cmd_hold_nic_awake) goto out; if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) - __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); else - __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* * Above we read the CSR_GP_CNTRL register, which will flush * any previous writes, but we need the write that clears the @@ -2567,24 +2483,6 @@ int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, return 0; } -int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr, - const void *buf, int dwords) -{ - int offs, ret = 0; - const u32 *vals = buf; - - if (iwl_trans_grab_nic_access(trans)) { - iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); - for (offs = 0; offs < dwords; offs++) - iwl_write32(trans, HBUS_TARG_MEM_WDAT, - vals ? vals[offs] : 0); - iwl_trans_release_nic_access(trans); - } else { - ret = -EBUSY; - } - return ret; -} - int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs, u32 *val) { @@ -2704,7 +2602,7 @@ void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); spin_lock_bh(&trans_pcie->reg_lock); - __iwl_trans_pcie_set_bits_mask(trans, reg, mask, value); + _iwl_trans_set_bits_mask(trans, reg, mask, value); spin_unlock_bh(&trans_pcie->reg_lock); } @@ -3786,36 +3684,56 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans) iwl_trans_sync_nmi_with_addr(trans, inta_addr, sw_err_bit); } -struct iwl_trans * +static int iwl_trans_pcie_set_txcmd_info(const struct iwl_mac_cfg *mac_cfg, + unsigned int *txcmd_size, + unsigned int *txcmd_align) +{ + if (!mac_cfg->gen2) { + *txcmd_size = sizeof(struct iwl_tx_cmd_v6); + *txcmd_align = sizeof(void *); + } else if (mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { + *txcmd_size = sizeof(struct iwl_tx_cmd_v9); + *txcmd_align = 64; + } else { + *txcmd_size = sizeof(struct iwl_tx_cmd); + *txcmd_align = 128; + } + + *txcmd_size += sizeof(struct iwl_cmd_header); + *txcmd_size += 36; /* biggest possible 802.11 header */ + + /* Ensure device TX cmd cannot reach/cross a page boundary in gen2 */ + if (WARN_ON((mac_cfg->gen2 && *txcmd_size >= *txcmd_align))) + return -EINVAL; + + return 0; +} + +static struct iwl_trans * iwl_trans_pcie_alloc(struct pci_dev *pdev, const struct iwl_mac_cfg *mac_cfg, - struct iwl_trans_info *info) + struct iwl_trans_info *info, u8 __iomem *hw_base) { struct iwl_trans_pcie *trans_pcie, **priv; + unsigned int txcmd_size, txcmd_align; struct iwl_trans *trans; unsigned int bc_tbl_n_entries; int ret, addr_size; - u32 bar0; - - /* reassign our BAR 0 if invalid due to possible runtime PM races */ - pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0); - if (bar0 == PCI_BASE_ADDRESS_MEM_TYPE_64) { - ret = pci_assign_resource(pdev, 0); - if (ret) - return ERR_PTR(ret); - } - ret = pcim_enable_device(pdev); + ret = iwl_trans_pcie_set_txcmd_info(mac_cfg, &txcmd_size, + &txcmd_align); if (ret) return ERR_PTR(ret); trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev, - mac_cfg); + mac_cfg, txcmd_size, txcmd_align); if (!trans) return ERR_PTR(-ENOMEM); trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + trans_pcie->hw_base = hw_base; + /* Initialize the wait queue for commands */ init_waitqueue_head(&trans_pcie->wait_command_queue); @@ -3913,8 +3831,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, PCIE_LINK_STATE_CLKPM); } - pci_set_master(pdev); - addr_size = trans_pcie->txqs.tfd.addr_size; ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_size)); if (ret) { @@ -3926,19 +3842,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, } } - ret = pcim_request_all_regions(pdev, DRV_NAME); - if (ret) { - dev_err(&pdev->dev, "Requesting all PCI BARs failed.\n"); - goto out_no_pci; - } - - trans_pcie->hw_base = pcim_iomap(pdev, 0, 0); - if (!trans_pcie->hw_base) { - dev_err(&pdev->dev, "Could not ioremap PCI BAR 0.\n"); - ret = -ENODEV; - goto out_no_pci; - } - /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); @@ -3946,13 +3849,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->pci_dev = pdev; iwl_disable_interrupts(trans); - info->hw_rev = iwl_read32(trans, CSR_HW_REV); - if (info->hw_rev == 0xffffffff) { - dev_err(&pdev->dev, "HW_REV=0xFFFFFFFF, PCI issues?\n"); - ret = -EIO; - goto out_no_pci; - } - /* * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have * changed, and now the revision step also includes bit 0-1 (no more @@ -4046,9 +3942,332 @@ int iwl_trans_pcie_copy_imr(struct iwl_trans *trans, IMR_D2S_REQUESTED, 5 * HZ); if (!ret || trans_pcie->imr_status == IMR_D2S_ERROR) { IWL_ERR(trans, "Failed to copy IMR Memory chunk!\n"); - iwl_trans_pcie_dump_regs(trans); + iwl_trans_pcie_dump_regs(trans, trans_pcie->pci_dev); return -ETIMEDOUT; } trans_pcie->imr_status = IMR_D2S_IDLE; return 0; } + +/* + * Read rf id and cdb info from prph register and store it + */ +static void get_crf_id(struct iwl_trans *iwl_trans, + struct iwl_trans_info *info) +{ + u32 sd_reg_ver_addr; + u32 hw_wfpm_id; + u32 val = 0; + u8 step; + + if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + sd_reg_ver_addr = SD_REG_VER_GEN2; + else + sd_reg_ver_addr = SD_REG_VER; + + /* Enable access to peripheral registers */ + val = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG); + val |= WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK; + iwl_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val); + + /* Read crf info */ + info->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr); + + /* Read cnv info */ + info->hw_cnv_id = iwl_read_prph_no_grab(iwl_trans, CNVI_AUX_MISC_CHIP); + + /* For BZ-W, take B step also when A step is indicated */ + if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) + step = SILICON_B_STEP; + + /* In BZ, the MAC step must be read from the CNVI aux register */ + if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ) { + step = CNVI_AUX_MISC_CHIP_MAC_STEP(info->hw_cnv_id); + + /* For BZ-U, take B step also when A step is indicated */ + if ((CNVI_AUX_MISC_CHIP_PROD_TYPE(info->hw_cnv_id) == + CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U) && + step == SILICON_A_STEP) + step = SILICON_B_STEP; + } + + if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ || + CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) { + info->hw_rev_step = step; + info->hw_rev |= step; + } + + /* Read cdb info (also contains the jacket info if needed in the future */ + hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); + IWL_INFO(iwl_trans, "Detected crf-id 0x%x, cnv-id 0x%x wfpm id 0x%x\n", + info->hw_crf_id, info->hw_cnv_id, hw_wfpm_id); +} + +/* + * In case that there is no OTP on the NIC, map the rf id and cdb info + * from the prph registers. + */ +static int map_crf_id(struct iwl_trans *iwl_trans, + struct iwl_trans_info *info) +{ + int ret = 0; + u32 val = info->hw_crf_id; + u32 step_id = REG_CRF_ID_STEP(val); + u32 slave_id = REG_CRF_ID_SLAVE(val); + u32 jacket_id_cnv = REG_CRF_ID_SLAVE(info->hw_cnv_id); + u32 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, + WFPM_OTP_CFG1_ADDR); + u32 jacket_id_wfpm = WFPM_OTP_CFG1_IS_JACKET(hw_wfpm_id); + u32 cdb_id_wfpm = WFPM_OTP_CFG1_IS_CDB(hw_wfpm_id); + + /* Map between crf id to rf id */ + switch (REG_CRF_ID_TYPE(val)) { + case REG_CRF_ID_TYPE_JF_1: + info->hw_rf_id = (IWL_CFG_RF_TYPE_JF1 << 12); + break; + case REG_CRF_ID_TYPE_JF_2: + info->hw_rf_id = (IWL_CFG_RF_TYPE_JF2 << 12); + break; + case REG_CRF_ID_TYPE_HR_NONE_CDB_1X1: + info->hw_rf_id = (IWL_CFG_RF_TYPE_HR1 << 12); + break; + case REG_CRF_ID_TYPE_HR_NONE_CDB: + info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12); + break; + case REG_CRF_ID_TYPE_HR_CDB: + info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12); + break; + case REG_CRF_ID_TYPE_GF: + info->hw_rf_id = (IWL_CFG_RF_TYPE_GF << 12); + break; + case REG_CRF_ID_TYPE_FM: + info->hw_rf_id = (IWL_CFG_RF_TYPE_FM << 12); + break; + case REG_CRF_ID_TYPE_WHP: + info->hw_rf_id = (IWL_CFG_RF_TYPE_WH << 12); + break; + case REG_CRF_ID_TYPE_PE: + info->hw_rf_id = (IWL_CFG_RF_TYPE_PE << 12); + break; + default: + ret = -EIO; + IWL_ERR(iwl_trans, + "Can't find a correct rfid for crf id 0x%x\n", + REG_CRF_ID_TYPE(val)); + goto out; + } + + /* Set Step-id */ + info->hw_rf_id |= (step_id << 8); + + /* Set CDB capabilities */ + if (cdb_id_wfpm || slave_id) { + info->hw_rf_id += BIT(28); + IWL_INFO(iwl_trans, "Adding cdb to rf id\n"); + } + + /* Set Jacket capabilities */ + if (jacket_id_wfpm || jacket_id_cnv) { + info->hw_rf_id += BIT(29); + IWL_INFO(iwl_trans, "Adding jacket to rf id\n"); + } + + IWL_INFO(iwl_trans, + "Detected rf-type 0x%x step-id 0x%x slave-id 0x%x from crf id 0x%x\n", + REG_CRF_ID_TYPE(val), step_id, slave_id, info->hw_rf_id); + IWL_INFO(iwl_trans, + "Detected cdb-id 0x%x jacket-id 0x%x from wfpm id 0x%x\n", + cdb_id_wfpm, jacket_id_wfpm, hw_wfpm_id); + IWL_INFO(iwl_trans, "Detected jacket-id 0x%x from cnvi id 0x%x\n", + jacket_id_cnv, info->hw_cnv_id); + +out: + return ret; +} + +static void iwl_pcie_recheck_me_status(struct work_struct *wk) +{ + struct iwl_trans_pcie *trans_pcie = container_of(wk, + typeof(*trans_pcie), + me_recheck_wk.work); + u32 val; + + val = iwl_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG); + trans_pcie->me_present = !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP); +} + +static void iwl_pcie_check_me_status(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 val; + + trans_pcie->me_present = -1; + + INIT_DELAYED_WORK(&trans_pcie->me_recheck_wk, + iwl_pcie_recheck_me_status); + + /* we don't have a good way of determining this until BZ */ + if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ) + return; + + val = iwl_read_prph(trans, CNVI_SCU_REG_FOR_ECO_1); + if (val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN) { + trans_pcie->me_present = + !!(val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT); + return; + } + + val = iwl_read32(trans, CSR_HW_IF_CONFIG_REG); + if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN | + CSR_HW_IF_CONFIG_REG_IAMT_UP)) { + trans_pcie->me_present = 1; + return; + } + + /* recheck again later, ME might still be initializing */ + schedule_delayed_work(&trans_pcie->me_recheck_wk, HZ); +} + +int iwl_pci_gen1_2_probe(struct pci_dev *pdev, + const struct pci_device_id *ent, + const struct iwl_mac_cfg *mac_cfg, + u8 __iomem *hw_base, u32 hw_rev) +{ + const struct iwl_dev_info *dev_info; + struct iwl_trans_info info = { + .hw_id = (pdev->device << 16) + pdev->subsystem_device, + .hw_rev = hw_rev, + }; + struct iwl_trans *iwl_trans; + struct iwl_trans_pcie *trans_pcie; + int ret; + + iwl_trans = iwl_trans_pcie_alloc(pdev, mac_cfg, &info, hw_base); + if (IS_ERR(iwl_trans)) + return PTR_ERR(iwl_trans); + + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); + + iwl_trans_pcie_check_product_reset_status(pdev); + iwl_trans_pcie_check_product_reset_mode(pdev); + + /* set the things we know so far for the grab NIC access */ + iwl_trans_set_info(iwl_trans, &info); + + /* + * Let's try to grab NIC access early here. Sometimes, NICs may + * fail to initialize, and if that happens it's better if we see + * issues early on (and can reprobe, per the logic inside), than + * first trying to load the firmware etc. and potentially only + * detecting any problems when the first interface is brought up. + */ + ret = iwl_pcie_prepare_card_hw(iwl_trans); + if (!ret) { + ret = iwl_finish_nic_init(iwl_trans); + if (ret) + goto out_free_trans; + if (iwl_trans_grab_nic_access(iwl_trans)) { + get_crf_id(iwl_trans, &info); + /* all good */ + iwl_trans_release_nic_access(iwl_trans); + } else { + ret = -EIO; + goto out_free_trans; + } + } + + info.hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID); + + /* + * The RF_ID is set to zero in blank OTP so read version to + * extract the RF_ID. + * This is relevant only for family 9000 and up. + */ + if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000 && + !CSR_HW_RFID_TYPE(info.hw_rf_id) && map_crf_id(iwl_trans, &info)) { + ret = -EINVAL; + goto out_free_trans; + } + + IWL_INFO(iwl_trans, "PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", + pdev->device, pdev->subsystem_device, + info.hw_rev, info.hw_rf_id); + + dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device, + CSR_HW_RFID_TYPE(info.hw_rf_id), + CSR_HW_RFID_IS_CDB(info.hw_rf_id), + IWL_SUBDEVICE_RF_ID(pdev->subsystem_device), + IWL_SUBDEVICE_BW_LIM(pdev->subsystem_device), + !iwl_trans->mac_cfg->integrated); + if (dev_info) { + iwl_trans->cfg = dev_info->cfg; + info.name = dev_info->name; + } + +#if IS_ENABLED(CONFIG_IWLMVM) + + /* + * special-case 7265D, it has the same PCI IDs. + * + * Note that because we already pass the cfg to the transport above, + * all the parameters that the transport uses must, until that is + * changed, be identical to the ones in the 7265D configuration. + */ + if (iwl_trans->cfg == &iwl7265_cfg && + (info.hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) + iwl_trans->cfg = &iwl7265d_cfg; +#endif + if (!iwl_trans->cfg) { + pr_err("No config found for PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", + pdev->device, pdev->subsystem_device, + info.hw_rev, info.hw_rf_id); + ret = -EINVAL; + goto out_free_trans; + } + + IWL_INFO(iwl_trans, "Detected %s\n", info.name); + + if (iwl_trans->mac_cfg->mq_rx_supported) { + if (WARN_ON(!iwl_trans->cfg->num_rbds)) { + ret = -EINVAL; + goto out_free_trans; + } + trans_pcie->num_rx_bufs = iwl_trans_get_num_rbds(iwl_trans); + } else { + trans_pcie->num_rx_bufs = RX_QUEUE_SIZE; + } + + if (!iwl_trans->mac_cfg->integrated) { + u16 link_status; + + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &link_status); + + info.pcie_link_speed = + u16_get_bits(link_status, PCI_EXP_LNKSTA_CLS); + } + + iwl_trans_set_info(iwl_trans, &info); + + pci_set_drvdata(pdev, iwl_trans); + + iwl_pcie_check_me_status(iwl_trans); + + /* try to get ownership so that we'll know if we don't own it */ + iwl_pcie_prepare_card_hw(iwl_trans); + + iwl_trans->drv = iwl_drv_start(iwl_trans); + + if (IS_ERR(iwl_trans->drv)) { + ret = PTR_ERR(iwl_trans->drv); + goto out_free_trans; + } + + /* register transport layer debugfs here */ + iwl_trans_pcie_dbgfs_register(iwl_trans); + + return 0; + +out_free_trans: + iwl_trans_pcie_free(iwl_trans); + return ret; +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c index df0545f09da9..df0545f09da9 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c index eee55428749c..84a05cc1c27a 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c @@ -25,6 +25,8 @@ #include "iwl-op-mode.h" #include "internal.h" #include "fw/api/tx.h" +#include "fw/dbg.h" +#include "pcie/utils.h" /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services @@ -203,8 +205,8 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) } trans_pcie->cmd_hold_nic_awake = false; - __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); spin_unlock(&trans_pcie->reg_lock); } @@ -494,9 +496,9 @@ void iwl_pcie_tx_start(struct iwl_trans *trans) iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); /* reset context data, TX status and translation data */ - iwl_trans_pcie_write_mem(trans, trans_pcie->scd_base_addr + - SCD_CONTEXT_MEM_LOWER_BOUND, - NULL, clear_dwords); + iwl_trans_write_mem(trans, trans_pcie->scd_base_addr + + SCD_CONTEXT_MEM_LOWER_BOUND, + NULL, clear_dwords); iwl_write_prph(trans, SCD_DRAM_BASE_ADDR, trans_pcie->txqs.scd_bc_tbls.dma >> 10); @@ -589,8 +591,8 @@ static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans) } /* Wait for DMA channels to be idle */ - ret = iwl_poll_bit(trans, FH_TSSR_TX_STATUS_REG, mask, mask, 5000); - if (ret < 0) + ret = iwl_poll_bits(trans, FH_TSSR_TX_STATUS_REG, mask, 5000); + if (ret) IWL_ERR(trans, "Failing on timeout while stopping DMA channel %d [0x%08x]\n", ch, iwl_read32(trans, FH_TSSR_TX_STATUS_REG)); @@ -1292,9 +1294,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, if (configure_scd) { iwl_scd_txq_set_inactive(trans, txq_id); - iwl_trans_pcie_write_mem(trans, stts_addr, - (const void *)zero_val, - ARRAY_SIZE(zero_val)); + iwl_trans_write_mem(trans, stts_addr, (const void *)zero_val, + ARRAY_SIZE(zero_val)); } iwl_pcie_txq_unmap(trans, txq_id); @@ -1638,13 +1639,11 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, /* If a Tx command is being handled and it isn't in the actual * command queue then there a command routing bug has been introduced * in the queue management code. */ - if (WARN(txq_id != trans->conf.cmd_queue, - "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d\n", - txq_id, trans->conf.cmd_queue, sequence, txq->read_ptr, - txq->write_ptr)) { - iwl_print_hex_error(trans, pkt, 32); + if (IWL_FW_CHECK(trans, txq_id != trans->conf.cmd_queue, + "wrong command queue %d (should be %d), sequence 0x%X readp=%d writep=%d pkt=%*phN\n", + txq_id, trans->conf.cmd_queue, sequence, txq->read_ptr, + txq->write_ptr, 32, pkt)) return; - } spin_lock_bh(&txq->lock); @@ -1964,7 +1963,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, * have in the MPDU by themselves, but that we duplicate into * all the different MSDUs inside the A-MSDU. */ - le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen); + le16_add_cpu(&tx_cmd->params.len, -snap_ip_tcp_hdrlen); tso_start(skb, &tso); @@ -2007,7 +2006,7 @@ static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, hdr_tb_phys, hdr_tb_len); /* add this subframe's headers' length to the tx_cmd */ - le16_add_cpu(&tx_cmd->len, pos_hdr - subf_hdrs_start); + le16_add_cpu(&tx_cmd->params.len, pos_hdr - subf_hdrs_start); /* prepare the start_hdr for the next subframe */ start_hdr = pos_hdr; @@ -2075,11 +2074,11 @@ static void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans, __le16 bc_ent; struct iwl_device_tx_cmd *dev_cmd = txq->entries[txq->write_ptr].cmd; struct iwl_tx_cmd_v6 *tx_cmd = (void *)dev_cmd->payload; - u8 sta_id = tx_cmd->sta_id; + u8 sta_id = tx_cmd->params.sta_id; scd_bc_tbl = trans_pcie->txqs.scd_bc_tbls.addr; - sec_ctl = tx_cmd->sec_ctl; + sec_ctl = tx_cmd->params.sec_ctl; switch (sec_ctl & TX_CMD_SEC_MSK) { case TX_CMD_SEC_CCM: @@ -2186,10 +2185,10 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tb0_phys = iwl_txq_get_first_tb_dma(txq, txq->write_ptr); scratch_phys = tb0_phys + sizeof(struct iwl_cmd_header) + - offsetof(struct iwl_tx_cmd_v6, scratch); + offsetof(struct iwl_tx_cmd_v6_params, scratch); - tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); + tx_cmd->params.dram_lsb_ptr = cpu_to_le32(scratch_phys); + tx_cmd->params.dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); /* Set up first empty entry in queue's array of Tx/cmd buffers */ out_meta = &txq->entries[txq->write_ptr].meta; @@ -2211,7 +2210,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tb1_len = ALIGN(len, 4); /* Tell NIC about any 2-byte padding after MAC header */ if (tb1_len != len) - tx_cmd->tx_flags |= cpu_to_le32(TX_CMD_FLG_MH_PAD); + tx_cmd->params.tx_flags |= cpu_to_le32(TX_CMD_FLG_MH_PAD); } else { tb1_len = len; } @@ -2226,7 +2225,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, /* there must be data left over for TB1 or this code must be changed */ BUILD_BUG_ON(sizeof(struct iwl_tx_cmd_v6) < IWL_FIRST_TB_SIZE); BUILD_BUG_ON(sizeof(struct iwl_cmd_header) + - offsetofend(struct iwl_tx_cmd_v6, scratch) > + offsetofend(struct iwl_tx_cmd_v6_params, scratch) > IWL_FIRST_TB_SIZE); /* map the data for TB1 */ @@ -2272,7 +2271,7 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, tfd = iwl_txq_get_tfd(trans, txq, txq->write_ptr); /* Set up entry for this TFD in Tx byte-count array */ - iwl_txq_gen1_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len), + iwl_txq_gen1_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->params.len), iwl_txq_gen1_tfd_get_num_tbs(tfd)); wait_write_ptr = ieee80211_has_morefrags(fc); @@ -2324,7 +2323,7 @@ static void iwl_txq_gen1_inval_byte_cnt_tbl(struct iwl_trans *trans, WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); if (txq_id != trans->conf.cmd_queue) - sta_id = tx_cmd->sta_id; + sta_id = tx_cmd->params.sta_id; bc_ent = cpu_to_le16(1 | (sta_id << 12)); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-v2.h b/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info-v2.h index 8c5c0ea46181..416baadc5017 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info-v2.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info-v2.h @@ -130,11 +130,11 @@ struct iwl_prph_scratch_pnvm_cfg { } __packed; /* PERIPH_SCRATCH_PNVM_CFG_S */ /** - * struct iwl_prph_scrath_mem_desc_addr_array + * struct iwl_prph_scratch_mem_desc_addr_array - DRAM * @mem_descs: array of dram addresses. - * Each address is the beggining of a pnvm payload. + * Each address is the beginning of a PNVM payload. */ -struct iwl_prph_scrath_mem_desc_addr_array { +struct iwl_prph_scratch_mem_desc_addr_array { __le64 mem_descs[IPC_DRAM_MAP_ENTRY_NUM_MAX]; } __packed; /* PERIPH_SCRATCH_MEM_DESC_ADDR_ARRAY_S_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h b/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info.h index 7ae0fbdef208..7ae0fbdef208 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-context-info.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info.h diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/utils.c b/drivers/net/wireless/intel/iwlwifi/pcie/utils.c new file mode 100644 index 000000000000..1bb274d8390c --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/pcie/utils.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2025 Intel Corporation + */ + +#include <linux/pci.h> +#include <linux/gfp.h> + +#include "iwl-io.h" +#include "pcie/utils.h" + +void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev) +{ +#define PCI_DUMP_SIZE 352 +#define PCI_MEM_DUMP_SIZE 64 +#define PCI_PARENT_DUMP_SIZE 524 +#define PREFIX_LEN 32 + + static bool pcie_dbg_dumped_once = 0; + u32 i, pos, alloc_size, *ptr, *buf; + char *prefix; + + if (pcie_dbg_dumped_once) + return; + + /* Should be a multiple of 4 */ + BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3); + BUILD_BUG_ON(PCI_MEM_DUMP_SIZE > 4096 || PCI_MEM_DUMP_SIZE & 0x3); + BUILD_BUG_ON(PCI_PARENT_DUMP_SIZE > 4096 || PCI_PARENT_DUMP_SIZE & 0x3); + + /* Alloc a max size buffer */ + alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN; + alloc_size = max_t(u32, alloc_size, PCI_DUMP_SIZE + PREFIX_LEN); + alloc_size = max_t(u32, alloc_size, PCI_MEM_DUMP_SIZE + PREFIX_LEN); + alloc_size = max_t(u32, alloc_size, PCI_PARENT_DUMP_SIZE + PREFIX_LEN); + + buf = kmalloc(alloc_size, GFP_ATOMIC); + if (!buf) + return; + prefix = (char *)buf + alloc_size - PREFIX_LEN; + + IWL_ERR(trans, "iwlwifi transaction failed, dumping registers\n"); + + /* Print wifi device registers */ + sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); + IWL_ERR(trans, "iwlwifi device config registers:\n"); + for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++) + if (pci_read_config_dword(pdev, i, ptr)) + goto err_read; + print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); + + IWL_ERR(trans, "iwlwifi device memory mapped registers:\n"); + for (i = 0, ptr = buf; i < PCI_MEM_DUMP_SIZE; i += 4, ptr++) + *ptr = iwl_read32(trans, i); + print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); + + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); + if (pos) { + IWL_ERR(trans, "iwlwifi device AER capability structure:\n"); + for (i = 0, ptr = buf; i < PCI_ERR_ROOT_COMMAND; i += 4, ptr++) + if (pci_read_config_dword(pdev, pos + i, ptr)) + goto err_read; + print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, + 32, 4, buf, i, 0); + } + + /* Print parent device registers next */ + if (!pdev->bus->self) + goto out; + + pdev = pdev->bus->self; + sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); + + IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n", + pci_name(pdev)); + for (i = 0, ptr = buf; i < PCI_PARENT_DUMP_SIZE; i += 4, ptr++) + if (pci_read_config_dword(pdev, i, ptr)) + goto err_read; + print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); + + /* Print root port AER registers */ + pos = 0; + pdev = pcie_find_root_port(pdev); + if (pdev) + pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR); + if (pos) { + IWL_ERR(trans, "iwlwifi root port (%s) AER cap structure:\n", + pci_name(pdev)); + sprintf(prefix, "iwlwifi %s: ", pci_name(pdev)); + for (i = 0, ptr = buf; i <= PCI_ERR_ROOT_ERR_SRC; i += 4, ptr++) + if (pci_read_config_dword(pdev, pos + i, ptr)) + goto err_read; + print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, + 4, buf, i, 0); + } + goto out; + +err_read: + print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0); + IWL_ERR(trans, "Read failed at 0x%X\n", i); +out: + pcie_dbg_dumped_once = 1; + kfree(buf); +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/utils.h b/drivers/net/wireless/intel/iwlwifi/pcie/utils.h new file mode 100644 index 000000000000..27437d5e099b --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/pcie/utils.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2025 Intel Corporation + */ + +#ifndef __iwl_pcie_utils_h__ +#define __iwl_pcie_utils_h__ + +#include "iwl-io.h" + +void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev); + +static inline void _iwl_trans_set_bits_mask(struct iwl_trans *trans, + u32 reg, u32 mask, u32 value) +{ + u32 v; + +#ifdef CONFIG_IWLWIFI_DEBUG + WARN_ON_ONCE(value & ~mask); +#endif + + v = iwl_read32(trans, reg); + v &= ~mask; + v |= value; + iwl_write32(trans, reg, v); +} + +static inline void iwl_trans_clear_bit(struct iwl_trans *trans, + u32 reg, u32 mask) +{ + _iwl_trans_set_bits_mask(trans, reg, mask, 0); +} + +static inline void iwl_trans_set_bit(struct iwl_trans *trans, + u32 reg, u32 mask) +{ + _iwl_trans_set_bits_mask(trans, reg, mask, mask); +} + +#endif /* __iwl_pcie_utils_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/tests/Makefile b/drivers/net/wireless/intel/iwlwifi/tests/Makefile index 84491488f589..1b49241c578f 100644 --- a/drivers/net/wireless/intel/iwlwifi/tests/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/tests/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -iwlwifi-tests-y += module.o devinfo.o +iwlwifi-tests-y += module.o devinfo.o utils.o ccflags-y += -I$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c index 784433bb246a..c31bbd4e7a4a 100644 --- a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c +++ b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c @@ -31,15 +31,6 @@ static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *d pos += scnprintf(buf + pos, sizeof(buf) - pos, " bw_limit=*"); - if (di->match_rf_step) - pos += scnprintf(buf + pos, sizeof(buf) - pos, - " rf_step=%c", - di->rf_step == SILICON_Z_STEP ? 'Z' : - 'A' + di->rf_step); - else - pos += scnprintf(buf + pos, sizeof(buf) - pos, - " rf_step=*"); - if (di->match_rf_id) pos += scnprintf(buf + pos, sizeof(buf) - pos, " rf_id=0x%x", di->rf_id); @@ -54,6 +45,13 @@ static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *d pos += scnprintf(buf + pos, sizeof(buf) - pos, " cdb=*"); + if (di->match_discrete) + pos += scnprintf(buf + pos, sizeof(buf) - pos, + " discrete=%d", + di->discrete); + else + pos += scnprintf(buf + pos, sizeof(buf) - pos, + " discrete=*"); printk(KERN_DEBUG "%sdev=%04x subdev=%04x/%04x%s\n", pfx, di->device, di->subdevice, subdevice_mask, buf); @@ -70,7 +68,7 @@ static void devinfo_table_order(struct kunit *test) ret = iwl_pci_find_dev_info(di->device, di->subdevice, di->rf_type, di->cdb, di->rf_id, di->bw_limit, - di->rf_step); + di->discrete); if (!ret) { iwl_pci_print_dev_info("No entry found for: ", di); KUNIT_FAIL(test, @@ -85,6 +83,32 @@ static void devinfo_table_order(struct kunit *test) } } +static void devinfo_discrete_match(struct kunit *test) +{ + /* + * Validate that any entries with discrete/integrated match have + * the same config with the value inverted (if they match at all.) + */ + + for (int idx = 0; idx < iwl_dev_info_table_size; idx++) { + const struct iwl_dev_info *di = &iwl_dev_info_table[idx]; + const struct iwl_dev_info *ret; + + if (!di->match_discrete) + continue; + + ret = iwl_pci_find_dev_info(di->device, di->subdevice, + di->rf_type, di->cdb, + di->rf_id, di->bw_limit, + !di->discrete); + if (!ret) + continue; + KUNIT_EXPECT_PTR_EQ(test, di->cfg, ret->cfg); + /* and check the name is different, that'd be the point of it */ + KUNIT_EXPECT_NE(test, strcmp(di->name, ret->name), 0); + } +} + static void devinfo_names(struct kunit *test) { int idx; @@ -214,8 +238,36 @@ static void devinfo_no_mac_cfg_dups(struct kunit *test) } } +static void devinfo_api_range(struct kunit *test) +{ + /* Check that all iwl_mac_cfg's have either both min and max set, or neither */ + for (int i = 0; iwl_hw_card_ids[i].vendor; i++) { + const struct iwl_mac_cfg *mac_cfg = + (void *)iwl_hw_card_ids[i].driver_data; + const struct iwl_family_base_params *base = mac_cfg->base; + + KUNIT_EXPECT_EQ_MSG(test, !!base->ucode_api_min, + !!base->ucode_api_max, + "%ps: ucode_api_min (%u) and ucode_api_min (%u) should be both set or neither.\n", + base, base->ucode_api_min, + base->ucode_api_max); + } + + /* Check the same for the iwl_rf_cfg's */ + for (int i = 0; i < iwl_dev_info_table_size; i++) { + const struct iwl_rf_cfg *rf_cfg = iwl_dev_info_table[i].cfg; + + KUNIT_EXPECT_EQ_MSG(test, !!rf_cfg->ucode_api_min, + !!rf_cfg->ucode_api_max, + "%ps: ucode_api_min (%u) and ucode_api_min (%u) should be both set or neither.\n", + rf_cfg, rf_cfg->ucode_api_min, + rf_cfg->ucode_api_max); + } +} + static struct kunit_case devinfo_test_cases[] = { KUNIT_CASE(devinfo_table_order), + KUNIT_CASE(devinfo_discrete_match), KUNIT_CASE(devinfo_names), KUNIT_CASE(devinfo_no_cfg_dups), KUNIT_CASE(devinfo_no_name_dups), @@ -223,6 +275,7 @@ static struct kunit_case devinfo_test_cases[] = { KUNIT_CASE(devinfo_check_killer_subdev), KUNIT_CASE(devinfo_pci_ids), KUNIT_CASE(devinfo_no_mac_cfg_dups), + KUNIT_CASE(devinfo_api_range), {} }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/scan.c b/drivers/net/wireless/intel/iwlwifi/tests/utils.c index 7a3275199ace..df2c3a891e7e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/tests/utils.c @@ -1,20 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * KUnit tests for channel helper functions + * KUnit tests for utilities * - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024-2025 Intel Corporation */ -#include <net/mac80211.h> -#include "../mvm.h" +#include "../iwl-utils.h" #include <kunit/test.h> -MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); +MODULE_IMPORT_NS("IWLWIFI"); -static const struct acs_average_db_case { +static const struct average_neg_db_case { const char *desc; u8 neg_dbm[22]; s8 result; -} acs_average_db_cases[] = { +} average_neg_db_cases[] = { { .desc = "Smallest possible value, all filled", .neg_dbm = { @@ -73,38 +72,38 @@ static const struct acs_average_db_case { }, }; -KUNIT_ARRAY_PARAM_DESC(acs_average_db, acs_average_db_cases, desc) +KUNIT_ARRAY_PARAM_DESC(average_neg_db, average_neg_db_cases, desc) -static void test_acs_average_db(struct kunit *test) +static void test_average_neg_db(struct kunit *test) { - const struct acs_average_db_case *params = test->param_value; - struct iwl_umac_scan_channel_survey_notif notif; + const struct average_neg_db_case *params = test->param_value; + u8 reversed[ARRAY_SIZE(params->neg_dbm)]; int i; /* Test the values in the given order */ - for (i = 0; i < ARRAY_SIZE(params->neg_dbm); i++) - notif.noise[i] = params->neg_dbm[i]; KUNIT_ASSERT_EQ(test, - iwl_mvm_average_dbm_values(¬if), + iwl_average_neg_dbm(params->neg_dbm, + ARRAY_SIZE(params->neg_dbm)), params->result); /* Test in reverse order */ for (i = 0; i < ARRAY_SIZE(params->neg_dbm); i++) - notif.noise[ARRAY_SIZE(params->neg_dbm) - i - 1] = + reversed[ARRAY_SIZE(params->neg_dbm) - i - 1] = params->neg_dbm[i]; KUNIT_ASSERT_EQ(test, - iwl_mvm_average_dbm_values(¬if), + iwl_average_neg_dbm(reversed, + ARRAY_SIZE(params->neg_dbm)), params->result); } -static struct kunit_case acs_average_db_case[] = { - KUNIT_CASE_PARAM(test_acs_average_db, acs_average_db_gen_params), +static struct kunit_case average_db_case[] = { + KUNIT_CASE_PARAM(test_average_neg_db, average_neg_db_gen_params), {} }; -static struct kunit_suite acs_average_db = { - .name = "iwlmvm-acs-average-db", - .test_cases = acs_average_db_case, +static struct kunit_suite average_db = { + .name = "iwl-average-db", + .test_cases = average_db_case, }; -kunit_test_suite(acs_average_db); +kunit_test_suite(average_db); diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c index 42111bb53f58..2ec3655f1a9c 100644 --- a/drivers/net/wireless/intersil/p54/main.c +++ b/drivers/net/wireless/intersil/p54/main.c @@ -313,7 +313,7 @@ static void p54_reset_stats(struct p54_common *priv) priv->survey_raw.tx = 0; } -static int p54_config(struct ieee80211_hw *dev, u32 changed) +static int p54_config(struct ieee80211_hw *dev, int radio_idx, u32 changed) { int ret = 0; struct p54_common *priv = dev->priv; @@ -692,6 +692,7 @@ static void p54_flush(struct ieee80211_hw *dev, struct ieee80211_vif *vif, } static void p54_set_coverage_class(struct ieee80211_hw *dev, + int radio_idx, s16 coverage_class) { struct p54_common *priv = dev->priv; diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c index 27f44a9f0bc1..9d66dcae54e0 100644 --- a/drivers/net/wireless/intersil/p54/p54spi.c +++ b/drivers/net/wireless/intersil/p54/p54spi.c @@ -32,7 +32,7 @@ MODULE_FIRMWARE("3826.eeprom"); /* gpios should be handled in board files and provided via platform data, * but because it's currently impossible for p54spi to have a header file - * in include/linux, let's use module paramaters for now + * in include/linux, let's use module parameters for now */ static int p54spi_gpio_power = 97; @@ -155,7 +155,7 @@ static int p54spi_request_firmware(struct ieee80211_hw *dev) struct p54s_priv *priv = dev->priv; int ret; - /* FIXME: should driver use it's own struct device? */ + /* FIXME: should driver use its own struct device? */ ret = request_firmware(&priv->firmware, "3826.arm", &priv->spi->dev); if (ret < 0) { diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 2e2c193716d9..94dd488becaf 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -2146,8 +2146,8 @@ static void lbs_reg_notifier(struct wiphy *wiphy, } /* - * This function get's called after lbs_setup_firmware() determined the - * firmware capabities. So we can setup the wiphy according to our + * This function gets called after lbs_setup_firmware() determined the + * firmware capabilities. So we can setup the wiphy according to our * hardware/firmware. */ int lbs_cfg_register(struct lbs_private *priv) diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 50c0f6179e2d..d1067874428f 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -337,7 +337,7 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw, lbtf_deb_leave(LBTF_DEB_MACOPS); } -static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) +static int lbtf_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct lbtf_private *priv = hw->priv; struct ieee80211_conf *conf = &hw->conf; diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 60c12328c2f3..3498743d5ec0 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -375,6 +375,7 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy, static int mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + int radio_idx, enum nl80211_tx_power_setting type, int mbm) { @@ -410,6 +411,7 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, static int mwifiex_cfg80211_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, + int radio_idx, unsigned int link_id, int *dbm) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); @@ -737,7 +739,8 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) * Fragmentation threshold of the driver. */ static int -mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) +mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, int radio_idx, + u32 changed) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; @@ -1939,7 +1942,8 @@ mwifiex_cfg80211_del_station(struct wiphy *wiphy, struct net_device *dev, } static int -mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) +mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, int radio_idx, u32 tx_ant, + u32 rx_ant) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv = mwifiex_get_priv(adapter, @@ -2002,7 +2006,8 @@ mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) } static int -mwifiex_cfg80211_get_antenna(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant) +mwifiex_cfg80211_get_antenna(struct wiphy *wiphy, int radio_idx, u32 *tx_ant, + u32 *rx_ant) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv = mwifiex_get_priv(adapter, @@ -4778,10 +4783,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; wiphy->n_iface_combinations = 1; - if (adapter->max_sta_conn > adapter->max_p2p_conn) - wiphy->max_ap_assoc_sta = adapter->max_sta_conn; - else - wiphy->max_ap_assoc_sta = adapter->max_p2p_conn; + wiphy->max_ap_assoc_sta = max_t(typeof(wiphy->max_ap_assoc_sta), + adapter->max_sta_conn, + adapter->max_p2p_conn); /* Initialize cipher suits */ wiphy->cipher_suites = mwifiex_cipher_suites; diff --git a/drivers/net/wireless/marvell/mwifiex/fw.h b/drivers/net/wireless/marvell/mwifiex/fw.h index 91458f3bd14a..e9e896606912 100644 --- a/drivers/net/wireless/marvell/mwifiex/fw.h +++ b/drivers/net/wireless/marvell/mwifiex/fw.h @@ -1119,7 +1119,7 @@ struct host_cmd_ds_get_hw_spec { __le32 fw_cap_info; __le32 dot_11n_dev_cap; u8 dev_mcs_support; - __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 mp_end_port; /* SDIO only, reserved for other interfaces */ __le16 mgmt_buf_count; /* mgmt IE buffer count */ __le32 reserved_5; __le32 reserved_6; @@ -1739,7 +1739,7 @@ struct host_cmd_ds_11n_cfg { struct host_cmd_ds_txbuf_cfg { __le16 action; __le16 buff_size; - __le16 mp_end_port; /* SDIO only, reserved for other interfacces */ + __le16 mp_end_port; /* SDIO only, reserved for other interfaces */ __le16 reserved3; } __packed; diff --git a/drivers/net/wireless/marvell/mwifiex/sdio.c b/drivers/net/wireless/marvell/mwifiex/sdio.c index c1fe48448839..f039d6f19183 100644 --- a/drivers/net/wireless/marvell/mwifiex/sdio.c +++ b/drivers/net/wireless/marvell/mwifiex/sdio.c @@ -438,7 +438,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8997 = { .can_auto_tdls = false, .can_ext_scan = true, .fw_ready_extra_delay = false, - .host_mlme = false, + .host_mlme = true, }; static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = { diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c index bab9ef37a1ab..891e125ad30b 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -1227,6 +1227,10 @@ static int rxq_refill(struct ieee80211_hw *hw, int index, int limit) addr = dma_map_single(&priv->pdev->dev, skb->data, MWL8K_RX_MAXSZ, DMA_FROM_DEVICE); + if (dma_mapping_error(&priv->pdev->dev, addr)) { + kfree_skb(skb); + break; + } rxq->rxd_count++; rx = rxq->tail++; @@ -3369,7 +3373,8 @@ struct mwl8k_cmd_set_rts_threshold { } __packed; static int -mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int rts_thresh) +mwl8k_cmd_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + int rts_thresh) { struct mwl8k_cmd_set_rts_threshold *cmd; int rc; @@ -4955,7 +4960,7 @@ fail: wiphy_err(hw->wiphy, "Firmware restart failed\n"); } -static int mwl8k_config(struct ieee80211_hw *hw, u32 changed) +static int mwl8k_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct ieee80211_conf *conf = &hw->conf; struct mwl8k_priv *priv = hw->priv; @@ -5321,9 +5326,10 @@ static void mwl8k_configure_filter(struct ieee80211_hw *hw, mwl8k_fw_unlock(hw); } -static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { - return mwl8k_cmd_set_rts_threshold(hw, value); + return mwl8k_cmd_set_rts_threshold(hw, radio_idx, value); } static int mwl8k_sta_remove(struct ieee80211_hw *hw, @@ -6056,7 +6062,7 @@ static int mwl8k_reload_firmware(struct ieee80211_hw *hw, char *fw_image) if (rc) goto fail; - rc = mwl8k_config(hw, ~0); + rc = mwl8k_config(hw, -1, ~0); if (rc) goto fail; diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c index cc2d888e3f17..77b75792eb48 100644 --- a/drivers/net/wireless/mediatek/mt76/channel.c +++ b/drivers/net/wireless/mediatek/mt76/channel.c @@ -173,13 +173,13 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, if (!mlink) goto out; - if (link_conf != &vif->bss_conf) + if (mlink != (struct mt76_vif_link *)vif->drv_priv) rcu_assign_pointer(mvif->link[link_id], NULL); dev->drv->vif_link_remove(phy, vif, link_conf, mlink); mlink->ctx = NULL; - if (link_conf != &vif->bss_conf) + if (mlink != (struct mt76_vif_link *)vif->drv_priv) kfree_rcu(mlink, rcu_head); out: diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 35b4ec91979e..87f531297f85 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -643,10 +643,8 @@ mt76_dma_rx_fill_buf(struct mt76_dev *dev, struct mt76_queue *q, while (q->queued < q->ndesc - 1) { struct mt76_queue_buf qbuf = {}; - enum dma_data_direction dir; - dma_addr_t addr; - int offset; void *buf = NULL; + int offset; if (mt76_queue_is_wed_rro_ind(q)) goto done; @@ -655,11 +653,8 @@ mt76_dma_rx_fill_buf(struct mt76_dev *dev, struct mt76_queue *q, if (!buf) break; - addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; - dir = page_pool_get_dma_dir(q->page_pool); - dma_sync_single_for_device(dev->dma_dev, addr, len, dir); - - qbuf.addr = addr + q->buf_offset; + qbuf.addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + + offset + q->buf_offset; done: qbuf.len = len - q->buf_offset; qbuf.skip_unmap = false; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 45c8db939d55..3afe4c4cd7bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -1892,7 +1892,8 @@ void mt76_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } EXPORT_SYMBOL_GPL(mt76_sw_scan_complete); -int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +int mt76_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, + u32 *rx_ant) { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index 3353012e8542..65d4c2adb538 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -78,6 +78,10 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb, unsigned long expires; int ret, seq; + if (mt76_is_sdio(dev)) + if (test_bit(MT76_RESET, &dev->phy.state) && atomic_read(&dev->bus_hung)) + return -EIO; + if (ret_skb) *ret_skb = NULL; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 74b75035d361..8dd5c29fb75b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -983,6 +983,8 @@ struct mt76_dev { struct mt76_usb usb; struct mt76_sdio sdio; }; + + atomic_t bus_hung; }; /* per-phy stats. */ @@ -1523,7 +1525,8 @@ int mt76_get_sar_power(struct mt76_phy *phy, void mt76_csa_check(struct mt76_dev *dev); void mt76_csa_finish(struct mt76_dev *dev); -int mt76_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); +int mt76_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, + u32 *rx_ant); int mt76_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set); void mt76_insert_ccmp_hdr(struct sk_buff *skb, u8 key_id); int mt76_get_rate(struct mt76_dev *dev, @@ -1807,7 +1810,8 @@ static inline void mt76_put_page_pool_buf(void *buf, bool allow_direct) { struct page *page = virt_to_head_page(buf); - page_pool_put_full_page(page->pp, page, allow_direct); + page_pool_put_full_page(pp_page_to_nmdesc(page)->pp, page, + allow_direct); } static inline void * @@ -1874,6 +1878,9 @@ mt76_vif_link(struct mt76_dev *dev, struct ieee80211_vif *vif, int link_id) struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; struct mt76_vif_data *mvif = mlink->mvif; + if (!link_id) + return mlink; + return mt76_dereference(mvif->link[link_id], dev); } @@ -1884,7 +1891,7 @@ mt76_vif_conf_link(struct mt76_dev *dev, struct ieee80211_vif *vif, struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; struct mt76_vif_data *mvif = mlink->mvif; - if (link_conf == &vif->bss_conf) + if (link_conf == &vif->bss_conf || !link_conf->link_id) return mlink; return mt76_dereference(mvif->link[link_conf->link_id], dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 3e8b1ec76169..0d7c84941cd0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -216,7 +216,7 @@ static int mt7603_set_sar_specs(struct ieee80211_hw *hw, } static int -mt7603_config(struct ieee80211_hw *hw, u32 changed) +mt7603_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct mt7603_dev *dev = hw->priv; int ret = 0; @@ -657,7 +657,8 @@ mt7603_sta_rate_tbl_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } static void -mt7603_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +mt7603_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, + s16 coverage_class) { struct mt7603_dev *dev = hw->priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 8a37fb37f77d..15fe155ac3f3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -420,7 +420,7 @@ static int mt7615_set_sar_specs(struct ieee80211_hw *hw, return mt76_update_channel(phy->mt76); } -static int mt7615_config(struct ieee80211_hw *hw, u32 changed) +static int mt7615_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); @@ -784,7 +784,8 @@ static void mt7615_tx(struct ieee80211_hw *hw, mt76_connac_pm_queue_skb(hw, &dev->pm, wcid, skb); } -static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +static int mt7615_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 val) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); @@ -972,7 +973,8 @@ mt7615_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } static void -mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +mt7615_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, + s16 coverage_class) { struct mt7615_phy *phy = mt7615_hw_phy(hw); struct mt7615_dev *dev = phy->dev; @@ -984,7 +986,8 @@ mt7615_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) } static int -mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +mt7615_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct mt7615_dev *dev = mt7615_hw_dev(hw); struct mt7615_phy *phy = mt7615_hw_phy(hw); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c index 4aa2dcedc874..a5c40d350612 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/main.c @@ -57,7 +57,7 @@ out: } EXPORT_SYMBOL_GPL(mt76x0_set_sar_specs); -int mt76x0_config(struct ieee80211_hw *hw, u32 changed) +int mt76x0_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct mt76x02_dev *dev = hw->priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h index 50f755344968..e5bc14d4c712 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/mt76x0.h @@ -48,7 +48,7 @@ void mt76x0_chip_onoff(struct mt76x02_dev *dev, bool enable, bool reset); void mt76x0_mac_stop(struct mt76x02_dev *dev); -int mt76x0_config(struct ieee80211_hw *hw, u32 changed); +int mt76x0_config(struct ieee80211_hw *hw, int radio_idx, u32 changed); int mt76x0_set_channel(struct mt76_phy *mphy); int mt76x0_set_sar_specs(struct ieee80211_hw *hw, const struct cfg80211_sar_specs *sar); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02.h b/drivers/net/wireless/mediatek/mt76/mt76x02.h index 9d7ee09b6cc9..8d06ef8c7c62 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02.h +++ b/drivers/net/wireless/mediatek/mt76/mt76x02.h @@ -183,8 +183,8 @@ void mt76x02_wdt_work(struct work_struct *work); void mt76x02_tx_set_txpwr_auto(struct mt76x02_dev *dev, s8 txpwr); void mt76x02_set_tx_ackto(struct mt76x02_dev *dev); void mt76x02_set_coverage_class(struct ieee80211_hw *hw, - s16 coverage_class); -int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val); + int radio_idx, s16 coverage_class); +int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val); void mt76x02_remove_hdr_pad(struct sk_buff *skb, int len); bool mt76x02_tx_status_data(struct mt76_dev *mdev, u8 *update); void mt76x02_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c index 4fb30589fa7a..7dfcb20c692c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c @@ -548,7 +548,7 @@ void mt76x02_set_tx_ackto(struct mt76x02_dev *dev) EXPORT_SYMBOL_GPL(mt76x02_set_tx_ackto); void mt76x02_set_coverage_class(struct ieee80211_hw *hw, - s16 coverage_class) + int radio_idx, s16 coverage_class) { struct mt76x02_dev *dev = hw->priv; @@ -559,7 +559,7 @@ void mt76x02_set_coverage_class(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(mt76x02_set_coverage_class); -int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +int mt76x02_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val) { struct mt76x02_dev *dev = hw->priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c index eb70130d2711..c5dfb06d81e8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci_main.c @@ -54,7 +54,7 @@ int mt76x2e_set_channel(struct mt76_phy *phy) } static int -mt76x2_config(struct ieee80211_hw *hw, u32 changed) +mt76x2_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct mt76x02_dev *dev = hw->priv; @@ -99,8 +99,8 @@ mt76x2_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { } -static int mt76x2_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, - u32 rx_ant) +static int mt76x2_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct mt76x02_dev *dev = hw->priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c index 83e7061b10e2..6671c53faf9f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb_main.c @@ -50,7 +50,7 @@ int mt76x2u_set_channel(struct mt76_phy *mphy) } static int -mt76x2u_config(struct ieee80211_hw *hw, u32 changed) +mt76x2u_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct mt76x02_dev *dev = hw->priv; int err = 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 3aa31c5cefa6..fe0639c14bf9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -449,7 +449,8 @@ out: return err; } -static int mt7915_config(struct ieee80211_hw *hw, u32 changed) +static int mt7915_config(struct ieee80211_hw *hw, int radio_idx, + u32 changed) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); @@ -906,7 +907,8 @@ static void mt7915_tx(struct ieee80211_hw *hw, mt76_tx(mphy, control->sta, wcid, skb); } -static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 val) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); @@ -1102,7 +1104,8 @@ mt7915_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } static void -mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +mt7915_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, + s16 coverage_class) { struct mt7915_phy *phy = mt7915_hw_phy(hw); struct mt7915_dev *dev = phy->dev; @@ -1114,7 +1117,7 @@ mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) } static int -mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +mt7915_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_ant) { struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); @@ -1655,7 +1658,7 @@ mt7915_twt_teardown_request(struct ieee80211_hw *hw, } static int -mt7915_set_frag_threshold(struct ieee80211_hw *hw, u32 val) +mt7915_set_frag_threshold(struct ieee80211_hw *hw, int radio_idx, u32 val) { return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index c6584d2b7509..2928e75b2397 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -197,6 +197,8 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd, static void mt7915_mcu_set_timeout(struct mt76_dev *mdev, int cmd) { + mdev->mcu.timeout = 5 * HZ; + if ((cmd & __MCU_CMD_FIELD_ID) != MCU_CMD_EXT_CID) return; @@ -208,6 +210,9 @@ mt7915_mcu_set_timeout(struct mt76_dev *mdev, int cmd) case MCU_EXT_CMD_BSS_INFO_UPDATE: mdev->mcu.timeout = 2 * HZ; return; + case MCU_EXT_CMD_EFUSE_BUFFER_MODE: + mdev->mcu.timeout = 10 * HZ; + return; default: break; } @@ -2110,16 +2115,21 @@ static int mt7915_load_firmware(struct mt7915_dev *dev) { int ret; - /* make sure fw is download state */ - if (mt7915_firmware_state(dev, false)) { - /* restart firmware once */ - mt76_connac_mcu_restart(&dev->mt76); - ret = mt7915_firmware_state(dev, false); - if (ret) { - dev_err(dev->mt76.dev, - "Firmware is not ready for download\n"); - return ret; - } + /* Release Semaphore if taken by previous failed attempt */ + ret = mt76_connac_mcu_patch_sem_ctrl(&dev->mt76, false); + if (ret != PATCH_REL_SEM_SUCCESS) { + dev_err(dev->mt76.dev, "Could not release semaphore\n"); + /* Continue anyways */ + } + + /* Always restart MCU firmware */ + mt76_connac_mcu_restart(&dev->mt76); + + /* Check if MCU is ready */ + ret = mt7915_firmware_state(dev, false); + if (ret) { + dev_err(dev->mt76.dev, "Firmware did not enter download state\n"); + return ret; } ret = mt76_connac2_load_patch(&dev->mt76, fw_name_var(dev, ROM_PATCH)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index f1f76506b0a5..bce26389ab18 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -675,6 +675,8 @@ void mt7921_mac_reset_work(struct work_struct *work) if (!ret) break; } + if (mt76_is_sdio(&dev->mt76) && atomic_read(&dev->mt76.bus_hung)) + return; if (i == 10) dev_err(dev->mt76.dev, "chip reset failed\n"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 77f73ae1d7ec..40954e64c7fc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -624,7 +624,7 @@ void mt7921_set_runtime_pm(struct mt792x_dev *dev) mt76_connac_mcu_set_deep_sleep(&dev->mt76, pm->ds_enable); } -static int mt7921_config(struct ieee80211_hw *hw, u32 changed) +static int mt7921_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); @@ -907,7 +907,8 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt7921_mac_sta_remove); -static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +static int mt7921_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 val) { struct mt792x_dev *dev = mt792x_hw_dev(hw); @@ -1088,7 +1089,8 @@ mt7921_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } static int -mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +mt7921_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c index 45b9f35aab17..d8d36b3c3068 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -150,6 +150,8 @@ static int mt7921s_probe(struct sdio_func *func, if (ret) goto error; + atomic_set(&mdev->bus_hung, false); + mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) | (mt76_rr(dev, MT_HW_REV) & 0xff); dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c index 1f77cf71ca70..a9eb6252a904 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio_mac.c @@ -6,6 +6,8 @@ #include "mt7921.h" #include "../mt76_connac2_mac.h" #include "../sdio.h" +#include <linux/mmc/host.h> +#include <linux/kallsyms.h> static void mt7921s_enable_irq(struct mt76_dev *dev) { @@ -35,6 +37,9 @@ int mt7921s_wfsys_reset(struct mt792x_dev *dev) struct mt76_sdio *sdio = &dev->mt76.sdio; u32 val, status; + if (atomic_read(&dev->mt76.bus_hung)) + return 0; + mt7921s_mcu_drv_pmctrl(dev); sdio_claim_host(sdio->func); @@ -91,11 +96,64 @@ int mt7921s_init_reset(struct mt792x_dev *dev) return 0; } +static struct mt76_sdio *msdio; +static void mt7921s_card_reset(struct work_struct *work) +{ + struct mmc_host *sdio_host = msdio->func->card->host; + + sdio_claim_host(msdio->func); + sdio_release_irq(msdio->func); + sdio_release_host(msdio->func); + + mmc_remove_host(sdio_host); + msleep(50); + mmc_add_host(sdio_host); +} + +static DECLARE_WORK(sdio_reset_work, mt7921s_card_reset); +static int mt7921s_check_bus(struct mt76_dev *dev) +{ + struct mt76_sdio *sdio = &dev->sdio; + int err; + + sdio_claim_host(sdio->func); + sdio_readl(dev->sdio.func, MCR_WHCR, &err); + sdio_release_host(sdio->func); + + return err; +} + +static int mt7921s_host_reset(struct mt792x_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + int err = -1; + + if (!atomic_read(&mdev->bus_hung)) + err = mt7921s_check_bus(&dev->mt76); + + if (err) { + atomic_set(&mdev->bus_hung, true); + msdio = &dev->mt76.sdio; + dev_err(mdev->dev, "SDIO bus problem detected(%d), resetting card!!\n", err); + schedule_work(&sdio_reset_work); + return err; + } + + atomic_set(&mdev->bus_hung, false); + + return 0; +} + int mt7921s_mac_reset(struct mt792x_dev *dev) { int err; mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + + mt7921s_host_reset(dev); + if (atomic_read(&dev->mt76.bus_hung)) + return 0; + mt76_txq_schedule_all(&dev->mphy); mt76_worker_disable(&dev->mt76.tx_worker); set_bit(MT76_MCU_RESET, &dev->mphy.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 5b001548dffc..a8d25b7d47d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -757,7 +757,7 @@ void mt7925_set_runtime_pm(struct mt792x_dev *dev) mt7925_mcu_set_deep_sleep(dev, pm->ds_enable); } -static int mt7925_config(struct ieee80211_hw *hw, u32 changed) +static int mt7925_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct mt792x_dev *dev = mt792x_hw_dev(hw); int ret = 0; @@ -1265,7 +1265,8 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt7925_mac_sta_remove); -static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +static int mt7925_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 val) { struct mt792x_dev *dev = mt792x_hw_dev(hw); @@ -1507,7 +1508,8 @@ mt7925_stop_sched_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) } static int -mt7925_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +mt7925_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_phy *phy = mt792x_hw_phy(hw); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 8ac6fbb736ab..300c863f0e3e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -2916,7 +2916,7 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, for (i = 0; i < sreq->n_ssids; i++) { if (!sreq->ssids[i].ssid_len) continue; - if (i > MT7925_RNR_SCAN_MAX_BSSIDS) + if (i >= MT7925_RNR_SCAN_MAX_BSSIDS) break; ssid->ssids[n_ssids].ssid_len = cpu_to_le32(sreq->ssids[i].ssid_len); @@ -2933,7 +2933,7 @@ int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, mt76_connac_mcu_build_rnr_scan_param(mdev, sreq); for (j = 0; j < mdev->rnr.bssid_num; j++) { - if (j > MT7925_RNR_SCAN_MAX_BSSIDS) + if (j >= MT7925_RNR_SCAN_MAX_BSSIDS) break; tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_BSSID, diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index e0359d431eca..443d397d9961 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -412,7 +412,8 @@ void mt792x_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct station_info *sinfo); -void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class); +void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, + s16 coverage_class); void mt792x_dma_cleanup(struct mt792x_dev *dev); int mt792x_dma_enable(struct mt792x_dev *dev); int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 05130ec1e5f7..e3a703398b30 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -601,7 +601,8 @@ void mt792x_sta_statistics(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(mt792x_sta_statistics); -void mt792x_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, + s16 coverage_class) { struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = phy->dev; @@ -687,6 +688,7 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); ieee80211_hw_set(hw, CONNECTION_MONITOR); + ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); if (is_mt7921(&dev->mt76)) ieee80211_hw_set(hw, CHANCTX_STA_CSA); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 92148518f6a5..226534490792 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -1084,9 +1084,9 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (wcid->offchannel) mlink = rcu_dereference(mvif->mt76.offchannel_link); if (!mlink) - mlink = &mvif->deflink.mt76; + mlink = rcu_dereference(mvif->mt76.link[wcid->link_id]); - txp->fw.bss_idx = mlink->idx; + txp->fw.bss_idx = mlink ? mlink->idx : mvif->deflink.mt76.idx; } txp->fw.token = cpu_to_le16(id); @@ -1126,15 +1126,14 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) } static void -mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) +mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta, + struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; - struct mt7996_sta_link *msta_link; - struct mt7996_sta *msta; u16 fc, tid; - if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he)) + if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) return; tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; @@ -1143,7 +1142,8 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) if (is_8023) { fc = IEEE80211_FTYPE_DATA | - (sta->wme ? IEEE80211_STYPE_QOS_DATA : IEEE80211_STYPE_DATA); + (link_sta->sta->wme ? IEEE80211_STYPE_QOS_DATA + : IEEE80211_STYPE_DATA); } else { /* No need to get precise TID for Action/Management Frame, * since it will not meet the following Frame Control @@ -1159,19 +1159,16 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb) if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) return; - msta = (struct mt7996_sta *)sta->drv_priv; - msta_link = &msta->deflink; - - if (!test_and_set_bit(tid, &msta_link->wcid.ampdu_state)) - ieee80211_start_tx_ba_session(sta, tid, 0); + if (!test_and_set_bit(tid, &wcid->ampdu_state)) + ieee80211_start_tx_ba_session(link_sta->sta, tid, 0); } static void mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t, - struct ieee80211_sta *sta, struct list_head *free_list) + struct ieee80211_link_sta *link_sta, + struct mt76_wcid *wcid, struct list_head *free_list) { struct mt76_dev *mdev = &dev->mt76; - struct mt76_wcid *wcid; __le32 *txwi; u16 wcid_idx; @@ -1180,12 +1177,10 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t, goto out; txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t); - if (sta) { - wcid = (struct mt76_wcid *)sta->drv_priv; + if (link_sta) { wcid_idx = wcid->idx; - if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7996_tx_check_aggr(sta, t->skb); + mt7996_tx_check_aggr(link_sta, wcid, t->skb); } else { wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX); } @@ -1204,8 +1199,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) struct mt76_dev *mdev = &dev->mt76; struct mt76_phy *phy2 = mdev->phys[MT_BAND1]; struct mt76_phy *phy3 = mdev->phys[MT_BAND2]; + struct ieee80211_link_sta *link_sta = NULL; struct mt76_txwi_cache *txwi; - struct ieee80211_sta *sta = NULL; struct mt76_wcid *wcid = NULL; LIST_HEAD(free_list); struct sk_buff *skb, *tmp; @@ -1242,7 +1237,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) */ info = le32_to_cpu(*cur_info); if (info & MT_TXFREE_INFO_PAIR) { - struct mt7996_sta_link *msta_link; + struct ieee80211_sta *sta; u16 idx; idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info); @@ -1251,9 +1246,11 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len) if (!sta) goto next; - msta_link = container_of(wcid, struct mt7996_sta_link, - wcid); - mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid); + link_sta = rcu_dereference(sta->link[wcid->link_id]); + if (!link_sta) + goto next; + + mt76_wcid_add_poll(&dev->mt76, wcid); next: /* ver 7 has a new DW with pair = 1, skip it */ if (ver == 7 && ((void *)(cur_info + 1) < end) && @@ -1286,7 +1283,8 @@ next: if (!txwi) continue; - mt7996_txwi_free(dev, txwi, sta, &free_list); + mt7996_txwi_free(dev, txwi, link_sta, wcid, + &free_list); } } @@ -1742,7 +1740,7 @@ void mt7996_tx_token_put(struct mt7996_dev *dev) spin_lock_bh(&dev->mt76.token_lock); idr_for_each_entry(&dev->mt76.token, txwi, id) { - mt7996_txwi_free(dev, txwi, NULL, NULL); + mt7996_txwi_free(dev, txwi, NULL, NULL, NULL); dev->mt76.token_count--; } spin_unlock_bh(&dev->mt76.token_lock); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 07dd75ce94a5..92b57bcce749 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -591,7 +591,7 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return err; } -static int mt7996_config(struct ieee80211_hw *hw, u32 changed) +static int mt7996_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { return 0; } @@ -960,8 +960,8 @@ mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, } static void -mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_sta *sta, - unsigned long links) +mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long links) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct mt76_dev *mdev = &dev->mt76; @@ -969,6 +969,8 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_sta *sta, for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { struct mt7996_sta_link *msta_link = NULL; + struct mt7996_vif_link *link; + struct mt76_phy *mphy; msta_link = rcu_replace_pointer(msta->link[link_id], msta_link, lockdep_is_held(&mdev->mutex)); @@ -976,6 +978,15 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_sta *sta, continue; mt7996_mac_sta_deinit_link(dev, msta_link); + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + continue; + + mphy = mt76_vif_link_phy(&link->mt76); + if (!mphy) + continue; + + mphy->num_sta--; if (msta->deflink_id == link_id) { msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; continue; @@ -997,6 +1008,7 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf; struct ieee80211_link_sta *link_sta; struct mt7996_vif_link *link; + struct mt76_phy *mphy; if (rcu_access_pointer(msta->link[link_id])) continue; @@ -1023,12 +1035,19 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, link_id); if (err) goto error_unlink; + + mphy = mt76_vif_link_phy(&link->mt76); + if (!mphy) { + err = -EINVAL; + goto error_unlink; + } + mphy->num_sta++; } return 0; error_unlink: - mt7996_mac_sta_remove_links(dev, sta, new_links); + mt7996_mac_sta_remove_links(dev, vif, sta, new_links); return err; } @@ -1045,7 +1064,7 @@ mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); - mt7996_mac_sta_remove_links(dev, sta, rem); + mt7996_mac_sta_remove_links(dev, vif, sta, rem); ret = mt7996_mac_sta_add_links(dev, vif, sta, add); mutex_unlock(&dev->mt76.mutex); @@ -1054,25 +1073,21 @@ mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } static int -mt7996_mac_sta_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, +mt7996_mac_sta_add(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct mt76_dev *mdev = mphy->dev; - struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - unsigned long links = sta->mlo ? sta->valid_links : BIT(0); + unsigned long links = sta->valid_links ? sta->valid_links : BIT(0); int err; - mutex_lock(&mdev->mutex); + mutex_lock(&dev->mt76.mutex); msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; msta->vif = mvif; err = mt7996_mac_sta_add_links(dev, vif, sta, links); - if (!err) - mphy->num_sta++; - mutex_unlock(&mdev->mutex); + mutex_unlock(&dev->mt76.mutex); return err; } @@ -1118,7 +1133,6 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, return err; msta_link->wcid.tx_info |= MT_WCID_TX_INFO_SET; - msta_link->wcid.sta = 1; break; case MT76_STA_EVENT_AUTHORIZE: err = mt7996_mcu_add_sta(dev, link_conf, link_sta, @@ -1150,19 +1164,14 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, } static void -mt7996_mac_sta_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, +mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct mt76_dev *mdev = mphy->dev; - struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); - unsigned long links = sta->mlo ? sta->valid_links : BIT(0); - - mutex_lock(&mdev->mutex); + unsigned long links = sta->valid_links ? sta->valid_links : BIT(0); - mt7996_mac_sta_remove_links(dev, sta, links); - mphy->num_sta--; - - mutex_unlock(&mdev->mutex); + mutex_lock(&dev->mt76.mutex); + mt7996_mac_sta_remove_links(dev, vif, sta, links); + mutex_unlock(&dev->mt76.mutex); } static int @@ -1170,20 +1179,16 @@ mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { - struct mt76_phy *mphy = mt76_vif_phy(hw, vif); struct mt7996_dev *dev = mt7996_hw_dev(hw); enum mt76_sta_event ev; - if (!mphy) - return -EINVAL; - if (old_state == IEEE80211_STA_NOTEXIST && new_state == IEEE80211_STA_NONE) - return mt7996_mac_sta_add(mphy, vif, sta); + return mt7996_mac_sta_add(dev, vif, sta); if (old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST) - mt7996_mac_sta_remove(mphy, vif, sta); + mt7996_mac_sta_remove(dev, vif, sta); if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) @@ -1216,10 +1221,17 @@ static void mt7996_tx(struct ieee80211_hw *hw, if (vif) { struct mt7996_vif *mvif = (void *)vif->drv_priv; - struct mt76_vif_link *mlink; + struct mt76_vif_link *mlink = &mvif->deflink.mt76; + + if (link_id < IEEE80211_LINK_UNSPECIFIED) + mlink = rcu_dereference(mvif->mt76.link[link_id]); + + if (!mlink) { + ieee80211_free_txskb(hw, skb); + goto unlock; + } - mlink = rcu_dereference(mvif->mt76.link[link_id]); - if (mlink && mlink->wcid) + if (mlink->wcid) wcid = mlink->wcid; if (mvif->mt76.roc_phy && @@ -1228,7 +1240,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, if (mphy->roc_link) wcid = mphy->roc_link->wcid; } else { - mphy = mt76_vif_link_phy(&mvif->deflink.mt76); + mphy = mt76_vif_link_phy(mlink); } } @@ -1237,7 +1249,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, goto unlock; } - if (control->sta) { + if (control->sta && link_id < IEEE80211_LINK_UNSPECIFIED) { struct mt7996_sta *msta = (void *)control->sta->drv_priv; struct mt7996_sta_link *msta_link; @@ -1250,7 +1262,8 @@ unlock: rcu_read_unlock(); } -static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val) +static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 val) { struct mt7996_dev *dev = mt7996_hw_dev(hw); int i, ret = 0; @@ -1490,7 +1503,8 @@ unlock: } static void -mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) +mt7996_set_coverage_class(struct ieee80211_hw *hw, int radio_idx, + s16 coverage_class) { struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_phy *phy; @@ -1504,7 +1518,8 @@ mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class) } static int -mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +mt7996_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct mt7996_dev *dev = mt7996_hw_dev(hw); int i; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 994526c65bfc..3593fd40c51b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -2299,15 +2299,15 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif, static void mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, + struct ieee80211_vif *vif, struct ieee80211_sta *sta) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - unsigned long links = sta->valid_links; - unsigned int nlinks = hweight16(links); + unsigned int nlinks = hweight16(sta->valid_links); struct mld_setup_link *mld_setup_link; + struct ieee80211_link_sta *link_sta; struct sta_rec_mld_setup *mld_setup; struct mt7996_sta_link *msta_link; - struct ieee80211_vif *vif; unsigned int link_id; struct tlv *tlv; @@ -2325,18 +2325,16 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx); if (nlinks > 1) { - link_id = __ffs(links & ~BIT(msta->deflink_id)); - msta_link = mt76_dereference(msta->link[msta->deflink_id], - &dev->mt76); + link_id = __ffs(sta->valid_links & ~BIT(msta->deflink_id)); + msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); if (!msta_link) return; } mld_setup->seconed_id = cpu_to_le16(msta_link->wcid.idx); mld_setup->link_num = nlinks; - vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); mld_setup_link = (struct mld_setup_link *)mld_setup->link_info; - for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + for_each_sta_active_link(vif, sta, link_sta, link_id) { struct mt7996_vif_link *link; msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); @@ -2428,7 +2426,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, mt7996_mcu_sta_muru_tlv(dev, skb, link_conf, link_sta); if (sta->mlo) { - mt7996_mcu_sta_mld_setup_tlv(dev, skb, sta); + mt7996_mcu_sta_mld_setup_tlv(dev, skb, link_conf->vif, + sta); mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta); } } diff --git a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c index 0a927a7313a6..f882d21c9f63 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio_txrx.c +++ b/drivers/net/wireless/mediatek/mt76/sdio_txrx.c @@ -112,6 +112,7 @@ mt76s_rx_run_queue(struct mt76_dev *dev, enum mt76_rxq_id qid, if (err < 0) { dev_err(dev->dev, "sdio read data failed:%d\n", err); + atomic_set(&dev->bus_hung, true); put_page(page); return err; } @@ -234,9 +235,10 @@ static int __mt76s_xmit_queue(struct mt76_dev *dev, u8 *data, int len) err = sdio_writesb(sdio->func, MCR_WTDR1, data, len); sdio_release_host(sdio->func); - if (err) + if (err) { dev_err(dev->dev, "sdio write failed: %d\n", err); - + atomic_set(&dev->bus_hung, true); + } return err; } diff --git a/drivers/net/wireless/mediatek/mt76/wed.c b/drivers/net/wireless/mediatek/mt76/wed.c index f89e4537555c..63f69e152b1c 100644 --- a/drivers/net/wireless/mediatek/mt76/wed.c +++ b/drivers/net/wireless/mediatek/mt76/wed.c @@ -34,11 +34,10 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; - int i, len = SKB_WITH_OVERHEAD(q->buf_size); struct mt76_txwi_cache *t = NULL; + int i; for (i = 0; i < size; i++) { - enum dma_data_direction dir; dma_addr_t addr; u32 offset; int token; @@ -53,9 +52,6 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) goto unmap; addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset; - dir = page_pool_get_dma_dir(q->page_pool); - dma_sync_single_for_device(dev->dma_dev, addr, len, dir); - desc->buf0 = cpu_to_le32(addr); token = mt76_rx_token_consume(dev, buf, t, addr); if (token < 0) { diff --git a/drivers/net/wireless/mediatek/mt7601u/main.c b/drivers/net/wireless/mediatek/mt7601u/main.c index 7570c6ceecea..05ba43e1985c 100644 --- a/drivers/net/wireless/mediatek/mt7601u/main.c +++ b/drivers/net/wireless/mediatek/mt7601u/main.c @@ -78,7 +78,7 @@ static void mt7601u_remove_interface(struct ieee80211_hw *hw, dev->wcid_mask[wcid / BITS_PER_LONG] &= ~BIT(wcid % BITS_PER_LONG); } -static int mt7601u_config(struct ieee80211_hw *hw, u32 changed) +static int mt7601u_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct mt7601u_dev *dev = hw->priv; int ret = 0; @@ -334,7 +334,8 @@ mt7601u_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return mt76_mac_wcid_set_key(dev, msta->wcid.idx, key); } -static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int mt7601u_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct mt7601u_dev *dev = hw->priv; diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index e7aa0f991923..a395829ebadf 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -800,7 +800,7 @@ static int change_bss(struct wiphy *wiphy, struct net_device *dev, return 0; } -static int set_wiphy_params(struct wiphy *wiphy, u32 changed) +static int set_wiphy_params(struct wiphy *wiphy, int radio_idx, u32 changed) { int ret = -EINVAL; struct cfg_param_attr cfg_param_val; @@ -1637,7 +1637,8 @@ static void wilc_set_wakeup(struct wiphy *wiphy, bool enabled) } static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, int mbm) + int radio_idx, enum nl80211_tx_power_setting type, + int mbm) { int ret; int srcu_idx; @@ -1669,7 +1670,7 @@ static int set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, } static int get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - unsigned int link_id, int *dbm) + int radio_idx, unsigned int link_id, int *dbm) { int ret; struct wilc_vif *vif = netdev_priv(wdev->netdev); diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 9d80adc45d6b..fedc7d59216a 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -1287,10 +1287,7 @@ int wilc_wlan_firmware_download(struct wilc *wilc, const u8 *buffer, offset += 8; while (((int)size) && (offset < buffer_size)) { - if (size <= blksz) - size2 = size; - else - size2 = blksz; + size2 = min(size, blksz); memcpy(dma_buffer, &buffer[offset], size2); ret = wilc->hif_func->hif_block_tx(wilc, addr, diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.c b/drivers/net/wireless/purelifi/plfxlc/mac.c index 82d1bf7edba2..a900421753ac 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.c +++ b/drivers/net/wireless/purelifi/plfxlc/mac.c @@ -99,11 +99,6 @@ int plfxlc_mac_init_hw(struct ieee80211_hw *hw) return r; } -void plfxlc_mac_release(struct plfxlc_mac *mac) -{ - plfxlc_chip_release(&mac->chip); -} - int plfxlc_op_start(struct ieee80211_hw *hw) { plfxlc_hw_mac(hw)->chip.usb.initialized = 1; @@ -531,7 +526,7 @@ static void plfxlc_op_remove_interface(struct ieee80211_hw *hw, mac->vif = NULL; } -static int plfxlc_op_config(struct ieee80211_hw *hw, u32 changed) +static int plfxlc_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { return 0; } @@ -677,7 +672,8 @@ static void plfxlc_get_et_stats(struct ieee80211_hw *hw, data[1] = mac->crc_errors; } -static int plfxlc_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int plfxlc_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { return 0; } @@ -755,3 +751,9 @@ struct ieee80211_hw *plfxlc_mac_alloc_hw(struct usb_interface *intf) SET_IEEE80211_DEV(hw, &intf->dev); return hw; } + +void plfxlc_mac_release_hw(struct ieee80211_hw *hw) +{ + plfxlc_chip_release(&plfxlc_hw_mac(hw)->chip); + ieee80211_free_hw(hw); +} diff --git a/drivers/net/wireless/purelifi/plfxlc/mac.h b/drivers/net/wireless/purelifi/plfxlc/mac.h index 9384acddcf26..56da502999c1 100644 --- a/drivers/net/wireless/purelifi/plfxlc/mac.h +++ b/drivers/net/wireless/purelifi/plfxlc/mac.h @@ -168,7 +168,7 @@ static inline u8 *plfxlc_mac_get_perm_addr(struct plfxlc_mac *mac) } struct ieee80211_hw *plfxlc_mac_alloc_hw(struct usb_interface *intf); -void plfxlc_mac_release(struct plfxlc_mac *mac); +void plfxlc_mac_release_hw(struct ieee80211_hw *hw); int plfxlc_mac_preinit_hw(struct ieee80211_hw *hw, const u8 *hw_address); int plfxlc_mac_init_hw(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/purelifi/plfxlc/usb.c b/drivers/net/wireless/purelifi/plfxlc/usb.c index d8b0b79dea1a..711902a809db 100644 --- a/drivers/net/wireless/purelifi/plfxlc/usb.c +++ b/drivers/net/wireless/purelifi/plfxlc/usb.c @@ -604,7 +604,7 @@ static int probe(struct usb_interface *intf, r = plfxlc_upload_mac_and_serial(intf, hw_address, serial_number); if (r) { dev_err(&intf->dev, "MAC and Serial upload failed (%d)\n", r); - goto error; + goto error_free_hw; } chip->unit_type = STA; @@ -613,13 +613,13 @@ static int probe(struct usb_interface *intf, r = plfxlc_mac_preinit_hw(hw, hw_address); if (r) { dev_err(&intf->dev, "Init mac failed (%d)\n", r); - goto error; + goto error_free_hw; } r = ieee80211_register_hw(hw); if (r) { dev_err(&intf->dev, "Register device failed (%d)\n", r); - goto error; + goto error_free_hw; } if ((le16_to_cpu(interface_to_usbdev(intf)->descriptor.idVendor) == @@ -632,7 +632,7 @@ static int probe(struct usb_interface *intf, } if (r != 0) { dev_err(&intf->dev, "FPGA download failed (%d)\n", r); - goto error; + goto error_unreg_hw; } tx->mac_fifo_full = 0; @@ -642,21 +642,21 @@ static int probe(struct usb_interface *intf, r = plfxlc_usb_init_hw(usb); if (r < 0) { dev_err(&intf->dev, "usb_init_hw failed (%d)\n", r); - goto error; + goto error_unreg_hw; } msleep(PLF_MSLEEP_TIME); r = plfxlc_chip_switch_radio(chip, PLFXLC_RADIO_ON); if (r < 0) { dev_dbg(&intf->dev, "chip_switch_radio_on failed (%d)\n", r); - goto error; + goto error_unreg_hw; } msleep(PLF_MSLEEP_TIME); r = plfxlc_chip_set_rate(chip, 8); if (r < 0) { dev_dbg(&intf->dev, "chip_set_rate failed (%d)\n", r); - goto error; + goto error_unreg_hw; } msleep(PLF_MSLEEP_TIME); @@ -664,7 +664,7 @@ static int probe(struct usb_interface *intf, hw_address, ETH_ALEN, USB_REQ_MAC_WR); if (r < 0) { dev_dbg(&intf->dev, "MAC_WR failure (%d)\n", r); - goto error; + goto error_unreg_hw; } plfxlc_chip_enable_rxtx(chip); @@ -691,12 +691,12 @@ static int probe(struct usb_interface *intf, plfxlc_mac_init_hw(hw); usb->initialized = true; return 0; + +error_unreg_hw: + ieee80211_unregister_hw(hw); +error_free_hw: + plfxlc_mac_release_hw(hw); error: - if (hw) { - plfxlc_mac_release(plfxlc_hw_mac(hw)); - ieee80211_unregister_hw(hw); - ieee80211_free_hw(hw); - } dev_err(&intf->dev, "pureLifi:Device error"); return r; } @@ -730,8 +730,7 @@ static void disconnect(struct usb_interface *intf) */ usb_reset_device(interface_to_usbdev(intf)); - plfxlc_mac_release(mac); - ieee80211_free_hw(hw); + plfxlc_mac_release_hw(hw); } static void plfxlc_usb_resume(struct plfxlc_usb *usb) diff --git a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c index 0b2282528342..f1188368e66b 100644 --- a/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c +++ b/drivers/net/wireless/quantenna/qtnfmac/cfg80211.c @@ -370,7 +370,8 @@ static int qtnf_stop_ap(struct wiphy *wiphy, struct net_device *dev, return ret; } -static int qtnf_set_wiphy_params(struct wiphy *wiphy, u32 changed) +static int qtnf_set_wiphy_params(struct wiphy *wiphy, int radio_idx, + u32 changed) { struct qtnf_wmac *mac = wiphy_priv(wiphy); struct qtnf_vif *vif; @@ -881,7 +882,7 @@ static int qtnf_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev, } static int qtnf_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - unsigned int link_id, int *dbm) + int radio_idx, unsigned int link_id, int *dbm) { struct qtnf_vif *vif = qtnf_netdev_get_priv(wdev->netdev); int ret; @@ -894,7 +895,8 @@ static int qtnf_get_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, } static int qtnf_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev, - enum nl80211_tx_power_setting type, int mbm) + int radio_idx, enum nl80211_tx_power_setting type, + int mbm) { struct qtnf_vif *vif; int ret; diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig index d1fd66d44a7e..4d98b7723c56 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -202,8 +202,7 @@ endif config RT2800SOC tristate "Ralink WiSoC support" - depends on SOC_RT288X || SOC_RT305X || SOC_MT7620 - select RT2X00_LIB_SOC + depends on OF && (SOC_RT288X || SOC_RT305X || SOC_MT7620 || COMPILE_TEST) select RT2X00_LIB_MMIO select RT2X00_LIB_CRYPTO select RT2X00_LIB_FIRMWARE @@ -231,10 +230,6 @@ config RT2X00_LIB_PCI tristate select RT2X00_LIB -config RT2X00_LIB_SOC - tristate - select RT2X00_LIB - config RT2X00_LIB_USB tristate select RT2X00_LIB diff --git a/drivers/net/wireless/ralink/rt2x00/Makefile b/drivers/net/wireless/ralink/rt2x00/Makefile index de030ebcdf6e..48d84d243606 100644 --- a/drivers/net/wireless/ralink/rt2x00/Makefile +++ b/drivers/net/wireless/ralink/rt2x00/Makefile @@ -12,7 +12,6 @@ rt2x00lib-$(CONFIG_RT2X00_LIB_LEDS) += rt2x00leds.o obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o obj-$(CONFIG_RT2X00_LIB_MMIO) += rt2x00mmio.o obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o -obj-$(CONFIG_RT2X00_LIB_SOC) += rt2x00soc.o obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o obj-$(CONFIG_RT2800_LIB) += rt2800lib.o obj-$(CONFIG_RT2800_LIB_MMIO) += rt2800mmio.o diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c index b7ea606bda08..b264ed0af923 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -639,7 +639,7 @@ static bool rt2800_check_firmware_crc(const u8 *data, const size_t len) /* * Use the crc ccitt algorithm. * This will return the same value as the legacy driver which - * used bit ordering reversion on the both the firmware bytes + * used bit ordering reversion on both the firmware bytes * before input input as well as on the final output. * Obviously using crc ccitt directly is much more efficient. */ @@ -12100,7 +12100,7 @@ void rt2800_get_key_seq(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2800_get_key_seq); -int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +int rt2800_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 value) { struct rt2x00_dev *rt2x00dev = hw->priv; u32 reg; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h index 194de676df8f..620a3d9872ce 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -253,7 +253,8 @@ int rt2800_probe_hw(struct rt2x00_dev *rt2x00dev); void rt2800_get_key_seq(struct ieee80211_hw *hw, struct ieee80211_key_conf *key, struct ieee80211_key_seq *seq); -int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +int rt2800_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value); int rt2800_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, unsigned int link_id, u16 queue_idx, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c index 701ba54bf3e5..8f510a84e7f1 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c @@ -18,11 +18,11 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include "rt2x00.h" #include "rt2x00mmio.h" -#include "rt2x00soc.h" #include "rt2800.h" #include "rt2800lib.h" #include "rt2800mmio.h" @@ -131,6 +131,24 @@ static int rt2800soc_write_firmware(struct rt2x00_dev *rt2x00dev, return 0; } +#ifdef CONFIG_PM +static int rt2800soc_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + return rt2x00lib_suspend(rt2x00dev); +} + +static int rt2800soc_resume(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + return rt2x00lib_resume(rt2x00dev); +} +#endif /* CONFIG_PM */ + static const struct ieee80211_ops rt2800soc_mac80211_ops = { .add_chanctx = ieee80211_emulate_add_chanctx, .remove_chanctx = ieee80211_emulate_remove_chanctx, @@ -238,20 +256,102 @@ static const struct rt2x00_ops rt2800soc_ops = { #endif /* CONFIG_RT2X00_LIB_DEBUGFS */ }; +static int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) +{ + struct rt2x00_dev *rt2x00dev; + struct ieee80211_hw *hw; + void __iomem *mem; + struct clk *clk; + __le16 *eeprom; + int retval; + u32 *rf; + int irq; + + mem = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(mem)) + return PTR_ERR(mem); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + clk = devm_clk_get_optional(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + eeprom = devm_kzalloc(&pdev->dev, ops->eeprom_size, GFP_KERNEL); + if (!eeprom) + return -ENOMEM; + + rf = devm_kzalloc(&pdev->dev, ops->rf_size, GFP_KERNEL); + if (!rf) + return -ENOMEM; + + hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); + if (!hw) + return dev_err_probe(&pdev->dev, -ENOMEM, "Failed to allocate hardware"); + + platform_set_drvdata(pdev, hw); + + rt2x00dev = hw->priv; + rt2x00dev->dev = &pdev->dev; + rt2x00dev->ops = ops; + rt2x00dev->hw = hw; + rt2x00dev->irq = irq; + rt2x00dev->clk = clk; + rt2x00dev->eeprom = eeprom; + rt2x00dev->rf = rf; + rt2x00dev->name = pdev->dev.driver->name; + rt2x00dev->csr.base = mem; + + rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); + + retval = rt2x00lib_probe_dev(rt2x00dev); + if (retval) + goto exit_free_device; + + return 0; + +exit_free_device: + ieee80211_free_hw(hw); + + return retval; +} + static int rt2800soc_probe(struct platform_device *pdev) { return rt2x00soc_probe(pdev, &rt2800soc_ops); } +static void rt2800soc_remove(struct platform_device *pdev) +{ + struct ieee80211_hw *hw = platform_get_drvdata(pdev); + struct rt2x00_dev *rt2x00dev = hw->priv; + + /* + * Free all allocated data. + */ + rt2x00lib_remove_dev(rt2x00dev); + ieee80211_free_hw(hw); +} + +static const struct of_device_id rt2880_wmac_match[] = { + { .compatible = "ralink,rt2880-wifi" }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt2880_wmac_match); + static struct platform_driver rt2800soc_driver = { .driver = { .name = "rt2800_wmac", - .mod_name = KBUILD_MODNAME, + .of_match_table = rt2880_wmac_match, }, .probe = rt2800soc_probe, - .remove = rt2x00soc_remove, - .suspend = rt2x00soc_suspend, - .resume = rt2x00soc_resume, + .remove = rt2800soc_remove, +#ifdef CONFIG_PM + .suspend = rt2800soc_suspend, + .resume = rt2800soc_resume, +#endif }; module_platform_driver(rt2800soc_driver); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h index dfb4bb370f01..09b9d1f9f793 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -1457,7 +1457,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); +int rt2x00mac_config(struct ieee80211_hw *hw, int radio_idx, u32 changed); void rt2x00mac_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, @@ -1489,8 +1489,10 @@ int rt2x00mac_conf_tx(struct ieee80211_hw *hw, void rt2x00mac_rfkill_poll(struct ieee80211_hw *hw); void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); -int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); -int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); +int rt2x00mac_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant); +int rt2x00mac_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant); void rt2x00mac_get_ringparam(struct ieee80211_hw *hw, u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); bool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c index 432ddfac2c33..7db29e90eb4f 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -357,7 +357,7 @@ static void rt2x00lib_fill_tx_status(struct rt2x00_dev *rt2x00dev, } /* - * Every single frame has it's own tx status, hence report + * Every single frame has its own tx status, hence report * every frame as ampdu of size 1. * * TODO: if we can find out how many frames were aggregated @@ -496,7 +496,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, /* * If the IV/EIV data was stripped from the frame before it was * passed to the hardware, we should now reinsert it again because - * mac80211 will expect the same data to be present it the + * mac80211 will expect the same data to be present in the * frame as it was passed to us. */ if (rt2x00_has_cap_hw_crypto(rt2x00dev)) diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c index 451632488805..3bc0c1c906c9 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c @@ -304,7 +304,7 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); -int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) +int rt2x00mac_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct rt2x00_dev *rt2x00dev = hw->priv; struct ieee80211_conf *conf = &hw->conf; @@ -740,7 +740,8 @@ void rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(rt2x00mac_flush); -int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +int rt2x00mac_set_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 tx_ant, u32 rx_ant) { struct rt2x00_dev *rt2x00dev = hw->priv; struct link_ant *ant = &rt2x00dev->link.ant; @@ -785,7 +786,8 @@ int rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) } EXPORT_SYMBOL_GPL(rt2x00mac_set_antenna); -int rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +int rt2x00mac_get_antenna(struct ieee80211_hw *hw, int radio_idx, + u32 *tx_ant, u32 *rx_ant) { struct rt2x00_dev *rt2x00dev = hw->priv; struct link_ant *ant = &rt2x00dev->link.ant; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c index 013003777fee..13e48b1e7356 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c @@ -45,7 +45,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp) /* * For IV/EIV/ICV assembly we must make sure there is - * at least 8 bytes bytes available in headroom for IV/EIV + * at least 8 bytes available in headroom for IV/EIV * and 8 bytes for ICV data as tailroon. */ if (rt2x00_has_cap_hw_crypto(rt2x00dev)) { diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c deleted file mode 100644 index f7f3a2340c39..000000000000 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c +++ /dev/null @@ -1,151 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> - Copyright (C) 2004 - 2009 Felix Fietkau <nbd@openwrt.org> - <http://rt2x00.serialmonkey.com> - - */ - -/* - Module: rt2x00soc - Abstract: rt2x00 generic soc device routines. - */ - -#include <linux/bug.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -#include "rt2x00.h" -#include "rt2x00soc.h" - -static void rt2x00soc_free_reg(struct rt2x00_dev *rt2x00dev) -{ - kfree(rt2x00dev->rf); - rt2x00dev->rf = NULL; - - kfree(rt2x00dev->eeprom); - rt2x00dev->eeprom = NULL; - - iounmap(rt2x00dev->csr.base); -} - -static int rt2x00soc_alloc_reg(struct rt2x00_dev *rt2x00dev) -{ - struct platform_device *pdev = to_platform_device(rt2x00dev->dev); - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - rt2x00dev->csr.base = ioremap(res->start, resource_size(res)); - if (!rt2x00dev->csr.base) - return -ENOMEM; - - rt2x00dev->eeprom = kzalloc(rt2x00dev->ops->eeprom_size, GFP_KERNEL); - if (!rt2x00dev->eeprom) - goto exit; - - rt2x00dev->rf = kzalloc(rt2x00dev->ops->rf_size, GFP_KERNEL); - if (!rt2x00dev->rf) - goto exit; - - return 0; - -exit: - rt2x00_probe_err("Failed to allocate registers\n"); - rt2x00soc_free_reg(rt2x00dev); - - return -ENOMEM; -} - -int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) -{ - struct ieee80211_hw *hw; - struct rt2x00_dev *rt2x00dev; - int retval; - - hw = ieee80211_alloc_hw(sizeof(struct rt2x00_dev), ops->hw); - if (!hw) { - rt2x00_probe_err("Failed to allocate hardware\n"); - return -ENOMEM; - } - - platform_set_drvdata(pdev, hw); - - rt2x00dev = hw->priv; - rt2x00dev->dev = &pdev->dev; - rt2x00dev->ops = ops; - rt2x00dev->hw = hw; - rt2x00dev->irq = platform_get_irq(pdev, 0); - rt2x00dev->name = pdev->dev.driver->name; - - rt2x00dev->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(rt2x00dev->clk)) - rt2x00dev->clk = NULL; - - rt2x00_set_chip_intf(rt2x00dev, RT2X00_CHIP_INTF_SOC); - - retval = rt2x00soc_alloc_reg(rt2x00dev); - if (retval) - goto exit_free_device; - - retval = rt2x00lib_probe_dev(rt2x00dev); - if (retval) - goto exit_free_reg; - - return 0; - -exit_free_reg: - rt2x00soc_free_reg(rt2x00dev); - -exit_free_device: - ieee80211_free_hw(hw); - - return retval; -} -EXPORT_SYMBOL_GPL(rt2x00soc_probe); - -void rt2x00soc_remove(struct platform_device *pdev) -{ - struct ieee80211_hw *hw = platform_get_drvdata(pdev); - struct rt2x00_dev *rt2x00dev = hw->priv; - - /* - * Free all allocated data. - */ - rt2x00lib_remove_dev(rt2x00dev); - rt2x00soc_free_reg(rt2x00dev); - ieee80211_free_hw(hw); -} -EXPORT_SYMBOL_GPL(rt2x00soc_remove); - -#ifdef CONFIG_PM -int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct ieee80211_hw *hw = platform_get_drvdata(pdev); - struct rt2x00_dev *rt2x00dev = hw->priv; - - return rt2x00lib_suspend(rt2x00dev); -} -EXPORT_SYMBOL_GPL(rt2x00soc_suspend); - -int rt2x00soc_resume(struct platform_device *pdev) -{ - struct ieee80211_hw *hw = platform_get_drvdata(pdev); - struct rt2x00_dev *rt2x00dev = hw->priv; - - return rt2x00lib_resume(rt2x00dev); -} -EXPORT_SYMBOL_GPL(rt2x00soc_resume); -#endif /* CONFIG_PM */ - -/* - * rt2x00soc module information. - */ -MODULE_AUTHOR(DRV_PROJECT); -MODULE_VERSION(DRV_VERSION); -MODULE_DESCRIPTION("rt2x00 soc library"); -MODULE_LICENSE("GPL"); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.h b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.h deleted file mode 100644 index d6226b8a10e0..000000000000 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> - <http://rt2x00.serialmonkey.com> - - */ - -/* - Module: rt2x00soc - Abstract: Data structures for the rt2x00soc module. - */ - -#ifndef RT2X00SOC_H -#define RT2X00SOC_H - -/* - * SoC driver handlers. - */ -int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops); -void rt2x00soc_remove(struct platform_device *pdev); -#ifdef CONFIG_PM -int rt2x00soc_suspend(struct platform_device *pdev, pm_message_t state); -int rt2x00soc_resume(struct platform_device *pdev); -#else -#define rt2x00soc_suspend NULL -#define rt2x00soc_resume NULL -#endif /* CONFIG_PM */ - -#endif /* RT2X00SOC_H */ diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c index ded8d4d59289..2905baea6239 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c @@ -1370,7 +1370,7 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev, priv->vif = NULL; } -static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) +static int rtl8180_config(struct ieee80211_hw *dev, int radio_idx, u32 changed) { struct rtl8180_priv *priv = dev->priv; struct ieee80211_conf *conf = &dev->conf; diff --git a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c index 220ac5bdf279..0c5c66401daa 100644 --- a/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c @@ -1041,10 +1041,11 @@ static void rtl8187_stop(struct ieee80211_hw *dev, bool suspend) rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); + usb_kill_anchored_urbs(&priv->anchored); + while ((skb = skb_dequeue(&priv->b_tx_status.queue))) dev_kfree_skb_any(skb); - usb_kill_anchored_urbs(&priv->anchored); mutex_unlock(&priv->conf_mutex); if (!priv->is_rtl8187b) @@ -1151,7 +1152,7 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, mutex_unlock(&priv->conf_mutex); } -static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) +static int rtl8187_config(struct ieee80211_hw *dev, int radio_idx, u32 changed) { struct rtl8187_priv *priv = dev->priv; struct ieee80211_conf *conf = &dev->conf; diff --git a/drivers/net/wireless/realtek/rtl8xxxu/core.c b/drivers/net/wireless/realtek/rtl8xxxu/core.c index 569856ca677f..831b5025c634 100644 --- a/drivers/net/wireless/realtek/rtl8xxxu/core.c +++ b/drivers/net/wireless/realtek/rtl8xxxu/core.c @@ -1163,7 +1163,7 @@ static void rtl8xxxu_start_tx_beacon(struct rtl8xxxu_priv *priv) /* - * The rtl8723a has 3 channel groups for it's efuse settings. It only + * The rtl8723a has 3 channel groups for its efuse settings. It only * supports the 2.4GHz band, so channels 1 - 14: * group 0: channels 1 - 3 * group 1: channels 4 - 9 @@ -4552,7 +4552,8 @@ static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv, } static -int rtl8xxxu_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +int rtl8xxxu_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, + u32 *rx_ant) { struct rtl8xxxu_priv *priv = hw->priv; @@ -6617,7 +6618,7 @@ static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv, skb_size = fops->rx_agg_buf_size; skb_size += (rx_desc_sz + sizeof(struct rtl8723au_phy_stats)); } else { - skb_size = IEEE80211_MAX_FRAME_LEN; + skb_size = IEEE80211_MAX_FRAME_LEN + rx_desc_sz; } skb = __netdev_alloc_skb(NULL, skb_size, GFP_KERNEL); @@ -6839,7 +6840,7 @@ static void rtl8xxxu_remove_interface(struct ieee80211_hw *hw, priv->vifs[rtlvif->port_num] = NULL; } -static int rtl8xxxu_config(struct ieee80211_hw *hw, u32 changed) +static int rtl8xxxu_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct rtl8xxxu_priv *priv = hw->priv; struct device *dev = &priv->udev->dev; @@ -6988,7 +6989,8 @@ static void rtl8xxxu_configure_filter(struct ieee80211_hw *hw, FIF_PROBE_REQ); } -static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, u32 rts) +static int rtl8xxxu_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 rts) { if (rts > 2347 && rts != (u32)-1) return -EINVAL; diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 819cf519e66e..22633c301564 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -566,7 +566,7 @@ static int rtl_op_resume(struct ieee80211_hw *hw) } #endif -static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) +static int rtl_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_phy *rtlphy = &(rtlpriv->phy); diff --git a/drivers/net/wireless/realtek/rtlwifi/pci.c b/drivers/net/wireless/realtek/rtlwifi/pci.c index 898f597f70a9..d080469264cf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/pci.c +++ b/drivers/net/wireless/realtek/rtlwifi/pci.c @@ -572,8 +572,11 @@ remap: dma_map_single(&rtlpci->pdev->dev, skb_tail_pointer(skb), rtlpci->rxbuffersize, DMA_FROM_DEVICE); bufferaddress = *((dma_addr_t *)skb->cb); - if (dma_mapping_error(&rtlpci->pdev->dev, bufferaddress)) + if (dma_mapping_error(&rtlpci->pdev->dev, bufferaddress)) { + if (!new_skb) + kfree_skb(skb); return 0; + } rtlpci->rx_ring[rxring_idx].rx_buf[desc_idx] = skb; if (rtlpriv->use_new_trx_flow) { /* skb->cb may be 64 bit address */ @@ -802,13 +805,19 @@ new_trx_end: skb = new_skb; no_new: if (rtlpriv->use_new_trx_flow) { - _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc, - rxring_idx, - rtlpci->rx_ring[rxring_idx].idx); + if (!_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)buffer_desc, + rxring_idx, + rtlpci->rx_ring[rxring_idx].idx)) { + if (new_skb) + dev_kfree_skb_any(skb); + } } else { - _rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc, - rxring_idx, - rtlpci->rx_ring[rxring_idx].idx); + if (!_rtl_pci_init_one_rxdesc(hw, skb, (u8 *)pdesc, + rxring_idx, + rtlpci->rx_ring[rxring_idx].idx)) { + if (new_skb) + dev_kfree_skb_any(skb); + } if (rtlpci->rx_ring[rxring_idx].idx == rtlpci->rxringcount - 1) rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c index d122f1eb345e..53c32e1de7e4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/hw.c @@ -1738,9 +1738,9 @@ static void read_power_value_fromprom(struct ieee80211_hw *hw, } } -static void _rtl88ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl88ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c index 2ad4523d1bef..79c6e0901e57 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/sw.c @@ -190,7 +190,7 @@ static bool rtl88e_get_btc_status(void) return false; } -static struct rtl_hal_ops rtl8188ee_hal_ops = { +static const struct rtl_hal_ops rtl8188ee_hal_ops = { .init_sw_vars = rtl88e_init_sw_vars, .deinit_sw_vars = rtl88e_deinit_sw_vars, .read_eeprom_info = rtl88ee_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c index 0bc915723b93..4354ae67a379 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/hw.c @@ -1412,9 +1412,9 @@ void rtl92ce_update_interrupt_mask(struct ieee80211_hw *hw, rtl92ce_enable_interrupt(hw); } -static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); @@ -1487,22 +1487,9 @@ static void _rtl92ce_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = rtlefuse-> eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; - - if ((rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path][index]) - > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path] - [index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path] - [index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c index ce7c28d9c874..f06b159f975d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/sw.c @@ -167,7 +167,7 @@ static void rtl92c_deinit_sw_vars(struct ieee80211_hw *hw) } } -static struct rtl_hal_ops rtl8192ce_hal_ops = { +static const struct rtl_hal_ops rtl8192ce_hal_ops = { .init_sw_vars = rtl92c_init_sw_vars, .deinit_sw_vars = rtl92c_deinit_sw_vars, .read_eeprom_info = rtl92ce_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c index 0195c9a3e9e8..989e7cff8e20 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/hw.c @@ -95,9 +95,9 @@ static void _rtl92cu_phy_param_tab_init(struct ieee80211_hw *hw) } } -static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); @@ -163,20 +163,9 @@ static void _rtl92cu_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->txpwrlevel_ht40_1s[rf_path][i] = rtlefuse-> eeprom_chnlarea_txpwr_ht40_1s[rf_path][index]; - if ((rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path][index]) - > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse-> - eeprom_chnlarea_txpwr_ht40_1s[rf_path] - [index] - rtlefuse-> - eprom_chnl_txpwr_ht40_2sdf[rf_path] - [index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { RTPRINT(rtlpriv, FINIT, INIT_TXPOWER, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c index c9b9e2bc90cc..00a6778df704 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/sw.c @@ -81,7 +81,7 @@ static bool rtl92cu_get_btc_status(void) return false; } -static struct rtl_hal_ops rtl8192cu_hal_ops = { +static const struct rtl_hal_ops rtl8192cu_hal_ops = { .init_sw_vars = rtl92cu_init_sw_vars, .deinit_sw_vars = rtl92cu_deinit_sw_vars, .read_chip_version = rtl92c_read_chip_version, @@ -156,7 +156,7 @@ static struct rtl_hal_usbint_cfg rtl92cu_interface_cfg = { .usb_mq_to_hwq = rtl8192cu_mq_to_hwq, }; -static struct rtl_hal_cfg rtl92cu_hal_cfg = { +static const struct rtl_hal_cfg rtl92cu_hal_cfg = { .name = "rtl92c_usb", .alt_fw_name = "rtlwifi/rtl8192cufw.bin", .ops = &rtl8192cu_hal_ops, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c index eb7d8b070cc7..494b2706abee 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/rf.c @@ -84,7 +84,7 @@ bool rtl92d_phy_rf6052_config(struct ieee80211_hw *hw) rtlphy->num_total_rfpath = 2; /* Single phy mode: use radio_a radio_b config path_A path_B */ - /* seperately by MAC0, and MAC1 needn't configure RF; */ + /* separately by MAC0, and MAC1 needn't configure RF; */ /* Dual PHY mode:MAC0 use radio_a config 1st phy path_A, */ /* MAC1 use radio_b config 2nd PHY path_A. */ /* DMDP,MAC0 on G band,MAC1 on A band. */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c index e36e4aeb9a95..7612c22a9842 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/sw.c @@ -184,7 +184,7 @@ static void rtl92d_deinit_sw_vars(struct ieee80211_hw *hw) skb_queue_purge(&rtlpriv->mac80211.skb_waitq[tid]); } -static struct rtl_hal_ops rtl8192de_hal_ops = { +static const struct rtl_hal_ops rtl8192de_hal_ops = { .init_sw_vars = rtl92d_init_sw_vars, .deinit_sw_vars = rtl92d_deinit_sw_vars, .read_eeprom_info = rtl92d_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c index 17486e3f322c..0108850bb9e5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/dm.c @@ -223,10 +223,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw) if (mac->link_state >= MAC80211_LINKED) { if (bfirstconnect) { - if (dm_dig->rssi_val_min <= dig_maxofmin) - current_igi = dm_dig->rssi_val_min; - else - current_igi = dig_maxofmin; + current_igi = min(dm_dig->rssi_val_min, dig_maxofmin); dm_dig->large_fa_hit = 0; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c index d4da5cdc8414..48a3c94606be 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/hw.c @@ -1731,7 +1731,7 @@ void rtl92ee_update_interrupt_mask(struct ieee80211_hw *hw, rtl92ee_enable_interrupt(hw); } -static u8 _rtl92ee_get_chnl_group(u8 chnl) +static __always_inline u8 _rtl92ee_get_chnl_group(u8 chnl) { u8 group = 0; @@ -2009,8 +2009,9 @@ static void _rtl8192ee_read_power_value_fromprom(struct ieee80211_hw *hw, } } -static void _rtl92ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, u8 *hwinfo) +static noinline_for_stack void +_rtl92ee_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *efu = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c index 162e734d5b08..181dd7823b26 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/sw.c @@ -176,7 +176,7 @@ static bool rtl92ee_get_btc_status(void) return true; } -static struct rtl_hal_ops rtl8192ee_hal_ops = { +static const struct rtl_hal_ops rtl8192ee_hal_ops = { .init_sw_vars = rtl92ee_init_sw_vars, .deinit_sw_vars = rtl92ee_deinit_sw_vars, .read_eeprom_info = rtl92ee_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c index 5a493602aaf2..17d29249a711 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/rf.c @@ -438,7 +438,7 @@ bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2, B3WIRE_DATALENGTH, 0x0); - /* Initialize RF fom connfiguration file */ + /* Initialize RF from configuration file */ switch (rfpath) { case RF90_PATH_A: rtstatus = rtl92s_phy_config_rf(hw, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c index e63c67b1861b..1cf801feb45e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/sw.c @@ -221,7 +221,7 @@ static bool rtl92se_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, return true; } -static struct rtl_hal_ops rtl8192se_hal_ops = { +static const struct rtl_hal_ops rtl8192se_hal_ops = { .init_sw_vars = rtl92s_init_sw_vars, .deinit_sw_vars = rtl92s_deinit_sw_vars, .read_eeprom_info = rtl92se_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c index 6991713a66d0..bd45d9bd40bb 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/hw.c @@ -1381,9 +1381,9 @@ static u8 _rtl8723e_get_chnl_group(u8 chnl) return group; } -static void _rtl8723e_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl8723e_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); @@ -1449,18 +1449,9 @@ static void _rtl8723e_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, rtlefuse->eeprom_chnlarea_txpwr_ht40_1s [rf_path][index]; - if ((rtlefuse->eeprom_chnlarea_txpwr_ht40_1s - [rf_path][index] - - rtlefuse->eprom_chnl_txpwr_ht40_2sdf - [rf_path][index]) > 0) { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = - rtlefuse->eeprom_chnlarea_txpwr_ht40_1s - [rf_path][index] - - rtlefuse->eprom_chnl_txpwr_ht40_2sdf - [rf_path][index]; - } else { - rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0; - } + rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = + max(rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][index] - + rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path][index], 0); } for (i = 0; i < 14; i++) { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c index 048744166a92..dcd7cdb96aa4 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/sw.c @@ -183,7 +183,7 @@ static bool is_fw_header(struct rtlwifi_firmware_header *hdr) return (le16_to_cpu(hdr->signature) & 0xfff0) == 0x2300; } -static struct rtl_hal_ops rtl8723e_hal_ops = { +static const struct rtl_hal_ops rtl8723e_hal_ops = { .init_sw_vars = rtl8723e_init_sw_vars, .deinit_sw_vars = rtl8723e_deinit_sw_vars, .read_eeprom_info = rtl8723e_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c index c53f95144812..c65d14fb914f 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/dm.c @@ -468,10 +468,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw) if (mac->link_state >= MAC80211_LINKED) { if (bfirstconnect) { - if (dm_digtable->rssi_val_min <= dig_maxofmin) - current_igi = dm_digtable->rssi_val_min; - else - current_igi = dig_maxofmin; + current_igi = min(dm_digtable->rssi_val_min, dig_maxofmin); dm_digtable->large_fa_hit = 0; } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c index bcfc53af4c1a..e1f811218894 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/hw.c @@ -1935,9 +1935,9 @@ static void _rtl8723be_read_power_value_fromprom(struct ieee80211_hw *hw, } } -static void _rtl8723be_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl8723be_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c index 0a92d0325098..5967df08e34e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/sw.c @@ -187,7 +187,7 @@ static bool is_fw_header(struct rtlwifi_firmware_header *hdr) return (le16_to_cpu(hdr->signature) & 0xfff0) == 0x5300; } -static struct rtl_hal_ops rtl8723be_hal_ops = { +static const struct rtl_hal_ops rtl8723be_hal_ops = { .init_sw_vars = rtl8723be_init_sw_vars, .deinit_sw_vars = rtl8723be_deinit_sw_vars, .read_eeprom_info = rtl8723be_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c index 76b5395539d0..f8b159c74658 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/dm.c @@ -756,10 +756,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) rtl_dbg(rtlpriv, COMP_DIG, DBG_LOUD, "DIG AfterLink\n"); if (first_connect) { - if (dm_digtable->rssi_val_min <= dig_max_of_min) - current_igi = dm_digtable->rssi_val_min; - else - current_igi = dig_max_of_min; + current_igi = min(dm_digtable->rssi_val_min, dig_max_of_min); rtl_dbg(rtlpriv, COMP_DIG, DBG_LOUD, "First Connect\n"); } else { diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c index f4b232f038a9..3a4a33476205 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c @@ -1026,7 +1026,7 @@ static void _rtl8821ae_hw_configure(struct ieee80211_hw *hw) /*Set retry limit*/ rtl_write_word(rtlpriv, REG_RL, 0x0707); - /* Set Data / Response auto rate fallack retry count*/ + /* Set Data / Response auto rate fallback retry count*/ rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000); rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504); rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000); @@ -1295,12 +1295,12 @@ static bool _rtl8821ae_reset_pcie_interface_dma(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, REG_CR, 0xFF); /* We should init LLT & RQPN and - * prepare Tx/Rx descrptor address later + * prepare Tx/Rx descriptor address later * because MAC function is reset.*/ } /* 7. Restore PCIe autoload down bit */ - /* 8812AE does not has the defination. */ + /* 8812AE does not have the definition. */ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8821AE) { /* write 0xF8 bit[17] = 1'b1 */ tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2); @@ -1308,7 +1308,7 @@ static bool _rtl8821ae_reset_pcie_interface_dma(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp); } - /* In MAC power on state, BB and RF maybe in ON state, + /* In MAC power on state, BB and RF may be in ON state, * if we release TRx DMA here. * it will cause packets to be started to Tx/Rx, * so we release Tx/Rx DMA later.*/ @@ -1713,7 +1713,7 @@ static bool _rtl8821ae_wowlan_initialize_adapter(struct ieee80211_hw *hw) _rtl8821ae_get_wakeup_reason(hw); /* Patch Pcie Rx DMA hang after S3/S4 several times. - * The root cause has not be found. */ + * The root cause has not been found. */ if (_rtl8821ae_check_pcie_dma_hang(hw)) _rtl8821ae_reset_pcie_interface_dma(hw, true, false); @@ -1926,7 +1926,7 @@ int rtl8821ae_hw_init(struct ieee80211_hw *hw) rtl8821ae_phy_mac_config(hw); /* because last function modify RCR, so we update * rcr var here, or TP will unstable for receive_config - * is wrong, RX RCR_ACRC32 will cause TP unstabel & Rx + * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252 rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR); rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV); @@ -2332,7 +2332,7 @@ void rtl8821ae_card_disable(struct ieee80211_hw *hw) if (_rtl8821ae_dynamic_rqpn(hw, 0xE0, 0x3, 0x80c20d0d)) rtlhal->re_init_llt_table = true; - /* 3 <2> Set Fw releted H2C cmd. */ + /* 3 <2> Set Fw related H2C cmd. */ /* Set WoWLAN related security information. */ rtl8821ae_set_fw_global_info_cmd(hw); @@ -2357,8 +2357,8 @@ void rtl8821ae_card_disable(struct ieee80211_hw *hw) /* 3 <3> Hw Configutations */ - /* Wait untill Rx DMA Finished before host sleep. - * FW Pause Rx DMA may happens when received packet doing dma. + /* Wait until Rx DMA Finished before host sleep. + * FW Pause Rx DMA may happen when received packet doing DMA. */ rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, BIT(2)); @@ -2782,9 +2782,9 @@ static void _rtl8812ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory); } #endif -static void _rtl8821ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, - bool autoload_fail, - u8 *hwinfo) +static noinline_for_stack void +_rtl8821ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw, + bool autoload_fail, u8 *hwinfo) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); @@ -3064,10 +3064,12 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_ struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); - int params[] = {RTL_EEPROM_ID, EEPROM_VID, EEPROM_DID, - EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, - EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, - COUNTRY_CODE_WORLD_WIDE_13}; + static const int params[] = { + RTL_EEPROM_ID, EEPROM_VID, EEPROM_DID, + EEPROM_SVID, EEPROM_SMID, EEPROM_MAC_ADDR, + EEPROM_CHANNELPLAN, EEPROM_VERSION, EEPROM_CUSTOMER_ID, + COUNTRY_CODE_WORLD_WIDE_13 + }; u8 *hwinfo; if (b_pseudo_test) { @@ -3925,7 +3927,7 @@ void rtl8821ae_resume(struct ieee80211_hw *hw) { } -/* Turn on AAP (RCR:bit 0) for promicuous mode. */ +/* Turn on AAP (RCR:bit 0) for promiscuous mode. */ void rtl8821ae_allow_all_destaddr(struct ieee80211_hw *hw, bool allow_all_da, bool write_into_reg) { @@ -3962,7 +3964,7 @@ void rtl8821ae_add_wowlan_pattern(struct ieee80211_hw *hw, /* RX page size = 128 byte */ offset = MAX_RX_DMA_BUFFER_SIZE_8812 / 128; - /* We should start from the boundry */ + /* We should start from the boundary */ cam_start = offset * 128; /* Enable Rx packet buffer access. */ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c index b5266e560416..1557d32efdd2 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/sw.c @@ -229,7 +229,7 @@ static bool rtl8821ae_get_btc_status(void) return true; } -static struct rtl_hal_ops rtl8821ae_hal_ops = { +static const struct rtl_hal_ops rtl8821ae_hal_ops = { .init_sw_vars = rtl8821ae_init_sw_vars, .deinit_sw_vars = rtl8821ae_deinit_sw_vars, .read_eeprom_info = rtl8821ae_read_eeprom_info, diff --git a/drivers/net/wireless/realtek/rtw88/coex.c b/drivers/net/wireless/realtek/rtw88/coex.c index 64904278ddad..b4dc6ff2c175 100644 --- a/drivers/net/wireless/realtek/rtw88/coex.c +++ b/drivers/net/wireless/realtek/rtw88/coex.c @@ -1501,28 +1501,28 @@ static u8 rtw_coex_algorithm(struct rtw_dev *rtwdev) algorithm = COEX_ALGO_HFP; break; case BPM_HID: - case BPM_HFP + BPM_HID: + case BPM_HFP | BPM_HID: algorithm = COEX_ALGO_HID; break; - case BPM_HFP + BPM_A2DP: - case BPM_HID + BPM_A2DP: - case BPM_HFP + BPM_HID + BPM_A2DP: + case BPM_HFP | BPM_A2DP: + case BPM_HID | BPM_A2DP: + case BPM_HFP | BPM_HID | BPM_A2DP: algorithm = COEX_ALGO_A2DP_HID; break; - case BPM_HFP + BPM_PAN: - case BPM_HID + BPM_PAN: - case BPM_HFP + BPM_HID + BPM_PAN: + case BPM_HFP | BPM_PAN: + case BPM_HID | BPM_PAN: + case BPM_HFP | BPM_HID | BPM_PAN: algorithm = COEX_ALGO_PAN_HID; break; - case BPM_HFP + BPM_A2DP + BPM_PAN: - case BPM_HID + BPM_A2DP + BPM_PAN: - case BPM_HFP + BPM_HID + BPM_A2DP + BPM_PAN: + case BPM_HFP | BPM_A2DP | BPM_PAN: + case BPM_HID | BPM_A2DP | BPM_PAN: + case BPM_HFP | BPM_HID | BPM_A2DP | BPM_PAN: algorithm = COEX_ALGO_A2DP_PAN_HID; break; case BPM_PAN: algorithm = COEX_ALGO_PAN; break; - case BPM_A2DP + BPM_PAN: + case BPM_A2DP | BPM_PAN: algorithm = COEX_ALGO_A2DP_PAN; break; case BPM_A2DP: diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 4fc78b882080..c68a9fff6808 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -521,7 +521,7 @@ rtw_fw_send_general_info(struct rtw_dev *rtwdev) u8 h2c_pkt[H2C_PKT_SIZE] = {0}; u16 total_size = H2C_PKT_HDR_SIZE + 4; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return; rtw_h2c_pkt_set_header(h2c_pkt, H2C_PKT_GENERAL_INFO); @@ -544,7 +544,7 @@ rtw_fw_send_phydm_info(struct rtw_dev *rtwdev) u16 total_size = H2C_PKT_HDR_SIZE + 8; u8 fw_rf_type = 0; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return; if (hal->rf_type == RF_1T1R) @@ -1480,7 +1480,7 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, bckp[2] = rtw_read8(rtwdev, REG_BCN_CTRL); - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { rtw_write32_set(rtwdev, REG_DWBCN0_CTRL, BIT_BCN_VALID); } else { pg_addr &= BIT_MASK_BCN_HEAD_1_V1; @@ -1509,7 +1509,7 @@ int rtw_fw_write_data_rsvd_page(struct rtw_dev *rtwdev, u16 pg_addr, goto restore; } - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { bcn_valid_addr = REG_DWBCN0_CTRL; bcn_valid_mask = BIT_BCN_VALID; } else { diff --git a/drivers/net/wireless/realtek/rtw88/mac.c b/drivers/net/wireless/realtek/rtw88/mac.c index f66d1b302dc5..eaa928bab240 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.c +++ b/drivers/net/wireless/realtek/rtw88/mac.c @@ -41,7 +41,7 @@ void rtw_set_channel_mac(struct rtw_dev *rtwdev, u8 channel, u8 bw, } rtw_write32(rtwdev, REG_WMAC_TRXPTCL_CTL, value32); - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return; value32 = rtw_read32(rtwdev, REG_AFE_CTRL1) & ~(BIT_MAC_CLK_SEL); @@ -67,7 +67,7 @@ static int rtw_mac_pre_system_cfg(struct rtw_dev *rtwdev) rtw_write8(rtwdev, REG_RSV_CTRL, 0); - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { if (rtw_read32(rtwdev, REG_SYS_CFG1) & BIT_LDO) rtw_write8(rtwdev, REG_LDO_SWR_CTRL, LDO_SEL); else @@ -278,7 +278,7 @@ static int rtw_mac_power_switch(struct rtw_dev *rtwdev, bool pwr_on) bool cur_pwr; int ret; - if (rtw_chip_wcpu_11ac(rtwdev)) { + if (rtw_chip_wcpu_3081(rtwdev)) { rpwm = rtw_read8(rtwdev, rtwdev->hci.rpwm_addr); /* Check FW still exist or not */ @@ -369,7 +369,7 @@ static int __rtw_mac_init_system_cfg_legacy(struct rtw_dev *rtwdev) static int rtw_mac_init_system_cfg(struct rtw_dev *rtwdev) { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return __rtw_mac_init_system_cfg_legacy(rtwdev); return __rtw_mac_init_system_cfg(rtwdev); @@ -981,7 +981,7 @@ out: static int _rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return __rtw_download_firmware_legacy(rtwdev, fw); return __rtw_download_firmware(rtwdev, fw); @@ -1122,7 +1122,7 @@ static int txdma_queue_mapping(struct rtw_dev *rtwdev) rtw_write8(rtwdev, REG_CR, 0); rtw_write8(rtwdev, REG_CR, MAC_TRX_ENABLE); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32(rtwdev, REG_H2CQ_CSR, BIT_H2CQ_FULL); if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_SDIO) { @@ -1145,7 +1145,7 @@ int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev) /* config rsvd page num */ fifo->rsvd_drv_pg_num = chip->rsvd_drv_pg_num; fifo->txff_pg_num = chip->txff_size / chip->page_size; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num; else fifo->rsvd_pg_num = fifo->rsvd_drv_pg_num + @@ -1163,7 +1163,7 @@ int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev) fifo->rsvd_boundary = fifo->txff_pg_num - fifo->rsvd_pg_num; cur_pg_addr = fifo->txff_pg_num; - if (rtw_chip_wcpu_11ac(rtwdev)) { + if (rtw_chip_wcpu_3081(rtwdev)) { cur_pg_addr -= csi_buf_pg_num; fifo->rsvd_csibuf_addr = cur_pg_addr; cur_pg_addr -= RSVD_PG_FW_TXBUF_NUM; @@ -1292,7 +1292,7 @@ static int priority_queue_cfg(struct rtw_dev *rtwdev) pubq_num = fifo->acq_pg_num - pg_tbl->hq_num - pg_tbl->lq_num - pg_tbl->nq_num - pg_tbl->exq_num - pg_tbl->gapq_num; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return __priority_queue_cfg_legacy(rtwdev, pg_tbl, pubq_num); else return __priority_queue_cfg(rtwdev, pg_tbl, pubq_num); @@ -1308,7 +1308,7 @@ static int init_h2c(struct rtw_dev *rtwdev) u32 h2cq_free; u32 wp, rp; - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) return 0; h2cq_addr = fifo->rsvd_h2cq_addr << TX_PAGE_SIZE_SHIFT; @@ -1375,7 +1375,7 @@ static int rtw_drv_info_cfg(struct rtw_dev *rtwdev) u8 value8; rtw_write8(rtwdev, REG_RX_DRVINFO_SZ, PHY_STATUS_SIZE); - if (rtw_chip_wcpu_11ac(rtwdev)) { + if (rtw_chip_wcpu_3081(rtwdev)) { value8 = rtw_read8(rtwdev, REG_TRXFF_BNDY + 1); value8 &= 0xF0; /* For rxdesc len = 0 issue */ @@ -1409,3 +1409,13 @@ int rtw_mac_init(struct rtw_dev *rtwdev) return 0; } + +int rtw_mac_postinit(struct rtw_dev *rtwdev) +{ + const struct rtw_chip_info *chip = rtwdev->chip; + + if (!chip->ops->mac_postinit) + return 0; + + return chip->ops->mac_postinit(rtwdev); +} diff --git a/drivers/net/wireless/realtek/rtw88/mac.h b/drivers/net/wireless/realtek/rtw88/mac.h index e92b1483728d..b73af90ee1d7 100644 --- a/drivers/net/wireless/realtek/rtw88/mac.h +++ b/drivers/net/wireless/realtek/rtw88/mac.h @@ -38,6 +38,7 @@ void rtw_write_firmware_page(struct rtw_dev *rtwdev, u32 page, const u8 *data, u32 size); int rtw_download_firmware(struct rtw_dev *rtwdev, struct rtw_fw_state *fw); int rtw_mac_init(struct rtw_dev *rtwdev); +int rtw_mac_postinit(struct rtw_dev *rtwdev); void rtw_mac_flush_queues(struct rtw_dev *rtwdev, u32 queues, bool drop); int rtw_set_trx_fifo_info(struct rtw_dev *rtwdev); int rtw_ddma_to_fw_fifo(struct rtw_dev *rtwdev, u32 ocp_src, u32 size); diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c index 77f9fbe1870c..766f22d31079 100644 --- a/drivers/net/wireless/realtek/rtw88/mac80211.c +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c @@ -71,7 +71,7 @@ static void rtw_ops_stop(struct ieee80211_hw *hw, bool suspend) mutex_unlock(&rtwdev->mutex); } -static int rtw_ops_config(struct ieee80211_hw *hw, u32 changed) +static int rtw_ops_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct rtw_dev *rtwdev = hw->priv; int ret = 0; @@ -708,7 +708,8 @@ static void rtw_ops_mgd_prepare_tx(struct ieee80211_hw *hw, mutex_unlock(&rtwdev->mutex); } -static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int rtw_ops_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct rtw_dev *rtwdev = hw->priv; @@ -797,6 +798,7 @@ static int rtw_ops_set_bitrate_mask(struct ieee80211_hw *hw, } static int rtw_ops_set_antenna(struct ieee80211_hw *hw, + int radio_idx, u32 tx_antenna, u32 rx_antenna) { @@ -808,13 +810,14 @@ static int rtw_ops_set_antenna(struct ieee80211_hw *hw, return -EOPNOTSUPP; mutex_lock(&rtwdev->mutex); - ret = chip->ops->set_antenna(rtwdev, tx_antenna, rx_antenna); + ret = chip->ops->set_antenna(rtwdev, -1, tx_antenna, rx_antenna); mutex_unlock(&rtwdev->mutex); return ret; } static int rtw_ops_get_antenna(struct ieee80211_hw *hw, + int radio_idx, u32 *tx_antenna, u32 *rx_antenna) { diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c index c4de5d114eda..fa0ed39cb199 100644 --- a/drivers/net/wireless/realtek/rtw88/main.c +++ b/drivers/net/wireless/realtek/rtw88/main.c @@ -349,7 +349,7 @@ int rtw_sta_add(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, struct rtw_vif *rtwvif = (struct rtw_vif *)vif->drv_priv; int i; - if (vif->type == NL80211_IFTYPE_STATION) { + if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls) { si->mac_id = rtwvif->mac_id; } else { si->mac_id = rtw_acquire_macid(rtwdev); @@ -386,7 +386,7 @@ void rtw_sta_remove(struct rtw_dev *rtwdev, struct ieee80211_sta *sta, cancel_work_sync(&si->rc_work); - if (vif->type != NL80211_IFTYPE_STATION) + if (vif->type != NL80211_IFTYPE_STATION || sta->tdls) rtw_release_macid(rtwdev, si->mac_id); if (fw_exist) rtw_fw_media_status_report(rtwdev, si->mac_id, false); @@ -636,6 +636,7 @@ void rtw_fw_recovery(struct rtw_dev *rtwdev) if (!test_bit(RTW_FLAG_RESTARTING, rtwdev->flags)) ieee80211_queue_work(rtwdev->hw, &rtwdev->fw_recovery_work); } +EXPORT_SYMBOL(rtw_fw_recovery); static void __fw_recovery_work(struct rtw_dev *rtwdev) { @@ -1411,6 +1412,12 @@ int rtw_power_on(struct rtw_dev *rtwdev) chip->ops->phy_set_param(rtwdev); + ret = rtw_mac_postinit(rtwdev); + if (ret) { + rtw_err(rtwdev, "failed to configure mac in postinit\n"); + goto err_off; + } + ret = rtw_hci_start(rtwdev); if (ret) { rtw_err(rtwdev, "failed to start hci\n"); @@ -1765,7 +1772,7 @@ static void __update_firmware_info_legacy(struct rtw_dev *rtwdev, static void update_firmware_info(struct rtw_dev *rtwdev, struct rtw_fw_state *fw) { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) __update_firmware_info_legacy(rtwdev, fw); else __update_firmware_info(rtwdev, fw); @@ -2218,7 +2225,6 @@ EXPORT_SYMBOL(rtw_core_deinit); int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) { - bool sta_mode_only = rtwdev->hci.type == RTW_HCI_TYPE_SDIO; struct rtw_hal *hal = &rtwdev->hal; int max_tx_headroom = 0; int ret; @@ -2248,12 +2254,9 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) ieee80211_hw_set(hw, TX_AMSDU); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); - if (sta_mode_only) - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); - else - hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_ADHOC); + hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_ADHOC); hw->wiphy->available_antennas_tx = hal->antenna_tx; hw->wiphy->available_antennas_rx = hal->antenna_rx; @@ -2264,7 +2267,7 @@ int rtw_register_hw(struct rtw_dev *rtwdev, struct ieee80211_hw *hw) hw->wiphy->max_scan_ssids = RTW_SCAN_MAX_SSIDS; hw->wiphy->max_scan_ie_len = rtw_get_max_scan_ie_len(rtwdev); - if (!sta_mode_only && rtwdev->chip->id == RTW_CHIP_TYPE_8822C) { + if (rtwdev->chip->id == RTW_CHIP_TYPE_8822C) { hw->wiphy->iface_combinations = rtw_iface_combs; hw->wiphy->n_iface_combinations = ARRAY_SIZE(rtw_iface_combs); } diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h index b0f1fabe9554..43ed6d6b4291 100644 --- a/drivers/net/wireless/realtek/rtw88/main.h +++ b/drivers/net/wireless/realtek/rtw88/main.h @@ -858,6 +858,7 @@ struct rtw_chip_ops { int (*power_on)(struct rtw_dev *rtwdev); void (*power_off)(struct rtw_dev *rtwdev); int (*mac_init)(struct rtw_dev *rtwdev); + int (*mac_postinit)(struct rtw_dev *rtwdev); int (*dump_fw_crash)(struct rtw_dev *rtwdev); void (*shutdown)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *map); @@ -873,7 +874,7 @@ struct rtw_chip_ops { void (*set_tx_power_index)(struct rtw_dev *rtwdev); int (*rsvd_page_dump)(struct rtw_dev *rtwdev, u8 *buf, u32 offset, u32 size); - int (*set_antenna)(struct rtw_dev *rtwdev, + int (*set_antenna)(struct rtw_dev *rtwdev, int radio_idx, u32 antenna_tx, u32 antenna_rx); void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable); @@ -1173,8 +1174,8 @@ struct rtw_pwr_track_tbl { }; enum rtw_wlan_cpu { - RTW_WCPU_11AC, - RTW_WCPU_11N, + RTW_WCPU_3081, + RTW_WCPU_8051, }; enum rtw_fw_fifo_sel { @@ -2166,14 +2167,14 @@ static inline void rtw_chip_efuse_grant_off(struct rtw_dev *rtwdev) rtwdev->chip->ops->efuse_grant(rtwdev, false); } -static inline bool rtw_chip_wcpu_11n(struct rtw_dev *rtwdev) +static inline bool rtw_chip_wcpu_8051(struct rtw_dev *rtwdev) { - return rtwdev->chip->wlan_cpu == RTW_WCPU_11N; + return rtwdev->chip->wlan_cpu == RTW_WCPU_8051; } -static inline bool rtw_chip_wcpu_11ac(struct rtw_dev *rtwdev) +static inline bool rtw_chip_wcpu_3081(struct rtw_dev *rtwdev) { - return rtwdev->chip->wlan_cpu == RTW_WCPU_11AC; + return rtwdev->chip->wlan_cpu == RTW_WCPU_3081; } static inline bool rtw_chip_has_rx_ldpc(struct rtw_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c index 7f2b6dc21f56..56b16186d3aa 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.c +++ b/drivers/net/wireless/realtek/rtw88/pci.c @@ -405,7 +405,7 @@ static void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev) dma = rtwpci->tx_rings[RTW_TX_QUEUE_BCN].r.dma; rtw_write32(rtwdev, RTK_PCI_TXBD_DESA_BCNQ, dma); - if (!rtw_chip_wcpu_11n(rtwdev)) { + if (!rtw_chip_wcpu_8051(rtwdev)) { len = rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.len; dma = rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.dma; rtwpci->tx_rings[RTW_TX_QUEUE_H2C].r.rp = 0; @@ -467,7 +467,7 @@ static void rtw_pci_reset_buf_desc(struct rtw_dev *rtwdev) rtw_write32(rtwdev, RTK_PCI_TXBD_RWPTR_CLR, 0xffffffff); /* reset H2C Queue index in a single write */ - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32_set(rtwdev, RTK_PCI_TXBD_H2CQ_CSR, BIT_CLR_H2CQ_HOST_IDX | BIT_CLR_H2CQ_HW_IDX); } @@ -487,7 +487,7 @@ static void rtw_pci_enable_interrupt(struct rtw_dev *rtwdev, rtw_write32(rtwdev, RTK_PCI_HIMR0, rtwpci->irq_mask[0] & ~imr0_unmask); rtw_write32(rtwdev, RTK_PCI_HIMR1, rtwpci->irq_mask[1]); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32(rtwdev, RTK_PCI_HIMR3, rtwpci->irq_mask[3]); rtwpci->irq_enabled = true; @@ -507,7 +507,7 @@ static void rtw_pci_disable_interrupt(struct rtw_dev *rtwdev, rtw_write32(rtwdev, RTK_PCI_HIMR0, 0); rtw_write32(rtwdev, RTK_PCI_HIMR1, 0); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32(rtwdev, RTK_PCI_HIMR3, 0); rtwpci->irq_enabled = false; @@ -1125,7 +1125,7 @@ static void rtw_pci_irq_recognized(struct rtw_dev *rtwdev, irq_status[0] = rtw_read32(rtwdev, RTK_PCI_HISR0); irq_status[1] = rtw_read32(rtwdev, RTK_PCI_HISR1); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) irq_status[3] = rtw_read32(rtwdev, RTK_PCI_HISR3); else irq_status[3] = 0; @@ -1134,7 +1134,7 @@ static void rtw_pci_irq_recognized(struct rtw_dev *rtwdev, irq_status[3] &= rtwpci->irq_mask[3]; rtw_write32(rtwdev, RTK_PCI_HISR0, irq_status[0]); rtw_write32(rtwdev, RTK_PCI_HISR1, irq_status[1]); - if (rtw_chip_wcpu_11ac(rtwdev)) + if (rtw_chip_wcpu_3081(rtwdev)) rtw_write32(rtwdev, RTK_PCI_HISR3, irq_status[3]); spin_unlock_irqrestore(&rtwpci->hwirq_lock, flags); @@ -1707,6 +1707,43 @@ static void rtw_pci_napi_deinit(struct rtw_dev *rtwdev) free_netdev(rtwpci->netdev); } +static pci_ers_result_t rtw_pci_io_err_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + netif_device_detach(netdev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t rtw_pci_io_slot_reset(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtw_dev *rtwdev = hw->priv; + + rtw_fw_recovery(rtwdev); + + return PCI_ERS_RESULT_RECOVERED; +} + +static void rtw_pci_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, PCI_D0, 0); + + netif_device_attach(netdev); +} + +const struct pci_error_handlers rtw_pci_err_handler = { + .error_detected = rtw_pci_io_err_detected, + .slot_reset = rtw_pci_io_slot_reset, + .resume = rtw_pci_io_resume, +}; +EXPORT_SYMBOL(rtw_pci_err_handler); + int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { diff --git a/drivers/net/wireless/realtek/rtw88/pci.h b/drivers/net/wireless/realtek/rtw88/pci.h index 13988db1cb4c..8ffdea11378f 100644 --- a/drivers/net/wireless/realtek/rtw88/pci.h +++ b/drivers/net/wireless/realtek/rtw88/pci.h @@ -231,6 +231,7 @@ struct rtw_pci { }; extern const struct dev_pm_ops rtw_pm_ops; +extern const struct pci_error_handlers rtw_pci_err_handler; int rtw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); void rtw_pci_remove(struct pci_dev *pdev); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8703b.c b/drivers/net/wireless/realtek/rtw88/rtw8703b.c index 9e6700c43a63..821c28d9cb5d 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8703b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8703b.c @@ -1832,6 +1832,7 @@ static const struct rtw_chip_ops rtw8703b_ops = { .power_on = rtw_power_on, .power_off = rtw_power_off, .mac_init = rtw8723x_mac_init, + .mac_postinit = rtw8723x_mac_postinit, .dump_fw_crash = NULL, .shutdown = NULL, .read_efuse = rtw8703b_read_efuse, @@ -1882,7 +1883,7 @@ const struct rtw_chip_info rtw8703b_hw_spec = { .id = RTW_CHIP_TYPE_8703B, .fw_name = "rtw88/rtw8703b_fw.bin", - .wlan_cpu = RTW_WCPU_11N, + .wlan_cpu = RTW_WCPU_8051, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723d.c b/drivers/net/wireless/realtek/rtw88/rtw8723d.c index 31876e708f9e..8715e0435f17 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723d.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723d.c @@ -1397,6 +1397,7 @@ static const struct rtw_chip_ops rtw8723d_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8723d_set_channel, .mac_init = rtw8723x_mac_init, + .mac_postinit = rtw8723x_mac_postinit, .shutdown = rtw8723d_shutdown, .read_rf = rtw_phy_read_rf_sipi, .write_rf = rtw_phy_write_rf_reg_sipi, @@ -2116,7 +2117,7 @@ const struct rtw_chip_info rtw8723d_hw_spec = { .ops = &rtw8723d_ops, .id = RTW_CHIP_TYPE_8723D, .fw_name = "rtw88/rtw8723d_fw.bin", - .wlan_cpu = RTW_WCPU_11N, + .wlan_cpu = RTW_WCPU_8051, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723de.c b/drivers/net/wireless/realtek/rtw88/rtw8723de.c index 87c8bc9d18a9..c6d0c88e5d81 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723de.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723de.c @@ -23,6 +23,7 @@ static struct pci_driver rtw_8723de_driver = { .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, .shutdown = rtw_pci_shutdown, + .err_handler = &rtw_pci_err_handler, }; module_pci_driver(rtw_8723de_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.c b/drivers/net/wireless/realtek/rtw88/rtw8723x.c index 4c77963fdd37..3f3e9b0c44e8 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723x.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.c @@ -353,7 +353,6 @@ static int __rtw8723x_read_efuse(struct rtw_dev *rtwdev, u8 *log_map) static int __rtw8723x_mac_init(struct rtw_dev *rtwdev) { - rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, WLAN_TXQ_RPT_EN); rtw_write32(rtwdev, REG_TCR, BIT_TCR_CFG); rtw_write16(rtwdev, REG_RXFLTMAP0, WLAN_RX_FILTER0); @@ -370,6 +369,13 @@ static int __rtw8723x_mac_init(struct rtw_dev *rtwdev) return 0; } +static int __rtw8723x_mac_postinit(struct rtw_dev *rtwdev) +{ + rtw_write8(rtwdev, REG_FWHW_TXQ_CTRL + 1, WLAN_TXQ_RPT_EN); + + return 0; +} + static void __rtw8723x_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { u8 ldo_pwr; @@ -760,6 +766,7 @@ const struct rtw8723x_common rtw8723x_common = { .lck = __rtw8723x_lck, .read_efuse = __rtw8723x_read_efuse, .mac_init = __rtw8723x_mac_init, + .mac_postinit = __rtw8723x_mac_postinit, .cfg_ldo25 = __rtw8723x_cfg_ldo25, .set_tx_power_index = __rtw8723x_set_tx_power_index, .efuse_grant = __rtw8723x_efuse_grant, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8723x.h b/drivers/net/wireless/realtek/rtw88/rtw8723x.h index a99af527c92c..0fc70dfdfc8b 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8723x.h +++ b/drivers/net/wireless/realtek/rtw88/rtw8723x.h @@ -137,6 +137,7 @@ struct rtw8723x_common { void (*lck)(struct rtw_dev *rtwdev); int (*read_efuse)(struct rtw_dev *rtwdev, u8 *log_map); int (*mac_init)(struct rtw_dev *rtwdev); + int (*mac_postinit)(struct rtw_dev *rtwdev); void (*cfg_ldo25)(struct rtw_dev *rtwdev, bool enable); void (*set_tx_power_index)(struct rtw_dev *rtwdev); void (*efuse_grant)(struct rtw_dev *rtwdev, bool on); @@ -383,6 +384,11 @@ static inline int rtw8723x_mac_init(struct rtw_dev *rtwdev) return rtw8723x_common.mac_init(rtwdev); } +static inline int rtw8723x_mac_postinit(struct rtw_dev *rtwdev) +{ + return rtw8723x_common.mac_postinit(rtwdev); +} + static inline void rtw8723x_cfg_ldo25(struct rtw_dev *rtwdev, bool enable) { rtw8723x_common.cfg_ldo25(rtwdev, enable); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8812a.c b/drivers/net/wireless/realtek/rtw88/rtw8812a.c index c2ef41767ff9..2078eb6e3628 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8812a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8812a.c @@ -919,6 +919,7 @@ static const struct rtw_chip_ops rtw8812a_ops = { .query_phy_status = rtw8812a_query_phy_status, .set_channel = rtw88xxa_set_channel, .mac_init = NULL, + .mac_postinit = NULL, .read_rf = rtw88xxa_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, @@ -1038,7 +1039,7 @@ const struct rtw_chip_info rtw8812a_hw_spec = { .ops = &rtw8812a_ops, .id = RTW_CHIP_TYPE_8812A, .fw_name = "rtw88/rtw8812a_fw.bin", - .wlan_cpu = RTW_WCPU_11N, + .wlan_cpu = RTW_WCPU_8051, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8814a.c b/drivers/net/wireless/realtek/rtw88/rtw8814a.c index 44dd3090484b..ca1079e12023 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8814a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8814a.c @@ -2055,6 +2055,7 @@ static const struct rtw_chip_ops rtw8814a_ops = { .query_phy_status = rtw8814a_query_phy_status, .set_channel = rtw8814a_set_channel, .mac_init = rtw8814a_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8814a_set_tx_power_index, @@ -2180,7 +2181,7 @@ const struct rtw_chip_info rtw8814a_hw_spec = { .ops = &rtw8814a_ops, .id = RTW_CHIP_TYPE_8814A, .fw_name = "rtw88/rtw8814a_fw.bin", - .wlan_cpu = RTW_WCPU_11AC, + .wlan_cpu = RTW_WCPU_3081, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821a.c b/drivers/net/wireless/realtek/rtw88/rtw8821a.c index 413aec694c33..414b77eef07c 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821a.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821a.c @@ -865,6 +865,7 @@ static const struct rtw_chip_ops rtw8821a_ops = { .query_phy_status = rtw8821a_query_phy_status, .set_channel = rtw88xxa_set_channel, .mac_init = NULL, + .mac_postinit = NULL, .read_rf = rtw88xxa_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, @@ -1138,7 +1139,7 @@ const struct rtw_chip_info rtw8821a_hw_spec = { .ops = &rtw8821a_ops, .id = RTW_CHIP_TYPE_8821A, .fw_name = "rtw88/rtw8821a_fw.bin", - .wlan_cpu = RTW_WCPU_11N, + .wlan_cpu = RTW_WCPU_8051, .tx_pkt_desc_sz = 40, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821c.c b/drivers/net/wireless/realtek/rtw88/rtw8821c.c index 413130a30ca9..2078b067562e 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821c.c @@ -1663,6 +1663,7 @@ static const struct rtw_chip_ops rtw8821c_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8821c_set_channel, .mac_init = rtw8821c_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_antenna = NULL, @@ -1973,7 +1974,7 @@ const struct rtw_chip_info rtw8821c_hw_spec = { .ops = &rtw8821c_ops, .id = RTW_CHIP_TYPE_8821C, .fw_name = "rtw88/rtw8821c_fw.bin", - .wlan_cpu = RTW_WCPU_11AC, + .wlan_cpu = RTW_WCPU_3081, .tx_pkt_desc_sz = 48, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8821ce.c b/drivers/net/wireless/realtek/rtw88/rtw8821ce.c index 40637c079d99..52a19cb17daa 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8821ce.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8821ce.c @@ -27,6 +27,7 @@ static struct pci_driver rtw_8821ce_driver = { .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, .shutdown = rtw_pci_shutdown, + .err_handler = &rtw_pci_err_handler, }; module_pci_driver(rtw_8821ce_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822b.c b/drivers/net/wireless/realtek/rtw88/rtw8822b.c index ab199eaea3c7..89b6485b229a 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822b.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822b.c @@ -983,6 +983,7 @@ static bool rtw8822b_check_rf_path(u8 antenna) } static int rtw8822b_set_antenna(struct rtw_dev *rtwdev, + int radio_idx, u32 antenna_tx, u32 antenna_rx) { @@ -2153,6 +2154,7 @@ static const struct rtw_chip_ops rtw8822b_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8822b_set_channel, .mac_init = rtw8822b_mac_init, + .mac_postinit = NULL, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_sipi, .set_tx_power_index = rtw8822b_set_tx_power_index, @@ -2513,7 +2515,7 @@ const struct rtw_chip_info rtw8822b_hw_spec = { .ops = &rtw8822b_ops, .id = RTW_CHIP_TYPE_8822B, .fw_name = "rtw88/rtw8822b_fw.bin", - .wlan_cpu = RTW_WCPU_11AC, + .wlan_cpu = RTW_WCPU_3081, .tx_pkt_desc_sz = 48, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822be.c b/drivers/net/wireless/realtek/rtw88/rtw8822be.c index 0bb9f70e7920..dda597d73219 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822be.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822be.c @@ -23,6 +23,7 @@ static struct pci_driver rtw_8822be_driver = { .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, .shutdown = rtw_pci_shutdown, + .err_handler = &rtw_pci_err_handler, }; module_pci_driver(rtw_8822be_driver); diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822c.c b/drivers/net/wireless/realtek/rtw88/rtw8822c.c index 017d959de3ce..28c121cf1e68 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822c.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822c.c @@ -2767,6 +2767,7 @@ static void rtw8822c_set_tx_power_index(struct rtw_dev *rtwdev) } static int rtw8822c_set_antenna(struct rtw_dev *rtwdev, + int radio_idx, u32 antenna_tx, u32 antenna_rx) { @@ -4963,6 +4964,7 @@ static const struct rtw_chip_ops rtw8822c_ops = { .query_phy_status = query_phy_status, .set_channel = rtw8822c_set_channel, .mac_init = rtw8822c_mac_init, + .mac_postinit = NULL, .dump_fw_crash = rtw8822c_dump_fw_crash, .read_rf = rtw_phy_read_rf, .write_rf = rtw_phy_write_rf_reg_mix, @@ -5332,7 +5334,7 @@ const struct rtw_chip_info rtw8822c_hw_spec = { .ops = &rtw8822c_ops, .id = RTW_CHIP_TYPE_8822C, .fw_name = "rtw88/rtw8822c_fw.bin", - .wlan_cpu = RTW_WCPU_11AC, + .wlan_cpu = RTW_WCPU_3081, .tx_pkt_desc_sz = 48, .tx_buf_desc_sz = 16, .rx_pkt_desc_sz = 24, diff --git a/drivers/net/wireless/realtek/rtw88/rtw8822ce.c b/drivers/net/wireless/realtek/rtw88/rtw8822ce.c index 9def732480af..7ae95415c224 100644 --- a/drivers/net/wireless/realtek/rtw88/rtw8822ce.c +++ b/drivers/net/wireless/realtek/rtw88/rtw8822ce.c @@ -27,6 +27,7 @@ static struct pci_driver rtw_8822ce_driver = { .remove = rtw_pci_remove, .driver.pm = &rtw_pm_ops, .shutdown = rtw_pci_shutdown, + .err_handler = &rtw_pci_err_handler, }; module_pci_driver(rtw_8822ce_driver); diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index e733ed846123..cc2d4fef3587 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -547,7 +547,7 @@ static int rtw_sdio_check_free_txpg(struct rtw_dev *rtwdev, u8 queue, { unsigned int pages_free, pages_needed; - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { u32 free_txpg; free_txpg = rtw_sdio_read32(rtwdev, REG_SDIO_FREE_TXPG); @@ -1030,7 +1030,7 @@ static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) u32 rx_len, hisr, total_rx_bytes = 0; do { - if (rtw_chip_wcpu_11n(rtwdev)) + if (rtw_chip_wcpu_8051(rtwdev)) rx_len = rtw_read16(rtwdev, REG_SDIO_RX0_REQ_LEN); else rx_len = rtw_read32(rtwdev, REG_SDIO_RX0_REQ_LEN); @@ -1042,7 +1042,7 @@ static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) total_rx_bytes += rx_len; - if (rtw_chip_wcpu_11n(rtwdev)) { + if (rtw_chip_wcpu_8051(rtwdev)) { /* Stop if no more RX requests are pending, even if * rx_len could be greater than zero in the next * iteration. This is needed because the RX buffer may @@ -1054,7 +1054,7 @@ static void rtw_sdio_rx_isr(struct rtw_dev *rtwdev) */ hisr = rtw_read32(rtwdev, REG_SDIO_HISR); } else { - /* RTW_WCPU_11AC chips have improved hardware or + /* RTW_WCPU_3081 chips have improved hardware or * firmware and can use rx_len unconditionally. */ hisr = REG_SDIO_HISR_RX_REQUEST; diff --git a/drivers/net/wireless/realtek/rtw89/Kconfig b/drivers/net/wireless/realtek/rtw89/Kconfig index 205d7ecca7d7..4288c30b400a 100644 --- a/drivers/net/wireless/realtek/rtw89/Kconfig +++ b/drivers/net/wireless/realtek/rtw89/Kconfig @@ -17,6 +17,9 @@ config RTW89_CORE config RTW89_PCI tristate +config RTW89_USB + tristate + config RTW89_8851B tristate @@ -49,6 +52,17 @@ config RTW89_8851BE 802.11ax PCIe wireless network (Wi-Fi 6) adapter +config RTW89_8851BU + tristate "Realtek 8851BU USB wireless network (Wi-Fi 6) adapter" + depends on USB + select RTW89_CORE + select RTW89_USB + select RTW89_8851B + help + Select this option will enable support for 8851BU chipset + + 802.11ax USB wireless network (Wi-Fi 6) adapter + config RTW89_8852AE tristate "Realtek 8852AE PCI wireless network (Wi-Fi 6) adapter" depends on PCI @@ -72,6 +86,18 @@ config RTW89_8852BE 802.11ax PCIe wireless network (Wi-Fi 6) adapter +config RTW89_8852BU + tristate "Realtek 8852BU USB wireless network (Wi-Fi 6) adapter" + depends on USB + select RTW89_CORE + select RTW89_USB + select RTW89_8852B + select RTW89_8852B_COMMON + help + Select this option will enable support for 8852BU chipset + + 802.11ax USB wireless network (Wi-Fi 6) adapter + config RTW89_8852BTE tristate "Realtek 8852BE-VT PCI wireless network (Wi-Fi 6) adapter" depends on PCI diff --git a/drivers/net/wireless/realtek/rtw89/Makefile b/drivers/net/wireless/realtek/rtw89/Makefile index c751013e811e..23e43c444f69 100644 --- a/drivers/net/wireless/realtek/rtw89/Makefile +++ b/drivers/net/wireless/realtek/rtw89/Makefile @@ -31,6 +31,9 @@ rtw89_8851b-objs := rtw8851b.o \ obj-$(CONFIG_RTW89_8851BE) += rtw89_8851be.o rtw89_8851be-objs := rtw8851be.o +obj-$(CONFIG_RTW89_8851BU) += rtw89_8851bu.o +rtw89_8851bu-objs := rtw8851bu.o + obj-$(CONFIG_RTW89_8852A) += rtw89_8852a.o rtw89_8852a-objs := rtw8852a.o \ rtw8852a_table.o \ @@ -52,6 +55,9 @@ rtw89_8852b-objs := rtw8852b.o \ obj-$(CONFIG_RTW89_8852BE) += rtw89_8852be.o rtw89_8852be-objs := rtw8852be.o +obj-$(CONFIG_RTW89_8852BU) += rtw89_8852bu.o +rtw89_8852bu-objs := rtw8852bu.o + obj-$(CONFIG_RTW89_8852BT) += rtw89_8852bt.o rtw89_8852bt-objs := rtw8852bt.o \ rtw8852bt_rfk.o \ @@ -81,3 +87,6 @@ rtw89_core-$(CONFIG_RTW89_DEBUG) += debug.o obj-$(CONFIG_RTW89_PCI) += rtw89_pci.o rtw89_pci-y := pci.o pci_be.o +obj-$(CONFIG_RTW89_USB) += rtw89_usb.o +rtw89_usb-y := usb.o + diff --git a/drivers/net/wireless/realtek/rtw89/acpi.c b/drivers/net/wireless/realtek/rtw89/acpi.c index 581d6d4154d3..f1e758a5f32b 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.c +++ b/drivers/net/wireless/realtek/rtw89/acpi.c @@ -236,6 +236,50 @@ int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev, return 0; } +static bool chk_acpi_policy_6ghz_vlp_sig(const struct rtw89_acpi_policy_6ghz_vlp *p) +{ + return p->signature[0] == 0x52 && + p->signature[1] == 0x54 && + p->signature[2] == 0x4B && + p->signature[3] == 0x0B; +} + +static +int rtw89_acpi_dsm_get_policy_6ghz_vlp(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_6ghz_vlp **policy) +{ + const struct rtw89_acpi_policy_6ghz_vlp *ptr; + u32 buf_len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + buf_len = obj->buffer.length; + if (buf_len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, buf_len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_6ghz_vlp_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL); + if (!*policy) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_vlp: ", *policy, + sizeof(*ptr)); + return 0; +} + static bool chk_acpi_policy_tas_sig(const struct rtw89_acpi_policy_tas *p) { return p->signature[0] == 0x52 && @@ -279,6 +323,51 @@ static int rtw89_acpi_dsm_get_policy_tas(struct rtw89_dev *rtwdev, return 0; } +static +bool chk_acpi_policy_reg_rules_sig(const struct rtw89_acpi_policy_reg_rules *p) +{ + return p->signature[0] == 0x52 && + p->signature[1] == 0x54 && + p->signature[2] == 0x4B && + p->signature[3] == 0x0A; +} + +static +int rtw89_acpi_dsm_get_policy_reg_rules(struct rtw89_dev *rtwdev, + union acpi_object *obj, + struct rtw89_acpi_policy_reg_rules **policy) +{ + const struct rtw89_acpi_policy_reg_rules *ptr; + u32 buf_len; + + if (obj->type != ACPI_TYPE_BUFFER) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, + "acpi: expect buffer but type: %d\n", obj->type); + return -EINVAL; + } + + buf_len = obj->buffer.length; + if (buf_len < sizeof(*ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n", + __func__, buf_len); + return -EINVAL; + } + + ptr = (typeof(ptr))obj->buffer.pointer; + if (!chk_acpi_policy_reg_rules_sig(ptr)) { + rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__); + return -EINVAL; + } + + *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL); + if (!*policy) + return -ENOMEM; + + rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_reg_rules: ", *policy, + sizeof(*ptr)); + return 0; +} + int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, enum rtw89_acpi_dsm_func func, struct rtw89_acpi_dsm_result *res) @@ -300,8 +389,14 @@ int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev, else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP) ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj, &res->u.policy_6ghz_sp); + else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP) + ret = rtw89_acpi_dsm_get_policy_6ghz_vlp(rtwdev, obj, + &res->u.policy_6ghz_vlp); else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN) ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas); + else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN) + ret = rtw89_acpi_dsm_get_policy_reg_rules(rtwdev, obj, + &res->u.policy_reg_rules); else ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value); diff --git a/drivers/net/wireless/realtek/rtw89/acpi.h b/drivers/net/wireless/realtek/rtw89/acpi.h index 8c918ee02d2e..48a46f2005b1 100644 --- a/drivers/net/wireless/realtek/rtw89/acpi.h +++ b/drivers/net/wireless/realtek/rtw89/acpi.h @@ -19,11 +19,13 @@ enum rtw89_acpi_dsm_func { RTW89_ACPI_DSM_FUNC_TAS_EN = 5, RTW89_ACPI_DSM_FUNC_UNII4_SUP = 6, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP = 7, + RTW89_ACPI_DSM_FUNC_REG_RULES_EN = 10, + RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP = 11, }; enum rtw89_acpi_conf_unii4 { - RTW89_ACPI_CONF_UNII4_FCC = BIT(0), - RTW89_ACPI_CONF_UNII4_IC = BIT(1), + RTW89_ACPI_CONF_UNII4_US = BIT(0), + RTW89_ACPI_CONF_UNII4_CA = BIT(1), }; enum rtw89_acpi_policy_mode { @@ -56,6 +58,7 @@ struct rtw89_acpi_policy_6ghz { enum rtw89_acpi_conf_6ghz_sp { RTW89_ACPI_CONF_6GHZ_SP_US = BIT(0), + RTW89_ACPI_CONF_6GHZ_SP_CA = BIT(1), }; struct rtw89_acpi_policy_6ghz_sp { @@ -66,6 +69,19 @@ struct rtw89_acpi_policy_6ghz_sp { u8 rsvd; } __packed; +enum rtw89_acpi_conf_6ghz_vlp { + RTW89_ACPI_CONF_6GHZ_VLP_US = BIT(0), + RTW89_ACPI_CONF_6GHZ_VLP_CA = BIT(1), +}; + +struct rtw89_acpi_policy_6ghz_vlp { + u8 signature[4]; + u8 revision; + u8 override; + u8 conf; + u8 rsvd; +} __packed; + struct rtw89_acpi_policy_tas { u8 signature[4]; u8 revision; @@ -74,13 +90,26 @@ struct rtw89_acpi_policy_tas { u8 rsvd[3]; } __packed; +enum rtw89_acpi_conf_reg_rules { + RTW89_ACPI_CONF_REG_RULE_REGD_UK = BIT(0), +}; + +struct rtw89_acpi_policy_reg_rules { + u8 signature[4]; + u8 revision; + u8 conf; + u8 rsvd[3]; +} __packed; + struct rtw89_acpi_dsm_result { union { u8 value; /* caller needs to free it after using */ struct rtw89_acpi_policy_6ghz *policy_6ghz; struct rtw89_acpi_policy_6ghz_sp *policy_6ghz_sp; + struct rtw89_acpi_policy_6ghz_vlp *policy_6ghz_vlp; struct rtw89_acpi_policy_tas *policy_tas; + struct rtw89_acpi_policy_reg_rules *policy_reg_rules; } u; }; diff --git a/drivers/net/wireless/realtek/rtw89/chan.c b/drivers/net/wireless/realtek/rtw89/chan.c index 806f42429a29..f7d1c5d3b92e 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.c +++ b/drivers/net/wireless/realtek/rtw89/chan.c @@ -7,6 +7,7 @@ #include "debug.h" #include "fw.h" #include "mac.h" +#include "phy.h" #include "ps.h" #include "sar.h" #include "util.h" @@ -128,6 +129,48 @@ void rtw89_chan_create(struct rtw89_chan *chan, u8 center_chan, u8 primary_chan, bandwidth); } +static void _rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + const struct cfg80211_chan_def *chandef) +{ + struct ieee80211_bss_conf *bss_conf; + + if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION && + rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT) + return; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->eht_support) { + rcu_read_unlock(); + return; + } + + rcu_read_unlock(); + + rtw89_chip_h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, chandef->punctured); +} + +static void rtw89_chan_update_punctured(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx idx, + const struct cfg80211_chan_def *chandef) +{ + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + if (!rtwvif_link->chanctx_assigned || + rtwvif_link->chanctx_idx != idx) + continue; + + _rtw89_chan_update_punctured(rtwdev, rtwvif_link, chandef); + } + } +} + bool rtw89_assign_entity_chan(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, const struct rtw89_chan *new) @@ -170,22 +213,26 @@ int rtw89_iterate_entity_chan(struct rtw89_dev *rtwdev, static void __rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, - const struct cfg80211_chan_def *chandef, - bool from_stack) + const struct cfg80211_chan_def *chandef) { struct rtw89_hal *hal = &rtwdev->hal; hal->chanctx[idx].chandef = *chandef; - - if (from_stack) - set_bit(idx, hal->entity_map); } void rtw89_config_entity_chandef(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx idx, const struct cfg80211_chan_def *chandef) { - __rtw89_config_entity_chandef(rtwdev, idx, chandef, true); + struct rtw89_hal *hal = &rtwdev->hal; + + if (!chandef) { + clear_bit(idx, hal->entity_map); + return; + } + + __rtw89_config_entity_chandef(rtwdev, idx, chandef); + set_bit(idx, hal->entity_map); } void rtw89_config_roc_chandef(struct rtw89_dev *rtwdev, @@ -227,7 +274,7 @@ static void rtw89_config_default_chandef(struct rtw89_dev *rtwdev) struct cfg80211_chan_def chandef = {0}; rtw89_get_default_chandef(&chandef); - __rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef, false); + __rtw89_config_entity_chandef(rtwdev, RTW89_CHANCTX_0, &chandef); } void rtw89_entity_init(struct rtw89_dev *rtwdev) @@ -265,6 +312,8 @@ static void rtw89_entity_calculate_weight(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif; int idx; + w->registered_chanctxs = bitmap_weight(hal->entity_map, NUM_OF_RTW89_CHANCTX); + for_each_set_bit(idx, hal->entity_map, NUM_OF_RTW89_CHANCTX) { cfg = hal->chanctx[idx].cfg; if (!cfg) { @@ -473,7 +522,8 @@ enum rtw89_entity_mode rtw89_entity_recalc(struct rtw89_dev *rtwdev) bitmap_zero(recalc_map, NUM_OF_RTW89_CHANCTX); fallthrough; case 0: - rtw89_config_default_chandef(rtwdev); + if (!w.registered_chanctxs) + rtw89_config_default_chandef(rtwdev); set_bit(RTW89_CHANCTX_0, recalc_map); fallthrough; case 1: @@ -953,6 +1003,7 @@ static int rtw89_mcc_fill_all_roles(struct rtw89_dev *rtwdev) } sel.bind_vif[i] = rtwvif_link; + rtw89_p2p_disable_all_noa(rtwdev, rtwvif_link, NULL); } ret = rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_fill_role_iterator, &sel); @@ -991,6 +1042,11 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, *pattern = *new; memset(&pattern->courtesy, 0, sizeof(pattern->courtesy)); + if (RTW89_MCC_REQ_COURTESY(pattern, aux) && aux->is_gc) + aux->ignore_bcn = true; + else + aux->ignore_bcn = false; + if (RTW89_MCC_REQ_COURTESY(pattern, aux) && rtw89_mcc_can_courtesy(ref, aux)) { crtz = &pattern->courtesy.ref; ref->crtz = crtz; @@ -1005,6 +1061,11 @@ static void rtw89_mcc_assign_pattern(struct rtw89_dev *rtwdev, ref->crtz = NULL; } + if (RTW89_MCC_REQ_COURTESY(pattern, ref) && ref->is_gc) + ref->ignore_bcn = true; + else + ref->ignore_bcn = false; + if (RTW89_MCC_REQ_COURTESY(pattern, ref) && rtw89_mcc_can_courtesy(aux, ref)) { crtz = &pattern->courtesy.aux; aux->crtz = crtz; @@ -1107,7 +1168,7 @@ static int __rtw89_mcc_calc_pattern_strict(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *ref = &mcc->role_ref; struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_config *config = &mcc->config; - u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME; + u16 min_tob = RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME; u16 min_toa = RTW89_MCC_MIN_RX_BCN_TIME; u16 bcn_ofst = config->beacon_offset; s16 upper_toa_ref, lower_toa_ref; @@ -1263,9 +1324,11 @@ static int __rtw89_mcc_calc_pattern_anchor(struct rtw89_dev *rtwdev, u16 bcn_ofst = config->beacon_offset; bool small_bcn_ofst; - if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME) + if (bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) + small_bcn_ofst = true; + else if (bcn_ofst < aux->duration - aux->limit.max_toa) small_bcn_ofst = true; - else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_TIME) + else if (mcc_intvl - bcn_ofst < RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME) small_bcn_ofst = false; else return -EPERM; @@ -1595,6 +1658,35 @@ static bool rtw89_mcc_duration_decision_on_bt(struct rtw89_dev *rtwdev) return false; } +void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + mcc_prepare_done_work.work); + + lockdep_assert_wiphy(wiphy); + + ieee80211_wake_queues(rtwdev->hw); +} + +static void rtw89_mcc_prepare(struct rtw89_dev *rtwdev, bool start) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_config *config = &mcc->config; + + if (start) { + ieee80211_stop_queues(rtwdev->hw); + + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work, + usecs_to_jiffies(config->prepare_delay)); + } else { + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work, 0); + wiphy_delayed_work_flush(rtwdev->hw->wiphy, + &rtwdev->mcc_prepare_done_work); + } +} + static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -1630,6 +1722,8 @@ static int rtw89_mcc_fill_start_tsf(struct rtw89_dev *rtwdev) config->start_tsf = start_tsf; config->start_tsf_in_aux_domain = tsf_aux + start_tsf - tsf; + config->prepare_delay = start_tsf - tsf; + return 0; } @@ -2129,6 +2223,7 @@ static void rtw89_mcc_handle_beacon_noa(struct rtw89_dev *rtwdev, bool enable) rtw89_p2p_noa_renew(rtwvif_go); if (enable) { + duration += RTW89_MCC_SWITCH_CH_TIME; noa_desc.start_time = cpu_to_le32(start_time); noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(interval)); noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(duration)); @@ -2177,6 +2272,18 @@ static void rtw89_mcc_stop_beacon_noa(struct rtw89_dev *rtwdev) rtw89_mcc_handle_beacon_noa(rtwdev, false); } +static bool rtw89_mcc_ignore_bcn(struct rtw89_dev *rtwdev, struct rtw89_mcc_role *role) +{ + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + + if (role->is_go) + return true; + else if (chip_gen == RTW89_CHIP_BE && role->is_gc) + return true; + else + return false; +} + static int rtw89_mcc_start(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; @@ -2208,6 +2315,15 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) if (ret) return ret; + if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, false); + } else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, false); + } else { + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, true); + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, true); + } + if (rtw89_concurrent_via_mrc(rtwdev)) ret = __mrc_fw_start(rtwdev, false); else @@ -2219,6 +2335,9 @@ static int rtw89_mcc_start(struct rtw89_dev *rtwdev) rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_START); rtw89_mcc_start_beacon_noa(rtwdev); + rtw89_phy_dig_suspend(rtwdev); + + rtw89_mcc_prepare(rtwdev, true); return 0; } @@ -2269,9 +2388,11 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_mcc_info *mcc = &rtwdev->mcc; struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_stop_sel sel = { .hint.target = pause ? pause->trigger : NULL, }; + bool rsn_scan; int ret; if (!pause) { @@ -2279,6 +2400,12 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, bitmap_zero(hal->changes, NUM_OF_RTW89_CHANCTX_CHANGES); } + rsn_scan = pause && pause->rsn == RTW89_CHANCTX_PAUSE_REASON_HW_SCAN; + if (rsn_scan && ref->is_go) + sel.hint.target = ref->rtwvif_link; + else if (rsn_scan && aux->is_go) + sel.hint.target = aux->rtwvif_link; + /* by default, stop at ref */ rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_stop_sel_iterator, &sel); if (!sel.filled) @@ -2307,12 +2434,20 @@ static void rtw89_mcc_stop(struct rtw89_dev *rtwdev, rtw89_chanctx_notify(rtwdev, RTW89_CHANCTX_STATE_MCC_STOP); rtw89_mcc_stop_beacon_noa(rtwdev); + rtw89_fw_h2c_mcc_dig(rtwdev, RTW89_CHANCTX_0, 0, 0, false); + rtw89_phy_dig_resume(rtwdev, true); + + rtw89_mcc_prepare(rtwdev, false); } static int rtw89_mcc_update(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; + bool old_ref_ignore_bcn = mcc->role_ref.ignore_bcn; + bool old_aux_ignore_bcn = mcc->role_aux.ignore_bcn; struct rtw89_mcc_config *config = &mcc->config; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; struct rtw89_mcc_config old_cfg = *config; bool courtesy_changed; bool sync_changed; @@ -2327,6 +2462,11 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) if (ret) return ret; + if (old_ref_ignore_bcn != ref->ignore_bcn) + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, ref->rtwvif_link, !ref->ignore_bcn); + else if (old_aux_ignore_bcn != aux->ignore_bcn) + rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, aux->rtwvif_link, !aux->ignore_bcn); + if (memcmp(&old_cfg.pattern.courtesy, &config->pattern.courtesy, sizeof(old_cfg.pattern.courtesy)) == 0) courtesy_changed = false; @@ -2362,15 +2502,144 @@ static int rtw89_mcc_update(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_mcc_search_gc_iterator(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *mcc_role, + unsigned int ordered_idx, + void *data) +{ + struct rtw89_mcc_role **role = data; + + if (mcc_role->is_gc) + *role = mcc_role; + + return 0; +} + +static struct rtw89_mcc_role *rtw89_mcc_get_gc_role(struct rtw89_dev *rtwdev) +{ + struct rtw89_mcc_info *mcc = &rtwdev->mcc; + struct rtw89_mcc_role *role = NULL; + + if (mcc->mode != RTW89_MCC_MODE_GC_STA) + return NULL; + + rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_search_gc_iterator, &role); + + return role; +} + +void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_vif_link *rtwvif_link = container_of(work, struct rtw89_vif_link, + mcc_gc_detect_beacon_work.work); + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + enum rtw89_entity_mode mode; + struct rtw89_dev *rtwdev; + + lockdep_assert_wiphy(wiphy); + + rtwdev = rtwvif_link->rtwvif->rtwdev; + + mode = rtw89_get_entity_mode(rtwdev); + if (mode != RTW89_ENTITY_MODE_MCC) + return; + + if (READ_ONCE(rtwvif_link->sync_bcn_tsf) > rtwvif_link->last_sync_bcn_tsf) + rtwvif_link->detect_bcn_count = 0; + else + rtwvif_link->detect_bcn_count++; + + if (rtwvif_link->detect_bcn_count < RTW89_MCC_DETECT_BCN_MAX_TRIES) + rtw89_chanctx_proceed(rtwdev, NULL); + else + ieee80211_connection_loss(vif); +} + +bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); + struct rtw89_chanctx_pause_parm pause_parm = { + .rsn = RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS, + .trigger = rtwvif_link, + }; + struct ieee80211_bss_conf *bss_conf; + struct rtw89_mcc_role *role; + u16 bcn_int; + + if (mode != RTW89_ENTITY_MODE_MCC) + return false; + + role = rtw89_mcc_get_gc_role(rtwdev); + if (!role) + return false; + + if (role->rtwvif_link != rtwvif_link) + return false; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC GC beacon loss, pause MCC to detect GO beacon\n"); + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + bcn_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + rtw89_chanctx_pause(rtwdev, &pause_parm); + rtwvif_link->last_sync_bcn_tsf = READ_ONCE(rtwvif_link->sync_bcn_tsf); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, + &rtwvif_link->mcc_gc_detect_beacon_work, + usecs_to_jiffies(ieee80211_tu_to_usec(bcn_int))); + + return true; +} + +static void rtw89_mcc_detect_connection(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *role) +{ + struct ieee80211_vif *vif; + bool start_detect; + int ret; + + ret = rtw89_core_send_nullfunc(rtwdev, role->rtwvif_link, true, false, + RTW89_MCC_PROBE_TIMEOUT); + if (ret) + role->probe_count++; + else + role->probe_count = 0; + + if (role->probe_count < RTW89_MCC_PROBE_MAX_TRIES) + return; + + rtw89_debug(rtwdev, RTW89_DBG_CHAN, + "MCC <macid %d> can not detect AP/GO\n", role->rtwvif_link->mac_id); + + start_detect = rtw89_mcc_detect_go_bcn(rtwdev, role->rtwvif_link); + if (start_detect) + return; + + vif = rtwvif_link_to_vif(role->rtwvif_link); + ieee80211_connection_loss(vif); +} + static void rtw89_mcc_track(struct rtw89_dev *rtwdev) { struct rtw89_mcc_info *mcc = &rtwdev->mcc; struct rtw89_mcc_config *config = &mcc->config; struct rtw89_mcc_pattern *pattern = &config->pattern; + struct rtw89_mcc_role *ref = &mcc->role_ref; + struct rtw89_mcc_role *aux = &mcc->role_aux; u16 tolerance; u16 bcn_ofst; u16 diff; + if (rtw89_mcc_ignore_bcn(rtwdev, ref) || aux->ignore_bcn) + rtw89_mcc_detect_connection(rtwdev, aux); + else if (rtw89_mcc_ignore_bcn(rtwdev, aux) || ref->ignore_bcn) + rtw89_mcc_detect_connection(rtwdev, ref); + if (mcc->mode != RTW89_MCC_MODE_GC_STA) return; @@ -2527,6 +2796,30 @@ static void rtw89_mcc_update_limit(struct rtw89_dev *rtwdev) rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_upd_lmt_iterator, NULL); } +static int rtw89_mcc_get_links_iterator(struct rtw89_dev *rtwdev, + struct rtw89_mcc_role *mcc_role, + unsigned int ordered_idx, + void *data) +{ + struct rtw89_mcc_links_info *info = data; + + info->links[ordered_idx] = mcc_role->rtwvif_link; + return 0; +} + +void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info) +{ + enum rtw89_entity_mode mode; + + memset(info, 0, sizeof(*info)); + + mode = rtw89_get_entity_mode(rtwdev); + if (unlikely(mode != RTW89_ENTITY_MODE_MCC)) + return; + + rtw89_iterate_mcc_roles(rtwdev, rtw89_mcc_get_links_iterator, info); +} + void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work) { struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, @@ -2595,6 +2888,7 @@ void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, return; case RTW89_ENTITY_MODE_MCC_PREPARE: delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC_PREPARE); + rtw89_phy_dig_suspend(rtwdev); break; case RTW89_ENTITY_MODE_MCC: delay = ieee80211_tu_to_usec(RTW89_CHANCTX_TIME_MCC); @@ -2619,6 +2913,201 @@ void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev) rtw89_queue_chanctx_change(rtwdev, RTW89_CHANCTX_CHANGE_DFLT); } +static enum rtw89_mr_wtype __rtw89_query_mr_wtype(struct rtw89_dev *rtwdev) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + enum rtw89_chanctx_idx chanctx_idx; + struct ieee80211_vif *vif; + struct rtw89_vif *rtwvif; + unsigned int num_mld = 0; + unsigned int num_ml = 0; + unsigned int cnt = 0; + u8 role_idx; + u8 idx; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + rtwvif = mgnt->active_roles[role_idx]; + if (!rtwvif) + continue; + + cnt++; + + vif = rtwvif_to_vif(rtwvif); + if (!ieee80211_vif_is_mld(vif)) + continue; + + num_mld++; + + for (idx = 0; idx < __RTW89_MLD_MAX_LINK_NUM; idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][idx]; + if (chanctx_idx != RTW89_CHANCTX_IDLE) + num_ml++; + } + } + + if (num_mld > 1) + goto err; + + switch (cnt) { + case 0: + return RTW89_MR_WTYPE_NONE; + case 1: + if (!num_mld) + return RTW89_MR_WTYPE_NONMLD; + switch (num_ml) { + case 1: + return RTW89_MR_WTYPE_MLD1L1R; + case 2: + return RTW89_MR_WTYPE_MLD2L1R; + default: + break; + } + break; + case 2: + if (!num_mld) + return RTW89_MR_WTYPE_NONMLD_NONMLD; + switch (num_ml) { + case 1: + return RTW89_MR_WTYPE_MLD1L1R_NONMLD; + case 2: + return RTW89_MR_WTYPE_MLD2L1R_NONMLD; + default: + break; + } + break; + default: + break; + } + +err: + rtw89_warn(rtwdev, "%s: unhandled cnt %u mld %u ml %u\n", __func__, + cnt, num_mld, num_ml); + return RTW89_MR_WTYPE_UNKNOWN; +} + +static enum rtw89_mr_wmode __rtw89_query_mr_wmode(struct rtw89_dev *rtwdev, + u8 inst_idx) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + unsigned int num[NUM_NL80211_IFTYPES] = {}; + enum rtw89_chanctx_idx chanctx_idx; + struct ieee80211_vif *vif; + struct rtw89_vif *rtwvif; + unsigned int cnt = 0; + u8 role_idx; + + if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM)) + return RTW89_MR_WMODE_UNKNOWN; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx]; + if (chanctx_idx == RTW89_CHANCTX_IDLE) + continue; + + rtwvif = mgnt->active_roles[role_idx]; + if (unlikely(!rtwvif)) + continue; + + vif = rtwvif_to_vif(rtwvif); + num[vif->type]++; + cnt++; + } + + switch (cnt) { + case 0: + return RTW89_MR_WMODE_NONE; + case 1: + if (num[NL80211_IFTYPE_STATION]) + return RTW89_MR_WMODE_1CLIENT; + if (num[NL80211_IFTYPE_AP]) + return RTW89_MR_WMODE_1AP; + break; + case 2: + if (num[NL80211_IFTYPE_STATION] == 2) + return RTW89_MR_WMODE_2CLIENTS; + if (num[NL80211_IFTYPE_AP] == 2) + return RTW89_MR_WMODE_2APS; + if (num[NL80211_IFTYPE_STATION] && num[NL80211_IFTYPE_AP]) + return RTW89_MR_WMODE_1AP_1CLIENT; + break; + default: + break; + } + + rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt); + return RTW89_MR_WMODE_UNKNOWN; +} + +static enum rtw89_mr_ctxtype __rtw89_query_mr_ctxtype(struct rtw89_dev *rtwdev, + u8 inst_idx) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + DECLARE_BITMAP(map, NUM_OF_RTW89_CHANCTX) = {}; + unsigned int num[RTW89_BAND_NUM] = {}; + enum rtw89_chanctx_idx chanctx_idx; + const struct rtw89_chan *chan; + unsigned int cnt = 0; + u8 role_idx; + + if (unlikely(inst_idx >= __RTW89_MLD_MAX_LINK_NUM)) + return RTW89_MR_CTX_UNKNOWN; + + for (role_idx = 0; role_idx < RTW89_MAX_INTERFACE_NUM; role_idx++) { + chanctx_idx = mgnt->chanctx_tbl[role_idx][inst_idx]; + if (chanctx_idx == RTW89_CHANCTX_IDLE) + continue; + + if (__test_and_set_bit(chanctx_idx, map)) + continue; + + chan = rtw89_chan_get(rtwdev, chanctx_idx); + num[chan->band_type]++; + cnt++; + } + + switch (cnt) { + case 0: + return RTW89_MR_CTX_NONE; + case 1: + if (num[RTW89_BAND_2G]) + return RTW89_MR_CTX1_2GHZ; + if (num[RTW89_BAND_5G]) + return RTW89_MR_CTX1_5GHZ; + if (num[RTW89_BAND_6G]) + return RTW89_MR_CTX1_6GHZ; + break; + case 2: + if (num[RTW89_BAND_2G] == 2) + return RTW89_MR_CTX2_2GHZ; + if (num[RTW89_BAND_5G] == 2) + return RTW89_MR_CTX2_5GHZ; + if (num[RTW89_BAND_6G] == 2) + return RTW89_MR_CTX2_6GHZ; + if (num[RTW89_BAND_2G] && num[RTW89_BAND_5G]) + return RTW89_MR_CTX2_2GHZ_5GHZ; + if (num[RTW89_BAND_2G] && num[RTW89_BAND_6G]) + return RTW89_MR_CTX2_2GHZ_6GHZ; + if (num[RTW89_BAND_5G] && num[RTW89_BAND_6G]) + return RTW89_MR_CTX2_5GHZ_6GHZ; + break; + default: + break; + } + + rtw89_warn(rtwdev, "%s: unhandled cnt %u\n", __func__, cnt); + return RTW89_MR_CTX_UNKNOWN; +} + +void rtw89_query_mr_chanctx_info(struct rtw89_dev *rtwdev, u8 inst_idx, + struct rtw89_mr_chanctx_info *info) +{ + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + info->wtype = __rtw89_query_mr_wtype(rtwdev); + info->wmode = __rtw89_query_mr_wmode(rtwdev, inst_idx); + info->ctxtype = __rtw89_query_mr_ctxtype(rtwdev, inst_idx); +} + void rtw89_chanctx_track(struct rtw89_dev *rtwdev) { struct rtw89_hal *hal = &rtwdev->hal; @@ -2782,10 +3271,9 @@ int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx) { - struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_chanctx_cfg *cfg = (struct rtw89_chanctx_cfg *)ctx->drv_priv; - clear_bit(cfg->idx, hal->entity_map); + rtw89_config_entity_chandef(rtwdev, cfg->idx, NULL); } void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, @@ -2799,6 +3287,9 @@ void rtw89_chanctx_ops_change(struct rtw89_dev *rtwdev, rtw89_config_entity_chandef(rtwdev, idx, &ctx->def); rtw89_set_channel(rtwdev); } + + if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) + rtw89_chan_update_punctured(rtwdev, idx, &ctx->def); } int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, @@ -2816,6 +3307,9 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_assigned = true; cfg->ref_count++; + if (rtwdev->scanning) + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); + if (list_empty(&rtwvif->mgnt_entry)) list_add_tail(&rtwvif->mgnt_entry, &mgnt->active_list); @@ -2855,6 +3349,9 @@ void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_assigned = false; cfg->ref_count--; + if (rtwdev->scanning) + rtw89_hw_scan_abort(rtwdev, rtwdev->scan_info.scanning_vif); + if (!rtw89_vif_is_active_role(rtwvif)) list_del_init(&rtwvif->mgnt_entry); @@ -2906,3 +3403,37 @@ out: break; } } + +int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_chanctx_conf *old_ctx, + struct ieee80211_chanctx_conf *new_ctx, + bool replace) +{ + int ret; + + rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, old_ctx); + + if (!replace) + goto assign; + + rtw89_chanctx_ops_remove(rtwdev, old_ctx); + ret = rtw89_chanctx_ops_add(rtwdev, new_ctx); + if (ret) { + rtw89_err(rtwdev, "%s: failed to add chanctx: %d\n", + __func__, ret); + return ret; + } + +assign: + ret = rtw89_chanctx_ops_assign_vif(rtwdev, rtwvif_link, new_ctx); + if (ret) { + rtw89_err(rtwdev, "%s: failed to assign chanctx: %d\n", + __func__, ret); + return ret; + } + + _rtw89_chan_update_punctured(rtwdev, rtwvif_link, &new_ctx->def); + + return 0; +} diff --git a/drivers/net/wireless/realtek/rtw89/chan.h b/drivers/net/wireless/realtek/rtw89/chan.h index 2a25563593af..b1175419f92b 100644 --- a/drivers/net/wireless/realtek/rtw89/chan.h +++ b/drivers/net/wireless/realtek/rtw89/chan.h @@ -18,6 +18,12 @@ #define RTW89_MCC_EARLY_RX_BCN_TIME 5 #define RTW89_MCC_MIN_RX_BCN_TIME 10 #define RTW89_MCC_DFLT_BCN_OFST_TIME 40 +#define RTW89_MCC_SWITCH_CH_TIME 3 + +#define RTW89_MCC_PROBE_TIMEOUT 100 +#define RTW89_MCC_PROBE_MAX_TRIES 3 + +#define RTW89_MCC_DETECT_BCN_MAX_TRIES 2 #define RTW89_MCC_MIN_GO_DURATION \ (RTW89_MCC_EARLY_TX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME) @@ -25,10 +31,13 @@ #define RTW89_MCC_MIN_STA_DURATION \ (RTW89_MCC_EARLY_RX_BCN_TIME + RTW89_MCC_MIN_RX_BCN_TIME) +#define RTW89_MCC_MIN_RX_BCN_WITH_SWITCH_CH_TIME \ + (RTW89_MCC_MIN_RX_BCN_TIME + RTW89_MCC_SWITCH_CH_TIME) + #define RTW89_MCC_DFLT_GROUP 0 #define RTW89_MCC_NEXT_GROUP(cur) (((cur) + 1) % 4) -#define RTW89_MCC_DFLT_TX_NULL_EARLY 3 +#define RTW89_MCC_DFLT_TX_NULL_EARLY 7 #define RTW89_MCC_DFLT_COURTESY_SLOT 3 #define RTW89_MCC_REQ_COURTESY_TIME 5 @@ -41,9 +50,53 @@ #define NUM_OF_RTW89_MCC_ROLES 2 +enum rtw89_mr_wtype { + RTW89_MR_WTYPE_NONE, + RTW89_MR_WTYPE_NONMLD, + RTW89_MR_WTYPE_MLD1L1R, + RTW89_MR_WTYPE_MLD2L1R, + RTW89_MR_WTYPE_MLD2L2R, + RTW89_MR_WTYPE_NONMLD_NONMLD, + RTW89_MR_WTYPE_MLD1L1R_NONMLD, + RTW89_MR_WTYPE_MLD2L1R_NONMLD, + RTW89_MR_WTYPE_MLD2L2R_NONMLD, + RTW89_MR_WTYPE_UNKNOWN, +}; + +enum rtw89_mr_wmode { + RTW89_MR_WMODE_NONE, + RTW89_MR_WMODE_1CLIENT, + RTW89_MR_WMODE_1AP, + RTW89_MR_WMODE_1AP_1CLIENT, + RTW89_MR_WMODE_2CLIENTS, + RTW89_MR_WMODE_2APS, + RTW89_MR_WMODE_UNKNOWN, +}; + +enum rtw89_mr_ctxtype { + RTW89_MR_CTX_NONE, + RTW89_MR_CTX1_2GHZ, + RTW89_MR_CTX1_5GHZ, + RTW89_MR_CTX1_6GHZ, + RTW89_MR_CTX2_2GHZ, + RTW89_MR_CTX2_5GHZ, + RTW89_MR_CTX2_6GHZ, + RTW89_MR_CTX2_2GHZ_5GHZ, + RTW89_MR_CTX2_2GHZ_6GHZ, + RTW89_MR_CTX2_5GHZ_6GHZ, + RTW89_MR_CTX_UNKNOWN, +}; + +struct rtw89_mr_chanctx_info { + enum rtw89_mr_wtype wtype; + enum rtw89_mr_wmode wmode; + enum rtw89_mr_ctxtype ctxtype; +}; + enum rtw89_chanctx_pause_reasons { RTW89_CHANCTX_PAUSE_REASON_HW_SCAN, RTW89_CHANCTX_PAUSE_REASON_ROC, + RTW89_CHANCTX_PAUSE_REASON_GC_BCN_LOSS, }; struct rtw89_chanctx_pause_parm { @@ -58,6 +111,7 @@ struct rtw89_chanctx_cb_parm { }; struct rtw89_entity_weight { + unsigned int registered_chanctxs; unsigned int active_chanctxs; unsigned int active_roles; }; @@ -116,6 +170,8 @@ void rtw89_chanctx_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_queue_chanctx_work(struct rtw89_dev *rtwdev); void rtw89_queue_chanctx_change(struct rtw89_dev *rtwdev, enum rtw89_chanctx_changes change); +void rtw89_query_mr_chanctx_info(struct rtw89_dev *rtwdev, u8 inst_idx, + struct rtw89_mr_chanctx_info *info); void rtw89_chanctx_track(struct rtw89_dev *rtwdev); void rtw89_chanctx_pause(struct rtw89_dev *rtwdev, const struct rtw89_chanctx_pause_parm *parm); @@ -129,6 +185,16 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, #define rtw89_mgnt_chan_get(rtwdev, link_index) \ __rtw89_mgnt_chan_get(rtwdev, __func__, link_index) +struct rtw89_mcc_links_info { + struct rtw89_vif_link *links[NUM_OF_RTW89_MCC_ROLES]; +}; + +void rtw89_mcc_get_links(struct rtw89_dev *rtwdev, struct rtw89_mcc_links_info *info); +void rtw89_mcc_prepare_done_work(struct wiphy *wiphy, struct wiphy_work *work); +void rtw89_mcc_gc_detect_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); +bool rtw89_mcc_detect_go_bcn(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link); + int rtw89_chanctx_ops_add(struct rtw89_dev *rtwdev, struct ieee80211_chanctx_conf *ctx); void rtw89_chanctx_ops_remove(struct rtw89_dev *rtwdev, @@ -142,5 +208,10 @@ int rtw89_chanctx_ops_assign_vif(struct rtw89_dev *rtwdev, void rtw89_chanctx_ops_unassign_vif(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct ieee80211_chanctx_conf *ctx); +int rtw89_chanctx_ops_reassign_vif(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_chanctx_conf *old_ctx, + struct ieee80211_chanctx_conf *new_ctx, + bool replace); #endif diff --git a/drivers/net/wireless/realtek/rtw89/coex.c b/drivers/net/wireless/realtek/rtw89/coex.c index 5ccf0cbaed2f..e4e6daf51a1b 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.c +++ b/drivers/net/wireless/realtek/rtw89/coex.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2020 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "fw.h" @@ -10,7 +11,7 @@ #include "ps.h" #include "reg.h" -#define RTW89_COEX_VERSION 0x07000413 +#define RTW89_COEX_VERSION 0x09000013 #define FCXDEF_STEP 50 /* MUST <= FCXMAX_STEP and match with wl fw*/ #define BTC_E2G_LIMIT_DEF 80 @@ -138,7 +139,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 8, }, {RTL8852BT, RTW89_FW_VER_CODE(0, 29, 90, 0), .fcxbtcrpt = 7, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, @@ -146,7 +147,23 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 8, + }, + {RTL8922A, RTW89_FW_VER_CODE(0, 35, 71, 0), + .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, + .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, + .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, + .fwlrole = 8, .frptmap = 4, .fcxctrl = 7, .fcxinit = 7, + .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800, + .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, .bt_desired = 9, + }, + {RTL8922A, RTW89_FW_VER_CODE(0, 35, 63, 0), + .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, + .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, + .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, + .fwlrole = 8, .frptmap = 4, .fcxctrl = 7, .fcxinit = 7, + .fwevntrptl = 1, .fwc2hfunc = 3, .drvinfo_type = 2, .info_buf = 1800, + .max_role_num = 6, .fcxosi = 1, .fcxmlo = 1, .bt_desired = 9, }, {RTL8922A, RTW89_FW_VER_CODE(0, 35, 8, 0), .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, @@ -154,7 +171,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, .fwlrole = 8, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, .fwevntrptl = 1, .fwc2hfunc = 1, .drvinfo_type = 1, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8851B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, @@ -162,7 +179,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 57, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -170,7 +187,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 42, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -178,7 +195,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852C, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -186,7 +203,15 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 2, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, + }, + {RTL8852B, RTW89_FW_VER_CODE(0, 29, 122, 0), + .fcxbtcrpt = 8, .fcxtdma = 7, .fcxslots = 7, .fcxcysta = 7, + .fcxstep = 7, .fcxnullsta = 7, .fcxmreg = 7, .fcxgpiodbg = 7, + .fcxbtver = 7, .fcxbtscan = 7, .fcxbtafh = 7, .fcxbtdevinfo = 7, + .fwlrole = 7, .frptmap = 3, .fcxctrl = 7, .fcxinit = 7, + .fwevntrptl = 1, .fwc2hfunc = 2, .drvinfo_type = 1, .info_buf = 1800, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 8, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 29, 0), .fcxbtcrpt = 105, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 5, @@ -194,7 +219,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 2, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 2, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852B, RTW89_FW_VER_CODE(0, 29, 14, 0), .fcxbtcrpt = 5, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 4, @@ -202,7 +227,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1800, - .max_role_num = 6, + .max_role_num = 6, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852B, RTW89_FW_VER_CODE(0, 27, 0, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -210,7 +235,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 1, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 37, 0), .fcxbtcrpt = 4, .fcxtdma = 3, .fcxslots = 1, .fcxcysta = 3, @@ -218,7 +243,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 2, .fcxbtdevinfo = 1, .fwlrole = 1, .frptmap = 3, .fcxctrl = 1, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1280, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, {RTL8852A, RTW89_FW_VER_CODE(0, 13, 0, 0), .fcxbtcrpt = 1, .fcxtdma = 1, .fcxslots = 1, .fcxcysta = 2, @@ -226,7 +251,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 0, .drvinfo_type = 0, .info_buf = 1024, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, /* keep it to be the last as default entry */ @@ -236,7 +261,7 @@ static const struct rtw89_btc_ver rtw89_btc_ver_defs[] = { .fcxbtver = 1, .fcxbtscan = 1, .fcxbtafh = 1, .fcxbtdevinfo = 1, .fwlrole = 0, .frptmap = 0, .fcxctrl = 0, .fcxinit = 0, .fwevntrptl = 0, .fwc2hfunc = 1, .drvinfo_type = 0, .info_buf = 1024, - .max_role_num = 5, + .max_role_num = 5, .fcxosi = 0, .fcxmlo = 0, .bt_desired = 7, }, }; @@ -269,6 +294,39 @@ static u32 chip_id_to_bt_rom_code_id(u32 id) } } +#define CASE_BTC_MLME_STATE(e) case MLME_##e: return #e + +static const char *id_to_mlme_state(u32 id) +{ + switch (id) { + CASE_BTC_MLME_STATE(NO_LINK); + CASE_BTC_MLME_STATE(LINKING); + CASE_BTC_MLME_STATE(LINKED); + default: + return "unknown"; + } +} + +static char *chip_id_str(u32 id) +{ + switch (id) { + case RTL8852A: + return "RTL8852A"; + case RTL8852B: + return "RTL8852B"; + case RTL8852C: + return "RTL8852C"; + case RTL8852BT: + return "RTL8852BT"; + case RTL8851B: + return "RTL8851B"; + case RTL8922A: + return "RTL8922A"; + default: + return "UNKNOWN"; + } +} + struct rtw89_btc_btf_tlv { u8 type; u8 len; @@ -291,6 +349,7 @@ enum btc_btf_set_report_en { RPT_EN_BT_DEVICE_INFO, RPT_EN_BT_AFH_MAP, RPT_EN_BT_AFH_MAP_LE, + RPT_EN_BT_TX_PWR_LVL, RPT_EN_FW_STEP_INFO, RPT_EN_TEST, RPT_EN_WL_ALL, @@ -668,6 +727,27 @@ enum btc_wl_link_mode { BTC_WLINK_MAX }; +#define CASE_BTC_WL_LINK_MODE(e) case BTC_WLINK_## e: return #e + +static const char *id_to_linkmode(u8 id) +{ + switch (id) { + CASE_BTC_WL_LINK_MODE(NOLINK); + CASE_BTC_WL_LINK_MODE(2G_STA); + CASE_BTC_WL_LINK_MODE(2G_AP); + CASE_BTC_WL_LINK_MODE(2G_GO); + CASE_BTC_WL_LINK_MODE(2G_GC); + CASE_BTC_WL_LINK_MODE(2G_SCC); + CASE_BTC_WL_LINK_MODE(2G_MCC); + CASE_BTC_WL_LINK_MODE(25G_MCC); + CASE_BTC_WL_LINK_MODE(25G_DBCC); + CASE_BTC_WL_LINK_MODE(5G); + CASE_BTC_WL_LINK_MODE(OTHER); + default: + return "unknown"; + } +} + enum btc_wl_mrole_type { BTC_WLMROLE_NONE = 0x0, BTC_WLMROLE_STA_GC, @@ -833,6 +913,9 @@ static int _send_fw_cmd(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, return ret; } +#define BTC_BT_DEF_BR_TX_PWR 4 +#define BTC_BT_DEF_LE_TX_PWR 4 + static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) { struct rtw89_btc *btc = &rtwdev->btc; @@ -901,6 +984,9 @@ static void _reset_btc_var(struct rtw89_dev *rtwdev, u8 type) if (type & BTC_RESET_MDINFO) memset(&btc->mdinfo, 0, sizeof(btc->mdinfo)); + + bt->link_info.bt_txpwr_desc.br_dbm = BTC_BT_DEF_BR_TX_PWR; + bt->link_info.bt_txpwr_desc.le_dbm = BTC_BT_DEF_LE_TX_PWR; } static u8 _search_reg_index(struct rtw89_dev *rtwdev, u8 mreg_num, u16 reg_type, u32 target) @@ -1324,6 +1410,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, u8 *prptbuf, u32 index) { struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver; const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_dm *dm = &btc->dm; struct rtw89_btc_rpt_cmn_info *pcinfo = NULL; @@ -1366,23 +1453,29 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxbtcrpt == 1) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v1); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v1.fver; } else if (ver->fcxbtcrpt == 4) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v4; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v4); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v4.fver; } else if (ver->fcxbtcrpt == 5) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v5; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v5); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v5.fver; } else if (ver->fcxbtcrpt == 105) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v105; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v105); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v105.fver; pcinfo->req_fver = 5; break; } else if (ver->fcxbtcrpt == 8) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v8; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v8); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v8.fver; } else if (ver->fcxbtcrpt == 7) { pfinfo = &pfwinfo->rpt_ctrl.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_ctrl.finfo.v7); + fwsubver->fcxbtcrpt = pfwinfo->rpt_ctrl.finfo.v7.fver; } else { goto err; } @@ -1393,9 +1486,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxtdma == 1) { pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v1); + fwsubver->fcxtdma = 0; } else if (ver->fcxtdma == 3 || ver->fcxtdma == 7) { pfinfo = &pfwinfo->rpt_fbtc_tdma.finfo.v3; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_tdma.finfo.v3); + fwsubver->fcxtdma = pfwinfo->rpt_fbtc_tdma.finfo.v3.fver; } else { goto err; } @@ -1406,9 +1501,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxslots == 1) { pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v1); + fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v1.fver; } else if (ver->fcxslots == 7) { pfinfo = &pfwinfo->rpt_fbtc_slots.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_slots.finfo.v7); + fwsubver->fcxslots = pfwinfo->rpt_fbtc_slots.finfo.v7.fver; } else { goto err; } @@ -1421,22 +1518,27 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v2; pcysta->v2 = pfwinfo->rpt_fbtc_cysta.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v2); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v2.fver; } else if (ver->fcxcysta == 3) { pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v3; pcysta->v3 = pfwinfo->rpt_fbtc_cysta.finfo.v3; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v3); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v3.fver; } else if (ver->fcxcysta == 4) { pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v4; pcysta->v4 = pfwinfo->rpt_fbtc_cysta.finfo.v4; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v4); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v4.fver; } else if (ver->fcxcysta == 5) { pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v5; pcysta->v5 = pfwinfo->rpt_fbtc_cysta.finfo.v5; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v5); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v5.fver; } else if (ver->fcxcysta == 7) { pfinfo = &pfwinfo->rpt_fbtc_cysta.finfo.v7; pcysta->v7 = pfwinfo->rpt_fbtc_cysta.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_cysta.finfo.v7); + fwsubver->fcxcysta = pfwinfo->rpt_fbtc_cysta.finfo.v7.fver; } else { goto err; } @@ -1452,11 +1554,13 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v2.step[0]) * trace_step + offsetof(struct rtw89_btc_fbtc_steps_v2, step); + fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v2.fver; } else if (ver->fcxstep == 3) { pfinfo = &pfwinfo->rpt_fbtc_step.finfo.v3; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_step.finfo.v3.step[0]) * trace_step + offsetof(struct rtw89_btc_fbtc_steps_v3, step); + fwsubver->fcxstep = pfwinfo->rpt_fbtc_step.finfo.v3.fver; } else { goto err; } @@ -1467,12 +1571,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxnullsta == 1) { pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v1); + fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v1.fver; } else if (ver->fcxnullsta == 2) { pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v2); + fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v2.fver; } else if (ver->fcxnullsta == 7) { pfinfo = &pfwinfo->rpt_fbtc_nullsta.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_nullsta.finfo.v7); + fwsubver->fcxnullsta = pfwinfo->rpt_fbtc_nullsta.finfo.v7.fver; } else { goto err; } @@ -1483,12 +1590,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxmreg == 1) { pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v1); + fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v1.fver; } else if (ver->fcxmreg == 2) { pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v2); + fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v2.fver; } else if (ver->fcxmreg == 7) { pfinfo = &pfwinfo->rpt_fbtc_mregval.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_mregval.finfo.v7); + fwsubver->fcxmreg = pfwinfo->rpt_fbtc_mregval.finfo.v7.fver; } else { goto err; } @@ -1499,9 +1609,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxgpiodbg == 7) { pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7); + fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v7.fver; } else { pfinfo = &pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1); + fwsubver->fcxgpiodbg = pfwinfo->rpt_fbtc_gpio_dbg.finfo.v1.fver; } pcinfo->req_fver = ver->fcxgpiodbg; break; @@ -1510,9 +1622,11 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxbtver == 1) { pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v1); + fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v1.fver; } else if (ver->fcxbtver == 7) { pfinfo = &pfwinfo->rpt_fbtc_btver.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btver.finfo.v7); + fwsubver->fcxbtver = pfwinfo->rpt_fbtc_btver.finfo.v7.fver; } pcinfo->req_fver = ver->fcxbtver; break; @@ -1521,12 +1635,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxbtscan == 1) { pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v1); + fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v1.fver; } else if (ver->fcxbtscan == 2) { pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v2); + fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v2.fver; } else if (ver->fcxbtscan == 7) { pfinfo = &pfwinfo->rpt_fbtc_btscan.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btscan.finfo.v7); + fwsubver->fcxbtscan = pfwinfo->rpt_fbtc_btscan.finfo.v7.fver; } else { goto err; } @@ -1537,12 +1654,15 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, if (ver->fcxbtafh == 1) { pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v1; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v1); + fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v1.fver; } else if (ver->fcxbtafh == 2) { pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v2; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v2); + fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v2.fver; } else if (ver->fcxbtafh == 7) { pfinfo = &pfwinfo->rpt_fbtc_btafh.finfo.v7; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btafh.finfo.v7); + fwsubver->fcxbtafh = pfwinfo->rpt_fbtc_btafh.finfo.v7.fver; } else { goto err; } @@ -1552,6 +1672,7 @@ static u32 _chk_btc_report(struct rtw89_dev *rtwdev, pcinfo = &pfwinfo->rpt_fbtc_btdev.cinfo; pfinfo = &pfwinfo->rpt_fbtc_btdev.finfo; pcinfo->req_len = sizeof(pfwinfo->rpt_fbtc_btdev.finfo); + fwsubver->fcxbtdevinfo = pfwinfo->rpt_fbtc_btdev.finfo.fver; pcinfo->req_fver = ver->fcxbtdevinfo; break; default: @@ -2283,6 +2404,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) bit_map = BIT(6); break; case 3: + case 4: bit_map = BIT(5); break; default: @@ -2297,6 +2419,7 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) bit_map = BIT(5); break; case 3: + case 4: bit_map = BIT(6); break; default: @@ -2309,12 +2432,27 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) bit_map = BIT(8); break; case 3: + case 4: bit_map = BIT(7); break; default: break; } break; + case RPT_EN_BT_TX_PWR_LVL: + switch (ver->frptmap) { + case 0: + case 1: + case 2: + case 3: + break; + case 4: + bit_map = BIT(8); + break; + default: + break; + } + break; case RPT_EN_FW_STEP_INFO: switch (ver->frptmap) { case 1: @@ -2324,6 +2462,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = BIT(8); break; + case 4: + bit_map = BIT(9); + break; default: break; } @@ -2341,6 +2482,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = GENMASK(2, 0) | BIT(8); break; + case 4: + bit_map = GENMASK(2, 0) | BIT(9); + break; default: break; } @@ -2357,6 +2501,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = GENMASK(7, 3); break; + case 4: + bit_map = GENMASK(8, 3); + break; default: break; } @@ -2373,6 +2520,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = GENMASK(8, 0); break; + case 4: + bit_map = GENMASK(9, 0); + break; default: break; } @@ -2389,6 +2539,9 @@ static u32 rtw89_btc_fw_rpt_ver(struct rtw89_dev *rtwdev, u32 rpt_map) case 3: bit_map = GENMASK(8, 2); break; + case 4: + bit_map = GENMASK(9, 2); + break; default: break; } @@ -2678,6 +2831,16 @@ static void _fw_set_drv_info(struct rtw89_dev *rtwdev, u8 type) case CXDRVINFO_FDDT: case CXDRVINFO_MLO: case CXDRVINFO_OSI: + if (!ver->fcxosi) + return; + + if (ver->drvinfo_type == 2) + type = 7; + else + return; + + rtw89_fw_h2c_cxdrv_osi_info(rtwdev, type); + break; default: break; } @@ -2758,6 +2921,8 @@ static void _set_gnt_v1(struct rtw89_dev *rtwdev, u8 phy_map, { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_dm *dm = &btc->dm; + struct rtw89_btc_fbtc_outsrc_set_info *osi = &dm->ost_info; + struct rtw89_mac_ax_wl_act *b = dm->gnt.bt; struct rtw89_mac_ax_gnt *g = dm->gnt.band; u8 i, bt_idx = dm->bt_select + 1; @@ -2806,21 +2971,35 @@ static void _set_gnt_v1(struct rtw89_dev *rtwdev, u8 phy_map, switch (wlact_state) { case BTC_WLACT_HW: - dm->gnt.bt[i].wlan_act_en = 0; - dm->gnt.bt[i].wlan_act = 0; + b[i].wlan_act_en = 0; + b[i].wlan_act = 0; break; case BTC_WLACT_SW_LO: - dm->gnt.bt[i].wlan_act_en = 1; - dm->gnt.bt[i].wlan_act = 0; + b[i].wlan_act_en = 1; + b[i].wlan_act = 0; break; case BTC_WLACT_SW_HI: - dm->gnt.bt[i].wlan_act_en = 1; - dm->gnt.bt[i].wlan_act = 1; + b[i].wlan_act_en = 1; + b[i].wlan_act = 1; break; } } } - rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); + + if (!btc->ver->fcxosi) { + rtw89_mac_cfg_gnt_v2(rtwdev, &dm->gnt); + return; + } + + memcpy(osi->gnt_set, dm->gnt.band, sizeof(osi->gnt_set)); + memcpy(osi->wlact_set, dm->gnt.bt, sizeof(osi->wlact_set)); + + /* GBT source should be GBT_S1 in 1+1 (HWB0:5G + HWB1:2G) case */ + if (osi->rf_band[BTC_RF_S0] == 1 && + osi->rf_band[BTC_RF_S1] == 0) + osi->rf_gbt_source = BTC_RF_S1; + else + osi->rf_gbt_source = BTC_RF_S0; } #define BTC_TDMA_WLROLE_MAX 3 @@ -3062,7 +3241,7 @@ static void _update_btc_state_map(struct rtw89_dev *rtwdev) } } -static void _set_bt_afh_info(struct rtw89_dev *rtwdev) +static void _set_bt_afh_info_v0(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_btc *btc = &rtwdev->btc; @@ -3231,6 +3410,115 @@ static void _set_bt_afh_info(struct rtw89_dev *rtwdev) btc->cx.cnt_wl[BTC_WCNT_CH_UPDATE]++; } +static void _set_bt_afh_info_v1(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; + struct rtw89_btc_wl_afh_info *wl_afh = &wl->afh_info; + struct rtw89_btc_bt_info *bt = &btc->cx.bt; + struct rtw89_btc_wl_rlink *rlink; + u8 en = 0, ch = 0, bw = 0, buf[3] = {}; + u8 i, j, link_mode; + + if (btc->manual_ctrl || wl->status.map.scan) + return; + + link_mode = wl_rinfo->link_mode; + + for (i = 0; i < btc->ver->max_role_num; i++) { + for (j = RTW89_MAC_0; j < RTW89_MAC_NUM; j++) { + if (wl->status.map.rf_off || bt->whql_test || + link_mode == BTC_WLINK_NOLINK || + link_mode == BTC_WLINK_5G) + break; + + rlink = &wl_rinfo->rlink[i][j]; + + /* Don't care no-connected/non-2G-band role */ + if (!rlink->connected || !rlink->active || + rlink->rf_band != RTW89_BAND_2G) + continue; + + en = 1; + ch = rlink->ch; + bw = rlink->bw; + + if (link_mode == BTC_WLINK_2G_MCC && + (rlink->role == RTW89_WIFI_ROLE_AP || + rlink->role == RTW89_WIFI_ROLE_P2P_GO || + rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)) { + /* for 2.4G MCC, take role = ap/go/gc */ + break; + } else if (link_mode != BTC_WLINK_2G_SCC || + rlink->bw == RTW89_CHANNEL_WIDTH_40) { + /* for 2.4G scc, take bw = 40M */ + break; + } + } + } + + /* default AFH channel sapn = center-ch +- 6MHz */ + switch (bw) { + case RTW89_CHANNEL_WIDTH_20: + if (btc->dm.freerun || btc->dm.fddt_train) + bw = 48; + else + bw = 20 + chip->afh_guard_ch * 2; + break; + case RTW89_CHANNEL_WIDTH_40: + if (btc->dm.freerun) + bw = 40 + chip->afh_guard_ch * 2; + else + bw = 40; + break; + case RTW89_CHANNEL_WIDTH_5: + bw = 5 + chip->afh_guard_ch * 2; + break; + case RTW89_CHANNEL_WIDTH_10: + bw = 10 + chip->afh_guard_ch * 2; + break; + default: + en = false; /* turn off AFH info if invalid BW */ + bw = 0; + ch = 0; + break; + } + + if (!en || ch > 14 || ch == 0) { + en = false; + bw = 0; + ch = 0; + } + + if (wl_afh->en == en && + wl_afh->ch == ch && + wl_afh->bw == bw && + (!bt->enable.now || bt->enable.last)) + return; + + wl_afh->en = buf[0]; + wl_afh->ch = buf[1]; + wl_afh->bw = buf[2]; + + if (_send_fw_cmd(rtwdev, BTFC_SET, SET_BT_WL_CH_INFO, &wl->afh_info, 3)) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): en=%d, ch=%d, bw=%d\n", + __func__, en, ch, bw); + + btc->cx.cnt_wl[BTC_WCNT_CH_UPDATE]++; + } +} + +static void _set_bt_afh_info(struct rtw89_dev *rtwdev) +{ + if (rtwdev->chip->chip_id == RTL8922A) + _set_bt_afh_info_v1(rtwdev); + else + _set_bt_afh_info_v0(rtwdev); +} + static bool _check_freerun(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -3716,6 +4004,15 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) u32 tbl_w1, tbl_b1, tbl_b4; u16 dur_2; + if (wl->status.map.lps) { + _slot_set_le(btc, CXST_E2G, s_def[CXST_E2G].dur, + s_def[CXST_E2G].cxtbl, s_def[CXST_E2G].cxtype); + _slot_set_le(btc, CXST_E5G, s_def[CXST_E5G].dur, + s_def[CXST_E5G].cxtbl, s_def[CXST_E5G].cxtype); + _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, + s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); + } + type = FIELD_GET(BTC_CXP_MASK, policy_type); if (btc->ant_type == BTC_ANT_SHARED) { @@ -3836,13 +4133,13 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) switch (policy_type) { case BTC_CXP_OFFE_2GBWISOB: /* for normal-case */ - _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_ISO); + _slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_ISO); _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); _slot_set_dur(btc, CXST_EBT, dur_2); break; case BTC_CXP_OFFE_2GISOB: /* for bt no-link */ - _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_ISO); + _slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_ISO); _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); _slot_set_dur(btc, CXST_EBT, dur_2); @@ -3868,15 +4165,15 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) break; case BTC_CXP_OFFE_2GBWMIXB: if (a2dp->exist) - _slot_set(btc, CXST_E2G, 0, cxtbl[2], SLOT_MIX); + _slot_set(btc, CXST_E2G, 5, cxtbl[2], SLOT_MIX); else - _slot_set(btc, CXST_E2G, 0, tbl_w1, SLOT_MIX); - _slot_set_le(btc, CXST_EBT, s_def[CXST_EBT].dur, + _slot_set(btc, CXST_E2G, 5, tbl_w1, SLOT_MIX); + _slot_set_le(btc, CXST_EBT, cpu_to_le16(40), s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); break; case BTC_CXP_OFFE_WL: /* for 4-way */ - _slot_set(btc, CXST_E2G, 0, cxtbl[1], SLOT_MIX); - _slot_set(btc, CXST_EBT, 0, cxtbl[1], SLOT_MIX); + _slot_set(btc, CXST_E2G, 5, cxtbl[1], SLOT_MIX); + _slot_set(btc, CXST_EBT, 5, cxtbl[1], SLOT_MIX); break; default: break; @@ -4864,16 +5161,14 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) struct rtw89_btc_wl_role_info_v2 *wl_rinfo_v2 = &wl->role_info_v2; struct rtw89_btc_wl_role_info_v7 *wl_rinfo_v7 = &wl->role_info_v7; struct rtw89_btc_wl_role_info_v8 *wl_rinfo_v8 = &wl->role_info_v8; + struct rtw89_btc_fbtc_outsrc_set_info *o_info = &btc->dm.ost_info; struct rtw89_btc_wl_role_info *wl_rinfo_v0 = &wl->role_info; - struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info; const struct rtw89_chip_info *chip = rtwdev->chip; const struct rtw89_btc_ver *ver = btc->ver; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_dm *dm = &btc->dm; struct _wl_rinfo_now wl_rinfo; - u32 run_reason = btc->dm.run_reason; - u32 is_btg; - u8 i, val; + u32 is_btg = BTC_BTGCTRL_DISABLE; if (btc->manual_ctrl) return; @@ -4891,63 +5186,62 @@ static void _set_btg_ctrl(struct rtw89_dev *rtwdev) else return; - if (rtwdev->dbcc_en) { - if (ver->fwlrole == 0) { - wl_rinfo.dbcc_2g_phy = RTW89_PHY_NUM; + /* notify halbb ignore GNT_BT or not for WL BB Rx-AGC control */ + if (btc->ant_type == BTC_ANT_SHARED) { + if (!(bt->run_patch_code && bt->enable.now)) + is_btg = BTC_BTGCTRL_DISABLE; + else if (wl_rinfo.link_mode != BTC_WLINK_5G) + is_btg = BTC_BTGCTRL_ENABLE; + else + is_btg = BTC_BTGCTRL_DISABLE; - for (i = 0; i < RTW89_PHY_NUM; i++) { - if (wl_dinfo->real_band[i] == RTW89_BAND_2G) - wl_rinfo.dbcc_2g_phy = i; - } - } else if (ver->fwlrole == 1) { - wl_rinfo.dbcc_2g_phy = wl_rinfo_v1->dbcc_2g_phy; - } else if (ver->fwlrole == 2) { - wl_rinfo.dbcc_2g_phy = wl_rinfo_v2->dbcc_2g_phy; - } else if (ver->fwlrole == 7) { - wl_rinfo.dbcc_2g_phy = wl_rinfo_v7->dbcc_2g_phy; - } else if (ver->fwlrole == 8) { - wl_rinfo.dbcc_2g_phy = wl_rinfo_v8->dbcc_2g_phy; - } else { - return; - } + /* bb call ctrl_btg() in WL FW by slot */ + if (!ver->fcxosi && + wl_rinfo.link_mode == BTC_WLINK_25G_MCC) + is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL; } - if (wl_rinfo.link_mode == BTC_WLINK_25G_MCC) - is_btg = BTC_BTGCTRL_BB_GNT_FWCTRL; - else if (!(bt->run_patch_code && bt->enable.now)) - is_btg = BTC_BTGCTRL_DISABLE; - else if (wl_rinfo.link_mode == BTC_WLINK_5G) - is_btg = BTC_BTGCTRL_DISABLE; - else if (dm->freerun) - is_btg = BTC_BTGCTRL_DISABLE; - else if (rtwdev->dbcc_en && wl_rinfo.dbcc_2g_phy != RTW89_PHY_1) - is_btg = BTC_BTGCTRL_DISABLE; + if (is_btg == dm->wl_btg_rx) + return; else - is_btg = BTC_BTGCTRL_ENABLE; + dm->wl_btg_rx = is_btg; - if (dm->wl_btg_rx_rb != dm->wl_btg_rx && - dm->wl_btg_rx_rb != BTC_BTGCTRL_BB_GNT_NOTFOUND) { - _get_reg_status(rtwdev, BTC_CSTATUS_BB_GNT_MUX, &val); - dm->wl_btg_rx_rb = val; - } + /* skip setup if btg_ctrl set by wl fw */ + if (!ver->fcxosi && is_btg > BTC_BTGCTRL_ENABLE) + return; - if (run_reason == BTC_RSN_NTFY_INIT || - run_reason == BTC_RSN_NTFY_SWBAND || - dm->wl_btg_rx_rb != dm->wl_btg_rx || - is_btg != dm->wl_btg_rx) { + /* Below flow is for BTC_FEAT_NEW_BBAPI_FLOW = 1 */ + if (o_info->rf_band[BTC_RF_S0] != o_info->rf_band[BTC_RF_S1]) {/* 1+1 */ + if (o_info->rf_band[BTC_RF_S0]) /* Non-2G */ + o_info->btg_rx[BTC_RF_S0] = BTC_BTGCTRL_DISABLE; + else + o_info->btg_rx[BTC_RF_S0] = is_btg; - dm->wl_btg_rx = is_btg; + if (o_info->rf_band[BTC_RF_S1]) /* Non-2G */ + o_info->btg_rx[BTC_RF_S1] = BTC_BTGCTRL_DISABLE; + else + o_info->btg_rx[BTC_RF_S1] = is_btg; + } else { /* 2+0 or 0+2 */ + o_info->btg_rx[BTC_RF_S0] = is_btg; + o_info->btg_rx[BTC_RF_S1] = is_btg; + } - if (is_btg > BTC_BTGCTRL_ENABLE) - return; + if (ver->fcxosi) + return; - chip->ops->ctrl_btg_bt_rx(rtwdev, is_btg, RTW89_PHY_0); - } + chip->ops->ctrl_btg_bt_rx(rtwdev, o_info->btg_rx[BTC_RF_S0], + RTW89_PHY_0); + if (chip->chip_id != RTL8922A) + return; + + chip->ops->ctrl_btg_bt_rx(rtwdev, o_info->btg_rx[BTC_RF_S1], + RTW89_PHY_1); } static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_fbtc_outsrc_set_info *o_info = &btc->dm.ost_info; struct rtw89_btc_bt_link_info *bt_linfo = &btc->cx.bt.link_info; struct rtw89_btc_wl_info *wl = &btc->cx.wl; struct rtw89_btc_wl_role_info_v2 *rinfo_v2 = &wl->role_info_v2; @@ -4979,9 +5273,7 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) return; } - if (link_mode == BTC_WLINK_25G_MCC) { - is_preagc = BTC_PREAGC_BB_FWCTRL; - } else if (!(bt->run_patch_code && bt->enable.now)) { + if (!(bt->run_patch_code && bt->enable.now)) { is_preagc = BTC_PREAGC_DISABLE; } else if (link_mode == BTC_WLINK_5G) { is_preagc = BTC_PREAGC_DISABLE; @@ -5001,6 +5293,9 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) is_preagc = BTC_PREAGC_ENABLE; } + if (!btc->ver->fcxosi && link_mode == BTC_WLINK_25G_MCC) + is_preagc = BTC_PREAGC_BB_FWCTRL; + if (dm->wl_pre_agc_rb != dm->wl_pre_agc && dm->wl_pre_agc_rb != BTC_PREAGC_NOTFOUND) { _get_reg_status(rtwdev, BTC_CSTATUS_BB_PRE_AGC, &val); @@ -5014,9 +5309,34 @@ static void _set_wl_preagc_ctrl(struct rtw89_dev *rtwdev) is_preagc != dm->wl_pre_agc) { dm->wl_pre_agc = is_preagc; - if (is_preagc > BTC_PREAGC_ENABLE) + if (!btc->ver->fcxosi && is_preagc > BTC_PREAGC_ENABLE) return; - chip->ops->ctrl_nbtg_bt_tx(rtwdev, dm->wl_pre_agc, RTW89_PHY_0); + + if (o_info->rf_band[BTC_RF_S0] != o_info->rf_band[BTC_RF_S1]) {/* 1+1 */ + if (o_info->rf_band[BTC_RF_S0]) /* Non-2G */ + o_info->nbtg_tx[BTC_RF_S0] = BTC_PREAGC_DISABLE; + else + o_info->nbtg_tx[BTC_RF_S0] = is_preagc; + + if (o_info->rf_band[BTC_RF_S1]) /* Non-2G */ + o_info->nbtg_tx[BTC_RF_S1] = BTC_PREAGC_DISABLE; + else + o_info->nbtg_tx[BTC_RF_S1] = is_preagc; + + } else { /* 2+0 or 0+2 */ + o_info->nbtg_tx[BTC_RF_S0] = is_preagc; + o_info->nbtg_tx[BTC_RF_S1] = is_preagc; + } + + if (btc->ver->fcxosi) + return; + + chip->ops->ctrl_nbtg_bt_tx(rtwdev, o_info->nbtg_tx[BTC_RF_S0], + RTW89_PHY_0); + if (chip->chip_id != RTL8922A) + return; + chip->ops->ctrl_nbtg_bt_tx(rtwdev, o_info->nbtg_tx[BTC_RF_S1], + RTW89_PHY_1); } } @@ -5229,15 +5549,47 @@ static void _set_bt_rx_scan_pri(struct rtw89_dev *rtwdev) _write_scbd(rtwdev, BTC_WSCB_RXSCAN_PRI, (bool)(!!bt->scan_rx_low_pri)); } +static void _wl_req_mac(struct rtw89_dev *rtwdev, u8 mac) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_dm *dm = &btc->dm; + u32 add; + + if (mac == wl->pta_req_mac) + return; + + dm->ost_info.pta_req_hw_band = mac; + wl->pta_req_mac = mac; + wl->pta_reg_mac_chg = true; + + if (btc->ver->fcxosi) + return; + + if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) + add = R_BE_BTC_CFG; + else + add = R_AX_BTC_CFG; + + if (mac == RTW89_MAC_0) + rtw89_write32_clr(rtwdev, add, B_AX_WL_SRC); + else + rtw89_write32_set(rtwdev, add, B_AX_WL_SRC); +} + static void _action_common(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_wl_info *wl = &btc->cx.wl; + struct rtw89_btc_wl_role_info_v8 *rinfo_v8 = &wl->role_info_v8; struct rtw89_btc_wl_smap *wl_smap = &wl->status.map; struct rtw89_btc_bt_info *bt = &btc->cx.bt; struct rtw89_btc_dm *dm = &btc->dm; u32 bt_rom_code_id, bt_fw_ver; + if (btc->ver->fwlrole == 8) + _wl_req_mac(rtwdev, rinfo_v8->pta_req_band); + _set_btg_ctrl(rtwdev); _set_wl_preagc_ctrl(rtwdev); _set_wl_tx_limit(rtwdev); @@ -5273,7 +5625,18 @@ static void _action_common(struct rtw89_dev *rtwdev) wl->scbd_change = false; btc->cx.cnt_wl[BTC_WCNT_SCBDUPDATE]++; } + + if (btc->ver->fcxosi) { + if (memcmp(&dm->ost_info_last, &dm->ost_info, + sizeof(dm->ost_info_last)) || + dm->run_reason == BTC_RSN_NTFY_INIT || + dm->run_reason == BTC_RSN_NTFY_RADIO_STATE) { + dm->ost_info_last = dm->ost_info; + _fw_set_drv_info(rtwdev, CXDRVINFO_OSI); + } + } btc->dm.tdma_instant_excute = 0; + wl->pta_reg_mac_chg = false; } static void _action_by_bt(struct rtw89_dev *rtwdev) @@ -5736,14 +6099,6 @@ _update_rssi_state(struct rtw89_dev *rtwdev, u8 pre_state, u8 rssi, u8 thresh) return next_state; } -static void _wl_req_mac(struct rtw89_dev *rtwdev, u8 mac) -{ - if (mac == RTW89_MAC_0) - rtw89_write32_clr(rtwdev, R_AX_BTC_CFG, B_AX_WL_SRC); - else - rtw89_write32_set(rtwdev, R_AX_BTC_CFG, B_AX_WL_SRC); -} - static void _update_dbcc_band(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -6239,23 +6594,16 @@ static bool _chk_role_ch_group(const struct rtw89_btc_chdef *r1, } static u8 _chk_dbcc(struct rtw89_dev *rtwdev, struct rtw89_btc_chdef *ch, - u8 *phy, u8 *role, u8 *dbcc_2g_phy) + u8 *phy, u8 *role, u8 link_cnt) { struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; struct rtw89_btc_wl_role_info_v7 *rinfo_v7 = &wl->role_info_v7; struct rtw89_btc_wl_role_info_v8 *rinfo_v8 = &wl->role_info_v8; bool is_2g_ch_exist = false, is_multi_role_in_2g_phy = false; - u8 j, k, dbcc_2g_cid, dbcc_2g_cid2, connect_cnt; - - if (rtwdev->btc.ver->fwlrole == 7) - connect_cnt = rinfo_v7->connect_cnt; - else if (rtwdev->btc.ver->fwlrole == 8) - connect_cnt = rinfo_v8->connect_cnt; - else - return BTC_WLINK_NOLINK; + u8 j, k, dbcc_2g_cid, dbcc_2g_cid2, dbcc_2g_phy, pta_req_band; /* find out the 2G-PHY by connect-id ->ch */ - for (j = 0; j < connect_cnt; j++) { + for (j = 0; j < link_cnt; j++) { if (ch[j].center_ch <= 14) { is_2g_ch_exist = true; break; @@ -6264,21 +6612,33 @@ static u8 _chk_dbcc(struct rtw89_dev *rtwdev, struct rtw89_btc_chdef *ch, /* If no any 2G-port exist, it's impossible because 5G-exclude */ if (!is_2g_ch_exist) - return BTC_WLINK_OTHER; + return BTC_WLINK_5G; dbcc_2g_cid = j; - *dbcc_2g_phy = phy[dbcc_2g_cid]; + dbcc_2g_phy = phy[dbcc_2g_cid]; + + if (dbcc_2g_phy == RTW89_PHY_1) + pta_req_band = RTW89_PHY_1; + else + pta_req_band = RTW89_PHY_0; + + if (rtwdev->btc.ver->fwlrole == 7) { + rinfo_v7->dbcc_2g_phy = dbcc_2g_phy; + } else if (rtwdev->btc.ver->fwlrole == 8) { + rinfo_v8->dbcc_2g_phy = dbcc_2g_phy; + rinfo_v8->pta_req_band = pta_req_band; + } /* connect_cnt <= 2 */ - if (connect_cnt < BTC_TDMA_WLROLE_MAX) + if (link_cnt < BTC_TDMA_WLROLE_MAX) return (_get_role_link_mode((role[dbcc_2g_cid]))); /* find the other-port in the 2G-PHY, ex: PHY-0:6G, PHY1: mcc/scc */ - for (k = 0; k < connect_cnt; k++) { + for (k = 0; k < link_cnt; k++) { if (k == dbcc_2g_cid) continue; - if (phy[k] == *dbcc_2g_phy) { + if (phy[k] == dbcc_2g_phy) { is_multi_role_in_2g_phy = true; dbcc_2g_cid2 = k; break; @@ -6480,7 +6840,7 @@ static void _update_wl_info_v7(struct rtw89_dev *rtwdev, u8 rid) } else if (cnt > BTC_TDMA_WLROLE_MAX) { mode = BTC_WLINK_OTHER; } else if (rtwdev->dbcc_en) { - mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, &dbcc_2g_phy); + mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, cnt); /* correct 2G-located PHY band for gnt ctrl */ if (dbcc_2g_phy < RTW89_PHY_NUM) @@ -6525,26 +6885,336 @@ static void _update_wl_info_v7(struct rtw89_dev *rtwdev, u8 rid) _fw_set_drv_info(rtwdev, CXDRVINFO_ROLE); } +static u8 _update_wl_link_mode(struct rtw89_dev *rtwdev, u8 hw_band, u8 type) +{ + struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; + struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info; + u8 mode = BTC_WLINK_NOLINK; + + switch (type) { + case RTW89_MR_WTYPE_NONE: /* no-link */ + mode = BTC_WLINK_NOLINK; + break; + case RTW89_MR_WTYPE_NONMLD: /* Non_MLO 1-role 2+0/0+2 */ + case RTW89_MR_WTYPE_MLD1L1R: /* MLO only-1 link 2+0/0+2 */ + if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) { + mode = BTC_WLINK_5G; + } else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1AP) { + mode = BTC_WLINK_2G_GO; + } else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1CLIENT) { + if (wl->role_info_v8.p2p_2g) + mode = BTC_WLINK_2G_GC; + else + mode = BTC_WLINK_2G_STA; + } + break; + case RTW89_MR_WTYPE_NONMLD_NONMLD: /* Non_MLO 2-role 2+0/0+2 */ + case RTW89_MR_WTYPE_MLD1L1R_NONMLD: /* MLO only-1 link + P2P 2+0/0+2 */ + if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) { + mode = BTC_WLINK_5G; + } else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ_5GHZ || + mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ_6GHZ) { + mode = BTC_WLINK_25G_MCC; + } else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX2_2GHZ) { + mode = BTC_WLINK_2G_MCC; + } else if (mlo_info->ch_type[hw_band] == RTW89_MR_CTX1_2GHZ) { + mode = BTC_WLINK_2G_SCC; + } + break; + case RTW89_MR_WTYPE_MLD2L1R: /* MLO_MLSR 2+0/0+2 */ + if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) + mode = BTC_WLINK_5G; + else if (wl->role_info_v8.p2p_2g) + mode = BTC_WLINK_2G_GC; + else + mode = BTC_WLINK_2G_STA; + break; + case RTW89_MR_WTYPE_MLD2L1R_NONMLD: /* MLO_MLSR + P2P 2+0/0+2 */ + case RTW89_MR_WTYPE_MLD2L2R_NONMLD: /* MLO_MLMR + P2P 1+1/2+2 */ + /* driver may doze 1-link to + * 2G+5G -> TDMA slot switch by E2G/E5G + * 5G only -> TDMA slot switch by E5G + */ + mode = BTC_WLINK_25G_MCC; + break; + case RTW89_MR_WTYPE_MLD2L2R: /* MLO_MLMR 1+1/2+2 */ + if (mlo_info->hwb_rf_band[hw_band] != RTW89_BAND_2G) { + mode = BTC_WLINK_5G; + } else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1AP) { + mode = BTC_WLINK_2G_GO; + } else if (mlo_info->wmode[hw_band] == RTW89_MR_WMODE_1CLIENT) { + if (wl->role_info_v8.p2p_2g) + mode = BTC_WLINK_2G_GC; + else + mode = BTC_WLINK_2G_STA; + } + break; + } + return mode; +} + +static void _update_wl_mlo_info(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; + struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; + struct rtw89_btc_wl_mlo_info *mlo_info = &wl->mlo_info; + struct rtw89_mr_chanctx_info qinfo; + u8 track_band = RTW89_PHY_0; + u8 rf_band = RTW89_BAND_2G; + u8 i, type; + + /* parse MLO info form PHL API for each HW-band */ + for (i = RTW89_MAC_0; i <= RTW89_MAC_1; i++) { + memset(&qinfo, 0, sizeof(qinfo)); + + rtw89_query_mr_chanctx_info(rtwdev, i, &qinfo); + mlo_info->wmode[i] = qinfo.wmode; + mlo_info->ch_type[i] = qinfo.ctxtype; + mlo_info->wtype = qinfo.wtype; + + if (mlo_info->ch_type[i] == RTW89_MR_CTX1_5GHZ || + mlo_info->ch_type[i] == RTW89_MR_CTX2_5GHZ || + mlo_info->ch_type[i] == RTW89_MR_CTX2_5GHZ_6GHZ) + mlo_info->hwb_rf_band[i] = RTW89_BAND_5G; + else if (mlo_info->ch_type[i] == RTW89_MR_CTX1_6GHZ || + mlo_info->ch_type[i] == RTW89_MR_CTX2_6GHZ) + mlo_info->hwb_rf_band[i] = RTW89_BAND_6G; + else /* check if "2G-included" or unknown in each HW-band */ + mlo_info->hwb_rf_band[i] = RTW89_BAND_2G; + } + + mlo_info->link_status = rtwdev->mlo_dbcc_mode; + type = mlo_info->wtype; + + if (mlo_info->wtype == RTW89_MR_WTYPE_MLD1L1R || + mlo_info->wtype == RTW89_MR_WTYPE_MLD2L1R || + mlo_info->wtype == RTW89_MR_WTYPE_MLD2L2R || + mlo_info->wtype == RTW89_MR_WTYPE_MLD1L1R_NONMLD || + mlo_info->wtype == RTW89_MR_WTYPE_MLD2L1R_NONMLD || + mlo_info->wtype == RTW89_MR_WTYPE_MLD2L2R_NONMLD) + mlo_info->mlo_en = 1; + else + mlo_info->mlo_en = 0; + + if (mlo_info->ch_type[RTW89_MAC_0] != RTW89_MR_CTX_NONE && + mlo_info->ch_type[RTW89_MAC_0] != RTW89_MR_CTX_UNKNOWN && + mlo_info->ch_type[RTW89_MAC_1] != RTW89_MR_CTX_NONE && + mlo_info->ch_type[RTW89_MAC_1] != RTW89_MR_CTX_UNKNOWN) + mlo_info->dual_hw_band_en = 1; /* two HW-hand link exist */ + else + mlo_info->dual_hw_band_en = 0; + + if (mlo_info->link_status == MLO_2_PLUS_0_2RF || + mlo_info->link_status == MLO_0_PLUS_2_2RF || + mlo_info->link_status == MLO_2_PLUS_2_2RF) + mlo_info->mlo_adie = 2; + else + mlo_info->mlo_adie = 1; + + switch (mlo_info->link_status) { + default: + case MLO_2_PLUS_0_1RF: /* 2+0 */ + case MLO_2_PLUS_0_2RF: + mlo_info->rf_combination = BTC_MLO_RF_2_PLUS_0; + track_band = RTW89_MAC_0; + rf_band = mlo_info->hwb_rf_band[RTW89_MAC_0]; + mlo_info->path_rf_band[BTC_RF_S0] = rf_band; + mlo_info->path_rf_band[BTC_RF_S1] = rf_band; + + wl_rinfo->pta_req_band = RTW89_MAC_0; + wl_rinfo->dbcc_2g_phy = RTW89_PHY_0; + wl_rinfo->dbcc_en = 0; + break; + case MLO_0_PLUS_2_1RF: /* 0+2 */ + case MLO_0_PLUS_2_2RF: + mlo_info->rf_combination = BTC_MLO_RF_0_PLUS_2; + track_band = RTW89_MAC_1; + rf_band = mlo_info->hwb_rf_band[RTW89_MAC_1]; + mlo_info->path_rf_band[BTC_RF_S0] = rf_band; + mlo_info->path_rf_band[BTC_RF_S1] = rf_band; + + wl_rinfo->pta_req_band = RTW89_MAC_1; + wl_rinfo->dbcc_2g_phy = RTW89_PHY_1; + wl_rinfo->dbcc_en = 0; + break; + case MLO_1_PLUS_1_1RF: /* 1+1 */ + case MLO_1_PLUS_1_2RF: /* 1+1 */ + case MLO_2_PLUS_2_2RF: /* 2+2 */ + case DBCC_LEGACY: /* DBCC 1+1 */ + if (mlo_info->link_status == MLO_2_PLUS_2_2RF) + mlo_info->rf_combination = BTC_MLO_RF_2_PLUS_2; + else + mlo_info->rf_combination = BTC_MLO_RF_1_PLUS_1; + + if (mlo_info->hwb_rf_band[RTW89_MAC_0] == RTW89_BAND_2G) + track_band = RTW89_MAC_0; + else + track_band = RTW89_MAC_1; + + mlo_info->path_rf_band[BTC_RF_S0] = + mlo_info->hwb_rf_band[RTW89_MAC_0]; + mlo_info->path_rf_band[BTC_RF_S1] = + mlo_info->hwb_rf_band[RTW89_MAC_1]; + + /* Check ch count from ch_type @ 2.4G HW-band, and modify type */ + if (mlo_info->ch_type[track_band] == RTW89_MR_CTX1_2GHZ) + type = RTW89_MR_WTYPE_NONMLD; /* only 1-role at 2G */ + else + type = RTW89_MR_WTYPE_NONMLD_NONMLD; + + if (mlo_info->hwb_rf_band[RTW89_MAC_0] == RTW89_BAND_2G) { + wl_rinfo->pta_req_band = RTW89_MAC_0; + wl_rinfo->dbcc_2g_phy = RTW89_PHY_0; + } else { + wl_rinfo->pta_req_band = RTW89_MAC_1; + wl_rinfo->dbcc_2g_phy = RTW89_PHY_1; + } + + if (mlo_info->wmode[RTW89_MAC_0] == RTW89_MR_WMODE_NONE && + mlo_info->wmode[RTW89_MAC_1] == RTW89_MR_WMODE_NONE) + wl_rinfo->dbcc_en = 0; + else + wl_rinfo->dbcc_en = 1; + break; + } + + wl_rinfo->link_mode = _update_wl_link_mode(rtwdev, track_band, type); + + rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(), mode=%s, pta_band=%d", + __func__, id_to_linkmode(wl_rinfo->link_mode), + wl_rinfo->pta_req_band); +} + +static void _update_wl_non_mlo_info(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; + struct rtw89_btc_wl_rlink *rlink = NULL; + struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; + struct rtw89_btc_chdef cid_ch[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; + u8 cid_role[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; + u8 cid_phy[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; + bool b2g = false, b5g = false, outloop = false; + u8 mode = BTC_WLINK_NOLINK; + u8 cnt_2g = 0, cnt_5g = 0; + u8 i, j, cnt = 0; + + for (j = RTW89_PHY_0; j < RTW89_PHY_NUM; j++) { + for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) { + rlink = &wl_rinfo->rlink[i][j]; + + if (!rlink->active || !rlink->connected) + continue; + + if (cnt >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER) { + outloop = true; + break; + } + + cid_ch[cnt] = wl->rlink_info[i][j].chdef; + cid_phy[cnt] = rlink->phy; + cid_role[cnt] = rlink->role; + cnt++; + + if (rlink->rf_band != RTW89_BAND_2G) { + cnt_5g++; + b5g = true; + } else { + cnt_2g++; + b2g = true; + } + } + if (outloop) + break; + } + + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): cnt_2g=%d, cnt_5g=%d\n", __func__, cnt_2g, cnt_5g); + + wl_rinfo->dbcc_en = rtwdev->dbcc_en; + /* Be careful to change the following sequence!! */ + if (cnt == 0) { + mode = BTC_WLINK_NOLINK; + } else if (!b2g && b5g) { + mode = BTC_WLINK_5G; + } else if (wl_rinfo->dbcc_en) { + mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, cnt); + } else if (b2g && b5g) { + mode = BTC_WLINK_25G_MCC; + } else if (!b5g && cnt >= 2) { + if (_chk_role_ch_group(&cid_ch[0], &cid_ch[1])) + mode = BTC_WLINK_2G_SCC; + else + mode = BTC_WLINK_2G_MCC; + } else if (!b5g) { /* cnt_connect = 1 */ + mode = _get_role_link_mode(cid_role[0]); + } + + wl_rinfo->link_mode = mode; +} + +static void _modify_role_link_mode(struct rtw89_dev *rtwdev) +{ + struct rtw89_btc_wl_info *wl = &rtwdev->btc.cx.wl; + struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; + u8 go_cleint_exist = wl->go_client_exist; + u8 link_mode = wl_rinfo->link_mode; + u32 role_map = wl_rinfo->role_map; + u8 noa_exist = wl->noa_exist; + u32 mrole = BTC_WLMROLE_NONE; + + /* if no client_joined, don't care P2P-GO/AP role */ + if (((role_map & BIT(RTW89_WIFI_ROLE_P2P_GO)) || + (role_map & BIT(RTW89_WIFI_ROLE_AP))) && !go_cleint_exist) { + if (link_mode == BTC_WLINK_2G_SCC) { + wl_rinfo->link_mode = BTC_WLINK_2G_STA; + } else if (link_mode == BTC_WLINK_2G_GO || + link_mode == BTC_WLINK_2G_AP) { + wl_rinfo->link_mode = BTC_WLINK_NOLINK; + } + } + + /* Identify 2-Role type */ + if (link_mode == BTC_WLINK_2G_SCC || + link_mode == BTC_WLINK_2G_MCC || + link_mode == BTC_WLINK_25G_MCC || + link_mode == BTC_WLINK_5G) { + if ((role_map & BIT(RTW89_WIFI_ROLE_P2P_GO)) || + (role_map & BIT(RTW89_WIFI_ROLE_AP))) { + if (noa_exist) + mrole = BTC_WLMROLE_STA_GO_NOA; + else + mrole = BTC_WLMROLE_STA_GO; + } else if (role_map & BIT(RTW89_WIFI_ROLE_P2P_CLIENT)) { + if (noa_exist) + mrole = BTC_WLMROLE_STA_GC_NOA; + else + mrole = BTC_WLMROLE_STA_GC; + } else { + mrole = BTC_WLMROLE_STA_STA; + } + } + + wl_rinfo->mrole_type = mrole; + + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s(): link_mode=%s, mrole_type=%d\n", __func__, + id_to_linkmode(wl_rinfo->link_mode), wl_rinfo->mrole_type); +} + static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id, enum btc_role_state state) { + struct rtw89_btc_wl_rlink *rlink = NULL; + struct rtw89_btc_wl_link_info *wl_linfo; struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_wl_info *wl = &btc->cx.wl; - struct rtw89_btc_chdef cid_ch[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER]; struct rtw89_btc_wl_role_info_v8 *wl_rinfo = &wl->role_info_v8; - struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info; - bool client_joined = false, b2g = false, b5g = false; - u8 cid_role[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; - u8 cid_phy[RTW89_BE_BTC_WL_MAX_ROLE_NUMBER] = {}; - u8 dbcc_en = 0, pta_req_band = RTW89_MAC_0; - u8 i, j, cnt = 0, cnt_2g = 0, cnt_5g = 0; - struct rtw89_btc_wl_link_info *wl_linfo; - struct rtw89_btc_wl_rlink *rlink = NULL; - u8 dbcc_2g_phy = RTW89_PHY_0; - u8 mode = BTC_WLINK_NOLINK; - u32 noa_dur = 0; + bool client_joined = false, noa_exist = false, p2p_exist = false; + bool is_5g_hi_channel = false, bg_mode = false, dbcc_en_ori; + u8 i, j, link_mode_ori; + u32 role_map = 0; - if (role_id >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER || rlink_id > RTW89_MAC_1) + if (role_id >= RTW89_BE_BTC_WL_MAX_ROLE_NUMBER || rlink_id >= RTW89_MAC_NUM) return; /* Extract wl->link_info[role_id][rlink_id] to wl->role_info @@ -6554,10 +7224,8 @@ static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id */ wl_linfo = &wl->rlink_info[role_id][rlink_id]; - if (wl_linfo->connected == MLME_LINKING) - return; - rlink = &wl_rinfo->rlink[role_id][rlink_id]; + rlink->role = wl_linfo->role; rlink->active = wl_linfo->active; /* Doze or not */ rlink->pid = wl_linfo->pid; @@ -6573,8 +7241,6 @@ static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id switch (wl_linfo->connected) { case MLME_NO_LINK: rlink->connected = 0; - if (rlink->role == RTW89_WIFI_ROLE_STATION) - btc->dm.leak_ap = 0; break; case MLME_LINKED: rlink->connected = 1; @@ -6583,130 +7249,72 @@ static void _update_wl_info_v8(struct rtw89_dev *rtwdev, u8 role_id, u8 rlink_id return; } - wl->is_5g_hi_channel = false; - wl->bg_mode = false; - wl_rinfo->role_map = 0; - wl_rinfo->p2p_2g = 0; - memset(cid_ch, 0, sizeof(cid_ch)); - - for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) { - for (j = RTW89_MAC_0; j <= RTW89_MAC_1; j++) { + for (j = RTW89_MAC_0; j <= RTW89_MAC_1; j++) { + for (i = 0; i < RTW89_BE_BTC_WL_MAX_ROLE_NUMBER; i++) { rlink = &wl_rinfo->rlink[i][j]; if (!rlink->active || !rlink->connected) continue; - cnt++; - wl_rinfo->role_map |= BIT(rlink->role); - - /* only if client connect for p2p-Go/AP */ - if ((rlink->role == RTW89_WIFI_ROLE_P2P_GO || - rlink->role == RTW89_WIFI_ROLE_AP) && - rlink->client_cnt > 1) - client_joined = true; - - /* Identufy if P2P-Go (GO/GC/AP) exist at 2G band*/ - if (rlink->rf_band == RTW89_BAND_2G && - (client_joined || rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT)) - wl_rinfo->p2p_2g = 1; + role_map |= BIT(rlink->role); /* only one noa-role exist */ if (rlink->noa && rlink->noa_dur > 0) - noa_dur = rlink->noa_dur; + noa_exist = true; /* for WL 5G-Rx interfered with BT issue */ - if (rlink->rf_band == RTW89_BAND_5G && rlink->ch >= 100) - wl->is_5g_hi_channel = 1; - - if ((rlink->mode & BIT(BTC_WL_MODE_11B)) || - (rlink->mode & BIT(BTC_WL_MODE_11G))) - wl->bg_mode = 1; + if (rlink->rf_band == RTW89_BAND_5G) { + if (rlink->ch >= 100) + is_5g_hi_channel = true; - if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) continue; + } - cid_ch[cnt - 1] = wl_linfo->chdef; - cid_phy[cnt - 1] = rlink->phy; - cid_role[cnt - 1] = rlink->role; - - if (rlink->rf_band != RTW89_BAND_2G) { - cnt_5g++; - b5g = true; - } else { - cnt_2g++; - b2g = true; + /* only if client connect for p2p-Go/AP */ + if ((rlink->role == RTW89_WIFI_ROLE_P2P_GO || + rlink->role == RTW89_WIFI_ROLE_AP) && + rlink->client_cnt > 1) { + p2p_exist = true; + client_joined = true; } - } - } - if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) { - rtw89_debug(rtwdev, RTW89_DBG_BTC, - "[BTC] rlink cnt_2g=%d cnt_5g=%d\n", cnt_2g, cnt_5g); - rtw89_warn(rtwdev, "not support MLO feature yet"); - } else { - dbcc_en = rtwdev->dbcc_en; + /* Identify if P2P-Go (GO/GC/AP) exist at 2G band */ + if (rlink->role == RTW89_WIFI_ROLE_P2P_CLIENT) + p2p_exist = true; - /* Be careful to change the following sequence!! */ - if (cnt == 0) { - mode = BTC_WLINK_NOLINK; - } else if (!b2g && b5g) { - mode = BTC_WLINK_5G; - } else if (wl_rinfo->role_map & BIT(RTW89_WIFI_ROLE_NAN)) { - mode = BTC_WLINK_2G_NAN; - } else if (cnt > BTC_TDMA_WLROLE_MAX) { - mode = BTC_WLINK_OTHER; - } else if (dbcc_en) { - mode = _chk_dbcc(rtwdev, cid_ch, cid_phy, cid_role, - &dbcc_2g_phy); - } else if (b2g && b5g && cnt == 2) { - mode = BTC_WLINK_25G_MCC; - } else if (!b5g && cnt == 2) { /* cnt_connect = 2 */ - if (_chk_role_ch_group(&cid_ch[0], &cid_ch[cnt - 1])) - mode = BTC_WLINK_2G_SCC; - else - mode = BTC_WLINK_2G_MCC; - } else if (!b5g && cnt == 1) { /* cnt_connect = 1 */ - mode = _get_role_link_mode(cid_role[0]); + if ((rlink->mode & BIT(BTC_WL_MODE_11B)) || + (rlink->mode & BIT(BTC_WL_MODE_11G))) + bg_mode = true; } } - wl_rinfo->link_mode = mode; - wl_rinfo->connect_cnt = cnt; - if (wl_rinfo->connect_cnt == 0) - wl_rinfo->role_map = BIT(RTW89_WIFI_ROLE_NONE); - _update_role_link_mode(rtwdev, client_joined, noa_dur); + link_mode_ori = wl_rinfo->link_mode; + wl->is_5g_hi_channel = is_5g_hi_channel; + wl->bg_mode = bg_mode; + wl->go_client_exist = client_joined; + wl->noa_exist = noa_exist; + wl_rinfo->p2p_2g = p2p_exist; + wl_rinfo->role_map = role_map; - wl_rinfo->dbcc_2g_phy = dbcc_2g_phy; - if (wl_rinfo->dbcc_en != dbcc_en) { - wl_rinfo->dbcc_en = dbcc_en; - wl_rinfo->dbcc_chg = 1; - btc->cx.cnt_wl[BTC_WCNT_DBCC_CHG]++; + dbcc_en_ori = wl_rinfo->dbcc_en; + + if (rtwdev->chip->para_ver & BTC_FEAT_MLO_SUPPORT) { + /* for MLO-supported, link-mode from driver directly */ + _update_wl_mlo_info(rtwdev); } else { - wl_rinfo->dbcc_chg = 0; + /* for non-MLO-supported, link-mode by BTC */ + _update_wl_non_mlo_info(rtwdev); } - if (wl_rinfo->dbcc_en) { - memset(wl_dinfo, 0, sizeof(struct rtw89_btc_wl_dbcc_info)); + _modify_role_link_mode(rtwdev); - if (mode == BTC_WLINK_5G) { - pta_req_band = RTW89_PHY_0; - wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_5G; - wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_2G; - } else if (wl_rinfo->dbcc_2g_phy == RTW89_PHY_1) { - pta_req_band = RTW89_PHY_1; - wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_5G; - wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_2G; - } else { - pta_req_band = RTW89_PHY_0; - wl_dinfo->op_band[RTW89_PHY_0] = RTW89_BAND_2G; - wl_dinfo->op_band[RTW89_PHY_1] = RTW89_BAND_5G; - } - _update_dbcc_band(rtwdev, RTW89_PHY_0); - _update_dbcc_band(rtwdev, RTW89_PHY_1); - } + if (link_mode_ori != wl_rinfo->link_mode) + wl->link_mode_chg = true; - wl_rinfo->pta_req_band = pta_req_band; - _fw_set_drv_info(rtwdev, CXDRVINFO_ROLE); + if (wl_rinfo->dbcc_en != dbcc_en_ori) { + wl->dbcc_chg = true; + btc->cx.cnt_wl[BTC_WCNT_DBCC_CHG]++; + } } void rtw89_coex_act1_work(struct wiphy *wiphy, struct wiphy_work *work) @@ -6829,12 +7437,33 @@ static void _update_bt_scbd(struct rtw89_dev *rtwdev, bool only_update) bt->rfk_info.map.req = !!(val & BTC_BSCB_RFK_REQ); bt->hi_lna_rx = !!(val & BTC_BSCB_BT_HILNA); bt->link_info.status.map.connect = !!(val & BTC_BSCB_BT_CONNECT); + if (bt->run_patch_code != !!(val & BTC_BSCB_PATCH_CODE)) + status_change = true; bt->run_patch_code = !!(val & BTC_BSCB_PATCH_CODE); if (!only_update && status_change) _run_coex(rtwdev, BTC_RSN_UPDATE_BT_SCBD); } +#define BTC_BTINFO_PWR_LEN 5 +static void _update_bt_txpwr_info(struct rtw89_dev *rtwdev, u8 *buf, u32 len) +{ + struct rtw89_btc_bt_info *bt = &rtwdev->btc.cx.bt; + struct rtw89_btc_bt_link_info *b = &bt->link_info; + + if (len != BTC_BTINFO_PWR_LEN) + return; + + if (!memcmp(bt->txpwr_info, buf, sizeof(bt->txpwr_info))) { + rtw89_debug(rtwdev, RTW89_DBG_BTC, + "[BTC], %s return by info duplicate!\n", __func__); + return; + } + + memcpy(bt->txpwr_info, buf, BTC_BTINFO_MAX); + memcpy(&b->bt_txpwr_desc, &buf[2], sizeof(b->bt_txpwr_desc)); +} + static bool _chk_wl_rfk_request(struct rtw89_dev *rtwdev) { struct rtw89_btc *btc = &rtwdev->btc; @@ -7618,7 +8247,6 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, wlinfo = &wl->link_info[r.pid]; - rlink_id = 0; /* to do */ if (ver->fwlrole == 0) { *wlinfo = r; _update_wl_info(rtwdev); @@ -7632,6 +8260,7 @@ void rtw89_btc_ntfy_role_info(struct rtw89_dev *rtwdev, *wlinfo = r; _update_wl_info_v7(rtwdev, r.pid); } else if (ver->fwlrole == 8) { + rlink_id = rtwvif_link->mac_idx; wlinfo = &wl->rlink_info[r.pid][rlink_id]; *wlinfo = r; link_mode_ori = wl->role_info_v8.link_mode; @@ -7876,7 +8505,11 @@ void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link, rssi = ewma_rssi_read(&rtwsta_link->avg_rssi) >> RSSI_FACTOR; rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], rssi=%d\n", rssi); - link_info = &wl->link_info[port]; + if (btc->ver->fwlrole != 8) + link_info = &wl->link_info[port]; + else + link_info = &wl->rlink_info[port][rtwvif_link->mac_idx]; + link_info->stat.traffic = *stats; link_info_t = &link_info->stat.traffic; @@ -7957,13 +8590,12 @@ void __rtw89_btc_ntfy_wl_sta_iter(struct rtw89_vif_link *rtwvif_link, r1->active_role_v1[port].rx_lvl = stats->rx_tfc_lv; r1->active_role_v1[port].tx_rate = rtwsta_link->ra_report.hw_rate; r1->active_role_v1[port].rx_rate = rtwsta_link->rx_hw_rate; - } else if (ver->fwlrole == 2) { - dm->trx_info.tx_lvl = stats->tx_tfc_lv; - dm->trx_info.rx_lvl = stats->rx_tfc_lv; - dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate; - dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate; } + dm->trx_info.tx_lvl = stats->tx_tfc_lv; + dm->trx_info.rx_lvl = stats->rx_tfc_lv; + dm->trx_info.tx_rate = rtwsta_link->ra_report.hw_rate; + dm->trx_info.rx_rate = rtwsta_link->rx_hw_rate; dm->trx_info.tx_tp = link_info_t->tx_throughput; dm->trx_info.rx_tp = link_info_t->rx_throughput; @@ -8070,6 +8702,8 @@ static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func) return BTF_EVNT_BUF_OVERFLOW; else if (ver->fwc2hfunc == 2) return func; + else if (ver->fwc2hfunc == 3) + return BTF_EVNT_BUF_OVERFLOW; else return BTF_EVNT_MAX; case BTF_EVNT_BUF_OVERFLOW: @@ -8079,11 +8713,20 @@ static u8 rtw89_btc_c2h_get_index_by_ver(struct rtw89_dev *rtwdev, u8 func) return BTF_EVNT_C2H_LOOPBACK; else if (ver->fwc2hfunc == 2) return func; + else if (ver->fwc2hfunc == 3) + return BTF_EVNT_C2H_LOOPBACK; else return BTF_EVNT_MAX; case BTF_EVNT_C2H_LOOPBACK: if (ver->fwc2hfunc == 2) return func; + else if (ver->fwc2hfunc == 3) + return BTF_EVNT_BT_LEAUDIO_INFO; + else + return BTF_EVNT_MAX; + case BTF_EVNT_BT_QUERY_TXPWR: + if (ver->fwc2hfunc == 3) + return func; else return BTF_EVNT_MAX; case BTF_EVNT_MAX: @@ -8146,6 +8789,9 @@ void rtw89_btc_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, case BTF_EVNT_CX_RUNINFO: btc->dm.cnt_dm[BTC_DCNT_CX_RUNINFO]++; break; + case BTF_EVNT_BT_QUERY_TXPWR: + btc->cx.cnt_bt[BTC_BCNT_BTTXPWR_UPDATE]++; + _update_bt_txpwr_info(rtwdev, buf, len); } } @@ -8168,11 +8814,9 @@ static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) if (!(dm->coex_info_map & BTC_COEX_INFO_CX)) return 0; - dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++; - p += scnprintf(p, end - p, - "========== [BTC COEX INFO (%d)] ==========\n", - chip->chip_id); + "\n========== [BTC COEX INFO (%s)] ==========\n", + chip_id_str(chip->chip_id)); ver_main = FIELD_GET(GENMASK(31, 24), RTW89_COEX_VERSION); ver_sub = FIELD_GET(GENMASK(23, 16), RTW89_COEX_VERSION); @@ -8198,8 +8842,8 @@ static int _show_cx_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "BT_FW_coex:%d(%s, desired:%d)\n", bt->ver_info.fw_coex, - (bt->ver_info.fw_coex >= chip->btcx_desired ? - "Match" : "Mismatch"), chip->btcx_desired); + (bt->ver_info.fw_coex >= ver->bt_desired ? + "Match" : "Mismatch"), ver->bt_desired); if (bt->enable.now && bt->ver_info.fw == 0) rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_VER_INFO, true); @@ -8248,65 +8892,52 @@ static int _show_wl_role_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) { struct rtw89_btc *btc = &rtwdev->btc; struct rtw89_btc_wl_link_info *plink = NULL; - struct rtw89_btc_wl_info *wl = &btc->cx.wl; - struct rtw89_btc_wl_dbcc_info *wl_dinfo = &wl->dbcc_info; struct rtw89_traffic_stats *t; char *p = buf, *end = buf + bufsz; - u8 i; - - if (rtwdev->dbcc_en) { - p += scnprintf(p, end - p, - " %-15s : PHY0_band(op:%d/scan:%d/real:%d), ", - "[dbcc_info]", wl_dinfo->op_band[RTW89_PHY_0], - wl_dinfo->scan_band[RTW89_PHY_0], - wl_dinfo->real_band[RTW89_PHY_0]); - p += scnprintf(p, end - p, - "PHY1_band(op:%d/scan:%d/real:%d)\n", - wl_dinfo->op_band[RTW89_PHY_1], - wl_dinfo->scan_band[RTW89_PHY_1], - wl_dinfo->real_band[RTW89_PHY_1]); - } + u8 i, j; - for (i = 0; i < RTW89_PORT_NUM; i++) { - if (btc->ver->fwlrole == 8) - plink = &btc->cx.wl.rlink_info[i][0]; - else - plink = &btc->cx.wl.link_info[i]; + for (i = 0; i < btc->ver->max_role_num; i++) { + for (j = 0; j < RTW89_MAC_NUM; j++) { + if (btc->ver->fwlrole == 8) + plink = &btc->cx.wl.rlink_info[i][j]; + else + plink = &btc->cx.wl.link_info[i]; - if (!plink->active) - continue; + if (!plink->active) + continue; - p += scnprintf(p, end - p, - " [port_%d] : role=%d(phy-%d), connect=%d(client_cnt=%d), mode=%d, center_ch=%d, bw=%d", - plink->pid, (u32)plink->role, plink->phy, - (u32)plink->connected, plink->client_cnt - 1, - (u32)plink->mode, plink->ch, (u32)plink->bw); + p += scnprintf(p, end - p, + " [port_%d] : role=%d(phy-%d), connect=%s(client_cnt=%d), mode=%d, center_ch=%d, bw=%d", + plink->pid, plink->role, plink->phy, + id_to_mlme_state(plink->connected), + plink->client_cnt - 1, plink->mode, + plink->ch, plink->bw); - if (plink->connected == MLME_NO_LINK) - continue; + if (plink->connected == MLME_NO_LINK) + continue; - p += scnprintf(p, end - p, - ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n", - plink->mac_id, plink->tx_time, plink->tx_retry); + p += scnprintf(p, end - p, + ", mac_id=%d, max_tx_time=%dus, max_tx_retry=%d\n", + plink->mac_id, plink->tx_time, plink->tx_retry); - p += scnprintf(p, end - p, - " [port_%d] : rssi=-%ddBm(%d), busy=%d, dir=%s, ", - plink->pid, 110 - plink->stat.rssi, - plink->stat.rssi, plink->busy, - plink->dir == RTW89_TFC_UL ? "UL" : "DL"); + p += scnprintf(p, end - p, + " [port_%d] : rssi=-%ddBm(%d), busy=%d, dir=%s, ", + plink->pid, 110 - plink->stat.rssi, + plink->stat.rssi, plink->busy, + plink->dir == RTW89_TFC_UL ? "UL" : "DL"); - t = &plink->stat.traffic; + t = &plink->stat.traffic; - p += scnprintf(p, end - p, - "tx[rate:%d/busy_level:%d], ", - (u32)t->tx_rate, t->tx_tfc_lv); + p += scnprintf(p, end - p, + "tx[rate:%d/busy_level:%d], ", + t->tx_rate, t->tx_tfc_lv); - p += scnprintf(p, end - p, - "rx[rate:%d/busy_level:%d/drop:%d]\n", - (u32)t->rx_rate, - t->rx_tfc_lv, plink->rx_rate_drop_cnt); + p += scnprintf(p, end - p, + "rx[rate:%d/busy_level:%d/drop:%d]\n", + t->rx_rate, + t->rx_tfc_lv, plink->rx_rate_drop_cnt); + } } - return p - buf; } @@ -8342,8 +8973,8 @@ static int _show_wl_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) else goto out; - p += scnprintf(p, end - p, " %-15s : link_mode:%d, ", "[status]", - mode); + p += scnprintf(p, end - p, " %-15s : link_mode:%s, ", "[status]", + id_to_linkmode(mode)); p += scnprintf(p, end - p, "rf_off:%d, power_save:%d, scan:%s(band:%d/phy_map:0x%x), ", @@ -8433,8 +9064,11 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) struct rtw89_btc_cx *cx = &btc->cx; struct rtw89_btc_bt_info *bt = &cx->bt; struct rtw89_btc_wl_info *wl = &cx->wl; + u32 ver_main = FIELD_GET(GENMASK(31, 24), wl->ver_info.fw_coex); struct rtw89_btc_bt_link_info *bt_linfo = &bt->link_info; union rtw89_btc_module_info *md = &btc->mdinfo; + s8 br_dbm = bt->link_info.bt_txpwr_desc.br_dbm; + s8 le_dbm = bt->link_info.bt_txpwr_desc.le_dbm; char *p = buf, *end = buf + bufsz; u8 *afh = bt_linfo->afh_map; u8 *afh_le = bt_linfo->afh_map_le; @@ -8567,6 +9201,28 @@ static int _show_bt_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "\n"); } + if (ver_main >= 9 && bt_linfo->profile_cnt.now) + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, true); + else + rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_TX_PWR_LVL, false); + + if (cx->cnt_bt[BTC_BCNT_BTTXPWR_UPDATE]) { + p += scnprintf(p, end - p, + " %-15s : br_index:0x%x, le_index:0x%x", + "[bt_txpwr_lvl]", + bt->link_info.bt_txpwr_desc.br_gain_index, + bt->link_info.bt_txpwr_desc.le_gain_index); + p += scnprintf(p, end - p, ", br_dbm:%d dBm", br_dbm); + p += scnprintf(p, end - p, ", le_dbm:%d dBm", le_dbm); + } else { + p += scnprintf(p, end - p, + " %-15s : br_index:NA, le_index:NA, br_dbm:%d dBm[def], le_dbm:%d dBm[def]", + "[bt_txpwr_lvl]", + bt->link_info.bt_txpwr_desc.br_dbm, + bt->link_info.bt_txpwr_desc.le_dbm); + } + p += scnprintf(p, end - p, "\n"); + if (bt_linfo->profile_cnt.now || bt_linfo->status.map.ble_connect) rtw89_btc_fw_en_rpt(rtwdev, RPT_EN_BT_AFH_MAP, true); else @@ -9142,7 +9798,6 @@ static int _show_fbtc_slots(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) if (i % 5 == 4) p += scnprintf(p, end - p, "\n"); } - p += scnprintf(p, end - p, "\n"); return p - buf; } @@ -9714,7 +10369,7 @@ static int _show_fbtc_cysta_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz return 0; pcysta = &pfwinfo->rpt_fbtc_cysta.finfo.v7; - p += scnprintf(p, end - p, "\n\r %-15s : cycle:%d", "[slot_stat]", + p += scnprintf(p, end - p, "\n %-15s : cycle:%d", "[slot_stat]", le16_to_cpu(pcysta->cycles)); for (i = 0; i < CXST_MAX; i++) { @@ -9862,7 +10517,7 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) ns = &pfwinfo->rpt_fbtc_nullsta.finfo; if (ver->fcxnullsta == 1) { for (i = 0; i < 2; i++) { - p += scnprintf(p, end - p, " %-15s : ", "[NULL-STA]"); + p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]"); p += scnprintf(p, end - p, "null-%d", i); p += scnprintf(p, end - p, "[ok:%d/", le32_to_cpu(ns->v1.result[i][1])); @@ -9875,13 +10530,13 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "avg_t:%d.%03d/", le32_to_cpu(ns->v1.avg_t[i]) / 1000, le32_to_cpu(ns->v1.avg_t[i]) % 1000); - p += scnprintf(p, end - p, "max_t:%d.%03d]\n", + p += scnprintf(p, end - p, "max_t:%d.%03d]", le32_to_cpu(ns->v1.max_t[i]) / 1000, le32_to_cpu(ns->v1.max_t[i]) % 1000); } } else if (ver->fcxnullsta == 7) { for (i = 0; i < 2; i++) { - p += scnprintf(p, end - p, " %-15s : ", "[NULL-STA]"); + p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]"); p += scnprintf(p, end - p, "null-%d", i); p += scnprintf(p, end - p, "[Tx:%d/", le32_to_cpu(ns->v7.result[i][4])); @@ -9896,13 +10551,13 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "avg_t:%d.%03d/", le32_to_cpu(ns->v7.tavg[i]) / 1000, le32_to_cpu(ns->v7.tavg[i]) % 1000); - p += scnprintf(p, end - p, "max_t:%d.%03d]\n", + p += scnprintf(p, end - p, "max_t:%d.%03d]", le32_to_cpu(ns->v7.tmax[i]) / 1000, le32_to_cpu(ns->v7.tmax[i]) % 1000); } } else { for (i = 0; i < 2; i++) { - p += scnprintf(p, end - p, " %-15s : ", "[NULL-STA]"); + p += scnprintf(p, end - p, " %-15s : ", "\n[NULL-STA]"); p += scnprintf(p, end - p, "null-%d", i); p += scnprintf(p, end - p, "[Tx:%d/", le32_to_cpu(ns->v2.result[i][4])); @@ -9917,7 +10572,7 @@ static int _show_fbtc_nullsta(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) p += scnprintf(p, end - p, "avg_t:%d.%03d/", le32_to_cpu(ns->v2.avg_t[i]) / 1000, le32_to_cpu(ns->v2.avg_t[i]) % 1000); - p += scnprintf(p, end - p, "max_t:%d.%03d]\n", + p += scnprintf(p, end - p, "max_t:%d.%03d]", le32_to_cpu(ns->v2.max_t[i]) / 1000, le32_to_cpu(ns->v2.max_t[i]) % 1000); } @@ -10159,7 +10814,6 @@ static int _show_gpio_dbg(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) rtw89_debug(rtwdev, RTW89_DBG_BTC, "[BTC], %s(): stop due rpt_fbtc_gpio_dbg.cinfo\n", __func__); - p += scnprintf(p, end - p, "\n"); goto out; } @@ -10432,7 +11086,6 @@ static int _show_mreg_v7(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) id_to_regtype(type), offset, val); cnt++; } - p += scnprintf(p, end - p, "\n"); out: return p - buf; @@ -11132,37 +11785,39 @@ static int _show_summary_v8(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) ssize_t rtw89_btc_dump_info(struct rtw89_dev *rtwdev, char *buf, size_t bufsz) { - struct rtw89_fw_suit *fw_suit = &rtwdev->fw.normal; struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_ver *fwsubver = &btc->fwinfo.fw_subver; const struct rtw89_btc_ver *ver = btc->ver; - struct rtw89_btc_cx *cx = &btc->cx; - struct rtw89_btc_bt_info *bt = &cx->bt; + struct rtw89_btc_dm *dm = &btc->dm; char *p = buf, *end = buf + bufsz; + dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO]++; + + p += scnprintf(p, end - p, + "\n\n\n** Page:%3d/RunCNT:%3d **", + dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO], + dm->cnt_dm[BTC_DCNT_RUN]); p += scnprintf(p, end - p, - "=========================================\n"); + "\n========== [BTC FEATURE SUB VER] =========="); p += scnprintf(p, end - p, - "WL FW / BT FW %d.%d.%d.%d / NA\n", - fw_suit->major_ver, fw_suit->minor_ver, - fw_suit->sub_ver, fw_suit->sub_idex); - p += scnprintf(p, end - p, "manual %d\n", - btc->manual_ctrl); - + "\n %-15s : fcxbtcrpt[%d/%d], fcxtdma[%d/%d], fcxslots[%d/%d], fcxcysta[%d/%d]", + "[FW/DRV]", fwsubver->fcxbtcrpt, ver->fcxbtcrpt, + fwsubver->fcxtdma, ver->fcxtdma, fwsubver->fcxslots, + ver->fcxslots, fwsubver->fcxcysta, ver->fcxcysta); p += scnprintf(p, end - p, - "=========================================\n"); - + "\n %-15s : fcxstep[%d/%d], fcxnullsta[%d/%d], fcxmreg[%d/%d], fcxgpiodbg[%d/%d]", + "[FW/DRV]", fwsubver->fcxstep, ver->fcxstep, + fwsubver->fcxnullsta, ver->fcxnullsta, fwsubver->fcxmreg, + ver->fcxmreg, fwsubver->fcxgpiodbg, ver->fcxgpiodbg); p += scnprintf(p, end - p, - "\n\r %-15s : raw_data[%02x %02x %02x %02x %02x %02x] (type:%s/cnt:%d/same:%d)", - "[bt_info]", - bt->raw_info[2], bt->raw_info[3], - bt->raw_info[4], bt->raw_info[5], - bt->raw_info[6], bt->raw_info[7], - bt->raw_info[0] == BTC_BTINFO_AUTO ? "auto" : "reply", - cx->cnt_bt[BTC_BCNT_INFOUPDATE], - cx->cnt_bt[BTC_BCNT_INFOSAME]); - + "\n %-15s : fcxbtver[%d/%d], fcxbtscan[%d/%d], fcxbtafh[%d/%d], fcxbtdevinfo[%d/%d]", + "[FW/DRV]", fwsubver->fcxbtver, ver->fcxbtver, + fwsubver->fcxbtscan, ver->fcxbtscan, fwsubver->fcxbtafh, + ver->fcxbtafh, fwsubver->fcxbtdevinfo, ver->fcxbtdevinfo); p += scnprintf(p, end - p, - "\n=========================================\n"); + "\n %-15s : fcxosi[%d/%d], fcxmlo[%d/%d],", + "[FW/DRV]", fwsubver->fcxosi, ver->fcxosi, + fwsubver->fcxmlo, ver->fcxmlo); p += _show_cx_info(rtwdev, p, end - p); p += _show_wl_info(rtwdev, p, end - p); diff --git a/drivers/net/wireless/realtek/rtw89/coex.h b/drivers/net/wireless/realtek/rtw89/coex.h index e3a1fcd79620..ea2c1e5d70f5 100644 --- a/drivers/net/wireless/realtek/rtw89/coex.h +++ b/drivers/net/wireless/realtek/rtw89/coex.h @@ -224,6 +224,13 @@ enum btc_wl_mode { BTC_WL_MODE_NUM, }; +enum btc_mlo_rf_combin { + BTC_MLO_RF_2_PLUS_0 = 0, + BTC_MLO_RF_0_PLUS_2 = 1, + BTC_MLO_RF_1_PLUS_1 = 2, + BTC_MLO_RF_2_PLUS_2 = 3, +}; + enum btc_wl_gpio_debug { BTC_DBG_GNT_BT = 0, BTC_DBG_GNT_WL = 1, diff --git a/drivers/net/wireless/realtek/rtw89/core.c b/drivers/net/wireless/realtek/rtw89/core.c index 49447668cbf3..57590f5577a3 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -204,6 +204,7 @@ static const struct ieee80211_iface_combination rtw89_iface_combs[] = { }; static const u8 rtw89_ext_capa_sta[] = { + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, }; @@ -318,15 +319,25 @@ static const struct ieee80211_supported_band rtw89_sband_6ghz = { .n_bitrates = ARRAY_SIZE(rtw89_bitrates) - 4, }; +static void __rtw89_traffic_stats_accu(struct rtw89_traffic_stats *stats, + struct sk_buff *skb, bool tx) +{ + if (tx) { + stats->tx_cnt++; + stats->tx_unicast += skb->len; + } else { + stats->rx_cnt++; + stats->rx_unicast += skb->len; + } +} + static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev, - struct rtw89_traffic_stats *stats, - struct sk_buff *skb, bool tx) + struct rtw89_vif *rtwvif, + struct sk_buff *skb, + bool accu_dev, bool tx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - if (tx && ieee80211_is_assoc_req(hdr->frame_control)) - rtw89_wow_parse_akm(rtwdev, skb); - if (!ieee80211_is_data(hdr->frame_control)) return; @@ -334,12 +345,12 @@ static void rtw89_traffic_stats_accu(struct rtw89_dev *rtwdev, is_multicast_ether_addr(hdr->addr1)) return; - if (tx) { - stats->tx_cnt++; - stats->tx_unicast += skb->len; - } else { - stats->rx_cnt++; - stats->rx_unicast += skb->len; + if (accu_dev) + __rtw89_traffic_stats_accu(&rtwdev->stats, skb, tx); + + if (rtwvif) { + __rtw89_traffic_stats_accu(&rtwvif->stats, skb, tx); + __rtw89_traffic_stats_accu(&rtwvif->stats_ps, skb, tx); } } @@ -983,13 +994,25 @@ rtw89_core_tx_wake(struct rtw89_dev *rtwdev, if (!RTW89_CHK_FW_FEATURE(TX_WAKE, &rtwdev->fw)) return; - if (!test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) - return; + switch (chip->chip_id) { + case RTL8852BT: + if (test_bit(RTW89_FLAG_LEISURE_PS, rtwdev->flags)) + goto notify; + break; + case RTL8852C: + if (test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags)) + goto notify; + break; + default: + if (test_bit(RTW89_FLAG_LOW_POWER_MODE, rtwdev->flags) && + tx_req->tx_type == RTW89_CORE_TX_TYPE_MGMT) + goto notify; + break; + } - if (chip->chip_id != RTL8852C && - tx_req->tx_type != RTW89_CORE_TX_TYPE_MGMT) - return; + return; +notify: rtw89_mac_notify_wake(rtwdev); } @@ -1149,8 +1172,8 @@ static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, tx_req.rtwsta_link = rtwsta_link; tx_req.desc_info.sw_mld = sw_mld; - rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, true); - rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, true); + rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, true, true); + rtw89_wow_parse_akm(rtwdev, skb); rtw89_core_tx_update_desc_info(rtwdev, &tx_req); rtw89_core_tx_wake(rtwdev, &tx_req); @@ -1722,7 +1745,7 @@ static u16 rtw89_core_get_phy_status_ie_len(struct rtw89_dev *rtwdev, }, [RTW89_CHIP_BE] = { 32, 40, 24, 24, 8, 8, 8, 8, VAR_LEN, 8, VAR_LEN, 176, VAR_LEN, - VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 16, 24, VAR_LEN, + VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, VAR_LEN, 88, 56, VAR_LEN, VAR_LEN, VAR_LEN, 0, 24, 24, 24, 24, 32, 32, 32, 32 }, }; @@ -1917,6 +1940,8 @@ static int rtw89_core_rx_parse_phy_sts(struct rtw89_dev *rtwdev, return -EINVAL; pos = phy_ppdu->buf + PHY_STS_HDR_LEN; + if (phy_ppdu->hdr_2_en) + pos += PHY_STS_HDR_LEN; end = phy_ppdu->buf + phy_ppdu->len; while (pos < end) { const struct rtw89_phy_sts_iehdr *iehdr = pos; @@ -2158,6 +2183,11 @@ static void rtw89_core_cancel_6ghz_probe_tx(struct rtw89_dev *rtwdev, if (rx_status->band != NL80211_BAND_6GHZ) return; + if (unlikely(!(rtwdev->chip->support_bands & BIT(NL80211_BAND_6GHZ)))) { + rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "invalid rx on unsupported 6 GHz\n"); + return; + } + ssid_ie = cfg80211_find_ie(WLAN_EID_SSID, ies, skb->len); list_for_each_entry(info, &pkt_list[NL80211_BAND_6GHZ], list) { @@ -2259,7 +2289,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, if (desc_info->data_rate < RTW89_HW_RATE_NR) pkt_stat->rx_rate_cnt[desc_info->data_rate]++; - rtw89_traffic_stats_accu(rtwdev, &rtwvif->stats, skb, false); + rtw89_traffic_stats_accu(rtwdev, rtwvif, skb, false, false); out: rcu_read_unlock(); @@ -2272,7 +2302,7 @@ static void rtw89_core_rx_stats(struct rtw89_dev *rtwdev, { struct rtw89_vif_rx_stats_iter_data iter_data; - rtw89_traffic_stats_accu(rtwdev, &rtwdev->stats, skb, false); + rtw89_traffic_stats_accu(rtwdev, NULL, skb, true, false); iter_data.rtwdev = rtwdev; iter_data.phy_ppdu = phy_ppdu; @@ -2477,6 +2507,41 @@ static void rtw89_core_update_rx_freq_from_ie(struct rtw89_dev *rtwdev, rx_status->freq = ieee80211_channel_to_frequency(chan, rx_status->band); } +static void rtw89_core_correct_mcc_chan(struct rtw89_dev *rtwdev, + struct rtw89_rx_desc_info *desc_info, + struct ieee80211_rx_status *rx_status, + struct rtw89_rx_phy_ppdu *phy_ppdu) +{ + enum rtw89_chip_gen chip_gen = rtwdev->chip->chip_gen; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_sta_link *rtwsta_link; + const struct rtw89_chan *chan; + u8 mac_id = desc_info->mac_id; + enum rtw89_entity_mode mode; + enum nl80211_band band; + + mode = rtw89_get_entity_mode(rtwdev); + if (likely(mode != RTW89_ENTITY_MODE_MCC)) + return; + + if (chip_gen == RTW89_CHIP_BE && phy_ppdu) + mac_id = phy_ppdu->mac_id; + + rcu_read_lock(); + + rtwsta_link = rtw89_assoc_link_rcu_dereference(rtwdev, mac_id); + if (!rtwsta_link) + goto out; + + rtwvif_link = rtwsta_link->rtwvif_link; + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + band = rtw89_hw_to_nl80211_band(chan->band_type); + rx_status->freq = ieee80211_channel_to_frequency(chan->primary_channel, band); + +out: + rcu_read_unlock(); +} + static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct rtw89_rx_desc_info *desc_info, @@ -2495,6 +2560,7 @@ static void rtw89_core_rx_to_mac80211(struct rtw89_dev *rtwdev, rtw89_core_update_radiotap(rtwdev, skb_ppdu, rx_status); rtw89_core_validate_rx_signal(rx_status); rtw89_core_update_rx_freq_from_ie(rtwdev, skb_ppdu, rx_status); + rtw89_core_correct_mcc_chan(rtwdev, desc_info, rx_status, phy_ppdu); /* In low power mode, it does RX in thread context. */ local_bh_disable(); @@ -2752,9 +2818,11 @@ static void rtw89_core_stats_sta_rx_status(struct rtw89_dev *rtwdev, } static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev, + struct sk_buff *skb, struct rtw89_rx_desc_info *desc_info, struct ieee80211_rx_status *rx_status) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; const struct cfg80211_chan_def *chandef = rtw89_chandef_get(rtwdev, RTW89_CHANCTX_0); u16 data_rate; @@ -2766,6 +2834,10 @@ static void rtw89_core_update_rx_status(struct rtw89_dev *rtwdev, rx_status->freq = chandef->chan->center_freq; rx_status->band = chandef->chan->band; + if (ieee80211_is_beacon(hdr->frame_control) || + ieee80211_is_probe_resp(hdr->frame_control)) + rx_status->boottime_ns = ktime_get_boottime_ns(); + if (rtwdev->scanning && RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD, &rtwdev->fw)) { const struct rtw89_chan *cur = rtw89_scan_chan_get(rtwdev); @@ -2834,6 +2906,9 @@ static enum rtw89_ps_mode rtw89_update_ps_mode(struct rtw89_dev *rtwdev) { const struct rtw89_chip_info *chip = rtwdev->chip; + if (rtwdev->hci.type != RTW89_HCI_TYPE_PCIE) + return RTW89_PS_MODE_NONE; + if (rtw89_disable_ps_mode || !chip->ps_mode_supported || RTW89_CHK_FW_FEATURE(NO_DEEP_PS, &rtwdev->fw)) return RTW89_PS_MODE_NONE; @@ -2922,7 +2997,7 @@ void rtw89_core_rx(struct rtw89_dev *rtwdev, rx_status = IEEE80211_SKB_RXCB(skb); memset(rx_status, 0, sizeof(*rx_status)); - rtw89_core_update_rx_status(rtwdev, desc_info, rx_status); + rtw89_core_update_rx_status(rtwdev, skb, desc_info, rx_status); rtw89_core_rx_pkt_hdl(rtwdev, skb, desc_info); if (desc_info->long_rxdesc && BIT(desc_info->frame_type) & PPDU_FILTER_BITMAP) @@ -3330,8 +3405,8 @@ static void rtw89_core_handle_sta_pending_tx(struct rtw89_dev *rtwdev, rtwvif_link); } -static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, - struct rtw89_vif_link *rtwvif_link, bool qos, bool ps) +int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + bool qos, bool ps, int timeout) { struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); int link_id = ieee80211_vif_is_mld(vif) ? rtwvif_link->link_id : -1; @@ -3379,7 +3454,7 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, rcu_read_unlock(); return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, qsel, - RTW89_ROC_TX_TIMEOUT); + timeout); out: rcu_read_unlock(); @@ -3416,7 +3491,8 @@ void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) pause_parm.trigger = rtwvif_link; rtw89_chanctx_pause(rtwdev, &pause_parm); - ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true); + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, true, + RTW89_ROC_TX_TIMEOUT); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, "roc send null-1 failed: %d\n", ret); @@ -3476,7 +3552,8 @@ void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) roc->state = RTW89_ROC_IDLE; rtw89_config_roc_chandef(rtwdev, rtwvif_link, NULL); rtw89_chanctx_proceed(rtwdev, NULL); - ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false); + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, true, false, + RTW89_ROC_TX_TIMEOUT); if (ret) rtw89_debug(rtwdev, RTW89_DBG_TXRX, "roc send null-0 failed: %d\n", ret); @@ -3515,9 +3592,22 @@ void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work) } static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev, - u32 throughput, u64 cnt) + u32 throughput, u64 cnt, + enum rtw89_tfc_interval interval) { - if (cnt < 100) + u64 cnt_level; + + switch (interval) { + default: + case RTW89_TFC_INTERVAL_100MS: + cnt_level = 5; + break; + case RTW89_TFC_INTERVAL_2SEC: + cnt_level = 100; + break; + } + + if (cnt < cnt_level) return RTW89_TFC_IDLE; if (throughput > 50) return RTW89_TFC_HIGH; @@ -3529,13 +3619,14 @@ static enum rtw89_tfc_lv rtw89_get_traffic_level(struct rtw89_dev *rtwdev, } static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, - struct rtw89_traffic_stats *stats) + struct rtw89_traffic_stats *stats, + enum rtw89_tfc_interval interval) { enum rtw89_tfc_lv tx_tfc_lv = stats->tx_tfc_lv; enum rtw89_tfc_lv rx_tfc_lv = stats->rx_tfc_lv; - stats->tx_throughput_raw = (u32)(stats->tx_unicast >> RTW89_TP_SHIFT); - stats->rx_throughput_raw = (u32)(stats->rx_unicast >> RTW89_TP_SHIFT); + stats->tx_throughput_raw = rtw89_bytes_to_mbps(stats->tx_unicast, interval); + stats->rx_throughput_raw = rtw89_bytes_to_mbps(stats->rx_unicast, interval); ewma_tp_add(&stats->tx_ewma_tp, stats->tx_throughput_raw); ewma_tp_add(&stats->rx_ewma_tp, stats->rx_throughput_raw); @@ -3543,9 +3634,9 @@ static bool rtw89_traffic_stats_calc(struct rtw89_dev *rtwdev, stats->tx_throughput = ewma_tp_read(&stats->tx_ewma_tp); stats->rx_throughput = ewma_tp_read(&stats->rx_ewma_tp); stats->tx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->tx_throughput, - stats->tx_cnt); + stats->tx_cnt, interval); stats->rx_tfc_lv = rtw89_get_traffic_level(rtwdev, stats->rx_throughput, - stats->rx_cnt); + stats->rx_cnt, interval); stats->tx_avg_len = stats->tx_cnt ? DIV_ROUND_DOWN_ULL(stats->tx_unicast, stats->tx_cnt) : 0; stats->rx_avg_len = stats->rx_cnt ? @@ -3571,10 +3662,12 @@ static bool rtw89_traffic_stats_track(struct rtw89_dev *rtwdev) unsigned int link_id; bool tfc_changed; - tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats); + tfc_changed = rtw89_traffic_stats_calc(rtwdev, &rtwdev->stats, + RTW89_TFC_INTERVAL_2SEC); rtw89_for_each_rtwvif(rtwdev, rtwvif) { - rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats); + rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats, + RTW89_TFC_INTERVAL_2SEC); rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) rtw89_fw_h2c_tp_offload(rtwdev, rtwvif_link); @@ -3594,8 +3687,8 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev) if (rtwvif->offchan) continue; - if (rtwvif->stats.tx_tfc_lv != RTW89_TFC_IDLE || - rtwvif->stats.rx_tfc_lv != RTW89_TFC_IDLE) + if (rtwvif->stats_ps.tx_tfc_lv >= RTW89_TFC_MID || + rtwvif->stats_ps.rx_tfc_lv >= RTW89_TFC_MID) continue; vif = rtwvif_to_vif(rtwvif); @@ -3734,6 +3827,34 @@ static void rtw89_core_mlo_track(struct rtw89_dev *rtwdev) } } +static void rtw89_track_ps_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + track_ps_work.work); + struct rtw89_vif *rtwvif; + + lockdep_assert_wiphy(wiphy); + + if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags)) + return; + + if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) + return; + + wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); + + rtw89_for_each_rtwvif(rtwdev, rtwvif) + rtw89_traffic_stats_calc(rtwdev, &rtwvif->stats_ps, + RTW89_TFC_INTERVAL_100MS); + + if (rtwdev->scanning) + return; + + if (rtwdev->lps_enabled && !rtwdev->btc.lps) + rtw89_enter_lps_track(rtwdev); +} + static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work) { struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, @@ -3742,7 +3863,7 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work) lockdep_assert_wiphy(wiphy); - if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags)) + if (test_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags)) return; if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) @@ -3967,6 +4088,13 @@ int rtw89_core_sta_link_add(struct rtw89_dev *rtwdev, rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_CONN_START); rtw89_chip_rfk_channel(rtwdev, rtwvif_link); + + if (vif->p2p) { + rtw89_mac_get_tx_retry_limit(rtwdev, rtwsta_link, + &rtwsta_link->tx_retry); + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, 60); + } + rtw89_phy_dig_suspend(rtwdev); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { ret = rtw89_mac_set_macid_pause(rtwdev, rtwsta_link->mac_id, false); if (ret) { @@ -4151,6 +4279,11 @@ int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, } rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); + + if (vif->p2p) + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, + rtwsta_link->tx_retry); + rtw89_phy_dig_resume(rtwdev, false); } rtw89_assoc_link_set(rtwsta_link); @@ -4169,6 +4302,10 @@ int rtw89_core_sta_link_remove(struct rtw89_dev *rtwdev, rtw89_reg_6ghz_recalc(rtwdev, rtwvif_link, false); rtw89_btc_ntfy_role_info(rtwdev, rtwvif_link, rtwsta_link, BTC_ROLE_MSTS_STA_DIS_CONN); + + if (vif->p2p) + rtw89_mac_set_tx_retry_limit(rtwdev, rtwsta_link, false, + rtwsta_link->tx_retry); } else if (vif->type == NL80211_IFTYPE_AP || sta->tdls) { ret = rtw89_fw_h2c_role_maintain(rtwdev, rtwvif_link, rtwsta_link, RTW89_ROLE_REMOVE); @@ -4655,6 +4792,43 @@ void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); } +void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_vif_link *rtwvif_link = + container_of(work, struct rtw89_vif_link, csa_beacon_work.work); + struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; + struct ieee80211_vif *vif = rtwvif_to_vif(rtwvif); + struct rtw89_dev *rtwdev = rtwvif->rtwdev; + struct ieee80211_bss_conf *bss_conf; + unsigned int delay; + + lockdep_assert_wiphy(wiphy); + + if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE) + return; + + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (!bss_conf->csa_active) { + rcu_read_unlock(); + return; + } + + delay = ieee80211_tu_to_usec(bss_conf->beacon_int); + + rcu_read_unlock(); + + if (!ieee80211_beacon_cntdwn_is_complete(vif, rtwvif_link->link_id)) { + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); + + wiphy_delayed_work_queue(wiphy, &rtwvif_link->csa_beacon_work, + usecs_to_jiffies(delay)); + } else { + ieee80211_csa_finish(vif, rtwvif_link->link_id); + } +} + int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond) { struct completion *cmpl = &wait->completion; @@ -4769,6 +4943,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); set_bit(RTW89_FLAG_RUNNING, rtwdev->flags); @@ -4803,11 +4979,13 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) wiphy_work_cancel(wiphy, &btc->icmp_notify_work); cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->chanctx_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_act1_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_bt_devinfo_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->coex_rfk_chk_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->cfo_track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->mcc_prepare_done_work); cancel_delayed_work_sync(&rtwdev->forbid_ba_work); wiphy_delayed_work_cancel(wiphy, &rtwdev->antdiv_work); @@ -5029,11 +5207,13 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_WORK(&rtwdev->txq_work, rtw89_core_txq_work); INIT_DELAYED_WORK(&rtwdev->txq_reinvoke_work, rtw89_core_txq_reinvoke_work); wiphy_delayed_work_init(&rtwdev->track_work, rtw89_track_work); + wiphy_delayed_work_init(&rtwdev->track_ps_work, rtw89_track_ps_work); wiphy_delayed_work_init(&rtwdev->chanctx_work, rtw89_chanctx_work); wiphy_delayed_work_init(&rtwdev->coex_act1_work, rtw89_coex_act1_work); wiphy_delayed_work_init(&rtwdev->coex_bt_devinfo_work, rtw89_coex_bt_devinfo_work); wiphy_delayed_work_init(&rtwdev->coex_rfk_chk_work, rtw89_coex_rfk_chk_work); wiphy_delayed_work_init(&rtwdev->cfo_track_work, rtw89_phy_cfo_track_work); + wiphy_delayed_work_init(&rtwdev->mcc_prepare_done_work, rtw89_mcc_prepare_done_work); INIT_DELAYED_WORK(&rtwdev->forbid_ba_work, rtw89_forbid_ba_work); wiphy_delayed_work_init(&rtwdev->antdiv_work, rtw89_phy_antdiv_work); rtwdev->txq_wq = alloc_workqueue("rtw89_tx_wq", WQ_UNBOUND | WQ_HIGHPRI, 0); @@ -5127,6 +5307,7 @@ void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, { struct ieee80211_bss_conf *bss_conf; struct rtw89_bb_ctx *bb; + int ret; if (!rtwvif_link) return; @@ -5146,6 +5327,14 @@ void rtw89_core_scan_complete(struct rtw89_dev *rtwdev, rtw89_phy_config_edcca(rtwdev, bb, false); rtw89_tas_scan(rtwdev, false); + if (hw_scan) { + ret = rtw89_core_send_nullfunc(rtwdev, rtwvif_link, false, false, + RTW89_SCAN_NULL_TIMEOUT); + if (ret) + rtw89_debug(rtwdev, RTW89_DBG_TXRX, + "scan send null-0 failed: %d\n", ret); + } + rtwdev->scanning = false; rtw89_for_each_active_bb(rtwdev, bb) bb->dig.bypass_dig = true; @@ -5239,7 +5428,8 @@ int rtw89_core_mlsr_switch(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, if (unlikely(!ieee80211_vif_is_mld(vif))) return -EOPNOTSUPP; - if (unlikely(!(usable_links & BIT(link_id)))) { + if (unlikely(link_id >= IEEE80211_MLD_MAX_NUM_LINKS || + !(usable_links & BIT(link_id)))) { rtw89_warn(rtwdev, "%s: link id %u is not usable\n", __func__, link_id); return -ENOLINK; @@ -5473,6 +5663,9 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) int ret; int tx_headroom = IEEE80211_HT_CTL_LEN; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + tx_headroom += chip->txwd_body_size + chip->txwd_info_size; + hw->vif_data_size = struct_size_t(struct rtw89_vif, links_inst, n); hw->sta_data_size = struct_size_t(struct rtw89_sta, links_inst, n); hw->txq_data_size = sizeof(struct rtw89_txq); @@ -5504,6 +5697,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ieee80211_hw_set(hw, WANT_MONITOR_VIF); + ieee80211_hw_set(hw, CHANCTX_STA_CSA); if (chip->support_bandwidths & BIT(NL80211_CHAN_WIDTH_160)) ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); @@ -5530,6 +5724,7 @@ static int rtw89_core_register_hw(struct rtw89_dev *rtwdev) hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_TDLS_EXTERNAL_SETUP | WIPHY_FLAG_AP_UAPSD | + WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_SUPPORTS_EXT_KEK_KCK; if (!chip->support_rnr) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 1c8f3b9b7c4c..43e10278e14d 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -40,6 +40,7 @@ extern const struct ieee80211_ops rtw89_ops; #define BYPASS_CR_DATA 0xbabecafe #define RTW89_TRACK_WORK_PERIOD round_jiffies_relative(HZ * 2) +#define RTW89_TRACK_PS_WORK_PERIOD msecs_to_jiffies(100) #define RTW89_FORBID_BA_TIMER round_jiffies_relative(HZ * 4) #define CFO_TRACK_MAX_USER 64 #define MAX_RSSI 110 @@ -130,6 +131,17 @@ enum rtw89_hci_type { RTW89_HCI_TYPE_PCIE, RTW89_HCI_TYPE_USB, RTW89_HCI_TYPE_SDIO, + + RTW89_HCI_TYPE_NUM, +}; + +enum rtw89_hci_dle_type { + RTW89_HCI_DLE_TYPE_PCIE, + RTW89_HCI_DLE_TYPE_USB2, + RTW89_HCI_DLE_TYPE_USB3, + RTW89_HCI_DLE_TYPE_SDIO, + + RTW89_HCI_DLE_TYPE_NUM, }; enum rtw89_core_chip_id { @@ -1205,7 +1217,7 @@ struct rtw89_mac_ax_gnt { struct rtw89_mac_ax_wl_act { u8 wlan_act_en; u8 wlan_act; -}; +} __packed; #define RTW89_MAC_AX_COEX_GNT_NR 2 struct rtw89_mac_ax_coex_gnt { @@ -1322,6 +1334,7 @@ enum rtw89_btc_bt_state_cnt { BTC_BCNT_POLUT_NOW, BTC_BCNT_POLUT_DIFF, BTC_BCNT_RATECHG, + BTC_BCNT_BTTXPWR_UPDATE, BTC_BCNT_NUM, }; @@ -1380,6 +1393,11 @@ struct rtw89_btc_wl_smap { u32 emlsr: 1; }; +enum rtw89_tfc_interval { + RTW89_TFC_INTERVAL_100MS, + RTW89_TFC_INTERVAL_2SEC, +}; + enum rtw89_tfc_lv { RTW89_TFC_IDLE, RTW89_TFC_ULTRA_LOW, @@ -1388,7 +1406,6 @@ enum rtw89_tfc_lv { RTW89_TFC_HIGH, }; -#define RTW89_TP_SHIFT 18 /* bytes/2s --> Mbps */ DECLARE_EWMA(tp, 10, 2); struct rtw89_traffic_stats { @@ -1557,6 +1574,25 @@ struct rtw89_btc_wl_dbcc_info { u8 role[RTW89_PHY_NUM]; /* role in each phy */ }; +struct rtw89_btc_wl_mlo_info { + u8 wmode[RTW89_PHY_NUM]; /* enum phl_mr_wmode */ + u8 ch_type[RTW89_PHY_NUM]; /* enum phl_mr_ch_type */ + u8 hwb_rf_band[RTW89_PHY_NUM]; /* enum band_type, RF-band for HW-band */ + u8 path_rf_band[RTW89_PHY_NUM]; /* enum band_type, RF-band for PHY0/1 */ + + u8 wtype; /* enum phl_mr_wtype */ + u8 mrcx_mode; + u8 mrcx_act_hwb_map; + u8 mrcx_bt_slot_rsp; + + u8 rf_combination; /* enum btc_mlo_rf_combin 0:2+0, 1:0+2, 2:1+1,3:2+2 */ + u8 mlo_en; /* MLO enable */ + u8 mlo_adie; /* a-die count */ + u8 dual_hw_band_en; /* both 2 HW-band link exist */ + + u32 link_status; /* enum mlo_dbcc_mode_type */ +}; + struct rtw89_btc_wl_active_role { u8 connected: 1; u8 pid: 3; @@ -1791,6 +1827,13 @@ union rtw89_btc_bt_state_map { #define BTC_BT_AFH_GROUP 12 #define BTC_BT_AFH_LE_GROUP 5 +struct rtw89_btc_bt_txpwr_desc { + s8 br_dbm; + s8 le_dbm; + u8 br_gain_index; + u8 le_gain_index; +}; + struct rtw89_btc_bt_link_info { struct rtw89_btc_u8_sta_chg profile_cnt; struct rtw89_btc_bool_sta_chg multi_link; @@ -1800,6 +1843,7 @@ struct rtw89_btc_bt_link_info { struct rtw89_btc_bt_a2dp_desc a2dp_desc; struct rtw89_btc_bt_pan_desc pan_desc; union rtw89_btc_bt_state_map status; + struct rtw89_btc_bt_txpwr_desc bt_txpwr_desc; u8 sut_pwr_level[BTC_PROFILE_MAX]; u8 golden_rx_shift[BTC_PROFILE_MAX]; @@ -1895,6 +1939,7 @@ struct rtw89_btc_wl_info { struct rtw89_btc_wl_role_info_v8 role_info_v8; struct rtw89_btc_wl_scan_info scan_info; struct rtw89_btc_wl_dbcc_info dbcc_info; + struct rtw89_btc_wl_mlo_info mlo_info; struct rtw89_btc_rf_para rf_para; struct rtw89_btc_wl_nhm nhm; union rtw89_btc_wl_state_map status; @@ -1907,12 +1952,16 @@ struct rtw89_btc_wl_info { u8 bt_polut_type[RTW89_PHY_NUM]; /* BT polluted WL-Tx type for phy0/1 */ bool is_5g_hi_channel; + bool go_client_exist; + bool noa_exist; bool pta_reg_mac_chg; bool bg_mode; bool he_mode; bool scbd_change; bool fw_ver_mismatch; bool client_cnt_inc_2g; + bool link_mode_chg; + bool dbcc_chg; u32 scbd; }; @@ -2065,6 +2114,7 @@ struct rtw89_btc_bt_info { union rtw89_btc_bt_rfk_info_map rfk_info; u8 raw_info[BTC_BTINFO_MAX]; /* raw bt info from mailbox */ + u8 txpwr_info[BTC_BTINFO_MAX]; u8 rssi_level; u32 scbd; @@ -2903,12 +2953,32 @@ struct rtw89_btc_trx_info { u32 rx_err_ratio; }; +enum btc_rf_path { + BTC_RF_S0 = 0, + BTC_RF_S1 = 1, + BTC_RF_NUM, +}; + +struct rtw89_btc_fbtc_outsrc_set_info { + u8 rf_band[BTC_RF_NUM]; /* 0:2G, 1:non-2G */ + u8 btg_rx[BTC_RF_NUM]; + u8 nbtg_tx[BTC_RF_NUM]; + + struct rtw89_mac_ax_gnt gnt_set[BTC_RF_NUM]; /* refer to btc_gnt_ctrl */ + struct rtw89_mac_ax_wl_act wlact_set[BTC_RF_NUM]; /* BT0/BT1 */ + + u8 pta_req_hw_band; + u8 rf_gbt_source; +} __packed; + union rtw89_btc_fbtc_slot_u { struct rtw89_btc_fbtc_slot v1[CXST_MAX]; struct rtw89_btc_fbtc_slot_v7 v7[CXST_MAX]; }; struct rtw89_btc_dm { + struct rtw89_btc_fbtc_outsrc_set_info ost_info_last; /* outsrc API setup info */ + struct rtw89_btc_fbtc_outsrc_set_info ost_info; /* outsrc API setup info */ union rtw89_btc_fbtc_slot_u slot; union rtw89_btc_fbtc_slot_u slot_now; struct rtw89_btc_fbtc_tdma tdma; @@ -2998,6 +3068,7 @@ enum rtw89_btc_btf_fw_event { BTF_EVNT_BT_LEAUDIO_INFO = 7, /* fwc2hfunc > 1 */ BTF_EVNT_BUF_OVERFLOW, BTF_EVNT_C2H_LOOPBACK, + BTF_EVNT_BT_QUERY_TXPWR, /* fwc2hfunc > 3 */ BTF_EVNT_MAX, }; @@ -3116,31 +3187,6 @@ enum rtw89_btc_btfre_type { BTFRE_MAX, }; -struct rtw89_btc_btf_fwinfo { - u32 cnt_c2h; - u32 cnt_h2c; - u32 cnt_h2c_fail; - u32 event[BTF_EVNT_MAX]; - - u32 err[BTFRE_MAX]; - u32 len_mismch; - u32 fver_mismch; - u32 rpt_en_map; - - struct rtw89_btc_report_ctrl_state rpt_ctrl; - struct rtw89_btc_rpt_fbtc_tdma rpt_fbtc_tdma; - struct rtw89_btc_rpt_fbtc_slots rpt_fbtc_slots; - struct rtw89_btc_rpt_fbtc_cysta rpt_fbtc_cysta; - struct rtw89_btc_rpt_fbtc_step rpt_fbtc_step; - struct rtw89_btc_rpt_fbtc_nullsta rpt_fbtc_nullsta; - struct rtw89_btc_rpt_fbtc_mreg rpt_fbtc_mregval; - struct rtw89_btc_rpt_fbtc_gpio_dbg rpt_fbtc_gpio_dbg; - struct rtw89_btc_rpt_fbtc_btver rpt_fbtc_btver; - struct rtw89_btc_rpt_fbtc_btscan rpt_fbtc_btscan; - struct rtw89_btc_rpt_fbtc_btafh rpt_fbtc_btafh; - struct rtw89_btc_rpt_fbtc_btdev rpt_fbtc_btdev; -}; - struct rtw89_btc_ver { enum rtw89_core_chip_id chip_id; u32 fw_ver_code; @@ -3167,6 +3213,35 @@ struct rtw89_btc_ver { u8 drvinfo_type; u16 info_buf; u8 max_role_num; + u8 fcxosi; + u8 fcxmlo; + u8 bt_desired; +}; + +struct rtw89_btc_btf_fwinfo { + u32 cnt_c2h; + u32 cnt_h2c; + u32 cnt_h2c_fail; + u32 event[BTF_EVNT_MAX]; + + u32 err[BTFRE_MAX]; + u32 len_mismch; + u32 fver_mismch; + u32 rpt_en_map; + + struct rtw89_btc_ver fw_subver; + struct rtw89_btc_report_ctrl_state rpt_ctrl; + struct rtw89_btc_rpt_fbtc_tdma rpt_fbtc_tdma; + struct rtw89_btc_rpt_fbtc_slots rpt_fbtc_slots; + struct rtw89_btc_rpt_fbtc_cysta rpt_fbtc_cysta; + struct rtw89_btc_rpt_fbtc_step rpt_fbtc_step; + struct rtw89_btc_rpt_fbtc_nullsta rpt_fbtc_nullsta; + struct rtw89_btc_rpt_fbtc_mreg rpt_fbtc_mregval; + struct rtw89_btc_rpt_fbtc_gpio_dbg rpt_fbtc_gpio_dbg; + struct rtw89_btc_rpt_fbtc_btver rpt_fbtc_btver; + struct rtw89_btc_rpt_fbtc_btscan rpt_fbtc_btscan; + struct rtw89_btc_rpt_fbtc_btafh rpt_fbtc_btafh; + struct rtw89_btc_rpt_fbtc_btdev rpt_fbtc_btdev; }; #define RTW89_BTC_POLICY_MAXLEN 512 @@ -3385,6 +3460,7 @@ struct rtw89_sta_link { unsigned int link_id; u8 mac_id; + u8 tx_retry; bool er_cap; struct rtw89_vif_link *rtwvif_link; struct rtw89_ra_info ra; @@ -3420,6 +3496,7 @@ struct rtw89_efuse { u8 addr[ETH_ALEN]; u8 rfe_type; char country_code[2]; + u8 adc_td; }; struct rtw89_phy_rate_pattern { @@ -3440,6 +3517,8 @@ struct rtw89_tx_skb_data { u8 hci_priv[]; }; +#define RTW89_SCAN_NULL_TIMEOUT 30 + #define RTW89_ROC_IDLE_TIMEOUT 500 #define RTW89_ROC_TX_TIMEOUT 30 enum rtw89_roc_state { @@ -3518,6 +3597,7 @@ struct rtw89_vif_link { u8 hit_rule; u8 last_noa_nr; u64 sync_bcn_tsf; + u64 last_sync_bcn_tsf; bool rand_tsf_done; bool trigger; bool lsig_txop; @@ -3533,6 +3613,7 @@ struct rtw89_vif_link { bool pwr_diff_en; u8 def_tri_idx; struct wiphy_work update_beacon_work; + struct wiphy_delayed_work csa_beacon_work; struct rtw89_addr_cam_entry addr_cam; struct rtw89_bssid_cam_entry bssid_cam; struct ieee80211_tx_queue_params tx_params[IEEE80211_NUM_ACS]; @@ -3540,6 +3621,8 @@ struct rtw89_vif_link { struct list_head general_pkt_list; struct rtw89_p2p_noa_setter p2p_noa; struct rtw89_ps_noa_once_handler noa_once; + struct wiphy_delayed_work mcc_gc_detect_beacon_work; + u8 detect_bcn_count; }; enum rtw89_lv1_rcvy_step { @@ -3596,6 +3679,7 @@ struct rtw89_hci_ops { struct rtw89_hci_info { const struct rtw89_hci_ops *ops; enum rtw89_hci_type type; + enum rtw89_hci_dle_type dle_type; u32 rpwm_addr; u32 cpwm_addr; bool paused; @@ -3645,6 +3729,8 @@ struct rtw89_chip_ops { enum rtw89_phy_idx phy_idx); int (*init_txpwr_unit)(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); u8 (*get_thermal)(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path); + u32 (*chan_to_rf18_val)(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan); void (*ctrl_btg_bt_rx)(struct rtw89_dev *rtwdev, bool en, enum rtw89_phy_idx phy_idx); void (*query_ppdu)(struct rtw89_dev *rtwdev, @@ -3693,6 +3779,9 @@ struct rtw89_chip_ops { struct rtw89_sta_link *rtwsta_link); int (*h2c_txtime_cmac_tbl)(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); + int (*h2c_punctured_cmac_tbl)(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured); int (*h2c_default_dmac_tbl)(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link); @@ -3777,7 +3866,7 @@ struct rtw89_scan_option { u16 slow_pd; u16 norm_cy; u8 opch_end; - u16 delay; + u16 delay; /* in unit of ms */ u64 prohib_chan; enum rtw89_phy_idx band; enum rtw89_scan_be_operation operation; @@ -4292,8 +4381,8 @@ struct rtw89_chip_info { u16 max_amsdu_limit; bool dis_2g_40m_ul_ofdma; u32 rsvd_ple_ofst; - const struct rtw89_hfc_param_ini *hfc_param_ini; - const struct rtw89_dle_mem *dle_mem; + const struct rtw89_hfc_param_ini *hfc_param_ini[RTW89_HCI_TYPE_NUM]; + const struct rtw89_dle_mem *dle_mem[RTW89_HCI_DLE_TYPE_NUM]; u8 wde_qempty_acq_grpnum; u8 wde_qempty_mgq_grpsel; u32 rf_base_addr[2]; @@ -4358,7 +4447,6 @@ struct rtw89_chip_info { u32 para_ver; u32 wlcx_desired; - u8 btcx_desired; u8 scbd; u8 mailbox; @@ -4498,11 +4586,21 @@ enum rtw89_fw_type { RTW89_FW_LOGFMT = 255, }; +#define RTW89_FW_FEATURE_GROUP(_grp, _features...) \ + RTW89_FW_FEATURE_##_grp##_MIN, \ + __RTW89_FW_FEATURE_##_grp##_S = RTW89_FW_FEATURE_##_grp##_MIN - 1, \ + _features \ + __RTW89_FW_FEATURE_##_grp##_E, \ + RTW89_FW_FEATURE_##_grp##_MAX = __RTW89_FW_FEATURE_##_grp##_E - 1 + enum rtw89_fw_feature { RTW89_FW_FEATURE_OLD_HT_RA_FORMAT, RTW89_FW_FEATURE_SCAN_OFFLOAD, RTW89_FW_FEATURE_TX_WAKE, - RTW89_FW_FEATURE_CRASH_TRIGGER, + RTW89_FW_FEATURE_GROUP(CRASH_TRIGGER, + RTW89_FW_FEATURE_CRASH_TRIGGER_TYPE_0, + RTW89_FW_FEATURE_CRASH_TRIGGER_TYPE_1, + ), RTW89_FW_FEATURE_NO_PACKET_DROP, RTW89_FW_FEATURE_NO_DEEP_PS, RTW89_FW_FEATURE_NO_LPS_PG, @@ -4513,6 +4611,7 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V0, RTW89_FW_FEATURE_RFK_PRE_NOTIFY_V1, RTW89_FW_FEATURE_RFK_RXDCK_V0, + RTW89_FW_FEATURE_RFK_IQK_V0, RTW89_FW_FEATURE_NO_WOW_CPU_IO_RX, RTW89_FW_FEATURE_NOTIFY_AP_INFO, RTW89_FW_FEATURE_CH_INFO_BE_V0, @@ -4520,6 +4619,9 @@ enum rtw89_fw_feature { RTW89_FW_FEATURE_NO_PHYCAP_P1, RTW89_FW_FEATURE_NO_POWER_DIFFERENCE, RTW89_FW_FEATURE_BEACON_LOSS_COUNT_V1, + RTW89_FW_FEATURE_SCAN_OFFLOAD_EXTRA_OP, + RTW89_FW_FEATURE_RFK_NTFY_MCC_V0, + RTW89_FW_FEATURE_LPS_DACK_BY_C2H_REG, }; struct rtw89_fw_suit { @@ -4617,6 +4719,10 @@ struct rtw89_fw_info { #define RTW89_CHK_FW_FEATURE(_feat, _fw) \ (!!((_fw)->feature_map & BIT(RTW89_FW_FEATURE_ ## _feat))) +#define RTW89_CHK_FW_FEATURE_GROUP(_grp, _fw) \ + (!!((_fw)->feature_map & GENMASK(RTW89_FW_FEATURE_ ## _grp ## _MAX, \ + RTW89_FW_FEATURE_ ## _grp ## _MIN))) + #define RTW89_SET_FW_FEATURE(_fw_feature, _fw) \ ((_fw)->feature_map |= BIT(_fw_feature)) @@ -4912,9 +5018,10 @@ enum rtw89_flags { RTW89_FLAG_CRASH_SIMULATING, RTW89_FLAG_SER_HANDLING, RTW89_FLAG_WOWLAN, - RTW89_FLAG_FORBIDDEN_TRACK_WROK, + RTW89_FLAG_FORBIDDEN_TRACK_WORK, RTW89_FLAG_CHANGING_INTERFACE, RTW89_FLAG_HW_RFKILL_STATE, + RTW89_FLAG_UNPLUGGED, NUM_OF_RTW89_FLAGS, }; @@ -5079,7 +5186,7 @@ struct rtw89_dpk_bkup_para { enum rtw89_band band; enum rtw89_bandwidth bw; u8 ch; - bool path_ok; + u8 path_ok; u8 mdpd_en; u8 txagc_dpk; u8 ther_dpk; @@ -5157,8 +5264,10 @@ struct rtw89_dig_info { s8 tia_gain_a[TIA_GAIN_NUM]; s8 tia_gain_g[TIA_GAIN_NUM]; s8 *tia_gain; + u32 bak_dig; bool is_linked_pre; bool bypass_dig; + bool pause_dig; }; enum rtw89_multi_cfo_mode { @@ -5300,6 +5409,7 @@ struct rtw89_regulatory_info { DECLARE_BITMAP(block_unii4, RTW89_REGD_MAX_COUNTRY_NUM); DECLARE_BITMAP(block_6ghz, RTW89_REGD_MAX_COUNTRY_NUM); DECLARE_BITMAP(block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM); + DECLARE_BITMAP(block_6ghz_vlp, RTW89_REGD_MAX_COUNTRY_NUM); }; enum rtw89_ifs_clm_application { @@ -5447,13 +5557,24 @@ struct rtw89_early_h2c { u16 h2c_len; }; +struct rtw89_hw_scan_extra_op { + bool set; + u8 macid; + u8 port; + struct rtw89_chan chan; + struct rtw89_vif_link *rtwvif_link; +}; + struct rtw89_hw_scan_info { struct rtw89_vif_link *scanning_vif; struct list_head pkt_list[NUM_NL80211_BANDS]; struct list_head chan_list; struct rtw89_chan op_chan; + struct rtw89_hw_scan_extra_op extra_op; bool connected; bool abort; + u16 delay; /* in unit of ms */ + u8 seq: 2; }; enum rtw89_phy_bb_gain_band { @@ -5672,12 +5793,14 @@ struct rtw89_mcc_role { /* byte-array in LE order for FW */ u8 macid_bitmap[BITS_TO_BYTES(RTW89_MAX_MAC_ID_NUM)]; + u8 probe_count; u16 duration; /* TU */ u16 beacon_interval; /* TU */ bool is_2ghz; bool is_go; bool is_gc; + bool ignore_bcn; }; struct rtw89_mcc_bt_role { @@ -5728,6 +5851,7 @@ struct rtw89_mcc_config { struct rtw89_mcc_sync sync; u64 start_tsf; u64 start_tsf_in_aux_domain; + u64 prepare_delay; u16 mcc_interval; /* TU */ u16 beacon_offset; /* TU */ }; @@ -5853,11 +5977,13 @@ struct rtw89_dev { } bbs[RTW89_PHY_NUM]; struct wiphy_delayed_work track_work; + struct wiphy_delayed_work track_ps_work; struct wiphy_delayed_work chanctx_work; struct wiphy_delayed_work coex_act1_work; struct wiphy_delayed_work coex_bt_devinfo_work; struct wiphy_delayed_work coex_rfk_chk_work; struct wiphy_delayed_work cfo_track_work; + struct wiphy_delayed_work mcc_prepare_done_work; struct delayed_work forbid_ba_work; struct wiphy_delayed_work antdiv_work; struct rtw89_ppdu_sts_info ppdu_sts; @@ -5902,6 +6028,7 @@ struct rtw89_vif { __be32 ip_addr; struct rtw89_traffic_stats stats; + struct rtw89_traffic_stats stats_ps; u32 tdls_peer; struct ieee80211_scan_ies *scan_ies; @@ -6880,6 +7007,17 @@ static inline u8 rtw89_chip_get_thermal(struct rtw89_dev *rtwdev, return chip->ops->get_thermal(rtwdev, rf_path); } +static inline u32 rtw89_chip_chan_to_rf18_val(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!chip->ops->chan_to_rf18_val) + return 0; + + return chip->ops->chan_to_rf18_val(rtwdev, chan); +} + static inline void rtw89_chip_query_ppdu(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu, struct ieee80211_rx_status *status) @@ -7203,6 +7341,17 @@ static inline bool rtw89_is_rtl885xb(struct rtw89_dev *rtwdev) return false; } +static inline u32 rtw89_bytes_to_mbps(u64 bytes, enum rtw89_tfc_interval interval) +{ + switch (interval) { + default: + case RTW89_TFC_INTERVAL_2SEC: + return bytes >> 18; /* bytes/2s --> Mbps */; + case RTW89_TFC_INTERVAL_100MS: + return (bytes * 10) >> 17; /* bytes/100ms --> Mbps */ + } +} + int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct sk_buff *skb, int *qsel); int rtw89_h2c_tx(struct rtw89_dev *rtwdev, @@ -7317,6 +7466,9 @@ void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond, int rtw89_core_start(struct rtw89_dev *rtwdev); void rtw89_core_stop(struct rtw89_dev *rtwdev); void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); +void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work); +int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, + bool qos, bool ps, int timeout); void rtw89_roc_work(struct wiphy *wiphy, struct wiphy_work *work); void rtw89_roc_start(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); void rtw89_roc_end(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c index d6016fa107fb..afdfb9647fc1 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -1114,6 +1114,7 @@ static int rtw89_debug_dump_mac_mem(struct rtw89_dev *rtwdev, const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 filter_model_addr = mac->filter_model_addr; u32 indir_access_addr = mac->indir_access_addr; + u32 mem_page_size = mac->mem_page_size; u32 base_addr, start_page, residue; char *p = buf, *end = buf + bufsz; u32 i, j, pp, pages; @@ -1121,14 +1122,14 @@ static int rtw89_debug_dump_mac_mem(struct rtw89_dev *rtwdev, u32 val; remain = len; - pages = len / MAC_MEM_DUMP_PAGE_SIZE + 1; - start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE; - residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE; + pages = len / mem_page_size + 1; + start_page = start_addr / mem_page_size; + residue = start_addr % mem_page_size; base_addr = mac->mem_base_addrs[sel]; - base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE; + base_addr += start_page * mem_page_size; for (pp = 0; pp < pages; pp++) { - dump_len = min_t(u32, remain, MAC_MEM_DUMP_PAGE_SIZE); + dump_len = min_t(u32, remain, mem_page_size); rtw89_write32(rtwdev, filter_model_addr, base_addr); for (i = indir_access_addr + residue; i < indir_access_addr + dump_len;) { @@ -1142,7 +1143,7 @@ static int rtw89_debug_dump_mac_mem(struct rtw89_dev *rtwdev, } p += scnprintf(p, end - p, "\n"); } - base_addr += MAC_MEM_DUMP_PAGE_SIZE; + base_addr += mem_page_size; } return p - buf; @@ -3595,7 +3596,7 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev, switch (crash_type) { case RTW89_DBG_SIM_CPU_EXCEPTION: - if (!RTW89_CHK_FW_FEATURE(CRASH_TRIGGER, &rtwdev->fw)) + if (!RTW89_CHK_FW_FEATURE_GROUP(CRASH_TRIGGER, &rtwdev->fw)) return -EOPNOTSUPP; sim = rtw89_fw_h2c_trigger_cpu_exception; break; diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 00b65b2995cf..16e59a4a486e 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -814,36 +814,45 @@ struct __fw_feat_cfg { static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, TX_WAKE), __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 37, 1, SCAN_OFFLOAD), - __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8851B, ge, 0, 29, 41, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852A, le, 0, 13, 29, 0, OLD_HT_RA_FORMAT), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 35, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852A, ge, 0, 13, 36, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 37, 0, NO_WOW_CPU_IO_RX), __CFG_FW_FEAT(RTL8852A, lt, 0, 13, 38, 0, NO_PACKET_DROP), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 26, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 29, 7, BEACON_FILTER), __CFG_FW_FEAT(RTL8852B, lt, 0, 29, 30, 0, NO_WOW_CPU_IO_RX), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, CRASH_TRIGGER_TYPE_1), + __CFG_FW_FEAT(RTL8852B, ge, 0, 29, 128, 0, SCAN_OFFLOAD_EXTRA_OP), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, NO_LPS_PG), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 74, 0, TX_WAKE), - __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 90, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 91, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 110, 0, BEACON_FILTER), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, SCAN_OFFLOAD_EXTRA_OP), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852BT, ge, 0, 29, 127, 0, CRASH_TRIGGER_TYPE_1), __CFG_FW_FEAT(RTL8852C, le, 0, 27, 33, 0, NO_DEEP_PS), + __CFG_FW_FEAT(RTL8852C, ge, 0, 0, 0, 0, RFK_NTFY_MCC_V0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 34, 0, TX_WAKE), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 36, 0, SCAN_OFFLOAD), - __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 40, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 56, 10, BEACON_FILTER), __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 80, 0, WOW_REASON_V1), - __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, BEACON_LOSS_COUNT_V1), + __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 30, 0, CRASH_TRIGGER_TYPE_0), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 11, 0, MACID_PAUSE_SLEEP), __CFG_FW_FEAT(RTL8922A, ge, 0, 34, 35, 0, SCAN_OFFLOAD), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 21, 0, SCAN_OFFLOAD_BE_V0), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 12, 0, BEACON_FILTER), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 22, 0, WOW_REASON_V1), + __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 28, 0, RFK_IQK_V0), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, RFK_PRE_NOTIFY_V0), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 31, 0, LPS_CH_INFO), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 42, 0, RFK_RXDCK_V0), @@ -853,6 +862,8 @@ static const struct __fw_feat_cfg fw_feat_tbl[] = { __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 51, 0, NO_PHYCAP_P1), __CFG_FW_FEAT(RTL8922A, lt, 0, 35, 64, 0, NO_POWER_DIFFERENCE), __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 71, 0, BEACON_LOSS_COUNT_V1), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 76, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 79, 0, CRASH_TRIGGER_TYPE_1), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -2821,8 +2832,14 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, struct rtw89_lps_parm *lps_param) { struct sk_buff *skb; + bool done_ack; int ret; + if (RTW89_CHK_FW_FEATURE(LPS_DACK_BY_C2H_REG, &rtwdev->fw)) + done_ack = false; + else + done_ack = !lps_param->psmode; + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_LPS_PARM_LEN); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw dl\n"); @@ -2844,7 +2861,7 @@ int rtw89_fw_h2c_lps_parm(struct rtw89_dev *rtwdev, rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_PS, - H2C_FUNC_MAC_LPS_PARM, 0, !lps_param->psmode, + H2C_FUNC_MAC_LPS_PARM, 0, done_ack, H2C_LPS_PARM_LEN); ret = rtw89_h2c_tx(rtwdev, skb, false); @@ -3030,12 +3047,10 @@ fail: #define H2C_P2P_ACT_LEN 20 int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, - struct ieee80211_bss_conf *bss_conf, struct ieee80211_p2p_noa_desc *desc, - u8 act, u8 noa_id) + u8 act, u8 noa_id, u8 ctwindow_oppps) { bool p2p_type_gc = rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT; - u8 ctwindow_oppps = bss_conf->p2p_noa_attr.oppps_ctwindow; struct sk_buff *skb; u8 *cmd; int ret; @@ -3730,6 +3745,49 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_txtime_cmac_tbl_g7); +int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured) +{ + struct rtw89_h2c_cctlinfo_ud_g7 *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for punctured cmac g7\n"); + return -ENOMEM; + } + + skb_put(skb, len); + h2c = (struct rtw89_h2c_cctlinfo_ud_g7 *)skb->data; + + h2c->c0 = le32_encode_bits(rtwvif_link->mac_id, CCTLINFO_G7_C0_MACID) | + le32_encode_bits(1, CCTLINFO_G7_C0_OP); + + h2c->w4 = le32_encode_bits(~punctured, CCTLINFO_G7_W4_ACT_SUBCH_CBW); + h2c->m4 = cpu_to_le32(CCTLINFO_G7_W4_ACT_SUBCH_CBW); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_FR_EXCHG, + H2C_FUNC_MAC_CCTLINFO_UD_G7, 0, 1, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_punctured_cmac_tbl_g7); + int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link) { @@ -5083,6 +5141,46 @@ fail: return ret; } +int rtw89_fw_h2c_cxdrv_osi_info(struct rtw89_dev *rtwdev, u8 type) +{ + struct rtw89_btc *btc = &rtwdev->btc; + struct rtw89_btc_fbtc_outsrc_set_info *osi = &btc->dm.ost_info; + struct rtw89_h2c_cxosi *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_osi\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_cxosi *)skb->data; + + h2c->hdr.type = type; + h2c->hdr.ver = btc->ver->fcxosi; + h2c->hdr.len = len - H2C_LEN_CXDRVHDR_V7; + h2c->osi = *osi; + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, BTFC_SET, + SET_DRV_INFO, 0, 0, + len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + #define H2C_LEN_CXDRVINFO_CTRL (4 + H2C_LEN_CXDRVHDR) int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type) { @@ -5361,6 +5459,7 @@ static int rtw89_fw_h2c_scan_list_offload_ax(struct rtw89_dev *rtwdev, int ch_num, struct list_head *chan_list) { + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_h2c_chinfo_elem *elem; struct rtw89_mac_chinfo_ax *ch_info; @@ -5403,6 +5502,10 @@ int rtw89_fw_h2c_scan_list_offload_ax(struct rtw89_dev *rtwdev, int ch_num, le32_encode_bits(ch_info->tx_null, RTW89_H2C_CHINFO_W1_TX_NULL) | le32_encode_bits(ch_info->rand_seq_num, RTW89_H2C_CHINFO_W1_RANDOM); + if (scan_info->extra_op.set) + elem->w1 |= le32_encode_bits(ch_info->macid_tx, + RTW89_H2C_CHINFO_W1_MACID_TX); + elem->w2 = le32_encode_bits(ch_info->pkt_id[0], RTW89_H2C_CHINFO_W2_PKT0) | le32_encode_bits(ch_info->pkt_id[1], RTW89_H2C_CHINFO_W2_PKT1) | le32_encode_bits(ch_info->pkt_id[2], RTW89_H2C_CHINFO_W2_PKT2) | @@ -5537,12 +5640,12 @@ int rtw89_fw_h2c_scan_list_offload_be(struct rtw89_dev *rtwdev, int ch_num, return 0; } -#define RTW89_SCAN_DELAY_TSF_UNIT 1000000 int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, struct rtw89_scan_option *option, struct rtw89_vif_link *rtwvif_link, bool wowlan) { + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct rtw89_chan *op = &rtwdev->scan_info.op_chan; enum rtw89_scan_mode scan_mode = RTW89_SCAN_IMMEDIATE; @@ -5568,7 +5671,7 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, scan_mode = RTW89_SCAN_IMMEDIATE; } else { scan_mode = RTW89_SCAN_DELAY; - tsf += (u64)option->delay * RTW89_SCAN_DELAY_TSF_UNIT; + tsf += (u64)option->delay * 1000; } } @@ -5602,6 +5705,10 @@ int rtw89_fw_h2c_scan_offload_ax(struct rtw89_dev *rtwdev, h2c->tsf_low = le32_encode_bits(lower_32_bits(tsf), RTW89_H2C_SCANOFLD_W4_TSF_LOW); + if (scan_info->extra_op.set) + h2c->w6 = le32_encode_bits(scan_info->extra_op.macid, + RTW89_H2C_SCANOFLD_W6_SECOND_MACID); + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_MAC, H2C_CL_MAC_FW_OFLD, H2C_FUNC_SCANOFLD, 1, 1, @@ -5650,26 +5757,47 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, { struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_wait_info *wait = &rtwdev->mac.fw_ofld_wait; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_h2c_scanofld_be_macc_role *macc_role; + struct rtw89_hw_scan_extra_op scan_op[2] = {}; struct rtw89_chan *op = &scan_info->op_chan; struct rtw89_h2c_scanofld_be_opch *opch; struct rtw89_pktofld_info *pkt_info; struct rtw89_h2c_scanofld_be *h2c; + struct ieee80211_vif *vif; struct sk_buff *skb; u8 macc_role_size = sizeof(*macc_role) * option->num_macc_role; u8 opch_size = sizeof(*opch) * option->num_opch; + enum rtw89_scan_be_opmode opmode; u8 probe_id[NUM_NL80211_BANDS]; u8 scan_offload_ver = U8_MAX; u8 cfg_len = sizeof(*h2c); unsigned int cond; + u8 ap_idx = U8_MAX; u8 ver = U8_MAX; + u8 policy_val; void *ptr; + u8 txbcn; int ret; u32 len; u8 i; + scan_op[0].macid = rtwvif_link->mac_id; + scan_op[0].port = rtwvif_link->port; + scan_op[0].chan = *op; + vif = rtwvif_to_vif(rtwvif_link->rtwvif); + if (vif->type == NL80211_IFTYPE_AP) + ap_idx = 0; + + if (ext->set) { + scan_op[1] = *ext; + vif = rtwvif_to_vif(ext->rtwvif_link->rtwvif); + if (vif->type == NL80211_IFTYPE_AP) + ap_idx = 1; + } + rtw89_scan_get_6g_disabled_chan(rtwdev, option); if (RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_BE_V0, &rtwdev->fw)) { @@ -5730,7 +5858,7 @@ int rtw89_fw_h2c_scan_offload_be(struct rtw89_dev *rtwdev, RTW89_H2C_SCANOFLD_BE_W4_PROBE_5G) | le32_encode_bits(probe_id[NL80211_BAND_6GHZ], RTW89_H2C_SCANOFLD_BE_W4_PROBE_6G) | - le32_encode_bits(option->delay, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); + le32_encode_bits(option->delay / 1000, RTW89_H2C_SCANOFLD_BE_W4_DELAY_START); h2c->w5 = le32_encode_bits(option->mlo_mode, RTW89_H2C_SCANOFLD_BE_W5_MLO_MODE); @@ -5772,29 +5900,35 @@ flex_member: } for (i = 0; i < option->num_opch; i++) { + bool is_ap_idx = i == ap_idx; + + opmode = is_ap_idx ? RTW89_SCAN_OPMODE_TBTT : RTW89_SCAN_OPMODE_INTV; + policy_val = is_ap_idx ? 2 : RTW89_OFF_CHAN_TIME / 10; + txbcn = is_ap_idx ? 1 : 0; + opch = ptr; - opch->w0 = le32_encode_bits(rtwvif_link->mac_id, + opch->w0 = le32_encode_bits(scan_op[i].macid, RTW89_H2C_SCANOFLD_BE_OPCH_W0_MACID) | le32_encode_bits(option->band, RTW89_H2C_SCANOFLD_BE_OPCH_W0_BAND) | - le32_encode_bits(rtwvif_link->port, + le32_encode_bits(scan_op[i].port, RTW89_H2C_SCANOFLD_BE_OPCH_W0_PORT) | - le32_encode_bits(RTW89_SCAN_OPMODE_INTV, + le32_encode_bits(opmode, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY) | le32_encode_bits(true, RTW89_H2C_SCANOFLD_BE_OPCH_W0_TXNULL) | - le32_encode_bits(RTW89_OFF_CHAN_TIME / 10, + le32_encode_bits(policy_val, RTW89_H2C_SCANOFLD_BE_OPCH_W0_POLICY_VAL); - opch->w1 = le32_encode_bits(op->band_type, + opch->w1 = le32_encode_bits(scan_op[i].chan.band_type, RTW89_H2C_SCANOFLD_BE_OPCH_W1_CH_BAND) | - le32_encode_bits(op->band_width, + le32_encode_bits(scan_op[i].chan.band_width, RTW89_H2C_SCANOFLD_BE_OPCH_W1_BW) | le32_encode_bits(0x3, RTW89_H2C_SCANOFLD_BE_OPCH_W1_NOTIFY) | - le32_encode_bits(op->primary_channel, + le32_encode_bits(scan_op[i].chan.primary_channel, RTW89_H2C_SCANOFLD_BE_OPCH_W1_PRI_CH) | - le32_encode_bits(op->channel, + le32_encode_bits(scan_op[i].chan.channel, RTW89_H2C_SCANOFLD_BE_OPCH_W1_CENTRAL_CH); opch->w2 = le32_encode_bits(0, @@ -5802,7 +5936,9 @@ flex_member: le32_encode_bits(0, RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF) | le32_encode_bits(rtw89_is_mlo_1_1(rtwdev) ? 1 : 2, - RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS); + RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS) | + le32_encode_bits(txbcn, + RTW89_H2C_SCANOFLD_BE_OPCH_W2_TXBCN); opch->w3 = le32_encode_bits(RTW89_SCANOFLD_PKT_NONE, RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0) | @@ -5877,31 +6013,48 @@ fail: int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev) { struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_fw_h2c_rf_get_mccch_v0 *mccch_v0; struct rtw89_fw_h2c_rf_get_mccch *mccch; + u32 len = sizeof(*mccch); struct sk_buff *skb; + u8 ver = U8_MAX; int ret; u8 idx; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, sizeof(*mccch)); + if (RTW89_CHK_FW_FEATURE(RFK_NTFY_MCC_V0, &rtwdev->fw)) { + len = sizeof(*mccch_v0); + ver = 0; + } + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c cxdrv_ctrl\n"); return -ENOMEM; } - skb_put(skb, sizeof(*mccch)); - mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data; + skb_put(skb, len); idx = rfk_mcc->table_idx; - mccch->ch_0 = cpu_to_le32(rfk_mcc->ch[0]); - mccch->ch_1 = cpu_to_le32(rfk_mcc->ch[1]); - mccch->band_0 = cpu_to_le32(rfk_mcc->band[0]); - mccch->band_1 = cpu_to_le32(rfk_mcc->band[1]); - mccch->current_channel = cpu_to_le32(rfk_mcc->ch[idx]); - mccch->current_band_type = cpu_to_le32(rfk_mcc->band[idx]); + if (ver == 0) { + mccch_v0 = (struct rtw89_fw_h2c_rf_get_mccch_v0 *)skb->data; + mccch_v0->ch_0 = cpu_to_le32(rfk_mcc->ch[0]); + mccch_v0->ch_1 = cpu_to_le32(rfk_mcc->ch[1]); + mccch_v0->band_0 = cpu_to_le32(rfk_mcc->band[0]); + mccch_v0->band_1 = cpu_to_le32(rfk_mcc->band[1]); + mccch_v0->current_band_type = cpu_to_le32(rfk_mcc->band[idx]); + mccch_v0->current_channel = cpu_to_le32(rfk_mcc->ch[idx]); + } else { + mccch = (struct rtw89_fw_h2c_rf_get_mccch *)skb->data; + mccch->ch_0_0 = cpu_to_le32(rfk_mcc->ch[0]); + mccch->ch_0_1 = cpu_to_le32(rfk_mcc->ch[0]); + mccch->ch_1_0 = cpu_to_le32(rfk_mcc->ch[1]); + mccch->ch_1_1 = cpu_to_le32(rfk_mcc->ch[1]); + mccch->current_channel = cpu_to_le32(rfk_mcc->ch[idx]); + } rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY, H2C_FUNC_OUTSRC_RF_GET_MCCCH, 0, 0, - sizeof(*mccch)); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { @@ -5917,6 +6070,118 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_rf_ntfy_mcc); +int rtw89_fw_h2c_mcc_dig(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx chanctx_idx, + u8 mcc_role_idx, u8 pd_val, bool en) +{ + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_h2c_mcc_dig *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c mcc_dig\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_mcc_dig *)skb->data; + + h2c->w0 = le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_REG_CNT) | + le32_encode_bits(en, RTW89_H2C_MCC_DIG_W0_DM_EN) | + le32_encode_bits(mcc_role_idx, RTW89_H2C_MCC_DIG_W0_IDX) | + le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_SET) | + le32_encode_bits(1, RTW89_H2C_MCC_DIG_W0_PHY0_EN) | + le32_encode_bits(chan->channel, RTW89_H2C_MCC_DIG_W0_CENTER_CH) | + le32_encode_bits(chan->band_type, RTW89_H2C_MCC_DIG_W0_BAND_TYPE); + h2c->w1 = le32_encode_bits(dig_regs->seg0_pd_reg, + RTW89_H2C_MCC_DIG_W1_ADDR_LSB) | + le32_encode_bits(dig_regs->seg0_pd_reg >> 8, + RTW89_H2C_MCC_DIG_W1_ADDR_MSB) | + le32_encode_bits(dig_regs->pd_lower_bound_mask, + RTW89_H2C_MCC_DIG_W1_BMASK_LSB) | + le32_encode_bits(dig_regs->pd_lower_bound_mask >> 8, + RTW89_H2C_MCC_DIG_W1_BMASK_MSB); + h2c->w2 = le32_encode_bits(pd_val, RTW89_H2C_MCC_DIG_W2_VAL_LSB); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_DM, + H2C_FUNC_FW_MCC_DIG, 0, 0, len); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} + +int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_h2c_rf_ps_info *h2c; + const struct rtw89_chan *chan; + u32 len = sizeof(*h2c); + unsigned int link_id; + struct sk_buff *skb; + int ret; + u8 path; + u32 val; + + if (chip->chip_gen != RTW89_CHIP_BE) + return 0; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c rf ps info\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_ps_info *)skb->data; + h2c->mlo_mode = cpu_to_le32(rtwdev->mlo_dbcc_mode); + + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + path = rtw89_phy_get_syn_sel(rtwdev, rtwvif_link->phy_idx); + val = rtw89_chip_chan_to_rf18_val(rtwdev, chan); + + if (path >= chip->rf_path_num || path >= NUM_OF_RTW89_FW_RFK_PATH) { + rtw89_err(rtwdev, "unsupported rf path (%d)\n", path); + ret = -ENOENT; + goto fail; + } + + h2c->rf18[path] = cpu_to_le32(val); + h2c->pri_ch[path] = chan->primary_channel; + } + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_NOTIFY, + H2C_FUNC_OUTSRC_RF_PS_INFO, 0, 0, + sizeof(*h2c)); + + ret = rtw89_h2c_tx(rtwdev, skb, false); + if (ret) { + rtw89_err(rtwdev, "failed to send h2c\n"); + goto fail; + } + + return 0; +fail: + dev_kfree_skb_any(skb); + + return ret; +} +EXPORT_SYMBOL(rtw89_fw_h2c_rf_ps_info); + int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { @@ -6031,6 +6296,7 @@ fail: int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, enum rtw89_tssi_mode tssi_mode) { + struct rtw89_efuse *efuse = &rtwdev->efuse; struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_h2c_rf_tssi *h2c; u32 len = sizeof(*h2c); @@ -6053,6 +6319,7 @@ int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, h2c->hwtx_en = true; h2c->cv = hal->cv; h2c->tssi_mode = tssi_mode; + h2c->rfe_type = efuse->rfe_type; rtw89_phy_rfk_tssi_fill_fwcmd_efuse_to_de(rtwdev, phy_idx, chan, h2c); rtw89_phy_rfk_tssi_fill_fwcmd_tmeter_tbl(rtwdev, phy_idx, chan, h2c); @@ -6077,22 +6344,47 @@ fail: int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan) { + struct rtw89_hal *hal = &rtwdev->hal; + struct rtw89_h2c_rf_iqk_v0 *h2c_v0; struct rtw89_h2c_rf_iqk *h2c; u32 len = sizeof(*h2c); struct sk_buff *skb; + u8 ver = U8_MAX; int ret; + if (RTW89_CHK_FW_FEATURE(RFK_IQK_V0, &rtwdev->fw)) { + len = sizeof(*h2c_v0); + ver = 0; + } + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for h2c RF IQK\n"); return -ENOMEM; } skb_put(skb, len); + + if (ver == 0) { + h2c_v0 = (struct rtw89_h2c_rf_iqk_v0 *)skb->data; + + h2c_v0->phy_idx = cpu_to_le32(phy_idx); + h2c_v0->dbcc = cpu_to_le32(rtwdev->dbcc_en); + + goto done; + } + h2c = (struct rtw89_h2c_rf_iqk *)skb->data; - h2c->phy_idx = cpu_to_le32(phy_idx); - h2c->dbcc = cpu_to_le32(rtwdev->dbcc_en); + h2c->len = sizeof(*h2c); + h2c->ktype = 0; + h2c->phy = phy_idx; + h2c->kpath = rtw89_phy_get_kpath(rtwdev, phy_idx); + h2c->band = chan->band_type; + h2c->bw = chan->band_width; + h2c->ch = chan->channel; + h2c->cv = hal->cv; +done: rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, H2C_FUNC_RFK_IQK_OFFLOAD, 0, 0, len); @@ -6467,6 +6759,34 @@ void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work) } } +void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev) +{ + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct sk_buff *skb, *tmp; + int limit; + + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + limit = skb_queue_len(&rtwdev->c2h_queue); + + skb_queue_walk_safe(&rtwdev->c2h_queue, skb, tmp) { + struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb); + + if (--limit < 0) + return; + + if (!attr->is_scan_event || attr->scan_seq == scan_info->seq) + continue; + + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "purge obsoleted scan event with seq=%d (cur=%d)\n", + attr->scan_seq, scan_info->seq); + + skb_unlink(skb, &rtwdev->c2h_queue); + dev_kfree_skb_any(skb); + } +} + static int rtw89_fw_write_h2c_reg(struct rtw89_dev *rtwdev, struct rtw89_mac_h2c_info *info) { @@ -6506,13 +6826,18 @@ static int rtw89_fw_read_c2h_reg(struct rtw89_dev *rtwdev, const struct rtw89_chip_info *chip = rtwdev->chip; struct rtw89_fw_info *fw_info = &rtwdev->fw; const u32 *c2h_reg = chip->c2h_regs; - u32 ret; + u32 ret, timeout; u8 i, val; info->id = RTW89_FWCMD_C2HREG_FUNC_NULL; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + timeout = RTW89_C2H_TIMEOUT_USB; + else + timeout = RTW89_C2H_TIMEOUT; + ret = read_poll_timeout_atomic(rtw89_read8, val, val, 1, - RTW89_C2H_TIMEOUT, false, rtwdev, + timeout, false, rtwdev, chip->c2h_ctrl_reg); if (ret) { rtw89_warn(rtwdev, "c2h reg timeout\n"); @@ -6619,6 +6944,7 @@ static void rtw89_hw_scan_cleanup(struct rtw89_dev *rtwdev, scan_info->scanning_vif = NULL; scan_info->abort = false; scan_info->connected = false; + scan_info->delay = 0; } static bool rtw89_is_6ghz_wildcard_probe_req(struct rtw89_dev *rtwdev, @@ -6845,6 +7171,7 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct ieee80211_scan_ies *ies = rtwvif->scan_ies; struct cfg80211_scan_request *req = rtwvif->scan_req; @@ -6915,6 +7242,15 @@ static void rtw89_hw_scan_add_chan_ax(struct rtw89_dev *rtwdev, int chan_type, case RTW89_CHAN_ACTIVE: ch_info->pause_data = true; break; + case RTW89_CHAN_EXTRA_OP: + ch_info->central_ch = ext->chan.channel; + ch_info->pri_ch = ext->chan.primary_channel; + ch_info->ch_band = ext->chan.band_type; + ch_info->bw = ext->chan.band_width; + ch_info->tx_null = true; + ch_info->num_pkt = 0; + ch_info->macid_tx = true; + break; default: rtw89_err(rtwdev, "Channel type out of bound\n"); } @@ -7073,10 +7409,45 @@ out: return ret; } +static int rtw89_hw_scan_add_op_types_ax(struct rtw89_dev *rtwdev, + enum rtw89_chan_type type, + struct list_head *chan_list, + struct cfg80211_scan_request *req, + int *off_chan_time) +{ + struct rtw89_mac_chinfo_ax *tmp; + + tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + switch (type) { + case RTW89_CHAN_OPERATE: + tmp->period = req->duration_mandatory ? + req->duration : RTW89_CHANNEL_TIME; + *off_chan_time = 0; + break; + case RTW89_CHAN_EXTRA_OP: + tmp->period = RTW89_CHANNEL_TIME_EXTRA_OP; + /* still calc @off_chan_time for scan op */ + *off_chan_time += tmp->period; + break; + default: + kfree(tmp); + return -EINVAL; + } + + rtw89_hw_scan_add_chan_ax(rtwdev, type, 0, tmp); + list_add_tail(&tmp->list, chan_list); + + return 0; +} + int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct cfg80211_scan_request *req = rtwvif->scan_req; struct rtw89_mac_chinfo_ax *ch_info, *tmp; @@ -7103,6 +7474,8 @@ int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev, else if (channel->band == NL80211_BAND_6GHZ) ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G; + else if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) + ch_info->period = RTW89_P2P_CHAN_TIME; else ch_info->period = RTW89_CHANNEL_TIME; @@ -7119,22 +7492,28 @@ int rtw89_hw_scan_prep_chan_list_ax(struct rtw89_dev *rtwdev, type = RTW89_CHAN_ACTIVE; rtw89_hw_scan_add_chan_ax(rtwdev, type, req->n_ssids, ch_info); - if (scan_info->connected && - off_chan_time + ch_info->period > RTW89_OFF_CHAN_TIME) { - tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); - if (!tmp) { - ret = -ENOMEM; - kfree(ch_info); - goto out; - } + if (!(scan_info->connected && + off_chan_time + ch_info->period > RTW89_OFF_CHAN_TIME)) + goto next; + + ret = rtw89_hw_scan_add_op_types_ax(rtwdev, RTW89_CHAN_OPERATE, + &chan_list, req, &off_chan_time); + if (ret) { + kfree(ch_info); + goto out; + } - type = RTW89_CHAN_OPERATE; - tmp->period = req->duration_mandatory ? - req->duration : RTW89_CHANNEL_TIME; - rtw89_hw_scan_add_chan_ax(rtwdev, type, 0, tmp); - list_add_tail(&tmp->list, &chan_list); - off_chan_time = 0; + if (!ext->set) + goto next; + + ret = rtw89_hw_scan_add_op_types_ax(rtwdev, RTW89_CHAN_EXTRA_OP, + &chan_list, req, &off_chan_time); + if (ret) { + kfree(ch_info); + goto out; } + +next: list_add_tail(&ch_info->list, &chan_list); off_chan_time += ch_info->period; } @@ -7273,6 +7652,8 @@ int rtw89_hw_scan_prep_chan_list_be(struct rtw89_dev *rtwdev, ch_info->period = req->duration; else if (channel->band == NL80211_BAND_6GHZ) ch_info->period = RTW89_CHANNEL_TIME_6G + RTW89_DWELL_TIME_6G; + else if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) + ch_info->period = RTW89_P2P_CHAN_TIME; else ch_info->period = RTW89_CHANNEL_TIME; @@ -7363,12 +7744,25 @@ out: static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, - u16 tu) + u16 tu, bool scan) { struct ieee80211_p2p_noa_desc noa_desc = {}; + struct ieee80211_bss_conf *bss_conf; + u16 beacon_int; u64 tsf; int ret; + rcu_read_lock(); + + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + beacon_int = bss_conf->beacon_int; + + rcu_read_unlock(); + + tu += beacon_int * 3; + if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) + rtwdev->scan_info.delay = ieee80211_tu_to_usec(beacon_int * 3) / 1000; + ret = rtw89_mac_port_get_tsf(rtwdev, rtwvif_link, &tsf); if (ret) { rtw89_warn(rtwdev, "%s: failed to get tsf\n", __func__); @@ -7376,17 +7770,24 @@ static void rtw89_hw_scan_update_link_beacon_noa(struct rtw89_dev *rtwdev, } noa_desc.start_time = cpu_to_le32(tsf); - noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu)); - noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu)); - noa_desc.count = 1; + if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) { + noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(tu)); + noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(tu)); + noa_desc.count = 1; + } else { + noa_desc.duration = cpu_to_le32(ieee80211_tu_to_usec(20000)); + noa_desc.interval = cpu_to_le32(ieee80211_tu_to_usec(20000)); + noa_desc.count = 255; + } rtw89_p2p_noa_renew(rtwvif_link); - rtw89_p2p_noa_append(rtwvif_link, &noa_desc); + if (scan) + rtw89_p2p_noa_append(rtwvif_link, &noa_desc); + rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); } -static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, - const struct cfg80211_scan_request *req) +static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, bool scan) { const struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; const struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; @@ -7401,6 +7802,9 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, lockdep_assert_wiphy(rtwdev->hw->wiphy); + if (!scan) + goto update; + list_for_each_safe(pos, tmp, &scan_info->chan_list) { switch (chip->chip_gen) { case RTW89_CHIP_AX: @@ -7424,6 +7828,7 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, return; } +update: list_for_each_entry(rtwvif, &mgnt->active_list, mgnt_entry) { unsigned int link_id; @@ -7432,7 +7837,51 @@ static void rtw89_hw_scan_update_beacon_noa(struct rtw89_dev *rtwdev, continue; rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) - rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link, tu); + rtw89_hw_scan_update_link_beacon_noa(rtwdev, rtwvif_link, + tu, scan); + } +} + +static void rtw89_hw_scan_set_extra_op_info(struct rtw89_dev *rtwdev, + struct rtw89_vif *scan_rtwvif, + const struct rtw89_chan *scan_op) +{ + struct rtw89_entity_mgnt *mgnt = &rtwdev->hal.entity_mgnt; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; + struct rtw89_vif *tmp; + + ext->set = false; + if (!RTW89_CHK_FW_FEATURE(SCAN_OFFLOAD_EXTRA_OP, &rtwdev->fw)) + return; + + list_for_each_entry(tmp, &mgnt->active_list, mgnt_entry) { + const struct rtw89_chan *tmp_chan; + struct rtw89_vif_link *tmp_link; + + if (tmp == scan_rtwvif) + continue; + + tmp_link = rtw89_vif_get_link_inst(tmp, 0); + if (unlikely(!tmp_link)) { + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "hw scan: no HW-0 link for extra op\n"); + continue; + } + + tmp_chan = rtw89_chan_get(rtwdev, tmp_link->chanctx_idx); + *ext = (struct rtw89_hw_scan_extra_op){ + .set = true, + .macid = tmp_link->mac_id, + .port = tmp_link->port, + .chan = *tmp_chan, + .rtwvif_link = tmp_link, + }; + + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "hw scan: extra op: center %d primary %d\n", + ext->chan.channel, ext->chan.primary_channel); + break; } } @@ -7458,9 +7907,16 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, /* clone op and keep it during scan */ rtwdev->scan_info.op_chan = *chan; + rtw89_debug(rtwdev, RTW89_DBG_HW_SCAN, + "hw scan: op: center %d primary %d\n", + chan->channel, chan->primary_channel); + + rtw89_hw_scan_set_extra_op_info(rtwdev, rtwvif, chan); + rtwdev->scan_info.connected = rtw89_is_any_vif_connected_or_connecting(rtwdev); rtwdev->scan_info.scanning_vif = rtwvif_link; rtwdev->scan_info.abort = false; + rtwdev->scan_info.delay = 0; rtwvif->scan_ies = &scan_req->ies; rtwvif->scan_req = req; @@ -7489,9 +7945,10 @@ int rtw89_hw_scan_start(struct rtw89_dev *rtwdev, rtw89_write32_mask(rtwdev, reg, B_AX_RX_FLTR_CFG_MASK, rx_fltr); rtw89_chanctx_pause(rtwdev, &pause_parm); + rtw89_phy_dig_suspend(rtwdev); if (mode == RTW89_ENTITY_MODE_MCC) - rtw89_hw_scan_update_beacon_noa(rtwdev, req); + rtw89_hw_scan_update_beacon_noa(rtwdev, true); return 0; } @@ -7504,6 +7961,7 @@ struct rtw89_hw_scan_complete_cb_data { static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + enum rtw89_entity_mode mode = rtw89_get_entity_mode(rtwdev); struct rtw89_hw_scan_complete_cb_data *cb_data = data; struct rtw89_vif_link *rtwvif_link = cb_data->rtwvif_link; struct cfg80211_scan_info info = { @@ -7522,9 +7980,13 @@ static int rtw89_hw_scan_complete_cb(struct rtw89_dev *rtwdev, void *data) ieee80211_wake_queues(rtwdev->hw); rtw89_mac_port_cfg_rx_sync(rtwdev, rtwvif_link, true); rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); + rtw89_phy_dig_resume(rtwdev, true); rtw89_hw_scan_cleanup(rtwdev, rtwvif_link); + if (mode == RTW89_ENTITY_MODE_MCC) + rtw89_hw_scan_update_beacon_noa(rtwdev, false); + return 0; } @@ -7591,6 +8053,8 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, bool enable) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + const struct rtw89_hw_scan_extra_op *ext = &scan_info->extra_op; struct rtw89_scan_option opt = {0}; bool connected; int ret = 0; @@ -7601,6 +8065,7 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, connected = rtwdev->scan_info.connected; opt.enable = enable; opt.target_ch_mode = connected; + opt.delay = rtwdev->scan_info.delay; if (enable) { ret = mac->add_chan_list(rtwdev, rtwvif_link); if (ret) @@ -7614,49 +8079,62 @@ int rtw89_hw_scan_offload(struct rtw89_dev *rtwdev, opt.num_macc_role = 0; opt.mlo_mode = rtwdev->mlo_dbcc_mode; opt.num_opch = connected ? 1 : 0; + if (connected && ext->set) + opt.num_opch++; + opt.opch_end = connected ? 0 : RTW89_CHAN_INVALID; } - ret = mac->scan_offload(rtwdev, &opt, rtwvif_link, false); + ret = rtw89_mac_scan_offload(rtwdev, &opt, rtwvif_link, false); + out: return ret; } -#define H2C_FW_CPU_EXCEPTION_LEN 4 -#define H2C_FW_CPU_EXCEPTION_TYPE_DEF 0x5566 +#define H2C_FW_CPU_EXCEPTION_TYPE_0 0x5566 +#define H2C_FW_CPU_EXCEPTION_TYPE_1 0x0 int rtw89_fw_h2c_trigger_cpu_exception(struct rtw89_dev *rtwdev) { + struct rtw89_h2c_trig_cpu_except *h2c; + u32 cpu_exception_type_def; + u32 len = sizeof(*h2c); struct sk_buff *skb; int ret; - skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, H2C_FW_CPU_EXCEPTION_LEN); + if (RTW89_CHK_FW_FEATURE(CRASH_TRIGGER_TYPE_1, &rtwdev->fw)) + cpu_exception_type_def = H2C_FW_CPU_EXCEPTION_TYPE_1; + else if (RTW89_CHK_FW_FEATURE(CRASH_TRIGGER_TYPE_0, &rtwdev->fw)) + cpu_exception_type_def = H2C_FW_CPU_EXCEPTION_TYPE_0; + else + return -EOPNOTSUPP; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { rtw89_err(rtwdev, "failed to alloc skb for fw cpu exception\n"); return -ENOMEM; } - skb_put(skb, H2C_FW_CPU_EXCEPTION_LEN); - RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(skb->data, - H2C_FW_CPU_EXCEPTION_TYPE_DEF); + skb_put(skb, len); + h2c = (struct rtw89_h2c_trig_cpu_except *)skb->data; + + h2c->w0 = le32_encode_bits(cpu_exception_type_def, + RTW89_H2C_CPU_EXCEPTION_TYPE); rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, H2C_CAT_TEST, H2C_CL_FW_STATUS_TEST, H2C_FUNC_CPU_EXCEPTION, 0, 0, - H2C_FW_CPU_EXCEPTION_LEN); + len); ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { rtw89_err(rtwdev, "failed to send h2c\n"); - goto fail; + dev_kfree_skb_any(skb); + return ret; } return 0; - -fail: - dev_kfree_skb_any(skb); - return ret; } #define H2C_PKT_DROP_LEN 24 diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 0fcc824e41be..3de29137b113 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -87,6 +87,9 @@ struct rtw89_c2hreg_phycap { #define RTW89_C2HREG_AOAC_RPT_2_W3_IGTK_IPN_IV_6 GENMASK(7, 0) #define RTW89_C2HREG_AOAC_RPT_2_W3_IGTK_IPN_IV_7 GENMASK(15, 8) +#define RTW89_C2HREG_PS_LEAVE_ACK_RET GENMASK(7, 0) +#define RTW89_C2HREG_PS_LEAVE_ACK_MACID GENMASK(31, 16) + struct rtw89_h2creg_hdr { u32 w0; }; @@ -112,6 +115,8 @@ struct rtw89_h2creg_sch_tx_en { #define RTW89_C2HREG_HDR_LEN 2 #define RTW89_H2CREG_HDR_LEN 2 #define RTW89_C2H_TIMEOUT 1000000 +#define RTW89_C2H_TIMEOUT_USB 4000 + struct rtw89_mac_c2h_info { u8 id; u8 content_len; @@ -154,6 +159,7 @@ enum rtw89_mac_c2h_type { RTW89_FWCMD_C2HREG_FUNC_TX_PAUSE_RPT, RTW89_FWCMD_C2HREG_FUNC_WOW_CPUIO_RX_ACK = 0xA, RTW89_FWCMD_C2HREG_FUNC_PHY_CAP_PART1 = 0xC, + RTW89_FWCMD_C2HREG_FUNC_PS_LEAVE_ACK = 0xD, RTW89_FWCMD_C2HREG_FUNC_NULL = 0xFF, }; @@ -237,6 +243,7 @@ enum rtw89_chan_type { RTW89_CHAN_OPERATE = 0, RTW89_CHAN_ACTIVE, RTW89_CHAN_DFS, + RTW89_CHAN_EXTRA_OP, }; enum rtw89_p2pps_action { @@ -316,8 +323,10 @@ struct rtw89_fw_macid_pause_sleep_grp { #define RTW89_H2C_MAX_SIZE 2048 #define RTW89_CHANNEL_TIME 45 #define RTW89_CHANNEL_TIME_6G 20 +#define RTW89_CHANNEL_TIME_EXTRA_OP 30 #define RTW89_DFS_CHAN_TIME 105 #define RTW89_OFF_CHAN_TIME 100 +#define RTW89_P2P_CHAN_TIME 105 #define RTW89_DWELL_TIME 20 #define RTW89_DWELL_TIME_6G 10 #define RTW89_SCAN_WIDTH 0 @@ -352,7 +361,8 @@ struct rtw89_mac_chinfo_ax { u8 tx_null:1; u8 rand_seq_num:1; u8 cfg_tx_pwr:1; - u8 rsvd0: 4; + u8 macid_tx: 1; + u8 rsvd0: 3; u8 pkt_id[RTW89_SCANOFLD_MAX_SSID]; u16 tx_pwr_idx; u8 rsvd1; @@ -1825,10 +1835,11 @@ struct rtw89_h2c_lps_ml_cmn_info { u8 dup_bcn_ofst[RTW89_PHY_NUM]; } __packed; -static inline void RTW89_SET_FWCMD_CPU_EXCEPTION_TYPE(void *cmd, u32 val) -{ - le32p_replace_bits((__le32 *)cmd, val, GENMASK(31, 0)); -} +struct rtw89_h2c_trig_cpu_except { + __le32 w0; +} __packed; + +#define RTW89_H2C_CPU_EXCEPTION_TYPE GENMASK(31, 0) static inline void RTW89_SET_FWCMD_PKT_DROP_SEL(void *cmd, u32 val) { @@ -2247,6 +2258,11 @@ struct rtw89_h2c_cxrole_v8 { struct rtw89_btc_wl_role_info_v8_u32 _u32; } __packed; +struct rtw89_h2c_cxosi { + struct rtw89_h2c_cxhdr_v7 hdr; + struct rtw89_btc_fbtc_outsrc_set_info osi; +} __packed; + struct rtw89_h2c_cxinit { struct rtw89_h2c_cxhdr hdr; u8 ant_type; @@ -2674,6 +2690,7 @@ struct rtw89_h2c_chinfo_elem { #define RTW89_H2C_CHINFO_W1_TX_NULL BIT(25) #define RTW89_H2C_CHINFO_W1_RANDOM BIT(26) #define RTW89_H2C_CHINFO_W1_CFG_TX BIT(27) +#define RTW89_H2C_CHINFO_W1_MACID_TX BIT(29) #define RTW89_H2C_CHINFO_W2_PKT0 GENMASK(7, 0) #define RTW89_H2C_CHINFO_W2_PKT1 GENMASK(15, 8) #define RTW89_H2C_CHINFO_W2_PKT2 GENMASK(23, 16) @@ -2773,6 +2790,7 @@ struct rtw89_h2c_scanofld { #define RTW89_H2C_SCANOFLD_W2_SLOW_PD GENMASK(23, 16) #define RTW89_H2C_SCANOFLD_W3_TSF_HIGH GENMASK(31, 0) #define RTW89_H2C_SCANOFLD_W4_TSF_LOW GENMASK(31, 0) +#define RTW89_H2C_SCANOFLD_W6_SECOND_MACID GENMASK(31, 24) struct rtw89_h2c_scanofld_be_macc_role { __le32 w0; @@ -2806,6 +2824,7 @@ struct rtw89_h2c_scanofld_be_opch { #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_PKTS_CTRL GENMASK(7, 0) #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SW_DEF GENMASK(15, 8) #define RTW89_H2C_SCANOFLD_BE_OPCH_W2_SS GENMASK(18, 16) +#define RTW89_H2C_SCANOFLD_BE_OPCH_W2_TXBCN BIT(19) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT0 GENMASK(7, 0) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT1 GENMASK(15, 8) #define RTW89_H2C_SCANOFLD_BE_OPCH_W3_PKT2 GENMASK(23, 16) @@ -3553,6 +3572,8 @@ struct rtw89_fw_c2h_attr { u8 class; u8 func; u16 len; + u8 is_scan_event: 1; + u8 scan_seq: 2; }; static inline struct rtw89_fw_c2h_attr *RTW89_SKB_C2H_CB(struct sk_buff *skb) @@ -4330,6 +4351,7 @@ enum rtw89_mrc_h2c_func { #define H2C_FUNC_OUTSRC_RA_MACIDCFG 0x0 #define H2C_CL_OUTSRC_DM 0x2 +#define H2C_FUNC_FW_MCC_DIG 0x6 #define H2C_FUNC_FW_LPS_CH_INFO 0xb #define H2C_FUNC_FW_LPS_ML_CMN_INFO 0xe @@ -4337,6 +4359,7 @@ enum rtw89_mrc_h2c_func { #define H2C_CL_OUTSRC_RF_REG_B 0x9 #define H2C_CL_OUTSRC_RF_FW_NOTIFY 0xa #define H2C_FUNC_OUTSRC_RF_GET_MCCCH 0x2 +#define H2C_FUNC_OUTSRC_RF_PS_INFO 0x10 #define H2C_CL_OUTSRC_RF_FW_RFK 0xb enum rtw89_rfk_offload_h2c_func { @@ -4350,6 +4373,14 @@ enum rtw89_rfk_offload_h2c_func { }; struct rtw89_fw_h2c_rf_get_mccch { + __le32 ch_0_0; + __le32 ch_0_1; + __le32 ch_1_0; + __le32 ch_1_1; + __le32 current_channel; +} __packed; + +struct rtw89_fw_h2c_rf_get_mccch_v0 { __le32 ch_0; __le32 ch_1; __le32 band_0; @@ -4358,9 +4389,36 @@ struct rtw89_fw_h2c_rf_get_mccch { __le32 current_band_type; } __packed; +struct rtw89_h2c_mcc_dig { + __le32 w0; + __le32 w1; + __le32 w2; +} __packed; + +#define RTW89_H2C_MCC_DIG_W0_REG_CNT GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W0_DM_EN BIT(8) +#define RTW89_H2C_MCC_DIG_W0_IDX GENMASK(10, 9) +#define RTW89_H2C_MCC_DIG_W0_SET BIT(11) +#define RTW89_H2C_MCC_DIG_W0_PHY0_EN BIT(12) +#define RTW89_H2C_MCC_DIG_W0_PHY1_EN BIT(13) +#define RTW89_H2C_MCC_DIG_W0_CENTER_CH GENMASK(23, 16) +#define RTW89_H2C_MCC_DIG_W0_BAND_TYPE GENMASK(31, 24) +#define RTW89_H2C_MCC_DIG_W1_ADDR_LSB GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W1_ADDR_MSB GENMASK(15, 8) +#define RTW89_H2C_MCC_DIG_W1_BMASK_LSB GENMASK(23, 16) +#define RTW89_H2C_MCC_DIG_W1_BMASK_MSB GENMASK(31, 24) +#define RTW89_H2C_MCC_DIG_W2_VAL_LSB GENMASK(7, 0) +#define RTW89_H2C_MCC_DIG_W2_VAL_MSB GENMASK(15, 8) + #define NUM_OF_RTW89_FW_RFK_PATH 2 #define NUM_OF_RTW89_FW_RFK_TBL 3 +struct rtw89_h2c_rf_ps_info { + __le32 rf18[NUM_OF_RTW89_FW_RFK_PATH]; + __le32 mlo_mode; + u8 pri_ch[NUM_OF_RTW89_FW_RFK_PATH]; +} __packed; + struct rtw89_fw_h2c_rfk_pre_info_common { struct { __le32 ch[NUM_OF_RTW89_FW_RFK_PATH][NUM_OF_RTW89_FW_RFK_TBL]; @@ -4435,13 +4493,25 @@ struct rtw89_h2c_rf_tssi { u8 pg_thermal[2]; u8 ftable[2][128]; u8 tssi_mode; + u8 rfe_type; } __packed; -struct rtw89_h2c_rf_iqk { +struct rtw89_h2c_rf_iqk_v0 { __le32 phy_idx; __le32 dbcc; } __packed; +struct rtw89_h2c_rf_iqk { + u8 len; + u8 ktype; + u8 phy; + u8 kpath; + u8 band; + u8 bw; + u8 ch; + u8 cv; +} __packed; + struct rtw89_h2c_rf_dpk { u8 len; u8 phy; @@ -4629,6 +4699,7 @@ struct rtw89_c2h_rf_tas_info { #define RTW89_FW_BACKTRACE_KEY 0xBACEBACE #define FWDL_WAIT_CNT 400000 +#define FWDL_WAIT_CNT_USB 3200 int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev, enum rtw89_fwdl_check_type type); int rtw89_fw_recognize(struct rtw89_dev *rtwdev); @@ -4670,6 +4741,9 @@ int rtw89_fw_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_txtime_cmac_tbl_g7(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); +int rtw89_fw_h2c_punctured_cmac_tbl_g7(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured); int rtw89_fw_h2c_txpath_cmac_tbl(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); int rtw89_fw_h2c_update_beacon(struct rtw89_dev *rtwdev, @@ -4686,6 +4760,7 @@ int rtw89_fw_h2c_dctl_sec_cam_v2(struct rtw89_dev *rtwdev, struct rtw89_sta_link *rtwsta_link); void rtw89_fw_c2h_irqsafe(struct rtw89_dev *rtwdev, struct sk_buff *c2h); void rtw89_fw_c2h_work(struct wiphy *wiphy, struct wiphy_work *work); +void rtw89_fw_c2h_purge_obsoleted_scan_events(struct rtw89_dev *rtwdev); int rtw89_fw_h2c_role_maintain(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, @@ -4713,6 +4788,7 @@ int rtw89_fw_h2c_cxdrv_role_v1(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_role_v2(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_role_v7(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_role_v8(struct rtw89_dev *rtwdev, u8 type); +int rtw89_fw_h2c_cxdrv_osi_info(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_ctrl(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_ctrl_v7(struct rtw89_dev *rtwdev, u8 type); int rtw89_fw_h2c_cxdrv_trx(struct rtw89_dev *rtwdev, u8 type); @@ -4732,8 +4808,12 @@ int rtw89_fw_h2c_rf_reg(struct rtw89_dev *rtwdev, struct rtw89_fw_h2c_rf_reg_info *info, u16 len, u8 page); int rtw89_fw_h2c_rf_ntfy_mcc(struct rtw89_dev *rtwdev); +int rtw89_fw_h2c_rf_ps_info(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif); int rtw89_fw_h2c_rf_pre_ntfy(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +int rtw89_fw_h2c_mcc_dig(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_idx chanctx_idx, + u8 mcc_role_idx, u8 pd_val, bool en); int rtw89_fw_h2c_rf_tssi(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, enum rtw89_tssi_mode tssi_mode); int rtw89_fw_h2c_rf_iqk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, @@ -4815,9 +4895,8 @@ int rtw89_fw_h2c_pkt_drop(struct rtw89_dev *rtwdev, const struct rtw89_pkt_drop_params *params); int rtw89_fw_h2c_p2p_act(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, - struct ieee80211_bss_conf *bss_conf, struct ieee80211_p2p_noa_desc *desc, - u8 act, u8 noa_id); + u8 act, u8 noa_id, u8 ctwindow_oppps); int rtw89_fw_h2c_tsf32_toggle(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool en); @@ -4969,6 +5048,19 @@ int rtw89_chip_h2c_txtime_cmac_tbl(struct rtw89_dev *rtwdev, } static inline +int rtw89_chip_h2c_punctured_cmac_tbl(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + u16 punctured) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + if (!chip->ops->h2c_punctured_cmac_tbl) + return 0; + + return chip->ops->h2c_punctured_cmac_tbl(rtwdev, rtwvif_link, punctured); +} + +static inline int rtw89_chip_h2c_ba_cam(struct rtw89_dev *rtwdev, struct rtw89_sta *rtwsta, bool valid, struct ieee80211_ampdu_params *params) { diff --git a/drivers/net/wireless/realtek/rtw89/mac.c b/drivers/net/wireless/realtek/rtw89/mac.c index 9f0e30e75009..5a5da9d9c0c5 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -88,7 +88,7 @@ int rtw89_mac_write_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 val) ret = read_poll_timeout(rtw89_read8, lte_ctrl, (lte_ctrl & BIT(5)) != 0, 50, 50000, false, rtwdev, R_AX_LTE_CTRL + 3); - if (ret) + if (ret && !test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) rtw89_err(rtwdev, "[ERR]lte not ready(W)\n"); rtw89_write32(rtwdev, R_AX_LTE_WDATA, val); @@ -104,7 +104,7 @@ int rtw89_mac_read_lte(struct rtw89_dev *rtwdev, const u32 offset, u32 *val) ret = read_poll_timeout(rtw89_read8, lte_ctrl, (lte_ctrl & BIT(5)) != 0, 50, 50000, false, rtwdev, R_AX_LTE_CTRL + 3); - if (ret) + if (ret && !test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) rtw89_err(rtwdev, "[ERR]lte not ready(W)\n"); rtw89_write32(rtwdev, R_AX_LTE_CTRL, 0x800F0000 | offset); @@ -875,31 +875,30 @@ EXPORT_SYMBOL(rtw89_mac_set_err_status); static int hfc_reset_param(struct rtw89_dev *rtwdev) { + const struct rtw89_hfc_param_ini *param_ini, *param_inis; struct rtw89_hfc_param *param = &rtwdev->mac.hfc_param; - struct rtw89_hfc_param_ini param_ini = {NULL}; u8 qta_mode = rtwdev->mac.dle_info.qta_mode; - switch (rtwdev->hci.type) { - case RTW89_HCI_TYPE_PCIE: - param_ini = rtwdev->chip->hfc_param_ini[qta_mode]; - param->en = 0; - break; - default: + param_inis = rtwdev->chip->hfc_param_ini[rtwdev->hci.type]; + if (!param_inis) return -EINVAL; - } - if (param_ini.pub_cfg) - param->pub_cfg = *param_ini.pub_cfg; + param_ini = ¶m_inis[qta_mode]; + + param->en = 0; - if (param_ini.prec_cfg) - param->prec_cfg = *param_ini.prec_cfg; + if (param_ini->pub_cfg) + param->pub_cfg = *param_ini->pub_cfg; - if (param_ini.ch_cfg) - param->ch_cfg = param_ini.ch_cfg; + if (param_ini->prec_cfg) + param->prec_cfg = *param_ini->prec_cfg; + + if (param_ini->ch_cfg) + param->ch_cfg = param_ini->ch_cfg; memset(¶m->ch_info, 0, sizeof(param->ch_info)); memset(¶m->pub_info, 0, sizeof(param->pub_info)); - param->mode = param_ini.mode; + param->mode = param_ini->mode; return 0; } @@ -1441,6 +1440,23 @@ void rtw89_mac_notify_wake(struct rtw89_dev *rtwdev) rtw89_mac_send_rpwm(rtwdev, state, true); } +static void rtw89_mac_power_switch_boot_mode(struct rtw89_dev *rtwdev) +{ + u32 boot_mode; + + if (rtwdev->hci.type != RTW89_HCI_TYPE_USB) + return; + + boot_mode = rtw89_read32_mask(rtwdev, R_AX_GPIO_MUXCFG, B_AX_BOOT_MODE); + if (!boot_mode) + return; + + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFN_ONMAC); + rtw89_write32_clr(rtwdev, R_AX_SYS_STATUS1, B_AX_AUTO_WLPON); + rtw89_write32_clr(rtwdev, R_AX_GPIO_MUXCFG, B_AX_BOOT_MODE); + rtw89_write32_clr(rtwdev, R_AX_RSV_CTRL, B_AX_R_DIS_PRST); +} + static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) { #define PWR_ACT 1 @@ -1451,6 +1467,8 @@ static int rtw89_mac_power_switch(struct rtw89_dev *rtwdev, bool on) int ret; u8 val; + rtw89_mac_power_switch_boot_mode(rtwdev); + if (on) { cfg_seq = chip->pwr_on_seq; cfg_func = chip->ops->pwr_on_func; @@ -1646,6 +1664,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* 8852C PCIE SCC */ .wde_size19 = {RTW89_WDE_PG_64, 3328, 0,}, .wde_size23 = {RTW89_WDE_PG_64, 1022, 2,}, + /* 8852B USB2.0/USB3.0 SCC */ + .wde_size25 = {RTW89_WDE_PG_64, 162, 94,}, /* PCIE */ .ple_size0 = {RTW89_PLE_PG_128, 1520, 16,}, .ple_size0_v1 = {RTW89_PLE_PG_128, 2688, 240, 212992,}, @@ -1661,6 +1681,10 @@ const struct rtw89_mac_size_set rtw89_mac_size = { .ple_size18 = {RTW89_PLE_PG_128, 2544, 16,}, /* 8852C PCIE SCC */ .ple_size19 = {RTW89_PLE_PG_128, 1904, 16,}, + /* 8852B USB2.0 SCC */ + .ple_size32 = {RTW89_PLE_PG_128, 620, 20,}, + /* 8852B USB3.0 SCC */ + .ple_size33 = {RTW89_PLE_PG_128, 632, 8,}, /* PCIE 64 */ .wde_qt0 = {3792, 196, 0, 107,}, .wde_qt0_v1 = {3302, 6, 0, 20,}, @@ -1675,6 +1699,8 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* 8852C PCIE SCC */ .wde_qt18 = {3228, 60, 0, 40,}, .wde_qt23 = {958, 48, 0, 16,}, + /* 8852B USB2.0/USB3.0 SCC */ + .wde_qt25 = {152, 2, 0, 8,}, .ple_qt0 = {320, 320, 32, 16, 13, 13, 292, 292, 64, 18, 1, 4, 0,}, .ple_qt1 = {320, 320, 32, 16, 1316, 1316, 1595, 1595, 1367, 1321, 1, 1307, 0,}, /* PCIE SCC */ @@ -1698,6 +1724,13 @@ const struct rtw89_mac_size_set rtw89_mac_size = { /* PCIE 64 */ .ple_qt58 = {147, 0, 16, 20, 157, 13, 229, 0, 172, 14, 24, 0,}, .ple_qt59 = {147, 0, 32, 20, 1860, 13, 2025, 0, 1879, 14, 24, 0,}, + /* USB2.0 52B SCC */ + .ple_qt72 = {130, 0, 16, 48, 4, 13, 322, 0, 32, 14, 8, 0, 0,}, + /* USB2.0 52B 92K */ + .ple_qt73 = {130, 0, 32, 48, 37, 13, 355, 0, 65, 14, 24, 0, 0,}, + /* USB3.0 52B 92K */ + .ple_qt74 = {286, 0, 16, 48, 4, 13, 178, 0, 32, 14, 8, 0, 0,}, + .ple_qt75 = {286, 0, 32, 48, 37, 13, 211, 0, 65, 14, 24, 0, 0,}, /* 8852A PCIE WOW */ .ple_qt_52a_wow = {264, 0, 32, 20, 64, 13, 1005, 0, 64, 128, 120,}, /* 8852B PCIE WOW */ @@ -1717,12 +1750,13 @@ static const struct rtw89_dle_mem *get_dle_mem_cfg(struct rtw89_dev *rtwdev, enum rtw89_qta_mode mode) { struct rtw89_mac_info *mac = &rtwdev->mac; - const struct rtw89_dle_mem *cfg; + const struct rtw89_dle_mem *cfg, *cfgs; - cfg = &rtwdev->chip->dle_mem[mode]; - if (!cfg) + cfgs = rtwdev->chip->dle_mem[rtwdev->hci.dle_type]; + if (!cfgs) return NULL; + cfg = &cfgs[mode]; if (cfg->mode != mode) { rtw89_warn(rtwdev, "qta mode unmatch!\n"); return NULL; @@ -4388,7 +4422,33 @@ static void rtw89_mac_port_cfg_tx_sw_by_nettype(struct rtw89_dev *rtwdev, rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); } -void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) +static void rtw89_mac_enable_ap_bcn_by_chan(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + const struct rtw89_chan *to_match, + bool en) +{ + const struct rtw89_chan *chan; + + if (rtwvif_link->net_type != RTW89_NET_TYPE_AP_MODE) + return; + + if (!to_match) + goto doit; + + /* @to_match may not be in the same domain as return of calling + * rtw89_chan_get(). So, cannot compare their addresses directly. + */ + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + if (chan->channel != to_match->channel) + return; + +doit: + rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); +} + +static void rtw89_mac_enable_aps_bcn_by_chan(struct rtw89_dev *rtwdev, + const struct rtw89_chan *to_match, + bool en) { struct rtw89_vif_link *rtwvif_link; struct rtw89_vif *rtwvif; @@ -4396,8 +4456,13 @@ void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) rtw89_for_each_rtwvif(rtwdev, rtwvif) rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) - if (rtwvif_link->net_type == RTW89_NET_TYPE_AP_MODE) - rtw89_mac_port_cfg_tx_sw(rtwdev, rtwvif_link, en); + rtw89_mac_enable_ap_bcn_by_chan(rtwdev, rtwvif_link, + to_match, en); +} + +void rtw89_mac_enable_beacon_for_ap_vifs(struct rtw89_dev *rtwdev, bool en) +{ + rtw89_mac_enable_aps_bcn_by_chan(rtwdev, NULL, en); } static void rtw89_mac_port_cfg_bcn_intv(struct rtw89_dev *rtwdev, @@ -4891,11 +4956,22 @@ rtw89_mac_c2h_macid_pause(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len { } -static bool rtw89_is_op_chan(struct rtw89_dev *rtwdev, u8 band, u8 channel) +static const struct rtw89_chan * +rtw89_hw_scan_search_op_chan(struct rtw89_dev *rtwdev, u8 band, u8 channel) { + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; const struct rtw89_chan *op = &rtwdev->scan_info.op_chan; - return band == op->band_type && channel == op->primary_channel; + if (band == op->band_type && channel == op->primary_channel) + return op; + + if (scan_info->extra_op.set) { + op = &scan_info->extra_op.chan; + if (band == op->band_type && channel == op->primary_channel) + return op; + } + + return NULL; } static void @@ -4905,6 +4981,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, const struct rtw89_c2h_scanofld *c2h = (const struct rtw89_c2h_scanofld *)skb->data; struct rtw89_vif_link *rtwvif_link = rtwdev->scan_info.scanning_vif; + const struct rtw89_chan *op_chan; struct rtw89_vif *rtwvif; struct rtw89_chan new; u16 actual_period, expect_period; @@ -4960,8 +5037,9 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, switch (reason) { case RTW89_SCAN_LEAVE_OP_NOTIFY: case RTW89_SCAN_LEAVE_CH_NOTIFY: - if (rtw89_is_op_chan(rtwdev, band, chan)) { - rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, false); + op_chan = rtw89_hw_scan_search_op_chan(rtwdev, band, chan); + if (op_chan) { + rtw89_mac_enable_aps_bcn_by_chan(rtwdev, op_chan, false); ieee80211_stop_queues(rtwdev->hw); } return; @@ -4971,6 +5049,7 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, if (rtwvif_link && rtwvif->scan_req && !list_empty(&rtwdev->scan_info.chan_list)) { + rtwdev->scan_info.delay = 0; ret = rtw89_hw_scan_offload(rtwdev, rtwvif_link, true); if (ret) { rtw89_hw_scan_abort(rtwdev, rtwvif_link); @@ -4982,10 +5061,10 @@ rtw89_mac_c2h_scanofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb, break; case RTW89_SCAN_ENTER_OP_NOTIFY: case RTW89_SCAN_ENTER_CH_NOTIFY: - if (rtw89_is_op_chan(rtwdev, band, chan)) { - rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, - &rtwdev->scan_info.op_chan); - rtw89_mac_enable_beacon_for_ap_vifs(rtwdev, true); + op_chan = rtw89_hw_scan_search_op_chan(rtwdev, band, chan); + if (op_chan) { + rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, op_chan); + rtw89_mac_enable_aps_bcn_by_chan(rtwdev, op_chan, true); ieee80211_wake_queues(rtwdev->hw); } else { rtw89_chan_create(&new, chan, chan, band, @@ -5009,6 +5088,7 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l const struct rtw89_c2h_mac_bcnfltr_rpt *c2h = (const struct rtw89_c2h_mac_bcnfltr_rpt *)skb->data; u8 type, event, mac_id; + bool start_detect; s8 sig; type = le32_get_bits(c2h->w2, RTW89_C2H_MAC_BCNFLTR_RPT_W2_TYPE); @@ -5026,10 +5106,15 @@ rtw89_mac_bcn_fltr_rpt(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_l switch (type) { case RTW89_BCN_FLTR_BEACON_LOSS: if (!rtwdev->scanning && !rtwvif->offchan && - !rtwvif_link->noa_once.in_duration) + !rtwvif_link->noa_once.in_duration) { + start_detect = rtw89_mcc_detect_go_bcn(rtwdev, rtwvif_link); + if (start_detect) + return; + ieee80211_connection_loss(vif); - else + } else { rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, true); + } return; case RTW89_BCN_FLTR_NOTIFY: nl_event = NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH; @@ -5080,6 +5165,7 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le { /* N.B. This will run in interrupt context. */ struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; struct rtw89_wait_info *ps_wait = &rtwdev->mac.ps_wait; const struct rtw89_c2h_done_ack *c2h = (const struct rtw89_c2h_done_ack *)skb_c2h->data; @@ -5122,9 +5208,11 @@ rtw89_mac_c2h_done_ack(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 le h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN; break; case H2C_FUNC_SCANOFLD: + scan_info->seq++; cond = RTW89_SCANOFLD_WAIT_COND_START; break; case H2C_FUNC_SCANOFLD_BE: + scan_info->seq++; cond = RTW89_SCANOFLD_BE_WAIT_COND_START; h2c_return &= RTW89_C2H_SCAN_DONE_ACK_RETURN; break; @@ -5621,10 +5709,15 @@ static void rtw89_mac_c2h_scanofld_rsp_atomic(struct rtw89_dev *rtwdev, const struct rtw89_c2h_scanofld *c2h = (const struct rtw89_c2h_scanofld *)skb->data; struct rtw89_wait_info *fw_ofld_wait = &rtwdev->mac.fw_ofld_wait; + struct rtw89_hw_scan_info *scan_info = &rtwdev->scan_info; + struct rtw89_fw_c2h_attr *attr = RTW89_SKB_C2H_CB(skb); struct rtw89_completion_data data = {}; unsigned int cond; u8 status, reason; + attr->is_scan_event = 1; + attr->scan_seq = scan_info->seq; + status = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_STATUS); reason = le32_get_bits(c2h->w2, RTW89_C2H_SCANOFLD_W2_RSN); data.err = status != RTW89_SCAN_STATUS_SUCCESS; @@ -5717,6 +5810,7 @@ void rtw89_mac_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, handler = rtw89_mac_c2h_ap_handler[func]; break; case RTW89_MAC_C2H_CLASS_FWDBG: + case RTW89_MAC_C2H_CLASS_ROLE: return; default: rtw89_info(rtwdev, "MAC c2h class %d not support\n", class); @@ -5779,7 +5873,7 @@ int rtw89_mac_cfg_ppdu_status_ax(struct rtw89_dev *rtwdev, u8 mac_idx, bool enab rtw89_write32(rtwdev, reg, B_AX_PPDU_STAT_RPT_EN | B_AX_APP_MAC_INFO_RPT | - B_AX_APP_RX_CNT_RPT | B_AX_APP_PLCP_HDR_RPT | + B_AX_APP_PLCP_HDR_RPT | B_AX_PPDU_STAT_RPT_CRC32); rtw89_write32_mask(rtwdev, R_AX_HW_RPT_FWD, B_AX_FWD_PPDU_STAT_MASK, RTW89_PRPT_DEST_HOST); @@ -5862,13 +5956,15 @@ int rtw89_mac_coex_init(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex ret = rtw89_mac_read_lte(rtwdev, R_AX_LTE_SW_CFG_2, &val32); if (ret) { - rtw89_err(rtwdev, "Read R_AX_LTE_SW_CFG_2 fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Read R_AX_LTE_SW_CFG_2 fail!\n"); return ret; } val32 = val32 & B_AX_WL_RX_CTRL; ret = rtw89_mac_write_lte(rtwdev, R_AX_LTE_SW_CFG_2, val32); if (ret) { - rtw89_err(rtwdev, "Write R_AX_LTE_SW_CFG_2 fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Write R_AX_LTE_SW_CFG_2 fail!\n"); return ret; } @@ -5992,7 +6088,8 @@ int rtw89_mac_cfg_gnt(struct rtw89_dev *rtwdev, ret = rtw89_mac_write_lte(rtwdev, R_AX_LTE_SW_CFG_1, val); if (ret) { - rtw89_err(rtwdev, "Write LTE fail!\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "Write LTE fail!\n"); return ret; } @@ -6843,10 +6940,16 @@ int rtw89_fwdl_check_path_ready_ax(struct rtw89_dev *rtwdev, bool h2c_or_fwdl) { u8 check = h2c_or_fwdl ? B_AX_H2C_PATH_RDY : B_AX_FWDL_PATH_RDY; + u32 timeout; u8 val; + if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + timeout = FWDL_WAIT_CNT_USB; + else + timeout = FWDL_WAIT_CNT; + return read_poll_timeout_atomic(rtw89_read8, val, val & check, - 1, FWDL_WAIT_CNT, false, + 1, timeout, false, rtwdev, R_AX_WCPU_FW_CTRL); } @@ -6869,6 +6972,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_ax = { .filter_model_addr = R_AX_FILTER_MODEL_ADDR, .indir_access_addr = R_AX_INDIR_ACCESS_ENTRY, .mem_base_addrs = rtw89_mac_mem_base_addrs_ax, + .mem_page_size = MAC_MEM_DUMP_PAGE_SIZE_AX, .rx_fltr = R_AX_RX_FLTR_OPT, .port_base = &rtw89_port_base_ax, .agg_len_ht = R_AX_AGG_LEN_HT_0, diff --git a/drivers/net/wireless/realtek/rtw89/mac.h b/drivers/net/wireless/realtek/rtw89/mac.h index 8013c852d5be..241e89983c4a 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.h +++ b/drivers/net/wireless/realtek/rtw89/mac.h @@ -6,9 +6,12 @@ #define __RTW89_MAC_H__ #include "core.h" +#include "fw.h" #include "reg.h" -#define MAC_MEM_DUMP_PAGE_SIZE 0x40000 +#define MAC_MEM_DUMP_PAGE_SIZE_AX 0x40000 +#define MAC_MEM_DUMP_PAGE_SIZE_BE 0x80000 + #define ADDR_CAM_ENT_SIZE 0x40 #define ADDR_CAM_ENT_SHORT_SIZE 0x20 #define BSSID_CAM_ENT_SIZE 0x08 @@ -469,6 +472,7 @@ enum rtw89_mac_c2h_class { RTW89_MAC_C2H_CLASS_MLO = 0xc, RTW89_MAC_C2H_CLASS_MRC = 0xe, RTW89_MAC_C2H_CLASS_AP = 0x18, + RTW89_MAC_C2H_CLASS_ROLE = 0x1b, RTW89_MAC_C2H_CLASS_MAX, }; @@ -921,6 +925,7 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size wde_size18; const struct rtw89_dle_size wde_size19; const struct rtw89_dle_size wde_size23; + const struct rtw89_dle_size wde_size25; const struct rtw89_dle_size ple_size0; const struct rtw89_dle_size ple_size0_v1; const struct rtw89_dle_size ple_size3_v1; @@ -930,6 +935,8 @@ struct rtw89_mac_size_set { const struct rtw89_dle_size ple_size9; const struct rtw89_dle_size ple_size18; const struct rtw89_dle_size ple_size19; + const struct rtw89_dle_size ple_size32; + const struct rtw89_dle_size ple_size33; const struct rtw89_wde_quota wde_qt0; const struct rtw89_wde_quota wde_qt0_v1; const struct rtw89_wde_quota wde_qt4; @@ -938,6 +945,7 @@ struct rtw89_mac_size_set { const struct rtw89_wde_quota wde_qt17; const struct rtw89_wde_quota wde_qt18; const struct rtw89_wde_quota wde_qt23; + const struct rtw89_wde_quota wde_qt25; const struct rtw89_ple_quota ple_qt0; const struct rtw89_ple_quota ple_qt1; const struct rtw89_ple_quota ple_qt4; @@ -952,6 +960,10 @@ struct rtw89_mac_size_set { const struct rtw89_ple_quota ple_qt57; const struct rtw89_ple_quota ple_qt58; const struct rtw89_ple_quota ple_qt59; + const struct rtw89_ple_quota ple_qt72; + const struct rtw89_ple_quota ple_qt73; + const struct rtw89_ple_quota ple_qt74; + const struct rtw89_ple_quota ple_qt75; const struct rtw89_ple_quota ple_qt_52a_wow; const struct rtw89_ple_quota ple_qt_52b_wow; const struct rtw89_ple_quota ple_qt_52bt_wow; @@ -969,6 +981,7 @@ struct rtw89_mac_gen_def { u32 filter_model_addr; u32 indir_access_addr; const u32 *mem_base_addrs; + u32 mem_page_size; u32 rx_fltr; const struct rtw89_port_reg *port_base; u32 agg_len_ht; @@ -1571,4 +1584,28 @@ void rtw89_fwdl_secure_idmem_share_mode(struct rtw89_dev *rtwdev, u8 mode) return mac->fwdl_secure_idmem_share_mode(rtwdev, mode); } + +static inline +int rtw89_mac_scan_offload(struct rtw89_dev *rtwdev, + struct rtw89_scan_option *option, + struct rtw89_vif_link *rtwvif_link, + bool wowlan) +{ + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + int ret; + + ret = mac->scan_offload(rtwdev, option, rtwvif_link, wowlan); + + if (option->enable) { + /* + * At this point, new scan request is acknowledged by firmware, + * so scan events of previous scan request become obsoleted. + * Purge the queued scan events to prevent interference to + * current new request. + */ + rtw89_fw_c2h_purge_obsoleted_scan_events(rtwdev); + } + + return ret; +} #endif diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c index a47971003bd4..c1ca6d741b32 100644 --- a/drivers/net/wireless/realtek/rtw89/mac80211.c +++ b/drivers/net/wireless/realtek/rtw89/mac80211.c @@ -72,7 +72,7 @@ static void rtw89_ops_stop(struct ieee80211_hw *hw, bool suspend) rtw89_core_stop(rtwdev); } -static int rtw89_ops_config(struct ieee80211_hw *hw, u32 changed) +static int rtw89_ops_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct rtw89_dev *rtwdev = hw->priv; @@ -112,6 +112,10 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, rtw89_vif_type_mapping(rtwvif_link, false); wiphy_work_init(&rtwvif_link->update_beacon_work, rtw89_core_update_beacon_work); + wiphy_delayed_work_init(&rtwvif_link->csa_beacon_work, rtw89_core_csa_beacon_work); + wiphy_delayed_work_init(&rtwvif_link->mcc_gc_detect_beacon_work, + rtw89_mcc_gc_detect_beacon_work); + INIT_LIST_HEAD(&rtwvif_link->general_pkt_list); rtw89_p2p_noa_once_init(rtwvif_link); @@ -122,6 +126,7 @@ static int __rtw89_ops_add_iface_link(struct rtw89_dev *rtwdev, rtwvif_link->chanctx_idx = RTW89_CHANCTX_0; rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; rtwvif_link->rand_tsf_done = false; + rtwvif_link->detect_bcn_count = 0; rcu_read_lock(); @@ -144,6 +149,9 @@ static void __rtw89_ops_remove_iface_link(struct rtw89_dev *rtwdev, lockdep_assert_wiphy(rtwdev->hw->wiphy); wiphy_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->update_beacon_work); + wiphy_delayed_work_cancel(rtwdev->hw->wiphy, &rtwvif_link->csa_beacon_work); + wiphy_delayed_work_cancel(rtwdev->hw->wiphy, + &rtwvif_link->mcc_gc_detect_beacon_work); rtw89_p2p_noa_once_deinit(rtwvif_link); @@ -1007,7 +1015,8 @@ static int rtw89_ops_ampdu_action(struct ieee80211_hw *hw, return 0; } -static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int rtw89_ops_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct rtw89_dev *rtwdev = hw->priv; @@ -1119,7 +1128,7 @@ static int rtw89_ops_set_bitrate_mask(struct ieee80211_hw *hw, } static -int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) +int rtw89_ops_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_ant) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_hal *hal = &rtwdev->hal; @@ -1142,7 +1151,8 @@ int rtw89_ops_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) } static -int rtw89_ops_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) +int rtw89_ops_get_antenna(struct ieee80211_hw *hw, int radio_idx, u32 *tx_ant, + u32 *rx_ant) { struct rtw89_dev *rtwdev = hw->priv; struct rtw89_hal *hal = &rtwdev->hal; @@ -1354,6 +1364,73 @@ static void rtw89_ops_unassign_vif_chanctx(struct ieee80211_hw *hw, rtw89_chanctx_ops_unassign_vif(rtwdev, rtwvif_link, ctx); } +static +int rtw89_ops_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + struct rtw89_dev *rtwdev = hw->priv; + bool replace; + int ret; + int i; + + lockdep_assert_wiphy(hw->wiphy); + + switch (mode) { + case CHANCTX_SWMODE_REASSIGN_VIF: + replace = false; + break; + case CHANCTX_SWMODE_SWAP_CONTEXTS: + replace = true; + break; + default: + return -EOPNOTSUPP; + } + + for (i = 0; i < n_vifs; i++) { + struct ieee80211_vif_chanctx_switch *p = &vifs[i]; + struct ieee80211_bss_conf *link_conf = p->link_conf; + struct rtw89_vif *rtwvif = vif_to_rtwvif(p->vif); + struct rtw89_vif_link *rtwvif_link; + + rtwvif_link = rtwvif->links[link_conf->link_id]; + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, + "%s: rtwvif link (link_id %u) is not active\n", + __func__, link_conf->link_id); + return -ENOLINK; + } + + ret = rtw89_chanctx_ops_reassign_vif(rtwdev, rtwvif_link, + p->old_ctx, p->new_ctx, + replace); + if (ret) + return ret; + } + + return 0; +} + +static void rtw89_ops_channel_switch_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_chan_def *chandef) +{ + struct rtw89_vif *rtwvif = vif_to_rtwvif(vif); + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_vif_link *rtwvif_link; + + BUILD_BUG_ON(RTW89_MLD_NON_STA_LINK_NUM != 1); + + rtwvif_link = rtw89_vif_get_link_inst(rtwvif, 0); + if (unlikely(!rtwvif_link)) { + rtw89_err(rtwdev, "chsw bcn: find no link on HW-0\n"); + return; + } + + wiphy_delayed_work_queue(hw->wiphy, &rtwvif_link->csa_beacon_work, 0); +} + static int rtw89_ops_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, @@ -1698,13 +1775,14 @@ static int rtw89_ops_suspend(struct ieee80211_hw *hw, lockdep_assert_wiphy(hw->wiphy); - set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + set_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(hw->wiphy, &rtwdev->track_ps_work); ret = rtw89_wow_suspend(rtwdev, wowlan); if (ret) { rtw89_warn(rtwdev, "failed to suspend for wow %d\n", ret); - clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); return 1; } @@ -1722,9 +1800,11 @@ static int rtw89_ops_resume(struct ieee80211_hw *hw) if (ret) rtw89_warn(rtwdev, "failed to resume for wow %d\n", ret); - clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WROK, rtwdev->flags); + clear_bit(RTW89_FLAG_FORBIDDEN_TRACK_WORK, rtwdev->flags); wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(hw->wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); return ret ? 1 : 0; } @@ -1805,6 +1885,8 @@ const struct ieee80211_ops rtw89_ops = { .change_chanctx = rtw89_ops_change_chanctx, .assign_vif_chanctx = rtw89_ops_assign_vif_chanctx, .unassign_vif_chanctx = rtw89_ops_unassign_vif_chanctx, + .switch_vif_chanctx = rtw89_ops_switch_vif_chanctx, + .channel_switch_beacon = rtw89_ops_channel_switch_beacon, .remain_on_channel = rtw89_ops_remain_on_channel, .cancel_remain_on_channel = rtw89_ops_cancel_remain_on_channel, .set_sar_specs = rtw89_ops_set_sar_specs, diff --git a/drivers/net/wireless/realtek/rtw89/mac_be.c b/drivers/net/wireless/realtek/rtw89/mac_be.c index 8c9d326dc907..0078080b3999 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -2567,6 +2567,7 @@ const struct rtw89_mac_gen_def rtw89_mac_gen_be = { .filter_model_addr = R_BE_FILTER_MODEL_ADDR, .indir_access_addr = R_BE_INDIR_ACCESS_ENTRY, .mem_base_addrs = rtw89_mac_mem_base_addrs_be, + .mem_page_size = MAC_MEM_DUMP_PAGE_SIZE_BE, .rx_fltr = R_BE_RX_FLTR_OPT, .port_base = &rtw89_port_base_be, .agg_len_ht = R_BE_AGG_LEN_HT_0, diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c index 064f6a940107..a669f2f843aa 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -2638,6 +2638,10 @@ static void rtw89_pci_set_dbg(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_AX_PCIE_DBG_CTRL, B_AX_ASFF_FULL_NO_STK | B_AX_EN_STUCK_DBG); + rtw89_write32_mask(rtwdev, R_AX_PCIE_EXP_CTRL, + B_AX_EN_STUCK_DBG | B_AX_ASFF_FULL_NO_STK, + B_AX_EN_STUCK_DBG); + if (rtwdev->chip->chip_id == RTL8852A) rtw89_write32_set(rtwdev, R_AX_PCIE_EXP_CTRL, B_AX_EN_CHKDSC_NO_RX_STUCK); @@ -4353,6 +4357,43 @@ static int __maybe_unused rtw89_pci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(rtw89_pm_ops, rtw89_pci_suspend, rtw89_pci_resume); EXPORT_SYMBOL(rtw89_pm_ops); +static pci_ers_result_t rtw89_pci_io_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + netif_device_detach(netdev); + + return PCI_ERS_RESULT_NEED_RESET; +} + +static pci_ers_result_t rtw89_pci_io_slot_reset(struct pci_dev *pdev) +{ + struct ieee80211_hw *hw = pci_get_drvdata(pdev); + struct rtw89_dev *rtwdev = hw->priv; + + rtw89_ser_notify(rtwdev, MAC_AX_ERR_ASSERTION); + + return PCI_ERS_RESULT_RECOVERED; +} + +static void rtw89_pci_io_resume(struct pci_dev *pdev) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + + /* ack any pending wake events, disable PME */ + pci_enable_wake(pdev, PCI_D0, 0); + + netif_device_attach(netdev); +} + +const struct pci_error_handlers rtw89_pci_err_handler = { + .error_detected = rtw89_pci_io_error_detected, + .slot_reset = rtw89_pci_io_slot_reset, + .resume = rtw89_pci_io_resume, +}; +EXPORT_SYMBOL(rtw89_pci_err_handler); + const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .isr_rdu = B_AX_RDU_INT, .isr_halt_c2h = B_AX_HALT_C2H_INT_EN, @@ -4449,6 +4490,7 @@ int rtw89_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) rtwdev->pci_info = info->bus.pci; rtwdev->hci.ops = &rtw89_pci_ops; rtwdev->hci.type = RTW89_HCI_TYPE_PCIE; + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_PCIE; rtwdev->hci.rpwm_addr = pci_info->rpwm_addr; rtwdev->hci.cpwm_addr = pci_info->cpwm_addr; diff --git a/drivers/net/wireless/realtek/rtw89/pci.h b/drivers/net/wireless/realtek/rtw89/pci.h index 79fef5f90140..52f527069da6 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -1622,6 +1622,7 @@ static inline bool rtw89_pci_ltr_is_err_reg_val(u32 val) extern const struct dev_pm_ops rtw89_pm_ops; extern const struct dev_pm_ops rtw89_pm_ops_be; +extern const struct pci_error_handlers rtw89_pci_err_handler; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_v1; extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be; diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 76a2e26d4a10..d607577b353c 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.c +++ b/drivers/net/wireless/realtek/rtw89/phy.c @@ -119,10 +119,12 @@ static u64 get_eht_mcs_ra_mask(u8 *max_nss, u8 start_mcs, u8 n_nss) return mask; } -static u64 get_eht_ra_mask(struct ieee80211_link_sta *link_sta) +static u64 get_eht_ra_mask(struct rtw89_vif_link *rtwvif_link, + struct ieee80211_link_sta *link_sta) { - struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; + struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); struct ieee80211_eht_mcs_nss_supp_20mhz_only *mcs_nss_20mhz; + struct ieee80211_sta_eht_cap *eht_cap = &link_sta->eht_cap; struct ieee80211_eht_mcs_nss_supp_bw *mcs_nss; u8 *he_phy_cap = link_sta->he_cap.he_cap_elem.phy_cap_info; @@ -136,8 +138,8 @@ static u64 get_eht_ra_mask(struct ieee80211_link_sta *link_sta) /* MCS 9, 11, 13 */ return get_eht_mcs_ra_mask(mcs_nss->rx_tx_max_nss, 9, 3); case IEEE80211_STA_RX_BW_20: - if (!(he_phy_cap[0] & - IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { + if (vif->type == NL80211_IFTYPE_AP && + !(he_phy_cap[0] & IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) { mcs_nss_20mhz = &eht_cap->eht_mcs_nss_supp.only_20mhz; /* MCS 7, 9, 11, 13 */ return get_eht_mcs_ra_mask(mcs_nss_20mhz->rx_tx_max_nss, 7, 4); @@ -332,7 +334,7 @@ static void rtw89_phy_ra_sta_update(struct rtw89_dev *rtwdev, /* Set the ra mask from sta's capability */ if (link_sta->eht_cap.has_eht) { mode |= RTW89_RA_MODE_EHT; - ra_mask |= get_eht_ra_mask(link_sta); + ra_mask |= get_eht_ra_mask(rtwvif_link, link_sta); if (rtwdev->hal.no_mcs_12_13) high_rate_masks = rtw89_ra_mask_eht_mcs0_11; @@ -895,7 +897,8 @@ static u32 rtw89_phy_read_rf_a(struct rtw89_dev *rtwdev, 30, false, rtwdev, R_SWSI_V1, B_SWSI_R_DATA_DONE_V1); if (ret) { - rtw89_err(rtwdev, "read swsi busy\n"); + if (!test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + rtw89_err(rtwdev, "read swsi busy\n"); return INV_RF_DATA; } @@ -5828,14 +5831,20 @@ void rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev) __rtw89_phy_env_monitor_track(rtwdev, bb); } -static bool rtw89_physts_ie_page_valid(enum rtw89_phy_status_bitmap *ie_page) +static bool rtw89_physts_ie_page_valid(struct rtw89_dev *rtwdev, + enum rtw89_phy_status_bitmap *ie_page) { + const struct rtw89_chip_info *chip = rtwdev->chip; + if (*ie_page >= RTW89_PHYSTS_BITMAP_NUM || *ie_page == RTW89_RSVD_9) return false; - else if (*ie_page > RTW89_RSVD_9) + else if (*ie_page > RTW89_RSVD_9 && *ie_page < RTW89_EHT_PKT) *ie_page -= 1; + if (*ie_page == RTW89_EHT_PKT && chip->chip_gen == RTW89_CHIP_AX) + return false; + return true; } @@ -5843,6 +5852,9 @@ static u32 rtw89_phy_get_ie_bitmap_addr(enum rtw89_phy_status_bitmap ie_page) { static const u8 ie_page_shift = 2; + if (ie_page == RTW89_EHT_PKT) + return R_PHY_STS_BITMAP_EHT; + return R_PHY_STS_BITMAP_ADDR_START + (ie_page << ie_page_shift); } @@ -5852,7 +5864,7 @@ static u32 rtw89_physts_get_ie_bitmap(struct rtw89_dev *rtwdev, { u32 addr; - if (!rtw89_physts_ie_page_valid(&ie_page)) + if (!rtw89_physts_ie_page_valid(rtwdev, &ie_page)) return 0; addr = rtw89_phy_get_ie_bitmap_addr(ie_page); @@ -5867,7 +5879,7 @@ static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, const struct rtw89_chip_info *chip = rtwdev->chip; u32 addr; - if (!rtw89_physts_ie_page_valid(&ie_page)) + if (!rtw89_physts_ie_page_valid(rtwdev, &ie_page)) return; if (chip->chip_id == RTL8852A) @@ -5877,21 +5889,6 @@ static void rtw89_physts_set_ie_bitmap(struct rtw89_dev *rtwdev, rtw89_phy_write32_idx(rtwdev, addr, MASKDWORD, val, phy_idx); } -static void rtw89_physts_enable_ie_bitmap(struct rtw89_dev *rtwdev, - enum rtw89_phy_status_bitmap bitmap, - enum rtw89_phy_status_ie_type ie, - bool enable, enum rtw89_phy_idx phy_idx) -{ - u32 val = rtw89_physts_get_ie_bitmap(rtwdev, bitmap, phy_idx); - - if (enable) - val |= BIT(ie); - else - val &= ~BIT(ie); - - rtw89_physts_set_ie_bitmap(rtwdev, bitmap, val, phy_idx); -} - static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, bool enable, enum rtw89_phy_idx phy_idx) @@ -5915,30 +5912,37 @@ static void rtw89_physts_enable_fail_report(struct rtw89_dev *rtwdev, static void __rtw89_physts_parsing_init(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { + const struct rtw89_chip_info *chip = rtwdev->chip; + u32 val; u8 i; rtw89_physts_enable_fail_report(rtwdev, false, phy_idx); for (i = 0; i < RTW89_PHYSTS_BITMAP_NUM; i++) { - if (i >= RTW89_CCK_PKT) - rtw89_physts_enable_ie_bitmap(rtwdev, i, - RTW89_PHYSTS_IE09_FTR_0, - true, phy_idx); - if ((i >= RTW89_CCK_BRK && i <= RTW89_VHT_MU) || - (i >= RTW89_RSVD_9 && i <= RTW89_CCK_PKT)) + if (i == RTW89_RSVD_9 || + (i == RTW89_EHT_PKT && chip->chip_gen == RTW89_CHIP_AX)) continue; - rtw89_physts_enable_ie_bitmap(rtwdev, i, - RTW89_PHYSTS_IE24_OFDM_TD_PATH_A, - true, phy_idx); - } - rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_VHT_PKT, - RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx); - rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_HE_PKT, - RTW89_PHYSTS_IE13_DL_MU_DEF, true, phy_idx); - /* force IE01 for channel index, only channel field is valid */ - rtw89_physts_enable_ie_bitmap(rtwdev, RTW89_CCK_PKT, - RTW89_PHYSTS_IE01_CMN_OFDM, true, phy_idx); + val = rtw89_physts_get_ie_bitmap(rtwdev, i, phy_idx); + if (i == RTW89_HE_MU || i == RTW89_VHT_MU) { + val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF); + } else if (i == RTW89_TRIG_BASE_PPDU) { + val |= BIT(RTW89_PHYSTS_IE13_DL_MU_DEF) | + BIT(RTW89_PHYSTS_IE01_CMN_OFDM); + } else if (i >= RTW89_CCK_PKT) { + val |= BIT(RTW89_PHYSTS_IE09_FTR_0); + + val &= ~(GENMASK(RTW89_PHYSTS_IE07_CMN_EXT_PATH_D, + RTW89_PHYSTS_IE04_CMN_EXT_PATH_A)); + + if (i == RTW89_CCK_PKT) + val |= BIT(RTW89_PHYSTS_IE01_CMN_OFDM); + else if (i >= RTW89_HT_PKT) + val |= BIT(RTW89_PHYSTS_IE20_DBG_OFDM_FD_USER_SEG_0); + } + + rtw89_physts_set_ie_bitmap(rtwdev, i, val, phy_idx); + } } static void rtw89_physts_parsing_init(struct rtw89_dev *rtwdev) @@ -6312,18 +6316,13 @@ static void rtw89_phy_dig_config_igi(struct rtw89_dev *rtwdev, } } -static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, - struct rtw89_bb_ctx *bb, - u8 rssi, bool enable) +static u8 rtw89_phy_dig_cal_under_region(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + const struct rtw89_chan *chan) { - const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, bb->phy_idx); - const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; enum rtw89_bandwidth cbw = chan->band_width; struct rtw89_dig_info *dig = &bb->dig; - u8 final_rssi = 0, under_region = dig->pd_low_th_ofst; - u8 ofdm_cca_th; - s8 cck_cca_th; - u32 pd_val = 0; + u8 under_region = dig->pd_low_th_ofst; if (rtwdev->chip->chip_gen == RTW89_CHIP_AX) under_region += PD_TH_SB_FLTR_CMP_VAL; @@ -6345,6 +6344,20 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, break; } + return under_region; +} + +static u32 __rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + u8 rssi, bool enable, + const struct rtw89_chan *chan) +{ + struct rtw89_dig_info *dig = &bb->dig; + u8 ofdm_cca_th, under_region; + u8 final_rssi; + u32 pd_val; + + under_region = rtw89_phy_dig_cal_under_region(rtwdev, bb, chan); dig->dyn_pd_th_max = dig->igi_rssi; final_rssi = min_t(u8, rssi, dig->igi_rssi); @@ -6357,10 +6370,28 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, "igi=%d, ofdm_ccaTH=%d, backoff=%d, PD_low=%d\n", final_rssi, ofdm_cca_th, under_region, pd_val); } else { + pd_val = 0; rtw89_debug(rtwdev, RTW89_DBG_DIG, "Dynamic PD th disabled, Set PD_low_bd=0\n"); } + return pd_val; +} + +static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + u8 rssi, bool enable) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, bb->phy_idx); + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_dig_info *dig = &bb->dig; + u8 final_rssi, under_region = dig->pd_low_th_ofst; + s8 cck_cca_th; + u32 pd_val; + + pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, rssi, enable, chan); + dig->bak_dig = pd_val; + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx); rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, @@ -6369,6 +6400,8 @@ static void rtw89_phy_dig_dyn_pd_th(struct rtw89_dev *rtwdev, if (!rtwdev->hal.support_cckpd) return; + final_rssi = min_t(u8, rssi, dig->igi_rssi); + under_region = rtw89_phy_dig_cal_under_region(rtwdev, bb, chan); cck_cca_th = max_t(s8, final_rssi - under_region, CCKPD_TH_MIN_RSSI); pd_val = (u32)(cck_cca_th - IGI_RSSI_MAX); @@ -6396,11 +6429,161 @@ void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) #define IGI_RSSI_MIN 10 #define ABS_IGI_MIN 0xc +static +void rtw89_phy_cal_igi_fa_rssi(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_dig_info *dig = &bb->dig; + u8 igi_min; + + rtw89_phy_dig_igi_offset_by_env(rtwdev, bb); + + igi_min = max_t(int, dig->igi_rssi - IGI_RSSI_MIN, 0); + dig->dyn_igi_max = min(igi_min + IGI_OFFSET_MAX, igi_max_performance_mode); + dig->dyn_igi_min = max(igi_min, ABS_IGI_MIN); + + if (dig->dyn_igi_max >= dig->dyn_igi_min) { + dig->igi_fa_rssi += dig->fa_rssi_ofst; + dig->igi_fa_rssi = clamp(dig->igi_fa_rssi, dig->dyn_igi_min, + dig->dyn_igi_max); + } else { + dig->igi_fa_rssi = dig->dyn_igi_max; + } +} + +struct rtw89_phy_iter_mcc_dig { + struct rtw89_vif_link *rtwvif_link; + bool has_sta; + u8 rssi_min; +}; + +static void rtw89_phy_set_mcc_dig(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct rtw89_bb_ctx *bb, + u8 rssi_min, u8 mcc_role_idx, + bool is_linked) +{ + struct rtw89_dig_info *dig = &bb->dig; + const struct rtw89_chan *chan; + u8 pd_val; + + if (is_linked) { + dig->igi_rssi = rssi_min >> 1; + dig->igi_fa_rssi = dig->igi_rssi; + } else { + rtw89_debug(rtwdev, RTW89_DBG_DIG, "RSSI update : NO Link\n"); + dig->igi_rssi = rssi_nolink; + dig->igi_fa_rssi = dig->igi_rssi; + } + + chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + rtw89_phy_cal_igi_fa_rssi(rtwdev, bb); + pd_val = __rtw89_phy_dig_dyn_pd_th(rtwdev, bb, dig->igi_fa_rssi, + is_linked, chan); + rtw89_fw_h2c_mcc_dig(rtwdev, rtwvif_link->chanctx_idx, + mcc_role_idx, pd_val, true); + + rtw89_debug(rtwdev, RTW89_DBG_DIG, + "MCC chanctx_idx %d chan %d rssi %d pd_val %d", + rtwvif_link->chanctx_idx, chan->primary_channel, + dig->igi_rssi, pd_val); +} + +static void rtw89_phy_set_mcc_dig_iter(void *data, struct ieee80211_sta *sta) +{ + struct rtw89_phy_iter_mcc_dig *mcc_dig = (struct rtw89_phy_iter_mcc_dig *)data; + unsigned int link_id = mcc_dig->rtwvif_link->link_id; + struct rtw89_sta *rtwsta = sta_to_rtwsta(sta); + struct rtw89_sta_link *rtwsta_link; + + if (rtwsta->rtwvif != mcc_dig->rtwvif_link->rtwvif) + return; + + rtwsta_link = rtwsta->links[link_id]; + if (!rtwsta_link) + return; + + mcc_dig->has_sta = true; + if (ewma_rssi_read(&rtwsta_link->avg_rssi) < mcc_dig->rssi_min) + mcc_dig->rssi_min = ewma_rssi_read(&rtwsta_link->avg_rssi); +} + +static void rtw89_phy_dig_mcc(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_phy_iter_mcc_dig mcc_dig; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_mcc_links_info info; + int i; + + rtw89_mcc_get_links(rtwdev, &info); + for (i = 0; i < ARRAY_SIZE(info.links); i++) { + rtwvif_link = info.links[i]; + if (!rtwvif_link) + continue; + + memset(&mcc_dig, 0, sizeof(mcc_dig)); + mcc_dig.rtwvif_link = rtwvif_link; + mcc_dig.has_sta = false; + mcc_dig.rssi_min = U8_MAX; + ieee80211_iterate_stations_atomic(rtwdev->hw, + rtw89_phy_set_mcc_dig_iter, + &mcc_dig); + + rtw89_phy_set_mcc_dig(rtwdev, rtwvif_link, bb, + mcc_dig.rssi_min, i, mcc_dig.has_sta); + } +} + +static void rtw89_phy_dig_ctrl(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb, + bool pause_dig, bool restore) +{ + const struct rtw89_dig_regs *dig_regs = rtwdev->chip->dig_regs; + struct rtw89_dig_info *dig = &bb->dig; + bool en_dig; + u32 pd_val; + + if (dig->pause_dig == pause_dig) + return; + + if (pause_dig) { + en_dig = false; + pd_val = 0; + } else { + en_dig = rtwdev->total_sta_assoc > 0; + pd_val = restore ? dig->bak_dig : 0; + } + + rtw89_debug(rtwdev, RTW89_DBG_DIG, "%s <%s> PD_low=%d", __func__, + pause_dig ? "suspend" : "resume", pd_val); + + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, + dig_regs->pd_lower_bound_mask, pd_val, bb->phy_idx); + rtw89_phy_write32_idx(rtwdev, dig_regs->seg0_pd_reg, + dig_regs->pd_spatial_reuse_en, en_dig, bb->phy_idx); + + dig->pause_dig = pause_dig; +} + +void rtw89_phy_dig_suspend(struct rtw89_dev *rtwdev) +{ + struct rtw89_bb_ctx *bb; + + rtw89_for_each_active_bb(rtwdev, bb) + rtw89_phy_dig_ctrl(rtwdev, bb, true, false); +} + +void rtw89_phy_dig_resume(struct rtw89_dev *rtwdev, bool restore) +{ + struct rtw89_bb_ctx *bb; + + rtw89_for_each_active_bb(rtwdev, bb) + rtw89_phy_dig_ctrl(rtwdev, bb, false, restore); +} + static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) { struct rtw89_dig_info *dig = &bb->dig; bool is_linked = rtwdev->total_sta_assoc > 0; - u8 igi_min; + enum rtw89_entity_mode mode; if (unlikely(dig->bypass_dig)) { dig->bypass_dig = false; @@ -6411,6 +6594,15 @@ static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) rtw89_phy_dig_update_rssi_info(rtwdev, bb); + mode = rtw89_get_entity_mode(rtwdev); + if (mode == RTW89_ENTITY_MODE_MCC) { + rtw89_phy_dig_mcc(rtwdev, bb); + return; + } + + if (unlikely(dig->pause_dig)) + return; + if (!dig->is_linked_pre && is_linked) { rtw89_debug(rtwdev, RTW89_DBG_DIG, "First connected\n"); rtw89_phy_dig_update_para(rtwdev, bb); @@ -6422,19 +6614,7 @@ static void __rtw89_phy_dig(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) } dig->is_linked_pre = is_linked; - rtw89_phy_dig_igi_offset_by_env(rtwdev, bb); - - igi_min = max_t(int, dig->igi_rssi - IGI_RSSI_MIN, 0); - dig->dyn_igi_max = min(igi_min + IGI_OFFSET_MAX, igi_max_performance_mode); - dig->dyn_igi_min = max(igi_min, ABS_IGI_MIN); - - if (dig->dyn_igi_max >= dig->dyn_igi_min) { - dig->igi_fa_rssi += dig->fa_rssi_ofst; - dig->igi_fa_rssi = clamp(dig->igi_fa_rssi, dig->dyn_igi_min, - dig->dyn_igi_max); - } else { - dig->igi_fa_rssi = dig->dyn_igi_max; - } + rtw89_phy_cal_igi_fa_rssi(rtwdev, bb); rtw89_debug(rtwdev, RTW89_DBG_DIG, "rssi=%03d, dyn_joint(max,min)=(%d,%d), final_rssi=%d\n", @@ -7125,7 +7305,7 @@ static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *b const struct rtw89_edcca_p_regs *edcca_p_regs; bool flag_fb, flag_p20, flag_s20, flag_s40, flag_s80; s8 pwdb_fb, pwdb_p20, pwdb_s20, pwdb_s40, pwdb_s80; - u8 path, per20_bitmap; + u8 path, per20_bitmap = 0; u8 pwdb[8]; u32 tmp; @@ -7155,14 +7335,11 @@ static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *b pwdb_fb = u32_get_bits(tmp, MASKBYTE3); rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel, - edcca_p_regs->rpt_sel_mask, 4); + edcca_p_regs->rpt_sel_mask, 5); tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_b); pwdb_s80 = u32_get_bits(tmp, MASKBYTE1); pwdb_s40 = u32_get_bits(tmp, MASKBYTE2); - per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_p_regs->rpt_a, - MASKBYTE0); - if (rtwdev->chip->chip_id == RTL8922A) { rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, edcca_regs->rpt_sel_be_mask, 4); @@ -7171,6 +7348,8 @@ static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *b pwdb[1] = u32_get_bits(tmp, MASKBYTE2); pwdb[2] = u32_get_bits(tmp, MASKBYTE1); pwdb[3] = u32_get_bits(tmp, MASKBYTE0); + per20_bitmap = rtw89_phy_read32_mask(rtwdev, edcca_p_regs->rpt_a, + MASKBYTE0); rtw89_phy_write32_mask(rtwdev, edcca_regs->rpt_sel_be, edcca_regs->rpt_sel_be_mask, 5); @@ -7187,7 +7366,7 @@ static void rtw89_phy_edcca_log(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *b pwdb[1] = u32_get_bits(tmp, MASKBYTE2); rtw89_phy_write32_mask(rtwdev, edcca_p_regs->rpt_sel, - edcca_p_regs->rpt_sel_mask, 1); + edcca_p_regs->rpt_sel_mask, 5); tmp = rtw89_phy_read32(rtwdev, edcca_p_regs->rpt_a); pwdb[2] = u32_get_bits(tmp, MASKBYTE3); pwdb[3] = u32_get_bits(tmp, MASKBYTE2); diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 5b451f1cfaac..dc156376d951 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -252,6 +252,7 @@ enum rtw89_phy_status_bitmap { RTW89_HT_PKT = 13, RTW89_VHT_PKT = 14, RTW89_HE_PKT = 15, + RTW89_EHT_PKT = 16, RTW89_PHYSTS_BITMAP_NUM }; @@ -1009,6 +1010,8 @@ void rtw89_phy_set_phy_regs(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 val); void rtw89_phy_dig_reset(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb); void rtw89_phy_dig(struct rtw89_dev *rtwdev); +void rtw89_phy_dig_suspend(struct rtw89_dev *rtwdev); +void rtw89_phy_dig_resume(struct rtw89_dev *rtwdev, bool restore); void rtw89_phy_tx_path_div_track(struct rtw89_dev *rtwdev); void rtw89_phy_antdiv_parse(struct rtw89_dev *rtwdev, struct rtw89_rx_phy_ppdu *phy_ppdu); diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 8e4fe73e7d77..652f8fc81b79 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.c +++ b/drivers/net/wireless/realtek/rtw89/ps.c @@ -13,6 +13,31 @@ #include "reg.h" #include "util.h" +static int rtw89_fw_receive_lps_h2c_check(struct rtw89_dev *rtwdev, u8 macid) +{ + struct rtw89_mac_c2h_info c2h_info = {}; + u16 c2hreg_macid; + u32 c2hreg_ret; + int ret; + + if (!RTW89_CHK_FW_FEATURE(LPS_DACK_BY_C2H_REG, &rtwdev->fw)) + return 0; + + c2h_info.id = RTW89_FWCMD_C2HREG_FUNC_PS_LEAVE_ACK; + ret = rtw89_fw_msg_reg(rtwdev, NULL, &c2h_info); + if (ret) + return ret; + + c2hreg_macid = u32_get_bits(c2h_info.u.c2hreg[0], + RTW89_C2HREG_PS_LEAVE_ACK_MACID); + c2hreg_ret = u32_get_bits(c2h_info.u.c2hreg[1], RTW89_C2HREG_PS_LEAVE_ACK_RET); + + if (macid != c2hreg_macid || c2hreg_ret) + rtw89_warn(rtwdev, "rtw89: check lps h2c received by firmware fail\n"); + + return 0; +} + static int rtw89_fw_leave_lps_check(struct rtw89_dev *rtwdev, u8 macid) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; @@ -106,7 +131,8 @@ static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, }; rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); - rtw89_fw_leave_lps_check(rtwdev, 0); + rtw89_fw_receive_lps_h2c_check(rtwdev, rtwvif_link->mac_id); + rtw89_fw_leave_lps_check(rtwdev, rtwvif_link->mac_id); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); rtw89_chip_digital_pwr_comp(rtwdev, rtwvif_link->phy_idx); } @@ -137,6 +163,8 @@ void rtw89_enter_lps(struct rtw89_dev *rtwdev, struct rtw89_vif *rtwvif, can_ps_mode = false; } + rtw89_fw_h2c_rf_ps_info(rtwdev, rtwvif); + if (RTW89_CHK_FW_FEATURE(LPS_CH_INFO, &rtwdev->fw)) rtw89_fw_h2c_lps_ch_info(rtwdev, rtwvif); else @@ -236,13 +264,23 @@ static void rtw89_tsf32_toggle(struct rtw89_dev *rtwdev, rtw89_fw_h2c_tsf32_toggle(rtwdev, rtwvif_link, false); } -static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, - struct rtw89_vif_link *rtwvif_link, - struct ieee80211_bss_conf *bss_conf) +void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf) { enum rtw89_p2pps_action act; + u8 oppps_ctwindow; u8 noa_id; + rcu_read_lock(); + + if (!bss_conf) + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + + oppps_ctwindow = bss_conf->p2p_noa_attr.oppps_ctwindow; + + rcu_read_unlock(); + if (rtwvif_link->last_noa_nr == 0) return; @@ -252,8 +290,8 @@ static void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, else act = RTW89_P2P_ACT_REMOVE; rtw89_tsf32_toggle(rtwdev, rtwvif_link, act); - rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf, - NULL, act, noa_id); + rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, NULL, + act, noa_id, oppps_ctwindow); } } @@ -275,8 +313,8 @@ static void rtw89_p2p_update_noa(struct rtw89_dev *rtwdev, else act = RTW89_P2P_ACT_UPDATE; rtw89_tsf32_toggle(rtwdev, rtwvif_link, act); - rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, bss_conf, - desc, act, noa_id); + rtw89_fw_h2c_p2p_act(rtwdev, rtwvif_link, desc, act, noa_id, + bss_conf->p2p_noa_attr.oppps_ctwindow); } rtwvif_link->last_noa_nr = noa_id; } diff --git a/drivers/net/wireless/realtek/rtw89/ps.h b/drivers/net/wireless/realtek/rtw89/ps.h index b2c43d44820d..729477153de6 100644 --- a/drivers/net/wireless/realtek/rtw89/ps.h +++ b/drivers/net/wireless/realtek/rtw89/ps.h @@ -25,6 +25,9 @@ u8 rtw89_p2p_noa_fetch(struct rtw89_vif_link *rtwvif_link, void **data); void rtw89_p2p_noa_once_init(struct rtw89_vif_link *rtwvif_link); void rtw89_p2p_noa_once_deinit(struct rtw89_vif_link *rtwvif_link); void rtw89_p2p_noa_once_recalc(struct rtw89_vif_link *rtwvif_link); +void rtw89_p2p_disable_all_noa(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, + struct ieee80211_bss_conf *bss_conf); static inline void rtw89_leave_ips_by_hwflags(struct rtw89_dev *rtwdev) { diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h index f05c81ae5869..de81103a072f 100644 --- a/drivers/net/wireless/realtek/rtw89/reg.h +++ b/drivers/net/wireless/realtek/rtw89/reg.h @@ -21,6 +21,7 @@ #define R_AX_SYS_PW_CTRL 0x0004 #define B_AX_SOP_ASWRM BIT(31) #define B_AX_SOP_PWMM_DSWR BIT(29) +#define B_AX_SOP_EDSWR BIT(28) #define B_AX_XTAL_OFF_A_DIE BIT(22) #define B_AX_DIS_WLBT_PDNSUSEN_SOPC BIT(18) #define B_AX_RDY_SYSPWR BIT(17) @@ -182,6 +183,7 @@ #define R_AX_SYS_STATUS1 0x00F4 #define B_AX_SEL_0XC0_MASK GENMASK(17, 16) +#define B_AX_AUTO_WLPON BIT(10) #define B_AX_PAD_HCI_SEL_V2_MASK GENMASK(5, 3) #define MAC_AX_HCI_SEL_SDIO_UART 0 #define MAC_AX_HCI_SEL_MULTI_USB 1 @@ -380,6 +382,18 @@ #define B_AX_ACH1_BUSY BIT(9) #define B_AX_ACH0_BUSY BIT(8) +#define R_AX_USB_ENDPOINT_0 0x1060 +#define B_AX_EP_IDX GENMASK(3, 0) +#define R_AX_USB_ENDPOINT_2 0x1068 +#define NUMP 0x1 +#define R_AX_USB_HOST_REQUEST_2 0x1078 +#define B_AX_R_USBIO_MODE BIT(4) +#define R_AX_USB3_MAC_NPI_CONFIG_INTF_0 0x1114 +#define B_AX_SSPHY_LFPS_FILTER BIT(31) +#define R_AX_USB_WLAN0_1 0x1174 +#define B_AX_USBRX_RST BIT(9) +#define B_AX_USBTX_RST BIT(8) + #define R_AX_PCIE_DBG_CTRL 0x11C0 #define B_AX_DBG_DUMMY_MASK GENMASK(23, 16) #define B_AX_PCIE_DBG_SEL_MASK GENMASK(15, 13) @@ -459,6 +473,17 @@ #define R_AX_WP_PAGE_CTRL2_V1 0x17A4 #define R_AX_WP_PAGE_INFO1_V1 0x17A8 +#define R_AX_USB_ENDPOINT_0_V1 0x5060 +#define B_AX_EP_IDX_V1 GENMASK(3, 0) +#define R_AX_USB_ENDPOINT_2_V1 0x5068 +#define R_AX_USB_HOST_REQUEST_2_V1 0x5078 +#define B_AX_R_USBIO_MODE_V1 BIT(4) +#define R_AX_USB3_MAC_NPI_CONFIG_INTF_0_V1 0x5114 +#define B_AX_SSPHY_LFPS_FILTER_V1 BIT(31) +#define R_AX_USB_WLAN0_1_V1 0x5174 +#define B_AX_USBRX_RST_V1 BIT(9) +#define B_AX_USBTX_RST_V1 BIT(8) + #define R_AX_H2CREG_DATA0_V1 0x7140 #define R_AX_H2CREG_DATA1_V1 0x7144 #define R_AX_H2CREG_DATA2_V1 0x7148 @@ -1025,6 +1050,12 @@ #define B_AX_DISPATCHER_INTN_SEL_MASK GENMASK(7, 4) #define B_AX_DISPATCHER_CH_SEL_MASK GENMASK(3, 0) +#define R_AX_RXDMA_SETTING 0x8908 +#define B_AX_BULK_SIZE GENMASK(1, 0) +#define USB11_BULKSIZE 0x2 +#define USB2_BULKSIZE 0x1 +#define USB3_BULKSIZE 0x0 + #define R_AX_RX_FUNCTION_STOP 0x8920 #define B_AX_HDR_RX_STOP BIT(0) @@ -6070,6 +6101,7 @@ #define B_BE_MACID_ACQ_GRP0_CLR_P BIT(2) #define B_BE_R_MACID_ACQ_CHK_EN BIT(0) +#define R_BE_BTC_CFG 0x0E300 #define R_BE_BT_BREAK_TABLE 0x0E344 #define R_BE_GNT_SW_CTRL 0x0E348 @@ -8024,6 +8056,7 @@ #define R_PHY_STS_BITMAP_HT 0x076C #define R_PHY_STS_BITMAP_VHT 0x0770 #define R_PHY_STS_BITMAP_HE 0x0774 +#define R_PHY_STS_BITMAP_EHT 0x0788 #define R_EDCCA_RPTREG_SEL_BE 0x078C #define B_EDCCA_RPTREG_SEL_BE_MSK GENMASK(22, 20) #define R_PMAC_GNT 0x0980 @@ -8773,6 +8806,8 @@ #define B_P0_TSSI_RFC GENMASK(28, 27) #define B_P0_TSSI_OFT_EN BIT(28) #define B_P0_TSSI_OFT GENMASK(7, 0) +#define R_P0_TSSI_SLOPE_CAL 0x581c +#define B_P0_TSSI_SLOPE_CAL_EN BIT(20) #define R_P0_TSSI_AVG 0x5820 #define B_P0_TSSI_EN BIT(31) #define B_P0_TSSI_AVG GENMASK(15, 12) @@ -9266,6 +9301,7 @@ #define B_WDADC_SEL GENMASK(5, 4) #define R_ADCMOD 0xC0E8 #define B_ADCMOD_LP GENMASK(31, 16) +#define B_ADCMOD_AUTO_RST BIT(6) #define R_DCIM 0xC0EC #define B_DCIM_RC GENMASK(23, 16) #define B_DCIM_FR GENMASK(14, 13) diff --git a/drivers/net/wireless/realtek/rtw89/regd.c b/drivers/net/wireless/realtek/rtw89/regd.c index 3ad14cab1f58..58582f8d2b74 100644 --- a/drivers/net/wireless/realtek/rtw89/regd.c +++ b/drivers/net/wireless/realtek/rtw89/regd.c @@ -360,15 +360,13 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, struct wiphy *wiphy) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; - const struct rtw89_regd_ctrl *regd_ctrl = ®ulatory->ctrl; const struct rtw89_chip_info *chip = rtwdev->chip; struct ieee80211_supported_band *sband; struct rtw89_acpi_dsm_result res = {}; - bool enable_by_fcc; - bool enable_by_ic; + bool enable; + u8 index; int ret; u8 val; - int i; sband = wiphy->bands[NL80211_BAND_5GHZ]; if (!sband) @@ -385,35 +383,25 @@ static void rtw89_regd_setup_unii4(struct rtw89_dev *rtwdev, if (ret) { rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: cannot eval unii 4: %d\n", ret); - enable_by_fcc = true; - enable_by_ic = false; + val = u8_encode_bits(1, RTW89_ACPI_CONF_UNII4_US); goto bottom; } val = res.u.value; - enable_by_fcc = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_FCC); - enable_by_ic = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_IC); rtw89_debug(rtwdev, RTW89_DBG_REGD, "acpi: eval if allow unii-4: 0x%x\n", val); bottom: - for (i = 0; i < regd_ctrl->nr; i++) { - const struct rtw89_regd *regd = ®d_ctrl->map[i]; - - switch (regd->txpwr_regd[RTW89_BAND_5G]) { - case RTW89_FCC: - if (enable_by_fcc) - clear_bit(i, regulatory->block_unii4); - break; - case RTW89_IC: - if (enable_by_ic) - clear_bit(i, regulatory->block_unii4); - break; - default: - break; - } - } + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_US); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_unii4); + + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_UNII4_CA); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_unii4); } static void __rtw89_regd_setup_policy_6ghz(struct rtw89_dev *rtwdev, bool block, @@ -490,12 +478,11 @@ out: static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; - const struct rtw89_regd_ctrl *regd_ctrl = ®ulatory->ctrl; const struct rtw89_acpi_policy_6ghz_sp *ptr; struct rtw89_acpi_dsm_result res = {}; - bool enable_by_us; + bool enable; + u8 index; int ret; - int i; ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP, &res); if (ret) { @@ -520,16 +507,66 @@ static void rtw89_regd_setup_policy_6ghz_sp(struct rtw89_dev *rtwdev) bitmap_fill(regulatory->block_6ghz_sp, RTW89_REGD_MAX_COUNTRY_NUM); - enable_by_us = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_US); + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_US); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_6ghz_sp); - for (i = 0; i < regd_ctrl->nr; i++) { - const struct rtw89_regd *tmp = ®d_ctrl->map[i]; + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(ptr->conf, RTW89_ACPI_CONF_6GHZ_SP_CA); + if (enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + clear_bit(index, regulatory->block_6ghz_sp); + +out: + kfree(ptr); +} - if (enable_by_us && memcmp(tmp->alpha2, "US", 2) == 0) - clear_bit(i, regulatory->block_6ghz_sp); +static void rtw89_regd_setup_policy_6ghz_vlp(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_policy_6ghz_vlp *ptr = NULL; + struct rtw89_acpi_dsm_result res = {}; + bool enable; + u8 index; + int ret; + u8 val; + + /* By default, allow 6 GHz VLP on all countries except US and CA. */ + val = ~(RTW89_ACPI_CONF_6GHZ_VLP_US | RTW89_ACPI_CONF_6GHZ_VLP_CA); + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy 6ghz-vlp: %d\n", ret); + goto bottom; } -out: + ptr = res.u.policy_6ghz_vlp; + + switch (ptr->override) { + default: + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%s: unknown override case: %d\n", __func__, + ptr->override); + fallthrough; + case 0: + break; + case 1: + val = ptr->conf; + break; + } + +bottom: + index = rtw89_regd_get_index_by_name(rtwdev, "US"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_6GHZ_VLP_US); + if (!enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + set_bit(index, regulatory->block_6ghz_vlp); + + index = rtw89_regd_get_index_by_name(rtwdev, "CA"); + enable = u8_get_bits(val, RTW89_ACPI_CONF_6GHZ_VLP_CA); + if (!enable && index != RTW89_REGD_MAX_COUNTRY_NUM) + set_bit(index, regulatory->block_6ghz_vlp); + kfree(ptr); } @@ -576,6 +613,7 @@ bottom: if (regd_allow_6ghz) { rtw89_regd_setup_policy_6ghz(rtwdev); rtw89_regd_setup_policy_6ghz_sp(rtwdev); + rtw89_regd_setup_policy_6ghz_vlp(rtwdev); return; } @@ -620,6 +658,30 @@ const char *rtw89_regd_get_string(enum rtw89_regulation_type regd) return rtw89_regd_string[regd]; } +static void rtw89_regd_setup_reg_rules(struct rtw89_dev *rtwdev) +{ + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_acpi_policy_reg_rules *ptr; + struct rtw89_acpi_dsm_result res = {}; + int ret; + + regulatory->txpwr_uk_follow_etsi = true; + + ret = rtw89_acpi_evaluate_dsm(rtwdev, RTW89_ACPI_DSM_FUNC_REG_RULES_EN, &res); + if (ret) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "acpi: cannot eval policy reg-rules: %d\n", ret); + return; + } + + ptr = res.u.policy_reg_rules; + + regulatory->txpwr_uk_follow_etsi = + !u8_get_bits(ptr->conf, RTW89_ACPI_CONF_REG_RULE_REGD_UK); + + kfree(ptr); +} + int rtw89_regd_setup(struct rtw89_dev *rtwdev) { struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; @@ -636,7 +698,8 @@ int rtw89_regd_setup(struct rtw89_dev *rtwdev) } regulatory->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; - regulatory->txpwr_uk_follow_etsi = true; + + rtw89_regd_setup_reg_rules(rtwdev); if (!wiphy) return -EINVAL; @@ -1046,7 +1109,16 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, bool active, unsigned int *changed) { + struct rtw89_regulatory_info *regulatory = &rtwdev->regulatory; + const struct rtw89_regd *regd = regulatory->regd; + bool blocked[NUM_OF_RTW89_REG_6GHZ_POWER] = {}; + u8 index = rtw89_regd_get_index(rtwdev, regd); struct ieee80211_bss_conf *bss_conf; + bool dflt = false; + + if (index == RTW89_REGD_MAX_COUNTRY_NUM || + test_bit(index, regulatory->block_6ghz_vlp)) + blocked[RTW89_REG_6GHZ_POWER_VLP] = true; rcu_read_lock(); @@ -1065,6 +1137,7 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, break; default: rtwvif_link->reg_6ghz_power = RTW89_REG_6GHZ_POWER_DFLT; + dflt = true; break; } } else { @@ -1073,6 +1146,14 @@ static int rtw89_reg_6ghz_power_recalc(struct rtw89_dev *rtwdev, rcu_read_unlock(); + if (!dflt && blocked[rtwvif_link->reg_6ghz_power]) { + rtw89_debug(rtwdev, RTW89_DBG_REGD, + "%c%c 6 GHz power type-%u is blocked by policy\n", + regd->alpha2[0], regd->alpha2[1], + rtwvif_link->reg_6ghz_power); + return -EINVAL; + } + *changed += __rtw89_reg_6ghz_power_recalc(rtwdev); return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b.c b/drivers/net/wireless/realtek/rtw89/rtw8851b.c index fafa200a9c8d..393df2b0dcae 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b.c @@ -51,6 +51,48 @@ static const struct rtw89_hfc_param_ini rtw8851b_hfc_param_ini_pcie[] = { [RTW89_QTA_INVALID] = {NULL}, }; +static const struct rtw89_hfc_ch_cfg rtw8851b_hfc_chcfg_usb[] = { + {18, 152, grp_0}, /* ACH 0 */ + {18, 152, grp_0}, /* ACH 1 */ + {18, 152, grp_0}, /* ACH 2 */ + {18, 152, grp_0}, /* ACH 3 */ + {0, 0, grp_0}, /* ACH 4 */ + {0, 0, grp_0}, /* ACH 5 */ + {0, 0, grp_0}, /* ACH 6 */ + {0, 0, grp_0}, /* ACH 7 */ + {18, 152, grp_0}, /* B0MGQ */ + {18, 152, grp_0}, /* B0HIQ */ + {0, 0, grp_0}, /* B1MGQ */ + {0, 0, grp_0}, /* B1HIQ */ + {0, 0, 0} /* FWCMDQ */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8851b_hfc_pubcfg_usb = { + 152, /* Group 0 */ + 0, /* Group 1 */ + 152, /* Public Max */ + 0 /* WP threshold */ +}; + +static const struct rtw89_hfc_prec_cfg rtw8851b_hfc_preccfg_usb = { + 9, /* CH 0-11 pre-cost */ + 32, /* H2C pre-cost */ + 64, /* WP CH 0-7 pre-cost */ + 24, /* WP CH 8-11 pre-cost */ + 1, /* CH 0-11 full condition */ + 1, /* H2C full condition */ + 1, /* WP CH 0-7 full condition */ + 1, /* WP CH 8-11 full condition */ +}; + +static const struct rtw89_hfc_param_ini rtw8851b_hfc_param_ini_usb[] = { + [RTW89_QTA_SCC] = {rtw8851b_hfc_chcfg_usb, &rtw8851b_hfc_pubcfg_usb, + &rtw8851b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_DLFW] = {NULL, NULL, + &rtw8851b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_INVALID] = {NULL}, +}; + static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = { [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size6, &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt6, @@ -68,6 +110,32 @@ static const struct rtw89_dle_mem rtw8851b_dle_mem_pcie[] = { NULL}, }; +static const struct rtw89_dle_mem rtw8851b_dle_mem_usb2[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size32, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt72, + &rtw89_mac_size.ple_qt73}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + +static const struct rtw89_dle_mem rtw8851b_dle_mem_usb3[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size33, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt74, + &rtw89_mac_size.ple_qt75}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + static const struct rtw89_reg3_def rtw8851b_btc_preagc_en_defs[] = { {0x46D0, GENMASK(1, 0), 0x3}, {0x4AD4, GENMASK(31, 0), 0xf}, @@ -317,7 +385,8 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); - rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); ret = rtw89_mac_write_xtal_si(rtwdev, XTAL_SI_ANAPAR_WL, XTAL_SI_OFF_WEI, XTAL_SI_OFF_WEI); @@ -362,8 +431,9 @@ static int rtw8851b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_clr(rtwdev, R_AX_SYS_ISO_CTRL, B_AX_PWC_EV2EF_B14); rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); - rtw89_write32_set(rtwdev, R_AX_GPIO0_16_EECS_EESK_LED1_PULL_LOW_EN, - B_AX_GPIO10_PULL_LOW_EN | B_AX_GPIO16_PULL_LOW_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_set(rtwdev, R_AX_GPIO0_16_EECS_EESK_LED1_PULL_LOW_EN, + B_AX_GPIO10_PULL_LOW_EN | B_AX_GPIO16_PULL_LOW_EN_V1); if (rtwdev->hal.cv == CHIP_CAV) { ret = rtw89_read_efuse_ver(rtwdev, &val8); @@ -447,7 +517,10 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) if (ret) return ret; - rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_EDSWR); if (rtwdev->hal.cv == CHIP_CAV) { rtw8851b_patch_swr_pfm2pwm(rtwdev); @@ -456,19 +529,18 @@ static int rtw8851b_pwr_off_func(struct rtw89_dev *rtwdev) rtw89_write32_set(rtwdev, R_AX_SPSANA_ON_CTRL1, B_AX_FPWMDELAY); } - rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + } else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) { + val32 = rtw89_read32(rtwdev, R_AX_SYS_PW_CTRL); + val32 &= ~B_AX_AFSM_PCIE_SUS_EN; + val32 |= B_AX_AFSM_WLSUS_EN; + rtw89_write32(rtwdev, R_AX_SYS_PW_CTRL, val32); + } return 0; } -static void rtw8851b_efuse_parsing(struct rtw89_efuse *efuse, - struct rtw8851b_efuse *map) -{ - ether_addr_copy(efuse->addr, map->e.mac_addr); - efuse->rfe_type = map->rfe_type; - efuse->xtal_cap = map->xtal_k; -} - static void rtw8851b_efuse_parsing_tssi(struct rtw89_dev *rtwdev, struct rtw8851b_efuse *map) { @@ -549,12 +621,18 @@ static int rtw8851b_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, switch (rtwdev->hci.type) { case RTW89_HCI_TYPE_PCIE: - rtw8851b_efuse_parsing(efuse, map); + ether_addr_copy(efuse->addr, map->e.mac_addr); + break; + case RTW89_HCI_TYPE_USB: + ether_addr_copy(efuse->addr, map->u.mac_addr); break; default: return -EOPNOTSUPP; } + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); return 0; @@ -712,12 +790,22 @@ static void rtw8851b_phycap_parsing_gain_comp(struct rtw89_dev *rtwdev, u8 *phyc gain->comp_valid = valid; } +static void rtw8851b_phycap_parsing_adc_td(struct rtw89_dev *rtwdev, u8 *phycap_map) +{ + u32 phycap_addr = rtwdev->chip->phycap_addr; + struct rtw89_efuse *efuse = &rtwdev->efuse; + const u32 addr_adc_td = 0x5AF; + + efuse->adc_td = phycap_map[addr_adc_td - phycap_addr] & GENMASK(4, 0); +} + static int rtw8851b_read_phycap(struct rtw89_dev *rtwdev, u8 *phycap_map) { rtw8851b_phycap_parsing_tssi(rtwdev, phycap_map); rtw8851b_phycap_parsing_thermal_trim(rtwdev, phycap_map); rtw8851b_phycap_parsing_pa_bias_trim(rtwdev, phycap_map); rtw8851b_phycap_parsing_gain_comp(rtwdev, phycap_map); + rtw8851b_phycap_parsing_adc_td(rtwdev, phycap_map); return 0; } @@ -1083,39 +1171,72 @@ static void rtw8851b_ctrl_ch(struct rtw89_dev *rtwdev, static void rtw8851b_bw_setting(struct rtw89_dev *rtwdev, u8 bw) { - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); - rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, 0x4); + struct rtw89_efuse *efuse = &rtwdev->efuse; + u8 adc_bw_sel; + + switch (efuse->adc_td) { + default: + case 0x19: + adc_bw_sel = 0x4; + break; + case 0x11: + adc_bw_sel = 0x5; + break; + case 0x9: + adc_bw_sel = 0x3; + break; + } + + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1, B_P0_CFCH_BW1, adc_bw_sel); rtw89_phy_write32_mask(rtwdev, R_DRCK, B_DRCK_MUL, 0xf); rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_LP, 0xa); - rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_RC, 0x3); switch (bw) { case RTW89_CHANNEL_WIDTH_5: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x1); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x0); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_10: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x1); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_20: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x2); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_40: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x2); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; case RTW89_CHANNEL_WIDTH_80: + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_CTL, 0x8); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_EN, 0x2); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0, B_P0_CFCH_BW0, 0x2); rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x0); rtw89_phy_write32_mask(rtwdev, R_WDADC, B_WDADC_SEL, 0x2); rtw89_phy_write32_mask(rtwdev, R_ADDCK0D, B_ADDCK_DS, 0x0); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK, B_P0_RXCK_ADJ, 0x92); break; default: rtw89_warn(rtwdev, "Fail to set ADC\n"); @@ -2402,6 +2523,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .set_txpwr_ctrl = rtw8851b_set_txpwr_ctrl, .init_txpwr_unit = rtw8851b_init_txpwr_unit, .get_thermal = rtw8851b_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8851b_ctrl_btg_bt_rx, .query_ppdu = rtw8851b_query_ppdu, .convert_rpl_to_rssi = NULL, @@ -2424,6 +2546,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, @@ -2466,8 +2589,13 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = rtw8851b_hfc_param_ini_pcie, - .dle_mem = rtw8851b_dle_mem_pcie, + .hfc_param_ini = {rtw8851b_hfc_param_ini_pcie, + rtw8851b_hfc_param_ini_usb, + NULL}, + .dle_mem = {rtw8851b_dle_mem_pcie, + rtw8851b_dle_mem_usb2, + rtw8851b_dle_mem_usb3, + NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000}, @@ -2528,7 +2656,6 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .phycap_size = 128, .para_ver = 0, .wlcx_desired = 0x06000000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index f72b3ac6f149..7a319a6c838a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -12,14 +12,14 @@ #include "rtw8851b_rfk_table.h" #include "rtw8851b_table.h" -#define DPK_VER_8851B 0x5 -#define DPK_KIP_REG_NUM_8851B 7 +#define DPK_VER_8851B 0x11 +#define DPK_KIP_REG_NUM_8851B 8 #define DPK_RF_REG_NUM_8851B 4 #define DPK_KSET_NUM 4 #define RTW8851B_RXK_GROUP_NR 4 #define RTW8851B_RXK_GROUP_IDX_NR 2 #define RTW8851B_TXK_GROUP_NR 1 -#define RTW8851B_IQK_VER 0x2a +#define RTW8851B_IQK_VER 0x14 #define RTW8851B_IQK_SS 1 #define RTW8851B_LOK_GRAM 10 #define RTW8851B_TSSI_PATH_NR 1 @@ -85,6 +85,24 @@ enum rf_mode { RF_RXK2 = 0x7, }; +enum adc_ck { + ADC_NA = 0, + ADC_480M = 1, + ADC_960M = 2, + ADC_1920M = 3, +}; + +enum dac_ck { + DAC_40M = 0, + DAC_80M = 1, + DAC_120M = 2, + DAC_160M = 3, + DAC_240M = 4, + DAC_320M = 5, + DAC_480M = 6, + DAC_960M = 7, +}; + static const u32 _tssi_de_cck_long[RF_PATH_NUM_8851B] = {0x5858}; static const u32 _tssi_de_cck_short[RF_PATH_NUM_8851B] = {0x5860}; static const u32 _tssi_de_mcs_20m[RF_PATH_NUM_8851B] = {0x5838}; @@ -116,7 +134,7 @@ static const u32 rtw8851b_backup_rf_regs[] = { #define BACKUP_RF_REGS_NR ARRAY_SIZE(rtw8851b_backup_rf_regs) static const u32 dpk_kip_reg[DPK_KIP_REG_NUM_8851B] = { - 0x813c, 0x8124, 0xc0ec, 0xc0e8, 0xc0c4, 0xc0d4, 0xc0d8}; + 0x813c, 0x8124, 0xc0ec, 0xc0e8, 0xc0c4, 0xc0d4, 0xc0d8, 0x12a0}; static const u32 dpk_rf_reg[DPK_RF_REG_NUM_8851B] = {0xde, 0x8f, 0x5, 0x10005}; static void _set_ch(struct rtw89_dev *rtwdev, u32 val); @@ -163,6 +181,51 @@ static void _rfk_drf_direct_cntrl(struct rtw89_dev *rtwdev, rtw89_write_rf(rtwdev, path, RR_BBDC, RR_BBDC_SEL, 0x0); } +static void _txck_force(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool force, enum dac_ck ck) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_ON, 0x0); + + if (!force) + return; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_VAL, ck); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_TXCK_ON, 0x1); +} + +static void _rxck_force(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool force, enum adc_ck ck) +{ + static const u32 ck960_8851b[] = {0x8, 0x2, 0x2, 0x4, 0xf, 0xa, 0x93}; + static const u32 ck1920_8851b[] = {0x9, 0x0, 0x0, 0x3, 0xf, 0xa, 0x49}; + const u32 *data; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x0); + if (!force) + return; + + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_VAL, ck); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 13), B_P0_RXCK_ON, 0x1); + + switch (ck) { + case ADC_960M: + data = ck960_8851b; + break; + case ADC_1920M: + default: + data = ck1920_8851b; + break; + } + + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_CTL, data[0]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_EN, data[1]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW0 | (path << 8), B_P0_CFCH_BW0, data[2]); + rtw89_phy_write32_mask(rtwdev, R_P0_CFCH_BW1 | (path << 8), B_P0_CFCH_BW1, data[3]); + rtw89_phy_write32_mask(rtwdev, R_DRCK | (path << 8), B_DRCK_MUL, data[4]); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD | (path << 8), B_ADCMOD_LP, data[5]); + rtw89_phy_write32_mask(rtwdev, R_P0_RXCK | (path << 8), B_P0_RXCK_ADJ, data[6]); +} + static void _wait_rx_mode(struct rtw89_dev *rtwdev, u8 kpath) { u32 rf_mode; @@ -1044,10 +1107,43 @@ static void _iqk_rxclk_setting(struct rtw89_dev *rtwdev, u8 path) rtw89_write_rf(rtwdev, path, RR_RXBB2, RR_RXBB2_CKT, 0x1); - if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) + if (iqk_info->iqk_bw[path] == RTW89_CHANNEL_WIDTH_80) { + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0101); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_960M); + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_rxclk_80_defs_tbl); - else + } else { + rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, B_ADC_FIFO_RXK, 0x0101); + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_960M); + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_rxclk_others_defs_tbl); + } + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, (2)before RXK IQK\n", path); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[07:10] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(10, 7))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[11:14] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(14, 11))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[26:27] = 0x%x\n", path, + 0xc0d4, rtw89_phy_read32_mask(rtwdev, 0xc0d4, GENMASK(27, 26))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[05:08] = 0x%x\n", path, + 0xc0d8, rtw89_phy_read32_mask(rtwdev, 0xc0d8, GENMASK(8, 5))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[17:21] = 0x%x\n", path, + 0xc0c4, rtw89_phy_read32_mask(rtwdev, 0xc0c4, GENMASK(21, 17))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[16:31] = 0x%x\n", path, + 0xc0e8, rtw89_phy_read32_mask(rtwdev, 0xc0e8, GENMASK(31, 16))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[04:05] = 0x%x\n", path, + 0xc0e4, rtw89_phy_read32_mask(rtwdev, 0xc0e4, GENMASK(5, 4))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[23:31] = 0x%x\n", path, + 0x12a0, rtw89_phy_read32_mask(rtwdev, 0x12a0, GENMASK(31, 23))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[13:14] = 0x%x\n", path, + 0xc0ec, rtw89_phy_read32_mask(rtwdev, 0xc0ec, GENMASK(14, 13))); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, 0x%x[16:23] = 0x%x\n", path, + 0xc0ec, rtw89_phy_read32_mask(rtwdev, 0xc0ec, GENMASK(23, 16))); } static bool _txk_5g_group_sel(struct rtw89_dev *rtwdev, @@ -1553,6 +1649,14 @@ static void _iqk_macbb_setting(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_macbb_defs_tbl); + + _txck_force(rtwdev, path, true, DAC_960M); + + rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_DPD_GDIS, 0x1); + + _rxck_force(rtwdev, path, true, ADC_1920M); + + rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_macbb_bh_defs_tbl); } static void _iqk_init(struct rtw89_dev *rtwdev) @@ -1794,7 +1898,21 @@ static void _dpk_bb_afe_setting(struct rtw89_dev *rtwdev, enum rtw89_rf_path pat rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x0); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), MASKDWORD, 0xd801dffd); - rtw89_rfk_parser(rtwdev, &rtw8851b_iqk_bb_afe_defs_tbl); + _txck_force(rtwdev, path, true, DAC_960M); + _rxck_force(rtwdev, path, true, ADC_1920M); + + rtw89_phy_write32_mask(rtwdev, R_DCIM, B_DCIM_FR, 0x0); + rtw89_phy_write32_mask(rtwdev, R_ADCMOD, B_ADCMOD_AUTO_RST, 0x1); + rtw89_phy_write32_mask(rtwdev, R_P0_NRBW, B_P0_NRBW_DBG, 0x1); + udelay(1); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x1f); + udelay(10); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR_PW15, B_ANAPAR_PW15, 0x13); + udelay(2); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0001); + udelay(2); + rtw89_phy_write32_mask(rtwdev, R_ANAPAR, B_ANAPAR_15, 0x0041); + udelay(10); rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(20 + path), 0x1); rtw89_phy_write32_mask(rtwdev, R_ADC_FIFO, BIT(28 + path), 0x1); @@ -1827,6 +1945,17 @@ static void _dpk_tssi_pause(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, is_pause ? "pause" : "resume"); } +static +void _dpk_tssi_slope_k_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, + bool is_on) +{ + rtw89_phy_write32_mask(rtwdev, R_P0_TSSI_SLOPE_CAL + (path << 13), + B_P0_TSSI_SLOPE_CAL_EN, is_on); + + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d TSSI slpoe_k %s\n", path, + str_on_off(is_on)); +} + static void _dpk_tpg_sel(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, u8 kidx) { struct rtw89_dpk_info *dpk = &rtwdev->dpk; @@ -1874,9 +2003,6 @@ static void _dpk_kip_control_rfc(struct rtw89_dev *rtwdev, { rtw89_phy_write32_mask(rtwdev, R_UPD_CLK + (path << 13), B_IQK_RFC_ON, ctrl_by_kip); - - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] RFC is controlled by %s\n", - ctrl_by_kip ? "KIP" : "BB"); } static void _dpk_kip_preset(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, @@ -2279,7 +2405,7 @@ static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, u8 order) case 0: /* (5,3,1) */ rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_OP, 0x0); rtw89_phy_write32_mask(rtwdev, R_DPK_IDL, B_DPK_IDL_SEL, 0x2); - rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x4); + rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_PN, 0x3); rtw89_phy_write32_mask(rtwdev, R_MDPK_SYNC, B_MDPK_SYNC_DMAN, 0x1); break; case 1: /* (5,3,0) */ @@ -2315,8 +2441,6 @@ static void _dpk_set_mdpd_para(struct rtw89_dev *rtwdev, u8 order) static void _dpk_idl_mpa(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, enum rtw89_rf_path path, u8 kidx) { - rtw89_phy_write32_mask(rtwdev, R_LDL_NORM, B_LDL_NORM_MA, 0x1); - if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_MD500) == 0x1) _dpk_set_mdpd_para(rtwdev, 0x2); else if (rtw89_phy_read32_mask(rtwdev, R_IDL_MPA, B_IDL_MD530) == 0x1) @@ -2419,9 +2543,6 @@ static bool _dpk_main(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u8 init_xdbm = 17; bool is_fail; - if (dpk->bp[path][kidx].band != RTW89_BAND_2G) - init_xdbm = 15; - _dpk_kip_control_rfc(rtwdev, path, false); _rfk_rf_direct_cntrl(rtwdev, path, false); rtw89_write_rf(rtwdev, path, RR_BBDC, RFREG_MASK, 0x03ffd); @@ -2485,6 +2606,7 @@ static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, "[DPK] ========= S%d[%d] DPK Start =========\n", path, dpk->cur_idx[path]); + _dpk_tssi_slope_k_onoff(rtwdev, path, false); _dpk_rxagc_onoff(rtwdev, path, false); _rfk_drf_direct_cntrl(rtwdev, path, false); _dpk_bb_afe_setting(rtwdev, path); @@ -2502,7 +2624,7 @@ static void _dpk_cal_select(struct rtw89_dev *rtwdev, bool force, _dpk_reload_rf(rtwdev, dpk_rf_reg, rf_bkup, path); _dpk_bb_afe_restore(rtwdev, path); _dpk_rxagc_onoff(rtwdev, path, true); - + _dpk_tssi_slope_k_onoff(rtwdev, path, true); if (rtwdev->is_tssi_mode[path]) _dpk_tssi_pause(rtwdev, path, false); } diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c index 0abf7978ccab..c5f70c045692 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.c @@ -63,16 +63,7 @@ static const struct rtw89_reg5_def rtw8851b_dack_manual_off_defs[] = { RTW89_DECLARE_RFK_TBL(rtw8851b_dack_manual_off_defs); static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_80_defs[] = { - RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0101), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x2), RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x8), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x5), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xf), RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x0f), @@ -85,16 +76,7 @@ static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_80_defs[] = { RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_rxclk_80_defs); static const struct rtw89_reg5_def rtw8851b_iqk_rxclk_others_defs[] = { - RTW89_DECL_RFK_WM(0x20fc, 0xffff0000, 0x0101), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x2), RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x8), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x5), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xf), RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x2), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x0f), @@ -157,55 +139,38 @@ static const struct rtw89_reg5_def rtw8851b_iqk_macbb_defs[] = { RTW89_DECL_RFK_WM(0x20fc, 0x10000000, 0x0), RTW89_DECL_RFK_WM(0x5670, MASKDWORD, 0xf801fffd), RTW89_DECL_RFK_WM(0x5670, 0x00004000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00008000, 0x1), RTW89_DECL_RFK_WM(0x5670, 0x80000000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00007000, 0x7), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x3), +}; + +RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_defs); + +static const struct rtw89_reg5_def rtw8851b_iqk_macbb_bh_defs[] = { RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x9), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x3), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xa), - RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), - RTW89_DECL_RFK_WM(0xc0e8, 0x00000040, 0x1), RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x1f), + RTW89_DECL_RFK_DELAY(10), + RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x13), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0001), + RTW89_DECL_RFK_DELAY(2), + RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0041), + RTW89_DECL_RFK_DELAY(10), + RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x1f), + RTW89_DECL_RFK_DELAY(10), RTW89_DECL_RFK_WM(0x030c, 0xff000000, 0x13), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0001), + RTW89_DECL_RFK_DELAY(2), RTW89_DECL_RFK_WM(0x032c, 0xffff0000, 0x0041), + RTW89_DECL_RFK_DELAY(10), RTW89_DECL_RFK_WM(0x20fc, 0x00100000, 0x1), RTW89_DECL_RFK_WM(0x20fc, 0x10000000, 0x1), }; -RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_defs); - -static const struct rtw89_reg5_def rtw8851b_iqk_bb_afe_defs[] = { - RTW89_DECL_RFK_WM(0x5670, 0x00004000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00008000, 0x1), - RTW89_DECL_RFK_WM(0x5670, 0x80000000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00007000, 0x7), - RTW89_DECL_RFK_WM(0x5670, 0x00002000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00080000, 0x1), - RTW89_DECL_RFK_WM(0x12a0, 0x00070000, 0x3), - RTW89_DECL_RFK_WM(0x5670, 0x60000000, 0x2), - RTW89_DECL_RFK_WM(0xc0d4, 0x00000780, 0x9), - RTW89_DECL_RFK_WM(0xc0d4, 0x00007800, 0x1), - RTW89_DECL_RFK_WM(0xc0d4, 0x0c000000, 0x0), - RTW89_DECL_RFK_WM(0xc0d8, 0x000001e0, 0x3), - RTW89_DECL_RFK_WM(0xc0c4, 0x003e0000, 0xa), - RTW89_DECL_RFK_WM(0xc0ec, 0x00006000, 0x0), - RTW89_DECL_RFK_WM(0xc0e8, 0x00000040, 0x1), - RTW89_DECL_RFK_WM(0x12b8, 0x40000000, 0x1), - RTW89_DECL_RFK_WM(0x030c, MASKBYTE3, 0x1f), - RTW89_DECL_RFK_WM(0x030c, MASKBYTE3, 0x13), - RTW89_DECL_RFK_WM(0x032c, MASKHWORD, 0x0001), - RTW89_DECL_RFK_WM(0x032c, MASKHWORD, 0x0041), -}; - -RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_bb_afe_defs); +RTW89_DECLARE_RFK_TBL(rtw8851b_iqk_macbb_bh_defs); static const struct rtw89_reg5_def rtw8851b_tssi_sys_defs[] = { RTW89_DECL_RFK_WM(0x12bc, 0x000ffff0, 0xb5b5), diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h index febfbecb691c..3f1547f57505 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk_table.h @@ -17,8 +17,8 @@ extern const struct rtw89_rfk_tbl rtw8851b_iqk_rxclk_others_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_2ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_txk_5ghz_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_afebb_restore_defs_tbl; -extern const struct rtw89_rfk_tbl rtw8851b_iqk_bb_afe_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_iqk_macbb_defs_tbl; +extern const struct rtw89_rfk_tbl rtw8851b_iqk_macbb_bh_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_defs_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_a_defs_2g_tbl; extern const struct rtw89_rfk_tbl rtw8851b_tssi_sys_a_defs_5g_tbl; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c index 522883c8dfb9..a9c309c245c3 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_table.c @@ -2320,9 +2320,9 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x813c, 0x40000000}, {0x8140, 0x00000000}, {0x8144, 0x0b040b03}, - {0x8148, 0x07020b04}, - {0x814c, 0x07020b04}, - {0x8150, 0xa0a00000}, + {0x8148, 0x07020a04}, + {0x814c, 0x07020a04}, + {0x8150, 0xe4e40000}, {0x8158, 0xffffffff}, {0x815c, 0xffffffff}, {0x8160, 0xffffffff}, @@ -2577,14 +2577,14 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8534, 0x400042fe}, {0x8538, 0x50554200}, {0x853c, 0xb4183000}, - {0x8540, 0xe537a50f}, + {0x8540, 0xe535a50f}, {0x8544, 0xf12bf02b}, {0x8548, 0xf32bf22b}, {0x854c, 0xf62bf42b}, {0x8550, 0xf82bf72b}, {0x8554, 0xfa2bf92b}, {0x8558, 0xfd2bfc2b}, - {0x855c, 0xe537fe2b}, + {0x855c, 0xe535fe2b}, {0x8560, 0xf12af02a}, {0x8564, 0xf32af22a}, {0x8568, 0xf52af42a}, @@ -2653,7 +2653,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8664, 0x9700140f}, {0x8668, 0x00017430}, {0x866c, 0xe39ce35e}, - {0x8670, 0xe52a0bbd}, + {0x8670, 0xe5280bbd}, {0x8674, 0xe36a0001}, {0x8678, 0x0001e3c4}, {0x867c, 0x55005b30}, @@ -2664,93 +2664,93 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8690, 0x46100005}, {0x8694, 0x00010004}, {0x8698, 0x30f8e35e}, - {0x869c, 0xe52a0023}, + {0x869c, 0xe5280023}, {0x86a0, 0x54ed0002}, {0x86a4, 0x00230baa}, - {0x86a8, 0x0002e52a}, + {0x86a8, 0x0002e528}, {0x86ac, 0xe356e3e4}, {0x86b0, 0xe35e0001}, {0x86b4, 0x002230f3}, - {0x86b8, 0x0002e52a}, + {0x86b8, 0x0002e528}, {0x86bc, 0x0baa54ec}, - {0x86c0, 0xe52a0022}, + {0x86c0, 0xe5280022}, {0x86c4, 0xe3e40002}, {0x86c8, 0x0001e356}, {0x86cc, 0x0baae35e}, {0x86d0, 0xe3e430ec}, {0x86d4, 0x0001e356}, {0x86d8, 0x6d0f6c67}, - {0x86dc, 0xe52ae39c}, + {0x86dc, 0xe528e39c}, {0x86e0, 0xe39c6c8b}, - {0x86e4, 0x0bace52a}, + {0x86e4, 0x0bace528}, {0x86e8, 0x6d0f6cb3}, - {0x86ec, 0xe52ae39c}, + {0x86ec, 0xe528e39c}, {0x86f0, 0x6cdb0bad}, {0x86f4, 0xe39c6d0f}, - {0x86f8, 0x6cf5e52a}, + {0x86f8, 0x6cf5e528}, {0x86fc, 0xe39c6d0f}, - {0x8700, 0x6c0be52a}, + {0x8700, 0x6c0be528}, {0x8704, 0xe39c6d00}, - {0x8708, 0x6c25e52a}, - {0x870c, 0xe52ae39c}, + {0x8708, 0x6c25e528}, + {0x870c, 0xe528e39c}, {0x8710, 0x6c4df8c6}, - {0x8714, 0xe52ae39c}, + {0x8714, 0xe528e39c}, {0x8718, 0x6c75f9cf}, - {0x871c, 0xe52ae39c}, + {0x871c, 0xe528e39c}, {0x8720, 0xe39c6c99}, - {0x8724, 0xfad6e52a}, + {0x8724, 0xfad6e528}, {0x8728, 0x21e87410}, {0x872c, 0x6e670009}, {0x8730, 0xe3c46f0f}, - {0x8734, 0x7410e52f}, + {0x8734, 0x7410e52d}, {0x8738, 0x000b21e8}, {0x873c, 0xe3c46e8b}, - {0x8740, 0x7410e52f}, + {0x8740, 0x7410e52d}, {0x8744, 0x000d21e8}, {0x8748, 0x6f0f6eb3}, - {0x874c, 0xe52fe3c4}, + {0x874c, 0xe52de3c4}, {0x8750, 0xfe07ff08}, {0x8754, 0x21e87410}, {0x8758, 0x6ec7000e}, - {0x875c, 0xe52fe3c4}, + {0x875c, 0xe52de3c4}, {0x8760, 0x21e87410}, {0x8764, 0x6edb000f}, {0x8768, 0xe3c46f0f}, - {0x876c, 0x7410e52f}, + {0x876c, 0x7410e52d}, {0x8770, 0x001021e8}, {0x8774, 0xe3c46eef}, - {0x8778, 0xff03e52f}, - {0x877c, 0xe52ffe02}, + {0x8778, 0xff03e52d}, + {0x877c, 0xe52dfe02}, {0x8780, 0x21e87410}, {0x8784, 0x6e110013}, {0x8788, 0xe3c46f00}, - {0x878c, 0xff03e52f}, - {0x8790, 0xe52ffe02}, + {0x878c, 0xff03e52d}, + {0x8790, 0xe52dfe02}, {0x8794, 0x21e87410}, {0x8798, 0x6e250014}, - {0x879c, 0xe52fe3c4}, + {0x879c, 0xe52de3c4}, {0x87a0, 0xff08fc24}, {0x87a4, 0x7410fe07}, {0x87a8, 0x001521e8}, {0x87ac, 0xe3c46e39}, - {0x87b0, 0x7410e52f}, + {0x87b0, 0x7410e52d}, {0x87b4, 0x001621e8}, {0x87b8, 0xe3c46e4d}, - {0x87bc, 0xfd27e52f}, + {0x87bc, 0xfd27e52d}, {0x87c0, 0x21e87410}, {0x87c4, 0x6e750018}, - {0x87c8, 0xe52fe3c4}, + {0x87c8, 0xe52de3c4}, {0x87cc, 0x21e87410}, {0x87d0, 0x6e99001a}, - {0x87d4, 0xe52fe3c4}, + {0x87d4, 0xe52de3c4}, {0x87d8, 0xe36afe24}, {0x87dc, 0x63404380}, {0x87e0, 0x43006880}, {0x87e4, 0x31300bac}, - {0x87e8, 0xe52f0022}, + {0x87e8, 0xe52d0022}, {0x87ec, 0x54ec0002}, {0x87f0, 0x00220baa}, - {0x87f4, 0x0002e52f}, + {0x87f4, 0x0002e52d}, {0x87f8, 0xe362e3e4}, {0x87fc, 0xe36a0001}, {0x8800, 0x63404380}, @@ -2770,7 +2770,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8838, 0x55010004}, {0x883c, 0x66055b40}, {0x8840, 0x62000007}, - {0x8844, 0xe40e6300}, + {0x8844, 0xe40c6300}, {0x8848, 0x09000004}, {0x884c, 0x0b400a01}, {0x8850, 0x0e010d00}, @@ -2782,13 +2782,13 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8868, 0x00044d01}, {0x886c, 0x00074300}, {0x8870, 0x05a30562}, - {0x8874, 0xe40e961f}, + {0x8874, 0xe40c961f}, {0x8878, 0xe37e0004}, {0x887c, 0x06a20007}, - {0x8880, 0xe40e07a3}, + {0x8880, 0xe40c07a3}, {0x8884, 0xe37e0004}, - {0x8888, 0x0002e3fe}, - {0x888c, 0x4380e406}, + {0x8888, 0x0002e3fc}, + {0x888c, 0x4380e404}, {0x8890, 0x4d000007}, {0x8894, 0x43000004}, {0x8898, 0x000742fe}, @@ -2815,13 +2815,13 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x88ec, 0x42000004}, {0x88f0, 0x00070001}, {0x88f4, 0x62006220}, - {0x88f8, 0x0001e406}, + {0x88f8, 0x0001e404}, {0x88fc, 0x63000007}, {0x8900, 0x09000004}, {0x8904, 0x0e010a00}, {0x8908, 0x00070032}, - {0x890c, 0xe40e06a2}, - {0x8910, 0x0002e41a}, + {0x890c, 0xe40c06a2}, + {0x8910, 0x0002e418}, {0x8914, 0x000742fe}, {0x8918, 0x00044d00}, {0x891c, 0x00014200}, @@ -2839,50 +2839,50 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x894c, 0x00014300}, {0x8950, 0x6c060005}, {0x8954, 0xe2aae298}, - {0x8958, 0xe42ae285}, - {0x895c, 0xe432e2f3}, + {0x8958, 0xe428e285}, + {0x895c, 0xe430e2f3}, {0x8960, 0x0001e30c}, {0x8964, 0x0005e285}, {0x8968, 0xe2986c06}, - {0x896c, 0xe42ae4a9}, - {0x8970, 0xe432e2f3}, + {0x896c, 0xe428e4a7}, + {0x8970, 0xe430e2f3}, {0x8974, 0x0001e30c}, {0x8978, 0x6c000005}, {0x897c, 0xe2aae298}, - {0x8980, 0xe445e285}, - {0x8984, 0xe44de2f3}, + {0x8980, 0xe443e285}, + {0x8984, 0xe44be2f3}, {0x8988, 0x0001e30c}, {0x898c, 0x0005e285}, {0x8990, 0xe2986c00}, - {0x8994, 0xe445e4a9}, - {0x8998, 0xe44de2f3}, + {0x8994, 0xe443e4a7}, + {0x8998, 0xe44be2f3}, {0x899c, 0x0001e30c}, {0x89a0, 0x6c040005}, {0x89a4, 0xe2aae298}, - {0x89a8, 0xe460e285}, - {0x89ac, 0xe468e2f3}, + {0x89a8, 0xe45ee285}, + {0x89ac, 0xe466e2f3}, {0x89b0, 0x0001e30c}, {0x89b4, 0x0005e285}, {0x89b8, 0xe2986c04}, - {0x89bc, 0xe460e4a9}, - {0x89c0, 0xe468e2f3}, + {0x89bc, 0xe45ee4a7}, + {0x89c0, 0xe466e2f3}, {0x89c4, 0x0001e30c}, {0x89c8, 0x6c020005}, {0x89cc, 0xe2aae298}, - {0x89d0, 0xe47be285}, - {0x89d4, 0xe483e2f3}, + {0x89d0, 0xe479e285}, + {0x89d4, 0xe481e2f3}, {0x89d8, 0x0001e30c}, {0x89dc, 0x0005e285}, {0x89e0, 0xe2986c02}, - {0x89e4, 0xe47be4a9}, - {0x89e8, 0xe483e2f3}, + {0x89e4, 0xe479e4a7}, + {0x89e8, 0xe481e2f3}, {0x89ec, 0x0001e30c}, {0x89f0, 0x43800004}, {0x89f4, 0x610a6008}, {0x89f8, 0x63ce6200}, {0x89fc, 0x60800006}, {0x8a00, 0x00047f00}, - {0x8a04, 0xe4e04300}, + {0x8a04, 0xe4de4300}, {0x8a08, 0x00070001}, {0x8a0c, 0x4d015500}, {0x8a10, 0x74200004}, @@ -2895,22 +2895,22 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8a2c, 0x00014300}, {0x8a30, 0x74200004}, {0x8a34, 0x77000005}, - {0x8a38, 0x73887e07}, + {0x8a38, 0x73887e06}, {0x8a3c, 0x8f007380}, {0x8a40, 0x0004140f}, {0x8a44, 0x00057430}, {0x8a48, 0x00017300}, - {0x8a4c, 0x0005e496}, + {0x8a4c, 0x0005e494}, {0x8a50, 0x00017300}, {0x8a54, 0x43800004}, {0x8a58, 0x0006b103}, {0x8a5c, 0x91037cdb}, {0x8a60, 0x40db0007}, {0x8a64, 0x43000004}, - {0x8a68, 0x0005e496}, + {0x8a68, 0x0005e494}, {0x8a6c, 0x00067380}, {0x8a70, 0x60025d01}, - {0x8a74, 0xe4ba6200}, + {0x8a74, 0xe4b86200}, {0x8a78, 0x73000005}, {0x8a7c, 0x76080007}, {0x8a80, 0x00047578}, @@ -2943,8 +2943,8 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8aec, 0x7cdb0006}, {0x8af0, 0x00079103}, {0x8af4, 0x000440db}, - {0x8af8, 0xe4964300}, - {0x8afc, 0xe4ba7e03}, + {0x8af8, 0xe4944300}, + {0x8afc, 0xe4b87e03}, {0x8b00, 0x43800004}, {0x8b04, 0x0006b103}, {0x8b08, 0x91037c5b}, @@ -2976,14 +2976,14 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8b70, 0x43000004}, {0x8b74, 0x73000005}, {0x8b78, 0x76000007}, - {0x8b7c, 0xe4c30001}, + {0x8b7c, 0xe4c10001}, {0x8b80, 0x00040001}, {0x8b84, 0x60004380}, {0x8b88, 0x62016100}, {0x8b8c, 0x00066310}, {0x8b90, 0x00046000}, {0x8b94, 0x00014300}, - {0x8b98, 0x0001e4e0}, + {0x8b98, 0x0001e4de}, {0x8b9c, 0x4e004f02}, {0x8ba0, 0x52015302}, {0x8ba4, 0x140f0001}, @@ -3030,7 +3030,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8c48, 0xbf1ae3ac}, {0x8c4c, 0xe36e300b}, {0x8c50, 0xe390e377}, - {0x8c54, 0x0001e523}, + {0x8c54, 0x0001e521}, {0x8c58, 0x54c054bf}, {0x8c5c, 0x54c154a3}, {0x8c60, 0x4c1854a4}, @@ -3039,7 +3039,7 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8c6c, 0xbf051402}, {0x8c70, 0x54a354c1}, {0x8c74, 0xbf011402}, - {0x8c78, 0x54dfe534}, + {0x8c78, 0x54dfe532}, {0x8c7c, 0x54bf0001}, {0x8c80, 0x050a54e5}, {0x8c84, 0x000154df}, @@ -3060,186 +3060,185 @@ static const struct rtw89_reg2_def rtw89_8851b_phy_nctl_regs[] = { {0x8cc0, 0x56005610}, {0x8cc4, 0x00018c00}, {0x8cc8, 0x57005704}, - {0x8ccc, 0xa7038e00}, - {0x8cd0, 0x33f0aff7}, - {0x8cd4, 0xaf034019}, - {0x8cd8, 0x33f0402b}, - {0x8cdc, 0x33df402b}, - {0x8ce0, 0x57005708}, - {0x8ce4, 0x57818e00}, - {0x8ce8, 0x8e005780}, - {0x8cec, 0x00074380}, - {0x8cf0, 0x5c005c01}, - {0x8cf4, 0x00041403}, - {0x8cf8, 0x00014300}, - {0x8cfc, 0x0007427f}, - {0x8d00, 0x62006280}, - {0x8d04, 0x00049200}, - {0x8d08, 0x00014200}, - {0x8d0c, 0x0007427f}, - {0x8d10, 0x63146394}, - {0x8d14, 0x00049200}, - {0x8d18, 0x00014200}, - {0x8d1c, 0x42fe0004}, - {0x8d20, 0x4d010007}, - {0x8d24, 0x42000004}, - {0x8d28, 0x140f7420}, - {0x8d2c, 0x57005710}, - {0x8d30, 0x0001141f}, - {0x8d34, 0x42fe0004}, - {0x8d38, 0x4d010007}, - {0x8d3c, 0x42000004}, - {0x8d40, 0x140f7420}, - {0x8d44, 0x000742bf}, - {0x8d48, 0x62006240}, - {0x8d4c, 0x0004141f}, - {0x8d50, 0x00014200}, - {0x8d54, 0x5d060006}, - {0x8d58, 0x61046003}, - {0x8d5c, 0x00056201}, - {0x8d60, 0x00017310}, - {0x8d64, 0x43800004}, - {0x8d68, 0x5e010007}, - {0x8d6c, 0x140a5e00}, - {0x8d70, 0x0006b103}, - {0x8d74, 0x91037f07}, - {0x8d78, 0x43070007}, - {0x8d7c, 0x5c000006}, - {0x8d80, 0x5e035d02}, - {0x8d84, 0x43000004}, - {0x8d88, 0x00060001}, - {0x8d8c, 0x60005d04}, - {0x8d90, 0x62016104}, - {0x8d94, 0x73100005}, - {0x8d98, 0x00040001}, - {0x8d9c, 0x00074380}, - {0x8da0, 0x5e005e01}, - {0x8da4, 0xb103140a}, - {0x8da8, 0x7fc60006}, - {0x8dac, 0x00079103}, - {0x8db0, 0x000643c6}, - {0x8db4, 0x5d025c00}, - {0x8db8, 0x00045e03}, - {0x8dbc, 0x00014300}, - {0x8dc0, 0x5d040006}, - {0x8dc4, 0x61046000}, - {0x8dc8, 0x00056201}, - {0x8dcc, 0x00017310}, - {0x8dd0, 0x43800004}, - {0x8dd4, 0x5e010007}, - {0x8dd8, 0x140a5e00}, - {0x8ddc, 0x0006b103}, - {0x8de0, 0x91037fc6}, - {0x8de4, 0x43c60007}, - {0x8de8, 0x5c000006}, - {0x8dec, 0x5e035d02}, - {0x8df0, 0x43000004}, - {0x8df4, 0x00060001}, - {0x8df8, 0x60025d00}, - {0x8dfc, 0x62016100}, - {0x8e00, 0x73000005}, - {0x8e04, 0x00040001}, - {0x8e08, 0x00074380}, - {0x8e0c, 0x5e005e01}, - {0x8e10, 0xb103140a}, - {0x8e14, 0x7fc00006}, - {0x8e18, 0x00079103}, - {0x8e1c, 0x000643c0}, - {0x8e20, 0x5d025c00}, - {0x8e24, 0x00045e03}, - {0x8e28, 0x00014300}, - {0x8e2c, 0x7e020005}, - {0x8e30, 0x42f70004}, - {0x8e34, 0x6c080005}, - {0x8e38, 0x42700004}, - {0x8e3c, 0x73810005}, - {0x8e40, 0x93007380}, - {0x8e44, 0x42f70004}, - {0x8e48, 0x6c000005}, - {0x8e4c, 0x42000004}, - {0x8e50, 0x00040001}, - {0x8e54, 0x00074380}, - {0x8e58, 0x73007304}, - {0x8e5c, 0x72401405}, - {0x8e60, 0x43000004}, - {0x8e64, 0x74040006}, - {0x8e68, 0x40010007}, - {0x8e6c, 0xab004000}, - {0x8e70, 0x0001140f}, - {0x8e74, 0x140ae517}, - {0x8e78, 0x140ae4c3}, - {0x8e7c, 0x0001e51e}, - {0x8e80, 0xe4c3e517}, - {0x8e84, 0x00040001}, - {0x8e88, 0x00047410}, - {0x8e8c, 0x42f04380}, - {0x8e90, 0x62080007}, - {0x8e94, 0x24206301}, - {0x8e98, 0x14c80000}, - {0x8e9c, 0x00002428}, - {0x8ea0, 0x1a4215f4}, - {0x8ea4, 0x6300000b}, - {0x8ea8, 0x42000004}, - {0x8eac, 0x74304300}, - {0x8eb0, 0x4380140f}, - {0x8eb4, 0x73080007}, - {0x8eb8, 0x00047300}, - {0x8ebc, 0x00014300}, - {0x8ec0, 0x4bf00007}, - {0x8ec4, 0x490b4a8f}, - {0x8ec8, 0x4a8e48f1}, - {0x8ecc, 0x48a5490a}, - {0x8ed0, 0x49094a8d}, - {0x8ed4, 0x4a8c487d}, - {0x8ed8, 0x48754908}, - {0x8edc, 0x49074a8b}, - {0x8ee0, 0x4a8a4889}, - {0x8ee4, 0x48b74906}, - {0x8ee8, 0x49054a89}, - {0x8eec, 0x4a8848fc}, - {0x8ef0, 0x48564905}, - {0x8ef4, 0x49044a87}, - {0x8ef8, 0x4a8648c1}, - {0x8efc, 0x483d4904}, - {0x8f00, 0x49034a85}, - {0x8f04, 0x4a8448c7}, - {0x8f08, 0x485e4903}, - {0x8f0c, 0x49024a83}, - {0x8f10, 0x4a8248ac}, - {0x8f14, 0x48624902}, - {0x8f18, 0x49024a81}, - {0x8f1c, 0x4a804820}, - {0x8f20, 0x48004900}, - {0x8f24, 0x49014a90}, - {0x8f28, 0x4a10481f}, - {0x8f2c, 0x00060001}, - {0x8f30, 0x5f005f80}, - {0x8f34, 0x00059900}, - {0x8f38, 0x00017300}, - {0x8f3c, 0x63800006}, - {0x8f40, 0x98006300}, - {0x8f44, 0x549f0001}, - {0x8f48, 0x5c015400}, - {0x8f4c, 0x540054df}, - {0x8f50, 0x00015c02}, - {0x8f54, 0x07145c01}, - {0x8f58, 0x5c025400}, - {0x8f5c, 0x5c020001}, - {0x8f60, 0x54000714}, - {0x8f64, 0x00015c01}, - {0x8f68, 0x4c184c98}, - {0x8f6c, 0x00080001}, - {0x8f70, 0x5c020004}, - {0x8f74, 0x09017430}, - {0x8f78, 0x0ba60c01}, - {0x8f7c, 0x77800005}, - {0x8f80, 0x52200007}, - {0x8f84, 0x43800004}, - {0x8f88, 0x610a6008}, - {0x8f8c, 0x63c26200}, - {0x8f90, 0x5c000007}, - {0x8f94, 0x43000004}, - {0x8f98, 0x00000001}, + {0x8ccc, 0x33ee8e00}, + {0x8cd0, 0xaf034019}, + {0x8cd4, 0x33ee402b}, + {0x8cd8, 0x33df402b}, + {0x8cdc, 0x57005708}, + {0x8ce0, 0x57818e00}, + {0x8ce4, 0x8e005780}, + {0x8ce8, 0x00074380}, + {0x8cec, 0x5c005c01}, + {0x8cf0, 0x00041403}, + {0x8cf4, 0x00014300}, + {0x8cf8, 0x0007427f}, + {0x8cfc, 0x62006280}, + {0x8d00, 0x00049200}, + {0x8d04, 0x00014200}, + {0x8d08, 0x0007427f}, + {0x8d0c, 0x63146394}, + {0x8d10, 0x00049200}, + {0x8d14, 0x00014200}, + {0x8d18, 0x42fe0004}, + {0x8d1c, 0x4d010007}, + {0x8d20, 0x42000004}, + {0x8d24, 0x140f7420}, + {0x8d28, 0x57005710}, + {0x8d2c, 0x0001141f}, + {0x8d30, 0x42fe0004}, + {0x8d34, 0x4d010007}, + {0x8d38, 0x42000004}, + {0x8d3c, 0x140f7420}, + {0x8d40, 0x000742bf}, + {0x8d44, 0x62006240}, + {0x8d48, 0x0004141f}, + {0x8d4c, 0x00014200}, + {0x8d50, 0x5d060006}, + {0x8d54, 0x61046003}, + {0x8d58, 0x00056200}, + {0x8d5c, 0x00017310}, + {0x8d60, 0x43800004}, + {0x8d64, 0x5e010007}, + {0x8d68, 0x140a5e00}, + {0x8d6c, 0x0006b103}, + {0x8d70, 0x91037f07}, + {0x8d74, 0x43070007}, + {0x8d78, 0x5c000006}, + {0x8d7c, 0x5e035d02}, + {0x8d80, 0x43000004}, + {0x8d84, 0x00060001}, + {0x8d88, 0x60005d04}, + {0x8d8c, 0x62006104}, + {0x8d90, 0x73100005}, + {0x8d94, 0x00040001}, + {0x8d98, 0x00074380}, + {0x8d9c, 0x5e005e01}, + {0x8da0, 0xb103140a}, + {0x8da4, 0x7fc60006}, + {0x8da8, 0x00079103}, + {0x8dac, 0x000643c6}, + {0x8db0, 0x5d025c00}, + {0x8db4, 0x00045e03}, + {0x8db8, 0x00014300}, + {0x8dbc, 0x5d040006}, + {0x8dc0, 0x61046000}, + {0x8dc4, 0x00056200}, + {0x8dc8, 0x00017310}, + {0x8dcc, 0x43800004}, + {0x8dd0, 0x5e010007}, + {0x8dd4, 0x140a5e00}, + {0x8dd8, 0x0006b103}, + {0x8ddc, 0x91037fc6}, + {0x8de0, 0x43c60007}, + {0x8de4, 0x5c000006}, + {0x8de8, 0x5e035d02}, + {0x8dec, 0x43000004}, + {0x8df0, 0x00060001}, + {0x8df4, 0x60025d00}, + {0x8df8, 0x62006100}, + {0x8dfc, 0x73000005}, + {0x8e00, 0x00040001}, + {0x8e04, 0x00074380}, + {0x8e08, 0x5e005e01}, + {0x8e0c, 0xb103140a}, + {0x8e10, 0x7fc00006}, + {0x8e14, 0x00079103}, + {0x8e18, 0x000643c0}, + {0x8e1c, 0x5d025c00}, + {0x8e20, 0x00045e03}, + {0x8e24, 0x00014300}, + {0x8e28, 0x7e020005}, + {0x8e2c, 0x42f70004}, + {0x8e30, 0x6c080005}, + {0x8e34, 0x42700004}, + {0x8e38, 0x73810005}, + {0x8e3c, 0x93007380}, + {0x8e40, 0x42f70004}, + {0x8e44, 0x6c000005}, + {0x8e48, 0x42000004}, + {0x8e4c, 0x00040001}, + {0x8e50, 0x00074380}, + {0x8e54, 0x73007304}, + {0x8e58, 0x72401405}, + {0x8e5c, 0x43000004}, + {0x8e60, 0x74040006}, + {0x8e64, 0x40010007}, + {0x8e68, 0xab004000}, + {0x8e6c, 0x0001140f}, + {0x8e70, 0x140ae515}, + {0x8e74, 0x140ae4c1}, + {0x8e78, 0x0001e51c}, + {0x8e7c, 0xe4c1e515}, + {0x8e80, 0x00040001}, + {0x8e84, 0x00047410}, + {0x8e88, 0x42f04380}, + {0x8e8c, 0x62080007}, + {0x8e90, 0x24206301}, + {0x8e94, 0x14c80000}, + {0x8e98, 0x00002428}, + {0x8e9c, 0x1a4215f4}, + {0x8ea0, 0x6300000b}, + {0x8ea4, 0x42000004}, + {0x8ea8, 0x74304300}, + {0x8eac, 0x4380140f}, + {0x8eb0, 0x73080007}, + {0x8eb4, 0x00047300}, + {0x8eb8, 0x00014300}, + {0x8ebc, 0x4bf00007}, + {0x8ec0, 0x490b4a8f}, + {0x8ec4, 0x4a8e48f1}, + {0x8ec8, 0x48a5490a}, + {0x8ecc, 0x49094a8d}, + {0x8ed0, 0x4a8c487d}, + {0x8ed4, 0x48754908}, + {0x8ed8, 0x49074a8b}, + {0x8edc, 0x4a8a4889}, + {0x8ee0, 0x48b74906}, + {0x8ee4, 0x49054a89}, + {0x8ee8, 0x4a8848fc}, + {0x8eec, 0x48564905}, + {0x8ef0, 0x49044a87}, + {0x8ef4, 0x4a8648c1}, + {0x8ef8, 0x483d4904}, + {0x8efc, 0x49034a85}, + {0x8f00, 0x4a8448c7}, + {0x8f04, 0x485e4903}, + {0x8f08, 0x49024a83}, + {0x8f0c, 0x4a8248ac}, + {0x8f10, 0x48624902}, + {0x8f14, 0x49024a81}, + {0x8f18, 0x4a804820}, + {0x8f1c, 0x48004900}, + {0x8f20, 0x49014a90}, + {0x8f24, 0x4a10481f}, + {0x8f28, 0x00060001}, + {0x8f2c, 0x5f005f80}, + {0x8f30, 0x00059900}, + {0x8f34, 0x00017300}, + {0x8f38, 0x63800006}, + {0x8f3c, 0x98006300}, + {0x8f40, 0x549f0001}, + {0x8f44, 0x5c015400}, + {0x8f48, 0x540054df}, + {0x8f4c, 0x00015c02}, + {0x8f50, 0x07145c01}, + {0x8f54, 0x5c025400}, + {0x8f58, 0x5c020001}, + {0x8f5c, 0x54000714}, + {0x8f60, 0x00015c01}, + {0x8f64, 0x4c184c98}, + {0x8f68, 0x00080001}, + {0x8f6c, 0x5c020004}, + {0x8f70, 0x09017430}, + {0x8f74, 0x0ba60c01}, + {0x8f78, 0x77800005}, + {0x8f7c, 0x52200007}, + {0x8f80, 0x43800004}, + {0x8f84, 0x610a6008}, + {0x8f88, 0x63c26200}, + {0x8f8c, 0x5c000007}, + {0x8f90, 0x43000004}, + {0x8f94, 0x00000001}, {0x8080, 0x00000004}, {0x8080, 0x00000000}, {0x8088, 0x00000000}, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851be.c b/drivers/net/wireless/realtek/rtw89/rtw8851be.c index 5810af825242..598730831707 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -89,6 +89,7 @@ static struct pci_driver rtw89_8851be_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8851be_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c new file mode 100644 index 000000000000..c3722547c6b0 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include <linux/module.h> +#include <linux/usb.h> +#include "rtw8851b.h" +#include "usb.h" + +static const struct rtw89_driver_info rtw89_8851bu_info = { + .chip = &rtw8851b_chip_info, + .variant = NULL, + .quirks = NULL, +}; + +static const struct usb_device_id rtw_8851bu_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb851, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + /* TP-Link Archer TX10UB Nano */ + { USB_DEVICE_AND_INTERFACE_INFO(0x3625, 0x010b, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + /* Edimax EW-7611UXB */ + { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0xe611, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8851bu_info }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8851bu_id_table); + +static struct usb_driver rtw_8851bu_driver = { + .name = KBUILD_MODNAME, + .id_table = rtw_8851bu_id_table, + .probe = rtw89_usb_probe, + .disconnect = rtw89_usb_disconnect, +}; +module_usb_driver(rtw_8851bu_driver); + +MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>"); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8851BU driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index cd5987fc52d7..3bbe2a808844 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -2128,6 +2128,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .set_txpwr_ctrl = rtw8852a_set_txpwr_ctrl, .init_txpwr_unit = rtw8852a_init_txpwr_unit, .get_thermal = rtw8852a_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8852a_ctrl_btg_bt_rx, .query_ppdu = rtw8852a_query_ppdu, .convert_rpl_to_rssi = NULL, @@ -2150,6 +2151,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, @@ -2183,8 +2185,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .max_amsdu_limit = 3500, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852a_hfc_param_ini_pcie, - .dle_mem = rtw8852a_dle_mem_pcie, + .hfc_param_ini = {rtw8852a_hfc_param_ini_pcie, NULL, NULL}, + .dle_mem = {rtw8852a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xc000, 0xd000}, @@ -2246,7 +2248,6 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .phycap_size = 128, .para_ver = 0x0, .wlcx_desired = 0x06000000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index 2037713e3952..90ffaf9f4f6a 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -91,6 +91,7 @@ static struct pci_driver rtw89_8852ae_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8852ae_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b.c b/drivers/net/wireless/realtek/rtw89/rtw8852b.c index dacdb384de2c..7ede07f7b1eb 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b.c @@ -49,6 +49,48 @@ static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_pcie[] = { [RTW89_QTA_INVALID] = {NULL}, }; +static const struct rtw89_hfc_ch_cfg rtw8852b_hfc_chcfg_usb[] = { + {18, 152, grp_0}, /* ACH 0 */ + {18, 152, grp_0}, /* ACH 1 */ + {18, 152, grp_0}, /* ACH 2 */ + {18, 152, grp_0}, /* ACH 3 */ + {0, 0, grp_0}, /* ACH 4 */ + {0, 0, grp_0}, /* ACH 5 */ + {0, 0, grp_0}, /* ACH 6 */ + {0, 0, grp_0}, /* ACH 7 */ + {18, 152, grp_0}, /* B0MGQ */ + {18, 152, grp_0}, /* B0HIQ */ + {0, 0, grp_0}, /* B1MGQ */ + {0, 0, grp_0}, /* B1HIQ */ + {0, 0, 0} /* FWCMDQ */ +}; + +static const struct rtw89_hfc_pub_cfg rtw8852b_hfc_pubcfg_usb = { + 152, /* Group 0 */ + 0, /* Group 1 */ + 152, /* Public Max */ + 0 /* WP threshold */ +}; + +static const struct rtw89_hfc_prec_cfg rtw8852b_hfc_preccfg_usb = { + 9, /* CH 0-11 pre-cost */ + 32, /* H2C pre-cost */ + 64, /* WP CH 0-7 pre-cost */ + 24, /* WP CH 8-11 pre-cost */ + 1, /* CH 0-11 full condition */ + 1, /* H2C full condition */ + 1, /* WP CH 0-7 full condition */ + 1, /* WP CH 8-11 full condition */ +}; + +static const struct rtw89_hfc_param_ini rtw8852b_hfc_param_ini_usb[] = { + [RTW89_QTA_SCC] = {rtw8852b_hfc_chcfg_usb, &rtw8852b_hfc_pubcfg_usb, + &rtw8852b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_DLFW] = {NULL, NULL, + &rtw8852b_hfc_preccfg_usb, RTW89_HCIFC_STF}, + [RTW89_QTA_INVALID] = {NULL}, +}; + static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size7, &rtw89_mac_size.ple_size6, &rtw89_mac_size.wde_qt7, @@ -66,6 +108,19 @@ static const struct rtw89_dle_mem rtw8852b_dle_mem_pcie[] = { NULL}, }; +static const struct rtw89_dle_mem rtw8852b_dle_mem_usb3[] = { + [RTW89_QTA_SCC] = {RTW89_QTA_SCC, &rtw89_mac_size.wde_size25, + &rtw89_mac_size.ple_size33, &rtw89_mac_size.wde_qt25, + &rtw89_mac_size.wde_qt25, &rtw89_mac_size.ple_qt74, + &rtw89_mac_size.ple_qt75}, + [RTW89_QTA_DLFW] = {RTW89_QTA_DLFW, &rtw89_mac_size.wde_size9, + &rtw89_mac_size.ple_size8, &rtw89_mac_size.wde_qt4, + &rtw89_mac_size.wde_qt4, &rtw89_mac_size.ple_qt13, + &rtw89_mac_size.ple_qt13}, + [RTW89_QTA_INVALID] = {RTW89_QTA_INVALID, NULL, NULL, NULL, NULL, NULL, + NULL}, +}; + static const u32 rtw8852b_h2c_regs[RTW89_H2CREG_MAX] = { R_AX_H2CREG_DATA0, R_AX_H2CREG_DATA1, R_AX_H2CREG_DATA2, R_AX_H2CREG_DATA3 @@ -299,7 +354,8 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write8_clr(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); rtw89_write8_set(rtwdev, R_AX_PLATFORM_ENABLE, B_AX_PLATFORM_EN); - rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32_clr(rtwdev, R_AX_SYS_SDIO_CTRL, B_AX_PCIE_CALIB_EN_V1); rtw89_write32_set(rtwdev, R_AX_SYS_ADIE_PAD_PWR_CTRL, B_AX_SYM_PADPDN_WL_PTA_1P3); @@ -361,7 +417,7 @@ static int rtw8852b_pwr_on_func(struct rtw89_dev *rtwdev) rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_VOL_L1_MASK, 0x9); rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_VREFPFM_L_MASK, 0xA); - if (rtwdev->hal.cv == CHIP_CBV) { + if (rtwdev->hal.cv == CHIP_CBV && rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { rtw89_write32_set(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); rtw89_write16_mask(rtwdev, R_AX_HCI_LDO_CTRL, B_AX_R_AX_VADJ_MASK, 0xA); rtw89_write32_clr(rtwdev, R_AX_PMC_DBG_CTRL2, B_AX_SYSON_DIS_PMCR_AX_WRMSK); @@ -443,10 +499,22 @@ static int rtw8852b_pwr_off_func(struct rtw89_dev *rtwdev) if (ret) return ret; - rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) + rtw89_write32(rtwdev, R_AX_WLLPS_CTRL, SW_LPS_OPTION); + else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) + rtw89_write32_clr(rtwdev, R_AX_SYS_PW_CTRL, B_AX_SOP_EDSWR); + rtw89_write32_set(rtwdev, R_AX_SYS_SWR_CTRL1, B_AX_SYM_CTRL_SPS_PWMFREQ); rtw89_write32_mask(rtwdev, R_AX_SPS_DIG_ON_CTRL0, B_AX_REG_ZCDC_H_MASK, 0x3); - rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + + if (rtwdev->hci.type == RTW89_HCI_TYPE_PCIE) { + rtw89_write32_set(rtwdev, R_AX_SYS_PW_CTRL, B_AX_APFM_SWLPS); + } else if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) { + val32 = rtw89_read32(rtwdev, R_AX_SYS_PW_CTRL); + val32 &= ~B_AX_AFSM_PCIE_SUS_EN; + val32 |= B_AX_AFSM_WLSUS_EN; + rtw89_write32(rtwdev, R_AX_SYS_PW_CTRL, val32); + } return 0; } @@ -560,8 +628,11 @@ static void rtw8852b_set_channel_help(struct rtw89_dev *rtwdev, bool enter, static void rtw8852b_rfk_init(struct rtw89_dev *rtwdev) { + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + rtwdev->is_tssi_mode[RF_PATH_A] = false; rtwdev->is_tssi_mode[RF_PATH_B] = false; + memset(rfk_mcc, 0, sizeof(*rfk_mcc)); rtw8852b_dpk_init(rtwdev); rtw8852b_rck(rtwdev); @@ -575,6 +646,7 @@ static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; + rtw8852b_mcc_get_ch_info(rtwdev, phy_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, true); rtw8852b_rx_dck(rtwdev, phy_idx, chanctx_idx); @@ -585,6 +657,7 @@ static void rtw8852b_rfk_channel(struct rtw89_dev *rtwdev, rtw8852b_dpk(rtwdev, phy_idx, chanctx_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, false); + rtw89_fw_h2c_rf_ntfy_mcc(rtwdev); } static void rtw8852b_rfk_band_changed(struct rtw89_dev *rtwdev, @@ -755,6 +828,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .set_txpwr_ctrl = rtw8852bx_set_txpwr_ctrl, .init_txpwr_unit = rtw8852bx_init_txpwr_unit, .get_thermal = rtw8852bx_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8852bx_ctrl_btg_bt_rx, .query_ppdu = rtw8852bx_query_ppdu, .convert_rpl_to_rssi = rtw8852bx_convert_rpl_to_rssi, @@ -777,6 +851,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, @@ -792,6 +867,10 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .btc_set_policy = rtw89_btc_set_policy_v1, }; +static const struct rtw89_chanctx_listener rtw8852b_chanctx_listener = { + .callbacks[RTW89_CHANCTX_CALLBACK_RFK] = rtw8852b_rfk_chanctx_cb, +}; + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8852b = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -819,8 +898,13 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x2f800, - .hfc_param_ini = rtw8852b_hfc_param_ini_pcie, - .dle_mem = rtw8852b_dle_mem_pcie, + .hfc_param_ini = {rtw8852b_hfc_param_ini_pcie, + rtw8852b_hfc_param_ini_usb, + NULL}, + .dle_mem = {rtw8852b_dle_mem_pcie, + rtw8852b_dle_mem_usb3, + rtw8852b_dle_mem_usb3, + NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, @@ -835,6 +919,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .nctl_post_table = NULL, .dflt_parms = &rtw89_8852b_dflt_parms, .rfe_parms_conf = NULL, + .chanctx_listener = &rtw8852b_chanctx_listener, .txpwr_factor_bb = 3, .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, @@ -843,7 +928,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .tssi_dbw_table = NULL, .support_macid_num = RTW89_MAX_MAC_ID_NUM, .support_link_num = 0, - .support_chanctx_num = 0, + .support_chanctx_num = 2, .support_rnr = false, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), @@ -882,7 +967,6 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .phycap_size = 128, .para_ver = 0, .wlcx_desired = 0x05050000, - .btcx_desired = 0x5, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c index 0cf03f18cbb1..3fb2972ae6f6 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_common.c @@ -172,14 +172,6 @@ static const struct rtw89_reg3_def rtw8852bx_btc_preagc_dis_defs[] = { static DECLARE_PHY_REG3_TBL(rtw8852bx_btc_preagc_dis_defs); -static void rtw8852be_efuse_parsing(struct rtw89_efuse *efuse, - struct rtw8852bx_efuse *map) -{ - ether_addr_copy(efuse->addr, map->e.mac_addr); - efuse->rfe_type = map->rfe_type; - efuse->xtal_cap = map->xtal_k; -} - static void rtw8852bx_efuse_parsing_tssi(struct rtw89_dev *rtwdev, struct rtw8852bx_efuse *map) { @@ -261,12 +253,18 @@ static int __rtw8852bx_read_efuse(struct rtw89_dev *rtwdev, u8 *log_map, switch (rtwdev->hci.type) { case RTW89_HCI_TYPE_PCIE: - rtw8852be_efuse_parsing(efuse, map); + ether_addr_copy(efuse->addr, map->e.mac_addr); + break; + case RTW89_HCI_TYPE_USB: + ether_addr_copy(efuse->addr, map->u.mac_addr); break; default: return -EOPNOTSUPP; } + efuse->rfe_type = map->rfe_type; + efuse->xtal_cap = map->xtal_k; + rtw89_info(rtwdev, "chip rfe_type is %d\n", efuse->rfe_type); return 0; diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c index fbf82d42687b..4796588c0256 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2022 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "mac.h" @@ -1145,19 +1146,19 @@ static void _lok_res_table(struct rtw89_dev *rtwdev, u8 path, u8 ibias) static bool _lok_finetune_check(struct rtw89_dev *rtwdev, u8 path) { + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 ch = rfk_mcc->table_idx; bool is_fail1, is_fail2; u32 vbuff_i; u32 vbuff_q; u32 core_i; u32 core_q; u32 tmp; - u8 ch; tmp = rtw89_read_rf(rtwdev, path, RR_TXMO, RFREG_MASK); core_i = FIELD_GET(RR_TXMO_COI, tmp); core_q = FIELD_GET(RR_TXMO_COQ, tmp); - ch = (iqk_info->iqk_times / 2) % RTW89_IQK_CHS_NR; if (core_i < 0x2 || core_i > 0x1d || core_q < 0x2 || core_q > 0x1d) is_fail1 = true; @@ -1386,26 +1387,11 @@ static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u enum rtw89_chanctx_idx chanctx_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; + u8 idx = rfk_mcc->table_idx; u32 reg_rf18; u32 reg_35c; - u8 idx; - u8 get_empty_table = false; - - for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { - if (iqk_info->iqk_mcc_ch[idx][path] == 0) { - get_empty_table = true; - break; - } - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (1)idx = %x\n", idx); - - if (!get_empty_table) { - idx = iqk_info->iqk_table_idx[path] + 1; - if (idx > 1) - idx = 0; - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (2)idx = %x\n", idx); reg_rf18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); reg_35c = rtw89_phy_read32_mask(rtwdev, R_CIRST, B_CIRST_SYN); @@ -1506,11 +1492,10 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) { - struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; - u8 idx; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + u8 idx = rfk_mcc->table_idx; - idx = iqk_info->iqk_table_idx[path]; - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (3)idx = %x\n", idx); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] idx = %x\n", idx); rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), B_COEF_SEL_IQC, idx); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), B_CFIR_LUT_G3, idx); @@ -4179,3 +4164,49 @@ void rtw8852b_set_channel_rf(struct rtw89_dev *rtwdev, rtw8852b_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type, chan->band_width); } + +void rtw8852b_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, 0); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; + u8 idx; + + for (idx = 0; idx < ARRAY_SIZE(desc); idx++) { + struct rtw89_rfk_chan_desc *p = &desc[idx]; + + p->ch = rfk_mcc->ch[idx]; + + p->has_band = true; + p->band = rfk_mcc->band[idx]; + } + + idx = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); + + rfk_mcc->ch[idx] = chan->channel; + rfk_mcc->band[idx] = chan->band_type; + rfk_mcc->table_idx = idx; +} + +void rtw8852b_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 path; + + switch (state) { + case RTW89_CHANCTX_STATE_MCC_START: + dpk->is_dpk_enable = false; + for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) + _dpk_onoff(rtwdev, path, false); + break; + case RTW89_CHANCTX_STATE_MCC_STOP: + dpk->is_dpk_enable = true; + for (path = 0; path < RTW8852B_DPK_RF_PATH; path++) + _dpk_onoff(rtwdev, path, false); + rtw8852b_dpk(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h index c31ba446e6e0..5fae980d5e2c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852b_rfk.h @@ -27,5 +27,8 @@ void rtw8852b_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, void rtw8852b_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); +void rtw8852b_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8852b_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state); #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852be.c b/drivers/net/wireless/realtek/rtw89/rtw8852be.c index abdeafc14b0b..b0726f590ca2 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -93,6 +93,7 @@ static struct pci_driver rtw89_8852be_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8852be_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c index 289dce688d72..9427823aca2f 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt.c @@ -533,8 +533,11 @@ static void rtw8852bt_set_channel_help(struct rtw89_dev *rtwdev, bool enter, static void rtw8852bt_rfk_init(struct rtw89_dev *rtwdev) { + struct rtw89_rfk_mcc_info *rfk_mcc = &rtwdev->rfk_mcc; + rtwdev->is_tssi_mode[RF_PATH_A] = false; rtwdev->is_tssi_mode[RF_PATH_B] = false; + memset(rfk_mcc, 0, sizeof(*rfk_mcc)); rtw8852bt_dpk_init(rtwdev); rtw8852bt_rck(rtwdev); @@ -548,6 +551,7 @@ static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, enum rtw89_chanctx_idx chanctx_idx = rtwvif_link->chanctx_idx; enum rtw89_phy_idx phy_idx = rtwvif_link->phy_idx; + rtw8852bt_mcc_get_ch_info(rtwdev, phy_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, true); rtw8852bt_rx_dck(rtwdev, phy_idx, chanctx_idx); @@ -558,6 +562,7 @@ static void rtw8852bt_rfk_channel(struct rtw89_dev *rtwdev, rtw8852bt_dpk(rtwdev, phy_idx, chanctx_idx); rtw89_btc_ntfy_conn_rfk(rtwdev, false); + rtw89_fw_h2c_rf_ntfy_mcc(rtwdev); } static void rtw8852bt_rfk_band_changed(struct rtw89_dev *rtwdev, @@ -689,6 +694,7 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .set_txpwr_ctrl = rtw8852bx_set_txpwr_ctrl, .init_txpwr_unit = rtw8852bx_init_txpwr_unit, .get_thermal = rtw8852bx_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8852bx_ctrl_btg_bt_rx, .query_ppdu = rtw8852bx_query_ppdu, .convert_rpl_to_rssi = rtw8852bx_convert_rpl_to_rssi, @@ -711,6 +717,7 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, @@ -726,6 +733,10 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .btc_set_policy = rtw89_btc_set_policy_v1, }; +static const struct rtw89_chanctx_listener rtw8852bt_chanctx_listener = { + .callbacks[RTW89_CHANCTX_CALLBACK_RFK] = rtw8852bt_rfk_chanctx_cb, +}; + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8852bt = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT, @@ -753,8 +764,8 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .max_amsdu_limit = 5000, .dis_2g_40m_ul_ofdma = true, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852bt_hfc_param_ini_pcie, - .dle_mem = rtw8852bt_dle_mem_pcie, + .hfc_param_ini = {rtw8852bt_hfc_param_ini_pcie, NULL, NULL}, + .dle_mem = {rtw8852bt_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, @@ -768,6 +779,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .nctl_post_table = NULL, .dflt_parms = NULL, .rfe_parms_conf = NULL, + .chanctx_listener = &rtw8852bt_chanctx_listener, .txpwr_factor_bb = 3, .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, @@ -776,7 +788,7 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .tssi_dbw_table = NULL, .support_macid_num = RTW89_MAX_MAC_ID_NUM, .support_link_num = 0, - .support_chanctx_num = 1, + .support_chanctx_num = 2, .support_rnr = false, .support_bands = BIT(NL80211_BAND_2GHZ) | BIT(NL80211_BAND_5GHZ), @@ -815,7 +827,6 @@ const struct rtw89_chip_info rtw8852bt_chip_info = { .phycap_size = 128, .para_ver = 0, .wlcx_desired = 0x070e0000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c index 6e6889eea9a0..d0e299803225 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.c @@ -2,6 +2,7 @@ /* Copyright(c) 2024 Realtek Corporation */ +#include "chan.h" #include "coex.h" #include "debug.h" #include "fw.h" @@ -1529,26 +1530,11 @@ static void _iqk_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, u enum rtw89_chanctx_idx chanctx_idx) { const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, chanctx_idx); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; - u8 get_empty_table = false; + u8 idx = rfk_mcc->table_idx; u32 reg_rf18; u32 reg_35c; - u8 idx; - - for (idx = 0; idx < RTW89_IQK_CHS_NR; idx++) { - if (iqk_info->iqk_mcc_ch[idx][path] == 0) { - get_empty_table = true; - break; - } - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (1)idx = %x\n", idx); - - if (!get_empty_table) { - idx = iqk_info->iqk_table_idx[path] + 1; - if (idx > 1) - idx = 0; - } - rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK] (2)idx = %x\n", idx); reg_rf18 = rtw89_read_rf(rtwdev, path, RR_CFGCH, RFREG_MASK); reg_35c = rtw89_phy_read32_mask(rtwdev, R_CIRST, B_CIRST_SYN); @@ -1640,7 +1626,8 @@ static void _iqk_afebb_restore(struct rtw89_dev *rtwdev, static void _iqk_preset(struct rtw89_dev *rtwdev, u8 path) { - u8 idx = 0; + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + u8 idx = rfk_mcc->table_idx; rtw89_phy_write32_mask(rtwdev, R_COEF_SEL + (path << 8), 0x00000001, idx); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT + (path << 8), 0x00000008, idx); @@ -4252,3 +4239,49 @@ void rtw8852bt_set_channel_rf(struct rtw89_dev *rtwdev, rtw8852bt_ctrl_bw_ch(rtwdev, phy_idx, chan->channel, chan->band_type, chan->band_width); } + +void rtw8852bt_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) +{ + const struct rtw89_chan *chan = rtw89_mgnt_chan_get(rtwdev, 0); + struct rtw89_rfk_mcc_info_data *rfk_mcc = rtwdev->rfk_mcc.data; + struct rtw89_rfk_chan_desc desc[__RTW89_RFK_CHS_NR_V0] = {}; + u8 idx; + + for (idx = 0; idx < ARRAY_SIZE(desc); idx++) { + struct rtw89_rfk_chan_desc *p = &desc[idx]; + + p->ch = rfk_mcc->ch[idx]; + + p->has_band = true; + p->band = rfk_mcc->band[idx]; + } + + idx = rtw89_rfk_chan_lookup(rtwdev, desc, ARRAY_SIZE(desc), chan); + + rfk_mcc->ch[idx] = chan->channel; + rfk_mcc->band[idx] = chan->band_type; + rfk_mcc->table_idx = idx; +} + +void rtw8852bt_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state) +{ + struct rtw89_dpk_info *dpk = &rtwdev->dpk; + u8 path; + + switch (state) { + case RTW89_CHANCTX_STATE_MCC_START: + dpk->is_dpk_enable = false; + for (path = 0; path < RTW8852BT_SS; path++) + _dpk_onoff(rtwdev, path, false); + break; + case RTW89_CHANCTX_STATE_MCC_STOP: + dpk->is_dpk_enable = true; + for (path = 0; path < RTW8852BT_SS; path++) + _dpk_onoff(rtwdev, path, false); + rtw8852bt_dpk(rtwdev, RTW89_PHY_0, RTW89_CHANCTX_0); + break; + default: + break; + } +} diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h index e34560b4905f..a663bbda4075 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bt_rfk.h @@ -27,5 +27,8 @@ void rtw8852bt_wifi_scan_notify(struct rtw89_dev *rtwdev, bool scan_start, void rtw8852bt_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx); +void rtw8852bt_mcc_get_ch_info(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx); +void rtw8852bt_rfk_chanctx_cb(struct rtw89_dev *rtwdev, + enum rtw89_chanctx_state state); #endif diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c index b69fa17beb33..a584c75b801d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c @@ -95,6 +95,7 @@ static struct pci_driver rtw89_8852bte_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8852bte_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c new file mode 100644 index 000000000000..b315cb997758 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include <linux/module.h> +#include <linux/usb.h> +#include "rtw8852b.h" +#include "usb.h" + +static const struct rtw89_driver_info rtw89_8852bu_info = { + .chip = &rtw8852b_chip_info, + .variant = NULL, + .quirks = NULL, +}; + +static const struct usb_device_id rtw_8852bu_id_table[] = { + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb832, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb83a, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb852, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xb85a, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0bda, 0xa85b, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0586, 0x3428, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0b05, 0x1a62, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x0db0, 0x6931, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6121, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0100, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0108, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + { USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x6822, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&rtw89_8852bu_info }, + {}, +}; +MODULE_DEVICE_TABLE(usb, rtw_8852bu_id_table); + +static struct usb_driver rtw_8852bu_driver = { + .name = KBUILD_MODNAME, + .id_table = rtw_8852bu_id_table, + .probe = rtw89_usb_probe, + .disconnect = rtw89_usb_disconnect, +}; +module_usb_driver(rtw_8852bu_driver); + +MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>"); +MODULE_DESCRIPTION("Realtek 802.11ax wireless 8852BU driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852c.c b/drivers/net/wireless/realtek/rtw89/rtw8852c.c index 2a6143a8d256..88cf8ea13e7c 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852c.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852c.c @@ -2948,6 +2948,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .set_txpwr_ctrl = rtw8852c_set_txpwr_ctrl, .init_txpwr_unit = rtw8852c_init_txpwr_unit, .get_thermal = rtw8852c_get_thermal, + .chan_to_rf18_val = NULL, .ctrl_btg_bt_rx = rtw8852c_ctrl_btg_bt_rx, .query_ppdu = rtw8852c_query_ppdu, .convert_rpl_to_rssi = NULL, @@ -2970,6 +2971,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl, .h2c_ampdu_cmac_tbl = NULL, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl, + .h2c_punctured_cmac_tbl = NULL, .h2c_default_dmac_tbl = NULL, .h2c_update_beacon = rtw89_fw_h2c_update_beacon, .h2c_ba_cam = rtw89_fw_h2c_ba_cam, @@ -3003,8 +3005,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .max_amsdu_limit = 8000, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x6f800, - .hfc_param_ini = rtw8852c_hfc_param_ini_pcie, - .dle_mem = rtw8852c_dle_mem_pcie, + .hfc_param_ini = {rtw8852c_hfc_param_ini_pcie, NULL, NULL}, + .dle_mem = {rtw8852c_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 16, .wde_qempty_mgq_grpsel = 16, .rf_base_addr = {0xe000, 0xf000}, @@ -3069,7 +3071,6 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .phycap_size = 0x60, .para_ver = 0x1, .wlcx_desired = 0x06000000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 5d864fd5974e..db01d3966c27 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -118,6 +118,7 @@ static struct pci_driver rtw89_8852ce_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8852ce_driver); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a.c b/drivers/net/wireless/realtek/rtw89/rtw8922a.c index 1d0f6e7df497..36c641e3bc13 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a.c @@ -15,7 +15,7 @@ #include "sar.h" #include "util.h" -#define RTW8922A_FW_FORMAT_MAX 3 +#define RTW8922A_FW_FORMAT_MAX 4 #define RTW8922A_FW_BASENAME "rtw89/rtw8922a_fw" #define RTW8922A_MODULE_FIRMWARE \ RTW8922A_FW_BASENAME "-" __stringify(RTW8922A_FW_FORMAT_MAX) ".bin" @@ -2390,6 +2390,48 @@ static u8 rtw8922a_get_thermal(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_p return clamp_t(int, th, 0, U8_MAX); } +static u32 rtw8922a_chan_to_rf18_val(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ + u32 val = u32_encode_bits(chan->channel, RR_CFGCH_CH); + + switch (chan->band_type) { + case RTW89_BAND_2G: + default: + break; + case RTW89_BAND_5G: + val |= u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) | + u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0); + break; + case RTW89_BAND_6G: + val |= u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) | + u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0); + break; + } + + switch (chan->band_width) { + case RTW89_CHANNEL_WIDTH_5: + case RTW89_CHANNEL_WIDTH_10: + case RTW89_CHANNEL_WIDTH_20: + default: + break; + case RTW89_CHANNEL_WIDTH_40: + val |= u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_80: + val |= u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_160: + val |= u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2); + break; + case RTW89_CHANNEL_WIDTH_320: + val |= u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2); + break; + } + + return val; +} + static void rtw8922a_btc_set_rfe(struct rtw89_dev *rtwdev) { union rtw89_btc_module_info *md = &rtwdev->btc.mdinfo; @@ -2761,6 +2803,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .set_txpwr_ctrl = rtw8922a_set_txpwr_ctrl, .init_txpwr_unit = NULL, .get_thermal = rtw8922a_get_thermal, + .chan_to_rf18_val = rtw8922a_chan_to_rf18_val, .ctrl_btg_bt_rx = rtw8922a_ctrl_btg_bt_rx, .query_ppdu = rtw8922a_query_ppdu, .convert_rpl_to_rssi = rtw8922a_convert_rpl_to_rssi, @@ -2783,6 +2826,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .h2c_assoc_cmac_tbl = rtw89_fw_h2c_assoc_cmac_tbl_g7, .h2c_ampdu_cmac_tbl = rtw89_fw_h2c_ampdu_cmac_tbl_g7, .h2c_txtime_cmac_tbl = rtw89_fw_h2c_txtime_cmac_tbl_g7, + .h2c_punctured_cmac_tbl = rtw89_fw_h2c_punctured_cmac_tbl_g7, .h2c_default_dmac_tbl = rtw89_fw_h2c_default_dmac_tbl_v2, .h2c_update_beacon = rtw89_fw_h2c_update_beacon_be, .h2c_ba_cam = rtw89_fw_h2c_ba_cam_v1, @@ -2816,8 +2860,8 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .max_amsdu_limit = 8000, .dis_2g_40m_ul_ofdma = false, .rsvd_ple_ofst = 0x8f800, - .hfc_param_ini = rtw8922a_hfc_param_ini_pcie, - .dle_mem = rtw8922a_dle_mem_pcie, + .hfc_param_ini = {rtw8922a_hfc_param_ini_pcie, NULL, NULL}, + .dle_mem = {rtw8922a_dle_mem_pcie, NULL, NULL, NULL}, .wde_qempty_acq_grpnum = 4, .wde_qempty_mgq_grpsel = 4, .rf_base_addr = {0xe000, 0xf000}, @@ -2880,7 +2924,6 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .phycap_size = 0x38, .para_ver = 0xf, .wlcx_desired = 0x07110000, - .btcx_desired = 0x7, .scbd = 0x1, .mailbox = 0x1, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c index 1659ea64ade1..fce094c7ce93 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922a_rfk.c @@ -36,8 +36,7 @@ void rtw8922a_tssi_cont_en_phyidx(struct rtw89_dev *rtwdev, bool en, u8 phy_idx) static void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, - u8 central_ch, enum rtw89_band band, - enum rtw89_bandwidth bw) + const struct rtw89_chan *chan) { const u32 rf_addr[2] = {RR_CFGCH, RR_CFGCH_V1}; struct rtw89_hal *hal = &rtwdev->hal; @@ -73,49 +72,9 @@ void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, return; } - rf_reg[path][i] &= ~(RR_CFGCH_BAND1 | RR_CFGCH_BW | + rf_reg[path][i] &= ~(RR_CFGCH_BAND1 | RR_CFGCH_BW_V2 | RR_CFGCH_BAND0 | RR_CFGCH_CH); - rf_reg[path][i] |= u32_encode_bits(central_ch, RR_CFGCH_CH); - - switch (band) { - case RTW89_BAND_2G: - default: - break; - case RTW89_BAND_5G: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BAND1_5G, RR_CFGCH_BAND1) | - u32_encode_bits(CFGCH_BAND0_5G, RR_CFGCH_BAND0); - break; - case RTW89_BAND_6G: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BAND1_6G, RR_CFGCH_BAND1) | - u32_encode_bits(CFGCH_BAND0_6G, RR_CFGCH_BAND0); - break; - } - - switch (bw) { - case RTW89_CHANNEL_WIDTH_5: - case RTW89_CHANNEL_WIDTH_10: - case RTW89_CHANNEL_WIDTH_20: - default: - break; - case RTW89_CHANNEL_WIDTH_40: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BW_V2_40M, RR_CFGCH_BW_V2); - break; - case RTW89_CHANNEL_WIDTH_80: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BW_V2_80M, RR_CFGCH_BW_V2); - break; - case RTW89_CHANNEL_WIDTH_160: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BW_V2_160M, RR_CFGCH_BW_V2); - break; - case RTW89_CHANNEL_WIDTH_320: - rf_reg[path][i] |= - u32_encode_bits(CFGCH_BW_V2_320M, RR_CFGCH_BW_V2); - break; - } + rf_reg[path][i] |= rtw89_chip_chan_to_rf18_val(rtwdev, chan); rtw89_write_rf(rtwdev, path, rf_addr[i], RFREG_MASK, rf_reg[path][i]); @@ -126,7 +85,7 @@ void rtw8922a_ctl_band_ch_bw(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, if (hal->cv != CHIP_CAV) return; - if (band == RTW89_BAND_2G) { + if (chan->band_type == RTW89_BAND_2G) { rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x80000); rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x00003); rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD1, RFREG_MASK, 0x0c990); @@ -145,8 +104,7 @@ void rtw8922a_set_channel_rf(struct rtw89_dev *rtwdev, const struct rtw89_chan *chan, enum rtw89_phy_idx phy_idx) { - rtw8922a_ctl_band_ch_bw(rtwdev, phy_idx, chan->channel, chan->band_type, - chan->band_width); + rtw8922a_ctl_band_ch_bw(rtwdev, phy_idx, chan); } enum _rf_syn_pow { diff --git a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c index 0ea8d5281c10..b730d79edd10 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -106,6 +106,7 @@ static struct pci_driver rtw89_8922ae_driver = { .probe = rtw89_pci_probe, .remove = rtw89_pci_remove, .driver.pm = &rtw89_pm_ops_be, + .err_handler = &rtw89_pci_err_handler, }; module_pci_driver(rtw89_8922ae_driver); diff --git a/drivers/net/wireless/realtek/rtw89/sar.c b/drivers/net/wireless/realtek/rtw89/sar.c index 517b66022f18..7f568ffb3766 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -199,7 +199,8 @@ struct rtw89_sar_handler rtw89_sar_handlers[RTW89_SAR_SOURCE_NR] = { typeof(_dev) _d = (_dev); \ BUILD_BUG_ON(!rtw89_sar_handlers[_s].descr_sar_source); \ BUILD_BUG_ON(!rtw89_sar_handlers[_s].query_sar_config); \ - lockdep_assert_wiphy(_d->hw->wiphy); \ + if (test_bit(RTW89_FLAG_PROBE_DONE, _d->flags)) \ + lockdep_assert_wiphy(_d->hw->wiphy); \ _d->sar._cfg_name = *(_cfg_data); \ _d->sar.src = _s; \ } while (0) @@ -499,8 +500,6 @@ static void rtw89_set_sar_from_acpi(struct rtw89_dev *rtwdev) struct rtw89_sar_cfg_acpi *cfg; int ret; - lockdep_assert_wiphy(rtwdev->hw->wiphy); - cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); if (!cfg) return; diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 811c91481441..bb39fdbcba0d 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -492,6 +492,7 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) case SER_EV_STATE_IN: wiphy_lock(wiphy); wiphy_delayed_work_cancel(wiphy, &rtwdev->track_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->track_ps_work); wiphy_unlock(wiphy); drv_stop_tx(ser); @@ -525,6 +526,8 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) drv_resume_tx(ser); wiphy_delayed_work_queue(wiphy, &rtwdev->track_work, RTW89_TRACK_WORK_PERIOD); + wiphy_delayed_work_queue(wiphy, &rtwdev->track_ps_work, + RTW89_TRACK_PS_WORK_PERIOD); break; default: @@ -566,21 +569,22 @@ static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf, const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; u32 filter_model_addr = mac->filter_model_addr; u32 indir_access_addr = mac->indir_access_addr; + u32 mem_page_size = mac->mem_page_size; u32 *ptr = (u32 *)buf; u32 base_addr, start_page, residue; u32 cnt = 0; u32 i; - start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE; - residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE; + start_page = start_addr / mem_page_size; + residue = start_addr % mem_page_size; base_addr = mac->mem_base_addrs[sel]; - base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE; + base_addr += start_page * mem_page_size; while (cnt < len) { rtw89_write32(rtwdev, filter_model_addr, base_addr); for (i = indir_access_addr + residue; - i < indir_access_addr + MAC_MEM_DUMP_PAGE_SIZE; + i < indir_access_addr + mem_page_size; i += 4, ptr++) { *ptr = rtw89_read32(rtwdev, i); cnt += 4; @@ -589,7 +593,7 @@ static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf, } residue = 0; - base_addr += MAC_MEM_DUMP_PAGE_SIZE; + base_addr += mem_page_size; } } diff --git a/drivers/net/wireless/realtek/rtw89/txrx.h b/drivers/net/wireless/realtek/rtw89/txrx.h index 94f27a9ee9f7..ec01bfc363da 100644 --- a/drivers/net/wireless/realtek/rtw89/txrx.h +++ b/drivers/net/wireless/realtek/rtw89/txrx.h @@ -73,6 +73,7 @@ static inline u8 rtw89_get_data_nss(struct rtw89_dev *rtwdev, u16 hw_rate) #define RTW89_TXWD_BODY0_FW_DL BIT(20) #define RTW89_TXWD_BODY0_CHANNEL_DMA GENMASK(19, 16) #define RTW89_TXWD_BODY0_HDR_LLC_LEN GENMASK(15, 11) +#define RTW89_TXWD_BODY0_STF_MODE BIT(10) #define RTW89_TXWD_BODY0_WD_PAGE BIT(7) #define RTW89_TXWD_BODY0_HW_AMSDU BIT(5) #define RTW89_TXWD_BODY0_HW_SSN_SEL GENMASK(3, 2) diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c new file mode 100644 index 000000000000..6cf89aee252e --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/usb.c @@ -0,0 +1,1042 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* Copyright(c) 2025 Realtek Corporation + */ + +#include <linux/usb.h> +#include "debug.h" +#include "mac.h" +#include "reg.h" +#include "txrx.h" +#include "usb.h" + +static void rtw89_usb_read_port_complete(struct urb *urb); + +static void rtw89_usb_vendorreq(struct rtw89_dev *rtwdev, u32 addr, + void *data, u16 len, u8 reqtype) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_device *udev = rtwusb->udev; + unsigned int pipe; + u16 value, index; + int attempt, ret; + + if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + return; + + value = u32_get_bits(addr, GENMASK(15, 0)); + index = u32_get_bits(addr, GENMASK(23, 16)); + + for (attempt = 0; attempt < 10; attempt++) { + *rtwusb->vendor_req_buf = 0; + + if (reqtype == RTW89_USB_VENQT_READ) { + pipe = usb_rcvctrlpipe(udev, 0); + } else { /* RTW89_USB_VENQT_WRITE */ + pipe = usb_sndctrlpipe(udev, 0); + + memcpy(rtwusb->vendor_req_buf, data, len); + } + + ret = usb_control_msg(udev, pipe, RTW89_USB_VENQT, reqtype, + value, index, rtwusb->vendor_req_buf, + len, 500); + + if (ret == len) { /* Success */ + atomic_set(&rtwusb->continual_io_error, 0); + + if (reqtype == RTW89_USB_VENQT_READ) + memcpy(data, rtwusb->vendor_req_buf, len); + + break; + } + + if (ret == -ESHUTDOWN || ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + else if (ret < 0) + rtw89_warn(rtwdev, + "usb %s%u 0x%x fail ret=%d value=0x%x attempt=%d\n", + reqtype == RTW89_USB_VENQT_READ ? "read" : "write", + len * 8, addr, ret, + le32_to_cpup(rtwusb->vendor_req_buf), + attempt); + else if (ret > 0 && reqtype == RTW89_USB_VENQT_READ) + memcpy(data, rtwusb->vendor_req_buf, len); + + if (atomic_inc_return(&rtwusb->continual_io_error) > 4) { + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + } + } +} + +static u32 rtw89_usb_read_cmac(struct rtw89_dev *rtwdev, u32 addr) +{ + u32 addr32, val32, shift; + __le32 data = 0; + int count; + + addr32 = addr & ~0x3; + shift = (addr & 0x3) * 8; + + for (count = 0; ; count++) { + rtw89_usb_vendorreq(rtwdev, addr32, &data, 4, + RTW89_USB_VENQT_READ); + + val32 = le32_to_cpu(data); + if (val32 != RTW89_R32_DEAD) + break; + + if (count >= MAC_REG_POOL_COUNT) { + rtw89_warn(rtwdev, "%s: addr %#x = %#x\n", + __func__, addr32, val32); + val32 = RTW89_R32_DEAD; + break; + } + + rtw89_write32(rtwdev, R_AX_CK_EN, B_AX_CMAC_ALLCKEN); + } + + return val32 >> shift; +} + +static u8 rtw89_usb_ops_read8(struct rtw89_dev *rtwdev, u32 addr) +{ + u8 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 1, RTW89_USB_VENQT_READ); + + return data; +} + +static u16 rtw89_usb_ops_read16(struct rtw89_dev *rtwdev, u32 addr) +{ + __le16 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 2, RTW89_USB_VENQT_READ); + + return le16_to_cpu(data); +} + +static u32 rtw89_usb_ops_read32(struct rtw89_dev *rtwdev, u32 addr) +{ + __le32 data = 0; + + if (ACCESS_CMAC(addr)) + return rtw89_usb_read_cmac(rtwdev, addr); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 4, + RTW89_USB_VENQT_READ); + + return le32_to_cpu(data); +} + +static void rtw89_usb_ops_write8(struct rtw89_dev *rtwdev, u32 addr, u8 val) +{ + u8 data = val; + + rtw89_usb_vendorreq(rtwdev, addr, &data, 1, RTW89_USB_VENQT_WRITE); +} + +static void rtw89_usb_ops_write16(struct rtw89_dev *rtwdev, u32 addr, u16 val) +{ + __le16 data = cpu_to_le16(val); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 2, RTW89_USB_VENQT_WRITE); +} + +static void rtw89_usb_ops_write32(struct rtw89_dev *rtwdev, u32 addr, u32 val) +{ + __le32 data = cpu_to_le32(val); + + rtw89_usb_vendorreq(rtwdev, addr, &data, 4, RTW89_USB_VENQT_WRITE); +} + +static u32 +rtw89_usb_ops_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, + u8 txch) +{ + if (txch == RTW89_TXCH_CH12) + return 1; + + return 42; /* TODO some kind of calculation? */ +} + +static u8 rtw89_usb_get_bulkout_id(u8 ch_dma) +{ + switch (ch_dma) { + case RTW89_DMA_ACH0: + return 3; + case RTW89_DMA_ACH1: + return 4; + case RTW89_DMA_ACH2: + return 5; + case RTW89_DMA_ACH3: + return 6; + default: + case RTW89_DMA_B0MG: + return 0; + case RTW89_DMA_B0HI: + return 1; + case RTW89_DMA_H2C: + return 2; + } +} + +static void rtw89_usb_write_port_complete(struct urb *urb) +{ + struct rtw89_usb_tx_ctrl_block *txcb = urb->context; + struct rtw89_dev *rtwdev = txcb->rtwdev; + struct ieee80211_tx_info *info; + struct rtw89_txwd_body *txdesc; + struct sk_buff *skb; + u32 txdesc_size; + + while (true) { + skb = skb_dequeue(&txcb->tx_ack_queue); + if (!skb) + break; + + if (txcb->txch == RTW89_TXCH_CH12) { + dev_kfree_skb_any(skb); + continue; + } + + txdesc = (struct rtw89_txwd_body *)skb->data; + + txdesc_size = rtwdev->chip->txwd_body_size; + if (le32_get_bits(txdesc->dword0, RTW89_TXWD_BODY0_WD_INFO_EN)) + txdesc_size += rtwdev->chip->txwd_info_size; + + skb_pull(skb, txdesc_size); + + info = IEEE80211_SKB_CB(skb); + ieee80211_tx_info_clear_status(info); + + if (urb->status == 0) { + if (info->flags & IEEE80211_TX_CTL_NO_ACK) + info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED; + else + info->flags |= IEEE80211_TX_STAT_ACK; + } + + ieee80211_tx_status_irqsafe(rtwdev->hw, skb); + } + + switch (urb->status) { + case 0: + case -EPIPE: + case -EPROTO: + case -EINPROGRESS: + case -ENOENT: + case -ECONNRESET: + break; + default: + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + } + + kfree(txcb); + usb_free_urb(urb); +} + +static int rtw89_usb_write_port(struct rtw89_dev *rtwdev, u8 ch_dma, + void *data, int len, void *context) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_device *usbd = rtwusb->udev; + struct urb *urb; + u8 bulkout_id = rtw89_usb_get_bulkout_id(ch_dma); + unsigned int pipe; + int ret; + + if (test_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags)) + return 0; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + return -ENOMEM; + + pipe = usb_sndbulkpipe(usbd, rtwusb->out_pipe[bulkout_id]); + + usb_fill_bulk_urb(urb, usbd, pipe, data, len, + rtw89_usb_write_port_complete, context); + urb->transfer_flags |= URB_ZERO_PACKET; + ret = usb_submit_urb(urb, GFP_ATOMIC); + + if (ret) + usb_free_urb(urb); + + if (ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + + return ret; +} + +static void rtw89_usb_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct rtw89_usb_tx_ctrl_block *txcb; + struct sk_buff *skb; + int ret; + + while (true) { + skb = skb_dequeue(&rtwusb->tx_queue[txch]); + if (!skb) + break; + + txcb = kmalloc(sizeof(*txcb), GFP_ATOMIC); + if (!txcb) { + dev_kfree_skb_any(skb); + continue; + } + + txcb->rtwdev = rtwdev; + txcb->txch = txch; + skb_queue_head_init(&txcb->tx_ack_queue); + + skb_queue_tail(&txcb->tx_ack_queue, skb); + + ret = rtw89_usb_write_port(rtwdev, txch, skb->data, skb->len, + txcb); + if (ret) { + rtw89_err(rtwdev, "write port txch %d failed: %d\n", + txch, ret); + + skb_dequeue(&txcb->tx_ack_queue); + kfree(txcb); + dev_kfree_skb_any(skb); + } + } +} + +static int rtw89_usb_tx_write_fwcmd(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = tx_req->skb; + struct sk_buff *skb512; + u32 txdesc_size = rtwdev->chip->h2c_desc_size; + void *txdesc; + + if (((desc_info->pkt_size + txdesc_size) % 512) == 0) { + rtw89_debug(rtwdev, RTW89_DBG_HCI, "avoiding multiple of 512\n"); + + skb512 = dev_alloc_skb(txdesc_size + desc_info->pkt_size + + RTW89_USB_MOD512_PADDING); + if (!skb512) { + rtw89_err(rtwdev, "%s: failed to allocate skb\n", + __func__); + + return -ENOMEM; + } + + skb_pull(skb512, txdesc_size); + skb_put_data(skb512, skb->data, skb->len); + skb_put_zero(skb512, RTW89_USB_MOD512_PADDING); + + dev_kfree_skb_any(skb); + skb = skb512; + tx_req->skb = skb512; + + desc_info->pkt_size += RTW89_USB_MOD512_PADDING; + } + + txdesc = skb_push(skb, txdesc_size); + memset(txdesc, 0, txdesc_size); + rtw89_chip_fill_txdesc_fwcmd(rtwdev, desc_info, txdesc); + + skb_queue_tail(&rtwusb->tx_queue[desc_info->ch_dma], skb); + + return 0; +} + +static int rtw89_usb_ops_tx_write(struct rtw89_dev *rtwdev, + struct rtw89_core_tx_request *tx_req) +{ + struct rtw89_tx_desc_info *desc_info = &tx_req->desc_info; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = tx_req->skb; + struct rtw89_txwd_body *txdesc; + u32 txdesc_size; + + if ((desc_info->ch_dma == RTW89_TXCH_CH12 || + tx_req->tx_type == RTW89_CORE_TX_TYPE_FWCMD) && + (desc_info->ch_dma != RTW89_TXCH_CH12 || + tx_req->tx_type != RTW89_CORE_TX_TYPE_FWCMD)) { + rtw89_err(rtwdev, "dma channel %d/TX type %d mismatch\n", + desc_info->ch_dma, tx_req->tx_type); + return -EINVAL; + } + + if (desc_info->ch_dma == RTW89_TXCH_CH12) + return rtw89_usb_tx_write_fwcmd(rtwdev, tx_req); + + txdesc_size = rtwdev->chip->txwd_body_size; + if (desc_info->en_wd_info) + txdesc_size += rtwdev->chip->txwd_info_size; + + txdesc = skb_push(skb, txdesc_size); + memset(txdesc, 0, txdesc_size); + rtw89_chip_fill_txdesc(rtwdev, desc_info, txdesc); + + le32p_replace_bits(&txdesc->dword0, 1, RTW89_TXWD_BODY0_STF_MODE); + + skb_queue_tail(&rtwusb->tx_queue[desc_info->ch_dma], skb); + + return 0; +} + +static void rtw89_usb_rx_handler(struct work_struct *work) +{ + struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_work); + struct rtw89_dev *rtwdev = rtwusb->rtwdev; + struct rtw89_rx_desc_info desc_info; + struct sk_buff *rx_skb; + struct sk_buff *skb; + u32 pkt_offset; + int limit; + + for (limit = 0; limit < 200; limit++) { + rx_skb = skb_dequeue(&rtwusb->rx_queue); + if (!rx_skb) + break; + + if (skb_queue_len(&rtwusb->rx_queue) >= RTW89_USB_MAX_RXQ_LEN) { + rtw89_warn(rtwdev, "rx_queue overflow\n"); + dev_kfree_skb_any(rx_skb); + continue; + } + + memset(&desc_info, 0, sizeof(desc_info)); + rtw89_chip_query_rxdesc(rtwdev, &desc_info, rx_skb->data, 0); + + skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size); + if (!skb) { + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "failed to allocate RX skb of size %u\n", + desc_info.pkt_size); + continue; + } + + pkt_offset = desc_info.offset + desc_info.rxd_len; + + skb_put_data(skb, rx_skb->data + pkt_offset, + desc_info.pkt_size); + + rtw89_core_rx(rtwdev, &desc_info, skb); + + if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM) + dev_kfree_skb_any(rx_skb); + else + skb_queue_tail(&rtwusb->rx_free_queue, rx_skb); + } + + if (limit == 200) { + rtw89_debug(rtwdev, RTW89_DBG_HCI, + "left %d rx skbs in the queue for later\n", + skb_queue_len(&rtwusb->rx_queue)); + queue_work(rtwusb->rxwq, &rtwusb->rx_work); + } +} + +static void rtw89_usb_rx_resubmit(struct rtw89_usb *rtwusb, + struct rtw89_usb_rx_ctrl_block *rxcb, + gfp_t gfp) +{ + struct rtw89_dev *rtwdev = rtwusb->rtwdev; + struct sk_buff *rx_skb; + int ret; + + rx_skb = skb_dequeue(&rtwusb->rx_free_queue); + if (!rx_skb) + rx_skb = alloc_skb(RTW89_USB_RECVBUF_SZ, gfp); + + if (!rx_skb) + goto try_later; + + skb_reset_tail_pointer(rx_skb); + rx_skb->len = 0; + + rxcb->rx_skb = rx_skb; + + usb_fill_bulk_urb(rxcb->rx_urb, rtwusb->udev, + usb_rcvbulkpipe(rtwusb->udev, rtwusb->in_pipe), + rxcb->rx_skb->data, RTW89_USB_RECVBUF_SZ, + rtw89_usb_read_port_complete, rxcb); + + ret = usb_submit_urb(rxcb->rx_urb, gfp); + if (ret) { + skb_queue_tail(&rtwusb->rx_free_queue, rxcb->rx_skb); + + if (ret == -ENODEV) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + else + rtw89_err(rtwdev, "Err sending rx data urb %d\n", ret); + + if (ret == -ENOMEM) + goto try_later; + } + + return; + +try_later: + rxcb->rx_skb = NULL; + queue_work(rtwusb->rxwq, &rtwusb->rx_urb_work); +} + +static void rtw89_usb_rx_resubmit_work(struct work_struct *work) +{ + struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_urb_work); + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + + if (!rxcb->rx_skb) + rtw89_usb_rx_resubmit(rtwusb, rxcb, GFP_ATOMIC); + } +} + +static void rtw89_usb_read_port_complete(struct urb *urb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb = urb->context; + struct rtw89_dev *rtwdev = rxcb->rtwdev; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *skb = rxcb->rx_skb; + + if (urb->status == 0) { + if (urb->actual_length > urb->transfer_buffer_length || + urb->actual_length < sizeof(struct rtw89_rxdesc_short)) { + rtw89_err(rtwdev, "failed to get urb length: %d\n", + urb->actual_length); + skb_queue_tail(&rtwusb->rx_free_queue, skb); + } else { + skb_put(skb, urb->actual_length); + skb_queue_tail(&rtwusb->rx_queue, skb); + queue_work(rtwusb->rxwq, &rtwusb->rx_work); + } + + rtw89_usb_rx_resubmit(rtwusb, rxcb, GFP_ATOMIC); + } else { + skb_queue_tail(&rtwusb->rx_free_queue, skb); + + if (atomic_inc_return(&rtwusb->continual_io_error) > 4) + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + + switch (urb->status) { + case -EINVAL: + case -EPIPE: + case -ENODEV: + case -ESHUTDOWN: + set_bit(RTW89_FLAG_UNPLUGGED, rtwdev->flags); + break; + case -EPROTO: + case -EILSEQ: + case -ETIME: + case -ECOMM: + case -EOVERFLOW: + case -ENOENT: + break; + case -EINPROGRESS: + rtw89_info(rtwdev, "URB is in progress\n"); + break; + default: + rtw89_err(rtwdev, "%s status %d\n", + __func__, urb->status); + break; + } + } +} + +static void rtw89_usb_cancel_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + usb_kill_urb(rxcb->rx_urb); + } +} + +static void rtw89_usb_free_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + usb_free_urb(rxcb->rx_urb); + } +} + +static int rtw89_usb_alloc_rx_bufs(struct rtw89_usb *rtwusb) +{ + struct rtw89_usb_rx_ctrl_block *rxcb; + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) { + rxcb = &rtwusb->rx_cb[i]; + + rxcb->rtwdev = rtwusb->rtwdev; + rxcb->rx_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rxcb->rx_urb) { + rtw89_usb_free_rx_bufs(rtwusb); + return -ENOMEM; + } + } + + return 0; +} + +static int rtw89_usb_init_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct sk_buff *rx_skb; + int i; + + rtwusb->rxwq = alloc_workqueue("rtw89_usb: rx wq", WQ_BH, 0); + if (!rtwusb->rxwq) { + rtw89_err(rtwdev, "failed to create RX work queue\n"); + return -ENOMEM; + } + + skb_queue_head_init(&rtwusb->rx_queue); + skb_queue_head_init(&rtwusb->rx_free_queue); + + INIT_WORK(&rtwusb->rx_work, rtw89_usb_rx_handler); + INIT_WORK(&rtwusb->rx_urb_work, rtw89_usb_rx_resubmit_work); + + for (i = 0; i < RTW89_USB_RX_SKB_NUM; i++) { + rx_skb = alloc_skb(RTW89_USB_RECVBUF_SZ, GFP_KERNEL); + if (rx_skb) + skb_queue_tail(&rtwusb->rx_free_queue, rx_skb); + } + + return 0; +} + +static void rtw89_usb_deinit_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + + skb_queue_purge(&rtwusb->rx_queue); + + destroy_workqueue(rtwusb->rxwq); + + skb_queue_purge(&rtwusb->rx_free_queue); +} + +static void rtw89_usb_start_rx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < RTW89_USB_RXCB_NUM; i++) + rtw89_usb_rx_resubmit(rtwusb, &rtwusb->rx_cb[i], GFP_KERNEL); +} + +static void rtw89_usb_init_tx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) + skb_queue_head_init(&rtwusb->tx_queue[i]); +} + +static void rtw89_usb_deinit_tx(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int i; + + for (i = 0; i < ARRAY_SIZE(rtwusb->tx_queue); i++) { + if (i == RTW89_TXCH_CH12) + skb_queue_purge(&rtwusb->tx_queue[i]); + else + ieee80211_purge_tx_queue(rtwdev->hw, &rtwusb->tx_queue[i]); + } +} + +static void rtw89_usb_ops_reset(struct rtw89_dev *rtwdev) +{ + /* TODO: anything to do here? */ +} + +static int rtw89_usb_ops_start(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static void rtw89_usb_ops_stop(struct rtw89_dev *rtwdev) +{ + /* Nothing to do. */ +} + +static void rtw89_usb_ops_pause(struct rtw89_dev *rtwdev, bool pause) +{ + /* Nothing to do? */ +} + +static void rtw89_usb_ops_switch_mode(struct rtw89_dev *rtwdev, bool low_power) +{ + /* Nothing to do. */ +} + +static int rtw89_usb_ops_deinit(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_pre_init(struct rtw89_dev *rtwdev) +{ + u32 val32; + + rtw89_write32_set(rtwdev, R_AX_USB_HOST_REQUEST_2, B_AX_R_USBIO_MODE); + + /* fix USB IO hang suggest by chihhanli@realtek.com */ + rtw89_write32_clr(rtwdev, R_AX_USB_WLAN0_1, + B_AX_USBRX_RST | B_AX_USBTX_RST); + + val32 = rtw89_read32(rtwdev, R_AX_HCI_FUNC_EN); + val32 &= ~(B_AX_HCI_RXDMA_EN | B_AX_HCI_TXDMA_EN); + rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val32); + + val32 |= B_AX_HCI_RXDMA_EN | B_AX_HCI_TXDMA_EN; + rtw89_write32(rtwdev, R_AX_HCI_FUNC_EN, val32); + /* fix USB TRX hang suggest by chihhanli@realtek.com */ + + return 0; +} + +static int rtw89_usb_ops_mac_pre_deinit(struct rtw89_dev *rtwdev) +{ + return 0; /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + enum usb_device_speed speed; + u32 ep; + + rtw89_write32_clr(rtwdev, R_AX_USB3_MAC_NPI_CONFIG_INTF_0, + B_AX_SSPHY_LFPS_FILTER); + + speed = rtwusb->udev->speed; + + if (speed == USB_SPEED_SUPER) + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB3_BULKSIZE); + else if (speed == USB_SPEED_HIGH) + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB2_BULKSIZE); + else + rtw89_write8(rtwdev, R_AX_RXDMA_SETTING, USB11_BULKSIZE); + + for (ep = 5; ep <= 12; ep++) { + if (ep == 8) + continue; + + rtw89_write8_mask(rtwdev, R_AX_USB_ENDPOINT_0, + B_AX_EP_IDX, ep); + rtw89_write8(rtwdev, R_AX_USB_ENDPOINT_2 + 1, NUMP); + } + + return 0; +} + +static void rtw89_usb_ops_recalc_int_mit(struct rtw89_dev *rtwdev) +{ + /* Nothing to do. */ +} + +static int rtw89_usb_ops_mac_lv1_rcvy(struct rtw89_dev *rtwdev, + enum rtw89_lv1_rcvy_step step) +{ + u32 reg, mask; + + switch (rtwdev->chip->chip_id) { + case RTL8851B: + case RTL8852A: + case RTL8852B: + reg = R_AX_USB_WLAN0_1; + mask = B_AX_USBRX_RST | B_AX_USBTX_RST; + break; + case RTL8852C: + reg = R_AX_USB_WLAN0_1_V1; + mask = B_AX_USBRX_RST_V1 | B_AX_USBTX_RST_V1; + break; + default: + rtw89_err(rtwdev, "%s: fix me\n", __func__); + return -EOPNOTSUPP; + } + + switch (step) { + case RTW89_LV1_RCVY_STEP_1: + rtw89_write32_set(rtwdev, reg, mask); + + msleep(30); + break; + case RTW89_LV1_RCVY_STEP_2: + rtw89_write32_clr(rtwdev, reg, mask); + break; + default: + return -EINVAL; + } + + return 0; +} + +static void rtw89_usb_ops_dump_err_status(struct rtw89_dev *rtwdev) +{ + rtw89_warn(rtwdev, "%s TODO\n", __func__); +} + +static const struct rtw89_hci_ops rtw89_usb_ops = { + .tx_write = rtw89_usb_ops_tx_write, + .tx_kick_off = rtw89_usb_ops_tx_kick_off, + .flush_queues = NULL, /* Not needed? */ + .reset = rtw89_usb_ops_reset, + .start = rtw89_usb_ops_start, + .stop = rtw89_usb_ops_stop, + .pause = rtw89_usb_ops_pause, + .switch_mode = rtw89_usb_ops_switch_mode, + .recalc_int_mit = rtw89_usb_ops_recalc_int_mit, + + .read8 = rtw89_usb_ops_read8, + .read16 = rtw89_usb_ops_read16, + .read32 = rtw89_usb_ops_read32, + .write8 = rtw89_usb_ops_write8, + .write16 = rtw89_usb_ops_write16, + .write32 = rtw89_usb_ops_write32, + + .mac_pre_init = rtw89_usb_ops_mac_pre_init, + .mac_pre_deinit = rtw89_usb_ops_mac_pre_deinit, + .mac_post_init = rtw89_usb_ops_mac_post_init, + .deinit = rtw89_usb_ops_deinit, + + .check_and_reclaim_tx_resource = rtw89_usb_ops_check_and_reclaim_tx_resource, + .mac_lv1_rcvy = rtw89_usb_ops_mac_lv1_rcvy, + .dump_err_status = rtw89_usb_ops_dump_err_status, + .napi_poll = NULL, + + .recovery_start = NULL, + .recovery_complete = NULL, + + .ctrl_txdma_ch = NULL, + .ctrl_txdma_fw_ch = NULL, + .ctrl_trxhci = NULL, + .poll_txdma_ch_idle = NULL, + + .clr_idx_all = NULL, + .clear = NULL, + .disable_intr = NULL, + .enable_intr = NULL, + .rst_bdram = NULL, +}; + +static int rtw89_usb_parse(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct usb_host_interface *host_interface = &intf->altsetting[0]; + struct usb_interface_descriptor *intf_desc = &host_interface->desc; + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + struct usb_endpoint_descriptor *endpoint; + int num_out_pipes = 0; + u8 num; + int i; + + if (intf_desc->bNumEndpoints > RTW89_MAX_ENDPOINT_NUM) { + rtw89_err(rtwdev, "found %d endpoints, expected %d max\n", + intf_desc->bNumEndpoints, RTW89_MAX_ENDPOINT_NUM); + return -EINVAL; + } + + for (i = 0; i < intf_desc->bNumEndpoints; i++) { + endpoint = &host_interface->endpoint[i].desc; + num = usb_endpoint_num(endpoint); + + if (usb_endpoint_dir_in(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + if (rtwusb->in_pipe) { + rtw89_err(rtwdev, + "found more than 1 bulk in endpoint\n"); + return -EINVAL; + } + + rtwusb->in_pipe = num; + } + + if (usb_endpoint_dir_out(endpoint) && + usb_endpoint_xfer_bulk(endpoint)) { + if (num_out_pipes >= RTW89_MAX_BULKOUT_NUM) { + rtw89_err(rtwdev, + "found more than %d bulk out endpoints\n", + RTW89_MAX_BULKOUT_NUM); + return -EINVAL; + } + + rtwusb->out_pipe[num_out_pipes++] = num; + } + } + + if (num_out_pipes < 1) { + rtw89_err(rtwdev, "no bulk out endpoints found\n"); + return -EINVAL; + } + + return 0; +} + +static int rtw89_usb_intf_init(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + int ret; + + ret = rtw89_usb_parse(rtwdev, intf); + if (ret) + return ret; + + rtwusb->vendor_req_buf = kmalloc(sizeof(*rtwusb->vendor_req_buf), + GFP_KERNEL); + if (!rtwusb->vendor_req_buf) + return -ENOMEM; + + rtwusb->udev = usb_get_dev(interface_to_usbdev(intf)); + + usb_set_intfdata(intf, rtwdev->hw); + + SET_IEEE80211_DEV(rtwdev->hw, &intf->dev); + + return 0; +} + +static void rtw89_usb_intf_deinit(struct rtw89_dev *rtwdev, + struct usb_interface *intf) +{ + struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev); + + usb_put_dev(rtwusb->udev); + kfree(rtwusb->vendor_req_buf); + usb_set_intfdata(intf, NULL); +} + +int rtw89_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + const struct rtw89_driver_info *info; + struct rtw89_dev *rtwdev; + struct rtw89_usb *rtwusb; + int ret; + + info = (const struct rtw89_driver_info *)id->driver_info; + + rtwdev = rtw89_alloc_ieee80211_hw(&intf->dev, + sizeof(struct rtw89_usb), + info->chip, info->variant); + if (!rtwdev) { + dev_err(&intf->dev, "failed to allocate hw\n"); + return -ENOMEM; + } + + rtwusb = rtw89_usb_priv(rtwdev); + rtwusb->rtwdev = rtwdev; + + rtwdev->hci.ops = &rtw89_usb_ops; + rtwdev->hci.type = RTW89_HCI_TYPE_USB; + + ret = rtw89_usb_intf_init(rtwdev, intf); + if (ret) { + rtw89_err(rtwdev, "failed to initialise intf: %d\n", ret); + goto err_free_hw; + } + + if (rtwusb->udev->speed == USB_SPEED_SUPER) + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_USB3; + else + rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_USB2; + + rtw89_usb_init_tx(rtwdev); + + ret = rtw89_usb_alloc_rx_bufs(rtwusb); + if (ret) + goto err_intf_deinit; + + ret = rtw89_usb_init_rx(rtwdev); + if (ret) + goto err_free_rx_bufs; + + ret = rtw89_core_init(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to initialise core: %d\n", ret); + goto err_deinit_rx; + } + + ret = rtw89_chip_info_setup(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to setup chip information\n"); + goto err_core_deinit; + } + + ret = rtw89_core_register(rtwdev); + if (ret) { + rtw89_err(rtwdev, "failed to register core\n"); + goto err_core_deinit; + } + + rtw89_usb_start_rx(rtwdev); + + set_bit(RTW89_FLAG_PROBE_DONE, rtwdev->flags); + + return 0; + +err_core_deinit: + rtw89_core_deinit(rtwdev); +err_deinit_rx: + rtw89_usb_deinit_rx(rtwdev); +err_free_rx_bufs: + rtw89_usb_free_rx_bufs(rtwusb); +err_intf_deinit: + rtw89_usb_intf_deinit(rtwdev, intf); +err_free_hw: + rtw89_free_ieee80211_hw(rtwdev); + + return ret; +} +EXPORT_SYMBOL(rtw89_usb_probe); + +void rtw89_usb_disconnect(struct usb_interface *intf) +{ + struct ieee80211_hw *hw = usb_get_intfdata(intf); + struct rtw89_dev *rtwdev; + struct rtw89_usb *rtwusb; + + if (!hw) + return; + + rtwdev = hw->priv; + rtwusb = rtw89_usb_priv(rtwdev); + + rtw89_usb_cancel_rx_bufs(rtwusb); + + rtw89_core_unregister(rtwdev); + rtw89_core_deinit(rtwdev); + rtw89_usb_deinit_rx(rtwdev); + rtw89_usb_free_rx_bufs(rtwusb); + rtw89_usb_deinit_tx(rtwdev); + rtw89_usb_intf_deinit(rtwdev, intf); + rtw89_free_ieee80211_hw(rtwdev); +} +EXPORT_SYMBOL(rtw89_usb_disconnect); + +MODULE_AUTHOR("Bitterblue Smith <rtl8821cerfe2@gmail.com>"); +MODULE_DESCRIPTION("Realtek USB 802.11ax wireless driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/wireless/realtek/rtw89/usb.h b/drivers/net/wireless/realtek/rtw89/usb.h new file mode 100644 index 000000000000..c1b4bfa20979 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/usb.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* Copyright(c) 2025 Realtek Corporation + */ + +#ifndef __RTW89_USB_H__ +#define __RTW89_USB_H__ + +#include "txrx.h" + +#define RTW89_USB_VENQT 0x05 +#define RTW89_USB_VENQT_READ 0xc0 +#define RTW89_USB_VENQT_WRITE 0x40 + +#define RTW89_USB_RECVBUF_SZ 20480 +#define RTW89_USB_RXCB_NUM 8 +#define RTW89_USB_RX_SKB_NUM 16 +#define RTW89_USB_MAX_RXQ_LEN 512 +#define RTW89_USB_MOD512_PADDING 4 + +#define RTW89_MAX_ENDPOINT_NUM 9 +#define RTW89_MAX_BULKOUT_NUM 7 + +struct rtw89_usb_rx_ctrl_block { + struct rtw89_dev *rtwdev; + struct urb *rx_urb; + struct sk_buff *rx_skb; +}; + +struct rtw89_usb_tx_ctrl_block { + struct rtw89_dev *rtwdev; + u8 txch; + struct sk_buff_head tx_ack_queue; +}; + +struct rtw89_usb { + struct rtw89_dev *rtwdev; + struct usb_device *udev; + + __le32 *vendor_req_buf; + + atomic_t continual_io_error; + + u8 in_pipe; + u8 out_pipe[RTW89_MAX_BULKOUT_NUM]; + + struct workqueue_struct *rxwq; + struct rtw89_usb_rx_ctrl_block rx_cb[RTW89_USB_RXCB_NUM]; + struct sk_buff_head rx_queue; + struct sk_buff_head rx_free_queue; + struct work_struct rx_work; + struct work_struct rx_urb_work; + + struct sk_buff_head tx_queue[RTW89_TXCH_NUM]; +}; + +static inline struct rtw89_usb *rtw89_usb_priv(struct rtw89_dev *rtwdev) +{ + return (struct rtw89_usb *)rtwdev->priv; +} + +int rtw89_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id); +void rtw89_usb_disconnect(struct usb_interface *intf); + +#endif diff --git a/drivers/net/wireless/realtek/rtw89/wow.c b/drivers/net/wireless/realtek/rtw89/wow.c index 34a0ab49bd7a..5bb7c1a42f1d 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.c +++ b/drivers/net/wireless/realtek/rtw89/wow.c @@ -12,7 +12,7 @@ #include "util.h" #include "wow.h" -void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) +void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) { struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; @@ -619,9 +619,12 @@ static struct ieee80211_key_conf *rtw89_wow_gtk_rekey(struct rtw89_dev *rtwdev, flex_array_size(rekey_conf, key, cipher_info->len)); if (ieee80211_vif_is_mld(wow_vif)) - key = ieee80211_gtk_rekey_add(wow_vif, rekey_conf, rtwvif_link->link_id); + key = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk, + cipher_info->len, + rtwvif_link->link_id); else - key = ieee80211_gtk_rekey_add(wow_vif, rekey_conf, -1); + key = ieee80211_gtk_rekey_add(wow_vif, keyidx, gtk, + cipher_info->len, -1); kfree(rekey_conf); if (IS_ERR(key)) { @@ -1412,6 +1415,8 @@ static void rtw89_fw_release_pno_pkt_list(struct rtw89_dev *rtwdev, static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { + static const u8 basic_rate_ie[] = {WLAN_EID_SUPP_RATES, 0x08, + 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c}; struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct cfg80211_sched_scan_request *nd_config = rtw_wow->nd_config; u8 num = nd_config->n_match_sets, i; @@ -1423,10 +1428,11 @@ static int rtw89_pno_scan_update_probe_req(struct rtw89_dev *rtwdev, skb = ieee80211_probereq_get(rtwdev->hw, rtwvif_link->mac_addr, nd_config->match_sets[i].ssid.ssid, nd_config->match_sets[i].ssid.ssid_len, - nd_config->ie_len); + nd_config->ie_len + sizeof(basic_rate_ie)); if (!skb) return -ENOMEM; + skb_put_data(skb, basic_rate_ie, sizeof(basic_rate_ie)); skb_put_data(skb, nd_config->ie, nd_config->ie_len); info = kzalloc(sizeof(*info), GFP_KERNEL); @@ -1477,7 +1483,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) opt.enable = enable; opt.repeat = RTW89_SCAN_NORMAL; opt.norm_pd = max(interval, 1) * 10; /* in unit of 100ms */ - opt.delay = max(rtw_wow->nd_config->delay, 1); + opt.delay = max(rtw_wow->nd_config->delay, 1) * 1000; if (rtwdev->chip->chip_gen == RTW89_CHIP_BE) { opt.operation = enable ? RTW89_SCAN_OP_START : RTW89_SCAN_OP_STOP; @@ -1489,7 +1495,7 @@ static int rtw89_pno_scan_offload(struct rtw89_dev *rtwdev, bool enable) opt.opch_end = RTW89_CHAN_INVALID; } - mac->scan_offload(rtwdev, &opt, rtwvif_link, true); + rtw89_mac_scan_offload(rtwdev, &opt, rtwvif_link, true); return 0; } diff --git a/drivers/net/wireless/realtek/rtw89/wow.h b/drivers/net/wireless/realtek/rtw89/wow.h index f91991e8f2e3..6606528d31c7 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -116,9 +116,21 @@ static inline bool rtw_wow_has_mgd_features(struct rtw89_dev *rtwdev) return !bitmap_empty(rtw_wow->flags, RTW89_WOW_FLAG_NUM); } +void __rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb); + +static inline +void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + + if (likely(!ieee80211_is_assoc_req(hdr->frame_control))) + return; + + __rtw89_wow_parse_akm(rtwdev, skb); +} + int rtw89_wow_suspend(struct rtw89_dev *rtwdev, struct cfg80211_wowlan *wowlan); int rtw89_wow_resume(struct rtw89_dev *rtwdev); -void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb); #else static inline void rtw89_wow_parse_akm(struct rtw89_dev *rtwdev, struct sk_buff *skb) diff --git a/drivers/net/wireless/rsi/rsi_91x_mac80211.c b/drivers/net/wireless/rsi/rsi_91x_mac80211.c index 0e115b428f96..f3a853edfc11 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mac80211.c +++ b/drivers/net/wireless/rsi/rsi_91x_mac80211.c @@ -656,11 +656,13 @@ static int rsi_config_power(struct ieee80211_hw *hw) * requests. The stack calls this function to * change hardware configuration, e.g., channel. * @hw: Pointer to the ieee80211_hw structure. + * @radio_idx: Radio index. * @changed: Changed flags set. * * Return: 0 on success, negative error code on failure. */ static int rsi_mac80211_config(struct ieee80211_hw *hw, + int radio_idx, u32 changed) { struct rsi_hw *adapter = hw->priv; @@ -1201,12 +1203,13 @@ unlock: /** * rsi_mac80211_set_rts_threshold() - This function sets rts threshold value. * @hw: Pointer to the ieee80211_hw structure. + * @radio_idx: Radio index. * @value: Rts threshold value. * * Return: 0 on success. */ static int rsi_mac80211_set_rts_threshold(struct ieee80211_hw *hw, - u32 value) + int radio_idx, u32 value) { struct rsi_hw *adapter = hw->priv; struct rsi_common *common = adapter->priv; @@ -1583,12 +1586,14 @@ static int rsi_mac80211_sta_remove(struct ieee80211_hw *hw, * rsi_mac80211_set_antenna() - This function is used to configure * tx and rx antennas. * @hw: Pointer to the ieee80211_hw structure. + * @radio_idx: Radio index * @tx_ant: Bitmap for tx antenna * @rx_ant: Bitmap for rx antenna * * Return: 0 on success, Negative error code on failure. */ static int rsi_mac80211_set_antenna(struct ieee80211_hw *hw, + int radio_idx, u32 tx_ant, u32 rx_ant) { struct rsi_hw *adapter = hw->priv; @@ -1634,12 +1639,14 @@ fail_set_antenna: * tx and rx antennas. * * @hw: Pointer to the ieee80211_hw structure. + * @radio_idx: Radio index * @tx_ant: Bitmap for tx antenna * @rx_ant: Bitmap for rx antenna * * Return: 0 on success, negative error codes on failure. */ static int rsi_mac80211_get_antenna(struct ieee80211_hw *hw, + int radio_idx, u32 *tx_ant, u32 *rx_ant) { struct rsi_hw *adapter = hw->priv; diff --git a/drivers/net/wireless/silabs/wfx/sta.c b/drivers/net/wireless/silabs/wfx/sta.c index e95b9ded17d9..d12fcc755701 100644 --- a/drivers/net/wireless/silabs/wfx/sta.c +++ b/drivers/net/wireless/silabs/wfx/sta.c @@ -220,7 +220,7 @@ int wfx_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } -int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +int wfx_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 value) { struct wfx_dev *wdev = hw->priv; struct wfx_vif *wvif = NULL; @@ -706,7 +706,7 @@ void wfx_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif wvif->channel = NULL; } -int wfx_config(struct ieee80211_hw *hw, u32 changed) +int wfx_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { return 0; } diff --git a/drivers/net/wireless/silabs/wfx/sta.h b/drivers/net/wireless/silabs/wfx/sta.h index 8702eed5267f..b4812b294f3c 100644 --- a/drivers/net/wireless/silabs/wfx/sta.h +++ b/drivers/net/wireless/silabs/wfx/sta.h @@ -21,8 +21,8 @@ struct wfx_sta_priv { /* mac80211 interface */ int wfx_start(struct ieee80211_hw *hw); void wfx_stop(struct ieee80211_hw *hw, bool suspend); -int wfx_config(struct ieee80211_hw *hw, u32 changed); -int wfx_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +int wfx_config(struct ieee80211_hw *hw, int radio_idx, u32 changed); +int wfx_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, u32 value); void wfx_set_default_unicast_key(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int idx); void wfx_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, u64 unused); diff --git a/drivers/net/wireless/st/cw1200/sta.c b/drivers/net/wireless/st/cw1200/sta.c index 5dd7f6a38900..b1dd76e8aecb 100644 --- a/drivers/net/wireless/st/cw1200/sta.c +++ b/drivers/net/wireless/st/cw1200/sta.c @@ -321,7 +321,7 @@ int cw1200_change_interface(struct ieee80211_hw *dev, return ret; } -int cw1200_config(struct ieee80211_hw *dev, u32 changed) +int cw1200_config(struct ieee80211_hw *dev, int radio_idx, u32 changed) { int ret = 0; struct cw1200_common *priv = dev->priv; @@ -857,7 +857,8 @@ void cw1200_wep_key_work(struct work_struct *work) wsm_unlock_tx(priv); } -int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +int cw1200_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { int ret = 0; __le32 val32; diff --git a/drivers/net/wireless/st/cw1200/sta.h b/drivers/net/wireless/st/cw1200/sta.h index b955b92cfd73..b4f04371668d 100644 --- a/drivers/net/wireless/st/cw1200/sta.h +++ b/drivers/net/wireless/st/cw1200/sta.h @@ -22,7 +22,7 @@ int cw1200_change_interface(struct ieee80211_hw *dev, struct ieee80211_vif *vif, enum nl80211_iftype new_type, bool p2p); -int cw1200_config(struct ieee80211_hw *dev, u32 changed); +int cw1200_config(struct ieee80211_hw *dev, int radio_idx, u32 changed); void cw1200_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -36,7 +36,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key); -int cw1200_set_rts_threshold(struct ieee80211_hw *hw, u32 value); +int cw1200_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value); void cw1200_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 queues, bool drop); diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index f78fc3880423..cb8b3102fa6c 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c @@ -832,41 +832,6 @@ int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats) return 0; } -int wl1251_acx_rate_policies(struct wl1251 *wl) -{ - struct acx_rate_policy *acx; - int ret = 0; - - wl1251_debug(DEBUG_ACX, "acx rate policies"); - - acx = kzalloc(sizeof(*acx), GFP_KERNEL); - if (!acx) - return -ENOMEM; - - /* configure one default (one-size-fits-all) rate class */ - acx->rate_class_cnt = 2; - acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; - acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; - acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; - acx->rate_class[0].aflags = 0; - - /* no-retry rate class */ - acx->rate_class[1].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; - acx->rate_class[1].short_retry_limit = 0; - acx->rate_class[1].long_retry_limit = 0; - acx->rate_class[1].aflags = 0; - - ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); - if (ret < 0) { - wl1251_warning("Setting of rate policies failed: %d", ret); - goto out; - } - -out: - kfree(acx); - return ret; -} - int wl1251_acx_mem_cfg(struct wl1251 *wl) { struct wl1251_acx_config_memory *mem_conf; diff --git a/drivers/net/wireless/ti/wl1251/acx.h b/drivers/net/wireless/ti/wl1251/acx.h index af5ec7f12231..efe1f61f89bc 100644 --- a/drivers/net/wireless/ti/wl1251/acx.h +++ b/drivers/net/wireless/ti/wl1251/acx.h @@ -1469,7 +1469,6 @@ int wl1251_acx_cts_protect(struct wl1251 *wl, enum acx_ctsprotect_type ctsprotect); int wl1251_acx_statistics(struct wl1251 *wl, struct acx_statistics *stats); int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime); -int wl1251_acx_rate_policies(struct wl1251 *wl); int wl1251_acx_mem_cfg(struct wl1251 *wl); int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c index c3be81dc7970..c33ee0d4d323 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.c +++ b/drivers/net/wireless/ti/wl1251/cmd.c @@ -59,47 +59,6 @@ out: } /** - * wl1251_cmd_test - Send test command to firmware - * - * @wl: wl struct - * @buf: buffer containing the command, with all headers, must work with dma - * @buf_len: length of the buffer - * @answer: is answer needed - */ -int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer) -{ - int ret; - - wl1251_debug(DEBUG_CMD, "cmd test"); - - ret = wl1251_cmd_send(wl, CMD_TEST, buf, buf_len); - - if (ret < 0) { - wl1251_warning("TEST command failed"); - return ret; - } - - if (answer) { - struct wl1251_command *cmd_answer; - - /* - * The test command got in, we can read the answer. - * The answer would be a wl1251_command, where the - * parameter array contains the actual answer. - */ - wl1251_mem_read(wl, wl->cmd_box_addr, buf, buf_len); - - cmd_answer = buf; - - if (cmd_answer->header.status != CMD_STATUS_SUCCESS) - wl1251_error("TEST command answer error: %d", - cmd_answer->header.status); - } - - return 0; -} - -/** * wl1251_cmd_interrogate - Read acx from firmware * * @wl: wl struct @@ -339,44 +298,6 @@ out: return ret; } -int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, - size_t len) -{ - struct cmd_read_write_memory *cmd; - int ret = 0; - - wl1251_debug(DEBUG_CMD, "cmd read memory"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - return -ENOMEM; - - WARN_ON(len > MAX_READ_SIZE); - len = min_t(size_t, len, MAX_READ_SIZE); - - cmd->addr = addr; - cmd->size = len; - - ret = wl1251_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); - if (ret < 0) { - wl1251_error("read memory command failed: %d", ret); - goto out; - } - - /* the read command got in, we can now read the answer */ - wl1251_mem_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd)); - - if (cmd->header.status != CMD_STATUS_SUCCESS) - wl1251_error("error in read command result: %d", - cmd->header.status); - - memcpy(answer, cmd->value, len); - -out: - kfree(cmd); - return ret; -} - int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len) { diff --git a/drivers/net/wireless/ti/wl1251/cmd.h b/drivers/net/wireless/ti/wl1251/cmd.h index 39159201b97e..3474b45af3b1 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.h +++ b/drivers/net/wireless/ti/wl1251/cmd.h @@ -16,7 +16,6 @@ struct acx_header; int wl1251_cmd_send(struct wl1251 *wl, u16 type, void *buf, size_t buf_len); -int wl1251_cmd_test(struct wl1251 *wl, void *buf, size_t buf_len, u8 answer); int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, @@ -26,8 +25,6 @@ int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable); int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, u16 beacon_interval, u8 dtim_interval); int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); -int wl1251_cmd_read_memory(struct wl1251 *wl, u32 addr, void *answer, - size_t len); int wl1251_cmd_template_set(struct wl1251 *wl, u16 cmd_id, void *buf, size_t buf_len); int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index bb53d681c11b..69fc51f183ad 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -589,7 +589,7 @@ static bool wl1251_can_do_pm(struct ieee80211_conf *conf, struct wl1251 *wl) return (conf->flags & IEEE80211_CONF_PS) && !wl->monitor_present; } -static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) +static int wl1251_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct wl1251 *wl = hw->priv; struct ieee80211_conf *conf = &hw->conf; @@ -1051,7 +1051,8 @@ out: return ret; } -static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int wl1251_op_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct wl1251 *wl = hw->priv; int ret; diff --git a/drivers/net/wireless/ti/wl1251/reg.h b/drivers/net/wireless/ti/wl1251/reg.h index 890176c915ab..bfe35754f33a 100644 --- a/drivers/net/wireless/ti/wl1251/reg.h +++ b/drivers/net/wireless/ti/wl1251/reg.h @@ -205,7 +205,7 @@ enum wl12xx_acx_int_reg { the burst read starts at EEPROM address 0. Otherwise, it starts at the address following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. + TheWlan hardware clears this bit automatically. Default: 0x00000000 *================================================*/ @@ -353,13 +353,13 @@ enum wl12xx_acx_int_reg { loads a single byte of data into the EE_DATA register from the EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. + The Wlan hardware clears this bit automatically. EE_DATA is valid when this bit is cleared. 0 EE_WRITE - EEPROM Write Request - Setting this bit writes a single byte of data from the EE_DATA register into the EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. + The Wlan hardware clears this bit automatically. *===============================================*/ #define EE_CTL (REGISTERS_BASE + 0x2000) #define ACX_EE_CTL_REG EE_CTL diff --git a/drivers/net/wireless/ti/wl12xx/reg.h b/drivers/net/wireless/ti/wl12xx/reg.h index 8ff018808020..601305a26141 100644 --- a/drivers/net/wireless/ti/wl12xx/reg.h +++ b/drivers/net/wireless/ti/wl12xx/reg.h @@ -168,7 +168,7 @@ the burst read starts at EEPROM address 0. Otherwise, it starts at the address following the address of the previous access. - TheWlan hardware hardware clears this bit automatically. + TheWlan hardware clears this bit automatically. Default: 0x00000000 *================================================*/ @@ -276,13 +276,13 @@ loads a single byte of data into the EE_DATA register from the EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. + The Wlan hardware clears this bit automatically. EE_DATA is valid when this bit is cleared. 0 EE_WRITE - EEPROM Write Request - Setting this bit writes a single byte of data from the EE_DATA register into the EEPROM location specified in the EE_ADDR register. - The Wlan hardware hardware clears this bit automatically. + The Wlan hardware clears this bit automatically. *===============================================*/ #define ACX_EE_CTL_REG EE_CTL #define EE_WRITE 0x00000001ul diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index cd8ad0fe59cc..fa3a3f71dd15 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -1804,32 +1804,6 @@ out: return ret; } -int wl12xx_cmd_start_fwlog(struct wl1271 *wl) -{ - struct wl12xx_cmd_start_fwlog *cmd; - int ret = 0; - - wl1271_debug(DEBUG_CMD, "cmd start firmware logger"); - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - ret = -ENOMEM; - goto out; - } - - ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0); - if (ret < 0) { - wl1271_error("failed to send start firmware logger command"); - goto out_free; - } - -out_free: - kfree(cmd); - -out: - return ret; -} - int wl12xx_cmd_stop_fwlog(struct wl1271 *wl) { struct wl12xx_cmd_stop_fwlog *cmd; diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 4c2f2608ef3b..d16afb35f9ee 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -81,7 +81,6 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl); int wlcore_cmd_generic_cfg(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 feature, u8 enable, u8 value); int wl12xx_cmd_config_fwlog(struct wl1271 *wl); -int wl12xx_cmd_start_fwlog(struct wl1271 *wl); int wl12xx_cmd_stop_fwlog(struct wl1271 *wl); int wl12xx_cmd_channel_switch(struct wl1271 *wl, struct wl12xx_vif *wlvif, diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index f93c95edd991..6116a8522d96 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -3166,7 +3166,7 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, return 0; } -static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed) +static int wl1271_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif; @@ -3895,7 +3895,8 @@ out: return 0; } -static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) +static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { struct wl1271 *wl = hw->priv; int ret = 0; @@ -3924,7 +3925,8 @@ out: return ret; } -static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int wl1271_op_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, + u32 value) { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif; diff --git a/drivers/net/wireless/ti/wlcore/sysfs.c b/drivers/net/wireless/ti/wlcore/sysfs.c index 7c57d4c8744a..65ca5dc569a0 100644 --- a/drivers/net/wireless/ti/wlcore/sysfs.c +++ b/drivers/net/wireless/ti/wlcore/sysfs.c @@ -121,7 +121,7 @@ static ssize_t wl1271_sysfs_read_fwlog(struct file *filp, struct kobject *kobj, static const struct bin_attribute fwlog_attr = { .attr = { .name = "fwlog", .mode = 0400 }, - .read_new = wl1271_sysfs_read_fwlog, + .read = wl1271_sysfs_read_fwlog, }; int wlcore_sysfs_init(struct wl1271 *wl) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.c b/drivers/net/wireless/virtual/mac80211_hwsim.c index f6add19d1da1..3789d46d5614 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -2381,7 +2381,8 @@ static const char * const hwsim_chanwidths[] = { [NL80211_CHAN_WIDTH_320] = "eht320", }; -static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) +static int mac80211_hwsim_config(struct ieee80211_hw *hw, int radio_idx, + u32 changed) { struct mac80211_hwsim_data *data = hw->priv; struct ieee80211_conf *conf = &hw->conf; @@ -3338,7 +3339,8 @@ static int mac80211_hwsim_tx_last_beacon(struct ieee80211_hw *hw) return 1; } -static int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw, u32 value) +static int mac80211_hwsim_set_rts_threshold(struct ieee80211_hw *hw, + int radio_idx, u32 value) { return -EOPNOTSUPP; } @@ -5382,7 +5384,8 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_STATIC_SMPS | NL80211_FEATURE_DYNAMIC_SMPS | - NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR | + NL80211_FEATURE_AP_SCAN; wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION); wiphy_ext_feature_set(hw->wiphy, diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.h b/drivers/net/wireless/virtual/mac80211_hwsim.h index f32fc3a492b0..fa157c883f7f 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim.h @@ -62,7 +62,7 @@ enum hwsim_tx_control_flags { * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to * kernel, uses: * %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS, - * %HWSIM_ATTR_TX_INFO, %WSIM_ATTR_TX_INFO_FLAGS, + * %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_TX_INFO_FLAGS, * %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE * @HWSIM_CMD_NEW_RADIO: create a new radio with the given parameters, * returns the radio ID (>= 0) or negative on errors, if successful @@ -126,24 +126,24 @@ enum hwsim_commands { * space * @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array * @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame - * @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_CREATE_RADIO + * @HWSIM_ATTR_CHANNELS: u32 attribute used with the %HWSIM_CMD_NEW_RADIO * command giving the number of channels supported by the new radio * @HWSIM_ATTR_RADIO_ID: u32 attribute used with %HWSIM_CMD_DESTROY_RADIO * only to destroy a radio - * @HWSIM_ATTR_REG_HINT_ALPHA2: alpha2 for regulatoro driver hint + * @HWSIM_ATTR_REG_HINT_ALPHA2: alpha2 for regulatory driver hint * (nla string, length 2) * @HWSIM_ATTR_REG_CUSTOM_REG: custom regulatory domain index (u32 attribute) * @HWSIM_ATTR_REG_STRICT_REG: request REGULATORY_STRICT_REG (flag attribute) * @HWSIM_ATTR_SUPPORT_P2P_DEVICE: support P2P Device virtual interface (flag) - * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_CREATE_RADIO + * @HWSIM_ATTR_USE_CHANCTX: used with the %HWSIM_CMD_NEW_RADIO * command to force use of channel contexts even when only a * single channel is supported - * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_CREATE_RADIO + * @HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE: used with the %HWSIM_CMD_NEW_RADIO * command to force radio removal when process that created the radio dies * @HWSIM_ATTR_RADIO_NAME: Name of radio, e.g. phy666 * @HWSIM_ATTR_NO_VIF: Do not create vif (wlanX) when creating radio. - * @HWSIM_ATTR_PAD: padding attribute for 64-bit values, ignore * @HWSIM_ATTR_FREQ: Frequency at which packet is transmitted or received. + * @HWSIM_ATTR_PAD: padding attribute for 64-bit values, ignore * @HWSIM_ATTR_TX_INFO_FLAGS: additional flags for corresponding * rates of %HWSIM_ATTR_TX_INFO * @HWSIM_ATTR_PERM_ADDR: permanent mac address of new radio @@ -151,7 +151,7 @@ enum hwsim_commands { * @HWSIM_ATTR_CIPHER_SUPPORT: u32 array of supported cipher types * @HWSIM_ATTR_MLO_SUPPORT: claim MLO support (exact parameters TBD) for * the new radio - * @HWSIM_ATTR_PMSR_SUPPORT: nested attribute used with %HWSIM_CMD_CREATE_RADIO + * @HWSIM_ATTR_PMSR_SUPPORT: nested attribute used with %HWSIM_CMD_NEW_RADIO * to provide peer measurement capabilities. (nl80211_peer_measurement_attrs) * @HWSIM_ATTR_PMSR_REQUEST: nested attribute used with %HWSIM_CMD_START_PMSR * to provide details about peer measurement request (nl80211_peer_measurement_attrs) diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c index 781510a3ec6d..0f6271d7259b 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_mac.c @@ -1137,7 +1137,7 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, zd_mac_free_cur_beacon(mac); } -static int zd_op_config(struct ieee80211_hw *hw, u32 changed) +static int zd_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) { struct zd_mac *mac = zd_hw_mac(hw); struct ieee80211_conf *conf = &hw->conf; diff --git a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c index 9ae10f65f2af..2faa0de2a36e 100644 --- a/drivers/net/wireless/zydas/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zydas/zd1211rw/zd_usb.c @@ -445,7 +445,7 @@ static void int_urb_complete(struct urb *urb) } if (urb->actual_length < sizeof(hdr)) { - dev_dbg_f(urb_dev(urb), "error: urb %p to small\n", urb); + dev_dbg_f(urb_dev(urb), "error: urb %p too small\n", urb); goto resubmit; } |