git: 60bac4d6438b - main - ath12k: update Atheros/QCA's ath12k driver
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 19 Apr 2026 15:39:19 UTC
The branch main has been updated by bz:
URL: https://cgit.FreeBSD.org/src/commit/?id=60bac4d6438b6bcb3d7b439684211d05396d90ce
commit 60bac4d6438b6bcb3d7b439684211d05396d90ce
Merge: 20cf11812ac7 80f1906e3b91
Author: Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2026-04-19 15:38:33 +0000
Commit: Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2026-04-19 15:38:33 +0000
ath12k: update Atheros/QCA's ath12k driver
This version is based on
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
028ef9c96e96197026887c0f092424679298aae8 ( tag: v7.0 ).
Sponsored by: The FreeBSD Foundation
MFC after: 3 days
sys/contrib/dev/athk/ath12k/Makefile | 8 +-
sys/contrib/dev/athk/ath12k/ahb.c | 165 +-
sys/contrib/dev/athk/ath12k/ahb.h | 31 +-
sys/contrib/dev/athk/ath12k/ce.c | 328 +-
sys/contrib/dev/athk/ath12k/ce.h | 7 +-
sys/contrib/dev/athk/ath12k/cmn_defs.h | 20 +
sys/contrib/dev/athk/ath12k/core.c | 77 +-
sys/contrib/dev/athk/ath12k/core.h | 209 +-
sys/contrib/dev/athk/ath12k/dbring.c | 6 +-
sys/contrib/dev/athk/ath12k/debug.c | 8 +-
sys/contrib/dev/athk/ath12k/debugfs.c | 8 +-
sys/contrib/dev/athk/ath12k/debugfs_htt_stats.c | 197 +-
sys/contrib/dev/athk/ath12k/debugfs_htt_stats.h | 85 +-
sys/contrib/dev/athk/ath12k/debugfs_sta.c | 62 +-
sys/contrib/dev/athk/ath12k/dp.c | 586 +---
sys/contrib/dev/athk/ath12k/dp.h | 1746 ++--------
sys/contrib/dev/athk/ath12k/dp_cmn.h | 106 +
sys/contrib/dev/athk/ath12k/dp_htt.c | 1353 +++++++
sys/contrib/dev/athk/ath12k/dp_htt.h | 1546 ++++++++
sys/contrib/dev/athk/ath12k/dp_mon.c | 3685 +-------------------
sys/contrib/dev/athk/ath12k/dp_mon.h | 58 +-
sys/contrib/dev/athk/ath12k/dp_peer.c | 690 ++++
sys/contrib/dev/athk/ath12k/dp_peer.h | 182 +
sys/contrib/dev/athk/ath12k/dp_rx.c | 3544 ++-----------------
sys/contrib/dev/athk/ath12k/dp_rx.h | 191 +-
sys/contrib/dev/athk/ath12k/dp_tx.c | 1634 +--------
sys/contrib/dev/athk/ath12k/dp_tx.h | 39 +-
sys/contrib/dev/athk/ath12k/fw.c | 10 +-
sys/contrib/dev/athk/ath12k/fw.h | 3 +-
sys/contrib/dev/athk/ath12k/hal.c | 2147 +-----------
sys/contrib/dev/athk/ath12k/hal.h | 1523 +++++---
sys/contrib/dev/athk/ath12k/htc.c | 3 +-
sys/contrib/dev/athk/ath12k/hw.c | 1680 ---------
sys/contrib/dev/athk/ath12k/hw.h | 96 +-
sys/contrib/dev/athk/ath12k/mac.c | 1294 ++++---
sys/contrib/dev/athk/ath12k/mac.h | 142 +-
sys/contrib/dev/athk/ath12k/mhi.c | 134 +-
sys/contrib/dev/athk/ath12k/mhi.h | 5 +-
sys/contrib/dev/athk/ath12k/pci.c | 261 +-
sys/contrib/dev/athk/ath12k/pci.h | 49 +-
sys/contrib/dev/athk/ath12k/peer.c | 453 +--
sys/contrib/dev/athk/ath12k/peer.h | 112 +-
sys/contrib/dev/athk/ath12k/qmi.c | 192 +-
sys/contrib/dev/athk/ath12k/qmi.h | 16 +
sys/contrib/dev/athk/ath12k/reg.c | 2 +-
sys/contrib/dev/athk/ath12k/testmode.c | 3 +-
sys/contrib/dev/athk/ath12k/wifi7/Makefile | 20 +
sys/contrib/dev/athk/ath12k/wifi7/ahb.c | 75 +
sys/contrib/dev/athk/ath12k/wifi7/ahb.h | 20 +
sys/contrib/dev/athk/ath12k/wifi7/ce.c | 973 ++++++
sys/contrib/dev/athk/ath12k/wifi7/ce.h | 22 +
sys/contrib/dev/athk/ath12k/wifi7/core.c | 68 +
sys/contrib/dev/athk/ath12k/wifi7/core.h | 11 +
sys/contrib/dev/athk/ath12k/wifi7/dp.c | 181 +
sys/contrib/dev/athk/ath12k/wifi7/dp.h | 20 +
sys/contrib/dev/athk/ath12k/wifi7/dp_mon.c | 3385 ++++++++++++++++++
sys/contrib/dev/athk/ath12k/wifi7/dp_mon.h | 23 +
sys/contrib/dev/athk/ath12k/wifi7/dp_rx.c | 2246 ++++++++++++
sys/contrib/dev/athk/ath12k/wifi7/dp_rx.h | 60 +
sys/contrib/dev/athk/ath12k/wifi7/dp_tx.c | 978 ++++++
sys/contrib/dev/athk/ath12k/wifi7/dp_tx.h | 16 +
sys/contrib/dev/athk/ath12k/wifi7/hal.c | 713 ++++
sys/contrib/dev/athk/ath12k/wifi7/hal.h | 561 +++
sys/contrib/dev/athk/ath12k/{ => wifi7}/hal_desc.h | 331 +-
sys/contrib/dev/athk/ath12k/wifi7/hal_qcc2072.c | 503 +++
sys/contrib/dev/athk/ath12k/wifi7/hal_qcc2072.h | 13 +
sys/contrib/dev/athk/ath12k/wifi7/hal_qcn9274.c | 1038 ++++++
sys/contrib/dev/athk/ath12k/wifi7/hal_qcn9274.h | 45 +
sys/contrib/dev/athk/ath12k/{ => wifi7}/hal_rx.c | 284 +-
sys/contrib/dev/athk/ath12k/{ => wifi7}/hal_rx.h | 424 +--
.../athk/ath12k/{rx_desc.h => wifi7/hal_rx_desc.h} | 72 +-
sys/contrib/dev/athk/ath12k/{ => wifi7}/hal_tx.c | 23 +-
sys/contrib/dev/athk/ath12k/{ => wifi7}/hal_tx.h | 30 +-
sys/contrib/dev/athk/ath12k/wifi7/hal_wcn7850.c | 809 +++++
sys/contrib/dev/athk/ath12k/wifi7/hal_wcn7850.h | 40 +
sys/contrib/dev/athk/ath12k/wifi7/hw.c | 1049 ++++++
sys/contrib/dev/athk/ath12k/wifi7/hw.h | 13 +
sys/contrib/dev/athk/ath12k/wifi7/mhi.c | 134 +
sys/contrib/dev/athk/ath12k/wifi7/mhi.h | 11 +
sys/contrib/dev/athk/ath12k/wifi7/pci.c | 215 ++
sys/contrib/dev/athk/ath12k/wifi7/pci.h | 12 +
sys/contrib/dev/athk/ath12k/wifi7/wmi.c | 110 +
sys/contrib/dev/athk/ath12k/wifi7/wmi.h | 15 +
sys/contrib/dev/athk/ath12k/wmi.c | 383 +-
sys/contrib/dev/athk/ath12k/wmi.h | 61 +-
sys/contrib/dev/athk/ath12k/wow.c | 27 +-
86 files changed, 22058 insertions(+), 17652 deletions(-)
diff --cc sys/contrib/dev/athk/ath12k/Makefile
index d95ee525a6cd,000000000000..3ba1236956cc
mode 100644,000000..100644
--- a/sys/contrib/dev/athk/ath12k/Makefile
+++ b/sys/contrib/dev/athk/ath12k/Makefile
@@@ -1,35 -1,0 +1,37 @@@
+# SPDX-License-Identifier: BSD-3-Clause-Clear
+obj-$(CONFIG_ATH12K) += ath12k.o
+ath12k-y += core.o \
+ hal.o \
- hal_tx.o \
- hal_rx.o \
+ wmi.o \
+ mac.o \
+ reg.o \
+ htc.o \
+ qmi.o \
+ dp.o \
+ dp_tx.o \
+ dp_rx.o \
++ dp_htt.o \
++ dp_peer.o \
+ debug.o \
+ ce.o \
+ peer.o \
+ dbring.o \
- hw.o \
+ mhi.o \
+ pci.o \
+ dp_mon.o \
+ fw.o \
+ p2p.o
+
+ath12k-$(CONFIG_ATH12K_AHB) += ahb.o
++
++obj-$(CONFIG_ATH12K) += wifi7/
++
+ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
+ath12k-$(CONFIG_ACPI) += acpi.o
+ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
+ath12k-$(CONFIG_PM) += wow.o
+ath12k-$(CONFIG_ATH12K_COREDUMP) += coredump.o
+ath12k-$(CONFIG_NL80211_TESTMODE) += testmode.o
+
+# for tracing framework to find trace.h
+CFLAGS_trace.o := -I$(src)
diff --cc sys/contrib/dev/athk/ath12k/cmn_defs.h
index 000000000000,20208ffea1c9..20208ffea1c9
mode 000000,100644..100644
--- a/sys/contrib/dev/athk/ath12k/cmn_defs.h
+++ b/sys/contrib/dev/athk/ath12k/cmn_defs.h
diff --cc sys/contrib/dev/athk/ath12k/core.c
index 9836d0aeba79,000000000000..1763b3b837e5
mode 100644,000000..100644
--- a/sys/contrib/dev/athk/ath12k/core.c
+++ b/sys/contrib/dev/athk/ath12k/core.c
@@@ -1,2344 -1,0 +1,2327 @@@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/*
+ * Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#if defined(__FreeBSD__)
+#define LINUXKPI_PARAM_PREFIX ath12k_core_
+#endif
+
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/remoteproc.h>
+#include <linux/firmware.h>
+#include <linux/of.h>
+#if defined(__FreeBSD__)
+#include <linux/delay.h>
+#endif
+#include <linux/of_graph.h>
+#include "ahb.h"
+#include "core.h"
+#include "dp_tx.h"
+#include "dp_rx.h"
+#include "debug.h"
+#include "debugfs.h"
+#include "fw.h"
+#include "hif.h"
+#include "pci.h"
+#include "wow.h"
++#include "dp_cmn.h"
++#include "peer.h"
+
- static int ahb_err, pci_err;
+unsigned int ath12k_debug_mask;
+module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
+MODULE_PARM_DESC(debug_mask, "Debugging mask");
++EXPORT_SYMBOL(ath12k_debug_mask);
+
+bool ath12k_ftm_mode;
+module_param_named(ftm_mode, ath12k_ftm_mode, bool, 0444);
+MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
++EXPORT_SYMBOL(ath12k_ftm_mode);
+
+/* protected with ath12k_hw_group_mutex */
+static struct list_head ath12k_hw_group_list = LIST_HEAD_INIT(ath12k_hw_group_list);
+
+static DEFINE_MUTEX(ath12k_hw_group_mutex);
+
+static const struct
+ath12k_mem_profile_based_param ath12k_mem_profile_based_param[] = {
+[ATH12K_QMI_MEMORY_MODE_DEFAULT] = {
+ .num_vdevs = 17,
+ .max_client_single = 512,
+ .max_client_dbs = 128,
+ .max_client_dbs_sbs = 128,
+ .dp_params = {
+ .tx_comp_ring_size = 32768,
+ .rxdma_monitor_buf_ring_size = 4096,
+ .rxdma_monitor_dst_ring_size = 8092,
+ .num_pool_tx_desc = 32768,
+ .rx_desc_count = 12288,
+ },
+ },
+[ATH12K_QMI_MEMORY_MODE_LOW_512_M] = {
+ .num_vdevs = 9,
+ .max_client_single = 128,
+ .max_client_dbs = 64,
+ .max_client_dbs_sbs = 64,
+ .dp_params = {
+ .tx_comp_ring_size = 16384,
+ .rxdma_monitor_buf_ring_size = 256,
+ .rxdma_monitor_dst_ring_size = 512,
+ .num_pool_tx_desc = 16384,
+ .rx_desc_count = 6144,
+ },
+ },
+};
+
+static int ath12k_core_rfkill_config(struct ath12k_base *ab)
+{
+ struct ath12k *ar;
+ int ret = 0, i;
+
+ if (!(ab->target_caps.sys_cap_info & WMI_SYS_CAP_INFO_RFKILL))
+ return 0;
+
+ if (ath12k_acpi_get_disable_rfkill(ab))
+ return 0;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ ar = ab->pdevs[i].ar;
+
+ ret = ath12k_mac_rfkill_config(ar);
+ if (ret && ret != -EOPNOTSUPP) {
+ ath12k_warn(ab, "failed to configure rfkill: %d", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/* Check if we need to continue with suspend/resume operation.
+ * Return:
+ * a negative value: error happens and don't continue.
+ * 0: no error but don't continue.
+ * positive value: no error and do continue.
+ */
+static int ath12k_core_continue_suspend_resume(struct ath12k_base *ab)
+{
+ struct ath12k *ar;
+
+ if (!ab->hw_params->supports_suspend)
+ return -EOPNOTSUPP;
+
+ /* so far single_pdev_only chips have supports_suspend as true
+ * so pass 0 as a dummy pdev_id here.
+ */
+ ar = ab->pdevs[0].ar;
+ if (!ar || !ar->ah || ar->ah->state != ATH12K_HW_STATE_OFF)
+ return 0;
+
+ return 1;
+}
+
+int ath12k_core_suspend(struct ath12k_base *ab)
+{
+ struct ath12k *ar;
+ int ret, i;
+
+ ret = ath12k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
+
+ for (i = 0; i < ab->num_radios; i++) {
+ ar = ab->pdevs[i].ar;
+ if (!ar)
+ continue;
+
+ wiphy_lock(ath12k_ar_to_hw(ar)->wiphy);
+
+ ret = ath12k_mac_wait_tx_complete(ar);
+ if (ret) {
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
+ ath12k_warn(ab, "failed to wait tx complete: %d\n", ret);
+ return ret;
+ }
+
+ wiphy_unlock(ath12k_ar_to_hw(ar)->wiphy);
+ }
+
+ /* PM framework skips suspend_late/resume_early callbacks
+ * if other devices report errors in their suspend callbacks.
+ * However ath12k_core_resume() would still be called because
+ * here we return success thus kernel put us on dpm_suspended_list.
+ * Since we won't go through a power down/up cycle, there is
+ * no chance to call complete(&ab->restart_completed) in
+ * ath12k_core_restart(), making ath12k_core_resume() timeout.
+ * So call it here to avoid this issue. This also works in case
+ * no error happens thus suspend_late/resume_early get called,
+ * because it will be reinitialized in ath12k_core_resume_early().
+ */
+ complete(&ab->restart_completed);
+
+ return 0;
+}
+EXPORT_SYMBOL(ath12k_core_suspend);
+
+int ath12k_core_suspend_late(struct ath12k_base *ab)
+{
+ int ret;
+
+ ret = ath12k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
+
+ ath12k_acpi_stop(ab);
+
+ ath12k_hif_irq_disable(ab);
+ ath12k_hif_ce_irq_disable(ab);
+
+ ath12k_hif_power_down(ab, true);
+
+ return 0;
+}
+EXPORT_SYMBOL(ath12k_core_suspend_late);
+
+int ath12k_core_resume_early(struct ath12k_base *ab)
+{
+ int ret;
+
+ ret = ath12k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
+
+ reinit_completion(&ab->restart_completed);
+ ret = ath12k_hif_power_up(ab);
+ if (ret)
+ ath12k_warn(ab, "failed to power up hif during resume: %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(ath12k_core_resume_early);
+
+int ath12k_core_resume(struct ath12k_base *ab)
+{
+ long time_left;
+ int ret;
+
+ ret = ath12k_core_continue_suspend_resume(ab);
+ if (ret <= 0)
+ return ret;
+
+ time_left = wait_for_completion_timeout(&ab->restart_completed,
+ ATH12K_RESET_TIMEOUT_HZ);
+ if (time_left == 0) {
+ ath12k_warn(ab, "timeout while waiting for restart complete");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ath12k_core_resume);
+
+static int __ath12k_core_create_board_name(struct ath12k_base *ab, char *name,
+ size_t name_len, bool with_variant,
+ bool bus_type_mode, bool with_default)
+{
+ /* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */
+ char variant[9 + ATH12K_QMI_BDF_EXT_STR_LENGTH] = {};
+
+ if (with_variant && ab->qmi.target.bdf_ext[0] != '\0')
+ scnprintf(variant, sizeof(variant), ",variant=%s",
+ ab->qmi.target.bdf_ext);
+
+ 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,
+ with_default ?
+ ATH12K_BOARD_ID_DEFAULT : 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, 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, true);
+}
+
+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, true);
+}
+
+const struct firmware *ath12k_core_firmware_request(struct ath12k_base *ab,
+ const char *file)
+{
+ const struct firmware *fw;
+ char path[100];
+ int ret;
+
+ if (!file)
+ return ERR_PTR(-ENOENT);
+
+ ath12k_core_create_firmware_path(ab, file, path, sizeof(path));
+
+ ret = firmware_request_nowarn(&fw, path, ab->dev);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot firmware request %s size %zu\n",
+ path, fw->size);
+
+ return fw;
+}
+
+void ath12k_core_free_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd)
+{
+ if (!IS_ERR(bd->fw))
+ release_firmware(bd->fw);
+
+ memset(bd, 0, sizeof(*bd));
+}
+
+static int ath12k_core_parse_bd_ie_board(struct ath12k_base *ab,
+ struct ath12k_board_data *bd,
+#if defined(__linux__)
+ const void *buf, size_t buf_len,
+#elif defined(__FreeBSD__)
+ const u8 *buf, size_t buf_len,
+#endif
+ const char *boardname,
+ int ie_id,
+ int name_id,
+ int data_id)
+{
+ const struct ath12k_fw_ie *hdr;
+ bool name_match_found;
+ int ret, board_ie_id;
+ size_t board_ie_len;
+ const void *board_ie_data;
+
+ name_match_found = false;
+
+ /* go through ATH12K_BD_IE_BOARD_/ATH12K_BD_IE_REGDB_ elements */
+ while (buf_len > sizeof(struct ath12k_fw_ie)) {
+#if defined(__linux__)
+ hdr = buf;
+#elif defined(__FreeBSD__)
+ hdr = (const struct ath12k_fw_ie *)buf;
+#endif
+ board_ie_id = le32_to_cpu(hdr->id);
+ board_ie_len = le32_to_cpu(hdr->len);
+ board_ie_data = hdr->data;
+
+ buf_len -= sizeof(*hdr);
+ buf += sizeof(*hdr);
+
+ if (buf_len < ALIGN(board_ie_len, 4)) {
+ 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;
+ }
+
+ 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))
+ goto next;
+
+ ret = memcmp(board_ie_data, boardname, strlen(boardname));
+ if (ret)
+ goto next;
+
+ name_match_found = true;
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "boot found match %s for name '%s'",
+ ath12k_bd_ie_type_str(ie_id),
+ boardname);
+ } else if (board_ie_id == data_id) {
+ if (!name_match_found)
+ /* no match found */
+ goto next;
+
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "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;
+ } else {
+ ath12k_warn(ab, "unknown %s id found: %d\n",
+ ath12k_bd_ie_type_str(ie_id),
+ board_ie_id);
+ }
+next:
+ /* jump over the padding */
+ board_ie_len = ALIGN(board_ie_len, 4);
+
+ buf_len -= board_ie_len;
+ buf += board_ie_len;
+ }
+
+ /* no match found */
+ ret = -ENOENT;
+
+out:
+ return ret;
+}
+
+static int ath12k_core_fetch_board_data_api_n(struct ath12k_base *ab,
+ struct ath12k_board_data *bd,
+ const char *boardname,
+ int ie_id_match,
+ int name_id,
+ int data_id)
+{
+ size_t len, magic_len;
+ const u8 *data;
+ char *filename, filepath[100];
+ size_t ie_len;
+#if defined(__linux__)
+ struct ath12k_fw_ie *hdr;
+#elif defined(__FreeBSD__)
+ const struct ath12k_fw_ie *hdr;
+#endif
+ int ret, ie_id;
+
+ filename = ATH12K_BOARD_API2_FILE;
+
+ if (!bd->fw)
+ bd->fw = ath12k_core_firmware_request(ab, filename);
+
+ if (IS_ERR(bd->fw))
+ return PTR_ERR(bd->fw);
+
+ data = bd->fw->data;
+ len = bd->fw->size;
+
+ ath12k_core_create_firmware_path(ab, filename,
+ filepath, sizeof(filepath));
+
+ /* magic has extra null byte padded */
+ magic_len = strlen(ATH12K_BOARD_MAGIC) + 1;
+ if (len < magic_len) {
+ ath12k_err(ab, "failed to find magic value in %s, file too short: %zu\n",
+ filepath, len);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (memcmp(data, ATH12K_BOARD_MAGIC, magic_len)) {
+ ath12k_err(ab, "found invalid board magic\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* magic is padded to 4 bytes */
+ magic_len = ALIGN(magic_len, 4);
+ if (len < magic_len) {
+ ath12k_err(ab, "failed: %s too small to contain board data, len: %zu\n",
+ filepath, len);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ data += magic_len;
+ len -= magic_len;
+
+ while (len > sizeof(struct ath12k_fw_ie)) {
+#if defined(__linux__)
+ hdr = (struct ath12k_fw_ie *)data;
+#elif defined(__FreeBSD__)
+ hdr = (const struct ath12k_fw_ie *)data;
+#endif
+ ie_id = le32_to_cpu(hdr->id);
+ ie_len = le32_to_cpu(hdr->len);
+
+ len -= sizeof(*hdr);
+ data = hdr->data;
+
+ if (len < ALIGN(ie_len, 4)) {
+ ath12k_err(ab, "invalid length for board ie_id %d ie_len %zu len %zu\n",
+ ie_id, ie_len, len);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (ie_id == ie_id_match) {
+ ret = ath12k_core_parse_bd_ie_board(ab, bd, data,
+ ie_len,
+ boardname,
+ ie_id_match,
+ name_id,
+ data_id);
+ if (ret == -ENOENT)
+ /* no match found, continue */
+ 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);
+
+ len -= ie_len;
+ data += ie_len;
+ }
+
+out:
+ if (!bd->data || !bd->len) {
+ 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;
+ }
+
+ return 0;
+
+err:
+ ath12k_core_free_bdf(ab, bd);
+ return ret;
+}
+
+int ath12k_core_fetch_board_data_api_1(struct ath12k_base *ab,
+ struct ath12k_board_data *bd,
+ char *filename)
+{
+ bd->fw = ath12k_core_firmware_request(ab, filename);
+ if (IS_ERR(bd->fw))
+ return PTR_ERR(bd->fw);
+
+ bd->data = bd->fw->data;
+ bd->len = bd->fw->size;
+
+ return 0;
+}
+
+#define BOARD_NAME_SIZE 200
+int ath12k_core_fetch_bdf(struct ath12k_base *ab, struct ath12k_board_data *bd)
+{
+ char boardname[BOARD_NAME_SIZE], fallback_boardname[BOARD_NAME_SIZE];
+ char *filename, filepath[100];
+ int bd_api;
+ int ret;
+
+ 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,
+ 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_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;
+ }
+
+success:
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "using board api %d\n", bd_api);
+ 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(ab, DBS);
+ if (ab->num_radios == 3)
+ return TARGET_NUM_STATIONS(ab, DBS_SBS);
+ return TARGET_NUM_STATIONS(ab, SINGLE);
+}
+
+u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab)
+{
+ return ath12k_core_get_max_station_per_radio(ab) + TARGET_NUM_VDEVS(ab);
+}
++EXPORT_SYMBOL(ath12k_core_get_max_peers_per_radio);
+
+struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab,
+ int index)
+{
+ struct device *dev = ab->dev;
+ struct reserved_mem *rmem;
+ struct device_node *node;
+
+ node = of_parse_phandle(dev->of_node, "memory-region", index);
+ if (!node) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "failed to parse memory-region for index %d\n", index);
+ return NULL;
+ }
+
+ rmem = of_reserved_mem_lookup(node);
+ of_node_put(node);
+ if (!rmem) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "unable to get memory-region for index %d\n", index);
+ return NULL;
+ }
+
+ return rmem;
+}
+
+static inline
+void ath12k_core_to_group_ref_get(struct ath12k_base *ab)
+{
+ struct ath12k_hw_group *ag = ab->ag;
+
+ lockdep_assert_held(&ag->mutex);
+
+ if (ab->hw_group_ref) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "core already attached to group %d\n",
+ ag->id);
+ return;
+ }
+
+ ab->hw_group_ref = true;
+ ag->num_started++;
+
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "core attached to group %d, num_started %d\n",
+ ag->id, ag->num_started);
+}
+
+static inline
+void ath12k_core_to_group_ref_put(struct ath12k_base *ab)
+{
+ struct ath12k_hw_group *ag = ab->ag;
+
+ lockdep_assert_held(&ag->mutex);
+
+ if (!ab->hw_group_ref) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "core already de-attached from group %d\n",
+ ag->id);
+ return;
+ }
+
+ ab->hw_group_ref = false;
+ ag->num_started--;
+
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "core de-attached from group %d, num_started %d\n",
+ ag->id, ag->num_started);
+}
+
+static void ath12k_core_stop(struct ath12k_base *ab)
+{
++ ath12k_link_sta_rhash_tbl_destroy(ab);
++
+ ath12k_core_to_group_ref_put(ab);
+
+ if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
+ ath12k_qmi_firmware_stop(ab);
+
+ ath12k_acpi_stop(ab);
+
+ ath12k_dp_rx_pdev_reo_cleanup(ab);
+ ath12k_hif_stop(ab);
+ ath12k_wmi_detach(ab);
- ath12k_dp_free(ab);
++ ath12k_dp_cmn_device_deinit(ath12k_ab_to_dp(ab));
+
+ /* De-Init of components as needed */
+}
+
+static void ath12k_core_check_cc_code_bdfext(const struct dmi_header *hdr, void *data)
+{
+ struct ath12k_base *ab = data;
+ const char *magic = ATH12K_SMBIOS_BDF_EXT_MAGIC;
+ struct ath12k_smbios_bdf *smbios = (struct ath12k_smbios_bdf *)hdr;
+ ssize_t copied;
+ size_t len;
+ int i;
+
+ if (ab->qmi.target.bdf_ext[0] != '\0')
+ return;
+
+ if (hdr->type != ATH12K_SMBIOS_BDF_EXT_TYPE)
+ return;
+
+ if (hdr->length != ATH12K_SMBIOS_BDF_EXT_LENGTH) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "wrong smbios bdf ext type length (%d).\n",
+ hdr->length);
+ return;
+ }
+
+ spin_lock_bh(&ab->base_lock);
+
+ switch (smbios->country_code_flag) {
+ case ATH12K_SMBIOS_CC_ISO:
+ ab->new_alpha2[0] = u16_get_bits(smbios->cc_code >> 8, 0xff);
+ ab->new_alpha2[1] = u16_get_bits(smbios->cc_code, 0xff);
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot smbios cc_code %c%c\n",
+ ab->new_alpha2[0], ab->new_alpha2[1]);
+ break;
+ case ATH12K_SMBIOS_CC_WW:
+ ab->new_alpha2[0] = '0';
+ ab->new_alpha2[1] = '0';
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot smbios worldwide regdomain\n");
+ break;
+ default:
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "boot ignore smbios country code setting %d\n",
+ smbios->country_code_flag);
+ break;
+ }
+
+ spin_unlock_bh(&ab->base_lock);
+
+ if (!smbios->bdf_enabled) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT, "bdf variant name not found.\n");
+ return;
+ }
+
+ /* Only one string exists (per spec) */
+ if (memcmp(smbios->bdf_ext, magic, strlen(magic)) != 0) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "bdf variant magic does not match.\n");
+ return;
+ }
+
+ len = min_t(size_t,
+ strlen(smbios->bdf_ext), sizeof(ab->qmi.target.bdf_ext));
+ for (i = 0; i < len; i++) {
+ if (!isascii(smbios->bdf_ext[i]) || !isprint(smbios->bdf_ext[i])) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "bdf variant name contains non ascii chars.\n");
+ return;
+ }
+ }
+
+ /* Copy extension name without magic prefix */
+ copied = strscpy(ab->qmi.target.bdf_ext, smbios->bdf_ext + strlen(magic),
+ sizeof(ab->qmi.target.bdf_ext));
+ if (copied < 0) {
+ ath12k_dbg(ab, ATH12K_DBG_BOOT,
+ "bdf variant string is longer than the buffer can accommodate\n");
+ return;
+ }
*** 26940 LINES SKIPPED ***