On Wed Mar 11, 2026 at 9:39 AM JST, Joel Fernandes wrote:
> Add first_usable_fb_region() to GspStaticConfigInfo to extract the first
> usable FB region from GSP's fbRegionInfoParams. Usable regions are those
> that are not reserved or protected.
>
> The extracted region is stored in GetGspStaticInfoReply and exposed via
> usable_fb_region() API for use by the memory subsystem.
>
> Cc: Nikola Djukic <[email protected]>
> Signed-off-by: Joel Fernandes <[email protected]>
> ---
> drivers/gpu/nova-core/gsp/commands.rs | 11 ++++++--
> drivers/gpu/nova-core/gsp/fw/commands.rs | 32 ++++++++++++++++++++++++
> 2 files changed, 41 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/nova-core/gsp/commands.rs
> b/drivers/gpu/nova-core/gsp/commands.rs
> index 8f270eca33be..8d5780d9cace 100644
> --- a/drivers/gpu/nova-core/gsp/commands.rs
> +++ b/drivers/gpu/nova-core/gsp/commands.rs
> @@ -4,6 +4,7 @@
> array,
> convert::Infallible,
> ffi::FromBytesUntilNulError,
> + ops::Range,
> str::Utf8Error, //
> };
>
> @@ -186,22 +187,28 @@ fn init(&self) -> impl Init<Self::Command,
> Self::InitError> {
> }
> }
>
> -/// The reply from the GSP to the [`GetGspInfo`] command.
> +/// The reply from the GSP to the [`GetGspStaticInfo`] command.
> pub(crate) struct GetGspStaticInfoReply {
> gpu_name: [u8; 64],
> + /// Usable FB (VRAM) region for driver memory allocation.
> + #[expect(dead_code)]
> + pub(crate) usable_fb_region: Range<u64>,
> }
>
> impl MessageFromGsp for GetGspStaticInfoReply {
> const FUNCTION: MsgFunction = MsgFunction::GetGspStaticInfo;
> type Message = GspStaticConfigInfo;
> - type InitError = Infallible;
> + type InitError = Error;
>
> fn read(
> msg: &Self::Message,
> _sbuffer: &mut SBufferIter<array::IntoIter<&[u8], 2>>,
> ) -> Result<Self, Self::InitError> {
> + let (base, size) = msg.first_usable_fb_region().ok_or(ENODEV)?;
> +
> Ok(GetGspStaticInfoReply {
> gpu_name: msg.gpu_name_str(),
> + usable_fb_region: base..base.saturating_add(size),
We already return a Result here, so why not use checked_add?:
`base..base.checked_add(size).ok_or(EOVERFLOW)?`
> })
> }
> }
> diff --git a/drivers/gpu/nova-core/gsp/fw/commands.rs
> b/drivers/gpu/nova-core/gsp/fw/commands.rs
> index 67f44421fcc3..cef86cab8a12 100644
> --- a/drivers/gpu/nova-core/gsp/fw/commands.rs
> +++ b/drivers/gpu/nova-core/gsp/fw/commands.rs
> @@ -5,6 +5,7 @@
> use kernel::{device, pci};
>
> use crate::gsp::GSP_PAGE_SIZE;
> +use crate::num::IntoSafeCast;
>
> use super::bindings;
>
> @@ -115,6 +116,37 @@ impl GspStaticConfigInfo {
> pub(crate) fn gpu_name_str(&self) -> [u8; 64] {
> self.0.gpuNameString
> }
> +
> + /// Extract the first usable FB region from GSP firmware data.
> + ///
> + /// Returns the first region suitable for driver memory allocation as a
> `(base, size)` tuple.
> + /// Usable regions are those that:
> + /// - Are not reserved for firmware internal use.
> + /// - Are not protected (hardware-enforced access restrictions).
> + /// - Support compression (can use GPU memory compression for bandwidth).
> + /// - Support ISO (isochronous memory for display requiring guaranteed
> bandwidth).
Are the above conditions all required (AND) or any required (OR)?
Might be worth clarifying in the doc.
> + pub(crate) fn first_usable_fb_region(&self) -> Option<(u64, u64)> {
> + let fb_info = &self.0.fbRegionInfoParams;
> + for i in 0..fb_info.numFBRegions.into_safe_cast() {
> + if let Some(reg) = fb_info.fbRegion.get(i) {
> + // Skip malformed regions where limit < base.
Is it normal that it returns a bunch of broken regions?
> + if reg.limit < reg.base {
> + continue;
> + }
> +
> + // Filter: not reserved, not protected, supports compression
> and ISO.
> + if reg.reserved == 0
> + && reg.bProtected == 0
> + && reg.supportCompressed != 0
> + && reg.supportISO != 0
> + {
> + let size = reg.limit - reg.base + 1;
> + return Some((reg.base, size));
This is identifying a range, so how about returning Option<Range<u64>>
instead? It gets immediately converted into a range anyway.
> + }
> + }
> + }
> + None
> + }
> }
>
> // SAFETY: Padding is explicit and will not contain uninitialized data.