Commit f5f58a0b authored by Kalle Valo's avatar Kalle Valo

Merge ath-next from git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/ath.git

ath.git patches for v5.9. Major changes:

ath11k

* add 6G band support

* add spectral scan support
parents b3a9e3b9 01e34233
...@@ -15,11 +15,11 @@ config WLAN_VENDOR_ATH ...@@ -15,11 +15,11 @@ config WLAN_VENDOR_ATH
For more information and documentation on this module you can visit: For more information and documentation on this module you can visit:
http://wireless.kernel.org/en/users/Drivers/ath https://wireless.wiki.kernel.org/en/users/Drivers/ath
For information on all Atheros wireless drivers visit: For information on all Atheros wireless drivers visit:
http://wireless.kernel.org/en/users/Drivers/Atheros https://wireless.wiki.kernel.org/en/users/Drivers/Atheros
if WLAN_VENDOR_ATH if WLAN_VENDOR_ATH
......
...@@ -1591,7 +1591,9 @@ static int ath10k_htt_tx_32(struct ath10k_htt *htt, ...@@ -1591,7 +1591,9 @@ static int ath10k_htt_tx_32(struct ath10k_htt *htt,
err_unmap_msdu: err_unmap_msdu:
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
err_free_msdu_id: err_free_msdu_id:
spin_lock_bh(&htt->tx_lock);
ath10k_htt_tx_free_msdu_id(htt, msdu_id); ath10k_htt_tx_free_msdu_id(htt, msdu_id);
spin_unlock_bh(&htt->tx_lock);
err: err:
return res; return res;
} }
...@@ -1798,7 +1800,9 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt, ...@@ -1798,7 +1800,9 @@ static int ath10k_htt_tx_64(struct ath10k_htt *htt,
err_unmap_msdu: err_unmap_msdu:
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
err_free_msdu_id: err_free_msdu_id:
spin_lock_bh(&htt->tx_lock);
ath10k_htt_tx_free_msdu_id(htt, msdu_id); ath10k_htt_tx_free_msdu_id(htt, msdu_id);
spin_unlock_bh(&htt->tx_lock);
err: err:
return res; return res;
} }
......
...@@ -34,3 +34,12 @@ config ATH11K_TRACING ...@@ -34,3 +34,12 @@ config ATH11K_TRACING
depends on ATH11K && EVENT_TRACING depends on ATH11K && EVENT_TRACING
help help
Select this to use ath11k tracing infrastructure. Select this to use ath11k tracing infrastructure.
config ATH11K_SPECTRAL
bool "QCA ath11k spectral scan support"
depends on ATH11K_DEBUGFS
depends on RELAY
help
Enable ath11k spectral scan support
Say Y to enable access to the FFT/spectral data via debugfs.
...@@ -15,12 +15,14 @@ ath11k-y += core.o \ ...@@ -15,12 +15,14 @@ ath11k-y += core.o \
dp_rx.o \ dp_rx.o \
debug.o \ debug.o \
ce.o \ ce.o \
peer.o peer.o \
dbring.o
ath11k-$(CONFIG_ATH11K_DEBUGFS) += debug_htt_stats.o debugfs_sta.o ath11k-$(CONFIG_ATH11K_DEBUGFS) += debug_htt_stats.o debugfs_sta.o
ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o
ath11k-$(CONFIG_ATH11K_TRACING) += trace.o ath11k-$(CONFIG_ATH11K_TRACING) += trace.o
ath11k-$(CONFIG_THERMAL) += thermal.o ath11k-$(CONFIG_THERMAL) += thermal.o
ath11k-$(CONFIG_ATH11K_SPECTRAL) += spectral.o
# for tracing framework to find trace.h # for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src) CFLAGS_trace.o := -I$(src)
...@@ -400,8 +400,16 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab) ...@@ -400,8 +400,16 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab)
goto err_dp_pdev_free; goto err_dp_pdev_free;
} }
ret = ath11k_spectral_init(ab);
if (ret) {
ath11k_err(ab, "failed to init spectral %d\n", ret);
goto err_thermal_unregister;
}
return 0; return 0;
err_thermal_unregister:
ath11k_thermal_unregister(ab);
err_dp_pdev_free: err_dp_pdev_free:
ath11k_dp_pdev_free(ab); ath11k_dp_pdev_free(ab);
err_mac_unregister: err_mac_unregister:
...@@ -414,6 +422,7 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab) ...@@ -414,6 +422,7 @@ static int ath11k_core_pdev_create(struct ath11k_base *ab)
static void ath11k_core_pdev_destroy(struct ath11k_base *ab) static void ath11k_core_pdev_destroy(struct ath11k_base *ab)
{ {
ath11k_spectral_deinit(ab);
ath11k_thermal_unregister(ab); ath11k_thermal_unregister(ab);
ath11k_mac_unregister(ab); ath11k_mac_unregister(ab);
ath11k_hif_irq_disable(ab); ath11k_hif_irq_disable(ab);
...@@ -582,6 +591,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab) ...@@ -582,6 +591,7 @@ static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)
ath11k_thermal_unregister(ab); ath11k_thermal_unregister(ab);
ath11k_hif_irq_disable(ab); ath11k_hif_irq_disable(ab);
ath11k_dp_pdev_free(ab); ath11k_dp_pdev_free(ab);
ath11k_spectral_deinit(ab);
ath11k_hif_stop(ab); ath11k_hif_stop(ab);
ath11k_wmi_detach(ab); ath11k_wmi_detach(ab);
ath11k_dp_pdev_reo_cleanup(ab); ath11k_dp_pdev_reo_cleanup(ab);
......
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include "hal_rx.h" #include "hal_rx.h"
#include "reg.h" #include "reg.h"
#include "thermal.h" #include "thermal.h"
#include "dbring.h"
#include "spectral.h"
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
...@@ -215,12 +217,15 @@ struct ath11k_vif { ...@@ -215,12 +217,15 @@ struct ath11k_vif {
bool is_started; bool is_started;
bool is_up; bool is_up;
bool spectral_enabled;
u32 aid; u32 aid;
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
struct cfg80211_bitrate_mask bitrate_mask; struct cfg80211_bitrate_mask bitrate_mask;
int num_legacy_stations; int num_legacy_stations;
int rtscts_prot_mode; int rtscts_prot_mode;
int txpower; int txpower;
bool rsnie_present;
bool wpaie_present;
}; };
struct ath11k_vif_iter { struct ath11k_vif_iter {
...@@ -353,7 +358,10 @@ struct ath11k_sta { ...@@ -353,7 +358,10 @@ struct ath11k_sta {
#endif #endif
}; };
#define ATH11K_NUM_CHANS 41 #define ATH11K_MIN_5G_FREQ 4150
#define ATH11K_MIN_6G_FREQ 5945
#define ATH11K_MAX_6G_FREQ 7115
#define ATH11K_NUM_CHANS 100
#define ATH11K_MAX_5G_CHAN 173 #define ATH11K_MAX_5G_CHAN 173
enum ath11k_state { enum ath11k_state {
...@@ -431,6 +439,7 @@ struct ath11k { ...@@ -431,6 +439,7 @@ struct ath11k {
u32 vht_cap_info; u32 vht_cap_info;
struct ath11k_he ar_he; struct ath11k_he ar_he;
enum ath11k_state state; enum ath11k_state state;
bool supports_6ghz;
struct { struct {
struct completion started; struct completion started;
struct completion completed; struct completion completed;
...@@ -536,6 +545,9 @@ struct ath11k { ...@@ -536,6 +545,9 @@ struct ath11k {
u32 cached_ppdu_id; u32 cached_ppdu_id;
#ifdef CONFIG_ATH11K_DEBUGFS #ifdef CONFIG_ATH11K_DEBUGFS
struct ath11k_debug debug; struct ath11k_debug debug;
#endif
#ifdef CONFIG_ATH11K_SPECTRAL
struct ath11k_spectral spectral;
#endif #endif
bool dfs_block_radar_events; bool dfs_block_radar_events;
struct ath11k_thermal thermal; struct ath11k_thermal thermal;
...@@ -548,6 +560,7 @@ struct ath11k_band_cap { ...@@ -548,6 +560,7 @@ struct ath11k_band_cap {
u32 he_mcs; u32 he_mcs;
u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE]; u32 he_cap_phy_info[PSOC_HOST_MAX_PHY_SIZE];
struct ath11k_ppe_threshold he_ppet; struct ath11k_ppe_threshold he_ppet;
u16 he_6ghz_capa;
}; };
struct ath11k_pdev_cap { struct ath11k_pdev_cap {
...@@ -579,12 +592,42 @@ struct ath11k_board_data { ...@@ -579,12 +592,42 @@ struct ath11k_board_data {
/* IPQ8074 HW channel counters frequency value in hertz */ /* IPQ8074 HW channel counters frequency value in hertz */
#define IPQ8074_CC_FREQ_HERTZ 320000 #define IPQ8074_CC_FREQ_HERTZ 320000
struct ath11k_soc_dp_rx_stats { struct ath11k_bp_stats {
/* Head Pointer reported by the last HTT Backpressure event for the ring */
u16 hp;
/* Tail Pointer reported by the last HTT Backpressure event for the ring */
u16 tp;
/* Number of Backpressure events received for the ring */
u32 count;
/* Last recorded event timestamp */
unsigned long jiffies;
};
struct ath11k_dp_ring_bp_stats {
struct ath11k_bp_stats umac_ring_bp_stats[HTT_SW_UMAC_RING_IDX_MAX];
struct ath11k_bp_stats lmac_ring_bp_stats[HTT_SW_LMAC_RING_IDX_MAX][MAX_RADIOS];
};
struct ath11k_soc_dp_tx_err_stats {
/* TCL Ring Descriptor unavailable */
u32 desc_na[DP_TCL_NUM_RING_MAX];
/* Other failures during dp_tx due to mem allocation failure
* idr unavailable etc.
*/
atomic_t misc_fail;
};
struct ath11k_soc_dp_stats {
u32 err_ring_pkts; u32 err_ring_pkts;
u32 invalid_rbm; u32 invalid_rbm;
u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX]; u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX];
u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX]; u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX];
u32 hal_reo_error[DP_REO_DST_RING_MAX]; u32 hal_reo_error[DP_REO_DST_RING_MAX];
struct ath11k_soc_dp_tx_err_stats tx_err;
struct ath11k_dp_ring_bp_stats bp_stats;
}; };
/* Master structure to hold the hw data which may be used in core module */ /* Master structure to hold the hw data which may be used in core module */
...@@ -653,7 +696,7 @@ struct ath11k_base { ...@@ -653,7 +696,7 @@ struct ath11k_base {
struct dentry *debugfs_soc; struct dentry *debugfs_soc;
struct dentry *debugfs_ath11k; struct dentry *debugfs_ath11k;
#endif #endif
struct ath11k_soc_dp_rx_stats soc_stats; struct ath11k_soc_dp_stats soc_stats;
unsigned long dev_flags; unsigned long dev_flags;
struct completion driver_recovery; struct completion driver_recovery;
...@@ -668,6 +711,9 @@ struct ath11k_base { ...@@ -668,6 +711,9 @@ struct ath11k_base {
/* Round robbin based TCL ring selector */ /* Round robbin based TCL ring selector */
atomic_t tcl_ring_selector; atomic_t tcl_ring_selector;
struct ath11k_dbring_cap *db_caps;
u32 num_db_cap;
/* must be last */ /* must be last */
u8 drv_priv[0] __aligned(sizeof(void *)); u8 drv_priv[0] __aligned(sizeof(void *));
}; };
......
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
*/
#include "core.h"
#include "debug.h"
static int ath11k_dbring_bufs_replenish(struct ath11k *ar,
struct ath11k_dbring *ring,
struct ath11k_dbring_element *buff,
gfp_t gfp)
{
struct ath11k_base *ab = ar->ab;
struct hal_srng *srng;
dma_addr_t paddr;
void *ptr_aligned, *ptr_unaligned, *desc;
int ret;
int buf_id;
u32 cookie;
srng = &ab->hal.srng_list[ring->refill_srng.ring_id];
lockdep_assert_held(&srng->lock);
ath11k_hal_srng_access_begin(ab, srng);
ptr_unaligned = buff->payload;
ptr_aligned = PTR_ALIGN(ptr_unaligned, ring->buf_align);
paddr = dma_map_single(ab->dev, ptr_aligned, ring->buf_sz,
DMA_FROM_DEVICE);
ret = dma_mapping_error(ab->dev, paddr);
if (ret)
goto err;
spin_lock_bh(&ring->idr_lock);
buf_id = idr_alloc(&ring->bufs_idr, buff, 0, ring->bufs_max, gfp);
spin_unlock_bh(&ring->idr_lock);
if (buf_id < 0) {
ret = -ENOBUFS;
goto err_dma_unmap;
}
desc = ath11k_hal_srng_src_get_next_entry(ab, srng);
if (!desc) {
ret = -ENOENT;
goto err_idr_remove;
}
buff->paddr = paddr;
cookie = FIELD_PREP(DP_RXDMA_BUF_COOKIE_PDEV_ID, ar->pdev_idx) |
FIELD_PREP(DP_RXDMA_BUF_COOKIE_BUF_ID, buf_id);
ath11k_hal_rx_buf_addr_info_set(desc, paddr, cookie, 0);
ath11k_hal_srng_access_end(ab, srng);
return 0;
err_idr_remove:
spin_lock_bh(&ring->idr_lock);
idr_remove(&ring->bufs_idr, buf_id);
spin_unlock_bh(&ring->idr_lock);
err_dma_unmap:
dma_unmap_single(ab->dev, paddr, ring->buf_sz,
DMA_FROM_DEVICE);
err:
ath11k_hal_srng_access_end(ab, srng);
return ret;
}
static int ath11k_dbring_fill_bufs(struct ath11k *ar,
struct ath11k_dbring *ring,
gfp_t gfp)
{
struct ath11k_dbring_element *buff;
struct hal_srng *srng;
int num_remain, req_entries, num_free;
u32 align;
int size, ret;
srng = &ar->ab->hal.srng_list[ring->refill_srng.ring_id];
spin_lock_bh(&srng->lock);
num_free = ath11k_hal_srng_src_num_free(ar->ab, srng, true);
req_entries = min(num_free, ring->bufs_max);
num_remain = req_entries;
align = ring->buf_align;
size = sizeof(*buff) + ring->buf_sz + align - 1;
while (num_remain > 0) {
buff = kzalloc(size, gfp);
if (!buff)
break;
ret = ath11k_dbring_bufs_replenish(ar, ring, buff, gfp);
if (ret) {
ath11k_warn(ar->ab, "failed to replenish db ring num_remain %d req_ent %d\n",
num_remain, req_entries);
kfree(buff);
break;
}
num_remain--;
}
spin_unlock_bh(&srng->lock);
return num_remain;
}
int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar,
struct ath11k_dbring *ring,
enum wmi_direct_buffer_module id)
{
struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd param = {0};
int ret;
if (id >= WMI_DIRECT_BUF_MAX)
return -EINVAL;
param.pdev_id = DP_SW2HW_MACID(ring->pdev_id);
param.module_id = id;
param.base_paddr_lo = lower_32_bits(ring->refill_srng.paddr);
param.base_paddr_hi = upper_32_bits(ring->refill_srng.paddr);
param.head_idx_paddr_lo = lower_32_bits(ring->hp_addr);
param.head_idx_paddr_hi = upper_32_bits(ring->hp_addr);
param.tail_idx_paddr_lo = lower_32_bits(ring->tp_addr);
param.tail_idx_paddr_hi = upper_32_bits(ring->tp_addr);
param.num_elems = ring->bufs_max;
param.buf_size = ring->buf_sz;
param.num_resp_per_event = ring->num_resp_per_event;
param.event_timeout_ms = ring->event_timeout_ms;
ret = ath11k_wmi_pdev_dma_ring_cfg(ar, &param);
if (ret) {
ath11k_warn(ar->ab, "failed to setup db ring cfg\n");
return ret;
}
return 0;
}
int ath11k_dbring_set_cfg(struct ath11k *ar, struct ath11k_dbring *ring,
u32 num_resp_per_event, u32 event_timeout_ms,
int (*handler)(struct ath11k *,
struct ath11k_dbring_data *))
{
if (WARN_ON(!ring))
return -EINVAL;
ring->num_resp_per_event = num_resp_per_event;
ring->event_timeout_ms = event_timeout_ms;
ring->handler = handler;
return 0;
}
int ath11k_dbring_buf_setup(struct ath11k *ar,
struct ath11k_dbring *ring,
struct ath11k_dbring_cap *db_cap)
{
struct ath11k_base *ab = ar->ab;
struct hal_srng *srng;
int ret;
srng = &ab->hal.srng_list[ring->refill_srng.ring_id];
ring->bufs_max = ring->refill_srng.size /
ath11k_hal_srng_get_entrysize(HAL_RXDMA_DIR_BUF);
ring->buf_sz = db_cap->min_buf_sz;
ring->buf_align = db_cap->min_buf_align;
ring->pdev_id = db_cap->pdev_id;
ring->hp_addr = ath11k_hal_srng_get_hp_addr(ar->ab, srng);
ring->tp_addr = ath11k_hal_srng_get_tp_addr(ar->ab, srng);
ret = ath11k_dbring_fill_bufs(ar, ring, GFP_KERNEL);
return ret;
}
int ath11k_dbring_srng_setup(struct ath11k *ar, struct ath11k_dbring *ring,
int ring_num, int num_entries)
{
int ret;
ret = ath11k_dp_srng_setup(ar->ab, &ring->refill_srng, HAL_RXDMA_DIR_BUF,
ring_num, ar->pdev_idx, num_entries);
if (ret < 0) {
ath11k_warn(ar->ab, "failed to setup srng: %d ring_id %d\n",
ret, ring_num);
goto err;
}
return 0;
err:
ath11k_dp_srng_cleanup(ar->ab, &ring->refill_srng);
return ret;
}
int ath11k_dbring_get_cap(struct ath11k_base *ab,
u8 pdev_idx,
enum wmi_direct_buffer_module id,
struct ath11k_dbring_cap *db_cap)
{
int i;
if (!ab->num_db_cap || !ab->db_caps)
return -ENOENT;
if (id >= WMI_DIRECT_BUF_MAX)
return -EINVAL;
for (i = 0; i < ab->num_db_cap; i++) {
if (pdev_idx == ab->db_caps[i].pdev_id &&
id == ab->db_caps[i].id) {
*db_cap = ab->db_caps[i];
return 0;
}
}
return -ENOENT;
}
int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,
struct ath11k_dbring_buf_release_event *ev)
{
struct ath11k_dbring *ring;
struct hal_srng *srng;
struct ath11k *ar;
struct ath11k_dbring_element *buff;
struct ath11k_dbring_data handler_data;
struct ath11k_buffer_addr desc;
u8 *vaddr_unalign;
u32 num_entry, num_buff_reaped;
u8 pdev_idx, rbm;
u32 cookie;
int buf_id;
int size;
dma_addr_t paddr;
int ret = 0;
pdev_idx = ev->fixed.pdev_id;
if (pdev_idx >= ab->num_radios) {
ath11k_warn(ab, "Invalid pdev id %d\n", pdev_idx);
return -EINVAL;
}
if (ev->fixed.num_buf_release_entry !=
ev->fixed.num_meta_data_entry) {
ath11k_warn(ab, "Buffer entry %d mismatch meta entry %d\n",
ev->fixed.num_buf_release_entry,
ev->fixed.num_meta_data_entry);
return -EINVAL;
}
ar = ab->pdevs[pdev_idx].ar;
rcu_read_lock();
if (!rcu_dereference(ab->pdevs_active[pdev_idx])) {
ret = -EINVAL;
goto rcu_unlock;
}
switch (ev->fixed.module_id) {
case WMI_DIRECT_BUF_SPECTRAL:
ring = ath11k_spectral_get_dbring(ar);
break;
default:
ring = NULL;
ath11k_warn(ab, "Recv dma buffer release ev on unsupp module %d\n",
ev->fixed.module_id);
break;
}
if (!ring) {
ret = -EINVAL;
goto rcu_unlock;
}
srng = &ab->hal.srng_list[ring->refill_srng.ring_id];
num_entry = ev->fixed.num_buf_release_entry;
size = sizeof(*buff) + ring->buf_sz + ring->buf_align - 1;
num_buff_reaped = 0;
spin_lock_bh(&srng->lock);
while (num_buff_reaped < num_entry) {
desc.info0 = ev->buf_entry[num_buff_reaped].paddr_lo;
desc.info1 = ev->buf_entry[num_buff_reaped].paddr_hi;
handler_data.meta = ev->meta_data[num_buff_reaped];
num_buff_reaped++;
ath11k_hal_rx_buf_addr_info_get(&desc, &paddr, &cookie, &rbm);
buf_id = FIELD_GET(DP_RXDMA_BUF_COOKIE_BUF_ID, cookie);
spin_lock_bh(&ring->idr_lock);
buff = idr_find(&ring->bufs_idr, buf_id);
if (!buff) {
spin_unlock_bh(&ring->idr_lock);
continue;
}
idr_remove(&ring->bufs_idr, buf_id);
spin_unlock_bh(&ring->idr_lock);
dma_unmap_single(ab->dev, buff->paddr, ring->buf_sz,
DMA_FROM_DEVICE);
if (ring->handler) {
vaddr_unalign = buff->payload;
handler_data.data = PTR_ALIGN(vaddr_unalign,
ring->buf_align);
handler_data.data_sz = ring->buf_sz;
ring->handler(ar, &handler_data);
}
memset(buff, 0, size);
ath11k_dbring_bufs_replenish(ar, ring, buff, GFP_ATOMIC);
}
spin_unlock_bh(&srng->lock);
rcu_unlock:
rcu_read_unlock();
return ret;
}
void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring)
{
ath11k_dp_srng_cleanup(ar->ab, &ring->refill_srng);
}
void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring)
{
struct ath11k_dbring_element *buff;
int buf_id;
spin_lock_bh(&ring->idr_lock);
idr_for_each_entry(&ring->bufs_idr, buff, buf_id) {
idr_remove(&ring->bufs_idr, buf_id);
dma_unmap_single(ar->ab->dev, buff->paddr,
ring->buf_sz, DMA_FROM_DEVICE);
kfree(buff);
}
idr_destroy(&ring->bufs_idr);
spin_unlock_bh(&ring->idr_lock);
}
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
*/
#ifndef ATH11K_DBRING_H
#define ATH11K_DBRING_H
#include <linux/types.h>
#include <linux/idr.h>
#include <linux/spinlock.h>
#include "dp.h"
struct ath11k_dbring_element {
dma_addr_t paddr;
u8 payload[0];
};
struct ath11k_dbring_data {
void *data;
u32 data_sz;
struct wmi_dma_buf_release_meta_data meta;
};
struct ath11k_dbring_buf_release_event {
struct ath11k_wmi_dma_buf_release_fixed_param fixed;
struct wmi_dma_buf_release_entry *buf_entry;
struct wmi_dma_buf_release_meta_data *meta_data;
u32 num_buf_entry;
u32 num_meta;
};
struct ath11k_dbring_cap {
u32 pdev_id;
enum wmi_direct_buffer_module id;
u32 min_elem;
u32 min_buf_sz;
u32 min_buf_align;
};
struct ath11k_dbring {
struct dp_srng refill_srng;
struct idr bufs_idr;
/* Protects bufs_idr */
spinlock_t idr_lock;
dma_addr_t tp_addr;
dma_addr_t hp_addr;
int bufs_max;
u32 pdev_id;
u32 buf_sz;
u32 buf_align;
u32 num_resp_per_event;
u32 event_timeout_ms;
int (*handler)(struct ath11k *, struct ath11k_dbring_data *);
};
int ath11k_dbring_set_cfg(struct ath11k *ar,
struct ath11k_dbring *ring,
u32 num_resp_per_event,
u32 event_timeout_ms,
int (*handler)(struct ath11k *,
struct ath11k_dbring_data *));
int ath11k_dbring_wmi_cfg_setup(struct ath11k *ar,
struct ath11k_dbring *ring,
enum wmi_direct_buffer_module id);
int ath11k_dbring_buf_setup(struct ath11k *ar,
struct ath11k_dbring *ring,
struct ath11k_dbring_cap *db_cap);
int ath11k_dbring_srng_setup(struct ath11k *ar, struct ath11k_dbring *ring,
int ring_num, int num_entries);
int ath11k_dbring_buffer_release_event(struct ath11k_base *ab,
struct ath11k_dbring_buf_release_event *ev);
int ath11k_dbring_get_cap(struct ath11k_base *ab,
u8 pdev_idx,
enum wmi_direct_buffer_module id,
struct ath11k_dbring_cap *db_cap);
void ath11k_dbring_srng_cleanup(struct ath11k *ar, struct ath11k_dbring *ring);
void ath11k_dbring_buf_cleanup(struct ath11k *ar, struct ath11k_dbring *ring);
#endif /* ATH11K_DBRING_H */
...@@ -12,6 +12,43 @@ ...@@ -12,6 +12,43 @@
#include "debug_htt_stats.h" #include "debug_htt_stats.h"
#include "peer.h" #include "peer.h"
static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
"REO2SW1_RING",
"REO2SW2_RING",
"REO2SW3_RING",
"REO2SW4_RING",
"WBM2REO_LINK_RING",
"REO2TCL_RING",
"REO2FW_RING",
"RELEASE_RING",
"PPE_RELEASE_RING",
"TCL2TQM_RING",
"TQM_RELEASE_RING",
"REO_RELEASE_RING",
"WBM2SW0_RELEASE_RING",
"WBM2SW1_RELEASE_RING",
"WBM2SW2_RELEASE_RING",
"WBM2SW3_RELEASE_RING",
"REO_CMD_RING",
"REO_STATUS_RING",
};
static const char *htt_bp_lmac_ring[HTT_SW_LMAC_RING_IDX_MAX] = {
"FW2RXDMA_BUF_RING",
"FW2RXDMA_STATUS_RING",
"FW2RXDMA_LINK_RING",
"SW2RXDMA_BUF_RING",
"WBM2RXDMA_LINK_RING",
"RXDMA2FW_RING",
"RXDMA2SW_RING",
"RXDMA2RELEASE_RING",
"RXDMA2REO_RING",
"MONITOR_STATUS_RING",
"MONITOR_BUF_RING",
"MONITOR_DESC_RING",
"MONITOR_DEST_RING",
};
void ath11k_info(struct ath11k_base *ab, const char *fmt, ...) void ath11k_info(struct ath11k_base *ab, const char *fmt, ...)
{ {
struct va_format vaf = { struct va_format vaf = {
...@@ -739,12 +776,78 @@ static const struct file_operations fops_extd_rx_stats = { ...@@ -739,12 +776,78 @@ static const struct file_operations fops_extd_rx_stats = {
.open = simple_open, .open = simple_open,
}; };
static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file, static int ath11k_fill_bp_stats(struct ath11k_base *ab,
struct ath11k_bp_stats *bp_stats,
char *buf, int len, int size)
{
lockdep_assert_held(&ab->base_lock);
len += scnprintf(buf + len, size - len, "count: %u\n",
bp_stats->count);
len += scnprintf(buf + len, size - len, "hp: %u\n",
bp_stats->hp);
len += scnprintf(buf + len, size - len, "tp: %u\n",
bp_stats->tp);
len += scnprintf(buf + len, size - len, "seen before: %ums\n\n",
jiffies_to_msecs(jiffies - bp_stats->jiffies));
return len;
}
static ssize_t ath11k_debug_dump_soc_ring_bp_stats(struct ath11k_base *ab,
char *buf, int size)
{
struct ath11k_bp_stats *bp_stats;
bool stats_rxd = false;
u8 i, pdev_idx;
int len = 0;
len += scnprintf(buf + len, size - len, "\nBackpressure Stats\n");
len += scnprintf(buf + len, size - len, "==================\n");
spin_lock_bh(&ab->base_lock);
for (i = 0; i < HTT_SW_UMAC_RING_IDX_MAX; i++) {
bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[i];
if (!bp_stats->count)
continue;
len += scnprintf(buf + len, size - len, "Ring: %s\n",
htt_bp_umac_ring[i]);
len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
stats_rxd = true;
}
for (i = 0; i < HTT_SW_LMAC_RING_IDX_MAX; i++) {
for (pdev_idx = 0; pdev_idx < MAX_RADIOS; pdev_idx++) {
bp_stats =
&ab->soc_stats.bp_stats.lmac_ring_bp_stats[i][pdev_idx];
if (!bp_stats->count)
continue;
len += scnprintf(buf + len, size - len, "Ring: %s\n",
htt_bp_lmac_ring[i]);
len += scnprintf(buf + len, size - len, "pdev: %d\n",
pdev_idx);
len = ath11k_fill_bp_stats(ab, bp_stats, buf, len, size);
stats_rxd = true;
}
}
spin_unlock_bh(&ab->base_lock);
if (!stats_rxd)
len += scnprintf(buf + len, size - len,
"No Ring Backpressure stats received\n\n");
return len;
}
static ssize_t ath11k_debug_dump_soc_dp_stats(struct file *file,
char __user *user_buf, char __user *user_buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct ath11k_base *ab = file->private_data; struct ath11k_base *ab = file->private_data;
struct ath11k_soc_dp_rx_stats *soc_stats = &ab->soc_stats; struct ath11k_soc_dp_stats *soc_stats = &ab->soc_stats;
int len = 0, i, retval; int len = 0, i, retval;
const int size = 4096; const int size = 4096;
static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = { static const char *rxdma_err[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX] = {
...@@ -788,6 +891,19 @@ static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file, ...@@ -788,6 +891,19 @@ static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file,
soc_stats->hal_reo_error[2], soc_stats->hal_reo_error[2],
soc_stats->hal_reo_error[3]); soc_stats->hal_reo_error[3]);
len += scnprintf(buf + len, size - len, "\nSOC TX STATS:\n");
len += scnprintf(buf + len, size - len, "\nTCL Ring Full Failures:\n");
for (i = 0; i < DP_TCL_NUM_RING_MAX; i++)
len += scnprintf(buf + len, size - len, "ring%d: %u\n",
i, soc_stats->tx_err.desc_na[i]);
len += scnprintf(buf + len, size - len,
"\nMisc Transmit Failures: %d\n",
atomic_read(&soc_stats->tx_err.misc_fail));
len += ath11k_debug_dump_soc_ring_bp_stats(ab, buf + len, size - len);
if (len > size) if (len > size)
len = size; len = size;
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len); retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
...@@ -796,8 +912,8 @@ static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file, ...@@ -796,8 +912,8 @@ static ssize_t ath11k_debug_dump_soc_rx_stats(struct file *file,
return retval; return retval;
} }
static const struct file_operations fops_soc_rx_stats = { static const struct file_operations fops_soc_dp_stats = {
.read = ath11k_debug_dump_soc_rx_stats, .read = ath11k_debug_dump_soc_dp_stats,
.open = simple_open, .open = simple_open,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = default_llseek, .llseek = default_llseek,
...@@ -819,8 +935,8 @@ int ath11k_debug_pdev_create(struct ath11k_base *ab) ...@@ -819,8 +935,8 @@ int ath11k_debug_pdev_create(struct ath11k_base *ab)
debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab, debugfs_create_file("simulate_fw_crash", 0600, ab->debugfs_soc, ab,
&fops_simulate_fw_crash); &fops_simulate_fw_crash);
debugfs_create_file("soc_rx_stats", 0600, ab->debugfs_soc, ab, debugfs_create_file("soc_dp_stats", 0600, ab->debugfs_soc, ab,
&fops_soc_rx_stats); &fops_soc_dp_stats);
return 0; return 0;
} }
......
...@@ -172,11 +172,12 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring, ...@@ -172,11 +172,12 @@ int ath11k_dp_srng_setup(struct ath11k_base *ab, struct dp_srng *ring,
case HAL_RXDMA_DST: case HAL_RXDMA_DST:
case HAL_RXDMA_MONITOR_DST: case HAL_RXDMA_MONITOR_DST:
case HAL_RXDMA_MONITOR_DESC: case HAL_RXDMA_MONITOR_DESC:
case HAL_RXDMA_DIR_BUF:
params.intr_batch_cntr_thres_entries = params.intr_batch_cntr_thres_entries =
HAL_SRNG_INT_BATCH_THRESHOLD_OTHER; HAL_SRNG_INT_BATCH_THRESHOLD_OTHER;
params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_OTHER; params.intr_timer_thres_us = HAL_SRNG_INT_TIMER_THRESHOLD_OTHER;
break; break;
case HAL_RXDMA_DIR_BUF:
break;
default: default:
ath11k_warn(ab, "Not a valid ring type in dp :%d\n", type); ath11k_warn(ab, "Not a valid ring type in dp :%d\n", type);
return -EINVAL; return -EINVAL;
......
...@@ -999,6 +999,48 @@ struct htt_resp_msg { ...@@ -999,6 +999,48 @@ struct htt_resp_msg {
#define HTT_BACKPRESSURE_EVENT_HP_M GENMASK(15, 0) #define HTT_BACKPRESSURE_EVENT_HP_M GENMASK(15, 0)
#define HTT_BACKPRESSURE_EVENT_TP_M GENMASK(31, 16) #define HTT_BACKPRESSURE_EVENT_TP_M GENMASK(31, 16)
#define HTT_BACKPRESSURE_UMAC_RING_TYPE 0
#define HTT_BACKPRESSURE_LMAC_RING_TYPE 1
enum htt_backpressure_umac_ringid {
HTT_SW_RING_IDX_REO_REO2SW1_RING,
HTT_SW_RING_IDX_REO_REO2SW2_RING,
HTT_SW_RING_IDX_REO_REO2SW3_RING,
HTT_SW_RING_IDX_REO_REO2SW4_RING,
HTT_SW_RING_IDX_REO_WBM2REO_LINK_RING,
HTT_SW_RING_IDX_REO_REO2TCL_RING,
HTT_SW_RING_IDX_REO_REO2FW_RING,
HTT_SW_RING_IDX_REO_REO_RELEASE_RING,
HTT_SW_RING_IDX_WBM_PPE_RELEASE_RING,
HTT_SW_RING_IDX_TCL_TCL2TQM_RING,
HTT_SW_RING_IDX_WBM_TQM_RELEASE_RING,
HTT_SW_RING_IDX_WBM_REO_RELEASE_RING,
HTT_SW_RING_IDX_WBM_WBM2SW0_RELEASE_RING,
HTT_SW_RING_IDX_WBM_WBM2SW1_RELEASE_RING,
HTT_SW_RING_IDX_WBM_WBM2SW2_RELEASE_RING,
HTT_SW_RING_IDX_WBM_WBM2SW3_RELEASE_RING,
HTT_SW_RING_IDX_REO_REO_CMD_RING,
HTT_SW_RING_IDX_REO_REO_STATUS_RING,
HTT_SW_UMAC_RING_IDX_MAX,
};
enum htt_backpressure_lmac_ringid {
HTT_SW_RING_IDX_FW2RXDMA_BUF_RING,
HTT_SW_RING_IDX_FW2RXDMA_STATUS_RING,
HTT_SW_RING_IDX_FW2RXDMA_LINK_RING,
HTT_SW_RING_IDX_SW2RXDMA_BUF_RING,
HTT_SW_RING_IDX_WBM2RXDMA_LINK_RING,
HTT_SW_RING_IDX_RXDMA2FW_RING,
HTT_SW_RING_IDX_RXDMA2SW_RING,
HTT_SW_RING_IDX_RXDMA2RELEASE_RING,
HTT_SW_RING_IDX_RXDMA2REO_RING,
HTT_SW_RING_IDX_MONITOR_STATUS_RING,
HTT_SW_RING_IDX_MONITOR_BUF_RING,
HTT_SW_RING_IDX_MONITOR_DESC_RING,
HTT_SW_RING_IDX_MONITOR_DEST_RING,
HTT_SW_LMAC_RING_IDX_MAX,
};
/* ppdu stats /* ppdu stats
* *
* @details * @details
......
...@@ -653,10 +653,8 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx, ...@@ -653,10 +653,8 @@ static void ath11k_dp_rx_tid_del_func(struct ath11k_dp *dp, void *ctx,
spin_lock_bh(&dp->reo_cmd_lock); spin_lock_bh(&dp->reo_cmd_lock);
list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list); list_add_tail(&elem->list, &dp->reo_cmd_cache_flush_list);
dp->reo_cmd_cache_flush_count++; dp->reo_cmd_cache_flush_count++;
spin_unlock_bh(&dp->reo_cmd_lock);
/* Flush and invalidate aged REO desc from HW cache */ /* Flush and invalidate aged REO desc from HW cache */
spin_lock_bh(&dp->reo_cmd_lock);
list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list, list_for_each_entry_safe(elem, tmp, &dp->reo_cmd_cache_flush_list,
list) { list) {
if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD || if (dp->reo_cmd_cache_flush_count > DP_REO_DESC_FREE_THRESHOLD ||
...@@ -1503,9 +1501,10 @@ static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab, ...@@ -1503,9 +1501,10 @@ static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab,
struct sk_buff *skb) struct sk_buff *skb)
{ {
u32 *data = (u32 *)skb->data; u32 *data = (u32 *)skb->data;
u8 pdev_id, ring_type, ring_id; u8 pdev_id, ring_type, ring_id, pdev_idx;
u16 hp, tp; u16 hp, tp;
u32 backpressure_time; u32 backpressure_time;
struct ath11k_bp_stats *bp_stats;
pdev_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_PDEV_ID_M, *data); pdev_id = FIELD_GET(HTT_BACKPRESSURE_EVENT_PDEV_ID_M, *data);
ring_type = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_TYPE_M, *data); ring_type = FIELD_GET(HTT_BACKPRESSURE_EVENT_RING_TYPE_M, *data);
...@@ -1520,6 +1519,31 @@ static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab, ...@@ -1520,6 +1519,31 @@ static void ath11k_htt_backpressure_event_handler(struct ath11k_base *ab,
ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt backpressure event, pdev %d, ring type %d,ring id %d, hp %d tp %d, backpressure time %d\n", ath11k_dbg(ab, ATH11K_DBG_DP_HTT, "htt backpressure event, pdev %d, ring type %d,ring id %d, hp %d tp %d, backpressure time %d\n",
pdev_id, ring_type, ring_id, hp, tp, backpressure_time); pdev_id, ring_type, ring_id, hp, tp, backpressure_time);
if (ring_type == HTT_BACKPRESSURE_UMAC_RING_TYPE) {
if (ring_id >= HTT_SW_UMAC_RING_IDX_MAX)
return;
bp_stats = &ab->soc_stats.bp_stats.umac_ring_bp_stats[ring_id];
} else if (ring_type == HTT_BACKPRESSURE_LMAC_RING_TYPE) {
pdev_idx = DP_HW2SW_MACID(pdev_id);
if (ring_id >= HTT_SW_LMAC_RING_IDX_MAX || pdev_idx >= MAX_RADIOS)
return;
bp_stats = &ab->soc_stats.bp_stats.lmac_ring_bp_stats[ring_id][pdev_idx];
} else {
ath11k_warn(ab, "unknown ring type received in htt bp event %d\n",
ring_type);
return;
}
spin_lock_bh(&ab->base_lock);
bp_stats->hp = hp;
bp_stats->tp = tp;
bp_stats->count++;
bp_stats->jiffies = jiffies;
spin_unlock_bh(&ab->base_lock);
} }
void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab, void ath11k_dp_htt_htc_t2h_msg_handler(struct ath11k_base *ab,
...@@ -2162,6 +2186,7 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc, ...@@ -2162,6 +2186,7 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
struct ieee80211_rx_status *rx_status) struct ieee80211_rx_status *rx_status)
{ {
u8 channel_num; u8 channel_num;
u32 center_freq;
rx_status->freq = 0; rx_status->freq = 0;
rx_status->rate_idx = 0; rx_status->rate_idx = 0;
...@@ -2172,8 +2197,11 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc, ...@@ -2172,8 +2197,11 @@ static void ath11k_dp_rx_h_ppdu(struct ath11k *ar, struct hal_rx_desc *rx_desc,
rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL; rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
channel_num = ath11k_dp_rx_h_msdu_start_freq(rx_desc); channel_num = ath11k_dp_rx_h_msdu_start_freq(rx_desc);
center_freq = ath11k_dp_rx_h_msdu_start_freq(rx_desc) >> 16;
if (channel_num >= 1 && channel_num <= 14) { if (center_freq >= 5935 && center_freq <= 7105) {
rx_status->band = NL80211_BAND_6GHZ;
} else if (channel_num >= 1 && channel_num <= 14) {
rx_status->band = NL80211_BAND_2GHZ; rx_status->band = NL80211_BAND_2GHZ;
} else if (channel_num >= 36 && channel_num <= 173) { } else if (channel_num >= 36 && channel_num <= 173) {
rx_status->band = NL80211_BAND_5GHZ; rx_status->band = NL80211_BAND_5GHZ;
......
...@@ -121,8 +121,10 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, ...@@ -121,8 +121,10 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
spin_unlock_bh(&tx_ring->tx_idr_lock); spin_unlock_bh(&tx_ring->tx_idr_lock);
if (ret < 0) { if (ret < 0) {
if (ring_map == (BIT(DP_TCL_NUM_RING_MAX) - 1)) if (ring_map == (BIT(DP_TCL_NUM_RING_MAX) - 1)) {
atomic_inc(&ab->soc_stats.tx_err.misc_fail);
return -ENOSPC; return -ENOSPC;
}
/* Check if the next ring is available */ /* Check if the next ring is available */
ring_selector++; ring_selector++;
...@@ -180,11 +182,13 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, ...@@ -180,11 +182,13 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
default: default:
/* TODO: Take care of other encap modes as well */ /* TODO: Take care of other encap modes as well */
ret = -EINVAL; ret = -EINVAL;
atomic_inc(&ab->soc_stats.tx_err.misc_fail);
goto fail_remove_idr; goto fail_remove_idr;
} }
ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE); ti.paddr = dma_map_single(ab->dev, skb->data, skb->len, DMA_TO_DEVICE);
if (dma_mapping_error(ab->dev, ti.paddr)) { if (dma_mapping_error(ab->dev, ti.paddr)) {
atomic_inc(&ab->soc_stats.tx_err.misc_fail);
ath11k_warn(ab, "failed to DMA map data Tx buffer\n"); ath11k_warn(ab, "failed to DMA map data Tx buffer\n");
ret = -ENOMEM; ret = -ENOMEM;
goto fail_remove_idr; goto fail_remove_idr;
...@@ -208,6 +212,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif, ...@@ -208,6 +212,7 @@ int ath11k_dp_tx(struct ath11k *ar, struct ath11k_vif *arvif,
* desc because the desc is directly enqueued onto hw queue. * desc because the desc is directly enqueued onto hw queue.
*/ */
ath11k_hal_srng_access_end(ab, tcl_ring); ath11k_hal_srng_access_end(ab, tcl_ring);
ab->soc_stats.tx_err.desc_na[ti.ring_id]++;
spin_unlock_bh(&tcl_ring->lock); spin_unlock_bh(&tcl_ring->lock);
ret = -ENOMEM; ret = -ENOMEM;
......
...@@ -33,6 +33,15 @@ ...@@ -33,6 +33,15 @@
.max_power = 30, \ .max_power = 30, \
} }
#define CHAN6G(_channel, _freq, _flags) { \
.band = NL80211_BAND_6GHZ, \
.hw_value = (_channel), \
.center_freq = (_freq), \
.flags = (_flags), \
.max_antenna_gain = 0, \
.max_power = 30, \
}
/* frame mode values are mapped as per enum ath11k_hw_txrx_mode */ /* frame mode values are mapped as per enum ath11k_hw_txrx_mode */
static unsigned int ath11k_frame_mode = ATH11K_HW_TXRX_NATIVE_WIFI; static unsigned int ath11k_frame_mode = ATH11K_HW_TXRX_NATIVE_WIFI;
module_param_named(frame_mode, ath11k_frame_mode, uint, 0644); module_param_named(frame_mode, ath11k_frame_mode, uint, 0644);
...@@ -86,6 +95,68 @@ static const struct ieee80211_channel ath11k_5ghz_channels[] = { ...@@ -86,6 +95,68 @@ static const struct ieee80211_channel ath11k_5ghz_channels[] = {
CHAN5G(173, 5865, 0), CHAN5G(173, 5865, 0),
}; };
static const struct ieee80211_channel ath11k_6ghz_channels[] = {
CHAN6G(1, 5955, 0),
CHAN6G(5, 5975, 0),
CHAN6G(9, 5995, 0),
CHAN6G(13, 6015, 0),
CHAN6G(17, 6035, 0),
CHAN6G(21, 6055, 0),
CHAN6G(25, 6075, 0),
CHAN6G(29, 6095, 0),
CHAN6G(33, 6115, 0),
CHAN6G(37, 6135, 0),
CHAN6G(41, 6155, 0),
CHAN6G(45, 6175, 0),
CHAN6G(49, 6195, 0),
CHAN6G(53, 6215, 0),
CHAN6G(57, 6235, 0),
CHAN6G(61, 6255, 0),
CHAN6G(65, 6275, 0),
CHAN6G(69, 6295, 0),
CHAN6G(73, 6315, 0),
CHAN6G(77, 6335, 0),
CHAN6G(81, 6355, 0),
CHAN6G(85, 6375, 0),
CHAN6G(89, 6395, 0),
CHAN6G(93, 6415, 0),
CHAN6G(97, 6435, 0),
CHAN6G(101, 6455, 0),
CHAN6G(105, 6475, 0),
CHAN6G(109, 6495, 0),
CHAN6G(113, 6515, 0),
CHAN6G(117, 6535, 0),
CHAN6G(121, 6555, 0),
CHAN6G(125, 6575, 0),
CHAN6G(129, 6595, 0),
CHAN6G(133, 6615, 0),
CHAN6G(137, 6635, 0),
CHAN6G(141, 6655, 0),
CHAN6G(145, 6675, 0),
CHAN6G(149, 6695, 0),
CHAN6G(153, 6715, 0),
CHAN6G(157, 6735, 0),
CHAN6G(161, 6755, 0),
CHAN6G(165, 6775, 0),
CHAN6G(169, 6795, 0),
CHAN6G(173, 6815, 0),
CHAN6G(177, 6835, 0),
CHAN6G(181, 6855, 0),
CHAN6G(185, 6875, 0),
CHAN6G(189, 6895, 0),
CHAN6G(193, 6915, 0),
CHAN6G(197, 6935, 0),
CHAN6G(201, 6955, 0),
CHAN6G(205, 6975, 0),
CHAN6G(209, 6995, 0),
CHAN6G(213, 7015, 0),
CHAN6G(217, 7035, 0),
CHAN6G(221, 7055, 0),
CHAN6G(225, 7075, 0),
CHAN6G(229, 7095, 0),
CHAN6G(233, 7115, 0),
};
static struct ieee80211_rate ath11k_legacy_rates[] = { static struct ieee80211_rate ath11k_legacy_rates[] = {
{ .bitrate = 10, { .bitrate = 10,
.hw_value = ATH11K_HW_RATE_CCK_LP_1M }, .hw_value = ATH11K_HW_RATE_CCK_LP_1M },
...@@ -134,6 +205,17 @@ ath11k_phymodes[NUM_NL80211_BANDS][ATH11K_CHAN_WIDTH_NUM] = { ...@@ -134,6 +205,17 @@ ath11k_phymodes[NUM_NL80211_BANDS][ATH11K_CHAN_WIDTH_NUM] = {
[NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160, [NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160,
[NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80, [NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80,
}, },
[NL80211_BAND_6GHZ] = {
[NL80211_CHAN_WIDTH_5] = MODE_UNKNOWN,
[NL80211_CHAN_WIDTH_10] = MODE_UNKNOWN,
[NL80211_CHAN_WIDTH_20_NOHT] = MODE_11AX_HE20,
[NL80211_CHAN_WIDTH_20] = MODE_11AX_HE20,
[NL80211_CHAN_WIDTH_40] = MODE_11AX_HE40,
[NL80211_CHAN_WIDTH_80] = MODE_11AX_HE80,
[NL80211_CHAN_WIDTH_160] = MODE_11AX_HE160,
[NL80211_CHAN_WIDTH_80P80] = MODE_11AX_HE80_80,
},
}; };
const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default = { const struct htt_rx_ring_tlv_filter ath11k_mac_mon_status_filter_default = {
...@@ -698,6 +780,8 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) ...@@ -698,6 +780,8 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
struct ieee80211_vif *vif = arvif->vif; struct ieee80211_vif *vif = arvif->vif;
struct ieee80211_mutable_offsets offs = {}; struct ieee80211_mutable_offsets offs = {};
struct sk_buff *bcn; struct sk_buff *bcn;
struct ieee80211_mgmt *mgmt;
u8 *ies;
int ret; int ret;
if (arvif->vdev_type != WMI_VDEV_TYPE_AP) if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
...@@ -709,6 +793,17 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif) ...@@ -709,6 +793,17 @@ static int ath11k_mac_setup_bcn_tmpl(struct ath11k_vif *arvif)
return -EPERM; return -EPERM;
} }
ies = bcn->data + ieee80211_get_hdrlen_from_skb(bcn);
ies += sizeof(mgmt->u.beacon);
if (cfg80211_find_ie(WLAN_EID_RSN, ies, (skb_tail_pointer(bcn) - ies)))
arvif->rsnie_present = true;
if (cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT,
WLAN_OUI_TYPE_MICROSOFT_WPA,
ies, (skb_tail_pointer(bcn) - ies)))
arvif->wpaie_present = true;
ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn); ret = ath11k_wmi_bcn_tmpl(ar, arvif->vdev_id, &offs, bcn);
kfree_skb(bcn); kfree_skb(bcn);
...@@ -798,6 +893,7 @@ static void ath11k_peer_assoc_h_crypto(struct ath11k *ar, ...@@ -798,6 +893,7 @@ static void ath11k_peer_assoc_h_crypto(struct ath11k *ar,
struct ieee80211_bss_conf *info = &vif->bss_conf; struct ieee80211_bss_conf *info = &vif->bss_conf;
struct cfg80211_chan_def def; struct cfg80211_chan_def def;
struct cfg80211_bss *bss; struct cfg80211_bss *bss;
struct ath11k_vif *arvif = (struct ath11k_vif *)vif->drv_priv;
const u8 *rsnie = NULL; const u8 *rsnie = NULL;
const u8 *wpaie = NULL; const u8 *wpaie = NULL;
...@@ -808,7 +904,12 @@ static void ath11k_peer_assoc_h_crypto(struct ath11k *ar, ...@@ -808,7 +904,12 @@ static void ath11k_peer_assoc_h_crypto(struct ath11k *ar,
bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0, bss = cfg80211_get_bss(ar->hw->wiphy, def.chan, info->bssid, NULL, 0,
IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY); IEEE80211_BSS_TYPE_ANY, IEEE80211_PRIVACY_ANY);
if (bss) {
if (arvif->rsnie_present || arvif->wpaie_present) {
arg->need_ptk_4_way = true;
if (arvif->wpaie_present)
arg->need_gtk_2_way = true;
} else if (bss) {
const struct cfg80211_bss_ies *ies; const struct cfg80211_bss_ies *ies;
rcu_read_lock(); rcu_read_lock();
...@@ -1489,6 +1590,7 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar, ...@@ -1489,6 +1590,7 @@ static void ath11k_peer_assoc_h_phymode(struct ath11k *ar,
} }
break; break;
case NL80211_BAND_5GHZ: case NL80211_BAND_5GHZ:
case NL80211_BAND_6GHZ:
/* Check HE first */ /* Check HE first */
if (sta->he_cap.has_he) { if (sta->he_cap.has_he) {
phymode = ath11k_mac_get_phymode_he(ar, sta); phymode = ath11k_mac_get_phymode_he(ar, sta);
...@@ -2125,6 +2227,9 @@ static int ath11k_start_scan(struct ath11k *ar, ...@@ -2125,6 +2227,9 @@ static int ath11k_start_scan(struct ath11k *ar,
lockdep_assert_held(&ar->conf_mutex); lockdep_assert_held(&ar->conf_mutex);
if (ath11k_spectral_get_mode(ar) == ATH11K_SPECTRAL_BACKGROUND)
ath11k_spectral_reset_buffer(ar);
ret = ath11k_wmi_send_scan_start_cmd(ar, arg); ret = ath11k_wmi_send_scan_start_cmd(ar, arg);
if (ret) if (ret)
return ret; return ret;
...@@ -3411,7 +3516,7 @@ static void ath11k_mac_setup_ht_vht_cap(struct ath11k *ar, ...@@ -3411,7 +3516,7 @@ static void ath11k_mac_setup_ht_vht_cap(struct ath11k *ar,
rate_cap_rx_chainmask); rate_cap_rx_chainmask);
} }
if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP) { if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP && !ar->supports_6ghz) {
band = &ar->mac.sbands[NL80211_BAND_5GHZ]; band = &ar->mac.sbands[NL80211_BAND_5GHZ];
ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info; ht_cap = cap->band[NL80211_BAND_5GHZ].ht_cap_info;
if (ht_cap_info) if (ht_cap_info)
...@@ -3532,6 +3637,35 @@ ath11k_mac_filter_he_cap_mesh(struct ieee80211_he_cap_elem *he_cap_elem) ...@@ -3532,6 +3637,35 @@ ath11k_mac_filter_he_cap_mesh(struct ieee80211_he_cap_elem *he_cap_elem)
he_cap_elem->phy_cap_info[9] &= ~m; he_cap_elem->phy_cap_info[9] &= ~m;
} }
static __le16 ath11k_mac_setup_he_6ghz_cap(struct ath11k_pdev_cap *pcap,
struct ath11k_band_cap *bcap)
{
u8 val;
bcap->he_6ghz_capa = IEEE80211_HT_MPDU_DENSITY_NONE;
if (bcap->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
bcap->he_6ghz_capa |=
FIELD_PREP(IEEE80211_HE_6GHZ_CAP_SM_PS,
WLAN_HT_CAP_SM_PS_DYNAMIC);
else
bcap->he_6ghz_capa |=
FIELD_PREP(IEEE80211_HE_6GHZ_CAP_SM_PS,
WLAN_HT_CAP_SM_PS_DISABLED);
val = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
pcap->vht_cap);
bcap->he_6ghz_capa |=
FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP, val);
val = FIELD_GET(IEEE80211_VHT_CAP_MAX_MPDU_MASK, pcap->vht_cap);
bcap->he_6ghz_capa |=
FIELD_PREP(IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN, val);
if (pcap->vht_cap & IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN)
bcap->he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
if (pcap->vht_cap & IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN)
bcap->he_6ghz_capa |= IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS;
return cpu_to_le16(bcap->he_6ghz_capa);
}
static int ath11k_mac_copy_he_cap(struct ath11k *ar, static int ath11k_mac_copy_he_cap(struct ath11k *ar,
struct ath11k_pdev_cap *cap, struct ath11k_pdev_cap *cap,
struct ieee80211_sband_iftype_data *data, struct ieee80211_sband_iftype_data *data,
...@@ -3614,6 +3748,11 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar, ...@@ -3614,6 +3748,11 @@ static int ath11k_mac_copy_he_cap(struct ath11k *ar,
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT)
ath11k_gen_ppe_thresh(&band_cap->he_ppet, ath11k_gen_ppe_thresh(&band_cap->he_ppet,
he_cap->ppe_thres); he_cap->ppe_thres);
if (band == NL80211_BAND_6GHZ) {
data[idx].he_6ghz_capa.capa =
ath11k_mac_setup_he_6ghz_cap(cap, band_cap);
}
idx++; idx++;
} }
...@@ -3643,6 +3782,16 @@ static void ath11k_mac_setup_he_cap(struct ath11k *ar, ...@@ -3643,6 +3782,16 @@ static void ath11k_mac_setup_he_cap(struct ath11k *ar,
band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ]; band->iftype_data = ar->mac.iftype[NL80211_BAND_5GHZ];
band->n_iftype_data = count; band->n_iftype_data = count;
} }
if (cap->supported_bands & WMI_HOST_WLAN_5G_CAP &&
ar->supports_6ghz) {
count = ath11k_mac_copy_he_cap(ar, cap,
ar->mac.iftype[NL80211_BAND_6GHZ],
NL80211_BAND_6GHZ);
band = &ar->mac.sbands[NL80211_BAND_6GHZ];
band->iftype_data = ar->mac.iftype[NL80211_BAND_6GHZ];
band->n_iftype_data = count;
}
} }
static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant) static int __ath11k_set_antenna(struct ath11k *ar, u32 tx_ant, u32 rx_ant)
...@@ -4085,6 +4234,11 @@ ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif, ...@@ -4085,6 +4234,11 @@ ath11k_mac_setup_vdev_create_params(struct ath11k_vif *arvif,
params->chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains; params->chains[NL80211_BAND_5GHZ].tx = ar->num_tx_chains;
params->chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains; params->chains[NL80211_BAND_5GHZ].rx = ar->num_rx_chains;
} }
if (pdev->cap.supported_bands & WMI_HOST_WLAN_5G_CAP &&
ar->supports_6ghz) {
params->chains[NL80211_BAND_6GHZ].tx = ar->num_tx_chains;
params->chains[NL80211_BAND_6GHZ].rx = ar->num_rx_chains;
}
} }
static u32 static u32
...@@ -5217,7 +5371,7 @@ ath11k_mac_get_single_legacy_rate(struct ath11k *ar, ...@@ -5217,7 +5371,7 @@ ath11k_mac_get_single_legacy_rate(struct ath11k *ar,
rate_idx = ffs(mask->control[band].legacy) - 1; rate_idx = ffs(mask->control[band].legacy) - 1;
if (band == NL80211_BAND_5GHZ) if (band == NL80211_BAND_5GHZ || band == NL80211_BAND_6GHZ)
rate_idx += ATH11K_MAC_FIRST_OFDM_RATE_IDX; rate_idx += ATH11K_MAC_FIRST_OFDM_RATE_IDX;
hw_rate = ath11k_legacy_rates[rate_idx].hw_value; hw_rate = ath11k_legacy_rates[rate_idx].hw_value;
...@@ -5683,7 +5837,8 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, ...@@ -5683,7 +5837,8 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar,
void *channels; void *channels;
BUILD_BUG_ON((ARRAY_SIZE(ath11k_2ghz_channels) + BUILD_BUG_ON((ARRAY_SIZE(ath11k_2ghz_channels) +
ARRAY_SIZE(ath11k_5ghz_channels)) != ARRAY_SIZE(ath11k_5ghz_channels) +
ARRAY_SIZE(ath11k_6ghz_channels)) !=
ATH11K_NUM_CHANS); ATH11K_NUM_CHANS);
reg_cap = &ar->ab->hal_reg_cap[ar->pdev_idx]; reg_cap = &ar->ab->hal_reg_cap[ar->pdev_idx];
...@@ -5696,6 +5851,7 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, ...@@ -5696,6 +5851,7 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar,
return -ENOMEM; return -ENOMEM;
band = &ar->mac.sbands[NL80211_BAND_2GHZ]; band = &ar->mac.sbands[NL80211_BAND_2GHZ];
band->band = NL80211_BAND_2GHZ;
band->n_channels = ARRAY_SIZE(ath11k_2ghz_channels); band->n_channels = ARRAY_SIZE(ath11k_2ghz_channels);
band->channels = channels; band->channels = channels;
band->n_bitrates = ath11k_g_rates_size; band->n_bitrates = ath11k_g_rates_size;
...@@ -5707,15 +5863,39 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, ...@@ -5707,15 +5863,39 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar,
} }
if (supported_bands & WMI_HOST_WLAN_5G_CAP) { if (supported_bands & WMI_HOST_WLAN_5G_CAP) {
if (reg_cap->high_5ghz_chan >= ATH11K_MAX_6G_FREQ) {
channels = kmemdup(ath11k_6ghz_channels,
sizeof(ath11k_6ghz_channels), GFP_KERNEL);
if (!channels) {
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
return -ENOMEM;
}
ar->supports_6ghz = true;
band = &ar->mac.sbands[NL80211_BAND_6GHZ];
band->band = NL80211_BAND_6GHZ;
band->n_channels = ARRAY_SIZE(ath11k_6ghz_channels);
band->channels = channels;
band->n_bitrates = ath11k_a_rates_size;
band->bitrates = ath11k_a_rates;
ar->hw->wiphy->bands[NL80211_BAND_6GHZ] = band;
ath11k_mac_update_ch_list(ar, band,
reg_cap->low_5ghz_chan,
reg_cap->high_5ghz_chan);
}
if (reg_cap->low_5ghz_chan < ATH11K_MIN_6G_FREQ) {
channels = kmemdup(ath11k_5ghz_channels, channels = kmemdup(ath11k_5ghz_channels,
sizeof(ath11k_5ghz_channels), sizeof(ath11k_5ghz_channels),
GFP_KERNEL); GFP_KERNEL);
if (!channels) { if (!channels) {
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
return -ENOMEM; return -ENOMEM;
} }
band = &ar->mac.sbands[NL80211_BAND_5GHZ]; band = &ar->mac.sbands[NL80211_BAND_5GHZ];
band->band = NL80211_BAND_5GHZ;
band->n_channels = ARRAY_SIZE(ath11k_5ghz_channels); band->n_channels = ARRAY_SIZE(ath11k_5ghz_channels);
band->channels = channels; band->channels = channels;
band->n_bitrates = ath11k_a_rates_size; band->n_bitrates = ath11k_a_rates_size;
...@@ -5725,6 +5905,7 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar, ...@@ -5725,6 +5905,7 @@ static int ath11k_mac_setup_channels_rates(struct ath11k *ar,
reg_cap->low_5ghz_chan, reg_cap->low_5ghz_chan,
reg_cap->high_5ghz_chan); reg_cap->high_5ghz_chan);
} }
}
return 0; return 0;
} }
...@@ -5777,6 +5958,7 @@ static void __ath11k_mac_unregister(struct ath11k *ar) ...@@ -5777,6 +5958,7 @@ static void __ath11k_mac_unregister(struct ath11k *ar)
kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_2GHZ].channels);
kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels); kfree(ar->mac.sbands[NL80211_BAND_5GHZ].channels);
kfree(ar->mac.sbands[NL80211_BAND_6GHZ].channels);
SET_IEEE80211_DEV(ar->hw, NULL); SET_IEEE80211_DEV(ar->hw, NULL);
} }
......
...@@ -161,6 +161,10 @@ int ath11k_reg_update_chan_list(struct ath11k *ar) ...@@ -161,6 +161,10 @@ int ath11k_reg_update_chan_list(struct ath11k *ar)
else else
ch->phy_mode = MODE_11A; ch->phy_mode = MODE_11A;
if (channel->band == NL80211_BAND_6GHZ &&
cfg80211_channel_is_psc(channel))
ch->psc_channel = true;
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
"mac channel [%d/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n", "mac channel [%d/%d] freq %d maxpower %d regpower %d antenna %d mode %d\n",
i, params->nallchans, i, params->nallchans,
......
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
*/
#include <linux/relay.h>
#include "core.h"
#include "debug.h"
#define ATH11K_SPECTRAL_NUM_RESP_PER_EVENT 2
#define ATH11K_SPECTRAL_EVENT_TIMEOUT_MS 1
#define ATH11K_SPECTRAL_DWORD_SIZE 4
/* HW bug, expected BIN size is 2 bytes but HW report as 4 bytes */
#define ATH11K_SPECTRAL_BIN_SIZE 4
#define ATH11K_SPECTRAL_ATH11K_MIN_BINS 64
#define ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS 32
#define ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS 256
#define ATH11K_SPECTRAL_SAMPLE_FFT_BIN_MASK 0xFF
#define ATH11K_SPECTRAL_SCAN_COUNT_MAX 4095
/* Max channel computed by sum of 2g and 5g band channels */
#define ATH11K_SPECTRAL_TOTAL_CHANNEL 41
#define ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL 70
#define ATH11K_SPECTRAL_PER_SAMPLE_SIZE (sizeof(struct fft_sample_ath11k) + \
ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS)
#define ATH11K_SPECTRAL_TOTAL_SAMPLE (ATH11K_SPECTRAL_TOTAL_CHANNEL * \
ATH11K_SPECTRAL_SAMPLES_PER_CHANNEL)
#define ATH11K_SPECTRAL_SUB_BUFF_SIZE ATH11K_SPECTRAL_PER_SAMPLE_SIZE
#define ATH11K_SPECTRAL_NUM_SUB_BUF ATH11K_SPECTRAL_TOTAL_SAMPLE
#define ATH11K_SPECTRAL_20MHZ 20
#define ATH11K_SPECTRAL_40MHZ 40
#define ATH11K_SPECTRAL_80MHZ 80
#define ATH11K_SPECTRAL_SIGNATURE 0xFA
#define ATH11K_SPECTRAL_TAG_RADAR_SUMMARY 0x0
#define ATH11K_SPECTRAL_TAG_RADAR_FFT 0x1
#define ATH11K_SPECTRAL_TAG_SCAN_SUMMARY 0x2
#define ATH11K_SPECTRAL_TAG_SCAN_SEARCH 0x3
#define SPECTRAL_TLV_HDR_LEN GENMASK(15, 0)
#define SPECTRAL_TLV_HDR_TAG GENMASK(23, 16)
#define SPECTRAL_TLV_HDR_SIGN GENMASK(31, 24)
#define SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN GENMASK(7, 0)
#define SPECTRAL_SUMMARY_INFO0_OB_FLAG BIT(8)
#define SPECTRAL_SUMMARY_INFO0_GRP_IDX GENMASK(16, 9)
#define SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT BIT(17)
#define SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB GENMASK(27, 18)
#define SPECTRAL_SUMMARY_INFO0_FALSE_SCAN BIT(28)
#define SPECTRAL_SUMMARY_INFO0_DETECTOR_ID GENMASK(30, 29)
#define SPECTRAL_SUMMARY_INFO0_PRI80 BIT(31)
#define SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX GENMASK(11, 0)
#define SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE GENMASK(21, 12)
#define SPECTRAL_SUMMARY_INFO2_NARROWBAND_MASK GENMASK(29, 22)
#define SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE BIT(30)
struct spectral_tlv {
__le32 timestamp;
__le32 header;
} __packed;
struct spectral_summary_fft_report {
__le32 timestamp;
__le32 tlv_header;
__le32 info0;
__le32 reserve0;
__le32 info2;
__le32 reserve1;
} __packed;
struct ath11k_spectral_summary_report {
struct wmi_dma_buf_release_meta_data meta;
u32 timestamp;
u8 agc_total_gain;
u8 grp_idx;
u16 inb_pwr_db;
s16 peak_idx;
u16 peak_mag;
u8 detector_id;
bool out_of_band_flag;
bool rf_saturation;
bool primary80;
bool gain_change;
bool false_scan;
};
#define SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID GENMASK(1, 0)
#define SPECTRAL_FFT_REPORT_INFO0_FFT_NUM GENMASK(4, 2)
#define SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK GENMASK(16, 5)
#define SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX GENMASK(27, 17)
#define SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX GENMASK(30, 28)
#define SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB GENMASK(8, 0)
#define SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB GENMASK(16, 9)
#define SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS GENMASK(7, 0)
#define SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE GENMASK(17, 8)
#define SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB GENMASK(24, 18)
#define SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB GENMASK(31, 25)
struct spectral_search_fft_report {
__le32 timestamp;
__le32 tlv_header;
__le32 info0;
__le32 info1;
__le32 info2;
__le32 reserve0;
u8 bins[0];
} __packed;
struct ath11k_spectral_search_report {
u32 timestamp;
u8 detector_id;
u8 fft_count;
u16 radar_check;
s16 peak_idx;
u8 chain_idx;
u16 base_pwr_db;
u8 total_gain_db;
u8 strong_bin_count;
u16 peak_mag;
u8 avg_pwr_db;
u8 rel_pwr_db;
};
static struct dentry *create_buf_file_handler(const char *filename,
struct dentry *parent,
umode_t mode,
struct rchan_buf *buf,
int *is_global)
{
struct dentry *buf_file;
buf_file = debugfs_create_file(filename, mode, parent, buf,
&relay_file_operations);
*is_global = 1;
return buf_file;
}
static int remove_buf_file_handler(struct dentry *dentry)
{
debugfs_remove(dentry);
return 0;
}
static struct rchan_callbacks rfs_scan_cb = {
.create_buf_file = create_buf_file_handler,
.remove_buf_file = remove_buf_file_handler,
};
static struct ath11k_vif *ath11k_spectral_get_vdev(struct ath11k *ar)
{
struct ath11k_vif *arvif;
lockdep_assert_held(&ar->conf_mutex);
if (list_empty(&ar->arvifs))
return NULL;
/* 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);
}
static int 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;
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;
return 0;
}
static int ath11k_spectral_scan_config(struct ath11k *ar,
enum ath11k_spectral_mode mode)
{
struct ath11k_wmi_vdev_spectral_conf_param param = { 0 };
struct ath11k_vif *arvif;
int ret, count;
lockdep_assert_held(&ar->conf_mutex);
arvif = ath11k_spectral_get_vdev(ar);
if (!arvif)
return -ENODEV;
arvif->spectral_enabled = (mode != ATH11K_SPECTRAL_DISABLED);
ar->spectral.mode = mode;
ret = ath11k_wmi_vdev_spectral_enable(ar, arvif->vdev_id,
ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
ATH11K_WMI_SPECTRAL_ENABLE_CMD_DISABLE);
if (ret) {
ath11k_warn(ar->ab, "failed to enable spectral scan: %d\n", ret);
return ret;
}
if (mode == ATH11K_SPECTRAL_DISABLED)
return 0;
if (mode == ATH11K_SPECTRAL_BACKGROUND)
count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT;
else
count = max_t(u16, 1, ar->spectral.count);
param.vdev_id = arvif->vdev_id;
param.scan_count = count;
param.scan_fft_size = ar->spectral.fft_size;
param.scan_period = ATH11K_WMI_SPECTRAL_PERIOD_DEFAULT;
param.scan_priority = ATH11K_WMI_SPECTRAL_PRIORITY_DEFAULT;
param.scan_gc_ena = ATH11K_WMI_SPECTRAL_GC_ENA_DEFAULT;
param.scan_restart_ena = ATH11K_WMI_SPECTRAL_RESTART_ENA_DEFAULT;
param.scan_noise_floor_ref = ATH11K_WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
param.scan_init_delay = ATH11K_WMI_SPECTRAL_INIT_DELAY_DEFAULT;
param.scan_nb_tone_thr = ATH11K_WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
param.scan_str_bin_thr = ATH11K_WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
param.scan_wb_rpt_mode = ATH11K_WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
param.scan_rssi_rpt_mode = ATH11K_WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
param.scan_rssi_thr = ATH11K_WMI_SPECTRAL_RSSI_THR_DEFAULT;
param.scan_pwr_format = ATH11K_WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
param.scan_rpt_mode = ATH11K_WMI_SPECTRAL_RPT_MODE_DEFAULT;
param.scan_bin_scale = ATH11K_WMI_SPECTRAL_BIN_SCALE_DEFAULT;
param.scan_dbm_adj = ATH11K_WMI_SPECTRAL_DBM_ADJ_DEFAULT;
param.scan_chn_mask = ATH11K_WMI_SPECTRAL_CHN_MASK_DEFAULT;
ret = ath11k_wmi_vdev_spectral_conf(ar, &param);
if (ret) {
ath11k_warn(ar->ab, "failed to configure spectral scan: %d\n", ret);
return ret;
}
return 0;
}
static ssize_t ath11k_read_file_spec_scan_ctl(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
char *mode = "";
size_t len;
enum ath11k_spectral_mode spectral_mode;
mutex_lock(&ar->conf_mutex);
spectral_mode = ar->spectral.mode;
mutex_unlock(&ar->conf_mutex);
switch (spectral_mode) {
case ATH11K_SPECTRAL_DISABLED:
mode = "disable";
break;
case ATH11K_SPECTRAL_BACKGROUND:
mode = "background";
break;
case ATH11K_SPECTRAL_MANUAL:
mode = "manual";
break;
}
len = strlen(mode);
return simple_read_from_buffer(user_buf, count, ppos, mode, len);
}
static ssize_t ath11k_write_file_spec_scan_ctl(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
char buf[32];
ssize_t len;
int ret;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
mutex_lock(&ar->conf_mutex);
if (strncmp("trigger", buf, 7) == 0) {
if (ar->spectral.mode == ATH11K_SPECTRAL_MANUAL ||
ar->spectral.mode == ATH11K_SPECTRAL_BACKGROUND) {
/* reset the configuration to adopt possibly changed
* debugfs parameters
*/
ret = ath11k_spectral_scan_config(ar, ar->spectral.mode);
if (ret) {
ath11k_warn(ar->ab, "failed to reconfigure spectral scan: %d\n",
ret);
goto unlock;
}
ret = ath11k_spectral_scan_trigger(ar);
if (ret) {
ath11k_warn(ar->ab, "failed to trigger spectral scan: %d\n",
ret);
}
} else {
ret = -EINVAL;
}
} else if (strncmp("background", buf, 10) == 0) {
ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_BACKGROUND);
} else if (strncmp("manual", buf, 6) == 0) {
ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_MANUAL);
} else if (strncmp("disable", buf, 7) == 0) {
ret = ath11k_spectral_scan_config(ar, ATH11K_SPECTRAL_DISABLED);
} else {
ret = -EINVAL;
}
unlock:
mutex_unlock(&ar->conf_mutex);
if (ret)
return ret;
return count;
}
static const struct file_operations fops_scan_ctl = {
.read = ath11k_read_file_spec_scan_ctl,
.write = ath11k_write_file_spec_scan_ctl,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_read_file_spectral_count(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
char buf[32];
size_t len;
u16 spectral_count;
mutex_lock(&ar->conf_mutex);
spectral_count = ar->spectral.count;
mutex_unlock(&ar->conf_mutex);
len = sprintf(buf, "%d\n", spectral_count);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath11k_write_file_spectral_count(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val > ATH11K_SPECTRAL_SCAN_COUNT_MAX)
return -EINVAL;
mutex_lock(&ar->conf_mutex);
ar->spectral.count = val;
mutex_unlock(&ar->conf_mutex);
return count;
}
static const struct file_operations fops_scan_count = {
.read = ath11k_read_file_spectral_count,
.write = ath11k_write_file_spectral_count,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static ssize_t ath11k_read_file_spectral_bins(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
char buf[32];
unsigned int bins, fft_size;
size_t len;
mutex_lock(&ar->conf_mutex);
fft_size = ar->spectral.fft_size;
bins = 1 << fft_size;
mutex_unlock(&ar->conf_mutex);
len = sprintf(buf, "%d\n", bins);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath11k_write_file_spectral_bins(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath11k *ar = file->private_data;
unsigned long val;
char buf[32];
ssize_t len;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
buf[len] = '\0';
if (kstrtoul(buf, 0, &val))
return -EINVAL;
if (val < ATH11K_SPECTRAL_ATH11K_MIN_BINS ||
val > SPECTRAL_ATH11K_MAX_NUM_BINS)
return -EINVAL;
if (!is_power_of_2(val))
return -EINVAL;
mutex_lock(&ar->conf_mutex);
ar->spectral.fft_size = ilog2(val);
mutex_unlock(&ar->conf_mutex);
return count;
}
static const struct file_operations fops_scan_bins = {
.read = ath11k_read_file_spectral_bins,
.write = ath11k_write_file_spectral_bins,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
static int ath11k_spectral_pull_summary(struct ath11k *ar,
struct wmi_dma_buf_release_meta_data *meta,
struct spectral_summary_fft_report *summary,
struct ath11k_spectral_summary_report *report)
{
report->timestamp = __le32_to_cpu(summary->timestamp);
report->agc_total_gain = FIELD_GET(SPECTRAL_SUMMARY_INFO0_AGC_TOTAL_GAIN,
__le32_to_cpu(summary->info0));
report->out_of_band_flag = FIELD_GET(SPECTRAL_SUMMARY_INFO0_OB_FLAG,
__le32_to_cpu(summary->info0));
report->grp_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO0_GRP_IDX,
__le32_to_cpu(summary->info0));
report->rf_saturation = FIELD_GET(SPECTRAL_SUMMARY_INFO0_RECENT_RFSAT,
__le32_to_cpu(summary->info0));
report->inb_pwr_db = FIELD_GET(SPECTRAL_SUMMARY_INFO0_INBAND_PWR_DB,
__le32_to_cpu(summary->info0));
report->false_scan = FIELD_GET(SPECTRAL_SUMMARY_INFO0_FALSE_SCAN,
__le32_to_cpu(summary->info0));
report->detector_id = FIELD_GET(SPECTRAL_SUMMARY_INFO0_DETECTOR_ID,
__le32_to_cpu(summary->info0));
report->primary80 = FIELD_GET(SPECTRAL_SUMMARY_INFO0_PRI80,
__le32_to_cpu(summary->info0));
report->peak_idx = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_SIGNED_IDX,
__le32_to_cpu(summary->info2));
report->peak_mag = FIELD_GET(SPECTRAL_SUMMARY_INFO2_PEAK_MAGNITUDE,
__le32_to_cpu(summary->info2));
report->gain_change = FIELD_GET(SPECTRAL_SUMMARY_INFO2_GAIN_CHANGE,
__le32_to_cpu(summary->info2));
memcpy(&report->meta, meta, sizeof(*meta));
return 0;
}
static int ath11k_spectral_pull_search(struct ath11k *ar,
struct spectral_search_fft_report *search,
struct ath11k_spectral_search_report *report)
{
report->timestamp = __le32_to_cpu(search->timestamp);
report->detector_id = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_DETECTOR_ID,
__le32_to_cpu(search->info0));
report->fft_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_FFT_NUM,
__le32_to_cpu(search->info0));
report->radar_check = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_RADAR_CHECK,
__le32_to_cpu(search->info0));
report->peak_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX,
__le32_to_cpu(search->info0));
report->chain_idx = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_CHAIN_IDX,
__le32_to_cpu(search->info0));
report->base_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_BASE_PWR_DB,
__le32_to_cpu(search->info1));
report->total_gain_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO1_TOTAL_GAIN_DB,
__le32_to_cpu(search->info1));
report->strong_bin_count = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_NUM_STRONG_BINS,
__le32_to_cpu(search->info2));
report->peak_mag = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_PEAK_MAGNITUDE,
__le32_to_cpu(search->info2));
report->avg_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_AVG_PWR_DB,
__le32_to_cpu(search->info2));
report->rel_pwr_db = FIELD_GET(SPECTRAL_FFT_REPORT_INFO2_REL_PWR_DB,
__le32_to_cpu(search->info2));
return 0;
}
static u8 ath11k_spectral_get_max_exp(s8 max_index, u8 max_magnitude,
int bin_len, u8 *bins)
{
int dc_pos;
u8 max_exp;
dc_pos = bin_len / 2;
/* peak index outside of bins */
if (dc_pos <= max_index || -dc_pos >= max_index)
return 0;
for (max_exp = 0; max_exp < 8; max_exp++) {
if (bins[dc_pos + max_index] == (max_magnitude >> max_exp))
break;
}
/* max_exp not found */
if (bins[dc_pos + max_index] != (max_magnitude >> max_exp))
return 0;
return max_exp;
}
static void ath11k_spectral_parse_16bit_fft(u8 *outbins, u8 *inbins, int num_bins)
{
int i;
__le16 *data = (__le16 *)inbins;
i = 0;
while (i < num_bins) {
outbins[i] = (__le16_to_cpu(data[i])) &
ATH11K_SPECTRAL_SAMPLE_FFT_BIN_MASK;
i++;
}
}
static
int ath11k_spectral_process_fft(struct ath11k *ar,
struct ath11k_spectral_summary_report *summary,
void *data,
struct fft_sample_ath11k *fft_sample,
u32 data_len)
{
struct ath11k_base *ab = ar->ab;
struct spectral_search_fft_report *fft_report = data;
struct ath11k_spectral_search_report search;
struct spectral_tlv *tlv;
int tlv_len, bin_len, num_bins;
u16 length, freq;
u8 chan_width_mhz;
int ret;
lockdep_assert_held(&ar->spectral.lock);
tlv = (struct spectral_tlv *)data;
tlv_len = FIELD_GET(SPECTRAL_TLV_HDR_LEN, __le32_to_cpu(tlv->header));
/* convert Dword into bytes */
tlv_len *= ATH11K_SPECTRAL_DWORD_SIZE;
bin_len = tlv_len - (sizeof(*fft_report) - sizeof(*tlv));
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;
}
num_bins = bin_len / ATH11K_SPECTRAL_BIN_SIZE;
/* Only In-band bins are useful to user for visualize */
num_bins >>= 1;
if (num_bins < ATH11K_SPECTRAL_ATH11K_MIN_IB_BINS ||
num_bins > ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS ||
!is_power_of_2(num_bins)) {
ath11k_warn(ab, "Invalid num of bins %d\n", num_bins);
return -EINVAL;
}
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;
default:
ath11k_warn(ab, "invalid channel width %d\n", chan_width_mhz);
return -EINVAL;
}
length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + num_bins;
fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH11K;
fft_sample->tlv.length = __cpu_to_be16(length);
fft_sample->tsf = __cpu_to_be32(search.timestamp);
fft_sample->max_magnitude = __cpu_to_be16(search.peak_mag);
fft_sample->max_index = FIELD_GET(SPECTRAL_FFT_REPORT_INFO0_PEAK_SIGNED_IDX,
__le32_to_cpu(fft_report->info0));
summary->inb_pwr_db >>= 1;
fft_sample->rssi = __cpu_to_be16(summary->inb_pwr_db);
fft_sample->noise = __cpu_to_be32(summary->meta.noise_floor[search.chain_idx]);
freq = summary->meta.freq1;
fft_sample->freq1 = __cpu_to_be16(freq);
freq = summary->meta.freq2;
fft_sample->freq2 = __cpu_to_be16(freq);
ath11k_spectral_parse_16bit_fft(fft_sample->data,
fft_report->bins,
num_bins);
fft_sample->max_exp = ath11k_spectral_get_max_exp(fft_sample->max_index,
search.peak_mag,
num_bins,
fft_sample->data);
if (ar->spectral.rfs_scan)
relay_write(ar->spectral.rfs_scan, fft_sample,
length + sizeof(struct fft_sample_tlv));
return 0;
}
static int ath11k_spectral_process_data(struct ath11k *ar,
struct ath11k_dbring_data *param)
{
struct ath11k_base *ab = ar->ab;
struct spectral_tlv *tlv;
struct spectral_summary_fft_report *summary = NULL;
struct ath11k_spectral_summary_report summ_rpt;
struct fft_sample_ath11k *fft_sample = NULL;
u8 *data;
u32 data_len, i;
u8 sign, tag;
int tlv_len, sample_sz;
int ret;
bool quit = false;
spin_lock_bh(&ar->spectral.lock);
if (!ar->spectral.enabled) {
ret = -EINVAL;
goto unlock;
}
sample_sz = sizeof(*fft_sample) + ATH11K_SPECTRAL_ATH11K_MAX_IB_BINS;
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);
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;
}
summary = (struct spectral_summary_fft_report *)tlv;
ath11k_spectral_pull_summary(ar, &param->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;
}
i += sizeof(*tlv) + tlv_len;
}
err:
kfree(fft_sample);
unlock:
spin_unlock_bh(&ar->spectral.lock);
return ret;
}
static int ath11k_spectral_ring_alloc(struct ath11k *ar,
struct ath11k_dbring_cap *db_cap)
{
struct ath11k_spectral *sp = &ar->spectral;
int ret;
ret = ath11k_dbring_srng_setup(ar, &sp->rx_ring,
0, db_cap->min_elem);
if (ret) {
ath11k_warn(ar->ab, "failed to setup db ring\n");
return ret;
}
ath11k_dbring_set_cfg(ar, &sp->rx_ring,
ATH11K_SPECTRAL_NUM_RESP_PER_EVENT,
ATH11K_SPECTRAL_EVENT_TIMEOUT_MS,
ath11k_spectral_process_data);
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;
}
return 0;
buffer_cleanup:
ath11k_dbring_buf_cleanup(ar, &sp->rx_ring);
srng_cleanup:
ath11k_dbring_srng_cleanup(ar, &sp->rx_ring);
return ret;
}
static inline void ath11k_spectral_ring_free(struct ath11k *ar)
{
struct ath11k_spectral *sp = &ar->spectral;
if (!sp->enabled)
return;
ath11k_dbring_srng_cleanup(ar, &sp->rx_ring);
ath11k_dbring_buf_cleanup(ar, &sp->rx_ring);
}
static inline void ath11k_spectral_debug_unregister(struct ath11k *ar)
{
debugfs_remove(ar->spectral.scan_bins);
ar->spectral.scan_bins = NULL;
debugfs_remove(ar->spectral.scan_count);
ar->spectral.scan_count = NULL;
debugfs_remove(ar->spectral.scan_ctl);
ar->spectral.scan_ctl = NULL;
if (ar->spectral.rfs_scan) {
relay_close(ar->spectral.rfs_scan);
ar->spectral.rfs_scan = NULL;
}
}
int ath11k_spectral_vif_stop(struct ath11k_vif *arvif)
{
if (!arvif->spectral_enabled)
return 0;
return ath11k_spectral_scan_config(arvif->ar, ATH11K_SPECTRAL_DISABLED);
}
void ath11k_spectral_reset_buffer(struct ath11k *ar)
{
if (!ar->spectral.enabled)
return;
if (ar->spectral.rfs_scan)
relay_reset(ar->spectral.rfs_scan);
}
void ath11k_spectral_deinit(struct ath11k_base *ab)
{
struct ath11k *ar;
struct ath11k_spectral *sp;
int i;
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
sp = &ar->spectral;
if (!sp->enabled)
continue;
ath11k_spectral_debug_unregister(ar);
ath11k_spectral_ring_free(ar);
spin_lock_bh(&sp->lock);
sp->mode = ATH11K_SPECTRAL_DISABLED;
sp->enabled = false;
spin_unlock_bh(&sp->lock);
}
}
static inline int 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,
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;
}
return 0;
debug_unregister:
ath11k_spectral_debug_unregister(ar);
return ret;
}
int ath11k_spectral_init(struct ath11k_base *ab)
{
struct ath11k *ar;
struct ath11k_spectral *sp;
struct ath11k_dbring_cap db_cap;
int ret;
int i;
if (!test_bit(WMI_TLV_SERVICE_FREQINFO_IN_METADATA,
ab->wmi_ab.svc_map)) {
ath11k_info(ab, "spectral not supported\n");
return 0;
}
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
sp = &ar->spectral;
ret = ath11k_dbring_get_cap(ar->ab, ar->pdev_idx,
WMI_DIRECT_BUF_SPECTRAL,
&db_cap);
if (ret) {
ath11k_info(ab, "spectral not enabled for pdev %d\n", i);
continue;
}
idr_init(&sp->rx_ring.bufs_idr);
spin_lock_init(&sp->rx_ring.idr_lock);
spin_lock_init(&sp->lock);
ret = ath11k_spectral_ring_alloc(ar, &db_cap);
if (ret) {
ath11k_warn(ab, "failed to init spectral ring for pdev %d\n",
i);
goto deinit;
}
spin_lock_bh(&sp->lock);
sp->mode = ATH11K_SPECTRAL_DISABLED;
sp->count = ATH11K_WMI_SPECTRAL_COUNT_DEFAULT;
sp->fft_size = ATH11K_WMI_SPECTRAL_FFT_SIZE_DEFAULT;
sp->enabled = true;
spin_unlock_bh(&sp->lock);
ret = ath11k_spectral_debug_register(ar);
if (ret) {
ath11k_warn(ab, "failed to register spectral for pdev %d\n",
i);
goto deinit;
}
}
return 0;
deinit:
ath11k_spectral_deinit(ab);
return ret;
}
enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar)
{
if (ar->spectral.enabled)
return ar->spectral.mode;
else
return ATH11K_SPECTRAL_DISABLED;
}
struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar)
{
if (ar->spectral.enabled)
return &ar->spectral.rx_ring;
else
return NULL;
}
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
*/
#ifndef ATH11K_SPECTRAL_H
#define ATH11K_SPECTRAL_H
#include "../spectral_common.h"
#include "dbring.h"
/* enum ath11k_spectral_mode:
*
* @SPECTRAL_DISABLED: spectral mode is disabled
* @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
* something else.
* @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
* is performed manually.
*/
enum ath11k_spectral_mode {
ATH11K_SPECTRAL_DISABLED = 0,
ATH11K_SPECTRAL_BACKGROUND,
ATH11K_SPECTRAL_MANUAL,
};
struct ath11k_spectral {
struct ath11k_dbring rx_ring;
/* Protects enabled */
spinlock_t lock;
struct rchan *rfs_scan; /* relay(fs) channel for spectral scan */
struct dentry *scan_ctl;
struct dentry *scan_count;
struct dentry *scan_bins;
enum ath11k_spectral_mode mode;
u16 count;
u8 fft_size;
bool enabled;
};
#ifdef CONFIG_ATH11K_SPECTRAL
int ath11k_spectral_init(struct ath11k_base *ab);
void ath11k_spectral_deinit(struct ath11k_base *ab);
int ath11k_spectral_vif_stop(struct ath11k_vif *arvif);
void ath11k_spectral_reset_buffer(struct ath11k *ar);
enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar);
struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar);
#else
static inline int ath11k_spectral_init(struct ath11k_base *ab)
{
return 0;
}
static inline void ath11k_spectral_deinit(struct ath11k_base *ab)
{
}
static inline int ath11k_spectral_vif_stop(struct ath11k_vif *arvif)
{
return 0;
}
static inline void ath11k_spectral_reset_buffer(struct ath11k *ar)
{
}
static inline
enum ath11k_spectral_mode ath11k_spectral_get_mode(struct ath11k *ar)
{
return ATH11K_SPECTRAL_DISABLED;
}
static inline
struct ath11k_dbring *ath11k_spectral_get_dbring(struct ath11k *ar)
{
return NULL;
}
#endif /* CONFIG_ATH11K_SPECTRAL */
#endif /* ATH11K_SPECTRAL_H */
...@@ -27,6 +27,11 @@ struct wmi_tlv_svc_ready_parse { ...@@ -27,6 +27,11 @@ struct wmi_tlv_svc_ready_parse {
bool wmi_svc_bitmap_done; bool wmi_svc_bitmap_done;
}; };
struct wmi_tlv_dma_ring_caps_parse {
struct wmi_dma_ring_capabilities *dma_ring_caps;
u32 n_dma_ring_caps;
};
struct wmi_tlv_svc_rdy_ext_parse { struct wmi_tlv_svc_rdy_ext_parse {
struct ath11k_service_ext_param param; struct ath11k_service_ext_param param;
struct wmi_soc_mac_phy_hw_mode_caps *hw_caps; struct wmi_soc_mac_phy_hw_mode_caps *hw_caps;
...@@ -39,15 +44,35 @@ struct wmi_tlv_svc_rdy_ext_parse { ...@@ -39,15 +44,35 @@ struct wmi_tlv_svc_rdy_ext_parse {
struct wmi_soc_hal_reg_capabilities *soc_hal_reg_caps; struct wmi_soc_hal_reg_capabilities *soc_hal_reg_caps;
struct wmi_hal_reg_capabilities_ext *ext_hal_reg_caps; struct wmi_hal_reg_capabilities_ext *ext_hal_reg_caps;
u32 n_ext_hal_reg_caps; u32 n_ext_hal_reg_caps;
struct wmi_tlv_dma_ring_caps_parse dma_caps_parse;
bool hw_mode_done; bool hw_mode_done;
bool mac_phy_done; bool mac_phy_done;
bool ext_hal_reg_done; bool ext_hal_reg_done;
bool mac_phy_chainmask_combo_done;
bool mac_phy_chainmask_cap_done;
bool oem_dma_ring_cap_done;
bool dma_ring_cap_done;
};
struct wmi_tlv_svc_rdy_ext2_parse {
struct wmi_tlv_dma_ring_caps_parse dma_caps_parse;
bool dma_ring_cap_done;
}; };
struct wmi_tlv_rdy_parse { struct wmi_tlv_rdy_parse {
u32 num_extra_mac_addr; u32 num_extra_mac_addr;
}; };
struct wmi_tlv_dma_buf_release_parse {
struct ath11k_wmi_dma_buf_release_fixed_param fixed;
struct wmi_dma_buf_release_entry *buf_entry;
struct wmi_dma_buf_release_meta_data *meta_data;
u32 num_buf_entry;
u32 num_meta;
bool buf_entry_done;
bool meta_data_done;
};
static const struct wmi_tlv_policy wmi_tlv_policies[] = { static const struct wmi_tlv_policy wmi_tlv_policies[] = {
[WMI_TAG_ARRAY_BYTE] [WMI_TAG_ARRAY_BYTE]
= { .min_len = 0 }, = { .min_len = 0 },
...@@ -368,6 +393,17 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle, ...@@ -368,6 +393,17 @@ ath11k_pull_mac_phy_cap_svc_ready_ext(struct ath11k_pdev_wmi *wmi_handle,
memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g, memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g,
sizeof(struct ath11k_ppe_threshold)); sizeof(struct ath11k_ppe_threshold));
cap_band = &pdev_cap->band[NL80211_BAND_6GHZ];
cap_band->max_bw_supported = mac_phy_caps->max_bw_supported_5g;
cap_band->ht_cap_info = mac_phy_caps->ht_cap_info_5g;
cap_band->he_cap_info[0] = mac_phy_caps->he_cap_info_5g;
cap_band->he_cap_info[1] = mac_phy_caps->he_cap_info_5g_ext;
cap_band->he_mcs = mac_phy_caps->he_supp_mcs_5g;
memcpy(cap_band->he_cap_phy_info, &mac_phy_caps->he_cap_phy_info_5g,
sizeof(u32) * PSOC_HOST_MAX_PHY_SIZE);
memcpy(&cap_band->he_ppet, &mac_phy_caps->he_ppet5g,
sizeof(struct ath11k_ppe_threshold));
return 0; return 0;
} }
...@@ -1692,10 +1728,10 @@ ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd, ...@@ -1692,10 +1728,10 @@ ath11k_wmi_copy_peer_flags(struct wmi_peer_assoc_complete_cmd *cmd,
*/ */
if (param->auth_flag) if (param->auth_flag)
cmd->peer_flags |= WMI_PEER_AUTH; cmd->peer_flags |= WMI_PEER_AUTH;
if (param->need_ptk_4_way) if (param->need_ptk_4_way) {
cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY; cmd->peer_flags |= WMI_PEER_NEED_PTK_4_WAY;
else cmd->peer_flags &= ~WMI_PEER_AUTH;
cmd->peer_flags &= ~WMI_PEER_NEED_PTK_4_WAY; }
if (param->need_gtk_2_way) if (param->need_gtk_2_way)
cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY; cmd->peer_flags |= WMI_PEER_NEED_GTK_2_WAY;
/* safe mode bypass the 4-way handshake */ /* safe mode bypass the 4-way handshake */
...@@ -1778,6 +1814,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, ...@@ -1778,6 +1814,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar,
cmd->peer_he_cap_info = param->peer_he_cap_macinfo[0]; cmd->peer_he_cap_info = param->peer_he_cap_macinfo[0];
cmd->peer_he_cap_info_ext = param->peer_he_cap_macinfo[1]; cmd->peer_he_cap_info_ext = param->peer_he_cap_macinfo[1];
cmd->peer_he_cap_info_internal = param->peer_he_cap_macinfo_internal; cmd->peer_he_cap_info_internal = param->peer_he_cap_macinfo_internal;
cmd->peer_he_caps_6ghz = param->peer_he_caps_6ghz;
cmd->peer_he_ops = param->peer_he_ops; cmd->peer_he_ops = param->peer_he_ops;
memcpy(&cmd->peer_he_cap_phy, &param->peer_he_cap_phyinfo, memcpy(&cmd->peer_he_cap_phy, &param->peer_he_cap_phyinfo,
sizeof(param->peer_he_cap_phyinfo)); sizeof(param->peer_he_cap_phyinfo));
...@@ -1831,6 +1868,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar, ...@@ -1831,6 +1868,7 @@ int ath11k_wmi_send_peer_assoc_cmd(struct ath11k *ar,
/* HE Rates */ /* HE Rates */
cmd->peer_he_mcs = param->peer_he_mcs_count; cmd->peer_he_mcs = param->peer_he_mcs_count;
cmd->min_data_rate = param->min_data_rate;
ptr += sizeof(*mcs); ptr += sizeof(*mcs);
...@@ -1886,6 +1924,8 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar, ...@@ -1886,6 +1924,8 @@ void ath11k_wmi_start_scan_init(struct ath11k *ar,
arg->dwell_time_active = 50; arg->dwell_time_active = 50;
arg->dwell_time_active_2g = 0; arg->dwell_time_active_2g = 0;
arg->dwell_time_passive = 150; arg->dwell_time_passive = 150;
arg->dwell_time_active_6g = 40;
arg->dwell_time_passive_6g = 30;
arg->min_rest_time = 50; arg->min_rest_time = 50;
arg->max_rest_time = 500; arg->max_rest_time = 500;
arg->repeat_probe_time = 0; arg->repeat_probe_time = 0;
...@@ -1990,6 +2030,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, ...@@ -1990,6 +2030,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
int i, ret, len; int i, ret, len;
u32 *tmp_ptr; u32 *tmp_ptr;
u8 extraie_len_with_pad = 0; u8 extraie_len_with_pad = 0;
struct hint_short_ssid *s_ssid = NULL;
struct hint_bssid *hint_bssid = NULL;
len = sizeof(*cmd); len = sizeof(*cmd);
...@@ -2011,6 +2053,14 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, ...@@ -2011,6 +2053,14 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
roundup(params->extraie.len, sizeof(u32)); roundup(params->extraie.len, sizeof(u32));
len += extraie_len_with_pad; len += extraie_len_with_pad;
if (params->num_hint_bssid)
len += TLV_HDR_SIZE +
params->num_hint_bssid * sizeof(struct hint_bssid);
if (params->num_hint_s_ssid)
len += TLV_HDR_SIZE +
params->num_hint_s_ssid * sizeof(struct hint_short_ssid);
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
...@@ -2032,6 +2082,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, ...@@ -2032,6 +2082,8 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
cmd->dwell_time_active = params->dwell_time_active; cmd->dwell_time_active = params->dwell_time_active;
cmd->dwell_time_active_2g = params->dwell_time_active_2g; cmd->dwell_time_active_2g = params->dwell_time_active_2g;
cmd->dwell_time_passive = params->dwell_time_passive; cmd->dwell_time_passive = params->dwell_time_passive;
cmd->dwell_time_active_6g = params->dwell_time_active_6g;
cmd->dwell_time_passive_6g = params->dwell_time_passive_6g;
cmd->min_rest_time = params->min_rest_time; cmd->min_rest_time = params->min_rest_time;
cmd->max_rest_time = params->max_rest_time; cmd->max_rest_time = params->max_rest_time;
cmd->repeat_probe_time = params->repeat_probe_time; cmd->repeat_probe_time = params->repeat_probe_time;
...@@ -2109,6 +2161,68 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar, ...@@ -2109,6 +2161,68 @@ int ath11k_wmi_send_scan_start_cmd(struct ath11k *ar,
ptr += extraie_len_with_pad; ptr += extraie_len_with_pad;
if (params->num_hint_s_ssid) {
len = params->num_hint_s_ssid * sizeof(struct hint_short_ssid);
tlv = ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) |
FIELD_PREP(WMI_TLV_LEN, len);
ptr += TLV_HDR_SIZE;
s_ssid = ptr;
for (i = 0; i < params->num_hint_s_ssid; ++i) {
s_ssid->freq_flags = params->hint_s_ssid[i].freq_flags;
s_ssid->short_ssid = params->hint_s_ssid[i].short_ssid;
s_ssid++;
}
ptr += len;
}
if (params->num_hint_bssid) {
len = params->num_hint_bssid * sizeof(struct hint_bssid);
tlv = ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) |
FIELD_PREP(WMI_TLV_LEN, len);
ptr += TLV_HDR_SIZE;
hint_bssid = ptr;
for (i = 0; i < params->num_hint_bssid; ++i) {
hint_bssid->freq_flags =
params->hint_bssid[i].freq_flags;
ether_addr_copy(&params->hint_bssid[i].bssid.addr[0],
&hint_bssid->bssid.addr[0]);
hint_bssid++;
}
}
len = params->num_hint_s_ssid * sizeof(struct hint_short_ssid);
tlv = ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) |
FIELD_PREP(WMI_TLV_LEN, len);
ptr += TLV_HDR_SIZE;
if (params->num_hint_s_ssid) {
s_ssid = ptr;
for (i = 0; i < params->num_hint_s_ssid; ++i) {
s_ssid->freq_flags = params->hint_s_ssid[i].freq_flags;
s_ssid->short_ssid = params->hint_s_ssid[i].short_ssid;
s_ssid++;
}
}
ptr += len;
len = params->num_hint_bssid * sizeof(struct hint_bssid);
tlv = ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_FIXED_STRUCT) |
FIELD_PREP(WMI_TLV_LEN, len);
ptr += TLV_HDR_SIZE;
if (params->num_hint_bssid) {
hint_bssid = ptr;
for (i = 0; i < params->num_hint_bssid; ++i) {
hint_bssid->freq_flags =
params->hint_bssid[i].freq_flags;
ether_addr_copy(&params->hint_bssid[i].bssid.addr[0],
&hint_bssid->bssid.addr[0]);
hint_bssid++;
}
}
ret = ath11k_wmi_cmd_send(wmi, skb, ret = ath11k_wmi_cmd_send(wmi, skb,
WMI_START_SCAN_CMDID); WMI_START_SCAN_CMDID);
if (ret) { if (ret) {
...@@ -2178,10 +2292,22 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, ...@@ -2178,10 +2292,22 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
struct wmi_tlv *tlv; struct wmi_tlv *tlv;
void *ptr; void *ptr;
int i, ret, len; int i, ret, len;
u16 num_send_chans, num_sends = 0, max_chan_limit = 0;
u32 *reg1, *reg2; u32 *reg1, *reg2;
len = sizeof(*cmd) + TLV_HDR_SIZE + tchan_info = &chan_list->ch_param[0];
sizeof(*chan_info) * chan_list->nallchans; while (chan_list->nallchans) {
len = sizeof(*cmd) + TLV_HDR_SIZE;
max_chan_limit = (wmi->wmi_ab->max_msg_len[ar->pdev_idx] - len) /
sizeof(*chan_info);
if (chan_list->nallchans > max_chan_limit)
num_send_chans = max_chan_limit;
else
num_send_chans = chan_list->nallchans;
chan_list->nallchans -= num_send_chans;
len += sizeof(*chan_info) * num_send_chans;
skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len); skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, len);
if (!skb) if (!skb)
...@@ -2190,23 +2316,24 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, ...@@ -2190,23 +2316,24 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
cmd = (struct wmi_scan_chan_list_cmd *)skb->data; cmd = (struct wmi_scan_chan_list_cmd *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SCAN_CHAN_LIST_CMD) | cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_SCAN_CHAN_LIST_CMD) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE); FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
cmd->pdev_id = chan_list->pdev_id;
cmd->num_scan_chans = num_send_chans;
if (num_sends)
cmd->flags |= WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG;
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
"WMI no.of chan = %d len = %d\n", chan_list->nallchans, len); "WMI no.of chan = %d len = %d pdev_id = %d num_sends = %d\n",
cmd->pdev_id = chan_list->pdev_id; num_send_chans, len, cmd->pdev_id, num_sends);
cmd->num_scan_chans = chan_list->nallchans;
ptr = skb->data + sizeof(*cmd); ptr = skb->data + sizeof(*cmd);
len = sizeof(*chan_info) * chan_list->nallchans; len = sizeof(*chan_info) * num_send_chans;
tlv = ptr; tlv = ptr;
tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) | tlv->header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_STRUCT) |
FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE); FIELD_PREP(WMI_TLV_LEN, len - TLV_HDR_SIZE);
ptr += TLV_HDR_SIZE; ptr += TLV_HDR_SIZE;
tchan_info = &chan_list->ch_param[0]; for (i = 0; i < num_send_chans; ++i) {
for (i = 0; i < chan_list->nallchans; ++i) {
chan_info = ptr; chan_info = ptr;
memset(chan_info, 0, sizeof(*chan_info)); memset(chan_info, 0, sizeof(*chan_info));
len = sizeof(*chan_info); len = sizeof(*chan_info);
...@@ -2233,6 +2360,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, ...@@ -2233,6 +2360,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
chan_info->info |= WMI_CHAN_INFO_HALF_RATE; chan_info->info |= WMI_CHAN_INFO_HALF_RATE;
if (tchan_info->quarter_rate) if (tchan_info->quarter_rate)
chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE; chan_info->info |= WMI_CHAN_INFO_QUARTER_RATE;
if (tchan_info->psc_channel)
chan_info->info |= WMI_CHAN_INFO_PSC;
chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE, chan_info->info |= FIELD_PREP(WMI_CHAN_INFO_MODE,
tchan_info->phy_mode); tchan_info->phy_mode);
...@@ -2248,8 +2377,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, ...@@ -2248,8 +2377,8 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
tchan_info->antennamax); tchan_info->antennamax);
ath11k_dbg(ar->ab, ATH11K_DBG_WMI, ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
"WMI chan scan list chan[%d] = %u\n", "WMI chan scan list chan[%d] = %u, chan_info->info %8x\n",
i, chan_info->mhz); i, chan_info->mhz, chan_info->info);
ptr += sizeof(*chan_info); ptr += sizeof(*chan_info);
...@@ -2260,9 +2389,13 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar, ...@@ -2260,9 +2389,13 @@ int ath11k_wmi_send_scan_chan_list_cmd(struct ath11k *ar,
if (ret) { if (ret) {
ath11k_warn(ar->ab, "failed to send WMI_SCAN_CHAN_LIST cmd\n"); ath11k_warn(ar->ab, "failed to send WMI_SCAN_CHAN_LIST cmd\n");
dev_kfree_skb(skb); dev_kfree_skb(skb);
return ret;
} }
return ret; num_sends++;
}
return 0;
} }
int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id, int ath11k_wmi_send_wmm_update_cmd_tlv(struct ath11k *ar, u32 vdev_id,
...@@ -3265,6 +3398,236 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab) ...@@ -3265,6 +3398,236 @@ int ath11k_wmi_cmd_init(struct ath11k_base *ab)
return ath11k_init_cmd_send(&wmi_sc->wmi[0], &init_param); return ath11k_init_cmd_send(&wmi_sc->wmi[0], &init_param);
} }
int ath11k_wmi_vdev_spectral_conf(struct ath11k *ar,
struct ath11k_wmi_vdev_spectral_conf_param *param)
{
struct ath11k_wmi_vdev_spectral_conf_cmd *cmd;
struct sk_buff *skb;
int ret;
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct ath11k_wmi_vdev_spectral_conf_cmd *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
WMI_TAG_VDEV_SPECTRAL_CONFIGURE_CMD) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
memcpy(&cmd->param, param, sizeof(*param));
ret = ath11k_wmi_cmd_send(ar->wmi, skb,
WMI_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID);
if (ret) {
ath11k_warn(ar->ab,
"failed to send spectral scan config wmi cmd\n");
goto err;
}
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
"WMI spectral scan config cmd vdev_id 0x%x\n",
param->vdev_id);
return 0;
err:
dev_kfree_skb(skb);
return ret;
}
int ath11k_wmi_vdev_spectral_enable(struct ath11k *ar, u32 vdev_id,
u32 trigger, u32 enable)
{
struct ath11k_wmi_vdev_spectral_enable_cmd *cmd;
struct sk_buff *skb;
int ret;
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct ath11k_wmi_vdev_spectral_enable_cmd *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG,
WMI_TAG_VDEV_SPECTRAL_ENABLE_CMD) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
cmd->vdev_id = vdev_id;
cmd->trigger_cmd = trigger;
cmd->enable_cmd = enable;
ret = ath11k_wmi_cmd_send(ar->wmi, skb,
WMI_VDEV_SPECTRAL_SCAN_ENABLE_CMDID);
if (ret) {
ath11k_warn(ar->ab,
"failed to send spectral enable wmi cmd\n");
goto err;
}
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
"WMI spectral enable cmd vdev id 0x%x\n",
vdev_id);
return 0;
err:
dev_kfree_skb(skb);
return ret;
}
int ath11k_wmi_pdev_dma_ring_cfg(struct ath11k *ar,
struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd *param)
{
struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd *cmd;
struct sk_buff *skb;
int ret;
skb = ath11k_wmi_alloc_skb(ar->wmi->wmi_ab, sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd *)skb->data;
cmd->tlv_header = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_DMA_RING_CFG_REQ) |
FIELD_PREP(WMI_TLV_LEN, sizeof(*cmd) - TLV_HDR_SIZE);
cmd->pdev_id = param->pdev_id;
cmd->module_id = param->module_id;
cmd->base_paddr_lo = param->base_paddr_lo;
cmd->base_paddr_hi = param->base_paddr_hi;
cmd->head_idx_paddr_lo = param->head_idx_paddr_lo;
cmd->head_idx_paddr_hi = param->head_idx_paddr_hi;
cmd->tail_idx_paddr_lo = param->tail_idx_paddr_lo;
cmd->tail_idx_paddr_hi = param->tail_idx_paddr_hi;
cmd->num_elems = param->num_elems;
cmd->buf_size = param->buf_size;
cmd->num_resp_per_event = param->num_resp_per_event;
cmd->event_timeout_ms = param->event_timeout_ms;
ret = ath11k_wmi_cmd_send(ar->wmi, skb,
WMI_PDEV_DMA_RING_CFG_REQ_CMDID);
if (ret) {
ath11k_warn(ar->ab,
"failed to send dma ring cfg req wmi cmd\n");
goto err;
}
ath11k_dbg(ar->ab, ATH11K_DBG_WMI,
"WMI DMA ring cfg req cmd pdev_id 0x%x\n",
param->pdev_id);
return 0;
err:
dev_kfree_skb(skb);
return ret;
}
static int ath11k_wmi_tlv_dma_buf_entry_parse(struct ath11k_base *soc,
u16 tag, u16 len,
const void *ptr, void *data)
{
struct wmi_tlv_dma_buf_release_parse *parse = data;
if (tag != WMI_TAG_DMA_BUF_RELEASE_ENTRY)
return -EPROTO;
if (parse->num_buf_entry >= parse->fixed.num_buf_release_entry)
return -ENOBUFS;
parse->num_buf_entry++;
return 0;
}
static int ath11k_wmi_tlv_dma_buf_meta_parse(struct ath11k_base *soc,
u16 tag, u16 len,
const void *ptr, void *data)
{
struct wmi_tlv_dma_buf_release_parse *parse = data;
if (tag != WMI_TAG_DMA_BUF_RELEASE_SPECTRAL_META_DATA)
return -EPROTO;
if (parse->num_meta >= parse->fixed.num_meta_data_entry)
return -ENOBUFS;
parse->num_meta++;
return 0;
}
static int ath11k_wmi_tlv_dma_buf_parse(struct ath11k_base *ab,
u16 tag, u16 len,
const void *ptr, void *data)
{
struct wmi_tlv_dma_buf_release_parse *parse = data;
int ret;
switch (tag) {
case WMI_TAG_DMA_BUF_RELEASE:
memcpy(&parse->fixed, ptr,
sizeof(struct ath11k_wmi_dma_buf_release_fixed_param));
parse->fixed.pdev_id = DP_HW2SW_MACID(parse->fixed.pdev_id);
break;
case WMI_TAG_ARRAY_STRUCT:
if (!parse->buf_entry_done) {
parse->num_buf_entry = 0;
parse->buf_entry = (struct wmi_dma_buf_release_entry *)ptr;
ret = ath11k_wmi_tlv_iter(ab, ptr, len,
ath11k_wmi_tlv_dma_buf_entry_parse,
parse);
if (ret) {
ath11k_warn(ab, "failed to parse dma buf entry tlv %d\n",
ret);
return ret;
}
parse->buf_entry_done = true;
} else if (!parse->meta_data_done) {
parse->num_meta = 0;
parse->meta_data = (struct wmi_dma_buf_release_meta_data *)ptr;
ret = ath11k_wmi_tlv_iter(ab, ptr, len,
ath11k_wmi_tlv_dma_buf_meta_parse,
parse);
if (ret) {
ath11k_warn(ab, "failed to parse dma buf meta tlv %d\n",
ret);
return ret;
}
parse->meta_data_done = true;
}
break;
default:
break;
}
return 0;
}
static void ath11k_wmi_pdev_dma_ring_buf_release_event(struct ath11k_base *ab,
struct sk_buff *skb)
{
struct wmi_tlv_dma_buf_release_parse parse = { };
struct ath11k_dbring_buf_release_event param;
int ret;
ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
ath11k_wmi_tlv_dma_buf_parse,
&parse);
if (ret) {
ath11k_warn(ab, "failed to parse dma buf release tlv %d\n", ret);
return;
}
param.fixed = parse.fixed;
param.buf_entry = parse.buf_entry;
param.num_buf_entry = parse.num_buf_entry;
param.meta_data = parse.meta_data;
param.num_meta = parse.num_meta;
ret = ath11k_dbring_buffer_release_event(ab, &param);
if (ret) {
ath11k_warn(ab, "failed to handle dma buf release event %d\n", ret);
return;
}
}
static int ath11k_wmi_tlv_hw_mode_caps_parse(struct ath11k_base *soc, static int ath11k_wmi_tlv_hw_mode_caps_parse(struct ath11k_base *soc,
u16 tag, u16 len, u16 tag, u16 len,
const void *ptr, void *data) const void *ptr, void *data)
...@@ -3445,6 +3808,95 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc, ...@@ -3445,6 +3808,95 @@ static int ath11k_wmi_tlv_ext_soc_hal_reg_caps_parse(struct ath11k_base *soc,
return 0; return 0;
} }
static int ath11k_wmi_tlv_dma_ring_caps_parse(struct ath11k_base *soc,
u16 tag, u16 len,
const void *ptr, void *data)
{
struct wmi_tlv_dma_ring_caps_parse *parse = data;
if (tag != WMI_TAG_DMA_RING_CAPABILITIES)
return -EPROTO;
parse->n_dma_ring_caps++;
return 0;
}
static int ath11k_wmi_alloc_dbring_caps(struct ath11k_base *ab,
u32 num_cap)
{
size_t sz;
void *ptr;
sz = num_cap * sizeof(struct ath11k_dbring_cap);
ptr = kzalloc(sz, GFP_ATOMIC);
if (!ptr)
return -ENOMEM;
ab->db_caps = ptr;
ab->num_db_cap = num_cap;
return 0;
}
static void ath11k_wmi_free_dbring_caps(struct ath11k_base *ab)
{
kfree(ab->db_caps);
ab->db_caps = NULL;
}
static int ath11k_wmi_tlv_dma_ring_caps(struct ath11k_base *ab,
u16 len, const void *ptr, void *data)
{
struct wmi_tlv_dma_ring_caps_parse *dma_caps_parse = data;
struct wmi_dma_ring_capabilities *dma_caps;
struct ath11k_dbring_cap *dir_buff_caps;
int ret;
u32 i;
dma_caps_parse->n_dma_ring_caps = 0;
dma_caps = (struct wmi_dma_ring_capabilities *)ptr;
ret = ath11k_wmi_tlv_iter(ab, ptr, len,
ath11k_wmi_tlv_dma_ring_caps_parse,
dma_caps_parse);
if (ret) {
ath11k_warn(ab, "failed to parse dma ring caps tlv %d\n", ret);
return ret;
}
if (!dma_caps_parse->n_dma_ring_caps)
return 0;
if (ab->num_db_cap) {
ath11k_warn(ab, "Already processed, so ignoring dma ring caps\n");
return 0;
}
ret = ath11k_wmi_alloc_dbring_caps(ab, dma_caps_parse->n_dma_ring_caps);
if (ret)
return ret;
dir_buff_caps = ab->db_caps;
for (i = 0; i < dma_caps_parse->n_dma_ring_caps; i++) {
if (dma_caps[i].module_id >= WMI_DIRECT_BUF_MAX) {
ath11k_warn(ab, "Invalid module id %d\n", dma_caps[i].module_id);
ret = -EINVAL;
goto free_dir_buff;
}
dir_buff_caps[i].id = dma_caps[i].module_id;
dir_buff_caps[i].pdev_id = DP_HW2SW_MACID(dma_caps[i].pdev_id);
dir_buff_caps[i].min_elem = dma_caps[i].min_elem;
dir_buff_caps[i].min_buf_sz = dma_caps[i].min_buf_sz;
dir_buff_caps[i].min_buf_align = dma_caps[i].min_buf_align;
}
return 0;
free_dir_buff:
ath11k_wmi_free_dbring_caps(ab);
return ret;
}
static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab, static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab,
u16 tag, u16 len, u16 tag, u16 len,
const void *ptr, void *data) const void *ptr, void *data)
...@@ -3501,7 +3953,19 @@ static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab, ...@@ -3501,7 +3953,19 @@ static int ath11k_wmi_tlv_svc_rdy_ext_parse(struct ath11k_base *ab,
return ret; return ret;
svc_rdy_ext->ext_hal_reg_done = true; svc_rdy_ext->ext_hal_reg_done = true;
complete(&ab->wmi_ab.service_ready); } else if (!svc_rdy_ext->mac_phy_chainmask_combo_done) {
svc_rdy_ext->mac_phy_chainmask_combo_done = true;
} else if (!svc_rdy_ext->mac_phy_chainmask_cap_done) {
svc_rdy_ext->mac_phy_chainmask_cap_done = true;
} else if (!svc_rdy_ext->oem_dma_ring_cap_done) {
svc_rdy_ext->oem_dma_ring_cap_done = true;
} else if (!svc_rdy_ext->dma_ring_cap_done) {
ret = ath11k_wmi_tlv_dma_ring_caps(ab, len, ptr,
&svc_rdy_ext->dma_caps_parse);
if (ret)
return ret;
svc_rdy_ext->dma_ring_cap_done = true;
} }
break; break;
...@@ -3522,11 +3986,66 @@ static int ath11k_service_ready_ext_event(struct ath11k_base *ab, ...@@ -3522,11 +3986,66 @@ static int ath11k_service_ready_ext_event(struct ath11k_base *ab,
&svc_rdy_ext); &svc_rdy_ext);
if (ret) { if (ret) {
ath11k_warn(ab, "failed to parse tlv %d\n", ret); ath11k_warn(ab, "failed to parse tlv %d\n", ret);
return ret; goto err;
} }
if (!test_bit(WMI_TLV_SERVICE_EXT2_MSG, ab->wmi_ab.svc_map))
complete(&ab->wmi_ab.service_ready);
kfree(svc_rdy_ext.mac_phy_caps); kfree(svc_rdy_ext.mac_phy_caps);
return 0; return 0;
err:
ath11k_wmi_free_dbring_caps(ab);
return ret;
}
static int ath11k_wmi_tlv_svc_rdy_ext2_parse(struct ath11k_base *ab,
u16 tag, u16 len,
const void *ptr, void *data)
{
struct wmi_tlv_svc_rdy_ext2_parse *parse = data;
int ret;
switch (tag) {
case WMI_TAG_ARRAY_STRUCT:
if (!parse->dma_ring_cap_done) {
ret = ath11k_wmi_tlv_dma_ring_caps(ab, len, ptr,
&parse->dma_caps_parse);
if (ret)
return ret;
parse->dma_ring_cap_done = true;
}
break;
default:
break;
}
return 0;
}
static int ath11k_service_ready_ext2_event(struct ath11k_base *ab,
struct sk_buff *skb)
{
struct wmi_tlv_svc_rdy_ext2_parse svc_rdy_ext2 = { };
int ret;
ret = ath11k_wmi_tlv_iter(ab, skb->data, skb->len,
ath11k_wmi_tlv_svc_rdy_ext2_parse,
&svc_rdy_ext2);
if (ret) {
ath11k_warn(ab, "failed to parse ext2 event tlv %d\n", ret);
goto err;
}
complete(&ab->wmi_ab.service_ready);
return 0;
err:
ath11k_wmi_free_dbring_caps(ab);
return ret;
} }
static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buff *skb, static int ath11k_pull_vdev_start_resp_tlv(struct ath11k_base *ab, struct sk_buff *skb,
...@@ -3822,6 +4341,7 @@ static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab, ...@@ -3822,6 +4341,7 @@ static int ath11k_pull_mgmt_rx_params_tlv(struct ath11k_base *ab,
} }
hdr->pdev_id = ev->pdev_id; hdr->pdev_id = ev->pdev_id;
hdr->chan_freq = ev->chan_freq;
hdr->channel = ev->channel; hdr->channel = ev->channel;
hdr->snr = ev->snr; hdr->snr = ev->snr;
hdr->rate = ev->rate; hdr->rate = ev->rate;
...@@ -5193,7 +5713,9 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) ...@@ -5193,7 +5713,9 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb)
if (rx_ev.status & WMI_RX_STATUS_ERR_MIC) if (rx_ev.status & WMI_RX_STATUS_ERR_MIC)
status->flag |= RX_FLAG_MMIC_ERROR; status->flag |= RX_FLAG_MMIC_ERROR;
if (rx_ev.channel >= 1 && rx_ev.channel <= 14) { if (rx_ev.chan_freq >= ATH11K_MIN_6G_FREQ) {
status->band = NL80211_BAND_6GHZ;
} else if (rx_ev.channel >= 1 && rx_ev.channel <= 14) {
status->band = NL80211_BAND_2GHZ; status->band = NL80211_BAND_2GHZ;
} else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH11K_MAX_5G_CHAN) { } else if (rx_ev.channel >= 36 && rx_ev.channel <= ATH11K_MAX_5G_CHAN) {
status->band = NL80211_BAND_5GHZ; status->band = NL80211_BAND_5GHZ;
...@@ -5206,9 +5728,10 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb) ...@@ -5206,9 +5728,10 @@ static void ath11k_mgmt_rx_event(struct ath11k_base *ab, struct sk_buff *skb)
goto exit; goto exit;
} }
if (rx_ev.phy_mode == MODE_11B && status->band == NL80211_BAND_5GHZ) if (rx_ev.phy_mode == MODE_11B &&
(status->band == NL80211_BAND_5GHZ || status->band == NL80211_BAND_6GHZ))
ath11k_dbg(ab, ATH11K_DBG_WMI, ath11k_dbg(ab, ATH11K_DBG_WMI,
"wmi mgmt rx 11b (CCK) on 5GHz\n"); "wmi mgmt rx 11b (CCK) on 5/6GHz, band = %d\n", status->band);
sband = &ar->mac.sbands[status->band]; sband = &ar->mac.sbands[status->band];
...@@ -5933,6 +6456,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) ...@@ -5933,6 +6456,9 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
case WMI_SERVICE_READY_EXT_EVENTID: case WMI_SERVICE_READY_EXT_EVENTID:
ath11k_service_ready_ext_event(ab, skb); ath11k_service_ready_ext_event(ab, skb);
break; break;
case WMI_SERVICE_READY_EXT2_EVENTID:
ath11k_service_ready_ext2_event(ab, skb);
break;
case WMI_REG_CHAN_LIST_CC_EVENTID: case WMI_REG_CHAN_LIST_CC_EVENTID:
ath11k_reg_chan_list_event(ab, skb); ath11k_reg_chan_list_event(ab, skb);
break; break;
...@@ -5994,12 +6520,16 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb) ...@@ -5994,12 +6520,16 @@ static void ath11k_wmi_tlv_op_rx(struct ath11k_base *ab, struct sk_buff *skb)
case WMI_PDEV_TEMPERATURE_EVENTID: case WMI_PDEV_TEMPERATURE_EVENTID:
ath11k_wmi_pdev_temperature_event(ab, skb); ath11k_wmi_pdev_temperature_event(ab, skb);
break; break;
case WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID:
ath11k_wmi_pdev_dma_ring_buf_release_event(ab, skb);
break;
/* add Unsupported events here */ /* add Unsupported events here */
case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID: case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
case WMI_VDEV_DELETE_RESP_EVENTID: case WMI_VDEV_DELETE_RESP_EVENTID:
case WMI_PEER_OPER_MODE_CHANGE_EVENTID: case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
case WMI_TWT_ENABLE_EVENTID: case WMI_TWT_ENABLE_EVENTID:
case WMI_TWT_DISABLE_EVENTID: case WMI_TWT_DISABLE_EVENTID:
case WMI_PDEV_DMA_RING_CFG_RSP_EVENTID:
ath11k_dbg(ab, ATH11K_DBG_WMI, ath11k_dbg(ab, ATH11K_DBG_WMI,
"ignoring unsupported event 0x%x\n", id); "ignoring unsupported event 0x%x\n", id);
break; break;
...@@ -6213,4 +6743,6 @@ void ath11k_wmi_detach(struct ath11k_base *ab) ...@@ -6213,4 +6743,6 @@ void ath11k_wmi_detach(struct ath11k_base *ab)
for (i = 0; i < ab->htc.wmi_ep_count; i++) for (i = 0; i < ab->htc.wmi_ep_count; i++)
ath11k_wmi_pdev_detach(ab, i); ath11k_wmi_pdev_detach(ab, i);
ath11k_wmi_free_dbring_caps(ab);
} }
...@@ -24,6 +24,8 @@ struct ath11k_fw_stats; ...@@ -24,6 +24,8 @@ struct ath11k_fw_stats;
#define HE_PET_8_USEC 1 #define HE_PET_8_USEC 1
#define HE_PET_16_USEC 2 #define HE_PET_16_USEC 2
#define WMI_MAX_CHAINS 8
#define WMI_MAX_NUM_SS MAX_HE_NSS #define WMI_MAX_NUM_SS MAX_HE_NSS
#define WMI_MAX_NUM_RU MAX_HE_RU #define WMI_MAX_NUM_RU MAX_HE_RU
...@@ -50,10 +52,20 @@ struct wmi_tlv { ...@@ -50,10 +52,20 @@ struct wmi_tlv {
#define WMI_MAX_MEM_REQS 32 #define WMI_MAX_MEM_REQS 32
#define ATH11K_MAX_HW_LISTEN_INTERVAL 5 #define ATH11K_MAX_HW_LISTEN_INTERVAL 5
#define WLAN_SCAN_MAX_HINT_S_SSID 10
#define WLAN_SCAN_MAX_HINT_BSSID 10
#define MAX_RNR_BSS 5
#define WLAN_SCAN_MAX_HINT_S_SSID 10
#define WLAN_SCAN_MAX_HINT_BSSID 10
#define MAX_RNR_BSS 5
#define WLAN_SCAN_PARAMS_MAX_SSID 16 #define WLAN_SCAN_PARAMS_MAX_SSID 16
#define WLAN_SCAN_PARAMS_MAX_BSSID 4 #define WLAN_SCAN_PARAMS_MAX_BSSID 4
#define WLAN_SCAN_PARAMS_MAX_IE_LEN 256 #define WLAN_SCAN_PARAMS_MAX_IE_LEN 256
#define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1
#define WMI_BA_MODE_BUFFER_SIZE_256 3 #define WMI_BA_MODE_BUFFER_SIZE_256 3
/* /*
* HW mode config type replicated from FW header * HW mode config type replicated from FW header
...@@ -586,6 +598,11 @@ enum wmi_tlv_event_id { ...@@ -586,6 +598,11 @@ enum wmi_tlv_event_id {
WMI_PDEV_DMA_RING_CFG_RSP_EVENTID, WMI_PDEV_DMA_RING_CFG_RSP_EVENTID,
WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID, WMI_PDEV_DMA_RING_BUF_RELEASE_EVENTID,
WMI_PDEV_CTL_FAILSAFE_CHECK_EVENTID, WMI_PDEV_CTL_FAILSAFE_CHECK_EVENTID,
WMI_PDEV_CSC_SWITCH_COUNT_STATUS_EVENTID,
WMI_PDEV_COLD_BOOT_CAL_DATA_EVENTID,
WMI_PDEV_RAP_INFO_EVENTID,
WMI_CHAN_RF_CHARACTERIZATION_INFO_EVENTID,
WMI_SERVICE_READY_EXT2_EVENTID,
WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV), WMI_VDEV_START_RESP_EVENTID = WMI_TLV_CMD(WMI_GRP_VDEV),
WMI_VDEV_STOPPED_EVENTID, WMI_VDEV_STOPPED_EVENTID,
WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID, WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
...@@ -1011,6 +1028,7 @@ enum wmi_tlv_vdev_param { ...@@ -1011,6 +1028,7 @@ enum wmi_tlv_vdev_param {
WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME, WMI_VDEV_PARAM_FILS_MAX_CHANNEL_GUARD_TIME,
WMI_VDEV_PARAM_BA_MODE = 0x7e, WMI_VDEV_PARAM_BA_MODE = 0x7e,
WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87, WMI_VDEV_PARAM_SET_HE_SOUNDING_MODE = 0x87,
WMI_VDEV_PARAM_6GHZ_PARAMS = 0x99,
WMI_VDEV_PARAM_PROTOTYPE = 0x8000, WMI_VDEV_PARAM_PROTOTYPE = 0x8000,
WMI_VDEV_PARAM_BSS_COLOR, WMI_VDEV_PARAM_BSS_COLOR,
WMI_VDEV_PARAM_SET_HEMU_MODE, WMI_VDEV_PARAM_SET_HEMU_MODE,
...@@ -2013,9 +2031,10 @@ enum wmi_tlv_service { ...@@ -2013,9 +2031,10 @@ enum wmi_tlv_service {
WMI_TLV_SERVICE_DSM_ROAM_FILTER = 211, WMI_TLV_SERVICE_DSM_ROAM_FILTER = 211,
WMI_TLV_SERVICE_PACKET_CAPTURE_SUPPORT = 212, WMI_TLV_SERVICE_PACKET_CAPTURE_SUPPORT = 212,
WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213, WMI_TLV_SERVICE_PER_PEER_HTT_STATS_RESET = 213,
WMI_TLV_SERVICE_FREQINFO_IN_METADATA = 219,
WMI_TLV_SERVICE_EXT2_MSG = 220,
WMI_MAX_EXT_SERVICE WMI_MAX_EXT_SERVICE
}; };
enum { enum {
...@@ -2076,6 +2095,14 @@ enum wmi_beacon_gen_mode { ...@@ -2076,6 +2095,14 @@ enum wmi_beacon_gen_mode {
WMI_BEACON_BURST_MODE = 1 WMI_BEACON_BURST_MODE = 1
}; };
enum wmi_direct_buffer_module {
WMI_DIRECT_BUF_SPECTRAL = 0,
WMI_DIRECT_BUF_CFR = 1,
/* keep it last */
WMI_DIRECT_BUF_MAX
};
struct wmi_host_pdev_band_to_mac { struct wmi_host_pdev_band_to_mac {
u32 pdev_id; u32 pdev_id;
u32 start_freq; u32 start_freq;
...@@ -2382,6 +2409,15 @@ struct wmi_mac_addr { ...@@ -2382,6 +2409,15 @@ struct wmi_mac_addr {
} __packed; } __packed;
} __packed; } __packed;
struct wmi_dma_ring_capabilities {
u32 tlv_header;
u32 pdev_id;
u32 module_id;
u32 min_elem;
u32 min_buf_sz;
u32 min_buf_align;
} __packed;
struct wmi_ready_event_min { struct wmi_ready_event_min {
struct wmi_abi_version fw_abi_vers; struct wmi_abi_version fw_abi_vers;
struct wmi_mac_addr mac_addr; struct wmi_mac_addr mac_addr;
...@@ -2519,7 +2555,8 @@ struct channel_param { ...@@ -2519,7 +2555,8 @@ struct channel_param {
allow_ht:1, allow_ht:1,
allow_vht:1, allow_vht:1,
allow_he:1, allow_he:1,
set_agile:1; set_agile:1,
psc_channel:1;
u32 phy_mode; u32 phy_mode;
u32 cfreq1; u32 cfreq1;
u32 cfreq2; u32 cfreq2;
...@@ -3059,6 +3096,9 @@ struct wmi_start_scan_cmd { ...@@ -3059,6 +3096,9 @@ struct wmi_start_scan_cmd {
u32 num_vendor_oui; u32 num_vendor_oui;
u32 scan_ctrl_flags_ext; u32 scan_ctrl_flags_ext;
u32 dwell_time_active_2g; u32 dwell_time_active_2g;
u32 dwell_time_active_6g;
u32 dwell_time_passive_6g;
u32 scan_start_offset;
} __packed; } __packed;
#define WMI_SCAN_FLAG_PASSIVE 0x1 #define WMI_SCAN_FLAG_PASSIVE 0x1
...@@ -3098,6 +3138,16 @@ enum { ...@@ -3098,6 +3138,16 @@ enum {
((flag) |= (((mode) << WMI_SCAN_DWELL_MODE_SHIFT) & \ ((flag) |= (((mode) << WMI_SCAN_DWELL_MODE_SHIFT) & \
WMI_SCAN_DWELL_MODE_MASK)) WMI_SCAN_DWELL_MODE_MASK))
struct hint_short_ssid {
u32 freq_flags;
u32 short_ssid;
};
struct hint_bssid {
u32 freq_flags;
struct wmi_mac_addr bssid;
};
struct scan_req_params { struct scan_req_params {
u32 scan_id; u32 scan_id;
u32 scan_req_id; u32 scan_req_id;
...@@ -3125,6 +3175,8 @@ struct scan_req_params { ...@@ -3125,6 +3175,8 @@ struct scan_req_params {
u32 dwell_time_active; u32 dwell_time_active;
u32 dwell_time_active_2g; u32 dwell_time_active_2g;
u32 dwell_time_passive; u32 dwell_time_passive;
u32 dwell_time_active_6g;
u32 dwell_time_passive_6g;
u32 min_rest_time; u32 min_rest_time;
u32 max_rest_time; u32 max_rest_time;
u32 repeat_probe_time; u32 repeat_probe_time;
...@@ -3175,6 +3227,10 @@ struct scan_req_params { ...@@ -3175,6 +3227,10 @@ struct scan_req_params {
struct element_info extraie; struct element_info extraie;
struct element_info htcap; struct element_info htcap;
struct element_info vhtcap; struct element_info vhtcap;
u32 num_hint_s_ssid;
u32 num_hint_bssid;
struct hint_short_ssid hint_s_ssid[WLAN_SCAN_MAX_HINT_S_SSID];
struct hint_bssid hint_bssid[WLAN_SCAN_MAX_HINT_BSSID];
}; };
struct wmi_ssid_arg { struct wmi_ssid_arg {
...@@ -3264,6 +3320,7 @@ struct wmi_bcn_send_from_host_cmd { ...@@ -3264,6 +3320,7 @@ struct wmi_bcn_send_from_host_cmd {
#define WMI_CHAN_INFO_QUARTER_RATE BIT(15) #define WMI_CHAN_INFO_QUARTER_RATE BIT(15)
#define WMI_CHAN_INFO_DFS_FREQ2 BIT(16) #define WMI_CHAN_INFO_DFS_FREQ2 BIT(16)
#define WMI_CHAN_INFO_ALLOW_HE BIT(17) #define WMI_CHAN_INFO_ALLOW_HE BIT(17)
#define WMI_CHAN_INFO_PSC BIT(18)
#define WMI_CHAN_REG_INFO1_MIN_PWR GENMASK(7, 0) #define WMI_CHAN_REG_INFO1_MIN_PWR GENMASK(7, 0)
#define WMI_CHAN_REG_INFO1_MAX_PWR GENMASK(15, 8) #define WMI_CHAN_REG_INFO1_MAX_PWR GENMASK(15, 8)
...@@ -3444,6 +3501,7 @@ struct peer_assoc_params { ...@@ -3444,6 +3501,7 @@ struct peer_assoc_params {
u32 tx_max_rate; u32 tx_max_rate;
u32 tx_mcs_set; u32 tx_mcs_set;
u8 vht_capable; u8 vht_capable;
u8 min_data_rate;
u32 tx_max_mcs_nss; u32 tx_max_mcs_nss;
u32 peer_bw_rxnss_override; u32 peer_bw_rxnss_override;
bool is_pmf_enabled; bool is_pmf_enabled;
...@@ -3472,6 +3530,7 @@ struct peer_assoc_params { ...@@ -3472,6 +3530,7 @@ struct peer_assoc_params {
bool he_flag; bool he_flag;
u32 peer_he_cap_macinfo[2]; u32 peer_he_cap_macinfo[2];
u32 peer_he_cap_macinfo_internal; u32 peer_he_cap_macinfo_internal;
u32 peer_he_caps_6ghz;
u32 peer_he_ops; u32 peer_he_ops;
u32 peer_he_cap_phyinfo[WMI_HOST_MAX_HECAP_PHY_SIZE]; u32 peer_he_cap_phyinfo[WMI_HOST_MAX_HECAP_PHY_SIZE];
u32 peer_he_mcs_count; u32 peer_he_mcs_count;
...@@ -3509,6 +3568,8 @@ struct wmi_peer_assoc_complete_cmd { ...@@ -3509,6 +3568,8 @@ struct wmi_peer_assoc_complete_cmd {
u32 peer_he_mcs; u32 peer_he_mcs;
u32 peer_he_cap_info_ext; u32 peer_he_cap_info_ext;
u32 peer_he_cap_info_internal; u32 peer_he_cap_info_internal;
u32 min_data_rate;
u32 peer_he_caps_6ghz;
} __packed; } __packed;
struct wmi_stop_scan_cmd { struct wmi_stop_scan_cmd {
...@@ -4228,6 +4289,7 @@ struct wmi_pdev_temperature_event { ...@@ -4228,6 +4289,7 @@ struct wmi_pdev_temperature_event {
#define WLAN_MGMT_TXRX_HOST_MAX_ANTENNA 4 #define WLAN_MGMT_TXRX_HOST_MAX_ANTENNA 4
struct mgmt_rx_event_params { struct mgmt_rx_event_params {
u32 chan_freq;
u32 channel; u32 channel;
u32 snr; u32 snr;
u8 rssi_ctl[WLAN_MGMT_TXRX_HOST_MAX_ANTENNA]; u8 rssi_ctl[WLAN_MGMT_TXRX_HOST_MAX_ANTENNA];
...@@ -4257,6 +4319,7 @@ struct wmi_mgmt_rx_hdr { ...@@ -4257,6 +4319,7 @@ struct wmi_mgmt_rx_hdr {
u32 rx_tsf_l32; u32 rx_tsf_l32;
u32 rx_tsf_u32; u32 rx_tsf_u32;
u32 pdev_id; u32 pdev_id;
u32 chan_freq;
} __packed; } __packed;
#define MAX_ANTENNA_EIGHT 8 #define MAX_ANTENNA_EIGHT 8
...@@ -4734,6 +4797,117 @@ struct ath11k_wmi_pdev_lro_config_cmd { ...@@ -4734,6 +4797,117 @@ struct ath11k_wmi_pdev_lro_config_cmd {
u32 pdev_id; u32 pdev_id;
} __packed; } __packed;
#define ATH11K_WMI_SPECTRAL_COUNT_DEFAULT 0
#define ATH11K_WMI_SPECTRAL_PERIOD_DEFAULT 224
#define ATH11K_WMI_SPECTRAL_PRIORITY_DEFAULT 1
#define ATH11K_WMI_SPECTRAL_FFT_SIZE_DEFAULT 7
#define ATH11K_WMI_SPECTRAL_GC_ENA_DEFAULT 1
#define ATH11K_WMI_SPECTRAL_RESTART_ENA_DEFAULT 0
#define ATH11K_WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT -96
#define ATH11K_WMI_SPECTRAL_INIT_DELAY_DEFAULT 80
#define ATH11K_WMI_SPECTRAL_NB_TONE_THR_DEFAULT 12
#define ATH11K_WMI_SPECTRAL_STR_BIN_THR_DEFAULT 8
#define ATH11K_WMI_SPECTRAL_WB_RPT_MODE_DEFAULT 0
#define ATH11K_WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT 0
#define ATH11K_WMI_SPECTRAL_RSSI_THR_DEFAULT 0xf0
#define ATH11K_WMI_SPECTRAL_PWR_FORMAT_DEFAULT 0
#define ATH11K_WMI_SPECTRAL_RPT_MODE_DEFAULT 2
#define ATH11K_WMI_SPECTRAL_BIN_SCALE_DEFAULT 1
#define ATH11K_WMI_SPECTRAL_DBM_ADJ_DEFAULT 1
#define ATH11K_WMI_SPECTRAL_CHN_MASK_DEFAULT 1
struct ath11k_wmi_vdev_spectral_conf_param {
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;
} __packed;
struct ath11k_wmi_vdev_spectral_conf_cmd {
u32 tlv_header;
struct ath11k_wmi_vdev_spectral_conf_param param;
} __packed;
#define ATH11K_WMI_SPECTRAL_TRIGGER_CMD_TRIGGER 1
#define ATH11K_WMI_SPECTRAL_TRIGGER_CMD_CLEAR 2
#define ATH11K_WMI_SPECTRAL_ENABLE_CMD_ENABLE 1
#define ATH11K_WMI_SPECTRAL_ENABLE_CMD_DISABLE 2
struct ath11k_wmi_vdev_spectral_enable_cmd {
u32 tlv_header;
u32 vdev_id;
u32 trigger_cmd;
u32 enable_cmd;
} __packed;
struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd {
u32 tlv_header;
u32 pdev_id;
u32 module_id; /* see enum wmi_direct_buffer_module */
u32 base_paddr_lo;
u32 base_paddr_hi;
u32 head_idx_paddr_lo;
u32 head_idx_paddr_hi;
u32 tail_idx_paddr_lo;
u32 tail_idx_paddr_hi;
u32 num_elems; /* Number of elems in the ring */
u32 buf_size; /* size of allocated buffer in bytes */
/* Number of wmi_dma_buf_release_entry packed together */
u32 num_resp_per_event;
/* Target should timeout and send whatever resp
* it has if this time expires, units in milliseconds
*/
u32 event_timeout_ms;
} __packed;
struct ath11k_wmi_dma_buf_release_fixed_param {
u32 pdev_id;
u32 module_id;
u32 num_buf_release_entry;
u32 num_meta_data_entry;
} __packed;
struct wmi_dma_buf_release_entry {
u32 tlv_header;
u32 paddr_lo;
/* Bits 11:0: address of data
* Bits 31:12: host context data
*/
u32 paddr_hi;
} __packed;
#define WMI_SPECTRAL_META_INFO1_FREQ1 GENMASK(15, 0)
#define WMI_SPECTRAL_META_INFO1_FREQ2 GENMASK(31, 16)
#define WMI_SPECTRAL_META_INFO2_CHN_WIDTH GENMASK(7, 0)
struct wmi_dma_buf_release_meta_data {
u32 tlv_header;
s32 noise_floor[WMI_MAX_CHAINS];
u32 reset_delay;
u32 freq1;
u32 freq2;
u32 ch_width;
} __packed;
struct target_resource_config { struct target_resource_config {
u32 num_vdevs; u32 num_vdevs;
u32 num_peers; u32 num_peers;
...@@ -4941,4 +5115,10 @@ int ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id, ...@@ -4941,4 +5115,10 @@ int ath11k_wmi_send_obss_color_collision_cfg_cmd(struct ath11k *ar, u32 vdev_id,
int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id, int ath11k_wmi_send_bss_color_change_enable_cmd(struct ath11k *ar, u32 vdev_id,
bool enable); bool enable);
int ath11k_wmi_pdev_lro_cfg(struct ath11k *ar, int pdev_id); int ath11k_wmi_pdev_lro_cfg(struct ath11k *ar, int pdev_id);
int ath11k_wmi_pdev_dma_ring_cfg(struct ath11k *ar,
struct ath11k_wmi_pdev_dma_ring_cfg_req_cmd *param);
int ath11k_wmi_vdev_spectral_enable(struct ath11k *ar, u32 vdev_id,
u32 trigger, u32 enable);
int ath11k_wmi_vdev_spectral_conf(struct ath11k *ar,
struct ath11k_wmi_vdev_spectral_conf_param *param);
#endif #endif
...@@ -34,7 +34,7 @@ config ATH9K ...@@ -34,7 +34,7 @@ config ATH9K
APs that come with these cards refer to ath9k wiki APs that come with these cards refer to ath9k wiki
products page: products page:
http://wireless.kernel.org/en/users/Drivers/ath9k/products https://wireless.wiki.kernel.org/en/users/Drivers/ath9k/products
If you choose to build a module, it'll be called ath9k. If you choose to build a module, it'll be called ath9k.
...@@ -185,7 +185,8 @@ config ATH9K_HTC ...@@ -185,7 +185,8 @@ config ATH9K_HTC
Support for Atheros HTC based cards. Support for Atheros HTC based cards.
Chipsets supported: AR9271 Chipsets supported: AR9271
For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc For more information:
https://wireless.wiki.kernel.org/en/users/Drivers/ath9k_htc
The built module will be ath9k_htc. The built module will be ath9k_htc.
......
...@@ -2410,7 +2410,7 @@ static u8 fixup_chainmask(u8 chip_chainmask, u8 eeprom_chainmask) ...@@ -2410,7 +2410,7 @@ static u8 fixup_chainmask(u8 chip_chainmask, u8 eeprom_chainmask)
* of tests. The testing requirements are going to be documented. Desired * of tests. The testing requirements are going to be documented. Desired
* test requirements are documented at: * test requirements are documented at:
* *
* http://wireless.kernel.org/en/users/Drivers/ath9k/dfs * https://wireless.wiki.kernel.org/en/users/Drivers/ath9k/dfs
* *
* Once a new chipset gets properly tested an individual commit can be used * Once a new chipset gets properly tested an individual commit can be used
* to document the testing for DFS for that chipset. * to document the testing for DFS for that chipset.
......
...@@ -10,7 +10,7 @@ config CARL9170 ...@@ -10,7 +10,7 @@ config CARL9170
It needs a special firmware (carl9170-1.fw), which can be downloaded It needs a special firmware (carl9170-1.fw), which can be downloaded
from our wiki here: from our wiki here:
<http://wireless.kernel.org/en/users/Drivers/carl9170> <https://wireless.wiki.kernel.org/en/users/Drivers/carl9170>
If you choose to build a module, it'll be called carl9170. If you choose to build a module, it'll be called carl9170.
......
...@@ -61,7 +61,7 @@ MODULE_ALIAS("arusb_lnx"); ...@@ -61,7 +61,7 @@ MODULE_ALIAS("arusb_lnx");
* Note: * Note:
* *
* Always update our wiki's device list (located at: * Always update our wiki's device list (located at:
* http://wireless.kernel.org/en/users/Drivers/ar9170/devices ), * https://wireless.wiki.kernel.org/en/users/Drivers/ar9170/devices ),
* whenever you add a new device. * whenever you add a new device.
*/ */
static const struct usb_device_id carl9170_usb_ids[] = { static const struct usb_device_id carl9170_usb_ids[] = {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
* could be acquired so far. * could be acquired so far.
*/ */
#define SPECTRAL_ATH10K_MAX_NUM_BINS 256 #define SPECTRAL_ATH10K_MAX_NUM_BINS 256
#define SPECTRAL_ATH11K_MAX_NUM_BINS 512
/* FFT sample format given to userspace via debugfs. /* FFT sample format given to userspace via debugfs.
* *
...@@ -37,6 +38,7 @@ enum ath_fft_sample_type { ...@@ -37,6 +38,7 @@ enum ath_fft_sample_type {
ATH_FFT_SAMPLE_HT20 = 1, ATH_FFT_SAMPLE_HT20 = 1,
ATH_FFT_SAMPLE_HT20_40, ATH_FFT_SAMPLE_HT20_40,
ATH_FFT_SAMPLE_ATH10K, ATH_FFT_SAMPLE_ATH10K,
ATH_FFT_SAMPLE_ATH11K
}; };
struct fft_sample_tlv { struct fft_sample_tlv {
...@@ -110,4 +112,19 @@ struct fft_sample_ath10k { ...@@ -110,4 +112,19 @@ struct fft_sample_ath10k {
u8 data[0]; u8 data[0];
} __packed; } __packed;
struct fft_sample_ath11k {
struct fft_sample_tlv tlv;
u8 chan_width_mhz;
s8 max_index;
u8 max_exp;
__be16 freq1;
__be16 freq2;
__be16 max_magnitude;
__be16 rssi;
__be32 tsf;
__be32 noise;
u8 data[0];
} __packed;
#endif /* SPECTRAL_COMMON_H */ #endif /* SPECTRAL_COMMON_H */
...@@ -10,7 +10,7 @@ config WIL6210 ...@@ -10,7 +10,7 @@ config WIL6210
wil6210 chip by Wilocity. It supports operation on the wil6210 chip by Wilocity. It supports operation on the
60 GHz band, covered by the IEEE802.11ad standard. 60 GHz band, covered by the IEEE802.11ad standard.
http://wireless.kernel.org/en/users/Drivers/wil6210 https://wireless.wiki.kernel.org/en/users/Drivers/wil6210
If you choose to build it as a module, it will be called If you choose to build it as a module, it will be called
wil6210 wil6210
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment