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
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.
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
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.
22 In case of unsegmented UTF event from firmware, driver notifies the
23 data to the user application as it comes. Applications handles
26 Command to boot in ftm mode:
28 insmod ath11k ftm_mode=1
30 Tested-on: IPQ8074 hw2.0 AHB WLAN.HK.2.7.0.1-01744-QCAHKSWPL_SILICONZ-1
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
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(-)
53 --- a/drivers/net/wireless/ath/ath11k/ahb.c
54 +++ b/drivers/net/wireless/ath/ath11k/ahb.c
56 // SPDX-License-Identifier: BSD-3-Clause-Clear
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.
63 #include <linux/module.h>
64 @@ -1155,6 +1155,7 @@ static int ath11k_ahb_probe(struct platf
65 ab->hif.ops = hif_ops;
68 + ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
69 platform_set_drvdata(pdev, ab);
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
75 // SPDX-License-Identifier: BSD-3-Clause-Clear
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.
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)");
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");
91 static const struct ath11k_hw_params ath11k_hw_params[] = {
93 .hw_rev = ATH11K_HW_IPQ8074,
94 @@ -1381,6 +1385,11 @@ static int ath11k_core_soc_create(struct
98 + if (ath11k_ftm_mode) {
99 + ab->fw_mode = ATH11K_FIRMWARE_MODE_FTM;
100 + ath11k_info(ab, "Booting in factory test mode\n");
103 ret = ath11k_qmi_init_service(ab);
105 ath11k_err(ab, "failed to initialize qmi :%d\n", ret);
106 @@ -1607,7 +1616,7 @@ int ath11k_core_qmi_firmware_ready(struc
110 - ret = ath11k_core_start_firmware(ab, ATH11K_FIRMWARE_MODE_NORMAL);
111 + ret = ath11k_core_start_firmware(ab, ab->fw_mode);
113 ath11k_err(ab, "failed to start firmware: %d\n", 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];
119 - if (!ar || ar->state == ATH11K_STATE_OFF)
120 + if (!ar || ar->state == ATH11K_STATE_OFF ||
121 + ar->state == ATH11K_STATE_FTM)
124 ieee80211_stop_queues(ar->hw);
125 @@ -1841,7 +1851,12 @@ static void ath11k_core_post_reconfigure
127 "device is wedged, will not restart radio %d\n", i);
129 + case ATH11K_STATE_FTM:
130 + ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
131 + "fw mode reset done radio %d\n", i);
135 mutex_unlock(&ar->conf_mutex);
137 complete(&ab->driver_recovery);
138 --- a/drivers/net/wireless/ath/ath11k/core.h
139 +++ b/drivers/net/wireless/ath/ath11k/core.h
141 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
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.
148 #ifndef ATH11K_CORE_H
150 #define ATH11K_SMBIOS_BDF_EXT_MAGIC "BDF_"
152 extern unsigned int ath11k_frame_mode;
153 +extern bool ath11k_ftm_mode;
155 #define ATH11K_SCAN_TIMEOUT_HZ (20 * HZ)
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,
164 enum ath11k_monitor_flags {
165 @@ -530,6 +532,7 @@ enum ath11k_state {
166 ATH11K_STATE_RESTARTING,
167 ATH11K_STATE_RESTARTED,
170 /* Add other states as required */
173 @@ -709,6 +712,8 @@ struct ath11k {
177 + struct completion fw_mode_reset;
179 #ifdef CPTCFG_ATH11K_DEBUGFS
180 struct ath11k_debug debug;
182 @@ -838,6 +843,7 @@ struct ath11k_msi_config {
183 /* Master structure to hold the hw data which may be used in core module */
185 enum ath11k_hw_rev hw_rev;
186 + enum ath11k_firmware_mode fw_mode;
187 struct platform_device *pdev;
189 struct ath11k_qmi qmi;
190 @@ -978,6 +984,14 @@ struct ath11k_base {
191 const struct ath11k_pci_ops *ops;
194 +#ifdef CPTCFG_NL80211_TESTMODE
203 u8 drv_priv[] __aligned(sizeof(void *));
205 --- a/drivers/net/wireless/ath/ath11k/debug.h
206 +++ b/drivers/net/wireless/ath/ath11k/debug.h
208 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
210 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
211 + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
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
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];
225 + pdev = rcu_dereference(ab->pdevs_active[i]);
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;
233 + if (ath11k_ftm_mode) {
234 + ath11k_warn(ab, "mac operations not supported in factory test mode\n");
235 + return -EOPNOTSUPP;
238 ath11k_mac_drain_tx(ar);
239 mutex_lock(&ar->conf_mutex);
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:
249 --- a/drivers/net/wireless/ath/ath11k/pci.c
250 +++ b/drivers/net/wireless/ath/ath11k/pci.c
252 // SPDX-License-Identifier: BSD-3-Clause-Clear
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.
259 #include <linux/module.h>
260 @@ -745,6 +745,7 @@ static int ath11k_pci_probe(struct pci_d
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);
268 --- a/drivers/net/wireless/ath/ath11k/testmode.c
269 +++ b/drivers/net/wireless/ath/ath11k/testmode.c
272 #include "testmode_i.h"
274 +#define ATH11K_FTM_SEGHDR_CURRENT_SEQ GENMASK(3, 0)
275 +#define ATH11K_FTM_SEGHDR_TOTAL_SEGMENTS GENMASK(7, 4)
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 },
284 +static struct ath11k *ath11k_tm_get_ar(struct ath11k_base *ab)
286 + struct ath11k_pdev *pdev;
287 + struct ath11k *ar = NULL;
290 + for (i = 0; i < ab->num_radios; i++) {
291 + pdev = &ab->pdevs[i];
294 + if (ar && ar->state == ATH11K_STATE_FTM)
301 +/* This function handles unsegmented events. Data in various events are aggregated
302 + * in application layer, this event is unsegmented from host perspective.
304 +static void ath11k_tm_wmi_event_unsegmented(struct ath11k_base *ab, u32 cmd_id,
305 + struct sk_buff *skb)
307 + struct sk_buff *nl_skb;
310 + ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
311 + "event wmi cmd_id %d skb length %d\n",
313 + ath11k_dbg_dump(ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
315 + ar = ath11k_tm_get_ar(ab);
317 + ath11k_warn(ab, "testmode event not handled due to invalid pdev\n");
321 + spin_lock_bh(&ar->data_lock);
323 + nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
324 + 2 * nla_total_size(sizeof(u32)) +
325 + nla_total_size(skb->len),
329 + "failed to allocate skb for unsegmented testmode wmi event\n");
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");
341 + cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
342 + spin_unlock_bh(&ar->data_lock);
346 + spin_unlock_bh(&ar->data_lock);
347 + ath11k_warn(ab, "Failed to send testmode event to higher layers\n");
350 +/* This function handles segmented events. Data of various events received
351 + * from firmware is aggregated and sent to application layer
353 +static int ath11k_tm_process_event(struct ath11k_base *ab, u32 cmd_id,
354 + const struct wmi_ftm_event_msg *ftm_msg,
357 + struct sk_buff *nl_skb;
362 + u8 total_segments, current_seq;
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);
372 + if (pdev_id >= ab->num_radios) {
373 + ath11k_warn(ab, "testmode event not handled due to invalid pdev id: %d\n",
378 + ar = ab->pdevs[pdev_id].ar;
380 + ath11k_warn(ab, "testmode event not handled due to absence of pdev\n");
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;
391 + spin_lock_bh(&ar->data_lock);
393 + if (current_seq == 0) {
394 + ab->testmode.expected_seq = 0;
395 + ab->testmode.data_pos = 0;
398 + data_pos = ab->testmode.data_pos;
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);
407 + memcpy(&ab->testmode.eventdata[data_pos], buf_pos, datalen);
408 + data_pos += datalen;
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);
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),
427 + "failed to allocate skb for segmented testmode wmi event\n");
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");
443 + cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
446 + spin_unlock_bh(&ar->data_lock);
450 +static void ath11k_tm_wmi_event_segmented(struct ath11k_base *ab, u32 cmd_id,
451 + struct sk_buff *skb)
454 + const struct wmi_ftm_event_msg *ev;
458 + tb = ath11k_wmi_tlv_parse_alloc(ab, skb->data, skb->len, GFP_ATOMIC);
461 + ath11k_warn(ab, "failed to parse ftm event tlv: %d\n", ret);
465 + ev = tb[WMI_TAG_ARRAY_BYTE];
467 + ath11k_warn(ab, "failed to fetch ftm msg\n");
472 + length = skb->len - TLV_HDR_SIZE;
473 + ret = ath11k_tm_process_event(ab, cmd_id, ev, length);
475 + ath11k_warn(ab, "Failed to process ftm event\n");
480 +void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id, struct sk_buff *skb)
482 + if (test_bit(ATH11K_FLAG_FTM_SEGMENTED, &ab->dev_flags))
483 + ath11k_tm_wmi_event_segmented(ab, cmd_id, skb);
485 + ath11k_tm_wmi_event_unsegmented(ab, cmd_id, skb);
488 static int ath11k_tm_cmd_get_version(struct ath11k *ar, struct nlattr *tb[])
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);
499 @@ -53,6 +260,43 @@ static int ath11k_tm_cmd_get_version(str
500 return cfg80211_testmode_reply(skb);
503 +static int ath11k_tm_cmd_testmode_start(struct ath11k *ar, struct nlattr *tb[])
507 + mutex_lock(&ar->conf_mutex);
509 + if (ar->state == ATH11K_STATE_FTM) {
514 + /* start utf only when the driver is not in use */
515 + if (ar->state != ATH11K_STATE_OFF) {
520 + ar->ab->testmode.eventdata = kzalloc(ATH11K_FTM_EVENT_MAX_BUF_LENGTH,
522 + if (!ar->ab->testmode.eventdata) {
527 + ar->state = ATH11K_STATE_FTM;
528 + ar->ftm_msgref = 0;
530 + mutex_unlock(&ar->conf_mutex);
532 + ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, "cmd start\n");
536 + mutex_unlock(&ar->conf_mutex);
540 static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[])
542 struct ath11k_pdev_wmi *wmi = ar->wmi;
543 @@ -63,11 +307,6 @@ static int ath11k_tm_cmd_wmi(struct ath1
545 mutex_lock(&ar->conf_mutex);
547 - if (ar->state != ATH11K_STATE_ON) {
552 if (!tb[ATH11K_TM_ATTR_DATA]) {
555 @@ -80,11 +319,17 @@ static int ath11k_tm_cmd_wmi(struct ath1
557 buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
558 buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
560 + ath11k_warn(ar->ab, "No data present in testmode wmi command\n");
565 cmd_id = nla_get_u32(tb[ATH11K_TM_ATTR_WMI_CMDID]);
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",
573 ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
575 @@ -111,6 +356,91 @@ out:
579 +static int ath11k_tm_cmd_wmi_ftm(struct ath11k *ar, struct nlattr *tb[])
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;
587 + u8 segnumber = 0, seginfo;
588 + u16 chunk_len, total_bytes, num_segments;
590 + struct wmi_ftm_cmd *ftm_cmd;
592 + set_bit(ATH11K_FLAG_FTM_SEGMENTED, &ab->dev_flags);
594 + mutex_lock(&ar->conf_mutex);
596 + if (ar->state != ATH11K_STATE_FTM) {
601 + if (!tb[ATH11K_TM_ATTR_DATA]) {
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;
610 + ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
611 + "cmd wmi ftm cmd_id %d buffer length %d\n",
613 + ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
616 + total_bytes = buf_len;
617 + num_segments = total_bytes / MAX_WMI_UTF_LEN;
619 + if (buf_len - (num_segments * MAX_WMI_UTF_LEN))
623 + chunk_len = min_t(u16, buf_len, MAX_WMI_UTF_LEN);
625 + skb = ath11k_wmi_alloc_skb(wmi->wmi_ab, (chunk_len +
626 + sizeof(struct wmi_ftm_cmd)));
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;
644 + memcpy(&ftm_cmd->data, bufpos, chunk_len);
646 + ret = ath11k_wmi_cmd_send(wmi, skb, cmd_id);
648 + ath11k_warn(ar->ab, "failed to send wmi ftm command: %d\n", ret);
652 + buf_len -= chunk_len;
653 + bufpos += chunk_len;
660 + mutex_unlock(&ar->conf_mutex);
664 int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
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);
678 --- a/drivers/net/wireless/ath/ath11k/testmode.h
679 +++ b/drivers/net/wireless/ath/ath11k/testmode.h
682 #ifdef CPTCFG_NL80211_TESTMODE
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);
690 +static inline void ath11k_tm_wmi_event(struct ath11k_base *ab, u32 cmd_id,
691 + struct sk_buff *skb)
695 static inline int ath11k_tm_cmd(struct ieee80211_hw *hw,
696 struct ieee80211_vif *vif,
698 --- a/drivers/net/wireless/ath/ath11k/testmode_i.h
699 +++ b/drivers/net/wireless/ath/ath11k/testmode_i.h
701 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
703 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
704 + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
707 /* "API" level of the ath11k testmode interface. Bump it after every
709 /* Bump this after every _compatible_ interface change, for example
710 * addition of a new command or an attribute.
712 -#define ATH11K_TESTMODE_VERSION_MINOR 0
713 +#define ATH11K_TESTMODE_VERSION_MINOR 1
715 #define ATH11K_TM_DATA_MAX_LEN 5000
716 +#define ATH11K_FTM_EVENT_MAX_BUF_LENGTH 2048
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.
723 ATH11K_TM_CMD_WMI = 1,
725 + /* Boots the UTF firmware, the netdev interface must be down at the
728 + ATH11K_TM_CMD_TESTMODE_START = 2,
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.
737 + ATH11K_TM_CMD_WMI_FTM = 3,
739 --- a/drivers/net/wireless/ath/ath11k/wmi.c
740 +++ b/drivers/net/wireless/ath/ath11k/wmi.c
742 // SPDX-License-Identifier: BSD-3-Clause-Clear
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.
748 #include <linux/skbuff.h>
749 #include <linux/ctype.h>
754 +#include "testmode.h"
756 struct wmi_tlv_policy {
758 @@ -237,9 +238,8 @@ static int ath11k_wmi_tlv_parse(struct a
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)
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);
774 + case WMI_PDEV_UTF_EVENTID:
775 + ath11k_tm_wmi_event(ab, id, skb);
777 case WMI_PDEV_TEMPERATURE_EVENTID:
778 ath11k_wmi_pdev_temperature_event(ab, skb);
780 --- a/drivers/net/wireless/ath/ath11k/wmi.h
781 +++ b/drivers/net/wireless/ath/ath11k/wmi.h
783 /* SPDX-License-Identifier: BSD-3-Clause-Clear */
785 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
786 + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
790 @@ -68,6 +69,7 @@ struct wmi_tlv {
792 #define WMI_APPEND_TO_EXISTING_CHAN_LIST_FLAG 1
794 +#define MAX_WMI_UTF_LEN 252
795 #define WMI_BA_MODE_BUFFER_SIZE_256 3
797 * HW mode config type replicated from FW header
798 @@ -3564,6 +3566,24 @@ struct wmi_get_pdev_temperature_cmd {
802 +struct wmi_ftm_seg_hdr {
809 +struct wmi_ftm_cmd {
811 + struct wmi_ftm_seg_hdr seg_hdr;
815 +struct wmi_ftm_event_msg {
816 + struct wmi_ftm_seg_hdr seg_hdr;
820 #define WMI_BEACON_TX_BUFFER_SIZE 512
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
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,
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
835 // SPDX-License-Identifier: BSD-3-Clause-Clear
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.
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",