diff options
Diffstat (limited to 'drivers/net/wireless')
519 files changed, 20927 insertions, 11730 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/leds.c b/drivers/net/wireless/ath/ath10k/leds.c index 9b1d04eb4265..3a6c8111e7c6 100644 --- a/drivers/net/wireless/ath/ath10k/leds.c +++ b/drivers/net/wireless/ath/ath10k/leds.c @@ -27,7 +27,7 @@ static int ath10k_leds_set_brightness_blocking(struct led_classdev *led_cdev, goto out; ar->leds.gpio_state_pin = (brightness != LED_OFF) ^ led->active_low; - ath10k_wmi_gpio_output(ar, led->gpio, ar->leds.gpio_state_pin); + ath10k_wmi_gpio_output(ar, ar->hw_params.led_pin, ar->leds.gpio_state_pin); out: mutex_unlock(&ar->conf_mutex); @@ -64,7 +64,6 @@ int ath10k_leds_register(struct ath10k *ar) snprintf(ar->leds.label, sizeof(ar->leds.label), "ath10k-%s", wiphy_name(ar->hw->wiphy)); ar->leds.wifi_led.active_low = 1; - ar->leds.wifi_led.gpio = ar->hw_params.led_pin; ar->leds.wifi_led.name = ar->leds.label; ar->leds.wifi_led.default_state = LEDS_GPIO_DEFSTATE_KEEP; diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 07fe05384cdf..154ac7a70982 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -9,12 +9,14 @@ #include "mac.h" +#include <linux/export.h> #include <net/cfg80211.h> #include <net/mac80211.h> #include <linux/etherdevice.h> #include <linux/acpi.h> #include <linux/of.h> #include <linux/bitfield.h> +#include <linux/random.h> #include "hif.h" #include "core.h" @@ -289,8 +291,15 @@ static int ath10k_send_key(struct ath10k_vif *arvif, key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (cmd == DISABLE_KEY) { - arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_NONE]; - arg.key_data = NULL; + if (flags & WMI_KEY_GROUP) { + /* Not all hardware handles group-key deletion operation + * correctly. Replace the key with a junk value to invalidate it. + */ + get_random_bytes(key->key, key->keylen); + } else { + arg.key_cipher = ar->wmi_key_cipher[WMI_CIPHER_NONE]; + arg.key_data = NULL; + } } return ath10k_wmi_vdev_install_key(arvif->ar, &arg); @@ -3384,7 +3393,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 +4829,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 +4893,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 +4951,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 +5077,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 +5183,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 +5448,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 +6347,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 +6359,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 +8047,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 +8071,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 +8170,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..b3f6424c17d3 100644 --- a/drivers/net/wireless/ath/ath10k/snoc.c +++ b/drivers/net/wireless/ath/ath10k/snoc.c @@ -13,7 +13,7 @@ #include <linux/property.h> #include <linux/regulator/consumer.h> #include <linux/remoteproc/qcom_rproc.h> -#include <linux/of_address.h> +#include <linux/of_reserved_mem.h> #include <linux/iommu.h> #include "ce.h" @@ -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)) @@ -1559,19 +1559,11 @@ static void ath10k_modem_deinit(struct ath10k *ar) static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size) { struct device *dev = ar->dev; - struct device_node *node; struct resource r; int ret; - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (node) { - ret = of_address_to_resource(node, 0, &r); - of_node_put(node); - if (ret) { - dev_err(dev, "failed to resolve msa fixed region\n"); - return ret; - } - + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &r); + if (!ret) { ar->msa.paddr = r.start; ar->msa.mem_size = resource_size(&r); ar->msa.vaddr = devm_memremap(dev, ar->msa.paddr, 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..e595b0979a56 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> @@ -1763,33 +1764,32 @@ void ath10k_wmi_put_wmi_channel(struct ath10k *ar, struct wmi_channel *ch, int ath10k_wmi_wait_for_service_ready(struct ath10k *ar) { + unsigned long timeout = jiffies + WMI_SERVICE_READY_TIMEOUT_HZ; unsigned long time_left, i; - time_left = wait_for_completion_timeout(&ar->wmi.service_ready, - WMI_SERVICE_READY_TIMEOUT_HZ); - if (!time_left) { - /* Sometimes the PCI HIF doesn't receive interrupt - * for the service ready message even if the buffer - * was completed. PCIe sniffer shows that it's - * because the corresponding CE ring doesn't fires - * it. Workaround here by polling CE rings once. - */ - ath10k_warn(ar, "failed to receive service ready completion, polling..\n"); - + /* Sometimes the PCI HIF doesn't receive interrupt + * for the service ready message even if the buffer + * was completed. PCIe sniffer shows that it's + * because the corresponding CE ring doesn't fires + * it. Workaround here by polling CE rings. Since + * the message could arrive at any time, continue + * polling until timeout. + */ + do { for (i = 0; i < CE_COUNT; i++) ath10k_hif_send_complete_check(ar, i, 1); + /* The 100 ms granularity is a tradeoff considering scheduler + * overhead and response latency + */ time_left = wait_for_completion_timeout(&ar->wmi.service_ready, - WMI_SERVICE_READY_TIMEOUT_HZ); - if (!time_left) { - ath10k_warn(ar, "polling timed out\n"); - return -ETIMEDOUT; - } + msecs_to_jiffies(100)); + if (time_left) + return 0; + } while (time_before(jiffies, timeout)); - ath10k_warn(ar, "service ready completion received, continuing normally\n"); - } - - return 0; + ath10k_warn(ar, "failed to receive service ready completion\n"); + return -ETIMEDOUT; } int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar) @@ -1941,6 +1941,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..8dfe9b40c126 100644 --- a/drivers/net/wireless/ath/ath11k/ahb.c +++ b/drivers/net/wireless/ath/ath11k/ahb.c @@ -9,8 +9,8 @@ #include <linux/property.h> #include <linux/of_device.h> #include <linux/of.h> +#include <linux/of_reserved_mem.h> #include <linux/dma-mapping.h> -#include <linux/of_address.h> #include <linux/iommu.h> #include "ahb.h" #include "debug.h" @@ -919,16 +919,10 @@ static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab) { struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab); struct device *dev = ab->dev; - struct device_node *node; struct resource r; int ret; - node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!node) - return -ENOENT; - - ret = of_address_to_resource(node, 0, &r); - of_node_put(node); + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &r); if (ret) { dev_err(dev, "failed to resolve msa fixed region\n"); return ret; @@ -937,12 +931,7 @@ static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab) ab_ahb->fw.msa_paddr = r.start; ab_ahb->fw.msa_size = resource_size(&r); - node = of_parse_phandle(dev->of_node, "memory-region", 1); - if (!node) - return -ENOENT; - - ret = of_address_to_resource(node, 0, &r); - of_node_put(node); + ret = of_reserved_mem_region_to_resource(dev->of_node, 1, &r); if (ret) { dev_err(dev, "failed to resolve ce fixed region\n"); return ret; @@ -988,7 +977,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..a7a163621b21 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" @@ -352,7 +354,8 @@ static int ath11k_ce_rx_post_pipe(struct ath11k_ce_pipe *pipe) ret = ath11k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr); if (ret) { - ath11k_warn(ab, "failed to enqueue rx buf: %d\n", ret); + ath11k_dbg(ab, ATH11K_DBG_CE, "failed to enqueue rx buf: %d\n", + ret); dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); @@ -393,9 +396,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 +555,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..2810752260f2 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", @@ -2213,14 +2215,10 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab) mutex_unlock(&ab->core_lock); ath11k_dp_free(ab); - ath11k_hal_srng_deinit(ab); + ath11k_hal_srng_clear(ab); ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1; - ret = ath11k_hal_srng_init(ab); - if (ret) - return ret; - clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags); ret = ath11k_core_qmi_firmware_ready(ab); @@ -2581,10 +2579,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..e8780b05ce11 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" @@ -410,6 +411,8 @@ struct ath11k_vif { bool do_not_send_tmpl; struct ath11k_arp_ns_offload arp_ns_offload; struct ath11k_rekey_data rekey_data; + u32 num_stations; + bool reinstall_group_keys; struct ath11k_reg_tpc_power_info reg_tpc_info; @@ -1322,8 +1325,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..b9e976ddcbbf 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; @@ -4622,7 +4615,6 @@ static void ath11k_hal_rx_msdu_list_get(struct ath11k *ar, msdu_details[i].buf_addr_info.info0) == 0) { msdu_desc_info = &msdu_details[i - 1].rx_msdu_info; msdu_desc_info->info0 |= last; - ; break; } msdu_desc_info = &msdu_details[i].rx_msdu_info; 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..0c797b8d0a27 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); @@ -1355,6 +1386,22 @@ void ath11k_hal_srng_deinit(struct ath11k_base *ab) } EXPORT_SYMBOL(ath11k_hal_srng_deinit); +void ath11k_hal_srng_clear(struct ath11k_base *ab) +{ + /* No need to memset rdp and wrp memory since each individual + * segment would get cleared in ath11k_hal_srng_src_hw_init() + * and ath11k_hal_srng_dst_hw_init(). + */ + memset(ab->hal.srng_list, 0, + sizeof(ab->hal.srng_list)); + memset(ab->hal.shadow_reg_addr, 0, + sizeof(ab->hal.shadow_reg_addr)); + ab->hal.avail_blk_resource = 0; + ab->hal.current_blk_index = 0; + ab->hal.num_shadow_reg_configured = 0; +} +EXPORT_SYMBOL(ath11k_hal_srng_clear); + void ath11k_hal_dump_srng_stats(struct ath11k_base *ab) { struct hal_srng *srng; diff --git a/drivers/net/wireless/ath/ath11k/hal.h b/drivers/net/wireless/ath/ath11k/hal.h index 601542410c75..839095af9267 100644 --- a/drivers/net/wireless/ath/ath11k/hal.h +++ b/drivers/net/wireless/ath/ath11k/hal.h @@ -965,6 +965,7 @@ int ath11k_hal_srng_setup(struct ath11k_base *ab, enum hal_ring_type type, struct hal_srng_params *params); int ath11k_hal_srng_init(struct ath11k_base *ath11k); void ath11k_hal_srng_deinit(struct ath11k_base *ath11k); +void ath11k_hal_srng_clear(struct ath11k_base *ab); void ath11k_hal_dump_srng_stats(struct ath11k_base *ab); void ath11k_hal_srng_get_shadow_config(struct ath11k_base *ab, u32 **cfg, u32 *len); 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..106e2530b64e 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); @@ -4317,6 +4317,40 @@ static int ath11k_clear_peer_keys(struct ath11k_vif *arvif, return first_errno; } +static int ath11k_set_group_keys(struct ath11k_vif *arvif) +{ + struct ath11k *ar = arvif->ar; + struct ath11k_base *ab = ar->ab; + const u8 *addr = arvif->bssid; + int i, ret, first_errno = 0; + struct ath11k_peer *peer; + + spin_lock_bh(&ab->base_lock); + peer = ath11k_peer_find(ab, arvif->vdev_id, addr); + spin_unlock_bh(&ab->base_lock); + + if (!peer) + return -ENOENT; + + for (i = 0; i < ARRAY_SIZE(peer->keys); i++) { + struct ieee80211_key_conf *key = peer->keys[i]; + + if (!key || (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) + continue; + + ret = ath11k_install_key(arvif, key, SET_KEY, addr, + WMI_KEY_GROUP); + if (ret < 0 && first_errno == 0) + first_errno = ret; + + if (ret < 0) + ath11k_warn(ab, "failed to set group key of idx %d for vdev %d: %d\n", + i, arvif->vdev_id, ret); + } + + return first_errno; +} + static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key) @@ -4326,6 +4360,7 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); struct ath11k_peer *peer; struct ath11k_sta *arsta; + bool is_ap_with_no_sta; const u8 *peer_addr; int ret = 0; u32 flags = 0; @@ -4386,16 +4421,57 @@ static int ath11k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, else flags |= WMI_KEY_GROUP; - ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags); - if (ret) { - ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret); - goto exit; - } + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, + "%s for peer %pM on vdev %d flags 0x%X, type = %d, num_sta %d\n", + cmd == SET_KEY ? "SET_KEY" : "DEL_KEY", peer_addr, arvif->vdev_id, + flags, arvif->vdev_type, arvif->num_stations); + + /* Allow group key clearing only in AP mode when no stations are + * associated. There is a known race condition in firmware where + * group addressed packets may be dropped if the key is cleared + * and immediately set again during rekey. + * + * During GTK rekey, mac80211 issues a clear key (if the old key + * exists) followed by an install key operation for same key + * index. This causes ath11k to send two WMI commands in quick + * succession: one to clear the old key and another to install the + * new key in the same slot. + * + * Under certain conditions—especially under high load or time + * sensitive scenarios, firmware may process these commands + * asynchronously in a way that firmware assumes the key is + * cleared whereas hardware has a valid key. This inconsistency + * between hardware and firmware leads to group addressed packet + * drops after rekey. + * Only setting the same key again can restore a valid key in + * firmware and allow packets to be transmitted. + * + * There is a use case where an AP can transition from Secure mode + * to open mode without a vdev restart by just deleting all + * associated peers and clearing key, Hence allow clear key for + * that case alone. Mark arvif->reinstall_group_keys in such cases + * and reinstall the same key when the first peer is added, + * allowing firmware to recover from the race if it had occurred. + */ - ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key); - if (ret) { - ath11k_warn(ab, "failed to offload PN replay detection %d\n", ret); - goto exit; + is_ap_with_no_sta = (vif->type == NL80211_IFTYPE_AP && + !arvif->num_stations); + if ((flags & WMI_KEY_PAIRWISE) || cmd == SET_KEY || is_ap_with_no_sta) { + ret = ath11k_install_key(arvif, key, cmd, peer_addr, flags); + if (ret) { + ath11k_warn(ab, "ath11k_install_key failed (%d)\n", ret); + goto exit; + } + + ret = ath11k_dp_peer_rx_pn_replay_config(arvif, peer_addr, cmd, key); + if (ret) { + ath11k_warn(ab, "failed to offload PN replay detection %d\n", + ret); + goto exit; + } + + if ((flags & WMI_KEY_GROUP) && cmd == SET_KEY && is_ap_with_no_sta) + arvif->reinstall_group_keys = true; } spin_lock_bh(&ab->base_lock); @@ -4994,6 +5070,7 @@ static int ath11k_mac_inc_num_stations(struct ath11k_vif *arvif, return -ENOBUFS; ar->num_stations++; + arvif->num_stations++; return 0; } @@ -5009,6 +5086,7 @@ static void ath11k_mac_dec_num_stations(struct ath11k_vif *arvif, return; ar->num_stations--; + arvif->num_stations--; } static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar, @@ -5323,7 +5401,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 +5568,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 +6237,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 +6756,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 +7122,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 +7137,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 +8262,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 +8271,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 +8822,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 +8891,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, @@ -9536,6 +9618,21 @@ static int ath11k_mac_station_add(struct ath11k *ar, goto exit; } + /* Driver allows the DEL KEY followed by SET KEY sequence for + * group keys for only when there is no clients associated, if at + * all firmware has entered the race during that window, + * reinstalling the same key when the first sta connects will allow + * firmware to recover from the race. + */ + if (arvif->num_stations == 1 && arvif->reinstall_group_keys) { + ath11k_dbg(ab, ATH11K_DBG_MAC, "set group keys on 1st station add for vdev %d\n", + arvif->vdev_id); + ret = ath11k_set_group_keys(arvif); + if (ret) + goto dec_num_station; + arvif->reinstall_group_keys = false; + } + arsta->rx_stats = kzalloc(sizeof(*arsta->rx_stats), GFP_KERNEL); if (!arsta->rx_stats) { ret = -ENOMEM; @@ -10417,7 +10514,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..aea56c38bf8f 100644 --- a/drivers/net/wireless/ath/ath11k/qmi.c +++ b/drivers/net/wireless/ath/ath11k/qmi.c @@ -2,16 +2,18 @@ /* * 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" #include "debug.h" #include "hif.h" #include <linux/of.h> -#include <linux/of_address.h> +#include <linux/of_reserved_mem.h> #include <linux/ioport.h> #include <linux/firmware.h> #include <linux/of_irq.h> @@ -2038,23 +2040,14 @@ static int ath11k_qmi_alloc_target_mem_chunk(struct ath11k_base *ab) static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) { struct device *dev = ab->dev; - struct device_node *hremote_node = NULL; - struct resource res; + struct resource res = {}; u32 host_ddr_sz; int i, idx, ret; for (i = 0, idx = 0; i < ab->qmi.mem_seg_count; i++) { switch (ab->qmi.target_mem[i].type) { case HOST_DDR_REGION_TYPE: - hremote_node = of_parse_phandle(dev->of_node, "memory-region", 0); - if (!hremote_node) { - ath11k_dbg(ab, ATH11K_DBG_QMI, - "fail to get hremote_node\n"); - return -ENODEV; - } - - ret = of_address_to_resource(hremote_node, 0, &res); - of_node_put(hremote_node); + ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &res); if (ret) { ath11k_dbg(ab, ATH11K_DBG_QMI, "fail to get reg from hremote\n"); @@ -2093,7 +2086,7 @@ static int ath11k_qmi_assign_target_mem_chunk(struct ath11k_base *ab) } if (ath11k_core_coldboot_cal_support(ab)) { - if (hremote_node) { + if (resource_size(&res)) { ab->qmi.target_mem[idx].paddr = res.start + host_ddr_sz; ab->qmi.target_mem[idx].iaddr = @@ -2555,7 +2548,7 @@ static int ath11k_qmi_m3_load(struct ath11k_base *ab) GFP_KERNEL); if (!m3_mem->vaddr) { ath11k_err(ab, "failed to allocate memory for M3 with size %zu\n", - fw->size); + m3_len); ret = -ENOMEM; goto out; } 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..b30527c402f6 100644 --- a/drivers/net/wireless/ath/ath12k/ahb.c +++ b/drivers/net/wireless/ath/ath12k/ahb.c @@ -414,7 +414,7 @@ static int ath12k_ahb_power_up(struct ath12k_base *ab) goto err_fw2; } - ret = qcom_mdt_load_no_init(dev, fw2, fw2_name, pasid, mem_region, mem_phys, + ret = qcom_mdt_load_no_init(dev, fw2, fw2_name, mem_region, mem_phys, mem_size, &mem_phys); if (ret) { ath12k_err(ab, "Failed to load MDT segments: %d\n", ret); @@ -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..9a63608838ac 100644 --- a/drivers/net/wireless/ath/ath12k/ce.c +++ b/drivers/net/wireless/ath/ath12k/ce.c @@ -392,7 +392,8 @@ static int ath12k_ce_rx_post_pipe(struct ath12k_ce_pipe *pipe) ret = ath12k_ce_rx_buf_enqueue_pipe(pipe, skb, paddr); if (ret) { - ath12k_warn(ab, "failed to enqueue rx buf: %d\n", ret); + ath12k_dbg(ab, ATH12K_DBG_CE, "failed to enqueue rx buf: %d\n", + ret); dma_unmap_single(ab->dev, paddr, skb->len + skb_tailroom(skb), DMA_FROM_DEVICE); @@ -433,9 +434,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]; @@ -481,7 +479,7 @@ static void ath12k_ce_recv_process_cb(struct ath12k_ce_pipe *pipe) } while ((skb = __skb_dequeue(&list))) { - ath12k_dbg(ab, ATH12K_DBG_AHB, "rx ce pipe %d len %d\n", + ath12k_dbg(ab, ATH12K_DBG_CE, "rx ce pipe %d len %d\n", pipe->pipe_num, skb->len); pipe->recv_cb(ab, skb); } @@ -581,7 +579,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..3d1956966a48 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * 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. */ #ifndef ATH12K_CORE_H @@ -72,6 +72,9 @@ #define ATH12K_MAX_MLO_PEERS 256 #define ATH12K_MLO_PEER_ID_INVALID 0xFFFF +#define ATH12K_INVALID_RSSI_FULL -1 +#define ATH12K_INVALID_RSSI_EMPTY -128 + enum ath12k_bdf_search { ATH12K_BDF_SEARCH_DEFAULT, ATH12K_BDF_SEARCH_BUS_AND_BOARD, @@ -116,6 +119,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 +320,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 +350,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 +390,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, @@ -555,12 +563,15 @@ struct ath12k_link_sta { u32 bw_prev; u32 peer_nss; s8 rssi_beacon; + s8 chain_signal[IEEE80211_MAX_CHAINS]; /* For now the assoc link will be considered primary */ bool is_assoc_link; /* for firmware use only */ u8 link_idx; + u32 tx_retry_failed; + u32 tx_retry_count; }; struct ath12k_reoq_buf { @@ -672,6 +683,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) @@ -714,12 +734,13 @@ struct ath12k { u32 txpower_scale; u32 power_scale; u32 chan_tx_pwr; + u32 rts_threshold; u32 num_stations; u32 max_num_stations; /* 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 +799,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 +834,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 +846,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 +904,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 +1017,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 +1236,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 +1364,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 +1372,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 +1507,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/debug.h b/drivers/net/wireless/ath/ath12k/debug.h index 48916e4e1f60..bf254e43a68d 100644 --- a/drivers/net/wireless/ath/ath12k/debug.h +++ b/drivers/net/wireless/ath/ath12k/debug.h @@ -26,6 +26,7 @@ enum ath12k_debug_mask { ATH12K_DBG_DP_TX = 0x00002000, ATH12K_DBG_DP_RX = 0x00004000, ATH12K_DBG_WOW = 0x00008000, + ATH12K_DBG_CE = 0x00010000, ATH12K_DBG_ANY = 0xffffffff, }; 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..4a54b8c35311 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, @@ -1711,7 +1745,9 @@ int ath12k_dp_alloc(struct ath12k_base *ab) INIT_LIST_HEAD(&dp->reo_cmd_list); INIT_LIST_HEAD(&dp->reo_cmd_cache_flush_list); + INIT_LIST_HEAD(&dp->reo_cmd_update_rx_queue_list); spin_lock_init(&dp->reo_cmd_lock); + spin_lock_init(&dp->reo_rxq_flush_lock); dp->reo_cmd_cache_flush_count = 0; dp->idle_link_rbm = ath12k_dp_get_idle_link_rbm(ab); @@ -1747,7 +1783,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 +1796,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..4ffec6ad7d8d 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 @@ -183,15 +184,17 @@ struct ath12k_pdev_dp { #define DP_REO_REINJECT_RING_SIZE 32 #define DP_RX_RELEASE_RING_SIZE 1024 #define DP_REO_EXCEPTION_RING_SIZE 128 -#define DP_REO_CMD_RING_SIZE 128 +#define DP_REO_CMD_RING_SIZE 256 #define DP_REO_STATUS_RING_SIZE 2048 #define DP_RXDMA_BUF_RING_SIZE 4096 #define DP_RX_MAC_BUF_RING_SIZE 2048 #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 @@ -384,23 +389,27 @@ struct ath12k_dp { struct dp_srng reo_dst_ring[DP_REO_DST_RING_MAX]; struct dp_tx_ring tx_ring[DP_TCL_NUM_RING_MAX]; struct hal_wbm_idle_scatter_list scatter_list[DP_IDLE_SCATTER_BUFS_MAX]; - struct list_head reo_cmd_list; + struct list_head reo_cmd_update_rx_queue_list; struct list_head reo_cmd_cache_flush_list; u32 reo_cmd_cache_flush_count; - /* protects access to below fields, - * - reo_cmd_list + * - reo_cmd_update_rx_queue_list * - reo_cmd_cache_flush_list * - reo_cmd_cache_flush_count */ + spinlock_t reo_rxq_flush_lock; + struct list_head reo_cmd_list; + /* protects access to below fields, + * - reo_cmd_list + */ spinlock_t reo_cmd_lock; struct ath12k_hp_update_timer reo_cmd_timer; struct ath12k_hp_update_timer tx_ring_timer[DP_TCL_NUM_RING_MAX]; 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 +478,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 +713,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 +1570,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..009c49502148 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1441,6 +1441,34 @@ static void ath12k_dp_mon_parse_rx_msdu_end_err(u32 info, u32 *errmap) } static void +ath12k_parse_cmn_usr_info(const struct hal_phyrx_common_user_info *cmn_usr_info, + struct hal_rx_mon_ppdu_info *ppdu_info) +{ + struct hal_rx_radiotap_eht *eht = &ppdu_info->eht_info.eht; + u32 known, data, cp_setting, ltf_size; + + known = __le32_to_cpu(eht->known); + known |= IEEE80211_RADIOTAP_EHT_KNOWN_GI | + IEEE80211_RADIOTAP_EHT_KNOWN_EHT_LTF; + eht->known = cpu_to_le32(known); + + cp_setting = le32_get_bits(cmn_usr_info->info0, + HAL_RX_CMN_USR_INFO0_CP_SETTING); + ltf_size = le32_get_bits(cmn_usr_info->info0, + HAL_RX_CMN_USR_INFO0_LTF_SIZE); + + data = __le32_to_cpu(eht->data[0]); + data |= u32_encode_bits(cp_setting, IEEE80211_RADIOTAP_EHT_DATA0_GI); + data |= u32_encode_bits(ltf_size, IEEE80211_RADIOTAP_EHT_DATA0_LTF); + eht->data[0] = cpu_to_le32(data); + + if (!ppdu_info->ltf_size) + ppdu_info->ltf_size = ltf_size; + if (!ppdu_info->gi) + ppdu_info->gi = cp_setting; +} + +static void ath12k_dp_mon_parse_status_msdu_end(struct ath12k_mon_data *pmon, const struct hal_rx_msdu_end *msdu_end) { @@ -1627,25 +1655,22 @@ ath12k_dp_mon_rx_parse_status_tlv(struct ath12k *ar, const struct hal_rx_phyrx_rssi_legacy_info *rssi = tlv_data; info[0] = __le32_to_cpu(rssi->info0); - info[1] = __le32_to_cpu(rssi->info1); + info[2] = __le32_to_cpu(rssi->info2); /* TODO: Please note that the combined rssi will not be accurate * in MU case. Rssi in MU needs to be retrieved from * PHYRX_OTHER_RECEIVE_INFO TLV. */ ppdu_info->rssi_comb = - u32_get_bits(info[1], - HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB); + u32_get_bits(info[2], + HAL_RX_RSSI_LEGACY_INFO_INFO2_RSSI_COMB_PPDU); ppdu_info->bw = u32_get_bits(info[0], - HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW); + HAL_RX_RSSI_LEGACY_INFO_INFO0_RX_BW); break; } - case HAL_PHYRX_OTHER_RECEIVE_INFO: { - const struct hal_phyrx_common_user_info *cmn_usr_info = tlv_data; - - ppdu_info->gi = le32_get_bits(cmn_usr_info->info0, - HAL_RX_PHY_CMN_USER_INFO0_GI); + case HAL_PHYRX_COMMON_USER_INFO: { + ath12k_parse_cmn_usr_info(tlv_data, ppdu_info); break; } case HAL_RX_PPDU_START_USER_INFO: @@ -2146,11 +2171,20 @@ 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->nss = ppduinfo->nss + 1; + if (test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT, + ar->ab->wmi_ab.svc_map)) + rxs->signal = ppduinfo->rssi_comb; + else + rxs->signal = ppduinfo->rssi_comb + noise_floor; if (ppduinfo->userstats[ppduinfo->userid].ampdu_present) { rxs->flag |= RX_FLAG_AMPDU_DETAILS; @@ -2239,6 +2273,7 @@ static void ath12k_dp_mon_update_radiotap(struct ath12k *ar, static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *napi, struct sk_buff *msdu, + const struct hal_rx_mon_ppdu_info *ppduinfo, struct ieee80211_rx_status *status, u8 decap) { @@ -2252,7 +2287,6 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct struct ieee80211_sta *pubsta = NULL; struct ath12k_peer *peer; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - struct ath12k_dp_rx_info rx_info; bool is_mcbc = rxcb->is_mcbc; bool is_eapol_tkip = rxcb->is_eapol; @@ -2266,8 +2300,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct } spin_lock_bh(&ar->ab->base_lock); - rx_info.addr2_present = false; - peer = ath12k_dp_rx_h_find_peer(ar->ab, msdu, &rx_info); + peer = ath12k_peer_find_by_id(ar->ab, ppduinfo->peer_id); if (peer && peer->sta) { pubsta = peer->sta; if (pubsta->valid_links) { @@ -2360,7 +2393,7 @@ static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, decap = mon_mpdu->decap_format; ath12k_dp_mon_update_radiotap(ar, ppduinfo, mon_skb, rxs); - ath12k_dp_mon_rx_deliver_msdu(ar, napi, mon_skb, rxs, decap); + ath12k_dp_mon_rx_deliver_msdu(ar, napi, mon_skb, ppduinfo, rxs, decap); mon_skb = skb_next; } while (mon_skb); rxs->flag = 0; @@ -3610,7 +3643,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 +3660,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 +3779,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 +3797,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 +3904,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 57648febc4a4..5e5c14a70316 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -21,6 +21,9 @@ #define ATH12K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ) +static int ath12k_dp_rx_tid_delete_handler(struct ath12k_base *ab, + struct ath12k_dp_rx_tid_rxq *rx_tid); + static enum hal_encrypt_type ath12k_dp_rx_h_enctype(struct ath12k_base *ab, struct hal_rx_desc *desc) { @@ -570,7 +573,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"); @@ -581,49 +584,71 @@ static int ath12k_dp_rx_pdev_srng_alloc(struct ath12k *ar) return 0; } +static void ath12k_dp_init_rx_tid_rxq(struct ath12k_dp_rx_tid_rxq *rx_tid_rxq, + struct ath12k_dp_rx_tid *rx_tid) +{ + rx_tid_rxq->tid = rx_tid->tid; + rx_tid_rxq->active = rx_tid->active; + rx_tid_rxq->qbuf = rx_tid->qbuf; +} + +static void ath12k_dp_rx_tid_cleanup(struct ath12k_base *ab, + struct ath12k_reoq_buf *tid_qbuf) +{ + if (tid_qbuf->vaddr) { + dma_unmap_single(ab->dev, tid_qbuf->paddr_aligned, + tid_qbuf->size, DMA_BIDIRECTIONAL); + kfree(tid_qbuf->vaddr); + tid_qbuf->vaddr = NULL; + } +} + void ath12k_dp_rx_reo_cmd_list_cleanup(struct ath12k_base *ab) { struct ath12k_dp *dp = &ab->dp; struct ath12k_dp_rx_reo_cmd *cmd, *tmp; struct ath12k_dp_rx_reo_cache_flush_elem *cmd_cache, *tmp_cache; + struct dp_reo_update_rx_queue_elem *cmd_queue, *tmp_queue; - spin_lock_bh(&dp->reo_cmd_lock); - list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { - list_del(&cmd->list); - dma_unmap_single(ab->dev, cmd->data.qbuf.paddr_aligned, - cmd->data.qbuf.size, DMA_BIDIRECTIONAL); - kfree(cmd->data.qbuf.vaddr); - kfree(cmd); + spin_lock_bh(&dp->reo_rxq_flush_lock); + list_for_each_entry_safe(cmd_queue, tmp_queue, &dp->reo_cmd_update_rx_queue_list, + list) { + list_del(&cmd_queue->list); + ath12k_dp_rx_tid_cleanup(ab, &cmd_queue->rx_tid.qbuf); + kfree(cmd_queue); } - list_for_each_entry_safe(cmd_cache, tmp_cache, &dp->reo_cmd_cache_flush_list, list) { list_del(&cmd_cache->list); dp->reo_cmd_cache_flush_count--; - dma_unmap_single(ab->dev, cmd_cache->data.qbuf.paddr_aligned, - cmd_cache->data.qbuf.size, DMA_BIDIRECTIONAL); - kfree(cmd_cache->data.qbuf.vaddr); + ath12k_dp_rx_tid_cleanup(ab, &cmd_cache->data.qbuf); kfree(cmd_cache); } + spin_unlock_bh(&dp->reo_rxq_flush_lock); + + spin_lock_bh(&dp->reo_cmd_lock); + list_for_each_entry_safe(cmd, tmp, &dp->reo_cmd_list, list) { + list_del(&cmd->list); + ath12k_dp_rx_tid_cleanup(ab, &cmd->data.qbuf); + kfree(cmd); + } spin_unlock_bh(&dp->reo_cmd_lock); } static void ath12k_dp_reo_cmd_free(struct ath12k_dp *dp, void *ctx, enum hal_reo_cmd_status status) { - struct ath12k_dp_rx_tid *rx_tid = ctx; + struct ath12k_dp_rx_tid_rxq *rx_tid = ctx; if (status != HAL_REO_CMD_SUCCESS) ath12k_warn(dp->ab, "failed to flush rx tid hw desc, tid %d status %d\n", rx_tid->tid, status); - dma_unmap_single(dp->ab->dev, rx_tid->qbuf.paddr_aligned, rx_tid->qbuf.size, - DMA_BIDIRECTIONAL); - kfree(rx_tid->qbuf.vaddr); - rx_tid->qbuf.vaddr = NULL; + ath12k_dp_rx_tid_cleanup(dp->ab, &rx_tid->qbuf); } -static int ath12k_dp_reo_cmd_send(struct ath12k_base *ab, struct ath12k_dp_rx_tid *rx_tid, +static int ath12k_dp_reo_cmd_send(struct ath12k_base *ab, + struct ath12k_dp_rx_tid_rxq *rx_tid, enum hal_reo_cmd_type type, struct ath12k_hal_reo_cmd *cmd, void (*cb)(struct ath12k_dp *dp, void *ctx, @@ -668,51 +693,95 @@ static int ath12k_dp_reo_cmd_send(struct ath12k_base *ab, struct ath12k_dp_rx_ti return 0; } -static void ath12k_dp_reo_cache_flush(struct ath12k_base *ab, - struct ath12k_dp_rx_tid *rx_tid) +static int ath12k_dp_reo_cache_flush(struct ath12k_base *ab, + struct ath12k_dp_rx_tid_rxq *rx_tid) { - struct ath12k_hal_reo_cmd cmd = {0}; - unsigned long tot_desc_sz, desc_sz; + struct ath12k_hal_reo_cmd cmd = {}; int ret; - tot_desc_sz = rx_tid->qbuf.size; - desc_sz = ath12k_hal_reo_qdesc_size(0, HAL_DESC_REO_NON_QOS_TID); - - while (tot_desc_sz > desc_sz) { - tot_desc_sz -= desc_sz; - cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned + tot_desc_sz); - cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned); - ret = ath12k_dp_reo_cmd_send(ab, rx_tid, - HAL_REO_CMD_FLUSH_CACHE, &cmd, - NULL); - if (ret) - ath12k_warn(ab, - "failed to send HAL_REO_CMD_FLUSH_CACHE, tid %d (%d)\n", - rx_tid->tid, ret); - } - - memset(&cmd, 0, sizeof(cmd)); cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned); cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned); - cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; + /* HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS - all pending MPDUs + *in the bitmap will be forwarded/flushed to REO output rings + */ + cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS | + HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS; + + /* For all QoS TIDs (except NON_QOS), the driver allocates a maximum + * window size of 1024. In such cases, the driver can issue a single + * 1KB descriptor flush command instead of sending multiple 128-byte + * flush commands for each QoS TID, improving efficiency. + */ + + if (rx_tid->tid != HAL_DESC_REO_NON_QOS_TID) + cmd.flag |= HAL_REO_CMD_FLG_FLUSH_QUEUE_1K_DESC; + ret = ath12k_dp_reo_cmd_send(ab, rx_tid, HAL_REO_CMD_FLUSH_CACHE, &cmd, ath12k_dp_reo_cmd_free); - if (ret) { - ath12k_err(ab, "failed to send HAL_REO_CMD_FLUSH_CACHE cmd, tid %d (%d)\n", - rx_tid->tid, ret); - dma_unmap_single(ab->dev, rx_tid->qbuf.paddr_aligned, rx_tid->qbuf.size, - DMA_BIDIRECTIONAL); - kfree(rx_tid->qbuf.vaddr); - rx_tid->qbuf.vaddr = NULL; + return ret; +} + +static void ath12k_peer_rx_tid_qref_reset(struct ath12k_base *ab, u16 peer_id, u16 tid) +{ + struct ath12k_reo_queue_ref *qref; + struct ath12k_dp *dp = &ab->dp; + bool ml_peer = false; + + if (!ab->hw_params->reoq_lut_support) + return; + + if (peer_id & ATH12K_PEER_ML_ID_VALID) { + peer_id &= ~ATH12K_PEER_ML_ID_VALID; + ml_peer = true; } + + if (ml_peer) + qref = (struct ath12k_reo_queue_ref *)dp->ml_reoq_lut.vaddr + + (peer_id * (IEEE80211_NUM_TIDS + 1) + tid); + else + qref = (struct ath12k_reo_queue_ref *)dp->reoq_lut.vaddr + + (peer_id * (IEEE80211_NUM_TIDS + 1) + tid); + + qref->info0 = u32_encode_bits(0, BUFFER_ADDR_INFO0_ADDR); + qref->info1 = u32_encode_bits(0, BUFFER_ADDR_INFO1_ADDR) | + u32_encode_bits(tid, DP_REO_QREF_NUM); +} + +static void ath12k_dp_rx_process_reo_cmd_update_rx_queue_list(struct ath12k_dp *dp) +{ + struct ath12k_base *ab = dp->ab; + struct dp_reo_update_rx_queue_elem *elem, *tmp; + + spin_lock_bh(&dp->reo_rxq_flush_lock); + + list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_update_rx_queue_list, list) { + if (elem->rx_tid.active) + continue; + + if (ath12k_dp_rx_tid_delete_handler(ab, &elem->rx_tid)) + break; + + ath12k_peer_rx_tid_qref_reset(ab, + elem->is_ml_peer ? elem->ml_peer_id : + elem->peer_id, + elem->rx_tid.tid); + + if (ab->hw_params->reoq_lut_support) + ath12k_hal_reo_shared_qaddr_cache_clear(ab); + + list_del(&elem->list); + kfree(elem); + } + + spin_unlock_bh(&dp->reo_rxq_flush_lock); } static void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx, enum hal_reo_cmd_status status) { struct ath12k_base *ab = dp->ab; - struct ath12k_dp_rx_tid *rx_tid = ctx; + struct ath12k_dp_rx_tid_rxq *rx_tid = ctx; struct ath12k_dp_rx_reo_cache_flush_elem *elem, *tmp; if (status == HAL_REO_CMD_DRAIN) { @@ -724,6 +793,13 @@ static void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx, return; } + /* Retry the HAL_REO_CMD_UPDATE_RX_QUEUE command for entries + * in the pending queue list marked TID as inactive + */ + spin_lock_bh(&dp->ab->base_lock); + ath12k_dp_rx_process_reo_cmd_update_rx_queue_list(dp); + spin_unlock_bh(&dp->ab->base_lock); + elem = kzalloc(sizeof(*elem), GFP_ATOMIC); if (!elem) goto free_desc; @@ -731,7 +807,7 @@ static void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx, elem->ts = jiffies; memcpy(&elem->data, rx_tid, sizeof(*rx_tid)); - spin_lock_bh(&dp->reo_cmd_lock); + spin_lock_bh(&dp->reo_rxq_flush_lock); list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list); dp->reo_cmd_cache_flush_count++; @@ -741,32 +817,44 @@ static void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx, if (dp->reo_cmd_cache_flush_count > ATH12K_DP_RX_REO_DESC_FREE_THRES || time_after(jiffies, elem->ts + msecs_to_jiffies(ATH12K_DP_RX_REO_DESC_FREE_TIMEOUT_MS))) { - list_del(&elem->list); - dp->reo_cmd_cache_flush_count--; - - /* Unlock the reo_cmd_lock before using ath12k_dp_reo_cmd_send() - * within ath12k_dp_reo_cache_flush. The reo_cmd_cache_flush_list - * is used in only two contexts, one is in this function called - * from napi and the other in ath12k_dp_free during core destroy. - * Before dp_free, the irqs would be disabled and would wait to - * synchronize. Hence there wouldn’t be any race against add or - * delete to this list. Hence unlock-lock is safe here. + /* The reo_cmd_cache_flush_list is used in only two contexts, + * one is in this function called from napi and the + * other in ath12k_dp_free during core destroy. + * If cache command sent is success, delete the element in + * the cache list. ath12k_dp_rx_reo_cmd_list_cleanup + * will be called during core destroy. */ - spin_unlock_bh(&dp->reo_cmd_lock); - ath12k_dp_reo_cache_flush(ab, &elem->data); + if (ath12k_dp_reo_cache_flush(ab, &elem->data)) + break; + + list_del(&elem->list); + dp->reo_cmd_cache_flush_count--; kfree(elem); - spin_lock_bh(&dp->reo_cmd_lock); } } - spin_unlock_bh(&dp->reo_cmd_lock); + spin_unlock_bh(&dp->reo_rxq_flush_lock); return; free_desc: - dma_unmap_single(ab->dev, rx_tid->qbuf.paddr_aligned, rx_tid->qbuf.size, - DMA_BIDIRECTIONAL); - kfree(rx_tid->qbuf.vaddr); - rx_tid->qbuf.vaddr = NULL; + ath12k_dp_rx_tid_cleanup(ab, &rx_tid->qbuf); +} + +static int ath12k_dp_rx_tid_delete_handler(struct ath12k_base *ab, + struct ath12k_dp_rx_tid_rxq *rx_tid) +{ + struct ath12k_hal_reo_cmd cmd = {}; + + cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; + cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned); + cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned); + cmd.upd0 |= HAL_REO_CMD_UPD0_VLD; + /* Observed flush cache failure, to avoid that set vld bit during delete */ + cmd.upd1 |= HAL_REO_CMD_UPD1_VLD; + + return ath12k_dp_reo_cmd_send(ab, rx_tid, + HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, + ath12k_dp_rx_tid_del_func); } static void ath12k_peer_rx_tid_qref_setup(struct ath12k_base *ab, u16 peer_id, u16 tid, @@ -799,64 +887,38 @@ static void ath12k_peer_rx_tid_qref_setup(struct ath12k_base *ab, u16 peer_id, u ath12k_hal_reo_shared_qaddr_cache_clear(ab); } -static void ath12k_peer_rx_tid_qref_reset(struct ath12k_base *ab, u16 peer_id, u16 tid) +static void ath12k_dp_mark_tid_as_inactive(struct ath12k_dp *dp, int peer_id, u8 tid) { - struct ath12k_reo_queue_ref *qref; - struct ath12k_dp *dp = &ab->dp; - bool ml_peer = false; + struct dp_reo_update_rx_queue_elem *elem; + struct ath12k_dp_rx_tid_rxq *rx_tid; - if (!ab->hw_params->reoq_lut_support) - return; - - if (peer_id & ATH12K_PEER_ML_ID_VALID) { - peer_id &= ~ATH12K_PEER_ML_ID_VALID; - ml_peer = true; + spin_lock_bh(&dp->reo_rxq_flush_lock); + list_for_each_entry(elem, &dp->reo_cmd_update_rx_queue_list, list) { + if (elem->peer_id == peer_id) { + rx_tid = &elem->rx_tid; + if (rx_tid->tid == tid) { + rx_tid->active = false; + break; + } + } } - - if (ml_peer) - qref = (struct ath12k_reo_queue_ref *)dp->ml_reoq_lut.vaddr + - (peer_id * (IEEE80211_NUM_TIDS + 1) + tid); - else - qref = (struct ath12k_reo_queue_ref *)dp->reoq_lut.vaddr + - (peer_id * (IEEE80211_NUM_TIDS + 1) + tid); - - qref->info0 = u32_encode_bits(0, BUFFER_ADDR_INFO0_ADDR); - qref->info1 = u32_encode_bits(0, BUFFER_ADDR_INFO1_ADDR) | - u32_encode_bits(tid, DP_REO_QREF_NUM); + spin_unlock_bh(&dp->reo_rxq_flush_lock); } 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_dp_rx_tid *rx_tid = &peer->rx_tid[tid]; - int ret; + struct ath12k_base *ab = ar->ab; + struct ath12k_dp *dp = &ab->dp; if (!rx_tid->active) return; - cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; - cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned); - cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned); - cmd.upd0 = HAL_REO_CMD_UPD0_VLD; - ret = ath12k_dp_reo_cmd_send(ar->ab, rx_tid, - HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, - ath12k_dp_rx_tid_del_func); - if (ret) { - ath12k_err(ar->ab, "failed to send HAL_REO_CMD_UPDATE_RX_QUEUE cmd, tid %d (%d)\n", - tid, ret); - dma_unmap_single(ar->ab->dev, rx_tid->qbuf.paddr_aligned, - rx_tid->qbuf.size, DMA_BIDIRECTIONAL); - kfree(rx_tid->qbuf.vaddr); - rx_tid->qbuf.vaddr = NULL; - } - - if (peer->mlo) - ath12k_peer_rx_tid_qref_reset(ar->ab, peer->ml_id, tid); - else - ath12k_peer_rx_tid_qref_reset(ar->ab, peer->peer_id, tid); - rx_tid->active = false; + + ath12k_dp_mark_tid_as_inactive(dp, peer->peer_id, tid); + ath12k_dp_rx_process_reo_cmd_update_rx_queue_list(dp); } int ath12k_dp_rx_link_desc_return(struct ath12k_base *ab, @@ -939,11 +1001,14 @@ 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; + struct ath12k_dp_rx_tid_rxq rx_tid_rxq; - cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned); - cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned); + ath12k_dp_init_rx_tid_rxq(&rx_tid_rxq, rx_tid); + + cmd.addr_lo = lower_32_bits(rx_tid_rxq.qbuf.paddr_aligned); + cmd.addr_hi = upper_32_bits(rx_tid_rxq.qbuf.paddr_aligned); cmd.flag = HAL_REO_CMD_FLG_NEED_STATUS; cmd.upd0 = HAL_REO_CMD_UPD0_BA_WINDOW_SIZE; cmd.ba_window_size = ba_win_sz; @@ -953,12 +1018,12 @@ static int ath12k_peer_rx_tid_reo_update(struct ath12k *ar, cmd.upd2 = u32_encode_bits(ssn, HAL_REO_CMD_UPD2_SSN); } - ret = ath12k_dp_reo_cmd_send(ar->ab, rx_tid, + ret = ath12k_dp_reo_cmd_send(ar->ab, &rx_tid_rxq, HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, NULL); if (ret) { ath12k_warn(ar->ab, "failed to update rx tid queue, tid %d (%d)\n", - rx_tid->tid, ret); + rx_tid_rxq.tid, ret); return ret; } @@ -1018,6 +1083,29 @@ static int ath12k_dp_rx_assign_reoq(struct ath12k_base *ab, return 0; } +static int ath12k_dp_prepare_reo_update_elem(struct ath12k_dp *dp, + struct ath12k_peer *peer, + struct ath12k_dp_rx_tid *rx_tid) +{ + struct dp_reo_update_rx_queue_elem *elem; + + elem = kzalloc(sizeof(*elem), GFP_ATOMIC); + if (!elem) + return -ENOMEM; + + elem->peer_id = peer->peer_id; + elem->is_ml_peer = peer->mlo; + elem->ml_peer_id = peer->ml_id; + + ath12k_dp_init_rx_tid_rxq(&elem->rx_tid, rx_tid); + + spin_lock_bh(&dp->reo_rxq_flush_lock); + list_add_tail(&elem->list, &dp->reo_cmd_update_rx_queue_list); + spin_unlock_bh(&dp->reo_rxq_flush_lock); + + return 0; +} + int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id, u8 tid, u32 ba_win_sz, u16 ssn, enum hal_pn_type pn_type) @@ -1060,7 +1148,6 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_ } rx_tid = &peer->rx_tid[tid]; - paddr_aligned = rx_tid->qbuf.paddr_aligned; /* Update the tid queue if it is already setup */ if (rx_tid->active) { ret = ath12k_peer_rx_tid_reo_update(ar, peer, rx_tid, @@ -1072,6 +1159,7 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_ } if (!ab->hw_params->reoq_lut_support) { + paddr_aligned = rx_tid->qbuf.paddr_aligned; ret = ath12k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, peer_mac, paddr_aligned, tid, @@ -1098,6 +1186,20 @@ int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_ return ret; } + /* Pre-allocate the update_rxq_list for the corresponding tid + * This will be used during the tid delete. The reason we are not + * allocating during tid delete is that, if any alloc fail in update_rxq_list + * we may not be able to delete the tid vaddr/paddr and may lead to leak + */ + ret = ath12k_dp_prepare_reo_update_elem(dp, peer, rx_tid); + if (ret) { + ath12k_warn(ab, "failed to alloc update_rxq_list for rx tid %u\n", tid); + ath12k_dp_rx_tid_cleanup(ab, &rx_tid->qbuf); + spin_unlock_bh(&ab->base_lock); + return ret; + } + + paddr_aligned = rx_tid->qbuf.paddr_aligned; if (ab->hw_params->reoq_lut_support) { /* Update the REO queue LUT at the corresponding peer id * and tid with qaddr. @@ -1203,9 +1305,10 @@ 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; + struct ath12k_dp_rx_tid_rxq rx_tid_rxq; u8 tid; int ret = 0; @@ -1252,9 +1355,11 @@ int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif, rx_tid = &peer->rx_tid[tid]; if (!rx_tid->active) continue; - cmd.addr_lo = lower_32_bits(rx_tid->qbuf.paddr_aligned); - cmd.addr_hi = upper_32_bits(rx_tid->qbuf.paddr_aligned); - ret = ath12k_dp_reo_cmd_send(ab, rx_tid, + + ath12k_dp_init_rx_tid_rxq(&rx_tid_rxq, rx_tid); + cmd.addr_lo = lower_32_bits(rx_tid_rxq.qbuf.paddr_aligned); + cmd.addr_hi = upper_32_bits(rx_tid_rxq.qbuf.paddr_aligned); + ret = ath12k_dp_reo_cmd_send(ab, &rx_tid_rxq, HAL_REO_CMD_UPDATE_RX_QUEUE, &cmd, NULL); if (ret) { @@ -1417,27 +1522,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)) { @@ -1459,6 +1570,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? @@ -1499,12 +1614,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; @@ -1533,11 +1653,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)); @@ -2502,6 +2637,8 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info) channel_num = meta_data; center_freq = meta_data >> 16; + rx_status->band = NUM_NL80211_BANDS; + if (center_freq >= ATH12K_MIN_6GHZ_FREQ && center_freq <= ATH12K_MAX_6GHZ_FREQ) { rx_status->band = NL80211_BAND_6GHZ; @@ -2510,21 +2647,33 @@ void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info) rx_status->band = NL80211_BAND_2GHZ; } else if (channel_num >= 36 && channel_num <= 173) { rx_status->band = NL80211_BAND_5GHZ; - } else { + } + + if (unlikely(rx_status->band == NUM_NL80211_BANDS || + !ath12k_ar_to_hw(ar)->wiphy->bands[rx_status->band])) { + ath12k_warn(ar->ab, "sband is NULL for status band %d channel_num %d center_freq %d pdev_id %d\n", + rx_status->band, channel_num, center_freq, ar->pdev_idx); + spin_lock_bh(&ar->data_lock); channel = ar->rx_channel; if (channel) { rx_status->band = channel->band; channel_num = ieee80211_frequency_to_channel(channel->center_freq); + rx_status->freq = ieee80211_channel_to_frequency(channel_num, + rx_status->band); + } else { + ath12k_err(ar->ab, "unable to determine channel, band for rx packet"); } spin_unlock_bh(&ar->data_lock); + goto h_rate; } if (rx_status->band != NL80211_BAND_6GHZ) rx_status->freq = ieee80211_channel_to_frequency(channel_num, rx_status->band); +h_rate: ath12k_dp_rx_h_rate(ar, rx_info); } @@ -2533,31 +2682,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); @@ -2720,7 +2853,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; @@ -3015,7 +3148,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; @@ -3984,7 +4117,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; @@ -4008,6 +4141,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); } @@ -4329,7 +4464,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; @@ -4370,7 +4505,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; @@ -4527,7 +4662,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_rx.h b/drivers/net/wireless/ath/ath12k/dp_rx.h index e971a314bd2d..69d0a36a91d8 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.h +++ b/drivers/net/wireless/ath/ath12k/dp_rx.h @@ -31,15 +31,29 @@ struct ath12k_dp_rx_tid { struct ath12k_base *ab; }; +struct ath12k_dp_rx_tid_rxq { + u8 tid; + bool active; + struct ath12k_reoq_buf qbuf; +}; + struct ath12k_dp_rx_reo_cache_flush_elem { struct list_head list; - struct ath12k_dp_rx_tid data; + struct ath12k_dp_rx_tid_rxq data; unsigned long ts; }; +struct dp_reo_update_rx_queue_elem { + struct list_head list; + struct ath12k_dp_rx_tid_rxq rx_tid; + int peer_id; + bool is_ml_peer; + u16 ml_peer_id; +}; + struct ath12k_dp_rx_reo_cmd { struct list_head list; - struct ath12k_dp_rx_tid data; + struct ath12k_dp_rx_tid_rxq data; int cmd_num; void (*handler)(struct ath12k_dp *dp, void *ctx, enum hal_reo_cmd_status status); 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/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index c1750b5dc03c..efe00e167998 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.h @@ -832,6 +832,7 @@ enum hal_rx_buf_return_buf_manager { #define HAL_REO_CMD_FLG_FLUSH_ALL BIT(6) #define HAL_REO_CMD_FLG_UNBLK_RESOURCE BIT(7) #define HAL_REO_CMD_FLG_UNBLK_CACHE BIT(8) +#define HAL_REO_CMD_FLG_FLUSH_QUEUE_1K_DESC BIT(9) /* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO0_UPD_* fields */ #define HAL_REO_CMD_UPD0_RX_QUEUE_NUM BIT(8) diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 0173f731bfef..13ddac4a9412 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -1225,6 +1225,7 @@ struct hal_reo_flush_queue { #define HAL_REO_FLUSH_CACHE_INFO0_FLUSH_WO_INVALIDATE BIT(12) #define HAL_REO_FLUSH_CACHE_INFO0_BLOCK_CACHE_USAGE BIT(13) #define HAL_REO_FLUSH_CACHE_INFO0_FLUSH_ALL BIT(14) +#define HAL_REO_FLUSH_CACHE_INFO0_FLUSH_QUEUE_1K_DESC BIT(15) struct hal_reo_flush_cache { struct hal_reo_cmd_hdr cmd; diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index 48aa48c48606..669096278fdd 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.c @@ -89,6 +89,9 @@ static int ath12k_hal_reo_cmd_flush_cache(struct ath12k_hal *hal, if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_ALL) desc->info0 |= cpu_to_le32(HAL_REO_FLUSH_CACHE_INFO0_FLUSH_ALL); + if (cmd->flag & HAL_REO_CMD_FLG_FLUSH_QUEUE_1K_DESC) + desc->info0 |= cpu_to_le32(HAL_REO_FLUSH_CACHE_INFO0_FLUSH_QUEUE_1K_DESC); + return le32_get_bits(desc->cmd.info0, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER); } diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.h b/drivers/net/wireless/ath/ath12k/hal_rx.h index a3ab588aae19..d1ad7747b82c 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.h +++ b/drivers/net/wireless/ath/ath12k/hal_rx.h @@ -483,15 +483,16 @@ enum hal_rx_ul_reception_type { HAL_RECEPTION_TYPE_FRAMELESS }; -#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RECEPTION GENMASK(3, 0) -#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO0_RX_BW GENMASK(7, 5) -#define HAL_RX_PHYRX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8) +#define HAL_RX_RSSI_LEGACY_INFO_INFO0_RECEPTION GENMASK(3, 0) +#define HAL_RX_RSSI_LEGACY_INFO_INFO0_RX_BW GENMASK(7, 5) +#define HAL_RX_RSSI_LEGACY_INFO_INFO1_RSSI_COMB GENMASK(15, 8) +#define HAL_RX_RSSI_LEGACY_INFO_INFO2_RSSI_COMB_PPDU GENMASK(7, 0) struct hal_rx_phyrx_rssi_legacy_info { __le32 info0; __le32 rsvd0[39]; __le32 info1; - __le32 rsvd1; + __le32 info2; } __packed; #define HAL_RX_MPDU_START_INFO0_PPDU_ID GENMASK(31, 16) @@ -695,7 +696,8 @@ struct hal_rx_resp_req_info { #define HAL_RX_MPDU_ERR_MPDU_LEN BIT(6) #define HAL_RX_MPDU_ERR_UNENCRYPTED_FRAME BIT(7) -#define HAL_RX_PHY_CMN_USER_INFO0_GI GENMASK(17, 16) +#define HAL_RX_CMN_USR_INFO0_CP_SETTING GENMASK(17, 16) +#define HAL_RX_CMN_USR_INFO0_LTF_SIZE GENMASK(19, 18) struct hal_phyrx_common_user_info { __le32 rsvd[2]; 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..1d7b60aa5cb0 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * 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 <net/mac80211.h> @@ -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)) @@ -1772,19 +1822,13 @@ void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb) skb); } -static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac, - struct ieee80211_vif *vif) +void ath12k_mac_handle_beacon_miss(struct ath12k *ar, + struct ath12k_link_vif *arvif) { - 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_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif); - if (arvif->vdev_id != *vdev_id) - return; - - if (!arvif->is_up) + if (!(arvif->is_created && arvif->is_up)) return; ieee80211_beacon_loss(vif); @@ -1798,14 +1842,6 @@ static void ath12k_mac_handle_beacon_miss_iter(void *data, u8 *mac, ATH12K_CONNECTION_LOSS_HZ); } -void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id) -{ - ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), - IEEE80211_IFACE_ITER_NORMAL, - ath12k_mac_handle_beacon_miss_iter, - &vdev_id); -} - static void ath12k_mac_vif_sta_connection_loss_work(struct work_struct *work) { struct ath12k_link_vif *arvif = container_of(work, struct ath12k_link_vif, @@ -2053,9 +2089,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 +2209,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 +2248,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 +2307,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 +2359,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; + } - /* TODO: rxnss_override */ + 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); +} + +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 +2455,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 +2492,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 +2603,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; + he_nss = ath12k_mac_max_he_nss(he_mcs_mask); - 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; - - 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 +2640,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 +2928,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: + if (link_sta->vht_cap.cap & (IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ | + IEEE80211_VHT_CAP_EXT_NSS_BW_MASK)) 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? */ - 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 +2957,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 +2986,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 +3014,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 +3028,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 +3044,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 +3075,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 +3379,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 +3595,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 +3639,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 +3689,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 +3864,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 +3934,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) @@ -3626,12 +4064,68 @@ static int ath12k_mac_fils_discovery(struct ath12k_link_vif *arvif, return ret; } +static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + struct ieee80211_vif *vif = arvif->ahvif->vif; + struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf; + enum wmi_sta_powersave_param param; + struct ieee80211_bss_conf *info; + enum wmi_sta_ps_mode psmode; + int ret; + int timeout; + bool enable_ps; + + lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + enable_ps = arvif->ahvif->ps; + if (enable_ps) { + psmode = WMI_STA_PS_MODE_ENABLED; + param = WMI_STA_PS_PARAM_INACTIVITY_TIME; + + timeout = conf->dynamic_ps_timeout; + if (timeout == 0) { + info = ath12k_mac_get_link_bss_conf(arvif); + if (!info) { + ath12k_warn(ar->ab, "unable to access bss link conf in setup ps for vif %pM link %u\n", + vif->addr, arvif->link_id); + return; + } + + /* firmware doesn't like 0 */ + timeout = ieee80211_tu_to_usec(info->beacon_int) / 1000; + } + + ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, + timeout); + if (ret) { + ath12k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n", + arvif->vdev_id, ret); + return; + } + } else { + psmode = WMI_STA_PS_MODE_DISABLED; + } + + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d psmode %s\n", + arvif->vdev_id, psmode ? "enable" : "disable"); + + ret = ath12k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode); + if (ret) + ath12k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n", + psmode, arvif->vdev_id, ret); +} + static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 changed) { struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif); unsigned long links = ahvif->links_map; + struct ieee80211_vif_cfg *vif_cfg; struct ieee80211_bss_conf *info; struct ath12k_link_vif *arvif; struct ieee80211_sta *sta; @@ -3695,70 +4189,33 @@ static void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw, } } } -} -static void ath12k_mac_vif_setup_ps(struct ath12k_link_vif *arvif) -{ - struct ath12k *ar = arvif->ar; - struct ieee80211_vif *vif = arvif->ahvif->vif; - struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf; - enum wmi_sta_powersave_param param; - struct ieee80211_bss_conf *info; - enum wmi_sta_ps_mode psmode; - int ret; - int timeout; - bool enable_ps; - - lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy); + if (changed & BSS_CHANGED_PS) { + links = ahvif->links_map; + vif_cfg = &vif->cfg; - if (vif->type != NL80211_IFTYPE_STATION) - return; + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + arvif = wiphy_dereference(hw->wiphy, ahvif->link[link_id]); + if (!arvif || !arvif->ar) + continue; - enable_ps = arvif->ahvif->ps; - if (enable_ps) { - psmode = WMI_STA_PS_MODE_ENABLED; - param = WMI_STA_PS_PARAM_INACTIVITY_TIME; + ar = arvif->ar; - timeout = conf->dynamic_ps_timeout; - if (timeout == 0) { - info = ath12k_mac_get_link_bss_conf(arvif); - if (!info) { - ath12k_warn(ar->ab, "unable to access bss link conf in setup ps for vif %pM link %u\n", - vif->addr, arvif->link_id); - return; + if (ar->ab->hw_params->supports_sta_ps) { + ahvif->ps = vif_cfg->ps; + ath12k_mac_vif_setup_ps(arvif); } - - /* firmware doesn't like 0 */ - timeout = ieee80211_tu_to_usec(info->beacon_int) / 1000; - } - - ret = ath12k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, - timeout); - if (ret) { - ath12k_warn(ar->ab, "failed to set inactivity time for vdev %d: %i\n", - arvif->vdev_id, ret); - return; } - } else { - psmode = WMI_STA_PS_MODE_DISABLED; } - - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev %d psmode %s\n", - arvif->vdev_id, psmode ? "enable" : "disable"); - - ret = ath12k_wmi_pdev_set_ps_mode(ar, arvif->vdev_id, psmode); - if (ret) - ath12k_warn(ar->ab, "failed to set sta power save mode %d for vdev %d: %d\n", - 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; @@ -3771,7 +4228,6 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, { struct ath12k_vif *ahvif = arvif->ahvif; struct ieee80211_vif *vif = ath12k_ahvif_to_vif(ahvif); - struct ieee80211_vif_cfg *vif_cfg = &vif->cfg; struct cfg80211_chan_def def; u32 param_id, param_value; enum nl80211_band band; @@ -3850,6 +4306,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 && @@ -4045,12 +4514,6 @@ static void ath12k_mac_bss_info_changed(struct ath12k *ar, } ath12k_mac_fils_discovery(arvif, info); - - if (changed & BSS_CHANGED_PS && - ar->ab->hw_params->supports_sta_ps) { - ahvif->ps = vif_cfg->ps; - ath12k_mac_vif_setup_ps(arvif); - } } static struct ath12k_vif_cache *ath12k_ahvif_get_link_cache(struct ath12k_vif *ahvif, @@ -4149,8 +4612,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 +4738,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 +4793,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 +4969,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 +4984,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 +5021,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 +5123,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 +5133,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 +5152,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 +5172,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 +5289,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 +5304,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 +5323,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 +5342,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; - return ar->install_key_status ? -EINVAL : 0; + 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 ret; } static int ath12k_clear_peer_keys(struct ath12k_link_vif *arvif, @@ -4869,9 +5511,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 +5627,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 +5717,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 +5776,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 +5842,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 +5868,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 +5884,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 +5903,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 +5969,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 +5991,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 +6006,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 +6092,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 +6116,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 +6194,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 +6215,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 +6373,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 +6717,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 +6779,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 +7517,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 +7673,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 +7682,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 +7705,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 +7888,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 +7946,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 +7977,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 +8167,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 +8375,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 +8402,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 +8601,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 +8869,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 +8896,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 +9091,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 +9147,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 +9162,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 +9271,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 +9286,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 +9294,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 +9451,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 +9680,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; @@ -8917,6 +9846,7 @@ int ath12k_mac_vdev_create(struct ath12k *ar, struct ath12k_link_vif *arvif) param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; param_value = hw->wiphy->rts_threshold; + ar->rts_threshold = param_value; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, param_id, param_value); if (ret) { @@ -9055,7 +9985,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 +10005,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 +10056,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 +10249,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 +10289,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 +10310,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 +10645,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 +10674,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 +10747,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 +10782,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 +10862,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 +10934,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; } @@ -10300,9 +11227,11 @@ void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar, struct ieee80211_channel *chan, *temp_chan; u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction; bool is_psd_power = false, is_tpe_present = false; - s8 max_tx_power[ATH12K_NUM_PWR_LEVELS], - psd_power, tx_power, eirp_power; + s8 max_tx_power[ATH12K_NUM_PWR_LEVELS], psd_power, tx_power; + s8 eirp_power = 0; + 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 +11387,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,15 +11427,17 @@ 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; tpc_info->num_pwr_levels = max(local_psd->count, reg_psd->count); - if (tpc_info->num_pwr_levels > ATH12K_NUM_PWR_LEVELS) - tpc_info->num_pwr_levels = ATH12K_NUM_PWR_LEVELS; + tpc_info->num_pwr_levels = + min3(tpc_info->num_pwr_levels, + IEEE80211_TPE_PSD_ENTRIES_320MHZ, + ATH12K_NUM_PWR_LEVELS); for (i = 0; i < tpc_info->num_pwr_levels; i++) { tpc_info->tpe[i] = min(local_psd->power[i], @@ -10515,8 +11452,10 @@ static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar, tpc_info->num_pwr_levels = max(local_non_psd->count, reg_non_psd->count); - if (tpc_info->num_pwr_levels > ATH12K_NUM_PWR_LEVELS) - tpc_info->num_pwr_levels = ATH12K_NUM_PWR_LEVELS; + tpc_info->num_pwr_levels = + min3(tpc_info->num_pwr_levels, + IEEE80211_TPE_EIRP_ENTRIES_320MHZ, + ATH12K_NUM_PWR_LEVELS); for (i = 0; i < tpc_info->num_pwr_levels; i++) { tpc_info->tpe[i] = min(local_non_psd->power[i], @@ -10735,19 +11674,36 @@ 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 wiphy *wiphy = hw->wiphy; struct ath12k *ar; - int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret = 0, i; + int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; + int ret = 0, ret_err, i; lockdep_assert_wiphy(hw->wiphy); - /* Currently we set the rts threshold value to all the vifs across - * all radios of the single wiphy. - * TODO Once support for vif specific RTS threshold in mac80211 is - * available, ath12k can make use of it. - */ + if (radio_idx >= wiphy->n_radio || radio_idx < -1) + return -EINVAL; + + if (radio_idx != -1) { + /* Update RTS threshold in specified radio */ + ar = ath12k_ah_to_ar(ah, radio_idx); + ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); + if (ret) { + ath12k_warn(ar->ab, + "failed to set RTS config for all vdevs of pdev %d", + ar->pdev->pdev_id); + return ret; + } + + ar->rts_threshold = value; + return 0; + } + + /* Radio_index passed is -1, so set RTS threshold for all radios. */ for_each_ar(ah, ar, i) { ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); if (ret) { @@ -10756,11 +11712,31 @@ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) break; } } + if (!ret) { + /* Setting new RTS threshold for vdevs of all radios passed, so update + * the RTS threshold value for all radios + */ + for_each_ar(ah, ar, i) + ar->rts_threshold = value; + return 0; + } + + /* RTS threshold config failed, revert to the previous RTS threshold */ + for (i = i - 1; i >= 0; i--) { + ar = ath12k_ah_to_ar(ah, i); + ret_err = ath12k_set_vdev_param_to_all_vifs(ar, param_id, + ar->rts_threshold); + if (ret_err) + ath12k_warn(ar->ab, + "failed to restore RTS threshold for all vdevs of pdev %d", + ar->pdev->pdev_id); + } 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 +11856,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 +11912,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 +11976,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; - vdev_param = WMI_VDEV_PARAM_SGI; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, - vdev_param, sgi); + WMI_VDEV_PARAM_AUTORATE_MISC_CFG, + he_ar_gi_ltf); if (ret) { - ath12k_warn(ar->ab, "failed to set sgi param %d: %d\n", - sgi, 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_LDPC; + 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, ldpc); + vdev_param, nss); + if (ret) { + ath12k_warn(ar->ab, "failed to set nss param %d: %d\n", + nss, ret); + return ret; + } + + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + 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 +12180,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 +12213,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 +12254,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 +12321,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 +12346,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 +12374,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 +12430,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 +12455,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 +12501,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); } @@ -11380,6 +12636,27 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, return 0; } +static void ath12k_mac_put_chain_rssi(struct station_info *sinfo, + struct ath12k_link_sta *arsta) +{ + s8 rssi; + int i; + + for (i = 0; i < ARRAY_SIZE(sinfo->chain_signal); i++) { + sinfo->chains &= ~BIT(i); + rssi = arsta->chain_signal[i]; + + if (rssi != ATH12K_DEFAULT_NOISE_FLOOR && + rssi != ATH12K_INVALID_RSSI_FULL && + rssi != ATH12K_INVALID_RSSI_EMPTY && + rssi != 0) { + sinfo->chain_signal[i] = rssi; + sinfo->chains |= BIT(i); + sinfo->filled |= BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL); + } + } +} + static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, @@ -11388,8 +12665,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 +12714,114 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, !(ath12k_mac_get_fw_stats(ar, ¶ms))) signal = arsta->rssi_beacon; + params.stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; + if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_CHAIN_SIGNAL)) && + ahsta->ahvif->vdev_type == WMI_VDEV_TYPE_STA && + !(ath12k_mac_get_fw_stats(ar, ¶ms))) + ath12k_mac_put_chain_rssi(sinfo, arsta); + + 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 +13059,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 +13132,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 +13168,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 +13190,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 +13206,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 +13240,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 +13252,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 +13290,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 +13306,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 +13430,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 +13518,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 +13596,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 +13675,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 +13716,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 +13794,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 +13833,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 +13873,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 +13903,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 +13913,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 +13923,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 +13952,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 +13989,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 +14064,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 +14356,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..c05af40bd7a2 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, @@ -148,7 +168,8 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable); int ath12k_mac_rfkill_config(struct ath12k *ar); int ath12k_mac_wait_tx_complete(struct ath12k *ar); void ath12k_mac_handle_beacon(struct ath12k *ar, struct sk_buff *skb); -void ath12k_mac_handle_beacon_miss(struct ath12k *ar, u32 vdev_id); +void ath12k_mac_handle_beacon_miss(struct ath12k *ar, + struct ath12k_link_vif *arvif); int ath12k_mac_vif_set_keepalive(struct ath12k_link_vif *arvif, enum wmi_sta_keepalive_method method, u32 interval); 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..36325e62aa24 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.c @@ -3307,20 +3307,28 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) /* This is number of CE configs */ req->tgt_cfg_len = ab->qmi.ce_cfg.tgt_ce_len; for (pipe_num = 0; pipe_num < req->tgt_cfg_len ; pipe_num++) { - req->tgt_cfg[pipe_num].pipe_num = ce_cfg[pipe_num].pipenum; - req->tgt_cfg[pipe_num].pipe_dir = ce_cfg[pipe_num].pipedir; - req->tgt_cfg[pipe_num].nentries = ce_cfg[pipe_num].nentries; - req->tgt_cfg[pipe_num].nbytes_max = ce_cfg[pipe_num].nbytes_max; - req->tgt_cfg[pipe_num].flags = ce_cfg[pipe_num].flags; + req->tgt_cfg[pipe_num].pipe_num = + __le32_to_cpu(ce_cfg[pipe_num].pipenum); + req->tgt_cfg[pipe_num].pipe_dir = + __le32_to_cpu(ce_cfg[pipe_num].pipedir); + req->tgt_cfg[pipe_num].nentries = + __le32_to_cpu(ce_cfg[pipe_num].nentries); + req->tgt_cfg[pipe_num].nbytes_max = + __le32_to_cpu(ce_cfg[pipe_num].nbytes_max); + req->tgt_cfg[pipe_num].flags = + __le32_to_cpu(ce_cfg[pipe_num].flags); } req->svc_cfg_valid = 1; /* This is number of Service/CE configs */ req->svc_cfg_len = ab->qmi.ce_cfg.svc_to_ce_map_len; for (pipe_num = 0; pipe_num < req->svc_cfg_len; pipe_num++) { - req->svc_cfg[pipe_num].service_id = svc_cfg[pipe_num].service_id; - req->svc_cfg[pipe_num].pipe_dir = svc_cfg[pipe_num].pipedir; - req->svc_cfg[pipe_num].pipe_num = svc_cfg[pipe_num].pipenum; + req->svc_cfg[pipe_num].service_id = + __le32_to_cpu(svc_cfg[pipe_num].service_id); + req->svc_cfg[pipe_num].pipe_dir = + __le32_to_cpu(svc_cfg[pipe_num].pipedir); + req->svc_cfg[pipe_num].pipe_num = + __le32_to_cpu(svc_cfg[pipe_num].pipenum); } /* set shadow v3 configuration */ @@ -3856,7 +3864,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..4767d9a2e309 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 @@ -393,17 +392,17 @@ enum qmi_wlanfw_pipedir_enum_v01 { }; struct qmi_wlanfw_ce_tgt_pipe_cfg_s_v01 { - __le32 pipe_num; - __le32 pipe_dir; - __le32 nentries; - __le32 nbytes_max; - __le32 flags; + u32 pipe_num; + u32 pipe_dir; + u32 nentries; + u32 nbytes_max; + u32 flags; }; struct qmi_wlanfw_ce_svc_pipe_cfg_s_v01 { - __le32 service_id; - __le32 pipe_dir; - __le32 pipe_num; + u32 service_id; + u32 pipe_dir; + u32 pipe_num; }; struct qmi_wlanfw_shadow_reg_cfg_s_v01 { @@ -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..ff6b3d4ea820 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.c @@ -30,6 +30,9 @@ struct ath12k_wmi_svc_ready_parse { struct wmi_tlv_fw_stats_parse { const struct wmi_stats_event *ev; struct ath12k_fw_stats *stats; + const struct wmi_per_chain_rssi_stat_params *rssi; + int rssi_num; + bool chain_rssi_done; }; struct ath12k_wmi_dma_ring_caps_parse { @@ -185,6 +188,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_p2p_noa_event) }, [WMI_TAG_11D_NEW_COUNTRY_EVENT] = { .min_len = sizeof(struct wmi_11d_new_cc_event) }, + [WMI_TAG_PER_CHAIN_RSSI_STATS] = { + .min_len = sizeof(struct wmi_per_chain_rssi_stat_params) }, }; __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -201,10 +206,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 +541,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 +790,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) @@ -814,10 +848,32 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, cmd->tx_params_valid = 0; frame_tlv = (struct wmi_tlv *)(skb->data + sizeof(*cmd)); - frame_tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, buf_len); + frame_tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, buf_len_aligned); 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 +1115,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 +2068,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 +2210,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) @@ -2370,6 +2428,7 @@ int ath12k_wmi_send_peer_assoc_cmd(struct ath12k *ar, eml_cap = arg->ml.eml_cap; if (u16_get_bits(eml_cap, IEEE80211_EML_CAP_EMLSR_SUPP)) { + ml_params->flags |= cpu_to_le32(ATH12K_WMI_FLAG_MLO_EMLSR_SUPPORT); /* Padding delay */ eml_pad_delay = ieee80211_emlsr_pad_delay_in_us(eml_cap); ml_params->emlsr_padding_delay_us = cpu_to_le32(eml_pad_delay); @@ -3880,7 +3939,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 +6176,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 +6200,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 +6253,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; @@ -6397,6 +6467,8 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf } arg->mac_addr = ev->peer_macaddr.addr; + arg->reason = le32_to_cpu(ev->reason); + arg->rssi = le32_to_cpu(ev->rssi); kfree(tb); return 0; @@ -6445,9 +6517,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 +6756,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 +6812,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 +6826,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 +7047,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 +7115,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 +7166,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 +7183,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 +7224,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"); @@ -7207,8 +7305,10 @@ static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb) static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_peer_sta_kickout_arg arg = {}; + struct ath12k_link_vif *arvif; struct ieee80211_sta *sta; struct ath12k_peer *peer; + unsigned int link_id; struct ath12k *ar; if (ath12k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) { @@ -7228,25 +7328,49 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff goto exit; } - ar = ath12k_mac_get_ar_by_vdev_id(ab, peer->vdev_id); - if (!ar) { + arvif = ath12k_mac_get_arvif_by_vdev_id(ab, peer->vdev_id); + if (!arvif) { ath12k_warn(ab, "invalid vdev id in peer sta kickout ev %d", peer->vdev_id); goto exit; } - sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar), - arg.mac_addr, NULL); + ar = arvif->ar; + + if (peer->mlo) { + sta = ieee80211_find_sta_by_link_addrs(ath12k_ar_to_hw(ar), + arg.mac_addr, + NULL, &link_id); + if (peer->link_id != link_id) { + ath12k_warn(ab, + "Spurious quick kickout for MLO STA %pM with invalid link_id, peer: %d, sta: %d\n", + arg.mac_addr, peer->link_id, link_id); + goto exit; + } + } else { + sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar), + arg.mac_addr, NULL); + } if (!sta) { - ath12k_warn(ab, "Spurious quick kickout for STA %pM\n", - arg.mac_addr); + ath12k_warn(ab, "Spurious quick kickout for %sSTA %pM\n", + peer->mlo ? "MLO " : "", arg.mac_addr); goto exit; } - ath12k_dbg(ab, ATH12K_DBG_WMI, "peer sta kickout event %pM", - arg.mac_addr); + ath12k_dbg(ab, ATH12K_DBG_WMI, + "peer sta kickout event %pM reason: %d rssi: %d\n", + arg.mac_addr, arg.reason, arg.rssi); - ieee80211_report_low_ack(sta, 10); + switch (arg.reason) { + case WMI_PEER_STA_KICKOUT_REASON_INACTIVITY: + if (arvif->ahvif->vif->type == NL80211_IFTYPE_STATION) { + ath12k_mac_handle_beacon_miss(ar, arvif); + break; + } + fallthrough; + default: + ieee80211_report_low_ack(sta, 10); + } exit: spin_unlock_bh(&ab->base_lock); @@ -7255,6 +7379,7 @@ exit: static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb) { + struct ath12k_link_vif *arvif; struct wmi_roam_event roam_ev = {}; struct ath12k *ar; u32 vdev_id; @@ -7273,21 +7398,22 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb) "wmi roam event vdev %u reason %d rssi %d\n", vdev_id, roam_reason, roam_ev.rssi); - rcu_read_lock(); - ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); - if (!ar) { + guard(rcu)(); + arvif = ath12k_mac_get_arvif_by_vdev_id(ab, vdev_id); + if (!arvif) { ath12k_warn(ab, "invalid vdev id in roam ev %d", vdev_id); - rcu_read_unlock(); return; } + ar = arvif->ar; + if (roam_reason >= WMI_ROAM_REASON_MAX) ath12k_warn(ab, "ignoring unknown roam event reason %d on vdev %i\n", roam_reason, vdev_id); switch (roam_reason) { case WMI_ROAM_REASON_BEACON_MISS: - ath12k_mac_handle_beacon_miss(ar, vdev_id); + ath12k_mac_handle_beacon_miss(ar, arvif); break; case WMI_ROAM_REASON_BETTER_AP: case WMI_ROAM_REASON_LOW_RSSI: @@ -7297,13 +7423,11 @@ static void ath12k_roam_event(struct ath12k_base *ab, struct sk_buff *skb) roam_reason, vdev_id); break; } - - rcu_read_unlock(); } 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 +7575,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 +7615,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 +7648,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 +7680,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) { @@ -8127,6 +8252,77 @@ exit: return ret; } +static int ath12k_wmi_tlv_rssi_chain_parse(struct ath12k_base *ab, + u16 tag, u16 len, + const void *ptr, void *data) +{ + const struct wmi_rssi_stat_params *stats_rssi = ptr; + struct wmi_tlv_fw_stats_parse *parse = data; + const struct wmi_stats_event *ev = parse->ev; + struct ath12k_fw_stats *stats = parse->stats; + struct ath12k_link_vif *arvif; + struct ath12k_link_sta *arsta; + struct ieee80211_sta *sta; + struct ath12k_sta *ahsta; + struct ath12k *ar; + int vdev_id; + int j; + + if (!ev) { + ath12k_warn(ab, "failed to fetch update stats ev"); + return -EPROTO; + } + + if (tag != WMI_TAG_RSSI_STATS) + return -EPROTO; + + if (!stats) + return -EINVAL; + + stats->pdev_id = le32_to_cpu(ev->pdev_id); + vdev_id = le32_to_cpu(stats_rssi->vdev_id); + guard(rcu)(); + ar = ath12k_mac_get_ar_by_pdev_id(ab, stats->pdev_id); + if (!ar) { + ath12k_warn(ab, "invalid pdev id %d in rssi chain parse\n", + stats->pdev_id); + return -EPROTO; + } + + arvif = ath12k_mac_get_arvif(ar, vdev_id); + if (!arvif) { + ath12k_warn(ab, "not found vif for vdev id %d\n", vdev_id); + return -EPROTO; + } + + ath12k_dbg(ab, ATH12K_DBG_WMI, + "stats bssid %pM vif %p\n", + arvif->bssid, arvif->ahvif->vif); + + sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar), + arvif->bssid, + NULL); + if (!sta) { + ath12k_dbg(ab, ATH12K_DBG_WMI, + "not found station of bssid %pM for rssi chain\n", + arvif->bssid); + return -EPROTO; + } + + ahsta = ath12k_sta_to_ahsta(sta); + arsta = &ahsta->deflink; + + BUILD_BUG_ON(ARRAY_SIZE(arsta->chain_signal) > + ARRAY_SIZE(stats_rssi->rssi_avg_beacon)); + + for (j = 0; j < ARRAY_SIZE(arsta->chain_signal); j++) + arsta->chain_signal[j] = le32_to_cpu(stats_rssi->rssi_avg_beacon[j]); + + stats->stats_id = WMI_REQUEST_RSSI_PER_CHAIN_STAT; + + return 0; +} + static int ath12k_wmi_tlv_fw_stats_parse(struct ath12k_base *ab, u16 tag, u16 len, const void *ptr, void *data) @@ -8141,6 +8337,22 @@ static int ath12k_wmi_tlv_fw_stats_parse(struct ath12k_base *ab, case WMI_TAG_ARRAY_BYTE: ret = ath12k_wmi_tlv_fw_stats_data_parse(ab, parse, ptr, len); break; + case WMI_TAG_PER_CHAIN_RSSI_STATS: + parse->rssi = ptr; + if (le32_to_cpu(parse->ev->stats_id) & WMI_REQUEST_RSSI_PER_CHAIN_STAT) + parse->rssi_num = le32_to_cpu(parse->rssi->num_per_chain_rssi); + break; + case WMI_TAG_ARRAY_STRUCT: + if (parse->rssi_num && !parse->chain_rssi_done) { + ret = ath12k_wmi_tlv_iter(ab, ptr, len, + ath12k_wmi_tlv_rssi_chain_parse, + parse); + if (ret) + return ret; + + parse->chain_rssi_done = true; + } + break; default: break; } @@ -8254,6 +8466,12 @@ static void ath12k_update_stats_event(struct ath12k_base *ab, struct sk_buff *sk goto complete; } + /* Handle WMI_REQUEST_RSSI_PER_CHAIN_STAT status update */ + if (stats.stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) { + complete(&ar->fw_stats_done); + goto complete; + } + /* Handle WMI_REQUEST_VDEV_STAT and WMI_REQUEST_BCN_STAT updates. */ ath12k_wmi_fw_stats_process(ar, &stats); @@ -8501,7 +8719,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 +9517,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 +9871,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..a8c3190e8ad9 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 { @@ -4476,12 +4548,27 @@ struct wmi_scan_event { __le32 tsf_timestamp; } __packed; +enum wmi_peer_sta_kickout_reason { + WMI_PEER_STA_KICKOUT_REASON_UNSPECIFIED = 0, + WMI_PEER_STA_KICKOUT_REASON_XRETRY = 1, + WMI_PEER_STA_KICKOUT_REASON_INACTIVITY = 2, + WMI_PEER_STA_KICKOUT_REASON_IBSS_DISCONNECT = 3, + WMI_PEER_STA_KICKOUT_REASON_TDLS_DISCONNECT = 4, + WMI_PEER_STA_KICKOUT_REASON_SA_QUERY_TIMEOUT = 5, + WMI_PEER_STA_KICKOUT_REASON_ROAMING_EVENT = 6, + WMI_PEER_STA_KICKOUT_REASON_PMF_ERROR = 7, +}; + struct wmi_peer_sta_kickout_arg { const u8 *mac_addr; + enum wmi_peer_sta_kickout_reason reason; + u32 rssi; }; struct wmi_peer_sta_kickout_event { struct ath12k_wmi_mac_addr_params peer_macaddr; + __le32 reason; + __le32 rssi; } __packed; #define WMI_ROAM_REASON_MASK GENMASK(3, 0) @@ -4670,7 +4757,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 { @@ -5803,9 +5890,10 @@ struct wmi_stats_event { } __packed; enum wmi_stats_id { - WMI_REQUEST_PDEV_STAT = BIT(2), - WMI_REQUEST_VDEV_STAT = BIT(3), - WMI_REQUEST_BCN_STAT = BIT(11), + WMI_REQUEST_PDEV_STAT = BIT(2), + WMI_REQUEST_VDEV_STAT = BIT(3), + WMI_REQUEST_RSSI_PER_CHAIN_STAT = BIT(8), + WMI_REQUEST_BCN_STAT = BIT(11), }; struct wmi_request_stats_cmd { @@ -5816,6 +5904,17 @@ struct wmi_request_stats_cmd { __le32 pdev_id; } __packed; +struct wmi_rssi_stat_params { + __le32 vdev_id; + __le32 rssi_avg_beacon[WMI_MAX_CHAINS]; + __le32 rssi_avg_data[WMI_MAX_CHAINS]; + struct ath12k_wmi_mac_addr_params peer_macaddr; +} __packed; + +struct wmi_per_chain_rssi_stat_params { + __le32 num_per_chain_rssi; +} __packed; + #define WLAN_MAX_AC 4 #define MAX_TX_RATE_VALUES 10 @@ -6174,6 +6273,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 +6317,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/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 908c4c8b7f82..6833430130f4 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -555,7 +555,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) /* Check whenever the PHY can be turned off again. */ /* 1. What about buffered unicast traffic for our AID? */ - cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid); + cam = ieee80211_check_tim(tim_ie, tim_len, ar->common.curaid, false); /* 2. Maybe the AP wants to send multicast/broadcast data? */ cam |= !!(tim_ie->bitmap_ctrl & 0x01); 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..7218fe70f3bc 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; @@ -2707,6 +2708,7 @@ static void wil_wiphy_init(struct wiphy *wiphy) wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites); wiphy->mgmt_stypes = wil_mgmt_stypes; wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; + wiphy->bss_param_support = WIPHY_BSS_PARAM_AP_ISOLATE; wiphy->n_vendor_commands = ARRAY_SIZE(wil_nl80211_vendor_commands); wiphy->vendor_commands = wil_nl80211_vendor_commands; 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..6a3f187320fc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -996,9 +996,10 @@ 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_43752, 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), BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_89359, CYW), CYW_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_CYPRESS_43439, CYW), { /* end: all zeroes */ } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c index 69ef8cf203d2..67c0c5a92f99 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c @@ -393,10 +393,8 @@ void brcmf_btcoex_detach(struct brcmf_cfg80211_info *cfg) if (!cfg->btcoex) return; - if (cfg->btcoex->timer_on) { - cfg->btcoex->timer_on = false; - timer_shutdown_sync(&cfg->btcoex->timer); - } + timer_shutdown_sync(&cfg->btcoex->timer); + cfg->btcoex->timer_on = false; cancel_work_sync(&cfg->btcoex->work); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index b94c3619526c..8afaffe31031 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); @@ -5933,6 +5958,26 @@ static int brcmf_cfg80211_del_pmk(struct wiphy *wiphy, struct net_device *dev, return brcmf_set_pmk(ifp, NULL, 0); } +static int brcmf_cfg80211_change_bss(struct wiphy *wiphy, struct net_device *dev, + struct bss_parameters *params) +{ + struct brcmf_if *ifp = netdev_priv(dev); + int ret = 0; + + /* In AP mode, the "ap_isolate" value represents + * 0 = allow low-level bridging of frames between associated stations + * 1 = restrict low-level bridging of frames to isolate associated stations + * -1 = do not change existing setting + */ + if (params->ap_isolate >= 0) { + ret = brcmf_fil_iovar_int_set(ifp, "ap_isolate", params->ap_isolate); + if (ret < 0) + brcmf_err("ap_isolate iovar failed: ret=%d\n", ret); + } + + return ret; +} + static struct cfg80211_ops brcmf_cfg80211_ops = { .add_virtual_intf = brcmf_cfg80211_add_iface, .del_virtual_intf = brcmf_cfg80211_del_iface, @@ -5980,6 +6025,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .update_connect_params = brcmf_cfg80211_update_conn_params, .set_pmk = brcmf_cfg80211_set_pmk, .del_pmk = brcmf_cfg80211_del_pmk, + .change_bss = brcmf_cfg80211_change_bss, }; struct cfg80211_ops *brcmf_cfg80211_get_ops(struct brcmf_mp_device *settings) @@ -7634,6 +7680,8 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) | BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST); + wiphy->bss_param_support = WIPHY_BSS_PARAM_AP_ISOLATE; + wiphy->flags |= WIPHY_FLAG_NETNS_OK | WIPHY_FLAG_PS_ON_BY_DEFAULT | WIPHY_FLAG_HAVE_AP_SME | @@ -8313,7 +8361,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..4239f2b21e54 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c @@ -738,7 +738,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) case BRCM_CC_4364_CHIP_ID: case CY_CC_4373_CHIP_ID: return 0x160000; - case CY_CC_43752_CHIP_ID: + case BRCM_CC_43751_CHIP_ID: + case BRCM_CC_43752_CHIP_ID: case BRCM_CC_4377_CHIP_ID: return 0x170000; case BRCM_CC_4378_CHIP_ID: @@ -1450,7 +1451,8 @@ 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 CY_CC_43752_CHIP_ID: + case BRCM_CC_43751_CHIP_ID: + case BRCM_CC_43752_CHIP_ID: case CY_CC_43012_CHIP_ID: addr = CORE_CC_REG(pmu->base, retention_ctl); reg = chip->ops->read32(chip->ctx, addr); 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/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c index 83f8ed7d00f9..ef79924fd8f4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -554,12 +554,16 @@ static int brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) data = (u8 *)fw->data; data_len = fw->size; } else { - if ((data = bcm47xx_nvram_get_contents(&data_len))) + data = bcm47xx_nvram_get_contents(&data_len); + if (data) { free_bcm47xx_nvram = true; - else if ((data = brcmf_fw_nvram_from_efi(&data_len))) - kfree_nvram = true; - else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL)) - goto fail; + } else { + data = brcmf_fw_nvram_from_efi(&data_len); + if (data) + kfree_nvram = true; + else if (!(cur->flags & BRCMF_FW_REQF_OPTIONAL)) + goto fail; + } } if (data) 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..8cf9d7e7c3f7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c @@ -654,10 +654,11 @@ 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(BRCM_CC_43752_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), - BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752) }; #define TXCTL_CREDITS 2 @@ -3424,8 +3425,9 @@ err: static bool brcmf_sdio_aos_no_decode(struct brcmf_sdio *bus) { - if (bus->ci->chip == CY_CC_43012_CHIP_ID || - bus->ci->chip == CY_CC_43752_CHIP_ID) + if (bus->ci->chip == BRCM_CC_43751_CHIP_ID || + bus->ci->chip == BRCM_CC_43752_CHIP_ID || + bus->ci->chip == CY_CC_43012_CHIP_ID) return true; else return false; @@ -4275,8 +4277,9 @@ 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_43752: 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", CY_4373_F2_WATERMARK); brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, 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..df3b67ba4db2 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 @@ -59,7 +60,6 @@ #define CY_CC_4373_CHIP_ID 0x4373 #define CY_CC_43012_CHIP_ID 43012 #define CY_CC_43439_CHIP_ID 43439 -#define CY_CC_43752_CHIP_ID 43752 /* USB Device IDs */ #define BRCM_USB_43143_DEVICE_ID 0xbd1e @@ -99,6 +99,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/iwlegacy/iwl-spectrum.h b/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h index 1e8ab704dbfb..f00eb878b94b 100644 --- a/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h +++ b/drivers/net/wireless/intel/iwlegacy/iwl-spectrum.h @@ -50,28 +50,4 @@ struct ieee80211_measurement_params { __le16 duration; } __packed; -struct ieee80211_info_element { - u8 id; - u8 len; - u8 data[]; -} __packed; - -struct ieee80211_measurement_request { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - struct ieee80211_measurement_params params[]; -} __packed; - -struct ieee80211_measurement_report { - struct ieee80211_info_element ie; - u8 token; - u8 mode; - u8 type; - union { - struct ieee80211_basic_report basic[0]; - } u; -} __packed; - #endif 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..3e6206e739f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -9,28 +9,22 @@ #include "iwl-prph.h" #include "fw/api/txq.h" -/* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 99 +/* Highest firmware core release supported */ +#define IWL_BZ_UCODE_CORE_MAX 99 /* Lowest firmware API version supported */ -#define IWL_BZ_UCODE_API_MIN 93 +#define IWL_BZ_UCODE_API_MIN 100 /* 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, @@ -81,7 +75,7 @@ static const struct iwl_family_base_params iwl_bz_base = { }, }, .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .ucode_api_max = IWL_BZ_UCODE_API_MAX, + .ucode_api_max = ENCODE_CORE_AS_API(IWL_BZ_UCODE_CORE_MAX), .ucode_api_min = IWL_BZ_UCODE_API_MIN, }; @@ -107,11 +101,8 @@ 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); -IWL_FW_AND_PNVM(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_API_MAX); -IWL_FW_AND_PNVM(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_API_MAX); +IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index 45e55cef42ea..e53a785686c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c @@ -8,11 +8,11 @@ #include "iwl-prph.h" #include "fw/api/txq.h" -/* Highest firmware API version supported */ -#define IWL_DR_UCODE_API_MAX 99 +/* Highest firmware core release supported */ +#define IWL_DR_UCODE_CORE_MAX 99 /* Lowest firmware API version supported */ -#define IWL_DR_UCODE_API_MIN 97 +#define IWL_DR_UCODE_API_MIN 100 /* Memory offsets and lengths */ #define IWL_DR_SMEM_OFFSET 0x400000 @@ -20,9 +20,6 @@ #define IWL_DR_A_PE_A_FW_PRE "iwlwifi-dr-a0-pe-a0" -#define IWL_DR_A_PE_A_FW_MODULE_FIRMWARE(api) \ - IWL_DR_A_PE_A_FW_PRE "-" __stringify(api) ".ucode" - static const struct iwl_family_base_params iwl_dr_base = { .num_of_queues = 512, .max_tfd_queue_size = 65536, @@ -73,7 +70,7 @@ static const struct iwl_family_base_params iwl_dr_base = { }, }, .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .ucode_api_max = IWL_DR_UCODE_API_MAX, + .ucode_api_max = ENCODE_CORE_AS_API(IWL_DR_UCODE_CORE_MAX), .ucode_api_min = IWL_DR_UCODE_API_MIN, }; @@ -89,5 +86,5 @@ const struct iwl_mac_cfg iwl_dr_mac_cfg = { .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, }; -MODULE_FIRMWARE(IWL_DR_A_PE_A_FW_MODULE_FIRMWARE(IWL_DR_UCODE_API_MAX)); +IWL_CORE_FW(IWL_DR_A_PE_A_FW_PRE, IWL_DR_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c index f55c286e83be..c16cda087a7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c @@ -5,6 +5,36 @@ */ #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 100 + +#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" + +#define IWL_BZ_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" + +#define IWL_BZ_A_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BZ_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" + +#define IWL_SC_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_SC_A_GF_A_FW_PRE "-" __stringify(api) ".ucode" + +#define IWL_SC_A_GF4_A_MODULE_FIRMWARE(api) \ + IWL_SC_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" + /* NVM versions */ #define IWL_GF_NVM_VERSION 0x0a1d @@ -22,6 +52,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 +72,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); +MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_GF_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC_A_GF4_A_MODULE_FIRMWARE(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..6cf187d92dbf 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 100 + +#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..e9449b59114a 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -9,11 +9,11 @@ #include "iwl-prph.h" #include "fw/api/txq.h" -/* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 99 +/* Highest firmware core release supported */ +#define IWL_SC_UCODE_CORE_MAX 99 /* Lowest firmware API version supported */ -#define IWL_SC_UCODE_API_MIN 97 +#define IWL_SC_UCODE_API_MIN 100 /* 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, @@ -89,7 +78,7 @@ static const struct iwl_family_base_params iwl_sc_base = { }, }, .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, - .ucode_api_max = IWL_SC_UCODE_API_MAX, + .ucode_api_max = ENCODE_CORE_AS_API(IWL_SC_UCODE_CORE_MAX), .ucode_api_min = IWL_SC_UCODE_API_MIN, }; @@ -105,14 +94,8 @@ const struct iwl_mac_cfg iwl_sc_mac_cfg = { .ltr_delay = IWL_CFG_TRANS_LTR_DELAY_2500US, }; -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); +IWL_CORE_FW(IWL_SC_A_FM_B_FW_PRE, IWL_SC_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_SC_A_FM_C_FW_PRE, IWL_SC_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_SC_A_WH_A_FW_PRE, IWL_SC_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_SC2_A_FM_C_FW_PRE, IWL_SC_UCODE_CORE_MAX); +IWL_CORE_FW(IWL_SC2_A_WH_A_FW_PRE, IWL_SC_UCODE_CORE_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..d337ab543eb0 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; } } @@ -767,7 +766,7 @@ static int iwl_init_otp_access(struct iwl_trans *trans) { int ret; - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (ret) return ret; @@ -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/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index 0771a46bd552..a0a26ef482a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -378,7 +378,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); - iwl_trans_d3_suspend(priv->trans, false, true); + iwl_trans_d3_suspend(priv->trans, true); goto out; @@ -422,7 +422,6 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) struct ieee80211_vif *vif; u32 base; int ret; - enum iwl_d3_status d3_status; struct error_table_start { /* cf. struct iwl_error_event_table */ u32 valid; @@ -451,15 +450,10 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) /* we'll clear ctx->vif during iwlagn_prepare_restart() */ vif = ctx->vif; - ret = iwl_trans_d3_resume(priv->trans, &d3_status, false, true); + ret = iwl_trans_d3_resume(priv->trans, true); if (ret) goto out_unlock; - if (d3_status != IWL_D3_STATUS_ALIVE) { - IWL_INFO(priv, "Device was reset during suspend\n"); - goto out_unlock; - } - /* uCode is no longer operating by itself */ iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); 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.c b/drivers/net/wireless/intel/iwlwifi/dvm/power.c index 6b42d6e5f30f..e7dbba7134f7 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/power.c @@ -368,7 +368,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) /* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { - priv->power_data.bus_pm = priv->trans->pm_support; + priv->power_data.bus_pm = iwl_trans_is_pm_supported(priv->trans); priv->power_data.debug_sleep_level_override = -1; 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/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index bee7d92293b8..52edc19d8cdd 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -9,9 +9,9 @@ #include "acpi.h" #include "fw/runtime.h" -const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, - 0xA5, 0xB3, 0x1F, 0x73, - 0x8E, 0x28, 0x5A, 0xDE); +static const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, + 0xA5, 0xB3, 0x1F, 0x73, + 0x8E, 0x28, 0x5A, 0xDE); static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = { [DSM_FUNC_QUERY] = sizeof(u32), @@ -169,7 +169,7 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS); - if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size))) + if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size) || !func)) return -EINVAL; expected_size = acpi_dsm_size[func]; @@ -178,6 +178,29 @@ int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) return -EOPNOTSUPP; + if (!fwrt->acpi_dsm_funcs_valid) { + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, + DSM_FUNC_QUERY, + &iwl_guid, &tmp, + acpi_dsm_size[DSM_FUNC_QUERY]); + if (ret) { + /* always indicate BIT(0) to avoid re-reading */ + fwrt->acpi_dsm_funcs_valid = BIT(0); + return ret; + } + + IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n", + (u32)tmp); + /* always indicate BIT(0) to avoid re-reading */ + fwrt->acpi_dsm_funcs_valid = tmp | BIT(0); + } + + if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n", + func); + return -ENODATA; + } + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, &iwl_guid, &tmp, expected_size); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 68d8fb5f6357..20bc6671f4eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -140,8 +140,6 @@ struct iwl_dsm_internal_product_reset_cmd { struct iwl_fw_runtime; -extern const guid_t iwl_guid; - union acpi_object *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func, union acpi_object *args, const guid_t *guid); 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..d3bed0216df4 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 */ /** @@ -365,6 +367,7 @@ enum iwl_wowlan_flags { ENABLE_NBNS_FILTERING = BIT(2), ENABLE_DHCP_FILTERING = BIT(3), ENABLE_STORE_BEACON = BIT(4), + HAS_BEACON_PROTECTION = BIT(5), }; /** @@ -454,11 +457,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]; @@ -634,10 +632,65 @@ struct iwl_wowlan_gtk_status_v3 { struct iwl_wowlan_all_rsc_tsc_v5 sc; } __packed; /* WOWLAN_GTK_MATERIAL_VER_3 */ +/** + * enum iwl_wowlan_key_status - Status of security keys in WoWLAN notifications + * @IWL_WOWLAN_NOTIF_NO_KEY: No key is present; this entry should be ignored. + * @IWL_WOWLAN_STATUS_OLD_KEY: old key exists; no rekey occurred, and only + * metadata is available. + * @IWL_WOWLAN_STATUS_NEW_KEY: A new key was created after a rekey; new key + * material is available. + */ +enum iwl_wowlan_key_status { + IWL_WOWLAN_NOTIF_NO_KEY = 0, + IWL_WOWLAN_STATUS_OLD_KEY = 1, + IWL_WOWLAN_STATUS_NEW_KEY = 2 +}; + +/** + * struct iwl_wowlan_gtk_status - GTK status + * @key: GTK material + * @key_len: GTK length, if set to 0, the key is not available + * @key_flags: information about the key: + * bits[0:1]: key index assigned by the AP + * bits[2:6]: GTK index of the key in the internal DB + * bit[7]: Set iff this is the currently used GTK + * @key_status: key status, see &enum iwl_wowlan_key_status + * @reserved: padding + * @tkip_mic_key: TKIP RX MIC key + * @sc: RSC/TSC counters + */ +struct iwl_wowlan_gtk_status { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 key_len; + u8 key_flags; + u8 key_status; + u8 reserved; + u8 tkip_mic_key[IWL_MIC_KEY_SIZE]; + struct iwl_wowlan_all_rsc_tsc_v5 sc; +} __packed; /* WOWLAN_GTK_MATERIAL_VER_4 */ + #define IWL_WOWLAN_GTK_IDX_MASK (BIT(0) | BIT(1)) #define IWL_WOWLAN_IGTK_BIGTK_IDX_MASK (BIT(0)) /** + * struct iwl_wowlan_igtk_status_v1 - IGTK status + * @key: IGTK material + * @ipn: the IGTK packet number (replay counter) + * @key_len: IGTK length, if set to 0, the key is not available + * @key_flags: information about the key: + * bits[0]: key index assigned by the AP (0: index 4, 1: index 5) + * (0: index 6, 1: index 7 with bigtk) + * bits[1:5]: IGTK index of the key in the internal DB + * bit[6]: Set iff this is the currently used IGTK + */ +struct iwl_wowlan_igtk_status_v1 { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 ipn[6]; + u8 key_len; + u8 key_flags; +} __packed; /* WOWLAN_IGTK_MATERIAL_VER_1 */ + +/** * struct iwl_wowlan_igtk_status - IGTK status * @key: IGTK material * @ipn: the IGTK packet number (replay counter) @@ -647,13 +700,17 @@ struct iwl_wowlan_gtk_status_v3 { * (0: index 6, 1: index 7 with bigtk) * bits[1:5]: IGTK index of the key in the internal DB * bit[6]: Set iff this is the currently used IGTK + * @key_status: key status, see &enum iwl_wowlan_key_status + * @reserved: padding */ struct iwl_wowlan_igtk_status { u8 key[WOWLAN_KEY_MAX_SIZE]; u8 ipn[6]; u8 key_len; u8 key_flags; -} __packed; /* WOWLAN_IGTK_MATERIAL_VER_1 */ + u8 key_status; + u8 reserved[3]; +} __packed; /* WOWLAN_IGTK_MATERIAL_VER_2 */ /** * struct iwl_wowlan_status_v6 - WoWLAN status @@ -703,7 +760,7 @@ struct iwl_wowlan_status_v6 { */ struct iwl_wowlan_status_v7 { struct iwl_wowlan_gtk_status_v2 gtk[WOWLAN_GTK_KEYS_NUM]; - struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; __le16 non_qos_seq_ctr; @@ -718,82 +775,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 @@ -814,7 +795,7 @@ struct iwl_wowlan_status_v12 { */ struct iwl_wowlan_info_notif_v1 { 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_v1 igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; __le16 reserved1; @@ -830,39 +811,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 +858,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,15 +873,12 @@ 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]; + struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 bigtk[WOWLAN_BIGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; __le16 reserved1; @@ -944,10 +889,47 @@ struct iwl_wowlan_info_notif_v4 { __le32 received_beacons; u8 tid_tear_down; u8 station_id; + u8 reserved2[2]; +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3 */ + +/** + * struct iwl_wowlan_info_notif_v5 - WoWLAN information notification + * @gtk: GTK data + * @igtk: IGTK data + * @bigtk: BIGTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched patterns + * @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 + * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs + * following this notif + * @tid_offloaded_tx: tid used by the firmware to transmit data packets + * while in wowlan + * @mlo_gtks: array of GTKs of size num_mlo_link_keys + */ +struct iwl_wowlan_info_notif_v5 { + struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status_v1 bigtk[WOWLAN_BIGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 qos_seq_ctr; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + u8 tid_tear_down; + u8 station_id; u8 num_mlo_link_keys; - u8 reserved2; + u8 tid_offloaded_tx; struct iwl_wowlan_mlo_gtk mlo_gtks[]; -} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */ +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */ /** * struct iwl_wowlan_info_notif - WoWLAN information notification @@ -971,7 +953,7 @@ struct iwl_wowlan_info_notif_v4 { * @mlo_gtks: array of GTKs of size num_mlo_link_keys */ struct iwl_wowlan_info_notif { - struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_gtk_status 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]; __le64 replay_ctr; @@ -986,7 +968,7 @@ struct iwl_wowlan_info_notif { u8 num_mlo_link_keys; u8 tid_offloaded_tx; struct iwl_wowlan_mlo_gtk mlo_gtks[]; -} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */ +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_6 */ /** * struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet 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/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index b9f559dac39f..f76cea6e9ec8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -420,6 +420,8 @@ struct iwl_mac_config_cmd { * eht_support set to true. No longer used since _VER_3 of this command. * @LINK_CONTEXT_MODIFY_BANDWIDTH: Covers iwl_link_ctx_cfg_cmd::modify_bandwidth. * Request RX OMI to the AP to modify bandwidth of this link. + * @LINK_CONTEXT_MODIFY_UHR_PARAMS: covers iwl_link_ctx_cfg_cmd::npca_params and + * iwl_link_ctx_cfg_cmd::prio_edca_params. Since _VER_7. * @LINK_CONTEXT_MODIFY_ALL: set all above flags */ enum iwl_link_ctx_modify_flags { @@ -432,6 +434,7 @@ enum iwl_link_ctx_modify_flags { LINK_CONTEXT_MODIFY_BSS_COLOR_DISABLE = BIT(6), LINK_CONTEXT_MODIFY_EHT_PARAMS = BIT(7), LINK_CONTEXT_MODIFY_BANDWIDTH = BIT(8), + LINK_CONTEXT_MODIFY_UHR_PARAMS = BIT(9), LINK_CONTEXT_MODIFY_ALL = 0xff, }; /* LINK_CONTEXT_MODIFY_MASK_E_VER_1 */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h index 5cdc09d465d4..e90f3187e55c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.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-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -754,7 +754,7 @@ struct iwl_lari_config_change_cmd_v10 { * according to the BIOS definitions. * For LARI cmd version 11 - bits 0:4 are supported. * For LARI cmd version 12 - bits 0:6 are supported and bits 7:31 are - * reserved. No need to mask out the reserved bits. + * reserved. * @force_disable_channels_bitmap: Bitmap of disabled bands/channels. * Each bit represents a set of channels in a specific band that should be * disabled @@ -787,6 +787,7 @@ struct iwl_lari_config_change_cmd { /* Activate UNII-1 (5.2GHz) for World Wide */ #define ACTIVATE_5G2_IN_WW_MASK BIT(4) #define CHAN_STATE_ACTIVE_BITMAP_CMD_V11 0x1F +#define CHAN_STATE_ACTIVE_BITMAP_CMD_V12 0x7F /** * struct iwl_pnvm_init_complete_ntfy - PNVM initialization complete diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h index 9b09b835560b..bb801650a565 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,8 +19,8 @@ enum iwl_prot_offload_subcmd_ids { /** * @WOWLAN_INFO_NOTIFICATION: Notification in - * &struct iwl_wowlan_info_notif_v1, &struct iwl_wowlan_info_notif_v2, - * or &struct iwl_wowlan_info_notif + * &struct iwl_wowlan_info_notif_v1, iwl_wowlan_info_notif_v3, + * &struct iwl_wowlan_info_notif_v5 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..5eb8d10678fd 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; }; }; @@ -632,17 +571,16 @@ enum iwl_ppag_flags { /** * union iwl_ppag_table_cmd - union for all versions of PPAG command * @v1: command version 1 structure. - * @v2: command version from 2 to 6 are same structure as v2. - * but has a different format of the flags bitmap - * @v3: command version 7 structure. + * @v5: command version 5 structure. + * @v7: command version 7 structure. * @v1.flags: values from &enum iwl_ppag_flags * @v1.gain: table of antenna gain values per chain and sub-band * @v1.reserved: reserved - * @v2.flags: values from &enum iwl_ppag_flags - * @v2.gain: table of antenna gain values per chain and sub-band - * @v3.ppag_config_info: see @struct bios_value_u32 - * @v3.gain: table of antenna gain values per chain and sub-band - * @v3.reserved: reserved + * @v5.flags: values from &enum iwl_ppag_flags + * @v5.gain: table of antenna gain values per chain and sub-band + * @v7.ppag_config_info: see @struct bios_value_u32 + * @v7.gain: table of antenna gain values per chain and sub-band + * @v7.reserved: reserved */ union iwl_ppag_table_cmd { struct { @@ -654,30 +592,19 @@ union iwl_ppag_table_cmd { __le32 flags; s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; s8 reserved[2]; - } __packed v2; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_2, VER3, VER4, - * VER5, VER6 - */ + } __packed v5; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_5 */ struct { struct bios_value_u32 ppag_config_info; s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; s8 reserved[2]; - } __packed v3; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */ + } __packed v7; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */ } __packed; -#define IWL_PPAG_CMD_V4_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) -#define IWL_PPAG_CMD_V5_MASK (IWL_PPAG_CMD_V4_MASK | \ +#define IWL_PPAG_CMD_V1_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) +#define IWL_PPAG_CMD_V5_MASK (IWL_PPAG_CMD_V1_MASK | \ IWL_PPAG_ETSI_LPI_UHB_MASK | \ IWL_PPAG_USA_LPI_UHB_MASK) -#define IWL_PPAG_CMD_V6_MASK (IWL_PPAG_CMD_V5_MASK | \ - IWL_PPAG_ETSI_VLP_UHB_MASK | \ - IWL_PPAG_ETSI_SP_UHB_MASK | \ - IWL_PPAG_USA_VLP_UHB_MASK | \ - IWL_PPAG_USA_SP_UHB_MASK | \ - IWL_PPAG_CANADA_LPI_UHB_MASK | \ - IWL_PPAG_CANADA_VLP_UHB_MASK | \ - IWL_PPAG_CANADA_SP_UHB_MASK) - #define MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE 26 #define MCC_TO_SAR_OFFSET_TABLE_COL_SIZE 13 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h index 3222cbcbe1ab..9c464e7aba10 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rs.h @@ -24,6 +24,8 @@ * for BPSK (MCS 0) with 2 spatial * streams * @IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK: enable support for EHT extra LTF + * @IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_1_5_MBPS_MSK: support ELR 1.5 Mbps + * @IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_3_MBPS_MSK: support ELR 3 Mbps */ enum iwl_tlc_mng_cfg_flags { IWL_TLC_MNG_CFG_FLAGS_STBC_MSK = BIT(0), @@ -32,6 +34,8 @@ enum iwl_tlc_mng_cfg_flags { IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK = BIT(3), IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_2_MSK = BIT(4), IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK = BIT(6), + IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_1_5_MBPS_MSK = BIT(7), + IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_3_MBPS_MSK = BIT(8), }; /** @@ -201,6 +205,37 @@ struct iwl_tlc_config_cmd_v4 { } __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */ /** + * struct iwl_tlc_config_cmd - TLC configuration + * @sta_id: station id + * @reserved1: reserved + * @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw + * @mode: &enum iwl_tlc_mng_cfg_mode + * @chains: bitmask of &enum iwl_tlc_mng_cfg_chains + * @sgi_ch_width_supp: bitmap of SGI support per channel width + * use BIT(&enum iwl_tlc_mng_cfg_cw) + * @flags: bitmask of &enum iwl_tlc_mng_cfg_flags + * @non_ht_rates: bitmap of supported legacy rates + * @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per <nss, channel-width> + * pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz). + * @max_mpdu_len: max MPDU length, in bytes + * @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI), + * set zero for no limit. + */ +struct iwl_tlc_config_cmd { + u8 sta_id; + u8 reserved1[3]; + u8 max_ch_width; + u8 mode; + u8 chains; + u8 sgi_ch_width_supp; + __le16 flags; + __le16 non_ht_rates; + __le32 ht_rates[IWL_TLC_NSS_MAX][IWL_TLC_MCS_PER_BW_NUM_V4]; + __le16 max_mpdu_len; + __le16 max_tx_op; +} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_5 */ + +/** * enum iwl_tlc_update_flags - updated fields * @IWL_TLC_NOTIF_FLAG_RATE: last initial rate update * @IWL_TLC_NOTIF_FLAG_AMSDU: umsdu parameters update 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..2ce55859641c 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -830,7 +830,7 @@ iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt, } /* reading RXF/TXF sizes */ - if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) { + if (iwl_trans_is_fw_error(fwrt->trans)) { fifo_len = iwl_fw_rxf_len(fwrt, mem_cfg); fifo_len += iwl_fw_txf_len(fwrt, mem_cfg); @@ -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); @@ -2377,7 +2393,7 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_dump_cfg_name *cfg_name; u32 size = sizeof(*tlv) + sizeof(*dump); u32 num_of_cfg_names = 0; - u32 hw_type, is_cdb, is_jacket; + u32 hw_type, is_cdb; list_for_each_entry(node, &fwrt->trans->dbg.debug_info_tlv_list, list) { size += sizeof(*cfg_name); @@ -2410,11 +2426,7 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, hw_type = CSR_HW_REV_TYPE(fwrt->trans->info.hw_rev); is_cdb = CSR_HW_RFID_IS_CDB(fwrt->trans->info.hw_rf_id); - is_jacket = !!(iwl_read_umac_prph(fwrt->trans, WFPM_OTP_CFG1_ADDR) & - WFPM_OTP_CFG1_IS_JACKET_BIT); - - /* Use bits 12 and 13 to indicate jacket/CDB, respectively */ - hw_type |= (is_jacket | (is_cdb << 1)) << IWL_JACKET_CDB_SHIFT; + hw_type |= IWL_CDB_MASK(is_cdb); dump->hw_type = cpu_to_le32(hw_type); @@ -2462,36 +2474,6 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, return entry->size; } -static u32 iwl_dump_ini_file_name_info(struct iwl_fw_runtime *fwrt, - struct list_head *list) -{ - struct iwl_fw_ini_dump_entry *entry; - struct iwl_dump_file_name_info *tlv; - u32 len = strnlen(fwrt->trans->dbg.dump_file_name_ext, - IWL_FW_INI_MAX_NAME); - - if (!fwrt->trans->dbg.dump_file_name_ext_valid) - return 0; - - entry = vzalloc(sizeof(*entry) + sizeof(*tlv) + len); - if (!entry) - return 0; - - entry->size = sizeof(*tlv) + len; - - tlv = (void *)entry->data; - tlv->type = cpu_to_le32(IWL_INI_DUMP_NAME_TYPE); - tlv->len = cpu_to_le32(len); - memcpy(tlv->data, fwrt->trans->dbg.dump_file_name_ext, len); - - /* add the dump file name extension tlv to the list */ - list_add_tail(&entry->list, list); - - fwrt->trans->dbg.dump_file_name_ext_valid = false; - - return entry->size; -} - static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { [IWL_FW_INI_REGION_INVALID] = {}, [IWL_FW_INI_REGION_INTERNAL_BUFFER] = { @@ -2748,7 +2730,6 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, &iwl_dump_ini_region_ops[IWL_FW_INI_REGION_DRAM_IMR]); if (size) { - size += iwl_dump_ini_file_name_info(fwrt, list); size += iwl_dump_ini_info(fwrt, trigger, list); } @@ -2962,7 +2943,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 +2989,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 +3020,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 +3032,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 +3054,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); @@ -3135,7 +3116,7 @@ static void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt, .len[0] = sizeof(hcmd_data), }; - if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) + if (iwl_trans_is_fw_error(fwrt->trans)) return; if (fw_has_capa(&fwrt->fw->ucode_capa, @@ -3164,13 +3145,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..ddd714cff2f4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -14,13 +14,6 @@ #include "iwl-csr.h" #include "pnvm.h" -#define FW_ASSERT_LMAC_FATAL 0x70 -#define FW_ASSERT_LMAC2_FATAL 0x72 -#define FW_ASSERT_UMAC_FATAL 0x71 -#define UMAC_RT_NMI_LMAC2_FATAL 0x72 -#define RT_NMI_INTERRUPT_OTHER_LMAC_FATAL 0x73 -#define FW_ASSERT_NMI_UNKNOWN 0x84 - /* * Note: This structure is read from the device with IO accesses, * and the reading already does the endian conversion. As it is @@ -103,17 +96,6 @@ struct iwl_umac_error_event_table { #define ERROR_START_OFFSET (1 * sizeof(u32)) #define ERROR_ELEM_SIZE (7 * sizeof(u32)) -static bool iwl_fwrt_if_errorid_other_cpu(u32 err_id) -{ - err_id &= 0xFF; - - if ((err_id >= FW_ASSERT_LMAC_FATAL && - err_id <= RT_NMI_INTERRUPT_OTHER_LMAC_FATAL) || - err_id == FW_ASSERT_NMI_UNKNOWN) - return true; - return false; -} - static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt) { struct iwl_trans *trans = fwrt->trans; @@ -131,13 +113,6 @@ static void iwl_fwrt_dump_umac_error_log(struct iwl_fw_runtime *fwrt) if (table.valid) fwrt->dump.umac_err_id = table.error_id; - if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.umac_err_id) && - !fwrt->trans->dbg.dump_file_name_ext_valid) { - fwrt->trans->dbg.dump_file_name_ext_valid = true; - snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "0x%x", fwrt->dump.umac_err_id); - } - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", @@ -199,11 +174,11 @@ 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; - err = iwl_finish_nic_init(trans); + err = iwl_trans_activate_nic(trans); if (err) return; } @@ -213,13 +188,6 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu if (table.valid) fwrt->dump.lmac_err_id[lmac_num] = table.error_id; - if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.lmac_err_id[lmac_num]) && - !fwrt->trans->dbg.dump_file_name_ext_valid) { - fwrt->trans->dbg.dump_file_name_ext_valid = true; - snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "0x%x", fwrt->dump.lmac_err_id[lmac_num]); - } - if (ERROR_START_OFFSET <= table.valid * ERROR_ELEM_SIZE) { IWL_ERR(trans, "Start IWL Error Log Dump:\n"); IWL_ERR(trans, "Transport status: 0x%08lX, valid: %d\n", @@ -305,16 +273,6 @@ static void iwl_fwrt_dump_tcm_error_log(struct iwl_fw_runtime *fwrt, int idx) iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - if (table.valid) - fwrt->dump.tcm_err_id[idx] = table.error_id; - - if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.tcm_err_id[idx]) && - !fwrt->trans->dbg.dump_file_name_ext_valid) { - fwrt->trans->dbg.dump_file_name_ext_valid = true; - snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "0x%x", fwrt->dump.tcm_err_id[idx]); - } - IWL_ERR(fwrt, "TCM%d status:\n", idx + 1); IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); IWL_ERR(fwrt, "0x%08X | tcm branchlink2\n", table.blink2); @@ -378,16 +336,6 @@ static void iwl_fwrt_dump_rcm_error_log(struct iwl_fw_runtime *fwrt, int idx) iwl_trans_read_mem_bytes(trans, base, &table, sizeof(table)); - if (table.valid) - fwrt->dump.rcm_err_id[idx] = table.error_id; - - if (!iwl_fwrt_if_errorid_other_cpu(fwrt->dump.rcm_err_id[idx]) && - !fwrt->trans->dbg.dump_file_name_ext_valid) { - fwrt->trans->dbg.dump_file_name_ext_valid = true; - snprintf(fwrt->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "0x%x", fwrt->dump.rcm_err_id[idx]); - } - IWL_ERR(fwrt, "RCM%d status:\n", idx + 1); IWL_ERR(fwrt, "0x%08X | error ID\n", table.error_id); IWL_ERR(fwrt, "0x%08X | rcm branchlink2\n", table.blink2); @@ -490,7 +438,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/error-dump.h b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h index cf41021d59ad..c2a73cc85eff 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/error-dump.h @@ -372,7 +372,8 @@ struct iwl_fw_ini_dump_cfg_name { u8 cfg_name[IWL_FW_INI_MAX_CFG_NAME]; } __packed; -#define IWL_JACKET_CDB_SHIFT 12 +#define IWL_CDB_MASK(val) val << 13 + /* struct iwl_fw_ini_dump_info - ini dump information * @version: dump version 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..f297e82d63d2 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) @@ -236,11 +237,12 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, return -ENOENT; } -static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) +static u8 *iwl_pnvm_get_from_fs(struct iwl_trans *trans, size_t *len) { const struct firmware *pnvm; char pnvm_name[MAX_PNVM_NAME]; size_t new_len; + u8 *data; int ret; iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name)); @@ -249,29 +251,73 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) if (ret) { IWL_DEBUG_FW(trans, "PNVM file %s not found %d\n", pnvm_name, ret); - return ret; + return NULL; } new_len = pnvm->size; - *data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL); + data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL); release_firmware(pnvm); - if (!*data) - return -ENOMEM; + if (!data) + return NULL; *len = new_len; - return 0; + return data; +} + +/** + * enum iwl_pnvm_source - different PNVM possible sources + * + * @IWL_PNVM_SOURCE_NONE: No PNVM. + * @IWL_PNVM_SOURCE_BIOS: PNVM should be read from BIOS. + * @IWL_PNVM_SOURCE_EXTERNAL: read .pnvm external file + * @IWL_PNVM_SOURCE_EMBEDDED: PNVM is embedded in the .ucode file. + */ +enum iwl_pnvm_source { + IWL_PNVM_SOURCE_NONE, + IWL_PNVM_SOURCE_BIOS, + IWL_PNVM_SOURCE_EXTERNAL, + IWL_PNVM_SOURCE_EMBEDDED +}; + +static enum iwl_pnvm_source iwl_select_pnvm_source(struct iwl_trans *trans, + bool intel_sku) +{ + + /* Get PNVM from BIOS for non-Intel SKU */ + if (!intel_sku) + return IWL_PNVM_SOURCE_BIOS; + + /* Before those devices, PNVM didn't exist at all */ + if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + return IWL_PNVM_SOURCE_NONE; + + /* After those devices, we moved to embedded PNVM */ + if (trans->mac_cfg->device_family > IWL_DEVICE_FAMILY_AX210) + return IWL_PNVM_SOURCE_EMBEDDED; + + /* For IWL_DEVICE_FAMILY_AX210, depends on the CRF */ + if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_GF) + return IWL_PNVM_SOURCE_EXTERNAL; + + return IWL_PNVM_SOURCE_NONE; } -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; + enum iwl_pnvm_source pnvm_src = + iwl_select_pnvm_source(trans_p, sku_id[2] == 0); u8 *image = NULL; - /* Get PNVM from BIOS for non-Intel SKU */ - if (sku_id[2]) { + IWL_DEBUG_FW(trans_p, "PNVM source %d\n", pnvm_src); + + if (pnvm_src == IWL_PNVM_SOURCE_NONE) + return NULL; + + if (pnvm_src == IWL_PNVM_SOURCE_BIOS) { package = iwl_uefi_get_pnvm(trans_p, len); if (!IS_ERR_OR_NULL(package)) { if (*len >= sizeof(*package)) { @@ -288,21 +334,35 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, if (image) return image; } + + /* PNVM doesn't exist in BIOS. Find the fallback source */ + pnvm_src = iwl_select_pnvm_source(trans_p, true); + IWL_DEBUG_FW(trans_p, "PNVM in BIOS doesn't exist, try %d\n", + pnvm_src); } - /* 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; - return image; + if (pnvm_src == IWL_PNVM_SOURCE_EXTERNAL) { + image = iwl_pnvm_get_from_fs(trans_p, len); + if (image) + return image; + } + + if (pnvm_src == IWL_PNVM_SOURCE_EMBEDDED && fw->pnvm_data) { + *len = fw->pnvm_size; + return fw->pnvm_data; + } + + IWL_ERR(trans_p, "Couldn't get PNVM from required source: %d\n", pnvm_src); + return NULL; } 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 +373,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 +389,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 +454,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 +464,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 74b90bd92c48..e1f28b053253 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -59,11 +59,16 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), }, }, - { .ident = "ASUS", + { .ident = "ASUSTEK", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), }, }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), + }, + }, { .ident = "GOOGLE-HP", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), @@ -141,11 +146,16 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, }, - { .ident = "ASUS", + { .ident = "ASUSTEK", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), }, }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), + }, + }, { .ident = "GOOGLE-HP", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Google"), @@ -305,6 +315,7 @@ static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain, return true; } +/* Utility function for iwlmvm and iwlxvt */ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd, int *cmd_size) { @@ -344,18 +355,18 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, num_sub_bands = IWL_NUM_SUB_BANDS_V1; gain = cmd->v1.gain[0]; *cmd_size = sizeof(cmd->v1); - cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); + cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK); if (fwrt->ppag_bios_rev >= 1) { /* in this case FW supports revision 0 */ IWL_DEBUG_RADIO(fwrt, "PPAG table rev is %d, send truncated table\n", fwrt->ppag_bios_rev); } - } else if (cmd_ver >= 2 && cmd_ver <= 6) { + } else if (cmd_ver == 5) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; - gain = cmd->v2.gain[0]; - *cmd_size = sizeof(cmd->v2); - cmd->v2.flags = cpu_to_le32(fwrt->ppag_flags); + gain = cmd->v5.gain[0]; + *cmd_size = sizeof(cmd->v5); + cmd->v5.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK); if (fwrt->ppag_bios_rev == 0) { /* in this case FW supports revisions 1,2 or 3 */ IWL_DEBUG_RADIO(fwrt, @@ -363,11 +374,11 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, } } else if (cmd_ver == 7) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; - gain = cmd->v3.gain[0]; - *cmd_size = sizeof(cmd->v3); - cmd->v3.ppag_config_info.table_source = fwrt->ppag_bios_source; - cmd->v3.ppag_config_info.table_revision = fwrt->ppag_bios_rev; - cmd->v3.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags); + gain = cmd->v7.gain[0]; + *cmd_size = sizeof(cmd->v7); + cmd->v7.ppag_config_info.table_source = fwrt->ppag_bios_source; + cmd->v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev; + cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags); } else { IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); return -EINVAL; @@ -378,30 +389,22 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, "PPAG MODE bits were read from bios: %d\n", fwrt->ppag_flags); - if (cmd_ver == 6) - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V6_MASK); - else if (cmd_ver == 5) - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK); - else if (cmd_ver < 5) - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK); - - if ((cmd_ver == 1 && - !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || - (cmd_ver == 2 && fwrt->ppag_bios_rev >= 2)) { + if (cmd_ver == 1 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) { cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); } else { IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); } - /* The 'flags' field is the same in v1 and v2 so we can just + /* The 'flags' field is the same in v1 and v5 so we can just * use v1 to access it. */ IWL_DEBUG_RADIO(fwrt, "PPAG MODE bits going to be sent: %d\n", (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) : - le32_to_cpu(cmd->v3.ppag_config_info.value)); + le32_to_cpu(cmd->v7.ppag_config_info.value)); for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { for (j = 0; j < num_sub_bands; j++) { @@ -579,6 +582,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 +598,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,13 +624,17 @@ int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); if (!ret) { - 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; @@ -633,13 +647,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..735482e7adf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -12,7 +12,6 @@ #include "fw/api/phy.h" #include "fw/api/config.h" #include "fw/api/nvm-reg.h" -#include "fw/img.h" #include "iwl-trans.h" #define BIOS_SAR_MAX_PROFILE_NUM 4 @@ -159,6 +158,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/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index 0444a736c2b2..806f9bcdf4f5 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -113,6 +113,10 @@ struct iwl_txf_iter_data { * @phy_filters: specific phy filters as read from WPFC BIOS table * @ppag_bios_rev: PPAG BIOS revision * @ppag_bios_source: see &enum bios_source + * @acpi_dsm_funcs_valid: bitmap indicating which DSM values are valid, + * zero (default initialization) means it hasn't been read yet, + * and BIT(0) is set when it has since function 0 also has this + * bitmap and is always supported */ struct iwl_fw_runtime { struct iwl_trans *trans; @@ -146,8 +150,6 @@ struct iwl_fw_runtime { unsigned long non_collect_ts_start[IWL_FW_INI_TIME_POINT_NUM]; u32 *d3_debug_data; u32 lmac_err_id[MAX_NUM_LMAC]; - u32 tcm_err_id[MAX_NUM_TCM]; - u32 rcm_err_id[MAX_NUM_RCM]; u32 umac_err_id; struct iwl_txf_iter_data txf_iter_data; @@ -189,6 +191,10 @@ struct iwl_fw_runtime { bool uats_valid; u8 uefi_tables_lock_status; struct iwl_phy_specific_cfg phy_filters; + +#ifdef CONFIG_ACPI + u32 acpi_dsm_funcs_valid; +#endif }; void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index 48126ec6b94b..4ae4d215e633 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -727,6 +727,8 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, struct uefi_cnv_var_general_cfg *data; int ret = -EINVAL; + BUILD_BUG_ON(ARRAY_SIZE(data->functions) < DSM_FUNC_NUM_FUNCS); + /* Not supported function index */ if (func >= DSM_FUNC_NUM_FUNCS || func == 5) return -EOPNOTSUPP; @@ -742,8 +744,9 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, goto out; } - if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) { - IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n"); + if (!(data->functions[DSM_FUNC_QUERY] & BIT(func))) { + IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n", + func, data->functions[DSM_FUNC_QUERY]); goto out; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 91f22ce36d74..a607e7ab914b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -11,6 +11,7 @@ #include <linux/netdevice.h> #include <linux/ieee80211.h> #include <linux/nl80211.h> +#include <linux/module.h> #include <linux/mod_devicetable.h> #include "iwl-csr.h" #include "iwl-drv.h" @@ -107,6 +108,9 @@ enum iwl_nvm_type { MODULE_FIRMWARE(pfx "-" __stringify(api) ".ucode"); \ MODULE_FIRMWARE(pfx ".pnvm") +#define IWL_CORE_FW(pfx, core) \ + MODULE_FIRMWARE(pfx "-c" __stringify(core) ".ucode") + static inline u8 num_of_ant(u8 mask) { return !!((mask) & ANT_A) + @@ -192,8 +196,8 @@ struct iwl_family_base_params { u8 max_ll_items; u8 led_compensation; - u8 ucode_api_max; - u8 ucode_api_min; + u16 ucode_api_max; + u16 ucode_api_min; u32 mac_addr_from_csr:10; u8 nvm_hw_section_num; netdev_features_t features; @@ -211,6 +215,34 @@ struct iwl_family_base_params { }; /* + * FW is released as "core N release", and we used to have a + * gap of 3 between the API version and core number. Now the + * reported API version will be 1000 + core and we encode it + * in the filename as "c<core>". + */ +#define API_IS_CORE_START 1000 +#define API_TO_CORE_OFFS 3 +#define ENCODE_CORE_AS_API(core) (API_IS_CORE_START + (core)) + +static inline bool iwl_api_is_core_number(int api) +{ + return api >= API_IS_CORE_START; +} + +static inline int iwl_api_to_core(int api) +{ + if (iwl_api_is_core_number(api)) + return api - API_IS_CORE_START; + + return api - API_TO_CORE_OFFS; +} + +#define FW_API_FMT "%s%d" +#define FW_API_ARG(n) \ + iwl_api_is_core_number(n) ? "c" : "", \ + iwl_api_is_core_number(n) ? (n) - API_IS_CORE_START : (n) + +/* * @stbc: support Tx STBC and 1*SS Rx STBC * @ldpc: support Tx/Rx with LDPC * @use_rts_for_aggregation: use rts/cts protection for HT traffic @@ -422,8 +454,8 @@ struct iwl_rf_cfg { u8 valid_tx_ant; u8 valid_rx_ant; u8 non_shared_ant; - u8 ucode_api_max; - u8 ucode_api_min; + u16 ucode_api_max; + u16 ucode_api_min; u16 num_rbds; }; @@ -488,8 +520,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 +531,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..607fcea6f4ef 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; @@ -331,10 +337,18 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) return -EINVAL; } + if (CSR_HW_RFID_TYPE(drv->trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_WH && + CSR_HW_RFID_STEP(drv->trans->info.hw_rf_id) == SILICON_A_STEP) { + IWL_ERR(drv, "WH A step is not supported\n"); + return -EINVAL; + } + fw_name_pre = iwl_drv_get_fwname_pre(drv->trans, _fw_name_pre); if (first) drv->fw_index = ucode_api_max; + else if (drv->fw_index == ENCODE_CORE_AS_API(99)) + drv->fw_index = 101; /* last API-scheme number below core 99 */ else drv->fw_index--; @@ -342,13 +356,15 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) IWL_ERR(drv, "no suitable firmware found!\n"); if (ucode_api_min == ucode_api_max) { - IWL_ERR(drv, "%s-%d is required\n", fw_name_pre, - ucode_api_max); + IWL_ERR(drv, "%s-" FW_API_FMT " is required\n", + fw_name_pre, FW_API_ARG(ucode_api_max)); } else { - IWL_ERR(drv, "minimum version required: %s-%d\n", - fw_name_pre, ucode_api_min); - IWL_ERR(drv, "maximum version supported: %s-%d\n", - fw_name_pre, ucode_api_max); + IWL_ERR(drv, + "minimum version required: %s-" FW_API_FMT "\n", + fw_name_pre, FW_API_ARG(ucode_api_min)); + IWL_ERR(drv, + "maximum version supported: %s-" FW_API_FMT "\n", + fw_name_pre, FW_API_ARG(ucode_api_max)); } IWL_ERR(drv, @@ -356,8 +372,9 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first) return -ENOENT; } - snprintf(drv->firmware_name, sizeof(drv->firmware_name), "%s-%d.ucode", - fw_name_pre, drv->fw_index); + snprintf(drv->firmware_name, sizeof(drv->firmware_name), + "%s-" FW_API_FMT ".ucode", + fw_name_pre, FW_API_ARG(drv->fw_index)); IWL_DEBUG_FW_INFO(drv, "attempting to load firmware '%s'\n", drv->firmware_name); @@ -1276,8 +1293,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 +1417,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 +1555,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 @@ -1573,6 +1599,7 @@ static void _iwl_op_mode_stop(struct iwl_drv *drv) */ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) { + unsigned int min_core, max_core, loaded_core; struct iwl_drv *drv = context; struct iwl_fw *fw = &drv->fw; const struct iwl_ucode_header *ucode; @@ -1635,11 +1662,24 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) * firmware filename ... but we don't check for that and only rely * on the API version read from firmware header from here on forward */ - if (api_ver < api_min || api_ver > api_max) { + + /* + * if -cN.ucode file was loaded, core version == file version, + * otherwise core version == file version (API version) - 3 + */ + if (iwl_api_is_core_number(drv->fw_index)) + loaded_core = api_ver; + else + loaded_core = api_ver - API_TO_CORE_OFFS; + + min_core = iwl_api_to_core(api_min); + max_core = iwl_api_to_core(api_max); + + if (loaded_core < min_core || loaded_core > max_core) { IWL_ERR(drv, "Driver unable to support your firmware API. " - "Driver supports v%u, firmware is v%u.\n", - api_max, api_ver); + "Driver supports FW core %u..%u, firmware is %u.\n", + min_core, max_core, loaded_core); goto try_again; } @@ -2037,8 +2077,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..b1944584c693 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -3,7 +3,6 @@ * Copyright (C) 2003-2014, 2018-2022, 2024-2025 Intel Corporation * Copyright (C) 2015-2016 Intel Deutschland GmbH */ -#include <linux/delay.h> #include <linux/device.h> #include <linux/export.h> @@ -13,6 +12,7 @@ #include "iwl-debug.h" #include "iwl-prph.h" #include "iwl-fh.h" +#include "pcie/gen1_2/internal.h" void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) { @@ -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) { @@ -166,7 +160,7 @@ int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, do { if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) - return t; + return 0; udelay(IWL_POLL_INTERVAL); t += IWL_POLL_INTERVAL; } while (t < timeout); @@ -402,96 +396,11 @@ int iwl_dump_fh(struct iwl_trans *trans, char **buf) return 0; } -#define IWL_HOST_MON_BLOCK_PEMON 0x00 -#define IWL_HOST_MON_BLOCK_HIPM 0x22 - -#define IWL_HOST_MON_BLOCK_PEMON_VEC0 0x00 -#define IWL_HOST_MON_BLOCK_PEMON_VEC1 0x01 -#define IWL_HOST_MON_BLOCK_PEMON_WFPM 0x06 - -static void iwl_dump_host_monitor_block(struct iwl_trans *trans, - u32 block, u32 vec, u32 iter) -{ - int i; - - IWL_ERR(trans, "Host monitor block 0x%x vector 0x%x\n", block, vec); - iwl_write32(trans, CSR_MONITOR_CFG_REG, (block << 8) | vec); - for (i = 0; i < iter; i++) - IWL_ERR(trans, " value [iter %d]: 0x%08x\n", - i, iwl_read32(trans, CSR_MONITOR_STATUS_REG)); -} - -static void iwl_dump_host_monitor(struct iwl_trans *trans) -{ - switch (trans->mac_cfg->device_family) { - case IWL_DEVICE_FAMILY_22000: - case IWL_DEVICE_FAMILY_AX210: - IWL_ERR(trans, "CSR_RESET = 0x%x\n", - iwl_read32(trans, CSR_RESET)); - iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, - IWL_HOST_MON_BLOCK_PEMON_VEC0, 15); - iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, - IWL_HOST_MON_BLOCK_PEMON_VEC1, 15); - iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, - IWL_HOST_MON_BLOCK_PEMON_WFPM, 15); - iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_HIPM, - IWL_HOST_MON_BLOCK_PEMON_VEC0, 1); - break; - default: - /* not supported yet */ - return; - } -} - -int iwl_finish_nic_init(struct iwl_trans *trans) +int iwl_trans_activate_nic(struct iwl_trans *trans) { - const struct iwl_mac_cfg *mac_cfg = trans->mac_cfg; - u32 poll_ready; - int err; - - if (mac_cfg->bisr_workaround) { - /* ensure the TOP FSM isn't still in previous reset */ - mdelay(2); - } - - /* - * Set "initialization complete" bit to move adapter from - * D0U* --> D0A* (powered-up active) state. - */ - if (mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ | - CSR_GP_CNTRL_REG_FLAG_MAC_INIT); - poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; - } else { - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY; - } - - if (mac_cfg->device_family == IWL_DEVICE_FAMILY_8000) - udelay(2); - - /* - * Wait for clock stabilization; once stabilized, access to - * 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); - if (err < 0) { - IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); - - iwl_dump_host_monitor(trans); - } - - if (mac_cfg->bisr_workaround) { - /* ensure BISR shift has finished */ - udelay(200); - } - - return err < 0 ? err : 0; + return iwl_pcie_gen1_2_activate_nic(trans); } -IWL_EXPORT_SYMBOL(iwl_finish_nic_init); +IWL_EXPORT_SYMBOL(iwl_trans_activate_nic); void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, u32 sw_err_bit) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h index f4833c5fe86e..5bcec239ffc4 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); @@ -52,7 +57,7 @@ void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); void iwl_force_nmi(struct iwl_trans *trans); -int iwl_finish_nic_init(struct iwl_trans *trans); +int iwl_trans_activate_nic(struct iwl_trans *trans); /* Error handling */ int iwl_dump_fh(struct iwl_trans *trans, char **buf); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 0592f0f59d1c..23465e4c4b39 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> @@ -139,47 +140,6 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = { #define N_RATES_52 (N_RATES_24 - RATES_52_OFFS) /** - * enum iwl_nvm_channel_flags - channel flags in NVM - * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo - * @NVM_CHANNEL_IBSS: usable as an IBSS channel and deprecated - * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. - * @NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY: active scanning allowed and - * AP allowed only in 20 MHz. Valid only - * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. - * @NVM_CHANNEL_ACTIVE: active scanning allowed and allows IBSS - * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. - * @NVM_CHANNEL_RADAR: radar detection required - * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed - * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS - * on same channel on 2.4 or same UNII band on 5.2 - * @NVM_CHANNEL_UNIFORM: uniform spreading required - * @NVM_CHANNEL_20MHZ: 20 MHz channel okay - * @NVM_CHANNEL_40MHZ: 40 MHz channel okay - * @NVM_CHANNEL_80MHZ: 80 MHz channel okay - * @NVM_CHANNEL_160MHZ: 160 MHz channel okay - * @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 - */ -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), -}; - -/** * enum iwl_reg_capa_flags_v1 - global flags applied for the whole regulatory * domain. * @REG_CAPA_V1_BF_CCD_LOW_BAND: Beam-forming or Cyclic Delay Diversity in the @@ -278,30 +238,6 @@ enum iwl_reg_capa_flags_v4 { */ #define REG_CAPA_V4_RESP_VER 8 -/** - * struct iwl_reg_capa - struct for global regulatory capabilities, Used for - * handling the different APIs of reg_capa_flags. - * - * @allow_40mhz: 11n channel with a width of 40Mhz is allowed - * for this regulatory domain. - * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed - * for this regulatory domain (valid only in 5 and 6 Ghz). - * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed - * for this regulatory domain (valid only in 5 and 6 Ghz). - * @allow_320mhz: 11be channel with a width of 320Mhz is allowed - * for this regulatory domain (valid only in 6 Ghz). - * @disable_11ax: 11ax is forbidden for this regulatory domain. - * @disable_11be: 11be is forbidden for this regulatory domain. - */ -struct iwl_reg_capa { - bool allow_40mhz; - bool allow_80mhz; - bool allow_160mhz; - bool allow_320mhz; - bool disable_11ax; - bool disable_11be; -}; - static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, int chan, u32 flags) { @@ -540,16 +476,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 +602,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 +632,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 +719,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 +746,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 +848,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,51 +963,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; - if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_22000 && !is_ap) { iftype_data->vendor_elems.data = iwl_vendor_caps; @@ -1241,11 +1134,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); @@ -1627,10 +1528,10 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, } 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) +VISIBLE_IF_IWLWIFI_KUNIT +u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, + int ch_idx, u16 nvm_flags, + struct iwl_reg_capa reg_capa) { u32 flags = NL80211_RRF_NO_HT40; @@ -1685,10 +1586,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; @@ -1718,6 +1621,7 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, return flags; } +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_nvm_get_regdom_bw_flags); static struct iwl_reg_capa iwl_get_reg_capa(u32 flags, u8 resp_ver) { @@ -1815,8 +1719,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-nvm-parse.h b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h index 9ce9fa4e78fd..cbc92abf9f87 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h @@ -21,6 +21,80 @@ enum iwl_nvm_sbands_flags { IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ = BIT(1), }; +/** + * struct iwl_reg_capa - struct for global regulatory capabilities, Used for + * handling the different APIs of reg_capa_flags. + * + * @allow_40mhz: 11n channel with a width of 40Mhz is allowed + * for this regulatory domain. + * @allow_80mhz: 11ac channel with a width of 80Mhz is allowed + * for this regulatory domain (valid only in 5 and 6 Ghz). + * @allow_160mhz: 11ac channel with a width of 160Mhz is allowed + * for this regulatory domain (valid only in 5 and 6 Ghz). + * @allow_320mhz: 11be channel with a width of 320Mhz is allowed + * for this regulatory domain (valid only in 6 Ghz). + * @disable_11ax: 11ax is forbidden for this regulatory domain. + * @disable_11be: 11be is forbidden for this regulatory domain. + */ +struct iwl_reg_capa { + bool allow_40mhz; + bool allow_80mhz; + bool allow_160mhz; + bool allow_320mhz; + bool disable_11ax; + bool disable_11be; +}; + +/** + * enum iwl_nvm_channel_flags - channel flags in NVM + * @NVM_CHANNEL_VALID: channel is usable for this SKU/geo + * @NVM_CHANNEL_IBSS: usable as an IBSS channel and deprecated + * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. + * @NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY: active scanning allowed and + * AP allowed only in 20 MHz. Valid only + * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. + * @NVM_CHANNEL_ACTIVE: active scanning allowed and allows IBSS + * when %IWL_NVM_SBANDS_FLAGS_LAR enabled. + * @NVM_CHANNEL_RADAR: radar detection required + * @NVM_CHANNEL_INDOOR_ONLY: only indoor use is allowed + * @NVM_CHANNEL_GO_CONCURRENT: GO operation is allowed when connected to BSS + * on same channel on 2.4 or same UNII band on 5.2 + * @NVM_CHANNEL_UNIFORM: uniform spreading required + * @NVM_CHANNEL_20MHZ: 20 MHz channel okay + * @NVM_CHANNEL_40MHZ: 40 MHz channel okay + * @NVM_CHANNEL_80MHZ: 80 MHz channel okay + * @NVM_CHANNEL_160MHZ: 160 MHz channel okay + * @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_VLP_AP_NOT_ALLOWED = BIT(15), +}; + +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, + int ch_idx, u16 nvm_flags, + struct iwl_reg_capa reg_capa); +#endif + /* * iwl_parse_nvm_data - parse NVM data and return values * 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..5232f66c2d52 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; @@ -293,48 +293,9 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, 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 = - kmem_cache_create(trans->dev_cmd_pool_name, - txcmd_size, txcmd_align, - SLAB_HWCACHE_ALIGN, NULL); - if (!trans->dev_cmd_pool) - return -ENOMEM; - - return 0; -} - void iwl_trans_free(struct iwl_trans *trans) { cancel_delayed_work_sync(&trans->restart.wk); - kmem_cache_destroy(trans->dev_cmd_pool); } int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) @@ -345,9 +306,6 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) test_bit(STATUS_RFKILL_OPMODE, &trans->status))) return -ERFKILL; - if (unlikely(test_bit(STATUS_SUSPENDED, &trans->status))) - return -EHOSTDOWN; - if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) return -EIO; @@ -375,6 +333,19 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) } IWL_EXPORT_SYMBOL(iwl_trans_send_cmd); +struct iwl_device_tx_cmd *iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) +{ + return iwl_pcie_gen1_2_alloc_tx_cmd(trans); +} +IWL_EXPORT_SYMBOL(iwl_trans_alloc_tx_cmd); + +void iwl_trans_free_tx_cmd(struct iwl_trans *trans, + struct iwl_device_tx_cmd *dev_cmd) +{ + iwl_pcie_gen1_2_free_tx_cmd(trans, dev_cmd); +} +IWL_EXPORT_SYMBOL(iwl_trans_free_tx_cmd); + /* Comparator for struct iwl_hcmd_names. * Used in the binary search over a list of host commands. * @@ -426,7 +397,7 @@ void iwl_trans_op_mode_enter(struct iwl_trans *trans, WARN_ON_ONCE(!trans->conf.rx_mpdu_cmd); - iwl_trans_pcie_op_mode_enter(trans); + iwl_pcie_gen1_2_op_mode_enter(trans); } IWL_EXPORT_SYMBOL(iwl_trans_op_mode_enter); @@ -435,8 +406,6 @@ int iwl_trans_start_hw(struct iwl_trans *trans) might_sleep(); clear_bit(STATUS_TRANS_RESET_IN_PROGRESS, &trans->status); - /* opmode may not resume if it detects errors */ - clear_bit(STATUS_SUSPENDED, &trans->status); return iwl_trans_pcie_start_hw(trans); } @@ -446,7 +415,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 +433,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 +464,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 +489,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,35 +502,20 @@ 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) +int iwl_trans_d3_suspend(struct iwl_trans *trans, bool reset) { - int err; - might_sleep(); - err = iwl_trans_pcie_d3_suspend(trans, test, reset); - - if (!err) - set_bit(STATUS_SUSPENDED, &trans->status); - - return err; + return iwl_trans_pcie_d3_suspend(trans, reset); } IWL_EXPORT_SYMBOL(iwl_trans_d3_suspend); -int iwl_trans_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, - bool test, bool reset) +int iwl_trans_d3_resume(struct iwl_trans *trans, bool reset) { - int err; - might_sleep(); - err = iwl_trans_pcie_d3_resume(trans, status, test, reset); - - clear_bit(STATUS_SUSPENDED, &trans->status); - - return err; + return iwl_trans_pcie_d3_resume(trans, reset); } IWL_EXPORT_SYMBOL(iwl_trans_d3_resume); @@ -560,20 +523,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 +547,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 +742,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 +779,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 +793,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 +801,24 @@ 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); + +bool iwl_trans_is_pm_supported(struct iwl_trans *trans) +{ + if (WARN_ON(trans->mac_cfg->gen2)) + return false; + + return iwl_pcie_gen1_is_pm_supported(trans); +} +IWL_EXPORT_SYMBOL(iwl_trans_is_pm_supported); + +bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans) +{ + return iwl_pcie_gen1_2_is_ltr_enabled(trans); +} +IWL_EXPORT_SYMBOL(iwl_trans_is_ltr_enabled); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 012b1e44bce3..a0cc5d7745e8 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -275,16 +275,6 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) #define IWL_9000_MAX_RX_HW_QUEUES 1 /** - * enum iwl_d3_status - WoWLAN image/device status - * @IWL_D3_STATUS_ALIVE: firmware is still running after resume - * @IWL_D3_STATUS_RESET: device was reset while suspended - */ -enum iwl_d3_status { - IWL_D3_STATUS_ALIVE, - IWL_D3_STATUS_RESET, -}; - -/** * enum iwl_trans_status: transport status flags * @STATUS_SYNC_HCMD_ACTIVE: a SYNC command is being processed * @STATUS_DEVICE_ENABLED: APM is enabled @@ -294,16 +284,12 @@ enum iwl_d3_status { * @STATUS_RFKILL_OPMODE: RF-kill state reported to opmode * @STATUS_FW_ERROR: the fw is in error state * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation - * @STATUS_SUPPRESS_CMD_ERROR_ONCE: suppress "FW error in SYNC CMD" once, - * e.g. for testing * @STATUS_IN_SW_RESET: device is undergoing reset, cleared by opmode * via iwl_trans_finish_sw_reset() * @STATUS_RESET_PENDING: reset worker was scheduled, but didn't dump * the firmware state yet * @STATUS_TRANS_RESET_IN_PROGRESS: reset is still in progress, don't * attempt another reset yet - * @STATUS_SUSPENDED: device is suspended, don't send commands that - * aren't marked accordingly */ enum iwl_trans_status { STATUS_SYNC_HCMD_ACTIVE, @@ -314,11 +300,9 @@ enum iwl_trans_status { STATUS_RFKILL_OPMODE, STATUS_FW_ERROR, STATUS_TRANS_DEAD, - STATUS_SUPPRESS_CMD_ERROR_ONCE, STATUS_IN_SW_RESET, STATUS_RESET_PENDING, STATUS_TRANS_RESET_IN_PROGRESS, - STATUS_SUSPENDED, }; static inline int @@ -658,8 +642,6 @@ struct iwl_pc_data { * @restart_required: indicates debug restart is required * @last_tp_resetfw: last handling of reset during debug timepoint * @imr_data: IMR debug data allocation - * @dump_file_name_ext: dump file name extension - * @dump_file_name_ext_valid: dump file name extension if valid or not * @num_pc: number of program counter for cpu * @pc_data: details of the program counter * @yoyo_bin_loaded: tells if a yoyo debug file has been loaded @@ -698,8 +680,6 @@ struct iwl_trans_debug { bool restart_required; u32 last_tp_resetfw; struct iwl_imr_data imr_data; - u8 dump_file_name_ext[IWL_FW_INI_MAX_NAME]; - bool dump_file_name_ext_valid; u32 num_pc; struct iwl_pc_data *pc_data; bool yoyo_bin_loaded; @@ -830,7 +810,6 @@ struct iwl_txq { * @hw_rf_id: the device RF ID * @hw_cnv_id: the device CNV ID * @hw_crf_id: the device CRF ID - * @hw_wfpm_id: the device wfpm ID * @hw_id: the ID of the device / sub-device * Bits 0:15 represent the sub-device ID * Bits 16:31 represent the device ID. @@ -846,7 +825,6 @@ struct iwl_trans_info { u32 hw_rf_id; u32 hw_crf_id; u32 hw_cnv_id; - u32 hw_wfpm_id; u32 hw_id; u8 pcie_link_speed; u8 num_rxqs; @@ -866,14 +844,11 @@ struct iwl_trans_info { * @dev: pointer to struct device * that represents the device * @info: device information for use by other layers * @pnvm_loaded: indicates PNVM was loaded - * @pm_support: set to true in start_hw if link pm is supported - * @ltr_enabled: set to true if the LTR is enabled + * @suppress_cmd_error_once: suppress "FW error in SYNC CMD" once, + * e.g. for testing * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed * @reduce_power_loaded: indicates reduced power section was loaded * @failed_to_load_reduce_power_image: set to true if pnvm loading failed - * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. - * The user should use iwl_trans_{alloc,free}_tx_cmd. - * @dev_cmd_pool_name: name for the TX command allocation pool * @dbgfs_dir: iwlwifi debugfs base dir for this device * @sync_cmd_lockdep_map: lockdep map for checking sync commands * @dbg: additional debug data, see &struct iwl_trans_debug @@ -905,18 +880,13 @@ struct iwl_trans { const struct iwl_trans_info info; bool reduced_cap_sku; bool step_urm; + bool suppress_cmd_error_once; - bool pm_support; - bool ltr_enabled; u8 pnvm_loaded:1; u8 fail_to_parse_pnvm_image:1; u8 reduce_power_loaded:1; u8 failed_to_load_reduce_power_image:1; - /* The following fields are internal only */ - struct kmem_cache *dev_cmd_pool; - char dev_cmd_pool_name[50]; - struct dentry *dbgfs_dir; #ifdef CONFIG_LOCKDEP @@ -956,29 +926,21 @@ int iwl_trans_start_fw(struct iwl_trans *trans, const struct iwl_fw *fw, void iwl_trans_stop_device(struct iwl_trans *trans); -int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, bool reset); +int iwl_trans_d3_suspend(struct iwl_trans *trans, bool reset); -int iwl_trans_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, - bool test, bool reset); +int iwl_trans_d3_resume(struct iwl_trans *trans, bool reset); struct iwl_trans_dump_data * iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, const struct iwl_dump_sanitize_ops *sanitize_ops, void *sanitize_ctx); -static inline struct iwl_device_tx_cmd * -iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) -{ - return kmem_cache_zalloc(trans->dev_cmd_pool, GFP_ATOMIC); -} +struct iwl_device_tx_cmd *iwl_trans_alloc_tx_cmd(struct iwl_trans *trans); int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd); -static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans, - struct iwl_device_tx_cmd *dev_cmd) -{ - kmem_cache_free(trans->dev_cmd_pool, dev_cmd); -} +void iwl_trans_free_tx_cmd(struct iwl_trans *trans, + struct iwl_device_tx_cmd *dev_cmd); int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_device_tx_cmd *dev_cmd, int queue); @@ -1096,7 +1058,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 +1166,8 @@ 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); void iwl_trans_free(struct iwl_trans *trans); static inline bool iwl_trans_is_hw_error_value(u32 val) @@ -1229,6 +1190,30 @@ static inline u16 iwl_trans_get_num_rbds(struct iwl_trans *trans) return result; } +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); +} + +static inline bool iwl_trans_is_fw_error(struct iwl_trans *trans) +{ + return test_bit(STATUS_FW_ERROR, &trans->status); +} + +/* + * This function notifies the transport layer of firmware error, the recovery + * will be handled by the op mode + */ +static inline void iwl_trans_notify_fw_error(struct iwl_trans *trans) +{ + trans->state = IWL_TRANS_NO_FW; + set_bit(STATUS_FW_ERROR, &trans->status); +} /***************************************************** * PCIe handling *****************************************************/ @@ -1273,4 +1258,8 @@ static inline u16 iwl_trans_get_device_id(struct iwl_trans *trans) return u32_get_bits(trans->info.hw_id, GENMASK(31, 16)); } +bool iwl_trans_is_pm_supported(struct iwl_trans *trans); + +bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans); + #endif /* __iwl_trans_h__ */ 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..f985ab90d41c 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__ @@ -300,13 +300,11 @@ enum iwl_sap_msg { * @type: See &enum iwl_sap_msg. * @len: The length of the message (header not included). * @seq_num: For debug. - * @payload: The payload of the message. */ struct iwl_sap_hdr { __le16 type; __le16 len; __le32 seq_num; - u8 payload[]; }; /** @@ -340,12 +338,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 +599,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 +631,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 +641,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 +651,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 +661,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 +671,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 +749,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..1d4282a21f09 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -11,6 +11,7 @@ #include "mcc.h" #include "sta.h" #include "mlo.h" +#include "key.h" #include "fw/api/d3.h" #include "fw/api/offload.h" @@ -40,8 +41,6 @@ enum iwl_mld_d3_notif { struct iwl_mld_resume_key_iter_data { struct iwl_mld *mld; struct iwl_mld_wowlan_status *wowlan_status; - u32 num_keys, gtk_cipher, igtk_cipher, bigtk_cipher; - bool unhandled_cipher; }; struct iwl_mld_suspend_key_iter_data { @@ -71,6 +70,12 @@ struct iwl_mld_mcast_key_data { }; +struct iwl_mld_wowlan_mlo_key { + u8 key[WOWLAN_KEY_MAX_SIZE]; + u8 idx, type, link_id; + u8 pn[6]; +}; + /** * struct iwl_mld_wowlan_status - contains wowlan status data from * all wowlan notifications @@ -89,6 +94,8 @@ struct iwl_mld_mcast_key_data { * @bigtk: data of the last two used gtk's by the FW upon resume * @ptk: last seq numbers per tid passed by the FW, * holds both in tkip and aes formats + * @num_mlo_keys: number of &struct iwl_mld_wowlan_mlo_key structs + * @mlo_keys: array of MLO keys */ struct iwl_mld_wowlan_status { u32 wakeup_reasons; @@ -108,6 +115,9 @@ struct iwl_mld_wowlan_status { struct ieee80211_key_seq tkip_seq[IWL_MAX_TID_COUNT]; } ptk; + + int num_mlo_keys; + struct iwl_mld_wowlan_mlo_key mlo_keys[WOWLAN_MAX_MLO_KEYS]; }; #define NETDETECT_QUERY_BUF_LEN \ @@ -204,66 +214,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, @@ -331,7 +281,7 @@ iwl_mld_convert_gtk_resume_seq(struct iwl_mld_mcast_key_data *gtk_data, static void iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld, struct iwl_mld_wowlan_status *wowlan_status, - const struct iwl_wowlan_gtk_status_v3 *gtk_data, + const struct iwl_wowlan_gtk_status *gtk_data, const struct iwl_wowlan_all_rsc_tsc_v5 *sc) { int status_idx = 0; @@ -343,8 +293,9 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld, for (int notif_idx = 0; notif_idx < ARRAY_SIZE(wowlan_status->gtk); notif_idx++) { int rsc_idx; + u8 key_status = gtk_data[notif_idx].key_status; - if (!(gtk_data[notif_idx].key_len)) + if (!key_status) continue; wowlan_status->gtk[status_idx].len = @@ -354,10 +305,6 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld, wowlan_status->gtk[status_idx].id = wowlan_status->gtk[status_idx].flags & IWL_WOWLAN_GTK_IDX_MASK; - memcpy(wowlan_status->gtk[status_idx].key, - gtk_data[notif_idx].key, - sizeof(gtk_data[notif_idx].key)); - /* The rsc for both gtk keys are stored in gtk[0]->sc->mcast_rsc * The gtk ids can be any two numbers between 0 and 3, * the id_map maps between the key id and the index in sc->mcast @@ -367,13 +314,27 @@ iwl_mld_convert_gtk_resume_data(struct iwl_mld *mld, iwl_mld_convert_gtk_resume_seq(&wowlan_status->gtk[status_idx], sc, rsc_idx); - /* if it's as long as the TKIP encryption key, copy MIC key */ - if (wowlan_status->gtk[status_idx].len == - NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) - memcpy(wowlan_status->gtk[status_idx].key + - NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, - gtk_data[notif_idx].tkip_mic_key, - sizeof(gtk_data[notif_idx].tkip_mic_key)); + if (key_status == IWL_WOWLAN_STATUS_NEW_KEY) { + memcpy(wowlan_status->gtk[status_idx].key, + gtk_data[notif_idx].key, + sizeof(gtk_data[notif_idx].key)); + + /* if it's as long as the TKIP encryption key, + * copy MIC key + */ + if (wowlan_status->gtk[status_idx].len == + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) + memcpy(wowlan_status->gtk[status_idx].key + + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY, + gtk_data[notif_idx].tkip_mic_key, + sizeof(gtk_data[notif_idx].tkip_mic_key)); + } else { + /* If the key status is WOWLAN_STATUS_OLD_KEY, it + * indicates that no key material is present, Set the + * key length to 0 as an indication + */ + wowlan_status->gtk[status_idx].len = 0; + } status_idx++; } } @@ -420,11 +381,11 @@ static void iwl_mld_convert_igtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status, const struct iwl_wowlan_igtk_status *igtk) { - BUILD_BUG_ON(sizeof(wowlan_status->igtk.key) < sizeof(igtk->key)); - - if (!igtk->key_len) + if (!igtk->key_status) return; + BUILD_BUG_ON(sizeof(wowlan_status->igtk.key) < sizeof(igtk->key)); + wowlan_status->igtk.len = igtk->key_len; wowlan_status->igtk.flags = igtk->key_flags; wowlan_status->igtk.id = @@ -432,7 +393,15 @@ iwl_mld_convert_igtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status, IWL_WOWLAN_IGTK_BIGTK_IDX_MASK) + WOWLAN_IGTK_MIN_INDEX; - memcpy(wowlan_status->igtk.key, igtk->key, sizeof(igtk->key)); + if (igtk->key_status == IWL_WOWLAN_STATUS_NEW_KEY) + memcpy(wowlan_status->igtk.key, igtk->key, sizeof(igtk->key)); + else + /* If the key status is WOWLAN_STATUS_OLD_KEY, it indicates + * that no key material is present. Set the key length to 0 + * as an indication. + */ + wowlan_status->igtk.len = 0; + iwl_mld_convert_mcast_ipn(&wowlan_status->igtk, igtk); } @@ -446,7 +415,7 @@ iwl_mld_convert_bigtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status, for (int notif_idx = 0; notif_idx < WOWLAN_BIGTK_KEYS_NUM; notif_idx++) { - if (!bigtk[notif_idx].key_len) + if (!bigtk[notif_idx].key_status) continue; wowlan_status->bigtk[status_idx].len = bigtk[notif_idx].key_len; @@ -459,32 +428,218 @@ iwl_mld_convert_bigtk_resume_data(struct iwl_mld_wowlan_status *wowlan_status, BUILD_BUG_ON(sizeof(wowlan_status->bigtk[status_idx].key) < sizeof(bigtk[notif_idx].key)); - memcpy(wowlan_status->bigtk[status_idx].key, - bigtk[notif_idx].key, sizeof(bigtk[notif_idx].key)); + if (bigtk[notif_idx].key_status == IWL_WOWLAN_STATUS_NEW_KEY) + memcpy(wowlan_status->bigtk[status_idx].key, + bigtk[notif_idx].key, + sizeof(bigtk[notif_idx].key)); + else + /* If the key status is WOWLAN_STATUS_OLD_KEY, it + * indicates that no key material is present. Set the + * key length to 0 as an indication. + */ + wowlan_status->bigtk[status_idx].len = 0; + iwl_mld_convert_mcast_ipn(&wowlan_status->bigtk[status_idx], &bigtk[notif_idx]); status_idx++; } } +static void +iwl_mld_convert_mlo_keys(struct iwl_mld *mld, + const struct iwl_wowlan_info_notif *notif, + struct iwl_mld_wowlan_status *wowlan_status) +{ + if (!notif->num_mlo_link_keys) + return; + + wowlan_status->num_mlo_keys = notif->num_mlo_link_keys; + + if (IWL_FW_CHECK(mld, wowlan_status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, + "Too many MLO keys: %d, max %d\n", + wowlan_status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) + wowlan_status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; + + for (int i = 0; i < wowlan_status->num_mlo_keys; i++) { + const struct iwl_wowlan_mlo_gtk *fw_mlo_key = ¬if->mlo_gtks[i]; + struct iwl_mld_wowlan_mlo_key *driver_mlo_key = + &wowlan_status->mlo_keys[i]; + u16 flags = le16_to_cpu(fw_mlo_key->flags); + + driver_mlo_key->link_id = + u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK); + driver_mlo_key->type = + u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK); + driver_mlo_key->idx = + u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK); + + BUILD_BUG_ON(sizeof(driver_mlo_key->key) != sizeof(fw_mlo_key->key)); + BUILD_BUG_ON(sizeof(driver_mlo_key->pn) != sizeof(fw_mlo_key->pn)); + + memcpy(driver_mlo_key->key, fw_mlo_key->key, sizeof(fw_mlo_key->key)); + memcpy(driver_mlo_key->pn, fw_mlo_key->pn, sizeof(fw_mlo_key->pn)); + } +} + +static void +iwl_mld_convert_wowlan_notif_v5(const struct iwl_wowlan_info_notif_v5 *notif_v5, + struct iwl_wowlan_info_notif *notif) +{ + /* Convert GTK from v3 to the new format */ + BUILD_BUG_ON(ARRAY_SIZE(notif->gtk) != ARRAY_SIZE(notif_v5->gtk)); + + for (int i = 0; i < ARRAY_SIZE(notif_v5->gtk); i++) { + const struct iwl_wowlan_gtk_status_v3 *gtk_v3 = ¬if_v5->gtk[i]; + struct iwl_wowlan_gtk_status *gtk = ¬if->gtk[i]; + + /* Copy key material and metadata */ + BUILD_BUG_ON(sizeof(gtk->key) != sizeof(gtk_v3->key)); + BUILD_BUG_ON(sizeof(gtk->tkip_mic_key) != sizeof(gtk_v3->tkip_mic_key)); + + memcpy(gtk->key, gtk_v3->key, sizeof(gtk_v3->key)); + + gtk->key_len = gtk_v3->key_len; + gtk->key_flags = gtk_v3->key_flags; + + memcpy(gtk->tkip_mic_key, gtk_v3->tkip_mic_key, + sizeof(gtk_v3->tkip_mic_key)); + gtk->sc = gtk_v3->sc; + + /* Set key_status based on whether key material is present. + * in v5, a key is either invalid (should be skipped) or has + * both meta data and the key itself. + */ + if (gtk_v3->key_len) + gtk->key_status = IWL_WOWLAN_STATUS_NEW_KEY; + } + + /* Convert IGTK from v1 to the new format, only one IGTK is passed by FW */ + BUILD_BUG_ON(offsetof(struct iwl_wowlan_igtk_status, key_status) != + sizeof(struct iwl_wowlan_igtk_status_v1)); + + memcpy(¬if->igtk[0], ¬if_v5->igtk[0], + offsetof(struct iwl_wowlan_igtk_status, key_status)); + + /* Set key_status based on whether key material is present. + * in v5, a key is either invalid (should be skipped) or has + * both meta data and the key itself. + */ + if (notif_v5->igtk[0].key_len) + notif->igtk[0].key_status = IWL_WOWLAN_STATUS_NEW_KEY; + + /* Convert BIGTK from v1 to the new format */ + BUILD_BUG_ON(ARRAY_SIZE(notif->bigtk) != ARRAY_SIZE(notif_v5->bigtk)); + + for (int i = 0; i < ARRAY_SIZE(notif_v5->bigtk); i++) { + /* Copy everything until key_status */ + memcpy(¬if->bigtk[i], ¬if_v5->bigtk[i], + offsetof(struct iwl_wowlan_igtk_status, key_status)); + + /* Set key_status based on whether key material is present. + * in v5, a key is either invalid (should be skipped) or has + * both meta data and the key itself. + */ + if (notif_v5->bigtk[i].key_len) + notif->bigtk[i].key_status = IWL_WOWLAN_STATUS_NEW_KEY; + } + + notif->replay_ctr = notif_v5->replay_ctr; + notif->pattern_number = notif_v5->pattern_number; + notif->qos_seq_ctr = notif_v5->qos_seq_ctr; + notif->wakeup_reasons = notif_v5->wakeup_reasons; + notif->num_of_gtk_rekeys = notif_v5->num_of_gtk_rekeys; + notif->transmitted_ndps = notif_v5->transmitted_ndps; + notif->received_beacons = notif_v5->received_beacons; + notif->tid_tear_down = notif_v5->tid_tear_down; + notif->station_id = notif_v5->station_id; + notif->num_mlo_link_keys = notif_v5->num_mlo_link_keys; + notif->tid_offloaded_tx = notif_v5->tid_offloaded_tx; + + /* Copy MLO GTK keys */ + if (notif_v5->num_mlo_link_keys) { + memcpy(notif->mlo_gtks, notif_v5->mlo_gtks, + notif_v5->num_mlo_link_keys * sizeof(struct iwl_wowlan_mlo_gtk)); + } +} + +static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld, + u32 len, + u32 expected_len, + u8 num_mlo_keys, + int version) +{ + u32 len_with_mlo_keys; + + if (IWL_FW_CHECK(mld, len < expected_len, + "Invalid wowlan_info_notif v%d (expected=%u got=%u)\n", + version, expected_len, len)) + return false; + + len_with_mlo_keys = expected_len + + (num_mlo_keys * sizeof(struct iwl_wowlan_mlo_gtk)); + + if (IWL_FW_CHECK(mld, len < len_with_mlo_keys, + "Invalid wowlan_info_notif v%d with MLO keys (expected=%u got=%u)\n", + version, len_with_mlo_keys, len)) + return false; + + return true; +} + static bool iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld, struct iwl_mld_wowlan_status *wowlan_status, struct iwl_rx_packet *pkt) { - const struct iwl_wowlan_info_notif *notif = (void *)pkt->data; - u32 expected_len, len = iwl_rx_packet_payload_len(pkt); - - expected_len = sizeof(*notif); + const struct iwl_wowlan_info_notif *notif; + struct iwl_wowlan_info_notif *converted_notif __free(kfree) = NULL; + u32 len = iwl_rx_packet_payload_len(pkt); + int wowlan_info_ver = iwl_fw_lookup_notif_ver(mld->fw, + PROT_OFFLOAD_GROUP, + WOWLAN_INFO_NOTIFICATION, + IWL_FW_CMD_VER_UNKNOWN); + + if (wowlan_info_ver == 5) { + /* v5 format - validate before conversion */ + const struct iwl_wowlan_info_notif_v5 *notif_v5 = (void *)pkt->data; + + if (!iwl_mld_validate_wowlan_notif_size(mld, len, + sizeof(*notif_v5), + notif_v5->num_mlo_link_keys, + 5)) + return true; + + converted_notif = kzalloc(struct_size(converted_notif, + mlo_gtks, + notif_v5->num_mlo_link_keys), + GFP_ATOMIC); + if (!converted_notif) { + IWL_ERR(mld, + "Failed to allocate memory for converted wowlan_info_notif\n"); + return true; + } - if (IWL_FW_CHECK(mld, len < expected_len, - "Invalid wowlan_info_notif (expected=%ud got=%ud)\n", - expected_len, len)) + iwl_mld_convert_wowlan_notif_v5(notif_v5, + converted_notif); + notif = converted_notif; + } else if (wowlan_info_ver == 6) { + notif = (void *)pkt->data; + if (!iwl_mld_validate_wowlan_notif_size(mld, len, + sizeof(*notif), + notif->num_mlo_link_keys, + 6)) + return true; + } else { + /* smaller versions are not supported */ + IWL_WARN(mld, + "Unsupported wowlan_info_notif version %d\n", + wowlan_info_ver); return true; + } if (IWL_FW_CHECK(mld, notif->tid_offloaded_tx != IWL_WOWLAN_OFFLOAD_TID, "Invalid tid_offloaded_tx %d\n", - wowlan_status->tid_offloaded_tx)) + notif->tid_offloaded_tx)) return true; iwl_mld_convert_gtk_resume_data(mld, wowlan_status, notif->gtk, @@ -502,8 +657,10 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld, wowlan_status->num_of_gtk_rekeys = le32_to_cpu(notif->num_of_gtk_rekeys); wowlan_status->wakeup_reasons = le32_to_cpu(notif->wakeup_reasons); + + iwl_mld_convert_mlo_keys(mld, notif, wowlan_status); + return false; - /* TODO: mlo_links (task=MLO)*/ } static bool @@ -679,8 +836,8 @@ iwl_mld_set_key_rx_seq_tids(struct ieee80211_key_conf *key, } static void -iwl_mld_set_key_rx_seq(struct ieee80211_key_conf *key, - struct iwl_mld_mcast_key_data *key_data) +iwl_mld_update_mcast_rx_seq(struct ieee80211_key_conf *key, + struct iwl_mld_mcast_key_data *key_data) { switch (key->cipher) { case WLAN_CIPHER_SUITE_CCMP: @@ -707,51 +864,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, @@ -792,170 +904,143 @@ iwl_mld_resume_keys_iter(struct ieee80211_hw *hw, struct iwl_mld_wowlan_status *wowlan_status = data->wowlan_status; u8 status_idx; - /* TODO: check key link id (task=MLO) */ - if (data->unhandled_cipher) - return; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - /* ignore WEP completely, nothing to do */ - return; - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - case WLAN_CIPHER_SUITE_TKIP: + if (key->keyidx >= 0 && key->keyidx <= 3) { + /* PTK */ if (sta) { iwl_mld_update_ptk_rx_seq(data->mld, wowlan_status, sta, key, key->cipher == WLAN_CIPHER_SUITE_TKIP); - return; + /* GTK */ + } else { + status_idx = key->keyidx == wowlan_status->gtk[1].id; + iwl_mld_update_mcast_rx_seq(key, + &wowlan_status->gtk[status_idx]); } + } - if (WARN_ON(data->gtk_cipher && - data->gtk_cipher != key->cipher)) - return; + /* IGTK */ + if (key->keyidx == 4 || key->keyidx == 5) { + if (key->keyidx == wowlan_status->igtk.id) + iwl_mld_update_mcast_rx_seq(key, &wowlan_status->igtk); + } - 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]); - 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) { - if (WARN_ON(data->igtk_cipher && - data->igtk_cipher != key->cipher)) - return; - - data->igtk_cipher = key->cipher; - iwl_mld_d3_update_mcast_key(data->mld, vif, - wowlan_status, - key, &wowlan_status->igtk); - } - if (key->keyidx == 6 || key->keyidx == 7) { - if (WARN_ON(data->bigtk_cipher && - data->bigtk_cipher != key->cipher)) - return; - - 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]); - } - break; - default: - data->unhandled_cipher = true; - return; + /* BIGTK */ + if (key->keyidx == 6 || key->keyidx == 7) { + status_idx = key->keyidx == wowlan_status->bigtk[1].id; + iwl_mld_update_mcast_rx_seq(key, + &wowlan_status->bigtk[status_idx]); } - 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, - struct ieee80211_bss_conf *link_conf, - u32 cipher) + struct ieee80211_bss_conf *link_conf) { 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, - }; int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - 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) < WLAN_KEY_LEN_BIP_GMAC_128); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_BIP_GMAC_256); - BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_AES_CMAC); - BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); - if (!key_data->len) - return true; - - switch (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_TKIP: - conf.conf.keylen = WLAN_KEY_LEN_TKIP; - 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; - default: - WARN_ON(1); - } + return; - memcpy(conf.conf.key, key_data->key, conf.conf.keylen); - key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); + key_config = ieee80211_gtk_rekey_add(vif, key_data->id, key_data->key, + sizeof(key_data->key), link_id); if (IS_ERR(key_config)) - return false; + return; - iwl_mld_set_key_rx_seq(key_config, key_data); + iwl_mld_update_mcast_rx_seq(key_config, key_data); /* The FW holds only one igtk so we keep track of the valid one */ 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; + } } - return true; + + /* Also keep track of the new BIGTK */ + if (key_config->keyidx == 6 || key_config->keyidx == 7) + iwl_mld_track_bigtk(mld, vif, key_config, true); } -static bool -iwl_mld_add_all_rekeys(struct ieee80211_vif *vif, +static void +iwl_mld_add_all_rekeys(struct iwl_mld *mld, + struct ieee80211_vif *vif, struct iwl_mld_wowlan_status *wowlan_status, - struct iwl_mld_resume_key_iter_data *key_iter_data, struct ieee80211_bss_conf *link_conf) { 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, mld, &wowlan_status->gtk[i], + link_conf); + + iwl_mld_add_mcast_rekey(vif, mld, &wowlan_status->igtk, link_conf); 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, mld, &wowlan_status->bigtk[i], + link_conf); +} - return true; +static void iwl_mld_mlo_rekey(struct iwl_mld *mld, + struct iwl_mld_wowlan_status *wowlan_status, + struct ieee80211_vif *vif) +{ + struct iwl_mld_old_mlo_keys *old_keys __free(kfree) = NULL; + + IWL_DEBUG_WOWLAN(mld, "Num of MLO Keys: %d\n", wowlan_status->num_mlo_keys); + + if (!wowlan_status->num_mlo_keys) + return; + + for (int i = 0; i < wowlan_status->num_mlo_keys; i++) { + struct iwl_mld_wowlan_mlo_key *mlo_key = &wowlan_status->mlo_keys[i]; + struct ieee80211_key_conf *key; + struct ieee80211_key_seq seq; + u8 link_id = mlo_key->link_id; + + if (IWL_FW_CHECK(mld, mlo_key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS || + mlo_key->idx >= 8 || + mlo_key->type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES, + "Invalid MLO key link_id %d, idx %d, type %d\n", + mlo_key->link_id, mlo_key->idx, mlo_key->type)) + continue; + + if (!(vif->valid_links & BIT(link_id)) || + (vif->active_links & BIT(link_id))) + continue; + + IWL_DEBUG_WOWLAN(mld, "Add MLO key id %d, link id %d\n", + mlo_key->idx, link_id); + + key = ieee80211_gtk_rekey_add(vif, mlo_key->idx, mlo_key->key, + sizeof(mlo_key->key), link_id); + + if (IS_ERR(key)) + continue; + + /* + * 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 (int 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); + } } static bool @@ -978,23 +1063,19 @@ iwl_mld_update_sec_keys(struct iwl_mld *mld, ieee80211_iter_keys(mld->hw, vif, iwl_mld_resume_keys_iter, &key_iter_data); - if (key_iter_data.unhandled_cipher) - return false; - - IWL_DEBUG_WOWLAN(mld, - "Number of installed keys: %d, Number of rekeys: %d\n", - key_iter_data.num_keys, + IWL_DEBUG_WOWLAN(mld, "Number of rekeys: %d\n", wowlan_status->num_of_gtk_rekeys); - if (!key_iter_data.num_keys || !wowlan_status->num_of_gtk_rekeys) + if (!wowlan_status->num_of_gtk_rekeys) return true; - iwl_mld_add_all_rekeys(vif, wowlan_status, &key_iter_data, + iwl_mld_add_all_rekeys(mld, vif, wowlan_status, link_conf); + iwl_mld_mlo_rekey(mld, wowlan_status, vif); + ieee80211_gtk_rekey_notify(vif, link_conf->bssid, (void *)&replay_ctr, GFP_KERNEL); - /* TODO: MLO rekey (task=MLO) */ return true; } @@ -1273,7 +1354,6 @@ static int iwl_mld_wait_d3_notif(struct iwl_mld *mld, WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION) }; struct iwl_notification_wait wait_d3_notif; - enum iwl_d3_status d3_status; int ret; if (with_wowlan) @@ -1289,14 +1369,10 @@ static int iwl_mld_wait_d3_notif(struct iwl_mld *mld, iwl_mld_handle_d3_notif, resume_data); - ret = iwl_trans_d3_resume(mld->trans, &d3_status, false, false); - if (ret || d3_status != IWL_D3_STATUS_ALIVE) { - if (d3_status != IWL_D3_STATUS_ALIVE) { - IWL_INFO(mld, "Device was reset during suspend\n"); - ret = -ENOENT; - } else { - IWL_ERR(mld, "Transport resume failed\n"); - } + ret = iwl_trans_d3_resume(mld->trans, false); + if (ret) { + /* Avoid sending commands if the FW is dead */ + iwl_trans_notify_fw_error(mld->trans); iwl_remove_notification(&mld->notif_wait, &wait_d3_notif); return ret; } @@ -1317,22 +1393,24 @@ 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"); iwl_mld_low_latency_stop(mld); - /* This will happen if iwl_mld_supsend failed with FW error */ - if (mld->trans->state == IWL_TRANS_NO_FW && - test_bit(STATUS_FW_ERROR, &mld->trans->status)) - return -ENODEV; - ret = iwl_mld_update_device_power(mld, true); if (ret) { IWL_ERR(mld, "d3 suspend: couldn't send power_device %d\n", ret); - goto out; + return ret; } ret = iwl_mld_send_cmd_pdu(mld, D3_CONFIG_CMD, @@ -1340,24 +1418,20 @@ int iwl_mld_no_wowlan_suspend(struct iwl_mld *mld) if (ret) { IWL_ERR(mld, "d3 suspend: couldn't send D3_CONFIG_CMD %d\n", ret); - goto out; + return ret; } - ret = iwl_trans_d3_suspend(mld->trans, false, false); + ret = iwl_trans_d3_suspend(mld->trans, false); if (ret) { IWL_ERR(mld, "d3 suspend: trans_d3_suspend failed %d\n", ret); + /* We are going to stop the FW. Avoid sending commands in that flow */ + iwl_trans_notify_fw_error(mld->trans); } else { /* Async notification might send hcmds, which is not allowed in suspend */ iwl_mld_cancel_async_notifications(mld); mld->fw_status.in_d3 = true; } - out: - if (ret) { - mld->trans->state = IWL_TRANS_NO_FW; - set_bit(STATUS_FW_ERROR, &mld->trans->status); - } - return ret; } @@ -1376,19 +1450,13 @@ 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) + return ret; if (!ret && (resume_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE)) return -ENODEV; - if (ret) { - mld->trans->state = IWL_TRANS_NO_FW; - set_bit(STATUS_FW_ERROR, &mld->trans->status); - return ret; - } iwl_mld_low_latency_restart(mld); return iwl_mld_update_device_power(mld, false); @@ -1620,7 +1688,8 @@ static void iwl_mld_set_wowlan_config_cmd(struct iwl_mld *mld, struct cfg80211_wowlan *wowlan, struct iwl_wowlan_config_cmd *wowlan_config_cmd, - struct ieee80211_sta *ap_sta) + struct ieee80211_sta *ap_sta, + struct ieee80211_bss_conf *link) { wowlan_config_cmd->is_11n_connection = ap_sta->deflink.ht_cap.ht_supported; @@ -1630,6 +1699,9 @@ iwl_mld_set_wowlan_config_cmd(struct iwl_mld *mld, if (ap_sta->mfp) wowlan_config_cmd->flags |= IS_11W_ASSOC; + if (iwl_mld_beacon_protection_enabled(mld, link)) + wowlan_config_cmd->flags |= HAS_BEACON_PROTECTION; + if (wowlan->disconnect) wowlan_config_cmd->wakeup_filter |= cpu_to_le32(IWL_WOWLAN_WAKEUP_BEACON_MISS | @@ -1827,7 +1899,7 @@ iwl_mld_wowlan_config(struct iwl_mld *mld, struct ieee80211_vif *bss_vif, return ret; iwl_mld_set_wowlan_config_cmd(mld, wowlan, - &wowlan_config_cmd, ap_sta); + &wowlan_config_cmd, ap_sta, link_conf); ret = iwl_mld_send_cmd_pdu(mld, WOWLAN_CONFIGURATION, &wowlan_config_cmd); if (ret) @@ -1897,7 +1969,6 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) }; int link_id; int ret; - bool fw_err = false; lockdep_assert_wiphy(mld->wiphy); @@ -1909,6 +1980,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 +2000,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; @@ -1944,7 +2011,6 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) ret = iwl_mld_wait_d3_notif(mld, &resume_data, true); if (ret) { IWL_ERR(mld, "Couldn't get the d3 notifs %d\n", ret); - fw_err = true; goto err; } @@ -1981,14 +2047,11 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld) goto out; err: - if (fw_err) { - mld->trans->state = IWL_TRANS_NO_FW; - set_bit(STATUS_FW_ERROR, &mld->trans->status); - } - 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..b9c9cd3f44e4 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); + mld->trans->suppress_cmd_error_once = true; } /* 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); @@ -996,8 +1001,12 @@ void iwl_mld_add_link_debugfs(struct ieee80211_hw *hw, * If not, this is a per-link dir of a MLO vif, add in it the iwlmld * dir. */ - if (!mld_link_dir) + if (!mld_link_dir) { mld_link_dir = debugfs_create_dir("iwlmld", dir); + } else { + /* Release the reference from debugfs_lookup */ + dput(mld_link_dir); + } } static ssize_t _iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf, 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..ed379825a923 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); } @@ -113,20 +115,12 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld, static void iwl_mld_set_he_support(struct iwl_mld *mld, struct ieee80211_vif *vif, - struct iwl_mac_config_cmd *cmd, - int cmd_ver) + struct iwl_mac_config_cmd *cmd) { - if (vif->type == NL80211_IFTYPE_AP) { - if (cmd_ver == 2) - cmd->wifi_gen_v2.he_ap_support = cpu_to_le16(1); - else - cmd->wifi_gen.he_ap_support = 1; - } else { - if (cmd_ver == 2) - cmd->wifi_gen_v2.he_support = cpu_to_le16(1); - else - cmd->wifi_gen.he_support = 1; - } + if (vif->type == NL80211_IFTYPE_AP) + cmd->wifi_gen.he_ap_support = 1; + else + cmd->wifi_gen.he_support = 1; } /* fill the common part for all interface types */ @@ -138,9 +132,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld, struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); struct ieee80211_bss_conf *link_conf; unsigned int link_id; - int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, - WIDE_ID(MAC_CONF_GROUP, - MAC_CONFIG_CMD), 0); lockdep_assert_wiphy(mld->wiphy); @@ -167,11 +158,8 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld, * and enable both when we have MLO. */ if (ieee80211_vif_is_mld(vif)) { - iwl_mld_set_he_support(mld, vif, cmd, cmd_ver); - if (cmd_ver == 2) - cmd->wifi_gen_v2.eht_support = cpu_to_le32(1); - else - cmd->wifi_gen.eht_support = 1; + iwl_mld_set_he_support(mld, vif, cmd); + cmd->wifi_gen.eht_support = 1; return; } @@ -179,7 +167,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld, if (!link_conf->he_support) continue; - iwl_mld_set_he_support(mld, vif, cmd, cmd_ver); + iwl_mld_set_he_support(mld, vif, cmd); /* EHT, if supported, was already set above */ break; @@ -385,6 +373,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 +411,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); @@ -436,24 +437,21 @@ int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) return ret; } -int iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) +void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - int ret; lockdep_assert_wiphy(mld->wiphy); - ret = iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); + iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_REMOVE); if (WARN_ON(mld_vif->fw_id >= ARRAY_SIZE(mld->fw_id_to_vif))) - return -EINVAL; + return; RCU_INIT_POINTER(mld->fw_id_to_vif[mld_vif->fw_id], NULL); iwl_mld_cancel_notifications_of_object(mld, IWL_MLD_OBJECT_TYPE_VIF, mld_vif->fw_id); - - return ret; } void iwl_mld_set_vif_associated(struct iwl_mld *mld, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h index 49e2ce65557d..a3573d20f214 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; @@ -122,8 +125,6 @@ struct iwl_mld_emlsr { * @ap_sta: pointer to AP sta, for easier access to it. * Relevant only for STA vifs. * @authorized: indicates the AP station was set to authorized - * @bigtks: BIGTKs of the AP, for beacon protection. - * Only valid for STA. (FIXME: needs to be per link) * @num_associated_stas: number of associated STAs. Relevant only for AP mode. * @ap_ibss_active: whether the AP/IBSS was started * @cca_40mhz_workaround: When we are connected in 2.4 GHz and 40 MHz, and the @@ -133,6 +134,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 +147,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 */ @@ -152,7 +156,6 @@ struct iwl_mld_vif { struct iwl_mld_session_protect session_protect; struct ieee80211_sta *ap_sta; bool authorized; - struct ieee80211_key_conf __rcu *bigtks[2]; u8 num_associated_stas; bool ap_ibss_active; enum iwl_mld_cca_40mhz_wa_status cca_40mhz_workaround; @@ -161,6 +164,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 +183,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 +193,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)) @@ -212,7 +224,7 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif); int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif, u32 action); int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif); -int iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif); +void iwl_mld_rm_vif(struct iwl_mld *mld, struct ieee80211_vif *vif); void iwl_mld_set_vif_associated(struct iwl_mld *mld, struct ieee80211_vif *vif); u8 iwl_mld_get_fw_bss_vifs_ids(struct iwl_mld *mld); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.c b/drivers/net/wireless/intel/iwlwifi/mld/key.c index 0eff13e5ffd5..04192c5f07ff 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; @@ -356,3 +368,41 @@ int iwl_mld_update_sta_keys(struct iwl_mld *mld, &data); return data.err; } + +void iwl_mld_track_bigtk(struct iwl_mld *mld, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *key, bool add) +{ + struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); + struct iwl_mld_link *link; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + if (WARN_ON(key->keyidx < 6 || key->keyidx > 7)) + return; + + if (WARN_ON(key->link_id < 0)) + return; + + link = iwl_mld_link_dereference_check(mld_vif, key->link_id); + if (WARN_ON(!link)) + return; + + if (add) + rcu_assign_pointer(link->bigtks[key->keyidx - 6], key); + else + RCU_INIT_POINTER(link->bigtks[key->keyidx - 6], NULL); +} + +bool iwl_mld_beacon_protection_enabled(struct iwl_mld *mld, + struct ieee80211_bss_conf *link) +{ + struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link); + + if (WARN_ON(!mld_link)) + return false; + + return rcu_access_pointer(mld_link->bigtks[0]) || + rcu_access_pointer(mld_link->bigtks[1]); +} diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.h b/drivers/net/wireless/intel/iwlwifi/mld/key.h index a68ea48913be..5a9efdaa3b03 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/key.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/key.h @@ -36,4 +36,11 @@ iwl_mld_cleanup_keys_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, key->hw_key_idx = STA_KEY_IDX_INVALID; } +void iwl_mld_track_bigtk(struct iwl_mld *mld, + struct ieee80211_vif *vif, + struct ieee80211_key_conf *key, bool add); + +bool iwl_mld_beacon_protection_enabled(struct iwl_mld *mld, + struct ieee80211_bss_conf *link); + #endif /* __iwl_mld_key_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index d0f56189ad3f..738f80fe0c50 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,24 @@ 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); - u32 bss_param_ch_cnt_link_id; + iwl_mld_fw_id_to_link_conf(mld, fw_link_id); + struct ieee80211_bss_conf *other_link; + u32 bss_param_ch_cnt_link_id, other_link_fw_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, @@ -888,11 +551,6 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, if (WARN_ON(!vif)) return; - 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, - iwl_mld_mac80211_iftype_to_fw(vif)); - iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_POINT_MISSED_BEACONS, &tp_data); @@ -910,8 +568,11 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, if (missed_bcon_since_rx > IWL_MLD_MISSED_BEACONS_THRESHOLD) { ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC); - /* try to switch links, no-op if we don't have MLO */ - iwl_mld_int_mlo_scan(mld, vif); + /* Not in EMLSR and we can't hear the link. + * Try to switch to a better link. EMLSR case is handled below. + */ + if (!iwl_mld_emlsr_active(vif)) + iwl_mld_int_mlo_scan(mld, vif); } /* no more logic if we're not in EMLSR */ @@ -922,6 +583,17 @@ void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld, if (le32_to_cpu(notif->other_link_id) == FW_CTXT_ID_INVALID) return; + other_link_fw_id = le32_to_cpu(notif->other_link_id); + other_link = iwl_mld_fw_id_to_link_conf(mld, other_link_fw_id); + + if (IWL_FW_CHECK(mld, !other_link, "link doesn't exist for: %d\n", + other_link_fw_id)) + return; + + IWL_DEBUG_EHT(mld, + "missed bcn on the other link (link_id=%u): %u\n", + other_link->link_id, scnd_lnk_bcn_lost); + /* Exit EMLSR if we lost more than * IWL_MLD_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links * OR more than IWL_MLD_BCN_LOSS_EXIT_ESR_THRESH on current link. @@ -1212,3 +884,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..9e4da8e4de93 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.h @@ -36,25 +36,18 @@ 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 + * @bigtks: BIGTKs of the AP. Only valid for STA mode. * @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; @@ -67,24 +60,16 @@ struct iwl_mld_link { struct ieee80211_chanctx_conf __rcu *chan_ctx; bool he_ru_2mhz_block; struct ieee80211_key_conf *igtk; + struct ieee80211_key_conf __rcu *bigtks[2]; ); /* 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 +105,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 +124,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..5725104a53bf 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; } @@ -609,7 +626,7 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw, IEEE80211_VIF_SUPPORTS_CQM_RSSI; } - if (vif->p2p || iwl_fw_lookup_cmd_ver(mld->fw, PHY_CONTEXT_CMD, 0) < 5) + if (vif->p2p) vif->driver_flags |= IEEE80211_VIF_IGNORE_OFDMA_WIDER_BW; /* @@ -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; @@ -2000,13 +1966,8 @@ iwl_mld_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) iwl_fw_runtime_suspend(&mld->fwrt); ret = iwl_mld_wowlan_suspend(mld, wowlan); - if (ret) { - if (ret < 0) { - mld->trans->state = IWL_TRANS_NO_FW; - set_bit(STATUS_FW_ERROR, &mld->trans->status); - } + if (ret) return 1; - } if (iwl_mld_no_wowlan_suspend(mld)) return 1; @@ -2099,9 +2060,8 @@ static int iwl_mld_set_key_add(struct iwl_mld *mld, return -EOPNOTSUPP; } - if (vif->type == NL80211_IFTYPE_STATION && - (keyidx == 6 || keyidx == 7)) - rcu_assign_pointer(mld_vif->bigtks[keyidx - 6], key); + if (keyidx == 6 || keyidx == 7) + iwl_mld_track_bigtk(mld, vif, key, true); /* After exiting from RFKILL, hostapd configures GTK/ITGK before the * AP is started, but those keys can't be sent to the FW before the @@ -2150,9 +2110,8 @@ static void iwl_mld_set_key_remove(struct iwl_mld *mld, sta ? iwl_mld_sta_from_mac80211(sta) : NULL; int keyidx = key->keyidx; - if (vif->type == NL80211_IFTYPE_STATION && - (keyidx == 6 || keyidx == 7)) - RCU_INIT_POINTER(mld_vif->bigtks[keyidx - 6], NULL); + if (keyidx == 6 || keyidx == 7) + iwl_mld_track_bigtk(mld, vif, key, false); if (mld_sta && key->flags & IEEE80211_KEY_FLAG_PAIRWISE && (key->cipher == WLAN_CIPHER_SUITE_CCMP || @@ -2573,28 +2532,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 +2544,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 +2574,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 +2620,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 +2661,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..a6962256bdd1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -147,6 +147,7 @@ iwl_mld_construct_fw_runtime(struct iwl_mld *mld, struct iwl_trans *trans, */ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = { HCMD_NAME(UCODE_ALIVE_NTFY), + HCMD_NAME(REPLY_ERROR), HCMD_NAME(INIT_COMPLETE_NOTIF), HCMD_NAME(PHY_CONTEXT_CMD), HCMD_NAME(SCAN_CFG_CMD), @@ -158,12 +159,14 @@ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = { HCMD_NAME(LEDS_CMD), HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_NOTIFICATION), HCMD_NAME(WNM_80211V_TIMING_MEASUREMENT_CONFIRM_NOTIFICATION), + HCMD_NAME(PHY_CONFIGURATION_CMD), HCMD_NAME(SCAN_OFFLOAD_UPDATE_PROFILES_CMD), HCMD_NAME(POWER_TABLE_CMD), HCMD_NAME(PSM_UAPSD_AP_MISBEHAVING_NOTIFICATION), HCMD_NAME(BEACON_NOTIFICATION), HCMD_NAME(BEACON_TEMPLATE_CMD), HCMD_NAME(TX_ANT_CONFIGURATION_CMD), + HCMD_NAME(BT_CONFIG), HCMD_NAME(REDUCE_TX_POWER_CMD), HCMD_NAME(MISSED_BEACONS_NOTIFICATION), HCMD_NAME(MAC_PM_POWER_TABLE), @@ -251,16 +254,24 @@ 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(SEC_KEY_CMD), 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 +320,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 +369,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 +518,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 +643,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 +738,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 +763,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..241a6271d13d 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); @@ -327,38 +357,26 @@ iwl_mld_vif_iter_emlsr_mode_notif(void *data, u8 *mac, struct ieee80211_vif *vif) { const struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - enum iwl_mvm_fw_esr_recommendation action; - const struct iwl_esr_mode_notif *notif = NULL; - - if (iwl_fw_lookup_notif_ver(mld_vif->mld->fw, DATA_PATH_GROUP, - ESR_MODE_NOTIF, 0) > 1) { - notif = (void *)data; - action = le32_to_cpu(notif->action); - } else { - const struct iwl_esr_mode_notif_v1 *notif_v1 = (void *)data; - - action = le32_to_cpu(notif_v1->action); - } + const struct iwl_esr_mode_notif *notif = (void *)data; + enum iwl_mvm_fw_esr_recommendation action = le32_to_cpu(notif->action); if (!iwl_mld_vif_has_emlsr_cap(vif)) return; switch (action) { case ESR_RECOMMEND_LEAVE: - if (notif) - IWL_DEBUG_INFO(mld_vif->mld, - "FW recommend leave reason = 0x%x\n", - le32_to_cpu(notif->leave_reason_mask)); + IWL_DEBUG_INFO(mld_vif->mld, + "FW recommend leave reason = 0x%x\n", + le32_to_cpu(notif->leave_reason_mask)); iwl_mld_exit_emlsr(mld_vif->mld, vif, IWL_MLD_EMLSR_EXIT_FW_REQUEST, iwl_mld_get_primary_link(vif)); break; case ESR_FORCE_LEAVE: - if (notif) - IWL_DEBUG_INFO(mld_vif->mld, - "FW force leave reason = 0x%x\n", - le32_to_cpu(notif->leave_reason_mask)); + IWL_DEBUG_INFO(mld_vif->mld, + "FW force leave reason = 0x%x\n", + le32_to_cpu(notif->leave_reason_mask)); fallthrough; case ESR_RECOMMEND_ENTER: default: @@ -530,10 +548,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 +677,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 +691,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 < @@ -740,12 +723,6 @@ iwl_mld_set_link_sel_data(struct iwl_mld *mld, u16 max_grade = 0; unsigned long link_id; - /* - * TODO: don't select links that weren't discovered in the last scan - * This requires mac80211 (or cfg80211) changes to forward/track when - * a BSS was last updated. cfg80211 already tracks this information but - * it is not exposed within the kernel. - */ for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct ieee80211_bss_conf *link_conf = link_conf_dereference_protected(vif, link_id); @@ -1046,41 +1023,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 +1133,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..884973d0b344 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, @@ -338,7 +333,6 @@ CMD_VERSIONS(bt_coex_notif, CMD_VERSIONS(beacon_notification, CMD_VER_ENTRY(6, iwl_extended_beacon_notif)) CMD_VERSIONS(emlsr_mode_notif, - CMD_VER_ENTRY(1, iwl_esr_mode_notif_v1) CMD_VER_ENTRY(2, iwl_esr_mode_notif)) CMD_VERSIONS(emlsr_trans_fail_notif, CMD_VER_ENTRY(1, iwl_esr_trans_fail_notif)) @@ -348,9 +342,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 +359,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 +405,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 +455,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 326c300470ea..40571125b3ab 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) @@ -203,18 +163,32 @@ int iwl_mld_init_sgom(struct iwl_mld *mld) static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld) { - union iwl_ppag_table_cmd cmd = {}; - int ret, len; + struct iwl_fw_runtime *fwrt = &mld->fwrt; + union iwl_ppag_table_cmd cmd = { + .v7.ppag_config_info.table_source = fwrt->ppag_bios_source, + .v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev, + .v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags), + }; + int ret; - ret = iwl_fill_ppag_table(&mld->fwrt, &cmd, &len); - /* Not supporting PPAG table is a valid scenario */ - if (ret < 0) - return 0; + IWL_DEBUG_RADIO(fwrt, + "PPAG MODE bits going to be sent: %d\n", + fwrt->ppag_flags); + + for (int chain = 0; chain < IWL_NUM_CHAIN_LIMITS; chain++) { + for (int subband = 0; subband < IWL_NUM_SUB_BANDS_V2; subband++) { + cmd.v7.gain[chain][subband] = + fwrt->ppag_chains[chain].subbands[subband]; + IWL_DEBUG_RADIO(fwrt, + "PPAG table: chain[%d] band[%d]: gain = %d\n", + chain, subband, cmd.v7.gain[chain][subband]); + } + } IWL_DEBUG_RADIO(mld, "Sending PER_PLATFORM_ANT_GAIN_CMD\n"); ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(PHY_OPS_GROUP, PER_PLATFORM_ANT_GAIN_CMD), - &cmd, len); + &cmd, sizeof(cmd.v7)); if (ret < 0) IWL_ERR(mld, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n", ret); @@ -238,34 +212,50 @@ 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) + if (!ret) { + if (!has_raw_dsm_capa) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12; cmd.chan_state_active_bitmap = cpu_to_le32(value); + } ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value); if (!ret) 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/roc.c b/drivers/net/wireless/intel/iwlwifi/mld/roc.c index e85f45bce79a..4136c98030d0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/roc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/roc.c @@ -82,9 +82,6 @@ int iwl_mld_start_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct iwl_roc_req cmd = { .action = cpu_to_le32(FW_CTXT_ACTION_ADD), }; - u8 ver = iwl_fw_lookup_cmd_ver(mld->fw, - WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); - u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd); enum iwl_roc_activity activity; int ret = 0; @@ -140,7 +137,7 @@ int iwl_mld_start_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, memcpy(cmd.node_addr, vif->addr, ETH_ALEN); ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), - &cmd, cmd_len); + &cmd); if (ret) { IWL_ERR(mld, "Couldn't send the ROC_CMD\n"); return ret; @@ -190,9 +187,6 @@ int iwl_mld_cancel_roc(struct ieee80211_hw *hw, struct iwl_roc_req cmd = { .action = cpu_to_le32(FW_CTXT_ACTION_REMOVE), }; - u8 ver = iwl_fw_lookup_cmd_ver(mld->fw, - WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0); - u16 cmd_len = ver < 6 ? sizeof(struct iwl_roc_req_v5) : sizeof(cmd); int ret; lockdep_assert_wiphy(mld->wiphy); @@ -208,7 +202,7 @@ int iwl_mld_cancel_roc(struct ieee80211_hw *hw, cmd.activity = cpu_to_le32(mld_vif->roc_activity); ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(MAC_CONF_GROUP, ROC_CMD), - &cmd, cmd_len); + &cmd); if (ret) IWL_ERR(mld, "Couldn't send the command to cancel the ROC\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index ce0093d5c638..20d866dd92c2 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) { @@ -1549,20 +1611,21 @@ iwl_mld_rx_with_sta(struct iwl_mld *mld, struct ieee80211_hdr *hdr, return sta; } -#define KEY_IDX_LEN 2 - static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta, struct ieee80211_hdr *hdr, struct ieee80211_rx_status *rx_status, u32 mpdu_status, u32 mpdu_len) { + struct iwl_mld_link *link; struct wireless_dev *wdev; struct iwl_mld_sta *mld_sta; struct iwl_mld_vif *mld_vif; u8 keyidx; struct ieee80211_key_conf *key; const u8 *frame = (void *)hdr; + const u8 *mmie; + u8 link_id; if ((mpdu_status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_NONE) @@ -1595,21 +1658,30 @@ static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta, return 0; } + link_id = rx_status->link_valid ? rx_status->link_id : 0; + link = rcu_dereference(mld_vif->link[link_id]); + if (WARN_ON_ONCE(!link)) + return -1; + /* both keys will have the same cipher and MIC length, use * whichever one is available */ - key = rcu_dereference(mld_vif->bigtks[0]); + key = rcu_dereference(link->bigtks[0]); if (!key) { - key = rcu_dereference(mld_vif->bigtks[1]); + key = rcu_dereference(link->bigtks[1]); if (!key) goto report; } - if (mpdu_len < key->icv_len + IEEE80211_GMAC_PN_LEN + KEY_IDX_LEN) + /* get the real key ID */ + if (mpdu_len < key->icv_len) goto report; - /* get the real key ID */ - keyidx = frame[mpdu_len - key->icv_len - IEEE80211_GMAC_PN_LEN - KEY_IDX_LEN]; + mmie = frame + (mpdu_len - key->icv_len); + + /* the position of the key_id in ieee80211_mmie_16 is the same */ + keyidx = le16_to_cpu(((const struct ieee80211_mmie *) mmie)->key_id); + /* and if that's the other key, look it up */ if (keyidx != key->keyidx) { /* shouldn't happen since firmware checked, but be safe @@ -1618,7 +1690,7 @@ static int iwl_mld_rx_mgmt_prot(struct ieee80211_sta *sta, if (keyidx != 6 && keyidx != 7) return -1; - key = rcu_dereference(mld_vif->bigtks[keyidx - 6]); + key = rcu_dereference(link->bigtks[keyidx - 6]); if (!key) goto report; } @@ -1733,7 +1805,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 +1894,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 +2110,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..fd1022ddc912 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,15 @@ 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) + flags |= IWL_UMAC_SCAN_GEN_FLAGS2_COLLECT_CHANNEL_STATS; + return flags; } @@ -544,6 +557,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 +1766,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 +1823,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 +1844,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 +2044,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/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index 8fb51209b4a6..5cdbfa29a202 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -401,11 +401,9 @@ static u32 iwl_mld_get_htc_flags(struct ieee80211_link_sta *link_sta) static int iwl_mld_send_sta_cmd(struct iwl_mld *mld, const struct iwl_sta_cfg_cmd *cmd) { - u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD); - int cmd_len = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0) > 1 ? - sizeof(*cmd) : - sizeof(struct iwl_sta_cfg_cmd_v1); - int ret = iwl_mld_send_cmd_pdu(mld, cmd_id, cmd, cmd_len); + int ret = iwl_mld_send_cmd_pdu(mld, + WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), + cmd); if (ret) IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/stats.c b/drivers/net/wireless/intel/iwlwifi/mld/stats.c index f633cb1cf510..7b8709716324 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/stats.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/stats.c @@ -379,11 +379,14 @@ static void iwl_mld_update_link_sig(struct ieee80211_vif *vif, int sig, /* TODO: task=statistics handle CQM notifications */ - if (sig < IWL_MLD_LOW_RSSI_MLO_SCAN_THRESH) - iwl_mld_int_mlo_scan(mld, vif); - - if (!iwl_mld_emlsr_active(vif)) + if (!iwl_mld_emlsr_active(vif)) { + /* We're not in EMLSR and our signal is bad, + * try to switch link maybe. EMLSR will be handled below. + */ + if (sig < IWL_MLD_LOW_RSSI_MLO_SCAN_THRESH) + iwl_mld_int_mlo_scan(mld, vif); return; + } /* We are in EMLSR, check if we need to exit */ exit_emlsr_thresh = @@ -508,8 +511,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/mld/tlc.c b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c index a9ca92c0455e..0e172281b0c8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c @@ -157,9 +157,9 @@ iwl_mld_get_highest_fw_mcs(const struct ieee80211_sta_vht_cap *vht_cap, static void iwl_mld_fill_vht_rates(const struct ieee80211_link_sta *link_sta, const struct ieee80211_sta_vht_cap *vht_cap, - struct iwl_tlc_config_cmd_v4 *cmd) + struct iwl_tlc_config_cmd *cmd) { - u16 supp; + u32 supp; int i, highest_mcs; u8 max_nss = link_sta->rx_nss; struct ieee80211_vht_cap ieee_vht_cap = { @@ -182,7 +182,7 @@ iwl_mld_fill_vht_rates(const struct ieee80211_link_sta *link_sta, if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20) supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9); - cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le16(supp); + cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le32(supp); /* Check if VHT extended NSS indicates that the bandwidth/NSS * configuration is supported - only for MCS 0 since we already * decoded the MCS bits anyway ourselves. @@ -196,7 +196,7 @@ iwl_mld_fill_vht_rates(const struct ieee80211_link_sta *link_sta, } } -static u16 iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs) +static u32 iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs) { switch (mcs) { case IEEE80211_HE_MCS_SUPPORT_0_7: @@ -216,7 +216,7 @@ static u16 iwl_mld_he_mac80211_mcs_to_fw_mcs(u16 mcs) static void iwl_mld_fill_he_rates(const struct ieee80211_link_sta *link_sta, const struct ieee80211_sta_he_cap *own_he_cap, - struct iwl_tlc_config_cmd_v4 *cmd) + struct iwl_tlc_config_cmd *cmd) { const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap; u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160); @@ -245,7 +245,7 @@ iwl_mld_fill_he_rates(const struct ieee80211_link_sta *link_sta, if (_mcs_80 > _tx_mcs_80) _mcs_80 = _tx_mcs_80; cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = - cpu_to_le16(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_80)); + cpu_to_le32(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_80)); /* If one side doesn't support - mark both as not supporting */ if (_mcs_160 == IEEE80211_HE_MCS_NOT_SUPPORTED || @@ -256,19 +256,19 @@ iwl_mld_fill_he_rates(const struct ieee80211_link_sta *link_sta, if (_mcs_160 > _tx_mcs_160) _mcs_160 = _tx_mcs_160; cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_160] = - cpu_to_le16(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_160)); + cpu_to_le32(iwl_mld_he_mac80211_mcs_to_fw_mcs(_mcs_160)); } } -static void iwl_mld_set_eht_mcs(__le16 ht_rates[][3], +static void iwl_mld_set_eht_mcs(__le32 ht_rates[][3], enum IWL_TLC_MCS_PER_BW bw, - u8 max_nss, u16 mcs_msk) + u8 max_nss, u32 mcs_msk) { if (max_nss >= 2) - ht_rates[IWL_TLC_NSS_2][bw] |= cpu_to_le16(mcs_msk); + ht_rates[IWL_TLC_NSS_2][bw] |= cpu_to_le32(mcs_msk); if (max_nss >= 1) - ht_rates[IWL_TLC_NSS_1][bw] |= cpu_to_le16(mcs_msk); + ht_rates[IWL_TLC_NSS_1][bw] |= cpu_to_le32(mcs_msk); } static const @@ -307,7 +307,7 @@ iwl_mld_fill_eht_rates(struct ieee80211_vif *vif, const struct ieee80211_link_sta *link_sta, const struct ieee80211_sta_he_cap *own_he_cap, const struct ieee80211_sta_eht_cap *own_eht_cap, - struct iwl_tlc_config_cmd_v4 *cmd) + struct iwl_tlc_config_cmd *cmd) { /* peer RX mcs capa */ const struct ieee80211_eht_mcs_nss_supp *eht_rx_mcs = @@ -405,7 +405,7 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, struct ieee80211_supported_band *sband, const struct ieee80211_sta_he_cap *own_he_cap, const struct ieee80211_sta_eht_cap *own_eht_cap, - struct iwl_tlc_config_cmd_v4 *cmd) + struct iwl_tlc_config_cmd *cmd) { int i; u16 non_ht_rates = 0; @@ -435,7 +435,7 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, } else if (ht_cap->ht_supported) { cmd->mode = IWL_TLC_MNG_MODE_HT; cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_MCS_PER_BW_80] = - cpu_to_le16(ht_cap->mcs.rx_mask[0]); + cpu_to_le32(ht_cap->mcs.rx_mask[0]); /* the station support only a single receive chain */ if (link_sta->smps_mode == IEEE80211_SMPS_STATIC) @@ -443,10 +443,30 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif, 0; else cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] = - cpu_to_le16(ht_cap->mcs.rx_mask[1]); + cpu_to_le32(ht_cap->mcs.rx_mask[1]); } } +static void iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd, + struct iwl_tlc_config_cmd_v4 *cmd_v4) +{ + /* Copy everything until ht_rates */ + memcpy(cmd_v4, cmd, offsetof(struct iwl_tlc_config_cmd, ht_rates)); + + /* Convert ht_rates from __le32 to __le16 */ + BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates) != ARRAY_SIZE(cmd->ht_rates)); + BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates[0]) != ARRAY_SIZE(cmd->ht_rates[0])); + + for (int nss = 0; nss < ARRAY_SIZE(cmd->ht_rates); nss++) + for (int bw = 0; bw < ARRAY_SIZE(cmd->ht_rates[nss]); bw++) + cmd_v4->ht_rates[nss][bw] = + cpu_to_le16(le32_to_cpu(cmd->ht_rates[nss][bw])); + + /* Copy the rest */ + cmd_v4->max_mpdu_len = cmd->max_mpdu_len; + cmd_v4->max_tx_op = cmd->max_tx_op; +} + static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif, struct ieee80211_link_sta *link_sta, @@ -458,7 +478,7 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, ieee80211_get_he_iftype_cap_vif(sband, vif); const struct ieee80211_sta_eht_cap *own_eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, vif); - struct iwl_tlc_config_cmd_v4 cmd = { + struct iwl_tlc_config_cmd cmd = { /* For AP mode, use 20 MHz until the STA is authorized */ .max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ? iwl_mld_fw_bw_from_sta_bw(link_sta) : @@ -470,6 +490,11 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, .max_mpdu_len = cpu_to_le16(link_sta->agg.max_amsdu_len), }; int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); + u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0); + struct iwl_tlc_config_cmd_v4 cmd_v4; + void *cmd_ptr; + u8 cmd_size; int ret; if (fw_sta_id < 0) @@ -481,14 +506,26 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, own_he_cap, own_eht_cap, &cmd); + if (cmd_ver == 5) { + cmd_ptr = &cmd; + cmd_size = sizeof(cmd); + } else if (cmd_ver == 4) { + iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4); + cmd_ptr = &cmd_v4; + cmd_size = sizeof(cmd_v4); + } else { + IWL_ERR(mld, "Unsupported TLC config cmd version %d\n", + cmd_ver); + return; + } + IWL_DEBUG_RATE(mld, "TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n", cmd.sta_id, cmd.max_ch_width, cmd.mode); /* Send async since this can be called within a RCU-read section */ - ret = iwl_mld_send_cmd_with_flags_pdu(mld, WIDE_ID(DATA_PATH_GROUP, - TLC_MNG_CONFIG_CMD), - CMD_ASYNC, &cmd); + ret = iwl_mld_send_cmd_with_flags_pdu(mld, cmd_id, CMD_ASYNC, cmd_ptr, + cmd_size); if (ret) IWL_ERR(mld, "Failed to send TLC cmd (%d)\n", ret); } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c index 13cdc077d8d3..ca63f780140f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c @@ -253,93 +253,6 @@ static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm, swap(data->primary, data->secondary); } -/* - * This function receives the LB link id and checks if eSR should be - * enabled or disabled (due to BT coex) - */ -bool -iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - s32 link_rssi, - bool primary) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool have_wifi_loss_rate = - iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, - BT_PROFILE_NOTIFICATION, 0) > 4 || - iwl_fw_lookup_notif_ver(mvm->fw, BT_COEX_GROUP, - PROFILE_NOTIF, 0) >= 1; - u8 wifi_loss_mid_high_rssi; - u8 wifi_loss_low_rssi; - u8 wifi_loss_rate; - - if (iwl_fw_lookup_notif_ver(mvm->fw, BT_COEX_GROUP, - PROFILE_NOTIF, 0) >= 1) { - /* For now, we consider 2.4 GHz band / ANT_A only */ - wifi_loss_mid_high_rssi = - mvm->last_bt_wifi_loss.wifi_loss_mid_high_rssi[PHY_BAND_24][0]; - wifi_loss_low_rssi = - mvm->last_bt_wifi_loss.wifi_loss_low_rssi[PHY_BAND_24][0]; - } else { - wifi_loss_mid_high_rssi = mvm->last_bt_notif.wifi_loss_mid_high_rssi; - wifi_loss_low_rssi = mvm->last_bt_notif.wifi_loss_low_rssi; - } - - if (wifi_loss_low_rssi == BT_OFF) - return true; - - if (primary) - return false; - - /* The feature is not supported */ - if (!have_wifi_loss_rate) - return true; - - - /* - * In case we don't know the RSSI - take the lower wifi loss, - * so we will more likely enter eSR, and if RSSI is low - - * we will get an update on this and exit eSR. - */ - if (!link_rssi) - wifi_loss_rate = wifi_loss_mid_high_rssi; - - else if (mvmvif->esr_active) - /* RSSI needs to get really low to disable eSR... */ - wifi_loss_rate = - link_rssi <= -IWL_MVM_BT_COEX_DISABLE_ESR_THRESH ? - wifi_loss_low_rssi : - wifi_loss_mid_high_rssi; - else - /* ...And really high before we enable it back */ - wifi_loss_rate = - link_rssi <= -IWL_MVM_BT_COEX_ENABLE_ESR_THRESH ? - wifi_loss_low_rssi : - wifi_loss_mid_high_rssi; - - return wifi_loss_rate <= IWL_MVM_BT_COEX_WIFI_LOSS_THRESH; -} - -void iwl_mvm_bt_coex_update_link_esr(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - int link_id) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id]; - - if (!ieee80211_vif_is_mld(vif) || - !iwl_mvm_vif_from_mac80211(vif)->authorized || - WARN_ON(!link)) - return; - - if (!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, - (s8)link->beacon_stats.avg_signal, - link_id == iwl_mvm_get_primary_link(vif))) - /* In case we decided to exit eSR - stay with the primary */ - iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_COEX, - iwl_mvm_get_primary_link(vif)); -} - static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_bt_iterator_data *data, @@ -385,8 +298,6 @@ static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, return; } - iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id); - if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2)) min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC; else @@ -525,32 +436,6 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac, iwl_mvm_bt_notif_per_link(mvm, vif, data, link_id); } -/* must be called under rcu_read_lock */ -static void iwl_mvm_bt_coex_notif_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm *mvm = _data; - struct ieee80211_bss_conf *link_conf; - unsigned int link_id; - - lockdep_assert_held(&mvm->mutex); - - if (vif->type != NL80211_IFTYPE_STATION) - return; - - for_each_vif_active_link(vif, link_conf, link_id) { - struct ieee80211_chanctx_conf *chanctx_conf = - rcu_dereference_check(link_conf->chanctx_conf, - lockdep_is_held(&mvm->mutex)); - - if ((!chanctx_conf || - chanctx_conf->def.chan->band != NL80211_BAND_2GHZ)) - continue; - - iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id); - } -} - static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) { struct iwl_bt_iterator_data data = { @@ -654,22 +539,6 @@ void iwl_mvm_rx_bt_coex_old_notif(struct iwl_mvm *mvm, iwl_mvm_bt_coex_notif_handle(mvm); } -void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - const struct iwl_rx_packet *pkt = rxb_addr(rxb); - const struct iwl_bt_coex_profile_notif *notif = (const void *)pkt->data; - - lockdep_assert_held(&mvm->mutex); - - mvm->last_bt_wifi_loss = *notif; - - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_bt_coex_notif_iterator, - mvm); -} - void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event_data rssi_event) { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h index 776600ddaea6..17f94663c941 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/constants.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2013-2014, 2018-2024 Intel Corporation + * Copyright (C) 2013-2014, 2018-2025 Intel Corporation * Copyright (C) 2015 Intel Deutschland GmbH */ #ifndef __MVM_CONSTANTS_H @@ -11,15 +11,7 @@ #include "fw-api.h" #define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20 -#define IWL_MVM_BT_COEX_DISABLE_ESR_THRESH 69 -#define IWL_MVM_BT_COEX_ENABLE_ESR_THRESH 63 -#define IWL_MVM_BT_COEX_WIFI_LOSS_THRESH 0 #define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC 30 -#define IWL_MVM_TPT_COUNT_WINDOW_SEC 5 -#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS 5 -#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH 15 -#define IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED 11 -#define IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH -72 #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) @@ -129,14 +121,4 @@ #define IWL_MVM_MIN_BEACON_INTERVAL_TU 16 #define IWL_MVM_AUTO_EML_ENABLE true -#define IWL_MVM_HIGH_RSSI_THRESH_20MHZ -67 -#define IWL_MVM_LOW_RSSI_THRESH_20MHZ -71 -#define IWL_MVM_HIGH_RSSI_THRESH_40MHZ -64 -#define IWL_MVM_LOW_RSSI_THRESH_40MHZ -67 -#define IWL_MVM_HIGH_RSSI_THRESH_80MHZ -61 -#define IWL_MVM_LOW_RSSI_THRESH_80MHZ -74 -#define IWL_MVM_HIGH_RSSI_THRESH_160MHZ -58 -#define IWL_MVM_LOW_RSSI_THRESH_160MHZ -61 - -#define IWL_MVM_ENTER_ESR_TPT_THRESH 400 #endif /* __MVM_CONSTANTS_H */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 507c03198c92..07f1a84c274e 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; @@ -938,6 +928,10 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, if (ap_sta->mfp) wowlan_config_cmd->flags |= IS_11W_ASSOC; + if (rcu_access_pointer(mvmvif->bcn_prot.keys[0]) || + rcu_access_pointer(mvmvif->bcn_prot.keys[1])) + wowlan_config_cmd->flags |= HAS_BEACON_PROTECTION; + if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 6) { /* Query the last used seqno and set it */ int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); @@ -1248,15 +1242,14 @@ static void iwl_mvm_free_nd(struct iwl_mvm *mvm) } static int __iwl_mvm_suspend(struct ieee80211_hw *hw, - struct cfg80211_wowlan *wowlan, - bool test) + struct cfg80211_wowlan *wowlan) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct ieee80211_vif *vif = NULL; struct iwl_mvm_vif *mvmvif = NULL; struct ieee80211_sta *ap_sta = NULL; struct iwl_mvm_vif_link_info *mvm_link; - struct iwl_d3_manager_config d3_cfg_cmd_data = { + struct iwl_d3_manager_config d3_cfg_cmd = { /* * Program the minimum sleep time to 10 seconds, as many * platforms have issues processing a wakeup signal while @@ -1264,23 +1257,14 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, */ .min_sleep_time = cpu_to_le32(10 * 1000 * 1000), }; - struct iwl_host_cmd d3_cfg_cmd = { - .id = D3_CONFIG_CMD, - .flags = CMD_WANT_SKB, - .data[0] = &d3_cfg_cmd_data, - .len[0] = sizeof(d3_cfg_cmd_data), - }; int ret; int len __maybe_unused; bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); if (!wowlan) { - /* - * mac80211 shouldn't get here, but for D3 test - * it doesn't warrant a warning - */ - WARN_ON(!test); + /* mac80211 shouldn't get here */ + WARN_ON(1); return -EINVAL; } @@ -1288,10 +1272,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, if (IS_ERR_OR_NULL(vif)) return 1; - ret = iwl_mvm_block_esr_sync(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN); - if (ret) - return ret; - mutex_lock(&mvm->mutex); set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); @@ -1361,7 +1341,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, #ifdef CONFIG_IWLWIFI_DEBUGFS if (mvm->d3_wake_sysassert) - d3_cfg_cmd_data.wakeup_flags |= + d3_cfg_cmd.wakeup_flags |= cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR); #endif @@ -1374,21 +1354,14 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, iwl_fw_dbg_stop_restart_recording(&mvm->fwrt, NULL, true); /* must be last -- this switches firmware state */ - ret = iwl_mvm_send_cmd(mvm, &d3_cfg_cmd); + ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, 0, sizeof(d3_cfg_cmd), + &d3_cfg_cmd); if (ret) goto out; -#ifdef CONFIG_IWLWIFI_DEBUGFS - len = iwl_rx_packet_payload_len(d3_cfg_cmd.resp_pkt); - if (len >= sizeof(u32)) { - mvm->d3_test_pme_ptr = - le32_to_cpup((__le32 *)d3_cfg_cmd.resp_pkt->data); - } -#endif - iwl_free_resp(&d3_cfg_cmd); clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); - ret = iwl_trans_d3_suspend(mvm->trans, test, !unified_image); + ret = iwl_trans_d3_suspend(mvm->trans, !unified_image); out: if (ret < 0) { iwl_mvm_free_nd(mvm); @@ -1411,7 +1384,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) iwl_fw_runtime_suspend(&mvm->fwrt); mutex_unlock(&mvm->mutex); - return __iwl_mvm_suspend(hw, wowlan, false); + return __iwl_mvm_suspend(hw, wowlan); } struct iwl_multicast_key_data { @@ -1475,9 +1448,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 +1663,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 +1678,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 +1761,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 +1769,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); } } @@ -1824,63 +1777,8 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm *mvm; struct iwl_wowlan_status_data *status; - u32 gtk_cipher, igtk_cipher, bigtk_cipher; - bool unhandled_cipher, igtk_support, bigtk_support; - int num_keys; }; -static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - void *_data) -{ - struct iwl_mvm_d3_gtk_iter_data *data = _data; - int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - - if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id) - return; - - if (data->unhandled_cipher) - return; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - case WLAN_CIPHER_SUITE_WEP104: - /* ignore WEP completely, nothing to do */ - return; - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - case WLAN_CIPHER_SUITE_TKIP: - /* we support these */ - data->gtk_cipher = key->cipher; - 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: - /* we support these */ - if (data->igtk_support && - (key->keyidx == 4 || key->keyidx == 5)) { - data->igtk_cipher = key->cipher; - } else if (data->bigtk_support && - (key->keyidx == 6 || key->keyidx == 7)) { - data->bigtk_cipher = key->cipher; - } else { - data->unhandled_cipher = true; - return; - } - break; - default: - /* everything else - disconnect from AP */ - data->unhandled_cipher = true; - return; - } - - data->num_keys++; -} - static void iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key, struct ieee80211_key_seq *seq, u32 cipher) @@ -1906,17 +1804,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, @@ -1933,9 +1824,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id) return; - if (data->unhandled_cipher) - return; - switch (key->cipher) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: @@ -1957,18 +1845,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,218 +1870,32 @@ 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) + struct iwl_mvm *mvm) { int i, j; struct ieee80211_key_conf *key; - struct { - struct ieee80211_key_conf conf; - u8 key[32]; - } conf = { - .conf.cipher = gtk_cipher, - }; int link_id = vif->active_links ? __ffs(vif->active_links) : -1; - 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)); - - switch (gtk_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_TKIP: - conf.conf.keylen = WLAN_KEY_LEN_TKIP; - break; - default: - WARN_ON(1); - } - for (i = 0; i < ARRAY_SIZE(status->gtk); i++) { if (!status->gtk[i].len) continue; - conf.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, - sizeof(status->gtk[i].key)); - - key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); - if (IS_ERR(key)) + "Received from FW GTK: key index %d\n", + status->gtk[i].id); + + key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id, + status->gtk[i].key, + sizeof(status->gtk[i].key), + 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 || @@ -2215,58 +1912,42 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, static bool iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, - struct ieee80211_vif *vif, u32 cipher, + struct ieee80211_vif *vif, struct iwl_multicast_key_data *key_data) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); 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; + s8 keyidx = key_data->id; if (!key_data->len) return true; - iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher); - - switch (cipher) { - 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; - default: - WARN_ON(1); + key_config = ieee80211_gtk_rekey_add(vif, keyidx, key_data->key, + sizeof(key_data->key), link_id); + if (IS_ERR(key_config)) { + /* FW may send also the old keys */ + return PTR_ERR(key_config) == -EALREADY; } - BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); - memcpy(conf.conf.key, key_data->key, conf.conf.keylen); - key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); - if (IS_ERR(key_config)) - return false; + iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, key_config->cipher); 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; } @@ -2304,27 +1985,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, if (!status || !vif->bss_conf.bssid) return false; - - if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 || - iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, - WOWLAN_INFO_NOTIFICATION, - 0)) - gtkdata.igtk_support = true; - - if (iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, - WOWLAN_INFO_NOTIFICATION, - 0) >= 3) - gtkdata.bigtk_support = true; - - /* find last GTK that we used initially, if any */ - ieee80211_iter_keys(mvm->hw, vif, - iwl_mvm_d3_find_last_keys, >kdata); - /* not trying to keep connections with MFP/unhandled ciphers */ - if (gtkdata.unhandled_cipher) - return false; - if (!gtkdata.num_keys) - goto out; - /* * invalidate all other GTKs that might still exist and update * the one that we used @@ -2338,29 +1998,23 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, IWL_DEBUG_WOWLAN(mvm, "num of GTK rekeying %d\n", status->num_of_gtk_rekeys); - if (!iwl_mvm_gtk_rekey(status, vif, mvm, gtkdata.gtk_cipher)) + if (!iwl_mvm_gtk_rekey(status, vif, mvm)) return false; if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif, - gtkdata.igtk_cipher, &status->igtk)) return false; for (i = 0; i < ARRAY_SIZE(status->bigtk); i++) { if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif, - gtkdata.bigtk_cipher, &status->bigtk[i])) 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); } -out: if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, WOWLAN_GET_STATUSES, IWL_FW_CMD_VER_UNKNOWN) < 10) { @@ -2385,6 +2039,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)); @@ -2427,7 +2082,7 @@ static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, } static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, - struct iwl_wowlan_igtk_status *data) + struct iwl_wowlan_igtk_status_v1 *data) { int i; @@ -2451,7 +2106,7 @@ static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, } static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, - const struct iwl_wowlan_igtk_status *data) + const struct iwl_wowlan_igtk_status_v1 *data) { int data_idx, status_idx = 0; @@ -2482,14 +2137,15 @@ static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, } static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, - struct iwl_wowlan_info_notif *data, + struct iwl_wowlan_info_notif_v5 *data, 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 +2174,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 +2207,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 +2296,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 +2351,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 +2363,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 +2371,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", @@ -2970,7 +2573,6 @@ enum iwl_d3_notif { /* manage d3 resume data */ struct iwl_d3_data { struct iwl_wowlan_status_data *status; - bool test; u32 d3_end_flags; u32 notif_expected; /* bitmap - see &enum iwl_d3_notif */ u32 notif_received; /* bitmap - see &enum iwl_d3_notif */ @@ -3162,18 +2764,11 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm, if (mvm->net_detect) { iwl_mvm_query_netdetect_reasons(mvm, vif, d3_data); - } else { - bool keep = iwl_mvm_query_wakeup_reasons(mvm, vif, - d3_data->status); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (keep) - mvm->keep_vif = vif; -#endif - - return keep; + return false; } - return false; + + return iwl_mvm_query_wakeup_reasons(mvm, vif, + d3_data->status); } #define IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT (IWL_WOWLAN_WAKEUP_BY_MAGIC_PACKET | \ @@ -3298,44 +2893,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 { - struct iwl_wowlan_info_notif *notif = + iwl_mvm_parse_wowlan_info_notif_v3(mvm, notif, + d3_data->status, len); + } else if (wowlan_info_ver == 5) { + struct iwl_wowlan_info_notif_v5 *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; @@ -3400,10 +2981,9 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, return d3_data->notif_received == d3_data->notif_expected; } -static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test) +static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm) { int ret; - enum iwl_d3_status d3_status; struct iwl_host_cmd cmd = { .id = D0I3_END_CMD, .flags = CMD_WANT_SKB, @@ -3411,15 +2991,10 @@ static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test) bool reset = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !reset); + ret = iwl_trans_d3_resume(mvm->trans, !reset); if (ret) return ret; - if (d3_status != IWL_D3_STATUS_ALIVE) { - IWL_INFO(mvm, "Device was reset during suspend\n"); - return -ENOENT; - } - /* * We should trigger resume flow using command only for 22000 family * AX210 and above don't need the command since they have @@ -3464,7 +3039,7 @@ static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm, ARRAY_SIZE(d3_resume_notif), iwl_mvm_wait_d3_notif, d3_data); - ret = iwl_mvm_resume_firmware(mvm, d3_data->test); + ret = iwl_mvm_resume_firmware(mvm); if (ret) { iwl_remove_notification(&mvm->notif_wait, &wait_d3_notif); return ret; @@ -3484,13 +3059,12 @@ static inline bool iwl_mvm_d3_resume_notif_based(struct iwl_mvm *mvm) D3_END_NOTIFICATION, 0); } -static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) +static int __iwl_mvm_resume(struct iwl_mvm *mvm) { struct ieee80211_vif *vif = NULL; int ret = 1; struct iwl_mvm_nd_results results = {}; struct iwl_d3_data d3_data = { - .test = test, .notif_expected = IWL_D3_NOTIF_WOWLAN_INFO | IWL_D3_NOTIF_D3_END_NOTIF, @@ -3528,7 +3102,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) rt_status = iwl_mvm_check_rt_status(mvm, vif); if (rt_status != FW_ALIVE) { - set_bit(STATUS_FW_ERROR, &mvm->trans->status); + iwl_trans_notify_fw_error(mvm->trans); if (rt_status == FW_ERROR) { IWL_ERR(mvm, "FW Error occurred during suspend. Restarting.\n"); iwl_mvm_dump_nic_error_log(mvm); @@ -3555,13 +3129,11 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) if (ret) goto err; } else { - ret = iwl_mvm_resume_firmware(mvm, test); + ret = iwl_mvm_resume_firmware(mvm); if (ret < 0) goto err; } - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN); - /* when reset is required we can't send these following commands */ if (d3_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE) goto query_wakeup_reasons; @@ -3603,7 +3175,7 @@ out: kfree(d3_data.status); iwl_mvm_free_nd(mvm); - if (!d3_data.test && !mvm->net_detect) + if (!mvm->net_detect) ieee80211_iterate_active_interfaces_mtx(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_d3_disconnect_iter, @@ -3642,7 +3214,7 @@ int iwl_mvm_resume(struct ieee80211_hw *hw) struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); int ret; - ret = __iwl_mvm_resume(mvm, false); + ret = __iwl_mvm_resume(mvm); iwl_mvm_resume_tcm(mvm); @@ -3677,7 +3249,7 @@ void iwl_mvm_fast_suspend(struct iwl_mvm *mvm) IWL_ERR(mvm, "fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret); - ret = iwl_trans_d3_suspend(mvm->trans, false, false); + ret = iwl_trans_d3_suspend(mvm->trans, false); if (ret) IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret); } @@ -3700,7 +3272,7 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm) rt_status = iwl_mvm_check_rt_status(mvm, NULL); if (rt_status != FW_ALIVE) { - set_bit(STATUS_FW_ERROR, &mvm->trans->status); + iwl_trans_notify_fw_error(mvm->trans); if (rt_status == FW_ERROR) { IWL_ERR(mvm, "iwl_mvm_check_rt_status failed, device is gone during suspend\n"); @@ -3712,7 +3284,6 @@ int iwl_mvm_fast_resume(struct iwl_mvm *mvm) &iwl_dump_desc_assert, false, 0); } - mvm->trans->state = IWL_TRANS_NO_FW; ret = -ENODEV; goto out; @@ -3730,125 +3301,3 @@ out: return ret; } - -#ifdef CONFIG_IWLWIFI_DEBUGFS -static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) -{ - struct iwl_mvm *mvm = inode->i_private; - int err; - - if (mvm->d3_test_active) - return -EBUSY; - - file->private_data = inode->i_private; - - iwl_mvm_pause_tcm(mvm, true); - - iwl_fw_runtime_suspend(&mvm->fwrt); - - /* start pseudo D3 */ - rtnl_lock(); - wiphy_lock(mvm->hw->wiphy); - err = __iwl_mvm_suspend(mvm->hw, mvm->hw->wiphy->wowlan_config, true); - wiphy_unlock(mvm->hw->wiphy); - rtnl_unlock(); - if (err > 0) - err = -EINVAL; - if (err) - return err; - - mvm->d3_test_active = true; - mvm->keep_vif = NULL; - return 0; -} - -static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - unsigned long end = jiffies + 60 * HZ; - u32 pme_asserted; - - while (true) { - /* read pme_ptr if available */ - if (mvm->d3_test_pme_ptr) { - pme_asserted = iwl_trans_read_mem32(mvm->trans, - mvm->d3_test_pme_ptr); - if (pme_asserted) - break; - } - - if (msleep_interruptible(100)) - break; - - if (time_is_before_jiffies(end)) { - IWL_ERR(mvm, - "ending pseudo-D3 with timeout after ~60 seconds\n"); - return -ETIMEDOUT; - } - } - - return 0; -} - -static void iwl_mvm_d3_test_disconn_work_iter(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - /* skip the one we keep connection on */ - if (_data == vif) - return; - - if (vif->type == NL80211_IFTYPE_STATION) - ieee80211_connection_loss(vif); -} - -static int iwl_mvm_d3_test_release(struct inode *inode, struct file *file) -{ - struct iwl_mvm *mvm = inode->i_private; - bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); - - mvm->d3_test_active = false; - - iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); - - rtnl_lock(); - wiphy_lock(mvm->hw->wiphy); - __iwl_mvm_resume(mvm, true); - wiphy_unlock(mvm->hw->wiphy); - rtnl_unlock(); - - iwl_mvm_resume_tcm(mvm); - - iwl_fw_runtime_resume(&mvm->fwrt); - - iwl_abort_notification_waits(&mvm->notif_wait); - if (!unified_image) { - int remaining_time = 10; - - ieee80211_restart_hw(mvm->hw); - - /* wait for restart and disconnect all interfaces */ - while (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) && - remaining_time > 0) { - remaining_time--; - msleep(1000); - } - - if (remaining_time == 0) - IWL_ERR(mvm, "Timed out waiting for HW restart!\n"); - } - - ieee80211_iterate_active_interfaces_atomic( - mvm->hw, IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_d3_test_disconn_work_iter, mvm->keep_vif); - - return 0; -} - -const struct file_operations iwl_dbgfs_d3_test_ops = { - .open = iwl_mvm_d3_test_open, - .read = iwl_mvm_d3_test_read, - .release = iwl_mvm_d3_test_release, -}; -#endif diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c index fbe4e4a50852..a56c352a459a 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c @@ -762,96 +762,6 @@ static ssize_t iwl_dbgfs_max_tx_op_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, len); } -static ssize_t iwl_dbgfs_int_mlo_scan_write(struct ieee80211_vif *vif, - char *buf, size_t count, - loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 action; - int ret; - - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) - return -EINVAL; - - if (kstrtou32(buf, 0, &action)) - return -EINVAL; - - mutex_lock(&mvm->mutex); - - if (!action) { - ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false); - } else if (action == 1) { - ret = iwl_mvm_int_mlo_scan(mvm, vif); - } else { - ret = -EINVAL; - } - - mutex_unlock(&mvm->mutex); - - return ret ?: count; -} - -static ssize_t iwl_dbgfs_esr_disable_reason_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct ieee80211_vif *vif = file->private_data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - unsigned long esr_mask; - char *buf; - int bufsz, pos, i; - ssize_t rv; - - mutex_lock(&mvm->mutex); - esr_mask = mvmvif->esr_disable_reason; - mutex_unlock(&mvm->mutex); - - bufsz = hweight32(esr_mask) * 32 + 40; - buf = kmalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - pos = scnprintf(buf, bufsz, "EMLSR state: '0x%lx'\nreasons:\n", - esr_mask); - for_each_set_bit(i, &esr_mask, BITS_PER_LONG) - pos += scnprintf(buf + pos, bufsz - pos, " - %s\n", - iwl_get_esr_state_string(BIT(i))); - - rv = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - return rv; -} - -static ssize_t iwl_dbgfs_esr_disable_reason_write(struct ieee80211_vif *vif, - char *buf, size_t count, - loff_t *ppos) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - u32 reason; - u8 block; - int ret; - - ret = sscanf(buf, "%u %hhu", &reason, &block); - if (ret < 0) - return ret; - - if (hweight16(reason) != 1 || !(reason & IWL_MVM_BLOCK_ESR_REASONS)) - return -EINVAL; - - mutex_lock(&mvm->mutex); - if (block) - iwl_mvm_block_esr(mvm, vif, reason, - iwl_mvm_get_primary_link(vif)); - else - iwl_mvm_unblock_esr(mvm, vif, reason); - mutex_unlock(&mvm->mutex); - - return count; -} - #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -884,8 +794,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff); MVM_DEBUGFS_READ_WRITE_FILE_OPS(max_tx_op, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(int_mlo_scan, 32); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(esr_disable_reason, 32); void iwl_mvm_vif_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -916,8 +824,6 @@ void iwl_mvm_vif_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(max_tx_op, mvmvif->dbgfs_dir, 0600); debugfs_create_bool("ftm_unprotected", 0200, mvmvif->dbgfs_dir, &mvmvif->ftm_unprotected); - MVM_DEBUGFS_ADD_FILE_VIF(int_mlo_scan, mvmvif->dbgfs_dir, 0200); - MVM_DEBUGFS_ADD_FILE_VIF(esr_disable_reason, mvmvif->dbgfs_dir, 0600); if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvmvif == mvm->bf_allowed_vif) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index 86a87ea89916..683c0ba5fb39 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); + mvm->trans->suppress_cmd_error_once = true; } /* take the return value to make compiler happy - it will fail anyway */ @@ -2159,7 +2159,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) MVM_DEBUGFS_ADD_FILE(uapsd_noagg_bssids, mvm->debugfs_dir, S_IRUSR); #ifdef CONFIG_PM_SLEEP - MVM_DEBUGFS_ADD_FILE(d3_test, mvm->debugfs_dir, 0400); debugfs_create_bool("d3_wake_sysassert", 0600, mvm->debugfs_dir, &mvm->d3_wake_sysassert); debugfs_create_u32("last_netdetect_scans", 0400, mvm->debugfs_dir, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 819e3228462a..865f973f677d 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); @@ -855,7 +837,7 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE), }; - if (!mvm->trans->ltr_enabled) + if (!iwl_trans_is_ltr_enabled(mvm->trans)) return 0; return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0, @@ -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..738facceb240 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c @@ -5,65 +5,6 @@ #include "mvm.h" #include "time-event.h" -#define HANDLE_ESR_REASONS(HOW) \ - HOW(BLOCKED_PREVENTION) \ - HOW(BLOCKED_WOWLAN) \ - HOW(BLOCKED_TPT) \ - HOW(BLOCKED_FW) \ - HOW(BLOCKED_NON_BSS) \ - HOW(BLOCKED_ROC) \ - HOW(BLOCKED_TMP_NON_BSS) \ - HOW(EXIT_MISSED_BEACON) \ - HOW(EXIT_LOW_RSSI) \ - HOW(EXIT_COEX) \ - HOW(EXIT_BANDWIDTH) \ - HOW(EXIT_CSA) \ - HOW(EXIT_LINK_USAGE) \ - HOW(EXIT_FAIL_ENTRY) - -static const char *const iwl_mvm_esr_states_names[] = { -#define NAME_ENTRY(x) [ilog2(IWL_MVM_ESR_##x)] = #x, - HANDLE_ESR_REASONS(NAME_ENTRY) -}; - -const char *iwl_get_esr_state_string(enum iwl_mvm_esr_state state) -{ - int offs = ilog2(state); - - if (offs >= ARRAY_SIZE(iwl_mvm_esr_states_names) || - !iwl_mvm_esr_states_names[offs]) - return "UNKNOWN"; - - return iwl_mvm_esr_states_names[offs]; -} - -static void iwl_mvm_print_esr_state(struct iwl_mvm *mvm, u32 mask) -{ -#define NAME_FMT(x) "%s" -#define NAME_PR(x) (mask & IWL_MVM_ESR_##x) ? "[" #x "]" : "", - IWL_DEBUG_INFO(mvm, - "EMLSR state = " HANDLE_ESR_REASONS(NAME_FMT) - " (0x%x)\n", - HANDLE_ESR_REASONS(NAME_PR) - mask); -#undef NAME_FMT -#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 +21,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 +41,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. @@ -142,65 +70,6 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD); } -struct iwl_mvm_esr_iter_data { - struct ieee80211_vif *vif; - unsigned int link_id; - bool lift_block; -}; - -static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_esr_iter_data *data = _data; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - int link_id; - - if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION) - return; - - for_each_mvm_vif_valid_link(mvmvif, link_id) { - struct iwl_mvm_vif_link_info *link_info = - mvmvif->link[link_id]; - if (vif == data->vif && link_id == data->link_id) - continue; - if (link_info->active) - data->lift_block = false; - } -} - -int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - unsigned int link_id, bool active) -{ - /* An active link of a non-station vif blocks EMLSR. Upon activation - * block EMLSR on the bss vif. Upon deactivation, check if this link - * was the last non-station link active, and if so unblock the bss vif - */ - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); - struct iwl_mvm_esr_iter_data data = { - .vif = vif, - .link_id = link_id, - .lift_block = true, - }; - - if (IS_ERR_OR_NULL(bss_vif)) - return 0; - - if (active) - return iwl_mvm_block_esr_sync(mvm, bss_vif, - IWL_MVM_ESR_BLOCKED_NON_BSS); - - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_esr_vif_iterator, &data); - if (data.lift_block) { - mutex_lock(&mvm->mutex); - iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_NON_BSS); - mutex_unlock(&mvm->mutex); - } - - return 0; -} - int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, u32 changes, bool active) @@ -374,24 +243,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 +252,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; @@ -438,452 +285,6 @@ int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return ret; } -struct iwl_mvm_rssi_to_grade { - s8 rssi[2]; - u16 grade; -}; - -#define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \ - { \ - .rssi = {_lb, _hb_uhb}, \ - .grade = _grade \ - } - -/* - * This array must be sorted by increasing RSSI for proper functionality. - * The grades are actually estimated throughput, represented as fixed-point - * with a scale factor of 1/10. - */ -static const struct iwl_mvm_rssi_to_grade rssi_to_grade_map[] = { - RSSI_TO_GRADE_LINE(-85, -89, 177), - RSSI_TO_GRADE_LINE(-83, -86, 344), - RSSI_TO_GRADE_LINE(-82, -85, 516), - RSSI_TO_GRADE_LINE(-80, -83, 688), - RSSI_TO_GRADE_LINE(-77, -79, 1032), - RSSI_TO_GRADE_LINE(-73, -76, 1376), - RSSI_TO_GRADE_LINE(-70, -74, 1548), - RSSI_TO_GRADE_LINE(-69, -72, 1750), - RSSI_TO_GRADE_LINE(-65, -68, 2064), - RSSI_TO_GRADE_LINE(-61, -66, 2294), - RSSI_TO_GRADE_LINE(-58, -61, 2580), - RSSI_TO_GRADE_LINE(-55, -58, 2868), - RSSI_TO_GRADE_LINE(-46, -55, 3098), - RSSI_TO_GRADE_LINE(-43, -54, 3442) -}; - -#define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade) - -#define DEFAULT_CHAN_LOAD_LB 30 -#define DEFAULT_CHAN_LOAD_HB 15 -#define DEFAULT_CHAN_LOAD_UHB 0 - -/* Factors calculation is done with fixed-point with a scaling factor of 1/256 */ -#define SCALE_FACTOR 256 - -/* Convert a percentage from [0,100] to [0,255] */ -#define NORMALIZE_PERCENT_TO_255(percentage) ((percentage) * SCALE_FACTOR / 100) - -static unsigned int -iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf) -{ - enum nl80211_chan_width chan_width = - link_conf->chanreq.oper.width; - int mhz = nl80211_chan_width_to_mhz(chan_width); - unsigned int n_subchannels, n_punctured, puncturing_penalty; - - if (WARN_ONCE(mhz < 20 || mhz > 320, - "Invalid channel width : (%d)\n", mhz)) - return SCALE_FACTOR; - - /* No puncturing, no penalty */ - if (mhz < 80) - return SCALE_FACTOR; - - /* total number of subchannels */ - n_subchannels = mhz / 20; - /* how many of these are punctured */ - n_punctured = hweight16(link_conf->chanreq.oper.punctured); - - puncturing_penalty = n_punctured * SCALE_FACTOR / n_subchannels; - return SCALE_FACTOR - puncturing_penalty; -} - -static unsigned int -iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf) -{ - struct ieee80211_vif *vif = link_conf->vif; - struct iwl_mvm_vif_link_info *mvm_link = - iwl_mvm_vif_from_mac80211(link_conf->vif)->link[link_conf->link_id]; - const struct element *bss_load_elem; - const struct ieee80211_bss_load_elem *bss_load; - enum nl80211_band band = link_conf->chanreq.oper.chan->band; - const struct cfg80211_bss_ies *ies; - unsigned int chan_load; - u32 chan_load_by_us; - - rcu_read_lock(); - if (ieee80211_vif_link_active(vif, link_conf->link_id)) - ies = rcu_dereference(link_conf->bss->beacon_ies); - else - ies = rcu_dereference(link_conf->bss->ies); - - if (ies) - bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD, - ies->data, ies->len); - else - bss_load_elem = NULL; - - /* If there isn't BSS Load element, take the defaults */ - if (!bss_load_elem || - bss_load_elem->datalen != sizeof(*bss_load)) { - rcu_read_unlock(); - switch (band) { - case NL80211_BAND_2GHZ: - chan_load = DEFAULT_CHAN_LOAD_LB; - break; - case NL80211_BAND_5GHZ: - chan_load = DEFAULT_CHAN_LOAD_HB; - break; - case NL80211_BAND_6GHZ: - chan_load = DEFAULT_CHAN_LOAD_UHB; - break; - default: - chan_load = 0; - break; - } - /* The defaults are given in percentage */ - return NORMALIZE_PERCENT_TO_255(chan_load); - } - - bss_load = (const void *)bss_load_elem->data; - /* Channel util is in range 0-255 */ - chan_load = bss_load->channel_util; - rcu_read_unlock(); - - if (!mvm_link || !mvm_link->active) - return chan_load; - - if (WARN_ONCE(!mvm_link->phy_ctxt, - "Active link (%u) without phy ctxt assigned!\n", - link_conf->link_id)) - return chan_load; - - /* channel load by us is given in percentage */ - chan_load_by_us = - NORMALIZE_PERCENT_TO_255(mvm_link->phy_ctxt->channel_load_by_us); - - /* Use only values that firmware sends that can possibly be valid */ - if (chan_load_by_us <= chan_load) - chan_load -= chan_load_by_us; - - return chan_load; -} - -static unsigned int -iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf *link_conf) -{ - return SCALE_FACTOR - iwl_mvm_get_chan_load(link_conf); -} - -/* This function calculates the grade of a link. Returns 0 in error case */ -VISIBLE_IF_IWLWIFI_KUNIT -unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf) -{ - enum nl80211_band band; - int i, rssi_idx; - s32 link_rssi; - unsigned int grade = MAX_GRADE; - - if (WARN_ON_ONCE(!link_conf)) - return 0; - - band = link_conf->chanreq.oper.chan->band; - if (WARN_ONCE(band != NL80211_BAND_2GHZ && - band != NL80211_BAND_5GHZ && - band != NL80211_BAND_6GHZ, - "Invalid band (%u)\n", band)) - return 0; - - link_rssi = MBM_TO_DBM(link_conf->bss->signal); - /* - * For 6 GHz the RSSI of the beacons is lower than - * the RSSI of the data. - */ - if (band == NL80211_BAND_6GHZ) - link_rssi += 4; - - rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1; - - /* No valid RSSI - take the lowest grade */ - if (!link_rssi) - link_rssi = rssi_to_grade_map[0].rssi[rssi_idx]; - - /* Get grade based on RSSI */ - for (i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) { - const struct iwl_mvm_rssi_to_grade *line = - &rssi_to_grade_map[i]; - - if (link_rssi > line->rssi[rssi_idx]) - continue; - grade = line->grade; - break; - } - - /* apply the channel load and puncturing factors */ - grade = grade * iwl_mvm_get_chan_load_factor(link_conf) / SCALE_FACTOR; - grade = grade * iwl_mvm_get_puncturing_factor(link_conf) / SCALE_FACTOR; - return grade; -} -EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_get_link_grade); - -static -u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif, - struct iwl_mvm_link_sel_data *data, - unsigned long usable_links, - u8 *best_link_idx) -{ - u8 n_data = 0; - u16 max_grade = 0; - unsigned long link_id; - - /* TODO: don't select links that weren't discovered in the last scan */ - for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_bss_conf *link_conf = - link_conf_dereference_protected(vif, link_id); - - if (WARN_ON_ONCE(!link_conf)) - continue; - - data[n_data].link_id = link_id; - data[n_data].chandef = &link_conf->chanreq.oper; - data[n_data].signal = link_conf->bss->signal / 100; - data[n_data].grade = iwl_mvm_get_link_grade(link_conf); - - if (data[n_data].grade > max_grade) { - max_grade = data[n_data].grade; - *best_link_idx = n_data; - } - n_data++; - } - - return n_data; -} - -struct iwl_mvm_bw_to_rssi_threshs { - s8 low; - s8 high; -}; - -#define BW_TO_RSSI_THRESHOLDS(_bw) \ - [IWL_PHY_CHANNEL_MODE ## _bw] = { \ - .low = IWL_MVM_LOW_RSSI_THRESH_##_bw##MHZ, \ - .high = IWL_MVM_HIGH_RSSI_THRESH_##_bw##MHZ \ - } - -s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm, - const struct cfg80211_chan_def *chandef, - bool low) -{ - const struct iwl_mvm_bw_to_rssi_threshs bw_to_rssi_threshs_map[] = { - BW_TO_RSSI_THRESHOLDS(20), - BW_TO_RSSI_THRESHOLDS(40), - BW_TO_RSSI_THRESHOLDS(80), - BW_TO_RSSI_THRESHOLDS(160) - /* 320 MHz has the same thresholds as 20 MHz */ - }; - const struct iwl_mvm_bw_to_rssi_threshs *threshs; - u8 chan_width = iwl_mvm_get_channel_width(chandef); - - if (WARN_ON(chandef->chan->band != NL80211_BAND_2GHZ && - chandef->chan->band != NL80211_BAND_5GHZ && - chandef->chan->band != NL80211_BAND_6GHZ)) - return S8_MAX; - - /* 6 GHz will always use 20 MHz thresholds, regardless of the BW */ - if (chan_width == IWL_PHY_CHANNEL_MODE320) - chan_width = IWL_PHY_CHANNEL_MODE20; - - threshs = &bw_to_rssi_threshs_map[chan_width]; - - return low ? threshs->low : threshs->high; -} - -static u32 -iwl_mvm_esr_disallowed_with_link(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - const struct iwl_mvm_link_sel_data *link, - bool primary) -{ - struct wiphy *wiphy = mvm->hw->wiphy; - struct ieee80211_bss_conf *conf; - enum iwl_mvm_esr_state ret = 0; - s8 thresh; - - conf = wiphy_dereference(wiphy, vif->link_conf[link->link_id]); - if (WARN_ON_ONCE(!conf)) - return false; - - /* BT Coex effects eSR mode only if one of the links is on LB */ - if (link->chandef->chan->band == NL80211_BAND_2GHZ && - (!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, link->signal, - primary))) - ret |= IWL_MVM_ESR_EXIT_COEX; - - thresh = iwl_mvm_get_esr_rssi_thresh(mvm, link->chandef, - false); - - if (link->signal < thresh) - ret |= IWL_MVM_ESR_EXIT_LOW_RSSI; - - if (conf->csa_active) - ret |= IWL_MVM_ESR_EXIT_CSA; - - if (ret) { - IWL_DEBUG_INFO(mvm, - "Link %d is not allowed for esr\n", - link->link_id); - iwl_mvm_print_esr_state(mvm, ret); - } - return ret; -} - -VISIBLE_IF_IWLWIFI_KUNIT -bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif, - const struct iwl_mvm_link_sel_data *a, - const struct iwl_mvm_link_sel_data *b) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = mvmvif->mvm; - enum iwl_mvm_esr_state ret = 0; - - /* Per-link considerations */ - if (iwl_mvm_esr_disallowed_with_link(mvm, vif, a, true) || - iwl_mvm_esr_disallowed_with_link(mvm, vif, b, false)) - return false; - - if (a->chandef->chan->band == b->chandef->chan->band || - a->chandef->width != b->chandef->width) - ret |= IWL_MVM_ESR_EXIT_BANDWIDTH; - - if (ret) { - IWL_DEBUG_INFO(mvm, - "Links %d and %d are not a valid pair for EMLSR\n", - a->link_id, b->link_id); - iwl_mvm_print_esr_state(mvm, ret); - return false; - } - - return true; - -} -EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_mld_valid_link_pair); - -/* - * Returns the combined eSR grade of two given links. - * Returns 0 if eSR is not allowed with these 2 links. - */ -static -unsigned int iwl_mvm_get_esr_grade(struct ieee80211_vif *vif, - const struct iwl_mvm_link_sel_data *a, - const struct iwl_mvm_link_sel_data *b, - u8 *primary_id) -{ - struct ieee80211_bss_conf *primary_conf; - struct wiphy *wiphy = ieee80211_vif_to_wdev(vif)->wiphy; - unsigned int primary_load; - - lockdep_assert_wiphy(wiphy); - - /* a is always primary, b is always secondary */ - if (b->grade > a->grade) - swap(a, b); - - *primary_id = a->link_id; - - if (!iwl_mvm_mld_valid_link_pair(vif, a, b)) - return 0; - - primary_conf = wiphy_dereference(wiphy, vif->link_conf[*primary_id]); - - if (WARN_ON_ONCE(!primary_conf)) - return 0; - - primary_load = iwl_mvm_get_chan_load(primary_conf); - - return a->grade + - ((b->grade * primary_load) / SCALE_FACTOR); -} - -void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct iwl_mvm_link_sel_data data[IEEE80211_MLD_MAX_NUM_LINKS]; - struct iwl_mvm_link_sel_data *best_link; - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u32 max_active_links = iwl_mvm_max_active_links(mvm, vif); - u16 usable_links = ieee80211_vif_usable_links(vif); - u8 best, primary_link, best_in_pair, n_data; - u16 max_esr_grade = 0, new_active_links; - - lockdep_assert_wiphy(mvm->hw->wiphy); - - if (!mvmvif->authorized || !ieee80211_vif_is_mld(vif)) - return; - - if (!IWL_MVM_AUTO_EML_ENABLE) - return; - - /* The logic below is a simple version that doesn't suit more than 2 - * links - */ - WARN_ON_ONCE(max_active_links > 2); - - n_data = iwl_mvm_set_link_selection_data(vif, data, usable_links, - &best); - - if (WARN(!n_data, "Couldn't find a valid grade for any link!\n")) - return; - - best_link = &data[best]; - primary_link = best_link->link_id; - new_active_links = BIT(best_link->link_id); - - /* eSR is not supported/blocked, or only one usable link */ - if (max_active_links == 1 || !iwl_mvm_vif_has_esr_cap(mvm, vif) || - mvmvif->esr_disable_reason || n_data == 1) - goto set_active; - - for (u8 a = 0; a < n_data; a++) - for (u8 b = a + 1; b < n_data; b++) { - u16 esr_grade = iwl_mvm_get_esr_grade(vif, &data[a], - &data[b], - &best_in_pair); - - if (esr_grade <= max_esr_grade) - continue; - - max_esr_grade = esr_grade; - primary_link = best_in_pair; - new_active_links = BIT(data[a].link_id) | - BIT(data[b].link_id); - } - - /* No valid pair was found, go with the best link */ - if (hweight16(new_active_links) <= 1) - goto set_active; - - /* For equal grade - prefer EMLSR */ - if (best_link->grade > max_esr_grade) { - primary_link = best_link->link_id; - new_active_links = BIT(best_link->link_id); - } -set_active: - IWL_DEBUG_INFO(mvm, "Link selection result: 0x%x. Primary = %d\n", - new_active_links, primary_link); - ieee80211_set_active_links_async(vif, new_active_links); - mvmvif->link_selection_res = new_active_links; - mvmvif->link_selection_primary = primary_link; -} - u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -906,266 +307,6 @@ u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif) return __ffs(vif->active_links); } -/* - * For non-MLO/single link, this will return the deflink/single active link, - * respectively - */ -u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id) -{ - switch (hweight16(vif->active_links)) { - case 0: - return 0; - default: - WARN_ON(1); - fallthrough; - case 1: - return __ffs(vif->active_links); - case 2: - return __ffs(vif->active_links & ~BIT(link_id)); - } -} - -/* Reasons that can cause esr prevention */ -#define IWL_MVM_ESR_PREVENT_REASONS IWL_MVM_ESR_EXIT_MISSED_BEACON -#define IWL_MVM_PREVENT_ESR_TIMEOUT (HZ * 400) -#define IWL_MVM_ESR_PREVENT_SHORT (HZ * 300) -#define IWL_MVM_ESR_PREVENT_LONG (HZ * 600) - -static bool iwl_mvm_check_esr_prevention(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvmvif, - enum iwl_mvm_esr_state reason) -{ - bool timeout_expired = time_after(jiffies, - mvmvif->last_esr_exit.ts + - IWL_MVM_PREVENT_ESR_TIMEOUT); - unsigned long delay; - - lockdep_assert_held(&mvm->mutex); - - /* Only handle reasons that can cause prevention */ - if (!(reason & IWL_MVM_ESR_PREVENT_REASONS)) - return false; - - /* - * Reset the counter if more than 400 seconds have passed between one - * exit and the other, or if we exited due to a different reason. - * Will also reset the counter after the long prevention is done. - */ - if (timeout_expired || mvmvif->last_esr_exit.reason != reason) { - mvmvif->exit_same_reason_count = 1; - return false; - } - - mvmvif->exit_same_reason_count++; - if (WARN_ON(mvmvif->exit_same_reason_count < 2 || - mvmvif->exit_same_reason_count > 3)) - return false; - - mvmvif->esr_disable_reason |= IWL_MVM_ESR_BLOCKED_PREVENTION; - - /* - * For the second exit, use a short prevention, and for the third one, - * use a long prevention. - */ - delay = mvmvif->exit_same_reason_count == 2 ? - IWL_MVM_ESR_PREVENT_SHORT : - IWL_MVM_ESR_PREVENT_LONG; - - IWL_DEBUG_INFO(mvm, - "Preventing EMLSR for %ld seconds due to %u exits with the reason = %s (0x%x)\n", - delay / HZ, mvmvif->exit_same_reason_count, - iwl_get_esr_state_string(reason), reason); - - wiphy_delayed_work_queue(mvm->hw->wiphy, - &mvmvif->prevent_esr_done_wk, delay); - return true; -} - -#define IWL_MVM_TRIGGER_LINK_SEL_TIME (IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC * HZ) - -/* API to exit eSR mode */ -void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason, - u8 link_to_keep) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u16 new_active_links; - bool prevented; - - lockdep_assert_held(&mvm->mutex); - - if (!IWL_MVM_AUTO_EML_ENABLE) - return; - - /* Nothing to do */ - if (!mvmvif->esr_active) - return; - - if (WARN_ON(!ieee80211_vif_is_mld(vif) || !mvmvif->authorized)) - return; - - if (WARN_ON(!(vif->active_links & BIT(link_to_keep)))) - link_to_keep = __ffs(vif->active_links); - - new_active_links = BIT(link_to_keep); - IWL_DEBUG_INFO(mvm, - "Exiting EMLSR. reason = %s (0x%x). Current active links=0x%x, new active links = 0x%x\n", - iwl_get_esr_state_string(reason), reason, - vif->active_links, new_active_links); - - ieee80211_set_active_links_async(vif, new_active_links); - - /* Prevent EMLSR if needed */ - prevented = iwl_mvm_check_esr_prevention(mvm, mvmvif, reason); - - /* Remember why and when we exited EMLSR */ - mvmvif->last_esr_exit.ts = jiffies; - mvmvif->last_esr_exit.reason = reason; - - /* - * If EMLSR is prevented now - don't try to get back to EMLSR. - * If we exited due to a blocking event, we will try to get back to - * EMLSR when the corresponding unblocking event will happen. - */ - if (prevented || reason & IWL_MVM_BLOCK_ESR_REASONS) - return; - - /* If EMLSR is not blocked - try enabling it again in 30 seconds */ - wiphy_delayed_work_queue(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk, - round_jiffies_relative(IWL_MVM_TRIGGER_LINK_SEL_TIME)); -} - -void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason, - u8 link_to_keep) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - lockdep_assert_held(&mvm->mutex); - - if (!IWL_MVM_AUTO_EML_ENABLE) - return; - - /* This should be called only with disable reasons */ - if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS))) - return; - - if (mvmvif->esr_disable_reason & reason) - return; - - IWL_DEBUG_INFO(mvm, - "Blocking EMLSR mode. reason = %s (0x%x)\n", - iwl_get_esr_state_string(reason), reason); - - mvmvif->esr_disable_reason |= reason; - - iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason); - - iwl_mvm_exit_esr(mvm, vif, reason, link_to_keep); -} - -int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason) -{ - int primary_link = iwl_mvm_get_primary_link(vif); - int ret; - - if (!IWL_MVM_AUTO_EML_ENABLE || !ieee80211_vif_is_mld(vif)) - return 0; - - /* This should be called only with blocking reasons */ - if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS))) - return 0; - - /* leave ESR immediately, not only async with iwl_mvm_block_esr() */ - ret = ieee80211_set_active_links(vif, BIT(primary_link)); - if (ret) - return ret; - - mutex_lock(&mvm->mutex); - /* only additionally block for consistency and to avoid concurrency */ - iwl_mvm_block_esr(mvm, vif, reason, primary_link); - mutex_unlock(&mvm->mutex); - - return 0; -} - -static void iwl_mvm_esr_unblocked(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - bool need_new_sel = time_after(jiffies, mvmvif->last_esr_exit.ts + - IWL_MVM_TRIGGER_LINK_SEL_TIME); - - lockdep_assert_held(&mvm->mutex); - - if (!ieee80211_vif_is_mld(vif) || !mvmvif->authorized || - mvmvif->esr_active) - return; - - IWL_DEBUG_INFO(mvm, "EMLSR is unblocked\n"); - - /* If we exited due to an EXIT reason, and the exit was in less than - * 30 seconds, then a MLO scan was scheduled already. - */ - if (!need_new_sel && - !(mvmvif->last_esr_exit.reason & IWL_MVM_BLOCK_ESR_REASONS)) { - IWL_DEBUG_INFO(mvm, "Wait for MLO scan\n"); - return; - } - - /* - * If EMLSR was blocked for more than 30 seconds, or the last link - * selection decided to not enter EMLSR, trigger a new scan. - */ - if (need_new_sel || hweight16(mvmvif->link_selection_res) < 2) { - IWL_DEBUG_INFO(mvm, "Trigger MLO scan\n"); - wiphy_delayed_work_queue(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk, 0); - /* - * If EMLSR was blocked for less than 30 seconds, and the last link - * selection decided to use EMLSR, activate EMLSR using the previous - * link selection result. - */ - } else { - IWL_DEBUG_INFO(mvm, - "Use the latest link selection result: 0x%x\n", - mvmvif->link_selection_res); - ieee80211_set_active_links_async(vif, - mvmvif->link_selection_res); - } -} - -void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - lockdep_assert_held(&mvm->mutex); - - if (!IWL_MVM_AUTO_EML_ENABLE) - return; - - /* This should be called only with disable reasons */ - if (WARN_ON(!(reason & IWL_MVM_BLOCK_ESR_REASONS))) - return; - - /* No Change */ - if (!(mvmvif->esr_disable_reason & reason)) - return; - - mvmvif->esr_disable_reason &= ~reason; - - IWL_DEBUG_INFO(mvm, - "Unblocking EMLSR mode. reason = %s (0x%x)\n", - iwl_get_esr_state_string(reason), reason); - iwl_mvm_print_esr_state(mvm, mvmvif->esr_disable_reason); - - if (!mvmvif->esr_disable_reason) - iwl_mvm_esr_unblocked(mvm, vif); -} - void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link) { link->bcast_sta.sta_id = IWL_INVALID_STA; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index 9098a36530cc..9c9e0e1c6e1d 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,13 +1586,11 @@ 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; u8 notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, MISSED_BEACONS_NOTIFICATION, 0); u8 new_notif_ver = iwl_fw_lookup_notif_ver(mvm->fw, MAC_CONF_GROUP, MISSED_BEACONS_NOTIF, 0); - struct ieee80211_bss_conf *bss_conf; /* If the firmware uses the new notification (from MAC_CONF_GROUP), * refer to that notification's version. @@ -1602,20 +1600,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,6 +1607,11 @@ 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; @@ -1630,10 +1619,6 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, IWL_DEBUG_INFO(mvm, "missed beacon mac_type=%u,\n", mac_type); - mvm->trans->dbg.dump_file_name_ext_valid = true; - snprintf(mvm->trans->dbg.dump_file_name_ext, IWL_FW_INI_MAX_NAME, - "MacId_%d_MacType_%d", id, mac_type); - rx_missed_bcon = le32_to_cpu(mb->consec_missed_beacons); rx_missed_bcon_since_rx = le32_to_cpu(mb->consec_missed_beacons_since_last_rx); @@ -1651,41 +1636,11 @@ iwl_mvm_handle_missed_beacons_notif(struct iwl_mvm *mvm, "missed_beacons:%d, missed_beacons_since_rx:%d\n", rx_missed_bcon, rx_missed_bcon_since_rx); } - } else if (link_id >= 0 && hweight16(vif->active_links) > 1) { - u32 bss_param_ch_cnt_link_id = - bss_conf->bss_param_ch_cnt_link_id; - u32 scnd_lnk_bcn_lost = 0; - - if (notif_ver >= 5 && - !IWL_FW_CHECK(mvm, - le32_to_cpu(mb->other_link_id) == IWL_MVM_FW_LINK_ID_INVALID, - "No data for other link id but we are in EMLSR active_links: 0x%x\n", - vif->active_links)) - scnd_lnk_bcn_lost = - le32_to_cpu(mb->consec_missed_beacons_other_link); - - /* Exit EMLSR if we lost more than - * IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH beacons on boths links - * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH on any link. - * OR more than IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED - * and the link's bss_param_ch_count has changed. - */ - if ((rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS && - scnd_lnk_bcn_lost >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_2_LINKS) || - rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH || - (bss_param_ch_cnt_link_id != link_id && - rx_missed_bcon >= IWL_MVM_BCN_LOSS_EXIT_ESR_THRESH_BSS_PARAM_CHANGED)) - iwl_mvm_exit_esr(mvm, vif, - IWL_MVM_ESR_EXIT_MISSED_BEACON, - iwl_mvm_get_primary_link(vif)); } else if (rx_missed_bcon_since_rx > IWL_MVM_MISSED_BEACONS_THRESHOLD) { if (!iwl_mvm_has_new_tx_api(mvm)) ieee80211_beacon_loss(vif); else ieee80211_cqm_beacon_loss_notify(vif, GFP_ATOMIC); - - /* try to switch links, no-op if we don't have MLO */ - iwl_mvm_int_mlo_scan(mvm, vif); } iwl_dbg_tlv_time_point(&mvm->fwrt, @@ -1875,16 +1830,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..44029ceb8f77 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 | @@ -1420,12 +1425,6 @@ void iwl_mvm_mac_stop(struct ieee80211_hw *hw, bool suspend) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - /* Stop internal MLO scan, if running */ - mutex_lock(&mvm->mutex); - iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false); - mutex_unlock(&mvm->mutex); - - wiphy_work_cancel(mvm->hw->wiphy, &mvm->trig_link_selection_wk); wiphy_work_flush(mvm->hw->wiphy, &mvm->async_handlers_wiphy_wk); flush_work(&mvm->async_handlers_wk); flush_work(&mvm->add_stream_wk); @@ -1518,10 +1517,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); @@ -1714,57 +1709,6 @@ static int iwl_mvm_alloc_bcast_mcast_sta(struct iwl_mvm *mvm, IWL_STA_MULTICAST); } -static void iwl_mvm_prevent_esr_done_wk(struct wiphy *wiphy, - struct wiphy_work *wk) -{ - struct iwl_mvm_vif *mvmvif = - container_of(wk, struct iwl_mvm_vif, prevent_esr_done_wk.work); - struct iwl_mvm *mvm = mvmvif->mvm; - struct ieee80211_vif *vif = - container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); - - guard(mvm)(mvm); - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_PREVENTION); -} - -static void iwl_mvm_mlo_int_scan_wk(struct wiphy *wiphy, struct wiphy_work *wk) -{ - struct iwl_mvm_vif *mvmvif = container_of(wk, struct iwl_mvm_vif, - mlo_int_scan_wk.work); - struct ieee80211_vif *vif = - container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); - - guard(mvm)(mvmvif->mvm); - iwl_mvm_int_mlo_scan(mvmvif->mvm, vif); -} - -static void iwl_mvm_unblock_esr_tpt(struct wiphy *wiphy, struct wiphy_work *wk) -{ - struct iwl_mvm_vif *mvmvif = - container_of(wk, struct iwl_mvm_vif, unblock_esr_tpt_wk); - struct iwl_mvm *mvm = mvmvif->mvm; - struct ieee80211_vif *vif = - container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); - - guard(mvm)(mvm); - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT); -} - -static void iwl_mvm_unblock_esr_tmp_non_bss(struct wiphy *wiphy, - struct wiphy_work *wk) -{ - struct iwl_mvm_vif *mvmvif = - container_of(wk, struct iwl_mvm_vif, - unblock_esr_tmp_non_bss_wk.work); - struct iwl_mvm *mvm = mvmvif->mvm; - struct ieee80211_vif *vif = - container_of((void *)mvmvif, struct ieee80211_vif, drv_priv); - - mutex_lock(&mvm->mutex); - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); - mutex_unlock(&mvm->mutex); -} - void iwl_mvm_mac_init_mvmvif(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif) { lockdep_assert_held(&mvm->mutex); @@ -1772,20 +1716,10 @@ 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); - - wiphy_delayed_work_init(&mvmvif->prevent_esr_done_wk, - iwl_mvm_prevent_esr_done_wk); - - wiphy_delayed_work_init(&mvmvif->mlo_int_scan_wk, - iwl_mvm_mlo_int_scan_wk); - - wiphy_work_init(&mvmvif->unblock_esr_tpt_wk, - iwl_mvm_unblock_esr_tpt); - - wiphy_delayed_work_init(&mvmvif->unblock_esr_tmp_non_bss_wk, - iwl_mvm_unblock_esr_tmp_non_bss); } static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, @@ -1809,9 +1743,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 +1764,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 @@ -1931,16 +1857,6 @@ void iwl_mvm_prepare_mac_removal(struct iwl_mvm *mvm, flush_work(&mvm->roc_done_wk); } - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->prevent_esr_done_wk); - - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk); - - wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->unblock_esr_tmp_non_bss_wk); - cancel_delayed_work_sync(&mvmvif->csa_work); } @@ -2012,7 +1928,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 +3253,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) @@ -4014,21 +3929,6 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm, callbacks->mac_ctxt_changed(mvm, vif, false); iwl_mvm_mei_host_associated(mvm, vif, mvm_sta); - - memset(&mvmvif->last_esr_exit, 0, - sizeof(mvmvif->last_esr_exit)); - - iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_TPT, 0); - - /* Block until FW notif will arrive */ - iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_FW, 0); - - /* when client is authorized (AP station marked as such), - * try to enable the best link(s). - */ - if (vif->type == NL80211_IFTYPE_STATION && - !test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) - iwl_mvm_select_links(mvm, vif); } mvm_sta->authorized = true; @@ -4076,16 +3976,6 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm, /* disable beacon filtering */ iwl_mvm_disable_beacon_filter(mvm, vif); - - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->prevent_esr_done_wk); - - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk); - - wiphy_work_cancel(mvm->hw->wiphy, &mvmvif->unblock_esr_tpt_wk); - wiphy_delayed_work_cancel(mvm->hw->wiphy, - &mvmvif->unblock_esr_tmp_non_bss_wk); } return 0; @@ -4249,7 +4139,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 +4241,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 +4505,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); } @@ -4921,7 +4816,6 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, const struct iwl_mvm_roc_ops *ops) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); u32 lmac_id; int ret; @@ -4934,13 +4828,6 @@ int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif, */ flush_work(&mvm->roc_done_wk); - if (!IS_ERR_OR_NULL(bss_vif)) { - ret = iwl_mvm_block_esr_sync(mvm, bss_vif, - IWL_MVM_ESR_BLOCKED_ROC); - if (ret) - return ret; - } - guard(mvm)(mvm); switch (vif->type) { @@ -5605,9 +5492,9 @@ static void iwl_mvm_csa_block_txqs(void *data, struct ieee80211_sta *sta) } #define IWL_MAX_CSA_BLOCK_TX 1500 -int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) +static int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) { struct ieee80211_vif *csa_vif; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); @@ -5725,9 +5612,9 @@ int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, return ret; } -static int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) +int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 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/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c index bf24f8cb673e..b1dca76b7141 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c @@ -340,20 +340,6 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw, { struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - /* update EMLSR mode */ - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) { - int ret; - - ret = iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id, - true); - /* - * Don't activate this link if failed to exit EMLSR in - * the BSS interface - */ - if (ret) - return ret; - } - guard(mvm)(mvm); return __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false); } @@ -472,10 +458,6 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw, iwl_mvm_add_link(mvm, vif, link_conf); } mutex_unlock(&mvm->mutex); - - /* update EMLSR mode */ - if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) - iwl_mvm_esr_non_bss_link(mvm, vif, link_conf->link_id, false); } static void @@ -684,25 +666,6 @@ static int iwl_mvm_mld_mac_sta_state(struct ieee80211_hw *hw, &callbacks); } -static bool iwl_mvm_esr_bw_criteria(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf) -{ - struct ieee80211_bss_conf *other_link; - int link_id; - - /* Exit EMLSR if links don't have equal bandwidths */ - for_each_vif_active_link(vif, other_link, link_id) { - if (link_id == link_conf->link_id) - continue; - if (link_conf->chanreq.oper.width == - other_link->chanreq.oper.width) - return true; - } - - return false; -} - static void iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, struct ieee80211_vif *vif, @@ -737,14 +700,6 @@ iwl_mvm_mld_link_info_changed_station(struct iwl_mvm *mvm, link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS; } - if ((changes & BSS_CHANGED_BANDWIDTH) && - ieee80211_vif_link_active(vif, link_conf->link_id) && - mvmvif->esr_active && - !iwl_mvm_esr_bw_criteria(mvm, vif, link_conf)) - iwl_mvm_exit_esr(mvm, vif, - IWL_MVM_ESR_EXIT_BANDWIDTH, - iwl_mvm_get_primary_link(vif)); - /* if associated, maybe puncturing changed - we'll check later */ if (vif->cfg.assoc) link_changes |= LINK_CONTEXT_MODIFY_EHT_PARAMS; @@ -879,11 +834,6 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "failed to update power mode\n"); } - - if (changes & (BSS_CHANGED_MLD_VALID_LINKS | BSS_CHANGED_MLD_TTLM) && - ieee80211_vif_is_mld(vif) && mvmvif->authorized) - wiphy_delayed_work_queue(mvm->hw->wiphy, - &mvmvif->mlo_int_scan_wk, 0); } static void @@ -1239,91 +1189,6 @@ iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return NEG_TTLM_RES_ACCEPT; } -static int -iwl_mvm_mld_mac_pre_channel_switch(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - int ret; - - mutex_lock(&mvm->mutex); - if (mvmvif->esr_active) { - u8 primary = iwl_mvm_get_primary_link(vif); - int selected; - - /* prefer primary unless quiet CSA on it */ - if (chsw->link_id == primary && chsw->block_tx) - selected = iwl_mvm_get_other_link(vif, primary); - else - selected = primary; - - /* - * remembers to tell the firmware that this link can't tx - * Note that this logic seems to be unrelated to esr, but it - * really is needed only when esr is active. When we have a - * single link, the firmware will handle all this on its own. - * In multi-link scenarios, we can learn about the CSA from - * another link and this logic is too complex for the firmware - * to track. - * Since we want to de-activate the link that got a CSA, we - * need to tell the firmware not to send any frame on that link - * as the firmware may not be aware that link is under a CSA - * with mode=1 (no Tx allowed). - */ - if (chsw->block_tx && mvmvif->link[chsw->link_id]) - mvmvif->link[chsw->link_id]->csa_block_tx = true; - - iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_CSA, selected); - mutex_unlock(&mvm->mutex); - - /* - * If we've not kept the link active that's doing the CSA - * then we don't need to do anything else, just return. - */ - if (selected != chsw->link_id) - return 0; - - mutex_lock(&mvm->mutex); - } - - ret = iwl_mvm_pre_channel_switch(mvm, vif, chsw); - mutex_unlock(&mvm->mutex); - - return ret; -} - -#define IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT (5 * HZ) - -static void iwl_mvm_mld_prep_add_interface(struct ieee80211_hw *hw, - enum nl80211_iftype type) -{ - struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); - struct iwl_mvm_vif *mvmvif; - int ret; - - IWL_DEBUG_MAC80211(mvm, "prep_add_interface: type=%u\n", - type); - - if (IS_ERR_OR_NULL(bss_vif) || - !(type == NL80211_IFTYPE_AP || - type == NL80211_IFTYPE_P2P_GO || - type == NL80211_IFTYPE_P2P_CLIENT)) - return; - - mvmvif = iwl_mvm_vif_from_mac80211(bss_vif); - ret = iwl_mvm_block_esr_sync(mvm, bss_vif, - IWL_MVM_ESR_BLOCKED_TMP_NON_BSS); - if (ret) - return; - - wiphy_delayed_work_queue(mvmvif->mvm->hw->wiphy, - &mvmvif->unblock_esr_tmp_non_bss_wk, - IWL_MVM_MLD_UNBLOCK_ESR_NON_BSS_TIMEOUT); -} - const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .tx = iwl_mvm_mac_tx, .wake_tx_queue = iwl_mvm_mac_wake_tx_queue, @@ -1377,7 +1242,7 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .tx_last_beacon = iwl_mvm_tx_last_beacon, .channel_switch = iwl_mvm_channel_switch, - .pre_channel_switch = iwl_mvm_mld_mac_pre_channel_switch, + .pre_channel_switch = iwl_mvm_mac_pre_channel_switch, .post_channel_switch = iwl_mvm_post_channel_switch, .abort_channel_switch = iwl_mvm_abort_channel_switch, .channel_switch_rx_beacon = iwl_mvm_channel_switch_rx_beacon, @@ -1418,5 +1283,4 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = { .change_sta_links = iwl_mvm_mld_change_sta_links, .can_activate_links = iwl_mvm_mld_can_activate_links, .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm, - .prep_add_interface = iwl_mvm_mld_prep_add_interface, }; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c index e1010521c3ea..d9a2801636cf 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c @@ -852,8 +852,6 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta, link_id); } - kfree(mvm_sta->mpdu_counters); - mvm_sta->mpdu_counters = NULL; return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index a4f412e750d0..b515028adc8f 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,70 +344,7 @@ struct iwl_mvm_vif_link_info { u16 mgmt_queue; struct iwl_mvm_link_bf_data bf_data; -}; - -/** - * enum iwl_mvm_esr_state - defines reasons for which the EMLSR is exited or - * blocked. - * The low 16 bits are used for blocking reasons, and the 16 higher bits - * are used for exit reasons. - * For the blocking reasons - use iwl_mvm_(un)block_esr(), and for the exit - * reasons - use iwl_mvm_exit_esr(). - * - * Note: new reasons shall be added to HANDLE_ESR_REASONS as well (for logs) - * - * @IWL_MVM_ESR_BLOCKED_PREVENTION: Prevent EMLSR to avoid entering and exiting - * in a loop. - * @IWL_MVM_ESR_BLOCKED_WOWLAN: WOWLAN is preventing the enablement of EMLSR - * @IWL_MVM_ESR_BLOCKED_TPT: block EMLSR when there is not enough traffic - * @IWL_MVM_ESR_BLOCKED_FW: FW didn't recommended/forced exit from EMLSR - * @IWL_MVM_ESR_BLOCKED_NON_BSS: An active non-BSS interface's link is - * preventing EMLSR - * @IWL_MVM_ESR_BLOCKED_ROC: remain-on-channel is preventing EMLSR - * @IWL_MVM_ESR_BLOCKED_TMP_NON_BSS: An expected active non-BSS interface's link - * is preventing EMLSR. This is a temporary blocking that is set when there - * is an indication that a non-BSS interface is to be added. - * @IWL_MVM_ESR_EXIT_MISSED_BEACON: exited EMLSR due to missed beacons - * @IWL_MVM_ESR_EXIT_LOW_RSSI: link is deactivated/not allowed for EMLSR - * due to low RSSI. - * @IWL_MVM_ESR_EXIT_COEX: link is deactivated/not allowed for EMLSR - * due to BT Coex. - * @IWL_MVM_ESR_EXIT_BANDWIDTH: Bandwidths of primary and secondry links - * 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, - IWL_MVM_ESR_BLOCKED_WOWLAN = 0x2, - IWL_MVM_ESR_BLOCKED_TPT = 0x4, - IWL_MVM_ESR_BLOCKED_FW = 0x8, - IWL_MVM_ESR_BLOCKED_NON_BSS = 0x10, - IWL_MVM_ESR_BLOCKED_ROC = 0x20, - IWL_MVM_ESR_BLOCKED_TMP_NON_BSS = 0x40, - IWL_MVM_ESR_EXIT_MISSED_BEACON = 0x10000, - IWL_MVM_ESR_EXIT_LOW_RSSI = 0x20000, - IWL_MVM_ESR_EXIT_COEX = 0x40000, - 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 - -const char *iwl_get_esr_state_string(enum iwl_mvm_esr_state state); - -/** - * struct iwl_mvm_esr_exit - details of the last exit from EMLSR mode. - * @reason: The reason for the last exit from EMLSR. - * &iwl_mvm_prevent_esr_reasons. Will be 0 before exiting EMLSR. - * @ts: the time stamp of the last time we existed EMLSR. - */ -struct iwl_mvm_esr_exit { - unsigned long ts; - enum iwl_mvm_esr_state reason; + u32 average_beacon_energy; }; /** @@ -442,7 +381,6 @@ struct iwl_mvm_esr_exit { * @deflink: default link data for use in non-MLO * @link: link data for each link in MLO * @esr_active: indicates eSR mode is active - * @esr_disable_reason: a bitmap of &enum iwl_mvm_esr_state * @pm_enabled: indicates powersave is enabled * @link_selection_res: bitmap of active links as it was decided in the last * link selection. Valid only for a MLO vif after assoc. 0 if there wasn't @@ -450,15 +388,6 @@ struct iwl_mvm_esr_exit { * @link_selection_primary: primary link selected by link selection * @primary_link: primary link in eSR. Valid only for an associated MLD vif, * and in eSR mode. Valid only for a STA. - * @last_esr_exit: Details of the last exit from EMLSR. - * @exit_same_reason_count: The number of times we exited due to the specified - * @last_esr_exit::reason, only counting exits due to - * &IWL_MVM_ESR_PREVENT_REASONS. - * @prevent_esr_done_wk: work that should be done when esr prevention ends. - * @mlo_int_scan_wk: work for the internal MLO scan. - * @unblock_esr_tpt_wk: work for unblocking EMLSR when tpt is high enough. - * @unblock_esr_tmp_non_bss_wk: work for removing the - * IWL_MVM_ESR_BLOCKED_TMP_NON_BSS blocking for EMLSR. * @roc_activity: currently running ROC activity for this vif (or * ROC_NUM_ACTIVITIES if no activity is running). * @session_prot_connection_loss: the connection was lost due to session @@ -514,7 +443,6 @@ struct iwl_mvm_vif { u8 authorized:1; bool ps_disabled; - u32 esr_disable_reason; u32 ap_beacon_time; bool bf_enabled; bool ba_enabled; @@ -590,12 +518,6 @@ struct iwl_mvm_vif { u16 link_selection_res; u8 link_selection_primary; u8 primary_link; - struct iwl_mvm_esr_exit last_esr_exit; - u8 exit_same_reason_count; - struct wiphy_delayed_work prevent_esr_done_wk; - struct wiphy_delayed_work mlo_int_scan_wk; - struct wiphy_work unblock_esr_tpt_wk; - struct wiphy_delayed_work unblock_esr_tmp_non_bss_wk; struct iwl_mvm_vif_link_info deflink; struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -621,7 +543,6 @@ enum iwl_scan_status { IWL_MVM_SCAN_REGULAR = BIT(0), IWL_MVM_SCAN_SCHED = BIT(1), IWL_MVM_SCAN_NETDETECT = BIT(2), - IWL_MVM_SCAN_INT_MLO = BIT(3), IWL_MVM_SCAN_STOPPING_REGULAR = BIT(8), IWL_MVM_SCAN_STOPPING_SCHED = BIT(9), @@ -634,8 +555,6 @@ enum iwl_scan_status { IWL_MVM_SCAN_STOPPING_SCHED, IWL_MVM_SCAN_NETDETECT_MASK = IWL_MVM_SCAN_NETDETECT | IWL_MVM_SCAN_STOPPING_NETDETECT, - IWL_MVM_SCAN_INT_MLO_MASK = IWL_MVM_SCAN_INT_MLO | - IWL_MVM_SCAN_STOPPING_INT_MLO, IWL_MVM_SCAN_STOPPING_MASK = 0xff << IWL_MVM_SCAN_STOPPING_SHIFT, IWL_MVM_SCAN_MASK = 0xff, @@ -1016,8 +935,6 @@ struct iwl_mvm { /* For async rx handlers that require the wiphy lock */ struct wiphy_work async_handlers_wiphy_wk; - struct wiphy_work trig_link_selection_wk; - struct work_struct roc_done_wk; unsigned long init_status; @@ -1179,8 +1096,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 @@ -1204,20 +1119,13 @@ struct iwl_mvm { u8 offload_tid; #ifdef CONFIG_IWLWIFI_DEBUGFS bool d3_wake_sysassert; - bool d3_test_active; - u32 d3_test_pme_ptr; - struct ieee80211_vif *keep_vif; u32 last_netdetect_scans; /* no. of scans in the last net-detect wake */ #endif #endif wait_queue_head_t rx_sync_waitq; - /* BT-Coex - only one of those will be used */ - union { - struct iwl_bt_coex_prof_old_notif last_bt_notif; - struct iwl_bt_coex_profile_notif last_bt_wifi_loss; - }; + struct iwl_bt_coex_prof_old_notif last_bt_notif; struct iwl_bt_coex_ci_cmd last_bt_ci_cmd; u8 bt_tx_prio; @@ -1326,7 +1234,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 +1279,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 +1394,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 +1729,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 +1763,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 +1986,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,23 +1996,19 @@ 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, struct ieee80211_bss_conf *link_conf); -void iwl_mvm_select_links(struct iwl_mvm *mvm, struct ieee80211_vif *vif); u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif); -u8 iwl_mvm_get_other_link(struct ieee80211_vif *vif, u8 link_id); struct iwl_mvm_link_sel_data { u8 link_id; @@ -2126,14 +2018,6 @@ struct iwl_mvm_link_sel_data { }; #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) -unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf); -bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif, - const struct iwl_mvm_link_sel_data *a, - const struct iwl_mvm_link_sel_data *b); - -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 @@ -2217,7 +2101,6 @@ int iwl_mvm_scan_stop(struct iwl_mvm *mvm, int type, bool notify); int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm); void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm); void iwl_mvm_scan_timeout_wk(struct work_struct *work); -int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif); void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); @@ -2343,8 +2226,6 @@ int iwl_mvm_send_proto_offload(struct iwl_mvm *mvm, int iwl_mvm_send_bt_init_conf(struct iwl_mvm *mvm); void iwl_mvm_rx_bt_coex_old_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); -void iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb); void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, enum ieee80211_rssi_event_data); void iwl_mvm_bt_coex_vif_change(struct iwl_mvm *mvm); @@ -2866,13 +2747,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 +2789,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, @@ -2941,9 +2826,10 @@ void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, int iwl_mvm_tx_last_beacon(struct ieee80211_hw *hw); void iwl_mvm_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel_switch *chsw); -int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_channel_switch *chsw); +int iwl_mvm_mac_pre_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw); + void iwl_mvm_abort_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); @@ -3000,30 +2886,6 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm, /* EMLSR */ bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif); -void iwl_mvm_block_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason, - u8 link_to_keep); -int iwl_mvm_block_esr_sync(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason); -void iwl_mvm_unblock_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason); -void iwl_mvm_exit_esr(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - enum iwl_mvm_esr_state reason, - u8 link_to_keep); -s8 iwl_mvm_get_esr_rssi_thresh(struct iwl_mvm *mvm, - const struct cfg80211_chan_def *chandef, - bool low); -void iwl_mvm_bt_coex_update_link_esr(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - int link_id); -bool -iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - s32 link_rssi, - bool primary); -int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - unsigned int link_id, bool active); - void iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index a2dc5c3b0596..5ebd046371f5 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; } @@ -141,61 +143,6 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); } -static void iwl_mvm_rx_esr_mode_notif(struct iwl_mvm *mvm, - struct iwl_rx_cmd_buffer *rxb) -{ - struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_esr_mode_notif *notif = (void *)pkt->data; - struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm); - - /* FW recommendations is only for entering EMLSR */ - if (IS_ERR_OR_NULL(vif) || iwl_mvm_vif_from_mac80211(vif)->esr_active) - return; - - if (le32_to_cpu(notif->action) == ESR_RECOMMEND_ENTER) - iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_FW); - else - iwl_mvm_block_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_FW, - 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) { @@ -380,9 +327,6 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER(BT_PROFILE_NOTIFICATION, iwl_mvm_rx_bt_coex_old_notif, RX_HANDLER_ASYNC_LOCKED_WIPHY, struct iwl_bt_coex_prof_old_notif), - RX_HANDLER_GRP(BT_COEX_GROUP, PROFILE_NOTIF, iwl_mvm_rx_bt_coex_notif, - RX_HANDLER_ASYNC_LOCKED_WIPHY, - struct iwl_bt_coex_profile_notif), RX_HANDLER_NO_SIZE(BEACON_NOTIFICATION, iwl_mvm_rx_beacon_notif, RX_HANDLER_ASYNC_LOCKED), RX_HANDLER_NO_SIZE(STATISTICS_NOTIFICATION, iwl_mvm_rx_statistics, @@ -492,11 +436,6 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { RX_HANDLER_ASYNC_UNLOCKED, struct iwl_channel_switch_error_notif), - RX_HANDLER_GRP(DATA_PATH_GROUP, ESR_MODE_NOTIF, - iwl_mvm_rx_esr_mode_notif, - RX_HANDLER_ASYNC_LOCKED_WIPHY, - struct iwl_esr_mode_notif), - RX_HANDLER_GRP(DATA_PATH_GROUP, MONITOR_NOTIF, iwl_mvm_rx_monitor_notif, RX_HANDLER_ASYNC_LOCKED, struct iwl_datapath_monitor_notif), @@ -524,10 +463,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 +598,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), @@ -696,9 +635,9 @@ static const struct iwl_hcmd_names iwl_mvm_data_path_names[] = { HCMD_NAME(CHEST_COLLECTOR_FILTER_CONFIG_CMD), HCMD_NAME(SCD_QUEUE_CONFIG_CMD), HCMD_NAME(SEC_KEY_CMD), - 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), @@ -1254,29 +1193,6 @@ static const struct iwl_mei_ops mei_ops = { .nic_stolen = iwl_mvm_mei_nic_stolen, }; -static void iwl_mvm_find_link_selection_vif(void *_data, u8 *mac, - struct ieee80211_vif *vif) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (ieee80211_vif_is_mld(vif) && mvmvif->authorized) - iwl_mvm_select_links(mvmvif->mvm, vif); -} - -static void iwl_mvm_trig_link_selection(struct wiphy *wiphy, - struct wiphy_work *wk) -{ - struct iwl_mvm *mvm = - container_of(wk, struct iwl_mvm, trig_link_selection_wk); - - mutex_lock(&mvm->mutex); - ieee80211_iterate_active_interfaces(mvm->hw, - IEEE80211_IFACE_ITER_NORMAL, - iwl_mvm_find_link_selection_vif, - NULL); - mutex_unlock(&mvm->mutex); -} - static struct iwl_op_mode * iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, const struct iwl_fw *fw, struct dentry *dbgfs_dir) @@ -1395,8 +1311,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 @@ -1447,9 +1361,6 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, wiphy_work_init(&mvm->async_handlers_wiphy_wk, iwl_mvm_async_handlers_wiphy_wk); - wiphy_work_init(&mvm->trig_link_selection_wk, - iwl_mvm_trig_link_selection); - init_waitqueue_head(&mvm->rx_sync_waitq); mvm->queue_sync_state = 0; @@ -2053,7 +1964,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 +2066,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 +2139,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..8c1bb3a7ffca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rx.c @@ -563,7 +563,6 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig, int thold = bss_conf->cqm_rssi_thold; int hyst = bss_conf->cqm_rssi_hyst; int last_event; - s8 exit_esr_thresh; if (sig == 0) { IWL_DEBUG_RX(mvm, "RSSI is 0 - skip signal based decision\n"); @@ -619,27 +618,6 @@ static void iwl_mvm_update_link_sig(struct ieee80211_vif *vif, int sig, sig, GFP_KERNEL); } - - /* ESR recalculation */ - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) - return; - - /* We're not in EMLSR and our signal is bad, try to switch link maybe */ - if (sig < IWL_MVM_LOW_RSSI_MLO_SCAN_THRESH && !mvmvif->esr_active) { - iwl_mvm_int_mlo_scan(mvm, vif); - return; - } - - /* We are in EMLSR, check if we need to exit */ - exit_esr_thresh = - iwl_mvm_get_esr_rssi_thresh(mvm, - &bss_conf->chanreq.oper, - true); - - if (sig < exit_esr_thresh) - iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_LOW_RSSI, - iwl_mvm_get_other_link(vif, - bss_conf->link_id)); } static void iwl_mvm_stat_iterator(void *_data, u8 *mac, @@ -877,28 +855,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; @@ -914,11 +892,6 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, link_info->beacon_stats.avg_signal = -le32_to_cpu(link_stats->beacon_average_energy); - 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); - /* make sure that beacon statistics don't go backwards with TCM * request to clear statistics */ @@ -927,8 +900,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)) @@ -958,111 +930,6 @@ iwl_mvm_stat_iterator_all_links(struct iwl_mvm *mvm, } } -#define SEC_LINK_MIN_PERC 10 -#define SEC_LINK_MIN_TX 3000 -#define SEC_LINK_MIN_RX 400 - -/* Accept a ~20% short window to avoid issues due to jitter */ -#define IWL_MVM_TPT_MIN_COUNT_WINDOW (IWL_MVM_TPT_COUNT_WINDOW_SEC * HZ * 4 / 5) - -static void iwl_mvm_update_esr_mode_tpt(struct iwl_mvm *mvm) -{ - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); - struct iwl_mvm_vif *mvmvif; - struct iwl_mvm_sta *mvmsta; - unsigned long total_tx = 0, total_rx = 0; - unsigned long sec_link_tx = 0, sec_link_rx = 0; - u8 sec_link_tx_perc, sec_link_rx_perc; - u8 sec_link; - bool skip = false; - - lockdep_assert_held(&mvm->mutex); - - if (IS_ERR_OR_NULL(bss_vif)) - return; - - mvmvif = iwl_mvm_vif_from_mac80211(bss_vif); - - if (!mvmvif->esr_active || !mvmvif->ap_sta) - return; - - mvmsta = iwl_mvm_sta_from_mac80211(mvmvif->ap_sta); - /* We only count for the AP sta in a MLO connection */ - if (!mvmsta->mpdu_counters) - return; - - /* Get the FW ID of the secondary link */ - sec_link = iwl_mvm_get_other_link(bss_vif, - iwl_mvm_get_primary_link(bss_vif)); - if (WARN_ON(!mvmvif->link[sec_link])) - return; - sec_link = mvmvif->link[sec_link]->fw_link_id; - - /* Sum up RX and TX MPDUs from the different queues/links */ - for (int q = 0; q < mvm->trans->info.num_rxqs; q++) { - spin_lock_bh(&mvmsta->mpdu_counters[q].lock); - - /* The link IDs that doesn't exist will contain 0 */ - for (int link = 0; link < IWL_FW_MAX_LINK_ID; link++) { - total_tx += mvmsta->mpdu_counters[q].per_link[link].tx; - total_rx += mvmsta->mpdu_counters[q].per_link[link].rx; - } - - sec_link_tx += mvmsta->mpdu_counters[q].per_link[sec_link].tx; - sec_link_rx += mvmsta->mpdu_counters[q].per_link[sec_link].rx; - - /* - * In EMLSR we have statistics every 5 seconds, so we can reset - * the counters upon every statistics notification. - * The FW sends the notification regularly, but it will be - * misaligned at the start. Skipping the measurement if it is - * short will synchronize us. - */ - if (jiffies - mvmsta->mpdu_counters[q].window_start < - IWL_MVM_TPT_MIN_COUNT_WINDOW) - skip = true; - mvmsta->mpdu_counters[q].window_start = jiffies; - memset(mvmsta->mpdu_counters[q].per_link, 0, - sizeof(mvmsta->mpdu_counters[q].per_link)); - - spin_unlock_bh(&mvmsta->mpdu_counters[q].lock); - } - - if (skip) { - IWL_DEBUG_INFO(mvm, "MPDU statistics window was short\n"); - return; - } - - IWL_DEBUG_INFO(mvm, "total Tx MPDUs: %ld. total Rx MPDUs: %ld\n", - total_tx, total_rx); - - /* If we don't have enough MPDUs - exit EMLSR */ - if (total_tx < IWL_MVM_ENTER_ESR_TPT_THRESH && - total_rx < IWL_MVM_ENTER_ESR_TPT_THRESH) { - iwl_mvm_block_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_TPT, - iwl_mvm_get_primary_link(bss_vif)); - return; - } - - IWL_DEBUG_INFO(mvm, "Secondary Link %d: Tx MPDUs: %ld. Rx MPDUs: %ld\n", - sec_link, sec_link_tx, sec_link_rx); - - /* Calculate the percentage of the secondary link TX/RX */ - sec_link_tx_perc = total_tx ? sec_link_tx * 100 / total_tx : 0; - sec_link_rx_perc = total_rx ? sec_link_rx * 100 / total_rx : 0; - - /* - * The TX/RX percentage is checked only if it exceeds the required - * minimum. In addition, RX is checked only if the TX check failed. - */ - if ((total_tx > SEC_LINK_MIN_TX && - sec_link_tx_perc < SEC_LINK_MIN_PERC) || - (total_rx > SEC_LINK_MIN_RX && - sec_link_rx_perc < SEC_LINK_MIN_PERC)) - iwl_mvm_exit_esr(mvm, bss_vif, IWL_MVM_ESR_EXIT_LINK_USAGE, - iwl_mvm_get_primary_link(bss_vif)); -} - void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { @@ -1090,8 +957,6 @@ void iwl_mvm_handle_rx_system_oper_stats(struct iwl_mvm *mvm, ieee80211_iterate_stations_atomic(mvm->hw, iwl_mvm_stats_energy_iter, average_energy); iwl_mvm_handle_per_phy_stats(mvm, stats->per_phy); - - iwl_mvm_update_esr_mode_tpt(mvm); } void iwl_mvm_handle_rx_system_oper_part1_stats(struct iwl_mvm *mvm, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 077aadbf95db..d35c63a673b6 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; } @@ -281,6 +332,7 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, struct ieee80211_key_conf *key; u32 len = le16_to_cpu(desc->mpdu_len); const u8 *frame = (void *)hdr; + const u8 *mmie; if ((status & IWL_RX_MPDU_STATUS_SEC_MASK) == IWL_RX_MPDU_STATUS_SEC_NONE) return 0; @@ -324,11 +376,15 @@ static int iwl_mvm_rx_mgmt_prot(struct ieee80211_sta *sta, goto report; } - if (len < key->icv_len + IEEE80211_GMAC_PN_LEN + 2) + if (len < key->icv_len) goto report; /* get the real key ID */ - keyid = frame[len - key->icv_len - IEEE80211_GMAC_PN_LEN - 2]; + mmie = frame + (len - key->icv_len); + + /* the position of the key_id in ieee80211_mmie_16 is the same */ + keyid = le16_to_cpu(((const struct ieee80211_mmie *) mmie)->key_id); + /* and if that's the other key, look it up */ if (keyid != key->keyidx) { /* @@ -854,10 +910,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 +1967,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 +2026,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 */ @@ -2040,7 +2104,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct ieee80211_sta *sta = NULL; struct sk_buff *skb; u8 crypt_len = 0; - u8 sta_id = le32_get_bits(desc->status, IWL_RX_MPDU_STATUS_STA_ID); size_t desc_size; struct iwl_mvm_rx_phy_data phy_data = {}; u32 format; @@ -2187,6 +2250,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, rcu_read_lock(); if (desc->status & cpu_to_le32(IWL_RX_MPDU_STATUS_SRC_STA_FOUND)) { + u8 sta_id = le32_get_bits(desc->status, + IWL_RX_MPDU_STATUS_STA_ID); + if (!WARN_ON_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations)) { struct ieee80211_link_sta *link_sta; @@ -2215,7 +2281,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); @@ -2314,16 +2380,6 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, iwl_mvm_agg_rx_received(mvm, reorder_data, baid); } - - if (ieee80211_is_data(hdr->frame_control)) { - u8 sub_frame_idx = desc->amsdu_info & - IWL_RX_MPDU_AMSDU_SUBFRAME_IDX_MASK; - - /* 0 means not an A-MSDU, and 1 means a new A-MSDU */ - if (!sub_frame_idx || sub_frame_idx == 1) - iwl_mvm_count_mpdu(mvmsta, sta_id, 1, false, - queue); - } } /* management stuff on default queue */ @@ -2445,7 +2501,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 +2604,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..b588f1dcf20d 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] <= @@ -1391,8 +1392,6 @@ static u32 iwl_mvm_scan_umac_ooc_priority(int type) { if (type == IWL_MVM_SCAN_REGULAR) return IWL_SCAN_PRIORITY_EXT_6; - if (type == IWL_MVM_SCAN_INT_MLO) - return IWL_SCAN_PRIORITY_EXT_4; return IWL_SCAN_PRIORITY_EXT_2; } @@ -3219,7 +3218,6 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, struct iwl_umac_scan_complete *notif = (void *)pkt->data; u32 uid = __le32_to_cpu(notif->uid); bool aborted = (notif->status == IWL_SCAN_OFFLOAD_ABORTED); - bool select_links = false; mvm->mei_scan_filter.is_mei_limited_scan = false; @@ -3266,13 +3264,6 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_SCHED) { ieee80211_sched_scan_stopped(mvm->hw); mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; - } else if (mvm->scan_uid_status[uid] == IWL_MVM_SCAN_INT_MLO) { - IWL_DEBUG_SCAN(mvm, "Internal MLO scan completed\n"); - /* - * Other scan types won't necessarily scan for the MLD links channels. - * Therefore, only select links after successful internal scan. - */ - select_links = notif->status == IWL_SCAN_OFFLOAD_COMPLETED; } mvm->scan_status &= ~mvm->scan_uid_status[uid]; @@ -3285,9 +3276,6 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, mvm->last_ebs_successful = false; mvm->scan_uid_status[uid] = 0; - - if (select_links) - wiphy_work_queue(mvm->hw->wiphy, &mvm->trig_link_selection_wk); } void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, @@ -3482,11 +3470,6 @@ void iwl_mvm_report_scan_aborted(struct iwl_mvm *mvm) mvm->sched_scan_pass_all = SCHED_SCAN_PASS_ALL_DISABLED; mvm->scan_uid_status[uid] = 0; } - uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_INT_MLO); - if (uid >= 0) { - IWL_DEBUG_SCAN(mvm, "Internal MLO scan aborted\n"); - mvm->scan_uid_status[uid] = 0; - } uid = iwl_mvm_scan_uid_by_status(mvm, IWL_MVM_SCAN_STOPPING_REGULAR); @@ -3546,7 +3529,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; } @@ -3582,89 +3565,6 @@ out: return ret; } -static int iwl_mvm_int_mlo_scan_start(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct ieee80211_channel **channels, - size_t n_channels) -{ - struct cfg80211_scan_request *req = NULL; - struct ieee80211_scan_ies ies = {}; - size_t size, i; - int ret; - - lockdep_assert_held(&mvm->mutex); - - IWL_DEBUG_SCAN(mvm, "Starting Internal MLO scan: n_channels=%zu\n", - n_channels); - - if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) || - hweight16(vif->valid_links) == 1) - return -EINVAL; - - size = struct_size(req, channels, n_channels); - req = kzalloc(size, GFP_KERNEL); - if (!req) - return -ENOMEM; - - /* set the requested channels */ - for (i = 0; i < n_channels; i++) - req->channels[i] = channels[i]; - - req->n_channels = n_channels; - - /* set the rates */ - for (i = 0; i < NUM_NL80211_BANDS; i++) - if (mvm->hw->wiphy->bands[i]) - req->rates[i] = - (1 << mvm->hw->wiphy->bands[i]->n_bitrates) - 1; - - req->wdev = ieee80211_vif_to_wdev(vif); - req->wiphy = mvm->hw->wiphy; - req->scan_start = jiffies; - req->tsf_report_link_id = -1; - - ret = _iwl_mvm_single_scan_start(mvm, vif, req, &ies, - IWL_MVM_SCAN_INT_MLO); - kfree(req); - - IWL_DEBUG_SCAN(mvm, "Internal MLO scan: ret=%d\n", ret); - return ret; -} - -int iwl_mvm_int_mlo_scan(struct iwl_mvm *mvm, struct ieee80211_vif *vif) -{ - struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS]; - unsigned long usable_links = ieee80211_vif_usable_links(vif); - size_t n_channels = 0; - u8 link_id; - - lockdep_assert_held(&mvm->mutex); - - if (mvm->scan_status & IWL_MVM_SCAN_INT_MLO) { - IWL_DEBUG_SCAN(mvm, "Internal MLO scan is already running\n"); - return -EBUSY; - } - - rcu_read_lock(); - - for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_bss_conf *link_conf = - rcu_dereference(vif->link_conf[link_id]); - - if (WARN_ON_ONCE(!link_conf)) - continue; - - channels[n_channels++] = link_conf->chanreq.oper.chan; - } - - rcu_read_unlock(); - - if (!n_channels) - return -EINVAL; - - return iwl_mvm_int_mlo_scan_start(mvm, vif, channels, n_channels); -} - static int iwl_mvm_chanidx_from_phy(struct iwl_mvm *mvm, enum nl80211_band band, u16 phy_chan_num) @@ -3685,117 +3585,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 +3642,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..363232bb74fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1835,18 +1835,6 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif, iwl_mvm_toggle_tx_ant(mvm, &mvm_sta->tx_ant); - /* MPDUs are counted only when EMLSR is possible */ - if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && - !sta->tdls && ieee80211_vif_is_mld(vif)) { - mvm_sta->mpdu_counters = - kcalloc(mvm->trans->info.num_rxqs, - sizeof(*mvm_sta->mpdu_counters), - GFP_KERNEL); - if (mvm_sta->mpdu_counters) - for (int q = 0; q < mvm->trans->info.num_rxqs; q++) - spin_lock_init(&mvm_sta->mpdu_counters[q].lock); - } - return 0; } @@ -2461,7 +2449,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 +2512,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 +2665,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) @@ -4328,80 +4316,3 @@ void iwl_mvm_cancel_channel_switch(struct iwl_mvm *mvm, if (ret) IWL_ERR(mvm, "Failed to cancel the channel switch\n"); } - -static int iwl_mvm_fw_sta_id_to_fw_link_id(struct iwl_mvm_vif *mvmvif, - u8 fw_sta_id) -{ - struct ieee80211_link_sta *link_sta = - rcu_dereference(mvmvif->mvm->fw_id_to_link_sta[fw_sta_id]); - struct iwl_mvm_vif_link_info *link; - - if (WARN_ON_ONCE(!link_sta)) - return -EINVAL; - - link = mvmvif->link[link_sta->link_id]; - - if (WARN_ON_ONCE(!link)) - return -EINVAL; - - return link->fw_link_id; -} - -#define IWL_MVM_TPT_COUNT_WINDOW (IWL_MVM_TPT_COUNT_WINDOW_SEC * HZ) - -void iwl_mvm_count_mpdu(struct iwl_mvm_sta *mvm_sta, u8 fw_sta_id, u32 count, - bool tx, int queue) -{ - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(mvm_sta->vif); - struct iwl_mvm *mvm = mvmvif->mvm; - struct iwl_mvm_tpt_counter *queue_counter; - struct iwl_mvm_mpdu_counter *link_counter; - u32 total_mpdus = 0; - int fw_link_id; - - /* Count only for a BSS sta, and only when EMLSR is possible */ - if (!mvm_sta->mpdu_counters) - return; - - /* Map sta id to link id */ - fw_link_id = iwl_mvm_fw_sta_id_to_fw_link_id(mvmvif, fw_sta_id); - if (fw_link_id < 0) - return; - - queue_counter = &mvm_sta->mpdu_counters[queue]; - link_counter = &queue_counter->per_link[fw_link_id]; - - spin_lock_bh(&queue_counter->lock); - - if (tx) - link_counter->tx += count; - else - link_counter->rx += count; - - /* - * When not in EMLSR, the window and the decision to enter EMLSR are - * handled during counting, when in EMLSR - in the statistics flow - */ - if (mvmvif->esr_active) - goto out; - - if (time_is_before_jiffies(queue_counter->window_start + - IWL_MVM_TPT_COUNT_WINDOW)) { - memset(queue_counter->per_link, 0, - sizeof(queue_counter->per_link)); - queue_counter->window_start = jiffies; - - IWL_DEBUG_INFO(mvm, "MPDU counters are cleared\n"); - } - - for (int i = 0; i < IWL_FW_MAX_LINK_ID; i++) - total_mpdus += tx ? queue_counter->per_link[i].tx : - queue_counter->per_link[i].rx; - - if (total_mpdus > IWL_MVM_ENTER_ESR_TPT_THRESH) - wiphy_work_queue(mvmvif->mvm->hw->wiphy, - &mvmvif->unblock_esr_tpt_wk); - -out: - spin_unlock_bh(&queue_counter->lock); -} diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h index 6b183f5e9bbc..c25edc7c1813 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. @@ -344,24 +344,6 @@ struct iwl_mvm_link_sta { u8 avg_energy; }; -struct iwl_mvm_mpdu_counter { - u32 tx; - u32 rx; -}; - -/** - * struct iwl_mvm_tpt_counter - per-queue MPDU counter - * - * @lock: Needed to protect the counters when modified from statistics. - * @per_link: per-link counters. - * @window_start: timestamp of the counting-window start - */ -struct iwl_mvm_tpt_counter { - spinlock_t lock; - struct iwl_mvm_mpdu_counter per_link[IWL_FW_MAX_LINK_ID]; - unsigned long window_start; -} ____cacheline_aligned_in_smp; - /** * struct iwl_mvm_sta - representation of a station in the driver * @vif: the interface the station belongs to @@ -409,7 +391,6 @@ struct iwl_mvm_tpt_counter { * @link: per link sta entries. For non-MLO only link[0] holds data. For MLO, * link[0] points to deflink and link[link_id] is allocated when new link * sta is added. - * @mpdu_counters: RX/TX MPDUs counters for each queue. * * When mac80211 creates a station it reserves some space (hw->sta_data_size) * in the structure for use by driver. This structure is placed in that @@ -449,8 +430,6 @@ struct iwl_mvm_sta { struct iwl_mvm_link_sta deflink; struct iwl_mvm_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; - - struct iwl_mvm_tpt_counter *mpdu_counters; }; u16 iwl_mvm_tid_queued(struct iwl_mvm *mvm, struct iwl_mvm_tid_data *tid_data); @@ -483,6 +462,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); @@ -532,9 +512,6 @@ void iwl_mvm_update_tkip_key(struct iwl_mvm *mvm, void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb); -void iwl_mvm_count_mpdu(struct iwl_mvm_sta *mvm_sta, u8 fw_sta_id, u32 count, - bool tx, int queue); - /* AMPDU */ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u16 ssn, bool start, u16 buf_size, u16 timeout); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/tests/Makefile index 895d53f223e9..2267be4cfb44 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 hcmd.o obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += iwlmvm-tests.o diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c b/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c deleted file mode 100644 index d692f1813d44..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tests/links.c +++ /dev/null @@ -1,433 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * KUnit tests for channel helper functions - * - * Copyright (C) 2024 Intel Corporation - */ -#include <net/mac80211.h> -#include "../mvm.h" -#include <kunit/test.h> - -MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); - -static struct wiphy wiphy = { - .mtx = __MUTEX_INITIALIZER(wiphy.mtx), -}; - -static struct ieee80211_hw hw = { - .wiphy = &wiphy, -}; - -static struct ieee80211_channel chan_5ghz = { - .band = NL80211_BAND_5GHZ, -}; - -static struct ieee80211_channel chan_6ghz = { - .band = NL80211_BAND_6GHZ, -}; - -static struct ieee80211_channel chan_2ghz = { - .band = NL80211_BAND_2GHZ, -}; - -static struct cfg80211_chan_def chandef_a = {}; - -static struct cfg80211_chan_def chandef_b = {}; - -static struct iwl_mvm_phy_ctxt ctx = {}; - -static struct iwl_mvm_vif_link_info mvm_link = { - .phy_ctxt = &ctx, - .active = true -}; - -static struct cfg80211_bss bss = {}; - -static struct ieee80211_bss_conf link_conf = {.bss = &bss}; - -static const struct iwl_fw_cmd_version entry = { - .group = LEGACY_GROUP, - .cmd = BT_PROFILE_NOTIFICATION, - .notif_ver = 4 -}; - -static struct iwl_fw fw = { - .ucode_capa = { - .n_cmd_versions = 1, - .cmd_versions = &entry, - }, -}; - -static struct iwl_mvm mvm = { - .hw = &hw, - .fw = &fw, -}; - -static const struct link_grading_case { - const char *desc; - const struct cfg80211_chan_def chandef; - s32 signal; - s16 channel_util; - int chan_load_by_us; - unsigned int grade; -} link_grading_cases[] = { - { - .desc = "UHB, RSSI below range, no factors", - .chandef = { - .chan = &chan_6ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -100, - .grade = 177, - }, - { - .desc = "LB, RSSI in range, no factors", - .chandef = { - .chan = &chan_2ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -84, - .grade = 344, - }, - { - .desc = "HB, RSSI above range, no factors", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -50, - .grade = 3442, - }, - { - .desc = "HB, BSS Load IE (20 percent), inactive link, no puncturing factor", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -66, - .channel_util = 51, - .grade = 1836, - }, - { - .desc = "LB, BSS Load IE (20 percent), active link, chan_load_by_us=10 percent. No puncturing factor", - .chandef = { - .chan = &chan_2ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -61, - .channel_util = 51, - .chan_load_by_us = 10, - .grade = 2061, - }, - { - .desc = "UHB, BSS Load IE (40 percent), active link, chan_load_by_us=50 (invalid) percent. No puncturing factor", - .chandef = { - .chan = &chan_6ghz, - .width = NL80211_CHAN_WIDTH_20, - }, - .signal = -66, - .channel_util = 102, - .chan_load_by_us = 50, - .grade = 1552, - }, - { .desc = "HB, 80 MHz, no channel load factor, punctured percentage 0", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_80, - .punctured = 0x0000 - }, - .signal = -72, - .grade = 1750, - }, - { .desc = "HB, 160 MHz, no channel load factor, punctured percentage 25", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_160, - .punctured = 0x3 - }, - .signal = -72, - .grade = 1312, - }, - { .desc = "UHB, 320 MHz, no channel load factor, punctured percentage 12.5 (2/16)", - .chandef = { - .chan = &chan_6ghz, - .width = NL80211_CHAN_WIDTH_320, - .punctured = 0x3 - }, - .signal = -72, - .grade = 1806, - }, - { .desc = "HB, 160 MHz, channel load 20, channel load by us 10, punctured percentage 25", - .chandef = { - .chan = &chan_5ghz, - .width = NL80211_CHAN_WIDTH_160, - .punctured = 0x3 - }, - .channel_util = 51, - .chan_load_by_us = 10, - .signal = -72, - .grade = 1179, - }, -}; - -KUNIT_ARRAY_PARAM_DESC(link_grading, link_grading_cases, desc) - -static void setup_link_conf(struct kunit *test) -{ - const struct link_grading_case *params = test->param_value; - size_t vif_size = sizeof(struct ieee80211_vif) + - sizeof(struct iwl_mvm_vif); - struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL); - struct ieee80211_bss_load_elem *bss_load; - struct element *element; - size_t ies_size = sizeof(struct cfg80211_bss_ies) + sizeof(*bss_load) + sizeof(element); - struct cfg80211_bss_ies *ies; - struct iwl_mvm_vif *mvmvif; - - KUNIT_ASSERT_NOT_NULL(test, vif); - - mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (params->chan_load_by_us > 0) { - ctx.channel_load_by_us = params->chan_load_by_us; - mvmvif->link[0] = &mvm_link; - } - - link_conf.vif = vif; - link_conf.chanreq.oper = params->chandef; - bss.signal = DBM_TO_MBM(params->signal); - - ies = kunit_kzalloc(test, ies_size, GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, ies); - ies->len = sizeof(*bss_load) + sizeof(struct element); - - element = (void *)ies->data; - element->datalen = sizeof(*bss_load); - element->id = 11; - - bss_load = (void *)element->data; - bss_load->channel_util = params->channel_util; - - rcu_assign_pointer(bss.ies, ies); - rcu_assign_pointer(bss.beacon_ies, ies); -} - -static void test_link_grading(struct kunit *test) -{ - const struct link_grading_case *params = test->param_value; - unsigned int ret; - - setup_link_conf(test); - - rcu_read_lock(); - ret = iwl_mvm_get_link_grade(&link_conf); - rcu_read_unlock(); - - KUNIT_EXPECT_EQ(test, ret, params->grade); - - kunit_kfree(test, link_conf.vif); - RCU_INIT_POINTER(bss.ies, NULL); -} - -static struct kunit_case link_grading_test_cases[] = { - KUNIT_CASE_PARAM(test_link_grading, link_grading_gen_params), - {} -}; - -static struct kunit_suite link_grading = { - .name = "iwlmvm-link-grading", - .test_cases = link_grading_test_cases, -}; - -kunit_test_suite(link_grading); - -static const struct valid_link_pair_case { - const char *desc; - bool bt; - struct ieee80211_channel *chan_a; - struct ieee80211_channel *chan_b; - enum nl80211_chan_width cw_a; - enum nl80211_chan_width cw_b; - s32 sig_a; - s32 sig_b; - bool csa_a; - bool valid; -} valid_link_pair_cases[] = { - { - .desc = "HB + UHB, valid.", - .chan_a = &chan_6ghz, - .chan_b = &chan_5ghz, - .valid = true, - }, - { - .desc = "LB + HB, no BT.", - .chan_a = &chan_2ghz, - .chan_b = &chan_5ghz, - .valid = true, - }, - { - .desc = "LB + HB, with BT.", - .bt = true, - .chan_a = &chan_2ghz, - .chan_b = &chan_5ghz, - .valid = false, - }, - { - .desc = "Same band", - .chan_a = &chan_2ghz, - .chan_b = &chan_2ghz, - .valid = false, - }, - { - .desc = "RSSI: LB, 20 MHz, low", - .chan_a = &chan_2ghz, - .cw_a = NL80211_CHAN_WIDTH_20, - .sig_a = -68, - .chan_b = &chan_5ghz, - .valid = false, - }, - { - .desc = "RSSI: UHB, 20 MHz, high", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_20, - .sig_a = -66, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_20, - .valid = true, - }, - { - .desc = "RSSI: UHB, 40 MHz, low", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_40, - .sig_a = -65, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_40, - .valid = false, - }, - { - .desc = "RSSI: UHB, 40 MHz, high", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_40, - .sig_a = -63, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_40, - .valid = true, - }, - { - .desc = "RSSI: UHB, 80 MHz, low", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_80, - .sig_a = -62, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_80, - .valid = false, - }, - { - .desc = "RSSI: UHB, 80 MHz, high", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_80, - .sig_a = -60, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_80, - .valid = true, - }, - { - .desc = "RSSI: UHB, 160 MHz, low", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_160, - .sig_a = -59, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_160, - .valid = false, - }, - { - .desc = "RSSI: HB, 160 MHz, high", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_160, - .sig_a = -5, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_160, - .valid = true, - }, - { - .desc = "CSA active", - .chan_a = &chan_6ghz, - .cw_a = NL80211_CHAN_WIDTH_160, - .sig_a = -5, - .chan_b = &chan_5ghz, - .cw_b = NL80211_CHAN_WIDTH_160, - .valid = false, - /* same as previous entry with valid=true except for CSA */ - .csa_a = true, - }, -}; - -KUNIT_ARRAY_PARAM_DESC(valid_link_pair, valid_link_pair_cases, desc) - -static void test_valid_link_pair(struct kunit *test) -{ - const struct valid_link_pair_case *params = test->param_value; - size_t vif_size = sizeof(struct ieee80211_vif) + - sizeof(struct iwl_mvm_vif); - struct ieee80211_vif *vif = kunit_kzalloc(test, vif_size, GFP_KERNEL); - struct iwl_trans *trans = kunit_kzalloc(test, sizeof(struct iwl_trans), - GFP_KERNEL); - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - struct iwl_mvm_link_sel_data link_a = { - .chandef = &chandef_a, - .link_id = 1, - .signal = params->sig_a, - }; - struct iwl_mvm_link_sel_data link_b = { - .chandef = &chandef_b, - .link_id = 5, - .signal = params->sig_b, - }; - struct ieee80211_bss_conf *conf; - bool result; - - KUNIT_ASSERT_NOT_NULL(test, vif); - KUNIT_ASSERT_NOT_NULL(test, trans); - - chandef_a.chan = params->chan_a; - chandef_b.chan = params->chan_b; - - chandef_a.width = params->cw_a ?: NL80211_CHAN_WIDTH_20; - chandef_b.width = params->cw_b ?: NL80211_CHAN_WIDTH_20; - - mvm.trans = trans; - - mvm.last_bt_notif.wifi_loss_low_rssi = params->bt; - mvmvif->mvm = &mvm; - - conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, conf); - conf->chanreq.oper = chandef_a; - conf->csa_active = params->csa_a; - vif->link_conf[link_a.link_id] = (void __rcu *)conf; - - conf = kunit_kzalloc(test, sizeof(*vif->link_conf[0]), GFP_KERNEL); - KUNIT_ASSERT_NOT_NULL(test, conf); - conf->chanreq.oper = chandef_b; - vif->link_conf[link_b.link_id] = (void __rcu *)conf; - - wiphy_lock(&wiphy); - result = iwl_mvm_mld_valid_link_pair(vif, &link_a, &link_b); - wiphy_unlock(&wiphy); - - KUNIT_EXPECT_EQ(test, result, params->valid); - - kunit_kfree(test, vif); - kunit_kfree(test, trans); -} - -static struct kunit_case valid_link_pair_test_cases[] = { - KUNIT_CASE_PARAM(test_valid_link_pair, valid_link_pair_gen_params), - {}, -}; - -static struct kunit_suite valid_link_pair = { - .name = "iwlmvm-valid-link-pair", - .test_cases = valid_link_pair_test_cases, -}; - -kunit_test_suite(valid_link_pair); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 478408f802d9..0c9c2492d8a7 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -47,7 +47,6 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm, static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) { - struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); struct ieee80211_vif *vif = mvm->p2p_device_vif; lockdep_assert_held(&mvm->mutex); @@ -125,8 +124,6 @@ static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm) iwl_mvm_rm_aux_sta(mvm); } - if (!IS_ERR_OR_NULL(bss_vif)) - iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_ROC); mutex_unlock(&mvm->mutex); } @@ -958,40 +955,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..bb97837baeda 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); @@ -1768,9 +1769,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm, IWL_DEBUG_TX_REPLY(mvm, "Next reclaimed packet:%d\n", next_reclaimed); - if (tid < IWL_MAX_TID_COUNT) - iwl_mvm_count_mpdu(mvmsta, sta_id, 1, - true, 0); } else { IWL_DEBUG_TX_REPLY(mvm, "NDP - don't update next_reclaimed\n"); @@ -2149,13 +2147,10 @@ void iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) ba_res->tx_rate, false); } - if (mvmsta) { + if (mvmsta) iwl_mvm_tx_airtime(mvm, mvmsta, le32_to_cpu(ba_res->wireless_time)); - iwl_mvm_count_mpdu(mvmsta, sta_id, - le16_to_cpu(ba_res->txed), true, 0); - } rcu_read_unlock(); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 62da0132f383..22602c32faa5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -22,11 +22,6 @@ int iwl_mvm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd) { int ret; -#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP) - if (WARN_ON(mvm->d3_test_active)) - return -EIO; -#endif - /* * Synchronous commands from this op-mode must hold * the mutex, this ensures we don't try to send two @@ -79,11 +74,6 @@ int iwl_mvm_send_cmd_status(struct iwl_mvm *mvm, struct iwl_host_cmd *cmd, lockdep_assert_held(&mvm->mutex); -#if defined(CONFIG_IWLWIFI_DEBUGFS) && defined(CONFIG_PM_SLEEP) - if (WARN_ON(mvm->d3_test_active)) - return -EIO; -#endif - /* * Only synchronous commands can wait for status, * we use WANT_SKB so the caller can't. 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..b21a4d8eb105 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) @@ -124,13 +124,13 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_mac_cfg)},/* low 5GHz active */ {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_mac_cfg)},/* high 5GHz active */ -/* 6x30 Series */ - {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008A, 0x5307, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008A, 0x5325, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008A, 0x5327, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008B, 0x5315, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x008B, 0x5317, iwl1000_mac_cfg)}, +/* 1030/6x30 Series */ + {IWL_PCI_DEVICE(0x008A, 0x5305, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008A, 0x5307, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008A, 0x5325, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008A, 0x5327, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008B, 0x5315, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x008B, 0x5317, iwl6030_mac_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5211, iwl6030_mac_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5215, iwl6030_mac_cfg)}, {IWL_PCI_DEVICE(0x0090, 0x5216, iwl6030_mac_cfg)}, @@ -181,12 +181,12 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x08AE, 0x1027, iwl1000_mac_cfg)}, /* 130 Series WiFi */ - {IWL_PCI_DEVICE(0x0896, 0x5005, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0896, 0x5007, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0897, 0x5015, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0897, 0x5017, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0896, 0x5025, iwl1000_mac_cfg)}, - {IWL_PCI_DEVICE(0x0896, 0x5027, iwl1000_mac_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5005, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5007, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0897, 0x5015, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0897, 0x5017, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5025, iwl6030_mac_cfg)}, + {IWL_PCI_DEVICE(0x0896, 0x5027, iwl6030_mac_cfg)}, /* 2x00 Series */ {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_mac_cfg)}, @@ -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 @@ -670,6 +673,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_sff_name, DEVICE(0x0082), SUBDEV_MASKED(0xC000, 0xF000)), + IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_sff_name, + DEVICE(0x0085), SUBDEV_MASKED(0xC000, 0xF000)), IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_d_name, DEVICE(0x0082), SUBDEV(0x4820)), IWL_DEV_INFO(iwl6005_n_cfg, iwl6005_2agn_mow1_name, @@ -726,10 +731,10 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { DEVICE(0x0083), SUBDEV_MASKED(0x5, 0xF)), IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, DEVICE(0x0083), SUBDEV_MASKED(0x6, 0xF)), + IWL_DEV_INFO(iwl1000_bgn_cfg, iwl1000_bgn_name, + DEVICE(0x0084), SUBDEV_MASKED(0x5, 0xF)), IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, - DEVICE(0x0084), SUBDEV(0x1216)), - IWL_DEV_INFO(iwl1000_bg_cfg, iwl1000_bg_name, - DEVICE(0x0084), SUBDEV(0x1316)), + DEVICE(0x0084), SUBDEV_MASKED(0x6, 0xF)), /* 100 Series WiFi */ IWL_DEV_INFO(iwl100_bgn_cfg, iwl100_bgn_name, @@ -961,6 +966,12 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { DEVICE(0x24F3), SUBDEV(0x0004)), IWL_DEV_INFO(iwl8260_cfg, iwl8260_2n_name, DEVICE(0x24F3), SUBDEV(0x0044)), + IWL_DEV_INFO(iwl8260_cfg, iwl8260_2ac_name, + DEVICE(0x24F4)), + IWL_DEV_INFO(iwl8260_cfg, iwl4165_2ac_name, + DEVICE(0x24F5)), + IWL_DEV_INFO(iwl8260_cfg, iwl4165_2ac_name, + DEVICE(0x24F6)), IWL_DEV_INFO(iwl8265_cfg, iwl8265_2ac_name, DEVICE(0x24FD)), IWL_DEV_INFO(iwl8265_cfg, iwl8275_2ac_name, @@ -1031,9 +1042,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 +1083,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 +1123,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,208 +1133,57 @@ 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; + return ret; } - 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; - } - -#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) { struct iwl_trans *trans = pci_get_drvdata(pdev); - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); if (!trans) return; - cancel_delayed_work_sync(&trans_pcie->me_recheck_wk); - - iwl_drv_stop(trans->drv); - - iwl_trans_pcie_free(trans); + iwl_pcie_gen1_2_remove(trans); } #ifdef CONFIG_PM_SLEEP @@ -1503,11 +1225,15 @@ static int _iwl_pci_resume(struct device *device, bool restore) * Note: MAC (bits 0:7) will be cleared upon suspend even with wowlan, * but not bits [15:8]. So if we have bits set in lower word, assume * the device is alive. + * Alternatively, if the scratch value is 0xFFFFFFFF, then we no longer + * have access to the device and consider it powered off. * For older devices, just try silently to grab the NIC. */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - if (!(iwl_read32(trans, CSR_FUNC_SCRATCH) & - CSR_FUNC_SCRATCH_POWER_OFF_MASK)) + u32 scratch = iwl_read32(trans, CSR_FUNC_SCRATCH); + + if (!(scratch & CSR_FUNC_SCRATCH_POWER_OFF_MASK) || + scratch == ~0U) device_was_powered_off = true; } else { /* @@ -1529,7 +1255,7 @@ static int _iwl_pci_resume(struct device *device, bool restore) * won't really know how to recover. */ iwl_pcie_prepare_card_hw(trans); - iwl_finish_nic_init(trans); + iwl_trans_activate_nic(trans); iwl_op_mode_device_powered_off(trans->op_mode); } @@ -1580,12 +1306,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..207c56e338dd 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 @@ -400,6 +400,11 @@ struct iwl_pcie_txqs { * @me_recheck_wk: worker to recheck WiAMT/CSME presence * @invalid_tx_cmd: invalid TX command buffer * @wait_command_queue: wait queue for sync commands + * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. + * The user should use iwl_trans_{alloc,free}_tx_cmd. + * @dev_cmd_pool_name: name for the TX command allocation pool + * @pm_support: set to true in start_hw if link pm is supported + * @ltr_enabled: set to true if the LTR is enabled */ struct iwl_trans_pcie { struct iwl_rxq *rxq; @@ -448,13 +453,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; @@ -502,6 +511,12 @@ struct iwl_trans_pcie { struct iwl_dma_ptr invalid_tx_cmd; wait_queue_head_t wait_command_queue; + + struct kmem_cache *dev_cmd_pool; + char dev_cmd_pool_name[50]; + + bool pm_support; + bool ltr_enabled; }; static inline struct iwl_trans_pcie * @@ -534,10 +549,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 +709,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 +721,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) { @@ -781,6 +794,23 @@ static inline u16 iwl_txq_gen1_tfd_tb_get_len(struct iwl_trans *trans, return le16_to_cpu(tb->hi_n_len) >> 4; } +static inline struct iwl_device_tx_cmd * +iwl_pcie_gen1_2_alloc_tx_cmd(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + return kmem_cache_zalloc(trans_pcie->dev_cmd_pool, GFP_ATOMIC); +} + +static inline void +iwl_pcie_gen1_2_free_tx_cmd(struct iwl_trans *trans, + struct iwl_device_tx_cmd *dev_cmd) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + kmem_cache_free(trans_pcie->dev_cmd_pool, dev_cmd); +} + void iwl_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, struct sk_buff_head *skbs, bool is_flush); void iwl_pcie_set_q_ptrs(struct iwl_trans *trans, int txq_id, int ptr); @@ -816,6 +846,8 @@ static inline void _iwl_disable_interrupts(struct iwl_trans *trans) trans_pcie->fh_init_mask); iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, trans_pcie->hw_init_mask); + trans_pcie->fh_mask = 0; + trans_pcie->hw_mask = 0; } IWL_DEBUG_ISR(trans, "Disabled interrupts\n"); } @@ -998,6 +1030,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) } else { iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, trans_pcie->fh_init_mask); + trans_pcie->fh_mask = 0; iwl_enable_hw_int_msk_msix(trans, MSIX_HW_INT_CAUSES_REG_RF_KILL); } @@ -1028,40 +1061,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); @@ -1073,7 +1078,8 @@ static inline void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) { } 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); +void iwl_pcie_gen1_2_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,17 +1089,14 @@ 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, const struct iwl_dump_sanitize_ops *sanitize_ops, void *sanitize_ctx); int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, - enum iwl_d3_status *status, - bool test, bool reset); -int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset); + bool reset); +int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool reset); void iwl_trans_pci_interrupts(struct iwl_trans *trans, bool enable); void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans); void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg, @@ -1104,6 +1107,11 @@ 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); +void iwl_pcie_gen1_2_remove(struct iwl_trans *trans); /* transport gen 1 exported functions */ void iwl_trans_pcie_fw_alive(struct iwl_trans *trans); @@ -1114,6 +1122,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); @@ -1127,6 +1136,7 @@ int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr, size_t size); void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); void iwl_pcie_apply_destination(struct iwl_trans *trans); +int iwl_pcie_gen1_2_activate_nic(struct iwl_trans *trans); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, @@ -1146,4 +1156,17 @@ int iwl_trans_pcie_copy_imr(struct iwl_trans *trans, int iwl_trans_pcie_rxq_dma_data(struct iwl_trans *trans, int queue, struct iwl_trans_rxq_dma_data *data); +static inline bool iwl_pcie_gen1_is_pm_supported(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + return trans_pcie->pm_support; +} + +static inline bool iwl_pcie_gen1_2_is_ltr_enabled(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + return trans_pcie->ltr_enabled; +} #endif /* __iwl_trans_int_pcie_h__ */ 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 c8f4f3a1d2eb..b15c5d486527 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" @@ -47,7 +47,7 @@ int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) iwl_pcie_apm_config(trans); - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (ret) return ret; @@ -546,8 +546,10 @@ again: } if (WARN_ON(trans->do_top_reset && - trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC)) - return -EINVAL; + trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_SC)) { + ret = -EINVAL; + goto out; + } /* we need to wait later - set state */ if (trans->do_top_reset) @@ -610,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; @@ -625,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..59307b5df441 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -28,106 +28,53 @@ #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 +#define IWL_HOST_MON_BLOCK_PEMON 0x00 +#define IWL_HOST_MON_BLOCK_HIPM 0x22 -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; +#define IWL_HOST_MON_BLOCK_PEMON_VEC0 0x00 +#define IWL_HOST_MON_BLOCK_PEMON_VEC1 0x01 +#define IWL_HOST_MON_BLOCK_PEMON_WFPM 0x06 - 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); +static void iwl_dump_host_monitor_block(struct iwl_trans *trans, + u32 block, u32 vec, u32 iter) +{ + int i; - /* 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); + IWL_ERR(trans, "Host monitor block 0x%x vector 0x%x\n", block, vec); + iwl_write32(trans, CSR_MONITOR_CFG_REG, (block << 8) | vec); + for (i = 0; i < iter; i++) + IWL_ERR(trans, " value [iter %d]: 0x%08x\n", + i, iwl_read32(trans, CSR_MONITOR_STATUS_REG)); +} - buf = kmalloc(alloc_size, GFP_ATOMIC); - if (!buf) +static void iwl_pcie_dump_host_monitor(struct iwl_trans *trans) +{ + switch (trans->mac_cfg->device_family) { + case IWL_DEVICE_FAMILY_22000: + case IWL_DEVICE_FAMILY_AX210: + IWL_ERR(trans, "CSR_RESET = 0x%x\n", + iwl_read32(trans, CSR_RESET)); + iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, + IWL_HOST_MON_BLOCK_PEMON_VEC0, 15); + iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, + IWL_HOST_MON_BLOCK_PEMON_VEC1, 15); + iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, + IWL_HOST_MON_BLOCK_PEMON_WFPM, 15); + iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_HIPM, + IWL_HOST_MON_BLOCK_PEMON_VEC0, 1); + break; + default: 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); + } } +/* extended range in FW SRAM */ +#define IWL_FW_MEM_EXTENDED_START 0x40000 +#define IWL_FW_MEM_EXTENDED_END 0x57FFF + int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership) { /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ @@ -267,13 +214,13 @@ void iwl_pcie_apm_config(struct iwl_trans *trans) iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_DISABLED); pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl); - trans->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); + trans_pcie->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_DEVCTL2, &cap); - trans->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; + trans_pcie->ltr_enabled = cap & PCI_EXP_DEVCTL2_LTR_EN; IWL_DEBUG_POWER(trans, "L1 %sabled - LTR %sabled\n", (lctl & PCI_EXP_LNKCTL_ASPM_L1) ? "En" : "Dis", - trans->ltr_enabled ? "En" : "Dis"); + trans_pcie->ltr_enabled ? "En" : "Dis"); } /* @@ -320,7 +267,7 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) if (trans->mac_cfg->base->pll_cfg) iwl_set_bit(trans, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (ret) return ret; @@ -387,18 +334,18 @@ 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); if (!ret) - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(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 +396,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 +420,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 +530,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 +551,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 +569,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 +648,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; } @@ -1492,17 +1436,10 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq) } static void iwl_pcie_d3_complete_suspend(struct iwl_trans *trans, - bool test, bool reset) + bool reset) { iwl_disable_interrupts(trans); - /* - * in testing mode, the host stays awake and the - * hardware won't be reset (not even partially) - */ - if (test) - return; - iwl_pcie_disable_ict(trans); iwl_pcie_synchronize_irqs(trans); @@ -1536,33 +1473,44 @@ 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) +int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool reset) { int ret; @@ -1575,26 +1523,18 @@ int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset) if (ret) return ret; - iwl_pcie_d3_complete_suspend(trans, test, reset); + iwl_pcie_d3_complete_suspend(trans, reset); return 0; } int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, - enum iwl_d3_status *status, - bool test, bool reset) + bool reset) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 val; int ret; - if (test) { - iwl_enable_interrupts(trans); - *status = IWL_D3_STATUS_ALIVE; - ret = 0; - goto out; - } - if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); @@ -1602,9 +1542,12 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - ret = iwl_finish_nic_init(trans); - if (ret) + ret = iwl_trans_activate_nic(trans); + if (ret) { + IWL_ERR(trans, "Failed to init nic upon resume. err = %d\n", + ret); return ret; + } /* * Reconfigure IVAR table in case of MSIX or reset ict table in @@ -1638,18 +1581,13 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_read_umac_prph(trans, WFPM_GP2)); val = iwl_read32(trans, CSR_RESET); - if (val & CSR_RESET_REG_FLAG_NEVO_RESET) - *status = IWL_D3_STATUS_RESET; - else - *status = IWL_D3_STATUS_ALIVE; - -out: - if (*status == IWL_D3_STATUS_ALIVE) - ret = iwl_pcie_d3_handshake(trans, false); - else + if (val & CSR_RESET_REG_FLAG_NEVO_RESET) { + IWL_INFO(trans, "Device was reset during suspend\n"); trans->state = IWL_TRANS_NO_FW; + return -ENOENT; + } - return ret; + return iwl_pcie_d3_handshake(trans, false); } static void @@ -1828,7 +1766,7 @@ static int iwl_pcie_gen2_force_power_gating(struct iwl_trans *trans) { int ret; - ret = iwl_finish_nic_init(trans); + ret = iwl_trans_activate_nic(trans); if (ret < 0) return ret; @@ -1845,7 +1783,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; @@ -1966,7 +1904,7 @@ void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, u32 val) iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val); } -void iwl_trans_pcie_op_mode_enter(struct iwl_trans *trans) +void iwl_pcie_gen1_2_op_mode_enter(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -2084,6 +2022,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans) free_percpu(trans_pcie->txqs.tso_hdr_page); } + kmem_cache_destroy(trans_pcie->dev_cmd_pool); iwl_trans_free(trans); } @@ -2412,7 +2351,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 +2375,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 +2388,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 +2440,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 +2506,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 +2625,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); } @@ -3618,7 +3539,7 @@ iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask, struct iwl_trans_dump_data *dump_data; u32 len, num_rbs = 0, monitor_len = 0; int i, ptr; - bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) && + bool dump_rbs = iwl_trans_is_fw_error(trans) && !trans->mac_cfg->mq_rx_supported && dump_mask & BIT(IWL_FW_ERROR_DUMP_RB); @@ -3786,28 +3707,52 @@ 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_alloc_txcmd_pool(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned int txcmd_size, txcmd_align; + + 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_pcie->dev_cmd_pool_name, + sizeof(trans_pcie->dev_cmd_pool_name), + "iwl_cmd_pool:%s", dev_name(trans->dev)); + + trans_pcie->dev_cmd_pool = + kmem_cache_create(trans_pcie->dev_cmd_pool_name, + txcmd_size, txcmd_align, + SLAB_HWCACHE_ALIGN, NULL); + if (!trans_pcie->dev_cmd_pool) + return -ENOMEM; + + 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; 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); - if (ret) - return ERR_PTR(ret); trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev, mac_cfg); @@ -3816,9 +3761,15 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, 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); + ret = iwl_trans_pcie_alloc_txcmd_pool(trans); + if (ret) + goto out_free_trans; + if (trans->mac_cfg->gen2) { trans_pcie->txqs.tfd.addr_size = 64; trans_pcie->txqs.tfd.max_tbs = IWL_TFH_NUM_TBS; @@ -3838,7 +3789,7 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->txqs.tso_hdr_page = alloc_percpu(struct iwl_tso_hdr_page); if (!trans_pcie->txqs.tso_hdr_page) { ret = -ENOMEM; - goto out_free_trans; + goto out_free_txcmd_pool; } if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) @@ -3913,8 +3864,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 +3875,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 +3882,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 @@ -4010,6 +3939,8 @@ out_free_ndev: free_netdev(trans_pcie->napi_dev); out_free_tso: free_percpu(trans_pcie->txqs.tso_hdr_page); +out_free_txcmd_pool: + kmem_cache_destroy(trans_pcie->dev_cmd_pool); out_free_trans: iwl_trans_free(trans); return ERR_PTR(ret); @@ -4046,9 +3977,382 @@ 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 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, + WFPM_OTP_CFG1_ADDR); + 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"); + } + + 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 from wfpm id 0x%x\n", + cdb_id_wfpm, hw_wfpm_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_trans_activate_nic(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; +} + +void iwl_pcie_gen1_2_remove(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + cancel_delayed_work_sync(&trans_pcie->me_recheck_wk); + + iwl_drv_stop(trans->drv); + + iwl_trans_pcie_free(trans); +} + +int iwl_pcie_gen1_2_activate_nic(struct iwl_trans *trans) +{ + const struct iwl_mac_cfg *mac_cfg = trans->mac_cfg; + u32 poll_ready; + int err; + + if (mac_cfg->bisr_workaround) { + /* ensure the TOP FSM isn't still in previous reset */ + mdelay(2); + } + + /* + * Set "initialization complete" bit to move adapter from + * D0U* --> D0A* (powered-up active) state. + */ + if (mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ | + CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; + } else { + iwl_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY; + } + + if (mac_cfg->device_family == IWL_DEVICE_FAMILY_8000) + udelay(2); + + /* + * Wait for clock stabilization; once stabilized, access to + * device-internal resources is supported, e.g. iwl_write_prph() + * and accesses to uCode SRAM. + */ + err = iwl_poll_bits(trans, CSR_GP_CNTRL, poll_ready, 25000); + if (err < 0) { + IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); + + iwl_pcie_dump_host_monitor(trans); + } + + if (mac_cfg->bisr_workaround) { + /* ensure BISR shift has finished */ + udelay(200); + } + + return err; +} 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 bb467e2b1779..6e85aa519e1b 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: @@ -2093,7 +2092,8 @@ static void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans, break; } - if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_7000 && + trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) len = DIV_ROUND_UP(len, 4); if (WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX)) @@ -2101,10 +2101,10 @@ static void iwl_txq_gen1_update_byte_cnt_tbl(struct iwl_trans *trans, bc_ent = cpu_to_le16(len | (sta_id << 12)); - scd_bc_tbl[txq_id * BC_TABLE_SIZE + write_ptr].tfd_offset = bc_ent; + scd_bc_tbl[txq_id * TFD_QUEUE_BC_SIZE + write_ptr].tfd_offset = bc_ent; if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) - scd_bc_tbl[txq_id * BC_TABLE_SIZE + TFD_QUEUE_SIZE_MAX + write_ptr].tfd_offset = + scd_bc_tbl[txq_id * TFD_QUEUE_BC_SIZE + TFD_QUEUE_SIZE_MAX + write_ptr].tfd_offset = bc_ent; } @@ -2186,10 +2186,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 +2211,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 +2226,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 +2272,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,14 +2324,14 @@ 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)); - scd_bc_tbl[txq_id * BC_TABLE_SIZE + read_ptr].tfd_offset = bc_ent; + scd_bc_tbl[txq_id * TFD_QUEUE_BC_SIZE + read_ptr].tfd_offset = bc_ent; if (read_ptr < TFD_QUEUE_SIZE_BC_DUP) - scd_bc_tbl[txq_id * BC_TABLE_SIZE + TFD_QUEUE_SIZE_MAX + read_ptr].tfd_offset = + scd_bc_tbl[txq_id * TFD_QUEUE_BC_SIZE + TFD_QUEUE_SIZE_MAX + read_ptr].tfd_offset = bc_ent; } @@ -2602,8 +2602,9 @@ static int iwl_trans_pcie_send_hcmd_sync(struct iwl_trans *trans, } if (test_bit(STATUS_FW_ERROR, &trans->status)) { - if (!test_and_clear_bit(STATUS_SUPPRESS_CMD_ERROR_ONCE, - &trans->status)) { + if (trans->suppress_cmd_error_once) { + trans->suppress_cmd_error_once = false; + } else { IWL_ERR(trans, "FW error in SYNC CMD %s\n", cmd_str); dump_stack(); } 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..b996c45d43e7 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 nvm_parse.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/tests/nvm_parse.c b/drivers/net/wireless/intel/iwlwifi/tests/nvm_parse.c new file mode 100644 index 000000000000..853911900bfd --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/tests/nvm_parse.c @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * KUnit tests for NVM parse + * + * Copyright (C) 2025 Intel Corporation + */ +#include <kunit/static_stub.h> +#include <kunit/test.h> +#include <iwl-nvm-parse.h> + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); + +static const struct nvm_flag_case { + const char *desc; + u16 nvm_flags; + u32 reg_rule_flags; + u32 set_reg_rule_flags; + u32 clear_reg_rule_flags; +} nvm_flag_cases[] = { + { + .desc = "Restricting VLP client and AP access", + .nvm_flags = 0, + .set_reg_rule_flags = NL80211_RRF_NO_6GHZ_VLP_CLIENT, + .clear_reg_rule_flags = NL80211_RRF_ALLOW_6GHZ_VLP_AP, + }, + { + .desc = "Allow VLP client and AP access", + .nvm_flags = NVM_CHANNEL_VLP, + .set_reg_rule_flags = NL80211_RRF_ALLOW_6GHZ_VLP_AP, + .clear_reg_rule_flags = NL80211_RRF_NO_6GHZ_VLP_CLIENT, + }, + { + .desc = "Allow VLP client access, while restricting AP access", + .nvm_flags = NVM_CHANNEL_VLP | NVM_CHANNEL_VLP_AP_NOT_ALLOWED, + .set_reg_rule_flags = 0, + .clear_reg_rule_flags = NL80211_RRF_ALLOW_6GHZ_VLP_AP | + NL80211_RRF_NO_6GHZ_VLP_CLIENT, + }, +}; + +KUNIT_ARRAY_PARAM_DESC(nvm_flag, nvm_flag_cases, desc) + +static void test_nvm_flags(struct kunit *test) +{ + const struct nvm_flag_case *params = test->param_value; + struct iwl_reg_capa reg_capa = {}; + u32 flags = 0; + + flags = iwl_nvm_get_regdom_bw_flags(NULL, 0, params->nvm_flags, + reg_capa); + + if ((params->set_reg_rule_flags & flags) != params->set_reg_rule_flags) + KUNIT_FAIL(test, "Expected set bits:0x%08x flags:0x%08x\n", + params->set_reg_rule_flags, flags); + + if (params->clear_reg_rule_flags & flags) + KUNIT_FAIL(test, "Expected clear bits:0x%08x flags:0x%08x\n", + params->clear_reg_rule_flags, flags); +} + +static struct kunit_case nvm_flags_test_cases[] = { + KUNIT_CASE_PARAM(test_nvm_flags, + nvm_flag_gen_params), + {}, +}; + +static struct kunit_suite nvm_flags_suite = { + .name = "iwlwifi-nvm_flags", + .test_cases = nvm_flags_test_cases, +}; + +kunit_test_suite(nvm_flags_suite); 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/intersil/p54/txrx.c b/drivers/net/wireless/intersil/p54/txrx.c index 2deb1bb54f24..1294a1d6528e 100644 --- a/drivers/net/wireless/intersil/p54/txrx.c +++ b/drivers/net/wireless/intersil/p54/txrx.c @@ -317,7 +317,7 @@ static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb) tim_len = tim[1]; tim_ie = (struct ieee80211_tim_ie *) &tim[2]; - new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid); + new_psm = ieee80211_check_tim(tim_ie, tim_len, priv->aid, false); if (new_psm != priv->powersave_override) { priv->powersave_override = new_psm; p54_set_ps(priv); diff --git a/drivers/net/wireless/marvell/libertas/cfg.c b/drivers/net/wireless/marvell/libertas/cfg.c index 2e2c193716d9..caba7491cd5a 100644 --- a/drivers/net/wireless/marvell/libertas/cfg.c +++ b/drivers/net/wireless/marvell/libertas/cfg.c @@ -1151,10 +1151,13 @@ static int lbs_associate(struct lbs_private *priv, /* add SSID TLV */ rcu_read_lock(); ssid_eid = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); - if (ssid_eid) - pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_eid[1]); - else + if (ssid_eid) { + u32 ssid_len = min(ssid_eid[1], IEEE80211_MAX_SSID_LEN); + + pos += lbs_add_ssid_tlv(pos, ssid_eid + 2, ssid_len); + } else { lbs_deb_assoc("no SSID\n"); + } rcu_read_unlock(); /* add DS param TLV */ @@ -2146,8 +2149,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/if_sdio.c b/drivers/net/wireless/marvell/libertas/if_sdio.c index 524034699972..fc5318035822 100644 --- a/drivers/net/wireless/marvell/libertas/if_sdio.c +++ b/drivers/net/wireless/marvell/libertas/if_sdio.c @@ -1181,7 +1181,8 @@ static int if_sdio_probe(struct sdio_func *func, spin_lock_init(&card->lock); INIT_LIST_HEAD(&card->packets); - card->workqueue = alloc_workqueue("libertas_sdio", WQ_MEM_RECLAIM, 0); + card->workqueue = alloc_workqueue("libertas_sdio", + WQ_MEM_RECLAIM | WQ_UNBOUND, 0); if (unlikely(!card->workqueue)) { ret = -ENOMEM; goto err_queue; diff --git a/drivers/net/wireless/marvell/libertas/if_spi.c b/drivers/net/wireless/marvell/libertas/if_spi.c index b722a6587fd3..8a2504a62840 100644 --- a/drivers/net/wireless/marvell/libertas/if_spi.c +++ b/drivers/net/wireless/marvell/libertas/if_spi.c @@ -1153,7 +1153,8 @@ static int if_spi_probe(struct spi_device *spi) priv->fw_ready = 1; /* Initialize interrupt handling stuff. */ - card->workqueue = alloc_workqueue("libertas_spi", WQ_MEM_RECLAIM, 0); + card->workqueue = alloc_workqueue("libertas_spi", + WQ_MEM_RECLAIM | WQ_UNBOUND, 0); if (!card->workqueue) { err = -ENOMEM; goto remove_card; diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 50c0f6179e2d..fb20fe31cd36 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; @@ -708,7 +708,7 @@ EXPORT_SYMBOL_GPL(lbtf_bcn_sent); static int __init lbtf_init_module(void) { lbtf_deb_enter(LBTF_DEB_MAIN); - lbtf_wq = alloc_workqueue("libertastf", WQ_MEM_RECLAIM, 0); + lbtf_wq = alloc_workqueue("libertastf", WQ_MEM_RECLAIM | WQ_UNBOUND, 0); if (lbtf_wq == NULL) { printk(KERN_ERR "libertastf: couldn't create workqueue\n"); return -ENOMEM; diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 60c12328c2f3..be23a29e7de0 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); @@ -684,10 +686,9 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy, return; } - /* Don't send world or same regdom info to firmware */ - if (strncmp(request->alpha2, "00", 2) && - strncmp(request->alpha2, adapter->country_code, - sizeof(request->alpha2))) { + /* Don't send same regdom info to firmware */ + if (strncmp(request->alpha2, adapter->country_code, + sizeof(request->alpha2)) != 0) { memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2)); mwifiex_send_domain_info_cmd_fw(wiphy); @@ -737,7 +738,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 +1941,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 +2005,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, @@ -4668,8 +4672,9 @@ int mwifiex_init_channel_scan_gap(struct mwifiex_adapter *adapter) * additional active scan request for hidden SSIDs on passive channels. */ adapter->num_in_chan_stats = 2 * (n_channels_bg + n_channels_a); - adapter->chan_stats = vmalloc(array_size(sizeof(*adapter->chan_stats), - adapter->num_in_chan_stats)); + adapter->chan_stats = kcalloc(adapter->num_in_chan_stats, + sizeof(*adapter->chan_stats), + GFP_KERNEL); if (!adapter->chan_stats) return -ENOMEM; @@ -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/main.c b/drivers/net/wireless/marvell/mwifiex/main.c index 7b50a88a18e5..ff177b06f42d 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.c +++ b/drivers/net/wireless/marvell/mwifiex/main.c @@ -494,6 +494,11 @@ static void mwifiex_free_adapter(struct mwifiex_adapter *adapter) return; } + if (adapter->rgpower_data) { + release_firmware(adapter->rgpower_data); + adapter->rgpower_data = NULL; + } + mwifiex_unregister(adapter); pr_debug("info: %s: free adapter\n", __func__); } @@ -642,7 +647,7 @@ static int _mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: - vfree(adapter->chan_stats); + kfree(adapter->chan_stats); err_init_chan_scan: wiphy_unregister(adapter->wiphy); wiphy_free(adapter->wiphy); @@ -1485,7 +1490,7 @@ static void mwifiex_uninit_sw(struct mwifiex_adapter *adapter) wiphy_free(adapter->wiphy); adapter->wiphy = NULL; - vfree(adapter->chan_stats); + kfree(adapter->chan_stats); mwifiex_free_cmd_buffers(adapter); } diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h index 9ac36bef980e..27559e2ddc31 100644 --- a/drivers/net/wireless/marvell/mwifiex/main.h +++ b/drivers/net/wireless/marvell/mwifiex/main.h @@ -982,6 +982,7 @@ struct mwifiex_adapter { u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; u16 max_mgmt_ie_index; const struct firmware *cal_data; + const struct firmware *rgpower_data; struct device_node *dt_node; /* 11AC */ @@ -1579,6 +1580,8 @@ int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv); int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv, struct device_node *node, const char *prefix); void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv); +int mwifiex_send_rgpower_table(struct mwifiex_private *priv, const u8 *data, + const size_t size); extern const struct ethtool_ops mwifiex_ethtool_ops; 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/mwifiex/sta_cmd.c b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c index c93281f5a47c..dcca71158fc6 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_cmd.c @@ -1483,6 +1483,119 @@ int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv, return 0; } +static int mwifiex_rgpower_table_advance_to_content(u8 **pos, const u8 *data, + const size_t size) +{ + while (*pos - data < size) { + /* skip spaces, tabs and empty lines */ + if (**pos == '\r' || **pos == '\n' || **pos == '\0' || + isspace(**pos)) { + (*pos)++; + continue; + } + /* skip line comments */ + if (**pos == '#') { + *pos = strchr(*pos, '\n'); + if (!*pos) + return -EINVAL; + (*pos)++; + continue; + } + return 0; + } + return 0; +} + +int mwifiex_send_rgpower_table(struct mwifiex_private *priv, const u8 *data, + const size_t size) +{ + int ret = 0; + bool start_raw = false; + u8 *ptr, *token, *pos = NULL; + u8 *_data __free(kfree) = NULL; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ds_misc_cmd *hostcmd __free(kfree) = NULL; + + hostcmd = kzalloc(sizeof(*hostcmd), GFP_KERNEL); + if (!hostcmd) + return -ENOMEM; + + _data = kmemdup(data, size, GFP_KERNEL); + if (!_data) + return -ENOMEM; + + pos = _data; + ptr = hostcmd->cmd; + while ((pos - _data) < size) { + ret = mwifiex_rgpower_table_advance_to_content(&pos, _data, size); + if (ret) { + mwifiex_dbg( + adapter, ERROR, + "%s: failed to advance to content in rgpower table\n", + __func__); + return ret; + } + + if (*pos == '}' && start_raw) { + hostcmd->len = get_unaligned_le16(&hostcmd->cmd[2]); + ret = mwifiex_send_cmd(priv, 0, 0, 0, hostcmd, false); + if (ret) { + mwifiex_dbg(adapter, ERROR, + "%s: failed to send hostcmd %d\n", + __func__, ret); + return ret; + } + + memset(hostcmd->cmd, 0, MWIFIEX_SIZE_OF_CMD_BUFFER); + ptr = hostcmd->cmd; + start_raw = false; + pos++; + continue; + } + + if (!start_raw) { + pos = strchr(pos, '='); + if (pos) { + pos = strchr(pos, '{'); + if (pos) { + start_raw = true; + pos++; + continue; + } + } + mwifiex_dbg(adapter, ERROR, + "%s: syntax error in hostcmd\n", __func__); + return -EINVAL; + } + + if (start_raw) { + while ((*pos != '\r' && *pos != '\n') && + (token = strsep((char **)&pos, " "))) { + if (ptr - hostcmd->cmd >= + MWIFIEX_SIZE_OF_CMD_BUFFER) { + mwifiex_dbg( + adapter, ERROR, + "%s: hostcmd is larger than %d, aborting\n", + __func__, MWIFIEX_SIZE_OF_CMD_BUFFER); + return -ENOMEM; + } + + ret = kstrtou8(token, 16, ptr); + if (ret < 0) { + mwifiex_dbg( + adapter, ERROR, + "%s: failed to parse hostcmd %d token: %s\n", + __func__, ret, token); + return ret; + } + ptr++; + } + } + } + + return ret; +} + /* This function prepares command of set_cfg_data. */ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf) diff --git a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c index f79589cafe57..ef6722ffdc74 100644 --- a/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/marvell/mwifiex/sta_ioctl.c @@ -180,7 +180,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); } -void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) +static void mwifiex_dnld_dt_txpwr_table(struct mwifiex_private *priv) { if (priv->adapter->dt_node) { char txpwr[] = {"marvell,00_txpwrlimit"}; @@ -190,6 +190,62 @@ void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) } } +static int mwifiex_request_rgpower_table(struct mwifiex_private *priv) +{ + struct mwifiex_802_11d_domain_reg *domain_info = &priv->adapter->domain_reg; + struct mwifiex_adapter *adapter = priv->adapter; + char rgpower_table_name[30]; + char country_code[3]; + + strscpy(country_code, domain_info->country_code, sizeof(country_code)); + + /* World regulatory domain "00" has WW as country code */ + if (strncmp(country_code, "00", 2) == 0) + strscpy(country_code, "WW", sizeof(country_code)); + + snprintf(rgpower_table_name, sizeof(rgpower_table_name), + "nxp/rgpower_%s.bin", country_code); + + mwifiex_dbg(adapter, INFO, "info: %s: requesting regulatory power table %s\n", + __func__, rgpower_table_name); + + if (adapter->rgpower_data) { + release_firmware(adapter->rgpower_data); + adapter->rgpower_data = NULL; + } + + if ((request_firmware(&adapter->rgpower_data, rgpower_table_name, + adapter->dev))) { + mwifiex_dbg( + adapter, INFO, + "info: %s: failed to request regulatory power table\n", + __func__); + return -EIO; + } + + return 0; +} + +static int mwifiex_dnld_rgpower_table(struct mwifiex_private *priv) +{ + int ret; + + ret = mwifiex_request_rgpower_table(priv); + if (ret) + return ret; + + return mwifiex_send_rgpower_table(priv, priv->adapter->rgpower_data->data, + priv->adapter->rgpower_data->size); +} + +void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) +{ + if (mwifiex_dnld_rgpower_table(priv) == 0) + return; + + mwifiex_dnld_dt_txpwr_table(priv); +} + static int mwifiex_process_country_ie(struct mwifiex_private *priv, struct cfg80211_bss *bss) { 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/agg-rx.c b/drivers/net/wireless/mediatek/mt76/agg-rx.c index 07c386c7b4d0..936ab1ca9246 100644 --- a/drivers/net/wireless/mediatek/mt76/agg-rx.c +++ b/drivers/net/wireless/mediatek/mt76/agg-rx.c @@ -173,6 +173,8 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames) if (ackp == IEEE80211_QOS_CTL_ACK_POLICY_NOACK) return; + if (wcid->def_wcid) + wcid = wcid->def_wcid; tid = rcu_dereference(wcid->aggr[tidno]); if (!tid) return; diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c index cc2d888e3f17..130af1b254db 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: @@ -314,21 +314,24 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, kfree(mlink); } -static void mt76_roc_complete(struct mt76_phy *phy) +void mt76_roc_complete(struct mt76_phy *phy) { struct mt76_vif_link *mlink = phy->roc_link; + struct mt76_dev *dev = phy->dev; if (!phy->roc_vif) return; if (mlink) mlink->mvif->roc_phy = NULL; - if (phy->main_chandef.chan) + if (phy->main_chandef.chan && + !test_bit(MT76_MCU_RESET, &dev->phy.state)) mt76_set_channel(phy, &phy->main_chandef, false); mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); phy->roc_vif = NULL; phy->roc_link = NULL; - ieee80211_remain_on_channel_expired(phy->hw); + if (!test_bit(MT76_MCU_RESET, &dev->phy.state)) + ieee80211_remain_on_channel_expired(phy->hw); } void mt76_roc_complete_work(struct work_struct *work) @@ -351,6 +354,7 @@ void mt76_abort_roc(struct mt76_phy *phy) mt76_roc_complete(phy); mutex_unlock(&dev->mutex); } +EXPORT_SYMBOL_GPL(mt76_abort_roc); int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration, @@ -368,7 +372,8 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mutex); - if (phy->roc_vif || dev->scan.phy == phy) { + if (phy->roc_vif || dev->scan.phy == phy || + test_bit(MT76_MCU_RESET, &dev->phy.state)) { ret = -EBUSY; goto out; } diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 35b4ec91979e..1fa7de1d2c45 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -186,6 +186,37 @@ mt76_free_pending_rxwi(struct mt76_dev *dev) EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi); static void +mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q) +{ + if (!mt76_queue_is_wed_rro(q)) + return; + + q->magic_cnt = 0; + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_desc *rro_desc; + u32 data1 = FIELD_PREP(RRO_IND_DATA1_MAGIC_CNT_MASK, + MT_DMA_WED_IND_CMD_CNT - 1); + int i; + + rro_desc = (struct mt76_wed_rro_desc *)q->desc; + for (i = 0; i < q->ndesc; i++) { + struct mt76_wed_rro_ind *cmd; + + cmd = (struct mt76_wed_rro_ind *)&rro_desc[i]; + cmd->data1 = cpu_to_le32(data1); + } + } else if (mt76_queue_is_wed_rro_rxdmad_c(q)) { + struct mt76_rro_rxdmad_c *dmad = (void *)q->desc; + u32 data3 = FIELD_PREP(RRO_RXDMAD_DATA3_MAGIC_CNT_MASK, + MT_DMA_MAGIC_CNT - 1); + int i; + + for (i = 0; i < q->ndesc; i++) + dmad[i].data3 = cpu_to_le32(data3); + } +} + +static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { Q_WRITE(q, desc_base, q->desc_dma); @@ -197,13 +228,14 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) q->tail = q->head; } -void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, - bool reset_idx) +void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx) { if (!q || !q->ndesc) return; - if (!mt76_queue_is_wed_rro_ind(q)) { + if (!mt76_queue_is_wed_rro_ind(q) && + !mt76_queue_is_wed_rro_rxdmad_c(q)) { int i; /* clear descriptors */ @@ -211,27 +243,26 @@ void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); } + mt76_dma_queue_magic_cnt_init(dev, q); if (reset_idx) { - Q_WRITE(q, cpu_idx, 0); + if (mt76_queue_is_emi(q)) + *q->emi_cpu_idx = 0; + else + Q_WRITE(q, cpu_idx, 0); Q_WRITE(q, dma_idx, 0); } mt76_dma_sync_idx(dev, q); } -void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) -{ - __mt76_dma_queue_reset(dev, q, true); -} - static int mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_buf *buf, void *data) { struct mt76_queue_entry *entry = &q->entry[q->head]; struct mt76_txwi_cache *txwi = NULL; + u32 buf1 = 0, ctrl, info = 0; struct mt76_desc *desc; int idx = q->head; - u32 buf1 = 0, ctrl; int rx_token; if (mt76_queue_is_wed_rro_ind(q)) { @@ -240,6 +271,9 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, rro_desc = (struct mt76_wed_rro_desc *)q->desc; data = &rro_desc[q->head]; goto done; + } else if (mt76_queue_is_wed_rro_rxdmad_c(q)) { + data = &q->desc[q->head]; + goto done; } desc = &q->desc[q->head]; @@ -248,7 +282,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32); #endif - if (mt76_queue_is_wed_rx(q)) { + if (mt76_queue_is_wed_rx(q) || mt76_queue_is_wed_rro_data(q)) { txwi = mt76_get_rxwi(dev); if (!txwi) return -ENOMEM; @@ -261,12 +295,26 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, buf1 |= FIELD_PREP(MT_DMA_CTL_TOKEN, rx_token); ctrl |= MT_DMA_CTL_TO_HOST; + + txwi->qid = q - dev->q_rx; + } + + if (mt76_queue_is_wed_rro_msdu_pg(q) && + dev->drv->rx_rro_add_msdu_page) { + if (dev->drv->rx_rro_add_msdu_page(dev, q, buf->addr, data)) + return -ENOMEM; + } + + if (q->flags & MT_QFLAG_WED_RRO_EN) { + info |= FIELD_PREP(MT_DMA_MAGIC_MASK, q->magic_cnt); + if ((q->head + 1) == q->ndesc) + q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_MAGIC_CNT; } WRITE_ONCE(desc->buf0, cpu_to_le32(buf->addr)); WRITE_ONCE(desc->buf1, cpu_to_le32(buf1)); WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); - WRITE_ONCE(desc->info, 0); + WRITE_ONCE(desc->info, cpu_to_le32(info)); done: entry->dma_addr[0] = buf->addr; @@ -375,7 +423,10 @@ static void mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) { wmb(); - Q_WRITE(q, cpu_idx, q->head); + if (mt76_queue_is_emi(q)) + *q->emi_cpu_idx = cpu_to_le16(q->head); + else + Q_WRITE(q, cpu_idx, q->head); } static void @@ -419,15 +470,61 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) } static void * +mt76_dma_get_rxdmad_c_buf(struct mt76_dev *dev, struct mt76_queue *q, + int idx, int *len, bool *more) +{ + struct mt76_queue_entry *e = &q->entry[idx]; + struct mt76_rro_rxdmad_c *dmad = e->buf; + u32 data1 = le32_to_cpu(dmad->data1); + u32 data2 = le32_to_cpu(dmad->data2); + struct mt76_txwi_cache *t; + u16 rx_token_id; + u8 ind_reason; + void *buf; + + rx_token_id = FIELD_GET(RRO_RXDMAD_DATA2_RX_TOKEN_ID_MASK, data2); + t = mt76_rx_token_release(dev, rx_token_id); + if (!t) + return ERR_PTR(-EAGAIN); + + q = &dev->q_rx[t->qid]; + dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr, + SKB_WITH_OVERHEAD(q->buf_size), + page_pool_get_dma_dir(q->page_pool)); + + if (len) + *len = FIELD_GET(RRO_RXDMAD_DATA1_SDL0_MASK, data1); + if (more) + *more = !FIELD_GET(RRO_RXDMAD_DATA1_LS_MASK, data1); + + buf = t->ptr; + ind_reason = FIELD_GET(RRO_RXDMAD_DATA2_IND_REASON_MASK, data2); + if (ind_reason == MT_DMA_WED_IND_REASON_REPEAT || + ind_reason == MT_DMA_WED_IND_REASON_OLDPKT) { + mt76_put_page_pool_buf(buf, false); + buf = ERR_PTR(-EAGAIN); + } + t->ptr = NULL; + t->dma_addr = 0; + + mt76_put_rxwi(dev, t); + + return buf; +} + +static void * mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, - int *len, u32 *info, bool *more, bool *drop) + int *len, u32 *info, bool *more, bool *drop, bool flush) { struct mt76_queue_entry *e = &q->entry[idx]; struct mt76_desc *desc = &q->desc[idx]; u32 ctrl, desc_info, buf1; void *buf = e->buf; - if (mt76_queue_is_wed_rro_ind(q)) + if (mt76_queue_is_wed_rro_rxdmad_c(q) && !flush) + buf = mt76_dma_get_rxdmad_c_buf(dev, q, idx, len, more); + + if (mt76_queue_is_wed_rro(q)) goto done; ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); @@ -482,20 +579,50 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, if (!q->queued) return NULL; - if (mt76_queue_is_wed_rro_data(q)) - return NULL; + if (mt76_queue_is_wed_rro_data(q) || mt76_queue_is_wed_rro_msdu_pg(q)) + goto done; + + if (mt76_queue_is_wed_rro_ind(q)) { + struct mt76_wed_rro_ind *cmd; + u8 magic_cnt; + + if (flush) + goto done; + + cmd = q->entry[idx].buf; + magic_cnt = FIELD_GET(RRO_IND_DATA1_MAGIC_CNT_MASK, + le32_to_cpu(cmd->data1)); + if (magic_cnt != q->magic_cnt) + return NULL; + + if (q->tail == q->ndesc - 1) + q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_WED_IND_CMD_CNT; + } else if (mt76_queue_is_wed_rro_rxdmad_c(q)) { + struct mt76_rro_rxdmad_c *dmad; + u16 magic_cnt; + + if (flush) + goto done; + + dmad = q->entry[idx].buf; + magic_cnt = FIELD_GET(RRO_RXDMAD_DATA3_MAGIC_CNT_MASK, + le32_to_cpu(dmad->data3)); + if (magic_cnt != q->magic_cnt) + return NULL; - if (!mt76_queue_is_wed_rro_ind(q)) { + if (q->tail == q->ndesc - 1) + q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_MAGIC_CNT; + } else { if (flush) q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) return NULL; } - +done: q->tail = (q->tail + 1) % q->ndesc; q->queued--; - return mt76_dma_get_buf(dev, q, idx, len, info, more, drop); + return mt76_dma_get_buf(dev, q, idx, len, info, more, drop, flush); } static int @@ -643,23 +770,19 @@ 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)) + if (mt76_queue_is_wed_rro_ind(q) || + mt76_queue_is_wed_rro_rxdmad_c(q)) goto done; buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); 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; @@ -681,9 +804,6 @@ int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, { int frames; - if (!q->ndesc) - return 0; - spin_lock_bh(&q->lock); frames = mt76_dma_rx_fill_buf(dev, q, allow_direct); spin_unlock_bh(&q->lock); @@ -713,19 +833,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, if (!q->desc) return -ENOMEM; - if (mt76_queue_is_wed_rro_ind(q)) { - struct mt76_wed_rro_desc *rro_desc; - int i; - - rro_desc = (struct mt76_wed_rro_desc *)q->desc; - for (i = 0; i < q->ndesc; i++) { - struct mt76_wed_rro_ind *cmd; - - cmd = (struct mt76_wed_rro_ind *)&rro_desc[i]; - cmd->magic_cnt = MT_DMA_WED_IND_CMD_CNT - 1; - } - } - + mt76_dma_queue_magic_cnt_init(dev, q); size = q->ndesc * sizeof(*q->entry); q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL); if (!q->entry) @@ -745,7 +853,10 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, return 0; } - mt76_dma_queue_reset(dev, q); + /* HW specific driver is supposed to reset brand-new EMI queues since + * it needs to set cpu index pointer. + */ + mt76_dma_queue_reset(dev, q, !mt76_queue_is_emi(q)); return 0; } @@ -788,7 +899,8 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) if (!q->ndesc) return; - if (!mt76_queue_is_wed_rro_ind(q)) { + if (!mt76_queue_is_wed_rro_ind(q) && + !mt76_queue_is_wed_rro_rxdmad_c(q)) { int i; for (i = 0; i < q->ndesc; i++) @@ -848,8 +960,9 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) bool allow_direct = !mt76_queue_is_wed_rx(q); bool more; - if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && - mt76_queue_is_wed_tx_free(q)) { + if ((q->flags & MT_QFLAG_WED_RRO_EN) || + (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && + mt76_queue_is_wed_tx_free(q))) { dma_idx = Q_READ(q, dma_idx); check_ddone = true; } @@ -871,6 +984,20 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) if (!data) break; + if (PTR_ERR(data) == -EAGAIN) { + done++; + continue; + } + + if (mt76_queue_is_wed_rro_ind(q) && dev->drv->rx_rro_ind_process) + dev->drv->rx_rro_ind_process(dev, data); + + if (mt76_queue_is_wed_rro(q) && + !mt76_queue_is_wed_rro_rxdmad_c(q)) { + done++; + continue; + } + if (drop) goto free_frag; @@ -948,6 +1075,15 @@ int mt76_dma_rx_poll(struct napi_struct *napi, int budget) } EXPORT_SYMBOL_GPL(mt76_dma_rx_poll); +static void +mt76_dma_rx_queue_init(struct mt76_dev *dev, enum mt76_rxq_id qid, + int (*poll)(struct napi_struct *napi, int budget)) +{ + netif_napi_add(dev->napi_dev, &dev->napi[qid], poll); + mt76_dma_rx_fill_buf(dev, &dev->q_rx[qid], false); + napi_enable(&dev->napi[qid]); +} + static int mt76_dma_init(struct mt76_dev *dev, int (*poll)(struct napi_struct *napi, int budget)) @@ -980,9 +1116,10 @@ mt76_dma_init(struct mt76_dev *dev, init_completion(&dev->mmio.wed_reset_complete); mt76_for_each_q_rx(dev, i) { - netif_napi_add(dev->napi_dev, &dev->napi[i], poll); - mt76_dma_rx_fill_buf(dev, &dev->q_rx[i], false); - napi_enable(&dev->napi[i]); + if (mt76_queue_is_wed_rro(&dev->q_rx[i])) + continue; + + mt76_dma_rx_queue_init(dev, i, poll); } return 0; @@ -995,6 +1132,7 @@ static const struct mt76_queue_ops mt76_dma_ops = { .tx_queue_skb_raw = mt76_dma_tx_queue_skb_raw, .tx_queue_skb = mt76_dma_tx_queue_skb, .tx_cleanup = mt76_dma_tx_cleanup, + .rx_queue_init = mt76_dma_rx_queue_init, .rx_cleanup = mt76_dma_rx_cleanup, .rx_reset = mt76_dma_rx_reset, .kick = mt76_dma_kick_queue, diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index e3ddc7a83757..17a80e1757fc 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -31,7 +31,12 @@ #define MT_DMA_CTL_PN_CHK_FAIL BIT(13) #define MT_DMA_CTL_VER_MASK BIT(7) -#define MT_DMA_RRO_EN BIT(13) +#define MT_DMA_SDP0 GENMASK(15, 0) +#define MT_DMA_TOKEN_ID GENMASK(31, 16) +#define MT_DMA_MAGIC_MASK GENMASK(31, 28) +#define MT_DMA_RRO_EN BIT(13) + +#define MT_DMA_MAGIC_CNT 16 #define MT_DMA_WED_IND_CMD_CNT 8 #define MT_DMA_WED_IND_REASON GENMASK(15, 12) @@ -53,6 +58,21 @@ struct mt76_wed_rro_desc { __le32 buf1; } __packed __aligned(4); +/* data1 */ +#define RRO_RXDMAD_DATA1_LS_MASK BIT(30) +#define RRO_RXDMAD_DATA1_SDL0_MASK GENMASK(29, 16) +/* data2 */ +#define RRO_RXDMAD_DATA2_RX_TOKEN_ID_MASK GENMASK(31, 16) +#define RRO_RXDMAD_DATA2_IND_REASON_MASK GENMASK(15, 12) +/* data3 */ +#define RRO_RXDMAD_DATA3_MAGIC_CNT_MASK GENMASK(31, 28) +struct mt76_rro_rxdmad_c { + __le32 data0; + __le32 data1; + __le32 data2; + __le32 data3; +}; + enum mt76_qsel { MT_QSEL_MGMT, MT_QSEL_HCCA, @@ -81,14 +101,13 @@ void mt76_dma_attach(struct mt76_dev *dev); void mt76_dma_cleanup(struct mt76_dev *dev); int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, bool allow_direct); -void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, - bool reset_idx); -void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q); +void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx); static inline void mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) { - dev->queue_ops->reset_q(dev, q); + dev->queue_ops->reset_q(dev, q, true); if (mtk_wed_device_active(&dev->mmio.wed)) mt76_wed_dma_setup(dev, q, true); } diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 443517d06c9f..a987c5e4eff6 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -163,13 +163,16 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len) return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len); } -void +int mt76_eeprom_override(struct mt76_phy *phy) { struct mt76_dev *dev = phy->dev; struct device_node *np = dev->dev->of_node; + int err; - of_get_mac_address(np, phy->macaddr); + err = of_get_mac_address(np, phy->macaddr); + if (err == -EPROBE_DEFER) + return err; if (!is_valid_ether_addr(phy->macaddr)) { eth_random_addr(phy->macaddr); @@ -177,6 +180,8 @@ mt76_eeprom_override(struct mt76_phy *phy) "Invalid MAC address, using random address %pM\n", phy->macaddr); } + + return 0; } EXPORT_SYMBOL_GPL(mt76_eeprom_override); diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 45c8db939d55..5ceaf78c9ea0 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -818,6 +818,48 @@ void mt76_free_device(struct mt76_dev *dev) } EXPORT_SYMBOL_GPL(mt76_free_device); +static void mt76_reset_phy(struct mt76_phy *phy) +{ + if (!phy) + return; + + INIT_LIST_HEAD(&phy->tx_list); + phy->num_sta = 0; + phy->chanctx = NULL; + mt76_roc_complete(phy); +} + +void mt76_reset_device(struct mt76_dev *dev) +{ + int i; + + rcu_read_lock(); + for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) { + struct mt76_wcid *wcid; + + wcid = rcu_dereference(dev->wcid[i]); + if (!wcid) + continue; + + wcid->sta = 0; + mt76_wcid_cleanup(dev, wcid); + rcu_assign_pointer(dev->wcid[i], NULL); + } + rcu_read_unlock(); + + mt76_abort_scan(dev); + + INIT_LIST_HEAD(&dev->wcid_list); + INIT_LIST_HEAD(&dev->sta_poll_list); + dev->vif_mask = 0; + memset(dev->wcid_mask, 0, sizeof(dev->wcid_mask)); + + mt76_reset_phy(&dev->phy); + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) + mt76_reset_phy(dev->phys[i]); +} +EXPORT_SYMBOL_GPL(mt76_reset_device); + struct mt76_phy *mt76_vif_phy(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { @@ -1198,6 +1240,8 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, mstat = *((struct mt76_rx_status *)skb->cb); memset(status, 0, sizeof(*status)); + skb->priority = mstat.qos_ctl & IEEE80211_QOS_CTL_TID_MASK; + status->flag = mstat.flag; status->freq = mstat.freq; status->enc_flags = mstat.enc_flags; @@ -1679,6 +1723,10 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) skb_queue_splice_tail_init(&wcid->tx_pending, &list); spin_unlock(&wcid->tx_pending.lock); + spin_lock(&wcid->tx_offchannel.lock); + skb_queue_splice_tail_init(&wcid->tx_offchannel, &list); + spin_unlock(&wcid->tx_offchannel.lock); + spin_unlock_bh(&phy->tx_lock); while ((skb = __skb_dequeue(&list)) != NULL) { @@ -1690,7 +1738,7 @@ EXPORT_SYMBOL_GPL(mt76_wcid_cleanup); void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid) { - if (test_bit(MT76_MCU_RESET, &dev->phy.state)) + if (test_bit(MT76_MCU_RESET, &dev->phy.state) || !wcid->sta) return; spin_lock_bh(&dev->sta_poll_lock); @@ -1892,7 +1940,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; @@ -2018,3 +2067,55 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif) mt76_abort_roc(mvif->roc_phy); } EXPORT_SYMBOL_GPL(mt76_vif_cleanup); + +u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links) +{ + unsigned long usable_links = ieee80211_vif_usable_links(vif); + struct { + u8 link_id; + enum nl80211_band band; + } data[IEEE80211_MLD_MAX_NUM_LINKS]; + unsigned int link_id; + int i, n_data = 0; + u16 sel_links = 0; + + if (!ieee80211_vif_is_mld(vif)) + return 0; + + if (vif->active_links == usable_links) + return vif->active_links; + + rcu_read_lock(); + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf; + + link_conf = rcu_dereference(vif->link_conf[link_id]); + if (WARN_ON_ONCE(!link_conf)) + continue; + + data[n_data].link_id = link_id; + data[n_data].band = link_conf->chanreq.oper.chan->band; + n_data++; + } + rcu_read_unlock(); + + for (i = 0; i < n_data; i++) { + int j; + + if (!(BIT(data[i].link_id) & vif->active_links)) + continue; + + sel_links = BIT(data[i].link_id); + for (j = 0; j < n_data; j++) { + if (data[i].band != data[j].band) { + sel_links |= BIT(data[j].link_id); + if (hweight16(sel_links) == max_active_links) + break; + } + } + break; + } + + return sel_links; +} +EXPORT_SYMBOL_GPL(mt76_select_links); 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..e0d50b58cd01 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -33,6 +33,7 @@ #define MT_QFLAG_WED BIT(5) #define MT_QFLAG_WED_RRO BIT(6) #define MT_QFLAG_WED_RRO_EN BIT(7) +#define MT_QFLAG_EMI_EN BIT(8) #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ @@ -45,6 +46,7 @@ #define MT_WED_RRO_Q_DATA(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_DATA, _n) #define MT_WED_RRO_Q_MSDU_PG(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_MSDU_PG, _n) #define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0) +#define MT_WED_RRO_Q_RXDMAD_C __MT_WED_RRO_Q(MT76_WED_RRO_Q_RXDMAD_C, 0) struct mt76_dev; struct mt76_phy; @@ -71,6 +73,13 @@ enum mt76_wed_type { MT76_WED_RRO_Q_DATA, MT76_WED_RRO_Q_MSDU_PG, MT76_WED_RRO_Q_IND, + MT76_WED_RRO_Q_RXDMAD_C, +}; + +enum mt76_hwrro_mode { + MT76_HWRRO_OFF, + MT76_HWRRO_V3, + MT76_HWRRO_V3_1, }; struct mt76_bus_ops { @@ -129,6 +138,7 @@ enum mt76_rxq_id { MT_RXQ_TXFREE_BAND1, MT_RXQ_TXFREE_BAND2, MT_RXQ_RRO_IND, + MT_RXQ_RRO_RXDMAD_C, __MT_RXQ_MAX }; @@ -232,6 +242,9 @@ struct mt76_queue { u8 buf_offset; u16 flags; + u8 magic_cnt; + + __le16 *emi_cpu_idx; struct mtk_wed_device *wed; u32 wed_regs; @@ -286,11 +299,15 @@ struct mt76_queue_ops { void (*tx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q, bool flush); + void (*rx_queue_init)(struct mt76_dev *dev, enum mt76_rxq_id qid, + int (*poll)(struct napi_struct *napi, int budget)); + void (*rx_cleanup)(struct mt76_dev *dev, struct mt76_queue *q); void (*kick)(struct mt76_dev *dev, struct mt76_queue *q); - void (*reset_q)(struct mt76_dev *dev, struct mt76_queue *q); + void (*reset_q)(struct mt76_dev *dev, struct mt76_queue *q, + bool reset_idx); }; enum mt76_phy_type { @@ -398,15 +415,16 @@ struct mt76_txq { bool aggr; }; +/* data0 */ +#define RRO_IND_DATA0_IND_REASON_MASK GENMASK(31, 28) +#define RRO_IND_DATA0_START_SEQ_MASK GENMASK(27, 16) +#define RRO_IND_DATA0_SEQ_ID_MASK GENMASK(11, 0) +/* data1 */ +#define RRO_IND_DATA1_MAGIC_CNT_MASK GENMASK(31, 29) +#define RRO_IND_DATA1_IND_COUNT_MASK GENMASK(12, 0) struct mt76_wed_rro_ind { - u32 se_id : 12; - u32 rsv : 4; - u32 start_sn : 12; - u32 ind_reason : 4; - u32 ind_cnt : 13; - u32 win_sz : 3; - u32 rsv2 : 13; - u32 magic_cnt : 3; + __le32 data0; + __le32 data1; }; struct mt76_txwi_cache { @@ -417,6 +435,8 @@ struct mt76_txwi_cache { struct sk_buff *skb; void *ptr; }; + + u8 qid; }; struct mt76_rx_tid { @@ -533,6 +553,10 @@ struct mt76_driver_ops { void (*rx_poll_complete)(struct mt76_dev *dev, enum mt76_rxq_id q); + void (*rx_rro_ind_process)(struct mt76_dev *dev, void *data); + int (*rx_rro_add_msdu_page)(struct mt76_dev *dev, struct mt76_queue *q, + dma_addr_t p, void *data); + void (*sta_ps)(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps); @@ -910,6 +934,7 @@ struct mt76_dev { struct mt76_queue q_rx[__MT_RXQ_MAX]; const struct mt76_queue_ops *queue_ops; int tx_dma_idx[4]; + enum mt76_hwrro_mode hwrro_mode; struct mt76_worker tx_worker; struct napi_struct tx_napi; @@ -983,6 +1008,8 @@ struct mt76_dev { struct mt76_usb usb; struct mt76_sdio sdio; }; + + atomic_t bus_hung; }; /* per-phy stats. */ @@ -1212,6 +1239,7 @@ static inline int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, #define mt76_tx_queue_skb(dev, ...) (dev)->mt76.queue_ops->tx_queue_skb(&((dev)->mphy), __VA_ARGS__) #define mt76_queue_rx_reset(dev, ...) (dev)->mt76.queue_ops->rx_reset(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_tx_cleanup(dev, ...) (dev)->mt76.queue_ops->tx_cleanup(&((dev)->mt76), __VA_ARGS__) +#define mt76_queue_rx_init(dev, ...) (dev)->mt76.queue_ops->rx_queue_init(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_rx_cleanup(dev, ...) (dev)->mt76.queue_ops->rx_cleanup(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_kick(dev, ...) (dev)->mt76.queue_ops->kick(&((dev)->mt76), __VA_ARGS__) #define mt76_queue_reset(dev, ...) (dev)->mt76.queue_ops->reset_q(&((dev)->mt76), __VA_ARGS__) @@ -1241,6 +1269,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, struct ieee80211_rate *rates, int n_rates); void mt76_unregister_device(struct mt76_dev *dev); void mt76_free_device(struct mt76_dev *dev); +void mt76_reset_device(struct mt76_dev *dev); void mt76_unregister_phy(struct mt76_phy *phy); struct mt76_phy *mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size, @@ -1265,7 +1294,7 @@ void mt76_seq_puts_array(struct seq_file *file, const char *str, s8 *val, int len); int mt76_eeprom_init(struct mt76_dev *dev, int len); -void mt76_eeprom_override(struct mt76_phy *phy); +int mt76_eeprom_override(struct mt76_phy *phy); int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len); int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep, const char *cell_name, int len); @@ -1523,7 +1552,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, @@ -1613,6 +1643,7 @@ int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, void mt76_scan_work(struct work_struct *work); void mt76_abort_scan(struct mt76_dev *dev); void mt76_roc_complete_work(struct work_struct *work); +void mt76_roc_complete(struct mt76_phy *phy); void mt76_abort_roc(struct mt76_phy *phy); struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif); @@ -1778,21 +1809,34 @@ static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q) FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_IND; } +static inline bool mt76_queue_is_wed_rro_rxdmad_c(struct mt76_queue *q) +{ + return mt76_queue_is_wed_rro(q) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_RXDMAD_C; +} + static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q) { return mt76_queue_is_wed_rro(q) && - (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA || - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_MSDU_PG); + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA; } -static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) +static inline bool mt76_queue_is_wed_rro_msdu_pg(struct mt76_queue *q) { - if (!(q->flags & MT_QFLAG_WED)) - return false; + return mt76_queue_is_wed_rro(q) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == + MT76_WED_RRO_Q_MSDU_PG; +} - return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX || - mt76_queue_is_wed_rro_ind(q) || mt76_queue_is_wed_rro_data(q); +static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) +{ + return (q->flags & MT_QFLAG_WED) && + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; +} +static inline bool mt76_queue_is_emi(struct mt76_queue *q) +{ + return q->flags & MT_QFLAG_EMI_EN; } struct mt76_txwi_cache * @@ -1807,7 +1851,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 * @@ -1867,6 +1912,7 @@ mt76_vif_init(struct ieee80211_vif *vif, struct mt76_vif_data *mvif) } void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif); +u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links); static inline struct mt76_vif_link * mt76_vif_link(struct mt76_dev *dev, struct ieee80211_vif *vif, int link_id) @@ -1874,6 +1920,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 +1933,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/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c index f5a6b03bc61d..88382b537a33 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c @@ -182,7 +182,6 @@ int mt7603_eeprom_init(struct mt7603_dev *dev) dev->mphy.antenna_mask = 1; dev->mphy.chainmask = dev->mphy.antenna_mask; - mt76_eeprom_override(&dev->mphy); - return 0; + return mt76_eeprom_override(&dev->mphy); } 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/mt7603/soc.c b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c index 08590aa68356..1dd372372048 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/soc.c @@ -48,7 +48,7 @@ mt76_wmac_probe(struct platform_device *pdev) return 0; error: - ieee80211_free_hw(mt76_hw(dev)); + mt76_free_device(mdev); return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c index ccedea7e8a50..d4bc7e11e772 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c @@ -351,8 +351,6 @@ int mt7615_eeprom_init(struct mt7615_dev *dev, u32 addr) memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, ETH_ALEN); - mt76_eeprom_override(&dev->mphy); - - return 0; + return mt76_eeprom_override(&dev->mphy); } EXPORT_SYMBOL_GPL(mt7615_eeprom_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index aae80005a3c1..3e7af3e58736 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -570,7 +570,10 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) ETH_ALEN); mphy->macaddr[0] |= 2; mphy->macaddr[0] ^= BIT(7); - mt76_eeprom_override(mphy); + + ret = mt76_eeprom_override(mphy); + if (ret) + return ret; /* second phy can only handle 5 GHz */ mphy->cap.has_5ghz = true; 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/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 1013cad57a7f..c5eaedca11e0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -294,6 +294,13 @@ enum tx_frag_idx { #define MT_TXP_BUF_LEN GENMASK(11, 0) #define MT_TXP_DMA_ADDR_H GENMASK(15, 12) +#define MT_TXP0_TOKEN_ID0 GENMASK(14, 0) +#define MT_TXP0_TOKEN_ID0_VALID_MASK BIT(15) + +#define MT_TXP1_TID_ADDBA GENMASK(14, 12) +#define MT_TXP3_ML0_MASK BIT(15) +#define MT_TXP3_DMA_ADDR_H GENMASK(13, 12) + #define MT_TX_RATE_STBC BIT(14) #define MT_TX_RATE_NSS GENMASK(13, 10) #define MT_TX_RATE_MODE GENMASK(9, 6) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 16db0f2082d1..fc3e6728fcfb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -1662,6 +1662,31 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, return err; } + if (enable && vif->bss_conf.bssid_indicator) { + struct { + struct { + u8 bss_idx; + u8 pad[3]; + } __packed hdr; + struct bss_info_uni_mbssid mbssid; + } mbssid_req = { + .hdr = { + .bss_idx = mvif->idx, + }, + .mbssid = { + .tag = cpu_to_le16(UNI_BSS_INFO_11V_MBSSID), + .len = cpu_to_le16(sizeof(struct bss_info_uni_mbssid)), + .max_indicator = vif->bss_conf.bssid_indicator, + .mbss_idx = vif->bss_conf.bssid_index, + }, + }; + + err = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(BSS_INFO_UPDATE), + &mbssid_req, sizeof(mbssid_req), true); + if (err < 0) + return err; + } + return mt76_connac_mcu_uni_set_chctx(phy, mvif, ctx); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_bss); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c index 4de45a56812d..d4506b8b46fa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x0/eeprom.c @@ -332,7 +332,11 @@ int mt76x0_eeprom_init(struct mt76x02_dev *dev) memcpy(dev->mphy.macaddr, (u8 *)dev->mt76.eeprom.data + MT_EE_MAC_ADDR, ETH_ALEN); - mt76_eeprom_override(&dev->mphy); + + err = mt76_eeprom_override(&dev->mphy); + if (err) + return err; + mt76x02_mac_setaddr(dev, dev->mphy.macaddr); mt76x0_set_chip_cap(dev); 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/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c index 156b16c17b2b..221805deb42f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x2/eeprom.c @@ -499,7 +499,9 @@ int mt76x2_eeprom_init(struct mt76x02_dev *dev) mt76x02_eeprom_parse_hw_cap(dev); mt76x2_eeprom_get_macaddr(dev); - mt76_eeprom_override(&dev->mphy); + ret = mt76_eeprom_override(&dev->mphy); + if (ret) + return ret; dev->mphy.macaddr[0] &= ~BIT(1); return 0; 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/dma.c b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c index 0c62272fe7d0..009ef713f437 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/dma.c @@ -624,13 +624,13 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force) } for (i = 0; i < __MT_MCUQ_MAX; i++) - mt76_queue_reset(dev, dev->mt76.q_mcu[i]); + mt76_queue_reset(dev, dev->mt76.q_mcu[i], true); mt76_for_each_q_rx(&dev->mt76, i) { if (mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) continue; - mt76_queue_reset(dev, &dev->mt76.q_rx[i]); + mt76_queue_reset(dev, &dev->mt76.q_rx[i], true); } mt76_tx_status_check(&dev->mt76, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index c0f3402d30bb..38dfd5de365c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -284,9 +284,7 @@ int mt7915_eeprom_init(struct mt7915_dev *dev) memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, ETH_ALEN); - mt76_eeprom_override(&dev->mphy); - - return 0; + return mt76_eeprom_override(&dev->mphy); } int mt7915_eeprom_get_target_power(struct mt7915_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h index 31aec0f40232..73611c9d26e1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.h @@ -50,9 +50,9 @@ enum mt7915_eeprom_field { #define MT_EE_CAL_GROUP_SIZE_7975 (54 * MT_EE_CAL_UNIT + 16) #define MT_EE_CAL_GROUP_SIZE_7976 (94 * MT_EE_CAL_UNIT + 16) #define MT_EE_CAL_GROUP_SIZE_7916_6G (94 * MT_EE_CAL_UNIT + 16) +#define MT_EE_CAL_GROUP_SIZE_7981 (144 * MT_EE_CAL_UNIT + 16) #define MT_EE_CAL_DPD_SIZE_V1 (54 * MT_EE_CAL_UNIT) #define MT_EE_CAL_DPD_SIZE_V2 (300 * MT_EE_CAL_UNIT) -#define MT_EE_CAL_DPD_SIZE_V2_7981 (102 * MT_EE_CAL_UNIT) /* no 6g dpd data */ #define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0) #define MT_EE_WIFI_CONF0_RX_PATH GENMASK(5, 3) @@ -180,6 +180,8 @@ mt7915_get_cal_group_size(struct mt7915_dev *dev) val = FIELD_GET(MT_EE_WIFI_CONF0_BAND_SEL, val); return (val == MT_EE_V2_BAND_SEL_6GHZ) ? MT_EE_CAL_GROUP_SIZE_7916_6G : MT_EE_CAL_GROUP_SIZE_7916; + } else if (is_mt7981(&dev->mt76)) { + return MT_EE_CAL_GROUP_SIZE_7981; } else if (mt7915_check_adie(dev, false)) { return MT_EE_CAL_GROUP_SIZE_7976; } else { @@ -192,8 +194,6 @@ mt7915_get_cal_dpd_size(struct mt7915_dev *dev) { if (is_mt7915(&dev->mt76)) return MT_EE_CAL_DPD_SIZE_V1; - else if (is_mt7981(&dev->mt76)) - return MT_EE_CAL_DPD_SIZE_V2_7981; else return MT_EE_CAL_DPD_SIZE_V2; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 3e30ca5155d2..5ea8b46e092e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -702,7 +702,9 @@ mt7915_register_ext_phy(struct mt7915_dev *dev, struct mt7915_phy *phy) mphy->macaddr[0] |= 2; mphy->macaddr[0] ^= BIT(7); } - mt76_eeprom_override(mphy); + ret = mt76_eeprom_override(mphy); + if (ret) + return ret; /* init wiphy according to mphy and phy */ mt7915_init_wiphy(phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index 6639976afcee..1c0d310146d6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -1460,17 +1460,15 @@ mt7915_mac_full_reset(struct mt7915_dev *dev) if (i == 10) dev_err(dev->mt76.dev, "chip full reset failed\n"); - spin_lock_bh(&dev->mt76.sta_poll_lock); - while (!list_empty(&dev->mt76.sta_poll_list)) - list_del_init(dev->mt76.sta_poll_list.next); - spin_unlock_bh(&dev->mt76.sta_poll_lock); - - memset(dev->mt76.wcid_mask, 0, sizeof(dev->mt76.wcid_mask)); - dev->mt76.vif_mask = 0; dev->phy.omac_mask = 0; if (phy2) phy2->omac_mask = 0; + mt76_reset_device(&dev->mt76); + + INIT_LIST_HEAD(&dev->sta_rc_list); + INIT_LIST_HEAD(&dev->twt_list); + i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA); dev->mt76.global_wcid.idx = i; dev->recovery.hw_full_reset = false; 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..c1fdd3c4f1ba 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)); @@ -3042,30 +3052,15 @@ static int mt7915_dpd_freq_idx(struct mt7915_dev *dev, u16 freq, u8 bw) /* 5G BW160 */ 5250, 5570, 5815 }; - static const u16 freq_list_v2_7981[] = { - /* 5G BW20 */ - 5180, 5200, 5220, 5240, - 5260, 5280, 5300, 5320, - 5500, 5520, 5540, 5560, - 5580, 5600, 5620, 5640, - 5660, 5680, 5700, 5720, - 5745, 5765, 5785, 5805, - 5825, 5845, 5865, 5885, - /* 5G BW160 */ - 5250, 5570, 5815 - }; - const u16 *freq_list = freq_list_v1; - int n_freqs = ARRAY_SIZE(freq_list_v1); - int idx; + const u16 *freq_list; + int idx, n_freqs; if (!is_mt7915(&dev->mt76)) { - if (is_mt7981(&dev->mt76)) { - freq_list = freq_list_v2_7981; - n_freqs = ARRAY_SIZE(freq_list_v2_7981); - } else { - freq_list = freq_list_v2; - n_freqs = ARRAY_SIZE(freq_list_v2); - } + freq_list = freq_list_v2; + n_freqs = ARRAY_SIZE(freq_list_v2); + } else { + freq_list = freq_list_v1; + n_freqs = ARRAY_SIZE(freq_list_v1); } if (freq < 4000) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 4a82f8e4c118..36488aa6cc20 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -664,8 +664,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, MT_RXQ_WED_RING_BASE; wed->wlan.wpdma_rx_glo = pci_resource_start(pci_dev, 0) + MT_WPDMA_GLO_CFG; - wed->wlan.wpdma_rx = pci_resource_start(pci_dev, 0) + - MT_RXQ_WED_DATA_RING_BASE; + wed->wlan.wpdma_rx[0] = pci_resource_start(pci_dev, 0) + + MT_RXQ_WED_DATA_RING_BASE; } else { struct platform_device *plat_dev = pdev_ptr; struct resource *res; @@ -687,7 +687,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, wed->wlan.wpdma_tx = res->start + MT_TXQ_WED_RING_BASE; wed->wlan.wpdma_txfree = res->start + MT_RXQ_WED_RING_BASE; wed->wlan.wpdma_rx_glo = res->start + MT_WPDMA_GLO_CFG; - wed->wlan.wpdma_rx = res->start + MT_RXQ_WED_DATA_RING_BASE; + wed->wlan.wpdma_rx[0] = res->start + MT_RXQ_WED_DATA_RING_BASE; } wed->wlan.nbuf = MT7915_HW_TOKEN_SIZE; wed->wlan.tx_tbit[0] = is_mt7915(&dev->mt76) ? 4 : 30; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 14e17dc90256..b9098a7331b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -189,7 +189,9 @@ static int __mt7921_init_hardware(struct mt792x_dev *dev) if (ret) goto out; - mt76_eeprom_override(&dev->mphy); + ret = mt76_eeprom_override(&dev->mphy); + if (ret) + goto out; ret = mt7921_mcu_set_eeprom(dev); if (ret) 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..67383c41a319 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -135,6 +135,8 @@ mt7921_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, if (is_mt7922(phy->mt76->dev)) { he_cap_elem->phy_cap_info[0] |= IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + he_cap_elem->phy_cap_info[4] |= + IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4; he_cap_elem->phy_cap_info[8] |= IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU; @@ -624,7 +626,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 +909,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 +1091,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); @@ -1457,11 +1461,8 @@ static int mt7921_pre_channel_switch(struct ieee80211_hw *hw, if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) return -EOPNOTSUPP; - /* Avoid beacon loss due to the CAC(Channel Availability Check) time - * of the AP. - */ if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef, - IEEE80211_CHAN_RADAR)) + IEEE80211_CHAN_DISABLED)) return -EOPNOTSUPP; return 0; 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/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c index fe9751851ff7..100bdba32ba5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c @@ -21,6 +21,9 @@ static const struct usb_device_id mt7921u_device_table[] = { /* Netgear, Inc. [A8000,AXE3000] */ { USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9060, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, + /* Netgear, Inc. A7500 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9065, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, /* TP-Link TXE50UH */ { USB_DEVICE_AND_INTERFACE_INFO(0x35bc, 0x0107, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM }, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index 4249bad83c93..d7d5afe365ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -249,7 +249,9 @@ static int __mt7925_init_hardware(struct mt792x_dev *dev) if (ret) goto out; - mt76_eeprom_override(&dev->mphy); + ret = mt76_eeprom_override(&dev->mphy); + if (ret) + goto out; ret = mt7925_mcu_set_eeprom(dev); if (ret) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 75823c9fd3a1..1e44e96f034e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -1300,7 +1300,6 @@ void mt7925_mac_reset_work(struct work_struct *work) cancel_delayed_work_sync(&dev->mphy.mac_work); cancel_delayed_work_sync(&pm->ps_work); cancel_work_sync(&pm->wake_work); - dev->sar_inited = false; for (i = 0; i < 10; i++) { mutex_lock(&dev->mt76.mutex); @@ -1329,6 +1328,10 @@ void mt7925_mac_reset_work(struct work_struct *work) IEEE80211_IFACE_ITER_RESUME_ALL, mt7925_vif_connect_iter, NULL); mt76_connac_power_save_sched(&dev->mt76.phy, pm); + + mt792x_mutex_acquire(dev); + mt7925_mcu_set_clc(dev, "00", ENVIRON_INDOOR); + mt792x_mutex_release(dev); } void mt7925_coredump_work(struct work_struct *work) @@ -1449,7 +1452,7 @@ void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, sta = wcid_to_sta(wcid); if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt76_connac2_tx_check_aggr(sta, txwi); + mt7925_tx_check_aggr(sta, e->skb, wcid); skb_pull(e->skb, headroom); mt76_tx_complete_skb(mdev, e->wcid, e->skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 5b001548dffc..ac3d485a2f78 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -240,6 +240,7 @@ int mt7925_init_mlo_caps(struct mt792x_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; static const u8 ext_capa_sta[] = { + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, }; static struct wiphy_iftype_ext_capab ext_capab[] = { @@ -310,7 +311,6 @@ void mt7925_set_stream_he_eht_caps(struct mt792x_phy *phy) int __mt7925_start(struct mt792x_phy *phy) { struct mt76_phy *mphy = phy->mt76; - struct mt792x_dev *dev = phy->dev; int err; err = mt7925_mcu_set_channel_domain(mphy); @@ -321,13 +321,6 @@ int __mt7925_start(struct mt792x_phy *phy) if (err) return err; - if (!dev->sar_inited) { - err = mt7925_set_tx_sar_pwr(mphy->hw, NULL); - if (err) - return err; - dev->sar_inited = true; - } - mt792x_mac_reset_counters(phy); set_bit(MT76_STATE_RUNNING, &mphy->state); @@ -757,7 +750,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; @@ -987,56 +980,6 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt7925_mac_sta_add); -static u16 -mt7925_mac_select_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) -{ - unsigned long usable_links = ieee80211_vif_usable_links(vif); - struct { - u8 link_id; - enum nl80211_band band; - } data[IEEE80211_MLD_MAX_NUM_LINKS]; - u8 link_id, i, j, n_data = 0; - u16 sel_links = 0; - - if (!ieee80211_vif_is_mld(vif)) - return 0; - - if (vif->active_links == usable_links) - return vif->active_links; - - rcu_read_lock(); - for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_bss_conf *link_conf = - rcu_dereference(vif->link_conf[link_id]); - - if (WARN_ON_ONCE(!link_conf)) - continue; - - data[n_data].link_id = link_id; - data[n_data].band = link_conf->chanreq.oper.chan->band; - n_data++; - } - rcu_read_unlock(); - - for (i = 0; i < n_data; i++) { - if (!(BIT(data[i].link_id) & vif->active_links)) - continue; - - sel_links = BIT(data[i].link_id); - - for (j = 0; j < n_data; j++) { - if (data[i].band != data[j].band) { - sel_links |= BIT(data[j].link_id); - break; - } - } - - break; - } - - return sel_links; -} - static void mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) { @@ -1047,7 +990,7 @@ mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif) struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; enum nl80211_band band = chandef->chan->band, secondary_band; - u16 sel_links = mt7925_mac_select_links(mdev, vif); + u16 sel_links = mt76_select_links(vif, 2); u8 secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links); if (!ieee80211_vif_is_mld(vif) || hweight16(sel_links) < 2) @@ -1191,6 +1134,9 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, struct mt792x_bss_conf *mconf; struct mt792x_link_sta *mlink; + if (vif->type == NL80211_IFTYPE_AP) + break; + link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); if (!link_sta) continue; @@ -1265,7 +1211,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 +1454,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); @@ -1726,13 +1674,7 @@ static int mt7925_set_sar_specs(struct ieee80211_hw *hw, int err; mt792x_mutex_acquire(dev); - err = mt7925_mcu_set_clc(dev, dev->mt76.alpha2, - dev->country_ie_env); - if (err < 0) - goto out; - err = mt7925_set_tx_sar_pwr(hw, sar); -out: mt792x_mutex_release(dev); return err; @@ -2067,8 +2009,10 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, GFP_KERNEL); mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL); - if (!mconf || !mlink) + if (!mconf || !mlink) { + mt792x_mutex_release(dev); return -ENOMEM; + } } mconfs[link_id] = mconf; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index 8ac6fbb736ab..8eda407e4135 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -759,7 +759,6 @@ static int mt7925_load_clc(struct mt792x_dev *dev, const char *fw_name) } } - ret = mt7925_mcu_set_clc(dev, "00", ENVIRON_INDOOR); out: release_firmware(fw); @@ -1834,13 +1833,13 @@ mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb, struct tlv *tlv; u16 eml_cap; + if (!ieee80211_vif_is_mld(vif)) + return; + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld)); eht_mld = (struct sta_rec_eht_mld *)tlv; eht_mld->mld_type = 0xff; - if (!ieee80211_vif_is_mld(vif)) - return; - ext_capa = cfg80211_get_iftype_ext_capa(wiphy, ieee80211_vif_type_p2p(vif)); if (!ext_capa) @@ -1912,6 +1911,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, struct mt76_dev *dev = phy->dev; struct mt792x_bss_conf *mconf; struct sk_buff *skb; + int conn_state; mconf = mt792x_vif_to_link(mvif, info->wcid->link_id); @@ -1920,10 +1920,13 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); + conn_state = info->enable ? CONN_STATE_PORT_SECURE : + CONN_STATE_DISCONNECT; + if (info->enable && info->link_sta) { mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf, info->link_sta, - info->enable, info->newly); + conn_state, info->newly); mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta); mt7925_mcu_sta_ht_tlv(skb, info->link_sta); mt7925_mcu_sta_vht_tlv(skb, info->link_sta); @@ -2618,6 +2621,25 @@ mt7925_mcu_bss_qos_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf } static void +mt7925_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, + bool enable) +{ + struct bss_info_uni_mbssid *mbssid; + struct tlv *tlv; + + if (!enable && !link_conf->bssid_indicator) + return; + + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_11V_MBSSID, + sizeof(*mbssid)); + + mbssid = (struct bss_info_uni_mbssid *)tlv; + mbssid->max_indicator = link_conf->bssid_indicator; + mbssid->mbss_idx = link_conf->bssid_index; + mbssid->tx_bss_omac_idx = 0; +} + +static void mt7925_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, struct mt792x_phy *phy) { @@ -2783,8 +2805,10 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, mt7925_mcu_bss_color_tlv(skb, link_conf, enable); } - if (enable) + if (enable) { mt7925_mcu_bss_rlm_tlv(skb, phy->mt76, link_conf, ctx); + mt7925_mcu_bss_mbssid_tlv(skb, link_conf, enable); + } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_UNI_CMD(BSS_INFO_UPDATE), true); @@ -2916,7 +2940,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 +2957,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, @@ -3699,6 +3723,8 @@ out: int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy) { + struct mt76_dev *mdev = phy->dev; + struct mt792x_dev *dev = mt792x_hw_dev(mdev->hw); int err; if (phy->cap.has_2ghz) { @@ -3715,7 +3741,7 @@ int mt7925_mcu_set_rate_txpower(struct mt76_phy *phy) return err; } - if (phy->cap.has_6ghz) { + if (phy->cap.has_6ghz && dev->phy.clc_chan_conf) { err = mt7925_mcu_rate_txpower_band(phy, NL80211_BAND_6GHZ); if (err < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 89dc30f7c6b7..8eb1fe1082d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -529,7 +529,7 @@ restore_suspend: return err; } -static int mt7925_pci_resume(struct device *device) +static int _mt7925_pci_resume(struct device *device, bool restore) { struct pci_dev *pdev = to_pci_dev(device); struct mt76_dev *mdev = pci_get_drvdata(pdev); @@ -569,6 +569,9 @@ static int mt7925_pci_resume(struct device *device) napi_schedule(&mdev->tx_napi); local_bh_enable(); + if (restore) + goto failed; + mt76_connac_mcu_set_hif_suspend(mdev, false, false); ret = wait_event_timeout(dev->wait, dev->hif_resumed, 3 * HZ); @@ -585,7 +588,7 @@ static int mt7925_pci_resume(struct device *device) failed: pm->suspended = false; - if (err < 0) + if (err < 0 || restore) mt792x_reset(&dev->mt76); return err; @@ -596,7 +599,24 @@ static void mt7925_pci_shutdown(struct pci_dev *pdev) mt7925_pci_remove(pdev); } -static DEFINE_SIMPLE_DEV_PM_OPS(mt7925_pm_ops, mt7925_pci_suspend, mt7925_pci_resume); +static int mt7925_pci_resume(struct device *device) +{ + return _mt7925_pci_resume(device, false); +} + +static int mt7925_pci_restore(struct device *device) +{ + return _mt7925_pci_resume(device, true); +} + +static const struct dev_pm_ops mt7925_pm_ops = { + .suspend = pm_sleep_ptr(mt7925_pci_suspend), + .resume = pm_sleep_ptr(mt7925_pci_resume), + .freeze = pm_sleep_ptr(mt7925_pci_suspend), + .thaw = pm_sleep_ptr(mt7925_pci_resume), + .poweroff = pm_sleep_ptr(mt7925_pci_suspend), + .restore = pm_sleep_ptr(mt7925_pci_restore), +}; static struct pci_driver mt7925_pci_driver = { .name = KBUILD_MODNAME, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c index 4dfbc1b6cfdd..bf040f34e4b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c @@ -12,6 +12,9 @@ static const struct usb_device_id mt7925u_device_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7925, 0xff, 0xff, 0xff), .driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM }, + /* Netgear, Inc. A9000 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9072, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM }, { }, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index e0359d431eca..f2c8b9e4aa0f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -234,7 +234,6 @@ struct mt792x_dev { bool aspm_supported:1; bool hif_idle:1; bool hif_resumed:1; - bool sar_inited:1; bool regd_change:1; wait_queue_head_t wait; @@ -412,7 +411,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..c0e56541a954 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,8 +688,13 @@ 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); - if (is_mt7921(&dev->mt76)) + ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); + ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); + ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); + + if (is_mt7921(&dev->mt76)) { ieee80211_hw_set(hw, CHANCTX_STA_CSA); + } if (dev->pm.enable) ieee80211_hw_set(hw, CONNECTION_MONITOR); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c index 6f9db782338e..69217ce91130 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c @@ -181,13 +181,13 @@ mt792x_dma_reset(struct mt792x_dev *dev, bool force) /* reset hw queues */ for (i = 0; i < __MT_TXQ_MAX; i++) - mt76_queue_reset(dev, dev->mphy.q_tx[i]); + mt76_queue_reset(dev, dev->mphy.q_tx[i], true); for (i = 0; i < __MT_MCUQ_MAX; i++) - mt76_queue_reset(dev, dev->mt76.q_mcu[i]); + mt76_queue_reset(dev, dev->mt76.q_mcu[i], true); mt76_for_each_q_rx(&dev->mt76, i) - mt76_queue_reset(dev, &dev->mt76.q_rx[i]); + mt76_queue_reset(dev, &dev->mt76.q_rx[i], true); mt76_tx_status_check(&dev->mt76, true); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index c8bef0b2a144..659015f93d32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -17,7 +17,7 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc, ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; idx -= MT_TXQ_ID(0); - if (phy->mt76->band_idx == MT_BAND2) + if (wed == &dev->mt76.mmio.wed_hif2) flags = MT_WED_Q_TX(0); else flags = MT_WED_Q_TX(idx); @@ -83,36 +83,74 @@ static void mt7996_dma_config(struct mt7996_dev *dev) break; } - if (dev->has_rro) { + if (mt7996_has_hwrro(dev)) { /* band0 */ RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0, MT7996_RXQ_RRO_BAND0); - RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0, - MT7996_RXQ_MSDU_PG_BAND0); - RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN, - MT7996_RXQ_TXFREE0); - /* band1 */ - RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1, - MT7996_RXQ_MSDU_PG_BAND1); - /* band2 */ - RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2, - MT7996_RXQ_RRO_BAND2); - RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2, - MT7996_RXQ_MSDU_PG_BAND2); - RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI, - MT7996_RXQ_TXFREE2); - - RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND, - MT7996_RXQ_RRO_IND); + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3) + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, + MT_INT_RX_DONE_MSDU_PG_BAND0, + MT7996_RXQ_MSDU_PG_BAND0); + if (is_mt7996(&dev->mt76)) { + RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, + MT_INT_RX_TXFREE_MAIN, MT7996_RXQ_TXFREE0); + /* band1 */ + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, + MT_INT_RX_DONE_MSDU_PG_BAND1, + MT7996_RXQ_MSDU_PG_BAND1); + /* band2 */ + RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, + MT_INT_RX_DONE_RRO_BAND2, + MT7996_RXQ_RRO_BAND2); + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, + MT_INT_RX_DONE_MSDU_PG_BAND2, + MT7996_RXQ_MSDU_PG_BAND2); + RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, + MT_INT_RX_TXFREE_TRI, MT7996_RXQ_TXFREE2); + } else { + RXQ_CONFIG(MT_RXQ_RRO_BAND1, WFDMA0, + MT_INT_RX_DONE_RRO_BAND1, + MT7996_RXQ_RRO_BAND1); + } + + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3) + RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, + MT_INT_RX_DONE_RRO_IND, + MT7996_RXQ_RRO_IND); + else + RXQ_CONFIG(MT_RXQ_RRO_RXDMAD_C, WFDMA0, + MT_INT_RX_DONE_RRO_RXDMAD_C, + MT7996_RXQ_RRO_RXDMAD_C); } /* data tx queue */ - TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); if (is_mt7996(&dev->mt76)) { - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); - TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2); + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); + if (dev->hif2) { + /* default bn1:ring19 bn2:ring21 */ + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, + MT7996_TXQ_BAND1); + TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, + MT7996_TXQ_BAND2); + } else { + /* single pcie bn0/1:ring18 bn2:ring19 */ + TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1, + MT7996_TXQ_BAND1); + } } else { - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); + if (dev->hif2) { + /* bn0:ring18 bn1:ring21 */ + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, + MT7996_TXQ_BAND0); + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND2, + MT7996_TXQ_BAND2); + } else { + /* single pcie bn0:ring18 bn1:ring19 */ + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, + MT7996_TXQ_BAND0); + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, + MT7996_TXQ_BAND1); + } } /* mcu tx queue */ @@ -166,11 +204,12 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) /* Rx TxFreeDone From MAC Rings */ val = is_mt7996(&dev->mt76) ? 4 : 8; - if (is_mt7990(&dev->mt76) || (is_mt7996(&dev->mt76) && dev->has_rro)) + if ((is_mt7996(&dev->mt76) && mt7996_has_hwrro(dev)) || + is_mt7990(&dev->mt76)) mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, PREFETCH(val)); if (is_mt7990(&dev->mt76) && dev->hif2) mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND1) + ofs, PREFETCH(val)); - else if (is_mt7996(&dev->mt76) && dev->has_rro) + else if (is_mt7996(&dev->mt76) && mt7996_has_hwrro(dev)) mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, PREFETCH(val)); /* Rx Data Rings */ @@ -179,7 +218,7 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) mt76_wr(dev, MT_RXQ_EXT_CTRL(queue) + ofs, PREFETCH(0x10)); /* Rx RRO Rings */ - if (dev->has_rro) { + if (mt7996_has_hwrro(dev)) { mt76_wr(dev, MT_RXQ_EXT_CTRL(MT_RXQ_RRO_BAND0) + ofs, PREFETCH(0x10)); queue = is_mt7996(&dev->mt76) ? MT_RXQ_RRO_BAND2 : MT_RXQ_RRO_BAND1; mt76_wr(dev, MT_RXQ_EXT_CTRL(queue) + ofs, PREFETCH(0x10)); @@ -288,11 +327,14 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) if (mt7996_band_valid(dev, MT_BAND0)) irq_mask |= MT_INT_BAND0_RX_DONE; - if (mt7996_band_valid(dev, MT_BAND1)) + if (mt7996_band_valid(dev, MT_BAND1)) { irq_mask |= MT_INT_BAND1_RX_DONE; + if (is_mt7992(&dev->mt76) && dev->hif2) + irq_mask |= MT_INT_RX_TXFREE_BAND1_EXT; + } if (mt7996_band_valid(dev, MT_BAND2)) - irq_mask |= MT_INT_BAND2_RX_DONE; + irq_mask |= MT_INT_BAND2_RX_DONE | MT_INT_TX_RX_DONE_EXT; if (mtk_wed_device_active(wed) && wed_reset) { u32 wed_irq_mask = irq_mask; @@ -378,13 +420,48 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE); mt76_set(dev, MT_WFDMA_HOST_CONFIG, - MT_WFDMA_HOST_CONFIG_PDMA_BAND | - MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); + MT_WFDMA_HOST_CONFIG_PDMA_BAND); + + mt76_clear(dev, MT_WFDMA_HOST_CONFIG, + MT_WFDMA_HOST_CONFIG_BAND0_PCIE1 | + MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 | + MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); + + if (is_mt7996(&dev->mt76)) + mt76_set(dev, MT_WFDMA_HOST_CONFIG, + MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); + else + mt76_set(dev, MT_WFDMA_HOST_CONFIG, + MT_WFDMA_HOST_CONFIG_BAND1_PCIE1); /* AXI read outstanding number */ mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); + if (dev->hif2->speed < PCIE_SPEED_5_0GT || + (dev->hif2->speed == PCIE_SPEED_5_0GT && + dev->hif2->width < PCIE_LNK_X2)) { + mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, + WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, + FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, + 0x1)); + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, + MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, + FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, + 0x1)); + } else if (dev->hif2->speed < PCIE_SPEED_8_0GT || + (dev->hif2->speed == PCIE_SPEED_8_0GT && + dev->hif2->width < PCIE_LNK_X2)) { + mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, + WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, + FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, + 0x2)); + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, + MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, + FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, + 0x2)); + } + /* WFDMA rx threshold */ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c); mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008); @@ -397,27 +474,58 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) * so, redirect pcie0 rx ring3 interrupt to pcie1 */ if (mtk_wed_device_active(&dev->mt76.mmio.wed) && - dev->has_rro) + mt7996_has_hwrro(dev)) { + u32 intr = is_mt7996(&dev->mt76) ? + MT_WFDMA0_RX_INT_SEL_RING6 : + MT_WFDMA0_RX_INT_SEL_RING9 | + MT_WFDMA0_RX_INT_SEL_RING5; + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs, - MT_WFDMA0_RX_INT_SEL_RING6); - else + intr); + } else { mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, MT_WFDMA0_RX_INT_SEL_RING3); + } } mt7996_dma_start(dev, reset, true); } -#ifdef CONFIG_NET_MEDIATEK_SOC_WED int mt7996_dma_rro_init(struct mt7996_dev *dev) { struct mt76_dev *mdev = &dev->mt76; u32 irq_mask; int ret; + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { + /* rxdmad_c */ + mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].flags = MT_WED_RRO_Q_RXDMAD_C; + if (mtk_wed_device_active(&mdev->mmio.wed)) + mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].wed = &mdev->mmio.wed; + else + mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].flags |= MT_QFLAG_EMI_EN; + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], + MT_RXQ_ID(MT_RXQ_RRO_RXDMAD_C), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RRO_AP_RING_BASE); + if (ret) + return ret; + + /* We need to set cpu idx pointer before resetting the EMI + * queues. + */ + mdev->q_rx[MT_RXQ_RRO_RXDMAD_C].emi_cpu_idx = + &dev->wed_rro.emi_rings_cpu.ptr->ring[0].idx; + mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], true); + goto start_hw_rro; + } + /* ind cmd */ mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND; - mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed; + if (mtk_wed_device_active(&mdev->mmio.wed) && + mtk_wed_get_rx_capa(&mdev->mmio.wed)) + mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed; ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_IND], MT_RXQ_ID(MT_RXQ_RRO_IND), MT7996_RX_RING_SIZE, @@ -428,7 +536,9 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) /* rx msdu page queue for band0 */ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].flags = MT_WED_RRO_Q_MSDU_PG(0) | MT_QFLAG_WED_RRO_EN; - mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; + if (mtk_wed_device_active(&mdev->mmio.wed) && + mtk_wed_get_rx_capa(&mdev->mmio.wed)) + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), MT7996_RX_RING_SIZE, @@ -437,11 +547,13 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) if (ret) return ret; - if (mt7996_band_valid(dev, MT_BAND1)) { + if (mt7996_band_valid(dev, MT_BAND1) && is_mt7996(&dev->mt76)) { /* rx msdu page queue for band1 */ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags = MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN; - mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; + if (mtk_wed_device_active(&mdev->mmio.wed) && + mtk_wed_get_rx_capa(&mdev->mmio.wed)) + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), MT7996_RX_RING_SIZE, @@ -455,7 +567,9 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) /* rx msdu page queue for band2 */ mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags = MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN; - mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; + if (mtk_wed_device_active(&mdev->mmio.wed) && + mtk_wed_get_rx_capa(&mdev->mmio.wed)) + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), MT7996_RX_RING_SIZE, @@ -465,15 +579,42 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) return ret; } - irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE | - MT_INT_TX_DONE_BAND2; - mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); - mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); - mt7996_irq_enable(dev, irq_mask); +start_hw_rro: + if (mtk_wed_device_active(&mdev->mmio.wed)) { + irq_mask = mdev->mmio.irqmask | + MT_INT_TX_DONE_BAND2; + + mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); + mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); + mt7996_irq_enable(dev, irq_mask); + } else { + if (is_mt7996(&dev->mt76)) { + mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1, + mt76_dma_rx_poll); + mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2, + mt76_dma_rx_poll); + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2, + mt76_dma_rx_poll); + } else { + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1, + mt76_dma_rx_poll); + } + + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll); + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { + mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C, + mt76_dma_rx_poll); + } else { + mt76_queue_rx_init(dev, MT_RXQ_RRO_IND, + mt76_dma_rx_poll); + mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0, + mt76_dma_rx_poll); + } + mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE); + } return 0; } -#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ int mt7996_dma_init(struct mt7996_dev *dev) { @@ -560,7 +701,9 @@ int mt7996_dma_init(struct mt7996_dev *dev) return ret; /* tx free notify event from WA for band0 */ - if (mtk_wed_device_active(wed) && !dev->has_rro) { + if (mtk_wed_device_active(wed) && + ((is_mt7996(&dev->mt76) && !mt7996_has_hwrro(dev)) || + (is_mt7992(&dev->mt76)))) { dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; } @@ -615,7 +758,7 @@ int mt7996_dma_init(struct mt7996_dev *dev) /* tx free notify event from WA for mt7996 band2 * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 */ - if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) { + if (mtk_wed_device_active(wed_hif2) && !mt7996_has_hwrro(dev)) { dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE; dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2; } @@ -630,6 +773,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) } else if (mt7996_band_valid(dev, MT_BAND1)) { /* rx data queue for mt7992 band1 */ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs; + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { + dev->mt76.q_rx[MT_RXQ_BAND1].flags = MT_WED_Q_RX(1); + dev->mt76.q_rx[MT_RXQ_BAND1].wed = wed; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1], MT_RXQ_ID(MT_RXQ_BAND1), MT7996_RX_RING_SIZE, @@ -641,6 +789,12 @@ int mt7996_dma_init(struct mt7996_dev *dev) /* tx free notify event from WA for mt7992 band1 */ if (mt7996_has_wa(dev)) { rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs; + if (mtk_wed_device_active(wed_hif2)) { + dev->mt76.q_rx[MT_RXQ_BAND1_WA].flags = + MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_BAND1_WA].wed = wed_hif2; + } + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA], MT_RXQ_ID(MT_RXQ_BAND1_WA), MT7996_RX_MCU_RING_SIZE, @@ -651,12 +805,12 @@ int mt7996_dma_init(struct mt7996_dev *dev) } } - if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && - dev->has_rro) { + if (mt7996_has_hwrro(dev)) { /* rx rro data queue for band0 */ dev->mt76.q_rx[MT_RXQ_RRO_BAND0].flags = MT_WED_RRO_Q_DATA(0) | MT_QFLAG_WED_RRO_EN; - dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed; + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0], MT_RXQ_ID(MT_RXQ_RRO_BAND0), MT7996_RX_RING_SIZE, @@ -665,23 +819,44 @@ int mt7996_dma_init(struct mt7996_dev *dev) if (ret) return ret; - /* tx free notify event from WA for band0 */ - dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; - dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; + if (is_mt7992(&dev->mt76)) { + dev->mt76.q_rx[MT_RXQ_RRO_BAND1].flags = + MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; + if (mtk_wed_device_active(wed) && + mtk_wed_get_rx_capa(wed)) + dev->mt76.q_rx[MT_RXQ_RRO_BAND1].wed = wed; + ret = mt76_queue_alloc(dev, + &dev->mt76.q_rx[MT_RXQ_RRO_BAND1], + MT_RXQ_ID(MT_RXQ_RRO_BAND1), + MT7996_RX_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + hif1_ofs); + if (ret) + return ret; + } else { + if (mtk_wed_device_active(wed)) { + /* tx free notify event from WA for band0 */ + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; + } - ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0], - MT_RXQ_ID(MT_RXQ_TXFREE_BAND0), - MT7996_RX_MCU_RING_SIZE, - MT7996_RX_BUF_SIZE, - MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0)); - if (ret) - return ret; + ret = mt76_queue_alloc(dev, + &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0], + MT_RXQ_ID(MT_RXQ_TXFREE_BAND0), + MT7996_RX_MCU_RING_SIZE, + MT7996_RX_BUF_SIZE, + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0)); + if (ret) + return ret; + } if (mt7996_band_valid(dev, MT_BAND2)) { /* rx rro data queue for band2 */ dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; - dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; + if (mtk_wed_device_active(wed) && + mtk_wed_get_rx_capa(wed)) + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], MT_RXQ_ID(MT_RXQ_RRO_BAND2), MT7996_RX_RING_SIZE, @@ -752,6 +927,10 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force) mt76_tx_status_check(&dev->mt76, true); + if (mt7996_has_hwrro(dev) && + !mtk_wed_device_active(&dev->mt76.mmio.wed)) + mt7996_rro_msdu_page_map_free(dev); + /* reset wfsys */ if (force) mt7996_wfsys_reset(dev); @@ -775,21 +954,32 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force) } for (i = 0; i < __MT_MCUQ_MAX; i++) - mt76_queue_reset(dev, dev->mt76.q_mcu[i]); + mt76_queue_reset(dev, dev->mt76.q_mcu[i], true); mt76_for_each_q_rx(&dev->mt76, i) { - if (mtk_wed_device_active(&dev->mt76.mmio.wed)) - if (mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]) || - mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) - continue; + struct mt76_queue *q = &dev->mt76.q_rx[i]; - mt76_queue_reset(dev, &dev->mt76.q_rx[i]); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + if (mt76_queue_is_wed_rro(q) || + mt76_queue_is_wed_tx_free(q)) { + if (force && mt76_queue_is_wed_rro_data(q)) + mt76_queue_reset(dev, q, false); + continue; + } + } + mt76_queue_reset(dev, q, true); } mt76_tx_status_check(&dev->mt76, true); - mt76_for_each_q_rx(&dev->mt76, i) + mt76_for_each_q_rx(&dev->mt76, i) { + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && force && + (mt76_queue_is_wed_rro_ind(&dev->mt76.q_rx[i]) || + mt76_queue_is_wed_rro_msdu_pg(&dev->mt76.q_rx[i]))) + continue; + mt76_queue_rx_reset(dev, i); + } mt7996_dma_enable(dev, !force); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 87c6192b6384..da3231c9aa11 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -334,9 +334,8 @@ int mt7996_eeprom_init(struct mt7996_dev *dev) return ret; memcpy(dev->mphy.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR, ETH_ALEN); - mt76_eeprom_override(&dev->mphy); - return 0; + return mt76_eeprom_override(&dev->mphy); } int mt7996_eeprom_get_target_power(struct mt7996_dev *dev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index a9599c286328..5e95a36b42d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -63,6 +63,33 @@ static const struct ieee80211_iface_combination if_comb = { .beacon_int_min_gcd = 100, }; +static const u8 if_types_ext_capa_ap[] = { + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, + [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, + [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, +}; + +static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = { + { + .iftype = NL80211_IFTYPE_AP, + .extended_capabilities = if_types_ext_capa_ap, + .extended_capabilities_mask = if_types_ext_capa_ap, + .extended_capabilities_len = sizeof(if_types_ext_capa_ap), + .eml_capabilities = IEEE80211_EML_CAP_EMLSR_SUPP, + .mld_capa_and_ops = + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, + MT7996_MAX_RADIOS - 1), + }, { + .iftype = NL80211_IFTYPE_STATION, + .extended_capabilities = if_types_ext_capa_ap, + .extended_capabilities_mask = if_types_ext_capa_ap, + .extended_capabilities_len = sizeof(if_types_ext_capa_ap), + .mld_capa_and_ops = + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, + MT7996_MAX_RADIOS - 1), + }, +}; + static ssize_t mt7996_thermal_temp_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -383,6 +410,7 @@ mt7996_init_wiphy_band(struct ieee80211_hw *hw, struct mt7996_phy *phy) phy->slottime = 9; phy->beacon_rate = -1; + phy->rxfilter = MT_WF_RFCR_DROP_OTHER_UC; if (phy->mt76->cap.has_2ghz) { phy->mt76->sband_2g.sband.ht_cap.cap |= @@ -463,8 +491,11 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) wiphy->radio = dev->radios; wiphy->reg_notifier = mt7996_regd_notifier; - wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH; + wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | + WIPHY_FLAG_SUPPORTS_MLO; wiphy->mbssid_max_interfaces = 16; + wiphy->iftype_ext_capab = iftypes_ext_capa; + wiphy->num_iftype_ext_capab = ARRAY_SIZE(iftypes_ext_capa); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BSS_COLOR); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS); @@ -575,19 +606,21 @@ void mt7996_mac_init(struct mt7996_dev *dev) } /* rro module init */ - if (is_mt7996(&dev->mt76)) - mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); - else + if (dev->hif2) mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, - dev->hif2 ? 7 : 0); + is_mt7996(&dev->mt76) ? 2 : 7); + else + mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0); - if (dev->has_rro) { + if (mt7996_has_hwrro(dev)) { u16 timeout; timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128; mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1); - mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, + is_mt7996(&dev->mt76) ? 1 : 2); + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, + !is_mt7996(&dev->mt76)); } else { mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); @@ -634,7 +667,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) if (!mt7996_band_valid(dev, band)) return 0; - if (is_mt7996(&dev->mt76) && band == MT_BAND2 && dev->hif2) { + if (dev->hif2 && + ((is_mt7996(&dev->mt76) && band == MT_BAND2) || + (is_mt7992(&dev->mt76) && band == MT_BAND1))) { hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); wed = &dev->mt76.mmio.wed_hif2; } @@ -667,17 +702,26 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) if (band == MT_BAND2) mphy->macaddr[0] ^= BIT(6); } - mt76_eeprom_override(mphy); + ret = mt76_eeprom_override(mphy); + if (ret) + goto error; /* init wiphy according to mphy and phy */ mt7996_init_wiphy_band(mphy->hw, phy); - ret = mt7996_init_tx_queues(mphy->priv, - MT_TXQ_ID(band), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(band) + hif1_ofs, - wed); - if (ret) - goto error; + + if (is_mt7996(&dev->mt76) && !dev->hif2 && band == MT_BAND1) { + int i; + + for (i = 0; i <= MT_TXQ_PSD; i++) + mphy->q_tx[i] = dev->mt76.phys[MT_BAND0]->q_tx[0]; + } else { + ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(band) + hif1_ofs, + wed); + if (ret) + goto error; + } ret = mt76_register_phy(mphy, true, mt76_rates, ARRAY_SIZE(mt76_rates)); @@ -685,10 +729,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) goto error; if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) { - u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; - - mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); - mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask); + mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, + MT_INT_TX_RX_DONE_EXT); } return 0; @@ -724,30 +767,151 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev) msleep(20); } -static int mt7996_wed_rro_init(struct mt7996_dev *dev) +static void mt7996_rro_hw_init_v3(struct mt7996_dev *dev) { -#ifdef CONFIG_NET_MEDIATEK_SOC_WED struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + u32 session_id; + + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) + return; + +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { + wed->wlan.ind_cmd.win_size = + ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6; + if (is_mt7996(&dev->mt76)) + wed->wlan.ind_cmd.particular_sid = + MT7996_RRO_MAX_SESSION; + else + wed->wlan.ind_cmd.particular_sid = 1; + wed->wlan.ind_cmd.particular_se_phys = + dev->wed_rro.session.phy_addr; + wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN; + wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL; + } +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { + mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00); + mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, + MT_RRO_IND_CMD_SIGNATURE_BASE1_EN); + } else { + mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0); + mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, 0); + } + + /* particular session configure */ + /* use max session idx + 1 as particular session id */ + mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr); + + session_id = is_mt7996(&dev->mt76) ? MT7996_RRO_MAX_SESSION : 1; + mt76_wr(dev, MT_RRO_PARTICULAR_CFG1, + MT_RRO_PARTICULAR_CONFG_EN | + FIELD_PREP(MT_RRO_PARTICULAR_SID, session_id)); +} + +void mt7996_rro_hw_init(struct mt7996_dev *dev) +{ u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0; + int i; + + if (!mt7996_has_hwrro(dev)) + return; + + INIT_LIST_HEAD(&dev->wed_rro.page_cache); + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.page_map); i++) + INIT_LIST_HEAD(&dev->wed_rro.page_map[i]); + + if (!is_mt7996(&dev->mt76)) { + reg = MT_RRO_MSDU_PG_SEG_ADDR0; + + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { + mt76_clear(dev, MT_RRO_3_0_EMU_CONF, + MT_RRO_3_0_EMU_CONF_EN_MASK); + mt76_set(dev, MT_RRO_3_1_GLOBAL_CONFIG, + MT_RRO_3_1_GLOBAL_CONFIG_RXDMAD_SEL); + if (!mtk_wed_device_active(&dev->mt76.mmio.wed)) { + mt76_set(dev, MT_RRO_3_1_GLOBAL_CONFIG, + MT_RRO_3_1_GLOBAL_CONFIG_RX_DIDX_WR_EN | + MT_RRO_3_1_GLOBAL_CONFIG_RX_CIDX_RD_EN); + mt76_wr(dev, MT_RRO_RX_RING_AP_CIDX_ADDR, + dev->wed_rro.emi_rings_cpu.phy_addr >> 4); + mt76_wr(dev, MT_RRO_RX_RING_AP_DIDX_ADDR, + dev->wed_rro.emi_rings_dma.phy_addr >> 4); + } + } else { + /* set emul 3.0 function */ + mt76_wr(dev, MT_RRO_3_0_EMU_CONF, + MT_RRO_3_0_EMU_CONF_EN_MASK); + + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0, + dev->wed_rro.addr_elem[0].phy_addr); + } + + mt76_set(dev, MT_RRO_3_1_GLOBAL_CONFIG, + MT_RRO_3_1_GLOBAL_CONFIG_INTERLEAVE_EN); + + /* setup Msdu page address */ + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) { + mt76_wr(dev, reg, + dev->wed_rro.msdu_pg[i].phy_addr >> 4); + reg += 4; + } + } else { + /* TODO: remove line after WM has set */ + mt76_clear(dev, WF_RRO_AXI_MST_CFG, + WF_RRO_AXI_MST_CFG_DIDX_OK); + + /* setup BA bitmap cache address */ + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0, + dev->wed_rro.ba_bitmap[0].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0, + dev->wed_rro.ba_bitmap[1].phy_addr); + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0); + + /* Setup Address element address */ + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { + mt76_wr(dev, reg, + dev->wed_rro.addr_elem[i].phy_addr >> 4); + reg += 4; + } + + /* Setup Address element address - separate address segment + * mode. + */ + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1, + MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE); + } + + mt7996_rro_hw_init_v3(dev); + + /* interrupt enable */ + mt76_wr(dev, MT_RRO_HOST_INT_ENA, + MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA); +} + +static int mt7996_wed_rro_init(struct mt7996_dev *dev) +{ + u32 val = FIELD_PREP(WED_RRO_ADDR_SIGNATURE_MASK, 0xff); struct mt7996_wed_rro_addr *addr; void *ptr; int i; - if (!dev->has_rro) + if (!mt7996_has_hwrro(dev)) return 0; - if (!mtk_wed_device_active(wed)) - return 0; + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3) { + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_BA_BITMAP_CR_SIZE, + &dev->wed_rro.ba_bitmap[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { - ptr = dmam_alloc_coherent(dev->mt76.dma_dev, - MT7996_RRO_BA_BITMAP_CR_SIZE, - &dev->wed_rro.ba_bitmap[i].phy_addr, - GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - dev->wed_rro.ba_bitmap[i].ptr = ptr; + dev->wed_rro.ba_bitmap[i].ptr = ptr; + } } for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { @@ -766,12 +930,53 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev) addr = dev->wed_rro.addr_elem[i].ptr; for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) { - addr->signature = 0xff; + addr->data = cpu_to_le32(val); addr++; } - wed->wlan.ind_cmd.addr_elem_phys[i] = - dev->wed_rro.addr_elem[i].phy_addr; +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) { + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; + + wed->wlan.ind_cmd.addr_elem_phys[i] = + dev->wed_rro.addr_elem[i].phy_addr; + } +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ + } + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) { + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + MT7996_RRO_MSDU_PG_SIZE_PER_CR, + &dev->wed_rro.msdu_pg[i].phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.msdu_pg[i].ptr = ptr; + + memset(dev->wed_rro.msdu_pg[i].ptr, 0, + MT7996_RRO_MSDU_PG_SIZE_PER_CR); + } + + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + sizeof(dev->wed_rro.emi_rings_cpu.ptr), + &dev->wed_rro.emi_rings_cpu.phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.emi_rings_cpu.ptr = ptr; + + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, + sizeof(dev->wed_rro.emi_rings_dma.ptr), + &dev->wed_rro.emi_rings_dma.phy_addr, + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + dev->wed_rro.emi_rings_dma.ptr = ptr; } ptr = dmam_alloc_coherent(dev->mt76.dma_dev, @@ -784,69 +989,20 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev) dev->wed_rro.session.ptr = ptr; addr = dev->wed_rro.session.ptr; for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { - addr->signature = 0xff; + addr->data = cpu_to_le32(val); addr++; } - /* rro hw init */ - /* TODO: remove line after WM has set */ - mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK); + mt7996_rro_hw_init(dev); - /* setup BA bitmap cache address */ - mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0, - dev->wed_rro.ba_bitmap[0].phy_addr); - mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0); - mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0, - dev->wed_rro.ba_bitmap[1].phy_addr); - mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0); - - /* setup Address element address */ - for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { - mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4); - reg += 4; - } - - /* setup Address element address - separate address segment mode */ - mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1, - MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE); - - wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6; - wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION; - wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr; - wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN; - wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL; - - mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00); - mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, - MT_RRO_IND_CMD_SIGNATURE_BASE1_EN); - - /* particular session configure */ - /* use max session idx + 1 as particular session id */ - mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr); - mt76_wr(dev, MT_RRO_PARTICULAR_CFG1, - MT_RRO_PARTICULAR_CONFG_EN | - FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION)); - - /* interrupt enable */ - mt76_wr(dev, MT_RRO_HOST_INT_ENA, - MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA); - - /* rro ind cmd queue init */ return mt7996_dma_rro_init(dev); -#else - return 0; -#endif } static void mt7996_wed_rro_free(struct mt7996_dev *dev) { -#ifdef CONFIG_NET_MEDIATEK_SOC_WED int i; - if (!dev->has_rro) - return; - - if (!mtk_wed_device_active(&dev->mt76.mmio.wed)) + if (!mt7996_has_hwrro(dev)) return; for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { @@ -870,6 +1026,16 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev) dev->wed_rro.addr_elem[i].phy_addr); } + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) { + if (!dev->wed_rro.msdu_pg[i].ptr) + continue; + + dmam_free_coherent(dev->mt76.dma_dev, + MT7996_RRO_MSDU_PG_SIZE_PER_CR, + dev->wed_rro.msdu_pg[i].ptr, + dev->wed_rro.msdu_pg[i].phy_addr); + } + if (!dev->wed_rro.session.ptr) return; @@ -878,12 +1044,11 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev) sizeof(struct mt7996_wed_rro_addr), dev->wed_rro.session.ptr, dev->wed_rro.session.phy_addr); -#endif } static void mt7996_wed_rro_work(struct work_struct *work) { -#ifdef CONFIG_NET_MEDIATEK_SOC_WED + u32 val = FIELD_PREP(WED_RRO_ADDR_SIGNATURE_MASK, 0xff); struct mt7996_dev *dev; LIST_HEAD(list); @@ -920,13 +1085,12 @@ static void mt7996_wed_rro_work(struct work_struct *work) MT7996_RRO_WINDOW_MAX_LEN; reset: elem = ptr + elem_id * sizeof(*elem); - elem->signature = 0xff; + elem->data |= cpu_to_le32(val); } mt7996_mcu_wed_rro_reset_sessions(dev, e->id); out: kfree(e); } -#endif } static int mt7996_variant_type_init(struct mt7996_dev *dev) @@ -1321,7 +1485,6 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band, eht_cap->has_eht = true; eht_cap_elem->mac_cap_info[0] = - IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | IEEE80211_EHT_MAC_CAP0_OM_CONTROL | u8_encode_bits(IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_11454, IEEE80211_EHT_MAC_CAP0_MAX_MPDU_LEN_MASK); @@ -1551,6 +1714,9 @@ void mt7996_unregister_device(struct mt7996_dev *dev) mt7996_mcu_exit(dev); mt7996_tx_token_put(dev); mt7996_dma_cleanup(dev); + if (mt7996_has_hwrro(dev) && + !mtk_wed_device_active(&dev->mt76.mmio.wed)) + mt7996_rro_msdu_page_map_free(dev); tasklet_disable(&dev->mt76.irq_tasklet); mt76_free_device(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 92148518f6a5..9501def3e0e3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -62,7 +62,7 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, int i; wcid = mt76_wcid_ptr(dev, idx); - if (!wcid) + if (!wcid || !wcid->sta) return NULL; if (!mt7996_band_valid(dev, band_idx)) @@ -229,7 +229,9 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) { struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap); - struct mt7996_sta *msta = (struct mt7996_sta *)status->wcid; + struct mt7996_sta_link *msta_link = (void *)status->wcid; + struct mt7996_sta *msta = msta_link->sta; + struct ieee80211_bss_conf *link_conf; __le32 *rxd = (__le32 *)skb->data; struct ieee80211_sta *sta; struct ieee80211_vif *vif; @@ -246,8 +248,11 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) if (!msta || !msta->vif) return -EINVAL; - sta = container_of((void *)msta, struct ieee80211_sta, drv_priv); + sta = wcid_to_sta(status->wcid); vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); + link_conf = rcu_dereference(vif->link_conf[msta_link->wcid.link_id]); + if (!link_conf) + return -EINVAL; /* store the info from RXD and ethhdr to avoid being overridden */ frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL); @@ -260,7 +265,7 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap) switch (frame_control & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) { case 0: - ether_addr_copy(hdr.addr3, vif->bss_conf.bssid); + ether_addr_copy(hdr.addr3, link_conf->bssid); break; case IEEE80211_FCTL_FROMDS: ether_addr_copy(hdr.addr3, eth_hdr->h_source); @@ -797,6 +802,9 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ) { if (is_mt7990(&dev->mt76)) txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TID_ADDBA, tid)); + else + txwi[7] |= cpu_to_le32(MT_TXD7_MAC_TXD); + tid = MT_TX_ADDBA; } else if (ieee80211_is_mgmt(hdr->frame_control)) { tid = MT_TX_NORMAL; @@ -903,8 +911,12 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, IEEE80211_TX_CTRL_MLO_LINK); mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL; - if (mvif) - mlink = rcu_dereference(mvif->mt76.link[link_id]); + if (mvif) { + if (wcid->offchannel) + mlink = rcu_dereference(mvif->mt76.offchannel_link); + if (!mlink) + mlink = rcu_dereference(mvif->mt76.link[link_id]); + } if (mlink) { omac_idx = mlink->omac_idx; @@ -956,8 +968,9 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, val |= MT_TXD5_TX_STATUS_HOST; txwi[5] = cpu_to_le32(val); - val = MT_TXD6_DAS; - if (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) + val = MT_TXD6_DAS | MT_TXD6_VTA; + if ((q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0) || + skb->protocol == cpu_to_be16(ETH_P_PAE)) val |= MT_TXD6_DIS_MAT; if (is_mt7996(&dev->mt76)) @@ -1025,10 +1038,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb); struct ieee80211_key_conf *key = info->control.hw_key; struct ieee80211_vif *vif = info->control.vif; - struct mt76_connac_txp_common *txp; struct mt76_txwi_cache *t; int id, i, pid, nbuf = tx_info->nbuf - 1; bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP; + __le32 *ptr = (__le32 *)txwi_ptr; u8 *txwi = (u8 *)txwi_ptr; if (unlikely(tx_info->skb->len <= ETH_HLEN)) @@ -1044,6 +1057,41 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (id < 0) return id; + /* Since the rules of HW MLD address translation are not fully + * compatible with 802.11 EAPOL frame, we do the translation by + * software + */ + if (tx_info->skb->protocol == cpu_to_be16(ETH_P_PAE) && sta->mlo) { + struct ieee80211_hdr *hdr = (void *)tx_info->skb->data; + struct ieee80211_bss_conf *link_conf; + struct ieee80211_link_sta *link_sta; + + link_conf = rcu_dereference(vif->link_conf[wcid->link_id]); + if (!link_conf) + return -EINVAL; + + link_sta = rcu_dereference(sta->link[wcid->link_id]); + if (!link_sta) + return -EINVAL; + + dma_sync_single_for_cpu(mdev->dma_dev, tx_info->buf[1].addr, + tx_info->buf[1].len, DMA_TO_DEVICE); + + memcpy(hdr->addr1, link_sta->addr, ETH_ALEN); + memcpy(hdr->addr2, link_conf->addr, ETH_ALEN); + if (ieee80211_has_a4(hdr->frame_control)) { + memcpy(hdr->addr3, sta->addr, ETH_ALEN); + memcpy(hdr->addr4, vif->addr, ETH_ALEN); + } else if (ieee80211_has_tods(hdr->frame_control)) { + memcpy(hdr->addr3, sta->addr, ETH_ALEN); + } else if (ieee80211_has_fromds(hdr->frame_control)) { + memcpy(hdr->addr3, vif->addr, ETH_ALEN); + } + + dma_sync_single_for_device(mdev->dma_dev, tx_info->buf[1].addr, + tx_info->buf[1].len, DMA_TO_DEVICE); + } + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); memset(txwi_ptr, 0, MT_TXD_SIZE); /* Transmit non qos data by 802.11 header and need to fill txd by host*/ @@ -1051,46 +1099,76 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key, pid, qid, 0); - txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE); - for (i = 0; i < nbuf; i++) { - u16 len; + /* MT7996 and MT7992 require driver to provide the MAC TXP for AddBA + * req + */ + if (le32_to_cpu(ptr[7]) & MT_TXD7_MAC_TXD) { + u32 val; + + ptr = (__le32 *)(txwi + MT_TXD_SIZE); + memset((void *)ptr, 0, sizeof(struct mt76_connac_fw_txp)); + + val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) | + MT_TXP0_TOKEN_ID0_VALID_MASK; + ptr[0] = cpu_to_le32(val); + + val = FIELD_PREP(MT_TXP1_TID_ADDBA, + tx_info->skb->priority & + IEEE80211_QOS_CTL_TID_MASK); + ptr[1] = cpu_to_le32(val); + ptr[2] = cpu_to_le32(tx_info->buf[1].addr & 0xFFFFFFFF); - len = FIELD_PREP(MT_TXP_BUF_LEN, tx_info->buf[i + 1].len); + val = FIELD_PREP(MT_TXP_BUF_LEN, tx_info->buf[1].len) | + MT_TXP3_ML0_MASK; #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT - len |= FIELD_PREP(MT_TXP_DMA_ADDR_H, - tx_info->buf[i + 1].addr >> 32); + val |= FIELD_PREP(MT_TXP3_DMA_ADDR_H, + tx_info->buf[1].addr >> 32); #endif + ptr[3] = cpu_to_le32(val); + } else { + struct mt76_connac_txp_common *txp; - txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); - txp->fw.len[i] = cpu_to_le16(len); - } - txp->fw.nbuf = nbuf; + txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE); + for (i = 0; i < nbuf; i++) { + u16 len; - txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST); + len = FIELD_PREP(MT_TXP_BUF_LEN, tx_info->buf[i + 1].len); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + len |= FIELD_PREP(MT_TXP_DMA_ADDR_H, + tx_info->buf[i + 1].addr >> 32); +#endif - if (!is_8023 || pid >= MT_PACKET_ID_FIRST) - txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD); + txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr); + txp->fw.len[i] = cpu_to_le16(len); + } + txp->fw.nbuf = nbuf; - if (!key) - txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); + txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST); - if (!is_8023 && mt7996_tx_use_mgmt(dev, tx_info->skb)) - txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); + if (!is_8023 || pid >= MT_PACKET_ID_FIRST) + txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD); - if (vif) { - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt76_vif_link *mlink = NULL; + if (!key) + txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME); - if (wcid->offchannel) - mlink = rcu_dereference(mvif->mt76.offchannel_link); - if (!mlink) - mlink = &mvif->deflink.mt76; + if (!is_8023 && mt7996_tx_use_mgmt(dev, tx_info->skb)) + txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME); - txp->fw.bss_idx = mlink->idx; - } + if (vif) { + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct mt76_vif_link *mlink = NULL; - txp->fw.token = cpu_to_le16(id); - txp->fw.rept_wds_wcid = cpu_to_le16(sta ? wcid->idx : 0xfff); + if (wcid->offchannel) + mlink = rcu_dereference(mvif->mt76.offchannel_link); + if (!mlink) + mlink = rcu_dereference(mvif->mt76.link[wcid->link_id]); + + txp->fw.bss_idx = mlink ? mlink->idx : mvif->deflink.mt76.idx; + } + + txp->fw.token = cpu_to_le16(id); + txp->fw.rept_wds_wcid = cpu_to_le16(sta ? wcid->idx : 0xfff); + } tx_info->skb = NULL; @@ -1126,15 +1204,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 +1220,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 +1237,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 +1255,16 @@ 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))) { + struct mt7996_sta *msta; - if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE))) - mt7996_tx_check_aggr(sta, t->skb); + /* AMPDU state is stored in the primary link */ + msta = (void *)link_sta->sta->drv_priv; + mt7996_tx_check_aggr(link_sta, &msta->deflink.wcid, + t->skb); + } } else { wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX); } @@ -1204,8 +1283,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,18 +1321,39 @@ 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; + unsigned long valid_links; + struct mt7996_sta *msta; + unsigned int id; u16 idx; idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info); wcid = mt76_wcid_ptr(dev, idx); sta = wcid_to_sta(wcid); - if (!sta) + if (!sta) { + link_sta = NULL; + goto next; + } + + link_sta = rcu_dereference(sta->link[wcid->link_id]); + if (!link_sta) goto next; - msta_link = container_of(wcid, struct mt7996_sta_link, - wcid); - mt76_wcid_add_poll(&dev->mt76, &msta_link->wcid); + msta = (struct mt7996_sta *)sta->drv_priv; + valid_links = sta->valid_links ?: BIT(0); + + /* For MLD STA, add all link's wcid to sta_poll_list */ + for_each_set_bit(id, &valid_links, + IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_sta_link *msta_link; + + msta_link = rcu_dereference(msta->link[id]); + if (!msta_link) + continue; + + mt76_wcid_add_poll(&dev->mt76, + &msta_link->wcid); + } next: /* ver 7 has a new DW with pair = 1, skip it */ if (ver == 7 && ((void *)(cur_info + 1) < end) && @@ -1286,7 +1386,8 @@ next: if (!txwi) continue; - mt7996_txwi_free(dev, txwi, sta, &free_list); + mt7996_txwi_free(dev, txwi, link_sta, wcid, + &free_list); } } @@ -1570,6 +1671,363 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, } } +static struct mt7996_msdu_page * +mt7996_msdu_page_get_from_cache(struct mt7996_dev *dev) +{ + struct mt7996_msdu_page *p = NULL; + + spin_lock(&dev->wed_rro.lock); + + if (!list_empty(&dev->wed_rro.page_cache)) { + p = list_first_entry(&dev->wed_rro.page_cache, + struct mt7996_msdu_page, list); + if (p) + list_del(&p->list); + } + + spin_unlock(&dev->wed_rro.lock); + + return p; +} + +static struct mt7996_msdu_page *mt7996_msdu_page_get(struct mt7996_dev *dev) +{ + struct mt7996_msdu_page *p; + + p = mt7996_msdu_page_get_from_cache(dev); + if (!p) { + p = kzalloc(L1_CACHE_ALIGN(sizeof(*p)), GFP_ATOMIC); + if (p) + INIT_LIST_HEAD(&p->list); + } + + return p; +} + +static void mt7996_msdu_page_put_to_cache(struct mt7996_dev *dev, + struct mt7996_msdu_page *p) +{ + if (p->buf) { + mt76_put_page_pool_buf(p->buf, false); + p->buf = NULL; + } + + spin_lock(&dev->wed_rro.lock); + list_add(&p->list, &dev->wed_rro.page_cache); + spin_unlock(&dev->wed_rro.lock); +} + +static void mt7996_msdu_page_free_cache(struct mt7996_dev *dev) +{ + while (true) { + struct mt7996_msdu_page *p; + + p = mt7996_msdu_page_get_from_cache(dev); + if (!p) + break; + + if (p->buf) + mt76_put_page_pool_buf(p->buf, false); + + kfree(p); + } +} + +static u32 mt7996_msdu_page_hash_from_addr(dma_addr_t dma_addr) +{ + u32 val = 0; + int i = 0; + + while (dma_addr) { + val += (u32)((dma_addr & 0xff) + i) % MT7996_RRO_MSDU_PG_HASH_SIZE; + dma_addr >>= 8; + i += 13; + } + + return val % MT7996_RRO_MSDU_PG_HASH_SIZE; +} + +static struct mt7996_msdu_page * +mt7996_rro_msdu_page_get(struct mt7996_dev *dev, dma_addr_t dma_addr) +{ + u32 hash = mt7996_msdu_page_hash_from_addr(dma_addr); + struct mt7996_msdu_page *p, *tmp, *addr = NULL; + + spin_lock(&dev->wed_rro.lock); + + list_for_each_entry_safe(p, tmp, &dev->wed_rro.page_map[hash], + list) { + if (p->dma_addr == dma_addr) { + list_del(&p->list); + addr = p; + break; + } + } + + spin_unlock(&dev->wed_rro.lock); + + return addr; +} + +static void mt7996_rx_token_put(struct mt7996_dev *dev) +{ + int i; + + for (i = 0; i < dev->mt76.rx_token_size; i++) { + struct mt76_txwi_cache *t; + + t = mt76_rx_token_release(&dev->mt76, i); + if (!t || !t->ptr) + continue; + + mt76_put_page_pool_buf(t->ptr, false); + t->dma_addr = 0; + t->ptr = NULL; + + mt76_put_rxwi(&dev->mt76, t); + } +} + +void mt7996_rro_msdu_page_map_free(struct mt7996_dev *dev) +{ + struct mt7996_msdu_page *p, *tmp; + int i; + + local_bh_disable(); + + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.page_map); i++) { + list_for_each_entry_safe(p, tmp, &dev->wed_rro.page_map[i], + list) { + list_del_init(&p->list); + if (p->buf) + mt76_put_page_pool_buf(p->buf, false); + kfree(p); + } + } + mt7996_msdu_page_free_cache(dev); + + local_bh_enable(); + + mt7996_rx_token_put(dev); +} + +int mt7996_rro_msdu_page_add(struct mt76_dev *mdev, struct mt76_queue *q, + dma_addr_t dma_addr, void *data) +{ + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt7996_msdu_page_info *pinfo = data; + struct mt7996_msdu_page *p; + u32 hash; + + pinfo->data |= cpu_to_le32(FIELD_PREP(MSDU_PAGE_INFO_OWNER_MASK, 1)); + p = mt7996_msdu_page_get(dev); + if (!p) + return -ENOMEM; + + p->buf = data; + p->dma_addr = dma_addr; + p->q = q; + + hash = mt7996_msdu_page_hash_from_addr(dma_addr); + + spin_lock(&dev->wed_rro.lock); + list_add_tail(&p->list, &dev->wed_rro.page_map[hash]); + spin_unlock(&dev->wed_rro.lock); + + return 0; +} + +static struct mt7996_wed_rro_addr * +mt7996_rro_addr_elem_get(struct mt7996_dev *dev, u16 session_id, u16 seq_num) +{ + u32 idx = 0; + void *addr; + + if (session_id == MT7996_RRO_MAX_SESSION) { + addr = dev->wed_rro.session.ptr; + } else { + idx = session_id / MT7996_RRO_BA_BITMAP_SESSION_SIZE; + addr = dev->wed_rro.addr_elem[idx].ptr; + + idx = session_id % MT7996_RRO_BA_BITMAP_SESSION_SIZE; + idx = idx * MT7996_RRO_WINDOW_MAX_LEN; + } + idx += seq_num % MT7996_RRO_WINDOW_MAX_LEN; + + return addr + idx * sizeof(struct mt7996_wed_rro_addr); +} + +#define MT996_RRO_SN_MASK GENMASK(11, 0) + +void mt7996_rro_rx_process(struct mt76_dev *mdev, void *data) +{ + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); + struct mt76_wed_rro_ind *cmd = (struct mt76_wed_rro_ind *)data; + u32 cmd_data0 = le32_to_cpu(cmd->data0); + u32 cmd_data1 = le32_to_cpu(cmd->data1); + u8 ind_reason = FIELD_GET(RRO_IND_DATA0_IND_REASON_MASK, cmd_data0); + u16 start_seq = FIELD_GET(RRO_IND_DATA0_START_SEQ_MASK, cmd_data0); + u16 seq_id = FIELD_GET(RRO_IND_DATA0_SEQ_ID_MASK, cmd_data0); + u16 ind_count = FIELD_GET(RRO_IND_DATA1_IND_COUNT_MASK, cmd_data1); + struct mt7996_msdu_page_info *pinfo = NULL; + struct mt7996_msdu_page *p = NULL; + int i, seq_num = 0; + + for (i = 0; i < ind_count; i++) { + struct mt7996_wed_rro_addr *e; + struct mt76_rx_status *status; + struct mt7996_rro_hif *rxd; + int j, len, qid, data_len; + struct mt76_txwi_cache *t; + dma_addr_t dma_addr = 0; + u16 rx_token_id, count; + struct mt76_queue *q; + struct sk_buff *skb; + u32 info = 0, data; + u8 signature; + void *buf; + bool ls; + + seq_num = FIELD_GET(MT996_RRO_SN_MASK, start_seq + i); + e = mt7996_rro_addr_elem_get(dev, seq_id, seq_num); + data = le32_to_cpu(e->data); + signature = FIELD_GET(WED_RRO_ADDR_SIGNATURE_MASK, data); + if (signature != (seq_num / MT7996_RRO_WINDOW_MAX_LEN)) { + u32 val = FIELD_PREP(WED_RRO_ADDR_SIGNATURE_MASK, + 0xff); + + e->data |= cpu_to_le32(val); + goto update_ack_seq_num; + } + +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + dma_addr = FIELD_GET(WED_RRO_ADDR_HEAD_HIGH_MASK, data); + dma_addr <<= 32; +#endif + dma_addr |= le32_to_cpu(e->head_low); + + count = FIELD_GET(WED_RRO_ADDR_COUNT_MASK, data); + for (j = 0; j < count; j++) { + if (!p) { + p = mt7996_rro_msdu_page_get(dev, dma_addr); + if (!p) + continue; + + dma_sync_single_for_cpu(mdev->dma_dev, p->dma_addr, + SKB_WITH_OVERHEAD(p->q->buf_size), + page_pool_get_dma_dir(p->q->page_pool)); + pinfo = (struct mt7996_msdu_page_info *)p->buf; + } + + rxd = &pinfo->rxd[j % MT7996_MAX_HIF_RXD_IN_PG]; + len = FIELD_GET(RRO_HIF_DATA1_SDL_MASK, + le32_to_cpu(rxd->data1)); + + rx_token_id = FIELD_GET(RRO_HIF_DATA4_RX_TOKEN_ID_MASK, + le32_to_cpu(rxd->data4)); + t = mt76_rx_token_release(mdev, rx_token_id); + if (!t) + goto next_page; + + qid = t->qid; + buf = t->ptr; + q = &mdev->q_rx[qid]; + dma_sync_single_for_cpu(mdev->dma_dev, t->dma_addr, + SKB_WITH_OVERHEAD(q->buf_size), + page_pool_get_dma_dir(q->page_pool)); + + t->dma_addr = 0; + t->ptr = NULL; + mt76_put_rxwi(mdev, t); + if (!buf) + goto next_page; + + if (q->rx_head) + data_len = q->buf_size; + else + data_len = SKB_WITH_OVERHEAD(q->buf_size); + + if (data_len < len + q->buf_offset) { + dev_kfree_skb(q->rx_head); + mt76_put_page_pool_buf(buf, false); + q->rx_head = NULL; + goto next_page; + } + + ls = FIELD_GET(RRO_HIF_DATA1_LS_MASK, + le32_to_cpu(rxd->data1)); + if (q->rx_head) { + /* TODO: Take into account non-linear skb. */ + mt76_put_page_pool_buf(buf, false); + if (ls) { + dev_kfree_skb(q->rx_head); + q->rx_head = NULL; + } + goto next_page; + } + + if (ls && !mt7996_rx_check(mdev, buf, len)) + goto next_page; + + skb = build_skb(buf, q->buf_size); + if (!skb) + goto next_page; + + skb_reserve(skb, q->buf_offset); + skb_mark_for_recycle(skb); + __skb_put(skb, len); + + if (ind_reason == 1 || ind_reason == 2) { + dev_kfree_skb(skb); + goto next_page; + } + + if (!ls) { + q->rx_head = skb; + goto next_page; + } + + status = (struct mt76_rx_status *)skb->cb; + if (seq_id != MT7996_RRO_MAX_SESSION) + status->aggr = true; + + mt7996_queue_rx_skb(mdev, qid, skb, &info); +next_page: + if ((j + 1) % MT7996_MAX_HIF_RXD_IN_PG == 0) { +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + dma_addr = + FIELD_GET(MSDU_PAGE_INFO_PG_HIGH_MASK, + le32_to_cpu(pinfo->data)); + dma_addr <<= 32; + dma_addr |= le32_to_cpu(pinfo->pg_low); +#else + dma_addr = le32_to_cpu(pinfo->pg_low); +#endif + mt7996_msdu_page_put_to_cache(dev, p); + p = NULL; + } + } + +update_ack_seq_num: + if ((i + 1) % 4 == 0) + mt76_wr(dev, MT_RRO_ACK_SN_CTRL, + FIELD_PREP(MT_RRO_ACK_SN_CTRL_SESSION_MASK, + seq_id) | + FIELD_PREP(MT_RRO_ACK_SN_CTRL_SN_MASK, + seq_num)); + if (p) { + mt7996_msdu_page_put_to_cache(dev, p); + p = NULL; + } + } + + /* Update ack_seq_num for remaining addr_elem */ + if (i % 4) + mt76_wr(dev, MT_RRO_ACK_SN_CTRL, + FIELD_PREP(MT_RRO_ACK_SN_CTRL_SESSION_MASK, seq_id) | + FIELD_PREP(MT_RRO_ACK_SN_CTRL_SN_MASK, seq_num)); +} + void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; @@ -1696,17 +2154,38 @@ mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state) static void mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) { - struct ieee80211_hw *hw = priv; + struct ieee80211_bss_conf *link_conf; + struct mt7996_phy *phy = priv; + struct mt7996_dev *dev = phy->dev; + unsigned int link_id; + switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_AP: - mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf); break; default: - break; + return; } + + for_each_vif_active_link(vif, link_conf, link_id) { + struct mt7996_vif_link *link; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link || link->phy != phy) + continue; + + mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf, + link_conf->enable_beacon); + } +} + +void mt7996_mac_update_beacons(struct mt7996_phy *phy) +{ + ieee80211_iterate_active_interfaces(phy->mt76->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7996_update_vif_beacon, phy); } static void @@ -1714,25 +2193,15 @@ mt7996_update_beacons(struct mt7996_dev *dev) { struct mt76_phy *phy2, *phy3; - ieee80211_iterate_active_interfaces(dev->mt76.hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7996_update_vif_beacon, dev->mt76.hw); + mt7996_mac_update_beacons(&dev->phy); phy2 = dev->mt76.phys[MT_BAND1]; - if (!phy2) - return; - - ieee80211_iterate_active_interfaces(phy2->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7996_update_vif_beacon, phy2->hw); + if (phy2) + mt7996_mac_update_beacons(phy2->priv); phy3 = dev->mt76.phys[MT_BAND2]; - if (!phy3) - return; - - ieee80211_iterate_active_interfaces(phy3->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7996_update_vif_beacon, phy3->hw); + if (phy3) + mt7996_mac_update_beacons(phy3->priv); } void mt7996_tx_token_put(struct mt7996_dev *dev) @@ -1742,7 +2211,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); @@ -1752,13 +2221,10 @@ void mt7996_tx_token_put(struct mt7996_dev *dev) static int mt7996_mac_restart(struct mt7996_dev *dev) { - struct mt7996_phy *phy2, *phy3; struct mt76_dev *mdev = &dev->mt76; + struct mt7996_phy *phy; int i, ret; - phy2 = mt7996_phy2(dev); - phy3 = mt7996_phy3(dev); - if (dev->hif2) { mt76_wr(dev, MT_INT1_MASK_CSR, 0x0); mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0); @@ -1770,20 +2236,14 @@ mt7996_mac_restart(struct mt7996_dev *dev) mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0); } - set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); + mt7996_for_each_phy(dev, phy) + set_bit(MT76_RESET, &phy->mt76->state); wake_up(&dev->mt76.mcu.wait); - if (phy2) - set_bit(MT76_RESET, &phy2->mt76->state); - if (phy3) - set_bit(MT76_RESET, &phy3->mt76->state); /* lock/unlock all queues to ensure that no tx is pending */ - mt76_txq_schedule_all(&dev->mphy); - if (phy2) - mt76_txq_schedule_all(phy2->mt76); - if (phy3) - mt76_txq_schedule_all(phy3->mt76); + mt7996_for_each_phy(dev, phy) + mt76_txq_schedule_all(phy->mt76); /* disable all tx/rx napi */ mt76_worker_disable(&dev->mt76.tx_worker); @@ -1835,42 +2295,57 @@ mt7996_mac_restart(struct mt7996_dev *dev) if (ret) goto out; + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && + mt7996_has_hwrro(dev)) { + u32 wed_irq_mask = dev->mt76.mmio.irqmask | + MT_INT_TX_DONE_BAND2; + + mt7996_rro_hw_init(dev); + mt76_for_each_q_rx(&dev->mt76, i) { + if (mt76_queue_is_wed_rro_ind(&dev->mt76.q_rx[i]) || + mt76_queue_is_wed_rro_msdu_pg(&dev->mt76.q_rx[i])) + mt76_queue_rx_reset(dev, i); + } + + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); + mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask, + false); + mt7996_irq_enable(dev, wed_irq_mask); + mt7996_irq_disable(dev, 0); + } + + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) { + mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, + MT_INT_TX_RX_DONE_EXT); + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, + MT_INT_TX_RX_DONE_EXT); + } + /* set the necessary init items */ ret = mt7996_mcu_set_eeprom(dev); if (ret) goto out; mt7996_mac_init(dev); - mt7996_init_txpower(&dev->phy); - mt7996_init_txpower(phy2); - mt7996_init_txpower(phy3); + mt7996_for_each_phy(dev, phy) + mt7996_init_txpower(phy); ret = mt7996_txbf_init(dev); + if (ret) + goto out; - if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { - ret = mt7996_run(&dev->phy); - if (ret) - goto out; - } - - if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) { - ret = mt7996_run(phy2); - if (ret) - goto out; - } + mt7996_for_each_phy(dev, phy) { + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + continue; - if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) { - ret = mt7996_run(phy3); + ret = mt7996_run(&dev->phy); if (ret) goto out; } out: /* reset done */ - clear_bit(MT76_RESET, &dev->mphy.state); - if (phy2) - clear_bit(MT76_RESET, &phy2->mt76->state); - if (phy3) - clear_bit(MT76_RESET, &phy3->mt76->state); + mt7996_for_each_phy(dev, phy) + clear_bit(MT76_RESET, &phy->mt76->state); napi_enable(&dev->mt76.tx_napi); local_bh_disable(); @@ -1882,74 +2357,121 @@ out: } static void +mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_dev *dev = data; + int i; + + for (i = 0; i < ARRAY_SIZE(msta->link); i++) { + struct mt7996_sta_link *msta_link = NULL; + + msta_link = rcu_replace_pointer(msta->link[i], msta_link, + lockdep_is_held(&dev->mt76.mutex)); + if (!msta_link) + continue; + + mt7996_mac_sta_deinit_link(dev, msta_link); + + if (msta->deflink_id == i) { + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + continue; + } + + kfree_rcu(msta_link, rcu_head); + } +} + +static void +mt7996_mac_reset_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + struct mt7996_dev *dev = data; + int i; + + rcu_read_lock(); + for (i = 0; i < ARRAY_SIZE(mvif->link); i++) { + + mlink = mt76_dereference(mvif->link[i], &dev->mt76); + if (!mlink || mlink == (struct mt76_vif_link *)vif->drv_priv) + continue; + + rcu_assign_pointer(mvif->link[i], NULL); + kfree_rcu(mlink, rcu_head); + } + rcu_read_unlock(); +} + +static void mt7996_mac_full_reset(struct mt7996_dev *dev) { - struct mt7996_phy *phy2, *phy3; + struct ieee80211_hw *hw = mt76_hw(dev); + struct mt7996_phy *phy; + LIST_HEAD(list); int i; - phy2 = mt7996_phy2(dev); - phy3 = mt7996_phy3(dev); dev->recovery.hw_full_reset = true; wake_up(&dev->mt76.mcu.wait); - ieee80211_stop_queues(mt76_hw(dev)); - if (phy2) - ieee80211_stop_queues(phy2->mt76->hw); - if (phy3) - ieee80211_stop_queues(phy3->mt76->hw); + ieee80211_stop_queues(hw); cancel_work_sync(&dev->wed_rro.work); - cancel_delayed_work_sync(&dev->mphy.mac_work); - if (phy2) - cancel_delayed_work_sync(&phy2->mt76->mac_work); - if (phy3) - cancel_delayed_work_sync(&phy3->mt76->mac_work); + mt7996_for_each_phy(dev, phy) + cancel_delayed_work_sync(&phy->mt76->mac_work); mutex_lock(&dev->mt76.mutex); for (i = 0; i < 10; i++) { if (!mt7996_mac_restart(dev)) break; } - mutex_unlock(&dev->mt76.mutex); if (i == 10) dev_err(dev->mt76.dev, "chip full reset failed\n"); - ieee80211_restart_hw(mt76_hw(dev)); - if (phy2) - ieee80211_restart_hw(phy2->mt76->hw); - if (phy3) - ieee80211_restart_hw(phy3->mt76->hw); + mt7996_for_each_phy(dev, phy) + phy->omac_mask = 0; - ieee80211_wake_queues(mt76_hw(dev)); - if (phy2) - ieee80211_wake_queues(phy2->mt76->hw); - if (phy3) - ieee80211_wake_queues(phy3->mt76->hw); + ieee80211_iterate_stations_atomic(hw, mt7996_mac_reset_sta_iter, dev); + ieee80211_iterate_active_interfaces_atomic(hw, + IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER, + mt7996_mac_reset_vif_iter, dev); + mt76_reset_device(&dev->mt76); + + INIT_LIST_HEAD(&dev->sta_rc_list); + INIT_LIST_HEAD(&dev->twt_list); + + spin_lock_bh(&dev->wed_rro.lock); + list_splice_init(&dev->wed_rro.poll_list, &list); + spin_unlock_bh(&dev->wed_rro.lock); + while (!list_empty(&list)) { + struct mt7996_wed_rro_session_id *e; + + e = list_first_entry(&list, struct mt7996_wed_rro_session_id, + list); + list_del_init(&e->list); + kfree(e); + } + + i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); + dev->mt76.global_wcid.idx = i; dev->recovery.hw_full_reset = false; - ieee80211_queue_delayed_work(mt76_hw(dev), - &dev->mphy.mac_work, - MT7996_WATCHDOG_TIME); - if (phy2) - ieee80211_queue_delayed_work(phy2->mt76->hw, - &phy2->mt76->mac_work, - MT7996_WATCHDOG_TIME); - if (phy3) - ieee80211_queue_delayed_work(phy3->mt76->hw, - &phy3->mt76->mac_work, - MT7996_WATCHDOG_TIME); + + mutex_unlock(&dev->mt76.mutex); + + ieee80211_restart_hw(mt76_hw(dev)); } void mt7996_mac_reset_work(struct work_struct *work) { - struct mt7996_phy *phy2, *phy3; + struct ieee80211_hw *hw; struct mt7996_dev *dev; + struct mt7996_phy *phy; int i; dev = container_of(work, struct mt7996_dev, reset_work); - phy2 = mt7996_phy2(dev); - phy3 = mt7996_phy3(dev); + hw = mt76_hw(dev); /* chip full reset */ if (dev->recovery.restart) { @@ -1980,7 +2502,7 @@ void mt7996_mac_reset_work(struct work_struct *work) return; dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.", - wiphy_name(dev->mt76.hw->wiphy)); + wiphy_name(hw->wiphy)); if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) mtk_wed_device_stop(&dev->mt76.mmio.wed_hif2); @@ -1989,25 +2511,19 @@ void mt7996_mac_reset_work(struct work_struct *work) mtk_wed_device_stop(&dev->mt76.mmio.wed); ieee80211_stop_queues(mt76_hw(dev)); - if (phy2) - ieee80211_stop_queues(phy2->mt76->hw); - if (phy3) - ieee80211_stop_queues(phy3->mt76->hw); set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); + mt76_abort_scan(&dev->mt76); wake_up(&dev->mt76.mcu.wait); cancel_work_sync(&dev->wed_rro.work); - cancel_delayed_work_sync(&dev->mphy.mac_work); - if (phy2) { - set_bit(MT76_RESET, &phy2->mt76->state); - cancel_delayed_work_sync(&phy2->mt76->mac_work); - } - if (phy3) { - set_bit(MT76_RESET, &phy3->mt76->state); - cancel_delayed_work_sync(&phy3->mt76->mac_work); + mt7996_for_each_phy(dev, phy) { + mt76_abort_roc(phy->mt76); + set_bit(MT76_RESET, &phy->mt76->state); + cancel_delayed_work_sync(&phy->mt76->mac_work); } + mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(&dev->mt76, i) { if (mtk_wed_device_active(&dev->mt76.mmio.wed) && @@ -2038,15 +2554,14 @@ void mt7996_mac_reset_work(struct work_struct *work) /* enable DMA Tx/Tx and interrupt */ mt7996_dma_start(dev, false, false); + if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3) + mt76_wr(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { - u32 wed_irq_mask = MT_INT_RRO_RX_DONE | MT_INT_TX_DONE_BAND2 | + u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 | dev->mt76.mmio.irqmask; - if (mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) - wed_irq_mask &= ~MT_INT_RX_DONE_RRO_IND; - mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); - mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask, true); mt7996_irq_enable(dev, wed_irq_mask); @@ -2060,11 +2575,8 @@ void mt7996_mac_reset_work(struct work_struct *work) } clear_bit(MT76_MCU_RESET, &dev->mphy.state); - clear_bit(MT76_RESET, &dev->mphy.state); - if (phy2) - clear_bit(MT76_RESET, &phy2->mt76->state); - if (phy3) - clear_bit(MT76_RESET, &phy3->mt76->state); + mt7996_for_each_phy(dev, phy) + clear_bit(MT76_RESET, &phy->mt76->state); mt76_for_each_q_rx(&dev->mt76, i) { if (mtk_wed_device_active(&dev->mt76.mmio.wed) && @@ -2086,25 +2598,14 @@ void mt7996_mac_reset_work(struct work_struct *work) napi_schedule(&dev->mt76.tx_napi); local_bh_enable(); - ieee80211_wake_queues(mt76_hw(dev)); - if (phy2) - ieee80211_wake_queues(phy2->mt76->hw); - if (phy3) - ieee80211_wake_queues(phy3->mt76->hw); + ieee80211_wake_queues(hw); mutex_unlock(&dev->mt76.mutex); mt7996_update_beacons(dev); - ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work, - MT7996_WATCHDOG_TIME); - if (phy2) - ieee80211_queue_delayed_work(phy2->mt76->hw, - &phy2->mt76->mac_work, - MT7996_WATCHDOG_TIME); - if (phy3) - ieee80211_queue_delayed_work(phy3->mt76->hw, - &phy3->mt76->mac_work, + mt7996_for_each_phy(dev, phy) + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT7996_WATCHDOG_TIME); dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.", wiphy_name(dev->mt76.hw->wiphy)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index 07dd75ce94a5..581314368c5b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -138,6 +138,28 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask) return -1; } +static int get_own_mld_idx(u64 mask, bool group_mld) +{ + u8 start = group_mld ? 0 : 16; + u8 end = group_mld ? 15 : 63; + int idx; + + idx = get_free_idx(mask, start, end); + if (idx) + return idx - 1; + + /* If the 16-63 range is not available, perform another lookup in the + * range 0-15 + */ + if (!group_mld) { + idx = get_free_idx(mask, 0, 15); + if (idx) + return idx - 1; + } + + return -EINVAL; +} + static void mt7996_init_bitrate_mask(struct ieee80211_vif *vif, struct mt7996_vif_link *mlink) { @@ -160,112 +182,105 @@ mt7996_init_bitrate_mask(struct ieee80211_vif *vif, struct mt7996_vif_link *mlin static int mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key) + unsigned int link_id, struct ieee80211_key_conf *key) { struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct ieee80211_bss_conf *link_conf; + struct mt7996_sta_link *msta_link; + struct mt7996_vif_link *link; int idx = key->keyidx; - unsigned int link_id; - unsigned long links; + u8 *wcid_keyidx; + bool is_bigtk; + int err; - if (key->link_id >= 0) - links = BIT(key->link_id); - else if (sta && sta->valid_links) - links = sta->valid_links; - else if (vif->valid_links) - links = vif->valid_links; - else - links = BIT(0); + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + return 0; - for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct mt7996_sta_link *msta_link; - struct mt7996_vif_link *link; - u8 *wcid_keyidx; - int err; + if (!mt7996_vif_link_phy(link)) + return 0; - link = mt7996_vif_link(dev, vif, link_id); - if (!link) - continue; + if (sta) { + struct mt7996_sta *msta; - if (sta) { - struct mt7996_sta *msta; + msta = (struct mt7996_sta *)sta->drv_priv; + msta_link = mt76_dereference(msta->link[link_id], + &dev->mt76); + if (!msta_link) + return 0; - msta = (struct mt7996_sta *)sta->drv_priv; - msta_link = mt76_dereference(msta->link[link_id], - &dev->mt76); - if (!msta_link) - continue; + if (!msta_link->wcid.sta) + return -EOPNOTSUPP; + } else { + msta_link = &link->msta_link; + } + wcid_keyidx = &msta_link->wcid.hw_key_idx; - if (!msta_link->wcid.sta) - return -EOPNOTSUPP; - } else { - msta_link = &link->msta_link; - } - wcid_keyidx = &msta_link->wcid.hw_key_idx; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_AES_CMAC: - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - if (key->keyidx == 6 || key->keyidx == 7) { - wcid_keyidx = &msta_link->wcid.hw_key_idx2; - key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; - } - break; - default: - break; + is_bigtk = key->keyidx == 6 || key->keyidx == 7; + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + if (is_bigtk) { + wcid_keyidx = &msta_link->wcid.hw_key_idx2; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE; } + break; + default: + break; + } - if (cmd == SET_KEY && !sta && !link->mt76.cipher) { - struct ieee80211_bss_conf *link_conf; + link_conf = link_conf_dereference_protected(vif, link_id); + if (!link_conf) + link_conf = &vif->bss_conf; - link_conf = link_conf_dereference_protected(vif, - link_id); - if (!link_conf) - link_conf = &vif->bss_conf; + if (cmd == SET_KEY && !sta && !link->mt76.cipher) { + link->mt76.cipher = + mt76_connac_mcu_get_cipher(key->cipher); + mt7996_mcu_add_bss_info(link->phy, vif, link_conf, + &link->mt76, msta_link, true); + } - link->mt76.cipher = - mt76_connac_mcu_get_cipher(key->cipher); - mt7996_mcu_add_bss_info(link->phy, vif, link_conf, - &link->mt76, msta_link, true); - } + if (cmd == SET_KEY) + *wcid_keyidx = idx; + else if (idx == *wcid_keyidx) + *wcid_keyidx = -1; - if (cmd == SET_KEY) { - *wcid_keyidx = idx; - } else { - if (idx == *wcid_keyidx) - *wcid_keyidx = -1; - continue; - } + if (cmd != SET_KEY && sta) + return 0; - mt76_wcid_key_setup(&dev->mt76, &msta_link->wcid, key); + mt76_wcid_key_setup(&dev->mt76, &msta_link->wcid, key); - if (key->keyidx == 6 || key->keyidx == 7) { - err = mt7996_mcu_bcn_prot_enable(dev, link, - msta_link, key); - if (err) - return err; - } + err = mt7996_mcu_add_key(&dev->mt76, vif, key, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), + &msta_link->wcid, cmd); - err = mt7996_mcu_add_key(&dev->mt76, vif, key, - MCU_WMWA_UNI_CMD(STA_REC_UPDATE), - &msta_link->wcid, cmd); - if (err) - return err; + /* remove and add beacon in order to enable beacon protection */ + if (cmd == SET_KEY && is_bigtk && link_conf->enable_beacon) { + mt7996_mcu_add_beacon(hw, vif, link_conf, false); + mt7996_mcu_add_beacon(hw, vif, link_conf, true); } - return 0; + return err; } +struct mt7996_key_iter_data { + enum set_key_cmd cmd; + unsigned int link_id; +}; + static void mt7996_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct ieee80211_key_conf *key, void *data) { + struct mt7996_key_iter_data *it = data; + if (sta) return; - WARN_ON(mt7996_set_hw_key(hw, SET_KEY, vif, NULL, key)); + WARN_ON(mt7996_set_hw_key(hw, it->cmd, vif, NULL, it->link_id, key)); } int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, @@ -278,8 +293,12 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, struct mt7996_phy *phy = mphy->priv; struct mt7996_dev *dev = phy->dev; u8 band_idx = phy->mt76->band_idx; + struct mt7996_key_iter_data it = { + .cmd = SET_KEY, + .link_id = link_conf->link_id, + }; struct mt76_txq *mtxq; - int idx, ret; + int mld_idx, idx, ret; mlink->idx = __ffs64(~dev->mt76.vif_mask); if (mlink->idx >= mt7996_max_interface_num(dev)) @@ -289,6 +308,17 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, if (idx < 0) return -ENOSPC; + if (!dev->mld_idx_mask) { /* first link in the group */ + mvif->mld_group_idx = get_own_mld_idx(dev->mld_idx_mask, true); + mvif->mld_remap_idx = get_free_idx(dev->mld_remap_idx_mask, + 0, 15); + } + + mld_idx = get_own_mld_idx(dev->mld_idx_mask, false); + if (mld_idx < 0) + return -ENOSPC; + + link->mld_idx = mld_idx; link->phy = phy; mlink->omac_idx = idx; mlink->band_idx = band_idx; @@ -301,6 +331,11 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, return ret; dev->mt76.vif_mask |= BIT_ULL(mlink->idx); + if (!dev->mld_idx_mask) { + dev->mld_idx_mask |= BIT_ULL(mvif->mld_group_idx); + dev->mld_remap_idx_mask |= BIT_ULL(mvif->mld_remap_idx); + } + dev->mld_idx_mask |= BIT_ULL(link->mld_idx); phy->omac_mask |= BIT_ULL(mlink->omac_idx); idx = MT7996_WTBL_RESERVED - mlink->idx; @@ -339,7 +374,7 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, CONN_STATE_PORT_SECURE, true); rcu_assign_pointer(dev->mt76.wcid[idx], &msta_link->wcid); - ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, NULL); + ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); if (mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) mvif->mt76.deflink_id = link_conf->link_id; @@ -356,8 +391,14 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, struct mt7996_sta_link *msta_link = &link->msta_link; struct mt7996_phy *phy = mphy->priv; struct mt7996_dev *dev = phy->dev; + struct mt7996_key_iter_data it = { + .cmd = SET_KEY, + .link_id = link_conf->link_id, + }; int idx = msta_link->wcid.idx; + ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); + mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, CONN_STATE_DISCONNECT, false); mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false); @@ -380,7 +421,13 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, } dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); + dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx); phy->omac_mask &= ~BIT_ULL(mlink->omac_idx); + if (!(dev->mld_idx_mask & ~BIT_ULL(mvif->mld_group_idx))) { + /* last link */ + dev->mld_idx_mask &= ~BIT_ULL(mvif->mld_group_idx); + dev->mld_remap_idx_mask &= ~BIT_ULL(mvif->mld_remap_idx); + } spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta_link->wcid.poll_list)) @@ -516,6 +563,9 @@ int mt7996_set_channel(struct mt76_phy *mphy) struct mt7996_phy *phy = mphy->priv; int ret; + if (mphy->offchannel) + mt7996_mac_update_beacons(phy); + ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH); if (ret) goto out; @@ -533,6 +583,8 @@ int mt7996_set_channel(struct mt76_phy *mphy) mt7996_mac_reset_counters(phy); phy->noise = 0; + if (!mphy->offchannel) + mt7996_mac_update_beacons(phy); out: ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, @@ -546,8 +598,9 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - int err; + unsigned int link_id; + unsigned long links; + int err = 0; /* The hardware does not support per-STA RX GTK, fallback * to software mode for these. @@ -581,17 +634,28 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return -EOPNOTSUPP; } - if (!mt7996_vif_link_phy(&mvif->deflink)) - return 0; /* defer until after link add */ - mutex_lock(&dev->mt76.mutex); - err = mt7996_set_hw_key(hw, cmd, vif, sta, key); + + if (key->link_id >= 0) + links = BIT(key->link_id); + else if (sta && sta->valid_links) + links = sta->valid_links; + else if (vif->valid_links) + links = vif->valid_links; + else + links = BIT(0); + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + err = mt7996_set_hw_key(hw, cmd, vif, sta, link_id, key); + if (err) + break; + } mutex_unlock(&dev->mt76.mutex); 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; } @@ -845,7 +909,7 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, link->mt76.beacon_rates_idx = mt7996_get_rates_table(phy, info, true, false); - mt7996_mcu_add_beacon(hw, vif, info); + mt7996_mcu_add_beacon(hw, vif, info, info->enable_beacon); } if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP | @@ -873,7 +937,7 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw, struct mt7996_dev *dev = mt7996_hw_dev(hw); mutex_lock(&dev->mt76.mutex); - mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf); + mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf, vif->bss_conf.enable_beacon); mutex_unlock(&dev->mt76.mutex); } @@ -920,6 +984,7 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, msta_link->wcid.sta = 1; msta_link->wcid.idx = idx; msta_link->wcid.link_id = link_id; + msta_link->wcid.def_wcid = &msta->deflink.wcid; ewma_avg_signal_init(&msta_link->avg_ack_signal); ewma_signal_init(&msta_link->wcid.rssi); @@ -936,18 +1001,9 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, return 0; } -static void -mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, - struct mt7996_sta_link *msta_link) +void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, + struct mt7996_sta_link *msta_link) { - int i; - - for (i = 0; i < ARRAY_SIZE(msta_link->wcid.aggr); i++) - mt76_rx_aggr_stop(&dev->mt76, &msta_link->wcid, i); - - mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, - MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta_link->wcid.poll_list)) list_del_init(&msta_link->wcid.poll_list); @@ -960,8 +1016,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,13 +1025,27 @@ 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)); if (!msta_link) continue; + mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, + MT_WTBL_UPDATE_ADM_COUNT_CLEAR); + 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 +1067,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; @@ -1019,16 +1090,24 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, goto error_unlink; } + mphy = mt76_vif_link_phy(&link->mt76); + if (!mphy) { + err = -EINVAL; + goto error_unlink; + } + err = mt7996_mac_sta_init_link(dev, link_conf, link_sta, link, link_id); if (err) 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 +1124,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 +1133,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 +1193,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 +1224,32 @@ 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); + unsigned long links = sta->valid_links ? sta->valid_links : BIT(0); + + mutex_lock(&dev->mt76.mutex); + mt7996_mac_sta_remove_links(dev, vif, sta, links); + mutex_unlock(&dev->mt76.mutex); +} + +static void +mt7996_set_active_links(struct ieee80211_vif *vif) +{ + u16 active_links; + + if (vif->type != NL80211_IFTYPE_STATION) + return; - mutex_lock(&mdev->mutex); + if (!ieee80211_vif_is_mld(vif)) + return; - mt7996_mac_sta_remove_links(dev, sta, links); - mphy->num_sta--; + active_links = mt76_select_links(vif, MT7996_MAX_RADIOS); + if (hweight16(active_links) < 2) + return; - mutex_unlock(&mdev->mutex); + ieee80211_set_active_links_async(vif, active_links); } static int @@ -1170,32 +1257,30 @@ 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) + new_state == IEEE80211_STA_ASSOC) { + mt7996_set_active_links(vif); ev = MT76_STA_EVENT_ASSOC; - else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTHORIZED) + } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTHORIZED) { ev = MT76_STA_EVENT_AUTHORIZE; - else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTH) + } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) { ev = MT76_STA_EVENT_DISASSOC; - else + } else { return 0; + } return mt7996_mac_sta_event(dev, vif, sta, ev); } @@ -1204,22 +1289,62 @@ static void mt7996_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct ieee80211_sta *sta = control->sta; + struct mt7996_sta *msta = sta ? (void *)sta->drv_priv : NULL; struct mt76_phy *mphy = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; + struct mt7996_vif *mvif = vif ? (void *)vif->drv_priv : NULL; struct mt76_wcid *wcid = &dev->mt76.global_wcid; u8 link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK); rcu_read_lock(); - if (vif) { - struct mt7996_vif *mvif = (void *)vif->drv_priv; - struct mt76_vif_link *mlink; + /* Use primary link_id if the value from mac80211 is set to + * IEEE80211_LINK_UNSPECIFIED. + */ + if (link_id == IEEE80211_LINK_UNSPECIFIED) { + if (msta) + link_id = msta->deflink_id; + else if (mvif) + link_id = mvif->mt76.deflink_id; + } + + if (vif && ieee80211_vif_is_mld(vif)) { + struct ieee80211_bss_conf *link_conf; + + if (msta) { + struct ieee80211_link_sta *link_sta; + + link_sta = rcu_dereference(sta->link[link_id]); + if (!link_sta) + link_sta = rcu_dereference(sta->link[msta->deflink_id]); + + if (link_sta) { + memcpy(hdr->addr1, link_sta->addr, ETH_ALEN); + if (ether_addr_equal(sta->addr, hdr->addr3)) + memcpy(hdr->addr3, link_sta->addr, ETH_ALEN); + } + } + + link_conf = rcu_dereference(vif->link_conf[link_id]); + if (link_conf) { + memcpy(hdr->addr2, link_conf->addr, ETH_ALEN); + if (ether_addr_equal(vif->addr, hdr->addr3)) + memcpy(hdr->addr3, link_conf->addr, ETH_ALEN); + } + } + + if (mvif) { + struct mt76_vif_link *mlink = &mvif->deflink.mt76; - mlink = rcu_dereference(mvif->mt76.link[link_id]); - if (mlink && mlink->wcid) + if (link_id < IEEE80211_LINK_UNSPECIFIED) + mlink = rcu_dereference(mvif->mt76.link[link_id]); + + if (mlink->wcid) wcid = mlink->wcid; if (mvif->mt76.roc_phy && @@ -1228,7 +1353,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,8 +1362,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, goto unlock; } - if (control->sta) { - struct mt7996_sta *msta = (void *)control->sta->drv_priv; + if (msta && link_id < IEEE80211_LINK_UNSPECIFIED) { struct mt7996_sta_link *msta_link; msta_link = rcu_dereference(msta->link[link_id]); @@ -1250,7 +1374,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; @@ -1274,16 +1399,13 @@ static int mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) { - enum ieee80211_ampdu_mlme_action action = params->action; struct mt7996_dev *dev = mt7996_hw_dev(hw); struct ieee80211_sta *sta = params->sta; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct ieee80211_txq *txq = sta->txq[params->tid]; - struct ieee80211_link_sta *link_sta; u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; - unsigned int link_id; int ret = 0; if (!txq) @@ -1293,59 +1415,42 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); - for_each_sta_active_link(vif, sta, link_sta, link_id) { - struct mt7996_sta_link *msta_link; - struct mt7996_vif_link *link; - - msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); - if (!msta_link) - continue; - - link = mt7996_vif_link(dev, vif, link_id); - if (!link) - continue; - - switch (action) { - case IEEE80211_AMPDU_RX_START: - mt76_rx_aggr_start(&dev->mt76, &msta_link->wcid, tid, - ssn, params->buf_size); - ret = mt7996_mcu_add_rx_ba(dev, params, link, true); - break; - case IEEE80211_AMPDU_RX_STOP: - mt76_rx_aggr_stop(&dev->mt76, &msta_link->wcid, tid); - ret = mt7996_mcu_add_rx_ba(dev, params, link, false); - break; - case IEEE80211_AMPDU_TX_OPERATIONAL: - mtxq->aggr = true; - mtxq->send_bar = false; - ret = mt7996_mcu_add_tx_ba(dev, params, link, - msta_link, true); - break; - case IEEE80211_AMPDU_TX_STOP_FLUSH: - case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: - mtxq->aggr = false; - clear_bit(tid, &msta_link->wcid.ampdu_state); - ret = mt7996_mcu_add_tx_ba(dev, params, link, - msta_link, false); - break; - case IEEE80211_AMPDU_TX_START: - set_bit(tid, &msta_link->wcid.ampdu_state); - ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; - break; - case IEEE80211_AMPDU_TX_STOP_CONT: - mtxq->aggr = false; - clear_bit(tid, &msta_link->wcid.ampdu_state); - ret = mt7996_mcu_add_tx_ba(dev, params, link, - msta_link, false); - break; - } - - if (ret) - break; - } - - if (action == IEEE80211_AMPDU_TX_STOP_CONT) + switch (params->action) { + case IEEE80211_AMPDU_RX_START: + /* Since packets belonging to the same TID can be split over + * multiple links, store the AMPDU state for reordering in the + * primary link + */ + mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, + ssn, params->buf_size); + ret = mt7996_mcu_add_rx_ba(dev, params, vif, true); + break; + case IEEE80211_AMPDU_RX_STOP: + mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid); + ret = mt7996_mcu_add_rx_ba(dev, params, vif, false); + break; + case IEEE80211_AMPDU_TX_OPERATIONAL: + mtxq->aggr = true; + mtxq->send_bar = false; + ret = mt7996_mcu_add_tx_ba(dev, params, vif, true); + break; + case IEEE80211_AMPDU_TX_STOP_FLUSH: + case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->deflink.wcid.ampdu_state); + ret = mt7996_mcu_add_tx_ba(dev, params, vif, false); + break; + case IEEE80211_AMPDU_TX_START: + set_bit(tid, &msta->deflink.wcid.ampdu_state); + ret = IEEE80211_AMPDU_TX_START_IMMEDIATE; + break; + case IEEE80211_AMPDU_TX_STOP_CONT: + mtxq->aggr = false; + clear_bit(tid, &msta->deflink.wcid.ampdu_state); + ret = mt7996_mcu_add_tx_ba(dev, params, vif, false); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); + break; + } mutex_unlock(&dev->mt76.mutex); @@ -1490,7 +1595,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 +1610,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; @@ -1597,19 +1704,13 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, } } -static void mt7996_link_rate_ctrl_update(void *data, struct ieee80211_sta *sta) +static void mt7996_link_rate_ctrl_update(void *data, + struct mt7996_sta_link *msta_link) { - struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_sta *msta = msta_link->sta; struct mt7996_dev *dev = msta->vif->deflink.phy->dev; - struct mt7996_sta_link *msta_link; u32 *changed = data; - rcu_read_lock(); - - msta_link = rcu_dereference(msta->link[msta->deflink_id]); - if (!msta_link) - goto out; - spin_lock_bh(&dev->mt76.sta_poll_lock); msta_link->changed |= *changed; @@ -1617,8 +1718,6 @@ static void mt7996_link_rate_ctrl_update(void *data, struct ieee80211_sta *sta) list_add_tail(&msta_link->rc_list, &dev->sta_rc_list); spin_unlock_bh(&dev->mt76.sta_poll_lock); -out: - rcu_read_unlock(); } static void mt7996_link_sta_rc_update(struct ieee80211_hw *hw, @@ -1626,11 +1725,32 @@ static void mt7996_link_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_link_sta *link_sta, u32 changed) { - struct mt7996_dev *dev = mt7996_hw_dev(hw); struct ieee80211_sta *sta = link_sta->sta; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_sta_link *msta_link; - mt7996_link_rate_ctrl_update(&changed, sta); - ieee80211_queue_work(hw, &dev->rc_work); + rcu_read_lock(); + + msta_link = rcu_dereference(msta->link[link_sta->link_id]); + if (msta_link) { + struct mt7996_dev *dev = mt7996_hw_dev(hw); + + mt7996_link_rate_ctrl_update(&changed, msta_link); + ieee80211_queue_work(hw, &dev->rc_work); + } + + rcu_read_unlock(); +} + +static void mt7996_sta_rate_ctrl_update(void *data, struct ieee80211_sta *sta) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_sta_link *msta_link; + u32 *changed = data; + + msta_link = rcu_dereference(msta->link[msta->deflink_id]); + if (msta_link) + mt7996_link_rate_ctrl_update(&changed, msta_link); } static int @@ -1651,7 +1771,7 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * - multiple rates: if it's not in range format i.e 0-{7,8,9} for VHT * then multiple MCS setting (MCS 4,5,6) is not supported. */ - ieee80211_iterate_stations_atomic(hw, mt7996_link_rate_ctrl_update, + ieee80211_iterate_stations_atomic(hw, mt7996_sta_rate_ctrl_update, &changed); ieee80211_queue_work(hw, &dev->rc_work); @@ -2052,9 +2172,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mtk_wed_device *wed = &dev->mt76.mmio.wed; struct mt7996_sta_link *msta_link; - struct mt7996_vif_link *link; struct mt76_vif_link *mlink; - struct mt7996_phy *phy; mlink = rcu_dereference(mvif->mt76.link[msta->deflink_id]); if (!mlink) @@ -2067,12 +2185,9 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, if (!msta_link->wcid.sta || msta_link->wcid.idx > MT7996_WTBL_STA) return -EIO; - link = (struct mt7996_vif_link *)mlink; - phy = mt7996_vif_link_phy(link); - if (!phy) - return -ENODEV; - - if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2) + if (dev->hif2 && + ((is_mt7996(&dev->mt76) && msta_link->wcid.phy_idx == MT_BAND2) || + (is_mt7992(&dev->mt76) && msta_link->wcid.phy_idx == MT_BAND1))) wed = &dev->mt76.mmio.wed_hif2; if (!mtk_wed_device_active(wed)) @@ -2085,7 +2200,11 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, path->mtk_wdma.queue = 0; path->mtk_wdma.wcid = msta_link->wcid.idx; - path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed); + if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU) && + mtk_wed_is_amsdu_supported(wed)) + path->mtk_wdma.amsdu = msta_link->wcid.amsdu; + else + path->mtk_wdma.amsdu = 0; ctx->dev = NULL; return 0; @@ -2101,6 +2220,19 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, return 0; } +static void +mt7996_reconfig_complete(struct ieee80211_hw *hw, + enum ieee80211_reconfig_type reconfig_type) +{ + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy; + + ieee80211_wake_queues(hw); + mt7996_for_each_phy(dev, phy) + ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, + MT7996_WATCHDOG_TIME); +} + const struct ieee80211_ops mt7996_ops = { .add_chanctx = mt76_add_chanctx, .remove_chanctx = mt76_remove_chanctx, @@ -2159,4 +2291,5 @@ const struct ieee80211_ops mt7996_ops = { #endif .change_vif_links = mt7996_change_vif_links, .change_sta_links = mt7996_mac_sta_change_links, + .reconfig_complete = mt7996_reconfig_complete, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 994526c65bfc..0347ee0c2dd7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -242,6 +242,30 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, return ret; } +static void +mt7996_mcu_set_timeout(struct mt76_dev *mdev, int cmd) +{ + mdev->mcu.timeout = 5 * HZ; + + if (!(cmd & __MCU_CMD_FIELD_UNI)) + return; + + switch (FIELD_GET(__MCU_CMD_FIELD_ID, cmd)) { + case MCU_UNI_CMD_THERMAL: + case MCU_UNI_CMD_TWT: + case MCU_UNI_CMD_GET_MIB_INFO: + case MCU_UNI_CMD_STA_REC_UPDATE: + case MCU_UNI_CMD_BSS_INFO_UPDATE: + mdev->mcu.timeout = 2 * HZ; + return; + case MCU_UNI_CMD_EFUSE_CTRL: + mdev->mcu.timeout = 20 * HZ; + return; + default: + break; + } +} + static int mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq) @@ -255,7 +279,7 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, u32 val; u8 seq; - mdev->mcu.timeout = 20 * HZ; + mt7996_mcu_set_timeout(mdev, cmd); seq = ++dev->mt76.mcu.msg_seq & 0xf; if (!seq) @@ -660,7 +684,7 @@ mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt7996_mcu_wed_rro_event *event = (void *)skb->data; - if (!dev->has_rro) + if (!mt7996_has_hwrro(dev)) return; skb_pull(skb, sizeof(struct mt7996_mcu_rxd) + 4); @@ -899,17 +923,28 @@ mt7996_mcu_bss_txcmd_tlv(struct sk_buff *skb, bool en) } static void -mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink) +mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, + struct ieee80211_bss_conf *link_conf, + struct mt7996_vif_link *link) { + struct ieee80211_vif *vif = link_conf->vif; + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct bss_mld_tlv *mld; struct tlv *tlv; tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld)); - mld = (struct bss_mld_tlv *)tlv; - mld->group_mld_id = 0xff; - mld->own_mld_id = mlink->idx; - mld->remap_idx = 0xff; + mld->own_mld_id = link->mld_idx; + mld->link_id = link_conf->link_id; + + if (ieee80211_vif_is_mld(vif)) { + mld->group_mld_id = mvif->mld_group_idx; + mld->remap_idx = mvif->mld_remap_idx; + memcpy(mld->mac_addr, vif->addr, ETH_ALEN); + } else { + mld->group_mld_id = 0xff; + mld->remap_idx = 0xff; + } } static void @@ -1108,6 +1143,8 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, goto out; if (enable) { + struct mt7996_vif_link *link; + mt7996_mcu_bss_rfch_tlv(skb, phy); mt7996_mcu_bss_bmc_tlv(skb, mlink, phy); mt7996_mcu_bss_ra_tlv(skb, phy); @@ -1118,7 +1155,8 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, mt7996_mcu_bss_he_tlv(skb, vif, link_conf, phy); /* this tag is necessary no matter if the vif is MLD */ - mt7996_mcu_bss_mld_tlv(skb, mlink); + link = container_of(mlink, struct mt7996_vif_link, mt76); + mt7996_mcu_bss_mld_tlv(skb, link_conf, link); } mt7996_mcu_bss_mbssid_tlv(skb, link_conf, enable); @@ -1149,9 +1187,8 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, static int mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif, struct ieee80211_ampdu_params *params, - bool enable, bool tx) + struct mt76_wcid *wcid, bool enable, bool tx) { - struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv; struct sta_rec_ba_uni *ba; struct sk_buff *skb; struct tlv *tlv; @@ -1170,7 +1207,7 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif, ba->ba_en = enable << params->tid; ba->amsdu = params->amsdu; ba->tid = params->tid; - ba->ba_rdd_rro = !tx && enable && dev->has_rro; + ba->ba_rdd_rro = !tx && enable && mt7996_has_hwrro(dev); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); @@ -1179,20 +1216,67 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif, /** starec & wtbl **/ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, - struct mt7996_vif_link *link, - struct mt7996_sta_link *msta_link, bool enable) + struct ieee80211_vif *vif, bool enable) { - if (enable && !params->amsdu) - msta_link->wcid.amsdu = false; + struct ieee80211_sta *sta = params->sta; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; + int ret = 0; - return mt7996_mcu_sta_ba(dev, &link->mt76, params, enable, true); + for_each_sta_active_link(vif, sta, link_sta, link_id) { + struct mt7996_sta_link *msta_link; + struct mt7996_vif_link *link; + + msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); + if (!msta_link) + continue; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + continue; + + if (enable && !params->amsdu) + msta_link->wcid.amsdu = false; + + ret = mt7996_mcu_sta_ba(dev, &link->mt76, params, + &msta_link->wcid, enable, true); + if (ret) + break; + } + + return ret; } int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, - struct mt7996_vif_link *link, bool enable) + struct ieee80211_vif *vif, bool enable) { - return mt7996_mcu_sta_ba(dev, &link->mt76, params, enable, false); + struct ieee80211_sta *sta = params->sta; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; + int ret = 0; + + for_each_sta_active_link(vif, sta, link_sta, link_id) { + struct mt7996_sta_link *msta_link; + struct mt7996_vif_link *link; + + msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); + if (!msta_link) + continue; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + continue; + + ret = mt7996_mcu_sta_ba(dev, &link->mt76, params, + &msta_link->wcid, enable, false); + if (ret) + break; + } + + return ret; } static void @@ -1753,19 +1837,6 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, bf->mem_20m = bf->nrow < BF_MAT_ORDER ? matrix[bf->nrow][bf->ncol] : 0; } - - switch (link_sta->bandwidth) { - case IEEE80211_STA_RX_BW_160: - case IEEE80211_STA_RX_BW_80: - bf->mem_total = bf->mem_20m * 2; - break; - case IEEE80211_STA_RX_BW_40: - bf->mem_total = bf->mem_20m; - break; - case IEEE80211_STA_RX_BW_20: - default: - break; - } } static void @@ -1879,8 +1950,8 @@ mt7996_mcu_get_mmps_mode(enum ieee80211_smps_mode smps) int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, void *data, u16 version) { + struct uni_header hdr = {}; struct ra_fixed_rate *req; - struct uni_header hdr; struct sk_buff *skb; struct tlv *tlv; int len; @@ -2265,13 +2336,10 @@ error_unlock: } static int -mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta) +mt7996_mcu_add_group(struct mt7996_dev *dev, struct mt7996_vif_link *link, + struct mt76_wcid *wcid) { #define MT_STA_BSS_GROUP 1 - struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; - struct mt7996_sta_link *msta_link; - struct mt7996_sta *msta; struct { u8 __rsv1[4]; @@ -2286,28 +2354,25 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct ieee80211_vif *vif, .tag = cpu_to_le16(UNI_VOW_DRR_CTRL), .len = cpu_to_le16(sizeof(req) - 4), .action = cpu_to_le32(MT_STA_BSS_GROUP), - .val = cpu_to_le32(mvif->deflink.mt76.idx % 16), + .val = cpu_to_le32(link->mt76.idx % 16), + .wlan_idx = cpu_to_le16(wcid->idx), }; - msta = sta ? (struct mt7996_sta *)sta->drv_priv : NULL; - msta_link = msta ? &msta->deflink : &mvif->deflink.msta_link; - req.wlan_idx = cpu_to_le16(msta_link->wcid.idx); - return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(VOW), &req, sizeof(req), true); } 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 +2390,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,12 +2491,13 @@ 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); } } - ret = mt7996_mcu_add_group(dev, link_conf->vif, sta); + ret = mt7996_mcu_add_group(dev, link, wcid); if (ret) { dev_kfree_skb(skb); return ret; @@ -2468,41 +2532,58 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid, enum set_key_cmd cmd) { struct sta_rec_sec_uni *sec; + struct sec_key_uni *sec_key; struct tlv *tlv; + u8 cipher; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_KEY_V2, sizeof(*sec)); sec = (struct sta_rec_sec_uni *)tlv; - sec->add = cmd; - - if (cmd == SET_KEY) { - struct sec_key_uni *sec_key; - u8 cipher; - - cipher = mt76_connac_mcu_get_cipher(key->cipher); - if (cipher == MCU_CIPHER_NONE) - return -EOPNOTSUPP; - - sec_key = &sec->key[0]; - sec_key->wlan_idx = cpu_to_le16(wcid->idx); - sec_key->mgmt_prot = 0; - sec_key->cipher_id = cipher; - sec_key->cipher_len = sizeof(*sec_key); - sec_key->key_id = key->keyidx; - sec_key->key_len = key->keylen; - sec_key->need_resp = 0; - memcpy(sec_key->key, key->key, key->keylen); - - if (cipher == MCU_CIPHER_TKIP) { - /* Rx/Tx MIC keys are swapped */ - memcpy(sec_key->key + 16, key->key + 24, 8); - memcpy(sec_key->key + 24, key->key + 16, 8); - } + sec->add = 0; + sec->n_cipher = 1; + sec_key = &sec->key[0]; + sec_key->wlan_idx = cpu_to_le16(wcid->idx); + sec_key->key_id = key->keyidx; - sec->n_cipher = 1; - } else { - sec->n_cipher = 0; + if (cmd != SET_KEY) + return 0; + + cipher = mt76_connac_mcu_get_cipher(key->cipher); + if (cipher == MCU_CIPHER_NONE) + return -EOPNOTSUPP; + + sec_key->mgmt_prot = 0; + sec_key->cipher_id = cipher; + sec_key->cipher_len = sizeof(*sec_key); + sec_key->key_len = key->keylen; + sec_key->need_resp = 0; + memcpy(sec_key->key, key->key, key->keylen); + + if (cipher == MCU_CIPHER_TKIP) { + /* Rx/Tx MIC keys are swapped */ + memcpy(sec_key->key + 16, key->key + 24, 8); + memcpy(sec_key->key + 24, key->key + 16, 8); + return 0; + } + + if (sec_key->key_id != 6 && sec_key->key_id != 7) + return 0; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_AES_CMAC: + sec_key->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + sec_key->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + sec_key->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256; + break; + default: + return -EOPNOTSUPP; } + sec_key->bcn_mode = BP_SW_MODE; + return 0; } @@ -2520,99 +2601,12 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); ret = mt7996_mcu_sta_key_tlv(wcid, skb, key, cmd); - if (ret) - return ret; - - return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); -} - -static int mt7996_mcu_get_pn(struct mt7996_dev *dev, - struct mt7996_vif_link *link, - struct mt7996_sta_link *msta_link, u8 *pn) -{ -#define TSC_TYPE_BIGTK_PN 2 - struct sta_rec_pn_info *pn_info; - struct sk_buff *skb, *rskb; - struct tlv *tlv; - int ret; - - skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, - &msta_link->wcid); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PN_INFO, sizeof(*pn_info)); - pn_info = (struct sta_rec_pn_info *)tlv; - - pn_info->tsc_type = TSC_TYPE_BIGTK_PN; - ret = mt76_mcu_skb_send_and_get_msg(&dev->mt76, skb, - MCU_WM_UNI_CMD_QUERY(STA_REC_UPDATE), - true, &rskb); - if (ret) - return ret; - - skb_pull(rskb, 4); - - pn_info = (struct sta_rec_pn_info *)rskb->data; - if (le16_to_cpu(pn_info->tag) == STA_REC_PN_INFO) - memcpy(pn, pn_info->pn, 6); - - dev_kfree_skb(rskb); - return 0; -} - -int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, - struct mt7996_vif_link *link, - struct mt7996_sta_link *msta_link, - struct ieee80211_key_conf *key) -{ - struct mt7996_mcu_bcn_prot_tlv *bcn_prot; - struct sk_buff *skb; - struct tlv *tlv; - u8 pn[6] = {}; - int len = sizeof(struct bss_req_hdr) + - sizeof(struct mt7996_mcu_bcn_prot_tlv); - int ret; - - skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_BCN_PROT, sizeof(*bcn_prot)); - - bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv; - - ret = mt7996_mcu_get_pn(dev, link, msta_link, pn); if (ret) { dev_kfree_skb(skb); return ret; } - switch (key->cipher) { - case WLAN_CIPHER_SUITE_AES_CMAC: - bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_CMAC_128; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_128; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - bcn_prot->cipher_id = MCU_CIPHER_BCN_PROT_GMAC_256; - break; - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - default: - dev_err(dev->mt76.dev, "Not supported Bigtk Cipher\n"); - dev_kfree_skb(skb); - return -EOPNOTSUPP; - } - - pn[0]++; - memcpy(bcn_prot->pn, pn, 6); - bcn_prot->enable = BP_SW_MODE; - memcpy(bcn_prot->key, key->key, WLAN_MAX_KEY_LEN); - bcn_prot->key_id = key->keyidx; - - return mt76_mcu_skb_send_msg(&dev->mt76, skb, - MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); + return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, @@ -2753,10 +2747,11 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, } int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf) + struct ieee80211_bss_conf *link_conf, bool enabled) { struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt76_vif_link *mlink = mt76_vif_conf_link(&dev->mt76, vif, link_conf); + struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); + struct mt76_vif_link *mlink = link ? &link->mt76 : NULL; struct ieee80211_mutable_offsets offs; struct ieee80211_tx_info *info; struct sk_buff *skb, *rskb; @@ -2770,13 +2765,16 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!mlink) return -EINVAL; + if (link->phy && link->phy->mt76->offchannel) + enabled = false; + rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, MT7996_MAX_BSS_OFFLOAD_SIZE); if (IS_ERR(rskb)) return PTR_ERR(rskb); skb = ieee80211_beacon_get_template(hw, vif, &offs, link_conf->link_id); - if (link_conf->enable_beacon && !skb) { + if (enabled && !skb) { dev_kfree_skb(rskb); return -EINVAL; } @@ -2795,7 +2793,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, len = ALIGN(sizeof(*bcn) + MT_TXD_SIZE + extra_len, 4); tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CONTENT, len); bcn = (struct bss_bcn_content_tlv *)tlv; - bcn->enable = link_conf->enable_beacon; + bcn->enable = enabled; if (!bcn->enable) goto out; @@ -3373,7 +3371,7 @@ int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans) { struct { u8 __rsv[4]; - } __packed hdr; + } __packed hdr = {}; struct hdr_trans_blacklist *req_blacklist; struct hdr_trans_en *req_en; struct sk_buff *skb; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 130ea95626d5..c841da1c60e5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -351,17 +351,6 @@ enum { BP_HW_MODE, }; -struct mt7996_mcu_bcn_prot_tlv { - __le16 tag; - __le16 len; - u8 pn[6]; - u8 enable; - u8 cipher_id; - u8 key[WLAN_MAX_KEY_LEN]; - u8 key_id; - u8 __rsv[3]; -} __packed; - struct bss_ra_tlv { __le16 tag; __le16 len; @@ -481,7 +470,8 @@ struct bss_mld_tlv { u8 own_mld_id; u8 mac_addr[ETH_ALEN]; u8 remap_idx; - u8 __rsv[3]; + u8 link_id; + u8 __rsv[2]; } __packed; struct sta_rec_ht_uni { @@ -530,6 +520,9 @@ struct sec_key_uni { u8 key_len; u8 need_resp; u8 key[32]; + u8 pn[6]; + u8 bcn_mode; + u8 _rsv; } __packed; struct sta_rec_sec_uni { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index 30b40f4a91be..d14b626ee511 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -459,14 +459,15 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, #ifdef CONFIG_NET_MEDIATEK_SOC_WED struct mtk_wed_device *wed = &dev->mt76.mmio.wed; struct pci_dev *pci_dev = pdev_ptr; - u32 hif1_ofs = 0; + u32 hif1_ofs; if (!wed_enable) return 0; - dev->has_rro = true; + dev->mt76.hwrro_mode = is_mt7996(&dev->mt76) ? MT76_HWRRO_V3 + : MT76_HWRRO_V3_1; - hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); + hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; if (hif2) wed = &dev->mt76.mmio.wed_hif2; @@ -490,11 +491,18 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + MT_TXQ_RING_BASE(0) + MT7996_TXQ_BAND2 * MT_RING_SIZE; - if (dev->has_rro) { - wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + - MT_RXQ_RING_BASE(0) + - MT7996_RXQ_TXFREE2 * MT_RING_SIZE; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; + if (mt7996_has_hwrro(dev)) { + if (is_mt7996(&dev->mt76)) { + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE2 * MT_RING_SIZE; + } else { + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_BAND1_EXT) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_EXT * MT_RING_SIZE; + } } else { wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + MT_RXQ_RING_BASE(0) + @@ -503,14 +511,14 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, } wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG; - wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs + - MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + - MT7996_RXQ_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx[0] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND2) + + MT7996_RXQ_BAND2 * MT_RING_SIZE; wed->wlan.id = MT7996_DEVICE_ID_2; wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; } else { - wed->wlan.hw_rro = dev->has_rro; /* default on */ + wed->wlan.hw_rro = mt7996_has_hwrro(dev); wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + @@ -518,16 +526,26 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG; - wed->wlan.wpdma_rx = wed->wlan.phy_base + - MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + - MT7996_RXQ_BAND0 * MT_RING_SIZE; + wed->wlan.wpdma_rx[0] = wed->wlan.phy_base + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + + MT7996_RXQ_BAND0 * MT_RING_SIZE; wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) + MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE; - wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs + - MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) + - MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE; + if (is_mt7996(&dev->mt76)) { + wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) + + MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE; + } else { + wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND1) + + MT7996_RXQ_RRO_BAND1 * MT_RING_SIZE; + wed->wlan.wpdma_rx[1] = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(MT7996_RXQ_BAND1) + + MT7996_RXQ_BAND1 * MT_RING_SIZE; + } + wed->wlan.wpdma_rx_pg = wed->wlan.phy_base + MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) + MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE; @@ -537,10 +555,14 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1; - wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; - wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1; - wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1; + if (is_mt7996(&dev->mt76)) { + wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; + wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1; + } else { + wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND1) - 1; + wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND1) - 1; + } wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1; wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1; @@ -548,16 +570,27 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; - if (dev->has_rro) { - wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + - MT7996_RXQ_TXFREE0 * MT_RING_SIZE; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; + if (is_mt7996(&dev->mt76)) { + if (mt7996_has_hwrro(dev)) { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE0 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; + } else { + wed->wlan.wpdma_txfree = wed->wlan.phy_base + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; + } } else { wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; } dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt; + + if (dev->hif2 && is_mt7992(&dev->mt76)) + wed->wlan.id = 0x7992; } wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; @@ -576,8 +609,10 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.reset_complete = mt76_wed_reset_complete; } - if (mtk_wed_device_attach(wed)) + if (mtk_wed_device_attach(wed)) { + dev->mt76.hwrro_mode = MT76_HWRRO_OFF; return 0; + } *irq = wed->irq; dev->mt76.dma_dev = wed->dev; @@ -690,12 +725,18 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t) dev->mt76.mmio.irqmask); if (intr1 & MT_INT_RX_TXFREE_EXT) napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]); + + if (intr1 & MT_INT_RX_DONE_BAND2_EXT) + napi_schedule(&dev->mt76.napi[MT_RXQ_BAND2]); + + if (intr1 & MT_INT_RX_TXFREE_BAND1_EXT) + napi_schedule(&dev->mt76.napi[MT_RXQ_BAND1_WA]); } if (mtk_wed_device_active(wed)) { mtk_wed_device_irq_set_mask(wed, 0); intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask); - intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT); + intr |= (intr1 & ~MT_INT_TX_RX_DONE_EXT); } else { mt76_wr(dev, MT_INT_MASK_CSR, 0); if (dev->hif2) @@ -781,6 +822,8 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev, .rx_skb = mt7996_queue_rx_skb, .rx_check = mt7996_rx_check, .rx_poll_complete = mt7996_rx_poll_complete, + .rx_rro_ind_process = mt7996_rro_rx_process, + .rx_rro_add_msdu_page = mt7996_rro_msdu_page_add, .update_survey = mt7996_update_channel, .set_channel = mt7996_set_channel, .vif_link_add = mt7996_vif_link_add, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 33ac16b64ef1..8ec2acdb3319 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -112,6 +112,8 @@ #define MT7996_CRIT_TEMP 110 #define MT7996_MAX_TEMP 120 +#define MT7996_MAX_HIF_RXD_IN_PG 5 +#define MT7996_RRO_MSDU_PG_HASH_SIZE 127 #define MT7996_RRO_MAX_SESSION 1024 #define MT7996_RRO_WINDOW_MAX_LEN 1024 #define MT7996_RRO_ADDR_ELEM_LEN 128 @@ -128,6 +130,10 @@ #define MT7996_RX_MSDU_PAGE_SIZE (128 + \ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +/* RRO 3.1 */ +#define MT7996_RRO_MSDU_PG_CR_CNT 8 +#define MT7996_RRO_MSDU_PG_SIZE_PER_CR 0x10000 + struct mt7996_vif; struct mt7996_sta; struct mt7996_dfs_pulse; @@ -178,7 +184,7 @@ enum mt7996_rxq_id { MT7996_RXQ_BAND1 = 5, /* for mt7992 */ MT7996_RXQ_BAND2 = 5, MT7996_RXQ_RRO_BAND0 = 8, - MT7996_RXQ_RRO_BAND1 = 8,/* unused */ + MT7996_RXQ_RRO_BAND1 = 9, MT7996_RXQ_RRO_BAND2 = 6, MT7996_RXQ_MSDU_PG_BAND0 = 10, MT7996_RXQ_MSDU_PG_BAND1 = 11, @@ -187,6 +193,7 @@ enum mt7996_rxq_id { MT7996_RXQ_TXFREE1 = 9, MT7996_RXQ_TXFREE2 = 7, MT7996_RXQ_RRO_IND = 0, + MT7996_RXQ_RRO_RXDMAD_C = 0, MT7990_RXQ_TXFREE0 = 6, MT7990_RXQ_TXFREE1 = 7, }; @@ -248,11 +255,16 @@ struct mt7996_vif_link { struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS]; struct cfg80211_bitrate_mask bitrate_mask; + + u8 mld_idx; }; struct mt7996_vif { struct mt7996_vif_link deflink; /* must be first */ struct mt76_vif_data mt76; + + u8 mld_group_idx; + u8 mld_remap_idx; }; /* crash-dump */ @@ -270,15 +282,17 @@ struct mt7996_hif { struct device *dev; void __iomem *regs; int irq; + + enum pci_bus_speed speed; + enum pcie_link_width width; }; +#define WED_RRO_ADDR_SIGNATURE_MASK GENMASK(31, 24) +#define WED_RRO_ADDR_COUNT_MASK GENMASK(14, 4) +#define WED_RRO_ADDR_HEAD_HIGH_MASK GENMASK(3, 0) struct mt7996_wed_rro_addr { - u32 head_low; - u32 head_high : 4; - u32 count: 11; - u32 oor: 1; - u32 rsv : 8; - u32 signature : 8; + __le32 head_low; + __le32 data; }; struct mt7996_wed_rro_session_id { @@ -286,6 +300,44 @@ struct mt7996_wed_rro_session_id { u16 id; }; +struct mt7996_msdu_page { + struct list_head list; + + struct mt76_queue *q; + dma_addr_t dma_addr; + void *buf; +}; + +/* data1 */ +#define RRO_HIF_DATA1_LS_MASK BIT(30) +#define RRO_HIF_DATA1_SDL_MASK GENMASK(29, 16) +/* data4 */ +#define RRO_HIF_DATA4_RX_TOKEN_ID_MASK GENMASK(15, 0) +struct mt7996_rro_hif { + __le32 data0; + __le32 data1; + __le32 data2; + __le32 data3; + __le32 data4; + __le32 data5; +}; + +#define MSDU_PAGE_INFO_OWNER_MASK BIT(31) +#define MSDU_PAGE_INFO_PG_HIGH_MASK GENMASK(3, 0) +struct mt7996_msdu_page_info { + struct mt7996_rro_hif rxd[MT7996_MAX_HIF_RXD_IN_PG]; + __le32 pg_low; + __le32 data; +}; + +#define MT7996_MAX_RRO_RRS_RING 4 +struct mt7996_rro_queue_regs_emi { + struct { + __le16 idx; + __le16 rsv; + } ring[MT7996_MAX_RRO_RRS_RING]; +}; + struct mt7996_phy { struct mt76_phy *mt76; struct mt7996_dev *dev; @@ -337,6 +389,9 @@ struct mt7996_dev { u32 q_int_mask[MT7996_MAX_QUEUE]; u32 q_wfdma_mask; + u64 mld_idx_mask; + u64 mld_remap_idx_mask; + const struct mt76_bus_ops *bus_ops; struct mt7996_phy phy; @@ -377,7 +432,6 @@ struct mt7996_dev { bool flash_mode:1; bool has_eht:1; - bool has_rro:1; struct { struct { @@ -392,10 +446,25 @@ struct mt7996_dev { void *ptr; dma_addr_t phy_addr; } session; + struct { + void *ptr; + dma_addr_t phy_addr; + } msdu_pg[MT7996_RRO_MSDU_PG_CR_CNT]; + struct { + struct mt7996_rro_queue_regs_emi *ptr; + dma_addr_t phy_addr; + } emi_rings_cpu; + struct { + struct mt7996_rro_queue_regs_emi *ptr; + dma_addr_t phy_addr; + } emi_rings_dma; struct work_struct work; struct list_head poll_list; spinlock_t lock; + + struct list_head page_cache; + struct list_head page_map[MT7996_RRO_MSDU_PG_HASH_SIZE]; } wed_rro; bool ibf; @@ -552,6 +621,7 @@ extern struct pci_driver mt7996_hif_driver; struct mt7996_dev *mt7996_mmio_probe(struct device *pdev, void __iomem *mem_base, u32 device_id); +void mt7996_rro_hw_init(struct mt7996_dev *dev); void mt7996_wfsys_reset(struct mt7996_dev *dev); irqreturn_t mt7996_irq_handler(int irq, void *dev_instance); u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif_link *link); @@ -604,16 +674,15 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, struct mt7996_sta_link *msta_link); int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, - struct mt7996_vif_link *link, - struct mt7996_sta_link *msta_link, bool enable); + struct ieee80211_vif *vif, bool enable); int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, - struct mt7996_vif_link *link, bool enable); + struct ieee80211_vif *vif, bool enable); int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct mt76_vif_link *mlink, struct cfg80211_he_bss_color *he_bss_color); int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf); + struct ieee80211_bss_conf *link_conf, bool enabled); int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, struct ieee80211_bss_conf *link_conf, struct mt7996_vif_link *link, u32 changed); @@ -669,6 +738,11 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled); +static inline bool mt7996_has_hwrro(struct mt7996_dev *dev) +{ + return dev->mt76.hwrro_mode != MT76_HWRRO_OFF; +} + static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev) { return min(MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) + @@ -732,6 +806,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, enum mt76_txq_id qid, u32 changed); +void mt7996_mac_update_beacons(struct mt7996_phy *phy); void mt7996_mac_set_coverage_class(struct mt7996_phy *phy); void mt7996_mac_work(struct work_struct *work); void mt7996_mac_reset_work(struct work_struct *work); @@ -742,6 +817,8 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, struct mt7996_vif_link *link, struct mt7996_sta_link *msta_link, u8 flowid); +void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, + struct mt7996_sta_link *msta_link); void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct ieee80211_twt_setup *twt); @@ -752,6 +829,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, void mt7996_tx_token_put(struct mt7996_dev *dev); void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, struct sk_buff *skb, u32 *info); +void mt7996_rro_msdu_page_map_free(struct mt7996_dev *dev); +int mt7996_rro_msdu_page_add(struct mt76_dev *mdev, struct mt76_queue *q, + dma_addr_t dma_addr, void *data); +void mt7996_rro_rx_process(struct mt76_dev *mdev, void *data); bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len); void mt7996_stats_work(struct work_struct *work); int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force); @@ -786,8 +867,6 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); #endif -#ifdef CONFIG_NET_MEDIATEK_SOC_WED int mt7996_dma_rro_init(struct mt7996_dev *dev); -#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index 19e99bc1c6c4..3f49bbbba3b9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -87,6 +87,7 @@ static int mt7996_pci_hif2_probe(struct pci_dev *pdev) hif->dev = &pdev->dev; hif->regs = pcim_iomap_table(pdev)[0]; hif->irq = pdev->irq; + pcie_bandwidth_available(pdev, NULL, &hif->speed, &hif->width); spin_lock_bh(&hif_lock); list_add(&hif->list, &hif_list); spin_unlock_bh(&hif_lock); @@ -137,6 +138,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev, mdev = &dev->mt76; mt7996_wfsys_reset(dev); hif2 = mt7996_pci_init_hif2(pdev); + dev->hif2 = hif2; ret = mt7996_mmio_wed_init(dev, pdev, false, &irq); if (ret < 0) @@ -161,7 +163,6 @@ static int mt7996_pci_probe(struct pci_dev *pdev, if (hif2) { hif2_dev = container_of(hif2->dev, struct pci_dev, dev); - dev->hif2 = hif2; ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &hif2_irq); if (ret < 0) diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index e942c0058731..0fa325f87fcd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -88,6 +88,8 @@ enum offs_rev { #define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC) #define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8) #define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12) + +#define MT_RRO_ADDR_ARRAY_BASE0 MT_RRO_TOP(0x30) #define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34) #define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31) @@ -108,6 +110,19 @@ enum offs_rev { #define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400) +#define MT_RRO_3_0_EMU_CONF MT_RRO_TOP(0x600) +#define MT_RRO_3_0_EMU_CONF_EN_MASK BIT(11) + +#define MT_RRO_3_1_GLOBAL_CONFIG MT_RRO_TOP(0x604) +#define MT_RRO_3_1_GLOBAL_CONFIG_RXDMAD_SEL BIT(6) +#define MT_RRO_3_1_GLOBAL_CONFIG_RX_CIDX_RD_EN BIT(3) +#define MT_RRO_3_1_GLOBAL_CONFIG_RX_DIDX_WR_EN BIT(2) +#define MT_RRO_3_1_GLOBAL_CONFIG_INTERLEAVE_EN BIT(0) + +#define MT_RRO_MSDU_PG_SEG_ADDR0 MT_RRO_TOP(0x620) +#define MT_RRO_RX_RING_AP_CIDX_ADDR MT_RRO_TOP(0x6f0) +#define MT_RRO_RX_RING_AP_DIDX_ADDR MT_RRO_TOP(0x6f4) + #define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50) #define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) #define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) @@ -412,7 +427,9 @@ enum offs_rev { #define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154) #define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3) +#define MT_WFDMA0_RX_INT_SEL_RING5 BIT(5) #define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6) +#define MT_WFDMA0_RX_INT_SEL_RING9 BIT(9) #define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) @@ -430,6 +447,7 @@ enum offs_rev { #define MT_WFDMA0_PAUSE_RX_Q_RRO_TH MT_WFDMA0(0x27c) #define WF_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) +#define WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK GENMASK(27, 24) #define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD BIT(18) #define WF_WFDMA0_GLO_CFG_EXT0_WED_MERGE_MODE BIT(14) @@ -451,6 +469,8 @@ enum offs_rev { #define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30) #define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0) +#define MT_WFDMA_HOST_CONFIG_BAND0_PCIE1 BIT(20) +#define MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 BIT(21) #define MT_WFDMA_HOST_CONFIG_BAND2_PCIE1 BIT(22) #define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44) @@ -459,6 +479,9 @@ enum offs_rev { #define MT_WFDMA_AXI_R2A_CTRL MT_WFDMA_EXT_CSR(0x500) #define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK GENMASK(4, 0) +#define MT_WFDMA_AXI_R2A_CTRL2 MT_WFDMA_EXT_CSR(0x508) +#define MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK GENMASK(31, 28) + #define MT_PCIE_RECOG_ID 0xd7090 #define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0) #define MT_PCIE_RECOG_ID_SEM BIT(31) @@ -492,6 +515,8 @@ enum offs_rev { #define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500) #define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40) +#define MT_RXQ_RRO_AP_RING_BASE MT_RRO_TOP(0x650) + #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ MT_MCUQ_ID(q) * 0x4) #define MT_RXQ_EXT_CTRL(q) (MT_Q_BASE(__RXQ(q)) + 0x680 + \ @@ -514,7 +539,9 @@ enum offs_rev { #define MT_INT_RX_DONE_WA_EXT BIT(3) /* for mt7992 */ #define MT_INT_RX_DONE_WA_TRI BIT(3) #define MT_INT_RX_TXFREE_MAIN BIT(17) +#define MT_INT_RX_TXFREE_BAND1 BIT(15) #define MT_INT_RX_TXFREE_TRI BIT(15) +#define MT_INT_RX_TXFREE_BAND1_EXT BIT(19) /* for mt7992 two PCIE*/ #define MT_INT_RX_TXFREE_BAND0_MT7990 BIT(14) #define MT_INT_RX_TXFREE_BAND1_MT7990 BIT(15) #define MT_INT_RX_DONE_BAND2_EXT BIT(23) @@ -522,9 +549,10 @@ enum offs_rev { #define MT_INT_MCU_CMD BIT(29) #define MT_INT_RX_DONE_RRO_BAND0 BIT(16) -#define MT_INT_RX_DONE_RRO_BAND1 BIT(16) +#define MT_INT_RX_DONE_RRO_BAND1 BIT(17) #define MT_INT_RX_DONE_RRO_BAND2 BIT(14) #define MT_INT_RX_DONE_RRO_IND BIT(11) +#define MT_INT_RX_DONE_RRO_RXDMAD_C BIT(11) #define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18) #define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19) #define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23) @@ -552,6 +580,8 @@ enum offs_rev { #define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \ MT_INT_RX(MT_RXQ_RRO_BAND1) | \ MT_INT_RX(MT_RXQ_RRO_BAND2) | \ + MT_INT_RX(MT_RXQ_RRO_IND) | \ + MT_INT_RX(MT_RXQ_RRO_RXDMAD_C) | \ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2)) diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c index 9b20ccbeb8cf..5a875aac410f 100644 --- a/drivers/net/wireless/mediatek/mt76/scan.c +++ b/drivers/net/wireless/mediatek/mt76/scan.c @@ -16,11 +16,13 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) clear_bit(MT76_SCANNING, &phy->state); - if (dev->scan.chan && phy->main_chandef.chan) + if (dev->scan.chan && phy->main_chandef.chan && + !test_bit(MT76_MCU_RESET, &dev->phy.state)) mt76_set_channel(phy, &phy->main_chandef, false); mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); memset(&dev->scan, 0, sizeof(dev->scan)); - ieee80211_scan_completed(phy->hw, &info); + if (!test_bit(MT76_MCU_RESET, &dev->phy.state)) + ieee80211_scan_completed(phy->hw, &info); } void mt76_abort_scan(struct mt76_dev *dev) @@ -28,6 +30,7 @@ void mt76_abort_scan(struct mt76_dev *dev) cancel_delayed_work_sync(&dev->scan_work); mt76_scan_complete(dev, true); } +EXPORT_SYMBOL_GPL(mt76_abort_scan); static void mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) @@ -112,9 +115,6 @@ void mt76_scan_work(struct work_struct *work) local_bh_enable(); out: - if (!duration) - return; - if (dev->scan.chan) duration = max_t(int, duration, msecs_to_jiffies(req->duration + @@ -139,7 +139,8 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mutex); - if (dev->scan.req || phy->roc_vif) { + if (dev->scan.req || phy->roc_vif || + test_bit(MT76_MCU_RESET, &dev->phy.state)) { ret = -EBUSY; goto out; } 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/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index e6cf16706667..b78ae6a34b65 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -332,6 +332,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (void *)skb->data; struct sk_buff_head *head; if (mt76_testmode_enabled(phy)) { @@ -349,7 +350,8 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta, info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx); if ((info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) || - (info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK)) + ((info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK) && + ieee80211_is_probe_req(hdr->frame_control))) head = &wcid->tx_offchannel; else head = &wcid->tx_pending; @@ -616,7 +618,8 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && !ieee80211_is_data(hdr->frame_control) && (!ieee80211_is_bufferable_mmpdu(skb) || - ieee80211_is_deauth(hdr->frame_control))) + ieee80211_is_deauth(hdr->frame_control) || + head == &wcid->tx_offchannel)) qid = MT_TXQ_PSD; q = phy->q_tx[qid]; @@ -644,6 +647,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, static void mt76_txq_schedule_pending(struct mt76_phy *phy) { LIST_HEAD(tx_list); + int ret = 0; if (list_empty(&phy->tx_list)) return; @@ -655,13 +659,13 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy) list_splice_init(&phy->tx_list, &tx_list); while (!list_empty(&tx_list)) { struct mt76_wcid *wcid; - int ret; wcid = list_first_entry(&tx_list, struct mt76_wcid, tx_list); list_del_init(&wcid->tx_list); spin_unlock(&phy->tx_lock); - ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel); + if (ret >= 0) + ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel); if (ret >= 0 && !phy->offchannel) ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending); spin_lock(&phy->tx_lock); @@ -670,9 +674,6 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy) !skb_queue_empty(&wcid->tx_offchannel) && list_empty(&wcid->tx_list)) list_add_tail(&wcid->tx_list, &phy->tx_list); - - if (ret < 0) - break; } spin_unlock(&phy->tx_lock); diff --git a/drivers/net/wireless/mediatek/mt76/wed.c b/drivers/net/wireless/mediatek/mt76/wed.c index f89e4537555c..907a8e43e72a 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) { @@ -122,7 +118,7 @@ int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) case MT76_WED_Q_TXFREE: /* WED txfree queue needs ring to be initialized before setup */ q->flags = 0; - mt76_dma_queue_reset(dev, q); + mt76_dma_queue_reset(dev, q, true); mt76_dma_rx_fill(dev, q, false); ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); @@ -137,21 +133,21 @@ int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) break; case MT76_WED_RRO_Q_DATA: q->flags &= ~MT_QFLAG_WED; - __mt76_dma_queue_reset(dev, q, false); + mt76_dma_queue_reset(dev, q, false); mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs); q->head = q->ndesc - 1; q->queued = q->head; break; case MT76_WED_RRO_Q_MSDU_PG: q->flags &= ~MT_QFLAG_WED; - __mt76_dma_queue_reset(dev, q, false); + mt76_dma_queue_reset(dev, q, false); mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs); q->head = q->ndesc - 1; q->queued = q->head; break; case MT76_WED_RRO_Q_IND: q->flags &= ~MT_QFLAG_WED; - mt76_dma_queue_reset(dev, q); + mt76_dma_queue_reset(dev, q, true); mt76_dma_rx_fill(dev, q, false); mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs); break; 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..c39e7f313ea1 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -794,13 +794,7 @@ static int get_station(struct wiphy *wiphy, struct net_device *dev, return 0; } -static int change_bss(struct wiphy *wiphy, struct net_device *dev, - struct bss_parameters *params) -{ - 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 +1631,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 +1664,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); @@ -1708,7 +1703,6 @@ static const struct cfg80211_ops wilc_cfg80211_ops = { .change_station = change_station, .get_station = get_station, .dump_station = dump_station, - .change_bss = change_bss, .set_wiphy_params = set_wiphy_params, .external_auth = external_auth, 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/microchip/wilc1000/wlan_cfg.c b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c index 131388886acb..cfabd5aebb54 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.c @@ -41,10 +41,10 @@ static const struct wilc_cfg_word g_cfg_word[] = { }; static const struct wilc_cfg_str g_cfg_str[] = { - {WID_FIRMWARE_VERSION, NULL}, - {WID_MAC_ADDR, NULL}, - {WID_ASSOC_RES_INFO, NULL}, - {WID_NIL, NULL} + {WID_FIRMWARE_VERSION, 0, NULL}, + {WID_MAC_ADDR, 0, NULL}, + {WID_ASSOC_RES_INFO, 0, NULL}, + {WID_NIL, 0, NULL} }; #define WILC_RESP_MSG_TYPE_CONFIG_REPLY 'R' @@ -147,44 +147,58 @@ static void wilc_wlan_parse_response_frame(struct wilc *wl, u8 *info, int size) switch (FIELD_GET(WILC_WID_TYPE, wid)) { case WID_CHAR: + len = 3; + if (len + 2 > size) + return; + while (cfg->b[i].id != WID_NIL && cfg->b[i].id != wid) i++; if (cfg->b[i].id == wid) cfg->b[i].val = info[4]; - len = 3; break; case WID_SHORT: + len = 4; + if (len + 2 > size) + return; + while (cfg->hw[i].id != WID_NIL && cfg->hw[i].id != wid) i++; if (cfg->hw[i].id == wid) cfg->hw[i].val = get_unaligned_le16(&info[4]); - len = 4; break; case WID_INT: + len = 6; + if (len + 2 > size) + return; + while (cfg->w[i].id != WID_NIL && cfg->w[i].id != wid) i++; if (cfg->w[i].id == wid) cfg->w[i].val = get_unaligned_le32(&info[4]); - len = 6; break; case WID_STR: + len = 2 + get_unaligned_le16(&info[2]); + while (cfg->s[i].id != WID_NIL && cfg->s[i].id != wid) i++; - if (cfg->s[i].id == wid) + if (cfg->s[i].id == wid) { + if (len > cfg->s[i].len || (len + 2 > size)) + return; + memcpy(cfg->s[i].str, &info[2], - get_unaligned_le16(&info[2]) + 2); + len); + } - len = 2 + get_unaligned_le16(&info[2]); break; default: @@ -384,12 +398,15 @@ int wilc_wlan_cfg_init(struct wilc *wl) /* store the string cfg parameters */ wl->cfg.s[i].id = WID_FIRMWARE_VERSION; wl->cfg.s[i].str = str_vals->firmware_version; + wl->cfg.s[i].len = sizeof(str_vals->firmware_version); i++; wl->cfg.s[i].id = WID_MAC_ADDR; wl->cfg.s[i].str = str_vals->mac_address; + wl->cfg.s[i].len = sizeof(str_vals->mac_address); i++; wl->cfg.s[i].id = WID_ASSOC_RES_INFO; wl->cfg.s[i].str = str_vals->assoc_rsp; + wl->cfg.s[i].len = sizeof(str_vals->assoc_rsp); i++; wl->cfg.s[i].id = WID_NIL; wl->cfg.s[i].str = NULL; diff --git a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h index 7038b74f8e8f..5ae74bced7d7 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h +++ b/drivers/net/wireless/microchip/wilc1000/wlan_cfg.h @@ -24,12 +24,13 @@ struct wilc_cfg_word { struct wilc_cfg_str { u16 id; + u16 len; u8 *str; }; struct wilc_cfg_str_vals { - u8 mac_address[7]; - u8 firmware_version[129]; + u8 mac_address[8]; + u8 firmware_version[130]; u8 assoc_rsp[WILC_MAX_ASSOC_RESP_FRAME_SIZE]; }; 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..17f063fc0b57 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -66,7 +66,6 @@ config RT2800PCI select RT2X00_LIB_PCI select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO - select CRC_CCITT select EEPROM_93CX6 help This adds support for rt27xx/rt28xx/rt30xx wireless chipset family. @@ -142,7 +141,6 @@ config RT2800USB select RT2X00_LIB_USB select RT2X00_LIB_FIRMWARE select RT2X00_LIB_CRYPTO - select CRC_CCITT help This adds support for rt27xx/rt28xx/rt30xx wireless chipset family. Supported chips: RT2770, RT2870 & RT3070, RT3071 & RT3072 @@ -202,8 +200,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 @@ -218,6 +215,7 @@ config RT2800SOC config RT2800_LIB tristate + select CRC_CCITT config RT2800_LIB_MMIO tristate @@ -226,12 +224,9 @@ config RT2800_LIB_MMIO config RT2X00_LIB_MMIO tristate - -config RT2X00_LIB_PCI - tristate select RT2X00_LIB -config RT2X00_LIB_SOC +config RT2X00_LIB_PCI 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..f8a6f9c968a1 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)) @@ -679,7 +679,7 @@ static void rt2x00lib_rxdone_check_ps(struct rt2x00_dev *rt2x00dev, /* Check whenever the PHY can be turned off again. */ /* 1. What about buffered unicast traffic for our AID? */ - cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid); + cam = ieee80211_check_tim(tim_ie, tim_len, rt2x00dev->aid, false); /* 2. Maybe the AP wants to send multicast/broadcast data? */ cam |= (tim_ie->bitmap_ctrl & 0x01); 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..3ded5952729f 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 @@ -1901,6 +1901,27 @@ static void rtl8xxxu_dump_efuse(struct rtl8xxxu_priv *priv) priv->efuse_wifi.raw, EFUSE_MAP_LEN, true); } +static ssize_t read_file_efuse(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct rtl8xxxu_priv *priv = file_inode(file)->i_private; + + return simple_read_from_buffer(user_buf, count, ppos, + priv->efuse_wifi.raw, EFUSE_MAP_LEN); +} + +static const struct debugfs_short_fops fops_efuse = { + .read = read_file_efuse, +}; + +static void rtl8xxxu_debugfs_init(struct rtl8xxxu_priv *priv) +{ + struct dentry *phydir; + + phydir = debugfs_create_dir("rtl8xxxu", priv->hw->wiphy->debugfsdir); + debugfs_create_file("efuse", 0400, phydir, priv, &fops_efuse); +} + void rtl8xxxu_reset_8051(struct rtl8xxxu_priv *priv) { u8 val8; @@ -4552,7 +4573,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 +6639,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 +6861,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 +7010,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; @@ -7813,7 +7836,8 @@ static int rtl8xxxu_probe(struct usb_interface *interface, untested = 0; break; case 0x2357: - if (id->idProduct == 0x0109 || id->idProduct == 0x0135) + if (id->idProduct == 0x0109 || id->idProduct == 0x010c || + id->idProduct == 0x0135) untested = 0; break; case 0x0b05: @@ -7972,6 +7996,7 @@ static int rtl8xxxu_probe(struct usb_interface *interface, } rtl8xxxu_init_led(priv); + rtl8xxxu_debugfs_init(priv); return 0; @@ -8170,8 +8195,6 @@ static const struct usb_device_id dev_table[] = { .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(0x06f8, 0xe033, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192cu_fops}, -{USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8188, 0xff, 0xff, 0xff), - .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(0x07b8, 0x8189, 0xff, 0xff, 0xff), .driver_info = (unsigned long)&rtl8192cu_fops}, {USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9041, 0xff, 0xff, 0xff), 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/ps.c b/drivers/net/wireless/realtek/rtlwifi/ps.c index 6241e4fed4f6..bcab12c3b4c1 100644 --- a/drivers/net/wireless/realtek/rtlwifi/ps.c +++ b/drivers/net/wireless/realtek/rtlwifi/ps.c @@ -519,7 +519,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) /* 1. What about buffered unicast traffic for our AID? */ u_buffed = ieee80211_check_tim(tim_ie, tim_len, - rtlpriv->mac80211.assoc_id); + rtlpriv->mac80211.assoc_id, false); /* 2. Maybe the AP wants to send multicast/broadcast data? */ m_buffed = tim_ie->bitmap_ctrl & 0x01; 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..9480823af838 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, @@ -291,7 +291,6 @@ static const struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x050d, 0x1102, rtl92cu_hal_cfg)}, /*Belkin - Edimax*/ {RTL_USB_DEVICE(0x050d, 0x11f2, rtl92cu_hal_cfg)}, /*Belkin - ISY*/ {RTL_USB_DEVICE(0x06f8, 0xe033, rtl92cu_hal_cfg)}, /*Hercules - Edimax*/ - {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ {RTL_USB_DEVICE(0x0846, 0x9043, rtl92cu_hal_cfg)}, /*NG WNA1000Mv2*/ 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/led.c b/drivers/net/wireless/realtek/rtw88/led.c index 25aa6cbaa728..4cc62e49d167 100644 --- a/drivers/net/wireless/realtek/rtw88/led.c +++ b/drivers/net/wireless/realtek/rtw88/led.c @@ -6,13 +6,17 @@ #include "debug.h" #include "led.h" -static int rtw_led_set_blocking(struct led_classdev *led, - enum led_brightness brightness) +static int rtw_led_set(struct led_classdev *led, + enum led_brightness brightness) { struct rtw_dev *rtwdev = container_of(led, struct rtw_dev, led_cdev); + mutex_lock(&rtwdev->mutex); + rtwdev->chip->ops->led_set(led, brightness); + mutex_unlock(&rtwdev->mutex); + return 0; } @@ -36,10 +40,7 @@ void rtw_led_init(struct rtw_dev *rtwdev) if (!rtwdev->chip->ops->led_set) return; - if (rtw_hci_type(rtwdev) == RTW_HCI_TYPE_PCIE) - led->brightness_set = rtwdev->chip->ops->led_set; - else - led->brightness_set_blocking = rtw_led_set_blocking; + led->brightness_set_blocking = rtw_led_set; snprintf(rtwdev->led_name, sizeof(rtwdev->led_name), "rtw88-%s", dev_name(rtwdev->dev)); 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..99d7c629eac6 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -144,6 +144,10 @@ static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr, static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr) { + if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags) && + !rtw_sdio_is_bus_addr(addr)) + return false; + return !rtw_sdio_is_sdio30_supported(rtwdev) || rtw_sdio_is_bus_addr(addr); } @@ -547,7 +551,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 +1034,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 +1046,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 +1058,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..86f1b39a967f 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,13 +274,14 @@ 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) { struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; + int i, j; hal->entity_pause = false; bitmap_zero(hal->entity_map, NUM_OF_RTW89_CHANCTX); @@ -242,6 +290,11 @@ void rtw89_entity_init(struct rtw89_dev *rtwdev) INIT_LIST_HEAD(&mgnt->active_list); + for (i = 0; i < RTW89_MAX_INTERFACE_NUM; i++) { + for (j = 0; j < __RTW89_MLD_MAX_LINK_NUM; j++) + mgnt->chanctx_tbl[i][j] = RTW89_CHANCTX_IDLE; + } + rtw89_config_default_chandef(rtwdev); } @@ -265,6 +318,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) { @@ -304,7 +359,7 @@ static void rtw89_normalize_link_chanctx(struct rtw89_dev *rtwdev, const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, const char *caller_message, - u8 link_index) + u8 link_index, bool nullchk) { struct rtw89_hal *hal = &rtwdev->hal; struct rtw89_entity_mgnt *mgnt = &hal->entity_mgnt; @@ -351,6 +406,9 @@ const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, return rtw89_chan_get(rtwdev, chanctx_idx); dflt: + if (unlikely(nullchk)) + return NULL; + rtw89_debug(rtwdev, RTW89_DBG_CHAN, "%s (%s): prefetch NULL on link index %u\n", __func__, caller_message ?: "", link_index); @@ -473,7 +531,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 +1012,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 +1051,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 +1070,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 +1177,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 +1333,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 +1667,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 +1731,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 +2232,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 +2281,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 +2324,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 +2344,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 +2397,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 +2409,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 +2443,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 +2471,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 +2511,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 +2805,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 +2897,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 +2922,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 +3280,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 +3296,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 +3316,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 +3358,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 +3412,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..5b22764d5329 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); @@ -124,10 +180,26 @@ void rtw89_chanctx_proceed(struct rtw89_dev *rtwdev, const struct rtw89_chan *__rtw89_mgnt_chan_get(struct rtw89_dev *rtwdev, const char *caller_message, - u8 link_index); + u8 link_index, bool nullchk); #define rtw89_mgnt_chan_get(rtwdev, link_index) \ - __rtw89_mgnt_chan_get(rtwdev, __func__, link_index) + __rtw89_mgnt_chan_get(rtwdev, __func__, link_index, false) + +static inline const struct rtw89_chan * +rtw89_mgnt_chan_get_or_null(struct rtw89_dev *rtwdev, u8 link_index) +{ + return __rtw89_mgnt_chan_get(rtwdev, NULL, link_index, true); +} + +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); @@ -142,5 +214,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..0f7ae572ef91 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 @@ -92,7 +93,7 @@ static const struct rtw89_btc_fbtc_slot s_def[] = { [CXST_E2G] = __DEF_FBTC_SLOT(5, 0xea5a5a5a, SLOT_MIX), [CXST_E5G] = __DEF_FBTC_SLOT(5, 0xffffffff, SLOT_ISO), [CXST_EBT] = __DEF_FBTC_SLOT(5, 0xe5555555, SLOT_MIX), - [CXST_ENULL] = __DEF_FBTC_SLOT(5, 0xaaaaaaaa, SLOT_ISO), + [CXST_ENULL] = __DEF_FBTC_SLOT(5, 0x55555555, SLOT_MIX), [CXST_WLK] = __DEF_FBTC_SLOT(250, 0xea5a5a5a, SLOT_MIX), [CXST_W1FDD] = __DEF_FBTC_SLOT(50, 0xffffffff, SLOT_ISO), [CXST_B1FDD] = __DEF_FBTC_SLOT(50, 0xffffdfff, SLOT_ISO), @@ -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); @@ -3856,6 +4153,7 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); _slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur, s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype); + _slot_set_dur(btc, CXST_EBT, dur_2); break; case BTC_CXP_OFFE_DEF2: _slot_set(btc, CXST_E2G, 20, cxtbl[1], SLOT_ISO); @@ -3865,18 +4163,20 @@ void rtw89_btc_set_policy_v1(struct rtw89_dev *rtwdev, u16 policy_type) s_def[CXST_EBT].cxtbl, s_def[CXST_EBT].cxtype); _slot_set_le(btc, CXST_ENULL, s_def[CXST_ENULL].dur, s_def[CXST_ENULL].cxtbl, s_def[CXST_ENULL].cxtype); + _slot_set_dur(btc, CXST_EBT, dur_2); 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); + _slot_set_dur(btc, CXST_EBT, dur_2); 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 +5164,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 +5189,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 +5276,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 +5296,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 +5312,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 +5552,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 +5628,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 +6102,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 +6597,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 +6615,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 +6843,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 +6888,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 +7227,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 +7244,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 +7252,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 +7440,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 +8250,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 +8263,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 +8508,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 +8593,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 +8705,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 +8716,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 +8792,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 +8817,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 +8845,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 +8895,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 +8976,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 +9067,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 +9204,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 +9801,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 +10372,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 +10520,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 +10533,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 +10554,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 +10575,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 +10817,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 +11089,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 +11788,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\n** Page:%3d/RunCNT:%3d **", + dm->cnt_notify[BTC_NCNT_SHOW_COEX_INFO], + dm->cnt_dm[BTC_DCNT_RUN]); 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========== [BTC FEATURE SUB VER] =========="); p += scnprintf(p, end - p, - "=========================================\n"); - + "\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\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 : 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 %-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..917b2adede61 100644 --- a/drivers/net/wireless/realtek/rtw89/core.c +++ b/drivers/net/wireless/realtek/rtw89/core.c @@ -2,6 +2,7 @@ /* Copyright(c) 2019-2020 Realtek Corporation */ #include <linux/ip.h> +#include <linux/sort.h> #include <linux/udp.h> #include "cam.h" @@ -204,6 +205,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, }; @@ -271,17 +273,18 @@ rtw89_get_6ghz_span(struct rtw89_dev *rtwdev, u32 center_freq) return NULL; } -bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate) +bool rtw89_legacy_rate_to_bitrate(struct rtw89_dev *rtwdev, u8 legacy_rate, u16 *bitrate) { - struct ieee80211_rate rate; + const struct ieee80211_rate *rate; - if (unlikely(rpt_rate >= ARRAY_SIZE(rtw89_bitrates))) { - rtw89_debug(rtwdev, RTW89_DBG_UNEXP, "invalid rpt rate %d\n", rpt_rate); + if (unlikely(legacy_rate >= ARRAY_SIZE(rtw89_bitrates))) { + rtw89_debug(rtwdev, RTW89_DBG_UNEXP, + "invalid legacy rate %d\n", legacy_rate); return false; } - rate = rtw89_bitrates[rpt_rate]; - *bitrate = rate.bitrate; + rate = &rtw89_bitrates[legacy_rate]; + *bitrate = rate->bitrate; return true; } @@ -318,15 +321,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 +347,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); } } @@ -686,6 +699,66 @@ static void rtw89_core_tx_update_llc_hdr(struct rtw89_dev *rtwdev, desc_info->hdr_llc_len >>= 1; /* in unit of 2 bytes */ } +u8 rtw89_core_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel) +{ + switch (qsel) { + default: + rtw89_warn(rtwdev, "Cannot map qsel to dma: %d\n", qsel); + fallthrough; + case RTW89_TX_QSEL_BE_0: + case RTW89_TX_QSEL_BE_1: + case RTW89_TX_QSEL_BE_2: + case RTW89_TX_QSEL_BE_3: + return RTW89_TXCH_ACH0; + case RTW89_TX_QSEL_BK_0: + case RTW89_TX_QSEL_BK_1: + case RTW89_TX_QSEL_BK_2: + case RTW89_TX_QSEL_BK_3: + return RTW89_TXCH_ACH1; + case RTW89_TX_QSEL_VI_0: + case RTW89_TX_QSEL_VI_1: + case RTW89_TX_QSEL_VI_2: + case RTW89_TX_QSEL_VI_3: + return RTW89_TXCH_ACH2; + case RTW89_TX_QSEL_VO_0: + case RTW89_TX_QSEL_VO_1: + case RTW89_TX_QSEL_VO_2: + case RTW89_TX_QSEL_VO_3: + return RTW89_TXCH_ACH3; + case RTW89_TX_QSEL_B0_MGMT: + return RTW89_TXCH_CH8; + case RTW89_TX_QSEL_B0_HI: + return RTW89_TXCH_CH9; + case RTW89_TX_QSEL_B1_MGMT: + return RTW89_TXCH_CH10; + case RTW89_TX_QSEL_B1_HI: + return RTW89_TXCH_CH11; + } +} +EXPORT_SYMBOL(rtw89_core_get_ch_dma); + +u8 rtw89_core_get_ch_dma_v1(struct rtw89_dev *rtwdev, u8 qsel) +{ + switch (qsel) { + default: + rtw89_warn(rtwdev, "Cannot map qsel to dma v1: %d\n", qsel); + fallthrough; + case RTW89_TX_QSEL_BE_0: + case RTW89_TX_QSEL_BK_0: + return RTW89_TXCH_ACH0; + case RTW89_TX_QSEL_VI_0: + case RTW89_TX_QSEL_VO_0: + return RTW89_TXCH_ACH2; + case RTW89_TX_QSEL_B0_MGMT: + case RTW89_TX_QSEL_B0_HI: + return RTW89_TXCH_CH8; + case RTW89_TX_QSEL_B1_MGMT: + case RTW89_TX_QSEL_B1_HI: + return RTW89_TXCH_CH10; + } +} +EXPORT_SYMBOL(rtw89_core_get_ch_dma_v1); + static void rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) @@ -699,7 +772,7 @@ rtw89_core_tx_update_mgmt_info(struct rtw89_dev *rtwdev, u8 qsel, ch_dma; qsel = rtw89_core_get_qsel_mgmt(rtwdev, tx_req); - ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel); + ch_dma = rtw89_chip_get_ch_dma(rtwdev, qsel); desc_info->qsel = qsel; desc_info->ch_dma = ch_dma; @@ -916,7 +989,7 @@ rtw89_core_tx_update_data_info(struct rtw89_dev *rtwdev, tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; tid_indicate = rtw89_core_get_tid_indicate(rtwdev, tid); qsel = desc_info->hiq ? RTW89_TX_QSEL_B0_HI : rtw89_core_get_qsel(rtwdev, tid); - ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel); + ch_dma = rtw89_chip_get_ch_dma(rtwdev, qsel); desc_info->ch_dma = ch_dma; desc_info->tid_indicate = tid_indicate; @@ -983,13 +1056,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); } @@ -1050,42 +1135,46 @@ rtw89_core_tx_update_desc_info(struct rtw89_dev *rtwdev, } } +static void rtw89_tx_wait_work(struct wiphy *wiphy, struct wiphy_work *work) +{ + struct rtw89_dev *rtwdev = container_of(work, struct rtw89_dev, + tx_wait_work.work); + + rtw89_tx_wait_list_clear(rtwdev); +} + void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel) { u8 ch_dma; - ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel); + ch_dma = rtw89_chip_get_ch_dma(rtwdev, qsel); rtw89_hci_tx_kick_off(rtwdev, ch_dma); } int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, - int qsel, unsigned int timeout) + struct rtw89_tx_wait_info *wait, int qsel, + unsigned int timeout) { - struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb); - struct rtw89_tx_wait_info *wait; unsigned long time_left; int ret = 0; - wait = kzalloc(sizeof(*wait), GFP_KERNEL); - if (!wait) { - rtw89_core_tx_kick_off(rtwdev, qsel); - return 0; - } - - init_completion(&wait->completion); - rcu_assign_pointer(skb_data->wait, wait); + lockdep_assert_wiphy(rtwdev->hw->wiphy); rtw89_core_tx_kick_off(rtwdev, qsel); time_left = wait_for_completion_timeout(&wait->completion, msecs_to_jiffies(timeout)); - if (time_left == 0) - ret = -ETIMEDOUT; - else if (!wait->tx_done) - ret = -EAGAIN; - rcu_assign_pointer(skb_data->wait, NULL); - kfree_rcu(wait, rcu_head); + if (time_left == 0) { + ret = -ETIMEDOUT; + list_add_tail(&wait->list, &rtwdev->tx_waits); + wiphy_delayed_work_queue(rtwdev->hw->wiphy, &rtwdev->tx_wait_work, + RTW89_TX_WAIT_WORK_TIMEOUT); + } else { + if (!wait->tx_done) + ret = -EAGAIN; + rtw89_tx_wait_release(wait); + } return ret; } @@ -1134,10 +1223,12 @@ int rtw89_h2c_tx(struct rtw89_dev *rtwdev, static int rtw89_core_tx_write_link(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, - struct sk_buff *skb, int *qsel, bool sw_mld) + struct sk_buff *skb, int *qsel, bool sw_mld, + struct rtw89_tx_wait_info *wait) { struct ieee80211_sta *sta = rtwsta_link_to_sta_safe(rtwsta_link); struct ieee80211_vif *vif = rtwvif_link_to_vif(rtwvif_link); + struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb); struct rtw89_vif *rtwvif = rtwvif_link->rtwvif; struct rtw89_core_tx_request tx_req = {}; int ret; @@ -1149,11 +1240,13 @@ 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); + rcu_assign_pointer(skb_data->wait, wait); + ret = rtw89_hci_tx_write(rtwdev, &tx_req); if (ret) { rtw89_err(rtwdev, "failed to transmit skb to HCI\n"); @@ -1190,7 +1283,8 @@ int rtw89_core_tx_write(struct rtw89_dev *rtwdev, struct ieee80211_vif *vif, } } - return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false); + return rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, qsel, false, + NULL); } static __le32 rtw89_build_txwd_body0(struct rtw89_tx_desc_info *desc_info) @@ -1722,7 +1816,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 }, }; @@ -1812,6 +1906,10 @@ static void rtw89_core_parse_phy_status_ie00(struct rtw89_dev *rtwdev, tmp_rpl = le32_get_bits(ie->w0, RTW89_PHY_STS_IE00_W0_RPL); phy_ppdu->rpl_avg = tmp_rpl >> 1; + + if (!phy_ppdu->hdr_2_en) + phy_ppdu->rx_path_en = + le32_get_bits(ie->w3, RTW89_PHY_STS_IE00_W3_RX_PATH_EN); } static void rtw89_core_parse_phy_status_ie00_v2(struct rtw89_dev *rtwdev, @@ -1917,6 +2015,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 +2258,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) { @@ -2191,6 +2296,435 @@ static void rtw89_vif_sync_bcn_tsf(struct rtw89_vif_link *rtwvif_link, WRITE_ONCE(rtwvif_link->sync_bcn_tsf, le64_to_cpu(mgmt->u.beacon.timestamp)); } +static u32 rtw89_bcn_calc_min_tbtt(struct rtw89_dev *rtwdev, u32 tbtt1, u32 tbtt2) +{ + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u32 close_bcn_intvl_th = bcn_track->close_bcn_intvl_th; + u32 tbtt_diff_th = bcn_track->tbtt_diff_th; + + if (tbtt2 > tbtt1) + swap(tbtt1, tbtt2); + + if (tbtt1 - tbtt2 > tbtt_diff_th) + return tbtt1; + else if (tbtt2 > close_bcn_intvl_th) + return tbtt2; + else if (tbtt1 > close_bcn_intvl_th) + return tbtt1; + else + return tbtt2; +} + +static void rtw89_bcn_cfg_tbtt_offset(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + enum rtw89_core_chip_id chip_id = rtwdev->chip->chip_id; + u32 offset = bcn_track->tbtt_offset; + + if (chip_id == RTL8852A || rtw89_is_rtl885xb(rtwdev)) { + const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; + const struct rtw89_port_reg *p = mac->port_base; + u32 bcnspc, val; + + bcnspc = rtw89_read32_port_mask(rtwdev, rtwvif_link, + p->bcn_space, B_AX_BCN_SPACE_MASK); + val = bcnspc - (offset / 1024); + val = u32_encode_bits(val, B_AX_TBTT_SHIFT_OFST_MAG) | + B_AX_TBTT_SHIFT_OFST_SIGN; + + rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift, + B_AX_TBTT_SHIFT_OFST_MASK, val); + + return; + } + + rtw89_fw_h2c_tbtt_tuning(rtwdev, rtwvif_link, offset); +} + +static void rtw89_bcn_update_tbtt_offset(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u32 *tbtt_us = bcn_stat->tbtt_us; + u32 offset = tbtt_us[0]; + u8 i; + + for (i = 1; i < RTW89_BCN_TRACK_STAT_NR; i++) + offset = rtw89_bcn_calc_min_tbtt(rtwdev, tbtt_us[i], offset); + + if (bcn_track->tbtt_offset == offset) + return; + + bcn_track->tbtt_offset = offset; + rtw89_bcn_cfg_tbtt_offset(rtwdev, rtwvif_link); +} + +static int cmp_u16(const void *a, const void *b) +{ + return *(const u16 *)a - *(const u16 *)b; +} + +static u16 _rtw89_bcn_calc_drift(u16 tbtt, u16 offset, u16 beacon_int) +{ + if (tbtt < offset) + return beacon_int - offset + tbtt; + + return tbtt - offset; +} + +static void rtw89_bcn_calc_drift(struct rtw89_dev *rtwdev) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u16 offset_tu = bcn_track->tbtt_offset / 1024; + u16 *tbtt_tu = bcn_stat->tbtt_tu; + u16 *drift = bcn_stat->drift; + u8 i; + + bcn_stat->tbtt_tu_min = U16_MAX; + bcn_stat->tbtt_tu_max = 0; + for (i = 0; i < RTW89_BCN_TRACK_STAT_NR; i++) { + drift[i] = _rtw89_bcn_calc_drift(tbtt_tu[i], offset_tu, + bcn_track->beacon_int); + + bcn_stat->tbtt_tu_min = min(bcn_stat->tbtt_tu_min, tbtt_tu[i]); + bcn_stat->tbtt_tu_max = max(bcn_stat->tbtt_tu_max, tbtt_tu[i]); + } + + sort(drift, RTW89_BCN_TRACK_STAT_NR, sizeof(*drift), cmp_u16, NULL); +} + +static void rtw89_bcn_calc_distribution(struct rtw89_dev *rtwdev) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist; + u16 lower_bound, upper_bound, outlier_count = 0; + u16 *drift = bcn_stat->drift; + u16 *bins = bcn_dist->bins; + u16 q1, q3, iqr, tmp; + u8 i; + + BUILD_BUG_ON(RTW89_BCN_TRACK_STAT_NR % 4 != 0); + + memset(bcn_dist, 0, sizeof(*bcn_dist)); + + bcn_dist->min = drift[0]; + bcn_dist->max = drift[RTW89_BCN_TRACK_STAT_NR - 1]; + + tmp = RTW89_BCN_TRACK_STAT_NR / 4; + q1 = ((drift[tmp] + drift[tmp - 1]) * RTW89_BCN_TRACK_SCALE_FACTOR) / 2; + + tmp = (RTW89_BCN_TRACK_STAT_NR * 3) / 4; + q3 = ((drift[tmp] + drift[tmp - 1]) * RTW89_BCN_TRACK_SCALE_FACTOR) / 2; + + iqr = q3 - q1; + tmp = (3 * iqr) / 2; + + if (bcn_dist->min <= 5) + lower_bound = bcn_dist->min; + else if (q1 > tmp) + lower_bound = (q1 - tmp) / RTW89_BCN_TRACK_SCALE_FACTOR; + else + lower_bound = 0; + + upper_bound = (q3 + tmp) / RTW89_BCN_TRACK_SCALE_FACTOR; + + for (i = 0; i < RTW89_BCN_TRACK_STAT_NR; i++) { + u16 tbtt = bcn_stat->tbtt_tu[i]; + u16 min = bcn_stat->tbtt_tu_min; + u8 bin_idx; + + /* histogram */ + bin_idx = min((tbtt - min) / RTW89_BCN_TRACK_BIN_WIDTH, + RTW89_BCN_TRACK_MAX_BIN_NUM - 1); + bins[bin_idx]++; + + /* boxplot outlier */ + if (drift[i] < lower_bound || drift[i] > upper_bound) + outlier_count++; + } + + bcn_dist->outlier_count = outlier_count; + bcn_dist->lower_bound = lower_bound; + bcn_dist->upper_bound = upper_bound; +} + +static u8 rtw89_bcn_get_coverage(struct rtw89_dev *rtwdev, u16 threshold) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + int l = 0, r = RTW89_BCN_TRACK_STAT_NR - 1, m; + u16 *drift = bcn_stat->drift; + int index = -1; + u8 count = 0; + + while (l <= r) { + m = l + (r - l) / 2; + + if (drift[m] <= threshold) { + index = m; + l = m + 1; + } else { + r = m - 1; + } + } + + count = (index == -1) ? 0 : (index + 1); + + return (count * PERCENT) / RTW89_BCN_TRACK_STAT_NR; +} + +static u16 rtw89_bcn_get_histogram_bound(struct rtw89_dev *rtwdev, u8 target) +{ + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist; + u16 tbtt_tu_max = bcn_stat->tbtt_tu_max; + u16 upper, lower = bcn_stat->tbtt_tu_min; + u8 i, count = 0; + + for (i = 0; i < RTW89_BCN_TRACK_MAX_BIN_NUM; i++) { + upper = lower + RTW89_BCN_TRACK_BIN_WIDTH - 1; + if (i == RTW89_BCN_TRACK_MAX_BIN_NUM - 1) + upper = max(upper, tbtt_tu_max); + + count += bcn_dist->bins[i]; + if (count > target) + break; + + lower = upper + 1; + } + + return upper; +} + +static u16 rtw89_bcn_get_rx_time(struct rtw89_dev *rtwdev, + const struct rtw89_chan *chan) +{ +#define RTW89_SYMBOL_TIME_2GHZ 192 +#define RTW89_SYMBOL_TIME_5GHZ 20 +#define RTW89_SYMBOL_TIME_6GHZ 20 + struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat; + u16 bitrate, val; + + if (!rtw89_legacy_rate_to_bitrate(rtwdev, pkt_stat->beacon_rate, &bitrate)) + return 0; + + val = (pkt_stat->beacon_len * 8 * RTW89_BCN_TRACK_SCALE_FACTOR) / bitrate; + + switch (chan->band_type) { + default: + case RTW89_BAND_2G: + val += RTW89_SYMBOL_TIME_2GHZ; + break; + case RTW89_BAND_5G: + val += RTW89_SYMBOL_TIME_5GHZ; + break; + case RTW89_BAND_6G: + val += RTW89_SYMBOL_TIME_6GHZ; + break; + } + + /* convert to millisecond */ + return DIV_ROUND_UP(val, 1000); +} + +static void rtw89_bcn_calc_timeout(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ +#define RTW89_BCN_TRACK_EXTEND_TIMEOUT 5 +#define RTW89_BCN_TRACK_COVERAGE_TH 0 /* unit: TU */ +#define RTW89_BCN_TRACK_STRONG_RSSI 80 + const struct rtw89_chan *chan = rtw89_chan_get(rtwdev, rtwvif_link->chanctx_idx); + struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.cur_pkt_stat; + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist; + u16 outlier_high_bcn_th = bcn_track->outlier_high_bcn_th; + u16 outlier_low_bcn_th = bcn_track->outlier_low_bcn_th; + u8 rssi = ewma_rssi_read(&rtwdev->phystat.bcn_rssi); + u16 target_bcn_th = bcn_track->target_bcn_th; + u16 low_bcn_th = bcn_track->low_bcn_th; + u16 med_bcn_th = bcn_track->med_bcn_th; + u16 beacon_int = bcn_track->beacon_int; + u16 bcn_timeout; + + if (pkt_stat->beacon_nr < low_bcn_th) { + bcn_timeout = (RTW89_BCN_TRACK_TARGET_BCN * beacon_int) / PERCENT; + goto out; + } + + if (bcn_dist->outlier_count >= outlier_high_bcn_th) { + bcn_timeout = bcn_dist->max; + goto out; + } + + if (pkt_stat->beacon_nr < med_bcn_th) { + if (bcn_dist->outlier_count > outlier_low_bcn_th) + bcn_timeout = (bcn_dist->max + bcn_dist->upper_bound) / 2; + else + bcn_timeout = bcn_dist->upper_bound + + RTW89_BCN_TRACK_EXTEND_TIMEOUT; + + goto out; + } + + if (rssi >= RTW89_BCN_TRACK_STRONG_RSSI) { + if (rtw89_bcn_get_coverage(rtwdev, RTW89_BCN_TRACK_COVERAGE_TH) >= 90) { + /* ideal case */ + bcn_timeout = 0; + } else { + u16 offset_tu = bcn_track->tbtt_offset / 1024; + u16 upper_bound; + + upper_bound = + rtw89_bcn_get_histogram_bound(rtwdev, target_bcn_th); + bcn_timeout = + _rtw89_bcn_calc_drift(upper_bound, offset_tu, beacon_int); + } + + goto out; + } + + bcn_timeout = bcn_stat->drift[target_bcn_th]; + +out: + bcn_track->bcn_timeout = bcn_timeout + rtw89_bcn_get_rx_time(rtwdev, chan); +} + +static void rtw89_bcn_update_timeout(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ + rtw89_bcn_calc_drift(rtwdev); + rtw89_bcn_calc_distribution(rtwdev); + rtw89_bcn_calc_timeout(rtwdev, rtwvif_link); +} + +static void rtw89_core_bcn_track(struct rtw89_dev *rtwdev) +{ + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + struct rtw89_vif_link *rtwvif_link; + struct rtw89_vif *rtwvif; + unsigned int link_id; + + if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) + return; + + if (!rtwdev->lps_enabled) + return; + + if (!bcn_track->is_data_ready) + return; + + rtw89_for_each_rtwvif(rtwdev, rtwvif) { + rtw89_vif_for_each_link(rtwvif, rtwvif_link, link_id) { + if (!(rtwvif_link->wifi_role == RTW89_WIFI_ROLE_STATION || + rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT)) + continue; + + rtw89_bcn_update_tbtt_offset(rtwdev, rtwvif_link); + rtw89_bcn_update_timeout(rtwdev, rtwvif_link); + } + } +} + +static bool rtw89_core_bcn_track_can_lps(struct rtw89_dev *rtwdev) +{ + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + + if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) + return true; + + return bcn_track->is_data_ready; +} + +static void rtw89_core_bcn_track_assoc(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) +{ +#define RTW89_BCN_TRACK_MED_BCN 70 +#define RTW89_BCN_TRACK_LOW_BCN 30 +#define RTW89_BCN_TRACK_OUTLIER_HIGH_BCN 30 +#define RTW89_BCN_TRACK_OUTLIER_LOW_BCN 20 + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u32 period = jiffies_to_msecs(RTW89_TRACK_WORK_PERIOD); + struct ieee80211_bss_conf *bss_conf; + u32 beacons_in_period; + u32 bcn_intvl_us; + u16 beacon_int; + u8 dtim; + + rcu_read_lock(); + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + beacon_int = bss_conf->beacon_int; + dtim = bss_conf->dtim_period; + rcu_read_unlock(); + + beacons_in_period = period / beacon_int / dtim; + bcn_intvl_us = ieee80211_tu_to_usec(beacon_int); + + bcn_track->low_bcn_th = + (beacons_in_period * RTW89_BCN_TRACK_LOW_BCN) / PERCENT; + bcn_track->med_bcn_th = + (beacons_in_period * RTW89_BCN_TRACK_MED_BCN) / PERCENT; + bcn_track->outlier_low_bcn_th = + (RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_OUTLIER_LOW_BCN) / PERCENT; + bcn_track->outlier_high_bcn_th = + (RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_OUTLIER_HIGH_BCN) / PERCENT; + bcn_track->target_bcn_th = + (RTW89_BCN_TRACK_STAT_NR * RTW89_BCN_TRACK_TARGET_BCN) / PERCENT; + + bcn_track->close_bcn_intvl_th = ieee80211_tu_to_usec(beacon_int - 3); + bcn_track->tbtt_diff_th = (bcn_intvl_us * 85) / PERCENT; + bcn_track->beacon_int = beacon_int; + bcn_track->dtim = dtim; +} + +static void rtw89_core_bcn_track_reset(struct rtw89_dev *rtwdev) +{ + memset(&rtwdev->phystat.bcn_stat, 0, sizeof(rtwdev->phystat.bcn_stat)); + memset(&rtwdev->bcn_track, 0, sizeof(rtwdev->bcn_track)); +} + +static void rtw89_vif_rx_bcn_stat(struct rtw89_dev *rtwdev, + struct ieee80211_bss_conf *bss_conf, + struct sk_buff *skb) +{ +#define RTW89_APPEND_TSF_2GHZ 384 +#define RTW89_APPEND_TSF_5GHZ 52 +#define RTW89_APPEND_TSF_6GHZ 52 + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data; + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + u32 bcn_intvl_us = ieee80211_tu_to_usec(bss_conf->beacon_int); + u64 tsf = le64_to_cpu(mgmt->u.beacon.timestamp); + u8 wp, num = bcn_stat->num; + u16 append; + + if (!RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) + return; + + switch (rx_status->band) { + default: + case NL80211_BAND_2GHZ: + append = RTW89_APPEND_TSF_2GHZ; + break; + case NL80211_BAND_5GHZ: + append = RTW89_APPEND_TSF_5GHZ; + break; + case NL80211_BAND_6GHZ: + append = RTW89_APPEND_TSF_6GHZ; + break; + } + + wp = bcn_stat->wp; + div_u64_rem(tsf - append, bcn_intvl_us, &bcn_stat->tbtt_us[wp]); + bcn_stat->tbtt_tu[wp] = bcn_stat->tbtt_us[wp] / 1024; + bcn_stat->wp = (wp + 1) % RTW89_BCN_TRACK_STAT_NR; + bcn_stat->num = umin(num + 1, RTW89_BCN_TRACK_STAT_NR); + bcn_track->is_data_ready = bcn_stat->num == RTW89_BCN_TRACK_STAT_NR; +} + static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { @@ -2207,6 +2741,7 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, struct ieee80211_bss_conf *bss_conf; struct rtw89_vif_link *rtwvif_link; const u8 *bssid = iter_data->bssid; + const u8 *target_bssid; if (rtwdev->scanning && (ieee80211_is_beacon(hdr->frame_control) || @@ -2228,7 +2763,10 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, goto out; } - if (!ether_addr_equal(bss_conf->bssid, bssid)) + target_bssid = ieee80211_is_beacon(hdr->frame_control) && + bss_conf->nontransmitted ? + bss_conf->transmitter_bssid : bss_conf->bssid; + if (!ether_addr_equal(target_bssid, bssid)) goto out; if (is_mld) { @@ -2242,7 +2780,6 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, rtw89_vif_sync_bcn_tsf(rtwvif_link, hdr, skb->len); rtw89_fw_h2c_rssi_offload(rtwdev, phy_ppdu); } - pkt_stat->beacon_nr++; if (phy_ppdu) { ewma_rssi_add(&rtwdev->phystat.bcn_rssi, phy_ppdu->rssi_avg); @@ -2250,7 +2787,11 @@ static void rtw89_vif_rx_stats_iter(void *data, u8 *mac, rtwvif_link->bcn_bw_idx = phy_ppdu->bw_idx; } + pkt_stat->beacon_nr++; pkt_stat->beacon_rate = desc_info->data_rate; + pkt_stat->beacon_len = skb->len; + + rtw89_vif_rx_bcn_stat(rtwdev, bss_conf, skb); } if (!ether_addr_equal(bss_conf->addr, hdr->addr1)) @@ -2259,7 +2800,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 +2813,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 +3018,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 +3071,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 +3329,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 +3345,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 +3417,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 +3508,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) @@ -3151,7 +3737,7 @@ static u32 rtw89_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, u8 tid) u8 qsel, ch_dma; qsel = rtw89_core_get_qsel(rtwdev, tid); - ch_dma = rtw89_core_get_ch_dma(rtwdev, qsel); + ch_dma = rtw89_chip_get_ch_dma(rtwdev, qsel); return rtw89_hci_check_and_reclaim_tx_resource(rtwdev, ch_dma); } @@ -3330,12 +3916,13 @@ 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; struct rtw89_sta_link *rtwsta_link; + struct rtw89_tx_wait_info *wait; struct ieee80211_sta *sta; struct ieee80211_hdr *hdr; struct rtw89_sta *rtwsta; @@ -3345,6 +3932,12 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) return 0; + wait = kzalloc(sizeof(*wait), GFP_KERNEL); + if (!wait) + return -ENOMEM; + + init_completion(&wait->completion); + rcu_read_lock(); sta = ieee80211_find_sta(vif, vif->cfg.ap_addr); if (!sta) { @@ -3359,6 +3952,8 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, goto out; } + wait->skb = skb; + hdr = (struct ieee80211_hdr *)skb->data; if (ps) hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); @@ -3366,10 +3961,12 @@ static int rtw89_core_send_nullfunc(struct rtw89_dev *rtwdev, rtwsta_link = rtwsta->links[rtwvif_link->link_id]; if (unlikely(!rtwsta_link)) { ret = -ENOLINK; + dev_kfree_skb_any(skb); goto out; } - ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true); + ret = rtw89_core_tx_write_link(rtwdev, rtwvif_link, rtwsta_link, skb, &qsel, true, + wait); if (ret) { rtw89_warn(rtwdev, "nullfunc transmit failed: %d\n", ret); dev_kfree_skb_any(skb); @@ -3378,10 +3975,11 @@ 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); + return rtw89_core_tx_kick_off_and_wait(rtwdev, skb, wait, qsel, + timeout); out: rcu_read_unlock(); + kfree(wait); return ret; } @@ -3416,7 +4014,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 +4075,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 +4115,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 +4142,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 +4157,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 +4185,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 +4210,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); @@ -3604,6 +4220,9 @@ static void rtw89_enter_lps_track(struct rtw89_dev *rtwdev) vif->type == NL80211_IFTYPE_P2P_CLIENT)) continue; + if (!rtw89_core_bcn_track_can_lps(rtwdev)) + continue; + rtw89_enter_lps(rtwdev, rtwvif, true); } } @@ -3734,6 +4353,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 +4389,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)) @@ -3762,6 +4409,7 @@ static void rtw89_track_work(struct wiphy *wiphy, struct wiphy_work *work) rtw89_btc_ntfy_wl_sta(rtwdev); } rtw89_mac_bf_monitor_track(rtwdev); + rtw89_core_bcn_track(rtwdev); rtw89_phy_stat_track(rtwdev); rtw89_phy_env_monitor_track(rtwdev); rtw89_phy_dig(rtwdev); @@ -3967,6 +4615,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) { @@ -4001,8 +4656,10 @@ int rtw89_core_sta_link_disassoc(struct rtw89_dev *rtwdev, rtw89_assoc_link_clr(rtwsta_link); - if (vif->type == NL80211_IFTYPE_STATION) + if (vif->type == NL80211_IFTYPE_STATION) { rtw89_fw_h2c_set_bcn_fltr_cfg(rtwdev, rtwvif_link, false); + rtw89_core_bcn_track_reset(rtwdev); + } if (rtwvif_link->wifi_role == RTW89_WIFI_ROLE_P2P_CLIENT) rtw89_p2p_noa_once_deinit(rtwvif_link); @@ -4143,6 +4800,7 @@ int rtw89_core_sta_link_assoc(struct rtw89_dev *rtwdev, BTC_ROLE_MSTS_STA_CONN_END); rtw89_core_get_no_ul_ofdma_htc(rtwdev, &rtwsta_link->htc_template, chan); rtw89_phy_ul_tb_assoc(rtwdev, rtwvif_link); + rtw89_core_bcn_track_assoc(rtwdev, rtwvif_link); ret = rtw89_fw_h2c_general_pkt(rtwdev, rtwvif_link, rtwsta_link->mac_id); if (ret) { @@ -4151,6 +4809,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 +4832,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,39 +5322,133 @@ void rtw89_core_update_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) rtw89_chip_h2c_update_beacon(rtwdev, rtwvif_link); } -int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond) +void rtw89_core_csa_beacon_work(struct wiphy *wiphy, struct wiphy_work *work) { - struct completion *cmpl = &wait->completion; - unsigned long time_left; + 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); + } +} + +struct rtw89_wait_response * +rtw89_wait_for_cond_prep(struct rtw89_wait_info *wait, unsigned int cond) +{ + struct rtw89_wait_response *prep; unsigned int cur; + /* use -EPERM _iff_ telling eval side not to make any changes */ + cur = atomic_cmpxchg(&wait->cond, RTW89_WAIT_COND_IDLE, cond); if (cur != RTW89_WAIT_COND_IDLE) - return -EBUSY; + return ERR_PTR(-EPERM); + + prep = kzalloc(sizeof(*prep), GFP_KERNEL); + if (!prep) + return ERR_PTR(-ENOMEM); + + init_completion(&prep->completion); + + rcu_assign_pointer(wait->resp, prep); + + return prep; +} + +int rtw89_wait_for_cond_eval(struct rtw89_wait_info *wait, + struct rtw89_wait_response *prep, int err) +{ + unsigned long time_left; + + if (IS_ERR(prep)) { + err = err ?: PTR_ERR(prep); - time_left = wait_for_completion_timeout(cmpl, RTW89_WAIT_FOR_COND_TIMEOUT); + /* special error case: no permission to reset anything */ + if (PTR_ERR(prep) == -EPERM) + return err; + + goto reset; + } + + if (err) + goto cleanup; + + time_left = wait_for_completion_timeout(&prep->completion, + RTW89_WAIT_FOR_COND_TIMEOUT); if (time_left == 0) { - atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE); - return -ETIMEDOUT; + err = -ETIMEDOUT; + goto cleanup; } + wait->data = prep->data; + +cleanup: + rcu_assign_pointer(wait->resp, NULL); + kfree_rcu(prep, rcu_head); + +reset: + atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE); + + if (err) + return err; + if (wait->data.err) return -EFAULT; return 0; } +static void rtw89_complete_cond_resp(struct rtw89_wait_response *resp, + const struct rtw89_completion_data *data) +{ + resp->data = *data; + complete(&resp->completion); +} + void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond, const struct rtw89_completion_data *data) { + struct rtw89_wait_response *resp; unsigned int cur; + guard(rcu)(); + + resp = rcu_dereference(wait->resp); + if (!resp) + return; + cur = atomic_cmpxchg(&wait->cond, cond, RTW89_WAIT_COND_IDLE); if (cur != cond) return; - wait->data = *data; - complete(&wait->completion); + rtw89_complete_cond_resp(resp, data); } void rtw89_core_ntfy_btc_event(struct rtw89_dev *rtwdev, enum rtw89_btc_hmsg event) @@ -4734,6 +5495,8 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) { int ret; + rtw89_phy_init_bb_afe(rtwdev); + ret = rtw89_mac_init(rtwdev); if (ret) { rtw89_err(rtwdev, "mac init fail, ret:%d\n", ret); @@ -4769,6 +5532,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); @@ -4776,6 +5541,7 @@ int rtw89_core_start(struct rtw89_dev *rtwdev) rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_ON); rtw89_fw_h2c_fw_log(rtwdev, rtwdev->fw.log.enable); rtw89_fw_h2c_init_ba_cam(rtwdev); + rtw89_tas_fw_timer_enable(rtwdev, true); return 0; } @@ -4791,6 +5557,7 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) if (!test_bit(RTW89_FLAG_RUNNING, rtwdev->flags)) return; + rtw89_tas_fw_timer_enable(rtwdev, false); rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_WL_OFF); clear_bit(RTW89_FLAG_RUNNING, rtwdev->flags); @@ -4802,12 +5569,15 @@ void rtw89_core_stop(struct rtw89_dev *rtwdev) wiphy_work_cancel(wiphy, &btc->dhcp_notify_work); wiphy_work_cancel(wiphy, &btc->icmp_notify_work); cancel_delayed_work_sync(&rtwdev->txq_reinvoke_work); + wiphy_delayed_work_cancel(wiphy, &rtwdev->tx_wait_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); @@ -5025,15 +5795,19 @@ int rtw89_core_init(struct rtw89_dev *rtwdev) INIT_LIST_HEAD(&rtwdev->scan_info.pkt_list[band]); } INIT_LIST_HEAD(&rtwdev->scan_info.chan_list); + INIT_LIST_HEAD(&rtwdev->tx_waits); INIT_WORK(&rtwdev->ba_work, rtw89_core_ba_work); 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); + wiphy_delayed_work_init(&rtwdev->tx_wait_work, rtw89_tx_wait_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 +5901,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 +5921,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 +6022,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 +6257,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 +6291,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 +6318,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) @@ -5618,6 +6407,7 @@ int rtw89_core_register(struct rtw89_dev *rtwdev) return ret; } + rtw89_phy_dm_init_data(rtwdev); rtw89_debugfs_init(rtwdev); return 0; @@ -5668,6 +6458,9 @@ struct rtw89_dev *rtw89_alloc_ieee80211_hw(struct device *device, ops->cancel_remain_on_channel = NULL; } + if (!chip->support_noise) + ops->get_survey = NULL; + driver_data_size = sizeof(struct rtw89_dev) + bus_data_size; hw = ieee80211_alloc_hw(driver_data_size, ops); if (!hw) diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 1c8f3b9b7c4c..928c8c84c964 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 { @@ -999,6 +1011,7 @@ struct rtw89_port_reg { u32 ptcl_dbg; u32 ptcl_dbg_info; u32 bcn_drop_all; + u32 bcn_psr_rpt; u32 hiq_win[RTW89_PORT_NUM]; }; @@ -1205,7 +1218,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 +1335,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 +1394,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 +1407,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 +1575,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 +1828,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 +1844,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 +1940,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 +1953,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 +2115,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 +2954,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 +3069,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 +3188,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 +3214,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 +3461,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 +3497,7 @@ struct rtw89_efuse { u8 addr[ETH_ALEN]; u8 rfe_type; char country_code[2]; + u8 adc_td; }; struct rtw89_phy_rate_pattern { @@ -3429,9 +3507,12 @@ struct rtw89_phy_rate_pattern { bool enable; }; +#define RTW89_TX_WAIT_WORK_TIMEOUT msecs_to_jiffies(500) struct rtw89_tx_wait_info { struct rcu_head rcu_head; + struct list_head list; struct completion completion; + struct sk_buff *skb; bool tx_done; }; @@ -3440,6 +3521,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 +3601,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 +3617,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 +3625,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 +3683,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 +3733,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, @@ -3673,6 +3763,7 @@ struct rtw89_chip_ops { void (*fill_txdesc_fwcmd)(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); + u8 (*get_ch_dma)(struct rtw89_dev *rtwdev, u8 qsel); int (*cfg_ctrl_path)(struct rtw89_dev *rtwdev, bool wl); int (*mac_cfg_gnt)(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg); @@ -3693,6 +3784,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 +3871,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; @@ -4274,6 +4368,9 @@ struct rtw89_chanctx_listener { (struct rtw89_dev *rtwdev, enum rtw89_chanctx_state state); }; +#define RTW89_NHM_TH_NUM 11 +#define RTW89_NHM_RPT_NUM 12 + struct rtw89_chip_info { enum rtw89_core_chip_id chip_id; enum rtw89_chip_gen chip_gen; @@ -4292,8 +4389,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]; @@ -4308,6 +4405,7 @@ struct rtw89_chip_info { bool support_ant_gain; bool support_tas; bool support_sar_by_ant; + bool support_noise; bool ul_tb_waveform_ctrl; bool ul_tb_pwr_diff; bool rx_freq_frome_ie; @@ -4358,7 +4456,6 @@ struct rtw89_chip_info { u32 para_ver; u32 wlcx_desired; - u8 btcx_desired; u8 scbd; u8 mailbox; @@ -4393,6 +4490,8 @@ struct rtw89_chip_info { bool cfo_hw_comp; const struct rtw89_reg_def *dcfo_comp; u8 dcfo_comp_sft; + const struct rtw89_reg_def (*nhm_report)[RTW89_NHM_RPT_NUM]; + const struct rtw89_reg_def (*nhm_th)[RTW89_NHM_TH_NUM]; const struct rtw89_imr_info *imr_info; const struct rtw89_imr_table *imr_dmac_table; const struct rtw89_imr_table *imr_cmac_table; @@ -4454,17 +4553,23 @@ struct rtw89_completion_data { u8 buf[RTW89_COMPLETION_BUF_SIZE]; }; +struct rtw89_wait_response { + struct rcu_head rcu_head; + struct completion completion; + struct rtw89_completion_data data; +}; + struct rtw89_wait_info { atomic_t cond; - struct completion completion; struct rtw89_completion_data data; + struct rtw89_wait_response __rcu *resp; }; #define RTW89_WAIT_FOR_COND_TIMEOUT msecs_to_jiffies(100) static inline void rtw89_init_wait(struct rtw89_wait_info *wait) { - init_completion(&wait->completion); + rcu_assign_pointer(wait->resp, NULL); atomic_set(&wait->cond, RTW89_WAIT_COND_IDLE); } @@ -4498,11 +4603,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 +4628,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 +4636,10 @@ 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, + RTW89_FW_FEATURE_BEACON_TRACKING, }; struct rtw89_fw_suit { @@ -4579,6 +4699,7 @@ struct rtw89_fw_elm_info { struct rtw89_fw_txpwr_track_cfg *txpwr_trk; struct rtw89_phy_rfk_log_fmt *rfk_log_fmt; const struct rtw89_regd_data *regd; + const struct rtw89_fw_element_hdr *afe; }; enum rtw89_fw_mss_dev_type { @@ -4617,6 +4738,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 +5037,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, }; @@ -4967,9 +5093,36 @@ struct rtw89_pkt_drop_params { struct rtw89_pkt_stat { u16 beacon_nr; u8 beacon_rate; + u32 beacon_len; u32 rx_rate_cnt[RTW89_HW_RATE_NR]; }; +#define RTW89_BCN_TRACK_STAT_NR 32 +#define RTW89_BCN_TRACK_SCALE_FACTOR 10 +#define RTW89_BCN_TRACK_MAX_BIN_NUM 6 +#define RTW89_BCN_TRACK_BIN_WIDTH 5 +#define RTW89_BCN_TRACK_TARGET_BCN 80 + +struct rtw89_beacon_dist { + u16 min; + u16 max; + u16 outlier_count; + u16 lower_bound; + u16 upper_bound; + u16 bins[RTW89_BCN_TRACK_MAX_BIN_NUM]; +}; + +struct rtw89_beacon_stat { + u8 num; + u8 wp; + u16 tbtt_tu_min; + u16 tbtt_tu_max; + u16 drift[RTW89_BCN_TRACK_STAT_NR]; + u32 tbtt_us[RTW89_BCN_TRACK_STAT_NR]; + u16 tbtt_tu[RTW89_BCN_TRACK_STAT_NR]; + struct rtw89_beacon_dist bcn_dist; +}; + DECLARE_EWMA(thermal, 4, 4); struct rtw89_phy_stat { @@ -4978,6 +5131,7 @@ struct rtw89_phy_stat { struct ewma_rssi bcn_rssi; struct rtw89_pkt_stat cur_pkt_stat; struct rtw89_pkt_stat last_pkt_stat; + struct rtw89_beacon_stat bcn_stat; }; enum rtw89_rfk_report_state { @@ -5079,7 +5233,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 +5311,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 +5456,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 { @@ -5324,6 +5481,7 @@ enum rtw89_env_racing_lv { struct rtw89_ccx_para_info { enum rtw89_env_racing_lv rac_lv; u16 mntr_time; + bool nhm_incld_cca; u8 nhm_manual_th_ofst; u8 nhm_manual_th0; enum rtw89_ifs_clm_application ifs_clm_app; @@ -5357,9 +5515,13 @@ enum rtw89_ccx_edcca_opt_bw_idx { RTW89_CCX_EDCCA_BW20_7 = 7 }; -#define RTW89_NHM_TH_NUM 11 +struct rtw89_nhm_report { + struct list_head list; + struct ieee80211_channel *channel; + u8 noise; +}; + #define RTW89_FAHM_TH_NUM 11 -#define RTW89_NHM_RPT_NUM 12 #define RTW89_FAHM_RPT_NUM 12 #define RTW89_IFS_CLM_NUM 4 struct rtw89_env_monitor_info { @@ -5393,6 +5555,13 @@ struct rtw89_env_monitor_info { u16 ifs_clm_ofdm_fa_permil; u32 ifs_clm_ifs_avg[RTW89_IFS_CLM_NUM]; u32 ifs_clm_cca_avg[RTW89_IFS_CLM_NUM]; + bool nhm_include_cca; + u32 nhm_sum; + u32 nhm_mntr_time; + u16 nhm_result[RTW89_NHM_RPT_NUM]; + u8 nhm_th[RTW89_NHM_RPT_NUM]; + struct rtw89_nhm_report *nhm_his[RTW89_BAND_NUM]; + struct list_head nhm_rpt_list; }; enum rtw89_ser_rcvy_step { @@ -5447,13 +5616,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 { @@ -5594,8 +5774,8 @@ struct rtw89_wow_gtk_info { u8 kck[32]; u8 kek[32]; u8 tk1[16]; - u8 txmickey[8]; u8 rxmickey[8]; + u8 txmickey[8]; __le32 igtk_keyid; __le64 ipn; u8 igtk[2][32]; @@ -5672,12 +5852,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 +5910,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 */ }; @@ -5758,6 +5941,24 @@ struct rtw89_mlo_info { struct rtw89_wait_info wait; }; +struct rtw89_beacon_track_info { + bool is_data_ready; + u32 tbtt_offset; /* in unit of microsecond */ + u16 bcn_timeout; /* in unit of millisecond */ + + /* The following are constant and set at association. */ + u8 dtim; + u16 beacon_int; + u16 low_bcn_th; + u16 med_bcn_th; + u16 high_bcn_th; + u16 target_bcn_th; + u16 outlier_low_bcn_th; + u16 outlier_high_bcn_th; + u32 close_bcn_intvl_th; + u32 tbtt_diff_th; +}; + struct rtw89_dev { struct ieee80211_hw *hw; struct device *dev; @@ -5772,6 +5973,7 @@ struct rtw89_dev { const struct rtw89_pci_info *pci_info; const struct rtw89_rfe_parms *rfe_parms; struct rtw89_hal hal; + struct rtw89_beacon_track_info bcn_track; struct rtw89_mcc_info mcc; struct rtw89_mlo_info mlo; struct rtw89_mac_info mac; @@ -5801,6 +6003,9 @@ struct rtw89_dev { /* used to protect rpwm */ spinlock_t rpwm_lock; + struct list_head tx_waits; + struct wiphy_delayed_work tx_wait_work; + struct rtw89_cam_info cam_info; struct sk_buff_head c2h_queue; @@ -5853,11 +6058,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 +6109,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; @@ -6054,6 +6262,26 @@ rtw89_assoc_link_rcu_dereference(struct rtw89_dev *rtwdev, u8 macid) list_first_entry_or_null(&p->dlink_pool, typeof(*p->links_inst), dlink_schd); \ }) +static inline void rtw89_tx_wait_release(struct rtw89_tx_wait_info *wait) +{ + dev_kfree_skb_any(wait->skb); + kfree_rcu(wait, rcu_head); +} + +static inline void rtw89_tx_wait_list_clear(struct rtw89_dev *rtwdev) +{ + struct rtw89_tx_wait_info *wait, *tmp; + + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + list_for_each_entry_safe(wait, tmp, &rtwdev->tx_waits, list) { + if (!completion_done(&wait->completion)) + continue; + list_del(&wait->list); + rtw89_tx_wait_release(wait); + } +} + static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request *tx_req) { @@ -6063,6 +6291,7 @@ static inline int rtw89_hci_tx_write(struct rtw89_dev *rtwdev, static inline void rtw89_hci_reset(struct rtw89_dev *rtwdev) { rtwdev->hci.ops->reset(rtwdev); + rtw89_tx_wait_list_clear(rtwdev); } static inline int rtw89_hci_start(struct rtw89_dev *rtwdev) @@ -6195,9 +6424,13 @@ static inline void rtw89_hci_clear(struct rtw89_dev *rtwdev, struct pci_dev *pde static inline struct rtw89_tx_skb_data *RTW89_TX_SKB_CB(struct sk_buff *skb) { + /* + * This should be used by/after rtw89_hci_tx_write() and before doing + * ieee80211_tx_info_clear_status(). + */ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - return (struct rtw89_tx_skb_data *)info->status.status_driver_data; + return (struct rtw89_tx_skb_data *)info->driver_data; } static inline u8 rtw89_read8(struct rtw89_dev *rtwdev, u32 addr) @@ -6880,6 +7113,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) @@ -6993,6 +7237,14 @@ void rtw89_chip_fill_txdesc_fwcmd(struct rtw89_dev *rtwdev, } static inline +u8 rtw89_chip_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + return chip->ops->get_ch_dma(rtwdev, qsel); +} + +static inline void rtw89_chip_mac_cfg_gnt(struct rtw89_dev *rtwdev, const struct rtw89_mac_ax_coex_gnt *gnt_cfg) { @@ -7120,11 +7372,12 @@ static inline struct sk_buff *rtw89_alloc_skb_for_rx(struct rtw89_dev *rtwdev, return dev_alloc_skb(length); } -static inline void rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev, +static inline bool rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev, struct rtw89_tx_skb_data *skb_data, bool tx_done) { struct rtw89_tx_wait_info *wait; + bool ret = false; rcu_read_lock(); @@ -7132,11 +7385,14 @@ static inline void rtw89_core_tx_wait_complete(struct rtw89_dev *rtwdev, if (!wait) goto out; + ret = true; wait->tx_done = tx_done; - complete(&wait->completion); + /* Don't access skb anymore after completion */ + complete_all(&wait->completion); out: rcu_read_unlock(); + return ret; } static inline bool rtw89_is_mlo_1_1(struct rtw89_dev *rtwdev) @@ -7203,13 +7459,25 @@ 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, struct sk_buff *skb, bool fwdl); void rtw89_core_tx_kick_off(struct rtw89_dev *rtwdev, u8 qsel); int rtw89_core_tx_kick_off_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, - int qsel, unsigned int timeout); + struct rtw89_tx_wait_info *wait, int qsel, + unsigned int timeout); void rtw89_core_fill_txdesc(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); @@ -7225,6 +7493,8 @@ void rtw89_core_fill_txdesc_fwcmd_v1(struct rtw89_dev *rtwdev, void rtw89_core_fill_txdesc_fwcmd_v2(struct rtw89_dev *rtwdev, struct rtw89_tx_desc_info *desc_info, void *txdesc); +u8 rtw89_core_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel); +u8 rtw89_core_get_ch_dma_v1(struct rtw89_dev *rtwdev, u8 qsel); void rtw89_core_rx(struct rtw89_dev *rtwdev, struct rtw89_rx_desc_info *desc_info, struct sk_buff *skb); @@ -7305,18 +7575,26 @@ void rtw89_vif_type_mapping(struct rtw89_vif_link *rtwvif_link, bool assoc); int rtw89_chip_info_setup(struct rtw89_dev *rtwdev); void rtw89_chip_cfg_txpwr_ul_tb_offset(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); -bool rtw89_ra_report_to_bitrate(struct rtw89_dev *rtwdev, u8 rpt_rate, u16 *bitrate); +bool rtw89_legacy_rate_to_bitrate(struct rtw89_dev *rtwdev, u8 legacy_rate, u16 *bitrate); int rtw89_regd_setup(struct rtw89_dev *rtwdev); int rtw89_regd_init_hint(struct rtw89_dev *rtwdev); const char *rtw89_regd_get_string(enum rtw89_regulation_type regd); void rtw89_traffic_stats_init(struct rtw89_dev *rtwdev, struct rtw89_traffic_stats *stats); -int rtw89_wait_for_cond(struct rtw89_wait_info *wait, unsigned int cond); +struct rtw89_wait_response * +rtw89_wait_for_cond_prep(struct rtw89_wait_info *wait, unsigned int cond) +__acquires(rtw89_wait); +int rtw89_wait_for_cond_eval(struct rtw89_wait_info *wait, + struct rtw89_wait_response *prep, int err) +__releases(rtw89_wait); void rtw89_complete_cond(struct rtw89_wait_info *wait, unsigned int cond, const struct rtw89_completion_data *data); 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..3dc7981c510f 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.c +++ b/drivers/net/wireless/realtek/rtw89/debug.c @@ -86,6 +86,7 @@ struct rtw89_debugfs { struct rtw89_debugfs_priv stations; struct rtw89_debugfs_priv disable_dm; struct rtw89_debugfs_priv mlo_mode; + struct rtw89_debugfs_priv beacon_info; }; struct rtw89_debugfs_iter_data { @@ -1114,6 +1115,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 +1123,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 +1144,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; @@ -3561,6 +3563,58 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev) return 0; } +static int rtw89_dbg_trigger_mac_error_ax(struct rtw89_dev *rtwdev) +{ + u16 val16; + u8 val8; + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL); + if (ret) + return ret; + + val8 = rtw89_read8(rtwdev, R_AX_CMAC_FUNC_EN); + rtw89_write8(rtwdev, R_AX_CMAC_FUNC_EN, val8 & ~B_AX_TMAC_EN); + mdelay(1); + rtw89_write8(rtwdev, R_AX_CMAC_FUNC_EN, val8); + + val16 = rtw89_read16(rtwdev, R_AX_PTCL_IMR0); + rtw89_write16(rtwdev, R_AX_PTCL_IMR0, val16 | B_AX_F2PCMD_EMPTY_ERR_INT_EN); + rtw89_write16(rtwdev, R_AX_PTCL_IMR0, val16); + + return 0; +} + +static int rtw89_dbg_trigger_mac_error_be(struct rtw89_dev *rtwdev) +{ + int ret; + + ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL); + if (ret) + return ret; + + rtw89_write32_set(rtwdev, R_BE_CMAC_FW_TRIGGER_IDCT_ISR, + B_BE_CMAC_FW_TRIG_IDCT | B_BE_CMAC_FW_ERR_IDCT_IMR); + + return 0; +} + +static int rtw89_dbg_trigger_mac_error(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + + rtw89_leave_ps_mode(rtwdev); + + switch (chip->chip_gen) { + case RTW89_CHIP_AX: + return rtw89_dbg_trigger_mac_error_ax(rtwdev); + case RTW89_CHIP_BE: + return rtw89_dbg_trigger_mac_error_be(rtwdev); + default: + return -EOPNOTSUPP; + } +} + static ssize_t rtw89_debug_priv_fw_crash_get(struct rtw89_dev *rtwdev, struct rtw89_debugfs_priv *debugfs_priv, @@ -3576,6 +3630,7 @@ rtw89_debug_priv_fw_crash_get(struct rtw89_dev *rtwdev, enum rtw89_dbg_crash_simulation_type { RTW89_DBG_SIM_CPU_EXCEPTION = 1, RTW89_DBG_SIM_CTRL_ERROR = 2, + RTW89_DBG_SIM_MAC_ERROR = 3, }; static ssize_t @@ -3584,6 +3639,7 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev, const char *buf, size_t count) { int (*sim)(struct rtw89_dev *rtwdev); + bool announce = true; u8 crash_type; int ret; @@ -3595,18 +3651,26 @@ 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; case RTW89_DBG_SIM_CTRL_ERROR: sim = rtw89_dbg_trigger_ctrl_error; break; + case RTW89_DBG_SIM_MAC_ERROR: + sim = rtw89_dbg_trigger_mac_error; + + /* Driver SER flow won't get involved; only FW will. */ + announce = false; + break; default: return -EINVAL; } - set_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags); + if (announce) + set_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags); + ret = sim(rtwdev); if (ret) @@ -4297,6 +4361,64 @@ rtw89_debug_priv_mlo_mode_set(struct rtw89_dev *rtwdev, return count; } +static ssize_t +rtw89_debug_priv_beacon_info_get(struct rtw89_dev *rtwdev, + struct rtw89_debugfs_priv *debugfs_priv, + char *buf, size_t bufsz) +{ + struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat; + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat; + struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist; + u16 upper, lower = bcn_stat->tbtt_tu_min; + char *p = buf, *end = buf + bufsz; + u16 *drift = bcn_stat->drift; + u8 bcn_num = bcn_stat->num; + u8 count; + u8 i; + + p += scnprintf(p, end - p, "[Beacon info]\n"); + p += scnprintf(p, end - p, "count: %u\n", pkt_stat->beacon_nr); + p += scnprintf(p, end - p, "interval: %u\n", bcn_track->beacon_int); + p += scnprintf(p, end - p, "dtim: %u\n", bcn_track->dtim); + p += scnprintf(p, end - p, "raw rssi: %lu\n", + ewma_rssi_read(&rtwdev->phystat.bcn_rssi)); + p += scnprintf(p, end - p, "hw rate: %u\n", pkt_stat->beacon_rate); + p += scnprintf(p, end - p, "length: %u\n", pkt_stat->beacon_len); + + p += scnprintf(p, end - p, "\n[Distribution]\n"); + p += scnprintf(p, end - p, "tbtt\n"); + for (i = 0; i < RTW89_BCN_TRACK_MAX_BIN_NUM; i++) { + upper = lower + RTW89_BCN_TRACK_BIN_WIDTH - 1; + if (i == RTW89_BCN_TRACK_MAX_BIN_NUM - 1) + upper = max(upper, bcn_stat->tbtt_tu_max); + + p += scnprintf(p, end - p, "%02u - %02u: %u\n", + lower, upper, bcn_dist->bins[i]); + + lower = upper + 1; + } + + p += scnprintf(p, end - p, "\ndrift\n"); + + for (i = 0; i < bcn_num; i += count) { + count = 1; + while (i + count < bcn_num && drift[i] == drift[i + count]) + count++; + + p += scnprintf(p, end - p, "%u: %u\n", drift[i], count); + } + p += scnprintf(p, end - p, "\nlower bound: %u\n", bcn_dist->lower_bound); + p += scnprintf(p, end - p, "upper bound: %u\n", bcn_dist->upper_bound); + p += scnprintf(p, end - p, "outlier count: %u\n", bcn_dist->outlier_count); + + p += scnprintf(p, end - p, "\n[Tracking]\n"); + p += scnprintf(p, end - p, "tbtt offset: %u\n", bcn_track->tbtt_offset); + p += scnprintf(p, end - p, "bcn timeout: %u\n", bcn_track->bcn_timeout); + + return p - buf; +} + #define rtw89_debug_priv_get(name, opts...) \ { \ .cb_read = rtw89_debug_priv_ ##name## _get, \ @@ -4355,6 +4477,7 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = { .stations = rtw89_debug_priv_get(stations, RLOCK), .disable_dm = rtw89_debug_priv_set_and_get(disable_dm, RWLOCK), .mlo_mode = rtw89_debug_priv_set_and_get(mlo_mode, RWLOCK), + .beacon_info = rtw89_debug_priv_get(beacon_info), }; #define rtw89_debugfs_add(name, mode, fopname, parent) \ @@ -4400,6 +4523,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top rtw89_debugfs_add_r(stations); rtw89_debugfs_add_rw(disable_dm); rtw89_debugfs_add_rw(mlo_mode); + rtw89_debugfs_add_r(beacon_info); } void rtw89_debugfs_init(struct rtw89_dev *rtwdev) diff --git a/drivers/net/wireless/realtek/rtw89/debug.h b/drivers/net/wireless/realtek/rtw89/debug.h index fc690f7c55dc..a364e7adb079 100644 --- a/drivers/net/wireless/realtek/rtw89/debug.h +++ b/drivers/net/wireless/realtek/rtw89/debug.h @@ -56,6 +56,7 @@ static inline void rtw89_debugfs_deinit(struct rtw89_dev *rtwdev) {} #endif #define rtw89_info(rtwdev, a...) dev_info((rtwdev)->dev, ##a) +#define rtw89_info_once(rtwdev, a...) dev_info_once((rtwdev)->dev, ##a) #define rtw89_warn(rtwdev, a...) dev_warn((rtwdev)->dev, ##a) #define rtw89_err(rtwdev, a...) dev_err((rtwdev)->dev, ##a) diff --git a/drivers/net/wireless/realtek/rtw89/fw.c b/drivers/net/wireless/realtek/rtw89/fw.c index 00b65b2995cf..ab904a7def1b 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.c +++ b/drivers/net/wireless/realtek/rtw89/fw.c @@ -814,36 +814,50 @@ 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(RTL8852B, ge, 0, 29, 128, 0, BEACON_TRACKING), __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, 122, 0, BEACON_TRACKING), + __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(RTL8852C, ge, 0, 27, 128, 0, LPS_DACK_BY_C2H_REG), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 128, 0, CRASH_TRIGGER_TYPE_1), + __CFG_FW_FEAT(RTL8852C, ge, 0, 27, 129, 1, BEACON_TRACKING), + __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 +867,9 @@ 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), + __CFG_FW_FEAT(RTL8922A, ge, 0, 35, 80, 0, BEACON_TRACKING), }; static void rtw89_fw_iterate_feature_cfg(struct rtw89_fw_info *fw, @@ -1269,6 +1286,18 @@ int rtw89_recognize_regd_from_elm(struct rtw89_dev *rtwdev, return 0; } +static +int rtw89_build_afe_pwr_seq_from_elm(struct rtw89_dev *rtwdev, + const struct rtw89_fw_element_hdr *elm, + const union rtw89_fw_element_arg arg) +{ + struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; + + elm_info->afe = elm; + + return 0; +} + static const struct rtw89_fw_element_handler __fw_element_handlers[] = { [RTW89_FW_ELEMENT_ID_BBMCU0] = {__rtw89_fw_recognize_from_elm, { .fw_type = RTW89_FW_BBMCU0 }, NULL}, @@ -1354,6 +1383,9 @@ static const struct rtw89_fw_element_handler __fw_element_handlers[] = { [RTW89_FW_ELEMENT_ID_REGD] = { rtw89_recognize_regd_from_elm, {}, "REGD", }, + [RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ] = { + rtw89_build_afe_pwr_seq_from_elm, {}, "AFE", + }, }; int rtw89_fw_recognize_elements(struct rtw89_dev *rtwdev) @@ -1526,7 +1558,7 @@ static int __rtw89_fw_download_hdr(struct rtw89_dev *rtwdev, struct rtw89_fw_hdr *fw_hdr; struct sk_buff *skb; u32 truncated; - u32 ret = 0; + int ret; skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); if (!skb) { @@ -2821,8 +2853,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 +2882,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 +3068,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 +3766,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) { @@ -3932,6 +4011,93 @@ fail: } EXPORT_SYMBOL(rtw89_fw_h2c_update_beacon_be); +int rtw89_fw_h2c_tbtt_tuning(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, u32 offset) +{ + struct rtw89_h2c_tbtt_tuning *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 tbtt tuning\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_tbtt_tuning *)skb->data; + + h2c->w0 = le32_encode_bits(rtwvif_link->phy_idx, RTW89_H2C_TBTT_TUNING_W0_BAND) | + le32_encode_bits(rtwvif_link->port, RTW89_H2C_TBTT_TUNING_W0_PORT); + h2c->w1 = le32_encode_bits(offset, RTW89_H2C_TBTT_TUNING_W1_SHIFT); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_PS, + H2C_FUNC_TBTT_TUNING, 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_pwr_lvl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) +{ +#define RTW89_BCN_TO_VAL_MIN 4 +#define RTW89_BCN_TO_VAL_MAX 64 +#define RTW89_DTIM_TO_VAL_MIN 7 +#define RTW89_DTIM_TO_VAL_MAX 15 + struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track; + struct rtw89_h2c_pwr_lvl *h2c; + u32 len = sizeof(*h2c); + struct sk_buff *skb; + u8 bcn_to_val; + int ret; + + skb = rtw89_fw_h2c_alloc_skb_with_hdr(rtwdev, len); + if (!skb) { + rtw89_err(rtwdev, "failed to alloc skb for h2c pwr lvl\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_pwr_lvl *)skb->data; + + bcn_to_val = clamp_t(u8, bcn_track->bcn_timeout, + RTW89_BCN_TO_VAL_MIN, RTW89_BCN_TO_VAL_MAX); + + h2c->w0 = le32_encode_bits(rtwvif_link->mac_id, RTW89_H2C_PWR_LVL_W0_MACID) | + le32_encode_bits(bcn_to_val, RTW89_H2C_PWR_LVL_W0_BCN_TO_VAL) | + le32_encode_bits(0, RTW89_H2C_PWR_LVL_W0_PS_LVL) | + le32_encode_bits(0, RTW89_H2C_PWR_LVL_W0_TRX_LVL) | + le32_encode_bits(RTW89_DTIM_TO_VAL_MIN, + RTW89_H2C_PWR_LVL_W0_DTIM_TO_VAL); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_MAC, H2C_CL_MAC_PS, + H2C_FUNC_PS_POWER_LEVEL, 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_role_maintain(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link, struct rtw89_sta_link *rtwsta_link, @@ -5083,6 +5249,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 +5567,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 +5610,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 +5748,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 +5779,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 +5813,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 +5865,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 +5966,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 +6008,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 +6044,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 +6121,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 +6178,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 +6404,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 +6427,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 +6452,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); @@ -6288,6 +6688,40 @@ fail: return ret; } +int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable) +{ + struct rtw89_h2c_rf_tas *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 RF TAS\n"); + return -ENOMEM; + } + skb_put(skb, len); + h2c = (struct rtw89_h2c_rf_tas *)skb->data; + + h2c->enable = cpu_to_le32(enable); + + rtw89_h2c_pkt_set_hdr(rtwdev, skb, FWCMD_TYPE_H2C, + H2C_CAT_OUTSRC, H2C_CL_OUTSRC_RF_FW_RFK, + H2C_FUNC_RFK_TAS_OFFLOAD, 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_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack) @@ -6467,6 +6901,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 +6968,19 @@ 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 timeout; u8 i, val; + int ret; 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"); @@ -6540,7 +7008,7 @@ int rtw89_fw_msg_reg(struct rtw89_dev *rtwdev, struct rtw89_mac_h2c_info *h2c_info, struct rtw89_mac_c2h_info *c2h_info) { - u32 ret; + int ret; if (h2c_info && h2c_info->id != RTW89_FWCMD_H2CREG_FUNC_GET_FEATURE) lockdep_assert_wiphy(rtwdev->hw->wiphy); @@ -6619,6 +7087,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, @@ -6797,7 +7266,6 @@ static void rtw89_pno_scan_add_chan_ax(struct rtw89_dev *rtwdev, struct rtw89_pktofld_info *info; u8 probe_count = 0; - ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK; ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS; ch_info->bw = RTW89_SCAN_WIDTH; ch_info->tx_pkt = true; @@ -6845,6 +7313,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 +7384,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"); } @@ -6928,7 +7406,6 @@ static void rtw89_pno_scan_add_chan_be(struct rtw89_dev *rtwdev, int chan_type, struct rtw89_pktofld_info *info; u8 probe_count = 0, i; - ch_info->notify_action = RTW89_SCANOFLD_DEBUG_MASK; ch_info->dfs_ch = chan_type == RTW89_CHAN_DFS; ch_info->bw = RTW89_SCAN_WIDTH; ch_info->tx_null = false; @@ -7073,10 +7550,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 +7615,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 +7633,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; - 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; + 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; } + + 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 +7793,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 +7885,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 +7911,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 +7943,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 +7969,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 +7978,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 +8048,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 +8086,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 +8102,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 +8121,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 +8194,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 +8206,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 +8220,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 @@ -8107,9 +8726,10 @@ int rtw89_fw_h2c_wow_gtk_ofld(struct rtw89_dev *rtwdev, goto fail; } - /* not support TKIP yet */ h2c->w0 = le32_encode_bits(enable, RTW89_H2C_WOW_GTK_OFLD_W0_EN) | - le32_encode_bits(0, RTW89_H2C_WOW_GTK_OFLD_W0_TKIP_EN) | + le32_encode_bits(!!memchr_inv(gtk_info->txmickey, 0, + sizeof(gtk_info->txmickey)), + RTW89_H2C_WOW_GTK_OFLD_W0_TKIP_EN) | le32_encode_bits(gtk_info->igtk_keyid ? 1 : 0, RTW89_H2C_WOW_GTK_OFLD_W0_IEEE80211W_EN) | le32_encode_bits(macid, RTW89_H2C_WOW_GTK_OFLD_W0_MAC_ID) | @@ -8201,19 +8821,30 @@ int rtw89_fw_h2c_wow_request_aoac(struct rtw89_dev *rtwdev) static int rtw89_h2c_tx_and_wait(struct rtw89_dev *rtwdev, struct sk_buff *skb, struct rtw89_wait_info *wait, unsigned int cond) { - int ret; + struct rtw89_wait_response *prep; + int ret = 0; + + lockdep_assert_wiphy(rtwdev->hw->wiphy); + + prep = rtw89_wait_for_cond_prep(wait, cond); + if (IS_ERR(prep)) + goto out; ret = rtw89_h2c_tx(rtwdev, skb, false); if (ret) { rtw89_err(rtwdev, "failed to send h2c\n"); dev_kfree_skb_any(skb); - return -EBUSY; + ret = -EBUSY; + goto out; } - if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) - return 1; + if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) { + ret = 1; + goto out; + } - return rtw89_wait_for_cond(wait, cond); +out: + return rtw89_wait_for_cond_eval(wait, prep, ret); } #define H2C_ADD_MCC_LEN 16 diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index 0fcc824e41be..ddebf7972068 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; @@ -1592,6 +1602,28 @@ struct rtw89_h2c_bcn_upd_be { #define RTW89_H2C_BCN_UPD_BE_W7_ECSA_OFST GENMASK(30, 16) #define RTW89_H2C_BCN_UPD_BE_W7_PROTECTION_KEY_ID BIT(31) +struct rtw89_h2c_tbtt_tuning { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_TBTT_TUNING_W0_BAND GENMASK(3, 0) +#define RTW89_H2C_TBTT_TUNING_W0_PORT GENMASK(7, 4) +#define RTW89_H2C_TBTT_TUNING_W1_SHIFT GENMASK(31, 0) + +struct rtw89_h2c_pwr_lvl { + __le32 w0; + __le32 w1; +} __packed; + +#define RTW89_H2C_PWR_LVL_W0_MACID GENMASK(7, 0) +#define RTW89_H2C_PWR_LVL_W0_BCN_TO_VAL GENMASK(15, 8) +#define RTW89_H2C_PWR_LVL_W0_PS_LVL GENMASK(19, 16) +#define RTW89_H2C_PWR_LVL_W0_TRX_LVL GENMASK(23, 20) +#define RTW89_H2C_PWR_LVL_W0_BCN_TO_LVL GENMASK(27, 24) +#define RTW89_H2C_PWR_LVL_W0_DTIM_TO_VAL GENMASK(31, 28) +#define RTW89_H2C_PWR_LVL_W1_MACID_EXT GENMASK(7, 0) + struct rtw89_h2c_role_maintain { __le32 w0; }; @@ -1825,10 +1857,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 +2280,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 +2712,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 +2812,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 +2846,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 +3594,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) @@ -3941,6 +3984,7 @@ enum rtw89_fw_element_id { RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_2GHZ = 24, RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_5GHZ = 25, RTW89_FW_ELEMENT_ID_TXPWR_DA_LMT_RU_6GHZ = 26, + RTW89_FW_ELEMENT_ID_AFE_PWR_SEQ = 27, RTW89_FW_ELEMENT_ID_NUM, }; @@ -4046,6 +4090,30 @@ struct rtw89_fw_txpwr_track_cfg { BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_N) | \ BIT(RTW89_FW_TXPWR_TRK_TYPE_2G_CCK_A_P)) +enum rtw89_fw_afe_action { + RTW89_FW_AFE_ACTION_WRITE = 0, + RTW89_FW_AFE_ACTION_DELAY = 1, + RTW89_FW_AFE_ACTION_POLL = 2, +}; + +enum rtw89_fw_afe_cat { + RTW89_FW_AFE_CAT_BB = 0, + RTW89_FW_AFE_CAT_BB1 = 1, + RTW89_FW_AFE_CAT_MAC = 2, + RTW89_FW_AFE_CAT_MAC1 = 3, + RTW89_FW_AFE_CAT_AFEDIG = 4, + RTW89_FW_AFE_CAT_AFEDIG1 = 5, +}; + +enum rtw89_fw_afe_class { + RTW89_FW_AFE_CLASS_P0 = 0, + RTW89_FW_AFE_CLASS_P1 = 1, + RTW89_FW_AFE_CLASS_P2 = 2, + RTW89_FW_AFE_CLASS_P3 = 3, + RTW89_FW_AFE_CLASS_P4 = 4, + RTW89_FW_AFE_CLASS_CMN = 5, +}; + struct rtw89_fw_element_hdr { __le32 id; /* enum rtw89_fw_element_id */ __le32 size; /* exclude header size */ @@ -4083,6 +4151,17 @@ struct rtw89_fw_element_hdr { u8 rsvd1[3]; __le16 offset[]; } __packed rfk_log_fmt; + struct { + u8 rsvd[8]; + struct rtw89_phy_afe_info { + __le32 action; /* enum rtw89_fw_afe_action */ + __le32 cat; /* enum rtw89_fw_afe_cat */ + __le32 class; /* enum rtw89_fw_afe_class */ + __le32 addr; + __le32 mask; + __le32 val; + } __packed infos[]; + } __packed afe; struct __rtw89_fw_txpwr_element txpwr; struct __rtw89_fw_regd_element regd; } __packed u; @@ -4180,6 +4259,8 @@ enum rtw89_ps_h2c_func { H2C_FUNC_MAC_LPS_PARM = 0x0, H2C_FUNC_P2P_ACT = 0x1, H2C_FUNC_IPS_CFG = 0x3, + H2C_FUNC_PS_POWER_LEVEL = 0x7, + H2C_FUNC_TBTT_TUNING = 0xA, NUM_OF_RTW89_PS_H2C_FUNC, }; @@ -4330,6 +4411,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 +4419,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 { @@ -4347,9 +4430,18 @@ enum rtw89_rfk_offload_h2c_func { H2C_FUNC_RFK_DACK_OFFLOAD = 0x5, H2C_FUNC_RFK_RXDCK_OFFLOAD = 0x6, H2C_FUNC_RFK_PRE_NOTIFY = 0x8, + H2C_FUNC_RFK_TAS_OFFLOAD = 0x9, }; 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 +4450,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 +4554,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; @@ -4481,6 +4612,10 @@ struct rtw89_h2c_rf_rxdck_v0 { u8 rxdck_dbg_en; } __packed; +struct rtw89_h2c_rf_tas { + __le32 enable; +} __packed; + struct rtw89_h2c_rf_rxdck { struct rtw89_h2c_rf_rxdck_v0 v0; u8 is_chl_k; @@ -4613,12 +4748,16 @@ struct rtw89_c2h_rfk_report { u8 version; } __packed; -struct rtw89_c2h_rf_tas_info { - struct rtw89_c2h_hdr hdr; +struct rtw89_c2h_rf_tas_rpt_log { __le32 cur_idx; __le16 txpwr_history[20]; } __packed; +struct rtw89_c2h_rf_tas_info { + struct rtw89_c2h_hdr hdr; + struct rtw89_c2h_rf_tas_rpt_log content; +} __packed; + #define RTW89_FW_RSVD_PLE_SIZE 0x800 #define RTW89_FW_BACKTRACE_INFO_SIZE 8 @@ -4629,6 +4768,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,12 +4810,18 @@ 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, struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_update_beacon_be(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); +int rtw89_fw_h2c_tbtt_tuning(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link, u32 offset); +int rtw89_fw_h2c_pwr_lvl(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link); int rtw89_fw_h2c_cam(struct rtw89_dev *rtwdev, struct rtw89_vif_link *vif, struct rtw89_sta_link *rtwsta_link, const u8 *scan_mac_addr); int rtw89_fw_h2c_dctl_sec_cam_v1(struct rtw89_dev *rtwdev, @@ -4686,6 +4832,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 +4860,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 +4880,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, @@ -4746,6 +4898,7 @@ int rtw89_fw_h2c_rf_dack(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan); int rtw89_fw_h2c_rf_rxdck(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, const struct rtw89_chan *chan, bool is_chl_k); +int rtw89_fw_h2c_rf_tas_trigger(struct rtw89_dev *rtwdev, bool enable); int rtw89_fw_h2c_raw_with_hdr(struct rtw89_dev *rtwdev, u8 h2c_class, u8 h2c_func, u8 *buf, u16 len, bool rack, bool dack); @@ -4815,9 +4968,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 +5121,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..fd11b8fb3c89 100644 --- a/drivers/net/wireless/realtek/rtw89/mac.c +++ b/drivers/net/wireless/realtek/rtw89/mac.c @@ -9,6 +9,7 @@ #include "fw.h" #include "mac.h" #include "pci.h" +#include "phy.h" #include "ps.h" #include "reg.h" #include "util.h" @@ -88,7 +89,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 +105,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); @@ -177,7 +178,7 @@ int rtw89_mac_dle_dfi_qempty_cfg(struct rtw89_dev *rtwdev, struct rtw89_mac_dle_dfi_qempty *qempty) { struct rtw89_mac_dle_dfi_ctrl ctrl; - u32 ret; + int ret; ctrl.type = qempty->dle_type; ctrl.target = DLE_DFI_TYPE_QEMPTY; @@ -875,31 +876,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->pub_cfg) + param->pub_cfg = *param_ini->pub_cfg; - if (param_ini.prec_cfg) - param->prec_cfg = *param_ini.prec_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; + 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; } @@ -986,7 +986,7 @@ static int hfc_upd_ch_info(struct rtw89_dev *rtwdev, u8 ch) struct rtw89_hfc_ch_info *info = param->ch_info; const struct rtw89_hfc_ch_cfg *cfg = param->ch_cfg; u32 val; - u32 ret; + int ret; ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_DMAC_SEL); if (ret) @@ -1177,8 +1177,8 @@ int rtw89_mac_hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_e const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_chip_info *chip = rtwdev->chip; u32 dma_ch_mask = chip->dma_ch_mask; + int ret = 0; u8 ch; - u32 ret = 0; if (reset) ret = hfc_reset_param(rtwdev); @@ -1194,7 +1194,7 @@ int rtw89_mac_hfc_init(struct rtw89_dev *rtwdev, bool reset, bool en, bool h2c_e if (!en && h2c_en) { mac->hfc_h2c_cfg(rtwdev); mac->hfc_func_en(rtwdev, en, h2c_en); - return ret; + return 0; } for (ch = RTW89_DMA_ACH0; ch < RTW89_DMA_H2C; ch++) { @@ -1441,6 +1441,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 +1468,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 +1665,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 +1682,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 +1700,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 +1725,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 +1751,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; @@ -2379,7 +2414,7 @@ static int addr_cam_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) static int scheduler_init_ax(struct rtw89_dev *rtwdev, u8 mac_idx) { - u32 ret; + int ret; u32 reg; u32 val; @@ -2920,7 +2955,7 @@ static int rtw89_mac_read_phycap(struct rtw89_dev *rtwdev, struct rtw89_mac_h2c_info h2c_info = {}; enum rtw89_mac_c2h_type c2h_type; u8 content_len; - u32 ret; + int ret; if (chip->chip_gen == RTW89_CHIP_AX) content_len = 0; @@ -3071,10 +3106,10 @@ int rtw89_mac_setup_phycap(struct rtw89_dev *rtwdev) static int rtw89_hw_sch_tx_en_h2c(struct rtw89_dev *rtwdev, u8 band, u16 tx_en_u16, u16 mask_u16) { - u32 ret; struct rtw89_mac_c2h_info c2h_info = {0}; struct rtw89_mac_h2c_info h2c_info = {0}; struct rtw89_h2creg_sch_tx_en *sch_tx_en = &h2c_info.u.sch_tx_en; + int ret; h2c_info.id = RTW89_FWCMD_H2CREG_FUNC_SCH_TX_EN; h2c_info.content_len = sizeof(*sch_tx_en) - RTW89_H2CREG_HDR_LEN; @@ -4163,6 +4198,7 @@ static const struct rtw89_port_reg rtw89_port_base_ax = { .ptcl_dbg = R_AX_PTCL_DBG, .ptcl_dbg_info = R_AX_PTCL_DBG_INFO, .bcn_drop_all = R_AX_BCN_DROP_ALL0, + .bcn_psr_rpt = R_AX_BCN_PSR_RPT_P0, .hiq_win = {R_AX_P0MB_HGQ_WINDOW_CFG_0, R_AX_PORT_HGQ_WINDOW_CFG, R_AX_PORT_HGQ_WINDOW_CFG + 1, R_AX_PORT_HGQ_WINDOW_CFG + 2, R_AX_PORT_HGQ_WINDOW_CFG + 3}, @@ -4388,7 +4424,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 +4458,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, @@ -4584,25 +4651,28 @@ static void rtw89_mac_port_cfg_bcn_early(struct rtw89_dev *rtwdev, BCN_ERLY_DEF); } -static void rtw89_mac_port_cfg_tbtt_shift(struct rtw89_dev *rtwdev, - struct rtw89_vif_link *rtwvif_link) +static void rtw89_mac_port_cfg_bcn_psr_rpt(struct rtw89_dev *rtwdev, + struct rtw89_vif_link *rtwvif_link) { const struct rtw89_mac_gen_def *mac = rtwdev->chip->mac_def; const struct rtw89_port_reg *p = mac->port_base; - u16 val; + struct ieee80211_bss_conf *bss_conf; + u8 bssid_index; + u32 reg; - if (rtwdev->chip->chip_id != RTL8852C) - return; + rcu_read_lock(); - if (rtwvif_link->wifi_role != RTW89_WIFI_ROLE_P2P_CLIENT && - rtwvif_link->wifi_role != RTW89_WIFI_ROLE_STATION) - return; + bss_conf = rtw89_vif_rcu_dereference_link(rtwvif_link, true); + if (bss_conf->nontransmitted) + bssid_index = bss_conf->bssid_index; + else + bssid_index = 0; - val = FIELD_PREP(B_AX_TBTT_SHIFT_OFST_MAG, 1) | - B_AX_TBTT_SHIFT_OFST_SIGN; + rcu_read_unlock(); - rtw89_write16_port_mask(rtwdev, rtwvif_link, p->tbtt_shift, - B_AX_TBTT_SHIFT_OFST_MASK, val); + reg = rtw89_mac_reg_by_idx(rtwdev, p->bcn_psr_rpt + rtwvif_link->port * 4, + rtwvif_link->mac_idx); + rtw89_write32_mask(rtwdev, reg, B_AX_BCAID_P0_MASK, bssid_index); } void rtw89_mac_port_tsf_sync(struct rtw89_dev *rtwdev, @@ -4755,13 +4825,13 @@ int rtw89_mac_port_update(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvi rtw89_mac_port_cfg_bcn_hold_time(rtwdev, rtwvif_link); rtw89_mac_port_cfg_bcn_mask_area(rtwdev, rtwvif_link); rtw89_mac_port_cfg_tbtt_early(rtwdev, rtwvif_link); - rtw89_mac_port_cfg_tbtt_shift(rtwdev, rtwvif_link); rtw89_mac_port_cfg_bss_color(rtwdev, rtwvif_link); rtw89_mac_port_cfg_mbssid(rtwdev, rtwvif_link); rtw89_mac_port_cfg_func_en(rtwdev, rtwvif_link, true); rtw89_mac_port_tsf_resync_all(rtwdev); fsleep(BCN_ERLY_SET_DLY); rtw89_mac_port_cfg_bcn_early(rtwdev, rtwvif_link); + rtw89_mac_port_cfg_bcn_psr_rpt(rtwdev, rtwvif_link); return 0; } @@ -4891,11 +4961,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 +4986,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,9 +5042,12 @@ 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); + } else { + rtw89_phy_nhm_get_result(rtwdev, band, chan); } return; case RTW89_SCAN_END_SCAN_NOTIFY: @@ -4971,6 +5056,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,16 +5068,17 @@ 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, RTW89_CHANNEL_WIDTH_20); rtw89_assign_entity_chan(rtwdev, rtwvif_link->chanctx_idx, &new); + rtw89_phy_nhm_trigger(rtwdev); } break; default: @@ -5009,6 +5096,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 +5114,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 +5173,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 +5216,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; @@ -5148,6 +5244,11 @@ rtw89_mac_c2h_bcn_cnt(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) } static void +rtw89_mac_c2h_bcn_upd_done(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ +} + +static void rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len) { @@ -5170,6 +5271,11 @@ rtw89_mac_c2h_pkt_ofld_rsp(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, } static void +rtw89_mac_c2h_bcn_resend(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ +} + +static void rtw89_mac_c2h_tx_duty_rpt(struct rtw89_dev *rtwdev, struct sk_buff *skb_c2h, u32 len) { struct rtw89_c2h_tx_duty_rpt *c2h = @@ -5558,7 +5664,7 @@ void (* const rtw89_mac_c2h_ofld_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_EFUSE_DUMP] = NULL, [RTW89_MAC_C2H_FUNC_READ_RSP] = NULL, [RTW89_MAC_C2H_FUNC_PKT_OFLD_RSP] = rtw89_mac_c2h_pkt_ofld_rsp, - [RTW89_MAC_C2H_FUNC_BCN_RESEND] = NULL, + [RTW89_MAC_C2H_FUNC_BCN_RESEND] = rtw89_mac_c2h_bcn_resend, [RTW89_MAC_C2H_FUNC_MACID_PAUSE] = rtw89_mac_c2h_macid_pause, [RTW89_MAC_C2H_FUNC_SCANOFLD_RSP] = rtw89_mac_c2h_scanofld_rsp, [RTW89_MAC_C2H_FUNC_TX_DUTY_RPT] = rtw89_mac_c2h_tx_duty_rpt, @@ -5573,6 +5679,7 @@ void (* const rtw89_mac_c2h_info_handler[])(struct rtw89_dev *rtwdev, [RTW89_MAC_C2H_FUNC_DONE_ACK] = rtw89_mac_c2h_done_ack, [RTW89_MAC_C2H_FUNC_C2H_LOG] = rtw89_mac_c2h_log, [RTW89_MAC_C2H_FUNC_BCN_CNT] = rtw89_mac_c2h_bcn_cnt, + [RTW89_MAC_C2H_FUNC_BCN_UPD_DONE] = rtw89_mac_c2h_bcn_upd_done, }; static @@ -5621,10 +5728,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,14 +5829,14 @@ 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); - return; + break; } if (!handler) { - rtw89_info(rtwdev, "MAC c2h class %d func %d not support\n", class, - func); + rtw89_info_once(rtwdev, "MAC c2h class %d func %d not support\n", + class, func); return; } handler(rtwdev, skb, len); @@ -5779,7 +5891,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 +5974,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 +6106,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; } @@ -6623,7 +6738,7 @@ int rtw89_mac_set_hw_muedca_ctrl(struct rtw89_dev *rtwdev, u8 mac_idx = rtwvif_link->mac_idx; u16 set = mac->muedca_ctrl.mask; u32 reg; - u32 ret; + int ret; ret = rtw89_mac_check_mac_en(rtwdev, mac_idx, RTW89_CMAC_SEL); if (ret) @@ -6765,7 +6880,7 @@ int rtw89_mac_cpu_io_rx(struct rtw89_dev *rtwdev, bool wow_enable) { struct rtw89_mac_h2c_info h2c_info = {}; struct rtw89_mac_c2h_info c2h_info = {}; - u32 ret; + int ret; if (RTW89_CHK_FW_FEATURE(NO_WOW_CPU_IO_RX, &rtwdev->fw)) return 0; @@ -6843,10 +6958,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 +6990,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..25fe5e5c8a97 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 @@ -416,6 +419,7 @@ enum rtw89_mac_c2h_info_func { RTW89_MAC_C2H_FUNC_DONE_ACK, RTW89_MAC_C2H_FUNC_C2H_LOG, RTW89_MAC_C2H_FUNC_BCN_CNT, + RTW89_MAC_C2H_FUNC_BCN_UPD_DONE = 0x06, RTW89_MAC_C2H_FUNC_INFO_MAX, }; @@ -469,6 +473,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 +926,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 +936,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 +946,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 +961,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 +982,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 +1585,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..7b04183a3a5d 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; } @@ -1757,6 +1837,40 @@ static void rtw89_set_rekey_data(struct ieee80211_hw *hw, } #endif +static int rtw89_ops_get_survey(struct ieee80211_hw *hw, int idx, + struct survey_info *survey) +{ + struct ieee80211_conf *conf = &hw->conf; + struct rtw89_dev *rtwdev = hw->priv; + struct rtw89_bb_ctx *bb; + + if (idx == 0) { + survey->channel = conf->chandef.chan; + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = RTW89_NOISE_DEFAULT; + + return 0; + } + + rtw89_for_each_active_bb(rtwdev, bb) { + struct rtw89_env_monitor_info *env = &bb->env_monitor; + struct rtw89_nhm_report *rpt; + + rpt = list_first_entry_or_null(&env->nhm_rpt_list, typeof(*rpt), list); + if (!rpt) + continue; + + survey->filled = SURVEY_INFO_NOISE_DBM; + survey->noise = rpt->noise - MAX_RSSI; + survey->channel = rpt->channel; + list_del_init(&rpt->list); + + return 0; + } + + return -EINVAL; +} + static void rtw89_ops_rfkill_poll(struct ieee80211_hw *hw) { struct rtw89_dev *rtwdev = hw->priv; @@ -1789,6 +1903,7 @@ const struct ieee80211_ops rtw89_ops = { .sta_state = rtw89_ops_sta_state, .set_key = rtw89_ops_set_key, .ampdu_action = rtw89_ops_ampdu_action, + .get_survey = rtw89_ops_get_survey, .set_rts_threshold = rtw89_ops_set_rts_threshold, .sta_statistics = rtw89_ops_sta_statistics, .flush = rtw89_ops_flush, @@ -1805,6 +1920,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..ef69672b6862 100644 --- a/drivers/net/wireless/realtek/rtw89/mac_be.c +++ b/drivers/net/wireless/realtek/rtw89/mac_be.c @@ -56,6 +56,7 @@ static const struct rtw89_port_reg rtw89_port_base_be = { .ptcl_dbg = R_BE_PTCL_DBG, .ptcl_dbg_info = R_BE_PTCL_DBG_INFO, .bcn_drop_all = R_BE_BCN_DROP_ALL0, + .bcn_psr_rpt = R_BE_BCN_PSR_RPT_P0, .hiq_win = {R_BE_P0MB_HGQ_WINDOW_CFG_0, R_BE_PORT_HGQ_WINDOW_CFG, R_BE_PORT_HGQ_WINDOW_CFG + 1, R_BE_PORT_HGQ_WINDOW_CFG + 2, R_BE_PORT_HGQ_WINDOW_CFG + 3}, @@ -2567,6 +2568,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..0ee5f8579447 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.c +++ b/drivers/net/wireless/realtek/rtw89/pci.c @@ -134,7 +134,7 @@ static void rtw89_pci_release_fwcmd(struct rtw89_dev *rtwdev, static void rtw89_pci_reclaim_tx_fwcmd(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) { - struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12]; + struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[RTW89_TXCH_CH12]; u32 cnt; cnt = rtw89_pci_txbd_recalc(rtwdev, tx_ring); @@ -440,7 +440,7 @@ static int rtw89_pci_poll_rxq_dma(struct rtw89_dev *rtwdev, int countdown = rtwdev->napi_budget_countdown; u32 cnt; - rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ]; + rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RXQ]; cnt = rtw89_pci_rxbd_recalc(rtwdev, rx_ring); if (!cnt) @@ -464,7 +464,8 @@ static void rtw89_pci_tx_status(struct rtw89_dev *rtwdev, struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb); struct ieee80211_tx_info *info; - rtw89_core_tx_wait_complete(rtwdev, skb_data, tx_status == RTW89_TX_DONE); + if (rtw89_core_tx_wait_complete(rtwdev, skb_data, tx_status == RTW89_TX_DONE)) + return; info = IEEE80211_SKB_CB(skb); ieee80211_tx_info_clear_status(info); @@ -568,31 +569,52 @@ static void rtw89_pci_release_txwd_skb(struct rtw89_dev *rtwdev, rtw89_pci_enqueue_txwd(tx_ring, txwd); } -static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev, - struct rtw89_pci_rpp_fmt *rpp) +void rtw89_pci_parse_rpp(struct rtw89_dev *rtwdev, void *_rpp, + struct rtw89_pci_rpp_info *rpp_info) +{ + const struct rtw89_pci_rpp_fmt *rpp = _rpp; + + rpp_info->seq = le32_get_bits(rpp->dword, RTW89_PCI_RPP_SEQ); + rpp_info->qsel = le32_get_bits(rpp->dword, RTW89_PCI_RPP_QSEL); + rpp_info->tx_status = le32_get_bits(rpp->dword, RTW89_PCI_RPP_TX_STATUS); + rpp_info->txch = rtw89_chip_get_ch_dma(rtwdev, rpp_info->qsel); +} +EXPORT_SYMBOL(rtw89_pci_parse_rpp); + +void rtw89_pci_parse_rpp_v1(struct rtw89_dev *rtwdev, void *_rpp, + struct rtw89_pci_rpp_info *rpp_info) +{ + const struct rtw89_pci_rpp_fmt_v1 *rpp = _rpp; + + rpp_info->seq = le32_get_bits(rpp->w0, RTW89_PCI_RPP_W0_PCIE_SEQ_V1_MASK); + rpp_info->qsel = le32_get_bits(rpp->w1, RTW89_PCI_RPP_W1_QSEL_V1_MASK); + rpp_info->tx_status = le32_get_bits(rpp->w0, RTW89_PCI_RPP_W0_TX_STATUS_V1_MASK); + rpp_info->txch = le32_get_bits(rpp->w0, RTW89_PCI_RPP_W0_DMA_CH_MASK); +} +EXPORT_SYMBOL(rtw89_pci_parse_rpp_v1); + +static void rtw89_pci_release_rpp(struct rtw89_dev *rtwdev, void *rpp) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; - struct rtw89_pci_tx_ring *tx_ring; + const struct rtw89_pci_info *info = rtwdev->pci_info; + struct rtw89_pci_rpp_info rpp_info = {}; struct rtw89_pci_tx_wd_ring *wd_ring; + struct rtw89_pci_tx_ring *tx_ring; struct rtw89_pci_tx_wd *txwd; - u16 seq; - u8 qsel, tx_status, txch; - seq = le32_get_bits(rpp->dword, RTW89_PCI_RPP_SEQ); - qsel = le32_get_bits(rpp->dword, RTW89_PCI_RPP_QSEL); - tx_status = le32_get_bits(rpp->dword, RTW89_PCI_RPP_TX_STATUS); - txch = rtw89_core_get_ch_dma(rtwdev, qsel); + info->parse_rpp(rtwdev, rpp, &rpp_info); - if (txch == RTW89_TXCH_CH12) { + if (rpp_info.txch == RTW89_TXCH_CH12) { rtw89_warn(rtwdev, "should no fwcmd release report\n"); return; } - tx_ring = &rtwpci->tx_rings[txch]; + tx_ring = &rtwpci->tx.rings[rpp_info.txch]; wd_ring = &tx_ring->wd_ring; - txwd = &wd_ring->pages[seq]; + txwd = &wd_ring->pages[rpp_info.seq]; - rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, seq, tx_status); + rtw89_pci_release_txwd_skb(rtwdev, tx_ring, txwd, rpp_info.seq, + rpp_info.tx_status); } static void rtw89_pci_release_pending_txwd_skb(struct rtw89_dev *rtwdev, @@ -617,13 +639,14 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev, u32 max_cnt) { struct rtw89_pci_dma_ring *bd_ring = &rx_ring->bd_ring; - struct rtw89_pci_rx_info *rx_info; - struct rtw89_pci_rpp_fmt *rpp; + const struct rtw89_pci_info *info = rtwdev->pci_info; struct rtw89_rx_desc_info desc_info = {}; + struct rtw89_pci_rx_info *rx_info; struct sk_buff *skb; - u32 cnt = 0; - u32 rpp_size = sizeof(struct rtw89_pci_rpp_fmt); + void *rpp; u32 rxinfo_size = sizeof(struct rtw89_pci_rxbd_info); + u32 rpp_size = info->rpp_fmt_size; + u32 cnt = 0; u32 skb_idx; u32 offset; int ret; @@ -649,7 +672,7 @@ static u32 rtw89_pci_release_tx_skbs(struct rtw89_dev *rtwdev, /* first segment has RX desc */ offset = desc_info.offset + desc_info.rxd_len; for (; offset + rpp_size <= rx_info->len; offset += rpp_size) { - rpp = (struct rtw89_pci_rpp_fmt *)(skb->data + offset); + rpp = skb->data + offset; rtw89_pci_release_rpp(rtwdev, rpp); } @@ -694,7 +717,7 @@ static int rtw89_pci_poll_rpq_dma(struct rtw89_dev *rtwdev, u32 cnt; int work_done; - rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; + rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RPQ]; spin_lock_bh(&rtwpci->trx_lock); @@ -724,7 +747,7 @@ static void rtw89_pci_isr_rxd_unavail(struct rtw89_dev *rtwdev, int i; for (i = 0; i < RTW89_RXCH_NUM; i++) { - rx_ring = &rtwpci->rx_rings[i]; + rx_ring = &rtwpci->rx.rings[i]; bd_ring = &rx_ring->bd_ring; reg_idx = rtw89_read32(rtwdev, bd_ring->addr.idx); @@ -797,6 +820,29 @@ void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v2); +void rtw89_pci_recognize_intrs_v3(struct rtw89_dev *rtwdev, + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs) +{ + isrs->ind_isrs = rtw89_read32(rtwdev, R_BE_PCIE_HISR) & rtwpci->ind_intrs; + isrs->halt_c2h_isrs = isrs->ind_isrs & B_BE_HS0ISR_IND_INT ? + rtw89_read32(rtwdev, R_BE_HISR0) & rtwpci->halt_c2h_intrs : 0; + isrs->isrs[1] = rtw89_read32(rtwdev, R_BE_PCIE_DMA_ISR) & rtwpci->intrs[1]; + + /* isrs[0] is not used, so borrow to store RDU status to share common + * flow in rtw89_pci_interrupt_threadfn(). + */ + isrs->isrs[0] = isrs->isrs[1] & (B_BE_PCIE_RDU_CH1_INT | + B_BE_PCIE_RDU_CH0_INT); + + if (isrs->halt_c2h_isrs) + rtw89_write32(rtwdev, R_BE_HISR0, isrs->halt_c2h_isrs); + if (isrs->isrs[1]) + rtw89_write32(rtwdev, R_BE_PCIE_DMA_ISR, isrs->isrs[1]); + rtw89_write32(rtwdev, R_BE_PCIE_HISR, isrs->ind_isrs); +} +EXPORT_SYMBOL(rtw89_pci_recognize_intrs_v3); + void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) { rtw89_write32(rtwdev, R_AX_HIMR0, rtwpci->halt_c2h_intrs); @@ -844,6 +890,21 @@ void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpc } EXPORT_SYMBOL(rtw89_pci_disable_intr_v2); +void rtw89_pci_enable_intr_v3(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) +{ + rtw89_write32(rtwdev, R_BE_HIMR0, rtwpci->halt_c2h_intrs); + rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, rtwpci->intrs[1]); + rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, rtwpci->ind_intrs); +} +EXPORT_SYMBOL(rtw89_pci_enable_intr_v3); + +void rtw89_pci_disable_intr_v3(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci) +{ + rtw89_write32(rtwdev, R_BE_PCIE_HIMR0, 0); + rtw89_write32(rtwdev, R_BE_PCIE_DMA_IMR_0_V1, 0); +} +EXPORT_SYMBOL(rtw89_pci_disable_intr_v3); + static void rtw89_pci_ops_recovery_start(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; @@ -885,7 +946,7 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) struct rtw89_dev *rtwdev = dev; struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; const struct rtw89_pci_info *info = rtwdev->pci_info; - const struct rtw89_pci_gen_def *gen_def = info->gen_def; + const struct rtw89_pci_isr_def *isr_def = info->isr_def; struct rtw89_pci_isrs isrs; unsigned long flags; @@ -893,13 +954,13 @@ static irqreturn_t rtw89_pci_interrupt_threadfn(int irq, void *dev) rtw89_chip_recognize_intrs(rtwdev, rtwpci, &isrs); spin_unlock_irqrestore(&rtwpci->irq_lock, flags); - if (unlikely(isrs.isrs[0] & gen_def->isr_rdu)) + if (unlikely(isrs.isrs[0] & isr_def->isr_rdu)) rtw89_pci_isr_rxd_unavail(rtwdev, rtwpci); - if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_halt_c2h)) + if (unlikely(isrs.halt_c2h_isrs & isr_def->isr_halt_c2h)) rtw89_ser_notify(rtwdev, rtw89_mac_get_err_status(rtwdev)); - if (unlikely(isrs.halt_c2h_isrs & gen_def->isr_wdt_timeout)) + if (unlikely(isrs.halt_c2h_isrs & isr_def->isr_wdt_timeout)) rtw89_ser_notify(rtwdev, MAC_AX_ERR_L2_ERR_WDT_TIMEOUT_INT); if (unlikely(rtwpci->under_recovery)) @@ -950,6 +1011,24 @@ exit: return irqret; } +#define DEF_TXCHADDRS_TYPE3(gen, ch_idx, txch, v...) \ + [RTW89_TXCH_##ch_idx] = { \ + .num = R_##gen##_##txch##_TXBD_CFG, \ + .idx = R_##gen##_##txch##_TXBD_IDX ##v, \ + .bdram = 0, \ + .desa_l = 0, \ + .desa_h = 0, \ + } + +#define DEF_TXCHADDRS_TYPE3_GRP_BASE(gen, ch_idx, txch, grp, v...) \ + [RTW89_TXCH_##ch_idx] = { \ + .num = R_##gen##_##txch##_TXBD_CFG, \ + .idx = R_##gen##_##txch##_TXBD_IDX ##v, \ + .bdram = 0, \ + .desa_l = R_##gen##_##grp##_TXBD_DESA_L, \ + .desa_h = R_##gen##_##grp##_TXBD_DESA_H, \ + } + #define DEF_TXCHADDRS_TYPE2(gen, ch_idx, txch, v...) \ [RTW89_TXCH_##ch_idx] = { \ .num = R_##gen##_##txch##_TXBD_NUM ##v, \ @@ -977,6 +1056,22 @@ exit: .desa_h = R_AX_##txch##_TXBD_DESA_H ##v, \ } +#define DEF_RXCHADDRS_TYPE3(gen, ch_idx, rxch, v...) \ + [RTW89_RXCH_##ch_idx] = { \ + .num = R_##gen##_RX_##rxch##_RXBD_CONFIG, \ + .idx = R_##gen##_##ch_idx##0_RXBD_IDX ##v, \ + .desa_l = 0, \ + .desa_h = 0, \ + } + +#define DEF_RXCHADDRS_TYPE3_GRP_BASE(gen, ch_idx, rxch, grp, v...) \ + [RTW89_RXCH_##ch_idx] = { \ + .num = R_##gen##_RX_##rxch##_RXBD_CONFIG, \ + .idx = R_##gen##_##ch_idx##0_RXBD_IDX ##v, \ + .desa_l = R_##gen##_##grp##_RXBD_DESA_L, \ + .desa_h = R_##gen##_##grp##_RXBD_DESA_H, \ + } + #define DEF_RXCHADDRS(gen, ch_idx, rxch, v...) \ [RTW89_RXCH_##ch_idx] = { \ .num = R_##gen##_##rxch##_RXBD_NUM ##v, \ @@ -1054,8 +1149,36 @@ const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be = { }; EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be); +const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be_v1 = { + .tx = { + DEF_TXCHADDRS_TYPE3_GRP_BASE(BE, ACH0, CH0, ACQ, _V1), + /* no CH1 */ + DEF_TXCHADDRS_TYPE3(BE, ACH2, CH2, _V1), + /* no CH3 */ + DEF_TXCHADDRS_TYPE3(BE, ACH4, CH4, _V1), + /* no CH5 */ + DEF_TXCHADDRS_TYPE3(BE, ACH6, CH6, _V1), + /* no CH7 */ + DEF_TXCHADDRS_TYPE3_GRP_BASE(BE, CH8, CH8, NACQ, _V1), + /* no CH9 */ + DEF_TXCHADDRS_TYPE3(BE, CH10, CH10, _V1), + /* no CH11 */ + DEF_TXCHADDRS_TYPE3(BE, CH12, CH12, _V1), + }, + .rx = { + DEF_RXCHADDRS_TYPE3_GRP_BASE(BE, RXQ, CH0, HOST0, _V1), + DEF_RXCHADDRS_TYPE3(BE, RPQ, CH1, _V1), + }, +}; +EXPORT_SYMBOL(rtw89_pci_ch_dma_addr_set_be_v1); + +#undef DEF_TXCHADDRS_TYPE3 +#undef DEF_TXCHADDRS_TYPE3_GRP_BASE +#undef DEF_TXCHADDRS_TYPE2 #undef DEF_TXCHADDRS_TYPE1 #undef DEF_TXCHADDRS +#undef DEF_RXCHADDRS_TYPE3 +#undef DEF_RXCHADDRS_TYPE3_GRP_BASE #undef DEF_RXCHADDRS static int rtw89_pci_get_txch_addrs(struct rtw89_dev *rtwdev, @@ -1101,7 +1224,7 @@ static u32 __rtw89_pci_check_and_reclaim_tx_fwcmd_resource(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; - struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[RTW89_TXCH_CH12]; + struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[RTW89_TXCH_CH12]; u32 cnt; spin_lock_bh(&rtwpci->trx_lock); @@ -1117,7 +1240,7 @@ u32 __rtw89_pci_check_and_reclaim_tx_resource_noio(struct rtw89_dev *rtwdev, u8 txch) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; - struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; + struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[txch]; struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; u32 cnt; @@ -1134,7 +1257,7 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, u8 txch) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; - struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; + struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[txch]; struct rtw89_pci_tx_wd_ring *wd_ring = &tx_ring->wd_ring; const struct rtw89_chip_info *chip = rtwdev->chip; u32 bd_cnt, wd_cnt, min_cnt = 0; @@ -1142,7 +1265,7 @@ static u32 __rtw89_pci_check_and_reclaim_tx_resource(struct rtw89_dev *rtwdev, enum rtw89_debug_mask debug_mask; u32 cnt; - rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; + rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RPQ]; spin_lock_bh(&rtwpci->trx_lock); bd_cnt = rtw89_pci_get_avail_txbd_num(tx_ring); @@ -1227,7 +1350,7 @@ static void rtw89_pci_tx_bd_ring_update(struct rtw89_dev *rtwdev, struct rtw89_p static void rtw89_pci_ops_tx_kick_off(struct rtw89_dev *rtwdev, u8 txch) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; - struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; + struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[txch]; if (rtwdev->hci.paused) { set_bit(txch, rtwpci->kick_map); @@ -1247,7 +1370,7 @@ static void rtw89_pci_tx_kick_off_pending(struct rtw89_dev *rtwdev) if (!test_and_clear_bit(txch, rtwpci->kick_map)) continue; - tx_ring = &rtwpci->tx_rings[txch]; + tx_ring = &rtwpci->tx.rings[txch]; __rtw89_pci_tx_kick_off(rtwdev, tx_ring); } } @@ -1255,7 +1378,7 @@ static void rtw89_pci_tx_kick_off_pending(struct rtw89_dev *rtwdev) static void __pci_flush_txch(struct rtw89_dev *rtwdev, u8 txch, bool drop) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; - struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx_rings[txch]; + struct rtw89_pci_tx_ring *tx_ring = &rtwpci->tx.rings[txch]; struct rtw89_pci_dma_ring *bd_ring = &tx_ring->bd_ring; u32 cur_idx, cur_rp; u8 i; @@ -1371,7 +1494,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev, struct pci_dev *pdev = rtwpci->pdev; struct sk_buff *skb = tx_req->skb; struct rtw89_pci_tx_data *tx_data = RTW89_PCI_TX_SKB_CB(skb); - struct rtw89_tx_skb_data *skb_data = RTW89_TX_SKB_CB(skb); bool en_wd_info = desc_info->en_wd_info; u32 txwd_len; u32 txwp_len; @@ -1387,7 +1509,6 @@ static int rtw89_pci_txwd_submit(struct rtw89_dev *rtwdev, } tx_data->dma = dma; - rcu_assign_pointer(skb_data->wait, NULL); txwp_len = sizeof(*txwp_info); txwd_len = chip->txwd_body_size; @@ -1521,7 +1642,7 @@ static int rtw89_pci_tx_write(struct rtw89_dev *rtwdev, struct rtw89_core_tx_req return -EINVAL; } - tx_ring = &rtwpci->tx_rings[txch]; + tx_ring = &rtwpci->tx.rings[txch]; spin_lock_bh(&rtwpci->trx_lock); n_avail_txbd = rtw89_pci_get_avail_txbd_num(tx_ring); @@ -1607,6 +1728,41 @@ static void rtw89_pci_init_wp_16sel(struct rtw89_dev *rtwdev) } } +static u16 rtw89_pci_enc_bd_cfg(struct rtw89_dev *rtwdev, u16 bd_num, + u32 dma_offset) +{ + u16 dma_offset_sel; + u16 num_sel; + + /* B_BE_TX_NUM_SEL_MASK, B_BE_RX_NUM_SEL_MASK: + * 0 -> 0 + * 1 -> 64 = 2^6 + * 2 -> 128 = 2^7 + * ... + * 7 -> 4096 = 2^12 + */ + num_sel = ilog2(bd_num) - 5; + + if (hweight16(bd_num) != 1) + rtw89_warn(rtwdev, "bd_num %u is not power of 2\n", bd_num); + + /* B_BE_TX_START_OFFSET_MASK, B_BE_RX_START_OFFSET_MASK: + * 0 -> 0 = 0 * 2^9 + * 1 -> 512 = 1 * 2^9 + * 2 -> 1024 = 2 * 2^9 + * 3 -> 1536 = 3 * 2^9 + * ... + * 255 -> 130560 = 255 * 2^9 + */ + dma_offset_sel = dma_offset >> 9; + + if (dma_offset % 512) + rtw89_warn(rtwdev, "offset %u is not multiple of 512\n", dma_offset); + + return u16_encode_bits(num_sel, B_BE_TX_NUM_SEL_MASK) | + u16_encode_bits(dma_offset_sel, B_BE_TX_START_OFFSET_MASK); +} + static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; @@ -1616,10 +1772,12 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) struct rtw89_pci_rx_ring *rx_ring; struct rtw89_pci_dma_ring *bd_ring; const struct rtw89_pci_bd_ram *bd_ram; + dma_addr_t group_dma_base = 0; + u16 num_or_offset; + u32 addr_desa_l; + u32 addr_bdram; u32 addr_num; u32 addr_idx; - u32 addr_bdram; - u32 addr_desa_l; u32 val32; int i; @@ -1627,7 +1785,7 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) if (info->tx_dma_ch_mask & BIT(i)) continue; - tx_ring = &rtwpci->tx_rings[i]; + tx_ring = &rtwpci->tx.rings[i]; bd_ring = &tx_ring->bd_ring; bd_ram = bd_ram_table ? &bd_ram_table[i] : NULL; addr_num = bd_ring->addr.num; @@ -1636,7 +1794,18 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) bd_ring->wp = 0; bd_ring->rp = 0; - rtw89_write16(rtwdev, addr_num, bd_ring->len); + if (info->group_bd_addr) { + if (addr_desa_l) + group_dma_base = bd_ring->dma; + + num_or_offset = + rtw89_pci_enc_bd_cfg(rtwdev, bd_ring->len, + bd_ring->dma - group_dma_base); + } else { + num_or_offset = bd_ring->len; + } + rtw89_write16(rtwdev, addr_num, num_or_offset); + if (addr_bdram && bd_ram) { val32 = FIELD_PREP(BDRAM_SIDX_MASK, bd_ram->start_idx) | FIELD_PREP(BDRAM_MAX_MASK, bd_ram->max_num) | @@ -1644,12 +1813,14 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, addr_bdram, val32); } - rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); - rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma)); + if (addr_desa_l) { + rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); + rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma)); + } } for (i = 0; i < RTW89_RXCH_NUM; i++) { - rx_ring = &rtwpci->rx_rings[i]; + rx_ring = &rtwpci->rx.rings[i]; bd_ring = &rx_ring->bd_ring; addr_num = bd_ring->addr.num; addr_idx = bd_ring->addr.idx; @@ -1663,9 +1834,22 @@ static void rtw89_pci_reset_trx_rings(struct rtw89_dev *rtwdev) rx_ring->diliver_desc.ready = false; rx_ring->target_rx_tag = 0; - rtw89_write16(rtwdev, addr_num, bd_ring->len); - rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); - rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma)); + if (info->group_bd_addr) { + if (addr_desa_l) + group_dma_base = bd_ring->dma; + + num_or_offset = + rtw89_pci_enc_bd_cfg(rtwdev, bd_ring->len, + bd_ring->dma - group_dma_base); + } else { + num_or_offset = bd_ring->len; + } + rtw89_write16(rtwdev, addr_num, num_or_offset); + + if (addr_desa_l) { + rtw89_write32(rtwdev, addr_desa_l, bd_ring->dma); + rtw89_write32(rtwdev, addr_desa_l + 4, upper_32_bits(bd_ring->dma)); + } if (info->rx_ring_eq_is_full) rtw89_write16(rtwdev, addr_idx, bd_ring->wp); @@ -1698,7 +1882,7 @@ void rtw89_pci_ops_reset(struct rtw89_dev *rtwdev) skb_queue_len(&rtwpci->h2c_queue), true); continue; } - rtw89_pci_release_tx_ring(rtwdev, &rtwpci->tx_rings[txch]); + rtw89_pci_release_tx_ring(rtwdev, &rtwpci->tx.rings[txch]); } spin_unlock_bh(&rtwpci->trx_lock); } @@ -1774,14 +1958,14 @@ void rtw89_pci_switch_bd_idx_addr(struct rtw89_dev *rtwdev, bool low_power) return; for (i = 0; i < RTW89_TXCH_NUM; i++) { - tx_ring = &rtwpci->tx_rings[i]; + tx_ring = &rtwpci->tx.rings[i]; tx_ring->bd_ring.addr.idx = low_power ? bd_idx_addr->tx_bd_addrs[i] : dma_addr_set->tx[i].idx; } for (i = 0; i < RTW89_RXCH_NUM; i++) { - rx_ring = &rtwpci->rx_rings[i]; + rx_ring = &rtwpci->rx.rings[i]; rx_ring->bd_ring.addr.idx = low_power ? bd_idx_addr->rx_bd_addrs[i] : dma_addr_set->rx[i].idx; @@ -2638,6 +2822,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); @@ -2721,7 +2909,7 @@ static int rtw89_pci_poll_rxdma_ch_idle_ax(struct rtw89_dev *rtwdev) static int rtw89_pci_poll_dma_all_idle(struct rtw89_dev *rtwdev) { - u32 ret; + int ret; ret = rtw89_pci_poll_txdma_ch_idle_ax(rtwdev); if (ret) { @@ -3207,15 +3395,6 @@ static void rtw89_pci_free_tx_ring(struct rtw89_dev *rtwdev, struct pci_dev *pdev, struct rtw89_pci_tx_ring *tx_ring) { - int ring_sz; - u8 *head; - dma_addr_t dma; - - head = tx_ring->bd_ring.head; - dma = tx_ring->bd_ring.dma; - ring_sz = tx_ring->bd_ring.desc_size * tx_ring->bd_ring.len; - dma_free_coherent(&pdev->dev, ring_sz, head, dma); - tx_ring->bd_ring.head = NULL; } @@ -3223,6 +3402,7 @@ static void rtw89_pci_free_tx_rings(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct rtw89_pci_dma_pool *bd_pool = &rtwpci->tx.bd_pool; const struct rtw89_pci_info *info = rtwdev->pci_info; struct rtw89_pci_tx_ring *tx_ring; int i; @@ -3230,10 +3410,12 @@ static void rtw89_pci_free_tx_rings(struct rtw89_dev *rtwdev, for (i = 0; i < RTW89_TXCH_NUM; i++) { if (info->tx_dma_ch_mask & BIT(i)) continue; - tx_ring = &rtwpci->tx_rings[i]; + tx_ring = &rtwpci->tx.rings[i]; rtw89_pci_free_tx_wd_ring(rtwdev, pdev, tx_ring); rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring); } + + dma_free_coherent(&pdev->dev, bd_pool->size, bd_pool->head, bd_pool->dma); } static void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev, @@ -3244,8 +3426,6 @@ static void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev, struct sk_buff *skb; dma_addr_t dma; u32 buf_sz; - u8 *head; - int ring_sz = rx_ring->bd_ring.desc_size * rx_ring->bd_ring.len; int i; buf_sz = rx_ring->buf_sz; @@ -3261,10 +3441,6 @@ static void rtw89_pci_free_rx_ring(struct rtw89_dev *rtwdev, rx_ring->buf[i] = NULL; } - head = rx_ring->bd_ring.head; - dma = rx_ring->bd_ring.dma; - dma_free_coherent(&pdev->dev, ring_sz, head, dma); - rx_ring->bd_ring.head = NULL; } @@ -3272,13 +3448,16 @@ static void rtw89_pci_free_rx_rings(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct rtw89_pci_dma_pool *bd_pool = &rtwpci->rx.bd_pool; struct rtw89_pci_rx_ring *rx_ring; int i; for (i = 0; i < RTW89_RXCH_NUM; i++) { - rx_ring = &rtwpci->rx_rings[i]; + rx_ring = &rtwpci->rx.rings[i]; rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring); } + + dma_free_coherent(&pdev->dev, bd_pool->size, bd_pool->head, bd_pool->dma); } static void rtw89_pci_free_trx_rings(struct rtw89_dev *rtwdev, @@ -3370,12 +3549,10 @@ static int rtw89_pci_alloc_tx_ring(struct rtw89_dev *rtwdev, struct pci_dev *pdev, struct rtw89_pci_tx_ring *tx_ring, u32 desc_size, u32 len, - enum rtw89_tx_channel txch) + enum rtw89_tx_channel txch, + void *head, dma_addr_t dma) { const struct rtw89_pci_ch_dma_addr *txch_addr; - int ring_sz = desc_size * len; - u8 *head; - dma_addr_t dma; int ret; ret = rtw89_pci_alloc_tx_wd_ring(rtwdev, pdev, tx_ring, txch); @@ -3390,12 +3567,6 @@ static int rtw89_pci_alloc_tx_ring(struct rtw89_dev *rtwdev, goto err_free_wd_ring; } - head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL); - if (!head) { - ret = -ENOMEM; - goto err_free_wd_ring; - } - INIT_LIST_HEAD(&tx_ring->busy_pages); tx_ring->bd_ring.head = head; tx_ring->bd_ring.dma = dma; @@ -3418,25 +3589,48 @@ static int rtw89_pci_alloc_tx_rings(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct rtw89_pci_dma_pool *bd_pool = &rtwpci->tx.bd_pool; const struct rtw89_pci_info *info = rtwdev->pci_info; struct rtw89_pci_tx_ring *tx_ring; + u32 i, tx_allocated; + dma_addr_t dma; u32 desc_size; + u32 ring_sz; + u32 pool_sz; + u32 ch_num; + void *head; u32 len; - u32 i, tx_allocated; int ret; + BUILD_BUG_ON(RTW89_PCI_TXBD_NUM_MAX % 16); + + desc_size = sizeof(struct rtw89_pci_tx_bd_32); + len = RTW89_PCI_TXBD_NUM_MAX; + ch_num = RTW89_TXCH_NUM - hweight32(info->tx_dma_ch_mask); + ring_sz = desc_size * len; + pool_sz = ring_sz * ch_num; + + head = dma_alloc_coherent(&pdev->dev, pool_sz, &dma, GFP_KERNEL); + if (!head) + return -ENOMEM; + + bd_pool->head = head; + bd_pool->dma = dma; + bd_pool->size = pool_sz; + for (i = 0; i < RTW89_TXCH_NUM; i++) { if (info->tx_dma_ch_mask & BIT(i)) continue; - tx_ring = &rtwpci->tx_rings[i]; - desc_size = sizeof(struct rtw89_pci_tx_bd_32); - len = RTW89_PCI_TXBD_NUM_MAX; + tx_ring = &rtwpci->tx.rings[i]; ret = rtw89_pci_alloc_tx_ring(rtwdev, pdev, tx_ring, - desc_size, len, i); + desc_size, len, i, head, dma); if (ret) { rtw89_err(rtwdev, "failed to alloc tx ring %d\n", i); goto err_free; } + + head += ring_sz; + dma += ring_sz; } return 0; @@ -3444,24 +3638,24 @@ static int rtw89_pci_alloc_tx_rings(struct rtw89_dev *rtwdev, err_free: tx_allocated = i; for (i = 0; i < tx_allocated; i++) { - tx_ring = &rtwpci->tx_rings[i]; + tx_ring = &rtwpci->tx.rings[i]; rtw89_pci_free_tx_ring(rtwdev, pdev, tx_ring); } + dma_free_coherent(&pdev->dev, bd_pool->size, bd_pool->head, bd_pool->dma); + return ret; } static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, struct pci_dev *pdev, struct rtw89_pci_rx_ring *rx_ring, - u32 desc_size, u32 len, u32 rxch) + u32 desc_size, u32 len, u32 rxch, + void *head, dma_addr_t dma) { const struct rtw89_pci_info *info = rtwdev->pci_info; const struct rtw89_pci_ch_dma_addr *rxch_addr; struct sk_buff *skb; - u8 *head; - dma_addr_t dma; - int ring_sz = desc_size * len; int buf_sz = RTW89_PCI_RX_BUF_SIZE; int i, allocated; int ret; @@ -3472,12 +3666,6 @@ static int rtw89_pci_alloc_rx_ring(struct rtw89_dev *rtwdev, return ret; } - head = dma_alloc_coherent(&pdev->dev, ring_sz, &dma, GFP_KERNEL); - if (!head) { - ret = -ENOMEM; - goto err; - } - rx_ring->bd_ring.head = head; rx_ring->bd_ring.dma = dma; rx_ring->bd_ring.len = len; @@ -3526,12 +3714,8 @@ err_free: rx_ring->buf[i] = NULL; } - head = rx_ring->bd_ring.head; - dma = rx_ring->bd_ring.dma; - dma_free_coherent(&pdev->dev, ring_sz, head, dma); - rx_ring->bd_ring.head = NULL; -err: + return ret; } @@ -3539,22 +3723,43 @@ static int rtw89_pci_alloc_rx_rings(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + struct rtw89_pci_dma_pool *bd_pool = &rtwpci->rx.bd_pool; struct rtw89_pci_rx_ring *rx_ring; + int i, rx_allocated; + dma_addr_t dma; u32 desc_size; + u32 ring_sz; + u32 pool_sz; + void *head; u32 len; - int i, rx_allocated; int ret; + desc_size = sizeof(struct rtw89_pci_rx_bd_32); + len = RTW89_PCI_RXBD_NUM_MAX; + ring_sz = desc_size * len; + pool_sz = ring_sz * RTW89_RXCH_NUM; + + head = dma_alloc_coherent(&pdev->dev, pool_sz, &dma, GFP_KERNEL); + if (!head) + return -ENOMEM; + + bd_pool->head = head; + bd_pool->dma = dma; + bd_pool->size = pool_sz; + for (i = 0; i < RTW89_RXCH_NUM; i++) { - rx_ring = &rtwpci->rx_rings[i]; - desc_size = sizeof(struct rtw89_pci_rx_bd_32); - len = RTW89_PCI_RXBD_NUM_MAX; + rx_ring = &rtwpci->rx.rings[i]; + ret = rtw89_pci_alloc_rx_ring(rtwdev, pdev, rx_ring, - desc_size, len, i); + desc_size, len, i, + head, dma); if (ret) { rtw89_err(rtwdev, "failed to alloc rx ring %d\n", i); goto err_free; } + + head += ring_sz; + dma += ring_sz; } return 0; @@ -3562,10 +3767,12 @@ static int rtw89_pci_alloc_rx_rings(struct rtw89_dev *rtwdev, err_free: rx_allocated = i; for (i = 0; i < rx_allocated; i++) { - rx_ring = &rtwpci->rx_rings[i]; + rx_ring = &rtwpci->rx.rings[i]; rtw89_pci_free_rx_ring(rtwdev, pdev, rx_ring); } + dma_free_coherent(&pdev->dev, bd_pool->size, bd_pool->head, bd_pool->dma); + return ret; } @@ -3772,6 +3979,40 @@ void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev) } EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v2); +static void rtw89_pci_recovery_intr_mask_v3(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = 0; + rtwpci->intrs[1] = 0; +} + +static void rtw89_pci_default_intr_mask_v3(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + rtwpci->ind_intrs = B_BE_HS0_IND_INT_EN0; + rtwpci->halt_c2h_intrs = B_BE_HALT_C2H_INT_EN | B_BE_WDT_TIMEOUT_INT_EN; + rtwpci->intrs[0] = 0; + rtwpci->intrs[1] = B_BE_PCIE_RDU_CH1_IMR | + B_BE_PCIE_RDU_CH0_IMR | + B_BE_PCIE_RX_RX0P2_IMR0_V1 | + B_BE_PCIE_RX_RPQ0_IMR0_V1; +} + +void rtw89_pci_config_intr_mask_v3(struct rtw89_dev *rtwdev) +{ + struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; + + if (rtwpci->under_recovery) + rtw89_pci_recovery_intr_mask_v3(rtwdev); + else + rtw89_pci_default_intr_mask_v3(rtwdev); +} +EXPORT_SYMBOL(rtw89_pci_config_intr_mask_v3); + static int rtw89_pci_request_irq(struct rtw89_dev *rtwdev, struct pci_dev *pdev) { @@ -4154,7 +4395,7 @@ static int rtw89_pci_lv1rst_stop_dma_ax(struct rtw89_dev *rtwdev) static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev) { - u32 ret; + int ret; if (rtwdev->chip->chip_id == RTL8852C) return 0; @@ -4168,7 +4409,7 @@ static int rtw89_pci_lv1rst_start_dma_ax(struct rtw89_dev *rtwdev) return ret; rtw89_pci_ctrl_dma_all(rtwdev, true); - return ret; + return 0; } static int rtw89_pci_ops_mac_lv1_recovery(struct rtw89_dev *rtwdev, @@ -4224,18 +4465,18 @@ static int rtw89_pci_napi_poll(struct napi_struct *napi, int budget) struct rtw89_dev *rtwdev = container_of(napi, struct rtw89_dev, napi); struct rtw89_pci *rtwpci = (struct rtw89_pci *)rtwdev->priv; const struct rtw89_pci_info *info = rtwdev->pci_info; - const struct rtw89_pci_gen_def *gen_def = info->gen_def; + const struct rtw89_pci_isr_def *isr_def = info->isr_def; unsigned long flags; int work_done; rtwdev->napi_budget_countdown = budget; - rtw89_write32(rtwdev, gen_def->isr_clear_rpq.addr, gen_def->isr_clear_rpq.data); + rtw89_write32(rtwdev, isr_def->isr_clear_rpq.addr, isr_def->isr_clear_rpq.data); work_done = rtw89_pci_poll_rpq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); if (work_done == budget) return budget; - rtw89_write32(rtwdev, gen_def->isr_clear_rxq.addr, gen_def->isr_clear_rxq.data); + rtw89_write32(rtwdev, isr_def->isr_clear_rxq.addr, isr_def->isr_clear_rxq.data); work_done += rtw89_pci_poll_rxq_dma(rtwdev, rtwpci, rtwdev->napi_budget_countdown); if (work_done < budget && napi_complete_done(napi, work_done)) { spin_lock_irqsave(&rtwpci->irq_lock, flags); @@ -4353,14 +4594,54 @@ 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); -const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { +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_isr_def rtw89_pci_isr_ax = { .isr_rdu = B_AX_RDU_INT, .isr_halt_c2h = B_AX_HALT_C2H_INT_EN, .isr_wdt_timeout = B_AX_WDT_TIMEOUT_INT_EN, .isr_clear_rpq = {R_AX_PCIE_HISR00, B_AX_RPQDMA_INT | B_AX_RPQBD_FULL_INT}, .isr_clear_rxq = {R_AX_PCIE_HISR00, B_AX_RXP1DMA_INT | B_AX_RXDMA_INT | B_AX_RDU_INT}, +}; +EXPORT_SYMBOL(rtw89_pci_isr_ax); +const struct rtw89_pci_gen_def rtw89_pci_gen_ax = { .mac_pre_init = rtw89_pci_ops_mac_pre_init_ax, .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_ax, .mac_post_init = rtw89_pci_ops_mac_post_init_ax, @@ -4449,6 +4730,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..cb05c83dfd56 100644 --- a/drivers/net/wireless/realtek/rtw89/pci.h +++ b/drivers/net/wireless/realtek/rtw89/pci.h @@ -372,6 +372,14 @@ #define B_BE_HS0ISR_IND_INT BIT(0) #define R_BE_PCIE_DMA_IMR_0_V1 0x30B8 +#define B_BE_PCIE_RDU_CH7_IMR BIT(31) +#define B_BE_PCIE_RDU_CH6_IMR BIT(30) +#define B_BE_PCIE_RDU_CH5_IMR BIT(29) +#define B_BE_PCIE_RDU_CH4_IMR BIT(28) +#define B_BE_PCIE_RDU_CH3_IMR BIT(27) +#define B_BE_PCIE_RDU_CH2_IMR BIT(26) +#define B_BE_PCIE_RDU_CH1_IMR BIT(25) +#define B_BE_PCIE_RDU_CH0_IMR BIT(24) #define B_BE_PCIE_RX_RX1P1_IMR0_V1 BIT(23) #define B_BE_PCIE_RX_RX0P1_IMR0_V1 BIT(22) #define B_BE_PCIE_RX_ROQ1_IMR0_V1 BIT(21) @@ -397,6 +405,14 @@ #define B_BE_PCIE_TX_CH0_IMR0 BIT(0) #define R_BE_PCIE_DMA_ISR 0x30BC +#define B_BE_PCIE_RDU_CH7_INT BIT(31) +#define B_BE_PCIE_RDU_CH6_INT BIT(30) +#define B_BE_PCIE_RDU_CH5_INT BIT(29) +#define B_BE_PCIE_RDU_CH4_INT BIT(28) +#define B_BE_PCIE_RDU_CH3_INT BIT(27) +#define B_BE_PCIE_RDU_CH2_INT BIT(26) +#define B_BE_PCIE_RDU_CH1_INT BIT(25) +#define B_BE_PCIE_RDU_CH0_INT BIT(24) #define B_BE_PCIE_RX_RX1P1_ISR_V1 BIT(23) #define B_BE_PCIE_RX_RX0P1_ISR_V1 BIT(22) #define B_BE_PCIE_RX_ROQ1_ISR_V1 BIT(21) @@ -426,9 +442,13 @@ #define B_BE_RDU_CH4_INT_IMR_V1 BIT(29) #define B_BE_RDU_CH3_INT_IMR_V1 BIT(28) #define B_BE_RDU_CH2_INT_IMR_V1 BIT(27) +#define B_BE_RDU_CH1_INT_EN_V2 BIT(27) #define B_BE_RDU_CH1_INT_IMR_V1 BIT(26) +#define B_BE_RDU_CH0_INT_EN_V2 BIT(26) #define B_BE_RDU_CH0_INT_IMR_V1 BIT(25) +#define B_BE_RXDMA_STUCK_INT_EN_V2 BIT(25) #define B_BE_RXDMA_STUCK_INT_EN_V1 BIT(24) +#define B_BE_TXDMA_STUCK_INT_EN_V2 BIT(24) #define B_BE_TXDMA_STUCK_INT_EN_V1 BIT(23) #define B_BE_TXDMA_CH14_INT_EN_V1 BIT(22) #define B_BE_TXDMA_CH13_INT_EN_V1 BIT(21) @@ -459,9 +479,13 @@ #define B_BE_RDU_CH4_INT_V1 BIT(29) #define B_BE_RDU_CH3_INT_V1 BIT(28) #define B_BE_RDU_CH2_INT_V1 BIT(27) +#define B_BE_RDU_CH1_INT_V2 BIT(27) #define B_BE_RDU_CH1_INT_V1 BIT(26) +#define B_BE_RDU_CH0_INT_V2 BIT(26) #define B_BE_RDU_CH0_INT_V1 BIT(25) +#define B_BE_RXDMA_STUCK_INT_V2 BIT(25) #define B_BE_RXDMA_STUCK_INT_V1 BIT(24) +#define B_BE_TXDMA_STUCK_INT_V2 BIT(24) #define B_BE_TXDMA_STUCK_INT_V1 BIT(23) #define B_BE_TXDMA_CH14_INT_V1 BIT(22) #define B_BE_TXDMA_CH13_INT_V1 BIT(21) @@ -784,9 +808,25 @@ #define R_BE_CH13_TXBD_NUM_V1 0xB04C #define R_BE_CH14_TXBD_NUM_V1 0xB04E +#define R_BE_CH0_TXBD_CFG 0xB030 +#define R_BE_CH2_TXBD_CFG 0xB034 +#define R_BE_CH4_TXBD_CFG 0xB038 +#define R_BE_CH6_TXBD_CFG 0xB03C +#define R_BE_CH8_TXBD_CFG 0xB040 +#define R_BE_CH10_TXBD_CFG 0xB044 +#define R_BE_CH12_TXBD_CFG 0xB048 +#define B_BE_TX_FLAG BIT(14) +#define B_BE_TX_START_OFFSET_MASK GENMASK(12, 4) +#define B_BE_TX_NUM_SEL_MASK GENMASK(2, 0) + #define R_BE_RXQ0_RXBD_NUM_V1 0xB050 #define R_BE_RPQ0_RXBD_NUM_V1 0xB052 +#define R_BE_RX_CH0_RXBD_CONFIG 0xB050 +#define R_BE_RX_CH1_RXBD_CONFIG 0xB052 +#define B_BE_RX_START_OFFSET_MASK GENMASK(11, 4) +#define B_BE_RX_NUM_SEL_MASK GENMASK(2, 0) + #define R_BE_CH0_TXBD_IDX_V1 0xB100 #define R_BE_CH1_TXBD_IDX_V1 0xB104 #define R_BE_CH2_TXBD_IDX_V1 0xB108 @@ -837,11 +877,25 @@ #define R_BE_CH14_TXBD_DESA_L_V1 0xB270 #define R_BE_CH14_TXBD_DESA_H_V1 0xB274 +#define R_BE_ACQ_TXBD_DESA_L 0xB200 +#define B_BE_TX_ACQ_DESA_L_MASK GENMASK(31, 3) +#define R_BE_ACQ_TXBD_DESA_H 0xB204 +#define B_BE_TX_ACQ_DESA_H_MASK GENMASK(7, 0) +#define R_BE_NACQ_TXBD_DESA_L 0xB240 +#define B_BE_TX_NACQ_DESA_L_MASK GENMASK(31, 3) +#define R_BE_NACQ_TXBD_DESA_H 0xB244 +#define B_BE_TX_NACQ_DESA_H_MASK GENMASK(7, 0) + #define R_BE_RXQ0_RXBD_DESA_L_V1 0xB300 #define R_BE_RXQ0_RXBD_DESA_H_V1 0xB304 #define R_BE_RPQ0_RXBD_DESA_L_V1 0xB308 #define R_BE_RPQ0_RXBD_DESA_H_V1 0xB30C +#define R_BE_HOST0_RXBD_DESA_L 0xB300 +#define B_BE_RX_HOST0_DESA_L_MASK GENMASK(31, 3) +#define R_BE_HOST0_RXBD_DESA_H 0xB304 +#define B_BE_RX_HOST0_DESA_H_MASK GENMASK(7, 0) + #define R_BE_WP_ADDR_H_SEL0_3_V1 0xB420 #define R_BE_WP_ADDR_H_SEL4_7_V1 0xB424 #define R_BE_WP_ADDR_H_SEL8_11_V1 0xB428 @@ -1249,7 +1303,7 @@ struct rtw89_pci_bd_idx_addr { }; struct rtw89_pci_ch_dma_addr { - u32 num; + u32 num; /* also `offset` addr for group_bd_addr design */ u32 idx; u32 bdram; u32 desa_l; @@ -1267,13 +1321,15 @@ struct rtw89_pci_bd_ram { u8 min_num; }; -struct rtw89_pci_gen_def { +struct rtw89_pci_isr_def { u32 isr_rdu; u32 isr_halt_c2h; u32 isr_wdt_timeout; struct rtw89_reg2_def isr_clear_rpq; struct rtw89_reg2_def isr_clear_rxq; +}; +struct rtw89_pci_gen_def { int (*mac_pre_init)(struct rtw89_dev *rtwdev); int (*mac_pre_deinit)(struct rtw89_dev *rtwdev); int (*mac_post_init)(struct rtw89_dev *rtwdev); @@ -1309,8 +1365,16 @@ struct rtw89_pci_ssid_quirk { unsigned long bitmap; /* bitmap of rtw89_quirks */ }; +struct rtw89_pci_rpp_info { + u16 seq; + u8 qsel; + u8 tx_status; + u8 txch; +}; + struct rtw89_pci_info { const struct rtw89_pci_gen_def *gen_def; + const struct rtw89_pci_isr_def *isr_def; enum mac_ax_bd_trunc_mode txbd_trunc_mode; enum mac_ax_bd_trunc_mode rxbd_trunc_mode; enum mac_ax_rxbd_mode rxbd_mode; @@ -1328,6 +1392,8 @@ struct rtw89_pci_info { bool rx_ring_eq_is_full; bool check_rx_tag; bool no_rxbd_fs; + bool group_bd_addr; + u32 rpp_fmt_size; u32 init_cfg_reg; u32 txhci_en_bit; @@ -1357,6 +1423,8 @@ struct rtw89_pci_info { u32 (*fill_txaddr_info)(struct rtw89_dev *rtwdev, void *txaddr_info_addr, u32 total_len, dma_addr_t dma, u8 *add_info_nr); + void (*parse_rpp)(struct rtw89_dev *rtwdev, void *rpp, + struct rtw89_pci_rpp_info *rpp_info); void (*config_intr_mask)(struct rtw89_dev *rtwdev); void (*enable_intr)(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void (*disable_intr)(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); @@ -1430,6 +1498,19 @@ struct rtw89_pci_rpp_fmt { __le32 dword; } __packed; +#define RTW89_PCI_RPP_W0_MACID_V1_MASK GENMASK(9, 0) +#define RTW89_PCI_RPP_W0_DMA_CH_MASK GENMASK(13, 10) +#define RTW89_PCI_RPP_W0_TX_STATUS_V1_MASK GENMASK(16, 14) +#define RTW89_PCI_RPP_W0_PCIE_SEQ_V1_MASK GENMASK(31, 17) +#define RTW89_PCI_RPP_W1_QSEL_V1_MASK GENMASK(5, 0) +#define RTW89_PCI_RPP_W1_TID_IND BIT(6) +#define RTW89_PCI_RPP_W1_CHANGE_LINK BIT(7) + +struct rtw89_pci_rpp_fmt_v1 { + __le32 w0; + __le32 w1; +} __packed; + struct rtw89_pci_rx_bd_32 { __le16 buf_size; __le16 opt; @@ -1468,6 +1549,12 @@ struct rtw89_pci_dma_ring { u32 rp; /* hw idx */ }; +struct rtw89_pci_dma_pool { + void *head; + dma_addr_t dma; + u32 size; +}; + struct rtw89_pci_tx_wd_ring { void *head; dma_addr_t dma; @@ -1497,6 +1584,11 @@ struct rtw89_pci_tx_ring { u64 tx_mac_id_drop; }; +struct rtw89_pci_tx_rings { + struct rtw89_pci_tx_ring rings[RTW89_TXCH_NUM]; + struct rtw89_pci_dma_pool bd_pool; +}; + struct rtw89_pci_rx_ring { struct rtw89_pci_dma_ring bd_ring; struct sk_buff *buf[RTW89_PCI_RXBD_NUM_MAX]; @@ -1506,6 +1598,11 @@ struct rtw89_pci_rx_ring { u32 target_rx_tag:13; }; +struct rtw89_pci_rx_rings { + struct rtw89_pci_rx_ring rings[RTW89_RXCH_NUM]; + struct rtw89_pci_dma_pool bd_pool; +}; + struct rtw89_pci_isrs { u32 ind_isrs; u32 halt_c2h_isrs; @@ -1523,8 +1620,8 @@ struct rtw89_pci { bool low_power; bool under_recovery; bool enable_dac; - struct rtw89_pci_tx_ring tx_rings[RTW89_TXCH_NUM]; - struct rtw89_pci_rx_ring rx_rings[RTW89_RXCH_NUM]; + struct rtw89_pci_tx_rings tx; + struct rtw89_pci_rx_rings rx; struct sk_buff_head h2c_queue; struct sk_buff_head h2c_release_queue; DECLARE_BITMAP(kick_map, RTW89_TXCH_NUM); @@ -1537,10 +1634,7 @@ struct rtw89_pci { static inline struct rtw89_pci_rx_info *RTW89_PCI_RX_SKB_CB(struct sk_buff *skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - - BUILD_BUG_ON(sizeof(struct rtw89_pci_tx_data) > - sizeof(info->status.status_driver_data)); + BUILD_BUG_ON(sizeof(struct rtw89_pci_rx_info) > sizeof(skb->cb)); return (struct rtw89_pci_rx_info *)skb->cb; } @@ -1571,6 +1665,10 @@ static inline struct rtw89_pci_tx_data *RTW89_PCI_TX_SKB_CB(struct sk_buff *skb) { struct rtw89_tx_skb_data *data = RTW89_TX_SKB_CB(skb); + BUILD_BUG_ON(sizeof(struct rtw89_tx_skb_data) + + sizeof(struct rtw89_pci_tx_data) > + sizeof_field(struct ieee80211_tx_info, driver_data)); + return (struct rtw89_pci_tx_data *)data->hci_priv; } @@ -1622,11 +1720,16 @@ 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; +extern const struct rtw89_pci_ch_dma_addr_set rtw89_pci_ch_dma_addr_set_be_v1; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_dual[RTW89_TXCH_NUM]; extern const struct rtw89_pci_bd_ram rtw89_bd_ram_table_single[RTW89_TXCH_NUM]; +extern const struct rtw89_pci_isr_def rtw89_pci_isr_ax; +extern const struct rtw89_pci_isr_def rtw89_pci_isr_be; +extern const struct rtw89_pci_isr_def rtw89_pci_isr_be_v1; extern const struct rtw89_pci_gen_def rtw89_pci_gen_ax; extern const struct rtw89_pci_gen_def rtw89_pci_gen_be; @@ -1645,16 +1748,23 @@ u32 rtw89_pci_fill_txaddr_info(struct rtw89_dev *rtwdev, u32 rtw89_pci_fill_txaddr_info_v1(struct rtw89_dev *rtwdev, void *txaddr_info_addr, u32 total_len, dma_addr_t dma, u8 *add_info_nr); +void rtw89_pci_parse_rpp(struct rtw89_dev *rtwdev, void *_rpp, + struct rtw89_pci_rpp_info *rpp_info); +void rtw89_pci_parse_rpp_v1(struct rtw89_dev *rtwdev, void *_rpp, + struct rtw89_pci_rpp_info *rpp_info); void rtw89_pci_ctrl_dma_all(struct rtw89_dev *rtwdev, bool enable); void rtw89_pci_config_intr_mask(struct rtw89_dev *rtwdev); void rtw89_pci_config_intr_mask_v1(struct rtw89_dev *rtwdev); void rtw89_pci_config_intr_mask_v2(struct rtw89_dev *rtwdev); +void rtw89_pci_config_intr_mask_v3(struct rtw89_dev *rtwdev); void rtw89_pci_enable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_enable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr_v1(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_enable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_disable_intr_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); +void rtw89_pci_enable_intr_v3(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); +void rtw89_pci_disable_intr_v3(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci); void rtw89_pci_recognize_intrs(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); @@ -1664,6 +1774,9 @@ void rtw89_pci_recognize_intrs_v1(struct rtw89_dev *rtwdev, void rtw89_pci_recognize_intrs_v2(struct rtw89_dev *rtwdev, struct rtw89_pci *rtwpci, struct rtw89_pci_isrs *isrs); +void rtw89_pci_recognize_intrs_v3(struct rtw89_dev *rtwdev, + struct rtw89_pci *rtwpci, + struct rtw89_pci_isrs *isrs); static inline u32 rtw89_chip_fill_txaddr_info(struct rtw89_dev *rtwdev, diff --git a/drivers/net/wireless/realtek/rtw89/pci_be.c b/drivers/net/wireless/realtek/rtw89/pci_be.c index 12e6a0cbb889..e4590879b800 100644 --- a/drivers/net/wireless/realtek/rtw89/pci_be.c +++ b/drivers/net/wireless/realtek/rtw89/pci_be.c @@ -175,10 +175,10 @@ static void rtw89_pci_clr_idx_all_be(struct rtw89_dev *rtwdev) rtw89_write32(rtwdev, R_BE_RXBD_RWPTR_CLR1_V1, B_BE_CLR_RXQ0_IDX | B_BE_CLR_RPQ0_IDX); - rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RXQ]; + rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RXQ]; rtw89_write16(rtwdev, R_BE_RXQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1); - rx_ring = &rtwpci->rx_rings[RTW89_RXCH_RPQ]; + rx_ring = &rtwpci->rx.rings[RTW89_RXCH_RPQ]; rtw89_write16(rtwdev, R_BE_RPQ0_RXBD_IDX_V1, rx_ring->bd_ring.len - 1); } @@ -665,13 +665,25 @@ static int __maybe_unused rtw89_pci_resume_be(struct device *dev) SIMPLE_DEV_PM_OPS(rtw89_pm_ops_be, rtw89_pci_suspend_be, rtw89_pci_resume_be); EXPORT_SYMBOL(rtw89_pm_ops_be); -const struct rtw89_pci_gen_def rtw89_pci_gen_be = { +const struct rtw89_pci_isr_def rtw89_pci_isr_be = { .isr_rdu = B_BE_RDU_CH1_INT_V1 | B_BE_RDU_CH0_INT_V1, .isr_halt_c2h = B_BE_HALT_C2H_INT, .isr_wdt_timeout = B_BE_WDT_TIMEOUT_INT, .isr_clear_rpq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RPQ0_ISR_V1}, .isr_clear_rxq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RX0P2_ISR_V1}, +}; +EXPORT_SYMBOL(rtw89_pci_isr_be); +const struct rtw89_pci_isr_def rtw89_pci_isr_be_v1 = { + .isr_rdu = B_BE_PCIE_RDU_CH1_INT | B_BE_PCIE_RDU_CH0_INT, + .isr_halt_c2h = B_BE_HALT_C2H_INT, + .isr_wdt_timeout = B_BE_WDT_TIMEOUT_INT, + .isr_clear_rpq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RPQ0_ISR_V1}, + .isr_clear_rxq = {R_BE_PCIE_DMA_ISR, B_BE_PCIE_RX_RX0P2_ISR_V1}, +}; +EXPORT_SYMBOL(rtw89_pci_isr_be_v1); + +const struct rtw89_pci_gen_def rtw89_pci_gen_be = { .mac_pre_init = rtw89_pci_ops_mac_pre_init_be, .mac_pre_deinit = rtw89_pci_ops_mac_pre_deinit_be, .mac_post_init = rtw89_pci_ops_mac_post_init_be, diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c index 76a2e26d4a10..ba7feadd7582 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; } @@ -1699,6 +1702,91 @@ void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev) rtw89_phy_bb_reset(rtwdev); } +void rtw89_phy_init_bb_afe(struct rtw89_dev *rtwdev) +{ + struct rtw89_fw_elm_info *elm_info = &rtwdev->fw.elm_info; + const struct rtw89_fw_element_hdr *afe_elm = elm_info->afe; + const struct rtw89_phy_afe_info *info; + u32 action, cat, class; + u32 addr, mask, val; + u32 poll, rpt; + u32 n, i; + + if (!afe_elm) + return; + + n = le32_to_cpu(afe_elm->size) / sizeof(*info); + + for (i = 0; i < n; i++) { + info = &afe_elm->u.afe.infos[i]; + + class = le32_to_cpu(info->class); + switch (class) { + case RTW89_FW_AFE_CLASS_P0: + case RTW89_FW_AFE_CLASS_P1: + case RTW89_FW_AFE_CLASS_CMN: + /* Currently support two paths */ + break; + case RTW89_FW_AFE_CLASS_P2: + case RTW89_FW_AFE_CLASS_P3: + case RTW89_FW_AFE_CLASS_P4: + default: + rtw89_warn(rtwdev, "unexpected AFE class %u\n", class); + continue; + } + + addr = le32_to_cpu(info->addr); + mask = le32_to_cpu(info->mask); + val = le32_to_cpu(info->val); + cat = le32_to_cpu(info->cat); + action = le32_to_cpu(info->action); + + switch (action) { + case RTW89_FW_AFE_ACTION_WRITE: + switch (cat) { + case RTW89_FW_AFE_CAT_MAC: + case RTW89_FW_AFE_CAT_MAC1: + rtw89_write32_mask(rtwdev, addr, mask, val); + break; + case RTW89_FW_AFE_CAT_AFEDIG: + case RTW89_FW_AFE_CAT_AFEDIG1: + rtw89_write32_mask(rtwdev, addr, mask, val); + break; + case RTW89_FW_AFE_CAT_BB: + rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_0); + break; + case RTW89_FW_AFE_CAT_BB1: + rtw89_phy_write32_idx(rtwdev, addr, mask, val, RTW89_PHY_1); + break; + default: + rtw89_warn(rtwdev, + "unexpected AFE writing action %u\n", action); + break; + } + break; + case RTW89_FW_AFE_ACTION_POLL: + for (poll = 0; poll <= 10; poll++) { + /* + * For CAT_BB, AFE reads register with mcu_offset 0, + * so both CAT_MAC and CAT_BB use the same method. + */ + rpt = rtw89_read32_mask(rtwdev, addr, mask); + if (rpt == val) + goto poll_done; + + fsleep(1); + } + rtw89_warn(rtwdev, "failed to poll AFE cat=%u addr=0x%x mask=0x%x\n", + cat, addr, mask); +poll_done: + break; + case RTW89_FW_AFE_ACTION_DELAY: + fsleep(addr); + break; + } + } +} + static u32 rtw89_phy_nctl_poll(struct rtw89_dev *rtwdev) { rtw89_phy_write32(rtwdev, 0x8080, 0x4); @@ -2940,7 +3028,7 @@ static void __rtw89_phy_c2h_ra_rpt_iter(struct rtw89_sta_link *rtwsta_link, } if (mode == RTW89_RA_RPT_MODE_LEGACY) { - valid = rtw89_ra_report_to_bitrate(rtwdev, rate, &legacy_bitrate); + valid = rtw89_legacy_rate_to_bitrate(rtwdev, rate, &legacy_bitrate); if (!valid) return; } @@ -3084,6 +3172,34 @@ void (* const rtw89_phy_c2h_dm_handler[])(struct rtw89_dev *rtwdev, [RTW89_PHY_C2H_DM_FUNC_FW_SCAN] = rtw89_phy_c2h_fw_scan_rpt, }; +static +void rtw89_phy_c2h_rfk_tas_pwr(struct rtw89_dev *rtwdev, + const struct rtw89_c2h_rf_tas_rpt_log *content) +{ + const enum rtw89_sar_sources src = rtwdev->sar.src; + struct rtw89_tas_info *tas = &rtwdev->tas; + u64 linear = 0; + u32 i, cur_idx; + s16 txpwr; + + if (!tas->enable || src == RTW89_SAR_SOURCE_NONE) + return; + + cur_idx = le32_to_cpu(content->cur_idx); + for (i = 0; i < cur_idx; i++) { + txpwr = le16_to_cpu(content->txpwr_history[i]); + linear += rtw89_db_quarter_to_linear(txpwr); + + rtw89_debug(rtwdev, RTW89_DBG_SAR, + "tas: index: %u, txpwr: %d\n", i, txpwr); + } + + if (cur_idx == 0) + tas->instant_txpwr = rtw89_db_to_linear(0); + else + tas->instant_txpwr = DIV_ROUND_DOWN_ULL(linear, cur_idx); +} + static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, enum rtw89_phy_c2h_rfk_log_func func, void *content, u16 len) @@ -3335,6 +3451,13 @@ static void rtw89_phy_c2h_rfk_rpt_log(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[TXGAPK]rpt power_d[1] = %*ph\n", (int)sizeof(txgapk->power_d[1]), txgapk->power_d[1]); return; + case RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR: + if (len != sizeof(struct rtw89_c2h_rf_tas_rpt_log)) + goto out; + + rtw89_phy_c2h_rfk_tas_pwr(rtwdev, content); + + return; default: break; } @@ -3387,9 +3510,6 @@ static void rtw89_phy_c2h_rfk_log(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u16 chunk_len; bool handled; - if (!rtw89_debug_is_enabled(rtwdev, RTW89_DBG_RFK)) - return; - log_ptr += sizeof(*c2h_hdr); len -= sizeof(*c2h_hdr); @@ -3466,6 +3586,13 @@ rtw89_phy_c2h_rfk_log_txgapk(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK, "TXGAPK"); } +static void +rtw89_phy_c2h_rfk_log_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +{ + rtw89_phy_c2h_rfk_log(rtwdev, c2h, len, + RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR, "TAS"); +} + static void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) = { @@ -3475,6 +3602,7 @@ void (* const rtw89_phy_c2h_rfk_log_handler[])(struct rtw89_dev *rtwdev, [RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK] = rtw89_phy_c2h_rfk_log_rxdck, [RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI] = rtw89_phy_c2h_rfk_log_tssi, [RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK] = rtw89_phy_c2h_rfk_log_txgapk, + [RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR] = rtw89_phy_c2h_rfk_log_tas_pwr, }; static @@ -3537,39 +3665,19 @@ rtw89_phy_c2h_rfk_report_state(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u3 } static void -rtw89_phy_c2h_rfk_log_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) +rtw89_phy_c2h_rfk_report_tas_pwr(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) { - const struct rtw89_c2h_rf_tas_info *rf_tas = + const struct rtw89_c2h_rf_tas_info *report = (const struct rtw89_c2h_rf_tas_info *)c2h->data; - const enum rtw89_sar_sources src = rtwdev->sar.src; - struct rtw89_tas_info *tas = &rtwdev->tas; - u64 linear = 0; - u32 i, cur_idx; - s16 txpwr; - - if (!tas->enable || src == RTW89_SAR_SOURCE_NONE) - return; - cur_idx = le32_to_cpu(rf_tas->cur_idx); - for (i = 0; i < cur_idx; i++) { - txpwr = (s16)le16_to_cpu(rf_tas->txpwr_history[i]); - linear += rtw89_db_quarter_to_linear(txpwr); - - rtw89_debug(rtwdev, RTW89_DBG_SAR, - "tas: index: %u, txpwr: %d\n", i, txpwr); - } - - if (cur_idx == 0) - tas->instant_txpwr = rtw89_db_to_linear(0); - else - tas->instant_txpwr = DIV_ROUND_DOWN_ULL(linear, cur_idx); + rtw89_phy_c2h_rfk_tas_pwr(rtwdev, &report->content); } static void (* const rtw89_phy_c2h_rfk_report_handler[])(struct rtw89_dev *rtwdev, struct sk_buff *c2h, u32 len) = { [RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE] = rtw89_phy_c2h_rfk_report_state, - [RTW89_PHY_C2H_RFK_LOG_TAS_PWR] = rtw89_phy_c2h_rfk_log_tas_pwr, + [RTW89_PHY_C2H_RFK_REPORT_FUNC_TAS_PWR] = rtw89_phy_c2h_rfk_report_tas_pwr, }; bool rtw89_phy_c2h_chk_atomic(struct rtw89_dev *rtwdev, u8 class, u8 func) @@ -3623,12 +3731,11 @@ void rtw89_phy_c2h_handle(struct rtw89_dev *rtwdev, struct sk_buff *skb, handler = rtw89_phy_c2h_dm_handler[func]; break; default: - rtw89_info(rtwdev, "PHY c2h class %d not support\n", class); - return; + break; } if (!handler) { - rtw89_info(rtwdev, "PHY c2h class %d func %d not support\n", class, - func); + rtw89_info_once(rtwdev, "PHY c2h class %d func %d not support\n", + class, func); return; } handler(rtwdev, skb, len); @@ -5494,6 +5601,34 @@ static void rtw89_phy_ifs_clm_set_th_reg(struct rtw89_dev *rtwdev, i + 1, env->ifs_clm_th_l[i], env->ifs_clm_th_h[i]); } +static void __rtw89_phy_nhm_setting_init(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + struct rtw89_env_monitor_info *env = &bb->env_monitor; + const struct rtw89_ccx_regs *ccx = phy->ccx; + + env->nhm_include_cca = false; + env->nhm_mntr_time = 0; + env->nhm_sum = 0; + + rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_config, ccx->nhm_en_mask, bb->phy_idx); + rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_method, ccx->nhm_pwr_method_msk, + bb->phy_idx); +} + +void rtw89_phy_nhm_setting_init(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_bb_ctx *bb; + + if (!chip->support_noise) + return; + + rtw89_for_each_active_bb(rtwdev, bb) + __rtw89_phy_nhm_setting_init(rtwdev, bb); +} + static void rtw89_phy_ifs_clm_setting_init(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) { @@ -5555,7 +5690,7 @@ static int rtw89_phy_ccx_racing_ctrl(struct rtw89_dev *rtwdev, } static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev, - struct rtw89_bb_ctx *bb) + struct rtw89_bb_ctx *bb, u8 sel) { const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; struct rtw89_env_monitor_info *env = &bb->env_monitor; @@ -5565,10 +5700,17 @@ static void rtw89_phy_ccx_trigger(struct rtw89_dev *rtwdev, bb->phy_idx); rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 0, bb->phy_idx); + if (sel & RTW89_PHY_ENV_MON_NHM) + rtw89_phy_write32_idx_clr(rtwdev, ccx->nhm_config, + ccx->nhm_en_mask, bb->phy_idx); + rtw89_phy_write32_idx(rtwdev, ccx->ifs_cnt_addr, ccx->ifs_clm_cnt_clear_mask, 1, bb->phy_idx); rtw89_phy_write32_idx(rtwdev, ccx->setting_addr, ccx->measurement_trig_mask, 1, bb->phy_idx); + if (sel & RTW89_PHY_ENV_MON_NHM) + rtw89_phy_write32_idx_set(rtwdev, ccx->nhm_config, + ccx->nhm_en_mask, bb->phy_idx); env->ccx_ongoing = true; } @@ -5639,6 +5781,125 @@ static void rtw89_phy_ifs_clm_get_utility(struct rtw89_dev *rtwdev, env->ifs_clm_cca_avg[i]); } +static u8 rtw89_nhm_weighted_avg(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_env_monitor_info *env = &bb->env_monitor; + u8 nhm_weight[RTW89_NHM_RPT_NUM]; + u32 nhm_weighted_sum = 0; + u8 weight_zero; + u8 i; + + if (env->nhm_sum == 0) + return 0; + + weight_zero = clamp_t(u16, env->nhm_th[0] - RTW89_NHM_WEIGHT_OFFSET, 0, U8_MAX); + + for (i = 0; i < RTW89_NHM_RPT_NUM; i++) { + if (i == 0) + nhm_weight[i] = weight_zero; + else if (i == (RTW89_NHM_RPT_NUM - 1)) + nhm_weight[i] = env->nhm_th[i - 1] + RTW89_NHM_WEIGHT_OFFSET; + else + nhm_weight[i] = (env->nhm_th[i - 1] + env->nhm_th[i]) / 2; + } + + if (rtwdev->chip->chip_id == RTL8852A || rtwdev->chip->chip_id == RTL8852B || + rtwdev->chip->chip_id == RTL8852C) { + if (env->nhm_th[RTW89_NHM_TH_NUM - 1] == RTW89_NHM_WA_TH) { + nhm_weight[RTW89_NHM_RPT_NUM - 1] = + env->nhm_th[RTW89_NHM_TH_NUM - 2] + + RTW89_NHM_WEIGHT_OFFSET; + nhm_weight[RTW89_NHM_RPT_NUM - 2] = + nhm_weight[RTW89_NHM_RPT_NUM - 1]; + } + + env->nhm_result[0] += env->nhm_result[RTW89_NHM_RPT_NUM - 1]; + env->nhm_result[RTW89_NHM_RPT_NUM - 1] = 0; + } + + for (i = 0; i < RTW89_NHM_RPT_NUM; i++) + nhm_weighted_sum += env->nhm_result[i] * nhm_weight[i]; + + return (nhm_weighted_sum / env->nhm_sum) >> RTW89_NHM_TH_FACTOR; +} + +static void __rtw89_phy_nhm_get_result(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, enum rtw89_band hw_band, + u16 ch_hw_value) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + struct rtw89_env_monitor_info *env = &bb->env_monitor; + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_ccx_regs *ccx = phy->ccx; + struct ieee80211_supported_band *sband; + const struct rtw89_reg_def *nhm_rpt; + enum nl80211_band band; + u32 sum = 0; + u8 chan_idx; + u8 nhm_pwr; + u8 i; + + if (!rtw89_phy_read32_idx(rtwdev, ccx->nhm, ccx->nhm_ready, bb->phy_idx)) { + rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "[NHM] Get NHM report Fail\n"); + return; + } + + for (i = 0; i < RTW89_NHM_RPT_NUM; i++) { + nhm_rpt = &(*chip->nhm_report)[i]; + + env->nhm_result[i] = + rtw89_phy_read32_idx(rtwdev, nhm_rpt->addr, + nhm_rpt->mask, bb->phy_idx); + sum += env->nhm_result[i]; + } + env->nhm_sum = sum; + nhm_pwr = rtw89_nhm_weighted_avg(rtwdev, bb); + + if (!ch_hw_value) + return; + + band = rtw89_hw_to_nl80211_band(hw_band); + sband = rtwdev->hw->wiphy->bands[band]; + if (!sband) + return; + + for (chan_idx = 0; chan_idx < sband->n_channels; chan_idx++) { + struct ieee80211_channel *channel; + struct rtw89_nhm_report *rpt; + struct list_head *nhm_list; + + channel = &sband->channels[chan_idx]; + if (channel->hw_value != ch_hw_value) + continue; + + rpt = &env->nhm_his[hw_band][chan_idx]; + nhm_list = &env->nhm_rpt_list; + + rpt->channel = channel; + rpt->noise = nhm_pwr; + + if (list_empty(&rpt->list)) + list_add_tail(&rpt->list, nhm_list); + + return; + } + + rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "[NHM] channel not found\n"); +} + +void rtw89_phy_nhm_get_result(struct rtw89_dev *rtwdev, enum rtw89_band hw_band, + u16 ch_hw_value) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_bb_ctx *bb; + + if (!chip->support_noise) + return; + + rtw89_for_each_active_bb(rtwdev, bb) + __rtw89_phy_nhm_get_result(rtwdev, bb, hw_band, ch_hw_value); +} + static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) { @@ -5739,6 +6000,107 @@ static bool rtw89_phy_ifs_clm_get_result(struct rtw89_dev *rtwdev, return true; } +static void rtw89_phy_nhm_th_update(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb) +{ + struct rtw89_env_monitor_info *env = &bb->env_monitor; + static const u8 nhm_th_11k[RTW89_NHM_RPT_NUM] = { + 18, 21, 24, 27, 30, 35, 40, 45, 50, 55, 60, 0 + }; + const struct rtw89_chip_info *chip = rtwdev->chip; + const struct rtw89_reg_def *nhm_th; + u8 i; + + for (i = 0; i < RTW89_NHM_RPT_NUM; i++) + env->nhm_th[i] = nhm_th_11k[i] << RTW89_NHM_TH_FACTOR; + + if (chip->chip_id == RTL8852A || chip->chip_id == RTL8852B || + chip->chip_id == RTL8852C) + env->nhm_th[RTW89_NHM_TH_NUM - 1] = RTW89_NHM_WA_TH; + + for (i = 0; i < RTW89_NHM_TH_NUM; i++) { + nhm_th = &(*chip->nhm_th)[i]; + + rtw89_phy_write32_idx(rtwdev, nhm_th->addr, nhm_th->mask, + env->nhm_th[i], bb->phy_idx); + } +} + +static int rtw89_phy_nhm_set(struct rtw89_dev *rtwdev, + struct rtw89_bb_ctx *bb, + struct rtw89_ccx_para_info *para) +{ + const struct rtw89_phy_gen_def *phy = rtwdev->chip->phy_def; + struct rtw89_env_monitor_info *env = &bb->env_monitor; + const struct rtw89_ccx_regs *ccx = phy->ccx; + u32 unit_idx = 0; + u32 period = 0; + + if (para->mntr_time == 0) { + rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, + "[NHM] MNTR_TIME is 0\n"); + return -EINVAL; + } + + if (rtw89_phy_ccx_racing_ctrl(rtwdev, bb, para->rac_lv)) + return -EINVAL; + + rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, + "[NHM]nhm_incld_cca=%d, mntr_time=%d ms\n", + para->nhm_incld_cca, para->mntr_time); + + if (para->mntr_time != env->nhm_mntr_time) { + rtw89_phy_ccx_ms_to_period_unit(rtwdev, para->mntr_time, + &period, &unit_idx); + rtw89_phy_write32_idx(rtwdev, ccx->nhm_config, + ccx->nhm_period_mask, period, bb->phy_idx); + rtw89_phy_write32_idx(rtwdev, ccx->nhm_config, + ccx->nhm_unit_mask, period, bb->phy_idx); + + env->nhm_mntr_time = para->mntr_time; + env->ccx_period = period; + env->ccx_unit_idx = unit_idx; + } + + if (para->nhm_incld_cca != env->nhm_include_cca) { + rtw89_phy_write32_idx(rtwdev, ccx->nhm_config, + ccx->nhm_include_cca_mask, para->nhm_incld_cca, + bb->phy_idx); + + env->nhm_include_cca = para->nhm_incld_cca; + } + + rtw89_phy_nhm_th_update(rtwdev, bb); + + return 0; +} + +static void __rtw89_phy_nhm_trigger(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_ccx_para_info para = { + .mntr_time = RTW89_NHM_MNTR_TIME, + .rac_lv = RTW89_RAC_LV_1, + .nhm_incld_cca = true, + }; + + rtw89_phy_ccx_racing_release(rtwdev, bb); + + rtw89_phy_nhm_set(rtwdev, bb, ¶); + rtw89_phy_ccx_trigger(rtwdev, bb, RTW89_PHY_ENV_MON_NHM); +} + +void rtw89_phy_nhm_trigger(struct rtw89_dev *rtwdev) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_bb_ctx *bb; + + if (!chip->support_noise) + return; + + rtw89_for_each_active_bb(rtwdev, bb) + __rtw89_phy_nhm_trigger(rtwdev, bb); +} + static int rtw89_phy_ifs_clm_set(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb, struct rtw89_ccx_para_info *para) @@ -5813,7 +6175,7 @@ static void __rtw89_phy_env_monitor_track(struct rtw89_dev *rtwdev, if (rtw89_phy_ifs_clm_set(rtwdev, bb, ¶) == 0) chk_result |= RTW89_PHY_ENV_MON_IFS_CLM; if (chk_result) - rtw89_phy_ccx_trigger(rtwdev, bb); + rtw89_phy_ccx_trigger(rtwdev, bb, chk_result); rtw89_debug(rtwdev, RTW89_DBG_PHY_TRACK, "get_result=0x%x, chk_result:0x%x\n", @@ -5828,14 +6190,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 +6211,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 +6223,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 +6238,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 +6248,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 +6271,35 @@ 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 &= ~(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 +6673,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 +6701,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 +6727,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 +6757,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 +6786,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 +6951,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 +6971,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", @@ -6730,6 +7267,7 @@ void rtw89_phy_dm_init(struct rtw89_dev *rtwdev) rtw89_chip_bb_sethw(rtwdev); rtw89_phy_env_monitor_init(rtwdev); + rtw89_phy_nhm_setting_init(rtwdev); rtw89_physts_parsing_init(rtwdev); rtw89_phy_dig_init(rtwdev); rtw89_phy_cfo_init(rtwdev); @@ -6755,6 +7293,43 @@ void rtw89_phy_dm_reinit(struct rtw89_dev *rtwdev) rtw89_physts_parsing_init(rtwdev); } +static void __rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev, struct rtw89_bb_ctx *bb) +{ + struct rtw89_env_monitor_info *env = &bb->env_monitor; + const struct rtw89_chip_info *chip = rtwdev->chip; + struct ieee80211_supported_band *sband; + enum rtw89_band hw_band; + enum nl80211_band band; + u8 idx; + + if (!chip->support_noise) + return; + + for (band = 0; band < NUM_NL80211_BANDS; band++) { + sband = rtwdev->hw->wiphy->bands[band]; + if (!sband) + continue; + + hw_band = rtw89_nl80211_to_hw_band(band); + env->nhm_his[hw_band] = + devm_kcalloc(rtwdev->dev, sband->n_channels, + sizeof(*env->nhm_his[0]), GFP_KERNEL); + + for (idx = 0; idx < sband->n_channels; idx++) + INIT_LIST_HEAD(&env->nhm_his[hw_band][idx].list); + + INIT_LIST_HEAD(&env->nhm_rpt_list); + } +} + +void rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev) +{ + struct rtw89_bb_ctx *bb; + + rtw89_for_each_capab_bb(rtwdev, bb) + __rtw89_phy_dm_init_data(rtwdev, bb); +} + void rtw89_phy_set_bss_color(struct rtw89_dev *rtwdev, struct rtw89_vif_link *rtwvif_link) { @@ -7125,7 +7700,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 +7730,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 +7743,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 +7761,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); @@ -7411,6 +7985,15 @@ static const struct rtw89_ccx_regs rtw89_ccx_regs_ax = { .ifs_total_addr = R_IFSCNT, .ifs_cnt_done_mask = B_IFSCNT_DONE_MSK, .ifs_total_mask = B_IFSCNT_TOTAL_CNT_MSK, + .nhm = R_NHM_AX, + .nhm_ready = B_NHM_READY_MSK, + .nhm_config = R_NHM_CFG, + .nhm_period_mask = B_NHM_PERIOD_MSK, + .nhm_unit_mask = B_NHM_COUNTER_MSK, + .nhm_include_cca_mask = B_NHM_INCLUDE_CCA_MSK, + .nhm_en_mask = B_NHM_EN_MSK, + .nhm_method = R_NHM_TH9, + .nhm_pwr_method_msk = B_NHM_PWDB_METHOD_MSK, }; static const struct rtw89_physts_regs rtw89_physts_regs_ax = { diff --git a/drivers/net/wireless/realtek/rtw89/phy.h b/drivers/net/wireless/realtek/rtw89/phy.h index 5b451f1cfaac..9caacffd0af8 100644 --- a/drivers/net/wireless/realtek/rtw89/phy.h +++ b/drivers/net/wireless/realtek/rtw89/phy.h @@ -149,13 +149,14 @@ enum rtw89_phy_c2h_rfk_log_func { RTW89_PHY_C2H_RFK_LOG_FUNC_RXDCK = 3, RTW89_PHY_C2H_RFK_LOG_FUNC_TSSI = 4, RTW89_PHY_C2H_RFK_LOG_FUNC_TXGAPK = 5, + RTW89_PHY_C2H_RFK_LOG_FUNC_TAS_PWR = 9, RTW89_PHY_C2H_RFK_LOG_FUNC_NUM, }; enum rtw89_phy_c2h_rfk_report_func { RTW89_PHY_C2H_RFK_REPORT_FUNC_STATE = 0, - RTW89_PHY_C2H_RFK_LOG_TAS_PWR = 6, + RTW89_PHY_C2H_RFK_REPORT_FUNC_TAS_PWR = 6, }; enum rtw89_phy_c2h_dm_func { @@ -188,6 +189,12 @@ enum rtw89_env_monitor_result_level { RTW89_PHY_ENV_MON_EDCCA_CLM = BIT(4), }; +#define RTW89_NHM_WEIGHT_OFFSET 2 +#define RTW89_NHM_WA_TH (109 << 1) +#define RTW89_NOISE_DEFAULT -96 +#define RTW89_NHM_MNTR_TIME 40 +#define RTW89_NHM_TH_FACTOR 1 + #define CCX_US_BASE_RATIO 4 enum rtw89_ccx_unit { RTW89_CCX_4_US = 0, @@ -252,6 +259,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 }; @@ -427,6 +435,15 @@ struct rtw89_ccx_regs { u32 ifs_total_addr; u32 ifs_cnt_done_mask; u32 ifs_total_mask; + u32 nhm; + u32 nhm_ready; + u32 nhm_config; + u32 nhm_period_mask; + u32 nhm_unit_mask; + u32 nhm_include_cca_mask; + u32 nhm_en_mask; + u32 nhm_method; + u32 nhm_pwr_method_msk; }; struct rtw89_physts_regs { @@ -813,6 +830,7 @@ bool rtw89_phy_write_rf_v1(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, bool rtw89_phy_write_rf_v2(struct rtw89_dev *rtwdev, enum rtw89_rf_path rf_path, u32 addr, u32 mask, u32 data); void rtw89_phy_init_bb_reg(struct rtw89_dev *rtwdev); +void rtw89_phy_init_bb_afe(struct rtw89_dev *rtwdev); void rtw89_phy_init_rf_reg(struct rtw89_dev *rtwdev, bool noio); void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev, const struct rtw89_reg2_def *reg, @@ -820,6 +838,7 @@ void rtw89_phy_config_rf_reg_v1(struct rtw89_dev *rtwdev, void *extra_data); void rtw89_phy_dm_init(struct rtw89_dev *rtwdev); void rtw89_phy_dm_reinit(struct rtw89_dev *rtwdev); +void rtw89_phy_dm_init_data(struct rtw89_dev *rtwdev); void rtw89_phy_write32_idx(struct rtw89_dev *rtwdev, u32 addr, u32 mask, u32 data, enum rtw89_phy_idx phy_idx); void rtw89_phy_write32_idx_set(struct rtw89_dev *rtwdev, u32 addr, u32 bits, @@ -1009,6 +1028,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); @@ -1035,5 +1056,9 @@ enum rtw89_rf_path rtw89_phy_get_syn_sel(struct rtw89_dev *rtwdev, u8 rtw89_rfk_chan_lookup(struct rtw89_dev *rtwdev, const struct rtw89_rfk_chan_desc *desc, u8 desc_nr, const struct rtw89_chan *target_chan); +void rtw89_phy_nhm_setting_init(struct rtw89_dev *rtwdev); +void rtw89_phy_nhm_get_result(struct rtw89_dev *rtwdev, enum rtw89_band hw_band, + u16 ch_hw_value); +void rtw89_phy_nhm_trigger(struct rtw89_dev *rtwdev); #endif diff --git a/drivers/net/wireless/realtek/rtw89/phy_be.c b/drivers/net/wireless/realtek/rtw89/phy_be.c index d321cf1fc485..3316a38a62d0 100644 --- a/drivers/net/wireless/realtek/rtw89/phy_be.c +++ b/drivers/net/wireless/realtek/rtw89/phy_be.c @@ -63,6 +63,15 @@ static const struct rtw89_ccx_regs rtw89_ccx_regs_be = { .ifs_total_addr = R_IFSCNT_V1, .ifs_cnt_done_mask = B_IFSCNT_DONE_MSK, .ifs_total_mask = B_IFSCNT_TOTAL_CNT_MSK, + .nhm = R_NHM_BE, + .nhm_ready = B_NHM_READY_BE_MSK, + .nhm_config = R_NHM_CFG, + .nhm_period_mask = B_NHM_PERIOD_MSK, + .nhm_unit_mask = B_NHM_COUNTER_MSK, + .nhm_include_cca_mask = B_NHM_INCLUDE_CCA_MSK, + .nhm_en_mask = B_NHM_EN_MSK, + .nhm_method = R_NHM_TH9, + .nhm_pwr_method_msk = B_NHM_PWDB_METHOD_MSK, }; static const struct rtw89_physts_regs rtw89_physts_regs_be = { diff --git a/drivers/net/wireless/realtek/rtw89/ps.c b/drivers/net/wireless/realtek/rtw89/ps.c index 8e4fe73e7d77..cf58121eb541 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; @@ -94,6 +119,9 @@ static void __rtw89_enter_lps_link(struct rtw89_dev *rtwdev, rtw89_btc_ntfy_radio_state(rtwdev, BTC_RFCTRL_FW_CTRL); rtw89_fw_h2c_lps_parm(rtwdev, &lps_param); + + if (RTW89_CHK_FW_FEATURE(BEACON_TRACKING, &rtwdev->fw)) + rtw89_fw_h2c_pwr_lvl(rtwdev, rtwvif_link); } static void __rtw89_leave_lps(struct rtw89_dev *rtwdev, @@ -106,7 +134,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 +166,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 +267,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 +293,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 +316,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..ed1d958bc49e 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) @@ -3339,6 +3370,10 @@ #define B_AX_CSIPRT_HESU_AID_EN BIT(25) #define B_AX_CSIPRT_VHTSU_AID_EN BIT(24) +#define R_AX_BCN_PSR_RPT_P0 0xCE84 +#define R_AX_BCN_PSR_RPT_P0_C1 0xEE84 +#define B_AX_BCAID_P0_MASK GENMASK(10, 0) + #define R_AX_RX_STATE_MONITOR 0xCEF0 #define R_AX_RX_STATE_MONITOR_C1 0xEEF0 #define B_AX_RX_STATE_MONITOR_MASK GENMASK(31, 0) @@ -6070,6 +6105,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 @@ -6226,6 +6262,11 @@ #define B_BE_PTCL_TOP_ERR_IND BIT(1) #define B_BE_SCHEDULE_TOP_ERR_IND BIT(0) +#define R_BE_CMAC_FW_TRIGGER_IDCT_ISR 0x10168 +#define R_BE_CMAC_FW_TRIGGER_IDCT_ISR_C1 0x14168 +#define B_BE_CMAC_FW_ERR_IDCT_IMR BIT(31) +#define B_BE_CMAC_FW_TRIG_IDCT BIT(0) + #define R_BE_SER_L0_DBG_CNT 0x10170 #define R_BE_SER_L0_DBG_CNT_C1 0x14170 #define B_BE_SER_L0_PHYINTF_CNT_MASK GENMASK(31, 24) @@ -7462,6 +7503,10 @@ #define R_BE_DRV_INFO_OPTION_C1 0x15470 #define B_BE_DRV_INFO_PHYRPT_EN BIT(0) +#define R_BE_BCN_PSR_RPT_P0 0x11484 +#define R_BE_BCN_PSR_RPT_P0_C1 0x15484 +#define B_BE_BCAID_P0_MASK GENMASK(10, 0) + #define R_BE_RX_ERR_ISR 0x114F4 #define R_BE_RX_ERR_ISR_C1 0x154F4 #define B_BE_RX_ERR_TRIG_ACT_TO BIT(9) @@ -8024,6 +8069,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 @@ -8059,6 +8105,26 @@ #define B_MEASUREMENT_TRIG_MSK BIT(2) #define B_CCX_TRIG_OPT_MSK BIT(1) #define B_CCX_EN_MSK BIT(0) +#define R_NHM_CFG 0x0C08 +#define B_NHM_PERIOD_MSK GENMASK(15, 0) +#define B_NHM_COUNTER_MSK GENMASK(17, 16) +#define B_NHM_EN_MSK BIT(18) +#define B_NHM_INCLUDE_CCA_MSK BIT(19) +#define B_NHM_TH0_MSK GENMASK(31, 24) +#define R_NHM_TH1 0x0C0C +#define B_NHM_TH1_MSK GENMASK(7, 0) +#define B_NHM_TH2_MSK GENMASK(15, 8) +#define B_NHM_TH3_MSK GENMASK(23, 16) +#define B_NHM_TH4_MSK GENMASK(31, 24) +#define R_NHM_TH5 0x0C10 +#define B_NHM_TH5_MSK GENMASK(7, 0) +#define B_NHM_TH6_MSK GENMASK(15, 8) +#define B_NHM_TH7_MSK GENMASK(23, 16) +#define B_NHM_TH8_MSK GENMASK(31, 24) +#define R_NHM_TH9 0x0C14 +#define B_NHM_TH9_MSK GENMASK(7, 0) +#define B_NHM_TH10_MSK GENMASK(15, 8) +#define B_NHM_PWDB_METHOD_MSK GENMASK(17, 16) #define R_FAHM 0x0C1C #define B_RXTD_CKEN BIT(2) #define R_IFS_COUNTER 0x0C28 @@ -8128,6 +8194,8 @@ #define R_BRK_ASYNC_RST_EN_1 0x0DC0 #define R_BRK_ASYNC_RST_EN_2 0x0DC4 #define R_BRK_ASYNC_RST_EN_3 0x0DC8 +#define R_NHM_BE 0x0EA4 +#define B_NHM_READY_BE_MSK BIT(16) #define R_CTLTOP 0x1008 #define B_CTLTOP_ON BIT(23) #define B_CTLTOP_VAL GENMASK(15, 12) @@ -8183,6 +8251,26 @@ #define B_SWSI_R_BUSY_V1 BIT(25) #define B_SWSI_R_DATA_DONE_V1 BIT(26) #define R_TX_COUNTER 0x1A40 +#define R_NHM_CNT0 0x1A88 +#define B_NHM_CNT0_MSK GENMASK(15, 0) +#define B_NHM_CNT1_MSK GENMASK(31, 16) +#define R_NHM_CNT2 0x1A8C +#define B_NHM_CNT2_MSK GENMASK(15, 0) +#define B_NHM_CNT3_MSK GENMASK(31, 16) +#define R_NHM_CNT4 0x1A90 +#define B_NHM_CNT4_MSK GENMASK(15, 0) +#define B_NHM_CNT5_MSK GENMASK(31, 16) +#define R_NHM_CNT6 0x1A94 +#define B_NHM_CNT6_MSK GENMASK(15, 0) +#define B_NHM_CNT7_MSK GENMASK(31, 16) +#define R_NHM_CNT8 0x1A98 +#define B_NHM_CNT8_MSK GENMASK(15, 0) +#define B_NHM_CNT9_MSK GENMASK(31, 16) +#define R_NHM_CNT10 0x1A9C +#define B_NHM_CNT10_MSK GENMASK(15, 0) +#define B_NHM_CNT11_MSK GENMASK(31, 16) +#define R_NHM_AX 0x1AA4 +#define B_NHM_READY_MSK BIT(16) #define R_IFS_CLM_TX_CNT 0x1ACC #define R_IFS_CLM_TX_CNT_V1 0x0ECC #define B_IFS_CLM_EDCCA_EXCLUDE_CCA_FA_MSK GENMASK(31, 16) @@ -8773,6 +8861,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) @@ -9091,6 +9181,7 @@ #define B_COEF_SEL_MDPD BIT(8) #define B_COEF_SEL_MDPD_V1 GENMASK(9, 8) #define B_COEF_SEL_EN BIT(31) +#define R_CFIR_COEF 0x810c #define R_CFIR_SYS 0x8120 #define R_IQK_RES 0x8124 #define B_IQK_RES_K BIT(28) @@ -9266,6 +9357,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..edcbda124916 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, @@ -2415,6 +2537,7 @@ static const struct rtw89_chip_ops rtw8851b_chip_ops = { .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, + .get_ch_dma = rtw89_core_get_ch_dma, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, .mac_cfg_gnt = rtw89_mac_cfg_gnt, .stop_sch_tx = rtw89_mac_stop_sch_tx, @@ -2424,6 +2547,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 +2590,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}, @@ -2500,6 +2629,7 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .support_ant_gain = false, .support_tas = false, .support_sar_by_ant = false, + .support_noise = false, .ul_tb_waveform_ctrl = true, .ul_tb_pwr_diff = false, .rx_freq_frome_ie = true, @@ -2528,7 +2658,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, @@ -2562,6 +2691,8 @@ const struct rtw89_chip_info rtw8851b_chip_info = { .cfo_hw_comp = true, .dcfo_comp = &rtw8851b_dcfo_comp, .dcfo_comp_sft = 12, + .nhm_report = NULL, + .nhm_th = NULL, .imr_info = &rtw8851b_imr_info, .imr_dmac_table = NULL, .imr_cmac_table = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c index f72b3ac6f149..84c46d2f4d85 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851b_rfk.c @@ -12,14 +12,15 @@ #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_RXK_GROUP_IDX_NR 4 +#define RTW8851B_A_TXK_GROUP_NR 2 +#define RTW8851B_G_TXK_GROUP_NR 1 +#define RTW8851B_IQK_VER 0x14 #define RTW8851B_IQK_SS 1 #define RTW8851B_LOK_GRAM 10 #define RTW8851B_TSSI_PATH_NR 1 @@ -85,6 +86,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}; @@ -96,19 +115,21 @@ static const u32 _tssi_de_mcs_10m[RF_PATH_NUM_8851B] = {0x5830}; static const u32 g_idxrxgain[RTW8851B_RXK_GROUP_NR] = {0x10e, 0x116, 0x28e, 0x296}; static const u32 g_idxattc2[RTW8851B_RXK_GROUP_NR] = {0x0, 0xf, 0x0, 0xf}; static const u32 g_idxrxagc[RTW8851B_RXK_GROUP_NR] = {0x0, 0x1, 0x2, 0x3}; -static const u32 a_idxrxgain[RTW8851B_RXK_GROUP_IDX_NR] = {0x10C, 0x28c}; -static const u32 a_idxattc2[RTW8851B_RXK_GROUP_IDX_NR] = {0xf, 0xf}; -static const u32 a_idxrxagc[RTW8851B_RXK_GROUP_IDX_NR] = {0x4, 0x6}; -static const u32 a_power_range[RTW8851B_TXK_GROUP_NR] = {0x0}; -static const u32 a_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; -static const u32 a_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x0a}; -static const u32 a_itqt[RTW8851B_TXK_GROUP_NR] = {0x12}; -static const u32 g_power_range[RTW8851B_TXK_GROUP_NR] = {0x0}; -static const u32 g_track_range[RTW8851B_TXK_GROUP_NR] = {0x6}; -static const u32 g_gain_bb[RTW8851B_TXK_GROUP_NR] = {0x10}; -static const u32 g_itqt[RTW8851B_TXK_GROUP_NR] = {0x12}; - -static const u32 rtw8851b_backup_bb_regs[] = {0xc0d4, 0xc0d8, 0xc0c4, 0xc0ec, 0xc0e8}; +static const u32 a_idxrxgain[RTW8851B_RXK_GROUP_IDX_NR] = {0x10C, 0x112, 0x28c, 0x292}; +static const u32 a_idxattc2[RTW8851B_RXK_GROUP_IDX_NR] = {0xf, 0xf, 0xf, 0xf}; +static const u32 a_idxrxagc[RTW8851B_RXK_GROUP_IDX_NR] = {0x4, 0x5, 0x6, 0x7}; +static const u32 a_power_range[RTW8851B_A_TXK_GROUP_NR] = {0x0, 0x0}; +static const u32 a_track_range[RTW8851B_A_TXK_GROUP_NR] = {0x7, 0x7}; +static const u32 a_gain_bb[RTW8851B_A_TXK_GROUP_NR] = {0x08, 0x0d}; +static const u32 a_itqt[RTW8851B_A_TXK_GROUP_NR] = {0x12, 0x12}; +static const u32 a_att_smxr[RTW8851B_A_TXK_GROUP_NR] = {0x0, 0x2}; +static const u32 g_power_range[RTW8851B_G_TXK_GROUP_NR] = {0x0}; +static const u32 g_track_range[RTW8851B_G_TXK_GROUP_NR] = {0x6}; +static const u32 g_gain_bb[RTW8851B_G_TXK_GROUP_NR] = {0x10}; +static const u32 g_itqt[RTW8851B_G_TXK_GROUP_NR] = {0x12}; + +static const u32 rtw8851b_backup_bb_regs[] = { + 0xc0d4, 0xc0d8, 0xc0c4, 0xc0ec, 0xc0e8, 0x12a0, 0xc0f0}; static const u32 rtw8851b_backup_rf_regs[] = { 0xef, 0xde, 0x0, 0x1e, 0x2, 0x85, 0x90, 0x5}; @@ -116,22 +137,11 @@ 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); -static u8 _rxk_5ghz_group_from_idx(u8 idx) -{ - /* There are four RXK groups (RTW8851B_RXK_GROUP_NR), but only group 0 - * and 2 are used in 5 GHz band, so reduce elements to 2. - */ - if (idx < RTW8851B_RXK_GROUP_IDX_NR) - return idx * 2; - - return 0; -} - static u8 _kpath(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx) { return RF_A; @@ -163,6 +173,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, 0x92}; + 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; @@ -737,7 +792,7 @@ static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, "[IQK]============ S%d ID_NBTXK ============\n", path); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, - 0x00b); + 0x11); iqk_cmd = 0x408 | (1 << (4 + path)); break; case ID_NBRXK: @@ -755,7 +810,7 @@ static bool _iqk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, rtw89_phy_write32_mask(rtwdev, R_NCTL_CFG, MASKDWORD, iqk_cmd + 1); notready = _iqk_check_cal(rtwdev, path); if (iqk_info->iqk_sram_en && - (ktype == ID_NBRXK || ktype == ID_RXK)) + (ktype == ID_NBRXK || ktype == ID_RXK || ktype == ID_NBTXK)) _iqk_sram(rtwdev, path); rtw89_phy_write32_mask(rtwdev, R_UPD_CLK, B_IQK_RFC_ON, 0x0); @@ -842,18 +897,27 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, bool kfail = false; bool notready; u32 rf_0; - u8 idx; + u32 val; u8 gp; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (idx = 0; idx < RTW8851B_RXK_GROUP_IDX_NR; idx++) { - gp = _rxk_5ghz_group_from_idx(idx); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x4); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x17); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x27); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x0); + + val = rtw89_read_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_MASK, 0xc); + for (gp = 0; gp < RTW8851B_RXK_GROUP_IDX_NR; gp++) { rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[idx]); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[idx]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); @@ -863,7 +927,7 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, fsleep(100); rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); - rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[idx]); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); @@ -896,6 +960,7 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, _iqk_sram(rtwdev, path); if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_IQK_RES, B_IQK_RES_RXCFIR, 0x0); rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, iqk_info->nb_rxcfir[path] | 0x2); iqk_info->is_wb_txiqk[path] = false; @@ -905,6 +970,14 @@ static bool _rxk_5g_group_sel(struct rtw89_dev *rtwdev, iqk_info->is_wb_txiqk[path] = true; } + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20, val); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x4); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x37); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x27); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x0); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, kfail = 0x%x, 0x8%x3c = 0x%x\n", path, kfail, 1 << path, iqk_info->nb_rxcfir[path]); @@ -917,17 +990,26 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; bool kfail = false; bool notready; - u8 idx = 0x1; + u8 gp = 2; u32 rf_0; - u8 gp; - - gp = _rxk_5ghz_group_from_idx(idx); + u32 val; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, gp = %x\n", path, gp); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[idx]); - rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[idx]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x4); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x17); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x27); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x0); + + val = rtw89_read_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_MASK, 0xc); + + rtw89_write_rf(rtwdev, RF_PATH_A, RR_MOD, RR_MOD_RGM, a_idxrxgain[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, RR_RXA2_ATT, a_idxattc2[gp]); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x0); @@ -937,7 +1019,7 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, fsleep(100); rf_0 = rtw89_read_rf(rtwdev, path, RR_MOD, RFREG_MASK); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF2, B_IQK_DIF2_RXPI, rf_0); - rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[idx]); + rtw89_phy_write32_mask(rtwdev, R_IQK_RXA, B_IQK_RXAGC, a_idxrxagc[gp]); rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_RXT, 0x11); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_RXAGC); @@ -963,6 +1045,7 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); if (kfail) { + rtw89_phy_write32_mask(rtwdev, R_IQK_RES + (path << 8), 0xf, 0x0); rtw89_phy_write32_mask(rtwdev, R_RXIQC + (path << 8), MASKDWORD, 0x40000002); iqk_info->is_wb_rxiqk[path] = false; @@ -970,6 +1053,14 @@ static bool _iqk_5g_nbrxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, iqk_info->is_wb_rxiqk[path] = false; } + rtw89_write_rf(rtwdev, RF_PATH_A, RR_RXA2, 0x20, val); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x1000); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x4); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x37); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWA, RFREG_MASK, 0x5); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWD0, RFREG_MASK, 0x27); + rtw89_write_rf(rtwdev, RF_PATH_A, RR_LUTWE, RFREG_MASK, 0x0); + rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]S%x, kfail = 0x%x, 0x8%x3c = 0x%x\n", path, kfail, 1 << path, iqk_info->nb_rxcfir[path]); @@ -1044,15 +1135,49 @@ 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, enum rtw89_phy_idx phy_idx, u8 path) { + static const u8 a_idx[RTW8851B_A_TXK_GROUP_NR] = {2, 3}; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; bool kfail = false; bool notready; @@ -1060,16 +1185,20 @@ static bool _txk_5g_group_sel(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + rtw89_phy_write32_mask(rtwdev, R_CFIR_COEF, MASKDWORD, 0x33332222); + + for (gp = 0x0; gp < RTW8851B_A_TXK_GROUP_NR; gp++) { rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + rtw89_write_rf(rtwdev, path, RR_BIASA, RR_BIASA_A, a_att_smxr[gp]); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, gp); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, a_idx[gp]); rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_IQK_DIF4, B_IQK_DIF4_TXT, 0x11); rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, a_itqt[gp]); notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); @@ -1110,7 +1239,9 @@ static bool _txk_2g_group_sel(struct rtw89_dev *rtwdev, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + rtw89_phy_write32_mask(rtwdev, R_CFIR_COEF, MASKDWORD, 0x0); + + for (gp = 0x0; gp < RTW8851B_G_TXK_GROUP_NR; gp++) { rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, g_power_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, g_track_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, g_gain_bb[gp]); @@ -1153,29 +1284,29 @@ static bool _txk_2g_group_sel(struct rtw89_dev *rtwdev, static bool _iqk_5g_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, u8 path) { + static const u8 a_idx[RTW8851B_A_TXK_GROUP_NR] = {2, 3}; struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; bool kfail = false; bool notready; - u8 gp; + u8 gp = 0; rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { - rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); - rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); - rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, a_power_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, a_track_range[gp]); + rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, a_gain_bb[gp]); + rtw89_write_rf(rtwdev, path, RR_BIASA, RR_BIASA_A, a_att_smxr[gp]); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); - rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, gp); - rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); - rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, a_itqt[gp]); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_SEL, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G3, 0x1); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_G2, 0x0); + rtw89_phy_write32_mask(rtwdev, R_CFIR_LUT, B_CFIR_LUT_GP, a_idx[gp]); + rtw89_phy_write32_mask(rtwdev, R_NCTL_N1, B_NCTL_N1_CIP, 0x00); + rtw89_phy_write32_mask(rtwdev, R_KIP_IQP, MASKDWORD, a_itqt[gp]); - notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); - iqk_info->nb_txcfir[path] = - rtw89_phy_read32_mask(rtwdev, R_TXIQC, MASKDWORD) | 0x2; - } + notready = _iqk_one_shot(rtwdev, phy_idx, path, ID_NBTXK); + iqk_info->nb_txcfir[path] = + rtw89_phy_read32_mask(rtwdev, R_TXIQC, MASKDWORD) | 0x2; if (!notready) kfail = !!rtw89_phy_read32_mask(rtwdev, R_NCTL_RPT, B_NCTL_RPT_FLG); @@ -1204,7 +1335,7 @@ static bool _iqk_2g_nbtxk(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy_idx, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[IQK]===>%s\n", __func__); - for (gp = 0x0; gp < RTW8851B_TXK_GROUP_NR; gp++) { + for (gp = 0x0; gp < RTW8851B_G_TXK_GROUP_NR; gp++) { rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR0, g_power_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_GR1, g_track_range[gp]); rtw89_write_rf(rtwdev, path, RR_TXIG, RR_TXIG_TG, g_gain_bb[gp]); @@ -1553,6 +1684,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) @@ -1560,8 +1699,6 @@ static void _iqk_init(struct rtw89_dev *rtwdev) struct rtw89_iqk_info *iqk_info = &rtwdev->iqk; u8 idx, path; - rtw89_phy_write32_mask(rtwdev, R_IQKINF, MASKDWORD, 0x0); - if (iqk_info->is_iqk_init) return; @@ -1794,7 +1931,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 +1978,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 +2036,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 +2438,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 +2474,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 +2576,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 +2639,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 +2657,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..ce59ac9f56ba 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8851be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8851be.c @@ -11,6 +11,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .gen_def = &rtw89_pci_gen_ax, + .isr_def = &rtw89_pci_isr_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -28,6 +29,8 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .rx_ring_eq_is_full = false, .check_rx_tag = false, .no_rxbd_fs = false, + .group_bd_addr = false, + .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt), .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -57,6 +60,7 @@ static const struct rtw89_pci_info rtw8851b_pci_info = { .ltr_set = rtw89_pci_ltr_set, .fill_txaddr_info = rtw89_pci_fill_txaddr_info, + .parse_rpp = rtw89_pci_parse_rpp, .config_intr_mask = rtw89_pci_config_intr_mask, .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, @@ -89,6 +93,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..04e1ab13b753 --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c @@ -0,0 +1,42 @@ +// 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 }, + /* D-Link AX9U rev. A1 */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x332a, 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..232f4c1bee1b 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -426,6 +426,35 @@ static const struct rtw89_reg_def rtw8852a_dcfo_comp = { R_DCFO_COMP_S0, B_DCFO_COMP_S0_MSK }; +static const struct rtw89_reg_def rtw8852a_nhm_th[RTW89_NHM_TH_NUM] = { + {R_NHM_CFG, B_NHM_TH0_MSK}, + {R_NHM_TH1, B_NHM_TH1_MSK}, + {R_NHM_TH1, B_NHM_TH2_MSK}, + {R_NHM_TH1, B_NHM_TH3_MSK}, + {R_NHM_TH1, B_NHM_TH4_MSK}, + {R_NHM_TH5, B_NHM_TH5_MSK}, + {R_NHM_TH5, B_NHM_TH6_MSK}, + {R_NHM_TH5, B_NHM_TH7_MSK}, + {R_NHM_TH5, B_NHM_TH8_MSK}, + {R_NHM_TH9, B_NHM_TH9_MSK}, + {R_NHM_TH9, B_NHM_TH10_MSK}, +}; + +static const struct rtw89_reg_def rtw8852a_nhm_rpt[RTW89_NHM_RPT_NUM] = { + {R_NHM_CNT0, B_NHM_CNT0_MSK}, + {R_NHM_CNT0, B_NHM_CNT1_MSK}, + {R_NHM_CNT2, B_NHM_CNT2_MSK}, + {R_NHM_CNT2, B_NHM_CNT3_MSK}, + {R_NHM_CNT4, B_NHM_CNT4_MSK}, + {R_NHM_CNT4, B_NHM_CNT5_MSK}, + {R_NHM_CNT6, B_NHM_CNT6_MSK}, + {R_NHM_CNT6, B_NHM_CNT7_MSK}, + {R_NHM_CNT8, B_NHM_CNT8_MSK}, + {R_NHM_CNT8, B_NHM_CNT9_MSK}, + {R_NHM_CNT10, B_NHM_CNT10_MSK}, + {R_NHM_CNT10, B_NHM_CNT11_MSK}, +}; + static const struct rtw89_imr_info rtw8852a_imr_info = { .wdrls_imr_set = B_AX_WDRLS_IMR_SET, .wsec_imr_reg = R_AX_SEC_DEBUG, @@ -2080,10 +2109,17 @@ static void rtw8852a_query_ppdu(struct rtw89_dev *rtwdev, { u8 path; u8 *rx_power = phy_ppdu->rssi; + u8 raw; + + if (!status->signal) { + if (phy_ppdu->to_self) + raw = ewma_rssi_read(&rtwdev->phystat.bcn_rssi); + else + raw = max(rx_power[RF_PATH_A], rx_power[RF_PATH_B]); + + status->signal = RTW89_RSSI_RAW_TO_DBM(raw); + } - if (!status->signal) - status->signal = RTW89_RSSI_RAW_TO_DBM(max(rx_power[RF_PATH_A], - rx_power[RF_PATH_B])); for (path = 0; path < rtwdev->chip->rf_path_num; path++) { status->chains |= BIT(path); status->chain_signal[path] = RTW89_RSSI_RAW_TO_DBM(rx_power[path]); @@ -2128,6 +2164,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, @@ -2141,6 +2178,7 @@ static const struct rtw89_chip_ops rtw8852a_chip_ops = { .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, + .get_ch_dma = rtw89_core_get_ch_dma, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, .mac_cfg_gnt = rtw89_mac_cfg_gnt, .stop_sch_tx = rtw89_mac_stop_sch_tx, @@ -2150,6 +2188,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 +2222,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}, @@ -2218,6 +2257,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .support_ant_gain = false, .support_tas = false, .support_sar_by_ant = false, + .support_noise = true, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = false, .rx_freq_frome_ie = true, @@ -2246,7 +2286,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, @@ -2281,6 +2320,8 @@ const struct rtw89_chip_info rtw8852a_chip_info = { .cfo_hw_comp = false, .dcfo_comp = &rtw8852a_dcfo_comp, .dcfo_comp_sft = 10, + .nhm_report = &rtw8852a_nhm_rpt, + .nhm_th = &rtw8852a_nhm_th, .imr_info = &rtw8852a_imr_info, .imr_dmac_table = NULL, .imr_cmac_table = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c index 2037713e3952..9e05e831569d 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ae.c @@ -11,6 +11,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .gen_def = &rtw89_pci_gen_ax, + .isr_def = &rtw89_pci_isr_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -28,6 +29,8 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .rx_ring_eq_is_full = false, .check_rx_tag = false, .no_rxbd_fs = false, + .group_bd_addr = false, + .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt), .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -55,6 +58,7 @@ static const struct rtw89_pci_info rtw8852a_pci_info = { .ltr_set = rtw89_pci_ltr_set, .fill_txaddr_info = rtw89_pci_fill_txaddr_info, + .parse_rpp = rtw89_pci_parse_rpp, .config_intr_mask = rtw89_pci_config_intr_mask, .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, @@ -91,6 +95,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..0777e336aaa1 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, @@ -768,6 +842,7 @@ static const struct rtw89_chip_ops rtw8852b_chip_ops = { .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, + .get_ch_dma = rtw89_core_get_ch_dma, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, .mac_cfg_gnt = rtw89_mac_cfg_gnt, .stop_sch_tx = rtw89_mac_stop_sch_tx, @@ -777,6 +852,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 +868,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 +899,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 +920,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 +929,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), @@ -854,6 +940,7 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .support_ant_gain = true, .support_tas = false, .support_sar_by_ant = true, + .support_noise = false, .ul_tb_waveform_ctrl = true, .ul_tb_pwr_diff = false, .rx_freq_frome_ie = true, @@ -882,7 +969,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, @@ -917,6 +1003,8 @@ const struct rtw89_chip_info rtw8852b_chip_info = { .cfo_hw_comp = true, .dcfo_comp = &rtw8852b_dcfo_comp, .dcfo_comp_sft = 10, + .nhm_report = NULL, + .nhm_th = NULL, .imr_info = &rtw8852b_imr_info, .imr_dmac_table = NULL, .imr_cmac_table = NULL, 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..12db0d0be547 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852be.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852be.c @@ -11,6 +11,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .gen_def = &rtw89_pci_gen_ax, + .isr_def = &rtw89_pci_isr_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -28,6 +29,8 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .rx_ring_eq_is_full = false, .check_rx_tag = false, .no_rxbd_fs = false, + .group_bd_addr = false, + .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt), .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -57,6 +60,7 @@ static const struct rtw89_pci_info rtw8852b_pci_info = { .ltr_set = rtw89_pci_ltr_set, .fill_txaddr_info = rtw89_pci_fill_txaddr_info, + .parse_rpp = rtw89_pci_parse_rpp, .config_intr_mask = rtw89_pci_config_intr_mask, .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, @@ -93,6 +97,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..b3a79ebc7e75 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, @@ -702,6 +708,7 @@ static const struct rtw89_chip_ops rtw8852bt_chip_ops = { .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc, + .get_ch_dma = rtw89_core_get_ch_dma, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path, .mac_cfg_gnt = rtw89_mac_cfg_gnt, .stop_sch_tx = rtw89_mac_stop_sch_tx, @@ -711,6 +718,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 +734,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 +765,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 +780,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 +789,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 +828,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..961b26ba2d3c 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); @@ -1812,22 +1799,14 @@ static void _dpk_onoff(struct rtw89_dev *rtwdev, enum rtw89_rf_path path, bool o { struct rtw89_dpk_info *dpk = &rtwdev->dpk; u8 val, kidx = dpk->cur_idx[path]; - bool off_reverse; val = dpk->is_dpk_enable && !off && dpk->bp[path][kidx].path_ok; - if (off) - off_reverse = false; - else - off_reverse = true; - - val = dpk->is_dpk_enable & off_reverse & dpk->bp[path][kidx].path_ok; - rtw89_phy_write32_mask(rtwdev, R_DPD_CH0A + (path << 8) + (kidx << 2), BIT(24), val); rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] DPK %s !!!\n", path, - kidx, str_enable_disable(dpk->is_dpk_enable & off_reverse)); + kidx, str_enable_disable(dpk->is_dpk_enable && !off)); } static void _dpk_one_shot(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, @@ -1896,8 +1875,8 @@ static void _dpk_information(struct rtw89_dev *rtwdev, enum rtw89_phy_idx phy, rtw89_debug(rtwdev, RTW89_DBG_RFK, "[DPK] S%d[%d] (PHY%d): TSSI %s/ DBCC %s/ %s/ CH%d/ %s\n", path, dpk->cur_idx[path], phy, - rtwdev->is_tssi_mode[path] ? "on" : "off", - rtwdev->dbcc_en ? "on" : "off", + str_on_off(rtwdev->is_tssi_mode[path]), + str_on_off(rtwdev->dbcc_en), dpk->bp[path][kidx].band == 0 ? "2G" : dpk->bp[path][kidx].band == 1 ? "5G" : "6G", dpk->bp[path][kidx].ch, @@ -4252,3 +4231,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..8c995aa95325 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852bte.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bte.c @@ -17,6 +17,7 @@ static const struct rtw89_pci_ssid_quirk rtw8852bt_pci_ssid_quirks[] = { static const struct rtw89_pci_info rtw8852bt_pci_info = { .gen_def = &rtw89_pci_gen_ax, + .isr_def = &rtw89_pci_isr_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -34,6 +35,8 @@ static const struct rtw89_pci_info rtw8852bt_pci_info = { .rx_ring_eq_is_full = false, .check_rx_tag = false, .no_rxbd_fs = false, + .group_bd_addr = false, + .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt), .init_cfg_reg = R_AX_PCIE_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN, @@ -63,6 +66,7 @@ static const struct rtw89_pci_info rtw8852bt_pci_info = { .ltr_set = rtw89_pci_ltr_set, .fill_txaddr_info = rtw89_pci_fill_txaddr_info, + .parse_rpp = rtw89_pci_parse_rpp, .config_intr_mask = rtw89_pci_config_intr_mask, .enable_intr = rtw89_pci_enable_intr, .disable_intr = rtw89_pci_disable_intr, @@ -95,6 +99,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..0694272f7ffa --- /dev/null +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c @@ -0,0 +1,57 @@ +// 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(0x2001, 0x3327, 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..440801d63343 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, @@ -2961,6 +2962,7 @@ static const struct rtw89_chip_ops rtw8852c_chip_ops = { .query_rxdesc = rtw89_core_query_rxdesc, .fill_txdesc = rtw89_core_fill_txdesc_v1, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc_fwcmd_v1, + .get_ch_dma = rtw89_core_get_ch_dma, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path_v1, .mac_cfg_gnt = rtw89_mac_cfg_gnt_v1, .stop_sch_tx = rtw89_mac_stop_sch_tx_v1, @@ -2970,6 +2972,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 +3006,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}, @@ -3041,6 +3044,7 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .support_ant_gain = true, .support_tas = true, .support_sar_by_ant = true, + .support_noise = false, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = true, .rx_freq_frome_ie = false, @@ -3069,7 +3073,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, @@ -3105,6 +3108,8 @@ const struct rtw89_chip_info rtw8852c_chip_info = { .cfo_hw_comp = false, .dcfo_comp = &rtw8852c_dcfo_comp, .dcfo_comp_sft = 12, + .nhm_report = NULL, + .nhm_th = NULL, .imr_info = &rtw8852c_imr_info, .imr_dmac_table = NULL, .imr_cmac_table = NULL, diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c index 5d864fd5974e..150fed189414 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852ce.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852ce.c @@ -20,6 +20,7 @@ static const struct rtw89_pci_bd_idx_addr rtw8852c_bd_idx_addr_low_power = { static const struct rtw89_pci_info rtw8852c_pci_info = { .gen_def = &rtw89_pci_gen_ax, + .isr_def = &rtw89_pci_isr_ax, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -37,6 +38,8 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .rx_ring_eq_is_full = false, .check_rx_tag = false, .no_rxbd_fs = false, + .group_bd_addr = false, + .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt), .init_cfg_reg = R_AX_HAXI_INIT_CFG1, .txhci_en_bit = B_AX_TXHCI_EN_V1, @@ -64,6 +67,7 @@ static const struct rtw89_pci_info rtw8852c_pci_info = { .ltr_set = rtw89_pci_ltr_set_v1, .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, + .parse_rpp = rtw89_pci_parse_rpp, .config_intr_mask = rtw89_pci_config_intr_mask_v1, .enable_intr = rtw89_pci_enable_intr_v1, .disable_intr = rtw89_pci_disable_intr_v1, @@ -118,6 +122,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..6aa19ad259ac 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; @@ -2723,6 +2765,10 @@ static int rtw8922a_mac_disable_bb_rf(struct rtw89_dev *rtwdev) return 0; } +static const struct rtw89_chanctx_listener rtw8922a_chanctx_listener = { + .callbacks[RTW89_CHANCTX_CALLBACK_TAS] = rtw89_tas_chanctx_cb, +}; + #ifdef CONFIG_PM static const struct wiphy_wowlan_support rtw_wowlan_stub_8922a = { .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | @@ -2761,6 +2807,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, @@ -2774,6 +2821,7 @@ static const struct rtw89_chip_ops rtw8922a_chip_ops = { .query_rxdesc = rtw89_core_query_rxdesc_v2, .fill_txdesc = rtw89_core_fill_txdesc_v2, .fill_txdesc_fwcmd = rtw89_core_fill_txdesc_fwcmd_v2, + .get_ch_dma = rtw89_core_get_ch_dma, .cfg_ctrl_path = rtw89_mac_cfg_ctrl_path_v2, .mac_cfg_gnt = rtw89_mac_cfg_gnt_v2, .stop_sch_tx = rtw89_mac_stop_sch_tx_v2, @@ -2783,6 +2831,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 +2865,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}, @@ -2831,6 +2880,7 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .nctl_post_table = NULL, .dflt_parms = NULL, /* load parm from fw */ .rfe_parms_conf = NULL, /* load parm from fw */ + .chanctx_listener = &rtw8922a_chanctx_listener, .txpwr_factor_bb = 3, .txpwr_factor_rf = 2, .txpwr_factor_mac = 1, @@ -2850,8 +2900,9 @@ const struct rtw89_chip_info rtw8922a_chip_info = { BIT(NL80211_CHAN_WIDTH_160), .support_unii4 = true, .support_ant_gain = true, - .support_tas = false, + .support_tas = true, .support_sar_by_ant = true, + .support_noise = false, .ul_tb_waveform_ctrl = false, .ul_tb_pwr_diff = false, .rx_freq_frome_ie = false, @@ -2880,7 +2931,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, @@ -2915,6 +2965,8 @@ const struct rtw89_chip_info rtw8922a_chip_info = { .cfo_hw_comp = true, .dcfo_comp = NULL, .dcfo_comp_sft = 0, + .nhm_report = NULL, + .nhm_th = NULL, .imr_info = NULL, .imr_dmac_table = &rtw8922a_imr_dmac_table, .imr_cmac_table = &rtw8922a_imr_cmac_table, 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..90c62b757c57 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8922ae.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8922ae.c @@ -17,6 +17,7 @@ static const struct rtw89_pci_ssid_quirk rtw8922a_pci_ssid_quirks[] = { static const struct rtw89_pci_info rtw8922a_pci_info = { .gen_def = &rtw89_pci_gen_be, + .isr_def = &rtw89_pci_isr_be, .txbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_trunc_mode = MAC_AX_BD_TRUNC, .rxbd_mode = MAC_AX_RXBD_PKT, @@ -34,6 +35,8 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .rx_ring_eq_is_full = true, .check_rx_tag = true, .no_rxbd_fs = true, + .group_bd_addr = false, + .rpp_fmt_size = sizeof(struct rtw89_pci_rpp_fmt), .init_cfg_reg = R_BE_HAXI_INIT_CFG1, .txhci_en_bit = B_BE_TXDMA_EN, @@ -61,6 +64,7 @@ static const struct rtw89_pci_info rtw8922a_pci_info = { .ltr_set = rtw89_pci_ltr_set_v2, .fill_txaddr_info = rtw89_pci_fill_txaddr_info_v1, + .parse_rpp = rtw89_pci_parse_rpp, .config_intr_mask = rtw89_pci_config_intr_mask_v2, .enable_intr = rtw89_pci_enable_intr_v2, .disable_intr = rtw89_pci_disable_intr_v2, @@ -106,6 +110,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..ef7feccccd5e 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.c +++ b/drivers/net/wireless/realtek/rtw89/sar.c @@ -4,6 +4,7 @@ #include "acpi.h" #include "debug.h" +#include "fw.h" #include "phy.h" #include "reg.h" #include "sar.h" @@ -199,7 +200,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 +501,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; @@ -844,6 +844,20 @@ void rtw89_tas_chanctx_cb(struct rtw89_dev *rtwdev, } EXPORT_SYMBOL(rtw89_tas_chanctx_cb); +void rtw89_tas_fw_timer_enable(struct rtw89_dev *rtwdev, bool enable) +{ + const struct rtw89_chip_info *chip = rtwdev->chip; + struct rtw89_tas_info *tas = &rtwdev->tas; + + if (!tas->enable) + return; + + if (chip->chip_gen == RTW89_CHIP_AX) + return; + + rtw89_fw_h2c_rf_tas_trigger(rtwdev, enable); +} + void rtw89_sar_init(struct rtw89_dev *rtwdev) { rtw89_set_sar_from_acpi(rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/sar.h b/drivers/net/wireless/realtek/rtw89/sar.h index 4b7f3d44f57b..60b3aec5b3be 100644 --- a/drivers/net/wireless/realtek/rtw89/sar.h +++ b/drivers/net/wireless/realtek/rtw89/sar.h @@ -37,6 +37,7 @@ void rtw89_tas_reset(struct rtw89_dev *rtwdev, bool force); void rtw89_tas_scan(struct rtw89_dev *rtwdev, bool start); void rtw89_tas_chanctx_cb(struct rtw89_dev *rtwdev, enum rtw89_chanctx_state state); +void rtw89_tas_fw_timer_enable(struct rtw89_dev *rtwdev, bool enable); void rtw89_sar_init(struct rtw89_dev *rtwdev); void rtw89_sar_track(struct rtw89_dev *rtwdev); diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index 811c91481441..f99e179f7ff9 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -205,7 +205,6 @@ static void rtw89_ser_hdl_work(struct work_struct *work) static int ser_send_msg(struct rtw89_ser *ser, u8 event) { - struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser); struct ser_msg *msg = NULL; if (test_bit(RTW89_SER_DRV_STOP_RUN, ser->flags)) @@ -221,7 +220,7 @@ static int ser_send_msg(struct rtw89_ser *ser, u8 event) list_add(&msg->list, &ser->msg_q); spin_unlock_irq(&ser->msg_q_lock); - ieee80211_queue_work(rtwdev->hw, &ser->ser_hdl_work); + schedule_work(&ser->ser_hdl_work); return 0; } @@ -492,6 +491,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); @@ -501,7 +501,9 @@ static void ser_reset_trx_st_hdl(struct rtw89_ser *ser, u8 evt) } drv_stop_rx(ser); + wiphy_lock(wiphy); drv_trx_reset(ser); + wiphy_unlock(wiphy); /* wait m3 */ hal_send_m2_event(ser); @@ -525,6 +527,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 +570,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 +594,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..984c9fdbb018 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) @@ -571,6 +572,7 @@ struct rtw89_phy_sts_ie00 { } __packed; #define RTW89_PHY_STS_IE00_W0_RPL GENMASK(15, 7) +#define RTW89_PHY_STS_IE00_W3_RX_PATH_EN GENMASK(31, 28) struct rtw89_phy_sts_ie00_v2 { __le32 w0; @@ -731,43 +733,6 @@ rtw89_core_get_qsel_mgmt(struct rtw89_dev *rtwdev, struct rtw89_core_tx_request return RTW89_TX_QSEL_B0_MGMT; } -static inline u8 rtw89_core_get_ch_dma(struct rtw89_dev *rtwdev, u8 qsel) -{ - switch (qsel) { - default: - rtw89_warn(rtwdev, "Cannot map qsel to dma: %d\n", qsel); - fallthrough; - case RTW89_TX_QSEL_BE_0: - case RTW89_TX_QSEL_BE_1: - case RTW89_TX_QSEL_BE_2: - case RTW89_TX_QSEL_BE_3: - return RTW89_TXCH_ACH0; - case RTW89_TX_QSEL_BK_0: - case RTW89_TX_QSEL_BK_1: - case RTW89_TX_QSEL_BK_2: - case RTW89_TX_QSEL_BK_3: - return RTW89_TXCH_ACH1; - case RTW89_TX_QSEL_VI_0: - case RTW89_TX_QSEL_VI_1: - case RTW89_TX_QSEL_VI_2: - case RTW89_TX_QSEL_VI_3: - return RTW89_TXCH_ACH2; - case RTW89_TX_QSEL_VO_0: - case RTW89_TX_QSEL_VO_1: - case RTW89_TX_QSEL_VO_2: - case RTW89_TX_QSEL_VO_3: - return RTW89_TXCH_ACH3; - case RTW89_TX_QSEL_B0_MGMT: - return RTW89_TXCH_CH8; - case RTW89_TX_QSEL_B0_HI: - return RTW89_TXCH_CH9; - case RTW89_TX_QSEL_B1_MGMT: - return RTW89_TXCH_CH10; - case RTW89_TX_QSEL_B1_HI: - return RTW89_TXCH_CH11; - } -} - static inline u8 rtw89_core_get_tid_indicate(struct rtw89_dev *rtwdev, u8 tid) { switch (tid) { 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..5faa51ad896a 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; @@ -99,13 +99,26 @@ static int rtw89_rx_pn_to_iv(struct rtw89_dev *rtwdev, ieee80211_get_key_rx_seq(key, 0, &seq); - /* seq.ccmp.pn[] is BE order array */ - pn = u64_encode_bits(seq.ccmp.pn[0], RTW89_KEY_PN_5) | - u64_encode_bits(seq.ccmp.pn[1], RTW89_KEY_PN_4) | - u64_encode_bits(seq.ccmp.pn[2], RTW89_KEY_PN_3) | - u64_encode_bits(seq.ccmp.pn[3], RTW89_KEY_PN_2) | - u64_encode_bits(seq.ccmp.pn[4], RTW89_KEY_PN_1) | - u64_encode_bits(seq.ccmp.pn[5], RTW89_KEY_PN_0); + switch (key->cipher) { + case WLAN_CIPHER_SUITE_TKIP: + pn = u64_encode_bits(seq.tkip.iv32, RTW89_KEY_TKIP_PN_IV32) | + u64_encode_bits(seq.tkip.iv16, RTW89_KEY_TKIP_PN_IV16); + break; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP_256: + /* seq.ccmp.pn[] is BE order array */ + pn = u64_encode_bits(seq.ccmp.pn[0], RTW89_KEY_PN_5) | + u64_encode_bits(seq.ccmp.pn[1], RTW89_KEY_PN_4) | + u64_encode_bits(seq.ccmp.pn[2], RTW89_KEY_PN_3) | + u64_encode_bits(seq.ccmp.pn[3], RTW89_KEY_PN_2) | + u64_encode_bits(seq.ccmp.pn[4], RTW89_KEY_PN_1) | + u64_encode_bits(seq.ccmp.pn[5], RTW89_KEY_PN_0); + break; + default: + return -EINVAL; + } err = _pn_to_iv(rtwdev, key, iv, pn, key->keyidx); if (err) @@ -177,13 +190,26 @@ static int rtw89_rx_iv_to_pn(struct rtw89_dev *rtwdev, if (err) return err; - /* seq.ccmp.pn[] is BE order array */ - seq.ccmp.pn[0] = u64_get_bits(pn, RTW89_KEY_PN_5); - seq.ccmp.pn[1] = u64_get_bits(pn, RTW89_KEY_PN_4); - seq.ccmp.pn[2] = u64_get_bits(pn, RTW89_KEY_PN_3); - seq.ccmp.pn[3] = u64_get_bits(pn, RTW89_KEY_PN_2); - seq.ccmp.pn[4] = u64_get_bits(pn, RTW89_KEY_PN_1); - seq.ccmp.pn[5] = u64_get_bits(pn, RTW89_KEY_PN_0); + switch (key->cipher) { + case WLAN_CIPHER_SUITE_TKIP: + seq.tkip.iv32 = u64_get_bits(pn, RTW89_KEY_TKIP_PN_IV32); + seq.tkip.iv16 = u64_get_bits(pn, RTW89_KEY_TKIP_PN_IV16); + break; + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_CCMP_256: + case WLAN_CIPHER_SUITE_GCMP_256: + /* seq.ccmp.pn[] is BE order array */ + seq.ccmp.pn[0] = u64_get_bits(pn, RTW89_KEY_PN_5); + seq.ccmp.pn[1] = u64_get_bits(pn, RTW89_KEY_PN_4); + seq.ccmp.pn[2] = u64_get_bits(pn, RTW89_KEY_PN_3); + seq.ccmp.pn[3] = u64_get_bits(pn, RTW89_KEY_PN_2); + seq.ccmp.pn[4] = u64_get_bits(pn, RTW89_KEY_PN_1); + seq.ccmp.pn[5] = u64_get_bits(pn, RTW89_KEY_PN_0); + break; + default: + return -EINVAL; + } ieee80211_set_key_rx_seq(key, 0, &seq); rtw89_debug(rtwdev, RTW89_DBG_WOW, "%s key %d iv-%*ph to pn-%*ph\n", @@ -285,6 +311,11 @@ static void rtw89_wow_get_key_info_iter(struct ieee80211_hw *hw, switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: + if (sta) + memcpy(gtk_info->txmickey, + key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY, + sizeof(gtk_info->txmickey)); + fallthrough; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_CCMP_256: @@ -348,10 +379,27 @@ static void rtw89_wow_set_key_info_iter(struct ieee80211_hw *hw, struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt; struct rtw89_set_key_info_iter_data *iter_data = data; bool update_tx_key_info = iter_data->rx_ready; + u8 tmp[RTW89_MIC_KEY_LEN]; int ret; switch (key->cipher) { case WLAN_CIPHER_SUITE_TKIP: + /* + * TX MIC KEY and RX MIC KEY is oppsite in FW, + * need to swap it before sending to mac80211. + */ + if (!sta && update_tx_key_info && aoac_rpt->rekey_ok && + !iter_data->tkip_gtk_swapped) { + memcpy(tmp, &aoac_rpt->gtk[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + RTW89_MIC_KEY_LEN); + memcpy(&aoac_rpt->gtk[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], + &aoac_rpt->gtk[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + RTW89_MIC_KEY_LEN); + memcpy(&aoac_rpt->gtk[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], + tmp, RTW89_MIC_KEY_LEN); + iter_data->tkip_gtk_swapped = true; + } + fallthrough; case WLAN_CIPHER_SUITE_CCMP: case WLAN_CIPHER_SUITE_GCMP: case WLAN_CIPHER_SUITE_CCMP_256: @@ -619,9 +667,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)) { @@ -639,7 +690,8 @@ static void rtw89_wow_update_key_info(struct rtw89_dev *rtwdev, bool rx_ready) struct rtw89_wow_param *rtw_wow = &rtwdev->wow; struct rtw89_wow_aoac_report *aoac_rpt = &rtw_wow->aoac_rpt; struct rtw89_set_key_info_iter_data data = {.error = false, - .rx_ready = rx_ready}; + .rx_ready = rx_ready, + .tkip_gtk_swapped = false}; struct ieee80211_bss_conf *bss_conf; struct ieee80211_key_conf *key; @@ -1412,6 +1464,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 +1477,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 +1532,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 +1544,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..d2ba6cebc2a6 100644 --- a/drivers/net/wireless/realtek/rtw89/wow.h +++ b/drivers/net/wireless/realtek/rtw89/wow.h @@ -5,6 +5,9 @@ #ifndef __RTW89_WOW_H__ #define __RTW89_WOW_H__ +#define RTW89_KEY_TKIP_PN_IV16 GENMASK_ULL(15, 0) +#define RTW89_KEY_TKIP_PN_IV32 GENMASK_ULL(47, 16) + #define RTW89_KEY_PN_0 GENMASK_ULL(7, 0) #define RTW89_KEY_PN_1 GENMASK_ULL(15, 8) #define RTW89_KEY_PN_2 GENMASK_ULL(23, 16) @@ -25,6 +28,8 @@ #define RTW89_WOW_SYMBOL_CHK_PTK BIT(0) #define RTW89_WOW_SYMBOL_CHK_GTK BIT(1) +#define RTW89_MIC_KEY_LEN 8 + enum rtw89_wake_reason { RTW89_WOW_RSN_RX_PTK_REKEY = 0x1, RTW89_WOW_RSN_RX_GTK_REKEY = 0x2, @@ -73,6 +78,7 @@ struct rtw89_set_key_info_iter_data { u32 igtk_cipher; bool rx_ready; bool error; + bool tkip_gtk_swapped; }; static inline int rtw89_wow_get_sec_hdr_len(struct rtw89_dev *rtwdev) @@ -116,9 +122,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..5d8eaa700779 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; @@ -1290,7 +1291,7 @@ static void cw1200_do_join(struct cw1200_common *priv) rcu_read_lock(); ssidie = ieee80211_bss_get_ie(bss, WLAN_EID_SSID); if (ssidie) { - join.ssid_len = ssidie[1]; + join.ssid_len = min(ssidie[1], IEEE80211_MAX_SSID_LEN); memcpy(join.ssid, &ssidie[2], join.ssid_len); } rcu_read_unlock(); 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..9f856042a67a 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim.c @@ -645,6 +645,7 @@ static LIST_HEAD(hwsim_radios); static struct rhashtable hwsim_radios_rht; static int hwsim_radio_idx; static int hwsim_radios_generation = 1; +static u8 hwsim_nan_cluster_id[ETH_ALEN]; static struct platform_driver mac80211_hwsim_driver = { .driver = { @@ -670,7 +671,7 @@ struct mac80211_hwsim_data { struct ieee80211_channel channels_s1g[ARRAY_SIZE(hwsim_channels_s1g)]; struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; struct ieee80211_iface_combination if_combination; - struct ieee80211_iface_limit if_limits[3]; + struct ieee80211_iface_limit if_limits[4]; int n_if_limits; struct ieee80211_iface_combination if_combination_radio; @@ -679,7 +680,7 @@ struct mac80211_hwsim_data { u32 ciphers[ARRAY_SIZE(hwsim_ciphers)]; - struct mac_address addresses[2]; + struct mac_address addresses[3]; int channels, idx; bool use_chanctx; bool destroy_on_close; @@ -752,6 +753,14 @@ struct mac80211_hwsim_data { struct wireless_dev *pmsr_request_wdev; struct mac80211_hwsim_link_data link_data[IEEE80211_MLD_MAX_NUM_LINKS]; + + struct ieee80211_vif *nan_device_vif; + u8 nan_bands; + + enum nl80211_band nan_curr_dw_band; + struct hrtimer nan_timer; + bool notify_dw; + struct ieee80211_vif *nan_vif; }; static const struct rhashtable_params hwsim_rht_params = { @@ -926,6 +935,7 @@ static const struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = { [HWSIM_ATTR_PMSR_SUPPORT] = NLA_POLICY_NESTED(hwsim_pmsr_capa_policy), [HWSIM_ATTR_PMSR_RESULT] = NLA_POLICY_NESTED(hwsim_pmsr_peers_result_policy), [HWSIM_ATTR_MULTI_RADIO] = { .type = NLA_FLAG }, + [HWSIM_ATTR_SUPPORT_NAN_DEVICE] = { .type = NLA_FLAG }, }; #if IS_REACHABLE(CONFIG_VIRTIO) @@ -1644,6 +1654,16 @@ static void mac80211_hwsim_tx_iter(void *_data, u8 *addr, struct tx_iter_data *data = _data; int i; + /* For NAN Device simulation purposes, assume that NAN is always + * on channel 6 or channel 149. + */ + if (vif->type == NL80211_IFTYPE_NAN) { + data->receive = (data->channel && + (data->channel->center_freq == 2437 || + data->channel->center_freq == 5745)); + return; + } + for (i = 0; i < ARRAY_SIZE(vif->link_conf); i++) { struct ieee80211_bss_conf *conf; struct ieee80211_chanctx_conf *chanctx; @@ -1944,6 +1964,7 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr = (void *)skb->data; struct ieee80211_chanctx_conf *chanctx_conf; struct ieee80211_channel *channel; + struct ieee80211_vif *vif = txi->control.vif; bool ack; enum nl80211_chan_width confbw = NL80211_CHAN_WIDTH_20_NOHT; u32 _portid, i; @@ -1954,7 +1975,23 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, return; } - if (!data->use_chanctx) { + if (vif && vif->type == NL80211_IFTYPE_NAN && !data->tmp_chan) { + /* For NAN Device simulation purposes, assume that NAN is always + * on channel 6 or channel 149, unless a ROC is in progress (for + * USD use cases). + */ + if (data->nan_curr_dw_band == NL80211_BAND_2GHZ) + channel = ieee80211_get_channel(hw->wiphy, 2437); + else if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) + channel = ieee80211_get_channel(hw->wiphy, 5745); + else + channel = NULL; + + if (WARN_ON(!channel)) { + ieee80211_free_txskb(hw, skb); + return; + } + } else if (!data->use_chanctx) { channel = data->channel; confbw = data->bw; } else if (txi->hw_queue == 4) { @@ -1962,7 +1999,6 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, } else { u8 link = u32_get_bits(IEEE80211_SKB_CB(skb)->control.flags, IEEE80211_TX_CTRL_MLO_LINK); - struct ieee80211_vif *vif = txi->control.vif; struct ieee80211_link_sta *link_sta = NULL; struct ieee80211_sta *sta = control->sta; struct ieee80211_bss_conf *bss_conf; @@ -2381,7 +2417,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 +3375,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; } @@ -3948,6 +3986,168 @@ out: return err; } +static enum hrtimer_restart +mac80211_hwsim_nan_dw_start(struct hrtimer *timer) +{ + struct mac80211_hwsim_data *data = + container_of(timer, struct mac80211_hwsim_data, + nan_timer); + struct ieee80211_hw *hw = data->hw; + u64 orig_tsf = mac80211_hwsim_get_tsf(hw, NULL), tsf = orig_tsf; + u32 dw_int = 512 * 1024; + u64 until_dw; + + if (!data->nan_device_vif) + return HRTIMER_NORESTART; + + if (data->nan_bands & BIT(NL80211_BAND_5GHZ)) { + if (data->nan_curr_dw_band == NL80211_BAND_2GHZ) { + dw_int = 128 * 1024; + data->nan_curr_dw_band = NL80211_BAND_5GHZ; + } else if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) { + data->nan_curr_dw_band = NL80211_BAND_2GHZ; + } + } + + until_dw = dw_int - do_div(tsf, dw_int); + + /* The timer might fire just before the actual DW, in which case + * update the timeout to the actual next DW + */ + if (until_dw < dw_int / 2) + until_dw += dw_int; + + /* The above do_div() call directly modifies the 'tsf' variable, thus, + * use a copy so that the print below would show the original TSF. + */ + wiphy_debug(hw->wiphy, + "%s: tsf=%llx, curr_dw_band=%u, next_dw=%llu\n", + __func__, orig_tsf, data->nan_curr_dw_band, + until_dw); + + hrtimer_forward_now(&data->nan_timer, + ns_to_ktime(until_dw * NSEC_PER_USEC)); + + if (data->notify_dw) { + struct ieee80211_channel *ch; + struct wireless_dev *wdev = + ieee80211_vif_to_wdev(data->nan_device_vif); + + if (data->nan_curr_dw_band == NL80211_BAND_5GHZ) + ch = ieee80211_get_channel(hw->wiphy, 5475); + else + ch = ieee80211_get_channel(hw->wiphy, 2437); + + cfg80211_next_nan_dw_notif(wdev, ch, GFP_ATOMIC); + } + + return HRTIMER_RESTART; +} + +static int mac80211_hwsim_start_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf) +{ + struct mac80211_hwsim_data *data = hw->priv; + u64 tsf = mac80211_hwsim_get_tsf(hw, NULL); + u32 dw_int = 512 * 1000; + u64 until_dw = dw_int - do_div(tsf, dw_int); + struct wireless_dev *wdev = ieee80211_vif_to_wdev(vif); + + if (vif->type != NL80211_IFTYPE_NAN) + return -EINVAL; + + if (data->nan_device_vif) + return -EALREADY; + + /* set this before starting the timer, as preemption might occur */ + data->nan_device_vif = vif; + data->nan_bands = conf->bands; + data->nan_curr_dw_band = NL80211_BAND_2GHZ; + + wiphy_debug(hw->wiphy, "nan_started, next_dw=%llu\n", + until_dw); + + hrtimer_start(&data->nan_timer, + ns_to_ktime(until_dw * NSEC_PER_USEC), + HRTIMER_MODE_REL_SOFT); + + if (conf->cluster_id && !is_zero_ether_addr(conf->cluster_id) && + is_zero_ether_addr(hwsim_nan_cluster_id)) { + memcpy(hwsim_nan_cluster_id, conf->cluster_id, ETH_ALEN); + } else if (is_zero_ether_addr(hwsim_nan_cluster_id)) { + hwsim_nan_cluster_id[0] = 0x50; + hwsim_nan_cluster_id[1] = 0x6f; + hwsim_nan_cluster_id[2] = 0x9a; + hwsim_nan_cluster_id[3] = 0x01; + hwsim_nan_cluster_id[4] = get_random_u8(); + hwsim_nan_cluster_id[5] = get_random_u8(); + } + + data->notify_dw = conf->enable_dw_notification; + + cfg80211_nan_cluster_joined(wdev, hwsim_nan_cluster_id, true, + GFP_KERNEL); + + return 0; +} + +static int mac80211_hwsim_stop_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = hw->priv; + struct mac80211_hwsim_data *data2; + bool nan_cluster_running = false; + + if (vif->type != NL80211_IFTYPE_NAN || !data->nan_device_vif || + data->nan_device_vif != vif) + return -EINVAL; + + hrtimer_cancel(&data->nan_timer); + data->nan_device_vif = NULL; + + spin_lock(&hwsim_radio_lock); + list_for_each_entry(data2, &hwsim_radios, list) { + if (data2->nan_device_vif) { + nan_cluster_running = true; + break; + } + } + spin_unlock(&hwsim_radio_lock); + + if (!nan_cluster_running) + memset(hwsim_nan_cluster_id, 0, ETH_ALEN); + + return 0; +} + +static int mac80211_hwsim_change_nan_config(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf, + u32 changes) +{ + struct mac80211_hwsim_data *data = hw->priv; + + if (vif->type != NL80211_IFTYPE_NAN) + return -EINVAL; + + if (!data->nan_device_vif) + return -EINVAL; + + wiphy_debug(hw->wiphy, "nan_config_changed: changes=0x%x\n", changes); + + /* Handle only the changes we care about for simulation purposes */ + if (changes & CFG80211_NAN_CONF_CHANGED_BANDS) { + data->nan_bands = conf->bands; + data->nan_curr_dw_band = NL80211_BAND_2GHZ; + } + + if (changes & CFG80211_NAN_CONF_CHANGED_CONFIG) + data->notify_dw = conf->enable_dw_notification; + + return 0; +} + #ifdef CONFIG_MAC80211_DEBUGFS #define HWSIM_DEBUGFS_OPS \ .link_add_debugfs = mac80211_hwsim_link_add_debugfs, @@ -3980,6 +4180,9 @@ out: .get_et_strings = mac80211_hwsim_get_et_strings, \ .start_pmsr = mac80211_hwsim_start_pmsr, \ .abort_pmsr = mac80211_hwsim_abort_pmsr, \ + .start_nan = mac80211_hwsim_start_nan, \ + .stop_nan = mac80211_hwsim_stop_nan, \ + .nan_change_conf = mac80211_hwsim_change_nan_config, \ HWSIM_DEBUGFS_OPS #define HWSIM_NON_MLO_OPS \ @@ -4045,6 +4248,7 @@ struct hwsim_new_radio_params { u8 n_ciphers; bool mlo; const struct cfg80211_pmsr_capabilities *pmsr_capa; + bool nan_device; }; static void hwsim_mcast_config_msg(struct sk_buff *mcast_skb, @@ -4125,6 +4329,11 @@ static int append_radio_msg(struct sk_buff *skb, int id, return ret; } + if (param->nan_device) { + ret = nla_put_flag(skb, HWSIM_ATTR_SUPPORT_NAN_DEVICE); + if (ret < 0) + return ret; + } return 0; } @@ -5237,14 +5446,18 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, /* Why need here second address ? */ memcpy(data->addresses[1].addr, addr, ETH_ALEN); data->addresses[1].addr[0] |= 0x40; - hw->wiphy->n_addresses = 2; + memcpy(data->addresses[2].addr, addr, ETH_ALEN); + data->addresses[2].addr[0] |= 0x50; + + hw->wiphy->n_addresses = 3; hw->wiphy->addresses = data->addresses; /* possible address clash is checked at hash table insertion */ } else { memcpy(data->addresses[0].addr, param->perm_addr, ETH_ALEN); /* compatibility with automatically generated mac addr */ memcpy(data->addresses[1].addr, param->perm_addr, ETH_ALEN); - hw->wiphy->n_addresses = 2; + memcpy(data->addresses[2].addr, param->perm_addr, ETH_ALEN); + hw->wiphy->n_addresses = 3; hw->wiphy->addresses = data->addresses; } @@ -5281,6 +5494,30 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, n_limits++; } + if (param->iftypes & BIT(NL80211_IFTYPE_NAN)) { + data->if_limits[n_limits].max = 1; + data->if_limits[n_limits].types = BIT(NL80211_IFTYPE_NAN); + n_limits++; + + hw->wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ) | + BIT(NL80211_BAND_5GHZ); + + hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC | + WIPHY_NAN_FLAGS_USERSPACE_DE; + hw->wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK | + NAN_OP_MODE_80P80MHZ | + NAN_OP_MODE_160MHZ; + + hw->wiphy->nan_capa.n_antennas = 0x22; + hw->wiphy->nan_capa.max_channel_switch_time = 0; + hw->wiphy->nan_capa.dev_capabilities = + NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED | + NAN_DEV_CAPA_NDPE_SUPPORTED; + + hrtimer_setup(&data->nan_timer, mac80211_hwsim_nan_dw_start, + CLOCK_MONOTONIC, HRTIMER_MODE_ABS_SOFT); + } + data->if_combination.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_5) | BIT(NL80211_CHAN_WIDTH_10) | @@ -5382,7 +5619,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, @@ -5698,6 +5936,8 @@ static int mac80211_hwsim_get_radio(struct sk_buff *skb, REGULATORY_STRICT_REG); param.p2p_device = !!(data->hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_DEVICE)); + param.nan_device = !!(data->hw->wiphy->interface_modes & + BIT(NL80211_IFTYPE_NAN)); param.use_chanctx = data->use_chanctx; param.regd = data->regd; param.channels = data->channels; @@ -6116,6 +6356,7 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) param.reg_strict = info->attrs[HWSIM_ATTR_REG_STRICT_REG]; param.p2p_device = info->attrs[HWSIM_ATTR_SUPPORT_P2P_DEVICE]; + param.nan_device = info->attrs[HWSIM_ATTR_SUPPORT_NAN_DEVICE]; param.channels = channels; param.destroy_on_close = info->attrs[HWSIM_ATTR_DESTROY_RADIO_ON_CLOSE]; @@ -6187,6 +6428,13 @@ static int hwsim_new_radio_nl(struct sk_buff *msg, struct genl_info *info) param.p2p_device = true; } + /* ensure both flag and iftype support is honored */ + if (param.nan_device || + param.iftypes & BIT(NL80211_IFTYPE_NAN)) { + param.iftypes |= BIT(NL80211_IFTYPE_NAN); + param.nan_device = true; + } + if (info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]) { u32 len = nla_len(info->attrs[HWSIM_ATTR_CIPHER_SUPPORT]); @@ -6907,12 +7155,14 @@ static int __init init_mac80211_hwsim(void) } param.p2p_device = support_p2p_device; + param.nan_device = true; param.mlo = mlo; param.multi_radio = multi_radio; param.use_chanctx = channels > 1 || mlo || multi_radio; param.iftypes = HWSIM_IFTYPE_SUPPORT_MASK; if (param.p2p_device) param.iftypes |= BIT(NL80211_IFTYPE_P2P_DEVICE); + param.iftypes |= BIT(NL80211_IFTYPE_NAN); err = mac80211_hwsim_new_radio(NULL, ¶m); if (err < 0) diff --git a/drivers/net/wireless/virtual/mac80211_hwsim.h b/drivers/net/wireless/virtual/mac80211_hwsim.h index f32fc3a492b0..c2d06cf852a5 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim.h +++ b/drivers/net/wireless/virtual/mac80211_hwsim.h @@ -3,7 +3,7 @@ * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211 * Copyright (c) 2008, Jouni Malinen <j@w1.fi> * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com> - * Copyright (C) 2020, 2022-2024 Intel Corporation + * Copyright (C) 2020, 2022-2025 Intel Corporation */ #ifndef __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) @@ -160,6 +160,7 @@ enum hwsim_commands { * @HWSIM_ATTR_MULTI_RADIO: Register multiple wiphy radios (flag). * Adds one radio for each band. Number of supported channels will be set for * each radio instead of for the wiphy. + * @HWSIM_ATTR_SUPPORT_NAN_DEVICE: support NAN Device virtual interface (flag) * @__HWSIM_ATTR_MAX: enum limit */ enum hwsim_attrs { @@ -193,6 +194,7 @@ enum hwsim_attrs { HWSIM_ATTR_PMSR_REQUEST, HWSIM_ATTR_PMSR_RESULT, HWSIM_ATTR_MULTI_RADIO, + HWSIM_ATTR_SUPPORT_NAN_DEVICE, __HWSIM_ATTR_MAX, }; #define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1) diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c index 1fffeff2190c..4eae89376feb 100644 --- a/drivers/net/wireless/virtual/virt_wifi.c +++ b/drivers/net/wireless/virtual/virt_wifi.c @@ -277,7 +277,9 @@ static void virt_wifi_connect_complete(struct work_struct *work) priv->is_connected = true; /* Schedules an event that acquires the rtnl lock. */ - cfg80211_connect_result(priv->upperdev, requested_bss, NULL, 0, NULL, 0, + cfg80211_connect_result(priv->upperdev, + priv->is_connected ? fake_router_bssid : NULL, + NULL, 0, NULL, 0, status, GFP_KERNEL); netif_carrier_on(priv->upperdev); } 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; } |