aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/304-ath10k-add-FW-API-support-to-test-mode.patch
diff options
context:
space:
mode:
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.patch331
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);