aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZefir Kurtisi <zefir.kurtisi@neratec.com>2012-04-20 11:20:34 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-23 15:37:41 -0400
commitb96f20b3afff36f30baa1e1e121ccbf7518a988d (patch)
treec9d58d8719c06b42ef50efb53552c101f995c305
parent2a5783b817c90ce6fb82a21e103335d1ecbac430 (diff)
ath9k: extend DFS detector stats in dfs_debugfs
Extend debugfs entry for dfs_stats with DFS detection events and shared pool statistics. Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.c46
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_debug.h45
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs_pri_detector.c20
4 files changed, 104 insertions, 11 deletions
diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c
index 92891f5fd45..ecc81792f2d 100644
--- a/drivers/net/wireless/ath/ath9k/dfs.c
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
@@ -148,11 +148,13 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
148 struct ath_hw *ah = sc->sc_ah; 148 struct ath_hw *ah = sc->sc_ah;
149 struct ath_common *common = ath9k_hw_common(ah); 149 struct ath_common *common = ath9k_hw_common(ah);
150 150
151 DFS_STAT_INC(sc, pulses_total);
151 if ((rs->rs_phyerr != ATH9K_PHYERR_RADAR) && 152 if ((rs->rs_phyerr != ATH9K_PHYERR_RADAR) &&
152 (rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT)) { 153 (rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT)) {
153 ath_dbg(common, DFS, 154 ath_dbg(common, DFS,
154 "Error: rs_phyer=0x%x not a radar error\n", 155 "Error: rs_phyer=0x%x not a radar error\n",
155 rs->rs_phyerr); 156 rs->rs_phyerr);
157 DFS_STAT_INC(sc, pulses_no_dfs);
156 return; 158 return;
157 } 159 }
158 160
@@ -188,7 +190,9 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
188 "width=%d, rssi=%d, delta_ts=%llu\n", 190 "width=%d, rssi=%d, delta_ts=%llu\n",
189 pe.freq, pe.ts, pe.width, pe.rssi, pe.ts-last_ts); 191 pe.freq, pe.ts, pe.width, pe.rssi, pe.ts-last_ts);
190 last_ts = pe.ts; 192 last_ts = pe.ts;
193 DFS_STAT_INC(sc, pulses_processed);
191 if (pd != NULL && pd->add_pulse(pd, &pe)) { 194 if (pd != NULL && pd->add_pulse(pd, &pe)) {
195 DFS_STAT_INC(sc, radar_detected);
192 /* 196 /*
193 * TODO: forward radar event to DFS management layer 197 * TODO: forward radar event to DFS management layer
194 */ 198 */
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.c b/drivers/net/wireless/ath/ath9k/dfs_debug.c
index 4364c103ed3..55d28072ade 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.c
@@ -21,9 +21,15 @@
21#include "ath9k.h" 21#include "ath9k.h"
22#include "dfs_debug.h" 22#include "dfs_debug.h"
23 23
24
25struct ath_dfs_pool_stats global_dfs_pool_stats = { 0 };
26
24#define ATH9K_DFS_STAT(s, p) \ 27#define ATH9K_DFS_STAT(s, p) \
25 len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \ 28 len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \
26 sc->debug.stats.dfs_stats.p); 29 sc->debug.stats.dfs_stats.p);
30#define ATH9K_DFS_POOL_STAT(s, p) \
31 len += snprintf(buf + len, size - len, "%28s : %10u\n", s, \
32 global_dfs_pool_stats.p);
27 33
28static ssize_t read_file_dfs(struct file *file, char __user *user_buf, 34static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
29 size_t count, loff_t *ppos) 35 size_t count, loff_t *ppos)
@@ -43,6 +49,9 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
43 hw_ver->macVersion, hw_ver->macRev, 49 hw_ver->macVersion, hw_ver->macRev,
44 (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ? 50 (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_DFS) ?
45 "enabled" : "disabled"); 51 "enabled" : "disabled");
52 len += snprintf(buf + len, size - len, "Pulse detector statistics:\n");
53 ATH9K_DFS_STAT("pulse events reported ", pulses_total);
54 ATH9K_DFS_STAT("invalid pulse events ", pulses_no_dfs);
46 ATH9K_DFS_STAT("DFS pulses detected ", pulses_detected); 55 ATH9K_DFS_STAT("DFS pulses detected ", pulses_detected);
47 ATH9K_DFS_STAT("Datalen discards ", datalen_discards); 56 ATH9K_DFS_STAT("Datalen discards ", datalen_discards);
48 ATH9K_DFS_STAT("RSSI discards ", rssi_discards); 57 ATH9K_DFS_STAT("RSSI discards ", rssi_discards);
@@ -50,6 +59,18 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
50 ATH9K_DFS_STAT("Primary channel pulses ", pri_phy_errors); 59 ATH9K_DFS_STAT("Primary channel pulses ", pri_phy_errors);
51 ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors); 60 ATH9K_DFS_STAT("Secondary channel pulses", ext_phy_errors);
52 ATH9K_DFS_STAT("Dual channel pulses ", dc_phy_errors); 61 ATH9K_DFS_STAT("Dual channel pulses ", dc_phy_errors);
62 len += snprintf(buf + len, size - len, "Radar detector statistics "
63 "(current DFS region: %d)\n", sc->dfs_detector->region);
64 ATH9K_DFS_STAT("Pulse events processed ", pulses_processed);
65 ATH9K_DFS_STAT("Radars detected ", radar_detected);
66 len += snprintf(buf + len, size - len, "Global Pool statistics:\n");
67 ATH9K_DFS_POOL_STAT("Pool references ", pool_reference);
68 ATH9K_DFS_POOL_STAT("Pulses allocated ", pulse_allocated);
69 ATH9K_DFS_POOL_STAT("Pulses alloc error ", pulse_alloc_error);
70 ATH9K_DFS_POOL_STAT("Pulses in use ", pulse_used);
71 ATH9K_DFS_POOL_STAT("Seqs. allocated ", pseq_allocated);
72 ATH9K_DFS_POOL_STAT("Seqs. alloc error ", pseq_alloc_error);
73 ATH9K_DFS_POOL_STAT("Seqs. in use ", pseq_used);
53 74
54 if (len > size) 75 if (len > size)
55 len = size; 76 len = size;
@@ -60,8 +81,33 @@ static ssize_t read_file_dfs(struct file *file, char __user *user_buf,
60 return retval; 81 return retval;
61} 82}
62 83
84/* magic number to prevent accidental reset of DFS statistics */
85#define DFS_STATS_RESET_MAGIC 0x80000000
86static ssize_t write_file_dfs(struct file *file, const char __user *user_buf,
87 size_t count, loff_t *ppos)
88{
89 struct ath_softc *sc = file->private_data;
90 unsigned long val;
91 char buf[32];
92 ssize_t len;
93
94 len = min(count, sizeof(buf) - 1);
95 if (copy_from_user(buf, user_buf, len))
96 return -EFAULT;
97
98 buf[len] = '\0';
99 if (strict_strtoul(buf, 0, &val))
100 return -EINVAL;
101
102 if (val == DFS_STATS_RESET_MAGIC)
103 memset(&sc->debug.stats.dfs_stats, 0,
104 sizeof(sc->debug.stats.dfs_stats));
105 return count;
106}
107
63static const struct file_operations fops_dfs_stats = { 108static const struct file_operations fops_dfs_stats = {
64 .read = read_file_dfs, 109 .read = read_file_dfs,
110 .write = write_file_dfs,
65 .open = simple_open, 111 .open = simple_open,
66 .owner = THIS_MODULE, 112 .owner = THIS_MODULE,
67 .llseek = default_llseek, 113 .llseek = default_llseek,
diff --git a/drivers/net/wireless/ath/ath9k/dfs_debug.h b/drivers/net/wireless/ath/ath9k/dfs_debug.h
index 4911724cb44..e36810a4b58 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_debug.h
+++ b/drivers/net/wireless/ath/ath9k/dfs_debug.h
@@ -22,17 +22,23 @@
22#include "hw.h" 22#include "hw.h"
23 23
24/** 24/**
25 * struct ath_dfs_stats - DFS Statistics 25 * struct ath_dfs_stats - DFS Statistics per wiphy
26 * 26 * @pulses_total: pulses reported by HW
27 * @pulses_detected: No. of pulses detected so far 27 * @pulses_no_dfs: pulses wrongly reported as DFS
28 * @datalen_discards: No. of pulses discarded due to invalid datalen 28 * @pulses_detected: pulses detected so far
29 * @rssi_discards: No. of pulses discarded due to invalid RSSI 29 * @datalen_discards: pulses discarded due to invalid datalen
30 * @bwinfo_discards: No. of pulses discarded due to invalid BW info 30 * @rssi_discards: pulses discarded due to invalid RSSI
31 * @pri_phy_errors: No. of pulses reported for primary channel 31 * @bwinfo_discards: pulses discarded due to invalid BW info
32 * @ext_phy_errors: No. of pulses reported for extension channel 32 * @pri_phy_errors: pulses reported for primary channel
33 * @dc_phy_errors: No. of pulses reported for primary + extension channel 33 * @ext_phy_errors: pulses reported for extension channel
34 * @dc_phy_errors: pulses reported for primary + extension channel
35 * @pulses_processed: pulses forwarded to detector
36 * @radar_detected: radars detected
34 */ 37 */
35struct ath_dfs_stats { 38struct ath_dfs_stats {
39 /* pulse stats */
40 u32 pulses_total;
41 u32 pulses_no_dfs;
36 u32 pulses_detected; 42 u32 pulses_detected;
37 u32 datalen_discards; 43 u32 datalen_discards;
38 u32 rssi_discards; 44 u32 rssi_discards;
@@ -40,18 +46,39 @@ struct ath_dfs_stats {
40 u32 pri_phy_errors; 46 u32 pri_phy_errors;
41 u32 ext_phy_errors; 47 u32 ext_phy_errors;
42 u32 dc_phy_errors; 48 u32 dc_phy_errors;
49 /* pattern detection stats */
50 u32 pulses_processed;
51 u32 radar_detected;
43}; 52};
44 53
54/**
55 * struct ath_dfs_pool_stats - DFS Statistics for global pools
56 */
57struct ath_dfs_pool_stats {
58 u32 pool_reference;
59 u32 pulse_allocated;
60 u32 pulse_alloc_error;
61 u32 pulse_used;
62 u32 pseq_allocated;
63 u32 pseq_alloc_error;
64 u32 pseq_used;
65};
45#if defined(CONFIG_ATH9K_DFS_DEBUGFS) 66#if defined(CONFIG_ATH9K_DFS_DEBUGFS)
46 67
47#define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++) 68#define DFS_STAT_INC(sc, c) (sc->debug.stats.dfs_stats.c++)
48void ath9k_dfs_init_debug(struct ath_softc *sc); 69void ath9k_dfs_init_debug(struct ath_softc *sc);
49 70
71#define DFS_POOL_STAT_INC(c) (global_dfs_pool_stats.c++)
72#define DFS_POOL_STAT_DEC(c) (global_dfs_pool_stats.c--)
73extern struct ath_dfs_pool_stats global_dfs_pool_stats;
74
50#else 75#else
51 76
52#define DFS_STAT_INC(sc, c) do { } while (0) 77#define DFS_STAT_INC(sc, c) do { } while (0)
53static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { } 78static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { }
54 79
80#define DFS_POOL_STAT_INC(c) do { } while (0)
81#define DFS_POOL_STAT_DEC(c) do { } while (0)
55#endif /* CONFIG_ATH9K_DFS_DEBUGFS */ 82#endif /* CONFIG_ATH9K_DFS_DEBUGFS */
56 83
57#endif /* ATH9K_DFS_DEBUG_H */ 84#endif /* ATH9K_DFS_DEBUG_H */
diff --git a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
index ecb6334fd20..91b8dceeadb 100644
--- a/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
+++ b/drivers/net/wireless/ath/ath9k/dfs_pri_detector.c
@@ -17,8 +17,10 @@
17#include <linux/slab.h> 17#include <linux/slab.h>
18#include <linux/spinlock.h> 18#include <linux/spinlock.h>
19 19
20#include "ath9k.h"
20#include "dfs_pattern_detector.h" 21#include "dfs_pattern_detector.h"
21#include "dfs_pri_detector.h" 22#include "dfs_pri_detector.h"
23#include "dfs_debug.h"
22 24
23/** 25/**
24 * struct pri_sequence - sequence of pulses matching one PRI 26 * struct pri_sequence - sequence of pulses matching one PRI
@@ -101,6 +103,7 @@ static void pool_register_ref(void)
101{ 103{
102 spin_lock_bh(&pool_lock); 104 spin_lock_bh(&pool_lock);
103 singleton_pool_references++; 105 singleton_pool_references++;
106 DFS_POOL_STAT_INC(pool_reference);
104 spin_unlock_bh(&pool_lock); 107 spin_unlock_bh(&pool_lock);
105} 108}
106 109
@@ -108,6 +111,7 @@ static void pool_deregister_ref(void)
108{ 111{
109 spin_lock_bh(&pool_lock); 112 spin_lock_bh(&pool_lock);
110 singleton_pool_references--; 113 singleton_pool_references--;
114 DFS_POOL_STAT_DEC(pool_reference);
111 if (singleton_pool_references == 0) { 115 if (singleton_pool_references == 0) {
112 /* free singleton pools with no references left */ 116 /* free singleton pools with no references left */
113 struct pri_sequence *ps, *ps0; 117 struct pri_sequence *ps, *ps0;
@@ -115,10 +119,12 @@ static void pool_deregister_ref(void)
115 119
116 list_for_each_entry_safe(p, p0, &pulse_pool, head) { 120 list_for_each_entry_safe(p, p0, &pulse_pool, head) {
117 list_del(&p->head); 121 list_del(&p->head);
122 DFS_POOL_STAT_DEC(pulse_allocated);
118 kfree(p); 123 kfree(p);
119 } 124 }
120 list_for_each_entry_safe(ps, ps0, &pseq_pool, head) { 125 list_for_each_entry_safe(ps, ps0, &pseq_pool, head) {
121 list_del(&ps->head); 126 list_del(&ps->head);
127 DFS_POOL_STAT_DEC(pseq_allocated);
122 kfree(ps); 128 kfree(ps);
123 } 129 }
124 } 130 }
@@ -129,6 +135,7 @@ static void pool_put_pulse_elem(struct pulse_elem *pe)
129{ 135{
130 spin_lock_bh(&pool_lock); 136 spin_lock_bh(&pool_lock);
131 list_add(&pe->head, &pulse_pool); 137 list_add(&pe->head, &pulse_pool);
138 DFS_POOL_STAT_DEC(pulse_used);
132 spin_unlock_bh(&pool_lock); 139 spin_unlock_bh(&pool_lock);
133} 140}
134 141
@@ -136,6 +143,7 @@ static void pool_put_pseq_elem(struct pri_sequence *pse)
136{ 143{
137 spin_lock_bh(&pool_lock); 144 spin_lock_bh(&pool_lock);
138 list_add(&pse->head, &pseq_pool); 145 list_add(&pse->head, &pseq_pool);
146 DFS_POOL_STAT_DEC(pseq_used);
139 spin_unlock_bh(&pool_lock); 147 spin_unlock_bh(&pool_lock);
140} 148}
141 149
@@ -146,6 +154,7 @@ static struct pri_sequence *pool_get_pseq_elem(void)
146 if (!list_empty(&pseq_pool)) { 154 if (!list_empty(&pseq_pool)) {
147 pse = list_first_entry(&pseq_pool, struct pri_sequence, head); 155 pse = list_first_entry(&pseq_pool, struct pri_sequence, head);
148 list_del(&pse->head); 156 list_del(&pse->head);
157 DFS_POOL_STAT_INC(pseq_used);
149 } 158 }
150 spin_unlock_bh(&pool_lock); 159 spin_unlock_bh(&pool_lock);
151 return pse; 160 return pse;
@@ -158,6 +167,7 @@ static struct pulse_elem *pool_get_pulse_elem(void)
158 if (!list_empty(&pulse_pool)) { 167 if (!list_empty(&pulse_pool)) {
159 pe = list_first_entry(&pulse_pool, struct pulse_elem, head); 168 pe = list_first_entry(&pulse_pool, struct pulse_elem, head);
160 list_del(&pe->head); 169 list_del(&pe->head);
170 DFS_POOL_STAT_INC(pulse_used);
161 } 171 }
162 spin_unlock_bh(&pool_lock); 172 spin_unlock_bh(&pool_lock);
163 return pe; 173 return pe;
@@ -210,9 +220,11 @@ static bool pulse_queue_enqueue(struct pri_detector *pde, u64 ts)
210 if (p == NULL) { 220 if (p == NULL) {
211 p = kmalloc(sizeof(*p), GFP_KERNEL); 221 p = kmalloc(sizeof(*p), GFP_KERNEL);
212 if (p == NULL) { 222 if (p == NULL) {
213 pr_err("failed to allocate pulse_elem\n"); 223 DFS_POOL_STAT_INC(pulse_alloc_error);
214 return false; 224 return false;
215 } 225 }
226 DFS_POOL_STAT_INC(pulse_allocated);
227 DFS_POOL_STAT_INC(pulse_used);
216 } 228 }
217 INIT_LIST_HEAD(&p->head); 229 INIT_LIST_HEAD(&p->head);
218 p->ts = ts; 230 p->ts = ts;
@@ -288,8 +300,12 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde,
288 new_ps = pool_get_pseq_elem(); 300 new_ps = pool_get_pseq_elem();
289 if (new_ps == NULL) { 301 if (new_ps == NULL) {
290 new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL); 302 new_ps = kmalloc(sizeof(*new_ps), GFP_KERNEL);
291 if (new_ps == NULL) 303 if (new_ps == NULL) {
304 DFS_POOL_STAT_INC(pseq_alloc_error);
292 return false; 305 return false;
306 }
307 DFS_POOL_STAT_INC(pseq_allocated);
308 DFS_POOL_STAT_INC(pseq_used);
293 } 309 }
294 memcpy(new_ps, &ps, sizeof(ps)); 310 memcpy(new_ps, &ps, sizeof(ps));
295 INIT_LIST_HEAD(&new_ps->head); 311 INIT_LIST_HEAD(&new_ps->head);