File Index
Files and directories
Sign in
FILE

efx_reflash.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/sfc/efx_reflash.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/****************************************************************************
  3 * Driver for AMD network controllers and boards
  4 * Copyright (C) 2025, Advanced Micro Devices, Inc.
  5 *
  6 * This program is free software; you can redistribute it and/or modify it
  7 * under the terms of the GNU General Public License version 2 as published
  8 * by the Free Software Foundation, incorporated herein by reference.
  9 */
 10
 11#include <linux/crc32.h>
 12#include <net/devlink.h>
 13#include "efx_reflash.h"
 14#include "net_driver.h"
 15#include "fw_formats.h"
 16#include "mcdi_pcol.h"
 17#include "mcdi.h"
 18
 19/* Try to parse a Reflash header at the specified offset */
 20static bool efx_reflash_parse_reflash_header(const struct firmware *fw,
 21					     size_t header_offset, u32 *type,
 22					     u32 *subtype, const u8 **data,
 23					     size_t *data_size)
 24{
 25	size_t header_end, trailer_offset, trailer_end;
 26	u32 magic, version, payload_size, header_len;
 27	const u8 *header, *trailer;
 28	u32 expected_crc, crc;
 29
 30	if (check_add_overflow(header_offset, EFX_REFLASH_HEADER_LENGTH_OFST +
 31					      EFX_REFLASH_HEADER_LENGTH_LEN,
 32			       &header_end))
 33		return false;
 34	if (fw->size < header_end)
 35		return false;
 36
 37	header = fw->data + header_offset;
 38	magic = get_unaligned_le32(header + EFX_REFLASH_HEADER_MAGIC_OFST);
 39	if (magic != EFX_REFLASH_HEADER_MAGIC_VALUE)
 40		return false;
 41
 42	version = get_unaligned_le32(header + EFX_REFLASH_HEADER_VERSION_OFST);
 43	if (version != EFX_REFLASH_HEADER_VERSION_VALUE)
 44		return false;
 45
 46	payload_size = get_unaligned_le32(header + EFX_REFLASH_HEADER_PAYLOAD_SIZE_OFST);
 47	header_len = get_unaligned_le32(header + EFX_REFLASH_HEADER_LENGTH_OFST);
 48	if (check_add_overflow(header_offset, header_len, &trailer_offset) ||
 49	    check_add_overflow(trailer_offset, payload_size, &trailer_offset) ||
 50	    check_add_overflow(trailer_offset, EFX_REFLASH_TRAILER_LEN,
 51			       &trailer_end))
 52		return false;
 53	if (fw->size < trailer_end)
 54		return false;
 55
 56	trailer = fw->data + trailer_offset;
 57	expected_crc = get_unaligned_le32(trailer + EFX_REFLASH_TRAILER_CRC_OFST);
 58	/* Addition could overflow u32, but not size_t since we already
 59	 * checked trailer_offset didn't overflow.  So cast to size_t first.
 60	 */
 61	crc = crc32_le(0, header, (size_t)header_len + payload_size);
 62	if (crc != expected_crc)
 63		return false;
 64
 65	*type = get_unaligned_le32(header + EFX_REFLASH_HEADER_FIRMWARE_TYPE_OFST);
 66	*subtype = get_unaligned_le32(header + EFX_REFLASH_HEADER_FIRMWARE_SUBTYPE_OFST);
 67	if (*type == EFX_REFLASH_FIRMWARE_TYPE_BUNDLE) {
 68		/* All the bundle data is written verbatim to NVRAM */
 69		*data = fw->data;
 70		*data_size = fw->size;
 71	} else {
 72		/* Other payload types strip the reflash header and trailer
 73		 * from the data written to NVRAM
 74		 */
 75		*data = header + header_len;
 76		*data_size = payload_size;
 77	}
 78
 79	return true;
 80}
 81
 82/* Map from FIRMWARE_TYPE to NVRAM_PARTITION_TYPE */
 83static int efx_reflash_partition_type(u32 type, u32 subtype,
 84				      u32 *partition_type,
 85				      u32 *partition_subtype)
 86{
 87	int rc = 0;
 88
 89	switch (type) {
 90	case EFX_REFLASH_FIRMWARE_TYPE_BOOTROM:
 91		*partition_type = NVRAM_PARTITION_TYPE_EXPANSION_ROM;
 92		*partition_subtype = subtype;
 93		break;
 94	case EFX_REFLASH_FIRMWARE_TYPE_BUNDLE:
 95		*partition_type = NVRAM_PARTITION_TYPE_BUNDLE;
 96		*partition_subtype = subtype;
 97		break;
 98	default:
 99		/* Not supported */
100		rc = -EINVAL;
101	}
102
103	return rc;
104}
105
106/* Try to parse a SmartNIC image header at the specified offset */
107static bool efx_reflash_parse_snic_header(const struct firmware *fw,
108					  size_t header_offset,
109					  u32 *partition_type,
110					  u32 *partition_subtype,
111					  const u8 **data, size_t *data_size)
112{
113	u32 magic, version, payload_size, header_len, expected_crc, crc;
114	size_t header_end, payload_end;
115	const u8 *header;
116
117	if (check_add_overflow(header_offset, EFX_SNICIMAGE_HEADER_MINLEN,
118			       &header_end) ||
119	    fw->size < header_end)
120		return false;
121
122	header = fw->data + header_offset;
123	magic = get_unaligned_le32(header + EFX_SNICIMAGE_HEADER_MAGIC_OFST);
124	if (magic != EFX_SNICIMAGE_HEADER_MAGIC_VALUE)
125		return false;
126
127	version = get_unaligned_le32(header + EFX_SNICIMAGE_HEADER_VERSION_OFST);
128	if (version != EFX_SNICIMAGE_HEADER_VERSION_VALUE)
129		return false;
130
131	header_len = get_unaligned_le32(header + EFX_SNICIMAGE_HEADER_LENGTH_OFST);
132	if (check_add_overflow(header_offset, header_len, &header_end))
133		return false;
134	payload_size = get_unaligned_le32(header + EFX_SNICIMAGE_HEADER_PAYLOAD_SIZE_OFST);
135	if (check_add_overflow(header_end, payload_size, &payload_end) ||
136	    fw->size < payload_end)
137		return false;
138
139	expected_crc = get_unaligned_le32(header + EFX_SNICIMAGE_HEADER_CRC_OFST);
140
141	/* Calculate CRC omitting the expected CRC field itself */
142	crc = crc32_le(~0, header, EFX_SNICIMAGE_HEADER_CRC_OFST);
143	crc = ~crc32_le(crc,
144			header + EFX_SNICIMAGE_HEADER_CRC_OFST +
145			EFX_SNICIMAGE_HEADER_CRC_LEN,
146			header_len + payload_size - EFX_SNICIMAGE_HEADER_CRC_OFST -
147			EFX_SNICIMAGE_HEADER_CRC_LEN);
148	if (crc != expected_crc)
149		return false;
150
151	*partition_type =
152		get_unaligned_le32(header + EFX_SNICIMAGE_HEADER_PARTITION_TYPE_OFST);
153	*partition_subtype =
154		get_unaligned_le32(header + EFX_SNICIMAGE_HEADER_PARTITION_SUBTYPE_OFST);
155	*data = fw->data;
156	*data_size = fw->size;
157	return true;
158}
159
160/* Try to parse a SmartNIC bundle header at the specified offset */
161static bool efx_reflash_parse_snic_bundle_header(const struct firmware *fw,
162						 size_t header_offset,
163						 u32 *partition_type,
164						 u32 *partition_subtype,
165						 const u8 **data,
166						 size_t *data_size)
167{
168	u32 magic, version, bundle_type, header_len, expected_crc, crc;
169	size_t header_end;
170	const u8 *header;
171
172	if (check_add_overflow(header_offset, EFX_SNICBUNDLE_HEADER_LEN,
173			       &header_end))
174		return false;
175	if (fw->size < header_end)
176		return false;
177
178	header = fw->data + header_offset;
179	magic = get_unaligned_le32(header + EFX_SNICBUNDLE_HEADER_MAGIC_OFST);
180	if (magic != EFX_SNICBUNDLE_HEADER_MAGIC_VALUE)
181		return false;
182
183	version = get_unaligned_le32(header + EFX_SNICBUNDLE_HEADER_VERSION_OFST);
184	if (version != EFX_SNICBUNDLE_HEADER_VERSION_VALUE)
185		return false;
186
187	bundle_type = get_unaligned_le32(header + EFX_SNICBUNDLE_HEADER_BUNDLE_TYPE_OFST);
188	if (bundle_type != NVRAM_PARTITION_TYPE_BUNDLE)
189		return false;
190
191	header_len = get_unaligned_le32(header + EFX_SNICBUNDLE_HEADER_LENGTH_OFST);
192	if (header_len != EFX_SNICBUNDLE_HEADER_LEN)
193		return false;
194
195	expected_crc = get_unaligned_le32(header + EFX_SNICBUNDLE_HEADER_CRC_OFST);
196	crc = ~crc32_le(~0, header, EFX_SNICBUNDLE_HEADER_CRC_OFST);
197	if (crc != expected_crc)
198		return false;
199
200	*partition_type = NVRAM_PARTITION_TYPE_BUNDLE;
201	*partition_subtype = get_unaligned_le32(header + EFX_SNICBUNDLE_HEADER_BUNDLE_SUBTYPE_OFST);
202	*data = fw->data;
203	*data_size = fw->size;
204	return true;
205}
206
207/* Try to find a valid firmware payload in the firmware data.
208 * When we recognise a valid header, we parse it for the partition type
209 * (so we know where to ask the MC to write it to) and the location of
210 * the data blob to write.
211 */
212static int efx_reflash_parse_firmware_data(const struct firmware *fw,
213					   u32 *partition_type,
214					   u32 *partition_subtype,
215					   const u8 **data, size_t *data_size)
216{
217	size_t header_offset;
218	u32 type, subtype;
219
220	/* Some packaging formats (such as CMS/PKCS#7 signed images)
221	 * prepend a header for which finding the size is a non-trivial
222	 * task, so step through the firmware data until we find a valid
223	 * header.
224	 *
225	 * The checks are intended to reject firmware data that is clearly not
226	 * in the expected format.  They do not need to be exhaustive as the
227	 * running firmware will perform its own comprehensive validity and
228	 * compatibility checks during the update procedure.
229	 *
230	 * Firmware packages may contain multiple reflash images, e.g. a
231	 * bundle containing one or more other images.  Only check the
232	 * outermost container by stopping after the first candidate image
233	 * found even it is for an unsupported partition type.
234	 */
235	for (header_offset = 0; header_offset < fw->size; header_offset++) {
236		if (efx_reflash_parse_snic_bundle_header(fw, header_offset,
237							 partition_type,
238							 partition_subtype,
239							 data, data_size))
240			return 0;
241
242		if (efx_reflash_parse_snic_header(fw, header_offset,
243						  partition_type,
244						  partition_subtype, data,
245						  data_size))
246			return 0;
247
248		if (efx_reflash_parse_reflash_header(fw, header_offset, &type,
249						     &subtype, data, data_size))
250			return efx_reflash_partition_type(type, subtype,
251							  partition_type,
252							  partition_subtype);
253	}
254
255	return -EINVAL;
256}
257
258/* Limit the number of status updates during the erase or write phases */
259#define EFX_DEVLINK_STATUS_UPDATE_COUNT		50
260
261/* Expected timeout for the efx_mcdi_nvram_update_finish_polled() */
262#define EFX_DEVLINK_UPDATE_FINISH_TIMEOUT	900
263
264/* Ideal erase chunk size.  This is a balance between minimising the number of
265 * MCDI requests to erase an entire partition whilst avoiding tripping the MCDI
266 * RPC timeout.
267 */
268#define EFX_NVRAM_ERASE_IDEAL_CHUNK_SIZE	(64 * 1024)
269
270static int efx_reflash_erase_partition(struct efx_nic *efx,
271				       struct netlink_ext_ack *extack,
272				       struct devlink *devlink, u32 type,
273				       size_t partition_size,
274				       size_t align)
275{
276	size_t chunk, offset, next_update;
277	int rc;
278
279	/* Partitions that cannot be erased or do not require erase before
280	 * write are advertised with a erase alignment/sector size of zero.
281	 */
282	if (align == 0)
283		/* Nothing to do */
284		return 0;
285
286	if (partition_size % align)
287		return -EINVAL;
288
289	/* Erase the entire NVRAM partition a chunk at a time to avoid
290	 * potentially tripping the MCDI RPC timeout.
291	 */
292	if (align >= EFX_NVRAM_ERASE_IDEAL_CHUNK_SIZE)
293		chunk = align;
294	else
295		chunk = rounddown(EFX_NVRAM_ERASE_IDEAL_CHUNK_SIZE, align);
296
297	for (offset = 0, next_update = 0; offset < partition_size; offset += chunk) {
298		if (offset >= next_update) {
299			devlink_flash_update_status_notify(devlink, "Erasing",
300							   NULL, offset,
301							   partition_size);
302			next_update += partition_size / EFX_DEVLINK_STATUS_UPDATE_COUNT;
303		}
304
305		chunk = min_t(size_t, partition_size - offset, chunk);
306		rc = efx_mcdi_nvram_erase(efx, type, offset, chunk);
307		if (rc) {
308			NL_SET_ERR_MSG_FMT_MOD(extack,
309					       "Erase failed for NVRAM partition %#x at %#zx-%#zx",
310					       type, offset, offset + chunk - 1);
311			return rc;
312		}
313	}
314
315	devlink_flash_update_status_notify(devlink, "Erasing", NULL,
316					   partition_size, partition_size);
317
318	return 0;
319}
320
321static int efx_reflash_write_partition(struct efx_nic *efx,
322				       struct netlink_ext_ack *extack,
323				       struct devlink *devlink, u32 type,
324				       const u8 *data, size_t data_size,
325				       size_t align)
326{
327	size_t write_max, chunk, offset, next_update;
328	int rc;
329
330	if (align == 0)
331		return -EINVAL;
332
333	/* Write the NVRAM partition in chunks that are the largest multiple
334	 * of the partition's required write alignment that will fit into the
335	 * MCDI NVRAM_WRITE RPC payload.
336	 */
337	if (efx->type->mcdi_max_ver < 2)
338		write_max = MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_LEN *
339			    MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_MAXNUM;
340	else
341		write_max = MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_LEN *
342			    MC_CMD_NVRAM_WRITE_IN_WRITE_BUFFER_MAXNUM_MCDI2;
343	chunk = rounddown(write_max, align);
344
345	for (offset = 0, next_update = 0; offset + chunk <= data_size; offset += chunk) {
346		if (offset >= next_update) {
347			devlink_flash_update_status_notify(devlink, "Writing",
348							   NULL, offset,
349							   data_size);
350			next_update += data_size / EFX_DEVLINK_STATUS_UPDATE_COUNT;
351		}
352
353		rc = efx_mcdi_nvram_write(efx, type, offset, data + offset, chunk);
354		if (rc) {
355			NL_SET_ERR_MSG_FMT_MOD(extack,
356					       "Write failed for NVRAM partition %#x at %#zx-%#zx",
357					       type, offset, offset + chunk - 1);
358			return rc;
359		}
360	}
361
362	/* Round up left over data to satisfy write alignment */
363	if (offset < data_size) {
364		size_t remaining = data_size - offset;
365		u8 *buf;
366
367		if (offset >= next_update)
368			devlink_flash_update_status_notify(devlink, "Writing",
369							   NULL, offset,
370							   data_size);
371
372		chunk = roundup(remaining, align);
373		buf = kmalloc(chunk, GFP_KERNEL);
374		if (!buf)
375			return -ENOMEM;
376
377		memcpy(buf, data + offset, remaining);
378		memset(buf + remaining, 0xFF, chunk - remaining);
379		rc = efx_mcdi_nvram_write(efx, type, offset, buf, chunk);
380		kfree(buf);
381		if (rc) {
382			NL_SET_ERR_MSG_FMT_MOD(extack,
383					       "Write failed for NVRAM partition %#x at %#zx-%#zx",
384					       type, offset, offset + chunk - 1);
385			return rc;
386		}
387	}
388
389	devlink_flash_update_status_notify(devlink, "Writing", NULL, data_size,
390					   data_size);
391
392	return 0;
393}
394
395int efx_reflash_flash_firmware(struct efx_nic *efx, const struct firmware *fw,
396			       struct netlink_ext_ack *extack)
397{
398	size_t data_size, size, erase_align, write_align;
399	struct devlink *devlink = efx->devlink;
400	u32 type, data_subtype, subtype;
401	const u8 *data;
402	bool protected;
403	int rc;
404
405	if (!efx_has_cap(efx, BUNDLE_UPDATE)) {
406		NL_SET_ERR_MSG_MOD(extack, "NVRAM bundle updates are not supported by the firmware");
407		return -EOPNOTSUPP;
408	}
409
410	mutex_lock(&efx->reflash_mutex);
411
412	devlink_flash_update_status_notify(devlink, "Checking update", NULL, 0, 0);
413
414	if (efx->type->flash_auto_partition) {
415		/* NIC wants entire FW file including headers;
416		 * FW will validate 'subtype' if there is one
417		 */
418		type = NVRAM_PARTITION_TYPE_AUTO;
419		data = fw->data;
420		data_size = fw->size;
421	} else {
422		rc = efx_reflash_parse_firmware_data(fw, &type, &data_subtype, &data,
423						     &data_size);
424		if (rc) {
425			NL_SET_ERR_MSG_MOD(extack,
426					   "Firmware image validation check failed");
427			goto out_unlock;
428		}
429
430		rc = efx_mcdi_nvram_metadata(efx, type, &subtype, NULL, NULL, 0);
431		if (rc) {
432			NL_SET_ERR_MSG_FMT_MOD(extack,
433					       "Metadata query for NVRAM partition %#x failed",
434					       type);
435			goto out_unlock;
436		}
437
438		if (subtype != data_subtype) {
439			NL_SET_ERR_MSG_MOD(extack,
440					   "Firmware image is not appropriate for this adapter");
441			rc = -EINVAL;
442			goto out_unlock;
443		}
444	}
445
446	rc = efx_mcdi_nvram_info(efx, type, &size, &erase_align, &write_align,
447				 &protected);
448	if (rc) {
449		NL_SET_ERR_MSG_FMT_MOD(extack,
450				       "Info query for NVRAM partition %#x failed",
451				       type);
452		goto out_unlock;
453	}
454
455	if (protected) {
456		NL_SET_ERR_MSG_FMT_MOD(extack,
457				       "NVRAM partition %#x is protected",
458				       type);
459		rc = -EPERM;
460		goto out_unlock;
461	}
462
463	if (write_align == 0) {
464		NL_SET_ERR_MSG_FMT_MOD(extack,
465				       "NVRAM partition %#x is not writable",
466				       type);
467		rc = -EACCES;
468		goto out_unlock;
469	}
470
471	if (erase_align != 0 && size % erase_align) {
472		NL_SET_ERR_MSG_FMT_MOD(extack,
473				       "NVRAM partition %#x has a bad partition table entry, can't erase it",
474				       type);
475		rc = -EACCES;
476		goto out_unlock;
477	}
478
479	if (data_size > size) {
480		NL_SET_ERR_MSG_FMT_MOD(extack,
481				       "Firmware image is too big for NVRAM partition %#x",
482				       type);
483		rc = -EFBIG;
484		goto out_unlock;
485	}
486
487	devlink_flash_update_status_notify(devlink, "Starting update", NULL, 0, 0);
488
489	rc = efx_mcdi_nvram_update_start(efx, type);
490	if (rc) {
491		NL_SET_ERR_MSG_FMT_MOD(extack,
492				       "Update start request for NVRAM partition %#x failed",
493				       type);
494		goto out_unlock;
495	}
496
497	rc = efx_reflash_erase_partition(efx, extack, devlink, type, size,
498					 erase_align);
499	if (rc)
500		goto out_update_finish;
501
502	rc = efx_reflash_write_partition(efx, extack, devlink, type, data,
503					 data_size, write_align);
504	if (rc)
505		goto out_update_finish;
506
507	devlink_flash_update_timeout_notify(devlink, "Finishing update", NULL,
508					    EFX_DEVLINK_UPDATE_FINISH_TIMEOUT);
509
510out_update_finish:
511	if (rc)
512		/* Don't obscure the return code from an earlier failure */
513		efx_mcdi_nvram_update_finish(efx, type, EFX_UPDATE_FINISH_ABORT);
514	else
515		rc = efx_mcdi_nvram_update_finish_polled(efx, type);
516out_unlock:
517	mutex_unlock(&efx->reflash_mutex);
518	devlink_flash_update_status_notify(devlink, rc ? "Update failed" :
519							 "Update complete",
520					   NULL, 0, 0);
521	return rc;
522}
~/ Read-only file preview.