diff options
author | Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> | 2013-10-11 08:09:55 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-10-18 14:03:53 -0400 |
commit | e07f01e4c7d583adb1ec25e63a52db5fc10a94d3 (patch) | |
tree | 0b09390f123a46db3e1ff5916c38ca9a4bc389e5 | |
parent | 5bc225acfe6a6226333061107708033a8d181d39 (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.h | 29 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 146 |
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 | */ |
887 | enum ath_fft_sample_type { | 887 | enum 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 | ||
891 | struct fft_sample_tlv { | 892 | struct 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 | ||
916 | struct 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 | |||
915 | void ath9k_tasklet(unsigned long data); | 944 | void ath9k_tasklet(unsigned long data); |
916 | int ath_cabq_update(struct ath_softc *); | 945 | int 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; |