470 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc.4 */5 6#include "testmode.h"7 8#include <net/netlink.h>9#include <linux/firmware.h>10 11#include "debug.h"12#include "wmi.h"13#include "hif.h"14#include "hw.h"15#include "core.h"16 17#include "testmode_i.h"18 19static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {20 [ATH10K_TM_ATTR_CMD] = { .type = NLA_U32 },21 [ATH10K_TM_ATTR_DATA] = { .type = NLA_BINARY,22 .len = ATH10K_TM_DATA_MAX_LEN },23 [ATH10K_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 },24 [ATH10K_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 },25 [ATH10K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },26};27 28/* Returns true if callee consumes the skb and the skb should be discarded.29 * Returns false if skb is not used. Does not sleep.30 */31bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)32{33 struct sk_buff *nl_skb;34 bool consumed;35 int ret;36 37 ath10k_dbg(ar, ATH10K_DBG_TESTMODE,38 "testmode event wmi cmd_id %d skb %pK skb->len %d\n",39 cmd_id, skb, skb->len);40 41 ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);42 43 spin_lock_bh(&ar->data_lock);44 45 if (!ar->testmode.utf_monitor) {46 consumed = false;47 goto out;48 }49 50 /* Only testmode.c should be handling events from utf firmware,51 * otherwise all sort of problems will arise as mac80211 operations52 * are not initialised.53 */54 consumed = true;55 56 nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,57 2 * sizeof(u32) + skb->len,58 GFP_ATOMIC);59 if (!nl_skb) {60 ath10k_warn(ar,61 "failed to allocate skb for testmode wmi event\n");62 goto out;63 }64 65 ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);66 if (ret) {67 ath10k_warn(ar,68 "failed to put testmode wmi event cmd attribute: %d\n",69 ret);70 kfree_skb(nl_skb);71 goto out;72 }73 74 ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);75 if (ret) {76 ath10k_warn(ar,77 "failed to put testmode wmi event cmd_id: %d\n",78 ret);79 kfree_skb(nl_skb);80 goto out;81 }82 83 ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);84 if (ret) {85 ath10k_warn(ar,86 "failed to copy skb to testmode wmi event: %d\n",87 ret);88 kfree_skb(nl_skb);89 goto out;90 }91 92 cfg80211_testmode_event(nl_skb, GFP_ATOMIC);93 94out:95 spin_unlock_bh(&ar->data_lock);96 97 return consumed;98}99 100static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])101{102 struct sk_buff *skb;103 int ret;104 105 ath10k_dbg(ar, ATH10K_DBG_TESTMODE,106 "testmode cmd get version_major %d version_minor %d\n",107 ATH10K_TESTMODE_VERSION_MAJOR,108 ATH10K_TESTMODE_VERSION_MINOR);109 110 skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,111 nla_total_size(sizeof(u32)));112 if (!skb)113 return -ENOMEM;114 115 ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,116 ATH10K_TESTMODE_VERSION_MAJOR);117 if (ret) {118 kfree_skb(skb);119 return ret;120 }121 122 ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,123 ATH10K_TESTMODE_VERSION_MINOR);124 if (ret) {125 kfree_skb(skb);126 return ret;127 }128 129 ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION,130 ar->normal_mode_fw.fw_file.wmi_op_version);131 if (ret) {132 kfree_skb(skb);133 return ret;134 }135 136 return cfg80211_testmode_reply(skb);137}138 139static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar,140 struct ath10k_fw_file *fw_file)141{142 char filename[100];143 int ret;144 145 snprintf(filename, sizeof(filename), "%s/%s",146 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);147 148 /* load utf firmware image */149 ret = firmware_request_nowarn(&fw_file->firmware, filename, ar->dev);150 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode fw request '%s': %d\n",151 filename, ret);152 153 if (ret) {154 ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",155 filename, ret);156 return ret;157 }158 159 /* We didn't find FW UTF API 1 ("utf.bin") does not advertise160 * firmware features. Do an ugly hack where we force the firmware161 * features to match with 10.1 branch so that wmi.c will use the162 * correct WMI interface.163 */164 165 fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;166 fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;167 fw_file->firmware_data = fw_file->firmware->data;168 fw_file->firmware_len = fw_file->firmware->size;169 170 return 0;171}172 173static int ath10k_tm_fetch_firmware(struct ath10k *ar)174{175 struct ath10k_fw_components *utf_mode_fw;176 int ret;177 char fw_name[100];178 int fw_api2 = 2;179 180 switch (ar->hif.bus) {181 case ATH10K_BUS_SDIO:182 case ATH10K_BUS_USB:183 scnprintf(fw_name, sizeof(fw_name), "%s-%s-%d.bin",184 ATH10K_FW_UTF_FILE_BASE, ath10k_bus_str(ar->hif.bus),185 fw_api2);186 break;187 default:188 scnprintf(fw_name, sizeof(fw_name), "%s-%d.bin",189 ATH10K_FW_UTF_FILE_BASE, fw_api2);190 break;191 }192 193 ret = ath10k_core_fetch_firmware_api_n(ar, fw_name,194 &ar->testmode.utf_mode_fw.fw_file);195 if (ret == 0) {196 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");197 goto out;198 }199 200 ret = ath10k_tm_fetch_utf_firmware_api_1(ar, &ar->testmode.utf_mode_fw.fw_file);201 if (ret) {202 ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);203 return ret;204 }205 206 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");207 208out:209 utf_mode_fw = &ar->testmode.utf_mode_fw;210 211 /* Use the same board data file as the normal firmware uses (but212 * it's still "owned" by normal_mode_fw so we shouldn't free it.213 */214 utf_mode_fw->board_data = ar->normal_mode_fw.board_data;215 utf_mode_fw->board_len = ar->normal_mode_fw.board_len;216 217 if (!utf_mode_fw->fw_file.otp_data) {218 ath10k_info(ar, "utf.bin didn't contain otp binary, taking it from the normal mode firmware");219 utf_mode_fw->fw_file.otp_data = ar->normal_mode_fw.fw_file.otp_data;220 utf_mode_fw->fw_file.otp_len = ar->normal_mode_fw.fw_file.otp_len;221 }222 223 return 0;224}225 226static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])227{228 const char *ver;229 int ret;230 231 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");232 233 mutex_lock(&ar->conf_mutex);234 235 if (ar->state == ATH10K_STATE_UTF) {236 ret = -EALREADY;237 goto err;238 }239 240 /* start utf only when the driver is not in use */241 if (ar->state != ATH10K_STATE_OFF) {242 ret = -EBUSY;243 goto err;244 }245 246 if (WARN_ON(ar->testmode.utf_mode_fw.fw_file.firmware != NULL)) {247 /* utf image is already downloaded, it shouldn't be */248 ret = -EEXIST;249 goto err;250 }251 252 ret = ath10k_tm_fetch_firmware(ar);253 if (ret) {254 ath10k_err(ar, "failed to fetch UTF firmware: %d", ret);255 goto err;256 }257 258 if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&259 ar->testmode.utf_mode_fw.fw_file.codeswap_len) {260 ret = ath10k_swap_code_seg_init(ar,261 &ar->testmode.utf_mode_fw.fw_file);262 if (ret) {263 ath10k_warn(ar,264 "failed to init utf code swap segment: %d\n",265 ret);266 goto err_release_utf_mode_fw;267 }268 }269 270 spin_lock_bh(&ar->data_lock);271 ar->testmode.utf_monitor = true;272 spin_unlock_bh(&ar->data_lock);273 274 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",275 ar->testmode.utf_mode_fw.fw_file.wmi_op_version);276 277 ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_UTF);278 if (ret) {279 ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);280 ar->state = ATH10K_STATE_OFF;281 goto err_release_utf_mode_fw;282 }283 284 ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF,285 &ar->testmode.utf_mode_fw);286 if (ret) {287 ath10k_err(ar, "failed to start core (testmode): %d\n", ret);288 ar->state = ATH10K_STATE_OFF;289 goto err_power_down;290 }291 292 ar->state = ATH10K_STATE_UTF;293 294 if (strlen(ar->testmode.utf_mode_fw.fw_file.fw_version) > 0)295 ver = ar->testmode.utf_mode_fw.fw_file.fw_version;296 else297 ver = "API 1";298 299 ath10k_info(ar, "UTF firmware %s started\n", ver);300 301 mutex_unlock(&ar->conf_mutex);302 303 return 0;304 305err_power_down:306 ath10k_hif_power_down(ar);307 308err_release_utf_mode_fw:309 if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&310 ar->testmode.utf_mode_fw.fw_file.codeswap_len)311 ath10k_swap_code_seg_release(ar,312 &ar->testmode.utf_mode_fw.fw_file);313 314 release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);315 ar->testmode.utf_mode_fw.fw_file.firmware = NULL;316 317err:318 mutex_unlock(&ar->conf_mutex);319 320 return ret;321}322 323static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)324{325 lockdep_assert_held(&ar->conf_mutex);326 327 ath10k_core_stop(ar);328 ath10k_hif_power_down(ar);329 330 spin_lock_bh(&ar->data_lock);331 332 ar->testmode.utf_monitor = false;333 334 spin_unlock_bh(&ar->data_lock);335 336 if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&337 ar->testmode.utf_mode_fw.fw_file.codeswap_len)338 ath10k_swap_code_seg_release(ar,339 &ar->testmode.utf_mode_fw.fw_file);340 341 release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);342 ar->testmode.utf_mode_fw.fw_file.firmware = NULL;343 344 ar->state = ATH10K_STATE_OFF;345}346 347static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])348{349 int ret;350 351 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");352 353 mutex_lock(&ar->conf_mutex);354 355 if (ar->state != ATH10K_STATE_UTF) {356 ret = -ENETDOWN;357 goto out;358 }359 360 __ath10k_tm_cmd_utf_stop(ar);361 362 ret = 0;363 364 ath10k_info(ar, "UTF firmware stopped\n");365 366out:367 mutex_unlock(&ar->conf_mutex);368 return ret;369}370 371static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])372{373 struct sk_buff *skb;374 int ret, buf_len;375 u32 cmd_id;376 void *buf;377 378 mutex_lock(&ar->conf_mutex);379 380 if (ar->state != ATH10K_STATE_UTF) {381 ret = -ENETDOWN;382 goto out;383 }384 385 if (!tb[ATH10K_TM_ATTR_DATA]) {386 ret = -EINVAL;387 goto out;388 }389 390 if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {391 ret = -EINVAL;392 goto out;393 }394 395 buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);396 buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);397 cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);398 399 ath10k_dbg(ar, ATH10K_DBG_TESTMODE,400 "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",401 cmd_id, buf, buf_len);402 403 ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);404 405 skb = ath10k_wmi_alloc_skb(ar, buf_len);406 if (!skb) {407 ret = -ENOMEM;408 goto out;409 }410 411 memcpy(skb->data, buf, buf_len);412 413 ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);414 if (ret) {415 ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",416 ret);417 goto out;418 }419 420 ret = 0;421 422out:423 mutex_unlock(&ar->conf_mutex);424 return ret;425}426 427int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,428 void *data, int len)429{430 struct ath10k *ar = hw->priv;431 struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];432 int ret;433 434 ret = nla_parse_deprecated(tb, ATH10K_TM_ATTR_MAX, data, len,435 ath10k_tm_policy, NULL);436 if (ret)437 return ret;438 439 if (!tb[ATH10K_TM_ATTR_CMD])440 return -EINVAL;441 442 switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {443 case ATH10K_TM_CMD_GET_VERSION:444 return ath10k_tm_cmd_get_version(ar, tb);445 case ATH10K_TM_CMD_UTF_START:446 return ath10k_tm_cmd_utf_start(ar, tb);447 case ATH10K_TM_CMD_UTF_STOP:448 return ath10k_tm_cmd_utf_stop(ar, tb);449 case ATH10K_TM_CMD_WMI:450 return ath10k_tm_cmd_wmi(ar, tb);451 default:452 return -EOPNOTSUPP;453 }454}455 456void ath10k_testmode_destroy(struct ath10k *ar)457{458 mutex_lock(&ar->conf_mutex);459 460 if (ar->state != ATH10K_STATE_UTF) {461 /* utf firmware is not running, nothing to do */462 goto out;463 }464 465 __ath10k_tm_cmd_utf_stop(ar);466 467out:468 mutex_unlock(&ar->conf_mutex);469}470