summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2026-02-02 17:55:04 +0100
committerJohannes Berg <johannes.berg@intel.com>2026-02-02 17:55:23 +0100
commit19dd0cc36a52d0d121d7854cbb9b00d6d4dcad0a (patch)
treebfe56948d666520168e3ad78cd4640ea32cf6c7e /drivers/net/wireless
parent0d95280a2d54ebd3d38adc4ff67808009798978c (diff)
parent2c1ba9c2adf0fda96eaaebd8799268a7506a8fc9 (diff)
downloadlwn-19dd0cc36a52d0d121d7854cbb9b00d6d4dcad0a.tar.gz
lwn-19dd0cc36a52d0d121d7854cbb9b00d6d4dcad0a.zip
Merge tag 'ath-next-20260202' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath
Jeff Johnson says: ================== ath.git patches for v6.20/v7.0 (#3) A set of small features and cleanups for the next merge window. ================== Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/ath/ath10k/sdio.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.c53
-rw-r--r--drivers/net/wireless/ath/ath10k/snoc.h3
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c4
-rw-r--r--drivers/net/wireless/ath/ath11k/core.c27
-rw-r--r--drivers/net/wireless/ath/ath11k/core.h4
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c197
-rw-r--r--drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h81
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.c174
-rw-r--r--drivers/net/wireless/ath/ath12k/mac.h3
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.c142
-rw-r--r--drivers/net/wireless/ath/ath12k/wmi.h47
12 files changed, 729 insertions, 12 deletions
diff --git a/drivers/net/wireless/ath/ath10k/sdio.c b/drivers/net/wireless/ath/ath10k/sdio.c
index c06d50db40b8..00d0556dafef 100644
--- a/drivers/net/wireless/ath/ath10k/sdio.c
+++ b/drivers/net/wireless/ath/ath10k/sdio.c
@@ -2487,7 +2487,11 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
if (fast_dump)
ath10k_bmi_start(ar);
+ mutex_lock(&ar->dump_mutex);
+
+ spin_lock_bh(&ar->data_lock);
ar->stats.fw_crash_counter++;
+ spin_unlock_bh(&ar->data_lock);
ath10k_sdio_disable_intrs(ar);
@@ -2505,6 +2509,8 @@ void ath10k_sdio_fw_crashed_dump(struct ath10k *ar)
ath10k_sdio_enable_intrs(ar);
+ mutex_unlock(&ar->dump_mutex);
+
ath10k_core_start_recovery(ar);
}
diff --git a/drivers/net/wireless/ath/ath10k/snoc.c b/drivers/net/wireless/ath/ath10k/snoc.c
index b3f6424c17d3..f72f236fb9eb 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.c
+++ b/drivers/net/wireless/ath/ath10k/snoc.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: ISC
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/bits.h>
@@ -11,6 +12,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/property.h>
+#include <linux/pwrseq/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/remoteproc/qcom_rproc.h>
#include <linux/of_reserved_mem.h>
@@ -1023,10 +1025,14 @@ static int ath10k_hw_power_on(struct ath10k *ar)
ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");
- ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);
+ ret = pwrseq_power_on(ar_snoc->pwrseq);
if (ret)
return ret;
+ ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);
+ if (ret)
+ goto pwrseq_off;
+
ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks);
if (ret)
goto vreg_off;
@@ -1035,18 +1041,28 @@ static int ath10k_hw_power_on(struct ath10k *ar)
vreg_off:
regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
+pwrseq_off:
+ pwrseq_power_off(ar_snoc->pwrseq);
+
return ret;
}
static int ath10k_hw_power_off(struct ath10k *ar)
{
struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);
+ int ret_seq = 0;
+ int ret_vreg;
ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");
clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks);
- return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
+ ret_vreg = regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);
+
+ if (ar_snoc->pwrseq)
+ ret_seq = pwrseq_power_off(ar_snoc->pwrseq);
+
+ return ret_vreg ? : ret_seq;
}
static void ath10k_snoc_wlan_disable(struct ath10k *ar)
@@ -1762,7 +1778,38 @@ static int ath10k_snoc_probe(struct platform_device *pdev)
goto err_release_resource;
}
- ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators);
+ /*
+ * devm_pwrseq_get() can return -EPROBE_DEFER in two cases:
+ * - it is not supposed to be used
+ * - it is supposed to be used, but the driver hasn't probed yet.
+ *
+ * There is no simple way to distinguish between these two cases, but:
+ * - if it is not supposed to be used, then regulator_bulk_get() will
+ * return all regulators as expected, continuing the probe
+ * - if it is supposed to be used, but wasn't probed yet, we will get
+ * -EPROBE_DEFER from regulator_bulk_get() too.
+ *
+ * For backwards compatibility with DTs specifying regulators directly
+ * rather than using the PMU device, ignore the defer error from
+ * pwrseq.
+ */
+ ar_snoc->pwrseq = devm_pwrseq_get(&pdev->dev, "wlan");
+ if (IS_ERR(ar_snoc->pwrseq)) {
+ ret = PTR_ERR(ar_snoc->pwrseq);
+ ar_snoc->pwrseq = NULL;
+ if (ret != -EPROBE_DEFER)
+ goto err_free_irq;
+
+ ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators);
+ } else {
+ /*
+ * The first regulator (vdd-0.8-cx-mx) is used to power on part
+ * of the SoC rather than the PMU on WCN399x, the rest are
+ * handled via pwrseq.
+ */
+ ar_snoc->num_vregs = 1;
+ }
+
ar_snoc->vregs = devm_kcalloc(&pdev->dev, ar_snoc->num_vregs,
sizeof(*ar_snoc->vregs), GFP_KERNEL);
if (!ar_snoc->vregs) {
diff --git a/drivers/net/wireless/ath/ath10k/snoc.h b/drivers/net/wireless/ath/ath10k/snoc.h
index d4bce1707696..1ecae34687c2 100644
--- a/drivers/net/wireless/ath/ath10k/snoc.h
+++ b/drivers/net/wireless/ath/ath10k/snoc.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: ISC */
/*
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef _SNOC_H_
@@ -53,6 +54,7 @@ enum ath10k_snoc_flags {
};
struct clk_bulk_data;
+struct pwrseq_desc;
struct regulator_bulk_data;
struct ath10k_snoc {
@@ -73,6 +75,7 @@ struct ath10k_snoc {
struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX];
struct ath10k_ce ce;
struct timer_list rx_post_retry;
+ struct pwrseq_desc *pwrseq;
struct regulator_bulk_data *vregs;
size_t num_vregs;
struct clk_bulk_data *clks;
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index b4aad6604d6d..ce22141e5efd 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -5289,8 +5289,6 @@ ath10k_wmi_event_peer_sta_ps_state_chg(struct ath10k *ar, struct sk_buff *skb)
struct ath10k_sta *arsta;
u8 peer_addr[ETH_ALEN];
- lockdep_assert_held(&ar->data_lock);
-
ev = (struct wmi_peer_sta_ps_state_chg_event *)skb->data;
ether_addr_copy(peer_addr, ev->peer_macaddr.addr);
@@ -5305,7 +5303,9 @@ ath10k_wmi_event_peer_sta_ps_state_chg(struct ath10k *ar, struct sk_buff *skb)
}
arsta = (struct ath10k_sta *)sta->drv_priv;
+ spin_lock_bh(&ar->data_lock);
arsta->peer_ps_state = __le32_to_cpu(ev->peer_ps_state);
+ spin_unlock_bh(&ar->data_lock);
exit:
rcu_read_unlock();
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index de84906d1b27..3f6f4db5b7ee 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1044,6 +1044,33 @@ static const struct dmi_system_id ath11k_pm_quirk_table[] = {
{}
};
+static const struct __ath11k_core_usecase_firmware_table {
+ u32 hw_rev;
+ const char *compatible;
+ const char *firmware_name;
+} ath11k_core_usecase_firmware_table[] = {
+ { ATH11K_HW_WCN6855_HW21, "qcom,lemans-evk", "nfa765"},
+ { ATH11K_HW_WCN6855_HW21, "qcom,monaco-evk", "nfa765"},
+ { ATH11K_HW_WCN6855_HW21, "qcom,hamoa-iot-evk", "nfa765"},
+ { /* Sentinel */ }
+};
+
+const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab)
+{
+ const struct __ath11k_core_usecase_firmware_table *entry = NULL;
+
+ entry = ath11k_core_usecase_firmware_table;
+ while (entry->compatible) {
+ if (ab->hw_rev == entry->hw_rev &&
+ of_machine_is_compatible(entry->compatible))
+ return entry->firmware_name;
+ entry++;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(ath11k_core_get_usecase_firmware);
+
void ath11k_fw_stats_pdevs_free(struct list_head *head)
{
struct ath11k_fw_stats_pdev *i, *tmp;
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 3f41e6569a78..a0d725923ef2 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -1292,6 +1292,7 @@ bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab);
const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
const char *filename);
+const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab);
static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state)
{
@@ -1346,6 +1347,9 @@ static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab,
of_property_read_string(ab->dev->of_node, "firmware-name", &fw_name);
+ if (!fw_name)
+ fw_name = ath11k_core_get_usecase_firmware(ab);
+
if (fw_name && strncmp(filename, "board", 5))
snprintf(buf, buf_len, "%s/%s/%s/%s", ATH11K_FW_DIR,
ab->hw_params.fw.dir, fw_name, filename);
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
index 48b010a1b756..7f6ca07fb335 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/vmalloc.h>
@@ -29,8 +29,10 @@ print_array_to_buf_index(u8 *buf, u32 offset, const char *header, u32 stats_inde
" %u:%u,", stats_index++, le32_to_cpu(array[i]));
}
/* To overwrite the last trailing comma */
- index--;
- *(buf + offset + index) = '\0';
+ if (array_len > 0) {
+ index--;
+ *(buf + offset + index) = '\0';
+ }
if (footer) {
index += scnprintf(buf + offset + index,
@@ -5537,6 +5539,189 @@ ath12k_htt_print_pdev_rtt_tbr_cmd_res_stats_tlv(const void *tag_buf, u16 tag_len
stats_req->buf_len = len;
}
+static void
+ath12k_htt_print_rx_pdev_fw_stats_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct htt_rx_pdev_fw_stats_tlv *htt_stats_buf = tag_buf;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 len = stats_req->buf_len;
+ u8 *buf = stats_req->buf;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_RX_PDEV_FW_STATS_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n",
+ le32_to_cpu(htt_stats_buf->mac_id__word) & 0xFF);
+ len += scnprintf(buf + len, buf_len - len, "ppdu_recvd = %u\n",
+ le32_to_cpu(htt_stats_buf->ppdu_recvd));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_cnt_fcs_ok = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_cnt_fcs_ok));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_cnt_fcs_err = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_cnt_fcs_err));
+ len += scnprintf(buf + len, buf_len - len, "tcp_msdu_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->tcp_msdu_cnt));
+ len += scnprintf(buf + len, buf_len - len, "tcp_ack_msdu_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->tcp_ack_msdu_cnt));
+ len += scnprintf(buf + len, buf_len - len, "udp_msdu_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->udp_msdu_cnt));
+ len += scnprintf(buf + len, buf_len - len, "other_msdu_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->other_msdu_cnt));
+ len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_ind = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_ring_mpdu_ind));
+ len += print_array_to_buf(buf, len, "fw_ring_mgmt_subtype",
+ htt_stats_buf->fw_ring_mgmt_subtype,
+ ATH12K_HTT_STATS_SUBTYPE_MAX, "\n");
+ len += print_array_to_buf(buf, len, "fw_ring_ctrl_subtype",
+ htt_stats_buf->fw_ring_ctrl_subtype,
+ ATH12K_HTT_STATS_SUBTYPE_MAX, "\n");
+ len += scnprintf(buf + len, buf_len - len, "fw_ring_mcast_data_msdu = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_ring_mcast_data_msdu));
+ len += scnprintf(buf + len, buf_len - len, "fw_ring_bcast_data_msdu = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_ring_bcast_data_msdu));
+ len += scnprintf(buf + len, buf_len - len, "fw_ring_ucast_data_msdu = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_ring_ucast_data_msdu));
+ len += scnprintf(buf + len, buf_len - len, "fw_ring_null_data_msdu = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_ring_null_data_msdu));
+ len += scnprintf(buf + len, buf_len - len, "fw_ring_mpdu_drop = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_ring_mpdu_drop));
+ len += scnprintf(buf + len, buf_len - len, "ofld_local_data_ind_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->ofld_local_data_ind_cnt));
+ len += scnprintf(buf + len, buf_len - len,
+ "ofld_local_data_buf_recycle_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->ofld_local_data_buf_recycle_cnt));
+ len += scnprintf(buf + len, buf_len - len, "drx_local_data_ind_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->drx_local_data_ind_cnt));
+ len += scnprintf(buf + len, buf_len - len,
+ "drx_local_data_buf_recycle_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->drx_local_data_buf_recycle_cnt));
+ len += scnprintf(buf + len, buf_len - len, "local_nondata_ind_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->local_nondata_ind_cnt));
+ len += scnprintf(buf + len, buf_len - len, "local_nondata_buf_recycle_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->local_nondata_buf_recycle_cnt));
+ len += scnprintf(buf + len, buf_len - len, "fw_status_buf_ring_refill_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_status_buf_ring_refill_cnt));
+ len += scnprintf(buf + len, buf_len - len, "fw_status_buf_ring_empty_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_status_buf_ring_empty_cnt));
+ len += scnprintf(buf + len, buf_len - len, "fw_pkt_buf_ring_refill_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_pkt_buf_ring_refill_cnt));
+ len += scnprintf(buf + len, buf_len - len, "fw_pkt_buf_ring_empty_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_pkt_buf_ring_empty_cnt));
+ len += scnprintf(buf + len, buf_len - len, "fw_link_buf_ring_refill_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_link_buf_ring_refill_cnt));
+ len += scnprintf(buf + len, buf_len - len, "fw_link_buf_ring_empty_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->fw_link_buf_ring_empty_cnt));
+ len += scnprintf(buf + len, buf_len - len, "host_pkt_buf_ring_refill_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->host_pkt_buf_ring_refill_cnt));
+ len += scnprintf(buf + len, buf_len - len, "host_pkt_buf_ring_empty_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->host_pkt_buf_ring_empty_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mon_pkt_buf_ring_refill_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mon_pkt_buf_ring_refill_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mon_pkt_buf_ring_empty_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mon_pkt_buf_ring_empty_cnt));
+ len += scnprintf(buf + len, buf_len - len,
+ "mon_status_buf_ring_refill_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mon_status_buf_ring_refill_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mon_status_buf_ring_empty_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mon_status_buf_ring_empty_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mon_desc_buf_ring_refill_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mon_desc_buf_ring_refill_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mon_desc_buf_ring_empty_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mon_desc_buf_ring_empty_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mon_dest_ring_update_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mon_dest_ring_update_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mon_dest_ring_full_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mon_dest_ring_full_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_suspend_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_suspend_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_suspend_fail_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_suspend_fail_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_resume_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_resume_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_resume_fail_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_resume_fail_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_ring_switch_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_ring_switch_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_ring_restore_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_ring_restore_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_flush_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_flush_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_recovery_reset_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_recovery_reset_cnt));
+ len += scnprintf(buf + len, buf_len - len, "rx_lwm_prom_filter_dis = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_lwm_prom_filter_dis));
+ len += scnprintf(buf + len, buf_len - len, "rx_hwm_prom_filter_en = %u\n",
+ le32_to_cpu(htt_stats_buf->rx_hwm_prom_filter_en));
+ len += scnprintf(buf + len, buf_len - len, "bytes_received_low_32 = %u\n",
+ le32_to_cpu(htt_stats_buf->bytes_received_low_32));
+ len += scnprintf(buf + len, buf_len - len, "bytes_received_high_32 = %u\n",
+ le32_to_cpu(htt_stats_buf->bytes_received_high_32));
+
+ stats_req->buf_len = len;
+}
+
+static void
+ath12k_htt_print_tx_hwq_stats_cmn_tlv(const void *tag_buf, u16 tag_len,
+ struct debug_htt_stats_req *stats_req)
+{
+ const struct htt_tx_hwq_stats_cmn_tlv *htt_stats_buf = tag_buf;
+ u32 buf_len = ATH12K_HTT_STATS_BUF_SIZE;
+ u32 len = stats_req->buf_len;
+ u8 *buf = stats_req->buf;
+
+ if (tag_len < sizeof(*htt_stats_buf))
+ return;
+
+ len += scnprintf(buf + len, buf_len - len, "HTT_TX_HWQ_STATS_CMN_TLV:\n");
+ len += scnprintf(buf + len, buf_len - len, "mac_id = %u\n",
+ le32_to_cpu(htt_stats_buf->mac_id__hwq_id__word) & 0xFF);
+ len += scnprintf(buf + len, buf_len - len, "hwq_id = %u\n",
+ (le32_to_cpu(htt_stats_buf->mac_id__hwq_id__word) & 0xFF00) >> 8);
+ len += scnprintf(buf + len, buf_len - len, "xretry = %u\n",
+ le32_to_cpu(htt_stats_buf->xretry));
+ len += scnprintf(buf + len, buf_len - len, "underrun_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->underrun_cnt));
+ len += scnprintf(buf + len, buf_len - len, "flush_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->flush_cnt));
+ len += scnprintf(buf + len, buf_len - len, "filt_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->filt_cnt));
+ len += scnprintf(buf + len, buf_len - len, "null_mpdu_bmap = %u\n",
+ le32_to_cpu(htt_stats_buf->null_mpdu_bmap));
+ len += scnprintf(buf + len, buf_len - len, "user_ack_failure = %u\n",
+ le32_to_cpu(htt_stats_buf->user_ack_failure));
+ len += scnprintf(buf + len, buf_len - len, "ack_tlv_proc = %u\n",
+ le32_to_cpu(htt_stats_buf->ack_tlv_proc));
+ len += scnprintf(buf + len, buf_len - len, "sched_id_proc = %u\n",
+ le32_to_cpu(htt_stats_buf->sched_id_proc));
+ len += scnprintf(buf + len, buf_len - len, "null_mpdu_tx_count = %u\n",
+ le32_to_cpu(htt_stats_buf->null_mpdu_tx_count));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_bmap_not_recvd = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_bmap_not_recvd));
+ len += scnprintf(buf + len, buf_len - len, "num_bar = %u\n",
+ le32_to_cpu(htt_stats_buf->num_bar));
+ len += scnprintf(buf + len, buf_len - len, "rts = %u\n",
+ le32_to_cpu(htt_stats_buf->rts));
+ len += scnprintf(buf + len, buf_len - len, "cts2self = %u\n",
+ le32_to_cpu(htt_stats_buf->cts2self));
+ len += scnprintf(buf + len, buf_len - len, "qos_null = %u\n",
+ le32_to_cpu(htt_stats_buf->qos_null));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_tried_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_tried_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_queued_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_queued_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_ack_fail_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_ack_fail_cnt));
+ len += scnprintf(buf + len, buf_len - len, "mpdu_filt_cnt = %u\n",
+ le32_to_cpu(htt_stats_buf->mpdu_filt_cnt));
+ len += scnprintf(buf + len, buf_len - len, "false_mpdu_ack_count = %u\n",
+ le32_to_cpu(htt_stats_buf->false_mpdu_ack_count));
+ len += scnprintf(buf + len, buf_len - len, "txq_timeout = %u\n",
+ le32_to_cpu(htt_stats_buf->txq_timeout));
+
+ stats_req->buf_len = len;
+}
+
static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
u16 tag, u16 len, const void *tag_buf,
void *user_data)
@@ -5690,6 +5875,9 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
case HTT_STATS_SFM_CLIENT_USER_TAG:
ath12k_htt_print_sfm_client_user_tlv(tag_buf, len, stats_req);
break;
+ case HTT_STATS_RX_PDEV_FW_STATS_TAG:
+ ath12k_htt_print_rx_pdev_fw_stats_tlv(tag_buf, len, stats_req);
+ break;
case HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG:
ath12k_htt_print_tx_pdev_mu_mimo_sch_stats_tlv(tag_buf, len, stats_req);
break;
@@ -5833,6 +6021,9 @@ static int ath12k_dbg_htt_ext_stats_parse(struct ath12k_base *ab,
case HTT_STATS_PDEV_RTT_TBR_CMD_RESULT_STATS_TAG:
ath12k_htt_print_pdev_rtt_tbr_cmd_res_stats_tlv(tag_buf, len, stats_req);
break;
+ case HTT_STATS_TX_HWQ_CMN_TAG:
+ ath12k_htt_print_tx_hwq_stats_cmn_tlv(tag_buf, len, stats_req);
+ break;
default:
break;
}
diff --git a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
index 8008658371aa..bfabe6500d44 100644
--- a/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
+++ b/drivers/net/wireless/ath/ath12k/debugfs_htt_stats.h
@@ -127,6 +127,8 @@ struct ath12k_htt_extd_stats_msg {
enum ath12k_dbg_htt_ext_stats_type {
ATH12K_DBG_HTT_EXT_STATS_RESET = 0,
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX = 1,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_RX = 2,
+ ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_HWQ = 3,
ATH12K_DBG_HTT_EXT_STATS_PDEV_TX_SCHED = 4,
ATH12K_DBG_HTT_EXT_STATS_PDEV_ERROR = 5,
ATH12K_DBG_HTT_EXT_STATS_PDEV_TQM = 6,
@@ -173,6 +175,7 @@ enum ath12k_dbg_htt_tlv_tag {
HTT_STATS_TX_PDEV_SIFS_TAG = 2,
HTT_STATS_TX_PDEV_FLUSH_TAG = 3,
HTT_STATS_STRING_TAG = 5,
+ HTT_STATS_TX_HWQ_CMN_TAG = 6,
HTT_STATS_TX_TQM_GEN_MPDU_TAG = 11,
HTT_STATS_TX_TQM_LIST_MPDU_TAG = 12,
HTT_STATS_TX_TQM_LIST_MPDU_CNT_TAG = 13,
@@ -188,6 +191,7 @@ enum ath12k_dbg_htt_tlv_tag {
HTT_STATS_TX_PDEV_MU_MIMO_STATS_TAG = 25,
HTT_STATS_SFM_CMN_TAG = 26,
HTT_STATS_SRING_STATS_TAG = 27,
+ HTT_STATS_RX_PDEV_FW_STATS_TAG = 28,
HTT_STATS_TX_PDEV_RATE_STATS_TAG = 34,
HTT_STATS_RX_PDEV_RATE_STATS_TAG = 35,
HTT_STATS_TX_PDEV_SCHEDULER_TXQ_STATS_TAG = 36,
@@ -2075,4 +2079,81 @@ struct ath12k_htt_stats_pdev_rtt_tbr_cmd_result_stats_tlv {
__le32 mu_res[ATH12K_HTT_FTYPE_MAX][ATH12K_HTT_MAX_SCH_CMD_RESULT];
} __packed;
+struct htt_rx_pdev_fw_stats_tlv {
+ __le32 mac_id__word;
+ __le32 ppdu_recvd;
+ __le32 mpdu_cnt_fcs_ok;
+ __le32 mpdu_cnt_fcs_err;
+ __le32 tcp_msdu_cnt;
+ __le32 tcp_ack_msdu_cnt;
+ __le32 udp_msdu_cnt;
+ __le32 other_msdu_cnt;
+ __le32 fw_ring_mpdu_ind;
+ __le32 fw_ring_mgmt_subtype[ATH12K_HTT_STATS_SUBTYPE_MAX];
+ __le32 fw_ring_ctrl_subtype[ATH12K_HTT_STATS_SUBTYPE_MAX];
+ __le32 fw_ring_mcast_data_msdu;
+ __le32 fw_ring_bcast_data_msdu;
+ __le32 fw_ring_ucast_data_msdu;
+ __le32 fw_ring_null_data_msdu;
+ __le32 fw_ring_mpdu_drop;
+ __le32 ofld_local_data_ind_cnt;
+ __le32 ofld_local_data_buf_recycle_cnt;
+ __le32 drx_local_data_ind_cnt;
+ __le32 drx_local_data_buf_recycle_cnt;
+ __le32 local_nondata_ind_cnt;
+ __le32 local_nondata_buf_recycle_cnt;
+ __le32 fw_status_buf_ring_refill_cnt;
+ __le32 fw_status_buf_ring_empty_cnt;
+ __le32 fw_pkt_buf_ring_refill_cnt;
+ __le32 fw_pkt_buf_ring_empty_cnt;
+ __le32 fw_link_buf_ring_refill_cnt;
+ __le32 fw_link_buf_ring_empty_cnt;
+ __le32 host_pkt_buf_ring_refill_cnt;
+ __le32 host_pkt_buf_ring_empty_cnt;
+ __le32 mon_pkt_buf_ring_refill_cnt;
+ __le32 mon_pkt_buf_ring_empty_cnt;
+ __le32 mon_status_buf_ring_refill_cnt;
+ __le32 mon_status_buf_ring_empty_cnt;
+ __le32 mon_desc_buf_ring_refill_cnt;
+ __le32 mon_desc_buf_ring_empty_cnt;
+ __le32 mon_dest_ring_update_cnt;
+ __le32 mon_dest_ring_full_cnt;
+ __le32 rx_suspend_cnt;
+ __le32 rx_suspend_fail_cnt;
+ __le32 rx_resume_cnt;
+ __le32 rx_resume_fail_cnt;
+ __le32 rx_ring_switch_cnt;
+ __le32 rx_ring_restore_cnt;
+ __le32 rx_flush_cnt;
+ __le32 rx_recovery_reset_cnt;
+ __le32 rx_lwm_prom_filter_dis;
+ __le32 rx_hwm_prom_filter_en;
+ __le32 bytes_received_low_32;
+ __le32 bytes_received_high_32;
+} __packed;
+
+struct htt_tx_hwq_stats_cmn_tlv {
+ __le32 mac_id__hwq_id__word;
+ __le32 xretry;
+ __le32 underrun_cnt;
+ __le32 flush_cnt;
+ __le32 filt_cnt;
+ __le32 null_mpdu_bmap;
+ __le32 user_ack_failure;
+ __le32 ack_tlv_proc;
+ __le32 sched_id_proc;
+ __le32 null_mpdu_tx_count;
+ __le32 mpdu_bmap_not_recvd;
+ __le32 num_bar;
+ __le32 rts;
+ __le32 cts2self;
+ __le32 qos_null;
+ __le32 mpdu_tried_cnt;
+ __le32 mpdu_queued_cnt;
+ __le32 mpdu_ack_fail_cnt;
+ __le32 mpdu_filt_cnt;
+ __le32 false_mpdu_ack_count;
+ __le32 txq_timeout;
+} __packed;
+
#endif
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index cdb72439dcf4..68431a0e128e 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4281,8 +4281,10 @@ ath12k_mac_op_change_vif_links(struct ieee80211_hw *hw,
if (WARN_ON(!arvif))
return -EINVAL;
- if (!arvif->is_created)
+ if (!arvif->is_created) {
+ ath12k_mac_unassign_link_vif(arvif);
continue;
+ }
if (WARN_ON(!arvif->ar))
return -EINVAL;
@@ -4505,6 +4507,166 @@ static void ath12k_wmi_vdev_params_up(struct ath12k *ar,
arvif->vdev_id, ret);
}
+static int ath12k_mac_config_obss_pd(struct ath12k_link_vif *arvif,
+ const struct ieee80211_he_obss_pd *he_obss_pd)
+{
+ struct ath12k_wmi_obss_pd_arg obss_pd_arg = {};
+ u32 srg_bitmap[2], non_srg_bitmap[2];
+ struct ath12k *ar = arvif->ar;
+ u32 param_id, pdev_id;
+ u32 param_val;
+ int ret;
+
+ if (ar->ab->hw_params->single_pdev_only)
+ pdev_id = ath12k_mac_get_target_pdev_id_from_vif(arvif);
+ else
+ pdev_id = ar->pdev->pdev_id;
+
+ /* Set and enable SRG/non-SRG OBSS PD threshold */
+ param_id = WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD;
+ if (ar->monitor_started || !he_obss_pd->enable) {
+ ret = ath12k_wmi_pdev_set_param(ar, param_id, 0, pdev_id);
+ if (ret)
+ ath12k_warn(ar->ab,
+ "failed to set OBSS PD threshold for pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ /*
+ * This service flag indicates firmware support for SRG/SRP-based
+ * spatial reuse. It also specifies whether OBSS PD threshold values
+ * should be interpreted as dB (offset) or dBm (absolute) units.
+ */
+ obss_pd_arg.srp_support = test_bit(WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT,
+ ar->ab->wmi_ab.svc_map);
+
+ if (!(he_obss_pd->sr_ctrl &
+ IEEE80211_HE_SPR_NON_SRG_OBSS_PD_SR_DISALLOWED)) {
+ if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_NON_SRG_OFFSET_PRESENT)
+ obss_pd_arg.non_srg_th = ATH12K_OBSS_PD_MAX_THRESHOLD +
+ he_obss_pd->non_srg_max_offset;
+ else
+ obss_pd_arg.non_srg_th = ATH12K_OBSS_PD_NON_SRG_MAX_THRESHOLD;
+
+ if (!obss_pd_arg.srp_support)
+ obss_pd_arg.non_srg_th -= ATH12K_DEFAULT_NOISE_FLOOR;
+
+ obss_pd_arg.non_srg_enabled = true;
+ }
+
+ if (he_obss_pd->sr_ctrl & IEEE80211_HE_SPR_SRG_INFORMATION_PRESENT) {
+ obss_pd_arg.srg_th = ATH12K_OBSS_PD_MAX_THRESHOLD +
+ he_obss_pd->max_offset;
+ obss_pd_arg.srg_enabled = true;
+ }
+
+ ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+ "pdev %u OBSS PD sr_ctrl 0x%x srg_th %d dBm non_srg_th %d dBm\n",
+ pdev_id, he_obss_pd->sr_ctrl,
+ obss_pd_arg.srg_th, obss_pd_arg.non_srg_th);
+
+ param_val = ath12k_wmi_build_obss_pd(&obss_pd_arg);
+ ret = ath12k_wmi_pdev_set_param(ar, param_id, param_val, pdev_id);
+ if (ret) {
+ ath12k_warn(ar->ab,
+ "failed to set OBSS PD threshold for pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ /* Enable OBSS PD for all access category */
+ param_id = WMI_PDEV_PARAM_SET_CMD_OBSS_PD_PER_AC;
+ param_val = 0xf;
+ ret = ath12k_wmi_pdev_set_param(ar, param_id, param_val, pdev_id);
+ if (ret) {
+ ath12k_warn(ar->ab,
+ "failed to set OBSS PD per ac for pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ /* Set SR prohibit */
+ param_id = WMI_PDEV_PARAM_ENABLE_SR_PROHIBIT;
+ param_val = !!(he_obss_pd->sr_ctrl &
+ IEEE80211_HE_SPR_HESIGA_SR_VAL15_ALLOWED);
+ ret = ath12k_wmi_pdev_set_param(ar, param_id, param_val, pdev_id);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to set SR prohibit for pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ if (!obss_pd_arg.srp_support)
+ return 0;
+
+ memcpy(srg_bitmap, he_obss_pd->bss_color_bitmap, sizeof(srg_bitmap));
+ /* Set SRG BSS color bitmap */
+ ret = ath12k_wmi_pdev_set_srg_bss_color_bitmap(ar, pdev_id, srg_bitmap);
+ if (ret) {
+ ath12k_warn(ar->ab,
+ "failed to set SRG bss color bitmap for pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ /* Enable BSS colors for SRG */
+ ret = ath12k_wmi_pdev_srg_obss_color_enable_bitmap(ar, pdev_id, srg_bitmap);
+ if (ret) {
+ ath12k_warn(ar->ab,
+ "failed to enable SRG bss color bitmap pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ memcpy(srg_bitmap, he_obss_pd->partial_bssid_bitmap, sizeof(srg_bitmap));
+ /* Set SRG partial bssid bitmap */
+ ret = ath12k_wmi_pdev_set_srg_partial_bssid_bitmap(ar, pdev_id, srg_bitmap);
+ if (ret) {
+ ath12k_warn(ar->ab,
+ "failed to set SRG partial bssid bitmap for pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ /* Enable partial bssid mask for SRG */
+ ret = ath12k_wmi_pdev_srg_obss_bssid_enable_bitmap(ar, pdev_id, srg_bitmap);
+ if (ret) {
+ ath12k_warn(ar->ab,
+ "failed to enable SRG bssid bitmap pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ /*
+ * No explicit non-SRG bitmap from mac80211; enable all colors/bssids
+ * as non-SRG candidates. Actual SRG members are filtered by SRG bitmaps.
+ */
+ memset(non_srg_bitmap, 0xff, sizeof(non_srg_bitmap));
+
+ /* Enable BSS colors for non-SRG */
+ ret = ath12k_wmi_pdev_non_srg_obss_color_enable_bitmap(ar, pdev_id,
+ non_srg_bitmap);
+ if (ret) {
+ ath12k_warn(ar->ab,
+ "failed to enable non SRG color bitmap pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ /* Enable partial bssid mask for non-SRG */
+ ret = ath12k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(ar, pdev_id,
+ non_srg_bitmap);
+ if (ret) {
+ ath12k_warn(ar->ab,
+ "failed to enable non SRG bssid bitmap pdev %u: %d\n",
+ pdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static void ath12k_mac_bss_info_changed(struct ath12k *ar,
struct ath12k_link_vif *arvif,
struct ieee80211_bss_conf *info,
@@ -4796,9 +4958,13 @@ skip_vdev_up:
ath12k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
}
- if (changed & BSS_CHANGED_HE_OBSS_PD)
- ath12k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id,
- &info->he_obss_pd);
+ if (changed & BSS_CHANGED_HE_OBSS_PD) {
+ if (vif->type == NL80211_IFTYPE_AP)
+ ath12k_mac_config_obss_pd(arvif, &info->he_obss_pd);
+ else
+ ath12k_wmi_send_obss_spr_cmd(ar, arvif->vdev_id,
+ &info->he_obss_pd);
+ }
if (changed & BSS_CHANGED_HE_BSS_COLOR) {
if (vif->type == NL80211_IFTYPE_AP) {
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 422bd3b095cd..7b50c5976384 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -138,6 +138,9 @@ struct ath12k_reg_tpc_power_info {
struct ath12k_chan_power_info chan_power_info[ATH12K_NUM_PWR_LEVELS];
};
+#define ATH12K_OBSS_PD_MAX_THRESHOLD -82
+#define ATH12K_OBSS_PD_NON_SRG_MAX_THRESHOLD -62
+
extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;
#define ATH12K_SCAN_11D_INTERVAL 600000
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index cce3d699112d..7617fc3a2479 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -126,6 +126,14 @@ struct wmi_tlv_mgmt_rx_parse {
bool frame_buf_done;
};
+struct wmi_pdev_set_obss_bitmap_arg {
+ u32 tlv_tag;
+ u32 pdev_id;
+ u32 cmd_id;
+ const u32 *bitmap;
+ const char *label;
+};
+
static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
[WMI_TAG_ARRAY_BYTE] = { .min_len = 0 },
[WMI_TAG_ARRAY_UINT32] = { .min_len = 0 },
@@ -3560,6 +3568,140 @@ ath12k_wmi_send_obss_spr_cmd(struct ath12k *ar, u32 vdev_id,
return ret;
}
+u32 ath12k_wmi_build_obss_pd(const struct ath12k_wmi_obss_pd_arg *arg)
+{
+ u32 param_val = 0;
+
+ param_val |= u32_encode_bits((u8)arg->srg_th, GENMASK(15, 8));
+ param_val |= u32_encode_bits((u8)arg->non_srg_th, GENMASK(7, 0));
+
+ if (arg->srp_support)
+ param_val |= ATH12K_OBSS_PD_THRESHOLD_IN_DBM;
+
+ if (arg->srg_enabled && arg->srp_support)
+ param_val |= ATH12K_OBSS_PD_SRG_EN;
+
+ if (arg->non_srg_enabled)
+ param_val |= ATH12K_OBSS_PD_NON_SRG_EN;
+
+ return param_val;
+}
+
+static int ath12k_wmi_pdev_set_obss_bitmap(struct ath12k *ar,
+ const struct wmi_pdev_set_obss_bitmap_arg *arg)
+{
+ struct wmi_pdev_obss_pd_bitmap_cmd *cmd;
+ struct ath12k_wmi_pdev *wmi = ar->wmi;
+ const int len = sizeof(*cmd);
+ struct sk_buff *skb;
+ int ret;
+
+ skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
+ if (!skb)
+ return -ENOMEM;
+
+ cmd = (struct wmi_pdev_obss_pd_bitmap_cmd *)skb->data;
+ cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(arg->tlv_tag, len);
+ cmd->pdev_id = cpu_to_le32(arg->pdev_id);
+ memcpy(cmd->bitmap, arg->bitmap, sizeof(cmd->bitmap));
+
+ ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+ "wmi set pdev %u %s %08x %08x\n",
+ arg->pdev_id, arg->label, arg->bitmap[0], arg->bitmap[1]);
+
+ ret = ath12k_wmi_cmd_send(wmi, skb, arg->cmd_id);
+ if (ret) {
+ ath12k_warn(ar->ab, "failed to send %s: %d\n", arg->label, ret);
+ dev_kfree_skb(skb);
+ }
+
+ return ret;
+}
+
+int ath12k_wmi_pdev_set_srg_bss_color_bitmap(struct ath12k *ar,
+ u32 pdev_id, const u32 *bitmap)
+{
+ struct wmi_pdev_set_obss_bitmap_arg arg = {
+ .tlv_tag = WMI_TAG_PDEV_SRG_BSS_COLOR_BITMAP_CMD,
+ .pdev_id = pdev_id,
+ .cmd_id = WMI_PDEV_SET_SRG_BSS_COLOR_BITMAP_CMDID,
+ .bitmap = bitmap,
+ .label = "SRG bss color bitmap",
+ };
+
+ return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
+}
+
+int ath12k_wmi_pdev_set_srg_partial_bssid_bitmap(struct ath12k *ar,
+ u32 pdev_id, const u32 *bitmap)
+{
+ struct wmi_pdev_set_obss_bitmap_arg arg = {
+ .tlv_tag = WMI_TAG_PDEV_SRG_PARTIAL_BSSID_BITMAP_CMD,
+ .pdev_id = pdev_id,
+ .cmd_id = WMI_PDEV_SET_SRG_PARTIAL_BSSID_BITMAP_CMDID,
+ .bitmap = bitmap,
+ .label = "SRG partial bssid bitmap",
+ };
+
+ return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
+}
+
+int ath12k_wmi_pdev_srg_obss_color_enable_bitmap(struct ath12k *ar,
+ u32 pdev_id, const u32 *bitmap)
+{
+ struct wmi_pdev_set_obss_bitmap_arg arg = {
+ .tlv_tag = WMI_TAG_PDEV_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD,
+ .pdev_id = pdev_id,
+ .cmd_id = WMI_PDEV_SET_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID,
+ .bitmap = bitmap,
+ .label = "SRG obss color enable bitmap",
+ };
+
+ return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
+}
+
+int ath12k_wmi_pdev_srg_obss_bssid_enable_bitmap(struct ath12k *ar,
+ u32 pdev_id, const u32 *bitmap)
+{
+ struct wmi_pdev_set_obss_bitmap_arg arg = {
+ .tlv_tag = WMI_TAG_PDEV_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
+ .pdev_id = pdev_id,
+ .cmd_id = WMI_PDEV_SET_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
+ .bitmap = bitmap,
+ .label = "SRG obss bssid enable bitmap",
+ };
+
+ return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
+}
+
+int ath12k_wmi_pdev_non_srg_obss_color_enable_bitmap(struct ath12k *ar,
+ u32 pdev_id, const u32 *bitmap)
+{
+ struct wmi_pdev_set_obss_bitmap_arg arg = {
+ .tlv_tag = WMI_TAG_PDEV_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD,
+ .pdev_id = pdev_id,
+ .cmd_id = WMI_PDEV_SET_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID,
+ .bitmap = bitmap,
+ .label = "non SRG obss color enable bitmap",
+ };
+
+ return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
+}
+
+int ath12k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(struct ath12k *ar,
+ u32 pdev_id, const u32 *bitmap)
+{
+ struct wmi_pdev_set_obss_bitmap_arg arg = {
+ .tlv_tag = WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
+ .pdev_id = pdev_id,
+ .cmd_id = WMI_PDEV_SET_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
+ .bitmap = bitmap,
+ .label = "non SRG obss bssid enable bitmap",
+ };
+
+ return ath12k_wmi_pdev_set_obss_bitmap(ar, &arg);
+}
+
int ath12k_wmi_obss_color_cfg_cmd(struct ath12k *ar, u32 vdev_id,
u8 bss_color, u32 period,
bool enable)
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index fdc203fdba0a..0bf0a7941cd3 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -374,6 +374,12 @@ enum wmi_tlv_cmd_id {
WMI_PDEV_DMA_RING_CFG_REQ_CMDID,
WMI_PDEV_HE_TB_ACTION_FRM_CMDID,
WMI_PDEV_PKTLOG_FILTER_CMDID,
+ WMI_PDEV_SET_SRG_BSS_COLOR_BITMAP_CMDID = 0x403b,
+ WMI_PDEV_SET_SRG_PARTIAL_BSSID_BITMAP_CMDID,
+ WMI_PDEV_SET_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID,
+ WMI_PDEV_SET_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
+ WMI_PDEV_SET_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMDID,
+ WMI_PDEV_SET_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMDID,
WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID = 0x4044,
WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045,
WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A,
@@ -1076,6 +1082,9 @@ enum wmi_tlv_pdev_param {
WMI_PDEV_PARAM_RADIO_CHAN_STATS_ENABLE,
WMI_PDEV_PARAM_RADIO_DIAGNOSIS_ENABLE,
WMI_PDEV_PARAM_MESH_MCAST_ENABLE,
+ WMI_PDEV_PARAM_SET_CMD_OBSS_PD_THRESHOLD = 0xbc,
+ WMI_PDEV_PARAM_SET_CMD_OBSS_PD_PER_AC = 0xbe,
+ WMI_PDEV_PARAM_ENABLE_SR_PROHIBIT = 0xc6,
};
enum wmi_tlv_vdev_param {
@@ -1987,6 +1996,12 @@ enum wmi_tlv_tag {
WMI_TAG_SERVICE_READY_EXT2_EVENT = 0x334,
WMI_TAG_FILS_DISCOVERY_TMPL_CMD = 0x344,
WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
+ WMI_TAG_PDEV_SRG_BSS_COLOR_BITMAP_CMD = 0x37b,
+ WMI_TAG_PDEV_SRG_PARTIAL_BSSID_BITMAP_CMD,
+ WMI_TAG_PDEV_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD = 0x381,
+ WMI_TAG_PDEV_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
+ WMI_TAG_PDEV_NON_SRG_OBSS_COLOR_ENABLE_BITMAP_CMD,
+ WMI_TAG_PDEV_NON_SRG_OBSS_BSSID_ENABLE_BITMAP_CMD,
WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
WMI_TAG_TPC_STATS_GET_CMD = 0x38B,
@@ -2244,6 +2259,7 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
WMI_TLV_SERVICE_EXT2_MSG = 220,
WMI_TLV_SERVICE_BEACON_PROTECTION_SUPPORT = 244,
+ WMI_TLV_SERVICE_SRG_SRP_SPATIAL_REUSE_SUPPORT = 249,
WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253,
WMI_MAX_EXT_SERVICE = 256,
@@ -4925,6 +4941,12 @@ struct wmi_obss_spatial_reuse_params_cmd {
__le32 vdev_id;
} __packed;
+struct wmi_pdev_obss_pd_bitmap_cmd {
+ __le32 tlv_header;
+ __le32 pdev_id;
+ __le32 bitmap[2];
+} __packed;
+
#define ATH12K_BSS_COLOR_COLLISION_SCAN_PERIOD_MS 200
#define ATH12K_OBSS_COLOR_COLLISION_DETECTION_DISABLE 0
#define ATH12K_OBSS_COLOR_COLLISION_DETECTION 1
@@ -6329,6 +6351,18 @@ struct ath12k_wmi_rssi_dbm_conv_info_arg {
/* each WMI cmd can hold 58 channel entries at most */
#define ATH12K_WMI_MAX_NUM_CHAN_PER_CMD 58
+#define ATH12K_OBSS_PD_THRESHOLD_IN_DBM BIT(29)
+#define ATH12K_OBSS_PD_SRG_EN BIT(30)
+#define ATH12K_OBSS_PD_NON_SRG_EN BIT(31)
+
+struct ath12k_wmi_obss_pd_arg {
+ bool srp_support;
+ bool srg_enabled;
+ bool non_srg_enabled;
+ s8 srg_th;
+ s8 non_srg_th;
+};
+
int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,
u32 cmd_id);
struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len);
@@ -6432,6 +6466,19 @@ int ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id);
int ath12k_wmi_send_twt_disable_cmd(struct ath12k *ar, u32 pdev_id);
int ath12k_wmi_send_obss_spr_cmd(struct ath12k *ar, u32 vdev_id,
struct ieee80211_he_obss_pd *he_obss_pd);
+u32 ath12k_wmi_build_obss_pd(const struct ath12k_wmi_obss_pd_arg *arg);
+int ath12k_wmi_pdev_set_srg_bss_color_bitmap(struct ath12k *ar, u32 pdev_id,
+ const u32 *bitmap);
+int ath12k_wmi_pdev_set_srg_partial_bssid_bitmap(struct ath12k *ar, u32 pdev_id,
+ const u32 *bitmap);
+int ath12k_wmi_pdev_srg_obss_color_enable_bitmap(struct ath12k *ar, u32 pdev_id,
+ const u32 *bitmap);
+int ath12k_wmi_pdev_srg_obss_bssid_enable_bitmap(struct ath12k *ar, u32 pdev_id,
+ const u32 *bitmap);
+int ath12k_wmi_pdev_non_srg_obss_color_enable_bitmap(struct ath12k *ar, u32 pdev_id,
+ const u32 *bitmap);
+int ath12k_wmi_pdev_non_srg_obss_bssid_enable_bitmap(struct ath12k *ar, u32 pdev_id,
+ const u32 *bitmap);
int ath12k_wmi_obss_color_cfg_cmd(struct ath12k *ar, u32 vdev_id,
u8 bss_color, u32 period,
bool enable);