All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/11] ath9k: Spectral scan updates
@ 2015-04-29 23:51 ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

On FFT spectral scans the hardware is able to send multiple FFT
frames per report (packet).

This is the default behavior when short_repeat is set to 0
(when is set to 1 hw will only generate one frame per report since
it only has 4usec to perform the measurement), however the current
code doesn't support that. In case hardware sends multiple frames
back the length check will fail and no frames will be processed. So
the current code doesn't work unless short_repeat is set to 1 or if
the hardware sends a single report per packet for some other reason.
Notice that on ath9k_htc short_repeat is by default set to 0
so that's what happened on my experiments with an AR7010 + AR9280
device, I got lots of data back but no output on the spectral scan.

This patch series adds support for handling multiple FFT frames per
report, performs a few integrity checks on the received data and
in general improves the handling of FFT spectral scans.

Note that this feature generates a LOT of data, each report can be
up to 1K for HT20 and 2K+ for HT20/40. It's meant to be used for
real-time data processing in the userspace. The buffers we currently
have for relayfs won't be able to handle a full report unless they
are being consumed from the userspace fast enough. That's why this
feature is disabled by default (short_repeat is set to 1 by default
also on ath9k_htc).

Now we need someone to write a nice real-time GUI for that...

Many thanks to Adrian Chadd for adding support for FFT spectral
scans in the first place !

Hope you enjoy it ;-)

Nick Kossifidis (11):
 Add a new debug flag for FFT spectral scan
 Fix hanlding of maximum magnitude index
 Move processing of FFT frames to different functions
 Perform integrity checks when processing FFT frames
 Support processing of multiple FFT frames per report
 Skip malformed frames on normal FFT report
 No need for that extra memcpy
 Skip FFT reports if we are out of output buffers
 No need for that extra memset
 Mix the received FFT bins to the random pool
 Enable short repeat by default on ath9k_htc

 drivers/net/wireless/ath/ath.h                   |   2 +
 drivers/net/wireless/ath/ath9k/common-spectral.c | 740 +++++++++++++++++++----
 drivers/net/wireless/ath/ath9k/common-spectral.h |  35 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c    |   2 +-
 4 files changed, 646 insertions(+), 133 deletions(-)

-- 
2.3.5


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 00/11] ath9k: Spectral scan updates
@ 2015-04-29 23:51 ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

On FFT spectral scans the hardware is able to send multiple FFT
frames per report (packet).

This is the default behavior when short_repeat is set to 0
(when is set to 1 hw will only generate one frame per report since
it only has 4usec to perform the measurement), however the current
code doesn't support that. In case hardware sends multiple frames
back the length check will fail and no frames will be processed. So
the current code doesn't work unless short_repeat is set to 1 or if
the hardware sends a single report per packet for some other reason.
Notice that on ath9k_htc short_repeat is by default set to 0
so that's what happened on my experiments with an AR7010 + AR9280
device, I got lots of data back but no output on the spectral scan.

This patch series adds support for handling multiple FFT frames per
report, performs a few integrity checks on the received data and
in general improves the handling of FFT spectral scans.

Note that this feature generates a LOT of data, each report can be
up to 1K for HT20 and 2K+ for HT20/40. It's meant to be used for
real-time data processing in the userspace. The buffers we currently
have for relayfs won't be able to handle a full report unless they
are being consumed from the userspace fast enough. That's why this
feature is disabled by default (short_repeat is set to 1 by default
also on ath9k_htc).

Now we need someone to write a nice real-time GUI for that...

Many thanks to Adrian Chadd for adding support for FFT spectral
scans in the first place !

Hope you enjoy it ;-)

Nick Kossifidis (11):
 Add a new debug flag for FFT spectral scan
 Fix hanlding of maximum magnitude index
 Move processing of FFT frames to different functions
 Perform integrity checks when processing FFT frames
 Support processing of multiple FFT frames per report
 Skip malformed frames on normal FFT report
 No need for that extra memcpy
 Skip FFT reports if we are out of output buffers
 No need for that extra memset
 Mix the received FFT bins to the random pool
 Enable short repeat by default on ath9k_htc

 drivers/net/wireless/ath/ath.h                   |   2 +
 drivers/net/wireless/ath/ath9k/common-spectral.c | 740 +++++++++++++++++++----
 drivers/net/wireless/ath/ath9k/common-spectral.h |  35 +-
 drivers/net/wireless/ath/ath9k/htc_drv_init.c    |   2 +-
 4 files changed, 646 insertions(+), 133 deletions(-)

-- 
2.3.5

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 01/11] ath9k: Add a new debug flag for FFT spectral scan
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

FFT spectral scan is a functionality that makes sense to have its own
debug flag.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 7e94810..65ef483 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -251,6 +251,7 @@ void ath_printk(const char *level, const struct ath_common *common,
  * @ATH_DBG_DFS: radar datection
  * @ATH_DBG_WOW: Wake on Wireless
  * @ATH_DBG_DYNACK: dynack handling
+ * @ATH_DBG_SPECTRAL_SCAN: FFT spectral scan
  * @ATH_DBG_ANY: enable all debugging
  *
  * The debug level is used to control the amount and type of debugging output
@@ -280,6 +281,7 @@ enum ATH_DEBUG {
 	ATH_DBG_WOW		= 0x00020000,
 	ATH_DBG_CHAN_CTX	= 0x00040000,
 	ATH_DBG_DYNACK		= 0x00080000,
+	ATH_DBG_SPECTRAL_SCAN	= 0x00100000,
 	ATH_DBG_ANY		= 0xffffffff
 };
 
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 01/11] ath9k: Add a new debug flag for FFT spectral scan
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

FFT spectral scan is a functionality that makes sense to have its own
debug flag.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 7e94810..65ef483 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -251,6 +251,7 @@ void ath_printk(const char *level, const struct ath_common *common,
  * @ATH_DBG_DFS: radar datection
  * @ATH_DBG_WOW: Wake on Wireless
  * @ATH_DBG_DYNACK: dynack handling
+ * @ATH_DBG_SPECTRAL_SCAN: FFT spectral scan
  * @ATH_DBG_ANY: enable all debugging
  *
  * The debug level is used to control the amount and type of debugging output
@@ -280,6 +281,7 @@ enum ATH_DEBUG {
 	ATH_DBG_WOW		= 0x00020000,
 	ATH_DBG_CHAN_CTX	= 0x00040000,
 	ATH_DBG_DYNACK		= 0x00080000,
+	ATH_DBG_SPECTRAL_SCAN	= 0x00100000,
 	ATH_DBG_ANY		= 0xffffffff
 };
 
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 02/11] ath9k: Fix hanlding of maximum magnitude index
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

Maximum magnitude index is a 5bit signed integer,
convert to an 8bit signed integer and then "shift" it so that it can be used
as an array index. Note that the current implementation adds +1 to the index
value (so it can't be used as an array index) and it's only valid for HT20
channels.

Note that the maximum magnitude index is not being used by
the userspace tools that parse FFT samples (they just use
maximum magnitude) so this doesn't break userspace compatibility.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c |  9 +++++---
 drivers/net/wireless/ath/ath9k/common-spectral.h | 29 ++++++++++++++++++------
 2 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 5cee231..8752634 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -160,8 +160,10 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 		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);
+		lower_max_index = spectral_max_index(mag_info->lower_bins,
+								num_bins);
+		upper_max_index = spectral_max_index(mag_info->upper_bins,
+								num_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);
@@ -189,7 +191,8 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 		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);
+		max_index = spectral_max_index(mag_info->all_bins,
+							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;
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h
index d45dc83..75e24da 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.h
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.h
@@ -117,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 */
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 02/11] ath9k: Fix hanlding of maximum magnitude index
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

Maximum magnitude index is a 5bit signed integer,
convert to an 8bit signed integer and then "shift" it so that it can be used
as an array index. Note that the current implementation adds +1 to the index
value (so it can't be used as an array index) and it's only valid for HT20
channels.

Note that the maximum magnitude index is not being used by
the userspace tools that parse FFT samples (they just use
maximum magnitude) so this doesn't break userspace compatibility.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c |  9 +++++---
 drivers/net/wireless/ath/ath9k/common-spectral.h | 29 ++++++++++++++++++------
 2 files changed, 28 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 5cee231..8752634 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -160,8 +160,10 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 		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);
+		lower_max_index = spectral_max_index(mag_info->lower_bins,
+								num_bins);
+		upper_max_index = spectral_max_index(mag_info->upper_bins,
+								num_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);
@@ -189,7 +191,8 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 		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);
+		max_index = spectral_max_index(mag_info->all_bins,
+							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;
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h
index d45dc83..75e24da 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.h
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.h
@@ -117,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 */
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 03/11] ath9k: Move processing of FFT frames to different functions
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

Since more checks and fixes will be added later and ath_cmn_process_fft is
already big enough.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 276 ++++++++++++++---------
 drivers/net/wireless/ath/ath9k/common-spectral.h |   6 +
 2 files changed, 171 insertions(+), 111 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 8752634..007edb4 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -36,21 +36,165 @@ 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_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_hw *ah = spec_priv->ah;
+	struct ath_ht20_mag_info *mag_info;
+	struct fft_sample_tlv *tlv;
+	int dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
+	u16 magnitude, length;
+	u8 max_index, bitmap_w;
+
+	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;
+
+	fft_sample_20.max_exp = mag_info->max_exp & 0xf;
+
+	fft_sample_20.tsf = __cpu_to_be64(tsf);
+
+	memcpy(fft_sample_20.data, sample_buf, SPECTRAL_HT20_NUM_BINS);
+
+	/* 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;
+
+	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_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;
+	s16 ext_nf;
+	u16 lower_mag, upper_mag, length;
+	s8 lower_rssi, upper_rssi;
+	u8 lower_max_index, upper_max_index;
+	u8 lower_bitmap_w, upper_bitmap_w;
+
+	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;
+
+	fft_sample_40.max_exp = mag_info->max_exp & 0xf;
+
+	fft_sample_40.tsf = __cpu_to_be64(tsf);
+
+	memcpy(fft_sample_40.data, sample_buf, SPECTRAL_HT20_40_NUM_BINS);
+
+	/* 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;
+
+	tlv = (struct fft_sample_tlv *)&fft_sample_40;
+
+	ath_debug_send_fft_sample(spec_priv, tlv);
+
+	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;
+	u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq;
 	enum nl80211_channel_type chan_type;
+	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
@@ -72,12 +216,14 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 	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_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;
+		fft_handler = &ath_cmn_process_ht20_fft;
 	}
 
 	/* Variation in the data length is possible and will be fixed later */
@@ -87,123 +233,31 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 	switch (len - fft_len) {
 	case 0:
 		/* length correct, nothing to do. */
-		memcpy(bins, vdata, num_bins);
+		memcpy(sample_buf, vdata, sample_len);
 		break;
 	case -1:
 		/* first byte missing, duplicate it. */
-		memcpy(&bins[1], vdata, num_bins - 1);
-		bins[0] = vdata[0];
+		memcpy(&sample_buf[1], vdata, sample_len - 1);
+		sample_buf[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);
+		memcpy(sample_buf, vdata, 30);
+		sample_buf[30] = vdata[31];
+		memcpy(&sample_buf[31], &vdata[33], sample_len - 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);
+		sample_buf[0] = vdata[0];
+		memcpy(&sample_buf[1], vdata, 30);
+		sample_buf[31] = vdata[31];
+		memcpy(&sample_buf[32], &vdata[33], sample_len - 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,
-								num_bins);
-		upper_max_index = spectral_max_index(mag_info->upper_bins,
-								num_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,
-							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;
-		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(spec_priv, tlv);
+	fft_handler(rs, spec_priv, sample_buf, tsf, freq, chan_type);
 
 	return 1;
 }
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h
index 072ff76..998743b 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)
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 03/11] ath9k: Move processing of FFT frames to different functions
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

Since more checks and fixes will be added later and ath_cmn_process_fft is
already big enough.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 276 ++++++++++++++---------
 drivers/net/wireless/ath/ath9k/common-spectral.h |   6 +
 2 files changed, 171 insertions(+), 111 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 8752634..007edb4 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -36,21 +36,165 @@ 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_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_hw *ah = spec_priv->ah;
+	struct ath_ht20_mag_info *mag_info;
+	struct fft_sample_tlv *tlv;
+	int dc_pos = SPECTRAL_HT20_NUM_BINS / 2;
+	u16 magnitude, length;
+	u8 max_index, bitmap_w;
+
+	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;
+
+	fft_sample_20.max_exp = mag_info->max_exp & 0xf;
+
+	fft_sample_20.tsf = __cpu_to_be64(tsf);
+
+	memcpy(fft_sample_20.data, sample_buf, SPECTRAL_HT20_NUM_BINS);
+
+	/* 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;
+
+	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_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;
+	s16 ext_nf;
+	u16 lower_mag, upper_mag, length;
+	s8 lower_rssi, upper_rssi;
+	u8 lower_max_index, upper_max_index;
+	u8 lower_bitmap_w, upper_bitmap_w;
+
+	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;
+
+	fft_sample_40.max_exp = mag_info->max_exp & 0xf;
+
+	fft_sample_40.tsf = __cpu_to_be64(tsf);
+
+	memcpy(fft_sample_40.data, sample_buf, SPECTRAL_HT20_40_NUM_BINS);
+
+	/* 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;
+
+	tlv = (struct fft_sample_tlv *)&fft_sample_40;
+
+	ath_debug_send_fft_sample(spec_priv, tlv);
+
+	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;
+	u16 fft_len, sample_len, freq = ah->curchan->chan->center_freq;
 	enum nl80211_channel_type chan_type;
+	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
@@ -72,12 +216,14 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 	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_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;
+		fft_handler = &ath_cmn_process_ht20_fft;
 	}
 
 	/* Variation in the data length is possible and will be fixed later */
@@ -87,123 +233,31 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 	switch (len - fft_len) {
 	case 0:
 		/* length correct, nothing to do. */
-		memcpy(bins, vdata, num_bins);
+		memcpy(sample_buf, vdata, sample_len);
 		break;
 	case -1:
 		/* first byte missing, duplicate it. */
-		memcpy(&bins[1], vdata, num_bins - 1);
-		bins[0] = vdata[0];
+		memcpy(&sample_buf[1], vdata, sample_len - 1);
+		sample_buf[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);
+		memcpy(sample_buf, vdata, 30);
+		sample_buf[30] = vdata[31];
+		memcpy(&sample_buf[31], &vdata[33], sample_len - 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);
+		sample_buf[0] = vdata[0];
+		memcpy(&sample_buf[1], vdata, 30);
+		sample_buf[31] = vdata[31];
+		memcpy(&sample_buf[32], &vdata[33], sample_len - 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,
-								num_bins);
-		upper_max_index = spectral_max_index(mag_info->upper_bins,
-								num_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,
-							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;
-		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(spec_priv, tlv);
+	fft_handler(rs, spec_priv, sample_buf, tsf, freq, chan_type);
 
 	return 1;
 }
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.h b/drivers/net/wireless/ath/ath9k/common-spectral.h
index 072ff76..998743b 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)
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 04/11] ath9k: Perform integrity checks when processing FFT frames
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

a) Check that the maximum magnitude is at the specified index

b) Check if the maximum magnitude index is at dc_pos and if so
calculate a new one (value at dc_pos is invalid)

c) Check if the specified maximum magnitude is indeed the maximum

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 169 ++++++++++++++++++++++-
 1 file changed, 163 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 007edb4..12db498 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -47,12 +47,15 @@ ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
 			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, length;
-	u8 max_index, bitmap_w;
+	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;
@@ -74,18 +77,66 @@ ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
 	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;
+	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);
@@ -100,16 +151,19 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
 			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, length;
+	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;
+	u8 lower_bitmap_w, upper_bitmap_w, max_exp;
 
 	if (caldata)
 		ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
@@ -163,18 +217,121 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
 	upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
 	fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
 
-	fft_sample_40.max_exp = mag_info->max_exp & 0xf;
+	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);
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 04/11] ath9k: Perform integrity checks when processing FFT frames
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

a) Check that the maximum magnitude is at the specified index

b) Check if the maximum magnitude index is at dc_pos and if so
calculate a new one (value at dc_pos is invalid)

c) Check if the specified maximum magnitude is indeed the maximum

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 169 ++++++++++++++++++++++-
 1 file changed, 163 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 007edb4..12db498 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -47,12 +47,15 @@ ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
 			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, length;
-	u8 max_index, bitmap_w;
+	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;
@@ -74,18 +77,66 @@ ath_cmn_process_ht20_fft(struct ath_rx_status *rs,
 	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;
+	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@%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);
@@ -100,16 +151,19 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
 			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, length;
+	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;
+	u8 lower_bitmap_w, upper_bitmap_w, max_exp;
 
 	if (caldata)
 		ext_nf = ath9k_hw_getchan_noise(ah, ah->curchan,
@@ -163,18 +217,121 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
 	upper_bitmap_w = spectral_bitmap_weight(mag_info->upper_bins);
 	fft_sample_40.upper_bitmap_weight = upper_bitmap_w;
 
-	fft_sample_40.max_exp = mag_info->max_exp & 0xf;
+	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@%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@%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);
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 05/11] ath9k: Support processing of multiple FFT frames per report.
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

Since we can identify the FFT frames on the report by checking the
consistency of their magnitude info, we can process all of them,
even when some of them are corrupted.

This patch introduces two functions to quickly verify the integrity
of the mag_info fields and some further tweaks to detect the frames
in the report and process them.

Note that in case of missing bytes we don't duplicate them, instead
we leave them as zeroes. This way we get less noise on the FFT plot.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 267 ++++++++++++++++++++---
 1 file changed, 237 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 12db498..51ab396 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -36,6 +36,104 @@ 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);
@@ -349,8 +447,14 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 	u8 num_bins, *vdata = (u8 *)hdr;
 	struct ath_radar_info *radar_info;
 	int len = rs->rs_datalen;
+	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
@@ -375,47 +479,150 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 		fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
 		sample_len = SPECTRAL_HT20_40_SAMPLE_LEN;
 		num_bins = SPECTRAL_HT20_40_NUM_BINS;
+		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;
+		fft_idx_validator = ath_cmn_max_idx_verify_ht20_fft;
 		fft_handler = &ath_cmn_process_ht20_fft;
 	}
 
-	/* Variation in the data length is possible and will be fixed later */
-	if ((len > fft_len + 2) || (len < fft_len - 1))
-		return 1;
+	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;
+		}
 
-	switch (len - fft_len) {
-	case 0:
-		/* length correct, nothing to do. */
-		memcpy(sample_buf, vdata, sample_len);
-		break;
-	case -1:
-		/* first byte missing, duplicate it. */
-		memcpy(&sample_buf[1], vdata, sample_len - 1);
-		sample_buf[0] = vdata[0];
-		break;
-	case 2:
-		/* MAC added 2 extra bytes at bin 30 and 32, remove them. */
-		memcpy(sample_buf, vdata, 30);
-		sample_buf[30] = vdata[31];
-		memcpy(&sample_buf[31], &vdata[33], sample_len - 31);
-		break;
-	case 1:
-		/* MAC added 2 extra bytes AND first byte is missing. */
-		sample_buf[0] = vdata[0];
-		memcpy(&sample_buf[1], vdata, 30);
-		sample_buf[31] = vdata[31];
-		memcpy(&sample_buf[32], &vdata[33], sample_len - 32);
-		break;
-	default:
-		return 1;
-	}
+		/* 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;
+			}
 
-	fft_handler(rs, spec_priv, sample_buf, tsf, freq, chan_type);
+			/* 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;
+		}
+
+		if (got_slen) {
+			ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
+				sample_bytes);
+			switch (sample_bytes - sample_len) {
+			case -1:
+				/* First byte missing */
+				memcpy(&sample_buf[1], sample_start,
+				       sample_len - 1);
+				break;
+			case 0:
+				/* Length correct, nothing to do. */
+				memcpy(sample_buf, sample_start, sample_len);
+				break;
+			case 1:
+				/* MAC added 2 extra bytes AND first byte
+				 * is missing.
+				 */
+				memcpy(&sample_buf[1], sample_start, 30);
+				sample_buf[31] = sample_start[31];
+				memcpy(&sample_buf[32], &sample_start[33],
+				       sample_len - 32);
+				break;
+			case 2:
+				/* MAC added 2 extra bytes at bin 30 and 32,
+				 * remove them.
+				 */
+				memcpy(sample_buf, sample_start, 30);
+				sample_buf[30] = sample_start[31];
+				memcpy(&sample_buf[31], &sample_start[33],
+				       sample_len - 31);
+				break;
+			default:
+				break;
+			}
+
+			ret = fft_handler(rs, spec_priv, sample_buf, tsf,
+							freq, chan_type);
+			memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
+			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;
+		}
+	}
 
+	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);
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 05/11] ath9k: Support processing of multiple FFT frames per report.
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

Since we can identify the FFT frames on the report by checking the
consistency of their magnitude info, we can process all of them,
even when some of them are corrupted.

This patch introduces two functions to quickly verify the integrity
of the mag_info fields and some further tweaks to detect the frames
in the report and process them.

Note that in case of missing bytes we don't duplicate them, instead
we leave them as zeroes. This way we get less noise on the FFT plot.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 267 ++++++++++++++++++++---
 1 file changed, 237 insertions(+), 30 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 12db498..51ab396 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -36,6 +36,104 @@ 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);
@@ -349,8 +447,14 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 	u8 num_bins, *vdata = (u8 *)hdr;
 	struct ath_radar_info *radar_info;
 	int len = rs->rs_datalen;
+	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
@@ -375,47 +479,150 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 		fft_len = SPECTRAL_HT20_40_TOTAL_DATA_LEN;
 		sample_len = SPECTRAL_HT20_40_SAMPLE_LEN;
 		num_bins = SPECTRAL_HT20_40_NUM_BINS;
+		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;
+		fft_idx_validator = ath_cmn_max_idx_verify_ht20_fft;
 		fft_handler = &ath_cmn_process_ht20_fft;
 	}
 
-	/* Variation in the data length is possible and will be fixed later */
-	if ((len > fft_len + 2) || (len < fft_len - 1))
-		return 1;
+	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;
+		}
 
-	switch (len - fft_len) {
-	case 0:
-		/* length correct, nothing to do. */
-		memcpy(sample_buf, vdata, sample_len);
-		break;
-	case -1:
-		/* first byte missing, duplicate it. */
-		memcpy(&sample_buf[1], vdata, sample_len - 1);
-		sample_buf[0] = vdata[0];
-		break;
-	case 2:
-		/* MAC added 2 extra bytes@bin 30 and 32, remove them. */
-		memcpy(sample_buf, vdata, 30);
-		sample_buf[30] = vdata[31];
-		memcpy(&sample_buf[31], &vdata[33], sample_len - 31);
-		break;
-	case 1:
-		/* MAC added 2 extra bytes AND first byte is missing. */
-		sample_buf[0] = vdata[0];
-		memcpy(&sample_buf[1], vdata, 30);
-		sample_buf[31] = vdata[31];
-		memcpy(&sample_buf[32], &vdata[33], sample_len - 32);
-		break;
-	default:
-		return 1;
-	}
+		/* 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;
+			}
 
-	fft_handler(rs, spec_priv, sample_buf, tsf, freq, chan_type);
+			/* 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;
+		}
+
+		if (got_slen) {
+			ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
+				sample_bytes);
+			switch (sample_bytes - sample_len) {
+			case -1:
+				/* First byte missing */
+				memcpy(&sample_buf[1], sample_start,
+				       sample_len - 1);
+				break;
+			case 0:
+				/* Length correct, nothing to do. */
+				memcpy(sample_buf, sample_start, sample_len);
+				break;
+			case 1:
+				/* MAC added 2 extra bytes AND first byte
+				 * is missing.
+				 */
+				memcpy(&sample_buf[1], sample_start, 30);
+				sample_buf[31] = sample_start[31];
+				memcpy(&sample_buf[32], &sample_start[33],
+				       sample_len - 32);
+				break;
+			case 2:
+				/* MAC added 2 extra bytes@bin 30 and 32,
+				 * remove them.
+				 */
+				memcpy(sample_buf, sample_start, 30);
+				sample_buf[30] = sample_start[31];
+				memcpy(&sample_buf[31], &sample_start[33],
+				       sample_len - 31);
+				break;
+			default:
+				break;
+			}
+
+			ret = fft_handler(rs, spec_priv, sample_buf, tsf,
+							freq, chan_type);
+			memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
+			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;
+		}
+	}
 
+	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);
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 06/11] ath9k: Skip malformed frames on normal FFT report
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

Since we have lots of frames on a normal FFT report don't bother
processing the malformed ones. Only try to fix malformed frames
in case of a short FFT report (only a single frame on the report).

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 94 ++++++++++++++++--------
 1 file changed, 62 insertions(+), 32 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 51ab396..0c9bc9e 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -437,6 +437,42 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
 	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;
+	}
+}
+
 /* 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)
@@ -570,46 +606,40 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 		if (got_slen) {
 			ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
 				sample_bytes);
-			switch (sample_bytes - sample_len) {
-			case -1:
-				/* First byte missing */
-				memcpy(&sample_buf[1], sample_start,
-				       sample_len - 1);
-				break;
-			case 0:
-				/* Length correct, nothing to do. */
+
+			/* 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);
+			}
+
+			/* Process a normal frame */
+			if (sample_bytes == sample_len) {
 				memcpy(sample_buf, sample_start, sample_len);
-				break;
-			case 1:
-				/* MAC added 2 extra bytes AND first byte
-				 * is missing.
-				 */
-				memcpy(&sample_buf[1], sample_start, 30);
-				sample_buf[31] = sample_start[31];
-				memcpy(&sample_buf[32], &sample_start[33],
-				       sample_len - 32);
-				break;
-			case 2:
-				/* MAC added 2 extra bytes at bin 30 and 32,
-				 * remove them.
-				 */
-				memcpy(sample_buf, sample_start, 30);
-				sample_buf[30] = sample_start[31];
-				memcpy(&sample_buf[31], &sample_start[33],
-				       sample_len - 31);
-				break;
-			default:
-				break;
+				ret = fft_handler(rs, spec_priv, sample_buf,
+						  tsf, freq, chan_type);
 			}
 
-			ret = fft_handler(rs, spec_priv, sample_buf, tsf,
-							freq, chan_type);
+			/* Short report processed, break out of the
+			 * loop.
+			 */
+			if (len <= fft_len + 2)
+				break;
+
 			memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
 			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. */
+			 * by byte instead.
+			 */
 			if (ret == 0) {
 				i += num_bins - 2;
 				sample_bytes = num_bins - 2;
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 06/11] ath9k: Skip malformed frames on normal FFT report
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

Since we have lots of frames on a normal FFT report don't bother
processing the malformed ones. Only try to fix malformed frames
in case of a short FFT report (only a single frame on the report).

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 94 ++++++++++++++++--------
 1 file changed, 62 insertions(+), 32 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 51ab396..0c9bc9e 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -437,6 +437,42 @@ ath_cmn_process_ht20_40_fft(struct ath_rx_status *rs,
 	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;
+	}
+}
+
 /* 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)
@@ -570,46 +606,40 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 		if (got_slen) {
 			ath_dbg(common, SPECTRAL_SCAN, "FFT frame len: %i\n",
 				sample_bytes);
-			switch (sample_bytes - sample_len) {
-			case -1:
-				/* First byte missing */
-				memcpy(&sample_buf[1], sample_start,
-				       sample_len - 1);
-				break;
-			case 0:
-				/* Length correct, nothing to do. */
+
+			/* 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);
+			}
+
+			/* Process a normal frame */
+			if (sample_bytes == sample_len) {
 				memcpy(sample_buf, sample_start, sample_len);
-				break;
-			case 1:
-				/* MAC added 2 extra bytes AND first byte
-				 * is missing.
-				 */
-				memcpy(&sample_buf[1], sample_start, 30);
-				sample_buf[31] = sample_start[31];
-				memcpy(&sample_buf[32], &sample_start[33],
-				       sample_len - 32);
-				break;
-			case 2:
-				/* MAC added 2 extra bytes@bin 30 and 32,
-				 * remove them.
-				 */
-				memcpy(sample_buf, sample_start, 30);
-				sample_buf[30] = sample_start[31];
-				memcpy(&sample_buf[31], &sample_start[33],
-				       sample_len - 31);
-				break;
-			default:
-				break;
+				ret = fft_handler(rs, spec_priv, sample_buf,
+						  tsf, freq, chan_type);
 			}
 
-			ret = fft_handler(rs, spec_priv, sample_buf, tsf,
-							freq, chan_type);
+			/* Short report processed, break out of the
+			 * loop.
+			 */
+			if (len <= fft_len + 2)
+				break;
+
 			memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
 			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. */
+			 * by byte instead.
+			 */
 			if (ret == 0) {
 				i += num_bins - 2;
 				sample_bytes = num_bins - 2;
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 07/11] ath9k: No need for that extra memcpy
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

No need to copy the frame to the temporary buffer when its length
is ok.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 0c9bc9e..b8682bc 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -620,11 +620,9 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 			}
 
 			/* Process a normal frame */
-			if (sample_bytes == sample_len) {
-				memcpy(sample_buf, sample_start, sample_len);
-				ret = fft_handler(rs, spec_priv, sample_buf,
+			if (sample_bytes == sample_len)
+				ret = fft_handler(rs, spec_priv, sample_start,
 						  tsf, freq, chan_type);
-			}
 
 			/* Short report processed, break out of the
 			 * loop.
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 07/11] ath9k: No need for that extra memcpy
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

No need to copy the frame to the temporary buffer when its length
is ok.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 0c9bc9e..b8682bc 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -620,11 +620,9 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 			}
 
 			/* Process a normal frame */
-			if (sample_bytes == sample_len) {
-				memcpy(sample_buf, sample_start, sample_len);
-				ret = fft_handler(rs, spec_priv, sample_buf,
+			if (sample_bytes == sample_len)
+				ret = fft_handler(rs, spec_priv, sample_start,
 						  tsf, freq, chan_type);
-			}
 
 			/* Short report processed, break out of the
 			 * loop.
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 8/11] ath9k: Skip FFT reports if we are out of output buffers
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

There is no reason to keep processing FFT reports if there is no
space left on the relayfs buffers for the results. This saves
lots of CPU cycles, especially on normal (non-short) reports.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 28 ++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index b8682bc..4ab08ed 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -473,6 +473,24 @@ ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes)
 	}
 }
 
+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)
@@ -509,6 +527,16 @@ 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)) {
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 8/11] ath9k: Skip FFT reports if we are out of output buffers
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

There is no reason to keep processing FFT reports if there is no
space left on the relayfs buffers for the results. This saves
lots of CPU cycles, especially on normal (non-short) reports.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 28 ++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index b8682bc..4ab08ed 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -473,6 +473,24 @@ ath_cmn_copy_fft_frame(u8 *in, u8 *out, int sample_len, int sample_bytes)
 	}
 }
 
+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)
@@ -509,6 +527,16 @@ 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)) {
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 9/11] ath9k: No need for that extra memset
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

Temp buffer is only used for fixing malformed frames, there is no
need to memset it every time.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 4ab08ed..5840b37 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -645,6 +645,8 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 
 				fft_handler(rs, spec_priv, sample_buf,
 					    tsf, freq, chan_type);
+
+				memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
 			}
 
 			/* Process a normal frame */
@@ -658,7 +660,6 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 			if (len <= fft_len + 2)
 				break;
 
-			memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
 			sample_start = &vdata[i + 1];
 
 			/* -1 to grab sample_len -1, -2 since
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 9/11] ath9k: No need for that extra memset
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

Temp buffer is only used for fixing malformed frames, there is no
need to memset it every time.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 4ab08ed..5840b37 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -645,6 +645,8 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 
 				fft_handler(rs, spec_priv, sample_buf,
 					    tsf, freq, chan_type);
+
+				memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
 			}
 
 			/* Process a normal frame */
@@ -658,7 +660,6 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 			if (len <= fft_len + 2)
 				break;
 
-			memset(sample_buf, 0, SPECTRAL_SAMPLE_MAX_LEN);
 			sample_start = &vdata[i + 1];
 
 			/* -1 to grab sample_len -1, -2 since
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 10/11] ath9k: Mix the received FFT bins to the random pool
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

E/M noise is a pretty good source of entropy so we mix the FFT
measurements of the E/M spectrum to /dev/random pool. Note that
this doesn't increase the pool's entropy count but it still helps
on improving the output of /dev/(u)random.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 5840b37..a876271 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)
@@ -647,13 +648,24 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 					    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)
+			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.
 			 */
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 10/11] ath9k: Mix the received FFT bins to the random pool
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

E/M noise is a pretty good source of entropy so we mix the FFT
measurements of the E/M spectrum to /dev/random pool. Note that
this doesn't increase the pool's entropy count but it still helps
on improving the output of /dev/(u)random.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/common-spectral.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index 5840b37..a876271 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)
@@ -647,13 +648,24 @@ int ath_cmn_process_fft(struct ath_spec_scan_priv *spec_priv, struct ieee80211_h
 					    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)
+			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.
 			 */
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 11/11] ath9k: Enable short repeat by default on ath9k_htc
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-04-29 23:51   ` Nick Kossifidis
  -1 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: kvalo, ath9k-devel
  Cc: linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis

Normal FFT reports generate a LOT of data, to save resources
enable short repeat by default also on ath9k_htc (it's already
enabled by default on ath9k). This can always be changed from
userspace if needed.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index d7beefe..7468562 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;
-- 
2.3.5


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 11/11] ath9k: Enable short repeat by default on ath9k_htc
@ 2015-04-29 23:51   ` Nick Kossifidis
  0 siblings, 0 replies; 28+ messages in thread
From: Nick Kossifidis @ 2015-04-29 23:51 UTC (permalink / raw)
  To: ath9k-devel

Normal FFT reports generate a LOT of data, to save resources
enable short repeat by default also on ath9k_htc (it's already
enabled by default on ath9k). This can always be changed from
userspace if needed.

Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>
---
 drivers/net/wireless/ath/ath9k/htc_drv_init.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index d7beefe..7468562 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;
-- 
2.3.5

^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 00/11] ath9k: Spectral scan updates
  2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
@ 2015-05-01 12:46   ` Bob Copeland
  -1 siblings, 0 replies; 28+ messages in thread
From: Bob Copeland @ 2015-05-01 12:46 UTC (permalink / raw)
  To: Nick Kossifidis
  Cc: kvalo, ath9k-devel, linux-wireless, ath9k-devel, adrian.chadd

On Wed, Apr 29, 2015 at 11:51:11PM +0000, Nick Kossifidis wrote:
> Now we need someone to write a nice real-time GUI for that...

This fails on the "nice" front, but as a starting point for something
"real-time" I hacked up this thing a while ago (most of the existing
tools I found for this were offline post-processors):

https://github.com/bcopeland/speccy

The visualization is basically garbage so complete rewrites welcome :)

I'll give your patches on my ath9k_htc device.

-- 
Bob Copeland %% http://bobcopeland.com/

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ath9k-devel] [PATCH 00/11] ath9k: Spectral scan updates
@ 2015-05-01 12:46   ` Bob Copeland
  0 siblings, 0 replies; 28+ messages in thread
From: Bob Copeland @ 2015-05-01 12:46 UTC (permalink / raw)
  To: ath9k-devel

On Wed, Apr 29, 2015 at 11:51:11PM +0000, Nick Kossifidis wrote:
> Now we need someone to write a nice real-time GUI for that...

This fails on the "nice" front, but as a starting point for something
"real-time" I hacked up this thing a while ago (most of the existing
tools I found for this were offline post-processors):

https://github.com/bcopeland/speccy

The visualization is basically garbage so complete rewrites welcome :)

I'll give your patches on my ath9k_htc device.

-- 
Bob Copeland %% http://bobcopeland.com/

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [01/11] ath9k: Add a new debug flag for FFT spectral scan
  2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
@ 2015-05-09 13:47     ` Kalle Valo
  -1 siblings, 0 replies; 28+ messages in thread
From: Kalle Valo @ 2015-05-09 13:47 UTC (permalink / raw)
  To: Nick Kossifidis
  Cc: ath9k-devel, linux-wireless, ath9k-devel, adrian.chadd, Nick Kossifidis


> FFT spectral scan is a functionality that makes sense to have its own
> debug flag.
> 
> Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>

Thanks, 11 patches applied to wireless-drivers-next.git:

04a81e183d50 ath9k: Add a new debug flag for FFT spectral scan
e33f855d4368 ath9k: Fix hanlding of maximum magnitude index
58b5e4c731b5 ath9k: Move processing of FFT frames to different functions
7fa580c19349 ath9k: Perform integrity checks when processing FFT frames
72dd2cdaade6 ath9k: Support processing of multiple FFT frames per report.
0f2c75de6422 ath9k: Skip malformed frames on normal FFT report
9acc98b9ecf9 ath9k: No need for that extra memcpy
6b8f85a91883 ath9k: Skip FFT reports if we are out of output buffers
3ea2ce3f7e63 ath9k: No need for that extra memset
2aa56cca3571 ath9k: Mix the received FFT bins to the random pool
a534f3b60cac ath9k: Enable short repeat by default on ath9k_htc

Kalle Valo

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [ath9k-devel] [01/11] ath9k: Add a new debug flag for FFT spectral scan
@ 2015-05-09 13:47     ` Kalle Valo
  0 siblings, 0 replies; 28+ messages in thread
From: Kalle Valo @ 2015-05-09 13:47 UTC (permalink / raw)
  To: ath9k-devel


> FFT spectral scan is a functionality that makes sense to have its own
> debug flag.
> 
> Signed-off-by: Nick Kossifidis <mickflemm@gmail.com>

Thanks, 11 patches applied to wireless-drivers-next.git:

04a81e183d50 ath9k: Add a new debug flag for FFT spectral scan
e33f855d4368 ath9k: Fix hanlding of maximum magnitude index
58b5e4c731b5 ath9k: Move processing of FFT frames to different functions
7fa580c19349 ath9k: Perform integrity checks when processing FFT frames
72dd2cdaade6 ath9k: Support processing of multiple FFT frames per report.
0f2c75de6422 ath9k: Skip malformed frames on normal FFT report
9acc98b9ecf9 ath9k: No need for that extra memcpy
6b8f85a91883 ath9k: Skip FFT reports if we are out of output buffers
3ea2ce3f7e63 ath9k: No need for that extra memset
2aa56cca3571 ath9k: Mix the received FFT bins to the random pool
a534f3b60cac ath9k: Enable short repeat by default on ath9k_htc

Kalle Valo

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2015-05-09 13:47 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-29 23:51 [PATCH 00/11] ath9k: Spectral scan updates Nick Kossifidis
2015-04-29 23:51 ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 01/11] ath9k: Add a new debug flag for FFT spectral scan Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-05-09 13:47   ` [01/11] " Kalle Valo
2015-05-09 13:47     ` [ath9k-devel] " Kalle Valo
2015-04-29 23:51 ` [PATCH 02/11] ath9k: Fix hanlding of maximum magnitude index Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 03/11] ath9k: Move processing of FFT frames to different functions Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 04/11] ath9k: Perform integrity checks when processing FFT frames Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 05/11] ath9k: Support processing of multiple FFT frames per report Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 06/11] ath9k: Skip malformed frames on normal FFT report Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 07/11] ath9k: No need for that extra memcpy Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 8/11] ath9k: Skip FFT reports if we are out of output buffers Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 9/11] ath9k: No need for that extra memset Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 10/11] ath9k: Mix the received FFT bins to the random pool Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-04-29 23:51 ` [PATCH 11/11] ath9k: Enable short repeat by default on ath9k_htc Nick Kossifidis
2015-04-29 23:51   ` [ath9k-devel] " Nick Kossifidis
2015-05-01 12:46 ` [PATCH 00/11] ath9k: Spectral scan updates Bob Copeland
2015-05-01 12:46   ` [ath9k-devel] " Bob Copeland

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.