From quic_lingbok at quicinc.com  Mon Sep  4 19:49:00 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Tue, 5 Sep 2023 10:49:00 +0800
Subject: [PATCH 0/4] wifi: ath12k: implement some functionalities through reading ACPI Table
Message-ID: <20230905024904.3882-1-quic_lingbok@quicinc.com>

Through reading ACPI table, implement Time-Average-SAR(TAS), BIOS SAR,
configuration of CCA threshold and band edge channel power functionalities.

Lingbo Kong (4):
  wifi: ath12k: add TAS capability for WCN7850
  wifi: ath12k: add BIOS SAR capability for WCN7850
  wifi: ath12k: adjust configuration of CCA threshold value
  wifi: ath12k: add band edge channel power for WCN7850

 drivers/net/wireless/ath/ath12k/Makefile |   3 +-
 drivers/net/wireless/ath/ath12k/acpi.c   | 365 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h   |  55 ++++
 drivers/net/wireless/ath/ath12k/core.c   |   6 +
 drivers/net/wireless/ath/ath12k/core.h   |  13 +
 drivers/net/wireless/ath/ath12k/hw.c     |  10 +
 drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
 drivers/net/wireless/ath/ath12k/pci.c    |   6 +
 drivers/net/wireless/ath/ath12k/wmi.c    | 258 ++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h    |  47 ++-
 10 files changed, 764 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h


base-commit: 4d4739971f44150b3dcb75f188a1a3cbc22889a3
-- 
2.34.1



From quic_lingbok at quicinc.com  Mon Sep  4 19:49:01 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Tue, 5 Sep 2023 10:49:01 +0800
Subject: [PATCH 1/4] wifi: ath12k: add TAS capability for WCN7850
In-Reply-To: <20230905024904.3882-1-quic_lingbok@quicinc.com>
References: <20230905024904.3882-1-quic_lingbok@quicinc.com>
Message-ID: <20230905024904.3882-2-quic_lingbok@quicinc.com>

In order to enable Time-Average-SAR(TAS) for WCN7850, define some
functions. One function is to return TAS configuration, the other return
SAR power table, then ath12k apply these data to wlan firmware. ath12k
register an ACPI event callback so that ACPI can notify ath12k to retrieve
the updated SAR power table and apply it to wlan firmware.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/Makefile |   3 +-
 drivers/net/wireless/ath/ath12k/acpi.c   | 203 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h   |  28 ++++
 drivers/net/wireless/ath/ath12k/core.c   |   6 +
 drivers/net/wireless/ath/ath12k/core.h   |   8 +
 drivers/net/wireless/ath/ath12k/hw.c     |  10 ++
 drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
 drivers/net/wireless/ath/ath12k/pci.c    |   6 +
 drivers/net/wireless/ath/ath12k/wmi.c    |  82 +++++++++
 drivers/net/wireless/ath/ath12k/wmi.h    |  20 ++-
 10 files changed, 367 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h

diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile
index 62c52e733b5e..a479fe06caac 100644
--- a/drivers/net/wireless/ath/ath12k/Makefile
+++ b/drivers/net/wireless/ath/ath12k/Makefile
@@ -19,7 +19,8 @@ ath12k-y += core.o \
 	    hw.o \
 	    mhi.o \
 	    pci.o \
-	    dp_mon.o
+	    dp_mon.o \
+	    acpi.o
 
 ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
 
diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
new file mode 100644
index 000000000000..384e01748b32
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -0,0 +1,203 @@
+// 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.
+ */
+
+#include "core.h"
+#include "acpi.h"
+#include "debug.h"
+
+static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
+{
+	union acpi_object *obj;
+	acpi_handle root_handle;
+	int ret = 0;
+
+	root_handle = ACPI_HANDLE(ab->dev);
+	if (!root_handle) {
+		ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid ACPI handler\n");
+		return -EOPNOTSUPP;
+	}
+
+	obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,
+				NULL);
+
+	if (!obj) {
+		ath12k_dbg(ab, ATH12K_DBG_BOOT, "ACPI _DSM method invocation failed\n");
+		return -ENOENT;
+	}
+
+	if (obj->type == ACPI_TYPE_INTEGER) {
+		ab->acdata->func_bit = obj->integer.value;
+	} else if (obj->type == ACPI_TYPE_BUFFER) {
+		switch (func) {
+		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
+				ath12k_err(ab, "Invalid TAS cfg size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->tas_cfg, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {
+				ath12k_err(ab, "Invalid TAS data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		}
+	} else {
+		ath12k_err(ab,
+			   "ACPI: DSM method did not return a valid object, type %d\n",
+			   obj->type);
+		ret = -EINVAL;
+	}
+
+out:
+	ACPI_FREE(obj);
+	return ret;
+}
+
+static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
+{
+	int ret;
+
+	if (ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
+	    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG) {
+		ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
+							       ab->acdata->tas_sar_power_table);
+		if (ret)
+			ath12k_err(ab, "failed to pass tas data table %d\n", ret);
+	} else {
+		ath12k_err(ab, "the latest tas data is invalid\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
+{
+	int ret;
+	struct ath12k_base *ab = data;
+
+	if (event == ATH12K_ACPI_NOTIFY_EVENT) {
+		if (ab->acdata->acpi_tas_enable) {
+			ret = ath12k_acpi_dsm_get_data(ab,
+						       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
+			if (ret) {
+				ath12k_err(ab, "failed to update tas data table %d\n", ret);
+				return;
+			}
+
+			ret = ath12k_set_tas_power_limit_data(ab);
+			if (ret)
+				return;
+		}
+	} else {
+		ath12k_err(ab, "unknown acpi notify %u\n", event);
+	}
+}
+
+void ath12k_acpi_remove_notify(struct ath12k_base *ab)
+{
+	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+				   ACPI_DEVICE_NOTIFY,
+				   acpi_dsm_notify);
+}
+
+static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
+{
+	int ret;
+
+	ret = ath12k_wmi_pdev_set_tas_cfg_table_param(ab,
+						      ab->acdata->tas_cfg);
+	if (ret) {
+		ath12k_err(ab, "failed to pass tas cfg table to fw %d\n", ret);
+		return ret;
+	}
+
+	ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
+						       ab->acdata->tas_sar_power_table);
+	if (ret)
+		ath12k_err(ab, "failed to pass tas data table to fw %d\n", ret);
+
+	return ret;
+}
+
+int ath12k_get_acpi_all_data(struct ath12k_base *ab)
+{
+	int ret;
+	acpi_status status;
+
+	ab->acdata = kzalloc(sizeof(*ab->acdata), GFP_KERNEL);
+	if (!ab->acdata)
+		return -ENOMEM;
+
+	ab->acdata->acpi_tas_enable = false;
+
+	ret = ath12k_acpi_dsm_get_data(ab,
+				       ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS);
+
+	if (ret)
+		return ret;
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG);
+		if (ret) {
+			ath12k_err(ab, "failed to get tas cfg table %d\n", ret);
+			goto err_free_acdata;
+		}
+	}
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
+		if (ret) {
+			ath12k_err(ab, "failed to get tas data table %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&
+		    ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
+		    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG)
+			ab->acdata->acpi_tas_enable = true;
+	}
+
+	if (ab->acdata->acpi_tas_enable) {
+		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
+		if (ret)
+			goto err_free_acdata;
+	}
+
+	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
+					     ACPI_DEVICE_NOTIFY,
+					     acpi_dsm_notify, ab);
+	if (ACPI_FAILURE(status)) {
+		ath12k_err(ab, "failed to install DSM notify callback\n");
+		goto err_remove_notify;
+	}
+
+	return 0;
+
+err_remove_notify:
+	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+				   ACPI_DEVICE_NOTIFY,
+				   acpi_dsm_notify);
+
+	ret = -EIO;
+
+err_free_acdata:
+	kfree(ab->acdata);
+	ab->acdata = NULL;
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
new file mode 100644
index 000000000000..cf742958a623
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -0,0 +1,28 @@
+/* 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.
+ */
+#include <linux/acpi.h>
+
+#ifndef ATH12K_ACPI_H
+#define ATH12K_ACPI_H
+
+#define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
+#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
+#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
+
+#define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
+#define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
+#define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
+#define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
+
+#define ATH12K_ACPI_NOTIFY_EVENT			0x86
+#define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
+
+#define ATH12K_ACPI_TAS_DATA_VERSION		0x1
+#define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
+
+int ath12k_get_acpi_all_data(struct ath12k_base *ab);
+void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
+#endif
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 3df8059d5512..7d876660a351 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -538,6 +538,12 @@ static int ath12k_core_start(struct ath12k_base *ab,
 		goto err_reo_cleanup;
 	}
 
+	if (!guid_is_null(ab->hw_params->acpi_guid)) {
+		ret = ath12k_get_acpi_all_data(ab);
+		if (!ret)
+			ath12k_info(ab, "success to get acpi cfg data\n");
+	}
+
 	return 0;
 
 err_reo_cleanup:
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d873b573dac6..cba4f176c018 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -22,6 +22,7 @@
 #include "hal_rx.h"
 #include "reg.h"
 #include "dbring.h"
+#include "acpi.h"
 
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
 
@@ -771,6 +772,13 @@ struct ath12k_base {
 	u64 fw_soc_drop_count;
 	bool static_window_map;
 
+	struct {
+		u32 func_bit;
+		bool acpi_tas_enable;
+		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
+		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
+	} *acdata;
+
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 5991cc91cd00..f0f7f9dbb08a 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -15,6 +15,10 @@
 #include "mhi.h"
 #include "dp_rx.h"
 
+static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec,
+					     0x90, 0xd6, 0x02, 0x42,
+					     0xac, 0x12, 0x00, 0x03);
+
 static u8 ath12k_hw_qcn9274_mac_from_pdev_id(int pdev_idx)
 {
 	return pdev_idx;
@@ -907,6 +911,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.acpi_guid = NULL,
 	},
 	{
 		.name = "wcn7850 hw2.0",
@@ -964,6 +970,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
 					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
+
+		.acpi_guid = &wcn7850_uuid,
 	},
 	{
 		.name = "qcn9274 hw2.0",
@@ -1019,6 +1027,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.acpi_guid = NULL,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e6c4223c283c..ab409e8ae268 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -8,7 +8,7 @@
 #define ATH12K_HW_H
 
 #include <linux/mhi.h>
-
+#include <linux/uuid.h>
 #include "wmi.h"
 #include "hal.h"
 
@@ -186,6 +186,8 @@ struct ath12k_hw_params {
 	const struct hal_ops *hal_ops;
 
 	u64 qmi_cnss_feature_bitmap;
+
+	const guid_t *acpi_guid;
 };
 
 struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index bd689efa7daa..3c2967e760ab 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1340,6 +1340,12 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
 
 	ath12k_hal_srng_deinit(ab);
 	ath12k_ce_free_pipes(ab);
+	if (!guid_is_null(ab->hw_params->acpi_guid) && ab->acdata) {
+		acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+					   ACPI_DEVICE_NOTIFY,
+					   acpi_dsm_notify);
+		kfree(ab->acdata);
+	}
 	ath12k_core_free(ab);
 }
 
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index ef0f3cf35cfd..2d501993b197 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6896,3 +6896,85 @@ void ath12k_wmi_detach(struct ath12k_base *ab)
 
 	ath12k_wmi_free_dbring_caps(ab);
 }
+
+int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
+					    const u8 *ptas_cfg)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+	int ret;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_CFG_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_CONFIG_TYPE);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_CFG_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, ptas_cfg, ATH12K_ACPI_DSM_TAS_CFG_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
+					     const u8 *ptas_data)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+	int ret;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_DATA_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_DATA_TYPE);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_DATA_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, ptas_data, ATH12K_ACPI_DSM_TAS_DATA_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c75a6fa1f7e0..38bbf59fc6b7 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -361,6 +361,7 @@ 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_BIOS_INTERFACE_CMDID = 0x404A,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
 	WMI_VDEV_START_REQUEST_CMDID,
@@ -1931,6 +1932,7 @@ enum wmi_tlv_tag {
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
 	WMI_TAG_EHT_RATE_SET = 0x3C4,
+	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
 	WMI_TAG_MAX
 };
 
@@ -4791,6 +4793,19 @@ struct ath12k_wmi_base {
 	struct ath12k_wmi_target_cap_arg *targ_cap;
 };
 
+struct wmi_pdev_set_bios_interface_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 param_type_id;
+	__le32 length;
+} __packed;
+
+enum bios_param_type {
+	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
+	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
+	WMI_BIOS_PARAM_TYPE_MAX,
+};
+
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
@@ -4912,5 +4927,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
 			       struct sk_buff *tmpl);
 int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
 			   enum wmi_host_hw_mode_config_type mode);
-
+int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
+					    const u8 *ptas_cfg);
+int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
+					     const u8 *ptas_data);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Mon Sep  4 19:49:02 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Tue, 5 Sep 2023 10:49:02 +0800
Subject: [PATCH 2/4] wifi: ath12k: add BIOS SAR capability for WCN7850
In-Reply-To: <20230905024904.3882-1-quic_lingbok@quicinc.com>
References: <20230905024904.3882-1-quic_lingbok@quicinc.com>
Message-ID: <20230905024904.3882-3-quic_lingbok@quicinc.com>

ath12k get the latest BIOS SAR power table by using ACPI _DSM method, then
pass this table to the firmware.ath12k register a notification callback for
ACPI event so ACPI can notify ath12k to get the latest BIOS SAR table.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/acpi.c | 103 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  15 ++++
 drivers/net/wireless/ath/ath12k/core.h |   3 +
 drivers/net/wireless/ath/ath12k/wmi.c  |  94 ++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  21 +++++
 5 files changed, 236 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index 384e01748b32..ae1ce7b99d2d 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -52,6 +52,26 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
+				ath12k_err(ab, "Invalid BIOS SAR data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->bios_sar_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
+				ath12k_err(ab, "Invalid GEO OFFSET data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -83,6 +103,24 @@ static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
 	return ret;
 }
 
+static int ath12k_set_bios_sar_power_limit_data(struct ath12k_base *ab)
+{
+	int ret;
+
+	if (ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
+	    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
+		ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
+							       ab->acdata->bios_sar_data);
+		if (ret)
+			ath12k_err(ab, "failed to pass bios sar table %d\n", ret);
+	} else {
+		ath12k_err(ab, "the latest bios sar data is invalid\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
 {
 	int ret;
@@ -101,6 +139,20 @@ void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
 			if (ret)
 				return;
 		}
+
+		if (ab->acdata->acpi_bios_sar_enable) {
+			ret = ath12k_acpi_dsm_get_data(ab,
+						       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
+			if (ret) {
+				ath12k_err(ab, "failed to update bios sar %d\n", ret);
+				return;
+			}
+
+			ret = ath12k_set_bios_sar_power_limit_data(ab);
+			if (ret)
+				return;
+		}
+
 	} else {
 		ath12k_err(ab, "unknown acpi notify %u\n", event);
 	}
@@ -113,6 +165,27 @@ void ath12k_acpi_remove_notify(struct ath12k_base *ab)
 				   acpi_dsm_notify);
 }
 
+static int ath12k_pass_acpi_bios_sar_and_geo_to_fw(struct ath12k_base *ab)
+{
+	int ret;
+
+	ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
+						       ab->acdata->bios_sar_data);
+
+	if (ret) {
+		ath12k_err(ab, "failed to pass bios sar table to fw %d\n", ret);
+		return ret;
+	}
+
+	ret = ath12k_wmi_pdev_set_bios_geo_table_param(ab,
+						       ab->acdata->geo_offset_data);
+
+	if (ret)
+		ath12k_err(ab, "failed to pass bios geo table to fw %d\n", ret);
+
+	return ret;
+}
+
 static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
 {
 	int ret;
@@ -172,12 +245,42 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 			ab->acdata->acpi_tas_enable = true;
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
+		if (ret) {
+			ath12k_err(ab, "failed to get bios sar data %d\n", ret);
+			goto err_free_acdata;
+		}
+	}
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET);
+		if (ret) {
+			ath12k_err(ab, "failed to get geo offset data %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
+		    ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
+		    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
+		    !ab->acdata->acpi_tas_enable)
+			ab->acdata->acpi_bios_sar_enable = true;
+	}
+
 	if (ab->acdata->acpi_tas_enable) {
 		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
 		if (ret)
 			goto err_free_acdata;
 	}
 
+	if (ab->acdata->acpi_bios_sar_enable) {
+		ret = ath12k_pass_acpi_bios_sar_and_geo_to_fw(ab);
+		if (ret)
+			goto err_free_acdata;
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index cf742958a623..59f87cb258c6 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -11,9 +11,16 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
+#define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
+#define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5
 
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
+#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
+#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
+
+#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
+#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
 
@@ -22,6 +29,14 @@
 
 #define ATH12K_ACPI_TAS_DATA_VERSION		0x1
 #define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
+#define ATH12K_ACPI_BIOS_SAR_TABLE_LEN		22
+#define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN	10
+#define ATH12K_ACPI_POWER_LIMIT_DATAOFFSET	12
+#define ATH12K_ACPI_DBS_BACKOFF_DATAOFFSET	2
+#define ATH12K_ACPI_POWER_LIMIT_VERSION		0x1
+#define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
+#define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
+#define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
 
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index cba4f176c018..6fe4f0ddee4a 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -775,8 +775,11 @@ struct ath12k_base {
 	struct {
 		u32 func_bit;
 		bool acpi_tas_enable;
+		bool acpi_bios_sar_enable;
 		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
 		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
+		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
+		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 2d501993b197..f090ccea5f64 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6978,3 +6978,97 @@ int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
 
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
+					     u8 *psar_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_sar_table_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, sar_table_len_aligned, sar_dbs_backoff_len_aligned;
+	u8 *psar_value = psar_table + ATH12K_ACPI_POWER_LIMIT_DATAOFFSET;
+	u8 *pdbs_value = psar_table + ATH12K_ACPI_DBS_BACKOFF_DATAOFFSET;
+
+	sar_table_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_TABLE_LEN, sizeof(u32));
+	sar_dbs_backoff_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_table_len_aligned +
+		TLV_HDR_SIZE + sar_dbs_backoff_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_sar_table_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->sar_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
+	cmd->dbs_backoff_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
+					 sar_table_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, psar_value, ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
+
+	buf_ptr += sar_table_len_aligned;
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
+					 sar_dbs_backoff_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pdbs_value, ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
+					     u8 *pgeo_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_geo_table_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, sar_geo_len_aligned;
+	u8 *pgeo_value = pgeo_table + ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET;
+
+	sar_geo_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_geo_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_geo_table_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->geo_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, sar_geo_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pgeo_value, ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 38bbf59fc6b7..8a774655fe9f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -361,6 +361,8 @@ 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_BIOS_SAR_TABLE_CMDID = 0x4044,
+	WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045,
 	WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
@@ -1932,6 +1934,8 @@ enum wmi_tlv_tag {
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
 	WMI_TAG_EHT_RATE_SET = 0x3C4,
+	WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS = 0x3D8,
+	WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS = 0x3D9,
 	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
 	WMI_TAG_MAX
 };
@@ -4806,6 +4810,19 @@ enum bios_param_type {
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
+struct wmi_pdev_set_bios_sar_table_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 sar_len;
+	__le32 dbs_backoff_len;
+} __packed;
+
+struct wmi_pdev_set_bios_geo_table_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 geo_len;
+} __packed;
+
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
@@ -4931,4 +4948,8 @@ int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
 					    const u8 *ptas_cfg);
 int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
 					     const u8 *ptas_data);
+int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
+					     u8 *psar_table);
+int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
+					     u8 *pgeo_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Mon Sep  4 19:49:04 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Tue, 5 Sep 2023 10:49:04 +0800
Subject: [PATCH 4/4] wifi: ath12k: add band edge channel power for WCN7850
In-Reply-To: <20230905024904.3882-1-quic_lingbok@quicinc.com>
References: <20230905024904.3882-1-quic_lingbok@quicinc.com>
Message-ID: <20230905024904.3882-5-quic_lingbok@quicinc.com>

ath12k need to retrieve band edge channel power table by invoking ACPI _DSM
method, then pass the table to firmware.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/acpi.c | 29 ++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  6 +++-
 drivers/net/wireless/ath/ath12k/core.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 41 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  3 ++
 5 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index a9931e17bd17..389b900df170 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -82,6 +82,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {
+				ath12k_err(ab, "Invalid BAND EDGE data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->band_edge_power, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -311,6 +321,25 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 		}
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);
+		if (ret) {
+			ath12k_err(ab, "failed to get band edge channel power %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ab->acdata->band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
+		    ab->acdata->band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {
+			ret = ath12k_wmi_pdev_set_band_edge_power(ab,
+								  ab->acdata->band_edge_power);
+			if (ret) {
+				ath12k_err(ab, "set band edge channel power failed %d\n", ret);
+				goto err_free_acdata;
+			}
+		}
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index acdf8d851fba..1acfd7696dfc 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -14,18 +14,21 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
 #define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5
 #define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
+#define ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE		10
 
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
 #define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
 #define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
 #define ATH12K_ACPI_DSM_CCA_DATA_SIZE			41
+#define ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE		100
 
 #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
 #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
 #define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
+#define ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER	BIT(9)
 
 #define ATH12K_ACPI_NOTIFY_EVENT			0x86
 #define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
@@ -44,7 +47,8 @@
 #define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
 #define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
 #define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET	5
-
+#define ATH12K_ACPI_BAND_EDGE_VERSION		0x1
+#define ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG	0x1
 
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d57e2013b0fe..d06c3984aef9 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -781,6 +781,7 @@ struct ath12k_base {
 		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
 		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
 		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
+		u8 band_edge_power[ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 3f66807b7961..345bdd50adb2 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7113,3 +7113,44 @@ int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
 	}
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
+					const u8 *pchan_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pchan_table, ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 7607cd7ab699..73d790d405cd 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4808,6 +4808,7 @@ enum bios_param_type {
 	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
 	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
 	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
+	WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER	=	3,
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
@@ -4955,4 +4956,6 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 					     u8 *pgeo_table);
 int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
 					    u8 *pcca_table);
+int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
+					const u8 *pchan_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Mon Sep  4 19:49:03 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Tue, 5 Sep 2023 10:49:03 +0800
Subject: [PATCH 3/4] wifi: ath12k: adjust configuration of CCA threshold value
In-Reply-To: <20230905024904.3882-1-quic_lingbok@quicinc.com>
References: <20230905024904.3882-1-quic_lingbok@quicinc.com>
Message-ID: <20230905024904.3882-4-quic_lingbok@quicinc.com>

ath12k need to adjust CCA threshold values to meet the regulatory
requirement. ath12k can retrieve CCA threshold configuration by invoking
ACPI _DSM method.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/acpi.c | 30 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  8 +++++
 drivers/net/wireless/ath/ath12k/core.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 41 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  7 +++--
 5 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index ae1ce7b99d2d..a9931e17bd17 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -72,6 +72,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {
+				ath12k_err(ab, "Invalid CCA data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -281,6 +291,26 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 			goto err_free_acdata;
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_CCA)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
+		if (ret) {
+			ath12k_err(ab, "failed to get cca threshold configuration %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ab->acdata->cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
+		    ab->acdata->cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
+		    ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {
+			ret = ath12k_wmi_pdev_set_cca_thr_table_param(ab,
+								      ab->acdata->cca_data);
+			if (ret) {
+				ath12k_err(ab, "set cca threshold failed %d\n", ret);
+				goto err_free_acdata;
+			}
+		}
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index 59f87cb258c6..acdf8d851fba 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -13,14 +13,17 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
 #define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
 #define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5
+#define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
 
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
 #define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
 #define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
+#define ATH12K_ACPI_DSM_CCA_DATA_SIZE			41
 
 #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
 #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
+#define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
 
@@ -37,6 +40,11 @@
 #define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
 #define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
 #define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
+#define ATH12K_ACPI_CCA_THR_VERSION		0x1
+#define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
+#define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
+#define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET	5
+
 
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 6fe4f0ddee4a..d57e2013b0fe 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -780,6 +780,7 @@ struct ath12k_base {
 		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
 		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
 		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
+		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index f090ccea5f64..3f66807b7961 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7072,3 +7072,44 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
+					    u8 *pcca_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, cca_thr_len_aligned;
+	u8 *pcca_value = pcca_table + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
+
+	cca_thr_len_aligned = roundup(ATH12K_ACPI_CCA_THR_OFFSET_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + cca_thr_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE);
+	cmd->length = ATH12K_ACPI_CCA_THR_OFFSET_LEN;
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, cca_thr_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pcca_value, ATH12K_ACPI_CCA_THR_OFFSET_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 8a774655fe9f..7607cd7ab699 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4805,8 +4805,9 @@ struct wmi_pdev_set_bios_interface_cmd {
 } __packed;
 
 enum bios_param_type {
-	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
-	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
+	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
+	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
+	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
@@ -4952,4 +4953,6 @@ int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
 					     u8 *psar_table);
 int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 					     u8 *pgeo_table);
+int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
+					    u8 *pcca_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Tue Sep  5 02:27:20 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Tue, 5 Sep 2023 17:27:20 +0800
Subject: [PATCH] wifi: ath12k: add support for hardware rfkill for WCN7850
Message-ID: <20230905092720.3533-1-quic_lingbok@quicinc.com>

When hardware rfkill is enabled in the firmware, it will report the
capability via using WMI_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY
event to the host. ath12k will check the capability if it is enabled then
ath12k will set the GPIO information to firmware using WMI_PDEV_SET_PARAM.
When the firmware detects hardware rfkill is enabled by the user, it will
report it via WMI_RFKILL_STATE_CHANGE_EVENTID. Once ath12k receive the
event it will send wmi command WMI_PDEV_SET_PARAM to the firmware and
also notify cfg80211.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c | 52 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/core.h |  4 ++
 drivers/net/wireless/ath/ath12k/hw.c   | 12 ++++++
 drivers/net/wireless/ath/ath12k/hw.h   |  4 ++
 drivers/net/wireless/ath/ath12k/mac.c  | 58 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/mac.h  |  2 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 39 +++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  | 25 +++++++++++
 8 files changed, 196 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 3df8059d5512..cae1ab9982cd 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -19,6 +19,27 @@ unsigned int ath12k_debug_mask;
 module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
 
+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;
+
+	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;
+}
+
 int ath12k_core_suspend(struct ath12k_base *ab)
 {
 	int ret;
@@ -603,6 +624,13 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
 		goto err_core_stop;
 	}
 	ath12k_hif_irq_enable(ab);
+
+	ret = ath12k_core_rfkill_config(ab);
+	if (ret && ret != -EOPNOTSUPP) {
+		ath12k_err(ab, "failed to config rfkill: %d\n", ret);
+		goto err_core_stop;
+	}
+
 	mutex_unlock(&ab->core_lock);
 
 	return 0;
@@ -655,6 +683,27 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab)
 	return ret;
 }
 
+static void ath12k_rfkill_work(struct work_struct *work)
+{
+	struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work);
+	struct ath12k *ar;
+	bool rfkill_radio_on;
+	int i;
+
+	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)
+			continue;
+
+		ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on);
+		wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on);
+	}
+}
+
 void ath12k_core_halt(struct ath12k *ar)
 {
 	struct ath12k_base *ab = ar->ab;
@@ -668,6 +717,7 @@ void ath12k_core_halt(struct ath12k *ar)
 	ath12k_mac_peer_cleanup_all(ar);
 	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->regd_update_work);
+	cancel_work_sync(&ab->rfkill_work);
 
 	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
 	synchronize_rcu();
@@ -922,6 +972,8 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 	init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
 	INIT_WORK(&ab->restart_work, ath12k_core_restart);
 	INIT_WORK(&ab->reset_work, ath12k_core_reset);
+	INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work);
+
 	timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
 	init_completion(&ab->htc_suspend);
 
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d873b573dac6..3f5f0471f640 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -771,6 +771,10 @@ struct ath12k_base {
 	u64 fw_soc_drop_count;
 	bool static_window_map;
 
+	struct work_struct rfkill_work;
+	/* true means radio is on */
+	bool rfkill_radio_on;
+
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 5991cc91cd00..f69649f58e82 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -907,6 +907,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.rfkill_pin = 0,
+		.rfkill_cfg = 0,
+		.rfkill_on_level = 0,
 	},
 	{
 		.name = "wcn7850 hw2.0",
@@ -964,6 +968,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
 					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
+
+		.rfkill_pin = 48,
+		.rfkill_cfg = 0,
+		.rfkill_on_level = 1,
 	},
 	{
 		.name = "qcn9274 hw2.0",
@@ -1019,6 +1027,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.rfkill_pin = 0,
+		.rfkill_cfg = 0,
+		.rfkill_on_level = 0,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e6c4223c283c..1b4912bf57ad 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -186,6 +186,10 @@ struct ath12k_hw_params {
 	const struct hal_ops *hal_ops;
 
 	u64 qmi_cnss_feature_bitmap;
+
+	u32 rfkill_pin;
+	u32 rfkill_cfg;
+	u32 rfkill_on_level;
 };
 
 struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 85602d64b607..486d062b0a76 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5108,6 +5108,63 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
 	return ret;
 }
 
+int ath12k_mac_rfkill_config(struct ath12k *ar)
+{
+	struct ath12k_base *ab = ar->ab;
+	u32 param;
+	int ret;
+
+	if (ab->hw_params->rfkill_pin == 0)
+		return -EOPNOTSUPP;
+
+	ath12k_dbg(ab, ATH12K_DBG_MAC,
+		   "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d",
+		   ab->hw_params->rfkill_pin, ab->hw_params->rfkill_cfg,
+		   ab->hw_params->rfkill_on_level);
+
+	param = u32_encode_bits(ab->hw_params->rfkill_on_level,
+				WMI_RFKILL_CFG_RADIO_LEVEL) |
+		u32_encode_bits(ab->hw_params->rfkill_pin,
+				WMI_RFKILL_CFG_GPIO_PIN_NUM) |
+		u32_encode_bits(ab->hw_params->rfkill_cfg,
+				WMI_RFKILL_CFG_PIN_AS_GPIO);
+
+	ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_HW_RFKILL_CONFIG,
+					param, ar->pdev->pdev_id);
+	if (ret) {
+		ath12k_warn(ab,
+			    "failed to set rfkill config 0x%x: %d\n",
+			    param, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable)
+{
+	enum wmi_rfkill_enable_radio param;
+	int ret;
+
+	if (enable)
+		param = WMI_RFKILL_ENABLE_RADIO_ON;
+	else
+		param = WMI_RFKILL_ENABLE_RADIO_OFF;
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac %d rfkill enable %d",
+		   ar->pdev_idx, param);
+
+	ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RFKILL_ENABLE,
+					param, ar->pdev->pdev_id);
+	if (ret) {
+		ath12k_warn(ar->ab, "failed to set rfkill enable param %d: %d\n",
+			    param, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
 {
 	struct ath12k *ar = hw->priv;
@@ -5128,6 +5185,7 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
 
 	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->regd_update_work);
+	cancel_work_sync(&ar->ab->rfkill_work);
 
 	spin_lock_bh(&ar->data_lock);
 	list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 7b16b70df4fa..59b4e8f5eee0 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -73,4 +73,6 @@ int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
 enum rate_info_bw ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw);
 enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw bw);
 enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher);
+int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
+int ath12k_mac_rfkill_config(struct ath12k *ar);
 #endif
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index ef0f3cf35cfd..4ac05cd7a1a5 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -152,6 +152,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
 		.min_len = sizeof(struct wmi_service_available_event) },
 	[WMI_TAG_PEER_ASSOC_CONF_EVENT] = {
 		.min_len = sizeof(struct wmi_peer_assoc_conf_event) },
+	[WMI_TAG_RFKILL_EVENT] = {
+		.min_len = sizeof(struct wmi_rfkill_state_change_event) },
 	[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] = {
 		.min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },
 	[WMI_TAG_HOST_SWFDA_EVENT] = {
@@ -6580,6 +6582,40 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
 	kfree(tb);
 }
 
+static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
+					     struct sk_buff *skb)
+{
+	const struct wmi_rfkill_state_change_event *ev;
+	const void **tb;
+	int ret;
+
+	tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
+		return;
+	}
+
+	ev = tb[WMI_TAG_RFKILL_EVENT];
+	if (!ev) {
+		kfree(tb);
+		return;
+	}
+
+	ath12k_dbg(ab, ATH12K_DBG_MAC,
+		   "wmi tlv rfkill state change gpio %d type %d radio_state %d\n",
+		   le32_to_cpu(ev->gpio_pin_num),
+		   le32_to_cpu(ev->int_type),
+		   le32_to_cpu(ev->radio_state));
+
+	spin_lock_bh(&ab->base_lock);
+	ab->rfkill_radio_on = (le32_to_cpu(ev->radio_state) == WMI_RFKILL_RADIO_STATE_ON);
+	spin_unlock_bh(&ab->base_lock);
+
+	queue_work(ab->workqueue, &ab->rfkill_work);
+	kfree(tb);
+}
+
 static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
 {
 	struct wmi_cmd_hdr *cmd_hdr;
@@ -6672,6 +6708,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
 	case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID:
 		ath12k_probe_resp_tx_status_event(ab, skb);
 		break;
+	case WMI_RFKILL_STATE_CHANGE_EVENTID:
+		ath12k_rfkill_state_change_event(ab, skb);
+		break;
 	/* add Unsupported events here */
 	case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
 	case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c75a6fa1f7e0..965755b4cbfd 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4793,6 +4793,31 @@ struct ath12k_wmi_base {
 
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
+enum wmi_sys_cap_info_flags {
+	WMI_SYS_CAP_INFO_RXTX_LED	= BIT(0),
+	WMI_SYS_CAP_INFO_RFKILL		= BIT(1),
+};
+
+#define WMI_RFKILL_CFG_GPIO_PIN_NUM		GENMASK(5, 0)
+#define WMI_RFKILL_CFG_RADIO_LEVEL		BIT(6)
+#define WMI_RFKILL_CFG_PIN_AS_GPIO		GENMASK(10, 7)
+
+enum wmi_rfkill_enable_radio {
+	WMI_RFKILL_ENABLE_RADIO_ON	= 0,
+	WMI_RFKILL_ENABLE_RADIO_OFF	= 1,
+};
+
+enum wmi_rfkill_radio_state {
+	WMI_RFKILL_RADIO_STATE_OFF	= 1,
+	WMI_RFKILL_RADIO_STATE_ON	= 2,
+};
+
+struct wmi_rfkill_state_change_event {
+	__le32 gpio_pin_num;
+	__le32 int_type;
+	__le32 radio_state;
+} __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,

base-commit: 4d4739971f44150b3dcb75f188a1a3cbc22889a3
-- 
2.34.1



From quic_wgong at quicinc.com  Tue Sep  5 03:52:29 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Tue, 5 Sep 2023 06:52:29 -0400
Subject: [PATCH] wifi: ath12k: fix recovery fail while firmware crash when doing channel switch
Message-ID: <20230905105229.10090-1-quic_wgong@quicinc.com>

When firmware crashed while channel switch running, recovery starts in
ath12k. Then ieee80211_sta_connection_lost() will be called by function
ieee80211_restart_work() in mac80211. And then many WMI command timeout
because firmware is crashed. Each WMI command cost 3 seconds, then the
total time will be large and leads recovery fail.

Hence change to set value ATH12K_FLAG_CRASH_FLUSH early and then
ath12k_wmi_cmd_send() will not wait 3 seconds, then recovery will be
started quickly and success.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 3df8059d5512..56be7298ac86 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -685,6 +685,9 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
 	ab->stats.fw_crash_counter++;
 	spin_unlock_bh(&ab->base_lock);
 
+	if (ab->is_reset)
+		set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags);
+
 	for (i = 0; i < ab->num_radios; i++) {
 		pdev = &ab->pdevs[i];
 		ar = pdev->ar;

base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_wgong at quicinc.com  Tue Sep  5 03:56:37 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Tue, 5 Sep 2023 06:56:37 -0400
Subject: [PATCH] wifi: ath12k: add read variant from SMBIOS for download board data
Message-ID: <20230905105637.10230-1-quic_wgong@quicinc.com>

This is to read variant from SMBIOS such as read from DT, the variant
string will be used to one part of string which used to search board
data from board-2.bin.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c | 69 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/core.h | 20 +++++++-
 drivers/net/wireless/ath/ath12k/qmi.c  |  5 ++
 3 files changed, 93 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 3df8059d5512..6350e2cf71ee 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -377,6 +377,75 @@ static void ath12k_core_stop(struct ath12k_base *ab)
 	/* De-Init of components as needed */
 }
 
+static void ath12k_core_check_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;
+	}
+
+	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;
+	}
+
+	ath12k_dbg(ab, ATH12K_DBG_BOOT,
+		   "found and validated bdf variant smbios_type 0x%x bdf %s\n",
+		   ATH12K_SMBIOS_BDF_EXT_TYPE, ab->qmi.target.bdf_ext);
+}
+
+int ath12k_core_check_smbios(struct ath12k_base *ab)
+{
+	ab->qmi.target.bdf_ext[0] = '\0';
+	dmi_walk(ath12k_core_check_bdfext, ab);
+
+	if (ab->qmi.target.bdf_ext[0] == '\0')
+		return -ENODATA;
+
+	return 0;
+}
+
 static int ath12k_core_soc_create(struct ath12k_base *ab)
 {
 	int ret;
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 4389ff40b49d..6c1468f64401 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -11,6 +11,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/bitfield.h>
+#include <linux/dmi.h>
+#include <linux/ctype.h>
 #include "qmi.h"
 #include "htc.h"
 #include "wmi.h"
@@ -32,6 +34,15 @@
 /* Pending management packets threshold for dropping probe responses */
 #define ATH12K_PRB_RSP_DROP_THRESHOLD ((ATH12K_TX_MGMT_TARGET_MAX_SUPPORT_WMI * 3) / 4)
 
+/* SMBIOS type containing Board Data File Name Extension */
+#define ATH12K_SMBIOS_BDF_EXT_TYPE 0xF8
+
+/* SMBIOS type structure length (excluding strings-set) */
+#define ATH12K_SMBIOS_BDF_EXT_LENGTH 0x9
+
+/* The magic used by QCA spec */
+#define ATH12K_SMBIOS_BDF_EXT_MAGIC "BDF_"
+
 #define ATH12K_INVALID_HW_MAC_ID	0xFF
 #define	ATH12K_RX_RATE_TABLE_NUM	320
 #define	ATH12K_RX_RATE_TABLE_11AX_NUM	576
@@ -129,6 +140,13 @@ struct ath12k_ext_irq_grp {
 	struct net_device napi_ndev;
 };
 
+struct ath12k_smbios_bdf {
+	struct dmi_header hdr;
+	u32 padding;
+	u8 bdf_enabled;
+	u8 bdf_ext[];
+} __packed;
+
 #define HEHANDLE_CAP_PHYINFO_SIZE       3
 #define HECAP_PHYINFO_SIZE              9
 #define HECAP_MACINFO_SIZE              5
@@ -789,7 +807,7 @@ 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_check_dt(struct ath12k_base *ath12k);
-
+int ath12k_core_check_smbios(struct ath12k_base *ab);
 void ath12k_core_halt(struct ath12k *ar);
 int ath12k_core_resume(struct ath12k_base *ab);
 int ath12k_core_suspend(struct ath12k_base *ab);
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index b2db0436bdde..fd1bf53c2502 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -2213,6 +2213,7 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab)
 	struct qmi_txn txn = {};
 	unsigned int board_id = ATH12K_BOARD_ID_DEFAULT;
 	int ret = 0;
+	int r;
 	int i;
 
 	memset(&req, 0, sizeof(req));
@@ -2297,6 +2298,10 @@ static int ath12k_qmi_request_target_cap(struct ath12k_base *ab)
 		    ab->qmi.target.fw_build_timestamp,
 		    ab->qmi.target.fw_build_id);
 
+	r = ath12k_core_check_smbios(ab);
+	if (r)
+		ath12k_dbg(ab, ATH12K_DBG_QMI, "SMBIOS bdf variant name not set.\n");
+
 out:
 	return ret;
 }

base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_wgong at quicinc.com  Tue Sep  5 03:59:47 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Tue, 5 Sep 2023 06:59:47 -0400
Subject: [PATCH] wifi: ath12k: indicate to mac80211 scan complete with aborted flag for ATH12K_SCAN_STARTING state
Message-ID: <20230905105947.10369-1-quic_wgong@quicinc.com>

Scan failure can not be recovered from when running a loop of the
following steps:
1. run scan: "iw wlan scan".
2. run command: echo assert > /sys/kernel/debug/ath12k/wcn7850\ hw2.0/simulate_fw_crash
   immediately after step 1.

result:
scan failed and can not recover even when wlan recovery succeeds:
command failed: Device or resource busy (-16)

reason:
When scan arrives, WMI_START_SCAN_CMDID is sent to the firmware and
function ath12k_mac_op_hw_scan() returns, then simulate_fw_crash arrives
and the scan started event does not arrive, and then it starts to do
recovery of wlan. __ath12k_mac_scan_finish() which is called from
ath12k_core_halt() is one step of recovery, it will not call
ieee80211_scan_completed() by logic currently because the scan state is
ATH12K_SCAN_STARTING. Thus it leads the scan not being completed in
mac80211, and leads all consecutive scans failing with -EBUSY in
nl80211_trigger_scan even after wlan recovery success.

Indicate scan complete with aborted flag to mac80211 for
ATH12K_SCAN_STARTING to allow recovery from scan failed with "Device or
resource busy (-16)" after wlan recovery.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/mac.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0f2af2f14ef7..a99324dbe7ad 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2780,18 +2780,21 @@ void __ath12k_mac_scan_finish(struct ath12k *ar)
 		break;
 	case ATH12K_SCAN_RUNNING:
 	case ATH12K_SCAN_ABORTING:
+		if (ar->scan.is_roc && ar->scan.roc_notify)
+			ieee80211_remain_on_channel_expired(ar->hw);
+		fallthrough;
+	case ATH12K_SCAN_STARTING:
 		if (!ar->scan.is_roc) {
 			struct cfg80211_scan_info info = {
-				.aborted = (ar->scan.state ==
-					    ATH12K_SCAN_ABORTING),
+				.aborted = ((ar->scan.state ==
+					    ATH12K_SCAN_ABORTING) ||
+					    (ar->scan.state ==
+					    ATH12K_SCAN_STARTING)),
 			};
 
 			ieee80211_scan_completed(ar->hw, &info);
-		} else if (ar->scan.roc_notify) {
-			ieee80211_remain_on_channel_expired(ar->hw);
 		}
-		fallthrough;
-	case ATH12K_SCAN_STARTING:
+
 		ar->scan.state = ATH12K_SCAN_IDLE;
 		ar->scan_channel = NULL;
 		ar->scan.roc_freq = 0;

base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From kvalo at kernel.org  Tue Sep  5 06:26:54 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Tue,  5 Sep 2023 13:26:54 +0000 (UTC)
Subject: [PATCH v2 1/2] wifi: ath12k: Ignore fragments from uninitialized
 peer
 in  dp
In-Reply-To: <20230821130343.29495-2-quic_hprem@quicinc.com>
References: <20230821130343.29495-2-quic_hprem@quicinc.com>
Message-ID: <169392041226.3610046.3872550352211944428.kvalo@kernel.org>

Harshitha Prem <quic_hprem at quicinc.com> wrote:

> When max virtual ap interfaces are configured in all the bands with
> ACS and hostapd restart is done every 60s, a crash is observed at
> random times.
> 
> In the above scenario, a fragmented packet is received for self peer,
> for which rx_tid and rx_frags are not initialized in datapath.
> While handling this fragment, crash is observed as the rx_frag list
> is uninitialized and when we walk in ath12k_dp_rx_h_sort_frags,
> skb null leads to exception.
> 
> To address this, before processing received fragments we check
> dp_setup_done flag is set to ensure that peer has completed its
> dp peer setup for fragment queue, else ignore processing the
> fragments.
> 
> Call trace:
>     PC points to "ath12k_dp_process_rx_err+0x4e8/0xfcc [ath12k]"
>     LR points to "ath12k_dp_process_rx_err+0x480/0xfcc [ath12k]".
>     The Backtrace obtained is as follows:
>     ath12k_dp_process_rx_err+0x4e8/0xfcc [ath12k]
>     ath12k_dp_service_srng+0x78/0x260 [ath12k]
>     ath12k_pci_write32+0x990/0xb0c [ath12k]
>     __napi_poll+0x30/0xa4
>     net_rx_action+0x118/0x270
>     __do_softirq+0x10c/0x244
>     irq_exit+0x64/0xb4
>     __handle_domain_irq+0x88/0xac
>     gic_handle_irq+0x74/0xbc
>     el1_irq+0xf0/0x1c0
>     arch_cpu_idle+0x10/0x18
>     do_idle+0x104/0x248
>     cpu_startup_entry+0x20/0x64
>     rest_init+0xd0/0xdc
>     arch_call_rest_init+0xc/0x14
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Harshitha Prem <quic_hprem at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

2 patches applied to ath-next branch of ath.git, thanks.

bbc86757ca62 wifi: ath12k: Ignore fragments from uninitialized peer in  dp
d48f55e773dc wifi: ath12k: fix undefined behavior with __fls in dp

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230821130343.29495-2-quic_hprem at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From quic_jjohnson at quicinc.com  Tue Sep  5 10:04:56 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 5 Sep 2023 10:04:56 -0700
Subject: [PATCH] wifi: ath12k: indicate to mac80211 scan complete with
 aborted flag for ATH12K_SCAN_STARTING state
In-Reply-To: <20230905105947.10369-1-quic_wgong@quicinc.com>
References: <20230905105947.10369-1-quic_wgong@quicinc.com>
Message-ID: <cc57c0fd-e6e0-49df-910b-2ce1204d3d41@quicinc.com>

On 9/5/2023 3:59 AM, Wen Gong wrote:
> Scan failure can not be recovered from when running a loop of the
> following steps:
> 1. run scan: "iw wlan scan".
> 2. run command: echo assert > /sys/kernel/debug/ath12k/wcn7850\ hw2.0/simulate_fw_crash
>     immediately after step 1.
> 
> result:
> scan failed and can not recover even when wlan recovery succeeds:
> command failed: Device or resource busy (-16)
> 
> reason:
> When scan arrives, WMI_START_SCAN_CMDID is sent to the firmware and
> function ath12k_mac_op_hw_scan() returns, then simulate_fw_crash arrives
> and the scan started event does not arrive, and then it starts to do
> recovery of wlan. __ath12k_mac_scan_finish() which is called from
> ath12k_core_halt() is one step of recovery, it will not call
> ieee80211_scan_completed() by logic currently because the scan state is
> ATH12K_SCAN_STARTING. Thus it leads the scan not being completed in
> mac80211, and leads all consecutive scans failing with -EBUSY in
> nl80211_trigger_scan even after wlan recovery success.
> 
> Indicate scan complete with aborted flag to mac80211 for
> ATH12K_SCAN_STARTING to allow recovery from scan failed with "Device or
> resource busy (-16)" after wlan recovery.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
>   drivers/net/wireless/ath/ath12k/mac.c | 15 +++++++++------
>   1 file changed, 9 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 0f2af2f14ef7..a99324dbe7ad 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -2780,18 +2780,21 @@ void __ath12k_mac_scan_finish(struct ath12k *ar)
>   		break;
>   	case ATH12K_SCAN_RUNNING:
>   	case ATH12K_SCAN_ABORTING:
> +		if (ar->scan.is_roc && ar->scan.roc_notify)
> +			ieee80211_remain_on_channel_expired(ar->hw);
> +		fallthrough;
> +	case ATH12K_SCAN_STARTING:
>   		if (!ar->scan.is_roc) {
>   			struct cfg80211_scan_info info = {
> -				.aborted = (ar->scan.state ==
> -					    ATH12K_SCAN_ABORTING),
> +				.aborted = ((ar->scan.state ==
> +					    ATH12K_SCAN_ABORTING) ||
> +					    (ar->scan.state ==
> +					    ATH12K_SCAN_STARTING)),
>   			};
>   
>   			ieee80211_scan_completed(ar->hw, &info);
> -		} else if (ar->scan.roc_notify) {
> -			ieee80211_remain_on_channel_expired(ar->hw);
>   		}
> -		fallthrough;
> -	case ATH12K_SCAN_STARTING:
> +
>   		ar->scan.state = ATH12K_SCAN_IDLE;
>   		ar->scan_channel = NULL;
>   		ar->scan.roc_freq = 0;
> 
> base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e



From quic_jjohnson at quicinc.com  Tue Sep  5 10:05:52 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 5 Sep 2023 10:05:52 -0700
Subject: [PATCH] wifi: ath12k: fix recovery fail while firmware crash when
 doing channel switch
In-Reply-To: <20230905105229.10090-1-quic_wgong@quicinc.com>
References: <20230905105229.10090-1-quic_wgong@quicinc.com>
Message-ID: <a1e4f4fd-7558-412f-8011-02740b8cf4a9@quicinc.com>

On 9/5/2023 3:52 AM, Wen Gong wrote:
> When firmware crashed while channel switch running, recovery starts in
> ath12k. Then ieee80211_sta_connection_lost() will be called by function
> ieee80211_restart_work() in mac80211. And then many WMI command timeout
> because firmware is crashed. Each WMI command cost 3 seconds, then the
> total time will be large and leads recovery fail.
> 
> Hence change to set value ATH12K_FLAG_CRASH_FLUSH early and then
> ath12k_wmi_cmd_send() will not wait 3 seconds, then recovery will be
> started quickly and success.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
>   drivers/net/wireless/ath/ath12k/core.c | 3 +++
>   1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 3df8059d5512..56be7298ac86 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -685,6 +685,9 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
>   	ab->stats.fw_crash_counter++;
>   	spin_unlock_bh(&ab->base_lock);
>   
> +	if (ab->is_reset)
> +		set_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags);
> +
>   	for (i = 0; i < ab->num_radios; i++) {
>   		pdev = &ab->pdevs[i];
>   		ar = pdev->ar;
> 
> base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e



From quic_sidhanta at quicinc.com  Tue Sep  5 11:27:31 2023
From: quic_sidhanta at quicinc.com (Sidhanta Sahu)
Date: Tue, 5 Sep 2023 11:27:31 -0700
Subject: [PATCH] wifi: ath12k: Set default beacon mode to burst mode
In-Reply-To: <d4ea2c1b-a142-1ce6-9566-7f501a30f533@quicinc.com>
References: <20230830194617.26400-1-quic_sidhanta@quicinc.com>
 <d4ea2c1b-a142-1ce6-9566-7f501a30f533@quicinc.com>
Message-ID: <bddf5e10-fe6d-4e7d-b4f0-49b27db3f3fd@quicinc.com>

On 8/30/2023 8:49 PM, Aditya Kumar Singh wrote:
> On 8/31/23 01:16, Sidhanta Sahu wrote:
>> Currently, firmware does not like when beacon mode is set as staggered
>> mode for more than one beaconing vifs. Beacon mode for multiple
>> beaconing (transmitted) vifs are expected to be in burst mode. So set
>> beacon mode to burst mode by default.
>>
>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>>
>> Signed-off-by: Sidhanta Sahu <quic_sidhanta at quicinc.com>
>> ---
>> ? drivers/net/wireless/ath/ath12k/mac.c | 2 +-
>> ? 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath12k/mac.c 
>> b/drivers/net/wireless/ath/ath12k/mac.c
>> index 1bb9802ef569..b16cbc3c906d 100644
>> --- a/drivers/net/wireless/ath/ath12k/mac.c
>> +++ b/drivers/net/wireless/ath/ath12k/mac.c
>> @@ -2314,7 +2314,7 @@ static void 
>> ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
>> ? ????? if (changed & BSS_CHANGED_BEACON) {
>> ????????? param_id = WMI_PDEV_PARAM_BEACON_TX_MODE;
>> -??????? param_value = WMI_BEACON_STAGGERED_MODE;
>> +??????? param_value = WMI_BEACON_BURST_MODE;
>> ????????? ret = ath12k_wmi_pdev_set_param(ar, param_id,
>> ????????????????????????? param_value, ar->pdev->pdev_id);
>> ????????? if (ret)
> In else part, we have a debug print. IMHO that should be changed too. 
> Please check once.
>
> ??????? else
> ??????????? ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
> ?????????????????? "Set staggered beacon mode for VDEV: %d\n",
> ?????????????????? arvif->vdev_id);
>
> Could you check once?
Yes, Will change it in next version.
>
> Aditya


From quic_jjohnson at quicinc.com  Tue Sep  5 13:09:53 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 5 Sep 2023 13:09:53 -0700
Subject: [PATCH] wifi: ath12k: add support for hardware rfkill for WCN7850
In-Reply-To: <20230905092720.3533-1-quic_lingbok@quicinc.com>
References: <20230905092720.3533-1-quic_lingbok@quicinc.com>
Message-ID: <b950a997-5565-488a-9b6f-225db2362878@quicinc.com>

On 9/5/2023 2:27 AM, Lingbo Kong wrote:
> When hardware rfkill is enabled in the firmware, it will report the
> capability via using WMI_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY

s/via //
('via' and 'using' are redundant in this context)

> event to the host. 

to follow the suggested template "Current code does (A), this has a 
problem when (B). We can improve this doing (C), because (D)" I'd add 
the additional sentence: Currently ath12k does not process this service 
capability.

And then I'd have a 2nd paragraph in present imperative tense:
In order to support this, update ath12k to check if the capability is 
enabled, and if so, send the GPIO information to firmware...

ath12k will check the capability if it is enabled then
> ath12k will set the GPIO information to firmware using WMI_PDEV_SET_PARAM.
> When the firmware detects hardware rfkill is enabled by the user, it will
> report it via WMI_RFKILL_STATE_CHANGE_EVENTID. Once ath12k receive the

and modify this last sentence to say update ath12k to receive the event, 
and in response send WMI command ...

> event it will send wmi command WMI_PDEV_SET_PARAM to the firmware and
> also notify cfg80211.

BTW can you specify which param is being set?

> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/core.c | 52 +++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/core.h |  4 ++
>   drivers/net/wireless/ath/ath12k/hw.c   | 12 ++++++
>   drivers/net/wireless/ath/ath12k/hw.h   |  4 ++
>   drivers/net/wireless/ath/ath12k/mac.c  | 58 ++++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/mac.h  |  2 +
>   drivers/net/wireless/ath/ath12k/wmi.c  | 39 +++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h  | 25 +++++++++++
>   8 files changed, 196 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 3df8059d5512..cae1ab9982cd 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -19,6 +19,27 @@ unsigned int ath12k_debug_mask;
>   module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
>   MODULE_PARM_DESC(debug_mask, "Debugging mask");
>   
> +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;
> +
> +	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;
> +}
> +
>   int ath12k_core_suspend(struct ath12k_base *ab)
>   {
>   	int ret;
> @@ -603,6 +624,13 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
>   		goto err_core_stop;
>   	}
>   	ath12k_hif_irq_enable(ab);
> +
> +	ret = ath12k_core_rfkill_config(ab);
> +	if (ret && ret != -EOPNOTSUPP) {
> +		ath12k_err(ab, "failed to config rfkill: %d\n", ret);
> +		goto err_core_stop;
> +	}
> +
>   	mutex_unlock(&ab->core_lock);
>   
>   	return 0;
> @@ -655,6 +683,27 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab)
>   	return ret;
>   }
>   
> +static void ath12k_rfkill_work(struct work_struct *work)
> +{
> +	struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work);
> +	struct ath12k *ar;
> +	bool rfkill_radio_on;
> +	int i;
> +
> +	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)
> +			continue;
> +
> +		ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on);
> +		wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on);
> +	}
> +}
> +
>   void ath12k_core_halt(struct ath12k *ar)
>   {
>   	struct ath12k_base *ab = ar->ab;
> @@ -668,6 +717,7 @@ void ath12k_core_halt(struct ath12k *ar)
>   	ath12k_mac_peer_cleanup_all(ar);
>   	cancel_delayed_work_sync(&ar->scan.timeout);
>   	cancel_work_sync(&ar->regd_update_work);
> +	cancel_work_sync(&ab->rfkill_work);
>   
>   	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
>   	synchronize_rcu();
> @@ -922,6 +972,8 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
>   	init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
>   	INIT_WORK(&ab->restart_work, ath12k_core_restart);
>   	INIT_WORK(&ab->reset_work, ath12k_core_reset);
> +	INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work);
> +
>   	timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
>   	init_completion(&ab->htc_suspend);
>   
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index d873b573dac6..3f5f0471f640 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -771,6 +771,10 @@ struct ath12k_base {
>   	u64 fw_soc_drop_count;
>   	bool static_window_map;
>   
> +	struct work_struct rfkill_work;
> +	/* true means radio is on */
> +	bool rfkill_radio_on;
> +
>   	/* must be last */
>   	u8 drv_priv[] __aligned(sizeof(void *));
>   };
> diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
> index 5991cc91cd00..f69649f58e82 100644
> --- a/drivers/net/wireless/ath/ath12k/hw.c
> +++ b/drivers/net/wireless/ath/ath12k/hw.c
> @@ -907,6 +907,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   		.hal_ops = &hal_qcn9274_ops,
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
> +
> +		.rfkill_pin = 0,
> +		.rfkill_cfg = 0,
> +		.rfkill_on_level = 0,
>   	},
>   	{
>   		.name = "wcn7850 hw2.0",
> @@ -964,6 +968,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
>   					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
> +
> +		.rfkill_pin = 48,
> +		.rfkill_cfg = 0,
> +		.rfkill_on_level = 1,
>   	},
>   	{
>   		.name = "qcn9274 hw2.0",
> @@ -1019,6 +1027,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   		.hal_ops = &hal_qcn9274_ops,
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
> +
> +		.rfkill_pin = 0,
> +		.rfkill_cfg = 0,
> +		.rfkill_on_level = 0,
>   	},
>   };
>   
> diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
> index e6c4223c283c..1b4912bf57ad 100644
> --- a/drivers/net/wireless/ath/ath12k/hw.h
> +++ b/drivers/net/wireless/ath/ath12k/hw.h
> @@ -186,6 +186,10 @@ struct ath12k_hw_params {
>   	const struct hal_ops *hal_ops;
>   
>   	u64 qmi_cnss_feature_bitmap;
> +
> +	u32 rfkill_pin;
> +	u32 rfkill_cfg;
> +	u32 rfkill_on_level;
>   };
>   
>   struct ath12k_hw_ops {
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 85602d64b607..486d062b0a76 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5108,6 +5108,63 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
>   	return ret;
>   }
>   
> +int ath12k_mac_rfkill_config(struct ath12k *ar)
> +{
> +	struct ath12k_base *ab = ar->ab;
> +	u32 param;
> +	int ret;
> +
> +	if (ab->hw_params->rfkill_pin == 0)
> +		return -EOPNOTSUPP;
> +
> +	ath12k_dbg(ab, ATH12K_DBG_MAC,
> +		   "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d",
> +		   ab->hw_params->rfkill_pin, ab->hw_params->rfkill_cfg,
> +		   ab->hw_params->rfkill_on_level);
> +
> +	param = u32_encode_bits(ab->hw_params->rfkill_on_level,
> +				WMI_RFKILL_CFG_RADIO_LEVEL) |
> +		u32_encode_bits(ab->hw_params->rfkill_pin,
> +				WMI_RFKILL_CFG_GPIO_PIN_NUM) |
> +		u32_encode_bits(ab->hw_params->rfkill_cfg,
> +				WMI_RFKILL_CFG_PIN_AS_GPIO);
> +
> +	ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_HW_RFKILL_CONFIG,
> +					param, ar->pdev->pdev_id);
> +	if (ret) {
> +		ath12k_warn(ab,
> +			    "failed to set rfkill config 0x%x: %d\n",
> +			    param, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable)
> +{
> +	enum wmi_rfkill_enable_radio param;
> +	int ret;
> +
> +	if (enable)
> +		param = WMI_RFKILL_ENABLE_RADIO_ON;
> +	else
> +		param = WMI_RFKILL_ENABLE_RADIO_OFF;
> +
> +	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac %d rfkill enable %d",
> +		   ar->pdev_idx, param);
> +
> +	ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RFKILL_ENABLE,
> +					param, ar->pdev->pdev_id);
> +	if (ret) {
> +		ath12k_warn(ar->ab, "failed to set rfkill enable param %d: %d\n",
> +			    param, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>   static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
>   {
>   	struct ath12k *ar = hw->priv;
> @@ -5128,6 +5185,7 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
>   
>   	cancel_delayed_work_sync(&ar->scan.timeout);
>   	cancel_work_sync(&ar->regd_update_work);
> +	cancel_work_sync(&ar->ab->rfkill_work);
>   
>   	spin_lock_bh(&ar->data_lock);
>   	list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
> diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
> index 7b16b70df4fa..59b4e8f5eee0 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.h
> +++ b/drivers/net/wireless/ath/ath12k/mac.h
> @@ -73,4 +73,6 @@ int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
>   enum rate_info_bw ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw);
>   enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw bw);
>   enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher);
> +int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
> +int ath12k_mac_rfkill_config(struct ath12k *ar);
>   #endif
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index ef0f3cf35cfd..4ac05cd7a1a5 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -152,6 +152,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
>   		.min_len = sizeof(struct wmi_service_available_event) },
>   	[WMI_TAG_PEER_ASSOC_CONF_EVENT] = {
>   		.min_len = sizeof(struct wmi_peer_assoc_conf_event) },
> +	[WMI_TAG_RFKILL_EVENT] = {
> +		.min_len = sizeof(struct wmi_rfkill_state_change_event) },
>   	[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] = {
>   		.min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },
>   	[WMI_TAG_HOST_SWFDA_EVENT] = {
> @@ -6580,6 +6582,40 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
>   	kfree(tb);
>   }
>   
> +static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
> +					     struct sk_buff *skb)
> +{
> +	const struct wmi_rfkill_state_change_event *ev;
> +	const void **tb;
> +	int ret;
> +
> +	tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
> +	if (IS_ERR(tb)) {
> +		ret = PTR_ERR(tb);
> +		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> +		return;
> +	}
> +
> +	ev = tb[WMI_TAG_RFKILL_EVENT];
> +	if (!ev) {
> +		kfree(tb);
> +		return;
> +	}
> +
> +	ath12k_dbg(ab, ATH12K_DBG_MAC,
> +		   "wmi tlv rfkill state change gpio %d type %d radio_state %d\n",
> +		   le32_to_cpu(ev->gpio_pin_num),
> +		   le32_to_cpu(ev->int_type),
> +		   le32_to_cpu(ev->radio_state));
> +
> +	spin_lock_bh(&ab->base_lock);
> +	ab->rfkill_radio_on = (le32_to_cpu(ev->radio_state) == WMI_RFKILL_RADIO_STATE_ON);

nit: when you have a choice it is more efficient to use an 
endian-conversion macro on a compile-time constant rather than on a 
variable since then it becomes a compile-time conversion instead of a 
runtime conversion:
	ab->rfkill_radio_on = (ev->radio_state == 
cpu_to_le32(WMI_RFKILL_RADIO_STATE_ON));

> +	spin_unlock_bh(&ab->base_lock);
> +
> +	queue_work(ab->workqueue, &ab->rfkill_work);
> +	kfree(tb);
> +}
> +
>   static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
>   {
>   	struct wmi_cmd_hdr *cmd_hdr;
> @@ -6672,6 +6708,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
>   	case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID:
>   		ath12k_probe_resp_tx_status_event(ab, skb);
>   		break;
> +	case WMI_RFKILL_STATE_CHANGE_EVENTID:
> +		ath12k_rfkill_state_change_event(ab, skb);
> +		break;
>   	/* add Unsupported events here */
>   	case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
>   	case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index c75a6fa1f7e0..965755b4cbfd 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -4793,6 +4793,31 @@ struct ath12k_wmi_base {
>   
>   #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
>   
> +enum wmi_sys_cap_info_flags {
> +	WMI_SYS_CAP_INFO_RXTX_LED	= BIT(0),
> +	WMI_SYS_CAP_INFO_RFKILL		= BIT(1),
> +};
> +
> +#define WMI_RFKILL_CFG_GPIO_PIN_NUM		GENMASK(5, 0)
> +#define WMI_RFKILL_CFG_RADIO_LEVEL		BIT(6)
> +#define WMI_RFKILL_CFG_PIN_AS_GPIO		GENMASK(10, 7)
> +
> +enum wmi_rfkill_enable_radio {
> +	WMI_RFKILL_ENABLE_RADIO_ON	= 0,
> +	WMI_RFKILL_ENABLE_RADIO_OFF	= 1,
> +};
> +
> +enum wmi_rfkill_radio_state {
> +	WMI_RFKILL_RADIO_STATE_OFF	= 1,
> +	WMI_RFKILL_RADIO_STATE_ON	= 2,
> +};
> +
> +struct wmi_rfkill_state_change_event {
> +	__le32 gpio_pin_num;
> +	__le32 int_type;
> +	__le32 radio_state;
> +} __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,
> 
> base-commit: 4d4739971f44150b3dcb75f188a1a3cbc22889a3



From quic_sidhanta at quicinc.com  Tue Sep  5 14:39:43 2023
From: quic_sidhanta at quicinc.com (Sidhanta Sahu)
Date: Tue,  5 Sep 2023 14:39:43 -0700
Subject: [PATCH v2] wifi: ath12k: Set default beacon mode to burst mode
Message-ID: <20230905213943.12275-1-quic_sidhanta@quicinc.com>

Currently, firmware does not like when beacon mode is set as staggered
mode for more than one beaconing vifs. Beacon mode for multiple
beaconing (transmitted) vifs are expected to be in burst mode. So set
beacon mode to burst mode by default.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Sidhanta Sahu <quic_sidhanta at quicinc.com>
---
v2: Modified the debug log.

 drivers/net/wireless/ath/ath12k/mac.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 1bb9802ef569..d38b85eaed37 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2314,7 +2314,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 
 	if (changed & BSS_CHANGED_BEACON) {
 		param_id = WMI_PDEV_PARAM_BEACON_TX_MODE;
-		param_value = WMI_BEACON_STAGGERED_MODE;
+		param_value = WMI_BEACON_BURST_MODE;
 		ret = ath12k_wmi_pdev_set_param(ar, param_id,
 						param_value, ar->pdev->pdev_id);
 		if (ret)
@@ -2322,7 +2322,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 				    arvif->vdev_id);
 		else
 			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
-				   "Set staggered beacon mode for VDEV: %d\n",
+				   "Set burst beacon mode for VDEV: %d\n",
 				   arvif->vdev_id);
 
 		ret = ath12k_mac_setup_bcn_tmpl(arvif);
-- 
2.17.1



From quic_jjohnson at quicinc.com  Tue Sep  5 22:00:00 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 5 Sep 2023 22:00:00 -0700
Subject: [PATCH v2] wifi: ath12k: Set default beacon mode to burst mode
In-Reply-To: <20230905213943.12275-1-quic_sidhanta@quicinc.com>
References: <20230905213943.12275-1-quic_sidhanta@quicinc.com>
Message-ID: <5b33c223-5781-4f72-84a0-bd3f228036d3@quicinc.com>

On 9/5/2023 2:39 PM, Sidhanta Sahu wrote:
> Currently, firmware does not like when beacon mode is set as staggered
> mode for more than one beaconing vifs. Beacon mode for multiple
> beaconing (transmitted) vifs are expected to be in burst mode. So set
> beacon mode to burst mode by default.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Sidhanta Sahu <quic_sidhanta at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
> v2: Modified the debug log.
> 
>   drivers/net/wireless/ath/ath12k/mac.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 1bb9802ef569..d38b85eaed37 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -2314,7 +2314,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
>   
>   	if (changed & BSS_CHANGED_BEACON) {
>   		param_id = WMI_PDEV_PARAM_BEACON_TX_MODE;
> -		param_value = WMI_BEACON_STAGGERED_MODE;
> +		param_value = WMI_BEACON_BURST_MODE;
>   		ret = ath12k_wmi_pdev_set_param(ar, param_id,
>   						param_value, ar->pdev->pdev_id);
>   		if (ret)
> @@ -2322,7 +2322,7 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
>   				    arvif->vdev_id);
>   		else
>   			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
> -				   "Set staggered beacon mode for VDEV: %d\n",
> +				   "Set burst beacon mode for VDEV: %d\n",
>   				   arvif->vdev_id);
>   
>   		ret = ath12k_mac_setup_bcn_tmpl(arvif);



From quic_jjohnson at quicinc.com  Tue Sep  5 22:17:35 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 5 Sep 2023 22:17:35 -0700
Subject: [PATCH 1/4] wifi: ath12k: add TAS capability for WCN7850
In-Reply-To: <20230905024904.3882-2-quic_lingbok@quicinc.com>
References: <20230905024904.3882-1-quic_lingbok@quicinc.com>
 <20230905024904.3882-2-quic_lingbok@quicinc.com>
Message-ID: <f859afc5-e51b-4b3a-9039-0da434d255e6@quicinc.com>

...

> diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
> new file mode 100644
> index 000000000000..cf742958a623
> --- /dev/null
> +++ b/drivers/net/wireless/ath/ath12k/acpi.h
> @@ -0,0 +1,28 @@
> +/* 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.
> + */
> +#include <linux/acpi.h>

nit: this should be inside the include guard...

> +
> +#ifndef ATH12K_ACPI_H
> +#define ATH12K_ACPI_H

...here




From quic_wgong at quicinc.com  Wed Sep  6 01:29:44 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 04:29:44 -0400
Subject: [PATCH 0/4] wifi: ath12k: add 11d scan offload support and handle country code for WCN7850
Message-ID: <20230906082948.18452-1-quic_wgong@quicinc.com>

Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID which is needed for 
11d scan offload to firmware. And add support for 11d scan offload for 
WCN7850.

Also fix firmware crash for country code set for WCN7850 and store country
code for device recovery for WCN7850.

Wen Gong (4):
  wifi: ath12k: add configure country code for WCN7850
  wifi: ath12k: add 11d scan offload support
  wifi: ath12k: avoid firmware crash when reg set for WCN7850
  wifi: ath12k: store and send country code to firmware after recovery

 drivers/net/wireless/ath/ath12k/core.c |  36 ++++-
 drivers/net/wireless/ath/ath12k/core.h |  17 +++
 drivers/net/wireless/ath/ath12k/hw.c   |   3 +
 drivers/net/wireless/ath/ath12k/hw.h   |   1 +
 drivers/net/wireless/ath/ath12k/mac.c  | 178 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h  |   7 +
 drivers/net/wireless/ath/ath12k/reg.c  |  67 ++++++++--
 drivers/net/wireless/ath/ath12k/reg.h  |   3 +-
 drivers/net/wireless/ath/ath12k/wmi.c  | 159 +++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/wmi.h  |  38 ++++++
 10 files changed, 489 insertions(+), 20 deletions(-)


base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 01:29:45 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 04:29:45 -0400
Subject: [PATCH 1/4] wifi: ath12k: add configure country code for WCN7850
In-Reply-To: <20230906082948.18452-1-quic_wgong@quicinc.com>
References: <20230906082948.18452-1-quic_wgong@quicinc.com>
Message-ID: <20230906082948.18452-2-quic_wgong@quicinc.com>

Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware which
is used for WCN7850.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/wmi.c | 36 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h | 13 ++++++++++
 2 files changed, 49 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 9ed33e2d6da0..aa87b559eff1 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -2844,6 +2844,42 @@ int ath12k_wmi_send_init_country_cmd(struct ath12k *ar,
 	return ret;
 }
 
+int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
+					    struct wmi_set_current_country_params *param)
+{
+	struct ath12k_wmi_pdev *wmi = ar->wmi;
+	struct wmi_set_current_country_cmd *cmd;
+	struct sk_buff *skb;
+	int ret;
+
+	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_current_country_cmd *)skb->data;
+	cmd->tlv_header =
+		ath12k_wmi_tlv_cmd_hdr(WMI_TAG_SET_CURRENT_COUNTRY_CMD,
+				       sizeof(*cmd));
+
+	cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id);
+	memcpy(&cmd->new_alpha2, &param->alpha2, 3);
+	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+		   "set current country pdev id %d alpha2 %c%c\n",
+		   ar->pdev->pdev_id,
+		   param->alpha2[0],
+		   param->alpha2[1]);
+
+	if (ret) {
+		ath12k_warn(ar->ab,
+			    "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
 int
 ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id)
 {
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 8c047a9623f9..8940b8154091 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -3749,6 +3749,16 @@ struct ath12k_wmi_ap_ps_arg {
 	u32 value;
 };
 
+struct wmi_set_current_country_params {
+	u8 alpha2[3];
+};
+
+struct wmi_set_current_country_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 new_alpha2;
+} __packed;
+
 enum set_init_cc_type {
 	WMI_COUNTRY_INFO_TYPE_ALPHA,
 	WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE,
@@ -4879,6 +4889,9 @@ int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar,
 					    u32 vdev_id, u32 bcn_ctrl_op);
 int ath12k_wmi_send_init_country_cmd(struct ath12k *ar,
 				     struct ath12k_wmi_init_country_arg *arg);
+int
+ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
+					struct wmi_set_current_country_params *param);
 int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar,
 					   int vdev_id, const u8 *addr,
 					   dma_addr_t paddr, u8 tid,
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 01:29:46 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 04:29:46 -0400
Subject: [PATCH 2/4] wifi: ath12k: add 11d scan offload support
In-Reply-To: <20230906082948.18452-1-quic_wgong@quicinc.com>
References: <20230906082948.18452-1-quic_wgong@quicinc.com>
Message-ID: <20230906082948.18452-3-quic_wgong@quicinc.com>

Add handler for WMI_11D_NEW_COUNTRY_EVENTID, WMI_11D_SCAN_START_CMDID,
WMI_11D_SCAN_STOP_CMDID.

The priority of 11d scan WMI_SCAN_PRIORITY_MEDIUM in firmware, the
priority of hw scan is WMI_SCAN_PRIORITY_LOW, then the 11d scan will
cancel the hw scan which is running. To avoid this, change the priority
of the 1st hw scan to WMI_SCAN_PRIORITY_MEDIUM. Add wait_for_completion_timeout
for ar->scan.completed in ath12k_reg_update_chan_list(), plus the existing
wait in ath12k_scan_stop(), then ath12k have 2 place to wait the
ar->scan.completed, they run in different thread, thus it is possible to
happen that the two threads both enter wait status. To handle this scenario,
ath12k should change the complete() to complete_all() for the ar->scan.completed,
this also work well when it is only one thread wait for ar->scan.completed.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c |  35 ++++-
 drivers/net/wireless/ath/ath12k/core.h |  16 +++
 drivers/net/wireless/ath/ath12k/mac.c  | 170 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h  |   7 +
 drivers/net/wireless/ath/ath12k/reg.c  |  37 +++++-
 drivers/net/wireless/ath/ath12k/reg.h  |   3 +-
 drivers/net/wireless/ath/ath12k/wmi.c  | 123 +++++++++++++++++-
 drivers/net/wireless/ath/ath12k/wmi.h  |  25 ++++
 8 files changed, 406 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 3df8059d5512..71450dc1f48d 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -668,6 +668,7 @@ void ath12k_core_halt(struct ath12k *ar)
 	ath12k_mac_peer_cleanup_all(ar);
 	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->regd_update_work);
+	cancel_work_sync(&ab->update_11d_work);
 
 	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
 	synchronize_rcu();
@@ -675,6 +676,34 @@ void ath12k_core_halt(struct ath12k *ar)
 	idr_init(&ar->txmgmt_idr);
 }
 
+static void ath12k_update_11d(struct work_struct *work)
+{
+	struct ath12k_base *ab = container_of(work, struct ath12k_base, update_11d_work);
+	struct ath12k *ar;
+	struct ath12k_pdev *pdev;
+	struct wmi_set_current_country_params set_current_param = {};
+	int ret, i;
+
+	spin_lock_bh(&ab->base_lock);
+	memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2);
+	spin_unlock_bh(&ab->base_lock);
+
+	ath12k_dbg(ab, ATH12K_DBG_WMI, "update 11d new cc %c%c\n",
+		   set_current_param.alpha2[0],
+		   set_current_param.alpha2[1]);
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+
+		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
+		if (ret)
+			ath12k_warn(ar->ab,
+				    "pdev id %d failed set current country code: %d\n",
+				    i, ret);
+	}
+}
+
 static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
 {
 	struct ath12k *ar;
@@ -693,8 +722,10 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
 
 		ieee80211_stop_queues(ar->hw);
 		ath12k_mac_drain_tx(ar);
+		ar->state_11d = ATH12K_11D_IDLE;
+		complete(&ar->completed_11d_scan);
 		complete(&ar->scan.started);
-		complete(&ar->scan.completed);
+		complete_all(&ar->scan.completed);
 		complete(&ar->peer_assoc_done);
 		complete(&ar->peer_delete_done);
 		complete(&ar->install_key_done);
@@ -913,6 +944,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 
 	mutex_init(&ab->core_lock);
 	spin_lock_init(&ab->base_lock);
+	mutex_init(&ab->vdev_id_11d_lock);
 	init_completion(&ab->reset_complete);
 	init_completion(&ab->reconfigure_complete);
 	init_completion(&ab->recovery_start);
@@ -921,6 +953,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 	init_waitqueue_head(&ab->peer_mapping_wq);
 	init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
 	INIT_WORK(&ab->restart_work, ath12k_core_restart);
+	INIT_WORK(&ab->update_11d_work, ath12k_update_11d);
 	INIT_WORK(&ab->reset_work, ath12k_core_reset);
 	timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
 	init_completion(&ab->htc_suspend);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 4389ff40b49d..ba8a4f968a3f 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -36,6 +36,8 @@
 #define	ATH12K_RX_RATE_TABLE_NUM	320
 #define	ATH12K_RX_RATE_TABLE_11AX_NUM	576
 
+#define ATH12K_SCAN_TIMEOUT_HZ (20 * HZ)
+
 #define ATH12K_MON_TIMER_INTERVAL  10
 #define ATH12K_RESET_TIMEOUT_HZ			(20 * HZ)
 #define ATH12K_RESET_MAX_FAIL_COUNT_FIRST	3
@@ -171,6 +173,12 @@ enum ath12k_scan_state {
 	ATH12K_SCAN_ABORTING,
 };
 
+enum ath12k_11d_state {
+	ATH12K_11D_IDLE,
+	ATH12K_11D_PREPARING,
+	ATH12K_11D_RUNNING,
+};
+
 enum ath12k_dev_flags {
 	ATH12K_CAC_RUNNING,
 	ATH12K_FLAG_CRASH_FLUSH,
@@ -570,6 +578,10 @@ struct ath12k {
 	bool monitor_vdev_created;
 	bool monitor_started;
 	int monitor_vdev_id;
+	u32 vdev_id_11d_scan;
+	struct completion completed_11d_scan;
+	enum ath12k_11d_state state_11d;
+	bool regdom_set_by_user;
 };
 
 struct ath12k_band_cap {
@@ -755,6 +767,10 @@ struct ath12k_base {
 	/* continuous recovery fail count */
 	atomic_t fail_cont_count;
 	unsigned long reset_fail_timeout;
+	struct work_struct update_11d_work;
+	u8 new_alpha2[3];
+	/* To synchronize 11d scan vdev id */
+	struct mutex vdev_id_11d_lock;
 	struct {
 		/* protected by data_lock */
 		u32 fw_crash_counter;
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0f2af2f14ef7..740e8045a6f1 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2354,6 +2354,11 @@ static void ath12k_bss_assoc(struct ieee80211_hw *hw,
 	if (ret)
 		ath12k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n",
 			    arvif->vdev_id, ret);
+
+	if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map) &&
+	    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
+		ath12k_mac_11d_scan_stop_all(ar->ab);
 }
 
 static void ath12k_bss_disassoc(struct ieee80211_hw *hw,
@@ -2796,7 +2801,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar)
 		ar->scan_channel = NULL;
 		ar->scan.roc_freq = 0;
 		cancel_delayed_work(&ar->scan.timeout);
-		complete(&ar->scan.completed);
+		complete_all(&ar->scan.completed);
 		break;
 	}
 }
@@ -2913,6 +2918,9 @@ static int ath12k_start_scan(struct ath12k *ar,
 		if (ret)
 			ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret);
 
+		if (ar->state_11d == ATH12K_11D_RUNNING)
+			return -EBUSY;
+
 		return -ETIMEDOUT;
 	}
 
@@ -3001,7 +3009,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
 
 	ret = ath12k_start_scan(ar, &arg);
 	if (ret) {
-		ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
+		if (ret == -EBUSY)
+			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+				   "scan engine is busy 11d state %d\n", ar->state_11d);
+		else
+			ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
+
 		spin_lock_bh(&ar->data_lock);
 		ar->scan.state = ATH12K_SCAN_IDLE;
 		spin_unlock_bh(&ar->data_lock);
@@ -3019,6 +3032,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
 		kfree(arg.extraie.ptr);
 
 	mutex_unlock(&ar->conf_mutex);
+
+	if (ar->state_11d == ATH12K_11D_PREPARING &&
+	    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
+		ath12k_mac_11d_scan_start(ar, arvif->vdev_id);
+
 	return ret;
 }
 
@@ -5060,7 +5079,7 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
 
 	/* TODO: Do we need to enable ANI? */
 
-	ath12k_reg_update_chan_list(ar);
+	ath12k_reg_update_chan_list(ar, false);
 
 	ar->num_started_vdevs = 0;
 	ar->num_created_vdevs = 0;
@@ -5128,6 +5147,9 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
 
 	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->regd_update_work);
+	cancel_work_sync(&ar->ab->update_11d_work);
+	ar->state_11d = ATH12K_11D_IDLE;
+	complete(&ar->completed_11d_scan);
 
 	spin_lock_bh(&ar->data_lock);
 	list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
@@ -5306,6 +5328,124 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
 	}
 }
 
+static bool ath12k_mac_vif_ap_active_any(struct ath12k_base *ab)
+{
+	struct ath12k *ar;
+	struct ath12k_pdev *pdev;
+	struct ath12k_vif *arvif;
+	int i;
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+		list_for_each_entry(arvif, &ar->arvifs, list) {
+			if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP)
+				return true;
+		}
+	}
+	return false;
+}
+
+void ath12k_mac_11d_scan_start(struct ath12k *ar, u32 vdev_id)
+{
+	struct wmi_11d_scan_start_params param;
+	int ret;
+
+	mutex_lock(&ar->ab->vdev_id_11d_lock);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev id for 11d scan %d\n",
+		   ar->vdev_id_11d_scan);
+
+	if (ar->regdom_set_by_user)
+		goto fin;
+
+	if (ar->vdev_id_11d_scan != ATH12K_11D_INVALID_VDEV_ID)
+		goto fin;
+
+	if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map))
+		goto fin;
+
+	if (ath12k_mac_vif_ap_active_any(ar->ab))
+		goto fin;
+
+	param.vdev_id = vdev_id;
+	param.start_interval_msec = 0;
+	param.scan_period_msec = ATH12K_SCAN_11D_INTERVAL;
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac start 11d scan\n");
+
+	ret = ath12k_wmi_send_11d_scan_start_cmd(ar, &param);
+	if (ret) {
+		ath12k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n",
+			    vdev_id, ret);
+	} else {
+		ar->vdev_id_11d_scan = vdev_id;
+		if (ar->state_11d == ATH12K_11D_PREPARING)
+			ar->state_11d = ATH12K_11D_RUNNING;
+	}
+
+fin:
+	if (ar->state_11d == ATH12K_11D_PREPARING) {
+		ar->state_11d = ATH12K_11D_IDLE;
+		complete(&ar->completed_11d_scan);
+	}
+
+	mutex_unlock(&ar->ab->vdev_id_11d_lock);
+}
+
+void ath12k_mac_11d_scan_stop(struct ath12k *ar)
+{
+	int ret;
+	u32 vdev_id;
+
+	if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map))
+		return;
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac stop 11d scan\n");
+
+	mutex_lock(&ar->ab->vdev_id_11d_lock);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac stop 11d vdev id %d\n",
+		   ar->vdev_id_11d_scan);
+
+	if (ar->state_11d == ATH12K_11D_PREPARING) {
+		ar->state_11d = ATH12K_11D_IDLE;
+		complete(&ar->completed_11d_scan);
+	}
+
+	if (ar->vdev_id_11d_scan != ATH12K_11D_INVALID_VDEV_ID) {
+		vdev_id = ar->vdev_id_11d_scan;
+
+		ret = ath12k_wmi_send_11d_scan_stop_cmd(ar, vdev_id);
+		if (ret) {
+			ath12k_warn(ar->ab,
+				    "failed to stopt 11d scan vdev %d ret: %d\n",
+				    vdev_id, ret);
+		} else {
+			ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID;
+			ar->state_11d = ATH12K_11D_IDLE;
+			complete(&ar->completed_11d_scan);
+		}
+	}
+	mutex_unlock(&ar->ab->vdev_id_11d_lock);
+}
+
+void ath12k_mac_11d_scan_stop_all(struct ath12k_base *ab)
+{
+	struct ath12k *ar;
+	struct ath12k_pdev *pdev;
+	int i;
+
+	ath12k_dbg(ab, ATH12K_DBG_MAC, "mac stop soc 11d scan\n");
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+
+		ath12k_mac_11d_scan_stop(ar);
+	}
+}
+
 static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 				       struct ieee80211_vif *vif)
 {
@@ -5438,6 +5578,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 				    arvif->vdev_id, ret);
 			goto err_peer_del;
 		}
+		ath12k_mac_11d_scan_stop_all(ar->ab);
 		break;
 	case WMI_VDEV_TYPE_STA:
 		param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY;
@@ -5476,6 +5617,14 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 				    arvif->vdev_id, ret);
 			goto err_peer_del;
 		}
+
+		if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
+		    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+		    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
+			reinit_completion(&ar->completed_11d_scan);
+			ar->state_11d = ATH12K_11D_PREPARING;
+		}
+
 		break;
 	default:
 		break;
@@ -5579,6 +5728,11 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
 	ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n",
 		   arvif->vdev_id);
 
+	if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
+	    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
+		ath12k_mac_11d_scan_stop(ar);
+
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 		ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr);
 		if (ret)
@@ -6289,6 +6443,14 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
 	    ar->num_started_vdevs == 1 && ar->monitor_vdev_created)
 		ath12k_mac_monitor_stop(ar);
 
+	if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
+	    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE &&
+	    ar->state_11d != ATH12K_11D_PREPARING) {
+		reinit_completion(&ar->completed_11d_scan);
+		ar->state_11d = ATH12K_11D_PREPARING;
+	}
+
 	mutex_unlock(&ar->conf_mutex);
 }
 
@@ -7461,6 +7623,8 @@ int ath12k_mac_allocate(struct ath12k_base *ab)
 		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);
+		ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID;
+		init_completion(&ar->completed_11d_scan);
 	}
 
 	return 0;
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 7b16b70df4fa..0653b6b54891 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -47,6 +47,13 @@ enum ath12k_supported_bw {
 
 extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;
 
+#define ATH12K_SCAN_11D_INTERVAL		600000
+#define ATH12K_11D_INVALID_VDEV_ID		0xFFFF
+
+void ath12k_mac_11d_scan_start(struct ath12k *ar, u32 vdev_id);
+void ath12k_mac_11d_scan_stop(struct ath12k *ar);
+void ath12k_mac_11d_scan_stop_all(struct ath12k_base *ab);
+
 void ath12k_mac_destroy(struct ath12k_base *ab);
 void ath12k_mac_unregister(struct ath12k_base *ab);
 int ath12k_mac_register(struct ath12k_base *ab);
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 6ede91ebc8e1..c2f2fcce9fb1 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -88,9 +88,12 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 	if (ret)
 		ath12k_warn(ar->ab,
 			    "INIT Country code set to fw failed : %d\n", ret);
+
+	ath12k_mac_11d_scan_stop(ar);
+	ar->regdom_set_by_user = true;
 }
 
-int ath12k_reg_update_chan_list(struct ath12k *ar)
+int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
 {
 	struct ieee80211_supported_band **bands;
 	struct ath12k_wmi_scan_chan_list_arg *arg;
@@ -99,7 +102,35 @@ int ath12k_reg_update_chan_list(struct ath12k *ar)
 	struct ath12k_wmi_channel_arg *ch;
 	enum nl80211_band band;
 	int num_channels = 0;
-	int i, ret;
+	int i, ret, left;
+
+	if (wait && ar->state_11d != ATH12K_11D_IDLE) {
+		left = wait_for_completion_timeout(&ar->completed_11d_scan,
+						   ATH12K_SCAN_TIMEOUT_HZ);
+		if (!left) {
+			ath12k_dbg(ar->ab, ATH12K_DBG_REG,
+				   "failed to receive 11d scan complete: timed out\n");
+			ar->state_11d = ATH12K_11D_IDLE;
+		}
+		ath12k_dbg(ar->ab, ATH12K_DBG_REG,
+			   "reg 11d scan wait left time %d\n", left);
+	}
+
+	if (wait &&
+	    (ar->scan.state == ATH12K_SCAN_STARTING ||
+	    ar->scan.state == ATH12K_SCAN_RUNNING)) {
+		left = wait_for_completion_timeout(&ar->scan.completed,
+						   ATH12K_SCAN_TIMEOUT_HZ);
+		if (!left)
+			ath12k_dbg(ar->ab, ATH12K_DBG_REG,
+				   "failed to receive hw scan complete: timed out\n");
+
+		ath12k_dbg(ar->ab, ATH12K_DBG_REG,
+			   "reg hw scan wait left time %d\n", left);
+	}
+
+	if (ar->state == ATH12K_STATE_RESTARTING)
+		return 0;
 
 	bands = hw->wiphy->bands;
 	for (band = 0; band < NUM_NL80211_BANDS; band++) {
@@ -257,7 +288,7 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
 		goto err;
 
 	if (ar->state == ATH12K_STATE_ON) {
-		ret = ath12k_reg_update_chan_list(ar);
+		ret = ath12k_reg_update_chan_list(ar, true);
 		if (ret)
 			goto err;
 	}
diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h
index 56d009a47234..7e8f9d7970dd 100644
--- a/drivers/net/wireless/ath/ath12k/reg.h
+++ b/drivers/net/wireless/ath/ath12k/reg.h
@@ -90,6 +90,5 @@ struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
 						  struct ath12k_reg_info *reg_info,
 						  bool intersect);
 int ath12k_regd_update(struct ath12k *ar, bool init);
-int ath12k_reg_update_chan_list(struct ath12k *ar);
-
+int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait);
 #endif
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index aa87b559eff1..38ee268d6a73 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -160,6 +160,8 @@ 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_11D_NEW_COUNTRY_EVENT] = {
+		.min_len = sizeof(struct wmi_11d_new_cc_ev) },
 };
 
 static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len)
@@ -2110,7 +2112,10 @@ void ath12k_wmi_start_scan_init(struct ath12k *ar,
 {
 	/* setup commonly used values */
 	arg->scan_req_id = 1;
-	arg->scan_priority = WMI_SCAN_PRIORITY_LOW;
+	if (ar->state_11d == ATH12K_11D_PREPARING)
+		arg->scan_priority = WMI_SCAN_PRIORITY_MEDIUM;
+	else
+		arg->scan_priority = WMI_SCAN_PRIORITY_LOW;
 	arg->dwell_time_active = 50;
 	arg->dwell_time_active_2g = 0;
 	arg->dwell_time_passive = 150;
@@ -2880,6 +2885,75 @@ int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
 	return ret;
 }
 
+int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar,
+				       struct wmi_11d_scan_start_params *param)
+{
+	struct ath12k_wmi_pdev *wmi = ar->wmi;
+	struct wmi_11d_scan_start_cmd *cmd;
+	struct sk_buff *skb;
+	int ret;
+
+	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_11d_scan_start_cmd *)skb->data;
+	cmd->tlv_header =
+		ath12k_wmi_tlv_cmd_hdr(WMI_TAG_11D_SCAN_START_CMD,
+				       sizeof(*cmd));
+
+	cmd->vdev_id = cpu_to_le32(param->vdev_id);
+	cmd->scan_period_msec = cpu_to_le32(param->scan_period_msec);
+	cmd->start_interval_msec = cpu_to_le32(param->start_interval_msec);
+	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+		   "send 11d scan start vdev id %d period %d ms internal %d ms\n",
+		   param->vdev_id,
+		   param->scan_period_msec,
+		   param->start_interval_msec);
+
+	if (ret) {
+		ath12k_warn(ar->ab,
+			    "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id)
+{
+	struct ath12k_wmi_pdev *wmi = ar->wmi;
+	struct wmi_11d_scan_stop_cmd *cmd;
+	struct sk_buff *skb;
+	int ret;
+
+	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_11d_scan_stop_cmd *)skb->data;
+	cmd->tlv_header =
+		ath12k_wmi_tlv_cmd_hdr(WMI_TAG_11D_SCAN_STOP_CMD,
+				       sizeof(*cmd));
+
+	cmd->vdev_id = cpu_to_le32(vdev_id);
+	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+		   "send 11d scan stop vdev id %d\n",
+		   cmd->vdev_id);
+
+	if (ret) {
+		ath12k_warn(ar->ab,
+			    "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
 int
 ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id)
 {
@@ -5418,6 +5492,50 @@ static void ath12k_wmi_op_ep_tx_credits(struct ath12k_base *ab)
 	wake_up(&ab->wmi_ab.tx_credits_wq);
 }
 
+static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *skb)
+{
+	const struct wmi_11d_new_cc_ev *ev;
+	struct ath12k *ar;
+	struct ath12k_pdev *pdev;
+	const void **tb;
+	int ret, i;
+
+	tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT];
+	if (!ev) {
+		kfree(tb);
+		ath12k_warn(ab, "failed to fetch 11d new cc ev");
+		return -EPROTO;
+	}
+
+	spin_lock_bh(&ab->base_lock);
+	memcpy(&ab->new_alpha2, &ev->new_alpha2, 2);
+	spin_unlock_bh(&ab->base_lock);
+
+	ath12k_dbg(ab, ATH12K_DBG_WMI, "wmi 11d new cc %c%c\n",
+		   ab->new_alpha2[0],
+		   ab->new_alpha2[1]);
+
+	kfree(tb);
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+		ar->state_11d = ATH12K_11D_IDLE;
+		complete(&ar->completed_11d_scan);
+	}
+
+	queue_work(ab->workqueue, &ab->update_11d_work);
+
+	return 0;
+}
+
 static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,
 				       struct sk_buff *skb)
 {
@@ -6718,6 +6836,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_11D_NEW_COUNTRY_EVENTID:
+		ath12k_reg_11d_new_cc_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 8940b8154091..890063c9e268 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -3792,6 +3792,28 @@ struct wmi_init_country_cmd {
 	} cc_info;
 } __packed;
 
+struct wmi_11d_scan_start_params {
+	u32 vdev_id;
+	u32 scan_period_msec;
+	u32 start_interval_msec;
+};
+
+struct wmi_11d_scan_start_cmd {
+	__le32 tlv_header;
+	__le32 vdev_id;
+	__le32 scan_period_msec;
+	__le32 start_interval_msec;
+} __packed;
+
+struct wmi_11d_scan_stop_cmd {
+	__le32 tlv_header;
+	__le32 vdev_id;
+} __packed;
+
+struct wmi_11d_new_cc_ev {
+	__le32 new_alpha2;
+} __packed;
+
 struct wmi_delba_send_cmd {
 	__le32 tlv_header;
 	__le32 vdev_id;
@@ -4897,6 +4919,9 @@ int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar,
 					   dma_addr_t paddr, u8 tid,
 					   u8 ba_window_size_valid,
 					   u32 ba_window_size);
+int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar,
+				       struct wmi_11d_scan_start_params *param);
+int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id);
 int
 ath12k_wmi_rx_reord_queue_remove(struct ath12k *ar,
 				 struct ath12k_wmi_rx_reorder_queue_remove_arg *arg);
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 01:29:47 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 04:29:47 -0400
Subject: [PATCH 3/4] wifi: ath12k: avoid firmware crash when reg set for WCN7850
In-Reply-To: <20230906082948.18452-1-quic_wgong@quicinc.com>
References: <20230906082948.18452-1-quic_wgong@quicinc.com>
Message-ID: <20230906082948.18452-4-quic_wgong@quicinc.com>

For the NL80211_REGDOM_SET_BY_USER hint from cfg80211, it set the new
alpha2 code to ath12k, then ath12k send WMI_SET_INIT_COUNTRY_CMDID to
firmware for all chips currently. When test with WCN7850 chips,
this WMI CMD leads firmware crash.

For AP based chips(QCN92xx), WMI_SET_INIT_COUNTRY_CMDID is the correct
command use. However, for STATION based chips(WCN7850), it need to use
another WMI CMD, WMI_SET_CURRENT_COUNTRY_CMDID.

Add flag current_cc_support in hardware parameters. It is used to
distinguish AP/STA platform. After that, the firmware will work
normal and the regulatory feature works well for WCN7850.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/hw.c  |  3 +++
 drivers/net/wireless/ath/ath12k/hw.h  |  1 +
 drivers/net/wireless/ath/ath12k/reg.c | 29 ++++++++++++++++++---------
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 5991cc91cd00..c9ed4c0e0da5 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -907,6 +907,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+		.current_cc_support = false,
 	},
 	{
 		.name = "wcn7850 hw2.0",
@@ -964,6 +965,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
 					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
+		.current_cc_support = true,
 	},
 	{
 		.name = "qcn9274 hw2.0",
@@ -1019,6 +1021,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+		.current_cc_support = false,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e6c4223c283c..292c07bb1a8b 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -173,6 +173,7 @@ struct ath12k_hw_params {
 	bool tcl_ring_retry:1;
 	bool reoq_lut_support:1;
 	bool supports_shadow_regs:1;
+	bool current_cc_support:1;
 
 	u32 hal_desc_sz;
 	u32 num_tcl_banks;
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index c2f2fcce9fb1..97c93a4901e6 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -48,6 +48,7 @@ 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 wmi_set_current_country_params set_current_param = {};
 	struct ath12k *ar = hw->priv;
 	int ret;
 
@@ -76,18 +77,26 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 		return;
 	}
 
-	/* Set the country code to the firmware and wait for
-	 * the WMI_REG_CHAN_LIST_CC EVENT for updating the
-	 * reg info
+	/* Set the country code to the firmware. ath12k will subsequently receive
+	 * the WMI_REG_CHAN_LIST_CC EVENT for updating the regulatory info.
 	 */
-	arg.flags = ALPHA_IS_SET;
-	memcpy(&arg.cc_info.alpha2, request->alpha2, 2);
-	arg.cc_info.alpha2[2] = 0;
+	if (ar->ab->hw_params->current_cc_support) {
+		memcpy(&set_current_param.alpha2, request->alpha2, 2);
 
-	ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
-	if (ret)
-		ath12k_warn(ar->ab,
-			    "INIT Country code set to fw failed : %d\n", ret);
+		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
+		if (ret)
+			ath12k_warn(ar->ab,
+				    "failed set current country code: %d\n", ret);
+	} else {
+		arg.flags = ALPHA_IS_SET;
+		memcpy(&arg.cc_info.alpha2, request->alpha2, 2);
+		arg.cc_info.alpha2[2] = 0;
+
+		ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
+		if (ret)
+			ath12k_warn(ar->ab,
+				    "INIT Country code set to fw failed : %d\n", ret);
+	}
 
 	ath12k_mac_11d_scan_stop(ar);
 	ar->regdom_set_by_user = true;
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 01:29:48 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 04:29:48 -0400
Subject: [PATCH 4/4] wifi: ath12k: store and send country code to firmware after recovery
In-Reply-To: <20230906082948.18452-1-quic_wgong@quicinc.com>
References: <20230906082948.18452-1-quic_wgong@quicinc.com>
Message-ID: <20230906082948.18452-5-quic_wgong@quicinc.com>

Currently ath12k does not send the country code to firmware after device
recovery. As a result the regdomain info is reported from firmware by
default. Regdomain info is important, so ath12k also need to restore
it to the value which was used before recovery.

This is only needed for platforms which support the current_cc_support
hardware parameter.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c | 1 +
 drivers/net/wireless/ath/ath12k/core.h | 1 +
 drivers/net/wireless/ath/ath12k/mac.c  | 8 ++++++++
 drivers/net/wireless/ath/ath12k/reg.c  | 1 +
 4 files changed, 11 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 71450dc1f48d..4433d7701c67 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -696,6 +696,7 @@ static void ath12k_update_11d(struct work_struct *work)
 		pdev = &ab->pdevs[i];
 		ar = pdev->ar;
 
+		memcpy(&ar->alpha2, &set_current_param.alpha2, 2);
 		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
 		if (ret)
 			ath12k_warn(ar->ab,
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index ba8a4f968a3f..10fa9de15024 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -582,6 +582,7 @@ struct ath12k {
 	struct completion completed_11d_scan;
 	enum ath12k_11d_state state_11d;
 	bool regdom_set_by_user;
+	u8 alpha2[REG_ALPHA2_LEN + 1];
 };
 
 struct ath12k_band_cap {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 740e8045a6f1..0df154c34f8f 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -6908,6 +6908,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
 		ar->state = ATH12K_STATE_ON;
 		ieee80211_wake_queues(ar->hw);
 
+		if (ar->ab->hw_params->current_cc_support &&
+		    ar->alpha2[0] != 0 && ar->alpha2[1] != 0) {
+			struct wmi_set_current_country_params set_current_param = {};
+
+			memcpy(&set_current_param.alpha2, ar->alpha2, 2);
+			ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
+		}
+
 		if (ab->is_reset) {
 			recovery_count = atomic_inc_return(&ab->recovery_count);
 			ath12k_dbg(ab, ATH12K_DBG_BOOT, "recovery count %d\n",
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 97c93a4901e6..eb46bfc2b2b9 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -82,6 +82,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 	 */
 	if (ar->ab->hw_params->current_cc_support) {
 		memcpy(&set_current_param.alpha2, request->alpha2, 2);
+		memcpy(&ar->alpha2, &set_current_param.alpha2, 2);
 
 		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
 		if (ret)
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 01:57:46 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 04:57:46 -0400
Subject: [PATCH] wifi: ath12k: indicate scan complete for scan canceled when scan running
Message-ID: <20230906085746.18968-1-quic_wgong@quicinc.com>

ath12k prints "Received scan event for unknown vdev" when doing the
following test:
1. trigger scan
2. wait 0.2 second
3. iw reg set is issued or 11d scan complete event is sent from firmware

Reason is:
When iw reg set is issues or the 11d scan complete event is received, the
new country code will be set to the firmware, and the new regdomain info
indicated to ath12k, then the new channel list will be sent to the firmware.
The firmware will cancel the current scan after receiving WMI_SCAN_CHAN_LIST_CMDID
which is used for the new channel list, and the state of ath12k is
ATH12K_SCAN_RUNNING, then ath12k_get_ar_on_scan_abort() returns NULL and
ath12k_scan_event() returns at this point and does not indicate scan
completion to mac80211.

Indicate scan completion to mac80211 and get rid of the "Received scan
event for unknown vdev" print for the above case.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/wmi.c | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 9ed33e2d6da0..d30de487f43f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5862,8 +5862,9 @@ static void ath12k_mgmt_tx_compl_event(struct ath12k_base *ab, struct sk_buff *s
 	rcu_read_unlock();
 }
 
-static struct ath12k *ath12k_get_ar_on_scan_abort(struct ath12k_base *ab,
-						  u32 vdev_id)
+static struct ath12k *ath12k_get_ar_on_scan_state(struct ath12k_base *ab,
+						  u32 vdev_id,
+						  enum ath12k_scan_state state)
 {
 	int i;
 	struct ath12k_pdev *pdev;
@@ -5875,7 +5876,7 @@ static struct ath12k *ath12k_get_ar_on_scan_abort(struct ath12k_base *ab,
 			ar = pdev->ar;
 
 			spin_lock_bh(&ar->data_lock);
-			if (ar->scan.state == ATH12K_SCAN_ABORTING &&
+			if (ar->scan.state == state &&
 			    ar->scan.vdev_id == vdev_id) {
 				spin_unlock_bh(&ar->data_lock);
 				return ar;
@@ -5905,10 +5906,15 @@ static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb)
 	 * aborting scan's vdev id matches this event info.
 	 */
 	if (le32_to_cpu(scan_ev.event_type) == WMI_SCAN_EVENT_COMPLETED &&
-	    le32_to_cpu(scan_ev.reason) == WMI_SCAN_REASON_CANCELLED)
-		ar = ath12k_get_ar_on_scan_abort(ab, le32_to_cpu(scan_ev.vdev_id));
-	else
+	    le32_to_cpu(scan_ev.reason) == WMI_SCAN_REASON_CANCELLED) {
+		ar = ath12k_get_ar_on_scan_state(ab, le32_to_cpu(scan_ev.vdev_id),
+						 ATH12K_SCAN_ABORTING);
+		if (!ar)
+			ar = ath12k_get_ar_on_scan_state(ab, le32_to_cpu(scan_ev.vdev_id),
+							 ATH12K_SCAN_RUNNING);
+	} else {
 		ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(scan_ev.vdev_id));
+	}
 
 	if (!ar) {
 		ath12k_warn(ab, "Received scan event for unknown vdev");

base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 02:03:55 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 05:03:55 -0400
Subject: [PATCH] wifi: ath12k: change to treat alpha code na as world wide regdomain
Message-ID: <20230906090355.19181-1-quic_wgong@quicinc.com>

Some firmware versions for WCN7850 report the default regdomain with
alpha code "na" by default when load as a world wide regdomain,
ath12k should treat it as a world wide alpha code.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/wmi.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 9ed33e2d6da0..4ebc09b35892 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5390,7 +5390,13 @@ static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,
 
 static bool ath12k_reg_is_world_alpha(char *alpha)
 {
-	return alpha[0] == '0' && alpha[1] == '0';
+	if (alpha[0] == '0' && alpha[1] == '0')
+		return true;
+
+	if (alpha[0] == 'n' && alpha[1] == 'a')
+		return true;
+
+	return false;
 }
 
 static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)

base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 03:34:55 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 06:34:55 -0400
Subject: [PATCH 0/3] wifi: mac80211: change to match driver to support MLO connection
Message-ID: <20230906103458.24092-1-quic_wgong@quicinc.com>

Currently mac80211 use its default settings, it does not meet requirement
of some driver such as ath12k. So extend its interface to driver for MLO 
connection.

The default settings in mac80211 are:
1. all link address are random for station
2. active link is only for primary link for station.

primary link: the link used by the latest exchange of successful
(Re)Association Request/Response frames.

Wen Gong (3):
  wifi: mac80211: add support to allow driver to generate local link
    address for station
  wifi: mac80211: add support to allow driver to set active link while
    connection for station
  wifi: mac80211: update link RX NSS by ieee80211_sta_set_rx_nss() in
    ieee80211_assoc_config_link()

 include/net/mac80211.h    | 17 +++++++++++++
 net/mac80211/driver-ops.h | 42 ++++++++++++++++++++++++++++++++
 net/mac80211/link.c       |  8 +++++++
 net/mac80211/mlme.c       | 26 +++++++++++++++-----
 net/mac80211/trace.h      | 50 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 137 insertions(+), 6 deletions(-)


base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 03:34:56 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 06:34:56 -0400
Subject: [PATCH 1/3] wifi: mac80211: add support to allow driver to generate local link address for station
In-Reply-To: <20230906103458.24092-1-quic_wgong@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
Message-ID: <20230906103458.24092-2-quic_wgong@quicinc.com>

Currently the local link address of all links is random generated by
eth_random_addr() in mac80211 while connecting to a MLO AP for station
mode. The MAC address of link is not passed from NL command. The 1st
link address is generated while authenticate with AP, the other links'
addresses are generated after assoc success with AP.

It is not convenient for some driver, reason is, for station mode,
the interface with its mac address is already created in driver after
wlan load, it is used for hw scan and non-MLO connection.

When connecting to MLO AP, driver reuse the interface as the 1st link of
MLO. If the mac address of the 1st link changed to a new value, then
driver need to change the mac address and do many synchronous operation
with firmware. Thus the operation become complex. After MLO disconnect,
driver need to restore the old mac address, it is also another complex
operation.

The hw scan maybe happen through the MLO connection/disconnection. And
the hw scan uses the 1st link address while MLO connected and uses the
interface address while MLO is disconnected, this leads hw scan complex.

Hence add this interface to allow driver to generate the address of each
link while MLO connection. Then driver could provide the same mac address
for the 1st link, thus hw scan/NON-MLO connection/1st link of MLO will use
the same mac address, then operation become easy.

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 include/net/mac80211.h    |  7 +++++++
 net/mac80211/driver-ops.h | 21 +++++++++++++++++++++
 net/mac80211/mlme.c       | 24 ++++++++++++++++++------
 net/mac80211/trace.h      | 27 +++++++++++++++++++++++++++
 4 files changed, 73 insertions(+), 6 deletions(-)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 3a8a2d2c58c3..c7f92a3db359 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3746,6 +3746,11 @@ struct ieee80211_prep_tx_info {
  *	non-MLO connections.
  *	The callback can sleep.
  *
+ * @generate_link_addr: Generate mac address of link.
+ *	This callback is optional. Returns zero if mac address is generated successfully
+ *	for the link.
+ *	This callback can sleep.
+ *
  * @prepare_multicast: Prepare for multicast filter configuration.
  *	This callback is optional, and its return value is passed
  *	to configure_filter(). This callback must be atomic.
@@ -4298,6 +4303,8 @@ struct ieee80211_ops {
 				  struct ieee80211_bss_conf *info,
 				  u64 changed);
 
+	int (*generate_link_addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+				  unsigned int link_id, u8 *link_local_addr);
 	int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			struct ieee80211_bss_conf *link_conf);
 	void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index c4505593ba7a..da164d4ca9a1 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -962,6 +962,27 @@ int drv_switch_vif_chanctx(struct ieee80211_local *local,
 			   struct ieee80211_vif_chanctx_switch *vifs,
 			   int n_vifs, enum ieee80211_chanctx_switch_mode mode);
 
+static inline int drv_generate_link_addr(struct ieee80211_local *local,
+					 struct ieee80211_sub_if_data *sdata,
+					 unsigned int link_id, u8 *link_local_addr)
+{
+	int ret = -EOPNOTSUPP;
+
+	might_sleep();
+
+	if (!check_sdata_in_driver(sdata))
+		return -EIO;
+
+	if (local->ops->generate_link_addr) {
+		ret = local->ops->generate_link_addr(&local->hw, &sdata->vif,
+						     link_id, link_local_addr);
+		trace_drv_generate_link_addr(local, sdata, link_local_addr, link_id);
+	}
+
+	trace_drv_return_int(local, ret);
+	return ret;
+}
+
 static inline int drv_start_ap(struct ieee80211_local *local,
 			       struct ieee80211_sub_if_data *sdata,
 			       struct ieee80211_bss_conf *link_conf)
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f93eb38ae0b8..1679d5011fb6 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -6852,6 +6852,7 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link)
 	struct ieee80211_sub_if_data *sdata = link->sdata;
 	struct ieee80211_local *local = sdata->local;
 	unsigned int link_id = link->link_id;
+	int ret;
 
 	link->u.mgd.p2p_noa_index = -1;
 	link->u.mgd.conn_flags = 0;
@@ -6867,11 +6868,15 @@ void ieee80211_mgd_setup_link(struct ieee80211_link_data *link)
 	wiphy_delayed_work_init(&link->u.mgd.chswitch_work,
 				ieee80211_chswitch_work);
 
-	if (sdata->u.mgd.assoc_data)
+	if (sdata->u.mgd.assoc_data) {
 		ether_addr_copy(link->conf->addr,
 				sdata->u.mgd.assoc_data->link[link_id].addr);
-	else if (!is_valid_ether_addr(link->conf->addr))
-		eth_random_addr(link->conf->addr);
+	} else if (!is_valid_ether_addr(link->conf->addr)) {
+		ret = drv_generate_link_addr(sdata->local, sdata,
+					     link_id, link->conf->addr);
+		if (ret)
+			eth_random_addr(link->conf->addr);
+	}
 }
 
 /* scan finished notification */
@@ -7448,11 +7453,18 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 			if (!req->links[i].bss)
 				continue;
 			link = sdata_dereference(sdata->link[i], sdata);
-			if (link)
+			if (link) {
 				ether_addr_copy(assoc_data->link[i].addr,
 						link->conf->addr);
-			else
-				eth_random_addr(assoc_data->link[i].addr);
+			} else {
+				u8 *link_addr = assoc_data->link[i].addr;
+				int ret;
+
+				ret = drv_generate_link_addr(sdata->local, sdata,
+							     i, link_addr);
+				if (ret)
+					eth_random_addr(link_addr);
+			}
 		}
 	} else {
 		memcpy(assoc_data->link[0].addr, sdata->vif.addr, ETH_ALEN);
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index b8c53b4a710b..b140a4e70df9 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -727,6 +727,33 @@ TRACE_EVENT(drv_sw_scan_start,
 		  LOCAL_PR_ARG, VIF_PR_ARG, __entry->mac_addr)
 );
 
+TRACE_EVENT(drv_generate_link_addr,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 const u8 *mac_addr,
+		 unsigned int link_id),
+
+	TP_ARGS(local, sdata, mac_addr, link_id),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__array(char, mac_addr, ETH_ALEN)
+		__field(unsigned int, link_id)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		memcpy(__entry->mac_addr, mac_addr, ETH_ALEN);
+		__entry->link_id = link_id;
+	),
+
+	TP_printk(LOCAL_PR_FMT ", " VIF_PR_FMT ", link addr: %pM link id: %#x",
+		  LOCAL_PR_ARG, VIF_PR_ARG, __entry->mac_addr,
+		  __entry->link_id)
+);
+
 DEFINE_EVENT(local_sdata_evt, drv_sw_scan_complete,
 	TP_PROTO(struct ieee80211_local *local,
 		 struct ieee80211_sub_if_data *sdata),
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 03:34:58 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 06:34:58 -0400
Subject: [PATCH 3/3] wifi: mac80211: update link RX NSS by ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link()
In-Reply-To: <20230906103458.24092-1-quic_wgong@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
Message-ID: <20230906103458.24092-4-quic_wgong@quicinc.com>

Currently for MLO connection, only deflink's rx_nss is set to correct
value. The others links' rx_nss of struct ieee80211_link_sta is
value 0 in ieee80211_set_associated(), because they are not pass into
ieee80211_sta_set_rx_nss() in mac80211 except the deflink in
rate_control_rate_init(). This leads driver get NSS = 0 for other links.
Add the ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link(),
then the other links' rx_nss will be set to the correct value.

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 net/mac80211/mlme.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1679d5011fb6..0a2fb660fa00 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4354,6 +4354,8 @@ static bool ieee80211_assoc_config_link(struct ieee80211_link_data *link,
 	bss_conf->assoc_capability = capab_info;
 
 	ret = true;
+
+	ieee80211_sta_set_rx_nss(link_sta);
 out:
 	kfree(elems);
 	kfree(bss_ies);
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep  6 03:34:57 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 6 Sep 2023 06:34:57 -0400
Subject: [PATCH 2/3] wifi: mac80211: add support to allow driver to set active link while connection for station
In-Reply-To: <20230906103458.24092-1-quic_wgong@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
Message-ID: <20230906103458.24092-3-quic_wgong@quicinc.com>

There are 2 fields valid_links and active_links in struct ieee80211_vif
of mac80211. For station mode, valid_links is always include the bitmap
of active_links. valid_links stores the bitmap of links which is created
in mac80211, and mac80211 only indicate the info of links which is existed
in active_links to driver. Finally, the active_links is the bitmap of
links which station can interactive with MLO AP it is connected to.

Currently the active links is always only contain the primary link,
primary link means the link used by the latest exchange of successful
(Re)Association Request/Response frames. Then it will always have only
one link in driver after connected.

Hence add this ops in struct ieee80211_ops to allow driver to determine
the active links bit map dynamically while connecting to MLO AP.

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 include/net/mac80211.h    | 10 ++++++++++
 net/mac80211/driver-ops.h | 21 +++++++++++++++++++++
 net/mac80211/link.c       |  8 ++++++++
 net/mac80211/trace.h      | 23 +++++++++++++++++++++++
 4 files changed, 62 insertions(+)

diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index c7f92a3db359..c50f1a99ccd5 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3732,6 +3732,14 @@ struct ieee80211_prep_tx_info {
  *	Note: this callback is called if @vif_cfg_changed or @link_info_changed
  *	are not implemented.
  *
+ * @calculate_active_links: Prepare for bit maps of links to active.
+ *	This callback is optional. The @new_links parameter is all links bit map
+ *	that mac80211 has capability to activate. Returns non-zero if driver handled
+ *	the @new_links, and the returned non-zero value is the bit map of the links
+ *	that driver allows to active. The bitmap of returned non-zero value may be
+ *	a subset of the @new_links. Return zero if driver not handled this.
+ *	This callback can sleep.
+ *
  * @vif_cfg_changed: Handler for configuration requests related to interface
  *	(MLD) parameters from &struct ieee80211_vif_cfg that vary during the
  *	lifetime of the interface (e.g. assoc status, IP addresses, etc.)
@@ -4295,6 +4303,8 @@ struct ieee80211_ops {
 				 struct ieee80211_vif *vif,
 				 struct ieee80211_bss_conf *info,
 				 u64 changed);
+	u16 (*calculate_active_links)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+			    u16 new_links);
 	void (*vif_cfg_changed)(struct ieee80211_hw *hw,
 				struct ieee80211_vif *vif,
 				u64 changed);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index da164d4ca9a1..d2a8bf5341b5 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -950,6 +950,27 @@ static inline void drv_verify_link_exists(struct ieee80211_sub_if_data *sdata,
 		sdata_assert_lock(sdata);
 }
 
+static inline u16 drv_calculate_active_links(struct ieee80211_local *local,
+				   struct ieee80211_sub_if_data *sdata,
+				   u16 new_links)
+{
+	u16 active_links = 0;
+
+	might_sleep();
+
+	if (!check_sdata_in_driver(sdata))
+		return active_links;
+
+	trace_drv_calculate_active_links(local, sdata, new_links);
+	if (local->ops->calculate_active_links)
+		active_links = local->ops->calculate_active_links(&local->hw,
+								  &sdata->vif,
+								  new_links);
+
+	trace_drv_return_int(local, active_links);
+	return active_links;
+}
+
 int drv_assign_vif_chanctx(struct ieee80211_local *local,
 			   struct ieee80211_sub_if_data *sdata,
 			   struct ieee80211_bss_conf *link_conf,
diff --git a/net/mac80211/link.c b/net/mac80211/link.c
index 6148208b320e..7ce229a64a7b 100644
--- a/net/mac80211/link.c
+++ b/net/mac80211/link.c
@@ -146,6 +146,7 @@ static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
 {
 	sdata->vif.valid_links = valid_links;
 	sdata->vif.dormant_links = dormant_links;
+	u16 active_links;
 
 	if (!valid_links ||
 	    WARN((~valid_links & dormant_links) ||
@@ -166,6 +167,13 @@ static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
 		WARN_ON(dormant_links);
 		break;
 	case NL80211_IFTYPE_STATION:
+		active_links = drv_calculate_active_links(sdata->local, sdata,
+							  valid_links & ~dormant_links);
+		if (active_links) {
+			sdata->vif.active_links = active_links;
+			break;
+		}
+
 		if (sdata->vif.active_links)
 			break;
 		sdata->vif.active_links = valid_links & ~dormant_links;
diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h
index b140a4e70df9..eb458c236101 100644
--- a/net/mac80211/trace.h
+++ b/net/mac80211/trace.h
@@ -652,6 +652,29 @@ TRACE_EVENT(drv_set_key,
 	)
 );
 
+TRACE_EVENT(drv_calculate_active_links,
+	TP_PROTO(struct ieee80211_local *local,
+		 struct ieee80211_sub_if_data *sdata,
+		 u16 new_links),
+
+	TP_ARGS(local, sdata, new_links),
+
+	TP_STRUCT__entry(
+		LOCAL_ENTRY
+		VIF_ENTRY
+		__field(unsigned int, new_links)
+	),
+
+	TP_fast_assign(
+		LOCAL_ASSIGN;
+		VIF_ASSIGN;
+		__entry->new_links = new_links;
+	),
+
+	TP_printk(LOCAL_PR_FMT ", " VIF_PR_FMT ", new_links: %u",
+		  LOCAL_PR_ARG, VIF_PR_ARG, __entry->new_links)
+);
+
 TRACE_EVENT(drv_update_tkip_key,
 	TP_PROTO(struct ieee80211_local *local,
 		 struct ieee80211_sub_if_data *sdata,
-- 
2.40.1



From quic_lingbok at quicinc.com  Wed Sep  6 04:04:12 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Wed, 6 Sep 2023 19:04:12 +0800
Subject: [PATCH v2] wifi: ath12k: add support for hardware rfkill for WCN7850
Message-ID: <20230906110412.182176-1-quic_lingbok@quicinc.com>

When hardware rfkill is enabled in the firmware, it will report the
capability using WMI_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY event
to the host. Currently ath12k does not process this service capability. In
order to support this, update ath12k to check if the capability is enabled,
if so, send the GPIO information to firmware. When the firmware detects
hardware rfkill is enabled by the user, it will report it using
WMI_RFKILL_STATE_CHANGE_EVENTID. When ath12k receive the event, it will set
the value of rfkill_radio_on based on whether radio_state is equal to
WMI_RFKILL_RADIO_STATE_ON, then send WMI_PDEV_PARAM_RFKILL_ENABLE to
firmware.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v2:
1.s/via//
2.modify commit log
3.use an endian-conversion macro

 drivers/net/wireless/ath/ath12k/core.c | 52 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/core.h |  4 ++
 drivers/net/wireless/ath/ath12k/hw.c   | 12 ++++++
 drivers/net/wireless/ath/ath12k/hw.h   |  4 ++
 drivers/net/wireless/ath/ath12k/mac.c  | 58 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/mac.h  |  2 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 39 +++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  | 25 +++++++++++
 8 files changed, 196 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 39f938fafa81..c6fb1e435d86 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -19,6 +19,27 @@ unsigned int ath12k_debug_mask;
 module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
 MODULE_PARM_DESC(debug_mask, "Debugging mask");
 
+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;
+
+	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;
+}
+
 int ath12k_core_suspend(struct ath12k_base *ab)
 {
 	int ret;
@@ -603,6 +624,13 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
 		goto err_core_stop;
 	}
 	ath12k_hif_irq_enable(ab);
+
+	ret = ath12k_core_rfkill_config(ab);
+	if (ret && ret != -EOPNOTSUPP) {
+		ath12k_err(ab, "failed to config rfkill: %d\n", ret);
+		goto err_core_stop;
+	}
+
 	mutex_unlock(&ab->core_lock);
 
 	return 0;
@@ -655,6 +683,27 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab)
 	return ret;
 }
 
+static void ath12k_rfkill_work(struct work_struct *work)
+{
+	struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work);
+	struct ath12k *ar;
+	bool rfkill_radio_on;
+	int i;
+
+	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)
+			continue;
+
+		ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on);
+		wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on);
+	}
+}
+
 void ath12k_core_halt(struct ath12k *ar)
 {
 	struct ath12k_base *ab = ar->ab;
@@ -668,6 +717,7 @@ void ath12k_core_halt(struct ath12k *ar)
 	ath12k_mac_peer_cleanup_all(ar);
 	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->regd_update_work);
+	cancel_work_sync(&ab->rfkill_work);
 
 	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
 	synchronize_rcu();
@@ -921,6 +971,8 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 	init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
 	INIT_WORK(&ab->restart_work, ath12k_core_restart);
 	INIT_WORK(&ab->reset_work, ath12k_core_reset);
+	INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work);
+
 	timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
 	init_completion(&ab->htc_suspend);
 
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d873b573dac6..3f5f0471f640 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -771,6 +771,10 @@ struct ath12k_base {
 	u64 fw_soc_drop_count;
 	bool static_window_map;
 
+	struct work_struct rfkill_work;
+	/* true means radio is on */
+	bool rfkill_radio_on;
+
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 5991cc91cd00..f69649f58e82 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -907,6 +907,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.rfkill_pin = 0,
+		.rfkill_cfg = 0,
+		.rfkill_on_level = 0,
 	},
 	{
 		.name = "wcn7850 hw2.0",
@@ -964,6 +968,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
 					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
+
+		.rfkill_pin = 48,
+		.rfkill_cfg = 0,
+		.rfkill_on_level = 1,
 	},
 	{
 		.name = "qcn9274 hw2.0",
@@ -1019,6 +1027,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.rfkill_pin = 0,
+		.rfkill_cfg = 0,
+		.rfkill_on_level = 0,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e6c4223c283c..1b4912bf57ad 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -186,6 +186,10 @@ struct ath12k_hw_params {
 	const struct hal_ops *hal_ops;
 
 	u64 qmi_cnss_feature_bitmap;
+
+	u32 rfkill_pin;
+	u32 rfkill_cfg;
+	u32 rfkill_on_level;
 };
 
 struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 8cc9ae2204b8..bfba9ad18776 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5108,6 +5108,63 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
 	return ret;
 }
 
+int ath12k_mac_rfkill_config(struct ath12k *ar)
+{
+	struct ath12k_base *ab = ar->ab;
+	u32 param;
+	int ret;
+
+	if (ab->hw_params->rfkill_pin == 0)
+		return -EOPNOTSUPP;
+
+	ath12k_dbg(ab, ATH12K_DBG_MAC,
+		   "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d",
+		   ab->hw_params->rfkill_pin, ab->hw_params->rfkill_cfg,
+		   ab->hw_params->rfkill_on_level);
+
+	param = u32_encode_bits(ab->hw_params->rfkill_on_level,
+				WMI_RFKILL_CFG_RADIO_LEVEL) |
+		u32_encode_bits(ab->hw_params->rfkill_pin,
+				WMI_RFKILL_CFG_GPIO_PIN_NUM) |
+		u32_encode_bits(ab->hw_params->rfkill_cfg,
+				WMI_RFKILL_CFG_PIN_AS_GPIO);
+
+	ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_HW_RFKILL_CONFIG,
+					param, ar->pdev->pdev_id);
+	if (ret) {
+		ath12k_warn(ab,
+			    "failed to set rfkill config 0x%x: %d\n",
+			    param, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable)
+{
+	enum wmi_rfkill_enable_radio param;
+	int ret;
+
+	if (enable)
+		param = WMI_RFKILL_ENABLE_RADIO_ON;
+	else
+		param = WMI_RFKILL_ENABLE_RADIO_OFF;
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac %d rfkill enable %d",
+		   ar->pdev_idx, param);
+
+	ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RFKILL_ENABLE,
+					param, ar->pdev->pdev_id);
+	if (ret) {
+		ath12k_warn(ar->ab, "failed to set rfkill enable param %d: %d\n",
+			    param, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
 static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
 {
 	struct ath12k *ar = hw->priv;
@@ -5128,6 +5185,7 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
 
 	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->regd_update_work);
+	cancel_work_sync(&ar->ab->rfkill_work);
 
 	spin_lock_bh(&ar->data_lock);
 	list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 7b16b70df4fa..59b4e8f5eee0 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -73,4 +73,6 @@ int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
 enum rate_info_bw ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw);
 enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw bw);
 enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher);
+int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
+int ath12k_mac_rfkill_config(struct ath12k *ar);
 #endif
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index f48ab69e256a..5bd357ea8a75 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -152,6 +152,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
 		.min_len = sizeof(struct wmi_service_available_event) },
 	[WMI_TAG_PEER_ASSOC_CONF_EVENT] = {
 		.min_len = sizeof(struct wmi_peer_assoc_conf_event) },
+	[WMI_TAG_RFKILL_EVENT] = {
+		.min_len = sizeof(struct wmi_rfkill_state_change_event) },
 	[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] = {
 		.min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },
 	[WMI_TAG_HOST_SWFDA_EVENT] = {
@@ -6602,6 +6604,40 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
 	kfree(tb);
 }
 
+static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
+					     struct sk_buff *skb)
+{
+	const struct wmi_rfkill_state_change_event *ev;
+	const void **tb;
+	int ret;
+
+	tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
+		return;
+	}
+
+	ev = tb[WMI_TAG_RFKILL_EVENT];
+	if (!ev) {
+		kfree(tb);
+		return;
+	}
+
+	ath12k_dbg(ab, ATH12K_DBG_MAC,
+		   "wmi tlv rfkill state change gpio %d type %d radio_state %d\n",
+		   le32_to_cpu(ev->gpio_pin_num),
+		   le32_to_cpu(ev->int_type),
+		   le32_to_cpu(ev->radio_state));
+
+	spin_lock_bh(&ab->base_lock);
+	ab->rfkill_radio_on = (ev->radio_state == cpu_to_le32(WMI_RFKILL_RADIO_STATE_ON));
+	spin_unlock_bh(&ab->base_lock);
+
+	queue_work(ab->workqueue, &ab->rfkill_work);
+	kfree(tb);
+}
+
 static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
 {
 	struct wmi_cmd_hdr *cmd_hdr;
@@ -6694,6 +6730,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
 	case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID:
 		ath12k_probe_resp_tx_status_event(ab, skb);
 		break;
+	case WMI_RFKILL_STATE_CHANGE_EVENTID:
+		ath12k_rfkill_state_change_event(ab, skb);
+		break;
 	/* add Unsupported events here */
 	case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
 	case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c75a6fa1f7e0..965755b4cbfd 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4793,6 +4793,31 @@ struct ath12k_wmi_base {
 
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
+enum wmi_sys_cap_info_flags {
+	WMI_SYS_CAP_INFO_RXTX_LED	= BIT(0),
+	WMI_SYS_CAP_INFO_RFKILL		= BIT(1),
+};
+
+#define WMI_RFKILL_CFG_GPIO_PIN_NUM		GENMASK(5, 0)
+#define WMI_RFKILL_CFG_RADIO_LEVEL		BIT(6)
+#define WMI_RFKILL_CFG_PIN_AS_GPIO		GENMASK(10, 7)
+
+enum wmi_rfkill_enable_radio {
+	WMI_RFKILL_ENABLE_RADIO_ON	= 0,
+	WMI_RFKILL_ENABLE_RADIO_OFF	= 1,
+};
+
+enum wmi_rfkill_radio_state {
+	WMI_RFKILL_RADIO_STATE_OFF	= 1,
+	WMI_RFKILL_RADIO_STATE_ON	= 2,
+};
+
+struct wmi_rfkill_state_change_event {
+	__le32 gpio_pin_num;
+	__le32 int_type;
+	__le32 radio_state;
+} __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,

base-commit: 1b5b69a51bb4909844e4003920af09ca1cc6bb0e
-- 
2.34.1



From quic_lingbok at quicinc.com  Wed Sep  6 05:35:16 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Wed, 6 Sep 2023 20:35:16 +0800
Subject: [PATCH v2 0/4] wifi: ath12k: implement some functionalities through reading ACPI Table
Message-ID: <20230906123520.184726-1-quic_lingbok@quicinc.com>

Through reading ACPI table, implement Time-Average-SAR(TAS), BIOS SAR,
configuration of CCA threshold and band edge channel power functionalities.

v2:
1.put <linux/acpi.h> in the include guard

Lingbo Kong (4):
  wifi: ath12k: add TAS capability for WCN7850
  wifi: ath12k: add BIOS SAR capability for WCN7850
  wifi: ath12k: adjust configuration of CCA threshold value
  wifi: ath12k: add band edge channel power for WCN7850

 drivers/net/wireless/ath/ath12k/Makefile |   3 +-
 drivers/net/wireless/ath/ath12k/acpi.c   | 365 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h   |  55 ++++
 drivers/net/wireless/ath/ath12k/core.c   |   6 +
 drivers/net/wireless/ath/ath12k/core.h   |  13 +
 drivers/net/wireless/ath/ath12k/hw.c     |  10 +
 drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
 drivers/net/wireless/ath/ath12k/pci.c    |   6 +
 drivers/net/wireless/ath/ath12k/wmi.c    | 258 ++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h    |  47 ++-
 10 files changed, 764 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h


base-commit: 1b5b69a51bb4909844e4003920af09ca1cc6bb0e
-- 
2.34.1



From quic_lingbok at quicinc.com  Wed Sep  6 05:35:17 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Wed, 6 Sep 2023 20:35:17 +0800
Subject: [PATCH v2 1/4] wifi: ath12k: add TAS capability for WCN7850
In-Reply-To: <20230906123520.184726-1-quic_lingbok@quicinc.com>
References: <20230906123520.184726-1-quic_lingbok@quicinc.com>
Message-ID: <20230906123520.184726-2-quic_lingbok@quicinc.com>

In order to enable Time-Average-SAR(TAS) for WCN7850, define some
functions. One function is to return TAS configuration, the other return
SAR power table, then ath12k apply these data to wlan firmware. ath12k
register an ACPI event callback so that ACPI can notify ath12k to retrieve
the updated SAR power table and apply it to wlan firmware.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v2:
1.put <linux/acpi.h> in the include guard

 drivers/net/wireless/ath/ath12k/Makefile |   3 +-
 drivers/net/wireless/ath/ath12k/acpi.c   | 203 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h   |  28 ++++
 drivers/net/wireless/ath/ath12k/core.c   |   6 +
 drivers/net/wireless/ath/ath12k/core.h   |   8 +
 drivers/net/wireless/ath/ath12k/hw.c     |  10 ++
 drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
 drivers/net/wireless/ath/ath12k/pci.c    |   6 +
 drivers/net/wireless/ath/ath12k/wmi.c    |  82 +++++++++
 drivers/net/wireless/ath/ath12k/wmi.h    |  20 ++-
 10 files changed, 367 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h

diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile
index 62c52e733b5e..a479fe06caac 100644
--- a/drivers/net/wireless/ath/ath12k/Makefile
+++ b/drivers/net/wireless/ath/ath12k/Makefile
@@ -19,7 +19,8 @@ ath12k-y += core.o \
 	    hw.o \
 	    mhi.o \
 	    pci.o \
-	    dp_mon.o
+	    dp_mon.o \
+	    acpi.o
 
 ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
 
diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
new file mode 100644
index 000000000000..384e01748b32
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -0,0 +1,203 @@
+// 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.
+ */
+
+#include "core.h"
+#include "acpi.h"
+#include "debug.h"
+
+static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
+{
+	union acpi_object *obj;
+	acpi_handle root_handle;
+	int ret = 0;
+
+	root_handle = ACPI_HANDLE(ab->dev);
+	if (!root_handle) {
+		ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid ACPI handler\n");
+		return -EOPNOTSUPP;
+	}
+
+	obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,
+				NULL);
+
+	if (!obj) {
+		ath12k_dbg(ab, ATH12K_DBG_BOOT, "ACPI _DSM method invocation failed\n");
+		return -ENOENT;
+	}
+
+	if (obj->type == ACPI_TYPE_INTEGER) {
+		ab->acdata->func_bit = obj->integer.value;
+	} else if (obj->type == ACPI_TYPE_BUFFER) {
+		switch (func) {
+		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
+				ath12k_err(ab, "Invalid TAS cfg size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->tas_cfg, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {
+				ath12k_err(ab, "Invalid TAS data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		}
+	} else {
+		ath12k_err(ab,
+			   "ACPI: DSM method did not return a valid object, type %d\n",
+			   obj->type);
+		ret = -EINVAL;
+	}
+
+out:
+	ACPI_FREE(obj);
+	return ret;
+}
+
+static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
+{
+	int ret;
+
+	if (ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
+	    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG) {
+		ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
+							       ab->acdata->tas_sar_power_table);
+		if (ret)
+			ath12k_err(ab, "failed to pass tas data table %d\n", ret);
+	} else {
+		ath12k_err(ab, "the latest tas data is invalid\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
+{
+	int ret;
+	struct ath12k_base *ab = data;
+
+	if (event == ATH12K_ACPI_NOTIFY_EVENT) {
+		if (ab->acdata->acpi_tas_enable) {
+			ret = ath12k_acpi_dsm_get_data(ab,
+						       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
+			if (ret) {
+				ath12k_err(ab, "failed to update tas data table %d\n", ret);
+				return;
+			}
+
+			ret = ath12k_set_tas_power_limit_data(ab);
+			if (ret)
+				return;
+		}
+	} else {
+		ath12k_err(ab, "unknown acpi notify %u\n", event);
+	}
+}
+
+void ath12k_acpi_remove_notify(struct ath12k_base *ab)
+{
+	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+				   ACPI_DEVICE_NOTIFY,
+				   acpi_dsm_notify);
+}
+
+static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
+{
+	int ret;
+
+	ret = ath12k_wmi_pdev_set_tas_cfg_table_param(ab,
+						      ab->acdata->tas_cfg);
+	if (ret) {
+		ath12k_err(ab, "failed to pass tas cfg table to fw %d\n", ret);
+		return ret;
+	}
+
+	ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
+						       ab->acdata->tas_sar_power_table);
+	if (ret)
+		ath12k_err(ab, "failed to pass tas data table to fw %d\n", ret);
+
+	return ret;
+}
+
+int ath12k_get_acpi_all_data(struct ath12k_base *ab)
+{
+	int ret;
+	acpi_status status;
+
+	ab->acdata = kzalloc(sizeof(*ab->acdata), GFP_KERNEL);
+	if (!ab->acdata)
+		return -ENOMEM;
+
+	ab->acdata->acpi_tas_enable = false;
+
+	ret = ath12k_acpi_dsm_get_data(ab,
+				       ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS);
+
+	if (ret)
+		return ret;
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG);
+		if (ret) {
+			ath12k_err(ab, "failed to get tas cfg table %d\n", ret);
+			goto err_free_acdata;
+		}
+	}
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
+		if (ret) {
+			ath12k_err(ab, "failed to get tas data table %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&
+		    ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
+		    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG)
+			ab->acdata->acpi_tas_enable = true;
+	}
+
+	if (ab->acdata->acpi_tas_enable) {
+		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
+		if (ret)
+			goto err_free_acdata;
+	}
+
+	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
+					     ACPI_DEVICE_NOTIFY,
+					     acpi_dsm_notify, ab);
+	if (ACPI_FAILURE(status)) {
+		ath12k_err(ab, "failed to install DSM notify callback\n");
+		goto err_remove_notify;
+	}
+
+	return 0;
+
+err_remove_notify:
+	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+				   ACPI_DEVICE_NOTIFY,
+				   acpi_dsm_notify);
+
+	ret = -EIO;
+
+err_free_acdata:
+	kfree(ab->acdata);
+	ab->acdata = NULL;
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
new file mode 100644
index 000000000000..e6eb6f02d524
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -0,0 +1,28 @@
+/* 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.
+ */
+#ifndef ATH12K_ACPI_H
+#define ATH12K_ACPI_H
+
+#include <linux/acpi.h>
+
+#define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
+#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
+#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
+
+#define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
+#define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
+#define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
+#define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
+
+#define ATH12K_ACPI_NOTIFY_EVENT			0x86
+#define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
+
+#define ATH12K_ACPI_TAS_DATA_VERSION		0x1
+#define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
+
+int ath12k_get_acpi_all_data(struct ath12k_base *ab);
+void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
+#endif
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 39f938fafa81..457261c7a0e9 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -538,6 +538,12 @@ static int ath12k_core_start(struct ath12k_base *ab,
 		goto err_reo_cleanup;
 	}
 
+	if (!guid_is_null(ab->hw_params->acpi_guid)) {
+		ret = ath12k_get_acpi_all_data(ab);
+		if (!ret)
+			ath12k_info(ab, "success to get acpi cfg data\n");
+	}
+
 	return 0;
 
 err_reo_cleanup:
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d873b573dac6..cba4f176c018 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -22,6 +22,7 @@
 #include "hal_rx.h"
 #include "reg.h"
 #include "dbring.h"
+#include "acpi.h"
 
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
 
@@ -771,6 +772,13 @@ struct ath12k_base {
 	u64 fw_soc_drop_count;
 	bool static_window_map;
 
+	struct {
+		u32 func_bit;
+		bool acpi_tas_enable;
+		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
+		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
+	} *acdata;
+
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 5991cc91cd00..f0f7f9dbb08a 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -15,6 +15,10 @@
 #include "mhi.h"
 #include "dp_rx.h"
 
+static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec,
+					     0x90, 0xd6, 0x02, 0x42,
+					     0xac, 0x12, 0x00, 0x03);
+
 static u8 ath12k_hw_qcn9274_mac_from_pdev_id(int pdev_idx)
 {
 	return pdev_idx;
@@ -907,6 +911,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.acpi_guid = NULL,
 	},
 	{
 		.name = "wcn7850 hw2.0",
@@ -964,6 +970,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
 					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
+
+		.acpi_guid = &wcn7850_uuid,
 	},
 	{
 		.name = "qcn9274 hw2.0",
@@ -1019,6 +1027,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.acpi_guid = NULL,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e6c4223c283c..ab409e8ae268 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -8,7 +8,7 @@
 #define ATH12K_HW_H
 
 #include <linux/mhi.h>
-
+#include <linux/uuid.h>
 #include "wmi.h"
 #include "hal.h"
 
@@ -186,6 +186,8 @@ struct ath12k_hw_params {
 	const struct hal_ops *hal_ops;
 
 	u64 qmi_cnss_feature_bitmap;
+
+	const guid_t *acpi_guid;
 };
 
 struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index bd689efa7daa..3c2967e760ab 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1340,6 +1340,12 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
 
 	ath12k_hal_srng_deinit(ab);
 	ath12k_ce_free_pipes(ab);
+	if (!guid_is_null(ab->hw_params->acpi_guid) && ab->acdata) {
+		acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+					   ACPI_DEVICE_NOTIFY,
+					   acpi_dsm_notify);
+		kfree(ab->acdata);
+	}
 	ath12k_core_free(ab);
 }
 
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index f48ab69e256a..e473712f0dab 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6918,3 +6918,85 @@ void ath12k_wmi_detach(struct ath12k_base *ab)
 
 	ath12k_wmi_free_dbring_caps(ab);
 }
+
+int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
+					    const u8 *ptas_cfg)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+	int ret;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_CFG_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_CONFIG_TYPE);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_CFG_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, ptas_cfg, ATH12K_ACPI_DSM_TAS_CFG_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
+					     const u8 *ptas_data)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+	int ret;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_DATA_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_DATA_TYPE);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_DATA_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, ptas_data, ATH12K_ACPI_DSM_TAS_DATA_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c75a6fa1f7e0..38bbf59fc6b7 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -361,6 +361,7 @@ 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_BIOS_INTERFACE_CMDID = 0x404A,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
 	WMI_VDEV_START_REQUEST_CMDID,
@@ -1931,6 +1932,7 @@ enum wmi_tlv_tag {
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
 	WMI_TAG_EHT_RATE_SET = 0x3C4,
+	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
 	WMI_TAG_MAX
 };
 
@@ -4791,6 +4793,19 @@ struct ath12k_wmi_base {
 	struct ath12k_wmi_target_cap_arg *targ_cap;
 };
 
+struct wmi_pdev_set_bios_interface_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 param_type_id;
+	__le32 length;
+} __packed;
+
+enum bios_param_type {
+	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
+	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
+	WMI_BIOS_PARAM_TYPE_MAX,
+};
+
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
@@ -4912,5 +4927,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
 			       struct sk_buff *tmpl);
 int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
 			   enum wmi_host_hw_mode_config_type mode);
-
+int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
+					    const u8 *ptas_cfg);
+int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
+					     const u8 *ptas_data);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Wed Sep  6 05:35:19 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Wed, 6 Sep 2023 20:35:19 +0800
Subject: [PATCH v2 3/4] wifi: ath12k: adjust configuration of CCA threshold value
In-Reply-To: <20230906123520.184726-1-quic_lingbok@quicinc.com>
References: <20230906123520.184726-1-quic_lingbok@quicinc.com>
Message-ID: <20230906123520.184726-4-quic_lingbok@quicinc.com>

ath12k need to adjust CCA threshold values to meet the regulatory
requirement. ath12k can retrieve CCA threshold configuration by invoking
ACPI _DSM method.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v2:
1.no change

 drivers/net/wireless/ath/ath12k/acpi.c | 30 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  8 +++++
 drivers/net/wireless/ath/ath12k/core.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 41 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  7 +++--
 5 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index ae1ce7b99d2d..a9931e17bd17 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -72,6 +72,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {
+				ath12k_err(ab, "Invalid CCA data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -281,6 +291,26 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 			goto err_free_acdata;
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_CCA)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
+		if (ret) {
+			ath12k_err(ab, "failed to get cca threshold configuration %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ab->acdata->cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
+		    ab->acdata->cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
+		    ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {
+			ret = ath12k_wmi_pdev_set_cca_thr_table_param(ab,
+								      ab->acdata->cca_data);
+			if (ret) {
+				ath12k_err(ab, "set cca threshold failed %d\n", ret);
+				goto err_free_acdata;
+			}
+		}
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index fdb32ba37b77..60d674fdeb41 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -13,14 +13,17 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
 #define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
 #define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5
+#define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
 
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
 #define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
 #define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
+#define ATH12K_ACPI_DSM_CCA_DATA_SIZE			41
 
 #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
 #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
+#define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
 
@@ -37,6 +40,11 @@
 #define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
 #define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
 #define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
+#define ATH12K_ACPI_CCA_THR_VERSION		0x1
+#define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
+#define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
+#define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET	5
+
 
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 6fe4f0ddee4a..d57e2013b0fe 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -780,6 +780,7 @@ struct ath12k_base {
 		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
 		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
 		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
+		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 07f0a35900e0..d97849b028d6 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7094,3 +7094,44 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
+					    u8 *pcca_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, cca_thr_len_aligned;
+	u8 *pcca_value = pcca_table + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
+
+	cca_thr_len_aligned = roundup(ATH12K_ACPI_CCA_THR_OFFSET_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + cca_thr_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE);
+	cmd->length = ATH12K_ACPI_CCA_THR_OFFSET_LEN;
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, cca_thr_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pcca_value, ATH12K_ACPI_CCA_THR_OFFSET_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 8a774655fe9f..7607cd7ab699 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4805,8 +4805,9 @@ struct wmi_pdev_set_bios_interface_cmd {
 } __packed;
 
 enum bios_param_type {
-	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
-	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
+	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
+	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
+	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
@@ -4952,4 +4953,6 @@ int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
 					     u8 *psar_table);
 int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 					     u8 *pgeo_table);
+int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
+					    u8 *pcca_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Wed Sep  6 05:35:18 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Wed, 6 Sep 2023 20:35:18 +0800
Subject: [PATCH v2 2/4] wifi: ath12k: add BIOS SAR capability for WCN7850
In-Reply-To: <20230906123520.184726-1-quic_lingbok@quicinc.com>
References: <20230906123520.184726-1-quic_lingbok@quicinc.com>
Message-ID: <20230906123520.184726-3-quic_lingbok@quicinc.com>

ath12k get the latest BIOS SAR power table by using ACPI _DSM method, then
pass this table to the firmware.ath12k register a notification callback for
ACPI event so ACPI can notify ath12k to get the latest BIOS SAR table.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v2:
1.no change

 drivers/net/wireless/ath/ath12k/acpi.c | 103 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  15 ++++
 drivers/net/wireless/ath/ath12k/core.h |   3 +
 drivers/net/wireless/ath/ath12k/wmi.c  |  94 ++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  21 +++++
 5 files changed, 236 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index 384e01748b32..ae1ce7b99d2d 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -52,6 +52,26 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
+				ath12k_err(ab, "Invalid BIOS SAR data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->bios_sar_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
+				ath12k_err(ab, "Invalid GEO OFFSET data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -83,6 +103,24 @@ static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
 	return ret;
 }
 
+static int ath12k_set_bios_sar_power_limit_data(struct ath12k_base *ab)
+{
+	int ret;
+
+	if (ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
+	    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
+		ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
+							       ab->acdata->bios_sar_data);
+		if (ret)
+			ath12k_err(ab, "failed to pass bios sar table %d\n", ret);
+	} else {
+		ath12k_err(ab, "the latest bios sar data is invalid\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
 {
 	int ret;
@@ -101,6 +139,20 @@ void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
 			if (ret)
 				return;
 		}
+
+		if (ab->acdata->acpi_bios_sar_enable) {
+			ret = ath12k_acpi_dsm_get_data(ab,
+						       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
+			if (ret) {
+				ath12k_err(ab, "failed to update bios sar %d\n", ret);
+				return;
+			}
+
+			ret = ath12k_set_bios_sar_power_limit_data(ab);
+			if (ret)
+				return;
+		}
+
 	} else {
 		ath12k_err(ab, "unknown acpi notify %u\n", event);
 	}
@@ -113,6 +165,27 @@ void ath12k_acpi_remove_notify(struct ath12k_base *ab)
 				   acpi_dsm_notify);
 }
 
+static int ath12k_pass_acpi_bios_sar_and_geo_to_fw(struct ath12k_base *ab)
+{
+	int ret;
+
+	ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
+						       ab->acdata->bios_sar_data);
+
+	if (ret) {
+		ath12k_err(ab, "failed to pass bios sar table to fw %d\n", ret);
+		return ret;
+	}
+
+	ret = ath12k_wmi_pdev_set_bios_geo_table_param(ab,
+						       ab->acdata->geo_offset_data);
+
+	if (ret)
+		ath12k_err(ab, "failed to pass bios geo table to fw %d\n", ret);
+
+	return ret;
+}
+
 static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
 {
 	int ret;
@@ -172,12 +245,42 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 			ab->acdata->acpi_tas_enable = true;
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
+		if (ret) {
+			ath12k_err(ab, "failed to get bios sar data %d\n", ret);
+			goto err_free_acdata;
+		}
+	}
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET);
+		if (ret) {
+			ath12k_err(ab, "failed to get geo offset data %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
+		    ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
+		    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
+		    !ab->acdata->acpi_tas_enable)
+			ab->acdata->acpi_bios_sar_enable = true;
+	}
+
 	if (ab->acdata->acpi_tas_enable) {
 		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
 		if (ret)
 			goto err_free_acdata;
 	}
 
+	if (ab->acdata->acpi_bios_sar_enable) {
+		ret = ath12k_pass_acpi_bios_sar_and_geo_to_fw(ab);
+		if (ret)
+			goto err_free_acdata;
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index e6eb6f02d524..fdb32ba37b77 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -11,9 +11,16 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
+#define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
+#define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5
 
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
+#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
+#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
+
+#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
+#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
 
@@ -22,6 +29,14 @@
 
 #define ATH12K_ACPI_TAS_DATA_VERSION		0x1
 #define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
+#define ATH12K_ACPI_BIOS_SAR_TABLE_LEN		22
+#define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN	10
+#define ATH12K_ACPI_POWER_LIMIT_DATAOFFSET	12
+#define ATH12K_ACPI_DBS_BACKOFF_DATAOFFSET	2
+#define ATH12K_ACPI_POWER_LIMIT_VERSION		0x1
+#define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
+#define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
+#define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
 
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index cba4f176c018..6fe4f0ddee4a 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -775,8 +775,11 @@ struct ath12k_base {
 	struct {
 		u32 func_bit;
 		bool acpi_tas_enable;
+		bool acpi_bios_sar_enable;
 		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
 		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
+		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
+		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index e473712f0dab..07f0a35900e0 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7000,3 +7000,97 @@ int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
 
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
+					     u8 *psar_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_sar_table_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, sar_table_len_aligned, sar_dbs_backoff_len_aligned;
+	u8 *psar_value = psar_table + ATH12K_ACPI_POWER_LIMIT_DATAOFFSET;
+	u8 *pdbs_value = psar_table + ATH12K_ACPI_DBS_BACKOFF_DATAOFFSET;
+
+	sar_table_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_TABLE_LEN, sizeof(u32));
+	sar_dbs_backoff_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_table_len_aligned +
+		TLV_HDR_SIZE + sar_dbs_backoff_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_sar_table_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->sar_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
+	cmd->dbs_backoff_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
+					 sar_table_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, psar_value, ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
+
+	buf_ptr += sar_table_len_aligned;
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
+					 sar_dbs_backoff_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pdbs_value, ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
+					     u8 *pgeo_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_geo_table_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, sar_geo_len_aligned;
+	u8 *pgeo_value = pgeo_table + ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET;
+
+	sar_geo_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_geo_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_geo_table_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->geo_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, sar_geo_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pgeo_value, ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 38bbf59fc6b7..8a774655fe9f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -361,6 +361,8 @@ 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_BIOS_SAR_TABLE_CMDID = 0x4044,
+	WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045,
 	WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
@@ -1932,6 +1934,8 @@ enum wmi_tlv_tag {
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
 	WMI_TAG_EHT_RATE_SET = 0x3C4,
+	WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS = 0x3D8,
+	WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS = 0x3D9,
 	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
 	WMI_TAG_MAX
 };
@@ -4806,6 +4810,19 @@ enum bios_param_type {
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
+struct wmi_pdev_set_bios_sar_table_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 sar_len;
+	__le32 dbs_backoff_len;
+} __packed;
+
+struct wmi_pdev_set_bios_geo_table_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 geo_len;
+} __packed;
+
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
@@ -4931,4 +4948,8 @@ int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
 					    const u8 *ptas_cfg);
 int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
 					     const u8 *ptas_data);
+int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
+					     u8 *psar_table);
+int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
+					     u8 *pgeo_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Wed Sep  6 05:35:20 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Wed, 6 Sep 2023 20:35:20 +0800
Subject: [PATCH v2 4/4] wifi: ath12k: add band edge channel power for WCN7850
In-Reply-To: <20230906123520.184726-1-quic_lingbok@quicinc.com>
References: <20230906123520.184726-1-quic_lingbok@quicinc.com>
Message-ID: <20230906123520.184726-5-quic_lingbok@quicinc.com>

ath12k need to retrieve band edge channel power table by invoking ACPI _DSM
method, then pass the table to firmware.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v2:
1.no change

 drivers/net/wireless/ath/ath12k/acpi.c | 29 ++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  6 +++-
 drivers/net/wireless/ath/ath12k/core.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 41 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  3 ++
 5 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index a9931e17bd17..389b900df170 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -82,6 +82,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {
+				ath12k_err(ab, "Invalid BAND EDGE data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->band_edge_power, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -311,6 +321,25 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 		}
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);
+		if (ret) {
+			ath12k_err(ab, "failed to get band edge channel power %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ab->acdata->band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
+		    ab->acdata->band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {
+			ret = ath12k_wmi_pdev_set_band_edge_power(ab,
+								  ab->acdata->band_edge_power);
+			if (ret) {
+				ath12k_err(ab, "set band edge channel power failed %d\n", ret);
+				goto err_free_acdata;
+			}
+		}
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index 60d674fdeb41..258007bcda5f 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -14,18 +14,21 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
 #define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5
 #define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
+#define ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE		10
 
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
 #define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
 #define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
 #define ATH12K_ACPI_DSM_CCA_DATA_SIZE			41
+#define ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE		100
 
 #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
 #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
 #define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
+#define ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER	BIT(9)
 
 #define ATH12K_ACPI_NOTIFY_EVENT			0x86
 #define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
@@ -44,7 +47,8 @@
 #define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
 #define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
 #define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET	5
-
+#define ATH12K_ACPI_BAND_EDGE_VERSION		0x1
+#define ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG	0x1
 
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d57e2013b0fe..d06c3984aef9 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -781,6 +781,7 @@ struct ath12k_base {
 		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
 		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
 		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
+		u8 band_edge_power[ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index d97849b028d6..244acfaa875d 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7135,3 +7135,44 @@ int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
 	}
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
+					const u8 *pchan_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header =
+		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						   sizeof(*cmd)));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pchan_table, ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 7607cd7ab699..73d790d405cd 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4808,6 +4808,7 @@ enum bios_param_type {
 	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
 	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
 	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
+	WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER	=	3,
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
@@ -4955,4 +4956,6 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 					     u8 *pgeo_table);
 int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
 					    u8 *pcca_table);
+int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
+					const u8 *pchan_table);
 #endif
-- 
2.34.1



From kvalo at kernel.org  Wed Sep  6 07:04:02 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 06 Sep 2023 17:04:02 +0300
Subject: ath12k-check warnings
In-Reply-To: <5376cd01-ab3e-416f-ea73-649c82e3bc40@quicinc.com> (Wen Gong's
	message of "Mon, 28 Aug 2023 14:09:48 +0800")
References: <20230824025432.19406-1-quic_wgong@quicinc.com>
	<169295002356.1753110.7150166655358699685.kvalo@kernel.org>
	<5376cd01-ab3e-416f-ea73-649c82e3bc40@quicinc.com>
Message-ID: <87cyyve6ul.fsf_-_@kernel.org>

(dropping linux-wireless and changing the title)

Wen Gong <quic_wgong at quicinc.com> writes:

> On 8/25/2023 3:53 PM, Kalle Valo wrote:
>
>> New warning:
>>
>> drivers/net/wireless/ath/ath12k/wmi.c:4199:69: warning: restricted
>> __le32 degrades to integer
>>
>> Remember to ALWAYS run ath12k-check.
>>
>> Patch set to Changes Requested.
>
> I found ath12k-check output many logs, about 5000 lines.
>
> And ath12k-check only has one item in CHECKPATCH_IGNORE, it does not 
> have the other items which
>
> existed in ath10k-check/ath11k-check, so ath12k-check output many info
>
> "struct? should normally be const"/"networking block comments don't use 
> an empty /* line, use /* Comment..."/.
>
> Also it print many "note: in included file ..." by sparse.
>
>
> May I change ath12k-check with diff below and use "ath12k-check | grep 
> -v "note: in included file"" for the patch check?
>
> wgong at wgong-Latitude-E6430:~/opensource/kernel/ath$ ./ath12k-check --version
> /home/wgong/opensource/kernel/ath/./ath12k-check:32: DeprecationWarning: 
> The distutils package is deprecated and slated for removal in Python 
> 3.12. Use setuptools or check PEP 632 for potential alternatives
>  ? import distutils.spawn
> ath12k-check (md5sum 194c6d6c4bad47f9780fe22541f2f68c)
>
> gcc:??????????? gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
> sparse:???????? 0.6.4 (Ubuntu: 0.6.4-2)
> checkpatch.pl:? Version: 0.32 (md5sum b169dcb45a7f32bd19b128e08288e9cc)
> gtags:????????? gtags (Global) 6.6.7

I assume this is because you are using an old version of checkpatch.pl.
I forgot to update the commit id in ath1?k-check scripts but I fixed it
now:

https://github.com/qca/qca-swiss-army-knife/commit/27d9574ce670d759681b662e380a826ca6106e48

This is the correct version of checkpatch.pl you should be using (also
printed in --help):

https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/scripts/checkpatch.pl?id=362173572a4018e9c8e39c616823189c41d39d41

Did that fix the issue?

I also added a check to make sure that I don't forget to update the
commit id in the future:

https://github.com/qca/qca-swiss-army-knife/commit/c880314adbb1006184265f002016ec3f87bef40d

Please always report any issues you have with ath12k-check. You should
see no warnings in output, otherwise something is wrong.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From quic_jjohnson at quicinc.com  Wed Sep  6 13:28:06 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Wed, 6 Sep 2023 13:28:06 -0700
Subject: [PATCH 2/4] wifi: ath12k: add BIOS SAR capability for WCN7850
In-Reply-To: <20230905024904.3882-3-quic_lingbok@quicinc.com>
References: <20230905024904.3882-1-quic_lingbok@quicinc.com>
 <20230905024904.3882-3-quic_lingbok@quicinc.com>
Message-ID: <fd32429f-7a33-4c94-a95d-03efd5283b3a@quicinc.com>

On 9/4/2023 7:49 PM, Lingbo Kong wrote:
> ath12k get the latest BIOS SAR power table by using ACPI _DSM method, then
> pass this table to the firmware.ath12k register a notification callback for
> ACPI event so ACPI can notify ath12k to get the latest BIOS SAR table.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/acpi.c | 103 +++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/acpi.h |  15 ++++
>   drivers/net/wireless/ath/ath12k/core.h |   3 +
>   drivers/net/wireless/ath/ath12k/wmi.c  |  94 ++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h  |  21 +++++
>   5 files changed, 236 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
> index 384e01748b32..ae1ce7b99d2d 100644
> --- a/drivers/net/wireless/ath/ath12k/acpi.c
> +++ b/drivers/net/wireless/ath/ath12k/acpi.c
> @@ -52,6 +52,26 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
>   			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
>   			       obj->buffer.length);
>   			break;
> +		case ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR:
> +			if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
> +				ath12k_err(ab, "Invalid BIOS SAR data size %d\n",
> +					   obj->buffer.length);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			memcpy(&ab->acdata->bios_sar_data, obj->buffer.pointer,
> +			       obj->buffer.length);
> +			break;
> +		case ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET:
> +			if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
> +				ath12k_err(ab, "Invalid GEO OFFSET data size %d\n",
> +					   obj->buffer.length);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
> +			       obj->buffer.length);
> +			break;
>   		}
>   	} else {
>   		ath12k_err(ab,
> @@ -83,6 +103,24 @@ static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
>   	return ret;
>   }
>   
> +static int ath12k_set_bios_sar_power_limit_data(struct ath12k_base *ab)
> +{
> +	int ret;
> +
> +	if (ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
> +	    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
> +		ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
> +							       ab->acdata->bios_sar_data);
> +		if (ret)
> +			ath12k_err(ab, "failed to pass bios sar table %d\n", ret);
> +	} else {
> +		ath12k_err(ab, "the latest bios sar data is invalid\n");
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
>   void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
>   {
>   	int ret;
> @@ -101,6 +139,20 @@ void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
>   			if (ret)
>   				return;
>   		}
> +
> +		if (ab->acdata->acpi_bios_sar_enable) {
> +			ret = ath12k_acpi_dsm_get_data(ab,
> +						       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
> +			if (ret) {
> +				ath12k_err(ab, "failed to update bios sar %d\n", ret);
> +				return;
> +			}
> +
> +			ret = ath12k_set_bios_sar_power_limit_data(ab);
> +			if (ret)
> +				return;
> +		}
> +
>   	} else {
>   		ath12k_err(ab, "unknown acpi notify %u\n", event);
>   	}
> @@ -113,6 +165,27 @@ void ath12k_acpi_remove_notify(struct ath12k_base *ab)
>   				   acpi_dsm_notify);
>   }
>   
> +static int ath12k_pass_acpi_bios_sar_and_geo_to_fw(struct ath12k_base *ab)
> +{
> +	int ret;
> +
> +	ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
> +						       ab->acdata->bios_sar_data);
> +
> +	if (ret) {
> +		ath12k_err(ab, "failed to pass bios sar table to fw %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = ath12k_wmi_pdev_set_bios_geo_table_param(ab,
> +						       ab->acdata->geo_offset_data);
> +
> +	if (ret)
> +		ath12k_err(ab, "failed to pass bios geo table to fw %d\n", ret);
> +
> +	return ret;
> +}
> +
>   static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
>   {
>   	int ret;
> @@ -172,12 +245,42 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
>   			ab->acdata->acpi_tas_enable = true;
>   	}
>   
> +	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
> +		ret = ath12k_acpi_dsm_get_data(ab,
> +					       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
> +		if (ret) {
> +			ath12k_err(ab, "failed to get bios sar data %d\n", ret);
> +			goto err_free_acdata;
> +		}
> +	}
> +
> +	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
> +		ret = ath12k_acpi_dsm_get_data(ab,
> +					       ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET);
> +		if (ret) {
> +			ath12k_err(ab, "failed to get geo offset data %d\n", ret);
> +			goto err_free_acdata;
> +		}
> +
> +		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
> +		    ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
> +		    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
> +		    !ab->acdata->acpi_tas_enable)
> +			ab->acdata->acpi_bios_sar_enable = true;
> +	}
> +
>   	if (ab->acdata->acpi_tas_enable) {
>   		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
>   		if (ret)
>   			goto err_free_acdata;
>   	}
>   
> +	if (ab->acdata->acpi_bios_sar_enable) {
> +		ret = ath12k_pass_acpi_bios_sar_and_geo_to_fw(ab);
> +		if (ret)
> +			goto err_free_acdata;
> +	}
> +
>   	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
>   					     ACPI_DEVICE_NOTIFY,
>   					     acpi_dsm_notify, ab);
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
> index cf742958a623..59f87cb258c6 100644
> --- a/drivers/net/wireless/ath/ath12k/acpi.h
> +++ b/drivers/net/wireless/ath/ath12k/acpi.h
> @@ -11,9 +11,16 @@
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5

can we have the above in some logical order, either numerical order or 
alphabetic order?

>   
>   #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
>   #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
> +#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
> +#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
> +
> +#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
> +#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
>   #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
>   #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
>   
> @@ -22,6 +29,14 @@
>   
>   #define ATH12K_ACPI_TAS_DATA_VERSION		0x1
>   #define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
> +#define ATH12K_ACPI_BIOS_SAR_TABLE_LEN		22
> +#define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN	10
> +#define ATH12K_ACPI_POWER_LIMIT_DATAOFFSET	12
> +#define ATH12K_ACPI_DBS_BACKOFF_DATAOFFSET	2
> +#define ATH12K_ACPI_POWER_LIMIT_VERSION		0x1
> +#define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
> +#define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
> +#define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
>   
>   int ath12k_get_acpi_all_data(struct ath12k_base *ab);
>   void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index cba4f176c018..6fe4f0ddee4a 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -775,8 +775,11 @@ struct ath12k_base {
>   	struct {
>   		u32 func_bit;
>   		bool acpi_tas_enable;
> +		bool acpi_bios_sar_enable;
>   		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
>   		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
> +		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
> +		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
>   	} *acdata;
>   
>   	/* must be last */
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 2d501993b197..f090ccea5f64 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -6978,3 +6978,97 @@ int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
>   
>   	return ret;
>   }
> +
> +int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
> +					     u8 *psar_table)
> +{
> +	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
> +	struct wmi_pdev_set_bios_sar_table_cmd *cmd;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	int ret;
> +	u8 *buf_ptr;
> +	u32 len, sar_table_len_aligned, sar_dbs_backoff_len_aligned;
> +	u8 *psar_value = psar_table + ATH12K_ACPI_POWER_LIMIT_DATAOFFSET;
> +	u8 *pdbs_value = psar_table + ATH12K_ACPI_DBS_BACKOFF_DATAOFFSET;
> +
> +	sar_table_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_TABLE_LEN, sizeof(u32));
> +	sar_dbs_backoff_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_table_len_aligned +
> +		TLV_HDR_SIZE + sar_dbs_backoff_len_aligned;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_pdev_set_bios_sar_table_cmd *)skb->data;
> +	cmd->tlv_header =
> +		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS,
> +						   sizeof(*cmd)));

cpu_to_le32() is incorrect here. ath12k_wmi_tlv_cmd_hdr() already 
returns a __le32 header

> +	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
> +	cmd->sar_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
> +	cmd->dbs_backoff_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
> +
> +	buf_ptr = skb->data + sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
> +					 sar_table_len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, psar_value, ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
> +
> +	buf_ptr += sar_table_len_aligned;
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
> +					 sar_dbs_backoff_len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, pdbs_value, ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
> +
> +	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> +
> +int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
> +					     u8 *pgeo_table)
> +{
> +	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
> +	struct wmi_pdev_set_bios_geo_table_cmd *cmd;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	int ret;
> +	u8 *buf_ptr;
> +	u32 len, sar_geo_len_aligned;
> +	u8 *pgeo_value = pgeo_table + ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET;
> +
> +	sar_geo_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_geo_len_aligned;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_pdev_set_bios_geo_table_cmd *)skb->data;
> +	cmd->tlv_header =
> +		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS,

cpu_to_le32() is incorrect here, ath12k_wmi_tlv_cmd_hdr() already 
returns a __le32 header

> +						   sizeof(*cmd)));
> +	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
> +	cmd->geo_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
> +
> +	buf_ptr = skb->data + sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, sar_geo_len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, pgeo_value, ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
> +
> +	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 38bbf59fc6b7..8a774655fe9f 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -361,6 +361,8 @@ 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_BIOS_SAR_TABLE_CMDID = 0x4044,
> +	WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045,
>   	WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A,
>   	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
>   	WMI_VDEV_DELETE_CMDID,
> @@ -1932,6 +1934,8 @@ enum wmi_tlv_tag {
>   	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
>   	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
>   	WMI_TAG_EHT_RATE_SET = 0x3C4,
> +	WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS = 0x3D8,
> +	WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS = 0x3D9,
>   	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
>   	WMI_TAG_MAX
>   };
> @@ -4806,6 +4810,19 @@ enum bios_param_type {
>   	WMI_BIOS_PARAM_TYPE_MAX,
>   };
>   
> +struct wmi_pdev_set_bios_sar_table_cmd {
> +	__le32 tlv_header;
> +	__le32 pdev_id;
> +	__le32 sar_len;
> +	__le32 dbs_backoff_len;
> +} __packed;
> +
> +struct wmi_pdev_set_bios_geo_table_cmd {
> +	__le32 tlv_header;
> +	__le32 pdev_id;
> +	__le32 geo_len;
> +} __packed;
> +
>   #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
>   
>   void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
> @@ -4931,4 +4948,8 @@ int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
>   					    const u8 *ptas_cfg);
>   int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
>   					     const u8 *ptas_data);
> +int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
> +					     u8 *psar_table);
> +int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
> +					     u8 *pgeo_table);
>   #endif



From quic_jjohnson at quicinc.com  Wed Sep  6 13:37:25 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Wed, 6 Sep 2023 13:37:25 -0700
Subject: [PATCH 3/4] wifi: ath12k: adjust configuration of CCA threshold
 value
In-Reply-To: <20230905024904.3882-4-quic_lingbok@quicinc.com>
References: <20230905024904.3882-1-quic_lingbok@quicinc.com>
 <20230905024904.3882-4-quic_lingbok@quicinc.com>
Message-ID: <a7e4e6b7-f640-477a-a7bd-16d1a8c7532b@quicinc.com>

On 9/4/2023 7:49 PM, Lingbo Kong wrote:
> ath12k need to adjust CCA threshold values to meet the regulatory
> requirement. ath12k can retrieve CCA threshold configuration by invoking
> ACPI _DSM method.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/acpi.c | 30 +++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/acpi.h |  8 +++++
>   drivers/net/wireless/ath/ath12k/core.h |  1 +
>   drivers/net/wireless/ath/ath12k/wmi.c  | 41 ++++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h  |  7 +++--
>   5 files changed, 85 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
> index ae1ce7b99d2d..a9931e17bd17 100644
> --- a/drivers/net/wireless/ath/ath12k/acpi.c
> +++ b/drivers/net/wireless/ath/ath12k/acpi.c
> @@ -72,6 +72,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
>   			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
>   			       obj->buffer.length);
>   			break;
> +		case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:
> +			if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {
> +				ath12k_err(ab, "Invalid CCA data size %d\n",
> +					   obj->buffer.length);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
> +			       obj->buffer.length);
> +			break;
>   		}
>   	} else {
>   		ath12k_err(ab,
> @@ -281,6 +291,26 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
>   			goto err_free_acdata;
>   	}
>   
> +	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_CCA)) {
> +		ret = ath12k_acpi_dsm_get_data(ab,
> +					       ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
> +		if (ret) {
> +			ath12k_err(ab, "failed to get cca threshold configuration %d\n", ret);
> +			goto err_free_acdata;
> +		}
> +
> +		if (ab->acdata->cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
> +		    ab->acdata->cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
> +		    ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {
> +			ret = ath12k_wmi_pdev_set_cca_thr_table_param(ab,
> +								      ab->acdata->cca_data);
> +			if (ret) {
> +				ath12k_err(ab, "set cca threshold failed %d\n", ret);
> +				goto err_free_acdata;
> +			}
> +		}
> +	}
> +
>   	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
>   					     ACPI_DEVICE_NOTIFY,
>   					     acpi_dsm_notify, ab);
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
> index 59f87cb258c6..acdf8d851fba 100644
> --- a/drivers/net/wireless/ath/ath12k/acpi.h
> +++ b/drivers/net/wireless/ath/ath12k/acpi.h
> @@ -13,14 +13,17 @@
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
>   
>   #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
>   #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
>   #define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
>   #define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
> +#define ATH12K_ACPI_DSM_CCA_DATA_SIZE			41
>   
>   #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
>   #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
> +#define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
>   #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
>   #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
>   
> @@ -37,6 +40,11 @@
>   #define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
>   #define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
>   #define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
> +#define ATH12K_ACPI_CCA_THR_VERSION		0x1
> +#define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
> +#define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
> +#define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET	5

for all of these macros it seems like you have duplication of knowledge.

here you have two macros that describe the layout, and you have a 
separate macro above that describes the entire data size. IMO it would 
be "better" if the data size was based upon the layout macros rather 
than being an independent quantity:

#define ATH12K_ACPI_DSM_CCA_DATA_SIZE 
(ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET +
ATH12K_ACPI_CCA_THR_OFFSET_LEN)

consider this advice to apply to the previous patches in this patchset

> +
>   
>   int ath12k_get_acpi_all_data(struct ath12k_base *ab);
>   void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 6fe4f0ddee4a..d57e2013b0fe 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -780,6 +780,7 @@ struct ath12k_base {
>   		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
>   		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
>   		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
> +		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
>   	} *acdata;
>   
>   	/* must be last */
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index f090ccea5f64..3f66807b7961 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -7072,3 +7072,44 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
>   
>   	return ret;
>   }
> +
> +int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
> +					    u8 *pcca_table)
> +{
> +	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
> +	struct wmi_pdev_set_bios_interface_cmd *cmd;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	int ret;
> +	u8 *buf_ptr;
> +	u32 len, cca_thr_len_aligned;
> +	u8 *pcca_value = pcca_table + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
> +
> +	cca_thr_len_aligned = roundup(ATH12K_ACPI_CCA_THR_OFFSET_LEN, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + cca_thr_len_aligned;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
> +	cmd->tlv_header =
> +		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
> +						   sizeof(*cmd)));

remove cpu_to_le32()

> +	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
> +	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE);
> +	cmd->length = ATH12K_ACPI_CCA_THR_OFFSET_LEN;
> +
> +	buf_ptr = skb->data + sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, cca_thr_len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, pcca_value, ATH12K_ACPI_CCA_THR_OFFSET_LEN);
> +
> +	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +	return ret;
> +}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 8a774655fe9f..7607cd7ab699 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -4805,8 +4805,9 @@ struct wmi_pdev_set_bios_interface_cmd {
>   } __packed;
>   
>   enum bios_param_type {
> -	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
> -	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
> +	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
> +	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
> +	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
>   	WMI_BIOS_PARAM_TYPE_MAX,
>   };
>   
> @@ -4952,4 +4953,6 @@ int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
>   					     u8 *psar_table);
>   int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
>   					     u8 *pgeo_table);
> +int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
> +					    u8 *pcca_table);
>   #endif



From quic_jjohnson at quicinc.com  Wed Sep  6 22:11:06 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Wed, 6 Sep 2023 22:11:06 -0700
Subject: [PATCH 4/4] wifi: ath12k: add band edge channel power for WCN7850
In-Reply-To: <20230905024904.3882-5-quic_lingbok@quicinc.com>
References: <20230905024904.3882-1-quic_lingbok@quicinc.com>
 <20230905024904.3882-5-quic_lingbok@quicinc.com>
Message-ID: <51377366-584d-4854-ab30-552e15100dee@quicinc.com>

On 9/4/2023 7:49 PM, Lingbo Kong wrote:
> ath12k need to retrieve band edge channel power table by invoking ACPI _DSM
> method, then pass the table to firmware.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/acpi.c | 29 ++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/acpi.h |  6 +++-
>   drivers/net/wireless/ath/ath12k/core.h |  1 +
>   drivers/net/wireless/ath/ath12k/wmi.c  | 41 ++++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h  |  3 ++
>   5 files changed, 79 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
> index a9931e17bd17..389b900df170 100644
> --- a/drivers/net/wireless/ath/ath12k/acpi.c
> +++ b/drivers/net/wireless/ath/ath12k/acpi.c
> @@ -82,6 +82,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
>   			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
>   			       obj->buffer.length);
>   			break;
> +		case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:
> +			if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {
> +				ath12k_err(ab, "Invalid BAND EDGE data size %d\n",
> +					   obj->buffer.length);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			memcpy(&ab->acdata->band_edge_power, obj->buffer.pointer,
> +			       obj->buffer.length);
> +			break;
>   		}
>   	} else {
>   		ath12k_err(ab,
> @@ -311,6 +321,25 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
>   		}
>   	}
>   
> +	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {
> +		ret = ath12k_acpi_dsm_get_data(ab,
> +					       ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);
> +		if (ret) {
> +			ath12k_err(ab, "failed to get band edge channel power %d\n", ret);
> +			goto err_free_acdata;
> +		}
> +
> +		if (ab->acdata->band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
> +		    ab->acdata->band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {
> +			ret = ath12k_wmi_pdev_set_band_edge_power(ab,
> +								  ab->acdata->band_edge_power);
> +			if (ret) {
> +				ath12k_err(ab, "set band edge channel power failed %d\n", ret);
> +				goto err_free_acdata;
> +			}
> +		}
> +	}
> +
>   	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
>   					     ACPI_DEVICE_NOTIFY,
>   					     acpi_dsm_notify, ab);
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
> index acdf8d851fba..1acfd7696dfc 100644
> --- a/drivers/net/wireless/ath/ath12k/acpi.h
> +++ b/drivers/net/wireless/ath/ath12k/acpi.h
> @@ -14,18 +14,21 @@
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR		4
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET		5
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE		10
>   
>   #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
>   #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
>   #define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE		34
>   #define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE		19
>   #define ATH12K_ACPI_DSM_CCA_DATA_SIZE			41
> +#define ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE		100
>   
>   #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
>   #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
>   #define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
>   #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
>   #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
> +#define ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER	BIT(9)
>   
>   #define ATH12K_ACPI_NOTIFY_EVENT			0x86
>   #define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
> @@ -44,7 +47,8 @@
>   #define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
>   #define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
>   #define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET	5
> -
> +#define ATH12K_ACPI_BAND_EDGE_VERSION		0x1
> +#define ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG	0x1
>   
>   int ath12k_get_acpi_all_data(struct ath12k_base *ab);
>   void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index d57e2013b0fe..d06c3984aef9 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -781,6 +781,7 @@ struct ath12k_base {
>   		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
>   		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
>   		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
> +		u8 band_edge_power[ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE];
>   	} *acdata;
>   
>   	/* must be last */
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 3f66807b7961..345bdd50adb2 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -7113,3 +7113,44 @@ int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
>   	}
>   	return ret;
>   }
> +
> +int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
> +					const u8 *pchan_table)
> +{
> +	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
> +	struct wmi_pdev_set_bios_interface_cmd *cmd;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	int ret;
> +	u8 *buf_ptr;
> +	u32 len, len_aligned;
> +
> +	len_aligned = roundup(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
> +	cmd->tlv_header =
> +		cpu_to_le32(ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,

remove cpu_to_le32()

> +						   sizeof(*cmd)));
> +	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
> +	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER);
> +	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
> +
> +	buf_ptr = skb->data + sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, pchan_table, ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
> +
> +	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 7607cd7ab699..73d790d405cd 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -4808,6 +4808,7 @@ enum bios_param_type {
>   	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
>   	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
>   	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
> +	WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER	=	3,
>   	WMI_BIOS_PARAM_TYPE_MAX,
>   };
>   
> @@ -4955,4 +4956,6 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
>   					     u8 *pgeo_table);
>   int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
>   					    u8 *pcca_table);
> +int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
> +					const u8 *pchan_table);
>   #endif



From quic_lingbok at quicinc.com  Thu Sep  7 03:17:06 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Thu, 7 Sep 2023 18:17:06 +0800
Subject: [PATCH v3 0/4] wifi: ath12k: implement some functionalities through reading ACPI Table
Message-ID: <20230907101710.11659-1-quic_lingbok@quicinc.com>

Through reading ACPI table, implement Time-Average-SAR(TAS), BIOS SAR,
configuration of CCA threshold and band edge channel power functionalities.

v3:
1.remove unnecessary cpu_to_le32()
2.adjust the order of the macros
3.apply jeff's advice

v2:
1.put <linux/acpi.h> in the include guard

Lingbo Kong (4):
  wifi: ath12k: add TAS capability for WCN7850
  wifi: ath12k: add BIOS SAR capability for WCN7850
  wifi: ath12k: adjust configuration of CCA threshold value
  wifi: ath12k: add band edge channel power for WCN7850

 drivers/net/wireless/ath/ath12k/Makefile |   3 +-
 drivers/net/wireless/ath/ath12k/acpi.c   | 365 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h   |  60 ++++
 drivers/net/wireless/ath/ath12k/core.c   |   6 +
 drivers/net/wireless/ath/ath12k/core.h   |  13 +
 drivers/net/wireless/ath/ath12k/hw.c     |  10 +
 drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
 drivers/net/wireless/ath/ath12k/pci.c    |   6 +
 drivers/net/wireless/ath/ath12k/wmi.c    | 252 ++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h    |  47 ++-
 10 files changed, 763 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h


base-commit: 1b5b69a51bb4909844e4003920af09ca1cc6bb0e
-- 
2.34.1



From quic_lingbok at quicinc.com  Thu Sep  7 03:17:07 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Thu, 7 Sep 2023 18:17:07 +0800
Subject: [PATCH v3 1/4] wifi: ath12k: add TAS capability for WCN7850
In-Reply-To: <20230907101710.11659-1-quic_lingbok@quicinc.com>
References: <20230907101710.11659-1-quic_lingbok@quicinc.com>
Message-ID: <20230907101710.11659-2-quic_lingbok@quicinc.com>

In order to enable Time-Average-SAR(TAS) for WCN7850, define some
functions. One function is to return TAS configuration, the other return
SAR power table, then ath12k apply these data to wlan firmware. ath12k
register an ACPI event callback so that ACPI can notify ath12k to retrieve
the updated SAR power table and apply it to wlan firmware.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v3:
1.remove unnecessary cpu_to_le32()

v2:
1.put <linux/acpi.h> in the include guard

 drivers/net/wireless/ath/ath12k/Makefile |   3 +-
 drivers/net/wireless/ath/ath12k/acpi.c   | 203 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h   |  29 ++++
 drivers/net/wireless/ath/ath12k/core.c   |   6 +
 drivers/net/wireless/ath/ath12k/core.h   |   8 +
 drivers/net/wireless/ath/ath12k/hw.c     |  10 ++
 drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
 drivers/net/wireless/ath/ath12k/pci.c    |   6 +
 drivers/net/wireless/ath/ath12k/wmi.c    |  80 +++++++++
 drivers/net/wireless/ath/ath12k/wmi.h    |  20 ++-
 10 files changed, 366 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h

diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile
index 62c52e733b5e..a479fe06caac 100644
--- a/drivers/net/wireless/ath/ath12k/Makefile
+++ b/drivers/net/wireless/ath/ath12k/Makefile
@@ -19,7 +19,8 @@ ath12k-y += core.o \
 	    hw.o \
 	    mhi.o \
 	    pci.o \
-	    dp_mon.o
+	    dp_mon.o \
+	    acpi.o
 
 ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
 
diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
new file mode 100644
index 000000000000..384e01748b32
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -0,0 +1,203 @@
+// 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.
+ */
+
+#include "core.h"
+#include "acpi.h"
+#include "debug.h"
+
+static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
+{
+	union acpi_object *obj;
+	acpi_handle root_handle;
+	int ret = 0;
+
+	root_handle = ACPI_HANDLE(ab->dev);
+	if (!root_handle) {
+		ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid ACPI handler\n");
+		return -EOPNOTSUPP;
+	}
+
+	obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,
+				NULL);
+
+	if (!obj) {
+		ath12k_dbg(ab, ATH12K_DBG_BOOT, "ACPI _DSM method invocation failed\n");
+		return -ENOENT;
+	}
+
+	if (obj->type == ACPI_TYPE_INTEGER) {
+		ab->acdata->func_bit = obj->integer.value;
+	} else if (obj->type == ACPI_TYPE_BUFFER) {
+		switch (func) {
+		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
+				ath12k_err(ab, "Invalid TAS cfg size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->tas_cfg, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {
+				ath12k_err(ab, "Invalid TAS data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		}
+	} else {
+		ath12k_err(ab,
+			   "ACPI: DSM method did not return a valid object, type %d\n",
+			   obj->type);
+		ret = -EINVAL;
+	}
+
+out:
+	ACPI_FREE(obj);
+	return ret;
+}
+
+static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
+{
+	int ret;
+
+	if (ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
+	    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG) {
+		ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
+							       ab->acdata->tas_sar_power_table);
+		if (ret)
+			ath12k_err(ab, "failed to pass tas data table %d\n", ret);
+	} else {
+		ath12k_err(ab, "the latest tas data is invalid\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
+{
+	int ret;
+	struct ath12k_base *ab = data;
+
+	if (event == ATH12K_ACPI_NOTIFY_EVENT) {
+		if (ab->acdata->acpi_tas_enable) {
+			ret = ath12k_acpi_dsm_get_data(ab,
+						       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
+			if (ret) {
+				ath12k_err(ab, "failed to update tas data table %d\n", ret);
+				return;
+			}
+
+			ret = ath12k_set_tas_power_limit_data(ab);
+			if (ret)
+				return;
+		}
+	} else {
+		ath12k_err(ab, "unknown acpi notify %u\n", event);
+	}
+}
+
+void ath12k_acpi_remove_notify(struct ath12k_base *ab)
+{
+	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+				   ACPI_DEVICE_NOTIFY,
+				   acpi_dsm_notify);
+}
+
+static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
+{
+	int ret;
+
+	ret = ath12k_wmi_pdev_set_tas_cfg_table_param(ab,
+						      ab->acdata->tas_cfg);
+	if (ret) {
+		ath12k_err(ab, "failed to pass tas cfg table to fw %d\n", ret);
+		return ret;
+	}
+
+	ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
+						       ab->acdata->tas_sar_power_table);
+	if (ret)
+		ath12k_err(ab, "failed to pass tas data table to fw %d\n", ret);
+
+	return ret;
+}
+
+int ath12k_get_acpi_all_data(struct ath12k_base *ab)
+{
+	int ret;
+	acpi_status status;
+
+	ab->acdata = kzalloc(sizeof(*ab->acdata), GFP_KERNEL);
+	if (!ab->acdata)
+		return -ENOMEM;
+
+	ab->acdata->acpi_tas_enable = false;
+
+	ret = ath12k_acpi_dsm_get_data(ab,
+				       ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS);
+
+	if (ret)
+		return ret;
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG);
+		if (ret) {
+			ath12k_err(ab, "failed to get tas cfg table %d\n", ret);
+			goto err_free_acdata;
+		}
+	}
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
+		if (ret) {
+			ath12k_err(ab, "failed to get tas data table %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&
+		    ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
+		    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG)
+			ab->acdata->acpi_tas_enable = true;
+	}
+
+	if (ab->acdata->acpi_tas_enable) {
+		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
+		if (ret)
+			goto err_free_acdata;
+	}
+
+	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
+					     ACPI_DEVICE_NOTIFY,
+					     acpi_dsm_notify, ab);
+	if (ACPI_FAILURE(status)) {
+		ath12k_err(ab, "failed to install DSM notify callback\n");
+		goto err_remove_notify;
+	}
+
+	return 0;
+
+err_remove_notify:
+	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+				   ACPI_DEVICE_NOTIFY,
+				   acpi_dsm_notify);
+
+	ret = -EIO;
+
+err_free_acdata:
+	kfree(ab->acdata);
+	ab->acdata = NULL;
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
new file mode 100644
index 000000000000..2331b8e3e035
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -0,0 +1,29 @@
+/* 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.
+ */
+#ifndef ATH12K_ACPI_H
+#define ATH12K_ACPI_H
+
+#include <linux/acpi.h>
+
+#define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
+#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
+#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
+
+#define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
+#define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
+
+#define ATH12K_ACPI_NOTIFY_EVENT			0x86
+#define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
+
+#define ATH12K_ACPI_TAS_DATA_VERSION		0x1
+#define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
+
+#define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
+#define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
+
+int ath12k_get_acpi_all_data(struct ath12k_base *ab);
+void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
+#endif
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 39f938fafa81..457261c7a0e9 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -538,6 +538,12 @@ static int ath12k_core_start(struct ath12k_base *ab,
 		goto err_reo_cleanup;
 	}
 
+	if (!guid_is_null(ab->hw_params->acpi_guid)) {
+		ret = ath12k_get_acpi_all_data(ab);
+		if (!ret)
+			ath12k_info(ab, "success to get acpi cfg data\n");
+	}
+
 	return 0;
 
 err_reo_cleanup:
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d873b573dac6..cba4f176c018 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -22,6 +22,7 @@
 #include "hal_rx.h"
 #include "reg.h"
 #include "dbring.h"
+#include "acpi.h"
 
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
 
@@ -771,6 +772,13 @@ struct ath12k_base {
 	u64 fw_soc_drop_count;
 	bool static_window_map;
 
+	struct {
+		u32 func_bit;
+		bool acpi_tas_enable;
+		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
+		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
+	} *acdata;
+
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 5991cc91cd00..f0f7f9dbb08a 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -15,6 +15,10 @@
 #include "mhi.h"
 #include "dp_rx.h"
 
+static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec,
+					     0x90, 0xd6, 0x02, 0x42,
+					     0xac, 0x12, 0x00, 0x03);
+
 static u8 ath12k_hw_qcn9274_mac_from_pdev_id(int pdev_idx)
 {
 	return pdev_idx;
@@ -907,6 +911,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.acpi_guid = NULL,
 	},
 	{
 		.name = "wcn7850 hw2.0",
@@ -964,6 +970,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
 					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
+
+		.acpi_guid = &wcn7850_uuid,
 	},
 	{
 		.name = "qcn9274 hw2.0",
@@ -1019,6 +1027,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.acpi_guid = NULL,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e6c4223c283c..ab409e8ae268 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -8,7 +8,7 @@
 #define ATH12K_HW_H
 
 #include <linux/mhi.h>
-
+#include <linux/uuid.h>
 #include "wmi.h"
 #include "hal.h"
 
@@ -186,6 +186,8 @@ struct ath12k_hw_params {
 	const struct hal_ops *hal_ops;
 
 	u64 qmi_cnss_feature_bitmap;
+
+	const guid_t *acpi_guid;
 };
 
 struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index bd689efa7daa..3c2967e760ab 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1340,6 +1340,12 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
 
 	ath12k_hal_srng_deinit(ab);
 	ath12k_ce_free_pipes(ab);
+	if (!guid_is_null(ab->hw_params->acpi_guid) && ab->acdata) {
+		acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+					   ACPI_DEVICE_NOTIFY,
+					   acpi_dsm_notify);
+		kfree(ab->acdata);
+	}
 	ath12k_core_free(ab);
 }
 
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index f48ab69e256a..f49f4325edff 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6918,3 +6918,83 @@ void ath12k_wmi_detach(struct ath12k_base *ab)
 
 	ath12k_wmi_free_dbring_caps(ab);
 }
+
+int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
+					    const u8 *ptas_cfg)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+	int ret;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_CFG_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_CONFIG_TYPE);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_CFG_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, ptas_cfg, ATH12K_ACPI_DSM_TAS_CFG_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
+					     const u8 *ptas_data)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+	int ret;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_DATA_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_DATA_TYPE);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_DATA_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, ptas_data, ATH12K_ACPI_DSM_TAS_DATA_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c75a6fa1f7e0..38bbf59fc6b7 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -361,6 +361,7 @@ 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_BIOS_INTERFACE_CMDID = 0x404A,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
 	WMI_VDEV_START_REQUEST_CMDID,
@@ -1931,6 +1932,7 @@ enum wmi_tlv_tag {
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
 	WMI_TAG_EHT_RATE_SET = 0x3C4,
+	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
 	WMI_TAG_MAX
 };
 
@@ -4791,6 +4793,19 @@ struct ath12k_wmi_base {
 	struct ath12k_wmi_target_cap_arg *targ_cap;
 };
 
+struct wmi_pdev_set_bios_interface_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 param_type_id;
+	__le32 length;
+} __packed;
+
+enum bios_param_type {
+	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
+	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
+	WMI_BIOS_PARAM_TYPE_MAX,
+};
+
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
@@ -4912,5 +4927,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
 			       struct sk_buff *tmpl);
 int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
 			   enum wmi_host_hw_mode_config_type mode);
-
+int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
+					    const u8 *ptas_cfg);
+int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
+					     const u8 *ptas_data);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Thu Sep  7 03:17:08 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Thu, 7 Sep 2023 18:17:08 +0800
Subject: [PATCH v3 2/4] wifi: ath12k: add BIOS SAR capability for WCN7850
In-Reply-To: <20230907101710.11659-1-quic_lingbok@quicinc.com>
References: <20230907101710.11659-1-quic_lingbok@quicinc.com>
Message-ID: <20230907101710.11659-3-quic_lingbok@quicinc.com>

ath12k get the latest BIOS SAR power table by using ACPI _DSM method, then
pass this table to the firmware.ath12k register a notification callback for
ACPI event so ACPI can notify ath12k to get the latest BIOS SAR table.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v3:
1.adjust the order of the macros
2.apply jeff's advice
3.remove unnecessary cpu_to_le32()

v2:
no change

 drivers/net/wireless/ath/ath12k/acpi.c | 103 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  18 +++++
 drivers/net/wireless/ath/ath12k/core.h |   3 +
 drivers/net/wireless/ath/ath12k/wmi.c  |  92 ++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  21 +++++
 5 files changed, 237 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index 384e01748b32..ae1ce7b99d2d 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -52,6 +52,26 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
+				ath12k_err(ab, "Invalid BIOS SAR data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->bios_sar_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
+				ath12k_err(ab, "Invalid GEO OFFSET data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -83,6 +103,24 @@ static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
 	return ret;
 }
 
+static int ath12k_set_bios_sar_power_limit_data(struct ath12k_base *ab)
+{
+	int ret;
+
+	if (ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
+	    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
+		ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
+							       ab->acdata->bios_sar_data);
+		if (ret)
+			ath12k_err(ab, "failed to pass bios sar table %d\n", ret);
+	} else {
+		ath12k_err(ab, "the latest bios sar data is invalid\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
 {
 	int ret;
@@ -101,6 +139,20 @@ void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
 			if (ret)
 				return;
 		}
+
+		if (ab->acdata->acpi_bios_sar_enable) {
+			ret = ath12k_acpi_dsm_get_data(ab,
+						       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
+			if (ret) {
+				ath12k_err(ab, "failed to update bios sar %d\n", ret);
+				return;
+			}
+
+			ret = ath12k_set_bios_sar_power_limit_data(ab);
+			if (ret)
+				return;
+		}
+
 	} else {
 		ath12k_err(ab, "unknown acpi notify %u\n", event);
 	}
@@ -113,6 +165,27 @@ void ath12k_acpi_remove_notify(struct ath12k_base *ab)
 				   acpi_dsm_notify);
 }
 
+static int ath12k_pass_acpi_bios_sar_and_geo_to_fw(struct ath12k_base *ab)
+{
+	int ret;
+
+	ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
+						       ab->acdata->bios_sar_data);
+
+	if (ret) {
+		ath12k_err(ab, "failed to pass bios sar table to fw %d\n", ret);
+		return ret;
+	}
+
+	ret = ath12k_wmi_pdev_set_bios_geo_table_param(ab,
+						       ab->acdata->geo_offset_data);
+
+	if (ret)
+		ath12k_err(ab, "failed to pass bios geo table to fw %d\n", ret);
+
+	return ret;
+}
+
 static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
 {
 	int ret;
@@ -172,12 +245,42 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 			ab->acdata->acpi_tas_enable = true;
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
+		if (ret) {
+			ath12k_err(ab, "failed to get bios sar data %d\n", ret);
+			goto err_free_acdata;
+		}
+	}
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET);
+		if (ret) {
+			ath12k_err(ab, "failed to get geo offset data %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
+		    ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
+		    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
+		    !ab->acdata->acpi_tas_enable)
+			ab->acdata->acpi_bios_sar_enable = true;
+	}
+
 	if (ab->acdata->acpi_tas_enable) {
 		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
 		if (ret)
 			goto err_free_acdata;
 	}
 
+	if (ab->acdata->acpi_bios_sar_enable) {
+		ret = ath12k_pass_acpi_bios_sar_and_geo_to_fw(ab);
+		if (ret)
+			goto err_free_acdata;
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index 2331b8e3e035..2f930f0718da 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -9,9 +9,13 @@
 #include <linux/acpi.h>
 
 #define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
+#define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR             4
+#define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET           5
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
 
+#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
+#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
 
@@ -20,10 +24,24 @@
 
 #define ATH12K_ACPI_TAS_DATA_VERSION		0x1
 #define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
+#define ATH12K_ACPI_POWER_LIMIT_VERSION		0x1
+#define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
+
+#define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
+#define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET	2
+#define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN	10
+#define ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET	12
+#define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
+#define ATH12K_ACPI_BIOS_SAR_TABLE_LEN		22
 
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 
+#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE (ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET + \
+					      ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN)
+#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE (ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET + \
+					    ATH12K_ACPI_BIOS_SAR_TABLE_LEN)
+
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
 #endif
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index cba4f176c018..6fe4f0ddee4a 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -775,8 +775,11 @@ struct ath12k_base {
 	struct {
 		u32 func_bit;
 		bool acpi_tas_enable;
+		bool acpi_bios_sar_enable;
 		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
 		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
+		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
+		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index f49f4325edff..9ad588897b09 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6998,3 +6998,95 @@ int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
 
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
+					     u8 *psar_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_sar_table_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, sar_table_len_aligned, sar_dbs_backoff_len_aligned;
+	u8 *psar_value = psar_table + ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET;
+	u8 *pdbs_value = psar_table + ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET;
+
+	sar_table_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_TABLE_LEN, sizeof(u32));
+	sar_dbs_backoff_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_table_len_aligned +
+		TLV_HDR_SIZE + sar_dbs_backoff_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_sar_table_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->sar_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
+	cmd->dbs_backoff_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
+					 sar_table_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, psar_value, ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
+
+	buf_ptr += sar_table_len_aligned;
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
+					 sar_dbs_backoff_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pdbs_value, ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
+					     u8 *pgeo_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_geo_table_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, sar_geo_len_aligned;
+	u8 *pgeo_value = pgeo_table + ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET;
+
+	sar_geo_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_geo_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_geo_table_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->geo_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, sar_geo_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pgeo_value, ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 38bbf59fc6b7..8a774655fe9f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -361,6 +361,8 @@ 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_BIOS_SAR_TABLE_CMDID = 0x4044,
+	WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045,
 	WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
@@ -1932,6 +1934,8 @@ enum wmi_tlv_tag {
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
 	WMI_TAG_EHT_RATE_SET = 0x3C4,
+	WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS = 0x3D8,
+	WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS = 0x3D9,
 	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
 	WMI_TAG_MAX
 };
@@ -4806,6 +4810,19 @@ enum bios_param_type {
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
+struct wmi_pdev_set_bios_sar_table_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 sar_len;
+	__le32 dbs_backoff_len;
+} __packed;
+
+struct wmi_pdev_set_bios_geo_table_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 geo_len;
+} __packed;
+
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
@@ -4931,4 +4948,8 @@ int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
 					    const u8 *ptas_cfg);
 int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
 					     const u8 *ptas_data);
+int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
+					     u8 *psar_table);
+int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
+					     u8 *pgeo_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Thu Sep  7 03:17:09 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Thu, 7 Sep 2023 18:17:09 +0800
Subject: [PATCH v3 3/4] wifi: ath12k: adjust configuration of CCA threshold value
In-Reply-To: <20230907101710.11659-1-quic_lingbok@quicinc.com>
References: <20230907101710.11659-1-quic_lingbok@quicinc.com>
Message-ID: <20230907101710.11659-4-quic_lingbok@quicinc.com>

ath12k need to adjust CCA threshold values to meet the regulatory
requirement. ath12k can retrieve CCA threshold configuration by invoking
ACPI _DSM method.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v3:
1.remove unnecessary cpu_to_le32()
2.adjust the order of the macros
3.apply jeff's advice

v2:
no change

 drivers/net/wireless/ath/ath12k/acpi.c | 30 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  8 ++++++
 drivers/net/wireless/ath/ath12k/core.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 40 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  7 +++--
 5 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index ae1ce7b99d2d..a9931e17bd17 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -72,6 +72,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {
+				ath12k_err(ab, "Invalid CCA data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -281,6 +291,26 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 			goto err_free_acdata;
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_CCA)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
+		if (ret) {
+			ath12k_err(ab, "failed to get cca threshold configuration %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ab->acdata->cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
+		    ab->acdata->cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
+		    ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {
+			ret = ath12k_wmi_pdev_set_cca_thr_table_param(ab,
+								      ab->acdata->cca_data);
+			if (ret) {
+				ath12k_err(ab, "set cca threshold failed %d\n", ret);
+				goto err_free_acdata;
+			}
+		}
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index 2f930f0718da..1f05a68e490b 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -11,11 +11,13 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
 #define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR             4
 #define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET           5
+#define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
 
 #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
 #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
+#define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
 
@@ -26,13 +28,17 @@
 #define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
 #define ATH12K_ACPI_POWER_LIMIT_VERSION		0x1
 #define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
+#define ATH12K_ACPI_CCA_THR_VERSION		0x1
+#define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
 
 #define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
 #define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET	2
+#define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET	5
 #define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN	10
 #define ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET	12
 #define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
 #define ATH12K_ACPI_BIOS_SAR_TABLE_LEN		22
+#define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
 
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
@@ -41,6 +47,8 @@
 					      ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN)
 #define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE (ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET + \
 					    ATH12K_ACPI_BIOS_SAR_TABLE_LEN)
+#define ATH12K_ACPI_DSM_CCA_DATA_SIZE (ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET + \
+				       ATH12K_ACPI_CCA_THR_OFFSET_LEN)
 
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 6fe4f0ddee4a..d57e2013b0fe 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -780,6 +780,7 @@ struct ath12k_base {
 		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
 		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
 		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
+		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 9ad588897b09..727ce28abd7d 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7090,3 +7090,43 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
+					    u8 *pcca_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, cca_thr_len_aligned;
+	u8 *pcca_value = pcca_table + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
+
+	cca_thr_len_aligned = roundup(ATH12K_ACPI_CCA_THR_OFFSET_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + cca_thr_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE);
+	cmd->length = ATH12K_ACPI_CCA_THR_OFFSET_LEN;
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, cca_thr_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pcca_value, ATH12K_ACPI_CCA_THR_OFFSET_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 8a774655fe9f..7607cd7ab699 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4805,8 +4805,9 @@ struct wmi_pdev_set_bios_interface_cmd {
 } __packed;
 
 enum bios_param_type {
-	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
-	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
+	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
+	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
+	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
@@ -4952,4 +4953,6 @@ int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
 					     u8 *psar_table);
 int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 					     u8 *pgeo_table);
+int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
+					    u8 *pcca_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Thu Sep  7 03:17:10 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Thu, 7 Sep 2023 18:17:10 +0800
Subject: [PATCH v3 4/4] wifi: ath12k: add band edge channel power for WCN7850
In-Reply-To: <20230907101710.11659-1-quic_lingbok@quicinc.com>
References: <20230907101710.11659-1-quic_lingbok@quicinc.com>
Message-ID: <20230907101710.11659-5-quic_lingbok@quicinc.com>

ath12k need to retrieve band edge channel power table by invoking ACPI _DSM
method, then pass the table to firmware.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v3:
1.remove unnecessary cpu_to_le32()
2.adjust the order of the macros

v2:
no change

 drivers/net/wireless/ath/ath12k/acpi.c | 29 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  5 ++++
 drivers/net/wireless/ath/ath12k/core.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 40 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  3 ++
 5 files changed, 78 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index a9931e17bd17..389b900df170 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -82,6 +82,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {
+				ath12k_err(ab, "Invalid BAND EDGE data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->band_edge_power, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -311,6 +321,25 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 		}
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);
+		if (ret) {
+			ath12k_err(ab, "failed to get band edge channel power %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ab->acdata->band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
+		    ab->acdata->band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {
+			ret = ath12k_wmi_pdev_set_band_edge_power(ab,
+								  ab->acdata->band_edge_power);
+			if (ret) {
+				ath12k_err(ab, "set band edge channel power failed %d\n", ret);
+				goto err_free_acdata;
+			}
+		}
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index 1f05a68e490b..27f28fc13600 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -14,12 +14,14 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
+#define ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE		10
 
 #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
 #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
 #define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
+#define ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER	BIT(9)
 
 #define ATH12K_ACPI_NOTIFY_EVENT			0x86
 #define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
@@ -30,6 +32,8 @@
 #define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
 #define ATH12K_ACPI_CCA_THR_VERSION		0x1
 #define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
+#define ATH12K_ACPI_BAND_EDGE_VERSION		0x1
+#define ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG	0x1
 
 #define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
 #define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET	2
@@ -41,6 +45,7 @@
 #define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
 
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
+#define ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE		100
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 
 #define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE (ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET + \
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d57e2013b0fe..d06c3984aef9 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -781,6 +781,7 @@ struct ath12k_base {
 		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
 		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
 		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
+		u8 band_edge_power[ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 727ce28abd7d..102228229932 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7130,3 +7130,43 @@ int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
 	}
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
+					const u8 *pchan_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pchan_table, ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 7607cd7ab699..73d790d405cd 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4808,6 +4808,7 @@ enum bios_param_type {
 	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
 	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
 	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
+	WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER	=	3,
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
@@ -4955,4 +4956,6 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 					     u8 *pgeo_table);
 int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
 					    u8 *pcca_table);
+int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
+					const u8 *pchan_table);
 #endif
-- 
2.34.1



From quic_jjohnson at quicinc.com  Thu Sep  7 09:12:29 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Thu, 7 Sep 2023 09:12:29 -0700
Subject: [PATCH v2] wifi: ath12k: add support for hardware rfkill for
 WCN7850
In-Reply-To: <20230906110412.182176-1-quic_lingbok@quicinc.com>
References: <20230906110412.182176-1-quic_lingbok@quicinc.com>
Message-ID: <d93aa6f3-e6a2-47d8-a4c4-55994ed79b12@quicinc.com>

On 9/6/2023 4:04 AM, Lingbo Kong wrote:
> When hardware rfkill is enabled in the firmware, it will report the
> capability using WMI_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY event
> to the host. Currently ath12k does not process this service capability. In
> order to support this, update ath12k to check if the capability is enabled,
> if so, send the GPIO information to firmware. When the firmware detects
> hardware rfkill is enabled by the user, it will report it using
> WMI_RFKILL_STATE_CHANGE_EVENTID. When ath12k receive the event, it will set
> the value of rfkill_radio_on based on whether radio_state is equal to
> WMI_RFKILL_RADIO_STATE_ON, then send WMI_PDEV_PARAM_RFKILL_ENABLE to
> firmware.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
> v2:
> 1.s/via//
> 2.modify commit log
> 3.use an endian-conversion macro
> 
>   drivers/net/wireless/ath/ath12k/core.c | 52 +++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/core.h |  4 ++
>   drivers/net/wireless/ath/ath12k/hw.c   | 12 ++++++
>   drivers/net/wireless/ath/ath12k/hw.h   |  4 ++
>   drivers/net/wireless/ath/ath12k/mac.c  | 58 ++++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/mac.h  |  2 +
>   drivers/net/wireless/ath/ath12k/wmi.c  | 39 +++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h  | 25 +++++++++++
>   8 files changed, 196 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 39f938fafa81..c6fb1e435d86 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -19,6 +19,27 @@ unsigned int ath12k_debug_mask;
>   module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
>   MODULE_PARM_DESC(debug_mask, "Debugging mask");
>   
> +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;
> +
> +	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;
> +}
> +
>   int ath12k_core_suspend(struct ath12k_base *ab)
>   {
>   	int ret;
> @@ -603,6 +624,13 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
>   		goto err_core_stop;
>   	}
>   	ath12k_hif_irq_enable(ab);
> +
> +	ret = ath12k_core_rfkill_config(ab);
> +	if (ret && ret != -EOPNOTSUPP) {
> +		ath12k_err(ab, "failed to config rfkill: %d\n", ret);
> +		goto err_core_stop;
> +	}
> +
>   	mutex_unlock(&ab->core_lock);
>   
>   	return 0;
> @@ -655,6 +683,27 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab)
>   	return ret;
>   }
>   
> +static void ath12k_rfkill_work(struct work_struct *work)
> +{
> +	struct ath12k_base *ab = container_of(work, struct ath12k_base, rfkill_work);
> +	struct ath12k *ar;
> +	bool rfkill_radio_on;
> +	int i;
> +
> +	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)
> +			continue;
> +
> +		ath12k_mac_rfkill_enable_radio(ar, rfkill_radio_on);
> +		wiphy_rfkill_set_hw_state(ar->hw->wiphy, !rfkill_radio_on);
> +	}
> +}
> +
>   void ath12k_core_halt(struct ath12k *ar)
>   {
>   	struct ath12k_base *ab = ar->ab;
> @@ -668,6 +717,7 @@ void ath12k_core_halt(struct ath12k *ar)
>   	ath12k_mac_peer_cleanup_all(ar);
>   	cancel_delayed_work_sync(&ar->scan.timeout);
>   	cancel_work_sync(&ar->regd_update_work);
> +	cancel_work_sync(&ab->rfkill_work);
>   
>   	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
>   	synchronize_rcu();
> @@ -921,6 +971,8 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
>   	init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
>   	INIT_WORK(&ab->restart_work, ath12k_core_restart);
>   	INIT_WORK(&ab->reset_work, ath12k_core_reset);
> +	INIT_WORK(&ab->rfkill_work, ath12k_rfkill_work);
> +
>   	timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
>   	init_completion(&ab->htc_suspend);
>   
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index d873b573dac6..3f5f0471f640 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -771,6 +771,10 @@ struct ath12k_base {
>   	u64 fw_soc_drop_count;
>   	bool static_window_map;
>   
> +	struct work_struct rfkill_work;
> +	/* true means radio is on */
> +	bool rfkill_radio_on;
> +
>   	/* must be last */
>   	u8 drv_priv[] __aligned(sizeof(void *));
>   };
> diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
> index 5991cc91cd00..f69649f58e82 100644
> --- a/drivers/net/wireless/ath/ath12k/hw.c
> +++ b/drivers/net/wireless/ath/ath12k/hw.c
> @@ -907,6 +907,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   		.hal_ops = &hal_qcn9274_ops,
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
> +
> +		.rfkill_pin = 0,
> +		.rfkill_cfg = 0,
> +		.rfkill_on_level = 0,
>   	},
>   	{
>   		.name = "wcn7850 hw2.0",
> @@ -964,6 +968,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
>   					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
> +
> +		.rfkill_pin = 48,
> +		.rfkill_cfg = 0,
> +		.rfkill_on_level = 1,
>   	},
>   	{
>   		.name = "qcn9274 hw2.0",
> @@ -1019,6 +1027,10 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   		.hal_ops = &hal_qcn9274_ops,
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
> +
> +		.rfkill_pin = 0,
> +		.rfkill_cfg = 0,
> +		.rfkill_on_level = 0,
>   	},
>   };
>   
> diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
> index e6c4223c283c..1b4912bf57ad 100644
> --- a/drivers/net/wireless/ath/ath12k/hw.h
> +++ b/drivers/net/wireless/ath/ath12k/hw.h
> @@ -186,6 +186,10 @@ struct ath12k_hw_params {
>   	const struct hal_ops *hal_ops;
>   
>   	u64 qmi_cnss_feature_bitmap;
> +
> +	u32 rfkill_pin;
> +	u32 rfkill_cfg;
> +	u32 rfkill_on_level;
>   };
>   
>   struct ath12k_hw_ops {
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 8cc9ae2204b8..bfba9ad18776 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5108,6 +5108,63 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
>   	return ret;
>   }
>   
> +int ath12k_mac_rfkill_config(struct ath12k *ar)
> +{
> +	struct ath12k_base *ab = ar->ab;
> +	u32 param;
> +	int ret;
> +
> +	if (ab->hw_params->rfkill_pin == 0)
> +		return -EOPNOTSUPP;
> +
> +	ath12k_dbg(ab, ATH12K_DBG_MAC,
> +		   "mac rfkill_pin %d rfkill_cfg %d rfkill_on_level %d",
> +		   ab->hw_params->rfkill_pin, ab->hw_params->rfkill_cfg,
> +		   ab->hw_params->rfkill_on_level);
> +
> +	param = u32_encode_bits(ab->hw_params->rfkill_on_level,
> +				WMI_RFKILL_CFG_RADIO_LEVEL) |
> +		u32_encode_bits(ab->hw_params->rfkill_pin,
> +				WMI_RFKILL_CFG_GPIO_PIN_NUM) |
> +		u32_encode_bits(ab->hw_params->rfkill_cfg,
> +				WMI_RFKILL_CFG_PIN_AS_GPIO);
> +
> +	ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_HW_RFKILL_CONFIG,
> +					param, ar->pdev->pdev_id);
> +	if (ret) {
> +		ath12k_warn(ab,
> +			    "failed to set rfkill config 0x%x: %d\n",
> +			    param, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable)
> +{
> +	enum wmi_rfkill_enable_radio param;
> +	int ret;
> +
> +	if (enable)
> +		param = WMI_RFKILL_ENABLE_RADIO_ON;
> +	else
> +		param = WMI_RFKILL_ENABLE_RADIO_OFF;
> +
> +	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac %d rfkill enable %d",
> +		   ar->pdev_idx, param);
> +
> +	ret = ath12k_wmi_pdev_set_param(ar, WMI_PDEV_PARAM_RFKILL_ENABLE,
> +					param, ar->pdev->pdev_id);
> +	if (ret) {
> +		ath12k_warn(ar->ab, "failed to set rfkill enable param %d: %d\n",
> +			    param, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
>   static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
>   {
>   	struct ath12k *ar = hw->priv;
> @@ -5128,6 +5185,7 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
>   
>   	cancel_delayed_work_sync(&ar->scan.timeout);
>   	cancel_work_sync(&ar->regd_update_work);
> +	cancel_work_sync(&ar->ab->rfkill_work);
>   
>   	spin_lock_bh(&ar->data_lock);
>   	list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
> diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
> index 7b16b70df4fa..59b4e8f5eee0 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.h
> +++ b/drivers/net/wireless/ath/ath12k/mac.h
> @@ -73,4 +73,6 @@ int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
>   enum rate_info_bw ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw);
>   enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw bw);
>   enum hal_encrypt_type ath12k_dp_tx_get_encrypt_type(u32 cipher);
> +int ath12k_mac_rfkill_enable_radio(struct ath12k *ar, bool enable);
> +int ath12k_mac_rfkill_config(struct ath12k *ar);
>   #endif
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index f48ab69e256a..5bd357ea8a75 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -152,6 +152,8 @@ static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
>   		.min_len = sizeof(struct wmi_service_available_event) },
>   	[WMI_TAG_PEER_ASSOC_CONF_EVENT] = {
>   		.min_len = sizeof(struct wmi_peer_assoc_conf_event) },
> +	[WMI_TAG_RFKILL_EVENT] = {
> +		.min_len = sizeof(struct wmi_rfkill_state_change_event) },
>   	[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT] = {
>   		.min_len = sizeof(struct wmi_pdev_ctl_failsafe_chk_event) },
>   	[WMI_TAG_HOST_SWFDA_EVENT] = {
> @@ -6602,6 +6604,40 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
>   	kfree(tb);
>   }
>   
> +static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
> +					     struct sk_buff *skb)
> +{
> +	const struct wmi_rfkill_state_change_event *ev;
> +	const void **tb;
> +	int ret;
> +
> +	tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
> +	if (IS_ERR(tb)) {
> +		ret = PTR_ERR(tb);
> +		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> +		return;
> +	}
> +
> +	ev = tb[WMI_TAG_RFKILL_EVENT];
> +	if (!ev) {
> +		kfree(tb);
> +		return;
> +	}
> +
> +	ath12k_dbg(ab, ATH12K_DBG_MAC,
> +		   "wmi tlv rfkill state change gpio %d type %d radio_state %d\n",
> +		   le32_to_cpu(ev->gpio_pin_num),
> +		   le32_to_cpu(ev->int_type),
> +		   le32_to_cpu(ev->radio_state));
> +
> +	spin_lock_bh(&ab->base_lock);
> +	ab->rfkill_radio_on = (ev->radio_state == cpu_to_le32(WMI_RFKILL_RADIO_STATE_ON));
> +	spin_unlock_bh(&ab->base_lock);
> +
> +	queue_work(ab->workqueue, &ab->rfkill_work);
> +	kfree(tb);
> +}
> +
>   static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
>   {
>   	struct wmi_cmd_hdr *cmd_hdr;
> @@ -6694,6 +6730,9 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
>   	case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID:
>   		ath12k_probe_resp_tx_status_event(ab, skb);
>   		break;
> +	case WMI_RFKILL_STATE_CHANGE_EVENTID:
> +		ath12k_rfkill_state_change_event(ab, skb);
> +		break;
>   	/* add Unsupported events here */
>   	case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
>   	case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index c75a6fa1f7e0..965755b4cbfd 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -4793,6 +4793,31 @@ struct ath12k_wmi_base {
>   
>   #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
>   
> +enum wmi_sys_cap_info_flags {
> +	WMI_SYS_CAP_INFO_RXTX_LED	= BIT(0),
> +	WMI_SYS_CAP_INFO_RFKILL		= BIT(1),
> +};
> +
> +#define WMI_RFKILL_CFG_GPIO_PIN_NUM		GENMASK(5, 0)
> +#define WMI_RFKILL_CFG_RADIO_LEVEL		BIT(6)
> +#define WMI_RFKILL_CFG_PIN_AS_GPIO		GENMASK(10, 7)
> +
> +enum wmi_rfkill_enable_radio {
> +	WMI_RFKILL_ENABLE_RADIO_ON	= 0,
> +	WMI_RFKILL_ENABLE_RADIO_OFF	= 1,
> +};
> +
> +enum wmi_rfkill_radio_state {
> +	WMI_RFKILL_RADIO_STATE_OFF	= 1,
> +	WMI_RFKILL_RADIO_STATE_ON	= 2,
> +};
> +
> +struct wmi_rfkill_state_change_event {
> +	__le32 gpio_pin_num;
> +	__le32 int_type;
> +	__le32 radio_state;
> +} __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,
> 
> base-commit: 1b5b69a51bb4909844e4003920af09ca1cc6bb0e



From quic_jjohnson at quicinc.com  Fri Sep  8 07:59:12 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Fri, 8 Sep 2023 07:59:12 -0700
Subject: [PATCH 2/4] wifi: ath12k: add 11d scan offload support
In-Reply-To: <20230906082948.18452-3-quic_wgong@quicinc.com>
References: <20230906082948.18452-1-quic_wgong@quicinc.com>
 <20230906082948.18452-3-quic_wgong@quicinc.com>
Message-ID: <51437508-874e-4e6f-8b6e-89b49e4c9704@quicinc.com>

On 9/6/2023 1:29 AM, Wen Gong wrote:
> Add handler for WMI_11D_NEW_COUNTRY_EVENTID, WMI_11D_SCAN_START_CMDID,
> WMI_11D_SCAN_STOP_CMDID.
> 
> The priority of 11d scan WMI_SCAN_PRIORITY_MEDIUM in firmware, the
> priority of hw scan is WMI_SCAN_PRIORITY_LOW, then the 11d scan will
> cancel the hw scan which is running. To avoid this, change the priority
> of the 1st hw scan to WMI_SCAN_PRIORITY_MEDIUM. Add wait_for_completion_timeout
> for ar->scan.completed in ath12k_reg_update_chan_list(), plus the existing
> wait in ath12k_scan_stop(), then ath12k have 2 place to wait the
> ar->scan.completed, they run in different thread, thus it is possible to
> happen that the two threads both enter wait status. To handle this scenario,
> ath12k should change the complete() to complete_all() for the ar->scan.completed,
> this also work well when it is only one thread wait for ar->scan.completed.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/core.c |  35 ++++-
>   drivers/net/wireless/ath/ath12k/core.h |  16 +++
>   drivers/net/wireless/ath/ath12k/mac.c  | 170 ++++++++++++++++++++++++-
>   drivers/net/wireless/ath/ath12k/mac.h  |   7 +
>   drivers/net/wireless/ath/ath12k/reg.c  |  37 +++++-
>   drivers/net/wireless/ath/ath12k/reg.h  |   3 +-
>   drivers/net/wireless/ath/ath12k/wmi.c  | 123 +++++++++++++++++-
>   drivers/net/wireless/ath/ath12k/wmi.h  |  25 ++++
>   8 files changed, 406 insertions(+), 10 deletions(-)

...

> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 8940b8154091..890063c9e268 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -3792,6 +3792,28 @@ struct wmi_init_country_cmd {
>   	} cc_info;
>   } __packed;
>   
> +struct wmi_11d_scan_start_params {
> +	u32 vdev_id;
> +	u32 scan_period_msec;
> +	u32 start_interval_msec;
> +};
> +
> +struct wmi_11d_scan_start_cmd {
> +	__le32 tlv_header;
> +	__le32 vdev_id;
> +	__le32 scan_period_msec;
> +	__le32 start_interval_msec;
> +} __packed;
> +
> +struct wmi_11d_scan_stop_cmd {
> +	__le32 tlv_header;
> +	__le32 vdev_id;
> +} __packed;
> +
> +struct wmi_11d_new_cc_ev {

one nit: does not conform to the naming convention:
  * _event means that this is a firmware event sent from firmware to host

> +	__le32 new_alpha2;
> +} __packed;
> +
>   struct wmi_delba_send_cmd {
>   	__le32 tlv_header;
>   	__le32 vdev_id;
> @@ -4897,6 +4919,9 @@ int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar,
>   					   dma_addr_t paddr, u8 tid,
>   					   u8 ba_window_size_valid,
>   					   u32 ba_window_size);
> +int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar,
> +				       struct wmi_11d_scan_start_params *param);
> +int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id);
>   int
>   ath12k_wmi_rx_reord_queue_remove(struct ath12k *ar,
>   				 struct ath12k_wmi_rx_reorder_queue_remove_arg *arg);



From quic_jjohnson at quicinc.com  Fri Sep  8 08:07:26 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Fri, 8 Sep 2023 08:07:26 -0700
Subject: [PATCH 4/4] wifi: ath12k: store and send country code to firmware
 after recovery
In-Reply-To: <20230906082948.18452-5-quic_wgong@quicinc.com>
References: <20230906082948.18452-1-quic_wgong@quicinc.com>
 <20230906082948.18452-5-quic_wgong@quicinc.com>
Message-ID: <3a4e40fe-1cf7-45b8-90a2-028d6a5c325b@quicinc.com>

On 9/6/2023 1:29 AM, Wen Gong wrote:
> Currently ath12k does not send the country code to firmware after device
> recovery. As a result the regdomain info is reported from firmware by
> default. Regdomain info is important, so ath12k also need to restore
> it to the value which was used before recovery.
> 
> This is only needed for platforms which support the current_cc_support
> hardware parameter.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/core.c | 1 +
>   drivers/net/wireless/ath/ath12k/core.h | 1 +
>   drivers/net/wireless/ath/ath12k/mac.c  | 8 ++++++++
>   drivers/net/wireless/ath/ath12k/reg.c  | 1 +
>   4 files changed, 11 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 71450dc1f48d..4433d7701c67 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -696,6 +696,7 @@ static void ath12k_update_11d(struct work_struct *work)
>   		pdev = &ab->pdevs[i];
>   		ar = pdev->ar;
>   
> +		memcpy(&ar->alpha2, &set_current_param.alpha2, 2);
>   		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
>   		if (ret)
>   			ath12k_warn(ar->ab,
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index ba8a4f968a3f..10fa9de15024 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -582,6 +582,7 @@ struct ath12k {
>   	struct completion completed_11d_scan;
>   	enum ath12k_11d_state state_11d;
>   	bool regdom_set_by_user;
> +	u8 alpha2[REG_ALPHA2_LEN + 1];

curious why +1?
don't you always just treat this as a 2-octet array rather than as a 
NUL-terminated string?


>   };
>   
>   struct ath12k_band_cap {
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 740e8045a6f1..0df154c34f8f 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -6908,6 +6908,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
>   		ar->state = ATH12K_STATE_ON;
>   		ieee80211_wake_queues(ar->hw);
>   
> +		if (ar->ab->hw_params->current_cc_support &&
> +		    ar->alpha2[0] != 0 && ar->alpha2[1] != 0) {
> +			struct wmi_set_current_country_params set_current_param = {};
> +
> +			memcpy(&set_current_param.alpha2, ar->alpha2, 2);
> +			ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
> +		}
> +
>   		if (ab->is_reset) {
>   			recovery_count = atomic_inc_return(&ab->recovery_count);
>   			ath12k_dbg(ab, ATH12K_DBG_BOOT, "recovery count %d\n",
> diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
> index 97c93a4901e6..eb46bfc2b2b9 100644
> --- a/drivers/net/wireless/ath/ath12k/reg.c
> +++ b/drivers/net/wireless/ath/ath12k/reg.c
> @@ -82,6 +82,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
>   	 */
>   	if (ar->ab->hw_params->current_cc_support) {
>   		memcpy(&set_current_param.alpha2, request->alpha2, 2);
> +		memcpy(&ar->alpha2, &set_current_param.alpha2, 2);
>   
>   		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
>   		if (ret)



From quic_jjohnson at quicinc.com  Fri Sep  8 08:16:03 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Fri, 8 Sep 2023 08:16:03 -0700
Subject: [PATCH 1/4] wifi: ath12k: add configure country code for WCN7850
In-Reply-To: <20230906082948.18452-2-quic_wgong@quicinc.com>
References: <20230906082948.18452-1-quic_wgong@quicinc.com>
 <20230906082948.18452-2-quic_wgong@quicinc.com>
Message-ID: <8b2a0893-c866-42f6-8567-e70bcadbc6c1@quicinc.com>

On 9/6/2023 1:29 AM, Wen Gong wrote:
> Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware which
> is used for WCN7850.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/wmi.c | 36 +++++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h | 13 ++++++++++
>   2 files changed, 49 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 9ed33e2d6da0..aa87b559eff1 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -2844,6 +2844,42 @@ int ath12k_wmi_send_init_country_cmd(struct ath12k *ar,
>   	return ret;
>   }
>   
> +int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
> +					    struct wmi_set_current_country_params *param)
> +{
> +	struct ath12k_wmi_pdev *wmi = ar->wmi;
> +	struct wmi_set_current_country_cmd *cmd;
> +	struct sk_buff *skb;
> +	int ret;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_set_current_country_cmd *)skb->data;
> +	cmd->tlv_header =
> +		ath12k_wmi_tlv_cmd_hdr(WMI_TAG_SET_CURRENT_COUNTRY_CMD,
> +				       sizeof(*cmd));
> +
> +	cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id);
> +	memcpy(&cmd->new_alpha2, &param->alpha2, 3);
> +	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID);
> +
> +	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
> +		   "set current country pdev id %d alpha2 %c%c\n",
> +		   ar->pdev->pdev_id,
> +		   param->alpha2[0],
> +		   param->alpha2[1]);
> +
> +	if (ret) {
> +		ath12k_warn(ar->ab,
> +			    "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> +
>   int
>   ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id)
>   {
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 8c047a9623f9..8940b8154091 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -3749,6 +3749,16 @@ struct ath12k_wmi_ap_ps_arg {
>   	u32 value;
>   };
>   
> +struct wmi_set_current_country_params {
> +	u8 alpha2[3];

having looked though the set of patches, I'm curious why this is [3] and 
not [2] (or IMO more correctly, [REG_ALPHA2_LEN]).
Isn't this read/written as two octets everywhere and never treated as a 
NUL-terminated string?

> +};
> +
> +struct wmi_set_current_country_cmd {
> +	__le32 tlv_header;
> +	__le32 pdev_id;
> +	__le32 new_alpha2;
> +} __packed;
> +
>   enum set_init_cc_type {
>   	WMI_COUNTRY_INFO_TYPE_ALPHA,
>   	WMI_COUNTRY_INFO_TYPE_COUNTRY_CODE,
> @@ -4879,6 +4889,9 @@ int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar,
>   					    u32 vdev_id, u32 bcn_ctrl_op);
>   int ath12k_wmi_send_init_country_cmd(struct ath12k *ar,
>   				     struct ath12k_wmi_init_country_arg *arg);
> +int
> +ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
> +					struct wmi_set_current_country_params *param);
>   int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar,
>   					   int vdev_id, const u8 *addr,
>   					   dma_addr_t paddr, u8 tid,



From quic_jjohnson at quicinc.com  Fri Sep  8 08:23:48 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Fri, 8 Sep 2023 08:23:48 -0700
Subject: [PATCH] wifi: ath12k: indicate scan complete for scan canceled
 when scan running
In-Reply-To: <20230906085746.18968-1-quic_wgong@quicinc.com>
References: <20230906085746.18968-1-quic_wgong@quicinc.com>
Message-ID: <232a1b91-f7b4-44da-8c91-b65bb661f22c@quicinc.com>

On 9/6/2023 1:57 AM, Wen Gong wrote:
> ath12k prints "Received scan event for unknown vdev" when doing the
> following test:
> 1. trigger scan
> 2. wait 0.2 second
> 3. iw reg set is issued or 11d scan complete event is sent from firmware
> 
> Reason is:
> When iw reg set is issues or the 11d scan complete event is received, the
> new country code will be set to the firmware, and the new regdomain info
> indicated to ath12k, then the new channel list will be sent to the firmware.
> The firmware will cancel the current scan after receiving WMI_SCAN_CHAN_LIST_CMDID
> which is used for the new channel list, and the state of ath12k is
> ATH12K_SCAN_RUNNING, then ath12k_get_ar_on_scan_abort() returns NULL and
> ath12k_scan_event() returns at this point and does not indicate scan
> completion to mac80211.
> 
> Indicate scan completion to mac80211 and get rid of the "Received scan
> event for unknown vdev" print for the above case.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
>   drivers/net/wireless/ath/ath12k/wmi.c | 18 ++++++++++++------
>   1 file changed, 12 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 9ed33e2d6da0..d30de487f43f 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -5862,8 +5862,9 @@ static void ath12k_mgmt_tx_compl_event(struct ath12k_base *ab, struct sk_buff *s
>   	rcu_read_unlock();
>   }
>   
> -static struct ath12k *ath12k_get_ar_on_scan_abort(struct ath12k_base *ab,
> -						  u32 vdev_id)
> +static struct ath12k *ath12k_get_ar_on_scan_state(struct ath12k_base *ab,
> +						  u32 vdev_id,
> +						  enum ath12k_scan_state state)
>   {
>   	int i;
>   	struct ath12k_pdev *pdev;
> @@ -5875,7 +5876,7 @@ static struct ath12k *ath12k_get_ar_on_scan_abort(struct ath12k_base *ab,
>   			ar = pdev->ar;
>   
>   			spin_lock_bh(&ar->data_lock);
> -			if (ar->scan.state == ATH12K_SCAN_ABORTING &&
> +			if (ar->scan.state == state &&
>   			    ar->scan.vdev_id == vdev_id) {
>   				spin_unlock_bh(&ar->data_lock);
>   				return ar;
> @@ -5905,10 +5906,15 @@ static void ath12k_scan_event(struct ath12k_base *ab, struct sk_buff *skb)
>   	 * aborting scan's vdev id matches this event info.
>   	 */
>   	if (le32_to_cpu(scan_ev.event_type) == WMI_SCAN_EVENT_COMPLETED &&
> -	    le32_to_cpu(scan_ev.reason) == WMI_SCAN_REASON_CANCELLED)
> -		ar = ath12k_get_ar_on_scan_abort(ab, le32_to_cpu(scan_ev.vdev_id));
> -	else
> +	    le32_to_cpu(scan_ev.reason) == WMI_SCAN_REASON_CANCELLED) {
> +		ar = ath12k_get_ar_on_scan_state(ab, le32_to_cpu(scan_ev.vdev_id),
> +						 ATH12K_SCAN_ABORTING);
> +		if (!ar)
> +			ar = ath12k_get_ar_on_scan_state(ab, le32_to_cpu(scan_ev.vdev_id),
> +							 ATH12K_SCAN_RUNNING);
> +	} else {
>   		ar = ath12k_mac_get_ar_by_vdev_id(ab, le32_to_cpu(scan_ev.vdev_id));
> +	}
>   
>   	if (!ar) {
>   		ath12k_warn(ab, "Received scan event for unknown vdev");
> 
> base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e



From quic_jjohnson at quicinc.com  Fri Sep  8 08:24:52 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Fri, 8 Sep 2023 08:24:52 -0700
Subject: [PATCH] wifi: ath12k: change to treat alpha code na as world wide
 regdomain
In-Reply-To: <20230906090355.19181-1-quic_wgong@quicinc.com>
References: <20230906090355.19181-1-quic_wgong@quicinc.com>
Message-ID: <3870f85d-d769-40c7-851d-295ad9fd8708@quicinc.com>

On 9/6/2023 2:03 AM, Wen Gong wrote:
> Some firmware versions for WCN7850 report the default regdomain with
> alpha code "na" by default when load as a world wide regdomain,
> ath12k should treat it as a world wide alpha code.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
>   drivers/net/wireless/ath/ath12k/wmi.c | 8 +++++++-
>   1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 9ed33e2d6da0..4ebc09b35892 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -5390,7 +5390,13 @@ static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,
>   
>   static bool ath12k_reg_is_world_alpha(char *alpha)
>   {
> -	return alpha[0] == '0' && alpha[1] == '0';
> +	if (alpha[0] == '0' && alpha[1] == '0')
> +		return true;
> +
> +	if (alpha[0] == 'n' && alpha[1] == 'a')
> +		return true;
> +
> +	return false;
>   }
>   
>   static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
> 
> base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e



From quic_jjohnson at quicinc.com  Fri Sep  8 08:47:12 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Fri, 8 Sep 2023 08:47:12 -0700
Subject: [PATCH v3 1/4] wifi: ath12k: add TAS capability for WCN7850
In-Reply-To: <20230907101710.11659-2-quic_lingbok@quicinc.com>
References: <20230907101710.11659-1-quic_lingbok@quicinc.com>
 <20230907101710.11659-2-quic_lingbok@quicinc.com>
Message-ID: <3d754d62-0f03-401a-949a-5aa4ba861716@quicinc.com>

On 9/7/2023 3:17 AM, Lingbo Kong wrote:
> In order to enable Time-Average-SAR(TAS) for WCN7850, define some
> functions. One function is to return TAS configuration, the other return
> SAR power table, then ath12k apply these data to wlan firmware. ath12k
> register an ACPI event callback so that ACPI can notify ath12k to retrieve
> the updated SAR power table and apply it to wlan firmware.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
> ---
> v3:
> 1.remove unnecessary cpu_to_le32()
> 
> v2:
> 1.put <linux/acpi.h> in the include guard
> 
>   drivers/net/wireless/ath/ath12k/Makefile |   3 +-
>   drivers/net/wireless/ath/ath12k/acpi.c   | 203 +++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/acpi.h   |  29 ++++
>   drivers/net/wireless/ath/ath12k/core.c   |   6 +
>   drivers/net/wireless/ath/ath12k/core.h   |   8 +
>   drivers/net/wireless/ath/ath12k/hw.c     |  10 ++
>   drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
>   drivers/net/wireless/ath/ath12k/pci.c    |   6 +
>   drivers/net/wireless/ath/ath12k/wmi.c    |  80 +++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h    |  20 ++-
>   10 files changed, 366 insertions(+), 3 deletions(-)
>   create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
>   create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h
> 
> diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile
> index 62c52e733b5e..a479fe06caac 100644
> --- a/drivers/net/wireless/ath/ath12k/Makefile
> +++ b/drivers/net/wireless/ath/ath12k/Makefile
> @@ -19,7 +19,8 @@ ath12k-y += core.o \
>   	    hw.o \
>   	    mhi.o \
>   	    pci.o \
> -	    dp_mon.o
> +	    dp_mon.o \
> +	    acpi.o
>   
>   ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
>   
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
> new file mode 100644
> index 000000000000..384e01748b32
> --- /dev/null
> +++ b/drivers/net/wireless/ath/ath12k/acpi.c
> @@ -0,0 +1,203 @@
> +// 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.
> + */
> +
> +#include "core.h"
> +#include "acpi.h"
> +#include "debug.h"
> +
> +static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
> +{
> +	union acpi_object *obj;
> +	acpi_handle root_handle;
> +	int ret = 0;
> +
> +	root_handle = ACPI_HANDLE(ab->dev);
> +	if (!root_handle) {
> +		ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid ACPI handler\n");
> +		return -EOPNOTSUPP;
> +	}
> +
> +	obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,
> +				NULL);
> +
> +	if (!obj) {
> +		ath12k_dbg(ab, ATH12K_DBG_BOOT, "ACPI _DSM method invocation failed\n");
> +		return -ENOENT;
> +	}
> +
> +	if (obj->type == ACPI_TYPE_INTEGER) {
> +		ab->acdata->func_bit = obj->integer.value;
> +	} else if (obj->type == ACPI_TYPE_BUFFER) {
> +		switch (func) {
> +		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG:
> +			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
> +				ath12k_err(ab, "Invalid TAS cfg size %d\n",
> +					   obj->buffer.length);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			memcpy(&ab->acdata->tas_cfg, obj->buffer.pointer,
> +			       obj->buffer.length);
> +			break;
> +		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA:
> +			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {
> +				ath12k_err(ab, "Invalid TAS data size %d\n",
> +					   obj->buffer.length);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
> +			       obj->buffer.length);
> +			break;
> +		}
> +	} else {
> +		ath12k_err(ab,
> +			   "ACPI: DSM method did not return a valid object, type %d\n",
> +			   obj->type);
> +		ret = -EINVAL;
> +	}
> +
> +out:
> +	ACPI_FREE(obj);
> +	return ret;
> +}
> +
> +static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
> +{
> +	int ret;
> +
> +	if (ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
> +	    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG) {
> +		ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
> +							       ab->acdata->tas_sar_power_table);
> +		if (ret)
> +			ath12k_err(ab, "failed to pass tas data table %d\n", ret);
> +	} else {
> +		ath12k_err(ab, "the latest tas data is invalid\n");
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
> +{
> +	int ret;
> +	struct ath12k_base *ab = data;
> +
> +	if (event == ATH12K_ACPI_NOTIFY_EVENT) {
> +		if (ab->acdata->acpi_tas_enable) {
> +			ret = ath12k_acpi_dsm_get_data(ab,
> +						       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
> +			if (ret) {
> +				ath12k_err(ab, "failed to update tas data table %d\n", ret);
> +				return;
> +			}
> +
> +			ret = ath12k_set_tas_power_limit_data(ab);
> +			if (ret)
> +				return;
> +		}
> +	} else {
> +		ath12k_err(ab, "unknown acpi notify %u\n", event);
> +	}
> +}
> +
> +void ath12k_acpi_remove_notify(struct ath12k_base *ab)
> +{
> +	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
> +				   ACPI_DEVICE_NOTIFY,
> +				   acpi_dsm_notify);
> +}
> +
> +static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
> +{
> +	int ret;
> +
> +	ret = ath12k_wmi_pdev_set_tas_cfg_table_param(ab,
> +						      ab->acdata->tas_cfg);
> +	if (ret) {
> +		ath12k_err(ab, "failed to pass tas cfg table to fw %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
> +						       ab->acdata->tas_sar_power_table);
> +	if (ret)
> +		ath12k_err(ab, "failed to pass tas data table to fw %d\n", ret);
> +
> +	return ret;
> +}
> +
> +int ath12k_get_acpi_all_data(struct ath12k_base *ab)
> +{
> +	int ret;
> +	acpi_status status;
> +
> +	ab->acdata = kzalloc(sizeof(*ab->acdata), GFP_KERNEL);
> +	if (!ab->acdata)
> +		return -ENOMEM;
> +
> +	ab->acdata->acpi_tas_enable = false;
> +
> +	ret = ath12k_acpi_dsm_get_data(ab,
> +				       ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS);
> +
> +	if (ret)
> +		return ret;
> +
> +	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
> +		ret = ath12k_acpi_dsm_get_data(ab,
> +					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG);
> +		if (ret) {
> +			ath12k_err(ab, "failed to get tas cfg table %d\n", ret);
> +			goto err_free_acdata;
> +		}
> +	}
> +
> +	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {
> +		ret = ath12k_acpi_dsm_get_data(ab,
> +					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
> +		if (ret) {
> +			ath12k_err(ab, "failed to get tas data table %d\n", ret);
> +			goto err_free_acdata;
> +		}
> +
> +		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&
> +		    ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
> +		    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG)
> +			ab->acdata->acpi_tas_enable = true;
> +	}
> +
> +	if (ab->acdata->acpi_tas_enable) {
> +		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
> +		if (ret)
> +			goto err_free_acdata;
> +	}
> +
> +	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
> +					     ACPI_DEVICE_NOTIFY,
> +					     acpi_dsm_notify, ab);
> +	if (ACPI_FAILURE(status)) {
> +		ath12k_err(ab, "failed to install DSM notify callback\n");
> +		goto err_remove_notify;
> +	}
> +
> +	return 0;
> +
> +err_remove_notify:
> +	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
> +				   ACPI_DEVICE_NOTIFY,
> +				   acpi_dsm_notify);
> +
> +	ret = -EIO;
> +
> +err_free_acdata:
> +	kfree(ab->acdata);
> +	ab->acdata = NULL;
> +
> +	return ret;
> +}
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
> new file mode 100644
> index 000000000000..2331b8e3e035
> --- /dev/null
> +++ b/drivers/net/wireless/ath/ath12k/acpi.h
> @@ -0,0 +1,29 @@
> +/* 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.
> + */
> +#ifndef ATH12K_ACPI_H
> +#define ATH12K_ACPI_H
> +
> +#include <linux/acpi.h>
> +
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
> +
> +#define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
> +#define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
> +
> +#define ATH12K_ACPI_NOTIFY_EVENT			0x86
> +#define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
> +
> +#define ATH12K_ACPI_TAS_DATA_VERSION		0x1
> +#define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
> +
> +#define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
> +#define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
> +
> +int ath12k_get_acpi_all_data(struct ath12k_base *ab);
> +void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
> +#endif
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 39f938fafa81..457261c7a0e9 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -538,6 +538,12 @@ static int ath12k_core_start(struct ath12k_base *ab,
>   		goto err_reo_cleanup;
>   	}
>   
> +	if (!guid_is_null(ab->hw_params->acpi_guid)) {

you seem to be misusing guid_is_null() in this patch.
that does not check to see if the pointer is NULL, but instead checks to 
see if the guid has the same contents as the global guid_null. in the 
case of QCN9274 I believe this will result in a NULL pointer 
dereference, which is why it wouold be good to verify your patch on that 
platform.

it seems that either you need to change the QCN9274 initializers to be:
	.acpi_guid = guid_null,
or else you need to change the guid_is_null() function calls to just 
NULL-checking the pointer


> +		ret = ath12k_get_acpi_all_data(ab);
> +		if (!ret)
> +			ath12k_info(ab, "success to get acpi cfg data\n");
> +	}
> +
>   	return 0;
>   
>   err_reo_cleanup:
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index d873b573dac6..cba4f176c018 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -22,6 +22,7 @@
>   #include "hal_rx.h"
>   #include "reg.h"
>   #include "dbring.h"
> +#include "acpi.h"
>   
>   #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
>   
> @@ -771,6 +772,13 @@ struct ath12k_base {
>   	u64 fw_soc_drop_count;
>   	bool static_window_map;
>   
> +	struct {
> +		u32 func_bit;
> +		bool acpi_tas_enable;
> +		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
> +		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
> +	} *acdata;
> +
>   	/* must be last */
>   	u8 drv_priv[] __aligned(sizeof(void *));
>   };
> diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
> index 5991cc91cd00..f0f7f9dbb08a 100644
> --- a/drivers/net/wireless/ath/ath12k/hw.c
> +++ b/drivers/net/wireless/ath/ath12k/hw.c
> @@ -15,6 +15,10 @@
>   #include "mhi.h"
>   #include "dp_rx.h"
>   
> +static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec,
> +					     0x90, 0xd6, 0x02, 0x42,
> +					     0xac, 0x12, 0x00, 0x03);
> +
>   static u8 ath12k_hw_qcn9274_mac_from_pdev_id(int pdev_idx)
>   {
>   	return pdev_idx;
> @@ -907,6 +911,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   		.hal_ops = &hal_qcn9274_ops,
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
> +
> +		.acpi_guid = NULL,
>   	},
>   	{
>   		.name = "wcn7850 hw2.0",
> @@ -964,6 +970,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
>   					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
> +
> +		.acpi_guid = &wcn7850_uuid,
>   	},
>   	{
>   		.name = "qcn9274 hw2.0",
> @@ -1019,6 +1027,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
>   		.hal_ops = &hal_qcn9274_ops,
>   
>   		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
> +
> +		.acpi_guid = NULL,
>   	},
>   };
>   
> diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
> index e6c4223c283c..ab409e8ae268 100644
> --- a/drivers/net/wireless/ath/ath12k/hw.h
> +++ b/drivers/net/wireless/ath/ath12k/hw.h
> @@ -8,7 +8,7 @@
>   #define ATH12K_HW_H
>   
>   #include <linux/mhi.h>
> -
> +#include <linux/uuid.h>
>   #include "wmi.h"
>   #include "hal.h"
>   
> @@ -186,6 +186,8 @@ struct ath12k_hw_params {
>   	const struct hal_ops *hal_ops;
>   
>   	u64 qmi_cnss_feature_bitmap;
> +
> +	const guid_t *acpi_guid;
>   };
>   
>   struct ath12k_hw_ops {
> diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
> index bd689efa7daa..3c2967e760ab 100644
> --- a/drivers/net/wireless/ath/ath12k/pci.c
> +++ b/drivers/net/wireless/ath/ath12k/pci.c
> @@ -1340,6 +1340,12 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
>   
>   	ath12k_hal_srng_deinit(ab);
>   	ath12k_ce_free_pipes(ab);
> +	if (!guid_is_null(ab->hw_params->acpi_guid) && ab->acdata) {

again this guid_is_null() call seems incorrect as stated earlier

> +		acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
> +					   ACPI_DEVICE_NOTIFY,
> +					   acpi_dsm_notify);
> +		kfree(ab->acdata);
> +	}
>   	ath12k_core_free(ab);
>   }
>   
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index f48ab69e256a..f49f4325edff 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -6918,3 +6918,83 @@ void ath12k_wmi_detach(struct ath12k_base *ab)
>   
>   	ath12k_wmi_free_dbring_caps(ab);
>   }
> +
> +int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
> +					    const u8 *ptas_cfg)
> +{
> +	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
> +	struct wmi_pdev_set_bios_interface_cmd *cmd;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	u8 *buf_ptr;
> +	u32 len, len_aligned;
> +	int ret;
> +
> +	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_CFG_SIZE, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
> +	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
> +						 sizeof(*cmd));
> +	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
> +	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_CONFIG_TYPE);
> +	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_CFG_SIZE);
> +
> +	buf_ptr = skb->data + sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, ptas_cfg, ATH12K_ACPI_DSM_TAS_CFG_SIZE);
> +
> +	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> +
> +int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
> +					     const u8 *ptas_data)
> +{
> +	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
> +	struct wmi_pdev_set_bios_interface_cmd *cmd;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	u8 *buf_ptr;
> +	u32 len, len_aligned;
> +	int ret;
> +
> +	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_DATA_SIZE, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
> +	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
> +						 sizeof(*cmd));
> +	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
> +	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_DATA_TYPE);
> +	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_DATA_SIZE);
> +
> +	buf_ptr = skb->data + sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, ptas_data, ATH12K_ACPI_DSM_TAS_DATA_SIZE);
> +
> +	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index c75a6fa1f7e0..38bbf59fc6b7 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -361,6 +361,7 @@ 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_BIOS_INTERFACE_CMDID = 0x404A,
>   	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
>   	WMI_VDEV_DELETE_CMDID,
>   	WMI_VDEV_START_REQUEST_CMDID,
> @@ -1931,6 +1932,7 @@ enum wmi_tlv_tag {
>   	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
>   	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
>   	WMI_TAG_EHT_RATE_SET = 0x3C4,
> +	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
>   	WMI_TAG_MAX
>   };
>   
> @@ -4791,6 +4793,19 @@ struct ath12k_wmi_base {
>   	struct ath12k_wmi_target_cap_arg *targ_cap;
>   };
>   
> +struct wmi_pdev_set_bios_interface_cmd {
> +	__le32 tlv_header;
> +	__le32 pdev_id;
> +	__le32 param_type_id;
> +	__le32 length;
> +} __packed;
> +
> +enum bios_param_type {
> +	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
> +	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
> +	WMI_BIOS_PARAM_TYPE_MAX,
> +};
> +
>   #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
>   
>   void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
> @@ -4912,5 +4927,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
>   			       struct sk_buff *tmpl);
>   int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
>   			   enum wmi_host_hw_mode_config_type mode);
> -
> +int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
> +					    const u8 *ptas_cfg);
> +int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
> +					     const u8 *ptas_data);
>   #endif



From quic_jjohnson at quicinc.com  Fri Sep  8 08:54:56 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Fri, 8 Sep 2023 08:54:56 -0700
Subject: [PATCH v3 2/4] wifi: ath12k: add BIOS SAR capability for WCN7850
In-Reply-To: <20230907101710.11659-3-quic_lingbok@quicinc.com>
References: <20230907101710.11659-1-quic_lingbok@quicinc.com>
 <20230907101710.11659-3-quic_lingbok@quicinc.com>
Message-ID: <1d5c6ad3-f788-4ce7-acc5-c64286cdb291@quicinc.com>

On 9/7/2023 3:17 AM, Lingbo Kong wrote:
> ath12k get the latest BIOS SAR power table by using ACPI _DSM method, then
> pass this table to the firmware.ath12k register a notification callback for

since you need to respin for the guid_is_null() issue can you fix the 
nit: add space after hard stop (.)

And as a more generic comment on commit text, ideally you should be 
using imperative voice:

<https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches#commit_messages>


> ACPI event so ACPI can notify ath12k to get the latest BIOS SAR table.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
> ---
> v3:
> 1.adjust the order of the macros
> 2.apply jeff's advice
> 3.remove unnecessary cpu_to_le32()
> 
> v2:
> no change
> 
>   drivers/net/wireless/ath/ath12k/acpi.c | 103 +++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/acpi.h |  18 +++++
>   drivers/net/wireless/ath/ath12k/core.h |   3 +
>   drivers/net/wireless/ath/ath12k/wmi.c  |  92 ++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h  |  21 +++++
>   5 files changed, 237 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
> index 384e01748b32..ae1ce7b99d2d 100644
> --- a/drivers/net/wireless/ath/ath12k/acpi.c
> +++ b/drivers/net/wireless/ath/ath12k/acpi.c
> @@ -52,6 +52,26 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
>   			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
>   			       obj->buffer.length);
>   			break;
> +		case ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR:
> +			if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
> +				ath12k_err(ab, "Invalid BIOS SAR data size %d\n",
> +					   obj->buffer.length);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			memcpy(&ab->acdata->bios_sar_data, obj->buffer.pointer,
> +			       obj->buffer.length);
> +			break;
> +		case ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET:
> +			if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
> +				ath12k_err(ab, "Invalid GEO OFFSET data size %d\n",
> +					   obj->buffer.length);
> +				ret = -EINVAL;
> +				goto out;
> +			}
> +			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
> +			       obj->buffer.length);
> +			break;
>   		}
>   	} else {
>   		ath12k_err(ab,
> @@ -83,6 +103,24 @@ static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
>   	return ret;
>   }
>   
> +static int ath12k_set_bios_sar_power_limit_data(struct ath12k_base *ab)
> +{
> +	int ret;
> +
> +	if (ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
> +	    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
> +		ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
> +							       ab->acdata->bios_sar_data);
> +		if (ret)
> +			ath12k_err(ab, "failed to pass bios sar table %d\n", ret);
> +	} else {
> +		ath12k_err(ab, "the latest bios sar data is invalid\n");
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
>   void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
>   {
>   	int ret;
> @@ -101,6 +139,20 @@ void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
>   			if (ret)
>   				return;
>   		}
> +
> +		if (ab->acdata->acpi_bios_sar_enable) {
> +			ret = ath12k_acpi_dsm_get_data(ab,
> +						       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
> +			if (ret) {
> +				ath12k_err(ab, "failed to update bios sar %d\n", ret);
> +				return;
> +			}
> +
> +			ret = ath12k_set_bios_sar_power_limit_data(ab);
> +			if (ret)
> +				return;
> +		}
> +
>   	} else {
>   		ath12k_err(ab, "unknown acpi notify %u\n", event);
>   	}
> @@ -113,6 +165,27 @@ void ath12k_acpi_remove_notify(struct ath12k_base *ab)
>   				   acpi_dsm_notify);
>   }
>   
> +static int ath12k_pass_acpi_bios_sar_and_geo_to_fw(struct ath12k_base *ab)
> +{
> +	int ret;
> +
> +	ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
> +						       ab->acdata->bios_sar_data);
> +
> +	if (ret) {
> +		ath12k_err(ab, "failed to pass bios sar table to fw %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = ath12k_wmi_pdev_set_bios_geo_table_param(ab,
> +						       ab->acdata->geo_offset_data);
> +
> +	if (ret)
> +		ath12k_err(ab, "failed to pass bios geo table to fw %d\n", ret);
> +
> +	return ret;
> +}
> +
>   static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
>   {
>   	int ret;
> @@ -172,12 +245,42 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
>   			ab->acdata->acpi_tas_enable = true;
>   	}
>   
> +	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
> +		ret = ath12k_acpi_dsm_get_data(ab,
> +					       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
> +		if (ret) {
> +			ath12k_err(ab, "failed to get bios sar data %d\n", ret);
> +			goto err_free_acdata;
> +		}
> +	}
> +
> +	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
> +		ret = ath12k_acpi_dsm_get_data(ab,
> +					       ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET);
> +		if (ret) {
> +			ath12k_err(ab, "failed to get geo offset data %d\n", ret);
> +			goto err_free_acdata;
> +		}
> +
> +		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
> +		    ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
> +		    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
> +		    !ab->acdata->acpi_tas_enable)
> +			ab->acdata->acpi_bios_sar_enable = true;
> +	}
> +
>   	if (ab->acdata->acpi_tas_enable) {
>   		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
>   		if (ret)
>   			goto err_free_acdata;
>   	}
>   
> +	if (ab->acdata->acpi_bios_sar_enable) {
> +		ret = ath12k_pass_acpi_bios_sar_and_geo_to_fw(ab);
> +		if (ret)
> +			goto err_free_acdata;
> +	}
> +
>   	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
>   					     ACPI_DEVICE_NOTIFY,
>   					     acpi_dsm_notify, ab);
> diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
> index 2331b8e3e035..2f930f0718da 100644
> --- a/drivers/net/wireless/ath/ath12k/acpi.h
> +++ b/drivers/net/wireless/ath/ath12k/acpi.h
> @@ -9,9 +9,13 @@
>   #include <linux/acpi.h>
>   
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR             4
> +#define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET           5
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
>   #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
>   
> +#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
> +#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
>   #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
>   #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
>   
> @@ -20,10 +24,24 @@
>   
>   #define ATH12K_ACPI_TAS_DATA_VERSION		0x1
>   #define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
> +#define ATH12K_ACPI_POWER_LIMIT_VERSION		0x1
> +#define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
> +
> +#define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
> +#define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET	2
> +#define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN	10
> +#define ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET	12
> +#define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
> +#define ATH12K_ACPI_BIOS_SAR_TABLE_LEN		22
>   
>   #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
>   #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
>   
> +#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE (ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET + \
> +					      ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN)
> +#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE (ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET + \
> +					    ATH12K_ACPI_BIOS_SAR_TABLE_LEN)
> +
>   int ath12k_get_acpi_all_data(struct ath12k_base *ab);
>   void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
>   #endif
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index cba4f176c018..6fe4f0ddee4a 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -775,8 +775,11 @@ struct ath12k_base {
>   	struct {
>   		u32 func_bit;
>   		bool acpi_tas_enable;
> +		bool acpi_bios_sar_enable;
>   		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
>   		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
> +		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
> +		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
>   	} *acdata;
>   
>   	/* must be last */
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index f49f4325edff..9ad588897b09 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -6998,3 +6998,95 @@ int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
>   
>   	return ret;
>   }
> +
> +int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
> +					     u8 *psar_table)
> +{
> +	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
> +	struct wmi_pdev_set_bios_sar_table_cmd *cmd;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	int ret;
> +	u8 *buf_ptr;
> +	u32 len, sar_table_len_aligned, sar_dbs_backoff_len_aligned;
> +	u8 *psar_value = psar_table + ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET;
> +	u8 *pdbs_value = psar_table + ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET;
> +
> +	sar_table_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_TABLE_LEN, sizeof(u32));
> +	sar_dbs_backoff_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_table_len_aligned +
> +		TLV_HDR_SIZE + sar_dbs_backoff_len_aligned;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_pdev_set_bios_sar_table_cmd *)skb->data;
> +	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS,
> +						 sizeof(*cmd));
> +	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
> +	cmd->sar_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
> +	cmd->dbs_backoff_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
> +
> +	buf_ptr = skb->data + sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
> +					 sar_table_len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, psar_value, ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
> +
> +	buf_ptr += sar_table_len_aligned;
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
> +					 sar_dbs_backoff_len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, pdbs_value, ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
> +
> +	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> +
> +int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
> +					     u8 *pgeo_table)
> +{
> +	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
> +	struct wmi_pdev_set_bios_geo_table_cmd *cmd;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	int ret;
> +	u8 *buf_ptr;
> +	u32 len, sar_geo_len_aligned;
> +	u8 *pgeo_value = pgeo_table + ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET;
> +
> +	sar_geo_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN, sizeof(u32));
> +	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_geo_len_aligned;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (struct wmi_pdev_set_bios_geo_table_cmd *)skb->data;
> +	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS,
> +						 sizeof(*cmd));
> +	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
> +	cmd->geo_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
> +
> +	buf_ptr = skb->data + sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)buf_ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, sar_geo_len_aligned);
> +	buf_ptr += TLV_HDR_SIZE;
> +	memcpy(buf_ptr, pgeo_value, ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
> +
> +	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID %d\n", ret);
> +		dev_kfree_skb(skb);
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 38bbf59fc6b7..8a774655fe9f 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -361,6 +361,8 @@ 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_BIOS_SAR_TABLE_CMDID = 0x4044,
> +	WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045,
>   	WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A,
>   	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
>   	WMI_VDEV_DELETE_CMDID,
> @@ -1932,6 +1934,8 @@ enum wmi_tlv_tag {
>   	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
>   	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
>   	WMI_TAG_EHT_RATE_SET = 0x3C4,
> +	WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS = 0x3D8,
> +	WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS = 0x3D9,
>   	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
>   	WMI_TAG_MAX
>   };
> @@ -4806,6 +4810,19 @@ enum bios_param_type {
>   	WMI_BIOS_PARAM_TYPE_MAX,
>   };
>   
> +struct wmi_pdev_set_bios_sar_table_cmd {
> +	__le32 tlv_header;
> +	__le32 pdev_id;
> +	__le32 sar_len;
> +	__le32 dbs_backoff_len;
> +} __packed;
> +
> +struct wmi_pdev_set_bios_geo_table_cmd {
> +	__le32 tlv_header;
> +	__le32 pdev_id;
> +	__le32 geo_len;
> +} __packed;
> +
>   #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
>   
>   void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
> @@ -4931,4 +4948,8 @@ int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
>   					    const u8 *ptas_cfg);
>   int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
>   					     const u8 *ptas_data);
> +int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
> +					     u8 *psar_table);
> +int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
> +					     u8 *pgeo_table);
>   #endif



From sashal at kernel.org  Fri Sep  8 11:12:57 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:12:57 -0400
Subject: [PATCH AUTOSEL 6.5 16/45] wifi: ath12k: Fix a NULL pointer dereference in ath12k_mac_op_hw_scan()
In-Reply-To: <20230908181327.3459042-1-sashal@kernel.org>
References: <20230908181327.3459042-1-sashal@kernel.org>
Message-ID: <20230908181327.3459042-16-sashal@kernel.org>

From: Wen Gong <quic_wgong at quicinc.com>

[ Upstream commit 8ad314da54c6dd223a6b6cc85019160aa842f659 ]

In ath12k_mac_op_hw_scan(), the return value of kzalloc() is directly
used in memcpy(), which may lead to a NULL pointer dereference on
failure of kzalloc().

Fix this bug by adding a check of arg.extraie.ptr.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
Link: https://lore.kernel.org/r/20230726092625.3350-1-quic_wgong at quicinc.com
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath12k/mac.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 1bb9802ef5696..af46b63bb15bc 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2755,9 +2755,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
 	arg.scan_id = ATH12K_SCAN_ID;
 
 	if (req->ie_len) {
+		arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL);
+		if (!arg.extraie.ptr) {
+			ret = -ENOMEM;
+			goto exit;
+		}
 		arg.extraie.len = req->ie_len;
-		arg.extraie.ptr = kzalloc(req->ie_len, GFP_KERNEL);
-		memcpy(arg.extraie.ptr, req->ie, req->ie_len);
 	}
 
 	if (req->n_ssids) {
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:12:58 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:12:58 -0400
Subject: [PATCH AUTOSEL 6.5 17/45] wifi: ath12k: avoid array overflow of hw mode for preferred_hw_mode
In-Reply-To: <20230908181327.3459042-1-sashal@kernel.org>
References: <20230908181327.3459042-1-sashal@kernel.org>
Message-ID: <20230908181327.3459042-17-sashal@kernel.org>

From: Wen Gong <quic_wgong at quicinc.com>

[ Upstream commit 1e9b1363e2de1552ee4e3d74ac8bb43a194f1cb4 ]

Currently ath12k define WMI_HOST_HW_MODE_DBS_OR_SBS=5 as max hw mode
for enum wmi_host_hw_mode_config_type, it is also same for the array
ath12k_hw_mode_pri_map.

When tested with new version firmware/board data which support new
hw mode eMLSR mode with hw mode value 8, it leads overflow usage for
array ath12k_hw_mode_pri_map in function ath12k_wmi_hw_mode_caps(),
and then lead preferred_hw_mode changed to 8, and finally function
ath12k_pull_mac_phy_cap_svc_ready_ext() select the capability of hw
mode 8, but the capability of eMLSR mode report from firmware does
not support 2.4 GHz band for WCN7850, so finally 2.4 GHz band is
disabled.

Skip the hw mode which exceeds WMI_HOST_HW_MODE_MAX in function
ath12k_wmi_hw_mode_caps() helps to avoid array overflow, then the 2.4
GHz band will not be disabled.

This is to keep compatibility with newer version firmware/board data
files, this change is still needed after ath12k add eMLSR hw mode 8 in
array ath12k_hw_mode_pri_map and enum wmi_host_hw_mode_config_type,
because more hw mode maybe added in next firmware/board data version
e.g hw mode 9, then it will also lead new array overflow without this
change.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
Link: https://lore.kernel.org/r/20230714072405.28705-1-quic_wgong at quicinc.com
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath12k/wmi.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 4928e4e916603..4f378f06e946e 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -3704,6 +3704,10 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,
 	for (i = 0 ; i < svc_rdy_ext->n_hw_mode_caps; i++) {
 		hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i];
 		mode = le32_to_cpu(hw_mode_caps->hw_mode_id);
+
+		if (mode >= WMI_HOST_HW_MODE_MAX)
+			continue;
+
 		pref = soc->wmi_ab.preferred_hw_mode;
 
 		if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) {
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:13:21 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:13:21 -0400
Subject: [PATCH AUTOSEL 6.5 40/45] wifi: ath12k: Fix memory leak in rx_desc and tx_desc
In-Reply-To: <20230908181327.3459042-1-sashal@kernel.org>
References: <20230908181327.3459042-1-sashal@kernel.org>
Message-ID: <20230908181327.3459042-40-sashal@kernel.org>

From: Rajat Soni <quic_rajson at quicinc.com>

[ Upstream commit afb522b36e76acaa9f8fc06d0a9742d841c47c16 ]

Currently when ath12k_dp_cc_desc_init() is called we allocate
memory to rx_descs and tx_descs. In ath12k_dp_cc_cleanup(), during
descriptor cleanup rx_descs and tx_descs memory is not freed.

This is cause of memory leak. These allocated memory should be
freed in ath12k_dp_cc_cleanup.

In ath12k_dp_cc_desc_init(), we can save base address of rx_descs
and tx_descs. In ath12k_dp_cc_cleanup(), we can free rx_descs and
tx_descs memory using their base address.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Rajat Soni <quic_rajson at quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
Link: https://lore.kernel.org/r/20230718053510.30894-1-quic_rajson at quicinc.com
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath12k/dp.c | 30 +++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/dp.h |  2 ++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index ae1645d0f42a2..f933896f2a68d 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -1129,6 +1129,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
 	struct ath12k_dp *dp = &ab->dp;
 	struct sk_buff *skb;
 	int i;
+	u32 pool_id, tx_spt_page;
 
 	if (!dp->spt_info)
 		return;
@@ -1148,6 +1149,14 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
 		dev_kfree_skb_any(skb);
 	}
 
+	for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) {
+		if (!dp->spt_info->rxbaddr[i])
+			continue;
+
+		kfree(dp->spt_info->rxbaddr[i]);
+		dp->spt_info->rxbaddr[i] = NULL;
+	}
+
 	spin_unlock_bh(&dp->rx_desc_lock);
 
 	/* TX Descriptor cleanup */
@@ -1170,6 +1179,21 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
 		spin_unlock_bh(&dp->tx_desc_lock[i]);
 	}
 
+	for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) {
+		spin_lock_bh(&dp->tx_desc_lock[pool_id]);
+
+		for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) {
+			tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
+			if (!dp->spt_info->txbaddr[tx_spt_page])
+				continue;
+
+			kfree(dp->spt_info->txbaddr[tx_spt_page]);
+			dp->spt_info->txbaddr[tx_spt_page] = NULL;
+		}
+
+		spin_unlock_bh(&dp->tx_desc_lock[pool_id]);
+	}
+
 	/* unmap SPT pages */
 	for (i = 0; i < dp->num_spt_pages; i++) {
 		if (!dp->spt_info[i].vaddr)
@@ -1343,6 +1367,8 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
 			return -ENOMEM;
 		}
 
+		dp->spt_info->rxbaddr[i] = &rx_descs[0];
+
 		for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
 			rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(i, j);
 			rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC;
@@ -1368,8 +1394,10 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
 				return -ENOMEM;
 			}
 
+			tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
+			dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0];
+
 			for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
-				tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
 				ppt_idx = ATH12K_NUM_RX_SPT_PAGES + tx_spt_page;
 				tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j);
 				tx_descs[j].pool_id = pool_id;
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index 7c5dafce5a68d..9aeda0321cd75 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -289,6 +289,8 @@ struct ath12k_tx_desc_info {
 struct ath12k_spt_info {
 	dma_addr_t paddr;
 	u64 *vaddr;
+	struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES];
+	struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES];
 };
 
 struct ath12k_reo_queue_ref {
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:13:23 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:13:23 -0400
Subject: [PATCH AUTOSEL 6.5 42/45] wifi: ath12k: add check max message length while scanning with extraie
In-Reply-To: <20230908181327.3459042-1-sashal@kernel.org>
References: <20230908181327.3459042-1-sashal@kernel.org>
Message-ID: <20230908181327.3459042-42-sashal@kernel.org>

From: Wen Gong <quic_wgong at quicinc.com>

[ Upstream commit 2f5124e86ae74b7ba24c9ae2644107b750cbf38f ]

Currently the extraie length is directly used to allocate skb buffer. When
the length of skb is greater than the max message length which firmware
supports, error will happen in firmware side.

Hence add check for the skb length and drop extraie when overflow and
print a message.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
Reviewed-by: Jeff Johnson <quic_jjohnson at quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
Link: https://lore.kernel.org/r/20230809081657.13858-1-quic_wgong at quicinc.com
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath12k/wmi.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 4f378f06e946e..eebc5a65ce3b4 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -2162,12 +2162,6 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	if (arg->num_bssid)
 		len += sizeof(*bssid) * arg->num_bssid;
 
-	len += TLV_HDR_SIZE;
-	if (arg->extraie.len)
-		extraie_len_with_pad =
-			roundup(arg->extraie.len, sizeof(u32));
-	len += extraie_len_with_pad;
-
 	if (arg->num_hint_bssid)
 		len += TLV_HDR_SIZE +
 		       arg->num_hint_bssid * sizeof(*hint_bssid);
@@ -2176,6 +2170,18 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 		len += TLV_HDR_SIZE +
 		       arg->num_hint_s_ssid * sizeof(*s_ssid);
 
+	len += TLV_HDR_SIZE;
+	if (arg->extraie.len)
+		extraie_len_with_pad =
+			roundup(arg->extraie.len, sizeof(u32));
+	if (extraie_len_with_pad <= (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len)) {
+		len += extraie_len_with_pad;
+	} else {
+		ath12k_warn(ar->ab, "discard large size %d bytes extraie for scan start\n",
+			    arg->extraie.len);
+		extraie_len_with_pad = 0;
+	}
+
 	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
 	if (!skb)
 		return -ENOMEM;
@@ -2265,7 +2271,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len);
 	ptr += TLV_HDR_SIZE;
 
-	if (arg->extraie.len)
+	if (extraie_len_with_pad)
 		memcpy(ptr, arg->extraie.ptr,
 		       arg->extraie.len);
 
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:13:24 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:13:24 -0400
Subject: [PATCH AUTOSEL 6.5 43/45] Fix nomenclature for USB and PCI wireless devices
In-Reply-To: <20230908181327.3459042-1-sashal@kernel.org>
References: <20230908181327.3459042-1-sashal@kernel.org>
Message-ID: <20230908181327.3459042-43-sashal@kernel.org>

From: Alan Stern <stern at rowland.harvard.edu>

[ Upstream commit 5d7cf67f72ae34d38e090bdfa673da4aefe4048e ]

A mouse that uses a USB connection is called a "USB mouse" device (or
"USB mouse" for short), not a "mouse USB" device.  By analogy, a WiFi
adapter that connects to the host computer via USB is a "USB wireless"
device, not a "wireless USB" device.  (The latter term more properly
refers to a defunct Wireless USB specification, which described a
technology for sending USB protocol messages over an ultra wideband
radio link.)

Similarly for a WiFi adapter card that plugs into a PCIe slot: It is a
"PCIe wireless" device, not a "wireless PCIe" device.

Rephrase the text in the kernel source where the word ordering is
wrong.

Signed-off-by: Alan Stern <stern at rowland.harvard.edu>
Reviewed-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Signed-off-by: Kalle Valo <kvalo at kernel.org>
Link: https://lore.kernel.org/r/57da7c80-0e48-41b5-8427-884a02648f55 at rowland.harvard.edu
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath10k/pci.c         |  2 +-
 drivers/net/wireless/ath/ath10k/usb.c         |  2 +-
 drivers/net/wireless/ath/ath11k/pci.c         |  2 +-
 drivers/net/wireless/ath/ath12k/pci.c         |  2 +-
 drivers/net/wireless/atmel/at76c50x-usb.c     |  8 ++--
 .../wireless/intersil/orinoco/orinoco_usb.c   | 12 ++---
 drivers/net/wireless/legacy/rndis_wlan.c      |  2 +-
 .../net/wireless/mediatek/mt76/mt7603/Kconfig |  2 +-
 .../net/wireless/mediatek/mt76/mt7615/Kconfig |  2 +-
 .../net/wireless/mediatek/mt76/mt76x0/Kconfig |  4 +-
 .../net/wireless/mediatek/mt76/mt76x2/Kconfig |  4 +-
 .../net/wireless/mediatek/mt76/mt7915/Kconfig |  2 +-
 .../net/wireless/mediatek/mt76/mt7996/Kconfig |  2 +-
 drivers/net/wireless/mediatek/mt7601u/Kconfig |  2 +-
 drivers/net/wireless/purelifi/plfxlc/Kconfig  |  2 +-
 drivers/net/wireless/ralink/rt2x00/Kconfig    |  2 +-
 drivers/net/wireless/realtek/rtw88/pci.c      |  2 +-
 drivers/net/wireless/realtek/rtw88/usb.c      |  2 +-
 drivers/net/wireless/realtek/rtw89/pci.c      |  2 +-
 drivers/net/wireless/zydas/zd1201.c           |  6 +--
 drivers/platform/x86/eeepc-laptop.c           |  2 +-
 drivers/staging/wlan-ng/prism2usb.c           | 48 +++++++++----------
 22 files changed, 57 insertions(+), 57 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index a7f44f6335fb8..3ef414b613bf3 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3816,7 +3816,7 @@ static void __exit ath10k_pci_exit(void)
 module_exit(ath10k_pci_exit);
 
 MODULE_AUTHOR("Qualcomm Atheros");
-MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN PCIe/AHB devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Atheros PCIe/AHB 802.11ac WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
 /* QCA988x 2.0 firmware files */
diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c
index b0067af685b16..3c482baacec10 100644
--- a/drivers/net/wireless/ath/ath10k/usb.c
+++ b/drivers/net/wireless/ath/ath10k/usb.c
@@ -1126,5 +1126,5 @@ static struct usb_driver ath10k_usb_driver = {
 module_usb_driver(ath10k_usb_driver);
 
 MODULE_AUTHOR("Atheros Communications, Inc.");
-MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN USB devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Atheros USB 802.11ac WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 79e2cbe826384..bfa9d4c950f11 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -1034,7 +1034,7 @@ static void ath11k_pci_exit(void)
 
 module_exit(ath11k_pci_exit);
 
-MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Technologies PCIe 802.11ax WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
 /* firmware files */
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 5990a55801f0a..bd689efa7daaf 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1409,5 +1409,5 @@ static void ath12k_pci_exit(void)
 
 module_exit(ath12k_pci_exit);
 
-MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11be WLAN PCIe devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Technologies PCIe 802.11be WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c
index 009bca34ece30..447b51cff8f96 100644
--- a/drivers/net/wireless/atmel/at76c50x-usb.c
+++ b/drivers/net/wireless/atmel/at76c50x-usb.c
@@ -10,7 +10,7 @@
  * Copyright (c) 2007 Kalle Valo <kalle.valo at iki.fi>
  * Copyright (c) 2010 Sebastian Smolorz <sesmo at gmx.net>
  *
- * This file is part of the Berlios driver for WLAN USB devices based on the
+ * This file is part of the Berlios driver for USB WLAN devices based on the
  * Atmel AT76C503A/505/505A.
  *
  * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed
@@ -143,7 +143,7 @@ static const struct usb_device_id dev_table[] = {
 	{ USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
 	/* Dynalink/Askey WLL013 (intersil) */
 	{ USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861) },
-	/* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */
+	/* EZ connect 11Mpbs USB Wireless Adapter SMC2662W v1 */
 	{ USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
 	/* BenQ AWL300 */
 	{ USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861) },
@@ -195,7 +195,7 @@ static const struct usb_device_id dev_table[] = {
 	{ USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503) },
 	/* 3Com 3CRSHEW696 */
 	{ USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503) },
-	/* Siemens Santis ADSL WLAN USB adapter WLL 013 */
+	/* Siemens Santis ADSL USB WLAN adapter WLL 013 */
 	{ USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503) },
 	/* Belkin F5D6050, version 2 */
 	{ USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503) },
@@ -238,7 +238,7 @@ static const struct usb_device_id dev_table[] = {
 	{ USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958) },
 	/* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */
 	{ USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958) },
-	/* Corega WLAN USB Stick 11 */
+	/* Corega USB WLAN Stick 11 */
 	{ USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },
 	/* Microstar MSI Box MS6978 */
 	{ USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958) },
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
index dd31929261ab9..866e0230df251 100644
--- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
@@ -129,18 +129,18 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
 
 #define USB_AVAYA8_VENDOR_ID     0x0D98
 #define USB_AVAYAE_VENDOR_ID     0x0D9E
-#define USB_AVAYA_WIRELESS_ID    0x0300 /* Avaya Wireless USB Card */
+#define USB_AVAYA_WIRELESS_ID    0x0300 /* Avaya USB Wireless Card */
 
 #define USB_AGERE_VENDOR_ID      0x0D4E /* Agere Systems */
-#define USB_AGERE_MODEL0801_ID   0x1000 /* Wireless USB Card Model 0801 */
-#define USB_AGERE_MODEL0802_ID   0x1001 /* Wireless USB Card Model 0802 */
-#define USB_AGERE_REBRANDED_ID   0x047A /* WLAN USB Card */
+#define USB_AGERE_MODEL0801_ID   0x1000 /* USB Wireless Card Model 0801 */
+#define USB_AGERE_MODEL0802_ID   0x1001 /* USB Wireless Card Model 0802 */
+#define USB_AGERE_REBRANDED_ID   0x047A /* USB WLAN Card */
 
 #define USB_ELSA_VENDOR_ID       0x05CC
 #define USB_ELSA_AIRLANCER_ID    0x3100 /* ELSA AirLancer USB-11 */
 
 #define USB_LEGEND_VENDOR_ID     0x0E7C
-#define USB_LEGEND_JOYNET_ID     0x0300 /* Joynet WLAN USB Card */
+#define USB_LEGEND_JOYNET_ID     0x0300 /* Joynet USB WLAN Card */
 
 #define USB_SAMSUNG_VENDOR_ID    0x04E8
 #define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
@@ -154,7 +154,7 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
 #define USB_FUJITSU_E1100_ID     0x1002 /* connect2AIR WLAN E-1100 USB */
 
 #define USB_2WIRE_VENDOR_ID      0x1630
-#define USB_2WIRE_WIRELESS_ID    0xff81 /* 2Wire Wireless USB adapter */
+#define USB_2WIRE_WIRELESS_ID    0xff81 /* 2Wire USB Wireless adapter */
 
 
 #define EZUSB_REQUEST_FW_TRANS		0xA0
diff --git a/drivers/net/wireless/legacy/rndis_wlan.c b/drivers/net/wireless/legacy/rndis_wlan.c
index 712038d46bdb3..e7fea7ded6d5c 100644
--- a/drivers/net/wireless/legacy/rndis_wlan.c
+++ b/drivers/net/wireless/legacy/rndis_wlan.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Driver for RNDIS based wireless USB devices.
+ * Driver for RNDIS based USB wireless devices.
  *
  * Copyright (C) 2007 by Bjorge Dijkstra <bjd at jooz.net>
  * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna at iki.fi>
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
index 6a0080f1d91c7..dd16acfd9735d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
@@ -5,7 +5,7 @@ config MT7603E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7603E wireless PCIe devices and the WLAN core
+	  This adds support for MT7603E PCIe wireless devices and the WLAN core
 	  on MT7628/MT7688 SoC devices. This family supports IEEE 802.11n 2x2
 	  to 300Mbps PHY rate
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
index 30fba36ff46bb..1ab1439143f41 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
@@ -11,7 +11,7 @@ config MT7615E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7615-based wireless PCIe devices,
+	  This adds support for MT7615-based PCIe wireless devices,
 	  which support concurrent dual-band operation at both 5GHz
 	  and 2.4GHz, IEEE 802.11ac 4x4:4SS 1733Mbps PHY rate, wave2
 	  MU-MIMO up to 4 users/group and 160MHz channels.
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
index 7c88ed8b8f1e9..3ed888782a709 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
@@ -10,7 +10,7 @@ config MT76x0U
 	depends on MAC80211
 	depends on USB
 	help
-	  This adds support for MT7610U-based wireless USB 2.0 dongles,
+	  This adds support for MT7610U-based USB 2.0 wireless dongles,
 	  which comply with IEEE 802.11ac standards and support 1x1
 	  433Mbps PHY rate.
 
@@ -22,7 +22,7 @@ config MT76x0E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7610/MT7630-based wireless PCIe devices,
+	  This adds support for MT7610/MT7630-based PCIe wireless devices,
 	  which comply with IEEE 802.11ac standards and support 1x1
 	  433Mbps PHY rate.
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
index 5fd4973e32dfb..482a32b70ddfe 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
@@ -9,7 +9,7 @@ config MT76x2E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7612/MT7602/MT7662-based wireless PCIe
+	  This adds support for MT7612/MT7602/MT7662-based PCIe wireless
 	  devices, which comply with IEEE 802.11ac standards and support
 	  2SS to 866Mbit/s PHY rate.
 
@@ -22,7 +22,7 @@ config MT76x2U
 	depends on MAC80211
 	depends on USB
 	help
-	  This adds support for MT7612U-based wireless USB 3.0 dongles,
+	  This adds support for MT7612U-based USB 3.0 wireless dongles,
 	  which comply with IEEE 802.11ac standards and support 2SS to
 	  866Mbit/s PHY rate.
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
index d710726d47bfd..3337cdfed0109 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
@@ -7,7 +7,7 @@ config MT7915E
 	depends on PCI
 	select RELAY
 	help
-	  This adds support for MT7915-based wireless PCIe devices,
+	  This adds support for MT7915-based PCIe wireless devices,
 	  which support concurrent dual-band operation at both 5GHz
 	  and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels,
 	  OFDMA, spatial reuse and dual carrier modulation.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
index 1afa2f662e473..bb44d4a5e2dc9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
@@ -7,7 +7,7 @@ config MT7996E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7996-based wireless PCIe devices,
+	  This adds support for MT7996-based PCIe wireless devices,
 	  which support concurrent tri-band operation at 6GHz, 5GHz,
 	  and 2.4GHz IEEE 802.11be 4x4:4SS 4096-QAM, 320MHz channels.
 
diff --git a/drivers/net/wireless/mediatek/mt7601u/Kconfig b/drivers/net/wireless/mediatek/mt7601u/Kconfig
index 4a8b962806707..4880fc053d9d3 100644
--- a/drivers/net/wireless/mediatek/mt7601u/Kconfig
+++ b/drivers/net/wireless/mediatek/mt7601u/Kconfig
@@ -4,4 +4,4 @@ config MT7601U
 	depends on MAC80211
 	depends on USB
 	help
-	  This adds support for MT7601U-based wireless USB dongles.
+	  This adds support for MT7601U-based USB wireless dongles.
diff --git a/drivers/net/wireless/purelifi/plfxlc/Kconfig b/drivers/net/wireless/purelifi/plfxlc/Kconfig
index 4e0be27a5e0eb..dd5fca480d7ef 100644
--- a/drivers/net/wireless/purelifi/plfxlc/Kconfig
+++ b/drivers/net/wireless/purelifi/plfxlc/Kconfig
@@ -3,7 +3,7 @@ config PLFXLC
 	tristate "pureLiFi X, XL, XC device support"
 	depends on CFG80211 && MAC80211 && USB
 	help
-	   This option adds support for pureLiFi LiFi wireless USB
+	   This option adds support for pureLiFi LiFi USB wireless
 	   adapters. The pureLiFi X, XL, XC USB devices are based on
 	   802.11 OFDM PHY but uses light as the transmission medium.
 	   The driver supports common 802.11 encryption/authentication
diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig
index dcccc290a7f52..d1fd66d44a7ed 100644
--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
+++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
@@ -170,7 +170,7 @@ config RT2800USB_RT35XX
 config RT2800USB_RT3573
 	bool "rt2800usb - Include support for rt3573 devices (EXPERIMENTAL)"
 	help
-	  This enables support for RT3573 chipset based wireless USB devices
+	  This enables support for RT3573 chipset based USB wireless devices
 	  in the rt2800usb driver.
 
 config RT2800USB_RT53XX
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 44a8fff34cddf..2bfc0e822b8d0 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -1828,5 +1828,5 @@ void rtw_pci_shutdown(struct pci_dev *pdev)
 EXPORT_SYMBOL(rtw_pci_shutdown);
 
 MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ac wireless PCI driver");
+MODULE_DESCRIPTION("Realtek PCI 802.11ac wireless driver");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index 4a57efdba97bb..1f0625bfcee1c 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -927,5 +927,5 @@ void rtw_usb_disconnect(struct usb_interface *intf)
 EXPORT_SYMBOL(rtw_usb_disconnect);
 
 MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ac wireless USB driver");
+MODULE_DESCRIPTION("Realtek USB 802.11ac wireless driver");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 9402f1a0caea8..3a4bfc44142b6 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -3939,5 +3939,5 @@ void rtw89_pci_remove(struct pci_dev *pdev)
 EXPORT_SYMBOL(rtw89_pci_remove);
 
 MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ax wireless PCI driver");
+MODULE_DESCRIPTION("Realtek PCI 802.11ax wireless driver");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c
index a85fe7e4c6d47..2814df1ecc78f 100644
--- a/drivers/net/wireless/zydas/zd1201.c
+++ b/drivers/net/wireless/zydas/zd1201.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- *	Driver for ZyDAS zd1201 based wireless USB devices.
+ *	Driver for ZyDAS zd1201 based USB wireless devices.
  *
  *	Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq at amsat.org)
  *
@@ -23,8 +23,8 @@
 #include "zd1201.h"
 
 static const struct usb_device_id zd1201_table[] = {
-	{USB_DEVICE(0x0586, 0x3400)}, /* Peabird Wireless USB Adapter */
-	{USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */
+	{USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */
+	{USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */
 	{USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb  adapter */
 	{USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb  adapter */
 	{USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 62b71e8e3567a..ff1b70269ccbf 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1394,7 +1394,7 @@ static int eeepc_acpi_add(struct acpi_device *device)
 	 * and machine-specific scripts find the fixed name convenient.  But
 	 * It's also good for us to exclude multiple instances because both
 	 * our hwmon and our wlan rfkill subdevice use global ACPI objects
-	 * (the EC and the wlan PCI slot respectively).
+	 * (the EC and the PCI wlan slot respectively).
 	 */
 	result = eeepc_platform_init(eeepc);
 	if (result)
diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c
index 80e36d03c4e25..0e0ccef4871e9 100644
--- a/drivers/staging/wlan-ng/prism2usb.c
+++ b/drivers/staging/wlan-ng/prism2usb.c
@@ -11,45 +11,45 @@
 
 static const struct usb_device_id usb_prism_tbl[] = {
 	PRISM_DEV(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS"),
-	PRISM_DEV(0x07aa, 0x0012, "Corega Wireless LAN USB Stick-11"),
-	PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter"),
+	PRISM_DEV(0x07aa, 0x0012, "Corega USB Wireless LAN Stick-11"),
+	PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps USB WLAN Adapter"),
 	PRISM_DEV(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter"),
-	PRISM_DEV(0x08de, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"),
-	PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B LAN USB Adapter"),
+	PRISM_DEV(0x08de, 0x7a01, "PRISM25 USB IEEE 802.11 Mini Adapter"),
+	PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B USB LAN Adapter"),
 	PRISM_DEV(0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"),
-	PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 Wireless USB Adapter"),
+	PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 USB Wireless Adapter"),
 	PRISM_DEV(0x0967, 0x0204, "Acer Warplink USB Adapter"),
 	PRISM_DEV(0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated"),
-	PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 Wireless 802.11b USB Adapter"),
-	PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 Wireless USB Adapter"),
-	PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 Wireless USB Adapter"),
-	PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 Wireless USB Adapter"),
+	PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 USB Wireless 802.11b Adapter"),
+	PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 USB Wireless Adapter"),
+	PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 USB Wireless Adapter"),
+	PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 USB Wireless Adapter"),
 	PRISM_DEV(0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter"),
 	PRISM_DEV(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter"),
 	PRISM_DEV(0x0846, 0x4110, "NetGear MA111"),
 	PRISM_DEV(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter"),
-	PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 / Hawking HighDB Wireless USB Adapter"),
-	PRISM_DEV(0x2001, 0x3700, "DWL-122 Wireless USB Adapter"),
-	PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F Wireless USB Adapter"),
+	PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 / Hawking HighDB USB Wireless Adapter"),
+	PRISM_DEV(0x2001, 0x3700, "DWL-122 USB Wireless Adapter"),
+	PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F USB Wireless Adapter"),
 	PRISM_DEV(0x50c2, 0x4013, "Averatec USB WLAN Adapter"),
-	PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H WLAN USB Adapter"),
-	PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 WLAN USB Adapter"),
+	PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H USB WLAN Adapter"),
+	PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 USB WLAN Adapter"),
 	PRISM_DEV(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter"),
 	PRISM_DEV(0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter"),
-	PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan 802.11b USB Adapter"),
-	PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA 802.11b USB Adapter"),
+	PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan USB 802.11b Adapter"),
+	PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA USB 802.11b Adapter"),
 	PRISM_DEV(0x0bb2, 0x0302, "Ambit Microsystems Corp."),
-	PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 802.11b USB Adapter"),
+	PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 USB 802.11b Adapter"),
 	PRISM_DEV(0x0543, 0x0f01,
 		  "ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)"),
 	PRISM_DEV(0x067c, 0x1022,
-		  "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter"),
+		  "Siemens SpeedStream 1022 11Mbps USB WLAN Adapter"),
 	PRISM_DEV(0x049f, 0x0033,
 		  "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter"),
 	{ } /* terminator */
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:15:28 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:15:28 -0400
Subject: [PATCH AUTOSEL 6.4 14/41] wifi: ath12k: Fix a NULL pointer dereference in ath12k_mac_op_hw_scan()
In-Reply-To: <20230908181555.3459640-1-sashal@kernel.org>
References: <20230908181555.3459640-1-sashal@kernel.org>
Message-ID: <20230908181555.3459640-14-sashal@kernel.org>

From: Wen Gong <quic_wgong at quicinc.com>

[ Upstream commit 8ad314da54c6dd223a6b6cc85019160aa842f659 ]

In ath12k_mac_op_hw_scan(), the return value of kzalloc() is directly
used in memcpy(), which may lead to a NULL pointer dereference on
failure of kzalloc().

Fix this bug by adding a check of arg.extraie.ptr.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
Link: https://lore.kernel.org/r/20230726092625.3350-1-quic_wgong at quicinc.com
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath12k/mac.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 58acfe8fdf8c0..4cae50c396486 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2752,9 +2752,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
 	arg.scan_id = ATH12K_SCAN_ID;
 
 	if (req->ie_len) {
+		arg.extraie.ptr = kmemdup(req->ie, req->ie_len, GFP_KERNEL);
+		if (!arg.extraie.ptr) {
+			ret = -ENOMEM;
+			goto exit;
+		}
 		arg.extraie.len = req->ie_len;
-		arg.extraie.ptr = kzalloc(req->ie_len, GFP_KERNEL);
-		memcpy(arg.extraie.ptr, req->ie, req->ie_len);
 	}
 
 	if (req->n_ssids) {
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:15:29 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:15:29 -0400
Subject: [PATCH AUTOSEL 6.4 15/41] wifi: ath12k: avoid array overflow of hw mode for preferred_hw_mode
In-Reply-To: <20230908181555.3459640-1-sashal@kernel.org>
References: <20230908181555.3459640-1-sashal@kernel.org>
Message-ID: <20230908181555.3459640-15-sashal@kernel.org>

From: Wen Gong <quic_wgong at quicinc.com>

[ Upstream commit 1e9b1363e2de1552ee4e3d74ac8bb43a194f1cb4 ]

Currently ath12k define WMI_HOST_HW_MODE_DBS_OR_SBS=5 as max hw mode
for enum wmi_host_hw_mode_config_type, it is also same for the array
ath12k_hw_mode_pri_map.

When tested with new version firmware/board data which support new
hw mode eMLSR mode with hw mode value 8, it leads overflow usage for
array ath12k_hw_mode_pri_map in function ath12k_wmi_hw_mode_caps(),
and then lead preferred_hw_mode changed to 8, and finally function
ath12k_pull_mac_phy_cap_svc_ready_ext() select the capability of hw
mode 8, but the capability of eMLSR mode report from firmware does
not support 2.4 GHz band for WCN7850, so finally 2.4 GHz band is
disabled.

Skip the hw mode which exceeds WMI_HOST_HW_MODE_MAX in function
ath12k_wmi_hw_mode_caps() helps to avoid array overflow, then the 2.4
GHz band will not be disabled.

This is to keep compatibility with newer version firmware/board data
files, this change is still needed after ath12k add eMLSR hw mode 8 in
array ath12k_hw_mode_pri_map and enum wmi_host_hw_mode_config_type,
because more hw mode maybe added in next firmware/board data version
e.g hw mode 9, then it will also lead new array overflow without this
change.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
Link: https://lore.kernel.org/r/20230714072405.28705-1-quic_wgong at quicinc.com
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath12k/wmi.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 7ae0bb78b2b53..cef01148fc163 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -3701,6 +3701,10 @@ static int ath12k_wmi_hw_mode_caps(struct ath12k_base *soc,
 	for (i = 0 ; i < svc_rdy_ext->n_hw_mode_caps; i++) {
 		hw_mode_caps = &svc_rdy_ext->hw_mode_caps[i];
 		mode = le32_to_cpu(hw_mode_caps->hw_mode_id);
+
+		if (mode >= WMI_HOST_HW_MODE_MAX)
+			continue;
+
 		pref = soc->wmi_ab.preferred_hw_mode;
 
 		if (ath12k_hw_mode_pri_map[mode] < ath12k_hw_mode_pri_map[pref]) {
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:15:50 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:15:50 -0400
Subject: [PATCH AUTOSEL 6.4 36/41] wifi: ath12k: Fix memory leak in rx_desc and tx_desc
In-Reply-To: <20230908181555.3459640-1-sashal@kernel.org>
References: <20230908181555.3459640-1-sashal@kernel.org>
Message-ID: <20230908181555.3459640-36-sashal@kernel.org>

From: Rajat Soni <quic_rajson at quicinc.com>

[ Upstream commit afb522b36e76acaa9f8fc06d0a9742d841c47c16 ]

Currently when ath12k_dp_cc_desc_init() is called we allocate
memory to rx_descs and tx_descs. In ath12k_dp_cc_cleanup(), during
descriptor cleanup rx_descs and tx_descs memory is not freed.

This is cause of memory leak. These allocated memory should be
freed in ath12k_dp_cc_cleanup.

In ath12k_dp_cc_desc_init(), we can save base address of rx_descs
and tx_descs. In ath12k_dp_cc_cleanup(), we can free rx_descs and
tx_descs memory using their base address.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Rajat Soni <quic_rajson at quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
Link: https://lore.kernel.org/r/20230718053510.30894-1-quic_rajson at quicinc.com
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath12k/dp.c | 30 +++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/dp.h |  2 ++
 2 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath12k/dp.c b/drivers/net/wireless/ath/ath12k/dp.c
index ae1645d0f42a2..f933896f2a68d 100644
--- a/drivers/net/wireless/ath/ath12k/dp.c
+++ b/drivers/net/wireless/ath/ath12k/dp.c
@@ -1129,6 +1129,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
 	struct ath12k_dp *dp = &ab->dp;
 	struct sk_buff *skb;
 	int i;
+	u32 pool_id, tx_spt_page;
 
 	if (!dp->spt_info)
 		return;
@@ -1148,6 +1149,14 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
 		dev_kfree_skb_any(skb);
 	}
 
+	for (i = 0; i < ATH12K_NUM_RX_SPT_PAGES; i++) {
+		if (!dp->spt_info->rxbaddr[i])
+			continue;
+
+		kfree(dp->spt_info->rxbaddr[i]);
+		dp->spt_info->rxbaddr[i] = NULL;
+	}
+
 	spin_unlock_bh(&dp->rx_desc_lock);
 
 	/* TX Descriptor cleanup */
@@ -1170,6 +1179,21 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
 		spin_unlock_bh(&dp->tx_desc_lock[i]);
 	}
 
+	for (pool_id = 0; pool_id < ATH12K_HW_MAX_QUEUES; pool_id++) {
+		spin_lock_bh(&dp->tx_desc_lock[pool_id]);
+
+		for (i = 0; i < ATH12K_TX_SPT_PAGES_PER_POOL; i++) {
+			tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
+			if (!dp->spt_info->txbaddr[tx_spt_page])
+				continue;
+
+			kfree(dp->spt_info->txbaddr[tx_spt_page]);
+			dp->spt_info->txbaddr[tx_spt_page] = NULL;
+		}
+
+		spin_unlock_bh(&dp->tx_desc_lock[pool_id]);
+	}
+
 	/* unmap SPT pages */
 	for (i = 0; i < dp->num_spt_pages; i++) {
 		if (!dp->spt_info[i].vaddr)
@@ -1343,6 +1367,8 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
 			return -ENOMEM;
 		}
 
+		dp->spt_info->rxbaddr[i] = &rx_descs[0];
+
 		for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
 			rx_descs[j].cookie = ath12k_dp_cc_cookie_gen(i, j);
 			rx_descs[j].magic = ATH12K_DP_RX_DESC_MAGIC;
@@ -1368,8 +1394,10 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
 				return -ENOMEM;
 			}
 
+			tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
+			dp->spt_info->txbaddr[tx_spt_page] = &tx_descs[0];
+
 			for (j = 0; j < ATH12K_MAX_SPT_ENTRIES; j++) {
-				tx_spt_page = i + pool_id * ATH12K_TX_SPT_PAGES_PER_POOL;
 				ppt_idx = ATH12K_NUM_RX_SPT_PAGES + tx_spt_page;
 				tx_descs[j].desc_id = ath12k_dp_cc_cookie_gen(ppt_idx, j);
 				tx_descs[j].pool_id = pool_id;
diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
index 7c5dafce5a68d..9aeda0321cd75 100644
--- a/drivers/net/wireless/ath/ath12k/dp.h
+++ b/drivers/net/wireless/ath/ath12k/dp.h
@@ -289,6 +289,8 @@ struct ath12k_tx_desc_info {
 struct ath12k_spt_info {
 	dma_addr_t paddr;
 	u64 *vaddr;
+	struct ath12k_rx_desc_info *rxbaddr[ATH12K_NUM_RX_SPT_PAGES];
+	struct ath12k_tx_desc_info *txbaddr[ATH12K_NUM_TX_SPT_PAGES];
 };
 
 struct ath12k_reo_queue_ref {
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:15:52 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:15:52 -0400
Subject: [PATCH AUTOSEL 6.4 38/41] wifi: ath12k: add check max message length while scanning with extraie
In-Reply-To: <20230908181555.3459640-1-sashal@kernel.org>
References: <20230908181555.3459640-1-sashal@kernel.org>
Message-ID: <20230908181555.3459640-38-sashal@kernel.org>

From: Wen Gong <quic_wgong at quicinc.com>

[ Upstream commit 2f5124e86ae74b7ba24c9ae2644107b750cbf38f ]

Currently the extraie length is directly used to allocate skb buffer. When
the length of skb is greater than the max message length which firmware
supports, error will happen in firmware side.

Hence add check for the skb length and drop extraie when overflow and
print a message.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
Reviewed-by: Jeff Johnson <quic_jjohnson at quicinc.com>
Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
Link: https://lore.kernel.org/r/20230809081657.13858-1-quic_wgong at quicinc.com
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath12k/wmi.c | 20 +++++++++++++-------
 1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index cef01148fc163..6ae09779a68cc 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -2163,12 +2163,6 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	if (arg->num_bssid)
 		len += sizeof(*bssid) * arg->num_bssid;
 
-	len += TLV_HDR_SIZE;
-	if (arg->extraie.len)
-		extraie_len_with_pad =
-			roundup(arg->extraie.len, sizeof(u32));
-	len += extraie_len_with_pad;
-
 	if (arg->num_hint_bssid)
 		len += TLV_HDR_SIZE +
 		       arg->num_hint_bssid * sizeof(*hint_bssid);
@@ -2177,6 +2171,18 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 		len += TLV_HDR_SIZE +
 		       arg->num_hint_s_ssid * sizeof(*s_ssid);
 
+	len += TLV_HDR_SIZE;
+	if (arg->extraie.len)
+		extraie_len_with_pad =
+			roundup(arg->extraie.len, sizeof(u32));
+	if (extraie_len_with_pad <= (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len)) {
+		len += extraie_len_with_pad;
+	} else {
+		ath12k_warn(ar->ab, "discard large size %d bytes extraie for scan start\n",
+			    arg->extraie.len);
+		extraie_len_with_pad = 0;
+	}
+
 	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
 	if (!skb)
 		return -ENOMEM;
@@ -2266,7 +2272,7 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len);
 	ptr += TLV_HDR_SIZE;
 
-	if (arg->extraie.len)
+	if (extraie_len_with_pad)
 		memcpy(ptr, arg->extraie.ptr,
 		       arg->extraie.len);
 
-- 
2.40.1



From sashal at kernel.org  Fri Sep  8 11:15:53 2023
From: sashal at kernel.org (Sasha Levin)
Date: Fri,  8 Sep 2023 14:15:53 -0400
Subject: [PATCH AUTOSEL 6.4 39/41] Fix nomenclature for USB and PCI wireless devices
In-Reply-To: <20230908181555.3459640-1-sashal@kernel.org>
References: <20230908181555.3459640-1-sashal@kernel.org>
Message-ID: <20230908181555.3459640-39-sashal@kernel.org>

From: Alan Stern <stern at rowland.harvard.edu>

[ Upstream commit 5d7cf67f72ae34d38e090bdfa673da4aefe4048e ]

A mouse that uses a USB connection is called a "USB mouse" device (or
"USB mouse" for short), not a "mouse USB" device.  By analogy, a WiFi
adapter that connects to the host computer via USB is a "USB wireless"
device, not a "wireless USB" device.  (The latter term more properly
refers to a defunct Wireless USB specification, which described a
technology for sending USB protocol messages over an ultra wideband
radio link.)

Similarly for a WiFi adapter card that plugs into a PCIe slot: It is a
"PCIe wireless" device, not a "wireless PCIe" device.

Rephrase the text in the kernel source where the word ordering is
wrong.

Signed-off-by: Alan Stern <stern at rowland.harvard.edu>
Reviewed-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
Signed-off-by: Kalle Valo <kvalo at kernel.org>
Link: https://lore.kernel.org/r/57da7c80-0e48-41b5-8427-884a02648f55 at rowland.harvard.edu
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
 drivers/net/wireless/ath/ath10k/pci.c         |  2 +-
 drivers/net/wireless/ath/ath10k/usb.c         |  2 +-
 drivers/net/wireless/ath/ath11k/pci.c         |  2 +-
 drivers/net/wireless/ath/ath12k/pci.c         |  2 +-
 drivers/net/wireless/atmel/at76c50x-usb.c     |  8 ++--
 .../wireless/intersil/orinoco/orinoco_usb.c   | 12 ++---
 drivers/net/wireless/legacy/rndis_wlan.c      |  2 +-
 .../net/wireless/mediatek/mt76/mt7603/Kconfig |  2 +-
 .../net/wireless/mediatek/mt76/mt7615/Kconfig |  2 +-
 .../net/wireless/mediatek/mt76/mt76x0/Kconfig |  4 +-
 .../net/wireless/mediatek/mt76/mt76x2/Kconfig |  4 +-
 .../net/wireless/mediatek/mt76/mt7915/Kconfig |  2 +-
 .../net/wireless/mediatek/mt76/mt7996/Kconfig |  2 +-
 drivers/net/wireless/mediatek/mt7601u/Kconfig |  2 +-
 drivers/net/wireless/purelifi/plfxlc/Kconfig  |  2 +-
 drivers/net/wireless/ralink/rt2x00/Kconfig    |  2 +-
 drivers/net/wireless/realtek/rtw88/pci.c      |  2 +-
 drivers/net/wireless/realtek/rtw88/usb.c      |  2 +-
 drivers/net/wireless/realtek/rtw89/pci.c      |  2 +-
 drivers/net/wireless/zydas/zd1201.c           |  6 +--
 drivers/platform/x86/eeepc-laptop.c           |  2 +-
 drivers/staging/wlan-ng/prism2usb.c           | 48 +++++++++----------
 22 files changed, 57 insertions(+), 57 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index a7f44f6335fb8..3ef414b613bf3 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -3816,7 +3816,7 @@ static void __exit ath10k_pci_exit(void)
 module_exit(ath10k_pci_exit);
 
 MODULE_AUTHOR("Qualcomm Atheros");
-MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN PCIe/AHB devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Atheros PCIe/AHB 802.11ac WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
 /* QCA988x 2.0 firmware files */
diff --git a/drivers/net/wireless/ath/ath10k/usb.c b/drivers/net/wireless/ath/ath10k/usb.c
index b0067af685b16..3c482baacec10 100644
--- a/drivers/net/wireless/ath/ath10k/usb.c
+++ b/drivers/net/wireless/ath/ath10k/usb.c
@@ -1126,5 +1126,5 @@ static struct usb_driver ath10k_usb_driver = {
 module_usb_driver(ath10k_usb_driver);
 
 MODULE_AUTHOR("Atheros Communications, Inc.");
-MODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN USB devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Atheros USB 802.11ac WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index 7b33731a50ee7..650587c8fcf8d 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -1033,7 +1033,7 @@ static void ath11k_pci_exit(void)
 
 module_exit(ath11k_pci_exit);
 
-MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN PCIe devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Technologies PCIe 802.11ax WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
 /* firmware files */
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 9f174daf324c9..05915f75d734c 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1397,5 +1397,5 @@ static void ath12k_pci_exit(void)
 
 module_exit(ath12k_pci_exit);
 
-MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11be WLAN PCIe devices");
+MODULE_DESCRIPTION("Driver support for Qualcomm Technologies PCIe 802.11be WLAN devices");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/atmel/at76c50x-usb.c b/drivers/net/wireless/atmel/at76c50x-usb.c
index 009bca34ece30..447b51cff8f96 100644
--- a/drivers/net/wireless/atmel/at76c50x-usb.c
+++ b/drivers/net/wireless/atmel/at76c50x-usb.c
@@ -10,7 +10,7 @@
  * Copyright (c) 2007 Kalle Valo <kalle.valo at iki.fi>
  * Copyright (c) 2010 Sebastian Smolorz <sesmo at gmx.net>
  *
- * This file is part of the Berlios driver for WLAN USB devices based on the
+ * This file is part of the Berlios driver for USB WLAN devices based on the
  * Atmel AT76C503A/505/505A.
  *
  * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed
@@ -143,7 +143,7 @@ static const struct usb_device_id dev_table[] = {
 	{ USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
 	/* Dynalink/Askey WLL013 (intersil) */
 	{ USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861) },
-	/* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */
+	/* EZ connect 11Mpbs USB Wireless Adapter SMC2662W v1 */
 	{ USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
 	/* BenQ AWL300 */
 	{ USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861) },
@@ -195,7 +195,7 @@ static const struct usb_device_id dev_table[] = {
 	{ USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503) },
 	/* 3Com 3CRSHEW696 */
 	{ USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503) },
-	/* Siemens Santis ADSL WLAN USB adapter WLL 013 */
+	/* Siemens Santis ADSL USB WLAN adapter WLL 013 */
 	{ USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503) },
 	/* Belkin F5D6050, version 2 */
 	{ USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503) },
@@ -238,7 +238,7 @@ static const struct usb_device_id dev_table[] = {
 	{ USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958) },
 	/* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */
 	{ USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958) },
-	/* Corega WLAN USB Stick 11 */
+	/* Corega USB WLAN Stick 11 */
 	{ USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },
 	/* Microstar MSI Box MS6978 */
 	{ USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958) },
diff --git a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
index dd31929261ab9..866e0230df251 100644
--- a/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/intersil/orinoco/orinoco_usb.c
@@ -129,18 +129,18 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
 
 #define USB_AVAYA8_VENDOR_ID     0x0D98
 #define USB_AVAYAE_VENDOR_ID     0x0D9E
-#define USB_AVAYA_WIRELESS_ID    0x0300 /* Avaya Wireless USB Card */
+#define USB_AVAYA_WIRELESS_ID    0x0300 /* Avaya USB Wireless Card */
 
 #define USB_AGERE_VENDOR_ID      0x0D4E /* Agere Systems */
-#define USB_AGERE_MODEL0801_ID   0x1000 /* Wireless USB Card Model 0801 */
-#define USB_AGERE_MODEL0802_ID   0x1001 /* Wireless USB Card Model 0802 */
-#define USB_AGERE_REBRANDED_ID   0x047A /* WLAN USB Card */
+#define USB_AGERE_MODEL0801_ID   0x1000 /* USB Wireless Card Model 0801 */
+#define USB_AGERE_MODEL0802_ID   0x1001 /* USB Wireless Card Model 0802 */
+#define USB_AGERE_REBRANDED_ID   0x047A /* USB WLAN Card */
 
 #define USB_ELSA_VENDOR_ID       0x05CC
 #define USB_ELSA_AIRLANCER_ID    0x3100 /* ELSA AirLancer USB-11 */
 
 #define USB_LEGEND_VENDOR_ID     0x0E7C
-#define USB_LEGEND_JOYNET_ID     0x0300 /* Joynet WLAN USB Card */
+#define USB_LEGEND_JOYNET_ID     0x0300 /* Joynet USB WLAN Card */
 
 #define USB_SAMSUNG_VENDOR_ID    0x04E8
 #define USB_SAMSUNG_SEW2001U1_ID 0x5002 /* Samsung SEW-2001u Card */
@@ -154,7 +154,7 @@ MODULE_FIRMWARE("orinoco_ezusb_fw");
 #define USB_FUJITSU_E1100_ID     0x1002 /* connect2AIR WLAN E-1100 USB */
 
 #define USB_2WIRE_VENDOR_ID      0x1630
-#define USB_2WIRE_WIRELESS_ID    0xff81 /* 2Wire Wireless USB adapter */
+#define USB_2WIRE_WIRELESS_ID    0xff81 /* 2Wire USB Wireless adapter */
 
 
 #define EZUSB_REQUEST_FW_TRANS		0xA0
diff --git a/drivers/net/wireless/legacy/rndis_wlan.c b/drivers/net/wireless/legacy/rndis_wlan.c
index 712038d46bdb3..e7fea7ded6d5c 100644
--- a/drivers/net/wireless/legacy/rndis_wlan.c
+++ b/drivers/net/wireless/legacy/rndis_wlan.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * Driver for RNDIS based wireless USB devices.
+ * Driver for RNDIS based USB wireless devices.
  *
  * Copyright (C) 2007 by Bjorge Dijkstra <bjd at jooz.net>
  * Copyright (C) 2008-2009 by Jussi Kivilinna <jussi.kivilinna at iki.fi>
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
index 6a0080f1d91c7..dd16acfd9735d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/Kconfig
@@ -5,7 +5,7 @@ config MT7603E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7603E wireless PCIe devices and the WLAN core
+	  This adds support for MT7603E PCIe wireless devices and the WLAN core
 	  on MT7628/MT7688 SoC devices. This family supports IEEE 802.11n 2x2
 	  to 300Mbps PHY rate
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
index 30fba36ff46bb..1ab1439143f41 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
@@ -11,7 +11,7 @@ config MT7615E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7615-based wireless PCIe devices,
+	  This adds support for MT7615-based PCIe wireless devices,
 	  which support concurrent dual-band operation at both 5GHz
 	  and 2.4GHz, IEEE 802.11ac 4x4:4SS 1733Mbps PHY rate, wave2
 	  MU-MIMO up to 4 users/group and 160MHz channels.
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
index 7c88ed8b8f1e9..3ed888782a709 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig
@@ -10,7 +10,7 @@ config MT76x0U
 	depends on MAC80211
 	depends on USB
 	help
-	  This adds support for MT7610U-based wireless USB 2.0 dongles,
+	  This adds support for MT7610U-based USB 2.0 wireless dongles,
 	  which comply with IEEE 802.11ac standards and support 1x1
 	  433Mbps PHY rate.
 
@@ -22,7 +22,7 @@ config MT76x0E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7610/MT7630-based wireless PCIe devices,
+	  This adds support for MT7610/MT7630-based PCIe wireless devices,
 	  which comply with IEEE 802.11ac standards and support 1x1
 	  433Mbps PHY rate.
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
index 5fd4973e32dfb..482a32b70ddfe 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig
@@ -9,7 +9,7 @@ config MT76x2E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7612/MT7602/MT7662-based wireless PCIe
+	  This adds support for MT7612/MT7602/MT7662-based PCIe wireless
 	  devices, which comply with IEEE 802.11ac standards and support
 	  2SS to 866Mbit/s PHY rate.
 
@@ -22,7 +22,7 @@ config MT76x2U
 	depends on MAC80211
 	depends on USB
 	help
-	  This adds support for MT7612U-based wireless USB 3.0 dongles,
+	  This adds support for MT7612U-based USB 3.0 wireless dongles,
 	  which comply with IEEE 802.11ac standards and support 2SS to
 	  866Mbit/s PHY rate.
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
index d710726d47bfd..3337cdfed0109 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
@@ -7,7 +7,7 @@ config MT7915E
 	depends on PCI
 	select RELAY
 	help
-	  This adds support for MT7915-based wireless PCIe devices,
+	  This adds support for MT7915-based PCIe wireless devices,
 	  which support concurrent dual-band operation at both 5GHz
 	  and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels,
 	  OFDMA, spatial reuse and dual carrier modulation.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
index 1afa2f662e473..bb44d4a5e2dc9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig
@@ -7,7 +7,7 @@ config MT7996E
 	depends on MAC80211
 	depends on PCI
 	help
-	  This adds support for MT7996-based wireless PCIe devices,
+	  This adds support for MT7996-based PCIe wireless devices,
 	  which support concurrent tri-band operation at 6GHz, 5GHz,
 	  and 2.4GHz IEEE 802.11be 4x4:4SS 4096-QAM, 320MHz channels.
 
diff --git a/drivers/net/wireless/mediatek/mt7601u/Kconfig b/drivers/net/wireless/mediatek/mt7601u/Kconfig
index 4a8b962806707..4880fc053d9d3 100644
--- a/drivers/net/wireless/mediatek/mt7601u/Kconfig
+++ b/drivers/net/wireless/mediatek/mt7601u/Kconfig
@@ -4,4 +4,4 @@ config MT7601U
 	depends on MAC80211
 	depends on USB
 	help
-	  This adds support for MT7601U-based wireless USB dongles.
+	  This adds support for MT7601U-based USB wireless dongles.
diff --git a/drivers/net/wireless/purelifi/plfxlc/Kconfig b/drivers/net/wireless/purelifi/plfxlc/Kconfig
index 4e0be27a5e0eb..dd5fca480d7ef 100644
--- a/drivers/net/wireless/purelifi/plfxlc/Kconfig
+++ b/drivers/net/wireless/purelifi/plfxlc/Kconfig
@@ -3,7 +3,7 @@ config PLFXLC
 	tristate "pureLiFi X, XL, XC device support"
 	depends on CFG80211 && MAC80211 && USB
 	help
-	   This option adds support for pureLiFi LiFi wireless USB
+	   This option adds support for pureLiFi LiFi USB wireless
 	   adapters. The pureLiFi X, XL, XC USB devices are based on
 	   802.11 OFDM PHY but uses light as the transmission medium.
 	   The driver supports common 802.11 encryption/authentication
diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig
index dcccc290a7f52..d1fd66d44a7ed 100644
--- a/drivers/net/wireless/ralink/rt2x00/Kconfig
+++ b/drivers/net/wireless/ralink/rt2x00/Kconfig
@@ -170,7 +170,7 @@ config RT2800USB_RT35XX
 config RT2800USB_RT3573
 	bool "rt2800usb - Include support for rt3573 devices (EXPERIMENTAL)"
 	help
-	  This enables support for RT3573 chipset based wireless USB devices
+	  This enables support for RT3573 chipset based USB wireless devices
 	  in the rt2800usb driver.
 
 config RT2800USB_RT53XX
diff --git a/drivers/net/wireless/realtek/rtw88/pci.c b/drivers/net/wireless/realtek/rtw88/pci.c
index 672ddde808160..a628606e48c1e 100644
--- a/drivers/net/wireless/realtek/rtw88/pci.c
+++ b/drivers/net/wireless/realtek/rtw88/pci.c
@@ -1827,5 +1827,5 @@ void rtw_pci_shutdown(struct pci_dev *pdev)
 EXPORT_SYMBOL(rtw_pci_shutdown);
 
 MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ac wireless PCI driver");
+MODULE_DESCRIPTION("Realtek PCI 802.11ac wireless driver");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index 976eafa739a2d..92ee9304d0723 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -920,5 +920,5 @@ void rtw_usb_disconnect(struct usb_interface *intf)
 EXPORT_SYMBOL(rtw_usb_disconnect);
 
 MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ac wireless USB driver");
+MODULE_DESCRIPTION("Realtek USB 802.11ac wireless driver");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/realtek/rtw89/pci.c b/drivers/net/wireless/realtek/rtw89/pci.c
index 70b4754667c98..eceaf1e5d2066 100644
--- a/drivers/net/wireless/realtek/rtw89/pci.c
+++ b/drivers/net/wireless/realtek/rtw89/pci.c
@@ -3938,5 +3938,5 @@ void rtw89_pci_remove(struct pci_dev *pdev)
 EXPORT_SYMBOL(rtw89_pci_remove);
 
 MODULE_AUTHOR("Realtek Corporation");
-MODULE_DESCRIPTION("Realtek 802.11ax wireless PCI driver");
+MODULE_DESCRIPTION("Realtek PCI 802.11ax wireless driver");
 MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/zydas/zd1201.c b/drivers/net/wireless/zydas/zd1201.c
index a85fe7e4c6d47..2814df1ecc78f 100644
--- a/drivers/net/wireless/zydas/zd1201.c
+++ b/drivers/net/wireless/zydas/zd1201.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- *	Driver for ZyDAS zd1201 based wireless USB devices.
+ *	Driver for ZyDAS zd1201 based USB wireless devices.
  *
  *	Copyright (c) 2004, 2005 Jeroen Vreeken (pe1rxq at amsat.org)
  *
@@ -23,8 +23,8 @@
 #include "zd1201.h"
 
 static const struct usb_device_id zd1201_table[] = {
-	{USB_DEVICE(0x0586, 0x3400)}, /* Peabird Wireless USB Adapter */
-	{USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 Wireless USB Adapter */
+	{USB_DEVICE(0x0586, 0x3400)}, /* Peabird USB Wireless Adapter */
+	{USB_DEVICE(0x0ace, 0x1201)}, /* ZyDAS ZD1201 USB Wireless Adapter */
 	{USB_DEVICE(0x050d, 0x6051)}, /* Belkin F5D6051 usb  adapter */
 	{USB_DEVICE(0x0db0, 0x6823)}, /* MSI UB11B usb  adapter */
 	{USB_DEVICE(0x1044, 0x8004)}, /* Gigabyte GN-WLBZ101 */
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 62b71e8e3567a..ff1b70269ccbf 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -1394,7 +1394,7 @@ static int eeepc_acpi_add(struct acpi_device *device)
 	 * and machine-specific scripts find the fixed name convenient.  But
 	 * It's also good for us to exclude multiple instances because both
 	 * our hwmon and our wlan rfkill subdevice use global ACPI objects
-	 * (the EC and the wlan PCI slot respectively).
+	 * (the EC and the PCI wlan slot respectively).
 	 */
 	result = eeepc_platform_init(eeepc);
 	if (result)
diff --git a/drivers/staging/wlan-ng/prism2usb.c b/drivers/staging/wlan-ng/prism2usb.c
index 80e36d03c4e25..0e0ccef4871e9 100644
--- a/drivers/staging/wlan-ng/prism2usb.c
+++ b/drivers/staging/wlan-ng/prism2usb.c
@@ -11,45 +11,45 @@
 
 static const struct usb_device_id usb_prism_tbl[] = {
 	PRISM_DEV(0x04bb, 0x0922, "IOData AirPort WN-B11/USBS"),
-	PRISM_DEV(0x07aa, 0x0012, "Corega Wireless LAN USB Stick-11"),
-	PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps WLAN USB Adapter"),
+	PRISM_DEV(0x07aa, 0x0012, "Corega USB Wireless LAN Stick-11"),
+	PRISM_DEV(0x09aa, 0x3642, "Prism2.x 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x1668, 0x0408, "Actiontec Prism2.5 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x1668, 0x0421, "Actiontec Prism2.5 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x1915, 0x2236, "Linksys WUSB11v3.0 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x066b, 0x2212, "Linksys WUSB11v2.5 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x066b, 0x2213, "Linksys WUSB12v1.1 11Mbps USB WLAN Adapter"),
 	PRISM_DEV(0x0411, 0x0016, "Melco WLI-USB-S11 11Mbps WLAN Adapter"),
-	PRISM_DEV(0x08de, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"),
-	PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B LAN USB Adapter"),
+	PRISM_DEV(0x08de, 0x7a01, "PRISM25 USB IEEE 802.11 Mini Adapter"),
+	PRISM_DEV(0x8086, 0x1111, "Intel PRO/Wireless 2011B USB LAN Adapter"),
 	PRISM_DEV(0x0d8e, 0x7a01, "PRISM25 IEEE 802.11 Mini USB Adapter"),
-	PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 Wireless USB Adapter"),
+	PRISM_DEV(0x045e, 0x006e, "Microsoft MN510 USB Wireless Adapter"),
 	PRISM_DEV(0x0967, 0x0204, "Acer Warplink USB Adapter"),
 	PRISM_DEV(0x0cde, 0x0002, "Z-Com 725/726 Prism2.5 USB/USB Integrated"),
-	PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 Wireless 802.11b USB Adapter"),
-	PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 Wireless USB Adapter"),
-	PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps WLAN USB Adapter"),
-	PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 Wireless USB Adapter"),
-	PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 Wireless USB Adapter"),
+	PRISM_DEV(0x0cde, 0x0005, "Z-Com Xl735 USB Wireless 802.11b Adapter"),
+	PRISM_DEV(0x413c, 0x8100, "Dell TrueMobile 1180 USB Wireless Adapter"),
+	PRISM_DEV(0x0b3b, 0x1601, "ALLNET 0193 11Mbps USB WLAN Adapter"),
+	PRISM_DEV(0x0b3b, 0x1602, "ZyXEL ZyAIR B200 USB Wireless Adapter"),
+	PRISM_DEV(0x0baf, 0x00eb, "USRobotics USR1120 USB Wireless Adapter"),
 	PRISM_DEV(0x0411, 0x0027, "Melco WLI-USB-KS11G 11Mbps WLAN Adapter"),
 	PRISM_DEV(0x04f1, 0x3009, "JVC MP-XP7250 Builtin USB WLAN Adapter"),
 	PRISM_DEV(0x0846, 0x4110, "NetGear MA111"),
 	PRISM_DEV(0x03f3, 0x0020, "Adaptec AWN-8020 USB WLAN Adapter"),
-	PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 / Hawking HighDB Wireless USB Adapter"),
-	PRISM_DEV(0x2001, 0x3700, "DWL-122 Wireless USB Adapter"),
-	PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F Wireless USB Adapter"),
+	PRISM_DEV(0x2821, 0x3300, "ASUS-WL140 / Hawking HighDB USB Wireless Adapter"),
+	PRISM_DEV(0x2001, 0x3700, "DWL-122 USB Wireless Adapter"),
+	PRISM_DEV(0x2001, 0x3702, "DWL-120 Rev F USB Wireless Adapter"),
 	PRISM_DEV(0x50c2, 0x4013, "Averatec USB WLAN Adapter"),
-	PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H WLAN USB Adapter"),
-	PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 WLAN USB Adapter"),
+	PRISM_DEV(0x2c02, 0x14ea, "Planex GW-US11H USB WLAN Adapter"),
+	PRISM_DEV(0x124a, 0x168b, "Airvast PRISM3 USB WLAN Adapter"),
 	PRISM_DEV(0x083a, 0x3503, "T-Sinus 111 USB WLAN Adapter"),
 	PRISM_DEV(0x0411, 0x0044, "Melco WLI-USB-KB11 11Mbps WLAN Adapter"),
-	PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan 802.11b USB Adapter"),
-	PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA 802.11b USB Adapter"),
+	PRISM_DEV(0x1668, 0x6106, "ROPEX FreeLan USB 802.11b Adapter"),
+	PRISM_DEV(0x124a, 0x4017, "Pheenet WL-503IA USB 802.11b Adapter"),
 	PRISM_DEV(0x0bb2, 0x0302, "Ambit Microsystems Corp."),
-	PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 802.11b USB Adapter"),
+	PRISM_DEV(0x9016, 0x182d, "Sitecom WL-022 USB 802.11b Adapter"),
 	PRISM_DEV(0x0543, 0x0f01,
 		  "ViewSonic Airsync USB Adapter 11Mbps (Prism2.5)"),
 	PRISM_DEV(0x067c, 0x1022,
-		  "Siemens SpeedStream 1022 11Mbps WLAN USB Adapter"),
+		  "Siemens SpeedStream 1022 11Mbps USB WLAN Adapter"),
 	PRISM_DEV(0x049f, 0x0033,
 		  "Compaq/Intel W100 PRO/Wireless 11Mbps multiport WLAN Adapter"),
 	{ } /* terminator */
-- 
2.40.1



From stern at rowland.harvard.edu  Fri Sep  8 12:12:26 2023
From: stern at rowland.harvard.edu (Alan Stern)
Date: Fri, 8 Sep 2023 15:12:26 -0400
Subject: [PATCH AUTOSEL 6.5 43/45] Fix nomenclature for USB and PCI
 wireless devices
In-Reply-To: <20230908181327.3459042-43-sashal@kernel.org>
References: <20230908181327.3459042-1-sashal@kernel.org>
 <20230908181327.3459042-43-sashal@kernel.org>
Message-ID: <0d2ddf90-2334-4d0c-9f63-018c150e06a9@rowland.harvard.edu>

On Fri, Sep 08, 2023 at 02:13:24PM -0400, Sasha Levin wrote:
> From: Alan Stern <stern at rowland.harvard.edu>
> 
> [ Upstream commit 5d7cf67f72ae34d38e090bdfa673da4aefe4048e ]
> 
> A mouse that uses a USB connection is called a "USB mouse" device (or
> "USB mouse" for short), not a "mouse USB" device.  By analogy, a WiFi
> adapter that connects to the host computer via USB is a "USB wireless"
> device, not a "wireless USB" device.  (The latter term more properly
> refers to a defunct Wireless USB specification, which described a
> technology for sending USB protocol messages over an ultra wideband
> radio link.)
> 
> Similarly for a WiFi adapter card that plugs into a PCIe slot: It is a
> "PCIe wireless" device, not a "wireless PCIe" device.
> 
> Rephrase the text in the kernel source where the word ordering is
> wrong.
> 
> Signed-off-by: Alan Stern <stern at rowland.harvard.edu>
> Reviewed-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> Signed-off-by: Kalle Valo <kvalo at kernel.org>
> Link: https://lore.kernel.org/r/57da7c80-0e48-41b5-8427-884a02648f55 at rowland.harvard.edu
> Signed-off-by: Sasha Levin <sashal at kernel.org>


Is there any real reason to apply this commit to the -stable kernels?
I did not mark it that way when it was submitted, and it doesn't fix
any bugs.  In fact, aside from updating some module and device
description strings, all it does is change a bunch of comments.

Does that really fall under the -stable rules for acceptance?

Alan Stern


From gregkh at linuxfoundation.org  Fri Sep  8 14:31:55 2023
From: gregkh at linuxfoundation.org (Greg Kroah-Hartman)
Date: Fri, 8 Sep 2023 22:31:55 +0100
Subject: [PATCH AUTOSEL 6.5 43/45] Fix nomenclature for USB and PCI
 wireless devices
In-Reply-To: <0d2ddf90-2334-4d0c-9f63-018c150e06a9@rowland.harvard.edu>
References: <20230908181327.3459042-1-sashal@kernel.org>
 <20230908181327.3459042-43-sashal@kernel.org>
 <0d2ddf90-2334-4d0c-9f63-018c150e06a9@rowland.harvard.edu>
Message-ID: <2023090838-slurp-tilt-c7c4@gregkh>

On Fri, Sep 08, 2023 at 03:12:26PM -0400, Alan Stern wrote:
> On Fri, Sep 08, 2023 at 02:13:24PM -0400, Sasha Levin wrote:
> > From: Alan Stern <stern at rowland.harvard.edu>
> > 
> > [ Upstream commit 5d7cf67f72ae34d38e090bdfa673da4aefe4048e ]
> > 
> > A mouse that uses a USB connection is called a "USB mouse" device (or
> > "USB mouse" for short), not a "mouse USB" device.  By analogy, a WiFi
> > adapter that connects to the host computer via USB is a "USB wireless"
> > device, not a "wireless USB" device.  (The latter term more properly
> > refers to a defunct Wireless USB specification, which described a
> > technology for sending USB protocol messages over an ultra wideband
> > radio link.)
> > 
> > Similarly for a WiFi adapter card that plugs into a PCIe slot: It is a
> > "PCIe wireless" device, not a "wireless PCIe" device.
> > 
> > Rephrase the text in the kernel source where the word ordering is
> > wrong.
> > 
> > Signed-off-by: Alan Stern <stern at rowland.harvard.edu>
> > Reviewed-by: Greg Kroah-Hartman <gregkh at linuxfoundation.org>
> > Signed-off-by: Kalle Valo <kvalo at kernel.org>
> > Link: https://lore.kernel.org/r/57da7c80-0e48-41b5-8427-884a02648f55 at rowland.harvard.edu
> > Signed-off-by: Sasha Levin <sashal at kernel.org>
> 
> 
> Is there any real reason to apply this commit to the -stable kernels?
> I did not mark it that way when it was submitted, and it doesn't fix
> any bugs.  In fact, aside from updating some module and device
> description strings, all it does is change a bunch of comments.
> 
> Does that really fall under the -stable rules for acceptance?

Not really, this is just documentation, it should be dropped from the
autosel queues.

thanks,

greg k-h


From quic_lingbok at quicinc.com  Sun Sep 10 01:27:58 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Sun, 10 Sep 2023 16:27:58 +0800
Subject: [PATCH v4 0/4] wifi: ath12k: implement some functionalities through reading ACPI Table
Message-ID: <20230910082802.9198-1-quic_lingbok@quicinc.com>

Through reading ACPI table, implement Time-Average-SAR(TAS), BIOS SAR,
configuration of CCA threshold and band edge channel power functionalities.

v4:
1.revise commit log using imperative voice
2.delete guid_is_null()

v3:
1.remove unnecessary cpu_to_le32()
2.adjust the order of the macros
3.apply jeff's advice

v2:
1.put <linux/acpi.h> in the include guard

Lingbo Kong (4):
  wifi: ath12k: add TAS capability for WCN7850
  wifi: ath12k: add BIOS SAR capability for WCN7850
  wifi: ath12k: add adjust configuration of CCA threshold value for
    WCN7850
  wifi: ath12k: add set band edge channel power for WCN7850

 drivers/net/wireless/ath/ath12k/Makefile |   3 +-
 drivers/net/wireless/ath/ath12k/acpi.c   | 365 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h   |  60 ++++
 drivers/net/wireless/ath/ath12k/core.c   |   6 +
 drivers/net/wireless/ath/ath12k/core.h   |  13 +
 drivers/net/wireless/ath/ath12k/hw.c     |  10 +
 drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
 drivers/net/wireless/ath/ath12k/pci.c    |   6 +
 drivers/net/wireless/ath/ath12k/wmi.c    | 252 ++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h    |  47 ++-
 10 files changed, 763 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h


base-commit: 1b5b69a51bb4909844e4003920af09ca1cc6bb0e
-- 
2.34.1



From quic_lingbok at quicinc.com  Sun Sep 10 01:28:00 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Sun, 10 Sep 2023 16:28:00 +0800
Subject: [PATCH v4 2/4] wifi: ath12k: add BIOS SAR capability for WCN7850
In-Reply-To: <20230910082802.9198-1-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
Message-ID: <20230910082802.9198-3-quic_lingbok@quicinc.com>

Currently, ath12k does not support BIOS SAR for WCN7850. In order to enable
BIOS SAR for WCN7850, ath12k gets BIOS SAR table and GEO offset table in
ath12k_acpi_dsm_get_data() function, then sets pdev_id, length of data, and
finally sends these data and WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID and
WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID to firmware to implement BIOS SAR during
the initialization phase. Besides, ath12k registers an ACPI event callback
so that ACPI can notify ath12k to get the updated BIOS SAR table and sends
it to firmware when the device state is changed.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v4:
1.revise commit log using imperative voice

v3:
1.adjust the order of the macros
2.apply jeff's advice
3.remove unnecessary cpu_to_le32()

v2:
no change

 drivers/net/wireless/ath/ath12k/acpi.c | 103 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  18 +++++
 drivers/net/wireless/ath/ath12k/core.h |   3 +
 drivers/net/wireless/ath/ath12k/wmi.c  |  92 ++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  21 +++++
 5 files changed, 237 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index 384e01748b32..ae1ce7b99d2d 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -52,6 +52,26 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE) {
+				ath12k_err(ab, "Invalid BIOS SAR data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->bios_sar_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE) {
+				ath12k_err(ab, "Invalid GEO OFFSET data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -83,6 +103,24 @@ static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
 	return ret;
 }
 
+static int ath12k_set_bios_sar_power_limit_data(struct ath12k_base *ab)
+{
+	int ret;
+
+	if (ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
+	    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG) {
+		ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
+							       ab->acdata->bios_sar_data);
+		if (ret)
+			ath12k_err(ab, "failed to pass bios sar table %d\n", ret);
+	} else {
+		ath12k_err(ab, "the latest bios sar data is invalid\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
 {
 	int ret;
@@ -101,6 +139,20 @@ void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
 			if (ret)
 				return;
 		}
+
+		if (ab->acdata->acpi_bios_sar_enable) {
+			ret = ath12k_acpi_dsm_get_data(ab,
+						       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
+			if (ret) {
+				ath12k_err(ab, "failed to update bios sar %d\n", ret);
+				return;
+			}
+
+			ret = ath12k_set_bios_sar_power_limit_data(ab);
+			if (ret)
+				return;
+		}
+
 	} else {
 		ath12k_err(ab, "unknown acpi notify %u\n", event);
 	}
@@ -113,6 +165,27 @@ void ath12k_acpi_remove_notify(struct ath12k_base *ab)
 				   acpi_dsm_notify);
 }
 
+static int ath12k_pass_acpi_bios_sar_and_geo_to_fw(struct ath12k_base *ab)
+{
+	int ret;
+
+	ret = ath12k_wmi_pdev_set_bios_sar_table_param(ab,
+						       ab->acdata->bios_sar_data);
+
+	if (ret) {
+		ath12k_err(ab, "failed to pass bios sar table to fw %d\n", ret);
+		return ret;
+	}
+
+	ret = ath12k_wmi_pdev_set_bios_geo_table_param(ab,
+						       ab->acdata->geo_offset_data);
+
+	if (ret)
+		ath12k_err(ab, "failed to pass bios geo table to fw %d\n", ret);
+
+	return ret;
+}
+
 static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
 {
 	int ret;
@@ -172,12 +245,42 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 			ab->acdata->acpi_tas_enable = true;
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR);
+		if (ret) {
+			ath12k_err(ab, "failed to get bios sar data %d\n", ret);
+			goto err_free_acdata;
+		}
+	}
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_GEO_OFFSET)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET);
+		if (ret) {
+			ath12k_err(ab, "failed to get geo offset data %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BIOS_SAR) &&
+		    ab->acdata->bios_sar_data[0] == ATH12K_ACPI_POWER_LIMIT_VERSION &&
+		    ab->acdata->bios_sar_data[1] == ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG &&
+		    !ab->acdata->acpi_tas_enable)
+			ab->acdata->acpi_bios_sar_enable = true;
+	}
+
 	if (ab->acdata->acpi_tas_enable) {
 		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
 		if (ret)
 			goto err_free_acdata;
 	}
 
+	if (ab->acdata->acpi_bios_sar_enable) {
+		ret = ath12k_pass_acpi_bios_sar_and_geo_to_fw(ab);
+		if (ret)
+			goto err_free_acdata;
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index 2331b8e3e035..2f930f0718da 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -9,9 +9,13 @@
 #include <linux/acpi.h>
 
 #define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
+#define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR             4
+#define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET           5
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
 
+#define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
+#define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
 
@@ -20,10 +24,24 @@
 
 #define ATH12K_ACPI_TAS_DATA_VERSION		0x1
 #define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
+#define ATH12K_ACPI_POWER_LIMIT_VERSION		0x1
+#define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
+
+#define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
+#define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET	2
+#define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN	10
+#define ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET	12
+#define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
+#define ATH12K_ACPI_BIOS_SAR_TABLE_LEN		22
 
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 
+#define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE (ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET + \
+					      ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN)
+#define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE (ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET + \
+					    ATH12K_ACPI_BIOS_SAR_TABLE_LEN)
+
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
 #endif
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index cba4f176c018..6fe4f0ddee4a 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -775,8 +775,11 @@ struct ath12k_base {
 	struct {
 		u32 func_bit;
 		bool acpi_tas_enable;
+		bool acpi_bios_sar_enable;
 		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
 		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
+		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
+		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index f49f4325edff..9ad588897b09 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6998,3 +6998,95 @@ int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
 
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
+					     u8 *psar_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_sar_table_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, sar_table_len_aligned, sar_dbs_backoff_len_aligned;
+	u8 *psar_value = psar_table + ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET;
+	u8 *pdbs_value = psar_table + ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET;
+
+	sar_table_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_TABLE_LEN, sizeof(u32));
+	sar_dbs_backoff_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_table_len_aligned +
+		TLV_HDR_SIZE + sar_dbs_backoff_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_sar_table_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->sar_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
+	cmd->dbs_backoff_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
+					 sar_table_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, psar_value, ATH12K_ACPI_BIOS_SAR_TABLE_LEN);
+
+	buf_ptr += sar_table_len_aligned;
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE,
+					 sar_dbs_backoff_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pdbs_value, ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
+					     u8 *pgeo_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_geo_table_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, sar_geo_len_aligned;
+	u8 *pgeo_value = pgeo_table + ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET;
+
+	sar_geo_len_aligned = roundup(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + sar_geo_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_geo_table_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->geo_len = cpu_to_le32(ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, sar_geo_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pgeo_value, ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 38bbf59fc6b7..8a774655fe9f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -361,6 +361,8 @@ 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_BIOS_SAR_TABLE_CMDID = 0x4044,
+	WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID = 0x4045,
 	WMI_PDEV_SET_BIOS_INTERFACE_CMDID = 0x404A,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
@@ -1932,6 +1934,8 @@ enum wmi_tlv_tag {
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
 	WMI_TAG_EHT_RATE_SET = 0x3C4,
+	WMI_TAG_PDEV_SET_BIOS_SAR_TABLE_CMD_PARAMS = 0x3D8,
+	WMI_TAG_PDEV_SET_BIOS_GEO_TABLE_CMD_PARAMS = 0x3D9,
 	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
 	WMI_TAG_MAX
 };
@@ -4806,6 +4810,19 @@ enum bios_param_type {
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
+struct wmi_pdev_set_bios_sar_table_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 sar_len;
+	__le32 dbs_backoff_len;
+} __packed;
+
+struct wmi_pdev_set_bios_geo_table_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 geo_len;
+} __packed;
+
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
@@ -4931,4 +4948,8 @@ int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
 					    const u8 *ptas_cfg);
 int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
 					     const u8 *ptas_data);
+int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
+					     u8 *psar_table);
+int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
+					     u8 *pgeo_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Sun Sep 10 01:27:59 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Sun, 10 Sep 2023 16:27:59 +0800
Subject: [PATCH v4 1/4] wifi: ath12k: add TAS capability for WCN7850
In-Reply-To: <20230910082802.9198-1-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
Message-ID: <20230910082802.9198-2-quic_lingbok@quicinc.com>

Currently, ath12k does not support Time-Average-SAR(TAS) for WCN7850. In
order to enable Time-Average-SAR(TAS) for WCN7850, ath12k defines
ath12k_get_acpi_all_data() function to get TAS configuration and SAR power
table, then sets pdev_id, param_type_id, and finally sends the TAS
configuration, SAR power table and WMI_PDEV_SET_BIOS_INTERFACE_CMDID
command to firmware to implement TAS during the initialization phase.
Besides, ath12k registers an ACPI event callback so that ACPI can notify
ath12k to get the updated SAR power table and sends it to firmware when the
device state is changed.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v4:
1.revise commit log using imperative voice
2.delete guid_is_null()

v3:
1.remove unnecessary cpu_to_le32()

v2:
1.put <linux/acpi.h> in the include guard

 drivers/net/wireless/ath/ath12k/Makefile |   3 +-
 drivers/net/wireless/ath/ath12k/acpi.c   | 203 +++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h   |  29 ++++
 drivers/net/wireless/ath/ath12k/core.c   |   6 +
 drivers/net/wireless/ath/ath12k/core.h   |   8 +
 drivers/net/wireless/ath/ath12k/hw.c     |  10 ++
 drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
 drivers/net/wireless/ath/ath12k/pci.c    |   6 +
 drivers/net/wireless/ath/ath12k/wmi.c    |  80 +++++++++
 drivers/net/wireless/ath/ath12k/wmi.h    |  20 ++-
 10 files changed, 366 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
 create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h

diff --git a/drivers/net/wireless/ath/ath12k/Makefile b/drivers/net/wireless/ath/ath12k/Makefile
index 62c52e733b5e..a479fe06caac 100644
--- a/drivers/net/wireless/ath/ath12k/Makefile
+++ b/drivers/net/wireless/ath/ath12k/Makefile
@@ -19,7 +19,8 @@ ath12k-y += core.o \
 	    hw.o \
 	    mhi.o \
 	    pci.o \
-	    dp_mon.o
+	    dp_mon.o \
+	    acpi.o
 
 ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
 
diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
new file mode 100644
index 000000000000..384e01748b32
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -0,0 +1,203 @@
+// 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.
+ */
+
+#include "core.h"
+#include "acpi.h"
+#include "debug.h"
+
+static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
+{
+	union acpi_object *obj;
+	acpi_handle root_handle;
+	int ret = 0;
+
+	root_handle = ACPI_HANDLE(ab->dev);
+	if (!root_handle) {
+		ath12k_dbg(ab, ATH12K_DBG_BOOT, "invalid ACPI handler\n");
+		return -EOPNOTSUPP;
+	}
+
+	obj = acpi_evaluate_dsm(root_handle, ab->hw_params->acpi_guid, 0, func,
+				NULL);
+
+	if (!obj) {
+		ath12k_dbg(ab, ATH12K_DBG_BOOT, "ACPI _DSM method invocation failed\n");
+		return -ENOENT;
+	}
+
+	if (obj->type == ACPI_TYPE_INTEGER) {
+		ab->acdata->func_bit = obj->integer.value;
+	} else if (obj->type == ACPI_TYPE_BUFFER) {
+		switch (func) {
+		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_CFG_SIZE) {
+				ath12k_err(ab, "Invalid TAS cfg size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->tas_cfg, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_TAS_DATA_SIZE) {
+				ath12k_err(ab, "Invalid TAS data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->tas_sar_power_table, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
+		}
+	} else {
+		ath12k_err(ab,
+			   "ACPI: DSM method did not return a valid object, type %d\n",
+			   obj->type);
+		ret = -EINVAL;
+	}
+
+out:
+	ACPI_FREE(obj);
+	return ret;
+}
+
+static int ath12k_set_tas_power_limit_data(struct ath12k_base *ab)
+{
+	int ret;
+
+	if (ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
+	    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG) {
+		ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
+							       ab->acdata->tas_sar_power_table);
+		if (ret)
+			ath12k_err(ab, "failed to pass tas data table %d\n", ret);
+	} else {
+		ath12k_err(ab, "the latest tas data is invalid\n");
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+void acpi_dsm_notify(acpi_handle handle, u32 event, void *data)
+{
+	int ret;
+	struct ath12k_base *ab = data;
+
+	if (event == ATH12K_ACPI_NOTIFY_EVENT) {
+		if (ab->acdata->acpi_tas_enable) {
+			ret = ath12k_acpi_dsm_get_data(ab,
+						       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
+			if (ret) {
+				ath12k_err(ab, "failed to update tas data table %d\n", ret);
+				return;
+			}
+
+			ret = ath12k_set_tas_power_limit_data(ab);
+			if (ret)
+				return;
+		}
+	} else {
+		ath12k_err(ab, "unknown acpi notify %u\n", event);
+	}
+}
+
+void ath12k_acpi_remove_notify(struct ath12k_base *ab)
+{
+	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+				   ACPI_DEVICE_NOTIFY,
+				   acpi_dsm_notify);
+}
+
+static int ath12k_pass_acpi_cfg_and_data_to_fw(struct ath12k_base *ab)
+{
+	int ret;
+
+	ret = ath12k_wmi_pdev_set_tas_cfg_table_param(ab,
+						      ab->acdata->tas_cfg);
+	if (ret) {
+		ath12k_err(ab, "failed to pass tas cfg table to fw %d\n", ret);
+		return ret;
+	}
+
+	ret = ath12k_wmi_pdev_set_tas_data_table_param(ab,
+						       ab->acdata->tas_sar_power_table);
+	if (ret)
+		ath12k_err(ab, "failed to pass tas data table to fw %d\n", ret);
+
+	return ret;
+}
+
+int ath12k_get_acpi_all_data(struct ath12k_base *ab)
+{
+	int ret;
+	acpi_status status;
+
+	ab->acdata = kzalloc(sizeof(*ab->acdata), GFP_KERNEL);
+	if (!ab->acdata)
+		return -ENOMEM;
+
+	ab->acdata->acpi_tas_enable = false;
+
+	ret = ath12k_acpi_dsm_get_data(ab,
+				       ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS);
+
+	if (ret)
+		return ret;
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG);
+		if (ret) {
+			ath12k_err(ab, "failed to get tas cfg table %d\n", ret);
+			goto err_free_acdata;
+		}
+	}
+
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_DATA)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA);
+		if (ret) {
+			ath12k_err(ab, "failed to get tas data table %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_TAS_CFG) &&
+		    ab->acdata->tas_sar_power_table[0] == ATH12K_ACPI_TAS_DATA_VERSION &&
+		    ab->acdata->tas_sar_power_table[1] == ATH12K_ACPI_TAS_DATA_ENABLE_FLAG)
+			ab->acdata->acpi_tas_enable = true;
+	}
+
+	if (ab->acdata->acpi_tas_enable) {
+		ret = ath12k_pass_acpi_cfg_and_data_to_fw(ab);
+		if (ret)
+			goto err_free_acdata;
+	}
+
+	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
+					     ACPI_DEVICE_NOTIFY,
+					     acpi_dsm_notify, ab);
+	if (ACPI_FAILURE(status)) {
+		ath12k_err(ab, "failed to install DSM notify callback\n");
+		goto err_remove_notify;
+	}
+
+	return 0;
+
+err_remove_notify:
+	acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+				   ACPI_DEVICE_NOTIFY,
+				   acpi_dsm_notify);
+
+	ret = -EIO;
+
+err_free_acdata:
+	kfree(ab->acdata);
+	ab->acdata = NULL;
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
new file mode 100644
index 000000000000..2331b8e3e035
--- /dev/null
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -0,0 +1,29 @@
+/* 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.
+ */
+#ifndef ATH12K_ACPI_H
+#define ATH12K_ACPI_H
+
+#include <linux/acpi.h>
+
+#define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
+#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
+#define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
+
+#define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
+#define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
+
+#define ATH12K_ACPI_NOTIFY_EVENT			0x86
+#define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
+
+#define ATH12K_ACPI_TAS_DATA_VERSION		0x1
+#define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
+
+#define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
+#define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
+
+int ath12k_get_acpi_all_data(struct ath12k_base *ab);
+void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
+#endif
diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 39f938fafa81..5abef586e3e7 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -538,6 +538,12 @@ static int ath12k_core_start(struct ath12k_base *ab,
 		goto err_reo_cleanup;
 	}
 
+	if (ab->hw_params->acpi_guid) {
+		ret = ath12k_get_acpi_all_data(ab);
+		if (!ret)
+			ath12k_info(ab, "success to get acpi cfg data\n");
+	}
+
 	return 0;
 
 err_reo_cleanup:
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d873b573dac6..cba4f176c018 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -22,6 +22,7 @@
 #include "hal_rx.h"
 #include "reg.h"
 #include "dbring.h"
+#include "acpi.h"
 
 #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
 
@@ -771,6 +772,13 @@ struct ath12k_base {
 	u64 fw_soc_drop_count;
 	bool static_window_map;
 
+	struct {
+		u32 func_bit;
+		bool acpi_tas_enable;
+		u8 tas_cfg[ATH12K_ACPI_DSM_TAS_CFG_SIZE];
+		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
+	} *acdata;
+
 	/* must be last */
 	u8 drv_priv[] __aligned(sizeof(void *));
 };
diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 5991cc91cd00..f0f7f9dbb08a 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -15,6 +15,10 @@
 #include "mhi.h"
 #include "dp_rx.h"
 
+static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec,
+					     0x90, 0xd6, 0x02, 0x42,
+					     0xac, 0x12, 0x00, 0x03);
+
 static u8 ath12k_hw_qcn9274_mac_from_pdev_id(int pdev_idx)
 {
 	return pdev_idx;
@@ -907,6 +911,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.acpi_guid = NULL,
 	},
 	{
 		.name = "wcn7850 hw2.0",
@@ -964,6 +970,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
 					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
+
+		.acpi_guid = &wcn7850_uuid,
 	},
 	{
 		.name = "qcn9274 hw2.0",
@@ -1019,6 +1027,8 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+
+		.acpi_guid = NULL,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e6c4223c283c..ab409e8ae268 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -8,7 +8,7 @@
 #define ATH12K_HW_H
 
 #include <linux/mhi.h>
-
+#include <linux/uuid.h>
 #include "wmi.h"
 #include "hal.h"
 
@@ -186,6 +186,8 @@ struct ath12k_hw_params {
 	const struct hal_ops *hal_ops;
 
 	u64 qmi_cnss_feature_bitmap;
+
+	const guid_t *acpi_guid;
 };
 
 struct ath12k_hw_ops {
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index bd689efa7daa..8284f2ca59b0 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -1340,6 +1340,12 @@ static void ath12k_pci_remove(struct pci_dev *pdev)
 
 	ath12k_hal_srng_deinit(ab);
 	ath12k_ce_free_pipes(ab);
+	if (ab->hw_params->acpi_guid && ab->acdata) {
+		acpi_remove_notify_handler(ACPI_HANDLE(ab->dev),
+					   ACPI_DEVICE_NOTIFY,
+					   acpi_dsm_notify);
+		kfree(ab->acdata);
+	}
 	ath12k_core_free(ab);
 }
 
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index f48ab69e256a..f49f4325edff 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -6918,3 +6918,83 @@ void ath12k_wmi_detach(struct ath12k_base *ab)
 
 	ath12k_wmi_free_dbring_caps(ab);
 }
+
+int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
+					    const u8 *ptas_cfg)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+	int ret;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_CFG_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_CONFIG_TYPE);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_CFG_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, ptas_cfg, ATH12K_ACPI_DSM_TAS_CFG_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
+					     const u8 *ptas_data)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+	int ret;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_TAS_DATA_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TAS_DATA_TYPE);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_TAS_DATA_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, ptas_data, ATH12K_ACPI_DSM_TAS_DATA_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c75a6fa1f7e0..38bbf59fc6b7 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -361,6 +361,7 @@ 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_BIOS_INTERFACE_CMDID = 0x404A,
 	WMI_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_VDEV),
 	WMI_VDEV_DELETE_CMDID,
 	WMI_VDEV_START_REQUEST_CMDID,
@@ -1931,6 +1932,7 @@ enum wmi_tlv_tag {
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
 	WMI_TAG_EHT_RATE_SET = 0x3C4,
+	WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS = 0x3FB,
 	WMI_TAG_MAX
 };
 
@@ -4791,6 +4793,19 @@ struct ath12k_wmi_base {
 	struct ath12k_wmi_target_cap_arg *targ_cap;
 };
 
+struct wmi_pdev_set_bios_interface_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 param_type_id;
+	__le32 length;
+} __packed;
+
+enum bios_param_type {
+	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
+	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
+	WMI_BIOS_PARAM_TYPE_MAX,
+};
+
 #define ATH12K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
@@ -4912,5 +4927,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
 			       struct sk_buff *tmpl);
 int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
 			   enum wmi_host_hw_mode_config_type mode);
-
+int ath12k_wmi_pdev_set_tas_cfg_table_param(struct ath12k_base *ab,
+					    const u8 *ptas_cfg);
+int ath12k_wmi_pdev_set_tas_data_table_param(struct ath12k_base *ab,
+					     const u8 *ptas_data);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Sun Sep 10 01:28:02 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Sun, 10 Sep 2023 16:28:02 +0800
Subject: [PATCH v4 4/4] wifi: ath12k: add set band edge channel power for WCN7850
In-Reply-To: <20230910082802.9198-1-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
Message-ID: <20230910082802.9198-5-quic_lingbok@quicinc.com>

Currently, ath12k does not have the ability to set band edge channel power
for WCN7850. In order to support this, ath12k gets band edge channel power
table in ath12k_acpi_dsm_get_data() function and sets pdev_id and
param_type_id, then finally sends these data and
WMI_PDEV_SET_BIOS_INTERFACE_CMDID to firmware to set band edge channel
power.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v4:
1.revise commit log using imperative voice

v3:
1.remove unnecessary cpu_to_le32()
2.adjust the order of the macros

v2:
no change

 drivers/net/wireless/ath/ath12k/acpi.c | 29 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  5 ++++
 drivers/net/wireless/ath/ath12k/core.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 40 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  3 ++
 5 files changed, 78 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index a9931e17bd17..389b900df170 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -82,6 +82,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE) {
+				ath12k_err(ab, "Invalid BAND EDGE data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->band_edge_power, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -311,6 +321,25 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 		}
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE);
+		if (ret) {
+			ath12k_err(ab, "failed to get band edge channel power %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ab->acdata->band_edge_power[0] == ATH12K_ACPI_BAND_EDGE_VERSION &&
+		    ab->acdata->band_edge_power[1] == ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG) {
+			ret = ath12k_wmi_pdev_set_band_edge_power(ab,
+								  ab->acdata->band_edge_power);
+			if (ret) {
+				ath12k_err(ab, "set band edge channel power failed %d\n", ret);
+				goto err_free_acdata;
+			}
+		}
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index 1f05a68e490b..27f28fc13600 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -14,12 +14,14 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
+#define ATH12K_ACPI_DSM_FUNC_INDEX_BAND_EDGE		10
 
 #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
 #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
 #define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
+#define ATH12K_ACPI_FUNC_BIT_BAND_EDGE_CHAN_POWER	BIT(9)
 
 #define ATH12K_ACPI_NOTIFY_EVENT			0x86
 #define ATH12K_ACPI_FUNC_BIT_VALID(_acdata, _func)	((((_acdata)->func_bit) & (_func)) != 0)
@@ -30,6 +32,8 @@
 #define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
 #define ATH12K_ACPI_CCA_THR_VERSION		0x1
 #define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
+#define ATH12K_ACPI_BAND_EDGE_VERSION		0x1
+#define ATH12K_ACPI_BAND_EDGE_ENABLE_FLAG	0x1
 
 #define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
 #define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET	2
@@ -41,6 +45,7 @@
 #define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
 
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
+#define ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE		100
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
 
 #define ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE (ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET + \
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index d57e2013b0fe..d06c3984aef9 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -781,6 +781,7 @@ struct ath12k_base {
 		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
 		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
 		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
+		u8 band_edge_power[ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 727ce28abd7d..102228229932 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7130,3 +7130,43 @@ int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
 	}
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
+					const u8 *pchan_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, len_aligned;
+
+	len_aligned = roundup(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER);
+	cmd->length = cpu_to_le32(ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pchan_table, ATH12K_ACPI_DSM_BAND_EDGE_DATA_SIZE);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 7607cd7ab699..73d790d405cd 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4808,6 +4808,7 @@ enum bios_param_type {
 	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
 	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
 	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
+	WMI_BIOS_PARAM_TYPE_BANDEDGE_CTL_POWER	=	3,
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
@@ -4955,4 +4956,6 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 					     u8 *pgeo_table);
 int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
 					    u8 *pcca_table);
+int ath12k_wmi_pdev_set_band_edge_power(struct ath12k_base *ab,
+					const u8 *pchan_table);
 #endif
-- 
2.34.1



From quic_lingbok at quicinc.com  Sun Sep 10 01:28:01 2023
From: quic_lingbok at quicinc.com (Lingbo Kong)
Date: Sun, 10 Sep 2023 16:28:01 +0800
Subject: [PATCH v4 3/4] wifi: ath12k: add adjust configuration of CCA threshold value for WCN7850
In-Reply-To: <20230910082802.9198-1-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
Message-ID: <20230910082802.9198-4-quic_lingbok@quicinc.com>

Currently, ath12k does not have the ability to adjust CCA threshold values
to meet the regulatory requirements. In order to support this, ath12k gets
CCA threshold configuration in ath12k_acpi_dsm_get_data() function, then
sets pdev_id and param_type_id and finally sends these data to firmware to
implement the adjustment of the CCA threshold value.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
---
v4:
1.revise commit log using imperative voice

v3:
1.remove unnecessary cpu_to_le32()
2.adjust the order of the macros
3.apply jeff's advice

v2:
no change

 drivers/net/wireless/ath/ath12k/acpi.c | 30 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/acpi.h |  8 ++++++
 drivers/net/wireless/ath/ath12k/core.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c  | 40 ++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h  |  7 +++--
 5 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/acpi.c b/drivers/net/wireless/ath/ath12k/acpi.c
index ae1ce7b99d2d..a9931e17bd17 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.c
+++ b/drivers/net/wireless/ath/ath12k/acpi.c
@@ -72,6 +72,16 @@ static int ath12k_acpi_dsm_get_data(struct ath12k_base *ab, int func)
 			memcpy(&ab->acdata->geo_offset_data, obj->buffer.pointer,
 			       obj->buffer.length);
 			break;
+		case ATH12K_ACPI_DSM_FUNC_INDEX_CCA:
+			if (obj->buffer.length != ATH12K_ACPI_DSM_CCA_DATA_SIZE) {
+				ath12k_err(ab, "Invalid CCA data size %d\n",
+					   obj->buffer.length);
+				ret = -EINVAL;
+				goto out;
+			}
+			memcpy(&ab->acdata->cca_data, obj->buffer.pointer,
+			       obj->buffer.length);
+			break;
 		}
 	} else {
 		ath12k_err(ab,
@@ -281,6 +291,26 @@ int ath12k_get_acpi_all_data(struct ath12k_base *ab)
 			goto err_free_acdata;
 	}
 
+	if (ATH12K_ACPI_FUNC_BIT_VALID(ab->acdata, ATH12K_ACPI_FUNC_BIT_CCA)) {
+		ret = ath12k_acpi_dsm_get_data(ab,
+					       ATH12K_ACPI_DSM_FUNC_INDEX_CCA);
+		if (ret) {
+			ath12k_err(ab, "failed to get cca threshold configuration %d\n", ret);
+			goto err_free_acdata;
+		}
+
+		if (ab->acdata->cca_data[0] == ATH12K_ACPI_CCA_THR_VERSION &&
+		    ab->acdata->cca_data[ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET] ==
+		    ATH12K_ACPI_CCA_THR_ENABLE_FLAG) {
+			ret = ath12k_wmi_pdev_set_cca_thr_table_param(ab,
+								      ab->acdata->cca_data);
+			if (ret) {
+				ath12k_err(ab, "set cca threshold failed %d\n", ret);
+				goto err_free_acdata;
+			}
+		}
+	}
+
 	status = acpi_install_notify_handler(ACPI_HANDLE(ab->dev),
 					     ACPI_DEVICE_NOTIFY,
 					     acpi_dsm_notify, ab);
diff --git a/drivers/net/wireless/ath/ath12k/acpi.h b/drivers/net/wireless/ath/ath12k/acpi.h
index 2f930f0718da..1f05a68e490b 100644
--- a/drivers/net/wireless/ath/ath12k/acpi.h
+++ b/drivers/net/wireless/ath/ath12k/acpi.h
@@ -11,11 +11,13 @@
 #define ATH12K_ACPI_DSM_FUNC_INDEX_SUPPORT_FUNCS	0
 #define ATH12K_ACPI_DSM_FUNC_INDEX_BIOS_SAR             4
 #define ATH12K_ACPI_DSM_FUNC_INDEX_GEO_OFFSET           5
+#define ATH12K_ACPI_DSM_FUNC_INDEX_CCA			6
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_CFG		8
 #define ATH12K_ACPI_DSM_FUNC_INDEX_TAS_DATA		9
 
 #define ATH12K_ACPI_FUNC_BIT_BIOS_SAR			BIT(3)
 #define ATH12K_ACPI_FUNC_BIT_GEO_OFFSET			BIT(4)
+#define ATH12K_ACPI_FUNC_BIT_CCA			BIT(5)
 #define ATH12K_ACPI_FUNC_BIT_TAS_CFG			BIT(7)
 #define ATH12K_ACPI_FUNC_BIT_TAS_DATA			BIT(8)
 
@@ -26,13 +28,17 @@
 #define ATH12K_ACPI_TAS_DATA_ENABLE_FLAG	0x1
 #define ATH12K_ACPI_POWER_LIMIT_VERSION		0x1
 #define ATH12K_ACPI_POWER_LIMIT_ENABLE_FLAG	0x1
+#define ATH12K_ACPI_CCA_THR_VERSION		0x1
+#define ATH12K_ACPI_CCA_THR_ENABLE_FLAG		0x1
 
 #define ATH12K_ACPI_GEO_OFFSET_DATA_OFFSET	1
 #define ATH12K_ACPI_DBS_BACKOFF_DATA_OFFSET	2
+#define ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET	5
 #define ATH12K_ACPI_BIOS_SAR_DBS_BACKOFF_LEN	10
 #define ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET	12
 #define ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN	18
 #define ATH12K_ACPI_BIOS_SAR_TABLE_LEN		22
+#define ATH12K_ACPI_CCA_THR_OFFSET_LEN		36
 
 #define ATH12K_ACPI_DSM_TAS_DATA_SIZE			69
 #define ATH12K_ACPI_DSM_TAS_CFG_SIZE			108
@@ -41,6 +47,8 @@
 					      ATH12K_ACPI_BIOS_SAR_GEO_OFFSET_LEN)
 #define ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE (ATH12K_ACPI_POWER_LIMIT_DATA_OFFSET + \
 					    ATH12K_ACPI_BIOS_SAR_TABLE_LEN)
+#define ATH12K_ACPI_DSM_CCA_DATA_SIZE (ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET + \
+				       ATH12K_ACPI_CCA_THR_OFFSET_LEN)
 
 int ath12k_get_acpi_all_data(struct ath12k_base *ab);
 void acpi_dsm_notify(acpi_handle handle, u32 event, void *data);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 6fe4f0ddee4a..d57e2013b0fe 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -780,6 +780,7 @@ struct ath12k_base {
 		u8 tas_sar_power_table[ATH12K_ACPI_DSM_TAS_DATA_SIZE];
 		u8 bios_sar_data[ATH12K_ACPI_DSM_BIOS_SAR_DATA_SIZE];
 		u8 geo_offset_data[ATH12K_ACPI_DSM_GEO_OFFSET_DATA_SIZE];
+		u8 cca_data[ATH12K_ACPI_DSM_CCA_DATA_SIZE];
 	} *acdata;
 
 	/* must be last */
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 9ad588897b09..727ce28abd7d 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -7090,3 +7090,43 @@ int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 
 	return ret;
 }
+
+int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
+					    u8 *pcca_table)
+{
+	struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
+	struct wmi_pdev_set_bios_interface_cmd *cmd;
+	struct wmi_tlv *tlv;
+	struct sk_buff *skb;
+	int ret;
+	u8 *buf_ptr;
+	u32 len, cca_thr_len_aligned;
+	u8 *pcca_value = pcca_table + ATH12K_ACPI_CCA_THR_OFFSET_DATA_OFFSET;
+
+	cca_thr_len_aligned = roundup(ATH12K_ACPI_CCA_THR_OFFSET_LEN, sizeof(u32));
+	len = sizeof(*cmd) + TLV_HDR_SIZE + cca_thr_len_aligned;
+
+	skb = ath12k_wmi_alloc_skb(wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_pdev_set_bios_interface_cmd *)skb->data;
+	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_PDEV_SET_BIOS_INTERFACE_CMD_PARAMS,
+						 sizeof(*cmd));
+	cmd->pdev_id = cpu_to_le32(WMI_PDEV_ID_SOC);
+	cmd->param_type_id = cpu_to_le32(WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE);
+	cmd->length = ATH12K_ACPI_CCA_THR_OFFSET_LEN;
+
+	buf_ptr = skb->data + sizeof(*cmd);
+	tlv = (struct wmi_tlv *)buf_ptr;
+	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_BYTE, cca_thr_len_aligned);
+	buf_ptr += TLV_HDR_SIZE;
+	memcpy(buf_ptr, pcca_value, ATH12K_ACPI_CCA_THR_OFFSET_LEN);
+
+	ret = ath12k_wmi_cmd_send(&wmi_ab->wmi[0], skb, WMI_PDEV_SET_BIOS_INTERFACE_CMDID);
+	if (ret) {
+		ath12k_warn(ab, "failed to send WMI_PDEV_SET_BIOS_INTERFACE_CMDID %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+	return ret;
+}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 8a774655fe9f..7607cd7ab699 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4805,8 +4805,9 @@ struct wmi_pdev_set_bios_interface_cmd {
 } __packed;
 
 enum bios_param_type {
-	WMI_BIOS_PARAM_TAS_CONFIG_TYPE	=	1,
-	WMI_BIOS_PARAM_TAS_DATA_TYPE	=	2,
+	WMI_BIOS_PARAM_CCA_THRESHOLD_TYPE	=	0,
+	WMI_BIOS_PARAM_TAS_CONFIG_TYPE		=	1,
+	WMI_BIOS_PARAM_TAS_DATA_TYPE		=	2,
 	WMI_BIOS_PARAM_TYPE_MAX,
 };
 
@@ -4952,4 +4953,6 @@ int ath12k_wmi_pdev_set_bios_sar_table_param(struct ath12k_base *ab,
 					     u8 *psar_table);
 int ath12k_wmi_pdev_set_bios_geo_table_param(struct ath12k_base *ab,
 					     u8 *pgeo_table);
+int ath12k_wmi_pdev_set_cca_thr_table_param(struct ath12k_base *ab,
+					    u8 *pcca_table);
 #endif
-- 
2.34.1



From quic_kangyang at quicinc.com  Mon Sep 11 02:30:54 2023
From: quic_kangyang at quicinc.com (Kang Yang)
Date: Mon, 11 Sep 2023 17:30:54 +0800
Subject: [PATCH v2] wifi: ath12k: add msdu_end structure for WCN7850
Message-ID: <20230911093054.74943-1-quic_kangyang@quicinc.com>

WCN7850 and QCN9274 currently use the same structure rx_msdu_end_qcn9274
for msdu_end. But content of msdu_end on WCN7850 is different from that of
QCN9274. Need to update it for WCN7850, otherwise will get the wrong
values when using it.

For example, TID is no longer in WCN7850's msdu_end. But
ath12k_dp_rx_process_err() and ath12k_dp_rx_process_wbm_err() still get
TID from msdu_end. So an uncertain value will be used in these two
functions on WCN7850.

Therefore, add new structure rx_msdu_end_wcn7850 for WCN7850.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Kang Yang <quic_kangyang at quicinc.com>
---

v2:
 1. use different macro names for different contents(Jeff).
 2. add () to function references(Jeff). 

 drivers/net/wireless/ath/ath12k/hal.c     | 12 +--
 drivers/net/wireless/ath/ath12k/rx_desc.h | 91 +++++++++++++++++++----
 2 files changed, 83 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/hal.c b/drivers/net/wireless/ath/ath12k/hal.c
index e7a150e7158e..eca86fc25a60 100644
--- a/drivers/net/wireless/ath/ath12k/hal.c
+++ b/drivers/net/wireless/ath/ath12k/hal.c
@@ -385,13 +385,13 @@ static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc)
 static u8 ath12k_hw_qcn9274_rx_desc_get_msdu_nss(struct hal_rx_desc *desc)
 {
 	return le32_get_bits(desc->u.qcn9274.msdu_end.info12,
-			     RX_MSDU_END_INFO12_MIMO_SS_BITMAP);
+			     RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP);
 }
 
 static u8 ath12k_hw_qcn9274_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc)
 {
 	return le16_get_bits(desc->u.qcn9274.msdu_end.info5,
-			    RX_MSDU_END_INFO5_TID);
+			    RX_MSDU_END_QCN9274_INFO5_TID);
 }
 
 static u16 ath12k_hw_qcn9274_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc)
@@ -819,13 +819,13 @@ static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_pkt_type(struct hal_rx_desc *desc)
 static u8 ath12k_hw_wcn7850_rx_desc_get_msdu_nss(struct hal_rx_desc *desc)
 {
 	return le32_get_bits(desc->u.wcn7850.msdu_end.info12,
-			     RX_MSDU_END_INFO12_MIMO_SS_BITMAP);
+			     RX_MSDU_END_WCN7850_INFO12_MIMO_SS_BITMAP);
 }
 
 static u8 ath12k_hw_wcn7850_rx_desc_get_mpdu_tid(struct hal_rx_desc *desc)
 {
-	return le16_get_bits(desc->u.wcn7850.msdu_end.info5,
-			     RX_MSDU_END_INFO5_TID);
+	return le32_get_bits(desc->u.wcn7850.mpdu_start.info2,
+			     RX_MPDU_START_INFO2_TID);
 }
 
 static u16 ath12k_hw_wcn7850_rx_desc_get_mpdu_peer_id(struct hal_rx_desc *desc)
@@ -837,7 +837,7 @@ static void ath12k_hw_wcn7850_rx_desc_copy_end_tlv(struct hal_rx_desc *fdesc,
 						   struct hal_rx_desc *ldesc)
 {
 	memcpy(&fdesc->u.wcn7850.msdu_end, &ldesc->u.wcn7850.msdu_end,
-	       sizeof(struct rx_msdu_end_qcn9274));
+	       sizeof(struct rx_msdu_end_wcn7850));
 }
 
 static u32 ath12k_hw_wcn7850_rx_desc_get_mpdu_start_tag(struct hal_rx_desc *desc)
diff --git a/drivers/net/wireless/ath/ath12k/rx_desc.h b/drivers/net/wireless/ath/ath12k/rx_desc.h
index bfa87cb8d021..c4058abc516e 100644
--- a/drivers/net/wireless/ath/ath12k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath12k/rx_desc.h
@@ -627,17 +627,18 @@ enum rx_msdu_start_reception_type {
 
 #define RX_MSDU_END_INFO5_SA_IDX_TIMEOUT	BIT(0)
 #define RX_MSDU_END_INFO5_DA_IDX_TIMEOUT	BIT(1)
-#define RX_MSDU_END_INFO5_TO_DS			BIT(2)
-#define RX_MSDU_END_INFO5_TID			GENMASK(6, 3)
 #define RX_MSDU_END_INFO5_SA_IS_VALID		BIT(7)
 #define RX_MSDU_END_INFO5_DA_IS_VALID		BIT(8)
 #define RX_MSDU_END_INFO5_DA_IS_MCBC		BIT(9)
 #define RX_MSDU_END_INFO5_L3_HDR_PADDING	GENMASK(11, 10)
 #define RX_MSDU_END_INFO5_FIRST_MSDU		BIT(12)
 #define RX_MSDU_END_INFO5_LAST_MSDU		BIT(13)
-#define RX_MSDU_END_INFO5_FROM_DS		BIT(14)
 #define RX_MSDU_END_INFO5_IP_CHKSUM_FAIL_COPY	BIT(15)
 
+#define RX_MSDU_END_QCN9274_INFO5_TO_DS         BIT(2)
+#define RX_MSDU_END_QCN9274_INFO5_TID           GENMASK(6, 3)
+#define RX_MSDU_END_QCN9274_INFO5_FROM_DS       BIT(14)
+
 #define RX_MSDU_END_INFO6_MSDU_DROP		BIT(0)
 #define RX_MSDU_END_INFO6_REO_DEST_IND		GENMASK(5, 1)
 #define RX_MSDU_END_INFO6_FLOW_IDX		GENMASK(25, 6)
@@ -650,14 +651,15 @@ enum rx_msdu_start_reception_type {
 #define RX_MSDU_END_INFO7_AGGR_COUNT		GENMASK(7, 0)
 #define RX_MSDU_END_INFO7_FLOW_AGGR_CONTN	BIT(8)
 #define RX_MSDU_END_INFO7_FISA_TIMEOUT		BIT(9)
-#define RX_MSDU_END_INFO7_TCPUDP_CSUM_FAIL_CPY	BIT(10)
-#define RX_MSDU_END_INFO7_MSDU_LIMIT_ERROR	BIT(11)
-#define RX_MSDU_END_INFO7_FLOW_IDX_TIMEOUT	BIT(12)
-#define RX_MSDU_END_INFO7_FLOW_IDX_INVALID	BIT(13)
-#define RX_MSDU_END_INFO7_CCE_MATCH		BIT(14)
-#define RX_MSDU_END_INFO7_AMSDU_PARSER_ERR	BIT(15)
 
-#define RX_MSDU_END_INFO8_KEY_ID		GENMASK(7, 0)
+#define RX_MSDU_END_QCN9274_INFO7_TCPUDP_CSUM_FAIL_CPY	BIT(10)
+#define RX_MSDU_END_QCN9274_INFO7_MSDU_LIMIT_ERROR	BIT(11)
+#define RX_MSDU_END_QCN9274_INFO7_FLOW_IDX_TIMEOUT	BIT(12)
+#define RX_MSDU_END_QCN9274_INFO7_FLOW_IDX_INVALID	BIT(13)
+#define RX_MSDU_END_QCN9274_INFO7_CCE_MATCH		BIT(14)
+#define RX_MSDU_END_QCN9274_INFO7_AMSDU_PARSER_ERR	BIT(15)
+
+#define RX_MSDU_END_QCN9274_INFO8_KEY_ID		GENMASK(7, 0)
 
 #define RX_MSDU_END_INFO9_SERVICE_CODE		GENMASK(14, 6)
 #define RX_MSDU_END_INFO9_PRIORITY_VALID	BIT(15)
@@ -698,8 +700,9 @@ enum rx_msdu_start_reception_type {
 #define RX_MSDU_END_INFO12_RATE_MCS		GENMASK(17, 14)
 #define RX_MSDU_END_INFO12_RECV_BW		GENMASK(20, 18)
 #define RX_MSDU_END_INFO12_RECEPTION_TYPE	GENMASK(23, 21)
-#define RX_MSDU_END_INFO12_MIMO_SS_BITMAP	GENMASK(30, 24)
-#define RX_MSDU_END_INFO12_MIMO_DONE_COPY	BIT(31)
+
+#define RX_MSDU_END_QCN9274_INFO12_MIMO_SS_BITMAP	GENMASK(30, 24)
+#define RX_MSDU_END_QCN9274_INFO12_MIMO_DONE_COPY	BIT(31)
 
 #define RX_MSDU_END_INFO13_FIRST_MPDU		BIT(0)
 #define RX_MSDU_END_INFO13_MCAST_BCAST		BIT(2)
@@ -714,7 +717,6 @@ enum rx_msdu_start_reception_type {
 #define RX_MSDU_END_INFO13_EOSP			BIT(11)
 #define RX_MSDU_END_INFO13_A_MSDU_ERROR		BIT(12)
 #define RX_MSDU_END_INFO13_ORDER		BIT(14)
-#define RX_MSDU_END_INFO13_WIFI_PARSER_ERR	BIT(15)
 #define RX_MSDU_END_INFO13_OVERFLOW_ERR		BIT(16)
 #define RX_MSDU_END_INFO13_MSDU_LEN_ERR		BIT(17)
 #define RX_MSDU_END_INFO13_TCP_UDP_CKSUM_FAIL	BIT(18)
@@ -732,6 +734,8 @@ enum rx_msdu_start_reception_type {
 #define RX_MSDU_END_INFO13_UNDECRYPT_FRAME_ERR	BIT(30)
 #define RX_MSDU_END_INFO13_FCS_ERR		BIT(31)
 
+#define RX_MSDU_END_QCN9274_INFO13_WIFI_PARSER_ERR      BIT(15)
+
 #define RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE	GENMASK(12, 10)
 #define RX_MSDU_END_INFO14_RX_BITMAP_NOT_UPDED	BIT(13)
 #define RX_MSDU_END_INFO14_MSDU_DONE		BIT(31)
@@ -782,6 +786,65 @@ struct rx_msdu_end_qcn9274 {
 	__le32 info14;
 } __packed;
 
+/* These macro definitions are only used for WCN7850 */
+#define RX_MSDU_END_WCN7850_INFO2_KEY_ID			BIT(7, 0)
+
+#define RX_MSDU_END_WCN7850_INFO5_MSDU_LIMIT_ERR		BIT(2)
+#define RX_MSDU_END_WCN7850_INFO5_IDX_TIMEOUT			BIT(3)
+#define RX_MSDU_END_WCN7850_INFO5_IDX_INVALID			BIT(4)
+#define RX_MSDU_END_WCN7850_INFO5_WIFI_PARSE_ERR		BIT(5)
+#define RX_MSDU_END_WCN7850_INFO5_AMSDU_PARSER_ERR		BIT(6)
+#define RX_MSDU_END_WCN7850_INFO5_TCPUDP_CSUM_FAIL_CPY		BIT(14)
+
+#define RX_MSDU_END_WCN7850_INFO12_MIMO_SS_BITMAP		GENMASK(31, 24)
+
+#define RX_MSDU_END_WCN7850_INFO13_FRAGMENT_FLAG		BIT(13)
+#define RX_MSDU_END_WCN7850_INFO13_CCE_MATCH			BIT(15)
+
+struct rx_msdu_end_wcn7850 {
+	__le16 info0;
+	__le16 phy_ppdu_id;
+	__le16 ip_hdr_cksum;
+	__le16 info1;
+	__le16 info2;
+	__le16 cumulative_l3_checksum;
+	__le32 rule_indication0;
+	__le32 rule_indication1;
+	__le16 info3;
+	__le16 l3_type;
+	__le32 ipv6_options_crc;
+	__le32 tcp_seq_num;
+	__le32 tcp_ack_num;
+	__le16 info4;
+	__le16 window_size;
+	__le16 tcp_udp_chksum;
+	__le16 info5;
+	__le16 sa_idx;
+	__le16 da_idx_or_sw_peer_id;
+	__le32 info6;
+	__le32 fse_metadata;
+	__le16 cce_metadata;
+	__le16 sa_sw_peer_id;
+	__le16 info7;
+	__le16 rsvd0;
+	__le16 cumulative_l4_checksum;
+	__le16 cumulative_ip_length;
+	__le32 info9;
+	__le32 info10;
+	__le32 info11;
+	__le32 toeplitz_hash_2_or_4;
+	__le32 flow_id_toeplitz;
+	__le32 info12;
+	__le32 ppdu_start_timestamp_31_0;
+	__le32 ppdu_start_timestamp_63_32;
+	__le32 phy_meta_data;
+	__le16 vlan_ctag_ci;
+	__le16 vlan_stag_ci;
+	__le32 rsvd[3];
+	__le32 info13;
+	__le32 info14;
+} __packed;
+
 /* rx_msdu_end
  *
  * rxpcu_mpdu_filter_in_category
@@ -1410,7 +1473,7 @@ struct rx_pkt_hdr_tlv {
 
 struct hal_rx_desc_wcn7850 {
 	__le64 msdu_end_tag;
-	struct rx_msdu_end_qcn9274 msdu_end;
+	struct rx_msdu_end_wcn7850 msdu_end;
 	u8 rx_padding0[RX_BE_PADDING0_BYTES];
 	__le64 mpdu_start_tag;
 	struct rx_mpdu_start_qcn9274 mpdu_start;
-- 
2.34.1



From quic_jjohnson at quicinc.com  Mon Sep 11 13:53:05 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Mon, 11 Sep 2023 13:53:05 -0700
Subject: [PATCH v2] wifi: ath12k: add msdu_end structure for WCN7850
In-Reply-To: <20230911093054.74943-1-quic_kangyang@quicinc.com>
References: <20230911093054.74943-1-quic_kangyang@quicinc.com>
Message-ID: <c71a6524-2d61-44fd-b918-a0215cfc983a@quicinc.com>

On 9/11/2023 2:30 AM, Kang Yang wrote:
> WCN7850 and QCN9274 currently use the same structure rx_msdu_end_qcn9274
> for msdu_end. But content of msdu_end on WCN7850 is different from that of
> QCN9274. Need to update it for WCN7850, otherwise will get the wrong
> values when using it.
> 
> For example, TID is no longer in WCN7850's msdu_end. But
> ath12k_dp_rx_process_err() and ath12k_dp_rx_process_wbm_err() still get
> TID from msdu_end. So an uncertain value will be used in these two
> functions on WCN7850.
> 
> Therefore, add new structure rx_msdu_end_wcn7850 for WCN7850.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Kang Yang <quic_kangyang at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_jjohnson at quicinc.com  Tue Sep 12 12:10:44 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 12 Sep 2023 12:10:44 -0700
Subject: [PATCH v4 0/4] wifi: ath12k: implement some functionalities
 through reading ACPI Table
In-Reply-To: <20230910082802.9198-1-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
Message-ID: <4f4cc727-4210-47d7-a635-a8cd14a04064@quicinc.com>

On 9/10/2023 1:27 AM, Lingbo Kong wrote:
> Through reading ACPI table, implement Time-Average-SAR(TAS), BIOS SAR,
> configuration of CCA threshold and band edge channel power functionalities.
> 
> v4:
> 1.revise commit log using imperative voice
> 2.delete guid_is_null()
> 
> v3:
> 1.remove unnecessary cpu_to_le32()
> 2.adjust the order of the macros
> 3.apply jeff's advice
> 
> v2:
> 1.put <linux/acpi.h> in the include guard
> 
> Lingbo Kong (4):
>    wifi: ath12k: add TAS capability for WCN7850
>    wifi: ath12k: add BIOS SAR capability for WCN7850
>    wifi: ath12k: add adjust configuration of CCA threshold value for
>      WCN7850
>    wifi: ath12k: add set band edge channel power for WCN7850
> 
>   drivers/net/wireless/ath/ath12k/Makefile |   3 +-
>   drivers/net/wireless/ath/ath12k/acpi.c   | 365 +++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/acpi.h   |  60 ++++
>   drivers/net/wireless/ath/ath12k/core.c   |   6 +
>   drivers/net/wireless/ath/ath12k/core.h   |  13 +
>   drivers/net/wireless/ath/ath12k/hw.c     |  10 +
>   drivers/net/wireless/ath/ath12k/hw.h     |   4 +-
>   drivers/net/wireless/ath/ath12k/pci.c    |   6 +
>   drivers/net/wireless/ath/ath12k/wmi.c    | 252 ++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h    |  47 ++-
>   10 files changed, 763 insertions(+), 3 deletions(-)
>   create mode 100644 drivers/net/wireless/ath/ath12k/acpi.c
>   create mode 100644 drivers/net/wireless/ath/ath12k/acpi.h
> 
> 
> base-commit: 1b5b69a51bb4909844e4003920af09ca1cc6bb0e
For the series

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_jjohnson at quicinc.com  Tue Sep 12 12:31:41 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 12 Sep 2023 12:31:41 -0700
Subject: [PATCH v4 1/4] wifi: ath12k: add TAS capability for WCN7850
In-Reply-To: <20230910082802.9198-2-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
 <20230910082802.9198-2-quic_lingbok@quicinc.com>
Message-ID: <f085c645-a728-4437-a79e-a805ea7c92b5@quicinc.com>

On 9/10/2023 1:27 AM, Lingbo Kong wrote:
> Currently, ath12k does not support Time-Average-SAR(TAS) for WCN7850. In
> order to enable Time-Average-SAR(TAS) for WCN7850, ath12k defines
> ath12k_get_acpi_all_data() function to get TAS configuration and SAR power
> table, then sets pdev_id, param_type_id, and finally sends the TAS
> configuration, SAR power table and WMI_PDEV_SET_BIOS_INTERFACE_CMDID
> command to firmware to implement TAS during the initialization phase.
> Besides, ath12k registers an ACPI event callback so that ACPI can notify
> ath12k to get the updated SAR power table and sends it to firmware when the
> device state is changed.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_jjohnson at quicinc.com  Tue Sep 12 12:32:11 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 12 Sep 2023 12:32:11 -0700
Subject: [PATCH v4 2/4] wifi: ath12k: add BIOS SAR capability for WCN7850
In-Reply-To: <20230910082802.9198-3-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
 <20230910082802.9198-3-quic_lingbok@quicinc.com>
Message-ID: <f05b4485-397a-4758-b0de-c2136bc665ec@quicinc.com>

On 9/10/2023 1:28 AM, Lingbo Kong wrote:
> Currently, ath12k does not support BIOS SAR for WCN7850. In order to enable
> BIOS SAR for WCN7850, ath12k gets BIOS SAR table and GEO offset table in
> ath12k_acpi_dsm_get_data() function, then sets pdev_id, length of data, and
> finally sends these data and WMI_PDEV_SET_BIOS_SAR_TABLE_CMDID and
> WMI_PDEV_SET_BIOS_GEO_TABLE_CMDID to firmware to implement BIOS SAR during
> the initialization phase. Besides, ath12k registers an ACPI event callback
> so that ACPI can notify ath12k to get the updated BIOS SAR table and sends
> it to firmware when the device state is changed.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_jjohnson at quicinc.com  Tue Sep 12 12:32:38 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 12 Sep 2023 12:32:38 -0700
Subject: [PATCH v4 3/4] wifi: ath12k: add adjust configuration of CCA
 threshold value for WCN7850
In-Reply-To: <20230910082802.9198-4-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
 <20230910082802.9198-4-quic_lingbok@quicinc.com>
Message-ID: <4159a107-2231-4e8f-93e5-bd42873f4c14@quicinc.com>

On 9/10/2023 1:28 AM, Lingbo Kong wrote:
> Currently, ath12k does not have the ability to adjust CCA threshold values
> to meet the regulatory requirements. In order to support this, ath12k gets
> CCA threshold configuration in ath12k_acpi_dsm_get_data() function, then
> sets pdev_id and param_type_id and finally sends these data to firmware to
> implement the adjustment of the CCA threshold value.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_jjohnson at quicinc.com  Tue Sep 12 12:32:58 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 12 Sep 2023 12:32:58 -0700
Subject: [PATCH v4 4/4] wifi: ath12k: add set band edge channel power for
 WCN7850
In-Reply-To: <20230910082802.9198-5-quic_lingbok@quicinc.com>
References: <20230910082802.9198-1-quic_lingbok@quicinc.com>
 <20230910082802.9198-5-quic_lingbok@quicinc.com>
Message-ID: <329ef7bc-5184-4fc8-8c59-8036e9d654c6@quicinc.com>

On 9/10/2023 1:28 AM, Lingbo Kong wrote:
> Currently, ath12k does not have the ability to set band edge channel power
> for WCN7850. In order to support this, ath12k gets band edge channel power
> table in ath12k_acpi_dsm_get_data() function and sets pdev_id and
> param_type_id, then finally sends these data and
> WMI_PDEV_SET_BIOS_INTERFACE_CMDID to firmware to set band edge channel
> power.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From johannes at sipsolutions.net  Wed Sep 13 01:55:00 2023
From: johannes at sipsolutions.net (Johannes Berg)
Date: Wed, 13 Sep 2023 10:55:00 +0200
Subject: [PATCH 1/3] wifi: mac80211: add support to allow driver to
 generate local link address for station
In-Reply-To: <20230906103458.24092-2-quic_wgong@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
	 <20230906103458.24092-2-quic_wgong@quicinc.com>
Message-ID: <cd762f33b1c15566237c85f1e265ee8a00006f5c.camel@sipsolutions.net>

On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
> Currently the local link address of all links is random generated by
> eth_random_addr() in mac80211 while connecting to a MLO AP for station
> mode. The MAC address of link is not passed from NL command. The 1st
> link address is generated while authenticate with AP, the other links'
> addresses are generated after assoc success with AP.
> 
> It is not convenient for some driver, reason is, for station mode,
> the interface with its mac address is already created in driver after
> wlan load, it is used for hw scan and non-MLO connection.
> 
> When connecting to MLO AP, driver reuse the interface as the 1st link of
> MLO. If the mac address of the 1st link changed to a new value, then
> driver need to change the mac address and do many synchronous operation
> with firmware. Thus the operation become complex. After MLO disconnect,
> driver need to restore the old mac address, it is also another complex
> operation.
> 
> The hw scan maybe happen through the MLO connection/disconnection. And
> the hw scan uses the 1st link address while MLO connected and uses the
> interface address while MLO is disconnected, this leads hw scan complex.
> 
> Hence add this interface to allow driver to generate the address of each
> link while MLO connection. Then driver could provide the same mac address
> for the 1st link, thus hw scan/NON-MLO connection/1st link of MLO will use
> the same mac address, then operation become easy.

Maybe after all this explanation, all we need is a flag "reuse MLD
address for assoc link"?


> +		ret = drv_generate_link_addr(sdata->local, sdata,
> +					     link_id, link->conf->addr);
> +		if (ret)
> +			eth_random_addr(link->conf->addr);

should probably refactor this into a separate function though.

I'm also not sure how the driver even knows that a link it's being asked
to get the address for *is* the assoc link? Do you want to rely on that
being the first address handed out?

johannes



From johannes at sipsolutions.net  Wed Sep 13 01:58:38 2023
From: johannes at sipsolutions.net (Johannes Berg)
Date: Wed, 13 Sep 2023 10:58:38 +0200
Subject: [PATCH 2/3] wifi: mac80211: add support to allow driver to set
 active link while connection for station
In-Reply-To: <20230906103458.24092-3-quic_wgong@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
	 <20230906103458.24092-3-quic_wgong@quicinc.com>
Message-ID: <4b597bba9dc13c3260f174826de38b4f1bc3bf6e.camel@sipsolutions.net>

On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
> There are 2 fields valid_links and active_links in struct ieee80211_vif
> of mac80211. For station mode, valid_links is always include the bitmap
> of active_links. valid_links stores the bitmap of links which is created
> in mac80211, and mac80211 only indicate the info of links which is existed
> in active_links to driver. Finally, the active_links is the bitmap of
> links which station can interactive with MLO AP it is connected to.
> 
> Currently the active links is always only contain the primary link,
> primary link means the link used by the latest exchange of successful
> (Re)Association Request/Response frames. Then it will always have only
> one link in driver after connected.
> 
> Hence add this ops in struct ieee80211_ops to allow driver to determine
> the active links bit map dynamically while connecting to MLO AP.

This commit log does nothing to address the question "why do we need
this", particularly since we already have
ieee80211_set_active_links(/_async), so the driver can pretty much
immediately enable all the links it wants.

I see no value in this patch whatsoever.

> @@ -166,6 +167,13 @@ static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
>  		WARN_ON(dormant_links);
>  		break;
>  	case NL80211_IFTYPE_STATION:
> +		active_links = drv_calculate_active_links(sdata->local, sdata,
> +							  valid_links & ~dormant_links);
> +		if (active_links) {
> +			sdata->vif.active_links = active_links;
> +			break;
> +		}
> 

I also _really_ don't think this should operate at this low-level
infrastructure.

johannes


From johannes at sipsolutions.net  Wed Sep 13 02:04:26 2023
From: johannes at sipsolutions.net (Johannes Berg)
Date: Wed, 13 Sep 2023 11:04:26 +0200
Subject: [PATCH 3/3] wifi: mac80211: update link RX NSS by
 ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link()
In-Reply-To: <20230906103458.24092-4-quic_wgong@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
	 <20230906103458.24092-4-quic_wgong@quicinc.com>
Message-ID: <e6ea3009c489fae910adbf2e1c766f2d827f287f.camel@sipsolutions.net>

On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
> Currently for MLO connection, only deflink's rx_nss is set to correct
> value. The others links' rx_nss of struct ieee80211_link_sta is
> value 0 in ieee80211_set_associated(), because they are not pass into
> ieee80211_sta_set_rx_nss() in mac80211 except the deflink in
> rate_control_rate_init(). This leads driver get NSS = 0 for other links.
> Add the ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link(),
> then the other links' rx_nss will be set to the correct value.

This is pretty much true, but I also think it's problematic the way you
phrase it. Software rate control is pretty much, at least currently,
_not_ supported for MLO (and I don't really see how to support it, if
firmware picks the link to transmit on, as it probably should).

Thus, I'm not even sure we should be calling rate_control_rate_init().
Clearly we do today, but it's also obviously wrong for everything except
the call to ieee80211_sta_set_rx_nss().

So while I agree that there's a problem with the RX NSS, I disagree that
this patch is the right way to fix it. Yes, it also fairly obviously
fixes the problem, but it just makes an existing design problem worse.

Please change change the overall design here so that
ieee80211_sta_set_rx_nss() isn't related to rate control at all.

johannes



From quic_wgong at quicinc.com  Wed Sep 13 03:51:56 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 13 Sep 2023 06:51:56 -0400
Subject: [PATCH] wifi: ath12k: read country code from SMBIOS for WCN7850
Message-ID: <20230913105156.17618-1-quic_wgong@quicinc.com>

This read the country code from SMBIOS and send the country code
to firmware, firmware will indicate the regulatory domain info of the
country code and then ath12k will use the info.

dmesg:
[ 1242.637253] ath12k_pci 0000:02:00.0: worldwide regdomain setting from SMBIOS
[ 1242.637259] ath12k_pci 0000:02:00.0: bdf variant name not found.
[ 1242.637261] ath12k_pci 0000:02:00.0: SMBIOS bdf variant name not set.
[ 1242.927543] ath12k_pci 0000:02:00.0: set current country pdev id 0 alpha2 00

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
depends on 5 patches in public review: 
Wen Gong:

https://lore.kernel.org/linux-wireless/20230905105637.10230-1-quic_wgong at quicinc.com/
wifi: ath12k: add read variant from SMBIOS for download board data

https://lore.kernel.org/linux-wireless/20230906082948.18452-1-quic_wgong at quicinc.com/
wifi: ath12k: add read variant from SMBIOS for download board data
[PATCH 0/4] wifi: ath12k: add 11d scan offload support and handle country code for WCN7850
  wifi: ath12k: add configure country code for WCN7850
  wifi: ath12k: add 11d scan offload support
  wifi: ath12k: avoid firmware crash when reg set for WCN7850
  wifi: ath12k: store and send country code to firmware after recovery

 drivers/net/wireless/ath/ath12k/core.c | 26 +++++++++++++++++++++++--
 drivers/net/wireless/ath/ath12k/core.h | 27 +++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.c  | 11 +++++++++++
 3 files changed, 61 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 4c4abeba39c8..de9b7604eaa2 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -377,7 +377,7 @@ static void ath12k_core_stop(struct ath12k_base *ab)
 	/* De-Init of components as needed */
 }
 
-static void ath12k_core_check_bdfext(const struct dmi_header *hdr, void *data)
+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;
@@ -399,6 +399,28 @@ static void ath12k_core_check_bdfext(const struct dmi_header *hdr, void *data)
 		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, 0xff00);
+		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;
@@ -438,7 +460,7 @@ static void ath12k_core_check_bdfext(const struct dmi_header *hdr, void *data)
 int ath12k_core_check_smbios(struct ath12k_base *ab)
 {
 	ab->qmi.target.bdf_ext[0] = '\0';
-	dmi_walk(ath12k_core_check_bdfext, ab);
+	dmi_walk(ath12k_core_check_cc_code_bdfext, ab);
 
 	if (ab->qmi.target.bdf_ext[0] == '\0')
 		return -ENODATA;
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 35a3b6357eb5..d35b97520e6d 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -142,9 +142,34 @@ struct ath12k_ext_irq_grp {
 	struct net_device napi_ndev;
 };
 
+enum ath12k_smbios_cc_type {
+	/* disable country code setting from SMBIOS */
+	ATH12K_SMBIOS_CC_DISABLE = 0,
+
+	/* set country code by ANSI country name, based on ISO3166-1 alpha2 */
+	ATH12K_SMBIOS_CC_ISO = 1,
+
+	/* worldwide regdomain */
+	ATH12K_SMBIOS_CC_WW = 2,
+};
+
 struct ath12k_smbios_bdf {
 	struct dmi_header hdr;
-	u32 padding;
+	u8 features_disabled;
+
+	/* enum ath12k_smbios_cc_type */
+	u8 country_code_flag;
+
+	/* To set specific country, you need to set country code
+	 * flag=ATH12K_SMBIOS_CC_ISO first, then if country is United
+	 * States, then country code value = 0x5553 ("US",'U' = 0x55, 'S'=
+	 * 0x53). To set country to INDONESIA, then country code value =
+	 * 0x4944 ("IN", 'I'=0x49, 'D'=0x44). If country code flag =
+	 * ATH12K_SMBIOS_CC_WW, then you can use worldwide regulatory
+	 * setting.
+	 */
+	u16 cc_code;
+
 	u8 bdf_enabled;
 	u8 bdf_ext[];
 } __packed;
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0df154c34f8f..ba292c2873d1 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -7509,6 +7509,17 @@ static int __ath12k_mac_register(struct ath12k *ar)
 		goto err_unregister_hw;
 	}
 
+	if (ar->ab->hw_params->current_cc_support && ab->new_alpha2[0]) {
+		struct wmi_set_current_country_params set_current_param = {};
+
+		memcpy(&set_current_param.alpha2, ab->new_alpha2, 2);
+		memcpy(&ar->alpha2, ab->new_alpha2, 2);
+		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
+		if (ret)
+			ath12k_warn(ar->ab,
+				    "failed set cc code for mac register: %d\n", ret);
+	}
+
 	return 0;
 
 err_unregister_hw:

base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
prerequisite-patch-id: 2ee4ca0fc2ff95861b978c44b2cb04771c927ee1
prerequisite-patch-id: a341b369c2d9f319970dff05a117cc4c6c85c31c
prerequisite-patch-id: 04c82a480f25fa06001c9ff3fb1d30630f9ec82a
prerequisite-patch-id: 9ba56bba555d7c1b7dea4ad394d39d8397e79754
prerequisite-patch-id: 7c1c0cda8e48fee003376e035ac2b472d22cbae9
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep 13 03:55:07 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 13 Sep 2023 06:55:07 -0400
Subject: [PATCH] wifi: ath12k: enable IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for WCN7850
Message-ID: <20230913105507.17675-1-quic_wgong@quicinc.com>

Currently mac80211 will send 3 scan request for each scan of WCN7850, they
are 2.4 GHz/5 GHz/6 GHz band scan. Firmware of WCN7850 will cache the RNR
IE(Reduced Neighbor Report element) which exist in the beacon of 2.4 GHz/5
GHz of the AP which is co-located with 6 GHz, and then use the cache to
scan in 6 GHz band scan if the 6 GHz scan is in the same scan with the 2.4
GHz/5 GHz band, this will helpful to search more AP of 6 GHz. Also it will
decrease the time cost of scan because firmware will use dual-band scan
for the 2.4 GHz/5 GHz, it means the 2.4 GHz and 5 GHz scans are doing
simultaneously.

Set the flag IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for WCN7850 since it
supports 2.4 GHz/5 GHz/6 GHz in a single wiphy/ieee80211_hw.

This does not impact QCN9274, because it is not single_phy, so does not
have 2.4 GHz/5 GHz/6 GHz in the same wiphy, then it does not match the
condition and then IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS will not set for
QCN9274.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/mac.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0f2af2f14ef7..d4dc03dc8d11 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -7232,6 +7232,11 @@ static int __ath12k_mac_register(struct ath12k *ar)
 
 	ar->hw->wiphy->interface_modes = ab->hw_params->interface_modes;
 
+	if (ar->hw->wiphy->bands[NL80211_BAND_2GHZ] &&
+	    ar->hw->wiphy->bands[NL80211_BAND_5GHZ] &&
+	    ar->hw->wiphy->bands[NL80211_BAND_6GHZ])
+		ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS);
+
 	ieee80211_hw_set(ar->hw, SIGNAL_DBM);
 	ieee80211_hw_set(ar->hw, SUPPORTS_PS);
 	ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);

base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_wgong at quicinc.com  Wed Sep 13 03:57:57 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 13 Sep 2023 06:57:57 -0400
Subject: [PATCH] wifi: ath12k: add keep backward compatibility of PHY mode to avoid firmware crash
Message-ID: <20230913105757.17744-1-quic_wgong@quicinc.com>

In a special WCN7855 firmware release the EHT (IEEE 802.11be) support has
been disabled for size reduction. Currently ath12k always enables EHT PHY
mode during vdev start but with the special firmware that will cause a
firmware crash during vdev start in firmware initialisation. This is
because the firmware will use the EHT mode to allocate resources but as
the EHT mode is not available in the firmware, there's an internal
conflict and the firmware will crash.

To fix the crash check the WMI_TLV_SERVICE_11BE flag to see if the firmware
supports EHT. If EHT is not supported downgrade the PHY mode to HE
(IEEE 802.11ax).

This does not impact QCN9274, because WMI_SERVICE_11BE is always enabled
for QCN9274, then eht_cap->has_eht will always set for it, and the logic
of this patch will not take effect and the PHY mode will not down grade
for it.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/mac.c | 65 ++++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/wmi.h |  3 ++
 2 files changed, 66 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0f2af2f14ef7..c72a7028b4b3 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -4553,7 +4553,8 @@ static void ath12k_mac_copy_eht_ppe_thresh(struct ath12k_wmi_ppe_threshold_arg *
 	}
 }
 
-static void ath12k_mac_copy_eht_cap(struct ath12k_band_cap *band_cap,
+static void ath12k_mac_copy_eht_cap(struct ath12k *ar,
+				    struct ath12k_band_cap *band_cap,
 				    struct ieee80211_he_cap_elem *he_cap_elem,
 				    int iftype,
 				    struct ieee80211_sta_eht_cap *eht_cap)
@@ -4561,6 +4562,10 @@ static void ath12k_mac_copy_eht_cap(struct ath12k_band_cap *band_cap,
 	struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem;
 
 	memset(eht_cap, 0, sizeof(struct ieee80211_sta_eht_cap));
+
+	if (!(test_bit(WMI_TLV_SERVICE_11BE, ar->ab->wmi_ab.svc_map)))
+		return;
+
 	eht_cap->has_eht = true;
 	memcpy(eht_cap_elem->mac_cap_info, band_cap->eht_cap_mac_info,
 	       sizeof(eht_cap_elem->mac_cap_info));
@@ -4626,7 +4631,7 @@ static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar,
 			data[idx].he_6ghz_capa.capa =
 				ath12k_mac_setup_he_6ghz_cap(cap, band_cap);
 		}
-		ath12k_mac_copy_eht_cap(band_cap, &he_cap->he_cap_elem, i,
+		ath12k_mac_copy_eht_cap(ar, band_cap, &he_cap->he_cap_elem, i,
 					&data[idx].eht_cap);
 		idx++;
 	}
@@ -5789,6 +5794,59 @@ static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
 	mutex_unlock(&ar->conf_mutex);
 }
 
+static enum wmi_phy_mode
+ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar,
+				     enum wmi_phy_mode mode,
+				     enum nl80211_band band,
+				     enum nl80211_iftype type)
+{
+	struct ieee80211_sta_eht_cap *eht_cap;
+	enum wmi_phy_mode down_mode;
+
+	if (mode < MODE_11BE_EHT20)
+		return mode;
+
+	eht_cap = &ar->mac.iftype[band][type].eht_cap;
+	if (eht_cap->has_eht)
+		return mode;
+
+	switch (mode) {
+	case MODE_11BE_EHT20:
+		down_mode = MODE_11AX_HE20;
+		break;
+	case MODE_11BE_EHT40:
+		down_mode = MODE_11AX_HE40;
+		break;
+	case MODE_11BE_EHT80:
+		down_mode = MODE_11AX_HE80;
+		break;
+	case MODE_11BE_EHT80_80:
+		down_mode = MODE_11AX_HE80_80;
+		break;
+	case MODE_11BE_EHT160:
+	case MODE_11BE_EHT160_160:
+	case MODE_11BE_EHT320:
+		down_mode = MODE_11AX_HE160;
+		break;
+	case MODE_11BE_EHT20_2G:
+		down_mode = MODE_11AX_HE20_2G;
+		break;
+	case MODE_11BE_EHT40_2G:
+		down_mode = MODE_11AX_HE40_2G;
+		break;
+	default:
+		down_mode = mode;
+		break;
+	}
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+		   "mac vdev start phymode %s downgrade to %s\n",
+		   ath12k_mac_phymode_str(mode),
+		   ath12k_mac_phymode_str(down_mode));
+
+	return down_mode;
+}
+
 static int
 ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
 			      const struct cfg80211_chan_def *chandef,
@@ -5814,6 +5872,9 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
 	arg.band_center_freq2 = chandef->center_freq2;
 	arg.mode = ath12k_phymodes[chandef->chan->band][chandef->width];
 
+	arg.mode = ath12k_mac_check_down_grade_phy_mode(ar, arg.mode,
+							chandef->chan->band,
+							arvif->vif->type);
 	arg.min_power = 0;
 	arg.max_power = chandef->chan->max_power * 2;
 	arg.max_reg_power = chandef->chan->max_reg_power * 2;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 8c047a9623f9..d7ab8c3ff177 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2158,6 +2158,9 @@ enum wmi_tlv_service {
 	WMI_MAX_EXT_SERVICE = 256,
 
 	WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281,
+
+	WMI_TLV_SERVICE_11BE = 289,
+
 	WMI_MAX_EXT2_SERVICE,
 };
 

base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_jjohnson at quicinc.com  Wed Sep 13 18:52:48 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Wed, 13 Sep 2023 18:52:48 -0700
Subject: [PATCH] wifi: ath12k: read country code from SMBIOS for WCN7850
In-Reply-To: <20230913105156.17618-1-quic_wgong@quicinc.com>
References: <20230913105156.17618-1-quic_wgong@quicinc.com>
Message-ID: <e0645b4c-4d9c-46b0-85e9-8964d82fb2e9@quicinc.com>

On 9/13/2023 3:51 AM, Wen Gong wrote:
> This read the country code from SMBIOS and send the country code
> to firmware, firmware will indicate the regulatory domain info of the
> country code and then ath12k will use the info.
> 
> dmesg:
> [ 1242.637253] ath12k_pci 0000:02:00.0: worldwide regdomain setting from SMBIOS
> [ 1242.637259] ath12k_pci 0000:02:00.0: bdf variant name not found.
> [ 1242.637261] ath12k_pci 0000:02:00.0: SMBIOS bdf variant name not set.
> [ 1242.927543] ath12k_pci 0000:02:00.0: set current country pdev id 0 alpha2 00
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
> depends on 5 patches in public review:
> Wen Gong:
> 
> https://lore.kernel.org/linux-wireless/20230905105637.10230-1-quic_wgong at quicinc.com/
> wifi: ath12k: add read variant from SMBIOS for download board data
> 
> https://lore.kernel.org/linux-wireless/20230906082948.18452-1-quic_wgong at quicinc.com/
> wifi: ath12k: add read variant from SMBIOS for download board data
> [PATCH 0/4] wifi: ath12k: add 11d scan offload support and handle country code for WCN7850
>    wifi: ath12k: add configure country code for WCN7850
>    wifi: ath12k: add 11d scan offload support
>    wifi: ath12k: avoid firmware crash when reg set for WCN7850
>    wifi: ath12k: store and send country code to firmware after recovery
> 
>   drivers/net/wireless/ath/ath12k/core.c | 26 +++++++++++++++++++++++--
>   drivers/net/wireless/ath/ath12k/core.h | 27 +++++++++++++++++++++++++-
>   drivers/net/wireless/ath/ath12k/mac.c  | 11 +++++++++++
>   3 files changed, 61 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index 4c4abeba39c8..de9b7604eaa2 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -377,7 +377,7 @@ static void ath12k_core_stop(struct ath12k_base *ab)
>   	/* De-Init of components as needed */
>   }
>   
> -static void ath12k_core_check_bdfext(const struct dmi_header *hdr, void *data)
> +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;
> @@ -399,6 +399,28 @@ static void ath12k_core_check_bdfext(const struct dmi_header *hdr, void *data)
>   		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, 0xff00);
> +		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;
> @@ -438,7 +460,7 @@ static void ath12k_core_check_bdfext(const struct dmi_header *hdr, void *data)
>   int ath12k_core_check_smbios(struct ath12k_base *ab)
>   {
>   	ab->qmi.target.bdf_ext[0] = '\0';
> -	dmi_walk(ath12k_core_check_bdfext, ab);
> +	dmi_walk(ath12k_core_check_cc_code_bdfext, ab);
>   
>   	if (ab->qmi.target.bdf_ext[0] == '\0')
>   		return -ENODATA;
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 35a3b6357eb5..d35b97520e6d 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -142,9 +142,34 @@ struct ath12k_ext_irq_grp {
>   	struct net_device napi_ndev;
>   };
>   
> +enum ath12k_smbios_cc_type {
> +	/* disable country code setting from SMBIOS */
> +	ATH12K_SMBIOS_CC_DISABLE = 0,
> +
> +	/* set country code by ANSI country name, based on ISO3166-1 alpha2 */
> +	ATH12K_SMBIOS_CC_ISO = 1,
> +
> +	/* worldwide regdomain */
> +	ATH12K_SMBIOS_CC_WW = 2,
> +};
> +
>   struct ath12k_smbios_bdf {
>   	struct dmi_header hdr;
> -	u32 padding;
> +	u8 features_disabled;
> +
> +	/* enum ath12k_smbios_cc_type */
> +	u8 country_code_flag;
> +
> +	/* To set specific country, you need to set country code
> +	 * flag=ATH12K_SMBIOS_CC_ISO first, then if country is United
> +	 * States, then country code value = 0x5553 ("US",'U' = 0x55, 'S'=
> +	 * 0x53). To set country to INDONESIA, then country code value =
> +	 * 0x4944 ("IN", 'I'=0x49, 'D'=0x44). If country code flag =
> +	 * ATH12K_SMBIOS_CC_WW, then you can use worldwide regulatory
> +	 * setting.
> +	 */
> +	u16 cc_code;
> +
>   	u8 bdf_enabled;
>   	u8 bdf_ext[];
>   } __packed;
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 0df154c34f8f..ba292c2873d1 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -7509,6 +7509,17 @@ static int __ath12k_mac_register(struct ath12k *ar)
>   		goto err_unregister_hw;
>   	}
>   
> +	if (ar->ab->hw_params->current_cc_support && ab->new_alpha2[0]) {
> +		struct wmi_set_current_country_params set_current_param = {};
> +
> +		memcpy(&set_current_param.alpha2, ab->new_alpha2, 2);
> +		memcpy(&ar->alpha2, ab->new_alpha2, 2);
> +		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
> +		if (ret)
> +			ath12k_warn(ar->ab,
> +				    "failed set cc code for mac register: %d\n", ret);
> +	}
> +
>   	return 0;
>   
>   err_unregister_hw:
> 
> base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
> prerequisite-patch-id: 2ee4ca0fc2ff95861b978c44b2cb04771c927ee1
> prerequisite-patch-id: a341b369c2d9f319970dff05a117cc4c6c85c31c
> prerequisite-patch-id: 04c82a480f25fa06001c9ff3fb1d30630f9ec82a
> prerequisite-patch-id: 9ba56bba555d7c1b7dea4ad394d39d8397e79754
> prerequisite-patch-id: 7c1c0cda8e48fee003376e035ac2b472d22cbae9



From quic_jjohnson at quicinc.com  Wed Sep 13 18:52:57 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Wed, 13 Sep 2023 18:52:57 -0700
Subject: [PATCH] wifi: ath12k: enable
 IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for WCN7850
In-Reply-To: <20230913105507.17675-1-quic_wgong@quicinc.com>
References: <20230913105507.17675-1-quic_wgong@quicinc.com>
Message-ID: <6a519ccd-823b-4dd1-a3dd-32752dfeccd3@quicinc.com>

On 9/13/2023 3:55 AM, Wen Gong wrote:
> Currently mac80211 will send 3 scan request for each scan of WCN7850, they
> are 2.4 GHz/5 GHz/6 GHz band scan. Firmware of WCN7850 will cache the RNR
> IE(Reduced Neighbor Report element) which exist in the beacon of 2.4 GHz/5
> GHz of the AP which is co-located with 6 GHz, and then use the cache to
> scan in 6 GHz band scan if the 6 GHz scan is in the same scan with the 2.4
> GHz/5 GHz band, this will helpful to search more AP of 6 GHz. Also it will
> decrease the time cost of scan because firmware will use dual-band scan
> for the 2.4 GHz/5 GHz, it means the 2.4 GHz and 5 GHz scans are doing
> simultaneously.
> 
> Set the flag IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for WCN7850 since it
> supports 2.4 GHz/5 GHz/6 GHz in a single wiphy/ieee80211_hw.
> 
> This does not impact QCN9274, because it is not single_phy, so does not
> have 2.4 GHz/5 GHz/6 GHz in the same wiphy, then it does not match the
> condition and then IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS will not set for
> QCN9274.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
>   drivers/net/wireless/ath/ath12k/mac.c | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 0f2af2f14ef7..d4dc03dc8d11 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -7232,6 +7232,11 @@ static int __ath12k_mac_register(struct ath12k *ar)
>   
>   	ar->hw->wiphy->interface_modes = ab->hw_params->interface_modes;
>   
> +	if (ar->hw->wiphy->bands[NL80211_BAND_2GHZ] &&
> +	    ar->hw->wiphy->bands[NL80211_BAND_5GHZ] &&
> +	    ar->hw->wiphy->bands[NL80211_BAND_6GHZ])
> +		ieee80211_hw_set(ar->hw, SINGLE_SCAN_ON_ALL_BANDS);
> +
>   	ieee80211_hw_set(ar->hw, SIGNAL_DBM);
>   	ieee80211_hw_set(ar->hw, SUPPORTS_PS);
>   	ieee80211_hw_set(ar->hw, SUPPORTS_DYNAMIC_PS);
> 
> base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e



From quic_jjohnson at quicinc.com  Wed Sep 13 18:53:05 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Wed, 13 Sep 2023 18:53:05 -0700
Subject: [PATCH] wifi: ath12k: add keep backward compatibility of PHY mode
 to avoid firmware crash
In-Reply-To: <20230913105757.17744-1-quic_wgong@quicinc.com>
References: <20230913105757.17744-1-quic_wgong@quicinc.com>
Message-ID: <bdfbb540-aceb-45d2-a0fc-aeee61b0a9c4@quicinc.com>

On 9/13/2023 3:57 AM, Wen Gong wrote:
> In a special WCN7855 firmware release the EHT (IEEE 802.11be) support has
> been disabled for size reduction. Currently ath12k always enables EHT PHY
> mode during vdev start but with the special firmware that will cause a
> firmware crash during vdev start in firmware initialisation. This is
> because the firmware will use the EHT mode to allocate resources but as
> the EHT mode is not available in the firmware, there's an internal
> conflict and the firmware will crash.
> 
> To fix the crash check the WMI_TLV_SERVICE_11BE flag to see if the firmware
> supports EHT. If EHT is not supported downgrade the PHY mode to HE
> (IEEE 802.11ax).
> 
> This does not impact QCN9274, because WMI_SERVICE_11BE is always enabled
> for QCN9274, then eht_cap->has_eht will always set for it, and the logic
> of this patch will not take effect and the PHY mode will not down grade
> for it.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

> ---
>   drivers/net/wireless/ath/ath12k/mac.c | 65 ++++++++++++++++++++++++++-
>   drivers/net/wireless/ath/ath12k/wmi.h |  3 ++
>   2 files changed, 66 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 0f2af2f14ef7..c72a7028b4b3 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -4553,7 +4553,8 @@ static void ath12k_mac_copy_eht_ppe_thresh(struct ath12k_wmi_ppe_threshold_arg *
>   	}
>   }
>   
> -static void ath12k_mac_copy_eht_cap(struct ath12k_band_cap *band_cap,
> +static void ath12k_mac_copy_eht_cap(struct ath12k *ar,
> +				    struct ath12k_band_cap *band_cap,
>   				    struct ieee80211_he_cap_elem *he_cap_elem,
>   				    int iftype,
>   				    struct ieee80211_sta_eht_cap *eht_cap)
> @@ -4561,6 +4562,10 @@ static void ath12k_mac_copy_eht_cap(struct ath12k_band_cap *band_cap,
>   	struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem;
>   
>   	memset(eht_cap, 0, sizeof(struct ieee80211_sta_eht_cap));
> +
> +	if (!(test_bit(WMI_TLV_SERVICE_11BE, ar->ab->wmi_ab.svc_map)))
> +		return;
> +
>   	eht_cap->has_eht = true;
>   	memcpy(eht_cap_elem->mac_cap_info, band_cap->eht_cap_mac_info,
>   	       sizeof(eht_cap_elem->mac_cap_info));
> @@ -4626,7 +4631,7 @@ static int ath12k_mac_copy_sband_iftype_data(struct ath12k *ar,
>   			data[idx].he_6ghz_capa.capa =
>   				ath12k_mac_setup_he_6ghz_cap(cap, band_cap);
>   		}
> -		ath12k_mac_copy_eht_cap(band_cap, &he_cap->he_cap_elem, i,
> +		ath12k_mac_copy_eht_cap(ar, band_cap, &he_cap->he_cap_elem, i,
>   					&data[idx].eht_cap);
>   		idx++;
>   	}
> @@ -5789,6 +5794,59 @@ static void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
>   	mutex_unlock(&ar->conf_mutex);
>   }
>   
> +static enum wmi_phy_mode
> +ath12k_mac_check_down_grade_phy_mode(struct ath12k *ar,
> +				     enum wmi_phy_mode mode,
> +				     enum nl80211_band band,
> +				     enum nl80211_iftype type)
> +{
> +	struct ieee80211_sta_eht_cap *eht_cap;
> +	enum wmi_phy_mode down_mode;
> +
> +	if (mode < MODE_11BE_EHT20)
> +		return mode;
> +
> +	eht_cap = &ar->mac.iftype[band][type].eht_cap;
> +	if (eht_cap->has_eht)
> +		return mode;
> +
> +	switch (mode) {
> +	case MODE_11BE_EHT20:
> +		down_mode = MODE_11AX_HE20;
> +		break;
> +	case MODE_11BE_EHT40:
> +		down_mode = MODE_11AX_HE40;
> +		break;
> +	case MODE_11BE_EHT80:
> +		down_mode = MODE_11AX_HE80;
> +		break;
> +	case MODE_11BE_EHT80_80:
> +		down_mode = MODE_11AX_HE80_80;
> +		break;
> +	case MODE_11BE_EHT160:
> +	case MODE_11BE_EHT160_160:
> +	case MODE_11BE_EHT320:
> +		down_mode = MODE_11AX_HE160;
> +		break;
> +	case MODE_11BE_EHT20_2G:
> +		down_mode = MODE_11AX_HE20_2G;
> +		break;
> +	case MODE_11BE_EHT40_2G:
> +		down_mode = MODE_11AX_HE40_2G;
> +		break;
> +	default:
> +		down_mode = mode;
> +		break;
> +	}
> +
> +	ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
> +		   "mac vdev start phymode %s downgrade to %s\n",
> +		   ath12k_mac_phymode_str(mode),
> +		   ath12k_mac_phymode_str(down_mode));
> +
> +	return down_mode;
> +}
> +
>   static int
>   ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>   			      const struct cfg80211_chan_def *chandef,
> @@ -5814,6 +5872,9 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>   	arg.band_center_freq2 = chandef->center_freq2;
>   	arg.mode = ath12k_phymodes[chandef->chan->band][chandef->width];
>   
> +	arg.mode = ath12k_mac_check_down_grade_phy_mode(ar, arg.mode,
> +							chandef->chan->band,
> +							arvif->vif->type);
>   	arg.min_power = 0;
>   	arg.max_power = chandef->chan->max_power * 2;
>   	arg.max_reg_power = chandef->chan->max_reg_power * 2;
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 8c047a9623f9..d7ab8c3ff177 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -2158,6 +2158,9 @@ enum wmi_tlv_service {
>   	WMI_MAX_EXT_SERVICE = 256,
>   
>   	WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281,
> +
> +	WMI_TLV_SERVICE_11BE = 289,
> +
>   	WMI_MAX_EXT2_SERVICE,
>   };
>   
> 
> base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e



From yunchuan at nfschina.com  Wed Sep 13 21:03:16 2023
From: yunchuan at nfschina.com (Wu Yunchuan)
Date: Thu, 14 Sep 2023 12:03:16 +0800
Subject: [PATCH wireless-next 0/9] Remove unnecessary (void*) conversions
Message-ID: <20230914040315.1169121-1-yunchuan@nfschina.com>

Remove all unnecessary (void*) conversions under the directory drivers/net/wireless/ath.

Wu Yunchuan (9):
  wifi: ar5523: Remove unnecessary (void*) conversions
  carl9170: remove unnecessary (void*) conversions
  wifi: wcn36xx: remove unnecessary (void*) conversions
  wifi: ath5k: remove unnecessary (void*) conversions
  ath6kl: remove unnecessary (void*) conversions
  wifi: ath10k: Remove unnecessary (void*) conversions
  wifi: ath12k: Remove unnecessary (void*) conversions
  wifi: ath11k: remove unnecessary (void*) conversions
  wifi: ath9k: Remove unnecessary (void*) conversions

 drivers/net/wireless/ath/ar5523/ar5523.c      |  2 +-
 drivers/net/wireless/ath/ath10k/htt_tx.c      |  6 ++--
 drivers/net/wireless/ath/ath11k/dp.c          |  2 +-
 drivers/net/wireless/ath/ath11k/dp_rx.c       | 13 +++----
 drivers/net/wireless/ath/ath11k/hal.c         |  8 ++---
 drivers/net/wireless/ath/ath11k/hal_rx.c      | 17 ++++-----
 drivers/net/wireless/ath/ath11k/hal_tx.c      |  2 +-
 drivers/net/wireless/ath/ath11k/mac.c         |  4 +--
 drivers/net/wireless/ath/ath11k/spectral.c    |  2 +-
 drivers/net/wireless/ath/ath11k/wmi.c         |  6 ++--
 drivers/net/wireless/ath/ath12k/dp_mon.c      |  6 ++--
 drivers/net/wireless/ath/ath12k/dp_rx.c       |  2 +-
 drivers/net/wireless/ath/ath12k/dp_tx.c       |  2 +-
 drivers/net/wireless/ath/ath5k/base.c         |  4 +--
 drivers/net/wireless/ath/ath5k/pci.c          |  4 +--
 drivers/net/wireless/ath/ath6kl/main.c        |  4 +--
 drivers/net/wireless/ath/ath6kl/txrx.c        |  2 +-
 .../wireless/ath/ath9k/ath9k_pci_owl_loader.c |  2 +-
 drivers/net/wireless/ath/ath9k/common-init.c  |  2 +-
 .../net/wireless/ath/ath9k/common-spectral.c  |  2 +-
 drivers/net/wireless/ath/ath9k/debug.c        |  2 +-
 drivers/net/wireless/ath/ath9k/hif_usb.c      | 10 +++---
 .../net/wireless/ath/ath9k/htc_drv_debug.c    |  2 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c | 36 +++++++++----------
 drivers/net/wireless/ath/ath9k/htc_hst.c      |  2 +-
 drivers/net/wireless/ath/ath9k/init.c         | 12 +++----
 drivers/net/wireless/ath/ath9k/link.c         |  2 +-
 drivers/net/wireless/ath/ath9k/pci.c          |  6 ++--
 drivers/net/wireless/ath/carl9170/usb.c       | 10 +++---
 drivers/net/wireless/ath/wcn36xx/dxe.c        |  6 ++--
 drivers/net/wireless/ath/wcn36xx/smd.c        | 20 +++++------
 drivers/net/wireless/ath/wcn36xx/testmode.c   |  2 +-
 32 files changed, 95 insertions(+), 107 deletions(-)

-- 
2.30.2



From yunchuan at nfschina.com  Wed Sep 13 21:05:25 2023
From: yunchuan at nfschina.com (Wu Yunchuan)
Date: Thu, 14 Sep 2023 12:05:25 +0800
Subject: [PATCH wireless-next 7/9] wifi: ath12k: Remove unnecessary (void*) conversions
Message-ID: <20230914040525.1170102-1-yunchuan@nfschina.com>

No need cast (void*) to (struct hal_rx_ppdu_end_user_stats *),
(struct ath12k_rx_desc_info *) or (struct hal_tx_msdu_ext_desc *).

Signed-off-by: Wu Yunchuan <yunchuan at nfschina.com>
---
 drivers/net/wireless/ath/ath12k/dp_mon.c | 6 ++----
 drivers/net/wireless/ath/ath12k/dp_rx.c  | 2 +-
 drivers/net/wireless/ath/ath12k/dp_tx.c  | 2 +-
 3 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index f1e57e98bdc6..41cfe7bd865f 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -13,8 +13,7 @@
 static void ath12k_dp_mon_rx_handle_ofdma_info(void *rx_tlv,
 					       struct hal_rx_user_status *rx_user_status)
 {
-	struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
-				(struct hal_rx_ppdu_end_user_stats *)rx_tlv;
+	struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
 
 	rx_user_status->ul_ofdma_user_v0_word0 =
 		__le32_to_cpu(ppdu_end_user->usr_resp_ref);
@@ -26,8 +25,7 @@ static void
 ath12k_dp_mon_rx_populate_byte_count(void *rx_tlv, void *ppduinfo,
 				     struct hal_rx_user_status *rx_user_status)
 {
-	struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
-		(struct hal_rx_ppdu_end_user_stats *)rx_tlv;
+	struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
 	u32 mpdu_ok_byte_count = __le32_to_cpu(ppdu_end_user->mpdu_ok_cnt);
 	u32 mpdu_err_byte_count = __le32_to_cpu(ppdu_end_user->mpdu_err_cnt);
 
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index e6e64d437c47..ff5f66ca7783 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -3730,7 +3730,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
 			continue;
 		}
 
-		desc_info = (struct ath12k_rx_desc_info *)err_info.rx_desc;
+		desc_info = err_info.rx_desc;
 
 		/* retry manual desc retrieval if hw cc is not done */
 		if (!desc_info) {
diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
index 8874c815d7fa..98ddf46b3bb9 100644
--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
@@ -109,7 +109,7 @@ static struct ath12k_tx_desc_info *ath12k_dp_tx_assign_buffer(struct ath12k_dp *
 static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab, void *cmd,
 					     struct hal_tx_info *ti)
 {
-	struct hal_tx_msdu_ext_desc *tcl_ext_cmd = (struct hal_tx_msdu_ext_desc *)cmd;
+	struct hal_tx_msdu_ext_desc *tcl_ext_cmd = cmd;
 
 	tcl_ext_cmd->info0 = le32_encode_bits(ti->paddr,
 					      HAL_TX_MSDU_EXT_INFO0_BUF_PTR_LO);
-- 
2.30.2



From quic_wgong at quicinc.com  Thu Sep 14 02:07:42 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Thu, 14 Sep 2023 05:07:42 -0400
Subject: [PATCH v2 0/4] wifi: ath12k: add 11d scan offload support and handle country code for WCN7850
Message-ID: <20230914090746.23560-1-quic_wgong@quicinc.com>

v2: change per Jeff.
    1. change alpha2 length from 3 to 2.
    2. change wmi_11d_new_cc_ev to wmi_11d_new_cc_event.

Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID which is needed for 
11d scan offload to firmware. And add support for 11d scan offload for 
WCN7850.

Also fix firmware crash for country code set for WCN7850 and store country
code for device recovery for WCN7850.

Wen Gong (4):
  wifi: ath12k: add configure country code for WCN7850
  wifi: ath12k: add 11d scan offload support
  wifi: ath12k: avoid firmware crash when reg set for WCN7850
  wifi: ath12k: store and send country code to firmware after recovery

 drivers/net/wireless/ath/ath12k/core.c |  36 ++++-
 drivers/net/wireless/ath/ath12k/core.h |  17 +++
 drivers/net/wireless/ath/ath12k/hw.c   |   3 +
 drivers/net/wireless/ath/ath12k/hw.h   |   1 +
 drivers/net/wireless/ath/ath12k/mac.c  | 178 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h  |   7 +
 drivers/net/wireless/ath/ath12k/reg.c  |  67 ++++++++--
 drivers/net/wireless/ath/ath12k/reg.h  |   3 +-
 drivers/net/wireless/ath/ath12k/wmi.c  | 159 +++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/wmi.h  |  38 ++++++
 10 files changed, 489 insertions(+), 20 deletions(-)


base-commit: 3f257461ab0ab19806bae2bfde4c3cd88dbf050e
-- 
2.40.1



From quic_wgong at quicinc.com  Thu Sep 14 02:07:44 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Thu, 14 Sep 2023 05:07:44 -0400
Subject: [PATCH v2 2/4] wifi: ath12k: add 11d scan offload support
In-Reply-To: <20230914090746.23560-1-quic_wgong@quicinc.com>
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
Message-ID: <20230914090746.23560-3-quic_wgong@quicinc.com>

Add handler for WMI_11D_NEW_COUNTRY_EVENTID, WMI_11D_SCAN_START_CMDID,
WMI_11D_SCAN_STOP_CMDID.

The priority of 11d scan WMI_SCAN_PRIORITY_MEDIUM in firmware, the
priority of hw scan is WMI_SCAN_PRIORITY_LOW, then the 11d scan will
cancel the hw scan which is running. To avoid this, change the priority
of the 1st hw scan to WMI_SCAN_PRIORITY_MEDIUM. Add wait_for_completion_timeout
for ar->scan.completed in ath12k_reg_update_chan_list(), plus the existing
wait in ath12k_scan_stop(), then ath12k have 2 place to wait the
ar->scan.completed, they run in different thread, thus it is possible to
happen that the two threads both enter wait status. To handle this scenario,
ath12k should change the complete() to complete_all() for the ar->scan.completed,
this also work well when it is only one thread wait for ar->scan.completed.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c |  35 ++++-
 drivers/net/wireless/ath/ath12k/core.h |  16 +++
 drivers/net/wireless/ath/ath12k/mac.c  | 170 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h  |   7 +
 drivers/net/wireless/ath/ath12k/reg.c  |  37 +++++-
 drivers/net/wireless/ath/ath12k/reg.h  |   3 +-
 drivers/net/wireless/ath/ath12k/wmi.c  | 123 +++++++++++++++++-
 drivers/net/wireless/ath/ath12k/wmi.h  |  25 ++++
 8 files changed, 406 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 3df8059d5512..71450dc1f48d 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -668,6 +668,7 @@ void ath12k_core_halt(struct ath12k *ar)
 	ath12k_mac_peer_cleanup_all(ar);
 	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->regd_update_work);
+	cancel_work_sync(&ab->update_11d_work);
 
 	rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);
 	synchronize_rcu();
@@ -675,6 +676,34 @@ void ath12k_core_halt(struct ath12k *ar)
 	idr_init(&ar->txmgmt_idr);
 }
 
+static void ath12k_update_11d(struct work_struct *work)
+{
+	struct ath12k_base *ab = container_of(work, struct ath12k_base, update_11d_work);
+	struct ath12k *ar;
+	struct ath12k_pdev *pdev;
+	struct wmi_set_current_country_params set_current_param = {};
+	int ret, i;
+
+	spin_lock_bh(&ab->base_lock);
+	memcpy(&set_current_param.alpha2, &ab->new_alpha2, 2);
+	spin_unlock_bh(&ab->base_lock);
+
+	ath12k_dbg(ab, ATH12K_DBG_WMI, "update 11d new cc %c%c\n",
+		   set_current_param.alpha2[0],
+		   set_current_param.alpha2[1]);
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+
+		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
+		if (ret)
+			ath12k_warn(ar->ab,
+				    "pdev id %d failed set current country code: %d\n",
+				    i, ret);
+	}
+}
+
 static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
 {
 	struct ath12k *ar;
@@ -693,8 +722,10 @@ static void ath12k_core_pre_reconfigure_recovery(struct ath12k_base *ab)
 
 		ieee80211_stop_queues(ar->hw);
 		ath12k_mac_drain_tx(ar);
+		ar->state_11d = ATH12K_11D_IDLE;
+		complete(&ar->completed_11d_scan);
 		complete(&ar->scan.started);
-		complete(&ar->scan.completed);
+		complete_all(&ar->scan.completed);
 		complete(&ar->peer_assoc_done);
 		complete(&ar->peer_delete_done);
 		complete(&ar->install_key_done);
@@ -913,6 +944,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 
 	mutex_init(&ab->core_lock);
 	spin_lock_init(&ab->base_lock);
+	mutex_init(&ab->vdev_id_11d_lock);
 	init_completion(&ab->reset_complete);
 	init_completion(&ab->reconfigure_complete);
 	init_completion(&ab->recovery_start);
@@ -921,6 +953,7 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
 	init_waitqueue_head(&ab->peer_mapping_wq);
 	init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
 	INIT_WORK(&ab->restart_work, ath12k_core_restart);
+	INIT_WORK(&ab->update_11d_work, ath12k_update_11d);
 	INIT_WORK(&ab->reset_work, ath12k_core_reset);
 	timer_setup(&ab->rx_replenish_retry, ath12k_ce_rx_replenish_retry, 0);
 	init_completion(&ab->htc_suspend);
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 4389ff40b49d..e739869ded73 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -36,6 +36,8 @@
 #define	ATH12K_RX_RATE_TABLE_NUM	320
 #define	ATH12K_RX_RATE_TABLE_11AX_NUM	576
 
+#define ATH12K_SCAN_TIMEOUT_HZ (20 * HZ)
+
 #define ATH12K_MON_TIMER_INTERVAL  10
 #define ATH12K_RESET_TIMEOUT_HZ			(20 * HZ)
 #define ATH12K_RESET_MAX_FAIL_COUNT_FIRST	3
@@ -171,6 +173,12 @@ enum ath12k_scan_state {
 	ATH12K_SCAN_ABORTING,
 };
 
+enum ath12k_11d_state {
+	ATH12K_11D_IDLE,
+	ATH12K_11D_PREPARING,
+	ATH12K_11D_RUNNING,
+};
+
 enum ath12k_dev_flags {
 	ATH12K_CAC_RUNNING,
 	ATH12K_FLAG_CRASH_FLUSH,
@@ -570,6 +578,10 @@ struct ath12k {
 	bool monitor_vdev_created;
 	bool monitor_started;
 	int monitor_vdev_id;
+	u32 vdev_id_11d_scan;
+	struct completion completed_11d_scan;
+	enum ath12k_11d_state state_11d;
+	bool regdom_set_by_user;
 };
 
 struct ath12k_band_cap {
@@ -755,6 +767,10 @@ struct ath12k_base {
 	/* continuous recovery fail count */
 	atomic_t fail_cont_count;
 	unsigned long reset_fail_timeout;
+	struct work_struct update_11d_work;
+	u8 new_alpha2[2];
+	/* To synchronize 11d scan vdev id */
+	struct mutex vdev_id_11d_lock;
 	struct {
 		/* protected by data_lock */
 		u32 fw_crash_counter;
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0f2af2f14ef7..740e8045a6f1 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2354,6 +2354,11 @@ static void ath12k_bss_assoc(struct ieee80211_hw *hw,
 	if (ret)
 		ath12k_warn(ar->ab, "failed to set vdev %i OBSS PD parameters: %d\n",
 			    arvif->vdev_id, ret);
+
+	if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map) &&
+	    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
+		ath12k_mac_11d_scan_stop_all(ar->ab);
 }
 
 static void ath12k_bss_disassoc(struct ieee80211_hw *hw,
@@ -2796,7 +2801,7 @@ void __ath12k_mac_scan_finish(struct ath12k *ar)
 		ar->scan_channel = NULL;
 		ar->scan.roc_freq = 0;
 		cancel_delayed_work(&ar->scan.timeout);
-		complete(&ar->scan.completed);
+		complete_all(&ar->scan.completed);
 		break;
 	}
 }
@@ -2913,6 +2918,9 @@ static int ath12k_start_scan(struct ath12k *ar,
 		if (ret)
 			ath12k_warn(ar->ab, "failed to stop scan: %d\n", ret);
 
+		if (ar->state_11d == ATH12K_11D_RUNNING)
+			return -EBUSY;
+
 		return -ETIMEDOUT;
 	}
 
@@ -3001,7 +3009,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
 
 	ret = ath12k_start_scan(ar, &arg);
 	if (ret) {
-		ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
+		if (ret == -EBUSY)
+			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+				   "scan engine is busy 11d state %d\n", ar->state_11d);
+		else
+			ath12k_warn(ar->ab, "failed to start hw scan: %d\n", ret);
+
 		spin_lock_bh(&ar->data_lock);
 		ar->scan.state = ATH12K_SCAN_IDLE;
 		spin_unlock_bh(&ar->data_lock);
@@ -3019,6 +3032,12 @@ static int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
 		kfree(arg.extraie.ptr);
 
 	mutex_unlock(&ar->conf_mutex);
+
+	if (ar->state_11d == ATH12K_11D_PREPARING &&
+	    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
+		ath12k_mac_11d_scan_start(ar, arvif->vdev_id);
+
 	return ret;
 }
 
@@ -5060,7 +5079,7 @@ static int ath12k_mac_op_start(struct ieee80211_hw *hw)
 
 	/* TODO: Do we need to enable ANI? */
 
-	ath12k_reg_update_chan_list(ar);
+	ath12k_reg_update_chan_list(ar, false);
 
 	ar->num_started_vdevs = 0;
 	ar->num_created_vdevs = 0;
@@ -5128,6 +5147,9 @@ static void ath12k_mac_op_stop(struct ieee80211_hw *hw)
 
 	cancel_delayed_work_sync(&ar->scan.timeout);
 	cancel_work_sync(&ar->regd_update_work);
+	cancel_work_sync(&ar->ab->update_11d_work);
+	ar->state_11d = ATH12K_11D_IDLE;
+	complete(&ar->completed_11d_scan);
 
 	spin_lock_bh(&ar->data_lock);
 	list_for_each_entry_safe(ppdu_stats, tmp, &ar->ppdu_stats_info, list) {
@@ -5306,6 +5328,124 @@ static void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
 	}
 }
 
+static bool ath12k_mac_vif_ap_active_any(struct ath12k_base *ab)
+{
+	struct ath12k *ar;
+	struct ath12k_pdev *pdev;
+	struct ath12k_vif *arvif;
+	int i;
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+		list_for_each_entry(arvif, &ar->arvifs, list) {
+			if (arvif->is_up && arvif->vdev_type == WMI_VDEV_TYPE_AP)
+				return true;
+		}
+	}
+	return false;
+}
+
+void ath12k_mac_11d_scan_start(struct ath12k *ar, u32 vdev_id)
+{
+	struct wmi_11d_scan_start_params param;
+	int ret;
+
+	mutex_lock(&ar->ab->vdev_id_11d_lock);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev id for 11d scan %d\n",
+		   ar->vdev_id_11d_scan);
+
+	if (ar->regdom_set_by_user)
+		goto fin;
+
+	if (ar->vdev_id_11d_scan != ATH12K_11D_INVALID_VDEV_ID)
+		goto fin;
+
+	if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map))
+		goto fin;
+
+	if (ath12k_mac_vif_ap_active_any(ar->ab))
+		goto fin;
+
+	param.vdev_id = vdev_id;
+	param.start_interval_msec = 0;
+	param.scan_period_msec = ATH12K_SCAN_11D_INTERVAL;
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac start 11d scan\n");
+
+	ret = ath12k_wmi_send_11d_scan_start_cmd(ar, &param);
+	if (ret) {
+		ath12k_warn(ar->ab, "failed to start 11d scan vdev %d ret: %d\n",
+			    vdev_id, ret);
+	} else {
+		ar->vdev_id_11d_scan = vdev_id;
+		if (ar->state_11d == ATH12K_11D_PREPARING)
+			ar->state_11d = ATH12K_11D_RUNNING;
+	}
+
+fin:
+	if (ar->state_11d == ATH12K_11D_PREPARING) {
+		ar->state_11d = ATH12K_11D_IDLE;
+		complete(&ar->completed_11d_scan);
+	}
+
+	mutex_unlock(&ar->ab->vdev_id_11d_lock);
+}
+
+void ath12k_mac_11d_scan_stop(struct ath12k *ar)
+{
+	int ret;
+	u32 vdev_id;
+
+	if (!test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ar->ab->wmi_ab.svc_map))
+		return;
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac stop 11d scan\n");
+
+	mutex_lock(&ar->ab->vdev_id_11d_lock);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac stop 11d vdev id %d\n",
+		   ar->vdev_id_11d_scan);
+
+	if (ar->state_11d == ATH12K_11D_PREPARING) {
+		ar->state_11d = ATH12K_11D_IDLE;
+		complete(&ar->completed_11d_scan);
+	}
+
+	if (ar->vdev_id_11d_scan != ATH12K_11D_INVALID_VDEV_ID) {
+		vdev_id = ar->vdev_id_11d_scan;
+
+		ret = ath12k_wmi_send_11d_scan_stop_cmd(ar, vdev_id);
+		if (ret) {
+			ath12k_warn(ar->ab,
+				    "failed to stopt 11d scan vdev %d ret: %d\n",
+				    vdev_id, ret);
+		} else {
+			ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID;
+			ar->state_11d = ATH12K_11D_IDLE;
+			complete(&ar->completed_11d_scan);
+		}
+	}
+	mutex_unlock(&ar->ab->vdev_id_11d_lock);
+}
+
+void ath12k_mac_11d_scan_stop_all(struct ath12k_base *ab)
+{
+	struct ath12k *ar;
+	struct ath12k_pdev *pdev;
+	int i;
+
+	ath12k_dbg(ab, ATH12K_DBG_MAC, "mac stop soc 11d scan\n");
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+
+		ath12k_mac_11d_scan_stop(ar);
+	}
+}
+
 static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 				       struct ieee80211_vif *vif)
 {
@@ -5438,6 +5578,7 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 				    arvif->vdev_id, ret);
 			goto err_peer_del;
 		}
+		ath12k_mac_11d_scan_stop_all(ar->ab);
 		break;
 	case WMI_VDEV_TYPE_STA:
 		param_id = WMI_STA_PS_PARAM_RX_WAKE_POLICY;
@@ -5476,6 +5617,14 @@ static int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
 				    arvif->vdev_id, ret);
 			goto err_peer_del;
 		}
+
+		if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
+		    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+		    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE) {
+			reinit_completion(&ar->completed_11d_scan);
+			ar->state_11d = ATH12K_11D_PREPARING;
+		}
+
 		break;
 	default:
 		break;
@@ -5579,6 +5728,11 @@ static void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
 	ath12k_dbg(ab, ATH12K_DBG_MAC, "mac remove interface (vdev %d)\n",
 		   arvif->vdev_id);
 
+	if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
+	    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE)
+		ath12k_mac_11d_scan_stop(ar);
+
 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
 		ret = ath12k_peer_delete(ar, arvif->vdev_id, vif->addr);
 		if (ret)
@@ -6289,6 +6443,14 @@ ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
 	    ar->num_started_vdevs == 1 && ar->monitor_vdev_created)
 		ath12k_mac_monitor_stop(ar);
 
+	if (test_bit(WMI_TLV_SERVICE_11D_OFFLOAD, ab->wmi_ab.svc_map) &&
+	    arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->vdev_subtype == WMI_VDEV_SUBTYPE_NONE &&
+	    ar->state_11d != ATH12K_11D_PREPARING) {
+		reinit_completion(&ar->completed_11d_scan);
+		ar->state_11d = ATH12K_11D_PREPARING;
+	}
+
 	mutex_unlock(&ar->conf_mutex);
 }
 
@@ -7461,6 +7623,8 @@ int ath12k_mac_allocate(struct ath12k_base *ab)
 		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);
+		ar->vdev_id_11d_scan = ATH12K_11D_INVALID_VDEV_ID;
+		init_completion(&ar->completed_11d_scan);
 	}
 
 	return 0;
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 7b16b70df4fa..0653b6b54891 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -47,6 +47,13 @@ enum ath12k_supported_bw {
 
 extern const struct htt_rx_ring_tlv_filter ath12k_mac_mon_status_filter_default;
 
+#define ATH12K_SCAN_11D_INTERVAL		600000
+#define ATH12K_11D_INVALID_VDEV_ID		0xFFFF
+
+void ath12k_mac_11d_scan_start(struct ath12k *ar, u32 vdev_id);
+void ath12k_mac_11d_scan_stop(struct ath12k *ar);
+void ath12k_mac_11d_scan_stop_all(struct ath12k_base *ab);
+
 void ath12k_mac_destroy(struct ath12k_base *ab);
 void ath12k_mac_unregister(struct ath12k_base *ab);
 int ath12k_mac_register(struct ath12k_base *ab);
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 6ede91ebc8e1..c2f2fcce9fb1 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -88,9 +88,12 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 	if (ret)
 		ath12k_warn(ar->ab,
 			    "INIT Country code set to fw failed : %d\n", ret);
+
+	ath12k_mac_11d_scan_stop(ar);
+	ar->regdom_set_by_user = true;
 }
 
-int ath12k_reg_update_chan_list(struct ath12k *ar)
+int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait)
 {
 	struct ieee80211_supported_band **bands;
 	struct ath12k_wmi_scan_chan_list_arg *arg;
@@ -99,7 +102,35 @@ int ath12k_reg_update_chan_list(struct ath12k *ar)
 	struct ath12k_wmi_channel_arg *ch;
 	enum nl80211_band band;
 	int num_channels = 0;
-	int i, ret;
+	int i, ret, left;
+
+	if (wait && ar->state_11d != ATH12K_11D_IDLE) {
+		left = wait_for_completion_timeout(&ar->completed_11d_scan,
+						   ATH12K_SCAN_TIMEOUT_HZ);
+		if (!left) {
+			ath12k_dbg(ar->ab, ATH12K_DBG_REG,
+				   "failed to receive 11d scan complete: timed out\n");
+			ar->state_11d = ATH12K_11D_IDLE;
+		}
+		ath12k_dbg(ar->ab, ATH12K_DBG_REG,
+			   "reg 11d scan wait left time %d\n", left);
+	}
+
+	if (wait &&
+	    (ar->scan.state == ATH12K_SCAN_STARTING ||
+	    ar->scan.state == ATH12K_SCAN_RUNNING)) {
+		left = wait_for_completion_timeout(&ar->scan.completed,
+						   ATH12K_SCAN_TIMEOUT_HZ);
+		if (!left)
+			ath12k_dbg(ar->ab, ATH12K_DBG_REG,
+				   "failed to receive hw scan complete: timed out\n");
+
+		ath12k_dbg(ar->ab, ATH12K_DBG_REG,
+			   "reg hw scan wait left time %d\n", left);
+	}
+
+	if (ar->state == ATH12K_STATE_RESTARTING)
+		return 0;
 
 	bands = hw->wiphy->bands;
 	for (band = 0; band < NUM_NL80211_BANDS; band++) {
@@ -257,7 +288,7 @@ int ath12k_regd_update(struct ath12k *ar, bool init)
 		goto err;
 
 	if (ar->state == ATH12K_STATE_ON) {
-		ret = ath12k_reg_update_chan_list(ar);
+		ret = ath12k_reg_update_chan_list(ar, true);
 		if (ret)
 			goto err;
 	}
diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h
index 56d009a47234..7e8f9d7970dd 100644
--- a/drivers/net/wireless/ath/ath12k/reg.h
+++ b/drivers/net/wireless/ath/ath12k/reg.h
@@ -90,6 +90,5 @@ struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
 						  struct ath12k_reg_info *reg_info,
 						  bool intersect);
 int ath12k_regd_update(struct ath12k *ar, bool init);
-int ath12k_reg_update_chan_list(struct ath12k *ar);
-
+int ath12k_reg_update_chan_list(struct ath12k *ar, bool wait);
 #endif
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index d22ff9c2326a..92f08e512443 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -160,6 +160,8 @@ 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_11D_NEW_COUNTRY_EVENT] = {
+		.min_len = sizeof(struct wmi_11d_new_cc_event) },
 };
 
 static __le32 ath12k_wmi_tlv_hdr(u32 cmd, u32 len)
@@ -2110,7 +2112,10 @@ void ath12k_wmi_start_scan_init(struct ath12k *ar,
 {
 	/* setup commonly used values */
 	arg->scan_req_id = 1;
-	arg->scan_priority = WMI_SCAN_PRIORITY_LOW;
+	if (ar->state_11d == ATH12K_11D_PREPARING)
+		arg->scan_priority = WMI_SCAN_PRIORITY_MEDIUM;
+	else
+		arg->scan_priority = WMI_SCAN_PRIORITY_LOW;
 	arg->dwell_time_active = 50;
 	arg->dwell_time_active_2g = 0;
 	arg->dwell_time_passive = 150;
@@ -2880,6 +2885,75 @@ int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
 	return ret;
 }
 
+int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar,
+				       struct wmi_11d_scan_start_params *param)
+{
+	struct ath12k_wmi_pdev *wmi = ar->wmi;
+	struct wmi_11d_scan_start_cmd *cmd;
+	struct sk_buff *skb;
+	int ret;
+
+	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_11d_scan_start_cmd *)skb->data;
+	cmd->tlv_header =
+		ath12k_wmi_tlv_cmd_hdr(WMI_TAG_11D_SCAN_START_CMD,
+				       sizeof(*cmd));
+
+	cmd->vdev_id = cpu_to_le32(param->vdev_id);
+	cmd->scan_period_msec = cpu_to_le32(param->scan_period_msec);
+	cmd->start_interval_msec = cpu_to_le32(param->start_interval_msec);
+	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_START_CMDID);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+		   "send 11d scan start vdev id %d period %d ms internal %d ms\n",
+		   param->vdev_id,
+		   param->scan_period_msec,
+		   param->start_interval_msec);
+
+	if (ret) {
+		ath12k_warn(ar->ab,
+			    "failed to send WMI_11D_SCAN_START_CMDID: %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
+int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id)
+{
+	struct ath12k_wmi_pdev *wmi = ar->wmi;
+	struct wmi_11d_scan_stop_cmd *cmd;
+	struct sk_buff *skb;
+	int ret;
+
+	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_11d_scan_stop_cmd *)skb->data;
+	cmd->tlv_header =
+		ath12k_wmi_tlv_cmd_hdr(WMI_TAG_11D_SCAN_STOP_CMD,
+				       sizeof(*cmd));
+
+	cmd->vdev_id = cpu_to_le32(vdev_id);
+	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_11D_SCAN_STOP_CMDID);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+		   "send 11d scan stop vdev id %d\n",
+		   cmd->vdev_id);
+
+	if (ret) {
+		ath12k_warn(ar->ab,
+			    "failed to send WMI_11D_SCAN_STOP_CMDID: %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
 int
 ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id)
 {
@@ -5418,6 +5492,50 @@ static void ath12k_wmi_op_ep_tx_credits(struct ath12k_base *ab)
 	wake_up(&ab->wmi_ab.tx_credits_wq);
 }
 
+static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *skb)
+{
+	const struct wmi_11d_new_cc_event *ev;
+	struct ath12k *ar;
+	struct ath12k_pdev *pdev;
+	const void **tb;
+	int ret, i;
+
+	tb = ath12k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
+	if (IS_ERR(tb)) {
+		ret = PTR_ERR(tb);
+		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
+		return ret;
+	}
+
+	ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT];
+	if (!ev) {
+		kfree(tb);
+		ath12k_warn(ab, "failed to fetch 11d new cc ev");
+		return -EPROTO;
+	}
+
+	spin_lock_bh(&ab->base_lock);
+	memcpy(&ab->new_alpha2, &ev->new_alpha2, REG_ALPHA2_LEN);
+	spin_unlock_bh(&ab->base_lock);
+
+	ath12k_dbg(ab, ATH12K_DBG_WMI, "wmi 11d new cc %c%c\n",
+		   ab->new_alpha2[0],
+		   ab->new_alpha2[1]);
+
+	kfree(tb);
+
+	for (i = 0; i < ab->num_radios; i++) {
+		pdev = &ab->pdevs[i];
+		ar = pdev->ar;
+		ar->state_11d = ATH12K_11D_IDLE;
+		complete(&ar->completed_11d_scan);
+	}
+
+	queue_work(ab->workqueue, &ab->update_11d_work);
+
+	return 0;
+}
+
 static void ath12k_wmi_htc_tx_complete(struct ath12k_base *ab,
 				       struct sk_buff *skb)
 {
@@ -6718,6 +6836,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_11D_NEW_COUNTRY_EVENTID:
+		ath12k_reg_11d_new_cc_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 fead9eba0791..f4f1df057812 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -3782,6 +3782,28 @@ struct wmi_init_country_cmd {
 	} cc_info;
 } __packed;
 
+struct wmi_11d_scan_start_params {
+	u32 vdev_id;
+	u32 scan_period_msec;
+	u32 start_interval_msec;
+};
+
+struct wmi_11d_scan_start_cmd {
+	__le32 tlv_header;
+	__le32 vdev_id;
+	__le32 scan_period_msec;
+	__le32 start_interval_msec;
+} __packed;
+
+struct wmi_11d_scan_stop_cmd {
+	__le32 tlv_header;
+	__le32 vdev_id;
+} __packed;
+
+struct wmi_11d_new_cc_event {
+	__le32 new_alpha2;
+} __packed;
+
 struct wmi_delba_send_cmd {
 	__le32 tlv_header;
 	__le32 vdev_id;
@@ -4897,6 +4919,9 @@ int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar,
 					   dma_addr_t paddr, u8 tid,
 					   u8 ba_window_size_valid,
 					   u32 ba_window_size);
+int ath12k_wmi_send_11d_scan_start_cmd(struct ath12k *ar,
+				       struct wmi_11d_scan_start_params *param);
+int ath12k_wmi_send_11d_scan_stop_cmd(struct ath12k *ar, u32 vdev_id);
 int
 ath12k_wmi_rx_reord_queue_remove(struct ath12k *ar,
 				 struct ath12k_wmi_rx_reorder_queue_remove_arg *arg);
-- 
2.40.1



From quic_wgong at quicinc.com  Thu Sep 14 02:07:43 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Thu, 14 Sep 2023 05:07:43 -0400
Subject: [PATCH v2 1/4] wifi: ath12k: add configure country code for WCN7850
In-Reply-To: <20230914090746.23560-1-quic_wgong@quicinc.com>
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
Message-ID: <20230914090746.23560-2-quic_wgong@quicinc.com>

Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware which
is used for WCN7850.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/wmi.c | 36 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h | 13 ++++++++++
 2 files changed, 49 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 9ed33e2d6da0..d22ff9c2326a 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -2844,6 +2844,42 @@ int ath12k_wmi_send_init_country_cmd(struct ath12k *ar,
 	return ret;
 }
 
+int ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
+					    struct wmi_set_current_country_params *param)
+{
+	struct ath12k_wmi_pdev *wmi = ar->wmi;
+	struct wmi_set_current_country_cmd *cmd;
+	struct sk_buff *skb;
+	int ret;
+
+	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, sizeof(*cmd));
+	if (!skb)
+		return -ENOMEM;
+
+	cmd = (struct wmi_set_current_country_cmd *)skb->data;
+	cmd->tlv_header =
+		ath12k_wmi_tlv_cmd_hdr(WMI_TAG_SET_CURRENT_COUNTRY_CMD,
+				       sizeof(*cmd));
+
+	cmd->pdev_id = cpu_to_le32(ar->pdev->pdev_id);
+	memcpy(&cmd->new_alpha2, &param->alpha2, sizeof(param->alpha2));
+	ret = ath12k_wmi_cmd_send(wmi, skb, WMI_SET_CURRENT_COUNTRY_CMDID);
+
+	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+		   "set current country pdev id %d alpha2 %c%c\n",
+		   ar->pdev->pdev_id,
+		   param->alpha2[0],
+		   param->alpha2[1]);
+
+	if (ret) {
+		ath12k_warn(ar->ab,
+			    "failed to send WMI_SET_CURRENT_COUNTRY_CMDID: %d\n", ret);
+		dev_kfree_skb(skb);
+	}
+
+	return ret;
+}
+
 int
 ath12k_wmi_send_twt_enable_cmd(struct ath12k *ar, u32 pdev_id)
 {
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 8c047a9623f9..fead9eba0791 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -3892,6 +3892,16 @@ struct ath12k_wmi_eht_rate_set_params {
 #define MAX_6G_REG_RULES 5
 #define REG_US_5G_NUM_REG_RULES 4
 
+struct wmi_set_current_country_params {
+	u8 alpha2[REG_ALPHA2_LEN];
+};
+
+struct wmi_set_current_country_cmd {
+	__le32 tlv_header;
+	__le32 pdev_id;
+	__le32 new_alpha2;
+} __packed;
+
 enum wmi_start_event_param {
 	WMI_VDEV_START_RESP_EVENT = 0,
 	WMI_VDEV_RESTART_RESP_EVENT,
@@ -4879,6 +4889,9 @@ int ath12k_wmi_send_bcn_offload_control_cmd(struct ath12k *ar,
 					    u32 vdev_id, u32 bcn_ctrl_op);
 int ath12k_wmi_send_init_country_cmd(struct ath12k *ar,
 				     struct ath12k_wmi_init_country_arg *arg);
+int
+ath12k_wmi_send_set_current_country_cmd(struct ath12k *ar,
+					struct wmi_set_current_country_params *param);
 int ath12k_wmi_peer_rx_reorder_queue_setup(struct ath12k *ar,
 					   int vdev_id, const u8 *addr,
 					   dma_addr_t paddr, u8 tid,
-- 
2.40.1



From quic_wgong at quicinc.com  Thu Sep 14 02:07:46 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Thu, 14 Sep 2023 05:07:46 -0400
Subject: [PATCH v2 4/4] wifi: ath12k: store and send country code to firmware after recovery
In-Reply-To: <20230914090746.23560-1-quic_wgong@quicinc.com>
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
Message-ID: <20230914090746.23560-5-quic_wgong@quicinc.com>

Currently ath12k does not send the country code to firmware after device
recovery. As a result the regdomain info is reported from firmware by
default. Regdomain info is important, so ath12k also need to restore
it to the value which was used before recovery.

This is only needed for platforms which support the current_cc_support
hardware parameter.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.c | 1 +
 drivers/net/wireless/ath/ath12k/core.h | 1 +
 drivers/net/wireless/ath/ath12k/mac.c  | 8 ++++++++
 drivers/net/wireless/ath/ath12k/reg.c  | 1 +
 4 files changed, 11 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 71450dc1f48d..4433d7701c67 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -696,6 +696,7 @@ static void ath12k_update_11d(struct work_struct *work)
 		pdev = &ab->pdevs[i];
 		ar = pdev->ar;
 
+		memcpy(&ar->alpha2, &set_current_param.alpha2, 2);
 		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
 		if (ret)
 			ath12k_warn(ar->ab,
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index e739869ded73..63586cc12a2e 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -582,6 +582,7 @@ struct ath12k {
 	struct completion completed_11d_scan;
 	enum ath12k_11d_state state_11d;
 	bool regdom_set_by_user;
+	u8 alpha2[REG_ALPHA2_LEN];
 };
 
 struct ath12k_band_cap {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 740e8045a6f1..0df154c34f8f 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -6908,6 +6908,14 @@ ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
 		ar->state = ATH12K_STATE_ON;
 		ieee80211_wake_queues(ar->hw);
 
+		if (ar->ab->hw_params->current_cc_support &&
+		    ar->alpha2[0] != 0 && ar->alpha2[1] != 0) {
+			struct wmi_set_current_country_params set_current_param = {};
+
+			memcpy(&set_current_param.alpha2, ar->alpha2, 2);
+			ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
+		}
+
 		if (ab->is_reset) {
 			recovery_count = atomic_inc_return(&ab->recovery_count);
 			ath12k_dbg(ab, ATH12K_DBG_BOOT, "recovery count %d\n",
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 97c93a4901e6..eb46bfc2b2b9 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -82,6 +82,7 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 	 */
 	if (ar->ab->hw_params->current_cc_support) {
 		memcpy(&set_current_param.alpha2, request->alpha2, 2);
+		memcpy(&ar->alpha2, &set_current_param.alpha2, 2);
 
 		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
 		if (ret)
-- 
2.40.1



From quic_wgong at quicinc.com  Thu Sep 14 02:07:45 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Thu, 14 Sep 2023 05:07:45 -0400
Subject: [PATCH v2 3/4] wifi: ath12k: avoid firmware crash when reg set for WCN7850
In-Reply-To: <20230914090746.23560-1-quic_wgong@quicinc.com>
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
Message-ID: <20230914090746.23560-4-quic_wgong@quicinc.com>

For the NL80211_REGDOM_SET_BY_USER hint from cfg80211, it set the new
alpha2 code to ath12k, then ath12k send WMI_SET_INIT_COUNTRY_CMDID to
firmware for all chips currently. When test with WCN7850 chips,
this WMI CMD leads firmware crash.

For AP based chips(QCN92xx), WMI_SET_INIT_COUNTRY_CMDID is the correct
command use. However, for STATION based chips(WCN7850), it need to use
another WMI CMD, WMI_SET_CURRENT_COUNTRY_CMDID.

Add flag current_cc_support in hardware parameters. It is used to
distinguish AP/STA platform. After that, the firmware will work
normal and the regulatory feature works well for WCN7850.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/hw.c  |  3 +++
 drivers/net/wireless/ath/ath12k/hw.h  |  1 +
 drivers/net/wireless/ath/ath12k/reg.c | 29 ++++++++++++++++++---------
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/hw.c b/drivers/net/wireless/ath/ath12k/hw.c
index 5991cc91cd00..c9ed4c0e0da5 100644
--- a/drivers/net/wireless/ath/ath12k/hw.c
+++ b/drivers/net/wireless/ath/ath12k/hw.c
@@ -907,6 +907,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+		.current_cc_support = false,
 	},
 	{
 		.name = "wcn7850 hw2.0",
@@ -964,6 +965,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
 					   BIT(CNSS_PCIE_PERST_NO_PULL_V01),
+		.current_cc_support = true,
 	},
 	{
 		.name = "qcn9274 hw2.0",
@@ -1019,6 +1021,7 @@ static const struct ath12k_hw_params ath12k_hw_params[] = {
 		.hal_ops = &hal_qcn9274_ops,
 
 		.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
+		.current_cc_support = false,
 	},
 };
 
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index e6c4223c283c..292c07bb1a8b 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -173,6 +173,7 @@ struct ath12k_hw_params {
 	bool tcl_ring_retry:1;
 	bool reoq_lut_support:1;
 	bool supports_shadow_regs:1;
+	bool current_cc_support:1;
 
 	u32 hal_desc_sz;
 	u32 num_tcl_banks;
diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index c2f2fcce9fb1..97c93a4901e6 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -48,6 +48,7 @@ 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 wmi_set_current_country_params set_current_param = {};
 	struct ath12k *ar = hw->priv;
 	int ret;
 
@@ -76,18 +77,26 @@ ath12k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 		return;
 	}
 
-	/* Set the country code to the firmware and wait for
-	 * the WMI_REG_CHAN_LIST_CC EVENT for updating the
-	 * reg info
+	/* Set the country code to the firmware. ath12k will subsequently receive
+	 * the WMI_REG_CHAN_LIST_CC EVENT for updating the regulatory info.
 	 */
-	arg.flags = ALPHA_IS_SET;
-	memcpy(&arg.cc_info.alpha2, request->alpha2, 2);
-	arg.cc_info.alpha2[2] = 0;
+	if (ar->ab->hw_params->current_cc_support) {
+		memcpy(&set_current_param.alpha2, request->alpha2, 2);
 
-	ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
-	if (ret)
-		ath12k_warn(ar->ab,
-			    "INIT Country code set to fw failed : %d\n", ret);
+		ret = ath12k_wmi_send_set_current_country_cmd(ar, &set_current_param);
+		if (ret)
+			ath12k_warn(ar->ab,
+				    "failed set current country code: %d\n", ret);
+	} else {
+		arg.flags = ALPHA_IS_SET;
+		memcpy(&arg.cc_info.alpha2, request->alpha2, 2);
+		arg.cc_info.alpha2[2] = 0;
+
+		ret = ath12k_wmi_send_init_country_cmd(ar, &arg);
+		if (ret)
+			ath12k_warn(ar->ab,
+				    "INIT Country code set to fw failed : %d\n", ret);
+	}
 
 	ath12k_mac_11d_scan_stop(ar);
 	ar->regdom_set_by_user = true;
-- 
2.40.1



From quic_jjohnson at quicinc.com  Thu Sep 14 10:06:51 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Thu, 14 Sep 2023 10:06:51 -0700
Subject: [PATCH wireless-next 7/9] wifi: ath12k: Remove unnecessary
 (void*) conversions
In-Reply-To: <20230914040525.1170102-1-yunchuan@nfschina.com>
References: <20230914040525.1170102-1-yunchuan@nfschina.com>
Message-ID: <7427d5aa-902a-4013-8aa9-f986bb5218a4@quicinc.com>

On 9/13/2023 9:05 PM, Wu Yunchuan wrote:
> No need cast (void*) to (struct hal_rx_ppdu_end_user_stats *),
> (struct ath12k_rx_desc_info *) or (struct hal_tx_msdu_ext_desc *).
> 
> Signed-off-by: Wu Yunchuan <yunchuan at nfschina.com>
> ---
>   drivers/net/wireless/ath/ath12k/dp_mon.c | 6 ++----
>   drivers/net/wireless/ath/ath12k/dp_rx.c  | 2 +-
>   drivers/net/wireless/ath/ath12k/dp_tx.c  | 2 +-
>   3 files changed, 4 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
> index f1e57e98bdc6..41cfe7bd865f 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_mon.c
> +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
> @@ -13,8 +13,7 @@
>   static void ath12k_dp_mon_rx_handle_ofdma_info(void *rx_tlv,
>   					       struct hal_rx_user_status *rx_user_status)
>   {
> -	struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
> -				(struct hal_rx_ppdu_end_user_stats *)rx_tlv;
> +	struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
>   
>   	rx_user_status->ul_ofdma_user_v0_word0 =
>   		__le32_to_cpu(ppdu_end_user->usr_resp_ref);
> @@ -26,8 +25,7 @@ static void
>   ath12k_dp_mon_rx_populate_byte_count(void *rx_tlv, void *ppduinfo,
>   				     struct hal_rx_user_status *rx_user_status)
>   {
> -	struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
> -		(struct hal_rx_ppdu_end_user_stats *)rx_tlv;
> +	struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
>   	u32 mpdu_ok_byte_count = __le32_to_cpu(ppdu_end_user->mpdu_ok_cnt);
>   	u32 mpdu_err_byte_count = __le32_to_cpu(ppdu_end_user->mpdu_err_cnt);
>   

for both of the above IMO the better solution is to change the prototype 
to replace void *rx_tlv with struct hal_rx_ppdu_end_user_stats 
*ppdu_end_user and to remove the local variable

further, I think you can add const to that since the TLV is only read, 
not written

this better describes that the function requires a specific flavor of RX 
TLV rather than handling any RX TLV

> diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
> index e6e64d437c47..ff5f66ca7783 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_rx.c
> +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
> @@ -3730,7 +3730,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
>   			continue;
>   		}
>   
> -		desc_info = (struct ath12k_rx_desc_info *)err_info.rx_desc;
> +		desc_info = err_info.rx_desc;

this is ok

>   
>   		/* retry manual desc retrieval if hw cc is not done */
>   		if (!desc_info) {
> diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
> index 8874c815d7fa..98ddf46b3bb9 100644
> --- a/drivers/net/wireless/ath/ath12k/dp_tx.c
> +++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
> @@ -109,7 +109,7 @@ static struct ath12k_tx_desc_info *ath12k_dp_tx_assign_buffer(struct ath12k_dp *
>   static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab, void *cmd,

This function is only called from one place, and it is already passing a 
variable that is of type struct hal_tx_msdu_ext_desc *
so IMO a better solution is to change the prototype to replace void *cmd 
with struct hal_tx_msdu_ext_desc *tcl_ext_desc and remove the local variable

again this better describes that the function requires a specific 
payload rather than a generic opaque payload

as a general rule, use void * when the payload has some level of 
opaqueness and use a specific struct * when the payload must be of a 
specific type

>   					     struct hal_tx_info *ti)
>   {
> -	struct hal_tx_msdu_ext_desc *tcl_ext_cmd = (struct hal_tx_msdu_ext_desc *)cmd;
> +	struct hal_tx_msdu_ext_desc *tcl_ext_cmd = cmd;
>   
>   	tcl_ext_cmd->info0 = le32_encode_bits(ti->paddr,
>   					      HAL_TX_MSDU_EXT_INFO0_BUF_PTR_LO);



From quic_jjohnson at quicinc.com  Thu Sep 14 10:16:23 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Thu, 14 Sep 2023 10:16:23 -0700
Subject: [PATCH v2 1/4] wifi: ath12k: add configure country code for
 WCN7850
In-Reply-To: <20230914090746.23560-2-quic_wgong@quicinc.com>
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
 <20230914090746.23560-2-quic_wgong@quicinc.com>
Message-ID: <584af1a0-798c-405a-a9e4-fd22ba7e2508@quicinc.com>

On 9/14/2023 2:07 AM, Wen Gong wrote:
> Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID to firmware which
> is used for WCN7850.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_jjohnson at quicinc.com  Thu Sep 14 10:16:30 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Thu, 14 Sep 2023 10:16:30 -0700
Subject: [PATCH v2 2/4] wifi: ath12k: add 11d scan offload support
In-Reply-To: <20230914090746.23560-3-quic_wgong@quicinc.com>
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
 <20230914090746.23560-3-quic_wgong@quicinc.com>
Message-ID: <a86e4484-3b03-443c-8c62-c76c2e439790@quicinc.com>

On 9/14/2023 2:07 AM, Wen Gong wrote:
> Add handler for WMI_11D_NEW_COUNTRY_EVENTID, WMI_11D_SCAN_START_CMDID,
> WMI_11D_SCAN_STOP_CMDID.
> 
> The priority of 11d scan WMI_SCAN_PRIORITY_MEDIUM in firmware, the
> priority of hw scan is WMI_SCAN_PRIORITY_LOW, then the 11d scan will
> cancel the hw scan which is running. To avoid this, change the priority
> of the 1st hw scan to WMI_SCAN_PRIORITY_MEDIUM. Add wait_for_completion_timeout
> for ar->scan.completed in ath12k_reg_update_chan_list(), plus the existing
> wait in ath12k_scan_stop(), then ath12k have 2 place to wait the
> ar->scan.completed, they run in different thread, thus it is possible to
> happen that the two threads both enter wait status. To handle this scenario,
> ath12k should change the complete() to complete_all() for the ar->scan.completed,
> this also work well when it is only one thread wait for ar->scan.completed.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_jjohnson at quicinc.com  Thu Sep 14 10:16:36 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Thu, 14 Sep 2023 10:16:36 -0700
Subject: [PATCH v2 3/4] wifi: ath12k: avoid firmware crash when reg set
 for WCN7850
In-Reply-To: <20230914090746.23560-4-quic_wgong@quicinc.com>
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
 <20230914090746.23560-4-quic_wgong@quicinc.com>
Message-ID: <706ae5a8-70bb-45c3-9757-849622af6b64@quicinc.com>

On 9/14/2023 2:07 AM, Wen Gong wrote:
> For the NL80211_REGDOM_SET_BY_USER hint from cfg80211, it set the new
> alpha2 code to ath12k, then ath12k send WMI_SET_INIT_COUNTRY_CMDID to
> firmware for all chips currently. When test with WCN7850 chips,
> this WMI CMD leads firmware crash.
> 
> For AP based chips(QCN92xx), WMI_SET_INIT_COUNTRY_CMDID is the correct
> command use. However, for STATION based chips(WCN7850), it need to use
> another WMI CMD, WMI_SET_CURRENT_COUNTRY_CMDID.
> 
> Add flag current_cc_support in hardware parameters. It is used to
> distinguish AP/STA platform. After that, the firmware will work
> normal and the regulatory feature works well for WCN7850.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>




From quic_jjohnson at quicinc.com  Thu Sep 14 10:16:38 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Thu, 14 Sep 2023 10:16:38 -0700
Subject: [PATCH v2 4/4] wifi: ath12k: store and send country code to
 firmware after recovery
In-Reply-To: <20230914090746.23560-5-quic_wgong@quicinc.com>
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
 <20230914090746.23560-5-quic_wgong@quicinc.com>
Message-ID: <9a24244c-8007-49d7-8355-d6b366826d61@quicinc.com>

On 9/14/2023 2:07 AM, Wen Gong wrote:
> Currently ath12k does not send the country code to firmware after device
> recovery. As a result the regdomain info is reported from firmware by
> default. Regdomain info is important, so ath12k also need to restore
> it to the value which was used before recovery.
> 
> This is only needed for platforms which support the current_cc_support
> hardware parameter.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_wgong at quicinc.com  Fri Sep 15 00:53:07 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Fri, 15 Sep 2023 15:53:07 +0800
Subject: [PATCH 3/3] wifi: mac80211: update link RX NSS by
 ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link()
In-Reply-To: <e6ea3009c489fae910adbf2e1c766f2d827f287f.camel@sipsolutions.net>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
 <20230906103458.24092-4-quic_wgong@quicinc.com>
 <e6ea3009c489fae910adbf2e1c766f2d827f287f.camel@sipsolutions.net>
Message-ID: <7e350410-0e45-910d-68db-ea1d85df958a@quicinc.com>

On 9/13/2023 5:04 PM, Johannes Berg wrote:
> On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
>> Currently for MLO connection, only deflink's rx_nss is set to correct
>> value. The others links' rx_nss of struct ieee80211_link_sta is
>> value 0 in ieee80211_set_associated(), because they are not pass into
>> ieee80211_sta_set_rx_nss() in mac80211 except the deflink in
>> rate_control_rate_init(). This leads driver get NSS = 0 for other links.
>> Add the ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link(),
>> then the other links' rx_nss will be set to the correct value.
> This is pretty much true, but I also think it's problematic the way you
> phrase it. Software rate control is pretty much, at least currently,
> _not_ supported for MLO (and I don't really see how to support it, if
> firmware picks the link to transmit on, as it probably should).
>
> Thus, I'm not even sure we should be calling rate_control_rate_init().
> Clearly we do today, but it's also obviously wrong for everything except
> the call to ieee80211_sta_set_rx_nss().
>
> So while I agree that there's a problem with the RX NSS, I disagree that
> this patch is the right way to fix it. Yes, it also fairly obviously
> fixes the problem, but it just makes an existing design problem worse.
>
> Please change change the overall design here so that
> ieee80211_sta_set_rx_nss() isn't related to rate control at all.
>
> johannes
So should I delete ieee80211_sta_set_rx_nss() in rate_control_rate_init(),
and add it into ieee80211_assoc_config_link() as you said before here?
https://lore.kernel.org/linux-wireless/ca0f6ea2d78538ffb6640f2e56d65c89c86f5221.camel at sipsolutions.net/

I checked the git log, ieee80211_sta_set_rx_nss() is added into
rate_control_rate_init() here for VHT, so is it correct to delete
ieee80211_sta_set_rx_nss() in rate_control_rate_init()?
https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?id=8921d04e8df7475d733d853564bdb001e83bf33f
>


From quic_wgong at quicinc.com  Fri Sep 15 01:11:32 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Fri, 15 Sep 2023 16:11:32 +0800
Subject: [PATCH 1/3] wifi: mac80211: add support to allow driver to
 generate local link address for station
In-Reply-To: <cd762f33b1c15566237c85f1e265ee8a00006f5c.camel@sipsolutions.net>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
 <20230906103458.24092-2-quic_wgong@quicinc.com>
 <cd762f33b1c15566237c85f1e265ee8a00006f5c.camel@sipsolutions.net>
Message-ID: <d23b617e-5ca0-e721-0c2a-fcca8942efef@quicinc.com>

On 9/13/2023 4:55 PM, Johannes Berg wrote:
> On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
[...]
> Maybe after all this explanation, all we need is a flag "reuse MLD
> address for assoc link"?

yes. It is similar as I said before here:

https://lore.kernel.org/linux-wireless/b9c6d022-12c3-a696-c4b9-cb14a6d30a45 at quicinc.com/

>
>
>> +		ret = drv_generate_link_addr(sdata->local, sdata,
>> +					     link_id, link->conf->addr);
>> +		if (ret)
>> +			eth_random_addr(link->conf->addr);
> should probably refactor this into a separate function though.
OK.
>
> I'm also not sure how the driver even knows that a link it's being asked
> to get the address for *is* the assoc link? Do you want to rely on that
> being the first address handed out?
Current I used (vif->valid_links==0) check for assoc link. When
drv_generate_link_addr() called for the assoc link, vif->valid_links
is 0, and it is not 0 for other links.
>
> johannes
>


From quic_wgong at quicinc.com  Fri Sep 15 01:33:30 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Fri, 15 Sep 2023 16:33:30 +0800
Subject: [PATCH 2/3] wifi: mac80211: add support to allow driver to set
 active link while connection for station
In-Reply-To: <4b597bba9dc13c3260f174826de38b4f1bc3bf6e.camel@sipsolutions.net>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
 <20230906103458.24092-3-quic_wgong@quicinc.com>
 <4b597bba9dc13c3260f174826de38b4f1bc3bf6e.camel@sipsolutions.net>
Message-ID: <96ae3c1d-274b-00b1-cb19-a9a301b6aa56@quicinc.com>

On 9/13/2023 4:58 PM, Johannes Berg wrote:
> On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
>> There are 2 fields valid_links and active_links in struct ieee80211_vif
>> of mac80211. For station mode, valid_links is always include the bitmap
>> of active_links. valid_links stores the bitmap of links which is created
>> in mac80211, and mac80211 only indicate the info of links which is existed
>> in active_links to driver. Finally, the active_links is the bitmap of
>> links which station can interactive with MLO AP it is connected to.
>>
>> Currently the active links is always only contain the primary link,
>> primary link means the link used by the latest exchange of successful
>> (Re)Association Request/Response frames. Then it will always have only
>> one link in driver after connected.
>>
>> Hence add this ops in struct ieee80211_ops to allow driver to determine
>> the active links bit map dynamically while connecting to MLO AP.
> This commit log does nothing to address the question "why do we need
> this", particularly since we already have
> ieee80211_set_active_links(/_async), so the driver can pretty much
> immediately enable all the links it wants.
>
> I see no value in this patch whatsoever.
For ieee80211_set_active_links(), driver need save and install pairwise
keys for the other links as you said in link below. But driver do not
save the key data currently. So driver could not install the pairwise
keys by itself.
https://lore.kernel.org/linux-wireless/50719d34bc48d816d00b56d3d9efdb59e3e51a16.camel at sipsolutions.net/

And driver could ensure this rule in spec as I said before in link below:
"For MLO, if RSNA has not been established, each message of the 4-way
handshake shall be sent on the same link used by the latest exchange of
successful (Re)Association Request/Response frames."
https://lore.kernel.org/linux-wireless/b6314b61-0700-0e1c-7b39-21c305dc28b3 at quicinc.com/

It will be complext for driver/ath12k to use 
ieee80211_set_active_links(/_async).
>
>> @@ -166,6 +167,13 @@ static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
>>   		WARN_ON(dormant_links);
>>   		break;
>>   	case NL80211_IFTYPE_STATION:
>> +		active_links = drv_calculate_active_links(sdata->local, sdata,
>> +							  valid_links & ~dormant_links);
>> +		if (active_links) {
>> +			sdata->vif.active_links = active_links;
>> +			break;
>> +		}
>>
> I also _really_ don't think this should operate at this low-level
> infrastructure.

I really want to know the reason why active *only* the assoc link for 
station, but

active *all* links for AP here??

> johannes


From quic_wgong at quicinc.com  Fri Sep 15 01:43:57 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Fri, 15 Sep 2023 16:43:57 +0800
Subject: [PATCH 3/3] wifi: mac80211: update link RX NSS by
 ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link()
In-Reply-To: <e6ea3009c489fae910adbf2e1c766f2d827f287f.camel@sipsolutions.net>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
 <20230906103458.24092-4-quic_wgong@quicinc.com>
 <e6ea3009c489fae910adbf2e1c766f2d827f287f.camel@sipsolutions.net>
Message-ID: <bfdcbf9a-0b27-1f7e-3eca-7390a9a7404e@quicinc.com>

On 9/13/2023 5:04 PM, Johannes Berg wrote:
> On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
>> Currently for MLO connection, only deflink's rx_nss is set to correct
>> value. The others links' rx_nss of struct ieee80211_link_sta is
>> value 0 in ieee80211_set_associated(), because they are not pass into
>> ieee80211_sta_set_rx_nss() in mac80211 except the deflink in
>> rate_control_rate_init(). This leads driver get NSS = 0 for other links.
>> Add the ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link(),
>> then the other links' rx_nss will be set to the correct value.
> This is pretty much true, but I also think it's problematic the way you
> phrase it. Software rate control is pretty much, at least currently,
> _not_ supported for MLO (and I don't really see how to support it, if
> firmware picks the link to transmit on, as it probably should).
I searched all the folder wireless, I only found 5 places have the 
handler of rate_init below,
and the functions are all empty. Is it means no driver support rate_init 
currently?
drivers/net/wireless/realtek/rtlwifi/rc.c:304:???? .rate_init = 
rtl_rate_init,
drivers/net/wireless/intel/iwlwifi/mvm/rs.c:4098:? .rate_init = 
rs_rate_init_ops,
drivers/net/wireless/intel/iwlwifi/dvm/rs.c:3276:? .rate_init = 
rs_rate_init_stub,
drivers/net/wireless/intel/iwlegacy/4965-rs.c:2779: .rate_init = 
il4965_rs_rate_init_stub,
drivers/net/wireless/intel/iwlegacy/3945-rs.c:867: .rate_init = 
il3945_rs_rate_init_stub,
[...]


From yunchuan at nfschina.com  Fri Sep 15 03:05:29 2023
From: yunchuan at nfschina.com (yunchuan)
Date: Fri, 15 Sep 2023 18:05:29 +0800
Subject: [PATCH wireless-next 7/9] wifi: ath12k: Remove unnecessary
 (void*) conversions
In-Reply-To: <7427d5aa-902a-4013-8aa9-f986bb5218a4@quicinc.com>
Message-ID: <5bb164e7-c147-64d1-031d-0ba20cfffa77@nfschina.com>

On 2023/9/15 01:06, Jeff Johnson wrote:
> On 9/13/2023 9:05 PM, Wu Yunchuan wrote:
>> No need cast (void*) to (struct hal_rx_ppdu_end_user_stats *),
>> (struct ath12k_rx_desc_info *) or (struct hal_tx_msdu_ext_desc *).
>>
>> Signed-off-by: Wu Yunchuan <yunchuan at nfschina.com>
>> ---
>> ? drivers/net/wireless/ath/ath12k/dp_mon.c | 6 ++----
>> ? drivers/net/wireless/ath/ath12k/dp_rx.c? | 2 +-
>> ? drivers/net/wireless/ath/ath12k/dp_tx.c? | 2 +-
>> ? 3 files changed, 4 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c 
>> b/drivers/net/wireless/ath/ath12k/dp_mon.c
>> index f1e57e98bdc6..41cfe7bd865f 100644
>> --- a/drivers/net/wireless/ath/ath12k/dp_mon.c
>> +++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
>> @@ -13,8 +13,7 @@
>> ? static void ath12k_dp_mon_rx_handle_ofdma_info(void *rx_tlv,
>> ???????????????????????????? struct hal_rx_user_status *rx_user_status)
>> ? {
>> -??? struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
>> -??????????????? (struct hal_rx_ppdu_end_user_stats *)rx_tlv;
>> +??? struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
>> ? ????? rx_user_status->ul_ofdma_user_v0_word0 =
>> ????????? __le32_to_cpu(ppdu_end_user->usr_resp_ref);
>> @@ -26,8 +25,7 @@ static void
>> ? ath12k_dp_mon_rx_populate_byte_count(void *rx_tlv, void *ppduinfo,
>> ?????????????????????? struct hal_rx_user_status *rx_user_status)
>> ? {
>> -??? struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
>> -??????? (struct hal_rx_ppdu_end_user_stats *)rx_tlv;
>> +??? struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
>> ????? u32 mpdu_ok_byte_count = 
>> __le32_to_cpu(ppdu_end_user->mpdu_ok_cnt);
>> ????? u32 mpdu_err_byte_count = 
>> __le32_to_cpu(ppdu_end_user->mpdu_err_cnt);
>
> for both of the above IMO the better solution is to change the 
> prototype to replace void *rx_tlv with struct 
> hal_rx_ppdu_end_user_stats *ppdu_end_user and to remove the local 
> variable
>
> further, I think you can add const to that since the TLV is only read, 
> not written
>
> this better describes that the function requires a specific flavor of 
> RX TLV rather than handling any RX TLV
>
Hi,

Sounds like a good idea, I will check other patches for this situation.
Thanks for your suggestions.

Wu Yunchuan




From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:50 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:50 +0300
Subject: [PATCH v2 00/13] PCI/ASPM: Make ASPM in core robust and remove driver workarounds
Message-ID: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>

Previously, ASPM service driver has ignored link state management
requests when OS is not authorized to touch LNKCTL (or ASPM is not
configured at all). Because the core interface has not been reliable,
drivers have create workarounds to force ASPM state by directly
writing into LNKCTL themselves.

A second problem is lack of symmetric pair for
pci_disable_link_state(). Any link state disable is permanent (NOTE:
pci_enable_link_state() despite its name is not a symmetric pair for
pci_disable_link_state()). The lack of way to re-enable ASPM prevents
drivers from using pci_disable_link_state() to disabling ASPM for
certain phases of driver operation and re-enabling it later.

Both cases are problematic because when ASPM is working normally
through the service driver, it is not aware of the extra link state
changes drivers perform directly causing the service driver to have
incorrect view about the ASPM state.

Address these problems by making pci_disable_link_state() reliable and
by providing proper pci_enable_link_state() pair for it (the function
currently on the way is renamed first to a more descriptive name).
After core improvements, convert drivers to use the new interface and
drop the workarounds.

v2:
- Rebased the series
- Reorder patches (rename patch first)

Ilpo J?rvinen (13):
  PCI/ASPM: Rename pci_enable_link_state() to
    pci_set_default_link_state()
  PCI/ASPM: Improve pci_set_default_link_state() kerneldoc
  PCI/ASPM: Disable ASPM when driver requests it
  PCI/ASPM: Move L0S/L1/sub states mask calculation into a helper
  PCI/ASPM: Add pci_enable_link_state()
  Bluetooth: hci_bcm4377: Convert aspm disable to quirk
  mt76: Remove unreliable pci_disable_link_state() workaround
  e1000e: Remove unreliable pci_disable_link_state{,_locked}()
    workaround
  wifi: ath10k: Use pci_disable/enable_link_state()
  wifi: ath11k: Use pci_disable/enable_link_state()
  wifi: ath12k: Use pci_disable/enable_link_state()
  RDMA/hfi1: Use pci_disable/enable_link_state()
  misc: rtsx: Use pci_disable/enable_link_state()

 drivers/bluetooth/hci_bcm4377.c               |  20 ---
 drivers/infiniband/hw/hfi1/aspm.c             |  38 +-----
 drivers/infiniband/hw/hfi1/pcie.c             |   2 +-
 drivers/misc/cardreader/rts5228.c             |   6 +-
 drivers/misc/cardreader/rts5261.c             |   6 +-
 drivers/misc/cardreader/rtsx_pcr.c            |   8 +-
 drivers/net/ethernet/intel/e1000e/netdev.c    |  77 +----------
 drivers/net/wireless/ath/ath10k/pci.c         |   8 +-
 drivers/net/wireless/ath/ath11k/pci.c         |  10 +-
 drivers/net/wireless/ath/ath12k/pci.c         |  10 +-
 drivers/net/wireless/mediatek/mt76/Makefile   |   1 -
 drivers/net/wireless/mediatek/mt76/mt76.h     |   1 -
 .../net/wireless/mediatek/mt76/mt7615/pci.c   |   2 +-
 .../net/wireless/mediatek/mt76/mt76x0/pci.c   |   2 +-
 .../net/wireless/mediatek/mt76/mt76x2/pci.c   |   2 +-
 .../net/wireless/mediatek/mt76/mt7915/pci.c   |   2 +-
 .../net/wireless/mediatek/mt76/mt7921/pci.c   |   2 +-
 .../net/wireless/mediatek/mt76/mt7996/pci.c   |   2 +-
 drivers/net/wireless/mediatek/mt76/pci.c      |  47 -------
 drivers/pci/controller/vmd.c                  |   2 +-
 drivers/pci/pcie/Makefile                     |   1 +
 drivers/pci/pcie/aspm.c                       | 126 +++++++++++++-----
 drivers/pci/pcie/aspm_minimal.c               |  66 +++++++++
 drivers/pci/quirks.c                          |   3 +
 include/linux/pci.h                           |  10 +-
 25 files changed, 199 insertions(+), 255 deletions(-)
 delete mode 100644 drivers/net/wireless/mediatek/mt76/pci.c
 create mode 100644 drivers/pci/pcie/aspm_minimal.c

-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:51 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:51 +0300
Subject: [PATCH v2 01/13] PCI/ASPM: Rename pci_enable_link_state() to pci_set_default_link_state()
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-2-ilpo.jarvinen@linux.intel.com>

pci_enable_link_state() and pci_disable_link_state() are not paired
symmetrically despite their names suggesting otherwise.
pci_enable_link_state() tweaks link state when the "default" policy is
in use rather than exactly "enabling" some link states. Obviously, when
the default policy is in use and the default link state is changed,
some link states may get enabled but that is a secondary effect.

Thus, rename pci_enable_link_state() to pci_set_default_link_state() to
better match what it does. The rename also frees
pci_enable_link_state() name so that a function that pairs
symmetrically with pci_disable_link_state() can be added later.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/pci/controller/vmd.c | 2 +-
 drivers/pci/pcie/aspm.c      | 8 ++++----
 include/linux/pci.h          | 4 ++--
 3 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/controller/vmd.c b/drivers/pci/controller/vmd.c
index ad56df98b8e6..e424ce897d23 100644
--- a/drivers/pci/controller/vmd.c
+++ b/drivers/pci/controller/vmd.c
@@ -752,7 +752,7 @@ static int vmd_pm_enable_quirk(struct pci_dev *pdev, void *userdata)
 	if (!(features & VMD_FEAT_BIOS_PM_QUIRK))
 		return 0;
 
-	pci_enable_link_state(pdev, PCIE_LINK_STATE_ALL);
+	pci_set_default_link_state(pdev, PCIE_LINK_STATE_ALL);
 
 	pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_LTR);
 	if (!pos)
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 1bf630059264..fc909e20365f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1102,8 +1102,8 @@ int pci_disable_link_state(struct pci_dev *pdev, int state)
 EXPORT_SYMBOL(pci_disable_link_state);
 
 /**
- * pci_enable_link_state - Clear and set the default device link state so that
- * the link may be allowed to enter the specified states. Note that if the
+ * pci_set_default_link_state - Clear and set the default device link state so
+ * that the link may be allowed to enter the specified states. Note that if the
  * BIOS didn't grant ASPM control to the OS, this does nothing because we can't
  * touch the LNKCTL register. Also note that this does not enable states
  * disabled by pci_disable_link_state(). Return 0 or a negative errno.
@@ -1111,7 +1111,7 @@ EXPORT_SYMBOL(pci_disable_link_state);
  * @pdev: PCI device
  * @state: Mask of ASPM link states to enable
  */
-int pci_enable_link_state(struct pci_dev *pdev, int state)
+int pci_set_default_link_state(struct pci_dev *pdev, int state)
 {
 	struct pcie_link_state *link = pcie_aspm_get_link(pdev);
 
@@ -1153,7 +1153,7 @@ int pci_enable_link_state(struct pci_dev *pdev, int state)
 
 	return 0;
 }
-EXPORT_SYMBOL(pci_enable_link_state);
+EXPORT_SYMBOL(pci_set_default_link_state);
 
 static int pcie_aspm_set_policy(const char *val,
 				const struct kernel_param *kp)
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 8c7c2c3c6c65..7df56988ff48 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1776,7 +1776,7 @@ extern bool pcie_ports_native;
 #ifdef CONFIG_PCIEASPM
 int pci_disable_link_state(struct pci_dev *pdev, int state);
 int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
-int pci_enable_link_state(struct pci_dev *pdev, int state);
+int pci_set_default_link_state(struct pci_dev *pdev, int state);
 void pcie_no_aspm(void);
 bool pcie_aspm_support_enabled(void);
 bool pcie_aspm_enabled(struct pci_dev *pdev);
@@ -1785,7 +1785,7 @@ static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
 { return 0; }
 static inline int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
 { return 0; }
-static inline int pci_enable_link_state(struct pci_dev *pdev, int state)
+static inline int pci_set_default_link_state(struct pci_dev *pdev, int state)
 { return 0; }
 static inline void pcie_no_aspm(void) { }
 static inline bool pcie_aspm_support_enabled(void) { return false; }
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:52 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:52 +0300
Subject: [PATCH v2 02/13] PCI/ASPM: Improve pci_set_default_link_state() kerneldoc
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-3-ilpo.jarvinen@linux.intel.com>

Improve pci_set_default_link_state() documentation:

- Note the link state may get changed if the default policy is in use
- Better follow kerneldoc formatting guidelines (separate description
  block and return entries)

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/pci/pcie/aspm.c | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index fc909e20365f..860bc94974ec 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1102,14 +1102,18 @@ int pci_disable_link_state(struct pci_dev *pdev, int state)
 EXPORT_SYMBOL(pci_disable_link_state);
 
 /**
- * pci_set_default_link_state - Clear and set the default device link state so
- * that the link may be allowed to enter the specified states. Note that if the
- * BIOS didn't grant ASPM control to the OS, this does nothing because we can't
- * touch the LNKCTL register. Also note that this does not enable states
- * disabled by pci_disable_link_state(). Return 0 or a negative errno.
- *
+ * pci_set_default_link_state - Set the default device link state
  * @pdev: PCI device
  * @state: Mask of ASPM link states to enable
+ *
+ * Set the default device link state so that the link may be allowed to
+ * enter the specified states. If the default policy is in use, the link
+ * state may also be updated to reflect the new default link state. Note
+ * that if the BIOS didn't grant ASPM control to the OS, this does nothing
+ * because we can't touch the LNKCTL register. Also note that this does not
+ * enable states disabled by pci_disable_link_state().
+ *
+ * Return: 0 or a negative errno.
  */
 int pci_set_default_link_state(struct pci_dev *pdev, int state)
 {
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:53 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:53 +0300
Subject: [PATCH v2 03/13] PCI/ASPM: Disable ASPM when driver requests it
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-4-ilpo.jarvinen@linux.intel.com>

PCI core/ASPM service driver allows controlling ASPM state through
pci_disable_link_state() and pci_enable_link_state() API. It was
decided earlier (see the Link below), to not allow ASPM changes when OS
does not have control over it but only log a warning about the problem
(commit 2add0ec14c25 ("PCI/ASPM: Warn when driver asks to disable ASPM,
but we can't do it")). Similarly, if ASPM is not enabled through
config, ASPM cannot be disabled.

A number of drivers have added workarounds to force ASPM off with own
writes into the Link Control Register (some even with comments
explaining why PCI core does not disable it under some circumstances).
According to the comments, some drivers require ASPM to be off for
reliable operation.

Having custom ASPM handling in drivers is problematic because the state
kept in the ASPM service driver is not updated by the changes made
outside the link state management API.

As the first step to address this issue, make pci_disable_link_state()
to unconditionally disable ASPM so the motivation for drivers to come
up with custom ASPM handling code is eliminated.

Place the minimal ASPM disable handling into own file as it is too
complicated to fit into a header as static inline and it has almost no
overlap with the existing, more complicated ASPM code in
drivers/pci/pce/aspm.c.

Make pci_disable_link_state() function comment to comply kerneldoc
formatting while changing the description.

Link: https://lore.kernel.org/all/CANUX_P3F5YhbZX3WGU-j1AGpbXb_T9Bis2ErhvKkFMtDvzatVQ at mail.gmail.com/
Link: https://lore.kernel.org/all/20230511131441.45704-1-ilpo.jarvinen at linux.intel.com/
Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/pci/pcie/Makefile       |  1 +
 drivers/pci/pcie/aspm.c         | 33 ++++++++++-------
 drivers/pci/pcie/aspm_minimal.c | 66 +++++++++++++++++++++++++++++++++
 include/linux/pci.h             |  6 +--
 4 files changed, 88 insertions(+), 18 deletions(-)
 create mode 100644 drivers/pci/pcie/aspm_minimal.c

diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index 8de4ed5f98f1..ec7f04037b01 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -6,6 +6,7 @@ pcieportdrv-y			:= portdrv.o rcec.o
 
 obj-$(CONFIG_PCIEPORTBUS)	+= pcieportdrv.o
 
+obj-y				+= aspm_minimal.o
 obj-$(CONFIG_PCIEASPM)		+= aspm.o
 obj-$(CONFIG_PCIEAER)		+= aer.o err.o
 obj-$(CONFIG_PCIEAER_INJECT)	+= aer_inject.o
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 860bc94974ec..ec6d7a092ac1 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1042,16 +1042,23 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
 		return -EINVAL;
 	/*
 	 * A driver requested that ASPM be disabled on this device, but
-	 * if we don't have permission to manage ASPM (e.g., on ACPI
+	 * if we might not have permission to manage ASPM (e.g., on ACPI
 	 * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and
-	 * the _OSC method), we can't honor that request.  Windows has
-	 * a similar mechanism using "PciASPMOptOut", which is also
-	 * ignored in this situation.
+	 * the _OSC method), previously we chose to not honor disable
+	 * request in that case. Windows has a similar mechanism using
+	 * "PciASPMOptOut", which is also ignored in this situation.
+	 *
+	 * Not honoring the requests to disable ASPM, however, led to
+	 * drivers forcing ASPM off on their own. As such changes of ASPM
+	 * state are not tracked by this service driver, the state kept here
+	 * became out of sync.
+	 *
+	 * Therefore, honor ASPM disable requests even when OS does not have
+	 * ASPM control. Plain disable for ASPM is assumed to be slightly
+	 * safer than fully managing it.
 	 */
-	if (aspm_disabled) {
-		pci_warn(pdev, "can't disable ASPM; OS doesn't have ASPM control\n");
-		return -EPERM;
-	}
+	if (aspm_disabled)
+		pci_warn(pdev, "OS doesn't have ASPM control, disabling ASPM anyway\n");
 
 	if (sem)
 		down_read(&pci_bus_sem);
@@ -1087,13 +1094,13 @@ int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
 EXPORT_SYMBOL(pci_disable_link_state_locked);
 
 /**
- * pci_disable_link_state - Disable device's link state, so the link will
- * never enter specific states.  Note that if the BIOS didn't grant ASPM
- * control to the OS, this does nothing because we can't touch the LNKCTL
- * register. Returns 0 or a negative errno.
- *
+ * pci_disable_link_state - Disable device's link state
  * @pdev: PCI device
  * @state: ASPM link state to disable
+ *
+ * Disable device's link state so the link will never enter specific states.
+ *
+ * Return: 0 or a negative errno
  */
 int pci_disable_link_state(struct pci_dev *pdev, int state)
 {
diff --git a/drivers/pci/pcie/aspm_minimal.c b/drivers/pci/pcie/aspm_minimal.c
new file mode 100644
index 000000000000..4e4f63e51b21
--- /dev/null
+++ b/drivers/pci/pcie/aspm_minimal.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Minimal PCIe ASPM handling when CONFIG_PCIEASPM is not set.
+ *
+ * Copyright (C) 2023 Intel Corporation.
+ */
+
+#include <linux/pci.h>
+
+#include "../pci.h"
+
+#ifndef CONFIG_PCIEASPM
+/*
+ * Always disable ASPM when requested, even when CONFIG_PCIEASPM is
+ * not build to avoid drivers adding code to do it on their own
+ * which caused issues when core does not know about the out-of-band
+ * ASPM state changes.
+ */
+int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
+{
+	struct pci_dev *parent = pdev->bus->self;
+	struct pci_bus *linkbus = pdev->bus;
+	struct pci_dev *child;
+	u16 aspm_enabled, linkctl;
+	int ret;
+
+	if (!parent)
+		return -ENODEV;
+
+	ret = pcie_capability_read_word(parent, PCI_EXP_LNKCTL, &linkctl);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return pcibios_err_to_errno(ret);
+	aspm_enabled = linkctl & PCI_EXP_LNKCTL_ASPMC;
+
+	ret = pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &linkctl);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return pcibios_err_to_errno(ret);
+	aspm_enabled |= linkctl & PCI_EXP_LNKCTL_ASPMC;
+
+	/* If no states need to be disabled, don't touch LNKCTL */
+	if (state & aspm_enabled)
+		return 0;
+
+	ret = pcie_capability_clear_word(parent, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_ASPMC);
+	if (ret != PCIBIOS_SUCCESSFUL)
+		return pcibios_err_to_errno(ret);
+	list_for_each_entry(child, &linkbus->devices, bus_list)
+		pcie_capability_clear_word(child, PCI_EXP_LNKCTL, PCI_EXP_LNKCTL_ASPMC);
+
+	return 0;
+}
+EXPORT_SYMBOL(pci_disable_link_state_locked);
+
+int pci_disable_link_state(struct pci_dev *pdev, int state)
+{
+	int ret;
+
+	down_read(&pci_bus_sem);
+	ret = pci_disable_link_state_locked(pdev, state);
+	up_read(&pci_bus_sem);
+
+	return ret;
+}
+EXPORT_SYMBOL(pci_disable_link_state);
+
+#endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 7df56988ff48..3c24ca164104 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1773,18 +1773,14 @@ extern bool pcie_ports_native;
 					 PCIE_LINK_STATE_L1_2 | PCIE_LINK_STATE_L1_1_PCIPM |\
 					 PCIE_LINK_STATE_L1_2_PCIPM)
 
-#ifdef CONFIG_PCIEASPM
 int pci_disable_link_state(struct pci_dev *pdev, int state);
 int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
+#ifdef CONFIG_PCIEASPM
 int pci_set_default_link_state(struct pci_dev *pdev, int state);
 void pcie_no_aspm(void);
 bool pcie_aspm_support_enabled(void);
 bool pcie_aspm_enabled(struct pci_dev *pdev);
 #else
-static inline int pci_disable_link_state(struct pci_dev *pdev, int state)
-{ return 0; }
-static inline int pci_disable_link_state_locked(struct pci_dev *pdev, int state)
-{ return 0; }
 static inline int pci_set_default_link_state(struct pci_dev *pdev, int state)
 { return 0; }
 static inline void pcie_no_aspm(void) { }
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:54 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:54 +0300
Subject: [PATCH v2 04/13] PCI/ASPM: Move L0S/L1/sub states mask calculation into a helper
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-5-ilpo.jarvinen@linux.intel.com>

ASPM service driver does the same L0S / L1S / sub states allowed
calculation in __pci_disable_link_state() and
pci_set_default_link_state().

Create a helper to calculate the mask for the allowed states.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/pci/pcie/aspm.c | 33 +++++++++++++++++++++------------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index ec6d7a092ac1..91dc95aca90f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1034,6 +1034,26 @@ static struct pcie_link_state *pcie_aspm_get_link(struct pci_dev *pdev)
 	return bridge->link_state;
 }
 
+static u8 pci_link_state_mask(int state)
+{
+	u8 result = 0;
+
+	if (state & PCIE_LINK_STATE_L0S)
+		result |= ASPM_STATE_L0S;
+	if (state & PCIE_LINK_STATE_L1)
+		result |= ASPM_STATE_L1;
+	if (state & PCIE_LINK_STATE_L1_1)
+		result |= ASPM_STATE_L1_1;
+	if (state & PCIE_LINK_STATE_L1_2)
+		result |= ASPM_STATE_L1_2;
+	if (state & PCIE_LINK_STATE_L1_1_PCIPM)
+		result |= ASPM_STATE_L1_1_PCIPM;
+	if (state & PCIE_LINK_STATE_L1_2_PCIPM)
+		result |= ASPM_STATE_L1_2_PCIPM;
+
+	return result;
+}
+
 static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
 {
 	struct pcie_link_state *link = pcie_aspm_get_link(pdev);
@@ -1063,18 +1083,7 @@ static int __pci_disable_link_state(struct pci_dev *pdev, int state, bool sem)
 	if (sem)
 		down_read(&pci_bus_sem);
 	mutex_lock(&aspm_lock);
-	if (state & PCIE_LINK_STATE_L0S)
-		link->aspm_disable |= ASPM_STATE_L0S;
-	if (state & PCIE_LINK_STATE_L1)
-		link->aspm_disable |= ASPM_STATE_L1;
-	if (state & PCIE_LINK_STATE_L1_1)
-		link->aspm_disable |= ASPM_STATE_L1_1;
-	if (state & PCIE_LINK_STATE_L1_2)
-		link->aspm_disable |= ASPM_STATE_L1_2;
-	if (state & PCIE_LINK_STATE_L1_1_PCIPM)
-		link->aspm_disable |= ASPM_STATE_L1_1_PCIPM;
-	if (state & PCIE_LINK_STATE_L1_2_PCIPM)
-		link->aspm_disable |= ASPM_STATE_L1_2_PCIPM;
+	link->aspm_disable |= pci_link_state_mask(state);
 	pcie_config_aspm_link(link, policy_to_aspm_state(link));
 
 	if (state & PCIE_LINK_STATE_CLKPM)
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:55 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:55 +0300
Subject: [PATCH v2 05/13] PCI/ASPM: Add pci_enable_link_state()
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-6-ilpo.jarvinen@linux.intel.com>

pci_disable_link_state() lacks a symmetric pair. Some drivers want to
disable ASPM during certain phases of their operation but then
re-enable it later on. If pci_disable_link_state() is made for the
device, there is currently no way to re-enable the states that were
disabled.

Add pci_enable_link_state() to remove ASPM states from the state
disable mask.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/pci/pcie/aspm.c | 42 +++++++++++++++++++++++++++++++++++++++++
 include/linux/pci.h     |  2 ++
 2 files changed, 44 insertions(+)

diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 91dc95aca90f..f45d18d47c20 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -1117,6 +1117,48 @@ int pci_disable_link_state(struct pci_dev *pdev, int state)
 }
 EXPORT_SYMBOL(pci_disable_link_state);
 
+/**
+ * pci_enable_link_state - Re-enable device's link state
+ * @pdev: PCI device
+ * @state: ASPM link states to re-enable
+ *
+ * Enable device's link state that were previously disable so the link is
+ * allowed to enter the specific states. Note that if the BIOS didn't grant
+ * ASPM control to the OS, this does nothing because we can't touch the
+ * LNKCTL register.
+ *
+ * Return: 0 or a negative errno.
+ */
+int pci_enable_link_state(struct pci_dev *pdev, int state)
+{
+	struct pcie_link_state *link = pcie_aspm_get_link(pdev);
+
+	if (!link)
+		return -EINVAL;
+	/*
+	 * A driver requested that ASPM be enabled on this device, but
+	 * if we don't have permission to manage ASPM (e.g., on ACPI
+	 * systems we have to observe the FADT ACPI_FADT_NO_ASPM bit and
+	 * the _OSC method), we can't honor that request.
+	 */
+	if (aspm_disabled) {
+		pci_warn(pdev, "can't enable ASPM; OS doesn't have ASPM control\n");
+		return -EPERM;
+	}
+
+	mutex_lock(&aspm_lock);
+	link->aspm_disable &= ~pci_link_state_mask(state);
+	pcie_config_aspm_link(link, policy_to_aspm_state(link));
+
+	if (state & PCIE_LINK_STATE_CLKPM)
+		link->clkpm_disable = 0;
+	pcie_set_clkpm(link, policy_to_clkpm_state(link));
+	mutex_unlock(&aspm_lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(pci_enable_link_state);
+
 /**
  * pci_set_default_link_state - Set the default device link state
  * @pdev: PCI device
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 3c24ca164104..844d09230264 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -1776,11 +1776,13 @@ extern bool pcie_ports_native;
 int pci_disable_link_state(struct pci_dev *pdev, int state);
 int pci_disable_link_state_locked(struct pci_dev *pdev, int state);
 #ifdef CONFIG_PCIEASPM
+int pci_enable_link_state(struct pci_dev *pdev, int state);
 int pci_set_default_link_state(struct pci_dev *pdev, int state);
 void pcie_no_aspm(void);
 bool pcie_aspm_support_enabled(void);
 bool pcie_aspm_enabled(struct pci_dev *pdev);
 #else
+static inline int pci_enable_link_state(struct pci_dev *pdev, int state) { return -EOPNOTSUPP; }
 static inline int pci_set_default_link_state(struct pci_dev *pdev, int state)
 { return 0; }
 static inline void pcie_no_aspm(void) { }
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:56 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:56 +0300
Subject: [PATCH v2 06/13] Bluetooth: hci_bcm4377: Convert aspm disable to quirk
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-7-ilpo.jarvinen@linux.intel.com>

pci_disable_link_state() was made reliable regardless of ASPM CONFIG
and OS being disallowed to change ASPM states to allow drivers to rely
on pci_disable_link_state() working.

Remove driver working around unreliable pci_disable_link_state() from
hci_bcm4377 driver and add a PCI quirk to disable ASPM.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/bluetooth/hci_bcm4377.c | 20 --------------------
 drivers/pci/quirks.c            |  3 +++
 2 files changed, 3 insertions(+), 20 deletions(-)

diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
index 19ad0e788646..2348ee2380db 100644
--- a/drivers/bluetooth/hci_bcm4377.c
+++ b/drivers/bluetooth/hci_bcm4377.c
@@ -490,7 +490,6 @@ struct bcm4377_data;
  * clear_pciecfg_subsystem_ctrl_bit19: Set to true if bit 19 in the
  *                                     vendor-specific subsystem control
  *                                     register has to be cleared
- * disable_aspm: Set to true if ASPM must be disabled due to hardware errata
  * broken_ext_scan: Set to true if the chip erroneously claims to support
  *                  extended scanning
  * broken_mws_transport_config: Set to true if the chip erroneously claims to
@@ -509,7 +508,6 @@ struct bcm4377_hw {
 
 	unsigned long has_bar0_core2_window2 : 1;
 	unsigned long clear_pciecfg_subsystem_ctrl_bit19 : 1;
-	unsigned long disable_aspm : 1;
 	unsigned long broken_ext_scan : 1;
 	unsigned long broken_mws_transport_config : 1;
 
@@ -2222,20 +2220,6 @@ static int bcm4377_probe_of(struct bcm4377_data *bcm4377)
 	return 0;
 }
 
-static void bcm4377_disable_aspm(struct bcm4377_data *bcm4377)
-{
-	pci_disable_link_state(bcm4377->pdev,
-			       PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
-
-	/*
-	 * pci_disable_link_state can fail if either CONFIG_PCIEASPM is disabled
-	 * or if the BIOS hasn't handed over control to us. We must *always*
-	 * disable ASPM for this device due to hardware errata though.
-	 */
-	pcie_capability_clear_word(bcm4377->pdev, PCI_EXP_LNKCTL,
-				   PCI_EXP_LNKCTL_ASPMC);
-}
-
 static void bcm4377_pci_free_irq_vectors(void *data)
 {
 	pci_free_irq_vectors(data);
@@ -2288,9 +2272,6 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		return -ENODEV;
 	}
 
-	if (bcm4377->hw->disable_aspm)
-		bcm4377_disable_aspm(bcm4377);
-
 	ret = pci_reset_function_locked(pdev);
 	if (ret)
 		dev_warn(
@@ -2448,7 +2429,6 @@ static const struct bcm4377_hw bcm4377_hw_variants[] = {
 		.otp_offset = 0x4120,
 		.bar0_window1 = 0x1800b000,
 		.bar0_window2 = 0x1810c000,
-		.disable_aspm = true,
 		.broken_ext_scan = true,
 		.send_ptb = bcm4377_send_ptb,
 	},
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index eeec1d6f9023..d6ab0e98013f 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -2502,6 +2502,9 @@ static void quirk_disable_aspm_l0s_l1(struct pci_dev *dev)
  */
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ASMEDIA, 0x1080, quirk_disable_aspm_l0s_l1);
 
+/* BCM4377 must always disable ASPM due to hardware errata. */
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, 0x5fa0, quirk_disable_aspm_l0s_l1);
+
 /*
  * Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain
  * Link bit cleared after starting the link retrain process to allow this
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:57 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:57 +0300
Subject: [PATCH v2 07/13] mt76: Remove unreliable pci_disable_link_state() workaround
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-8-ilpo.jarvinen@linux.intel.com>

pci_disable_link_state() was made reliable regardless of ASPM CONFIG
and OS being disallowed to change ASPM states to allow drivers to rely
on pci_disable_link_state() working.

Remove driver working around unreliable pci_disable_link_state() from
mt76 driver and just call pci_disable_link_state() directly.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---

It's a bit unclear which of these devices really need ASPM disabled.
Probably all 76xx given the commit messages that added their disabling
but 79xx seems a lot more uncertain and handwavy.

mt7915 was done without observing any issue in commit 03b3dedc5de1
("mt76: mt7915: disable ASPM").

mt7921 re-enabled aspm in bf3747ae2e25 ("mt76: mt7921: enable aspm by
default").

mt7996 was added with aspm disabled.

I didn't convert these to quirk due to how unclear the situation
currently is (but for 76xx quirk would seem justified as there is
actually some evidence to back aspm being harmful).
---
 drivers/net/wireless/mediatek/mt76/Makefile   |  1 -
 drivers/net/wireless/mediatek/mt76/mt76.h     |  1 -
 .../net/wireless/mediatek/mt76/mt7615/pci.c   |  2 +-
 .../net/wireless/mediatek/mt76/mt76x0/pci.c   |  2 +-
 .../net/wireless/mediatek/mt76/mt76x2/pci.c   |  2 +-
 .../net/wireless/mediatek/mt76/mt7915/pci.c   |  2 +-
 .../net/wireless/mediatek/mt76/mt7921/pci.c   |  2 +-
 .../net/wireless/mediatek/mt76/mt7996/pci.c   |  2 +-
 drivers/net/wireless/mediatek/mt76/pci.c      | 47 -------------------
 9 files changed, 6 insertions(+), 55 deletions(-)
 delete mode 100644 drivers/net/wireless/mediatek/mt76/pci.c

diff --git a/drivers/net/wireless/mediatek/mt76/Makefile b/drivers/net/wireless/mediatek/mt76/Makefile
index 85c4799be954..cb28cef780a5 100644
--- a/drivers/net/wireless/mediatek/mt76/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/Makefile
@@ -12,7 +12,6 @@ mt76-y := \
 	mmio.o util.o trace.o dma.o mac80211.o debugfs.o eeprom.o \
 	tx.o agg-rx.o mcu.o
 
-mt76-$(CONFIG_PCI) += pci.o
 mt76-$(CONFIG_NL80211_TESTMODE) += testmode.o
 
 mt76-usb-y := usb.o usb_trace.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index e8757865a3d0..0869fe03e3d2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -1038,7 +1038,6 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
 #define mt76_poll_msec_tick(dev, ...) ____mt76_poll_msec(&((dev)->mt76), __VA_ARGS__)
 
 void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs);
-void mt76_pci_disable_aspm(struct pci_dev *pdev);
 
 static inline u16 mt76_chip(struct mt76_dev *dev)
 {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
index 9f43e673518b..d43efe4bf9e3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
@@ -43,7 +43,7 @@ static int mt7615_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		goto error;
 
-	mt76_pci_disable_aspm(pdev);
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	map = id->device == 0x7663 ? mt7663e_reg_map : mt7615e_reg_map;
 	ret = mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0],
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
index 9277ff38b7a2..49c7a63cb1f6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/pci.c
@@ -181,7 +181,7 @@ mt76x0e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	if (ret)
 		return ret;
 
-	mt76_pci_disable_aspm(pdev);
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt76x0e_ops,
 				 &drv_ops);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
index df85ebc6e1df..de6eb593ab59 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/pci.c
@@ -85,7 +85,7 @@ mt76x2e_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 	/* RG_SSUSB_CDR_BR_PE1D = 0x3 */
 	mt76_rmw_field(dev, 0x15c58, 0x3 << 6, 0x3);
 
-	mt76_pci_disable_aspm(pdev);
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	return 0;
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
index 39132894e8ea..8cf9a1a6d851 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c
@@ -122,7 +122,7 @@ static int mt7915_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		return ret;
 
-	mt76_pci_disable_aspm(pdev);
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	if (id->device == 0x7916 || id->device == 0x790a)
 		return mt7915_pci_hif2_probe(pdev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index 3dda84a93717..45a861122926 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -294,7 +294,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
 		goto err_free_pci_vec;
 
 	if (mt7921_disable_aspm)
-		mt76_pci_disable_aspm(pdev);
+		pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7921_ops,
 				      (void *)id->driver_data, &features);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
index c5301050ff8b..1e84c1f37c37 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
@@ -111,7 +111,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
 	if (ret)
 		return ret;
 
-	mt76_pci_disable_aspm(pdev);
+	pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	if (id->device == 0x7991)
 		return mt7996_pci_hif2_probe(pdev);
diff --git a/drivers/net/wireless/mediatek/mt76/pci.c b/drivers/net/wireless/mediatek/mt76/pci.c
deleted file mode 100644
index 4c1c159fbb62..000000000000
--- a/drivers/net/wireless/mediatek/mt76/pci.c
+++ /dev/null
@@ -1,47 +0,0 @@
-// SPDX-License-Identifier: ISC
-/*
- * Copyright (C) 2019 Lorenzo Bianconi <lorenzo at kernel.org>
- */
-
-#include "mt76.h"
-#include <linux/pci.h>
-
-void mt76_pci_disable_aspm(struct pci_dev *pdev)
-{
-	struct pci_dev *parent = pdev->bus->self;
-	u16 aspm_conf, parent_aspm_conf = 0;
-
-	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &aspm_conf);
-	aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
-	if (parent) {
-		pcie_capability_read_word(parent, PCI_EXP_LNKCTL,
-					  &parent_aspm_conf);
-		parent_aspm_conf &= PCI_EXP_LNKCTL_ASPMC;
-	}
-
-	if (!aspm_conf && (!parent || !parent_aspm_conf)) {
-		/* aspm already disabled */
-		return;
-	}
-
-	dev_info(&pdev->dev, "disabling ASPM %s %s\n",
-		 (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S) ? "L0s" : "",
-		 (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1) ? "L1" : "");
-
-	if (IS_ENABLED(CONFIG_PCIEASPM)) {
-		int err;
-
-		err = pci_disable_link_state(pdev, aspm_conf);
-		if (!err)
-			return;
-	}
-
-	/* both device and parent should have the same ASPM setting.
-	 * disable ASPM in downstream component first and then upstream.
-	 */
-	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_conf);
-	if (parent)
-		pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
-					   aspm_conf);
-}
-EXPORT_SYMBOL_GPL(mt76_pci_disable_aspm);
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:58 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:58 +0300
Subject: [PATCH v2 08/13] e1000e: Remove unreliable pci_disable_link_state{,_locked}() workaround
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-9-ilpo.jarvinen@linux.intel.com>

pci_disable_link_state() and pci_disable_link_state_locked() were made
reliable regardless of ASPM CONFIG and OS being disallowed to change
ASPM states to allow drivers to rely on them working.

Remove driver working around unreliable
pci_disable_link_state{,_locked}() from e1000e driver and just call the
functions directly.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/net/ethernet/intel/e1000e/netdev.c | 77 +---------------------
 1 file changed, 2 insertions(+), 75 deletions(-)

diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index f536c856727c..fbe468061591 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -6765,79 +6765,6 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime)
 	return 0;
 }
 
-/**
- * __e1000e_disable_aspm - Disable ASPM states
- * @pdev: pointer to PCI device struct
- * @state: bit-mask of ASPM states to disable
- * @locked: indication if this context holds pci_bus_sem locked.
- *
- * Some devices *must* have certain ASPM states disabled per hardware errata.
- **/
-static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state, int locked)
-{
-	struct pci_dev *parent = pdev->bus->self;
-	u16 aspm_dis_mask = 0;
-	u16 pdev_aspmc, parent_aspmc;
-
-	switch (state) {
-	case PCIE_LINK_STATE_L0S:
-	case PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1:
-		aspm_dis_mask |= PCI_EXP_LNKCTL_ASPM_L0S;
-		fallthrough; /* can't have L1 without L0s */
-	case PCIE_LINK_STATE_L1:
-		aspm_dis_mask |= PCI_EXP_LNKCTL_ASPM_L1;
-		break;
-	default:
-		return;
-	}
-
-	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc);
-	pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC;
-
-	if (parent) {
-		pcie_capability_read_word(parent, PCI_EXP_LNKCTL,
-					  &parent_aspmc);
-		parent_aspmc &= PCI_EXP_LNKCTL_ASPMC;
-	}
-
-	/* Nothing to do if the ASPM states to be disabled already are */
-	if (!(pdev_aspmc & aspm_dis_mask) &&
-	    (!parent || !(parent_aspmc & aspm_dis_mask)))
-		return;
-
-	dev_info(&pdev->dev, "Disabling ASPM %s %s\n",
-		 (aspm_dis_mask & pdev_aspmc & PCI_EXP_LNKCTL_ASPM_L0S) ?
-		 "L0s" : "",
-		 (aspm_dis_mask & pdev_aspmc & PCI_EXP_LNKCTL_ASPM_L1) ?
-		 "L1" : "");
-
-#ifdef CONFIG_PCIEASPM
-	if (locked)
-		pci_disable_link_state_locked(pdev, state);
-	else
-		pci_disable_link_state(pdev, state);
-
-	/* Double-check ASPM control.  If not disabled by the above, the
-	 * BIOS is preventing that from happening (or CONFIG_PCIEASPM is
-	 * not enabled); override by writing PCI config space directly.
-	 */
-	pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &pdev_aspmc);
-	pdev_aspmc &= PCI_EXP_LNKCTL_ASPMC;
-
-	if (!(aspm_dis_mask & pdev_aspmc))
-		return;
-#endif
-
-	/* Both device and parent should have the same ASPM setting.
-	 * Disable ASPM in downstream component first and then upstream.
-	 */
-	pcie_capability_clear_word(pdev, PCI_EXP_LNKCTL, aspm_dis_mask);
-
-	if (parent)
-		pcie_capability_clear_word(parent, PCI_EXP_LNKCTL,
-					   aspm_dis_mask);
-}
-
 /**
  * e1000e_disable_aspm - Disable ASPM states.
  * @pdev: pointer to PCI device struct
@@ -6848,7 +6775,7 @@ static void __e1000e_disable_aspm(struct pci_dev *pdev, u16 state, int locked)
  **/
 static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
 {
-	__e1000e_disable_aspm(pdev, state, 0);
+	pci_disable_link_state(pdev, state);
 }
 
 /**
@@ -6861,7 +6788,7 @@ static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state)
  **/
 static void e1000e_disable_aspm_locked(struct pci_dev *pdev, u16 state)
 {
-	__e1000e_disable_aspm(pdev, state, 1);
+	pci_disable_link_state_locked(pdev, state);
 }
 
 static int e1000e_pm_thaw(struct device *dev)
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:10:59 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:10:59 +0300
Subject: [PATCH v2 09/13] wifi: ath10k: Use pci_disable/enable_link_state()
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-10-ilpo.jarvinen@linux.intel.com>

ath10k driver adjusts ASPM state itself which leaves ASPM service
driver in PCI core unaware of the link state changes the driver
implemented.

Call pci_disable_link_state() and pci_enable_link_state() instead of
adjusting ASPMC field in LNKCTL directly in the driver and let PCI core
handle the ASPM state management.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/net/wireless/ath/ath10k/pci.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 23f366221939..64f7133ce122 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -1963,9 +1963,8 @@ static int ath10k_pci_hif_start(struct ath10k *ar)
 	ath10k_pci_irq_enable(ar);
 	ath10k_pci_rx_post(ar);
 
-	pcie_capability_clear_and_set_word(ar_pci->pdev, PCI_EXP_LNKCTL,
-					   PCI_EXP_LNKCTL_ASPMC,
-					   ar_pci->link_ctl & PCI_EXP_LNKCTL_ASPMC);
+	pci_enable_link_state(ar_pci->pdev, ar_pci->link_ctl &
+			      (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1));
 
 	return 0;
 }
@@ -2822,8 +2821,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar,
 
 	pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL,
 				  &ar_pci->link_ctl);
-	pcie_capability_clear_word(ar_pci->pdev, PCI_EXP_LNKCTL,
-				   PCI_EXP_LNKCTL_ASPMC);
+	pci_disable_link_state(ar_pci->pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	/*
 	 * Bring the target up cleanly.
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:11:00 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:11:00 +0300
Subject: [PATCH v2 10/13] wifi: ath11k: Use pci_disable/enable_link_state()
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-11-ilpo.jarvinen@linux.intel.com>

ath11k driver adjusts ASPM state itself which leaves ASPM service
driver in PCI core unaware of the link state changes the driver
implemented.

Call pci_disable_link_state() and pci_enable_link_state() instead of
adjusting ASPMC field in LNKCTL directly in the driver and let PCI core
handle the ASPM state management.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/net/wireless/ath/ath11k/pci.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/pci.c b/drivers/net/wireless/ath/ath11k/pci.c
index a5aa1857ec14..764cdf74b0e9 100644
--- a/drivers/net/wireless/ath/ath11k/pci.c
+++ b/drivers/net/wireless/ath/ath11k/pci.c
@@ -582,19 +582,15 @@ static void ath11k_pci_aspm_disable(struct ath11k_pci *ab_pci)
 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
 
 	/* disable L0s and L1 */
-	pcie_capability_clear_word(ab_pci->pdev, PCI_EXP_LNKCTL,
-				   PCI_EXP_LNKCTL_ASPMC);
-
+	pci_disable_link_state(ab_pci->pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 	set_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags);
 }
 
 static void ath11k_pci_aspm_restore(struct ath11k_pci *ab_pci)
 {
 	if (test_and_clear_bit(ATH11K_PCI_ASPM_RESTORE, &ab_pci->flags))
-		pcie_capability_clear_and_set_word(ab_pci->pdev, PCI_EXP_LNKCTL,
-						   PCI_EXP_LNKCTL_ASPMC,
-						   ab_pci->link_ctl &
-						   PCI_EXP_LNKCTL_ASPMC);
+		pci_enable_link_state(ab_pci->pdev, ab_pci->link_ctl &
+				      (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1));
 }
 
 static int ath11k_pci_power_up(struct ath11k_base *ab)
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:11:01 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:11:01 +0300
Subject: [PATCH v2 11/13] wifi: ath12k: Use pci_disable/enable_link_state()
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-12-ilpo.jarvinen@linux.intel.com>

ath12k driver adjusts ASPM state itself which leaves ASPM service
driver in PCI core unaware of the link state changes the driver
implemented.

Call pci_disable_link_state() and pci_enable_link_state() instead of
adjusting ASPMC field in LNKCTL directly in the driver and let PCI core
handle the ASPM state management.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/net/wireless/ath/ath12k/pci.c | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index fae5dfd6e9d7..9401f62476be 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -794,19 +794,15 @@ static void ath12k_pci_aspm_disable(struct ath12k_pci *ab_pci)
 		   u16_get_bits(ab_pci->link_ctl, PCI_EXP_LNKCTL_ASPM_L1));
 
 	/* disable L0s and L1 */
-	pcie_capability_clear_word(ab_pci->pdev, PCI_EXP_LNKCTL,
-				   PCI_EXP_LNKCTL_ASPMC);
-
+	pci_disable_link_state(ab_pci->pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 	set_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags);
 }
 
 static void ath12k_pci_aspm_restore(struct ath12k_pci *ab_pci)
 {
 	if (test_and_clear_bit(ATH12K_PCI_ASPM_RESTORE, &ab_pci->flags))
-		pcie_capability_clear_and_set_word(ab_pci->pdev, PCI_EXP_LNKCTL,
-						   PCI_EXP_LNKCTL_ASPMC,
-						   ab_pci->link_ctl &
-						   PCI_EXP_LNKCTL_ASPMC);
+		pci_enable_link_state(ab_pci->pdev, ab_pci->link_ctl &
+				      (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1));
 }
 
 static void ath12k_pci_kill_tasklets(struct ath12k_base *ab)
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:11:02 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:11:02 +0300
Subject: [PATCH v2 12/13] RDMA/hfi1: Use pci_disable/enable_link_state()
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-13-ilpo.jarvinen@linux.intel.com>

IB/hfi1 driver adjusts ASPM state itself which leaves ASPM service
driver in PCI core unaware of the link state changes the driver
implemented.

Call pci_disable_link_state() and pci_enable_link_state() instead of
adjusting ASPMC field in LNKCTL directly in the driver and let PCI core
handle the ASPM state management. Remove the functions that handled the
ASPM changes that are now unnecessary.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
Reviewed-by: Dean Luick <dean.luick at cornelisnetworks.com>
---
 drivers/infiniband/hw/hfi1/aspm.c | 38 +++----------------------------
 drivers/infiniband/hw/hfi1/pcie.c |  2 +-
 2 files changed, 4 insertions(+), 36 deletions(-)

diff --git a/drivers/infiniband/hw/hfi1/aspm.c b/drivers/infiniband/hw/hfi1/aspm.c
index a3c53be4072c..8e3fc1d4c9c6 100644
--- a/drivers/infiniband/hw/hfi1/aspm.c
+++ b/drivers/infiniband/hw/hfi1/aspm.c
@@ -54,45 +54,13 @@ static void aspm_hw_set_l1_ent_latency(struct hfi1_devdata *dd)
 	pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL3, reg32);
 }
 
-static void aspm_hw_enable_l1(struct hfi1_devdata *dd)
-{
-	struct pci_dev *parent = dd->pcidev->bus->self;
-
-	/*
-	 * If the driver does not have access to the upstream component,
-	 * it cannot support ASPM L1 at all.
-	 */
-	if (!parent)
-		return;
-
-	/* Enable ASPM L1 first in upstream component and then downstream */
-	pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
-					   PCI_EXP_LNKCTL_ASPMC,
-					   PCI_EXP_LNKCTL_ASPM_L1);
-	pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL,
-					   PCI_EXP_LNKCTL_ASPMC,
-					   PCI_EXP_LNKCTL_ASPM_L1);
-}
-
-void aspm_hw_disable_l1(struct hfi1_devdata *dd)
-{
-	struct pci_dev *parent = dd->pcidev->bus->self;
-
-	/* Disable ASPM L1 first in downstream component and then upstream */
-	pcie_capability_clear_and_set_word(dd->pcidev, PCI_EXP_LNKCTL,
-					   PCI_EXP_LNKCTL_ASPMC, 0x0);
-	if (parent)
-		pcie_capability_clear_and_set_word(parent, PCI_EXP_LNKCTL,
-						   PCI_EXP_LNKCTL_ASPMC, 0x0);
-}
-
 static  void aspm_enable(struct hfi1_devdata *dd)
 {
 	if (dd->aspm_enabled || aspm_mode == ASPM_MODE_DISABLED ||
 	    !dd->aspm_supported)
 		return;
 
-	aspm_hw_enable_l1(dd);
+	pci_enable_link_state(dd->pcidev, PCI_EXP_LNKCTL_ASPM_L1);
 	dd->aspm_enabled = true;
 }
 
@@ -101,7 +69,7 @@ static  void aspm_disable(struct hfi1_devdata *dd)
 	if (!dd->aspm_enabled || aspm_mode == ASPM_MODE_ENABLED)
 		return;
 
-	aspm_hw_disable_l1(dd);
+	pci_disable_link_state(dd->pcidev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 	dd->aspm_enabled = false;
 }
 
@@ -254,7 +222,7 @@ void aspm_init(struct hfi1_devdata *dd)
 	/* Start with ASPM disabled */
 	aspm_hw_set_l1_ent_latency(dd);
 	dd->aspm_enabled = false;
-	aspm_hw_disable_l1(dd);
+	pci_disable_link_state(dd->pcidev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	/* Now turn on ASPM if configured */
 	aspm_enable_all(dd);
diff --git a/drivers/infiniband/hw/hfi1/pcie.c b/drivers/infiniband/hw/hfi1/pcie.c
index 08732e1ac966..767f6cb770b6 100644
--- a/drivers/infiniband/hw/hfi1/pcie.c
+++ b/drivers/infiniband/hw/hfi1/pcie.c
@@ -1182,7 +1182,7 @@ int do_pcie_gen3_transition(struct hfi1_devdata *dd)
 	 * will be enabled if required later
 	 */
 	dd_dev_info(dd, "%s: clearing ASPM\n", __func__);
-	aspm_hw_disable_l1(dd);
+	pci_disable_link_state(dd->pcidev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 
 	/*
 	 * step 5f: clear DirectSpeedChange
-- 
2.30.2



From ilpo.jarvinen at linux.intel.com  Mon Sep 18 06:11:03 2023
From: ilpo.jarvinen at linux.intel.com (=?UTF-8?q?Ilpo=20J=C3=A4rvinen?=)
Date: Mon, 18 Sep 2023 16:11:03 +0300
Subject: [PATCH v2 13/13] misc: rtsx: Use pci_disable/enable_link_state()
In-Reply-To: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
Message-ID: <20230918131103.24119-14-ilpo.jarvinen@linux.intel.com>

rtsx driver adjusts ASPM state itself which leaves ASPM service
driver in PCI core unaware of the link state changes the driver
implemented.

Call pci_disable_link_state() and pci_enable_link_state() instead of
adjusting ASPMC field in LNKCTL directly in the driver and let PCI core
handle the ASPM state management.

Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
---
 drivers/misc/cardreader/rts5228.c  | 6 ++----
 drivers/misc/cardreader/rts5261.c  | 6 ++----
 drivers/misc/cardreader/rtsx_pcr.c | 8 +++++---
 3 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c
index f4ab09439da7..8d3216c64ad1 100644
--- a/drivers/misc/cardreader/rts5228.c
+++ b/drivers/misc/cardreader/rts5228.c
@@ -497,8 +497,7 @@ static void rts5228_enable_aspm(struct rtsx_pcr *pcr, bool enable)
 	val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
 	val |= (pcr->aspm_en & 0x02);
 	rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
-	pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
-					   PCI_EXP_LNKCTL_ASPMC, pcr->aspm_en);
+	pci_enable_link_state(pcr->pci, pcr->aspm_en);
 	pcr->aspm_enabled = enable;
 }
 
@@ -509,8 +508,7 @@ static void rts5228_disable_aspm(struct rtsx_pcr *pcr, bool enable)
 	if (pcr->aspm_enabled == enable)
 		return;
 
-	pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
-					   PCI_EXP_LNKCTL_ASPMC, 0);
+	pci_disable_link_state(pcr->pci, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 	mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
 	val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
 	rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c
index 94af6bf8a25a..f1ef15683a2f 100644
--- a/drivers/misc/cardreader/rts5261.c
+++ b/drivers/misc/cardreader/rts5261.c
@@ -578,8 +578,7 @@ static void rts5261_enable_aspm(struct rtsx_pcr *pcr, bool enable)
 
 	val |= (pcr->aspm_en & 0x02);
 	rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
-	pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
-					   PCI_EXP_LNKCTL_ASPMC, pcr->aspm_en);
+	pci_enable_link_state(pcr->pci, pcr->aspm_en);
 	pcr->aspm_enabled = enable;
 }
 
@@ -591,8 +590,7 @@ static void rts5261_disable_aspm(struct rtsx_pcr *pcr, bool enable)
 	if (pcr->aspm_enabled == enable)
 		return;
 
-	pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
-					   PCI_EXP_LNKCTL_ASPMC, 0);
+	pci_disable_link_state(pcr->pci, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
 	rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
 	rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
 	udelay(10);
diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c
index a3f4b52bb159..6efb792152f2 100644
--- a/drivers/misc/cardreader/rtsx_pcr.c
+++ b/drivers/misc/cardreader/rtsx_pcr.c
@@ -86,9 +86,11 @@ static void rtsx_comm_set_aspm(struct rtsx_pcr *pcr, bool enable)
 		return;
 
 	if (pcr->aspm_mode == ASPM_MODE_CFG) {
-		pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
-						PCI_EXP_LNKCTL_ASPMC,
-						enable ? pcr->aspm_en : 0);
+		if (enable)
+			pci_enable_link_state(pcr->pci, pcr->aspm_en);
+		else
+			pci_disable_link_state(pcr->pci, PCIE_LINK_STATE_L0S |
+							 PCIE_LINK_STATE_L1);
 	} else if (pcr->aspm_mode == ASPM_MODE_REG) {
 		if (pcr->aspm_en & 0x02)
 			rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, FORCE_ASPM_CTL0 |
-- 
2.30.2



From yunchuan at nfschina.com  Mon Sep 18 21:48:33 2023
From: yunchuan at nfschina.com (Wu Yunchuan)
Date: Tue, 19 Sep 2023 12:48:33 +0800
Subject: [PATCH v2 wireless-next 0/9] Remove unnecessary (void*) conversions
Message-ID: <20230919044832.522947-1-yunchuan@nfschina.com>

Remove all unnecessary (void*) conversions under the directory drivers/net/wireless/ath.

Changes in v2:
 - fix file path error in v1 patch 
 - change the prototype to remove the local variable(Jeff Johnson's suggestion.)[1]

[1] https://lore.kernel.org/all/5bb164e7-c147-64d1-031d-0ba20cfffa77 at nfschina.com/

Wu Yunchuan (9):
  wifi: ar5523: Remove unnecessary (void*) conversions
  carl9170: remove unnecessary (void*) conversions
  wifi: wcn36xx: remove unnecessary (void*) conversions
  wifi: ath5k: remove unnecessary (void*) conversions
  ath6kl: remove unnecessary (void*) conversions
  wifi: ath10k: Remove unnecessary (void*) conversions
  wifi: ath12k: Remove unnecessary (void*) conversions
  wifi: ath11k: remove unnecessary (void*) conversions
  wifi: ath9k: Remove unnecessary (void*) conversions

 drivers/net/wireless/ath/ar5523/ar5523.c      |  2 +-
 drivers/net/wireless/ath/ath10k/htt_tx.c      | 16 ++++-----
 drivers/net/wireless/ath/ath11k/dp.c          |  2 +-
 drivers/net/wireless/ath/ath11k/dp_rx.c       | 13 +++----
 drivers/net/wireless/ath/ath11k/hal.c         |  8 ++---
 drivers/net/wireless/ath/ath11k/hal_rx.c      | 17 ++++-----
 drivers/net/wireless/ath/ath11k/hal_tx.c      |  2 +-
 drivers/net/wireless/ath/ath11k/mac.c         |  4 +--
 drivers/net/wireless/ath/ath11k/spectral.c    |  2 +-
 drivers/net/wireless/ath/ath11k/wmi.c         |  6 ++--
 drivers/net/wireless/ath/ath12k/dp_mon.c      |  9 ++---
 drivers/net/wireless/ath/ath12k/dp_rx.c       |  2 +-
 drivers/net/wireless/ath/ath12k/dp_tx.c       |  5 ++-
 drivers/net/wireless/ath/ath5k/base.c         |  4 +--
 drivers/net/wireless/ath/ath5k/pci.c          |  4 +--
 drivers/net/wireless/ath/ath6kl/main.c        |  4 +--
 drivers/net/wireless/ath/ath6kl/txrx.c        |  2 +-
 .../wireless/ath/ath9k/ath9k_pci_owl_loader.c |  2 +-
 drivers/net/wireless/ath/ath9k/common-init.c  |  2 +-
 .../net/wireless/ath/ath9k/common-spectral.c  |  2 +-
 drivers/net/wireless/ath/ath9k/debug.c        |  2 +-
 drivers/net/wireless/ath/ath9k/hif_usb.c      | 10 +++---
 .../net/wireless/ath/ath9k/htc_drv_debug.c    |  2 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c | 36 +++++++++----------
 drivers/net/wireless/ath/ath9k/htc_hst.c      |  2 +-
 drivers/net/wireless/ath/ath9k/init.c         | 12 +++----
 drivers/net/wireless/ath/ath9k/link.c         |  2 +-
 drivers/net/wireless/ath/ath9k/pci.c          |  6 ++--
 drivers/net/wireless/ath/carl9170/usb.c       | 10 +++---
 drivers/net/wireless/ath/wcn36xx/dxe.c        |  6 ++--
 drivers/net/wireless/ath/wcn36xx/smd.c        | 20 +++++------
 drivers/net/wireless/ath/wcn36xx/testmode.c   |  2 +-
 32 files changed, 101 insertions(+), 117 deletions(-)

-- 
2.30.2



From yunchuan at nfschina.com  Mon Sep 18 21:51:42 2023
From: yunchuan at nfschina.com (Wu Yunchuan)
Date: Tue, 19 Sep 2023 12:51:42 +0800
Subject: [PATCH v2 wireless-next 7/9] wifi: ath12k: Remove unnecessary (void*) conversions
Message-ID: <20230919045142.524226-1-yunchuan@nfschina.com>

No need cast (void*) to (struct hal_rx_ppdu_end_user_stats *),
(struct ath12k_rx_desc_info *) or (struct hal_tx_msdu_ext_desc *).
Change the prototype to remove the local variable.

Signed-off-by: Wu Yunchuan <yunchuan at nfschina.com>
Suggested-by: Jeff Johnson <quic_jjohnson at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/dp_mon.c | 9 +++------
 drivers/net/wireless/ath/ath12k/dp_rx.c  | 2 +-
 drivers/net/wireless/ath/ath12k/dp_tx.c  | 5 ++---
 3 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/dp_mon.c b/drivers/net/wireless/ath/ath12k/dp_mon.c
index f1e57e98bdc6..86aa397c074f 100644
--- a/drivers/net/wireless/ath/ath12k/dp_mon.c
+++ b/drivers/net/wireless/ath/ath12k/dp_mon.c
@@ -13,8 +13,7 @@
 static void ath12k_dp_mon_rx_handle_ofdma_info(void *rx_tlv,
 					       struct hal_rx_user_status *rx_user_status)
 {
-	struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
-				(struct hal_rx_ppdu_end_user_stats *)rx_tlv;
+	struct hal_rx_ppdu_end_user_stats *ppdu_end_user = rx_tlv;
 
 	rx_user_status->ul_ofdma_user_v0_word0 =
 		__le32_to_cpu(ppdu_end_user->usr_resp_ref);
@@ -23,11 +22,9 @@ static void ath12k_dp_mon_rx_handle_ofdma_info(void *rx_tlv,
 }
 
 static void
-ath12k_dp_mon_rx_populate_byte_count(void *rx_tlv, void *ppduinfo,
-				     struct hal_rx_user_status *rx_user_status)
+ath12k_dp_mon_rx_populate_byte_count(const struct hal_rx_ppdu_end_user_stats *ppdu_end_user,
+				     void *ppduinfo, struct hal_rx_user_status *rx_user_status)
 {
-	struct hal_rx_ppdu_end_user_stats *ppdu_end_user =
-		(struct hal_rx_ppdu_end_user_stats *)rx_tlv;
 	u32 mpdu_ok_byte_count = __le32_to_cpu(ppdu_end_user->mpdu_ok_cnt);
 	u32 mpdu_err_byte_count = __le32_to_cpu(ppdu_end_user->mpdu_err_cnt);
 
diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c
index e6e64d437c47..ff5f66ca7783 100644
--- a/drivers/net/wireless/ath/ath12k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_rx.c
@@ -3730,7 +3730,7 @@ int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
 			continue;
 		}
 
-		desc_info = (struct ath12k_rx_desc_info *)err_info.rx_desc;
+		desc_info = err_info.rx_desc;
 
 		/* retry manual desc retrieval if hw cc is not done */
 		if (!desc_info) {
diff --git a/drivers/net/wireless/ath/ath12k/dp_tx.c b/drivers/net/wireless/ath/ath12k/dp_tx.c
index 8874c815d7fa..41a93320b036 100644
--- a/drivers/net/wireless/ath/ath12k/dp_tx.c
+++ b/drivers/net/wireless/ath/ath12k/dp_tx.c
@@ -106,11 +106,10 @@ static struct ath12k_tx_desc_info *ath12k_dp_tx_assign_buffer(struct ath12k_dp *
 	return desc;
 }
 
-static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab, void *cmd,
+static void ath12k_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab,
+					     struct hal_tx_msdu_ext_desc *tcl_ext_cmd,
 					     struct hal_tx_info *ti)
 {
-	struct hal_tx_msdu_ext_desc *tcl_ext_cmd = (struct hal_tx_msdu_ext_desc *)cmd;
-
 	tcl_ext_cmd->info0 = le32_encode_bits(ti->paddr,
 					      HAL_TX_MSDU_EXT_INFO0_BUF_PTR_LO);
 	tcl_ext_cmd->info1 = le32_encode_bits(0x0,
-- 
2.30.2



From quic_aisr at quicinc.com  Tue Sep 19 00:17:17 2023
From: quic_aisr at quicinc.com (Aishwarya R)
Date: Tue, 19 Sep 2023 12:47:17 +0530
Subject: [PATCH 0/7] wifi: ath12k: add support for 6 GHz AP for various power modes
Message-ID: <20230919071724.15505-1-quic_aisr@quicinc.com>

Add support for 6 GHz for various modes. Supports various power type of
AP(STANDARD_POWER_AP, INDOOR_AP, VERY_LOW_POWER_AP), power type of
STATION(DEFAULT_CLIENT, SUBORDINATE_CLIENT) and Power Spectral Density(PSD).

Implement the new rules for 6 GHz band in ath12k.
ath12k parse the transmit power envelope element in beacon of AP
and then set new wmi cmd WMI_VDEV_SET_TPC_POWER_CMDID to firmware
when connect to 6 GHz AP, also support backward compatibility with
firmware which not support new wmi cmd WMI_VDEV_SET_TPC_POWER_CMDID.

Aishwarya R (7):
  wifi: ath12k: add support to select 6 GHz Regulatory type
  wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type
  wifi: ath12k: get 6 GHz power type from HE operation element
  wifi: ath12k: save power spectral density(PSD) of regulatory rule
  wifi: ath12k: add parse of transmit power envelope element
  wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
  wifi: ath12k: send TPC power to firmware for 6 GHz VDEV

 drivers/net/wireless/ath/ath12k/core.h |  39 ++
 drivers/net/wireless/ath/ath12k/mac.c  | 515 ++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/mac.h  |   4 +
 drivers/net/wireless/ath/ath12k/reg.c  |  79 +++-
 drivers/net/wireless/ath/ath12k/reg.h  |   6 +-
 drivers/net/wireless/ath/ath12k/wmi.c  | 320 +++++++++++++--
 drivers/net/wireless/ath/ath12k/wmi.h  |  94 ++++-
 7 files changed, 1003 insertions(+), 54 deletions(-)

-- 
2.17.1



From quic_aisr at quicinc.com  Tue Sep 19 00:17:18 2023
From: quic_aisr at quicinc.com (Aishwarya R)
Date: Tue, 19 Sep 2023 12:47:18 +0530
Subject: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory type
In-Reply-To: <20230919071724.15505-1-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
Message-ID: <20230919071724.15505-2-quic_aisr@quicinc.com>

There are 3 types of regulatory rules for AP mode and 6 types for
STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
to select the exact reg rules.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/reg.c |  62 +++++++--
 drivers/net/wireless/ath/ath12k/reg.h |   6 +-
 drivers/net/wireless/ath/ath12k/wmi.c | 182 +++++++++++++++++++++++++-
 drivers/net/wireless/ath/ath12k/wmi.h |  27 +++-
 4 files changed, 257 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 6ede91ebc8e1..8501f77eee55 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -28,6 +28,21 @@ static const struct ieee80211_regdomain ath12k_world_regd = {
 	}
 };
 
+enum wmi_reg_6g_ap_type
+ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power power_type)
+{
+	switch (power_type) {
+	case IEEE80211_REG_LPI_AP:
+		return WMI_REG_INDOOR_AP;
+	case IEEE80211_REG_SP_AP:
+		return WMI_REG_STD_POWER_AP;
+	case IEEE80211_REG_VLP_AP:
+		return WMI_REG_VLP_AP;
+	default:
+		return WMI_REG_MAX_AP_TYPE;
+	}
+}
+
 static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2)
 {
 	const struct ieee80211_regdomain *regd;
@@ -562,14 +577,16 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
 
 struct ieee80211_regdomain *
 ath12k_reg_build_regd(struct ath12k_base *ab,
-		      struct ath12k_reg_info *reg_info, bool intersect)
+		      struct ath12k_reg_info *reg_info, bool intersect,
+		      enum wmi_vdev_type vdev_type,
+		      enum ieee80211_ap_reg_power power_type)
 {
 	struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
-	struct ath12k_reg_rule *reg_rule;
+	struct ath12k_reg_rule *reg_rule, *reg_rule_6ghz;
 	u8 i = 0, j = 0, k = 0;
 	u8 num_rules;
 	u16 max_bw;
-	u32 flags;
+	u32 flags, reg_6ghz_number, max_bw_6ghz;
 	char alpha2[3];
 
 	num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
@@ -578,8 +595,33 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
 	 * This can be updated to choose the combination dynamically based on AP
 	 * type and client type, after complete 6G regulatory support is added.
 	 */
-	if (reg_info->is_ext_reg_event)
-		num_rules += reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP];
+	if (reg_info->is_ext_reg_event) {
+		if (vdev_type == WMI_VDEV_TYPE_STA) {
+			enum wmi_reg_6g_ap_type ap_type;
+
+			ap_type = ath12k_ieee80211_ap_pwr_type_convert(power_type);
+
+			if (ap_type == WMI_REG_MAX_AP_TYPE)
+				ap_type = WMI_REG_INDOOR_AP;
+			reg_6ghz_number = reg_info->num_6g_reg_rules_cl
+					[ap_type][WMI_REG_DEFAULT_CLIENT];
+			if (reg_6ghz_number == 0) {
+				ap_type = WMI_REG_INDOOR_AP;
+				reg_6ghz_number = reg_info->num_6g_reg_rules_cl
+						[ap_type][WMI_REG_DEFAULT_CLIENT];
+			}
+			reg_rule_6ghz = reg_info->reg_rules_6g_client_ptr
+					[ap_type][WMI_REG_DEFAULT_CLIENT];
+			max_bw_6ghz = reg_info->max_bw_6g_client
+					[ap_type][WMI_REG_DEFAULT_CLIENT];
+		} else {
+			reg_6ghz_number = reg_info->num_6g_reg_rules_ap
+					[WMI_REG_INDOOR_AP];
+			reg_rule_6ghz = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP];
+			max_bw_6ghz = reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP];
+		}
+		num_rules += reg_6ghz_number;
+	}
 
 	if (!num_rules)
 		goto ret;
@@ -626,12 +668,10 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
 			 * per other BW rule flags we pass from here
 			 */
 			flags = NL80211_RRF_AUTO_BW;
-		} else if (reg_info->is_ext_reg_event &&
-			   reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP] &&
-			(k < reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP])) {
-			reg_rule = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP] + k++;
-			max_bw = min_t(u16, reg_rule->max_bw,
-				       reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP]);
+		} else if (reg_info->is_ext_reg_event && reg_6ghz_number &&
+			   (k < reg_6ghz_number)) {
+			reg_rule = reg_rule_6ghz + k++;
+			max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
 			flags = NL80211_RRF_AUTO_BW;
 		} else {
 			break;
diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h
index 56d009a47234..56324e30a358 100644
--- a/drivers/net/wireless/ath/ath12k/reg.h
+++ b/drivers/net/wireless/ath/ath12k/reg.h
@@ -88,7 +88,11 @@ void ath12k_reg_free(struct ath12k_base *ab);
 void ath12k_regd_update_work(struct work_struct *work);
 struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
 						  struct ath12k_reg_info *reg_info,
-						  bool intersect);
+						  bool intersect,
+						  enum wmi_vdev_type vdev_type,
+						  enum ieee80211_ap_reg_power power_type);
+enum wmi_reg_6g_ap_type
+ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power power_type);
 int ath12k_regd_update(struct ath12k *ar, bool init);
 int ath12k_reg_update_chan_list(struct ath12k *ar);
 
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index af910296c41e..1b9ce9a2ae96 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -4152,6 +4152,119 @@ static struct ath12k_reg_rule
 	return reg_rule_ptr;
 }
 
+static char *ath12k_cc_status_to_str(enum ath12k_reg_cc_code code)
+{
+	switch (code) {
+	case REG_SET_CC_STATUS_PASS:
+		return "REG_SET_CC_STATUS_PASS";
+	case REG_CURRENT_ALPHA2_NOT_FOUND:
+		return "REG_CURRENT_ALPHA2_NOT_FOUND";
+	case REG_INIT_ALPHA2_NOT_FOUND:
+		return "REG_INIT_ALPHA2_NOT_FOUND";
+	case REG_SET_CC_CHANGE_NOT_ALLOWED:
+		return "REG_SET_CC_CHANGE_NOT_ALLOWED";
+	case REG_SET_CC_STATUS_NO_MEMORY:
+		return "REG_SET_CC_STATUS_NO_MEMORY";
+	case REG_SET_CC_STATUS_FAIL:
+		return "REG_SET_CC_STATUS_FAIL";
+	default:
+		return "unknown cc status";
+	}
+};
+
+static char *ath12k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz domain_id)
+{
+	switch (domain_id) {
+	case FCC1_6GHZ:
+		return "FCC1_6GHZ";
+	case ETSI1_6GHZ:
+		return "ETSI1_6GHZ";
+	case ETSI2_6GHZ:
+		return "ETSI2_6GHZ";
+	case APL1_6GHZ:
+		return "APL1_6GHZ";
+	case FCC1_6GHZ_CL:
+		return "FCC1_6GHZ_CL";
+	default:
+		return "unknown domain id";
+	}
+}
+
+static char *ath12k_6ghz_client_type_to_str(enum wmi_reg_6g_client_type type)
+{
+	switch (type) {
+	case WMI_REG_DEFAULT_CLIENT:
+		return "DEFAULT CLIENT";
+	case WMI_REG_SUBORDINATE_CLIENT:
+		return "SUBORDINATE CLIENT";
+	default:
+		return "unknown client type";
+	}
+}
+
+static char *ath12k_6ghz_ap_type_to_str(enum wmi_reg_6g_ap_type type)
+{
+	switch (type) {
+	case WMI_REG_INDOOR_AP:
+		return "INDOOR AP";
+	case WMI_REG_STD_POWER_AP:
+		return "STANDARD POWER AP";
+	case WMI_REG_VLP_AP:
+		return "VERY LOW POWER AP";
+	default:
+		return "unknown AP type";
+	}
+}
+
+static char *ath12k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz sub_id)
+{
+	switch (sub_id) {
+	case FCC1_CLIENT_LPI_REGULAR_6GHZ:
+		return "FCC1_CLIENT_LPI_REGULAR_6GHZ";
+	case FCC1_CLIENT_SP_6GHZ:
+		return "FCC1_CLIENT_SP_6GHZ";
+	case FCC1_AP_LPI_6GHZ:
+		return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE";
+	case FCC1_AP_SP_6GHZ:
+		return "FCC1_AP_SP_6GHZ";
+	case ETSI1_LPI_6GHZ:
+		return "ETSI1_LPI_6GHZ";
+	case ETSI1_VLP_6GHZ:
+		return "ETSI1_VLP_6GHZ";
+	case ETSI2_LPI_6GHZ:
+		return "ETSI2_LPI_6GHZ";
+	case ETSI2_VLP_6GHZ:
+		return "ETSI2_VLP_6GHZ";
+	case APL1_LPI_6GHZ:
+		return "APL1_LPI_6GHZ";
+	case APL1_VLP_6GHZ:
+		return "APL1_VLP_6GHZ";
+	case EMPTY_6GHZ:
+		return "N/A";
+	default:
+		return "unknown sub reg id";
+	}
+}
+
+static void ath12k_print_reg_rule(struct ath12k_base *ab, char *prev,
+				  u32 num_reg_rules,
+				  struct ath12k_reg_rule *reg_rule_ptr)
+{
+	struct ath12k_reg_rule *reg_rule = reg_rule_ptr;
+	u32 count;
+
+	ath12k_dbg(ab, ATH12K_DBG_WMI, "%s reg rules number %d\n", prev, num_reg_rules);
+
+	for (count = 0; count < num_reg_rules; count++) {
+		ath12k_dbg(ab, ATH12K_DBG_WMI,
+			   "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d) (psd flag %d EIRP %d dB/MHz)\n",
+			   count + 1, reg_rule->start_freq, reg_rule->end_freq,
+			   reg_rule->max_bw, reg_rule->ant_gain, reg_rule->reg_power,
+			   reg_rule->flags, reg_rule->psd_flag, reg_rule->psd_eirp);
+		reg_rule++;
+	}
+}
+
 static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 						   struct sk_buff *skb,
 						   struct ath12k_reg_info *reg_info)
@@ -4163,7 +4276,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 	u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
 	u32 num_6g_reg_rules_cl[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
 	u32 total_reg_rules = 0;
-	int ret, i, j;
+	int ret, i, j, skip_6ghz_rules_in_5ghz_rules = 0;
 
 	ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n");
 
@@ -4265,6 +4378,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 	 * from 5G rules list.
 	 */
 	if (memcmp(reg_info->alpha2, "US", 2) == 0) {
+		ath12k_dbg(ab, ATH12K_DBG_WMI,
+			   "US 5 GHz reg rules number %d from fw",
+			   reg_info->num_5g_reg_rules);
+
+		if (reg_info->num_5g_reg_rules > REG_US_5G_NUM_REG_RULES)
+			skip_6ghz_rules_in_5ghz_rules = reg_info->num_5g_reg_rules -
+						    REG_US_5G_NUM_REG_RULES;
 		reg_info->num_5g_reg_rules = REG_US_5G_NUM_REG_RULES;
 		num_5g_reg_rules = reg_info->num_5g_reg_rules;
 	}
@@ -4297,6 +4417,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 		break;
 	}
 
+	ath12k_dbg(ab, ATH12K_DBG_WMI,
+		   "%s: status_code %s", __func__,
+		   ath12k_cc_status_to_str(reg_info->status_code));
+
 	reg_info->is_ext_reg_event = true;
 
 	reg_info->min_bw_2g = le32_to_cpu(ev->min_bw_2g);
@@ -4325,6 +4449,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 			le32_to_cpu(ev->max_bw_6g_client_vlp[i]);
 	}
 
+	ath12k_dbg(ab, ATH12K_DBG_WMI,
+		   "%s: status_code %s", __func__,
+		   ath12k_cc_status_to_str(reg_info->status_code));
+
 	ath12k_dbg(ab, ATH12K_DBG_WMI,
 		   "%s:cc_ext %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",
 		   __func__, reg_info->alpha2, reg_info->dfs_region,
@@ -4368,10 +4496,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 			ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");
 			return -ENOMEM;
 		}
+		ath12k_print_reg_rule(ab, "2 GHz",
+				      num_2g_reg_rules,
+				      reg_info->reg_rules_2g_ptr);
 	}
+	ext_wmi_reg_rule += num_2g_reg_rules;
 
 	if (num_5g_reg_rules) {
-		ext_wmi_reg_rule += num_2g_reg_rules;
 		reg_info->reg_rules_5g_ptr =
 			create_ext_reg_rules_from_wmi(num_5g_reg_rules,
 						      ext_wmi_reg_rule);
@@ -4381,9 +4512,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 			ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");
 			return -ENOMEM;
 		}
+		ath12k_print_reg_rule(ab, "5 GHz",
+				      num_5g_reg_rules,
+				      reg_info->reg_rules_5g_ptr);
 	}
 
-	ext_wmi_reg_rule += num_5g_reg_rules;
+	/* We have adjusted the number of 5 GHz reg rules via the hack above.
+	 * Here, we adjust that many extra rules which came with 5g reg rules
+	 * (for cc: US)
+	 *
+	 * NOTE: skip_6ghz_rules_in_5ghz_rules will be 0 for rest other cases.
+	 */
+	ext_wmi_reg_rule += num_5g_reg_rules + skip_6ghz_rules_in_5ghz_rules;
 
 	for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
 		reg_info->reg_rules_6g_ap_ptr[i] =
@@ -4396,10 +4536,17 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 			return -ENOMEM;
 		}
 
+		ath12k_print_reg_rule(ab, ath12k_6ghz_ap_type_to_str(i),
+				      num_6g_reg_rules_ap[i],
+				      reg_info->reg_rules_6g_ap_ptr[i]);
+
 		ext_wmi_reg_rule += num_6g_reg_rules_ap[i];
 	}
 
 	for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
+		ath12k_dbg(ab, ATH12K_DBG_WMI,
+			   "AP type %s", ath12k_6ghz_ap_type_to_str(j));
+
 		for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
 			reg_info->reg_rules_6g_client_ptr[j][i] =
 				create_ext_reg_rules_from_wmi(num_6g_reg_rules_cl[j][i],
@@ -4411,6 +4558,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 				return -ENOMEM;
 			}
 
+			ath12k_print_reg_rule(ab, ath12k_6ghz_client_type_to_str(i),
+					      num_6g_reg_rules_cl[j][i],
+					      reg_info->reg_rules_6g_client_ptr[j][i]);
+
 			ext_wmi_reg_rule += num_6g_reg_rules_cl[j][i];
 		}
 	}
@@ -4425,6 +4576,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 	reg_info->domain_code_6g_ap[WMI_REG_VLP_AP] =
 		le32_to_cpu(ev->domain_code_6g_ap_vlp);
 
+	ath12k_dbg(ab, ATH12K_DBG_WMI,
+		   "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s , sp %s , vlp %s\n",
+		   ath12k_6ghz_client_type_to_str(reg_info->client_type),
+		   reg_info->rnr_tpe_usable,
+		   reg_info->unspecified_ap_usable,
+		   ath12k_sub_reg_6ghz_to_str
+		   (le32_to_cpu(ev->domain_code_6g_ap_lpi)),
+		   ath12k_sub_reg_6ghz_to_str
+		   (le32_to_cpu(ev->domain_code_6g_ap_sp)),
+		   ath12k_sub_reg_6ghz_to_str
+		   (le32_to_cpu(ev->domain_code_6g_ap_vlp)));
+
 	for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
 		reg_info->domain_code_6g_client[WMI_REG_INDOOR_AP][i] =
 			le32_to_cpu(ev->domain_code_6g_client_lpi[i]);
@@ -4432,12 +4595,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
 			le32_to_cpu(ev->domain_code_6g_client_sp[i]);
 		reg_info->domain_code_6g_client[WMI_REG_VLP_AP][i] =
 			le32_to_cpu(ev->domain_code_6g_client_vlp[i]);
+		ath12k_dbg(ab, ATH12K_DBG_WMI,
+			   "6 GHz AP BW: lpi %d - %d sp %d - %d vlp %d - %d\n",
+			   ev->min_bw_6g_ap_lpi, ev->max_bw_6g_ap_lpi,
+			   ev->min_bw_6g_ap_sp, ev->max_bw_6g_ap_sp,
+			   ev->min_bw_6g_ap_vlp, ev->max_bw_6g_ap_vlp);
 	}
 
 	reg_info->domain_code_6g_super_id = le32_to_cpu(ev->domain_code_6g_super_id);
 
-	ath12k_dbg(ab, ATH12K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d",
-		   reg_info->client_type, reg_info->domain_code_6g_super_id);
+	ath12k_dbg(ab, ATH12K_DBG_WMI, "6 GHz client_type: %s 6 GHz super domain %s",
+		   ath12k_6ghz_client_type_to_str(reg_info->client_type),
+		   ath12k_super_reg_6ghz_to_str(reg_info->domain_code_6g_super_id));
 
 	ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n");
 
@@ -5192,7 +5361,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
 	    !ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
 		intersect = true;
 
-	regd = ath12k_reg_build_regd(ab, reg_info, intersect);
+	regd = ath12k_reg_build_regd(ab, reg_info, intersect,
+				     WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);
 	if (!regd) {
 		ath12k_warn(ab, "failed to build regd from reg_info\n");
 		goto fallback;
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 08a8c9e0f59f..966e6ba4e162 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2832,8 +2832,8 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg {
 #define REG_RULE_MAX_BW				0x0000ffff
 #define REG_RULE_REG_PWR			0x00ff0000
 #define REG_RULE_ANT_GAIN			0xff000000
-#define REG_RULE_PSD_INFO			BIT(2)
-#define REG_RULE_PSD_EIRP			0xffff0000
+#define REG_RULE_PSD_INFO                       BIT(0)
+#define REG_RULE_PSD_EIRP                       0xff0000
 
 #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
 #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
@@ -3844,6 +3844,29 @@ enum {
 	WMI_REG_SET_CC_STATUS_FAIL = 5,
 };
 
+enum reg_subdomains_6ghz {
+	EMPTY_6GHZ = 0x0,
+	FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01,
+	FCC1_CLIENT_SP_6GHZ = 0x02,
+	FCC1_AP_LPI_6GHZ = 0x03,
+	FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ,
+	FCC1_AP_SP_6GHZ = 0x04,
+	ETSI1_LPI_6GHZ = 0x10,
+	ETSI1_VLP_6GHZ = 0x11,
+	ETSI2_LPI_6GHZ = 0x12,
+	ETSI2_VLP_6GHZ = 0x13,
+	APL1_LPI_6GHZ = 0x20,
+	APL1_VLP_6GHZ = 0x21,
+};
+
+enum reg_super_domain_6ghz {
+	FCC1_6GHZ = 0x01,
+	ETSI1_6GHZ = 0x02,
+	ETSI2_6GHZ = 0x03,
+	APL1_6GHZ = 0x04,
+	FCC1_6GHZ_CL = 0x05,
+};
+
 #define WMI_REG_CLIENT_MAX 4
 
 struct wmi_reg_chan_list_cc_ext_event {
-- 
2.17.1



From quic_aisr at quicinc.com  Tue Sep 19 00:17:19 2023
From: quic_aisr at quicinc.com (Aishwarya R)
Date: Tue, 19 Sep 2023 12:47:19 +0530
Subject: [PATCH 2/7] wifi: ath12k: build 6 GHz regd based on vdev type and 6 GHz power type
In-Reply-To: <20230919071724.15505-1-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
Message-ID: <20230919071724.15505-3-quic_aisr@quicinc.com>

During bootup, WMI_REG_CHAN_LIST_CC_EXT_EVENTID event sent from firmware
at an early stage and it expects the 6 GHz power type for 6 GHz reg rules.
As power mode is not defined at this point host selects IEEE80211_REG_UNSET_AP
as default mode.

When interface is created, it updates regd rules accordingly.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/mac.c | 11 ++++
 drivers/net/wireless/ath/ath12k/mac.h |  1 +
 drivers/net/wireless/ath/ath12k/wmi.c | 75 ++++++++++++++++-----------
 drivers/net/wireless/ath/ath12k/wmi.h |  1 +
 4 files changed, 58 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index ee792822b411..5b9af264d305 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -563,6 +563,17 @@ struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id)
 	return NULL;
 }
 
+enum wmi_vdev_type ath12k_mac_get_ar_vdev_type(struct ath12k *ar)
+{
+	struct ath12k_vif *arvif;
+
+	list_for_each_entry(arvif, &ar->arvifs, list) {
+		return arvif->vdev_type;
+	}
+
+	return WMI_VDEV_TYPE_UNSPEC;
+}
+
 struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id)
 {
 	int i;
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 57f4295420bb..82f590004d05 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -66,6 +66,7 @@ struct ath12k_vif *ath12k_mac_get_arvif_by_vdev_id(struct ath12k_base *ab,
 						   u32 vdev_id);
 struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id);
 struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id);
+enum wmi_vdev_type ath12k_mac_get_ar_vdev_type(struct ath12k *ar);
 
 void ath12k_mac_drain_tx(struct ath12k *ar);
 void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 1b9ce9a2ae96..211bdb915173 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5299,26 +5299,15 @@ static bool ath12k_reg_is_world_alpha(char *alpha)
 	return alpha[0] == '0' && alpha[1] == '0';
 }
 
-static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
+static int ath12k_reg_handle_chan_list(struct ath12k_base *ab,
+				       struct ath12k_reg_info *reg_info,
+				       enum ieee80211_ap_reg_power power_type)
 {
-	struct ath12k_reg_info *reg_info = NULL;
-	struct ieee80211_regdomain *regd = NULL;
+	struct ieee80211_regdomain *regd;
 	bool intersect = false;
-	int ret = 0, pdev_idx, i, j;
+	int pdev_idx;
 	struct ath12k *ar;
-
-	reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
-	if (!reg_info) {
-		ret = -ENOMEM;
-		goto fallback;
-	}
-
-	ret = ath12k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);
-
-	if (ret) {
-		ath12k_warn(ab, "failed to extract regulatory info from received event\n");
-		goto fallback;
-	}
+	enum wmi_vdev_type vdev_type;
 
 	if (reg_info->status_code != REG_SET_CC_STATUS_PASS) {
 		/* In case of failure to set the requested ctry,
@@ -5326,7 +5315,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
 		 * and return from here.
 		 */
 		ath12k_warn(ab, "Failed to set the requested Country regulatory setting\n");
-		goto mem_free;
+		return -EINVAL;
 	}
 
 	pdev_idx = reg_info->phy_id;
@@ -5338,9 +5327,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
 		 */
 		if (ab->hw_params->single_pdev_only &&
 		    pdev_idx < ab->hw_params->num_rxmda_per_pdev)
-			goto mem_free;
-		else
-			goto fallback;
+			return -EINVAL;
+		goto fallback;
 	}
 
 	/* Avoid multiple overwrites to default regd, during core
@@ -5349,7 +5337,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
 	if (ab->default_regd[pdev_idx] && !ab->new_regd[pdev_idx] &&
 	    !memcmp(ab->default_regd[pdev_idx]->alpha2,
 		    reg_info->alpha2, 2))
-		goto mem_free;
+		return -EINVAL;
 
 	/* Intersect new rules with default regd if a new country setting was
 	 * requested, i.e a default regd was already set during initialization
@@ -5361,8 +5349,13 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
 	    !ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
 		intersect = true;
 
-	regd = ath12k_reg_build_regd(ab, reg_info, intersect,
-				     WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);
+	ar = ab->pdevs[pdev_idx].ar;
+	vdev_type = ath12k_mac_get_ar_vdev_type(ar);
+	ath12k_dbg(ab, ATH12K_DBG_WMI,
+		   "wmi handle chan list power type %d vdev type %d intersect %d\n",
+		    power_type, vdev_type, intersect);
+
+	regd = ath12k_reg_build_regd(ab, reg_info, intersect, vdev_type, power_type);
 	if (!regd) {
 		ath12k_warn(ab, "failed to build regd from reg_info\n");
 		goto fallback;
@@ -5394,7 +5387,7 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
 	ab->dfs_region = reg_info->dfs_region;
 	spin_unlock(&ab->base_lock);
 
-	goto mem_free;
+	return 0;
 
 fallback:
 	/* Fallback to older reg (by sending previous country setting
@@ -5406,17 +5399,39 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
 	 */
 	/* TODO: This is rare, but still should also be handled */
 	WARN_ON(1);
+	return -EINVAL;
+}
+
+static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *skb)
+{
+	struct ath12k_reg_info *reg_info;
+	int ret, i, j;
+
+	reg_info = kzalloc(sizeof(*reg_info), GFP_ATOMIC);
+	if (!reg_info)
+		return -ENOMEM;
+
+	ret = ath12k_pull_reg_chan_list_ext_update_ev(ab, skb, reg_info);
+
+	if (ret) {
+		ath12k_warn(ab, "failed to extract regulatory info from received event\n");
+		goto mem_free;
+	}
+
+	ret = ath12k_reg_handle_chan_list(ab, reg_info, IEEE80211_REG_UNSET_AP);
+	if (ret)
+		ath12k_warn(ab, "failed to process regulatory info from received event\n");
+
 mem_free:
 	if (reg_info) {
 		kfree(reg_info->reg_rules_2g_ptr);
 		kfree(reg_info->reg_rules_5g_ptr);
 		if (reg_info->is_ext_reg_event) {
-			for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++)
+			for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
 				kfree(reg_info->reg_rules_6g_ap_ptr[i]);
-
-			for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++)
-				for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++)
-					kfree(reg_info->reg_rules_6g_client_ptr[j][i]);
+				for (j = 0; j < WMI_REG_MAX_CLIENT_TYPE; j++)
+					kfree(reg_info->reg_rules_6g_client_ptr[i][j]);
+			}
 		}
 		kfree(reg_info);
 	}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 966e6ba4e162..c3b110af1272 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -4161,6 +4161,7 @@ struct ath12k_wmi_target_cap_arg {
 };
 
 enum wmi_vdev_type {
+	WMI_VDEV_TYPE_UNSPEC  = 0,
 	WMI_VDEV_TYPE_AP      = 1,
 	WMI_VDEV_TYPE_STA     = 2,
 	WMI_VDEV_TYPE_IBSS    = 3,
-- 
2.17.1



From quic_aisr at quicinc.com  Tue Sep 19 00:17:20 2023
From: quic_aisr at quicinc.com (Aishwarya R)
Date: Tue, 19 Sep 2023 12:47:20 +0530
Subject: [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation element
In-Reply-To: <20230919071724.15505-1-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
Message-ID: <20230919071724.15505-4-quic_aisr@quicinc.com>

When 6 GHz AP or STA is assigned a channel ctx, it needs to
extract the power type from HE operation element.
If unset power type is present, by default IEEE80211_REG_LPI_AP
power mode will be used.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 5b9af264d305..01f81b087fa2 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5823,6 +5823,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
 	struct ath12k_vif *arvif = (void *)vif->drv_priv;
 	int ret;
 	struct ath12k_wmi_peer_create_arg param;
+	enum ieee80211_ap_reg_power power_type;
 
 	mutex_lock(&ar->conf_mutex);
 
@@ -5830,6 +5831,16 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
 		   "mac chanctx assign ptr %pK vdev_id %i\n",
 		   ctx, arvif->vdev_id);
 
+	if (ar->supports_6ghz && ctx->def.chan->band == NL80211_BAND_6GHZ &&
+	    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
+	     arvif->vdev_type == WMI_VDEV_TYPE_AP)) {
+		power_type = vif->bss_conf.power_type;
+		ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx power type %d\n",
+			   power_type);
+		if (power_type == IEEE80211_REG_UNSET_AP)
+			power_type = IEEE80211_REG_LPI_AP;
+	}
+
 	/* for some targets bss peer must be created before vdev_start */
 	if (ab->hw_params->vdev_start_delay &&
 	    arvif->vdev_type != WMI_VDEV_TYPE_AP &&
-- 
2.17.1



From quic_aisr at quicinc.com  Tue Sep 19 00:17:21 2023
From: quic_aisr at quicinc.com (Aishwarya R)
Date: Tue, 19 Sep 2023 12:47:21 +0530
Subject: [PATCH 4/7] wifi: ath12k: save power spectral density(PSD) of regulatory rule
In-Reply-To: <20230919071724.15505-1-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
Message-ID: <20230919071724.15505-5-quic_aisr@quicinc.com>

Save the Power Spectral Density(PSD) report from firmware
to struct ieee80211_reg_rule. 6 GHz regulatory domains
introduces PSD. The PSD value of the regulatory rule should
be taken into effect for the ieee80211_channels falling into
that particular regulatory rule.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/reg.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
index 8501f77eee55..19681474026f 100644
--- a/drivers/net/wireless/ath/ath12k/reg.c
+++ b/drivers/net/wireless/ath/ath12k/reg.c
@@ -390,6 +390,10 @@ static void ath12k_reg_intersect_rules(struct ieee80211_reg_rule *rule1,
 
 	/* Use the flags of both the rules */
 	new_rule->flags = rule1->flags | rule2->flags;
+	if ((rule1->flags & NL80211_RRF_PSD) && (rule2->flags & NL80211_RRF_PSD))
+		new_rule->psd = min_t(s8, rule1->psd, rule2->psd);
+	else
+		new_rule->flags &= ~NL80211_RRF_PSD;
 
 	/* To be safe, lts use the max cac timeout of both rules */
 	new_rule->dfs_cac_ms = max_t(u32, rule1->dfs_cac_ms,
@@ -488,13 +492,14 @@ ath12k_reg_adjust_bw(u16 start_freq, u16 end_freq, u16 max_bw)
 static void
 ath12k_reg_update_rule(struct ieee80211_reg_rule *reg_rule, u32 start_freq,
 		       u32 end_freq, u32 bw, u32 ant_gain, u32 reg_pwr,
-		       u32 reg_flags)
+		       s8 psd, u32 reg_flags)
 {
 	reg_rule->freq_range.start_freq_khz = MHZ_TO_KHZ(start_freq);
 	reg_rule->freq_range.end_freq_khz = MHZ_TO_KHZ(end_freq);
 	reg_rule->freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw);
 	reg_rule->power_rule.max_antenna_gain = DBI_TO_MBI(ant_gain);
 	reg_rule->power_rule.max_eirp = DBM_TO_MBM(reg_pwr);
+	reg_rule->psd = psd;
 	reg_rule->flags = reg_flags;
 }
 
@@ -516,7 +521,7 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
 	ath12k_reg_update_rule(regd->reg_rules + i, reg_rule->start_freq,
 			       ETSI_WEATHER_RADAR_BAND_LOW, bw,
 			       reg_rule->ant_gain, reg_rule->reg_power,
-			       flags);
+			       reg_rule->psd_eirp, flags);
 
 	ath12k_dbg(ab, ATH12K_DBG_REG,
 		   "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
@@ -538,7 +543,7 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
 	ath12k_reg_update_rule(regd->reg_rules + i,
 			       ETSI_WEATHER_RADAR_BAND_LOW, end_freq, bw,
 			       reg_rule->ant_gain, reg_rule->reg_power,
-			       flags);
+			       reg_rule->psd_eirp, flags);
 
 	regd->reg_rules[i].dfs_cac_ms = ETSI_WEATHER_RADAR_BAND_CAC_TIMEOUT;
 
@@ -563,7 +568,7 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
 	ath12k_reg_update_rule(regd->reg_rules + i, ETSI_WEATHER_RADAR_BAND_HIGH,
 			       reg_rule->end_freq, bw,
 			       reg_rule->ant_gain, reg_rule->reg_power,
-			       flags);
+			       reg_rule->psd_eirp, flags);
 
 	ath12k_dbg(ab, ATH12K_DBG_REG,
 		   "\t%d. (%d - %d @ %d) (%d, %d) (%d ms) (FLAGS %d)\n",
@@ -673,6 +678,8 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
 			reg_rule = reg_rule_6ghz + k++;
 			max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
 			flags = NL80211_RRF_AUTO_BW;
+			if (reg_rule->psd_flag)
+				flags |= NL80211_RRF_PSD;
 		} else {
 			break;
 		}
@@ -683,7 +690,7 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
 				       reg_rule->start_freq,
 				       reg_rule->end_freq, max_bw,
 				       reg_rule->ant_gain, reg_rule->reg_power,
-				       flags);
+				       reg_rule->psd_eirp, flags);
 
 		/* Update dfs cac timeout if the dfs domain is ETSI and the
 		 * new rule covers weather radar band.
-- 
2.17.1



From quic_aisr at quicinc.com  Tue Sep 19 00:17:22 2023
From: quic_aisr at quicinc.com (Aishwarya R)
Date: Tue, 19 Sep 2023 12:47:22 +0530
Subject: [PATCH 5/7] wifi: ath12k: add parse of transmit power envelope element
In-Reply-To: <20230919071724.15505-1-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
Message-ID: <20230919071724.15505-6-quic_aisr@quicinc.com>

The transmit power envelope element has some fields for power, ath12k
should parse it according to IEEE Std 802.11ax??2021.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.h |  38 +++++
 drivers/net/wireless/ath/ath12k/mac.c  | 194 +++++++++++++++++++++++++
 2 files changed, 232 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 9439052a652e..01768fe79bd6 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -187,6 +187,43 @@ enum ath12k_monitor_flags {
 	ATH12K_FLAG_MONITOR_ENABLED,
 };
 
+/**
+ * struct chan_power_info - TPE containing power info per channel chunk
+ * @chan_cfreq: channel center freq (MHz)
+ * e.g.
+ * channel 37/20MHz,  it is 6135
+ * channel 37/40MHz,  it is 6125
+ * channel 37/80MHz,  it is 6145
+ * channel 37/160MHz, it is 6185
+ * @tx_power: transmit power (dBm)
+ */
+struct chan_power_info {
+	u16 chan_cfreq;
+	s8 tx_power;
+};
+
+/**
+ * struct reg_tpc_power_info - regulatory TPC power info
+ * @is_psd_power: is PSD power or not
+ * @eirp_power: Maximum EIRP power (dBm), valid only if power is PSD
+ * @power_type_6ghz: type of power (SP/LPI/VLP)
+ * @num_pwr_levels: number of power levels
+ * @reg_max: Array of maximum TX power (dBm) per PSD value
+ * @ap_constraint_power: AP constraint power (dBm)
+ * @tpe: TPE values processed from TPE IE
+ * @chan_power_info: power info to send to FW
+ */
+struct ath12k_reg_tpc_power_info {
+	bool is_psd_power;
+	u8 eirp_power;
+	enum wmi_reg_6g_ap_type power_type_6ghz;
+	u8 num_pwr_levels;
+	u8 reg_max[IEEE80211_MAX_NUM_PWR_LEVEL];
+	u8 ap_constraint_power;
+	s8 tpe[IEEE80211_MAX_NUM_PWR_LEVEL];
+	struct chan_power_info chan_power_info[IEEE80211_MAX_NUM_PWR_LEVEL];
+};
+
 struct ath12k_vif {
 	u32 vdev_id;
 	enum wmi_vdev_type vdev_type;
@@ -235,6 +272,7 @@ struct ath12k_vif {
 	bool rsnie_present;
 	bool wpaie_present;
 	struct ieee80211_chanctx_conf chanctx;
+	struct ath12k_reg_tpc_power_info reg_tpc_info;
 	u32 key_cipher;
 	u8 tx_encap_type;
 	u8 vdev_stats_id;
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 01f81b087fa2..0683b22137b0 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5812,6 +5812,197 @@ static int ath12k_start_vdev_delay(struct ieee80211_hw *hw,
 	return 0;
 }
 
+static u8 ath12k_mac_get_tpe_count(u8 txpwr_intrprt, u8 txpwr_cnt)
+{
+	switch (txpwr_intrprt) {
+	/* Refer "Table 9-276-Meaning of Maximum Transmit Power Count subfield
+	 * if the Maximum Transmit Power Interpretation subfield is 0 or 2" of
+	 * "IEEE Std 802.11ax 2021".
+	 */
+	case IEEE80211_TPE_LOCAL_EIRP:
+	case IEEE80211_TPE_REG_CLIENT_EIRP:
+		txpwr_cnt = txpwr_cnt <= 3 ? txpwr_cnt : 3;
+		txpwr_cnt = txpwr_cnt + 1;
+		break;
+	/* Refer "Table 9-277-Meaning of Maximum Transmit Power Count subfield
+	 * if Maximum Transmit Power Interpretation subfield is 1 or 3" of
+	 * "IEEE Std 802.11ax 2021".
+	 */
+	case IEEE80211_TPE_LOCAL_EIRP_PSD:
+	case IEEE80211_TPE_REG_CLIENT_EIRP_PSD:
+		txpwr_cnt = txpwr_cnt <= 4 ? txpwr_cnt : 4;
+		txpwr_cnt = txpwr_cnt ? (BIT(txpwr_cnt - 1)) : 1;
+		break;
+	}
+
+	return txpwr_cnt;
+}
+
+static u8 ath12k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
+{
+	u8 num_pwr_levels;
+
+	if (chan_def->chan->flags & IEEE80211_CHAN_PSD) {
+		switch (chan_def->width) {
+		case NL80211_CHAN_WIDTH_20:
+			num_pwr_levels = 1;
+			break;
+		case NL80211_CHAN_WIDTH_40:
+			num_pwr_levels = 2;
+			break;
+		case NL80211_CHAN_WIDTH_80:
+			num_pwr_levels = 4;
+			break;
+		case NL80211_CHAN_WIDTH_80P80:
+		case NL80211_CHAN_WIDTH_160:
+			num_pwr_levels = 8;
+			break;
+		default:
+			return 1;
+		}
+	} else {
+		switch (chan_def->width) {
+		case NL80211_CHAN_WIDTH_20:
+			num_pwr_levels = 1;
+			break;
+		case NL80211_CHAN_WIDTH_40:
+			num_pwr_levels = 2;
+			break;
+		case NL80211_CHAN_WIDTH_80:
+			num_pwr_levels = 3;
+			break;
+		case NL80211_CHAN_WIDTH_80P80:
+		case NL80211_CHAN_WIDTH_160:
+			num_pwr_levels = 4;
+			break;
+		default:
+			return 1;
+		}
+	}
+
+	return num_pwr_levels;
+}
+
+static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar,
+					struct ieee80211_vif *vif,
+					struct ieee80211_chanctx_conf *ctx)
+{
+	struct ath12k_base *ab = ar->ab;
+	struct ath12k_vif *arvif = (void *)vif->drv_priv;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+	struct ieee80211_tx_pwr_env *single_tpe;
+	enum wmi_reg_6g_client_type client_type;
+	int i;
+	u8 pwr_count, pwr_interpret, pwr_category;
+	u8 psd_index = 0, non_psd_index = 0, local_tpe_count = 0, reg_tpe_count = 0;
+	bool use_local_tpe, non_psd_set = false, psd_set = false;
+
+	client_type = WMI_REG_DEFAULT_CLIENT;
+
+	for (i = 0; i < bss_conf->tx_pwr_env_num; i++) {
+		single_tpe = &bss_conf->tx_pwr_env[i];
+		pwr_category = u8_get_bits(single_tpe->tx_power_info,
+					   IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
+		pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+					    IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+
+		if (pwr_category == client_type) {
+			if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP ||
+			    pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD)
+				local_tpe_count++;
+			else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP ||
+				 pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD)
+				reg_tpe_count++;
+		}
+	}
+
+	if (!reg_tpe_count && !local_tpe_count) {
+		ath12k_warn(ab,
+			    "no transmit power envelope match client power type %d\n",
+			    client_type);
+		return;
+	} else if (!reg_tpe_count) {
+		use_local_tpe = true;
+	} else {
+		use_local_tpe = false;
+	}
+	for (i = 0; i < bss_conf->tx_pwr_env_num; i++) {
+		single_tpe = &bss_conf->tx_pwr_env[i];
+		pwr_category = u8_get_bits(single_tpe->tx_power_info,
+					   IEEE80211_TX_PWR_ENV_INFO_CATEGORY);
+		pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+					    IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+
+		if (pwr_category != client_type)
+			continue;
+
+		/* get local transmit power envelope */
+		if (use_local_tpe) {
+			if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP) {
+				non_psd_index = i;
+				non_psd_set = true;
+			} else if (pwr_interpret == IEEE80211_TPE_LOCAL_EIRP_PSD) {
+				psd_index = i;
+				psd_set = true;
+			}
+		/* get regulatory transmit power envelope */
+		} else {
+			if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP) {
+				non_psd_index = i;
+				non_psd_set = true;
+			} else if (pwr_interpret == IEEE80211_TPE_REG_CLIENT_EIRP_PSD) {
+				psd_index = i;
+				psd_set = true;
+			}
+		}
+	}
+
+	if (non_psd_set && !psd_set) {
+		single_tpe = &bss_conf->tx_pwr_env[non_psd_index];
+		pwr_count = u8_get_bits(single_tpe->tx_power_info,
+					IEEE80211_TX_PWR_ENV_INFO_COUNT);
+		pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+					    IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+		arvif->reg_tpc_info.is_psd_power = false;
+		arvif->reg_tpc_info.eirp_power = 0;
+
+		arvif->reg_tpc_info.num_pwr_levels =
+			ath12k_mac_get_tpe_count(pwr_interpret, pwr_count);
+		for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
+			ath12k_dbg(ab, ATH12K_DBG_MAC,
+				   "non PSD power[%d] : %d\n",
+				   i, single_tpe->tx_power[i]);
+		arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2;
+		}
+	}
+	if (psd_set) {
+		single_tpe = &bss_conf->tx_pwr_env[psd_index];
+		pwr_count = u8_get_bits(single_tpe->tx_power_info,
+					IEEE80211_TX_PWR_ENV_INFO_COUNT);
+		pwr_interpret = u8_get_bits(single_tpe->tx_power_info,
+					    IEEE80211_TX_PWR_ENV_INFO_INTERPRET);
+		arvif->reg_tpc_info.is_psd_power = true;
+
+		if (pwr_count == 0) {
+			ath12k_dbg(ab, ATH12K_DBG_MAC,
+				   "TPE PSD power : %d\n", single_tpe->tx_power[0]);
+			arvif->reg_tpc_info.num_pwr_levels =
+				ath12k_mac_get_num_pwr_levels(&ctx->def);
+			for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++)
+				arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[0] / 2;
+		} else {
+			arvif->reg_tpc_info.num_pwr_levels =
+				ath12k_mac_get_tpe_count(pwr_interpret, pwr_count);
+			for (i = 0; i < arvif->reg_tpc_info.num_pwr_levels; i++) {
+				ath12k_dbg(ab, ATH12K_DBG_MAC,
+					   "TPE PSD power[%d] : %d\n",
+					   i, single_tpe->tx_power[i]);
+			arvif->reg_tpc_info.tpe[i] = single_tpe->tx_power[i] / 2;
+			}
+		}
+	}
+}
+
 static int
 ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
 				 struct ieee80211_vif *vif,
@@ -5839,6 +6030,9 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
 			   power_type);
 		if (power_type == IEEE80211_REG_UNSET_AP)
 			power_type = IEEE80211_REG_LPI_AP;
+
+		if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
+			ath12k_mac_parse_tx_pwr_env(ar, vif, ctx);
 	}
 
 	/* for some targets bss peer must be created before vdev_start */
-- 
2.17.1



From quic_aisr at quicinc.com  Tue Sep 19 00:17:23 2023
From: quic_aisr at quicinc.com (Aishwarya R)
Date: Tue, 19 Sep 2023 12:47:23 +0530
Subject: [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power wmi command
In-Reply-To: <20230919071724.15505-1-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
Message-ID: <20230919071724.15505-7-quic_aisr@quicinc.com>

Prepare the parameters which is needed for wmi cmd
vdev_set_tpc_power.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/core.h |   1 +
 drivers/net/wireless/ath/ath12k/mac.c  | 273 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/mac.h  |   3 +
 drivers/net/wireless/ath/ath12k/wmi.c  |   1 +
 drivers/net/wireless/ath/ath12k/wmi.h  |   1 +
 5 files changed, 279 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 01768fe79bd6..e9bf87f740cd 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -606,6 +606,7 @@ struct ath12k {
 	bool monitor_vdev_created;
 	bool monitor_started;
 	int monitor_vdev_id;
+	s8 max_allowed_tx_power;
 };
 
 struct ath12k_band_cap {
diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 0683b22137b0..35bd472267c1 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -5883,6 +5883,279 @@ static u8 ath12k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
 	return num_pwr_levels;
 }
 
+static u16 ath12k_mac_get_6ghz_start_frequency(struct cfg80211_chan_def *chan_def)
+{
+	u16 diff_seq;
+
+	/* It is to get the lowest channel number's center frequency of the chan.
+	 * For example,
+	 * bandwidth=40 MHz, center frequency is 5965, lowest channel is 1
+	 * with center frequency 5955, its diff is 5965 - 5955 = 10.
+	 * bandwidth=80 MHz, center frequency is 5985, lowest channel is 1
+	 * with center frequency 5955, its diff is 5985 - 5955 = 30.
+	 * bandwidth=160 MHz, center frequency is 6025, lowest channel is 1
+	 * with center frequency 5955, its diff is 6025 - 5955 = 70.
+	 */
+	switch (chan_def->width) {
+	case NL80211_CHAN_WIDTH_160:
+		diff_seq = 70;
+		break;
+	case NL80211_CHAN_WIDTH_80:
+	case NL80211_CHAN_WIDTH_80P80:
+		diff_seq = 30;
+		break;
+	case NL80211_CHAN_WIDTH_40:
+		diff_seq = 10;
+		break;
+	default:
+		diff_seq = 0;
+	}
+
+	return chan_def->center_freq1 - diff_seq;
+}
+
+static u16 ath12k_mac_get_seg_freq(struct cfg80211_chan_def *chan_def,
+				   u16 start_seq, u8 seq)
+{
+	u16 seg_seq;
+
+	/* It is to get the center frequency of the specific bandwidth.
+	 * start_seq means the lowest channel number's center frequency.
+	 * seq 0/1/2/3 means 20 MHz/40 MHz/80 MHz/160 MHz & 80P80.
+	 * For example,
+	 * lowest channel is 1, its center frequency 5955,
+	 * center frequency is 5955 when bandwidth=20 MHz, its diff is 5955 - 5955 = 0.
+	 * lowest channel is 1, its center frequency 5955,
+	 * center frequency is 5965 when bandwidth=40 MHz, its diff is 5965 - 5955 = 10.
+	 * lowest channel is 1, its center frequency 5955,
+	 * center frequency is 5985 when bandwidth=80 MHz, its diff is 5985 - 5955 = 30.
+	 * lowest channel is 1, its center frequency 5955,
+	 * center frequency is 6025 when bandwidth=160 MHz, its diff is 6025 - 5955 = 70.
+	 */
+	if (chan_def->width == NL80211_CHAN_WIDTH_80P80 && seq == 3)
+		return chan_def->center_freq2;
+
+	seg_seq = 10 * (BIT(seq) - 1);
+	return seg_seq + start_seq;
+}
+
+static void ath12k_mac_get_psd_channel(struct ath12k *ar,
+				       u16 step_freq,
+				       u16 *start_freq,
+				       u16 *center_freq,
+				       u8 i,
+				       struct ieee80211_channel **temp_chan,
+				       s8 *tx_power)
+{
+	/* It is to get the center frequency for each 20 MHz.
+	 * For example, if the chan is 160 MHz and center frequency is 6025,
+	 * then it include 8 channels, they are 1/5/9/13/17/21/25/29,
+	 * channel number 1's center frequency is 5955, it is parameter start_freq.
+	 * parameter i is the step of the 8 channels. i is 0~7 for the 8 channels.
+	 * the channel 1/5/9/13/17/21/25/29 maps i=0/1/2/3/4/5/6/7,
+	 * and maps its center frequency is 5955/5975/5995/6015/6035/6055/6075/6095,
+	 * the gap is 20 for each channel, parameter step_freq means the gap.
+	 * after get the center frequency of each channel, it is easy to find the
+	 * struct ieee80211_channel of it and get the max_reg_power.
+	 */
+	*center_freq = *start_freq + i * step_freq;
+	*temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
+	*tx_power = (*temp_chan)->max_reg_power;
+}
+
+static void ath12k_mac_get_eirp_power(struct ath12k *ar,
+				      u16 *start_freq,
+				      u16 *center_freq,
+				      u8 i,
+				      struct ieee80211_channel **temp_chan,
+				      struct cfg80211_chan_def *def,
+				      s8 *tx_power)
+{
+	/* It is to get the center frequency for 20 MHz/40 MHz/80 MHz/
+	 * 160 MHz & 80P80 bandwidth, and then plus 10 to the center frequency,
+	 * it is the center frequency of a channel number.
+	 * For example, when configured channel number is 1.
+	 * center frequency is 5965 when bandwidth=40 MHz, after plus 10, it is 5975,
+	 * then it is channel number 5.
+	 * center frequency is 5985 when bandwidth=80 MHz, after plus 10, it is 5995,
+	 * then it is channel number 9.
+	 * center frequency is 6025 when bandwidth=160 MHz, after plus 10, it is 6035,
+	 * then it is channel number 17.
+	 * after get the center frequency of each channel, it is easy to find the
+	 * struct ieee80211_channel of it and get the max_reg_power.
+	 */
+	*center_freq = ath12k_mac_get_seg_freq(def, *start_freq, i);
+	*center_freq += 10;
+	*temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
+	*tx_power = (*temp_chan)->max_reg_power;
+}
+
+void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_chanctx_conf *ctx)
+{
+	struct ath12k_base *ab = ar->ab;
+	struct ath12k_vif *arvif = (void *)vif->drv_priv;
+	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+	struct ath12k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info;
+	struct ieee80211_channel *chan, *temp_chan;
+	u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction;
+	bool is_psd_power = false, is_tpe_present = false;
+	s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL],
+		psd_power, tx_power = 0, eirp_power = 0;
+	u16 start_freq = 0, center_freq = 0;
+
+	chan = ctx->def.chan;
+	start_freq = ath12k_mac_get_6ghz_start_frequency(&ctx->def);
+	pwr_reduction = bss_conf->pwr_reduction;
+
+	if (arvif->vdev_type == WMI_VDEV_TYPE_STA &&
+	    arvif->reg_tpc_info.num_pwr_levels) {
+		is_tpe_present = true;
+		num_pwr_levels = arvif->reg_tpc_info.num_pwr_levels;
+	} else {
+		num_pwr_levels = ath12k_mac_get_num_pwr_levels(&ctx->def);
+	}
+
+	for (pwr_lvl_idx = 0; pwr_lvl_idx < num_pwr_levels; pwr_lvl_idx++) {
+		/* STA received TPE IE*/
+		if (is_tpe_present) {
+			/* local power is PSD power*/
+			if (chan->flags & IEEE80211_CHAN_PSD) {
+				/* Connecting AP is psd power */
+				if (reg_tpc_info->is_psd_power) {
+					is_psd_power = true;
+					ath12k_mac_get_psd_channel(ar, 20,
+								   &start_freq,
+								   &center_freq,
+								   pwr_lvl_idx,
+								   &temp_chan,
+								   &tx_power);
+					psd_power = temp_chan->psd;
+					eirp_power = tx_power;
+					max_tx_power[pwr_lvl_idx] =
+						min_t(s8,
+						      psd_power,
+						      reg_tpc_info->tpe[pwr_lvl_idx]);
+				/* Connecting AP is not psd power */
+				} else {
+					ath12k_mac_get_eirp_power(ar,
+								  &start_freq,
+								  &center_freq,
+								  pwr_lvl_idx,
+								  &temp_chan,
+								  &ctx->def,
+								  &tx_power);
+					psd_power = temp_chan->psd;
+					/* convert psd power to EIRP power based
+					 * on channel width
+					 */
+					tx_power =
+						min_t(s8, tx_power,
+						      psd_power + 13 + pwr_lvl_idx * 3);
+					max_tx_power[pwr_lvl_idx] =
+						min_t(s8,
+						      tx_power,
+						      reg_tpc_info->tpe[pwr_lvl_idx]);
+			}
+			/* local power is not PSD power */
+			} else {
+				/* Connecting AP is psd power */
+				if (reg_tpc_info->is_psd_power) {
+					is_psd_power = true;
+					ath12k_mac_get_psd_channel(ar, 20,
+								   &start_freq,
+								   &center_freq,
+								   pwr_lvl_idx,
+								   &temp_chan,
+								   &tx_power);
+					eirp_power = tx_power;
+					max_tx_power[pwr_lvl_idx] =
+						reg_tpc_info->tpe[pwr_lvl_idx];
+				/* Connecting AP is not psd power */
+				} else {
+					ath12k_mac_get_eirp_power(ar,
+								  &start_freq,
+								  &center_freq,
+								  pwr_lvl_idx,
+								  &temp_chan,
+								  &ctx->def,
+								  &tx_power);
+					max_tx_power[pwr_lvl_idx] =
+						min_t(s8,
+						      tx_power,
+						      reg_tpc_info->tpe[pwr_lvl_idx]);
+				}
+		}
+		/* STA not received TPE IE */
+		} else {
+			/* local power is PSD power*/
+			if (chan->flags & IEEE80211_CHAN_PSD) {
+				is_psd_power = true;
+				ath12k_mac_get_psd_channel(ar, 20,
+							   &start_freq,
+							   &center_freq,
+							   pwr_lvl_idx,
+							   &temp_chan,
+							   &tx_power);
+				psd_power = temp_chan->psd;
+				eirp_power = tx_power;
+				max_tx_power[pwr_lvl_idx] = psd_power;
+			} else {
+				ath12k_mac_get_eirp_power(ar,
+							  &start_freq,
+							  &center_freq,
+							  pwr_lvl_idx,
+							  &temp_chan,
+							  &ctx->def,
+							  &tx_power);
+				max_tx_power[pwr_lvl_idx] = tx_power;
+			}
+		}
+
+		if (is_psd_power) {
+			/* If AP local power constraint is present */
+			if (pwr_reduction)
+				eirp_power = eirp_power - pwr_reduction;
+
+			/* If FW updated max tx power is non zero, then take the min of
+			 * firmware updated ap tx power
+			 * and max power derived from above mentioned parameters.
+			 */
+			ath12k_dbg(ab, ATH12K_DBG_MAC,
+				   "eirp power : %d firmware report power : %d\n",
+				   eirp_power, ar->max_allowed_tx_power);
+			if ((ar->max_allowed_tx_power) && (ab->hw_params->idle_ps))
+				eirp_power = min_t(s8,
+						   eirp_power,
+						   ar->max_allowed_tx_power);
+		} else {
+			/* If AP local power constraint is present */
+			if (pwr_reduction)
+				max_tx_power[pwr_lvl_idx] =
+					max_tx_power[pwr_lvl_idx] - pwr_reduction;
+			/* If FW updated max tx power is non zero, then take the min of
+			 * firmware updated ap tx power
+			 * and max power derived from above mentioned parameters.
+			 */
+			if ((ar->max_allowed_tx_power) && (ab->hw_params->idle_ps))
+				max_tx_power[pwr_lvl_idx] =
+					min_t(s8,
+					      max_tx_power[pwr_lvl_idx],
+					      ar->max_allowed_tx_power);
+		}
+		reg_tpc_info->chan_power_info[pwr_lvl_idx].chan_cfreq = center_freq;
+		reg_tpc_info->chan_power_info[pwr_lvl_idx].tx_power =
+			max_tx_power[pwr_lvl_idx];
+	}
+
+	reg_tpc_info->num_pwr_levels = num_pwr_levels;
+	reg_tpc_info->is_psd_power = is_psd_power;
+	reg_tpc_info->eirp_power = eirp_power;
+	reg_tpc_info->power_type_6ghz =
+		ath12k_ieee80211_ap_pwr_type_convert(vif->bss_conf.power_type);
+}
+
 static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar,
 					struct ieee80211_vif *vif,
 					struct ieee80211_chanctx_conf *ctx)
diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
index 82f590004d05..ce2ce7f324d7 100644
--- a/drivers/net/wireless/ath/ath12k/mac.h
+++ b/drivers/net/wireless/ath/ath12k/mac.h
@@ -68,6 +68,9 @@ struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id)
 struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id);
 enum wmi_vdev_type ath12k_mac_get_ar_vdev_type(struct ath12k *ar);
 
+void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_chanctx_conf *ctx);
 void ath12k_mac_drain_tx(struct ath12k *ar);
 void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
 int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 211bdb915173..5bfca2513730 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -5588,6 +5588,7 @@ static void ath12k_vdev_start_resp_event(struct ath12k_base *ab, struct sk_buff
 	}
 
 	ar->last_wmi_vdev_start_status = 0;
+	ar->max_allowed_tx_power = le32_to_cpu(vdev_start_resp.max_allowed_tx_power);
 
 	status = le32_to_cpu(vdev_start_resp.status);
 
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c3b110af1272..9f24f8ded52f 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -3796,6 +3796,7 @@ struct wmi_vdev_start_resp_event {
 	};
 	__le32 cfgd_tx_streams;
 	__le32 cfgd_rx_streams;
+	__le32 max_allowed_tx_power;
 } __packed;
 
 /* VDEV start response status codes */
-- 
2.17.1



From quic_aisr at quicinc.com  Tue Sep 19 00:17:24 2023
From: quic_aisr at quicinc.com (Aishwarya R)
Date: Tue, 19 Sep 2023 12:47:24 +0530
Subject: [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz VDEV
In-Reply-To: <20230919071724.15505-1-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
Message-ID: <20230919071724.15505-8-quic_aisr@quicinc.com>

When STATION is connected to a 6 GHz AP, or when AP boots up, it has
2 ways to configure the power limit to firmware. Currently it
sends 2 wmi command WMI_PDEV_PARAM_TXPOWER_LIMIT2G/
WMI_PDEV_PARAM_TXPOWER_LIMIT5G to firmware.

Add support to send WMI_VDEV_SET_TPC_POWER_CMDID to firmware which
include more parameters for power control. When firmware support
SERVICE_EXT_TPC_REG, it means firmware support this feature, then ath12k
discard BSS_CHANGED_TXPOWER flag from mac80211 which is used to the first
way for 6 GHz band.

The second way is to prepare the parameter for wmi command
WMI_VDEV_SET_TPC_POWER_CMDID and send the firmware after vdev start
response success from firmware.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/mac.c | 25 +++++++++-
 drivers/net/wireless/ath/ath12k/wmi.c | 67 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h | 36 +++++++++++++-
 3 files changed, 125 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 35bd472267c1..5505f933a4e1 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2467,8 +2467,18 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 		ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev_id %i txpower %d\n",
 			   arvif->vdev_id, info->txpower);
 
-		arvif->txpower = info->txpower;
-		ath12k_mac_txpower_recalc(ar);
+		if (ar->supports_6ghz && info->chandef.chan &&
+		    info->chandef.chan->band == NL80211_BAND_6GHZ &&
+		    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
+		     arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
+		     test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT,
+			      ar->ab->wmi_ab.svc_map)) {
+			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+				   "discard tx power, change to set TPC power\n");
+		} else {
+			arvif->txpower = info->txpower;
+			ath12k_mac_txpower_recalc(ar);
+		}
 	}
 
 	if (changed & BSS_CHANGED_MCAST_RATE &&
@@ -5519,6 +5529,16 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
 		return ret;
 	}
 
+	if (ar->supports_6ghz &&
+	    chandef->chan->band == NL80211_BAND_6GHZ &&
+	    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
+	     arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
+	     test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map)) {
+		ath12k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx);
+		ath12k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id,
+						   &arvif->reg_tpc_info);
+	}
+
 	ar->num_started_vdevs++;
 	ath12k_dbg(ab, ATH12K_DBG_MAC,  "vdev %pM started, vdev_id %d\n",
 		   arvif->vif->addr, arvif->vdev_id);
@@ -6304,6 +6324,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
 		if (power_type == IEEE80211_REG_UNSET_AP)
 			power_type = IEEE80211_REG_LPI_AP;
 
+		arvif->chanctx = *ctx;
 		if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
 			ath12k_mac_parse_tx_pwr_env(ar, vif, ctx);
 	}
diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
index 5bfca2513730..582c7e80c76b 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.c
+++ b/drivers/net/wireless/ath/ath12k/wmi.c
@@ -2311,6 +2311,73 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
 	return ret;
 }
 
+int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
+				       u32 vdev_id,
+				       struct ath12k_reg_tpc_power_info *param)
+{
+	struct ath12k_wmi_pdev *wmi = ar->wmi;
+	struct wmi_vdev_set_tpc_power_cmd *cmd;
+	struct wmi_vdev_ch_power_info_params *ch;
+	struct sk_buff *skb;
+	struct wmi_tlv *tlv;
+	u8 *ptr;
+	int i, ret, len;
+
+	len = sizeof(*cmd) + TLV_HDR_SIZE;
+	len += (sizeof(*ch) * param->num_pwr_levels);
+
+	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
+	if (!skb)
+		return -ENOMEM;
+
+	ptr = skb->data;
+
+	cmd = (struct wmi_vdev_set_tpc_power_cmd *)ptr;
+	cmd->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
+						 WMI_TAG_VDEV_SET_TPC_POWER_CMD) |
+				      FIELD_PREP(WMI_TLV_LEN,
+						 sizeof(*cmd) - TLV_HDR_SIZE));
+	cmd->vdev_id = cpu_to_le32(vdev_id);
+	cmd->psd_power = cpu_to_le32(param->is_psd_power);
+	cmd->eirp_power = cpu_to_le32(param->eirp_power);
+	cmd->power_type_6ghz = cpu_to_le32(param->power_type_6ghz);
+	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+		   "wmi TPC vdev_id: %d is_psd_power: %d eirp_power: %d power_type_6ghz: %d\n",
+		   vdev_id, param->is_psd_power, param->eirp_power,
+		   param->power_type_6ghz);
+
+	ptr += sizeof(*cmd);
+	tlv = (struct wmi_tlv *)ptr;
+	tlv->header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
+				  FIELD_PREP(WMI_TLV_LEN,
+					     param->num_pwr_levels * sizeof(*ch)));
+
+	ptr += TLV_HDR_SIZE;
+	ch = (struct wmi_vdev_ch_power_info_params *)ptr;
+
+	for (i = 0; i < param->num_pwr_levels; i++, ch++) {
+		ch->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
+							WMI_TAG_VDEV_CH_POWER_INFO) |
+					     FIELD_PREP(WMI_TLV_LEN,
+							sizeof(*ch) - TLV_HDR_SIZE));
+
+		ch->chan_cfreq = cpu_to_le32(param->chan_power_info[i].chan_cfreq);
+		ch->tx_power = cpu_to_le32(param->chan_power_info[i].tx_power);
+
+		ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
+			   "wmi TPC chan_cfreq: %d , tx_power: %d\n",
+			   ch->chan_cfreq, ch->tx_power);
+	}
+
+	ret = ath12k_wmi_cmd_send(wmi, skb,
+				  WMI_VDEV_SET_TPC_POWER_CMDID);
+	if (ret) {
+		ath12k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n");
+		dev_kfree_skb(skb);
+	}
+	return ret;
+}
+
 int ath12k_wmi_send_scan_stop_cmd(struct ath12k *ar,
 				  struct ath12k_wmi_scan_cancel_arg *arg)
 {
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index 9f24f8ded52f..a97eb2544ab0 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -24,6 +24,7 @@
 
 struct ath12k_base;
 struct ath12k;
+struct ath12k_reg_tpc_power_info;
 
 /* There is no signed version of __le32, so for a temporary solution come
  * up with our own version. The idea is from fs/ntfs/endian.h.
@@ -388,6 +389,7 @@ enum wmi_tlv_cmd_id {
 	WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID,
 	WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID,
 	WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID,
+	WMI_VDEV_SET_TPC_POWER_CMDID,
 	WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER),
 	WMI_PEER_DELETE_CMDID,
 	WMI_PEER_FLUSH_TIDS_CMDID,
@@ -1924,6 +1926,8 @@ enum wmi_tlv_tag {
 	WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
 	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
 	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
+	WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
+	WMI_TAG_VDEV_CH_POWER_INFO,
 	WMI_TAG_MAX
 };
 
@@ -2148,7 +2152,8 @@ enum wmi_tlv_service {
 	WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
 	WMI_TLV_SERVICE_EXT2_MSG = 220,
 
-	WMI_MAX_EXT_SERVICE
+	WMI_MAX_EXT_SERVICE,
+	WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT = 280,
 };
 
 enum {
@@ -3037,6 +3042,32 @@ struct ath12k_wmi_element_info_arg {
 	u8 *ptr;
 };
 
+struct wmi_vdev_ch_power_info_params {
+	__le32 tlv_header;
+	__le32 chan_cfreq; /* Channel center frequency (MHz) */
+	/* Unit: dBm, either PSD/EIRP power for this frequency or
+	 * incremental for non-PSD BW
+	 */
+	__le32 tx_power;
+} __packed;
+
+struct wmi_vdev_set_tpc_power_cmd {
+	__le32 tlv_header;
+	__le32 vdev_id;
+	__le32 psd_power; /* Value: 0 or 1, is PSD power or not */
+	__le32 eirp_power;
+	/* Maximum EIRP power (dBm units), valid only if power is PSD */
+	__le32 power_type_6ghz; /* Type: WMI_6 GHz_REG_TYPE, used for halphy CTL lookup */
+	/* This fixed_param TLV is followed by the below TLVs:
+	 * num_pwr_levels of wmi_vdev_ch_power_info
+	 * For PSD power, it is the PSD/EIRP power of the frequency (20 MHz chunks).
+	 * For non-psd power, the power values are for 20, 40, and till
+	 * BSS BW power levels.
+	 * The num_pwr_levels will be checked by sw how many elements present
+	 * in the variable-length array.
+	 */
+} __packed;
+
 #define WMI_IE_BITMAP_SIZE             8
 
 #define WMI_SCAN_MAX_NUM_SSID                0x0A
@@ -4824,5 +4855,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
 			       struct sk_buff *tmpl);
 int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
 			   enum wmi_host_hw_mode_config_type mode);
+int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
+				       u32 vdev_id,
+				       struct ath12k_reg_tpc_power_info *param);
 
 #endif
-- 
2.17.1



From kvalo at kernel.org  Tue Sep 19 02:39:54 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Tue, 19 Sep 2023 12:39:54 +0300
Subject: [PATCH v2 09/13] wifi: ath10k: Use pci_disable/enable_link_state()
In-Reply-To: <20230918131103.24119-10-ilpo.jarvinen@linux.intel.com> ("Ilpo
	=?utf-8?Q?J=C3=A4rvinen=22's?= message of "Mon, 18 Sep 2023 16:10:59
 +0300")
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
	<20230918131103.24119-10-ilpo.jarvinen@linux.intel.com>
Message-ID: <87msxibixh.fsf@kernel.org>

Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com> writes:

> ath10k driver adjusts ASPM state itself which leaves ASPM service
> driver in PCI core unaware of the link state changes the driver
> implemented.
>
> Call pci_disable_link_state() and pci_enable_link_state() instead of
> adjusting ASPMC field in LNKCTL directly in the driver and let PCI core
> handle the ASPM state management.
>
> Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>

Acked-by: Kalle Valo <kvalo at kernel.org>

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From kvalo at kernel.org  Tue Sep 19 02:40:15 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Tue, 19 Sep 2023 12:40:15 +0300
Subject: [PATCH v2 10/13] wifi: ath11k: Use pci_disable/enable_link_state()
In-Reply-To: <20230918131103.24119-11-ilpo.jarvinen@linux.intel.com> ("Ilpo
	=?utf-8?Q?J=C3=A4rvinen=22's?= message of "Mon, 18 Sep 2023 16:11:00
 +0300")
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
	<20230918131103.24119-11-ilpo.jarvinen@linux.intel.com>
Message-ID: <87il86biww.fsf@kernel.org>

Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com> writes:

> ath11k driver adjusts ASPM state itself which leaves ASPM service
> driver in PCI core unaware of the link state changes the driver
> implemented.
>
> Call pci_disable_link_state() and pci_enable_link_state() instead of
> adjusting ASPMC field in LNKCTL directly in the driver and let PCI core
> handle the ASPM state management.
>
> Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>

Acked-by: Kalle Valo <kvalo at kernel.org>

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From kvalo at kernel.org  Tue Sep 19 02:40:55 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Tue, 19 Sep 2023 12:40:55 +0300
Subject: [PATCH v2 11/13] wifi: ath12k: Use pci_disable/enable_link_state()
In-Reply-To: <20230918131103.24119-12-ilpo.jarvinen@linux.intel.com> ("Ilpo
	=?utf-8?Q?J=C3=A4rvinen=22's?= message of "Mon, 18 Sep 2023 16:11:01
 +0300")
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
	<20230918131103.24119-12-ilpo.jarvinen@linux.intel.com>
Message-ID: <87ediubivs.fsf@kernel.org>

Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com> writes:

> ath12k driver adjusts ASPM state itself which leaves ASPM service
> driver in PCI core unaware of the link state changes the driver
> implemented.
>
> Call pci_disable_link_state() and pci_enable_link_state() instead of
> adjusting ASPMC field in LNKCTL directly in the driver and let PCI core
> handle the ASPM state management.
>
> Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>

Acked-by: Kalle Valo <kvalo at kernel.org>

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From sven at svenpeter.dev  Tue Sep 19 06:36:10 2023
From: sven at svenpeter.dev (Sven Peter)
Date: Tue, 19 Sep 2023 15:36:10 +0200
Subject: [PATCH v2 06/13] Bluetooth: hci_bcm4377: Convert aspm disable to quirk
In-Reply-To: <20230918131103.24119-7-ilpo.jarvinen@linux.intel.com>
References: <20230918131103.24119-1-ilpo.jarvinen@linux.intel.com>
 <20230918131103.24119-7-ilpo.jarvinen@linux.intel.com>
Message-ID: <aabaa49f-8988-42c0-bf8e-2266005e2155@app.fastmail.com>

Hi,

On Mon, Sep 18, 2023, at 15:10, Ilpo J?rvinen wrote:
> pci_disable_link_state() was made reliable regardless of ASPM CONFIG
> and OS being disallowed to change ASPM states to allow drivers to rely
> on pci_disable_link_state() working.
>
> Remove driver working around unreliable pci_disable_link_state() from
> hci_bcm4377 driver and add a PCI quirk to disable ASPM.
>
> Signed-off-by: Ilpo J?rvinen <ilpo.jarvinen at linux.intel.com>
> ---

Acked-by: Sven Peter <sven at svenpeter.dev>


Thanks,

Sven


From quic_jjohnson at quicinc.com  Tue Sep 19 10:47:52 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 19 Sep 2023 10:47:52 -0700
Subject: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory
 type
In-Reply-To: <20230919071724.15505-2-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
 <20230919071724.15505-2-quic_aisr@quicinc.com>
Message-ID: <4282f92a-3543-4863-bc00-478ae03759e0@quicinc.com>

On 9/19/2023 12:17 AM, Aishwarya R wrote:
> There are 3 types of regulatory rules for AP mode and 6 types for
> STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
> to select the exact reg rules.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

Wen,
Can you provide a "Tested-on: WCN7850" tag for this series?

> 
> Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/reg.c |  62 +++++++--
>   drivers/net/wireless/ath/ath12k/reg.h |   6 +-
>   drivers/net/wireless/ath/ath12k/wmi.c | 182 +++++++++++++++++++++++++-
>   drivers/net/wireless/ath/ath12k/wmi.h |  27 +++-
>   4 files changed, 257 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/reg.c b/drivers/net/wireless/ath/ath12k/reg.c
> index 6ede91ebc8e1..8501f77eee55 100644
> --- a/drivers/net/wireless/ath/ath12k/reg.c
> +++ b/drivers/net/wireless/ath/ath12k/reg.c
> @@ -28,6 +28,21 @@ static const struct ieee80211_regdomain ath12k_world_regd = {
>   	}
>   };
>   
> +enum wmi_reg_6g_ap_type
> +ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power power_type)
> +{
> +	switch (power_type) {
> +	case IEEE80211_REG_LPI_AP:
> +		return WMI_REG_INDOOR_AP;
> +	case IEEE80211_REG_SP_AP:
> +		return WMI_REG_STD_POWER_AP;
> +	case IEEE80211_REG_VLP_AP:
> +		return WMI_REG_VLP_AP;
> +	default:
> +		return WMI_REG_MAX_AP_TYPE;
> +	}
> +}
> +
>   static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2)
>   {
>   	const struct ieee80211_regdomain *regd;
> @@ -562,14 +577,16 @@ ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
>   
>   struct ieee80211_regdomain *
>   ath12k_reg_build_regd(struct ath12k_base *ab,
> -		      struct ath12k_reg_info *reg_info, bool intersect)
> +		      struct ath12k_reg_info *reg_info, bool intersect,
> +		      enum wmi_vdev_type vdev_type,
> +		      enum ieee80211_ap_reg_power power_type)
>   {
>   	struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
> -	struct ath12k_reg_rule *reg_rule;
> +	struct ath12k_reg_rule *reg_rule, *reg_rule_6ghz;
>   	u8 i = 0, j = 0, k = 0;
>   	u8 num_rules;
>   	u16 max_bw;
> -	u32 flags;
> +	u32 flags, reg_6ghz_number, max_bw_6ghz;
>   	char alpha2[3];
>   
>   	num_rules = reg_info->num_5g_reg_rules + reg_info->num_2g_reg_rules;
> @@ -578,8 +595,33 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
>   	 * This can be updated to choose the combination dynamically based on AP
>   	 * type and client type, after complete 6G regulatory support is added.
>   	 */
> -	if (reg_info->is_ext_reg_event)
> -		num_rules += reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP];
> +	if (reg_info->is_ext_reg_event) {
> +		if (vdev_type == WMI_VDEV_TYPE_STA) {
> +			enum wmi_reg_6g_ap_type ap_type;
> +
> +			ap_type = ath12k_ieee80211_ap_pwr_type_convert(power_type);
> +
> +			if (ap_type == WMI_REG_MAX_AP_TYPE)
> +				ap_type = WMI_REG_INDOOR_AP;

where is power_type coming from and can it be tainted?
if we always expect a valid value then why not just have the conversion 
function set the default to WMI_REG_INDOOR_AP?
Are there places in upcoming patches that actually perform error 
handling if the conversion function returns MAX?

> +			reg_6ghz_number = reg_info->num_6g_reg_rules_cl
> +					[ap_type][WMI_REG_DEFAULT_CLIENT];

please avoid splitting lines in the middle of a variable reference; that 
decreases the readability of the code. It is better to exceed some 
arbitrary line length guideline. you can use a client_type = 
WMI_REG_DEFAULT_CLIENT assignment to help reduce the length.
if the line is still exceedingly long, split the lines after =

repeat for all cases that follow


> +			if (reg_6ghz_number == 0) {
> +				ap_type = WMI_REG_INDOOR_AP;
> +				reg_6ghz_number = reg_info->num_6g_reg_rules_cl
> +						[ap_type][WMI_REG_DEFAULT_CLIENT];
> +			}
> +			reg_rule_6ghz = reg_info->reg_rules_6g_client_ptr
> +					[ap_type][WMI_REG_DEFAULT_CLIENT];
> +			max_bw_6ghz = reg_info->max_bw_6g_client
> +					[ap_type][WMI_REG_DEFAULT_CLIENT];
> +		} else {
> +			reg_6ghz_number = reg_info->num_6g_reg_rules_ap
> +					[WMI_REG_INDOOR_AP];
> +			reg_rule_6ghz = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP];
> +			max_bw_6ghz = reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP];
> +		}
> +		num_rules += reg_6ghz_number;
> +	}
>   
>   	if (!num_rules)
>   		goto ret;
> @@ -626,12 +668,10 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
>   			 * per other BW rule flags we pass from here
>   			 */
>   			flags = NL80211_RRF_AUTO_BW;
> -		} else if (reg_info->is_ext_reg_event &&
> -			   reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP] &&
> -			(k < reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP])) {
> -			reg_rule = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP] + k++;
> -			max_bw = min_t(u16, reg_rule->max_bw,
> -				       reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP]);
> +		} else if (reg_info->is_ext_reg_event && reg_6ghz_number &&
> +			   (k < reg_6ghz_number)) {
> +			reg_rule = reg_rule_6ghz + k++;
> +			max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
>   			flags = NL80211_RRF_AUTO_BW;
>   		} else {
>   			break;
> diff --git a/drivers/net/wireless/ath/ath12k/reg.h b/drivers/net/wireless/ath/ath12k/reg.h
> index 56d009a47234..56324e30a358 100644
> --- a/drivers/net/wireless/ath/ath12k/reg.h
> +++ b/drivers/net/wireless/ath/ath12k/reg.h
> @@ -88,7 +88,11 @@ void ath12k_reg_free(struct ath12k_base *ab);
>   void ath12k_regd_update_work(struct work_struct *work);
>   struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
>   						  struct ath12k_reg_info *reg_info,
> -						  bool intersect);
> +						  bool intersect,
> +						  enum wmi_vdev_type vdev_type,
> +						  enum ieee80211_ap_reg_power power_type);
> +enum wmi_reg_6g_ap_type
> +ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power power_type);
>   int ath12k_regd_update(struct ath12k *ar, bool init);
>   int ath12k_reg_update_chan_list(struct ath12k *ar);
>   
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index af910296c41e..1b9ce9a2ae96 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -4152,6 +4152,119 @@ static struct ath12k_reg_rule
>   	return reg_rule_ptr;
>   }
>   
> +static char *ath12k_cc_status_to_str(enum ath12k_reg_cc_code code)

all of these *_str() functions should return const char *

> +{
> +	switch (code) {
> +	case REG_SET_CC_STATUS_PASS:
> +		return "REG_SET_CC_STATUS_PASS";
> +	case REG_CURRENT_ALPHA2_NOT_FOUND:
> +		return "REG_CURRENT_ALPHA2_NOT_FOUND";
> +	case REG_INIT_ALPHA2_NOT_FOUND:
> +		return "REG_INIT_ALPHA2_NOT_FOUND";
> +	case REG_SET_CC_CHANGE_NOT_ALLOWED:
> +		return "REG_SET_CC_CHANGE_NOT_ALLOWED";
> +	case REG_SET_CC_STATUS_NO_MEMORY:
> +		return "REG_SET_CC_STATUS_NO_MEMORY";
> +	case REG_SET_CC_STATUS_FAIL:
> +		return "REG_SET_CC_STATUS_FAIL";
> +	default:
> +		return "unknown cc status";
> +	}
> +};
> +
> +static char *ath12k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz domain_id)
> +{
> +	switch (domain_id) {
> +	case FCC1_6GHZ:
> +		return "FCC1_6GHZ";
> +	case ETSI1_6GHZ:
> +		return "ETSI1_6GHZ";
> +	case ETSI2_6GHZ:
> +		return "ETSI2_6GHZ";
> +	case APL1_6GHZ:
> +		return "APL1_6GHZ";
> +	case FCC1_6GHZ_CL:
> +		return "FCC1_6GHZ_CL";
> +	default:
> +		return "unknown domain id";
> +	}
> +}
> +
> +static char *ath12k_6ghz_client_type_to_str(enum wmi_reg_6g_client_type type)
> +{
> +	switch (type) {
> +	case WMI_REG_DEFAULT_CLIENT:
> +		return "DEFAULT CLIENT";
> +	case WMI_REG_SUBORDINATE_CLIENT:
> +		return "SUBORDINATE CLIENT";
> +	default:
> +		return "unknown client type";
> +	}
> +}
> +
> +static char *ath12k_6ghz_ap_type_to_str(enum wmi_reg_6g_ap_type type)
> +{
> +	switch (type) {
> +	case WMI_REG_INDOOR_AP:
> +		return "INDOOR AP";
> +	case WMI_REG_STD_POWER_AP:
> +		return "STANDARD POWER AP";
> +	case WMI_REG_VLP_AP:
> +		return "VERY LOW POWER AP";
> +	default:
> +		return "unknown AP type";
> +	}
> +}
> +
> +static char *ath12k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz sub_id)
> +{
> +	switch (sub_id) {
> +	case FCC1_CLIENT_LPI_REGULAR_6GHZ:
> +		return "FCC1_CLIENT_LPI_REGULAR_6GHZ";
> +	case FCC1_CLIENT_SP_6GHZ:
> +		return "FCC1_CLIENT_SP_6GHZ";
> +	case FCC1_AP_LPI_6GHZ:
> +		return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE";
> +	case FCC1_AP_SP_6GHZ:
> +		return "FCC1_AP_SP_6GHZ";
> +	case ETSI1_LPI_6GHZ:
> +		return "ETSI1_LPI_6GHZ";
> +	case ETSI1_VLP_6GHZ:
> +		return "ETSI1_VLP_6GHZ";
> +	case ETSI2_LPI_6GHZ:
> +		return "ETSI2_LPI_6GHZ";
> +	case ETSI2_VLP_6GHZ:
> +		return "ETSI2_VLP_6GHZ";
> +	case APL1_LPI_6GHZ:
> +		return "APL1_LPI_6GHZ";
> +	case APL1_VLP_6GHZ:
> +		return "APL1_VLP_6GHZ";
> +	case EMPTY_6GHZ:
> +		return "N/A";
> +	default:
> +		return "unknown sub reg id";
> +	}
> +}
> +
> +static void ath12k_print_reg_rule(struct ath12k_base *ab, char *prev,
> +				  u32 num_reg_rules,
> +				  struct ath12k_reg_rule *reg_rule_ptr)
> +{
> +	struct ath12k_reg_rule *reg_rule = reg_rule_ptr;
> +	u32 count;
> +
> +	ath12k_dbg(ab, ATH12K_DBG_WMI, "%s reg rules number %d\n", prev, num_reg_rules);
> +
> +	for (count = 0; count < num_reg_rules; count++) {
> +		ath12k_dbg(ab, ATH12K_DBG_WMI,
> +			   "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d) (psd flag %d EIRP %d dB/MHz)\n",
> +			   count + 1, reg_rule->start_freq, reg_rule->end_freq,
> +			   reg_rule->max_bw, reg_rule->ant_gain, reg_rule->reg_power,
> +			   reg_rule->flags, reg_rule->psd_flag, reg_rule->psd_eirp);
> +		reg_rule++;
> +	}
> +}
> +
>   static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   						   struct sk_buff *skb,
>   						   struct ath12k_reg_info *reg_info)
> @@ -4163,7 +4276,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   	u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
>   	u32 num_6g_reg_rules_cl[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
>   	u32 total_reg_rules = 0;
> -	int ret, i, j;
> +	int ret, i, j, skip_6ghz_rules_in_5ghz_rules = 0;
>   
>   	ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n");
>   
> @@ -4265,6 +4378,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   	 * from 5G rules list.
>   	 */
>   	if (memcmp(reg_info->alpha2, "US", 2) == 0) {
> +		ath12k_dbg(ab, ATH12K_DBG_WMI,
> +			   "US 5 GHz reg rules number %d from fw",
> +			   reg_info->num_5g_reg_rules);
> +
> +		if (reg_info->num_5g_reg_rules > REG_US_5G_NUM_REG_RULES)
> +			skip_6ghz_rules_in_5ghz_rules = reg_info->num_5g_reg_rules -
> +						    REG_US_5G_NUM_REG_RULES;

I'd split this line after = instead of in the middle of the expression

>   		reg_info->num_5g_reg_rules = REG_US_5G_NUM_REG_RULES;
>   		num_5g_reg_rules = reg_info->num_5g_reg_rules;
>   	}
> @@ -4297,6 +4417,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   		break;
>   	}
>   
> +	ath12k_dbg(ab, ATH12K_DBG_WMI,
> +		   "%s: status_code %s", __func__,
> +		   ath12k_cc_status_to_str(reg_info->status_code));
> +
>   	reg_info->is_ext_reg_event = true;
>   
>   	reg_info->min_bw_2g = le32_to_cpu(ev->min_bw_2g);
> @@ -4325,6 +4449,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   			le32_to_cpu(ev->max_bw_6g_client_vlp[i]);
>   	}
>   
> +	ath12k_dbg(ab, ATH12K_DBG_WMI,
> +		   "%s: status_code %s", __func__,
> +		   ath12k_cc_status_to_str(reg_info->status_code));
> +
>   	ath12k_dbg(ab, ATH12K_DBG_WMI,
>   		   "%s:cc_ext %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",
>   		   __func__, reg_info->alpha2, reg_info->dfs_region,
> @@ -4368,10 +4496,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   			ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");
>   			return -ENOMEM;
>   		}
> +		ath12k_print_reg_rule(ab, "2 GHz",
> +				      num_2g_reg_rules,
> +				      reg_info->reg_rules_2g_ptr);
>   	}
> +	ext_wmi_reg_rule += num_2g_reg_rules;
>   
>   	if (num_5g_reg_rules) {
> -		ext_wmi_reg_rule += num_2g_reg_rules;
>   		reg_info->reg_rules_5g_ptr =
>   			create_ext_reg_rules_from_wmi(num_5g_reg_rules,
>   						      ext_wmi_reg_rule);
> @@ -4381,9 +4512,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   			ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");
>   			return -ENOMEM;
>   		}
> +		ath12k_print_reg_rule(ab, "5 GHz",
> +				      num_5g_reg_rules,
> +				      reg_info->reg_rules_5g_ptr);
>   	}
>   
> -	ext_wmi_reg_rule += num_5g_reg_rules;
> +	/* We have adjusted the number of 5 GHz reg rules via the hack above.
> +	 * Here, we adjust that many extra rules which came with 5g reg rules
> +	 * (for cc: US)
> +	 *
> +	 * NOTE: skip_6ghz_rules_in_5ghz_rules will be 0 for rest other cases.
> +	 */
> +	ext_wmi_reg_rule += num_5g_reg_rules + skip_6ghz_rules_in_5ghz_rules;
>   
>   	for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
>   		reg_info->reg_rules_6g_ap_ptr[i] =
> @@ -4396,10 +4536,17 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   			return -ENOMEM;
>   		}
>   
> +		ath12k_print_reg_rule(ab, ath12k_6ghz_ap_type_to_str(i),
> +				      num_6g_reg_rules_ap[i],
> +				      reg_info->reg_rules_6g_ap_ptr[i]);
> +
>   		ext_wmi_reg_rule += num_6g_reg_rules_ap[i];
>   	}
>   
>   	for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
> +		ath12k_dbg(ab, ATH12K_DBG_WMI,
> +			   "AP type %s", ath12k_6ghz_ap_type_to_str(j));
> +
>   		for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
>   			reg_info->reg_rules_6g_client_ptr[j][i] =
>   				create_ext_reg_rules_from_wmi(num_6g_reg_rules_cl[j][i],
> @@ -4411,6 +4558,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   				return -ENOMEM;
>   			}
>   
> +			ath12k_print_reg_rule(ab, ath12k_6ghz_client_type_to_str(i),
> +					      num_6g_reg_rules_cl[j][i],
> +					      reg_info->reg_rules_6g_client_ptr[j][i]);
> +
>   			ext_wmi_reg_rule += num_6g_reg_rules_cl[j][i];
>   		}
>   	}
> @@ -4425,6 +4576,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   	reg_info->domain_code_6g_ap[WMI_REG_VLP_AP] =
>   		le32_to_cpu(ev->domain_code_6g_ap_vlp);
>   
> +	ath12k_dbg(ab, ATH12K_DBG_WMI,
> +		   "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s , sp %s , vlp %s\n",
> +		   ath12k_6ghz_client_type_to_str(reg_info->client_type),
> +		   reg_info->rnr_tpe_usable,
> +		   reg_info->unspecified_ap_usable,
> +		   ath12k_sub_reg_6ghz_to_str
> +		   (le32_to_cpu(ev->domain_code_6g_ap_lpi)),
> +		   ath12k_sub_reg_6ghz_to_str
> +		   (le32_to_cpu(ev->domain_code_6g_ap_sp)),
> +		   ath12k_sub_reg_6ghz_to_str
> +		   (le32_to_cpu(ev->domain_code_6g_ap_vlp)));

avoid splitting the line between a function and it's parameters.
it is ok to split in the middle of a parameter list, but the first 
parameter should almost always be on the same line as the function

> +
>   	for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
>   		reg_info->domain_code_6g_client[WMI_REG_INDOOR_AP][i] =
>   			le32_to_cpu(ev->domain_code_6g_client_lpi[i]);
> @@ -4432,12 +4595,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   			le32_to_cpu(ev->domain_code_6g_client_sp[i]);
>   		reg_info->domain_code_6g_client[WMI_REG_VLP_AP][i] =
>   			le32_to_cpu(ev->domain_code_6g_client_vlp[i]);
> +		ath12k_dbg(ab, ATH12K_DBG_WMI,
> +			   "6 GHz AP BW: lpi %d - %d sp %d - %d vlp %d - %d\n",
> +			   ev->min_bw_6g_ap_lpi, ev->max_bw_6g_ap_lpi,
> +			   ev->min_bw_6g_ap_sp, ev->max_bw_6g_ap_sp,
> +			   ev->min_bw_6g_ap_vlp, ev->max_bw_6g_ap_vlp);
>   	}
>   
>   	reg_info->domain_code_6g_super_id = le32_to_cpu(ev->domain_code_6g_super_id);
>   
> -	ath12k_dbg(ab, ATH12K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d",
> -		   reg_info->client_type, reg_info->domain_code_6g_super_id);
> +	ath12k_dbg(ab, ATH12K_DBG_WMI, "6 GHz client_type: %s 6 GHz super domain %s",
> +		   ath12k_6ghz_client_type_to_str(reg_info->client_type),
> +		   ath12k_super_reg_6ghz_to_str(reg_info->domain_code_6g_super_id));
>   
>   	ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n");
>   
> @@ -5192,7 +5361,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
>   	    !ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
>   		intersect = true;
>   
> -	regd = ath12k_reg_build_regd(ab, reg_info, intersect);
> +	regd = ath12k_reg_build_regd(ab, reg_info, intersect,
> +				     WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);

why is this forced to AP?
where is logic for client?

>   	if (!regd) {
>   		ath12k_warn(ab, "failed to build regd from reg_info\n");
>   		goto fallback;
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 08a8c9e0f59f..966e6ba4e162 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -2832,8 +2832,8 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg {
>   #define REG_RULE_MAX_BW				0x0000ffff
>   #define REG_RULE_REG_PWR			0x00ff0000
>   #define REG_RULE_ANT_GAIN			0xff000000
> -#define REG_RULE_PSD_INFO			BIT(2)
> -#define REG_RULE_PSD_EIRP			0xffff0000
> +#define REG_RULE_PSD_INFO                       BIT(0)
> +#define REG_RULE_PSD_EIRP                       0xff0000
>   
>   #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
>   #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1)
> @@ -3844,6 +3844,29 @@ enum {
>   	WMI_REG_SET_CC_STATUS_FAIL = 5,
>   };
>   
> +enum reg_subdomains_6ghz {
> +	EMPTY_6GHZ = 0x0,
> +	FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01,
> +	FCC1_CLIENT_SP_6GHZ = 0x02,
> +	FCC1_AP_LPI_6GHZ = 0x03,
> +	FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ,
> +	FCC1_AP_SP_6GHZ = 0x04,
> +	ETSI1_LPI_6GHZ = 0x10,
> +	ETSI1_VLP_6GHZ = 0x11,
> +	ETSI2_LPI_6GHZ = 0x12,
> +	ETSI2_VLP_6GHZ = 0x13,
> +	APL1_LPI_6GHZ = 0x20,
> +	APL1_VLP_6GHZ = 0x21,
> +};
> +
> +enum reg_super_domain_6ghz {
> +	FCC1_6GHZ = 0x01,
> +	ETSI1_6GHZ = 0x02,
> +	ETSI2_6GHZ = 0x03,
> +	APL1_6GHZ = 0x04,
> +	FCC1_6GHZ_CL = 0x05,
> +};
> +
>   #define WMI_REG_CLIENT_MAX 4
>   
>   struct wmi_reg_chan_list_cc_ext_event {



From quic_jjohnson at quicinc.com  Tue Sep 19 12:57:51 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 19 Sep 2023 12:57:51 -0700
Subject: [PATCH 2/7] wifi: ath12k: build 6 GHz regd based on vdev type and
 6 GHz power type
In-Reply-To: <20230919071724.15505-3-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
 <20230919071724.15505-3-quic_aisr@quicinc.com>
Message-ID: <66901daa-0c69-4a22-82fd-e66f8b6a011b@quicinc.com>

On 9/19/2023 12:17 AM, Aishwarya R wrote:
> During bootup, WMI_REG_CHAN_LIST_CC_EXT_EVENTID event sent from firmware
> at an early stage and it expects the 6 GHz power type for 6 GHz reg rules.

what is "it"?

> As power mode is not defined at this point host selects IEEE80211_REG_UNSET_AP
> as default mode.
> 
> When interface is created, it updates regd rules accordingly.

Again what is "it"?

I'm having trouble discerning what is existing behavior and what is new 
behavior.

That distinction should be clear.  In the past the following template 
has been suggested:
   " Current code does (A), this has a problem when (B).
     We can improve this doing (C), because (D)."
<http://www.spinics.net/lists/kernel/msg1633438.html>

Obviously that exact format isn't required, but you should at least 
describe, if it isn't obvious:
1) what does the current code do
2) what is wrong with that code
3) what should be done to the code to fix the issue

I don't actually have an code patch comments



From quic_jjohnson at quicinc.com  Tue Sep 19 12:59:46 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 19 Sep 2023 12:59:46 -0700
Subject: [PATCH 3/7] wifi: ath12k: get 6 GHz power type from HE operation
 element
In-Reply-To: <20230919071724.15505-4-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
 <20230919071724.15505-4-quic_aisr@quicinc.com>
Message-ID: <0457896f-2d58-4a4f-9be3-77c30b2d0585@quicinc.com>

On 9/19/2023 12:17 AM, Aishwarya R wrote:
> When 6 GHz AP or STA is assigned a channel ctx, it needs to

here again, what is "it"?
and why does "it" need the power type?

> extract the power type from HE operation element.
> If unset power type is present, by default IEEE80211_REG_LPI_AP
> power mode will be used.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/mac.c | 11 +++++++++++
>   1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 5b9af264d305..01f81b087fa2 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5823,6 +5823,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>   	struct ath12k_vif *arvif = (void *)vif->drv_priv;
>   	int ret;
>   	struct ath12k_wmi_peer_create_arg param;
> +	enum ieee80211_ap_reg_power power_type;
>   
>   	mutex_lock(&ar->conf_mutex);
>   
> @@ -5830,6 +5831,16 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>   		   "mac chanctx assign ptr %pK vdev_id %i\n",
>   		   ctx, arvif->vdev_id);
>   
> +	if (ar->supports_6ghz && ctx->def.chan->band == NL80211_BAND_6GHZ &&
> +	    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> +	     arvif->vdev_type == WMI_VDEV_TYPE_AP)) {
> +		power_type = vif->bss_conf.power_type;
> +		ath12k_dbg(ab, ATH12K_DBG_MAC, "mac chanctx power type %d\n",
> +			   power_type);
> +		if (power_type == IEEE80211_REG_UNSET_AP)
> +			power_type = IEEE80211_REG_LPI_AP;
> +	}
> +
>   	/* for some targets bss peer must be created before vdev_start */
>   	if (ab->hw_params->vdev_start_delay &&
>   	    arvif->vdev_type != WMI_VDEV_TYPE_AP &&



From quic_jjohnson at quicinc.com  Tue Sep 19 13:09:08 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 19 Sep 2023 13:09:08 -0700
Subject: [PATCH 6/7] wifi: ath12k: fill parameters for vdev_set_tpc_power
 wmi command
In-Reply-To: <20230919071724.15505-7-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
 <20230919071724.15505-7-quic_aisr@quicinc.com>
Message-ID: <bca298ab-6f68-47d4-9de1-61815793cb08@quicinc.com>

On 9/19/2023 12:17 AM, Aishwarya R wrote:
> Prepare the parameters which is needed for wmi cmd
> vdev_set_tpc_power.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/core.h |   1 +
>   drivers/net/wireless/ath/ath12k/mac.c  | 273 +++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/mac.h  |   3 +
>   drivers/net/wireless/ath/ath12k/wmi.c  |   1 +
>   drivers/net/wireless/ath/ath12k/wmi.h  |   1 +
>   5 files changed, 279 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 01768fe79bd6..e9bf87f740cd 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -606,6 +606,7 @@ struct ath12k {
>   	bool monitor_vdev_created;
>   	bool monitor_started;
>   	int monitor_vdev_id;
> +	s8 max_allowed_tx_power;
>   };
>   
>   struct ath12k_band_cap {
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 0683b22137b0..35bd472267c1 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -5883,6 +5883,279 @@ static u8 ath12k_mac_get_num_pwr_levels(struct cfg80211_chan_def *chan_def)
>   	return num_pwr_levels;
>   }
>   
> +static u16 ath12k_mac_get_6ghz_start_frequency(struct cfg80211_chan_def *chan_def)
> +{
> +	u16 diff_seq;
> +
> +	/* It is to get the lowest channel number's center frequency of the chan.

s/It is to //

also suggest any function documentation should appear before the 
function, and if the function requires documentation, that kernel-doc 
format be used

same guidance applies to the functions that follow

> +	 * For example,
> +	 * bandwidth=40 MHz, center frequency is 5965, lowest channel is 1
> +	 * with center frequency 5955, its diff is 5965 - 5955 = 10.
> +	 * bandwidth=80 MHz, center frequency is 5985, lowest channel is 1
> +	 * with center frequency 5955, its diff is 5985 - 5955 = 30.
> +	 * bandwidth=160 MHz, center frequency is 6025, lowest channel is 1
> +	 * with center frequency 5955, its diff is 6025 - 5955 = 70.
> +	 */
> +	switch (chan_def->width) {
> +	case NL80211_CHAN_WIDTH_160:
> +		diff_seq = 70;
> +		break;
> +	case NL80211_CHAN_WIDTH_80:
> +	case NL80211_CHAN_WIDTH_80P80:
> +		diff_seq = 30;
> +		break;
> +	case NL80211_CHAN_WIDTH_40:
> +		diff_seq = 10;
> +		break;
> +	default:
> +		diff_seq = 0;
> +	}
> +
> +	return chan_def->center_freq1 - diff_seq;
> +}
> +
> +static u16 ath12k_mac_get_seg_freq(struct cfg80211_chan_def *chan_def,
> +				   u16 start_seq, u8 seq)
> +{
> +	u16 seg_seq;
> +
> +	/* It is to get the center frequency of the specific bandwidth.
> +	 * start_seq means the lowest channel number's center frequency.
> +	 * seq 0/1/2/3 means 20 MHz/40 MHz/80 MHz/160 MHz & 80P80.
> +	 * For example,
> +	 * lowest channel is 1, its center frequency 5955,
> +	 * center frequency is 5955 when bandwidth=20 MHz, its diff is 5955 - 5955 = 0.
> +	 * lowest channel is 1, its center frequency 5955,
> +	 * center frequency is 5965 when bandwidth=40 MHz, its diff is 5965 - 5955 = 10.
> +	 * lowest channel is 1, its center frequency 5955,
> +	 * center frequency is 5985 when bandwidth=80 MHz, its diff is 5985 - 5955 = 30.
> +	 * lowest channel is 1, its center frequency 5955,
> +	 * center frequency is 6025 when bandwidth=160 MHz, its diff is 6025 - 5955 = 70.
> +	 */
> +	if (chan_def->width == NL80211_CHAN_WIDTH_80P80 && seq == 3)
> +		return chan_def->center_freq2;
> +
> +	seg_seq = 10 * (BIT(seq) - 1);
> +	return seg_seq + start_seq;
> +}
> +
> +static void ath12k_mac_get_psd_channel(struct ath12k *ar,
> +				       u16 step_freq,
> +				       u16 *start_freq,
> +				       u16 *center_freq,
> +				       u8 i,
> +				       struct ieee80211_channel **temp_chan,
> +				       s8 *tx_power)
> +{
> +	/* It is to get the center frequency for each 20 MHz.
> +	 * For example, if the chan is 160 MHz and center frequency is 6025,
> +	 * then it include 8 channels, they are 1/5/9/13/17/21/25/29,
> +	 * channel number 1's center frequency is 5955, it is parameter start_freq.
> +	 * parameter i is the step of the 8 channels. i is 0~7 for the 8 channels.
> +	 * the channel 1/5/9/13/17/21/25/29 maps i=0/1/2/3/4/5/6/7,
> +	 * and maps its center frequency is 5955/5975/5995/6015/6035/6055/6075/6095,
> +	 * the gap is 20 for each channel, parameter step_freq means the gap.
> +	 * after get the center frequency of each channel, it is easy to find the
> +	 * struct ieee80211_channel of it and get the max_reg_power.
> +	 */
> +	*center_freq = *start_freq + i * step_freq;
> +	*temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
> +	*tx_power = (*temp_chan)->max_reg_power;
> +}
> +
> +static void ath12k_mac_get_eirp_power(struct ath12k *ar,
> +				      u16 *start_freq,
> +				      u16 *center_freq,
> +				      u8 i,
> +				      struct ieee80211_channel **temp_chan,
> +				      struct cfg80211_chan_def *def,
> +				      s8 *tx_power)
> +{
> +	/* It is to get the center frequency for 20 MHz/40 MHz/80 MHz/
> +	 * 160 MHz & 80P80 bandwidth, and then plus 10 to the center frequency,
> +	 * it is the center frequency of a channel number.
> +	 * For example, when configured channel number is 1.
> +	 * center frequency is 5965 when bandwidth=40 MHz, after plus 10, it is 5975,
> +	 * then it is channel number 5.
> +	 * center frequency is 5985 when bandwidth=80 MHz, after plus 10, it is 5995,
> +	 * then it is channel number 9.
> +	 * center frequency is 6025 when bandwidth=160 MHz, after plus 10, it is 6035,
> +	 * then it is channel number 17.
> +	 * after get the center frequency of each channel, it is easy to find the
> +	 * struct ieee80211_channel of it and get the max_reg_power.
> +	 */
> +	*center_freq = ath12k_mac_get_seg_freq(def, *start_freq, i);
> +	*center_freq += 10;
> +	*temp_chan = ieee80211_get_channel(ar->hw->wiphy, *center_freq);
> +	*tx_power = (*temp_chan)->max_reg_power;
> +}
> +
> +void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
> +				  struct ieee80211_vif *vif,
> +				  struct ieee80211_chanctx_conf *ctx)
> +{
> +	struct ath12k_base *ab = ar->ab;
> +	struct ath12k_vif *arvif = (void *)vif->drv_priv;
> +	struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
> +	struct ath12k_reg_tpc_power_info *reg_tpc_info = &arvif->reg_tpc_info;
> +	struct ieee80211_channel *chan, *temp_chan;
> +	u8 pwr_lvl_idx, num_pwr_levels, pwr_reduction;
> +	bool is_psd_power = false, is_tpe_present = false;
> +	s8 max_tx_power[IEEE80211_MAX_NUM_PWR_LEVEL],
> +		psd_power, tx_power = 0, eirp_power = 0;
> +	u16 start_freq = 0, center_freq = 0;
> +
> +	chan = ctx->def.chan;
> +	start_freq = ath12k_mac_get_6ghz_start_frequency(&ctx->def);
> +	pwr_reduction = bss_conf->pwr_reduction;
> +
> +	if (arvif->vdev_type == WMI_VDEV_TYPE_STA &&
> +	    arvif->reg_tpc_info.num_pwr_levels) {
> +		is_tpe_present = true;
> +		num_pwr_levels = arvif->reg_tpc_info.num_pwr_levels;
> +	} else {
> +		num_pwr_levels = ath12k_mac_get_num_pwr_levels(&ctx->def);
> +	}
> +
> +	for (pwr_lvl_idx = 0; pwr_lvl_idx < num_pwr_levels; pwr_lvl_idx++) {
> +		/* STA received TPE IE*/
> +		if (is_tpe_present) {
> +			/* local power is PSD power*/
> +			if (chan->flags & IEEE80211_CHAN_PSD) {
> +				/* Connecting AP is psd power */
> +				if (reg_tpc_info->is_psd_power) {
> +					is_psd_power = true;
> +					ath12k_mac_get_psd_channel(ar, 20,
> +								   &start_freq,
> +								   &center_freq,
> +								   pwr_lvl_idx,
> +								   &temp_chan,
> +								   &tx_power);
> +					psd_power = temp_chan->psd;
> +					eirp_power = tx_power;
> +					max_tx_power[pwr_lvl_idx] =
> +						min_t(s8,
> +						      psd_power,
> +						      reg_tpc_info->tpe[pwr_lvl_idx]);
> +				/* Connecting AP is not psd power */
> +				} else {
> +					ath12k_mac_get_eirp_power(ar,
> +								  &start_freq,
> +								  &center_freq,
> +								  pwr_lvl_idx,
> +								  &temp_chan,
> +								  &ctx->def,
> +								  &tx_power);
> +					psd_power = temp_chan->psd;
> +					/* convert psd power to EIRP power based
> +					 * on channel width
> +					 */
> +					tx_power =
> +						min_t(s8, tx_power,
> +						      psd_power + 13 + pwr_lvl_idx * 3);
> +					max_tx_power[pwr_lvl_idx] =
> +						min_t(s8,
> +						      tx_power,
> +						      reg_tpc_info->tpe[pwr_lvl_idx]);
> +			}

bad brace placement?

> +			/* local power is not PSD power */
> +			} else {
> +				/* Connecting AP is psd power */
> +				if (reg_tpc_info->is_psd_power) {
> +					is_psd_power = true;
> +					ath12k_mac_get_psd_channel(ar, 20,
> +								   &start_freq,
> +								   &center_freq,
> +								   pwr_lvl_idx,
> +								   &temp_chan,
> +								   &tx_power);
> +					eirp_power = tx_power;
> +					max_tx_power[pwr_lvl_idx] =
> +						reg_tpc_info->tpe[pwr_lvl_idx];
> +				/* Connecting AP is not psd power */
> +				} else {
> +					ath12k_mac_get_eirp_power(ar,
> +								  &start_freq,
> +								  &center_freq,
> +								  pwr_lvl_idx,
> +								  &temp_chan,
> +								  &ctx->def,
> +								  &tx_power);
> +					max_tx_power[pwr_lvl_idx] =
> +						min_t(s8,
> +						      tx_power,
> +						      reg_tpc_info->tpe[pwr_lvl_idx]);
> +				}
> +		}

bad brace placement?

> +		/* STA not received TPE IE */
> +		} else {
> +			/* local power is PSD power*/
> +			if (chan->flags & IEEE80211_CHAN_PSD) {
> +				is_psd_power = true;
> +				ath12k_mac_get_psd_channel(ar, 20,
> +							   &start_freq,
> +							   &center_freq,
> +							   pwr_lvl_idx,
> +							   &temp_chan,
> +							   &tx_power);
> +				psd_power = temp_chan->psd;
> +				eirp_power = tx_power;
> +				max_tx_power[pwr_lvl_idx] = psd_power;
> +			} else {
> +				ath12k_mac_get_eirp_power(ar,
> +							  &start_freq,
> +							  &center_freq,
> +							  pwr_lvl_idx,
> +							  &temp_chan,
> +							  &ctx->def,
> +							  &tx_power);
> +				max_tx_power[pwr_lvl_idx] = tx_power;
> +			}
> +		}
> +
> +		if (is_psd_power) {
> +			/* If AP local power constraint is present */
> +			if (pwr_reduction)
> +				eirp_power = eirp_power - pwr_reduction;
> +
> +			/* If FW updated max tx power is non zero, then take the min of
> +			 * firmware updated ap tx power
> +			 * and max power derived from above mentioned parameters.
> +			 */
> +			ath12k_dbg(ab, ATH12K_DBG_MAC,
> +				   "eirp power : %d firmware report power : %d\n",
> +				   eirp_power, ar->max_allowed_tx_power);
> +			if ((ar->max_allowed_tx_power) && (ab->hw_params->idle_ps))
> +				eirp_power = min_t(s8,
> +						   eirp_power,
> +						   ar->max_allowed_tx_power);
> +		} else {
> +			/* If AP local power constraint is present */
> +			if (pwr_reduction)
> +				max_tx_power[pwr_lvl_idx] =
> +					max_tx_power[pwr_lvl_idx] - pwr_reduction;
> +			/* If FW updated max tx power is non zero, then take the min of
> +			 * firmware updated ap tx power
> +			 * and max power derived from above mentioned parameters.
> +			 */
> +			if ((ar->max_allowed_tx_power) && (ab->hw_params->idle_ps))
> +				max_tx_power[pwr_lvl_idx] =
> +					min_t(s8,
> +					      max_tx_power[pwr_lvl_idx],
> +					      ar->max_allowed_tx_power);
> +		}
> +		reg_tpc_info->chan_power_info[pwr_lvl_idx].chan_cfreq = center_freq;
> +		reg_tpc_info->chan_power_info[pwr_lvl_idx].tx_power =
> +			max_tx_power[pwr_lvl_idx];
> +	}
> +
> +	reg_tpc_info->num_pwr_levels = num_pwr_levels;
> +	reg_tpc_info->is_psd_power = is_psd_power;
> +	reg_tpc_info->eirp_power = eirp_power;
> +	reg_tpc_info->power_type_6ghz =
> +		ath12k_ieee80211_ap_pwr_type_convert(vif->bss_conf.power_type);
> +}
> +
>   static void ath12k_mac_parse_tx_pwr_env(struct ath12k *ar,
>   					struct ieee80211_vif *vif,
>   					struct ieee80211_chanctx_conf *ctx)
> diff --git a/drivers/net/wireless/ath/ath12k/mac.h b/drivers/net/wireless/ath/ath12k/mac.h
> index 82f590004d05..ce2ce7f324d7 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.h
> +++ b/drivers/net/wireless/ath/ath12k/mac.h
> @@ -68,6 +68,9 @@ struct ath12k *ath12k_mac_get_ar_by_vdev_id(struct ath12k_base *ab, u32 vdev_id)
>   struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id);
>   enum wmi_vdev_type ath12k_mac_get_ar_vdev_type(struct ath12k *ar);
>   
> +void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
> +				  struct ieee80211_vif *vif,
> +				  struct ieee80211_chanctx_conf *ctx);
>   void ath12k_mac_drain_tx(struct ath12k *ar);
>   void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
>   int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 211bdb915173..5bfca2513730 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -5588,6 +5588,7 @@ static void ath12k_vdev_start_resp_event(struct ath12k_base *ab, struct sk_buff
>   	}
>   
>   	ar->last_wmi_vdev_start_status = 0;
> +	ar->max_allowed_tx_power = le32_to_cpu(vdev_start_resp.max_allowed_tx_power);
>   
>   	status = le32_to_cpu(vdev_start_resp.status);
>   
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index c3b110af1272..9f24f8ded52f 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -3796,6 +3796,7 @@ struct wmi_vdev_start_resp_event {
>   	};
>   	__le32 cfgd_tx_streams;
>   	__le32 cfgd_rx_streams;
> +	__le32 max_allowed_tx_power;
>   } __packed;
>   
>   /* VDEV start response status codes */



From quic_jjohnson at quicinc.com  Tue Sep 19 13:21:57 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Tue, 19 Sep 2023 13:21:57 -0700
Subject: [PATCH 7/7] wifi: ath12k: send TPC power to firmware for 6 GHz
 VDEV
In-Reply-To: <20230919071724.15505-8-quic_aisr@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
 <20230919071724.15505-8-quic_aisr@quicinc.com>
Message-ID: <b5238b10-ca83-40df-b7e3-b0161b98ede7@quicinc.com>

On 9/19/2023 12:17 AM, Aishwarya R wrote:
> When STATION is connected to a 6 GHz AP, or when AP boots up, it has

what is "it"?

> 2 ways to configure the power limit to firmware. Currently it
> sends 2 wmi command WMI_PDEV_PARAM_TXPOWER_LIMIT2G/
> WMI_PDEV_PARAM_TXPOWER_LIMIT5G to firmware.
> 
> Add support to send WMI_VDEV_SET_TPC_POWER_CMDID to firmware which
> include more parameters for power control. When firmware support
> SERVICE_EXT_TPC_REG, it means firmware support this feature, then ath12k
> discard BSS_CHANGED_TXPOWER flag from mac80211 which is used to the first
> way for 6 GHz band.

I'm not parsing this last sentence. s I mentioned in a previous patch, 
it will be easier to understand if you break it down:
what the current code does
what is wrong with the current code
how to fix the current code

> 
> The second way is to prepare the parameter for wmi command
> WMI_VDEV_SET_TPC_POWER_CMDID and send the firmware after vdev start
> response success from firmware.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
> ---
>   drivers/net/wireless/ath/ath12k/mac.c | 25 +++++++++-
>   drivers/net/wireless/ath/ath12k/wmi.c | 67 +++++++++++++++++++++++++++
>   drivers/net/wireless/ath/ath12k/wmi.h | 36 +++++++++++++-
>   3 files changed, 125 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
> index 35bd472267c1..5505f933a4e1 100644
> --- a/drivers/net/wireless/ath/ath12k/mac.c
> +++ b/drivers/net/wireless/ath/ath12k/mac.c
> @@ -2467,8 +2467,18 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
>   		ath12k_dbg(ar->ab, ATH12K_DBG_MAC, "mac vdev_id %i txpower %d\n",
>   			   arvif->vdev_id, info->txpower);
>   
> -		arvif->txpower = info->txpower;
> -		ath12k_mac_txpower_recalc(ar);
> +		if (ar->supports_6ghz && info->chandef.chan &&
> +		    info->chandef.chan->band == NL80211_BAND_6GHZ &&
> +		    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> +		     arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
> +		     test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT,
> +			      ar->ab->wmi_ab.svc_map)) {
> +			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
> +				   "discard tx power, change to set TPC power\n");
> +		} else {
> +			arvif->txpower = info->txpower;
> +			ath12k_mac_txpower_recalc(ar);
> +		}
>   	}
>   
>   	if (changed & BSS_CHANGED_MCAST_RATE &&
> @@ -5519,6 +5529,16 @@ ath12k_mac_vdev_start_restart(struct ath12k_vif *arvif,
>   		return ret;
>   	}
>   
> +	if (ar->supports_6ghz &&
> +	    chandef->chan->band == NL80211_BAND_6GHZ &&
> +	    (arvif->vdev_type == WMI_VDEV_TYPE_STA ||
> +	     arvif->vdev_type == WMI_VDEV_TYPE_AP) &&
> +	     test_bit(WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT, ar->ab->wmi_ab.svc_map)) {

this complex test occurs in two places. can it be refactored into a 
well-named bool imperative function?

> +		ath12k_mac_fill_reg_tpc_info(ar, arvif->vif, &arvif->chanctx);
> +		ath12k_wmi_send_vdev_set_tpc_power(ar, arvif->vdev_id,
> +						   &arvif->reg_tpc_info);
> +	}
> +
>   	ar->num_started_vdevs++;
>   	ath12k_dbg(ab, ATH12K_DBG_MAC,  "vdev %pM started, vdev_id %d\n",
>   		   arvif->vif->addr, arvif->vdev_id);
> @@ -6304,6 +6324,7 @@ ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
>   		if (power_type == IEEE80211_REG_UNSET_AP)
>   			power_type = IEEE80211_REG_LPI_AP;
>   
> +		arvif->chanctx = *ctx;
>   		if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
>   			ath12k_mac_parse_tx_pwr_env(ar, vif, ctx);
>   	}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 5bfca2513730..582c7e80c76b 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -2311,6 +2311,73 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
>   	return ret;
>   }
>   
> +int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
> +				       u32 vdev_id,
> +				       struct ath12k_reg_tpc_power_info *param)
> +{
> +	struct ath12k_wmi_pdev *wmi = ar->wmi;
> +	struct wmi_vdev_set_tpc_power_cmd *cmd;
> +	struct wmi_vdev_ch_power_info_params *ch;
> +	struct sk_buff *skb;
> +	struct wmi_tlv *tlv;
> +	u8 *ptr;
> +	int i, ret, len;
> +
> +	len = sizeof(*cmd) + TLV_HDR_SIZE;
> +	len += (sizeof(*ch) * param->num_pwr_levels);
> +
> +	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	ptr = skb->data;
> +
> +	cmd = (struct wmi_vdev_set_tpc_power_cmd *)ptr;
> +	cmd->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
> +						 WMI_TAG_VDEV_SET_TPC_POWER_CMD) |
> +				      FIELD_PREP(WMI_TLV_LEN,
> +						 sizeof(*cmd) - TLV_HDR_SIZE));

use ath12k_wmi_tlv_cmd_hdr() everywhere you are creating a TLV header


> +	cmd->vdev_id = cpu_to_le32(vdev_id);
> +	cmd->psd_power = cpu_to_le32(param->is_psd_power);
> +	cmd->eirp_power = cpu_to_le32(param->eirp_power);
> +	cmd->power_type_6ghz = cpu_to_le32(param->power_type_6ghz);
> +	ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
> +		   "wmi TPC vdev_id: %d is_psd_power: %d eirp_power: %d power_type_6ghz: %d\n",
> +		   vdev_id, param->is_psd_power, param->eirp_power,
> +		   param->power_type_6ghz);
> +
> +	ptr += sizeof(*cmd);
> +	tlv = (struct wmi_tlv *)ptr;
> +	tlv->header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
> +				  FIELD_PREP(WMI_TLV_LEN,
> +					     param->num_pwr_levels * sizeof(*ch)));
> +
> +	ptr += TLV_HDR_SIZE;
> +	ch = (struct wmi_vdev_ch_power_info_params *)ptr;
> +
> +	for (i = 0; i < param->num_pwr_levels; i++, ch++) {
> +		ch->tlv_header = cpu_to_le32(FIELD_PREP(WMI_TLV_TAG,
> +							WMI_TAG_VDEV_CH_POWER_INFO) |
> +					     FIELD_PREP(WMI_TLV_LEN,
> +							sizeof(*ch) - TLV_HDR_SIZE));
> +
> +		ch->chan_cfreq = cpu_to_le32(param->chan_power_info[i].chan_cfreq);
> +		ch->tx_power = cpu_to_le32(param->chan_power_info[i].tx_power);
> +
> +		ath12k_dbg(ar->ab, ATH12K_DBG_WMI,
> +			   "wmi TPC chan_cfreq: %d , tx_power: %d\n",
> +			   ch->chan_cfreq, ch->tx_power);
> +	}
> +
> +	ret = ath12k_wmi_cmd_send(wmi, skb,
> +				  WMI_VDEV_SET_TPC_POWER_CMDID);
> +	if (ret) {
> +		ath12k_warn(ar->ab, "failed to send WMI_VDEV_SET_TPC_POWER_CMDID\n");
> +		dev_kfree_skb(skb);
> +	}
> +	return ret;
> +}
> +
>   int ath12k_wmi_send_scan_stop_cmd(struct ath12k *ar,
>   				  struct ath12k_wmi_scan_cancel_arg *arg)
>   {
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 9f24f8ded52f..a97eb2544ab0 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -24,6 +24,7 @@
>   
>   struct ath12k_base;
>   struct ath12k;
> +struct ath12k_reg_tpc_power_info;
>   
>   /* There is no signed version of __le32, so for a temporary solution come
>    * up with our own version. The idea is from fs/ntfs/endian.h.
> @@ -388,6 +389,7 @@ enum wmi_tlv_cmd_id {
>   	WMI_VDEV_SET_CUSTOM_AGGR_SIZE_CMDID,
>   	WMI_VDEV_ENCRYPT_DECRYPT_DATA_REQ_CMDID,
>   	WMI_VDEV_ADD_MAC_ADDR_TO_RX_FILTER_CMDID,
> +	WMI_VDEV_SET_TPC_POWER_CMDID,
>   	WMI_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_GRP_PEER),
>   	WMI_PEER_DELETE_CMDID,
>   	WMI_PEER_FLUSH_TIDS_CMDID,
> @@ -1924,6 +1926,8 @@ enum wmi_tlv_tag {
>   	WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
>   	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
>   	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
> +	WMI_TAG_VDEV_SET_TPC_POWER_CMD = 0x3B5,
> +	WMI_TAG_VDEV_CH_POWER_INFO,
>   	WMI_TAG_MAX
>   };
>   
> @@ -2148,7 +2152,8 @@ enum wmi_tlv_service {
>   	WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
>   	WMI_TLV_SERVICE_EXT2_MSG = 220,
>   
> -	WMI_MAX_EXT_SERVICE
> +	WMI_MAX_EXT_SERVICE,
> +	WMI_TLV_SERVICE_EXT_TPC_REG_SUPPORT = 280,
>   };
>   
>   enum {
> @@ -3037,6 +3042,32 @@ struct ath12k_wmi_element_info_arg {
>   	u8 *ptr;
>   };
>   
> +struct wmi_vdev_ch_power_info_params {
> +	__le32 tlv_header;
> +	__le32 chan_cfreq; /* Channel center frequency (MHz) */
> +	/* Unit: dBm, either PSD/EIRP power for this frequency or
> +	 * incremental for non-PSD BW
> +	 */
> +	__le32 tx_power;
> +} __packed;
> +
> +struct wmi_vdev_set_tpc_power_cmd {
> +	__le32 tlv_header;
> +	__le32 vdev_id;
> +	__le32 psd_power; /* Value: 0 or 1, is PSD power or not */
> +	__le32 eirp_power;
> +	/* Maximum EIRP power (dBm units), valid only if power is PSD */
> +	__le32 power_type_6ghz; /* Type: WMI_6 GHz_REG_TYPE, used for halphy CTL lookup */
> +	/* This fixed_param TLV is followed by the below TLVs:
> +	 * num_pwr_levels of wmi_vdev_ch_power_info
> +	 * For PSD power, it is the PSD/EIRP power of the frequency (20 MHz chunks).
> +	 * For non-psd power, the power values are for 20, 40, and till
> +	 * BSS BW power levels.
> +	 * The num_pwr_levels will be checked by sw how many elements present
> +	 * in the variable-length array.
> +	 */
> +} __packed;
> +
>   #define WMI_IE_BITMAP_SIZE             8
>   
>   #define WMI_SCAN_MAX_NUM_SSID                0x0A
> @@ -4824,5 +4855,8 @@ int ath12k_wmi_probe_resp_tmpl(struct ath12k *ar, u32 vdev_id,
>   			       struct sk_buff *tmpl);
>   int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
>   			   enum wmi_host_hw_mode_config_type mode);
> +int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
> +				       u32 vdev_id,
> +				       struct ath12k_reg_tpc_power_info *param);
>   
>   #endif



From quic_wgong at quicinc.com  Tue Sep 19 19:10:38 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Wed, 20 Sep 2023 10:10:38 +0800
Subject: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory
 type
In-Reply-To: <4282f92a-3543-4863-bc00-478ae03759e0@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
 <20230919071724.15505-2-quic_aisr@quicinc.com>
 <4282f92a-3543-4863-bc00-478ae03759e0@quicinc.com>
Message-ID: <46b69fe7-d007-18b0-baae-e59ffb035e42@quicinc.com>

On 9/20/2023 1:47 AM, Jeff Johnson wrote:
> On 9/19/2023 12:17 AM, Aishwarya R wrote:
>> There are 3 types of regulatory rules for AP mode and 6 types for
>> STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
>> to select the exact reg rules.
>>
>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>
> Wen,
> Can you provide a "Tested-on: WCN7850" tag for this series?
>
Jeff, it is this tag below.

I have not tested this serials on WCN7850.

Should I test this serials on WCN7850?

Tested-on: WCN7850 hw2.0 PCI 
WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

[...]



From quic_aisr at quicinc.com  Tue Sep 19 22:48:27 2023
From: quic_aisr at quicinc.com (Aishwarya R (QUIC))
Date: Wed, 20 Sep 2023 05:48:27 +0000
Subject: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory
 type
In-Reply-To: <4282f92a-3543-4863-bc00-478ae03759e0@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
 <20230919071724.15505-2-quic_aisr@quicinc.com>
 <4282f92a-3543-4863-bc00-478ae03759e0@quicinc.com>
Message-ID: <0a83690159fa452b9e7c0ebb3f751b55@quicinc.com>

On 9/19/2023 12:17 AM, Aishwarya R wrote:
>> There are 3 types of regulatory rules for AP mode and 6 types for 
>> STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power 
>> to select the exact reg rules.
>> 
>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1

> Wen,
> Can you provide a "Tested-on: WCN7850" tag for this series?

>> 
>> Signed-off-by: Aishwarya R <quic_aisr at quicinc.com>
>> ---
>>   drivers/net/wireless/ath/ath12k/reg.c |  62 +++++++--
>>   drivers/net/wireless/ath/ath12k/reg.h |   6 +-
>>   drivers/net/wireless/ath/ath12k/wmi.c | 182 +++++++++++++++++++++++++-
>>   drivers/net/wireless/ath/ath12k/wmi.h |  27 +++-
>>   4 files changed, 257 insertions(+), 20 deletions(-)
>> 
>> diff --git a/drivers/net/wireless/ath/ath12k/reg.c 
>> b/drivers/net/wireless/ath/ath12k/reg.c
>> index 6ede91ebc8e1..8501f77eee55 100644
>> --- a/drivers/net/wireless/ath/ath12k/reg.c
>> +++ b/drivers/net/wireless/ath/ath12k/reg.c
>> @@ -28,6 +28,21 @@ static const struct ieee80211_regdomain ath12k_world_regd = {
>>   	}
>>   };
>>   
>> +enum wmi_reg_6g_ap_type
>> +ath12k_ieee80211_ap_pwr_type_convert(enum ieee80211_ap_reg_power 
>> +power_type) {
>> +	switch (power_type) {
>> +	case IEEE80211_REG_LPI_AP:
>> +		return WMI_REG_INDOOR_AP;
>> +	case IEEE80211_REG_SP_AP:
>> +		return WMI_REG_STD_POWER_AP;
>> +	case IEEE80211_REG_VLP_AP:
>> +		return WMI_REG_VLP_AP;
>> +	default:
>> +		return WMI_REG_MAX_AP_TYPE;
>> +	}
>> +}
>> +
>>   static bool ath12k_regdom_changes(struct ath12k *ar, char *alpha2)
>>   {
>>   	const struct ieee80211_regdomain *regd; @@ -562,14 +577,16 @@ 
>> ath12k_reg_update_weather_radar_band(struct ath12k_base *ab,
>>   
>>   struct ieee80211_regdomain *
>>   ath12k_reg_build_regd(struct ath12k_base *ab,
>> -		      struct ath12k_reg_info *reg_info, bool intersect)
>> +		      struct ath12k_reg_info *reg_info, bool intersect,
>> +		      enum wmi_vdev_type vdev_type,
>> +		      enum ieee80211_ap_reg_power power_type)
>>   {
>>   	struct ieee80211_regdomain *tmp_regd, *default_regd, *new_regd = NULL;
>> -	struct ath12k_reg_rule *reg_rule;
>> +	struct ath12k_reg_rule *reg_rule, *reg_rule_6ghz;
>>   	u8 i = 0, j = 0, k = 0;
>>   	u8 num_rules;
>>   	u16 max_bw;
>> -	u32 flags;
>> +	u32 flags, reg_6ghz_number, max_bw_6ghz;
>>   	char alpha2[3];
>>   
>>   	num_rules = reg_info->num_5g_reg_rules + 
>> reg_info->num_2g_reg_rules; @@ -578,8 +595,33 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
>>   	 * This can be updated to choose the combination dynamically based on AP
>>   	 * type and client type, after complete 6G regulatory support is added.
>>   	 */
>> -	if (reg_info->is_ext_reg_event)
>> -		num_rules += reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP];
>> +	if (reg_info->is_ext_reg_event) {
>> +		if (vdev_type == WMI_VDEV_TYPE_STA) {
>> +			enum wmi_reg_6g_ap_type ap_type;
>> +
>> +			ap_type = ath12k_ieee80211_ap_pwr_type_convert(power_type);
>> +
>> +			if (ap_type == WMI_REG_MAX_AP_TYPE)
>> +				ap_type = WMI_REG_INDOOR_AP;

> where is power_type coming from and can it be tainted?
> if we always expect a valid value then why not just have the conversion function set the default to WMI_REG_INDOOR_AP?
> Are there places in upcoming patches that actually perform error handling if the conversion function returns MAX?

>> +			reg_6ghz_number = reg_info->num_6g_reg_rules_cl
>> +					[ap_type][WMI_REG_DEFAULT_CLIENT];

> please avoid splitting lines in the middle of a variable reference; that decreases the readability of the code. It is better to exceed some arbitrary line length guideline. you can use a client_type = WMI_REG_DEFAULT_CLIENT assignment to help reduce the length.
> if the line is still exceedingly long, split the lines after =

> repeat for all cases that follow


>> +			if (reg_6ghz_number == 0) {
>> +				ap_type = WMI_REG_INDOOR_AP;
>> +				reg_6ghz_number = reg_info->num_6g_reg_rules_cl
>> +						[ap_type][WMI_REG_DEFAULT_CLIENT];
>> +			}
>> +			reg_rule_6ghz = reg_info->reg_rules_6g_client_ptr
>> +					[ap_type][WMI_REG_DEFAULT_CLIENT];
>> +			max_bw_6ghz = reg_info->max_bw_6g_client
>> +					[ap_type][WMI_REG_DEFAULT_CLIENT];
>> +		} else {
>> +			reg_6ghz_number = reg_info->num_6g_reg_rules_ap
>> +					[WMI_REG_INDOOR_AP];
>> +			reg_rule_6ghz = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP];
>> +			max_bw_6ghz = reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP];
>> +		}
>> +		num_rules += reg_6ghz_number;
>> +	}
>>   
>>   	if (!num_rules)
>>   		goto ret;
>> @@ -626,12 +668,10 @@ ath12k_reg_build_regd(struct ath12k_base *ab,
>>   			 * per other BW rule flags we pass from here
>>   			 */
>>   			flags = NL80211_RRF_AUTO_BW;
>> -		} else if (reg_info->is_ext_reg_event &&
>> -			   reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP] &&
>> -			(k < reg_info->num_6g_reg_rules_ap[WMI_REG_INDOOR_AP])) {
>> -			reg_rule = reg_info->reg_rules_6g_ap_ptr[WMI_REG_INDOOR_AP] + k++;
>> -			max_bw = min_t(u16, reg_rule->max_bw,
>> -				       reg_info->max_bw_6g_ap[WMI_REG_INDOOR_AP]);
>> +		} else if (reg_info->is_ext_reg_event && reg_6ghz_number &&
>> +			   (k < reg_6ghz_number)) {
>> +			reg_rule = reg_rule_6ghz + k++;
>> +			max_bw = min_t(u16, reg_rule->max_bw, max_bw_6ghz);
>>   			flags = NL80211_RRF_AUTO_BW;
>>   		} else {
>>   			break;
>> diff --git a/drivers/net/wireless/ath/ath12k/reg.h 
>> b/drivers/net/wireless/ath/ath12k/reg.h
>> index 56d009a47234..56324e30a358 100644
>> --- a/drivers/net/wireless/ath/ath12k/reg.h
>> +++ b/drivers/net/wireless/ath/ath12k/reg.h
>> @@ -88,7 +88,11 @@ void ath12k_reg_free(struct ath12k_base *ab);
>>   void ath12k_regd_update_work(struct work_struct *work);
>>   struct ieee80211_regdomain *ath12k_reg_build_regd(struct ath12k_base *ab,
>>   						  struct ath12k_reg_info *reg_info,
>> -						  bool intersect);
>> +						  bool intersect,
>> +						  enum wmi_vdev_type vdev_type,
>> +						  enum ieee80211_ap_reg_power power_type); enum 
>> +wmi_reg_6g_ap_type ath12k_ieee80211_ap_pwr_type_convert(enum 
>> +ieee80211_ap_reg_power power_type);
>>   int ath12k_regd_update(struct ath12k *ar, bool init);
>>   int ath12k_reg_update_chan_list(struct ath12k *ar);
>>   
>> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c 
>> b/drivers/net/wireless/ath/ath12k/wmi.c
>> index af910296c41e..1b9ce9a2ae96 100644
>> --- a/drivers/net/wireless/ath/ath12k/wmi.c
>> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
>> @@ -4152,6 +4152,119 @@ static struct ath12k_reg_rule
>>   	return reg_rule_ptr;
>>   }
>>   
>> +static char *ath12k_cc_status_to_str(enum ath12k_reg_cc_code code)

> all of these *_str() functions should return const char *

>> +{
>> +	switch (code) {
>> +	case REG_SET_CC_STATUS_PASS:
>> +		return "REG_SET_CC_STATUS_PASS";
>> +	case REG_CURRENT_ALPHA2_NOT_FOUND:
>> +		return "REG_CURRENT_ALPHA2_NOT_FOUND";
>> +	case REG_INIT_ALPHA2_NOT_FOUND:
>> +		return "REG_INIT_ALPHA2_NOT_FOUND";
>> +	case REG_SET_CC_CHANGE_NOT_ALLOWED:
>> +		return "REG_SET_CC_CHANGE_NOT_ALLOWED";
>> +	case REG_SET_CC_STATUS_NO_MEMORY:
>> +		return "REG_SET_CC_STATUS_NO_MEMORY";
>> +	case REG_SET_CC_STATUS_FAIL:
>> +		return "REG_SET_CC_STATUS_FAIL";
>> +	default:
>> +		return "unknown cc status";
>> +	}
>> +};
>> +
>> +static char *ath12k_super_reg_6ghz_to_str(enum reg_super_domain_6ghz 
>> +domain_id) {
>> +	switch (domain_id) {
>> +	case FCC1_6GHZ:
>> +		return "FCC1_6GHZ";
>> +	case ETSI1_6GHZ:
>> +		return "ETSI1_6GHZ";
>> +	case ETSI2_6GHZ:
>> +		return "ETSI2_6GHZ";
>> +	case APL1_6GHZ:
>> +		return "APL1_6GHZ";
>> +	case FCC1_6GHZ_CL:
>> +		return "FCC1_6GHZ_CL";
>> +	default:
>> +		return "unknown domain id";
>> +	}
>> +}
>> +
>> +static char *ath12k_6ghz_client_type_to_str(enum 
>> +wmi_reg_6g_client_type type) {
>> +	switch (type) {
>> +	case WMI_REG_DEFAULT_CLIENT:
>> +		return "DEFAULT CLIENT";
>> +	case WMI_REG_SUBORDINATE_CLIENT:
>> +		return "SUBORDINATE CLIENT";
>> +	default:
>> +		return "unknown client type";
>> +	}
>> +}
>> +
>> +static char *ath12k_6ghz_ap_type_to_str(enum wmi_reg_6g_ap_type type) 
>> +{
>> +	switch (type) {
>> +	case WMI_REG_INDOOR_AP:
>> +		return "INDOOR AP";
>> +	case WMI_REG_STD_POWER_AP:
>> +		return "STANDARD POWER AP";
>> +	case WMI_REG_VLP_AP:
>> +		return "VERY LOW POWER AP";
>> +	default:
>> +		return "unknown AP type";
>> +	}
>> +}
>> +
>> +static char *ath12k_sub_reg_6ghz_to_str(enum reg_subdomains_6ghz 
>> +sub_id) {
>> +	switch (sub_id) {
>> +	case FCC1_CLIENT_LPI_REGULAR_6GHZ:
>> +		return "FCC1_CLIENT_LPI_REGULAR_6GHZ";
>> +	case FCC1_CLIENT_SP_6GHZ:
>> +		return "FCC1_CLIENT_SP_6GHZ";
>> +	case FCC1_AP_LPI_6GHZ:
>> +		return "FCC1_AP_LPI_6GHZ/FCC1_CLIENT_LPI_SUBORDINATE";
>> +	case FCC1_AP_SP_6GHZ:
>> +		return "FCC1_AP_SP_6GHZ";
>> +	case ETSI1_LPI_6GHZ:
>> +		return "ETSI1_LPI_6GHZ";
>> +	case ETSI1_VLP_6GHZ:
>> +		return "ETSI1_VLP_6GHZ";
>> +	case ETSI2_LPI_6GHZ:
>> +		return "ETSI2_LPI_6GHZ";
>> +	case ETSI2_VLP_6GHZ:
>> +		return "ETSI2_VLP_6GHZ";
>> +	case APL1_LPI_6GHZ:
>> +		return "APL1_LPI_6GHZ";
>> +	case APL1_VLP_6GHZ:
>> +		return "APL1_VLP_6GHZ";
>> +	case EMPTY_6GHZ:
>> +		return "N/A";
>> +	default:
>> +		return "unknown sub reg id";
>> +	}
>> +}
>> +
>> +static void ath12k_print_reg_rule(struct ath12k_base *ab, char *prev,
>> +				  u32 num_reg_rules,
>> +				  struct ath12k_reg_rule *reg_rule_ptr) {
>> +	struct ath12k_reg_rule *reg_rule = reg_rule_ptr;
>> +	u32 count;
>> +
>> +	ath12k_dbg(ab, ATH12K_DBG_WMI, "%s reg rules number %d\n", prev, 
>> +num_reg_rules);
>> +
>> +	for (count = 0; count < num_reg_rules; count++) {
>> +		ath12k_dbg(ab, ATH12K_DBG_WMI,
>> +			   "reg rule %d: (%d - %d @ %d) (%d, %d) (FLAGS %d) (psd flag %d EIRP %d dB/MHz)\n",
>> +			   count + 1, reg_rule->start_freq, reg_rule->end_freq,
>> +			   reg_rule->max_bw, reg_rule->ant_gain, reg_rule->reg_power,
>> +			   reg_rule->flags, reg_rule->psd_flag, reg_rule->psd_eirp);
>> +		reg_rule++;
>> +	}
>> +}
>> +
>>   static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   						   struct sk_buff *skb,
>>   						   struct ath12k_reg_info *reg_info) @@ -4163,7 +4276,7 @@ 
>> static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   	u32 num_6g_reg_rules_ap[WMI_REG_CURRENT_MAX_AP_TYPE];
>>   	u32 num_6g_reg_rules_cl[WMI_REG_CURRENT_MAX_AP_TYPE][WMI_REG_MAX_CLIENT_TYPE];
>>   	u32 total_reg_rules = 0;
>> -	int ret, i, j;
>> +	int ret, i, j, skip_6ghz_rules_in_5ghz_rules = 0;
>>   
>>   	ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel 
>> list\n");
>>   
>> @@ -4265,6 +4378,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   	 * from 5G rules list.
>>   	 */
>>   	if (memcmp(reg_info->alpha2, "US", 2) == 0) {
>> +		ath12k_dbg(ab, ATH12K_DBG_WMI,
>> +			   "US 5 GHz reg rules number %d from fw",
>> +			   reg_info->num_5g_reg_rules);
>> +
>> +		if (reg_info->num_5g_reg_rules >> REG_US_5G_NUM_REG_RULES)
>> +			skip_6ghz_rules_in_5ghz_rules = reg_info->num_5g_reg_rules -
>> +						    REG_US_5G_NUM_REG_RULES;

> I'd split this line after = instead of in the middle of the expression

>>   		reg_info->num_5g_reg_rules = REG_US_5G_NUM_REG_RULES;
>>   		num_5g_reg_rules = reg_info->num_5g_reg_rules;
>>   	}
>> @@ -4297,6 +4417,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   		break;
>>   	}
>>   
>> +	ath12k_dbg(ab, ATH12K_DBG_WMI,
>> +		   "%s: status_code %s", __func__,
>> +		   ath12k_cc_status_to_str(reg_info->status_code));
>> +
>>   	reg_info->is_ext_reg_event = true;
>>   
>>   	reg_info->min_bw_2g = le32_to_cpu(ev->min_bw_2g); @@ -4325,6 
>> +4449,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   			le32_to_cpu(ev->max_bw_6g_client_vlp[i]);
>>   	}
>>   
>> +	ath12k_dbg(ab, ATH12K_DBG_WMI,
>> +		   "%s: status_code %s", __func__,
>> +		   ath12k_cc_status_to_str(reg_info->status_code));
>> +
>>   	ath12k_dbg(ab, ATH12K_DBG_WMI,
>>   		   "%s:cc_ext %s dsf %d BW: min_2g %d max_2g %d min_5g %d max_5g %d",
>>   		   __func__, reg_info->alpha2, reg_info->dfs_region, @@ -4368,10 
>> +4496,13 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   			ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");
>>   			return -ENOMEM;
>>   		}
>> +		ath12k_print_reg_rule(ab, "2 GHz",
>> +				      num_2g_reg_rules,
>> +				      reg_info->reg_rules_2g_ptr);
>>   	}
>> +	ext_wmi_reg_rule += num_2g_reg_rules;
>>   
>>   	if (num_5g_reg_rules) {
>> -		ext_wmi_reg_rule += num_2g_reg_rules;
>>   		reg_info->reg_rules_5g_ptr =
>>   			create_ext_reg_rules_from_wmi(num_5g_reg_rules,
>>   						      ext_wmi_reg_rule);
>> @@ -4381,9 +4512,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   			ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");
>>   			return -ENOMEM;
>>   		}
>> +		ath12k_print_reg_rule(ab, "5 GHz",
>> +				      num_5g_reg_rules,
>> +				      reg_info->reg_rules_5g_ptr);
>>   	}
>>   
>> -	ext_wmi_reg_rule += num_5g_reg_rules;
>> +	/* We have adjusted the number of 5 GHz reg rules via the hack above.
>> +	 * Here, we adjust that many extra rules which came with 5g reg rules
>> +	 * (for cc: US)
>> +	 *
>> +	 * NOTE: skip_6ghz_rules_in_5ghz_rules will be 0 for rest other cases.
>> +	 */
>> +	ext_wmi_reg_rule += num_5g_reg_rules + 
>> +skip_6ghz_rules_in_5ghz_rules;
>>   
>>   	for (i = 0; i < WMI_REG_CURRENT_MAX_AP_TYPE; i++) {
>>   		reg_info->reg_rules_6g_ap_ptr[i] = @@ -4396,10 +4536,17 @@ static 
>> int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   			return -ENOMEM;
>>   		}
>>   
>> +		ath12k_print_reg_rule(ab, ath12k_6ghz_ap_type_to_str(i),
>> +				      num_6g_reg_rules_ap[i],
>> +				      reg_info->reg_rules_6g_ap_ptr[i]);
>> +
>>   		ext_wmi_reg_rule += num_6g_reg_rules_ap[i];
>>   	}
>>   
>>   	for (j = 0; j < WMI_REG_CURRENT_MAX_AP_TYPE; j++) {
>> +		ath12k_dbg(ab, ATH12K_DBG_WMI,
>> +			   "AP type %s", ath12k_6ghz_ap_type_to_str(j));
>> +
>>   		for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
>>   			reg_info->reg_rules_6g_client_ptr[j][i] =
>>   				create_ext_reg_rules_from_wmi(num_6g_reg_rules_cl[j][i],
>> @@ -4411,6 +4558,10 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   				return -ENOMEM;
>>   			}
>>   
>> +			ath12k_print_reg_rule(ab, ath12k_6ghz_client_type_to_str(i),
>> +					      num_6g_reg_rules_cl[j][i],
>> +					      reg_info->reg_rules_6g_client_ptr[j][i]);
>> +
>>   			ext_wmi_reg_rule += num_6g_reg_rules_cl[j][i];
>>   		}
>>   	}
>> @@ -4425,6 +4576,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   	reg_info->domain_code_6g_ap[WMI_REG_VLP_AP] =
>>   		le32_to_cpu(ev->domain_code_6g_ap_vlp);
>>   
>> +	ath12k_dbg(ab, ATH12K_DBG_WMI,
>> +		   "6 GHz reg info client type %s rnr_tpe_usable %d unspecified_ap_usable %d AP sub domain: lpi %s , sp %s , vlp %s\n",
>> +		   ath12k_6ghz_client_type_to_str(reg_info->client_type),
>> +		   reg_info->rnr_tpe_usable,
>> +		   reg_info->unspecified_ap_usable,
>> +		   ath12k_sub_reg_6ghz_to_str
>> +		   (le32_to_cpu(ev->domain_code_6g_ap_lpi)),
>> +		   ath12k_sub_reg_6ghz_to_str
>> +		   (le32_to_cpu(ev->domain_code_6g_ap_sp)),
>> +		   ath12k_sub_reg_6ghz_to_str
>> +		   (le32_to_cpu(ev->domain_code_6g_ap_vlp)));

> avoid splitting the line between a function and it's parameters.
> it is ok to split in the middle of a parameter list, but the first parameter should almost always be on the same line as the function

>> +
>>   	for (i = 0; i < WMI_REG_MAX_CLIENT_TYPE; i++) {
>>   		reg_info->domain_code_6g_client[WMI_REG_INDOOR_AP][i] =
>>   			le32_to_cpu(ev->domain_code_6g_client_lpi[i]);
>> @@ -4432,12 +4595,18 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>>   			le32_to_cpu(ev->domain_code_6g_client_sp[i]);
>>   		reg_info->domain_code_6g_client[WMI_REG_VLP_AP][i] =
>>   			le32_to_cpu(ev->domain_code_6g_client_vlp[i]);
>> +		ath12k_dbg(ab, ATH12K_DBG_WMI,
>> +			   "6 GHz AP BW: lpi %d - %d sp %d - %d vlp %d - %d\n",
>> +			   ev->min_bw_6g_ap_lpi, ev->max_bw_6g_ap_lpi,
>> +			   ev->min_bw_6g_ap_sp, ev->max_bw_6g_ap_sp,
>> +			   ev->min_bw_6g_ap_vlp, ev->max_bw_6g_ap_vlp);
>>   	}
>>   
>>   	reg_info->domain_code_6g_super_id = 
>> le32_to_cpu(ev->domain_code_6g_super_id);
>>   
>> -	ath12k_dbg(ab, ATH12K_DBG_WMI, "6g client_type: %d domain_code_6g_super_id: %d",
>> -		   reg_info->client_type, reg_info->domain_code_6g_super_id);
>> +	ath12k_dbg(ab, ATH12K_DBG_WMI, "6 GHz client_type: %s 6 GHz super domain %s",
>> +		   ath12k_6ghz_client_type_to_str(reg_info->client_type),
>> +		   
>> +ath12k_super_reg_6ghz_to_str(reg_info->domain_code_6g_super_id));
>>   
>>   	ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel 
>> list\n");
>>   
>> @@ -5192,7 +5361,8 @@ static int ath12k_reg_chan_list_event(struct ath12k_base *ab, struct sk_buff *sk
>>   	    !ath12k_reg_is_world_alpha((char *)reg_info->alpha2))
>>   		intersect = true;
>>   
>> -	regd = ath12k_reg_build_regd(ab, reg_info, intersect);
>> +	regd = ath12k_reg_build_regd(ab, reg_info, intersect,
>> +				     WMI_VDEV_TYPE_AP, IEEE80211_REG_UNSET_AP);

> why is this forced to AP?
> where is logic for client?

>>   	if (!regd) {
>>   		ath12k_warn(ab, "failed to build regd from reg_info\n");
>>   		goto fallback;
>> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h 
>> b/drivers/net/wireless/ath/ath12k/wmi.h
>> index 08a8c9e0f59f..966e6ba4e162 100644
>> --- a/drivers/net/wireless/ath/ath12k/wmi.h
>> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
>> @@ -2832,8 +2832,8 @@ struct ath12k_wmi_rx_reorder_queue_remove_arg {
>>   #define REG_RULE_MAX_BW				0x0000ffff
>>   #define REG_RULE_REG_PWR			0x00ff0000
>>   #define REG_RULE_ANT_GAIN			0xff000000
>> -#define REG_RULE_PSD_INFO			BIT(2)
>> -#define REG_RULE_PSD_EIRP			0xffff0000
>> +#define REG_RULE_PSD_INFO                       BIT(0)
>> +#define REG_RULE_PSD_EIRP                       0xff0000
>>   
>>   #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
>>   #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) @@ -3844,6 +3844,29 @@ 
>> enum {
>>   	WMI_REG_SET_CC_STATUS_FAIL = 5,
>>   };
>>   
>> +enum reg_subdomains_6ghz {
>> +	EMPTY_6GHZ = 0x0,
>> +	FCC1_CLIENT_LPI_REGULAR_6GHZ = 0x01,
>> +	FCC1_CLIENT_SP_6GHZ = 0x02,
>> +	FCC1_AP_LPI_6GHZ = 0x03,
>> +	FCC1_CLIENT_LPI_SUBORDINATE = FCC1_AP_LPI_6GHZ,
>> +	FCC1_AP_SP_6GHZ = 0x04,
>> +	ETSI1_LPI_6GHZ = 0x10,
>> +	ETSI1_VLP_6GHZ = 0x11,
>> +	ETSI2_LPI_6GHZ = 0x12,
>> +	ETSI2_VLP_6GHZ = 0x13,
>> +	APL1_LPI_6GHZ = 0x20,
>> +	APL1_VLP_6GHZ = 0x21,
>> +};
>> +
>> +enum reg_super_domain_6ghz {
>> +	FCC1_6GHZ = 0x01,
>> +	ETSI1_6GHZ = 0x02,
>> +	ETSI2_6GHZ = 0x03,
>> +	APL1_6GHZ = 0x04,
>> +	FCC1_6GHZ_CL = 0x05,
>> +};
>> +
>>   #define WMI_REG_CLIENT_MAX 4
>>   
>>   struct wmi_reg_chan_list_cc_ext_event {

Thanks for your review. I will address all your comments in next revision.

Aishwarya 

From kvalo at kernel.org  Wed Sep 20 06:15:00 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 20 Sep 2023 13:15:00 +0000 (UTC)
Subject: [PATCH 1/2] wifi: ath12k: fix WARN_ON during
 ath12k_mac_update_vif_chan
In-Reply-To: <20230802085852.19821-2-quic_mdharane@quicinc.com>
References: <20230802085852.19821-2-quic_mdharane@quicinc.com>
Message-ID: <169521569886.1118199.14851919916487311370.kvalo@kernel.org>

Manish Dharanenthiran <quic_mdharane at quicinc.com> wrote:

> Fix WARN_ON() from ath12k_mac_update_vif_chan() if vdev is not up.
> Since change_chanctx can be called even before vdev_up.
> 
> Do vdev stop followed by a vdev start in case of vdev is down.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0-02903-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Manish Dharanenthiran <quic_mdharane at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

2 patches applied to ath-next branch of ath.git, thanks.

8b8b990fe495 wifi: ath12k: fix WARN_ON during ath12k_mac_update_vif_chan
3f53624f74f4 wifi: ath12k: fix radar detection in 160 MHz

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230802085852.19821-2-quic_mdharane at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Wed Sep 20 06:24:38 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 20 Sep 2023 13:24:38 +0000 (UTC)
Subject: [PATCH v3] wifi: ath12k: enable 320 MHz bandwidth for 6 GHz band
 in
 EHT PHY capability for WCN7850
In-Reply-To: <20230828040420.2165-1-quic_wgong@quicinc.com>
References: <20230828040420.2165-1-quic_wgong@quicinc.com>
Message-ID: <169521627689.1118199.8777112577980679434.kvalo@kernel.org>

Wen Gong <quic_wgong at quicinc.com> wrote:

> 320 MHz bandwidth is reported only for single PHY mode for WCN7850, get it
> from WMI_HOST_HW_MODE_SINGLE ath12k_wmi_caps_ext_params and report it for
> 6 GHz band.
> 
> After this patch, "iw list" shows 320 MHz support for WCN7850:
> 
> EHT Iftypes: managed
>         EHT PHY Capabilities: (0xe26f090010768800):
>                 320MHz in 6GHz Supported
>         EHT bw=320 MHz, max NSS for MCS 8-9: Rx=0, Tx=0
>         EHT bw=320 MHz, max NSS for MCS 10-11: Rx=0, Tx=0
>         EHT bw=320 MHz, max NSS for MCS 12-13: Rx=0, Tx=0
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

d4e244c85e45 wifi: ath12k: enable 320 MHz bandwidth for 6 GHz band in EHT PHY capability for WCN7850

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230828040420.2165-1-quic_wgong at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Wed Sep 20 06:34:27 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 20 Sep 2023 16:34:27 +0300
Subject: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz
 Regulatory type
In-Reply-To: <0a83690159fa452b9e7c0ebb3f751b55@quicinc.com> (Aishwarya R.'s
	message of "Wed, 20 Sep 2023 05:48:27 +0000")
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
	<20230919071724.15505-2-quic_aisr@quicinc.com>
	<4282f92a-3543-4863-bc00-478ae03759e0@quicinc.com>
	<0a83690159fa452b9e7c0ebb3f751b55@quicinc.com>
Message-ID: <87zg1h9dek.fsf@kernel.org>

"Aishwarya R (QUIC)" <quic_aisr at quicinc.com> writes:

[deleting ~500 lines of unnecessary quotes]

> Thanks for your review. I will address all your comments in next revision.

Please edit your quotes and only include the necessary information in
your reply. These kind of huge mails make use of patchwork very
difficult:

https://patchwork.kernel.org/project/linux-wireless/patch/20230919071724.15505-2-quic_aisr at quicinc.com/

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From kvalo at kernel.org  Wed Sep 20 06:37:36 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 20 Sep 2023 13:37:36 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: change to initialize recovery variables
 earlier
 in ath12k_core_reset()
In-Reply-To: <20230830060850.18881-1-quic_wgong@quicinc.com>
References: <20230830060850.18881-1-quic_wgong@quicinc.com>
Message-ID: <169521705525.1118199.1914505460908896362.kvalo@kernel.org>

Wen Gong <quic_wgong at quicinc.com> wrote:

> Sometimes device recovery fail with this operation.
> Run test command for many times:
> echo assert > /sys/kernel/debug/ath12k/wcn7850\ hw2.0_0000\:03\:00.0/simulate_fw_crash
> 
> While recovery start, ath12k_core_post_reconfigure_recovery() will
> call ieee80211_restart_hw(), and the restart_work which queued by
> ieee80211_restart_hw() is running in another thread, it will call
> into ath12k_mac_op_start() and ath12k_mac_wait_reconfigure(), and
> the variables ab->recovery_start_count and ab->recovery_start is used
> in ath12k_mac_wait_reconfigure(), so ath12k need to initialize the
> variables before queue the restart_work, otherwise ath12k_mac_wait_reconfigure()
> maybe use the un-initialized variables. Change to initialize the 2
> variables earlier and then recovery process become correct.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

41e7a399aea1 wifi: ath12k: change to initialize recovery variables earlier in ath12k_core_reset()

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230830060850.18881-1-quic_wgong at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Wed Sep 20 06:38:33 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 20 Sep 2023 13:38:33 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: fix possible out-of-bound read in
 ath12k_htt_pull_ppdu_stats()
In-Reply-To: <20230901015602.45112-1-quic_bqiang@quicinc.com>
References: <20230901015602.45112-1-quic_bqiang@quicinc.com>
Message-ID: <169521711198.1118199.13181861616088470480.kvalo@kernel.org>

Baochen Qiang <quic_bqiang at quicinc.com> wrote:

> len is extracted from HTT message and could be an unexpected value in
> case errors happen, so add validation before using to avoid possible
> out-of-bound read in the following message iteration and parsing.
> 
> The same issue also applies to ppdu_info->ppdu_stats.common.num_users,
> so validate it before using too.
> 
> These are found during code review.
> 
> Compile test only.
> 
> Signed-off-by: Baochen Qiang <quic_bqiang at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

1bc44a505a22 wifi: ath12k: fix possible out-of-bound read in ath12k_htt_pull_ppdu_stats()

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230901015602.45112-1-quic_bqiang at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Wed Sep 20 06:39:16 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 20 Sep 2023 13:39:16 +0000 (UTC)
Subject: [PATCH] wifi: ath11k: add chip id board name while searching
 board-2.bin for WCN6855
In-Reply-To: <20230830060226.18664-1-quic_wgong@quicinc.com>
References: <20230830060226.18664-1-quic_wgong@quicinc.com>
Message-ID: <169521715461.1118199.17273674544092350994.kvalo@kernel.org>

Wen Gong <quic_wgong at quicinc.com> wrote:

> Sometimes board-2.bin does not have the board data which matched the
> parameters such as bus type, vendor, device, subsystem-vendor,
> subsystem-device, qmi-chip-id and qmi-board-id, then wlan will load fail.
> 
> Hence add another type which only matches the bus type and qmi-chip-id,
> then the ratio of missing board data reduced.
> 
> Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.23
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

1133af5aea58 wifi: ath11k: add chip id board name while searching board-2.bin for WCN6855

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230830060226.18664-1-quic_wgong at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Wed Sep 20 07:52:35 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 20 Sep 2023 14:52:35 +0000 (UTC)
Subject: [PATCH v2 wireless-next 7/9] wifi: ath12k: Remove unnecessary
 (void*)
 conversions
In-Reply-To: <20230919045142.524226-1-yunchuan@nfschina.com>
References: <20230919045142.524226-1-yunchuan@nfschina.com>
Message-ID: <169522155403.1418260.5064455550425202498.kvalo@kernel.org>

Wu Yunchuan <yunchuan at nfschina.com> wrote:

> No need cast (void*) to (struct hal_rx_ppdu_end_user_stats *),
> (struct ath12k_rx_desc_info *) or (struct hal_tx_msdu_ext_desc *).
> Change the prototype to remove the local variable.
> 
> Signed-off-by: Wu Yunchuan <yunchuan at nfschina.com>
> Suggested-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

This added new warnings:

drivers/net/wireless/ath/ath12k/dp_mon.c:25: line length of 92 exceeds 90 columns
drivers/net/wireless/ath/ath12k/dp_mon.c:26: line length of 95 exceeds 90 columns

I fixed them in the pending branch by renaming ppdu_end_user to stats and
moving rx_user_status to it's own line:

https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=pending&id=5c0910fdf1d800f1aeb8ab3e860e61bebec0091b

No need to resend because of this.

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230919045142.524226-1-yunchuan at nfschina.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From quic_jjohnson at quicinc.com  Wed Sep 20 11:03:47 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Wed, 20 Sep 2023 11:03:47 -0700
Subject: [PATCH v2 wireless-next 7/9] wifi: ath12k: Remove unnecessary
 (void*) conversions
In-Reply-To: <169522155403.1418260.5064455550425202498.kvalo@kernel.org>
References: <20230919045142.524226-1-yunchuan@nfschina.com>
 <169522155403.1418260.5064455550425202498.kvalo@kernel.org>
Message-ID: <5a67f11d-0cd2-42bd-bbda-58b0cd196add@quicinc.com>

On 9/20/2023 7:52 AM, Kalle Valo wrote:
> Wu Yunchuan <yunchuan at nfschina.com> wrote:
> 
>> No need cast (void*) to (struct hal_rx_ppdu_end_user_stats *),
>> (struct ath12k_rx_desc_info *) or (struct hal_tx_msdu_ext_desc *).
>> Change the prototype to remove the local variable.
>>
>> Signed-off-by: Wu Yunchuan <yunchuan at nfschina.com>
>> Suggested-by: Jeff Johnson <quic_jjohnson at quicinc.com>
>> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

For the Pending change:
Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>



From quic_jjohnson at quicinc.com  Wed Sep 20 11:09:17 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Wed, 20 Sep 2023 11:09:17 -0700
Subject: [PATCH 1/7] wifi: ath12k: add support to select 6 GHz Regulatory
 type
In-Reply-To: <46b69fe7-d007-18b0-baae-e59ffb035e42@quicinc.com>
References: <20230919071724.15505-1-quic_aisr@quicinc.com>
 <20230919071724.15505-2-quic_aisr@quicinc.com>
 <4282f92a-3543-4863-bc00-478ae03759e0@quicinc.com>
 <46b69fe7-d007-18b0-baae-e59ffb035e42@quicinc.com>
Message-ID: <4c9423bf-1667-45dd-ab06-e5183875a21d@quicinc.com>

On 9/19/2023 7:10 PM, Wen Gong wrote:
> On 9/20/2023 1:47 AM, Jeff Johnson wrote:
>> On 9/19/2023 12:17 AM, Aishwarya R wrote:
>>> There are 3 types of regulatory rules for AP mode and 6 types for
>>> STATION mode. This is to add wmi_vdev_type and ieee80211_ap_reg_power
>>> to select the exact reg rules.
>>>
>>> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
>>
>> Wen,
>> Can you provide a "Tested-on: WCN7850" tag for this series?
>>
> Jeff, it is this tag below.
> 
> I have not tested this serials on WCN7850.
> 
> Should I test this serials on WCN7850?

For a large, non-trivial patchset such as this I'd like to be sure that 
both AP-focused and STA-focused products are tested before merge.

/jeff



From kvalo at kernel.org  Thu Sep 21 01:02:14 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 21 Sep 2023 08:02:14 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: fix possible out-of-bound write in
 ath12k_wmi_ext_hal_reg_caps()
In-Reply-To: <20230830020716.5420-1-quic_bqiang@quicinc.com>
References: <20230830020716.5420-1-quic_bqiang@quicinc.com>
Message-ID: <169528333260.1539628.5137606082787828430.kvalo@kernel.org>

Baochen Qiang <quic_bqiang at quicinc.com> wrote:

> reg_cap.phy_id is extracted from WMI event and could be an unexpected value
> in case some errors happen. As a result out-of-bound write may occur to
> soc->hal_reg_cap. Fix it by validating reg_cap.phy_id before using it.
> 
> This is found during code review.
> 
> Compile tested only.
> 
> Signed-off-by: Baochen Qiang <quic_bqiang at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

b302dce3d9ed wifi: ath12k: fix possible out-of-bound write in ath12k_wmi_ext_hal_reg_caps()

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230830020716.5420-1-quic_bqiang at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 21 01:02:55 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 21 Sep 2023 08:02:55 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: fix DMA unmap warning on NULL DMA address
In-Reply-To: <20230830021131.5610-1-quic_bqiang@quicinc.com>
References: <20230830021131.5610-1-quic_bqiang@quicinc.com>
Message-ID: <169528337320.1539628.12793449694122971146.kvalo@kernel.org>

Baochen Qiang <quic_bqiang at quicinc.com> wrote:

> In ath12k_dp_tx(), if we reach fail_dma_unmap due to some errors,
> current code does DMA unmap unconditionally on skb_cb->paddr_ext_desc.
> However, skb_cb->paddr_ext_desc may be NULL and thus we get below
> warning:
> 
> kernel: [ 8887.076212] WARNING: CPU: 3 PID: 0 at drivers/iommu/dma-iommu.c:1077 iommu_dma_unmap_page+0x79/0x90
> 
> Fix it by checking skb_cb->paddr_ext_desc before unmap it.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Fixes: d889913205cf ("wifi: ath12k: driver for Qualcomm Wi-Fi 7 devices")
> Signed-off-by: Baochen Qiang <quic_bqiang at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

9ae8c496d211 wifi: ath12k: fix DMA unmap warning on NULL DMA address

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230830021131.5610-1-quic_bqiang at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From make_ruc2021 at 163.com  Thu Sep 21 19:10:36 2023
From: make_ruc2021 at 163.com (Ma Ke)
Date: Fri, 22 Sep 2023 10:10:36 +0800
Subject: [PATCH] ath12k: mhi: fix potential memory leak in ath12k_mhi_register()
Message-ID: <20230922021036.3604157-1-make_ruc2021@163.com>

mhi_alloc_controller() allocates a memory space for mhi_ctrl. When some
errors occur, mhi_ctrl should be freed by mhi_free_controller() and set
ab_pci->mhi_ctrl = NULL.

We can fix it by calling mhi_free_controller() when the failure happens
and set ab_pci->mhi_ctrl = NULL in all of the places where we call
mhi_free_controller().

Signed-off-by: Ma Ke <make_ruc2021 at 163.com>
---
 drivers/net/wireless/ath/ath12k/mhi.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c
index 42f1140baa4f..f83d3e09ae36 100644
--- a/drivers/net/wireless/ath/ath12k/mhi.c
+++ b/drivers/net/wireless/ath/ath12k/mhi.c
@@ -370,8 +370,7 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci)
 	ret = ath12k_mhi_get_msi(ab_pci);
 	if (ret) {
 		ath12k_err(ab, "failed to get msi for mhi\n");
-		mhi_free_controller(mhi_ctrl);
-		return ret;
+		goto free_controller;
 	}
 
 	mhi_ctrl->iova_start = 0;
@@ -388,11 +387,15 @@ int ath12k_mhi_register(struct ath12k_pci *ab_pci)
 	ret = mhi_register_controller(mhi_ctrl, ab->hw_params->mhi_config);
 	if (ret) {
 		ath12k_err(ab, "failed to register to mhi bus, err = %d\n", ret);
-		mhi_free_controller(mhi_ctrl);
-		return ret;
+		goto free_controller;
 	}
 
 	return 0;
+
+free_controller:
+	mhi_free_controller(mhi_ctrl);
+	ab_pci->mhi_ctrl = NULL;
+	return ret;
 }
 
 void ath12k_mhi_unregister(struct ath12k_pci *ab_pci)
-- 
2.37.2



From quic_wgong at quicinc.com  Mon Sep 25 19:32:48 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Tue, 26 Sep 2023 10:32:48 +0800
Subject: ath12k-check warnings
In-Reply-To: <87cyyve6ul.fsf_-_@kernel.org>
References: <20230824025432.19406-1-quic_wgong@quicinc.com>
 <169295002356.1753110.7150166655358699685.kvalo@kernel.org>
 <5376cd01-ab3e-416f-ea73-649c82e3bc40@quicinc.com>
 <87cyyve6ul.fsf_-_@kernel.org>
Message-ID: <b27fb345-b9e5-1ab0-b6df-1fad6c24a825@quicinc.com>

On 9/6/2023 10:04 PM, Kalle Valo wrote:
> (dropping linux-wireless and changing the title)
>
> Wen Gong <quic_wgong at quicinc.com> writes:
>
>> On 8/25/2023 3:53 PM, Kalle Valo wrote:
>>
>>> New warning:
>>>
>>> drivers/net/wireless/ath/ath12k/wmi.c:4199:69: warning: restricted
>>> __le32 degrades to integer
>>>
>>> Remember to ALWAYS run ath12k-check.
>>>
>>> Patch set to Changes Requested.
>> I found ath12k-check output many logs, about 5000 lines.
>>
>> And ath12k-check only has one item in CHECKPATCH_IGNORE, it does not
>> have the other items which
>>
>> existed in ath10k-check/ath11k-check, so ath12k-check output many info
>>
>> "struct? should normally be const"/"networking block comments don't use
>> an empty /* line, use /* Comment..."/.
>>
>> Also it print many "note: in included file ..." by sparse.
>>
>>
>> May I change ath12k-check with diff below and use "ath12k-check | grep
>> -v "note: in included file"" for the patch check?
>>
>> wgong at wgong-Latitude-E6430:~/opensource/kernel/ath$ ./ath12k-check --version
>> /home/wgong/opensource/kernel/ath/./ath12k-check:32: DeprecationWarning:
>> The distutils package is deprecated and slated for removal in Python
>> 3.12. Use setuptools or check PEP 632 for potential alternatives
>>   ? import distutils.spawn
>> ath12k-check (md5sum 194c6d6c4bad47f9780fe22541f2f68c)
>>
>> gcc:??????????? gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
>> sparse:???????? 0.6.4 (Ubuntu: 0.6.4-2)
>> checkpatch.pl:? Version: 0.32 (md5sum b169dcb45a7f32bd19b128e08288e9cc)
>> gtags:????????? gtags (Global) 6.6.7
> I assume this is because you are using an old version of checkpatch.pl.
> I forgot to update the commit id in ath1?k-check scripts but I fixed it
> now:
>
> https://github.com/qca/qca-swiss-army-knife/commit/27d9574ce670d759681b662e380a826ca6106e48
>
> This is the correct version of checkpatch.pl you should be using (also
> printed in --help):
>
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/scripts/checkpatch.pl?id=362173572a4018e9c8e39c616823189c41d39d41
>
> Did that fix the issue?

Sorry for delay since subject title changed.

I updated to latest commit of qca-swiss-army-knife (9a16a4a - 
ath11k-check: verify checkpatch.pl md5sum),

and it still print about ~500 "note: in included file ...", they are 
print by sparse, not by checkpatch.pl.

wgong at wgong-Latitude-E6430:~/opensource/kernel/ath$ ./ath12k-check
/home/wgong/opensource/kernel/ath/./ath12k-check:32: DeprecationWarning: 
The distutils package is deprecated and slated for removal in Python 
3.12. Use setuptools or check PEP 632 for potential alternatives
 ? import distutils.spawn
drivers/net/wireless/ath/ath12k/hal_tx.c: note: in included file 
(through include/linux/bitops.h, include/linux/kernel.h, 
include/linux/interrupt.h, drivers/net/wireless/ath/ath12k/core.h, 
drivers/net/wireless/ath/ath12k/hal_desc.h):
drivers/net/wireless/ath/ath12k/hal_tx.c: note: in included file 
(through include/linux/bitops.h, include/linux/kernel.h, 
include/linux/interrupt.h, drivers/net/wireless/ath/ath12k/core.h, 
drivers/net/wireless/ath/ath12k/hal_desc.h):
...
...
drivers/net/wireless/ath/ath12k/dp_mon.c: note: in included file 
(through include/linux/bitops.h, include/linux/kernel.h, 
include/linux/interrupt.h, drivers/net/wireless/ath/ath12k/core.h, 
drivers/net/wireless/ath/ath12k/dp_mon.h):
drivers/net/wireless/ath/ath12k/dp_mon.c: note: in included file 
(through arch/x86/include/asm/bitops.h, include/linux/bitops.h, 
include/linux/kernel.h, include/linux/interrupt.h, 
drivers/net/wireless/ath/ath12k/core.h, ...):

wgong at wgong-Latitude-E6430:~/opensource/kernel/ath$ ./ath12k-check --version
/home/wgong/opensource/kernel/ath/./ath12k-check:32: DeprecationWarning: 
The distutils package is deprecated and slated for removal in Python 
3.12. Use setuptools or check PEP 632 for potential alternatives
 ? import distutils.spawn
ath12k-check (md5sum a934e18a6f7c439e351695268471156c)

gcc:??????????? gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
sparse:???????? 0.6.4 (Ubuntu: 0.6.4-2)
checkpatch.pl:? Version: 0.32 (md5sum 47ef327d772c156e53a36597723fc781)
gtags:????????? gtags (Global) 6.6.7

wgong at wgong-Latitude-E6430:~/opensource/kernel/ath$ ./ath12k-check | 
grep -c "note: in included file"
/home/wgong/opensource/kernel/ath/./ath12k-check:32: DeprecationWarning: 
The distutils package is deprecated and slated for removal in Python 
3.12. Use setuptools or check PEP 632 for potential alternatives
 ? import distutils.spawn
441
wgong at wgong-Latitude-E6430:~/opensource/kernel/ath$ ./ath11k-check | 
grep -c "note: in included file"
/home/wgong/opensource/kernel/ath/./ath11k-check:32: DeprecationWarning: 
The distutils package is deprecated and slated for removal in Python 
3.12. Use setuptools or check PEP 632 for potential alternatives
 ? import distutils.spawn
567

>
> I also added a check to make sure that I don't forget to update the
> commit id in the future:
>
> https://github.com/qca/qca-swiss-army-knife/commit/c880314adbb1006184265f002016ec3f87bef40d
>
> Please always report any issues you have with ath12k-check. You should
> see no warnings in output, otherwise something is wrong.
>


From kvalo at kernel.org  Mon Sep 25 21:42:18 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Tue, 26 Sep 2023 07:42:18 +0300
Subject: ath12k-check warnings
In-Reply-To: <b27fb345-b9e5-1ab0-b6df-1fad6c24a825@quicinc.com> (Wen Gong's
	message of "Tue, 26 Sep 2023 10:32:48 +0800")
References: <20230824025432.19406-1-quic_wgong@quicinc.com>
	<169295002356.1753110.7150166655358699685.kvalo@kernel.org>
	<5376cd01-ab3e-416f-ea73-649c82e3bc40@quicinc.com>
	<87cyyve6ul.fsf_-_@kernel.org>
	<b27fb345-b9e5-1ab0-b6df-1fad6c24a825@quicinc.com>
Message-ID: <87o7hp8s0l.fsf@kernel.org>

Wen Gong <quic_wgong at quicinc.com> writes:

> I updated to latest commit of qca-swiss-army-knife (9a16a4a -
> ath11k-check: verify checkpatch.pl md5sum),
>
> and it still print about ~500 "note: in included file ...", they are
> print by sparse, not by checkpatch.pl.

Ah, I missed that these are coming from sparse.

> wgong at wgong-Latitude-E6430:~/opensource/kernel/ath$ ./ath12k-check --version
> /home/wgong/opensource/kernel/ath/./ath12k-check:32:
> DeprecationWarning: The distutils package is deprecated and slated for
> removal in Python 3.12. Use setuptools or check PEP 632 for potential
> alternatives
> ? import distutils.spawn
> ath12k-check (md5sum a934e18a6f7c439e351695268471156c)
>
> gcc:??????????? gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
> sparse:???????? 0.6.4 (Ubuntu: 0.6.4-2)
> checkpatch.pl:? Version: 0.32 (md5sum 47ef327d772c156e53a36597723fc781)
> gtags:????????? gtags (Global) 6.6.7

I guess your sparse is too old. I'm using:

$ ath12k-check --version
ath12k-check (md5sum a934e18a6f7c439e351695268471156c)

gcc:		gcc (Debian 12.2.0-14) 12.2.0
sparse:		v0.6.4-39-gce1a6720f69e
checkpatch.pl:	Version: 0.32 (md5sum 47ef327d772c156e53a36597723fc781)
gtags:		gtags (Global) 6.6.9

I recommend installing sparse directly from git, it's quite easy:

https://git.kernel.org/pub/scm/devel/sparse/sparse.git/

> /home/wgong/opensource/kernel/ath/./ath12k-check:32:
> DeprecationWarning: The distutils package is deprecated and slated for
> removal in Python 3.12. Use setuptools or check PEP 632 for potential
> alternatives
> ? import distutils.spawn

I don't see this warning on Debian 12 but I'll need to fix that as well.
But this is what I hate with python, they are always depracating
something and it's extra work for us.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From johannes at sipsolutions.net  Tue Sep 26 02:42:45 2023
From: johannes at sipsolutions.net (Johannes Berg)
Date: Tue, 26 Sep 2023 11:42:45 +0200
Subject: [PATCH 3/3] wifi: mac80211: update link RX NSS by
 ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link()
In-Reply-To: <7e350410-0e45-910d-68db-ea1d85df958a@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
	 <20230906103458.24092-4-quic_wgong@quicinc.com>
	 <e6ea3009c489fae910adbf2e1c766f2d827f287f.camel@sipsolutions.net>
	 <7e350410-0e45-910d-68db-ea1d85df958a@quicinc.com>
Message-ID: <d42b46d628c1d0d09d8772f19cec0b572251c02b.camel@sipsolutions.net>

On Fri, 2023-09-15 at 15:53 +0800, Wen Gong wrote:
> On 9/13/2023 5:04 PM, Johannes Berg wrote:
> > On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
> > > Currently for MLO connection, only deflink's rx_nss is set to correct
> > > value. The others links' rx_nss of struct ieee80211_link_sta is
> > > value 0 in ieee80211_set_associated(), because they are not pass into
> > > ieee80211_sta_set_rx_nss() in mac80211 except the deflink in
> > > rate_control_rate_init(). This leads driver get NSS = 0 for other links.
> > > Add the ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link(),
> > > then the other links' rx_nss will be set to the correct value.
> > This is pretty much true, but I also think it's problematic the way you
> > phrase it. Software rate control is pretty much, at least currently,
> > _not_ supported for MLO (and I don't really see how to support it, if
> > firmware picks the link to transmit on, as it probably should).
> > 
> > Thus, I'm not even sure we should be calling rate_control_rate_init().
> > Clearly we do today, but it's also obviously wrong for everything except
> > the call to ieee80211_sta_set_rx_nss().
> > 
> > So while I agree that there's a problem with the RX NSS, I disagree that
> > this patch is the right way to fix it. Yes, it also fairly obviously
> > fixes the problem, but it just makes an existing design problem worse.
> > 
> > Please change change the overall design here so that
> > ieee80211_sta_set_rx_nss() isn't related to rate control at all.
> > 
> > johannes
> So should I delete ieee80211_sta_set_rx_nss() in rate_control_rate_init(),
> and add it into ieee80211_assoc_config_link() as you said before here?
> https://lore.kernel.org/linux-wireless/ca0f6ea2d78538ffb6640f2e56d65c89c86f5221.camel at sipsolutions.net/

I think that would make sense. After all, rate_control_rate_init() is
related to the software rate control which isn't really supported with
MLD, and the NSS init is unrelated, it's just updating a piece of per
(link) station data.

> I checked the git log, ieee80211_sta_set_rx_nss() is added into
> rate_control_rate_init() here for VHT, so is it correct to delete
> ieee80211_sta_set_rx_nss() in rate_control_rate_init()?
> https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?id=8921d04e8df7475d733d853564bdb001e83bf33f
> > 

Well we'll have to call it appropriately when rate_control_rate_init()
is called today, and then the new places in your patch, I guess.

But I per the above that makes more sense semantically, since we don't
support software rate control on link stations.

johannes


From johannes at sipsolutions.net  Tue Sep 26 02:44:02 2023
From: johannes at sipsolutions.net (Johannes Berg)
Date: Tue, 26 Sep 2023 11:44:02 +0200
Subject: [PATCH 3/3] wifi: mac80211: update link RX NSS by
 ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link()
In-Reply-To: <bfdcbf9a-0b27-1f7e-3eca-7390a9a7404e@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
	 <20230906103458.24092-4-quic_wgong@quicinc.com>
	 <e6ea3009c489fae910adbf2e1c766f2d827f287f.camel@sipsolutions.net>
	 <bfdcbf9a-0b27-1f7e-3eca-7390a9a7404e@quicinc.com>
Message-ID: <18228b58173d9f33b1c3ddda9df5b3c4b49fb075.camel@sipsolutions.net>

On Fri, 2023-09-15 at 16:43 +0800, Wen Gong wrote:
> On 9/13/2023 5:04 PM, Johannes Berg wrote:
> > On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
> > > Currently for MLO connection, only deflink's rx_nss is set to correct
> > > value. The others links' rx_nss of struct ieee80211_link_sta is
> > > value 0 in ieee80211_set_associated(), because they are not pass into
> > > ieee80211_sta_set_rx_nss() in mac80211 except the deflink in
> > > rate_control_rate_init(). This leads driver get NSS = 0 for other links.
> > > Add the ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link(),
> > > then the other links' rx_nss will be set to the correct value.
> > This is pretty much true, but I also think it's problematic the way you
> > phrase it. Software rate control is pretty much, at least currently,
> > _not_ supported for MLO (and I don't really see how to support it, if
> > firmware picks the link to transmit on, as it probably should).
> I searched all the folder wireless, I only found 5 places have the 
> handler of rate_init below,
> and the functions are all empty. Is it means no driver support rate_init 
> currently?
> drivers/net/wireless/realtek/rtlwifi/rc.c:304:???? .rate_init = 
> rtl_rate_init,
> drivers/net/wireless/intel/iwlwifi/mvm/rs.c:4098:? .rate_init = 
> rs_rate_init_ops,
> drivers/net/wireless/intel/iwlwifi/dvm/rs.c:3276:? .rate_init = 
> rs_rate_init_stub,
> drivers/net/wireless/intel/iwlegacy/4965-rs.c:2779: .rate_init = 
> il4965_rs_rate_init_stub,
> drivers/net/wireless/intel/iwlegacy/3945-rs.c:867: .rate_init = 
> il3945_rs_rate_init_stub,
> [...]
> 

Well, many other drivers use minstrel, and the _stub ones in intel are
atually not doing anything.

So most drivers would use 

net/mac80211/rc80211_minstrel_ht.c:     .rate_init =
minstrel_ht_rate_init,

here.

johannes



From johannes at sipsolutions.net  Tue Sep 26 02:45:36 2023
From: johannes at sipsolutions.net (Johannes Berg)
Date: Tue, 26 Sep 2023 11:45:36 +0200
Subject: [PATCH 1/3] wifi: mac80211: add support to allow driver to
 generate local link address for station
In-Reply-To: <d23b617e-5ca0-e721-0c2a-fcca8942efef@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
	 <20230906103458.24092-2-quic_wgong@quicinc.com>
	 <cd762f33b1c15566237c85f1e265ee8a00006f5c.camel@sipsolutions.net>
	 <d23b617e-5ca0-e721-0c2a-fcca8942efef@quicinc.com>
Message-ID: <4dac29f3844309fb62afe6acd4c4ebd379b0a194.camel@sipsolutions.net>

On Fri, 2023-09-15 at 16:11 +0800, Wen Gong wrote:
> On 9/13/2023 4:55 PM, Johannes Berg wrote:
> > On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
> [...]
> > Maybe after all this explanation, all we need is a flag "reuse MLD
> > address for assoc link"?
> 
> yes. It is similar as I said before here:
> 
> https://lore.kernel.org/linux-wireless/b9c6d022-12c3-a696-c4b9-cb14a6d30a45 at quicinc.com/
> 
> > 
> > 
> > > +		ret = drv_generate_link_addr(sdata->local, sdata,
> > > +					     link_id, link->conf->addr);
> > > +		if (ret)
> > > +			eth_random_addr(link->conf->addr);
> > should probably refactor this into a separate function though.
> OK.
> > 
> > I'm also not sure how the driver even knows that a link it's being asked
> > to get the address for *is* the assoc link? Do you want to rely on that
> > being the first address handed out?
> Current I used (vif->valid_links==0) check for assoc link. When
> drv_generate_link_addr() called for the assoc link, vif->valid_links
> is 0, and it is not 0 for other links.

That seems a bit questionable?

Well then again, what do you want for AP mode? Anyway you can still
distinguish, and if we later need to change an internal API that's not
the end of the world either ...

So OK, I guess we can live with this, just would like to see it wrapped
up into a single function.

johannes


From johannes at sipsolutions.net  Tue Sep 26 03:00:20 2023
From: johannes at sipsolutions.net (Johannes Berg)
Date: Tue, 26 Sep 2023 12:00:20 +0200
Subject: [PATCH 2/3] wifi: mac80211: add support to allow driver to set
 active link while connection for station
In-Reply-To: <96ae3c1d-274b-00b1-cb19-a9a301b6aa56@quicinc.com>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
	 <20230906103458.24092-3-quic_wgong@quicinc.com>
	 <4b597bba9dc13c3260f174826de38b4f1bc3bf6e.camel@sipsolutions.net>
	 <96ae3c1d-274b-00b1-cb19-a9a301b6aa56@quicinc.com>
Message-ID: <6892f4026a275756eecf36f46711442882aac7fd.camel@sipsolutions.net>


> For ieee80211_set_active_links(), driver need save and install pairwise
> keys for the other links as you said in link below. But driver do not
> save the key data currently. So driver could not install the pairwise
> keys by itself.
> https://lore.kernel.org/linux-wireless/50719d34bc48d816d00b56d3d9efdb59e3e51a16.camel at sipsolutions.net/

Well it can still easily iterate the keys, but OK, I can buy this
argument. You should probably mention it all in the commit log though.

> > > @@ -166,6 +167,13 @@ static void ieee80211_set_vif_links_bitmaps(struct ieee80211_sub_if_data *sdata,
> > >   		WARN_ON(dormant_links);
> > >   		break;
> > >   	case NL80211_IFTYPE_STATION:
> > > +		active_links = drv_calculate_active_links(sdata->local, sdata,
> > > +							  valid_links & ~dormant_links);
> > > +		if (active_links) {
> > > +			sdata->vif.active_links = active_links;
> > > +			break;
> > > +		}
> > > 
> > I also _really_ don't think this should operate at this low-level
> > infrastructure.
> 
> I really want to know the reason why active *only* the assoc link for 
> station, but
> 
> active *all* links for AP here??

Well, fair point.

I was somehow anyway thinking that it should be the other way around, I
mean, in the sense that this code here is just mechanism, and the policy
should've been in higher-level code ... but somehow that's not what we
ended up doign here.


It really feels wrong to me to have the driver involved in this low-
level infrastructure, but OTOH that really is how it works now?


Maybe really what you want is a driver flag saying
IEEE80211_HW_MANAGES_ACTIVE_LINKS or something, and then from a mac80211
perspective you don't set active links at all? Though I'm not sure that
works with TTLM, for instance? And maybe you'd still want the debugfs?

But in fact, if you do still want something from mac80211 for debugfs or
TTLM, then this code here is not really right, since you'd interact with
_all_ attempts in mac80211 to activate or deactivate links - when all
you really wanted was the very first one.

Which today mac80211 achieves by bailing out
"if (sdata->vif.active_links)", and while you could do the same in the
driver, it feels really brittle / error-prone to me.


I think it'd be better than all these callbacks to encode the specific
behaviour you need in a flag, e.g. "activate all STA links on assoc" or
something?

johannes


From quic_wgong at quicinc.com  Tue Sep 26 03:44:02 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Tue, 26 Sep 2023 18:44:02 +0800
Subject: [PATCH 1/3] wifi: mac80211: add support to allow driver to
 generate local link address for station
In-Reply-To: <4dac29f3844309fb62afe6acd4c4ebd379b0a194.camel@sipsolutions.net>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
 <20230906103458.24092-2-quic_wgong@quicinc.com>
 <cd762f33b1c15566237c85f1e265ee8a00006f5c.camel@sipsolutions.net>
 <d23b617e-5ca0-e721-0c2a-fcca8942efef@quicinc.com>
 <4dac29f3844309fb62afe6acd4c4ebd379b0a194.camel@sipsolutions.net>
Message-ID: <7ac4b560-26d5-2125-b1be-2f1313097d0a@quicinc.com>

On 9/26/2023 5:45 PM, Johannes Berg wrote:
> On Fri, 2023-09-15 at 16:11 +0800, Wen Gong wrote:
>> On 9/13/2023 4:55 PM, Johannes Berg wrote:
>>> On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
>> [...]
>>> Maybe after all this explanation, all we need is a flag "reuse MLD
>>> address for assoc link"?
>> yes. It is similar as I said before here:
>>
>> https://lore.kernel.org/linux-wireless/b9c6d022-12c3-a696-c4b9-cb14a6d30a45 at quicinc.com/
>>
>>>
>>>> +		ret = drv_generate_link_addr(sdata->local, sdata,
>>>> +					     link_id, link->conf->addr);
>>>> +		if (ret)
>>>> +			eth_random_addr(link->conf->addr);
>>> should probably refactor this into a separate function though.
>> OK.
>>> I'm also not sure how the driver even knows that a link it's being asked
>>> to get the address for *is* the assoc link? Do you want to rely on that
>>> being the first address handed out?
>> Current I used (vif->valid_links==0) check for assoc link. When
>> drv_generate_link_addr() called for the assoc link, vif->valid_links
>> is 0, and it is not 0 for other links.
> That seems a bit questionable?

Also we can change to indicate a new flag(e.g. 
IEEE80211_HW_MLO_FIXED_ASSOC_LINK_ADDR) to

mac80211 from driver, if the flag is not set, then keep current logic.

If it is set, then copy vif->addr to the link->conf->addr for assoc link 
in ieee80211_mgd_setup_link().

The logic keep not change for other links.

> Well then again, what do you want for AP mode? Anyway you can still
> distinguish, and if we later need to change an internal API that's not
> the end of the world either ...
I do not want any change for AP mode.
>
> So OK, I guess we can live with this, just would like to see it wrapped
> up into a single function.
>
> johannes


From quic_wgong at quicinc.com  Tue Sep 26 03:46:17 2023
From: quic_wgong at quicinc.com (Wen Gong)
Date: Tue, 26 Sep 2023 18:46:17 +0800
Subject: [PATCH 3/3] wifi: mac80211: update link RX NSS by
 ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link()
In-Reply-To: <d42b46d628c1d0d09d8772f19cec0b572251c02b.camel@sipsolutions.net>
References: <20230906103458.24092-1-quic_wgong@quicinc.com>
 <20230906103458.24092-4-quic_wgong@quicinc.com>
 <e6ea3009c489fae910adbf2e1c766f2d827f287f.camel@sipsolutions.net>
 <7e350410-0e45-910d-68db-ea1d85df958a@quicinc.com>
 <d42b46d628c1d0d09d8772f19cec0b572251c02b.camel@sipsolutions.net>
Message-ID: <3a9cf522-85d3-fa42-378c-56467fb50636@quicinc.com>

On 9/26/2023 5:42 PM, Johannes Berg wrote:
> On Fri, 2023-09-15 at 15:53 +0800, Wen Gong wrote:
>> On 9/13/2023 5:04 PM, Johannes Berg wrote:
>>> On Wed, 2023-09-06 at 06:34 -0400, Wen Gong wrote:
>>>> Currently for MLO connection, only deflink's rx_nss is set to correct
>>>> value. The others links' rx_nss of struct ieee80211_link_sta is
>>>> value 0 in ieee80211_set_associated(), because they are not pass into
>>>> ieee80211_sta_set_rx_nss() in mac80211 except the deflink in
>>>> rate_control_rate_init(). This leads driver get NSS = 0 for other links.
>>>> Add the ieee80211_sta_set_rx_nss() in ieee80211_assoc_config_link(),
>>>> then the other links' rx_nss will be set to the correct value.
>>> This is pretty much true, but I also think it's problematic the way you
>>> phrase it. Software rate control is pretty much, at least currently,
>>> _not_ supported for MLO (and I don't really see how to support it, if
>>> firmware picks the link to transmit on, as it probably should).
>>>
>>> Thus, I'm not even sure we should be calling rate_control_rate_init().
>>> Clearly we do today, but it's also obviously wrong for everything except
>>> the call to ieee80211_sta_set_rx_nss().
>>>
>>> So while I agree that there's a problem with the RX NSS, I disagree that
>>> this patch is the right way to fix it. Yes, it also fairly obviously
>>> fixes the problem, but it just makes an existing design problem worse.
>>>
>>> Please change change the overall design here so that
>>> ieee80211_sta_set_rx_nss() isn't related to rate control at all.
>>>
>>> johannes
>> So should I delete ieee80211_sta_set_rx_nss() in rate_control_rate_init(),
>> and add it into ieee80211_assoc_config_link() as you said before here?
>> https://lore.kernel.org/linux-wireless/ca0f6ea2d78538ffb6640f2e56d65c89c86f5221.camel at sipsolutions.net/
> I think that would make sense. After all, rate_control_rate_init() is
> related to the software rate control which isn't really supported with
> MLD, and the NSS init is unrelated, it's just updating a piece of per
> (link) station data.
>
>> I checked the git log, ieee80211_sta_set_rx_nss() is added into
>> rate_control_rate_init() here for VHT, so is it correct to delete
>> ieee80211_sta_set_rx_nss() in rate_control_rate_init()?
>> https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?id=8921d04e8df7475d733d853564bdb001e83bf33f
> Well we'll have to call it appropriately when rate_control_rate_init()
> is called today, and then the new places in your patch, I guess.
>
> But I per the above that makes more sense semantically, since we don't
> support software rate control on link stations.
>
> johannes

OK. So I will send new version patch to remove the

ieee80211_sta_set_rx_nss() in rate_control_rate_init() as you said.



From kvalo at kernel.org  Wed Sep 27 00:09:21 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Wed, 27 Sep 2023 10:09:21 +0300
Subject: ath12k-check warnings
In-Reply-To: <87o7hp8s0l.fsf@kernel.org> (Kalle Valo's message of "Tue, 26 Sep
	2023 07:42:18 +0300")
References: <20230824025432.19406-1-quic_wgong@quicinc.com>
	<169295002356.1753110.7150166655358699685.kvalo@kernel.org>
	<5376cd01-ab3e-416f-ea73-649c82e3bc40@quicinc.com>
	<87cyyve6ul.fsf_-_@kernel.org>
	<b27fb345-b9e5-1ab0-b6df-1fad6c24a825@quicinc.com>
	<87o7hp8s0l.fsf@kernel.org>
Message-ID: <87bkdo853y.fsf@kernel.org>

Kalle Valo <kvalo at kernel.org> writes:

>> /home/wgong/opensource/kernel/ath/./ath12k-check:32:
>> DeprecationWarning: The distutils package is deprecated and slated for
>> removal in Python 3.12. Use setuptools or check PEP 632 for potential
>> alternatives
>> ? import distutils.spawn
>
> I don't see this warning on Debian 12 but I'll need to fix that as well.
> But this is what I hate with python, they are always depracating
> something and it's extra work for us.

I fixed this now:

https://github.com/qca/qca-swiss-army-knife/commit/2bd53768fa273f78ed044aee9ac88daf2ccc1682

Please let me know if you still see warnings from ath12k-check or
ath11k-check. With ath.git master branch you should get no warnings,
otherwise something is wrong.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From quic_kangyang at quicinc.com  Wed Sep 27 22:50:20 2023
From: quic_kangyang at quicinc.com (Kang Yang)
Date: Thu, 28 Sep 2023 13:50:20 +0800
Subject: [PATCH 2/4] wifi: mac80211: mlme: correct the verification of extracted bitmap
In-Reply-To: <20230928055022.9670-1-quic_kangyang@quicinc.com>
References: <20230928055022.9670-1-quic_kangyang@quicinc.com>
Message-ID: <20230928055022.9670-3-quic_kangyang@quicinc.com>

Mac80211 will extract puncturing bitmap according to the negotiated
bandwidth. After extraction, should check the new puncturing bitmap
according to the negotiated bandwidth, but here input the original bitmap.

When bandwidth downgrade occurs, this function may return an error even
though negotiated bandwidth and puncturing bitmap match correctly.

So correct it.

Fixes: aa87cd8b3573 ("wifi: mac80211: mlme: handle EHT channel puncturing")
Signed-off-by: Kang Yang <quic_kangyang at quicinc.com>
---
 net/mac80211/mlme.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 16e15ced28a5..13fba1f1cd89 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -145,7 +145,7 @@ ieee80211_handle_puncturing_bitmap(struct ieee80211_link_data *link,
 			ieee80211_extract_dis_subch_bmap(eht_oper, chandef,
 							 bitmap);
 
-		if (cfg80211_valid_disable_subchannel_bitmap(&bitmap,
+		if (cfg80211_valid_disable_subchannel_bitmap(&extracted,
 							     chandef))
 			break;
 		link->u.mgd.conn_flags |=
-- 
2.34.1



From quic_kangyang at quicinc.com  Wed Sep 27 22:50:18 2023
From: quic_kangyang at quicinc.com (Kang Yang)
Date: Thu, 28 Sep 2023 13:50:18 +0800
Subject: [PATCH 0/4] dynamically update puncturing bitmap
Message-ID: <20230928055022.9670-1-quic_kangyang@quicinc.com>

After connection, puncturing bitmap maybe change. AP will include the
related changes in beacon.

So update the related changes dynamically.

Kang Yang (4):
  wifi: mac80211: mlme: fix verification of puncturing bitmap obtained
    from AP
  wifi: mac80211: mlme: correct the verification of extracted bitmap
  wifi: mac80211: mlme: enable tracking bandwidth changes for 6 GHz band
  wifi: ath12k: dynamically update puncturing bitmap

 drivers/net/wireless/ath/ath12k/mac.c | 50 +++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h | 17 +++++++
 net/mac80211/mlme.c                   | 72 ++++++++++++++++++++-------
 3 files changed, 121 insertions(+), 18 deletions(-)


base-commit: 73e13f6a439b75a9dbc84bbfa0b0d6624b354853
-- 
2.34.1



From quic_kangyang at quicinc.com  Wed Sep 27 22:50:19 2023
From: quic_kangyang at quicinc.com (Kang Yang)
Date: Thu, 28 Sep 2023 13:50:19 +0800
Subject: [PATCH 1/4] wifi: mac80211: mlme: fix verification of puncturing bitmap obtained from AP
In-Reply-To: <20230928055022.9670-1-quic_kangyang@quicinc.com>
References: <20230928055022.9670-1-quic_kangyang@quicinc.com>
Message-ID: <20230928055022.9670-2-quic_kangyang@quicinc.com>

Puncturing bitmap and bandwidth is included in beacon's EHT Operation
element. After receiving beacon, mac80211 will verify if they are match.
But the bandwidth used for verification is incorrect. Because bandwidth
in link->conf->chandef is a negotiated bandwidth, it may be downgraded.
Should use bandwidth included in beacon. Otherwise when bandwidth
downgrade occurs, even if the received values match, an error may be
returned.

Also, checking if bitmap and bandwidth match should be done before
extraction. But here extract first and then check.

So fix these two issues.

Fixes: aa87cd8b3573 ("wifi: mac80211: mlme: handle EHT channel puncturing")
Signed-off-by: Kang Yang <quic_kangyang at quicinc.com>
---
 net/mac80211/mlme.c | 54 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 44 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index f93eb38ae0b8..16e15ced28a5 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -5670,11 +5670,33 @@ static bool ieee80211_rx_our_beacon(const u8 *tx_bssid,
 	return ether_addr_equal(tx_bssid, bss->transmitted_bss->bssid);
 }
 
+static enum nl80211_chan_width
+ieee80211_rx_bw_to_nlwidth(enum ieee80211_sta_rx_bandwidth bw)
+{
+	switch (bw) {
+	case IEEE80211_STA_RX_BW_20:
+		return NL80211_CHAN_WIDTH_20;
+	case IEEE80211_STA_RX_BW_40:
+		return NL80211_CHAN_WIDTH_40;
+	case IEEE80211_STA_RX_BW_80:
+		return NL80211_CHAN_WIDTH_80;
+	case IEEE80211_STA_RX_BW_160:
+		return NL80211_CHAN_WIDTH_160;
+	case IEEE80211_STA_RX_BW_320:
+		return NL80211_CHAN_WIDTH_320;
+	default:
+		WARN_ON(1);
+		return NL80211_CHAN_WIDTH_20;
+	}
+}
+
 static bool ieee80211_config_puncturing(struct ieee80211_link_data *link,
 					const struct ieee80211_eht_operation *eht_oper,
 					u64 *changed)
 {
+	struct cfg80211_chan_def rx_chandef = link->conf->chandef;
 	u16 bitmap = 0, extracted;
+	u8 bw = 0;
 
 	if ((eht_oper->params & IEEE80211_EHT_OPER_INFO_PRESENT) &&
 	    (eht_oper->params &
@@ -5684,6 +5706,28 @@ static bool ieee80211_config_puncturing(struct ieee80211_link_data *link,
 		const u8 *disable_subchannel_bitmap = info->optional;
 
 		bitmap = get_unaligned_le16(disable_subchannel_bitmap);
+		bw = u8_get_bits(info->control, IEEE80211_EHT_OPER_CHAN_WIDTH);
+		rx_chandef.width = ieee80211_rx_bw_to_nlwidth(bw);
+
+		if (rx_chandef.width == NL80211_CHAN_WIDTH_80)
+			rx_chandef.center_freq1 =
+				ieee80211_channel_to_frequency(info->ccfs0,
+							       rx_chandef.chan->band);
+		else if (rx_chandef.width == NL80211_CHAN_WIDTH_160 ||
+			 rx_chandef.width == NL80211_CHAN_WIDTH_320)
+			rx_chandef.center_freq1 =
+				ieee80211_channel_to_frequency(info->ccfs1,
+							       rx_chandef.chan->band);
+	}
+
+	if (!cfg80211_valid_disable_subchannel_bitmap(&bitmap,
+						      &rx_chandef)) {
+		link_info(link,
+			  "Got an invalid disable subchannel bitmap from AP %pM: bitmap = 0x%x, bw = 0x%x. disconnect\n",
+			  link->u.mgd.bssid,
+			  bitmap,
+			  rx_chandef.width);
+		return false;
 	}
 
 	extracted = ieee80211_extract_dis_subch_bmap(eht_oper,
@@ -5695,16 +5739,6 @@ static bool ieee80211_config_puncturing(struct ieee80211_link_data *link,
 	    extracted == link->conf->eht_puncturing)
 		return true;
 
-	if (!cfg80211_valid_disable_subchannel_bitmap(&bitmap,
-						      &link->conf->chandef)) {
-		link_info(link,
-			  "Got an invalid disable subchannel bitmap from AP %pM: bitmap = 0x%x, bw = 0x%x. disconnect\n",
-			  link->u.mgd.bssid,
-			  bitmap,
-			  link->conf->chandef.width);
-		return false;
-	}
-
 	ieee80211_handle_puncturing_bitmap(link, eht_oper, bitmap, changed);
 	return true;
 }
-- 
2.34.1



From quic_kangyang at quicinc.com  Wed Sep 27 22:50:21 2023
From: quic_kangyang at quicinc.com (Kang Yang)
Date: Thu, 28 Sep 2023 13:50:21 +0800
Subject: [PATCH 3/4] wifi: mac80211: mlme: enable tracking bandwidth changes for 6 GHz band
In-Reply-To: <20230928055022.9670-1-quic_kangyang@quicinc.com>
References: <20230928055022.9670-1-quic_kangyang@quicinc.com>
Message-ID: <20230928055022.9670-4-quic_kangyang@quicinc.com>

After connection, mac80211 will track bandwidth changes upon
beacon's CRC is changed. But it will stop tracking bandwidth
changes when these is no HT Operation element.

According to the section 9.4.2.311 in IEEE P802.11be draft 4.0:
The operation of EHT STAs in an EHT BSS is controlled by the following:
        -'The HT Operation element, HE Operation element, and EHT
          Operation element if operating in the 2.4 GHz band'
        -'The HT Operation element, VHT Operation element (if present),
          HE Operation element, and EHT Operation element if operating
          in the 5 GHz band'
        -'The HE Operation element and EHT Operation element if
          operating in the 6 GHz band'

For 6 GHz band, beacon doesn't contain HT Operation element. Therefore,
current checking code needs to be changed.

Signed-off-by: Kang Yang <quic_kangyang at quicinc.com>
---
 net/mac80211/mlme.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 13fba1f1cd89..f55d677f9ace 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -501,9 +501,9 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,
 	u32 vht_cap_info = 0;
 	int ret;
 
-	/* if HT was/is disabled, don't track any bandwidth changes */
-	if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT || !ht_oper)
-		return 0;
+	/* don't check HT if we associated as non-HT station */
+	if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_HT)
+		ht_oper = NULL;
 
 	/* don't check VHT if we associated as non-VHT station */
 	if (link->u.mgd.conn_flags & IEEE80211_CONN_DISABLE_VHT)
@@ -525,10 +525,12 @@ static int ieee80211_config_bw(struct ieee80211_link_data *link,
 	 * if bss configuration changed store the new one -
 	 * this may be applicable even if channel is identical
 	 */
-	ht_opmode = le16_to_cpu(ht_oper->operation_mode);
-	if (link->conf->ht_operation_mode != ht_opmode) {
-		*changed |= BSS_CHANGED_HT;
-		link->conf->ht_operation_mode = ht_opmode;
+	if (ht_oper) {
+		ht_opmode = le16_to_cpu(ht_oper->operation_mode);
+		if (link->conf->ht_operation_mode != ht_opmode) {
+			*changed |= BSS_CHANGED_HT;
+			link->conf->ht_operation_mode = ht_opmode;
+		}
 	}
 
 	if (vht_cap)
-- 
2.34.1



From quic_kangyang at quicinc.com  Wed Sep 27 22:50:22 2023
From: quic_kangyang at quicinc.com (Kang Yang)
Date: Thu, 28 Sep 2023 13:50:22 +0800
Subject: [PATCH 4/4] wifi: ath12k: dynamically update puncturing bitmap
In-Reply-To: <20230928055022.9670-1-quic_kangyang@quicinc.com>
References: <20230928055022.9670-1-quic_kangyang@quicinc.com>
Message-ID: <20230928055022.9670-5-quic_kangyang@quicinc.com>

Every time EHT Operation element changed, mac80211 will parse it and
extract the valid puncturing bitmap according to the negotiated bandwidth.

So add updates of bandwidth and puncturing bitmap in ath12k. Then
process and send them to the firmware by WMI event.

Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4

Signed-off-by: Kang Yang <quic_kangyang at quicinc.com>
---
 drivers/net/wireless/ath/ath12k/mac.c | 50 +++++++++++++++++++++++++++
 drivers/net/wireless/ath/ath12k/wmi.h | 17 +++++++++
 2 files changed, 67 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c
index 85602d64b607..24968ef02978 100644
--- a/drivers/net/wireless/ath/ath12k/mac.c
+++ b/drivers/net/wireless/ath/ath12k/mac.c
@@ -2486,6 +2486,32 @@ static int ath12k_mac_fils_discovery(struct ath12k_vif *arvif,
 	return ret;
 }
 
+static enum wmi_channel_width
+ath12k_mac_nlwidth_to_wmiwidth(enum nl80211_chan_width width)
+{
+	switch (width) {
+	case NL80211_CHAN_WIDTH_20:
+		return WMI_CHAN_WIDTH_20;
+	case NL80211_CHAN_WIDTH_40:
+		return WMI_CHAN_WIDTH_40;
+	case NL80211_CHAN_WIDTH_80:
+		return WMI_CHAN_WIDTH_80;
+	case NL80211_CHAN_WIDTH_160:
+		return WMI_CHAN_WIDTH_160;
+	case NL80211_CHAN_WIDTH_80P80:
+		return WMI_CHAN_WIDTH_80P80;
+	case NL80211_CHAN_WIDTH_5:
+		return WMI_CHAN_WIDTH_5;
+	case NL80211_CHAN_WIDTH_10:
+		return WMI_CHAN_WIDTH_10;
+	case NL80211_CHAN_WIDTH_320:
+		return WMI_CHAN_WIDTH_320;
+	default:
+		WARN_ON(1);
+		return WMI_CHAN_WIDTH_20;
+	}
+}
+
 static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 					   struct ieee80211_vif *vif,
 					   struct ieee80211_bss_conf *info,
@@ -2507,6 +2533,27 @@ static void ath12k_mac_op_bss_info_changed(struct ieee80211_hw *hw,
 
 	mutex_lock(&ar->conf_mutex);
 
+	if (changed & BSS_CHANGED_EHT_PUNCTURING) {
+		param_id = WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP;
+		param_value = ath12k_mac_nlwidth_to_wmiwidth(info->chandef.width) |
+			      u32_encode_bits((~info->eht_puncturing),
+					      WMI_PEER_PUNCTURE_BITMAP);
+
+		ret = ath12k_wmi_set_peer_param(ar, arvif->bssid,
+						arvif->vdev_id, param_id,
+						param_value);
+		if (ret)
+			ath12k_warn(ar->ab,
+				    "Failed to set puncturing bitmap %04x "
+				    "and bandwidth %d for VDEV: %d\n",
+				    info->eht_puncturing, info->chandef.width,
+				    arvif->vdev_id);
+		else
+			ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
+				   "Set puncturing bitmap %04x and and bandwidth %d for VDEV: %d\n",
+				   info->eht_puncturing, info->chandef.width, arvif->vdev_id);
+	}
+
 	if (changed & BSS_CHANGED_BEACON_INT) {
 		arvif->beacon_interval = info->beacon_int;
 
@@ -3725,6 +3772,9 @@ static u32 ath12k_mac_ieee80211_sta_bw_to_wmi(struct ath12k *ar,
 	case IEEE80211_STA_RX_BW_160:
 		bw = WMI_PEER_CHWIDTH_160MHZ;
 		break;
+	case IEEE80211_STA_RX_BW_320:
+		bw = WMI_PEER_CHWIDTH_320MHZ;
+		break;
 	default:
 		ath12k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n",
 			    sta->deflink.bandwidth, sta->addr);
diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
index c75a6fa1f7e0..55ef3443fcc5 100644
--- a/drivers/net/wireless/ath/ath12k/wmi.h
+++ b/drivers/net/wireless/ath/ath12k/wmi.h
@@ -2194,8 +2194,11 @@ enum wmi_peer_param {
 	WMI_PEER_SET_MAX_TX_RATE = 17,
 	WMI_PEER_SET_MIN_TX_RATE = 18,
 	WMI_PEER_SET_DEFAULT_ROUTING = 19,
+	WMI_PEER_CHWIDTH_PUNCTURE_20MHZ_BITMAP = 39,
 };
 
+#define WMI_PEER_PUNCTURE_BITMAP		GENMASK(23, 8)
+
 enum wmi_slot_time {
 	WMI_VDEV_SLOT_TIME_LONG = 1,
 	WMI_VDEV_SLOT_TIME_SHORT = 2,
@@ -2217,6 +2220,7 @@ enum wmi_peer_chwidth {
 	WMI_PEER_CHWIDTH_40MHZ = 1,
 	WMI_PEER_CHWIDTH_80MHZ = 2,
 	WMI_PEER_CHWIDTH_160MHZ = 3,
+	WMI_PEER_CHWIDTH_320MHZ = 4,
 };
 
 enum wmi_beacon_gen_mode {
@@ -2265,6 +2269,19 @@ struct ath12k_wmi_hal_reg_capabilities_ext_arg {
 	u32 high_5ghz_chan;
 };
 
+enum wmi_channel_width {
+	WMI_CHAN_WIDTH_20 = 0,
+	WMI_CHAN_WIDTH_40 = 1,
+	WMI_CHAN_WIDTH_80 = 2,
+	WMI_CHAN_WIDTH_160 = 3,
+	WMI_CHAN_WIDTH_80P80 = 4,
+	WMI_CHAN_WIDTH_5 = 5,
+	WMI_CHAN_WIDTH_10 = 6,
+	WMI_CHAN_WIDTH_165 = 7,
+	WMI_CHAN_WIDTH_160P160 = 8,
+	WMI_CHAN_WIDTH_320 = 9,
+};
+
 #define WMI_HOST_MAX_PDEV 3
 
 struct ath12k_wmi_host_mem_chunk_params {
-- 
2.34.1



From quic_jjohnson at quicinc.com  Thu Sep 28 07:33:03 2023
From: quic_jjohnson at quicinc.com (Jeff Johnson)
Date: Thu, 28 Sep 2023 07:33:03 -0700
Subject: [PATCH 3/4] wifi: mac80211: mlme: enable tracking bandwidth
 changes for 6 GHz band
In-Reply-To: <20230928055022.9670-4-quic_kangyang@quicinc.com>
References: <20230928055022.9670-1-quic_kangyang@quicinc.com>
 <20230928055022.9670-4-quic_kangyang@quicinc.com>
Message-ID: <887e4058-ef0e-4664-9bb5-3b73dc546f75@quicinc.com>

On 9/27/2023 10:50 PM, Kang Yang wrote:
> After connection, mac80211 will track bandwidth changes upon
> beacon's CRC is changed. But it will stop tracking bandwidth
> changes when these is no HT Operation element.

nit: s/these/there/



From kvalo at kernel.org  Thu Sep 28 07:59:51 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 14:59:51 +0000 (UTC)
Subject: [PATCH v2] wifi: ath12k: add support for hardware rfkill for
 WCN7850
In-Reply-To: <20230906110412.182176-1-quic_lingbok@quicinc.com>
References: <20230906110412.182176-1-quic_lingbok@quicinc.com>
Message-ID: <169591318971.3019228.13253796564349878064.kvalo@kernel.org>

Lingbo Kong <quic_lingbok at quicinc.com> wrote:

> When hardware rfkill is enabled in the firmware, it will report the
> capability using WMI_SYS_CAP_INFO_RFKILL bit in the WMI_SERVICE_READY event
> to the host. Currently ath12k does not process this service capability. In
> order to support this, update ath12k to check if the capability is enabled,
> if so, send the GPIO information to firmware. When the firmware detects
> hardware rfkill is enabled by the user, it will report it using
> WMI_RFKILL_STATE_CHANGE_EVENTID. When ath12k receive the event, it will set
> the value of rfkill_radio_on based on whether radio_state is equal to
> WMI_RFKILL_RADIO_STATE_ON, then send WMI_PDEV_PARAM_RFKILL_ENABLE to
> firmware.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

004ccbc0dd49 wifi: ath12k: add support for hardware rfkill for WCN7850

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230906110412.182176-1-quic_lingbok at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 28 08:01:19 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 15:01:19 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: fix recovery fail while firmware crash when
 doing channel switch
In-Reply-To: <20230905105229.10090-1-quic_wgong@quicinc.com>
References: <20230905105229.10090-1-quic_wgong@quicinc.com>
Message-ID: <169591327779.3019228.18229314827081753794.kvalo@kernel.org>

Wen Gong <quic_wgong at quicinc.com> wrote:

> When firmware crashed while channel switch running, recovery starts in
> ath12k. Then ieee80211_sta_connection_lost() will be called by function
> ieee80211_restart_work() in mac80211. And then many WMI command timeout
> because firmware is crashed. Each WMI command cost 3 seconds, then the
> total time will be large and leads recovery fail.
> 
> Hence change to set value ATH12K_FLAG_CRASH_FLUSH early and then
> ath12k_wmi_cmd_send() will not wait 3 seconds, then recovery will be
> started quickly and success.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

ecbb987b0a96 wifi: ath12k: fix recovery fail while firmware crash when doing channel switch

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230905105229.10090-1-quic_wgong at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 28 08:02:46 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 15:02:46 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: indicate to mac80211 scan complete with
 aborted
 flag for ATH12K_SCAN_STARTING state
In-Reply-To: <20230905105947.10369-1-quic_wgong@quicinc.com>
References: <20230905105947.10369-1-quic_wgong@quicinc.com>
Message-ID: <169591336483.3019228.4801533515401885948.kvalo@kernel.org>

Wen Gong <quic_wgong at quicinc.com> wrote:

> Scan failure can not be recovered from when running a loop of the
> following steps:
> 1. run scan: "iw wlan scan".
> 2. run command: echo assert > /sys/kernel/debug/ath12k/wcn7850\ hw2.0/simulate_fw_crash
>    immediately after step 1.
> 
> result:
> scan failed and can not recover even when wlan recovery succeeds:
> command failed: Device or resource busy (-16)
> 
> reason:
> When scan arrives, WMI_START_SCAN_CMDID is sent to the firmware and
> function ath12k_mac_op_hw_scan() returns, then simulate_fw_crash arrives
> and the scan started event does not arrive, and then it starts to do
> recovery of wlan. __ath12k_mac_scan_finish() which is called from
> ath12k_core_halt() is one step of recovery, it will not call
> ieee80211_scan_completed() by logic currently because the scan state is
> ATH12K_SCAN_STARTING. Thus it leads the scan not being completed in
> mac80211, and leads all consecutive scans failing with -EBUSY in
> nl80211_trigger_scan even after wlan recovery success.
> 
> Indicate scan complete with aborted flag to mac80211 for
> ATH12K_SCAN_STARTING to allow recovery from scan failed with "Device or
> resource busy (-16)" after wlan recovery.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

c2ebb1d11ab9 wifi: ath12k: indicate to mac80211 scan complete with aborted flag for ATH12K_SCAN_STARTING state

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230905105947.10369-1-quic_wgong at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 28 08:05:04 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 15:05:04 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: indicate scan complete for scan canceled
 when
 scan running
In-Reply-To: <20230906085746.18968-1-quic_wgong@quicinc.com>
References: <20230906085746.18968-1-quic_wgong@quicinc.com>
Message-ID: <169591350295.3019228.15462824983218170799.kvalo@kernel.org>

Wen Gong <quic_wgong at quicinc.com> wrote:

> ath12k prints "Received scan event for unknown vdev" when doing the
> following test:
> 1. trigger scan
> 2. wait 0.2 second
> 3. iw reg set is issued or 11d scan complete event is sent from firmware
> 
> Reason is:
> When iw reg set is issues or the 11d scan complete event is received, the
> new country code will be set to the firmware, and the new regdomain info
> indicated to ath12k, then the new channel list will be sent to the firmware.
> The firmware will cancel the current scan after receiving WMI_SCAN_CHAN_LIST_CMDID
> which is used for the new channel list, and the state of ath12k is
> ATH12K_SCAN_RUNNING, then ath12k_get_ar_on_scan_abort() returns NULL and
> ath12k_scan_event() returns at this point and does not indicate scan
> completion to mac80211.
> 
> Indicate scan completion to mac80211 and get rid of the "Received scan
> event for unknown vdev" print for the above case.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

870c6a72739c wifi: ath12k: indicate scan complete for scan canceled when scan running

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230906085746.18968-1-quic_wgong at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 28 08:06:56 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 15:06:56 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: change to treat alpha code na as world wide
 regdomain
In-Reply-To: <20230906090355.19181-1-quic_wgong@quicinc.com>
References: <20230906090355.19181-1-quic_wgong@quicinc.com>
Message-ID: <169591361532.3019228.18442918001635347196.kvalo@kernel.org>

Wen Gong <quic_wgong at quicinc.com> wrote:

> Some firmware versions for WCN7850 report the default regdomain with
> alpha code "na" by default when load as a world wide regdomain,
> ath12k should treat it as a world wide alpha code.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

c86ba8ee7e32 wifi: ath12k: change to treat alpha code na as world wide regdomain

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230906090355.19181-1-quic_wgong at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 28 08:08:11 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 15:08:11 +0000 (UTC)
Subject: [PATCH] wifi: ath12k: enable
 IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS
 for WCN7850
In-Reply-To: <20230913105507.17675-1-quic_wgong@quicinc.com>
References: <20230913105507.17675-1-quic_wgong@quicinc.com>
Message-ID: <169591368967.3019228.17079892721310631838.kvalo@kernel.org>

Wen Gong <quic_wgong at quicinc.com> wrote:

> Currently mac80211 will send 3 scan request for each scan of WCN7850, they
> are 2.4 GHz/5 GHz/6 GHz band scan. Firmware of WCN7850 will cache the RNR
> IE(Reduced Neighbor Report element) which exist in the beacon of 2.4 GHz/5
> GHz of the AP which is co-located with 6 GHz, and then use the cache to
> scan in 6 GHz band scan if the 6 GHz scan is in the same scan with the 2.4
> GHz/5 GHz band, this will helpful to search more AP of 6 GHz. Also it will
> decrease the time cost of scan because firmware will use dual-band scan
> for the 2.4 GHz/5 GHz, it means the 2.4 GHz and 5 GHz scans are doing
> simultaneously.
> 
> Set the flag IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for WCN7850 since it
> supports 2.4 GHz/5 GHz/6 GHz in a single wiphy/ieee80211_hw.
> 
> This does not impact QCN9274, because it is not single_phy, so does not
> have 2.4 GHz/5 GHz/6 GHz in the same wiphy, then it does not match the
> condition and then IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS will not set for
> QCN9274.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

a1e09eb35476 wifi: ath12k: enable IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS for WCN7850

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230913105507.17675-1-quic_wgong at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 28 08:12:06 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 15:12:06 +0000 (UTC)
Subject: [PATCH v2] wifi: ath12k: Set default beacon mode to burst mode
In-Reply-To: <20230905213943.12275-1-quic_sidhanta@quicinc.com>
References: <20230905213943.12275-1-quic_sidhanta@quicinc.com>
Message-ID: <169591392416.3019228.2935423910724687574.kvalo@kernel.org>

Sidhanta Sahu <quic_sidhanta at quicinc.com> wrote:

> Currently, firmware does not like when beacon mode is set as staggered
> mode for more than one beaconing vifs. Beacon mode for multiple
> beaconing (transmitted) vifs are expected to be in burst mode. So set
> beacon mode to burst mode by default.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Sidhanta Sahu <quic_sidhanta at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

c4cb46dfb291 wifi: ath12k: Set default beacon mode to burst mode

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230905213943.12275-1-quic_sidhanta at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 28 08:12:43 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 15:12:43 +0000 (UTC)
Subject: [PATCH v2] wifi: ath12k: add msdu_end structure for WCN7850
In-Reply-To: <20230911093054.74943-1-quic_kangyang@quicinc.com>
References: <20230911093054.74943-1-quic_kangyang@quicinc.com>
Message-ID: <169591396177.3019228.6958340171406115973.kvalo@kernel.org>

Kang Yang <quic_kangyang at quicinc.com> wrote:

> WCN7850 and QCN9274 currently use the same structure rx_msdu_end_qcn9274
> for msdu_end. But content of msdu_end on WCN7850 is different from that of
> QCN9274. Need to update it for WCN7850, otherwise will get the wrong
> values when using it.
> 
> For example, TID is no longer in WCN7850's msdu_end. But
> ath12k_dp_rx_process_err() and ath12k_dp_rx_process_wbm_err() still get
> TID from msdu_end. So an uncertain value will be used in these two
> functions on WCN7850.
> 
> Therefore, add new structure rx_msdu_end_wcn7850 for WCN7850.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Kang Yang <quic_kangyang at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>

Patch applied to ath-next branch of ath.git, thanks.

ed823fd113b7 wifi: ath12k: add msdu_end structure for WCN7850

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230911093054.74943-1-quic_kangyang at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Thu Sep 28 08:33:12 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Thu, 28 Sep 2023 15:33:12 +0000 (UTC)
Subject: [PATCH v4 1/4] wifi: ath12k: add TAS capability for WCN7850
In-Reply-To: <20230910082802.9198-2-quic_lingbok@quicinc.com>
References: <20230910082802.9198-2-quic_lingbok@quicinc.com>
Message-ID: <169591519084.3096214.13489607891365501029.kvalo@kernel.org>

Lingbo Kong <quic_lingbok at quicinc.com> wrote:

> Currently, ath12k does not support Time-Average-SAR(TAS) for WCN7850. In
> order to enable Time-Average-SAR(TAS) for WCN7850, ath12k defines
> ath12k_get_acpi_all_data() function to get TAS configuration and SAR power
> table, then sets pdev_id, param_type_id, and finally sends the TAS
> configuration, SAR power table and WMI_PDEV_SET_BIOS_INTERFACE_CMDID
> command to firmware to implement TAS during the initialization phase.
> Besides, ath12k registers an ACPI event callback so that ACPI can notify
> ath12k to get the updated SAR power table and sends it to firmware when the
> device state is changed.
> 
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
> 
> Signed-off-by: Lingbo Kong <quic_lingbok at quicinc.com>
> Acked-by: Jeff Johnson <quic_jjohnson at quicinc.com>

Fails to apply, please rebase.

error: patch failed: drivers/net/wireless/ath/ath12k/core.h:771
error: drivers/net/wireless/ath/ath12k/core.h: patch does not apply
error: patch failed: drivers/net/wireless/ath/ath12k/hw.c:907
error: drivers/net/wireless/ath/ath12k/hw.c: patch does not apply
error: patch failed: drivers/net/wireless/ath/ath12k/hw.h:186
error: drivers/net/wireless/ath/ath12k/hw.h: patch does not apply
error: patch failed: drivers/net/wireless/ath/ath12k/wmi.h:4791
error: drivers/net/wireless/ath/ath12k/wmi.h: patch does not apply
stg import: Diff does not apply cleanly

4 patches set to Changes Requested.

13378463 [v4,1/4] wifi: ath12k: add TAS capability for WCN7850
13378462 [v4,2/4] wifi: ath12k: add BIOS SAR capability for WCN7850
13378465 [v4,3/4] wifi: ath12k: add adjust configuration of CCA threshold value for WCN7850
13378464 [v4,4/4] wifi: ath12k: add set band edge channel power for WCN7850

-- 
https://patchwork.kernel.org/project/linux-wireless/patch/20230910082802.9198-2-quic_lingbok at quicinc.com/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches



From kvalo at kernel.org  Fri Sep 29 01:58:45 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Fri, 29 Sep 2023 11:58:45 +0300
Subject: wifi: ath12k: do not drop data frames from unassociated stations
In-Reply-To: <1689749074-14676-1-git-send-email-quic_haric@quicinc.com> (Hari
	Chandrakanthan's message of "Wed, 19 Jul 2023 12:14:34 +0530")
References: <1689749074-14676-1-git-send-email-quic_haric@quicinc.com>
Message-ID: <87y1gp73ui.fsf@kernel.org>

(moving from ath11k to ath12k list)

Hari Chandrakanthan <quic_haric at quicinc.com> writes:

>>From 'IEEE Std 802.11-2020 section 11.3.4.1':
> If STA A in an infrastructure BSS receives a Class 2 or Class 3 frame
> from STA B that is not authenticated with STA A
> (i.e., the state for STA B is State 1), STA A shall discard the frame.
> If the frame has an individual address in the Address 1 field,
> the MLME of STA A shall send a Deauthentication frame to STA B.
>
> When data frames from unassociated stations are received by an AP,
> the AP is supposed to send a deauthentication/disassociation frame with
> reason code "Class 2 frame received from nonauthenticated STA" or
> "Class 3 frame received from nonassociated STA".
>
> But ath12k AP doesn't send deauthentication/disassociation frames,
> when it receives data frames from unassociated stations.
>
> The ath12k driver drops the data frames from unassociated
> station and the upper layer(mac80211/hostapd) is not aware of such event.
> Hence deauthentication/disassociation frame is not sent to that
> particular station by the AP.
>
> To address this issue, allow the data frames from the
> unassociated stations to reach mac80211 so that mac80211 can send
> NL80211_CMD_UNEXPECTED_FRAME event to userspace(hostapd) and hostapd
> upon receiving the event will send the deauthentication/disassociation
> frame with proper reason code.
>
> The data frame from unassociated stations gets dropped in mac80211.
>
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0-02903-QCAHKSWPL_SILICONZ-1
>
> Signed-off-by: Hari Chandrakanthan <quic_haric at quicinc.com>

Heh, I think I found a bug in patchwork. I had a weird problem that
whenever I took this patch from patchwork and applied it using git-am
the commit was empty. The issue seems to be that in mbox format
patchwork doesn't replace "\nFrom " with "\n>From " like all other
software do.

When downloading from patchwork[1]:

[...]
X-Mailing-List: linux-wireless at vger.kernel.org

>From 'IEEE Std 802.11-2020 section 11.3.4.1':
If STA A in an infrastructure BSS receives a Class 2 or Class 3 frame
[...]

But from lore[2] it's correct:

[...]
X-Mailing-List: linux-wireless at vger.kernel.org

>From 'IEEE Std 802.11-2020 section 11.3.4.1':
If STA A in an infrastructure BSS receives a Class 2 or Class 3 frame
[...]

No need to resend because of this, the patch will be soon in the pending
branch.

[1] https://patchwork.kernel.org/project/linux-wireless/patch/1689749074-14676-1-git-send-email-quic_haric at quicinc.com/mbox/

[2] https://lore.kernel.org/linux-wireless/1689749074-14676-1-git-send-email-quic_haric at quicinc.com/raw

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From kvalo at kernel.org  Fri Sep 29 06:11:56 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Fri, 29 Sep 2023 16:11:56 +0300
Subject: [PATCH v2 0/4] wifi: ath12k: add 11d scan offload support and
 handle country code for WCN7850
In-Reply-To: <20230914090746.23560-1-quic_wgong@quicinc.com> (Wen Gong's
	message of "Thu, 14 Sep 2023 05:07:42 -0400")
References: <20230914090746.23560-1-quic_wgong@quicinc.com>
Message-ID: <87ttrd6s4j.fsf@kernel.org>

Wen Gong <quic_wgong at quicinc.com> writes:

> v2: change per Jeff.
>     1. change alpha2 length from 3 to 2.
>     2. change wmi_11d_new_cc_ev to wmi_11d_new_cc_event.
>
> Add handler to send WMI_SET_CURRENT_COUNTRY_CMDID which is needed for 
> 11d scan offload to firmware. And add support for 11d scan offload for 
> WCN7850.
>
> Also fix firmware crash for country code set for WCN7850 and store country
> code for device recovery for WCN7850.
>
> Wen Gong (4):
>   wifi: ath12k: add configure country code for WCN7850
>   wifi: ath12k: add 11d scan offload support
>   wifi: ath12k: avoid firmware crash when reg set for WCN7850
>   wifi: ath12k: store and send country code to firmware after recovery

Patches 2 & 3 had trivial conflicts with rfkill patches, fixed in the
pending branch:

https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=pending&id=3261a8fe9de8fd5a94215eaf0c8738c3f0051105

https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=pending&id=0f82a7f8a8d1944faea458f992d492daa74a968e

No need to resend because of this.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


From kvalo at kernel.org  Fri Sep 29 06:14:09 2023
From: kvalo at kernel.org (Kalle Valo)
Date: Fri, 29 Sep 2023 16:14:09 +0300
Subject: [PATCH] wifi: ath12k: add read variant from SMBIOS for download
 board data
In-Reply-To: <20230905105637.10230-1-quic_wgong@quicinc.com> (Wen Gong's
	message of "Tue, 5 Sep 2023 06:56:37 -0400")
References: <20230905105637.10230-1-quic_wgong@quicinc.com>
Message-ID: <87pm216s0u.fsf@kernel.org>

Wen Gong <quic_wgong at quicinc.com> writes:

> This is to read variant from SMBIOS such as read from DT, the variant
> string will be used to one part of string which used to search board
> data from board-2.bin.
>
> Tested-on: WCN7850 hw2.0 PCI
> WLAN.HMT.1.0-03427-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.15378.4
>
> Signed-off-by: Wen Gong <quic_wgong at quicinc.com>

This had a trivial conflict in core.h, fixed in the pending branch:

https://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git/commit/?h=pending&id=e19165609e6c2823e74ca1a1517f9213b3a540ae

No need to resend because of this.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches


