aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLorenzo Bianconi <lorenzo.bianconi83@gmail.com>2013-10-11 08:09:55 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-10-18 14:03:53 -0400
commite07f01e4c7d583adb1ec25e63a52db5fc10a94d3 (patch)
tree0b09390f123a46db3e1ff5916c38ca9a4bc389e5
parent5bc225acfe6a6226333061107708033a8d181d39 (diff)
ath9k: add HT40 spectral scan capability
Add spectral scan feature on HT40 channels for ath9k. This patch extends previous capability added by Simon Wunderlich Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> Reviewed-by: Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> Tested-by: Simon Wunderlich <simon.wunderlich@s2003.tu-chemnitz.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h29
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c146
2 files changed, 137 insertions, 38 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 5492a0ce0729..1fce36dd9088 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -886,6 +886,7 @@ static inline u8 spectral_bitmap_weight(u8 *bins)
886 */ 886 */
887enum ath_fft_sample_type { 887enum ath_fft_sample_type {
888 ATH_FFT_SAMPLE_HT20 = 1, 888 ATH_FFT_SAMPLE_HT20 = 1,
889 ATH_FFT_SAMPLE_HT20_40,
889}; 890};
890 891
891struct fft_sample_tlv { 892struct fft_sample_tlv {
@@ -912,6 +913,34 @@ struct fft_sample_ht20 {
912 u8 data[SPECTRAL_HT20_NUM_BINS]; 913 u8 data[SPECTRAL_HT20_NUM_BINS];
913} __packed; 914} __packed;
914 915
916struct fft_sample_ht20_40 {
917 struct fft_sample_tlv tlv;
918
919 u8 channel_type;
920 __be16 freq;
921
922 s8 lower_rssi;
923 s8 upper_rssi;
924
925 __be64 tsf;
926
927 s8 lower_noise;
928 s8 upper_noise;
929
930 __be16 lower_max_magnitude;
931 __be16 upper_max_magnitude;
932
933 u8 lower_max_index;
934 u8 upper_max_index;
935
936 u8 lower_bitmap_weight;
937 u8 upper_bitmap_weight;
938
939 u8 max_exp;
940
941 u8 data[SPECTRAL_HT20_40_NUM_BINS];
942} __packed;
943
915void ath9k_tasklet(unsigned long data); 944void ath9k_tasklet(unsigned long data);
916int ath_cabq_update(struct ath_softc *); 945int ath_cabq_update(struct ath_softc *);
917 946
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index a05164166de8..e37559a85bf6 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -972,14 +972,15 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
972{ 972{
973#ifdef CONFIG_ATH9K_DEBUGFS 973#ifdef CONFIG_ATH9K_DEBUGFS
974 struct ath_hw *ah = sc->sc_ah; 974 struct ath_hw *ah = sc->sc_ah;
975 u8 bins[SPECTRAL_HT20_NUM_BINS]; 975 u8 num_bins, *bins, *vdata = (u8 *)hdr;
976 u8 *vdata = (u8 *)hdr; 976 struct fft_sample_ht20 fft_sample_20;
977 struct fft_sample_ht20 fft_sample; 977 struct fft_sample_ht20_40 fft_sample_40;
978 struct fft_sample_tlv *tlv;
978 struct ath_radar_info *radar_info; 979 struct ath_radar_info *radar_info;
979 struct ath_ht20_mag_info *mag_info;
980 int len = rs->rs_datalen; 980 int len = rs->rs_datalen;
981 int dc_pos; 981 int dc_pos;
982 u16 length, max_magnitude; 982 u16 fft_len, length, freq = ah->curchan->chan->center_freq;
983 enum nl80211_channel_type chan_type;
983 984
984 /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer 985 /* AR9280 and before report via ATH9K_PHYERR_RADAR, AR93xx and newer
985 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT 986 * via ATH9K_PHYERR_SPECTRAL. Haven't seen ATH9K_PHYERR_FALSE_RADAR_EXT
@@ -997,45 +998,44 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
997 if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK)) 998 if (!(radar_info->pulse_bw_info & SPECTRAL_SCAN_BITMASK))
998 return 0; 999 return 0;
999 1000
1000 /* Variation in the data length is possible and will be fixed later. 1001 chan_type = cfg80211_get_chandef_type(&sc->hw->conf.chandef);
1001 * Note that we only support HT20 for now. 1002 if ((chan_type == NL80211_CHAN_HT40MINUS) ||
1002 * 1003 (chan_type == NL80211_CHAN_HT40PLUS)) {
1003 * TODO: add HT20_40 support as well. 1004 fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
1004 */ 1005 num_bins = SPECTRAL_HT20_40_NUM_BINS;
1005 if ((len > SPECTRAL_HT20_TOTAL_DATA_LEN + 2) || 1006 bins = (u8 *)fft_sample_40.data;
1006 (len < SPECTRAL_HT20_TOTAL_DATA_LEN - 1)) 1007 } else {
1007 return 1; 1008 fft_len = SPECTRAL_HT20_TOTAL_DATA_LEN;
1008 1009 num_bins = SPECTRAL_HT20_NUM_BINS;
1009 fft_sample.tlv.type = ATH_FFT_SAMPLE_HT20; 1010 bins = (u8 *)fft_sample_20.data;
1010 length = sizeof(fft_sample) - sizeof(fft_sample.tlv); 1011 }
1011 fft_sample.tlv.length = __cpu_to_be16(length);
1012 1012
1013 fft_sample.freq = __cpu_to_be16(ah->curchan->chan->center_freq); 1013 /* Variation in the data length is possible and will be fixed later */
1014 fft_sample.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0); 1014 if ((len > fft_len + 2) || (len < fft_len - 1))
1015 fft_sample.noise = ah->noise; 1015 return 1;
1016 1016
1017 switch (len - SPECTRAL_HT20_TOTAL_DATA_LEN) { 1017 switch (len - fft_len) {
1018 case 0: 1018 case 0:
1019 /* length correct, nothing to do. */ 1019 /* length correct, nothing to do. */
1020 memcpy(bins, vdata, SPECTRAL_HT20_NUM_BINS); 1020 memcpy(bins, vdata, num_bins);
1021 break; 1021 break;
1022 case -1: 1022 case -1:
1023 /* first byte missing, duplicate it. */ 1023 /* first byte missing, duplicate it. */
1024 memcpy(&bins[1], vdata, SPECTRAL_HT20_NUM_BINS - 1); 1024 memcpy(&bins[1], vdata, num_bins - 1);
1025 bins[0] = vdata[0]; 1025 bins[0] = vdata[0];
1026 break; 1026 break;
1027 case 2: 1027 case 2:
1028 /* MAC added 2 extra bytes at bin 30 and 32, remove them. */ 1028 /* MAC added 2 extra bytes at bin 30 and 32, remove them. */
1029 memcpy(bins, vdata, 30); 1029 memcpy(bins, vdata, 30);
1030 bins[30] = vdata[31]; 1030 bins[30] = vdata[31];
1031 memcpy(&bins[31], &vdata[33], SPECTRAL_HT20_NUM_BINS - 31); 1031 memcpy(&bins[31], &vdata[33], num_bins - 31);
1032 break; 1032 break;
1033 case 1: 1033 case 1:
1034 /* MAC added 2 extra bytes AND first byte is missing. */ 1034 /* MAC added 2 extra bytes AND first byte is missing. */
1035 bins[0] = vdata[0]; 1035 bins[0] = vdata[0];
1036 memcpy(&bins[0], vdata, 30); 1036 memcpy(&bins[1], vdata, 30);
1037 bins[31] = vdata[31]; 1037 bins[31] = vdata[31];
1038 memcpy(&bins[32], &vdata[33], SPECTRAL_HT20_NUM_BINS - 32); 1038 memcpy(&bins[32], &vdata[33], num_bins - 32);
1039 break; 1039 break;
1040 default: 1040 default:
1041 return 1; 1041 return 1;
@@ -1044,23 +1044,93 @@ static int ath_process_fft(struct ath_softc *sc, struct ieee80211_hdr *hdr,
1044 /* DC value (value in the middle) is the blind spot of the spectral 1044 /* DC value (value in the middle) is the blind spot of the spectral
1045 * sample and invalid, interpolate it. 1045 * sample and invalid, interpolate it.
1046 */ 1046 */
1047 dc_pos = SPECTRAL_HT20_NUM_BINS / 2; 1047 dc_pos = num_bins / 2;
1048 bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2; 1048 bins[dc_pos] = (bins[dc_pos + 1] + bins[dc_pos - 1]) / 2;
1049 1049
1050 /* mag data is at the end of the frame, in front of radar_info */ 1050 if ((chan_type == NL80211_CHAN_HT40MINUS) ||
1051 mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1; 1051 (chan_type == NL80211_CHAN_HT40PLUS)) {
1052 s8 lower_rssi, upper_rssi;
1053 s16 ext_nf;
1054 u8 lower_max_index, upper_max_index;
1055 u8 lower_bitmap_w, upper_bitmap_w;
1056 u16 lower_mag, upper_mag;
1057 struct ath9k_hw_cal_data *caldata = ah->caldata;
1058 struct ath_ht20_40_mag_info *mag_info;
1059
1060 if (caldata)
1061 ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
1062 caldata->nfCalHist[3].privNF);
1063 else
1064 ext_nf = ATH_DEFAULT_NOISE_FLOOR;
1065
1066 length = sizeof(fft_sample_40) - sizeof(struct fft_sample_tlv);
1067 fft_sample_40.tlv.type = ATH_FFT_SAMPLE_HT20_40;
1068 fft_sample_40.tlv.length = __cpu_to_be16(length);
1069 fft_sample_40.freq = __cpu_to_be16(freq);
1070 fft_sample_40.channel_type = chan_type;
1052 1071
1053 /* copy raw bins without scaling them */ 1072 if (chan_type == NL80211_CHAN_HT40PLUS) {
1054 memcpy(fft_sample.data, bins, SPECTRAL_HT20_NUM_BINS); 1073 lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
1055 fft_sample.max_exp = mag_info->max_exp & 0xf; 1074 upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ext0);
1075
1076 fft_sample_40.lower_noise = ah->noise;
1077 fft_sample_40.upper_noise = ext_nf;
1078 } else {
1079 lower_rssi = fix_rssi_inv_only(rs->rs_rssi_ext0);
1080 upper_rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
1056 1081
1057 max_magnitude = spectral_max_magnitude(mag_info->all_bins); 1082 fft_sample_40.lower_noise = ext_nf;
1058 fft_sample.max_magnitude = __cpu_to_be16(max_magnitude); 1083 fft_sample_40.upper_noise = ah->noise;
1059 fft_sample.max_index = spectral_max_index(mag_info->all_bins); 1084 }
1060 fft_sample.bitmap_weight = spectral_bitmap_weight(mag_info->all_bins); 1085 fft_sample_40.lower_rssi = lower_rssi;
1061 fft_sample.tsf = __cpu_to_be64(tsf); 1086 fft_sample_40.upper_rssi = upper_rssi;
1087
1088 mag_info = ((struct ath_ht20_40_mag_info *)radar_info) - 1;
1089 lower_mag = spectral_max_magnitude(mag_info->lower_bins);
1090 upper_mag = spectral_max_magnitude(mag_info->upper_bins);
1091 fft_sample_40.lower_max_magnitude = __cpu_to_be16(lower_mag);
1092 fft_sample_40.upper_max_magnitude = __cpu_to_be16(upper_mag);
1093 lower_max_index = spectral_max_index(mag_info->lower_bins);
1094 upper_max_index = spectral_max_index(mag_info->upper_bins);
1095 fft_sample_40.lower_max_index = lower_max_index;
1096 fft_sample_40.upper_max_index = upper_max_index;
1097 lower_bitmap_w = spectral_bitmap_weight(mag_info->lower_bins);
1098 upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
1099 fft_sample_40.lower_bitmap_weight = lower_bitmap_w;
1100 fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
1101 fft_sample_40.max_exp = mag_info->max_exp & 0xf;
1102
1103 fft_sample_40.tsf = __cpu_to_be64(tsf);
1104
1105 tlv = (struct fft_sample_tlv *)&fft_sample_40;
1106 } else {
1107 u8 max_index, bitmap_w;
1108 u16 magnitude;
1109 struct ath_ht20_mag_info *mag_info;
1110
1111 length = sizeof(fft_sample_20) - sizeof(struct fft_sample_tlv);
1112 fft_sample_20.tlv.type = ATH_FFT_SAMPLE_HT20;
1113 fft_sample_20.tlv.length = __cpu_to_be16(length);
1114 fft_sample_20.freq = __cpu_to_be16(freq);
1115
1116 fft_sample_20.rssi = fix_rssi_inv_only(rs->rs_rssi_ctl0);
1117 fft_sample_20.noise = ah->noise;
1118
1119 mag_info = ((struct ath_ht20_mag_info *)radar_info) - 1;
1120 magnitude = spectral_max_magnitude(mag_info->all_bins);
1121 fft_sample_20.max_magnitude = __cpu_to_be16(magnitude);
1122 max_index = spectral_max_index(mag_info->all_bins);
1123 fft_sample_20.max_index = max_index;
1124 bitmap_w = spectral_bitmap_weight(mag_info->all_bins);
1125 fft_sample_20.bitmap_weight = bitmap_w;
1126 fft_sample_20.max_exp = mag_info->max_exp & 0xf;
1127
1128 fft_sample_20.tsf = __cpu_to_be64(tsf);
1129
1130 tlv = (struct fft_sample_tlv *)&fft_sample_20;
1131 }
1062 1132
1063 ath_debug_send_fft_sample(sc, &fft_sample.tlv); 1133 ath_debug_send_fft_sample(sc, tlv);
1064 return 1; 1134 return 1;
1065#else 1135#else
1066 return 0; 1136 return 0;