brintos

brintos / linux-shallow public Read only

0
0
Text · 3.0 KiB · 3d9f51b Raw
128 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (C) 2019 Arm Ltd.3 *4 * Based on msm_gem_freedreno.c:5 * Copyright (C) 2016 Red Hat6 * Author: Rob Clark <robdclark@gmail.com>7 */8 9#include <linux/list.h>10 11#include <drm/drm_device.h>12#include <drm/drm_gem_shmem_helper.h>13 14#include "panfrost_device.h"15#include "panfrost_gem.h"16#include "panfrost_mmu.h"17 18static unsigned long19panfrost_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)20{21	struct panfrost_device *pfdev = shrinker->private_data;22	struct drm_gem_shmem_object *shmem;23	unsigned long count = 0;24 25	if (!mutex_trylock(&pfdev->shrinker_lock))26		return 0;27 28	list_for_each_entry(shmem, &pfdev->shrinker_list, madv_list) {29		if (drm_gem_shmem_is_purgeable(shmem))30			count += shmem->base.size >> PAGE_SHIFT;31	}32 33	mutex_unlock(&pfdev->shrinker_lock);34 35	return count;36}37 38static bool panfrost_gem_purge(struct drm_gem_object *obj)39{40	struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);41	struct panfrost_gem_object *bo = to_panfrost_bo(obj);42	bool ret = false;43 44	if (atomic_read(&bo->gpu_usecount))45		return false;46 47	if (!mutex_trylock(&bo->mappings.lock))48		return false;49 50	if (!dma_resv_trylock(shmem->base.resv))51		goto unlock_mappings;52 53	panfrost_gem_teardown_mappings_locked(bo);54	drm_gem_shmem_purge(&bo->base);55	ret = true;56 57	dma_resv_unlock(shmem->base.resv);58 59unlock_mappings:60	mutex_unlock(&bo->mappings.lock);61	return ret;62}63 64static unsigned long65panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)66{67	struct panfrost_device *pfdev = shrinker->private_data;68	struct drm_gem_shmem_object *shmem, *tmp;69	unsigned long freed = 0;70 71	if (!mutex_trylock(&pfdev->shrinker_lock))72		return SHRINK_STOP;73 74	list_for_each_entry_safe(shmem, tmp, &pfdev->shrinker_list, madv_list) {75		if (freed >= sc->nr_to_scan)76			break;77		if (drm_gem_shmem_is_purgeable(shmem) &&78		    panfrost_gem_purge(&shmem->base)) {79			freed += shmem->base.size >> PAGE_SHIFT;80			list_del_init(&shmem->madv_list);81		}82	}83 84	mutex_unlock(&pfdev->shrinker_lock);85 86	if (freed > 0)87		pr_info_ratelimited("Purging %lu bytes\n", freed << PAGE_SHIFT);88 89	return freed;90}91 92/**93 * panfrost_gem_shrinker_init - Initialize panfrost shrinker94 * @dev: DRM device95 *96 * This function registers and sets up the panfrost shrinker.97 */98int panfrost_gem_shrinker_init(struct drm_device *dev)99{100	struct panfrost_device *pfdev = dev->dev_private;101 102	pfdev->shrinker = shrinker_alloc(0, "drm-panfrost");103	if (!pfdev->shrinker)104		return -ENOMEM;105 106	pfdev->shrinker->count_objects = panfrost_gem_shrinker_count;107	pfdev->shrinker->scan_objects = panfrost_gem_shrinker_scan;108	pfdev->shrinker->private_data = pfdev;109 110	shrinker_register(pfdev->shrinker);111 112	return 0;113}114 115/**116 * panfrost_gem_shrinker_cleanup - Clean up panfrost shrinker117 * @dev: DRM device118 *119 * This function unregisters the panfrost shrinker.120 */121void panfrost_gem_shrinker_cleanup(struct drm_device *dev)122{123	struct panfrost_device *pfdev = dev->dev_private;124 125	if (pfdev->shrinker)126		shrinker_free(pfdev->shrinker);127}128