diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath12k')
30 files changed, 3414 insertions, 796 deletions
diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile index 62c52e733b..71669f94ff 100644 --- a/drivers/net/wireless/ath/ath12k/Makefile +++ b/drivers/net/wireless/ath/ath12k/Makefile @@ -19,7 +19,9 @@ ath12k-y += core.o \ hw.o \ mhi.o \ pci.o \ - dp_mon.o + dp_mon.o \ + fw.o \ + p2p.o ath12k-$(CONFIG_ATH12K_TRACING) += trace.o diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c index 6c01b282fc..bff4598de4 100644 --- a/drivers/net/wireless/ath/ath12k/core.c +++ b/drivers/net/wireless/ath/ath12k/core.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> @@ -14,6 +14,7 @@ #include "dp_rx.h" #include "debug.h" #include "hif.h" +#include "fw.h" unsigned int ath12k_debug_mask; module_param_named(debug_mask, ath12k_debug_mask, uint, 0644); @@ -104,27 +105,66 @@ int ath12k_core_resume(struct ath12k_base *ab) return 0; } -static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, - size_t name_len) +static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name, + size_t name_len, bool with_variant, + bool bus_type_mode) { /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */ char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = { 0 }; - if (ab->qmi.target.bdf_ext[0] != '\0') + if (with_variant && ab->qmi.target.bdf_ext[0] != '\0') scnprintf(variant, sizeof(variant), ",variant=%s", ab->qmi.target.bdf_ext); - scnprintf(name, name_len, - "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", - ath12k_bus_str(ab->hif.bus), - ab->qmi.target.chip_id, - ab->qmi.target.board_id, variant); + switch (ab->id.bdf_search) { + case ATH12K_BDF_SEARCH_BUS_AND_BOARD: + if (bus_type_mode) + scnprintf(name, name_len, + "bus=%s", + ath12k_bus_str(ab->hif.bus)); + else + scnprintf(name, name_len, + "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s", + ath12k_bus_str(ab->hif.bus), + ab->id.vendor, ab->id.device, + ab->id.subsystem_vendor, + ab->id.subsystem_device, + ab->qmi.target.chip_id, + ab->qmi.target.board_id, + variant); + break; + default: + scnprintf(name, name_len, + "bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s", + ath12k_bus_str(ab->hif.bus), + ab->qmi.target.chip_id, + ab->qmi.target.board_id, variant); + break; + } ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot using board name '%s'\n", name); return 0; } +static int ath12k_core_create_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, true, false); +} + +static int ath12k_core_create_fallback_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, false, false); +} + +static int ath12k_core_create_bus_type_board_name(struct ath12k_base *ab, char *name, + size_t name_len) +{ + return __ath12k_core_create_board_name(ab, name, name_len, false, true); +} + const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab, const char *file) { @@ -159,7 +199,9 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, struct ath12k_board_data *bd, const void *buf, size_t buf_len, const char *boardname, - int bd_ie_type) + int ie_id, + int name_id, + int data_id) { const struct ath12k_fw_ie *hdr; bool name_match_found; @@ -169,7 +211,7 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, name_match_found = false; - /* go through ATH12K_BD_IE_BOARD_ elements */ + /* go through ATH12K_BD_IE_BOARD_/ATH12K_BD_IE_REGDB_ elements */ while (buf_len > sizeof(struct ath12k_fw_ie)) { hdr = buf; board_ie_id = le32_to_cpu(hdr->id); @@ -180,48 +222,50 @@ static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab, buf += sizeof(*hdr); if (buf_len < ALIGN(board_ie_len, 4)) { - ath12k_err(ab, "invalid ATH12K_BD_IE_BOARD length: %zu < %zu\n", + ath12k_err(ab, "invalid %s length: %zu < %zu\n", + ath12k_bd_ie_type_str(ie_id), buf_len, ALIGN(board_ie_len, 4)); ret = -EINVAL; goto out; } - switch (board_ie_id) { - case ATH12K_BD_IE_BOARD_NAME: + if (board_ie_id == name_id) { ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "board name", "", board_ie_data, board_ie_len); if (board_ie_len != strlen(boardname)) - break; + goto next; ret = memcmp(board_ie_data, boardname, strlen(boardname)); if (ret) - break; + goto next; name_match_found = true; ath12k_dbg(ab, ATH12K_DBG_BOOT, - "boot found match for name '%s'", + "boot found match %s for name '%s'", + ath12k_bd_ie_type_str(ie_id), boardname); - break; - case ATH12K_BD_IE_BOARD_DATA: + } else if (board_ie_id == data_id) { if (!name_match_found) /* no match found */ - break; + goto next; ath12k_dbg(ab, ATH12K_DBG_BOOT, - "boot found board data for '%s'", boardname); + "boot found %s for '%s'", + ath12k_bd_ie_type_str(ie_id), + boardname); bd->data = board_ie_data; bd->len = board_ie_len; ret = 0; goto out; - default: - ath12k_warn(ab, "unknown ATH12K_BD_IE_BOARD found: %d\n", + } else { + ath12k_warn(ab, "unknown %s id found: %d\n", + ath12k_bd_ie_type_str(ie_id), board_ie_id); - break; } - +next: /* jump over the padding */ board_ie_len = ALIGN(board_ie_len, 4); @@ -238,7 +282,10 @@ out: static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab, struct ath12k_board_data *bd, - const char *boardname) + const char *boardname, + int ie_id_match, + int name_id, + int data_id) { size_t len, magic_len; const u8 *data; @@ -303,22 +350,23 @@ static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab, goto err; } - switch (ie_id) { - case ATH12K_BD_IE_BOARD: + if (ie_id == ie_id_match) { ret = ath12k_core_parse_bd_ie_board(ab, bd, data, ie_len, boardname, - ATH12K_BD_IE_BOARD); + ie_id_match, + name_id, + data_id); if (ret == -ENOENT) /* no match found, continue */ - break; + goto next; else if (ret) /* there was an error, bail out */ goto err; /* either found or error, so stop searching */ goto out; } - +next: /* jump over the padding */ ie_len = ALIGN(ie_len, 4); @@ -328,8 +376,9 @@ static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab, out: if (!bd->data || !bd->len) { - ath12k_err(ab, - "failed to fetch board data for %s from %s\n", + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "failed to fetch %s for %s from %s\n", + ath12k_bd_ie_type_str(ie_id_match), boardname, filepath); ret = -ENODATA; goto err; @@ -356,28 +405,56 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab, return 0; } -#define BOARD_NAME_SIZE 100 +#define BOARD_NAME_SIZE 200 int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd) { - char boardname[BOARD_NAME_SIZE]; + char boardname[BOARD_NAME_SIZE], fallback_boardname[BOARD_NAME_SIZE]; + char *filename, filepath[100]; int bd_api; int ret; - ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); + filename = ATH12K_BOARD_API2_FILE; + + ret = ath12k_core_create_board_name(ab, boardname, sizeof(boardname)); if (ret) { ath12k_err(ab, "failed to create board name: %d", ret); return ret; } bd_api = 2; - ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname); + ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname, + ATH12K_BD_IE_BOARD, + ATH12K_BD_IE_BOARD_NAME, + ATH12K_BD_IE_BOARD_DATA); + if (!ret) + goto success; + + ret = ath12k_core_create_fallback_board_name(ab, fallback_boardname, + sizeof(fallback_boardname)); + if (ret) { + ath12k_err(ab, "failed to create fallback board name: %d", ret); + return ret; + } + + ret = ath12k_core_fetch_board_data_api_n(ab, bd, fallback_boardname, + ATH12K_BD_IE_BOARD, + ATH12K_BD_IE_BOARD_NAME, + ATH12K_BD_IE_BOARD_DATA); if (!ret) goto success; bd_api = 1; ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_DEFAULT_BOARD_FILE); if (ret) { - ath12k_err(ab, "failed to fetch board-2.bin or board.bin from %s\n", + ath12k_core_create_firmware_path(ab, filename, + filepath, sizeof(filepath)); + ath12k_err(ab, "failed to fetch board data for %s from %s\n", + boardname, filepath); + if (memcmp(boardname, fallback_boardname, strlen(boardname))) + ath12k_err(ab, "failed to fetch board data for %s from %s\n", + fallback_boardname, filepath); + + ath12k_err(ab, "failed to fetch board.bin from %s\n", ab->hw_params->fw.dir); return ret; } @@ -387,6 +464,79 @@ success: return 0; } +int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd) +{ + char boardname[BOARD_NAME_SIZE], default_boardname[BOARD_NAME_SIZE]; + int ret; + + ret = ath12k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE); + if (ret) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "failed to create board name for regdb: %d", ret); + goto exit; + } + + ret = ath12k_core_fetch_board_data_api_n(ab, bd, boardname, + ATH12K_BD_IE_REGDB, + ATH12K_BD_IE_REGDB_NAME, + ATH12K_BD_IE_REGDB_DATA); + if (!ret) + goto exit; + + ret = ath12k_core_create_bus_type_board_name(ab, default_boardname, + BOARD_NAME_SIZE); + if (ret) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "failed to create default board name for regdb: %d", ret); + goto exit; + } + + ret = ath12k_core_fetch_board_data_api_n(ab, bd, default_boardname, + ATH12K_BD_IE_REGDB, + ATH12K_BD_IE_REGDB_NAME, + ATH12K_BD_IE_REGDB_DATA); + if (!ret) + goto exit; + + ret = ath12k_core_fetch_board_data_api_1(ab, bd, ATH12K_REGDB_FILE_NAME); + if (ret) + ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to fetch %s from %s\n", + ATH12K_REGDB_FILE_NAME, ab->hw_params->fw.dir); + +exit: + if (!ret) + ath12k_dbg(ab, ATH12K_DBG_BOOT, "fetched regdb\n"); + + return ret; +} + +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; +} + +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); +} + static void ath12k_core_stop(struct ath12k_base *ab) { if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags)) @@ -592,14 +742,14 @@ static int ath12k_core_start(struct ath12k_base *ab, ath12k_dp_cc_config(ab); - ath12k_dp_pdev_pre_alloc(ab); - ret = ath12k_dp_rx_pdev_reo_setup(ab); if (ret) { ath12k_err(ab, "failed to initialize reo destination rings: %d\n", ret); goto err_mac_destroy; } + ath12k_dp_hal_rx_desc_init(ab); + ret = ath12k_wmi_cmd_init(ab); if (ret) { ath12k_err(ab, "failed to send wmi init cmd: %d\n", ret); @@ -759,20 +909,30 @@ static void ath12k_rfkill_work(struct work_struct *work) { struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work); struct ath12k *ar; + struct ath12k_hw *ah; + struct ieee80211_hw *hw; bool rfkill_radio_on; - int i; + int i, j; spin_lock_bh(&ab->base_lock); rfkill_radio_on = ab->rfkill_radio_on; spin_unlock_bh(&ab->base_lock); - for (i = 0; i < ab->num_radios; i++) { - ar = ab->pdevs[i].ar; - if (!ar) + for (i = 0; i < ab->num_hw; i++) { + ah = ab->ah[i]; + if (!ah) continue; - ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on); - wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on); + for (j = 0; j < ah->num_radio; j++) { + ar = &ah->radio[j]; + if (!ar) + continue; + + ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on); + } + + hw = ah->hw; + wiphy_rfkill_set_hw_state(hw->wiphy, !rfkill_radio_on); } } @@ -801,6 +961,7 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) { struct ath12k *ar; struct ath12k_pdev *pdev; + struct ath12k_hw *ah; int i; spin_lock_bh(&ab->base_lock); @@ -810,16 +971,24 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab) if (ab->is_reset) set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags); + for (i = 0; i < ab->num_hw; i++) { + if (!ab->ah[i]) + continue; + + ah = ab->ah[i]; + ieee80211_stop_queues(ah->hw); + } + for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; ar = pdev->ar; if (!ar || ar->state == ATH12K_STATE_OFF) continue; - ieee80211_stop_queues(ar->hw); ath12k_mac_drain_tx(ar); complete(&ar->scan.started); complete(&ar->scan.completed); + complete(&ar->scan.on_channel); complete(&ar->peer_assoc_done); complete(&ar->peer_delete_done); complete(&ar->install_key_done); @@ -856,7 +1025,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab) case ATH12K_STATE_ON: ar->state = ATH12K_STATE_RESTARTING; ath12k_core_halt(ar); - ieee80211_restart_hw(ar->hw); + ieee80211_restart_hw(ath12k_ar_to_hw(ar)); break; case ATH12K_STATE_OFF: ath12k_warn(ab, @@ -963,7 +1132,6 @@ static void ath12k_core_reset(struct work_struct *work) ATH12K_RECOVER_START_TIMEOUT_HZ); ath12k_hif_power_down(ab); - ath12k_qmi_free_resource(ab); ath12k_hif_power_up(ab); ath12k_dbg(ab, ATH12K_DBG_BOOT, "reset started\n"); @@ -979,6 +1147,8 @@ int ath12k_core_pre_init(struct ath12k_base *ab) return ret; } + ath12k_fw_map(ab); + return 0; } @@ -1007,6 +1177,7 @@ void ath12k_core_deinit(struct ath12k_base *ab) ath12k_hif_power_down(ab); ath12k_mac_destroy(ab); ath12k_core_soc_destroy(ab); + ath12k_fw_unmap(ab); } void ath12k_core_free(struct ath12k_base *ab) @@ -1054,6 +1225,8 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size, ab->dev = dev; ab->hif.bus = bus; + ab->qmi.num_radios = U8_MAX; + ab->slo_capable = true; return ab; diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index 01fb9b2ae4..97e5a0ccd2 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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_CORE_H @@ -13,6 +13,7 @@ #include <linux/bitfield.h> #include <linux/dmi.h> #include <linux/ctype.h> +#include <linux/firmware.h> #include "qmi.h" #include "htc.h" #include "wmi.h" @@ -24,6 +25,7 @@ #include "hal_rx.h" #include "reg.h" #include "dbring.h" +#include "fw.h" #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -55,6 +57,11 @@ #define ATH12K_RECONFIGURE_TIMEOUT_HZ (10 * HZ) #define ATH12K_RECOVER_START_TIMEOUT_HZ (20 * HZ) +enum ath12k_bdf_search { + ATH12K_BDF_SEARCH_DEFAULT, + ATH12K_BDF_SEARCH_BUS_AND_BOARD, +}; + enum wme_ac { WME_AC_BE, WME_AC_BK, @@ -259,6 +266,7 @@ struct ath12k_vif { u8 tx_encap_type; u8 vdev_stats_id; u32 punct_bitmap; + bool ps; }; struct ath12k_vif_iter { @@ -468,7 +476,7 @@ struct ath12k_per_peer_tx_stats { struct ath12k { struct ath12k_base *ab; struct ath12k_pdev *pdev; - struct ieee80211_hw *hw; + struct ath12k_hw *ah; struct ath12k_wmi_pdev *wmi; struct ath12k_pdev_dp dp; u8 mac_addr[ETH_ALEN]; @@ -532,6 +540,7 @@ struct ath12k { /* pdev_idx starts from 0 whereas pdev->pdev_id starts with 1 */ u8 pdev_idx; u8 lmac_id; + u8 hw_link_id; struct completion peer_assoc_done; struct completion peer_delete_done; @@ -591,6 +600,13 @@ struct ath12k { int monitor_vdev_id; }; +struct ath12k_hw { + struct ieee80211_hw *hw; + + u8 num_radio; + struct ath12k radio[] __aligned(sizeof(void *)); +}; + struct ath12k_band_cap { u32 phy_id; u32 max_bw_supported; @@ -724,6 +740,16 @@ struct ath12k_base { u8 fw_pdev_count; struct ath12k_pdev __rcu *pdevs_active[MAX_RADIOS]; + + /* Holds information of wiphy (hw) registration. + * + * In Multi/Single Link Operation case, all pdevs are registered as + * a single wiphy. In other (legacy/Non-MLO) cases, each pdev is + * registered as separate wiphys. + */ + struct ath12k_hw *ah[MAX_RADIOS]; + u8 num_hw; + struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS]; unsigned long long free_vdev_map; unsigned long long free_vdev_stats_id_map; @@ -793,10 +819,44 @@ struct ath12k_base { /* true means radio is on */ bool rfkill_radio_on; + struct { + enum ath12k_bdf_search bdf_search; + u32 vendor; + u32 device; + u32 subsystem_vendor; + u32 subsystem_device; + } id; + + struct { + u32 api_version; + + const struct firmware *fw; + const u8 *amss_data; + size_t amss_len; + const u8 *amss_dualmac_data; + size_t amss_dualmac_len; + const u8 *m3_data; + size_t m3_len; + + DECLARE_BITMAP(fw_features, ATH12K_FW_FEATURE_COUNT); + } fw; + + const struct hal_rx_ops *hal_rx_ops; + + /* slo_capable denotes if the single/multi link operation + * is supported within the same chip (SoC). + */ + bool slo_capable; + /* must be last */ u8 drv_priv[] __aligned(sizeof(void *)); }; +struct ath12k_pdev_map { + struct ath12k_base *ab; + u8 pdev_idx; +}; + int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab); int ath12k_core_pre_init(struct ath12k_base *ab); int ath12k_core_init(struct ath12k_base *ath12k); @@ -810,6 +870,7 @@ int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab, int ath12k_core_fetch_bdf(struct ath12k_base *ath12k, struct ath12k_board_data *bd); void ath12k_core_free_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd); +int ath12k_core_fetch_regdb(struct ath12k_base *ab, struct ath12k_board_data *bd); int ath12k_core_check_dt(struct ath12k_base *ath12k); int ath12k_core_check_smbios(struct ath12k_base *ab); void ath12k_core_halt(struct ath12k *ar); @@ -818,6 +879,9 @@ int ath12k_core_suspend(struct ath12k_base *ab); 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); static inline const char *ath12k_scan_state_str(enum ath12k_scan_state state) { @@ -882,4 +946,18 @@ static inline const char *ath12k_bus_str(enum ath12k_bus bus) return "unknown"; } +static inline struct ath12k_hw *ath12k_hw_to_ah(struct ieee80211_hw *hw) +{ + return hw->priv; +} + +static inline struct ath12k *ath12k_ah_to_ar(struct ath12k_hw *ah) +{ + return ah->radio; +} + +static inline struct ieee80211_hw *ath12k_ar_to_hw(struct ath12k *ar) +{ + return ar->ah->hw; +} #endif /* _CORE_H_ */ diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c index a6f81f2f97..c8e1b244b6 100644 --- a/drivers/net/wireless/ath/ath12k/dp.c +++ b/drivers/net/wireless/ath/ath12k/dp.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <crypto/hash.h> @@ -997,6 +997,29 @@ void ath12k_dp_pdev_pre_alloc(struct ath12k_base *ab) } } +bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab) +{ + if (test_bit(WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS, ab->wmi_ab.svc_map) && + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_mpdu_start && + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_msdu_end && + ab->hw_params->hal_ops->get_hal_rx_compact_ops) { + return true; + } + return false; +} + +void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab) +{ + if (ath12k_dp_wmask_compaction_rx_tlv_supported(ab)) { + /* RX TLVS compaction is supported, hence change the hal_rx_ops + * to compact hal_rx_ops. + */ + ab->hal_rx_ops = ab->hw_params->hal_ops->get_hal_rx_compact_ops(); + } + ab->hal.hal_desc_sz = + ab->hal_rx_ops->rx_desc_get_desc_size(); +} + static void ath12k_dp_service_mon_ring(struct timer_list *t) { struct ath12k_base *ab = from_timer(ab, t, mon_reap_timer); diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h index 1df3cdd461..eb2dd408e0 100644 --- a/drivers/net/wireless/ath/ath12k/dp.h +++ b/drivers/net/wireless/ath/ath12k/dp.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_DP_H @@ -150,7 +150,7 @@ struct ath12k_pdev_dp { #define DP_RX_HASH_ENABLE 1 /* Enable hash based Rx steering */ -#define DP_BA_WIN_SZ_MAX 256 +#define DP_BA_WIN_SZ_MAX 1024 #define DP_TCL_NUM_RING_MAX 4 @@ -170,6 +170,7 @@ struct ath12k_pdev_dp { #define DP_REO_CMD_RING_SIZE 128 #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 @@ -765,6 +766,11 @@ enum htt_stats_internal_ppdu_frametype { #define HTT_RX_RING_SELECTION_CFG_RX_MSDU_START_OFFSET GENMASK(31, 16) #define HTT_RX_RING_SELECTION_CFG_RX_ATTENTION_OFFSET GENMASK(15, 0) +#define HTT_RX_RING_SELECTION_CFG_WORD_MASK_COMPACT_SET BIT(23) +#define HTT_RX_RING_SELECTION_CFG_RX_MPDU_START_MASK GENMASK(15, 0) +#define HTT_RX_RING_SELECTION_CFG_RX_MPDU_END_MASK GENMASK(18, 16) +#define HTT_RX_RING_SELECTION_CFG_RX_MSDU_END_MASK GENMASK(16, 0) + enum htt_rx_filter_tlv_flags { HTT_RX_FILTER_TLV_FLAGS_MPDU_START = BIT(0), HTT_RX_FILTER_TLV_FLAGS_MSDU_START = BIT(1), @@ -1088,6 +1094,11 @@ struct htt_rx_ring_selection_cfg_cmd { __le32 rx_mpdu_offset; __le32 rx_msdu_offset; __le32 rx_attn_offset; + __le32 info2; + __le32 reserved[2]; + __le32 rx_mpdu_start_end_mask; + __le32 rx_msdu_end_word_mask; + __le32 info3; } __packed; struct htt_rx_ring_tlv_filter { @@ -1104,6 +1115,9 @@ struct htt_rx_ring_tlv_filter { u16 rx_msdu_end_offset; u16 rx_msdu_start_offset; u16 rx_attn_offset; + u16 rx_mpdu_start_wmask; + u16 rx_mpdu_end_wmask; + u32 rx_msdu_end_wmask; }; #define HTT_STATS_FRAME_CTRL_TYPE_MGMT 0x0 @@ -1820,4 +1834,6 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab, u32 cookie); struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab, u32 desc_id); +bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab); +void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c index be4b39f5fa..2d56913a75 100644 --- a/drivers/net/wireless/ath/ath12k/dp_mon.c +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "dp_mon.h" @@ -864,7 +864,7 @@ static void ath12k_dp_mon_rx_msdus_set_payload(struct ath12k *ar, struct sk_buff { u32 rx_pkt_offset, l2_hdr_offset; - rx_pkt_offset = ar->ab->hw_params->hal_desc_sz; + rx_pkt_offset = ar->ab->hal.hal_desc_sz; l2_hdr_offset = ath12k_dp_rx_h_l3pad(ar->ab, (struct hal_rx_desc *)msdu->data); skb_pull(msdu, rx_pkt_offset + l2_hdr_offset); @@ -917,7 +917,8 @@ ath12k_dp_mon_rx_merg_msdus(struct ath12k *ar, u8 qos_pkt = 0; rx_desc = (struct hal_rx_desc *)head_msdu->data; - hdr_desc = ab->hw_params->hal_ops->rx_desc_get_msdu_payload(rx_desc); + hdr_desc = + ab->hal_rx_ops->rx_desc_get_msdu_payload(rx_desc); /* Base size */ wh = (struct ieee80211_hdr_3addr *)hdr_desc; @@ -1130,7 +1131,7 @@ static void ath12k_dp_mon_rx_deliver_msdu(struct ath12k *ar, struct napi_struct !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) rx_status->flag |= RX_FLAG_8023; - ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi); } static int ath12k_dp_mon_rx_deliver(struct ath12k *ar, u32 mac_id, diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 1ee83f7659..ca76c018dd 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/ieee80211.h> @@ -23,34 +23,34 @@ static enum hal_encrypt_type ath12k_dp_rx_h_enctype(struct ath12k_base *ab, struct hal_rx_desc *desc) { - if (!ab->hw_params->hal_ops->rx_desc_encrypt_valid(desc)) + if (!ab->hal_rx_ops->rx_desc_encrypt_valid(desc)) return HAL_ENCRYPT_TYPE_OPEN; - return ab->hw_params->hal_ops->rx_desc_get_encrypt_type(desc); + return ab->hal_rx_ops->rx_desc_get_encrypt_type(desc); } u8 ath12k_dp_rx_h_decap_type(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_decap_type(desc); + return ab->hal_rx_ops->rx_desc_get_decap_type(desc); } static u8 ath12k_dp_rx_h_mesh_ctl_present(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mesh_ctl(desc); + return ab->hal_rx_ops->rx_desc_get_mesh_ctl(desc); } static bool ath12k_dp_rx_h_seq_ctrl_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_seq_ctl_vld(desc); } static bool ath12k_dp_rx_h_fc_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_fc_valid(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_fc_valid(desc); } static bool ath12k_dp_rx_h_more_frags(struct ath12k_base *ab, @@ -58,7 +58,7 @@ static bool ath12k_dp_rx_h_more_frags(struct ath12k_base *ab, { struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params->hal_desc_sz); + hdr = (struct ieee80211_hdr *)(skb->data + ab->hal.hal_desc_sz); return ieee80211_has_morefrags(hdr->frame_control); } @@ -67,156 +67,156 @@ static u16 ath12k_dp_rx_h_frag_no(struct ath12k_base *ab, { struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr *)(skb->data + ab->hw_params->hal_desc_sz); + hdr = (struct ieee80211_hdr *)(skb->data + ab->hal.hal_desc_sz); return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG; } static u16 ath12k_dp_rx_h_seq_no(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_start_seq_no(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_start_seq_no(desc); } static bool ath12k_dp_rx_h_msdu_done(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_msdu_done(desc); + return ab->hal_rx_ops->dp_rx_h_msdu_done(desc); } static bool ath12k_dp_rx_h_l4_cksum_fail(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_l4_cksum_fail(desc); + return ab->hal_rx_ops->dp_rx_h_l4_cksum_fail(desc); } static bool ath12k_dp_rx_h_ip_cksum_fail(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_ip_cksum_fail(desc); + return ab->hal_rx_ops->dp_rx_h_ip_cksum_fail(desc); } static bool ath12k_dp_rx_h_is_decrypted(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_is_decrypted(desc); + return ab->hal_rx_ops->dp_rx_h_is_decrypted(desc); } u32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->dp_rx_h_mpdu_err(desc); + return ab->hal_rx_ops->dp_rx_h_mpdu_err(desc); } static u16 ath12k_dp_rx_h_msdu_len(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_len(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_len(desc); } static u8 ath12k_dp_rx_h_sgi(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_sgi(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_sgi(desc); } static u8 ath12k_dp_rx_h_rate_mcs(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_rate_mcs(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_rate_mcs(desc); } static u8 ath12k_dp_rx_h_rx_bw(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_rx_bw(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_rx_bw(desc); } static u32 ath12k_dp_rx_h_freq(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_freq(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_freq(desc); } static u8 ath12k_dp_rx_h_pkt_type(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_msdu_pkt_type(desc); + return ab->hal_rx_ops->rx_desc_get_msdu_pkt_type(desc); } static u8 ath12k_dp_rx_h_nss(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return hweight8(ab->hw_params->hal_ops->rx_desc_get_msdu_nss(desc)); + return hweight8(ab->hal_rx_ops->rx_desc_get_msdu_nss(desc)); } static u8 ath12k_dp_rx_h_tid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_tid(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_tid(desc); } static u16 ath12k_dp_rx_h_peer_id(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_peer_id(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_peer_id(desc); } u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_l3_pad_bytes(desc); + return ab->hal_rx_ops->rx_desc_get_l3_pad_bytes(desc); } static bool ath12k_dp_rx_h_first_msdu(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_first_msdu(desc); + return ab->hal_rx_ops->rx_desc_get_first_msdu(desc); } static bool ath12k_dp_rx_h_last_msdu(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_last_msdu(desc); + return ab->hal_rx_ops->rx_desc_get_last_msdu(desc); } static void ath12k_dp_rx_desc_end_tlv_copy(struct ath12k_base *ab, struct hal_rx_desc *fdesc, struct hal_rx_desc *ldesc) { - ab->hw_params->hal_ops->rx_desc_copy_end_tlv(fdesc, ldesc); + ab->hal_rx_ops->rx_desc_copy_end_tlv(fdesc, ldesc); } static void ath12k_dp_rxdesc_set_msdu_len(struct ath12k_base *ab, struct hal_rx_desc *desc, u16 len) { - ab->hw_params->hal_ops->rx_desc_set_msdu_len(desc, len); + ab->hal_rx_ops->rx_desc_set_msdu_len(desc, len); } static bool ath12k_dp_rx_h_is_da_mcbc(struct ath12k_base *ab, struct hal_rx_desc *desc) { return (ath12k_dp_rx_h_first_msdu(ab, desc) && - ab->hw_params->hal_ops->rx_desc_is_da_mcbc(desc)); + ab->hal_rx_ops->rx_desc_is_da_mcbc(desc)); } static bool ath12k_dp_rxdesc_mac_addr2_valid(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_mac_addr2_valid(desc); + return ab->hal_rx_ops->rx_desc_mac_addr2_valid(desc); } static u8 *ath12k_dp_rxdesc_get_mpdu_start_addr2(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_mpdu_start_addr2(desc); + return ab->hal_rx_ops->rx_desc_mpdu_start_addr2(desc); } static void ath12k_dp_rx_desc_get_dot11_hdr(struct ath12k_base *ab, struct hal_rx_desc *desc, struct ieee80211_hdr *hdr) { - ab->hw_params->hal_ops->rx_desc_get_dot11_hdr(desc, hdr); + ab->hal_rx_ops->rx_desc_get_dot11_hdr(desc, hdr); } static void ath12k_dp_rx_desc_get_crypto_header(struct ath12k_base *ab, @@ -224,13 +224,19 @@ static void ath12k_dp_rx_desc_get_crypto_header(struct ath12k_base *ab, u8 *crypto_hdr, enum hal_encrypt_type enctype) { - ab->hw_params->hal_ops->rx_desc_get_crypto_header(desc, crypto_hdr, enctype); + ab->hal_rx_ops->rx_desc_get_crypto_header(desc, crypto_hdr, enctype); } static u16 ath12k_dp_rxdesc_get_mpdu_frame_ctrl(struct ath12k_base *ab, struct hal_rx_desc *desc) { - return ab->hw_params->hal_ops->rx_desc_get_mpdu_frame_ctl(desc); + return ab->hal_rx_ops->rx_desc_get_mpdu_frame_ctl(desc); +} + +static inline u8 ath12k_dp_rx_get_msdu_src_link(struct ath12k_base *ab, + struct hal_rx_desc *desc) +{ + return ab->hal_rx_ops->rx_desc_get_msdu_src_link_id(desc); } static int ath12k_dp_purge_mon_ring(struct ath12k_base *ab) @@ -1761,7 +1767,7 @@ static int ath12k_dp_rx_msdu_coalesce(struct ath12k *ar, int buf_first_hdr_len, buf_first_len; struct hal_rx_desc *ldesc; int space_extra, rem_len, buf_len; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; /* As the msdu is spread across multiple rx buffers, * find the offset to the start of msdu for computing @@ -2458,7 +2464,7 @@ static void ath12k_dp_rx_deliver_msdu(struct ath12k *ar, struct napi_struct *nap !(is_mcbc && rx_status->flag & RX_FLAG_DECRYPTED)) rx_status->flag |= RX_FLAG_8023; - ieee80211_rx_napi(ar->hw, pubsta, msdu, napi); + ieee80211_rx_napi(ath12k_ar_to_hw(ar), pubsta, msdu, napi); } static int ath12k_dp_rx_process_msdu(struct ath12k *ar, @@ -2473,7 +2479,7 @@ static int ath12k_dp_rx_process_msdu(struct ath12k *ar, u8 l3_pad_bytes; u16 msdu_len; int ret; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; last_buf = ath12k_dp_rx_get_msdu_last_buf(msdu_list, msdu); if (!last_buf) { @@ -2804,7 +2810,7 @@ static int ath12k_dp_rx_h_verify_tkip_mic(struct ath12k *ar, struct ath12k_peer u8 mic[IEEE80211_CCMP_MIC_LEN]; int head_len, tail_len, ret; size_t data_len; - u32 hdr_len, hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hdr_len, hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; u8 *key, *data; u8 key_idx; @@ -2844,7 +2850,7 @@ mic_fail: ath12k_dp_rx_h_ppdu(ar, rx_desc, rxs); ath12k_dp_rx_h_undecap(ar, msdu, rx_desc, HAL_ENCRYPT_TYPE_TKIP_MIC, rxs, true); - ieee80211_rx(ar->hw, msdu); + ieee80211_rx(ath12k_ar_to_hw(ar), msdu); return -EINVAL; } @@ -2854,7 +2860,7 @@ static void ath12k_dp_rx_h_undecap_frag(struct ath12k *ar, struct sk_buff *msdu, struct ieee80211_hdr *hdr; size_t hdr_len; size_t crypto_len; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; if (!flags) return; @@ -2892,7 +2898,7 @@ static int ath12k_dp_rx_h_defrag(struct ath12k *ar, bool is_decrypted = false; int msdu_len = 0; int extra_space; - u32 flags, hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 flags, hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; first_frag = skb_peek(&rx_tid->rx_frags); last_frag = skb_peek_tail(&rx_tid->rx_frags); @@ -2968,7 +2974,7 @@ static int ath12k_dp_rx_h_defrag_reo_reinject(struct ath12k *ar, struct ath12k_rx_desc_info *desc_info; u8 dst_ind; - hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + hal_rx_desc_sz = ab->hal.hal_desc_sz; link_desc_banks = dp->link_desc_banks; reo_dest_ring = rx_tid->dst_ring_desc; @@ -3122,7 +3128,7 @@ static u64 ath12k_dp_rx_h_get_pn(struct ath12k *ar, struct sk_buff *skb) struct ieee80211_hdr *hdr; u64 pn = 0; u8 *ehdr; - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; hdr = (struct ieee80211_hdr *)(skb->data + hal_rx_desc_sz); ehdr = skb->data + hal_rx_desc_sz + ieee80211_hdrlen(hdr->frame_control); @@ -3305,7 +3311,7 @@ ath12k_dp_process_rx_err_buf(struct ath12k *ar, struct hal_reo_dest_ring *desc, struct ath12k_skb_rxcb *rxcb; struct hal_rx_desc *rx_desc; u16 msdu_len; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; struct ath12k_rx_desc_info *desc_info; u64 desc_va; @@ -3486,7 +3492,7 @@ static void ath12k_dp_rx_null_q_desc_sg_drop(struct ath12k *ar, int n_buffs; n_buffs = DIV_ROUND_UP(msdu_len, - (DP_RX_BUFFER_SIZE - ar->ab->hw_params->hal_desc_sz)); + (DP_RX_BUFFER_SIZE - ar->ab->hal.hal_desc_sz)); skb_queue_walk_safe(msdu_list, skb, tmp) { rxcb = ATH12K_SKB_RXCB(skb); @@ -3510,7 +3516,7 @@ static int ath12k_dp_rx_h_null_q_desc(struct ath12k *ar, struct sk_buff *msdu, struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; u8 l3pad_bytes; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; msdu_len = ath12k_dp_rx_h_msdu_len(ab, desc); @@ -3607,7 +3613,7 @@ static void ath12k_dp_rx_h_tkip_mic_err(struct ath12k *ar, struct sk_buff *msdu, struct hal_rx_desc *desc = (struct hal_rx_desc *)msdu->data; u8 l3pad_bytes; struct ath12k_skb_rxcb *rxcb = ATH12K_SKB_RXCB(msdu); - u32 hal_rx_desc_sz = ar->ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ar->ab->hal.hal_desc_sz; rxcb->is_first_msdu = ath12k_dp_rx_h_first_msdu(ab, desc); rxcb->is_last_msdu = ath12k_dp_rx_h_last_msdu(ab, desc); @@ -3695,16 +3701,15 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, struct hal_rx_wbm_rel_info err_info; struct hal_srng *srng; struct sk_buff *msdu; - struct sk_buff_head msdu_list[MAX_RADIOS]; + struct sk_buff_head msdu_list; struct ath12k_skb_rxcb *rxcb; void *rx_desc; - int mac_id; + u8 mac_id; int num_buffs_reaped = 0; struct ath12k_rx_desc_info *desc_info; - int ret, i; + int ret, pdev_id; - for (i = 0; i < ab->num_radios; i++) - __skb_queue_head_init(&msdu_list[i]); + __skb_queue_head_init(&msdu_list); srng = &ab->hal.srng_list[dp->rx_rel_ring.ring_id]; rx_ring = &dp->rx_refill_buf_ring; @@ -3737,11 +3742,6 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, } } - /* FIXME: Extract mac id correctly. Since descs are not tied - * to mac, we can extract from vdev id in ring desc. - */ - mac_id = 0; - if (desc_info->magic != ATH12K_DP_RX_DESC_MAGIC) ath12k_warn(ab, "WBM RX err, Check HW CC implementation"); @@ -3771,7 +3771,8 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, rxcb->err_rel_src = err_info.err_rel_src; rxcb->err_code = err_info.err_code; rxcb->rx_desc = (struct hal_rx_desc *)msdu->data; - __skb_queue_tail(&msdu_list[mac_id], msdu); + + __skb_queue_tail(&msdu_list, msdu); rxcb->is_first_msdu = err_info.first_msdu; rxcb->is_last_msdu = err_info.last_msdu; @@ -3788,21 +3789,22 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab, ath12k_dp_rx_bufs_replenish(ab, rx_ring, num_buffs_reaped); rcu_read_lock(); - for (i = 0; i < ab->num_radios; i++) { - if (!rcu_dereference(ab->pdevs_active[i])) { - __skb_queue_purge(&msdu_list[i]); + while ((msdu = __skb_dequeue(&msdu_list))) { + mac_id = ath12k_dp_rx_get_msdu_src_link(ab, + (struct hal_rx_desc *)msdu->data); + pdev_id = ath12k_hw_mac_id_to_pdev_id(ab->hw_params, mac_id); + ar = ab->pdevs[pdev_id].ar; + + if (!ar || !rcu_dereference(ar->ab->pdevs_active[mac_id])) { + dev_kfree_skb_any(msdu); continue; } - ar = ab->pdevs[i].ar; - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { - __skb_queue_purge(&msdu_list[i]); + dev_kfree_skb_any(msdu); continue; } - - while ((msdu = __skb_dequeue(&msdu_list[i])) != NULL) - ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list[i]); + ath12k_dp_rx_wbm_err(ar, napi, msdu, &msdu_list); } rcu_read_unlock(); done: @@ -3922,7 +3924,7 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 ring_id; int ret; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; @@ -3935,14 +3937,20 @@ int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab) tlv_filter.rx_packet_offset = hal_rx_desc_sz; tlv_filter.rx_mpdu_start_offset = - ab->hw_params->hal_ops->rx_desc_get_mpdu_start_offset(); + ab->hal_rx_ops->rx_desc_get_mpdu_start_offset(); tlv_filter.rx_msdu_end_offset = - ab->hw_params->hal_ops->rx_desc_get_msdu_end_offset(); + ab->hal_rx_ops->rx_desc_get_msdu_end_offset(); + + if (ath12k_dp_wmask_compaction_rx_tlv_supported(ab)) { + tlv_filter.rx_mpdu_start_wmask = + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_mpdu_start(); + tlv_filter.rx_msdu_end_wmask = + ab->hw_params->hal_ops->rxdma_ring_wmask_rx_msdu_end(); + ath12k_dbg(ab, ATH12K_DBG_DATA, + "Configuring compact tlv masks rx_mpdu_start_wmask 0x%x rx_msdu_end_wmask 0x%x\n", + tlv_filter.rx_mpdu_start_wmask, tlv_filter.rx_msdu_end_wmask); + } - /* TODO: Selectively subscribe to required qwords within msdu_end - * and mpdu_start and setup the mask in below msg - * and modify the rx_desc struct - */ ret = ath12k_dp_tx_htt_rx_filter_setup(ab, ring_id, 0, HAL_RXDMA_BUF, DP_RXDMA_REFILL_RING_SIZE, @@ -3957,7 +3965,7 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) struct htt_rx_ring_tlv_filter tlv_filter = {0}; u32 ring_id; int ret; - u32 hal_rx_desc_sz = ab->hw_params->hal_desc_sz; + u32 hal_rx_desc_sz = ab->hal.hal_desc_sz; int i; ring_id = dp->rx_refill_buf_ring.refill_buf_ring.ring_id; @@ -3973,9 +3981,9 @@ int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab) tlv_filter.rx_header_offset = offsetof(struct hal_rx_desc_wcn7850, pkt_hdr_tlv); tlv_filter.rx_mpdu_start_offset = - ab->hw_params->hal_ops->rx_desc_get_mpdu_start_offset(); + ab->hal_rx_ops->rx_desc_get_mpdu_start_offset(); tlv_filter.rx_msdu_end_offset = - ab->hw_params->hal_ops->rx_desc_get_msdu_end_offset(); + ab->hal_rx_ops->rx_desc_get_msdu_end_offset(); /* TODO: Selectively subscribe to required qwords within msdu_end * and mpdu_start and setup the mask in below msg @@ -4086,7 +4094,7 @@ int ath12k_dp_rx_alloc(struct ath12k_base *ab) ret = ath12k_dp_srng_setup(ab, &dp->rx_mac_buf_ring[i], HAL_RXDMA_BUF, 1, - i, 1024); + i, DP_RX_MAC_BUF_RING_SIZE); if (ret) { ath12k_warn(ab, "failed to setup rx_mac_buf_ring %d\n", i); diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c index 62f9cdbb81..572b871536 100644 --- a/drivers/net/wireless/ath/ath12k/dp_tx.c +++ b/drivers/net/wireless/ath/ath12k/dp_tx.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "core.h" @@ -151,7 +151,7 @@ int ath12k_dp_tx(struct ath12k *ar, struct ath12k_vif *arvif, if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && !ieee80211_is_data(hdr->frame_control)) - return -ENOTSUPP; + return -EOPNOTSUPP; pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1); @@ -401,7 +401,7 @@ ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_base *ab, } } - ieee80211_tx_status_skb(ar->hw, msdu); + ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu); } static void @@ -498,7 +498,7 @@ static void ath12k_dp_tx_complete_msdu(struct ath12k *ar, * Might end up reporting it out-of-band from HTT stats. */ - ieee80211_tx_status_skb(ar->hw, msdu); + ieee80211_tx_status_skb(ath12k_ar_to_hw(ar), msdu); exit: rcu_read_unlock(); @@ -837,7 +837,7 @@ int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab) if (dp->htt_tgt_ver_major != HTT_TARGET_VERSION_MAJOR) { ath12k_err(ab, "unsupported htt major version %d supported version is %d\n", dp->htt_tgt_ver_major, HTT_TARGET_VERSION_MAJOR); - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; @@ -964,6 +964,26 @@ int ath12k_dp_tx_htt_rx_filter_setup(struct ath12k_base *ab, u32 ring_id, HTT_RX_RING_SELECTION_CFG_RX_ATTENTION_OFFSET); } + if (tlv_filter->rx_mpdu_start_wmask > 0 && + tlv_filter->rx_msdu_end_wmask > 0) { + cmd->info2 |= + le32_encode_bits(true, + HTT_RX_RING_SELECTION_CFG_WORD_MASK_COMPACT_SET); + cmd->rx_mpdu_start_end_mask = + le32_encode_bits(tlv_filter->rx_mpdu_start_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MPDU_START_MASK); + /* mpdu_end is not used for any hardwares so far + * please assign it in future if any chip is + * using through hal ops + */ + cmd->rx_mpdu_start_end_mask |= + le32_encode_bits(tlv_filter->rx_mpdu_end_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MPDU_END_MASK); + cmd->rx_msdu_end_word_mask = + le32_encode_bits(tlv_filter->rx_msdu_end_wmask, + HTT_RX_RING_SELECTION_CFG_RX_MSDU_END_MASK); + } + ret = ath12k_htc_send(&ab->htc, ab->dp.eid, skb); if (ret) goto err_free; diff --git a/drivers/net/wireless/ath/ath12k/fw.c b/drivers/net/wireless/ath/ath12k/fw.c new file mode 100644 index 0000000000..5be4b2d4a1 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/fw.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include "core.h" + +#include "debug.h" + +static int ath12k_fw_request_firmware_api_n(struct ath12k_base *ab, + const char *name) +{ + size_t magic_len, len, ie_len; + int ie_id, i, index, bit, ret; + struct ath12k_fw_ie *hdr; + const u8 *data; + __le32 *timestamp; + + ab->fw.fw = ath12k_core_firmware_request(ab, name); + if (IS_ERR(ab->fw.fw)) { + ret = PTR_ERR(ab->fw.fw); + ath12k_dbg(ab, ATH12K_DBG_BOOT, "failed to load %s: %d\n", name, ret); + ab->fw.fw = NULL; + return ret; + } + + data = ab->fw.fw->data; + len = ab->fw.fw->size; + + /* magic also includes the null byte, check that as well */ + magic_len = strlen(ATH12K_FIRMWARE_MAGIC) + 1; + + if (len < magic_len) { + ath12k_err(ab, "firmware image too small to contain magic: %zu\n", + len); + ret = -EINVAL; + goto err; + } + + if (memcmp(data, ATH12K_FIRMWARE_MAGIC, magic_len) != 0) { + ath12k_err(ab, "Invalid firmware magic\n"); + ret = -EINVAL; + goto err; + } + + /* jump over the padding */ + magic_len = ALIGN(magic_len, 4); + + /* make sure there's space for padding */ + if (magic_len > len) { + ath12k_err(ab, "No space for padding after magic\n"); + ret = -EINVAL; + goto err; + } + + len -= magic_len; + data += magic_len; + + /* loop elements */ + while (len > sizeof(struct ath12k_fw_ie)) { + hdr = (struct ath12k_fw_ie *)data; + + ie_id = le32_to_cpu(hdr->id); + ie_len = le32_to_cpu(hdr->len); + + len -= sizeof(*hdr); + data += sizeof(*hdr); + + if (len < ie_len) { + ath12k_err(ab, "Invalid length for FW IE %d (%zu < %zu)\n", + ie_id, len, ie_len); + ret = -EINVAL; + goto err; + } + + switch (ie_id) { + case ATH12K_FW_IE_TIMESTAMP: + if (ie_len != sizeof(u32)) + break; + + timestamp = (__le32 *)data; + + ath12k_dbg(ab, ATH12K_DBG_BOOT, "found fw timestamp %d\n", + le32_to_cpup(timestamp)); + break; + case ATH12K_FW_IE_FEATURES: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found firmware features ie (%zd B)\n", + ie_len); + + for (i = 0; i < ATH12K_FW_FEATURE_COUNT; i++) { + index = i / 8; + bit = i % 8; + + if (index == ie_len) + break; + + if (data[index] & (1 << bit)) + __set_bit(i, ab->fw.fw_features); + } + + ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "features", "", + ab->fw.fw_features, + sizeof(ab->fw.fw_features)); + break; + case ATH12K_FW_IE_AMSS_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found fw image ie (%zd B)\n", + ie_len); + + ab->fw.amss_data = data; + ab->fw.amss_len = ie_len; + break; + case ATH12K_FW_IE_M3_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found m3 image ie (%zd B)\n", + ie_len); + + ab->fw.m3_data = data; + ab->fw.m3_len = ie_len; + break; + case ATH12K_FW_IE_AMSS_DUALMAC_IMAGE: + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "found dualmac fw image ie (%zd B)\n", + ie_len); + ab->fw.amss_dualmac_data = data; + ab->fw.amss_dualmac_len = ie_len; + break; + default: + ath12k_warn(ab, "Unknown FW IE: %u\n", ie_id); + break; + } + + /* jump over the padding */ + ie_len = ALIGN(ie_len, 4); + + /* make sure there's space for padding */ + if (ie_len > len) + break; + + len -= ie_len; + data += ie_len; + } + + return 0; + +err: + release_firmware(ab->fw.fw); + ab->fw.fw = NULL; + return ret; +} + +void ath12k_fw_map(struct ath12k_base *ab) +{ + int ret; + + ret = ath12k_fw_request_firmware_api_n(ab, ATH12K_FW_API2_FILE); + if (ret == 0) + ab->fw.api_version = 2; + else + ab->fw.api_version = 1; + + ath12k_dbg(ab, ATH12K_DBG_BOOT, "using fw api %d\n", + ab->fw.api_version); +} + +void ath12k_fw_unmap(struct ath12k_base *ab) +{ + release_firmware(ab->fw.fw); + memset(&ab->fw, 0, sizeof(ab->fw)); +} diff --git a/drivers/net/wireless/ath/ath12k/fw.h b/drivers/net/wireless/ath/ath12k/fw.h new file mode 100644 index 0000000000..3ff041f15f --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/fw.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#ifndef ATH12K_FW_H +#define ATH12K_FW_H + +#define ATH12K_FW_API2_FILE "firmware-2.bin" +#define ATH12K_FIRMWARE_MAGIC "QCOM-ATH12K-FW" + +enum ath12k_fw_ie_type { + ATH12K_FW_IE_TIMESTAMP = 0, + ATH12K_FW_IE_FEATURES = 1, + ATH12K_FW_IE_AMSS_IMAGE = 2, + ATH12K_FW_IE_M3_IMAGE = 3, + ATH12K_FW_IE_AMSS_DUALMAC_IMAGE = 4, +}; + +enum ath12k_fw_features { + /* The firmware supports setting the QRTR id via register + * PCIE_LOCAL_REG_QRTR_NODE_ID + */ + ATH12K_FW_FEATURE_MULTI_QRTR_ID = 0, + + /* keep last */ + ATH12K_FW_FEATURE_COUNT, +}; + +void ath12k_fw_map(struct ath12k_base *ab); +void ath12k_fw_unmap(struct ath12k_base *ab); + +#endif /* ATH12K_FW_H */ diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c index 1bdab8604d..78310da8cf 100644 --- a/drivers/net/wireless/ath/ath12k/hal.c +++ b/drivers/net/wireless/ath/ath12k/hal.c @@ -626,6 +626,21 @@ static int ath12k_hal_srng_create_config_qcn9274(struct ath12k_base *ab) return 0; } +static u16 ath12k_hal_qcn9274_rx_mpdu_start_wmask_get(void) +{ + return QCN9274_MPDU_START_WMASK; +} + +static u32 ath12k_hal_qcn9274_rx_msdu_end_wmask_get(void) +{ + return QCN9274_MSDU_END_WMASK; +} + +static const struct hal_rx_ops *ath12k_hal_qcn9274_get_hal_rx_compact_ops(void) +{ + return &hal_rx_qcn9274_compact_ops; +} + static bool ath12k_hw_qcn9274_dp_rx_h_msdu_done(struct hal_rx_desc *desc) { return !!le32_get_bits(desc->u.qcn9274.msdu_end.info14, @@ -680,7 +695,17 @@ static u32 ath12k_hw_qcn9274_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } -const struct hal_ops hal_qcn9274_ops = { +static u32 ath12k_hw_qcn9274_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_qcn9274); +} + +static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return 0; +} + +const struct hal_rx_ops hal_rx_qcn9274_ops = { .rx_desc_get_first_msdu = ath12k_hw_qcn9274_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_qcn9274_rx_desc_get_last_msdu, .rx_desc_get_l3_pad_bytes = ath12k_hw_qcn9274_rx_desc_get_l3_pad_bytes, @@ -712,13 +737,367 @@ const struct hal_ops hal_qcn9274_ops = { .rx_desc_get_dot11_hdr = ath12k_hw_qcn9274_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_qcn9274_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_qcn9274_rx_desc_get_mpdu_frame_ctl, - .create_srng_config = ath12k_hal_srng_create_config_qcn9274, - .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, .dp_rx_h_msdu_done = ath12k_hw_qcn9274_dp_rx_h_msdu_done, .dp_rx_h_l4_cksum_fail = ath12k_hw_qcn9274_dp_rx_h_l4_cksum_fail, .dp_rx_h_ip_cksum_fail = ath12k_hw_qcn9274_dp_rx_h_ip_cksum_fail, .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_qcn9274_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = ath12k_hw_qcn9274_rx_desc_get_msdu_src_link, +}; + +static bool ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_FIRST_MSDU); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_get_last_msdu(struct hal_rx_desc *desc) +{ + return !!le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_LAST_MSDU); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_l3_pad_bytes(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_INFO5_L3_HDR_PADDING); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_encrypt_valid(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_ENCRYPT_INFO_VALID); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_encrypt_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info2, + RX_MPDU_START_INFO2_ENC_TYPE); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_decap_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info11, + RX_MSDU_END_INFO11_DECAP_FORMAT); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mesh_ctl(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274.msdu_end.info11, + RX_MSDU_END_INFO11_MESH_CTRL_PRESENT); +} + +static bool +ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_seq_ctl_vld(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_CTRL_VALID); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_fc_valid(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_FCTRL_VALID); +} + +static u16 +ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_seq_no(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info4, + RX_MPDU_START_INFO4_MPDU_SEQ_NUM); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_len(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info10, + RX_MSDU_END_INFO10_MSDU_LENGTH); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_sgi(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_SGI); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rate_mcs(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_RATE_MCS); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rx_bw(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_RECV_BW); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_freq(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.phy_meta_data); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_INFO12_PKT_TYPE); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss(struct hal_rx_desc *desc) +{ + return le32_get_bits(desc->u.qcn9274_compact.msdu_end.info12, + RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc) +{ + return le16_get_bits(desc->u.qcn9274_compact.msdu_end.info5, + RX_MSDU_END_QCN9274_INFO5_TID); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.sw_peer_id); +} + +static void ath12k_hw_qcn9274_compact_rx_desc_copy_end_tlv(struct hal_rx_desc *fdesc, + struct hal_rx_desc *ldesc) +{ + fdesc->u.qcn9274_compact.msdu_end = ldesc->u.qcn9274_compact.msdu_end; +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_ppdu_id(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.phy_ppdu_id); +} + +static void +ath12k_hw_qcn9274_compact_rx_desc_set_msdu_len(struct hal_rx_desc *desc, u16 len) +{ + u32 info = __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.info10); + + info = u32_replace_bits(info, len, RX_MSDU_END_INFO10_MSDU_LENGTH); + desc->u.qcn9274_compact.msdu_end.info10 = __cpu_to_le32(info); +} + +static u8 *ath12k_hw_qcn9274_compact_rx_desc_get_msdu_payload(struct hal_rx_desc *desc) +{ + return &desc->u.qcn9274_compact.msdu_payload[0]; +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_offset(void) +{ + return offsetof(struct hal_rx_desc_qcn9274_compact, mpdu_start); +} + +static u32 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_end_offset(void) +{ + return offsetof(struct hal_rx_desc_qcn9274_compact, msdu_end); +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_mac_addr2_valid(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR2_VALID; +} + +static u8 *ath12k_hw_qcn9274_compact_rx_desc_mpdu_start_addr2(struct hal_rx_desc *desc) +{ + return desc->u.qcn9274_compact.mpdu_start.addr2; +} + +static bool ath12k_hw_qcn9274_compact_rx_desc_is_da_mcbc(struct hal_rx_desc *desc) +{ + return __le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info6) & + RX_MPDU_START_INFO6_MCAST_BCAST; +} + +static void ath12k_hw_qcn9274_compact_rx_desc_get_dot11_hdr(struct hal_rx_desc *desc, + struct ieee80211_hdr *hdr) +{ + hdr->frame_control = desc->u.qcn9274_compact.mpdu_start.frame_ctrl; + hdr->duration_id = desc->u.qcn9274_compact.mpdu_start.duration; + ether_addr_copy(hdr->addr1, desc->u.qcn9274_compact.mpdu_start.addr1); + ether_addr_copy(hdr->addr2, desc->u.qcn9274_compact.mpdu_start.addr2); + ether_addr_copy(hdr->addr3, desc->u.qcn9274_compact.mpdu_start.addr3); + if (__le32_to_cpu(desc->u.qcn9274_compact.mpdu_start.info4) & + RX_MPDU_START_INFO4_MAC_ADDR4_VALID) { + ether_addr_copy(hdr->addr4, desc->u.qcn9274_compact.mpdu_start.addr4); + } + hdr->seq_ctrl = desc->u.qcn9274_compact.mpdu_start.seq_ctrl; +} + +static void +ath12k_hw_qcn9274_compact_rx_desc_get_crypto_hdr(struct hal_rx_desc *desc, + u8 *crypto_hdr, + enum hal_encrypt_type enctype) +{ + unsigned int key_id; + + switch (enctype) { + case HAL_ENCRYPT_TYPE_OPEN: + return; + case HAL_ENCRYPT_TYPE_TKIP_NO_MIC: + case HAL_ENCRYPT_TYPE_TKIP_MIC: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[1] = 0; + crypto_hdr[2] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[0]); + break; + case HAL_ENCRYPT_TYPE_CCMP_128: + case HAL_ENCRYPT_TYPE_CCMP_256: + case HAL_ENCRYPT_TYPE_GCMP_128: + case HAL_ENCRYPT_TYPE_AES_GCMP_256: + crypto_hdr[0] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[1] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[2] = 0; + break; + case HAL_ENCRYPT_TYPE_WEP_40: + case HAL_ENCRYPT_TYPE_WEP_104: + case HAL_ENCRYPT_TYPE_WEP_128: + case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4: + case HAL_ENCRYPT_TYPE_WAPI: + return; + } + key_id = le32_get_bits(desc->u.qcn9274_compact.mpdu_start.info5, + RX_MPDU_START_INFO5_KEY_ID); + crypto_hdr[3] = 0x20 | (key_id << 6); + crypto_hdr[4] = + HAL_RX_MPDU_INFO_PN_GET_BYTE3(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[5] = + HAL_RX_MPDU_INFO_PN_GET_BYTE4(desc->u.qcn9274_compact.mpdu_start.pn[0]); + crypto_hdr[6] = + HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.qcn9274_compact.mpdu_start.pn[1]); + crypto_hdr[7] = + HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.qcn9274_compact.mpdu_start.pn[1]); +} + +static u16 ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_frame_ctl(struct hal_rx_desc *desc) +{ + return __le16_to_cpu(desc->u.qcn9274_compact.mpdu_start.frame_ctrl); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_msdu_done(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info14, + RX_MSDU_END_INFO14_MSDU_DONE); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_l4_cksum_fail(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info13, + RX_MSDU_END_INFO13_TCP_UDP_CKSUM_FAIL); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_ip_cksum_fail(struct hal_rx_desc *desc) +{ + return !!le32_get_bits(desc->u.qcn9274_compact.msdu_end.info13, + RX_MSDU_END_INFO13_IP_CKSUM_FAIL); +} + +static bool ath12k_hw_qcn9274_compact_dp_rx_h_is_decrypted(struct hal_rx_desc *desc) +{ + return (le32_get_bits(desc->u.qcn9274_compact.msdu_end.info14, + RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE) == + RX_DESC_DECRYPT_STATUS_CODE_OK); +} + +static u32 ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) +{ + u32 info = __le32_to_cpu(desc->u.qcn9274_compact.msdu_end.info13); + u32 errmap = 0; + + if (info & RX_MSDU_END_INFO13_FCS_ERR) + errmap |= HAL_RX_MPDU_ERR_FCS; + + if (info & RX_MSDU_END_INFO13_DECRYPT_ERR) + errmap |= HAL_RX_MPDU_ERR_DECRYPT; + + if (info & RX_MSDU_END_INFO13_TKIP_MIC_ERR) + errmap |= HAL_RX_MPDU_ERR_TKIP_MIC; + + if (info & RX_MSDU_END_INFO13_A_MSDU_ERROR) + errmap |= HAL_RX_MPDU_ERR_AMSDU_ERR; + + if (info & RX_MSDU_END_INFO13_OVERFLOW_ERR) + errmap |= HAL_RX_MPDU_ERR_OVERFLOW; + + if (info & RX_MSDU_END_INFO13_MSDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MSDU_LEN; + + if (info & RX_MSDU_END_INFO13_MPDU_LEN_ERR) + errmap |= HAL_RX_MPDU_ERR_MPDU_LEN; + + return errmap; +} + +static u32 ath12k_hw_qcn9274_compact_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_qcn9274_compact); +} + +static u8 ath12k_hw_qcn9274_compact_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return le64_get_bits(desc->u.qcn9274_compact.msdu_end.msdu_end_tag, + RX_MSDU_END_64_TLV_SRC_LINK_ID); +} + +const struct hal_rx_ops hal_rx_qcn9274_compact_ops = { + .rx_desc_get_first_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_first_msdu, + .rx_desc_get_last_msdu = ath12k_hw_qcn9274_compact_rx_desc_get_last_msdu, + .rx_desc_get_l3_pad_bytes = ath12k_hw_qcn9274_compact_rx_desc_get_l3_pad_bytes, + .rx_desc_encrypt_valid = ath12k_hw_qcn9274_compact_rx_desc_encrypt_valid, + .rx_desc_get_encrypt_type = ath12k_hw_qcn9274_compact_rx_desc_get_encrypt_type, + .rx_desc_get_decap_type = ath12k_hw_qcn9274_compact_rx_desc_get_decap_type, + .rx_desc_get_mesh_ctl = ath12k_hw_qcn9274_compact_rx_desc_get_mesh_ctl, + .rx_desc_get_mpdu_seq_ctl_vld = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_seq_ctl_vld, + .rx_desc_get_mpdu_fc_valid = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_fc_valid, + .rx_desc_get_mpdu_start_seq_no = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_seq_no, + .rx_desc_get_msdu_len = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_len, + .rx_desc_get_msdu_sgi = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_sgi, + .rx_desc_get_msdu_rate_mcs = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rate_mcs, + .rx_desc_get_msdu_rx_bw = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_rx_bw, + .rx_desc_get_msdu_freq = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_freq, + .rx_desc_get_msdu_pkt_type = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_pkt_type, + .rx_desc_get_msdu_nss = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_nss, + .rx_desc_get_mpdu_tid = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_tid, + .rx_desc_get_mpdu_peer_id = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_peer_id, + .rx_desc_copy_end_tlv = ath12k_hw_qcn9274_compact_rx_desc_copy_end_tlv, + .rx_desc_get_mpdu_ppdu_id = ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_ppdu_id, + .rx_desc_set_msdu_len = ath12k_hw_qcn9274_compact_rx_desc_set_msdu_len, + .rx_desc_get_msdu_payload = ath12k_hw_qcn9274_compact_rx_desc_get_msdu_payload, + .rx_desc_get_mpdu_start_offset = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_start_offset, + .rx_desc_get_msdu_end_offset = + ath12k_hw_qcn9274_compact_rx_desc_get_msdu_end_offset, + .rx_desc_mac_addr2_valid = ath12k_hw_qcn9274_compact_rx_desc_mac_addr2_valid, + .rx_desc_mpdu_start_addr2 = ath12k_hw_qcn9274_compact_rx_desc_mpdu_start_addr2, + .rx_desc_is_da_mcbc = ath12k_hw_qcn9274_compact_rx_desc_is_da_mcbc, + .rx_desc_get_dot11_hdr = ath12k_hw_qcn9274_compact_rx_desc_get_dot11_hdr, + .rx_desc_get_crypto_header = ath12k_hw_qcn9274_compact_rx_desc_get_crypto_hdr, + .rx_desc_get_mpdu_frame_ctl = + ath12k_hw_qcn9274_compact_rx_desc_get_mpdu_frame_ctl, + .dp_rx_h_msdu_done = ath12k_hw_qcn9274_compact_dp_rx_h_msdu_done, + .dp_rx_h_l4_cksum_fail = ath12k_hw_qcn9274_compact_dp_rx_h_l4_cksum_fail, + .dp_rx_h_ip_cksum_fail = ath12k_hw_qcn9274_compact_dp_rx_h_ip_cksum_fail, + .dp_rx_h_is_decrypted = ath12k_hw_qcn9274_compact_dp_rx_h_is_decrypted, + .dp_rx_h_mpdu_err = ath12k_hw_qcn9274_compact_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_qcn9274_compact_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = + ath12k_hw_qcn9274_compact_rx_desc_get_msdu_src_link, +}; + +const struct hal_ops hal_qcn9274_ops = { + .create_srng_config = ath12k_hal_srng_create_config_qcn9274, + .tcl_to_wbm_rbm_map = ath12k_hal_qcn9274_tcl_to_wbm_rbm_map, + .rxdma_ring_wmask_rx_mpdu_start = ath12k_hal_qcn9274_rx_mpdu_start_wmask_get, + .rxdma_ring_wmask_rx_msdu_end = ath12k_hal_qcn9274_rx_msdu_end_wmask_get, + .get_hal_rx_compact_ops = ath12k_hal_qcn9274_get_hal_rx_compact_ops, }; static bool ath12k_hw_wcn7850_rx_desc_get_first_msdu(struct hal_rx_desc *desc) @@ -1134,7 +1513,17 @@ static u32 ath12k_hw_wcn7850_dp_rx_h_mpdu_err(struct hal_rx_desc *desc) return errmap; } -const struct hal_ops hal_wcn7850_ops = { +static u32 ath12k_hw_wcn7850_get_rx_desc_size(void) +{ + return sizeof(struct hal_rx_desc_wcn7850); +} + +static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_src_link(struct hal_rx_desc *desc) +{ + return 0; +} + +const struct hal_rx_ops hal_rx_wcn7850_ops = { .rx_desc_get_first_msdu = ath12k_hw_wcn7850_rx_desc_get_first_msdu, .rx_desc_get_last_msdu = ath12k_hw_wcn7850_rx_desc_get_last_msdu, .rx_desc_get_l3_pad_bytes = ath12k_hw_wcn7850_rx_desc_get_l3_pad_bytes, @@ -1167,13 +1556,21 @@ const struct hal_ops hal_wcn7850_ops = { .rx_desc_get_dot11_hdr = ath12k_hw_wcn7850_rx_desc_get_dot11_hdr, .rx_desc_get_crypto_header = ath12k_hw_wcn7850_rx_desc_get_crypto_hdr, .rx_desc_get_mpdu_frame_ctl = ath12k_hw_wcn7850_rx_desc_get_mpdu_frame_ctl, - .create_srng_config = ath12k_hal_srng_create_config_wcn7850, - .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, .dp_rx_h_msdu_done = ath12k_hw_wcn7850_dp_rx_h_msdu_done, .dp_rx_h_l4_cksum_fail = ath12k_hw_wcn7850_dp_rx_h_l4_cksum_fail, .dp_rx_h_ip_cksum_fail = ath12k_hw_wcn7850_dp_rx_h_ip_cksum_fail, .dp_rx_h_is_decrypted = ath12k_hw_wcn7850_dp_rx_h_is_decrypted, .dp_rx_h_mpdu_err = ath12k_hw_wcn7850_dp_rx_h_mpdu_err, + .rx_desc_get_desc_size = ath12k_hw_wcn7850_get_rx_desc_size, + .rx_desc_get_msdu_src_link_id = ath12k_hw_wcn7850_rx_desc_get_msdu_src_link, +}; + +const struct hal_ops hal_wcn7850_ops = { + .create_srng_config = ath12k_hal_srng_create_config_wcn7850, + .tcl_to_wbm_rbm_map = ath12k_hal_wcn7850_tcl_to_wbm_rbm_map, + .rxdma_ring_wmask_rx_mpdu_start = NULL, + .rxdma_ring_wmask_rx_msdu_end = NULL, + .get_hal_rx_compact_ops = NULL, }; static int ath12k_hal_alloc_cont_rdp(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/hal.h b/drivers/net/wireless/ath/ath12k/hal.h index fc47e7e6b4..107927d64b 100644 --- a/drivers/net/wireless/ath/ath12k/hal.h +++ b/drivers/net/wireless/ath/ath12k/hal.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HAL_H @@ -1023,6 +1023,8 @@ struct ath12k_hal { /* shadow register configuration */ u32 shadow_reg_addr[HAL_SHADOW_NUM_REGS]; int num_shadow_reg_configured; + + u32 hal_desc_sz; }; /* Maps WBM ring number and Return Buffer Manager Id per TCL ring */ @@ -1031,7 +1033,7 @@ struct ath12k_hal_tcl_to_wbm_rbm_map { u8 rbm_id; }; -struct hal_ops { +struct hal_rx_ops { bool (*rx_desc_get_first_msdu)(struct hal_rx_desc *desc); bool (*rx_desc_get_last_msdu)(struct hal_rx_desc *desc); u8 (*rx_desc_get_l3_pad_bytes)(struct hal_rx_desc *desc); @@ -1070,18 +1072,30 @@ struct hal_ops { void (*rx_desc_get_crypto_header)(struct hal_rx_desc *desc, u8 *crypto_hdr, enum hal_encrypt_type enctype); - int (*create_srng_config)(struct ath12k_base *ab); bool (*dp_rx_h_msdu_done)(struct hal_rx_desc *desc); bool (*dp_rx_h_l4_cksum_fail)(struct hal_rx_desc *desc); bool (*dp_rx_h_ip_cksum_fail)(struct hal_rx_desc *desc); bool (*dp_rx_h_is_decrypted)(struct hal_rx_desc *desc); u32 (*dp_rx_h_mpdu_err)(struct hal_rx_desc *desc); + u32 (*rx_desc_get_desc_size)(void); + u8 (*rx_desc_get_msdu_src_link_id)(struct hal_rx_desc *desc); +}; + +struct hal_ops { + int (*create_srng_config)(struct ath12k_base *ab); + u16 (*rxdma_ring_wmask_rx_mpdu_start)(void); + u32 (*rxdma_ring_wmask_rx_msdu_end)(void); + const struct hal_rx_ops *(*get_hal_rx_compact_ops)(void); const struct ath12k_hal_tcl_to_wbm_rbm_map *tcl_to_wbm_rbm_map; }; extern const struct hal_ops hal_qcn9274_ops; extern const struct hal_ops hal_wcn7850_ops; +extern const struct hal_rx_ops hal_rx_qcn9274_ops; +extern const struct hal_rx_ops hal_rx_qcn9274_compact_ops; +extern const struct hal_rx_ops hal_rx_wcn7850_ops; + u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid); void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, int tid, u32 ba_window_size, diff --git a/drivers/net/wireless/ath/ath12k/hal_desc.h b/drivers/net/wireless/ath/ath12k/hal_desc.h index 6c17adc6d6..63340256d3 100644 --- a/drivers/net/wireless/ath/ath12k/hal_desc.h +++ b/drivers/net/wireless/ath/ath12k/hal_desc.h @@ -2500,13 +2500,13 @@ struct hal_rx_reo_queue { #define HAL_REO_UPD_RX_QUEUE_INFO1_PN_HANDLE_ENABLE BIT(30) #define HAL_REO_UPD_RX_QUEUE_INFO1_IGNORE_AMPDU_FLG BIT(31) -#define HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE GENMASK(7, 0) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE GENMASK(9, 8) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SVLD BIT(10) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SSN GENMASK(22, 11) -#define HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR BIT(23) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR BIT(24) -#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_VALID BIT(25) +#define HAL_REO_UPD_RX_QUEUE_INFO2_BA_WINDOW_SIZE GENMASK(9, 0) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_SIZE GENMASK(11, 10) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SVLD BIT(12) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SSN GENMASK(24, 13) +#define HAL_REO_UPD_RX_QUEUE_INFO2_SEQ_2K_ERR BIT(25) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_ERR BIT(26) +#define HAL_REO_UPD_RX_QUEUE_INFO2_PN_VALID BIT(27) struct hal_reo_update_rx_queue { struct hal_reo_cmd_hdr cmd; @@ -2517,6 +2517,12 @@ struct hal_reo_update_rx_queue { __le32 pn[4]; } __packed; +struct hal_rx_reo_queue_1k { + struct hal_desc_header desc_hdr; + __le32 rx_bitmap_1023_288[23]; + __le32 reserved[8]; +} __packed; + #define HAL_REO_UNBLOCK_CACHE_INFO0_UNBLK_CACHE BIT(0) #define HAL_REO_UNBLOCK_CACHE_INFO0_RESOURCE_IDX GENMASK(2, 1) diff --git a/drivers/net/wireless/ath/ath12k/hal_rx.c b/drivers/net/wireless/ath/ath12k/hal_rx.c index 4f25eb9f77..f7c1aaa3b5 100644 --- a/drivers/net/wireless/ath/ath12k/hal_rx.c +++ b/drivers/net/wireless/ath/ath12k/hal_rx.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include "debug.h" @@ -247,7 +247,7 @@ int ath12k_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng, case HAL_REO_CMD_UNBLOCK_CACHE: case HAL_REO_CMD_FLUSH_TIMEOUT_LIST: ath12k_warn(ab, "Unsupported reo command %d\n", type); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; break; default: ath12k_warn(ab, "Unknown reo command %d\n", type); @@ -688,23 +688,28 @@ void ath12k_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab, u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid) { - u32 num_ext_desc; + u32 num_ext_desc, num_1k_desc = 0; if (ba_window_size <= 1) { if (tid != HAL_DESC_REO_NON_QOS_TID) num_ext_desc = 1; else num_ext_desc = 0; + } else if (ba_window_size <= 105) { num_ext_desc = 1; } else if (ba_window_size <= 210) { num_ext_desc = 2; - } else { + } else if (ba_window_size <= 256) { num_ext_desc = 3; + } else { + num_ext_desc = 10; + num_1k_desc = 1; } return sizeof(struct hal_rx_reo_queue) + - (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext)); + (num_ext_desc * sizeof(struct hal_rx_reo_queue_ext)) + + (num_1k_desc * sizeof(struct hal_rx_reo_queue_1k)); } void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc, diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c index de60d988d8..0b17dfd478 100644 --- a/drivers/net/wireless/ath/ath12k/hw.c +++ b/drivers/net/wireless/ath/ath12k/hw.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/types.h> @@ -897,7 +897,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = false, - .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274), .num_tcl_banks = 48, .max_tx_ring = 4, @@ -914,6 +913,13 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 0, .rddm_size = 0, + + .def_num_link = 0, + .max_mlo_peer = 256, + + .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, + + .supports_sta_ps = false, }, { .name = "wcn7850 hw2.0", @@ -950,7 +956,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .vdev_start_delay = true, .interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP), + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_DEVICE) | + BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO), .supports_monitor = false, .idle_ps = true, @@ -960,7 +969,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = true, - .hal_desc_sz = sizeof(struct hal_rx_desc_wcn7850), .num_tcl_banks = 7, .max_tx_ring = 3, @@ -978,6 +986,13 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 1, .rddm_size = 0x780000, + + .def_num_link = 2, + .max_mlo_peer = 32, + + .otp_board_id_register = 0, + + .supports_sta_ps = true, }, { .name = "qcn9274 hw2.0", @@ -987,7 +1002,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .board_size = 256 * 1024, .cal_offset = 128 * 1024, }, - .max_radios = 1, + .max_radios = 2, .single_pdev_only = false, .qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9274, .internal_sleep_clock = false, @@ -1023,7 +1038,6 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .reoq_lut_support = false, .supports_shadow_regs = false, - .hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274), .num_tcl_banks = 48, .max_tx_ring = 4, @@ -1040,6 +1054,13 @@ static const struct ath12k_hw_params ath12k_hw_params[] = { .rfkill_on_level = 0, .rddm_size = 0, + + .def_num_link = 0, + .max_mlo_peer = 256, + + .otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB, + + .supports_sta_ps = false, }, }; diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h index d2622bfef9..87965980b9 100644 --- a/drivers/net/wireless/ath/ath12k/hw.h +++ b/drivers/net/wireless/ath/ath12k/hw.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_HW_H @@ -17,19 +17,30 @@ /* Num VDEVS per radio */ #define TARGET_NUM_VDEVS (16 + 1) -#define TARGET_NUM_PEERS_PDEV (512 + TARGET_NUM_VDEVS) +#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) +#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) +#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) +#define TARGET_NUM_PEERS_DBS_SBS (3 * TARGET_NUM_PEERS_PDEV_DBS_SBS) -/* Max num of stations (per radio) */ -#define TARGET_NUM_STATIONS 512 +/* Max num of stations for Single Radio mode */ +#define TARGET_NUM_STATIONS_SINGLE 512 + +/* Max num of stations for DBS */ +#define TARGET_NUM_STATIONS_DBS 128 + +/* Max num of stations for DBS_SBS */ +#define TARGET_NUM_STATIONS_DBS_SBS 128 #define TARGET_NUM_PEERS(x) TARGET_NUM_PEERS_##x #define TARGET_NUM_PEER_KEYS 2 @@ -66,6 +77,8 @@ #define TARGET_NUM_WDS_ENTRIES 32 #define TARGET_DMA_BURST_SIZE 1 #define TARGET_RX_BATCHMODE 1 +#define TARGET_RX_PEER_METADATA_VER_V1A 2 +#define TARGET_RX_PEER_METADATA_VER_V1B 3 #define ATH12K_HW_MAX_QUEUES 4 #define ATH12K_QUEUE_LEN 4096 @@ -174,7 +187,6 @@ struct ath12k_hw_params { bool reoq_lut_support:1; bool supports_shadow_regs:1; - u32 hal_desc_sz; u32 num_tcl_banks; u32 max_tx_ring; @@ -192,6 +204,13 @@ struct ath12k_hw_params { u32 rfkill_on_level; u32 rddm_size; + + u8 def_num_link; + u16 max_mlo_peer; + + u32 otp_board_id_register; + + bool supports_sta_ps; }; struct ath12k_hw_ops { @@ -242,10 +261,16 @@ enum ath12k_bd_ie_board_type { ATH12K_BD_IE_BOARD_DATA = 1, }; +enum ath12k_bd_ie_regdb_type { + ATH12K_BD_IE_REGDB_NAME = 0, + ATH12K_BD_IE_REGDB_DATA = 1, +}; + enum ath12k_bd_ie_type { /* contains sub IEs of enum ath12k_bd_ie_board_type */ ATH12K_BD_IE_BOARD = 0, - ATH12K_BD_IE_BOARD_EXT = 1, + /* contains sub IEs of enum ath12k_bd_ie_regdb_type */ + ATH12K_BD_IE_REGDB = 1, }; struct ath12k_hw_regs { @@ -315,6 +340,18 @@ struct ath12k_hw_regs { u32 hal_reo_status_ring_base; }; +static inline const char *ath12k_bd_ie_type_str(enum ath12k_bd_ie_type type) +{ + switch (type) { + case ATH12K_BD_IE_BOARD: + return "board data"; + case ATH12K_BD_IE_REGDB: + return "regdb data"; + } + + return "unknown"; +} + int ath12k_hw_init(struct ath12k_base *ab); #endif diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index b965fc46ad..82ef4d4da6 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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <net/mac80211.h> @@ -241,8 +241,8 @@ static const u32 ath12k_smps_map[] = { [WLAN_HT_CAP_SM_PS_DISABLED] = WMI_PEER_SMPS_PS_NONE, }; -static int ath12k_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif); +static int ath12k_start_vdev_delay(struct ath12k *ar, + struct ath12k_vif *arvif); static const char *ath12k_mac_phymode_str(enum wmi_phy_mode mode) { @@ -542,7 +542,7 @@ struct ath12k_vif *ath12k_mac_get_arvif(struct ath12k *ar, u32 vdev_id) arvif_iter.vdev_id = vdev_id; flags = IEEE80211_IFACE_ITER_RESUME_ALL; - ieee80211_iterate_active_interfaces_atomic(ar->hw, + ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), flags, ath12k_get_arvif_iter, &arvif_iter); @@ -563,7 +563,8 @@ struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab, for (i = 0; i < ab->num_radios; i++) { pdev = rcu_dereference(ab->pdevs_active[i]); - if (pdev && pdev->ar) { + if (pdev && pdev->ar && + (pdev->ar->allocated_vdev_map & (1LL << vdev_id))) { arvif = ath12k_mac_get_arvif(pdev->ar, vdev_id); if (arvif) return arvif; @@ -1040,7 +1041,7 @@ static int ath12k_mac_monitor_start(struct ath12k *ar) if (ar->monitor_started) return 0; - ieee80211_iter_chan_contexts_atomic(ar->hw, + ieee80211_iter_chan_contexts_atomic(ath12k_ar_to_hw(ar), ath12k_mac_get_any_chandef_iter, &chandef); if (!chandef) @@ -1083,9 +1084,49 @@ static int ath12k_mac_monitor_stop(struct ath12k *ar) return ret; } -static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) +static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) +{ + struct ath12k *ar = arvif->ar; + int ret; + + lockdep_assert_held(&ar->conf_mutex); + + reinit_completion(&ar->vdev_setup_done); + + ret = ath12k_wmi_vdev_stop(ar, arvif->vdev_id); + if (ret) { + ath12k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n", + arvif->vdev_id, ret); + goto err; + } + + ret = ath12k_mac_vdev_setup_sync(ar); + if (ret) { + ath12k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n", + arvif->vdev_id, ret); + goto err; + } + + WARN_ON(ar->num_started_vdevs == 0); + + ar->num_started_vdevs--; + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", + arvif->vif->addr, arvif->vdev_id); + + if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { + clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "CAC Stopped for vdev %d\n", + arvif->vdev_id); + } + + return 0; +err: + return ret; +} + +static int ath12k_mac_config(struct ath12k *ar, u32 changed) { - struct ath12k *ar = hw->priv; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ieee80211_conf *conf = &hw->conf; int ret = 0; @@ -1122,11 +1163,84 @@ err_mon_del: return ret; } +static int ath12k_mac_op_config(struct ieee80211_hw *hw, u32 changed) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + int ret; + + ar = ath12k_ah_to_ar(ah); + + ret = ath12k_mac_config(ar, changed); + if (ret) + ath12k_warn(ar->ab, "failed to update config pdev idx %d: %d\n", + ar->pdev_idx, ret); + + return ret; +} + +static int ath12k_mac_setup_bcn_p2p_ie(struct ath12k_vif *arvif, + struct sk_buff *bcn) +{ + struct ath12k *ar = arvif->ar; + struct ieee80211_mgmt *mgmt; + const u8 *p2p_ie; + int ret; + + mgmt = (void *)bcn->data; + p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P, + mgmt->u.beacon.variable, + bcn->len - (mgmt->u.beacon.variable - + bcn->data)); + if (!p2p_ie) { + ath12k_warn(ar->ab, "no P2P ie found in beacon\n"); + return -ENOENT; + } + + ret = ath12k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie); + if (ret) { + ath12k_warn(ar->ab, "failed to submit P2P GO bcn ie for vdev %i: %d\n", + arvif->vdev_id, ret); + return ret; + } + + return 0; +} + +static int ath12k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui, + u8 oui_type, size_t ie_offset) +{ + const u8 *next, *end; + size_t len; + u8 *ie; + + if (WARN_ON(skb->len < ie_offset)) + return -EINVAL; + + ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type, + skb->data + ie_offset, + skb->len - ie_offset); + if (!ie) + return -ENOENT; + + len = ie[1] + 2; + end = skb->data + skb->len; + next = ie + len; + + if (WARN_ON(next > end)) + return -EINVAL; + + memmove(ie, next, end - next); + skb_trim(skb, skb->len - len); + + return 0; +} + static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) { struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ieee80211_vif *vif = arvif->vif; struct ieee80211_mutable_offsets offs = {}; struct sk_buff *bcn; @@ -1154,14 +1268,37 @@ static int ath12k_mac_setup_bcn_tmpl(struct ath12k_vif *arvif) ies, (skb_tail_pointer(bcn) - ies))) arvif->wpaie_present = true; - ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); + if (arvif->vif->type == NL80211_IFTYPE_AP && arvif->vif->p2p) { + ret = ath12k_mac_setup_bcn_p2p_ie(arvif, bcn); + if (ret) { + ath12k_warn(ab, "failed to setup P2P GO bcn ie: %d\n", + ret); + goto free_bcn_skb; + } - kfree_skb(bcn); + /* P2P IE is inserted by firmware automatically (as + * configured above) so remove it from the base beacon + * template to avoid duplicate P2P IEs in beacon frames. + */ + ret = ath12k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, + WLAN_OUI_TYPE_WFA_P2P, + offsetof(struct ieee80211_mgmt, + u.beacon.variable)); + if (ret) { + ath12k_warn(ab, "failed to remove P2P vendor ie: %d\n", + ret); + goto free_bcn_skb; + } + } + + ret = ath12k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); if (ret) ath12k_warn(ab, "failed to submit beacon template command: %d\n", ret); +free_bcn_skb: + kfree_skb(bcn); return ret; } @@ -1214,6 +1351,7 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar, struct ath12k_wmi_peer_assoc_arg *arg) { struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); u32 aid; lockdep_assert_held(&ar->conf_mutex); @@ -1228,7 +1366,7 @@ static void ath12k_peer_assoc_h_basic(struct ath12k *ar, arg->peer_associd = aid; arg->auth_flag = true; /* TODO: STA WAR in ath10k for listen interval required? */ - arg->peer_listen_intval = ar->hw->conf.listen_interval; + arg->peer_listen_intval = hw->conf.listen_interval; arg->peer_nss = 1; arg->peer_caps = vif->bss_conf.assoc_capability; } @@ -1242,6 +1380,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, struct cfg80211_chan_def def; struct cfg80211_bss *bss; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); const u8 *rsnie = NULL; const u8 *wpaie = NULL; @@ -1250,7 +1389,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, if (WARN_ON(ath12k_mac_vif_chan(vif, &def))) return; - bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0, + bss = cfg80211_get_bss(hw->wiphy, def.chan, info->bssid, NULL, 0, IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); if (arvif->rsnie_present || arvif->wpaie_present) { @@ -1270,7 +1409,7 @@ static void ath12k_peer_assoc_h_crypto(struct ath12k *ar, ies->data, ies->len); rcu_read_unlock(); - cfg80211_put_bss(ar->hw->wiphy, bss); + cfg80211_put_bss(hw->wiphy, bss); } /* FIXME: base on RSN IE/WPA IE is a correct idea? */ @@ -1304,6 +1443,7 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar, struct cfg80211_chan_def def; const struct ieee80211_supported_band *sband; const struct ieee80211_rate *rates; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); enum nl80211_band band; u32 ratemask; u8 rate; @@ -1315,7 +1455,7 @@ static void ath12k_peer_assoc_h_rates(struct ath12k *ar, return; band = def.chan->band; - sband = ar->hw->wiphy->bands[band]; + sband = hw->wiphy->bands[band]; ratemask = sta->deflink.supp_rates[band]; ratemask &= arvif->bitrate_mask.control[band].legacy; rates = sband->bitrates; @@ -2266,12 +2406,11 @@ static int ath12k_setup_peer_smps(struct ath12k *ar, struct ath12k_vif *arvif, ath12k_smps_map[smps]); } -static void ath12k_bss_assoc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, +static void ath12k_bss_assoc(struct ath12k *ar, + struct ath12k_vif *arvif, struct ieee80211_bss_conf *bss_conf) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = arvif->vif; struct ath12k_wmi_peer_assoc_arg peer_arg; struct ieee80211_sta *ap_sta; struct ath12k_peer *peer; @@ -2361,11 +2500,9 @@ static void ath12k_bss_assoc(struct ieee80211_hw *hw, arvif->vdev_id, ret); } -static void ath12k_bss_disassoc(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void ath12k_bss_disassoc(struct ath12k *ar, + struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; lockdep_assert_held(&ar->conf_mutex); @@ -2413,6 +2550,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, struct cfg80211_chan_def *def) { struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); const struct ieee80211_supported_band *sband; u8 basic_rate_idx; int hw_rate_code; @@ -2422,7 +2560,7 @@ static void ath12k_recalculate_mgmt_rate(struct ath12k *ar, lockdep_assert_held(&ar->conf_mutex); - sband = ar->hw->wiphy->bands[def->chan->band]; + sband = hw->wiphy->bands[def->chan->band]; basic_rate_idx = ffs(vif->bss_conf.basic_rates) - 1; bitrate = sband->bitrates[basic_rate_idx].bitrate; @@ -2449,6 +2587,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, struct ieee80211_bss_conf *info) { struct ath12k *ar = arvif->ar; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct sk_buff *tmpl; int ret; u32 interval; @@ -2457,7 +2596,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, if (info->fils_discovery.max_interval) { interval = info->fils_discovery.max_interval; - tmpl = ieee80211_get_fils_discovery_tmpl(ar->hw, arvif->vif); + tmpl = ieee80211_get_fils_discovery_tmpl(hw, arvif->vif); if (tmpl) ret = ath12k_wmi_fils_discovery_tmpl(ar, arvif->vdev_id, tmpl); @@ -2465,7 +2604,7 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, unsol_bcast_probe_resp_enabled = 1; interval = info->unsol_bcast_probe_resp_interval; - tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(ar->hw, + tmpl = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, arvif->vif); if (tmpl) ret = ath12k_wmi_probe_resp_tmpl(ar, arvif->vdev_id, @@ -2491,13 +2630,60 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif, return ret; } -static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_bss_conf *info, - u64 changed) +static void ath12k_mac_vif_setup_ps(struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar = arvif->ar; + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_conf *conf = &ath12k_ar_to_hw(ar)->conf; + enum wmi_sta_powersave_param param; + enum wmi_sta_ps_mode psmode; + int ret; + int timeout; + bool enable_ps; + + lockdep_assert_held(&ar->conf_mutex); + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + enable_ps = arvif->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) { + /* firmware doesn't like 0 */ + timeout = ieee80211_tu_to_usec(vif->bss_conf.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_bss_info_changed(struct ath12k *ar, + struct ath12k_vif *arvif, + struct ieee80211_bss_conf *info, + u64 changed) +{ + struct ieee80211_vif *vif = arvif->vif; + struct ieee80211_vif_cfg *vif_cfg = &vif->cfg; struct cfg80211_chan_def def; u32 param_id, param_value; enum nl80211_band band; @@ -2510,7 +2696,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, u8 rateidx; u32 rate; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); if (changed & BSS_CHANGED_BEACON_INT) { arvif->beacon_interval = info->beacon_int; @@ -2666,9 +2852,9 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { if (vif->cfg.assoc) - ath12k_bss_assoc(hw, vif, info); + ath12k_bss_assoc(ar, arvif, info); else - ath12k_bss_disassoc(hw, vif); + ath12k_bss_disassoc(ar, arvif); } if (changed & BSS_CHANGED_TXPOWER) { @@ -2768,14 +2954,35 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, ath12k_mac_fils_discovery(arvif, info); - if (changed & BSS_CHANGED_EHT_PUNCTURING) - arvif->punct_bitmap = info->eht_puncturing; + if (changed & BSS_CHANGED_PS && + ar->ab->hw_params->supports_sta_ps) { + arvif->ps = vif_cfg->ps; + ath12k_mac_vif_setup_ps(arvif); + } +} + +static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u64 changed) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + + ath12k_mac_bss_info_changed(ar, arvif, info, changed); mutex_unlock(&ar->conf_mutex); } void __ath12k_mac_scan_finish(struct ath12k *ar) { + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + lockdep_assert_held(&ar->data_lock); switch (ar->scan.state) { @@ -2784,7 +2991,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar) case ATH12K_SCAN_RUNNING: case ATH12K_SCAN_ABORTING: if (ar->scan.is_roc && ar->scan.roc_notify) - ieee80211_remain_on_channel_expired(ar->hw); + ieee80211_remain_on_channel_expired(hw); fallthrough; case ATH12K_SCAN_STARTING: if (!ar->scan.is_roc) { @@ -2795,7 +3002,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar) ATH12K_SCAN_STARTING)), }; - ieee80211_scan_completed(ar->hw, &info); + ieee80211_scan_completed(hw, &info); } ar->scan.state = ATH12K_SCAN_IDLE; @@ -2940,13 +3147,16 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct cfg80211_scan_request *req = &hw_req->req; struct ath12k_wmi_scan_req_arg arg = {}; int ret; int i; + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); spin_lock_bh(&ar->data_lock); @@ -2988,7 +3198,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, for (i = 0; i < arg.num_ssids; i++) arg.ssid[i] = req->ssids[i]; } else { - arg.scan_flags |= WMI_SCAN_FLAG_PASSIVE; + arg.scan_f_passive = 1; } if (req->n_channels) { @@ -3014,7 +3224,7 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw, } /* Add a margin to account for event/command processing */ - ieee80211_queue_delayed_work(ar->hw, &ar->scan.timeout, + ieee80211_queue_delayed_work(ath12k_ar_to_hw(ar), &ar->scan.timeout, msecs_to_jiffies(arg.max_scan_time + ATH12K_MAC_SCAN_TIMEOUT_MSECS)); @@ -3025,13 +3235,17 @@ exit: kfree(arg.extraie.ptr); mutex_unlock(&ar->conf_mutex); + return ret; } static void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); mutex_lock(&ar->conf_mutex); ath12k_scan_abort(ar); @@ -3159,8 +3373,9 @@ static int ath12k_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) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_peer *peer; struct ath12k_sta *arsta; @@ -3175,6 +3390,9 @@ static int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key->cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256) return 1; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + if (test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags)) return 1; @@ -3696,7 +3914,7 @@ static int ath12k_mac_station_add(struct ath12k *ar, if (ab->hw_params->vdev_start_delay && !arvif->is_started && arvif->vdev_type != WMI_VDEV_TYPE_AP) { - ret = ath12k_start_vdev_delay(ar->hw, vif); + ret = ath12k_start_vdev_delay(ar, arvif); if (ret) { ath12k_warn(ab, "failed to delay vdev start: %d\n", ret); goto free_peer; @@ -3750,7 +3968,8 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); struct ath12k_peer *peer; @@ -3761,6 +3980,8 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, new_state == IEEE80211_STA_NOTEXIST)) cancel_work_sync(&arsta->update_wk); + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); if (old_state == IEEE80211_STA_NOTEXIST && @@ -3775,6 +3996,13 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, sta->addr, arvif->vdev_id); } else if ((old_state == IEEE80211_STA_NONE && new_state == IEEE80211_STA_NOTEXIST)) { + if (arvif->vdev_type == WMI_VDEV_TYPE_STA) { + ath12k_bss_disassoc(ar, arvif); + ret = ath12k_mac_vdev_stop(arvif); + if (ret) + ath12k_warn(ar->ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + } ath12k_dp_peer_cleanup(ar, arvif->vdev_id, sta->addr); ret = ath12k_peer_delete(ar, arvif->vdev_id, sta->addr); @@ -3856,6 +4084,7 @@ static int ath12k_mac_op_sta_state(struct ieee80211_hw *hw, } mutex_unlock(&ar->conf_mutex); + return ret; } @@ -3863,7 +4092,8 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; s16 txpwr; @@ -3879,6 +4109,8 @@ static int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw, if (txpwr > ATH12K_TX_POWER_MAX_VAL || txpwr < ATH12K_TX_POWER_MIN_VAL) return -EINVAL; + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); ret = ath12k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id, @@ -3899,12 +4131,15 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_sta *sta, u32 changed) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_sta *arsta = ath12k_sta_to_arsta(sta); struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_peer *peer; u32 bw, smps; + ar = ath12k_ah_to_ar(ah); + spin_lock_bh(&ar->ab->base_lock); peer = ath12k_peer_find(ar->ab, arvif->vdev_id, sta->addr); @@ -3964,10 +4199,10 @@ static void ath12k_mac_op_sta_rc_update(struct ieee80211_hw *hw, ieee80211_queue_work(hw, &arsta->update_wk); } -static int ath12k_conf_tx_uapsd(struct ath12k *ar, struct ieee80211_vif *vif, +static int ath12k_conf_tx_uapsd(struct ath12k_vif *arvif, u16 ac, bool enable) { - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar = arvif->ar; u32 value; int ret; @@ -4021,17 +4256,16 @@ exit: return ret; } -static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - unsigned int link_id, u16 ac, - const struct ieee80211_tx_queue_params *params) +static int ath12k_mac_conf_tx(struct ath12k_vif *arvif, + unsigned int link_id, u16 ac, + const struct ieee80211_tx_queue_params *params) { - struct ath12k *ar = hw->priv; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct wmi_wmm_params_arg *p = NULL; + struct ath12k *ar = arvif->ar; + struct ath12k_base *ab = ar->ab; int ret; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); switch (ac) { case IEEE80211_AC_VO: @@ -4061,17 +4295,36 @@ static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, ret = ath12k_wmi_send_wmm_update_cmd(ar, arvif->vdev_id, &arvif->wmm_params); if (ret) { - ath12k_warn(ar->ab, "failed to set wmm params: %d\n", ret); + ath12k_warn(ab, "pdev idx %d failed to set wmm params: %d\n", + ar->pdev_idx, ret); goto exit; } - ret = ath12k_conf_tx_uapsd(ar, vif, ac, params->uapsd); - + ret = ath12k_conf_tx_uapsd(arvif, ac, params->uapsd); if (ret) - ath12k_warn(ar->ab, "failed to set sta uapsd: %d\n", ret); + ath12k_warn(ab, "pdev idx %d failed to set sta uapsd: %d\n", + ar->pdev_idx, ret); exit: + return ret; +} + +static int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + unsigned int link_id, u16 ac, + const struct ieee80211_tx_queue_params *params) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + int ret; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + ret = ath12k_mac_conf_tx(arvif, link_id, ac, params); mutex_unlock(&ar->conf_mutex); + return ret; } @@ -4782,7 +5035,7 @@ static void ath12k_mgmt_over_wmi_tx_drop(struct ath12k *ar, struct sk_buff *skb) { int num_mgmt; - ieee80211_free_txskb(ar->hw, skb); + ieee80211_free_txskb(ath12k_ar_to_hw(ar), skb); num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); @@ -4914,8 +5167,8 @@ static void ath12k_mgmt_over_wmi_tx_work(struct work_struct *work) } arvif = ath12k_vif_to_arvif(skb_cb->vif); - if (ar->allocated_vdev_map & (1LL << arvif->vdev_id) && - arvif->is_started) { + + if (ar->allocated_vdev_map & (1LL << arvif->vdev_id)) { 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", @@ -4959,20 +5212,41 @@ static int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb, skb_queue_tail(q, skb); atomic_inc(&ar->num_pending_mgmt_tx); - ieee80211_queue_work(ar->hw, &ar->wmi_mgmt_tx_work); + ieee80211_queue_work(ath12k_ar_to_hw(ar), &ar->wmi_mgmt_tx_work); return 0; } +static void ath12k_mac_add_p2p_noa_ie(struct ath12k *ar, + struct ieee80211_vif *vif, + struct sk_buff *skb, + bool is_prb_rsp) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + if (likely(!is_prb_rsp)) + return; + + spin_lock_bh(&ar->data_lock); + + if (arvif->u.ap.noa_data && + !pskb_expand_head(skb, 0, arvif->u.ap.noa_len, + GFP_ATOMIC)) + skb_put_data(skb, arvif->u.ap.noa_data, + arvif->u.ap.noa_len); + + spin_unlock_bh(&ar->data_lock); +} + static void ath12k_mac_op_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb); - struct ath12k *ar = hw->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_vif *vif = info->control.vif; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k *ar = arvif->ar; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_key_conf *key = info->control.hw_key; u32 info_flags = info->flags; @@ -4987,10 +5261,11 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, skb_cb->flags |= ATH12K_SKB_CIPHER_SET; } + is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); + if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) { skb_cb->flags |= ATH12K_SKB_HW_80211_ENCAP; } else if (ieee80211_is_mgmt(hdr->frame_control)) { - is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control); ret = ath12k_mac_mgmt_tx(ar, skb, is_prb_rsp); if (ret) { ath12k_warn(ar->ab, "failed to queue management frame %d\n", @@ -5000,6 +5275,10 @@ static void ath12k_mac_op_tx(struct ieee80211_hw *hw, return; } + /* This is case only for P2P_GO */ + if (vif->type == NL80211_IFTYPE_AP && vif->p2p) + ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp); + ret = ath12k_dp_tx(ar, arvif, skb); if (ret) { ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret); @@ -5018,7 +5297,7 @@ void ath12k_mac_drain_tx(struct ath12k *ar) static int ath12k_mac_config_mon_status_default(struct ath12k *ar, bool enable) { - return -ENOTSUPP; + return -EOPNOTSUPP; /* TODO: Need to support new monitor mode */ } @@ -5044,14 +5323,12 @@ static void ath12k_mac_wait_reconfigure(struct ath12k_base *ab) ATH12K_RECONFIGURE_TIMEOUT_HZ); } -static int ath12k_mac_op_start(struct ieee80211_hw *hw) +static int ath12k_mac_start(struct ath12k *ar) { - struct ath12k *ar = hw->priv; struct ath12k_base *ab = ar->ab; struct ath12k_pdev *pdev = ar->pdev; int ret; - ath12k_mac_drain_tx(ar); mutex_lock(&ar->conf_mutex); switch (ar->state) { @@ -5074,14 +5351,14 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable PMF QOS: (%d\n", ret); + ath12k_err(ab, "failed to enable PMF QOS: (%d\n", ret); goto err; } ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_DYNAMIC_BW, 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable dynamic bw: %d\n", ret); + ath12k_err(ab, "failed to enable dynamic bw: %d\n", ret); goto err; } @@ -5111,7 +5388,7 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) 1, pdev->pdev_id); if (ret) { - ath12k_err(ar->ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret); + ath12k_err(ab, "failed to enable MESH MCAST ENABLE: (%d\n", ret); goto err; } @@ -5130,14 +5407,14 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) * such as rssi, rx_duration. */ ret = ath12k_mac_config_mon_status_default(ar, true); - if (ret && (ret != -ENOTSUPP)) { + if (ret && (ret != -EOPNOTSUPP)) { ath12k_err(ab, "failed to configure monitor status ring with default rx_filter: (%d)\n", ret); goto err; } - if (ret == -ENOTSUPP) - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + if (ret == -EOPNOTSUPP) + ath12k_dbg(ab, ATH12K_DBG_MAC, "monitor status config is not yet supported"); /* Configure the hash seed for hash based reo dest ring selection */ @@ -5159,7 +5436,6 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw) &ab->pdevs[ar->pdev_idx]); return 0; - err: ar->state = ATH12K_STATE_OFF; mutex_unlock(&ar->conf_mutex); @@ -5167,6 +5443,25 @@ err: return ret; } +static int ath12k_mac_op_start(struct ieee80211_hw *hw) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k_base *ab = ar->ab; + int ret; + + ath12k_mac_drain_tx(ar); + + ret = ath12k_mac_start(ar); + if (ret) { + ath12k_err(ab, "fail to start mac operations in pdev idx %d ret %d\n", + ar->pdev_idx, ret); + return ret; + } + + return 0; +} + int ath12k_mac_rfkill_config(struct ath12k *ar) { struct ath12k_base *ab = ar->ab; @@ -5224,17 +5519,14 @@ int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable) return 0; } -static void ath12k_mac_op_stop(struct ieee80211_hw *hw) +static void ath12k_mac_stop(struct ath12k *ar) { - struct ath12k *ar = hw->priv; struct htt_ppdu_stats_info *ppdu_stats, *tmp; int ret; - ath12k_mac_drain_tx(ar); - mutex_lock(&ar->conf_mutex); ret = ath12k_mac_config_mon_status_default(ar, false); - if (ret && (ret != -ENOTSUPP)) + if (ret && (ret != -EOPNOTSUPP)) ath12k_err(ar->ab, "failed to clear rx_filter for monitor status ring: (%d)\n", ret); @@ -5260,6 +5552,16 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw) atomic_set(&ar->num_pending_mgmt_tx, 0); } +static void ath12k_mac_op_stop(struct ieee80211_hw *hw) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); + + ath12k_mac_drain_tx(ar); + + ath12k_mac_stop(ar); +} + static u8 ath12k_mac_get_vdev_stats_id(struct ath12k_vif *arvif) { @@ -5376,12 +5678,11 @@ static int ath12k_set_he_mu_sounding_mode(struct ath12k *ar, return ret; } -static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static void ath12k_mac_update_vif_offload(struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; + struct ieee80211_vif *vif = arvif->vif; + struct ath12k *ar = arvif->ar; struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); u32 param_id, param_value; int ret; @@ -5423,11 +5724,20 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, } } +static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + + ath12k_mac_update_vif_offload(arvif); +} + static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); struct ath12k_wmi_vdev_create_arg vdev_arg = {0}; struct ath12k_wmi_peer_create_arg peer_param; @@ -5439,6 +5749,9 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); if (vif->type == NL80211_IFTYPE_AP && @@ -5483,17 +5796,29 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: arvif->vdev_type = WMI_VDEV_TYPE_STA; + + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT; + break; case NL80211_IFTYPE_MESH_POINT: arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH_11S; fallthrough; case NL80211_IFTYPE_AP: arvif->vdev_type = WMI_VDEV_TYPE_AP; + + if (vif->p2p) + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO; + break; case NL80211_IFTYPE_MONITOR: arvif->vdev_type = WMI_VDEV_TYPE_MONITOR; ar->monitor_vdev_id = bit; break; + case NL80211_IFTYPE_P2P_DEVICE: + arvif->vdev_type = WMI_VDEV_TYPE_STA; + arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE; + break; default: WARN_ON(1); break; @@ -5526,7 +5851,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw, list_add(&arvif->list, &ar->arvifs); spin_unlock_bh(&ar->data_lock); - ath12k_mac_op_update_vif_offload(hw, vif); + ath12k_mac_update_vif_offload(arvif); nss = hweight32(ar->cfg_tx_chainmask) ? : 1; ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, @@ -5685,12 +6010,16 @@ static void ath12k_mac_vif_unref(struct ath12k_dp *dp, struct ieee80211_vif *vif static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); - struct ath12k_base *ab = ar->ab; + struct ath12k_base *ab; unsigned long time_left; int ret; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n", @@ -5766,19 +6095,15 @@ err_vdev_del: FIF_PROBE_REQ | \ FIF_FCSFAIL) -static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, - unsigned int changed_flags, - unsigned int *total_flags, - u64 multicast) +static void ath12k_mac_configure_filter(struct ath12k *ar, + unsigned int total_flags) { - struct ath12k *ar = hw->priv; bool reset_flag; int ret; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); - *total_flags &= SUPPORTED_FILTERS; - ar->filter_flags = *total_flags; + ar->filter_flags = total_flags; /* For monitor mode */ reset_flag = !(ar->filter_flags & FIF_BCN_PRBRESP_PROMISC); @@ -5793,16 +6118,36 @@ static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, ath12k_warn(ar->ab, "fail to set monitor filter: %d\n", ret); } + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "total_flags:0x%x, reset_flag:%d\n", - *total_flags, reset_flag); + total_flags, reset_flag); +} + +static void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw, + unsigned int changed_flags, + unsigned int *total_flags, + u64 multicast) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + + *total_flags &= SUPPORTED_FILTERS; + ath12k_mac_configure_filter(ar, *total_flags); mutex_unlock(&ar->conf_mutex); } static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); mutex_lock(&ar->conf_mutex); @@ -5816,9 +6161,12 @@ static int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 * static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; int ret; + ar = ath12k_ah_to_ar(ah); + mutex_lock(&ar->conf_mutex); ret = __ath12k_set_antenna(ar, tx_ant, rx_ant); mutex_unlock(&ar->conf_mutex); @@ -5826,14 +6174,13 @@ static int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx return ret; } -static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_ampdu_params *params) +static int ath12k_mac_ampdu_action(struct ath12k_vif *arvif, + struct ieee80211_ampdu_params *params) { - struct ath12k *ar = hw->priv; + struct ath12k *ar = arvif->ar; int ret = -EINVAL; - mutex_lock(&ar->conf_mutex); + lockdep_assert_held(&ar->conf_mutex); switch (params->action) { case IEEE80211_AMPDU_RX_START: @@ -5854,16 +6201,40 @@ static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, break; } + return ret; +} + +static int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_ampdu_params *params) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + int ret = -EINVAL; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + ret = ath12k_mac_ampdu_action(arvif, params); mutex_unlock(&ar->conf_mutex); + if (ret) + ath12k_warn(ar->ab, "pdev idx %d unable to perform ampdu action %d ret %d\n", + ar->pdev_idx, params->action, ret); + return ret; } static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; + + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx add freq %u width %d ptr %pK\n", @@ -5886,8 +6257,12 @@ static int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw, static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; + + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx remove freq %u width %d ptr %pK\n", @@ -5911,14 +6286,24 @@ ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar, enum nl80211_band band, enum nl80211_iftype type) { - struct ieee80211_sta_eht_cap *eht_cap; + struct ieee80211_sta_eht_cap *eht_cap = NULL; enum wmi_phy_mode down_mode; + int n = ar->mac.sbands[band].n_iftype_data; + int i; + struct ieee80211_sband_iftype_data *data; if (mode < MODE_11BE_EHT20) return mode; - eht_cap = &ar->mac.iftype[band][type].eht_cap; - if (eht_cap->has_eht) + data = ar->mac.iftype[band]; + for (i = 0; i < n; i++) { + if (data[i].types_mask & BIT(type)) { + eht_cap = &data[i].eht_cap; + break; + } + } + + if (eht_cap && eht_cap->has_eht) return mode; switch (mode) { @@ -5995,6 +6380,11 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, arg.pref_tx_streams = ar->num_tx_chains; arg.pref_rx_streams = ar->num_rx_chains; + /* Fill the MBSSID flags to indicate AP is non MBSSID by default + * Corresponding flags would be updated with MBSSID support. + */ + arg.mbssid_flags = WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP; + if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; arg.ssid_len = arvif->u.ap.ssid_len; @@ -6071,46 +6461,6 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif, return 0; } -static int ath12k_mac_vdev_stop(struct ath12k_vif *arvif) -{ - struct ath12k *ar = arvif->ar; - int ret; - - lockdep_assert_held(&ar->conf_mutex); - - reinit_completion(&ar->vdev_setup_done); - - ret = ath12k_wmi_vdev_stop(ar, arvif->vdev_id); - if (ret) { - ath12k_warn(ar->ab, "failed to stop WMI vdev %i: %d\n", - arvif->vdev_id, ret); - goto err; - } - - ret = ath12k_mac_vdev_setup_sync(ar); - if (ret) { - ath12k_warn(ar->ab, "failed to synchronize setup for vdev %i: %d\n", - arvif->vdev_id, ret); - goto err; - } - - WARN_ON(ar->num_started_vdevs == 0); - - ar->num_started_vdevs--; - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "vdev %pM stopped, vdev_id %d\n", - arvif->vif->addr, arvif->vdev_id); - - if (test_bit(ATH12K_CAC_RUNNING, &ar->dev_flags)) { - clear_bit(ATH12K_CAC_RUNNING, &ar->dev_flags); - ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "CAC Stopped for vdev %d\n", - arvif->vdev_id); - } - - return 0; -err: - return ret; -} - static int ath12k_mac_vdev_start(struct ath12k_vif *arvif, struct ieee80211_chanctx_conf *ctx) { @@ -6215,6 +6565,8 @@ ath12k_mac_update_vif_chan(struct ath12k *ar, if (WARN_ON(!arvif->is_started)) continue; + arvif->punct_bitmap = vifs[i].new_ctx->def.punctured; + /* Firmware expect vdev_restart only if vdev is up. * If vdev is down then it expect vdev_stop->vdev_start. */ @@ -6266,7 +6618,7 @@ ath12k_mac_update_active_vif_chan(struct ath12k *ar, struct ieee80211_chanctx_conf *ctx) { struct ath12k_mac_change_chanctx_arg arg = { .ctx = ctx }; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); lockdep_assert_held(&ar->conf_mutex); @@ -6295,8 +6647,12 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx, u32 changed) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; + + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; mutex_lock(&ar->conf_mutex); @@ -6311,7 +6667,8 @@ static void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw, goto unlock; if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH || - changed & IEEE80211_CHANCTX_CHANGE_RADAR) + changed & IEEE80211_CHANCTX_CHANGE_RADAR || + changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) ath12k_mac_update_active_vif_chan(ar, ctx); /* TODO: Recalc radar detection */ @@ -6320,12 +6677,11 @@ unlock: mutex_unlock(&ar->conf_mutex); } -static int ath12k_start_vdev_delay(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static int ath12k_start_vdev_delay(struct ath12k *ar, + struct ath12k_vif *arvif) { - struct ath12k *ar = hw->priv; struct ath12k_base *ab = ar->ab; - struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ieee80211_vif *vif = arvif->vif; int ret; if (WARN_ON(arvif->is_started)) @@ -6359,19 +6715,23 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; struct ath12k_wmi_peer_create_arg param; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx assign ptr %pK vdev_id %i\n", ctx, arvif->vdev_id); - arvif->punct_bitmap = link_conf->eht_puncturing; + arvif->punct_bitmap = ctx->def.punctured; /* for some targets bss peer must be created before vdev_start */ if (ab->hw_params->vdev_start_delay && @@ -6438,11 +6798,15 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_bss_conf *link_conf, struct ieee80211_chanctx_conf *ctx) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); int ret; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); ath12k_dbg(ab, ATH12K_DBG_MAC, @@ -6466,11 +6830,13 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = false; } - ret = ath12k_mac_vdev_stop(arvif); - if (ret) - ath12k_warn(ab, "failed to stop vdev %i: %d\n", - arvif->vdev_id, ret); - + if (arvif->vdev_type != WMI_VDEV_TYPE_STA) { + ath12k_bss_disassoc(ar, arvif); + ret = ath12k_mac_vdev_stop(arvif); + if (ret) + ath12k_warn(ab, "failed to stop vdev %i: %d\n", + arvif->vdev_id, ret); + } arvif->is_started = false; if (ab->hw_params->vdev_start_delay && @@ -6490,7 +6856,10 @@ ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); mutex_lock(&ar->conf_mutex); @@ -6532,10 +6901,15 @@ ath12k_set_vdev_param_to_all_vifs(struct ath12k *ar, int param, u32 value) */ static int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw, u32 value) { - struct ath12k *ar = hw->priv; - int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + int param_id = WMI_VDEV_PARAM_RTS_THRESHOLD, ret; + + ar = ath12k_ah_to_ar(ah); + + ret = ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); - return ath12k_set_vdev_param_to_all_vifs(ar, param_id, value); + return ret; } static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) @@ -6553,15 +6927,10 @@ static int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value) return -EOPNOTSUPP; } -static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - u32 queues, bool drop) +static void ath12k_mac_flush(struct ath12k *ar) { - struct ath12k *ar = hw->priv; long time_left; - if (drop) - return; - time_left = wait_event_timeout(ar->dp.tx_empty_waitq, (atomic_read(&ar->dp.num_tx_pending) == 0), ATH12K_FLUSH_TIMEOUT); @@ -6576,6 +6945,18 @@ static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *v time_left); } +static void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); + + if (drop) + return; + + ath12k_mac_flush(ar); +} + static int ath12k_mac_bitrate_mask_num_ht_rates(struct ath12k *ar, enum nl80211_band band, @@ -6778,7 +7159,7 @@ static void ath12k_mac_set_bitrate_mask_iter(void *data, arsta->changed |= IEEE80211_RC_SUPP_RATES_CHANGED; spin_unlock_bh(&ar->data_lock); - ieee80211_queue_work(ar->hw, &arsta->update_wk); + ieee80211_queue_work(ath12k_ar_to_hw(ar), &arsta->update_wk); } static void ath12k_mac_disable_peer_fixed_rate(void *data, @@ -6826,8 +7207,10 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, ldpc = !!(ar->ht_cap_info & WMI_HT_CAP_LDPC); sgi = mask->control[band].gi; - if (sgi == NL80211_TXRATE_FORCE_LGI) - return -EINVAL; + if (sgi == NL80211_TXRATE_FORCE_LGI) { + ret = -EINVAL; + goto out; + } /* 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. @@ -6843,7 +7226,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, if (ret) { ath12k_warn(ar->ab, "failed to get single legacy rate for vdev %i: %d\n", arvif->vdev_id, ret); - return ret; + goto out; } ieee80211_iterate_stations_atomic(hw, ath12k_mac_disable_peer_fixed_rate, @@ -6888,7 +7271,8 @@ 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; } ieee80211_iterate_stations_atomic(hw, @@ -6915,6 +7299,7 @@ ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw, mutex_unlock(&ar->conf_mutex); +out: return ret; } @@ -6922,14 +7307,18 @@ static void ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw, enum ieee80211_reconfig_type reconfig_type) { - struct ath12k *ar = hw->priv; - struct ath12k_base *ab = ar->ab; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + struct ath12k_base *ab; struct ath12k_vif *arvif; int recovery_count; if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART) return; + ar = ath12k_ah_to_ar(ah); + ab = ar->ab; + mutex_lock(&ar->conf_mutex); if (ar->state == ATH12K_STATE_RESTARTED) { @@ -7013,7 +7402,8 @@ ath12k_mac_update_bss_chan_survey(struct ath12k *ar, static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; struct ieee80211_supported_band *sband; struct survey_info *ar_survey; int ret = 0; @@ -7021,6 +7411,8 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, if (idx >= ATH12K_NUM_CHANS) return -ENOENT; + ar = ath12k_ah_to_ar(ah); + ar_survey = &ar->survey[idx]; mutex_lock(&ar->conf_mutex); @@ -7052,6 +7444,7 @@ static int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx, exit: mutex_unlock(&ar->conf_mutex); + return ret; } @@ -7089,6 +7482,125 @@ static void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw, sinfo->filled |= BIT_ULL(NL80211_STA_INFO_SIGNAL); } +static int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + ar->scan.roc_notify = false; + spin_unlock_bh(&ar->data_lock); + + ath12k_scan_abort(ar); + + mutex_unlock(&ar->conf_mutex); + + cancel_delayed_work_sync(&ar->scan.timeout); + + return 0; +} + +static int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel *chan, + int duration, + enum ieee80211_roc_type type) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k_wmi_scan_req_arg arg; + struct ath12k *ar; + u32 scan_time_msec; + int ret; + + ar = ath12k_ah_to_ar(ah); + + mutex_lock(&ar->conf_mutex); + spin_lock_bh(&ar->data_lock); + + switch (ar->scan.state) { + case ATH12K_SCAN_IDLE: + reinit_completion(&ar->scan.started); + reinit_completion(&ar->scan.completed); + reinit_completion(&ar->scan.on_channel); + ar->scan.state = ATH12K_SCAN_STARTING; + ar->scan.is_roc = true; + ar->scan.vdev_id = arvif->vdev_id; + ar->scan.roc_freq = chan->center_freq; + ar->scan.roc_notify = true; + ret = 0; + break; + case ATH12K_SCAN_STARTING: + case ATH12K_SCAN_RUNNING: + case ATH12K_SCAN_ABORTING: + ret = -EBUSY; + break; + } + + spin_unlock_bh(&ar->data_lock); + + if (ret) + goto exit; + + scan_time_msec = hw->wiphy->max_remain_on_channel_duration * 2; + + memset(&arg, 0, sizeof(arg)); + ath12k_wmi_start_scan_init(ar, &arg); + arg.num_chan = 1; + arg.chan_list = kcalloc(arg.num_chan, sizeof(*arg.chan_list), + GFP_KERNEL); + if (!arg.chan_list) { + ret = -ENOMEM; + goto exit; + } + + arg.vdev_id = arvif->vdev_id; + arg.scan_id = ATH12K_SCAN_ID; + arg.chan_list[0] = chan->center_freq; + arg.dwell_time_active = scan_time_msec; + arg.dwell_time_passive = scan_time_msec; + arg.max_scan_time = scan_time_msec; + arg.scan_f_passive = 1; + arg.burst_duration = duration; + + ret = ath12k_start_scan(ar, &arg); + if (ret) { + ath12k_warn(ar->ab, "failed to start roc scan: %d\n", ret); + + spin_lock_bh(&ar->data_lock); + ar->scan.state = ATH12K_SCAN_IDLE; + spin_unlock_bh(&ar->data_lock); + goto free_chan_list; + } + + ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ); + if (ret == 0) { + ath12k_warn(ar->ab, "failed to switch to channel for roc scan\n"); + ret = ath12k_scan_stop(ar); + if (ret) + ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret); + ret = -ETIMEDOUT; + goto free_chan_list; + } + + ieee80211_queue_delayed_work(hw, &ar->scan.timeout, + msecs_to_jiffies(duration)); + + ret = 0; + +free_chan_list: + kfree(arg.chan_list); +exit: + mutex_unlock(&ar->conf_mutex); + + return ret; +} + static const struct ieee80211_ops ath12k_ops = { .tx = ath12k_mac_op_tx, .wake_tx_queue = ieee80211_handle_wake_tx_queue, @@ -7123,6 +7635,8 @@ 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, + .remain_on_channel = ath12k_mac_op_remain_on_channel, + .cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel, }; static void ath12k_mac_update_ch_list(struct ath12k *ar, @@ -7158,9 +7672,9 @@ static u32 ath12k_get_phy_id(struct ath12k *ar, u32 band) } static int ath12k_mac_setup_channels_rates(struct ath12k *ar, - u32 supported_bands) + u32 supported_bands, + struct ieee80211_supported_band *bands[]) { - struct ieee80211_hw *hw = ar->hw; struct ieee80211_supported_band *band; struct ath12k_wmi_hal_reg_capabilities_ext_arg *reg_cap; void *channels; @@ -7186,7 +7700,7 @@ 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; - hw->wiphy->bands[NL80211_BAND_2GHZ] = band; + bands[NL80211_BAND_2GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_2G_CAP); @@ -7213,7 +7727,7 @@ 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; - hw->wiphy->bands[NL80211_BAND_6GHZ] = band; + bands[NL80211_BAND_6GHZ] = band; ath12k_mac_update_ch_list(ar, band, reg_cap->low_5ghz_chan, reg_cap->high_5ghz_chan); @@ -7235,7 +7749,7 @@ 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; - hw->wiphy->bands[NL80211_BAND_5GHZ] = band; + bands[NL80211_BAND_5GHZ] = band; if (ar->ab->hw_params->single_pdev_only) { phy_id = ath12k_get_phy_id(ar, WMI_HOST_WLAN_5G_CAP); @@ -7251,28 +7765,59 @@ static int ath12k_mac_setup_channels_rates(struct ath12k *ar, return 0; } -static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) +static u16 ath12k_mac_get_ifmodes(struct ath12k_hw *ah) { - struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ar->hw; - struct wiphy *wiphy = hw->wiphy; + struct ath12k *ar = ath12k_ah_to_ar(ah); + u16 interface_modes = U16_MAX; + + interface_modes &= ar->ab->hw_params->interface_modes; + + return interface_modes == U16_MAX ? 0 : interface_modes; +} + +static bool ath12k_mac_is_iface_mode_enable(struct ath12k_hw *ah, + enum nl80211_iftype type) +{ + struct ath12k *ar = ath12k_ah_to_ar(ah); + u16 interface_modes, mode; + bool is_enable = true; + + mode = BIT(type); + + interface_modes = ar->ab->hw_params->interface_modes; + if (!(interface_modes & mode)) + is_enable = false; + + return is_enable; +} + +static int ath12k_mac_setup_iface_combinations(struct ath12k_hw *ah) +{ + struct wiphy *wiphy = ah->hw->wiphy; struct ieee80211_iface_combination *combinations; struct ieee80211_iface_limit *limits; int n_limits, max_interfaces; - bool ap, mesh; + bool ap, mesh, p2p; - ap = ab->hw_params->interface_modes & BIT(NL80211_IFTYPE_AP); + ap = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_AP); + p2p = ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_P2P_DEVICE); mesh = IS_ENABLED(CONFIG_MAC80211_MESH) && - ab->hw_params->interface_modes & BIT(NL80211_IFTYPE_MESH_POINT); + ath12k_mac_is_iface_mode_enable(ah, NL80211_IFTYPE_MESH_POINT); combinations = kzalloc(sizeof(*combinations), GFP_KERNEL); if (!combinations) return -ENOMEM; - if (ap || mesh) { + if ((ap || mesh) && !p2p) { n_limits = 2; max_interfaces = 16; + } else if (p2p) { + n_limits = 3; + if (ap || mesh) + max_interfaces = 16; + else + max_interfaces = 3; } else { n_limits = 1; max_interfaces = 1; @@ -7287,14 +7832,22 @@ static int ath12k_mac_setup_iface_combinations(struct ath12k *ar) limits[0].max = 1; limits[0].types |= BIT(NL80211_IFTYPE_STATION); - if (ap) { + if (ap || mesh || p2p) limits[1].max = max_interfaces; + + if (ap) limits[1].types |= BIT(NL80211_IFTYPE_AP); - } if (mesh) limits[1].types |= BIT(NL80211_IFTYPE_MESH_POINT); + if (p2p) { + limits[1].types |= BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + limits[2].max = 1; + limits[2].types |= BIT(NL80211_IFTYPE_P2P_DEVICE); + } + combinations[0].limits = limits; combinations[0].n_limits = n_limits; combinations[0].max_interfaces = max_interfaces; @@ -7349,21 +7902,27 @@ static const struct wiphy_iftype_ext_capab ath12k_iftypes_ext_capa[] = { }, }; -static void __ath12k_mac_unregister(struct ath12k *ar) +static void ath12k_mac_cleanup_unregister(struct ath12k *ar) { - struct ieee80211_hw *hw = ar->hw; - struct wiphy *wiphy = hw->wiphy; - - cancel_work_sync(&ar->regd_update_work); - - ieee80211_unregister_hw(hw); - idr_for_each(&ar->txmgmt_idr, ath12k_mac_tx_mgmt_pending_free, ar); idr_destroy(&ar->txmgmt_idr); kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); +} + +static void ath12k_mac_hw_unregister(struct ath12k_hw *ah) +{ + struct ieee80211_hw *hw = ah->hw; + struct wiphy *wiphy = hw->wiphy; + struct ath12k *ar = ath12k_ah_to_ar(ah); + + cancel_work_sync(&ar->regd_update_work); + + ieee80211_unregister_hw(hw); + + ath12k_mac_cleanup_unregister(ar); kfree(wiphy->iface_combinations[0].limits); kfree(wiphy->iface_combinations); @@ -7371,28 +7930,42 @@ static void __ath12k_mac_unregister(struct ath12k *ar) SET_IEEE80211_DEV(hw, NULL); } -void ath12k_mac_unregister(struct ath12k_base *ab) +static int ath12k_mac_setup_register(struct ath12k *ar, + u32 *ht_cap, + struct ieee80211_supported_band *bands[]) { - struct ath12k *ar; - struct ath12k_pdev *pdev; - int i; + struct ath12k_pdev_cap *cap = &ar->pdev->cap; + int ret; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar) - continue; + init_waitqueue_head(&ar->txmgmt_empty_waitq); + idr_init(&ar->txmgmt_idr); + spin_lock_init(&ar->txmgmt_idr_lock); - __ath12k_mac_unregister(ar); - } + ath12k_pdev_caps_update(ar); + + ret = ath12k_mac_setup_channels_rates(ar, + cap->supported_bands, + bands); + if (ret) + return ret; + + ath12k_mac_setup_ht_vht_cap(ar, cap, ht_cap); + ath12k_mac_setup_sband_iftype_data(ar, cap); + + 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); + + return 0; } -static int __ath12k_mac_register(struct ath12k *ar) +static int ath12k_mac_hw_register(struct ath12k_hw *ah) { - struct ath12k_base *ab = ar->ab; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ah->hw; struct wiphy *wiphy = hw->wiphy; - struct ath12k_pdev_cap *cap = &ar->pdev->cap; + struct ath12k *ar = ath12k_ah_to_ar(ah); + struct ath12k_base *ab = ar->ab; + struct ath12k_pdev *pdev; + struct ath12k_pdev_cap *cap; static const u32 cipher_suites[] = { WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, @@ -7407,30 +7980,34 @@ static int __ath12k_mac_register(struct ath12k *ar) int ret; u32 ht_cap = 0; - ath12k_pdev_caps_update(ar); - - SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); + pdev = ar->pdev; - SET_IEEE80211_DEV(hw, ab->dev); + if (ab->pdevs_macaddr_valid) + ether_addr_copy(ar->mac_addr, pdev->mac_addr); + else + ether_addr_copy(ar->mac_addr, ab->mac_addr); - ret = ath12k_mac_setup_channels_rates(ar, - cap->supported_bands); + ret = ath12k_mac_setup_register(ar, &ht_cap, hw->wiphy->bands); if (ret) - goto err; + goto out; - ath12k_mac_setup_ht_vht_cap(ar, cap, &ht_cap); - ath12k_mac_setup_sband_iftype_data(ar, cap); + wiphy->max_ap_assoc_sta = ar->max_num_stations; - ret = ath12k_mac_setup_iface_combinations(ar); - if (ret) { - ath12k_err(ar->ab, "failed to setup interface combinations: %d\n", ret); - goto err_free_channels; - } + cap = &pdev->cap; wiphy->available_antennas_rx = cap->rx_chain_mask; wiphy->available_antennas_tx = cap->tx_chain_mask; - wiphy->interface_modes = ab->hw_params->interface_modes; + SET_IEEE80211_PERM_ADDR(hw, ar->mac_addr); + SET_IEEE80211_DEV(hw, ab->dev); + + ret = ath12k_mac_setup_iface_combinations(ah); + if (ret) { + ath12k_err(ab, "failed to setup interface combinations: %d\n", ret); + goto err_cleanup_unregister; + } + + wiphy->interface_modes = ath12k_mac_get_ifmodes(ah); if (wiphy->bands[NL80211_BAND_2GHZ] && wiphy->bands[NL80211_BAND_5GHZ] && @@ -7483,15 +8060,10 @@ static int __ath12k_mac_register(struct ath12k *ar) wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | NL80211_FEATURE_AP_SCAN; - ar->max_num_stations = TARGET_NUM_STATIONS; - ar->max_num_peers = TARGET_NUM_PEERS_PDEV; - - wiphy->max_ap_assoc_sta = ar->max_num_stations; - hw->queues = ATH12K_HW_MAX_QUEUES; wiphy->tx_queue_len = ATH12K_QUEUE_LEN; hw->offchannel_tx_hw_queue = ATH12K_HW_MAX_QUEUES - 1; - hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE; + hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_EHT; hw->vif_data_size = sizeof(struct ath12k_vif); hw->sta_data_size = sizeof(struct ath12k_sta); @@ -7524,7 +8096,7 @@ static int __ath12k_mac_register(struct ath12k *ar) ret = ieee80211_register_hw(hw); if (ret) { - ath12k_err(ar->ab, "ieee80211 registration failed: %d\n", ret); + ath12k_err(ab, "ieee80211 registration failed: %d\n", ret); goto err_free_if_combs; } @@ -7552,142 +8124,213 @@ err_free_if_combs: kfree(wiphy->iface_combinations[0].limits); kfree(wiphy->iface_combinations); -err_free_channels: - kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); - kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels); +err_cleanup_unregister: + ath12k_mac_cleanup_unregister(ar); -err: +out: SET_IEEE80211_DEV(hw, NULL); + return ret; } +static void ath12k_mac_setup(struct ath12k *ar) +{ + struct ath12k_base *ab = ar->ab; + struct ath12k_pdev *pdev = ar->pdev; + u8 pdev_idx = ar->pdev_idx; + + ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, pdev_idx); + + ar->wmi = &ab->wmi_ab.wmi[pdev_idx]; + /* FIXME: wmi[0] is already initialized during attach, + * Should we do this again? + */ + ath12k_wmi_pdev_attach(ab, pdev_idx); + + ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask; + ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask; + ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask); + ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask); + + spin_lock_init(&ar->data_lock); + INIT_LIST_HEAD(&ar->arvifs); + INIT_LIST_HEAD(&ar->ppdu_stats_info); + mutex_init(&ar->conf_mutex); + init_completion(&ar->vdev_setup_done); + init_completion(&ar->vdev_delete_done); + init_completion(&ar->peer_assoc_done); + init_completion(&ar->peer_delete_done); + init_completion(&ar->install_key_done); + init_completion(&ar->bss_survey_done); + init_completion(&ar->scan.started); + init_completion(&ar->scan.completed); + init_completion(&ar->scan.on_channel); + + INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); + INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); + + INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); + skb_queue_head_init(&ar->wmi_mgmt_tx_queue); + clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); +} + int ath12k_mac_register(struct ath12k_base *ab) { - struct ath12k *ar; - struct ath12k_pdev *pdev; + struct ath12k_hw *ah; int i; int ret; if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) return 0; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (ab->pdevs_macaddr_valid) { - ether_addr_copy(ar->mac_addr, pdev->mac_addr); - } else { - ether_addr_copy(ar->mac_addr, ab->mac_addr); - ar->mac_addr[4] += i; - } - - ret = __ath12k_mac_register(ar); - if (ret) - goto err_cleanup; - - init_waitqueue_head(&ar->txmgmt_empty_waitq); - idr_init(&ar->txmgmt_idr); - spin_lock_init(&ar->txmgmt_idr_lock); - } - /* Initialize channel counters frequency value in hertz */ ab->cc_freq_hz = 320000; ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS)) - 1; + for (i = 0; i < ab->num_hw; i++) { + ah = ab->ah[i]; + + ret = ath12k_mac_hw_register(ah); + if (ret) + goto err; + } + return 0; -err_cleanup: +err: for (i = i - 1; i >= 0; i--) { - pdev = &ab->pdevs[i]; - ar = pdev->ar; - __ath12k_mac_unregister(ar); + ah = ab->ah[i]; + if (!ah) + continue; + + ath12k_mac_hw_unregister(ah); } return ret; } -int ath12k_mac_allocate(struct ath12k_base *ab) +void ath12k_mac_unregister(struct ath12k_base *ab) +{ + struct ath12k_hw *ah; + int i; + + for (i = ab->num_hw - 1; i >= 0; i--) { + ah = ab->ah[i]; + if (!ah) + continue; + + ath12k_mac_hw_unregister(ah); + } +} + +static void ath12k_mac_hw_destroy(struct ath12k_hw *ah) +{ + ieee80211_free_hw(ah->hw); +} + +static struct ath12k_hw *ath12k_mac_hw_allocate(struct ath12k_base *ab, + struct ath12k_pdev_map *pdev_map, + u8 num_pdev_map) { struct ieee80211_hw *hw; struct ath12k *ar; struct ath12k_pdev *pdev; - int ret; + struct ath12k_hw *ah; int i; + u8 pdev_idx; - if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) - return 0; + hw = ieee80211_alloc_hw(struct_size(ah, radio, num_pdev_map), + &ath12k_ops); + if (!hw) + return NULL; - for (i = 0; i < ab->num_radios; i++) { - pdev = &ab->pdevs[i]; - hw = ieee80211_alloc_hw(sizeof(struct ath12k), &ath12k_ops); - if (!hw) { - ath12k_warn(ab, "failed to allocate mac80211 hw device\n"); - ret = -ENOMEM; - goto err_free_mac; - } + ah = ath12k_hw_to_ah(hw); + ah->hw = hw; + ah->num_radio = num_pdev_map; + + for (i = 0; i < num_pdev_map; i++) { + ab = pdev_map[i].ab; + pdev_idx = pdev_map[i].pdev_idx; + pdev = &ab->pdevs[pdev_idx]; - ar = hw->priv; - ar->hw = hw; + ar = ath12k_ah_to_ar(ah); + ar->ah = ah; ar->ab = ab; + ar->hw_link_id = i; ar->pdev = pdev; - ar->pdev_idx = i; - ar->lmac_id = ath12k_hw_get_mac_from_pdev_id(ab->hw_params, i); - - ar->wmi = &ab->wmi_ab.wmi[i]; - /* FIXME: wmi[0] is already initialized during attach, - * Should we do this again? - */ - ath12k_wmi_pdev_attach(ab, i); - - ar->cfg_tx_chainmask = pdev->cap.tx_chain_mask; - ar->cfg_rx_chainmask = pdev->cap.rx_chain_mask; - ar->num_tx_chains = hweight32(pdev->cap.tx_chain_mask); - ar->num_rx_chains = hweight32(pdev->cap.rx_chain_mask); - + ar->pdev_idx = pdev_idx; pdev->ar = ar; - spin_lock_init(&ar->data_lock); - INIT_LIST_HEAD(&ar->arvifs); - INIT_LIST_HEAD(&ar->ppdu_stats_info); - mutex_init(&ar->conf_mutex); - init_completion(&ar->vdev_setup_done); - init_completion(&ar->vdev_delete_done); - init_completion(&ar->peer_assoc_done); - init_completion(&ar->peer_delete_done); - init_completion(&ar->install_key_done); - init_completion(&ar->bss_survey_done); - init_completion(&ar->scan.started); - init_completion(&ar->scan.completed); - - INIT_DELAYED_WORK(&ar->scan.timeout, ath12k_scan_timeout_work); - INIT_WORK(&ar->regd_update_work, ath12k_regd_update_work); - - INIT_WORK(&ar->wmi_mgmt_tx_work, ath12k_mgmt_over_wmi_tx_work); - skb_queue_head_init(&ar->wmi_mgmt_tx_queue); - clear_bit(ATH12K_FLAG_MONITOR_ENABLED, &ar->monitor_flags); - } - return 0; - -err_free_mac: - ath12k_mac_destroy(ab); + ath12k_mac_setup(ar); + } - return ret; + return ah; } void ath12k_mac_destroy(struct ath12k_base *ab) { - struct ath12k *ar; struct ath12k_pdev *pdev; int i; for (i = 0; i < ab->num_radios; i++) { pdev = &ab->pdevs[i]; - ar = pdev->ar; - if (!ar) + if (!pdev->ar) continue; - ieee80211_free_hw(ar->hw); pdev->ar = NULL; } + + for (i = 0; i < ab->num_hw; i++) { + if (!ab->ah[i]) + continue; + + ath12k_mac_hw_destroy(ab->ah[i]); + ab->ah[i] = NULL; + } +} + +int ath12k_mac_allocate(struct ath12k_base *ab) +{ + struct ath12k_hw *ah; + struct ath12k_pdev_map pdev_map[MAX_RADIOS]; + int ret, i, j; + u8 radio_per_hw; + + if (test_bit(ATH12K_FLAG_REGISTERED, &ab->dev_flags)) + return 0; + + ab->num_hw = ab->num_radios; + radio_per_hw = 1; + + for (i = 0; i < ab->num_hw; i++) { + for (j = 0; j < radio_per_hw; j++) { + pdev_map[j].ab = ab; + pdev_map[j].pdev_idx = (i * radio_per_hw) + j; + } + + ah = ath12k_mac_hw_allocate(ab, pdev_map, radio_per_hw); + if (!ah) { + ath12k_warn(ab, "failed to allocate mac80211 hw device for hw_idx %d\n", + i); + ret = -ENOMEM; + goto err; + } + + ab->ah[i] = ah; + } + + ath12k_dp_pdev_pre_alloc(ab); + + return 0; + +err: + for (i = i - 1; i >= 0; i--) { + if (!ab->ah[i]) + continue; + + ath12k_mac_hw_destroy(ab->ah[i]); + ab->ah[i] = NULL; + } + + return ret; } diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h index 7c63bb628a..3f5e1be0df 100644 --- a/drivers/net/wireless/ath/ath12k/mac.h +++ b/drivers/net/wireless/ath/ath12k/mac.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_MAC_H @@ -12,6 +12,8 @@ struct ath12k; struct ath12k_base; +struct ath12k_hw; +struct ath12k_pdev_map; struct ath12k_generic_iter { struct ath12k *ar; diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c index d5441ddb37..adb8c3ec19 100644 --- a/drivers/net/wireless/ath/ath12k/mhi.c +++ b/drivers/net/wireless/ath/ath12k/mhi.c @@ -1,11 +1,12 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/msi.h> #include <linux/pci.h> +#include <linux/firmware.h> #include "core.h" #include "debug.h" @@ -13,6 +14,8 @@ #include "pci.h" #define MHI_TIMEOUT_DEFAULT_MS 90000 +#define OTP_INVALID_BOARD_ID 0xFFFF +#define OTP_VALID_DUALMAC_BOARD_ID_MASK 0x1000 static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = { { @@ -358,23 +361,60 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci) { struct ath12k_base *ab = ab_pci->ab; struct mhi_controller *mhi_ctrl; + unsigned int board_id; int ret; + bool dualmac = false; mhi_ctrl = mhi_alloc_controller(); if (!mhi_ctrl) return -ENOMEM; - ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, - ab_pci->amss_path, - sizeof(ab_pci->amss_path)); - ab_pci->mhi_ctrl = mhi_ctrl; mhi_ctrl->cntrl_dev = ab->dev; - mhi_ctrl->fw_image = ab_pci->amss_path; mhi_ctrl->regs = ab->mem; mhi_ctrl->reg_len = ab->mem_len; mhi_ctrl->rddm_size = ab->hw_params->rddm_size; + if (ab->hw_params->otp_board_id_register) { + board_id = + ath12k_pci_read32(ab, ab->hw_params->otp_board_id_register); + board_id = u32_get_bits(board_id, OTP_BOARD_ID_MASK); + + if (!board_id || (board_id == OTP_INVALID_BOARD_ID)) { + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "failed to read board id\n"); + } else if (board_id & OTP_VALID_DUALMAC_BOARD_ID_MASK) { + dualmac = true; + ab->slo_capable = false; + ath12k_dbg(ab, ATH12K_DBG_BOOT, + "dualmac fw selected for board id: %x\n", board_id); + } + } + + if (dualmac) { + if (ab->fw.amss_dualmac_data && ab->fw.amss_dualmac_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_dualmac_data; + mhi_ctrl->fw_sz = ab->fw.amss_dualmac_len; + } else { + ath12k_warn(ab, "dualmac firmware IE not present in firmware-N.bin\n"); + ret = -ENOENT; + goto free_controller; + } + } else { + if (ab->fw.amss_data && ab->fw.amss_len > 0) { + /* use MHI firmware file from firmware-N.bin */ + mhi_ctrl->fw_data = ab->fw.amss_data; + mhi_ctrl->fw_sz = ab->fw.amss_len; + } else { + /* use the old separate mhi.bin MHI firmware file */ + ath12k_core_create_firmware_path(ab, ATH12K_AMSS_FILE, + ab_pci->amss_path, + sizeof(ab_pci->amss_path)); + mhi_ctrl->fw_image = ab_pci->amss_path; + } + } + ret = ath12k_mhi_get_msi(ab_pci); if (ret) { ath12k_err(ab, "failed to get msi for mhi\n"); diff --git a/drivers/net/wireless/ath/ath12k/p2p.c b/drivers/net/wireless/ath/ath12k/p2p.c new file mode 100644 index 0000000000..d334df7200 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/p2p.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + */ + +#include <net/mac80211.h> +#include "core.h" +#include "mac.h" +#include "p2p.h" + +static void ath12k_p2p_noa_ie_fill(u8 *data, size_t len, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ieee80211_p2p_noa_attr *noa_attr; + u8 ctwindow = le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_CTWIN_TU); + bool oppps = le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS); + __le16 *noa_attr_len; + u16 attr_len; + u8 noa_descriptors = le32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_DESC_NUM); + int i; + + /* P2P IE */ + data[0] = WLAN_EID_VENDOR_SPECIFIC; + data[1] = len - 2; + data[2] = (WLAN_OUI_WFA >> 16) & 0xff; + data[3] = (WLAN_OUI_WFA >> 8) & 0xff; + data[4] = (WLAN_OUI_WFA >> 0) & 0xff; + data[5] = WLAN_OUI_TYPE_WFA_P2P; + + /* NOA ATTR */ + data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE; + noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */ + noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9]; + + noa_attr->index = le32_get_bits(noa->noa_attr, + WMI_P2P_NOA_INFO_INDEX); + noa_attr->oppps_ctwindow = ctwindow; + if (oppps) + noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT; + + for (i = 0; i < noa_descriptors; i++) { + noa_attr->desc[i].count = + __le32_to_cpu(noa->descriptors[i].type_count); + noa_attr->desc[i].duration = noa->descriptors[i].duration; + noa_attr->desc[i].interval = noa->descriptors[i].interval; + noa_attr->desc[i].start_time = noa->descriptors[i].start_time; + } + + attr_len = 2; /* index + oppps_ctwindow */ + attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc); + *noa_attr_len = __cpu_to_le16(attr_len); +} + +static size_t ath12k_p2p_noa_ie_len_compute(const struct ath12k_wmi_p2p_noa_info *noa) +{ + size_t len = 0; + + if (!(le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)) && + !(le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_OPP_PS))) + return 0; + + len += 1 + 1 + 4; /* EID + len + OUI */ + len += 1 + 2; /* noa attr + attr len */ + len += 1 + 1; /* index + oppps_ctwindow */ + len += le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM) * + sizeof(struct ieee80211_p2p_noa_desc); + + return len; +} + +static void ath12k_p2p_noa_ie_assign(struct ath12k_vif *arvif, void *ie, + size_t len) +{ + struct ath12k *ar = arvif->ar; + + lockdep_assert_held(&ar->data_lock); + + kfree(arvif->u.ap.noa_data); + + arvif->u.ap.noa_data = ie; + arvif->u.ap.noa_len = len; +} + +static void __ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k *ar = arvif->ar; + void *ie; + size_t len; + + lockdep_assert_held(&ar->data_lock); + + ath12k_p2p_noa_ie_assign(arvif, NULL, 0); + + len = ath12k_p2p_noa_ie_len_compute(noa); + if (!len) + return; + + ie = kmalloc(len, GFP_ATOMIC); + if (!ie) + return; + + ath12k_p2p_noa_ie_fill(ie, len, noa); + ath12k_p2p_noa_ie_assign(arvif, ie, len); +} + +void ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k *ar = arvif->ar; + + spin_lock_bh(&ar->data_lock); + __ath12k_p2p_noa_update(arvif, noa); + spin_unlock_bh(&ar->data_lock); +} + +static void ath12k_p2p_noa_update_vdev_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct ath12k_vif *arvif = ath12k_vif_to_arvif(vif); + struct ath12k_p2p_noa_arg *arg = data; + + if (arvif->vdev_id != arg->vdev_id) + return; + + ath12k_p2p_noa_update(arvif, arg->noa); +} + +void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, + const struct ath12k_wmi_p2p_noa_info *noa) +{ + struct ath12k_p2p_noa_arg arg = { + .vdev_id = vdev_id, + .noa = noa, + }; + + ieee80211_iterate_active_interfaces_atomic(ath12k_ar_to_hw(ar), + IEEE80211_IFACE_ITER_NORMAL, + ath12k_p2p_noa_update_vdev_iter, + &arg); +} diff --git a/drivers/net/wireless/ath/ath12k/p2p.h b/drivers/net/wireless/ath/ath12k/p2p.h new file mode 100644 index 0000000000..5768139a78 --- /dev/null +++ b/drivers/net/wireless/ath/ath12k/p2p.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* + * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.. + */ + +#ifndef ATH12K_P2P_H +#define ATH12K_P2P_H + +#include "wmi.h" + +struct ath12k_wmi_p2p_noa_info; + +struct ath12k_p2p_noa_arg { + u32 vdev_id; + const struct ath12k_wmi_p2p_noa_info *noa; +}; + +void ath12k_p2p_noa_update(struct ath12k_vif *arvif, + const struct ath12k_wmi_p2p_noa_info *noa); +void ath12k_p2p_noa_update_by_vdev_id(struct ath12k *ar, u32 vdev_id, + const struct ath12k_wmi_p2p_noa_info *noa); + +#endif diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index f0d2e2d871..14954bc051 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/module.h> @@ -39,6 +39,10 @@ #define QCN9274_DEVICE_ID 0x1109 #define WCN7850_DEVICE_ID 0x1107 +#define PCIE_LOCAL_REG_QRTR_NODE_ID 0x1E03164 +#define DOMAIN_NUMBER_MASK GENMASK(7, 4) +#define BUS_NUMBER_MASK GENMASK(3, 0) + static const struct pci_device_id ath12k_pci_id_table[] = { { PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) }, { PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) }, @@ -201,18 +205,17 @@ static u32 ath12k_pci_get_window_start(struct ath12k_base *ab, /* If offset lies within CE register range, use 2nd window */ else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK) window_start = 2 * WINDOW_START; - /* If offset lies within PCI_BAR_WINDOW0_BASE and within PCI_SOC_PCI_REG_BASE - * use 0th window - */ - else if (((offset ^ PCI_BAR_WINDOW0_BASE) < WINDOW_RANGE_MASK) && - !((offset ^ PCI_SOC_PCI_REG_BASE) < PCI_SOC_RANGE_MASK)) - window_start = 0; else window_start = WINDOW_START; return window_start; } +static inline bool ath12k_pci_is_offset_within_mhi_region(u32 offset) +{ + return (offset >= PCI_MHIREGLEN_REG && offset <= PCI_MHI_REGION_END); +} + static void ath12k_pci_soc_global_reset(struct ath12k_base *ab) { u32 val, delay; @@ -682,12 +685,22 @@ static void ath12k_pci_init_qmi_ce_config(struct ath12k_base *ab) { struct ath12k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg; + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + struct pci_bus *bus = ab_pci->pdev->bus; + cfg->tgt_ce = ab->hw_params->target_ce_config; cfg->tgt_ce_len = ab->hw_params->target_ce_count; cfg->svc_to_ce_map = ab->hw_params->svc_to_ce_map; cfg->svc_to_ce_map_len = ab->hw_params->svc_to_ce_map_len; ab->qmi.service_ins_id = ab->hw_params->qmi_service_ins_id; + + if (test_bit(ATH12K_FW_FEATURE_MULTI_QRTR_ID, ab->fw.fw_features)) { + ab_pci->qmi_instance = + u32_encode_bits(pci_domain_nr(bus), DOMAIN_NUMBER_MASK) | + u32_encode_bits(bus->number, BUS_NUMBER_MASK); + ab->qmi.service_ins_id += ab_pci->qmi_instance; + } } static void ath12k_pci_ce_irqs_enable(struct ath12k_base *ab) @@ -901,6 +914,26 @@ static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci) set_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags); } +static void ath12k_pci_update_qrtr_node_id(struct ath12k_base *ab) +{ + struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); + u32 reg; + + /* On platforms with two or more identical mhi devices, qmi service run + * with identical qrtr-node-id. Because of this identical ID qrtr-lookup + * cannot register more than one qmi service with identical node ID. + * + * This generates a unique instance ID from PCIe domain number and bus number, + * writes to the given register, it is available for firmware when the QMI service + * is spawned. + */ + reg = PCIE_LOCAL_REG_QRTR_NODE_ID & WINDOW_RANGE_MASK; + ath12k_pci_write32(ab, reg, ab_pci->qmi_instance); + + ath12k_dbg(ab, ATH12K_DBG_PCI, "pci reg 0x%x instance 0x%x read val 0x%x\n", + reg, ab_pci->qmi_instance, ath12k_pci_read32(ab, reg)); +} + static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci) { if (test_and_clear_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags)) @@ -1138,15 +1171,17 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset) if (window_start == WINDOW_START) { spin_lock_bh(&ab_pci->window_lock); ath12k_pci_select_window(ab_pci, offset); - val = ioread32(ab->mem + window_start + - (offset & WINDOW_RANGE_MASK)); + + if (ath12k_pci_is_offset_within_mhi_region(offset)) { + offset = offset - PCI_MHIREGLEN_REG; + val = ioread32(ab->mem + + (offset & WINDOW_RANGE_MASK)); + } else { + val = ioread32(ab->mem + window_start + + (offset & WINDOW_RANGE_MASK)); + } spin_unlock_bh(&ab_pci->window_lock); } else { - if ((!window_start) && - (offset >= PCI_MHIREGLEN_REG && - offset <= PCI_MHI_REGION_END)) - offset = offset - PCI_MHIREGLEN_REG; - val = ioread32(ab->mem + window_start + (offset & WINDOW_RANGE_MASK)); } @@ -1183,15 +1218,17 @@ void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value) if (window_start == WINDOW_START) { spin_lock_bh(&ab_pci->window_lock); ath12k_pci_select_window(ab_pci, offset); - iowrite32(value, ab->mem + window_start + - (offset & WINDOW_RANGE_MASK)); + + if (ath12k_pci_is_offset_within_mhi_region(offset)) { + offset = offset - PCI_MHIREGLEN_REG; + iowrite32(value, ab->mem + + (offset & WINDOW_RANGE_MASK)); + } else { + iowrite32(value, ab->mem + window_start + + (offset & WINDOW_RANGE_MASK)); + } spin_unlock_bh(&ab_pci->window_lock); } else { - if ((!window_start) && - (offset >= PCI_MHIREGLEN_REG && - offset <= PCI_MHI_REGION_END)) - offset = offset - PCI_MHIREGLEN_REG; - iowrite32(value, ab->mem + window_start + (offset & WINDOW_RANGE_MASK)); } @@ -1219,6 +1256,9 @@ int ath12k_pci_power_up(struct ath12k_base *ab) ath12k_pci_msi_enable(ab_pci); + if (test_bit(ATH12K_FW_FEATURE_MULTI_QRTR_ID, ab->fw.fw_features)) + ath12k_pci_update_qrtr_node_id(ab); + ret = ath12k_mhi_start(ab_pci); if (ret) { ath12k_err(ab, "failed to start mhi: %d\n", ret); @@ -1310,11 +1350,21 @@ static int ath12k_pci_probe(struct pci_dev *pdev, goto err_free_core; } + ath12k_dbg(ab, ATH12K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", + pdev->vendor, pdev->device, + pdev->subsystem_vendor, pdev->subsystem_device); + + ab->id.vendor = pdev->vendor; + ab->id.device = pdev->device; + ab->id.subsystem_vendor = pdev->subsystem_vendor; + ab->id.subsystem_device = pdev->subsystem_device; + switch (pci_dev->device) { case QCN9274_DEVICE_ID: ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = true; ab_pci->pci_ops = &ath12k_pci_ops_qcn9274; + ab->hal_rx_ops = &hal_rx_qcn9274_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { @@ -1333,9 +1383,11 @@ static int ath12k_pci_probe(struct pci_dev *pdev, } break; case WCN7850_DEVICE_ID: + ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD; ab_pci->msi_config = &ath12k_msi_config[0]; ab->static_window_map = false; ab_pci->pci_ops = &ath12k_pci_ops_wcn7850; + ab->hal_rx_ops = &hal_rx_wcn7850_ops; ath12k_pci_read_hw_version(ab, &soc_hw_version_major, &soc_hw_version_minor); switch (soc_hw_version_major) { diff --git a/drivers/net/wireless/ath/ath12k/pci.h b/drivers/net/wireless/ath/ath12k/pci.h index b2edf32ada..ca93693ba4 100644 --- a/drivers/net/wireless/ath/ath12k/pci.h +++ b/drivers/net/wireless/ath/ath12k/pci.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_PCI_H #define ATH12K_PCI_H @@ -53,6 +53,9 @@ #define WLAON_QFPROM_PWR_CTRL_REG 0x01f8031c #define QFPROM_PWR_CTRL_VDD4BLOW_MASK 0x4 +#define QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB 0x1E20338 +#define OTP_BOARD_ID_MASK GENMASK(15, 0) + #define PCI_BAR_WINDOW0_BASE 0x1E00000 #define PCI_BAR_WINDOW0_END 0x1E7FFFC #define PCI_SOC_RANGE_MASK 0x3FFF @@ -111,6 +114,7 @@ struct ath12k_pci { u16 link_ctl; unsigned long irq_flags; const struct ath12k_pci_ops *pci_ops; + u32 qmi_instance; }; static inline struct ath12k_pci *ath12k_pci_priv(struct ath12k_base *ab) diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c index b3440a5e38..e8eb996380 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.c +++ b/drivers/net/wireless/ath/ath12k/qmi.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/elf.h> @@ -17,7 +17,7 @@ #define PLATFORM_CAP_PCIE_GLOBAL_RESET 0x08 #define ATH12K_QMI_MAX_CHUNK_SIZE 2097152 -static struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { +static const struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, @@ -61,7 +61,7 @@ static struct qmi_elem_info wlfw_host_mlo_chip_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -511,7 +511,7 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -528,7 +528,68 @@ static struct qmi_elem_info qmi_wlanfw_host_cap_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_phy_cap_req_msg_v01_ei[] = { + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info qmi_wlanfw_phy_cap_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + num_phy_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + num_phy), + }, + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + board_id_valid), + }, + { + .data_type = QMI_UNSIGNED_4_BYTE, + .elem_len = 1, + .elem_size = sizeof(u32), + .array_type = NO_ARRAY, + .tlv_type = 0x11, + .offset = offsetof(struct qmi_wlanfw_phy_cap_resp_msg_v01, + board_id), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -753,7 +814,7 @@ static struct qmi_elem_info qmi_wlanfw_ind_register_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -789,7 +850,7 @@ static struct qmi_elem_info qmi_wlanfw_ind_register_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -821,7 +882,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -863,7 +924,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_seg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, @@ -890,7 +951,7 @@ static struct qmi_elem_info qmi_wlanfw_request_mem_ind_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -930,7 +991,7 @@ static struct qmi_elem_info qmi_wlanfw_mem_seg_resp_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, @@ -957,7 +1018,7 @@ static struct qmi_elem_info qmi_wlanfw_respond_mem_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -975,7 +1036,7 @@ static struct qmi_elem_info qmi_wlanfw_respond_mem_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, @@ -983,7 +1044,7 @@ static struct qmi_elem_info qmi_wlanfw_cap_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1009,7 +1070,7 @@ static struct qmi_elem_info qmi_wlanfw_rf_chip_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1026,7 +1087,7 @@ static struct qmi_elem_info qmi_wlanfw_rf_board_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1042,7 +1103,7 @@ static struct qmi_elem_info qmi_wlanfw_soc_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -1068,7 +1129,7 @@ static struct qmi_elem_info qmi_wlanfw_dev_mem_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1094,7 +1155,7 @@ static struct qmi_elem_info qmi_wlanfw_fw_version_info_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1348,7 +1409,7 @@ static struct qmi_elem_info qmi_wlanfw_cap_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_1_BYTE, .elem_len = 1, @@ -1483,7 +1544,7 @@ static struct qmi_elem_info qmi_wlanfw_bdf_download_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1501,7 +1562,7 @@ static struct qmi_elem_info qmi_wlanfw_bdf_download_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_8_BYTE, .elem_len = 1, @@ -1525,7 +1586,7 @@ static struct qmi_elem_info qmi_wlanfw_m3_info_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1542,7 +1603,7 @@ static struct qmi_elem_info qmi_wlanfw_m3_info_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1595,7 +1656,7 @@ static struct qmi_elem_info qmi_wlanfw_ce_tgt_pipe_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1630,7 +1691,7 @@ static struct qmi_elem_info qmi_wlanfw_ce_svc_pipe_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_2_BYTE, .elem_len = 1, @@ -1654,7 +1715,7 @@ static struct qmi_elem_info qmi_wlanfw_shadow_reg_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1671,7 +1732,7 @@ static struct qmi_elem_info qmi_wlanfw_shadow_reg_v3_cfg_s_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { { .data_type = QMI_UNSIGNED_4_BYTE, .elem_len = 1, @@ -1706,7 +1767,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_mode_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1724,7 +1785,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_mode_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { { .data_type = QMI_OPT_FLAG, .elem_len = 1, @@ -1862,7 +1923,7 @@ static struct qmi_elem_info qmi_wlanfw_wlan_cfg_req_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { { .data_type = QMI_STRUCT, .elem_len = 1, @@ -1879,22 +1940,78 @@ static struct qmi_elem_info qmi_wlanfw_wlan_cfg_resp_msg_v01_ei[] = { }, }; -static struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_mem_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, }, }; -static struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { +static const struct qmi_elem_info qmi_wlanfw_fw_ready_ind_msg_v01_ei[] = { { .data_type = QMI_EOTI, .array_type = NO_ARRAY, }, }; -static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *req) +static const struct qmi_elem_info qmi_wlanfw_wlan_ini_req_msg_v01_ei[] = { + { + .data_type = QMI_OPT_FLAG, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01, + enable_fwlog_valid), + }, + { + .data_type = QMI_UNSIGNED_1_BYTE, + .elem_len = 1, + .elem_size = sizeof(u8), + .array_type = NO_ARRAY, + .tlv_type = 0x10, + .offset = offsetof(struct qmi_wlanfw_wlan_ini_req_msg_v01, + enable_fwlog), + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static const struct qmi_elem_info qmi_wlanfw_wlan_ini_resp_msg_v01_ei[] = { + { + .data_type = QMI_STRUCT, + .elem_len = 1, + .elem_size = sizeof(struct qmi_response_type_v01), + .array_type = NO_ARRAY, + .tlv_type = 0x02, + .offset = offsetof(struct qmi_wlanfw_wlan_ini_resp_msg_v01, + resp), + .ei_array = qmi_response_type_v01_ei, + }, + { + .data_type = QMI_EOTI, + .array_type = NO_ARRAY, + .tlv_type = QMI_COMMON_TLV_TYPE, + }, +}; + +static void ath12k_host_cap_parse_mlo(struct ath12k_base *ab, + struct qmi_wlanfw_host_cap_req_msg_v01 *req) { + struct wlfw_host_mlo_chip_info_s_v01 *info; + u8 hw_link_id = 0; + int i; + + if (!ab->qmi.num_radios || ab->qmi.num_radios == U8_MAX) { + ath12k_dbg(ab, ATH12K_DBG_QMI, + "skip QMI MLO cap due to invalid num_radio %d\n", + ab->qmi.num_radios); + return; + } + req->mlo_capable_valid = 1; req->mlo_capable = 1; req->mlo_chip_id_valid = 1; @@ -1905,28 +2022,31 @@ static void ath12k_host_cap_parse_mlo(struct qmi_wlanfw_host_cap_req_msg_v01 *re /* Max peer number generally won't change for the same device * but needs to be synced with host driver. */ - req->max_mlo_peer = 32; + req->max_mlo_peer = ab->hw_params->max_mlo_peer; req->mlo_num_chips_valid = 1; req->mlo_num_chips = 1; + + info = &req->mlo_chip_info[0]; + info->chip_id = 0; + info->num_local_links = ab->qmi.num_radios; + + for (i = 0; i < info->num_local_links; i++) { + info->hw_link_id[i] = hw_link_id; + info->valid_mlo_link_id[i] = 1; + + hw_link_id++; + } + req->mlo_chip_info_valid = 1; - req->mlo_chip_info[0].chip_id = 0; - req->mlo_chip_info[0].num_local_links = 2; - req->mlo_chip_info[0].hw_link_id[0] = 0; - req->mlo_chip_info[0].hw_link_id[1] = 1; - req->mlo_chip_info[0].valid_mlo_link_id[0] = 1; - req->mlo_chip_info[0].valid_mlo_link_id[1] = 1; } static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) { - struct qmi_wlanfw_host_cap_req_msg_v01 req; - struct qmi_wlanfw_host_cap_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_wlanfw_host_cap_req_msg_v01 req = {}; + struct qmi_wlanfw_host_cap_resp_msg_v01 resp = {}; + struct qmi_txn txn; int ret = 0; - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - req.num_clients_valid = 1; req.num_clients = 1; req.mem_cfg_mode = ab->qmi.target_mem_mode; @@ -1963,10 +2083,10 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) */ req.nm_modem |= SLEEP_CLOCK_SELECT_INTERNAL_BIT; req.nm_modem |= PLATFORM_CAP_PCIE_GLOBAL_RESET; - - ath12k_host_cap_parse_mlo(&req); } + ath12k_host_cap_parse_mlo(ab, &req); + ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_host_cap_resp_msg_v01_ei, &resp); if (ret < 0) @@ -1977,6 +2097,7 @@ static int ath12k_qmi_host_cap_send(struct ath12k_base *ab) QMI_WLANFW_HOST_CAP_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_host_cap_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "Failed to send host capability request,err = %d\n", ret); goto out; } @@ -1996,6 +2117,62 @@ out: return ret; } +static void ath12k_qmi_phy_cap_send(struct ath12k_base *ab) +{ + struct qmi_wlanfw_phy_cap_req_msg_v01 req = {}; + struct qmi_wlanfw_phy_cap_resp_msg_v01 resp = {}; + struct qmi_txn txn; + int ret; + + if (!ab->slo_capable) + goto out; + + ret = qmi_txn_init(&ab->qmi.handle, &txn, + qmi_wlanfw_phy_cap_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, + QMI_WLANFW_PHY_CAP_REQ_V01, + QMI_WLANFW_PHY_CAP_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_phy_cap_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath12k_warn(ab, "failed to send phy capability request: %d\n", ret); + goto out; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS)); + if (ret < 0) + goto out; + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ret = -EOPNOTSUPP; + goto out; + } + + if (!resp.num_phy_valid) { + ret = -ENODATA; + goto out; + } + + ab->qmi.num_radios = resp.num_phy; + + ath12k_dbg(ab, ATH12K_DBG_QMI, "phy capability resp valid %d num_phy %d valid %d board_id %d\n", + resp.num_phy_valid, resp.num_phy, + resp.board_id_valid, resp.board_id); + + return; + +out: + /* If PHY capability not advertised then rely on default num link */ + ab->qmi.num_radios = ab->hw_params->def_num_link; + + ath12k_dbg(ab, ATH12K_DBG_QMI, + "no valid response from PHY capability, choose default num_phy %d\n", + ab->qmi.num_radios); +} + static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab) { struct qmi_wlanfw_ind_register_req_msg_v01 *req; @@ -2040,6 +2217,7 @@ static int ath12k_qmi_fw_ind_register_send(struct ath12k_base *ab) QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_ind_register_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "Failed to send indication register request, err = %d\n", ret); goto out; @@ -2068,8 +2246,8 @@ resp_out: static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) { struct qmi_wlanfw_respond_mem_req_msg_v01 *req; - struct qmi_wlanfw_respond_mem_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_wlanfw_respond_mem_resp_msg_v01 resp = {}; + struct qmi_txn txn; int ret = 0, i; bool delayed; @@ -2077,8 +2255,6 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) if (!req) return -ENOMEM; - memset(&resp, 0, sizeof(resp)); - /* Some targets by default request a block of big contiguous * DMA memory, it's hard to allocate from kernel. So host returns * failure to firmware and firmware then request multiple blocks of @@ -2088,7 +2264,6 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) delayed = true; ath12k_dbg(ab, ATH12K_DBG_QMI, "qmi delays mem_request %d\n", ab->qmi.mem_seg_count); - memset(req, 0, sizeof(*req)); } else { delayed = false; req->mem_seg_len = ab->qmi.mem_seg_count; @@ -2114,6 +2289,7 @@ static int ath12k_qmi_respond_fw_mem_request(struct ath12k_base *ab) QMI_WLANFW_RESPOND_MEM_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_respond_mem_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to respond memory request, err = %d\n", ret); goto out; @@ -2149,8 +2325,9 @@ static void ath12k_qmi_free_target_mem_chunk(struct ath12k_base *ab) for (i = 0; i < ab->qmi.mem_seg_count; i++) { if (!ab->qmi.target_mem[i].v.addr) continue; + dma_free_coherent(ab->dev, - ab->qmi.target_mem[i].size, + ab->qmi.target_mem[i].prev_size, ab->qmi.target_mem[i].v.addr, ab->qmi.target_mem[i].paddr); ab->qmi.target_mem[i].v.addr = NULL; @@ -2176,6 +2353,20 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) case M3_DUMP_REGION_TYPE: case PAGEABLE_MEM_REGION_TYPE: case CALDB_MEM_REGION_TYPE: + /* Firmware reloads in recovery/resume. + * In such cases, no need to allocate memory for FW again. + */ + if (chunk->v.addr) { + if (chunk->prev_type == chunk->type && + chunk->prev_size == chunk->size) + goto this_chunk_done; + + /* cannot reuse the existing chunk */ + dma_free_coherent(ab->dev, chunk->prev_size, + chunk->v.addr, chunk->paddr); + chunk->v.addr = NULL; + } + chunk->v.addr = dma_alloc_coherent(ab->dev, chunk->size, &chunk->paddr, @@ -2194,6 +2385,10 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) chunk->type, chunk->size); return -ENOMEM; } + + chunk->prev_type = chunk->type; + chunk->prev_size = chunk->size; +this_chunk_done: break; default: ath12k_warn(ab, "memory type %u not supported\n", @@ -2208,17 +2403,14 @@ static int ath12k_qmi_alloc_target_mem_chunk(struct ath12k_base *ab) static int ath12k_qmi_request_target_cap(struct ath12k_base *ab) { - struct qmi_wlanfw_cap_req_msg_v01 req; - struct qmi_wlanfw_cap_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_wlanfw_cap_req_msg_v01 req = {}; + struct qmi_wlanfw_cap_resp_msg_v01 resp = {}; + struct qmi_txn txn; unsigned int board_id = ATH12K_BOARD_ID_DEFAULT; int ret = 0; int r; int i; - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - ret = qmi_txn_init(&ab->qmi.handle, &txn, qmi_wlanfw_cap_resp_msg_v01_ei, &resp); if (ret < 0) @@ -2229,6 +2421,7 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab) QMI_WLANFW_CAP_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_cap_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send target cap request, err = %d\n", ret); goto out; @@ -2310,8 +2503,8 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab, const u8 *data, u32 len, u8 type) { struct qmi_wlanfw_bdf_download_req_msg_v01 *req; - struct qmi_wlanfw_bdf_download_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_wlanfw_bdf_download_resp_msg_v01 resp = {}; + struct qmi_txn txn; const u8 *temp = data; int ret; u32 remaining = len; @@ -2319,7 +2512,6 @@ static int ath12k_qmi_load_file_target_mem(struct ath12k_base *ab, req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) return -ENOMEM; - memset(&resp, 0, sizeof(resp)); while (remaining) { req->valid = 1; @@ -2423,8 +2615,7 @@ static int ath12k_qmi_load_bdf_qmi(struct ath12k_base *ab, break; case ATH12K_QMI_BDF_TYPE_REGDB: - ret = ath12k_core_fetch_board_data_api_1(ab, &bd, - ATH12K_REGDB_FILE_NAME); + ret = ath12k_core_fetch_regdb(ab, &bd); if (ret) { ath12k_warn(ab, "qmi failed to load regdb bin:\n"); goto out; @@ -2494,66 +2685,88 @@ out: return ret; } +static void ath12k_qmi_m3_free(struct ath12k_base *ab) +{ + struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; + + if (!m3_mem->vaddr) + return; + + dma_free_coherent(ab->dev, m3_mem->size, + m3_mem->vaddr, m3_mem->paddr); + m3_mem->vaddr = NULL; + m3_mem->size = 0; +} + static int ath12k_qmi_m3_load(struct ath12k_base *ab) { struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; - const struct firmware *fw; + const struct firmware *fw = NULL; + const void *m3_data; char path[100]; + size_t m3_len; int ret; - if (m3_mem->vaddr || m3_mem->size) - return 0; + if (ab->fw.m3_data && ab->fw.m3_len > 0) { + /* firmware-N.bin had a m3 firmware file so use that */ + m3_data = ab->fw.m3_data; + m3_len = ab->fw.m3_len; + } else { + /* No m3 file in firmware-N.bin so try to request old + * separate m3.bin. + */ + fw = ath12k_core_firmware_request(ab, ATH12K_M3_FILE); + if (IS_ERR(fw)) { + ret = PTR_ERR(fw); + ath12k_core_create_firmware_path(ab, ATH12K_M3_FILE, + path, sizeof(path)); + ath12k_err(ab, "failed to load %s: %d\n", path, ret); + return ret; + } - fw = ath12k_core_firmware_request(ab, ATH12K_M3_FILE); - if (IS_ERR(fw)) { - ret = PTR_ERR(fw); - ath12k_core_create_firmware_path(ab, ATH12K_M3_FILE, - path, sizeof(path)); - ath12k_err(ab, "failed to load %s: %d\n", path, ret); - return ret; + m3_data = fw->data; + m3_len = fw->size; + } + + /* In recovery/resume cases, M3 buffer is not freed, try to reuse that */ + if (m3_mem->vaddr) { + if (m3_mem->size >= m3_len) + goto skip_m3_alloc; + + /* Old buffer is too small, free and reallocate */ + ath12k_qmi_m3_free(ab); } m3_mem->vaddr = dma_alloc_coherent(ab->dev, - fw->size, &m3_mem->paddr, + m3_len, &m3_mem->paddr, GFP_KERNEL); if (!m3_mem->vaddr) { ath12k_err(ab, "failed to allocate memory for M3 with size %zu\n", fw->size); - release_firmware(fw); - return -ENOMEM; + ret = -ENOMEM; + goto out; } - memcpy(m3_mem->vaddr, fw->data, fw->size); - m3_mem->size = fw->size; - release_firmware(fw); - - return 0; -} +skip_m3_alloc: + memcpy(m3_mem->vaddr, m3_data, m3_len); + m3_mem->size = m3_len; -static void ath12k_qmi_m3_free(struct ath12k_base *ab) -{ - struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; + ret = 0; - if (!m3_mem->vaddr) - return; +out: + release_firmware(fw); - dma_free_coherent(ab->dev, m3_mem->size, - m3_mem->vaddr, m3_mem->paddr); - m3_mem->vaddr = NULL; - m3_mem->size = 0; + return ret; } static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) { struct m3_mem_region *m3_mem = &ab->qmi.m3_mem; - struct qmi_wlanfw_m3_info_req_msg_v01 req; - struct qmi_wlanfw_m3_info_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_wlanfw_m3_info_req_msg_v01 req = {}; + struct qmi_wlanfw_m3_info_resp_msg_v01 resp = {}; + struct qmi_txn txn; int ret = 0; - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - ret = ath12k_qmi_m3_load(ab); if (ret) { ath12k_err(ab, "failed to load m3 firmware: %d", ret); @@ -2573,6 +2786,7 @@ static int ath12k_qmi_wlanfw_m3_info_send(struct ath12k_base *ab) QMI_WLANFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN, qmi_wlanfw_m3_info_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send M3 information request, err = %d\n", ret); goto out; @@ -2597,14 +2811,11 @@ out: static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, u32 mode) { - struct qmi_wlanfw_wlan_mode_req_msg_v01 req; - struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp; - struct qmi_txn txn = {}; + struct qmi_wlanfw_wlan_mode_req_msg_v01 req = {}; + struct qmi_wlanfw_wlan_mode_resp_msg_v01 resp = {}; + struct qmi_txn txn; int ret = 0; - memset(&req, 0, sizeof(req)); - memset(&resp, 0, sizeof(resp)); - req.mode = mode; req.hw_debug_valid = 1; req.hw_debug = 0; @@ -2619,6 +2830,7 @@ static int ath12k_qmi_wlanfw_mode_send(struct ath12k_base *ab, QMI_WLANFW_WLAN_MODE_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_wlan_mode_req_msg_v01_ei, &req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send mode request, mode: %d, err = %d\n", mode, ret); goto out; @@ -2649,10 +2861,10 @@ out: static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) { struct qmi_wlanfw_wlan_cfg_req_msg_v01 *req; - struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp; + struct qmi_wlanfw_wlan_cfg_resp_msg_v01 resp = {}; struct ce_pipe_config *ce_cfg; struct service_to_pipe *svc_cfg; - struct qmi_txn txn = {}; + struct qmi_txn txn; int ret = 0, pipe_num; ce_cfg = (struct ce_pipe_config *)ab->qmi.ce_cfg.tgt_ce; @@ -2662,8 +2874,6 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) if (!req) return -ENOMEM; - memset(&resp, 0, sizeof(resp)); - req->host_version_valid = 1; strscpy(req->host_version, ATH12K_HOST_VERSION_STRING, sizeof(req->host_version)); @@ -2710,6 +2920,7 @@ static int ath12k_qmi_wlanfw_wlan_cfg_send(struct ath12k_base *ab) QMI_WLANFW_WLAN_CFG_REQ_MSG_V01_MAX_LEN, qmi_wlanfw_wlan_cfg_req_msg_v01_ei, req); if (ret < 0) { + qmi_txn_cancel(&txn); ath12k_warn(ab, "qmi failed to send wlan config request, err = %d\n", ret); goto out; @@ -2733,6 +2944,49 @@ out: return ret; } +static int ath12k_qmi_wlanfw_wlan_ini_send(struct ath12k_base *ab) +{ + struct qmi_wlanfw_wlan_ini_resp_msg_v01 resp = {}; + struct qmi_wlanfw_wlan_ini_req_msg_v01 req = {}; + struct qmi_txn txn; + int ret; + + req.enable_fwlog_valid = true; + req.enable_fwlog = 1; + + ret = qmi_txn_init(&ab->qmi.handle, &txn, + qmi_wlanfw_wlan_ini_resp_msg_v01_ei, &resp); + if (ret < 0) + goto out; + + ret = qmi_send_request(&ab->qmi.handle, NULL, &txn, + ATH12K_QMI_WLANFW_WLAN_INI_REQ_V01, + QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN, + qmi_wlanfw_wlan_ini_req_msg_v01_ei, &req); + if (ret < 0) { + qmi_txn_cancel(&txn); + ath12k_warn(ab, "failed to send QMI wlan ini request: %d\n", + ret); + goto out; + } + + ret = qmi_txn_wait(&txn, msecs_to_jiffies(ATH12K_QMI_WLANFW_TIMEOUT_MS)); + if (ret < 0) { + ath12k_warn(ab, "failed to receive QMI wlan ini request: %d\n", ret); + goto out; + } + + if (resp.resp.result != QMI_RESULT_SUCCESS_V01) { + ath12k_warn(ab, "QMI wlan ini response failure: %d %d\n", + resp.resp.result, resp.resp.error); + ret = -EINVAL; + goto out; + } + +out: + return ret; +} + void ath12k_qmi_firmware_stop(struct ath12k_base *ab) { int ret; @@ -2749,6 +3003,12 @@ int ath12k_qmi_firmware_start(struct ath12k_base *ab, { int ret; + ret = ath12k_qmi_wlanfw_wlan_ini_send(ab); + if (ret < 0) { + ath12k_warn(ab, "qmi failed to send wlan fw ini: %d\n", ret); + return ret; + } + ret = ath12k_qmi_wlanfw_wlan_cfg_send(ab); if (ret < 0) { ath12k_warn(ab, "qmi failed to send wlan cfg:%d\n", ret); @@ -2792,6 +3052,8 @@ static int ath12k_qmi_event_server_arrive(struct ath12k_qmi *qmi) struct ath12k_base *ab = qmi->ab; int ret; + ath12k_qmi_phy_cap_send(ab); + ret = ath12k_qmi_fw_ind_register_send(ab); if (ret < 0) { ath12k_warn(ab, "qmi failed to send FW indication QMI:%d\n", ret); diff --git a/drivers/net/wireless/ath/ath12k/qmi.h b/drivers/net/wireless/ath/ath12k/qmi.h index e25bbaa125..f34263d4be 100644 --- a/drivers/net/wireless/ath/ath12k/qmi.h +++ b/drivers/net/wireless/ath/ath12k/qmi.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_QMI_H @@ -15,7 +15,6 @@ #define ATH12K_QMI_MAX_BDF_FILE_NAME_SIZE 64 #define ATH12K_QMI_CALDB_ADDRESS 0x4BA00000 #define ATH12K_QMI_WLANFW_MAX_BUILD_ID_LEN_V01 128 -#define ATH12K_QMI_WLFW_NODE_ID_BASE 0x07 #define ATH12K_QMI_WLFW_SERVICE_ID_V01 0x45 #define ATH12K_QMI_WLFW_SERVICE_VERS_V01 0x01 #define ATH12K_QMI_WLFW_SERVICE_INS_ID_V01 0x02 @@ -97,6 +96,8 @@ struct ath12k_qmi_event_msg { struct target_mem_chunk { u32 size; u32 type; + u32 prev_size; + u32 prev_type; dma_addr_t paddr; union { void __iomem *ioaddr; @@ -141,6 +142,7 @@ struct ath12k_qmi { u32 target_mem_mode; bool target_mem_delayed; u8 cal_done; + u8 num_radios; struct target_info target; struct m3_mem_region m3_mem; unsigned int service_ins_id; @@ -251,6 +253,22 @@ struct qmi_wlanfw_host_cap_resp_msg_v01 { struct qmi_response_type_v01 resp; }; +#define QMI_WLANFW_PHY_CAP_REQ_MSG_V01_MAX_LEN 0 +#define QMI_WLANFW_PHY_CAP_REQ_V01 0x0057 +#define QMI_WLANFW_PHY_CAP_RESP_MSG_V01_MAX_LEN 18 +#define QMI_WLANFW_PHY_CAP_RESP_V01 0x0057 + +struct qmi_wlanfw_phy_cap_req_msg_v01 { +}; + +struct qmi_wlanfw_phy_cap_resp_msg_v01 { + struct qmi_response_type_v01 resp; + u8 num_phy_valid; + u8 num_phy; + u8 board_id_valid; + u32 board_id; +}; + #define QMI_WLANFW_IND_REGISTER_REQ_MSG_V01_MAX_LEN 54 #define QMI_WLANFW_IND_REGISTER_REQ_V01 0x0020 #define QMI_WLANFW_IND_REGISTER_RESP_MSG_V01_MAX_LEN 18 @@ -559,6 +577,21 @@ struct qmi_wlanfw_wlan_cfg_resp_msg_v01 { struct qmi_response_type_v01 resp; }; +#define ATH12K_QMI_WLANFW_WLAN_INI_REQ_V01 0x002F +#define ATH12K_QMI_WLANFW_WLAN_INI_RESP_V01 0x002F +#define QMI_WLANFW_WLAN_INI_REQ_MSG_V01_MAX_LEN 7 +#define QMI_WLANFW_WLAN_INI_RESP_MSG_V01_MAX_LEN 7 + +struct qmi_wlanfw_wlan_ini_req_msg_v01 { + /* Must be set to true if enable_fwlog is being passed */ + u8 enable_fwlog_valid; + u8 enable_fwlog; +}; + +struct qmi_wlanfw_wlan_ini_resp_msg_v01 { + struct qmi_response_type_v01 resp; +}; + int ath12k_qmi_firmware_start(struct ath12k_base *ab, u32 mode); void ath12k_qmi_firmware_stop(struct ath12k_base *ab); diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c index 29542c46b0..f308e9a6ed 100644 --- a/drivers/net/wireless/ath/ath12k/reg.c +++ b/drivers/net/wireless/ath/ath12k/reg.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/rtnetlink.h> #include "core.h" @@ -48,7 +48,8 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath12k_wmi_init_country_arg arg; - struct ath12k *ar = hw->priv; + struct ath12k_hw *ah = ath12k_hw_to_ah(hw); + struct ath12k *ar = ath12k_ah_to_ar(ah); int ret; ath12k_dbg(ar->ab, ATH12K_DBG_REG, @@ -95,7 +96,7 @@ int ath12k_reg_update_chan_list(struct ath12k *ar) struct ieee80211_supported_band **bands; struct ath12k_wmi_scan_chan_list_arg *arg; struct ieee80211_channel *channel; - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ath12k_wmi_channel_arg *ch; enum nl80211_band band; int num_channels = 0; @@ -199,7 +200,7 @@ static void ath12k_copy_regd(struct ieee80211_regdomain *regd_orig, int ath12k_regd_update(struct ath12k *ar, bool init) { - struct ieee80211_hw *hw = ar->hw; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); struct ieee80211_regdomain *regd, *regd_copy = NULL; int ret, regd_len, pdev_id; struct ath12k_base *ab; diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h index 55f20c446c..a0db6702a1 100644 --- a/drivers/net/wireless/ath/ath12k/rx_desc.h +++ b/drivers/net/wireless/ath/ath12k/rx_desc.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_RX_DESC_H #define ATH12K_RX_DESC_H @@ -147,6 +147,61 @@ struct rx_mpdu_start_qcn9274 { __le32 res1; } __packed; +#define QCN9274_MPDU_START_SELECT_MPDU_START_TAG BIT(0) +#define QCN9274_MPDU_START_SELECT_INFO0_REO_QUEUE_DESC_LO BIT(1) +#define QCN9274_MPDU_START_SELECT_INFO1_PN_31_0 BIT(2) +#define QCN9274_MPDU_START_SELECT_PN_95_32 BIT(3) +#define QCN9274_MPDU_START_SELECT_PN_127_96_INFO2 BIT(4) +#define QCN9274_MPDU_START_SELECT_PEER_MDATA_INFO3_PHY_PPDU_ID BIT(5) +#define QCN9274_MPDU_START_SELECT_AST_IDX_SW_PEER_ID_INFO4 BIT(6) +#define QCN9274_MPDU_START_SELECT_INFO5_INFO6 BIT(7) +#define QCN9274_MPDU_START_SELECT_FRAME_CTRL_DURATION_ADDR1_31_0 BIT(8) +#define QCN9274_MPDU_START_SELECT_ADDR2_47_0_ADDR1_47_32 BIT(9) +#define QCN9274_MPDU_START_SELECT_ADDR3_47_0_SEQ_CTRL BIT(10) +#define QCN9274_MPDU_START_SELECT_ADDR4_47_0_QOS_CTRL BIT(11) +#define QCN9274_MPDU_START_SELECT_HT_CTRL_INFO7 BIT(12) +#define QCN9274_MPDU_START_SELECT_ML_ADDR1_47_0_ML_ADDR2_15_0 BIT(13) +#define QCN9274_MPDU_START_SELECT_ML_ADDR2_47_16_INFO8 BIT(14) +#define QCN9274_MPDU_START_SELECT_RES_0_RES_1 BIT(15) + +#define QCN9274_MPDU_START_WMASK (QCN9274_MPDU_START_SELECT_INFO1_PN_31_0 | \ + QCN9274_MPDU_START_SELECT_PN_95_32 | \ + QCN9274_MPDU_START_SELECT_PN_127_96_INFO2 | \ + QCN9274_MPDU_START_SELECT_PEER_MDATA_INFO3_PHY_PPDU_ID | \ + QCN9274_MPDU_START_SELECT_AST_IDX_SW_PEER_ID_INFO4 | \ + QCN9274_MPDU_START_SELECT_INFO5_INFO6 | \ + QCN9274_MPDU_START_SELECT_FRAME_CTRL_DURATION_ADDR1_31_0 | \ + QCN9274_MPDU_START_SELECT_ADDR2_47_0_ADDR1_47_32 | \ + QCN9274_MPDU_START_SELECT_ADDR3_47_0_SEQ_CTRL | \ + QCN9274_MPDU_START_SELECT_ADDR4_47_0_QOS_CTRL) + +/* The below rx_mpdu_start_qcn9274_compact structure is tied with the mask + * value QCN9274_MPDU_START_WMASK. If the mask value changes the structure + * will also change. + */ + +struct rx_mpdu_start_qcn9274_compact { + __le32 info1; + __le32 pn[4]; + __le32 info2; + __le32 peer_meta_data; + __le16 info3; + __le16 phy_ppdu_id; + __le16 ast_index; + __le16 sw_peer_id; + __le32 info4; + __le32 info5; + __le32 info6; + __le16 frame_ctrl; + __le16 duration; + u8 addr1[ETH_ALEN]; + u8 addr2[ETH_ALEN]; + u8 addr3[ETH_ALEN]; + __le16 seq_ctrl; + u8 addr4[ETH_ALEN]; + __le16 qos_ctrl; +} __packed; + /* rx_mpdu_start * * reo_destination_indication @@ -608,6 +663,8 @@ enum rx_msdu_start_reception_type { RX_MSDU_START_RECEPTION_TYPE_UL_MU_OFDMA_MIMO, }; +#define RX_MSDU_END_64_TLV_SRC_LINK_ID GENMASK(24, 22) + #define RX_MSDU_END_INFO0_RXPCU_MPDU_FITLER GENMASK(1, 0) #define RX_MSDU_END_INFO0_SW_FRAME_GRP_ID GENMASK(8, 2) @@ -786,6 +843,52 @@ struct rx_msdu_end_qcn9274 { __le32 info14; } __packed; +#define QCN9274_MSDU_END_SELECT_MSDU_END_TAG BIT(0) +#define QCN9274_MSDU_END_SELECT_INFO0_PHY_PPDUID_IP_HDR_CSUM_INFO1 BIT(1) +#define QCN9274_MSDU_END_SELECT_INFO2_CUMULATIVE_CSUM_RULE_IND_0 BIT(2) +#define QCN9274_MSDU_END_SELECT_IPV6_OP_CRC_INFO3_TYPE13 BIT(3) +#define QCN9274_MSDU_END_SELECT_RULE_IND_1_TCP_SEQ_NUM BIT(4) +#define QCN9274_MSDU_END_SELECT_TCP_ACK_NUM_INFO4_WINDOW_SIZE BIT(5) +#define QCN9274_MSDU_END_SELECT_SA_SW_PER_ID_INFO5_SA_DA_ID BIT(6) +#define QCN9274_MSDU_END_SELECT_INFO6_FSE_METADATA BIT(7) +#define QCN9274_MSDU_END_SELECT_CCE_MDATA_TCP_UDP_CSUM_INFO7_IP_LEN BIT(8) +#define QCN9274_MSDU_END_SELECT_INFO8_INFO9 BIT(9) +#define QCN9274_MSDU_END_SELECT_INFO10_INFO11 BIT(10) +#define QCN9274_MSDU_END_SELECT_VLAN_CTAG_STAG_CI_PEER_MDATA BIT(11) +#define QCN9274_MSDU_END_SELECT_INFO12_AND_FLOW_ID_TOEPLITZ BIT(12) +#define QCN9274_MSDU_END_SELECT_PPDU_START_TS_63_32_PHY_MDATA BIT(13) +#define QCN9274_MSDU_END_SELECT_PPDU_START_TS_31_0_TOEPLITZ_HASH_2_4 BIT(14) +#define QCN9274_MSDU_END_SELECT_RES0_SA_47_0 BIT(15) +#define QCN9274_MSDU_END_SELECT_INFO13_INFO14 BIT(16) + +#define QCN9274_MSDU_END_WMASK (QCN9274_MSDU_END_SELECT_MSDU_END_TAG | \ + QCN9274_MSDU_END_SELECT_SA_SW_PER_ID_INFO5_SA_DA_ID | \ + QCN9274_MSDU_END_SELECT_INFO10_INFO11 | \ + QCN9274_MSDU_END_SELECT_INFO12_AND_FLOW_ID_TOEPLITZ | \ + QCN9274_MSDU_END_SELECT_PPDU_START_TS_63_32_PHY_MDATA | \ + QCN9274_MSDU_END_SELECT_INFO13_INFO14) + +/* The below rx_msdu_end_qcn9274_compact structure is tied with the mask value + * QCN9274_MSDU_END_WMASK. If the mask value changes the structure will also + * change. + */ + +struct rx_msdu_end_qcn9274_compact { + __le64 msdu_end_tag; + __le16 sa_sw_peer_id; + __le16 info5; + __le16 sa_idx; + __le16 da_idx_or_sw_peer_id; + __le32 info10; + __le32 info11; + __le32 info12; + __le32 flow_id_toeplitz; + __le32 ppdu_start_timestamp_63_32; + __le32 phy_meta_data; + __le32 info13; + __le32 info14; +} __packed; + /* These macro definitions are only used for WCN7850 */ #define RX_MSDU_END_WCN7850_INFO2_KEY_ID BIT(7, 0) @@ -1450,16 +1553,18 @@ struct rx_msdu_end_wcn7850 { * */ -/* TODO: Move to compact TLV approach - * By default these tlv's are not aligned to 128b boundary - * Need to remove unused qwords and make them compact/aligned - */ struct hal_rx_desc_qcn9274 { struct rx_msdu_end_qcn9274 msdu_end; struct rx_mpdu_start_qcn9274 mpdu_start; u8 msdu_payload[]; } __packed; +struct hal_rx_desc_qcn9274_compact { + struct rx_msdu_end_qcn9274_compact msdu_end; + struct rx_mpdu_start_qcn9274_compact mpdu_start; + u8 msdu_payload[]; +} __packed; + #define RX_BE_PADDING0_BYTES 8 #define RX_BE_PADDING1_BYTES 8 @@ -1484,6 +1589,7 @@ struct hal_rx_desc_wcn7850 { struct hal_rx_desc { union { struct hal_rx_desc_qcn9274 qcn9274; + struct hal_rx_desc_qcn9274_compact qcn9274_compact; struct hal_rx_desc_wcn7850 wcn7850; } u; } __packed; diff --git a/drivers/net/wireless/ath/ath12k/trace.h b/drivers/net/wireless/ath/ath12k/trace.h index f72096684b..240737e154 100644 --- a/drivers/net/wireless/ath/ath12k/trace.h +++ b/drivers/net/wireless/ath/ath12k/trace.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ) @@ -140,6 +140,33 @@ TRACE_EVENT(ath12k_htt_rxdesc, ) ); +TRACE_EVENT(ath12k_wmi_diag, + TP_PROTO(struct ath12k_base *ab, const void *data, size_t len), + + TP_ARGS(ab, data, len), + + TP_STRUCT__entry( + __string(device, dev_name(ab->dev)) + __string(driver, dev_driver_string(ab->dev)) + __field(u16, len) + __dynamic_array(u8, data, len) + ), + + TP_fast_assign( + __assign_str(device, dev_name(ab->dev)); + __assign_str(driver, dev_driver_string(ab->dev)); + __entry->len = len; + memcpy(__get_dynamic_array(data), data, len); + ), + + TP_printk( + "%s %s tlv diag len %d", + __get_str(driver), + __get_str(device), + __entry->len + ) +); + #endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/ /* we don't want to use include/trace/events */ diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c index 035d8f247e..34de3d16ef 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.c +++ b/drivers/net/wireless/ath/ath12k/wmi.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/skbuff.h> #include <linux/ctype.h> @@ -19,6 +19,7 @@ #include "mac.h" #include "hw.h" #include "peer.h" +#include "p2p.h" struct ath12k_wmi_svc_ready_parse { bool wmi_svc_bitmap_done; @@ -162,6 +163,14 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = { .min_len = sizeof(struct wmi_probe_resp_tx_status_event) }, [WMI_TAG_VDEV_DELETE_RESP_EVENT] = { .min_len = sizeof(struct wmi_vdev_delete_resp_event) }, + [WMI_TAG_TWT_ENABLE_COMPLETE_EVENT] = { + .min_len = sizeof(struct wmi_twt_enable_event) }, + [WMI_TAG_TWT_DISABLE_COMPLETE_EVENT] = { + .min_len = sizeof(struct wmi_twt_disable_event) }, + [WMI_TAG_P2P_NOA_INFO] = { + .min_len = sizeof(struct ath12k_wmi_p2p_noa_info) }, + [WMI_TAG_P2P_NOA_EVENT] = { + .min_len = sizeof(struct wmi_p2p_noa_event) }, }; static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len) @@ -179,18 +188,9 @@ 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; - - if (ab->num_radios == 2) { - config->num_peers = TARGET_NUM_PEERS(DBS); - config->num_tids = TARGET_NUM_TIDS(DBS); - } else if (ab->num_radios == 3) { - config->num_peers = TARGET_NUM_PEERS(DBS_SBS); - config->num_tids = TARGET_NUM_TIDS(DBS_SBS); - } else { - /* Control should not reach here */ - config->num_peers = TARGET_NUM_PEERS(SINGLE); - config->num_tids = TARGET_NUM_TIDS(SINGLE); - } + 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; @@ -228,6 +228,9 @@ void ath12k_wmi_init_qcn9274(struct ath12k_base *ab, config->peer_map_unmap_version = 0x32; config->twt_ap_pdev_count = ab->num_radios; config->twt_ap_sta_count = 1000; + + if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map)) + config->dp_peer_meta_data_ver = TARGET_RX_PEER_METADATA_VER_V1B; } void ath12k_wmi_init_wcn7850(struct ath12k_base *ab, @@ -359,8 +362,8 @@ static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb, } static const void ** -ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr, - size_t len, gfp_t gfp) +ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, + struct sk_buff *skb, gfp_t gfp) { const void **tb; int ret; @@ -369,7 +372,7 @@ ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab, const void *ptr, if (!tb) return ERR_PTR(-ENOMEM); - ret = ath12k_wmi_tlv_parse(ab, tb, ptr, len); + ret = ath12k_wmi_tlv_parse(ab, tb, skb->data, skb->len); if (ret) { kfree(tb); return ERR_PTR(ret); @@ -493,13 +496,13 @@ ath12k_pull_mac_phy_cap_svc_ready_ext(struct ath12k_wmi_pdev *wmi_handle, mac_caps = wmi_mac_phy_caps + phy_idx; - pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id); + pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); pdev_cap->supported_bands |= le32_to_cpu(mac_caps->supported_bands); pdev_cap->ampdu_density = le32_to_cpu(mac_caps->ampdu_density); fw_pdev = &ab->fw_pdev[ab->fw_pdev_count]; fw_pdev->supported_bands = le32_to_cpu(mac_caps->supported_bands); - fw_pdev->pdev_id = le32_to_cpu(mac_caps->pdev_id); + fw_pdev->pdev_id = ath12k_wmi_mac_phy_get_pdev_id(mac_caps); fw_pdev->phy_id = le32_to_cpu(mac_caps->phy_id); ab->fw_pdev_count++; @@ -727,6 +730,20 @@ static int ath12k_service_ready_event(struct ath12k_base *ab, struct sk_buff *sk return 0; } +static u32 ath12k_wmi_mgmt_get_freq(struct ath12k *ar, + struct ieee80211_tx_info *info) +{ + struct ath12k_base *ab = ar->ab; + u32 freq = 0; + + if (ab->hw_params->single_pdev_only && + ar->scan.is_roc && + (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)) + freq = ar->scan.roc_freq; + + return freq; +} + struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_ab, u32 len) { struct sk_buff *skb; @@ -752,6 +769,7 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, { 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 sk_buff *skb; u32 buf_len; @@ -770,7 +788,7 @@ int ath12k_wmi_mgmt_send(struct ath12k *ar, u32 vdev_id, u32 buf_id, sizeof(*cmd)); cmd->vdev_id = cpu_to_le32(vdev_id); cmd->desc_id = cpu_to_le32(buf_id); - cmd->chanfreq = 0; + cmd->chanfreq = cpu_to_le32(ath12k_wmi_mgmt_get_freq(ar, info)); cmd->paddr_lo = cpu_to_le32(lower_32_bits(ATH12K_SKB_CB(frame)->paddr)); cmd->paddr_hi = cpu_to_le32(upper_32_bits(ATH12K_SKB_CB(frame)->paddr)); cmd->frame_len = cpu_to_le32(frame->len); @@ -826,6 +844,9 @@ int ath12k_wmi_vdev_create(struct ath12k *ar, u8 *macaddr, cmd->vdev_stats_id = cpu_to_le32(args->if_stats_id); ether_addr_copy(cmd->vdev_macaddr.addr, macaddr); + if (args->if_stats_id != ATH12K_INVAL_VDEV_STATS_ID) + cmd->vdev_stats_id_valid = cpu_to_le32(BIT(0)); + ptr = skb->data + sizeof(*cmd); len = WMI_NUM_SUPPORTED_BAND_MAX * sizeof(*txrx_streams); @@ -1024,6 +1045,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, cmd->regdomain = cpu_to_le32(arg->regdomain); cmd->he_ops = cpu_to_le32(arg->he_ops); cmd->punct_bitmap = cpu_to_le32(arg->punct_bitmap); + cmd->mbssid_flags = cpu_to_le32(arg->mbssid_flags); if (!restart) { if (arg->ssid) { @@ -1051,7 +1073,7 @@ int ath12k_wmi_vdev_start(struct ath12k *ar, struct wmi_vdev_start_req_arg *arg, tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_STRUCT, 0); /* Note: This is a nested TLV containing: - * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv].. + * [wmi_tlv][ath12k_wmi_p2p_noa_descriptor][wmi_tlv].. */ ptr += sizeof(*tlv); @@ -1710,6 +1732,48 @@ int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar, return ret; } +int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, + const u8 *p2p_ie) +{ + struct ath12k_wmi_pdev *wmi = ar->wmi; + struct wmi_p2p_go_set_beacon_ie_cmd *cmd; + size_t p2p_ie_len, aligned_len; + struct wmi_tlv *tlv; + struct sk_buff *skb; + void *ptr; + int ret, len; + + p2p_ie_len = p2p_ie[1] + 2; + aligned_len = roundup(p2p_ie_len, sizeof(u32)); + + len = sizeof(*cmd) + TLV_HDR_SIZE + aligned_len; + + skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len); + if (!skb) + return -ENOMEM; + + ptr = skb->data; + cmd = ptr; + cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_P2P_GO_SET_BEACON_IE, + sizeof(*cmd)); + cmd->vdev_id = cpu_to_le32(vdev_id); + cmd->ie_buf_len = cpu_to_le32(p2p_ie_len); + + ptr += sizeof(*cmd); + tlv = ptr; + tlv->header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_ARRAY_BYTE, + aligned_len); + memcpy(tlv->value, p2p_ie, p2p_ie_len); + + ret = ath12k_wmi_cmd_send(wmi, skb, WMI_P2P_GO_SET_BEACON_IE); + if (ret) { + ath12k_warn(ar->ab, "failed to send WMI_P2P_GO_SET_BEACON_IE\n"); + dev_kfree_skb(skb); + } + + return ret; +} + int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn) @@ -2130,7 +2194,7 @@ void ath12k_wmi_start_scan_init(struct ath12k *ar, WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHAN | WMI_SCAN_EVENT_DEQUEUED; - arg->scan_flags |= WMI_SCAN_CHAN_STAT_EVENT; + arg->scan_f_chan_stat_evnt = 1; arg->num_bssid = 1; /* fill bssid_list[0] with 0xff, otherwise bssid and RA will be @@ -3265,6 +3329,9 @@ ath12k_wmi_copy_resource_config(struct ath12k_wmi_resource_config_params *wmi_cf 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); wmi_cfg->twt_ap_sta_count = cpu_to_le32(tg_cfg->twt_ap_sta_count); + wmi_cfg->flags2 = le32_encode_bits(tg_cfg->dp_peer_meta_data_ver, + WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION); + wmi_cfg->host_service_flags = cpu_to_le32(tg_cfg->is_reg_cc_ext_event_supported << WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT); } @@ -4214,7 +4281,7 @@ ath12k_wmi_tlv_mac_phy_caps_ext_parse(struct ath12k_base *ab, for (i = 0; i < ab->fw_pdev_count; i++) { struct ath12k_fw_pdev *fw_pdev = &ab->fw_pdev[i]; - if (fw_pdev->pdev_id == le32_to_cpu(caps->pdev_id) && + if (fw_pdev->pdev_id == ath12k_wmi_caps_ext_get_pdev_id(caps) && fw_pdev->phy_id == le32_to_cpu(caps->phy_id)) { bands = fw_pdev->supported_bands; break; @@ -4271,7 +4338,8 @@ static int ath12k_wmi_tlv_mac_phy_caps_ext(struct ath12k_base *ab, u16 tag, return 0; } else { for (i = 0; i < ab->num_radios; i++) { - if (ab->pdevs[i].pdev_id == le32_to_cpu(caps->pdev_id)) + if (ab->pdevs[i].pdev_id == + ath12k_wmi_caps_ext_get_pdev_id(caps)) break; } @@ -4374,7 +4442,7 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf const struct wmi_vdev_start_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4452,7 +4520,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab, ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n"); - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4738,7 +4806,7 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff * const struct wmi_peer_delete_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4770,7 +4838,7 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, const struct wmi_vdev_delete_resp_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4790,15 +4858,15 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab, return 0; } -static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, void *evt_buf, - u32 len, u32 *vdev_id, - u32 *tx_status) +static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab, + struct sk_buff *skb, + u32 *vdev_id, u32 *tx_status) { const void **tb; const struct wmi_bcn_tx_status_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4826,7 +4894,7 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_ const struct wmi_vdev_stopped_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -4948,7 +5016,7 @@ static int wmi_process_mgmt_tx_comp(struct ath12k *ar, u32 desc_id, if ((!(info->flags & IEEE80211_TX_CTL_NO_ACK)) && !status) info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(ar->hw, msdu); + ieee80211_tx_status_irqsafe(ath12k_ar_to_hw(ar), msdu); num_mgmt = atomic_dec_if_positive(&ar->num_pending_mgmt_tx); @@ -4970,7 +5038,7 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab, const struct wmi_mgmt_tx_compl_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5006,6 +5074,10 @@ static void ath12k_wmi_event_scan_started(struct ath12k *ar) break; case ATH12K_SCAN_STARTING: ar->scan.state = ATH12K_SCAN_RUNNING; + + if (ar->scan.is_roc) + ieee80211_ready_on_channel(ath12k_ar_to_hw(ar)); + complete(&ar->scan.started); break; } @@ -5076,6 +5148,8 @@ static void ath12k_wmi_event_scan_bss_chan(struct ath12k *ar) static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq) { + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); + lockdep_assert_held(&ar->data_lock); switch (ar->scan.state) { @@ -5087,7 +5161,11 @@ static void ath12k_wmi_event_scan_foreign_chan(struct ath12k *ar, u32 freq) break; case ATH12K_SCAN_RUNNING: case ATH12K_SCAN_ABORTING: - ar->scan_channel = ieee80211_get_channel(ar->hw->wiphy, freq); + ar->scan_channel = ieee80211_get_channel(hw->wiphy, freq); + + if (ar->scan.is_roc && ar->scan.roc_freq == freq) + complete(&ar->scan.on_channel); + break; } } @@ -5141,7 +5219,7 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_scan_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5174,7 +5252,7 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf const struct wmi_peer_sta_kickout_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5201,7 +5279,7 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_roam_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5226,13 +5304,14 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb, static int freq_to_idx(struct ath12k *ar, int freq) { struct ieee80211_supported_band *sband; + struct ieee80211_hw *hw = ath12k_ar_to_hw(ar); int band, ch, idx = 0; for (band = NL80211_BAND_2GHZ; band < NUM_NL80211_BANDS; band++) { if (!ar->mac.sbands[band].channels) continue; - sband = ar->hw->wiphy->bands[band]; + sband = hw->wiphy->bands[band]; if (!sband) continue; @@ -5245,14 +5324,14 @@ exit: return idx; } -static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, u8 *evt_buf, - u32 len, struct wmi_chan_info_event *ch_info_ev) +static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, + struct wmi_chan_info_event *ch_info_ev) { const void **tb; const struct wmi_chan_info_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5291,7 +5370,7 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb, const struct wmi_pdev_bss_chan_info_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5331,7 +5410,7 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk const struct wmi_vdev_install_key_compl_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5362,7 +5441,7 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff const struct wmi_peer_assoc_conf_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5384,13 +5463,13 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff } static int -ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, u8 *evt_buf, - u32 len, const struct wmi_pdev_temperature_event *ev) +ath12k_pull_pdev_temp_ev(struct ath12k_base *ab, struct sk_buff *skb, + const struct wmi_pdev_temperature_event *ev) { const void **tb; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, evt_buf, len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -5725,8 +5804,7 @@ static void ath12k_bcn_tx_status_event(struct ath12k_base *ab, struct sk_buff *s { u32 vdev_id, tx_status; - if (ath12k_pull_bcn_tx_status_ev(ab, skb->data, skb->len, - &vdev_id, &tx_status) != 0) { + if (ath12k_pull_bcn_tx_status_ev(ab, skb, &vdev_id, &tx_status) != 0) { ath12k_warn(ab, "failed to extract bcn tx status"); return; } @@ -5864,7 +5942,7 @@ static void ath12k_mgmt_rx_event(struct ath12k_base *ab, struct sk_buff *skb) status->freq, status->band, status->signal, status->rate_idx); - ieee80211_rx_ni(ar->hw, skb); + ieee80211_rx_ni(ath12k_ar_to_hw(ar), skb); exit: rcu_read_unlock(); @@ -6037,7 +6115,7 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff goto exit; } - sta = ieee80211_find_sta_by_ifaddr(ar->hw, + 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", @@ -6110,7 +6188,7 @@ static void ath12k_chan_info_event(struct ath12k_base *ab, struct sk_buff *skb) /* HW channel counters frequency value in hertz */ u32 cc_freq_hz = ab->cc_freq_hz; - if (ath12k_pull_chan_info_ev(ab, skb->data, skb->len, &ch_info_ev) != 0) { + if (ath12k_pull_chan_info_ev(ab, skb, &ch_info_ev) != 0) { ath12k_warn(ab, "failed to extract chan info event"); return; } @@ -6395,7 +6473,7 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab, const struct wmi_pdev_ctl_failsafe_chk_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6446,7 +6524,7 @@ ath12k_wmi_process_csa_switch_count_event(struct ath12k_base *ab, } if (arvif->is_up && arvif->vif->bss_conf.csa_active) - ieee80211_csa_finish(arvif->vif); + ieee80211_csa_finish(arvif->vif, 0); } rcu_read_unlock(); } @@ -6460,7 +6538,7 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab, const u32 *vdev_ids; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6494,7 +6572,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff struct ath12k *ar; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6531,7 +6609,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff if (ar->dfs_block_radar_events) ath12k_info(ab, "DFS Radar detected, but ignored as requested\n"); else - ieee80211_radar_detected(ar->hw); + ieee80211_radar_detected(ath12k_ar_to_hw(ar)); exit: rcu_read_unlock(); @@ -6546,7 +6624,7 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab, struct ath12k *ar; struct wmi_pdev_temperature_event ev = {0}; - if (ath12k_pull_pdev_temp_ev(ab, skb->data, skb->len, &ev) != 0) { + if (ath12k_pull_pdev_temp_ev(ab, skb, &ev) != 0) { ath12k_warn(ab, "failed to extract pdev temperature event"); return; } @@ -6573,7 +6651,7 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab, const struct wmi_fils_discovery_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, @@ -6603,7 +6681,7 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, const struct wmi_probe_resp_tx_status_event *ev; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, @@ -6628,6 +6706,56 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab, kfree(tb); } +static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_p2p_noa_event *ev; + const struct ath12k_wmi_p2p_noa_info *noa; + struct ath12k *ar; + int ret, vdev_id; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse P2P NoA TLV: %d\n", ret); + return ret; + } + + ev = tb[WMI_TAG_P2P_NOA_EVENT]; + noa = tb[WMI_TAG_P2P_NOA_INFO]; + + if (!ev || !noa) { + ret = -EPROTO; + goto out; + } + + vdev_id = __le32_to_cpu(ev->vdev_id); + + ath12k_dbg(ab, ATH12K_DBG_WMI, + "wmi tlv p2p noa vdev_id %i descriptors %u\n", + vdev_id, le32_get_bits(noa->noa_attr, WMI_P2P_NOA_INFO_DESC_NUM)); + + rcu_read_lock(); + ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id); + if (!ar) { + ath12k_warn(ab, "invalid vdev id %d in P2P NoA event\n", + vdev_id); + ret = -EINVAL; + goto unlock; + } + + ath12k_p2p_noa_update_by_vdev_id(ar, vdev_id, noa); + + ret = 0; + +unlock: + rcu_read_unlock(); +out: + kfree(tb); + return ret; +} + static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, struct sk_buff *skb) { @@ -6635,7 +6763,7 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, const void **tb; int ret; - tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC); + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); if (IS_ERR(tb)) { ret = PTR_ERR(tb); ath12k_warn(ab, "failed to parse tlv: %d\n", ret); @@ -6662,6 +6790,70 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab, kfree(tb); } +static void +ath12k_wmi_diag_event(struct ath12k_base *ab, struct sk_buff *skb) +{ + trace_ath12k_wmi_diag(ab, skb->data, skb->len); +} + +static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_twt_enable_event *ev; + int ret; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse wmi twt enable status event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_TWT_ENABLE_COMPLETE_EVENT]; + if (!ev) { + ath12k_warn(ab, "failed to fetch twt enable wmi event\n"); + goto exit; + } + + ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt enable event pdev id %u status %u\n", + le32_to_cpu(ev->pdev_id), + le32_to_cpu(ev->status)); + +exit: + kfree(tb); +} + +static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab, + struct sk_buff *skb) +{ + const void **tb; + const struct wmi_twt_disable_event *ev; + int ret; + + tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC); + if (IS_ERR(tb)) { + ret = PTR_ERR(tb); + ath12k_warn(ab, "failed to parse wmi twt disable status event tlv: %d\n", + ret); + return; + } + + ev = tb[WMI_TAG_TWT_DISABLE_COMPLETE_EVENT]; + if (!ev) { + ath12k_warn(ab, "failed to fetch twt disable wmi event\n"); + goto exit; + } + + ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt disable event pdev id %d status %u\n", + le32_to_cpu(ev->pdev_id), + le32_to_cpu(ev->status)); + +exit: + kfree(tb); +} + static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) { struct wmi_cmd_hdr *cmd_hdr; @@ -6757,11 +6949,18 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_RFKILL_STATE_CHANGE_EVENTID: ath12k_rfkill_state_change_event(ab, skb); break; + case WMI_TWT_ENABLE_EVENTID: + ath12k_wmi_twt_enable_event(ab, skb); + break; + case WMI_TWT_DISABLE_EVENTID: + ath12k_wmi_twt_disable_event(ab, skb); + break; + case WMI_P2P_NOA_EVENTID: + ath12k_wmi_p2p_noa_event(ab, skb); + break; /* add Unsupported events here */ case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID: - case WMI_TWT_ENABLE_EVENTID: - case WMI_TWT_DISABLE_EVENTID: case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID: ath12k_dbg(ab, ATH12K_DBG_WMI, "ignoring unsupported event 0x%x\n", id); @@ -6772,6 +6971,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb) case WMI_VDEV_DELETE_RESP_EVENTID: ath12k_vdev_delete_resp_event(ab, skb); break; + case WMI_DIAG_EVENTID: + ath12k_wmi_diag_event(ab, skb); + break; /* TODO: Add remaining events */ default: ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id); diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h index 06e5b9b404..103462feb9 100644 --- a/drivers/net/wireless/ath/ath12k/wmi.h +++ b/drivers/net/wireless/ath/ath12k/wmi.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-2023 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef ATH12K_WMI_H @@ -168,10 +168,6 @@ struct wmi_tlv { #define WLAN_SCAN_MAX_HINT_BSSID 10 #define MAX_RNR_BSS 5 -#define WLAN_SCAN_PARAMS_MAX_SSID 16 -#define WLAN_SCAN_PARAMS_MAX_BSSID 4 -#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 - #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1 #define WMI_BA_MODE_BUFFER_SIZE_256 3 @@ -2163,6 +2159,10 @@ enum wmi_tlv_service { WMI_TLV_SERVICE_11BE = 289, + WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS = 361, + + WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT = 365, + WMI_MAX_EXT2_SERVICE, }; @@ -2350,6 +2350,7 @@ struct ath12k_wmi_resource_config_arg { u32 twt_ap_pdev_count; u32 twt_ap_sta_count; bool is_reg_cc_ext_event_supported; + u8 dp_peer_meta_data_ver; }; struct ath12k_wmi_init_cmd_arg { @@ -2402,6 +2403,7 @@ struct wmi_init_cmd { } __packed; #define WMI_RSRC_CFG_HOST_SVC_FLAG_REG_CC_EXT_SUPPORT_BIT 4 +#define WMI_RSRC_CFG_FLAGS2_RX_PEER_METADATA_VERSION GENMASK(5, 4) struct ath12k_wmi_resource_config_params { __le32 tlv_header; @@ -2542,9 +2544,17 @@ struct ath12k_wmi_hw_mode_cap_params { #define WMI_MAX_HECAP_PHY_SIZE (3) +/* 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. + * + * hw_link_id is present in higher 16 bits of pdev_and_hw_link_ids. + */ +#define WMI_CAPS_PARAMS_PDEV_ID GENMASK(15, 0) +#define WMI_CAPS_PARAMS_HW_LINK_ID GENMASK(31, 16) + struct ath12k_wmi_mac_phy_caps_params { __le32 hw_mode_id; - __le32 pdev_id; + __le32 pdev_and_hw_link_ids; __le32 phy_id; __le32 supported_flags; __le32 supported_bands; @@ -2636,13 +2646,7 @@ struct wmi_service_ready_ext2_event { struct ath12k_wmi_caps_ext_params { __le32 hw_mode_id; - union { - struct { - __le16 pdev_id; - __le16 hw_link_id; - } __packed ath12k_wmi_pdev_to_link_map; - __le32 pdev_id; - }; + __le32 pdev_and_hw_link_ids; __le32 phy_id; __le32 wireless_modes_ext; __le32 eht_cap_mac_info_2ghz[WMI_MAX_EHTCAP_MAC_SIZE]; @@ -2716,6 +2720,9 @@ struct wmi_vdev_create_cmd { struct ath12k_wmi_mac_addr_params vdev_macaddr; __le32 num_cfg_txrx_streams; __le32 pdev_id; + __le32 mbssid_flags; + __le32 mbssid_tx_vdev_id; + __le32 vdev_stats_id_valid; __le32 vdev_stats_id; } __packed; @@ -2764,6 +2771,10 @@ struct ath12k_wmi_ssid_params { #define ATH12K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ) +enum wmi_vdev_mbssid_flags { + WMI_VDEV_MBSSID_FLAGS_NON_MBSSID_AP = BIT(0), +}; + struct wmi_vdev_start_request_cmd { __le32 tlv_header; __le32 vdev_id; @@ -2782,7 +2793,7 @@ struct wmi_vdev_start_request_cmd { __le32 cac_duration_ms; __le32 regdomain; __le32 min_data_rate; - __le32 mbssid_flags; + __le32 mbssid_flags; /* uses enum wmi_vdev_mbssid_flags */ __le32 mbssid_tx_vdev_id; __le32 eht_ops; __le32 punct_bitmap; @@ -3146,7 +3157,7 @@ struct ath12k_wmi_element_info_arg { #define WLAN_SCAN_PARAMS_MAX_SSID 16 #define WLAN_SCAN_PARAMS_MAX_BSSID 4 -#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 +#define WLAN_SCAN_PARAMS_MAX_IE_LEN 512 /* Values lower than this may be refused by some firmware revisions with a scan * completion with a timedout reason. @@ -3270,24 +3281,19 @@ struct ath12k_wmi_scan_req_arg { u32 vdev_id; u32 pdev_id; enum wmi_scan_priority scan_priority; - union { - struct { - u32 scan_ev_started:1, - scan_ev_completed:1, - scan_ev_bss_chan:1, - scan_ev_foreign_chan:1, - scan_ev_dequeued:1, - scan_ev_preempted:1, - scan_ev_start_failed:1, - scan_ev_restarted:1, - scan_ev_foreign_chn_exit:1, - scan_ev_invalid:1, - scan_ev_gpio_timeout:1, - scan_ev_suspended:1, - scan_ev_resumed:1; - }; - u32 scan_events; - }; + u32 scan_ev_started:1, + scan_ev_completed:1, + scan_ev_bss_chan:1, + scan_ev_foreign_chan:1, + scan_ev_dequeued:1, + scan_ev_preempted:1, + scan_ev_start_failed:1, + scan_ev_restarted:1, + scan_ev_foreign_chn_exit:1, + scan_ev_invalid:1, + scan_ev_gpio_timeout:1, + scan_ev_suspended:1, + scan_ev_resumed:1; u32 dwell_time_active; u32 dwell_time_active_2g; u32 dwell_time_passive; @@ -3300,36 +3306,31 @@ struct ath12k_wmi_scan_req_arg { u32 idle_time; u32 max_scan_time; u32 probe_delay; - union { - struct { - u32 scan_f_passive:1, - scan_f_bcast_probe:1, - scan_f_cck_rates:1, - scan_f_ofdm_rates:1, - scan_f_chan_stat_evnt:1, - scan_f_filter_prb_req:1, - scan_f_bypass_dfs_chn:1, - scan_f_continue_on_err:1, - scan_f_offchan_mgmt_tx:1, - scan_f_offchan_data_tx:1, - scan_f_promisc_mode:1, - scan_f_capture_phy_err:1, - scan_f_strict_passive_pch:1, - scan_f_half_rate:1, - scan_f_quarter_rate:1, - scan_f_force_active_dfs_chn:1, - scan_f_add_tpc_ie_in_probe:1, - scan_f_add_ds_ie_in_probe:1, - scan_f_add_spoofed_mac_in_probe:1, - scan_f_add_rand_seq_in_probe:1, - scan_f_en_ie_whitelist_in_probe:1, - scan_f_forced:1, - scan_f_2ghz:1, - scan_f_5ghz:1, - scan_f_80mhz:1; - }; - u32 scan_flags; - }; + u32 scan_f_passive:1, + scan_f_bcast_probe:1, + scan_f_cck_rates:1, + scan_f_ofdm_rates:1, + scan_f_chan_stat_evnt:1, + scan_f_filter_prb_req:1, + scan_f_bypass_dfs_chn:1, + scan_f_continue_on_err:1, + scan_f_offchan_mgmt_tx:1, + scan_f_offchan_data_tx:1, + scan_f_promisc_mode:1, + scan_f_capture_phy_err:1, + scan_f_strict_passive_pch:1, + scan_f_half_rate:1, + scan_f_quarter_rate:1, + scan_f_force_active_dfs_chn:1, + scan_f_add_tpc_ie_in_probe:1, + scan_f_add_ds_ie_in_probe:1, + scan_f_add_spoofed_mac_in_probe:1, + scan_f_add_rand_seq_in_probe:1, + scan_f_en_ie_whitelist_in_probe:1, + scan_f_forced:1, + scan_f_2ghz:1, + scan_f_5ghz:1, + scan_f_80mhz:1; enum scan_dwelltime_adaptive_mode adaptive_dwell_time_mode; u32 burst_duration; u32 num_chan; @@ -3489,6 +3490,37 @@ struct wmi_get_pdev_temperature_cmd { __le32 pdev_id; } __packed; +#define WMI_P2P_MAX_NOA_DESCRIPTORS 4 + +struct wmi_p2p_noa_event { + __le32 vdev_id; +} __packed; + +struct ath12k_wmi_p2p_noa_descriptor { + __le32 type_count; /* 255: continuous schedule, 0: reserved */ + __le32 duration; /* Absent period duration in micro seconds */ + __le32 interval; /* Absent period interval in micro seconds */ + __le32 start_time; /* 32 bit tsf time when in starts */ +} __packed; + +#define WMI_P2P_NOA_INFO_CHANGED_FLAG BIT(0) +#define WMI_P2P_NOA_INFO_INDEX GENMASK(15, 8) +#define WMI_P2P_NOA_INFO_OPP_PS BIT(16) +#define WMI_P2P_NOA_INFO_CTWIN_TU GENMASK(23, 17) +#define WMI_P2P_NOA_INFO_DESC_NUM GENMASK(31, 24) + +struct ath12k_wmi_p2p_noa_info { + /* Bit 0 - Flag to indicate an update in NOA schedule + * Bits 7-1 - Reserved + * Bits 15-8 - Index (identifies the instance of NOA sub element) + * Bit 16 - Opp PS state of the AP + * Bits 23-17 - Ctwindow in TUs + * Bits 31-24 - Number of NOA descriptors + */ + __le32 noa_attr; + struct ath12k_wmi_p2p_noa_descriptor descriptors[WMI_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + #define WMI_BEACON_TX_BUFFER_SIZE 512 struct wmi_bcn_tmpl_cmd { @@ -3503,6 +3535,12 @@ struct wmi_bcn_tmpl_cmd { __le32 esp_ie_offset; } __packed; +struct wmi_p2p_go_set_beacon_ie_cmd { + __le32 tlv_header; + __le32 vdev_id; + __le32 ie_buf_len; +} __packed; + struct wmi_vdev_install_key_cmd { __le32 tlv_header; __le32 vdev_id; @@ -4797,6 +4835,16 @@ struct wmi_rfkill_state_change_event { __le32 radio_state; } __packed; +struct wmi_twt_enable_event { + __le32 pdev_id; + __le32 status; +} __packed; + +struct wmi_twt_disable_event { + __le32 pdev_id; + __le32 status; +} __packed; + 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, @@ -4806,6 +4854,8 @@ int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb, 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, struct sk_buff *frame); +int ath12k_wmi_p2p_go_bcn_ie(struct ath12k *ar, u32 vdev_id, + const u8 *p2p_ie); int ath12k_wmi_bcn_tmpl(struct ath12k *ar, u32 vdev_id, struct ieee80211_mutable_offsets *offs, struct sk_buff *bcn); @@ -4917,4 +4967,30 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id, int ath12k_wmi_set_hw_mode(struct ath12k_base *ab, enum wmi_host_hw_mode_config_type mode); +static inline u32 +ath12k_wmi_caps_ext_get_pdev_id(const struct ath12k_wmi_caps_ext_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, WMI_CAPS_PARAMS_PDEV_ID); +} + +static inline u32 +ath12k_wmi_caps_ext_get_hw_link_id(const struct ath12k_wmi_caps_ext_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, WMI_CAPS_PARAMS_HW_LINK_ID); +} + +static inline u32 +ath12k_wmi_mac_phy_get_pdev_id(const struct ath12k_wmi_mac_phy_caps_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, + WMI_CAPS_PARAMS_PDEV_ID); +} + +static inline u32 +ath12k_wmi_mac_phy_get_hw_link_id(const struct ath12k_wmi_mac_phy_caps_params *param) +{ + return le32_get_bits(param->pdev_and_hw_link_ids, + WMI_CAPS_PARAMS_HW_LINK_ID); +} + #endif |