brintos

brintos / linux-shallow public Read only

0
0
Text · 47.7 KiB · 57281a1 Raw
1924 lines · c
1// SPDX-License-Identifier: BSD-3-Clause-Clear2/*3 * Copyright (c) 2018-2020 The Linux Foundation. All rights reserved.4 * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.5 */6 7#include <linux/vmalloc.h>8 9#include "debugfs.h"10 11#include "core.h"12#include "debug.h"13#include "wmi.h"14#include "hal_rx.h"15#include "dp_tx.h"16#include "debugfs_htt_stats.h"17#include "peer.h"18#include "hif.h"19 20static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {21	"REO2SW1_RING",22	"REO2SW2_RING",23	"REO2SW3_RING",24	"REO2SW4_RING",25	"WBM2REO_LINK_RING",26	"REO2TCL_RING",27	"REO2FW_RING",28	"RELEASE_RING",29	"PPE_RELEASE_RING",30	"TCL2TQM_RING",31	"TQM_RELEASE_RING",32	"REO_RELEASE_RING",33	"WBM2SW0_RELEASE_RING",34	"WBM2SW1_RELEASE_RING",35	"WBM2SW2_RELEASE_RING",36	"WBM2SW3_RELEASE_RING",37	"REO_CMD_RING",38	"REO_STATUS_RING",39};40 41static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {42	"FW2RXDMA_BUF_RING",43	"FW2RXDMA_STATUS_RING",44	"FW2RXDMA_LINK_RING",45	"SW2RXDMA_BUF_RING",46	"WBM2RXDMA_LINK_RING",47	"RXDMA2FW_RING",48	"RXDMA2SW_RING",49	"RXDMA2RELEASE_RING",50	"RXDMA2REO_RING",51	"MONITOR_STATUS_RING",52	"MONITOR_BUF_RING",53	"MONITOR_DESC_RING",54	"MONITOR_DEST_RING",55};56 57void ath11k_debugfs_add_dbring_entry(struct ath11k *ar,58				     enum wmi_direct_buffer_module id,59				     enum ath11k_dbg_dbr_event event,60				     struct hal_srng *srng)61{62	struct ath11k_debug_dbr *dbr_debug;63	struct ath11k_dbg_dbr_data *dbr_data;64	struct ath11k_dbg_dbr_entry *entry;65 66	if (id >= WMI_DIRECT_BUF_MAX || event >= ATH11K_DBG_DBR_EVENT_MAX)67		return;68 69	dbr_debug = ar->debug.dbr_debug[id];70	if (!dbr_debug)71		return;72 73	if (!dbr_debug->dbr_debug_enabled)74		return;75 76	dbr_data = &dbr_debug->dbr_dbg_data;77 78	spin_lock_bh(&dbr_data->lock);79 80	if (dbr_data->entries) {81		entry = &dbr_data->entries[dbr_data->dbr_debug_idx];82		entry->hp = srng->u.src_ring.hp;83		entry->tp = *srng->u.src_ring.tp_addr;84		entry->timestamp = jiffies;85		entry->event = event;86 87		dbr_data->dbr_debug_idx++;88		if (dbr_data->dbr_debug_idx ==89		    dbr_data->num_ring_debug_entries)90			dbr_data->dbr_debug_idx = 0;91	}92 93	spin_unlock_bh(&dbr_data->lock);94}95 96static void ath11k_debugfs_fw_stats_reset(struct ath11k *ar)97{98	spin_lock_bh(&ar->data_lock);99	ar->fw_stats_done = false;100	ath11k_fw_stats_pdevs_free(&ar->fw_stats.pdevs);101	ath11k_fw_stats_vdevs_free(&ar->fw_stats.vdevs);102	spin_unlock_bh(&ar->data_lock);103}104 105void ath11k_debugfs_fw_stats_process(struct ath11k *ar, struct ath11k_fw_stats *stats)106{107	struct ath11k_base *ab = ar->ab;108	struct ath11k_pdev *pdev;109	bool is_end;110	static unsigned int num_vdev, num_bcn;111	size_t total_vdevs_started = 0;112	int i;113 114	/* WMI_REQUEST_PDEV_STAT request has been already processed */115 116	if (stats->stats_id == WMI_REQUEST_RSSI_PER_CHAIN_STAT) {117		ar->fw_stats_done = true;118		return;119	}120 121	if (stats->stats_id == WMI_REQUEST_VDEV_STAT) {122		if (list_empty(&stats->vdevs)) {123			ath11k_warn(ab, "empty vdev stats");124			return;125		}126		/* FW sends all the active VDEV stats irrespective of PDEV,127		 * hence limit until the count of all VDEVs started128		 */129		for (i = 0; i < ab->num_radios; i++) {130			pdev = rcu_dereference(ab->pdevs_active[i]);131			if (pdev && pdev->ar)132				total_vdevs_started += ar->num_started_vdevs;133		}134 135		is_end = ((++num_vdev) == total_vdevs_started);136 137		list_splice_tail_init(&stats->vdevs,138				      &ar->fw_stats.vdevs);139 140		if (is_end) {141			ar->fw_stats_done = true;142			num_vdev = 0;143		}144		return;145	}146 147	if (stats->stats_id == WMI_REQUEST_BCN_STAT) {148		if (list_empty(&stats->bcn)) {149			ath11k_warn(ab, "empty bcn stats");150			return;151		}152		/* Mark end until we reached the count of all started VDEVs153		 * within the PDEV154		 */155		is_end = ((++num_bcn) == ar->num_started_vdevs);156 157		list_splice_tail_init(&stats->bcn,158				      &ar->fw_stats.bcn);159 160		if (is_end) {161			ar->fw_stats_done = true;162			num_bcn = 0;163		}164	}165}166 167static int ath11k_debugfs_fw_stats_request(struct ath11k *ar,168					   struct stats_request_params *req_param)169{170	struct ath11k_base *ab = ar->ab;171	unsigned long timeout, time_left;172	int ret;173 174	lockdep_assert_held(&ar->conf_mutex);175 176	/* FW stats can get split when exceeding the stats data buffer limit.177	 * In that case, since there is no end marking for the back-to-back178	 * received 'update stats' event, we keep a 3 seconds timeout in case,179	 * fw_stats_done is not marked yet180	 */181	timeout = jiffies + msecs_to_jiffies(3 * 1000);182 183	ath11k_debugfs_fw_stats_reset(ar);184 185	reinit_completion(&ar->fw_stats_complete);186 187	ret = ath11k_wmi_send_stats_request_cmd(ar, req_param);188 189	if (ret) {190		ath11k_warn(ab, "could not request fw stats (%d)\n",191			    ret);192		return ret;193	}194 195	time_left = wait_for_completion_timeout(&ar->fw_stats_complete, 1 * HZ);196 197	if (!time_left)198		return -ETIMEDOUT;199 200	for (;;) {201		if (time_after(jiffies, timeout))202			break;203 204		spin_lock_bh(&ar->data_lock);205		if (ar->fw_stats_done) {206			spin_unlock_bh(&ar->data_lock);207			break;208		}209		spin_unlock_bh(&ar->data_lock);210	}211	return 0;212}213 214int ath11k_debugfs_get_fw_stats(struct ath11k *ar, u32 pdev_id,215				u32 vdev_id, u32 stats_id)216{217	struct ath11k_base *ab = ar->ab;218	struct stats_request_params req_param;219	int ret;220 221	mutex_lock(&ar->conf_mutex);222 223	if (ar->state != ATH11K_STATE_ON) {224		ret = -ENETDOWN;225		goto err_unlock;226	}227 228	req_param.pdev_id = pdev_id;229	req_param.vdev_id = vdev_id;230	req_param.stats_id = stats_id;231 232	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);233	if (ret)234		ath11k_warn(ab, "failed to request fw stats: %d\n", ret);235 236	ath11k_dbg(ab, ATH11K_DBG_WMI,237		   "debug get fw stat pdev id %d vdev id %d stats id 0x%x\n",238		   pdev_id, vdev_id, stats_id);239 240err_unlock:241	mutex_unlock(&ar->conf_mutex);242 243	return ret;244}245 246static int ath11k_open_pdev_stats(struct inode *inode, struct file *file)247{248	struct ath11k *ar = inode->i_private;249	struct ath11k_base *ab = ar->ab;250	struct stats_request_params req_param;251	void *buf = NULL;252	int ret;253 254	mutex_lock(&ar->conf_mutex);255 256	if (ar->state != ATH11K_STATE_ON) {257		ret = -ENETDOWN;258		goto err_unlock;259	}260 261	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);262	if (!buf) {263		ret = -ENOMEM;264		goto err_unlock;265	}266 267	req_param.pdev_id = ar->pdev->pdev_id;268	req_param.vdev_id = 0;269	req_param.stats_id = WMI_REQUEST_PDEV_STAT;270 271	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);272	if (ret) {273		ath11k_warn(ab, "failed to request fw pdev stats: %d\n", ret);274		goto err_free;275	}276 277	ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);278 279	file->private_data = buf;280 281	mutex_unlock(&ar->conf_mutex);282	return 0;283 284err_free:285	vfree(buf);286 287err_unlock:288	mutex_unlock(&ar->conf_mutex);289	return ret;290}291 292static int ath11k_release_pdev_stats(struct inode *inode, struct file *file)293{294	vfree(file->private_data);295 296	return 0;297}298 299static ssize_t ath11k_read_pdev_stats(struct file *file,300				      char __user *user_buf,301				      size_t count, loff_t *ppos)302{303	const char *buf = file->private_data;304	size_t len = strlen(buf);305 306	return simple_read_from_buffer(user_buf, count, ppos, buf, len);307}308 309static const struct file_operations fops_pdev_stats = {310	.open = ath11k_open_pdev_stats,311	.release = ath11k_release_pdev_stats,312	.read = ath11k_read_pdev_stats,313	.owner = THIS_MODULE,314	.llseek = default_llseek,315};316 317static int ath11k_open_vdev_stats(struct inode *inode, struct file *file)318{319	struct ath11k *ar = inode->i_private;320	struct stats_request_params req_param;321	void *buf = NULL;322	int ret;323 324	mutex_lock(&ar->conf_mutex);325 326	if (ar->state != ATH11K_STATE_ON) {327		ret = -ENETDOWN;328		goto err_unlock;329	}330 331	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);332	if (!buf) {333		ret = -ENOMEM;334		goto err_unlock;335	}336 337	req_param.pdev_id = ar->pdev->pdev_id;338	/* VDEV stats is always sent for all active VDEVs from FW */339	req_param.vdev_id = 0;340	req_param.stats_id = WMI_REQUEST_VDEV_STAT;341 342	ret = ath11k_debugfs_fw_stats_request(ar, &req_param);343	if (ret) {344		ath11k_warn(ar->ab, "failed to request fw vdev stats: %d\n", ret);345		goto err_free;346	}347 348	ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);349 350	file->private_data = buf;351 352	mutex_unlock(&ar->conf_mutex);353	return 0;354 355err_free:356	vfree(buf);357 358err_unlock:359	mutex_unlock(&ar->conf_mutex);360	return ret;361}362 363static int ath11k_release_vdev_stats(struct inode *inode, struct file *file)364{365	vfree(file->private_data);366 367	return 0;368}369 370static ssize_t ath11k_read_vdev_stats(struct file *file,371				      char __user *user_buf,372				      size_t count, loff_t *ppos)373{374	const char *buf = file->private_data;375	size_t len = strlen(buf);376 377	return simple_read_from_buffer(user_buf, count, ppos, buf, len);378}379 380static const struct file_operations fops_vdev_stats = {381	.open = ath11k_open_vdev_stats,382	.release = ath11k_release_vdev_stats,383	.read = ath11k_read_vdev_stats,384	.owner = THIS_MODULE,385	.llseek = default_llseek,386};387 388static int ath11k_open_bcn_stats(struct inode *inode, struct file *file)389{390	struct ath11k *ar = inode->i_private;391	struct ath11k_vif *arvif;392	struct stats_request_params req_param;393	void *buf = NULL;394	int ret;395 396	mutex_lock(&ar->conf_mutex);397 398	if (ar->state != ATH11K_STATE_ON) {399		ret = -ENETDOWN;400		goto err_unlock;401	}402 403	buf = vmalloc(ATH11K_FW_STATS_BUF_SIZE);404	if (!buf) {405		ret = -ENOMEM;406		goto err_unlock;407	}408 409	req_param.stats_id = WMI_REQUEST_BCN_STAT;410	req_param.pdev_id = ar->pdev->pdev_id;411 412	/* loop all active VDEVs for bcn stats */413	list_for_each_entry(arvif, &ar->arvifs, list) {414		if (!arvif->is_up)415			continue;416 417		req_param.vdev_id = arvif->vdev_id;418		ret = ath11k_debugfs_fw_stats_request(ar, &req_param);419		if (ret) {420			ath11k_warn(ar->ab, "failed to request fw bcn stats: %d\n", ret);421			goto err_free;422		}423	}424 425	ath11k_wmi_fw_stats_fill(ar, &ar->fw_stats, req_param.stats_id, buf);426 427	/* since beacon stats request is looped for all active VDEVs, saved fw428	 * stats is not freed for each request until done for all active VDEVs429	 */430	spin_lock_bh(&ar->data_lock);431	ath11k_fw_stats_bcn_free(&ar->fw_stats.bcn);432	spin_unlock_bh(&ar->data_lock);433 434	file->private_data = buf;435 436	mutex_unlock(&ar->conf_mutex);437	return 0;438 439err_free:440	vfree(buf);441 442err_unlock:443	mutex_unlock(&ar->conf_mutex);444	return ret;445}446 447static int ath11k_release_bcn_stats(struct inode *inode, struct file *file)448{449	vfree(file->private_data);450 451	return 0;452}453 454static ssize_t ath11k_read_bcn_stats(struct file *file,455				     char __user *user_buf,456				     size_t count, loff_t *ppos)457{458	const char *buf = file->private_data;459	size_t len = strlen(buf);460 461	return simple_read_from_buffer(user_buf, count, ppos, buf, len);462}463 464static const struct file_operations fops_bcn_stats = {465	.open = ath11k_open_bcn_stats,466	.release = ath11k_release_bcn_stats,467	.read = ath11k_read_bcn_stats,468	.owner = THIS_MODULE,469	.llseek = default_llseek,470};471 472static ssize_t ath11k_read_simulate_fw_crash(struct file *file,473					     char __user *user_buf,474					     size_t count, loff_t *ppos)475{476	const char buf[] =477		"To simulate firmware crash write one of the keywords to this file:\n"478		"`assert` - this will send WMI_FORCE_FW_HANG_CMDID to firmware to cause assert.\n"479		"`hw-restart` - this will simply queue hw restart without fw/hw actually crashing.\n";480 481	return simple_read_from_buffer(user_buf, count, ppos, buf, strlen(buf));482}483 484/* Simulate firmware crash:485 * 'soft': Call wmi command causing firmware hang. This firmware hang is486 * recoverable by warm firmware reset.487 * 'hard': Force firmware crash by setting any vdev parameter for not allowed488 * vdev id. This is hard firmware crash because it is recoverable only by cold489 * firmware reset.490 */491static ssize_t ath11k_write_simulate_fw_crash(struct file *file,492					      const char __user *user_buf,493					      size_t count, loff_t *ppos)494{495	struct ath11k_base *ab = file->private_data;496	struct ath11k_pdev *pdev;497	struct ath11k *ar = ab->pdevs[0].ar;498	char buf[32] = {0};499	ssize_t rc;500	int i, ret, radioup = 0;501 502	for (i = 0; i < ab->num_radios; i++) {503		pdev = &ab->pdevs[i];504		ar = pdev->ar;505		if (ar && ar->state == ATH11K_STATE_ON) {506			radioup = 1;507			break;508		}509	}510	/* filter partial writes and invalid commands */511	if (*ppos != 0 || count >= sizeof(buf) || count == 0)512		return -EINVAL;513 514	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);515	if (rc < 0)516		return rc;517 518	/* drop the possible '\n' from the end */519	if (buf[*ppos - 1] == '\n')520		buf[*ppos - 1] = '\0';521 522	if (radioup == 0) {523		ret = -ENETDOWN;524		goto exit;525	}526 527	if (!strcmp(buf, "assert")) {528		ath11k_info(ab, "simulating firmware assert crash\n");529		ret = ath11k_wmi_force_fw_hang_cmd(ar,530						   ATH11K_WMI_FW_HANG_ASSERT_TYPE,531						   ATH11K_WMI_FW_HANG_DELAY);532	} else if (!strcmp(buf, "hw-restart")) {533		ath11k_info(ab, "user requested hw restart\n");534		queue_work(ab->workqueue_aux, &ab->reset_work);535		ret = 0;536	} else {537		ret = -EINVAL;538		goto exit;539	}540 541	if (ret) {542		ath11k_warn(ab, "failed to simulate firmware crash: %d\n", ret);543		goto exit;544	}545 546	ret = count;547 548exit:549	return ret;550}551 552static const struct file_operations fops_simulate_fw_crash = {553	.read = ath11k_read_simulate_fw_crash,554	.write = ath11k_write_simulate_fw_crash,555	.open = simple_open,556	.owner = THIS_MODULE,557	.llseek = default_llseek,558};559 560static ssize_t ath11k_write_enable_extd_tx_stats(struct file *file,561						 const char __user *ubuf,562						 size_t count, loff_t *ppos)563{564	struct ath11k *ar = file->private_data;565	u32 filter;566	int ret;567 568	if (kstrtouint_from_user(ubuf, count, 0, &filter))569		return -EINVAL;570 571	mutex_lock(&ar->conf_mutex);572 573	if (ar->state != ATH11K_STATE_ON) {574		ret = -ENETDOWN;575		goto out;576	}577 578	if (filter == ar->debug.extd_tx_stats) {579		ret = count;580		goto out;581	}582 583	ar->debug.extd_tx_stats = filter;584	ret = count;585 586out:587	mutex_unlock(&ar->conf_mutex);588	return ret;589}590 591static ssize_t ath11k_read_enable_extd_tx_stats(struct file *file,592						char __user *ubuf,593						size_t count, loff_t *ppos)594 595{596	char buf[32] = {0};597	struct ath11k *ar = file->private_data;598	int len = 0;599 600	mutex_lock(&ar->conf_mutex);601	len = scnprintf(buf, sizeof(buf) - len, "%08x\n",602			ar->debug.extd_tx_stats);603	mutex_unlock(&ar->conf_mutex);604 605	return simple_read_from_buffer(ubuf, count, ppos, buf, len);606}607 608static const struct file_operations fops_extd_tx_stats = {609	.read = ath11k_read_enable_extd_tx_stats,610	.write = ath11k_write_enable_extd_tx_stats,611	.open = simple_open612};613 614static ssize_t ath11k_write_extd_rx_stats(struct file *file,615					  const char __user *ubuf,616					  size_t count, loff_t *ppos)617{618	struct ath11k *ar = file->private_data;619	struct ath11k_base *ab = ar->ab;620	struct htt_rx_ring_tlv_filter tlv_filter = {0};621	u32 enable, rx_filter = 0, ring_id;622	int i;623	int ret;624 625	if (kstrtouint_from_user(ubuf, count, 0, &enable))626		return -EINVAL;627 628	mutex_lock(&ar->conf_mutex);629 630	if (ar->state != ATH11K_STATE_ON) {631		ret = -ENETDOWN;632		goto exit;633	}634 635	if (enable > 1) {636		ret = -EINVAL;637		goto exit;638	}639 640	if (enable == ar->debug.extd_rx_stats) {641		ret = count;642		goto exit;643	}644 645	if (test_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags)) {646		ar->debug.extd_rx_stats = enable;647		ret = count;648		goto exit;649	}650 651	if (enable) {652		rx_filter =  HTT_RX_FILTER_TLV_FLAGS_MPDU_START;653		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_START;654		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END;655		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS;656		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT;657		rx_filter |= HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE;658 659		tlv_filter.rx_filter = rx_filter;660		tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;661		tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;662		tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;663		tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |664			HTT_RX_FP_DATA_FILTER_FLASG3;665	} else {666		tlv_filter = ath11k_mac_mon_status_filter_default;667	}668 669	ar->debug.rx_filter = tlv_filter.rx_filter;670 671	for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {672		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;673		ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,674						       HAL_RXDMA_MONITOR_STATUS,675						       DP_RX_BUFFER_SIZE, &tlv_filter);676 677		if (ret) {678			ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");679			goto exit;680		}681	}682 683	ar->debug.extd_rx_stats = enable;684	ret = count;685exit:686	mutex_unlock(&ar->conf_mutex);687	return ret;688}689 690static ssize_t ath11k_read_extd_rx_stats(struct file *file,691					 char __user *ubuf,692					 size_t count, loff_t *ppos)693{694	struct ath11k *ar = file->private_data;695	char buf[32];696	int len = 0;697 698	mutex_lock(&ar->conf_mutex);699	len = scnprintf(buf, sizeof(buf) - len, "%d\n",700			ar->debug.extd_rx_stats);701	mutex_unlock(&ar->conf_mutex);702 703	return simple_read_from_buffer(ubuf, count, ppos, buf, len);704}705 706static const struct file_operations fops_extd_rx_stats = {707	.read = ath11k_read_extd_rx_stats,708	.write = ath11k_write_extd_rx_stats,709	.open = simple_open,710};711 712static int ath11k_fill_bp_stats(struct ath11k_base *ab,713				struct ath11k_bp_stats *bp_stats,714				char *buf, int len, int size)715{716	lockdep_assert_held(&ab->base_lock);717 718	len += scnprintf(buf + len, size - len, "count: %u\n",719			 bp_stats->count);720	len += scnprintf(buf + len, size - len, "hp: %u\n",721			 bp_stats->hp);722	len += scnprintf(buf + len, size - len, "tp: %u\n",723			 bp_stats->tp);724	len += scnprintf(buf + len, size - len, "seen before: %ums\n\n",725			 jiffies_to_msecs(jiffies - bp_stats->jiffies));726	return len;727}728 729static ssize_t ath11k_debugfs_dump_soc_ring_bp_stats(struct ath11k_base *ab,730						     char *buf, int size)731{732	struct ath11k_bp_stats *bp_stats;733	bool stats_rxd = false;734	u8 i, pdev_idx;735	int len = 0;736 737	len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n");738	len += scnprintf(buf + len, size - len, "==================\n");739 740	spin_lock_bh(&ab->base_lock);741	for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) {742		bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i];743 744		if (!bp_stats->count)745			continue;746 747		len += scnprintf(buf + len, size - len, "Ring: %s\n",748				 htt_bp_umac_ring[i]);749		len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);750		stats_rxd = true;751	}752 753	for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) {754		for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) {755			bp_stats =756				&ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx];757 758			if (!bp_stats->count)759				continue;760 761			len += scnprintf(buf + len, size - len, "Ring: %s\n",762					 htt_bp_lmac_ring[i]);763			len += scnprintf(buf + len, size - len, "pdev: %d\n",764					 pdev_idx);765			len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);766			stats_rxd = true;767		}768	}769	spin_unlock_bh(&ab->base_lock);770 771	if (!stats_rxd)772		len += scnprintf(buf + len, size - len,773				 "No Ring Backpressure stats received\n\n");774 775	return len;776}777 778static ssize_t ath11k_debugfs_dump_soc_dp_stats(struct file *file,779						char __user *user_buf,780						size_t count, loff_t *ppos)781{782	struct ath11k_base *ab = file->private_data;783	struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats;784	int len = 0, i, retval;785	const int size = 4096;786	static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {787			"Overflow", "MPDU len", "FCS", "Decrypt", "TKIP MIC",788			"Unencrypt", "MSDU len", "MSDU limit", "WiFi parse",789			"AMSDU parse", "SA timeout", "DA timeout",790			"Flow timeout", "Flush req"};791	static const char *reo_err[HAL_REO_DEST_RING_ERROR_CODE_MAX] = {792			"Desc addr zero", "Desc inval", "AMPDU in non BA",793			"Non BA dup", "BA dup", "Frame 2k jump", "BAR 2k jump",794			"Frame OOR", "BAR OOR", "No BA session",795			"Frame SN equal SSN", "PN check fail", "2k err",796			"PN err", "Desc blocked"};797 798	char *buf;799 800	buf = kzalloc(size, GFP_KERNEL);801	if (!buf)802		return -ENOMEM;803 804	len += scnprintf(buf + len, size - len, "SOC RX STATS:\n\n");805	len += scnprintf(buf + len, size - len, "err ring pkts: %u\n",806			 soc_stats->err_ring_pkts);807	len += scnprintf(buf + len, size - len, "Invalid RBM: %u\n\n",808			 soc_stats->invalid_rbm);809	len += scnprintf(buf + len, size - len, "RXDMA errors:\n");810	for (i = 0; i < HAL_REO_ENTR_RING_RXDMA_ECODE_MAX; i++)811		len += scnprintf(buf + len, size - len, "%s: %u\n",812				 rxdma_err[i], soc_stats->rxdma_error[i]);813 814	len += scnprintf(buf + len, size - len, "\nREO errors:\n");815	for (i = 0; i < HAL_REO_DEST_RING_ERROR_CODE_MAX; i++)816		len += scnprintf(buf + len, size - len, "%s: %u\n",817				 reo_err[i], soc_stats->reo_error[i]);818 819	len += scnprintf(buf + len, size - len, "\nHAL REO errors:\n");820	len += scnprintf(buf + len, size - len,821			 "ring0: %u\nring1: %u\nring2: %u\nring3: %u\n",822			 soc_stats->hal_reo_error[0],823			 soc_stats->hal_reo_error[1],824			 soc_stats->hal_reo_error[2],825			 soc_stats->hal_reo_error[3]);826 827	len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n");828	len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");829 830	for (i = 0; i < ab->hw_params.max_tx_ring; i++)831		len += scnprintf(buf + len, size - len, "ring%d: %u\n",832				 i, soc_stats->tx_err.desc_na[i]);833 834	len += scnprintf(buf + len, size - len,835			 "\nMisc Transmit Failures: %d\n",836			 atomic_read(&soc_stats->tx_err.misc_fail));837 838	len += ath11k_debugfs_dump_soc_ring_bp_stats(ab, buf + len, size - len);839 840	if (len > size)841		len = size;842	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);843	kfree(buf);844 845	return retval;846}847 848static const struct file_operations fops_soc_dp_stats = {849	.read = ath11k_debugfs_dump_soc_dp_stats,850	.open = simple_open,851	.owner = THIS_MODULE,852	.llseek = default_llseek,853};854 855static ssize_t ath11k_write_fw_dbglog(struct file *file,856				      const char __user *user_buf,857				      size_t count, loff_t *ppos)858{859	struct ath11k *ar = file->private_data;860	char buf[128] = {0};861	struct ath11k_fw_dbglog dbglog;862	unsigned int param, mod_id_index, is_end;863	u64 value;864	int ret, num;865 866	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,867				     user_buf, count);868	if (ret <= 0)869		return ret;870 871	num = sscanf(buf, "%u %llx %u %u", &param, &value, &mod_id_index, &is_end);872 873	if (num < 2)874		return -EINVAL;875 876	mutex_lock(&ar->conf_mutex);877	if (param == WMI_DEBUG_LOG_PARAM_MOD_ENABLE_BITMAP ||878	    param == WMI_DEBUG_LOG_PARAM_WOW_MOD_ENABLE_BITMAP) {879		if (num != 4 || mod_id_index > (MAX_MODULE_ID_BITMAP_WORDS - 1)) {880			ret = -EINVAL;881			goto out;882		}883		ar->debug.module_id_bitmap[mod_id_index] = upper_32_bits(value);884		if (!is_end) {885			ret = count;886			goto out;887		}888	} else {889		if (num != 2) {890			ret = -EINVAL;891			goto out;892		}893	}894 895	dbglog.param = param;896	dbglog.value = lower_32_bits(value);897	ret = ath11k_wmi_fw_dbglog_cfg(ar, ar->debug.module_id_bitmap, &dbglog);898	if (ret) {899		ath11k_warn(ar->ab, "fw dbglog config failed from debugfs: %d\n",900			    ret);901		goto out;902	}903 904	ret = count;905 906out:907	mutex_unlock(&ar->conf_mutex);908	return ret;909}910 911static const struct file_operations fops_fw_dbglog = {912	.write = ath11k_write_fw_dbglog,913	.open = simple_open,914	.owner = THIS_MODULE,915	.llseek = default_llseek,916};917 918static int ath11k_open_sram_dump(struct inode *inode, struct file *file)919{920	struct ath11k_base *ab = inode->i_private;921	u8 *buf;922	u32 start, end;923	int ret;924 925	start = ab->hw_params.sram_dump.start;926	end = ab->hw_params.sram_dump.end;927 928	buf = vmalloc(end - start + 1);929	if (!buf)930		return -ENOMEM;931 932	ret = ath11k_hif_read(ab, buf, start, end);933	if (ret) {934		ath11k_warn(ab, "failed to dump sram: %d\n", ret);935		vfree(buf);936		return ret;937	}938 939	file->private_data = buf;940	return 0;941}942 943static ssize_t ath11k_read_sram_dump(struct file *file,944				     char __user *user_buf,945				     size_t count, loff_t *ppos)946{947	struct ath11k_base *ab = file->f_inode->i_private;948	const char *buf = file->private_data;949	int len;950	u32 start, end;951 952	start = ab->hw_params.sram_dump.start;953	end = ab->hw_params.sram_dump.end;954	len = end - start + 1;955 956	return simple_read_from_buffer(user_buf, count, ppos, buf, len);957}958 959static int ath11k_release_sram_dump(struct inode *inode, struct file *file)960{961	vfree(file->private_data);962	file->private_data = NULL;963 964	return 0;965}966 967static const struct file_operations fops_sram_dump = {968	.open = ath11k_open_sram_dump,969	.read = ath11k_read_sram_dump,970	.release = ath11k_release_sram_dump,971	.owner = THIS_MODULE,972	.llseek = default_llseek,973};974 975int ath11k_debugfs_pdev_create(struct ath11k_base *ab)976{977	if (test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))978		return 0;979 980	debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,981			    &fops_simulate_fw_crash);982 983	debugfs_create_file("soc_dp_stats", 0400, ab->debugfs_soc, ab,984			    &fops_soc_dp_stats);985 986	if (ab->hw_params.sram_dump.start != 0)987		debugfs_create_file("sram", 0400, ab->debugfs_soc, ab,988				    &fops_sram_dump);989 990	return 0;991}992 993void ath11k_debugfs_pdev_destroy(struct ath11k_base *ab)994{995	debugfs_remove_recursive(ab->debugfs_soc);996	ab->debugfs_soc = NULL;997}998 999int ath11k_debugfs_soc_create(struct ath11k_base *ab)1000{1001	struct dentry *root;1002	bool dput_needed;1003	char name[64];1004	int ret;1005 1006	root = debugfs_lookup("ath11k", NULL);1007	if (!root) {1008		root = debugfs_create_dir("ath11k", NULL);1009		if (IS_ERR_OR_NULL(root))1010			return PTR_ERR(root);1011 1012		dput_needed = false;1013	} else {1014		/* a dentry from lookup() needs dput() after we don't use it */1015		dput_needed = true;1016	}1017 1018	scnprintf(name, sizeof(name), "%s-%s", ath11k_bus_str(ab->hif.bus),1019		  dev_name(ab->dev));1020 1021	ab->debugfs_soc = debugfs_create_dir(name, root);1022	if (IS_ERR_OR_NULL(ab->debugfs_soc)) {1023		ret = PTR_ERR(ab->debugfs_soc);1024		goto out;1025	}1026 1027	ret = 0;1028 1029out:1030	if (dput_needed)1031		dput(root);1032 1033	return ret;1034}1035 1036void ath11k_debugfs_soc_destroy(struct ath11k_base *ab)1037{1038	debugfs_remove_recursive(ab->debugfs_soc);1039	ab->debugfs_soc = NULL;1040 1041	/* We are not removing ath11k directory on purpose, even if it1042	 * would be empty. This simplifies the directory handling and it's1043	 * a minor cosmetic issue to leave an empty ath11k directory to1044	 * debugfs.1045	 */1046}1047EXPORT_SYMBOL(ath11k_debugfs_soc_destroy);1048 1049void ath11k_debugfs_fw_stats_init(struct ath11k *ar)1050{1051	struct dentry *fwstats_dir = debugfs_create_dir("fw_stats",1052							ar->debug.debugfs_pdev);1053 1054	ar->fw_stats.debugfs_fwstats = fwstats_dir;1055 1056	/* all stats debugfs files created are under "fw_stats" directory1057	 * created per PDEV1058	 */1059	debugfs_create_file("pdev_stats", 0600, fwstats_dir, ar,1060			    &fops_pdev_stats);1061	debugfs_create_file("vdev_stats", 0600, fwstats_dir, ar,1062			    &fops_vdev_stats);1063	debugfs_create_file("beacon_stats", 0600, fwstats_dir, ar,1064			    &fops_bcn_stats);1065}1066 1067static ssize_t ath11k_write_pktlog_filter(struct file *file,1068					  const char __user *ubuf,1069					  size_t count, loff_t *ppos)1070{1071	struct ath11k *ar = file->private_data;1072	struct ath11k_base *ab = ar->ab;1073	struct htt_rx_ring_tlv_filter tlv_filter = {0};1074	u32 rx_filter = 0, ring_id, filter, mode;1075	u8 buf[128] = {0};1076	int i, ret, rx_buf_sz = 0;1077	ssize_t rc;1078 1079	mutex_lock(&ar->conf_mutex);1080	if (ar->state != ATH11K_STATE_ON) {1081		ret = -ENETDOWN;1082		goto out;1083	}1084 1085	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);1086	if (rc < 0) {1087		ret = rc;1088		goto out;1089	}1090	buf[rc] = '\0';1091 1092	ret = sscanf(buf, "0x%x %u", &filter, &mode);1093	if (ret != 2) {1094		ret = -EINVAL;1095		goto out;1096	}1097 1098	if (filter) {1099		ret = ath11k_wmi_pdev_pktlog_enable(ar, filter);1100		if (ret) {1101			ath11k_warn(ar->ab,1102				    "failed to enable pktlog filter %x: %d\n",1103				    ar->debug.pktlog_filter, ret);1104			goto out;1105		}1106	} else {1107		ret = ath11k_wmi_pdev_pktlog_disable(ar);1108		if (ret) {1109			ath11k_warn(ar->ab, "failed to disable pktlog: %d\n", ret);1110			goto out;1111		}1112	}1113 1114	/* Clear rx filter set for monitor mode and rx status */1115	for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {1116		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;1117		ret = ath11k_dp_tx_htt_rx_filter_setup(ar->ab, ring_id, ar->dp.mac_id,1118						       HAL_RXDMA_MONITOR_STATUS,1119						       rx_buf_sz, &tlv_filter);1120		if (ret) {1121			ath11k_warn(ar->ab, "failed to set rx filter for monitor status ring\n");1122			goto out;1123		}1124	}1125#define HTT_RX_FILTER_TLV_LITE_MODE \1126			(HTT_RX_FILTER_TLV_FLAGS_PPDU_START | \1127			HTT_RX_FILTER_TLV_FLAGS_PPDU_END | \1128			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS | \1129			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_USER_STATS_EXT | \1130			HTT_RX_FILTER_TLV_FLAGS_PPDU_END_STATUS_DONE | \1131			HTT_RX_FILTER_TLV_FLAGS_MPDU_START)1132 1133	if (mode == ATH11K_PKTLOG_MODE_FULL) {1134		rx_filter = HTT_RX_FILTER_TLV_LITE_MODE |1135			    HTT_RX_FILTER_TLV_FLAGS_MSDU_START |1136			    HTT_RX_FILTER_TLV_FLAGS_MSDU_END |1137			    HTT_RX_FILTER_TLV_FLAGS_MPDU_END |1138			    HTT_RX_FILTER_TLV_FLAGS_PACKET_HEADER |1139			    HTT_RX_FILTER_TLV_FLAGS_ATTENTION;1140		rx_buf_sz = DP_RX_BUFFER_SIZE;1141	} else if (mode == ATH11K_PKTLOG_MODE_LITE) {1142		ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,1143							  HTT_PPDU_STATS_TAG_PKTLOG);1144		if (ret) {1145			ath11k_err(ar->ab, "failed to enable pktlog lite: %d\n", ret);1146			goto out;1147		}1148 1149		rx_filter = HTT_RX_FILTER_TLV_LITE_MODE;1150		rx_buf_sz = DP_RX_BUFFER_SIZE_LITE;1151	} else {1152		rx_buf_sz = DP_RX_BUFFER_SIZE;1153		tlv_filter = ath11k_mac_mon_status_filter_default;1154		rx_filter = tlv_filter.rx_filter;1155 1156		ret = ath11k_dp_tx_htt_h2t_ppdu_stats_req(ar,1157							  HTT_PPDU_STATS_TAG_DEFAULT);1158		if (ret) {1159			ath11k_err(ar->ab, "failed to send htt ppdu stats req: %d\n",1160				   ret);1161			goto out;1162		}1163	}1164 1165	tlv_filter.rx_filter = rx_filter;1166	if (rx_filter) {1167		tlv_filter.pkt_filter_flags0 = HTT_RX_FP_MGMT_FILTER_FLAGS0;1168		tlv_filter.pkt_filter_flags1 = HTT_RX_FP_MGMT_FILTER_FLAGS1;1169		tlv_filter.pkt_filter_flags2 = HTT_RX_FP_CTRL_FILTER_FLASG2;1170		tlv_filter.pkt_filter_flags3 = HTT_RX_FP_CTRL_FILTER_FLASG3 |1171					       HTT_RX_FP_DATA_FILTER_FLASG3;1172	}1173 1174	for (i = 0; i < ab->hw_params.num_rxdma_per_pdev; i++) {1175		ring_id = ar->dp.rx_mon_status_refill_ring[i].refill_buf_ring.ring_id;1176		ret = ath11k_dp_tx_htt_rx_filter_setup(ab, ring_id,1177						       ar->dp.mac_id + i,1178						       HAL_RXDMA_MONITOR_STATUS,1179						       rx_buf_sz, &tlv_filter);1180 1181		if (ret) {1182			ath11k_warn(ab, "failed to set rx filter for monitor status ring\n");1183			goto out;1184		}1185	}1186 1187	ath11k_info(ab, "pktlog mode %s\n",1188		    ((mode == ATH11K_PKTLOG_MODE_FULL) ? "full" : "lite"));1189 1190	ar->debug.pktlog_filter = filter;1191	ar->debug.pktlog_mode = mode;1192	ret = count;1193 1194out:1195	mutex_unlock(&ar->conf_mutex);1196	return ret;1197}1198 1199static ssize_t ath11k_read_pktlog_filter(struct file *file,1200					 char __user *ubuf,1201					 size_t count, loff_t *ppos)1202 1203{1204	char buf[32] = {0};1205	struct ath11k *ar = file->private_data;1206	int len = 0;1207 1208	mutex_lock(&ar->conf_mutex);1209	len = scnprintf(buf, sizeof(buf) - len, "%08x %08x\n",1210			ar->debug.pktlog_filter,1211			ar->debug.pktlog_mode);1212	mutex_unlock(&ar->conf_mutex);1213 1214	return simple_read_from_buffer(ubuf, count, ppos, buf, len);1215}1216 1217static const struct file_operations fops_pktlog_filter = {1218	.read = ath11k_read_pktlog_filter,1219	.write = ath11k_write_pktlog_filter,1220	.open = simple_open1221};1222 1223static ssize_t ath11k_write_simulate_radar(struct file *file,1224					   const char __user *user_buf,1225					   size_t count, loff_t *ppos)1226{1227	struct ath11k *ar = file->private_data;1228	int ret;1229 1230	ret = ath11k_wmi_simulate_radar(ar);1231	if (ret)1232		return ret;1233 1234	return count;1235}1236 1237static const struct file_operations fops_simulate_radar = {1238	.write = ath11k_write_simulate_radar,1239	.open = simple_open1240};1241 1242static ssize_t ath11k_debug_dump_dbr_entries(struct file *file,1243					     char __user *user_buf,1244					     size_t count, loff_t *ppos)1245{1246	struct ath11k_dbg_dbr_data *dbr_dbg_data = file->private_data;1247	static const char * const event_id_to_string[] = {"empty", "Rx", "Replenish"};1248	int size = ATH11K_DEBUG_DBR_ENTRIES_MAX * 100;1249	char *buf;1250	int i, ret;1251	int len = 0;1252 1253	buf = kzalloc(size, GFP_KERNEL);1254	if (!buf)1255		return -ENOMEM;1256 1257	len += scnprintf(buf + len, size - len,1258			 "-----------------------------------------\n");1259	len += scnprintf(buf + len, size - len,1260			 "| idx |  hp  |  tp  | timestamp |  event |\n");1261	len += scnprintf(buf + len, size - len,1262			 "-----------------------------------------\n");1263 1264	spin_lock_bh(&dbr_dbg_data->lock);1265 1266	for (i = 0; i < dbr_dbg_data->num_ring_debug_entries; i++) {1267		len += scnprintf(buf + len, size - len,1268				 "|%4u|%8u|%8u|%11llu|%8s|\n", i,1269				 dbr_dbg_data->entries[i].hp,1270				 dbr_dbg_data->entries[i].tp,1271				 dbr_dbg_data->entries[i].timestamp,1272				 event_id_to_string[dbr_dbg_data->entries[i].event]);1273	}1274 1275	spin_unlock_bh(&dbr_dbg_data->lock);1276 1277	ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);1278	kfree(buf);1279 1280	return ret;1281}1282 1283static const struct file_operations fops_debug_dump_dbr_entries = {1284	.read = ath11k_debug_dump_dbr_entries,1285	.open = simple_open,1286	.owner = THIS_MODULE,1287	.llseek = default_llseek,1288};1289 1290static void ath11k_debugfs_dbr_dbg_destroy(struct ath11k *ar, int dbr_id)1291{1292	struct ath11k_debug_dbr *dbr_debug;1293	struct ath11k_dbg_dbr_data *dbr_dbg_data;1294 1295	if (!ar->debug.dbr_debug[dbr_id])1296		return;1297 1298	dbr_debug = ar->debug.dbr_debug[dbr_id];1299	dbr_dbg_data = &dbr_debug->dbr_dbg_data;1300 1301	debugfs_remove_recursive(dbr_debug->dbr_debugfs);1302	kfree(dbr_dbg_data->entries);1303	kfree(dbr_debug);1304	ar->debug.dbr_debug[dbr_id] = NULL;1305}1306 1307static int ath11k_debugfs_dbr_dbg_init(struct ath11k *ar, int dbr_id)1308{1309	struct ath11k_debug_dbr *dbr_debug;1310	struct ath11k_dbg_dbr_data *dbr_dbg_data;1311	static const char * const dbr_id_to_str[] = {"spectral", "CFR"};1312 1313	if (ar->debug.dbr_debug[dbr_id])1314		return 0;1315 1316	ar->debug.dbr_debug[dbr_id] = kzalloc(sizeof(*dbr_debug),1317					      GFP_KERNEL);1318 1319	if (!ar->debug.dbr_debug[dbr_id])1320		return -ENOMEM;1321 1322	dbr_debug = ar->debug.dbr_debug[dbr_id];1323	dbr_dbg_data = &dbr_debug->dbr_dbg_data;1324 1325	if (dbr_debug->dbr_debugfs)1326		return 0;1327 1328	dbr_debug->dbr_debugfs = debugfs_create_dir(dbr_id_to_str[dbr_id],1329						    ar->debug.debugfs_pdev);1330	if (IS_ERR_OR_NULL(dbr_debug->dbr_debugfs)) {1331		if (IS_ERR(dbr_debug->dbr_debugfs))1332			return PTR_ERR(dbr_debug->dbr_debugfs);1333		return -ENOMEM;1334	}1335 1336	dbr_debug->dbr_debug_enabled = true;1337	dbr_dbg_data->num_ring_debug_entries = ATH11K_DEBUG_DBR_ENTRIES_MAX;1338	dbr_dbg_data->dbr_debug_idx = 0;1339	dbr_dbg_data->entries = kcalloc(ATH11K_DEBUG_DBR_ENTRIES_MAX,1340					sizeof(struct ath11k_dbg_dbr_entry),1341					GFP_KERNEL);1342	if (!dbr_dbg_data->entries)1343		return -ENOMEM;1344 1345	spin_lock_init(&dbr_dbg_data->lock);1346 1347	debugfs_create_file("dump_dbr_debug", 0444, dbr_debug->dbr_debugfs,1348			    dbr_dbg_data, &fops_debug_dump_dbr_entries);1349 1350	return 0;1351}1352 1353static ssize_t ath11k_debugfs_write_enable_dbr_dbg(struct file *file,1354						   const char __user *ubuf,1355						   size_t count, loff_t *ppos)1356{1357	struct ath11k *ar = file->private_data;1358	char buf[32] = {0};1359	u32 dbr_id, enable;1360	int ret;1361 1362	mutex_lock(&ar->conf_mutex);1363 1364	if (ar->state != ATH11K_STATE_ON) {1365		ret = -ENETDOWN;1366		goto out;1367	}1368 1369	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);1370	if (ret < 0)1371		goto out;1372 1373	buf[ret] = '\0';1374	ret = sscanf(buf, "%u %u", &dbr_id, &enable);1375	if (ret != 2 || dbr_id > 1 || enable > 1) {1376		ret = -EINVAL;1377		ath11k_warn(ar->ab, "usage: echo <dbr_id> <val> dbr_id:0-Spectral 1-CFR val:0-disable 1-enable\n");1378		goto out;1379	}1380 1381	if (enable) {1382		ret = ath11k_debugfs_dbr_dbg_init(ar, dbr_id);1383		if (ret) {1384			ath11k_warn(ar->ab, "db ring module debugfs init failed: %d\n",1385				    ret);1386			goto out;1387		}1388	} else {1389		ath11k_debugfs_dbr_dbg_destroy(ar, dbr_id);1390	}1391 1392	ret = count;1393out:1394	mutex_unlock(&ar->conf_mutex);1395	return ret;1396}1397 1398static const struct file_operations fops_dbr_debug = {1399	.write = ath11k_debugfs_write_enable_dbr_dbg,1400	.open = simple_open,1401	.owner = THIS_MODULE,1402	.llseek = default_llseek,1403};1404 1405static ssize_t ath11k_write_ps_timekeeper_enable(struct file *file,1406						 const char __user *user_buf,1407						 size_t count, loff_t *ppos)1408{1409	struct ath11k *ar = file->private_data;1410	ssize_t ret;1411	u8 ps_timekeeper_enable;1412 1413	if (kstrtou8_from_user(user_buf, count, 0, &ps_timekeeper_enable))1414		return -EINVAL;1415 1416	mutex_lock(&ar->conf_mutex);1417 1418	if (ar->state != ATH11K_STATE_ON) {1419		ret = -ENETDOWN;1420		goto exit;1421	}1422 1423	if (!ar->ps_state_enable) {1424		ret = -EINVAL;1425		goto exit;1426	}1427 1428	ar->ps_timekeeper_enable = !!ps_timekeeper_enable;1429	ret = count;1430exit:1431	mutex_unlock(&ar->conf_mutex);1432 1433	return ret;1434}1435 1436static ssize_t ath11k_read_ps_timekeeper_enable(struct file *file,1437						char __user *user_buf,1438						size_t count, loff_t *ppos)1439{1440	struct ath11k *ar = file->private_data;1441	char buf[32];1442	int len;1443 1444	mutex_lock(&ar->conf_mutex);1445	len = scnprintf(buf, sizeof(buf), "%d\n", ar->ps_timekeeper_enable);1446	mutex_unlock(&ar->conf_mutex);1447 1448	return simple_read_from_buffer(user_buf, count, ppos, buf, len);1449}1450 1451static const struct file_operations fops_ps_timekeeper_enable = {1452	.read = ath11k_read_ps_timekeeper_enable,1453	.write = ath11k_write_ps_timekeeper_enable,1454	.open = simple_open,1455	.owner = THIS_MODULE,1456	.llseek = default_llseek,1457};1458 1459static void ath11k_reset_peer_ps_duration(void *data,1460					  struct ieee80211_sta *sta)1461{1462	struct ath11k *ar = data;1463	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);1464 1465	spin_lock_bh(&ar->data_lock);1466	arsta->ps_total_duration = 0;1467	spin_unlock_bh(&ar->data_lock);1468}1469 1470static ssize_t ath11k_write_reset_ps_duration(struct file *file,1471					      const  char __user *user_buf,1472					      size_t count, loff_t *ppos)1473{1474	struct ath11k *ar = file->private_data;1475	int ret;1476	u8 reset_ps_duration;1477 1478	if (kstrtou8_from_user(user_buf, count, 0, &reset_ps_duration))1479		return -EINVAL;1480 1481	mutex_lock(&ar->conf_mutex);1482 1483	if (ar->state != ATH11K_STATE_ON) {1484		ret = -ENETDOWN;1485		goto exit;1486	}1487 1488	if (!ar->ps_state_enable) {1489		ret = -EINVAL;1490		goto exit;1491	}1492 1493	ieee80211_iterate_stations_atomic(ar->hw,1494					  ath11k_reset_peer_ps_duration,1495					  ar);1496 1497	ret = count;1498exit:1499	mutex_unlock(&ar->conf_mutex);1500	return ret;1501}1502 1503static const struct file_operations fops_reset_ps_duration = {1504	.write = ath11k_write_reset_ps_duration,1505	.open = simple_open,1506	.owner = THIS_MODULE,1507	.llseek = default_llseek,1508};1509 1510static void ath11k_peer_ps_state_disable(void *data,1511					 struct ieee80211_sta *sta)1512{1513	struct ath11k *ar = data;1514	struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta);1515 1516	spin_lock_bh(&ar->data_lock);1517	arsta->peer_ps_state = WMI_PEER_PS_STATE_DISABLED;1518	arsta->ps_start_time = 0;1519	arsta->ps_total_duration = 0;1520	spin_unlock_bh(&ar->data_lock);1521}1522 1523static ssize_t ath11k_write_ps_state_enable(struct file *file,1524					    const char __user *user_buf,1525					    size_t count, loff_t *ppos)1526{1527	struct ath11k *ar = file->private_data;1528	struct ath11k_pdev *pdev = ar->pdev;1529	int ret;1530	u32 param;1531	u8 ps_state_enable;1532 1533	if (kstrtou8_from_user(user_buf, count, 0, &ps_state_enable))1534		return -EINVAL;1535 1536	mutex_lock(&ar->conf_mutex);1537 1538	ps_state_enable = !!ps_state_enable;1539 1540	if (ar->ps_state_enable == ps_state_enable) {1541		ret = count;1542		goto exit;1543	}1544 1545	param = WMI_PDEV_PEER_STA_PS_STATECHG_ENABLE;1546	ret = ath11k_wmi_pdev_set_param(ar, param, ps_state_enable, pdev->pdev_id);1547	if (ret) {1548		ath11k_warn(ar->ab, "failed to enable ps_state_enable: %d\n",1549			    ret);1550		goto exit;1551	}1552	ar->ps_state_enable = ps_state_enable;1553 1554	if (!ar->ps_state_enable) {1555		ar->ps_timekeeper_enable = false;1556		ieee80211_iterate_stations_atomic(ar->hw,1557						  ath11k_peer_ps_state_disable,1558						  ar);1559	}1560 1561	ret = count;1562 1563exit:1564	mutex_unlock(&ar->conf_mutex);1565 1566	return ret;1567}1568 1569static ssize_t ath11k_read_ps_state_enable(struct file *file,1570					   char __user *user_buf,1571					   size_t count, loff_t *ppos)1572{1573	struct ath11k *ar = file->private_data;1574	char buf[32];1575	int len;1576 1577	mutex_lock(&ar->conf_mutex);1578	len = scnprintf(buf, sizeof(buf), "%d\n", ar->ps_state_enable);1579	mutex_unlock(&ar->conf_mutex);1580 1581	return simple_read_from_buffer(user_buf, count, ppos, buf, len);1582}1583 1584static const struct file_operations fops_ps_state_enable = {1585	.read = ath11k_read_ps_state_enable,1586	.write = ath11k_write_ps_state_enable,1587	.open = simple_open,1588	.owner = THIS_MODULE,1589	.llseek = default_llseek,1590};1591 1592int ath11k_debugfs_register(struct ath11k *ar)1593{1594	struct ath11k_base *ab = ar->ab;1595	char pdev_name[10];1596	char buf[100] = {0};1597 1598	snprintf(pdev_name, sizeof(pdev_name), "%s%u", "mac", ar->pdev_idx);1599 1600	ar->debug.debugfs_pdev = debugfs_create_dir(pdev_name, ab->debugfs_soc);1601	if (IS_ERR(ar->debug.debugfs_pdev))1602		return PTR_ERR(ar->debug.debugfs_pdev);1603 1604	/* Create a symlink under ieee80211/phy* */1605	snprintf(buf, 100, "../../ath11k/%pd2", ar->debug.debugfs_pdev);1606	debugfs_create_symlink("ath11k", ar->hw->wiphy->debugfsdir, buf);1607 1608	ath11k_debugfs_htt_stats_init(ar);1609 1610	ath11k_debugfs_fw_stats_init(ar);1611 1612	debugfs_create_file("ext_tx_stats", 0644,1613			    ar->debug.debugfs_pdev, ar,1614			    &fops_extd_tx_stats);1615	debugfs_create_file("ext_rx_stats", 0644,1616			    ar->debug.debugfs_pdev, ar,1617			    &fops_extd_rx_stats);1618	debugfs_create_file("pktlog_filter", 0644,1619			    ar->debug.debugfs_pdev, ar,1620			    &fops_pktlog_filter);1621	debugfs_create_file("fw_dbglog_config", 0600,1622			    ar->debug.debugfs_pdev, ar,1623			    &fops_fw_dbglog);1624 1625	if (ar->hw->wiphy->bands[NL80211_BAND_5GHZ]) {1626		debugfs_create_file("dfs_simulate_radar", 0200,1627				    ar->debug.debugfs_pdev, ar,1628				    &fops_simulate_radar);1629		debugfs_create_bool("dfs_block_radar_events", 0200,1630				    ar->debug.debugfs_pdev,1631				    &ar->dfs_block_radar_events);1632	}1633 1634	if (ab->hw_params.dbr_debug_support)1635		debugfs_create_file("enable_dbr_debug", 0200, ar->debug.debugfs_pdev,1636				    ar, &fops_dbr_debug);1637 1638	debugfs_create_file("ps_state_enable", 0600, ar->debug.debugfs_pdev, ar,1639			    &fops_ps_state_enable);1640 1641	if (test_bit(WMI_TLV_SERVICE_PEER_POWER_SAVE_DURATION_SUPPORT,1642		     ar->ab->wmi_ab.svc_map)) {1643		debugfs_create_file("ps_timekeeper_enable", 0600,1644				    ar->debug.debugfs_pdev, ar,1645				    &fops_ps_timekeeper_enable);1646 1647		debugfs_create_file("reset_ps_duration", 0200,1648				    ar->debug.debugfs_pdev, ar,1649				    &fops_reset_ps_duration);1650	}1651 1652	return 0;1653}1654 1655void ath11k_debugfs_unregister(struct ath11k *ar)1656{1657	struct ath11k_debug_dbr *dbr_debug;1658	struct ath11k_dbg_dbr_data *dbr_dbg_data;1659	int i;1660 1661	for (i = 0; i < WMI_DIRECT_BUF_MAX; i++) {1662		dbr_debug = ar->debug.dbr_debug[i];1663		if (!dbr_debug)1664			continue;1665 1666		dbr_dbg_data = &dbr_debug->dbr_dbg_data;1667		kfree(dbr_dbg_data->entries);1668		debugfs_remove_recursive(dbr_debug->dbr_debugfs);1669		kfree(dbr_debug);1670		ar->debug.dbr_debug[i] = NULL;1671	}1672}1673 1674static ssize_t ath11k_write_twt_add_dialog(struct file *file,1675					   const char __user *ubuf,1676					   size_t count, loff_t *ppos)1677{1678	struct ath11k_vif *arvif = file->private_data;1679	struct wmi_twt_add_dialog_params params = { 0 };1680	struct wmi_twt_enable_params twt_params = {0};1681	struct ath11k *ar = arvif->ar;1682	u8 buf[128] = {0};1683	int ret;1684 1685	if (ar->twt_enabled == 0) {1686		ath11k_err(ar->ab, "twt support is not enabled\n");1687		return -EOPNOTSUPP;1688	}1689 1690	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);1691	if (ret < 0)1692		return ret;1693 1694	buf[ret] = '\0';1695	ret = sscanf(buf,1696		     "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u %u %u %hhu %hhu %hhu %hhu %hhu",1697		     &params.peer_macaddr[0],1698		     &params.peer_macaddr[1],1699		     &params.peer_macaddr[2],1700		     &params.peer_macaddr[3],1701		     &params.peer_macaddr[4],1702		     &params.peer_macaddr[5],1703		     &params.dialog_id,1704		     &params.wake_intvl_us,1705		     &params.wake_intvl_mantis,1706		     &params.wake_dura_us,1707		     &params.sp_offset_us,1708		     &params.twt_cmd,1709		     &params.flag_bcast,1710		     &params.flag_trigger,1711		     &params.flag_flow_type,1712		     &params.flag_protection);1713	if (ret != 16)1714		return -EINVAL;1715 1716	/* In the case of station vif, TWT is entirely handled by1717	 * the firmware based on the input parameters in the TWT enable1718	 * WMI command that is sent to the target during assoc.1719	 * For manually testing the TWT feature, we need to first disable1720	 * TWT and send enable command again with TWT input parameter1721	 * sta_cong_timer_ms set to 0.1722	 */1723	if (arvif->vif->type == NL80211_IFTYPE_STATION) {1724		ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);1725 1726		ath11k_wmi_fill_default_twt_params(&twt_params);1727		twt_params.sta_cong_timer_ms = 0;1728 1729		ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);1730	}1731 1732	params.vdev_id = arvif->vdev_id;1733 1734	ret = ath11k_wmi_send_twt_add_dialog_cmd(arvif->ar, &params);1735	if (ret)1736		goto err_twt_add_dialog;1737 1738	return count;1739 1740err_twt_add_dialog:1741	if (arvif->vif->type == NL80211_IFTYPE_STATION) {1742		ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);1743		ath11k_wmi_fill_default_twt_params(&twt_params);1744		ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);1745	}1746 1747	return ret;1748}1749 1750static ssize_t ath11k_write_twt_del_dialog(struct file *file,1751					   const char __user *ubuf,1752					   size_t count, loff_t *ppos)1753{1754	struct ath11k_vif *arvif = file->private_data;1755	struct wmi_twt_del_dialog_params params = { 0 };1756	struct wmi_twt_enable_params twt_params = {0};1757	struct ath11k *ar = arvif->ar;1758	u8 buf[64] = {0};1759	int ret;1760 1761	if (ar->twt_enabled == 0) {1762		ath11k_err(ar->ab, "twt support is not enabled\n");1763		return -EOPNOTSUPP;1764	}1765 1766	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);1767	if (ret < 0)1768		return ret;1769 1770	buf[ret] = '\0';1771	ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u",1772		     &params.peer_macaddr[0],1773		     &params.peer_macaddr[1],1774		     &params.peer_macaddr[2],1775		     &params.peer_macaddr[3],1776		     &params.peer_macaddr[4],1777		     &params.peer_macaddr[5],1778		     &params.dialog_id);1779	if (ret != 7)1780		return -EINVAL;1781 1782	params.vdev_id = arvif->vdev_id;1783 1784	ret = ath11k_wmi_send_twt_del_dialog_cmd(arvif->ar, &params);1785	if (ret)1786		return ret;1787 1788	if (arvif->vif->type == NL80211_IFTYPE_STATION) {1789		ath11k_wmi_send_twt_disable_cmd(ar, ar->pdev->pdev_id);1790		ath11k_wmi_fill_default_twt_params(&twt_params);1791		ath11k_wmi_send_twt_enable_cmd(ar, ar->pdev->pdev_id, &twt_params);1792	}1793 1794	return count;1795}1796 1797static ssize_t ath11k_write_twt_pause_dialog(struct file *file,1798					     const char __user *ubuf,1799					     size_t count, loff_t *ppos)1800{1801	struct ath11k_vif *arvif = file->private_data;1802	struct wmi_twt_pause_dialog_params params = { 0 };1803	u8 buf[64] = {0};1804	int ret;1805 1806	if (arvif->ar->twt_enabled == 0) {1807		ath11k_err(arvif->ar->ab, "twt support is not enabled\n");1808		return -EOPNOTSUPP;1809	}1810 1811	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);1812	if (ret < 0)1813		return ret;1814 1815	buf[ret] = '\0';1816	ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u",1817		     &params.peer_macaddr[0],1818		     &params.peer_macaddr[1],1819		     &params.peer_macaddr[2],1820		     &params.peer_macaddr[3],1821		     &params.peer_macaddr[4],1822		     &params.peer_macaddr[5],1823		     &params.dialog_id);1824	if (ret != 7)1825		return -EINVAL;1826 1827	params.vdev_id = arvif->vdev_id;1828 1829	ret = ath11k_wmi_send_twt_pause_dialog_cmd(arvif->ar, &params);1830	if (ret)1831		return ret;1832 1833	return count;1834}1835 1836static ssize_t ath11k_write_twt_resume_dialog(struct file *file,1837					      const char __user *ubuf,1838					      size_t count, loff_t *ppos)1839{1840	struct ath11k_vif *arvif = file->private_data;1841	struct wmi_twt_resume_dialog_params params = { 0 };1842	u8 buf[64] = {0};1843	int ret;1844 1845	if (arvif->ar->twt_enabled == 0) {1846		ath11k_err(arvif->ar->ab, "twt support is not enabled\n");1847		return -EOPNOTSUPP;1848	}1849 1850	ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, ubuf, count);1851	if (ret < 0)1852		return ret;1853 1854	buf[ret] = '\0';1855	ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx %u %u %u",1856		     &params.peer_macaddr[0],1857		     &params.peer_macaddr[1],1858		     &params.peer_macaddr[2],1859		     &params.peer_macaddr[3],1860		     &params.peer_macaddr[4],1861		     &params.peer_macaddr[5],1862		     &params.dialog_id,1863		     &params.sp_offset_us,1864		     &params.next_twt_size);1865	if (ret != 9)1866		return -EINVAL;1867 1868	params.vdev_id = arvif->vdev_id;1869 1870	ret = ath11k_wmi_send_twt_resume_dialog_cmd(arvif->ar, &params);1871	if (ret)1872		return ret;1873 1874	return count;1875}1876 1877static const struct file_operations ath11k_fops_twt_add_dialog = {1878	.write = ath11k_write_twt_add_dialog,1879	.open = simple_open1880};1881 1882static const struct file_operations ath11k_fops_twt_del_dialog = {1883	.write = ath11k_write_twt_del_dialog,1884	.open = simple_open1885};1886 1887static const struct file_operations ath11k_fops_twt_pause_dialog = {1888	.write = ath11k_write_twt_pause_dialog,1889	.open = simple_open1890};1891 1892static const struct file_operations ath11k_fops_twt_resume_dialog = {1893	.write = ath11k_write_twt_resume_dialog,1894	.open = simple_open1895};1896 1897void ath11k_debugfs_op_vif_add(struct ieee80211_hw *hw,1898			       struct ieee80211_vif *vif)1899{1900	struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);1901	struct ath11k_base *ab = arvif->ar->ab;1902	struct dentry *debugfs_twt;1903 1904	if (arvif->vif->type != NL80211_IFTYPE_AP &&1905	    !(arvif->vif->type == NL80211_IFTYPE_STATION &&1906	      test_bit(WMI_TLV_SERVICE_STA_TWT, ab->wmi_ab.svc_map)))1907		return;1908 1909	debugfs_twt = debugfs_create_dir("twt",1910					 arvif->vif->debugfs_dir);1911	debugfs_create_file("add_dialog", 0200, debugfs_twt,1912			    arvif, &ath11k_fops_twt_add_dialog);1913 1914	debugfs_create_file("del_dialog", 0200, debugfs_twt,1915			    arvif, &ath11k_fops_twt_del_dialog);1916 1917	debugfs_create_file("pause_dialog", 0200, debugfs_twt,1918			    arvif, &ath11k_fops_twt_pause_dialog);1919 1920	debugfs_create_file("resume_dialog", 0200, debugfs_twt,1921			    arvif, &ath11k_fops_twt_resume_dialog);1922}1923 1924