mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-12-19 18:31:33 +00:00
585 lines
16 KiB
Diff
585 lines
16 KiB
Diff
--- a/drivers/net/wireless/ath/ath11k/ahb.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/ahb.c
|
|
@@ -693,6 +693,7 @@ static int ath11k_ahb_probe(struct platf
|
|
ab->hif.ops = &ath11k_ahb_hif_ops;
|
|
ab->pdev = pdev;
|
|
ab->hw_rev = (enum ath11k_hw_rev)of_id->data;
|
|
+ ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
|
|
ab->mem = mem;
|
|
ab->mem_len = resource_size(mem_res);
|
|
platform_set_drvdata(pdev, ab);
|
|
--- a/drivers/net/wireless/ath/ath11k/core.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.c
|
|
@@ -837,7 +837,7 @@ int ath11k_core_qmi_firmware_ready(struc
|
|
set_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags);
|
|
|
|
mutex_lock(&ab->core_lock);
|
|
- ret = ath11k_core_start(ab, ATH11K_FIRMWARE_MODE_NORMAL);
|
|
+ ret = ath11k_core_start(ab, ab->fw_mode);
|
|
if (ret) {
|
|
ath11k_err(ab, "failed to start core: %d\n", ret);
|
|
goto err_dp_free;
|
|
@@ -934,7 +934,8 @@ static void ath11k_core_restart(struct w
|
|
for (i = 0; i < ab->num_radios; i++) {
|
|
pdev = &ab->pdevs[i];
|
|
ar = pdev->ar;
|
|
- if (!ar || ar->state == ATH11K_STATE_OFF)
|
|
+ if (!ar || ar->state == ATH11K_STATE_OFF ||
|
|
+ ar->state == ATH11K_STATE_TM)
|
|
continue;
|
|
|
|
ieee80211_stop_queues(ar->hw);
|
|
@@ -992,6 +993,12 @@ static void ath11k_core_restart(struct w
|
|
ath11k_warn(ab,
|
|
"device is wedged, will not restart radio %d\n", i);
|
|
break;
|
|
+ case ATH11K_STATE_TM:
|
|
+ ath11k_warn(ab, "fw mode reset done radio %d\n", i);
|
|
+ if (test_bit(ATH11K_FLAG_FW_RESTART_FOR_HOST, &ar->ab->dev_flags)) {
|
|
+ complete(&ar->fw_mode_reset);
|
|
+ }
|
|
+ break;
|
|
}
|
|
mutex_unlock(&ar->conf_mutex);
|
|
}
|
|
--- a/drivers/net/wireless/ath/ath11k/core.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/core.h
|
|
@@ -189,6 +189,7 @@ enum ath11k_dev_flags {
|
|
ATH11K_FLAG_REGISTERED,
|
|
ATH11K_FLAG_QMI_FAIL,
|
|
ATH11K_FLAG_HTC_SUSPEND_COMPLETE,
|
|
+ ATH11K_FLAG_FW_RESTART_FOR_HOST,
|
|
};
|
|
|
|
enum ath11k_monitor_flags {
|
|
@@ -386,12 +387,19 @@ enum ath11k_state {
|
|
ATH11K_STATE_RESTARTING,
|
|
ATH11K_STATE_RESTARTED,
|
|
ATH11K_STATE_WEDGED,
|
|
+ ATH11K_STATE_TM,
|
|
/* Add other states as required */
|
|
};
|
|
|
|
/* Antenna noise floor */
|
|
#define ATH11K_DEFAULT_NOISE_FLOOR -95
|
|
|
|
+struct ath11k_ftm_event_obj {
|
|
+ u32 data_pos;
|
|
+ u32 expected_seq;
|
|
+ u8 *eventdata;
|
|
+};
|
|
+
|
|
struct ath11k_fw_stats {
|
|
struct dentry *debugfs_fwstats;
|
|
u32 pdev_id;
|
|
@@ -570,6 +578,7 @@ struct ath11k {
|
|
#endif
|
|
bool dfs_block_radar_events;
|
|
struct ath11k_thermal thermal;
|
|
+ struct completion fw_mode_reset;
|
|
};
|
|
|
|
struct ath11k_band_cap {
|
|
@@ -661,6 +670,7 @@ struct ath11k_soc_dp_stats {
|
|
/* Master structure to hold the hw data which may be used in core module */
|
|
struct ath11k_base {
|
|
enum ath11k_hw_rev hw_rev;
|
|
+ enum ath11k_firmware_mode fw_mode;
|
|
struct platform_device *pdev;
|
|
struct device *dev;
|
|
struct ath11k_qmi qmi;
|
|
@@ -741,6 +751,7 @@ struct ath11k_base {
|
|
/* protected by data_lock */
|
|
u32 fw_crash_counter;
|
|
} stats;
|
|
+ struct ath11k_ftm_event_obj ftm_event_obj;
|
|
u32 pktlog_defs_checksum;
|
|
|
|
struct ath11k_dbring_cap *db_caps;
|
|
--- a/drivers/net/wireless/ath/ath11k/mac.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/mac.c
|
|
@@ -528,7 +528,10 @@ struct ath11k *ath11k_mac_get_ar_by_pdev
|
|
return NULL;
|
|
|
|
for (i = 0; i < ab->num_radios; i++) {
|
|
- pdev = rcu_dereference(ab->pdevs_active[i]);
|
|
+ if (ab->fw_mode == ATH11K_FIRMWARE_MODE_FTM)
|
|
+ pdev = &ab->pdevs[i];
|
|
+ else
|
|
+ pdev = rcu_dereference(ab->pdevs_active[i]);
|
|
|
|
if (pdev && pdev->pdev_id == pdev_id)
|
|
return (pdev->ar ? pdev->ar : NULL);
|
|
@@ -4326,6 +4329,7 @@ static int ath11k_mac_op_start(struct ie
|
|
case ATH11K_STATE_RESTARTED:
|
|
case ATH11K_STATE_WEDGED:
|
|
case ATH11K_STATE_ON:
|
|
+ case ATH11K_STATE_TM:
|
|
WARN_ON(1);
|
|
ret = -EINVAL;
|
|
goto err;
|
|
--- a/drivers/net/wireless/ath/ath11k/testmode.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/testmode.c
|
|
@@ -9,6 +9,7 @@
|
|
#include "wmi.h"
|
|
#include "hw.h"
|
|
#include "core.h"
|
|
+#include "hif.h"
|
|
#include "testmode_i.h"
|
|
|
|
static const struct nla_policy ath11k_tm_policy[ATH11K_TM_ATTR_MAX + 1] = {
|
|
@@ -23,34 +24,89 @@ static const struct nla_policy ath11k_tm
|
|
/* Returns true if callee consumes the skb and the skb should be discarded.
|
|
* Returns false if skb is not used. Does not sleep.
|
|
*/
|
|
-bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb)
|
|
+bool ath11k_tm_event_wmi(struct ath11k_base *ab, u32 cmd_id,
|
|
+ struct sk_buff *skb)
|
|
{
|
|
struct sk_buff *nl_skb;
|
|
bool consumed;
|
|
- int ret;
|
|
+ int ret, i;
|
|
+ struct ath11k *ar;
|
|
+ struct ath11k_pdev *pdev;
|
|
+ u8 *buf_pos;
|
|
+ u16 datalen;
|
|
+ struct seg_hdr_info *seghdr_info;
|
|
+ u8 total_segments, current_seq;
|
|
+ u32 data_pos;
|
|
|
|
- ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
|
|
+ ath11k_dbg(ab, ATH11K_DBG_TESTMODE,
|
|
"testmode event wmi cmd_id %d skb %pK skb->len %d\n",
|
|
cmd_id, skb, skb->len);
|
|
|
|
- ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
|
|
+ ath11k_dbg_dump(ab, ATH11K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
|
|
+
|
|
+ for (i = 0; i < ab->num_radios; i++) {
|
|
+ pdev = &ab->pdevs[i];
|
|
+ ar = pdev->ar;
|
|
+ if (ar && ar->state == ATH11K_STATE_TM)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (i >= ab->num_radios) {
|
|
+ ath11k_dbg(ab, ATH11K_DBG_TESTMODE, "testmode event not handled\n");
|
|
+ return false;
|
|
+ }
|
|
|
|
spin_lock_bh(&ar->data_lock);
|
|
|
|
consumed = true;
|
|
|
|
+ seghdr_info = (struct seg_hdr_info *)(skb->data + WMI_TLV_HDR_SIZE);
|
|
+ current_seq = (seghdr_info->segmentinfo & 0xF);
|
|
+ total_segments = (seghdr_info->segmentinfo >> 4) & 0xF;
|
|
+
|
|
+ datalen = skb->len - (sizeof(struct seg_hdr_info) + WMI_TLV_HDR_SIZE);
|
|
+ buf_pos = skb->data + (sizeof(struct seg_hdr_info) + WMI_TLV_HDR_SIZE);
|
|
+
|
|
+ if (current_seq == 0) {
|
|
+ ab->ftm_event_obj.expected_seq = 0;
|
|
+ ab->ftm_event_obj.data_pos = 0;
|
|
+ }
|
|
+ data_pos = ab->ftm_event_obj.data_pos;
|
|
+
|
|
+ if ((data_pos + datalen) > ATH11K_FTM_EVENT_MAX_BUF_LENGTH) {
|
|
+ ath11k_warn(ab,
|
|
+ "Invalid event length date_pos[%d] datalen[%d]\n",
|
|
+ data_pos, datalen);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ memcpy(&ab->ftm_event_obj.eventdata[data_pos], buf_pos, datalen);
|
|
+ data_pos += datalen;
|
|
+
|
|
+ if (++ab->ftm_event_obj.expected_seq != total_segments) {
|
|
+ ab->ftm_event_obj.data_pos = data_pos;
|
|
+ ath11k_warn(ab,
|
|
+ "parial data received current_seq[%d], total_seg[%d]\n",
|
|
+ current_seq, total_segments);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ath11k_warn(ab,
|
|
+ "total data length[%d] = [%d]\n",
|
|
+ data_pos, seghdr_info->len);
|
|
+
|
|
nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
|
|
- 2 * sizeof(u32) + skb->len,
|
|
+ 2 * sizeof(u32) + data_pos,
|
|
GFP_ATOMIC);
|
|
if (!nl_skb) {
|
|
- ath11k_warn(ar->ab,
|
|
+ ath11k_warn(ab,
|
|
"failed to allocate skb for testmode wmi event\n");
|
|
goto out;
|
|
}
|
|
|
|
- ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI);
|
|
+ ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_CMD, ATH11K_TM_CMD_WMI_FTM);
|
|
if (ret) {
|
|
- ath11k_warn(ar->ab,
|
|
+ ath11k_warn(ab,
|
|
"failed to put testmode wmi event cmd attribute: %d\n",
|
|
ret);
|
|
kfree_skb(nl_skb);
|
|
@@ -59,16 +115,17 @@ bool ath11k_tm_event_wmi(struct ath11k *
|
|
|
|
ret = nla_put_u32(nl_skb, ATH11K_TM_ATTR_WMI_CMDID, cmd_id);
|
|
if (ret) {
|
|
- ath11k_warn(ar->ab,
|
|
+ ath11k_warn(ab,
|
|
"failed to put testmode wmi even cmd_id: %d\n",
|
|
ret);
|
|
kfree_skb(nl_skb);
|
|
goto out;
|
|
}
|
|
|
|
- ret = nla_put(nl_skb, ATH11K_TM_ATTR_DATA, skb->len, skb->data);
|
|
+ ret = nla_put(nl_skb, ATH11K_TM_ATTR_DATA, data_pos,
|
|
+ &ab->ftm_event_obj.eventdata[0]);
|
|
if (ret) {
|
|
- ath11k_warn(ar->ab,
|
|
+ ath11k_warn(ab,
|
|
"failed to copy skb to testmode wmi event: %d\n",
|
|
ret);
|
|
kfree_skb(nl_skb);
|
|
@@ -115,6 +172,107 @@ static int ath11k_tm_cmd_get_version(str
|
|
return cfg80211_testmode_reply(skb);
|
|
}
|
|
|
|
+static int ath11k_tm_cmd_testmode_start(struct ath11k *ar, struct nlattr *tb[])
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, " enter testmode cmd fw start\n");
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+
|
|
+ if (ar->state == ATH11K_STATE_TM) {
|
|
+ ret = -EALREADY;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ /* start utf only when the driver is not in use */
|
|
+ if (ar->state != ATH11K_STATE_OFF) {
|
|
+ ret = -EBUSY;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ /* Firmware already running in FTM mode */
|
|
+ if (ar->ab->fw_mode == ATH11K_FIRMWARE_MODE_FTM) {
|
|
+ ar->state = ATH11K_STATE_TM;
|
|
+ ret = 0;
|
|
+ goto err;
|
|
+ }
|
|
+ ar->ab->ftm_event_obj.eventdata = kzalloc(ATH11K_FTM_EVENT_MAX_BUF_LENGTH,
|
|
+ GFP_KERNEL);
|
|
+ if (!ar->ab->ftm_event_obj.eventdata) {
|
|
+ ret = -ENOMEM;
|
|
+ goto err;
|
|
+ }
|
|
+
|
|
+ ar->ab->fw_mode = ATH11K_FIRMWARE_MODE_FTM;
|
|
+ ar->state = ATH11K_STATE_TM;
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ init_completion(&ar->fw_mode_reset);
|
|
+
|
|
+ set_bit(ATH11K_FLAG_FW_RESTART_FOR_HOST, &ar->ab->dev_flags);
|
|
+ ath11k_hif_power_down(ar->ab);
|
|
+ ath11k_hif_power_up(ar->ab);
|
|
+
|
|
+ if (!wait_for_completion_timeout(&ar->fw_mode_reset,
|
|
+ FTM_MODE_RESET_TIMEOUT_HZ)) {
|
|
+ clear_bit(ATH11K_FLAG_FW_RESTART_FOR_HOST, &ar->ab->dev_flags);
|
|
+ ath11k_warn(ar->ab, "failed to restat the core in ftm mode\n");
|
|
+ return 0;
|
|
+ }
|
|
+ clear_bit(ATH11K_FLAG_FW_RESTART_FOR_HOST, &ar->ab->dev_flags);
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, " enter testmode cmd started\n");
|
|
+
|
|
+ return 0;
|
|
+err:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ath11k_tm_cmd_testmode_stop(struct ath11k *ar, struct nlattr *tb[])
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, "Enter testmode cmd fw stop\n");
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+
|
|
+ if (ar->state != ATH11K_STATE_TM) {
|
|
+ ret = -ENETDOWN;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ /* Firmware not running in FTM mode */
|
|
+ if (ar->ab->fw_mode != ATH11K_FIRMWARE_MODE_FTM) {
|
|
+ ar->state = ATH11K_STATE_OFF;
|
|
+ ret = 0;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ ar->ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ init_completion(&ar->fw_mode_reset);
|
|
+
|
|
+ set_bit(ATH11K_FLAG_FW_RESTART_FOR_HOST, &ar->ab->dev_flags);
|
|
+ ath11k_hif_power_down(ar->ab);
|
|
+ ath11k_hif_power_up(ar->ab);
|
|
+
|
|
+ if (!wait_for_completion_timeout(&ar->fw_mode_reset,
|
|
+ FTM_MODE_RESET_TIMEOUT_HZ)) {
|
|
+ clear_bit(ATH11K_FLAG_FW_RESTART_FOR_HOST, &ar->ab->dev_flags);
|
|
+ ath11k_warn(ar->ab, "failed to restat the core in ftm mode\n");
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ ar->state = ATH11K_STATE_OFF;
|
|
+ clear_bit(ATH11K_FLAG_FW_RESTART_FOR_HOST, &ar->ab->dev_flags);
|
|
+ kfree(ar->ab->ftm_event_obj.eventdata);
|
|
+ ath11k_info(ar->ab, "UTF firmware stopped\n");
|
|
+ return 0;
|
|
+out:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
static int ath11k_tm_cmd_wmi(struct ath11k *ar, struct nlattr *tb[])
|
|
{
|
|
struct ath11k_pdev_wmi *wmi = ar->wmi;
|
|
@@ -173,8 +331,95 @@ out:
|
|
return ret;
|
|
}
|
|
|
|
+static int ath11k_tm_cmd_process_ftm(struct ath11k *ar, struct nlattr *tb[])
|
|
+{
|
|
+ struct ath11k_pdev_wmi *wmi = ar->wmi;
|
|
+ struct sk_buff *skb;
|
|
+ u32 cmd_id, buf_len;
|
|
+ int ret;
|
|
+ void *buf;
|
|
+ u8 *cmd;
|
|
+ /* if buf_len is 0 no data is sent, return error */
|
|
+ static u8 msgref = 1;
|
|
+ u8 segnumber = 0, seginfo;
|
|
+ u16 chunk_len, total_bytes, num_segments;
|
|
+ u8 *bufpos;
|
|
+ struct seg_hdr_info seg_hdr;
|
|
+
|
|
+ mutex_lock(&ar->conf_mutex);
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE, "ar->state %d\n", ar->state);
|
|
+
|
|
+ if (ar->state != ATH11K_STATE_TM) {
|
|
+ ret = -ENETDOWN;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if (!tb[ATH11K_TM_ATTR_DATA]) {
|
|
+ ret = -EINVAL;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ buf = nla_data(tb[ATH11K_TM_ATTR_DATA]);
|
|
+ buf_len = nla_len(tb[ATH11K_TM_ATTR_DATA]);
|
|
+ cmd_id = WMI_PDEV_UTF_CMDID;
|
|
+
|
|
+ ath11k_dbg(ar->ab, ATH11K_DBG_TESTMODE,
|
|
+ "testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
|
|
+ cmd_id, buf, buf_len);
|
|
+ ath11k_dbg_dump(ar->ab, ATH11K_DBG_TESTMODE, NULL, "", buf, buf_len);
|
|
+
|
|
+ bufpos = buf;
|
|
+ total_bytes = buf_len;
|
|
+ num_segments = total_bytes / MAX_WMI_UTF_LEN;
|
|
+
|
|
+ if (buf_len - (num_segments * MAX_WMI_UTF_LEN))
|
|
+ num_segments++;
|
|
+
|
|
+ while (buf_len) {
|
|
+ if (buf_len > MAX_WMI_UTF_LEN)
|
|
+ chunk_len = MAX_WMI_UTF_LEN; /* MAX message */
|
|
+ else
|
|
+ chunk_len = buf_len;
|
|
+
|
|
+ skb = ath11k_wmi_alloc_skb(wmi->wmi_ab,
|
|
+ (chunk_len + sizeof(seg_hdr) +
|
|
+ WMI_TLV_HDR_SIZE));
|
|
+ if (!skb) {
|
|
+ ret = -ENOMEM;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ seg_hdr.len = total_bytes;
|
|
+ seg_hdr.msgref = msgref;
|
|
+ seginfo = ((num_segments << 4) & 0xF0) | (segnumber & 0xF);
|
|
+ seg_hdr.segmentinfo = seginfo;
|
|
+ seg_hdr.pad = 0;
|
|
+ segnumber++;
|
|
+
|
|
+ cmd = (uint8_t *)skb->data;
|
|
+ WMITLV_SET_HDR(cmd, WMITLV_TAG_BYTE, (chunk_len + sizeof(seg_hdr)));
|
|
+ cmd += WMI_TLV_HDR_SIZE;
|
|
+ memcpy(cmd, &seg_hdr, sizeof(seg_hdr));
|
|
+ memcpy(&cmd[sizeof(seg_hdr)], bufpos, chunk_len);
|
|
+
|
|
+ ret = ath11k_wmi_cmd_send(wmi, skb, cmd_id);
|
|
+ if (ret) {
|
|
+ ath11k_warn(ar->ab, "ftm wmi command fail: %d\n", ret);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ buf_len -= chunk_len;
|
|
+ bufpos += chunk_len;
|
|
+ }
|
|
+ ret = 0;
|
|
+out:
|
|
+ mutex_unlock(&ar->conf_mutex);
|
|
+ return ret;
|
|
+}
|
|
+
|
|
int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|
- void *data, int len)
|
|
+ void *data, int len)
|
|
{
|
|
struct ath11k *ar = hw->priv;
|
|
struct nlattr *tb[ATH11K_TM_ATTR_MAX + 1];
|
|
@@ -189,9 +434,15 @@ int ath11k_tm_cmd(struct ieee80211_hw *h
|
|
return -EINVAL;
|
|
|
|
switch (nla_get_u32(tb[ATH11K_TM_ATTR_CMD])) {
|
|
+ case ATH11K_TM_CMD_WMI_FTM:
|
|
+ return ath11k_tm_cmd_process_ftm(ar, tb);
|
|
+ case ATH11K_TM_CMD_TESTMODE_START:
|
|
+ return ath11k_tm_cmd_testmode_start(ar, tb);
|
|
+ case ATH11K_TM_CMD_TESTMODE_STOP:
|
|
+ return ath11k_tm_cmd_testmode_stop(ar, tb);
|
|
case ATH11K_TM_CMD_GET_VERSION:
|
|
return ath11k_tm_cmd_get_version(ar, tb);
|
|
- case ATH11K_TM_CMD_WMI:
|
|
+ case ATH11K_TM_CMD_WMI_FW_TEST:
|
|
return ath11k_tm_cmd_wmi(ar, tb);
|
|
default:
|
|
return -EOPNOTSUPP;
|
|
--- a/drivers/net/wireless/ath/ath11k/testmode.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/testmode.h
|
|
@@ -4,16 +4,33 @@
|
|
*/
|
|
|
|
#include "core.h"
|
|
+#include "ahb.h"
|
|
+
|
|
+#define MAX_WMI_UTF_LEN 252
|
|
+#define WMI_TLV_HDR_SIZE 4
|
|
+#define WMITLV_TAG_BYTE 17
|
|
+#define FTM_MODE_RESET_TIMEOUT_HZ (10 * HZ)
|
|
+#define WMITLV_SET_HDR(tlv_buf, tag, len) ({ \
|
|
+ (((u32 *)(tlv_buf))[0]) = (((tag) << 16) | ((len) & 0x0000FFFF)); \
|
|
+ })
|
|
+
|
|
+struct seg_hdr_info {
|
|
+ u32 len;
|
|
+ u32 msgref;
|
|
+ u32 segmentinfo;
|
|
+ u32 pad;
|
|
+};
|
|
|
|
#ifdef CPTCFG_NL80211_TESTMODE
|
|
|
|
-bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id, struct sk_buff *skb);
|
|
+bool ath11k_tm_event_wmi(struct ath11k_base *ab, u32 cmd_id,
|
|
+ struct sk_buff *skb);
|
|
int ath11k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|
void *data, int len);
|
|
|
|
#else
|
|
|
|
-static inline bool ath11k_tm_event_wmi(struct ath11k *ar, u32 cmd_id,
|
|
+static inline bool ath11k_tm_event_wmi(struct ath11k_base *ab, u32 cmd_id,
|
|
struct sk_buff *skb)
|
|
{
|
|
return false;
|
|
--- a/drivers/net/wireless/ath/ath11k/testmode_i.h
|
|
+++ b/drivers/net/wireless/ath/ath11k/testmode_i.h
|
|
@@ -14,6 +14,7 @@
|
|
#define ATH11K_TESTMODE_VERSION_MINOR 0
|
|
|
|
#define ATH11K_TM_DATA_MAX_LEN 5000
|
|
+#define ATH11K_FTM_EVENT_MAX_BUF_LENGTH 2048
|
|
|
|
enum ath11k_tm_attr {
|
|
__ATH11K_TM_ATTR_INVALID = 0,
|
|
@@ -40,11 +41,29 @@ enum ath11k_tm_cmd {
|
|
*/
|
|
ATH11K_TM_CMD_GET_VERSION = 0,
|
|
|
|
- /* The command used to transmit a WMI command to the firmware and
|
|
- * the event to receive WMI events from the firmware. Without
|
|
+ /* Boots the UTF firmware, the netdev interface must be down at the
|
|
+ * time.
|
|
+ */
|
|
+ ATH11K_TM_CMD_TESTMODE_START = 1,
|
|
+
|
|
+ /* Shuts down the UTF firmware and puts the driver back into OFF
|
|
+ * state.
|
|
+ */
|
|
+ ATH11K_TM_CMD_TESTMODE_STOP = 2,
|
|
+
|
|
+ /* The command used to transmit a FW test WMI command to the firmware
|
|
+ * and the event to receive WMI events from the firmware. Without
|
|
* struct wmi_cmd_hdr header, only the WMI payload. Command id is
|
|
* provided with ATH11K_TM_ATTR_WMI_CMDID and payload in
|
|
* ATH11K_TM_ATTR_DATA.
|
|
*/
|
|
- ATH11K_TM_CMD_WMI = 1,
|
|
+ ATH11K_TM_CMD_WMI_FW_TEST = 3,
|
|
+
|
|
+ /* The command used to transmit a FTM WMI command to the firmware
|
|
+ * and the event to receive WMI events from the firmware.The data
|
|
+ * received only contain the payload, Need to add the tlv
|
|
+ * header and send the cmd to fw with commandid WMI_PDEV_UTF_CMDID.
|
|
+ */
|
|
+ ATH11K_TM_CMD_WMI_FTM = 4,
|
|
+
|
|
};
|
|
--- a/drivers/net/wireless/ath/ath11k/wmi.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/wmi.c
|
|
@@ -18,6 +18,7 @@
|
|
#include "mac.h"
|
|
#include "hw.h"
|
|
#include "peer.h"
|
|
+#include "testmode.h"
|
|
|
|
struct wmi_tlv_policy {
|
|
size_t min_len;
|
|
@@ -7077,6 +7078,9 @@ static void ath11k_wmi_tlv_op_rx(struct
|
|
case WMI_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID:
|
|
ath11k_probe_resp_tx_status_event(ab, skb);
|
|
break;
|
|
+ case WMI_PDEV_UTF_EVENTID:
|
|
+ ath11k_tm_event_wmi(ab, id, skb);
|
|
+ break;
|
|
/* add Unsupported events here */
|
|
case WMI_TBTTOFFSET_EXT_UPDATE_EVENTID:
|
|
case WMI_PEER_OPER_MODE_CHANGE_EVENTID:
|
|
--- a/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
|
|
+++ b/drivers/net/wireless/ath/ath11k/debugfs_htt_stats.c
|
|
@@ -4469,7 +4469,8 @@ static int ath11k_open_htt_stats(struct
|
|
|
|
mutex_lock(&ar->conf_mutex);
|
|
|
|
- if (ar->state != ATH11K_STATE_ON) {
|
|
+ if (ar->state != ATH11K_STATE_ON &&
|
|
+ ar->ab->fw_mode != ATH11K_FIRMWARE_MODE_FTM) {
|
|
ret = -ENETDOWN;
|
|
goto err_unlock;
|
|
}
|