Skip to content

Commit

Permalink
ath11k: register vendor sub command for CFR configuration
Browse files Browse the repository at this point in the history
Add support to parse CFR parameters configured through
the vendor commands.

Also, send the required WMI commands to the firmware based
on the CFR configurations.

Tested-on: IPQ8074 WLAN.HK.2.5.0.1-00991-QCAHKSWPL_SILICONZ-1

Signed-off-by: Venkateswara Naralasetty <quic_vnaralas@quicinc.com>
  • Loading branch information
Venkateswara Naralasetty authored and intel-lab-lkp committed Feb 11, 2022
1 parent 923d7b8 commit f43f535
Show file tree
Hide file tree
Showing 9 changed files with 639 additions and 6 deletions.
3 changes: 2 additions & 1 deletion drivers/net/wireless/ath/ath11k/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ ath11k-y += core.o \
peer.o \
dbring.o \
hw.o \
wow.o
wow.o \
vendor.o

ath11k-$(CONFIG_ATH11K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
ath11k-$(CONFIG_NL80211_TESTMODE) += testmode.o
Expand Down
227 changes: 227 additions & 0 deletions drivers/net/wireless/ath/ath11k/cfr.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,233 @@ static int ath11k_cfr_process_data(struct ath11k *ar,
return 0;
}

/* Helper function to check whether the given peer mac address
* is in unassociated peer pool or not.
*/
bool ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar, const u8 *peer_mac)
{
struct ath11k_cfr *cfr = &ar->cfr;
struct cfr_unassoc_pool_entry *entry;
int i;

if (!ar->cfr_enabled)
return false;

spin_lock_bh(&cfr->lock);
for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) {
entry = &cfr->unassoc_pool[i];
if (!entry->is_valid)
continue;

if (ether_addr_equal(peer_mac, entry->peer_mac)) {
spin_unlock_bh(&cfr->lock);
return true;
}
}

spin_unlock_bh(&cfr->lock);

return false;
}

void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar,
const u8 *peer_mac)
{
struct ath11k_cfr *cfr = &ar->cfr;
struct cfr_unassoc_pool_entry *entry;
int i;

spin_lock_bh(&cfr->lock);
for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) {
entry = &cfr->unassoc_pool[i];
if (!entry->is_valid)
continue;

if (ether_addr_equal(peer_mac, entry->peer_mac) &&
entry->period == 0) {
memset(entry->peer_mac, 0, ETH_ALEN);
entry->is_valid = false;
cfr->cfr_enabled_peer_cnt--;
break;
}
}

spin_unlock_bh(&cfr->lock);
}

void ath11k_cfr_decrement_peer_count(struct ath11k *ar,
struct ath11k_sta *arsta)
{
struct ath11k_cfr *cfr = &ar->cfr;

spin_lock_bh(&cfr->lock);

if (arsta->cfr_capture.cfr_enable)
cfr->cfr_enabled_peer_cnt--;

spin_unlock_bh(&cfr->lock);
}

static enum ath11k_wmi_cfr_capture_bw
ath11k_cfr_bw_to_fw_cfr_bw(enum ath11k_cfr_capture_bw bw)
{
switch (bw) {
case ATH11K_CFR_CAPTURE_BW_20:
return WMI_PEER_CFR_CAPTURE_BW_20;
case ATH11K_CFR_CAPTURE_BW_40:
return WMI_PEER_CFR_CAPTURE_BW_40;
case ATH11K_CFR_CAPTURE_BW_80:
return WMI_PEER_CFR_CAPTURE_BW_80;
default:
return WMI_PEER_CFR_CAPTURE_BW_MAX;
}
}

static enum ath11k_wmi_cfr_capture_method
ath11k_cfr_method_to_fw_cfr_method(enum ath11k_cfr_capture_method method)
{
switch (method) {
case ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME:
return WMI_CFR_CAPTURE_METHOD_NULL_FRAME;
case ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE:
return WMI_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE;
case ATH11K_CFR_CAPTURE_METHOD_PROBE_RESP:
return WMI_CFR_CAPTURE_METHOD_PROBE_RESP;
default:
return WMI_CFR_CAPTURE_METHOD_MAX;
}
}

int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar,
struct ath11k_sta *arsta,
struct ath11k_per_peer_cfr_capture *params,
const u8 *peer_mac)
{
struct ath11k_cfr *cfr = &ar->cfr;
struct wmi_peer_cfr_capture_conf_arg arg;
enum ath11k_wmi_cfr_capture_bw bw;
enum ath11k_wmi_cfr_capture_method method;
int ret = 0;

if (cfr->cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS &&
!arsta->cfr_capture.cfr_enable) {
ath11k_err(ar->ab, "CFR enable peer threshold reached %u\n",
cfr->cfr_enabled_peer_cnt);
return -ENOSPC;
}

if (params->cfr_enable == arsta->cfr_capture.cfr_enable &&
params->cfr_period == arsta->cfr_capture.cfr_period &&
params->cfr_method == arsta->cfr_capture.cfr_method &&
params->cfr_bw == arsta->cfr_capture.cfr_bw)
return ret;

if (!params->cfr_enable && !arsta->cfr_capture.cfr_enable)
return ret;

bw = ath11k_cfr_bw_to_fw_cfr_bw(params->cfr_bw);
if (bw >= WMI_PEER_CFR_CAPTURE_BW_MAX) {
ath11k_warn(ar->ab, "FW doesn't support configured bw %d\n",
params->cfr_bw);
return -EINVAL;
}

method = ath11k_cfr_method_to_fw_cfr_method(params->cfr_method);
if (method >= WMI_CFR_CAPTURE_METHOD_MAX) {
ath11k_warn(ar->ab, "FW doesn't support configured method %d\n",
params->cfr_method);
return -EINVAL;
}

arg.request = params->cfr_enable;
arg.periodicity = params->cfr_period;
arg.bw = bw;
arg.method = method;

ret = ath11k_wmi_peer_set_cfr_capture_conf(ar, arsta->arvif->vdev_id,
peer_mac, &arg);
if (ret) {
ath11k_warn(ar->ab,
"failed to send cfr capture info: vdev_id %u peer %pM\n",
arsta->arvif->vdev_id, peer_mac);
return ret;
}

spin_lock_bh(&cfr->lock);

if (params->cfr_enable &&
params->cfr_enable != arsta->cfr_capture.cfr_enable)
cfr->cfr_enabled_peer_cnt++;
else if (!params->cfr_enable)
cfr->cfr_enabled_peer_cnt--;

spin_unlock_bh(&cfr->lock);

arsta->cfr_capture.cfr_enable = params->cfr_enable;
arsta->cfr_capture.cfr_period = params->cfr_period;
arsta->cfr_capture.cfr_method = params->cfr_method;
arsta->cfr_capture.cfr_bw = params->cfr_bw;

return ret;
}

void ath11k_cfr_update_unassoc_pool(struct ath11k *ar,
struct ath11k_per_peer_cfr_capture *params,
u8 *peer_mac)
{
struct ath11k_cfr *cfr = &ar->cfr;
struct cfr_unassoc_pool_entry *entry;
int i;
int available_idx = -1;

spin_lock_bh(&cfr->lock);

if (!params->cfr_enable) {
for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) {
entry = &cfr->unassoc_pool[i];
if (ether_addr_equal(peer_mac, entry->peer_mac)) {
memset(entry->peer_mac, 0, ETH_ALEN);
entry->is_valid = false;
cfr->cfr_enabled_peer_cnt--;
break;
}
}

goto exit;
}

if (cfr->cfr_enabled_peer_cnt >= ATH11K_MAX_CFR_ENABLED_CLIENTS) {
ath11k_info(ar->ab, "Max cfr peer threshold reached\n");
goto exit;
}

for (i = 0; i < ATH11K_MAX_CFR_ENABLED_CLIENTS; i++) {
entry = &cfr->unassoc_pool[i];

if (ether_addr_equal(peer_mac, entry->peer_mac)) {
ath11k_info(ar->ab,
"peer entry already present updating params\n");
entry->period = params->cfr_period;
available_idx = -1;
break;
}

if (available_idx < 0 && !entry->is_valid)
available_idx = i;
}

if (available_idx >= 0) {
entry = &cfr->unassoc_pool[available_idx];
ether_addr_copy(entry->peer_mac, peer_mac);
entry->period = params->cfr_period;
entry->is_valid = true;
cfr->cfr_enabled_peer_cnt++;
}

exit:
spin_unlock_bh(&cfr->lock);
}

static struct dentry *create_buf_file_handler(const char *filename,
struct dentry *parent,
umode_t mode,
Expand Down
72 changes: 72 additions & 0 deletions drivers/net/wireless/ath/ath11k/cfr.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
#define ATH11K_CFR_NUM_RESP_PER_EVENT 1
#define ATH11K_CFR_EVENT_TIMEOUT_MS 1

#define ATH11K_MAX_CFR_ENABLED_CLIENTS 10
#define CFR_MAX_LUT_ENTRIES 136

#define HOST_MAX_CHAINS 8

struct ath11k_sta;
struct ath11k_per_peer_cfr_capture;

struct ath11k_cfir_dma_hdr {
u16 info0;
u16 info1;
Expand All @@ -42,12 +46,19 @@ struct ath11k_look_up_table {
struct ath11k_dbring_element *buff;
};

struct cfr_unassoc_pool_entry {
u8 peer_mac[ETH_ALEN];
u32 period;
bool is_valid;
};

struct ath11k_cfr {
struct ath11k_dbring rx_ring;
/* Protects cfr data */
spinlock_t lock;
struct rchan *rfs_cfr_capture;
struct ath11k_look_up_table *lut;
u8 cfr_enabled_peer_cnt;
u32 lut_num;
u32 dbr_buf_size;
u32 dbr_num_bufs;
Expand All @@ -67,13 +78,42 @@ struct ath11k_cfr {
u64 clear_txrx_event;
u64 cfr_dma_aborts;
u64 flush_timeout_dbr_cnt;
struct cfr_unassoc_pool_entry unassoc_pool[ATH11K_MAX_CFR_ENABLED_CLIENTS];
};

enum ath11k_cfr_capture_method {
ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME,
ATH11K_CFR_CAPTURE_METHOD_NULL_FRAME_WITH_PHASE,
ATH11K_CFR_CAPTURE_METHOD_PROBE_RESP,
ATH11K_CFR_CAPTURE_METHOD_MAX,
};

enum ath11k_cfr_capture_bw {
ATH11K_CFR_CAPTURE_BW_20,
ATH11K_CFR_CAPTURE_BW_40,
ATH11K_CFR_CAPTURE_BW_80,
ATH11K_CFR_CAPTURE_BW_MAX,
};

#ifdef CONFIG_ATH11K_CFR
int ath11k_cfr_init(struct ath11k_base *ab);
void ath11k_cfr_deinit(struct ath11k_base *ab);
void ath11k_cfr_lut_update_paddr(struct ath11k *ar, dma_addr_t paddr,
u32 buf_id);
void ath11k_cfr_decrement_peer_count(struct ath11k *ar,
struct ath11k_sta *arsta);
void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar,
const u8 *peer_mac);
bool ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar,
const u8 *peer_mac);
void ath11k_cfr_update_unassoc_pool(struct ath11k *ar,
struct ath11k_per_peer_cfr_capture *params,
u8 *peer_mac);
int ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar,
struct ath11k_sta *arsta,
struct ath11k_per_peer_cfr_capture *params,
const u8 *peer_mac);

#else
static inline int ath11k_cfr_init(struct ath11k_base *ab)
{
Expand All @@ -88,5 +128,37 @@ static inline void ath11k_cfr_lut_update_paddr(struct ath11k *ar,
dma_addr_t paddr, u32 buf_id)
{
}

static inline void ath11k_cfr_decrement_peer_count(struct ath11k *ar,
struct ath11k_sta *arsta)
{
}

static inline void ath11k_cfr_update_unassoc_pool_entry(struct ath11k *ar,
const u8 *peer_mac)
{
}

static inline bool
ath11k_cfr_peer_is_in_cfr_unassoc_pool(struct ath11k *ar, const u8 *peer_mac)
{
return false;
}

static inline void
ath11k_cfr_update_unassoc_pool(struct ath11k *ar,
struct ath11k_per_peer_cfr_capture *params,
u8 *peer_mac)
{
}

static inline int
ath11k_cfr_send_peer_cfr_capture_cmd(struct ath11k *ar,
struct ath11k_sta *arsta,
struct ath11k_per_peer_cfr_capture *params,
const u8 *peer_mac)
{
return 0;
}
#endif /* CONFIG_ATH11K_CFR */
#endif /* ATH11K_CFR_H */
11 changes: 11 additions & 0 deletions drivers/net/wireless/ath/ath11k/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "dbring.h"
#include "spectral.h"
#include "cfr.h"
#include "vendor.h"

#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)

Expand Down Expand Up @@ -375,6 +376,13 @@ struct ath11k_per_ppdu_tx_stats {
u32 retry_bytes;
};

struct ath11k_per_peer_cfr_capture {
enum ath11k_cfr_capture_method cfr_method;
enum ath11k_cfr_capture_bw cfr_bw;
u32 cfr_enable;
u32 cfr_period;
};

struct ath11k_sta {
struct ath11k_vif *arvif;

Expand Down Expand Up @@ -405,6 +413,9 @@ struct ath11k_sta {

bool use_4addr_set;
u16 tcl_metadata;
#ifdef CONFIG_ATH11K_CFR
struct ath11k_per_peer_cfr_capture cfr_capture;
#endif
};

#define ATH11K_MIN_5G_FREQ 4150
Expand Down

0 comments on commit f43f535

Please sign in to comment.