xref: /linux/drivers/gpu/drm/xe/xe_shrinker.c (revision a032fe30cf09b6723ab61a05aee057311b00f9e1)
1 // SPDX-License-Identifier: MIT
2 /*
3  * Copyright © 2024 Intel Corporation
4  */
5 
6 #include <linux/shrinker.h>
7 
8 #include <drm/drm_managed.h>
9 #include <drm/ttm/ttm_backup.h>
10 #include <drm/ttm/ttm_bo.h>
11 #include <drm/ttm/ttm_tt.h>
12 
13 #include "xe_bo.h"
14 #include "xe_pm.h"
15 #include "xe_shrinker.h"
16 
17 /**
18  * struct xe_shrinker - per-device shrinker
19  * @xe: Back pointer to the device.
20  * @lock: Lock protecting accounting.
21  * @shrinkable_pages: Number of pages that are currently shrinkable.
22  * @purgeable_pages: Number of pages that are currently purgeable.
23  * @shrink: Pointer to the mm shrinker.
24  * @pm_worker: Worker to wake up the device if required.
25  */
26 struct xe_shrinker {
27 	struct xe_device *xe;
28 	rwlock_t lock;
29 	long shrinkable_pages;
30 	long purgeable_pages;
31 	struct shrinker *shrink;
32 	struct work_struct pm_worker;
33 };
34 
35 static struct xe_shrinker *to_xe_shrinker(struct shrinker *shrink)
36 {
37 	return shrink->private_data;
38 }
39 
40 /**
41  * xe_shrinker_mod_pages() - Modify shrinker page accounting
42  * @shrinker: Pointer to the struct xe_shrinker.
43  * @shrinkable: Shrinkable pages delta. May be negative.
44  * @purgeable: Purgeable page delta. May be negative.
45  *
46  * Modifies the shrinkable and purgeable pages accounting.
47  */
48 void
49 xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long purgeable)
50 {
51 	write_lock(&shrinker->lock);
52 	shrinker->shrinkable_pages += shrinkable;
53 	shrinker->purgeable_pages += purgeable;
54 	write_unlock(&shrinker->lock);
55 }
56 
57 static s64 xe_shrinker_walk(struct xe_device *xe,
58 			    struct ttm_operation_ctx *ctx,
59 			    const struct xe_bo_shrink_flags flags,
60 			    unsigned long to_scan, unsigned long *scanned)
61 {
62 	unsigned int mem_type;
63 	s64 freed = 0, lret;
64 
65 	for (mem_type = XE_PL_SYSTEM; mem_type <= XE_PL_TT; ++mem_type) {
66 		struct ttm_resource_manager *man = ttm_manager_type(&xe->ttm, mem_type);
67 		struct ttm_bo_lru_cursor curs;
68 		struct ttm_buffer_object *ttm_bo;
69 		struct ttm_lru_walk_arg arg = {
70 			.ctx = ctx,
71 			.trylock_only = true,
72 		};
73 
74 		if (!man || !man->use_tt)
75 			continue;
76 
77 		ttm_bo_lru_for_each_reserved_guarded(&curs, man, &arg, ttm_bo) {
78 			if (!ttm_bo_shrink_suitable(ttm_bo, ctx))
79 				continue;
80 
81 			lret = xe_bo_shrink(ctx, ttm_bo, flags, scanned);
82 			if (lret < 0)
83 				return lret;
84 
85 			freed += lret;
86 			if (*scanned >= to_scan)
87 				break;
88 		}
89 		/* Trylocks should never error, just fail. */
90 		xe_assert(xe, !IS_ERR(ttm_bo));
91 	}
92 
93 	return freed;
94 }
95 
96 static unsigned long
97 xe_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
98 {
99 	struct xe_shrinker *shrinker = to_xe_shrinker(shrink);
100 	unsigned long num_pages;
101 	bool can_backup = !!(sc->gfp_mask & __GFP_FS);
102 
103 	num_pages = ttm_backup_bytes_avail() >> PAGE_SHIFT;
104 	read_lock(&shrinker->lock);
105 
106 	if (can_backup)
107 		num_pages = min_t(unsigned long, num_pages, shrinker->shrinkable_pages);
108 	else
109 		num_pages = 0;
110 
111 	num_pages += shrinker->purgeable_pages;
112 	read_unlock(&shrinker->lock);
113 
114 	return num_pages ? num_pages : SHRINK_EMPTY;
115 }
116 
117 /*
118  * Check if we need runtime pm, and if so try to grab a reference if
119  * already active. If grabbing a reference fails, queue a worker that
120  * does it for us outside of reclaim, but don't wait for it to complete.
121  * If bo shrinking needs an rpm reference and we don't have it (yet),
122  * that bo will be skipped anyway.
123  */
124 static bool xe_shrinker_runtime_pm_get(struct xe_shrinker *shrinker, bool force,
125 				       unsigned long nr_to_scan, bool can_backup)
126 {
127 	struct xe_device *xe = shrinker->xe;
128 
129 	if (IS_DGFX(xe) || !xe_device_has_flat_ccs(xe) ||
130 	    !ttm_backup_bytes_avail())
131 		return false;
132 
133 	if (!force) {
134 		read_lock(&shrinker->lock);
135 		force = (nr_to_scan > shrinker->purgeable_pages && can_backup);
136 		read_unlock(&shrinker->lock);
137 		if (!force)
138 			return false;
139 	}
140 
141 	if (!xe_pm_runtime_get_if_active(xe)) {
142 		if (xe_rpm_reclaim_safe(xe) && !ttm_bo_shrink_avoid_wait()) {
143 			xe_pm_runtime_get(xe);
144 			return true;
145 		}
146 		queue_work(xe->unordered_wq, &shrinker->pm_worker);
147 		return false;
148 	}
149 
150 	return true;
151 }
152 
153 static void xe_shrinker_runtime_pm_put(struct xe_shrinker *shrinker, bool runtime_pm)
154 {
155 	if (runtime_pm)
156 		xe_pm_runtime_put(shrinker->xe);
157 }
158 
159 static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc)
160 {
161 	struct xe_shrinker *shrinker = to_xe_shrinker(shrink);
162 	struct ttm_operation_ctx ctx = {
163 		.interruptible = false,
164 		.no_wait_gpu = ttm_bo_shrink_avoid_wait(),
165 	};
166 	unsigned long nr_to_scan, nr_scanned = 0, freed = 0;
167 	struct xe_bo_shrink_flags shrink_flags = {
168 		.purge = true,
169 		/* Don't request writeback without __GFP_IO. */
170 		.writeback = !ctx.no_wait_gpu && (sc->gfp_mask & __GFP_IO),
171 	};
172 	bool runtime_pm;
173 	bool purgeable;
174 	bool can_backup = !!(sc->gfp_mask & __GFP_FS);
175 	s64 lret;
176 
177 	nr_to_scan = sc->nr_to_scan;
178 
179 	read_lock(&shrinker->lock);
180 	purgeable = !!shrinker->purgeable_pages;
181 	read_unlock(&shrinker->lock);
182 
183 	/* Might need runtime PM. Try to wake early if it looks like it. */
184 	runtime_pm = xe_shrinker_runtime_pm_get(shrinker, false, nr_to_scan, can_backup);
185 
186 	if (purgeable && nr_scanned < nr_to_scan) {
187 		lret = xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags,
188 					nr_to_scan, &nr_scanned);
189 		if (lret >= 0)
190 			freed += lret;
191 	}
192 
193 	sc->nr_scanned = nr_scanned;
194 	if (nr_scanned >= nr_to_scan || !can_backup)
195 		goto out;
196 
197 	/* If we didn't wake before, try to do it now if needed. */
198 	if (!runtime_pm)
199 		runtime_pm = xe_shrinker_runtime_pm_get(shrinker, true, 0, can_backup);
200 
201 	shrink_flags.purge = false;
202 	lret = xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags,
203 				nr_to_scan, &nr_scanned);
204 	if (lret >= 0)
205 		freed += lret;
206 
207 	sc->nr_scanned = nr_scanned;
208 out:
209 	xe_shrinker_runtime_pm_put(shrinker, runtime_pm);
210 	return nr_scanned ? freed : SHRINK_STOP;
211 }
212 
213 /* Wake up the device for shrinking. */
214 static void xe_shrinker_pm(struct work_struct *work)
215 {
216 	struct xe_shrinker *shrinker =
217 		container_of(work, typeof(*shrinker), pm_worker);
218 
219 	xe_pm_runtime_get(shrinker->xe);
220 	xe_pm_runtime_put(shrinker->xe);
221 }
222 
223 static void xe_shrinker_fini(struct drm_device *drm, void *arg)
224 {
225 	struct xe_shrinker *shrinker = arg;
226 
227 	xe_assert(shrinker->xe, !shrinker->shrinkable_pages);
228 	xe_assert(shrinker->xe, !shrinker->purgeable_pages);
229 	shrinker_free(shrinker->shrink);
230 	flush_work(&shrinker->pm_worker);
231 	kfree(shrinker);
232 }
233 
234 /**
235  * xe_shrinker_create() - Create an xe per-device shrinker
236  * @xe: Pointer to the xe device.
237  *
238  * Return: %0 on success. Negative error code on failure.
239  */
240 int xe_shrinker_create(struct xe_device *xe)
241 {
242 	struct xe_shrinker *shrinker = kzalloc(sizeof(*shrinker), GFP_KERNEL);
243 
244 	if (!shrinker)
245 		return -ENOMEM;
246 
247 	shrinker->shrink = shrinker_alloc(0, "drm-xe_gem:%s", xe->drm.unique);
248 	if (!shrinker->shrink) {
249 		kfree(shrinker);
250 		return -ENOMEM;
251 	}
252 
253 	INIT_WORK(&shrinker->pm_worker, xe_shrinker_pm);
254 	shrinker->xe = xe;
255 	rwlock_init(&shrinker->lock);
256 	shrinker->shrink->count_objects = xe_shrinker_count;
257 	shrinker->shrink->scan_objects = xe_shrinker_scan;
258 	shrinker->shrink->private_data = shrinker;
259 	shrinker_register(shrinker->shrink);
260 	xe->mem.shrinker = shrinker;
261 
262 	return drmm_add_action_or_reset(&xe->drm, xe_shrinker_fini, shrinker);
263 }
264