Prechádzať zdrojové kódy

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
Wu Gao 5 rokov pred
rodič
commit
4425921c33

+ 66 - 0
core/hdd/inc/wlan_hdd_cfr.h

@@ -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 */
+

+ 2 - 0
core/hdd/src/wlan_hdd_cfg80211.c

@@ -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 - 0
core/hdd/src/wlan_hdd_cfr.c

@@ -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;
+}