File Index
Files and directories
Sign in
FILE

fw.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/ath/ath11k/fw.c C
  1// SPDX-License-Identifier: BSD-3-Clause-Clear
  2/*
  3 * Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
  4 * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
  5 */
  6
  7#include <linux/export.h>
  8#include "core.h"
  9
 10#include "debug.h"
 11
 12static int ath11k_fw_request_firmware_api_n(struct ath11k_base *ab,
 13					    const char *name)
 14{
 15	size_t magic_len, len, ie_len;
 16	int ie_id, i, index, bit, ret;
 17	struct ath11k_fw_ie *hdr;
 18	const u8 *data;
 19	__le32 *timestamp;
 20
 21	ab->fw.fw = ath11k_core_firmware_request(ab, name);
 22	if (IS_ERR(ab->fw.fw)) {
 23		ret = PTR_ERR(ab->fw.fw);
 24		ath11k_dbg(ab, ATH11K_DBG_BOOT, "failed to load %s: %d\n", name, ret);
 25		ab->fw.fw = NULL;
 26		return ret;
 27	}
 28
 29	data = ab->fw.fw->data;
 30	len = ab->fw.fw->size;
 31
 32	/* magic also includes the null byte, check that as well */
 33	magic_len = strlen(ATH11K_FIRMWARE_MAGIC) + 1;
 34
 35	if (len < magic_len) {
 36		ath11k_err(ab, "firmware image too small to contain magic: %zu\n",
 37			   len);
 38		ret = -EINVAL;
 39		goto err;
 40	}
 41
 42	if (memcmp(data, ATH11K_FIRMWARE_MAGIC, magic_len) != 0) {
 43		ath11k_err(ab, "Invalid firmware magic\n");
 44		ret = -EINVAL;
 45		goto err;
 46	}
 47
 48	/* jump over the padding */
 49	magic_len = ALIGN(magic_len, 4);
 50
 51	/* make sure there's space for padding */
 52	if (magic_len > len) {
 53		ath11k_err(ab, "No space for padding after magic\n");
 54		ret = -EINVAL;
 55		goto err;
 56	}
 57
 58	len -= magic_len;
 59	data += magic_len;
 60
 61	/* loop elements */
 62	while (len > sizeof(struct ath11k_fw_ie)) {
 63		hdr = (struct ath11k_fw_ie *)data;
 64
 65		ie_id = le32_to_cpu(hdr->id);
 66		ie_len = le32_to_cpu(hdr->len);
 67
 68		len -= sizeof(*hdr);
 69		data += sizeof(*hdr);
 70
 71		if (len < ie_len) {
 72			ath11k_err(ab, "Invalid length for FW IE %d (%zu < %zu)\n",
 73				   ie_id, len, ie_len);
 74			ret = -EINVAL;
 75			goto err;
 76		}
 77
 78		switch (ie_id) {
 79		case ATH11K_FW_IE_TIMESTAMP:
 80			if (ie_len != sizeof(u32))
 81				break;
 82
 83			timestamp = (__le32 *)data;
 84
 85			ath11k_dbg(ab, ATH11K_DBG_BOOT, "found fw timestamp %d\n",
 86				   le32_to_cpup(timestamp));
 87			break;
 88		case ATH11K_FW_IE_FEATURES:
 89			ath11k_dbg(ab, ATH11K_DBG_BOOT,
 90				   "found firmware features ie (%zd B)\n",
 91				   ie_len);
 92
 93			for (i = 0; i < ATH11K_FW_FEATURE_COUNT; i++) {
 94				index = i / 8;
 95				bit = i % 8;
 96
 97				if (index == ie_len)
 98					break;
 99
100				if (data[index] & (1 << bit))
101					__set_bit(i, ab->fw.fw_features);
102			}
103
104			ath11k_dbg_dump(ab, ATH11K_DBG_BOOT, "features", "",
105					ab->fw.fw_features,
106					sizeof(ab->fw.fw_features));
107			break;
108		case ATH11K_FW_IE_AMSS_IMAGE:
109			ath11k_dbg(ab, ATH11K_DBG_BOOT,
110				   "found fw image ie (%zd B)\n",
111				   ie_len);
112
113			ab->fw.amss_data = data;
114			ab->fw.amss_len = ie_len;
115			break;
116		case ATH11K_FW_IE_M3_IMAGE:
117			ath11k_dbg(ab, ATH11K_DBG_BOOT,
118				   "found m3 image ie (%zd B)\n",
119				   ie_len);
120
121			ab->fw.m3_data = data;
122			ab->fw.m3_len = ie_len;
123			break;
124		default:
125			ath11k_warn(ab, "Unknown FW IE: %u\n", ie_id);
126			break;
127		}
128
129		/* jump over the padding */
130		ie_len = ALIGN(ie_len, 4);
131
132		/* make sure there's space for padding */
133		if (ie_len > len)
134			break;
135
136		len -= ie_len;
137		data += ie_len;
138	}
139
140	return 0;
141
142err:
143	release_firmware(ab->fw.fw);
144	ab->fw.fw = NULL;
145	return ret;
146}
147
148int ath11k_fw_pre_init(struct ath11k_base *ab)
149{
150	int ret;
151
152	ret = ath11k_fw_request_firmware_api_n(ab, ATH11K_FW_API2_FILE);
153	if (ret == 0) {
154		ab->fw.api_version = 2;
155		goto out;
156	}
157
158	ab->fw.api_version = 1;
159
160out:
161	ath11k_dbg(ab, ATH11K_DBG_BOOT, "using fw api %d\n",
162		   ab->fw.api_version);
163
164	return 0;
165}
166
167void ath11k_fw_destroy(struct ath11k_base *ab)
168{
169	release_firmware(ab->fw.fw);
170}
171EXPORT_SYMBOL(ath11k_fw_destroy);
~/ Read-only file preview.