/* * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. 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" #include "wlan_fwol_ucfg_api.h" 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}; struct wlan_fwol_coex_config config = {0}; int errno; QDF_STATUS status; hdd_enter(); 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 != 0) return errno; status = ucfg_fwol_get_coex_config_params(hdd_ctx->psoc, &config); if (QDF_IS_STATUS_ERROR(status)) { hdd_err("Unable to get coex config params"); return -EINVAL; } if (!config.btc_three_way_coex_config_legacy_enable) { hdd_err("Coex legacy feature should be enable first"); return -EINVAL; } 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->deflink->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; }