uboot-envtools: ramips: add support for ALFA Network AX1800RM
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / ath11k / 0082-wifi-ath11k-factory-test-mode-support.patch
1 From b43310e44edc823a7f02af1e1e2b4e8a9abc7d91 Mon Sep 17 00:00:00 2001
2 From: Govindaraj Saminathan <quic_gsaminat@quicinc.com>
3 Date: Fri, 26 May 2023 12:41:07 +0300
4 Subject: [PATCH 83/84] wifi: ath11k: factory test mode support
5
6 Add support to process factory test mode commands (FTM) for calibration.
7 By default firmware start with NORMAL mode and to process the FTM commands
8 firmware needs to be restarted in FTM mode using module parameter ftm_mode.
9 The pre-request is all the radios should be down before starting the test.
10
11 When start command ATH11K_TM_CMD_TESTMODE_START is received, ar->state
12 is set to Test Mode. If the FTM command or event length is greater
13 than 256 bytes, it will be broken down into multiple segments and
14 encoded with TLV header if it is segmented commands, else it is sent
15 to firmware as it is.
16
17 On receiving UTF event from firmware, if it is segmented event, the driver
18 will wait until it receives all the segments and notify the complete
19 data to user application. In case the segmented sequence are missed or
20 lost from the firmware, driver will skip the already received partial data.
21
22 In case of unsegmented UTF event from firmware, driver notifies the
23 data to the user application as it comes. Applications handles
24 the data further.
25
26 Command to boot in ftm mode:
27
28 insmod ath11k ftm_mode=1
29
30 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
31
32 Signed-off-by: Govindaraj Saminathan <quic_gsaminat@quicinc.com>
33 Co-developed-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
34 Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
35 Signed-off-by: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com>
36 Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
37 Link: https://lore.kernel.org/r/20230517135934.16408-4-quic_rajkbhag@quicinc.com
38 ---
39 drivers/net/wireless/ath/ath11k/ahb.c | 3 +-
40 drivers/net/wireless/ath/ath11k/core.c | 21 +-
41 drivers/net/wireless/ath/ath11k/core.h | 16 +-
42 drivers/net/wireless/ath/ath11k/debug.h | 1 +
43 drivers/net/wireless/ath/ath11k/mac.c | 11 +-
44 drivers/net/wireless/ath/ath11k/pci.c | 3 +-
45 drivers/net/wireless/ath/ath11k/testmode.c | 350 ++++++++++++++++++-
46 drivers/net/wireless/ath/ath11k/testmode.h | 6 +
47 drivers/net/wireless/ath/ath11k/testmode_i.h | 18 +-
48 drivers/net/wireless/ath/ath11k/wmi.c | 11 +-
49 drivers/net/wireless/ath/ath11k/wmi.h | 22 ++
50 drivers/net/wireless/ath/ath11k/wow.c | 3 +-
51 12 files changed, 444 insertions(+), 21 deletions(-)
52
53 --- a/drivers/net/wireless/ath/ath11k/ahb.c
54 +++ b/drivers/net/wireless/ath/ath11k/ahb.c
55 @@ -1,7 +1,7 @@
56 // SPDX-License-Identifier: BSD-3-Clause-Clear
57 /*
58 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
59 - * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
60 + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
61 */
62
63 #include <linux/module.h>
64 @@ -1155,6 +1155,7 @@ static int ath11k_ahb_probe(struct platf
65 ab->hif.ops = hif_ops;
66 ab->pdev = pdev;
67 ab->hw_rev = hw_rev;
68 + ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
69 platform_set_drvdata(pdev, ab);
70
71 ret = ath11k_pcic_register_pci_ops(ab, pci_ops);
72 --- a/drivers/net/wireless/ath/ath11k/core.c
73 +++ b/drivers/net/wireless/ath/ath11k/core.c
74 @@ -1,7 +1,7 @@
75 // SPDX-License-Identifier: BSD-3-Clause-Clear
76 /*
77 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
78 - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
79 + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
80 */
81
82 #include <linux/module.h>
83 @@ -32,6 +32,10 @@ module_param_named(frame_mode, ath11k_fr
84 MODULE_PARM_DESC(frame_mode,
85 "Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");
86
87 +bool ath11k_ftm_mode;
88 +module_param_named(ftm_mode, ath11k_ftm_mode, bool, 0444);
89 +MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
90 +
91 static const struct ath11k_hw_params ath11k_hw_params[] = {
92 {
93 .hw_rev = ATH11K_HW_IPQ8074,
94 @@ -1381,6 +1385,11 @@ static int ath11k_core_soc_create(struct
95 {
96 int ret;
97
98 + if (ath11k_ftm_mode) {
99 + ab->fw_mode = ATH11K_FIRMWARE_MODE_FTM;
100 + ath11k_info(ab, "Booting in factory test mode\n");
101 + }
102 +
103 ret = ath11k_qmi_init_service(ab);
104 if (ret) {
105 ath11k_err(ab, "failed to initialize qmi :%d\n", ret);
106 @@ -1607,7 +1616,7 @@ int ath11k_core_qmi_firmware_ready(struc
107 {
108 int ret;
109
110 - ret = ath11k_core_start_firmware(ab, ATH11K_FIRMWARE_MODE_NORMAL);
111 + ret = ath11k_core_start_firmware(ab, ab->fw_mode);
112 if (ret) {
113 ath11k_err(ab, "failed to start firmware: %d\n", ret);
114 return ret;
115 @@ -1772,7 +1781,8 @@ void ath11k_core_pre_reconfigure_recover
116 for (i = 0; i < ab->num_radios; i++) {
117 pdev = &ab->pdevs[i];
118 ar = pdev->ar;
119 - if (!ar || ar->state == ATH11K_STATE_OFF)
120 + if (!ar || ar->state == ATH11K_STATE_OFF ||
121 + ar->state == ATH11K_STATE_FTM)
122 continue;
123
124 ieee80211_stop_queues(ar->hw);
125 @@ -1841,7 +1851,12 @@ static void ath11k_core_post_reconfigure
126 ath11k_warn(ab,
127 "device is wedged, will not restart radio %d\n", i);
128 break;
129 + case ATH11K_STATE_FTM:
130 + ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
131 + "fw mode reset done radio %d\n", i);
132 + break;
133 }
134 +
135 mutex_unlock(&ar->conf_mutex);
136 }
137 complete(&ab->driver_recovery);
138 --- a/drivers/net/wireless/ath/ath11k/core.h
139 +++ b/drivers/net/wireless/ath/ath11k/core.h
140 @@ -1,7 +1,7 @@
141 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
142 /*
143 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
144 - * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
145 + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
146 */
147
148 #ifndef ATH11K_CORE_H
149 @@ -52,6 +52,7 @@
150 #define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_"
151
152 extern unsigned int ath11k_frame_mode;
153 +extern bool ath11k_ftm_mode;
154
155 #define ATH11K_SCAN_TIMEOUT_HZ (20 * HZ)
156
157 @@ -277,6 +278,7 @@ enum ath11k_dev_flags {
158 ATH11K_FLAG_FIXED_MEM_RGN,
159 ATH11K_FLAG_DEVICE_INIT_DONE,
160 ATH11K_FLAG_MULTI_MSI_VECTORS,
161 + ATH11K_FLAG_FTM_SEGMENTED,
162 };
163
164 enum ath11k_monitor_flags {
165 @@ -530,6 +532,7 @@ enum ath11k_state {
166 ATH11K_STATE_RESTARTING,
167 ATH11K_STATE_RESTARTED,
168 ATH11K_STATE_WEDGED,
169 + ATH11K_STATE_FTM,
170 /* Add other states as required */
171 };
172
173 @@ -709,6 +712,8 @@ struct ath11k {
174 u32 last_ppdu_id;
175 u32 cached_ppdu_id;
176 int monitor_vdev_id;
177 + struct completion fw_mode_reset;
178 + u8 ftm_msgref;
179 #ifdef CPTCFG_ATH11K_DEBUGFS
180 struct ath11k_debug debug;
181 #endif
182 @@ -838,6 +843,7 @@ struct ath11k_msi_config {
183 /* Master structure to hold the hw data which may be used in core module */
184 struct ath11k_base {
185 enum ath11k_hw_rev hw_rev;
186 + enum ath11k_firmware_mode fw_mode;
187 struct platform_device *pdev;
188 struct device *dev;
189 struct ath11k_qmi qmi;
190 @@ -978,6 +984,14 @@ struct ath11k_base {
191 const struct ath11k_pci_ops *ops;
192 } pci;
193
194 +#ifdef CPTCFG_NL80211_TESTMODE
195 + struct {
196 + u32 data_pos;
197 + u32 expected_seq;
198 + u8 *eventdata;
199 + } testmode;
200 +#endif
201 +
202 /* must be last */
203 u8 drv_priv[] __aligned(sizeof(void *));
204 };
205 --- a/drivers/net/wireless/ath/ath11k/debug.h
206 +++ b/drivers/net/wireless/ath/ath11k/debug.h
207 @@ -1,6 +1,7 @@
208 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
209 /*
210 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
211 + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
212 */
213
214 #ifndef _ATH11K_DEBUG_H_
215 --- a/drivers/net/wireless/ath/ath11k/mac.c
216 +++ b/drivers/net/wireless/ath/ath11k/mac.c
217 @@ -643,7 +643,10 @@ struct ath11k *ath11k_mac_get_ar_by_pdev
218 return NULL;
219
220 for (i = 0; i < ab->num_radios; i++) {
221 - pdev = rcu_dereference(ab->pdevs_active[i]);
222 + if (ab->fw_mode == ATH11K_FIRMWARE_MODE_FTM)
223 + pdev = &ab->pdevs[i];
224 + else
225 + pdev = rcu_dereference(ab->pdevs_active[i]);
226
227 if (pdev && pdev->pdev_id == pdev_id)
228 return (pdev->ar ? pdev->ar : NULL);
229 @@ -6271,6 +6274,11 @@ static int ath11k_mac_op_start(struct ie
230 struct ath11k_pdev *pdev = ar->pdev;
231 int ret;
232
233 + if (ath11k_ftm_mode) {
234 + ath11k_warn(ab, "mac operations not supported in factory test mode\n");
235 + return -EOPNOTSUPP;
236 + }
237 +
238 ath11k_mac_drain_tx(ar);
239 mutex_lock(&ar->conf_mutex);
240
241 @@ -6285,6 +6293,7 @@ static int ath11k_mac_op_start(struct ie
242 case ATH11K_STATE_RESTARTED:
243 case ATH11K_STATE_WEDGED:
244 case ATH11K_STATE_ON:
245 + case ATH11K_STATE_FTM:
246 WARN_ON(1);
247 ret = -EINVAL;
248 goto err;
249 --- a/drivers/net/wireless/ath/ath11k/pci.c
250 +++ b/drivers/net/wireless/ath/ath11k/pci.c
251 @@ -1,7 +1,7 @@
252 // SPDX-License-Identifier: BSD-3-Clause-Clear
253 /*
254 * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
255 - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
256 + * Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
257 */
258
259 #include <linux/module.h>
260 @@ -745,6 +745,7 @@ static int ath11k_pci_probe(struct pci_d
261 ab_pci->ab = ab;
262 ab_pci->pdev = pdev;
263 ab->hif.ops = &ath11k_pci_hif_ops;
264 + ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
265 pci_set_drvdata(pdev, ab);
266 spin_lock_init(&ab_pci->window_lock);
267
268 --- a/drivers/net/wireless/ath/ath11k/testmode.c
269 +++ b/drivers/net/wireless/ath/ath11k/testmode.c
270 @@ -12,6 +12,9 @@
271 #include "core.h"
272 #include "testmode_i.h"
273
274 +#define ATH11K_FTM_SEGHDR_CURRENT_SEQ GENMASK(3, 0)
275 +#define ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS GENMASK(7, 4)
276 +
277 static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = {
278 [ATH11K_TM_ATTR_CMD] = { .type = NLA_U32 },
279 [ATH11K_TM_ATTR_DATA] = { .type = NLA_BINARY,
280 @@ -21,13 +24,217 @@ static const struct nla_policy ath11k_tm
281 [ATH11K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
282 };
283
284 +static struct ath11k *ath11k_tm_get_ar(struct ath11k_base *ab)
285 +{
286 + struct ath11k_pdev *pdev;
287 + struct ath11k *ar = NULL;
288 + int i;
289 +
290 + for (i = 0; i < ab->num_radios; i++) {
291 + pdev = &ab->pdevs[i];
292 + ar = pdev->ar;
293 +
294 + if (ar && ar->state == ATH11K_STATE_FTM)
295 + break;
296 + }
297 +
298 + return ar;
299 +}
300 +
301 +/* This function handles unsegmented events. Data in various events are aggregated
302 + * in application layer, this event is unsegmented from host perspective.
303 + */
304 +static void ath11k_tm_wmi_event_unsegmented(struct ath11k_base *ab, u32 cmd_id,
305 + struct sk_buff *skb)
306 +{
307 + struct sk_buff *nl_skb;
308 + struct ath11k *ar;
309 +
310 + ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
311 + "event wmi cmd_id %d skb length %d\n",
312 + cmd_id, skb->len);
313 + ath11k_dbg_dump(ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
314 +
315 + ar = ath11k_tm_get_ar(ab);
316 + if (!ar) {
317 + ath11k_warn(ab, "testmode event not handled due to invalid pdev\n");
318 + return;
319 + }
320 +
321 + spin_lock_bh(&ar->data_lock);
322 +
323 + nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
324 + 2 * nla_total_size(sizeof(u32)) +
325 + nla_total_size(skb->len),
326 + GFP_ATOMIC);
327 + if (!nl_skb) {
328 + ath11k_warn(ab,
329 + "failed to allocate skb for unsegmented testmode wmi event\n");
330 + goto out;
331 + }
332 +
333 + if (nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI) ||
334 + nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id) ||
335 + nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data)) {
336 + ath11k_warn(ab, "failed to populate testmode unsegmented event\n");
337 + kfree_skb(nl_skb);
338 + goto out;
339 + }
340 +
341 + cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
342 + spin_unlock_bh(&ar->data_lock);
343 + return;
344 +
345 +out:
346 + spin_unlock_bh(&ar->data_lock);
347 + ath11k_warn(ab, "Failed to send testmode event to higher layers\n");
348 +}
349 +
350 +/* This function handles segmented events. Data of various events received
351 + * from firmware is aggregated and sent to application layer
352 + */
353 +static int ath11k_tm_process_event(struct ath11k_base *ab, u32 cmd_id,
354 + const struct wmi_ftm_event_msg *ftm_msg,
355 + u16 length)
356 +{
357 + struct sk_buff *nl_skb;
358 + int ret = 0;
359 + struct ath11k *ar;
360 + u8 const *buf_pos;
361 + u16 datalen;
362 + u8 total_segments, current_seq;
363 + u32 data_pos;
364 + u32 pdev_id;
365 +
366 + ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
367 + "event wmi cmd_id %d ftm event msg %pK datalen %d\n",
368 + cmd_id, ftm_msg, length);
369 + ath11k_dbg_dump(ab, ATH11K_DBG_TESTMODE, NULL, "", ftm_msg, length);
370 + pdev_id = DP_HW2SW_MACID(ftm_msg->seg_hdr.pdev_id);
371 +
372 + if (pdev_id >= ab->num_radios) {
373 + ath11k_warn(ab, "testmode event not handled due to invalid pdev id: %d\n",
374 + pdev_id);
375 + return -EINVAL;
376 + }
377 +
378 + ar = ab->pdevs[pdev_id].ar;
379 + if (!ar) {
380 + ath11k_warn(ab, "testmode event not handled due to absence of pdev\n");
381 + return -ENODEV;
382 + }
383 +
384 + current_seq = FIELD_GET(ATH11K_FTM_SEGHDR_CURRENT_SEQ,
385 + ftm_msg->seg_hdr.segmentinfo);
386 + total_segments = FIELD_GET(ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS,
387 + ftm_msg->seg_hdr.segmentinfo);
388 + datalen = length - (sizeof(struct wmi_ftm_seg_hdr));
389 + buf_pos = ftm_msg->data;
390 +
391 + spin_lock_bh(&ar->data_lock);
392 +
393 + if (current_seq == 0) {
394 + ab->testmode.expected_seq = 0;
395 + ab->testmode.data_pos = 0;
396 + }
397 +
398 + data_pos = ab->testmode.data_pos;
399 +
400 + if ((data_pos + datalen) > ATH11K_FTM_EVENT_MAX_BUF_LENGTH) {
401 + ath11k_warn(ab, "Invalid ftm event length at %d: %d\n",
402 + data_pos, datalen);
403 + ret = -EINVAL;
404 + goto out;
405 + }
406 +
407 + memcpy(&ab->testmode.eventdata[data_pos], buf_pos, datalen);
408 + data_pos += datalen;
409 +
410 + if (++ab->testmode.expected_seq != total_segments) {
411 + ab->testmode.data_pos = data_pos;
412 + ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
413 + "partial data received current_seq %d total_seg %d\n",
414 + current_seq, total_segments);
415 + goto out;
416 + }
417 +
418 + ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
419 + "total data length pos %d len %d\n",
420 + data_pos, ftm_msg->seg_hdr.len);
421 + nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
422 + 2 * nla_total_size(sizeof(u32)) +
423 + nla_total_size(data_pos),
424 + GFP_ATOMIC);
425 + if (!nl_skb) {
426 + ath11k_warn(ab,
427 + "failed to allocate skb for segmented testmode wmi event\n");
428 + ret = -ENOMEM;
429 + goto out;
430 + }
431 +
432 + if (nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD,
433 + ATH11K_TM_CMD_WMI_FTM) ||
434 + nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id) ||
435 + nla_put(nl_skb, ATH11K_TM_ATTR_DATA, data_pos,
436 + &ab->testmode.eventdata[0])) {
437 + ath11k_warn(ab, "failed to populate segmented testmode event");
438 + kfree_skb(nl_skb);
439 + ret = -ENOBUFS;
440 + goto out;
441 + }
442 +
443 + cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
444 +
445 +out:
446 + spin_unlock_bh(&ar->data_lock);
447 + return ret;
448 +}
449 +
450 +static void ath11k_tm_wmi_event_segmented(struct ath11k_base *ab, u32 cmd_id,
451 + struct sk_buff *skb)
452 +{
453 + const void **tb;
454 + const struct wmi_ftm_event_msg *ev;
455 + u16 length;
456 + int ret;
457 +
458 + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
459 + if (IS_ERR(tb)) {
460 + ret = PTR_ERR(tb);
461 + ath11k_warn(ab, "failed to parse ftm event tlv: %d\n", ret);
462 + return;
463 + }
464 +
465 + ev = tb[WMI_TAG_ARRAY_BYTE];
466 + if (!ev) {
467 + ath11k_warn(ab, "failed to fetch ftm msg\n");
468 + kfree(tb);
469 + return;
470 + }
471 +
472 + length = skb->len - TLV_HDR_SIZE;
473 + ret = ath11k_tm_process_event(ab, cmd_id, ev, length);
474 + if (ret)
475 + ath11k_warn(ab, "Failed to process ftm event\n");
476 +
477 + kfree(tb);
478 +}
479 +
480 +void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id, struct sk_buff *skb)
481 +{
482 + if (test_bit(ATH11K_FLAG_FTM_SEGMENTED, &ab->dev_flags))
483 + ath11k_tm_wmi_event_segmented(ab, cmd_id, skb);
484 + else
485 + ath11k_tm_wmi_event_unsegmented(ab, cmd_id, skb);
486 +}
487 +
488 static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[])
489 {
490 struct sk_buff *skb;
491 int ret;
492
493 ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
494 - "testmode cmd get version_major %d version_minor %d\n",
495 + "cmd get version_major %d version_minor %d\n",
496 ATH11K_TESTMODE_VERSION_MAJOR,
497 ATH11K_TESTMODE_VERSION_MINOR);
498
499 @@ -53,6 +260,43 @@ static int ath11k_tm_cmd_get_version(str
500 return cfg80211_testmode_reply(skb);
501 }
502
503 +static int ath11k_tm_cmd_testmode_start(struct ath11k *ar, struct nlattr *tb[])
504 +{
505 + int ret;
506 +
507 + mutex_lock(&ar->conf_mutex);
508 +
509 + if (ar->state == ATH11K_STATE_FTM) {
510 + ret = -EALREADY;
511 + goto err;
512 + }
513 +
514 + /* start utf only when the driver is not in use */
515 + if (ar->state != ATH11K_STATE_OFF) {
516 + ret = -EBUSY;
517 + goto err;
518 + }
519 +
520 + ar->ab->testmode.eventdata = kzalloc(ATH11K_FTM_EVENT_MAX_BUF_LENGTH,
521 + GFP_KERNEL);
522 + if (!ar->ab->testmode.eventdata) {
523 + ret = -ENOMEM;
524 + goto err;
525 + }
526 +
527 + ar->state = ATH11K_STATE_FTM;
528 + ar->ftm_msgref = 0;
529 +
530 + mutex_unlock(&ar->conf_mutex);
531 +
532 + ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, "cmd start\n");
533 + return 0;
534 +
535 +err:
536 + mutex_unlock(&ar->conf_mutex);
537 + return ret;
538 +}
539 +
540 static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[])
541 {
542 struct ath11k_pdev_wmi *wmi = ar->wmi;
543 @@ -63,11 +307,6 @@ static int ath11k_tm_cmd_wmi(struct ath1
544
545 mutex_lock(&ar->conf_mutex);
546
547 - if (ar->state != ATH11K_STATE_ON) {
548 - ret = -ENETDOWN;
549 - goto out;
550 - }
551 -
552 if (!tb[ATH11K_TM_ATTR_DATA]) {
553 ret = -EINVAL;
554 goto out;
555 @@ -80,11 +319,17 @@ static int ath11k_tm_cmd_wmi(struct ath1
556
557 buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
558 buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
559 + if (!buf_len) {
560 + ath11k_warn(ar->ab, "No data present in testmode wmi command\n");
561 + ret = -EINVAL;
562 + goto out;
563 + }
564 +
565 cmd_id = nla_get_u32(tb[ATH11K_TM_ATTR_WMI_CMDID]);
566
567 ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
568 - "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
569 - cmd_id, buf, buf_len);
570 + "cmd wmi cmd_id %d buf length %d\n",
571 + cmd_id, buf_len);
572
573 ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
574
575 @@ -111,6 +356,91 @@ out:
576 return ret;
577 }
578
579 +static int ath11k_tm_cmd_wmi_ftm(struct ath11k *ar, struct nlattr *tb[])
580 +{
581 + struct ath11k_pdev_wmi *wmi = ar->wmi;
582 + struct ath11k_base *ab = ar->ab;
583 + struct sk_buff *skb;
584 + u32 cmd_id, buf_len, hdr_info;
585 + int ret;
586 + void *buf;
587 + u8 segnumber = 0, seginfo;
588 + u16 chunk_len, total_bytes, num_segments;
589 + u8 *bufpos;
590 + struct wmi_ftm_cmd *ftm_cmd;
591 +
592 + set_bit(ATH11K_FLAG_FTM_SEGMENTED, &ab->dev_flags);
593 +
594 + mutex_lock(&ar->conf_mutex);
595 +
596 + if (ar->state != ATH11K_STATE_FTM) {
597 + ret = -ENETDOWN;
598 + goto out;
599 + }
600 +
601 + if (!tb[ATH11K_TM_ATTR_DATA]) {
602 + ret = -EINVAL;
603 + goto out;
604 + }
605 +
606 + buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
607 + buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
608 + cmd_id = WMI_PDEV_UTF_CMDID;
609 +
610 + ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
611 + "cmd wmi ftm cmd_id %d buffer length %d\n",
612 + cmd_id, buf_len);
613 + ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
614 +
615 + bufpos = buf;
616 + total_bytes = buf_len;
617 + num_segments = total_bytes / MAX_WMI_UTF_LEN;
618 +
619 + if (buf_len - (num_segments * MAX_WMI_UTF_LEN))
620 + num_segments++;
621 +
622 + while (buf_len) {
623 + chunk_len = min_t(u16, buf_len, MAX_WMI_UTF_LEN);
624 +
625 + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, (chunk_len +
626 + sizeof(struct wmi_ftm_cmd)));
627 + if (!skb) {
628 + ret = -ENOMEM;
629 + goto out;
630 + }
631 +
632 + ftm_cmd = (struct wmi_ftm_cmd *)skb->data;
633 + hdr_info = FIELD_PREP(WMI_TLV_TAG, WMI_TAG_ARRAY_BYTE) |
634 + FIELD_PREP(WMI_TLV_LEN, (chunk_len +
635 + sizeof(struct wmi_ftm_seg_hdr)));
636 + ftm_cmd->tlv_header = hdr_info;
637 + ftm_cmd->seg_hdr.len = total_bytes;
638 + ftm_cmd->seg_hdr.msgref = ar->ftm_msgref;
639 + seginfo = FIELD_PREP(ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS, num_segments) |
640 + FIELD_PREP(ATH11K_FTM_SEGHDR_CURRENT_SEQ, segnumber);
641 + ftm_cmd->seg_hdr.segmentinfo = seginfo;
642 + segnumber++;
643 +
644 + memcpy(&ftm_cmd->data, bufpos, chunk_len);
645 +
646 + ret = ath11k_wmi_cmd_send(wmi, skb, cmd_id);
647 + if (ret) {
648 + ath11k_warn(ar->ab, "failed to send wmi ftm command: %d\n", ret);
649 + goto out;
650 + }
651 +
652 + buf_len -= chunk_len;
653 + bufpos += chunk_len;
654 + }
655 +
656 + ar->ftm_msgref++;
657 + ret = 0;
658 +
659 +out:
660 + mutex_unlock(&ar->conf_mutex);
661 + return ret;
662 +}
663 +
664 int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
665 void *data, int len)
666 {
667 @@ -131,6 +461,10 @@ int ath11k_tm_cmd(struct ieee80211_hw *h
668 return ath11k_tm_cmd_get_version(ar, tb);
669 case ATH11K_TM_CMD_WMI:
670 return ath11k_tm_cmd_wmi(ar, tb);
671 + case ATH11K_TM_CMD_TESTMODE_START:
672 + return ath11k_tm_cmd_testmode_start(ar, tb);
673 + case ATH11K_TM_CMD_WMI_FTM:
674 + return ath11k_tm_cmd_wmi_ftm(ar, tb);
675 default:
676 return -EOPNOTSUPP;
677 }
678 --- a/drivers/net/wireless/ath/ath11k/testmode.h
679 +++ b/drivers/net/wireless/ath/ath11k/testmode.h
680 @@ -8,11 +8,17 @@
681
682 #ifdef CPTCFG_NL80211_TESTMODE
683
684 +void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id, struct sk_buff *skb);
685 int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
686 void *data, int len);
687
688 #else
689
690 +static inline void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id,
691 + struct sk_buff *skb)
692 +{
693 +}
694 +
695 static inline int ath11k_tm_cmd(struct ieee80211_hw *hw,
696 struct ieee80211_vif *vif,
697 void *data, int len)
698 --- a/drivers/net/wireless/ath/ath11k/testmode_i.h
699 +++ b/drivers/net/wireless/ath/ath11k/testmode_i.h
700 @@ -1,6 +1,7 @@
701 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
702 /*
703 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
704 + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
705 */
706
707 /* "API" level of the ath11k testmode interface. Bump it after every
708 @@ -11,9 +12,10 @@
709 /* Bump this after every _compatible_ interface change, for example
710 * addition of a new command or an attribute.
711 */
712 -#define ATH11K_TESTMODE_VERSION_MINOR 0
713 +#define ATH11K_TESTMODE_VERSION_MINOR 1
714
715 #define ATH11K_TM_DATA_MAX_LEN 5000
716 +#define ATH11K_FTM_EVENT_MAX_BUF_LENGTH 2048
717
718 enum ath11k_tm_attr {
719 __ATH11K_TM_ATTR_INVALID = 0,
720 @@ -47,4 +49,18 @@ enum ath11k_tm_cmd {
721 * ATH11K_TM_ATTR_DATA.
722 */
723 ATH11K_TM_CMD_WMI = 1,
724 +
725 + /* Boots the UTF firmware, the netdev interface must be down at the
726 + * time.
727 + */
728 + ATH11K_TM_CMD_TESTMODE_START = 2,
729 +
730 + /* The command used to transmit a FTM WMI command to the firmware
731 + * and the event to receive WMI events from the firmware. The data
732 + * received only contain the payload, need to add the tlv header
733 + * and send the cmd to firmware with command id WMI_PDEV_UTF_CMDID.
734 + * The data payload size could be large and the driver needs to
735 + * send segmented data to firmware.
736 + */
737 + ATH11K_TM_CMD_WMI_FTM = 3,
738 };
739 --- a/drivers/net/wireless/ath/ath11k/wmi.c
740 +++ b/drivers/net/wireless/ath/ath11k/wmi.c
741 @@ -1,7 +1,7 @@
742 // SPDX-License-Identifier: BSD-3-Clause-Clear
743 /*
744 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
745 - * Copyright (c) 2021, Qualcomm Innovation Center, Inc. All rights reserved.
746 + * Copyright (c) 2021, 2023 Qualcomm Innovation Center, Inc. All rights reserved.
747 */
748 #include <linux/skbuff.h>
749 #include <linux/ctype.h>
750 @@ -19,6 +19,7 @@
751 #include "mac.h"
752 #include "hw.h"
753 #include "peer.h"
754 +#include "testmode.h"
755
756 struct wmi_tlv_policy {
757 size_t min_len;
758 @@ -237,9 +238,8 @@ static int ath11k_wmi_tlv_parse(struct a
759 (void *)tb);
760 }
761
762 -static const void **
763 -ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
764 - size_t len, gfp_t gfp)
765 +const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
766 + size_t len, gfp_t gfp)
767 {
768 const void **tb;
769 int ret;
770 @@ -8628,6 +8628,9 @@ static void ath11k_wmi_tlv_op_rx(struct
771 case WMI_PDEV_CSA_SWITCH_COUNT_STATUS_EVENTID:
772 ath11k_wmi_pdev_csa_switch_count_status_event(ab, skb);
773 break;
774 + case WMI_PDEV_UTF_EVENTID:
775 + ath11k_tm_wmi_event(ab, id, skb);
776 + break;
777 case WMI_PDEV_TEMPERATURE_EVENTID:
778 ath11k_wmi_pdev_temperature_event(ab, skb);
779 break;
780 --- a/drivers/net/wireless/ath/ath11k/wmi.h
781 +++ b/drivers/net/wireless/ath/ath11k/wmi.h
782 @@ -1,6 +1,7 @@
783 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
784 /*
785 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
786 + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
787 */
788
789 #ifndef ATH11K_WMI_H
790 @@ -68,6 +69,7 @@ struct wmi_tlv {
791
792 #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1
793
794 +#define MAX_WMI_UTF_LEN 252
795 #define WMI_BA_MODE_BUFFER_SIZE_256 3
796 /*
797 * HW mode config type replicated from FW header
798 @@ -3564,6 +3566,24 @@ struct wmi_get_pdev_temperature_cmd {
799 u32 pdev_id;
800 } __packed;
801
802 +struct wmi_ftm_seg_hdr {
803 + u32 len;
804 + u32 msgref;
805 + u32 segmentinfo;
806 + u32 pdev_id;
807 +} __packed;
808 +
809 +struct wmi_ftm_cmd {
810 + u32 tlv_header;
811 + struct wmi_ftm_seg_hdr seg_hdr;
812 + u8 data[];
813 +} __packed;
814 +
815 +struct wmi_ftm_event_msg {
816 + struct wmi_ftm_seg_hdr seg_hdr;
817 + u8 data[];
818 +} __packed;
819 +
820 #define WMI_BEACON_TX_BUFFER_SIZE 512
821
822 #define WMI_EMA_TMPL_IDX_SHIFT 8
823 @@ -6300,6 +6320,8 @@ enum wmi_sta_keepalive_method {
824 #define WMI_STA_KEEPALIVE_INTERVAL_DEFAULT 30
825 #define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0
826
827 +const void **ath11k_wmi_tlv_parse_alloc(struct ath11k_base *ab, const void *ptr,
828 + size_t len, gfp_t gfp);
829 int ath11k_wmi_cmd_send(struct ath11k_pdev_wmi *wmi, struct sk_buff *skb,
830 u32 cmd_id);
831 struct sk_buff *ath11k_wmi_alloc_skb(struct ath11k_wmi_base *wmi_sc, u32 len);
832 --- a/drivers/net/wireless/ath/ath11k/wow.c
833 +++ b/drivers/net/wireless/ath/ath11k/wow.c
834 @@ -1,7 +1,7 @@
835 // SPDX-License-Identifier: BSD-3-Clause-Clear
836 /*
837 * Copyright (c) 2020 The Linux Foundation. All rights reserved.
838 - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
839 + * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
840 */
841
842 #include <linux/delay.h>
843 @@ -838,6 +838,7 @@ exit:
844 case ATH11K_STATE_RESTARTING:
845 case ATH11K_STATE_RESTARTED:
846 case ATH11K_STATE_WEDGED:
847 + case ATH11K_STATE_FTM:
848 ath11k_warn(ar->ab, "encountered unexpected device state %d on resume, cannot recover\n",
849 ar->state);
850 ret = -EIO;