| // SPDX-License-Identifier: GPL-2.0 | |
| use kernel::{ | |
| auxiliary, | |
| device::Core, | |
| pci, | |
| pci::{ | |
| Class, | |
| ClassMask, | |
| Vendor, // | |
| }, | |
| prelude::*, | |
| sizes::SZ_16M, | |
| sync::atomic::{ | |
| Atomic, | |
| Relaxed, // | |
| }, | |
| types::ForLt, | |
| }; | |
| use crate::gpu::Gpu; | |
| /// Counter for generating unique auxiliary device IDs. | |
| static AUXILIARY_ID_COUNTER: Atomic<u32> = Atomic::new(0); | |
| #[pin_data] | |
| pub(crate) struct NovaCore<'bound> { | |
| #[pin] | |
| pub(crate) gpu: Gpu<'bound>, | |
| bar: pci::Bar<'bound, BAR0_SIZE>, | |
| #[allow(clippy::type_complexity)] | |
| _reg: auxiliary::Registration<'bound, ForLt!(())>, | |
| } | |
| pub(crate) struct NovaCoreDriver; | |
| const BAR0_SIZE: usize = SZ_16M; | |
| pub(crate) type Bar0<'a> = &'a pci::Bar<'a, BAR0_SIZE>; | |
| kernel::pci_device_table!( | |
| PCI_TABLE, | |
| MODULE_PCI_TABLE, | |
| <NovaCoreDriver as pci::Driver>::IdInfo, | |
| [ | |
| // Modern NVIDIA GPUs will show up as either VGA or 3D controllers. | |
| ( | |
| pci::DeviceId::from_class_and_vendor( | |
| Class::DISPLAY_VGA, | |
| ClassMask::ClassSubclass, | |
| Vendor::NVIDIA | |
| ), | |
| () | |
| ), | |
| ( | |
| pci::DeviceId::from_class_and_vendor( | |
| Class::DISPLAY_3D, | |
| ClassMask::ClassSubclass, | |
| Vendor::NVIDIA | |
| ), | |
| () | |
| ), | |
| ] | |
| ); | |
| impl pci::Driver for NovaCoreDriver { | |
| type IdInfo = (); | |
| type Data<'bound> = NovaCore<'bound>; | |
| const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE; | |
| fn probe<'bound>( | |
| pdev: &'bound pci::Device<Core<'_>>, | |
| _info: &'bound Self::IdInfo, | |
| ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound { | |
| pin_init::pin_init_scope(move || { | |
| dev_dbg!(pdev, "Probe Nova Core GPU driver.\n"); | |
| pdev.enable_device_mem()?; | |
| pdev.set_master(); | |
| Ok(try_pin_init!(NovaCore { | |
| bar: pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")?, | |
| // TODO: Use `&bar` self-referential pin-init syntax once available. | |
| // | |
| // SAFETY: `bar` is initialized before this expression is evaluated | |
| // (`try_pin_init!()` initializes fields in declaration order), lives at a pinned | |
| // stable address, and is dropped after `gpu` (struct field drop order). | |
| gpu <- Gpu::new(pdev, unsafe { &*core::ptr::from_ref(bar) }), | |
| _reg: auxiliary::Registration::new( | |
| pdev.as_ref(), | |
| c"nova-drm", | |
| // TODO[XARR]: Use XArray or perhaps IDA for proper ID allocation/recycling. For | |
| // now, use a simple atomic counter that never recycles IDs. | |
| AUXILIARY_ID_COUNTER.fetch_add(1, Relaxed), | |
| crate::MODULE_NAME, | |
| (), | |
| )?, | |
| })) | |
| }) | |
| } | |
| } |