rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Danilo Krummrich <dakr@kernel.org>
To: Joel Fernandes <joelagnelf@nvidia.com>
Cc: "Alexandre Courbot" <acourbot@nvidia.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"David Airlie" <airlied@gmail.com>,
	"Simona Vetter" <simona@ffwll.ch>,
	"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
	"Maxime Ripard" <mripard@kernel.org>,
	"Thomas Zimmermann" <tzimmermann@suse.de>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"John Hubbard" <jhubbard@nvidia.com>,
	"Ben Skeggs" <bskeggs@nvidia.com>,
	"Timur Tabi" <ttabi@nvidia.com>,
	"Alistair Popple" <apopple@nvidia.com>,
	linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
	nouveau@lists.freedesktop.org, dri-devel@lists.freedesktop.org,
	"Shirish Baskaran" <sbaskaran@nvidia.com>
Subject: Re: [PATCH v3 16/19] nova-core: Add support for VBIOS ucode extraction for boot
Date: Tue, 20 May 2025 11:30:51 +0200	[thread overview]
Message-ID: <aCxLyxcERNHKzfvI@cassiopeiae> (raw)
In-Reply-To: <4fee85be-a8c5-4a99-8397-c93e79d72d15@nvidia.com>

On Tue, May 20, 2025 at 03:55:06AM -0400, Joel Fernandes wrote:
> On 5/13/2025 1:19 PM, Danilo Krummrich wrote:
> > On Wed, May 07, 2025 at 10:52:43PM +0900, Alexandre Courbot wrote:
> >> @@ -238,6 +239,8 @@ pub(crate) fn new(
> >>  
> >>          let _sec2_falcon = Falcon::<Sec2>::new(pdev.as_ref(), spec.chipset, bar, true)?;
> >>  
> >> +        let _bios = Vbios::new(pdev, bar)?;
> > 
> > Please add a comment why, even though unused, it is important to create this
> > instance.
> > 
> > Also, please use `_` if it's not intended to ever be used.
> 
> If I add a comment, it will simply be removed by the next patch. I can add that
> though so it makes it more clear.

I recommend to add such comments, because then reviewers don't stumble over it.
:-)

> >> +impl Vbios {
> >> +    /// Probe for VBIOS extraction
> >> +    /// Once the VBIOS object is built, bar0 is not read for vbios purposes anymore.
> >> +    pub(crate) fn new(pdev: &pci::Device, bar0: &Bar0) -> Result<Vbios> {
> >> +        // Images to extract from iteration
> >> +        let mut pci_at_image: Option<PciAtBiosImage> = None;
> >> +        let mut first_fwsec_image: Option<FwSecBiosImage> = None;
> >> +        let mut second_fwsec_image: Option<FwSecBiosImage> = None;
> >> +
> >> +        // Parse all VBIOS images in the ROM
> >> +        for image_result in VbiosIterator::new(pdev, bar0)? {
> >> +            let full_image = image_result?;
> >> +
> >> +            dev_info!(
> > 
> > Let's use dev_dbg!() instaed.
> 
> Done.
> 
> > 
> >> +                pdev.as_ref(),
> >> +                "Found BIOS image: size: {:#x}, type: {}, last: {}\n",
> >> +                full_image.image_size_bytes()?,
> >> +                full_image.image_type_str(),
> >> +                full_image.is_last()
> >> +            );
> >> +
> >> +            // Get references to images we will need after the loop, in order to
> >> +            // setup the falcon data offset.
> >> +            match full_image {
> >> +                BiosImage::PciAt(image) => {
> >> +                    pci_at_image = Some(image);
> >> +                }
> >> +                BiosImage::FwSec(image) => {
> >> +                    if first_fwsec_image.is_none() {
> >> +                        first_fwsec_image = Some(image);
> >> +                    } else {
> >> +                        second_fwsec_image = Some(image);
> >> +                    }
> >> +                }
> >> +                // For now we don't need to handle these
> >> +                BiosImage::Efi(_image) => {}
> >> +                BiosImage::Nbsi(_image) => {}
> >> +            }
> >> +        }
> >> +
> >> +        // Using all the images, setup the falcon data pointer in Fwsec.
> >> +        // We need mutable access here, so we handle the Option manually.
> >> +        let final_fwsec_image = {
> >> +            let mut second = second_fwsec_image; // Take ownership of the option
> >> +
> >> +            if let (Some(second), Some(first), Some(pci_at)) =
> >> +                (second.as_mut(), first_fwsec_image, pci_at_image)
> >> +            {
> >> +                second
> >> +                    .setup_falcon_data(pdev, &pci_at, &first)
> >> +                    .inspect_err(|e| {
> >> +                        dev_err!(pdev.as_ref(), "Falcon data setup failed: {:?}\n", e)
> >> +                    })?;
> >> +            } else {
> >> +                dev_err!(
> >> +                    pdev.as_ref(),
> >> +                    "Missing required images for falcon data setup, skipping\n"
> >> +                );
> >> +                return Err(EINVAL);
> > 
> > This means that if second == None we fail, which makes sense, so why store an
> > Option in Vbios? All methods of Vbios fail if fwsec_image == None.
> > 
> 
> Well, if first and pci_at are None, we will fail as well. Not just second. But
> we don't know until we finish parsing all the images in the prior loop, if we
> found all the images. So we store it as Option during the prior loop, and check
> it later. Right?

My point is not that second is an option within this function -- that's fine. I
don't want the Vbios type to store an Option, because that doesn't make sense.
I.e. it should be

	struct Vbios {
	   fwsec_image: FwSecBiosImage,
	}

or just

	struct Vbios(FwSecBiosImage);

which is the same, rather than

	struct Vbios {
	   fwsec_image: Option<FwSecBiosImage>,
	}

because Vbios::new() fails anyways if any of the images is None, i.e.
vbios.fwsec_image can't ever be None.

The code below does that for you, i.e. it returns an instance of Vbios without
the inner Option.

> >> +            }
> >> +            second
> >> +        };
> > 
> > I think this should be:
> > 
> > 	let mut second = second_fwsec_image;
> > 	
> > 	if let (Some(second), Some(first), Some(pci_at)) =
> > 	    (second.as_mut(), first_fwsec_image, pci_at_image)
> > 	{
> > 	    second
> > 	        .setup_falcon_data(pdev, &pci_at, &first)
> > 	        .inspect_err(|e| {
> > 	            dev_err!(pdev.as_ref(), "Falcon data setup failed: {:?}\n", e)
> > 	        })?;
> > 	
> > 	    Ok(Vbios(second)
> > 	} else {
> > 	    dev_err!(
> > 	        pdev.as_ref(),
> > 	        "Missing required images for falcon data setup, skipping\n"
> > 	    );
> > 	
> > 	    Err(EINVAL)
> > 	}
> > 
> > where Vbios can just be
> > 
> > 	pub(crate) struct Vbios(FwSecBiosImage);
> 
> But your suggestion here still considers second as an Option? That's why you
> wrote 'Some(second)' ?

Yes, that's fine, see above. The difference is that the code returns you an
instance of

	struct Vbios(FwSecBiosImage);

rather than

	struct Vbios {
	   fwsec_image: Option<FwSecBiosImage>,
	}

which is unnecessary.

> 
> > 
> >> +
> >> +        Ok(Vbios {
> >> +            fwsec_image: final_fwsec_image,
> >> +        })
> >> +    }
> >> +
> >> +    pub(crate) fn fwsec_header(&self, pdev: &device::Device) -> Result<&FalconUCodeDescV3> {
> >> +        let image = self.fwsec_image.as_ref().ok_or(EINVAL)?;
> >> +        image.fwsec_header(pdev)
> >> +    }
> >> +
> >> +    pub(crate) fn fwsec_ucode(&self, pdev: &device::Device) -> Result<&[u8]> {
> >> +        let image = self.fwsec_image.as_ref().ok_or(EINVAL)?;
> >> +        image.fwsec_ucode(pdev, image.fwsec_header(pdev)?)
> >> +    }
> >> +
> >> +    pub(crate) fn fwsec_sigs(&self, pdev: &device::Device) -> Result<&[u8]> {
> >> +        let image = self.fwsec_image.as_ref().ok_or(EINVAL)?;
> >> +        image.fwsec_sigs(pdev, image.fwsec_header(pdev)?)
> >> +    }
> > 
> > Those then become infallible, e.g.
> > 
> > 	pub(crate) fn fwsec_sigs(&self, pdev: &device::Device) -> &[u8] {
> > 	    self.0.fwsec_sigs(pdev, self.fwsec_header(pdev))
> > 	}
> > 
> 
> Nope, I think you are wrong there. fwsec_sigs() of the underlying .0 returns a
> Result.

That's true, I confused self.fwsec_sigs() with self.0.fwsec_sigs(). It seems
that you may want to implement Deref for Vbios.

Also, can you please double check the Options in FwSecBiosImage (in case we
didn't talk about them yet)? They look quite suspicious too.

In general, I feel like a lot of those Option come from a programming pattern
that is very common in C, i.e. allocate a structure (stack or heap) and then
initialize its fields.

In Rust you should aim to initialize all the fields of a structure when you
create the instance. Option as a return type of a function is common, but it's
always a bit suspicious when there is an Option field in a struct.

I understand that there are cases where we can't omit it, and for obvious
reasons the Vbios code is probably a perfect example for that.

However, I recommend looking at this from top to bottom: Do the "final"
structures that we expose to the driver from the Vbios module have fields that
are *really* optional? Or is the Option type just a result from the parsing
process?

If it's the latter, we should get rid of it and work with a different type
during the parsing process and then create the final instance that is exposed to
the driver at the end.

For instance FwSecBiosImage is defined as:

	pub(crate) struct FwSecBiosImage {
	    base: BiosImageBase,
	    falcon_data_offset: Option<usize>,
	    pmu_lookup_table: Option<PmuLookupTable>,
	    falcon_ucode_offset: Option<usize>,
	}

Do only *some* FwSecBiosImage instances have a falcon_ucode_offset?

If the answer is 'no' then it shouldn't be an Option. If the answer is 'yes',
then this indicates that FwSecBiosImage is probably too generic and should be
split into more specific types of a FwSecBiosImage which instead share a common
trait in order to treat the different types generically.

> Also in Vbios::new(), I extract the Option when returning:
> 
>         Ok(Vbios {
>             fwsec_image: final_fwsec_image.ok_or(EINVAL)?,
>         })

Maybe you do so in your tree? v3 of the patch series has:

	pub(crate) struct Vbios {
	   pub fwsec_image: Option<FwSecBiosImage>,
	}

and

	Ok(Vbios {
	   fwsec_image: final_fwsec_image,
	})

  reply	other threads:[~2025-05-20  9:30 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-07 13:52 [PATCH v3 00/19] nova-core: run FWSEC-FRTS to perform first stage of GSP initialization Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 01/19] rust: dma: expose the count and size of CoherentAllocation Alexandre Courbot
2025-05-13 12:15   ` Danilo Krummrich
2025-05-07 13:52 ` [PATCH v3 02/19] gpu: nova-core: derive useful traits for Chipset Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 03/19] gpu: nova-core: add missing GA100 definition Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 04/19] gpu: nova-core: take bound device in Gpu::new Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 05/19] gpu: nova-core: define registers layout using helper macro Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 06/19] gpu: nova-core: fix layout of NV_PMC_BOOT_0 Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 07/19] gpu: nova-core: move Firmware to firmware module Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 08/19] rust: make ETIMEDOUT error available Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 09/19] gpu: nova-core: wait for GFW_BOOT completion Alexandre Courbot
2025-05-13 14:07   ` Danilo Krummrich
2025-05-16 12:16     ` Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 10/19] gpu: nova-core: add DMA object struct Alexandre Courbot
2025-05-13 14:25   ` Danilo Krummrich
2025-05-07 13:52 ` [PATCH v3 11/19] gpu: nova-core: register sysmem flush page Alexandre Courbot
2025-05-13 14:47   ` Danilo Krummrich
2025-05-07 13:52 ` [PATCH v3 12/19] gpu: nova-core: add helper function to wait on condition Alexandre Courbot
2025-05-13 14:50   ` Danilo Krummrich
2025-05-07 13:52 ` [PATCH v3 13/19] gpu: nova-core: add falcon register definitions and base code Alexandre Courbot
2025-05-13 16:19   ` Danilo Krummrich
2025-05-16 12:19     ` Alexandre Courbot
2025-05-16 12:26       ` Danilo Krummrich
2025-05-07 13:52 ` [PATCH v3 14/19] gpu: nova-core: firmware: add ucode descriptor used by FWSEC-FRTS Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 15/19] rust: num: Add an upward alignment helper for usize Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 16/19] nova-core: Add support for VBIOS ucode extraction for boot Alexandre Courbot
2025-05-13 17:19   ` Danilo Krummrich
2025-05-20  7:55     ` Joel Fernandes
2025-05-20  9:30       ` Danilo Krummrich [this message]
2025-05-20 13:43         ` Joel Fernandes
2025-05-20 15:01           ` Danilo Krummrich
2025-05-20 15:11             ` Joel Fernandes
2025-05-20 15:36               ` Danilo Krummrich
2025-05-20 16:02                 ` Joel Fernandes
2025-05-20 18:13                 ` Joel Fernandes
2025-05-20 21:32                   ` Dave Airlie
2025-05-21  3:17                     ` Joel Fernandes
2025-05-14 16:23   ` Danilo Krummrich
2025-05-19 22:59     ` Joel Fernandes
2025-05-20  7:18     ` Joel Fernandes
2025-05-16 20:38   ` Timur Tabi
2025-05-20  6:35     ` Joel Fernandes
2025-05-07 13:52 ` [PATCH v3 17/19] gpu: nova-core: compute layout of the FRTS region Alexandre Courbot
2025-05-13 16:41   ` Danilo Krummrich
2025-05-17 13:42     ` Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 18/19] gpu: nova-core: extract FWSEC from BIOS and patch it to run FWSEC-FRTS Alexandre Courbot
2025-05-14 16:38   ` Danilo Krummrich
2025-05-19 14:24     ` Alexandre Courbot
2025-05-07 13:52 ` [PATCH v3 19/19] gpu: nova-core: load and " Alexandre Courbot
2025-05-14 16:42   ` Danilo Krummrich
2025-05-13 13:10 ` [PATCH v3 00/19] nova-core: run FWSEC-FRTS to perform first stage of GSP initialization Danilo Krummrich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=aCxLyxcERNHKzfvI@cassiopeiae \
    --to=dakr@kernel.org \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=airlied@gmail.com \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=apopple@nvidia.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=bskeggs@nvidia.com \
    --cc=corbet@lwn.net \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=gary@garyguo.net \
    --cc=jhubbard@nvidia.com \
    --cc=joelagnelf@nvidia.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=mripard@kernel.org \
    --cc=nouveau@lists.freedesktop.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=sbaskaran@nvidia.com \
    --cc=simona@ffwll.ch \
    --cc=tmgross@umich.edu \
    --cc=ttabi@nvidia.com \
    --cc=tzimmermann@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).