Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3d backports from 6.13 #6620

Merged
merged 16 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions drivers/gpu/drm/drm_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,29 +114,55 @@ drm_gem_init(struct drm_device *dev)
}

/**
* drm_gem_object_init - initialize an allocated shmem-backed GEM object
* drm_gem_object_init_with_mnt - initialize an allocated shmem-backed GEM
* object in a given shmfs mountpoint
*
* @dev: drm_device the object should be initialized for
* @obj: drm_gem_object to initialize
* @size: object size
* @gemfs: tmpfs mount where the GEM object will be created. If NULL, use
* the usual tmpfs mountpoint (`shm_mnt`).
*
* Initialize an already allocated GEM object of the specified size with
* shmfs backing store.
*/
int drm_gem_object_init(struct drm_device *dev,
struct drm_gem_object *obj, size_t size)
int drm_gem_object_init_with_mnt(struct drm_device *dev,
struct drm_gem_object *obj, size_t size,
struct vfsmount *gemfs)
{
struct file *filp;

drm_gem_private_object_init(dev, obj, size);

filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
if (gemfs)
filp = shmem_file_setup_with_mnt(gemfs, "drm mm object", size,
VM_NORESERVE);
else
filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);

if (IS_ERR(filp))
return PTR_ERR(filp);

obj->filp = filp;

return 0;
}
EXPORT_SYMBOL(drm_gem_object_init_with_mnt);

/**
* drm_gem_object_init - initialize an allocated shmem-backed GEM object
* @dev: drm_device the object should be initialized for
* @obj: drm_gem_object to initialize
* @size: object size
*
* Initialize an already allocated GEM object of the specified size with
* shmfs backing store.
*/
int drm_gem_object_init(struct drm_device *dev, struct drm_gem_object *obj,
size_t size)
{
return drm_gem_object_init_with_mnt(dev, obj, size, NULL);
}
EXPORT_SYMBOL(drm_gem_object_init);

/**
Expand Down
30 changes: 26 additions & 4 deletions drivers/gpu/drm/drm_gem_shmem_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ static const struct drm_gem_object_funcs drm_gem_shmem_funcs = {
};

static struct drm_gem_shmem_object *
__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)
__drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private,
struct vfsmount *gemfs)
{
struct drm_gem_shmem_object *shmem;
struct drm_gem_object *obj;
Expand All @@ -76,7 +77,7 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)
drm_gem_private_object_init(dev, obj, size);
shmem->map_wc = false; /* dma-buf mappings use always writecombine */
} else {
ret = drm_gem_object_init(dev, obj, size);
ret = drm_gem_object_init_with_mnt(dev, obj, size, gemfs);
}
if (ret) {
drm_gem_private_object_fini(obj);
Expand Down Expand Up @@ -123,10 +124,31 @@ __drm_gem_shmem_create(struct drm_device *dev, size_t size, bool private)
*/
struct drm_gem_shmem_object *drm_gem_shmem_create(struct drm_device *dev, size_t size)
{
return __drm_gem_shmem_create(dev, size, false);
return __drm_gem_shmem_create(dev, size, false, NULL);
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_create);

/**
* drm_gem_shmem_create_with_mnt - Allocate an object with the given size in a
* given mountpoint
* @dev: DRM device
* @size: Size of the object to allocate
* @gemfs: tmpfs mount where the GEM object will be created
*
* This function creates a shmem GEM object in a given tmpfs mountpoint.
*
* Returns:
* A struct drm_gem_shmem_object * on success or an ERR_PTR()-encoded negative
* error code on failure.
*/
struct drm_gem_shmem_object *drm_gem_shmem_create_with_mnt(struct drm_device *dev,
size_t size,
struct vfsmount *gemfs)
{
return __drm_gem_shmem_create(dev, size, false, gemfs);
}
EXPORT_SYMBOL_GPL(drm_gem_shmem_create_with_mnt);

/**
* drm_gem_shmem_free - Free resources associated with a shmem GEM object
* @shmem: shmem GEM object to free
Expand Down Expand Up @@ -765,7 +787,7 @@ drm_gem_shmem_prime_import_sg_table(struct drm_device *dev,
size_t size = PAGE_ALIGN(attach->dmabuf->size);
struct drm_gem_shmem_object *shmem;

shmem = __drm_gem_shmem_create(dev, size, true);
shmem = __drm_gem_shmem_create(dev, size, true, NULL);
if (IS_ERR(shmem))
return ERR_CAST(shmem);

Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/v3d/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ v3d-y := \
v3d_trace_points.o \
v3d_sched.o \
v3d_sysfs.o \
v3d_submit.o
v3d_submit.o \
v3d_gemfs.o

v3d-$(CONFIG_DEBUG_FS) += v3d_debugfs.o

Expand Down
20 changes: 14 additions & 6 deletions drivers/gpu/drm/v3d/v3d_bo.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@
* Display engines requiring physically contiguous allocations should
* look into Mesa's "renderonly" support (as used by the Mesa pl111
* driver) for an example of how to integrate with V3D.
*
* Long term, we should support evicting pages from the MMU when under
* memory pressure (thus the v3d_bo_get_pages() refcounting), but
* that's not a high priority since our systems tend to not have swap.
*/

#include <linux/dma-buf.h>
Expand Down Expand Up @@ -107,6 +103,7 @@ v3d_bo_create_finish(struct drm_gem_object *obj)
struct v3d_dev *v3d = to_v3d_dev(obj->dev);
struct v3d_bo *bo = to_v3d_bo(obj);
struct sg_table *sgt;
u64 align;
int ret;

/* So far we pin the BO in the MMU for its lifetime, so use
Expand All @@ -116,14 +113,23 @@ v3d_bo_create_finish(struct drm_gem_object *obj)
if (IS_ERR(sgt))
return PTR_ERR(sgt);

if (!v3d->gemfs)
align = SZ_4K;
else if (obj->size >= SZ_1M)
align = SZ_1M;
else if (obj->size >= SZ_64K)
align = SZ_64K;
else
align = SZ_4K;

spin_lock(&v3d->mm_lock);
/* Allocate the object's space in the GPU's page tables.
* Inserting PTEs will happen later, but the offset is for the
* lifetime of the BO.
*/
ret = drm_mm_insert_node_generic(&v3d->mm, &bo->node,
obj->size >> V3D_MMU_PAGE_SHIFT,
GMP_GRANULARITY >> V3D_MMU_PAGE_SHIFT, 0, 0);
align >> V3D_MMU_PAGE_SHIFT, 0, 0);
spin_unlock(&v3d->mm_lock);
if (ret)
return ret;
Expand All @@ -143,10 +149,12 @@ struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
size_t unaligned_size)
{
struct drm_gem_shmem_object *shmem_obj;
struct v3d_dev *v3d = to_v3d_dev(dev);
struct v3d_bo *bo;
int ret;

shmem_obj = drm_gem_shmem_create(dev, unaligned_size);
shmem_obj = drm_gem_shmem_create_with_mnt(dev, unaligned_size,
v3d->gemfs);
if (IS_ERR(shmem_obj))
return ERR_CAST(shmem_obj);
bo = to_v3d_bo(&shmem_obj->base);
Expand Down
4 changes: 2 additions & 2 deletions drivers/gpu/drm/v3d/v3d_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ static int v3d_measure_clock(struct seq_file *m, void *unused)
if (v3d->ver >= 40) {
int cycle_count_reg = V3D_PCTR_CYCLE_COUNT(v3d->ver);
V3D_CORE_WRITE(core, V3D_V4_PCTR_0_SRC_0_3,
V3D_SET_FIELD(cycle_count_reg,
V3D_PCTR_S0));
V3D_SET_FIELD_VER(cycle_count_reg,
V3D_PCTR_S0, v3d->ver));
V3D_CORE_WRITE(core, V3D_V4_PCTR_0_CLR, 1);
V3D_CORE_WRITE(core, V3D_V4_PCTR_0_EN, 1);
} else {
Expand Down
11 changes: 11 additions & 0 deletions drivers/gpu/drm/v3d/v3d_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@
#define DRIVER_MINOR 0
#define DRIVER_PATCHLEVEL 0

/* Only expose the `super_pages` modparam if THP is enabled. */
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
bool super_pages = true;
module_param_named(super_pages, super_pages, bool, 0400);
MODULE_PARM_DESC(super_pages, "Enable/Disable Super Pages support.");
#endif

static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
Expand Down Expand Up @@ -101,6 +108,9 @@ static int v3d_get_param_ioctl(struct drm_device *dev, void *data,
case DRM_V3D_PARAM_MAX_PERF_COUNTERS:
args->value = v3d->perfmon_info.max_counters;
return 0;
case DRM_V3D_PARAM_SUPPORTS_SUPER_PAGES:
args->value = !!v3d->gemfs;
return 0;
default:
DRM_DEBUG("Unknown parameter %d\n", args->param);
return -EINVAL;
Expand Down Expand Up @@ -218,6 +228,7 @@ static const struct drm_ioctl_desc v3d_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_VALUES, v3d_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(V3D_SUBMIT_CPU, v3d_submit_cpu_ioctl, DRM_RENDER_ALLOW | DRM_AUTH),
DRM_IOCTL_DEF_DRV(V3D_PERFMON_GET_COUNTER, v3d_perfmon_get_counter_ioctl, DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(V3D_PERFMON_SET_GLOBAL, v3d_perfmon_set_global_ioctl, DRM_RENDER_ALLOW),
};

static const struct drm_driver v3d_drm_driver = {
Expand Down
22 changes: 19 additions & 3 deletions drivers/gpu/drm/v3d/v3d_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,8 @@ struct clk;
struct platform_device;
struct reset_control;

#define GMP_GRANULARITY (128 * 1024)

#define V3D_MMU_PAGE_SHIFT 12
#define V3D_PAGE_FACTOR (PAGE_SIZE >> V3D_MMU_PAGE_SHIFT)

#define V3D_MAX_QUEUES (V3D_CPU + 1)

Expand Down Expand Up @@ -143,13 +142,17 @@ struct v3d_dev {
struct drm_mm mm;
spinlock_t mm_lock;

/*
* tmpfs instance used for shmem backed objects
*/
struct vfsmount *gemfs;

struct work_struct overflow_mem_work;

struct v3d_bin_job *bin_job;
struct v3d_render_job *render_job;
struct v3d_tfu_job *tfu_job;
struct v3d_csd_job *csd_job;
struct v3d_cpu_job *cpu_job;

struct v3d_queue_state queue[V3D_MAX_QUEUES];

Expand Down Expand Up @@ -185,6 +188,12 @@ struct v3d_dev {
u32 num_allocated;
u32 pages_allocated;
} bo_stats;

/* To support a performance analysis tool in user space, we require
* a single, globally configured performance monitor (perfmon) for
* all jobs.
*/
struct v3d_perfmon *global_perfmon;
};

static inline struct v3d_dev *
Expand Down Expand Up @@ -540,6 +549,11 @@ void v3d_reset(struct v3d_dev *v3d);
void v3d_invalidate_caches(struct v3d_dev *v3d);
void v3d_clean_caches(struct v3d_dev *v3d);

/* v3d_gemfs.c */
extern bool super_pages;
void v3d_gemfs_init(struct v3d_dev *v3d);
void v3d_gemfs_fini(struct v3d_dev *v3d);

/* v3d_submit.c */
void v3d_job_cleanup(struct v3d_job *job);
void v3d_job_put(struct v3d_job *job);
Expand Down Expand Up @@ -591,6 +605,8 @@ int v3d_perfmon_get_values_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int v3d_perfmon_get_counter_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int v3d_perfmon_set_global_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);

/* v3d_sysfs.c */
int v3d_sysfs_init(struct device *dev);
Expand Down
6 changes: 5 additions & 1 deletion drivers/gpu/drm/v3d/v3d_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,11 +291,14 @@ v3d_gem_init(struct drm_device *dev)
v3d_init_hw_state(v3d);
v3d_mmu_set_page_table(v3d);

v3d_gemfs_init(v3d);

ret = v3d_sched_init(v3d);
if (ret) {
drm_mm_takedown(&v3d->mm);
dma_free_coherent(v3d->drm.dev, 4096 * 1024, (void *)v3d->pt,
dma_free_coherent(v3d->drm.dev, pt_size, (void *)v3d->pt,
v3d->pt_paddr);
return ret;
}

return 0;
Expand All @@ -307,6 +310,7 @@ v3d_gem_destroy(struct drm_device *dev)
struct v3d_dev *v3d = to_v3d_dev(dev);

v3d_sched_fini(v3d);
v3d_gemfs_fini(v3d);

/* Waiting for jobs to finish would need to be done before
* unregistering V3D.
Expand Down
50 changes: 50 additions & 0 deletions drivers/gpu/drm/v3d/v3d_gemfs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: GPL-2.0+
/* Copyright (C) 2024 Raspberry Pi */

#include <linux/fs.h>
#include <linux/mount.h>

#include "v3d_drv.h"

void v3d_gemfs_init(struct v3d_dev *v3d)
{
char huge_opt[] = "huge=within_size";
struct file_system_type *type;
struct vfsmount *gemfs;

/*
* By creating our own shmemfs mountpoint, we can pass in
* mount flags that better match our usecase. However, we
* only do so on platforms which benefit from it.
*/
if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE))
goto err;

/* The user doesn't want to enable Super Pages */
if (!super_pages)
goto err;

type = get_fs_type("tmpfs");
if (!type)
goto err;

gemfs = vfs_kern_mount(type, SB_KERNMOUNT, type->name, huge_opt);
if (IS_ERR(gemfs))
goto err;

v3d->gemfs = gemfs;
drm_info(&v3d->drm, "Using Transparent Hugepages\n");

return;

err:
v3d->gemfs = NULL;
drm_notice(&v3d->drm,
"Transparent Hugepage support is recommended for optimal performance on this platform!\n");
}

void v3d_gemfs_fini(struct v3d_dev *v3d)
{
if (v3d->gemfs)
kern_unmount(v3d->gemfs);
}
Loading
Loading