From: Danilo Krummrich <dakr@kernel.org>
To: Alexandre Courbot <acourbot@nvidia.com>
Cc: airlied@gmail.com, simona@ffwll.ch, corbet@lwn.net,
maarten.lankhorst@linux.intel.com, mripard@kernel.org,
tzimmermann@suse.de, ajanulgu@redhat.com, lyude@redhat.com,
pstanner@redhat.com, zhiw@nvidia.com, cjia@nvidia.com,
jhubbard@nvidia.com, bskeggs@nvidia.com, acurrid@nvidia.com,
ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com,
gary@garyguo.net, bjorn3_gh@protonmail.com,
benno.lossin@proton.me, a.hindborg@kernel.org,
aliceryhl@google.com, tmgross@umich.edu,
dri-devel@lists.freedesktop.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, nouveau@lists.freedesktop.org,
rust-for-linux@vger.kernel.org,
Nouveau <nouveau-bounces@lists.freedesktop.org>
Subject: Re: [PATCH v2 1/2] gpu: nova-core: add initial driver stub
Date: Thu, 6 Feb 2025 15:49:09 +0100 [thread overview]
Message-ID: <Z6TL5a5SCZoVq8Zt@cassiopeiae> (raw)
In-Reply-To: <D7LF554L2J0N.JRPHDUCHVKP3@nvidia.com>
Hi Alexandre,
On Thu, Feb 06, 2025 at 11:05:37PM +0900, Alexandre Courbot wrote:
> > +
> > +/// Enum representation of the GPU chipset.
> > +#[derive(fmt::Debug)]
>
> I suspect you will eventually want to also derive Copy and Clone, as
> well as PartialEq and Eq (so the assigned values can be used), but it's
> of course fine to postpone this until we actually need them.
Indeed, the idea is to add it as needed.
>
> Note that the usage made of Debug suggests that you actually want
> Display - but I understand that implementing Display would be more
> cumbersome.
>
> > +
> > +// TODO replace with something like derive(FromPrimitive)
> > +impl Chipset {
> > + fn from_u32(value: u32) -> Option<Chipset> {
> > + match value {
> > + 0x162 => Some(Chipset::TU102),
> > + 0x164 => Some(Chipset::TU104),
> > + 0x166 => Some(Chipset::TU106),
> > + 0x167 => Some(Chipset::TU117),
> > + 0x168 => Some(Chipset::TU116),
> > + 0x172 => Some(Chipset::GA102),
> > + 0x173 => Some(Chipset::GA103),
> > + 0x174 => Some(Chipset::GA104),
> > + 0x176 => Some(Chipset::GA106),
> > + 0x177 => Some(Chipset::GA107),
> > + 0x192 => Some(Chipset::AD102),
> > + 0x193 => Some(Chipset::AD103),
> > + 0x194 => Some(Chipset::AD104),
> > + 0x196 => Some(Chipset::AD106),
> > + 0x197 => Some(Chipset::AD107),
> > + _ => None,
> > + }
> > + }
> > +}
>
> Shouldn't this be an implementation of TryFrom<u32>? By doing so you can
> return ENODEV as the error and simplify the caller code below.
Yes, it should be. I wanted to change that, but forgot about it. Thanks for the
reminder.
But ultimately, as the comment says, I'd like to have some kind of FromPrimitive
implementation for that.
>
> > +
> > +// TODO:
> > +// - replace with something like derive(FromPrimitive)
> > +// - consider to store within Chipset, if arbitrary_enum_discriminant becomes stable
> > +impl Architecture {
> > + fn from_u32(value: u32) -> Option<Architecture> {
> > + match value {
> > + 0x16 => Some(Architecture::Turing),
> > + 0x17 => Some(Architecture::Ampere),
> > + 0x19 => Some(Architecture::Ada),
> > + _ => None,
> > + }
> > + }
> > +}
> > +
> > +impl Revision {
> > + fn new(major: u8, minor: u8) -> Self {
> > + Self { major, minor }
> > + }
>
> Suggestion: add a version that takes a Boot0 as argument and call the
> right methods directly in the method instead of relying on the caller to
> do that for us, e.g:
>
> fn from_boot0(boot0: ®s::Boot0) -> Self {
> Self::new(boot0.major_rev(), boot0.minor_rev())
> }
>
>
> Then new() can also be removed if Boot0 is the only sensible source of
> Revision.
That's a good suggestion, I'll pick that up.
>
> (I'd argue that Boot0 should also implement Copy, that way this method
> can take it by value directly)
>
> > +}
> > +
> > +impl fmt::Display for Revision {
> > + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> > + write!(f, "{:x}.{:x}", self.major, self.minor)
> > + }
> > +}
> > +
> > +impl Spec {
> > + fn new(bar: &Devres<Bar0>) -> Result<Spec> {
> > + let bar = bar.try_access().ok_or(ENXIO)?;
> > + let boot0 = regs::Boot0::read(&bar);
> > +
> > + let Some(chipset) = Chipset::from_u32(boot0.chipset()) else {
> > + return Err(ENODEV);
> > + };
> > +
> > + let Some(arch) = Architecture::from_u32(boot0.arch()) else {
> > + return Err(ENODEV);
> > + };
>
> Technically the Architecture is already known if the Chipset has been
> built successfully, so there should be no need to build it again (and
> test for a failure that cannot happen at this point).
>
> Since the architecture information is already embedded in Chipset, maybe
> we can have an arch() method there?
>
> Something like:
>
> impl Chipset {
> pub(crate) fn arch(self) -> Architecture {
> match self as u32 & !0xf {
> 0x160 => Architecture::Turing,
> 0x170 => Architecture::Ampere,
> 0x190 => Architecture::Ada,
> _ => unreachable!(),
> }
> }
> }
I thought about this, which is also why the comment above says: "consider to
store within Chipset, if arbitrary_enum_discriminant becomes stable".
I did not go with what you suggest because it leaves us with either
Chipset::arch() returning a Result, which is annoying, or with Chipset::arch()
being able to panic the kernel, which I'd dislike even more.
There's also a third option, which would be to have some kind of unknown
architecture, which we could catch later on, but that's just a worse variation
of returning a Result.
Another reason was that I did not want to encode register specific masks into
the Chipset type.
>
>
> This would also enable us to remove Architecture::from_u32() and
> Spec::arch, which is redundant with Spec::chipset anyway.
>
> A better (but more verbose) implementation of Chipset::arch() might be
> to match every possible variant, so we get a build error if we forget to
> handle a new chipset instead of hitting the unreachable!() at runtime...
I think that would indeed be a reasonable option.
>
> > +
> > + let revision = Revision::new(boot0.major_rev(), boot0.minor_rev());
> > +
> > + Ok(Self {
> > + arch,
> > + chipset,
> > + revision,
> > + })
> > + }
> > +}
> > +
> > +impl Firmware {
> > + fn new(dev: &device::Device, spec: &Spec, ver: &str) -> Result<Firmware> {
> > + let mut chip_name = CString::try_from_fmt(fmt!("{:?}", spec.chipset))?;
> > + chip_name.make_ascii_lowercase();
> > +
> > + let fw_booter_load_path =
> > + CString::try_from_fmt(fmt!("nvidia/{}/gsp/booter_load-{}.bin", &*chip_name, ver))?;
> > + let fw_booter_unload_path =
> > + CString::try_from_fmt(fmt!("nvidia/{}/gsp/booter_unload-{}.bin", &*chip_name, ver))?;
> > + let fw_bootloader_path =
> > + CString::try_from_fmt(fmt!("nvidia/{}/gsp/bootloader-{}.bin", &*chip_name, ver))?;
> > + let fw_gsp_path =
> > + CString::try_from_fmt(fmt!("nvidia/{}/gsp/gsp-{}.bin", &*chip_name, ver))?;
> > +
> > + let booter_load = firmware::Firmware::request(&fw_booter_load_path, dev)?;
> > + let booter_unload = firmware::Firmware::request(&fw_booter_unload_path, dev)?;
> > + let bootloader = firmware::Firmware::request(&fw_bootloader_path, dev)?;
> > + let gsp = firmware::Firmware::request(&fw_gsp_path, dev)?;
> > +
> > + Ok(Firmware {
> > + booter_load,
> > + booter_unload,
> > + bootloader,
> > + gsp,
> > + })
>
> This looks like a good opportunity to use a closure and avoid
> repeating the code:
>
> let request_fw = |type_| {
> CString::try_from_fmt(fmt!("nvidia/{}/gsp/{}-{}.bin", type_, &*chip_name, ver))
> .and_then(|path| firmware::Firmware::request(&path, dev))
> };
>
> It is also short enough that you can directly invoke it when building
> the Firmware object, without using temporary variables:
>
> Ok(Firmware {
> booter_load: request_fw("booter_load")?,
> booter_unload: request_fw("booter_unload")?,
> bootloader: request_fw("bootloader")?,
> gsp: request_fw("gsp")?,
> })
>
> IMHO this has the benefit of being more concise and keeping related
> operations closer.
I agree, that's pretty clean.
>
> Thanks!
> Alex.
>
next prev parent reply other threads:[~2025-02-06 14:49 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-02-04 19:03 [PATCH v2 1/2] gpu: nova-core: add initial driver stub Danilo Krummrich
2025-02-04 19:03 ` [PATCH v2 2/2] gpu: nova-core: add initial documentation Danilo Krummrich
2025-02-05 13:56 ` Zhi Wang
2025-02-05 14:13 ` Miguel Ojeda
2025-02-05 14:56 ` Zhi Wang
2025-02-05 16:20 ` Danilo Krummrich
2025-02-05 16:10 ` Danilo Krummrich
2025-02-05 19:44 ` Zhi Wang
2025-02-09 15:36 ` Danilo Krummrich
2025-02-07 8:23 ` Alexandre Courbot
2025-02-09 15:25 ` Danilo Krummrich
2025-02-06 14:05 ` [PATCH v2 1/2] gpu: nova-core: add initial driver stub Alexandre Courbot
2025-02-06 14:49 ` Danilo Krummrich [this message]
2025-02-07 1:41 ` Alexandre Courbot
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=Z6TL5a5SCZoVq8Zt@cassiopeiae \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=acurrid@nvidia.com \
--cc=airlied@gmail.com \
--cc=ajanulgu@redhat.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=bskeggs@nvidia.com \
--cc=cjia@nvidia.com \
--cc=corbet@lwn.net \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lyude@redhat.com \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=nouveau-bounces@lists.freedesktop.org \
--cc=nouveau@lists.freedesktop.org \
--cc=ojeda@kernel.org \
--cc=pstanner@redhat.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tmgross@umich.edu \
--cc=tzimmermann@suse.de \
--cc=zhiw@nvidia.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.