xref: /linux/drivers/gpu/drm/tyr/mmu.rs (revision ae047468e047a67d5b6d4c1988da613d77f7a9dc)
1 // SPDX-License-Identifier: GPL-2.0 or MIT
2 
3 //! Memory Management Unit (MMU) module.
4 //!
5 //! The GPU MMU provides a limited number of memory address spaces for use by command streams.
6 //! The MMU translates virtual addresses to physical addresses and manages memory configuration
7 //! and access permissions.
8 //!
9 //! This MMU module is essentially a locked wrapper around a [`SlotManager`] instance.
10 //! The [`SlotManager`] manages the assignment of virtual address spaces to hardware address-space
11 //! (AS) slots. MMU commands such as updates and flushes are carried out by the
12 //! [`AddressSpaceManager`] which actually writes to the MMU registers.
13 #![expect(dead_code)]
14 
15 use core::ops::Range;
16 
17 use kernel::{
18     device::{
19         Bound,
20         Device, //
21     },
22     new_mutex,
23     prelude::*,
24     sync::{
25         Arc,
26         ArcBorrow,
27         Mutex, //
28     }, //
29 };
30 
31 use crate::{
32     driver::IoMem,
33     gpu::GpuInfo,
34     mmu::address_space::{
35         AddressSpaceManager,
36         VmAsData, //
37     },
38     regs::{
39         gpu_control::AS_PRESENT,
40         MAX_AS, //
41     },
42     slot::SlotManager, //
43 };
44 
45 pub(crate) mod address_space;
46 
47 pub(crate) type AsSlotManager<'drm> = SlotManager<AddressSpaceManager<'drm>, MAX_AS>;
48 
49 /// Locked wrapper for carrying out virtual memory (VM) operations on the MMU.
50 #[pin_data]
51 pub(crate) struct Mmu<'drm> {
52     /// Slot Manager instance used to allocate hardware slots and write to MMU registers.
53     #[pin]
54     pub(crate) as_manager: Mutex<AsSlotManager<'drm>>,
55 }
56 
57 impl<'drm> Mmu<'drm> {
58     /// Create an MMU component for this device.
59     pub(crate) fn new(
60         dev: &'drm Device<Bound>,
61         iomem: ArcBorrow<'_, IoMem<'drm>>,
62         gpu_info: &GpuInfo,
63     ) -> Result<Arc<Mmu<'drm>>> {
64         let present = AS_PRESENT::from_raw(gpu_info.as_present).present().get();
65         let slot_count = present.count_ones().try_into()?;
66 
67         let address_space_manager = AddressSpaceManager::new(dev, iomem.into(), present)?;
68         let as_slot_manager =
69             SlotManager::new(address_space_manager, slot_count).inspect_err(|e| {
70                 dev_err!(
71                     dev,
72                     "Failed to initialize MMU slot manager with {} slots: {:?}",
73                     slot_count,
74                     e
75                 );
76             })?;
77         let mmu_init = try_pin_init!(Self{
78             as_manager <- new_mutex!(as_slot_manager),
79         });
80         Arc::pin_init(mmu_init, GFP_KERNEL)
81     }
82 
83     /// Assign a VM to an AS slot, provide a translation table,
84     /// and update the MMU to make the VM resident.
85     pub(crate) fn activate_vm(&self, vm_as_data: ArcBorrow<'_, VmAsData<'drm>>) -> Result {
86         self.as_manager.lock().activate_vm(vm_as_data)
87     }
88 
89     /// Evict a VM from its AS slot and flush the MMU.
90     pub(crate) fn deactivate_vm(&self, vm_as_data: &VmAsData<'drm>) -> Result {
91         self.as_manager.lock().deactivate_vm(vm_as_data)
92     }
93 
94     /// Flush MMU translation caches after a VM update.
95     pub(crate) fn flush_vm(&self, vm_as_data: &VmAsData<'drm>) -> Result {
96         self.as_manager.lock().flush_vm(vm_as_data)
97     }
98 
99     /// Flags the start of a VM update.
100     ///
101     /// If the VM is resident, any GPU access on the memory range being
102     /// updated will be blocked until `Mmu::end_vm_update()` is called.
103     /// This guarantees the atomicity of a VM update.
104     /// If the VM is not resident, this is a NOP.
105     pub(crate) fn start_vm_update(
106         &self,
107         vm_as_data: &VmAsData<'drm>,
108         region: &Range<u64>,
109     ) -> Result {
110         self.as_manager.lock().start_vm_update(vm_as_data, region)
111     }
112 
113     /// Flags the end of a VM update.
114     ///
115     /// If the VM is resident, this will let GPU accesses on the updated
116     /// range go through, in case any of them were blocked.
117     /// If the VM is not resident, this is a NOP.
118     pub(crate) fn end_vm_update(&self, vm_as_data: &VmAsData<'drm>) -> Result {
119         self.as_manager.lock().end_vm_update(vm_as_data)
120     }
121 }
122