Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 013b6510 authored by Rob Herring's avatar Rob Herring
Browse files

drm/panfrost: Add madvise and shrinker support



Add support for madvise and a shrinker similar to other drivers. This
allows userspace to mark BOs which can be freed when there is memory
pressure.

Unlike other implementations, we don't depend on struct_mutex. The
driver maintains a list of BOs which can be freed when the shrinker
is called. Access to the list is serialized with the shrinker_lock.

Cc: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Cc: David Airlie <airlied@linux.ie>
Cc: Daniel Vetter <daniel@ffwll.ch>
Acked-by: default avatarAlyssa Rosenzweig <alyssa.rosenzweig@collabora.com>
Signed-off-by: default avatarRob Herring <robh@kernel.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20190805143358.21245-2-robh@kernel.org
parent 17acb9f3
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ panfrost-y := \
	panfrost_device.o \
	panfrost_devfreq.o \
	panfrost_gem.o \
	panfrost_gem_shrinker.o \
	panfrost_gpu.o \
	panfrost_job.o \
	panfrost_mmu.o \
+0 −2
Original line number Diff line number Diff line
@@ -14,7 +14,5 @@

- Support userspace controlled GPU virtual addresses. Needed for Vulkan. (Tomeu)

- Support for madvise and a shrinker.

- Compute job support. So called 'compute only' jobs need to be plumbed up to
  userspace.
+4 −0
Original line number Diff line number Diff line
@@ -85,6 +85,10 @@ struct panfrost_device {
	struct mutex sched_lock;
	struct mutex reset_lock;

	struct mutex shrinker_lock;
	struct list_head shrinker_list;
	struct shrinker shrinker;

	struct {
		struct devfreq *devfreq;
		struct thermal_cooling_device *cooling;
+38 −0
Original line number Diff line number Diff line
@@ -333,6 +333,38 @@ static int panfrost_ioctl_get_bo_offset(struct drm_device *dev, void *data,
	return 0;
}

static int panfrost_ioctl_madvise(struct drm_device *dev, void *data,
				  struct drm_file *file_priv)
{
	struct drm_panfrost_madvise *args = data;
	struct panfrost_device *pfdev = dev->dev_private;
	struct drm_gem_object *gem_obj;

	gem_obj = drm_gem_object_lookup(file_priv, args->handle);
	if (!gem_obj) {
		DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
		return -ENOENT;
	}

	args->retained = drm_gem_shmem_madvise(gem_obj, args->madv);

	if (args->retained) {
		struct panfrost_gem_object *bo = to_panfrost_bo(gem_obj);

		mutex_lock(&pfdev->shrinker_lock);

		if (args->madv == PANFROST_MADV_DONTNEED)
			list_add_tail(&bo->base.madv_list, &pfdev->shrinker_list);
		else if (args->madv == PANFROST_MADV_WILLNEED)
			list_del_init(&bo->base.madv_list);

		mutex_unlock(&pfdev->shrinker_lock);
	}

	drm_gem_object_put_unlocked(gem_obj);
	return 0;
}

int panfrost_unstable_ioctl_check(void)
{
	if (!unstable_ioctls)
@@ -384,6 +416,7 @@ static const struct drm_ioctl_desc panfrost_drm_driver_ioctls[] = {
	PANFROST_IOCTL(GET_BO_OFFSET,	get_bo_offset,	DRM_RENDER_ALLOW),
	PANFROST_IOCTL(PERFCNT_ENABLE,	perfcnt_enable,	DRM_RENDER_ALLOW),
	PANFROST_IOCTL(PERFCNT_DUMP,	perfcnt_dump,	DRM_RENDER_ALLOW),
	PANFROST_IOCTL(MADVISE,		madvise,	DRM_RENDER_ALLOW),
};

DEFINE_DRM_GEM_SHMEM_FOPS(panfrost_drm_driver_fops);
@@ -432,6 +465,8 @@ static int panfrost_probe(struct platform_device *pdev)
	pfdev->ddev = ddev;

	spin_lock_init(&pfdev->mm_lock);
	mutex_init(&pfdev->shrinker_lock);
	INIT_LIST_HEAD(&pfdev->shrinker_list);

	/* 4G enough for now. can be 48-bit */
	drm_mm_init(&pfdev->mm, SZ_32M >> PAGE_SHIFT, (SZ_4G - SZ_32M) >> PAGE_SHIFT);
@@ -462,6 +497,8 @@ static int panfrost_probe(struct platform_device *pdev)
	if (err < 0)
		goto err_out1;

	panfrost_gem_shrinker_init(ddev);

	return 0;

err_out1:
@@ -478,6 +515,7 @@ static int panfrost_remove(struct platform_device *pdev)
	struct drm_device *ddev = pfdev->ddev;

	drm_dev_unregister(ddev);
	panfrost_gem_shrinker_cleanup(ddev);
	pm_runtime_get_sync(pfdev->dev);
	pm_runtime_put_sync_autosuspend(pfdev->dev);
	pm_runtime_disable(pfdev->dev);
+5 −0
Original line number Diff line number Diff line
@@ -26,6 +26,11 @@ static void panfrost_gem_free_object(struct drm_gem_object *obj)
	drm_mm_remove_node(&bo->node);
	spin_unlock(&pfdev->mm_lock);

	mutex_lock(&pfdev->shrinker_lock);
	if (!list_empty(&bo->base.madv_list))
		list_del(&bo->base.madv_list);
	mutex_unlock(&pfdev->shrinker_lock);

	drm_gem_shmem_free_object(obj);
}

Loading