[Intel-wired-lan] [PATCH v7 1/2] ice: reduce time to read Option ROM CIVD data

Paul Menzel pmenzel at molgen.mpg.de
Thu Oct 28 06:43:16 UTC 2021


[Cc: +linux-pci for ideas how to work with Option ROMs]

Dear Jacob,


On 28.10.21 01:22, Jacob Keller wrote:
> During probe and device reset, the ice driver reads some data from the
> NVM image as part of ice_init_nvm. Part of this data includes a section
> of the Option ROM which contains version information.
> 
> The function ice_get_orom_civd_data is used to locate the '$CIV' data
> section of the Option ROM.
> 
> Timing of ice_probe and ice_rebuild indicate that the
> ice_get_orom_civd_data function takes about 10 seconds to finish
> executing.
> 
> The function locates the section by scanning the Option ROM every 512
> bytes. This requires a significant number of NVM read accesses, since
> the Option ROM bank is 500KB. In the worst case it would take about 1000
> reads. Worse, all PFs serialize this operation during reload because of
> acquiring the NVM semaphore.
> 
> The CIVD section is located at the end of the Option ROM image data.
> Unfortunately, the driver has no easy method to determine the offset
> manually. Practical experiments have shown that the data could be at
> a variety of locations, so simply reversing the scanning order is not
> sufficient to reduce the overall read time.
> 
> Instead, copy the entire contents of the Option ROM into memory. This
> allows reading the data using 4Kb pages instead of 512 bytes at a time.
> This reduces the total number of firmware commands by a factor of 8. In
> addition, reading the whole section together at once allows better
> indication to firmware of when we're "done".
> 
> Re-write ice_get_orom_civd_data to allocate virtual memory to store the
> Option ROM data. Copy the entire OptionROM contents at once using

Option ROM

> ice_read_flash_module. Finally, use this memory copy to scan for the
> '$CIV' section.
> 
> This change significantly reduces the time to read the Option ROM CIVD
> section from ~10 seconds down to ~1 second. This has a significant
> impact on the total time to complete a driver rebuild or probe.

Thank you for taking up the challenge and looking into this, and for 
decreasing the time.

OT: Out of curiosity, how does it work on UEFI systems without using 
Compatibility System Mode (CSM) and just “EFI drivers”?

> Signed-off-by: Jacob Keller <jacob.e.keller at intel.com>
> ---
> Changes since v6
> * fix a memory leak
> 
> Changes since v5
> * new patch
> 
>   drivers/net/ethernet/intel/ice/ice_nvm.c | 48 ++++++++++++++++++------
>   1 file changed, 36 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/net/ethernet/intel/ice/ice_nvm.c b/drivers/net/ethernet/intel/ice/ice_nvm.c
> index 941bfce97bf4..c5a39aa8ac94 100644
> --- a/drivers/net/ethernet/intel/ice/ice_nvm.c
> +++ b/drivers/net/ethernet/intel/ice/ice_nvm.c
> @@ -619,7 +619,7 @@ static int
>   ice_get_orom_civd_data(struct ice_hw *hw, enum ice_bank_select bank,
>   		       struct ice_orom_civd_info *civd)
>   {
> -	struct ice_orom_civd_info tmp;
> +	u8 *orom_data;

I know the function names use orom, but oprom is already used in other 
subsystems.

>   	int status;
>   	u32 offset;
>   
> @@ -627,36 +627,60 @@ ice_get_orom_civd_data(struct ice_hw *hw, enum ice_bank_select bank,
>   	 * The first 4 bytes must contain the ASCII characters "$CIV".
>   	 * A simple modulo 256 sum of all of the bytes of the structure must
>   	 * equal 0.
> +	 *
> +	 * The exact location is unknown and varies between images but is
> +	 * usually somewhere in the middle of the bank. We need to scan the
> +	 * Option ROM bank to locate it.
> +	 *
> +	 * It's significantly faster to read the entire Option ROM up front
> +	 * using the maximum page size, than to read each possible location
> +	 * with a separate firmware command.
>   	 */
> +	orom_data = vzalloc(hw->flash.banks.orom_size);
> +	if (!orom_data)
> +		return -ENOMEM;
> +
> +	status = ice_read_flash_module(hw, bank, ICE_SR_1ST_OROM_BANK_PTR, 0,
> +				       orom_data, hw->flash.banks.orom_size);
> +	if (status) {
> +		ice_debug(hw, ICE_DBG_NVM, "Unable to read Option ROM data\n");
> +		return status;
> +	}
> +
> +	/* Scan the memory buffer to locate the CIVD data section */
>   	for (offset = 0; (offset + 512) <= hw->flash.banks.orom_size; offset += 512) {
> +		struct ice_orom_civd_info *tmp;
>   		u8 sum = 0, i;
>   
> -		status = ice_read_flash_module(hw, bank, ICE_SR_1ST_OROM_BANK_PTR,
> -					       offset, (u8 *)&tmp, sizeof(tmp));
> -		if (status) {
> -			ice_debug(hw, ICE_DBG_NVM, "Unable to read Option ROM CIVD data\n");
> -			return status;
> -		}
> +		tmp = (struct ice_orom_civd_info *)&orom_data[offset];
>   
>   		/* Skip forward until we find a matching signature */
> -		if (memcmp("$CIV", tmp.signature, sizeof(tmp.signature)) != 0)
> +		if (memcmp("$CIV", tmp->signature, sizeof(tmp->signature)) != 0)
>   			continue;
>   
> +		ice_debug(hw, ICE_DBG_NVM, "Found CIVD section at offset %u\n",
> +			  offset);
> +
>   		/* Verify that the simple checksum is zero */
> -		for (i = 0; i < sizeof(tmp); i++)
> +		for (i = 0; i < sizeof(*tmp); i++)
>   			/* cppcheck-suppress objectIndex */
> -			sum += ((u8 *)&tmp)[i];
> +			sum += ((u8 *)tmp)[i];
>   
>   		if (sum) {
>   			ice_debug(hw, ICE_DBG_NVM, "Found CIVD data with invalid checksum of %u\n",
>   				  sum);
> -			return -EIO;
> +			goto err_invalid_checksum;
>   		}
>   
> -		*civd = tmp;
> +		*civd = *tmp;
> +		vfree(orom_data);
>   		return 0;
>   	}
>   
> +	ice_debug(hw, ICE_DBG_NVM, "Unable to locate CIVD data within the Option ROM\n");
> +
> +err_invalid_checksum:
> +	vfree(orom_data);
>   	return -EIO;
>   }

Please excuse my ignorance. I would have though, that the system 
firmware already put that Option ROM into memory. There is a function 
`pci_map_biosrom()` declared in `arch/x86/include/asm/probe_roms.h` and 
implemented in `arch/x86/kernel/probe_roms.c`, which might be used?


Kind regards,

Paul



More information about the Intel-wired-lan mailing list