xref: /linux/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
2 /*
3  * Copyright(c) 2020-2026 Intel Corporation
4  */
5 
6 #include "iwl-drv.h"
7 #include "pnvm.h"
8 #include "iwl-prph.h"
9 #include "iwl-io.h"
10 #include "fw/api/commands.h"
11 #include "fw/api/nvm-reg.h"
12 #include "fw/api/alive.h"
13 #include "fw/uefi.h"
14 #include "fw/img.h"
15 #include "fw/dbg.h"
16 
17 #define IWL_PNVM_REDUCED_CAP_BIT BIT(25)
18 
19 struct iwl_pnvm_section {
20 	__le32 offset;
21 	const u8 data[];
22 } __packed;
23 
iwl_pnvm_complete_fn(struct iwl_notif_wait_data * notif_wait,struct iwl_rx_packet * pkt,void * data)24 static bool iwl_pnvm_complete_fn(struct iwl_notif_wait_data *notif_wait,
25 				 struct iwl_rx_packet *pkt, void *data)
26 {
27 	struct iwl_trans *trans = (struct iwl_trans *)data;
28 	struct iwl_pnvm_init_complete_ntfy *pnvm_ntf = (void *)pkt->data;
29 
30 	if (IWL_FW_CHECK(trans,
31 			 iwl_rx_packet_payload_len(pkt) < sizeof(*pnvm_ntf),
32 			 "Bad notif len: %d\n",
33 			 iwl_rx_packet_payload_len(pkt)))
34 		return true;
35 
36 	IWL_DEBUG_FW(trans,
37 		     "PNVM complete notification received with status 0x%0x\n",
38 		     le32_to_cpu(pnvm_ntf->status));
39 
40 	return true;
41 }
42 
iwl_pnvm_handle_section(struct iwl_trans * trans,const u8 * data,size_t len,struct iwl_pnvm_image * pnvm_data)43 static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data,
44 				   size_t len,
45 				   struct iwl_pnvm_image *pnvm_data)
46 {
47 	const struct iwl_ucode_tlv *tlv;
48 	u32 sha1 = 0;
49 	u16 mac_type = 0, rf_id = 0;
50 	bool hw_match = false;
51 
52 	IWL_DEBUG_FW(trans, "Handling PNVM section\n");
53 
54 	memset(pnvm_data, 0, sizeof(*pnvm_data));
55 
56 	while (len >= sizeof(*tlv)) {
57 		u32 tlv_len, tlv_type;
58 
59 		len -= sizeof(*tlv);
60 		tlv = (const void *)data;
61 
62 		tlv_len = le32_to_cpu(tlv->length);
63 		tlv_type = le32_to_cpu(tlv->type);
64 
65 		if (len < tlv_len) {
66 			IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
67 				len, tlv_len);
68 			return -EINVAL;
69 		}
70 
71 		data += sizeof(*tlv);
72 
73 		switch (tlv_type) {
74 		case IWL_UCODE_TLV_PNVM_VERSION:
75 			if (tlv_len < sizeof(__le32)) {
76 				IWL_DEBUG_FW(trans,
77 					     "Invalid size for IWL_UCODE_TLV_PNVM_VERSION (expected %zd, got %d)\n",
78 					     sizeof(__le32), tlv_len);
79 				break;
80 			}
81 
82 			sha1 = le32_to_cpup((const __le32 *)data);
83 
84 			IWL_DEBUG_FW(trans,
85 				     "Got IWL_UCODE_TLV_PNVM_VERSION %0x\n",
86 				     sha1);
87 			pnvm_data->version = sha1;
88 			break;
89 		case IWL_UCODE_TLV_HW_TYPE:
90 			if (tlv_len < 2 * sizeof(__le16)) {
91 				IWL_DEBUG_FW(trans,
92 					     "Invalid size for IWL_UCODE_TLV_HW_TYPE (expected %zd, got %d)\n",
93 					     2 * sizeof(__le16), tlv_len);
94 				break;
95 			}
96 
97 			if (hw_match)
98 				break;
99 
100 			mac_type = le16_to_cpup((const __le16 *)data);
101 			rf_id = le16_to_cpup((const __le16 *)(data + sizeof(__le16)));
102 
103 			IWL_DEBUG_FW(trans,
104 				     "Got IWL_UCODE_TLV_HW_TYPE mac_type 0x%0x rf_id 0x%0x\n",
105 				     mac_type, rf_id);
106 
107 			if (mac_type == CSR_HW_REV_TYPE(trans->info.hw_rev) &&
108 			    rf_id == CSR_HW_RFID_TYPE(trans->info.hw_rf_id))
109 				hw_match = true;
110 			break;
111 		case IWL_UCODE_TLV_SEC_RT: {
112 			const struct iwl_pnvm_section *section = (const void *)data;
113 			u32 data_len = tlv_len - sizeof(*section);
114 
115 			IWL_DEBUG_FW(trans,
116 				     "Got IWL_UCODE_TLV_SEC_RT len %d\n",
117 				     tlv_len);
118 
119 			/* TODO: remove, this is a deprecated separator */
120 			if (le32_to_cpup((const __le32 *)data) == 0xddddeeee) {
121 				IWL_DEBUG_FW(trans, "Ignoring separator.\n");
122 				break;
123 			}
124 
125 			if (pnvm_data->n_chunks == IPC_DRAM_MAP_ENTRY_NUM_MAX) {
126 				IWL_DEBUG_FW(trans,
127 					     "too many payloads to allocate in DRAM.\n");
128 				return -EINVAL;
129 			}
130 
131 			IWL_DEBUG_FW(trans, "Adding data (size %d)\n",
132 				     data_len);
133 
134 			pnvm_data->chunks[pnvm_data->n_chunks].data = section->data;
135 			pnvm_data->chunks[pnvm_data->n_chunks].len = data_len;
136 			pnvm_data->n_chunks++;
137 
138 			break;
139 		}
140 		case IWL_UCODE_TLV_MEM_DESC:
141 			if (iwl_uefi_handle_tlv_mem_desc(trans, data, tlv_len,
142 							 pnvm_data))
143 				return -EINVAL;
144 			break;
145 		case IWL_UCODE_TLV_PNVM_SKU:
146 			IWL_DEBUG_FW(trans,
147 				     "New PNVM section started, stop parsing.\n");
148 			goto done;
149 		default:
150 			IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n",
151 				     tlv_type, tlv_len);
152 			break;
153 		}
154 
155 		len -= ALIGN(tlv_len, 4);
156 		data += ALIGN(tlv_len, 4);
157 	}
158 
159 done:
160 	if (!hw_match) {
161 		IWL_DEBUG_FW(trans,
162 			     "HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n",
163 			     CSR_HW_REV_TYPE(trans->info.hw_rev),
164 			     CSR_HW_RFID_TYPE(trans->info.hw_rf_id));
165 		return -ENOENT;
166 	}
167 
168 	if (!pnvm_data->n_chunks) {
169 		IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n");
170 		return -ENOENT;
171 	}
172 
173 	return 0;
174 }
175 
iwl_pnvm_parse(struct iwl_trans * trans,const u8 * data,size_t len,struct iwl_pnvm_image * pnvm_data,__le32 sku_id[3])176 static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data,
177 			  size_t len,
178 			  struct iwl_pnvm_image *pnvm_data,
179 			  __le32 sku_id[3])
180 {
181 	const struct iwl_ucode_tlv *tlv;
182 
183 	IWL_DEBUG_FW(trans, "Parsing PNVM file\n");
184 
185 	while (len >= sizeof(*tlv)) {
186 		u32 tlv_len, tlv_type;
187 		u32 rf_type;
188 
189 		len -= sizeof(*tlv);
190 		tlv = (const void *)data;
191 
192 		tlv_len = le32_to_cpu(tlv->length);
193 		tlv_type = le32_to_cpu(tlv->type);
194 
195 		if (len < tlv_len) {
196 			IWL_ERR(trans, "invalid TLV len: %zd/%u\n",
197 				len, tlv_len);
198 			return -EINVAL;
199 		}
200 
201 		if (tlv_type == IWL_UCODE_TLV_PNVM_SKU) {
202 			const struct iwl_sku_id *tlv_sku_id =
203 				(const void *)(data + sizeof(*tlv));
204 
205 			IWL_DEBUG_FW(trans,
206 				     "Got IWL_UCODE_TLV_PNVM_SKU len %d\n",
207 				     tlv_len);
208 			if (tlv_len < sizeof(*tlv_sku_id)) {
209 				IWL_ERR(trans, "invalid PNVM SKU TLV len: %u\n",
210 					tlv_len);
211 				return -EINVAL;
212 			}
213 
214 			IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n",
215 				     le32_to_cpu(tlv_sku_id->data[0]),
216 				     le32_to_cpu(tlv_sku_id->data[1]),
217 				     le32_to_cpu(tlv_sku_id->data[2]));
218 
219 			data += sizeof(*tlv) + ALIGN(tlv_len, 4);
220 			len -= ALIGN(tlv_len, 4);
221 
222 			trans->reduced_cap_sku = false;
223 			rf_type = CSR_HW_RFID_TYPE(trans->info.hw_rf_id);
224 			if ((sku_id[0] & cpu_to_le32(IWL_PNVM_REDUCED_CAP_BIT)) &&
225 			    rf_type == IWL_CFG_RF_TYPE_FM)
226 				trans->reduced_cap_sku = true;
227 
228 			IWL_DEBUG_FW(trans,
229 				     "Reduced SKU device %d\n",
230 				     trans->reduced_cap_sku);
231 
232 			if (sku_id[0] == tlv_sku_id->data[0] &&
233 			    sku_id[1] == tlv_sku_id->data[1] &&
234 			    sku_id[2] == tlv_sku_id->data[2]) {
235 				int ret;
236 
237 				ret = iwl_pnvm_handle_section(trans, data, len,
238 							      pnvm_data);
239 				if (!ret)
240 					return 0;
241 			} else {
242 				IWL_DEBUG_FW(trans, "SKU ID didn't match!\n");
243 			}
244 		} else {
245 			data += sizeof(*tlv) + ALIGN(tlv_len, 4);
246 			len -= ALIGN(tlv_len, 4);
247 		}
248 	}
249 
250 	return -ENOENT;
251 }
252 
iwl_pnvm_get_from_fs(struct iwl_trans * trans,size_t * len)253 static u8 *iwl_pnvm_get_from_fs(struct iwl_trans *trans, size_t *len)
254 {
255 	const struct firmware *pnvm;
256 	char pnvm_name[MAX_PNVM_NAME];
257 	size_t new_len;
258 	u8 *data;
259 	int ret;
260 
261 	iwl_pnvm_get_fs_name(trans, pnvm_name, sizeof(pnvm_name));
262 
263 	ret = firmware_request_nowarn(&pnvm, pnvm_name, trans->dev);
264 	if (ret) {
265 		IWL_DEBUG_FW(trans, "PNVM file %s not found %d\n",
266 			     pnvm_name, ret);
267 		return NULL;
268 	}
269 
270 	new_len = pnvm->size;
271 	data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL);
272 	release_firmware(pnvm);
273 
274 	if (!data)
275 		return NULL;
276 
277 	*len = new_len;
278 
279 	return data;
280 }
281 
282 /**
283  * enum iwl_pnvm_source - different PNVM possible sources
284  *
285  * @IWL_PNVM_SOURCE_NONE: No PNVM.
286  * @IWL_PNVM_SOURCE_BIOS: PNVM should be read from BIOS.
287  * @IWL_PNVM_SOURCE_EXTERNAL: read .pnvm external file
288  * @IWL_PNVM_SOURCE_EMBEDDED: PNVM is embedded in the .ucode file.
289  */
290 enum iwl_pnvm_source {
291 	IWL_PNVM_SOURCE_NONE,
292 	IWL_PNVM_SOURCE_BIOS,
293 	IWL_PNVM_SOURCE_EXTERNAL,
294 	IWL_PNVM_SOURCE_EMBEDDED
295 };
296 
iwl_select_pnvm_source(struct iwl_trans * trans,bool intel_sku)297 static enum iwl_pnvm_source iwl_select_pnvm_source(struct iwl_trans *trans,
298 						   bool intel_sku)
299 {
300 
301 	/* Get PNVM from BIOS for non-Intel SKU */
302 	if (!intel_sku)
303 		return IWL_PNVM_SOURCE_BIOS;
304 
305 	/* Before those devices, PNVM didn't exist at all */
306 	if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
307 		return IWL_PNVM_SOURCE_NONE;
308 
309 	/* After those devices, we moved to embedded PNVM */
310 	if (trans->mac_cfg->device_family > IWL_DEVICE_FAMILY_AX210)
311 		return IWL_PNVM_SOURCE_EMBEDDED;
312 
313 	/* For IWL_DEVICE_FAMILY_AX210, depends on the CRF */
314 	if (CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_GF)
315 		return IWL_PNVM_SOURCE_EXTERNAL;
316 
317 	return IWL_PNVM_SOURCE_NONE;
318 }
319 
iwl_get_pnvm_image(struct iwl_trans * trans_p,size_t * len,__le32 sku_id[3],const struct iwl_fw * fw)320 static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len,
321 				    __le32 sku_id[3], const struct iwl_fw *fw)
322 {
323 	struct pnvm_sku_package *package;
324 	enum iwl_pnvm_source pnvm_src =
325 		iwl_select_pnvm_source(trans_p, sku_id[2] == 0);
326 	u8 *image = NULL;
327 
328 	IWL_DEBUG_FW(trans_p, "PNVM source %d\n", pnvm_src);
329 
330 	if (pnvm_src == IWL_PNVM_SOURCE_NONE)
331 		return NULL;
332 
333 	if (pnvm_src == IWL_PNVM_SOURCE_BIOS) {
334 		package = iwl_uefi_get_pnvm(trans_p, len);
335 		if (!IS_ERR_OR_NULL(package)) {
336 			if (*len >= sizeof(*package)) {
337 				/* we need only the data */
338 				*len -= sizeof(*package);
339 				image = kvmemdup(package->data,
340 						 *len, GFP_KERNEL);
341 			}
342 			/*
343 			 * free package regardless of whether kmemdup
344 			 * succeeded
345 			 */
346 			kfree(package);
347 			if (image)
348 				return image;
349 		}
350 
351 		/* PNVM doesn't exist in BIOS. Find the fallback source */
352 		pnvm_src = iwl_select_pnvm_source(trans_p, true);
353 		IWL_DEBUG_FW(trans_p, "PNVM in BIOS doesn't exist, try %d\n",
354 			     pnvm_src);
355 	}
356 
357 	if (pnvm_src == IWL_PNVM_SOURCE_EXTERNAL) {
358 		image = iwl_pnvm_get_from_fs(trans_p, len);
359 		if (image)
360 			return image;
361 	}
362 
363 	if (pnvm_src == IWL_PNVM_SOURCE_EMBEDDED && fw->pnvm_data) {
364 		*len = fw->pnvm_size;
365 		return fw->pnvm_data;
366 	}
367 
368 	IWL_ERR(trans_p, "Couldn't get PNVM from required source: %d\n", pnvm_src);
369 	return NULL;
370 }
371 
372 static void
iwl_pnvm_load_pnvm_to_trans(struct iwl_trans * trans,const struct iwl_fw * fw,__le32 sku_id[3])373 iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
374 			    const struct iwl_fw *fw,
375 			    __le32 sku_id[3])
376 {
377 	struct iwl_pnvm_image *pnvm_data = NULL;
378 	const u8 *data = NULL;
379 	size_t length;
380 	int ret;
381 
382 	/* failed to get/parse the image in the past, no use trying again */
383 	if (trans->fail_to_parse_pnvm_image)
384 		return;
385 
386 	if (trans->pnvm_loaded)
387 		goto set;
388 
389 	data = iwl_get_pnvm_image(trans, &length, sku_id, fw);
390 	if (!data) {
391 		trans->fail_to_parse_pnvm_image = true;
392 		return;
393 	}
394 
395 	pnvm_data = kzalloc_obj(*pnvm_data);
396 	if (!pnvm_data)
397 		goto free;
398 
399 	ret = iwl_pnvm_parse(trans, data, length, pnvm_data, sku_id);
400 	if (ret) {
401 		trans->fail_to_parse_pnvm_image = true;
402 		goto free;
403 	}
404 
405 	ret = iwl_trans_load_pnvm(trans, pnvm_data, &fw->ucode_capa);
406 	if (ret)
407 		goto free;
408 	IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version);
409 
410 set:
411 	iwl_trans_set_pnvm(trans, &fw->ucode_capa);
412 free:
413 	/* free only if it was allocated, i.e. not just embedded PNVM data */
414 	if (data != fw->pnvm_data)
415 		kvfree(data);
416 	kfree(pnvm_data);
417 }
418 
419 static void
iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans * trans,const struct iwl_ucode_capabilities * capa,__le32 sku_id[3])420 iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans,
421 				    const struct iwl_ucode_capabilities *capa,
422 				    __le32 sku_id[3])
423 {
424 	struct iwl_pnvm_image *pnvm_data = NULL;
425 	u8 *data = NULL;
426 	size_t length;
427 	int ret;
428 
429 	if (trans->failed_to_load_reduce_power_image)
430 		return;
431 
432 	if (trans->reduce_power_loaded)
433 		goto set;
434 
435 	data = iwl_uefi_get_reduced_power(trans, &length);
436 	if (IS_ERR(data)) {
437 		trans->failed_to_load_reduce_power_image = true;
438 		return;
439 	}
440 
441 	pnvm_data = kzalloc_obj(*pnvm_data);
442 	if (!pnvm_data)
443 		goto free;
444 
445 	ret = iwl_uefi_reduce_power_parse(trans, data, length, pnvm_data,
446 					  sku_id);
447 	if (ret) {
448 		trans->failed_to_load_reduce_power_image = true;
449 		goto free;
450 	}
451 
452 	ret = iwl_trans_load_reduce_power(trans, pnvm_data, capa);
453 	if (ret) {
454 		IWL_DEBUG_FW(trans,
455 			     "Failed to load reduce power table %d\n",
456 			     ret);
457 		trans->failed_to_load_reduce_power_image = true;
458 		goto free;
459 	}
460 
461 set:
462 	iwl_trans_set_reduce_power(trans, capa);
463 free:
464 	kfree(data);
465 	kfree(pnvm_data);
466 }
467 
iwl_pnvm_load(struct iwl_trans * trans,struct iwl_notif_wait_data * notif_wait,const struct iwl_fw * fw,__le32 sku_id[3])468 int iwl_pnvm_load(struct iwl_trans *trans,
469 		  struct iwl_notif_wait_data *notif_wait,
470 		  const struct iwl_fw *fw, __le32 sku_id[3])
471 {
472 	struct iwl_notification_wait pnvm_wait;
473 	static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP,
474 						PNVM_INIT_COMPLETE_NTFY) };
475 
476 	/* if the SKU_ID is empty, there's nothing to do */
477 	if (!sku_id[0] && !sku_id[1] && !sku_id[2])
478 		return 0;
479 
480 	iwl_pnvm_load_pnvm_to_trans(trans, fw, sku_id);
481 	iwl_pnvm_load_reduce_power_to_trans(trans, &fw->ucode_capa, sku_id);
482 
483 	iwl_init_notification_wait(notif_wait, &pnvm_wait,
484 				   ntf_cmds, ARRAY_SIZE(ntf_cmds),
485 				   iwl_pnvm_complete_fn, trans);
486 
487 	/* kick the doorbell */
488 	iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6,
489 			    UREG_DOORBELL_TO_ISR6_PNVM);
490 
491 	return iwl_wait_notification(notif_wait, &pnvm_wait,
492 				     MVM_UCODE_PNVM_TIMEOUT);
493 }
494 IWL_EXPORT_SYMBOL(iwl_pnvm_load);
495