129942bc1SZefir Kurtisi /* 229942bc1SZefir Kurtisi * Copyright (c) 2008-2011 Atheros Communications Inc. 329942bc1SZefir Kurtisi * Copyright (c) 2011 Neratec Solutions AG 429942bc1SZefir Kurtisi * 529942bc1SZefir Kurtisi * Permission to use, copy, modify, and/or distribute this software for any 629942bc1SZefir Kurtisi * purpose with or without fee is hereby granted, provided that the above 729942bc1SZefir Kurtisi * copyright notice and this permission notice appear in all copies. 829942bc1SZefir Kurtisi * 929942bc1SZefir Kurtisi * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1029942bc1SZefir Kurtisi * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1129942bc1SZefir Kurtisi * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1229942bc1SZefir Kurtisi * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1329942bc1SZefir Kurtisi * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1429942bc1SZefir Kurtisi * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1529942bc1SZefir Kurtisi * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1629942bc1SZefir Kurtisi */ 1729942bc1SZefir Kurtisi 1829942bc1SZefir Kurtisi #include "hw.h" 1929942bc1SZefir Kurtisi #include "hw-ops.h" 2029942bc1SZefir Kurtisi #include "ath9k.h" 2129942bc1SZefir Kurtisi #include "dfs.h" 2229942bc1SZefir Kurtisi #include "dfs_debug.h" 2329942bc1SZefir Kurtisi 2429942bc1SZefir Kurtisi /* internal struct to pass radar data */ 2529942bc1SZefir Kurtisi struct ath_radar_data { 2629942bc1SZefir Kurtisi u8 pulse_bw_info; 2729942bc1SZefir Kurtisi u8 rssi; 2829942bc1SZefir Kurtisi u8 ext_rssi; 2929942bc1SZefir Kurtisi u8 pulse_length_ext; 3029942bc1SZefir Kurtisi u8 pulse_length_pri; 3129942bc1SZefir Kurtisi }; 3229942bc1SZefir Kurtisi 338fc2b61aSZefir Kurtisi /**** begin: CHIRP ************************************************************/ 348fc2b61aSZefir Kurtisi 358fc2b61aSZefir Kurtisi /* min and max gradients for defined FCC chirping pulses, given by 368fc2b61aSZefir Kurtisi * - 20MHz chirp width over a pulse width of 50us 378fc2b61aSZefir Kurtisi * - 5MHz chirp width over a pulse width of 100us 388fc2b61aSZefir Kurtisi */ 398fc2b61aSZefir Kurtisi static const int BIN_DELTA_MIN = 1; 408fc2b61aSZefir Kurtisi static const int BIN_DELTA_MAX = 10; 418fc2b61aSZefir Kurtisi 428fc2b61aSZefir Kurtisi /* we need at least 3 deltas / 4 samples for a reliable chirp detection */ 438fc2b61aSZefir Kurtisi #define NUM_DIFFS 3 449c27489aSGustavo A. R. Silva #define FFT_NUM_SAMPLES (NUM_DIFFS + 1) 458fc2b61aSZefir Kurtisi 468fc2b61aSZefir Kurtisi /* Threshold for difference of delta peaks */ 478fc2b61aSZefir Kurtisi static const int MAX_DIFF = 2; 488fc2b61aSZefir Kurtisi 498fc2b61aSZefir Kurtisi /* width range to be checked for chirping */ 508fc2b61aSZefir Kurtisi static const int MIN_CHIRP_PULSE_WIDTH = 20; 518fc2b61aSZefir Kurtisi static const int MAX_CHIRP_PULSE_WIDTH = 110; 528fc2b61aSZefir Kurtisi 538fc2b61aSZefir Kurtisi struct ath9k_dfs_fft_20 { 548fc2b61aSZefir Kurtisi u8 bin[28]; 558fc2b61aSZefir Kurtisi u8 lower_bins[3]; 568fc2b61aSZefir Kurtisi } __packed; 578fc2b61aSZefir Kurtisi struct ath9k_dfs_fft_40 { 588fc2b61aSZefir Kurtisi u8 bin[64]; 598fc2b61aSZefir Kurtisi u8 lower_bins[3]; 608fc2b61aSZefir Kurtisi u8 upper_bins[3]; 618fc2b61aSZefir Kurtisi } __packed; 628fc2b61aSZefir Kurtisi 638fc2b61aSZefir Kurtisi static inline int fft_max_index(u8 *bins) 648fc2b61aSZefir Kurtisi { 658fc2b61aSZefir Kurtisi return (bins[2] & 0xfc) >> 2; 668fc2b61aSZefir Kurtisi } 678fc2b61aSZefir Kurtisi static inline int fft_max_magnitude(u8 *bins) 688fc2b61aSZefir Kurtisi { 698fc2b61aSZefir Kurtisi return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; 708fc2b61aSZefir Kurtisi } 718fc2b61aSZefir Kurtisi static inline u8 fft_bitmap_weight(u8 *bins) 728fc2b61aSZefir Kurtisi { 738fc2b61aSZefir Kurtisi return bins[0] & 0x3f; 748fc2b61aSZefir Kurtisi } 758fc2b61aSZefir Kurtisi 768fc2b61aSZefir Kurtisi static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, 778fc2b61aSZefir Kurtisi bool is_ctl, bool is_ext) 788fc2b61aSZefir Kurtisi { 798fc2b61aSZefir Kurtisi const int DFS_UPPER_BIN_OFFSET = 64; 808fc2b61aSZefir Kurtisi /* if detected radar on both channels, select the significant one */ 818fc2b61aSZefir Kurtisi if (is_ctl && is_ext) { 828fc2b61aSZefir Kurtisi /* first check wether channels have 'strong' bins */ 838fc2b61aSZefir Kurtisi is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; 848fc2b61aSZefir Kurtisi is_ext = fft_bitmap_weight(fft->upper_bins) != 0; 858fc2b61aSZefir Kurtisi 868fc2b61aSZefir Kurtisi /* if still unclear, take higher magnitude */ 878fc2b61aSZefir Kurtisi if (is_ctl && is_ext) { 888fc2b61aSZefir Kurtisi int mag_lower = fft_max_magnitude(fft->lower_bins); 898fc2b61aSZefir Kurtisi int mag_upper = fft_max_magnitude(fft->upper_bins); 908fc2b61aSZefir Kurtisi if (mag_upper > mag_lower) 918fc2b61aSZefir Kurtisi is_ctl = false; 928fc2b61aSZefir Kurtisi else 938fc2b61aSZefir Kurtisi is_ext = false; 948fc2b61aSZefir Kurtisi } 958fc2b61aSZefir Kurtisi } 968fc2b61aSZefir Kurtisi if (is_ctl) 978fc2b61aSZefir Kurtisi return fft_max_index(fft->lower_bins); 988fc2b61aSZefir Kurtisi return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; 998fc2b61aSZefir Kurtisi } 1008fc2b61aSZefir Kurtisi static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, 1018fc2b61aSZefir Kurtisi int datalen, bool is_ctl, bool is_ext) 1028fc2b61aSZefir Kurtisi { 1038fc2b61aSZefir Kurtisi int i; 1048fc2b61aSZefir Kurtisi int max_bin[FFT_NUM_SAMPLES]; 1058fc2b61aSZefir Kurtisi struct ath_hw *ah = sc->sc_ah; 1068fc2b61aSZefir Kurtisi struct ath_common *common = ath9k_hw_common(ah); 1078fc2b61aSZefir Kurtisi int prev_delta; 1088fc2b61aSZefir Kurtisi 1098fc2b61aSZefir Kurtisi if (IS_CHAN_HT40(ah->curchan)) { 1108fc2b61aSZefir Kurtisi struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; 1118fc2b61aSZefir Kurtisi int num_fft_packets = datalen / sizeof(*fft); 1128fc2b61aSZefir Kurtisi if (num_fft_packets == 0) 1138fc2b61aSZefir Kurtisi return false; 1148fc2b61aSZefir Kurtisi 1158fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", 1168fc2b61aSZefir Kurtisi datalen, num_fft_packets); 1179c27489aSGustavo A. R. Silva if (num_fft_packets < FFT_NUM_SAMPLES) { 1188fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "not enough packets for chirp\n"); 1198fc2b61aSZefir Kurtisi return false; 1208fc2b61aSZefir Kurtisi } 1218fc2b61aSZefir Kurtisi /* HW sometimes adds 2 garbage bytes in front of FFT samples */ 1228fc2b61aSZefir Kurtisi if ((datalen % sizeof(*fft)) == 2) { 1238fc2b61aSZefir Kurtisi fft = (struct ath9k_dfs_fft_40 *) (data + 2); 1248fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "fixing datalen by 2\n"); 1258fc2b61aSZefir Kurtisi } 126626ab670SGustavo A. R. Silva if (IS_CHAN_HT40MINUS(ah->curchan)) 127626ab670SGustavo A. R. Silva swap(is_ctl, is_ext); 128626ab670SGustavo A. R. Silva 1298fc2b61aSZefir Kurtisi for (i = 0; i < FFT_NUM_SAMPLES; i++) 1308fc2b61aSZefir Kurtisi max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, 1318fc2b61aSZefir Kurtisi is_ext); 1328fc2b61aSZefir Kurtisi } else { 1338fc2b61aSZefir Kurtisi struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; 1348fc2b61aSZefir Kurtisi int num_fft_packets = datalen / sizeof(*fft); 1358fc2b61aSZefir Kurtisi if (num_fft_packets == 0) 1368fc2b61aSZefir Kurtisi return false; 1378fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", 1388fc2b61aSZefir Kurtisi datalen, num_fft_packets); 1399c27489aSGustavo A. R. Silva if (num_fft_packets < FFT_NUM_SAMPLES) { 1408fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "not enough packets for chirp\n"); 1418fc2b61aSZefir Kurtisi return false; 1428fc2b61aSZefir Kurtisi } 1438fc2b61aSZefir Kurtisi /* in ht20, this is a 6-bit signed number => shift it to 0 */ 1448fc2b61aSZefir Kurtisi for (i = 0; i < FFT_NUM_SAMPLES; i++) 1458fc2b61aSZefir Kurtisi max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; 1468fc2b61aSZefir Kurtisi } 1478fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", 1488fc2b61aSZefir Kurtisi max_bin[0], max_bin[1], max_bin[2], max_bin[3]); 1498fc2b61aSZefir Kurtisi 1508fc2b61aSZefir Kurtisi /* Check for chirp attributes within specs 1518fc2b61aSZefir Kurtisi * a) delta of adjacent max_bins is within range 1528fc2b61aSZefir Kurtisi * b) delta of adjacent deltas are within tolerance 1538fc2b61aSZefir Kurtisi */ 1548fc2b61aSZefir Kurtisi prev_delta = 0; 1558fc2b61aSZefir Kurtisi for (i = 0; i < NUM_DIFFS; i++) { 1568fc2b61aSZefir Kurtisi int ddelta = -1; 1578fc2b61aSZefir Kurtisi int delta = max_bin[i + 1] - max_bin[i]; 1588fc2b61aSZefir Kurtisi 1598fc2b61aSZefir Kurtisi /* ensure gradient is within valid range */ 1608fc2b61aSZefir Kurtisi if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { 1618fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "CHIRP: invalid delta %d " 1628fc2b61aSZefir Kurtisi "in sample %d\n", delta, i); 1638fc2b61aSZefir Kurtisi return false; 1648fc2b61aSZefir Kurtisi } 1658fc2b61aSZefir Kurtisi if (i == 0) 1668fc2b61aSZefir Kurtisi goto done; 1678fc2b61aSZefir Kurtisi ddelta = delta - prev_delta; 1688fc2b61aSZefir Kurtisi if (abs(ddelta) > MAX_DIFF) { 1698fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", 1708fc2b61aSZefir Kurtisi ddelta); 1718fc2b61aSZefir Kurtisi return false; 1728fc2b61aSZefir Kurtisi } 1738fc2b61aSZefir Kurtisi done: 1748fc2b61aSZefir Kurtisi ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", 1758fc2b61aSZefir Kurtisi i, delta, ddelta); 1768fc2b61aSZefir Kurtisi prev_delta = delta; 1778fc2b61aSZefir Kurtisi } 1788fc2b61aSZefir Kurtisi return true; 1798fc2b61aSZefir Kurtisi } 1808fc2b61aSZefir Kurtisi /**** end: CHIRP **************************************************************/ 1818fc2b61aSZefir Kurtisi 18229942bc1SZefir Kurtisi /* convert pulse duration to usecs, considering clock mode */ 18329942bc1SZefir Kurtisi static u32 dur_to_usecs(struct ath_hw *ah, u32 dur) 18429942bc1SZefir Kurtisi { 18529942bc1SZefir Kurtisi const u32 AR93X_NSECS_PER_DUR = 800; 18629942bc1SZefir Kurtisi const u32 AR93X_NSECS_PER_DUR_FAST = (8000 / 11); 18729942bc1SZefir Kurtisi u32 nsecs; 18829942bc1SZefir Kurtisi 18929942bc1SZefir Kurtisi if (IS_CHAN_A_FAST_CLOCK(ah, ah->curchan)) 19029942bc1SZefir Kurtisi nsecs = dur * AR93X_NSECS_PER_DUR_FAST; 19129942bc1SZefir Kurtisi else 19229942bc1SZefir Kurtisi nsecs = dur * AR93X_NSECS_PER_DUR; 19329942bc1SZefir Kurtisi 19429942bc1SZefir Kurtisi return (nsecs + 500) / 1000; 19529942bc1SZefir Kurtisi } 19629942bc1SZefir Kurtisi 19729942bc1SZefir Kurtisi #define PRI_CH_RADAR_FOUND 0x01 19829942bc1SZefir Kurtisi #define EXT_CH_RADAR_FOUND 0x02 19929942bc1SZefir Kurtisi static bool 20029942bc1SZefir Kurtisi ath9k_postprocess_radar_event(struct ath_softc *sc, 20156dc389fSZefir Kurtisi struct ath_radar_data *ard, 20256dc389fSZefir Kurtisi struct pulse_event *pe) 20329942bc1SZefir Kurtisi { 20429942bc1SZefir Kurtisi u8 rssi; 20529942bc1SZefir Kurtisi u16 dur; 20629942bc1SZefir Kurtisi 20729942bc1SZefir Kurtisi /* 20829942bc1SZefir Kurtisi * Only the last 2 bits of the BW info are relevant, they indicate 20929942bc1SZefir Kurtisi * which channel the radar was detected in. 21029942bc1SZefir Kurtisi */ 21156dc389fSZefir Kurtisi ard->pulse_bw_info &= 0x03; 21229942bc1SZefir Kurtisi 21356dc389fSZefir Kurtisi switch (ard->pulse_bw_info) { 21429942bc1SZefir Kurtisi case PRI_CH_RADAR_FOUND: 21529942bc1SZefir Kurtisi /* radar in ctrl channel */ 21656dc389fSZefir Kurtisi dur = ard->pulse_length_pri; 21729942bc1SZefir Kurtisi DFS_STAT_INC(sc, pri_phy_errors); 21829942bc1SZefir Kurtisi /* 21929942bc1SZefir Kurtisi * cannot use ctrl channel RSSI 22029942bc1SZefir Kurtisi * if extension channel is stronger 22129942bc1SZefir Kurtisi */ 22256dc389fSZefir Kurtisi rssi = (ard->ext_rssi >= (ard->rssi + 3)) ? 0 : ard->rssi; 22329942bc1SZefir Kurtisi break; 22429942bc1SZefir Kurtisi case EXT_CH_RADAR_FOUND: 22529942bc1SZefir Kurtisi /* radar in extension channel */ 22656dc389fSZefir Kurtisi dur = ard->pulse_length_ext; 22729942bc1SZefir Kurtisi DFS_STAT_INC(sc, ext_phy_errors); 22829942bc1SZefir Kurtisi /* 22929942bc1SZefir Kurtisi * cannot use extension channel RSSI 23029942bc1SZefir Kurtisi * if control channel is stronger 23129942bc1SZefir Kurtisi */ 23256dc389fSZefir Kurtisi rssi = (ard->rssi >= (ard->ext_rssi + 12)) ? 0 : ard->ext_rssi; 23329942bc1SZefir Kurtisi break; 23429942bc1SZefir Kurtisi case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND): 23529942bc1SZefir Kurtisi /* 23629942bc1SZefir Kurtisi * Conducted testing, when pulse is on DC, both pri and ext 23729942bc1SZefir Kurtisi * durations are reported to be same 23829942bc1SZefir Kurtisi * 23929942bc1SZefir Kurtisi * Radiated testing, when pulse is on DC, different pri and 24029942bc1SZefir Kurtisi * ext durations are reported, so take the larger of the two 24129942bc1SZefir Kurtisi */ 24256dc389fSZefir Kurtisi if (ard->pulse_length_ext >= ard->pulse_length_pri) 24356dc389fSZefir Kurtisi dur = ard->pulse_length_ext; 24429942bc1SZefir Kurtisi else 24556dc389fSZefir Kurtisi dur = ard->pulse_length_pri; 24629942bc1SZefir Kurtisi DFS_STAT_INC(sc, dc_phy_errors); 24729942bc1SZefir Kurtisi 24829942bc1SZefir Kurtisi /* when both are present use stronger one */ 24956dc389fSZefir Kurtisi rssi = (ard->rssi < ard->ext_rssi) ? ard->ext_rssi : ard->rssi; 25029942bc1SZefir Kurtisi break; 25129942bc1SZefir Kurtisi default: 25229942bc1SZefir Kurtisi /* 25329942bc1SZefir Kurtisi * Bogus bandwidth info was received in descriptor, 25429942bc1SZefir Kurtisi * so ignore this PHY error 25529942bc1SZefir Kurtisi */ 25629942bc1SZefir Kurtisi DFS_STAT_INC(sc, bwinfo_discards); 25729942bc1SZefir Kurtisi return false; 25829942bc1SZefir Kurtisi } 25929942bc1SZefir Kurtisi 26029942bc1SZefir Kurtisi if (rssi == 0) { 26129942bc1SZefir Kurtisi DFS_STAT_INC(sc, rssi_discards); 26229942bc1SZefir Kurtisi return false; 26329942bc1SZefir Kurtisi } 26429942bc1SZefir Kurtisi 26529942bc1SZefir Kurtisi /* convert duration to usecs */ 26656dc389fSZefir Kurtisi pe->width = dur_to_usecs(sc->sc_ah, dur); 26756dc389fSZefir Kurtisi pe->rssi = rssi; 26829942bc1SZefir Kurtisi 26929942bc1SZefir Kurtisi DFS_STAT_INC(sc, pulses_detected); 27029942bc1SZefir Kurtisi return true; 27129942bc1SZefir Kurtisi } 27258766977SZefir Kurtisi 27358766977SZefir Kurtisi static void 27458766977SZefir Kurtisi ath9k_dfs_process_radar_pulse(struct ath_softc *sc, struct pulse_event *pe) 27558766977SZefir Kurtisi { 27658766977SZefir Kurtisi struct dfs_pattern_detector *pd = sc->dfs_detector; 27758766977SZefir Kurtisi DFS_STAT_INC(sc, pulses_processed); 27858766977SZefir Kurtisi if (pd == NULL) 27958766977SZefir Kurtisi return; 280*f40105e6SSriram R if (!pd->add_pulse(pd, pe, NULL)) 28158766977SZefir Kurtisi return; 28258766977SZefir Kurtisi DFS_STAT_INC(sc, radar_detected); 28358766977SZefir Kurtisi ieee80211_radar_detected(sc->hw); 28458766977SZefir Kurtisi } 28529942bc1SZefir Kurtisi 28629942bc1SZefir Kurtisi /* 28729942bc1SZefir Kurtisi * DFS: check PHY-error for radar pulse and feed the detector 28829942bc1SZefir Kurtisi */ 28929942bc1SZefir Kurtisi void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, 29029942bc1SZefir Kurtisi struct ath_rx_status *rs, u64 mactime) 29129942bc1SZefir Kurtisi { 29229942bc1SZefir Kurtisi struct ath_radar_data ard; 29329942bc1SZefir Kurtisi u16 datalen; 29429942bc1SZefir Kurtisi char *vdata_end; 29556dc389fSZefir Kurtisi struct pulse_event pe; 29629942bc1SZefir Kurtisi struct ath_hw *ah = sc->sc_ah; 29729942bc1SZefir Kurtisi struct ath_common *common = ath9k_hw_common(ah); 29829942bc1SZefir Kurtisi 299b96f20b3SZefir Kurtisi DFS_STAT_INC(sc, pulses_total); 30056dc389fSZefir Kurtisi if ((rs->rs_phyerr != ATH9K_PHYERR_RADAR) && 30156dc389fSZefir Kurtisi (rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT)) { 302ec9a5705SLuis R. Rodriguez ath_dbg(common, DFS, 30329942bc1SZefir Kurtisi "Error: rs_phyer=0x%x not a radar error\n", 30429942bc1SZefir Kurtisi rs->rs_phyerr); 305b96f20b3SZefir Kurtisi DFS_STAT_INC(sc, pulses_no_dfs); 30629942bc1SZefir Kurtisi return; 30729942bc1SZefir Kurtisi } 30829942bc1SZefir Kurtisi 30929942bc1SZefir Kurtisi datalen = rs->rs_datalen; 31029942bc1SZefir Kurtisi if (datalen == 0) { 31129942bc1SZefir Kurtisi DFS_STAT_INC(sc, datalen_discards); 31229942bc1SZefir Kurtisi return; 31329942bc1SZefir Kurtisi } 31429942bc1SZefir Kurtisi 315e45e91d8SFelix Fietkau ard.rssi = rs->rs_rssi_ctl[0]; 316e45e91d8SFelix Fietkau ard.ext_rssi = rs->rs_rssi_ext[0]; 31729942bc1SZefir Kurtisi 31829942bc1SZefir Kurtisi /* 31929942bc1SZefir Kurtisi * hardware stores this as 8 bit signed value. 32029942bc1SZefir Kurtisi * we will cap it at 0 if it is a negative number 32129942bc1SZefir Kurtisi */ 32229942bc1SZefir Kurtisi if (ard.rssi & 0x80) 32329942bc1SZefir Kurtisi ard.rssi = 0; 32429942bc1SZefir Kurtisi if (ard.ext_rssi & 0x80) 32529942bc1SZefir Kurtisi ard.ext_rssi = 0; 32629942bc1SZefir Kurtisi 32750c8cd44SHimanshu Jha vdata_end = data + datalen; 32829942bc1SZefir Kurtisi ard.pulse_bw_info = vdata_end[-1]; 32929942bc1SZefir Kurtisi ard.pulse_length_ext = vdata_end[-2]; 33029942bc1SZefir Kurtisi ard.pulse_length_pri = vdata_end[-3]; 33156dc389fSZefir Kurtisi pe.freq = ah->curchan->channel; 33256dc389fSZefir Kurtisi pe.ts = mactime; 33358766977SZefir Kurtisi if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) 33458766977SZefir Kurtisi return; 33558766977SZefir Kurtisi 3368fc2b61aSZefir Kurtisi if (pe.width > MIN_CHIRP_PULSE_WIDTH && 3378fc2b61aSZefir Kurtisi pe.width < MAX_CHIRP_PULSE_WIDTH) { 3388fc2b61aSZefir Kurtisi bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); 3398fc2b61aSZefir Kurtisi bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); 3408fc2b61aSZefir Kurtisi int clen = datalen - 3; 3418fc2b61aSZefir Kurtisi pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); 3428fc2b61aSZefir Kurtisi } else { 3438fc2b61aSZefir Kurtisi pe.chirp = false; 3448fc2b61aSZefir Kurtisi } 3458fc2b61aSZefir Kurtisi 346ec9a5705SLuis R. Rodriguez ath_dbg(common, DFS, 34758766977SZefir Kurtisi "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " 34829942bc1SZefir Kurtisi "width=%d, rssi=%d, delta_ts=%llu\n", 34958766977SZefir Kurtisi ard.pulse_bw_info, pe.freq, pe.ts, pe.width, pe.rssi, 3503f3c09f3SZefir Kurtisi pe.ts - sc->dfs_prev_pulse_ts); 3513f3c09f3SZefir Kurtisi sc->dfs_prev_pulse_ts = pe.ts; 35258766977SZefir Kurtisi if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND) 35358766977SZefir Kurtisi ath9k_dfs_process_radar_pulse(sc, &pe); 3548f010d9cSZefir Kurtisi if (IS_CHAN_HT40(ah->curchan) && 3558f010d9cSZefir Kurtisi ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { 35658766977SZefir Kurtisi pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20; 35758766977SZefir Kurtisi ath9k_dfs_process_radar_pulse(sc, &pe); 35829942bc1SZefir Kurtisi } 35929942bc1SZefir Kurtisi } 36058766977SZefir Kurtisi #undef PRI_CH_RADAR_FOUND 36158766977SZefir Kurtisi #undef EXT_CH_RADAR_FOUND 362