1 // SPDX-License-Identifier: GPL-2.0 2 3 use kernel::{ 4 auxiliary, 5 device::Core, 6 pci, 7 pci::{ 8 Class, 9 ClassMask, 10 Vendor, // 11 }, 12 prelude::*, 13 sizes::SZ_16M, 14 sync::atomic::{ 15 Atomic, 16 Relaxed, // 17 }, 18 types::ForLt, 19 }; 20 21 use crate::gpu::Gpu; 22 23 /// Counter for generating unique auxiliary device IDs. 24 static AUXILIARY_ID_COUNTER: Atomic<u32> = Atomic::new(0); 25 26 #[pin_data] 27 pub(crate) struct NovaCore<'bound> { 28 #[pin] 29 pub(crate) gpu: Gpu<'bound>, 30 bar: pci::Bar<'bound, BAR0_SIZE>, 31 #[allow(clippy::type_complexity)] 32 _reg: auxiliary::Registration<'bound, ForLt!(())>, 33 } 34 35 pub(crate) struct NovaCoreDriver; 36 37 const BAR0_SIZE: usize = SZ_16M; 38 39 pub(crate) type Bar0 = kernel::io::Mmio<BAR0_SIZE>; 40 41 kernel::pci_device_table!( 42 PCI_TABLE, 43 MODULE_PCI_TABLE, 44 <NovaCoreDriver as pci::Driver>::IdInfo, 45 [ 46 // Modern NVIDIA GPUs will show up as either VGA or 3D controllers. 47 ( 48 pci::DeviceId::from_class_and_vendor( 49 Class::DISPLAY_VGA, 50 ClassMask::ClassSubclass, 51 Vendor::NVIDIA 52 ), 53 () 54 ), 55 ( 56 pci::DeviceId::from_class_and_vendor( 57 Class::DISPLAY_3D, 58 ClassMask::ClassSubclass, 59 Vendor::NVIDIA 60 ), 61 () 62 ), 63 ] 64 ); 65 66 impl pci::Driver for NovaCoreDriver { 67 type IdInfo = (); 68 type Data<'bound> = NovaCore<'bound>; 69 const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; 70 71 fn probe<'bound>( 72 pdev: &'bound pci::Device<Core<'_>>, 73 _info: &'bound Self::IdInfo, 74 ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { 75 pin_init::pin_init_scope(move || { 76 dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); 77 78 pdev.enable_device_mem()?; 79 pdev.set_master(); 80 81 Ok(try_pin_init!(NovaCore { 82 bar: pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")?, 83 // TODO: Use `&bar` self-referential pin-init syntax once available. 84 // 85 // SAFETY: `bar` is initialized before this expression is evaluated 86 // (`try_pin_init!()` initializes fields in declaration order), lives at a pinned 87 // stable address, and is dropped after `gpu` (struct field drop order). 88 gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) }), 89 _reg: auxiliary::Registration::new( 90 pdev.as_ref(), 91 c"nova-drm", 92 // TODO[XARR]: Use XArray or perhaps IDA for proper ID allocation/recycling. For 93 // now, use a simple atomic counter that never recycles IDs. 94 AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed), 95 crate::MODULE_NAME, 96 (), 97 )?, 98 })) 99 }) 100 } 101 } 102