Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
net
wireless
ath
ath9k
dfs.c
Go to the documentation of this file.
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
/* internal struct to pass radar data */
25
struct
ath_radar_data
{
26
u8
pulse_bw_info
;
27
u8
rssi
;
28
u8
ext_rssi
;
29
u8
pulse_length_ext
;
30
u8
pulse_length_pri
;
31
};
32
33
/* convert pulse duration to usecs, considering clock mode */
34
static
u32
dur_to_usecs(
struct
ath_hw
*
ah
,
u32
dur)
35
{
36
const
u32
AR93X_NSECS_PER_DUR = 800;
37
const
u32
AR93X_NSECS_PER_DUR_FAST = (8000 / 11);
38
u32
nsecs
;
39
40
if
(
IS_CHAN_A_FAST_CLOCK
(ah, ah->
curchan
))
41
nsecs = dur * AR93X_NSECS_PER_DUR_FAST;
42
else
43
nsecs = dur * AR93X_NSECS_PER_DUR;
44
45
return
(nsecs + 500) / 1000;
46
}
47
48
#define PRI_CH_RADAR_FOUND 0x01
49
#define EXT_CH_RADAR_FOUND 0x02
50
static
bool
51
ath9k_postprocess_radar_event(
struct
ath_softc
*
sc
,
52
struct
ath_radar_data
*ard,
53
struct
pulse_event
*pe)
54
{
55
u8
rssi;
56
u16
dur;
57
58
ath_dbg
(ath9k_hw_common(sc->
sc_ah
),
DFS
,
59
"pulse_bw_info=0x%x, pri,ext len/rssi=(%u/%u, %u/%u)\n"
,
60
ard->
pulse_bw_info
,
61
ard->
pulse_length_pri
, ard->
rssi
,
62
ard->
pulse_length_ext
, ard->
ext_rssi
);
63
64
/*
65
* Only the last 2 bits of the BW info are relevant, they indicate
66
* which channel the radar was detected in.
67
*/
68
ard->
pulse_bw_info
&= 0x03;
69
70
switch
(ard->
pulse_bw_info
) {
71
case
PRI_CH_RADAR_FOUND
:
72
/* radar in ctrl channel */
73
dur = ard->
pulse_length_pri
;
74
DFS_STAT_INC
(sc, pri_phy_errors);
75
/*
76
* cannot use ctrl channel RSSI
77
* if extension channel is stronger
78
*/
79
rssi = (ard->
ext_rssi
>= (ard->
rssi
+ 3)) ? 0 : ard->
rssi
;
80
break
;
81
case
EXT_CH_RADAR_FOUND
:
82
/* radar in extension channel */
83
dur = ard->
pulse_length_ext
;
84
DFS_STAT_INC
(sc, ext_phy_errors);
85
/*
86
* cannot use extension channel RSSI
87
* if control channel is stronger
88
*/
89
rssi = (ard->
rssi
>= (ard->
ext_rssi
+ 12)) ? 0 : ard->
ext_rssi
;
90
break
;
91
case
(
PRI_CH_RADAR_FOUND
|
EXT_CH_RADAR_FOUND
):
92
/*
93
* Conducted testing, when pulse is on DC, both pri and ext
94
* durations are reported to be same
95
*
96
* Radiated testing, when pulse is on DC, different pri and
97
* ext durations are reported, so take the larger of the two
98
*/
99
if
(ard->
pulse_length_ext
>= ard->
pulse_length_pri
)
100
dur = ard->
pulse_length_ext
;
101
else
102
dur = ard->
pulse_length_pri
;
103
DFS_STAT_INC
(sc, dc_phy_errors);
104
105
/* when both are present use stronger one */
106
rssi = (ard->
rssi
< ard->
ext_rssi
) ? ard->
ext_rssi
: ard->
rssi
;
107
break
;
108
default
:
109
/*
110
* Bogus bandwidth info was received in descriptor,
111
* so ignore this PHY error
112
*/
113
DFS_STAT_INC
(sc, bwinfo_discards);
114
return
false
;
115
}
116
117
if
(rssi == 0) {
118
DFS_STAT_INC
(sc, rssi_discards);
119
return
false
;
120
}
121
122
/*
123
* TODO: check chirping pulses
124
* checks for chirping are dependent on the DFS regulatory domain
125
* used, which is yet TBD
126
*/
127
128
/* convert duration to usecs */
129
pe->
width
= dur_to_usecs(sc->
sc_ah
, dur);
130
pe->
rssi
= rssi;
131
132
DFS_STAT_INC
(sc, pulses_detected);
133
return
true
;
134
}
135
#undef PRI_CH_RADAR_FOUND
136
#undef EXT_CH_RADAR_FOUND
137
138
/*
139
* DFS: check PHY-error for radar pulse and feed the detector
140
*/
141
void
ath9k_dfs_process_phyerr
(
struct
ath_softc
*
sc
,
void
*
data
,
142
struct
ath_rx_status
*rs,
u64
mactime)
143
{
144
struct
ath_radar_data
ard;
145
u16
datalen
;
146
char
*vdata_end;
147
struct
pulse_event
pe;
148
struct
ath_hw
*
ah
= sc->
sc_ah
;
149
struct
ath_common
*
common
= ath9k_hw_common(ah);
150
151
DFS_STAT_INC
(sc, pulses_total);
152
if
((rs->
rs_phyerr
!=
ATH9K_PHYERR_RADAR
) &&
153
(rs->
rs_phyerr
!=
ATH9K_PHYERR_FALSE_RADAR_EXT
)) {
154
ath_dbg
(common,
DFS
,
155
"Error: rs_phyer=0x%x not a radar error\n"
,
156
rs->
rs_phyerr
);
157
DFS_STAT_INC
(sc, pulses_no_dfs);
158
return
;
159
}
160
161
datalen = rs->
rs_datalen
;
162
if
(datalen == 0) {
163
DFS_STAT_INC
(sc, datalen_discards);
164
return
;
165
}
166
167
ard.
rssi
= rs->
rs_rssi_ctl0
;
168
ard.
ext_rssi
= rs->
rs_rssi_ext0
;
169
170
/*
171
* hardware stores this as 8 bit signed value.
172
* we will cap it at 0 if it is a negative number
173
*/
174
if
(ard.
rssi
& 0x80)
175
ard.
rssi
= 0;
176
if
(ard.
ext_rssi
& 0x80)
177
ard.
ext_rssi
= 0;
178
179
vdata_end = (
char
*)data + datalen;
180
ard.
pulse_bw_info
= vdata_end[-1];
181
ard.
pulse_length_ext
= vdata_end[-2];
182
ard.
pulse_length_pri
= vdata_end[-3];
183
pe.
freq
= ah->
curchan
->channel;
184
pe.
ts
= mactime;
185
if
(ath9k_postprocess_radar_event(sc, &ard, &pe)) {
186
struct
dfs_pattern_detector
*
pd
= sc->
dfs_detector
;
187
static
u64
last_ts;
188
ath_dbg
(common,
DFS
,
189
"ath9k_dfs_process_phyerr: channel=%d, ts=%llu, "
190
"width=%d, rssi=%d, delta_ts=%llu\n"
,
191
pe.
freq
, pe.
ts
, pe.
width
, pe.
rssi
, pe.
ts
-last_ts);
192
last_ts = pe.
ts
;
193
DFS_STAT_INC
(sc, pulses_processed);
194
if
(pd !=
NULL
&& pd->
add_pulse
(pd, &pe)) {
195
DFS_STAT_INC
(sc, radar_detected);
196
/*
197
* TODO: forward radar event to DFS management layer
198
*/
199
}
200
}
201
}
Generated on Thu Jan 10 2013 14:09:04 for Linux Kernel by
1.8.2