mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-24 21:02:35 +00:00
435 lines
12 KiB
Diff
435 lines
12 KiB
Diff
From 4728611f5a938152a099ba6659c10bfeaff7773c Mon Sep 17 00:00:00 2001
|
|
From: Maharaja Kennadyrajan <mkenna@codeaurora.org>
|
|
Date: Fri, 3 Sep 2021 13:03:53 +0530
|
|
Subject: [PATCH] ath11k: Add Smart antenna debugfs support
|
|
|
|
Signed-off-by: Maharaja Kennadyrajan <mkenna@codeaurora.org>
|
|
---
|
|
drivers/net/wireless/ath/ath11k/Makefile | 2 +-
|
|
drivers/net/wireless/ath/ath11k/core.h | 1 +
|
|
drivers/net/wireless/ath/ath11k/debug_smart_ant.c | 356 ++++++++++++++++++++++
|
|
drivers/net/wireless/ath/ath11k/debugfs.c | 1 +
|
|
drivers/net/wireless/ath/ath11k/debugfs.h | 4 +
|
|
5 files changed, 363 insertions(+), 1 deletion(-)
|
|
create mode 100644 drivers/net/wireless/ath/ath11k/debug_smart_ant.c
|
|
|
|
--- a/drivers/net/wireless/ath/ath11k/Makefile
|
|
+++ b/drivers/net/wireless/ath/ath11k/Makefile
|
|
@@ -20,7 +20,7 @@ ath11k-y += core.o \
|
|
wow.o \
|
|
vendor.o
|
|
|
|
-ath11k-$(CPTCFG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o debug_nss.o
|
|
+ath11k-$(CPTCFG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o debug_nss.o debug_smart_ant.o
|
|
ath11k-$(CPTCFG_NL80211_TESTMODE) += testmode.o
|
|
ath11k-$(CPTCFG_ATH11K_TRACING) += trace.o
|
|
ath11k-$(CONFIG_THERMAL) += thermal.o
|
|
--- a/drivers/net/wireless/ath/ath11k/core.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
|
@@ -592,6 +592,7 @@ struct ath11k_debug {
|
|
u32 wmi_ctrl_path_stats_tagid;
|
|
struct ath11k_db_module_debug *module_debug[WMI_DIRECT_BUF_MAX];
|
|
bool disable_dynamic_bw;
|
|
+ struct dentry *debugfs_smartant;
|
|
};
|
|
|
|
struct ath11k_per_peer_tx_stats {
|
|
--- /dev/null
|
|
+++ b/drivers/net/wireless/ath/ath11k/debug_smart_ant.c
|
|
@@ -0,0 +1,365 @@
|
|
+// SPDX-License-Identifier: BSD-3-Clause-Clear
|
|
+/*
|
|
+ * Copyright (c) 2015, 2021 The Linux Foundation. All rights reserved.
|
|
+ *
|
|
+ * Permission to use, copy, modify, and/or distribute this software for
|
|
+ * any purpose with or without fee is hereby granted, provided that the
|
|
+ * above copyright notice and this permission notice appear in all copies.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
+ */
|
|
+
|
|
+#include "core.h"
|
|
+#include "wmi.h"
|
|
+#include "debug.h"
|
|
+#include "debugfs.h"
|
|
+#include "smart_ant.h"
|
|
+
|
|
+static ssize_t ath11k_read_sa_enable_ops(struct file *file,
|
|
+ const char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ char buf[4];
|
|
+ int len = 0;
|
|
+
|
|
+ if (!ath11k_smart_ant_enabled(ar))
|
|
+ return -ENOTSUPP;
|
|
+
|
|
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
|
+ ar->smart_ant_info.enabled);
|
|
+
|
|
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
|
|
+}
|
|
+
|
|
+static ssize_t ath11k_write_sa_enable_ops(struct file *file,
|
|
+ const char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ int ret;
|
|
+ bool enable;
|
|
+
|
|
+ if (!ath11k_smart_ant_enabled(ar))
|
|
+ return -ENOTSUPP;
|
|
+
|
|
+ if (kstrtobool_from_user(ubuf, count, &enable))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (ar->smart_ant_info.enabled == enable)
|
|
+ return count;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ ar->smart_ant_info.enabled = enable;
|
|
+ if (enable) {
|
|
+ ret = ath11k_wmi_pdev_enable_smart_ant(ar,
|
|
+ &ar->smart_ant_info);
|
|
+ if (ret)
|
|
+ goto exit;
|
|
+ } else {
|
|
+ ret = ath11k_wmi_pdev_disable_smart_ant(ar,
|
|
+ &ar->smart_ant_info);
|
|
+ if (ret)
|
|
+ goto exit;
|
|
+ }
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_SMART_ANT, "Smart antenna %s\n",
|
|
+ enable ? "enabled" : "disabled");
|
|
+exit:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ if (ret)
|
|
+ return ret;
|
|
+ return count;
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_sa_enable_ops = {
|
|
+ .read = ath11k_read_sa_enable_ops,
|
|
+ .write = ath11k_write_sa_enable_ops,
|
|
+ .open = simple_open,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+#define ATH11K_SA_TX_ANT_MIN_LEN 20
|
|
+
|
|
+static ssize_t ath11k_write_sa_tx_ant(struct file *file,
|
|
+ const char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ u32 ants[WMI_SMART_MAX_RATE_SERIES], txant;
|
|
+ u8 mac_addr[ETH_ALEN];
|
|
+ struct ieee80211_sta *sta;
|
|
+ struct ath11k_sta *arsta;
|
|
+ int ret, i, vdev_id, len;
|
|
+ char *token, *sptr;
|
|
+ char buf[64];
|
|
+
|
|
+ if (!ath11k_smart_ant_enabled(ar))
|
|
+ return -ENOTSUPP;
|
|
+
|
|
+ len = min(count, sizeof(buf) - 1);
|
|
+ if (copy_from_user(buf, ubuf, len))
|
|
+ return -EFAULT;
|
|
+
|
|
+ if (len < ATH11K_SA_TX_ANT_MIN_LEN)
|
|
+ return -EINVAL;
|
|
+
|
|
+ buf[len] = '\0';
|
|
+ sptr = buf;
|
|
+ for (i = 0; i < ETH_ALEN - 1; i++) {
|
|
+ token = strsep(&sptr, ":");
|
|
+ if (!token)
|
|
+ return -EINVAL;
|
|
+ if (kstrtou8(token, 16, &mac_addr[i]))
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ token = strsep(&sptr, " ");
|
|
+ if (!token)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (kstrtou8(token, 16, &mac_addr[i]))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (kstrtou32(sptr, 16, &txant))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (txant > ((1 << ar->ab->target_caps.num_rf_chains) - 1)) {
|
|
+ ath11k_err(ar->ab, "Invalid tx antenna config\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ rcu_read_lock();
|
|
+
|
|
+ sta = ieee80211_find_sta_by_ifaddr(ar->hw, mac_addr, NULL);
|
|
+ if (!sta) {
|
|
+ ath11k_err(ar->ab, "Sta entry not found\n");
|
|
+ rcu_read_unlock();
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
+ vdev_id = arsta->arvif->vdev_id;
|
|
+
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ for (i = 0; i < WMI_SMART_MAX_RATE_SERIES; i++)
|
|
+ ants[i] = txant;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_SMART_ANT, "Smart antenna set tx antenna to %d\n",
|
|
+ txant);
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ ret = ath11k_wmi_peer_set_smart_tx_ant(ar, vdev_id, mac_addr,
|
|
+ ants);
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ if (!ret)
|
|
+ ret = count;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_sa_tx_ant = {
|
|
+ .write = ath11k_write_sa_tx_ant,
|
|
+ .open = simple_open,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+static ssize_t ath11k_write_sa_rx_ant(struct file *file,
|
|
+ const char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ u8 rxant;
|
|
+ int ret;
|
|
+
|
|
+ if (!ath11k_smart_ant_enabled(ar))
|
|
+ return -ENOTSUPP;
|
|
+
|
|
+ if (kstrtou8_from_user(ubuf, count, 0, &rxant))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (rxant > ((1 << ar->ab->target_caps.num_rf_chains) - 1)) {
|
|
+ ath11k_err(ar->ab, "Invalid Rx antenna config\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_SMART_ANT,
|
|
+ "Setting Rx antenna to %d\n", rxant);
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ ret = ath11k_wmi_pdev_set_rx_ant(ar, rxant);
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+
|
|
+ if (!ret)
|
|
+ ret = count;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static ssize_t ath11k_read_sa_rx_ant(struct file *file,
|
|
+ const char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ char buf[4];
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ int len = 0;
|
|
+
|
|
+ len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
|
+ ar->rx_antenna);
|
|
+
|
|
+ return simple_read_from_buffer(ubuf, count, ppos, buf, len);
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_sa_rx_ant = {
|
|
+ .read = ath11k_read_sa_rx_ant,
|
|
+ .write = ath11k_write_sa_rx_ant,
|
|
+ .open = simple_open,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+#define ATH11K_SA_TRAIN_INFO_MIN_LEN 24
|
|
+
|
|
+static ssize_t ath11k_write_sa_train_info(struct file *file,
|
|
+ const char __user *ubuf,
|
|
+ size_t count, loff_t *ppos)
|
|
+{
|
|
+ struct ath11k *ar = file->private_data;
|
|
+ u8 mac_addr[ETH_ALEN];
|
|
+ struct ieee80211_sta *sta;
|
|
+ struct ath11k_sta *arsta;
|
|
+ struct ath11k_smart_ant_train_info params;
|
|
+ int ret, i, vdev_id, len;
|
|
+ u32 rate_mask = 0;
|
|
+ char *token, *sptr;
|
|
+ char buf[128];
|
|
+
|
|
+ if (!ath11k_smart_ant_enabled(ar))
|
|
+ return -ENOTSUPP;
|
|
+
|
|
+ len = min(count, sizeof(buf) - 1);
|
|
+ if (copy_from_user(buf, ubuf, len))
|
|
+ return -EFAULT;
|
|
+
|
|
+ if (len < ATH11K_SA_TRAIN_INFO_MIN_LEN)
|
|
+ return -EINVAL;
|
|
+
|
|
+ buf[len] = '\0';
|
|
+ sptr = buf;
|
|
+ for (i = 0; i < ETH_ALEN - 1; i++) {
|
|
+ token = strsep(&sptr, ":");
|
|
+ if (!token)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (kstrtou8(token, 16, &mac_addr[i]))
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ token = strsep(&sptr, " ");
|
|
+ if (!token)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (kstrtou8(token, 16, &mac_addr[i]))
|
|
+ return -EINVAL;
|
|
+
|
|
+ token = strsep(&sptr, " ");
|
|
+ if (!token)
|
|
+ return -EINVAL;
|
|
+ if (kstrtou32(token, 0, ¶ms.rate_array[0]))
|
|
+ return -EINVAL;
|
|
+
|
|
+ token = strsep(&sptr, " ");
|
|
+ if (!token)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (kstrtou32(token, 16, ¶ms.antenna_array[0]))
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (kstrtou32(sptr, 0, ¶ms.numpkts))
|
|
+ return -EINVAL;
|
|
+
|
|
+ for (i = 0; i < WMI_SMART_MAX_RATE_SERIES; i++) {
|
|
+ params.rate_array[i] = params.rate_array[0];
|
|
+ params.antenna_array[i] = params.antenna_array[0];
|
|
+ }
|
|
+
|
|
+ if (params.antenna_array[0] >
|
|
+ ((1 << ar->ab->target_caps.num_rf_chains) - 1)) {
|
|
+ ath11k_err(ar->ab, "Invalid tx ant for trianing\n");
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ rcu_read_lock();
|
|
+ sta = ieee80211_find_sta_by_ifaddr(ar->hw, mac_addr, NULL);
|
|
+ if (!sta) {
|
|
+ ath11k_err(ar->ab, "Sta entry not found\n");
|
|
+ rcu_read_unlock();
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i <= sta->bandwidth; i++)
|
|
+ rate_mask |= (0xff << (8 * i));
|
|
+
|
|
+ if ((params.rate_array[0] & rate_mask) != params.rate_array[0]) {
|
|
+ ath11k_err(ar->ab, "Invalid rates for training\n");
|
|
+ rcu_read_unlock();
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ arsta = (struct ath11k_sta *)sta->drv_priv;
|
|
+ vdev_id = arsta->arvif->vdev_id;
|
|
+
|
|
+ rcu_read_unlock();
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_SMART_ANT, "Training for peer %pM num pkts:%d\n",
|
|
+ mac_addr, params.numpkts);
|
|
+
|
|
+ for (i = 0; i < WMI_SMART_MAX_RATE_SERIES; i++) {
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_SMART_ANT, "rate[%d] 0x%x antenna[%d] %d\n",
|
|
+ i, params.rate_array[i], i, params.antenna_array[i]);
|
|
+ }
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+ ret = ath11k_wmi_peer_set_smart_ant_train_info(ar, vdev_id, mac_addr,
|
|
+ ¶ms);
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ if (!ret)
|
|
+ ret = count;
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static const struct file_operations fops_sa_train_info_ops = {
|
|
+ .write = ath11k_write_sa_train_info,
|
|
+ .open = simple_open,
|
|
+ .owner = THIS_MODULE,
|
|
+ .llseek = default_llseek,
|
|
+};
|
|
+
|
|
+void ath11k_smart_ant_debugfs_init(struct ath11k *ar)
|
|
+{
|
|
+ ar->debug.debugfs_smartant = debugfs_create_dir("smart_antenna",
|
|
+ ar->debug.debugfs_pdev);
|
|
+
|
|
+ debugfs_create_file("smart_ant_enable", S_IRUSR | S_IWUSR,
|
|
+ ar->debug.debugfs_smartant, ar, &fops_sa_enable_ops);
|
|
+
|
|
+ debugfs_create_file("smart_ant_tx_ant", S_IWUSR,
|
|
+ ar->debug.debugfs_smartant, ar, &fops_sa_tx_ant);
|
|
+
|
|
+ debugfs_create_file("smart_ant_rx_ant", S_IRUSR | S_IWUSR,
|
|
+ ar->debug.debugfs_smartant, ar, &fops_sa_rx_ant);
|
|
+
|
|
+ debugfs_create_file("smart_ant_train_info", S_IWUSR,
|
|
+ ar->debug.debugfs_smartant, ar, &fops_sa_train_info_ops);
|
|
+
|
|
+}
|
|
--- a/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/debugfs.c
|
|
@@ -4327,6 +4327,7 @@ int ath11k_debugfs_register(struct ath11
|
|
|
|
ath11k_debugfs_fw_stats_init(ar);
|
|
ath11k_init_pktlog(ar);
|
|
+ ath11k_smart_ant_debugfs_init(ar);
|
|
init_completion(&ar->tpc_complete);
|
|
init_completion(&ab->ani_ofdm_event);
|
|
init_completion(&ab->ani_cck_event);
|
|
--- a/drivers/net/wireless/ath/ath11k/debugfs.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/debugfs.h
|
|
@@ -239,6 +239,7 @@ void ath11k_debugfs_unregister(struct at
|
|
void ath11k_debugfs_fw_stats_process(struct ath11k_base *ab, struct sk_buff *skb);
|
|
|
|
void ath11k_debugfs_fw_stats_init(struct ath11k *ar);
|
|
+void ath11k_smart_ant_debugfs_init(struct ath11k *ar);
|
|
ssize_t ath11k_debugfs_dump_soc_ring_bp_stats(struct ath11k_base *ab,
|
|
char *buf, int size);
|
|
void ath11k_dbring_add_debug_entry(struct ath11k *ar,
|
|
@@ -375,6 +376,9 @@ ath11k_dbring_add_debug_entry(struct ath
|
|
struct hal_srng *srng)
|
|
{
|
|
}
|
|
+static inline void ath11k_smart_ant_debugfs_init(struct ath11k *ar)
|
|
+{
|
|
+}
|
|
#endif /* CPTCFG_MAC80211_DEBUGFS*/
|
|
|
|
#ifdef CPTCFG_ATH11K_PKTLOG
|