aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/dfs.c
diff options
context:
space:
mode:
authorZefir Kurtisi <zefir.kurtisi@neratec.com>2011-12-14 23:16:34 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-12-15 14:46:37 -0500
commit29942bc125374b5aa049a438fb628ea729538ca5 (patch)
tree87d1a9f96ade552d8404899046775fa15aab730c /drivers/net/wireless/ath/ath9k/dfs.c
parent9a66af3317be2b2ceea38f403d2f682f255de82a (diff)
ath9k: add DFS radar pulse processing
This initial DFS module provides basic functionality to deal with radar pulses reported by the Atheros DFS HW pulse detector. The reported data is evaluated and basic plausibility checks are performed to filter false pulses. Passing radar pulses are forwarded to pattern detectors which are not yet implemented. (Some modifications to actually use ATH9K_DFS_DEBUGFS based on comments from Julian Calaby <julian.calaby@gmail.com>. -- JWL) Signed-off-by: Zefir Kurtisi <zefir.kurtisi@neratec.com> Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/dfs.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/dfs.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c
new file mode 100644
index 00000000000..e4e84a9e627
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/dfs.c
@@ -0,0 +1,215 @@
1/*
2 * Copyright (c) 2008-2011 Atheros Communications Inc.
3 * Copyright (c) 2011 Neratec Solutions AG
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include "hw.h"
19#include "hw-ops.h"
20#include "ath9k.h"
21#include "dfs.h"
22#include "dfs_debug.h"
23
24/*
25 * TODO: move into or synchronize this with generic header
26 * as soon as IF is defined
27 */
28struct dfs_radar_pulse {
29 u16 freq;
30 u64 ts;
31 u32 width;
32 u8 rssi;
33};
34
35/* internal struct to pass radar data */
36struct ath_radar_data {
37 u8 pulse_bw_info;
38 u8 rssi;
39 u8 ext_rssi;
40 u8 pulse_length_ext;
41 u8 pulse_length_pri;
42};
43
44/* convert pulse duration to usecs, considering clock mode */
45static u32 dur_to_usecs(struct ath_hw *ah, u32 dur)
46{
47 const u32 AR93X_NSECS_PER_DUR = 800;
48 const u32 AR93X_NSECS_PER_DUR_FAST = (8000 / 11);
49 u32 nsecs;
50
51 if (IS_CHAN_A_FAST_CLOCK(ah, ah->curchan))
52 nsecs = dur * AR93X_NSECS_PER_DUR_FAST;
53 else
54 nsecs = dur * AR93X_NSECS_PER_DUR;
55
56 return (nsecs + 500) / 1000;
57}
58
59#define PRI_CH_RADAR_FOUND 0x01
60#define EXT_CH_RADAR_FOUND 0x02
61static bool
62ath9k_postprocess_radar_event(struct ath_softc *sc,
63 struct ath_radar_data *are,
64 struct dfs_radar_pulse *drp)
65{
66 u8 rssi;
67 u16 dur;
68
69 ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_DFS,
70 "pulse_bw_info=0x%x, pri,ext len/rssi=(%u/%u, %u/%u)\n",
71 are->pulse_bw_info,
72 are->pulse_length_pri, are->rssi,
73 are->pulse_length_ext, are->ext_rssi);
74
75 /*
76 * Only the last 2 bits of the BW info are relevant, they indicate
77 * which channel the radar was detected in.
78 */
79 are->pulse_bw_info &= 0x03;
80
81 switch (are->pulse_bw_info) {
82 case PRI_CH_RADAR_FOUND:
83 /* radar in ctrl channel */
84 dur = are->pulse_length_pri;
85 DFS_STAT_INC(sc, pri_phy_errors);
86 /*
87 * cannot use ctrl channel RSSI
88 * if extension channel is stronger
89 */
90 rssi = (are->ext_rssi >= (are->rssi + 3)) ? 0 : are->rssi;
91 break;
92 case EXT_CH_RADAR_FOUND:
93 /* radar in extension channel */
94 dur = are->pulse_length_ext;
95 DFS_STAT_INC(sc, ext_phy_errors);
96 /*
97 * cannot use extension channel RSSI
98 * if control channel is stronger
99 */
100 rssi = (are->rssi >= (are->ext_rssi + 12)) ? 0 : are->ext_rssi;
101 break;
102 case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND):
103 /*
104 * Conducted testing, when pulse is on DC, both pri and ext
105 * durations are reported to be same
106 *
107 * Radiated testing, when pulse is on DC, different pri and
108 * ext durations are reported, so take the larger of the two
109 */
110 if (are->pulse_length_ext >= are->pulse_length_pri)
111 dur = are->pulse_length_ext;
112 else
113 dur = are->pulse_length_pri;
114 DFS_STAT_INC(sc, dc_phy_errors);
115
116 /* when both are present use stronger one */
117 rssi = (are->rssi < are->ext_rssi) ? are->ext_rssi : are->rssi;
118 break;
119 default:
120 /*
121 * Bogus bandwidth info was received in descriptor,
122 * so ignore this PHY error
123 */
124 DFS_STAT_INC(sc, bwinfo_discards);
125 return false;
126 }
127
128 if (rssi == 0) {
129 DFS_STAT_INC(sc, rssi_discards);
130 return false;
131 }
132
133 /*
134 * TODO: check chirping pulses
135 * checks for chirping are dependent on the DFS regulatory domain
136 * used, which is yet TBD
137 */
138
139 /* convert duration to usecs */
140 drp->width = dur_to_usecs(sc->sc_ah, dur);
141 drp->rssi = rssi;
142
143 DFS_STAT_INC(sc, pulses_detected);
144 return true;
145}
146#undef PRI_CH_RADAR_FOUND
147#undef EXT_CH_RADAR_FOUND
148
149/*
150 * DFS: check PHY-error for radar pulse and feed the detector
151 */
152void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data,
153 struct ath_rx_status *rs, u64 mactime)
154{
155 struct ath_radar_data ard;
156 u16 datalen;
157 char *vdata_end;
158 struct dfs_radar_pulse drp;
159 struct ath_hw *ah = sc->sc_ah;
160 struct ath_common *common = ath9k_hw_common(ah);
161
162 if ((!(rs->rs_phyerr != ATH9K_PHYERR_RADAR)) &&
163 (!(rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT))) {
164 ath_dbg(common, ATH_DBG_DFS,
165 "Error: rs_phyer=0x%x not a radar error\n",
166 rs->rs_phyerr);
167 return;
168 }
169
170 datalen = rs->rs_datalen;
171 if (datalen == 0) {
172 DFS_STAT_INC(sc, datalen_discards);
173 return;
174 }
175
176 ard.rssi = rs->rs_rssi_ctl0;
177 ard.ext_rssi = rs->rs_rssi_ext0;
178
179 /*
180 * hardware stores this as 8 bit signed value.
181 * we will cap it at 0 if it is a negative number
182 */
183 if (ard.rssi & 0x80)
184 ard.rssi = 0;
185 if (ard.ext_rssi & 0x80)
186 ard.ext_rssi = 0;
187
188 vdata_end = (char *)data + datalen;
189 ard.pulse_bw_info = vdata_end[-1];
190 ard.pulse_length_ext = vdata_end[-2];
191 ard.pulse_length_pri = vdata_end[-3];
192
193 ath_dbg(common, ATH_DBG_DFS,
194 "bw_info=%d, length_pri=%d, length_ext=%d, "
195 "rssi_pri=%d, rssi_ext=%d\n",
196 ard.pulse_bw_info, ard.pulse_length_pri, ard.pulse_length_ext,
197 ard.rssi, ard.ext_rssi);
198
199 drp.freq = ah->curchan->channel;
200 drp.ts = mactime;
201 if (ath9k_postprocess_radar_event(sc, &ard, &drp)) {
202 static u64 last_ts;
203 ath_dbg(common, ATH_DBG_DFS,
204 "ath9k_dfs_process_phyerr: channel=%d, ts=%llu, "
205 "width=%d, rssi=%d, delta_ts=%llu\n",
206 drp.freq, drp.ts, drp.width, drp.rssi, drp.ts-last_ts);
207 last_ts = drp.ts;
208 /*
209 * TODO: forward pulse to pattern detector
210 *
211 * ieee80211_add_radar_pulse(drp.freq, drp.ts,
212 * drp.width, drp.rssi);
213 */
214 }
215}