diff options
author | Johannes Berg <johannes.berg@intel.com> | 2015-06-10 12:44:58 +0200 |
---|---|---|
committer | Johannes Berg <johannes.berg@intel.com> | 2015-06-10 12:45:09 +0200 |
commit | 206c59d1d7d42bcafc1d7f1e476e87e4427e2345 (patch) | |
tree | a2f99470bd0fe43f5cf57812fca969bb3ca3c451 /drivers/net/wireless/ath/ath9k | |
parent | 5ec596c41bba6f4e3eeef5dc089afc8eaa702a7e (diff) | |
parent | c3eee1fb1d308564ada5f7ea57bc51efc6130b37 (diff) |
Merge remote-tracking branch 'net-next/master' into mac80211-next
Merge back net-next to get wireless driver changes (from Kalle)
to be able to create the API change across all trees properly.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar5008_phy.c | 155 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ar9002_phy.c | 144 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/common-spectral.c | 740 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/common-spectral.h | 35 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 52 |
8 files changed, 759 insertions, 377 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index 6c23d279525f..8f8793004b9f 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -254,86 +254,25 @@ static int ar5008_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) return 0; } -/** - * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios - * @ah: atheros hardware structure - * @chan: - * - * For non single-chip solutions. Converts to baseband spur frequency given the - * input channel frequency and compute register settings below. - */ -static void ar5008_hw_spur_mitigate(struct ath_hw *ah, - struct ath9k_channel *chan) +void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan, int bin) { - int bb_spur = AR_NO_SPUR; - int bin, cur_bin; - int spur_freq_sd; - int spur_delta_phase; - int denominator; + int cur_bin; int upper, lower, cur_vit_mask; - int tmp, new; int i; - static int pilot_mask_reg[4] = { + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + static const int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 }; - static int chan_mask_reg[4] = { + static const int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 }; - static int inc[4] = { 0, 100, 0, 0 }; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - (chan->channel * 10); - if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) - return; - - bin = bb_spur * 32; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - - new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, new); - - spur_delta_phase = ((bb_spur * 524288) / 100) & - AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; - spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - - new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, new); + static const int inc[4] = { 0, 100, 0, 0 }; cur_bin = -6000; upper = bin + 100; @@ -343,6 +282,7 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, int pilot_mask = 0; int chan_mask = 0; int bp = 0; + for (bp = 0; bp < 30; bp++) { if ((cur_bin > lower) && (cur_bin < upper)) { pilot_mask = pilot_mask | 0x1 << bp; @@ -361,7 +301,6 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, for (i = 0; i < 123; i++) { if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - /* workaround for gcc bug #37014 */ volatile int tmp_v = abs(cur_vit_mask - bin); @@ -467,6 +406,78 @@ static void ar5008_hw_spur_mitigate(struct ath_hw *ah, } /** + * ar5008_hw_spur_mitigate - convert baseband spur frequency for external radios + * @ah: atheros hardware structure + * @chan: + * + * For non single-chip solutions. Converts to baseband spur frequency given the + * input channel frequency and compute register settings below. + */ +static void ar5008_hw_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int tmp, new; + int i; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ah->eep_ops->get_spur_channel(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) + return; + + bin = bb_spur * 32; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); + + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, new); + + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; + + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, new); + + ar5008_hw_cmn_spur_mitigate(ah, chan, bin); +} + +/** * ar5008_hw_rf_alloc_ext_banks - allocates banks for external radio programming * @ah: atheros hardware structure * diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c index fc08162b5820..db6624527d99 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c @@ -169,29 +169,17 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah, { int bb_spur = AR_NO_SPUR; int freq; - int bin, cur_bin; + int bin; int bb_spur_off, spur_subchannel_sd; int spur_freq_sd; int spur_delta_phase; int denominator; - int upper, lower, cur_vit_mask; int tmp, newVal; int i; - static const int pilot_mask_reg[4] = { - AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - static const int chan_mask_reg[4] = { - AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - static const int inc[4] = { 0, 100, 0, 0 }; struct chan_centers centers; int8_t mask_m[123]; int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; int cur_bb_spur; bool is2GHz = IS_CHAN_2GHZ(chan); @@ -288,135 +276,7 @@ static void ar9002_hw_spur_mitigate(struct ath_hw *ah, newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp_v = abs(cur_vit_mask - bin); - - if (tmp_v < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); + ar5008_hw_cmn_spur_mitigate(ah, chan, bin); REGWRITE_BUFFER_FLUSH(ah); } diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c index 5cee231cca1f..a8762711ad74 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.c +++ b/drivers/net/wireless/ath/ath9k/common-spectral.c @@ -15,6 +15,7 @@ */ #include <linux/relay.h> +#include <linux/random.h> #include "ath9k.h" static s8 fix_rssi_inv_only(u8 rssi_val) @@ -36,21 +37,480 @@ static void ath_debug_send_fft_sample(struct ath_spec_scan_priv *spec_priv, relay_write(spec_priv->rfs_chan_spec_scan, fft_sample_tlv, length); } +typedef int (ath_cmn_fft_idx_validator) (u8 *sample_end, int bytes_read); + +static int +ath_cmn_max_idx_verify_ht20_fft(u8 *sample_end, int bytes_read) +{ + struct ath_ht20_mag_info *mag_info; + u8 *sample; + u16 max_magnitude; + u8 max_index; + u8 max_exp; + + /* Sanity check so that we don't read outside the read + * buffer + */ + if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN - 1) + return -1; + + mag_info = (struct ath_ht20_mag_info *) (sample_end - + sizeof(struct ath_ht20_mag_info) + 1); + + sample = sample_end - SPECTRAL_HT20_SAMPLE_LEN + 1; + + max_index = spectral_max_index(mag_info->all_bins, + SPECTRAL_HT20_NUM_BINS); + max_magnitude = spectral_max_magnitude(mag_info->all_bins); + + max_exp = mag_info->max_exp & 0xf; + + /* Don't try to read something outside the read buffer + * in case of a missing byte (so bins[0] will be outside + * the read buffer) + */ + if (bytes_read < SPECTRAL_HT20_SAMPLE_LEN && max_index < 1) + return -1; + + if (sample[max_index] != (max_magnitude >> max_exp)) + return -1; + else + return 0; +} + +static int +ath_cmn_max_idx_verify_ht20_40_fft(u8 *sample_end, int bytes_read) +{ + struct ath_ht20_40_mag_info *mag_info; + u8 *sample; + u16 lower_mag, upper_mag; + u8 lower_max_index, upper_max_index; + u8 max_exp; + int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2; + + /* Sanity check so that we don't read outside the read + * buffer + */ + if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN - 1) + return -1; + + mag_info = (struct ath_ht20_40_mag_info *) (sample_end - + sizeof(struct ath_ht20_40_mag_info) + 1); + + sample = sample_end - SPECTRAL_HT20_40_SAMPLE_LEN + 1; + + lower_mag = spectral_max_magnitude(mag_info->lower_bins); + lower_max_index = spectral_max_index(mag_info->lower_bins, + SPECTRAL_HT20_40_NUM_BINS); + + upper_mag = spectral_max_magnitude(mag_info->upper_bins); + upper_max_index = spectral_max_index(mag_info->upper_bins, + SPECTRAL_HT20_40_NUM_BINS); + + max_exp = mag_info->max_exp & 0xf; + + /* Don't try to read something outside the read buffer + * in case of a missing byte (so bins[0] will be outside + * the read buffer) + */ + if (bytes_read < SPECTRAL_HT20_40_SAMPLE_LEN && + ((upper_max_index < 1) || (lower_max_index < 1))) + return -1; + + /* Some time hardware messes up the index and adds + * the index of the middle point (dc_pos). Try to fix it. + */ + if ((upper_max_index - dc_pos > 0) && + (sample[upper_max_index] == (upper_mag >> max_exp))) + upper_max_index -= dc_pos; + + if ((lower_max_index - dc_pos > 0) && + (sample[lower_max_index - dc_pos] == (lower_mag >> max_exp))) + lower_max_index -= dc_pos; + + if ((sample[upper_max_index + dc_pos] != (upper_mag >> max_exp)) || + (sample[lower_max_index] != (lower_mag >> max_exp))) + return -1; + else + return 0; +} + +typedef int (ath_cmn_fft_sample_handler) (struct ath_rx_status *rs, + struct ath_spec_scan_priv *spec_priv, + u8 *sample_buf, u64 tsf, u16 freq, int chan_type); + +static int +ath_cmn_process_ht20_fft(struct ath_rx_status *rs, + struct ath_spec_scan_priv *spec_priv, + u8 *sample_buf, + u64 tsf, u16 freq, int chan_type) +{ + struct fft_sample_ht20 fft_sample_20; + struct ath_common *common = ath9k_hw_common(spec_priv->ah); + struct ath_hw *ah = spec_priv->ah; + struct ath_ht20_mag_info *mag_info; + struct fft_sample_tlv *tlv; + int i = 0; + int ret = 0; + int dc_pos = SPECTRAL_HT20_NUM_BINS / 2; + u16 magnitude, tmp_mag, length; + u8 max_index, bitmap_w, max_exp; + + 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 *) (sample_buf + + SPECTRAL_HT20_NUM_BINS); + + 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, + SPECTRAL_HT20_NUM_BINS); + fft_sample_20.max_index = max_index; + + bitmap_w = spectral_bitmap_weight(mag_info->all_bins); + fft_sample_20.bitmap_weight = bitmap_w; + + max_exp = mag_info->max_exp & 0xf; + fft_sample_20.max_exp = max_exp; + + fft_sample_20.tsf = __cpu_to_be64(tsf); + + memcpy(fft_sample_20.data, sample_buf, SPECTRAL_HT20_NUM_BINS); + + ath_dbg(common, SPECTRAL_SCAN, "FFT HT20 frame: max mag 0x%X," + "max_mag_idx %i\n", + magnitude >> max_exp, + max_index); + + if (fft_sample_20.data[max_index] != (magnitude >> max_exp)) { + ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n"); + ret = -1; + } + + /* DC value (value in the middle) is the blind spot of the spectral + * sample and invalid, interpolate it. + */ + fft_sample_20.data[dc_pos] = (fft_sample_20.data[dc_pos + 1] + + fft_sample_20.data[dc_pos - 1]) / 2; + + /* Check if the maximum magnitude is indeed maximum, + * also if the maximum value was at dc_pos, calculate + * a new one (since value at dc_pos is invalid). + */ + if (max_index == dc_pos) { + tmp_mag = 0; + for (i = 0; i < dc_pos; i++) { + if (fft_sample_20.data[i] > tmp_mag) { + tmp_mag = fft_sample_20.data[i]; + fft_sample_20.max_index = i; + } + } + + magnitude = tmp_mag << max_exp; + fft_sample_20.max_magnitude = __cpu_to_be16(magnitude); + + ath_dbg(common, SPECTRAL_SCAN, + "Calculated new lower max 0x%X at %i\n", + tmp_mag, fft_sample_20.max_index); + } else + for (i = 0; i < SPECTRAL_HT20_NUM_BINS; i++) { + if (fft_sample_20.data[i] == (magnitude >> max_exp)) + ath_dbg(common, SPECTRAL_SCAN, + "Got max: 0x%X at index %i\n", + fft_sample_20.data[i], i); + + if (fft_sample_20.data[i] > (magnitude >> max_exp)) { + ath_dbg(common, SPECTRAL_SCAN, + "Got bin %i greater than max: 0x%X\n", + i, fft_sample_20.data[i]); + ret = -1; + } + } + + if (ret < 0) + return ret; + + tlv = (struct fft_sample_tlv *)&fft_sample_20; + + ath_debug_send_fft_sample(spec_priv, tlv); + + return 0; +} + +static int +ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs, + struct ath_spec_scan_priv *spec_priv, + u8 *sample_buf, + u64 tsf, u16 freq, int chan_type) +{ + struct fft_sample_ht20_40 fft_sample_40; + struct ath_common *common = ath9k_hw_common(spec_priv->ah); + struct ath_hw *ah = spec_priv->ah; + struct ath9k_hw_cal_data *caldata = ah->caldata; + struct ath_ht20_40_mag_info *mag_info; + struct fft_sample_tlv *tlv; + int dc_pos = SPECTRAL_HT20_40_NUM_BINS / 2; + int i = 0; + int ret = 0; + s16 ext_nf; + u16 lower_mag, upper_mag, tmp_mag, length; + s8 lower_rssi, upper_rssi; + u8 lower_max_index, upper_max_index; + u8 lower_bitmap_w, upper_bitmap_w, max_exp; + + 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 *) (sample_buf + + SPECTRAL_HT20_40_NUM_BINS); + + lower_mag = spectral_max_magnitude(mag_info->lower_bins); + fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag); + + upper_mag = spectral_max_magnitude(mag_info->upper_bins); + fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag); + + lower_max_index = spectral_max_index(mag_info->lower_bins, + SPECTRAL_HT20_40_NUM_BINS); + fft_sample_40.lower_max_index = lower_max_index; + + upper_max_index = spectral_max_index(mag_info->upper_bins, + SPECTRAL_HT20_40_NUM_BINS); + fft_sample_40.upper_max_index = upper_max_index; + + lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins); + fft_sample_40.lower_bitmap_weight = lower_bitmap_w; + + upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins); + fft_sample_40.upper_bitmap_weight = upper_bitmap_w; + + max_exp = mag_info->max_exp & 0xf; + fft_sample_40.max_exp = max_exp; + + fft_sample_40.tsf = __cpu_to_be64(tsf); + + memcpy(fft_sample_40.data, sample_buf, SPECTRAL_HT20_40_NUM_BINS); + + ath_dbg(common, SPECTRAL_SCAN, "FFT HT20/40 frame: lower mag 0x%X," + "lower_mag_idx %i, upper mag 0x%X," + "upper_mag_idx %i\n", + lower_mag >> max_exp, + lower_max_index, + upper_mag >> max_exp, + upper_max_index); + + /* Some time hardware messes up the index and adds + * the index of the middle point (dc_pos). Try to fix it. + */ + if ((upper_max_index - dc_pos > 0) && + (fft_sample_40.data[upper_max_index] == (upper_mag >> max_exp))) { + upper_max_index -= dc_pos; + fft_sample_40.upper_max_index = upper_max_index; + } + + if ((lower_max_index - dc_pos > 0) && + (fft_sample_40.data[lower_max_index - dc_pos] == + (lower_mag >> max_exp))) { + lower_max_index -= dc_pos; + fft_sample_40.lower_max_index = lower_max_index; + } + + /* Check if we got the expected magnitude values at + * the expected bins + */ + if ((fft_sample_40.data[upper_max_index + dc_pos] + != (upper_mag >> max_exp)) || + (fft_sample_40.data[lower_max_index] + != (lower_mag >> max_exp))) { + ath_dbg(common, SPECTRAL_SCAN, "Magnitude mismatch !\n"); + ret = -1; + } + + /* DC value (value in the middle) is the blind spot of the spectral + * sample and invalid, interpolate it. + */ + fft_sample_40.data[dc_pos] = (fft_sample_40.data[dc_pos + 1] + + fft_sample_40.data[dc_pos - 1]) / 2; + + /* Check if the maximum magnitudes are indeed maximum, + * also if the maximum value was at dc_pos, calculate + * a new one (since value at dc_pos is invalid). + */ + if (lower_max_index == dc_pos) { + tmp_mag = 0; + for (i = 0; i < dc_pos; i++) { + if (fft_sample_40.data[i] > tmp_mag) { + tmp_mag = fft_sample_40.data[i]; + fft_sample_40.lower_max_index = i; + } + } + + lower_mag = tmp_mag << max_exp; + fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag); + + ath_dbg(common, SPECTRAL_SCAN, + "Calculated new lower max 0x%X at %i\n", + tmp_mag, fft_sample_40.lower_max_index); + } else + for (i = 0; i < dc_pos; i++) { + if (fft_sample_40.data[i] == (lower_mag >> max_exp)) + ath_dbg(common, SPECTRAL_SCAN, + "Got lower mag: 0x%X at index %i\n", + fft_sample_40.data[i], i); + + if (fft_sample_40.data[i] > (lower_mag >> max_exp)) { + ath_dbg(common, SPECTRAL_SCAN, + "Got lower bin %i higher than max: 0x%X\n", + i, fft_sample_40.data[i]); + ret = -1; + } + } + + if (upper_max_index == dc_pos) { + tmp_mag = 0; + for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) { + if (fft_sample_40.data[i] > tmp_mag) { + tmp_mag = fft_sample_40.data[i]; + fft_sample_40.upper_max_index = i; + } + } + upper_mag = tmp_mag << max_exp; + fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag); + + ath_dbg(common, SPECTRAL_SCAN, + "Calculated new upper max 0x%X at %i\n", + tmp_mag, i); + } else + for (i = dc_pos; i < SPECTRAL_HT20_40_NUM_BINS; i++) { + if (fft_sample_40.data[i] == (upper_mag >> max_exp)) + ath_dbg(common, SPECTRAL_SCAN, + "Got upper mag: 0x%X at index %i\n", + fft_sample_40.data[i], i); + + if (fft_sample_40.data[i] > (upper_mag >> max_exp)) { + ath_dbg(common, SPECTRAL_SCAN, + "Got upper bin %i higher than max: 0x%X\n", + i, fft_sample_40.data[i]); + + ret = -1; + } + } + + if (ret < 0) + return ret; + + tlv = (struct fft_sample_tlv *)&fft_sample_40; + + ath_debug_send_fft_sample(spec_priv, tlv); + + return 0; +} + +static inline void +ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes) +{ + switch (sample_bytes - sample_len) { + case -1: + /* First byte missing */ + memcpy(&out[1], in, + sample_len - 1); + break; + case 0: + /* Length correct, nothing to do. */ + memcpy(out, in, sample_len); + break; + case 1: + /* MAC added 2 extra bytes AND first byte + * is missing. + */ + memcpy(&out[1], in, 30); + out[31] = in[31]; + memcpy(&out[32], &in[33], + sample_len - 32); + break; + case 2: + /* MAC added 2 extra bytes at bin 30 and 32, + * remove them. + */ + memcpy(out, in, 30); + out[30] = in[31]; + memcpy(&out[31], &in[33], + sample_len - 31); + break; + default: + break; + } +} + +static int +ath_cmn_is_fft_buf_full(struct ath_spec_scan_priv *spec_priv) +{ + int i = 0; + int ret = 0; + struct rchan *rc = spec_priv->rfs_chan_spec_scan; + + for_each_online_cpu(i) + ret += relay_buf_full(rc->buf[i]); + + i = num_online_cpus(); + + if (ret == i) + return 1; + else + return 0; +} + /* returns 1 if this was a spectral frame, even if not handled. */ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_hdr *hdr, struct ath_rx_status *rs, u64 tsf) { + u8 sample_buf[SPECTRAL_SAMPLE_MAX_LEN] = {0}; struct ath_hw *ah = spec_priv->ah; struct ath_common *common = ath9k_hw_common(spec_priv->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; + u8 num_bins, *vdata = (u8 *)hdr; struct ath_radar_info *radar_info; int len = rs->rs_datalen; - int dc_pos; - u16 fft_len, length, freq = ah->curchan->chan->center_freq; + int i; + int got_slen = 0; + u8 *sample_start; + int sample_bytes = 0; + int ret = 0; + u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq; enum nl80211_channel_type chan_type; + ath_cmn_fft_idx_validator *fft_idx_validator; + ath_cmn_fft_sample_handler *fft_handler; /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT @@ -68,140 +528,170 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) return 0; + /* Output buffers are full, no need to process anything + * since there is no space to put the result anyway + */ + ret = ath_cmn_is_fft_buf_full(spec_priv); + if (ret == 1) { + ath_dbg(common, SPECTRAL_SCAN, "FFT report ignored, no space " + "left on output buffers\n"); + return 1; + } + chan_type = cfg80211_get_chandef_type(&common->hw->conf.chandef); if ((chan_type == NL80211_CHAN_HT40MINUS) || (chan_type == NL80211_CHAN_HT40PLUS)) { fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN; + sample_len = SPECTRAL_HT20_40_SAMPLE_LEN; num_bins = SPECTRAL_HT20_40_NUM_BINS; - bins = (u8 *)fft_sample_40.data; + fft_idx_validator = &ath_cmn_max_idx_verify_ht20_40_fft; + fft_handler = &ath_cmn_process_ht20_40_fft; } else { fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN; + sample_len = SPECTRAL_HT20_SAMPLE_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; + fft_idx_validator = ath_cmn_max_idx_verify_ht20_fft; + fft_handler = &ath_cmn_process_ht20_fft; } - /* 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; + ath_dbg(common, SPECTRAL_SCAN, "Got radar dump bw_info: 0x%X," + "len: %i fft_len: %i\n", + radar_info->pulse_bw_info, + len, + fft_len); + sample_start = vdata; + for (i = 0; i < len - 2; i++) { + sample_bytes++; + + /* Only a single sample received, no need to look + * for the sample's end, do the correction based + * on the packet's length instead. Note that hw + * will always put the radar_info structure on + * the end. + */ + if (len <= fft_len + 2) { + sample_bytes = len - sizeof(struct ath_radar_info); + got_slen = 1; } - 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); + /* Search for the end of the FFT frame between + * sample_len - 1 and sample_len + 2. exp_max is 3 + * bits long and it's the only value on the last + * byte of the frame so since it'll be smaller than + * the next byte (the first bin of the next sample) + * 90% of the time, we can use it as a separator. + */ + if (vdata[i] <= 0x7 && sample_bytes >= sample_len - 1) { + + /* Got a frame length within boundaries, there are + * four scenarios here: + * + * a) sample_len -> We got the correct length + * b) sample_len + 2 -> 2 bytes added around bin[31] + * c) sample_len - 1 -> The first byte is missing + * d) sample_len + 1 -> b + c at the same time + * + * When MAC adds 2 extra bytes, bin[31] and bin[32] + * have the same value, so we can use that for further + * verification in cases b and d. + */ + + /* Did we go too far ? If so we couldn't determine + * this sample's boundaries, discard any further + * data + */ + if ((sample_bytes > sample_len + 2) || + ((sample_bytes > sample_len) && + (sample_start[31] != sample_start[32]))) + break; + + /* See if we got a valid frame by checking the + * consistency of mag_info fields. This is to + * prevent from "fixing" a correct frame. + * Failure is non-fatal, later frames may + * be valid. + */ + if (!fft_idx_validator(&vdata[i], i)) { + ath_dbg(common, SPECTRAL_SCAN, + "Found valid fft frame at %i\n", i); + got_slen = 1; + } + + /* We expect 1 - 2 more bytes */ + else if ((sample_start[31] == sample_start[32]) && + (sample_bytes >= sample_len) && + (sample_bytes < sample_len + 2) && + (vdata[i + 1] <= 0x7)) + continue; + + /* Try to distinguish cases a and c */ + else if ((sample_bytes == sample_len - 1) && + (vdata[i + 1] <= 0x7)) + continue; + + got_slen = 1; + } - tlv = (struct fft_sample_tlv *)&fft_sample_20; + if (got_slen) { + ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n", + sample_bytes); + + /* Only try to fix a frame if it's the only one + * on the report, else just skip it. + */ + if (sample_bytes != sample_len && len <= fft_len + 2) { + ath_cmn_copy_fft_frame(sample_start, + sample_buf, sample_len, + sample_bytes); + + fft_handler(rs, spec_priv, sample_buf, + tsf, freq, chan_type); + + memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN); + + /* Mix the received bins to the /dev/random + * pool + */ + add_device_randomness(sample_buf, num_bins); + } + + /* Process a normal frame */ + if (sample_bytes == sample_len) { + ret = fft_handler(rs, spec_priv, sample_start, + tsf, freq, chan_type); + + /* Mix the received bins to the /dev/random + * pool + */ + add_device_randomness(sample_start, num_bins); + } + + /* Short report processed, break out of the + * loop. + */ + if (len <= fft_len + 2) + break; + + sample_start = &vdata[i + 1]; + + /* -1 to grab sample_len -1, -2 since + * they 'll get increased by one. In case + * of failure try to recover by going byte + * by byte instead. + */ + if (ret == 0) { + i += num_bins - 2; + sample_bytes = num_bins - 2; + } + got_slen = 0; + } } - ath_debug_send_fft_sample(spec_priv, tlv); - + i -= num_bins - 2; + if (len - i != sizeof(struct ath_radar_info)) + ath_dbg(common, SPECTRAL_SCAN, "FFT report truncated" + "(bytes left: %i)\n", + len - i); return 1; } EXPORT_SYMBOL(ath_cmn_process_fft); diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h index 82d9dd29652c..998743be9c67 100644 --- a/drivers/net/wireless/ath/ath9k/common-spectral.h +++ b/drivers/net/wireless/ath/ath9k/common-spectral.h @@ -66,6 +66,8 @@ struct ath_ht20_fft_packet { } __packed; #define SPECTRAL_HT20_TOTAL_DATA_LEN (sizeof(struct ath_ht20_fft_packet)) +#define SPECTRAL_HT20_SAMPLE_LEN (sizeof(struct ath_ht20_mag_info) +\ + SPECTRAL_HT20_NUM_BINS) /* Dynamic 20/40 mode: * @@ -101,6 +103,10 @@ struct ath_spec_scan_priv { }; #define SPECTRAL_HT20_40_TOTAL_DATA_LEN (sizeof(struct ath_ht20_40_fft_packet)) +#define SPECTRAL_HT20_40_SAMPLE_LEN (sizeof(struct ath_ht20_40_mag_info) +\ + SPECTRAL_HT20_40_NUM_BINS) + +#define SPECTRAL_SAMPLE_MAX_LEN SPECTRAL_HT20_40_SAMPLE_LEN /* grabs the max magnitude from the all/upper/lower bins */ static inline u16 spectral_max_magnitude(u8 *bins) @@ -111,17 +117,32 @@ static inline u16 spectral_max_magnitude(u8 *bins) } /* return the max magnitude from the all/upper/lower bins */ -static inline u8 spectral_max_index(u8 *bins) +static inline u8 spectral_max_index(u8 *bins, int num_bins) { s8 m = (bins[2] & 0xfc) >> 2; - - /* TODO: this still doesn't always report the right values ... */ - if (m > 32) + u8 zero_idx = num_bins / 2; + + /* It's a 5 bit signed int, remove its sign and use one's + * complement interpretation to add the sign back to the 8 + * bit int + */ + if (m & 0x20) { + m &= ~0x20; m |= 0xe0; - else - m &= ~0xe0; + } + + /* Bring the zero point to the beginning + * instead of the middle so that we can use + * it for array lookup and that we don't deal + * with negative values later + */ + m += zero_idx; + + /* Sanity check to make sure index is within bounds */ + if (m < 0 || m > num_bins - 1) + m = 0; - return m + 29; + return m; } /* return the bitmap weight from the all/upper/lower bins */ diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index e82a0d4ce23f..5dbc617ecf8a 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -440,9 +440,9 @@ static inline void ath9k_htc_stop_btcoex(struct ath9k_htc_priv *priv) } #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ -#define OP_BT_PRIORITY_DETECTED BIT(3) -#define OP_BT_SCAN BIT(4) -#define OP_TSF_RESET BIT(6) +#define OP_BT_PRIORITY_DETECTED 3 +#define OP_BT_SCAN 4 +#define OP_TSF_RESET 6 enum htc_op_flags { HTC_FWFLAG_NO_RMW, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index d7beefe60683..746856243bff 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -594,7 +594,7 @@ static void ath9k_init_misc(struct ath9k_htc_priv *priv) priv->spec_priv.ah = priv->ah; priv->spec_priv.spec_config.enabled = 0; - priv->spec_priv.spec_config.short_repeat = false; + priv->spec_priv.spec_config.short_repeat = true; priv->spec_priv.spec_config.count = 8; priv->spec_priv.spec_config.endless = false; priv->spec_priv.spec_config.period = 0x12; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index c1d2d0340feb..e8454db17634 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -1119,6 +1119,8 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah); void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx); void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array, struct ath9k_channel *chan); +void ar5008_hw_cmn_spur_mitigate(struct ath_hw *ah, + struct ath9k_channel *chan, int bin); void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, struct ath9k_channel *chan, int ht40_delta); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 0acd079ba96b..3ad79bb4f2c2 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1103,28 +1103,14 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, struct sk_buff *skb; struct ath_frame_info *fi; struct ieee80211_tx_info *info; - struct ieee80211_vif *vif; struct ath_hw *ah = sc->sc_ah; if (sc->tx99_state || !ah->tpc_enabled) return MAX_RATE_POWER; skb = bf->bf_mpdu; - info = IEEE80211_SKB_CB(skb); - vif = info->control.vif; - - if (!vif) { - max_power = sc->cur_chan->cur_txpower; - goto out; - } - - if (vif->bss_conf.txpower_type != NL80211_TX_POWER_LIMITED) { - max_power = min_t(u8, sc->cur_chan->cur_txpower, - 2 * vif->bss_conf.txpower); - goto out; - } - fi = get_frame_info(skb); + info = IEEE80211_SKB_CB(skb); if (!AR_SREV_9300_20_OR_LATER(ah)) { int txpower = fi->tx_power; @@ -1161,25 +1147,26 @@ static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf, txpower -= 2; txpower = max(txpower, 0); - max_power = min_t(u8, ah->tx_power[rateidx], - 2 * vif->bss_conf.txpower); - max_power = min_t(u8, max_power, txpower); + max_power = min_t(u8, ah->tx_power[rateidx], txpower); + + /* XXX: clamp minimum TX power at 1 for AR9160 since if + * max_power is set to 0, frames are transmitted at max + * TX power + */ + if (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) + max_power = 1; } else if (!bf->bf_state.bfs_paprd) { if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC)) max_power = min_t(u8, ah->tx_power_stbc[rateidx], - 2 * vif->bss_conf.txpower); + fi->tx_power); else max_power = min_t(u8, ah->tx_power[rateidx], - 2 * vif->bss_conf.txpower); - max_power = min(max_power, fi->tx_power); + fi->tx_power); } else { max_power = ah->paprd_training_power; } -out: - /* XXX: clamp minimum TX power at 1 for AR9160 since if max_power - * is set to 0, frames are transmitted at max TX power - */ - return (!max_power && !AR_SREV_9280_20_OR_LATER(ah)) ? 1 : max_power; + + return max_power; } static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, @@ -2129,6 +2116,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct ath_node *an = NULL; enum ath9k_key_type keytype; bool short_preamble = false; + u8 txpower; /* * We check if Short Preamble is needed for the CTS rate by @@ -2145,6 +2133,16 @@ static void setup_frame_info(struct ieee80211_hw *hw, if (sta) an = (struct ath_node *) sta->drv_priv; + if (tx_info->control.vif) { + struct ieee80211_vif *vif = tx_info->control.vif; + + txpower = 2 * vif->bss_conf.txpower; + } else { + struct ath_softc *sc = hw->priv; + + txpower = sc->cur_chan->cur_txpower; + } + memset(fi, 0, sizeof(*fi)); fi->txq = -1; if (hw_key) @@ -2155,7 +2153,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; fi->framelen = framelen; - fi->tx_power = MAX_RATE_POWER; + fi->tx_power = txpower; if (!rate) return; |