public inbox for rust-for-linux@vger.kernel.org
 help / color / mirror / Atom feed
From: "Danilo Krummrich" <dakr@kernel.org>
To: "Zhi Wang" <zhiw@nvidia.com>
Cc: <rust-for-linux@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
	<jgg@nvidia.com>, <gary@garyguo.net>, <joelagnelf@nvidia.com>,
	<aliceryhl@google.com>, <bhelgaas@google.com>,
	<kwilczynski@kernel.org>, <ojeda@kernel.org>,
	<alex.gaynor@gmail.com>, <boqun.feng@gmail.com>,
	<bjorn3_gh@protonmail.com>, <lossin@kernel.org>,
	<a.hindborg@kernel.org>, <tmgross@umich.edu>,
	<markus.probst@posteo.de>, <helgaas@kernel.org>,
	<cjia@nvidia.com>, <smitra@nvidia.com>, <ankita@nvidia.com>,
	<aniketa@nvidia.com>, <kwankhede@nvidia.com>,
	<targupta@nvidia.com>, <acourbot@nvidia.com>,
	<jhubbard@nvidia.com>, <zhiwang@kernel.org>,
	<daniel.almeida@collabora.com>
Subject: Re: [PATCH 2/2] gpu: nova-core: add fwctl driver for firmware control interface
Date: Fri, 13 Mar 2026 17:03:28 +0100	[thread overview]
Message-ID: <DH1S5A8YOFJZ.5D7A45BB4IAT@kernel.org> (raw)
In-Reply-To: <20260305190936.398590-3-zhiw@nvidia.com>

On Thu Mar 5, 2026 at 8:09 PM CET, Zhi Wang wrote:
> +use kernel::{
> +    fwctl::{
> +        self,
> +        DeviceType,
> +        FwRpcResponse,
> +        Operations,
> +        RpcScope, //
> +    },
> +    prelude::*,
> +    transmute::{AsBytes, FromBytes},

NIT: Formatting.

> +    uapi, //
> +};
> +
> +use crate::{
> +    driver::NovaCore,
> +    gsp::{
> +        RmControlMsgFunction,
> +        rm::commands::send_rm_control, //
> +    },
> +};
> +
> +/// Byte-serializable wrapper for [`uapi::fwctl_rpc_nova_core_request_hdr`].
> +#[repr(transparent)]
> +struct FwctlNovaCoreReqHdr(uapi::fwctl_rpc_nova_core_request_hdr);
> +
> +// SAFETY: All fields are plain `__u32` with no padding.
> +unsafe impl FromBytes for FwctlNovaCoreReqHdr {}
> +
> +/// Byte-serializable wrapper for [`uapi::fwctl_rpc_nova_core_resp_hdr`].
> +#[repr(transparent)]
> +struct FwctlNovaCoreRespHdr(uapi::fwctl_rpc_nova_core_resp_hdr);
> +
> +// SAFETY: All fields are plain `__u32` with no padding.
> +unsafe impl AsBytes for FwctlNovaCoreRespHdr {}
> +
> +/// Per-FD fwctl user context and operations for nova-core.
> +pub(crate) struct NovaCoreFwCtl;
> +
> +impl Operations for NovaCoreFwCtl {
> +    type DeviceData = ();
> +
> +    const DEVICE_TYPE: DeviceType = DeviceType::NovaCore;
> +
> +    fn open(_device: &fwctl::Device<Self>) -> Result<impl PinInit<Self, Error>, Error> {
> +        Ok(Ok(NovaCoreFwCtl))
> +    }
> +
> +    fn fw_rpc(
> +        _this: &Self,
> +        device: &fwctl::Device<Self>,
> +        scope: RpcScope,
> +        rpc_in: &mut [u8],
> +    ) -> Result<FwRpcResponse, Error> {

Result<FwRpcResponse>

> +        let hdr_size = size_of::<FwctlNovaCoreReqHdr>();
> +
> +        if rpc_in.len() < hdr_size {
> +            return Err(EINVAL);
> +        }
> +
> +        if scope != RpcScope::Configuration {
> +            return Err(EPERM);
> +        }
> +
> +        let (hdr, _) = FwctlNovaCoreReqHdr::from_bytes_prefix(rpc_in).ok_or(EINVAL)?;
> +        let cmd = hdr.0.cmd;
> +
> +        let rm_cmd = match cmd {
> +            uapi::fwctl_cmd_nova_core_FWCTL_CMD_NOVA_CORE_UPLOAD_VGPU_TYPE => {
> +                RmControlMsgFunction::VgpuMgrInternalPgpuAddVgpuType
> +            }
> +            _ => return Err(EINVAL),
> +        };
> +
> +        let parent = device.parent();
> +        let data = parent.drvdata::<NovaCore>()?;

Please don't use drvdata() for this, it is not what it is intended for and I
kinda regret a bit that I added it in the first place.

Instead, please use your fwctl::Device private data, i.e. Self.

> +        let bar = data.gpu.bar.as_ref().access(parent)?;
> +
> +        let params = &rpc_in[hdr_size..];
> +        let reply_params = send_rm_control(
> +            &data.gpu.gsp.cmdq,
> +            bar,
> +            data.gpu.gsp.h_client,
> +            data.gpu.gsp.h_subdevice,
> +            rm_cmd,
> +            params,
> +        )?;
> +
> +        let resp_hdr = FwctlNovaCoreRespHdr(uapi::fwctl_rpc_nova_core_resp_hdr {
> +            mctp_header: 0,
> +            nvdm_header: 0,
> +        });
> +        let mut out = KVec::new();
> +        out.extend_from_slice(resp_hdr.as_bytes(), GFP_KERNEL)?;
> +        out.extend_from_slice(&reply_params, GFP_KERNEL)?;
> +        Ok(FwRpcResponse::NewBuffer(out))
> +    }
> +}
> diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
> index 60c85fffaeaf..7965ce37eb08 100644
> --- a/drivers/gpu/nova-core/gpu.rs
> +++ b/drivers/gpu/nova-core/gpu.rs
> @@ -241,7 +241,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
>  pub(crate) struct Gpu {
>      spec: Spec,
>      /// MMIO mapping of PCI BAR 0
> -    bar: Arc<Devres<Bar0>>,
> +    pub(crate) bar: Arc<Devres<Bar0>>,
>      /// System memory page required for flushing all pending GPU-side memory writes done through
>      /// PCIE into system memory, via sysmembar (A GPU-initiated HW memory-barrier operation).
>      sysmem_flush: SysmemFlush,
> @@ -251,7 +251,7 @@ pub(crate) struct Gpu {
>      sec2_falcon: Falcon<Sec2Falcon>,
>      /// GSP runtime data. Temporarily an empty placeholder.
>      #[pin]
> -    gsp: Gsp,
> +    pub(crate) gsp: Gsp,
>  }
>  
>  impl Gpu {
> diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
> index 1a1c4e9808ac..77eb30010c2f 100644
> --- a/drivers/gpu/nova-core/gsp.rs
> +++ b/drivers/gpu/nova-core/gsp.rs
> @@ -4,11 +4,13 @@
>  
>  use kernel::{
>      device,
> +    devres::Devres,
>      dma::{
>          CoherentAllocation,
>          DmaAddress, //
>      },
>      dma_write,
> +    fwctl,
>      pci,
>      prelude::*,
>      transmute::AsBytes, //
> @@ -21,15 +23,19 @@
>  mod sequencer;
>  
>  pub(crate) use fw::{
> +    rm::RmControlMsgFunction,
>      GspFwWprMeta,
>      LibosParams, //
>  };
>  
>  use crate::{
> -    gsp::cmdq::Cmdq,
> -    gsp::fw::{
> -        GspArgumentsPadded,
> -        LibosMemoryRegionInitArgument, //
> +    fwctl::NovaCoreFwCtl,
> +    gsp::{
> +        cmdq::Cmdq,
> +        fw::{
> +            GspArgumentsPadded,
> +            LibosMemoryRegionInitArgument, //
> +        },
>      },
>      num,
>  };
> @@ -117,6 +123,12 @@ pub(crate) struct Gsp {
>      pub(crate) cmdq: Cmdq,
>      /// RM arguments.
>      rmargs: CoherentAllocation<GspArgumentsPadded>,
> +    /// Cached RM internal client handle from GSP static info.
> +    pub(crate) h_client: u32,
> +    /// Cached RM internal subdevice handle from GSP static info.
> +    pub(crate) h_subdevice: u32,
> +    /// fwctl registration for userspace RM control.
> +    fwctl: Pin<KBox<Devres<fwctl::Registration<NovaCoreFwCtl>>>>,

This does not need to be in a separate allocation.

>  }
>  
>  impl Gsp {
> @@ -125,6 +137,8 @@ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error
>          pin_init::pin_init_scope(move || {
>              let dev = pdev.as_ref();
>  
> +            let fwctl_dev = fwctl::Device::<NovaCoreFwCtl>::new(pdev.as_ref(), Ok(()))?;

You should store everything you need in the private data of your fwctl::Device
to properly tie it to its lifetime, e.g.

	struct NovaCoreFwCtl {
		gpu: Arc<Gpu>,
		bar: Arc<Devres<Bar0>>,
	}

> +
>              Ok(try_pin_init!(Self {
>                  libos: CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent(
>                      dev,
> @@ -140,6 +154,9 @@ pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error
>                      1,
>                      GFP_KERNEL | __GFP_ZERO,
>                  )?,
> +                h_client: 0,
> +                h_subdevice: 0,
> +                fwctl: KBox::pin_init(fwctl::Registration::new(pdev.as_ref(), &fwctl_dev), GFP_KERNEL)?,

I don't think this should live in the Gsp structure, please move this to probe()
and store the registration in struct NovaCore after the Gpu structure.

>                  _: {
>                      // Initialise the logging structures. The OpenRM equivalents are in:
>                      // _kgspInitLibosLoggingStructures (allocates memory for buffers)
> diff --git a/drivers/gpu/nova-core/gsp/boot.rs b/drivers/gpu/nova-core/gsp/boot.rs
> index bc53e667cd9e..f493546b78ff 100644
> --- a/drivers/gpu/nova-core/gsp/boot.rs
> +++ b/drivers/gpu/nova-core/gsp/boot.rs
> @@ -128,7 +128,7 @@ fn run_fwsec_frts(
>      ///
>      /// Upon return, the GSP is up and running, and its runtime object given as return value.
>      pub(crate) fn boot(
> -        self: Pin<&mut Self>,
> +        mut self: Pin<&mut Self>,
>          pdev: &pci::Device<device::Bound>,
>          bar: &Bar0,
>          chipset: Chipset,
> @@ -221,6 +221,10 @@ pub(crate) fn boot(
>  
>          // Obtain and display basic GPU information.
>          let info = commands::get_gsp_info(&self.cmdq, bar)?;
> +        // SAFETY: h_client and h_subdevice are not structurally pinned.
> +        let this = unsafe { self.as_mut().get_unchecked_mut() };
> +        this.h_client = info.h_client();
> +        this.h_subdevice = info.h_subdevice();

Ick! If this is only needed from the fwctl callbacks, just move those into your
fwctl::Device private data.

But I think this is needed in other cases as well. So, more generally I think
Gsp::boot() should just be part of the constructor, as we won't be able to
properly construct a Gsp object without having a chance to interact with the Gsp
before.

>  /// Sends an RM control command, checks the reply status, and returns the raw parameter bytes.
> -fn send_rm_control(
> +pub(crate) fn send_rm_control(
>      cmdq: &Cmdq,
>      bar: &Bar0,
>      h_client: u32,
> @@ -106,7 +106,7 @@ fn send_rm_control(
>      cmd: RmControlMsgFunction,
>      params: &[u8],
>  ) -> Result<KVVec<u8>> {
> -    let reply = cmdq.send_sync_command(bar, RmControl::new(h_client, h_object, cmd, params))?;
> +    let reply = cmdq.send_command(bar, RmControl::new(h_client, h_object, cmd, params))?;

This looks like it should be a separate patch, or fixed in one of the
dependencies of this patch.

>  
>      Result::from(reply.status)?;
>  
> diff --git a/drivers/gpu/nova-core/nova_core.rs b/drivers/gpu/nova-core/nova_core.rs
> index b5caf1044697..863dc041272c 100644
> --- a/drivers/gpu/nova-core/nova_core.rs
> +++ b/drivers/gpu/nova-core/nova_core.rs
> @@ -10,6 +10,7 @@
>  mod falcon;
>  mod fb;
>  mod firmware;
> +mod fwctl;
>  mod gfw;
>  mod gpu;
>  mod gsp;
> @@ -27,6 +28,7 @@
>      description: "Nova Core GPU driver",
>      license: "GPL v2",
>      firmware: [],
> +    imports_ns: ["FWCTL"],
>  }
>  
>  kernel::module_firmware!(firmware::ModInfoBuilder);
> diff --git a/include/uapi/fwctl/fwctl.h b/include/uapi/fwctl/fwctl.h
> index 716ac0eee42d..f6289fbf3062 100644
> --- a/include/uapi/fwctl/fwctl.h
> +++ b/include/uapi/fwctl/fwctl.h
> @@ -45,6 +45,7 @@ enum fwctl_device_type {
>  	FWCTL_DEVICE_TYPE_MLX5 = 1,
>  	FWCTL_DEVICE_TYPE_CXL = 2,
>  	FWCTL_DEVICE_TYPE_PDS = 4,
> +	FWCTL_DEVICE_TYPE_NOVA_CORE = 5,
>  };
>  
>  /**
> diff --git a/include/uapi/fwctl/nova-core.h b/include/uapi/fwctl/nova-core.h
> new file mode 100644
> index 000000000000..3f1d94b44ec8
> --- /dev/null
> +++ b/include/uapi/fwctl/nova-core.h

Why is this not include/uapi/gpu/nova-core.h? This driver does not live under
drivers/fwctl/.

If we want to separate it, I suggest include/uapi/gpu/nova-core/fwctl.h, but it
doesn't seem necessary as we don't have any other UAPIs.

  reply	other threads:[~2026-03-13 16:03 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-05 19:09 [PATCH 0/2] gpu: nova-core: add fwctl driver Zhi Wang
2026-03-05 19:09 ` [PATCH 1/2] fwctl: use subsys_initcall for built-in configuration Zhi Wang
2026-03-05 19:09 ` [PATCH 2/2] gpu: nova-core: add fwctl driver for firmware control interface Zhi Wang
2026-03-13 16:03   ` Danilo Krummrich [this message]
2026-03-13 16:26     ` Jason Gunthorpe

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=DH1S5A8YOFJZ.5D7A45BB4IAT@kernel.org \
    --to=dakr@kernel.org \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=aniketa@nvidia.com \
    --cc=ankita@nvidia.com \
    --cc=bhelgaas@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=cjia@nvidia.com \
    --cc=daniel.almeida@collabora.com \
    --cc=gary@garyguo.net \
    --cc=helgaas@kernel.org \
    --cc=jgg@nvidia.com \
    --cc=jhubbard@nvidia.com \
    --cc=joelagnelf@nvidia.com \
    --cc=kwankhede@nvidia.com \
    --cc=kwilczynski@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=markus.probst@posteo.de \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=smitra@nvidia.com \
    --cc=targupta@nvidia.com \
    --cc=tmgross@umich.edu \
    --cc=zhiw@nvidia.com \
    --cc=zhiwang@kernel.org \
    /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