18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 38c2ecf20Sopenharmony_ci * Copyright (c) 2011 Neratec Solutions AG 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 68c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 78c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 108c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 118c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 128c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 138c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 158c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "hw.h" 198c2ecf20Sopenharmony_ci#include "hw-ops.h" 208c2ecf20Sopenharmony_ci#include "ath9k.h" 218c2ecf20Sopenharmony_ci#include "dfs.h" 228c2ecf20Sopenharmony_ci#include "dfs_debug.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* internal struct to pass radar data */ 258c2ecf20Sopenharmony_cistruct ath_radar_data { 268c2ecf20Sopenharmony_ci u8 pulse_bw_info; 278c2ecf20Sopenharmony_ci u8 rssi; 288c2ecf20Sopenharmony_ci u8 ext_rssi; 298c2ecf20Sopenharmony_ci u8 pulse_length_ext; 308c2ecf20Sopenharmony_ci u8 pulse_length_pri; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/**** begin: CHIRP ************************************************************/ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* min and max gradients for defined FCC chirping pulses, given by 368c2ecf20Sopenharmony_ci * - 20MHz chirp width over a pulse width of 50us 378c2ecf20Sopenharmony_ci * - 5MHz chirp width over a pulse width of 100us 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_cistatic const int BIN_DELTA_MIN = 1; 408c2ecf20Sopenharmony_cistatic const int BIN_DELTA_MAX = 10; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* we need at least 3 deltas / 4 samples for a reliable chirp detection */ 438c2ecf20Sopenharmony_ci#define NUM_DIFFS 3 448c2ecf20Sopenharmony_ci#define FFT_NUM_SAMPLES (NUM_DIFFS + 1) 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* Threshold for difference of delta peaks */ 478c2ecf20Sopenharmony_cistatic const int MAX_DIFF = 2; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* width range to be checked for chirping */ 508c2ecf20Sopenharmony_cistatic const int MIN_CHIRP_PULSE_WIDTH = 20; 518c2ecf20Sopenharmony_cistatic const int MAX_CHIRP_PULSE_WIDTH = 110; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistruct ath9k_dfs_fft_20 { 548c2ecf20Sopenharmony_ci u8 bin[28]; 558c2ecf20Sopenharmony_ci u8 lower_bins[3]; 568c2ecf20Sopenharmony_ci} __packed; 578c2ecf20Sopenharmony_cistruct ath9k_dfs_fft_40 { 588c2ecf20Sopenharmony_ci u8 bin[64]; 598c2ecf20Sopenharmony_ci u8 lower_bins[3]; 608c2ecf20Sopenharmony_ci u8 upper_bins[3]; 618c2ecf20Sopenharmony_ci} __packed; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic inline int fft_max_index(u8 *bins) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci return (bins[2] & 0xfc) >> 2; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_cistatic inline int fft_max_magnitude(u8 *bins) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_cistatic inline u8 fft_bitmap_weight(u8 *bins) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci return bins[0] & 0x3f; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, 778c2ecf20Sopenharmony_ci bool is_ctl, bool is_ext) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci const int DFS_UPPER_BIN_OFFSET = 64; 808c2ecf20Sopenharmony_ci /* if detected radar on both channels, select the significant one */ 818c2ecf20Sopenharmony_ci if (is_ctl && is_ext) { 828c2ecf20Sopenharmony_ci /* first check wether channels have 'strong' bins */ 838c2ecf20Sopenharmony_ci is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; 848c2ecf20Sopenharmony_ci is_ext = fft_bitmap_weight(fft->upper_bins) != 0; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* if still unclear, take higher magnitude */ 878c2ecf20Sopenharmony_ci if (is_ctl && is_ext) { 888c2ecf20Sopenharmony_ci int mag_lower = fft_max_magnitude(fft->lower_bins); 898c2ecf20Sopenharmony_ci int mag_upper = fft_max_magnitude(fft->upper_bins); 908c2ecf20Sopenharmony_ci if (mag_upper > mag_lower) 918c2ecf20Sopenharmony_ci is_ctl = false; 928c2ecf20Sopenharmony_ci else 938c2ecf20Sopenharmony_ci is_ext = false; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci if (is_ctl) 978c2ecf20Sopenharmony_ci return fft_max_index(fft->lower_bins); 988c2ecf20Sopenharmony_ci return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_cistatic bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, 1018c2ecf20Sopenharmony_ci int datalen, bool is_ctl, bool is_ext) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci int i; 1048c2ecf20Sopenharmony_ci int max_bin[FFT_NUM_SAMPLES]; 1058c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 1068c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 1078c2ecf20Sopenharmony_ci int prev_delta; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (IS_CHAN_HT40(ah->curchan)) { 1108c2ecf20Sopenharmony_ci struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; 1118c2ecf20Sopenharmony_ci int num_fft_packets = datalen / sizeof(*fft); 1128c2ecf20Sopenharmony_ci if (num_fft_packets == 0) 1138c2ecf20Sopenharmony_ci return false; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", 1168c2ecf20Sopenharmony_ci datalen, num_fft_packets); 1178c2ecf20Sopenharmony_ci if (num_fft_packets < FFT_NUM_SAMPLES) { 1188c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "not enough packets for chirp\n"); 1198c2ecf20Sopenharmony_ci return false; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci /* HW sometimes adds 2 garbage bytes in front of FFT samples */ 1228c2ecf20Sopenharmony_ci if ((datalen % sizeof(*fft)) == 2) { 1238c2ecf20Sopenharmony_ci fft = (struct ath9k_dfs_fft_40 *) (data + 2); 1248c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "fixing datalen by 2\n"); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci if (IS_CHAN_HT40MINUS(ah->curchan)) 1278c2ecf20Sopenharmony_ci swap(is_ctl, is_ext); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci for (i = 0; i < FFT_NUM_SAMPLES; i++) 1308c2ecf20Sopenharmony_ci max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, 1318c2ecf20Sopenharmony_ci is_ext); 1328c2ecf20Sopenharmony_ci } else { 1338c2ecf20Sopenharmony_ci struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; 1348c2ecf20Sopenharmony_ci int num_fft_packets = datalen / sizeof(*fft); 1358c2ecf20Sopenharmony_ci if (num_fft_packets == 0) 1368c2ecf20Sopenharmony_ci return false; 1378c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", 1388c2ecf20Sopenharmony_ci datalen, num_fft_packets); 1398c2ecf20Sopenharmony_ci if (num_fft_packets < FFT_NUM_SAMPLES) { 1408c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "not enough packets for chirp\n"); 1418c2ecf20Sopenharmony_ci return false; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci /* in ht20, this is a 6-bit signed number => shift it to 0 */ 1448c2ecf20Sopenharmony_ci for (i = 0; i < FFT_NUM_SAMPLES; i++) 1458c2ecf20Sopenharmony_ci max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", 1488c2ecf20Sopenharmony_ci max_bin[0], max_bin[1], max_bin[2], max_bin[3]); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci /* Check for chirp attributes within specs 1518c2ecf20Sopenharmony_ci * a) delta of adjacent max_bins is within range 1528c2ecf20Sopenharmony_ci * b) delta of adjacent deltas are within tolerance 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci prev_delta = 0; 1558c2ecf20Sopenharmony_ci for (i = 0; i < NUM_DIFFS; i++) { 1568c2ecf20Sopenharmony_ci int ddelta = -1; 1578c2ecf20Sopenharmony_ci int delta = max_bin[i + 1] - max_bin[i]; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* ensure gradient is within valid range */ 1608c2ecf20Sopenharmony_ci if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { 1618c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "CHIRP: invalid delta %d " 1628c2ecf20Sopenharmony_ci "in sample %d\n", delta, i); 1638c2ecf20Sopenharmony_ci return false; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci if (i == 0) 1668c2ecf20Sopenharmony_ci goto done; 1678c2ecf20Sopenharmony_ci ddelta = delta - prev_delta; 1688c2ecf20Sopenharmony_ci if (abs(ddelta) > MAX_DIFF) { 1698c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", 1708c2ecf20Sopenharmony_ci ddelta); 1718c2ecf20Sopenharmony_ci return false; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_cidone: 1748c2ecf20Sopenharmony_ci ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", 1758c2ecf20Sopenharmony_ci i, delta, ddelta); 1768c2ecf20Sopenharmony_ci prev_delta = delta; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci return true; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci/**** end: CHIRP **************************************************************/ 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* convert pulse duration to usecs, considering clock mode */ 1838c2ecf20Sopenharmony_cistatic u32 dur_to_usecs(struct ath_hw *ah, u32 dur) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci const u32 AR93X_NSECS_PER_DUR = 800; 1868c2ecf20Sopenharmony_ci const u32 AR93X_NSECS_PER_DUR_FAST = (8000 / 11); 1878c2ecf20Sopenharmony_ci u32 nsecs; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (IS_CHAN_A_FAST_CLOCK(ah, ah->curchan)) 1908c2ecf20Sopenharmony_ci nsecs = dur * AR93X_NSECS_PER_DUR_FAST; 1918c2ecf20Sopenharmony_ci else 1928c2ecf20Sopenharmony_ci nsecs = dur * AR93X_NSECS_PER_DUR; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci return (nsecs + 500) / 1000; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci#define PRI_CH_RADAR_FOUND 0x01 1988c2ecf20Sopenharmony_ci#define EXT_CH_RADAR_FOUND 0x02 1998c2ecf20Sopenharmony_cistatic bool 2008c2ecf20Sopenharmony_ciath9k_postprocess_radar_event(struct ath_softc *sc, 2018c2ecf20Sopenharmony_ci struct ath_radar_data *ard, 2028c2ecf20Sopenharmony_ci struct pulse_event *pe) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci u8 rssi; 2058c2ecf20Sopenharmony_ci u16 dur; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* 2088c2ecf20Sopenharmony_ci * Only the last 2 bits of the BW info are relevant, they indicate 2098c2ecf20Sopenharmony_ci * which channel the radar was detected in. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci ard->pulse_bw_info &= 0x03; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci switch (ard->pulse_bw_info) { 2148c2ecf20Sopenharmony_ci case PRI_CH_RADAR_FOUND: 2158c2ecf20Sopenharmony_ci /* radar in ctrl channel */ 2168c2ecf20Sopenharmony_ci dur = ard->pulse_length_pri; 2178c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, pri_phy_errors); 2188c2ecf20Sopenharmony_ci /* 2198c2ecf20Sopenharmony_ci * cannot use ctrl channel RSSI 2208c2ecf20Sopenharmony_ci * if extension channel is stronger 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ci rssi = (ard->ext_rssi >= (ard->rssi + 3)) ? 0 : ard->rssi; 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci case EXT_CH_RADAR_FOUND: 2258c2ecf20Sopenharmony_ci /* radar in extension channel */ 2268c2ecf20Sopenharmony_ci dur = ard->pulse_length_ext; 2278c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, ext_phy_errors); 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * cannot use extension channel RSSI 2308c2ecf20Sopenharmony_ci * if control channel is stronger 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_ci rssi = (ard->rssi >= (ard->ext_rssi + 12)) ? 0 : ard->ext_rssi; 2338c2ecf20Sopenharmony_ci break; 2348c2ecf20Sopenharmony_ci case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND): 2358c2ecf20Sopenharmony_ci /* 2368c2ecf20Sopenharmony_ci * Conducted testing, when pulse is on DC, both pri and ext 2378c2ecf20Sopenharmony_ci * durations are reported to be same 2388c2ecf20Sopenharmony_ci * 2398c2ecf20Sopenharmony_ci * Radiated testing, when pulse is on DC, different pri and 2408c2ecf20Sopenharmony_ci * ext durations are reported, so take the larger of the two 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci if (ard->pulse_length_ext >= ard->pulse_length_pri) 2438c2ecf20Sopenharmony_ci dur = ard->pulse_length_ext; 2448c2ecf20Sopenharmony_ci else 2458c2ecf20Sopenharmony_ci dur = ard->pulse_length_pri; 2468c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, dc_phy_errors); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* when both are present use stronger one */ 2498c2ecf20Sopenharmony_ci rssi = (ard->rssi < ard->ext_rssi) ? ard->ext_rssi : ard->rssi; 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci default: 2528c2ecf20Sopenharmony_ci /* 2538c2ecf20Sopenharmony_ci * Bogus bandwidth info was received in descriptor, 2548c2ecf20Sopenharmony_ci * so ignore this PHY error 2558c2ecf20Sopenharmony_ci */ 2568c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, bwinfo_discards); 2578c2ecf20Sopenharmony_ci return false; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (rssi == 0) { 2618c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, rssi_discards); 2628c2ecf20Sopenharmony_ci return false; 2638c2ecf20Sopenharmony_ci } 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci /* convert duration to usecs */ 2668c2ecf20Sopenharmony_ci pe->width = dur_to_usecs(sc->sc_ah, dur); 2678c2ecf20Sopenharmony_ci pe->rssi = rssi; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, pulses_detected); 2708c2ecf20Sopenharmony_ci return true; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic void 2748c2ecf20Sopenharmony_ciath9k_dfs_process_radar_pulse(struct ath_softc *sc, struct pulse_event *pe) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci struct dfs_pattern_detector *pd = sc->dfs_detector; 2778c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, pulses_processed); 2788c2ecf20Sopenharmony_ci if (pd == NULL) 2798c2ecf20Sopenharmony_ci return; 2808c2ecf20Sopenharmony_ci if (!pd->add_pulse(pd, pe, NULL)) 2818c2ecf20Sopenharmony_ci return; 2828c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, radar_detected); 2838c2ecf20Sopenharmony_ci ieee80211_radar_detected(sc->hw); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/* 2878c2ecf20Sopenharmony_ci * DFS: check PHY-error for radar pulse and feed the detector 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_civoid ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, 2908c2ecf20Sopenharmony_ci struct ath_rx_status *rs, u64 mactime) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct ath_radar_data ard; 2938c2ecf20Sopenharmony_ci u16 datalen; 2948c2ecf20Sopenharmony_ci char *vdata_end; 2958c2ecf20Sopenharmony_ci struct pulse_event pe; 2968c2ecf20Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 2978c2ecf20Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, pulses_total); 3008c2ecf20Sopenharmony_ci if ((rs->rs_phyerr != ATH9K_PHYERR_RADAR) && 3018c2ecf20Sopenharmony_ci (rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT)) { 3028c2ecf20Sopenharmony_ci ath_dbg(common, DFS, 3038c2ecf20Sopenharmony_ci "Error: rs_phyer=0x%x not a radar error\n", 3048c2ecf20Sopenharmony_ci rs->rs_phyerr); 3058c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, pulses_no_dfs); 3068c2ecf20Sopenharmony_ci return; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci datalen = rs->rs_datalen; 3108c2ecf20Sopenharmony_ci if (datalen == 0) { 3118c2ecf20Sopenharmony_ci DFS_STAT_INC(sc, datalen_discards); 3128c2ecf20Sopenharmony_ci return; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ard.rssi = rs->rs_rssi_ctl[0]; 3168c2ecf20Sopenharmony_ci ard.ext_rssi = rs->rs_rssi_ext[0]; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* 3198c2ecf20Sopenharmony_ci * hardware stores this as 8 bit signed value. 3208c2ecf20Sopenharmony_ci * we will cap it at 0 if it is a negative number 3218c2ecf20Sopenharmony_ci */ 3228c2ecf20Sopenharmony_ci if (ard.rssi & 0x80) 3238c2ecf20Sopenharmony_ci ard.rssi = 0; 3248c2ecf20Sopenharmony_ci if (ard.ext_rssi & 0x80) 3258c2ecf20Sopenharmony_ci ard.ext_rssi = 0; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci vdata_end = data + datalen; 3288c2ecf20Sopenharmony_ci ard.pulse_bw_info = vdata_end[-1]; 3298c2ecf20Sopenharmony_ci ard.pulse_length_ext = vdata_end[-2]; 3308c2ecf20Sopenharmony_ci ard.pulse_length_pri = vdata_end[-3]; 3318c2ecf20Sopenharmony_ci pe.freq = ah->curchan->channel; 3328c2ecf20Sopenharmony_ci pe.ts = mactime; 3338c2ecf20Sopenharmony_ci if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) 3348c2ecf20Sopenharmony_ci return; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (pe.width > MIN_CHIRP_PULSE_WIDTH && 3378c2ecf20Sopenharmony_ci pe.width < MAX_CHIRP_PULSE_WIDTH) { 3388c2ecf20Sopenharmony_ci bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); 3398c2ecf20Sopenharmony_ci bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); 3408c2ecf20Sopenharmony_ci int clen = datalen - 3; 3418c2ecf20Sopenharmony_ci pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); 3428c2ecf20Sopenharmony_ci } else { 3438c2ecf20Sopenharmony_ci pe.chirp = false; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ath_dbg(common, DFS, 3478c2ecf20Sopenharmony_ci "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " 3488c2ecf20Sopenharmony_ci "width=%d, rssi=%d, delta_ts=%llu\n", 3498c2ecf20Sopenharmony_ci ard.pulse_bw_info, pe.freq, pe.ts, pe.width, pe.rssi, 3508c2ecf20Sopenharmony_ci pe.ts - sc->dfs_prev_pulse_ts); 3518c2ecf20Sopenharmony_ci sc->dfs_prev_pulse_ts = pe.ts; 3528c2ecf20Sopenharmony_ci if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND) 3538c2ecf20Sopenharmony_ci ath9k_dfs_process_radar_pulse(sc, &pe); 3548c2ecf20Sopenharmony_ci if (IS_CHAN_HT40(ah->curchan) && 3558c2ecf20Sopenharmony_ci ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { 3568c2ecf20Sopenharmony_ci pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20; 3578c2ecf20Sopenharmony_ci ath9k_dfs_process_radar_pulse(sc, &pe); 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci#undef PRI_CH_RADAR_FOUND 3618c2ecf20Sopenharmony_ci#undef EXT_CH_RADAR_FOUND 362