1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Copyright(c) 2020-2021 Intel Corporation
10 #include "fw/api/commands.h"
11 #include "fw/api/nvm-reg.h"
12 #include "fw/api/alive.h"
15 struct iwl_pnvm_section
{
20 static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data
*notif_wait
,
21 struct iwl_rx_packet
*pkt
, void *data
)
23 struct iwl_trans
*trans
= (struct iwl_trans
*)data
;
24 struct iwl_pnvm_init_complete_ntfy
*pnvm_ntf
= (void *)pkt
->data
;
27 "PNVM complete notification received with status 0x%0x\n",
28 le32_to_cpu(pnvm_ntf
->status
));
33 static int iwl_pnvm_handle_section(struct iwl_trans
*trans
, const u8
*data
,
36 struct iwl_ucode_tlv
*tlv
;
38 u16 mac_type
= 0, rf_id
= 0;
39 u8
*pnvm_data
= NULL
, *tmp
;
40 bool hw_match
= false;
44 IWL_DEBUG_FW(trans
, "Handling PNVM section\n");
46 while (len
>= sizeof(*tlv
)) {
47 u32 tlv_len
, tlv_type
;
52 tlv_len
= le32_to_cpu(tlv
->length
);
53 tlv_type
= le32_to_cpu(tlv
->type
);
56 IWL_ERR(trans
, "invalid TLV len: %zd/%u\n",
65 case IWL_UCODE_TLV_PNVM_VERSION
:
66 if (tlv_len
< sizeof(__le32
)) {
68 "Invalid size for IWL_UCODE_TLV_PNVM_VERSION (expected %zd, got %d)\n",
69 sizeof(__le32
), tlv_len
);
73 sha1
= le32_to_cpup((__le32
*)data
);
76 "Got IWL_UCODE_TLV_PNVM_VERSION %0x\n",
79 case IWL_UCODE_TLV_HW_TYPE
:
80 if (tlv_len
< 2 * sizeof(__le16
)) {
82 "Invalid size for IWL_UCODE_TLV_HW_TYPE (expected %zd, got %d)\n",
83 2 * sizeof(__le16
), tlv_len
);
90 mac_type
= le16_to_cpup((__le16
*)data
);
91 rf_id
= le16_to_cpup((__le16
*)(data
+ sizeof(__le16
)));
94 "Got IWL_UCODE_TLV_HW_TYPE mac_type 0x%0x rf_id 0x%0x\n",
97 if (mac_type
== CSR_HW_REV_TYPE(trans
->hw_rev
) &&
98 rf_id
== CSR_HW_RFID_TYPE(trans
->hw_rf_id
))
101 case IWL_UCODE_TLV_SEC_RT
: {
102 struct iwl_pnvm_section
*section
= (void *)data
;
103 u32 data_len
= tlv_len
- sizeof(*section
);
106 "Got IWL_UCODE_TLV_SEC_RT len %d\n",
109 /* TODO: remove, this is a deprecated separator */
110 if (le32_to_cpup((__le32
*)data
) == 0xddddeeee) {
111 IWL_DEBUG_FW(trans
, "Ignoring separator.\n");
115 IWL_DEBUG_FW(trans
, "Adding data (size %d)\n",
118 tmp
= krealloc(pnvm_data
, size
+ data_len
, GFP_KERNEL
);
121 "Couldn't allocate (more) pnvm_data\n");
129 memcpy(pnvm_data
+ size
, section
->data
, data_len
);
135 case IWL_UCODE_TLV_PNVM_SKU
:
137 "New PNVM section started, stop parsing.\n");
140 IWL_DEBUG_FW(trans
, "Found TLV 0x%0x, len %d\n",
145 len
-= ALIGN(tlv_len
, 4);
146 data
+= ALIGN(tlv_len
, 4);
152 "HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n",
153 CSR_HW_REV_TYPE(trans
->hw_rev
),
154 CSR_HW_RFID_TYPE(trans
->hw_rf_id
));
160 IWL_DEBUG_FW(trans
, "Empty PNVM, skipping.\n");
165 IWL_INFO(trans
, "loaded PNVM version 0x%0x\n", sha1
);
167 ret
= iwl_trans_set_pnvm(trans
, pnvm_data
, size
);
173 static int iwl_pnvm_parse(struct iwl_trans
*trans
, const u8
*data
,
176 struct iwl_ucode_tlv
*tlv
;
178 IWL_DEBUG_FW(trans
, "Parsing PNVM file\n");
180 while (len
>= sizeof(*tlv
)) {
181 u32 tlv_len
, tlv_type
;
186 tlv_len
= le32_to_cpu(tlv
->length
);
187 tlv_type
= le32_to_cpu(tlv
->type
);
190 IWL_ERR(trans
, "invalid TLV len: %zd/%u\n",
195 if (tlv_type
== IWL_UCODE_TLV_PNVM_SKU
) {
196 struct iwl_sku_id
*sku_id
=
197 (void *)(data
+ sizeof(*tlv
));
200 "Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
202 IWL_DEBUG_FW(trans
, "sku_id 0x%0x 0x%0x 0x%0x\n",
203 le32_to_cpu(sku_id
->data
[0]),
204 le32_to_cpu(sku_id
->data
[1]),
205 le32_to_cpu(sku_id
->data
[2]));
207 data
+= sizeof(*tlv
) + ALIGN(tlv_len
, 4);
208 len
-= ALIGN(tlv_len
, 4);
210 if (trans
->sku_id
[0] == le32_to_cpu(sku_id
->data
[0]) &&
211 trans
->sku_id
[1] == le32_to_cpu(sku_id
->data
[1]) &&
212 trans
->sku_id
[2] == le32_to_cpu(sku_id
->data
[2])) {
215 ret
= iwl_pnvm_handle_section(trans
, data
, len
);
219 IWL_DEBUG_FW(trans
, "SKU ID didn't match!\n");
222 data
+= sizeof(*tlv
) + ALIGN(tlv_len
, 4);
223 len
-= ALIGN(tlv_len
, 4);
230 static int iwl_pnvm_get_from_fs(struct iwl_trans
*trans
, u8
**data
, size_t *len
)
232 const struct firmware
*pnvm
;
233 char pnvm_name
[MAX_PNVM_NAME
];
237 iwl_pnvm_get_fs_name(trans
, pnvm_name
, sizeof(pnvm_name
));
239 ret
= firmware_request_nowarn(&pnvm
, pnvm_name
, trans
->dev
);
241 IWL_DEBUG_FW(trans
, "PNVM file %s not found %d\n",
246 new_len
= pnvm
->size
;
247 *data
= kmemdup(pnvm
->data
, pnvm
->size
, GFP_KERNEL
);
248 release_firmware(pnvm
);
258 int iwl_pnvm_load(struct iwl_trans
*trans
,
259 struct iwl_notif_wait_data
*notif_wait
)
263 struct pnvm_sku_package
*package
;
264 struct iwl_notification_wait pnvm_wait
;
265 static const u16 ntf_cmds
[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP
,
266 PNVM_INIT_COMPLETE_NTFY
) };
269 /* if the SKU_ID is empty, there's nothing to do */
270 if (!trans
->sku_id
[0] && !trans
->sku_id
[1] && !trans
->sku_id
[2])
274 * If we already loaded (or tried to load) it before, we just
275 * need to set it again.
277 if (trans
->pnvm_loaded
) {
278 ret
= iwl_trans_set_pnvm(trans
, NULL
, 0);
284 /* First attempt to get the PNVM from BIOS */
285 package
= iwl_uefi_get_pnvm(trans
, &len
);
286 if (!IS_ERR_OR_NULL(package
)) {
287 data
= kmemdup(package
->data
, len
, GFP_KERNEL
);
289 /* free package regardless of whether kmemdup succeeded */
293 /* we need only the data size */
294 len
-= sizeof(*package
);
299 /* If it's not available, try from the filesystem */
300 ret
= iwl_pnvm_get_from_fs(trans
, &data
, &len
);
303 * Pretend we've loaded it - at least we've tried and
304 * couldn't load it at all, so there's no point in
305 * trying again over and over.
307 trans
->pnvm_loaded
= true;
313 iwl_pnvm_parse(trans
, data
, len
);
319 /* now try to get the reduce power table, if not loaded yet */
320 if (!trans
->reduce_power_loaded
) {
321 data
= iwl_uefi_get_reduced_power(trans
, &len
);
322 if (IS_ERR_OR_NULL(data
)) {
324 * Pretend we've loaded it - at least we've tried and
325 * couldn't load it at all, so there's no point in
326 * trying again over and over.
328 trans
->reduce_power_loaded
= true;
330 goto skip_reduce_power
;
334 ret
= iwl_trans_set_reduce_power(trans
, data
, len
);
337 "Failed to set reduce power table %d\n",
342 iwl_init_notification_wait(notif_wait
, &pnvm_wait
,
343 ntf_cmds
, ARRAY_SIZE(ntf_cmds
),
344 iwl_pnvm_complete_fn
, trans
);
346 /* kick the doorbell */
347 iwl_write_umac_prph(trans
, UREG_DOORBELL_TO_ISR6
,
348 UREG_DOORBELL_TO_ISR6_PNVM
);
350 return iwl_wait_notification(notif_wait
, &pnvm_wait
,
351 MVM_UCODE_PNVM_TIMEOUT
);
353 IWL_EXPORT_SYMBOL(iwl_pnvm_load
);