| /* |
| * 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; |
| } |