154e6baf1SDanilo Krummrich // SPDX-License-Identifier: GPL-2.0 254e6baf1SDanilo Krummrich 354e6baf1SDanilo Krummrich use kernel::{device, devres::Devres, error::code::*, pci, prelude::*}; 454e6baf1SDanilo Krummrich 554e6baf1SDanilo Krummrich use crate::driver::Bar0; 654e6baf1SDanilo Krummrich use crate::firmware::{Firmware, FIRMWARE_VERSION}; 754e6baf1SDanilo Krummrich use crate::regs; 854e6baf1SDanilo Krummrich use crate::util; 954e6baf1SDanilo Krummrich use core::fmt; 1054e6baf1SDanilo Krummrich 1154e6baf1SDanilo Krummrich macro_rules! define_chipset { 1254e6baf1SDanilo Krummrich ({ $($variant:ident = $value:expr),* $(,)* }) => 1354e6baf1SDanilo Krummrich { 1454e6baf1SDanilo Krummrich /// Enum representation of the GPU chipset. 1554e6baf1SDanilo Krummrich #[derive(fmt::Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] 1654e6baf1SDanilo Krummrich pub(crate) enum Chipset { 1754e6baf1SDanilo Krummrich $($variant = $value),*, 1854e6baf1SDanilo Krummrich } 1954e6baf1SDanilo Krummrich 2054e6baf1SDanilo Krummrich impl Chipset { 2154e6baf1SDanilo Krummrich pub(crate) const ALL: &'static [Chipset] = &[ 2254e6baf1SDanilo Krummrich $( Chipset::$variant, )* 2354e6baf1SDanilo Krummrich ]; 2454e6baf1SDanilo Krummrich 2554e6baf1SDanilo Krummrich pub(crate) const NAMES: [&'static str; Self::ALL.len()] = [ 2654e6baf1SDanilo Krummrich $( util::const_bytes_to_str( 2754e6baf1SDanilo Krummrich util::to_lowercase_bytes::<{ stringify!($variant).len() }>( 2854e6baf1SDanilo Krummrich stringify!($variant) 2954e6baf1SDanilo Krummrich ).as_slice() 3054e6baf1SDanilo Krummrich ), )* 3154e6baf1SDanilo Krummrich ]; 3254e6baf1SDanilo Krummrich } 3354e6baf1SDanilo Krummrich 3454e6baf1SDanilo Krummrich // TODO replace with something like derive(FromPrimitive) 3554e6baf1SDanilo Krummrich impl TryFrom<u32> for Chipset { 3654e6baf1SDanilo Krummrich type Error = kernel::error::Error; 3754e6baf1SDanilo Krummrich 3854e6baf1SDanilo Krummrich fn try_from(value: u32) -> Result<Self, Self::Error> { 3954e6baf1SDanilo Krummrich match value { 4054e6baf1SDanilo Krummrich $( $value => Ok(Chipset::$variant), )* 4154e6baf1SDanilo Krummrich _ => Err(ENODEV), 4254e6baf1SDanilo Krummrich } 4354e6baf1SDanilo Krummrich } 4454e6baf1SDanilo Krummrich } 4554e6baf1SDanilo Krummrich } 4654e6baf1SDanilo Krummrich } 4754e6baf1SDanilo Krummrich 4854e6baf1SDanilo Krummrich define_chipset!({ 4954e6baf1SDanilo Krummrich // Turing 5054e6baf1SDanilo Krummrich TU102 = 0x162, 5154e6baf1SDanilo Krummrich TU104 = 0x164, 5254e6baf1SDanilo Krummrich TU106 = 0x166, 5354e6baf1SDanilo Krummrich TU117 = 0x167, 5454e6baf1SDanilo Krummrich TU116 = 0x168, 5554e6baf1SDanilo Krummrich // Ampere 5654e6baf1SDanilo Krummrich GA100 = 0x170, 5754e6baf1SDanilo Krummrich GA102 = 0x172, 5854e6baf1SDanilo Krummrich GA103 = 0x173, 5954e6baf1SDanilo Krummrich GA104 = 0x174, 6054e6baf1SDanilo Krummrich GA106 = 0x176, 6154e6baf1SDanilo Krummrich GA107 = 0x177, 6254e6baf1SDanilo Krummrich // Ada 6354e6baf1SDanilo Krummrich AD102 = 0x192, 6454e6baf1SDanilo Krummrich AD103 = 0x193, 6554e6baf1SDanilo Krummrich AD104 = 0x194, 6654e6baf1SDanilo Krummrich AD106 = 0x196, 6754e6baf1SDanilo Krummrich AD107 = 0x197, 6854e6baf1SDanilo Krummrich }); 6954e6baf1SDanilo Krummrich 7054e6baf1SDanilo Krummrich impl Chipset { arch(&self) -> Architecture7154e6baf1SDanilo Krummrich pub(crate) fn arch(&self) -> Architecture { 7254e6baf1SDanilo Krummrich match self { 7354e6baf1SDanilo Krummrich Self::TU102 | Self::TU104 | Self::TU106 | Self::TU117 | Self::TU116 => { 7454e6baf1SDanilo Krummrich Architecture::Turing 7554e6baf1SDanilo Krummrich } 7654e6baf1SDanilo Krummrich Self::GA100 | Self::GA102 | Self::GA103 | Self::GA104 | Self::GA106 | Self::GA107 => { 7754e6baf1SDanilo Krummrich Architecture::Ampere 7854e6baf1SDanilo Krummrich } 7954e6baf1SDanilo Krummrich Self::AD102 | Self::AD103 | Self::AD104 | Self::AD106 | Self::AD107 => { 8054e6baf1SDanilo Krummrich Architecture::Ada 8154e6baf1SDanilo Krummrich } 8254e6baf1SDanilo Krummrich } 8354e6baf1SDanilo Krummrich } 8454e6baf1SDanilo Krummrich } 8554e6baf1SDanilo Krummrich 8654e6baf1SDanilo Krummrich // TODO 8754e6baf1SDanilo Krummrich // 8854e6baf1SDanilo Krummrich // The resulting strings are used to generate firmware paths, hence the 8954e6baf1SDanilo Krummrich // generated strings have to be stable. 9054e6baf1SDanilo Krummrich // 9154e6baf1SDanilo Krummrich // Hence, replace with something like strum_macros derive(Display). 9254e6baf1SDanilo Krummrich // 9354e6baf1SDanilo Krummrich // For now, redirect to fmt::Debug for convenience. 9454e6baf1SDanilo Krummrich impl fmt::Display for Chipset { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result9554e6baf1SDanilo Krummrich fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 96*211dcf77SMiguel Ojeda write!(f, "{self:?}") 9754e6baf1SDanilo Krummrich } 9854e6baf1SDanilo Krummrich } 9954e6baf1SDanilo Krummrich 10054e6baf1SDanilo Krummrich /// Enum representation of the GPU generation. 10154e6baf1SDanilo Krummrich #[derive(fmt::Debug)] 10254e6baf1SDanilo Krummrich pub(crate) enum Architecture { 10354e6baf1SDanilo Krummrich Turing = 0x16, 10454e6baf1SDanilo Krummrich Ampere = 0x17, 10554e6baf1SDanilo Krummrich Ada = 0x19, 10654e6baf1SDanilo Krummrich } 10754e6baf1SDanilo Krummrich 10854e6baf1SDanilo Krummrich impl TryFrom<u8> for Architecture { 10954e6baf1SDanilo Krummrich type Error = Error; 11054e6baf1SDanilo Krummrich try_from(value: u8) -> Result<Self>11154e6baf1SDanilo Krummrich fn try_from(value: u8) -> Result<Self> { 11254e6baf1SDanilo Krummrich match value { 11354e6baf1SDanilo Krummrich 0x16 => Ok(Self::Turing), 11454e6baf1SDanilo Krummrich 0x17 => Ok(Self::Ampere), 11554e6baf1SDanilo Krummrich 0x19 => Ok(Self::Ada), 11654e6baf1SDanilo Krummrich _ => Err(ENODEV), 11754e6baf1SDanilo Krummrich } 11854e6baf1SDanilo Krummrich } 11954e6baf1SDanilo Krummrich } 12054e6baf1SDanilo Krummrich 12154e6baf1SDanilo Krummrich pub(crate) struct Revision { 12254e6baf1SDanilo Krummrich major: u8, 12354e6baf1SDanilo Krummrich minor: u8, 12454e6baf1SDanilo Krummrich } 12554e6baf1SDanilo Krummrich 12654e6baf1SDanilo Krummrich impl Revision { from_boot0(boot0: regs::NV_PMC_BOOT_0) -> Self12754e6baf1SDanilo Krummrich fn from_boot0(boot0: regs::NV_PMC_BOOT_0) -> Self { 12854e6baf1SDanilo Krummrich Self { 12954e6baf1SDanilo Krummrich major: boot0.major_revision(), 13054e6baf1SDanilo Krummrich minor: boot0.minor_revision(), 13154e6baf1SDanilo Krummrich } 13254e6baf1SDanilo Krummrich } 13354e6baf1SDanilo Krummrich } 13454e6baf1SDanilo Krummrich 13554e6baf1SDanilo Krummrich impl fmt::Display for Revision { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result13654e6baf1SDanilo Krummrich fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 13754e6baf1SDanilo Krummrich write!(f, "{:x}.{:x}", self.major, self.minor) 13854e6baf1SDanilo Krummrich } 13954e6baf1SDanilo Krummrich } 14054e6baf1SDanilo Krummrich 14154e6baf1SDanilo Krummrich /// Structure holding the metadata of the GPU. 14254e6baf1SDanilo Krummrich pub(crate) struct Spec { 14354e6baf1SDanilo Krummrich chipset: Chipset, 14454e6baf1SDanilo Krummrich /// The revision of the chipset. 14554e6baf1SDanilo Krummrich revision: Revision, 14654e6baf1SDanilo Krummrich } 14754e6baf1SDanilo Krummrich 14854e6baf1SDanilo Krummrich impl Spec { new(bar: &Bar0) -> Result<Spec>14954e6baf1SDanilo Krummrich fn new(bar: &Bar0) -> Result<Spec> { 15054e6baf1SDanilo Krummrich let boot0 = regs::NV_PMC_BOOT_0::read(bar); 15154e6baf1SDanilo Krummrich 15254e6baf1SDanilo Krummrich Ok(Self { 15354e6baf1SDanilo Krummrich chipset: boot0.chipset()?, 15454e6baf1SDanilo Krummrich revision: Revision::from_boot0(boot0), 15554e6baf1SDanilo Krummrich }) 15654e6baf1SDanilo Krummrich } 15754e6baf1SDanilo Krummrich } 15854e6baf1SDanilo Krummrich 15954e6baf1SDanilo Krummrich /// Structure holding the resources required to operate the GPU. 16054e6baf1SDanilo Krummrich #[pin_data] 16154e6baf1SDanilo Krummrich pub(crate) struct Gpu { 16254e6baf1SDanilo Krummrich spec: Spec, 16354e6baf1SDanilo Krummrich /// MMIO mapping of PCI BAR 0 16454e6baf1SDanilo Krummrich bar: Devres<Bar0>, 16554e6baf1SDanilo Krummrich fw: Firmware, 16654e6baf1SDanilo Krummrich } 16754e6baf1SDanilo Krummrich 16854e6baf1SDanilo Krummrich impl Gpu { new( pdev: &pci::Device<device::Bound>, devres_bar: Devres<Bar0>, ) -> Result<impl PinInit<Self>>16954e6baf1SDanilo Krummrich pub(crate) fn new( 17054e6baf1SDanilo Krummrich pdev: &pci::Device<device::Bound>, 17154e6baf1SDanilo Krummrich devres_bar: Devres<Bar0>, 17254e6baf1SDanilo Krummrich ) -> Result<impl PinInit<Self>> { 17354e6baf1SDanilo Krummrich let bar = devres_bar.access(pdev.as_ref())?; 17454e6baf1SDanilo Krummrich let spec = Spec::new(bar)?; 17554e6baf1SDanilo Krummrich let fw = Firmware::new(pdev.as_ref(), spec.chipset, FIRMWARE_VERSION)?; 17654e6baf1SDanilo Krummrich 17754e6baf1SDanilo Krummrich dev_info!( 17854e6baf1SDanilo Krummrich pdev.as_ref(), 17954e6baf1SDanilo Krummrich "NVIDIA (Chipset: {}, Architecture: {:?}, Revision: {})\n", 18054e6baf1SDanilo Krummrich spec.chipset, 18154e6baf1SDanilo Krummrich spec.chipset.arch(), 18254e6baf1SDanilo Krummrich spec.revision 18354e6baf1SDanilo Krummrich ); 18454e6baf1SDanilo Krummrich 18554e6baf1SDanilo Krummrich Ok(pin_init!(Self { 18654e6baf1SDanilo Krummrich spec, 18754e6baf1SDanilo Krummrich bar: devres_bar, 18854e6baf1SDanilo Krummrich fw 18954e6baf1SDanilo Krummrich })) 19054e6baf1SDanilo Krummrich } 19154e6baf1SDanilo Krummrich } 19254e6baf1SDanilo Krummrich