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