[PATCH 7/9] gpu: nova-core: gsp: add RM control command infrastructure

Eliot Courtney posted 9 patches 1 month, 1 week ago
There is a newer version of this series
[PATCH 7/9] gpu: nova-core: gsp: add RM control command infrastructure
Posted by Eliot Courtney 1 month, 1 week ago
Add `RmControl` which implements CommandToGsp for sending RM control
RPCs.

Add `RmControlReply` which implements MessageFromGsp for getting the
reply back.

Add `send_rm_control` which sends an RM control RPC via the command
queue using the above structures.

This gives a generic way to send each RM control RPC. Each new RM
control RPC can be added by extending RmControlMsgFunction and adding
its bindings wrappers and writing a helper function to send it via
`send_rm_control`.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp.rs             |   1 +
 drivers/gpu/nova-core/gsp/rm.rs          |   3 +
 drivers/gpu/nova-core/gsp/rm/commands.rs | 111 +++++++++++++++++++++++++++++++
 3 files changed, 115 insertions(+)

diff --git a/drivers/gpu/nova-core/gsp.rs b/drivers/gpu/nova-core/gsp.rs
index a6f3918c20b1..1a1c4e9808ac 100644
--- a/drivers/gpu/nova-core/gsp.rs
+++ b/drivers/gpu/nova-core/gsp.rs
@@ -17,6 +17,7 @@
 pub(crate) mod cmdq;
 pub(crate) mod commands;
 mod fw;
+pub(crate) mod rm;
 mod sequencer;
 
 pub(crate) use fw::{
diff --git a/drivers/gpu/nova-core/gsp/rm.rs b/drivers/gpu/nova-core/gsp/rm.rs
new file mode 100644
index 000000000000..10e879a3e842
--- /dev/null
+++ b/drivers/gpu/nova-core/gsp/rm.rs
@@ -0,0 +1,3 @@
+// SPDX-License-Identifier: GPL-2.0
+
+pub(crate) mod commands;
diff --git a/drivers/gpu/nova-core/gsp/rm/commands.rs b/drivers/gpu/nova-core/gsp/rm/commands.rs
new file mode 100644
index 000000000000..16bcf88644db
--- /dev/null
+++ b/drivers/gpu/nova-core/gsp/rm/commands.rs
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use core::{
+    array,
+    convert::Infallible, //
+};
+
+use kernel::prelude::*;
+
+use crate::{
+    driver::Bar0,
+    gsp::{
+        cmdq::{
+            Cmdq,
+            CommandToGsp,
+            MessageFromGsp, //
+        },
+        fw::{
+            rm::*,
+            MsgFunction,
+            NvStatus, //
+        },
+    },
+    sbuffer::SBufferIter,
+};
+
+/// Command for sending an RM control message to the GSP.
+struct RmControl<'a> {
+    h_client: u32,
+    h_object: u32,
+    cmd: RmControlMsgFunction,
+    params: &'a [u8],
+}
+
+impl<'a> RmControl<'a> {
+    /// Creates a new RM control command.
+    fn new(h_client: u32, h_object: u32, cmd: RmControlMsgFunction, params: &'a [u8]) -> Self {
+        Self {
+            h_client,
+            h_object,
+            cmd,
+            params,
+        }
+    }
+}
+
+impl CommandToGsp for RmControl<'_> {
+    const FUNCTION: MsgFunction = MsgFunction::GspRmControl;
+    type Command = GspRmControl;
+    type Reply = RmControlReply;
+    type InitError = Infallible;
+
+    fn init(&self) -> impl Init<Self::Command, Self::InitError> {
+        GspRmControl::new(
+            self.h_client,
+            self.h_object,
+            self.cmd,
+            self.params.len() as u32,
+        )
+    }
+
+    fn variable_payload_len(&self) -> usize {
+        self.params.len()
+    }
+
+    fn init_variable_payload(
+        &self,
+        dst: &mut SBufferIter<array::IntoIter<&mut [u8], 2>>,
+    ) -> Result {
+        dst.write_all(self.params)
+    }
+}
+
+/// Response from an RM control message.
+pub(crate) struct RmControlReply {
+    status: NvStatus,
+    params: KVVec<u8>,
+}
+
+impl MessageFromGsp for RmControlReply {
+    const FUNCTION: MsgFunction = MsgFunction::GspRmControl;
+    type Message = GspRmControl;
+    type InitError = Error;
+
+    fn read(
+        msg: &Self::Message,
+        sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
+    ) -> Result<Self, Self::InitError> {
+        Ok(RmControlReply {
+            status: msg.status(),
+            params: sbuffer.flush_into_kvvec(GFP_KERNEL)?,
+        })
+    }
+}
+
+/// Sends an RM control command, checks the reply status, and returns the raw parameter bytes.
+#[expect(dead_code)]
+fn send_rm_control(
+    cmdq: &Cmdq,
+    bar: &Bar0,
+    h_client: u32,
+    h_object: u32,
+    cmd: RmControlMsgFunction,
+    params: &[u8],
+) -> Result<KVVec<u8>> {
+    let reply = cmdq.send_sync_command(bar, RmControl::new(h_client, h_object, cmd, params))?;
+
+    Result::from(reply.status)?;
+
+    Ok(reply.params)
+}

-- 
2.53.0
Re: [PATCH 7/9] gpu: nova-core: gsp: add RM control command infrastructure
Posted by Danilo Krummrich 3 weeks, 4 days ago
On Fri Feb 27, 2026 at 1:32 PM CET, Eliot Courtney wrote:
> +/// Command for sending an RM control message to the GSP.
> +struct RmControl<'a> {
> +    h_client: u32,
> +    h_object: u32,
> +    cmd: RmControlMsgFunction,
> +    params: &'a [u8],
> +}

Please expand the documentation, especially the fields.

> +impl<'a> RmControl<'a> {
> +    /// Creates a new RM control command.
> +    fn new(h_client: u32, h_object: u32, cmd: RmControlMsgFunction, params: &'a [u8]) -> Self {
> +        Self {
> +            h_client,
> +            h_object,
> +            cmd,
> +            params,
> +        }
> +    }
> +}
> +
> +impl CommandToGsp for RmControl<'_> {
> +    const FUNCTION: MsgFunction = MsgFunction::GspRmControl;
> +    type Command = GspRmControl;
> +    type Reply = RmControlReply;
> +    type InitError = Infallible;
> +
> +    fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> +        GspRmControl::new(
> +            self.h_client,
> +            self.h_object,
> +            self.cmd,
> +            self.params.len() as u32,
> +        )
> +    }
> +
> +    fn variable_payload_len(&self) -> usize {
> +        self.params.len()
> +    }
> +
> +    fn init_variable_payload(
> +        &self,
> +        dst: &mut SBufferIter<array::IntoIter<&mut [u8], 2>>,
> +    ) -> Result {
> +        dst.write_all(self.params)
> +    }
> +}
> +
> +/// Response from an RM control message.
> +pub(crate) struct RmControlReply {
> +    status: NvStatus,
> +    params: KVVec<u8>,
> +}
> +
> +impl MessageFromGsp for RmControlReply {
> +    const FUNCTION: MsgFunction = MsgFunction::GspRmControl;
> +    type Message = GspRmControl;
> +    type InitError = Error;
> +
> +    fn read(
> +        msg: &Self::Message,
> +        sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> +    ) -> Result<Self, Self::InitError> {
> +        Ok(RmControlReply {
> +            status: msg.status(),
> +            params: sbuffer.flush_into_kvvec(GFP_KERNEL)?,
> +        })
> +    }
> +}
> +
> +/// Sends an RM control command, checks the reply status, and returns the raw parameter bytes.
> +#[expect(dead_code)]
> +fn send_rm_control(

Why isn't this a method of Cmdq?

> +    cmdq: &Cmdq,
> +    bar: &Bar0,
> +    h_client: u32,
> +    h_object: u32,
> +    cmd: RmControlMsgFunction,
> +    params: &[u8],
> +) -> Result<KVVec<u8>> {
> +    let reply = cmdq.send_sync_command(bar, RmControl::new(h_client, h_object, cmd, params))?;

Why not let the caller construct RmControl?

> +
> +    Result::from(reply.status)?;
> +
> +    Ok(reply.params)
> +}
>
> -- 
> 2.53.0
Re: [PATCH 7/9] gpu: nova-core: gsp: add RM control command infrastructure
Posted by Eliot Courtney 3 weeks, 1 day ago
On Sat Mar 14, 2026 at 12:40 AM JST, Danilo Krummrich wrote:
> On Fri Feb 27, 2026 at 1:32 PM CET, Eliot Courtney wrote:
>> +/// Command for sending an RM control message to the GSP.
>> +struct RmControl<'a> {
>> +    h_client: u32,
>> +    h_object: u32,
>> +    cmd: RmControlMsgFunction,
>> +    params: &'a [u8],
>> +}
>
> Please expand the documentation, especially the fields.

Will do. Will add an explanation of client/device/subdevice/object
plus fix all the names.

>> +/// Response from an RM control message.
>> +pub(crate) struct RmControlReply {
>> +    status: NvStatus,
>> +    params: KVVec<u8>,
>> +}
>> +
>> +impl MessageFromGsp for RmControlReply {
>> +    const FUNCTION: MsgFunction = MsgFunction::GspRmControl;
>> +    type Message = GspRmControl;
>> +    type InitError = Error;
>> +
>> +    fn read(
>> +        msg: &Self::Message,
>> +        sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
>> +    ) -> Result<Self, Self::InitError> {
>> +        Ok(RmControlReply {
>> +            status: msg.status(),
>> +            params: sbuffer.flush_into_kvvec(GFP_KERNEL)?,
>> +        })
>> +    }
>> +}
>> +
>> +/// Sends an RM control command, checks the reply status, and returns the raw parameter bytes.
>> +#[expect(dead_code)]
>> +fn send_rm_control(
>
> Why isn't this a method of Cmdq?

Because this can be fully implemented in terms of existing primitives
available on Cmdq - it doesn't need to know anything about Cmdq
internals (it's a protocol on top of the Cmdq, not at the same level
of abstraction), and it fits the existing pattern of adding helpers for
sending messages to/from GSP (e.g. `get_gsp_info`), so IMO it is nicer
to keep it out of Cmdq.

>
>> +    cmdq: &Cmdq,
>> +    bar: &Bar0,
>> +    h_client: u32,
>> +    h_object: u32,
>> +    cmd: RmControlMsgFunction,
>> +    params: &[u8],
>> +) -> Result<KVVec<u8>> {
>> +    let reply = cmdq.send_sync_command(bar, RmControl::new(h_client, h_object, cmd, params))?;
>
> Why not let the caller construct RmControl?

Yeah, that seems fine to me, as long as we don't make `RmControl`
public outside of this module (so each helper would construct it and
call `send_rm_control`). If `RmControl` is public then it could be
misused and sent directly via `Cmdq`, which makes it easier to forget
to check the reply status.
Re: [PATCH 7/9] gpu: nova-core: gsp: add RM control command infrastructure
Posted by Joel Fernandes 4 weeks ago
On Fri, 27 Feb 2026, Eliot Courtney wrote:

> +fn send_rm_control(
> +    cmdq: &Cmdq,
> +    bar: &Bar0,
> +    h_client: u32,
> +    h_object: u32,
> +    cmd: RmControlMsgFunction,
> +    params: &[u8],
> +) -> Result<KVVec<u8>> {
> +    let reply = cmdq.send_sync_command(bar, RmControl::new(h_client, h_object, cmd, params))?;

This series uses `send_sync_command`, but the cmdq locking series v3 [1]
renamed it to `send_command`? This series will need to be rebased and reposted.

[1]: https://lore.kernel.org/all/20260304-cmdq-locking-v3-0-a6314b708850@nvidia.com/

thanks,

--
Joel Fernandes
Re: [PATCH 7/9] gpu: nova-core: gsp: add RM control command infrastructure
Posted by Zhi Wang 1 month ago
On Fri, 27 Feb 2026 21:32:12 +0900
Eliot Courtney <ecourtney@nvidia.com> wrote:

Tested-by: Zhi Wang <zhiw@nvidia.com>

> Add `RmControl` which implements CommandToGsp for sending RM control
> RPCs.
> 
> Add `RmControlReply` which implements MessageFromGsp for getting the
> reply back.
> 
> Add `send_rm_control` which sends an RM control RPC via the command
> queue using the above structures.
> 
> This gives a generic way to send each RM control RPC. Each new RM
> control RPC can be added by extending RmControlMsgFunction and adding
> its bindings wrappers and writing a helper function to send it via
> `send_rm_control`.
> 
> Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
> ---
>  drivers/gpu/nova-core/gsp.rs             |   1 +
>  drivers/gpu/nova-core/gsp/rm.rs          |   3 +
>  drivers/gpu/nova-core/gsp/rm/commands.rs | 111
> +++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+)
> 
> diff --git a/drivers/gpu/nova-core/gsp.rs
> b/drivers/gpu/nova-core/gsp.rs index a6f3918c20b1..1a1c4e9808ac 100644
> --- a/drivers/gpu/nova-core/gsp.rs
> +++ b/drivers/gpu/nova-core/gsp.rs
> @@ -17,6 +17,7 @@
>  pub(crate) mod cmdq;
>  pub(crate) mod commands;
>  mod fw;
> +pub(crate) mod rm;
>  mod sequencer;
>  
>  pub(crate) use fw::{
> diff --git a/drivers/gpu/nova-core/gsp/rm.rs
> b/drivers/gpu/nova-core/gsp/rm.rs new file mode 100644
> index 000000000000..10e879a3e842
> --- /dev/null
> +++ b/drivers/gpu/nova-core/gsp/rm.rs
> @@ -0,0 +1,3 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +pub(crate) mod commands;
> diff --git a/drivers/gpu/nova-core/gsp/rm/commands.rs
> b/drivers/gpu/nova-core/gsp/rm/commands.rs new file mode 100644
> index 000000000000..16bcf88644db
> --- /dev/null
> +++ b/drivers/gpu/nova-core/gsp/rm/commands.rs
> @@ -0,0 +1,111 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use core::{
> +    array,
> +    convert::Infallible, //
> +};
> +
> +use kernel::prelude::*;
> +
> +use crate::{
> +    driver::Bar0,
> +    gsp::{
> +        cmdq::{
> +            Cmdq,
> +            CommandToGsp,
> +            MessageFromGsp, //
> +        },
> +        fw::{
> +            rm::*,
> +            MsgFunction,
> +            NvStatus, //
> +        },
> +    },
> +    sbuffer::SBufferIter,
> +};
> +
> +/// Command for sending an RM control message to the GSP.
> +struct RmControl<'a> {
> +    h_client: u32,
> +    h_object: u32,
> +    cmd: RmControlMsgFunction,
> +    params: &'a [u8],
> +}
> +
> +impl<'a> RmControl<'a> {
> +    /// Creates a new RM control command.
> +    fn new(h_client: u32, h_object: u32, cmd: RmControlMsgFunction,
> params: &'a [u8]) -> Self {
> +        Self {
> +            h_client,
> +            h_object,
> +            cmd,
> +            params,
> +        }
> +    }
> +}
> +
> +impl CommandToGsp for RmControl<'_> {
> +    const FUNCTION: MsgFunction = MsgFunction::GspRmControl;
> +    type Command = GspRmControl;
> +    type Reply = RmControlReply;
> +    type InitError = Infallible;
> +
> +    fn init(&self) -> impl Init<Self::Command, Self::InitError> {
> +        GspRmControl::new(
> +            self.h_client,
> +            self.h_object,
> +            self.cmd,
> +            self.params.len() as u32,
> +        )
> +    }
> +
> +    fn variable_payload_len(&self) -> usize {
> +        self.params.len()
> +    }
> +
> +    fn init_variable_payload(
> +        &self,
> +        dst: &mut SBufferIter<array::IntoIter<&mut [u8], 2>>,
> +    ) -> Result {
> +        dst.write_all(self.params)
> +    }
> +}
> +
> +/// Response from an RM control message.
> +pub(crate) struct RmControlReply {
> +    status: NvStatus,
> +    params: KVVec<u8>,
> +}
> +
> +impl MessageFromGsp for RmControlReply {
> +    const FUNCTION: MsgFunction = MsgFunction::GspRmControl;
> +    type Message = GspRmControl;
> +    type InitError = Error;
> +
> +    fn read(
> +        msg: &Self::Message,
> +        sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> +    ) -> Result<Self, Self::InitError> {
> +        Ok(RmControlReply {
> +            status: msg.status(),
> +            params: sbuffer.flush_into_kvvec(GFP_KERNEL)?,
> +        })
> +    }
> +}
> +
> +/// Sends an RM control command, checks the reply status, and
> returns the raw parameter bytes. +#[expect(dead_code)]
> +fn send_rm_control(
> +    cmdq: &Cmdq,
> +    bar: &Bar0,
> +    h_client: u32,
> +    h_object: u32,
> +    cmd: RmControlMsgFunction,
> +    params: &[u8],
> +) -> Result<KVVec<u8>> {
> +    let reply = cmdq.send_sync_command(bar, RmControl::new(h_client,
> h_object, cmd, params))?; +
> +    Result::from(reply.status)?;
> +
> +    Ok(reply.params)
> +}
>