18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc.
38c2ecf20Sopenharmony_ci * Copyright (c) 2011 Neratec Solutions AG
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
68c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
78c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
108c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
118c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
128c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
138c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
158c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
198c2ecf20Sopenharmony_ci#include <linux/export.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "ath9k.h"
228c2ecf20Sopenharmony_ci#include "dfs_debug.h"
238c2ecf20Sopenharmony_ci#include "../dfs_pattern_detector.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic struct ath_dfs_pool_stats dfs_pool_stats = { 0 };
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define ATH9K_DFS_STAT(s, p) \
288c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
298c2ecf20Sopenharmony_ci			 sc->debug.stats.dfs_stats.p);
308c2ecf20Sopenharmony_ci#define ATH9K_DFS_POOL_STAT(s, p) \
318c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
328c2ecf20Sopenharmony_ci			 dfs_pool_stats.p);
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic ssize_t read_file_dfs(struct file *file, char __user *user_buf,
358c2ecf20Sopenharmony_ci			     size_t count, loff_t *ppos)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	struct ath_softc *sc = file->private_data;
388c2ecf20Sopenharmony_ci	struct ath9k_hw_version *hw_ver = &sc->sc_ah->hw_version;
398c2ecf20Sopenharmony_ci	char *buf;
408c2ecf20Sopenharmony_ci	unsigned int len = 0, size = 8000;
418c2ecf20Sopenharmony_ci	ssize_t retval = 0;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	buf = kzalloc(size, GFP_KERNEL);
448c2ecf20Sopenharmony_ci	if (buf == NULL)
458c2ecf20Sopenharmony_ci		return -ENOMEM;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, size - len, "DFS support for "
488c2ecf20Sopenharmony_ci			 "macVersion = 0x%x, macRev = 0x%x: %s\n",
498c2ecf20Sopenharmony_ci			 hw_ver->macVersion, hw_ver->macRev,
508c2ecf20Sopenharmony_ci			 (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ?
518c2ecf20Sopenharmony_ci					"enabled" : "disabled");
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	if (!sc->dfs_detector) {
548c2ecf20Sopenharmony_ci		len += scnprintf(buf + len, size - len,
558c2ecf20Sopenharmony_ci				 "DFS detector not enabled\n");
568c2ecf20Sopenharmony_ci		goto exit;
578c2ecf20Sopenharmony_ci	}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	dfs_pool_stats = sc->dfs_detector->get_stats(sc->dfs_detector);
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
628c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("pulse events reported   ", pulses_total);
638c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("invalid pulse events    ", pulses_no_dfs);
648c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("DFS pulses detected     ", pulses_detected);
658c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("Datalen discards        ", datalen_discards);
668c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("RSSI discards           ", rssi_discards);
678c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("BW info discards        ", bwinfo_discards);
688c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("Primary channel pulses  ", pri_phy_errors);
698c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors);
708c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("Dual channel pulses     ", dc_phy_errors);
718c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, size - len, "Radar detector statistics "
728c2ecf20Sopenharmony_ci			 "(current DFS region: %d)\n",
738c2ecf20Sopenharmony_ci			 sc->dfs_detector->region);
748c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("Pulse events processed  ", pulses_processed);
758c2ecf20Sopenharmony_ci	ATH9K_DFS_STAT("Radars detected         ", radar_detected);
768c2ecf20Sopenharmony_ci	len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");
778c2ecf20Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Pool references         ", pool_reference);
788c2ecf20Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Pulses allocated        ", pulse_allocated);
798c2ecf20Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Pulses alloc error      ", pulse_alloc_error);
808c2ecf20Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Pulses in use           ", pulse_used);
818c2ecf20Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Seqs. allocated         ", pseq_allocated);
828c2ecf20Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Seqs. alloc error       ", pseq_alloc_error);
838c2ecf20Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Seqs. in use            ", pseq_used);
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ciexit:
868c2ecf20Sopenharmony_ci	if (len > size)
878c2ecf20Sopenharmony_ci		len = size;
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
908c2ecf20Sopenharmony_ci	kfree(buf);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	return retval;
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci/* magic number to prevent accidental reset of DFS statistics */
968c2ecf20Sopenharmony_ci#define DFS_STATS_RESET_MAGIC	0x80000000
978c2ecf20Sopenharmony_cistatic ssize_t write_file_dfs(struct file *file, const char __user *user_buf,
988c2ecf20Sopenharmony_ci			      size_t count, loff_t *ppos)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	struct ath_softc *sc = file->private_data;
1018c2ecf20Sopenharmony_ci	unsigned long val;
1028c2ecf20Sopenharmony_ci	char buf[32];
1038c2ecf20Sopenharmony_ci	ssize_t len;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	len = min(count, sizeof(buf) - 1);
1068c2ecf20Sopenharmony_ci	if (copy_from_user(buf, user_buf, len))
1078c2ecf20Sopenharmony_ci		return -EFAULT;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	buf[len] = '\0';
1108c2ecf20Sopenharmony_ci	if (kstrtoul(buf, 0, &val))
1118c2ecf20Sopenharmony_ci		return -EINVAL;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (val == DFS_STATS_RESET_MAGIC)
1148c2ecf20Sopenharmony_ci		memset(&sc->debug.stats.dfs_stats, 0,
1158c2ecf20Sopenharmony_ci		       sizeof(sc->debug.stats.dfs_stats));
1168c2ecf20Sopenharmony_ci	return count;
1178c2ecf20Sopenharmony_ci}
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic ssize_t write_file_simulate_radar(struct file *file,
1208c2ecf20Sopenharmony_ci					 const char __user *user_buf,
1218c2ecf20Sopenharmony_ci					 size_t count, loff_t *ppos)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct ath_softc *sc = file->private_data;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	ieee80211_radar_detected(sc->hw);
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	return count;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic const struct file_operations fops_simulate_radar = {
1318c2ecf20Sopenharmony_ci	.write = write_file_simulate_radar,
1328c2ecf20Sopenharmony_ci	.open = simple_open,
1338c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
1348c2ecf20Sopenharmony_ci	.llseek = default_llseek,
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic const struct file_operations fops_dfs_stats = {
1388c2ecf20Sopenharmony_ci	.read = read_file_dfs,
1398c2ecf20Sopenharmony_ci	.write = write_file_dfs,
1408c2ecf20Sopenharmony_ci	.open = simple_open,
1418c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
1428c2ecf20Sopenharmony_ci	.llseek = default_llseek,
1438c2ecf20Sopenharmony_ci};
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_civoid ath9k_dfs_init_debug(struct ath_softc *sc)
1468c2ecf20Sopenharmony_ci{
1478c2ecf20Sopenharmony_ci	debugfs_create_file("dfs_stats", 0400,
1488c2ecf20Sopenharmony_ci			    sc->debug.debugfs_phy, sc, &fops_dfs_stats);
1498c2ecf20Sopenharmony_ci	debugfs_create_file("dfs_simulate_radar", 0200,
1508c2ecf20Sopenharmony_ci			    sc->debug.debugfs_phy, sc, &fops_simulate_radar);
1518c2ecf20Sopenharmony_ci}
152