// SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
/* if there already is a vif doing spectral, return that. */
list_for_each_entry(arvif, &ar->arvifs, list) if (arvif->spectral_enabled) return arvif;
/* otherwise, return the first vif. */ return list_first_entry(&ar->arvifs, typeof(*arvif), list);
}
staticint ath11k_spectral_scan_trigger(struct ath11k *ar)
{ struct ath11k_vif *arvif; int ret;
lockdep_assert_held(&ar->conf_mutex);
arvif = ath11k_spectral_get_vdev(ar); if (!arvif) return -ENODEV;
if (ar->spectral.mode == ATH11K_SPECTRAL_DISABLED) return 0;
ar->spectral.is_primary = true;
ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE); if (ret) return ret;
ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
ATH11K_WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE); if (ret) return ret;
if (data_len < (bin_len + sizeof(*fft_report))) {
ath11k_warn(ab, "mismatch in expected bin len %d and data len %d\n",
bin_len, data_len); return -EINVAL;
}
bin_sz = ab->hw_params.spectral.fft_sz + ab->hw_params.spectral.fft_pad_sz;
num_bins = bin_len / bin_sz; /* Only In-band bins are useful to user for visualize */
num_bins >>= 1;
if (num_bins < ATH11K_SPECTRAL_MIN_IB_BINS ||
num_bins > ATH11K_SPECTRAL_MAX_IB_BINS(ab) ||
!is_power_of_2(num_bins)) {
ath11k_warn(ab, "Invalid num of bins %d\n", num_bins); return -EINVAL;
}
check_length = sizeof(*fft_report) + (num_bins * ab->hw_params.spectral.fft_sz);
ret = ath11k_dbring_validate_buffer(ar, data, check_length); if (ret) {
ath11k_warn(ar->ab, "found magic value in fft data, dropping\n"); return ret;
}
ret = ath11k_spectral_pull_search(ar, data, &search); if (ret) {
ath11k_warn(ab, "failed to pull search report %d\n", ret); return ret;
}
chan_width_mhz = summary->meta.ch_width;
switch (chan_width_mhz) { case ATH11K_SPECTRAL_20MHZ: case ATH11K_SPECTRAL_40MHZ: case ATH11K_SPECTRAL_80MHZ:
fft_sample->chan_width_mhz = chan_width_mhz; break; case ATH11K_SPECTRAL_160MHZ: if (ab->hw_params.spectral.fragment_160mhz) {
chan_width_mhz /= 2;
fragment_sample = true;
}
fft_sample->chan_width_mhz = chan_width_mhz; break; default:
ath11k_warn(ab, "invalid channel width %d\n", chan_width_mhz); return -EINVAL;
}
/* If freq2 is available then the spectral scan results are fragmented * as primary and secondary
*/ if (fragment_sample && freq) { if (!ar->spectral.is_primary)
fft_sample->freq1 = cpu_to_be16(freq);
/* We have to toggle the is_primary to handle the next report */
ar->spectral.is_primary = !ar->spectral.is_primary;
}
if (!ar->spectral.enabled) {
ret = -EINVAL; goto unlock;
}
sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_MAX_IB_BINS(ab);
fft_sample = kmalloc(sample_sz, GFP_ATOMIC); if (!fft_sample) {
ret = -ENOBUFS; goto unlock;
}
data = param->data;
data_len = param->data_sz;
i = 0; while (!quit && (i < data_len)) { if ((i + sizeof(*tlv)) > data_len) {
ath11k_warn(ab, "failed to parse spectral tlv hdr at bytes %d\n",
i);
ret = -EINVAL; goto err;
}
tlv = (struct spectral_tlv *)&data[i];
sign = FIELD_GET(SPECTRAL_TLV_HDR_SIGN,
__le32_to_cpu(tlv->header)); if (sign != ATH11K_SPECTRAL_SIGNATURE) {
ath11k_warn(ab, "Invalid sign 0x%x at bytes %d\n",
sign, i);
ret = -EINVAL; goto err;
}
tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN,
__le32_to_cpu(tlv->header)); /* convert Dword into bytes */
tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE; if ((i + sizeof(*tlv) + tlv_len) > data_len) {
ath11k_warn(ab, "failed to parse spectral tlv payload at bytes %d tlv_len:%d data_len:%d\n",
i, tlv_len, data_len);
ret = -EINVAL; goto err;
}
tag = FIELD_GET(SPECTRAL_TLV_HDR_TAG,
__le32_to_cpu(tlv->header)); switch (tag) { case ATH11K_SPECTRAL_TAG_SCAN_SUMMARY: /* HW bug in tlv length of summary report, * HW report 3 DWORD size but the data payload * is 4 DWORD size (16 bytes). * Need to remove this workaround once HW bug fixed
*/
tlv_len = sizeof(*summary) - sizeof(*tlv) +
ab->hw_params.spectral.summary_pad_sz;
if (tlv_len < (sizeof(*summary) - sizeof(*tlv))) {
ath11k_warn(ab, "failed to parse spectral summary at bytes %d tlv_len:%d\n",
i, tlv_len);
ret = -EINVAL; goto err;
}
ret = ath11k_dbring_validate_buffer(ar, data, tlv_len); if (ret) {
ath11k_warn(ar->ab, "found magic value in spectral summary, dropping\n"); goto err;
}
summary = (struct spectral_summary_fft_report *)tlv;
ath11k_spectral_pull_summary(ar, ¶m->meta,
summary, &summ_rpt); break; case ATH11K_SPECTRAL_TAG_SCAN_SEARCH: if (tlv_len < (sizeof(struct spectral_search_fft_report) - sizeof(*tlv))) {
ath11k_warn(ab, "failed to parse spectral search fft at bytes %d\n",
i);
ret = -EINVAL; goto err;
}
memset(fft_sample, 0, sample_sz);
ret = ath11k_spectral_process_fft(ar, &summ_rpt, tlv,
fft_sample,
data_len - i); if (ret) {
ath11k_warn(ab, "failed to process spectral fft at bytes %d\n",
i); goto err;
}
quit = true; break;
}
ret = ath11k_dbring_buf_setup(ar, &sp->rx_ring, db_cap); if (ret) {
ath11k_warn(ar->ab, "failed to setup db ring buffer\n"); goto srng_cleanup;
}
ret = ath11k_dbring_wmi_cfg_setup(ar, &sp->rx_ring,
WMI_DIRECT_BUF_SPECTRAL); if (ret) {
ath11k_warn(ar->ab, "failed to setup db ring cfg\n"); goto buffer_cleanup;
}
staticinlineint ath11k_spectral_debug_register(struct ath11k *ar)
{ int ret;
ar->spectral.rfs_scan = relay_open("spectral_scan",
ar->debug.debugfs_pdev,
ATH11K_SPECTRAL_SUB_BUFF_SIZE(ar->ab),
ATH11K_SPECTRAL_NUM_SUB_BUF,
&rfs_scan_cb, NULL); if (!ar->spectral.rfs_scan) {
ath11k_warn(ar->ab, "failed to open relay in pdev %d\n",
ar->pdev_idx); return -EINVAL;
}
ar->spectral.scan_ctl = debugfs_create_file("spectral_scan_ctl",
0600,
ar->debug.debugfs_pdev, ar,
&fops_scan_ctl); if (!ar->spectral.scan_ctl) {
ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
ar->pdev_idx);
ret = -EINVAL; goto debug_unregister;
}
ar->spectral.scan_count = debugfs_create_file("spectral_count",
0600,
ar->debug.debugfs_pdev, ar,
&fops_scan_count); if (!ar->spectral.scan_count) {
ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
ar->pdev_idx);
ret = -EINVAL; goto debug_unregister;
}
ar->spectral.scan_bins = debugfs_create_file("spectral_bins",
0600,
ar->debug.debugfs_pdev, ar,
&fops_scan_bins); if (!ar->spectral.scan_bins) {
ath11k_warn(ar->ab, "failed to open debugfs in pdev %d\n",
ar->pdev_idx);
ret = -EINVAL; goto debug_unregister;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.