]> Git Repo - linux.git/blob - drivers/gpu/drm/panfrost/panfrost_gem_shrinker.c
Merge tag 'cxl-for-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
[linux.git] / drivers / gpu / drm / panfrost / panfrost_gem_shrinker.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2019 Arm Ltd.
3  *
4  * Based on msm_gem_freedreno.c:
5  * Copyright (C) 2016 Red Hat
6  * Author: Rob Clark <[email protected]>
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
18 static unsigned long
19 panfrost_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
38 static 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
59 unlock_mappings:
60         mutex_unlock(&bo->mappings.lock);
61         return ret;
62 }
63
64 static unsigned long
65 panfrost_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 shrinker
94  * @dev: DRM device
95  *
96  * This function registers and sets up the panfrost shrinker.
97  */
98 int 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 shrinker
117  * @dev: DRM device
118  *
119  * This function unregisters the panfrost shrinker.
120  */
121 void 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 }
This page took 0.045343 seconds and 4 git commands to generate.