Re: [PATCH 13/16] gpu: nova-core: Add support for VBIOS ucode extraction for boot

Danilo Krummrich
2025-04-23T15:03:06Z

On Wed, Apr 23, 2025 at 10:52:42AM -0400, Joel Fernandes wrote:
> Hello, Danilo,
> Thanks for all the feedback. Due to the volume of feedback, I will respond
> incrementally in multiple emails so we can discuss as we go - hope that's Ok but
> let me know if that is annoying.

That's perfectly fine, whatever works best for you. :)

> On 4/23/2025 10:06 AM, Danilo Krummrich wrote:
>
> >> +impl Vbios {
> >> + /// Read bytes from the ROM at the current end of the data vector
> >> + fn read_more(bar0: &Devres<Bar0>, data: &mut KVec<u8>, len: usize) -> Result {
> >> + let current_len = data.len();
> >> + let start = ROM_OFFSET + current_len;
> >> +
> >> + // Ensure length is a multiple of 4 for 32-bit reads
> >> + if len % core::mem::size_of::<u32>() != 0 {
> >> + pr_err!("VBIOS read length {} is not a multiple of 4\n", len);
> >
> > Please don't use any of the pr_*() print macros within a driver, use the dev_*()
> > ones instead.
>
> Ok I'll switch to this. One slight complication is I've to retrieve the 'dev'
> from the Bar0 and pass that along, but that should be doable.

You can also pass the pci::Device reference to VBios::probe() directly.

>
> >
> >> + return Err(EINVAL);
> >> + }
> >> +
> >> + // Allocate and zero-initialize the required memory
> >
> > That's obvious from the code, if you feel this needs a comment, better explain
> > what we need it for, why zero-initialize, etc.
>
> Sure, actually the extends_with() is a performance optimization as we want to do
> only a single allocation and then fill in the allocated data. It has nothing to
> do with 0-initializing per-se. I will adjust the comment, but:
>
> This code...
>
> >> + data.extend_with(len, 0, GFP_KERNEL)?;
> >> + with_bar!(?bar0, |bar0_ref| {
> >> + let dst = &mut data[current_len..current_len + len];
> >> + for (idx, chunk) in dst
> >> + .chunks_exact_mut(core::mem::size_of::<u32>())
> >> + .enumerate()
> >> + {
> >> + let addr = start + (idx * core::mem::size_of::<u32>());
> >> + // Convert the u32 to a 4 byte array. We use the .to_ne_bytes()
> >> + // method out of convenience to convert the 32-bit integer as it
> >> + // is in memory into a byte array without any endianness
> >> + // conversion or byte-swapping.
> >> + chunk.copy_from_slice(&bar0_ref.try_read32(addr)?.to_ne_bytes());
> >> + }
> >> + Ok(())
> >> + })?;
> >> +
> >> + Ok(())
> >> + }
> ..actually initially was:
>
> + with_bar!(self.bar0, |bar0| {
> + // Get current length
> + let current_len = self.data.len();
> +
> + // Read ROM data bytes push directly to vector
> + for i in 0..bytes as usize {
> + // Read byte from the VBIOS ROM and push it to the data vector
> + let rom_addr = ROM_OFFSET + current_len + i;
> + let byte = bar0.try_readb(rom_addr)?;
> + self.data.push(byte, GFP_KERNEL)?;
>
> Where this bit could result in a lot of allocation.
>
> There was an unsafe() way of not having to do this but we settled with
> extends_with().
>
> Thoughts?

If I understand you correctly, you just want to make sure that subsequent push()
calls don't re-allocate? If so, you can just use reserve() [1] and keep the
subsequent push() calls.

[1] https://rust.docs.kernel.org/kernel/alloc/kvec/struct.Vec.html#method.reserve