qcacld-3.0: Add MPTA helper support

Due to PTA matser limitation, zigbee joining network success rate
is low while wlan is working. Wlan host driver need to configure
some parameters including Zigbee state and specific WLAN periods
to enhance PTA master. This mechanism is called MPTA helper.
Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG
is added to realize this feature. NL attributes
qca_mpta_helper_vendor_attr is used to deliver parameters from
uplayer to host driver.

Change-Id: Ic76130e4b92c88e8034f6a0c6c0447c9c6dee945
CRs-Fixed: 2407801
diff --git a/Kbuild b/Kbuild
index 228ea36..c7b56fa 100644
--- a/Kbuild
+++ b/Kbuild
@@ -229,6 +229,10 @@
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_fw_state.o
 endif
 
+ifeq ($(CONFIG_QCACLD_FEATURE_MPTA_HELPER), y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_mpta_helper.o
+endif
+
 ###### OSIF_SYNC ########
 SYNC_DIR := os_if/sync
 SYNC_INC_DIR := $(SYNC_DIR)/inc
@@ -2507,6 +2511,9 @@
 #Flag to enable get firmware state feature
 cppflags-$(CONFIG_QCACLD_FEATURE_FW_STATE) += -DFEATURE_FW_STATE
 
+#Flag to enable MPTA helper feature
+cppflags-$(CONFIG_QCACLD_FEATURE_MPTA_HELPER) += -DFEATURE_MPTA_HELPER
+
 ifdef CONFIG_MAX_LOGS_PER_SEC
 ccflags-y += -DWLAN_MAX_LOGS_PER_SEC=$(CONFIG_MAX_LOGS_PER_SEC)
 endif
diff --git a/configs/default_defconfig b/configs/default_defconfig
index 79a3352..7d4dc67 100644
--- a/configs/default_defconfig
+++ b/configs/default_defconfig
@@ -659,6 +659,7 @@
 CONFIG_FEATURE_CONCURRENCY_MATRIX := y
 CONFIG_FEATURE_SAP_COND_CHAN_SWITCH := y
 CONFIG_FEATURE_P2P_LISTEN_OFFLOAD := y
+CONFIG_QCACLD_FEATURE_MPTA_HELPER := n
 
 #Flags to enable/disable WMI APIs
 CONFIG_WMI_ROAM_SUPPORT := y
diff --git a/core/hdd/inc/wlan_hdd_mpta_helper.h b/core/hdd/inc/wlan_hdd_mpta_helper.h
new file mode 100644
index 0000000..4839558
--- /dev/null
+++ b/core/hdd/inc/wlan_hdd_mpta_helper.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 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_mpta_helper.h
+ *
+ * Add Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG
+ */
+
+#ifndef __WLAN_HDD_MPTA_HELPER_H
+#define __WLAN_HDD_MPTA_HELPER_H
+
+#include "wlan_fw_offload_main.h"
+
+#ifdef FEATURE_MPTA_HELPER
+#include <net/cfg80211.h>
+
+/**
+ * wlan_hdd_mpta_helper_enable() - enable/disable mpta helper
+ * according to cfg from INI
+ * @coex_cfg_params: pointer of coex config command params
+ * @config: pointer of BTC config items
+ *
+ * Return: 0 on success; error number otherwise.
+ *
+ */
+int
+wlan_hdd_mpta_helper_enable(struct coex_config_params *coex_cfg_params,
+			    struct wlan_fwol_coex_config *config);
+
+/**
+ * wlan_hdd_cfg80211_mpta_helper_config() - update
+ * tri-radio coex status by mpta helper
+ * @wiphy: wiphy device pointer
+ * @wdev: wireless device pointer
+ * @data: Vendor command data buffer
+ * @data_len: Buffer length
+ *
+ * Return: 0 on success; error number otherwise.
+ *
+ */
+int wlan_hdd_cfg80211_mpta_helper_config(struct wiphy *wiphy,
+					 struct wireless_dev *wdev,
+					 const void *data,
+					 int data_len);
+
+#define FEATURE_MPTA_HELPER_COMMANDS				\
+{								\
+	.info.vendor_id = QCA_NL80211_VENDOR_ID,		\
+	.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_MPTA_HELPER_CONFIG,\
+	.flags = WIPHY_VENDOR_CMD_NEED_WDEV |			\
+		WIPHY_VENDOR_CMD_NEED_NETDEV |			\
+		WIPHY_VENDOR_CMD_NEED_RUNNING,			\
+	.doit = wlan_hdd_cfg80211_mpta_helper_config	\
+},
+
+#else /* FEATURE_MPTA_HELPER */
+#define FEATURE_MPTA_HELPER_COMMANDS
+
+static inline int
+wlan_hdd_mpta_helper_enable(struct coex_config_params *coex_cfg_params,
+			    struct wlan_fwol_coex_config *config)
+{
+	return 0;
+}
+
+#endif /* FEATURE_MPTA_HELPER */
+
+#endif /* __WLAN_HDD_MPTA_HELPER_H */
+
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index da29b92..7b757fc 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -95,6 +95,7 @@
 #include "wlan_hdd_apf.h"
 #endif
 #include "wlan_hdd_fw_state.h"
+#include "wlan_hdd_mpta_helper.h"
 
 #include <cdp_txrx_cmn.h>
 #include <cdp_txrx_misc.h>
@@ -12708,6 +12709,7 @@
 	FEATURE_ACTIVE_TOS_VENDOR_COMMANDS
 	FEATURE_NAN_VENDOR_COMMANDS
 	FEATURE_FW_STATE_COMMANDS
+	FEATURE_MPTA_HELPER_COMMANDS
 };
 
 struct hdd_context *hdd_cfg80211_wiphy_alloc(void)
diff --git a/core/hdd/src/wlan_hdd_mpta_helper.c b/core/hdd/src/wlan_hdd_mpta_helper.c
new file mode 100644
index 0000000..fe4502f
--- /dev/null
+++ b/core/hdd/src/wlan_hdd_mpta_helper.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2019 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_mpta_helper.c
+ *
+ * The implementation of mpta helper configuration
+ */
+
+#include "wlan_hdd_main.h"
+#include "wmi_unified_param.h"
+#include "wlan_hdd_mpta_helper.h"
+#include "qca_vendor.h"
+#include "wlan_osif_request_manager.h"
+#include "osif_sync.h"
+
+static const struct nla_policy
+qca_wlan_vendor_mpta_helper_attr[QCA_MPTA_HELPER_VENDOR_ATTR_MAX + 1] = {
+	[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE] = {.type = NLA_U32 },
+	[QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION] = {.type = NLA_U32 },
+	[QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION] = {
+							.type = NLA_U32 },
+	[QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION] = {.type = NLA_U32 },
+	[QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION] = {
+							.type = NLA_U32 },
+	[QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION] = {.type = NLA_U32 },
+	[QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION] = {.type = NLA_U32 },
+	[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN] = {.type = NLA_U32 },
+	[QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION] = {.type = NLA_U32 },
+};
+
+/**
+ * __wlan_hdd_cfg80211_mpta_helper_config() - update
+ * tri-radio coex status by mpta helper
+ * @wiphy: wiphy device pointer
+ * @wdev: wireless device pointer
+ * @data: Vendor command data buffer
+ * @data_len: Buffer length
+ *
+ * Return: 0 on success; error number otherwise.
+ *
+ */
+static int
+__wlan_hdd_cfg80211_mpta_helper_config(struct wiphy *wiphy,
+				       struct wireless_dev *wdev,
+				       const void *data,
+				       int data_len)
+{
+	struct net_device *netdev = wdev->netdev;
+	struct hdd_context *hdd_ctx  = wiphy_priv(wiphy);
+	struct nlattr *tb[QCA_MPTA_HELPER_VENDOR_ATTR_MAX + 1];
+	struct coex_config_params coex_cfg_params = {0};
+	int errno;
+	QDF_STATUS status;
+
+	hdd_enter_dev(netdev);
+
+	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
+		hdd_err("Command not allowed in FTM mode");
+		return -EPERM;
+	}
+
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno)
+		return errno;
+
+	if (wlan_cfg80211_nla_parse(tb, QCA_MPTA_HELPER_VENDOR_ATTR_MAX, data,
+				    data_len,
+				    qca_wlan_vendor_mpta_helper_attr)) {
+		hdd_err("invalid attr");
+		return -EINVAL;
+	}
+
+	/* if no attributes specified, return -EINVAL */
+	errno = -EINVAL;
+
+	if (tb[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE]) {
+		coex_cfg_params.config_type =
+			WMI_COEX_CONFIG_MPTA_HELPER_ZIGBEE_STATE;
+		coex_cfg_params.config_arg1 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_STATE]);
+
+		status = sme_send_coex_config_cmd(&coex_cfg_params);
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("Failed to set zigbee STATE");
+			return -EINVAL;
+		}
+
+		errno = 0;
+	}
+
+	if ((tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION]) &&
+	    (tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION])) {
+		coex_cfg_params.config_type =
+			WMI_COEX_CONFIG_MPTA_HELPER_INT_OCS_PARAMS;
+		coex_cfg_params.config_arg1 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_WLAN_DURATION]);
+		coex_cfg_params.config_arg2 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_NON_WLAN_DURATION]);
+
+		status = sme_send_coex_config_cmd(&coex_cfg_params);
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("Failed to set int OCS duration");
+			return -EINVAL;
+		}
+
+		errno = 0;
+	}
+
+	if ((tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION]) &&
+	    (tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION])) {
+		coex_cfg_params.config_type =
+			WMI_COEX_CONFIG_MPTA_HELPER_MON_OCS_PARAMS;
+		coex_cfg_params.config_arg1 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_WLAN_DURATION]);
+		coex_cfg_params.config_arg2 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_NON_WLAN_DURATION]);
+
+		status = sme_send_coex_config_cmd(&coex_cfg_params);
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("Failed to set mon OCS duration");
+			return -EINVAL;
+		}
+
+		errno = 0;
+	}
+
+	if ((tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION]) &&
+	    (tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION])) {
+		coex_cfg_params.config_type =
+			WMI_COEX_CONFIG_MPTA_HELPER_INT_MON_DURATION;
+		coex_cfg_params.config_arg1 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_INT_OCS_DURATION]);
+		coex_cfg_params.config_arg2 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_MON_OCS_DURATION]);
+
+		status = sme_send_coex_config_cmd(&coex_cfg_params);
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("Failed to set int mon duration");
+			return -EINVAL;
+		}
+
+		errno = 0;
+	}
+
+	if (tb[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN]) {
+		coex_cfg_params.config_type =
+			WMI_COEX_CONFIG_MPTA_HELPER_ZIGBEE_CHANNEL;
+		coex_cfg_params.config_arg1 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_ZIGBEE_CHAN]);
+
+		status = sme_send_coex_config_cmd(&coex_cfg_params);
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("Failed to set zigbee chan");
+			return -EINVAL;
+		}
+
+		errno = 0;
+	}
+
+	if (tb[QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION]) {
+		coex_cfg_params.config_type =
+			WMI_COEX_CONFIG_MPTA_HELPER_WLAN_MUTE_DURATION;
+		coex_cfg_params.config_arg1 = nla_get_u32
+			(tb[QCA_MPTA_HELPER_VENDOR_ATTR_WLAN_MUTE_DURATION]);
+
+		status = sme_send_coex_config_cmd(&coex_cfg_params);
+
+		if (QDF_IS_STATUS_ERROR(status)) {
+			hdd_err("Failed to set wlan mute duration");
+			return -EINVAL;
+		}
+
+		errno = 0;
+	}
+
+	return errno;
+}
+
+/**
+ * wlan_hdd_cfg80211_mpta_helper_config() - update
+ * tri-radio coex status by mpta helper
+ * @wiphy: wiphy device pointer
+ * @wdev: wireless device pointer
+ * @data: Vendor command data buffer
+ * @data_len: Buffer length
+ *
+ * Return: 0 on success; error number otherwise.
+ *
+ */
+int
+wlan_hdd_cfg80211_mpta_helper_config(struct wiphy *wiphy,
+				     struct wireless_dev *wdev,
+				     const void *data,
+				     int data_len)
+{
+	int errno;
+	struct osif_vdev_sync *vdev_sync;
+
+	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
+	if (errno)
+		return errno;
+
+	errno = __wlan_hdd_cfg80211_mpta_helper_config(
+					wiphy, wdev, data, data_len);
+
+	osif_vdev_sync_op_stop(vdev_sync);
+
+	return errno;
+}
+
+/**
+ * wlan_hdd_mpta_helper_enable() - enable/disable mpta helper
+ * according to cfg from INI
+ * @coex_cfg_params: pointer of coex config command params
+ * @config: pointer of BTC config items
+ *
+ * Return: 0 on success; error number otherwise.
+ *
+ */
+int
+wlan_hdd_mpta_helper_enable(struct coex_config_params *coex_cfg_params,
+			    struct wlan_fwol_coex_config *config)
+{
+	QDF_STATUS status;
+
+	coex_cfg_params->config_type = WMI_COEX_CONFIG_MPTA_HELPER_ENABLE;
+	coex_cfg_params->config_arg1 = config->btc_mpta_helper_enable;
+
+	status = sme_send_coex_config_cmd(coex_cfg_params);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to send coex MPTA Helper Enable");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+