@@ -255,13 +255,151 @@ static int efx_reflash_parse_firmware_data(const struct firmware *fw,
255255 return - EINVAL ;
256256}
257257
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+
270+ static 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+
321+ static 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+
258395int efx_reflash_flash_firmware (struct efx_nic * efx , const struct firmware * fw ,
259396 struct netlink_ext_ack * extack )
260397{
398+ size_t data_size , size , erase_align , write_align ;
261399 struct devlink * devlink = efx -> devlink ;
262- u32 type , data_subtype ;
263- size_t data_size ;
400+ u32 type , data_subtype , subtype ;
264401 const u8 * data ;
402+ bool protected ;
265403 int rc ;
266404
267405 if (!efx_has_cap (efx , BUNDLE_UPDATE )) {
@@ -279,8 +417,95 @@ int efx_reflash_flash_firmware(struct efx_nic *efx, const struct firmware *fw,
279417 goto out ;
280418 }
281419
282- rc = - EOPNOTSUPP ;
420+ mutex_lock (& efx -> reflash_mutex );
421+
422+ rc = efx_mcdi_nvram_metadata (efx , type , & subtype , NULL , NULL , 0 );
423+ if (rc ) {
424+ NL_SET_ERR_MSG_FMT_MOD (extack ,
425+ "Metadata query for NVRAM partition %#x failed" ,
426+ type );
427+ goto out_unlock ;
428+ }
429+
430+ if (subtype != data_subtype ) {
431+ NL_SET_ERR_MSG_MOD (extack ,
432+ "Firmware image is not appropriate for this adapter" );
433+ rc = - EINVAL ;
434+ goto out_unlock ;
435+ }
436+
437+ rc = efx_mcdi_nvram_info (efx , type , & size , & erase_align , & write_align ,
438+ & protected );
439+ if (rc ) {
440+ NL_SET_ERR_MSG_FMT_MOD (extack ,
441+ "Info query for NVRAM partition %#x failed" ,
442+ type );
443+ goto out_unlock ;
444+ }
445+
446+ if (protected ) {
447+ NL_SET_ERR_MSG_FMT_MOD (extack ,
448+ "NVRAM partition %#x is protected" ,
449+ type );
450+ rc = - EPERM ;
451+ goto out_unlock ;
452+ }
453+
454+ if (write_align == 0 ) {
455+ NL_SET_ERR_MSG_FMT_MOD (extack ,
456+ "NVRAM partition %#x is not writable" ,
457+ type );
458+ rc = - EACCES ;
459+ goto out_unlock ;
460+ }
461+
462+ if (erase_align != 0 && size % erase_align ) {
463+ NL_SET_ERR_MSG_FMT_MOD (extack ,
464+ "NVRAM partition %#x has a bad partition table entry, can't erase it" ,
465+ type );
466+ rc = - EACCES ;
467+ goto out_unlock ;
468+ }
469+
470+ if (data_size > size ) {
471+ NL_SET_ERR_MSG_FMT_MOD (extack ,
472+ "Firmware image is too big for NVRAM partition %#x" ,
473+ type );
474+ rc = - EFBIG ;
475+ goto out_unlock ;
476+ }
477+
478+ devlink_flash_update_status_notify (devlink , "Starting update" , NULL , 0 , 0 );
479+
480+ rc = efx_mcdi_nvram_update_start (efx , type );
481+ if (rc ) {
482+ NL_SET_ERR_MSG_FMT_MOD (extack ,
483+ "Update start request for NVRAM partition %#x failed" ,
484+ type );
485+ goto out_unlock ;
486+ }
283487
488+ rc = efx_reflash_erase_partition (efx , extack , devlink , type , size ,
489+ erase_align );
490+ if (rc )
491+ goto out_update_finish ;
492+
493+ rc = efx_reflash_write_partition (efx , extack , devlink , type , data ,
494+ data_size , write_align );
495+ if (rc )
496+ goto out_update_finish ;
497+
498+ devlink_flash_update_timeout_notify (devlink , "Finishing update" , NULL ,
499+ EFX_DEVLINK_UPDATE_FINISH_TIMEOUT );
500+
501+ out_update_finish :
502+ if (rc )
503+ /* Don't obscure the return code from an earlier failure */
504+ efx_mcdi_nvram_update_finish (efx , type , EFX_UPDATE_FINISH_ABORT );
505+ else
506+ rc = efx_mcdi_nvram_update_finish_polled (efx , type );
507+ out_unlock :
508+ mutex_unlock (& efx -> reflash_mutex );
284509out :
285510 devlink_flash_update_status_notify (devlink , rc ? "Update failed" :
286511 "Update complete" ,
0 commit comments