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