drm/panthor: Add the MMU/VM logical block

MMU and VM management is related and placed in the same source file.

Page table updates are delegated to the io-pgtable-arm driver that's in
the iommu subsystem.

The VM management logic is based on drm_gpuva_mgr, and is assuming the
VA space is mostly managed by the usermode driver, except for a reserved
portion of this VA-space that's used for kernel objects (like the heap
contexts/chunks).

Both asynchronous and synchronous VM operations are supported, and
internal helpers are exposed to allow other logical blocks to map their
buffers in the GPU VA space.

There's one VM_BIND queue per-VM (meaning the Vulkan driver can only
expose one sparse-binding queue), and this bind queue is managed with
a 1:1 drm_sched_entity:drm_gpu_scheduler, such that each VM gets its own
independent execution queue, avoiding VM operation serialization at the
device level (things are still serialized at the VM level).

The rest is just implementation details that are hopefully well explained
in the documentation.

v6:
- Add Maxime's and Heiko's acks
- Add Steve's R-b
- Adjust the TRANSCFG value to account for SW VA space limitation on
  32-bit systems
- Keep header inclusion alphabetically ordered

v5:
- Fix a double panthor_vm_cleanup_op_ctx() call
- Fix a race between panthor_vm_prepare_map_op_ctx() and
  panthor_vm_bo_put()
- Fix panthor_vm_pool_destroy_vm() kernel doc
- Fix paddr adjustment in panthor_vm_map_pages()
- Fix bo_offset calculation in panthor_vm_get_bo_for_va()

v4:
- Add an helper to return the VM state
- Check drmm_mutex_init() return code
- Remove the VM from the AS reclaim list when panthor_vm_active() is
  called
- Count the number of active VM users instead of considering there's
  at most one user (several scheduling groups can point to the same
  vM)
- Pre-allocate a VMA object for unmap operations (unmaps can trigger
  a sm_step_remap() call)
- Check vm->root_page_table instead of vm->pgtbl_ops to detect if
  the io-pgtable is trying to allocate the root page table
- Don't memset() the va_node in panthor_vm_alloc_va(), make it a
  caller requirement
- Fix the kernel doc in a few places
- Drop the panthor_vm::base offset constraint and modify
  panthor_vm_put() to explicitly check for a NULL value
- Fix unbalanced vm_bo refcount in panthor_gpuva_sm_step_remap()
- Drop stale comments about the shared_bos list
- Patch mmu_features::va_bits on 32-bit builds to reflect the
  io_pgtable limitation and let the UMD know about it

v3:
- Add acks for the MIT/GPL2 relicensing
- Propagate MMU faults to the scheduler
- Move pages pinning/unpinning out of the dma_signalling path
- Fix 32-bit support
- Rework the user/kernel VA range calculation
- Make the auto-VA range explicit (auto-VA range doesn't cover the full
  kernel-VA range on the MCU VM)
- Let callers of panthor_vm_alloc_va() allocate the drm_mm_node
  (embedded in panthor_kernel_bo now)
- Adjust things to match the latest drm_gpuvm changes (extobj tracking,
  resv prep and more)
- Drop the per-AS lock and use slots_lock (fixes a race on vm->as.id)
- Set as.id to -1 when reusing an address space from the LRU list
- Drop misleading comment about page faults
- Remove check for irq being assigned in panthor_mmu_unplug()

Co-developed-by: Steven Price <steven.price@arm.com>
Signed-off-by: Steven Price <steven.price@arm.com>
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Acked-by: Steven Price <steven.price@arm.com> # MIT+GPL2 relicensing,Arm
Acked-by: Grant Likely <grant.likely@linaro.org> # MIT+GPL2 relicensing,Linaro
Acked-by: Boris Brezillon <boris.brezillon@collabora.com> # MIT+GPL2 relicensing,Collabora
Reviewed-by: Steven Price <steven.price@arm.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Acked-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20240229162230.2634044-8-boris.brezillon@collabora.com
This commit is contained in:
Boris Brezillon 2024-02-29 17:22:21 +01:00
parent fac9b22df4
commit 647810ec24
2 changed files with 2870 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0 or MIT */
/* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
/* Copyright 2023 Collabora ltd. */
#ifndef __PANTHOR_MMU_H__
#define __PANTHOR_MMU_H__
#include <linux/dma-resv.h>
struct drm_exec;
struct drm_sched_job;
struct panthor_gem_object;
struct panthor_heap_pool;
struct panthor_vm;
struct panthor_vma;
struct panthor_mmu;
int panthor_mmu_init(struct panthor_device *ptdev);
void panthor_mmu_unplug(struct panthor_device *ptdev);
void panthor_mmu_pre_reset(struct panthor_device *ptdev);
void panthor_mmu_post_reset(struct panthor_device *ptdev);
void panthor_mmu_suspend(struct panthor_device *ptdev);
void panthor_mmu_resume(struct panthor_device *ptdev);
int panthor_vm_map_bo_range(struct panthor_vm *vm, struct panthor_gem_object *bo,
u64 offset, u64 size, u64 va, u32 flags);
int panthor_vm_unmap_range(struct panthor_vm *vm, u64 va, u64 size);
struct panthor_gem_object *
panthor_vm_get_bo_for_va(struct panthor_vm *vm, u64 va, u64 *bo_offset);
int panthor_vm_active(struct panthor_vm *vm);
void panthor_vm_idle(struct panthor_vm *vm);
int panthor_vm_as(struct panthor_vm *vm);
struct panthor_heap_pool *
panthor_vm_get_heap_pool(struct panthor_vm *vm, bool create);
struct panthor_vm *panthor_vm_get(struct panthor_vm *vm);
void panthor_vm_put(struct panthor_vm *vm);
struct panthor_vm *panthor_vm_create(struct panthor_device *ptdev, bool for_mcu,
u64 kernel_va_start, u64 kernel_va_size,
u64 kernel_auto_va_start,
u64 kernel_auto_va_size);
int panthor_vm_prepare_mapped_bos_resvs(struct drm_exec *exec,
struct panthor_vm *vm,
u32 slot_count);
int panthor_vm_add_bos_resvs_deps_to_job(struct panthor_vm *vm,
struct drm_sched_job *job);
void panthor_vm_add_job_fence_to_bos_resvs(struct panthor_vm *vm,
struct drm_sched_job *job);
struct dma_resv *panthor_vm_resv(struct panthor_vm *vm);
struct drm_gem_object *panthor_vm_root_gem(struct panthor_vm *vm);
void panthor_vm_pool_destroy(struct panthor_file *pfile);
int panthor_vm_pool_create(struct panthor_file *pfile);
int panthor_vm_pool_create_vm(struct panthor_device *ptdev,
struct panthor_vm_pool *pool,
struct drm_panthor_vm_create *args);
int panthor_vm_pool_destroy_vm(struct panthor_vm_pool *pool, u32 handle);
struct panthor_vm *panthor_vm_pool_get_vm(struct panthor_vm_pool *pool, u32 handle);
bool panthor_vm_has_unhandled_faults(struct panthor_vm *vm);
bool panthor_vm_is_unusable(struct panthor_vm *vm);
/*
* PANTHOR_VM_KERNEL_AUTO_VA: Use this magic address when you want the GEM
* logic to auto-allocate the virtual address in the reserved kernel VA range.
*/
#define PANTHOR_VM_KERNEL_AUTO_VA ~0ull
int panthor_vm_alloc_va(struct panthor_vm *vm, u64 va, u64 size,
struct drm_mm_node *va_node);
void panthor_vm_free_va(struct panthor_vm *vm, struct drm_mm_node *va_node);
int panthor_vm_bind_exec_sync_op(struct drm_file *file,
struct panthor_vm *vm,
struct drm_panthor_vm_bind_op *op);
struct drm_sched_job *
panthor_vm_bind_job_create(struct drm_file *file,
struct panthor_vm *vm,
const struct drm_panthor_vm_bind_op *op);
void panthor_vm_bind_job_put(struct drm_sched_job *job);
int panthor_vm_bind_job_prepare_resvs(struct drm_exec *exec,
struct drm_sched_job *job);
void panthor_vm_bind_job_update_resvs(struct drm_exec *exec, struct drm_sched_job *job);
void panthor_vm_update_resvs(struct panthor_vm *vm, struct drm_exec *exec,
struct dma_fence *fence,
enum dma_resv_usage private_usage,
enum dma_resv_usage extobj_usage);
int panthor_mmu_pt_cache_init(void);
void panthor_mmu_pt_cache_fini(void);
#ifdef CONFIG_DEBUG_FS
void panthor_mmu_debugfs_init(struct drm_minor *minor);
#endif
#endif