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