linux/drivers/net/wireless/ath/ath11k/spectral.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause-Clear
   2/*
   3 * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
   4 */
   5
   6#include <linux/relay.h>
   7#include "core.h"
   8#include "debug.h"
   9
  10#define ATH11K_SPECTRAL_NUM_RESP_PER_EVENT      2
  11#define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS        1
  12
  13#define ATH11K_SPECTRAL_DWORD_SIZE              4
  14#define ATH11K_SPECTRAL_MIN_BINS                32
  15#define ATH11K_SPECTRAL_MIN_IB_BINS             (ATH11K_SPECTRAL_MIN_BINS >> 1)
  16#define ATH11K_SPECTRAL_MAX_IB_BINS(x)  ((x)->hw_params.spectral.max_fft_bins >> 1)
  17
  18#define ATH11K_SPECTRAL_SCAN_COUNT_MAX          4095
  19
  20/* Max channel computed by sum of 2g and 5g band channels */
  21#define ATH11K_SPECTRAL_TOTAL_CHANNEL           41
  22#define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL     70
  23#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x)      (sizeof(struct fft_sample_ath11k) + \
  24                                                 ATH11K_SPECTRAL_MAX_IB_BINS(x))
  25#define ATH11K_SPECTRAL_TOTAL_SAMPLE            (ATH11K_SPECTRAL_TOTAL_CHANNEL * \
  26                                                 ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL)
  27#define ATH11K_SPECTRAL_SUB_BUFF_SIZE(x)        ATH11K_SPECTRAL_PER_SAMPLE_SIZE(x)
  28#define ATH11K_SPECTRAL_NUM_SUB_BUF             ATH11K_SPECTRAL_TOTAL_SAMPLE
  29
  30#define ATH11K_SPECTRAL_20MHZ                   20
  31#define ATH11K_SPECTRAL_40MHZ                   40
  32#define ATH11K_SPECTRAL_80MHZ                   80
  33
  34#define ATH11K_SPECTRAL_SIGNATURE               0xFA
  35
  36#define ATH11K_SPECTRAL_TAG_RADAR_SUMMARY       0x0
  37#define ATH11K_SPECTRAL_TAG_RADAR_FFT           0x1
  38#define ATH11K_SPECTRAL_TAG_SCAN_SUMMARY        0x2
  39#define ATH11K_SPECTRAL_TAG_SCAN_SEARCH         0x3
  40
  41#define SPECTRAL_TLV_HDR_LEN                            GENMASK(15, 0)
  42#define SPECTRAL_TLV_HDR_TAG                            GENMASK(23, 16)
  43#define SPECTRAL_TLV_HDR_SIGN                           GENMASK(31, 24)
  44
  45#define SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN           GENMASK(7, 0)
  46#define SPECTRAL_SUMMARY_INFO0_OB_FLAG                  BIT(8)
  47#define SPECTRAL_SUMMARY_INFO0_GRP_IDX                  GENMASK(16, 9)
  48#define SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT             BIT(17)
  49#define SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB            GENMASK(27, 18)
  50#define SPECTRAL_SUMMARY_INFO0_FALSE_SCAN               BIT(28)
  51#define SPECTRAL_SUMMARY_INFO0_DETECTOR_ID              GENMASK(30, 29)
  52#define SPECTRAL_SUMMARY_INFO0_PRI80                    BIT(31)
  53
  54#define SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX          GENMASK(11, 0)
  55#define SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE           GENMASK(21, 12)
  56#define SPECTRAL_SUMMARY_INFO2_NARROWBAND_MASK          GENMASK(29, 22)
  57#define SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE              BIT(30)
  58
  59struct spectral_tlv {
  60        __le32 timestamp;
  61        __le32 header;
  62} __packed;
  63
  64struct spectral_summary_fft_report {
  65        __le32 timestamp;
  66        __le32 tlv_header;
  67        __le32 info0;
  68        __le32 reserve0;
  69        __le32 info2;
  70        __le32 reserve1;
  71} __packed;
  72
  73struct ath11k_spectral_summary_report {
  74        struct wmi_dma_buf_release_meta_data meta;
  75        u32 timestamp;
  76        u8 agc_total_gain;
  77        u8 grp_idx;
  78        u16 inb_pwr_db;
  79        s16 peak_idx;
  80        u16 peak_mag;
  81        u8 detector_id;
  82        bool out_of_band_flag;
  83        bool rf_saturation;
  84        bool primary80;
  85        bool gain_change;
  86        bool false_scan;
  87};
  88
  89#define SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID           GENMASK(1, 0)
  90#define SPECTRAL_FFT_REPORT_INFO0_FFT_NUM               GENMASK(4, 2)
  91#define SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK           GENMASK(16, 5)
  92#define SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX       GENMASK(27, 17)
  93#define SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX             GENMASK(30, 28)
  94
  95#define SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB           GENMASK(8, 0)
  96#define SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB         GENMASK(16, 9)
  97
  98#define SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS       GENMASK(7, 0)
  99#define SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE        GENMASK(17, 8)
 100#define SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB            GENMASK(24, 18)
 101#define SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB            GENMASK(31, 25)
 102
 103struct spectral_search_fft_report {
 104        __le32 timestamp;
 105        __le32 tlv_header;
 106        __le32 info0;
 107        __le32 info1;
 108        __le32 info2;
 109        __le32 reserve0;
 110        u8 bins[];
 111} __packed;
 112
 113struct ath11k_spectral_search_report {
 114        u32 timestamp;
 115        u8 detector_id;
 116        u8 fft_count;
 117        u16 radar_check;
 118        s16 peak_idx;
 119        u8 chain_idx;
 120        u16 base_pwr_db;
 121        u8 total_gain_db;
 122        u8 strong_bin_count;
 123        u16 peak_mag;
 124        u8 avg_pwr_db;
 125        u8 rel_pwr_db;
 126};
 127
 128static struct dentry *create_buf_file_handler(const char *filename,
 129                                              struct dentry *parent,
 130                                              umode_t mode,
 131                                              struct rchan_buf *buf,
 132                                              int *is_global)
 133{
 134        struct dentry *buf_file;
 135
 136        buf_file = debugfs_create_file(filename, mode, parent, buf,
 137                                       &relay_file_operations);
 138        *is_global = 1;
 139        return buf_file;
 140}
 141
 142static int remove_buf_file_handler(struct dentry *dentry)
 143{
 144        debugfs_remove(dentry);
 145
 146        return 0;
 147}
 148
 149static const struct rchan_callbacks rfs_scan_cb = {
 150        .create_buf_file = create_buf_file_handler,
 151        .remove_buf_file = remove_buf_file_handler,
 152};
 153
 154static struct ath11k_vif *ath11k_spectral_get_vdev(struct ath11k *ar)
 155{
 156        struct ath11k_vif *arvif;
 157
 158        lockdep_assert_held(&ar->conf_mutex);
 159
 160        if (list_empty(&ar->arvifs))
 161                return NULL;
 162
 163        /* if there already is a vif doing spectral, return that. */
 164        list_for_each_entry(arvif, &ar->arvifs, list)
 165                if (arvif->spectral_enabled)
 166                        return arvif;
 167
 168        /* otherwise, return the first vif. */
 169        return list_first_entry(&ar->arvifs, typeof(*arvif), list);
 170}
 171
 172static int ath11k_spectral_scan_trigger(struct ath11k *ar)
 173{
 174        struct ath11k_vif *arvif;
 175        int ret;
 176
 177        lockdep_assert_held(&ar->conf_mutex);
 178
 179        arvif = ath11k_spectral_get_vdev(ar);
 180        if (!arvif)
 181                return -ENODEV;
 182
 183        if (ar->spectral.mode == ATH11K_SPECTRAL_DISABLED)
 184                return 0;
 185
 186        ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
 187                                              ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
 188                                              ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE);
 189        if (ret)
 190                return ret;
 191
 192        ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
 193                                              ATH11K_WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
 194                                              ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE);
 195        if (ret)
 196                return ret;
 197
 198        return 0;
 199}
 200
 201static int ath11k_spectral_scan_config(struct ath11k *ar,
 202                                       enum ath11k_spectral_mode mode)
 203{
 204        struct ath11k_wmi_vdev_spectral_conf_param param = { 0 };
 205        struct ath11k_vif *arvif;
 206        int ret, count;
 207
 208        lockdep_assert_held(&ar->conf_mutex);
 209
 210        arvif = ath11k_spectral_get_vdev(ar);
 211        if (!arvif)
 212                return -ENODEV;
 213
 214        arvif->spectral_enabled = (mode != ATH11K_SPECTRAL_DISABLED);
 215
 216        spin_lock_bh(&ar->spectral.lock);
 217        ar->spectral.mode = mode;
 218        spin_unlock_bh(&ar->spectral.lock);
 219
 220        ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
 221                                              ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
 222                                              ATH11K_WMI_SPECTRAL_ENABLE_CMD_DISABLE);
 223        if (ret) {
 224                ath11k_warn(ar->ab, "failed to enable spectral scan: %d\n", ret);
 225                return ret;
 226        }
 227
 228        if (mode == ATH11K_SPECTRAL_DISABLED)
 229                return 0;
 230
 231        if (mode == ATH11K_SPECTRAL_BACKGROUND)
 232                count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT;
 233        else
 234                count = max_t(u16, 1, ar->spectral.count);
 235
 236        param.vdev_id = arvif->vdev_id;
 237        param.scan_count = count;
 238        param.scan_fft_size = ar->spectral.fft_size;
 239        param.scan_period = ATH11K_WMI_SPECTRAL_PERIOD_DEFAULT;
 240        param.scan_priority = ATH11K_WMI_SPECTRAL_PRIORITY_DEFAULT;
 241        param.scan_gc_ena = ATH11K_WMI_SPECTRAL_GC_ENA_DEFAULT;
 242        param.scan_restart_ena = ATH11K_WMI_SPECTRAL_RESTART_ENA_DEFAULT;
 243        param.scan_noise_floor_ref = ATH11K_WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
 244        param.scan_init_delay = ATH11K_WMI_SPECTRAL_INIT_DELAY_DEFAULT;
 245        param.scan_nb_tone_thr = ATH11K_WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
 246        param.scan_str_bin_thr = ATH11K_WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
 247        param.scan_wb_rpt_mode = ATH11K_WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
 248        param.scan_rssi_rpt_mode = ATH11K_WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
 249        param.scan_rssi_thr = ATH11K_WMI_SPECTRAL_RSSI_THR_DEFAULT;
 250        param.scan_pwr_format = ATH11K_WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
 251        param.scan_rpt_mode = ATH11K_WMI_SPECTRAL_RPT_MODE_DEFAULT;
 252        param.scan_bin_scale = ATH11K_WMI_SPECTRAL_BIN_SCALE_DEFAULT;
 253        param.scan_dbm_adj = ATH11K_WMI_SPECTRAL_DBM_ADJ_DEFAULT;
 254        param.scan_chn_mask = ATH11K_WMI_SPECTRAL_CHN_MASK_DEFAULT;
 255
 256        ret = ath11k_wmi_vdev_spectral_conf(ar, &param);
 257        if (ret) {
 258                ath11k_warn(ar->ab, "failed to configure spectral scan: %d\n", ret);
 259                return ret;
 260        }
 261
 262        return 0;
 263}
 264
 265static ssize_t ath11k_read_file_spec_scan_ctl(struct file *file,
 266                                              char __user *user_buf,
 267                                              size_t count, loff_t *ppos)
 268{
 269        struct ath11k *ar = file->private_data;
 270        char *mode = "";
 271        size_t len;
 272        enum ath11k_spectral_mode spectral_mode;
 273
 274        mutex_lock(&ar->conf_mutex);
 275        spectral_mode = ar->spectral.mode;
 276        mutex_unlock(&ar->conf_mutex);
 277
 278        switch (spectral_mode) {
 279        case ATH11K_SPECTRAL_DISABLED:
 280                mode = "disable";
 281                break;
 282        case ATH11K_SPECTRAL_BACKGROUND:
 283                mode = "background";
 284                break;
 285        case ATH11K_SPECTRAL_MANUAL:
 286                mode = "manual";
 287                break;
 288        }
 289
 290        len = strlen(mode);
 291        return simple_read_from_buffer(user_buf, count, ppos, mode, len);
 292}
 293
 294static ssize_t ath11k_write_file_spec_scan_ctl(struct file *file,
 295                                               const char __user *user_buf,
 296                                               size_t count, loff_t *ppos)
 297{
 298        struct ath11k *ar = file->private_data;
 299        char buf[32];
 300        ssize_t len;
 301        int ret;
 302
 303        len = min(count, sizeof(buf) - 1);
 304        if (copy_from_user(buf, user_buf, len))
 305                return -EFAULT;
 306
 307        buf[len] = '\0';
 308
 309        mutex_lock(&ar->conf_mutex);
 310
 311        if (strncmp("trigger", buf, 7) == 0) {
 312                if (ar->spectral.mode == ATH11K_SPECTRAL_MANUAL ||
 313                    ar->spectral.mode == ATH11K_SPECTRAL_BACKGROUND) {
 314                        /* reset the configuration to adopt possibly changed
 315                         * debugfs parameters
 316                         */
 317                        ret = ath11k_spectral_scan_config(ar, ar->spectral.mode);
 318                        if (ret) {
 319                                ath11k_warn(ar->ab, "failed to reconfigure spectral scan: %d\n",
 320                                            ret);
 321                                goto unlock;
 322                        }
 323
 324                        ret = ath11k_spectral_scan_trigger(ar);
 325                        if (ret) {
 326                                ath11k_warn(ar->ab, "failed to trigger spectral scan: %d\n",
 327                                            ret);
 328                        }
 329                } else {
 330                        ret = -EINVAL;
 331                }
 332        } else if (strncmp("background", buf, 10) == 0) {
 333                ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_BACKGROUND);
 334        } else if (strncmp("manual", buf, 6) == 0) {
 335                ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_MANUAL);
 336        } else if (strncmp("disable", buf, 7) == 0) {
 337                ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED);
 338        } else {
 339                ret = -EINVAL;
 340        }
 341
 342unlock:
 343        mutex_unlock(&ar->conf_mutex);
 344
 345        if (ret)
 346                return ret;
 347
 348        return count;
 349}
 350
 351static const struct file_operations fops_scan_ctl = {
 352        .read = ath11k_read_file_spec_scan_ctl,
 353        .write = ath11k_write_file_spec_scan_ctl,
 354        .open = simple_open,
 355        .owner = THIS_MODULE,
 356        .llseek = default_llseek,
 357};
 358
 359static ssize_t ath11k_read_file_spectral_count(struct file *file,
 360                                               char __user *user_buf,
 361                                               size_t count, loff_t *ppos)
 362{
 363        struct ath11k *ar = file->private_data;
 364        char buf[32];
 365        size_t len;
 366        u16 spectral_count;
 367
 368        mutex_lock(&ar->conf_mutex);
 369        spectral_count = ar->spectral.count;
 370        mutex_unlock(&ar->conf_mutex);
 371
 372        len = sprintf(buf, "%d\n", spectral_count);
 373        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 374}
 375
 376static ssize_t ath11k_write_file_spectral_count(struct file *file,
 377                                                const char __user *user_buf,
 378                                                size_t count, loff_t *ppos)
 379{
 380        struct ath11k *ar = file->private_data;
 381        unsigned long val;
 382        char buf[32];
 383        ssize_t len;
 384
 385        len = min(count, sizeof(buf) - 1);
 386        if (copy_from_user(buf, user_buf, len))
 387                return -EFAULT;
 388
 389        buf[len] = '\0';
 390        if (kstrtoul(buf, 0, &val))
 391                return -EINVAL;
 392
 393        if (val > ATH11K_SPECTRAL_SCAN_COUNT_MAX)
 394                return -EINVAL;
 395
 396        mutex_lock(&ar->conf_mutex);
 397        ar->spectral.count = val;
 398        mutex_unlock(&ar->conf_mutex);
 399
 400        return count;
 401}
 402
 403static const struct file_operations fops_scan_count = {
 404        .read = ath11k_read_file_spectral_count,
 405        .write = ath11k_write_file_spectral_count,
 406        .open = simple_open,
 407        .owner = THIS_MODULE,
 408        .llseek = default_llseek,
 409};
 410
 411static ssize_t ath11k_read_file_spectral_bins(struct file *file,
 412                                              char __user *user_buf,
 413                                              size_t count, loff_t *ppos)
 414{
 415        struct ath11k *ar = file->private_data;
 416        char buf[32];
 417        unsigned int bins, fft_size;
 418        size_t len;
 419
 420        mutex_lock(&ar->conf_mutex);
 421
 422        fft_size = ar->spectral.fft_size;
 423        bins = 1 << fft_size;
 424
 425        mutex_unlock(&ar->conf_mutex);
 426
 427        len = sprintf(buf, "%d\n", bins);
 428        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 429}
 430
 431static ssize_t ath11k_write_file_spectral_bins(struct file *file,
 432                                               const char __user *user_buf,
 433                                               size_t count, loff_t *ppos)
 434{
 435        struct ath11k *ar = file->private_data;
 436        unsigned long val;
 437        char buf[32];
 438        ssize_t len;
 439
 440        len = min(count, sizeof(buf) - 1);
 441        if (copy_from_user(buf, user_buf, len))
 442                return -EFAULT;
 443
 444        buf[len] = '\0';
 445        if (kstrtoul(buf, 0, &val))
 446                return -EINVAL;
 447
 448        if (val < ATH11K_SPECTRAL_MIN_BINS ||
 449            val > ar->ab->hw_params.spectral.max_fft_bins)
 450                return -EINVAL;
 451
 452        if (!is_power_of_2(val))
 453                return -EINVAL;
 454
 455        mutex_lock(&ar->conf_mutex);
 456        ar->spectral.fft_size = ilog2(val);
 457        mutex_unlock(&ar->conf_mutex);
 458
 459        return count;
 460}
 461
 462static const struct file_operations fops_scan_bins = {
 463        .read = ath11k_read_file_spectral_bins,
 464        .write = ath11k_write_file_spectral_bins,
 465        .open = simple_open,
 466        .owner = THIS_MODULE,
 467        .llseek = default_llseek,
 468};
 469
 470static int ath11k_spectral_pull_summary(struct ath11k *ar,
 471                                        struct wmi_dma_buf_release_meta_data *meta,
 472                                        struct spectral_summary_fft_report *summary,
 473                                        struct ath11k_spectral_summary_report *report)
 474{
 475        report->timestamp = __le32_to_cpu(summary->timestamp);
 476        report->agc_total_gain = FIELD_GET(SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN,
 477                                           __le32_to_cpu(summary->info0));
 478        report->out_of_band_flag = FIELD_GET(SPECTRAL_SUMMARY_INFO0_OB_FLAG,
 479                                             __le32_to_cpu(summary->info0));
 480        report->grp_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO0_GRP_IDX,
 481                                    __le32_to_cpu(summary->info0));
 482        report->rf_saturation = FIELD_GET(SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT,
 483                                          __le32_to_cpu(summary->info0));
 484        report->inb_pwr_db = FIELD_GET(SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB,
 485                                       __le32_to_cpu(summary->info0));
 486        report->false_scan = FIELD_GET(SPECTRAL_SUMMARY_INFO0_FALSE_SCAN,
 487                                       __le32_to_cpu(summary->info0));
 488        report->detector_id = FIELD_GET(SPECTRAL_SUMMARY_INFO0_DETECTOR_ID,
 489                                        __le32_to_cpu(summary->info0));
 490        report->primary80 = FIELD_GET(SPECTRAL_SUMMARY_INFO0_PRI80,
 491                                      __le32_to_cpu(summary->info0));
 492        report->peak_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX,
 493                                     __le32_to_cpu(summary->info2));
 494        report->peak_mag = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE,
 495                                     __le32_to_cpu(summary->info2));
 496        report->gain_change = FIELD_GET(SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE,
 497                                        __le32_to_cpu(summary->info2));
 498
 499        memcpy(&report->meta, meta, sizeof(*meta));
 500
 501        return 0;
 502}
 503
 504static int ath11k_spectral_pull_search(struct ath11k *ar,
 505                                       struct spectral_search_fft_report *search,
 506                                       struct ath11k_spectral_search_report *report)
 507{
 508        report->timestamp = __le32_to_cpu(search->timestamp);
 509        report->detector_id = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID,
 510                                        __le32_to_cpu(search->info0));
 511        report->fft_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_FFT_NUM,
 512                                      __le32_to_cpu(search->info0));
 513        report->radar_check = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK,
 514                                        __le32_to_cpu(search->info0));
 515        report->peak_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX,
 516                                     __le32_to_cpu(search->info0));
 517        report->chain_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX,
 518                                      __le32_to_cpu(search->info0));
 519        report->base_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB,
 520                                        __le32_to_cpu(search->info1));
 521        report->total_gain_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB,
 522                                          __le32_to_cpu(search->info1));
 523        report->strong_bin_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS,
 524                                             __le32_to_cpu(search->info2));
 525        report->peak_mag = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE,
 526                                     __le32_to_cpu(search->info2));
 527        report->avg_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB,
 528                                       __le32_to_cpu(search->info2));
 529        report->rel_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB,
 530                                       __le32_to_cpu(search->info2));
 531
 532        return 0;
 533}
 534
 535static u8 ath11k_spectral_get_max_exp(s8 max_index, u8 max_magnitude,
 536                                      int bin_len, u8 *bins)
 537{
 538        int dc_pos;
 539        u8 max_exp;
 540
 541        dc_pos = bin_len / 2;
 542
 543        /* peak index outside of bins */
 544        if (dc_pos <= max_index || -dc_pos >= max_index)
 545                return 0;
 546
 547        for (max_exp = 0; max_exp < 8; max_exp++) {
 548                if (bins[dc_pos + max_index] == (max_magnitude >> max_exp))
 549                        break;
 550        }
 551
 552        /* max_exp not found */
 553        if (bins[dc_pos + max_index] != (max_magnitude >> max_exp))
 554                return 0;
 555
 556        return max_exp;
 557}
 558
 559static void ath11k_spectral_parse_fft(u8 *outbins, u8 *inbins, int num_bins, u8 fft_sz)
 560{
 561        int i, j;
 562
 563        i = 0;
 564        j = 0;
 565        while (i < num_bins) {
 566                outbins[i] = inbins[j];
 567                i++;
 568                j += fft_sz;
 569        }
 570}
 571
 572static
 573int ath11k_spectral_process_fft(struct ath11k *ar,
 574                                struct ath11k_spectral_summary_report *summary,
 575                                void *data,
 576                                struct fft_sample_ath11k *fft_sample,
 577                                u32 data_len)
 578{
 579        struct ath11k_base *ab = ar->ab;
 580        struct spectral_search_fft_report *fft_report = data;
 581        struct ath11k_spectral_search_report search;
 582        struct spectral_tlv *tlv;
 583        int tlv_len, bin_len, num_bins;
 584        u16 length, freq;
 585        u8 chan_width_mhz, bin_sz;
 586        int ret;
 587        u32 check_length;
 588
 589        lockdep_assert_held(&ar->spectral.lock);
 590
 591        if (!ab->hw_params.spectral.fft_sz) {
 592                ath11k_warn(ab, "invalid bin size type for hw rev %d\n",
 593                            ab->hw_rev);
 594                return -EINVAL;
 595        }
 596
 597        tlv = (struct spectral_tlv *)data;
 598        tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header));
 599        /* convert Dword into bytes */
 600        tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE;
 601        bin_len = tlv_len - ab->hw_params.spectral.fft_hdr_len;
 602
 603        if (data_len < (bin_len + sizeof(*fft_report))) {
 604                ath11k_warn(ab, "mismatch in expected bin len %d and data len %d\n",
 605                            bin_len, data_len);
 606                return -EINVAL;
 607        }
 608
 609        bin_sz = ab->hw_params.spectral.fft_sz + ab->hw_params.spectral.fft_pad_sz;
 610        num_bins = bin_len / bin_sz;
 611        /* Only In-band bins are useful to user for visualize */
 612        num_bins >>= 1;
 613
 614        if (num_bins < ATH11K_SPECTRAL_MIN_IB_BINS ||
 615            num_bins > ATH11K_SPECTRAL_MAX_IB_BINS(ab) ||
 616            !is_power_of_2(num_bins)) {
 617                ath11k_warn(ab, "Invalid num of bins %d\n", num_bins);
 618                return -EINVAL;
 619        }
 620
 621        check_length = sizeof(*fft_report) + (num_bins * ab->hw_params.spectral.fft_sz);
 622        ret = ath11k_dbring_validate_buffer(ar, data, check_length);
 623        if (ret) {
 624                ath11k_warn(ar->ab, "found magic value in fft data, dropping\n");
 625                return ret;
 626        }
 627
 628        ret = ath11k_spectral_pull_search(ar, data, &search);
 629        if (ret) {
 630                ath11k_warn(ab, "failed to pull search report %d\n", ret);
 631                return ret;
 632        }
 633
 634        chan_width_mhz = summary->meta.ch_width;
 635
 636        switch (chan_width_mhz) {
 637        case ATH11K_SPECTRAL_20MHZ:
 638        case ATH11K_SPECTRAL_40MHZ:
 639        case ATH11K_SPECTRAL_80MHZ:
 640                fft_sample->chan_width_mhz = chan_width_mhz;
 641                break;
 642        default:
 643                ath11k_warn(ab, "invalid channel width %d\n", chan_width_mhz);
 644                return -EINVAL;
 645        }
 646
 647        length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + num_bins;
 648        fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH11K;
 649        fft_sample->tlv.length = __cpu_to_be16(length);
 650
 651        fft_sample->tsf = __cpu_to_be32(search.timestamp);
 652        fft_sample->max_magnitude = __cpu_to_be16(search.peak_mag);
 653        fft_sample->max_index = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX,
 654                                          __le32_to_cpu(fft_report->info0));
 655
 656        summary->inb_pwr_db >>= 1;
 657        fft_sample->rssi = __cpu_to_be16(summary->inb_pwr_db);
 658        fft_sample->noise = __cpu_to_be32(summary->meta.noise_floor[search.chain_idx]);
 659
 660        freq = summary->meta.freq1;
 661        fft_sample->freq1 = __cpu_to_be16(freq);
 662
 663        freq = summary->meta.freq2;
 664        fft_sample->freq2 = __cpu_to_be16(freq);
 665
 666        ath11k_spectral_parse_fft(fft_sample->data, fft_report->bins, num_bins,
 667                                  ab->hw_params.spectral.fft_sz);
 668
 669        fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index,
 670                                                          search.peak_mag,
 671                                                          num_bins,
 672                                                          fft_sample->data);
 673
 674        if (ar->spectral.rfs_scan)
 675                relay_write(ar->spectral.rfs_scan, fft_sample,
 676                            length + sizeof(struct fft_sample_tlv));
 677
 678        return 0;
 679}
 680
 681static int ath11k_spectral_process_data(struct ath11k *ar,
 682                                        struct ath11k_dbring_data *param)
 683{
 684        struct ath11k_base *ab = ar->ab;
 685        struct spectral_tlv *tlv;
 686        struct spectral_summary_fft_report *summary = NULL;
 687        struct ath11k_spectral_summary_report summ_rpt;
 688        struct fft_sample_ath11k *fft_sample = NULL;
 689        u8 *data;
 690        u32 data_len, i;
 691        u8 sign, tag;
 692        int tlv_len, sample_sz;
 693        int ret;
 694        bool quit = false;
 695
 696        spin_lock_bh(&ar->spectral.lock);
 697
 698        if (!ar->spectral.enabled) {
 699                ret = -EINVAL;
 700                goto unlock;
 701        }
 702
 703        sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_MAX_IB_BINS(ab);
 704        fft_sample = kmalloc(sample_sz, GFP_ATOMIC);
 705        if (!fft_sample) {
 706                ret = -ENOBUFS;
 707                goto unlock;
 708        }
 709
 710        data = param->data;
 711        data_len = param->data_sz;
 712        i = 0;
 713        while (!quit && (i < data_len)) {
 714                if ((i + sizeof(*tlv)) > data_len) {
 715                        ath11k_warn(ab, "failed to parse spectral tlv hdr at bytes %d\n",
 716                                    i);
 717                        ret = -EINVAL;
 718                        goto err;
 719                }
 720
 721                tlv = (struct spectral_tlv *)&data[i];
 722                sign = FIELD_GET(SPECTRAL_TLV_HDR_SIGN,
 723                                 __le32_to_cpu(tlv->header));
 724                if (sign != ATH11K_SPECTRAL_SIGNATURE) {
 725                        ath11k_warn(ab, "Invalid sign 0x%x at bytes %d\n",
 726                                    sign, i);
 727                        ret = -EINVAL;
 728                        goto err;
 729                }
 730
 731                tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN,
 732                                    __le32_to_cpu(tlv->header));
 733                /* convert Dword into bytes */
 734                tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE;
 735                if ((i + sizeof(*tlv) + tlv_len) > data_len) {
 736                        ath11k_warn(ab, "failed to parse spectral tlv payload at bytes %d tlv_len:%d data_len:%d\n",
 737                                    i, tlv_len, data_len);
 738                        ret = -EINVAL;
 739                        goto err;
 740                }
 741
 742                tag = FIELD_GET(SPECTRAL_TLV_HDR_TAG,
 743                                __le32_to_cpu(tlv->header));
 744                switch (tag) {
 745                case ATH11K_SPECTRAL_TAG_SCAN_SUMMARY:
 746                        /* HW bug in tlv length of summary report,
 747                         * HW report 3 DWORD size but the data payload
 748                         * is 4 DWORD size (16 bytes).
 749                         * Need to remove this workaround once HW bug fixed
 750                         */
 751                        tlv_len = sizeof(*summary) - sizeof(*tlv) +
 752                                  ab->hw_params.spectral.summary_pad_sz;
 753
 754                        if (tlv_len < (sizeof(*summary) - sizeof(*tlv))) {
 755                                ath11k_warn(ab, "failed to parse spectral summary at bytes %d tlv_len:%d\n",
 756                                            i, tlv_len);
 757                                ret = -EINVAL;
 758                                goto err;
 759                        }
 760
 761                        ret = ath11k_dbring_validate_buffer(ar, data, tlv_len);
 762                        if (ret) {
 763                                ath11k_warn(ar->ab, "found magic value in spectral summary, dropping\n");
 764                                goto err;
 765                        }
 766
 767                        summary = (struct spectral_summary_fft_report *)tlv;
 768                        ath11k_spectral_pull_summary(ar, &param->meta,
 769                                                     summary, &summ_rpt);
 770                        break;
 771                case ATH11K_SPECTRAL_TAG_SCAN_SEARCH:
 772                        if (tlv_len < (sizeof(struct spectral_search_fft_report) -
 773                                       sizeof(*tlv))) {
 774                                ath11k_warn(ab, "failed to parse spectral search fft at bytes %d\n",
 775                                            i);
 776                                ret = -EINVAL;
 777                                goto err;
 778                        }
 779
 780                        memset(fft_sample, 0, sample_sz);
 781                        ret = ath11k_spectral_process_fft(ar, &summ_rpt, tlv,
 782                                                          fft_sample,
 783                                                          data_len - i);
 784                        if (ret) {
 785                                ath11k_warn(ab, "failed to process spectral fft at bytes %d\n",
 786                                            i);
 787                                goto err;
 788                        }
 789                        quit = true;
 790                        break;
 791                }
 792
 793                i += sizeof(*tlv) + tlv_len;
 794        }
 795
 796        ret = 0;
 797
 798err:
 799        kfree(fft_sample);
 800unlock:
 801        spin_unlock_bh(&ar->spectral.lock);
 802        return ret;
 803}
 804
 805static int ath11k_spectral_ring_alloc(struct ath11k *ar,
 806                                      struct ath11k_dbring_cap *db_cap)
 807{
 808        struct ath11k_spectral *sp = &ar->spectral;
 809        int ret;
 810
 811        ret = ath11k_dbring_srng_setup(ar, &sp->rx_ring,
 812                                       0, db_cap->min_elem);
 813        if (ret) {
 814                ath11k_warn(ar->ab, "failed to setup db ring\n");
 815                return ret;
 816        }
 817
 818        ath11k_dbring_set_cfg(ar, &sp->rx_ring,
 819                              ATH11K_SPECTRAL_NUM_RESP_PER_EVENT,
 820                              ATH11K_SPECTRAL_EVENT_TIMEOUT_MS,
 821                              ath11k_spectral_process_data);
 822
 823        ret = ath11k_dbring_buf_setup(ar, &sp->rx_ring, db_cap);
 824        if (ret) {
 825                ath11k_warn(ar->ab, "failed to setup db ring buffer\n");
 826                goto srng_cleanup;
 827        }
 828
 829        ret = ath11k_dbring_wmi_cfg_setup(ar, &sp->rx_ring,
 830                                          WMI_DIRECT_BUF_SPECTRAL);
 831        if (ret) {
 832                ath11k_warn(ar->ab, "failed to setup db ring cfg\n");
 833                goto buffer_cleanup;
 834        }
 835
 836        return 0;
 837
 838buffer_cleanup:
 839        ath11k_dbring_buf_cleanup(ar, &sp->rx_ring);
 840srng_cleanup:
 841        ath11k_dbring_srng_cleanup(ar, &sp->rx_ring);
 842        return ret;
 843}
 844
 845static inline void ath11k_spectral_ring_free(struct ath11k *ar)
 846{
 847        struct ath11k_spectral *sp = &ar->spectral;
 848
 849        ath11k_dbring_srng_cleanup(ar, &sp->rx_ring);
 850        ath11k_dbring_buf_cleanup(ar, &sp->rx_ring);
 851}
 852
 853static inline void ath11k_spectral_debug_unregister(struct ath11k *ar)
 854{
 855        debugfs_remove(ar->spectral.scan_bins);
 856        ar->spectral.scan_bins = NULL;
 857
 858        debugfs_remove(ar->spectral.scan_count);
 859        ar->spectral.scan_count = NULL;
 860
 861        debugfs_remove(ar->spectral.scan_ctl);
 862        ar->spectral.scan_ctl = NULL;
 863
 864        if (ar->spectral.rfs_scan) {
 865                relay_close(ar->spectral.rfs_scan);
 866                ar->spectral.rfs_scan = NULL;
 867        }
 868}
 869
 870int ath11k_spectral_vif_stop(struct ath11k_vif *arvif)
 871{
 872        if (!arvif->spectral_enabled)
 873                return 0;
 874
 875        return ath11k_spectral_scan_config(arvif->ar, ATH11K_SPECTRAL_DISABLED);
 876}
 877
 878void ath11k_spectral_reset_buffer(struct ath11k *ar)
 879{
 880        if (!ar->spectral.enabled)
 881                return;
 882
 883        if (ar->spectral.rfs_scan)
 884                relay_reset(ar->spectral.rfs_scan);
 885}
 886
 887void ath11k_spectral_deinit(struct ath11k_base *ab)
 888{
 889        struct ath11k *ar;
 890        struct ath11k_spectral *sp;
 891        int i;
 892
 893        for (i = 0; i <  ab->num_radios; i++) {
 894                ar = ab->pdevs[i].ar;
 895                sp = &ar->spectral;
 896
 897                if (!sp->enabled)
 898                        continue;
 899
 900                mutex_lock(&ar->conf_mutex);
 901                ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED);
 902                mutex_unlock(&ar->conf_mutex);
 903
 904                spin_lock_bh(&sp->lock);
 905                sp->enabled = false;
 906                spin_unlock_bh(&sp->lock);
 907
 908                ath11k_spectral_debug_unregister(ar);
 909                ath11k_spectral_ring_free(ar);
 910        }
 911}
 912
 913static inline int ath11k_spectral_debug_register(struct ath11k *ar)
 914{
 915        int ret;
 916
 917        ar->spectral.rfs_scan = relay_open("spectral_scan",
 918                                           ar->debug.debugfs_pdev,
 919                                           ATH11K_SPECTRAL_SUB_BUFF_SIZE(ar->ab),
 920                                           ATH11K_SPECTRAL_NUM_SUB_BUF,
 921                                           &rfs_scan_cb, NULL);
 922        if (!ar->spectral.rfs_scan) {
 923                ath11k_warn(ar->ab, "failed to open relay in pdev %d\n",
 924                            ar->pdev_idx);
 925                return -EINVAL;
 926        }
 927
 928        ar->spectral.scan_ctl = debugfs_create_file("spectral_scan_ctl",
 929                                                    0600,
 930                                                    ar->debug.debugfs_pdev, ar,
 931                                                    &fops_scan_ctl);
 932        if (!ar->spectral.scan_ctl) {
 933                ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
 934                            ar->pdev_idx);
 935                ret = -EINVAL;
 936                goto debug_unregister;
 937        }
 938
 939        ar->spectral.scan_count = debugfs_create_file("spectral_count",
 940                                                      0600,
 941                                                      ar->debug.debugfs_pdev, ar,
 942                                                      &fops_scan_count);
 943        if (!ar->spectral.scan_count) {
 944                ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
 945                            ar->pdev_idx);
 946                ret = -EINVAL;
 947                goto debug_unregister;
 948        }
 949
 950        ar->spectral.scan_bins = debugfs_create_file("spectral_bins",
 951                                                     0600,
 952                                                     ar->debug.debugfs_pdev, ar,
 953                                                     &fops_scan_bins);
 954        if (!ar->spectral.scan_bins) {
 955                ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
 956                            ar->pdev_idx);
 957                ret = -EINVAL;
 958                goto debug_unregister;
 959        }
 960
 961        return 0;
 962
 963debug_unregister:
 964        ath11k_spectral_debug_unregister(ar);
 965        return ret;
 966}
 967
 968int ath11k_spectral_init(struct ath11k_base *ab)
 969{
 970        struct ath11k *ar;
 971        struct ath11k_spectral *sp;
 972        struct ath11k_dbring_cap db_cap;
 973        int ret;
 974        int i;
 975
 976        if (!test_bit(WMI_TLV_SERVICE_FREQINFO_IN_METADATA,
 977                      ab->wmi_ab.svc_map))
 978                return 0;
 979
 980        if (!ab->hw_params.spectral.fft_sz)
 981                return 0;
 982
 983        for (i = 0; i < ab->num_radios; i++) {
 984                ar = ab->pdevs[i].ar;
 985                sp = &ar->spectral;
 986
 987                ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx,
 988                                            WMI_DIRECT_BUF_SPECTRAL,
 989                                            &db_cap);
 990                if (ret)
 991                        continue;
 992
 993                idr_init(&sp->rx_ring.bufs_idr);
 994                spin_lock_init(&sp->rx_ring.idr_lock);
 995                spin_lock_init(&sp->lock);
 996
 997                ret = ath11k_spectral_ring_alloc(ar, &db_cap);
 998                if (ret) {
 999                        ath11k_warn(ab, "failed to init spectral ring for pdev %d\n",
1000                                    i);
1001                        goto deinit;
1002                }
1003
1004                spin_lock_bh(&sp->lock);
1005
1006                sp->mode = ATH11K_SPECTRAL_DISABLED;
1007                sp->count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT;
1008                sp->fft_size = ATH11K_WMI_SPECTRAL_FFT_SIZE_DEFAULT;
1009                sp->enabled = true;
1010
1011                spin_unlock_bh(&sp->lock);
1012
1013                ret = ath11k_spectral_debug_register(ar);
1014                if (ret) {
1015                        ath11k_warn(ab, "failed to register spectral for pdev %d\n",
1016                                    i);
1017                        goto deinit;
1018                }
1019        }
1020
1021        return 0;
1022
1023deinit:
1024        ath11k_spectral_deinit(ab);
1025        return ret;
1026}
1027
1028enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar)
1029{
1030        if (ar->spectral.enabled)
1031                return ar->spectral.mode;
1032        else
1033                return ATH11K_SPECTRAL_DISABLED;
1034}
1035
1036struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar)
1037{
1038        if (ar->spectral.enabled)
1039                return &ar->spectral.rx_ring;
1040        else
1041                return NULL;
1042}
1043