diff options
author | Zefir Kurtisi <zefir.kurtisi@neratec.com> | 2012-04-20 11:20:34 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-04-23 15:37:41 -0400 |
commit | b96f20b3afff36f30baa1e1e121ccbf7518a988d (patch) | |
tree | c9d58d8719c06b42ef50efb53552c101f995c305 | |
parent | 2a5783b817c90ce6fb82a21e103335d1ecbac430 (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.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/dfs_debug.c | 46 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/dfs_debug.h | 45 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/dfs_pri_detector.c | 20 |
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 | |||
25 | struct 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 | ||
28 | static ssize_t read_file_dfs(struct file *file, char __user *user_buf, | 34 | static 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 | ||
86 | static 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 | |||
63 | static const struct file_operations fops_dfs_stats = { | 108 | static 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 | */ |
35 | struct ath_dfs_stats { | 38 | struct 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 | */ | ||
57 | struct 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++) |
48 | void ath9k_dfs_init_debug(struct ath_softc *sc); | 69 | void 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--) | ||
73 | extern 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) |
53 | static inline void ath9k_dfs_init_debug(struct ath_softc *sc) { } | 78 | static 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); |