mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	Add a GEM implementation based on drm_gem_shmem, and support code for the
PowerVR GPU MMU. The GPU VA manager is used for address space management.
Changes since v8:
- Updated for changes to drm_gpuvm
- Switched to dma_resv locking for vm ops
- Removed linked lists for collecting BOs in vm_context and for freeing
  after ops. This is now done internally in drm_gpuvm
- Corrected license identifiers
Changes since v7:
- kernel-doc fixes
- Remove prefixes from DRM_PVR_BO_* flags
- CREATE_BO ioctl now returns an error if provided size isn't page aligned
- Optimised MMU flushes
Changes since v6:
- Don't initialise kernel_vm_ctx when using MIPS firmware processor
- Rename drm_gpuva_manager uses to drm_gpuvm
- Sync GEM object to device on creation
Changes since v5:
- Use WRITE_ONCE() when writing to page tables
- Add memory barriers to page table insertion
- Fixed double backing page alloc on page table objects
- Fix BO mask checks in DRM_IOCTL_PVR_CREATE_BO handler
- Document use of pvr_page_table_*_idx when preallocing page table objs
- Remove pvr_vm_gpuva_mapping_init()
- Remove NULL check for unmap op in remap function
- Protect gem object with mutex during drm_gpuva_link/unlink
- Defer free or release of page table pages until after TLB flush
- Use drm_gpuva_op_remap_get_unmap_range() helper
Changes since v4:
- Correct sync function in vmap/vunmap function documentation
- Update for upstream GPU VA manager
- Fix missing frees when unmapping drm_gpuva objects
- Always zero GEM BOs on creation
Changes since v3:
- Split MMU and VM code
- Register page table allocations with kmemleak
- Use drm_dev_{enter,exit}
Changes since v2:
- Use GPU VA manager
- Use drm_gem_shmem
Co-developed-by: Matt Coster <matt.coster@imgtec.com>
Signed-off-by: Matt Coster <matt.coster@imgtec.com>
Co-developed-by: Donald Robson <donald.robson@imgtec.com>
Signed-off-by: Donald Robson <donald.robson@imgtec.com>
Signed-off-by: Sarah Walker <sarah.walker@imgtec.com>
Link: https://lore.kernel.org/r/3c96dd170efe759b73897e3675d7310a7c4b06d0.1700668843.git.donald.robson@imgtec.com
Signed-off-by: Maxime Ripard <mripard@kernel.org>
		
	
			
		
			
				
	
	
		
			170 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
	
		
			5.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* SPDX-License-Identifier: GPL-2.0-only OR MIT */
 | 
						|
/* Copyright (c) 2023 Imagination Technologies Ltd. */
 | 
						|
 | 
						|
#ifndef PVR_GEM_H
 | 
						|
#define PVR_GEM_H
 | 
						|
 | 
						|
#include "pvr_rogue_heap_config.h"
 | 
						|
#include "pvr_rogue_meta.h"
 | 
						|
 | 
						|
#include <uapi/drm/pvr_drm.h>
 | 
						|
 | 
						|
#include <drm/drm_gem.h>
 | 
						|
#include <drm/drm_gem_shmem_helper.h>
 | 
						|
#include <drm/drm_mm.h>
 | 
						|
 | 
						|
#include <linux/bitfield.h>
 | 
						|
#include <linux/bits.h>
 | 
						|
#include <linux/const.h>
 | 
						|
#include <linux/compiler_attributes.h>
 | 
						|
#include <linux/kernel.h>
 | 
						|
#include <linux/mutex.h>
 | 
						|
#include <linux/refcount.h>
 | 
						|
#include <linux/scatterlist.h>
 | 
						|
#include <linux/sizes.h>
 | 
						|
#include <linux/types.h>
 | 
						|
 | 
						|
/* Forward declaration from "pvr_device.h". */
 | 
						|
struct pvr_device;
 | 
						|
struct pvr_file;
 | 
						|
 | 
						|
/**
 | 
						|
 * DOC: Flags for DRM_IOCTL_PVR_CREATE_BO (kernel-only)
 | 
						|
 *
 | 
						|
 * Kernel-only values allowed in &pvr_gem_object->flags. The majority of options
 | 
						|
 * for this field are specified in the UAPI header "pvr_drm.h" with a
 | 
						|
 * DRM_PVR_BO_ prefix. To distinguish these internal options (which must exist
 | 
						|
 * in ranges marked as "reserved" in the UAPI header), we drop the DRM prefix.
 | 
						|
 * The public options should be used directly, DRM prefix and all.
 | 
						|
 *
 | 
						|
 * To avoid potentially confusing gaps in the UAPI options, these kernel-only
 | 
						|
 * options are specified "in reverse", starting at bit 63.
 | 
						|
 *
 | 
						|
 * We use "reserved" to refer to bits defined here and not exposed in the UAPI.
 | 
						|
 * Bits not defined anywhere are "undefined".
 | 
						|
 *
 | 
						|
 * CPU mapping options
 | 
						|
 *    :PVR_BO_CPU_CACHED: By default, all GEM objects are mapped write-combined on the CPU. Set this
 | 
						|
 *       flag to override this behaviour and map the object cached.
 | 
						|
 *
 | 
						|
 * Firmware options
 | 
						|
 *    :PVR_BO_FW_NO_CLEAR_ON_RESET: By default, all FW objects are cleared and reinitialised on hard
 | 
						|
 *       reset. Set this flag to override this behaviour and preserve buffer contents on reset.
 | 
						|
 */
 | 
						|
#define PVR_BO_CPU_CACHED BIT_ULL(63)
 | 
						|
 | 
						|
#define PVR_BO_FW_NO_CLEAR_ON_RESET BIT_ULL(62)
 | 
						|
 | 
						|
#define PVR_BO_KERNEL_FLAGS_MASK (PVR_BO_CPU_CACHED | PVR_BO_FW_NO_CLEAR_ON_RESET)
 | 
						|
 | 
						|
/* Bits 61..3 are undefined. */
 | 
						|
/* Bits 2..0 are defined in the UAPI. */
 | 
						|
 | 
						|
/* Other utilities. */
 | 
						|
#define PVR_BO_UNDEFINED_MASK ~(PVR_BO_KERNEL_FLAGS_MASK | DRM_PVR_BO_FLAGS_MASK)
 | 
						|
 | 
						|
/*
 | 
						|
 * All firmware-mapped memory uses (mostly) the same flags. Specifically,
 | 
						|
 * firmware-mapped memory should be:
 | 
						|
 *  * Read/write on the device,
 | 
						|
 *  * Read/write on the CPU, and
 | 
						|
 *  * Write-combined on the CPU.
 | 
						|
 *
 | 
						|
 * The only variation is in caching on the device.
 | 
						|
 */
 | 
						|
#define PVR_BO_FW_FLAGS_DEVICE_CACHED (ULL(0))
 | 
						|
#define PVR_BO_FW_FLAGS_DEVICE_UNCACHED DRM_PVR_BO_BYPASS_DEVICE_CACHE
 | 
						|
 | 
						|
/**
 | 
						|
 * struct pvr_gem_object - powervr-specific wrapper for &struct drm_gem_object
 | 
						|
 */
 | 
						|
struct pvr_gem_object {
 | 
						|
	/**
 | 
						|
	 * @base: The underlying &struct drm_gem_shmem_object.
 | 
						|
	 *
 | 
						|
	 * Do not access this member directly, instead call
 | 
						|
	 * shem_gem_from_pvr_gem().
 | 
						|
	 */
 | 
						|
	struct drm_gem_shmem_object base;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * @flags: Options set at creation-time. Some of these options apply to
 | 
						|
	 * the creation operation itself (which are stored here for reference)
 | 
						|
	 * with the remainder used for mapping options to both the device and
 | 
						|
	 * CPU. These are used every time this object is mapped, but may be
 | 
						|
	 * changed after creation.
 | 
						|
	 *
 | 
						|
	 * Must be a combination of DRM_PVR_BO_* and/or PVR_BO_* flags.
 | 
						|
	 *
 | 
						|
	 * .. note::
 | 
						|
	 *
 | 
						|
	 *    This member is declared const to indicate that none of these
 | 
						|
	 *    options may change or be changed throughout the object's
 | 
						|
	 *    lifetime.
 | 
						|
	 */
 | 
						|
	u64 flags;
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
static_assert(offsetof(struct pvr_gem_object, base) == 0,
 | 
						|
	      "offsetof(struct pvr_gem_object, base) not zero");
 | 
						|
 | 
						|
#define shmem_gem_from_pvr_gem(pvr_obj) (&(pvr_obj)->base)
 | 
						|
 | 
						|
#define shmem_gem_to_pvr_gem(shmem_obj) container_of_const(shmem_obj, struct pvr_gem_object, base)
 | 
						|
 | 
						|
#define gem_from_pvr_gem(pvr_obj) (&(pvr_obj)->base.base)
 | 
						|
 | 
						|
#define gem_to_pvr_gem(gem_obj) container_of_const(gem_obj, struct pvr_gem_object, base.base)
 | 
						|
 | 
						|
/* Functions defined in pvr_gem.c */
 | 
						|
 | 
						|
struct drm_gem_object *pvr_gem_create_object(struct drm_device *drm_dev, size_t size);
 | 
						|
 | 
						|
struct pvr_gem_object *pvr_gem_object_create(struct pvr_device *pvr_dev,
 | 
						|
					     size_t size, u64 flags);
 | 
						|
 | 
						|
int pvr_gem_object_into_handle(struct pvr_gem_object *pvr_obj,
 | 
						|
			       struct pvr_file *pvr_file, u32 *handle);
 | 
						|
struct pvr_gem_object *pvr_gem_object_from_handle(struct pvr_file *pvr_file,
 | 
						|
						  u32 handle);
 | 
						|
 | 
						|
static __always_inline struct sg_table *
 | 
						|
pvr_gem_object_get_pages_sgt(struct pvr_gem_object *pvr_obj)
 | 
						|
{
 | 
						|
	return drm_gem_shmem_get_pages_sgt(shmem_gem_from_pvr_gem(pvr_obj));
 | 
						|
}
 | 
						|
 | 
						|
void *pvr_gem_object_vmap(struct pvr_gem_object *pvr_obj);
 | 
						|
void pvr_gem_object_vunmap(struct pvr_gem_object *pvr_obj);
 | 
						|
 | 
						|
int pvr_gem_get_dma_addr(struct pvr_gem_object *pvr_obj, u32 offset,
 | 
						|
			 dma_addr_t *dma_addr_out);
 | 
						|
 | 
						|
/**
 | 
						|
 * pvr_gem_object_get() - Acquire reference on pvr_gem_object
 | 
						|
 * @pvr_obj: Pointer to object to acquire reference on.
 | 
						|
 */
 | 
						|
static __always_inline void
 | 
						|
pvr_gem_object_get(struct pvr_gem_object *pvr_obj)
 | 
						|
{
 | 
						|
	drm_gem_object_get(gem_from_pvr_gem(pvr_obj));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * pvr_gem_object_put() - Release reference on pvr_gem_object
 | 
						|
 * @pvr_obj: Pointer to object to release reference on.
 | 
						|
 */
 | 
						|
static __always_inline void
 | 
						|
pvr_gem_object_put(struct pvr_gem_object *pvr_obj)
 | 
						|
{
 | 
						|
	drm_gem_object_put(gem_from_pvr_gem(pvr_obj));
 | 
						|
}
 | 
						|
 | 
						|
static __always_inline size_t
 | 
						|
pvr_gem_object_size(struct pvr_gem_object *pvr_obj)
 | 
						|
{
 | 
						|
	return gem_from_pvr_gem(pvr_obj)->size;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* PVR_GEM_H */
 |