Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/athk/ath10k/testmode.c
105585 views
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
/* Returns true if callee consumes the skb and the skb should be discarded.
160
* Returns false if skb is not used. Does not sleep.
161
*/
162
bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
163
{
164
bool consumed;
165
166
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
167
"testmode event wmi cmd_id %d skb %p skb->len %d\n",
168
cmd_id, skb, skb->len);
169
170
ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
171
172
spin_lock_bh(&ar->data_lock);
173
174
if (!ar->testmode.utf_monitor) {
175
consumed = false;
176
goto out;
177
}
178
179
/* Only testmode.c should be handling events from utf firmware,
180
* otherwise all sort of problems will arise as mac80211 operations
181
* are not initialised.
182
*/
183
consumed = true;
184
185
if (ar->testmode.expected_seq != ATH10K_FTM_SEG_NONE)
186
ath10k_tm_event_segmented(ar, cmd_id, skb);
187
else
188
ath10k_tm_event_unsegmented(ar, cmd_id, skb);
189
190
out:
191
spin_unlock_bh(&ar->data_lock);
192
193
return consumed;
194
}
195
196
static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
197
{
198
struct sk_buff *skb;
199
int ret;
200
201
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
202
"testmode cmd get version_major %d version_minor %d\n",
203
ATH10K_TESTMODE_VERSION_MAJOR,
204
ATH10K_TESTMODE_VERSION_MINOR);
205
206
skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
207
nla_total_size(sizeof(u32)));
208
if (!skb)
209
return -ENOMEM;
210
211
ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
212
ATH10K_TESTMODE_VERSION_MAJOR);
213
if (ret) {
214
kfree_skb(skb);
215
return ret;
216
}
217
218
ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
219
ATH10K_TESTMODE_VERSION_MINOR);
220
if (ret) {
221
kfree_skb(skb);
222
return ret;
223
}
224
225
ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION,
226
ar->normal_mode_fw.fw_file.wmi_op_version);
227
if (ret) {
228
kfree_skb(skb);
229
return ret;
230
}
231
232
return cfg80211_testmode_reply(skb);
233
}
234
235
static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar,
236
struct ath10k_fw_file *fw_file)
237
{
238
char filename[100];
239
int ret;
240
241
snprintf(filename, sizeof(filename), "%s/%s",
242
ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
243
244
/* load utf firmware image */
245
ret = firmware_request_nowarn(&fw_file->firmware, filename, ar->dev);
246
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode fw request '%s': %d\n",
247
filename, ret);
248
249
if (ret) {
250
ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
251
filename, ret);
252
return ret;
253
}
254
255
/* We didn't find FW UTF API 1 ("utf.bin") does not advertise
256
* firmware features. Do an ugly hack where we force the firmware
257
* features to match with 10.1 branch so that wmi.c will use the
258
* correct WMI interface.
259
*/
260
261
fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
262
fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
263
fw_file->firmware_data = fw_file->firmware->data;
264
fw_file->firmware_len = fw_file->firmware->size;
265
266
return 0;
267
}
268
269
static int ath10k_tm_fetch_firmware(struct ath10k *ar)
270
{
271
struct ath10k_fw_components *utf_mode_fw;
272
int ret;
273
char fw_name[100];
274
int fw_api2 = 2;
275
276
switch (ar->hif.bus) {
277
case ATH10K_BUS_SDIO:
278
case ATH10K_BUS_USB:
279
scnprintf(fw_name, sizeof(fw_name), "%s-%s-%d.bin",
280
ATH10K_FW_UTF_FILE_BASE, ath10k_bus_str(ar->hif.bus),
281
fw_api2);
282
break;
283
default:
284
scnprintf(fw_name, sizeof(fw_name), "%s-%d.bin",
285
ATH10K_FW_UTF_FILE_BASE, fw_api2);
286
break;
287
}
288
289
ret = ath10k_core_fetch_firmware_api_n(ar, fw_name,
290
&ar->testmode.utf_mode_fw.fw_file);
291
if (ret == 0) {
292
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
293
goto out;
294
}
295
296
ret = ath10k_tm_fetch_utf_firmware_api_1(ar, &ar->testmode.utf_mode_fw.fw_file);
297
if (ret) {
298
ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);
299
return ret;
300
}
301
302
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");
303
304
out:
305
utf_mode_fw = &ar->testmode.utf_mode_fw;
306
307
/* Use the same board data file as the normal firmware uses (but
308
* it's still "owned" by normal_mode_fw so we shouldn't free it.
309
*/
310
utf_mode_fw->board_data = ar->normal_mode_fw.board_data;
311
utf_mode_fw->board_len = ar->normal_mode_fw.board_len;
312
313
if (!utf_mode_fw->fw_file.otp_data) {
314
ath10k_info(ar, "utf.bin didn't contain otp binary, taking it from the normal mode firmware");
315
utf_mode_fw->fw_file.otp_data = ar->normal_mode_fw.fw_file.otp_data;
316
utf_mode_fw->fw_file.otp_len = ar->normal_mode_fw.fw_file.otp_len;
317
}
318
319
return 0;
320
}
321
322
static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
323
{
324
const char *ver;
325
int ret;
326
327
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
328
329
mutex_lock(&ar->conf_mutex);
330
331
if (ar->state == ATH10K_STATE_UTF) {
332
ret = -EALREADY;
333
goto err;
334
}
335
336
/* start utf only when the driver is not in use */
337
if (ar->state != ATH10K_STATE_OFF) {
338
ret = -EBUSY;
339
goto err;
340
}
341
342
if (WARN_ON(ar->testmode.utf_mode_fw.fw_file.firmware != NULL)) {
343
/* utf image is already downloaded, it shouldn't be */
344
ret = -EEXIST;
345
goto err;
346
}
347
348
ret = ath10k_tm_fetch_firmware(ar);
349
if (ret) {
350
ath10k_err(ar, "failed to fetch UTF firmware: %d", ret);
351
goto err;
352
}
353
354
if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
355
ar->testmode.utf_mode_fw.fw_file.codeswap_len) {
356
ret = ath10k_swap_code_seg_init(ar,
357
&ar->testmode.utf_mode_fw.fw_file);
358
if (ret) {
359
ath10k_warn(ar,
360
"failed to init utf code swap segment: %d\n",
361
ret);
362
goto err_release_utf_mode_fw;
363
}
364
}
365
366
spin_lock_bh(&ar->data_lock);
367
ar->testmode.utf_monitor = true;
368
spin_unlock_bh(&ar->data_lock);
369
370
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",
371
ar->testmode.utf_mode_fw.fw_file.wmi_op_version);
372
373
ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_UTF);
374
if (ret) {
375
ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
376
ar->state = ATH10K_STATE_OFF;
377
goto err_release_utf_mode_fw;
378
}
379
380
ar->testmode.eventdata = kzalloc(ATH_FTM_EVENT_MAX_BUF_LENGTH, GFP_KERNEL);
381
if (!ar->testmode.eventdata) {
382
ret = -ENOMEM;
383
goto err_power_down;
384
}
385
386
ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF,
387
&ar->testmode.utf_mode_fw);
388
if (ret) {
389
ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
390
ar->state = ATH10K_STATE_OFF;
391
goto err_release_eventdata;
392
}
393
394
ar->state = ATH10K_STATE_UTF;
395
396
if (strlen(ar->testmode.utf_mode_fw.fw_file.fw_version) > 0)
397
ver = ar->testmode.utf_mode_fw.fw_file.fw_version;
398
else
399
ver = "API 1";
400
401
ath10k_info(ar, "UTF firmware %s started\n", ver);
402
403
mutex_unlock(&ar->conf_mutex);
404
405
return 0;
406
407
err_release_eventdata:
408
kfree(ar->testmode.eventdata);
409
ar->testmode.eventdata = NULL;
410
411
err_power_down:
412
ath10k_hif_power_down(ar);
413
414
err_release_utf_mode_fw:
415
if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
416
ar->testmode.utf_mode_fw.fw_file.codeswap_len)
417
ath10k_swap_code_seg_release(ar,
418
&ar->testmode.utf_mode_fw.fw_file);
419
420
release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
421
ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
422
423
err:
424
mutex_unlock(&ar->conf_mutex);
425
426
return ret;
427
}
428
429
static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
430
{
431
lockdep_assert_held(&ar->conf_mutex);
432
433
ath10k_core_stop(ar);
434
ath10k_hif_power_down(ar);
435
436
spin_lock_bh(&ar->data_lock);
437
438
ar->testmode.utf_monitor = false;
439
440
spin_unlock_bh(&ar->data_lock);
441
442
if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
443
ar->testmode.utf_mode_fw.fw_file.codeswap_len)
444
ath10k_swap_code_seg_release(ar,
445
&ar->testmode.utf_mode_fw.fw_file);
446
447
release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
448
ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
449
450
kfree(ar->testmode.eventdata);
451
ar->testmode.eventdata = NULL;
452
453
ar->state = ATH10K_STATE_OFF;
454
}
455
456
static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
457
{
458
int ret;
459
460
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
461
462
mutex_lock(&ar->conf_mutex);
463
464
if (ar->state != ATH10K_STATE_UTF) {
465
ret = -ENETDOWN;
466
goto out;
467
}
468
469
__ath10k_tm_cmd_utf_stop(ar);
470
471
ret = 0;
472
473
ath10k_info(ar, "UTF firmware stopped\n");
474
475
out:
476
mutex_unlock(&ar->conf_mutex);
477
return ret;
478
}
479
480
static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
481
{
482
struct sk_buff *skb;
483
int ret, buf_len;
484
u32 cmd_id;
485
void *buf;
486
487
mutex_lock(&ar->conf_mutex);
488
489
if (ar->state != ATH10K_STATE_UTF) {
490
ret = -ENETDOWN;
491
goto out;
492
}
493
494
if (!tb[ATH10K_TM_ATTR_DATA]) {
495
ret = -EINVAL;
496
goto out;
497
}
498
499
if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
500
ret = -EINVAL;
501
goto out;
502
}
503
504
buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
505
buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
506
cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
507
508
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
509
"testmode cmd wmi cmd_id %d buf %p buf_len %d\n",
510
cmd_id, buf, buf_len);
511
512
ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
513
514
skb = ath10k_wmi_alloc_skb(ar, buf_len);
515
if (!skb) {
516
ret = -ENOMEM;
517
goto out;
518
}
519
520
memcpy(skb->data, buf, buf_len);
521
522
ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
523
if (ret) {
524
ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
525
ret);
526
goto out;
527
}
528
529
ret = 0;
530
531
out:
532
mutex_unlock(&ar->conf_mutex);
533
return ret;
534
}
535
536
static int ath10k_tm_cmd_tlv(struct ath10k *ar, struct nlattr *tb[])
537
{
538
u16 total_bytes, num_segments;
539
u32 cmd_id, buf_len;
540
u8 segnumber = 0;
541
u8 *bufpos;
542
void *buf;
543
int ret;
544
545
mutex_lock(&ar->conf_mutex);
546
547
if (ar->state != ATH10K_STATE_UTF) {
548
ret = -ENETDOWN;
549
goto out;
550
}
551
552
buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
553
buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
554
cmd_id = WMI_PDEV_UTF_CMDID;
555
556
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
557
"cmd wmi ftm cmd_id %d buffer length %d\n",
558
cmd_id, buf_len);
559
ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
560
561
bufpos = buf;
562
total_bytes = buf_len;
563
num_segments = total_bytes / MAX_WMI_UTF_LEN;
564
ar->testmode.expected_seq = 0;
565
566
if (buf_len - (num_segments * MAX_WMI_UTF_LEN))
567
num_segments++;
568
569
while (buf_len) {
570
u16 chunk_len = min_t(u16, buf_len, MAX_WMI_UTF_LEN);
571
struct wmi_ftm_cmd *ftm_cmd;
572
struct sk_buff *skb;
573
u32 hdr_info;
574
u8 seginfo;
575
576
skb = ath10k_wmi_alloc_skb(ar, (chunk_len +
577
sizeof(struct wmi_ftm_cmd)));
578
if (!skb) {
579
ret = -ENOMEM;
580
goto out;
581
}
582
583
ftm_cmd = (struct wmi_ftm_cmd *)skb->data;
584
hdr_info = FIELD_PREP(WMI_TLV_TAG, WMI_TLV_TAG_ARRAY_BYTE) |
585
FIELD_PREP(WMI_TLV_LEN, (chunk_len +
586
sizeof(struct wmi_ftm_seg_hdr)));
587
ftm_cmd->tlv_header = __cpu_to_le32(hdr_info);
588
ftm_cmd->seg_hdr.len = __cpu_to_le32(total_bytes);
589
ftm_cmd->seg_hdr.msgref = __cpu_to_le32(ar->testmode.ftm_msgref);
590
seginfo = FIELD_PREP(ATH10K_FTM_SEGHDR_TOTAL_SEGMENTS, num_segments) |
591
FIELD_PREP(ATH10K_FTM_SEGHDR_CURRENT_SEQ, segnumber);
592
ftm_cmd->seg_hdr.segmentinfo = __cpu_to_le32(seginfo);
593
segnumber++;
594
595
memcpy(&ftm_cmd->data, bufpos, chunk_len);
596
597
ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
598
if (ret) {
599
ath10k_warn(ar, "failed to send wmi ftm command: %d\n", ret);
600
goto out;
601
}
602
603
buf_len -= chunk_len;
604
bufpos += chunk_len;
605
}
606
607
ar->testmode.ftm_msgref++;
608
ret = 0;
609
610
out:
611
mutex_unlock(&ar->conf_mutex);
612
return ret;
613
}
614
615
int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
616
void *data, int len)
617
{
618
struct ath10k *ar = hw->priv;
619
struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
620
int ret;
621
622
ret = nla_parse_deprecated(tb, ATH10K_TM_ATTR_MAX, data, len,
623
ath10k_tm_policy, NULL);
624
if (ret)
625
return ret;
626
627
if (!tb[ATH10K_TM_ATTR_CMD])
628
return -EINVAL;
629
630
ar->testmode.expected_seq = ATH10K_FTM_SEG_NONE;
631
632
switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
633
case ATH10K_TM_CMD_GET_VERSION:
634
if (!tb[ATH10K_TM_ATTR_DATA])
635
return ath10k_tm_cmd_get_version(ar, tb);
636
else /* ATH10K_TM_CMD_TLV */
637
return ath10k_tm_cmd_tlv(ar, tb);
638
case ATH10K_TM_CMD_UTF_START:
639
return ath10k_tm_cmd_utf_start(ar, tb);
640
case ATH10K_TM_CMD_UTF_STOP:
641
return ath10k_tm_cmd_utf_stop(ar, tb);
642
case ATH10K_TM_CMD_WMI:
643
return ath10k_tm_cmd_wmi(ar, tb);
644
default:
645
return -EOPNOTSUPP;
646
}
647
}
648
649
void ath10k_testmode_destroy(struct ath10k *ar)
650
{
651
mutex_lock(&ar->conf_mutex);
652
653
if (ar->state != ATH10K_STATE_UTF) {
654
/* utf firmware is not running, nothing to do */
655
goto out;
656
}
657
658
__ath10k_tm_cmd_utf_stop(ar);
659
660
out:
661
mutex_unlock(&ar->conf_mutex);
662
}
663
664