brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · 5be4b2d Raw
172 lines · c
1// SPDX-License-Identifier: BSD-3-Clause-Clear2/*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	else161		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}172