mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-19 10:23:03 +00:00
343 lines
9.6 KiB
Diff
343 lines
9.6 KiB
Diff
From a7c191e95212c2169b8155ba8456d37c2f33ca65 Mon Sep 17 00:00:00 2001
|
|
From: Lavanya Suresh <lavaks@codeaurora.org>
|
|
Date: Thu, 6 May 2021 13:31:08 +0530
|
|
Subject: [PATCH] ath11k: Add support to handle AWGN interference for 6G
|
|
|
|
When AWGN interference is detected in any 6G channel, FW indicates it to
|
|
host using WMI_DCS_INTERFERENCE_EVENT. Added support to parse new wmi
|
|
event to get AWGN interference info and indicate to mac80211.
|
|
|
|
AWGN interference detection support in FW will be advertised in wmi service
|
|
ready event, based on which host can decide to handle and process interference
|
|
events.
|
|
|
|
Added debugfs support to simulate AWGN interference from host, for testing
|
|
purposes.
|
|
Usage:
|
|
echo 1 > /sys/kernel/debug/ath11k/qcn9074\ hw1.0_000X\:01\:00.0/
|
|
mac0/simulate_awgn
|
|
|
|
Signed-off-by: Lavanya Suresh <lavaks@codeaurora.org>
|
|
---
|
|
drivers/net/wireless/ath/ath11k/debugfs.c | 25 +++++
|
|
drivers/net/wireless/ath/ath11k/wmi.c | 176 ++++++++++++++++++++++++++++++
|
|
drivers/net/wireless/ath/ath11k/wmi.h | 29 +++++
|
|
3 files changed, 230 insertions(+)
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
@@ -2161,6 +2161,35 @@ static const struct file_operations fops
|
|
.open = simple_open
|
|
};
|
|
|
|
+static ssize_t ath11k_write_simulate_awgn(struct file *file,
|
|
+ const char __user *user_buf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ int ret;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ if (ar->state != ATH11K_STATE_ON) {
|
|
+ ret = -ENETDOWN;
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ ret = ath11k_wmi_simulate_awgn(ar);
|
|
+ if (ret)
|
|
+ goto exit;
|
|
+
|
|
+ ret = count;
|
|
+
|
|
+exit:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_simulate_awgn = {
|
|
+ .write = ath11k_write_simulate_awgn,
|
|
+ .open = simple_open
|
|
+};
|
|
+
|
|
static ssize_t ath11k_write_btcoex(struct file *file,
|
|
const char __user *ubuf,
|
|
size_t count, loff_t *ppos)
|
|
@@ -3765,6 +3794,12 @@ int ath11k_debugfs_register(struct ath11
|
|
&ar->dfs_block_radar_events);
|
|
}
|
|
|
|
+ if (ar->hw->wiphy->bands[NL80211_BAND_6GHZ]) {
|
|
+ debugfs_create_file("simulate_awgn", 0200,
|
|
+ ar->debug.debugfs_pdev, ar,
|
|
+ &fops_simulate_awgn);
|
|
+ }
|
|
+
|
|
debugfs_create_file("enable_m3_dump", 0644,
|
|
ar->debug.debugfs_pdev, ar,
|
|
&fops_enable_m3_dump);
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
|
@@ -8419,6 +8419,143 @@ exit:
|
|
kfree(tb);
|
|
}
|
|
|
|
+static int ath11k_wmi_awgn_intf_subtlv_parser(struct ath11k_base *ab,
|
|
+ u16 tag, u16 len,
|
|
+ const void *ptr, void *data)
|
|
+{
|
|
+ int ret = 0;
|
|
+ struct wmi_dcs_awgn_info *awgn_info;
|
|
+
|
|
+ switch (tag) {
|
|
+ case WMI_TAG_DCS_AWGN_INT_TYPE:
|
|
+ awgn_info = (struct wmi_dcs_awgn_info *)ptr;
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
|
|
+ "AWGN Info: channel width: %d, chan freq: %d, center_freq0: %d, center_freq1: %d, bw_intf_bitmap: %d\n",
|
|
+ awgn_info->channel_width, awgn_info->chan_freq, awgn_info->center_freq0, awgn_info->center_freq1,
|
|
+ awgn_info->chan_bw_interference_bitmap);
|
|
+ break;
|
|
+ default:
|
|
+ ath11k_warn(ab,
|
|
+ "Received invalid tag for wmi dcs interference in subtlvs\n");
|
|
+ return -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ath11k_wmi_dcs_awgn_event_parser(struct ath11k_base *ab,
|
|
+ u16 tag, u16 len,
|
|
+ const void *ptr, void *data)
|
|
+{
|
|
+ int ret = 0;
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI, "wmi dcs awgn event tag 0x%x of len %d rcvd\n",
|
|
+ tag, len);
|
|
+
|
|
+ switch (tag) {
|
|
+ case WMI_TAG_DCS_INTERFERENCE_EVENT:
|
|
+ /* Fixed param is already processed*/
|
|
+ break;
|
|
+ case WMI_TAG_ARRAY_STRUCT:
|
|
+ /* len 0 is expected for array of struct when there
|
|
+ * is no content of that type to pack inside that tlv
|
|
+ */
|
|
+ if (len == 0)
|
|
+ return 0;
|
|
+ ret = ath11k_wmi_tlv_iter(ab, ptr, len,
|
|
+ ath11k_wmi_awgn_intf_subtlv_parser,
|
|
+ data);
|
|
+ break;
|
|
+ default:
|
|
+ ath11k_warn(ab, "Received invalid tag for wmi dcs interference event\n");
|
|
+ ret = -EINVAL;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void
|
|
+ath11k_wmi_dcs_awgn_interference_event(struct ath11k_base *ab,
|
|
+ struct sk_buff *skb)
|
|
+{
|
|
+ const struct wmi_dcs_interference_ev *dcs_intf_ev;
|
|
+ struct wmi_dcs_awgn_info *awgn_info;
|
|
+ struct ath11k *ar;
|
|
+ struct ath11k_vif *arvif;
|
|
+ const struct wmi_tlv *tlv;
|
|
+ u16 tlv_tag;
|
|
+ u8 *ptr;
|
|
+ int ret;
|
|
+
|
|
+ if (!test_bit(WMI_TLV_SERVICE_DCS_AWGN_INT_SUPPORT, ab->wmi_ab.svc_map)) {
|
|
+ ath11k_warn(ab, "firmware doesn't support awgn interference, so dropping dcs interference ev\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ptr = skb->data;
|
|
+
|
|
+ if (skb->len < (sizeof(*dcs_intf_ev) + TLV_HDR_SIZE)) {
|
|
+ ath11k_warn(ab, "dcs interference event size invalid\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ tlv = (struct wmi_tlv *)ptr;
|
|
+ tlv_tag = FIELD_GET(WMI_TLV_TAG, tlv->header);
|
|
+ ptr += sizeof(*tlv);
|
|
+
|
|
+ if (tlv_tag == WMI_TAG_DCS_INTERFERENCE_EVENT) {
|
|
+ dcs_intf_ev = (struct wmi_dcs_interference_ev*)ptr;
|
|
+
|
|
+ ath11k_dbg(ab, ATH11K_DBG_WMI,
|
|
+ "pdev awgn detected on pdev %d, interference type %d\n",
|
|
+ dcs_intf_ev->pdev_id, dcs_intf_ev->interference_type);
|
|
+
|
|
+ if (dcs_intf_ev->interference_type != WMI_DCS_AWGN_INTF) {
|
|
+ ath11k_warn(ab, "interference type is not awgn\n");
|
|
+ return;
|
|
+ }
|
|
+ } else {
|
|
+ ath11k_warn(ab, "dcs interference event received with wrong tag\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
|
|
+ ath11k_wmi_dcs_awgn_event_parser,
|
|
+ awgn_info);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ab, "failed to parse awgn tlv %d\n", ret);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ rcu_read_lock();
|
|
+ ar = ath11k_mac_get_ar_by_pdev_id(ab, dcs_intf_ev->pdev_id);
|
|
+ if (!ar) {
|
|
+ ath11k_warn(ab, "awgn detected in invalid pdev id(%d)\n",
|
|
+ dcs_intf_ev->pdev_id);
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ if (!ar->supports_6ghz) {
|
|
+ ath11k_warn(ab, "pdev does not supports 6G, so dropping dcs interference event\n");
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ ath11k_info(ab, "Interface(pdev %d) will be disabled because of AWGN interference\n",
|
|
+ dcs_intf_ev->pdev_id);
|
|
+
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
+ if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
|
+ ieee80211_awgn_detected(arvif->vif);
|
|
+ }
|
|
+ }
|
|
+
|
|
+exit:
|
|
+ rcu_read_unlock();
|
|
+}
|
|
+
|
|
static void ath11k_wmi_tm_event_segmented(struct ath11k_base *ab, u32 cmd_id,
|
|
struct sk_buff *skb)
|
|
{
|
|
@@ -9566,6 +9703,9 @@ static void ath11k_wmi_tlv_op_rx(struct
|
|
case WMI_WOW_WAKEUP_HOST_EVENTID:
|
|
ath11k_wmi_event_wow_wakeup_host(ab, skb);
|
|
break;
|
|
+ case WMI_DCS_INTERFERENCE_EVENTID:
|
|
+ ath11k_wmi_dcs_awgn_interference_event(ab, skb);
|
|
+ break;
|
|
case WMI_PDEV_GET_TPC_STATS_EVENTID:
|
|
ath11k_process_tpc_stats(ab, skb);
|
|
break;
|
|
@@ -9728,6 +9868,42 @@ int ath11k_wmi_simulate_radar(struct ath
|
|
return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args);
|
|
}
|
|
|
|
+
|
|
+int ath11k_wmi_simulate_awgn(struct ath11k *ar)
|
|
+{
|
|
+ struct ath11k_vif *arvif;
|
|
+ u32 awgn_args[WMI_AWGN_MAX_TEST_ARGS];
|
|
+ struct wmi_unit_test_cmd wmi_ut;
|
|
+ bool arvif_found = false;
|
|
+
|
|
+ if (!test_bit(WMI_TLV_SERVICE_DCS_AWGN_INT_SUPPORT, ar->ab->wmi_ab.svc_map)) {
|
|
+ ath11k_warn(ar->ab, "firmware doesn't support awgn interference, so can't simulate it\n");
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ list_for_each_entry(arvif, &ar->arvifs, list) {
|
|
+ if (arvif->is_started && arvif->vdev_type == WMI_VDEV_TYPE_AP) {
|
|
+ arvif_found = true;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!arvif_found)
|
|
+ return -EINVAL;
|
|
+
|
|
+ awgn_args[WMI_AWGN_TEST_AWGN_INT] = WMI_UNIT_TEST_AWGN_INTF_TYPE;
|
|
+ awgn_args[WMI_AWGN_TEST_BITMAP] = WMI_UNIT_TEST_AWGN_PRIMARY_20;
|
|
+
|
|
+ wmi_ut.vdev_id = arvif->vdev_id;
|
|
+ wmi_ut.module_id = WMI_AWGN_UNIT_TEST_MODULE;
|
|
+ wmi_ut.num_args = WMI_AWGN_MAX_TEST_ARGS;
|
|
+ wmi_ut.diag_token = WMI_AWGN_UNIT_TEST_TOKEN;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_WMI, "Triggering AWGN Simulation\n");
|
|
+
|
|
+ return ath11k_wmi_send_unit_test_cmd(ar, wmi_ut, awgn_args);
|
|
+}
|
|
+
|
|
int ath11k_wmi_pdev_m3_dump_enable(struct ath11k *ar, u32 enable) {
|
|
struct ath11k_vif *arvif;
|
|
u32 m3_args[WMI_M3_MAX_TEST_ARGS];
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.h
|
|
@@ -1903,6 +1903,7 @@ enum wmi_tlv_tag {
|
|
WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
|
|
|
|
WMI_CTRL_PATH_CAL_STATS = 0x3BC,
|
|
+ WMI_TAG_DCS_AWGN_INT_TYPE = 0x3C5,
|
|
|
|
WMI_TAG_MAX
|
|
};
|
|
@@ -2175,6 +2176,7 @@ enum wmi_tlv_service {
|
|
WMI_TLV_SERVICE_PASSIVE_SCAN_START_TIME_ENHANCE = 263,
|
|
WMI_TLV_SERVICE_QOS_NULL_FRAME_TX_OVER_WMI = 264,
|
|
WMI_TLV_SERVICE_REG_CC_EXT_EVENT_SUPPORT = 281,
|
|
+ WMI_TLV_SERVICE_DCS_AWGN_INT_SUPPORT = 286,
|
|
|
|
WMI_MAX_EXT2_SERVICE
|
|
};
|
|
@@ -4216,6 +4218,17 @@ struct wmi_dfs_unit_test_arg {
|
|
u32 radar_param;
|
|
};
|
|
|
|
+#define WMI_AWGN_UNIT_TEST_MODULE 0x18
|
|
+#define WMI_AWGN_UNIT_TEST_TOKEN 0
|
|
+#define WMI_UNIT_TEST_AWGN_INTF_TYPE 1
|
|
+#define WMI_UNIT_TEST_AWGN_PRIMARY_20 0x01
|
|
+
|
|
+enum wmi_awgn_test_args_idx {
|
|
+ WMI_AWGN_TEST_AWGN_INT,
|
|
+ WMI_AWGN_TEST_BITMAP,
|
|
+ WMI_AWGN_MAX_TEST_ARGS,
|
|
+};
|
|
+
|
|
#define WMI_M3_UNIT_TEST_MODULE 0x22
|
|
#define WMI_M3_UNIT_TEST_TOKEN 0
|
|
|
|
@@ -4843,6 +4856,21 @@ struct wmi_pdev_radar_ev {
|
|
s32 sidx;
|
|
} __packed;
|
|
|
|
+#define WMI_DCS_AWGN_INTF 0x04
|
|
+
|
|
+struct wmi_dcs_awgn_info {
|
|
+ u32 channel_width;
|
|
+ u32 chan_freq;
|
|
+ u32 center_freq0;
|
|
+ u32 center_freq1;
|
|
+ u32 chan_bw_interference_bitmap;
|
|
+} __packed;
|
|
+
|
|
+struct wmi_dcs_interference_ev {
|
|
+ u32 interference_type;
|
|
+ u32 pdev_id;
|
|
+} __packed;
|
|
+
|
|
struct wmi_pdev_temperature_event {
|
|
/* temperature value in Celcius degree */
|
|
s32 temp;
|
|
@@ -6636,6 +6664,7 @@ void ath11k_wmi_fw_stats_fill(struct ath
|
|
struct ath11k_fw_stats *fw_stats, u32 stats_id,
|
|
char *buf);
|
|
int ath11k_wmi_simulate_radar(struct ath11k *ar);
|
|
+int ath11k_wmi_simulate_awgn(struct ath11k *ar);
|
|
int ath11k_wmi_send_twt_enable_cmd(struct ath11k *ar, u32 pdev_id);
|
|
int ath11k_wmi_send_twt_disable_cmd(struct ath11k *ar, u32 pdev_id);
|
|
int ath11k_wmi_send_twt_add_dialog_cmd(struct ath11k *ar,
|