1 /* SPDX-License-Identifier: GPL-2.0 */
2 /* Copyright (C) 2019 Arm Ltd.
4 * Based on msm_gem_freedreno.c:
5 * Copyright (C) 2016 Red Hat
6 * Author: Rob Clark <robdclark@gmail.com>
9 #include <linux/list.h>
11 #include <drm/drm_device.h>
12 #include <drm/drm_gem_shmem_helper.h>
14 #include "panfrost_device.h"
15 #include "panfrost_gem.h"
16 #include "panfrost_mmu.h"
19 panfrost_gem_shrinker_count(struct shrinker
*shrinker
, struct shrink_control
*sc
)
21 struct panfrost_device
*pfdev
=
22 container_of(shrinker
, struct panfrost_device
, shrinker
);
23 struct drm_gem_shmem_object
*shmem
;
24 unsigned long count
= 0;
26 if (!mutex_trylock(&pfdev
->shrinker_lock
))
29 list_for_each_entry(shmem
, &pfdev
->shrinker_list
, madv_list
) {
30 if (drm_gem_shmem_is_purgeable(shmem
))
31 count
+= shmem
->base
.size
>> PAGE_SHIFT
;
34 mutex_unlock(&pfdev
->shrinker_lock
);
39 static bool panfrost_gem_purge(struct drm_gem_object
*obj
)
41 struct drm_gem_shmem_object
*shmem
= to_drm_gem_shmem_obj(obj
);
42 struct panfrost_gem_object
*bo
= to_panfrost_bo(obj
);
44 if (!mutex_trylock(&shmem
->pages_lock
))
47 panfrost_gem_teardown_mappings(bo
);
48 drm_gem_shmem_purge_locked(obj
);
50 mutex_unlock(&shmem
->pages_lock
);
55 panfrost_gem_shrinker_scan(struct shrinker
*shrinker
, struct shrink_control
*sc
)
57 struct panfrost_device
*pfdev
=
58 container_of(shrinker
, struct panfrost_device
, shrinker
);
59 struct drm_gem_shmem_object
*shmem
, *tmp
;
60 unsigned long freed
= 0;
62 if (!mutex_trylock(&pfdev
->shrinker_lock
))
65 list_for_each_entry_safe(shmem
, tmp
, &pfdev
->shrinker_list
, madv_list
) {
66 if (freed
>= sc
->nr_to_scan
)
68 if (drm_gem_shmem_is_purgeable(shmem
) &&
69 panfrost_gem_purge(&shmem
->base
)) {
70 freed
+= shmem
->base
.size
>> PAGE_SHIFT
;
71 list_del_init(&shmem
->madv_list
);
75 mutex_unlock(&pfdev
->shrinker_lock
);
78 pr_info_ratelimited("Purging %lu bytes\n", freed
<< PAGE_SHIFT
);
84 * panfrost_gem_shrinker_init - Initialize panfrost shrinker
87 * This function registers and sets up the panfrost shrinker.
89 void panfrost_gem_shrinker_init(struct drm_device
*dev
)
91 struct panfrost_device
*pfdev
= dev
->dev_private
;
92 pfdev
->shrinker
.count_objects
= panfrost_gem_shrinker_count
;
93 pfdev
->shrinker
.scan_objects
= panfrost_gem_shrinker_scan
;
94 pfdev
->shrinker
.seeks
= DEFAULT_SEEKS
;
95 WARN_ON(register_shrinker(&pfdev
->shrinker
));
99 * panfrost_gem_shrinker_cleanup - Clean up panfrost shrinker
102 * This function unregisters the panfrost shrinker.
104 void panfrost_gem_shrinker_cleanup(struct drm_device
*dev
)
106 struct panfrost_device
*pfdev
= dev
->dev_private
;
108 if (pfdev
->shrinker
.nr_deferred
) {
109 unregister_shrinker(&pfdev
->shrinker
);