Linux Audio

Check our new training course

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