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