xref: /linux/drivers/gpu/nova-core/driver.rs (revision 6dfafbd0299a60bfb5d5e277fdf100037c7ded07)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 use kernel::{
4     auxiliary,
5     c_str,
6     device::Core,
7     dma::Device,
8     dma::DmaMask,
9     pci,
10     pci::{
11         Class,
12         ClassMask,
13         Vendor, //
14     },
15     prelude::*,
16     sizes::SZ_16M,
17     sync::Arc, //
18 };
19 
20 use crate::gpu::Gpu;
21 
22 #[pin_data]
23 pub(crate) struct NovaCore {
24     #[pin]
25     pub(crate) gpu: Gpu,
26     _reg: auxiliary::Registration,
27 }
28 
29 const BAR0_SIZE: usize = SZ_16M;
30 
31 // For now we only support Ampere which can use up to 47-bit DMA addresses.
32 //
33 // TODO: Add an abstraction for this to support newer GPUs which may support
34 // larger DMA addresses. Limiting these GPUs to smaller address widths won't
35 // have any adverse affects, unless installed on systems which require larger
36 // DMA addresses. These systems should be quite rare.
37 const GPU_DMA_BITS: u32 = 47;
38 
39 pub(crate) type Bar0 = pci::Bar<BAR0_SIZE>;
40 
41 kernel::pci_device_table!(
42     PCI_TABLE,
43     MODULE_PCI_TABLE,
44     <NovaCore 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 NovaCore {
67     type IdInfo = ();
68     const ID_TABLE: pci::IdTable<Self::IdInfo> = &PCI_TABLE;
69 
70     fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> Result<Pin<KBox<Self>>> {
71         dev_dbg!(pdev.as_ref(), "Probe Nova Core GPU driver.\n");
72 
73         pdev.enable_device_mem()?;
74         pdev.set_master();
75 
76         // SAFETY: No concurrent DMA allocations or mappings can be made because
77         // the device is still being probed and therefore isn't being used by
78         // other threads of execution.
79         unsafe { pdev.dma_set_mask_and_coherent(DmaMask::new::<GPU_DMA_BITS>())? };
80 
81         let devres_bar = Arc::pin_init(
82             pdev.iomap_region_sized::<BAR0_SIZE>(0, c_str!("nova-core/bar0")),
83             GFP_KERNEL,
84         )?;
85 
86         // Used to provided a `&Bar0` to `Gpu::new` without tying it to the lifetime of
87         // `devres_bar`.
88         let bar_clone = Arc::clone(&devres_bar);
89         let bar = bar_clone.access(pdev.as_ref())?;
90 
91         let this = KBox::pin_init(
92             try_pin_init!(Self {
93                 gpu <- Gpu::new(pdev, devres_bar, bar),
94                 _reg: auxiliary::Registration::new(
95                     pdev.as_ref(),
96                     c_str!("nova-drm"),
97                     0, // TODO[XARR]: Once it lands, use XArray; for now we don't use the ID.
98                     crate::MODULE_NAME
99                 )?,
100             }),
101             GFP_KERNEL,
102         )?;
103 
104         Ok(this)
105     }
106 
107     fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) {
108         this.gpu.unbind(pdev.as_ref());
109     }
110 }
111