1 // SPDX-License-Identifier: ISC 2 /* 3 * Copyright (c) 2014-2017 Qualcomm Atheros, Inc. 4 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. 5 */ 6 7 #include "testmode.h" 8 9 #include <net/netlink.h> 10 #include <linux/firmware.h> 11 12 #include "debug.h" 13 #include "wmi.h" 14 #include "wmi-tlv.h" 15 #include "hif.h" 16 #include "hw.h" 17 #include "core.h" 18 19 #include "testmode_i.h" 20 21 #define ATH10K_FTM_SEG_NONE ((u32)-1) 22 #define ATH10K_FTM_SEGHDR_CURRENT_SEQ GENMASK(3, 0) 23 #define ATH10K_FTM_SEGHDR_TOTAL_SEGMENTS GENMASK(7, 4) 24 25 static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = { 26 [ATH10K_TM_ATTR_CMD] = { .type = NLA_U32 }, 27 [ATH10K_TM_ATTR_DATA] = { .type = NLA_BINARY, 28 .len = ATH10K_TM_DATA_MAX_LEN }, 29 [ATH10K_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 }, 30 [ATH10K_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 }, 31 [ATH10K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 }, 32 }; 33 34 static void ath10k_tm_event_unsegmented(struct ath10k *ar, u32 cmd_id, 35 struct sk_buff *skb) 36 { 37 struct sk_buff *nl_skb; 38 int ret; 39 40 nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy, 41 2 * sizeof(u32) + skb->len, 42 GFP_ATOMIC); 43 if (!nl_skb) { 44 ath10k_warn(ar, 45 "failed to allocate skb for testmode wmi event\n"); 46 return; 47 } 48 49 ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI); 50 if (ret) { 51 ath10k_warn(ar, 52 "failed to put testmode wmi event cmd attribute: %d\n", 53 ret); 54 kfree_skb(nl_skb); 55 return; 56 } 57 58 ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id); 59 if (ret) { 60 ath10k_warn(ar, 61 "failed to put testmode wmi event cmd_id: %d\n", 62 ret); 63 kfree_skb(nl_skb); 64 return; 65 } 66 67 ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data); 68 if (ret) { 69 ath10k_warn(ar, 70 "failed to copy skb to testmode wmi event: %d\n", 71 ret); 72 kfree_skb(nl_skb); 73 return; 74 } 75 76 cfg80211_testmode_event(nl_skb, GFP_ATOMIC); 77 } 78 79 static void ath10k_tm_event_segmented(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb) 80 { 81 struct wmi_ftm_cmd *ftm = (struct wmi_ftm_cmd *)skb->data; 82 u8 total_segments, current_seq; 83 struct sk_buff *nl_skb; 84 u8 const *buf_pos; 85 u16 datalen; 86 u32 data_pos; 87 int ret; 88 89 if (skb->len < sizeof(*ftm)) { 90 ath10k_warn(ar, "Invalid ftm event length: %d\n", skb->len); 91 return; 92 } 93 94 current_seq = FIELD_GET(ATH10K_FTM_SEGHDR_CURRENT_SEQ, 95 __le32_to_cpu(ftm->seg_hdr.segmentinfo)); 96 total_segments = FIELD_GET(ATH10K_FTM_SEGHDR_TOTAL_SEGMENTS, 97 __le32_to_cpu(ftm->seg_hdr.segmentinfo)); 98 datalen = skb->len - sizeof(*ftm); 99 buf_pos = ftm->data; 100 101 if (current_seq == 0) { 102 ar->testmode.expected_seq = 0; 103 ar->testmode.data_pos = 0; 104 } 105 106 data_pos = ar->testmode.data_pos; 107 108 if ((data_pos + datalen) > ATH_FTM_EVENT_MAX_BUF_LENGTH) { 109 ath10k_warn(ar, "Invalid ftm event length at %u: %u\n", 110 data_pos, datalen); 111 ret = -EINVAL; 112 return; 113 } 114 115 memcpy(&ar->testmode.eventdata[data_pos], buf_pos, datalen); 116 data_pos += datalen; 117 118 if (++ar->testmode.expected_seq != total_segments) { 119 ar->testmode.data_pos = data_pos; 120 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "partial data received %u/%u\n", 121 current_seq + 1, total_segments); 122 return; 123 } 124 125 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "total data length %u\n", data_pos); 126 127 nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy, 128 2 * sizeof(u32) + data_pos, 129 GFP_ATOMIC); 130 if (!nl_skb) { 131 ath10k_warn(ar, "failed to allocate skb for testmode wmi event\n"); 132 return; 133 } 134 135 ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_TLV); 136 if (ret) { 137 ath10k_warn(ar, "failed to put testmode wmi event attribute: %d\n", ret); 138 kfree_skb(nl_skb); 139 return; 140 } 141 142 ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id); 143 if (ret) { 144 ath10k_warn(ar, "failed to put testmode wmi event cmd_id: %d\n", ret); 145 kfree_skb(nl_skb); 146 return; 147 } 148 149 ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, data_pos, &ar->testmode.eventdata[0]); 150 if (ret) { 151 ath10k_warn(ar, "failed to copy skb to testmode wmi event: %d\n", ret); 152 kfree_skb(nl_skb); 153 return; 154 } 155 156 cfg80211_testmode_event(nl_skb, GFP_ATOMIC); 157 } 158 159 static bool ath10k_tm_is_utf_event(u32 cmd_id) 160 { 161 return cmd_id == WMI_10X_PDEV_UTF_EVENTID || 162 cmd_id == WMI_10_2_PDEV_UTF_EVENTID || 163 cmd_id == WMI_10_4_PDEV_UTF_EVENTID || 164 cmd_id == WMI_TLV_PDEV_UTF_EVENTID; 165 } 166 167 /* Returns true if callee consumes the skb and the skb should be discarded. 168 * Returns false if skb is not used. Does not sleep. 169 */ 170 bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb) 171 { 172 bool consumed; 173 174 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, 175 "testmode event wmi cmd_id %d skb %p skb->len %d\n", 176 cmd_id, skb, skb->len); 177 178 ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len); 179 180 spin_lock_bh(&ar->data_lock); 181 182 if (!ar->testmode.utf_monitor) { 183 consumed = false; 184 goto out; 185 } 186 187 /* Only testmode.c should be handling events from utf firmware, 188 * otherwise all sort of problems will arise as mac80211 operations 189 * are not initialised. 190 */ 191 consumed = true; 192 193 if (!ath10k_tm_is_utf_event(cmd_id)) { 194 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, 195 "testmode drop non-utf event cmd_id %u\n", cmd_id); 196 goto out; 197 } 198 199 if (ar->testmode.expected_seq != ATH10K_FTM_SEG_NONE) 200 ath10k_tm_event_segmented(ar, cmd_id, skb); 201 else 202 ath10k_tm_event_unsegmented(ar, cmd_id, skb); 203 204 out: 205 spin_unlock_bh(&ar->data_lock); 206 207 return consumed; 208 } 209 210 static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[]) 211 { 212 struct sk_buff *skb; 213 int ret; 214 215 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, 216 "testmode cmd get version_major %d version_minor %d\n", 217 ATH10K_TESTMODE_VERSION_MAJOR, 218 ATH10K_TESTMODE_VERSION_MINOR); 219 220 skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy, 221 nla_total_size(sizeof(u32))); 222 if (!skb) 223 return -ENOMEM; 224 225 ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR, 226 ATH10K_TESTMODE_VERSION_MAJOR); 227 if (ret) { 228 kfree_skb(skb); 229 return ret; 230 } 231 232 ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR, 233 ATH10K_TESTMODE_VERSION_MINOR); 234 if (ret) { 235 kfree_skb(skb); 236 return ret; 237 } 238 239 ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION, 240 ar->normal_mode_fw.fw_file.wmi_op_version); 241 if (ret) { 242 kfree_skb(skb); 243 return ret; 244 } 245 246 return cfg80211_testmode_reply(skb); 247 } 248 249 static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar, 250 struct ath10k_fw_file *fw_file) 251 { 252 char filename[100]; 253 int ret; 254 255 snprintf(filename, sizeof(filename), "%s/%s", 256 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE); 257 258 /* load utf firmware image */ 259 ret = firmware_request_nowarn(&fw_file->firmware, filename, ar->dev); 260 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode fw request '%s': %d\n", 261 filename, ret); 262 263 if (ret) { 264 ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n", 265 filename, ret); 266 return ret; 267 } 268 269 /* We didn't find FW UTF API 1 ("utf.bin") does not advertise 270 * firmware features. Do an ugly hack where we force the firmware 271 * features to match with 10.1 branch so that wmi.c will use the 272 * correct WMI interface. 273 */ 274 275 fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1; 276 fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1; 277 fw_file->firmware_data = fw_file->firmware->data; 278 fw_file->firmware_len = fw_file->firmware->size; 279 280 return 0; 281 } 282 283 static int ath10k_tm_fetch_firmware(struct ath10k *ar) 284 { 285 struct ath10k_fw_components *utf_mode_fw; 286 int ret; 287 char fw_name[100]; 288 int fw_api2 = 2; 289 290 switch (ar->hif.bus) { 291 case ATH10K_BUS_SDIO: 292 case ATH10K_BUS_USB: 293 scnprintf(fw_name, sizeof(fw_name), "%s-%s-%d.bin", 294 ATH10K_FW_UTF_FILE_BASE, ath10k_bus_str(ar->hif.bus), 295 fw_api2); 296 break; 297 default: 298 scnprintf(fw_name, sizeof(fw_name), "%s-%d.bin", 299 ATH10K_FW_UTF_FILE_BASE, fw_api2); 300 break; 301 } 302 303 ret = ath10k_core_fetch_firmware_api_n(ar, fw_name, 304 &ar->testmode.utf_mode_fw.fw_file); 305 if (ret == 0) { 306 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2"); 307 goto out; 308 } 309 310 ret = ath10k_tm_fetch_utf_firmware_api_1(ar, &ar->testmode.utf_mode_fw.fw_file); 311 if (ret) { 312 ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret); 313 return ret; 314 } 315 316 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1"); 317 318 out: 319 utf_mode_fw = &ar->testmode.utf_mode_fw; 320 321 /* Use the same board data file as the normal firmware uses (but 322 * it's still "owned" by normal_mode_fw so we shouldn't free it. 323 */ 324 utf_mode_fw->board_data = ar->normal_mode_fw.board_data; 325 utf_mode_fw->board_len = ar->normal_mode_fw.board_len; 326 327 if (!utf_mode_fw->fw_file.otp_data) { 328 ath10k_info(ar, "utf.bin didn't contain otp binary, taking it from the normal mode firmware"); 329 utf_mode_fw->fw_file.otp_data = ar->normal_mode_fw.fw_file.otp_data; 330 utf_mode_fw->fw_file.otp_len = ar->normal_mode_fw.fw_file.otp_len; 331 } 332 333 return 0; 334 } 335 336 static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) 337 { 338 const char *ver; 339 int ret; 340 341 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n"); 342 343 mutex_lock(&ar->conf_mutex); 344 345 if (ar->state == ATH10K_STATE_UTF) { 346 ret = -EALREADY; 347 goto err; 348 } 349 350 /* start utf only when the driver is not in use */ 351 if (ar->state != ATH10K_STATE_OFF) { 352 ret = -EBUSY; 353 goto err; 354 } 355 356 if (WARN_ON(ar->testmode.utf_mode_fw.fw_file.firmware != NULL)) { 357 /* utf image is already downloaded, it shouldn't be */ 358 ret = -EEXIST; 359 goto err; 360 } 361 362 ret = ath10k_tm_fetch_firmware(ar); 363 if (ret) { 364 ath10k_err(ar, "failed to fetch UTF firmware: %d", ret); 365 goto err; 366 } 367 368 if (ar->testmode.utf_mode_fw.fw_file.codeswap_data && 369 ar->testmode.utf_mode_fw.fw_file.codeswap_len) { 370 ret = ath10k_swap_code_seg_init(ar, 371 &ar->testmode.utf_mode_fw.fw_file); 372 if (ret) { 373 ath10k_warn(ar, 374 "failed to init utf code swap segment: %d\n", 375 ret); 376 goto err_release_utf_mode_fw; 377 } 378 } 379 380 spin_lock_bh(&ar->data_lock); 381 ar->testmode.utf_monitor = true; 382 spin_unlock_bh(&ar->data_lock); 383 384 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n", 385 ar->testmode.utf_mode_fw.fw_file.wmi_op_version); 386 387 ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_UTF); 388 if (ret) { 389 ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret); 390 ar->state = ATH10K_STATE_OFF; 391 goto err_release_utf_mode_fw; 392 } 393 394 ar->testmode.eventdata = kzalloc(ATH_FTM_EVENT_MAX_BUF_LENGTH, GFP_KERNEL); 395 if (!ar->testmode.eventdata) { 396 ret = -ENOMEM; 397 goto err_power_down; 398 } 399 400 ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF, 401 &ar->testmode.utf_mode_fw); 402 if (ret) { 403 ath10k_err(ar, "failed to start core (testmode): %d\n", ret); 404 ar->state = ATH10K_STATE_OFF; 405 goto err_release_eventdata; 406 } 407 408 ar->state = ATH10K_STATE_UTF; 409 410 if (strlen(ar->testmode.utf_mode_fw.fw_file.fw_version) > 0) 411 ver = ar->testmode.utf_mode_fw.fw_file.fw_version; 412 else 413 ver = "API 1"; 414 415 ath10k_info(ar, "UTF firmware %s started\n", ver); 416 417 mutex_unlock(&ar->conf_mutex); 418 419 return 0; 420 421 err_release_eventdata: 422 kfree(ar->testmode.eventdata); 423 ar->testmode.eventdata = NULL; 424 425 err_power_down: 426 ath10k_hif_power_down(ar); 427 428 err_release_utf_mode_fw: 429 if (ar->testmode.utf_mode_fw.fw_file.codeswap_data && 430 ar->testmode.utf_mode_fw.fw_file.codeswap_len) 431 ath10k_swap_code_seg_release(ar, 432 &ar->testmode.utf_mode_fw.fw_file); 433 434 release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware); 435 ar->testmode.utf_mode_fw.fw_file.firmware = NULL; 436 437 err: 438 mutex_unlock(&ar->conf_mutex); 439 440 return ret; 441 } 442 443 static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar) 444 { 445 lockdep_assert_held(&ar->conf_mutex); 446 447 ath10k_core_stop(ar); 448 ath10k_hif_power_down(ar); 449 450 spin_lock_bh(&ar->data_lock); 451 452 ar->testmode.utf_monitor = false; 453 454 spin_unlock_bh(&ar->data_lock); 455 456 if (ar->testmode.utf_mode_fw.fw_file.codeswap_data && 457 ar->testmode.utf_mode_fw.fw_file.codeswap_len) 458 ath10k_swap_code_seg_release(ar, 459 &ar->testmode.utf_mode_fw.fw_file); 460 461 release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware); 462 ar->testmode.utf_mode_fw.fw_file.firmware = NULL; 463 464 kfree(ar->testmode.eventdata); 465 ar->testmode.eventdata = NULL; 466 467 ar->state = ATH10K_STATE_OFF; 468 } 469 470 static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[]) 471 { 472 int ret; 473 474 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n"); 475 476 mutex_lock(&ar->conf_mutex); 477 478 if (ar->state != ATH10K_STATE_UTF) { 479 ret = -ENETDOWN; 480 goto out; 481 } 482 483 __ath10k_tm_cmd_utf_stop(ar); 484 485 ret = 0; 486 487 ath10k_info(ar, "UTF firmware stopped\n"); 488 489 out: 490 mutex_unlock(&ar->conf_mutex); 491 return ret; 492 } 493 494 static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[]) 495 { 496 struct sk_buff *skb; 497 int ret, buf_len; 498 u32 cmd_id; 499 void *buf; 500 501 mutex_lock(&ar->conf_mutex); 502 503 if (ar->state != ATH10K_STATE_UTF) { 504 ret = -ENETDOWN; 505 goto out; 506 } 507 508 if (!tb[ATH10K_TM_ATTR_DATA]) { 509 ret = -EINVAL; 510 goto out; 511 } 512 513 if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) { 514 ret = -EINVAL; 515 goto out; 516 } 517 518 buf = nla_data(tb[ATH10K_TM_ATTR_DATA]); 519 buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]); 520 cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]); 521 522 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, 523 "testmode cmd wmi cmd_id %d buf %p buf_len %d\n", 524 cmd_id, buf, buf_len); 525 526 ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len); 527 528 skb = ath10k_wmi_alloc_skb(ar, buf_len); 529 if (!skb) { 530 ret = -ENOMEM; 531 goto out; 532 } 533 534 memcpy(skb->data, buf, buf_len); 535 536 ret = ath10k_wmi_cmd_send(ar, skb, cmd_id); 537 if (ret) { 538 ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n", 539 ret); 540 goto out; 541 } 542 543 ret = 0; 544 545 out: 546 mutex_unlock(&ar->conf_mutex); 547 return ret; 548 } 549 550 static int ath10k_tm_cmd_tlv(struct ath10k *ar, struct nlattr *tb[]) 551 { 552 u16 total_bytes, num_segments; 553 u32 cmd_id, buf_len; 554 u8 segnumber = 0; 555 u8 *bufpos; 556 void *buf; 557 int ret; 558 559 mutex_lock(&ar->conf_mutex); 560 561 if (ar->state != ATH10K_STATE_UTF) { 562 ret = -ENETDOWN; 563 goto out; 564 } 565 566 buf = nla_data(tb[ATH10K_TM_ATTR_DATA]); 567 buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]); 568 cmd_id = WMI_PDEV_UTF_CMDID; 569 570 ath10k_dbg(ar, ATH10K_DBG_TESTMODE, 571 "cmd wmi ftm cmd_id %d buffer length %d\n", 572 cmd_id, buf_len); 573 ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len); 574 575 bufpos = buf; 576 total_bytes = buf_len; 577 num_segments = total_bytes / MAX_WMI_UTF_LEN; 578 ar->testmode.expected_seq = 0; 579 580 if (buf_len - (num_segments * MAX_WMI_UTF_LEN)) 581 num_segments++; 582 583 while (buf_len) { 584 u16 chunk_len = min_t(u16, buf_len, MAX_WMI_UTF_LEN); 585 struct wmi_ftm_cmd *ftm_cmd; 586 struct sk_buff *skb; 587 u32 hdr_info; 588 u8 seginfo; 589 590 skb = ath10k_wmi_alloc_skb(ar, (chunk_len + 591 sizeof(struct wmi_ftm_cmd))); 592 if (!skb) { 593 ret = -ENOMEM; 594 goto out; 595 } 596 597 ftm_cmd = (struct wmi_ftm_cmd *)skb->data; 598 hdr_info = FIELD_PREP(WMI_TLV_TAG, WMI_TLV_TAG_ARRAY_BYTE) | 599 FIELD_PREP(WMI_TLV_LEN, (chunk_len + 600 sizeof(struct wmi_ftm_seg_hdr))); 601 ftm_cmd->tlv_header = __cpu_to_le32(hdr_info); 602 ftm_cmd->seg_hdr.len = __cpu_to_le32(total_bytes); 603 ftm_cmd->seg_hdr.msgref = __cpu_to_le32(ar->testmode.ftm_msgref); 604 seginfo = FIELD_PREP(ATH10K_FTM_SEGHDR_TOTAL_SEGMENTS, num_segments) | 605 FIELD_PREP(ATH10K_FTM_SEGHDR_CURRENT_SEQ, segnumber); 606 ftm_cmd->seg_hdr.segmentinfo = __cpu_to_le32(seginfo); 607 segnumber++; 608 609 memcpy(&ftm_cmd->data, bufpos, chunk_len); 610 611 ret = ath10k_wmi_cmd_send(ar, skb, cmd_id); 612 if (ret) { 613 ath10k_warn(ar, "failed to send wmi ftm command: %d\n", ret); 614 goto out; 615 } 616 617 buf_len -= chunk_len; 618 bufpos += chunk_len; 619 } 620 621 ar->testmode.ftm_msgref++; 622 ret = 0; 623 624 out: 625 mutex_unlock(&ar->conf_mutex); 626 return ret; 627 } 628 629 int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 630 void *data, int len) 631 { 632 struct ath10k *ar = hw->priv; 633 struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1]; 634 int ret; 635 636 ret = nla_parse_deprecated(tb, ATH10K_TM_ATTR_MAX, data, len, 637 ath10k_tm_policy, NULL); 638 if (ret) 639 return ret; 640 641 if (!tb[ATH10K_TM_ATTR_CMD]) 642 return -EINVAL; 643 644 ar->testmode.expected_seq = ATH10K_FTM_SEG_NONE; 645 646 switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) { 647 case ATH10K_TM_CMD_GET_VERSION: 648 if (!tb[ATH10K_TM_ATTR_DATA]) 649 return ath10k_tm_cmd_get_version(ar, tb); 650 else /* ATH10K_TM_CMD_TLV */ 651 return ath10k_tm_cmd_tlv(ar, tb); 652 case ATH10K_TM_CMD_UTF_START: 653 return ath10k_tm_cmd_utf_start(ar, tb); 654 case ATH10K_TM_CMD_UTF_STOP: 655 return ath10k_tm_cmd_utf_stop(ar, tb); 656 case ATH10K_TM_CMD_WMI: 657 return ath10k_tm_cmd_wmi(ar, tb); 658 default: 659 return -EOPNOTSUPP; 660 } 661 } 662 663 void ath10k_testmode_destroy(struct ath10k *ar) 664 { 665 mutex_lock(&ar->conf_mutex); 666 667 if (ar->state != ATH10K_STATE_UTF) { 668 /* utf firmware is not running, nothing to do */ 669 goto out; 670 } 671 672 __ath10k_tm_cmd_utf_stop(ar); 673 674 out: 675 mutex_unlock(&ar->conf_mutex); 676 } 677