162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2008-2011 Atheros Communications Inc. 362306a36Sopenharmony_ci * Copyright (c) 2011 Neratec Solutions AG 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 662306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 762306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1062306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1162306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1262306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1362306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1462306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1562306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "hw.h" 1962306a36Sopenharmony_ci#include "hw-ops.h" 2062306a36Sopenharmony_ci#include "ath9k.h" 2162306a36Sopenharmony_ci#include "dfs.h" 2262306a36Sopenharmony_ci#include "dfs_debug.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* internal struct to pass radar data */ 2562306a36Sopenharmony_cistruct ath_radar_data { 2662306a36Sopenharmony_ci u8 pulse_bw_info; 2762306a36Sopenharmony_ci u8 rssi; 2862306a36Sopenharmony_ci u8 ext_rssi; 2962306a36Sopenharmony_ci u8 pulse_length_ext; 3062306a36Sopenharmony_ci u8 pulse_length_pri; 3162306a36Sopenharmony_ci}; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/**** begin: CHIRP ************************************************************/ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* min and max gradients for defined FCC chirping pulses, given by 3662306a36Sopenharmony_ci * - 20MHz chirp width over a pulse width of 50us 3762306a36Sopenharmony_ci * - 5MHz chirp width over a pulse width of 100us 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_cistatic const int BIN_DELTA_MIN = 1; 4062306a36Sopenharmony_cistatic const int BIN_DELTA_MAX = 10; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* we need at least 3 deltas / 4 samples for a reliable chirp detection */ 4362306a36Sopenharmony_ci#define NUM_DIFFS 3 4462306a36Sopenharmony_ci#define FFT_NUM_SAMPLES (NUM_DIFFS + 1) 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci/* Threshold for difference of delta peaks */ 4762306a36Sopenharmony_cistatic const int MAX_DIFF = 2; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* width range to be checked for chirping */ 5062306a36Sopenharmony_cistatic const int MIN_CHIRP_PULSE_WIDTH = 20; 5162306a36Sopenharmony_cistatic const int MAX_CHIRP_PULSE_WIDTH = 110; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct ath9k_dfs_fft_20 { 5462306a36Sopenharmony_ci u8 bin[28]; 5562306a36Sopenharmony_ci u8 lower_bins[3]; 5662306a36Sopenharmony_ci} __packed; 5762306a36Sopenharmony_cistruct ath9k_dfs_fft_40 { 5862306a36Sopenharmony_ci u8 bin[64]; 5962306a36Sopenharmony_ci u8 lower_bins[3]; 6062306a36Sopenharmony_ci u8 upper_bins[3]; 6162306a36Sopenharmony_ci} __packed; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic inline int fft_max_index(u8 *bins) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci return (bins[2] & 0xfc) >> 2; 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_cistatic inline int fft_max_magnitude(u8 *bins) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_cistatic inline u8 fft_bitmap_weight(u8 *bins) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci return bins[0] & 0x3f; 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, 7762306a36Sopenharmony_ci bool is_ctl, bool is_ext) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci const int DFS_UPPER_BIN_OFFSET = 64; 8062306a36Sopenharmony_ci /* if detected radar on both channels, select the significant one */ 8162306a36Sopenharmony_ci if (is_ctl && is_ext) { 8262306a36Sopenharmony_ci /* first check wether channels have 'strong' bins */ 8362306a36Sopenharmony_ci is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; 8462306a36Sopenharmony_ci is_ext = fft_bitmap_weight(fft->upper_bins) != 0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* if still unclear, take higher magnitude */ 8762306a36Sopenharmony_ci if (is_ctl && is_ext) { 8862306a36Sopenharmony_ci int mag_lower = fft_max_magnitude(fft->lower_bins); 8962306a36Sopenharmony_ci int mag_upper = fft_max_magnitude(fft->upper_bins); 9062306a36Sopenharmony_ci if (mag_upper > mag_lower) 9162306a36Sopenharmony_ci is_ctl = false; 9262306a36Sopenharmony_ci else 9362306a36Sopenharmony_ci is_ext = false; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci if (is_ctl) 9762306a36Sopenharmony_ci return fft_max_index(fft->lower_bins); 9862306a36Sopenharmony_ci return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_cistatic bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, 10162306a36Sopenharmony_ci int datalen, bool is_ctl, bool is_ext) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci int i; 10462306a36Sopenharmony_ci int max_bin[FFT_NUM_SAMPLES]; 10562306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 10662306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 10762306a36Sopenharmony_ci int prev_delta; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (IS_CHAN_HT40(ah->curchan)) { 11062306a36Sopenharmony_ci struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; 11162306a36Sopenharmony_ci int num_fft_packets = datalen / sizeof(*fft); 11262306a36Sopenharmony_ci if (num_fft_packets == 0) 11362306a36Sopenharmony_ci return false; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", 11662306a36Sopenharmony_ci datalen, num_fft_packets); 11762306a36Sopenharmony_ci if (num_fft_packets < FFT_NUM_SAMPLES) { 11862306a36Sopenharmony_ci ath_dbg(common, DFS, "not enough packets for chirp\n"); 11962306a36Sopenharmony_ci return false; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci /* HW sometimes adds 2 garbage bytes in front of FFT samples */ 12262306a36Sopenharmony_ci if ((datalen % sizeof(*fft)) == 2) { 12362306a36Sopenharmony_ci fft = (struct ath9k_dfs_fft_40 *) (data + 2); 12462306a36Sopenharmony_ci ath_dbg(common, DFS, "fixing datalen by 2\n"); 12562306a36Sopenharmony_ci } 12662306a36Sopenharmony_ci if (IS_CHAN_HT40MINUS(ah->curchan)) 12762306a36Sopenharmony_ci swap(is_ctl, is_ext); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci for (i = 0; i < FFT_NUM_SAMPLES; i++) 13062306a36Sopenharmony_ci max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, 13162306a36Sopenharmony_ci is_ext); 13262306a36Sopenharmony_ci } else { 13362306a36Sopenharmony_ci struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; 13462306a36Sopenharmony_ci int num_fft_packets = datalen / sizeof(*fft); 13562306a36Sopenharmony_ci if (num_fft_packets == 0) 13662306a36Sopenharmony_ci return false; 13762306a36Sopenharmony_ci ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", 13862306a36Sopenharmony_ci datalen, num_fft_packets); 13962306a36Sopenharmony_ci if (num_fft_packets < FFT_NUM_SAMPLES) { 14062306a36Sopenharmony_ci ath_dbg(common, DFS, "not enough packets for chirp\n"); 14162306a36Sopenharmony_ci return false; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci /* in ht20, this is a 6-bit signed number => shift it to 0 */ 14462306a36Sopenharmony_ci for (i = 0; i < FFT_NUM_SAMPLES; i++) 14562306a36Sopenharmony_ci max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", 14862306a36Sopenharmony_ci max_bin[0], max_bin[1], max_bin[2], max_bin[3]); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* Check for chirp attributes within specs 15162306a36Sopenharmony_ci * a) delta of adjacent max_bins is within range 15262306a36Sopenharmony_ci * b) delta of adjacent deltas are within tolerance 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ci prev_delta = 0; 15562306a36Sopenharmony_ci for (i = 0; i < NUM_DIFFS; i++) { 15662306a36Sopenharmony_ci int ddelta = -1; 15762306a36Sopenharmony_ci int delta = max_bin[i + 1] - max_bin[i]; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* ensure gradient is within valid range */ 16062306a36Sopenharmony_ci if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { 16162306a36Sopenharmony_ci ath_dbg(common, DFS, "CHIRP: invalid delta %d " 16262306a36Sopenharmony_ci "in sample %d\n", delta, i); 16362306a36Sopenharmony_ci return false; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci if (i == 0) 16662306a36Sopenharmony_ci goto done; 16762306a36Sopenharmony_ci ddelta = delta - prev_delta; 16862306a36Sopenharmony_ci if (abs(ddelta) > MAX_DIFF) { 16962306a36Sopenharmony_ci ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", 17062306a36Sopenharmony_ci ddelta); 17162306a36Sopenharmony_ci return false; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_cidone: 17462306a36Sopenharmony_ci ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", 17562306a36Sopenharmony_ci i, delta, ddelta); 17662306a36Sopenharmony_ci prev_delta = delta; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci return true; 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci/**** end: CHIRP **************************************************************/ 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci/* convert pulse duration to usecs, considering clock mode */ 18362306a36Sopenharmony_cistatic u32 dur_to_usecs(struct ath_hw *ah, u32 dur) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci const u32 AR93X_NSECS_PER_DUR = 800; 18662306a36Sopenharmony_ci const u32 AR93X_NSECS_PER_DUR_FAST = (8000 / 11); 18762306a36Sopenharmony_ci u32 nsecs; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci if (IS_CHAN_A_FAST_CLOCK(ah, ah->curchan)) 19062306a36Sopenharmony_ci nsecs = dur * AR93X_NSECS_PER_DUR_FAST; 19162306a36Sopenharmony_ci else 19262306a36Sopenharmony_ci nsecs = dur * AR93X_NSECS_PER_DUR; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci return (nsecs + 500) / 1000; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci#define PRI_CH_RADAR_FOUND 0x01 19862306a36Sopenharmony_ci#define EXT_CH_RADAR_FOUND 0x02 19962306a36Sopenharmony_cistatic bool 20062306a36Sopenharmony_ciath9k_postprocess_radar_event(struct ath_softc *sc, 20162306a36Sopenharmony_ci struct ath_radar_data *ard, 20262306a36Sopenharmony_ci struct pulse_event *pe) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci u8 rssi; 20562306a36Sopenharmony_ci u16 dur; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* 20862306a36Sopenharmony_ci * Only the last 2 bits of the BW info are relevant, they indicate 20962306a36Sopenharmony_ci * which channel the radar was detected in. 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci ard->pulse_bw_info &= 0x03; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci switch (ard->pulse_bw_info) { 21462306a36Sopenharmony_ci case PRI_CH_RADAR_FOUND: 21562306a36Sopenharmony_ci /* radar in ctrl channel */ 21662306a36Sopenharmony_ci dur = ard->pulse_length_pri; 21762306a36Sopenharmony_ci DFS_STAT_INC(sc, pri_phy_errors); 21862306a36Sopenharmony_ci /* 21962306a36Sopenharmony_ci * cannot use ctrl channel RSSI 22062306a36Sopenharmony_ci * if extension channel is stronger 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci rssi = (ard->ext_rssi >= (ard->rssi + 3)) ? 0 : ard->rssi; 22362306a36Sopenharmony_ci break; 22462306a36Sopenharmony_ci case EXT_CH_RADAR_FOUND: 22562306a36Sopenharmony_ci /* radar in extension channel */ 22662306a36Sopenharmony_ci dur = ard->pulse_length_ext; 22762306a36Sopenharmony_ci DFS_STAT_INC(sc, ext_phy_errors); 22862306a36Sopenharmony_ci /* 22962306a36Sopenharmony_ci * cannot use extension channel RSSI 23062306a36Sopenharmony_ci * if control channel is stronger 23162306a36Sopenharmony_ci */ 23262306a36Sopenharmony_ci rssi = (ard->rssi >= (ard->ext_rssi + 12)) ? 0 : ard->ext_rssi; 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci case (PRI_CH_RADAR_FOUND | EXT_CH_RADAR_FOUND): 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * Conducted testing, when pulse is on DC, both pri and ext 23762306a36Sopenharmony_ci * durations are reported to be same 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * Radiated testing, when pulse is on DC, different pri and 24062306a36Sopenharmony_ci * ext durations are reported, so take the larger of the two 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_ci if (ard->pulse_length_ext >= ard->pulse_length_pri) 24362306a36Sopenharmony_ci dur = ard->pulse_length_ext; 24462306a36Sopenharmony_ci else 24562306a36Sopenharmony_ci dur = ard->pulse_length_pri; 24662306a36Sopenharmony_ci DFS_STAT_INC(sc, dc_phy_errors); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* when both are present use stronger one */ 24962306a36Sopenharmony_ci rssi = max(ard->rssi, ard->ext_rssi); 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci default: 25262306a36Sopenharmony_ci /* 25362306a36Sopenharmony_ci * Bogus bandwidth info was received in descriptor, 25462306a36Sopenharmony_ci * so ignore this PHY error 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci DFS_STAT_INC(sc, bwinfo_discards); 25762306a36Sopenharmony_ci return false; 25862306a36Sopenharmony_ci } 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci if (rssi == 0) { 26162306a36Sopenharmony_ci DFS_STAT_INC(sc, rssi_discards); 26262306a36Sopenharmony_ci return false; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* convert duration to usecs */ 26662306a36Sopenharmony_ci pe->width = dur_to_usecs(sc->sc_ah, dur); 26762306a36Sopenharmony_ci pe->rssi = rssi; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci DFS_STAT_INC(sc, pulses_detected); 27062306a36Sopenharmony_ci return true; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic void 27462306a36Sopenharmony_ciath9k_dfs_process_radar_pulse(struct ath_softc *sc, struct pulse_event *pe) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct dfs_pattern_detector *pd = sc->dfs_detector; 27762306a36Sopenharmony_ci DFS_STAT_INC(sc, pulses_processed); 27862306a36Sopenharmony_ci if (pd == NULL) 27962306a36Sopenharmony_ci return; 28062306a36Sopenharmony_ci if (!pd->add_pulse(pd, pe, NULL)) 28162306a36Sopenharmony_ci return; 28262306a36Sopenharmony_ci DFS_STAT_INC(sc, radar_detected); 28362306a36Sopenharmony_ci ieee80211_radar_detected(sc->hw); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci/* 28762306a36Sopenharmony_ci * DFS: check PHY-error for radar pulse and feed the detector 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_civoid ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, 29062306a36Sopenharmony_ci struct ath_rx_status *rs, u64 mactime) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct ath_radar_data ard; 29362306a36Sopenharmony_ci u16 datalen; 29462306a36Sopenharmony_ci char *vdata_end; 29562306a36Sopenharmony_ci struct pulse_event pe; 29662306a36Sopenharmony_ci struct ath_hw *ah = sc->sc_ah; 29762306a36Sopenharmony_ci struct ath_common *common = ath9k_hw_common(ah); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci DFS_STAT_INC(sc, pulses_total); 30062306a36Sopenharmony_ci if ((rs->rs_phyerr != ATH9K_PHYERR_RADAR) && 30162306a36Sopenharmony_ci (rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT)) { 30262306a36Sopenharmony_ci ath_dbg(common, DFS, 30362306a36Sopenharmony_ci "Error: rs_phyer=0x%x not a radar error\n", 30462306a36Sopenharmony_ci rs->rs_phyerr); 30562306a36Sopenharmony_ci DFS_STAT_INC(sc, pulses_no_dfs); 30662306a36Sopenharmony_ci return; 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci datalen = rs->rs_datalen; 31062306a36Sopenharmony_ci if (datalen == 0) { 31162306a36Sopenharmony_ci DFS_STAT_INC(sc, datalen_discards); 31262306a36Sopenharmony_ci return; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci ard.rssi = rs->rs_rssi_ctl[0]; 31662306a36Sopenharmony_ci ard.ext_rssi = rs->rs_rssi_ext[0]; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* 31962306a36Sopenharmony_ci * hardware stores this as 8 bit signed value. 32062306a36Sopenharmony_ci * we will cap it at 0 if it is a negative number 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci if (ard.rssi & 0x80) 32362306a36Sopenharmony_ci ard.rssi = 0; 32462306a36Sopenharmony_ci if (ard.ext_rssi & 0x80) 32562306a36Sopenharmony_ci ard.ext_rssi = 0; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci vdata_end = data + datalen; 32862306a36Sopenharmony_ci ard.pulse_bw_info = vdata_end[-1]; 32962306a36Sopenharmony_ci ard.pulse_length_ext = vdata_end[-2]; 33062306a36Sopenharmony_ci ard.pulse_length_pri = vdata_end[-3]; 33162306a36Sopenharmony_ci pe.freq = ah->curchan->channel; 33262306a36Sopenharmony_ci pe.ts = mactime; 33362306a36Sopenharmony_ci if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) 33462306a36Sopenharmony_ci return; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (pe.width > MIN_CHIRP_PULSE_WIDTH && 33762306a36Sopenharmony_ci pe.width < MAX_CHIRP_PULSE_WIDTH) { 33862306a36Sopenharmony_ci bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); 33962306a36Sopenharmony_ci bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); 34062306a36Sopenharmony_ci int clen = datalen - 3; 34162306a36Sopenharmony_ci pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); 34262306a36Sopenharmony_ci } else { 34362306a36Sopenharmony_ci pe.chirp = false; 34462306a36Sopenharmony_ci } 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci ath_dbg(common, DFS, 34762306a36Sopenharmony_ci "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " 34862306a36Sopenharmony_ci "width=%d, rssi=%d, delta_ts=%llu\n", 34962306a36Sopenharmony_ci ard.pulse_bw_info, pe.freq, pe.ts, pe.width, pe.rssi, 35062306a36Sopenharmony_ci pe.ts - sc->dfs_prev_pulse_ts); 35162306a36Sopenharmony_ci sc->dfs_prev_pulse_ts = pe.ts; 35262306a36Sopenharmony_ci if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND) 35362306a36Sopenharmony_ci ath9k_dfs_process_radar_pulse(sc, &pe); 35462306a36Sopenharmony_ci if (IS_CHAN_HT40(ah->curchan) && 35562306a36Sopenharmony_ci ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { 35662306a36Sopenharmony_ci pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20; 35762306a36Sopenharmony_ci ath9k_dfs_process_radar_pulse(sc, &pe); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci#undef PRI_CH_RADAR_FOUND 36162306a36Sopenharmony_ci#undef EXT_CH_RADAR_FOUND 362