xref: /openbmc/linux/drivers/net/wireless/ath/ath11k/debugfs.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
1da3a9d3cSKalle Valo // SPDX-License-Identifier: BSD-3-Clause-Clear
2da3a9d3cSKalle Valo /*
3da3a9d3cSKalle Valo  * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.
4*586c7fb1SJeff Johnson  * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
5da3a9d3cSKalle Valo  */
6da3a9d3cSKalle Valo 
715fcb103SJakub Kicinski #include <linux/vmalloc.h>
815fcb103SJakub Kicinski 
9da3a9d3cSKalle Valo #include "debugfs.h"
10da3a9d3cSKalle Valo 
11da3a9d3cSKalle Valo #include "core.h"
12da3a9d3cSKalle Valo #include "debug.h"
13da3a9d3cSKalle Valo #include "wmi.h"
14da3a9d3cSKalle Valo #include "hal_rx.h"
15da3a9d3cSKalle Valo #include "dp_tx.h"
1656292162SKalle Valo #include "debugfs_htt_stats.h"
17da3a9d3cSKalle Valo #include "peer.h"
18876eb848SBaochen Qiang #include "hif.h"
19da3a9d3cSKalle Valo 
20da3a9d3cSKalle Valo static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
21da3a9d3cSKalle Valo 	"REO2SW1_RING",
22da3a9d3cSKalle Valo 	"REO2SW2_RING",
23da3a9d3cSKalle Valo 	"REO2SW3_RING",
24da3a9d3cSKalle Valo 	"REO2SW4_RING",
25da3a9d3cSKalle Valo 	"WBM2REO_LINK_RING",
26da3a9d3cSKalle Valo 	"REO2TCL_RING",
27da3a9d3cSKalle Valo 	"REO2FW_RING",
28da3a9d3cSKalle Valo 	"RELEASE_RING",
29da3a9d3cSKalle Valo 	"PPE_RELEASE_RING",
30da3a9d3cSKalle Valo 	"TCL2TQM_RING",
31da3a9d3cSKalle Valo 	"TQM_RELEASE_RING",
32da3a9d3cSKalle Valo 	"REO_RELEASE_RING",
33da3a9d3cSKalle Valo 	"WBM2SW0_RELEASE_RING",
34da3a9d3cSKalle Valo 	"WBM2SW1_RELEASE_RING",
35da3a9d3cSKalle Valo 	"WBM2SW2_RELEASE_RING",
36da3a9d3cSKalle Valo 	"WBM2SW3_RELEASE_RING",
37da3a9d3cSKalle Valo 	"REO_CMD_RING",
38da3a9d3cSKalle Valo 	"REO_STATUS_RING",
39da3a9d3cSKalle Valo };
40da3a9d3cSKalle Valo 
41da3a9d3cSKalle Valo static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {
42da3a9d3cSKalle Valo 	"FW2RXDMA_BUF_RING",
43da3a9d3cSKalle Valo 	"FW2RXDMA_STATUS_RING",
44da3a9d3cSKalle Valo 	"FW2RXDMA_LINK_RING",
45da3a9d3cSKalle Valo 	"SW2RXDMA_BUF_RING",
46da3a9d3cSKalle Valo 	"WBM2RXDMA_LINK_RING",
47da3a9d3cSKalle Valo 	"RXDMA2FW_RING",
48da3a9d3cSKalle Valo 	"RXDMA2SW_RING",
49da3a9d3cSKalle Valo 	"RXDMA2RELEASE_RING",
50da3a9d3cSKalle Valo 	"RXDMA2REO_RING",
51da3a9d3cSKalle Valo 	"MONITOR_STATUS_RING",
52da3a9d3cSKalle Valo 	"MONITOR_BUF_RING",
53da3a9d3cSKalle Valo 	"MONITOR_DESC_RING",
54da3a9d3cSKalle Valo 	"MONITOR_DEST_RING",
55da3a9d3cSKalle Valo };
56da3a9d3cSKalle Valo 
ath11k_debugfs_add_dbring_entry(struct ath11k * ar,enum wmi_direct_buffer_module id,enum ath11k_dbg_dbr_event event,struct hal_srng * srng)57691425b4SVenkateswara Naralasetty void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,
58691425b4SVenkateswara Naralasetty 				     enum wmi_direct_buffer_module id,
59691425b4SVenkateswara Naralasetty 				     enum ath11k_dbg_dbr_event event,
60691425b4SVenkateswara Naralasetty 				     struct hal_srng *srng)
61691425b4SVenkateswara Naralasetty {
62691425b4SVenkateswara Naralasetty 	struct ath11k_debug_dbr *dbr_debug;
63691425b4SVenkateswara Naralasetty 	struct ath11k_dbg_dbr_data *dbr_data;
64691425b4SVenkateswara Naralasetty 	struct ath11k_dbg_dbr_entry *entry;
65691425b4SVenkateswara Naralasetty 
66691425b4SVenkateswara Naralasetty 	if (id >= WMI_DIRECT_BUF_MAX || event >= ATH11K_DBG_DBR_EVENT_MAX)
67691425b4SVenkateswara Naralasetty 		return;
68691425b4SVenkateswara Naralasetty 
69691425b4SVenkateswara Naralasetty 	dbr_debug = ar->debug.dbr_debug[id];
70691425b4SVenkateswara Naralasetty 	if (!dbr_debug)
71691425b4SVenkateswara Naralasetty 		return;
72691425b4SVenkateswara Naralasetty 
73691425b4SVenkateswara Naralasetty 	if (!dbr_debug->dbr_debug_enabled)
74691425b4SVenkateswara Naralasetty 		return;
75691425b4SVenkateswara Naralasetty 
76691425b4SVenkateswara Naralasetty 	dbr_data = &dbr_debug->dbr_dbg_data;
77691425b4SVenkateswara Naralasetty 
78691425b4SVenkateswara Naralasetty 	spin_lock_bh(&dbr_data->lock);
79691425b4SVenkateswara Naralasetty 
80691425b4SVenkateswara Naralasetty 	if (dbr_data->entries) {
81691425b4SVenkateswara Naralasetty 		entry = &dbr_data->entries[dbr_data->dbr_debug_idx];
82691425b4SVenkateswara Naralasetty 		entry->hp = srng->u.src_ring.hp;
83691425b4SVenkateswara Naralasetty 		entry->tp = *srng->u.src_ring.tp_addr;
84691425b4SVenkateswara Naralasetty 		entry->timestamp = jiffies;
85691425b4SVenkateswara Naralasetty 		entry->event = event;
86691425b4SVenkateswara Naralasetty 
87691425b4SVenkateswara Naralasetty 		dbr_data->dbr_debug_idx++;
88691425b4SVenkateswara Naralasetty 		if (dbr_data->dbr_debug_idx ==
89691425b4SVenkateswara Naralasetty 		    dbr_data->num_ring_debug_entries)
90691425b4SVenkateswara Naralasetty 			dbr_data->dbr_debug_idx = 0;
91691425b4SVenkateswara Naralasetty 	}
92691425b4SVenkateswara Naralasetty 
93691425b4SVenkateswara Naralasetty 	spin_unlock_bh(&dbr_data->lock);
94691425b4SVenkateswara Naralasetty }
95691425b4SVenkateswara Naralasetty 
ath11k_debugfs_fw_stats_reset(struct ath11k * ar)96cb4e57dbSKalle Valo static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar)
97da3a9d3cSKalle Valo {
98da3a9d3cSKalle Valo 	spin_lock_bh(&ar->data_lock);
99ec8918f9SAditya Kumar Singh 	ar->fw_stats_done = false;
100ec8918f9SAditya Kumar Singh 	ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);
101ec8918f9SAditya Kumar Singh 	ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);
102da3a9d3cSKalle Valo 	spin_unlock_bh(&ar->data_lock);
103da3a9d3cSKalle Valo }
104da3a9d3cSKalle Valo 
ath11k_debugfs_fw_stats_process(struct ath11k * ar,struct ath11k_fw_stats * stats)105ec8918f9SAditya Kumar Singh void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats)
106da3a9d3cSKalle Valo {
107ec8918f9SAditya Kumar Singh 	struct ath11k_base *ab = ar->ab;
108da3a9d3cSKalle Valo 	struct ath11k_pdev *pdev;
109da3a9d3cSKalle Valo 	bool is_end;
110da3a9d3cSKalle Valo 	static unsigned int num_vdev, num_bcn;
111da3a9d3cSKalle Valo 	size_t total_vdevs_started = 0;
112ec8918f9SAditya Kumar Singh 	int i;
113da3a9d3cSKalle Valo 
114ec8918f9SAditya Kumar Singh 	/* WMI_REQUEST_PDEV_STAT request has been already processed */
115da3a9d3cSKalle Valo 
116ec8918f9SAditya Kumar Singh 	if (stats->stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {
117ec8918f9SAditya Kumar Singh 		ar->fw_stats_done = true;
118ec8918f9SAditya Kumar Singh 		return;
119da3a9d3cSKalle Valo 	}
120da3a9d3cSKalle Valo 
121ec8918f9SAditya Kumar Singh 	if (stats->stats_id == WMI_REQUEST_VDEV_STAT) {
122ec8918f9SAditya Kumar Singh 		if (list_empty(&stats->vdevs)) {
123da3a9d3cSKalle Valo 			ath11k_warn(ab, "empty vdev stats");
124ec8918f9SAditya Kumar Singh 			return;
125da3a9d3cSKalle Valo 		}
126da3a9d3cSKalle Valo 		/* FW sends all the active VDEV stats irrespective of PDEV,
127da3a9d3cSKalle Valo 		 * hence limit until the count of all VDEVs started
128da3a9d3cSKalle Valo 		 */
129da3a9d3cSKalle Valo 		for (i = 0; i < ab->num_radios; i++) {
130da3a9d3cSKalle Valo 			pdev = rcu_dereference(ab->pdevs_active[i]);
131da3a9d3cSKalle Valo 			if (pdev && pdev->ar)
132da3a9d3cSKalle Valo 				total_vdevs_started += ar->num_started_vdevs;
133da3a9d3cSKalle Valo 		}
134da3a9d3cSKalle Valo 
135da3a9d3cSKalle Valo 		is_end = ((++num_vdev) == total_vdevs_started);
136da3a9d3cSKalle Valo 
137ec8918f9SAditya Kumar Singh 		list_splice_tail_init(&stats->vdevs,
138ec8918f9SAditya Kumar Singh 				      &ar->fw_stats.vdevs);
139da3a9d3cSKalle Valo 
140da3a9d3cSKalle Valo 		if (is_end) {
141ec8918f9SAditya Kumar Singh 			ar->fw_stats_done = true;
142da3a9d3cSKalle Valo 			num_vdev = 0;
143da3a9d3cSKalle Valo 		}
144ec8918f9SAditya Kumar Singh 		return;
145da3a9d3cSKalle Valo 	}
146da3a9d3cSKalle Valo 
147ec8918f9SAditya Kumar Singh 	if (stats->stats_id == WMI_REQUEST_BCN_STAT) {
148ec8918f9SAditya Kumar Singh 		if (list_empty(&stats->bcn)) {
149da3a9d3cSKalle Valo 			ath11k_warn(ab, "empty bcn stats");
150ec8918f9SAditya Kumar Singh 			return;
151da3a9d3cSKalle Valo 		}
152da3a9d3cSKalle Valo 		/* Mark end until we reached the count of all started VDEVs
153da3a9d3cSKalle Valo 		 * within the PDEV
154da3a9d3cSKalle Valo 		 */
155da3a9d3cSKalle Valo 		is_end = ((++num_bcn) == ar->num_started_vdevs);
156da3a9d3cSKalle Valo 
157ec8918f9SAditya Kumar Singh 		list_splice_tail_init(&stats->bcn,
158ec8918f9SAditya Kumar Singh 				      &ar->fw_stats.bcn);
159da3a9d3cSKalle Valo 
160da3a9d3cSKalle Valo 		if (is_end) {
161ec8918f9SAditya Kumar Singh 			ar->fw_stats_done = true;
162da3a9d3cSKalle Valo 			num_bcn = 0;
163da3a9d3cSKalle Valo 		}
164da3a9d3cSKalle Valo 	}
165da3a9d3cSKalle Valo }
166da3a9d3cSKalle Valo 
ath11k_debugfs_fw_stats_request(struct ath11k * ar,struct stats_request_params * req_param)167cb4e57dbSKalle Valo static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,
168da3a9d3cSKalle Valo 					   struct stats_request_params *req_param)
169da3a9d3cSKalle Valo {
170da3a9d3cSKalle Valo 	struct ath11k_base *ab = ar->ab;
171da3a9d3cSKalle Valo 	unsigned long timeout, time_left;
172da3a9d3cSKalle Valo 	int ret;
173da3a9d3cSKalle Valo 
174da3a9d3cSKalle Valo 	lockdep_assert_held(&ar->conf_mutex);
175da3a9d3cSKalle Valo 
176da3a9d3cSKalle Valo 	/* FW stats can get split when exceeding the stats data buffer limit.
177da3a9d3cSKalle Valo 	 * In that case, since there is no end marking for the back-to-back
178da3a9d3cSKalle Valo 	 * received 'update stats' event, we keep a 3 seconds timeout in case,
179da3a9d3cSKalle Valo 	 * fw_stats_done is not marked yet
180da3a9d3cSKalle Valo 	 */
181c8f2d41bSWen Gong 	timeout = jiffies + msecs_to_jiffies(3 * 1000);
182da3a9d3cSKalle Valo 
183cb4e57dbSKalle Valo 	ath11k_debugfs_fw_stats_reset(ar);
184da3a9d3cSKalle Valo 
185ec8918f9SAditya Kumar Singh 	reinit_completion(&ar->fw_stats_complete);
186da3a9d3cSKalle Valo 
187da3a9d3cSKalle Valo 	ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);
188da3a9d3cSKalle Valo 
189da3a9d3cSKalle Valo 	if (ret) {
190da3a9d3cSKalle Valo 		ath11k_warn(ab, "could not request fw stats (%d)\n",
191da3a9d3cSKalle Valo 			    ret);
192da3a9d3cSKalle Valo 		return ret;
193da3a9d3cSKalle Valo 	}
194da3a9d3cSKalle Valo 
195ec8918f9SAditya Kumar Singh 	time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ);
196ec8918f9SAditya Kumar Singh 
197da3a9d3cSKalle Valo 	if (!time_left)
198da3a9d3cSKalle Valo 		return -ETIMEDOUT;
199da3a9d3cSKalle Valo 
200da3a9d3cSKalle Valo 	for (;;) {
201da3a9d3cSKalle Valo 		if (time_after(jiffies, timeout))
202da3a9d3cSKalle Valo 			break;
203da3a9d3cSKalle Valo 
204da3a9d3cSKalle Valo 		spin_lock_bh(&ar->data_lock);
205ec8918f9SAditya Kumar Singh 		if (ar->fw_stats_done) {
206da3a9d3cSKalle Valo 			spin_unlock_bh(&ar->data_lock);
207da3a9d3cSKalle Valo 			break;
208da3a9d3cSKalle Valo 		}
209da3a9d3cSKalle Valo 		spin_unlock_bh(&ar->data_lock);
210da3a9d3cSKalle Valo 	}
211da3a9d3cSKalle Valo 	return 0;
212da3a9d3cSKalle Valo }
213da3a9d3cSKalle Valo 
ath11k_debugfs_get_fw_stats(struct ath11k * ar,u32 pdev_id,u32 vdev_id,u32 stats_id)214b488c766SWen Gong int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id,
215b488c766SWen Gong 				u32 vdev_id, u32 stats_id)
216b488c766SWen Gong {
217b488c766SWen Gong 	struct ath11k_base *ab = ar->ab;
218b488c766SWen Gong 	struct stats_request_params req_param;
219b488c766SWen Gong 	int ret;
220b488c766SWen Gong 
221b488c766SWen Gong 	mutex_lock(&ar->conf_mutex);
222b488c766SWen Gong 
223b488c766SWen Gong 	if (ar->state != ATH11K_STATE_ON) {
224b488c766SWen Gong 		ret = -ENETDOWN;
225b488c766SWen Gong 		goto err_unlock;
226b488c766SWen Gong 	}
227b488c766SWen Gong 
228b488c766SWen Gong 	req_param.pdev_id = pdev_id;
229b488c766SWen Gong 	req_param.vdev_id = vdev_id;
230b488c766SWen Gong 	req_param.stats_id = stats_id;
231b488c766SWen Gong 
232b488c766SWen Gong 	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
233b488c766SWen Gong 	if (ret)
234b488c766SWen Gong 		ath11k_warn(ab, "failed to request fw stats: %d\n", ret);
235b488c766SWen Gong 
236b488c766SWen Gong 	ath11k_dbg(ab, ATH11K_DBG_WMI,
237b488c766SWen Gong 		   "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n",
238b488c766SWen Gong 		   pdev_id, vdev_id, stats_id);
239b488c766SWen Gong 
240b488c766SWen Gong err_unlock:
241b488c766SWen Gong 	mutex_unlock(&ar->conf_mutex);
242b488c766SWen Gong 
243b488c766SWen Gong 	return ret;
244b488c766SWen Gong }
245b488c766SWen Gong 
ath11k_open_pdev_stats(struct inode * inode,struct file * file)246da3a9d3cSKalle Valo static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)
247da3a9d3cSKalle Valo {
248da3a9d3cSKalle Valo 	struct ath11k *ar = inode->i_private;
249da3a9d3cSKalle Valo 	struct ath11k_base *ab = ar->ab;
250da3a9d3cSKalle Valo 	struct stats_request_params req_param;
251da3a9d3cSKalle Valo 	void *buf = NULL;
252da3a9d3cSKalle Valo 	int ret;
253da3a9d3cSKalle Valo 
254da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
255da3a9d3cSKalle Valo 
256da3a9d3cSKalle Valo 	if (ar->state != ATH11K_STATE_ON) {
257da3a9d3cSKalle Valo 		ret = -ENETDOWN;
258da3a9d3cSKalle Valo 		goto err_unlock;
259da3a9d3cSKalle Valo 	}
260da3a9d3cSKalle Valo 
261da3a9d3cSKalle Valo 	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
262da3a9d3cSKalle Valo 	if (!buf) {
263da3a9d3cSKalle Valo 		ret = -ENOMEM;
264da3a9d3cSKalle Valo 		goto err_unlock;
265da3a9d3cSKalle Valo 	}
266da3a9d3cSKalle Valo 
267da3a9d3cSKalle Valo 	req_param.pdev_id = ar->pdev->pdev_id;
268da3a9d3cSKalle Valo 	req_param.vdev_id = 0;
269da3a9d3cSKalle Valo 	req_param.stats_id = WMI_REQUEST_PDEV_STAT;
270da3a9d3cSKalle Valo 
271cb4e57dbSKalle Valo 	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
272da3a9d3cSKalle Valo 	if (ret) {
273da3a9d3cSKalle Valo 		ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);
274da3a9d3cSKalle Valo 		goto err_free;
275da3a9d3cSKalle Valo 	}
276da3a9d3cSKalle Valo 
277ec8918f9SAditya Kumar Singh 	ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
278da3a9d3cSKalle Valo 
279da3a9d3cSKalle Valo 	file->private_data = buf;
280da3a9d3cSKalle Valo 
281da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
282da3a9d3cSKalle Valo 	return 0;
283da3a9d3cSKalle Valo 
284da3a9d3cSKalle Valo err_free:
285da3a9d3cSKalle Valo 	vfree(buf);
286da3a9d3cSKalle Valo 
287da3a9d3cSKalle Valo err_unlock:
288da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
289da3a9d3cSKalle Valo 	return ret;
290da3a9d3cSKalle Valo }
291da3a9d3cSKalle Valo 
ath11k_release_pdev_stats(struct inode * inode,struct file * file)292da3a9d3cSKalle Valo static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)
293da3a9d3cSKalle Valo {
294da3a9d3cSKalle Valo 	vfree(file->private_data);
295da3a9d3cSKalle Valo 
296da3a9d3cSKalle Valo 	return 0;
297da3a9d3cSKalle Valo }
298da3a9d3cSKalle Valo 
ath11k_read_pdev_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)299da3a9d3cSKalle Valo static ssize_t ath11k_read_pdev_stats(struct file *file,
300da3a9d3cSKalle Valo 				      char __user *user_buf,
301da3a9d3cSKalle Valo 				      size_t count, loff_t *ppos)
302da3a9d3cSKalle Valo {
303da3a9d3cSKalle Valo 	const char *buf = file->private_data;
304da3a9d3cSKalle Valo 	size_t len = strlen(buf);
305da3a9d3cSKalle Valo 
306da3a9d3cSKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
307da3a9d3cSKalle Valo }
308da3a9d3cSKalle Valo 
309da3a9d3cSKalle Valo static const struct file_operations fops_pdev_stats = {
310da3a9d3cSKalle Valo 	.open = ath11k_open_pdev_stats,
311da3a9d3cSKalle Valo 	.release = ath11k_release_pdev_stats,
312da3a9d3cSKalle Valo 	.read = ath11k_read_pdev_stats,
313da3a9d3cSKalle Valo 	.owner = THIS_MODULE,
314da3a9d3cSKalle Valo 	.llseek = default_llseek,
315da3a9d3cSKalle Valo };
316da3a9d3cSKalle Valo 
ath11k_open_vdev_stats(struct inode * inode,struct file * file)317da3a9d3cSKalle Valo static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)
318da3a9d3cSKalle Valo {
319da3a9d3cSKalle Valo 	struct ath11k *ar = inode->i_private;
320da3a9d3cSKalle Valo 	struct stats_request_params req_param;
321da3a9d3cSKalle Valo 	void *buf = NULL;
322da3a9d3cSKalle Valo 	int ret;
323da3a9d3cSKalle Valo 
324da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
325da3a9d3cSKalle Valo 
326da3a9d3cSKalle Valo 	if (ar->state != ATH11K_STATE_ON) {
327da3a9d3cSKalle Valo 		ret = -ENETDOWN;
328da3a9d3cSKalle Valo 		goto err_unlock;
329da3a9d3cSKalle Valo 	}
330da3a9d3cSKalle Valo 
331da3a9d3cSKalle Valo 	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
332da3a9d3cSKalle Valo 	if (!buf) {
333da3a9d3cSKalle Valo 		ret = -ENOMEM;
334da3a9d3cSKalle Valo 		goto err_unlock;
335da3a9d3cSKalle Valo 	}
336da3a9d3cSKalle Valo 
337da3a9d3cSKalle Valo 	req_param.pdev_id = ar->pdev->pdev_id;
338da3a9d3cSKalle Valo 	/* VDEV stats is always sent for all active VDEVs from FW */
339da3a9d3cSKalle Valo 	req_param.vdev_id = 0;
340da3a9d3cSKalle Valo 	req_param.stats_id = WMI_REQUEST_VDEV_STAT;
341da3a9d3cSKalle Valo 
342cb4e57dbSKalle Valo 	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
343da3a9d3cSKalle Valo 	if (ret) {
344da3a9d3cSKalle Valo 		ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);
345da3a9d3cSKalle Valo 		goto err_free;
346da3a9d3cSKalle Valo 	}
347da3a9d3cSKalle Valo 
348ec8918f9SAditya Kumar Singh 	ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
349da3a9d3cSKalle Valo 
350da3a9d3cSKalle Valo 	file->private_data = buf;
351da3a9d3cSKalle Valo 
352da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
353da3a9d3cSKalle Valo 	return 0;
354da3a9d3cSKalle Valo 
355da3a9d3cSKalle Valo err_free:
356da3a9d3cSKalle Valo 	vfree(buf);
357da3a9d3cSKalle Valo 
358da3a9d3cSKalle Valo err_unlock:
359da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
360da3a9d3cSKalle Valo 	return ret;
361da3a9d3cSKalle Valo }
362da3a9d3cSKalle Valo 
ath11k_release_vdev_stats(struct inode * inode,struct file * file)363da3a9d3cSKalle Valo static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)
364da3a9d3cSKalle Valo {
365da3a9d3cSKalle Valo 	vfree(file->private_data);
366da3a9d3cSKalle Valo 
367da3a9d3cSKalle Valo 	return 0;
368da3a9d3cSKalle Valo }
369da3a9d3cSKalle Valo 
ath11k_read_vdev_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)370da3a9d3cSKalle Valo static ssize_t ath11k_read_vdev_stats(struct file *file,
371da3a9d3cSKalle Valo 				      char __user *user_buf,
372da3a9d3cSKalle Valo 				      size_t count, loff_t *ppos)
373da3a9d3cSKalle Valo {
374da3a9d3cSKalle Valo 	const char *buf = file->private_data;
375da3a9d3cSKalle Valo 	size_t len = strlen(buf);
376da3a9d3cSKalle Valo 
377da3a9d3cSKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
378da3a9d3cSKalle Valo }
379da3a9d3cSKalle Valo 
380da3a9d3cSKalle Valo static const struct file_operations fops_vdev_stats = {
381da3a9d3cSKalle Valo 	.open = ath11k_open_vdev_stats,
382da3a9d3cSKalle Valo 	.release = ath11k_release_vdev_stats,
383da3a9d3cSKalle Valo 	.read = ath11k_read_vdev_stats,
384da3a9d3cSKalle Valo 	.owner = THIS_MODULE,
385da3a9d3cSKalle Valo 	.llseek = default_llseek,
386da3a9d3cSKalle Valo };
387da3a9d3cSKalle Valo 
ath11k_open_bcn_stats(struct inode * inode,struct file * file)388da3a9d3cSKalle Valo static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)
389da3a9d3cSKalle Valo {
390da3a9d3cSKalle Valo 	struct ath11k *ar = inode->i_private;
391da3a9d3cSKalle Valo 	struct ath11k_vif *arvif;
392da3a9d3cSKalle Valo 	struct stats_request_params req_param;
393da3a9d3cSKalle Valo 	void *buf = NULL;
394da3a9d3cSKalle Valo 	int ret;
395da3a9d3cSKalle Valo 
396da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
397da3a9d3cSKalle Valo 
398da3a9d3cSKalle Valo 	if (ar->state != ATH11K_STATE_ON) {
399da3a9d3cSKalle Valo 		ret = -ENETDOWN;
400da3a9d3cSKalle Valo 		goto err_unlock;
401da3a9d3cSKalle Valo 	}
402da3a9d3cSKalle Valo 
403da3a9d3cSKalle Valo 	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);
404da3a9d3cSKalle Valo 	if (!buf) {
405da3a9d3cSKalle Valo 		ret = -ENOMEM;
406da3a9d3cSKalle Valo 		goto err_unlock;
407da3a9d3cSKalle Valo 	}
408da3a9d3cSKalle Valo 
409da3a9d3cSKalle Valo 	req_param.stats_id = WMI_REQUEST_BCN_STAT;
410da3a9d3cSKalle Valo 	req_param.pdev_id = ar->pdev->pdev_id;
411da3a9d3cSKalle Valo 
412da3a9d3cSKalle Valo 	/* loop all active VDEVs for bcn stats */
413da3a9d3cSKalle Valo 	list_for_each_entry(arvif, &ar->arvifs, list) {
414da3a9d3cSKalle Valo 		if (!arvif->is_up)
415da3a9d3cSKalle Valo 			continue;
416da3a9d3cSKalle Valo 
417da3a9d3cSKalle Valo 		req_param.vdev_id = arvif->vdev_id;
418cb4e57dbSKalle Valo 		ret = ath11k_debugfs_fw_stats_request(ar, &req_param);
419da3a9d3cSKalle Valo 		if (ret) {
420da3a9d3cSKalle Valo 			ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);
421da3a9d3cSKalle Valo 			goto err_free;
422da3a9d3cSKalle Valo 		}
423da3a9d3cSKalle Valo 	}
424da3a9d3cSKalle Valo 
425ec8918f9SAditya Kumar Singh 	ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);
426da3a9d3cSKalle Valo 
427da3a9d3cSKalle Valo 	/* since beacon stats request is looped for all active VDEVs, saved fw
428da3a9d3cSKalle Valo 	 * stats is not freed for each request until done for all active VDEVs
429da3a9d3cSKalle Valo 	 */
430da3a9d3cSKalle Valo 	spin_lock_bh(&ar->data_lock);
431ec8918f9SAditya Kumar Singh 	ath11k_fw_stats_bcn_free(&ar->fw_stats.bcn);
432da3a9d3cSKalle Valo 	spin_unlock_bh(&ar->data_lock);
433da3a9d3cSKalle Valo 
434da3a9d3cSKalle Valo 	file->private_data = buf;
435da3a9d3cSKalle Valo 
436da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
437da3a9d3cSKalle Valo 	return 0;
438da3a9d3cSKalle Valo 
439da3a9d3cSKalle Valo err_free:
440da3a9d3cSKalle Valo 	vfree(buf);
441da3a9d3cSKalle Valo 
442da3a9d3cSKalle Valo err_unlock:
443da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
444da3a9d3cSKalle Valo 	return ret;
445da3a9d3cSKalle Valo }
446da3a9d3cSKalle Valo 
ath11k_release_bcn_stats(struct inode * inode,struct file * file)447da3a9d3cSKalle Valo static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)
448da3a9d3cSKalle Valo {
449da3a9d3cSKalle Valo 	vfree(file->private_data);
450da3a9d3cSKalle Valo 
451da3a9d3cSKalle Valo 	return 0;
452da3a9d3cSKalle Valo }
453da3a9d3cSKalle Valo 
ath11k_read_bcn_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)454da3a9d3cSKalle Valo static ssize_t ath11k_read_bcn_stats(struct file *file,
455da3a9d3cSKalle Valo 				     char __user *user_buf,
456da3a9d3cSKalle Valo 				     size_t count, loff_t *ppos)
457da3a9d3cSKalle Valo {
458da3a9d3cSKalle Valo 	const char *buf = file->private_data;
459da3a9d3cSKalle Valo 	size_t len = strlen(buf);
460da3a9d3cSKalle Valo 
461da3a9d3cSKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
462da3a9d3cSKalle Valo }
463da3a9d3cSKalle Valo 
464da3a9d3cSKalle Valo static const struct file_operations fops_bcn_stats = {
465da3a9d3cSKalle Valo 	.open = ath11k_open_bcn_stats,
466da3a9d3cSKalle Valo 	.release = ath11k_release_bcn_stats,
467da3a9d3cSKalle Valo 	.read = ath11k_read_bcn_stats,
468da3a9d3cSKalle Valo 	.owner = THIS_MODULE,
469da3a9d3cSKalle Valo 	.llseek = default_llseek,
470da3a9d3cSKalle Valo };
471da3a9d3cSKalle Valo 
ath11k_read_simulate_fw_crash(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)472da3a9d3cSKalle Valo static ssize_t ath11k_read_simulate_fw_crash(struct file *file,
473da3a9d3cSKalle Valo 					     char __user *user_buf,
474da3a9d3cSKalle Valo 					     size_t count, loff_t *ppos)
475da3a9d3cSKalle Valo {
476da3a9d3cSKalle Valo 	const char buf[] =
477da3a9d3cSKalle Valo 		"To simulate firmware crash write one of the keywords to this file:\n"
478da3a9d3cSKalle Valo 		"`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"
479da3a9d3cSKalle Valo 		"`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";
480da3a9d3cSKalle Valo 
481da3a9d3cSKalle Valo 	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));
482da3a9d3cSKalle Valo }
483da3a9d3cSKalle Valo 
484da3a9d3cSKalle Valo /* Simulate firmware crash:
485da3a9d3cSKalle Valo  * 'soft': Call wmi command causing firmware hang. This firmware hang is
486da3a9d3cSKalle Valo  * recoverable by warm firmware reset.
487da3a9d3cSKalle Valo  * 'hard': Force firmware crash by setting any vdev parameter for not allowed
488da3a9d3cSKalle Valo  * vdev id. This is hard firmware crash because it is recoverable only by cold
489da3a9d3cSKalle Valo  * firmware reset.
490da3a9d3cSKalle Valo  */
ath11k_write_simulate_fw_crash(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)491da3a9d3cSKalle Valo static ssize_t ath11k_write_simulate_fw_crash(struct file *file,
492da3a9d3cSKalle Valo 					      const char __user *user_buf,
493da3a9d3cSKalle Valo 					      size_t count, loff_t *ppos)
494da3a9d3cSKalle Valo {
495da3a9d3cSKalle Valo 	struct ath11k_base *ab = file->private_data;
496da3a9d3cSKalle Valo 	struct ath11k_pdev *pdev;
497da3a9d3cSKalle Valo 	struct ath11k *ar = ab->pdevs[0].ar;
498da3a9d3cSKalle Valo 	char buf[32] = {0};
499da3a9d3cSKalle Valo 	ssize_t rc;
500da3a9d3cSKalle Valo 	int i, ret, radioup = 0;
501da3a9d3cSKalle Valo 
502da3a9d3cSKalle Valo 	for (i = 0; i < ab->num_radios; i++) {
503da3a9d3cSKalle Valo 		pdev = &ab->pdevs[i];
504da3a9d3cSKalle Valo 		ar = pdev->ar;
505da3a9d3cSKalle Valo 		if (ar && ar->state == ATH11K_STATE_ON) {
506da3a9d3cSKalle Valo 			radioup = 1;
507da3a9d3cSKalle Valo 			break;
508da3a9d3cSKalle Valo 		}
509da3a9d3cSKalle Valo 	}
510da3a9d3cSKalle Valo 	/* filter partial writes and invalid commands */
511da3a9d3cSKalle Valo 	if (*ppos != 0 || count >= sizeof(buf) || count == 0)
512da3a9d3cSKalle Valo 		return -EINVAL;
513da3a9d3cSKalle Valo 
514da3a9d3cSKalle Valo 	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
515da3a9d3cSKalle Valo 	if (rc < 0)
516da3a9d3cSKalle Valo 		return rc;
517da3a9d3cSKalle Valo 
518da3a9d3cSKalle Valo 	/* drop the possible '\n' from the end */
519da3a9d3cSKalle Valo 	if (buf[*ppos - 1] == '\n')
520da3a9d3cSKalle Valo 		buf[*ppos - 1] = '\0';
521da3a9d3cSKalle Valo 
522da3a9d3cSKalle Valo 	if (radioup == 0) {
523da3a9d3cSKalle Valo 		ret = -ENETDOWN;
524da3a9d3cSKalle Valo 		goto exit;
525da3a9d3cSKalle Valo 	}
526da3a9d3cSKalle Valo 
527da3a9d3cSKalle Valo 	if (!strcmp(buf, "assert")) {
528da3a9d3cSKalle Valo 		ath11k_info(ab, "simulating firmware assert crash\n");
529da3a9d3cSKalle Valo 		ret = ath11k_wmi_force_fw_hang_cmd(ar,
530da3a9d3cSKalle Valo 						   ATH11K_WMI_FW_HANG_ASSERT_TYPE,
531da3a9d3cSKalle Valo 						   ATH11K_WMI_FW_HANG_DELAY);
53278e3e609SWen Gong 	} else if (!strcmp(buf, "hw-restart")) {
53378e3e609SWen Gong 		ath11k_info(ab, "user requested hw restart\n");
53478e3e609SWen Gong 		queue_work(ab->workqueue_aux, &ab->reset_work);
53578e3e609SWen Gong 		ret = 0;
536da3a9d3cSKalle Valo 	} else {
537da3a9d3cSKalle Valo 		ret = -EINVAL;
538da3a9d3cSKalle Valo 		goto exit;
539da3a9d3cSKalle Valo 	}
540da3a9d3cSKalle Valo 
541da3a9d3cSKalle Valo 	if (ret) {
542da3a9d3cSKalle Valo 		ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);
543da3a9d3cSKalle Valo 		goto exit;
544da3a9d3cSKalle Valo 	}
545da3a9d3cSKalle Valo 
546da3a9d3cSKalle Valo 	ret = count;
547da3a9d3cSKalle Valo 
548da3a9d3cSKalle Valo exit:
549da3a9d3cSKalle Valo 	return ret;
550da3a9d3cSKalle Valo }
551da3a9d3cSKalle Valo 
552da3a9d3cSKalle Valo static const struct file_operations fops_simulate_fw_crash = {
553da3a9d3cSKalle Valo 	.read = ath11k_read_simulate_fw_crash,
554da3a9d3cSKalle Valo 	.write = ath11k_write_simulate_fw_crash,
555da3a9d3cSKalle Valo 	.open = simple_open,
556da3a9d3cSKalle Valo 	.owner = THIS_MODULE,
557da3a9d3cSKalle Valo 	.llseek = default_llseek,
558da3a9d3cSKalle Valo };
559da3a9d3cSKalle Valo 
ath11k_write_enable_extd_tx_stats(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)560da3a9d3cSKalle Valo static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,
561da3a9d3cSKalle Valo 						 const char __user *ubuf,
562da3a9d3cSKalle Valo 						 size_t count, loff_t *ppos)
563da3a9d3cSKalle Valo {
564da3a9d3cSKalle Valo 	struct ath11k *ar = file->private_data;
565da3a9d3cSKalle Valo 	u32 filter;
566da3a9d3cSKalle Valo 	int ret;
567da3a9d3cSKalle Valo 
568da3a9d3cSKalle Valo 	if (kstrtouint_from_user(ubuf, count, 0, &filter))
569da3a9d3cSKalle Valo 		return -EINVAL;
570da3a9d3cSKalle Valo 
571da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
572da3a9d3cSKalle Valo 
573da3a9d3cSKalle Valo 	if (ar->state != ATH11K_STATE_ON) {
574da3a9d3cSKalle Valo 		ret = -ENETDOWN;
575da3a9d3cSKalle Valo 		goto out;
576da3a9d3cSKalle Valo 	}
577da3a9d3cSKalle Valo 
578da3a9d3cSKalle Valo 	if (filter == ar->debug.extd_tx_stats) {
579da3a9d3cSKalle Valo 		ret = count;
580da3a9d3cSKalle Valo 		goto out;
581da3a9d3cSKalle Valo 	}
582da3a9d3cSKalle Valo 
583da3a9d3cSKalle Valo 	ar->debug.extd_tx_stats = filter;
584da3a9d3cSKalle Valo 	ret = count;
585da3a9d3cSKalle Valo 
586da3a9d3cSKalle Valo out:
587da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
588da3a9d3cSKalle Valo 	return ret;
589da3a9d3cSKalle Valo }
590da3a9d3cSKalle Valo 
ath11k_read_enable_extd_tx_stats(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)591da3a9d3cSKalle Valo static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,
592da3a9d3cSKalle Valo 						char __user *ubuf,
593da3a9d3cSKalle Valo 						size_t count, loff_t *ppos)
594da3a9d3cSKalle Valo 
595da3a9d3cSKalle Valo {
596da3a9d3cSKalle Valo 	char buf[32] = {0};
597da3a9d3cSKalle Valo 	struct ath11k *ar = file->private_data;
598da3a9d3cSKalle Valo 	int len = 0;
599da3a9d3cSKalle Valo 
600da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
601da3a9d3cSKalle Valo 	len = scnprintf(buf, sizeof(buf) - len, "%08x\n",
602da3a9d3cSKalle Valo 			ar->debug.extd_tx_stats);
603da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
604da3a9d3cSKalle Valo 
605da3a9d3cSKalle Valo 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
606da3a9d3cSKalle Valo }
607da3a9d3cSKalle Valo 
608da3a9d3cSKalle Valo static const struct file_operations fops_extd_tx_stats = {
609da3a9d3cSKalle Valo 	.read = ath11k_read_enable_extd_tx_stats,
610da3a9d3cSKalle Valo 	.write = ath11k_write_enable_extd_tx_stats,
611da3a9d3cSKalle Valo 	.open = simple_open
612da3a9d3cSKalle Valo };
613da3a9d3cSKalle Valo 
ath11k_write_extd_rx_stats(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)614da3a9d3cSKalle Valo static ssize_t ath11k_write_extd_rx_stats(struct file *file,
615da3a9d3cSKalle Valo 					  const char __user *ubuf,
616da3a9d3cSKalle Valo 					  size_t count, loff_t *ppos)
617da3a9d3cSKalle Valo {
618da3a9d3cSKalle Valo 	struct ath11k *ar = file->private_data;
619da3a9d3cSKalle Valo 	struct ath11k_base *ab = ar->ab;
620da3a9d3cSKalle Valo 	struct htt_rx_ring_tlv_filter tlv_filter = {0};
621da3a9d3cSKalle Valo 	u32 enable, rx_filter = 0, ring_id;
622da3a9d3cSKalle Valo 	int i;
623da3a9d3cSKalle Valo 	int ret;
624da3a9d3cSKalle Valo 
625da3a9d3cSKalle Valo 	if (kstrtouint_from_user(ubuf, count, 0, &enable))
626da3a9d3cSKalle Valo 		return -EINVAL;
627da3a9d3cSKalle Valo 
628da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
629da3a9d3cSKalle Valo 
630da3a9d3cSKalle Valo 	if (ar->state != ATH11K_STATE_ON) {
631da3a9d3cSKalle Valo 		ret = -ENETDOWN;
632da3a9d3cSKalle Valo 		goto exit;
633da3a9d3cSKalle Valo 	}
634da3a9d3cSKalle Valo 
635da3a9d3cSKalle Valo 	if (enable > 1) {
636da3a9d3cSKalle Valo 		ret = -EINVAL;
637da3a9d3cSKalle Valo 		goto exit;
638da3a9d3cSKalle Valo 	}
639da3a9d3cSKalle Valo 
640da3a9d3cSKalle Valo 	if (enable == ar->debug.extd_rx_stats) {
641da3a9d3cSKalle Valo 		ret = count;
642da3a9d3cSKalle Valo 		goto exit;
643da3a9d3cSKalle Valo 	}
644da3a9d3cSKalle Valo 
64567a9d399SMiles Hu 	if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) {
64667a9d399SMiles Hu 		ar->debug.extd_rx_stats = enable;
64767a9d399SMiles Hu 		ret = count;
64867a9d399SMiles Hu 		goto exit;
64967a9d399SMiles Hu 	}
65067a9d399SMiles Hu 
651da3a9d3cSKalle Valo 	if (enable) {
652da3a9d3cSKalle Valo 		rx_filter =  HTT_RX_FILTER_TLV_FLAGS_MPDU_START;
653da3a9d3cSKalle Valo 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;
654da3a9d3cSKalle Valo 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;
655da3a9d3cSKalle Valo 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;
656da3a9d3cSKalle Valo 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;
657da3a9d3cSKalle Valo 		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;
658da3a9d3cSKalle Valo 
659da3a9d3cSKalle Valo 		tlv_filter.rx_filter = rx_filter;
660da3a9d3cSKalle Valo 		tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
661da3a9d3cSKalle Valo 		tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
662da3a9d3cSKalle Valo 		tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
663da3a9d3cSKalle Valo 		tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
664da3a9d3cSKalle Valo 			HTT_RX_FP_DATA_FILTER_FLASG3;
665da3a9d3cSKalle Valo 	} else {
666da3a9d3cSKalle Valo 		tlv_filter = ath11k_mac_mon_status_filter_default;
667da3a9d3cSKalle Valo 	}
668da3a9d3cSKalle Valo 
669da3a9d3cSKalle Valo 	ar->debug.rx_filter = tlv_filter.rx_filter;
670da3a9d3cSKalle Valo 
671da3a9d3cSKalle Valo 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
672da3a9d3cSKalle Valo 		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
673da3a9d3cSKalle Valo 		ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
674da3a9d3cSKalle Valo 						       HAL_RXDMA_MONITOR_STATUS,
675da3a9d3cSKalle Valo 						       DP_RX_BUFFER_SIZE, &tlv_filter);
676da3a9d3cSKalle Valo 
677da3a9d3cSKalle Valo 		if (ret) {
678da3a9d3cSKalle Valo 			ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
679da3a9d3cSKalle Valo 			goto exit;
680da3a9d3cSKalle Valo 		}
681da3a9d3cSKalle Valo 	}
682da3a9d3cSKalle Valo 
683da3a9d3cSKalle Valo 	ar->debug.extd_rx_stats = enable;
684da3a9d3cSKalle Valo 	ret = count;
685da3a9d3cSKalle Valo exit:
686da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
687da3a9d3cSKalle Valo 	return ret;
688da3a9d3cSKalle Valo }
689da3a9d3cSKalle Valo 
ath11k_read_extd_rx_stats(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)690da3a9d3cSKalle Valo static ssize_t ath11k_read_extd_rx_stats(struct file *file,
691da3a9d3cSKalle Valo 					 char __user *ubuf,
692da3a9d3cSKalle Valo 					 size_t count, loff_t *ppos)
693da3a9d3cSKalle Valo {
694da3a9d3cSKalle Valo 	struct ath11k *ar = file->private_data;
695da3a9d3cSKalle Valo 	char buf[32];
696da3a9d3cSKalle Valo 	int len = 0;
697da3a9d3cSKalle Valo 
698da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
699da3a9d3cSKalle Valo 	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
700da3a9d3cSKalle Valo 			ar->debug.extd_rx_stats);
701da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
702da3a9d3cSKalle Valo 
703da3a9d3cSKalle Valo 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
704da3a9d3cSKalle Valo }
705da3a9d3cSKalle Valo 
706da3a9d3cSKalle Valo static const struct file_operations fops_extd_rx_stats = {
707da3a9d3cSKalle Valo 	.read = ath11k_read_extd_rx_stats,
708da3a9d3cSKalle Valo 	.write = ath11k_write_extd_rx_stats,
709da3a9d3cSKalle Valo 	.open = simple_open,
710da3a9d3cSKalle Valo };
711da3a9d3cSKalle Valo 
ath11k_fill_bp_stats(struct ath11k_base * ab,struct ath11k_bp_stats * bp_stats,char * buf,int len,int size)712da3a9d3cSKalle Valo static int ath11k_fill_bp_stats(struct ath11k_base *ab,
713da3a9d3cSKalle Valo 				struct ath11k_bp_stats *bp_stats,
714da3a9d3cSKalle Valo 				char *buf, int len, int size)
715da3a9d3cSKalle Valo {
716da3a9d3cSKalle Valo 	lockdep_assert_held(&ab->base_lock);
717da3a9d3cSKalle Valo 
718da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "count: %u\n",
719da3a9d3cSKalle Valo 			 bp_stats->count);
720da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "hp: %u\n",
721da3a9d3cSKalle Valo 			 bp_stats->hp);
722da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "tp: %u\n",
723da3a9d3cSKalle Valo 			 bp_stats->tp);
724da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "seen before: %ums\n\n",
725da3a9d3cSKalle Valo 			 jiffies_to_msecs(jiffies - bp_stats->jiffies));
726da3a9d3cSKalle Valo 	return len;
727da3a9d3cSKalle Valo }
728da3a9d3cSKalle Valo 
ath11k_debugfs_dump_soc_ring_bp_stats(struct ath11k_base * ab,char * buf,int size)729cb4e57dbSKalle Valo static ssize_t ath11k_debugfs_dump_soc_ring_bp_stats(struct ath11k_base *ab,
730da3a9d3cSKalle Valo 						     char *buf, int size)
731da3a9d3cSKalle Valo {
732da3a9d3cSKalle Valo 	struct ath11k_bp_stats *bp_stats;
733da3a9d3cSKalle Valo 	bool stats_rxd = false;
734da3a9d3cSKalle Valo 	u8 i, pdev_idx;
735da3a9d3cSKalle Valo 	int len = 0;
736da3a9d3cSKalle Valo 
737da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n");
738da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "==================\n");
739da3a9d3cSKalle Valo 
740da3a9d3cSKalle Valo 	spin_lock_bh(&ab->base_lock);
741da3a9d3cSKalle Valo 	for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) {
742da3a9d3cSKalle Valo 		bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i];
743da3a9d3cSKalle Valo 
744da3a9d3cSKalle Valo 		if (!bp_stats->count)
745da3a9d3cSKalle Valo 			continue;
746da3a9d3cSKalle Valo 
747da3a9d3cSKalle Valo 		len += scnprintf(buf + len, size - len, "Ring: %s\n",
748da3a9d3cSKalle Valo 				 htt_bp_umac_ring[i]);
749da3a9d3cSKalle Valo 		len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
750da3a9d3cSKalle Valo 		stats_rxd = true;
751da3a9d3cSKalle Valo 	}
752da3a9d3cSKalle Valo 
753da3a9d3cSKalle Valo 	for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) {
754da3a9d3cSKalle Valo 		for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) {
755da3a9d3cSKalle Valo 			bp_stats =
756da3a9d3cSKalle Valo 				&ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx];
757da3a9d3cSKalle Valo 
758da3a9d3cSKalle Valo 			if (!bp_stats->count)
759da3a9d3cSKalle Valo 				continue;
760da3a9d3cSKalle Valo 
761da3a9d3cSKalle Valo 			len += scnprintf(buf + len, size - len, "Ring: %s\n",
762da3a9d3cSKalle Valo 					 htt_bp_lmac_ring[i]);
763da3a9d3cSKalle Valo 			len += scnprintf(buf + len, size - len, "pdev: %d\n",
764da3a9d3cSKalle Valo 					 pdev_idx);
765da3a9d3cSKalle Valo 			len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
766da3a9d3cSKalle Valo 			stats_rxd = true;
767da3a9d3cSKalle Valo 		}
768da3a9d3cSKalle Valo 	}
769da3a9d3cSKalle Valo 	spin_unlock_bh(&ab->base_lock);
770da3a9d3cSKalle Valo 
771da3a9d3cSKalle Valo 	if (!stats_rxd)
772da3a9d3cSKalle Valo 		len += scnprintf(buf + len, size - len,
773da3a9d3cSKalle Valo 				 "No Ring Backpressure stats received\n\n");
774da3a9d3cSKalle Valo 
775da3a9d3cSKalle Valo 	return len;
776da3a9d3cSKalle Valo }
777da3a9d3cSKalle Valo 
ath11k_debugfs_dump_soc_dp_stats(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)778cb4e57dbSKalle Valo static ssize_t ath11k_debugfs_dump_soc_dp_stats(struct file *file,
779da3a9d3cSKalle Valo 						char __user *user_buf,
780da3a9d3cSKalle Valo 						size_t count, loff_t *ppos)
781da3a9d3cSKalle Valo {
782da3a9d3cSKalle Valo 	struct ath11k_base *ab = file->private_data;
783da3a9d3cSKalle Valo 	struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats;
784da3a9d3cSKalle Valo 	int len = 0, i, retval;
785da3a9d3cSKalle Valo 	const int size = 4096;
786da3a9d3cSKalle Valo 	static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
787da3a9d3cSKalle Valo 			"Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",
788da3a9d3cSKalle Valo 			"Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",
789da3a9d3cSKalle Valo 			"AMSDU parse", "SA timeout", "DA timeout",
790da3a9d3cSKalle Valo 			"Flow timeout", "Flush req"};
791da3a9d3cSKalle Valo 	static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {
792da3a9d3cSKalle Valo 			"Desc addr zero", "Desc inval", "AMPDU in non BA",
793da3a9d3cSKalle Valo 			"Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",
794da3a9d3cSKalle Valo 			"Frame OOR", "BAR OOR", "No BA session",
795da3a9d3cSKalle Valo 			"Frame SN equal SSN", "PN check fail", "2k err",
796da3a9d3cSKalle Valo 			"PN err", "Desc blocked"};
797da3a9d3cSKalle Valo 
798da3a9d3cSKalle Valo 	char *buf;
799da3a9d3cSKalle Valo 
800da3a9d3cSKalle Valo 	buf = kzalloc(size, GFP_KERNEL);
801da3a9d3cSKalle Valo 	if (!buf)
802da3a9d3cSKalle Valo 		return -ENOMEM;
803da3a9d3cSKalle Valo 
804da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");
805da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",
806da3a9d3cSKalle Valo 			 soc_stats->err_ring_pkts);
807da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",
808da3a9d3cSKalle Valo 			 soc_stats->invalid_rbm);
809da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "RXDMA errors:\n");
810da3a9d3cSKalle Valo 	for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)
811da3a9d3cSKalle Valo 		len += scnprintf(buf + len, size - len, "%s: %u\n",
812da3a9d3cSKalle Valo 				 rxdma_err[i], soc_stats->rxdma_error[i]);
813da3a9d3cSKalle Valo 
814da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "\nREO errors:\n");
815da3a9d3cSKalle Valo 	for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)
816da3a9d3cSKalle Valo 		len += scnprintf(buf + len, size - len, "%s: %u\n",
817da3a9d3cSKalle Valo 				 reo_err[i], soc_stats->reo_error[i]);
818da3a9d3cSKalle Valo 
819da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");
820da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len,
821da3a9d3cSKalle Valo 			 "ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",
822da3a9d3cSKalle Valo 			 soc_stats->hal_reo_error[0],
823da3a9d3cSKalle Valo 			 soc_stats->hal_reo_error[1],
824da3a9d3cSKalle Valo 			 soc_stats->hal_reo_error[2],
825da3a9d3cSKalle Valo 			 soc_stats->hal_reo_error[3]);
826da3a9d3cSKalle Valo 
827da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n");
828da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
829da3a9d3cSKalle Valo 
83031582373SBaochen Qiang 	for (i = 0; i < ab->hw_params.max_tx_ring; i++)
831da3a9d3cSKalle Valo 		len += scnprintf(buf + len, size - len, "ring%d: %u\n",
832da3a9d3cSKalle Valo 				 i, soc_stats->tx_err.desc_na[i]);
833da3a9d3cSKalle Valo 
834da3a9d3cSKalle Valo 	len += scnprintf(buf + len, size - len,
835da3a9d3cSKalle Valo 			 "\nMisc Transmit Failures: %d\n",
836da3a9d3cSKalle Valo 			 atomic_read(&soc_stats->tx_err.misc_fail));
837da3a9d3cSKalle Valo 
838cb4e57dbSKalle Valo 	len += ath11k_debugfs_dump_soc_ring_bp_stats(ab, buf + len, size - len);
839da3a9d3cSKalle Valo 
840da3a9d3cSKalle Valo 	if (len > size)
841da3a9d3cSKalle Valo 		len = size;
842da3a9d3cSKalle Valo 	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
843da3a9d3cSKalle Valo 	kfree(buf);
844da3a9d3cSKalle Valo 
845da3a9d3cSKalle Valo 	return retval;
846da3a9d3cSKalle Valo }
847da3a9d3cSKalle Valo 
848da3a9d3cSKalle Valo static const struct file_operations fops_soc_dp_stats = {
849cb4e57dbSKalle Valo 	.read = ath11k_debugfs_dump_soc_dp_stats,
850da3a9d3cSKalle Valo 	.open = simple_open,
851da3a9d3cSKalle Valo 	.owner = THIS_MODULE,
852da3a9d3cSKalle Valo 	.llseek = default_llseek,
853da3a9d3cSKalle Valo };
854da3a9d3cSKalle Valo 
ath11k_write_fw_dbglog(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)855f295ad91SSeevalamuthu Mariappan static ssize_t ath11k_write_fw_dbglog(struct file *file,
856f295ad91SSeevalamuthu Mariappan 				      const char __user *user_buf,
857f295ad91SSeevalamuthu Mariappan 				      size_t count, loff_t *ppos)
858f295ad91SSeevalamuthu Mariappan {
859f295ad91SSeevalamuthu Mariappan 	struct ath11k *ar = file->private_data;
860f295ad91SSeevalamuthu Mariappan 	char buf[128] = {0};
861f295ad91SSeevalamuthu Mariappan 	struct ath11k_fw_dbglog dbglog;
862f295ad91SSeevalamuthu Mariappan 	unsigned int param, mod_id_index, is_end;
863f295ad91SSeevalamuthu Mariappan 	u64 value;
864f295ad91SSeevalamuthu Mariappan 	int ret, num;
865f295ad91SSeevalamuthu Mariappan 
866f295ad91SSeevalamuthu Mariappan 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
867f295ad91SSeevalamuthu Mariappan 				     user_buf, count);
868f295ad91SSeevalamuthu Mariappan 	if (ret <= 0)
869f295ad91SSeevalamuthu Mariappan 		return ret;
870f295ad91SSeevalamuthu Mariappan 
871f295ad91SSeevalamuthu Mariappan 	num = sscanf(buf, "%u %llx %u %u", &param, &value, &mod_id_index, &is_end);
872f295ad91SSeevalamuthu Mariappan 
873f295ad91SSeevalamuthu Mariappan 	if (num < 2)
874f295ad91SSeevalamuthu Mariappan 		return -EINVAL;
875f295ad91SSeevalamuthu Mariappan 
876f295ad91SSeevalamuthu Mariappan 	mutex_lock(&ar->conf_mutex);
877f295ad91SSeevalamuthu Mariappan 	if (param == WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP ||
878f295ad91SSeevalamuthu Mariappan 	    param == WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP) {
879f295ad91SSeevalamuthu Mariappan 		if (num != 4 || mod_id_index > (MAX_MODULE_ID_BITMAP_WORDS - 1)) {
880f295ad91SSeevalamuthu Mariappan 			ret = -EINVAL;
881f295ad91SSeevalamuthu Mariappan 			goto out;
882f295ad91SSeevalamuthu Mariappan 		}
883f295ad91SSeevalamuthu Mariappan 		ar->debug.module_id_bitmap[mod_id_index] = upper_32_bits(value);
884f295ad91SSeevalamuthu Mariappan 		if (!is_end) {
885f295ad91SSeevalamuthu Mariappan 			ret = count;
886f295ad91SSeevalamuthu Mariappan 			goto out;
887f295ad91SSeevalamuthu Mariappan 		}
888f295ad91SSeevalamuthu Mariappan 	} else {
889f295ad91SSeevalamuthu Mariappan 		if (num != 2) {
890f295ad91SSeevalamuthu Mariappan 			ret = -EINVAL;
891f295ad91SSeevalamuthu Mariappan 			goto out;
892f295ad91SSeevalamuthu Mariappan 		}
893f295ad91SSeevalamuthu Mariappan 	}
894f295ad91SSeevalamuthu Mariappan 
895f295ad91SSeevalamuthu Mariappan 	dbglog.param = param;
896f295ad91SSeevalamuthu Mariappan 	dbglog.value = lower_32_bits(value);
897f295ad91SSeevalamuthu Mariappan 	ret = ath11k_wmi_fw_dbglog_cfg(ar, ar->debug.module_id_bitmap, &dbglog);
898f295ad91SSeevalamuthu Mariappan 	if (ret) {
899f295ad91SSeevalamuthu Mariappan 		ath11k_warn(ar->ab, "fw dbglog config failed from debugfs: %d\n",
900f295ad91SSeevalamuthu Mariappan 			    ret);
901f295ad91SSeevalamuthu Mariappan 		goto out;
902f295ad91SSeevalamuthu Mariappan 	}
903f295ad91SSeevalamuthu Mariappan 
904f295ad91SSeevalamuthu Mariappan 	ret = count;
905f295ad91SSeevalamuthu Mariappan 
906f295ad91SSeevalamuthu Mariappan out:
907f295ad91SSeevalamuthu Mariappan 	mutex_unlock(&ar->conf_mutex);
908f295ad91SSeevalamuthu Mariappan 	return ret;
909f295ad91SSeevalamuthu Mariappan }
910f295ad91SSeevalamuthu Mariappan 
911f295ad91SSeevalamuthu Mariappan static const struct file_operations fops_fw_dbglog = {
912f295ad91SSeevalamuthu Mariappan 	.write = ath11k_write_fw_dbglog,
913f295ad91SSeevalamuthu Mariappan 	.open = simple_open,
914f295ad91SSeevalamuthu Mariappan 	.owner = THIS_MODULE,
915f295ad91SSeevalamuthu Mariappan 	.llseek = default_llseek,
916f295ad91SSeevalamuthu Mariappan };
917f295ad91SSeevalamuthu Mariappan 
ath11k_open_sram_dump(struct inode * inode,struct file * file)918876eb848SBaochen Qiang static int ath11k_open_sram_dump(struct inode *inode, struct file *file)
919876eb848SBaochen Qiang {
920876eb848SBaochen Qiang 	struct ath11k_base *ab = inode->i_private;
921876eb848SBaochen Qiang 	u8 *buf;
922876eb848SBaochen Qiang 	u32 start, end;
923876eb848SBaochen Qiang 	int ret;
924876eb848SBaochen Qiang 
925876eb848SBaochen Qiang 	start = ab->hw_params.sram_dump.start;
926876eb848SBaochen Qiang 	end = ab->hw_params.sram_dump.end;
927876eb848SBaochen Qiang 
928876eb848SBaochen Qiang 	buf = vmalloc(end - start + 1);
929876eb848SBaochen Qiang 	if (!buf)
930876eb848SBaochen Qiang 		return -ENOMEM;
931876eb848SBaochen Qiang 
932876eb848SBaochen Qiang 	ret = ath11k_hif_read(ab, buf, start, end);
933876eb848SBaochen Qiang 	if (ret) {
934876eb848SBaochen Qiang 		ath11k_warn(ab, "failed to dump sram: %d\n", ret);
935876eb848SBaochen Qiang 		vfree(buf);
936876eb848SBaochen Qiang 		return ret;
937876eb848SBaochen Qiang 	}
938876eb848SBaochen Qiang 
939876eb848SBaochen Qiang 	file->private_data = buf;
940876eb848SBaochen Qiang 	return 0;
941876eb848SBaochen Qiang }
942876eb848SBaochen Qiang 
ath11k_read_sram_dump(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)943876eb848SBaochen Qiang static ssize_t ath11k_read_sram_dump(struct file *file,
944876eb848SBaochen Qiang 				     char __user *user_buf,
945876eb848SBaochen Qiang 				     size_t count, loff_t *ppos)
946876eb848SBaochen Qiang {
947876eb848SBaochen Qiang 	struct ath11k_base *ab = file->f_inode->i_private;
948876eb848SBaochen Qiang 	const char *buf = file->private_data;
949876eb848SBaochen Qiang 	int len;
950876eb848SBaochen Qiang 	u32 start, end;
951876eb848SBaochen Qiang 
952876eb848SBaochen Qiang 	start = ab->hw_params.sram_dump.start;
953876eb848SBaochen Qiang 	end = ab->hw_params.sram_dump.end;
954876eb848SBaochen Qiang 	len = end - start + 1;
955876eb848SBaochen Qiang 
956876eb848SBaochen Qiang 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
957876eb848SBaochen Qiang }
958876eb848SBaochen Qiang 
ath11k_release_sram_dump(struct inode * inode,struct file * file)959876eb848SBaochen Qiang static int ath11k_release_sram_dump(struct inode *inode, struct file *file)
960876eb848SBaochen Qiang {
961876eb848SBaochen Qiang 	vfree(file->private_data);
962876eb848SBaochen Qiang 	file->private_data = NULL;
963876eb848SBaochen Qiang 
964876eb848SBaochen Qiang 	return 0;
965876eb848SBaochen Qiang }
966876eb848SBaochen Qiang 
967876eb848SBaochen Qiang static const struct file_operations fops_sram_dump = {
968876eb848SBaochen Qiang 	.open = ath11k_open_sram_dump,
969876eb848SBaochen Qiang 	.read = ath11k_read_sram_dump,
970876eb848SBaochen Qiang 	.release = ath11k_release_sram_dump,
971876eb848SBaochen Qiang 	.owner = THIS_MODULE,
972876eb848SBaochen Qiang 	.llseek = default_llseek,
973876eb848SBaochen Qiang };
974876eb848SBaochen Qiang 
ath11k_debugfs_pdev_create(struct ath11k_base * ab)975cb4e57dbSKalle Valo int ath11k_debugfs_pdev_create(struct ath11k_base *ab)
976da3a9d3cSKalle Valo {
977da3a9d3cSKalle Valo 	if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))
978da3a9d3cSKalle Valo 		return 0;
979da3a9d3cSKalle Valo 
980da3a9d3cSKalle Valo 	debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
981da3a9d3cSKalle Valo 			    &fops_simulate_fw_crash);
982da3a9d3cSKalle Valo 
983da3a9d3cSKalle Valo 	debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab,
984da3a9d3cSKalle Valo 			    &fops_soc_dp_stats);
985da3a9d3cSKalle Valo 
986876eb848SBaochen Qiang 	if (ab->hw_params.sram_dump.start != 0)
987876eb848SBaochen Qiang 		debugfs_create_file("sram", 0400, ab->debugfs_soc, ab,
988876eb848SBaochen Qiang 				    &fops_sram_dump);
989876eb848SBaochen Qiang 
990da3a9d3cSKalle Valo 	return 0;
991da3a9d3cSKalle Valo }
992da3a9d3cSKalle Valo 
ath11k_debugfs_pdev_destroy(struct ath11k_base * ab)993cb4e57dbSKalle Valo void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab)
994da3a9d3cSKalle Valo {
995089ba909SCarl Huang 	debugfs_remove_recursive(ab->debugfs_soc);
996089ba909SCarl Huang 	ab->debugfs_soc = NULL;
997da3a9d3cSKalle Valo }
998da3a9d3cSKalle Valo 
ath11k_debugfs_soc_create(struct ath11k_base * ab)999cb4e57dbSKalle Valo int ath11k_debugfs_soc_create(struct ath11k_base *ab)
1000da3a9d3cSKalle Valo {
1001323d91d4SKalle Valo 	struct dentry *root;
1002323d91d4SKalle Valo 	bool dput_needed;
1003323d91d4SKalle Valo 	char name[64];
1004323d91d4SKalle Valo 	int ret;
1005da3a9d3cSKalle Valo 
1006323d91d4SKalle Valo 	root = debugfs_lookup("ath11k", NULL);
1007323d91d4SKalle Valo 	if (!root) {
1008323d91d4SKalle Valo 		root = debugfs_create_dir("ath11k", NULL);
1009323d91d4SKalle Valo 		if (IS_ERR_OR_NULL(root))
1010323d91d4SKalle Valo 			return PTR_ERR(root);
1011323d91d4SKalle Valo 
1012323d91d4SKalle Valo 		dput_needed = false;
1013323d91d4SKalle Valo 	} else {
1014323d91d4SKalle Valo 		/* a dentry from lookup() needs dput() after we don't use it */
1015323d91d4SKalle Valo 		dput_needed = true;
1016323d91d4SKalle Valo 	}
1017323d91d4SKalle Valo 
1018323d91d4SKalle Valo 	scnprintf(name, sizeof(name), "%s-%s", ath11k_bus_str(ab->hif.bus),
1019323d91d4SKalle Valo 		  dev_name(ab->dev));
1020323d91d4SKalle Valo 
1021323d91d4SKalle Valo 	ab->debugfs_soc = debugfs_create_dir(name, root);
1022323d91d4SKalle Valo 	if (IS_ERR_OR_NULL(ab->debugfs_soc)) {
1023323d91d4SKalle Valo 		ret = PTR_ERR(ab->debugfs_soc);
1024323d91d4SKalle Valo 		goto out;
1025323d91d4SKalle Valo 	}
1026323d91d4SKalle Valo 
1027323d91d4SKalle Valo 	ret = 0;
1028323d91d4SKalle Valo 
1029323d91d4SKalle Valo out:
1030323d91d4SKalle Valo 	if (dput_needed)
1031323d91d4SKalle Valo 		dput(root);
1032323d91d4SKalle Valo 
1033323d91d4SKalle Valo 	return ret;
1034da3a9d3cSKalle Valo }
1035da3a9d3cSKalle Valo 
ath11k_debugfs_soc_destroy(struct ath11k_base * ab)1036cb4e57dbSKalle Valo void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)
1037da3a9d3cSKalle Valo {
1038323d91d4SKalle Valo 	debugfs_remove_recursive(ab->debugfs_soc);
1039323d91d4SKalle Valo 	ab->debugfs_soc = NULL;
1040323d91d4SKalle Valo 
1041323d91d4SKalle Valo 	/* We are not removing ath11k directory on purpose, even if it
1042323d91d4SKalle Valo 	 * would be empty. This simplifies the directory handling and it's
1043323d91d4SKalle Valo 	 * a minor cosmetic issue to leave an empty ath11k directory to
1044323d91d4SKalle Valo 	 * debugfs.
1045323d91d4SKalle Valo 	 */
1046da3a9d3cSKalle Valo }
104761a57e51SAnilkumar Kolli EXPORT_SYMBOL(ath11k_debugfs_soc_destroy);
1048da3a9d3cSKalle Valo 
ath11k_debugfs_fw_stats_init(struct ath11k * ar)1049cb4e57dbSKalle Valo void ath11k_debugfs_fw_stats_init(struct ath11k *ar)
1050da3a9d3cSKalle Valo {
1051da3a9d3cSKalle Valo 	struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",
1052da3a9d3cSKalle Valo 							ar->debug.debugfs_pdev);
1053da3a9d3cSKalle Valo 
1054ec8918f9SAditya Kumar Singh 	ar->fw_stats.debugfs_fwstats = fwstats_dir;
1055da3a9d3cSKalle Valo 
1056da3a9d3cSKalle Valo 	/* all stats debugfs files created are under "fw_stats" directory
1057da3a9d3cSKalle Valo 	 * created per PDEV
1058da3a9d3cSKalle Valo 	 */
1059da3a9d3cSKalle Valo 	debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,
1060da3a9d3cSKalle Valo 			    &fops_pdev_stats);
1061da3a9d3cSKalle Valo 	debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,
1062da3a9d3cSKalle Valo 			    &fops_vdev_stats);
1063da3a9d3cSKalle Valo 	debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,
1064da3a9d3cSKalle Valo 			    &fops_bcn_stats);
1065da3a9d3cSKalle Valo }
1066da3a9d3cSKalle Valo 
ath11k_write_pktlog_filter(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)1067da3a9d3cSKalle Valo static ssize_t ath11k_write_pktlog_filter(struct file *file,
1068da3a9d3cSKalle Valo 					  const char __user *ubuf,
1069da3a9d3cSKalle Valo 					  size_t count, loff_t *ppos)
1070da3a9d3cSKalle Valo {
1071da3a9d3cSKalle Valo 	struct ath11k *ar = file->private_data;
1072da3a9d3cSKalle Valo 	struct ath11k_base *ab = ar->ab;
1073da3a9d3cSKalle Valo 	struct htt_rx_ring_tlv_filter tlv_filter = {0};
1074da3a9d3cSKalle Valo 	u32 rx_filter = 0, ring_id, filter, mode;
1075da3a9d3cSKalle Valo 	u8 buf[128] = {0};
1076ab18e3bcSAnilkumar Kolli 	int i, ret, rx_buf_sz = 0;
1077da3a9d3cSKalle Valo 	ssize_t rc;
1078da3a9d3cSKalle Valo 
1079da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
1080da3a9d3cSKalle Valo 	if (ar->state != ATH11K_STATE_ON) {
1081da3a9d3cSKalle Valo 		ret = -ENETDOWN;
1082da3a9d3cSKalle Valo 		goto out;
1083da3a9d3cSKalle Valo 	}
1084da3a9d3cSKalle Valo 
1085da3a9d3cSKalle Valo 	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1086da3a9d3cSKalle Valo 	if (rc < 0) {
1087da3a9d3cSKalle Valo 		ret = rc;
1088da3a9d3cSKalle Valo 		goto out;
1089da3a9d3cSKalle Valo 	}
1090da3a9d3cSKalle Valo 	buf[rc] = '\0';
1091da3a9d3cSKalle Valo 
1092da3a9d3cSKalle Valo 	ret = sscanf(buf, "0x%x %u", &filter, &mode);
1093da3a9d3cSKalle Valo 	if (ret != 2) {
1094da3a9d3cSKalle Valo 		ret = -EINVAL;
1095da3a9d3cSKalle Valo 		goto out;
1096da3a9d3cSKalle Valo 	}
1097da3a9d3cSKalle Valo 
1098da3a9d3cSKalle Valo 	if (filter) {
1099da3a9d3cSKalle Valo 		ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);
1100da3a9d3cSKalle Valo 		if (ret) {
1101da3a9d3cSKalle Valo 			ath11k_warn(ar->ab,
1102da3a9d3cSKalle Valo 				    "failed to enable pktlog filter %x: %d\n",
1103da3a9d3cSKalle Valo 				    ar->debug.pktlog_filter, ret);
1104da3a9d3cSKalle Valo 			goto out;
1105da3a9d3cSKalle Valo 		}
1106da3a9d3cSKalle Valo 	} else {
1107da3a9d3cSKalle Valo 		ret = ath11k_wmi_pdev_pktlog_disable(ar);
1108da3a9d3cSKalle Valo 		if (ret) {
1109da3a9d3cSKalle Valo 			ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);
1110da3a9d3cSKalle Valo 			goto out;
1111da3a9d3cSKalle Valo 		}
1112da3a9d3cSKalle Valo 	}
1113da3a9d3cSKalle Valo 
1114ab18e3bcSAnilkumar Kolli 	/* Clear rx filter set for monitor mode and rx status */
1115ab18e3bcSAnilkumar Kolli 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
1116ab18e3bcSAnilkumar Kolli 		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
1117ab18e3bcSAnilkumar Kolli 		ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,
1118ab18e3bcSAnilkumar Kolli 						       HAL_RXDMA_MONITOR_STATUS,
1119ab18e3bcSAnilkumar Kolli 						       rx_buf_sz, &tlv_filter);
1120ab18e3bcSAnilkumar Kolli 		if (ret) {
1121ab18e3bcSAnilkumar Kolli 			ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");
1122ab18e3bcSAnilkumar Kolli 			goto out;
1123ab18e3bcSAnilkumar Kolli 		}
1124ab18e3bcSAnilkumar Kolli 	}
1125da3a9d3cSKalle Valo #define HTT_RX_FILTER_TLV_LITE_MODE \
1126da3a9d3cSKalle Valo 			(HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \
1127da3a9d3cSKalle Valo 			HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \
1128da3a9d3cSKalle Valo 			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \
1129da3a9d3cSKalle Valo 			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \
1130da3a9d3cSKalle Valo 			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \
1131da3a9d3cSKalle Valo 			HTT_RX_FILTER_TLV_FLAGS_MPDU_START)
1132da3a9d3cSKalle Valo 
1133da3a9d3cSKalle Valo 	if (mode == ATH11K_PKTLOG_MODE_FULL) {
1134da3a9d3cSKalle Valo 		rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |
1135da3a9d3cSKalle Valo 			    HTT_RX_FILTER_TLV_FLAGS_MSDU_START |
1136da3a9d3cSKalle Valo 			    HTT_RX_FILTER_TLV_FLAGS_MSDU_END |
1137da3a9d3cSKalle Valo 			    HTT_RX_FILTER_TLV_FLAGS_MPDU_END |
1138da3a9d3cSKalle Valo 			    HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |
1139da3a9d3cSKalle Valo 			    HTT_RX_FILTER_TLV_FLAGS_ATTENTION;
1140ab18e3bcSAnilkumar Kolli 		rx_buf_sz = DP_RX_BUFFER_SIZE;
1141da3a9d3cSKalle Valo 	} else if (mode == ATH11K_PKTLOG_MODE_LITE) {
1142da3a9d3cSKalle Valo 		ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
1143da3a9d3cSKalle Valo 							  HTT_PPDU_STATS_TAG_PKTLOG);
1144da3a9d3cSKalle Valo 		if (ret) {
1145da3a9d3cSKalle Valo 			ath11k_err(ar->ab, "failed to enable pktlog lite: %d\n", ret);
1146da3a9d3cSKalle Valo 			goto out;
1147da3a9d3cSKalle Valo 		}
1148da3a9d3cSKalle Valo 
1149da3a9d3cSKalle Valo 		rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;
1150ab18e3bcSAnilkumar Kolli 		rx_buf_sz = DP_RX_BUFFER_SIZE_LITE;
1151da3a9d3cSKalle Valo 	} else {
1152ab18e3bcSAnilkumar Kolli 		rx_buf_sz = DP_RX_BUFFER_SIZE;
1153ab18e3bcSAnilkumar Kolli 		tlv_filter = ath11k_mac_mon_status_filter_default;
1154ab18e3bcSAnilkumar Kolli 		rx_filter = tlv_filter.rx_filter;
1155ab18e3bcSAnilkumar Kolli 
1156da3a9d3cSKalle Valo 		ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,
1157da3a9d3cSKalle Valo 							  HTT_PPDU_STATS_TAG_DEFAULT);
1158da3a9d3cSKalle Valo 		if (ret) {
1159da3a9d3cSKalle Valo 			ath11k_err(ar->ab, "failed to send htt ppdu stats req: %d\n",
1160da3a9d3cSKalle Valo 				   ret);
1161da3a9d3cSKalle Valo 			goto out;
1162da3a9d3cSKalle Valo 		}
1163da3a9d3cSKalle Valo 	}
1164da3a9d3cSKalle Valo 
1165da3a9d3cSKalle Valo 	tlv_filter.rx_filter = rx_filter;
1166da3a9d3cSKalle Valo 	if (rx_filter) {
1167da3a9d3cSKalle Valo 		tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;
1168da3a9d3cSKalle Valo 		tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;
1169da3a9d3cSKalle Valo 		tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;
1170da3a9d3cSKalle Valo 		tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |
1171da3a9d3cSKalle Valo 					       HTT_RX_FP_DATA_FILTER_FLASG3;
1172da3a9d3cSKalle Valo 	}
1173da3a9d3cSKalle Valo 
1174da3a9d3cSKalle Valo 	for (i = 0; i < ab->hw_params.num_rxmda_per_pdev; i++) {
1175da3a9d3cSKalle Valo 		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;
1176da3a9d3cSKalle Valo 		ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,
1177da3a9d3cSKalle Valo 						       ar->dp.mac_id + i,
1178da3a9d3cSKalle Valo 						       HAL_RXDMA_MONITOR_STATUS,
1179ab18e3bcSAnilkumar Kolli 						       rx_buf_sz, &tlv_filter);
1180da3a9d3cSKalle Valo 
1181da3a9d3cSKalle Valo 		if (ret) {
1182da3a9d3cSKalle Valo 			ath11k_warn(ab, "failed to set rx filter for monitor status ring\n");
1183da3a9d3cSKalle Valo 			goto out;
1184da3a9d3cSKalle Valo 		}
1185da3a9d3cSKalle Valo 	}
1186da3a9d3cSKalle Valo 
1187ab18e3bcSAnilkumar Kolli 	ath11k_info(ab, "pktlog mode %s\n",
1188ab18e3bcSAnilkumar Kolli 		    ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));
1189da3a9d3cSKalle Valo 
1190da3a9d3cSKalle Valo 	ar->debug.pktlog_filter = filter;
1191da3a9d3cSKalle Valo 	ar->debug.pktlog_mode = mode;
1192da3a9d3cSKalle Valo 	ret = count;
1193da3a9d3cSKalle Valo 
1194da3a9d3cSKalle Valo out:
1195da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
1196da3a9d3cSKalle Valo 	return ret;
1197da3a9d3cSKalle Valo }
1198da3a9d3cSKalle Valo 
ath11k_read_pktlog_filter(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)1199da3a9d3cSKalle Valo static ssize_t ath11k_read_pktlog_filter(struct file *file,
1200da3a9d3cSKalle Valo 					 char __user *ubuf,
1201da3a9d3cSKalle Valo 					 size_t count, loff_t *ppos)
1202da3a9d3cSKalle Valo 
1203da3a9d3cSKalle Valo {
1204da3a9d3cSKalle Valo 	char buf[32] = {0};
1205da3a9d3cSKalle Valo 	struct ath11k *ar = file->private_data;
1206da3a9d3cSKalle Valo 	int len = 0;
1207da3a9d3cSKalle Valo 
1208da3a9d3cSKalle Valo 	mutex_lock(&ar->conf_mutex);
1209da3a9d3cSKalle Valo 	len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",
1210da3a9d3cSKalle Valo 			ar->debug.pktlog_filter,
1211da3a9d3cSKalle Valo 			ar->debug.pktlog_mode);
1212da3a9d3cSKalle Valo 	mutex_unlock(&ar->conf_mutex);
1213da3a9d3cSKalle Valo 
1214da3a9d3cSKalle Valo 	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
1215da3a9d3cSKalle Valo }
1216da3a9d3cSKalle Valo 
1217da3a9d3cSKalle Valo static const struct file_operations fops_pktlog_filter = {
1218da3a9d3cSKalle Valo 	.read = ath11k_read_pktlog_filter,
1219da3a9d3cSKalle Valo 	.write = ath11k_write_pktlog_filter,
1220da3a9d3cSKalle Valo 	.open = simple_open
1221da3a9d3cSKalle Valo };
1222da3a9d3cSKalle Valo 
ath11k_write_simulate_radar(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1223da3a9d3cSKalle Valo static ssize_t ath11k_write_simulate_radar(struct file *file,
1224da3a9d3cSKalle Valo 					   const char __user *user_buf,
1225da3a9d3cSKalle Valo 					   size_t count, loff_t *ppos)
1226da3a9d3cSKalle Valo {
1227da3a9d3cSKalle Valo 	struct ath11k *ar = file->private_data;
1228da3a9d3cSKalle Valo 	int ret;
1229da3a9d3cSKalle Valo 
1230da3a9d3cSKalle Valo 	ret = ath11k_wmi_simulate_radar(ar);
1231da3a9d3cSKalle Valo 	if (ret)
1232da3a9d3cSKalle Valo 		return ret;
1233da3a9d3cSKalle Valo 
1234da3a9d3cSKalle Valo 	return count;
1235da3a9d3cSKalle Valo }
1236da3a9d3cSKalle Valo 
1237da3a9d3cSKalle Valo static const struct file_operations fops_simulate_radar = {
1238da3a9d3cSKalle Valo 	.write = ath11k_write_simulate_radar,
1239da3a9d3cSKalle Valo 	.open = simple_open
1240da3a9d3cSKalle Valo };
1241da3a9d3cSKalle Valo 
ath11k_debug_dump_dbr_entries(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1242691425b4SVenkateswara Naralasetty static ssize_t ath11k_debug_dump_dbr_entries(struct file *file,
1243691425b4SVenkateswara Naralasetty 					     char __user *user_buf,
1244691425b4SVenkateswara Naralasetty 					     size_t count, loff_t *ppos)
1245691425b4SVenkateswara Naralasetty {
1246691425b4SVenkateswara Naralasetty 	struct ath11k_dbg_dbr_data *dbr_dbg_data = file->private_data;
1247691425b4SVenkateswara Naralasetty 	static const char * const event_id_to_string[] = {"empty", "Rx", "Replenish"};
1248691425b4SVenkateswara Naralasetty 	int size = ATH11K_DEBUG_DBR_ENTRIES_MAX * 100;
1249691425b4SVenkateswara Naralasetty 	char *buf;
1250691425b4SVenkateswara Naralasetty 	int i, ret;
1251691425b4SVenkateswara Naralasetty 	int len = 0;
1252691425b4SVenkateswara Naralasetty 
1253691425b4SVenkateswara Naralasetty 	buf = kzalloc(size, GFP_KERNEL);
1254691425b4SVenkateswara Naralasetty 	if (!buf)
1255691425b4SVenkateswara Naralasetty 		return -ENOMEM;
1256691425b4SVenkateswara Naralasetty 
1257691425b4SVenkateswara Naralasetty 	len += scnprintf(buf + len, size - len,
1258691425b4SVenkateswara Naralasetty 			 "-----------------------------------------\n");
1259691425b4SVenkateswara Naralasetty 	len += scnprintf(buf + len, size - len,
1260691425b4SVenkateswara Naralasetty 			 "| idx |  hp  |  tp  | timestamp |  event |\n");
1261691425b4SVenkateswara Naralasetty 	len += scnprintf(buf + len, size - len,
1262691425b4SVenkateswara Naralasetty 			 "-----------------------------------------\n");
1263691425b4SVenkateswara Naralasetty 
1264691425b4SVenkateswara Naralasetty 	spin_lock_bh(&dbr_dbg_data->lock);
1265691425b4SVenkateswara Naralasetty 
1266691425b4SVenkateswara Naralasetty 	for (i = 0; i < dbr_dbg_data->num_ring_debug_entries; i++) {
1267691425b4SVenkateswara Naralasetty 		len += scnprintf(buf + len, size - len,
1268691425b4SVenkateswara Naralasetty 				 "|%4u|%8u|%8u|%11llu|%8s|\n", i,
1269691425b4SVenkateswara Naralasetty 				 dbr_dbg_data->entries[i].hp,
1270691425b4SVenkateswara Naralasetty 				 dbr_dbg_data->entries[i].tp,
1271691425b4SVenkateswara Naralasetty 				 dbr_dbg_data->entries[i].timestamp,
1272691425b4SVenkateswara Naralasetty 				 event_id_to_string[dbr_dbg_data->entries[i].event]);
1273691425b4SVenkateswara Naralasetty 	}
1274691425b4SVenkateswara Naralasetty 
1275691425b4SVenkateswara Naralasetty 	spin_unlock_bh(&dbr_dbg_data->lock);
1276691425b4SVenkateswara Naralasetty 
1277691425b4SVenkateswara Naralasetty 	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
1278691425b4SVenkateswara Naralasetty 	kfree(buf);
1279691425b4SVenkateswara Naralasetty 
1280691425b4SVenkateswara Naralasetty 	return ret;
1281691425b4SVenkateswara Naralasetty }
1282691425b4SVenkateswara Naralasetty 
1283691425b4SVenkateswara Naralasetty static const struct file_operations fops_debug_dump_dbr_entries = {
1284691425b4SVenkateswara Naralasetty 	.read = ath11k_debug_dump_dbr_entries,
1285691425b4SVenkateswara Naralasetty 	.open = simple_open,
1286691425b4SVenkateswara Naralasetty 	.owner = THIS_MODULE,
1287691425b4SVenkateswara Naralasetty 	.llseek = default_llseek,
1288691425b4SVenkateswara Naralasetty };
1289691425b4SVenkateswara Naralasetty 
ath11k_debugfs_dbr_dbg_destroy(struct ath11k * ar,int dbr_id)1290691425b4SVenkateswara Naralasetty static void ath11k_debugfs_dbr_dbg_destroy(struct ath11k *ar, int dbr_id)
1291691425b4SVenkateswara Naralasetty {
1292691425b4SVenkateswara Naralasetty 	struct ath11k_debug_dbr *dbr_debug;
1293691425b4SVenkateswara Naralasetty 	struct ath11k_dbg_dbr_data *dbr_dbg_data;
1294691425b4SVenkateswara Naralasetty 
1295691425b4SVenkateswara Naralasetty 	if (!ar->debug.dbr_debug[dbr_id])
1296691425b4SVenkateswara Naralasetty 		return;
1297691425b4SVenkateswara Naralasetty 
1298691425b4SVenkateswara Naralasetty 	dbr_debug = ar->debug.dbr_debug[dbr_id];
1299691425b4SVenkateswara Naralasetty 	dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1300691425b4SVenkateswara Naralasetty 
1301691425b4SVenkateswara Naralasetty 	debugfs_remove_recursive(dbr_debug->dbr_debugfs);
1302691425b4SVenkateswara Naralasetty 	kfree(dbr_dbg_data->entries);
1303691425b4SVenkateswara Naralasetty 	kfree(dbr_debug);
1304691425b4SVenkateswara Naralasetty 	ar->debug.dbr_debug[dbr_id] = NULL;
1305691425b4SVenkateswara Naralasetty }
1306691425b4SVenkateswara Naralasetty 
ath11k_debugfs_dbr_dbg_init(struct ath11k * ar,int dbr_id)1307691425b4SVenkateswara Naralasetty static int ath11k_debugfs_dbr_dbg_init(struct ath11k *ar, int dbr_id)
1308691425b4SVenkateswara Naralasetty {
1309691425b4SVenkateswara Naralasetty 	struct ath11k_debug_dbr *dbr_debug;
1310691425b4SVenkateswara Naralasetty 	struct ath11k_dbg_dbr_data *dbr_dbg_data;
1311691425b4SVenkateswara Naralasetty 	static const char * const dbr_id_to_str[] = {"spectral", "CFR"};
1312691425b4SVenkateswara Naralasetty 
1313691425b4SVenkateswara Naralasetty 	if (ar->debug.dbr_debug[dbr_id])
1314691425b4SVenkateswara Naralasetty 		return 0;
1315691425b4SVenkateswara Naralasetty 
1316691425b4SVenkateswara Naralasetty 	ar->debug.dbr_debug[dbr_id] = kzalloc(sizeof(*dbr_debug),
1317691425b4SVenkateswara Naralasetty 					      GFP_KERNEL);
1318691425b4SVenkateswara Naralasetty 
1319691425b4SVenkateswara Naralasetty 	if (!ar->debug.dbr_debug[dbr_id])
1320691425b4SVenkateswara Naralasetty 		return -ENOMEM;
1321691425b4SVenkateswara Naralasetty 
1322691425b4SVenkateswara Naralasetty 	dbr_debug = ar->debug.dbr_debug[dbr_id];
1323691425b4SVenkateswara Naralasetty 	dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1324691425b4SVenkateswara Naralasetty 
1325691425b4SVenkateswara Naralasetty 	if (dbr_debug->dbr_debugfs)
1326691425b4SVenkateswara Naralasetty 		return 0;
1327691425b4SVenkateswara Naralasetty 
1328691425b4SVenkateswara Naralasetty 	dbr_debug->dbr_debugfs = debugfs_create_dir(dbr_id_to_str[dbr_id],
1329691425b4SVenkateswara Naralasetty 						    ar->debug.debugfs_pdev);
1330691425b4SVenkateswara Naralasetty 	if (IS_ERR_OR_NULL(dbr_debug->dbr_debugfs)) {
1331691425b4SVenkateswara Naralasetty 		if (IS_ERR(dbr_debug->dbr_debugfs))
1332691425b4SVenkateswara Naralasetty 			return PTR_ERR(dbr_debug->dbr_debugfs);
1333691425b4SVenkateswara Naralasetty 		return -ENOMEM;
1334691425b4SVenkateswara Naralasetty 	}
1335691425b4SVenkateswara Naralasetty 
1336691425b4SVenkateswara Naralasetty 	dbr_debug->dbr_debug_enabled = true;
1337691425b4SVenkateswara Naralasetty 	dbr_dbg_data->num_ring_debug_entries = ATH11K_DEBUG_DBR_ENTRIES_MAX;
1338691425b4SVenkateswara Naralasetty 	dbr_dbg_data->dbr_debug_idx = 0;
1339691425b4SVenkateswara Naralasetty 	dbr_dbg_data->entries = kcalloc(ATH11K_DEBUG_DBR_ENTRIES_MAX,
1340691425b4SVenkateswara Naralasetty 					sizeof(struct ath11k_dbg_dbr_entry),
1341691425b4SVenkateswara Naralasetty 					GFP_KERNEL);
1342691425b4SVenkateswara Naralasetty 	if (!dbr_dbg_data->entries)
1343691425b4SVenkateswara Naralasetty 		return -ENOMEM;
1344691425b4SVenkateswara Naralasetty 
1345691425b4SVenkateswara Naralasetty 	spin_lock_init(&dbr_dbg_data->lock);
1346691425b4SVenkateswara Naralasetty 
1347691425b4SVenkateswara Naralasetty 	debugfs_create_file("dump_dbr_debug", 0444, dbr_debug->dbr_debugfs,
1348691425b4SVenkateswara Naralasetty 			    dbr_dbg_data, &fops_debug_dump_dbr_entries);
1349691425b4SVenkateswara Naralasetty 
1350691425b4SVenkateswara Naralasetty 	return 0;
1351691425b4SVenkateswara Naralasetty }
1352691425b4SVenkateswara Naralasetty 
ath11k_debugfs_write_enable_dbr_dbg(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)1353691425b4SVenkateswara Naralasetty static ssize_t ath11k_debugfs_write_enable_dbr_dbg(struct file *file,
1354691425b4SVenkateswara Naralasetty 						   const char __user *ubuf,
1355691425b4SVenkateswara Naralasetty 						   size_t count, loff_t *ppos)
1356691425b4SVenkateswara Naralasetty {
1357691425b4SVenkateswara Naralasetty 	struct ath11k *ar = file->private_data;
1358691425b4SVenkateswara Naralasetty 	char buf[32] = {0};
1359691425b4SVenkateswara Naralasetty 	u32 dbr_id, enable;
1360691425b4SVenkateswara Naralasetty 	int ret;
1361691425b4SVenkateswara Naralasetty 
1362691425b4SVenkateswara Naralasetty 	mutex_lock(&ar->conf_mutex);
1363691425b4SVenkateswara Naralasetty 
1364691425b4SVenkateswara Naralasetty 	if (ar->state != ATH11K_STATE_ON) {
1365691425b4SVenkateswara Naralasetty 		ret = -ENETDOWN;
1366691425b4SVenkateswara Naralasetty 		goto out;
1367691425b4SVenkateswara Naralasetty 	}
1368691425b4SVenkateswara Naralasetty 
1369691425b4SVenkateswara Naralasetty 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1370691425b4SVenkateswara Naralasetty 	if (ret < 0)
1371691425b4SVenkateswara Naralasetty 		goto out;
1372691425b4SVenkateswara Naralasetty 
1373691425b4SVenkateswara Naralasetty 	buf[ret] = '\0';
1374691425b4SVenkateswara Naralasetty 	ret = sscanf(buf, "%u %u", &dbr_id, &enable);
1375691425b4SVenkateswara Naralasetty 	if (ret != 2 || dbr_id > 1 || enable > 1) {
1376691425b4SVenkateswara Naralasetty 		ret = -EINVAL;
1377691425b4SVenkateswara Naralasetty 		ath11k_warn(ar->ab, "usage: echo <dbr_id> <val> dbr_id:0-Spectral 1-CFR val:0-disable 1-enable\n");
1378691425b4SVenkateswara Naralasetty 		goto out;
1379691425b4SVenkateswara Naralasetty 	}
1380691425b4SVenkateswara Naralasetty 
1381691425b4SVenkateswara Naralasetty 	if (enable) {
1382691425b4SVenkateswara Naralasetty 		ret = ath11k_debugfs_dbr_dbg_init(ar, dbr_id);
1383691425b4SVenkateswara Naralasetty 		if (ret) {
1384691425b4SVenkateswara Naralasetty 			ath11k_warn(ar->ab, "db ring module debugfs init failed: %d\n",
1385691425b4SVenkateswara Naralasetty 				    ret);
1386691425b4SVenkateswara Naralasetty 			goto out;
1387691425b4SVenkateswara Naralasetty 		}
1388691425b4SVenkateswara Naralasetty 	} else {
1389691425b4SVenkateswara Naralasetty 		ath11k_debugfs_dbr_dbg_destroy(ar, dbr_id);
1390691425b4SVenkateswara Naralasetty 	}
1391691425b4SVenkateswara Naralasetty 
1392691425b4SVenkateswara Naralasetty 	ret = count;
1393691425b4SVenkateswara Naralasetty out:
1394691425b4SVenkateswara Naralasetty 	mutex_unlock(&ar->conf_mutex);
1395691425b4SVenkateswara Naralasetty 	return ret;
1396691425b4SVenkateswara Naralasetty }
1397691425b4SVenkateswara Naralasetty 
1398691425b4SVenkateswara Naralasetty static const struct file_operations fops_dbr_debug = {
1399691425b4SVenkateswara Naralasetty 	.write = ath11k_debugfs_write_enable_dbr_dbg,
1400691425b4SVenkateswara Naralasetty 	.open = simple_open,
1401691425b4SVenkateswara Naralasetty 	.owner = THIS_MODULE,
1402691425b4SVenkateswara Naralasetty 	.llseek = default_llseek,
1403691425b4SVenkateswara Naralasetty };
1404691425b4SVenkateswara Naralasetty 
ath11k_write_ps_timekeeper_enable(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1405710a95f9SVenkateswara Naralasetty static ssize_t ath11k_write_ps_timekeeper_enable(struct file *file,
1406710a95f9SVenkateswara Naralasetty 						 const char __user *user_buf,
1407710a95f9SVenkateswara Naralasetty 						 size_t count, loff_t *ppos)
1408710a95f9SVenkateswara Naralasetty {
1409710a95f9SVenkateswara Naralasetty 	struct ath11k *ar = file->private_data;
1410710a95f9SVenkateswara Naralasetty 	ssize_t ret;
1411710a95f9SVenkateswara Naralasetty 	u8 ps_timekeeper_enable;
1412710a95f9SVenkateswara Naralasetty 
1413710a95f9SVenkateswara Naralasetty 	if (kstrtou8_from_user(user_buf, count, 0, &ps_timekeeper_enable))
1414710a95f9SVenkateswara Naralasetty 		return -EINVAL;
1415710a95f9SVenkateswara Naralasetty 
1416710a95f9SVenkateswara Naralasetty 	mutex_lock(&ar->conf_mutex);
1417710a95f9SVenkateswara Naralasetty 
1418710a95f9SVenkateswara Naralasetty 	if (ar->state != ATH11K_STATE_ON) {
1419710a95f9SVenkateswara Naralasetty 		ret = -ENETDOWN;
1420710a95f9SVenkateswara Naralasetty 		goto exit;
1421710a95f9SVenkateswara Naralasetty 	}
1422710a95f9SVenkateswara Naralasetty 
1423710a95f9SVenkateswara Naralasetty 	if (!ar->ps_state_enable) {
1424710a95f9SVenkateswara Naralasetty 		ret = -EINVAL;
1425710a95f9SVenkateswara Naralasetty 		goto exit;
1426710a95f9SVenkateswara Naralasetty 	}
1427710a95f9SVenkateswara Naralasetty 
1428710a95f9SVenkateswara Naralasetty 	ar->ps_timekeeper_enable = !!ps_timekeeper_enable;
1429710a95f9SVenkateswara Naralasetty 	ret = count;
1430710a95f9SVenkateswara Naralasetty exit:
1431710a95f9SVenkateswara Naralasetty 	mutex_unlock(&ar->conf_mutex);
1432710a95f9SVenkateswara Naralasetty 
1433710a95f9SVenkateswara Naralasetty 	return ret;
1434710a95f9SVenkateswara Naralasetty }
1435710a95f9SVenkateswara Naralasetty 
ath11k_read_ps_timekeeper_enable(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1436710a95f9SVenkateswara Naralasetty static ssize_t ath11k_read_ps_timekeeper_enable(struct file *file,
1437710a95f9SVenkateswara Naralasetty 						char __user *user_buf,
1438710a95f9SVenkateswara Naralasetty 						size_t count, loff_t *ppos)
1439710a95f9SVenkateswara Naralasetty {
1440710a95f9SVenkateswara Naralasetty 	struct ath11k *ar = file->private_data;
1441710a95f9SVenkateswara Naralasetty 	char buf[32];
1442710a95f9SVenkateswara Naralasetty 	int len;
1443710a95f9SVenkateswara Naralasetty 
1444710a95f9SVenkateswara Naralasetty 	mutex_lock(&ar->conf_mutex);
1445710a95f9SVenkateswara Naralasetty 	len = scnprintf(buf, sizeof(buf), "%d\n", ar->ps_timekeeper_enable);
1446710a95f9SVenkateswara Naralasetty 	mutex_unlock(&ar->conf_mutex);
1447710a95f9SVenkateswara Naralasetty 
1448710a95f9SVenkateswara Naralasetty 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1449710a95f9SVenkateswara Naralasetty }
1450710a95f9SVenkateswara Naralasetty 
1451710a95f9SVenkateswara Naralasetty static const struct file_operations fops_ps_timekeeper_enable = {
1452710a95f9SVenkateswara Naralasetty 	.read = ath11k_read_ps_timekeeper_enable,
1453710a95f9SVenkateswara Naralasetty 	.write = ath11k_write_ps_timekeeper_enable,
1454710a95f9SVenkateswara Naralasetty 	.open = simple_open,
1455710a95f9SVenkateswara Naralasetty 	.owner = THIS_MODULE,
1456710a95f9SVenkateswara Naralasetty 	.llseek = default_llseek,
1457710a95f9SVenkateswara Naralasetty };
1458710a95f9SVenkateswara Naralasetty 
ath11k_reset_peer_ps_duration(void * data,struct ieee80211_sta * sta)1459710a95f9SVenkateswara Naralasetty static void ath11k_reset_peer_ps_duration(void *data,
1460710a95f9SVenkateswara Naralasetty 					  struct ieee80211_sta *sta)
1461710a95f9SVenkateswara Naralasetty {
1462710a95f9SVenkateswara Naralasetty 	struct ath11k *ar = data;
1463710a95f9SVenkateswara Naralasetty 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
1464710a95f9SVenkateswara Naralasetty 
1465710a95f9SVenkateswara Naralasetty 	spin_lock_bh(&ar->data_lock);
1466710a95f9SVenkateswara Naralasetty 	arsta->ps_total_duration = 0;
1467710a95f9SVenkateswara Naralasetty 	spin_unlock_bh(&ar->data_lock);
1468710a95f9SVenkateswara Naralasetty }
1469710a95f9SVenkateswara Naralasetty 
ath11k_write_reset_ps_duration(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1470710a95f9SVenkateswara Naralasetty static ssize_t ath11k_write_reset_ps_duration(struct file *file,
1471710a95f9SVenkateswara Naralasetty 					      const  char __user *user_buf,
1472710a95f9SVenkateswara Naralasetty 					      size_t count, loff_t *ppos)
1473710a95f9SVenkateswara Naralasetty {
1474710a95f9SVenkateswara Naralasetty 	struct ath11k *ar = file->private_data;
1475710a95f9SVenkateswara Naralasetty 	int ret;
1476710a95f9SVenkateswara Naralasetty 	u8 reset_ps_duration;
1477710a95f9SVenkateswara Naralasetty 
1478710a95f9SVenkateswara Naralasetty 	if (kstrtou8_from_user(user_buf, count, 0, &reset_ps_duration))
1479710a95f9SVenkateswara Naralasetty 		return -EINVAL;
1480710a95f9SVenkateswara Naralasetty 
1481710a95f9SVenkateswara Naralasetty 	mutex_lock(&ar->conf_mutex);
1482710a95f9SVenkateswara Naralasetty 
1483710a95f9SVenkateswara Naralasetty 	if (ar->state != ATH11K_STATE_ON) {
1484710a95f9SVenkateswara Naralasetty 		ret = -ENETDOWN;
1485710a95f9SVenkateswara Naralasetty 		goto exit;
1486710a95f9SVenkateswara Naralasetty 	}
1487710a95f9SVenkateswara Naralasetty 
1488710a95f9SVenkateswara Naralasetty 	if (!ar->ps_state_enable) {
1489710a95f9SVenkateswara Naralasetty 		ret = -EINVAL;
1490710a95f9SVenkateswara Naralasetty 		goto exit;
1491710a95f9SVenkateswara Naralasetty 	}
1492710a95f9SVenkateswara Naralasetty 
1493710a95f9SVenkateswara Naralasetty 	ieee80211_iterate_stations_atomic(ar->hw,
1494710a95f9SVenkateswara Naralasetty 					  ath11k_reset_peer_ps_duration,
1495710a95f9SVenkateswara Naralasetty 					  ar);
1496710a95f9SVenkateswara Naralasetty 
1497710a95f9SVenkateswara Naralasetty 	ret = count;
1498710a95f9SVenkateswara Naralasetty exit:
1499710a95f9SVenkateswara Naralasetty 	mutex_unlock(&ar->conf_mutex);
1500710a95f9SVenkateswara Naralasetty 	return ret;
1501710a95f9SVenkateswara Naralasetty }
1502710a95f9SVenkateswara Naralasetty 
1503710a95f9SVenkateswara Naralasetty static const struct file_operations fops_reset_ps_duration = {
1504710a95f9SVenkateswara Naralasetty 	.write = ath11k_write_reset_ps_duration,
1505710a95f9SVenkateswara Naralasetty 	.open = simple_open,
1506710a95f9SVenkateswara Naralasetty 	.owner = THIS_MODULE,
1507710a95f9SVenkateswara Naralasetty 	.llseek = default_llseek,
1508710a95f9SVenkateswara Naralasetty };
1509710a95f9SVenkateswara Naralasetty 
ath11k_peer_ps_state_disable(void * data,struct ieee80211_sta * sta)1510710a95f9SVenkateswara Naralasetty static void ath11k_peer_ps_state_disable(void *data,
1511710a95f9SVenkateswara Naralasetty 					 struct ieee80211_sta *sta)
1512710a95f9SVenkateswara Naralasetty {
1513710a95f9SVenkateswara Naralasetty 	struct ath11k *ar = data;
1514710a95f9SVenkateswara Naralasetty 	struct ath11k_sta *arsta = (struct ath11k_sta *)sta->drv_priv;
1515710a95f9SVenkateswara Naralasetty 
1516710a95f9SVenkateswara Naralasetty 	spin_lock_bh(&ar->data_lock);
1517710a95f9SVenkateswara Naralasetty 	arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;
1518710a95f9SVenkateswara Naralasetty 	arsta->ps_start_time = 0;
1519710a95f9SVenkateswara Naralasetty 	arsta->ps_total_duration = 0;
1520710a95f9SVenkateswara Naralasetty 	spin_unlock_bh(&ar->data_lock);
1521710a95f9SVenkateswara Naralasetty }
1522710a95f9SVenkateswara Naralasetty 
ath11k_write_ps_state_enable(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1523710a95f9SVenkateswara Naralasetty static ssize_t ath11k_write_ps_state_enable(struct file *file,
1524710a95f9SVenkateswara Naralasetty 					    const char __user *user_buf,
1525710a95f9SVenkateswara Naralasetty 					    size_t count, loff_t *ppos)
1526710a95f9SVenkateswara Naralasetty {
1527710a95f9SVenkateswara Naralasetty 	struct ath11k *ar = file->private_data;
1528710a95f9SVenkateswara Naralasetty 	struct ath11k_pdev *pdev = ar->pdev;
1529710a95f9SVenkateswara Naralasetty 	int ret;
1530710a95f9SVenkateswara Naralasetty 	u32 param;
1531710a95f9SVenkateswara Naralasetty 	u8 ps_state_enable;
1532710a95f9SVenkateswara Naralasetty 
1533710a95f9SVenkateswara Naralasetty 	if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))
1534710a95f9SVenkateswara Naralasetty 		return -EINVAL;
1535710a95f9SVenkateswara Naralasetty 
1536710a95f9SVenkateswara Naralasetty 	mutex_lock(&ar->conf_mutex);
1537710a95f9SVenkateswara Naralasetty 
1538710a95f9SVenkateswara Naralasetty 	ps_state_enable = !!ps_state_enable;
1539710a95f9SVenkateswara Naralasetty 
1540710a95f9SVenkateswara Naralasetty 	if (ar->ps_state_enable == ps_state_enable) {
1541710a95f9SVenkateswara Naralasetty 		ret = count;
1542710a95f9SVenkateswara Naralasetty 		goto exit;
1543710a95f9SVenkateswara Naralasetty 	}
1544710a95f9SVenkateswara Naralasetty 
1545710a95f9SVenkateswara Naralasetty 	param = WMI_PDEV_PEER_STA_PS_STATECHG_ENABLE;
1546710a95f9SVenkateswara Naralasetty 	ret = ath11k_wmi_pdev_set_param(ar, param, ps_state_enable, pdev->pdev_id);
1547710a95f9SVenkateswara Naralasetty 	if (ret) {
1548710a95f9SVenkateswara Naralasetty 		ath11k_warn(ar->ab, "failed to enable ps_state_enable: %d\n",
1549710a95f9SVenkateswara Naralasetty 			    ret);
1550710a95f9SVenkateswara Naralasetty 		goto exit;
1551710a95f9SVenkateswara Naralasetty 	}
1552710a95f9SVenkateswara Naralasetty 	ar->ps_state_enable = ps_state_enable;
1553710a95f9SVenkateswara Naralasetty 
1554710a95f9SVenkateswara Naralasetty 	if (!ar->ps_state_enable) {
1555710a95f9SVenkateswara Naralasetty 		ar->ps_timekeeper_enable = false;
1556710a95f9SVenkateswara Naralasetty 		ieee80211_iterate_stations_atomic(ar->hw,
1557710a95f9SVenkateswara Naralasetty 						  ath11k_peer_ps_state_disable,
1558710a95f9SVenkateswara Naralasetty 						  ar);
1559710a95f9SVenkateswara Naralasetty 	}
1560710a95f9SVenkateswara Naralasetty 
1561710a95f9SVenkateswara Naralasetty 	ret = count;
1562710a95f9SVenkateswara Naralasetty 
1563710a95f9SVenkateswara Naralasetty exit:
1564710a95f9SVenkateswara Naralasetty 	mutex_unlock(&ar->conf_mutex);
1565710a95f9SVenkateswara Naralasetty 
1566710a95f9SVenkateswara Naralasetty 	return ret;
1567710a95f9SVenkateswara Naralasetty }
1568710a95f9SVenkateswara Naralasetty 
ath11k_read_ps_state_enable(struct file * file,char __user * user_buf,size_t count,loff_t * ppos)1569710a95f9SVenkateswara Naralasetty static ssize_t ath11k_read_ps_state_enable(struct file *file,
1570710a95f9SVenkateswara Naralasetty 					   char __user *user_buf,
1571710a95f9SVenkateswara Naralasetty 					   size_t count, loff_t *ppos)
1572710a95f9SVenkateswara Naralasetty {
1573710a95f9SVenkateswara Naralasetty 	struct ath11k *ar = file->private_data;
1574710a95f9SVenkateswara Naralasetty 	char buf[32];
1575710a95f9SVenkateswara Naralasetty 	int len;
1576710a95f9SVenkateswara Naralasetty 
1577710a95f9SVenkateswara Naralasetty 	mutex_lock(&ar->conf_mutex);
1578710a95f9SVenkateswara Naralasetty 	len = scnprintf(buf, sizeof(buf), "%d\n", ar->ps_state_enable);
1579710a95f9SVenkateswara Naralasetty 	mutex_unlock(&ar->conf_mutex);
1580710a95f9SVenkateswara Naralasetty 
1581710a95f9SVenkateswara Naralasetty 	return simple_read_from_buffer(user_buf, count, ppos, buf, len);
1582710a95f9SVenkateswara Naralasetty }
1583710a95f9SVenkateswara Naralasetty 
1584710a95f9SVenkateswara Naralasetty static const struct file_operations fops_ps_state_enable = {
1585710a95f9SVenkateswara Naralasetty 	.read = ath11k_read_ps_state_enable,
1586710a95f9SVenkateswara Naralasetty 	.write = ath11k_write_ps_state_enable,
1587710a95f9SVenkateswara Naralasetty 	.open = simple_open,
1588710a95f9SVenkateswara Naralasetty 	.owner = THIS_MODULE,
1589710a95f9SVenkateswara Naralasetty 	.llseek = default_llseek,
1590710a95f9SVenkateswara Naralasetty };
1591710a95f9SVenkateswara Naralasetty 
ath11k_debugfs_register(struct ath11k * ar)1592cb4e57dbSKalle Valo int ath11k_debugfs_register(struct ath11k *ar)
1593da3a9d3cSKalle Valo {
1594da3a9d3cSKalle Valo 	struct ath11k_base *ab = ar->ab;
1595da3a9d3cSKalle Valo 	char pdev_name[5];
1596da3a9d3cSKalle Valo 	char buf[100] = {0};
1597da3a9d3cSKalle Valo 
1598da3a9d3cSKalle Valo 	snprintf(pdev_name, sizeof(pdev_name), "%s%d", "mac", ar->pdev_idx);
1599da3a9d3cSKalle Valo 
1600da3a9d3cSKalle Valo 	ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);
1601da3a9d3cSKalle Valo 	if (IS_ERR(ar->debug.debugfs_pdev))
1602da3a9d3cSKalle Valo 		return PTR_ERR(ar->debug.debugfs_pdev);
1603da3a9d3cSKalle Valo 
1604da3a9d3cSKalle Valo 	/* Create a symlink under ieee80211/phy* */
1605da3a9d3cSKalle Valo 	snprintf(buf, 100, "../../ath11k/%pd2", ar->debug.debugfs_pdev);
1606da3a9d3cSKalle Valo 	debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);
1607da3a9d3cSKalle Valo 
160856292162SKalle Valo 	ath11k_debugfs_htt_stats_init(ar);
1609da3a9d3cSKalle Valo 
1610cb4e57dbSKalle Valo 	ath11k_debugfs_fw_stats_init(ar);
1611da3a9d3cSKalle Valo 
1612da3a9d3cSKalle Valo 	debugfs_create_file("ext_tx_stats", 0644,
1613da3a9d3cSKalle Valo 			    ar->debug.debugfs_pdev, ar,
1614da3a9d3cSKalle Valo 			    &fops_extd_tx_stats);
1615da3a9d3cSKalle Valo 	debugfs_create_file("ext_rx_stats", 0644,
1616da3a9d3cSKalle Valo 			    ar->debug.debugfs_pdev, ar,
1617da3a9d3cSKalle Valo 			    &fops_extd_rx_stats);
1618da3a9d3cSKalle Valo 	debugfs_create_file("pktlog_filter", 0644,
1619da3a9d3cSKalle Valo 			    ar->debug.debugfs_pdev, ar,
1620da3a9d3cSKalle Valo 			    &fops_pktlog_filter);
1621f295ad91SSeevalamuthu Mariappan 	debugfs_create_file("fw_dbglog_config", 0600,
1622f295ad91SSeevalamuthu Mariappan 			    ar->debug.debugfs_pdev, ar,
1623f295ad91SSeevalamuthu Mariappan 			    &fops_fw_dbglog);
1624da3a9d3cSKalle Valo 
1625da3a9d3cSKalle Valo 	if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {
1626da3a9d3cSKalle Valo 		debugfs_create_file("dfs_simulate_radar", 0200,
1627da3a9d3cSKalle Valo 				    ar->debug.debugfs_pdev, ar,
1628da3a9d3cSKalle Valo 				    &fops_simulate_radar);
1629da3a9d3cSKalle Valo 		debugfs_create_bool("dfs_block_radar_events", 0200,
1630da3a9d3cSKalle Valo 				    ar->debug.debugfs_pdev,
1631da3a9d3cSKalle Valo 				    &ar->dfs_block_radar_events);
1632da3a9d3cSKalle Valo 	}
1633da3a9d3cSKalle Valo 
1634691425b4SVenkateswara Naralasetty 	if (ab->hw_params.dbr_debug_support)
1635691425b4SVenkateswara Naralasetty 		debugfs_create_file("enable_dbr_debug", 0200, ar->debug.debugfs_pdev,
1636691425b4SVenkateswara Naralasetty 				    ar, &fops_dbr_debug);
1637691425b4SVenkateswara Naralasetty 
1638710a95f9SVenkateswara Naralasetty 	debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_pdev, ar,
1639710a95f9SVenkateswara Naralasetty 			    &fops_ps_state_enable);
1640710a95f9SVenkateswara Naralasetty 
1641710a95f9SVenkateswara Naralasetty 	if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,
1642710a95f9SVenkateswara Naralasetty 		     ar->ab->wmi_ab.svc_map)) {
1643710a95f9SVenkateswara Naralasetty 		debugfs_create_file("ps_timekeeper_enable", 0600,
1644710a95f9SVenkateswara Naralasetty 				    ar->debug.debugfs_pdev, ar,
1645710a95f9SVenkateswara Naralasetty 				    &fops_ps_timekeeper_enable);
1646710a95f9SVenkateswara Naralasetty 
1647710a95f9SVenkateswara Naralasetty 		debugfs_create_file("reset_ps_duration", 0200,
1648710a95f9SVenkateswara Naralasetty 				    ar->debug.debugfs_pdev, ar,
1649710a95f9SVenkateswara Naralasetty 				    &fops_reset_ps_duration);
1650710a95f9SVenkateswara Naralasetty 	}
1651710a95f9SVenkateswara Naralasetty 
1652da3a9d3cSKalle Valo 	return 0;
1653da3a9d3cSKalle Valo }
1654da3a9d3cSKalle Valo 
ath11k_debugfs_unregister(struct ath11k * ar)1655cb4e57dbSKalle Valo void ath11k_debugfs_unregister(struct ath11k *ar)
1656da3a9d3cSKalle Valo {
1657691425b4SVenkateswara Naralasetty 	struct ath11k_debug_dbr *dbr_debug;
1658691425b4SVenkateswara Naralasetty 	struct ath11k_dbg_dbr_data *dbr_dbg_data;
1659691425b4SVenkateswara Naralasetty 	int i;
1660691425b4SVenkateswara Naralasetty 
1661691425b4SVenkateswara Naralasetty 	for (i = 0; i < WMI_DIRECT_BUF_MAX; i++) {
1662691425b4SVenkateswara Naralasetty 		dbr_debug = ar->debug.dbr_debug[i];
1663691425b4SVenkateswara Naralasetty 		if (!dbr_debug)
1664691425b4SVenkateswara Naralasetty 			continue;
1665691425b4SVenkateswara Naralasetty 
1666691425b4SVenkateswara Naralasetty 		dbr_dbg_data = &dbr_debug->dbr_dbg_data;
1667691425b4SVenkateswara Naralasetty 		kfree(dbr_dbg_data->entries);
1668691425b4SVenkateswara Naralasetty 		debugfs_remove_recursive(dbr_debug->dbr_debugfs);
1669691425b4SVenkateswara Naralasetty 		kfree(dbr_debug);
1670691425b4SVenkateswara Naralasetty 		ar->debug.dbr_debug[i] = NULL;
1671691425b4SVenkateswara Naralasetty 	}
1672da3a9d3cSKalle Valo }
1673fe98a613SJohn Crispin 
ath11k_write_twt_add_dialog(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)1674fe98a613SJohn Crispin static ssize_t ath11k_write_twt_add_dialog(struct file *file,
1675fe98a613SJohn Crispin 					   const char __user *ubuf,
1676fe98a613SJohn Crispin 					   size_t count, loff_t *ppos)
1677fe98a613SJohn Crispin {
1678fe98a613SJohn Crispin 	struct ath11k_vif *arvif = file->private_data;
1679fe98a613SJohn Crispin 	struct wmi_twt_add_dialog_params params = { 0 };
16809e2747c3SManikanta Pubbisetty 	struct wmi_twt_enable_params twt_params = {0};
16819e2747c3SManikanta Pubbisetty 	struct ath11k *ar = arvif->ar;
1682fe98a613SJohn Crispin 	u8 buf[128] = {0};
1683fe98a613SJohn Crispin 	int ret;
1684fe98a613SJohn Crispin 
16859e2747c3SManikanta Pubbisetty 	if (ar->twt_enabled == 0) {
16869e2747c3SManikanta Pubbisetty 		ath11k_err(ar->ab, "twt support is not enabled\n");
1687fe98a613SJohn Crispin 		return -EOPNOTSUPP;
1688fe98a613SJohn Crispin 	}
1689fe98a613SJohn Crispin 
1690fe98a613SJohn Crispin 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1691fe98a613SJohn Crispin 	if (ret < 0)
1692fe98a613SJohn Crispin 		return ret;
1693fe98a613SJohn Crispin 
1694fe98a613SJohn Crispin 	buf[ret] = '\0';
1695fe98a613SJohn Crispin 	ret = sscanf(buf,
1696fe98a613SJohn Crispin 		     "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u %u %u %hhu %hhu %hhu %hhu %hhu",
1697fe98a613SJohn Crispin 		     &params.peer_macaddr[0],
1698fe98a613SJohn Crispin 		     &params.peer_macaddr[1],
1699fe98a613SJohn Crispin 		     &params.peer_macaddr[2],
1700fe98a613SJohn Crispin 		     &params.peer_macaddr[3],
1701fe98a613SJohn Crispin 		     &params.peer_macaddr[4],
1702fe98a613SJohn Crispin 		     &params.peer_macaddr[5],
1703fe98a613SJohn Crispin 		     &params.dialog_id,
1704fe98a613SJohn Crispin 		     &params.wake_intvl_us,
1705fe98a613SJohn Crispin 		     &params.wake_intvl_mantis,
1706fe98a613SJohn Crispin 		     &params.wake_dura_us,
1707fe98a613SJohn Crispin 		     &params.sp_offset_us,
1708fe98a613SJohn Crispin 		     &params.twt_cmd,
1709fe98a613SJohn Crispin 		     &params.flag_bcast,
1710fe98a613SJohn Crispin 		     &params.flag_trigger,
1711fe98a613SJohn Crispin 		     &params.flag_flow_type,
1712fe98a613SJohn Crispin 		     &params.flag_protection);
1713fe98a613SJohn Crispin 	if (ret != 16)
1714fe98a613SJohn Crispin 		return -EINVAL;
1715fe98a613SJohn Crispin 
17169e2747c3SManikanta Pubbisetty 	/* In the case of station vif, TWT is entirely handled by
17179e2747c3SManikanta Pubbisetty 	 * the firmware based on the input parameters in the TWT enable
17189e2747c3SManikanta Pubbisetty 	 * WMI command that is sent to the target during assoc.
17199e2747c3SManikanta Pubbisetty 	 * For manually testing the TWT feature, we need to first disable
17209e2747c3SManikanta Pubbisetty 	 * TWT and send enable command again with TWT input parameter
17219e2747c3SManikanta Pubbisetty 	 * sta_cong_timer_ms set to 0.
17229e2747c3SManikanta Pubbisetty 	 */
17239e2747c3SManikanta Pubbisetty 	if (arvif->vif->type == NL80211_IFTYPE_STATION) {
17249e2747c3SManikanta Pubbisetty 		ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
17259e2747c3SManikanta Pubbisetty 
17269e2747c3SManikanta Pubbisetty 		ath11k_wmi_fill_default_twt_params(&twt_params);
17279e2747c3SManikanta Pubbisetty 		twt_params.sta_cong_timer_ms = 0;
17289e2747c3SManikanta Pubbisetty 
17299e2747c3SManikanta Pubbisetty 		ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
17309e2747c3SManikanta Pubbisetty 	}
17319e2747c3SManikanta Pubbisetty 
1732fe98a613SJohn Crispin 	params.vdev_id = arvif->vdev_id;
1733fe98a613SJohn Crispin 
1734fe98a613SJohn Crispin 	ret = ath11k_wmi_send_twt_add_dialog_cmd(arvif->ar, &params);
1735fe98a613SJohn Crispin 	if (ret)
17369e2747c3SManikanta Pubbisetty 		goto err_twt_add_dialog;
1737fe98a613SJohn Crispin 
1738fe98a613SJohn Crispin 	return count;
17399e2747c3SManikanta Pubbisetty 
17409e2747c3SManikanta Pubbisetty err_twt_add_dialog:
17419e2747c3SManikanta Pubbisetty 	if (arvif->vif->type == NL80211_IFTYPE_STATION) {
17429e2747c3SManikanta Pubbisetty 		ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
17439e2747c3SManikanta Pubbisetty 		ath11k_wmi_fill_default_twt_params(&twt_params);
17449e2747c3SManikanta Pubbisetty 		ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
17459e2747c3SManikanta Pubbisetty 	}
17469e2747c3SManikanta Pubbisetty 
17479e2747c3SManikanta Pubbisetty 	return ret;
1748fe98a613SJohn Crispin }
1749fe98a613SJohn Crispin 
ath11k_write_twt_del_dialog(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)1750fe98a613SJohn Crispin static ssize_t ath11k_write_twt_del_dialog(struct file *file,
1751fe98a613SJohn Crispin 					   const char __user *ubuf,
1752fe98a613SJohn Crispin 					   size_t count, loff_t *ppos)
1753fe98a613SJohn Crispin {
1754fe98a613SJohn Crispin 	struct ath11k_vif *arvif = file->private_data;
1755fe98a613SJohn Crispin 	struct wmi_twt_del_dialog_params params = { 0 };
17569e2747c3SManikanta Pubbisetty 	struct wmi_twt_enable_params twt_params = {0};
17579e2747c3SManikanta Pubbisetty 	struct ath11k *ar = arvif->ar;
1758fe98a613SJohn Crispin 	u8 buf[64] = {0};
1759fe98a613SJohn Crispin 	int ret;
1760fe98a613SJohn Crispin 
17619e2747c3SManikanta Pubbisetty 	if (ar->twt_enabled == 0) {
17629e2747c3SManikanta Pubbisetty 		ath11k_err(ar->ab, "twt support is not enabled\n");
1763fe98a613SJohn Crispin 		return -EOPNOTSUPP;
1764fe98a613SJohn Crispin 	}
1765fe98a613SJohn Crispin 
1766fe98a613SJohn Crispin 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1767fe98a613SJohn Crispin 	if (ret < 0)
1768fe98a613SJohn Crispin 		return ret;
1769fe98a613SJohn Crispin 
1770fe98a613SJohn Crispin 	buf[ret] = '\0';
1771fe98a613SJohn Crispin 	ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u",
1772fe98a613SJohn Crispin 		     &params.peer_macaddr[0],
1773fe98a613SJohn Crispin 		     &params.peer_macaddr[1],
1774fe98a613SJohn Crispin 		     &params.peer_macaddr[2],
1775fe98a613SJohn Crispin 		     &params.peer_macaddr[3],
1776fe98a613SJohn Crispin 		     &params.peer_macaddr[4],
1777fe98a613SJohn Crispin 		     &params.peer_macaddr[5],
1778fe98a613SJohn Crispin 		     &params.dialog_id);
1779fe98a613SJohn Crispin 	if (ret != 7)
1780fe98a613SJohn Crispin 		return -EINVAL;
1781fe98a613SJohn Crispin 
1782fe98a613SJohn Crispin 	params.vdev_id = arvif->vdev_id;
1783fe98a613SJohn Crispin 
1784fe98a613SJohn Crispin 	ret = ath11k_wmi_send_twt_del_dialog_cmd(arvif->ar, &params);
1785fe98a613SJohn Crispin 	if (ret)
1786fe98a613SJohn Crispin 		return ret;
1787fe98a613SJohn Crispin 
17889e2747c3SManikanta Pubbisetty 	if (arvif->vif->type == NL80211_IFTYPE_STATION) {
17899e2747c3SManikanta Pubbisetty 		ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);
17909e2747c3SManikanta Pubbisetty 		ath11k_wmi_fill_default_twt_params(&twt_params);
17919e2747c3SManikanta Pubbisetty 		ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);
17929e2747c3SManikanta Pubbisetty 	}
17939e2747c3SManikanta Pubbisetty 
1794fe98a613SJohn Crispin 	return count;
1795fe98a613SJohn Crispin }
1796fe98a613SJohn Crispin 
ath11k_write_twt_pause_dialog(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)1797fe98a613SJohn Crispin static ssize_t ath11k_write_twt_pause_dialog(struct file *file,
1798fe98a613SJohn Crispin 					     const char __user *ubuf,
1799fe98a613SJohn Crispin 					     size_t count, loff_t *ppos)
1800fe98a613SJohn Crispin {
1801fe98a613SJohn Crispin 	struct ath11k_vif *arvif = file->private_data;
1802fe98a613SJohn Crispin 	struct wmi_twt_pause_dialog_params params = { 0 };
1803fe98a613SJohn Crispin 	u8 buf[64] = {0};
1804fe98a613SJohn Crispin 	int ret;
1805fe98a613SJohn Crispin 
1806fe98a613SJohn Crispin 	if (arvif->ar->twt_enabled == 0) {
1807fe98a613SJohn Crispin 		ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
1808fe98a613SJohn Crispin 		return -EOPNOTSUPP;
1809fe98a613SJohn Crispin 	}
1810fe98a613SJohn Crispin 
1811fe98a613SJohn Crispin 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1812fe98a613SJohn Crispin 	if (ret < 0)
1813fe98a613SJohn Crispin 		return ret;
1814fe98a613SJohn Crispin 
1815fe98a613SJohn Crispin 	buf[ret] = '\0';
1816fe98a613SJohn Crispin 	ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u",
1817fe98a613SJohn Crispin 		     &params.peer_macaddr[0],
1818fe98a613SJohn Crispin 		     &params.peer_macaddr[1],
1819fe98a613SJohn Crispin 		     &params.peer_macaddr[2],
1820fe98a613SJohn Crispin 		     &params.peer_macaddr[3],
1821fe98a613SJohn Crispin 		     &params.peer_macaddr[4],
1822fe98a613SJohn Crispin 		     &params.peer_macaddr[5],
1823fe98a613SJohn Crispin 		     &params.dialog_id);
1824fe98a613SJohn Crispin 	if (ret != 7)
1825fe98a613SJohn Crispin 		return -EINVAL;
1826fe98a613SJohn Crispin 
1827fe98a613SJohn Crispin 	params.vdev_id = arvif->vdev_id;
1828fe98a613SJohn Crispin 
1829fe98a613SJohn Crispin 	ret = ath11k_wmi_send_twt_pause_dialog_cmd(arvif->ar, &params);
1830fe98a613SJohn Crispin 	if (ret)
1831fe98a613SJohn Crispin 		return ret;
1832fe98a613SJohn Crispin 
1833fe98a613SJohn Crispin 	return count;
1834fe98a613SJohn Crispin }
1835fe98a613SJohn Crispin 
ath11k_write_twt_resume_dialog(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)1836fe98a613SJohn Crispin static ssize_t ath11k_write_twt_resume_dialog(struct file *file,
1837fe98a613SJohn Crispin 					      const char __user *ubuf,
1838fe98a613SJohn Crispin 					      size_t count, loff_t *ppos)
1839fe98a613SJohn Crispin {
1840fe98a613SJohn Crispin 	struct ath11k_vif *arvif = file->private_data;
1841fe98a613SJohn Crispin 	struct wmi_twt_resume_dialog_params params = { 0 };
1842fe98a613SJohn Crispin 	u8 buf[64] = {0};
1843fe98a613SJohn Crispin 	int ret;
1844fe98a613SJohn Crispin 
1845fe98a613SJohn Crispin 	if (arvif->ar->twt_enabled == 0) {
1846fe98a613SJohn Crispin 		ath11k_err(arvif->ar->ab, "twt support is not enabled\n");
1847fe98a613SJohn Crispin 		return -EOPNOTSUPP;
1848fe98a613SJohn Crispin 	}
1849fe98a613SJohn Crispin 
1850fe98a613SJohn Crispin 	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);
1851fe98a613SJohn Crispin 	if (ret < 0)
1852fe98a613SJohn Crispin 		return ret;
1853fe98a613SJohn Crispin 
1854fe98a613SJohn Crispin 	buf[ret] = '\0';
1855fe98a613SJohn Crispin 	ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u",
1856fe98a613SJohn Crispin 		     &params.peer_macaddr[0],
1857fe98a613SJohn Crispin 		     &params.peer_macaddr[1],
1858fe98a613SJohn Crispin 		     &params.peer_macaddr[2],
1859fe98a613SJohn Crispin 		     &params.peer_macaddr[3],
1860fe98a613SJohn Crispin 		     &params.peer_macaddr[4],
1861fe98a613SJohn Crispin 		     &params.peer_macaddr[5],
1862fe98a613SJohn Crispin 		     &params.dialog_id,
1863fe98a613SJohn Crispin 		     &params.sp_offset_us,
1864fe98a613SJohn Crispin 		     &params.next_twt_size);
1865fe98a613SJohn Crispin 	if (ret != 9)
1866fe98a613SJohn Crispin 		return -EINVAL;
1867fe98a613SJohn Crispin 
1868fe98a613SJohn Crispin 	params.vdev_id = arvif->vdev_id;
1869fe98a613SJohn Crispin 
1870fe98a613SJohn Crispin 	ret = ath11k_wmi_send_twt_resume_dialog_cmd(arvif->ar, &params);
1871fe98a613SJohn Crispin 	if (ret)
1872fe98a613SJohn Crispin 		return ret;
1873fe98a613SJohn Crispin 
1874fe98a613SJohn Crispin 	return count;
1875fe98a613SJohn Crispin }
1876fe98a613SJohn Crispin 
1877fe98a613SJohn Crispin static const struct file_operations ath11k_fops_twt_add_dialog = {
1878fe98a613SJohn Crispin 	.write = ath11k_write_twt_add_dialog,
1879fe98a613SJohn Crispin 	.open = simple_open
1880fe98a613SJohn Crispin };
1881fe98a613SJohn Crispin 
1882fe98a613SJohn Crispin static const struct file_operations ath11k_fops_twt_del_dialog = {
1883fe98a613SJohn Crispin 	.write = ath11k_write_twt_del_dialog,
1884fe98a613SJohn Crispin 	.open = simple_open
1885fe98a613SJohn Crispin };
1886fe98a613SJohn Crispin 
1887fe98a613SJohn Crispin static const struct file_operations ath11k_fops_twt_pause_dialog = {
1888fe98a613SJohn Crispin 	.write = ath11k_write_twt_pause_dialog,
1889fe98a613SJohn Crispin 	.open = simple_open
1890fe98a613SJohn Crispin };
1891fe98a613SJohn Crispin 
1892fe98a613SJohn Crispin static const struct file_operations ath11k_fops_twt_resume_dialog = {
1893fe98a613SJohn Crispin 	.write = ath11k_write_twt_resume_dialog,
1894fe98a613SJohn Crispin 	.open = simple_open
1895fe98a613SJohn Crispin };
1896fe98a613SJohn Crispin 
ath11k_debugfs_add_interface(struct ath11k_vif * arvif)1897607c467eSManikanta Pubbisetty void ath11k_debugfs_add_interface(struct ath11k_vif *arvif)
1898fe98a613SJohn Crispin {
18999e2747c3SManikanta Pubbisetty 	struct ath11k_base *ab = arvif->ar->ab;
19009e2747c3SManikanta Pubbisetty 
19019e2747c3SManikanta Pubbisetty 	if (arvif->vif->type != NL80211_IFTYPE_AP &&
19029e2747c3SManikanta Pubbisetty 	    !(arvif->vif->type == NL80211_IFTYPE_STATION &&
19039e2747c3SManikanta Pubbisetty 	      test_bit(WMI_TLV_SERVICE_STA_TWT, ab->wmi_ab.svc_map)))
1904607c467eSManikanta Pubbisetty 		return;
19059e2747c3SManikanta Pubbisetty 
1906fe98a613SJohn Crispin 	arvif->debugfs_twt = debugfs_create_dir("twt",
1907fe98a613SJohn Crispin 						arvif->vif->debugfs_dir);
1908fe98a613SJohn Crispin 	debugfs_create_file("add_dialog", 0200, arvif->debugfs_twt,
1909fe98a613SJohn Crispin 			    arvif, &ath11k_fops_twt_add_dialog);
1910fe98a613SJohn Crispin 
1911fe98a613SJohn Crispin 	debugfs_create_file("del_dialog", 0200, arvif->debugfs_twt,
1912fe98a613SJohn Crispin 			    arvif, &ath11k_fops_twt_del_dialog);
1913fe98a613SJohn Crispin 
1914fe98a613SJohn Crispin 	debugfs_create_file("pause_dialog", 0200, arvif->debugfs_twt,
1915fe98a613SJohn Crispin 			    arvif, &ath11k_fops_twt_pause_dialog);
1916fe98a613SJohn Crispin 
1917fe98a613SJohn Crispin 	debugfs_create_file("resume_dialog", 0200, arvif->debugfs_twt,
1918fe98a613SJohn Crispin 			    arvif, &ath11k_fops_twt_resume_dialog);
1919fe98a613SJohn Crispin }
1920fe98a613SJohn Crispin 
ath11k_debugfs_remove_interface(struct ath11k_vif * arvif)1921fe98a613SJohn Crispin void ath11k_debugfs_remove_interface(struct ath11k_vif *arvif)
1922fe98a613SJohn Crispin {
1923607c467eSManikanta Pubbisetty 	if (!arvif->debugfs_twt)
1924607c467eSManikanta Pubbisetty 		return;
1925607c467eSManikanta Pubbisetty 
1926fe98a613SJohn Crispin 	debugfs_remove_recursive(arvif->debugfs_twt);
1927fe98a613SJohn Crispin 	arvif->debugfs_twt = NULL;
1928fe98a613SJohn Crispin }
1929