162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc.
362306a36Sopenharmony_ci * Copyright (c) 2011 Neratec Solutions AG
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any
662306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above
762306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1062306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1162306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1262306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1362306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1462306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1562306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/debugfs.h>
1962306a36Sopenharmony_ci#include <linux/export.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "ath9k.h"
2262306a36Sopenharmony_ci#include "dfs_debug.h"
2362306a36Sopenharmony_ci#include "../dfs_pattern_detector.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic struct ath_dfs_pool_stats dfs_pool_stats = { 0 };
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define ATH9K_DFS_STAT(s, p) \
2862306a36Sopenharmony_ci	len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
2962306a36Sopenharmony_ci			 sc->debug.stats.dfs_stats.p)
3062306a36Sopenharmony_ci#define ATH9K_DFS_POOL_STAT(s, p) \
3162306a36Sopenharmony_ci	len += scnprintf(buf + len, size - len, "%28s : %10u\n", s, \
3262306a36Sopenharmony_ci			 dfs_pool_stats.p);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic ssize_t read_file_dfs(struct file *file, char __user *user_buf,
3562306a36Sopenharmony_ci			     size_t count, loff_t *ppos)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	struct ath_softc *sc = file->private_data;
3862306a36Sopenharmony_ci	struct ath9k_hw_version *hw_ver = &sc->sc_ah->hw_version;
3962306a36Sopenharmony_ci	char *buf;
4062306a36Sopenharmony_ci	unsigned int len = 0, size = 8000;
4162306a36Sopenharmony_ci	ssize_t retval = 0;
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	buf = kzalloc(size, GFP_KERNEL);
4462306a36Sopenharmony_ci	if (buf == NULL)
4562306a36Sopenharmony_ci		return -ENOMEM;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	len += scnprintf(buf + len, size - len, "DFS support for "
4862306a36Sopenharmony_ci			 "macVersion = 0x%x, macRev = 0x%x: %s\n",
4962306a36Sopenharmony_ci			 hw_ver->macVersion, hw_ver->macRev,
5062306a36Sopenharmony_ci			 (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ?
5162306a36Sopenharmony_ci					"enabled" : "disabled");
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (!sc->dfs_detector) {
5462306a36Sopenharmony_ci		len += scnprintf(buf + len, size - len,
5562306a36Sopenharmony_ci				 "DFS detector not enabled\n");
5662306a36Sopenharmony_ci		goto exit;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	dfs_pool_stats = sc->dfs_detector->get_stats(sc->dfs_detector);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	len += scnprintf(buf + len, size - len, "Pulse detector statistics:\n");
6262306a36Sopenharmony_ci	ATH9K_DFS_STAT("pulse events reported   ", pulses_total);
6362306a36Sopenharmony_ci	ATH9K_DFS_STAT("invalid pulse events    ", pulses_no_dfs);
6462306a36Sopenharmony_ci	ATH9K_DFS_STAT("DFS pulses detected     ", pulses_detected);
6562306a36Sopenharmony_ci	ATH9K_DFS_STAT("Datalen discards        ", datalen_discards);
6662306a36Sopenharmony_ci	ATH9K_DFS_STAT("RSSI discards           ", rssi_discards);
6762306a36Sopenharmony_ci	ATH9K_DFS_STAT("BW info discards        ", bwinfo_discards);
6862306a36Sopenharmony_ci	ATH9K_DFS_STAT("Primary channel pulses  ", pri_phy_errors);
6962306a36Sopenharmony_ci	ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors);
7062306a36Sopenharmony_ci	ATH9K_DFS_STAT("Dual channel pulses     ", dc_phy_errors);
7162306a36Sopenharmony_ci	len += scnprintf(buf + len, size - len, "Radar detector statistics "
7262306a36Sopenharmony_ci			 "(current DFS region: %d)\n",
7362306a36Sopenharmony_ci			 sc->dfs_detector->region);
7462306a36Sopenharmony_ci	ATH9K_DFS_STAT("Pulse events processed  ", pulses_processed);
7562306a36Sopenharmony_ci	ATH9K_DFS_STAT("Radars detected         ", radar_detected);
7662306a36Sopenharmony_ci	len += scnprintf(buf + len, size - len, "Global Pool statistics:\n");
7762306a36Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Pool references         ", pool_reference);
7862306a36Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Pulses allocated        ", pulse_allocated);
7962306a36Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Pulses alloc error      ", pulse_alloc_error);
8062306a36Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Pulses in use           ", pulse_used);
8162306a36Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Seqs. allocated         ", pseq_allocated);
8262306a36Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Seqs. alloc error       ", pseq_alloc_error);
8362306a36Sopenharmony_ci	ATH9K_DFS_POOL_STAT("Seqs. in use            ", pseq_used);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ciexit:
8662306a36Sopenharmony_ci	if (len > size)
8762306a36Sopenharmony_ci		len = size;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
9062306a36Sopenharmony_ci	kfree(buf);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return retval;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci/* magic number to prevent accidental reset of DFS statistics */
9662306a36Sopenharmony_ci#define DFS_STATS_RESET_MAGIC	0x80000000
9762306a36Sopenharmony_cistatic ssize_t write_file_dfs(struct file *file, const char __user *user_buf,
9862306a36Sopenharmony_ci			      size_t count, loff_t *ppos)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	struct ath_softc *sc = file->private_data;
10162306a36Sopenharmony_ci	unsigned long val;
10262306a36Sopenharmony_ci	ssize_t ret;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	ret = kstrtoul_from_user(user_buf, count, 0, &val);
10562306a36Sopenharmony_ci	if (ret)
10662306a36Sopenharmony_ci		return ret;
10762306a36Sopenharmony_ci	if (val == DFS_STATS_RESET_MAGIC)
10862306a36Sopenharmony_ci		memset(&sc->debug.stats.dfs_stats, 0,
10962306a36Sopenharmony_ci		       sizeof(sc->debug.stats.dfs_stats));
11062306a36Sopenharmony_ci	return count;
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic ssize_t write_file_simulate_radar(struct file *file,
11462306a36Sopenharmony_ci					 const char __user *user_buf,
11562306a36Sopenharmony_ci					 size_t count, loff_t *ppos)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct ath_softc *sc = file->private_data;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	ieee80211_radar_detected(sc->hw);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return count;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic const struct file_operations fops_simulate_radar = {
12562306a36Sopenharmony_ci	.write = write_file_simulate_radar,
12662306a36Sopenharmony_ci	.open = simple_open,
12762306a36Sopenharmony_ci	.owner = THIS_MODULE,
12862306a36Sopenharmony_ci	.llseek = default_llseek,
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic const struct file_operations fops_dfs_stats = {
13262306a36Sopenharmony_ci	.read = read_file_dfs,
13362306a36Sopenharmony_ci	.write = write_file_dfs,
13462306a36Sopenharmony_ci	.open = simple_open,
13562306a36Sopenharmony_ci	.owner = THIS_MODULE,
13662306a36Sopenharmony_ci	.llseek = default_llseek,
13762306a36Sopenharmony_ci};
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_civoid ath9k_dfs_init_debug(struct ath_softc *sc)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	debugfs_create_file("dfs_stats", 0400,
14262306a36Sopenharmony_ci			    sc->debug.debugfs_phy, sc, &fops_dfs_stats);
14362306a36Sopenharmony_ci	debugfs_create_file("dfs_simulate_radar", 0200,
14462306a36Sopenharmony_ci			    sc->debug.debugfs_phy, sc, &fops_simulate_radar);
14562306a36Sopenharmony_ci}
146