1 /* 2 * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: wlan_hdd_coex_config.c 22 * 23 * The implementation of coex configuration 24 * 25 */ 26 27 #include "wlan_hdd_main.h" 28 #include "wmi_unified_param.h" 29 #include "wlan_hdd_coex_config.h" 30 #include "qca_vendor.h" 31 #include "wlan_osif_request_manager.h" 32 #include "osif_sync.h" 33 #include "wlan_fwol_ucfg_api.h" 34 35 const struct nla_policy 36 coex_config_three_way_policy[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX + 1] = { 37 [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE] = { 38 .type = NLA_U32}, 39 [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1] = {.type = NLA_U32}, 40 [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2] = {.type = NLA_U32}, 41 [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3] = {.type = NLA_U32}, 42 [QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4] = {.type = NLA_U32}, 43 }; 44 45 static const uint32_t 46 config_type_to_wmi_tbl[QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX] = { 47 [QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_RESET] = 48 WMI_COEX_CONFIG_THREE_WAY_COEX_RESET, 49 [QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_COEX_START] = 50 WMI_COEX_CONFIG_THREE_WAY_COEX_START, 51 }; 52 53 /** 54 * __wlan_hdd_cfg80211_set_coex_config() - set coex configuration 55 * parameters 56 * @wiphy: pointer to wireless wiphy structure. 57 * @wdev: pointer to wireless_dev structure. 58 * @data: pointer to limit off-channel command parameters. 59 * @data_len: the length in byte of limit off-channel command parameters. 60 * 61 * Return: An error code or 0 on success. 62 */ 63 static int __wlan_hdd_cfg80211_set_coex_config(struct wiphy *wiphy, 64 struct wireless_dev *wdev, 65 const void *data, int data_len) 66 { 67 struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(wdev->netdev); 68 struct hdd_context *hdd_ctx = wiphy_priv(wiphy); 69 struct nlattr *tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX + 1]; 70 uint32_t config_type; 71 struct coex_config_params coex_cfg_params = {0}; 72 struct wlan_fwol_coex_config config = {0}; 73 int errno; 74 QDF_STATUS status; 75 76 hdd_enter(); 77 78 if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) { 79 hdd_err("Command not allowed in FTM mode"); 80 return -EPERM; 81 } 82 83 errno = wlan_hdd_validate_context(hdd_ctx); 84 if (errno != 0) 85 return errno; 86 87 status = ucfg_fwol_get_coex_config_params(hdd_ctx->psoc, &config); 88 if (QDF_IS_STATUS_ERROR(status)) { 89 hdd_err("Unable to get coex config params"); 90 return -EINVAL; 91 } 92 if (!config.btc_three_way_coex_config_legacy_enable) { 93 hdd_err("Coex legacy feature should be enable first"); 94 return -EINVAL; 95 } 96 97 if (wlan_cfg80211_nla_parse(tb, 98 QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_MAX, 99 data, data_len, 100 coex_config_three_way_policy)) { 101 hdd_err("Invalid coex config ATTR"); 102 return -EINVAL; 103 } 104 105 if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE]) { 106 hdd_err("coex config - attr config_type failed"); 107 return -EINVAL; 108 } 109 110 config_type = nla_get_u32( 111 tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_CONFIG_TYPE]); 112 if (config_type >= QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX) { 113 hdd_err("config_type value %d exceeded Max value %d", 114 config_type, 115 QCA_WLAN_VENDOR_ATTR_COEX_CONFIG_TYPE_MAX); 116 return -EINVAL; 117 } 118 coex_cfg_params.config_type = config_type_to_wmi_tbl[config_type]; 119 if (coex_cfg_params.config_type < 120 WMI_COEX_CONFIG_THREE_WAY_DELAY_PARA || 121 coex_cfg_params.config_type > 122 WMI_COEX_CONFIG_THREE_WAY_COEX_START) { 123 hdd_err("config_type_wmi val error %d", 124 coex_cfg_params.config_type); 125 return -EINVAL; 126 } 127 128 hdd_debug("config_type %d, config_type_wmi %d", 129 config_type, coex_cfg_params.config_type); 130 131 if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1]) { 132 hdd_err("coex config - attr priority1 failed"); 133 return -EINVAL; 134 } 135 coex_cfg_params.config_arg1 = nla_get_u32( 136 tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_1]); 137 138 hdd_debug("priority1 0x%x", coex_cfg_params.config_arg1); 139 140 if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2]) { 141 hdd_err("coex config - attr priority2 failed"); 142 return -EINVAL; 143 } 144 coex_cfg_params.config_arg2 = nla_get_u32( 145 tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_2]); 146 147 hdd_debug("priority2 0x%x", coex_cfg_params.config_arg2); 148 149 if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3]) { 150 hdd_err("coex config - attr priority3 failed"); 151 return -EINVAL; 152 } 153 coex_cfg_params.config_arg3 = nla_get_u32( 154 tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_3]); 155 156 hdd_debug("priority3 0x%x", coex_cfg_params.config_arg3); 157 158 if (!tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4]) { 159 hdd_err("coex config - attr priority4 failed"); 160 return -EINVAL; 161 } 162 coex_cfg_params.config_arg4 = nla_get_u32( 163 tb[QCA_VENDOR_ATTR_COEX_CONFIG_THREE_WAY_PRIORITY_4]); 164 165 hdd_debug("priority4 0x%x", coex_cfg_params.config_arg4); 166 167 coex_cfg_params.vdev_id = adapter->deflink->vdev_id; 168 status = sme_send_coex_config_cmd(&coex_cfg_params); 169 if (QDF_IS_STATUS_ERROR(status)) { 170 hdd_err("Failed to send coex config params"); 171 return -EINVAL; 172 } 173 174 return 0; 175 } 176 177 /** 178 * wlan_hdd_cfg80211_set_coex_config() - set coex configuration 179 * @wiphy: pointer to wireless wiphy structure. 180 * @wdev: pointer to wireless_dev structure. 181 * @data: pointer to limit off-channel command parameters. 182 * @data_len: the length in byte of limit off-channel command parameters. 183 * 184 * 185 * Return: An error code or 0 on success. 186 */ 187 int wlan_hdd_cfg80211_set_coex_config(struct wiphy *wiphy, 188 struct wireless_dev *wdev, 189 const void *data, int data_len) 190 { 191 int errno; 192 struct osif_vdev_sync *vdev_sync; 193 194 errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync); 195 if (errno) 196 return errno; 197 198 errno = __wlan_hdd_cfg80211_set_coex_config(wiphy, wdev, 199 data, data_len); 200 201 osif_vdev_sync_op_stop(vdev_sync); 202 203 return errno; 204 } 205