|
@@ -0,0 +1,135 @@
|
|
|
+/*
|
|
|
+ * 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: defines driver functions interfacing with linux kernel
|
|
|
+ */
|
|
|
+#include <wmi_unified_param.h>
|
|
|
+#include <wlan_osif_request_manager.h>
|
|
|
+#include <osif_sync.h>
|
|
|
+#include <wlan_objmgr_psoc_obj_i.h>
|
|
|
+#include <wlan_coex_main.h>
|
|
|
+#include <wlan_coex_ucfg_api.h>
|
|
|
+#include <wlan_cfg80211_coex.h>
|
|
|
+
|
|
|
+static const struct nla_policy
|
|
|
+btc_chain_mode_policy[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1] = {
|
|
|
+ [QCA_VENDOR_ATTR_BTC_CHAIN_MODE] = {.type = NLA_U32},
|
|
|
+ [QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART] = {.type = NLA_FLAG},
|
|
|
+};
|
|
|
+
|
|
|
+static int
|
|
|
+__wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
|
|
|
+ uint8_t mode, bool do_restart)
|
|
|
+{
|
|
|
+ QDF_STATUS status;
|
|
|
+ uint8_t cur_mode;
|
|
|
+ int err;
|
|
|
+ struct wlan_objmgr_psoc *psoc;
|
|
|
+ struct wlan_objmgr_vdev *vdev_tmp;
|
|
|
+ int vdev_id;
|
|
|
+ struct coex_psoc_obj *coex_obj;
|
|
|
+
|
|
|
+ if (!vdev) {
|
|
|
+ coex_err("Null vdev");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ psoc = wlan_vdev_get_psoc(vdev);
|
|
|
+ if (!psoc) {
|
|
|
+ coex_err("NULL psoc");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ coex_obj = wlan_psoc_get_coex_obj(psoc);
|
|
|
+ if (!coex_obj)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ status = ucfg_coex_psoc_get_btc_chain_mode(psoc, &cur_mode);
|
|
|
+ if (QDF_IS_STATUS_ERROR(status)) {
|
|
|
+ coex_err("failed to get cur BTC chain mode, status %d", status);
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cur_mode == mode)
|
|
|
+ return -EALREADY;
|
|
|
+
|
|
|
+ status = ucfg_coex_psoc_set_btc_chain_mode(psoc, mode);
|
|
|
+ if (!QDF_IS_STATUS_SUCCESS(status)) {
|
|
|
+ coex_err("unable to set BTC chain mode to %d", mode);
|
|
|
+ return -EFAULT;
|
|
|
+ }
|
|
|
+
|
|
|
+ wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev_tmp) {
|
|
|
+ status = ucfg_coex_send_btc_chain_mode(vdev, mode);
|
|
|
+ err = qdf_status_to_os_return(status);
|
|
|
+ if (err) {
|
|
|
+ coex_err("Failed to set btc chain mode to %d for vdev %d",
|
|
|
+ mode, vdev_id);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ coex_debug("Set btc chain mode to %d for vdev %d",
|
|
|
+ mode, vdev_id);
|
|
|
+
|
|
|
+ if (!do_restart)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ wlan_coex_config_updated(vdev, COEX_CONFIG_BTC_CHAIN_MODE);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * wlan_hdd_cfg80211_set_btc_chain_mode() - set btc chain mode
|
|
|
+ * @wiphy: pointer to wireless wiphy structure.
|
|
|
+ * @wdev: pointer to wireless_dev structure.
|
|
|
+ * @data: pointer to btc chain mode command parameters.
|
|
|
+ * @data_len: the length in byte of btc chain mode command parameters.
|
|
|
+ *
|
|
|
+ * Return: An error code or 0 on success.
|
|
|
+ */
|
|
|
+int wlan_cfg80211_coex_set_btc_chain_mode(struct wlan_objmgr_vdev *vdev,
|
|
|
+ const void *data, int data_len)
|
|
|
+{
|
|
|
+ struct nlattr *tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX + 1];
|
|
|
+ uint32_t mode;
|
|
|
+ bool restart;
|
|
|
+
|
|
|
+ if (wlan_cfg80211_nla_parse(tb, QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX,
|
|
|
+ data, data_len, btc_chain_mode_policy)) {
|
|
|
+ coex_err("Invalid btc chain mode ATTR");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE]) {
|
|
|
+ coex_err("btc chain mode - no attr mode");
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ mode = nla_get_u32(tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE]);
|
|
|
+ if (mode < QCA_BTC_CHAIN_SHARED || mode > QCA_BTC_CHAIN_SEPARATED) {
|
|
|
+ coex_err("Invalid btc chain mode %d", mode);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ restart = nla_get_flag(tb[QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART]);
|
|
|
+
|
|
|
+ coex_debug("vdev_id %u mode %u restart %u",
|
|
|
+ wlan_vdev_get_id(vdev), mode, restart);
|
|
|
+
|
|
|
+ return __wlan_cfg80211_coex_set_btc_chain_mode(vdev, mode, restart);
|
|
|
+}
|