diff options
Diffstat (limited to 'package/kernel/mac80211/patches/304-ath10k-add-FW-API-support-to-test-mode.patch')
-rw-r--r-- | package/kernel/mac80211/patches/304-ath10k-add-FW-API-support-to-test-mode.patch | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/304-ath10k-add-FW-API-support-to-test-mode.patch b/package/kernel/mac80211/patches/304-ath10k-add-FW-API-support-to-test-mode.patch new file mode 100644 index 0000000..e4ccac3 --- /dev/null +++ b/package/kernel/mac80211/patches/304-ath10k-add-FW-API-support-to-test-mode.patch @@ -0,0 +1,331 @@ +From: Alan Liu <alanliu@qca.qualcomm.com> +Date: Wed, 28 Oct 2015 21:38:32 +0200 +Subject: [PATCH] ath10k: add FW API support to test mode + +Add WMI-TLV and FW API support in ath10k testmode. +Ath10k can get right wmi command format from UTF image +to communicate UTF firmware. + +Signed-off-by: Alan Liu <alanliu@qca.qualcomm.com> +Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com> +--- + +--- a/drivers/net/wireless/ath/ath10k/core.c ++++ b/drivers/net/wireless/ath/ath10k/core.c +@@ -569,8 +569,8 @@ static int ath10k_download_fw(struct ath + } + break; + case ATH10K_FIRMWARE_MODE_UTF: +- data = ar->testmode.utf->data; +- data_len = ar->testmode.utf->size; ++ data = ar->testmode.utf_firmware_data; ++ data_len = ar->testmode.utf_firmware_len; + mode_name = "utf"; + break; + default: +--- a/drivers/net/wireless/ath/ath10k/core.h ++++ b/drivers/net/wireless/ath/ath10k/core.h +@@ -817,9 +817,12 @@ struct ath10k { + struct { + /* protected by conf_mutex */ + const struct firmware *utf; ++ char utf_version[32]; ++ const void *utf_firmware_data; ++ size_t utf_firmware_len; + DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT); + enum ath10k_fw_wmi_op_version orig_wmi_op_version; +- ++ enum ath10k_fw_wmi_op_version op_version; + /* protected by data_lock */ + bool utf_monitor; + } testmode; +--- a/drivers/net/wireless/ath/ath10k/hw.h ++++ b/drivers/net/wireless/ath/ath10k/hw.h +@@ -94,6 +94,7 @@ enum qca6174_chip_id_rev { + #define ATH10K_FW_API5_FILE "firmware-5.bin" + + #define ATH10K_FW_UTF_FILE "utf.bin" ++#define ATH10K_FW_UTF_API2_FILE "utf-2.bin" + + /* includes also the null byte */ + #define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K" +--- a/drivers/net/wireless/ath/ath10k/testmode.c ++++ b/drivers/net/wireless/ath/ath10k/testmode.c +@@ -139,11 +139,181 @@ static int ath10k_tm_cmd_get_version(str + return cfg80211_testmode_reply(skb); + } + +-static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) ++static int ath10k_tm_fetch_utf_firmware_api_2(struct ath10k *ar) ++{ ++ size_t len, magic_len, ie_len; ++ struct ath10k_fw_ie *hdr; ++ char filename[100]; ++ __le32 *version; ++ const u8 *data; ++ int ie_id, ret; ++ ++ snprintf(filename, sizeof(filename), "%s/%s", ++ ar->hw_params.fw.dir, ATH10K_FW_UTF_API2_FILE); ++ ++ /* load utf firmware image */ ++ ret = request_firmware(&ar->testmode.utf, filename, ar->dev); ++ if (ret) { ++ ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n", ++ filename, ret); ++ return ret; ++ } ++ ++ data = ar->testmode.utf->data; ++ len = ar->testmode.utf->size; ++ ++ /* FIXME: call release_firmware() in error cases */ ++ ++ /* magic also includes the null byte, check that as well */ ++ magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1; ++ ++ if (len < magic_len) { ++ ath10k_err(ar, "utf firmware file is too small to contain magic\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) { ++ ath10k_err(ar, "invalid firmware magic\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ /* jump over the padding */ ++ magic_len = ALIGN(magic_len, 4); ++ ++ len -= magic_len; ++ data += magic_len; ++ ++ /* loop elements */ ++ while (len > sizeof(struct ath10k_fw_ie)) { ++ hdr = (struct ath10k_fw_ie *)data; ++ ++ ie_id = le32_to_cpu(hdr->id); ++ ie_len = le32_to_cpu(hdr->len); ++ ++ len -= sizeof(*hdr); ++ data += sizeof(*hdr); ++ ++ if (len < ie_len) { ++ ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n", ++ ie_id, len, ie_len); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ switch (ie_id) { ++ case ATH10K_FW_IE_FW_VERSION: ++ if (ie_len > sizeof(ar->testmode.utf_version) - 1) ++ break; ++ ++ memcpy(ar->testmode.utf_version, data, ie_len); ++ ar->testmode.utf_version[ie_len] = '\0'; ++ ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, ++ "testmode found fw utf version %s\n", ++ ar->testmode.utf_version); ++ break; ++ case ATH10K_FW_IE_TIMESTAMP: ++ /* ignore timestamp, but don't warn about it either */ ++ break; ++ case ATH10K_FW_IE_FW_IMAGE: ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, ++ "testmode found fw image ie (%zd B)\n", ++ ie_len); ++ ++ ar->testmode.utf_firmware_data = data; ++ ar->testmode.utf_firmware_len = ie_len; ++ break; ++ case ATH10K_FW_IE_WMI_OP_VERSION: ++ if (ie_len != sizeof(u32)) ++ break; ++ version = (__le32 *)data; ++ ar->testmode.op_version = le32_to_cpup(version); ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode found fw ie wmi op version %d\n", ++ ar->testmode.op_version); ++ break; ++ default: ++ ath10k_warn(ar, "Unknown testmode FW IE: %u\n", ++ le32_to_cpu(hdr->id)); ++ break; ++ } ++ /* jump over the padding */ ++ ie_len = ALIGN(ie_len, 4); ++ ++ len -= ie_len; ++ data += ie_len; ++ } ++ ++ if (!ar->testmode.utf_firmware_data || !ar->testmode.utf_firmware_len) { ++ ath10k_err(ar, "No ATH10K_FW_IE_FW_IMAGE found\n"); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ return 0; ++ ++err: ++ release_firmware(ar->testmode.utf); ++ ++ return ret; ++} ++ ++static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar) + { + char filename[100]; + int ret; + ++ snprintf(filename, sizeof(filename), "%s/%s", ++ ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE); ++ ++ /* load utf firmware image */ ++ ret = request_firmware(&ar->testmode.utf, filename, ar->dev); ++ if (ret) { ++ ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n", ++ filename, ret); ++ return ret; ++ } ++ ++ /* We didn't find FW UTF API 1 ("utf.bin") does not advertise ++ * firmware features. Do an ugly hack where we force the firmware ++ * features to match with 10.1 branch so that wmi.c will use the ++ * correct WMI interface. ++ */ ++ ++ ar->testmode.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; ++ ar->testmode.utf_firmware_data = ar->testmode.utf->data; ++ ar->testmode.utf_firmware_len = ar->testmode.utf->size; ++ ++ return 0; ++} ++ ++static int ath10k_tm_fetch_firmware(struct ath10k *ar) ++{ ++ int ret; ++ ++ ret = ath10k_tm_fetch_utf_firmware_api_2(ar); ++ if (ret == 0) { ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2"); ++ return 0; ++ } ++ ++ ret = ath10k_tm_fetch_utf_firmware_api_1(ar); ++ if (ret) { ++ ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret); ++ return ret; ++ } ++ ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1"); ++ ++ return 0; ++} ++ ++static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[]) ++{ ++ const char *ver; ++ int ret; ++ + ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n"); + + mutex_lock(&ar->conf_mutex); +@@ -165,36 +335,27 @@ static int ath10k_tm_cmd_utf_start(struc + goto err; + } + +- snprintf(filename, sizeof(filename), "%s/%s", +- ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE); +- +- /* load utf firmware image */ +- ret = request_firmware(&ar->testmode.utf, filename, ar->dev); ++ ret = ath10k_tm_fetch_firmware(ar); + if (ret) { +- ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n", +- filename, ret); ++ ath10k_err(ar, "failed to fetch UTF firmware: %d", ret); + goto err; + } + + spin_lock_bh(&ar->data_lock); +- + ar->testmode.utf_monitor = true; +- + spin_unlock_bh(&ar->data_lock); +- + BUILD_BUG_ON(sizeof(ar->fw_features) != + sizeof(ar->testmode.orig_fw_features)); + + memcpy(ar->testmode.orig_fw_features, ar->fw_features, + sizeof(ar->fw_features)); + ar->testmode.orig_wmi_op_version = ar->wmi.op_version; +- +- /* utf.bin firmware image does not advertise firmware features. Do +- * an ugly hack where we force the firmware features so that wmi.c +- * will use the correct WMI interface. +- */ + memset(ar->fw_features, 0, sizeof(ar->fw_features)); +- ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1; ++ ++ ar->wmi.op_version = ar->testmode.op_version; ++ ++ ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n", ++ ar->wmi.op_version); + + ret = ath10k_hif_power_up(ar); + if (ret) { +@@ -212,7 +373,12 @@ static int ath10k_tm_cmd_utf_start(struc + + ar->state = ATH10K_STATE_UTF; + +- ath10k_info(ar, "UTF firmware started\n"); ++ if (strlen(ar->testmode.utf_version) > 0) ++ ver = ar->testmode.utf_version; ++ else ++ ver = "API 1"; ++ ++ ath10k_info(ar, "UTF firmware %s started\n", ver); + + mutex_unlock(&ar->conf_mutex); + +--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c ++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c +@@ -23,6 +23,7 @@ + #include "wmi-ops.h" + #include "wmi-tlv.h" + #include "p2p.h" ++#include "testmode.h" + + /***************/ + /* TLV helpers */ +@@ -419,6 +420,7 @@ static void ath10k_wmi_tlv_op_rx(struct + { + struct wmi_cmd_hdr *cmd_hdr; + enum wmi_tlv_event_id id; ++ bool consumed; + + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); +@@ -428,6 +430,18 @@ static void ath10k_wmi_tlv_op_rx(struct + + trace_ath10k_wmi_event(ar, id, skb->data, skb->len); + ++ consumed = ath10k_tm_event_wmi(ar, id, skb); ++ ++ /* Ready event must be handled normally also in UTF mode so that we ++ * know the UTF firmware has booted, others we are just bypass WMI ++ * events to testmode. ++ */ ++ if (consumed && id != WMI_TLV_READY_EVENTID) { ++ ath10k_dbg(ar, ATH10K_DBG_WMI, ++ "wmi tlv testmode consumed 0x%x\n", id); ++ goto out; ++ } ++ + switch (id) { + case WMI_TLV_MGMT_RX_EVENTID: + ath10k_wmi_event_mgmt_rx(ar, skb); |