Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/athk/ath12k/fw.c
178701 views
1
// SPDX-License-Identifier: BSD-3-Clause-Clear
2
/*
3
* Copyright (c) 2022-2025 Qualcomm Innovation Center, Inc. All rights reserved.
4
*/
5
6
#include "core.h"
7
8
#include "debug.h"
9
10
static 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
ab->fw.fw_features_valid = true;
103
104
ath12k_dbg_dump(ab, ATH12K_DBG_BOOT, "features", "",
105
ab->fw.fw_features,
106
sizeof(ab->fw.fw_features));
107
break;
108
case ATH12K_FW_IE_AMSS_IMAGE:
109
ath12k_dbg(ab, ATH12K_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 ATH12K_FW_IE_M3_IMAGE:
117
ath12k_dbg(ab, ATH12K_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
case ATH12K_FW_IE_AMSS_DUALMAC_IMAGE:
125
ath12k_dbg(ab, ATH12K_DBG_BOOT,
126
"found dualmac fw image ie (%zd B)\n",
127
ie_len);
128
ab->fw.amss_dualmac_data = data;
129
ab->fw.amss_dualmac_len = ie_len;
130
break;
131
default:
132
ath12k_warn(ab, "Unknown FW IE: %u\n", ie_id);
133
break;
134
}
135
136
/* jump over the padding */
137
ie_len = ALIGN(ie_len, 4);
138
139
/* make sure there's space for padding */
140
if (ie_len > len)
141
break;
142
143
len -= ie_len;
144
data += ie_len;
145
}
146
147
return 0;
148
149
err:
150
release_firmware(ab->fw.fw);
151
ab->fw.fw = NULL;
152
return ret;
153
}
154
155
void ath12k_fw_map(struct ath12k_base *ab)
156
{
157
int ret;
158
159
ret = ath12k_fw_request_firmware_api_n(ab, ATH12K_FW_API2_FILE);
160
if (ret == 0)
161
ab->fw.api_version = 2;
162
else
163
ab->fw.api_version = 1;
164
165
ath12k_dbg(ab, ATH12K_DBG_BOOT, "using fw api %d\n",
166
ab->fw.api_version);
167
}
168
169
void ath12k_fw_unmap(struct ath12k_base *ab)
170
{
171
release_firmware(ab->fw.fw);
172
memset(&ab->fw, 0, sizeof(ab->fw));
173
}
174
175
bool ath12k_fw_feature_supported(struct ath12k_base *ab, enum ath12k_fw_features feat)
176
{
177
return ab->fw.fw_features_valid && test_bit(feat, ab->fw.fw_features);
178
}
179
180