[RFC 2/2] ath10k: add spectral scan feature

Michal Kazior michal.kazior at tieto.com
Wed Jul 16 02:30:12 PDT 2014


On 15 July 2014 18:32, Simon Wunderlich <sw at simonwunderlich.de> wrote:
> From: Sven Eckelmann <sven at narfation.org>
>
> Adds the spectral scan feature for ath10k. The spectral scan is triggered by
> configuring a mode through a debugfs control file. Samples can be gathered via
> another relay debugfs file.
>
> Essentially, to try it out:
>
> ip link dev wlan0 set up
> echo background > /sys/kernel/debug/ieee80211/phy0/ath10k/spectral_scan_ctl
> iw dev wlan0 scan
> echo disable > /sys/kernel/debug/ieee80211/phy0/ath10k/spectral_scan_ctl
> cat /sys/kernel/debug/ieee80211/phy0/ath10k/spectral_scan0 > samples
>
> This feature is still experimental.
>
> Signed-off-by: Sven Eckelmann <sven at narfation.org>
> Signed-off-by: Simon Wunderlich <sw at simonwunderlich.de>
> Signed-off-by: Mathias Kretschmer <mathias.kretschmer at fokus.fraunhofer.de>
> ---
>  drivers/net/wireless/ath/ath10k/Kconfig    |   1 +
>  drivers/net/wireless/ath/ath10k/Makefile   |   3 +-
>  drivers/net/wireless/ath/ath10k/core.h     |   6 +
>  drivers/net/wireless/ath/ath10k/debug.c    |   3 +
>  drivers/net/wireless/ath/ath10k/spectral.c | 368 +++++++++++++++++++++++++++++
>  drivers/net/wireless/ath/ath10k/spectral.h |  66 ++++++
>  drivers/net/wireless/ath/ath10k/wmi.c      |  98 +++++++-
>  drivers/net/wireless/ath/ath10k/wmi.h      |  80 +++++++
>  drivers/net/wireless/ath/spectral_common.h |  20 ++
>  9 files changed, 643 insertions(+), 2 deletions(-)
>  create mode 100644 drivers/net/wireless/ath/ath10k/spectral.c
>  create mode 100644 drivers/net/wireless/ath/ath10k/spectral.h
>
[...]
> +static void ath_debug_send_fft_sample(struct ath10k *ar,
> +                                     struct fft_sample_tlv *fft_sample_tlv)
> +{

Why ath_debug_... instead of ath10k_debug_.. ?


[...]
> +static int ath_get_spectral_vdevid(struct ath10k *ar)

ath_get_..? Shouldn't this be ath10k_get?


> +{
> +       struct ath10k_vif *arvif;
> +
> +       if (list_empty(&ar->arvifs))
> +               return -ENODEV;
> +
> +       arvif = list_first_entry(&ar->arvifs, typeof(*arvif), list);
> +       return arvif->vdev_id;
> +}

No locks? Access to arvifs must be protected with conf_mutex.

What happens when an interface is removed without spectral scan being stopped?


> +int ath10k_spectral_scan_trigger(struct ath10k *ar)
> +{
> +       int ret;
> +       int vdev_id;
> +
> +       vdev_id = ath_get_spectral_vdevid(ar);
> +       if (vdev_id < 0)
> +               return vdev_id;
> +
> +       if (ar->spectral_mode == SPECTRAL_DISABLED)
> +               return 0;
> +
> +       ret = ath10k_vdev_spectral_enable(ar, vdev_id,
> +                                         WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
> +                                         WMI_SPECTRAL_ENABLE_CMD_ENABLE);
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = ath10k_vdev_spectral_enable(ar, vdev_id,
> +                                         WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
> +                                         WMI_SPECTRAL_ENABLE_CMD_ENABLE);
> +       if (ret < 0)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +int ath10k_spectral_scan_config(struct ath10k *ar, enum spectral_mode mode)
> +{
> +       int count, ret;

We tend to use `res` in ath10k.


> +       struct wmi_vdev_spectral_configure_arg arg;
> +       int vdev_id;
> +
> +       vdev_id = ath_get_spectral_vdevid(ar);
> +       if (vdev_id < 0)
> +               return vdev_id;
> +
> +       ar->spectral_mode = mode;
> +
> +       ath10k_vdev_spectral_enable(ar, vdev_id,
> +                                   WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
> +                                   WMI_SPECTRAL_ENABLE_CMD_DISABLE);
> +       if (mode == SPECTRAL_DISABLED)
> +               return 0;
> +
> +       if (mode == SPECTRAL_BACKGROUND)
> +               count = WMI_SPECTRAL_COUNT_DEFAULT;
> +       else
> +               count = max_t(u8, 1, ar->spec_config.count);
> +
> +       arg.vdev_id              = vdev_id;
> +       arg.scan_count           = count;
> +       arg.scan_period          = WMI_SPECTRAL_PERIOD_DEFAULT;
> +       arg.scan_priority        = WMI_SPECTRAL_PRIORITY_DEFAULT;
> +       arg.scan_fft_size        = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
> +       arg.scan_gc_ena          = WMI_SPECTRAL_GC_ENA_DEFAULT;
> +       arg.scan_restart_ena     = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
> +       arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
> +       arg.scan_init_delay      = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
> +       arg.scan_nb_tone_thr     = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
> +       arg.scan_str_bin_thr     = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
> +       arg.scan_wb_rpt_mode     = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
> +       arg.scan_rssi_rpt_mode   = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
> +       arg.scan_rssi_thr        = WMI_SPECTRAL_RSSI_THR_DEFAULT;
> +       arg.scan_pwr_format      = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
> +       arg.scan_rpt_mode        = WMI_SPECTRAL_RPT_MODE_DEFAULT;
> +       arg.scan_bin_scale       = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
> +       arg.scan_dBm_adj         = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
> +       arg.scan_chn_mask        = WMI_SPECTRAL_CHN_MASK_DEFAULT;
> +
> +       ret = ath10k_vdev_spectral_configure(ar, &arg);
> +       if (ret < 0)

+ ath10k_warn("failed to configure spectral scan: %d\n", ret);


> +               return ret;
> +
> +       if (mode == SPECTRAL_BACKGROUND)
> +               ath10k_spectral_scan_trigger(ar);

Why isn't ath10k_spectral_scan_trigger() return value not checked?
Also +ath10k_warn.


[...]
> diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
> index 6f83cae..7ad9c71 100644
> --- a/drivers/net/wireless/ath/ath10k/wmi.c
> +++ b/drivers/net/wireless/ath/ath10k/wmi.c
> @@ -1659,7 +1659,47 @@ static void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
>                                 struct wmi_single_phyerr_rx_event *event,
>                                 u64 tsf)
>  {
> -       ath10k_dbg(ATH10K_DBG_WMI, "wmi event spectral scan\n");
> +       int buf_len, tlv_len, res, i = 0;
> +       struct phyerr_tlv *tlv;
> +       u8 *tlv_buf;
> +       struct phyerr_fft_report *fftr;
> +       size_t fftr_len;
> +
> +       buf_len = __le32_to_cpu(event->hdr.buf_len);
> +
> +       while (i < buf_len) {
> +               if (i + sizeof(*tlv) > buf_len) {
> +                       ath10k_warn("too short buf for tlv header (%d)\n", i);

"failed to parse phyerr tlv header at byte %d\n", i


> +                       return;
> +               }
> +
> +               tlv = (struct phyerr_tlv *)&event->bufp[i];
> +               tlv_len = __le16_to_cpu(tlv->len);
> +               tlv_buf = &event->bufp[i + sizeof(*tlv)];
> +
> +               if (i + sizeof(*tlv) + tlv_len > buf_len) {
> +                       ath10k_warn("too short buf for tlv (%d)\n", i);

"failed to parse phyerr tlv payload at byte %d\n", i


> +                       return;
> +               }
> +
> +               switch (tlv->tag) {
> +               case PHYERR_TLV_TAG_SEARCH_FFT_REPORT:
> +                       if (sizeof(*fftr) > tlv_len) {
> +                               ath10k_warn("too short fft report (%d)\n", i);

"failed to parse fft report at byte %d\n", i


> +                               return;
> +                       }
> +
> +                       fftr_len = tlv_len - sizeof(*fftr);
> +                       fftr = (struct phyerr_fft_report *)tlv_buf;
> +                       res = ath10k_process_fft(ar, event, fftr, fftr_len,
> +                                                tsf);
> +                       if (res)

+ ath10k_warn("failed to process fft report: %d\n", res)


[...]
> +int ath10k_vdev_spectral_configure(struct ath10k *ar,
> +                             const struct wmi_vdev_spectral_configure_arg *arg)

ath10k_wmi_vdev_spectral_configure


[...]
> +int ath10k_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
> +                               u32 enable)

ath10k_wmi_vdev_spectral_enable


[...]
> +struct wmi_vdev_spectral_configure_arg {
> +       u32 vdev_id;
> +       u32 scan_count;
> +       u32 scan_period;
> +       u32 scan_priority;
> +       u32 scan_fft_size;
> +       u32 scan_gc_ena;
> +       u32 scan_restart_ena;
> +       u32 scan_noise_floor_ref;
> +       u32 scan_init_delay;
> +       u32 scan_nb_tone_thr;
> +       u32 scan_str_bin_thr;
> +       u32 scan_wb_rpt_mode;
> +       u32 scan_rssi_rpt_mode;
> +       u32 scan_rssi_thr;
> +       u32 scan_pwr_format;
> +       u32 scan_rpt_mode;
> +       u32 scan_bin_scale;
> +       u32 scan_dBm_adj;
> +       u32 scan_chn_mask;

Some stuff isn't self-explanatory. I'd love to see some of these
fields documented to account for possible values (wb_rpt_mode?) and
units (init_delay?).


[...]
> +struct fft_sample_ath10k_ht20 {
> +       struct fft_sample_tlv tlv;
> +       u8 mhz;

A more suitable name would be "chan_width_mhz" I guess?


> +       __be16 freq1;
> +       __be16 freq2;
> +       __be16 noise;
> +       __be16 max_magnitude;
> +       __be16 total_gain_db;
> +       __be16 base_pwr_db;
> +       __be64 tsf;
> +       s8 max_index;
> +       u8 rssi;
> +       u8 relpwr_db;
> +       u8 avgpwr_db;
> +
> +       u8 data[SPECTRAL_ATH10K_HT20_NUM_BINS];

And as pointed out the size/count of bins is most likely not
bandwidth-dependant. It's just a matter of resolution configured with
fft_size + bin_scale. Maybe this should be a variable-sized array?


Generally this seems to be missing locking (does debugfs guarantee
serialized read/write calls?).


Michał



More information about the ath10k mailing list