Search Linux Wireless

Re: [PATCH] wifi: ath12k: Add WMI control path stats infra

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 5/29/2024 11:39 PM, Ramya Gnanasekar wrote:
> From: Rajat Soni <quic_rajson@xxxxxxxxxxx>
> 
> Currently, firmware stats is requested by host through HTT interface.
> Since HTT interface is already overloaded for data path stats,
> leveraging control path to request other stats through WMI interface.
> 
> Add debugfs to request the stats and dump the stats forwarded by firmware.
> 
> ath12k
> `-- pci-0000:06:00.0
>     |-- mac0
>         `-- wmi_ctrl_stats
> 
> This patch also adds support to request PDEV Tx stats, parse and dump
> the data sent from firmware.
> 
> Usage:
> echo <stats id> <action> > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/wmi_ctrl_stats
> 
> Sample:
> echo 1 1 > /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/wmi_ctrl_stats
> cat /sys/kernel/debug/ath12k/pci-0000\:06\:00.0/mac0/wmi_ctrl_stats
> WMI_CTRL_PATH_PDEV_TX_STATS:
> fw_tx_mgmt_subtype =  0:0, 1:2, 2:0, 3:0, 4:0, 5:37, 6:0, 7:0, 8:908, 9:0, 10:0, 11:18, 12:2, 13:3, 14:0, 15:0,
> fw_rx_mgmt_subtype =  0:0, 1:0, 2:0, 3:0, 4:0, 5:0, 6:0, 7:0, 8:0, 9:0, 10:0, 11:0, 12:0, 13:0, 14:0, 15:0,
> scan_fail_dfs_violation_time_ms = 0
> nol_chk_fail_last_chan_freq = 0
> nol_chk_fail_time_stamp_ms = 0
> tot_peer_create_cnt = 7
> tot_peer_del_cnt = 7
> tot_peer_del_resp_cnt = 7
> vdev_pause_fail_rt_to_sched_algo_fifo_full_cnt = 0
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.0.1-00029-QCAHKSWPL_SILICONZ-1
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3
> 
> Signed-off-by: Rajat Soni <quic_rajson@xxxxxxxxxxx>
> Co-developed-by: Ramya Gnanasekar <quic_rgnanase@xxxxxxxxxxx>
> Signed-off-by: Ramya Gnanasekar <quic_rgnanase@xxxxxxxxxxx>
> ---
> Depends-On: [PATCH v2 3/5] wifi: ath12k: Fix Pdev id in HTT stats request for WCN7850
> Link: https://lore.kernel.org/linux-wireless/20240510050806.514126-1-quic_rgnanase@xxxxxxxxxxx
> ---
>  drivers/net/wireless/ath/ath12k/core.h    |   7 +
>  drivers/net/wireless/ath/ath12k/debugfs.c | 146 ++++++++++
>  drivers/net/wireless/ath/ath12k/wmi.c     | 320 ++++++++++++++++++++++
>  drivers/net/wireless/ath/ath12k/wmi.h     |  86 ++++++
>  4 files changed, 559 insertions(+)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
> index 8acf6424f981..18f9b8e0eb85 100644
> --- a/drivers/net/wireless/ath/ath12k/core.h
> +++ b/drivers/net/wireless/ath/ath12k/core.h
> @@ -484,6 +484,13 @@ struct ath12k_dbg_htt_stats {
>  struct ath12k_debug {
>  	struct dentry *debugfs_pdev;
>  	struct ath12k_dbg_htt_stats htt_stats;
> +	struct ath12k_wmi_ctrl_path_stats_list wmi_ctrl_path_stats;
> +	enum wmi_tlv_tag wmi_ctrl_path_stats_tagid;
> +	struct completion wmi_ctrl_path_stats_rcvd;
> +	u8 wmi_ctrl_path_stats_reqid;
> +	/* To protect wmi_list manipulation */
> +	spinlock_t  wmi_ctrl_path_stats_lock;
> +	bool wmi_ctrl_path_stats_more_enabled;
>  };
>  
>  struct ath12k_per_peer_tx_stats {
> diff --git a/drivers/net/wireless/ath/ath12k/debugfs.c b/drivers/net/wireless/ath/ath12k/debugfs.c
> index 30a80f04d824..5cd5b69324d2 100644
> --- a/drivers/net/wireless/ath/ath12k/debugfs.c
> +++ b/drivers/net/wireless/ath/ath12k/debugfs.c
> @@ -68,6 +68,148 @@ void ath12k_debugfs_soc_destroy(struct ath12k_base *ab)
>  	 */
>  }
>  
> +static ssize_t ath12k_write_wmi_ctrl_path_stats(struct file *file,
> +						const char __user *ubuf,
> +						size_t count, loff_t *ppos)
> +{
> +	struct ath12k *ar = file->private_data;
> +	struct wmi_ctrl_path_stats_arg arg = {};
> +	u8 buf[128] = {0};
> +	int ret;
> +
> +	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
> +	if (ret < 0)
> +		return ret;
> +
> +	buf[ret] = '\0';
> +
> +	ret = sscanf(buf, "%u %u", &arg.stats_id, &arg.action);
> +	if (ret != 2)
> +		return -EINVAL;
> +
> +	if (!arg.action || arg.action > WMI_REQUEST_CTRL_PATH_STAT_RESET)
> +		return -EINVAL;
> +
> +	ret = ath12k_wmi_send_wmi_ctrl_stats_cmd(ar, &arg);
> +	return ret ? ret : count;
> +}
> +
> +static int wmi_ctrl_path_pdev_stat(struct ath12k *ar, char __user *ubuf,
> +				   size_t count, loff_t *ppos)
> +{
> +	char fw_tx_mgmt_subtype[WMI_MAX_STRING_LEN] = {0};
> +	char fw_rx_mgmt_subtype[WMI_MAX_STRING_LEN] = {0};
> +	struct wmi_ctrl_path_pdev_stats *stats, *tmp;
> +	u16 index_tx, index_rx;
> +	const int size = 2048;
> +	u8 i;
> +	int len = 0;
> +
> +	char *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	LIST_HEAD(wmi_stats_list);
> +
> +	spin_lock_bh(&ar->debug.wmi_ctrl_path_stats_lock);
> +	list_splice_tail_init(&ar->debug.wmi_ctrl_path_stats.pdev_stats, &wmi_stats_list);
> +	spin_unlock_bh(&ar->debug.wmi_ctrl_path_stats_lock);
> +
> +	list_for_each_entry_safe(stats, tmp, &wmi_stats_list, list) {
> +		if (!stats)
> +			break;
> +
> +		index_tx = 0;
> +		index_rx = 0;
> +
> +		for (i = 0; i < IEEE80211_MGMT_FRAME_SUBTYPE_MAX; i++) {
> +			index_tx += scnprintf(&fw_tx_mgmt_subtype[index_tx],
> +					     WMI_MAX_STRING_LEN - index_tx,
> +					     " %u:%u,", i,
> +					    stats->tx_mgmt_subtype[i]);
> +			index_rx += scnprintf(&fw_rx_mgmt_subtype[index_rx],
> +					     WMI_MAX_STRING_LEN - index_rx,
> +					     " %u:%u,", i,
> +					     stats->rx_mgmt_subtype[i]);
> +		}
> +
> +		len += scnprintf(buf + len, size - len,
> +				 "WMI_CTRL_PATH_PDEV_TX_STATS:\n");
> +		len += scnprintf(buf + len, size - len,
> +				 "fw_tx_mgmt_subtype = %s\n",
> +				 fw_tx_mgmt_subtype);
> +		len += scnprintf(buf + len, size - len,
> +				 "fw_rx_mgmt_subtype = %s\n",
> +				 fw_rx_mgmt_subtype);
> +		len += scnprintf(buf + len, size - len,
> +				 "scan_fail_dfs_violation_time_ms = %u\n",
> +				 stats->scan_fail_dfs_viol_time_ms);
> +		len += scnprintf(buf + len, size - len,
> +				 "nol_chk_fail_last_chan_freq = %u\n",
> +				 stats->nol_chk_fail_last_chan_freq);
> +		len += scnprintf(buf + len, size - len,
> +				 "nol_chk_fail_time_stamp_ms = %u\n",
> +				 stats->nol_chk_fail_time_stamp_ms);
> +		len += scnprintf(buf + len, size - len,
> +				 "tot_peer_create_cnt = %u\n",
> +				 stats->tot_peer_create_cnt);
> +		len += scnprintf(buf + len, size - len,
> +				 "tot_peer_del_cnt = %u\n",
> +				 stats->tot_peer_del_cnt);
> +		len += scnprintf(buf + len, size - len,
> +				 "tot_peer_del_resp_cnt = %u\n",
> +				 stats->tot_peer_del_resp_cnt);
> +		len += scnprintf(buf + len, size - len,
> +				 "vdev_pause_fail_rt_to_sched_algo_fifo_full_cnt = %u\n",
> +				 stats->sched_algo_fifo_full_cnt);
> +		list_del(&stats->list);
> +		kfree(stats);
> +	}
> +
> +	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
> +}
> +
> +static ssize_t ath12k_read_wmi_ctrl_path_stats(struct file *file,
> +					       char __user *ubuf,
> +					       size_t count, loff_t *ppos)
> +{
> +	struct ath12k *ar = file->private_data;
> +	int ret;
> +	enum wmi_tlv_tag tagid;
> +
> +	tagid = ar->debug.wmi_ctrl_path_stats_tagid;
> +
> +	switch (tagid) {
> +	case WMI_TAG_CTRL_PATH_PDEV_STATS:
> +		ret = wmi_ctrl_path_pdev_stat(ar, ubuf, count, ppos);
> +		break;
> +	default:
> +		/* Unsupported tag */
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static const struct file_operations ath12k_fops_wmi_ctrl_stats = {
> +	.write = ath12k_write_wmi_ctrl_path_stats,
> +	.open = simple_open,
> +	.read = ath12k_read_wmi_ctrl_path_stats,
> +};
> +
> +static void ath12k_debugfs_wmi_ctrl_stats_register(struct ath12k *ar)
> +{
> +	debugfs_create_file("wmi_ctrl_stats", 0600,
> +			    ar->debug.debugfs_pdev,
> +			    ar,
> +			    &ath12k_fops_wmi_ctrl_stats);
> +	INIT_LIST_HEAD(&ar->debug.wmi_ctrl_path_stats.pdev_stats);
> +	spin_lock_init(&ar->debug.wmi_ctrl_path_stats_lock);
> +	init_completion(&ar->debug.wmi_ctrl_path_stats_rcvd);
> +	ar->debug.wmi_ctrl_path_stats_more_enabled = false;
> +}
> +
>  void ath12k_debugfs_register(struct ath12k *ar)
>  {
>  	struct ath12k_base *ab = ar->ab;
> @@ -90,4 +232,8 @@ void ath12k_debugfs_register(struct ath12k *ar)
>  	}
>  
>  	ath12k_debugfs_htt_stats_init(ar);
> +
> +	if (test_bit(WMI_TLV_SERVICE_CTRL_PATH_STATS_REQUEST,
> +		     ar->ab->wmi_ab.svc_map))
> +		ath12k_debugfs_wmi_ctrl_stats_register(ar);
>  }
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 99106b088311..2d636baa1d53 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -16,6 +16,7 @@
>  #include <linux/of.h>
>  #include "core.h"
>  #include "debug.h"
> +#include "debugfs.h"
>  #include "mac.h"
>  #include "hw.h"
>  #include "peer.h"
> @@ -7029,6 +7030,232 @@ static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab,
>  	kfree(tb);
>  }
>  
> +#ifdef CONFIG_ATH12K_DEBUGFS
> +static void
> +ath12k_wmi_ctrl_path_pdev_stats_list_free(struct list_head *head)
> +{
> +	struct wmi_ctrl_path_pdev_stats *stats_list, *tmp;
> +
> +	list_for_each_entry_safe(stats_list, tmp, head, list) {
> +		list_del(&stats_list->list);
> +		kfree(stats_list);
> +	}
> +}
> +
> +static void
> +ath12k_wmi_ctrl_path_stats_list_free(struct ath12k_wmi_ctrl_path_stats_list *param)
> +{
> +	ath12k_wmi_ctrl_path_pdev_stats_list_free(&param->pdev_stats);
> +}
> +
> +static int wmi_pull_ctrl_path_pdev_tx_stats_tlv(struct ath12k_base *ab, u16 len,
> +						const void *ptr, void *data)
> +{
> +	struct ath12k_wmi_ctrl_path_stats_list *stats_buff = data;
> +	const struct wmi_ctrl_path_pdev_stats_params *stats = ptr;
> +	struct ath12k_wmi_ctrl_path_stats_list *stats_list;
> +	struct wmi_ctrl_path_pdev_stats *pdev_stats =
> +		kzalloc(sizeof(*pdev_stats), GFP_ATOMIC);
> +	struct ath12k *ar;
> +	u32 pdev_id;
> +	int i;
> +
> +	if (!pdev_stats)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < IEEE80211_MGMT_FRAME_SUBTYPE_MAX; i++) {
> +		pdev_stats->tx_mgmt_subtype[i] =
> +			__le32_to_cpu(stats->tx_mgmt_subtype[i]);
> +		pdev_stats->rx_mgmt_subtype[i] =
> +			__le32_to_cpu(stats->rx_mgmt_subtype[i]);
> +	}
> +	pdev_stats->scan_fail_dfs_viol_time_ms =
> +		__le32_to_cpu(stats->scan_fail_dfs_viol_time_ms);
> +	pdev_stats->nol_chk_fail_last_chan_freq =
> +		__le32_to_cpu(stats->nol_chk_fail_last_chan_freq);
> +	pdev_stats->nol_chk_fail_time_stamp_ms =
> +		__le32_to_cpu(stats->nol_chk_fail_time_stamp_ms);
> +	pdev_stats->tot_peer_create_cnt =
> +		__le32_to_cpu(stats->tot_peer_create_cnt);
> +	pdev_stats->tot_peer_del_cnt =
> +		__le32_to_cpu(stats->tot_peer_del_cnt);
> +	pdev_stats->tot_peer_del_resp_cnt =
> +		__le32_to_cpu(stats->tot_peer_del_resp_cnt);
> +	pdev_stats->sched_algo_fifo_full_cnt =
> +		__le32_to_cpu(stats->sched_algo_fifo_full_cnt);
> +
> +	list_add_tail(&pdev_stats->list, &stats_buff->pdev_stats);
> +	pdev_id = le32_to_cpu(stats->pdev_id);
> +
> +	rcu_read_lock();
> +	ar = ath12k_mac_get_ar_by_pdev_id(ab, pdev_id + 1);
> +	if (!ar) {
> +		rcu_read_unlock();
> +		ath12k_warn(ab, "Failed to get ar for wmi ctrl stats\n");
> +		kfree(pdev_stats);
> +		return -EINVAL;
> +	}
> +
> +	spin_lock_bh(&ar->debug.wmi_ctrl_path_stats_lock);
> +	stats_list = &ar->debug.wmi_ctrl_path_stats;
> +	ath12k_wmi_ctrl_path_pdev_stats_list_free(&stats_list->pdev_stats);
> +	spin_unlock_bh(&ar->debug.wmi_ctrl_path_stats_lock);
> +	ar->debug.wmi_ctrl_path_stats_tagid = WMI_TAG_CTRL_PATH_PDEV_STATS;
> +	stats_buff->ar = ar;
> +	rcu_read_unlock();
> +	return 0;
> +}
> +
> +static int ath12k_wmi_ctrl_stats_subtlv_parser(struct ath12k_base *ab,
> +					       u16 tag, u16 len,
> +					       const void *ptr, void *data)
> +{
> +	int ret;
> +
> +	switch (tag) {
> +	case WMI_TAG_CTRL_PATH_STATS_EV_FIXED_PARAM:
> +		break;
> +	case WMI_TAG_CTRL_PATH_PDEV_STATS:
> +		ret = wmi_pull_ctrl_path_pdev_tx_stats_tlv(ab, len, ptr, data);
> +		break;
> +		/* Add case for newly wmi ctrl path added stats here */
> +	default:
> +		ath12k_warn(ab,
> +			    "Received invalid tag for wmi ctrl path stats in subtlvs, tag : 0x%x\n",
> +			    tag);
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int ath12k_wmi_ctrl_stats_event_parser(struct ath12k_base *ab,
> +					      u16 tag, u16 len,
> +					      const void *ptr, void *data)
> +{
> +	int ret;
> +
> +	ath12k_dbg(ab, ATH12K_DBG_WMI, "wmi ctrl path stats tag 0x%x of len %d rcvd\n",
> +		   tag, len);
> +
> +	switch (tag) {
> +	case WMI_TAG_CTRL_PATH_STATS_EV_FIXED_PARAM:
> +		/* Fixed param is already processed*/
> +		ret = 0;
> +		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 = ath12k_wmi_tlv_iter(ab, ptr, len,
> +					  ath12k_wmi_ctrl_stats_subtlv_parser,
> +					  data);
> +		break;
> +	default:
> +		ath12k_warn(ab, "Received invalid tag for wmi ctrl path stats\n");
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static void ath12k_wmi_ctrl_path_stats_event(struct ath12k_base *ab, struct sk_buff *skb)
> +{
> +	struct wmi_ctrl_path_stats_event *fixed_param;
> +	struct ath12k_wmi_ctrl_path_stats_list param = {0};
> +	struct ath12k_wmi_ctrl_path_stats_list *stats;
> +	const struct wmi_tlv *tlv;
> +	struct list_head *src, *dst;
> +	struct ath12k *ar;
> +	void *ptr = skb->data;
> +	u16 tlv_tag, tag_id;
> +	u32 more;
> +	int ret;
> +
> +	if (!skb->data) {
> +		ath12k_warn(ab, "No data present in wmi ctrl stats event\n");
> +		return;
> +	}
> +
> +	if (skb->len < (sizeof(*fixed_param) + TLV_HDR_SIZE)) {
> +		ath12k_warn(ab, "wmi ctrl stats event size invalid\n");
> +		return;
> +	}
> +
> +	param.ar = NULL;
> +
> +	tlv = ptr;
> +	tlv_tag = le32_get_bits(tlv->header, WMI_TLV_TAG);
> +	ptr += sizeof(*tlv);
> +
> +	if (tlv_tag != WMI_TAG_CTRL_PATH_STATS_EV_FIXED_PARAM) {
> +		ath12k_warn(ab, "wmi ctrl stats without fixed param tlv at start\n");
> +		return;
> +	}
> +
> +	INIT_LIST_HEAD(&param.pdev_stats);
> +
> +	fixed_param = ptr;
> +	ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,
> +				  ath12k_wmi_ctrl_stats_event_parser,
> +				  &param);
> +	if (ret) {
> +		ath12k_warn(ab, "failed to parse wmi_ctrl_path_stats tlv: %d\n", ret);
> +		goto free;
> +	}
> +
> +	ar = param.ar;
> +	if (!ar)
> +		return;
> +
> +	tag_id = ar->debug.wmi_ctrl_path_stats_tagid;
> +	stats = &ar->debug.wmi_ctrl_path_stats;
> +	more = __le32_to_cpu(fixed_param->more);
> +
> +	switch (tag_id) {
> +	case WMI_TAG_CTRL_PATH_PDEV_STATS:
> +		src = &param.pdev_stats;
> +		dst = &stats->pdev_stats;
> +		break;
> +	default:
> +		goto free;
> +	}
> +
> +	spin_lock_bh(&ar->debug.wmi_ctrl_path_stats_lock);
> +	if (!more) {
> +		if (!ar->debug.wmi_ctrl_path_stats_more_enabled)
> +			ath12k_wmi_ctrl_path_stats_list_free(stats);
> +		else
> +			ar->debug.wmi_ctrl_path_stats_more_enabled = false;
> +
> +		list_splice_tail_init(src, dst);
> +		complete(&ar->debug.wmi_ctrl_path_stats_rcvd);
> +	} else {
> +		if (!ar->debug.wmi_ctrl_path_stats_more_enabled) {
> +			ath12k_wmi_ctrl_path_stats_list_free(stats);
> +			ar->debug.wmi_ctrl_path_stats_more_enabled = true;
> +		}
> +		list_splice_tail_init(src, dst);
> +	}
> +	spin_unlock_bh(&ar->debug.wmi_ctrl_path_stats_lock);
> +	return;
> +free:
> +	spin_lock_bh(&ar->debug.wmi_ctrl_path_stats_lock);
> +	ath12k_wmi_ctrl_path_stats_list_free(&param);
> +	spin_unlock_bh(&ar->debug.wmi_ctrl_path_stats_lock);
> +}
> +#else
> +static void ath12k_wmi_ctrl_path_stats_event(struct ath12k_base *ab,
> +					     struct sk_buff *skb)
> +{
> +}
> +#endif /* CONFIG_ATH12K_DEBUGFS */
> +
>  static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
>  {
>  	struct wmi_cmd_hdr *cmd_hdr;
> @@ -7149,6 +7376,10 @@ static void ath12k_wmi_op_rx(struct ath12k_base *ab, struct sk_buff *skb)
>  	case WMI_DIAG_EVENTID:
>  		ath12k_wmi_diag_event(ab, skb);
>  		break;
> +	case WMI_CTRL_PATH_STATS_EVENTID:
> +		ath12k_wmi_ctrl_path_stats_event(ab, skb);
> +		break;
> +
>  	/* TODO: Add remaining events */
>  	default:
>  		ath12k_dbg(ab, ATH12K_DBG_WMI, "Unknown eventid: 0x%x\n", id);
> @@ -7284,6 +7515,95 @@ int ath12k_wmi_simulate_radar(struct ath12k *ar)
>  	return ath12k_wmi_send_unit_test_cmd(ar, wmi_ut, dfs_args);
>  }
>  
> +#ifdef CONFIG_ATH12K_DEBUGFS
> +int
> +ath12k_wmi_send_wmi_ctrl_stats_cmd(struct ath12k *ar,
> +				   struct wmi_ctrl_path_stats_arg *arg)
> +{
> +	struct wmi_ctrl_path_stats_cmd *cmd;
> +	struct ath12k_wmi_pdev *wmi = ar->wmi;
> +	struct ath12k_base *ab = wmi->wmi_ab->ab;
> +	struct ath12k_debug *debug = &ar->debug;
> +	__le32 pdev_id;
> +	struct wmi_tlv *tlv;
> +	struct sk_buff *skb;
> +	int len, ret;
> +	void *ptr;
> +	u32 stats_id;
> +
> +	if (ab->hw_params->single_pdev_only)
> +		pdev_id = cpu_to_le32(ath12k_mac_get_target_pdev_id(ar));
> +	else
> +		pdev_id = cpu_to_le32(ar->pdev->pdev_id);
> +	stats_id = (1 << arg->stats_id);
> +
> +	len = sizeof(*cmd) +
> +		TLV_HDR_SIZE + sizeof(u32) +
> +		TLV_HDR_SIZE + TLV_HDR_SIZE;
> +
> +	skb = ath12k_wmi_alloc_skb(wmi->wmi_ab, len);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	cmd = (void *)skb->data;
> +	cmd->tlv_header = ath12k_wmi_tlv_cmd_hdr(WMI_TAG_CTRL_PATH_STATS_CMD_FIXED_PARAM,
> +						 sizeof(*cmd));
> +	cmd->stats_id = cpu_to_le32(stats_id);
> +	cmd->req_id = cpu_to_le32(arg->req_id);
> +	cmd->action = cpu_to_le32(arg->action);
> +
> +	ptr = skb->data + sizeof(*cmd);
> +
> +	/* The below TLV arrays optionally follow this fixed param TLV structure
> +	 * 1. ARRAY_UINT32 pdev_ids[]
> +	 *	If this array is present and non-zero length, stats should only
> +	 *	be provided from the pdevs identified in the array.
> +	 * 2. ARRAY_UNIT32 vdev_ids[]
> +	 *	If this array is present and non-zero length, stats should only
> +	 *	be provided from the vdevs identified in the array.
> +	 * 3. ath12k_wmi_mac_addr_params peer_macaddr[];
> +	 *	If this array is present and non-zero length, stats should only
> +	 *	be provided from the peers with the MAC addresses specified
> +	 *	in the array
> +	 */
> +
> +	tlv = ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, sizeof(u32));
> +	ptr += TLV_HDR_SIZE;
> +	memcpy(ptr, &pdev_id, sizeof(u32));
> +	ptr += sizeof(u32);
> +
> +	tlv = ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, 0);
> +	ptr += TLV_HDR_SIZE;
> +
> +	tlv = ptr;
> +	tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_FIXED_STRUCT, 0);
> +	ptr += TLV_HDR_SIZE;
> +
> +	if (arg->action == WMI_REQUEST_CTRL_PATH_STAT_GET)
> +		reinit_completion(&ar->debug.wmi_ctrl_path_stats_rcvd);
> +
> +	ret = ath12k_wmi_cmd_send(wmi, skb,
> +				  WMI_REQUEST_CTRL_PATH_STATS_CMDID);
> +	if (ret) {
> +		dev_kfree_skb(skb);
> +		ath12k_warn(ab, "Failed to send WMI_REQUEST_CTRL_PATH_STATS_CMDID: %d",
> +			    ret);
> +	} else {
> +		if (arg->action == WMI_REQUEST_CTRL_PATH_STAT_GET) {
> +			if (!wait_for_completion_timeout(&debug->wmi_ctrl_path_stats_rcvd,
> +							 WMI_CTRL_STATS_READY_TIMEOUT)) {
> +				ath12k_warn(ab, "wmi ctrl path stats timed out\n");
> +				ret = -ETIMEDOUT;
> +			}
> +		}
> +	}
> +
> +	return ret;
> +}
> +#endif
> +
>  int ath12k_wmi_connect(struct ath12k_base *ab)
>  {
>  	u32 i;
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index c2b86e187a03..6ecd6c326912 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -514,6 +514,8 @@ enum wmi_tlv_cmd_id {
>  	WMI_REQUEST_RCPI_CMDID,
>  	WMI_REQUEST_PEER_STATS_INFO_CMDID,
>  	WMI_REQUEST_RADIO_CHAN_STATS_CMDID,
> +	WMI_REQUEST_WLM_STATS_CMDID,
> +	WMI_REQUEST_CTRL_PATH_STATS_CMDID,
>  	WMI_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_GRP_ARP_NS_OFL),
>  	WMI_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID,
>  	WMI_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID,
> @@ -776,6 +778,8 @@ enum wmi_tlv_event_id {
>  	WMI_UPDATE_RCPI_EVENTID,
>  	WMI_PEER_STATS_INFO_EVENTID,
>  	WMI_RADIO_CHAN_STATS_EVENTID,
> +	WMI_WLM_STATS_EVENTID,
> +	WMI_CTRL_PATH_STATS_EVENTID,
>  	WMI_NLO_MATCH_EVENTID = WMI_TLV_CMD(WMI_GRP_NLO_OFL),
>  	WMI_NLO_SCAN_COMPLETE_EVENTID,
>  	WMI_APFIND_EVENTID,
> @@ -1925,6 +1929,9 @@ enum wmi_tlv_tag {
>  	WMI_TAG_SERVICE_READY_EXT2_EVENT = 0x334,
>  	WMI_TAG_FILS_DISCOVERY_TMPL_CMD = 0x344,
>  	WMI_TAG_MAC_PHY_CAPABILITIES_EXT = 0x36F,
> +	WMI_TAG_CTRL_PATH_STATS_CMD_FIXED_PARAM = 0x388,
> +	WMI_TAG_CTRL_PATH_STATS_EV_FIXED_PARAM,
> +	WMI_TAG_CTRL_PATH_PDEV_STATS,
>  	WMI_TAG_REGULATORY_RULE_EXT_STRUCT = 0x3A9,
>  	WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT,
>  	WMI_TAG_EHT_RATE_SET = 0x3C4,
> @@ -2154,6 +2161,7 @@ enum wmi_tlv_service {
>  	WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213,
>  	WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
>  	WMI_TLV_SERVICE_EXT2_MSG = 220,
> +	WMI_TLV_SERVICE_CTRL_PATH_STATS_REQUEST = 250,
>  	WMI_TLV_SERVICE_MBSS_PARAM_IN_VDEV_START_SUPPORT = 253,
>  
>  	WMI_MAX_EXT_SERVICE = 256,
> @@ -4902,6 +4910,82 @@ struct wmi_twt_disable_event {
>  	__le32 status;
>  } __packed;
>  
> +#define WMI_CTRL_STATS_READY_TIMEOUT		(1 * HZ)
> +
> +enum  wmi_ctrl_path_stats_id {
> +	/* bit 0 is currently unused / reserved */
> +	WMI_REQ_CTRL_PATH_PDEV_TX_STAT		= 1,
> +};
> +
> +enum wmi_ctrl_path_stats_action {
> +	WMI_REQUEST_CTRL_PATH_STAT_GET		= 1,
> +	WMI_REQUEST_CTRL_PATH_STAT_RESET	= 2,
> +	WMI_REQUEST_CTRL_PATH_STAT_START	= 3,
> +	WMI_REQUEST_CTRL_PATH_STAT_STOP		= 4,
> +};
> +
> +struct  wmi_ctrl_path_stats_cmd {
> +	__le32 tlv_header;
> +	__le32 stats_id;
> +	__le32 req_id;
> +	/* get/reset/start/stop based on stats id is defined as
> +	 * a part of wmi_ctrl_path_stats_action
> +	 */
> +	__le32 action;
> +} __packed;
> +
> +struct wmi_ctrl_path_stats_arg {
> +	u32 stats_id;
> +	u32 req_id;
> +	u32 action;
> +};
> +
> +struct wmi_ctrl_path_stats_event {
> +	__le32 req_id;
> +	/* more flag
> +	 * 1 - More events sent after this event.
> +	 * 0 - no more events after this event.
> +	 */
> +	__le32 more;
> +};
> +
> +/* WMI arrays of length WMI_MGMT_FRAME_SUBTYPE_MAX use the
> + * IEEE802.11 standard's enumeration of mgmt frame subtypes:
> + */
> +#define IEEE80211_MGMT_FRAME_SUBTYPE_MAX	16
> +#define WMI_MAX_STRING_LEN			256
> +
> +struct wmi_ctrl_path_pdev_stats_params {
> +	__le32 pdev_id;
> +	__le32 tx_mgmt_subtype[IEEE80211_MGMT_FRAME_SUBTYPE_MAX];
> +	__le32 rx_mgmt_subtype[IEEE80211_MGMT_FRAME_SUBTYPE_MAX];
> +	__le32 scan_fail_dfs_viol_time_ms;
> +	__le32 nol_chk_fail_last_chan_freq;
> +	__le32 nol_chk_fail_time_stamp_ms;
> +	__le32 tot_peer_create_cnt;
> +	__le32 tot_peer_del_cnt;
> +	__le32 tot_peer_del_resp_cnt;
> +	__le32 sched_algo_fifo_full_cnt;
> +} __packed;
> +
> +struct ath12k_wmi_ctrl_path_stats_list {
> +	struct list_head pdev_stats;
> +	struct ath12k *ar;
> +};
> +
> +struct wmi_ctrl_path_pdev_stats {
> +	struct list_head list;
> +	u32 tx_mgmt_subtype[IEEE80211_MGMT_FRAME_SUBTYPE_MAX];
> +	u32 rx_mgmt_subtype[IEEE80211_MGMT_FRAME_SUBTYPE_MAX];
> +	u32 scan_fail_dfs_viol_time_ms;
> +	u32 nol_chk_fail_last_chan_freq;
> +	u32 nol_chk_fail_time_stamp_ms;
> +	u32 tot_peer_create_cnt;
> +	u32 tot_peer_del_cnt;
> +	u32 tot_peer_del_resp_cnt;
> +	u32 sched_algo_fifo_full_cnt;
> +};
> +
>  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,
> @@ -5027,6 +5111,8 @@ int ath12k_wmi_set_bios_cmd(struct ath12k_base *ab, u32 param_id,
>  			    const u8 *buf, size_t buf_len);
>  int ath12k_wmi_set_bios_sar_cmd(struct ath12k_base *ab, const u8 *psar_table);
>  int ath12k_wmi_set_bios_geo_cmd(struct ath12k_base *ab, const u8 *pgeo_table);
> +int ath12k_wmi_send_wmi_ctrl_stats_cmd(struct ath12k *ar,
> +				       struct wmi_ctrl_path_stats_arg *arg);
>  
>  static inline u32
>  ath12k_wmi_caps_ext_get_pdev_id(const struct ath12k_wmi_caps_ext_params *param)

Please drop this patch. I'll send a re-based version




[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Wireless Regulations]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux