qcacld-3.0: Add HDD files for CFR component

Add host driver interface files for Channel frenquency response (CFR).

Change-Id: I8ac35befa797d8100b38210cd3831b9a78bb03f1
CRs-Fixed: 2637146
This commit is contained in:
Wu Gao 2020-03-07 17:06:34 +08:00 committed by nshrivas
parent 2a536beb66
commit 4425921c33
3 changed files with 449 additions and 0 deletions

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC : wlan_hdd_cfr.h
*
* WLAN Host Device Driver cfr capture implementation
*
*/
#if !defined(_WLAN_HDD_CFR_H)
#define _WLAN_HDD_CFR_H
#ifdef WLAN_CFR_ENABLE
#define HDD_INVALID_GROUP_ID 16
#define ENHANCED_CFR_VERSION 2
/**
* wlan_hdd_cfg80211_peer_cfr_capture_cfg() - configure peer cfr capture
* @wiphy: WIPHY structure pointer
* @wdev: Wireless device structure pointer
* @data: Pointer to the data received
* @data_len: Length of the data received
*
* This function starts CFR capture
*
* Return: 0 on success and errno on failure
*/
int
wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
int data_len);
extern const struct nla_policy cfr_config_policy[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1];
#define FEATURE_CFR_VENDOR_COMMANDS \
{ \
.info.vendor_id = QCA_NL80211_VENDOR_ID, \
.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_PEER_CFR_CAPTURE_CFG, \
.flags = WIPHY_VENDOR_CMD_NEED_WDEV | \
WIPHY_VENDOR_CMD_NEED_NETDEV, \
.doit = wlan_hdd_cfg80211_peer_cfr_capture_cfg, \
vendor_command_policy(cfr_config_policy, \
QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX) \
},
#else
#define FEATURE_CFR_VENDOR_COMMANDS
#endif /* WLAN_CFR_ENABLE */
#endif /* _WLAN_HDD_CFR_H */

View File

@ -149,6 +149,7 @@
#include "wlan_hdd_btc_chain_mode.h"
#include "os_if_nan.h"
#include "wlan_hdd_apf.h"
#include "wlan_hdd_cfr.h"
#define g_mode_rates_size (12)
#define a_mode_rates_size (8)
@ -14301,6 +14302,7 @@ const struct wiphy_vendor_command hdd_wiphy_vendor_commands[] = {
FEATURE_BSS_TRANSITION_VENDOR_COMMANDS
FEATURE_SPECTRAL_SCAN_VENDOR_COMMANDS
FEATURE_CFR_VENDOR_COMMANDS
FEATURE_11AX_VENDOR_COMMANDS
{

381
core/hdd/src/wlan_hdd_cfr.c Normal file
View File

@ -0,0 +1,381 @@
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**
* DOC: wlan_hdd_cfr.c
*
* WLAN Host Device Driver CFR capture Implementation
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <net/cfg80211.h>
#include "wlan_hdd_includes.h"
#include "osif_sync.h"
#include "wlan_hdd_cfr.h"
#include "wlan_cfr_ucfg_api.h"
const struct nla_policy cfr_config_policy[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1] = {
[QCA_WLAN_VENDOR_ATTR_CFR_PEER_MAC_ADDR] = {
.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE] = {.type = NLA_FLAG},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_BANDWIDTH] = {.type = NLA_U8},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_PERIODICITY] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_METHOD] = {.type = NLA_U8},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION] = {.type = NLA_U8},
[QCA_WLAN_VENDOR_ATTR_PERIODIC_CFR_CAPTURE_ENABLE] = {
.type = NLA_FLAG},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP] = {
.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK] = {.type = NLA_U64},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT] = {
.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA] = {
.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA] = {
.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK] = {
.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK] = {
.type = NLA_BINARY, .len = QDF_MAC_ADDR_SIZE},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW] = {.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER] = {
.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER] = {
.type = NLA_U32},
[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER] = {
.type = NLA_U32},
};
static QDF_STATUS
wlan_cfg80211_cfr_set_group_config(struct wlan_objmgr_vdev *vdev,
struct nlattr *tb[])
{
struct cfr_wlanconfig_param params = { 0 };
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER]) {
params.grp_id = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NUMBER]);
hdd_debug("group_id %d", params.grp_id);
}
if (params.grp_id >= HDD_INVALID_GROUP_ID) {
hdd_err("invalid group id");
return QDF_STATUS_E_INVAL;
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA]) {
nla_memcpy(&params.ta[0],
tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA],
QDF_MAC_ADDR_SIZE);
hdd_debug("ta " QDF_MAC_ADDR_STR,
QDF_MAC_ADDR_ARRAY(&params.ta[0]));
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK]) {
nla_memcpy(&params.ta_mask[0],
tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TA_MASK],
QDF_MAC_ADDR_SIZE);
hdd_debug("ta_mask " QDF_MAC_ADDR_STR,
QDF_MAC_ADDR_ARRAY(&params.ta_mask[0]));
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA]) {
nla_memcpy(&params.ra[0],
tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA],
QDF_MAC_ADDR_SIZE);
hdd_debug("ra " QDF_MAC_ADDR_STR,
QDF_MAC_ADDR_ARRAY(&params.ra[0]));
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK]) {
nla_memcpy(&params.ra_mask[0],
tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_RA_MASK],
QDF_MAC_ADDR_SIZE);
hdd_debug("ra_mask " QDF_MAC_ADDR_STR,
QDF_MAC_ADDR_ARRAY(&params.ra_mask[0]));
}
if (!qdf_is_macaddr_zero((struct qdf_mac_addr *)&params.ta) ||
!qdf_is_macaddr_zero((struct qdf_mac_addr *)&params.ra) ||
!qdf_is_macaddr_zero((struct qdf_mac_addr *)&params.ta_mask) ||
!qdf_is_macaddr_zero((struct qdf_mac_addr *)&params.ra_mask)) {
hdd_debug("set tara config");
ucfg_cfr_set_tara_config(vdev, &params);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS]) {
params.nss = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_NSS]);
hdd_debug("nss %d", params.nss);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW]) {
params.bw = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_BW]);
hdd_debug("bw %d", params.bw);
}
if (params.nss || params.bw) {
hdd_debug("set bw nss");
ucfg_cfr_set_bw_nss(vdev, &params);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER]) {
params.expected_mgmt_subtype = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_MGMT_FILTER]);
hdd_debug("expected_mgmt_subtype %d(%x)",
params.expected_mgmt_subtype,
params.expected_mgmt_subtype);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER]) {
params.expected_ctrl_subtype = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_CTRL_FILTER]);
hdd_debug("expected_mgmt_subtype %d(%x)",
params.expected_ctrl_subtype,
params.expected_ctrl_subtype);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER]) {
params.expected_data_subtype = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_DATA_FILTER]);
hdd_debug("expected_mgmt_subtype %d(%x)",
params.expected_data_subtype,
params.expected_data_subtype);
}
if (!params.expected_mgmt_subtype ||
!params.expected_ctrl_subtype ||
!params.expected_data_subtype) {
hdd_debug("set frame type");
ucfg_cfr_set_frame_type_subtype(vdev, &params);
}
return QDF_STATUS_SUCCESS;
}
static int
wlan_cfg80211_cfr_set_config(struct wlan_objmgr_vdev *vdev,
struct nlattr *tb[])
{
struct nlattr *group[QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1];
struct nlattr *group_list;
struct cfr_wlanconfig_param params = { 0 };
enum capture_type type;
int rem = 0;
int maxtype;
int attr;
uint64_t ul_mu_user_mask = 0;
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION]) {
params.cap_dur = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_DURATION]);
ucfg_cfr_set_capture_duration(vdev, &params);
hdd_debug("params.cap_dur %d", params.cap_dur);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL]) {
params.cap_intvl = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_INTERVAL]);
ucfg_cfr_set_capture_interval(vdev, &params);
hdd_debug("params.cap_intvl %d", params.cap_intvl);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE]) {
type = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_CAPTURE_TYPE]);
ucfg_cfr_set_rcc_mode(vdev, type, 1);
hdd_debug("type %d", type);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK]) {
ul_mu_user_mask = nla_get_u64(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_UL_MU_MASK]);
hdd_debug("ul_mu_user_mask_lower %d",
params.ul_mu_user_mask_lower);
}
if (ul_mu_user_mask) {
params.ul_mu_user_mask_lower =
(uint32_t)(ul_mu_user_mask & 0xffffffff);
params.ul_mu_user_mask_lower =
(uint32_t)(ul_mu_user_mask >> 32);
hdd_debug("set ul mu user maks");
ucfg_cfr_set_ul_mu_user_mask(vdev, &params);
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT]) {
params.freeze_tlv_delay_cnt_thr = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_FREEZE_TLV_DELAY_COUNT]);
if (params.freeze_tlv_delay_cnt_thr) {
params.freeze_tlv_delay_cnt_en = 1;
ucfg_cfr_set_freeze_tlv_delay_cnt(vdev, &params);
hdd_debug("freeze_tlv_delay_cnt_thr %d",
params.freeze_tlv_delay_cnt_thr);
}
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE]) {
maxtype = QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX;
attr = QCA_WLAN_VENDOR_ATTR_PEER_CFR_GROUP_TABLE;
nla_for_each_nested(group_list, tb[attr], rem) {
if (wlan_cfg80211_nla_parse(group, maxtype,
nla_data(group_list),
nla_len(group_list),
cfr_config_policy)) {
hdd_err("nla_parse failed for cfr config group");
return -EINVAL;
}
wlan_cfg80211_cfr_set_group_config(vdev, group);
}
}
return 0;
}
static int
wlan_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy,
struct hdd_adapter *adapter,
const void *data,
int data_len)
{
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX + 1];
struct cfr_wlanconfig_param params = { 0 };
struct wlan_objmgr_vdev *vdev;
uint8_t version = 0;
bool is_start_capture = false;
QDF_STATUS status;
int ret;
if (wlan_cfg80211_nla_parse(
tb,
QCA_WLAN_VENDOR_ATTR_PEER_CFR_MAX,
data,
data_len,
cfr_config_policy)) {
hdd_err("Invalid ATTR");
return -EINVAL;
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION]) {
version = nla_get_u8(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_VERSION]);
hdd_debug("version %d", version);
if (version != ENHANCED_CFR_VERSION) {
hdd_err("unsupported version");
return -EFAULT;
}
}
if (tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]) {
is_start_capture = nla_get_flag(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE]);
}
if (is_start_capture &&
!tb[QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP]) {
hdd_err("Invalid group bitmap");
return -EINVAL;
}
vdev = adapter->vdev;
status = wlan_objmgr_vdev_try_get_ref(vdev, WLAN_CFR_ID);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("can't get vdev");
return qdf_status_to_os_return(status);
}
if (is_start_capture) {
ret = wlan_cfg80211_cfr_set_config(vdev, tb);
if (ret) {
hdd_err("set config failed");
wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
return ret;
}
params.en_cfg = nla_get_u32(tb[
QCA_WLAN_VENDOR_ATTR_PEER_CFR_ENABLE_GROUP_BITMAP]);
hdd_debug("params.en_cfg %d", params.en_cfg);
ucfg_cfr_set_en_bitmap(vdev, &params);
} else {
hdd_debug("cleanup rcc mode");
ucfg_cfr_set_rcc_mode(vdev, RCC_DIS_ALL_MODE, 0);
}
ucfg_cfr_subscribe_ppdu_desc(wlan_vdev_get_pdev(vdev),
is_start_capture);
ucfg_cfr_committed_rcc_config(vdev);
wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID);
return 0;
}
static int __wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
int data_len)
{
int ret;
struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
struct net_device *dev = wdev->netdev;
struct hdd_adapter *adapter;
hdd_enter();
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return ret;
if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
hdd_err("Command not allowed in FTM mode");
return -EPERM;
}
adapter = WLAN_HDD_GET_PRIV_PTR(dev);
if (wlan_hdd_validate_vdev_id(adapter->vdev_id))
return -EINVAL;
wlan_cfg80211_peer_cfr_capture_cfg(wiphy, adapter,
data, data_len);
hdd_exit();
return ret;
}
int wlan_hdd_cfg80211_peer_cfr_capture_cfg(struct wiphy *wiphy,
struct wireless_dev *wdev,
const void *data,
int data_len)
{
struct osif_psoc_sync *psoc_sync;
int errno;
errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
if (errno)
return errno;
errno = __wlan_hdd_cfg80211_peer_cfr_capture_cfg(wiphy, wdev,
data, data_len);
osif_psoc_sync_op_stop(psoc_sync);
return errno;
}