2013-09-25 21:08:27

by Kalle Valo

[permalink] [raw]
Subject: [PATCH 0/3] ath10k: implement FW IE support

FW IE format is needed for ath10k automatically detect what features the
firmware image supports. This is important especially with 10.x firmwares which
has a different interface.

Please review.

---

Kalle Valo (3):
ath10k: rename board_data in struct ath10k
ath10k: store separate pointers for firmware data
ath10k: implement firmware IE container support


drivers/net/wireless/ath/ath10k/core.c | 210 +++++++++++++++++++++++++++++---
drivers/net/wireless/ath/ath10k/core.h | 12 ++
drivers/net/wireless/ath/ath10k/hw.h | 19 +++
drivers/net/wireless/ath/ath10k/wmi.c | 3
4 files changed, 220 insertions(+), 24 deletions(-)



2013-09-26 06:04:41

by Michal Kazior

[permalink] [raw]
Subject: Re: [PATCH 3/3] ath10k: implement firmware IE container support

On 26 September 2013 07:55, Kalle Valo <[email protected]> wrote:
> Michal Kazior <[email protected]> writes:
>
>> Did you skip board file intentionally?
>
> Yes, because my understanding is that the board file is not tied to any
> particular firmware version. The board file should be specific to the
> hardware configuration in use, or at least that's how it is with ath6kl.

But the board file is not loaded at all for API 2. The api_1 variant
requests 3 files and can result with up to 3 binaries loaded. api_n
requests 1 file and can result with up to 2 binaries loaded.


Michał.

2013-09-26 05:55:17

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 3/3] ath10k: implement firmware IE container support

Michal Kazior <[email protected]> writes:

> Did you skip board file intentionally?

Yes, because my understanding is that the board file is not tied to any
particular firmware version. The board file should be specific to the
hardware configuration in use, or at least that's how it is with ath6kl.

--
Kalle Valo

2013-09-25 21:08:45

by Kalle Valo

[permalink] [raw]
Subject: [PATCH 2/3] ath10k: store separate pointers for firmware data

Needed for firmware IE formatted images.

Signed-off-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 43 ++++++++++++++++++++++----------
drivers/net/wireless/ath/ath10k/core.h | 8 ++++++
2 files changed, 37 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index e07c487..6a354f7 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -189,8 +189,7 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
return fw;
}

-static int ath10k_push_board_ext_data(struct ath10k *ar,
- const struct firmware *fw)
+static int ath10k_push_board_ext_data(struct ath10k *ar)
{
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
@@ -210,14 +209,14 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,
if (board_ext_data_addr == 0)
return 0;

- if (fw->size != (board_data_size + board_ext_data_size)) {
+ if (ar->board_len != (board_data_size + board_ext_data_size)) {
ath10k_err("invalid board (ext) data sizes %zu != %d+%d\n",
- fw->size, board_data_size, board_ext_data_size);
+ ar->board_len, board_data_size, board_ext_data_size);
return -EINVAL;
}

ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,
- fw->data + board_data_size,
+ ar->board_data + board_data_size,
board_ext_data_size);
if (ret) {
ath10k_err("could not write board ext data (%d)\n", ret);
@@ -236,12 +235,11 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,

static int ath10k_download_board_data(struct ath10k *ar)
{
- const struct firmware *fw = ar->board;
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 address;
int ret;

- ret = ath10k_push_board_ext_data(ar, fw);
+ ret = ath10k_push_board_ext_data(ar);
if (ret) {
ath10k_err("could not push board ext data (%d)\n", ret);
goto exit;
@@ -253,8 +251,9 @@ static int ath10k_download_board_data(struct ath10k *ar)
goto exit;
}

- ret = ath10k_bmi_write_memory(ar, address, fw->data,
- min_t(u32, board_data_size, fw->size));
+ ret = ath10k_bmi_write_memory(ar, address, ar->board_data,
+ min_t(u32, board_data_size,
+ ar->board_len));
if (ret) {
ath10k_err("could not write board data (%d)\n", ret);
goto exit;
@@ -272,17 +271,16 @@ exit:

static int ath10k_download_and_run_otp(struct ath10k *ar)
{
- const struct firmware *fw = ar->otp;
u32 address = ar->hw_params.patch_load_addr;
u32 exec_param;
int ret;

/* OTP is optional */

- if (!ar->otp)
+ if (!ar->otp_data || !ar->otp_len)
return 0;

- ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
+ ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
if (ret) {
ath10k_err("could not write otp (%d)\n", ret);
goto exit;
@@ -301,13 +299,13 @@ exit:

static int ath10k_download_fw(struct ath10k *ar)
{
- const struct firmware *fw = ar->firmware;
u32 address;
int ret;

address = ar->hw_params.patch_load_addr;

- ret = ath10k_bmi_fast_download(ar, address, fw->data, fw->size);
+ ret = ath10k_bmi_fast_download(ar, address, ar->firmware_data,
+ ar->firmware_len);
if (ret) {
ath10k_err("could not write fw (%d)\n", ret);
goto exit;
@@ -329,8 +327,16 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
release_firmware(ar->firmware);

ar->board = NULL;
+ ar->board_data = NULL;
+ ar->board_len = 0;
+
ar->otp = NULL;
+ ar->otp_data = NULL;
+ ar->otp_len = 0;
+
ar->firmware = NULL;
+ ar->firmware_data = NULL;
+ ar->firmware_len = 0;
}

static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
@@ -356,6 +362,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
goto err;
}

+ ar->board_data = ar->board->data;
+ ar->board_len = ar->board->size;
+
ar->firmware = ath10k_fetch_fw_file(ar,
ar->hw_params.fw.dir,
ar->hw_params.fw.fw);
@@ -365,6 +374,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
goto err;
}

+ ar->firmware_data = ar->firmware->data;
+ ar->firmware_len = ar->firmware->size;
+
/* OTP may be undefined. If so, don't fetch it at all */
if (ar->hw_params.fw.otp == NULL)
return 0;
@@ -378,6 +390,9 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
goto err;
}

+ ar->otp_data = ar->otp->data;
+ ar->otp_len = ar->otp->size;
+
return 0;

err:
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 12b03b6..511b20d 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -325,8 +325,16 @@ struct ath10k {
} hw_params;

const struct firmware *board;
+ const void *board_data;
+ size_t board_len;
+
const struct firmware *otp;
+ const void *otp_data;
+ size_t otp_len;
+
const struct firmware *firmware;
+ const void *firmware_data;
+ size_t firmware_len;

struct {
struct completion started;


2013-09-25 21:08:35

by Kalle Valo

[permalink] [raw]
Subject: [PATCH 1/3] ath10k: rename board_data in struct ath10k

I will use board_data for something else in the following patch
so I need to rename it.

Signed-off-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 18 +++++++++---------
drivers/net/wireless/ath/ath10k/core.h | 2 +-
2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 76906d5..e07c487 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -236,7 +236,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar,

static int ath10k_download_board_data(struct ath10k *ar)
{
- const struct firmware *fw = ar->board_data;
+ const struct firmware *fw = ar->board;
u32 board_data_size = QCA988X_BOARD_DATA_SZ;
u32 address;
int ret;
@@ -319,8 +319,8 @@ exit:

static void ath10k_core_free_firmware_files(struct ath10k *ar)
{
- if (ar->board_data && !IS_ERR(ar->board_data))
- release_firmware(ar->board_data);
+ if (ar->board && !IS_ERR(ar->board))
+ release_firmware(ar->board);

if (ar->otp && !IS_ERR(ar->otp))
release_firmware(ar->otp);
@@ -328,7 +328,7 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
if (ar->firmware && !IS_ERR(ar->firmware))
release_firmware(ar->firmware);

- ar->board_data = NULL;
+ ar->board = NULL;
ar->otp = NULL;
ar->firmware = NULL;
}
@@ -347,11 +347,11 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
return -EINVAL;
}

- ar->board_data = ath10k_fetch_fw_file(ar,
- ar->hw_params.fw.dir,
- ar->hw_params.fw.board);
- if (IS_ERR(ar->board_data)) {
- ret = PTR_ERR(ar->board_data);
+ ar->board = ath10k_fetch_fw_file(ar,
+ ar->hw_params.fw.dir,
+ ar->hw_params.fw.board);
+ if (IS_ERR(ar->board)) {
+ ret = PTR_ERR(ar->board);
ath10k_err("could not fetch board data (%d)\n", ret);
goto err;
}
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 292ad45..12b03b6 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -324,7 +324,7 @@ struct ath10k {
} fw;
} hw_params;

- const struct firmware *board_data;
+ const struct firmware *board;
const struct firmware *otp;
const struct firmware *firmware;



2013-09-26 05:46:18

by Michal Kazior

[permalink] [raw]
Subject: Re: [PATCH 3/3] ath10k: implement firmware IE container support

On 25 September 2013 23:08, Kalle Valo <[email protected]> wrote:
> +static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
> +{
> + size_t magic_len, len, ie_len;
> + struct ath10k_fw_ie *hdr;
> + const u8 *data;
> + int ie_id, i, index, bit;
> + __le32 *timestamp;
> +
> + ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
> + if (IS_ERR(ar->firmware)) {
> + ath10k_err("Could not fetch firmware file '%s': %ld\n",
> + name, PTR_ERR(ar->firmware));
> + return PTR_ERR(ar->firmware);
> + }
> +
> + data = ar->firmware->data;
> + len = ar->firmware->size;
> +
> + /* magic also includes the null byte, check that as well */
> + magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
> +
> + if (len < magic_len) {
> + ath10k_err("firmware image too small to contain magic: %d\n",
> + len);
> + return -EINVAL;
> + }
> +
> + if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
> + ath10k_err("Invalid firmware magic\n");
> + return -EINVAL;
> + }
> +
> + /* 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("Invalid length for FW IE %d (%d < %d)\n",
> + ie_id, len, ie_len);
> + return -EINVAL;
> + }
> +
> + switch (ie_id) {
> + case ATH10K_FW_IE_FW_VERSION:
> + if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1)
> + break;
> +
> + memcpy(ar->hw->wiphy->fw_version, data, ie_len);
> + ar->hw->wiphy->fw_version[ie_len] = '\0';
> +
> + ath10k_dbg(ATH10K_DBG_BOOT,
> + "found fw version %s\n",
> + ar->hw->wiphy->fw_version);
> + break;
> + case ATH10K_FW_IE_TIMESTAMP:
> + if (ie_len != sizeof(u32))
> + break;
> +
> + timestamp = (__le32 *)data;
> +
> + ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n",
> + le32_to_cpup(timestamp));
> + break;
> + case ATH10K_FW_IE_FEATURES:
> + ath10k_dbg(ATH10K_DBG_BOOT,
> + "found firmware features ie (%zd B)\n",
> + ie_len);
> +
> + for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) {
> + index = i / 8;
> + bit = i % 8;
> +
> + if (index == ie_len)
> + break;
> +
> + if (data[index] & (1 << bit))
> + __set_bit(i, ar->fw_features);
> + }
> +
> + ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
> + ar->fw_features,
> + sizeof(ar->fw_features));
> + break;
> + case ATH10K_FW_IE_FW_IMAGE:
> + ath10k_dbg(ATH10K_DBG_BOOT,
> + "found fw image ie (%zd B)\n",
> + ie_len);
> +
> + ar->firmware_data = data;
> + ar->firmware_len = ie_len;
> +
> + break;
> + case ATH10K_FW_IE_OTP_IMAGE:
> + ath10k_dbg(ATH10K_DBG_BOOT,
> + "found otp image ie (%zd B)\n",
> + ie_len);
> +
> + ar->otp_data = data;
> + ar->otp_len = ie_len;
> +
> + break;
> + default:
> + ath10k_warn("Unknown 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;
> + };
> +
> + return 0;
> +}
> +
> +static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
> +{
> + int ret;
> +
> + ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
> + if (ret == 0) {
> + ar->fw_api = 2;
> + goto out;
> + }

Did you skip board file intentionally?


Michał.

2013-09-26 06:18:14

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH 3/3] ath10k: implement firmware IE container support

Michal Kazior <[email protected]> writes:

> On 26 September 2013 07:55, Kalle Valo <[email protected]> wrote:
>> Michal Kazior <[email protected]> writes:
>>
>>> Did you skip board file intentionally?
>>
>> Yes, because my understanding is that the board file is not tied to any
>> particular firmware version. The board file should be specific to the
>> hardware configuration in use, or at least that's how it is with ath6kl.
>
> But the board file is not loaded at all for API 2. The api_1 variant
> requests 3 files and can result with up to 3 binaries loaded. api_n
> requests 1 file and can result with up to 2 binaries loaded.

Oops, that's clearly a bug. How did it even pass my tests without the
board file? I'll send v2 to fix that.

So my idea is that with API 2 we load only firmware-2.bin and board.bin
from user space. With API 1 we continue loading firmware.bin, otp.bin
(optional) and board.bin, just as before. And firmware-2.bin can contain
the old firmware.bin (mandatory) and otp.bin (optional) images.

I just realised that I'm missing a check that there really is a firmware
image inside firmware-2.bin, need to add that as well.

--
Kalle Valo

2013-09-25 21:08:54

by Kalle Valo

[permalink] [raw]
Subject: [PATCH 3/3] ath10k: implement firmware IE container support

Firmware IE containers can dynamically provide various information what
firmware supports. Also it can embed more than one image so updating firmware
is easy, user just needs to update one file in /lib/firmware/.

The firmware API 2 or higher will use the IE container format, the current API
1 will not use the new format but it still is supported for some time. FW API 2
files are named as firmware-2.bin (which contains both firmware and otp images)
and API 1 files are firmware.bin and otp.bin.

Signed-off-by: Kalle Valo <[email protected]>
---
drivers/net/wireless/ath/ath10k/core.c | 153 ++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath10k/core.h | 2
drivers/net/wireless/ath/ath10k/hw.h | 19 ++++
drivers/net/wireless/ath/ath10k/wmi.c | 3 -
4 files changed, 175 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 6a354f7..a1a3dcc 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -339,7 +339,7 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar)
ar->firmware_len = 0;
}

-static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
+static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
{
int ret = 0;

@@ -400,6 +400,157 @@ err:
return ret;
}

+static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
+{
+ size_t magic_len, len, ie_len;
+ struct ath10k_fw_ie *hdr;
+ const u8 *data;
+ int ie_id, i, index, bit;
+ __le32 *timestamp;
+
+ ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
+ if (IS_ERR(ar->firmware)) {
+ ath10k_err("Could not fetch firmware file '%s': %ld\n",
+ name, PTR_ERR(ar->firmware));
+ return PTR_ERR(ar->firmware);
+ }
+
+ data = ar->firmware->data;
+ len = ar->firmware->size;
+
+ /* magic also includes the null byte, check that as well */
+ magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
+
+ if (len < magic_len) {
+ ath10k_err("firmware image too small to contain magic: %d\n",
+ len);
+ return -EINVAL;
+ }
+
+ if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
+ ath10k_err("Invalid firmware magic\n");
+ return -EINVAL;
+ }
+
+ /* 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("Invalid length for FW IE %d (%d < %d)\n",
+ ie_id, len, ie_len);
+ return -EINVAL;
+ }
+
+ switch (ie_id) {
+ case ATH10K_FW_IE_FW_VERSION:
+ if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1)
+ break;
+
+ memcpy(ar->hw->wiphy->fw_version, data, ie_len);
+ ar->hw->wiphy->fw_version[ie_len] = '\0';
+
+ ath10k_dbg(ATH10K_DBG_BOOT,
+ "found fw version %s\n",
+ ar->hw->wiphy->fw_version);
+ break;
+ case ATH10K_FW_IE_TIMESTAMP:
+ if (ie_len != sizeof(u32))
+ break;
+
+ timestamp = (__le32 *)data;
+
+ ath10k_dbg(ATH10K_DBG_BOOT, "found fw timestamp %d\n",
+ le32_to_cpup(timestamp));
+ break;
+ case ATH10K_FW_IE_FEATURES:
+ ath10k_dbg(ATH10K_DBG_BOOT,
+ "found firmware features ie (%zd B)\n",
+ ie_len);
+
+ for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) {
+ index = i / 8;
+ bit = i % 8;
+
+ if (index == ie_len)
+ break;
+
+ if (data[index] & (1 << bit))
+ __set_bit(i, ar->fw_features);
+ }
+
+ ath10k_dbg_dump(ATH10K_DBG_BOOT, "features", "",
+ ar->fw_features,
+ sizeof(ar->fw_features));
+ break;
+ case ATH10K_FW_IE_FW_IMAGE:
+ ath10k_dbg(ATH10K_DBG_BOOT,
+ "found fw image ie (%zd B)\n",
+ ie_len);
+
+ ar->firmware_data = data;
+ ar->firmware_len = ie_len;
+
+ break;
+ case ATH10K_FW_IE_OTP_IMAGE:
+ ath10k_dbg(ATH10K_DBG_BOOT,
+ "found otp image ie (%zd B)\n",
+ ie_len);
+
+ ar->otp_data = data;
+ ar->otp_len = ie_len;
+
+ break;
+ default:
+ ath10k_warn("Unknown 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;
+ };
+
+ return 0;
+}
+
+static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
+{
+ int ret;
+
+ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
+ if (ret == 0) {
+ ar->fw_api = 2;
+ goto out;
+ }
+
+ ret = ath10k_core_fetch_firmware_api_1(ar);
+ if (ret)
+ return ret;
+
+ ar->fw_api = 1;
+
+out:
+ ath10k_dbg(ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);
+
+ return 0;
+}
+
static int ath10k_init_download_firmware(struct ath10k *ar)
{
int ret;
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 511b20d..3b5e78d 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -336,6 +336,8 @@ struct ath10k {
const void *firmware_data;
size_t firmware_len;

+ int fw_api;
+
struct {
struct completion started;
struct completion completed;
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index 643f0c9..a9cac43 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -38,6 +38,25 @@
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234

+#define ATH10K_FW_API2_FILE "firmware-2.bin"
+
+/* includes also the null byte */
+#define ATH10K_FIRMWARE_MAGIC "QCA-ATH10K"
+
+struct ath10k_fw_ie {
+ __le32 id;
+ __le32 len;
+ u8 data[0];
+};
+
+enum ath10k_fw_ie_type {
+ ATH10K_FW_IE_FW_VERSION = 0,
+ ATH10K_FW_IE_TIMESTAMP = 1,
+ ATH10K_FW_IE_FEATURES = 2,
+ ATH10K_FW_IE_FW_IMAGE = 3,
+ ATH10K_FW_IE_OTP_IMAGE = 4,
+};
+
/* Known pecularities:
* - current FW doesn't support raw rx mode (last tested v599)
* - current FW dumps upon raw tx mode (last tested v599)
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index 6803ead..771d77c 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -988,7 +988,8 @@ static void ath10k_wmi_service_ready_event_rx(struct ath10k *ar,
ar->phy_capability = __le32_to_cpu(ev->phy_capability);
ar->num_rf_chains = __le32_to_cpu(ev->num_rf_chains);

- if (ar->fw_version_build > 636)
+ /* only manually set fw features when not using FW IE format */
+ if (ar->fw_api == 1 && ar->fw_version_build > 636)
set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);

if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) {