Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /* Copyright (C) 2019 Arm Ltd.
0003  *
0004  * Based on msm_gem_freedreno.c:
0005  * Copyright (C) 2016 Red Hat
0006  * Author: Rob Clark <robdclark@gmail.com>
0007  */
0008 
0009 #include <linux/list.h>
0010 
0011 #include <drm/drm_device.h>
0012 #include <drm/drm_gem_shmem_helper.h>
0013 
0014 #include "panfrost_device.h"
0015 #include "panfrost_gem.h"
0016 #include "panfrost_mmu.h"
0017 
0018 static unsigned long
0019 panfrost_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
0020 {
0021     struct panfrost_device *pfdev =
0022         container_of(shrinker, struct panfrost_device, shrinker);
0023     struct drm_gem_shmem_object *shmem;
0024     unsigned long count = 0;
0025 
0026     if (!mutex_trylock(&pfdev->shrinker_lock))
0027         return 0;
0028 
0029     list_for_each_entry(shmem, &pfdev->shrinker_list, madv_list) {
0030         if (drm_gem_shmem_is_purgeable(shmem))
0031             count += shmem->base.size >> PAGE_SHIFT;
0032     }
0033 
0034     mutex_unlock(&pfdev->shrinker_lock);
0035 
0036     return count;
0037 }
0038 
0039 static bool panfrost_gem_purge(struct drm_gem_object *obj)
0040 {
0041     struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
0042     struct panfrost_gem_object *bo = to_panfrost_bo(obj);
0043     bool ret = false;
0044 
0045     if (atomic_read(&bo->gpu_usecount))
0046         return false;
0047 
0048     if (!mutex_trylock(&bo->mappings.lock))
0049         return false;
0050 
0051     if (!mutex_trylock(&shmem->pages_lock))
0052         goto unlock_mappings;
0053 
0054     panfrost_gem_teardown_mappings_locked(bo);
0055     drm_gem_shmem_purge_locked(&bo->base);
0056     ret = true;
0057 
0058     mutex_unlock(&shmem->pages_lock);
0059 
0060 unlock_mappings:
0061     mutex_unlock(&bo->mappings.lock);
0062     return ret;
0063 }
0064 
0065 static unsigned long
0066 panfrost_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc)
0067 {
0068     struct panfrost_device *pfdev =
0069         container_of(shrinker, struct panfrost_device, shrinker);
0070     struct drm_gem_shmem_object *shmem, *tmp;
0071     unsigned long freed = 0;
0072 
0073     if (!mutex_trylock(&pfdev->shrinker_lock))
0074         return SHRINK_STOP;
0075 
0076     list_for_each_entry_safe(shmem, tmp, &pfdev->shrinker_list, madv_list) {
0077         if (freed >= sc->nr_to_scan)
0078             break;
0079         if (drm_gem_shmem_is_purgeable(shmem) &&
0080             panfrost_gem_purge(&shmem->base)) {
0081             freed += shmem->base.size >> PAGE_SHIFT;
0082             list_del_init(&shmem->madv_list);
0083         }
0084     }
0085 
0086     mutex_unlock(&pfdev->shrinker_lock);
0087 
0088     if (freed > 0)
0089         pr_info_ratelimited("Purging %lu bytes\n", freed << PAGE_SHIFT);
0090 
0091     return freed;
0092 }
0093 
0094 /**
0095  * panfrost_gem_shrinker_init - Initialize panfrost shrinker
0096  * @dev: DRM device
0097  *
0098  * This function registers and sets up the panfrost shrinker.
0099  */
0100 void panfrost_gem_shrinker_init(struct drm_device *dev)
0101 {
0102     struct panfrost_device *pfdev = dev->dev_private;
0103     pfdev->shrinker.count_objects = panfrost_gem_shrinker_count;
0104     pfdev->shrinker.scan_objects = panfrost_gem_shrinker_scan;
0105     pfdev->shrinker.seeks = DEFAULT_SEEKS;
0106     WARN_ON(register_shrinker(&pfdev->shrinker, "drm-panfrost"));
0107 }
0108 
0109 /**
0110  * panfrost_gem_shrinker_cleanup - Clean up panfrost shrinker
0111  * @dev: DRM device
0112  *
0113  * This function unregisters the panfrost shrinker.
0114  */
0115 void panfrost_gem_shrinker_cleanup(struct drm_device *dev)
0116 {
0117     struct panfrost_device *pfdev = dev->dev_private;
0118 
0119     if (pfdev->shrinker.nr_deferred) {
0120         unregister_shrinker(&pfdev->shrinker);
0121     }
0122 }