qcacld-3.0: Set Coex priorities among WLAN/BT/ZB

Coex priority on some scenarios need to be updated.
Host will transfer the chosen coex config attributes
by WMI command.

Change-Id: Ic28ad6af462b305ec9aaf3027d76bce9ae6320b1
CRs-Fixed: 2410493
diff --git a/Kbuild b/Kbuild
index c7b56fa..e854d52 100644
--- a/Kbuild
+++ b/Kbuild
@@ -229,6 +229,10 @@
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_fw_state.o
 endif
 
+ifeq ($(CONFIG_QCACLD_FEATURE_COEX_CONFIG), y)
+HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_coex_config.o
+endif
+
 ifeq ($(CONFIG_QCACLD_FEATURE_MPTA_HELPER), y)
 HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_mpta_helper.o
 endif
@@ -2511,6 +2515,9 @@
 #Flag to enable get firmware state feature
 cppflags-$(CONFIG_QCACLD_FEATURE_FW_STATE) += -DFEATURE_FW_STATE
 
+#Flag to enable set coex configuration feature
+cppflags-$(CONFIG_QCACLD_FEATURE_COEX_CONFIG) += -DFEATURE_COEX_CONFIG
+
 #Flag to enable MPTA helper feature
 cppflags-$(CONFIG_QCACLD_FEATURE_MPTA_HELPER) += -DFEATURE_MPTA_HELPER
 
diff --git a/configs/default_defconfig b/configs/default_defconfig
index 7d4dc67..be3bf4f 100644
--- a/configs/default_defconfig
+++ b/configs/default_defconfig
@@ -121,6 +121,9 @@
 #Flag to enable get firmware state
 CONFIG_QCACLD_FEATURE_FW_STATE := y
 
+#Flag to enable set coex configuration
+CONFIG_QCACLD_FEATURE_COEX_CONFIG := y
+
 ifeq ($(CONFIG_ARCH_MSM8998), y)
 CONFIG_QCACLD_FEATURE_METERING := y
 endif
diff --git a/core/hdd/src/wlan_hdd_cfg80211.c b/core/hdd/src/wlan_hdd_cfg80211.c
index 7b757fc..fc4c4b3 100644
--- a/core/hdd/src/wlan_hdd_cfg80211.c
+++ b/core/hdd/src/wlan_hdd_cfg80211.c
@@ -137,6 +137,7 @@
 #include "wlan_fwol_ucfg_api.h"
 #include "wlan_cfg80211_crypto.h"
 #include "wlan_scan_ucfg_api.h"
+#include "wlan_hdd_coex_config.h"
 
 #define g_mode_rates_size (12)
 #define a_mode_rates_size (8)
@@ -12709,6 +12710,7 @@
 	FEATURE_ACTIVE_TOS_VENDOR_COMMANDS
 	FEATURE_NAN_VENDOR_COMMANDS
 	FEATURE_FW_STATE_COMMANDS
+	FEATURE_COEX_CONFIG_COMMANDS
 	FEATURE_MPTA_HELPER_COMMANDS
 };
 
diff --git a/core/hdd/src/wlan_hdd_coex_config.c b/core/hdd/src/wlan_hdd_coex_config.c
new file mode 100644
index 0000000..fe2755f
--- /dev/null
+++ b/core/hdd/src/wlan_hdd_coex_config.c
@@ -0,0 +1,186 @@
+/*
+ * 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_coex_config.c
+ *
+ * The implementation of coex configuration
+ *
+ */
+
+#include "wlan_hdd_main.h"
+#include "wmi_unified_param.h"
+#include "wlan_hdd_coex_config.h"
+#include "qca_vendor.h"
+#include "wlan_osif_request_manager.h"
+#include "osif_sync.h"
+
+static const struct nla_policy
+coex_config_three_way_policy[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX + 1] = {
+	[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE] = {
+							      .type = NLA_U32},
+	[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1] = {.type = NLA_U32},
+	[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2] = {.type = NLA_U32},
+	[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3] = {.type = NLA_U32},
+	[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4] = {.type = NLA_U32},
+};
+
+static const uint32_t
+config_type_to_wmi_tbl[QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX] = {
+	[QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET] =
+		WMI_COEX_CONFIG_THREE_WAY_COEX_RESET,
+	[QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START] =
+		WMI_COEX_CONFIG_THREE_WAY_COEX_START,
+};
+
+/**
+ * __wlan_hdd_cfg80211_set_coex_config() - set coex configuration
+ * parameters
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to limit off-channel command parameters.
+ * @data_len: the length in byte of  limit off-channel command parameters.
+ *
+ * Return: An error code or 0 on success.
+ */
+static int __wlan_hdd_cfg80211_set_coex_config(struct wiphy *wiphy,
+					       struct wireless_dev *wdev,
+					       const void *data, int data_len)
+{
+	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev);
+	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
+	struct nlattr *tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX + 1];
+	uint32_t config_type;
+	struct coex_config_params coex_cfg_params = {0};
+	int errno;
+	QDF_STATUS status;
+
+	hdd_enter();
+
+	errno = wlan_hdd_validate_context(hdd_ctx);
+	if (errno != 0)
+		return errno;
+
+	if (wlan_cfg80211_nla_parse(tb,
+				    QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX,
+				    data, data_len,
+				    coex_config_three_way_policy)) {
+		hdd_err("Invalid coex config ATTR");
+		return -EINVAL;
+	}
+
+	if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE]) {
+		hdd_err("coex config - attr config_type failed");
+		return -EINVAL;
+	}
+
+	config_type = nla_get_u32(
+		tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE]);
+	if (config_type >= QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX) {
+		hdd_err("config_type value %d exceeded Max value %d",
+			config_type,
+			QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX);
+		return -EINVAL;
+	}
+	coex_cfg_params.config_type = config_type_to_wmi_tbl[config_type];
+	if (coex_cfg_params.config_type <
+	    WMI_COEX_CONFIG_THREE_WAY_DELAY_PARA ||
+	    coex_cfg_params.config_type >
+	    WMI_COEX_CONFIG_THREE_WAY_COEX_START) {
+		hdd_err("config_type_wmi val error %d",
+			coex_cfg_params.config_type);
+		return -EINVAL;
+	}
+
+	hdd_debug("config_type %d, config_type_wmi %d",
+		  config_type, coex_cfg_params.config_type);
+
+	if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1]) {
+		hdd_err("coex config - attr priority1 failed");
+		return -EINVAL;
+	}
+	coex_cfg_params.config_arg1 = nla_get_u32(
+		tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1]);
+
+	hdd_debug("priority1 0x%x", coex_cfg_params.config_arg1);
+
+	if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2]) {
+		hdd_err("coex config - attr priority2 failed");
+		return -EINVAL;
+	}
+	coex_cfg_params.config_arg2 = nla_get_u32(
+		tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2]);
+
+	hdd_debug("priority2 0x%x", coex_cfg_params.config_arg2);
+
+	if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3]) {
+		hdd_err("coex config - attr priority3 failed");
+		return -EINVAL;
+	}
+	coex_cfg_params.config_arg3 = nla_get_u32(
+		tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3]);
+
+	hdd_debug("priority3 0x%x", coex_cfg_params.config_arg3);
+
+	if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4]) {
+		hdd_err("coex config - attr priority4 failed");
+		return -EINVAL;
+	}
+	coex_cfg_params.config_arg4 = nla_get_u32(
+		tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4]);
+
+	hdd_debug("priority4 0x%x", coex_cfg_params.config_arg4);
+
+	coex_cfg_params.vdev_id = adapter->vdev_id;
+	status = sme_send_coex_config_cmd(&coex_cfg_params);
+	if (QDF_IS_STATUS_ERROR(status)) {
+		hdd_err("Failed to send coex config params");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * wlan_hdd_cfg80211_set_coex_config() - set coex configuration
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to limit off-channel command parameters.
+ * @data_len: the length in byte of  limit off-channel command parameters.
+ *
+ *
+ * Return: An error code or 0 on success.
+ */
+int wlan_hdd_cfg80211_set_coex_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_set_coex_config(wiphy, wdev,
+						    data, data_len);
+
+	osif_vdev_sync_op_stop(vdev_sync);
+
+	return errno;
+}
diff --git a/core/hdd/src/wlan_hdd_coex_config.h b/core/hdd/src/wlan_hdd_coex_config.h
new file mode 100644
index 0000000..fbba0d0
--- /dev/null
+++ b/core/hdd/src/wlan_hdd_coex_config.h
@@ -0,0 +1,57 @@
+/*
+ * 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_coex_config.h
+ *
+ * Add Vendor subcommand QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG
+ */
+
+#ifndef __WLAN_HDD_COEX_CONFIG_H
+#define __WLAN_HDD_COEX_CONFIG_H
+
+#ifdef FEATURE_COEX_CONFIG
+#include <net/cfg80211.h>
+
+/**
+ * wlan_hdd_cfg80211_set_coex_config() - set coex configuration
+ * @wiphy: pointer to wireless wiphy structure.
+ * @wdev: pointer to wireless_dev structure.
+ * @data: pointer to limit off-channel command parameters.
+ * @data_len: the length in byte of  limit off-channel command parameters.
+ *
+ * Return: An error code or 0 on success.
+ */
+int wlan_hdd_cfg80211_set_coex_config(struct wiphy *wiphy,
+				      struct wireless_dev *wdev,
+				      const void *data, int data_len);
+
+#define FEATURE_COEX_CONFIG_COMMANDS				\
+{								\
+	.info.vendor_id = QCA_NL80211_VENDOR_ID,		\
+	.info.subcmd = QCA_NL80211_VENDOR_SUBCMD_COEX_CONFIG,\
+	.flags = WIPHY_VENDOR_CMD_NEED_WDEV |			\
+		WIPHY_VENDOR_CMD_NEED_NETDEV |			\
+		WIPHY_VENDOR_CMD_NEED_RUNNING,			\
+	.doit = wlan_hdd_cfg80211_set_coex_config			\
+},
+#else /* FEATURE_COEX_CONFIG */
+#define FEATURE_COEX_CONFIG_COMMANDS
+#endif /* FEATURE_COEX_CONFIG */
+
+#endif /* __WLAN_HDD_COEX_CONFIG_H */