/* returns 1 if this was a spectral frame, even if not handled. */ int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr, struct ath_rx_status *rs, u64 tsf) { struct ath_hw *ah = sc->sc_ah; u8 num_bins, *bins, *vdata = (u8 *)hdr; struct fft_sample_ht20 fft_sample_20; struct fft_sample_ht20_40 fft_sample_40; struct fft_sample_tlv *tlv; struct ath_radar_info *radar_info; int len = rs->rs_datalen; int dc_pos; u16 fft_len, length, freq = ah->curchan->chan->center_freq; enum nl80211_channel_type chan_type; /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT * yet, but this is supposed to be possible as well. */ if (rs->rs_phyerr != ATH9K_PHYERR_RADAR && rs->rs_phyerr != ATH9K_PHYERR_FALSE_RADAR_EXT && rs->rs_phyerr != ATH9K_PHYERR_SPECTRAL) return 0; /* check if spectral scan bit is set. This does not have to be checked * if received through a SPECTRAL phy error, but shouldn't hurt. */ radar_info = ((struct ath_radar_info *)&vdata[len]) - 1; if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) return 0; chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef); if ((chan_type == NL80211_CHAN_HT40MINUS) || (chan_type == NL80211_CHAN_HT40PLUS)) { fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN; num_bins = SPECTRAL_HT20_40_NUM_BINS; bins = (u8 *)fft_sample_40.data; } else { fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN; num_bins = SPECTRAL_HT20_NUM_BINS; bins = (u8 *)fft_sample_20.data; } /* Variation in the data length is possible and will be fixed later */ if ((len > fft_len + 2) || (len < fft_len - 1)) return 1; switch (len - fft_len) { case 0: /* length correct, nothing to do. */ memcpy(bins, vdata, num_bins); break; case -1: /* first byte missing, duplicate it. */ memcpy(&bins[1], vdata, num_bins - 1); bins[0] = vdata[0]; break; case 2: /* MAC added 2 extra bytes at bin 30 and 32, remove them. */ memcpy(bins, vdata, 30); bins[30] = vdata[31]; memcpy(&bins[31], &vdata[33], num_bins - 31); break; case 1: /* MAC added 2 extra bytes AND first byte is missing. */ bins[0] = vdata[0]; memcpy(&bins[1], vdata, 30); bins[31] = vdata[31]; memcpy(&bins[32], &vdata[33], num_bins - 32); break; default: return 1; } /* DC value (value in the middle) is the blind spot of the spectral * sample and invalid, interpolate it. */ dc_pos = num_bins / 2; bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; if ((chan_type == NL80211_CHAN_HT40MINUS) || (chan_type == NL80211_CHAN_HT40PLUS)) { s8 lower_rssi, upper_rssi; s16 ext_nf; u8 lower_max_index, upper_max_index; u8 lower_bitmap_w, upper_bitmap_w; u16 lower_mag, upper_mag; struct ath9k_hw_cal_data *caldata = ah->caldata; struct ath_ht20_40_mag_info *mag_info; if (caldata) ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan, caldata->nfCalHist[3].privNF); else ext_nf = ATH_DEFAULT_NOISE_FLOOR; length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv); fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40; fft_sample_40.tlv.length = __cpu_to_be16(length); fft_sample_40.freq = __cpu_to_be16(freq); fft_sample_40.channel_type = chan_type; if (chan_type == NL80211_CHAN_HT40PLUS) { lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]); fft_sample_40.lower_noise = ah->noise; fft_sample_40.upper_noise = ext_nf; } else { lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext[0]); upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); fft_sample_40.lower_noise = ext_nf; fft_sample_40.upper_noise = ah->noise; } fft_sample_40.lower_rssi = lower_rssi; fft_sample_40.upper_rssi = upper_rssi; mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1; lower_mag = spectral_max_magnitude(mag_info->lower_bins); upper_mag = spectral_max_magnitude(mag_info->upper_bins); fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag); fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag); lower_max_index = spectral_max_index(mag_info->lower_bins); upper_max_index = spectral_max_index(mag_info->upper_bins); fft_sample_40.lower_max_index = lower_max_index; fft_sample_40.upper_max_index = upper_max_index; lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins); upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins); fft_sample_40.lower_bitmap_weight = lower_bitmap_w; fft_sample_40.upper_bitmap_weight = upper_bitmap_w; fft_sample_40.max_exp = mag_info->max_exp & 0xf; fft_sample_40.tsf = __cpu_to_be64(tsf); tlv = (struct fft_sample_tlv *)&fft_sample_40; } else { u8 max_index, bitmap_w; u16 magnitude; struct ath_ht20_mag_info *mag_info; length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv); fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20; fft_sample_20.tlv.length = __cpu_to_be16(length); fft_sample_20.freq = __cpu_to_be16(freq); fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl[0]); fft_sample_20.noise = ah->noise; mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; magnitude = spectral_max_magnitude(mag_info->all_bins); fft_sample_20.max_magnitude = __cpu_to_be16(magnitude); max_index = spectral_max_index(mag_info->all_bins); fft_sample_20.max_index = max_index; bitmap_w = spectral_bitmap_weight(mag_info->all_bins); fft_sample_20.bitmap_weight = bitmap_w; fft_sample_20.max_exp = mag_info->max_exp & 0xf; fft_sample_20.tsf = __cpu_to_be64(tsf); tlv = (struct fft_sample_tlv *)&fft_sample_20; } ath_debug_send_fft_sample(sc, tlv); return 1; }
void ath_process_spectraldata(struct ath_spectral *spectral, struct ath_buf *bf, struct ath_rx_status *rxs, u_int64_t fulltsf) { #define EXT_CH_RADAR_FOUND 0x02 #define PRI_CH_RADAR_FOUND 0x01 #define EXT_CH_RADAR_EARLY_FOUND 0x04 #define SPECTRAL_SCAN_DATA 0x10 #define DEFAULT_CHAN_NOISE_FLOOR -110 int i = 0; struct samp_msg_params params; u_int8_t rssi = 0; u_int8_t control_rssi = 0; u_int8_t extension_rssi = 0; u_int8_t combined_rssi = 0; u_int8_t max_exp = 0; u_int8_t max_scale = 0; u_int8_t dc_index = 0; u_int8_t lower_dc = 0; u_int8_t upper_dc = 0; u_int8_t ext_rssi = 0; int8_t inv_control_rssi = 0; int8_t inv_combined_rssi = 0; int8_t inv_extension_rssi = 0; int8_t temp_nf = 0; u_int8_t pulse_bw_info = 0; u_int8_t pulse_length_ext = 0; u_int8_t pulse_length_pri = 0; u_int32_t tstamp = 0; u_int16_t datalen = 0; u_int16_t max_mag = 0; u_int16_t newdatalen = 0; u_int16_t already_copied = 0; u_int16_t maxmag_upper = 0; u_int8_t maxindex_upper = 0; u_int8_t max_index = 0; int bin_pwr_count = 0; u_int32_t *last_word_ptr = NULL; u_int32_t *secondlast_word_ptr = NULL; u_int8_t *byte_ptr = NULL; u_int8_t *fft_data_end_ptr = NULL; u_int8_t last_byte_0 = 0; u_int8_t last_byte_1 = 0; u_int8_t last_byte_2 = 0; u_int8_t last_byte_3 = 0; u_int8_t secondlast_byte_0 = 0; u_int8_t secondlast_byte_1 = 0; u_int8_t secondlast_byte_2 = 0; u_int8_t secondlast_byte_3 = 0; HT20_FFT_PACKET fft_20; HT40_FFT_PACKET fft_40; u_int8_t *fft_data_ptr = NULL; u_int8_t *fft_src_ptr = NULL; u_int8_t *data_ptr = NULL; int8_t cmp_rssi = -110; int8_t rssi_up = 0; int8_t rssi_low = 0; static u_int64_t last_tsf = 0; static u_int64_t send_tstamp = 0; int8_t nfc_control_rssi = 0; int8_t nfc_extension_rssi = 0; int peak_freq = 0; int nb_lower = 0; int nb_upper = 0; int8_t ctl_chan_noise_floor = DEFAULT_CHAN_NOISE_FLOOR; int8_t ext_chan_noise_floor = DEFAULT_CHAN_NOISE_FLOOR; struct ath_softc* sc = NULL; SPECTRAL_OPS* p_sops = NULL; if (((rxs->rs_phyerr != HAL_PHYERR_RADAR)) && ((rxs->rs_phyerr != HAL_PHYERR_FALSE_RADAR_EXT)) && ((rxs->rs_phyerr != HAL_PHYERR_SPECTRAL))) { printk("%s : Unknown PHY error (0x%x)\n", __func__, rxs->rs_phyerr); return; } if (spectral == NULL) { printk("Spectral Module not attached\n"); return; } sc = GET_SPECTRAL_ATHSOFTC(spectral); p_sops = GET_SPECTRAL_OPS(spectral); spectral->ath_spectral_stats.total_phy_errors++; /* Get pointer to data & timestamp*/ datalen = rxs->rs_datalen; tstamp = (rxs->rs_tstamp & SPECTRAL_TSMASK); /* check for valid data length */ if ((!datalen) || (datalen < spectral->spectral_data_len - 1)) { spectral->ath_spectral_stats.datalen_discards++; return; } /* WAR: Never trust combined RSSI on radar pulses for <= * OWL2.0. For short pulses only the chain 0 rssi is present * and remaining descriptor data is all 0x80, for longer * pulses the descriptor is present, but the combined value is * inaccurate. This HW capability is queried in spectral_attach and stored in * the sc_spectral_combined_rssi_ok flag.*/ if (spectral->sc_spectral_combined_rssi_ok) { rssi = (u_int8_t) rxs->rs_rssi; } else { rssi = (u_int8_t) rxs->rs_rssi_ctl0; } /* get rssi values */ combined_rssi = rssi; control_rssi = (u_int8_t) rxs->rs_rssi_ctl0; extension_rssi = (u_int8_t) rxs->rs_rssi_ext0; ext_rssi = (u_int8_t) rxs->rs_rssi_ext0; /* * If the combined RSSI is less than a particular threshold, this pulse is of no * interest to the classifier, so discard it here itself * except when noise power cal is required (then we want all rssi values) */ inv_combined_rssi = fix_rssi_inv_only(combined_rssi); if (inv_combined_rssi < 5 && !spectral->sc_spectral_noise_pwr_cal) { return; } last_word_ptr = (u_int32_t *)(((u_int8_t*)bf->bf_vdata) + datalen - (datalen%4)); secondlast_word_ptr = last_word_ptr-1; byte_ptr = (u_int8_t*)last_word_ptr; last_byte_0 = (*(byte_ptr) & 0xff); last_byte_1 = (*(byte_ptr+1) & 0xff); last_byte_2 = (*(byte_ptr+2) & 0xff); last_byte_3 = (*(byte_ptr+3) & 0xff); byte_ptr = (u_int8_t*)secondlast_word_ptr; secondlast_byte_0 = (*(byte_ptr) & 0xff); secondlast_byte_1 = (*(byte_ptr+1) & 0xff); secondlast_byte_2 = (*(byte_ptr+2) & 0xff); secondlast_byte_3 = (*(byte_ptr+3) & 0xff); switch((datalen & 0x3)) { case 0: pulse_bw_info = secondlast_byte_3; pulse_length_ext = secondlast_byte_2; pulse_length_pri = secondlast_byte_1; byte_ptr = (u_int8_t*)secondlast_word_ptr; fft_data_end_ptr = (byte_ptr); break; case 1: pulse_bw_info = last_byte_0; pulse_length_ext = secondlast_byte_3; pulse_length_pri = secondlast_byte_2; byte_ptr = (u_int8_t*)secondlast_word_ptr; fft_data_end_ptr = (byte_ptr+2); break; case 2: pulse_bw_info = last_byte_1; pulse_length_ext = last_byte_0; pulse_length_pri = secondlast_byte_3; byte_ptr = (u_int8_t*)secondlast_word_ptr; fft_data_end_ptr = (byte_ptr+3); break; case 3: pulse_bw_info = last_byte_2; pulse_length_ext = last_byte_1; pulse_length_pri = last_byte_0; byte_ptr = (u_int8_t*)last_word_ptr; fft_data_end_ptr = (byte_ptr); break; default: printk( "datalen mod4=%d spectral_data_len=%d\n", (datalen%4), spectral->spectral_data_len); } /* * Only the last 3 bits of the BW info are relevant, * they indicate which channel the radar was detected in. */ pulse_bw_info &= 0x17; if (pulse_bw_info & SPECTRAL_SCAN_DATA) { if (datalen > spectral->spectral_data_len + 2) { //printk("Invalid spectral scan datalen = %d\n", datalen); return; } if (spectral->num_spectral_data == 0) { spectral->first_tstamp = tstamp; spectral->max_rssi = -110; //printk( "First FFT data tstamp = %u rssi=%d\n", tstamp, fix_rssi_inv_only(combined_rssi)); } spectral->num_spectral_data++; OS_MEMZERO(&fft_40, sizeof (fft_40)); OS_MEMZERO(&fft_20, sizeof (fft_20)); if (spectral->sc_spectral_20_40_mode) { fft_data_ptr = (u_int8_t*)&fft_40.lower_bins.bin_magnitude[0]; } else { fft_data_ptr = (u_int8_t*)&fft_20.lower_bins.bin_magnitude[0]; } byte_ptr = fft_data_ptr; if (datalen == spectral->spectral_data_len) { if (spectral->sc_spectral_20_40_mode) { // HT40 packet, correct length OS_MEMCPY(&fft_40, (u_int8_t*)(bf->bf_vdata), datalen); } else { // HT20 packet, correct length OS_MEMCPY(&fft_20, (u_int8_t*)(bf->bf_vdata), datalen); } } /* This happens when there is a missing byte because CCK is enabled. * This may happen with or without the second bug of the MAC inserting * 2 bytes */ if ((datalen == (spectral->spectral_data_len - 1)) || (datalen == (spectral->spectral_data_len + 1))) { printk( "%s %d missing 1 byte datalen=%d expected=%d\n", __func__, __LINE__, datalen, spectral->spectral_data_len); already_copied++; if (spectral->sc_spectral_20_40_mode) { // HT40 packet, missing 1 byte // Use the beginning byte as byte 0 and byte 1 fft_40.lower_bins.bin_magnitude[0]=*(u_int8_t*)(bf->bf_vdata); // Now copy over the rest fft_data_ptr = (u_int8_t*)&fft_40.lower_bins.bin_magnitude[1]; OS_MEMCPY(fft_data_ptr, (u_int8_t*)(bf->bf_vdata), datalen); } else { // HT20 packet, missing 1 byte // Use the beginning byte as byte 0 and byte 1 fft_20.lower_bins.bin_magnitude[0]=*(u_int8_t*)(bf->bf_vdata); // Now copy over the rest fft_data_ptr = (u_int8_t*)&fft_20.lower_bins.bin_magnitude[1]; OS_MEMCPY(fft_data_ptr, (u_int8_t*)(bf->bf_vdata), datalen); } } if ((datalen == (spectral->spectral_data_len + 1)) || (datalen == (spectral->spectral_data_len + 2))) { //printk( "%s %d extra bytes datalen=%d expected=%d\n", __func__, __LINE__, datalen, spectral->spectral_data_len); if (spectral->sc_spectral_20_40_mode) {// HT40 packet, MAC added 2 extra bytes fft_src_ptr = (u_int8_t*)(bf->bf_vdata); fft_data_ptr = (u_int8_t*)&fft_40.lower_bins.bin_magnitude[already_copied]; for( i = 0, newdatalen=0; newdatalen < (SPECTRAL_HT40_DATA_LEN - already_copied); i++) { if (i == 30 || i == 32) { continue; } *(fft_data_ptr+newdatalen)=*(fft_src_ptr+i); newdatalen++; } } else { //HT20 packet, MAC added 2 extra bytes fft_src_ptr = (u_int8_t*)(bf->bf_vdata); fft_data_ptr = (u_int8_t*)&fft_20.lower_bins.bin_magnitude[already_copied]; for(i=0, newdatalen=0; newdatalen < (SPECTRAL_HT20_DATA_LEN - already_copied); i++) { if (i == 30 || i == 32) continue; *(fft_data_ptr+newdatalen)=*(fft_src_ptr+i); newdatalen++; } } } spectral->total_spectral_data++; dc_index = spectral->spectral_dc_index; if (spectral->sc_spectral_20_40_mode) { max_exp = (fft_40.max_exp & 0x07); byte_ptr = (u_int8_t*)&fft_40.lower_bins.bin_magnitude[0]; /* Correct the DC bin value */ lower_dc = *(byte_ptr+dc_index-1); upper_dc = *(byte_ptr+dc_index+1); *(byte_ptr+dc_index)=((upper_dc + lower_dc)/2); } else { max_exp = (fft_20.max_exp & 0x07); byte_ptr = (u_int8_t*)&fft_20.lower_bins.bin_magnitude[0]; /* Correct the DC bin value */ lower_dc = *(byte_ptr+dc_index-1); upper_dc = *(byte_ptr+dc_index+1); *(byte_ptr+dc_index)=((upper_dc + lower_dc)/2); } if (p_sops->get_ent_spectral_mask(spectral)) { *(byte_ptr+dc_index) &= ~((1 << p_sops->get_ent_spectral_mask(spectral)) - 1); } if (max_exp < 1) { max_scale = 1; } else { max_scale = (2) << (max_exp - 1); } bin_pwr_count = spectral->spectral_numbins; if ((last_tsf > fulltsf) && (!spectral->classify_scan)) { spectral->send_single_packet = 1; last_tsf = fulltsf; } inv_combined_rssi = fix_rssi_inv_only(combined_rssi); inv_control_rssi = fix_rssi_inv_only(control_rssi); inv_extension_rssi = fix_rssi_inv_only(extension_rssi); { if (spectral->upper_is_control) rssi_up = control_rssi; else rssi_up = extension_rssi; if (spectral->lower_is_control) rssi_low = control_rssi; else rssi_low = extension_rssi; nfc_control_rssi = get_nfc_ctl_rssi(spectral, inv_control_rssi, &temp_nf); ctl_chan_noise_floor = temp_nf; rssi_low = fix_rssi_for_classifier(spectral, rssi_low, spectral->lower_is_control, spectral->lower_is_extension); if (spectral->sc_spectral_20_40_mode) { rssi_up = fix_rssi_for_classifier(spectral, rssi_up,spectral->upper_is_control,spectral->upper_is_extension); nfc_extension_rssi = get_nfc_ext_rssi(spectral, inv_extension_rssi, &temp_nf); ext_chan_noise_floor = temp_nf; } } if(sc->sc_ieee_ops->spectral_eacs_update) { sc->sc_ieee_ops->spectral_eacs_update(sc->sc_ieee, nfc_control_rssi, nfc_extension_rssi, ctl_chan_noise_floor, ext_chan_noise_floor); } if (!spectral->sc_spectral_20_40_mode) { rssi_up = 0; extension_rssi = 0; inv_extension_rssi = 0; nb_upper = 0; maxindex_upper = 0; maxmag_upper = 0; } params.rssi = inv_combined_rssi; params.lower_rssi = rssi_low; params.upper_rssi = rssi_up; if (spectral->sc_spectral_noise_pwr_cal) { params.chain_ctl_rssi[0] = fix_rssi_inv_only(rxs->rs_rssi_ctl0); params.chain_ctl_rssi[1] = fix_rssi_inv_only(rxs->rs_rssi_ctl1); params.chain_ctl_rssi[2] = fix_rssi_inv_only(rxs->rs_rssi_ctl2); params.chain_ext_rssi[0] = fix_rssi_inv_only(rxs->rs_rssi_ext0); params.chain_ext_rssi[1] = fix_rssi_inv_only(rxs->rs_rssi_ext1); params.chain_ext_rssi[2] = fix_rssi_inv_only(rxs->rs_rssi_ext2); } params.bwinfo = pulse_bw_info; params.tstamp = tstamp; params.max_mag = max_mag; params.max_index = max_index; params.max_exp = max_scale; params.peak = peak_freq; params.pwr_count = bin_pwr_count; params.bin_pwr_data = &byte_ptr; params.freq = p_sops->get_current_channel(spectral); if(sc->sc_ieee_ops->spectral_get_freq_loading) { params.freq_loading = sc->sc_ieee_ops->spectral_get_freq_loading(sc->sc_ieee); } else { params.freq_loading = 0; } params.interf_list.count = 0; params.max_lower_index = 0;//maxindex_lower; params.max_upper_index = 0;//maxindex_upper; params.nb_lower = nb_lower; params.nb_upper = nb_upper; params.last_tstamp = spectral->last_tstamp; get_nfc_ctl_rssi(spectral, inv_control_rssi, &temp_nf); params.noise_floor = (int16_t)temp_nf; OS_MEMCPY(¶ms.classifier_params, &spectral->classifier_params, sizeof(SPECTRAL_CLASSIFIER_PARAMS)); cmp_rssi = fix_rssi_inv_only (combined_rssi); spectral->send_single_packet = 0; #ifdef SPECTRAL_DEBUG_TIMER OS_CANCEL_TIMER(&spectral->debug_timer); #endif spectral->spectral_sent_msg++; params.datalen = datalen; if (spectral->sc_spectral_20_40_mode) { data_ptr = (u_int8_t*)&fft_40.lower_bins.bin_magnitude; } else { data_ptr = (u_int8_t*)&fft_20.lower_bins.bin_magnitude; } byte_ptr = (u_int8_t*)data_ptr; params.bin_pwr_data = &byte_ptr; send_tstamp = p_sops->get_tsf64(spectral); spectral_create_samp_msg(spectral, ¶ms); #ifdef SPECTRAL_CLASSIFIER_IN_KERNEL if (spectral->classify_scan && maxindex_lower != (SPECTRAL_HT20_DC_INDEX + 1)) { classifier(&spectral->bd_lower, tstamp, spectral->last_tstamp, rssi_low, nb_lower, maxindex_lower); if (spectral->sc_spectral_20_40_mode && maxindex_upper != (SPECTRAL_HT40_DC_INDEX)) { classifier(&spectral->bd_upper, tstamp, spectral->last_tstamp, rssi_up, nb_upper, maxindex_upper); } print_detection(sc); } #endif /* SPECTRAL_CLASSIFIER_IN_KERNEL */ spectral->last_tstamp=tstamp; return; } else { /* * Add a HAL capability that tests if chip is capable of spectral scan. * Probably just a check if its a Merlin and above. */ printk("Non Spectral error\n"); spectral->ath_spectral_stats.owl_phy_errors++; } #undef EXT_CH_RADAR_FOUND #undef PRI_CH_RADAR_FOUND #undef EXT_CH_RADAR_EARLY_FOUND #undef SPECTRAL_SCAN_DATA }