2 * Copyright (c) 2013 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 #include <linux/relay.h>
18 #include <linux/random.h>
21 static s8
fix_rssi_inv_only(u8 rssi_val
)
28 static void ath_debug_send_fft_sample(struct ath_spec_scan_priv
*spec_priv
,
29 struct fft_sample_tlv
*fft_sample_tlv
)
32 if (!spec_priv
->rfs_chan_spec_scan
)
35 length
= __be16_to_cpu(fft_sample_tlv
->length
) +
36 sizeof(*fft_sample_tlv
);
37 relay_write(spec_priv
->rfs_chan_spec_scan
, fft_sample_tlv
, length
);
40 typedef int (ath_cmn_fft_idx_validator
) (u8
*sample_end
, int bytes_read
);
43 ath_cmn_max_idx_verify_ht20_fft(u8
*sample_end
, int bytes_read
)
45 struct ath_ht20_mag_info
*mag_info
;
51 /* Sanity check so that we don't read outside the read
54 if (bytes_read
< SPECTRAL_HT20_SAMPLE_LEN
- 1)
57 mag_info
= (struct ath_ht20_mag_info
*) (sample_end
-
58 sizeof(struct ath_ht20_mag_info
) + 1);
60 sample
= sample_end
- SPECTRAL_HT20_SAMPLE_LEN
+ 1;
62 max_index
= spectral_max_index_ht20(mag_info
->all_bins
);
63 max_magnitude
= spectral_max_magnitude(mag_info
->all_bins
);
65 max_exp
= mag_info
->max_exp
& 0xf;
67 /* Don't try to read something outside the read buffer
68 * in case of a missing byte (so bins[0] will be outside
71 if (bytes_read
< SPECTRAL_HT20_SAMPLE_LEN
&& max_index
< 1)
74 if ((sample
[max_index
] & 0xf8) != ((max_magnitude
>> max_exp
) & 0xf8))
81 ath_cmn_max_idx_verify_ht20_40_fft(u8
*sample_end
, int bytes_read
)
83 struct ath_ht20_40_mag_info
*mag_info
;
85 u16 lower_mag
, upper_mag
;
86 u8 lower_max_index
, upper_max_index
;
88 int dc_pos
= SPECTRAL_HT20_40_NUM_BINS
/ 2;
90 /* Sanity check so that we don't read outside the read
93 if (bytes_read
< SPECTRAL_HT20_40_SAMPLE_LEN
- 1)
96 mag_info
= (struct ath_ht20_40_mag_info
*) (sample_end
-
97 sizeof(struct ath_ht20_40_mag_info
) + 1);
99 sample
= sample_end
- SPECTRAL_HT20_40_SAMPLE_LEN
+ 1;
101 lower_mag
= spectral_max_magnitude(mag_info
->lower_bins
);
102 lower_max_index
= spectral_max_index_ht40(mag_info
->lower_bins
);
104 upper_mag
= spectral_max_magnitude(mag_info
->upper_bins
);
105 upper_max_index
= spectral_max_index_ht40(mag_info
->upper_bins
);
107 max_exp
= mag_info
->max_exp
& 0xf;
109 /* Don't try to read something outside the read buffer
110 * in case of a missing byte (so bins[0] will be outside
113 if (bytes_read
< SPECTRAL_HT20_40_SAMPLE_LEN
&&
114 ((upper_max_index
< 1) || (lower_max_index
< 1)))
117 if (((sample
[upper_max_index
+ dc_pos
] & 0xf8) !=
118 ((upper_mag
>> max_exp
) & 0xf8)) ||
119 ((sample
[lower_max_index
] & 0xf8) !=
120 ((lower_mag
>> max_exp
) & 0xf8)))
126 typedef int (ath_cmn_fft_sample_handler
) (struct ath_rx_status
*rs
,
127 struct ath_spec_scan_priv
*spec_priv
,
128 u8
*sample_buf
, u64 tsf
, u16 freq
, int chan_type
);
131 ath_cmn_process_ht20_fft(struct ath_rx_status
*rs
,
132 struct ath_spec_scan_priv
*spec_priv
,
134 u64 tsf
, u16 freq
, int chan_type
)
136 struct fft_sample_ht20 fft_sample_20
;
137 struct ath_common
*common
= ath9k_hw_common(spec_priv
->ah
);
138 struct ath_hw
*ah
= spec_priv
->ah
;
139 struct ath_ht20_mag_info
*mag_info
;
140 struct fft_sample_tlv
*tlv
;
143 int dc_pos
= SPECTRAL_HT20_NUM_BINS
/ 2;
144 u16 magnitude
, tmp_mag
, length
;
145 u8 max_index
, bitmap_w
, max_exp
;
147 length
= sizeof(fft_sample_20
) - sizeof(struct fft_sample_tlv
);
148 fft_sample_20
.tlv
.type
= ATH_FFT_SAMPLE_HT20
;
149 fft_sample_20
.tlv
.length
= __cpu_to_be16(length
);
150 fft_sample_20
.freq
= __cpu_to_be16(freq
);
151 fft_sample_20
.rssi
= fix_rssi_inv_only(rs
->rs_rssi_ctl
[0]);
152 fft_sample_20
.noise
= ah
->noise
;
154 mag_info
= (struct ath_ht20_mag_info
*) (sample_buf
+
155 SPECTRAL_HT20_NUM_BINS
);
157 magnitude
= spectral_max_magnitude(mag_info
->all_bins
);
158 fft_sample_20
.max_magnitude
= __cpu_to_be16(magnitude
);
160 max_index
= spectral_max_index_ht20(mag_info
->all_bins
);
161 fft_sample_20
.max_index
= max_index
;
163 bitmap_w
= spectral_bitmap_weight(mag_info
->all_bins
);
164 fft_sample_20
.bitmap_weight
= bitmap_w
;
166 max_exp
= mag_info
->max_exp
& 0xf;
167 fft_sample_20
.max_exp
= max_exp
;
169 fft_sample_20
.tsf
= __cpu_to_be64(tsf
);
171 memcpy(fft_sample_20
.data
, sample_buf
, SPECTRAL_HT20_NUM_BINS
);
173 ath_dbg(common
, SPECTRAL_SCAN
, "FFT HT20 frame: max mag 0x%X,"
175 magnitude
>> max_exp
,
178 if ((fft_sample_20
.data
[max_index
] & 0xf8) !=
179 ((magnitude
>> max_exp
) & 0xf8)) {
180 ath_dbg(common
, SPECTRAL_SCAN
, "Magnitude mismatch !\n");
184 /* DC value (value in the middle) is the blind spot of the spectral
185 * sample and invalid, interpolate it.
187 fft_sample_20
.data
[dc_pos
] = (fft_sample_20
.data
[dc_pos
+ 1] +
188 fft_sample_20
.data
[dc_pos
- 1]) / 2;
190 /* Check if the maximum magnitude is indeed maximum,
191 * also if the maximum value was at dc_pos, calculate
192 * a new one (since value at dc_pos is invalid).
194 if (max_index
== dc_pos
) {
196 for (i
= 0; i
< dc_pos
; i
++) {
197 if (fft_sample_20
.data
[i
] > tmp_mag
) {
198 tmp_mag
= fft_sample_20
.data
[i
];
199 fft_sample_20
.max_index
= i
;
203 magnitude
= tmp_mag
<< max_exp
;
204 fft_sample_20
.max_magnitude
= __cpu_to_be16(magnitude
);
206 ath_dbg(common
, SPECTRAL_SCAN
,
207 "Calculated new lower max 0x%X at %i\n",
208 tmp_mag
, fft_sample_20
.max_index
);
210 for (i
= 0; i
< SPECTRAL_HT20_NUM_BINS
; i
++) {
211 if (fft_sample_20
.data
[i
] == (magnitude
>> max_exp
))
212 ath_dbg(common
, SPECTRAL_SCAN
,
213 "Got max: 0x%X at index %i\n",
214 fft_sample_20
.data
[i
], i
);
216 if (fft_sample_20
.data
[i
] > (magnitude
>> max_exp
)) {
217 ath_dbg(common
, SPECTRAL_SCAN
,
218 "Got bin %i greater than max: 0x%X\n",
219 i
, fft_sample_20
.data
[i
]);
227 tlv
= (struct fft_sample_tlv
*)&fft_sample_20
;
229 ath_debug_send_fft_sample(spec_priv
, tlv
);
235 ath_cmn_process_ht20_40_fft(struct ath_rx_status
*rs
,
236 struct ath_spec_scan_priv
*spec_priv
,
238 u64 tsf
, u16 freq
, int chan_type
)
240 struct fft_sample_ht20_40 fft_sample_40
;
241 struct ath_common
*common
= ath9k_hw_common(spec_priv
->ah
);
242 struct ath_hw
*ah
= spec_priv
->ah
;
243 struct ath9k_hw_cal_data
*caldata
= ah
->caldata
;
244 struct ath_ht20_40_mag_info
*mag_info
;
245 struct fft_sample_tlv
*tlv
;
246 int dc_pos
= SPECTRAL_HT20_40_NUM_BINS
/ 2;
250 u16 lower_mag
, upper_mag
, tmp_mag
, length
;
251 s8 lower_rssi
, upper_rssi
;
252 u8 lower_max_index
, upper_max_index
;
253 u8 lower_bitmap_w
, upper_bitmap_w
, max_exp
;
256 ext_nf
= ath9k_hw_getchan_noise(ah
, ah
->curchan
,
257 caldata
->nfCalHist
[3].privNF
);
259 ext_nf
= ATH_DEFAULT_NOISE_FLOOR
;
261 length
= sizeof(fft_sample_40
) - sizeof(struct fft_sample_tlv
);
262 fft_sample_40
.tlv
.type
= ATH_FFT_SAMPLE_HT20_40
;
263 fft_sample_40
.tlv
.length
= __cpu_to_be16(length
);
264 fft_sample_40
.freq
= __cpu_to_be16(freq
);
265 fft_sample_40
.channel_type
= chan_type
;
267 if (chan_type
== NL80211_CHAN_HT40PLUS
) {
268 lower_rssi
= fix_rssi_inv_only(rs
->rs_rssi_ctl
[0]);
269 upper_rssi
= fix_rssi_inv_only(rs
->rs_rssi_ext
[0]);
271 fft_sample_40
.lower_noise
= ah
->noise
;
272 fft_sample_40
.upper_noise
= ext_nf
;
274 lower_rssi
= fix_rssi_inv_only(rs
->rs_rssi_ext
[0]);
275 upper_rssi
= fix_rssi_inv_only(rs
->rs_rssi_ctl
[0]);
277 fft_sample_40
.lower_noise
= ext_nf
;
278 fft_sample_40
.upper_noise
= ah
->noise
;
281 fft_sample_40
.lower_rssi
= lower_rssi
;
282 fft_sample_40
.upper_rssi
= upper_rssi
;
284 mag_info
= (struct ath_ht20_40_mag_info
*) (sample_buf
+
285 SPECTRAL_HT20_40_NUM_BINS
);
287 lower_mag
= spectral_max_magnitude(mag_info
->lower_bins
);
288 fft_sample_40
.lower_max_magnitude
= __cpu_to_be16(lower_mag
);
290 upper_mag
= spectral_max_magnitude(mag_info
->upper_bins
);
291 fft_sample_40
.upper_max_magnitude
= __cpu_to_be16(upper_mag
);
293 lower_max_index
= spectral_max_index_ht40(mag_info
->lower_bins
);
294 fft_sample_40
.lower_max_index
= lower_max_index
;
296 upper_max_index
= spectral_max_index_ht40(mag_info
->upper_bins
);
297 fft_sample_40
.upper_max_index
= upper_max_index
;
299 lower_bitmap_w
= spectral_bitmap_weight(mag_info
->lower_bins
);
300 fft_sample_40
.lower_bitmap_weight
= lower_bitmap_w
;
302 upper_bitmap_w
= spectral_bitmap_weight(mag_info
->upper_bins
);
303 fft_sample_40
.upper_bitmap_weight
= upper_bitmap_w
;
305 max_exp
= mag_info
->max_exp
& 0xf;
306 fft_sample_40
.max_exp
= max_exp
;
308 fft_sample_40
.tsf
= __cpu_to_be64(tsf
);
310 memcpy(fft_sample_40
.data
, sample_buf
, SPECTRAL_HT20_40_NUM_BINS
);
312 ath_dbg(common
, SPECTRAL_SCAN
, "FFT HT20/40 frame: lower mag 0x%X,"
313 "lower_mag_idx %i, upper mag 0x%X,"
314 "upper_mag_idx %i\n",
315 lower_mag
>> max_exp
,
317 upper_mag
>> max_exp
,
320 /* Check if we got the expected magnitude values at
323 if (((fft_sample_40
.data
[upper_max_index
+ dc_pos
] & 0xf8)
324 != ((upper_mag
>> max_exp
) & 0xf8)) ||
325 ((fft_sample_40
.data
[lower_max_index
] & 0xf8)
326 != ((lower_mag
>> max_exp
) & 0xf8))) {
327 ath_dbg(common
, SPECTRAL_SCAN
, "Magnitude mismatch !\n");
331 /* DC value (value in the middle) is the blind spot of the spectral
332 * sample and invalid, interpolate it.
334 fft_sample_40
.data
[dc_pos
] = (fft_sample_40
.data
[dc_pos
+ 1] +
335 fft_sample_40
.data
[dc_pos
- 1]) / 2;
337 /* Check if the maximum magnitudes are indeed maximum,
338 * also if the maximum value was at dc_pos, calculate
339 * a new one (since value at dc_pos is invalid).
341 if (lower_max_index
== dc_pos
) {
343 for (i
= 0; i
< dc_pos
; i
++) {
344 if (fft_sample_40
.data
[i
] > tmp_mag
) {
345 tmp_mag
= fft_sample_40
.data
[i
];
346 fft_sample_40
.lower_max_index
= i
;
350 lower_mag
= tmp_mag
<< max_exp
;
351 fft_sample_40
.lower_max_magnitude
= __cpu_to_be16(lower_mag
);
353 ath_dbg(common
, SPECTRAL_SCAN
,
354 "Calculated new lower max 0x%X at %i\n",
355 tmp_mag
, fft_sample_40
.lower_max_index
);
357 for (i
= 0; i
< dc_pos
; i
++) {
358 if (fft_sample_40
.data
[i
] == (lower_mag
>> max_exp
))
359 ath_dbg(common
, SPECTRAL_SCAN
,
360 "Got lower mag: 0x%X at index %i\n",
361 fft_sample_40
.data
[i
], i
);
363 if (fft_sample_40
.data
[i
] > (lower_mag
>> max_exp
)) {
364 ath_dbg(common
, SPECTRAL_SCAN
,
365 "Got lower bin %i higher than max: 0x%X\n",
366 i
, fft_sample_40
.data
[i
]);
371 if (upper_max_index
== dc_pos
) {
373 for (i
= dc_pos
; i
< SPECTRAL_HT20_40_NUM_BINS
; i
++) {
374 if (fft_sample_40
.data
[i
] > tmp_mag
) {
375 tmp_mag
= fft_sample_40
.data
[i
];
376 fft_sample_40
.upper_max_index
= i
;
379 upper_mag
= tmp_mag
<< max_exp
;
380 fft_sample_40
.upper_max_magnitude
= __cpu_to_be16(upper_mag
);
382 ath_dbg(common
, SPECTRAL_SCAN
,
383 "Calculated new upper max 0x%X at %i\n",
384 tmp_mag
, fft_sample_40
.upper_max_index
);
386 for (i
= dc_pos
; i
< SPECTRAL_HT20_40_NUM_BINS
; i
++) {
387 if (fft_sample_40
.data
[i
] == (upper_mag
>> max_exp
))
388 ath_dbg(common
, SPECTRAL_SCAN
,
389 "Got upper mag: 0x%X at index %i\n",
390 fft_sample_40
.data
[i
], i
);
392 if (fft_sample_40
.data
[i
] > (upper_mag
>> max_exp
)) {
393 ath_dbg(common
, SPECTRAL_SCAN
,
394 "Got upper bin %i higher than max: 0x%X\n",
395 i
, fft_sample_40
.data
[i
]);
404 tlv
= (struct fft_sample_tlv
*)&fft_sample_40
;
406 ath_debug_send_fft_sample(spec_priv
, tlv
);
412 ath_cmn_copy_fft_frame(u8
*in
, u8
*out
, int sample_len
, int sample_bytes
)
414 switch (sample_bytes
- sample_len
) {
416 /* First byte missing */
421 /* Length correct, nothing to do. */
422 memcpy(out
, in
, sample_len
);
425 /* MAC added 2 extra bytes AND first byte
428 memcpy(&out
[1], in
, 30);
430 memcpy(&out
[32], &in
[33],
434 /* MAC added 2 extra bytes at bin 30 and 32,
439 memcpy(&out
[31], &in
[33],
448 ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv
*spec_priv
)
452 struct rchan_buf
*buf
;
453 struct rchan
*rc
= spec_priv
->rfs_chan_spec_scan
;
455 for_each_possible_cpu(i
) {
456 if ((buf
= *per_cpu_ptr(rc
->buf
, i
))) {
457 ret
+= relay_buf_full(buf
);
467 /* returns 1 if this was a spectral frame, even if not handled. */
468 int ath_cmn_process_fft(struct ath_spec_scan_priv
*spec_priv
, struct ieee80211_hdr
*hdr
,
469 struct ath_rx_status
*rs
, u64 tsf
)
471 u8 sample_buf
[SPECTRAL_SAMPLE_MAX_LEN
] = {0};
472 struct ath_hw
*ah
= spec_priv
->ah
;
473 struct ath_common
*common
= ath9k_hw_common(spec_priv
->ah
);
474 struct ath_softc
*sc
= (struct ath_softc
*)common
->priv
;
475 u8 num_bins
, *vdata
= (u8
*)hdr
;
476 struct ath_radar_info
*radar_info
;
477 int len
= rs
->rs_datalen
;
481 int sample_bytes
= 0;
483 u16 fft_len
, sample_len
, freq
= ah
->curchan
->chan
->center_freq
;
484 enum nl80211_channel_type chan_type
;
485 ath_cmn_fft_idx_validator
*fft_idx_validator
;
486 ath_cmn_fft_sample_handler
*fft_handler
;
488 /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
489 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
490 * yet, but this is supposed to be possible as well.
492 if (rs
->rs_phyerr
!= ATH9K_PHYERR_RADAR
&&
493 rs
->rs_phyerr
!= ATH9K_PHYERR_FALSE_RADAR_EXT
&&
494 rs
->rs_phyerr
!= ATH9K_PHYERR_SPECTRAL
)
497 /* check if spectral scan bit is set. This does not have to be checked
498 * if received through a SPECTRAL phy error, but shouldn't hurt.
500 radar_info
= ((struct ath_radar_info
*)&vdata
[len
]) - 1;
501 if (!(radar_info
->pulse_bw_info
& SPECTRAL_SCAN_BITMASK
))
504 if (!spec_priv
->rfs_chan_spec_scan
)
507 /* Output buffers are full, no need to process anything
508 * since there is no space to put the result anyway
510 ret
= ath_cmn_is_fft_buf_full(spec_priv
);
512 ath_dbg(common
, SPECTRAL_SCAN
, "FFT report ignored, no space "
513 "left on output buffers\n");
517 chan_type
= cfg80211_get_chandef_type(&common
->hw
->conf
.chandef
);
518 if ((chan_type
== NL80211_CHAN_HT40MINUS
) ||
519 (chan_type
== NL80211_CHAN_HT40PLUS
)) {
520 fft_len
= SPECTRAL_HT20_40_TOTAL_DATA_LEN
;
521 sample_len
= SPECTRAL_HT20_40_SAMPLE_LEN
;
522 num_bins
= SPECTRAL_HT20_40_NUM_BINS
;
523 fft_idx_validator
= &ath_cmn_max_idx_verify_ht20_40_fft
;
524 fft_handler
= &ath_cmn_process_ht20_40_fft
;
526 fft_len
= SPECTRAL_HT20_TOTAL_DATA_LEN
;
527 sample_len
= SPECTRAL_HT20_SAMPLE_LEN
;
528 num_bins
= SPECTRAL_HT20_NUM_BINS
;
529 fft_idx_validator
= ath_cmn_max_idx_verify_ht20_fft
;
530 fft_handler
= &ath_cmn_process_ht20_fft
;
533 ath_dbg(common
, SPECTRAL_SCAN
, "Got radar dump bw_info: 0x%X,"
534 "len: %i fft_len: %i\n",
535 radar_info
->pulse_bw_info
,
538 sample_start
= vdata
;
539 for (i
= 0; i
< len
- 2; i
++) {
542 /* Only a single sample received, no need to look
543 * for the sample's end, do the correction based
544 * on the packet's length instead. Note that hw
545 * will always put the radar_info structure on
548 if (len
<= fft_len
+ 2) {
549 sample_bytes
= len
- sizeof(struct ath_radar_info
);
553 /* Search for the end of the FFT frame between
554 * sample_len - 1 and sample_len + 2. exp_max is 3
555 * bits long and it's the only value on the last
556 * byte of the frame so since it'll be smaller than
557 * the next byte (the first bin of the next sample)
558 * 90% of the time, we can use it as a separator.
560 if (vdata
[i
] <= 0x7 && sample_bytes
>= sample_len
- 1) {
562 /* Got a frame length within boundaries, there are
563 * four scenarios here:
565 * a) sample_len -> We got the correct length
566 * b) sample_len + 2 -> 2 bytes added around bin[31]
567 * c) sample_len - 1 -> The first byte is missing
568 * d) sample_len + 1 -> b + c at the same time
570 * When MAC adds 2 extra bytes, bin[31] and bin[32]
571 * have the same value, so we can use that for further
572 * verification in cases b and d.
575 /* Did we go too far ? If so we couldn't determine
576 * this sample's boundaries, discard any further
579 if ((sample_bytes
> sample_len
+ 2) ||
580 ((sample_bytes
> sample_len
) &&
581 (sample_start
[31] != sample_start
[32])))
584 /* See if we got a valid frame by checking the
585 * consistency of mag_info fields. This is to
586 * prevent from "fixing" a correct frame.
587 * Failure is non-fatal, later frames may
590 if (!fft_idx_validator(&vdata
[i
], i
)) {
591 ath_dbg(common
, SPECTRAL_SCAN
,
592 "Found valid fft frame at %i\n", i
);
596 /* We expect 1 - 2 more bytes */
597 else if ((sample_start
[31] == sample_start
[32]) &&
598 (sample_bytes
>= sample_len
) &&
599 (sample_bytes
< sample_len
+ 2) &&
600 (vdata
[i
+ 1] <= 0x7))
603 /* Try to distinguish cases a and c */
604 else if ((sample_bytes
== sample_len
- 1) &&
605 (vdata
[i
+ 1] <= 0x7))
612 ath_dbg(common
, SPECTRAL_SCAN
, "FFT frame len: %i\n",
615 /* Only try to fix a frame if it's the only one
616 * on the report, else just skip it.
618 if (sample_bytes
!= sample_len
&& len
<= fft_len
+ 2) {
619 ath_cmn_copy_fft_frame(sample_start
,
620 sample_buf
, sample_len
,
623 ret
= fft_handler(rs
, spec_priv
, sample_buf
,
624 tsf
, freq
, chan_type
);
627 RX_STAT_INC(sc
, rx_spectral_sample_good
);
629 RX_STAT_INC(sc
, rx_spectral_sample_err
);
631 memset(sample_buf
, 0, SPECTRAL_SAMPLE_MAX_LEN
);
633 /* Mix the received bins to the /dev/random
636 add_device_randomness(sample_buf
, num_bins
);
639 /* Process a normal frame */
640 if (sample_bytes
== sample_len
) {
641 ret
= fft_handler(rs
, spec_priv
, sample_start
,
642 tsf
, freq
, chan_type
);
645 RX_STAT_INC(sc
, rx_spectral_sample_good
);
647 RX_STAT_INC(sc
, rx_spectral_sample_err
);
649 /* Mix the received bins to the /dev/random
652 add_device_randomness(sample_start
, num_bins
);
655 /* Short report processed, break out of the
658 if (len
<= fft_len
+ 2)
661 sample_start
= &vdata
[i
+ 1];
663 /* -1 to grab sample_len -1, -2 since
664 * they 'll get increased by one. In case
665 * of failure try to recover by going byte
670 sample_bytes
= num_bins
- 2;
677 if (len
- i
!= sizeof(struct ath_radar_info
))
678 ath_dbg(common
, SPECTRAL_SCAN
, "FFT report truncated"
679 "(bytes left: %i)\n",
683 EXPORT_SYMBOL(ath_cmn_process_fft
);
685 /*********************/
686 /* spectral_scan_ctl */
687 /*********************/
689 static ssize_t
read_file_spec_scan_ctl(struct file
*file
, char __user
*user_buf
,
690 size_t count
, loff_t
*ppos
)
692 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
696 switch (spec_priv
->spectral_mode
) {
697 case SPECTRAL_DISABLED
:
700 case SPECTRAL_BACKGROUND
:
703 case SPECTRAL_CHANSCAN
:
706 case SPECTRAL_MANUAL
:
711 return simple_read_from_buffer(user_buf
, count
, ppos
, mode
, len
);
714 void ath9k_cmn_spectral_scan_trigger(struct ath_common
*common
,
715 struct ath_spec_scan_priv
*spec_priv
)
717 struct ath_hw
*ah
= spec_priv
->ah
;
720 if (IS_ENABLED(CONFIG_ATH9K_TX99
))
723 if (!ath9k_hw_ops(ah
)->spectral_scan_trigger
) {
724 ath_err(common
, "spectrum analyzer not implemented on this hardware\n");
728 if (!spec_priv
->spec_config
.enabled
)
731 ath_ps_ops(common
)->wakeup(common
);
732 rxfilter
= ath9k_hw_getrxfilter(ah
);
733 ath9k_hw_setrxfilter(ah
, rxfilter
|
734 ATH9K_RX_FILTER_PHYRADAR
|
735 ATH9K_RX_FILTER_PHYERR
);
737 /* TODO: usually this should not be neccesary, but for some reason
738 * (or in some mode?) the trigger must be called after the
739 * configuration, otherwise the register will have its values reset
740 * (on my ar9220 to value 0x01002310)
742 ath9k_cmn_spectral_scan_config(common
, spec_priv
, spec_priv
->spectral_mode
);
743 ath9k_hw_ops(ah
)->spectral_scan_trigger(ah
);
744 ath_ps_ops(common
)->restore(common
);
746 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_trigger
);
748 int ath9k_cmn_spectral_scan_config(struct ath_common
*common
,
749 struct ath_spec_scan_priv
*spec_priv
,
750 enum spectral_mode spectral_mode
)
752 struct ath_hw
*ah
= spec_priv
->ah
;
754 if (!ath9k_hw_ops(ah
)->spectral_scan_trigger
) {
755 ath_err(common
, "spectrum analyzer not implemented on this hardware\n");
759 switch (spectral_mode
) {
760 case SPECTRAL_DISABLED
:
761 spec_priv
->spec_config
.enabled
= 0;
763 case SPECTRAL_BACKGROUND
:
764 /* send endless samples.
765 * TODO: is this really useful for "background"?
767 spec_priv
->spec_config
.endless
= 1;
768 spec_priv
->spec_config
.enabled
= 1;
770 case SPECTRAL_CHANSCAN
:
771 case SPECTRAL_MANUAL
:
772 spec_priv
->spec_config
.endless
= 0;
773 spec_priv
->spec_config
.enabled
= 1;
779 ath_ps_ops(common
)->wakeup(common
);
780 ath9k_hw_ops(ah
)->spectral_scan_config(ah
, &spec_priv
->spec_config
);
781 ath_ps_ops(common
)->restore(common
);
783 spec_priv
->spectral_mode
= spectral_mode
;
787 EXPORT_SYMBOL(ath9k_cmn_spectral_scan_config
);
789 static ssize_t
write_file_spec_scan_ctl(struct file
*file
,
790 const char __user
*user_buf
,
791 size_t count
, loff_t
*ppos
)
793 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
794 struct ath_common
*common
= ath9k_hw_common(spec_priv
->ah
);
798 if (IS_ENABLED(CONFIG_ATH9K_TX99
))
801 len
= min(count
, sizeof(buf
) - 1);
802 if (copy_from_user(buf
, user_buf
, len
))
807 if (strncmp("trigger", buf
, 7) == 0) {
808 ath9k_cmn_spectral_scan_trigger(common
, spec_priv
);
809 } else if (strncmp("background", buf
, 10) == 0) {
810 ath9k_cmn_spectral_scan_config(common
, spec_priv
, SPECTRAL_BACKGROUND
);
811 ath_dbg(common
, CONFIG
, "spectral scan: background mode enabled\n");
812 } else if (strncmp("chanscan", buf
, 8) == 0) {
813 ath9k_cmn_spectral_scan_config(common
, spec_priv
, SPECTRAL_CHANSCAN
);
814 ath_dbg(common
, CONFIG
, "spectral scan: channel scan mode enabled\n");
815 } else if (strncmp("manual", buf
, 6) == 0) {
816 ath9k_cmn_spectral_scan_config(common
, spec_priv
, SPECTRAL_MANUAL
);
817 ath_dbg(common
, CONFIG
, "spectral scan: manual mode enabled\n");
818 } else if (strncmp("disable", buf
, 7) == 0) {
819 ath9k_cmn_spectral_scan_config(common
, spec_priv
, SPECTRAL_DISABLED
);
820 ath_dbg(common
, CONFIG
, "spectral scan: disabled\n");
828 static const struct file_operations fops_spec_scan_ctl
= {
829 .read
= read_file_spec_scan_ctl
,
830 .write
= write_file_spec_scan_ctl
,
832 .owner
= THIS_MODULE
,
833 .llseek
= default_llseek
,
836 /*************************/
837 /* spectral_short_repeat */
838 /*************************/
840 static ssize_t
read_file_spectral_short_repeat(struct file
*file
,
841 char __user
*user_buf
,
842 size_t count
, loff_t
*ppos
)
844 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
848 len
= sprintf(buf
, "%d\n", spec_priv
->spec_config
.short_repeat
);
849 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
852 static ssize_t
write_file_spectral_short_repeat(struct file
*file
,
853 const char __user
*user_buf
,
854 size_t count
, loff_t
*ppos
)
856 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
861 len
= min(count
, sizeof(buf
) - 1);
862 if (copy_from_user(buf
, user_buf
, len
))
866 if (kstrtoul(buf
, 0, &val
))
872 spec_priv
->spec_config
.short_repeat
= val
;
876 static const struct file_operations fops_spectral_short_repeat
= {
877 .read
= read_file_spectral_short_repeat
,
878 .write
= write_file_spectral_short_repeat
,
880 .owner
= THIS_MODULE
,
881 .llseek
= default_llseek
,
888 static ssize_t
read_file_spectral_count(struct file
*file
,
889 char __user
*user_buf
,
890 size_t count
, loff_t
*ppos
)
892 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
896 len
= sprintf(buf
, "%d\n", spec_priv
->spec_config
.count
);
897 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
900 static ssize_t
write_file_spectral_count(struct file
*file
,
901 const char __user
*user_buf
,
902 size_t count
, loff_t
*ppos
)
904 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
909 len
= min(count
, sizeof(buf
) - 1);
910 if (copy_from_user(buf
, user_buf
, len
))
914 if (kstrtoul(buf
, 0, &val
))
920 spec_priv
->spec_config
.count
= val
;
924 static const struct file_operations fops_spectral_count
= {
925 .read
= read_file_spectral_count
,
926 .write
= write_file_spectral_count
,
928 .owner
= THIS_MODULE
,
929 .llseek
= default_llseek
,
932 /*******************/
933 /* spectral_period */
934 /*******************/
936 static ssize_t
read_file_spectral_period(struct file
*file
,
937 char __user
*user_buf
,
938 size_t count
, loff_t
*ppos
)
940 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
944 len
= sprintf(buf
, "%d\n", spec_priv
->spec_config
.period
);
945 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
948 static ssize_t
write_file_spectral_period(struct file
*file
,
949 const char __user
*user_buf
,
950 size_t count
, loff_t
*ppos
)
952 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
957 len
= min(count
, sizeof(buf
) - 1);
958 if (copy_from_user(buf
, user_buf
, len
))
962 if (kstrtoul(buf
, 0, &val
))
968 spec_priv
->spec_config
.period
= val
;
972 static const struct file_operations fops_spectral_period
= {
973 .read
= read_file_spectral_period
,
974 .write
= write_file_spectral_period
,
976 .owner
= THIS_MODULE
,
977 .llseek
= default_llseek
,
980 /***********************/
981 /* spectral_fft_period */
982 /***********************/
984 static ssize_t
read_file_spectral_fft_period(struct file
*file
,
985 char __user
*user_buf
,
986 size_t count
, loff_t
*ppos
)
988 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
992 len
= sprintf(buf
, "%d\n", spec_priv
->spec_config
.fft_period
);
993 return simple_read_from_buffer(user_buf
, count
, ppos
, buf
, len
);
996 static ssize_t
write_file_spectral_fft_period(struct file
*file
,
997 const char __user
*user_buf
,
998 size_t count
, loff_t
*ppos
)
1000 struct ath_spec_scan_priv
*spec_priv
= file
->private_data
;
1005 len
= min(count
, sizeof(buf
) - 1);
1006 if (copy_from_user(buf
, user_buf
, len
))
1010 if (kstrtoul(buf
, 0, &val
))
1016 spec_priv
->spec_config
.fft_period
= val
;
1020 static const struct file_operations fops_spectral_fft_period
= {
1021 .read
= read_file_spectral_fft_period
,
1022 .write
= write_file_spectral_fft_period
,
1023 .open
= simple_open
,
1024 .owner
= THIS_MODULE
,
1025 .llseek
= default_llseek
,
1028 /*******************/
1029 /* Relay interface */
1030 /*******************/
1032 static struct dentry
*create_buf_file_handler(const char *filename
,
1033 struct dentry
*parent
,
1035 struct rchan_buf
*buf
,
1038 struct dentry
*buf_file
;
1040 buf_file
= debugfs_create_file(filename
, mode
, parent
, buf
,
1041 &relay_file_operations
);
1042 if (IS_ERR(buf_file
))
1049 static int remove_buf_file_handler(struct dentry
*dentry
)
1051 debugfs_remove(dentry
);
1056 static const struct rchan_callbacks rfs_spec_scan_cb
= {
1057 .create_buf_file
= create_buf_file_handler
,
1058 .remove_buf_file
= remove_buf_file_handler
,
1061 /*********************/
1062 /* Debug Init/Deinit */
1063 /*********************/
1065 void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv
*spec_priv
)
1067 if (spec_priv
->rfs_chan_spec_scan
) {
1068 relay_close(spec_priv
->rfs_chan_spec_scan
);
1069 spec_priv
->rfs_chan_spec_scan
= NULL
;
1072 EXPORT_SYMBOL(ath9k_cmn_spectral_deinit_debug
);
1074 void ath9k_cmn_spectral_init_debug(struct ath_spec_scan_priv
*spec_priv
,
1075 struct dentry
*debugfs_phy
)
1077 spec_priv
->rfs_chan_spec_scan
= relay_open("spectral_scan",
1079 1024, 256, &rfs_spec_scan_cb
,
1081 if (!spec_priv
->rfs_chan_spec_scan
)
1084 debugfs_create_file("spectral_scan_ctl",
1086 debugfs_phy
, spec_priv
,
1087 &fops_spec_scan_ctl
);
1088 debugfs_create_file("spectral_short_repeat",
1090 debugfs_phy
, spec_priv
,
1091 &fops_spectral_short_repeat
);
1092 debugfs_create_file("spectral_count",
1094 debugfs_phy
, spec_priv
,
1095 &fops_spectral_count
);
1096 debugfs_create_file("spectral_period",
1098 debugfs_phy
, spec_priv
,
1099 &fops_spectral_period
);
1100 debugfs_create_file("spectral_fft_period",
1102 debugfs_phy
, spec_priv
,
1103 &fops_spectral_fft_period
);
1105 EXPORT_SYMBOL(ath9k_cmn_spectral_init_debug
);