[PATCH v4 3/3] wifi: ath11k: add firmware-2.bin support
Jeff Johnson
quic_jjohnson at quicinc.com
Thu Jul 27 10:12:27 PDT 2023
On 7/27/2023 3:04 AM, Kalle Valo wrote:
> From: Anilkumar Kolli <quic_akolli at quicinc.com>
>
> 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. Firmware API 2 files are named as firmware-2.bin
> (which contains both amss.bin and m3.bin images) and API 1 files are
> amss.bin and m3.bin.
>
> Currently ath11k PCI driver provides firmware binary (amss.bin) path to
> MHI driver, MHI driver reads firmware from filesystem and boots it. Add
> provision to read firmware files from ath11k driver and provide the amss.bin
> firmware data and size to MHI using a pointer.
>
> Currently enum ath11k_fw_features is empty, the patches adding features will
> add the flags.
>
> With AHB devices there's no amss.bin or m3.bin, so no changes in how AHB
> firmware files are used. But AHB devices can use future additions to the meta
> data, for example in enum ath11k_fw_features.
>
> Tested-on: WCN6855 hw2.0 PCI WLAN.HSP.1.1-03125-QCAHSPSWPL_V1_V2_SILICONZ_LITE-3.6510.9
>
> Co-developed-by: P Praneesh <quic_ppranees at quicinc.com>
> Signed-off-by: P Praneesh <quic_ppranees at quicinc.com>
> Signed-off-by: Anilkumar Kolli <quic_akolli at quicinc.com>
> Co-developed-by: Kalle Valo <quic_kvalo at quicinc.com>
> Signed-off-by: Kalle Valo <quic_kvalo at quicinc.com>
> ---
> drivers/net/wireless/ath/ath11k/Makefile | 3 +-
> drivers/net/wireless/ath/ath11k/core.c | 8 ++
> drivers/net/wireless/ath/ath11k/core.h | 15 +++
> drivers/net/wireless/ath/ath11k/fw.c | 157 +++++++++++++++++++++++
> drivers/net/wireless/ath/ath11k/fw.h | 27 ++++
> drivers/net/wireless/ath/ath11k/mhi.c | 18 ++-
> drivers/net/wireless/ath/ath11k/qmi.c | 36 ++++--
> 7 files changed, 247 insertions(+), 17 deletions(-)
> create mode 100644 drivers/net/wireless/ath/ath11k/fw.c
> create mode 100644 drivers/net/wireless/ath/ath11k/fw.h
...
>
> diff --git a/drivers/net/wireless/ath/ath11k/fw.c b/drivers/net/wireless/ath/ath11k/fw.c
> new file mode 100644
> index 000000000000..5423c0be63fa
> --- /dev/null
> +++ b/drivers/net/wireless/ath/ath11k/fw.c
> @@ -0,0 +1,157 @@
> +// SPDX-License-Identifier: BSD-3-Clause-Clear
> +/*
> + * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved.
should the year be updated?
same question applies to the .h file
> + */
> +
> +#include "core.h"
> +
> +#include "debug.h"
> +
> +static int ath11k_fw_request_firmware_api_n(struct ath11k_base *ab,
> + const char *name)
> +{
> + size_t magic_len, len, ie_len;
> + int ie_id, i, index, bit, ret;
> + struct ath11k_fw_ie *hdr;
> + const u8 *data;
> + __le32 *timestamp;
> +
> + ab->fw.fw = ath11k_core_firmware_request(ab, name);
> + if (IS_ERR(ab->fw.fw)) {
> + ret = PTR_ERR(ab->fw.fw);
> + ath11k_dbg(ab, ATH11K_DBG_BOOT, "failed to load %s: %d\n", name, ret);
> + ab->fw.fw = NULL;
> + return ret;
> + }
> +
> + data = ab->fw.fw->data;
> + len = ab->fw.fw->size;
> +
> + /* magic also includes the null byte, check that as well */
> + magic_len = strlen(ATH11K_FIRMWARE_MAGIC) + 1;
> +
> + if (len < magic_len) {
> + ath11k_err(ab, "firmware image too small to contain magic: %zu\n",
> + len);
> + ret = -EINVAL;
> + goto err;
> + }
> +
> + if (memcmp(data, ATH11K_FIRMWARE_MAGIC, magic_len) != 0) {
> + ath11k_err(ab, "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 ath11k_fw_ie)) {
> + hdr = (struct ath11k_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) {
> + ath11k_err(ab, "Invalid length for FW IE %d (%zu < %zu)\n",
> + ie_id, len, ie_len);
> + ret = -EINVAL;
> + goto err;
> + }
> +
> + switch (ie_id) {
> + case ATH11K_FW_IE_TIMESTAMP:
> + if (ie_len != sizeof(u32))
> + break;
> +
> + timestamp = (__le32 *)data;
> +
> + ath11k_dbg(ab, ATH11K_DBG_BOOT, "found fw timestamp %d\n",
> + le32_to_cpup(timestamp));
> + break;
> + case ATH11K_FW_IE_FEATURES:
> + ath11k_dbg(ab, ATH11K_DBG_BOOT,
> + "found firmware features ie (%zd B)\n",
> + ie_len);
> +
> + for (i = 0; i < ATH11K_FW_FEATURE_COUNT; i++) {
> + index = i / 8;
> + bit = i % 8;
> +
> + if (index == ie_len)
> + break;
> +
> + if (data[index] & (1 << bit))
> + __set_bit(i, ab->fw.fw_features);
> + }
> +
> + ath11k_dbg_dump(ab, ATH11K_DBG_BOOT, "features", "",
> + ab->fw.fw_features,
> + sizeof(ab->fw.fw_features));
> + break;
> + case ATH11K_FW_IE_AMSS_IMAGE:
> + ath11k_dbg(ab, ATH11K_DBG_BOOT,
> + "found fw image ie (%zd B)\n",
> + ie_len);
> +
> + ab->fw.amss_data = data;
> + ab->fw.amss_len = ie_len;
> + break;
> + case ATH11K_FW_IE_M3_IMAGE:
> + ath11k_dbg(ab, ATH11K_DBG_BOOT,
> + "found m3 image ie (%zd B)\n",
> + ie_len);
> +
> + ab->fw.m3_data = data;
> + ab->fw.m3_len = ie_len;
> + break;
> + default:
> + ath11k_warn(ab, "Unknown FW IE: %u\n", ie_id);
> + break;
> + }
> +
> + /* jump over the padding */
> + ie_len = ALIGN(ie_len, 4);
> +
> + len -= ie_len;
> + data += ie_len;
is this always safe?
can we have a case where the original ie_len was <= len but the aligned
ie_len is > len, and hence this will lead to an integer underflow of len
(becoming a large unsigned value) and we'll continue looping with a
buffer overread?
the same question applies to the code where the magic is checked & skipped
> + };
> +
> + return 0;
> +
> +err:
> + release_firmware(ab->fw.fw);
> + ab->fw.fw = NULL;
> + return ret;
> +}
> +
More information about the ath11k
mailing list