Add a declarative macro impl_num_enum!() to generate both From<Enum>
for primitive and TryFrom<primitive> for Enum implementations for
repr(primitive) enums. This addresses the TODO[FPRI] markers
throughout the driver.

The macro accepts a list of variants to map, allowing certain variants
to be excluded from the reverse mapping (e.g. dead_code variants like
FalconModSelAlgo::Aes).

Replace the manual TryFrom and impl_from_enum_to_u8!() boilerplate for:
  - FalconCoreRev
  - FalconSecurityModel
  - FalconModSelAlgo
  - DmaTrfCmdSize
  - FalconFbifTarget
  - Architecture

FalconCoreRevSubversion retains its manual TryFrom because it requires
a bitmask operation on the input value. The Chipset enum retains its
existing define_chipset!() macro which already generates TryFrom.

While at it, add the missing repr(u8) attribute to FalconFbifTarget,
which is needed for the enum-to-primitive cast to be well-defined.

Signed-off-by: Artem Lytkin <[email protected]>
---
 drivers/gpu/nova-core/falcon.rs | 128 ++++++--------------------------
 drivers/gpu/nova-core/gpu.rs    |  21 +-----
 drivers/gpu/nova-core/num.rs    |  34 +++++++++
 3 files changed, 57 insertions(+), 126 deletions(-)

diff --git a/drivers/gpu/nova-core/falcon.rs b/drivers/gpu/nova-core/falcon.rs
index 82c661aef594..5b67cabe02f2 100644
--- a/drivers/gpu/nova-core/falcon.rs
+++ b/drivers/gpu/nova-core/falcon.rs
@@ -23,6 +23,7 @@
     driver::Bar0,
     gpu::Chipset,
     num::{
+        impl_num_enum,
         FromSafeCast,
         IntoSafeCast, //
     },
@@ -34,17 +35,6 @@
 mod hal;
 pub(crate) mod sec2;
 
-// TODO[FPRI]: Replace with `ToPrimitive`.
-macro_rules! impl_from_enum_to_u8 {
-    ($enum_type:ty) => {
-        impl From<$enum_type> for u8 {
-            fn from(value: $enum_type) -> Self {
-                value as u8
-            }
-        }
-    };
-}
-
 /// Revision number of a falcon core, used in the 
[`crate::regs::NV_PFALCON_FALCON_HWCFG1`]
 /// register.
 #[repr(u8)]
@@ -59,29 +49,7 @@ pub(crate) enum FalconCoreRev {
     Rev6 = 6,
     Rev7 = 7,
 }
-impl_from_enum_to_u8!(FalconCoreRev);
-
-// TODO[FPRI]: replace with `FromPrimitive`.
-impl TryFrom<u8> for FalconCoreRev {
-    type Error = Error;
-
-    fn try_from(value: u8) -> Result<Self> {
-        use FalconCoreRev::*;
-
-        let rev = match value {
-            1 => Rev1,
-            2 => Rev2,
-            3 => Rev3,
-            4 => Rev4,
-            5 => Rev5,
-            6 => Rev6,
-            7 => Rev7,
-            _ => return Err(EINVAL),
-        };
-
-        Ok(rev)
-    }
-}
+impl_num_enum!(FalconCoreRev: u8 [Rev1, Rev2, Rev3, Rev4, Rev5, Rev6, Rev7] => 
EINVAL);
 
 /// Revision subversion number of a falcon core, used in the
 /// [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] register.
@@ -94,24 +62,27 @@ pub(crate) enum FalconCoreRevSubversion {
     Subversion2 = 2,
     Subversion3 = 3,
 }
-impl_from_enum_to_u8!(FalconCoreRevSubversion);
 
-// TODO[FPRI]: replace with `FromPrimitive`.
+impl From<FalconCoreRevSubversion> for u8 {
+    fn from(val: FalconCoreRevSubversion) -> u8 {
+        val as u8
+    }
+}
+
+// Manual TryFrom is required here due to the bitmask operation on the input 
value.
 impl TryFrom<u8> for FalconCoreRevSubversion {
     type Error = Error;
 
     fn try_from(value: u8) -> Result<Self> {
         use FalconCoreRevSubversion::*;
 
-        let sub_version = match value & 0b11 {
-            0 => Subversion0,
-            1 => Subversion1,
-            2 => Subversion2,
-            3 => Subversion3,
-            _ => return Err(EINVAL),
-        };
-
-        Ok(sub_version)
+        match value & 0b11 {
+            0 => Ok(Subversion0),
+            1 => Ok(Subversion1),
+            2 => Ok(Subversion2),
+            3 => Ok(Subversion3),
+            _ => Err(EINVAL),
+        }
     }
 }
 
@@ -138,25 +109,7 @@ pub(crate) enum FalconSecurityModel {
     /// Also known as High-Secure, Privilege Level 3 or PL3.
     Heavy = 3,
 }
-impl_from_enum_to_u8!(FalconSecurityModel);
-
-// TODO[FPRI]: replace with `FromPrimitive`.
-impl TryFrom<u8> for FalconSecurityModel {
-    type Error = Error;
-
-    fn try_from(value: u8) -> Result<Self> {
-        use FalconSecurityModel::*;
-
-        let sec_model = match value {
-            0 => None,
-            2 => Light,
-            3 => Heavy,
-            _ => return Err(EINVAL),
-        };
-
-        Ok(sec_model)
-    }
-}
+impl_num_enum!(FalconSecurityModel: u8 [None, Light, Heavy] => EINVAL);
 
 /// Signing algorithm for a given firmware, used in the 
[`crate::regs::NV_PFALCON2_FALCON_MOD_SEL`]
 /// register. It is passed to the Falcon Boot ROM (BROM) as a parameter.
@@ -170,19 +123,7 @@ pub(crate) enum FalconModSelAlgo {
     #[default]
     Rsa3k = 1,
 }
-impl_from_enum_to_u8!(FalconModSelAlgo);
-
-// TODO[FPRI]: replace with `FromPrimitive`.
-impl TryFrom<u8> for FalconModSelAlgo {
-    type Error = Error;
-
-    fn try_from(value: u8) -> Result<Self> {
-        match value {
-            1 => Ok(FalconModSelAlgo::Rsa3k),
-            _ => Err(EINVAL),
-        }
-    }
-}
+impl_num_enum!(FalconModSelAlgo: u8 [Rsa3k] => EINVAL);
 
 /// Valid values for the `size` field of the 
[`crate::regs::NV_PFALCON_FALCON_DMATRFCMD`] register.
 #[repr(u8)]
@@ -192,19 +133,7 @@ pub(crate) enum DmaTrfCmdSize {
     #[default]
     Size256B = 0x6,
 }
-impl_from_enum_to_u8!(DmaTrfCmdSize);
-
-// TODO[FPRI]: replace with `FromPrimitive`.
-impl TryFrom<u8> for DmaTrfCmdSize {
-    type Error = Error;
-
-    fn try_from(value: u8) -> Result<Self> {
-        match value {
-            0x6 => Ok(Self::Size256B),
-            _ => Err(EINVAL),
-        }
-    }
-}
+impl_num_enum!(DmaTrfCmdSize: u8 [Size256B] => EINVAL);
 
 /// Currently active core on a dual falcon/riscv (Peregrine) controller.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
@@ -247,6 +176,7 @@ pub(crate) enum FalconMem {
 /// This determines the memory type for external memory access during a DMA 
transfer, which is
 /// performed by the Falcon's Framebuffer DMA (FBDMA) engine. See falcon.rst 
for more details.
 #[derive(Debug, Clone, Default)]
+#[repr(u8)]
 pub(crate) enum FalconFbifTarget {
     /// VRAM.
     #[default]
@@ -257,23 +187,7 @@ pub(crate) enum FalconFbifTarget {
     /// Non-coherent system memory (System DRAM).
     NoncoherentSysmem = 2,
 }
-impl_from_enum_to_u8!(FalconFbifTarget);
-
-// TODO[FPRI]: replace with `FromPrimitive`.
-impl TryFrom<u8> for FalconFbifTarget {
-    type Error = Error;
-
-    fn try_from(value: u8) -> Result<Self> {
-        let res = match value {
-            0 => Self::LocalFb,
-            1 => Self::CoherentSysmem,
-            2 => Self::NoncoherentSysmem,
-            _ => return Err(EINVAL),
-        };
-
-        Ok(res)
-    }
-}
+impl_num_enum!(FalconFbifTarget: u8 [LocalFb, CoherentSysmem, 
NoncoherentSysmem] => EINVAL);
 
 /// Type of memory addresses to use.
 #[derive(Debug, Clone, Default)]
diff --git a/drivers/gpu/nova-core/gpu.rs b/drivers/gpu/nova-core/gpu.rs
index 629c9d2dc994..045bd35f2d8f 100644
--- a/drivers/gpu/nova-core/gpu.rs
+++ b/drivers/gpu/nova-core/gpu.rs
@@ -19,6 +19,7 @@
     fb::SysmemFlush,
     gfw,
     gsp::Gsp,
+    num::impl_num_enum,
     regs,
 };
 
@@ -135,25 +136,7 @@ pub(crate) enum Architecture {
     Ada = 0x19,
 }
 
-impl TryFrom<u8> for Architecture {
-    type Error = Error;
-
-    fn try_from(value: u8) -> Result<Self> {
-        match value {
-            0x16 => Ok(Self::Turing),
-            0x17 => Ok(Self::Ampere),
-            0x19 => Ok(Self::Ada),
-            _ => Err(ENODEV),
-        }
-    }
-}
-
-impl From<Architecture> for u8 {
-    fn from(value: Architecture) -> Self {
-        // CAST: `Architecture` is `repr(u8)`, so this cast is always lossless.
-        value as u8
-    }
-}
+impl_num_enum!(Architecture: u8 [Turing, Ampere, Ada] => ENODEV);
 
 pub(crate) struct Revision {
     major: u8,
diff --git a/drivers/gpu/nova-core/num.rs b/drivers/gpu/nova-core/num.rs
index c952a834e662..d5db97c3de0f 100644
--- a/drivers/gpu/nova-core/num.rs
+++ b/drivers/gpu/nova-core/num.rs
@@ -215,3 +215,37 @@ pub(crate) const fn [<$from _into_ $into>]<const N: 
$from>() -> $into {
 impl_const_into!(u64 => { u8, u16, u32 });
 impl_const_into!(u32 => { u8, u16 });
 impl_const_into!(u16 => { u8 });
+
+/// Implements [`TryFrom`] and [`From`] conversions between a 
`#[repr(primitive)]` enum and its
+/// underlying primitive type.
+///
+/// The [`TryFrom`] conversion returns the specified error for unrecognized 
values. The [`From`]
+/// conversion casts the enum variant to the primitive type.
+///
+/// Only the variants listed in the macro invocation are recognized by 
[`TryFrom`]. This allows
+/// excluding certain variants (e.g., dead code) from the reverse mapping.
+///
+/// The enum **must** have a `#[repr($prim_type)]` attribute. Without it, the 
`as` cast in the
+/// generated [`From`] impl is not guaranteed to be correct.
+macro_rules! impl_num_enum {
+    ($enum_type:ty : $prim_type:ty [$($variant:ident),+ $(,)?] => $err:expr) 
=> {
+        impl From<$enum_type> for $prim_type {
+            fn from(val: $enum_type) -> $prim_type {
+                val as $prim_type
+            }
+        }
+
+        impl TryFrom<$prim_type> for $enum_type {
+            type Error = kernel::error::Error;
+
+            fn try_from(val: $prim_type) -> core::result::Result<Self, 
Self::Error> {
+                $(if val == <$enum_type>::$variant as $prim_type {
+                    return Ok(<$enum_type>::$variant);
+                })*
+                Err($err)
+            }
+        }
+    };
+}
+
+pub(crate) use impl_num_enum;
-- 
2.43.0

Reply via email to