xref: /linux/drivers/gpu/drm/amd/amdgpu/amdgpu_eviction_fence.c (revision e332935a540eb76dd656663ca908eb0544d96757)
1fb796c30SShashank Sharma // SPDX-License-Identifier: MIT
2fb796c30SShashank Sharma /*
3fb796c30SShashank Sharma  * Copyright 2024 Advanced Micro Devices, Inc.
4fb796c30SShashank Sharma  *
5fb796c30SShashank Sharma  * Permission is hereby granted, free of charge, to any person obtaining a
6fb796c30SShashank Sharma  * copy of this software and associated documentation files (the "Software"),
7fb796c30SShashank Sharma  * to deal in the Software without restriction, including without limitation
8fb796c30SShashank Sharma  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9fb796c30SShashank Sharma  * and/or sell copies of the Software, and to permit persons to whom the
10fb796c30SShashank Sharma  * Software is furnished to do so, subject to the following conditions:
11fb796c30SShashank Sharma  *
12fb796c30SShashank Sharma  * The above copyright notice and this permission notice shall be included in
13fb796c30SShashank Sharma  * all copies or substantial portions of the Software.
14fb796c30SShashank Sharma  *
15fb796c30SShashank Sharma  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16fb796c30SShashank Sharma  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17fb796c30SShashank Sharma  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18fb796c30SShashank Sharma  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
19fb796c30SShashank Sharma  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20fb796c30SShashank Sharma  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21fb796c30SShashank Sharma  * OTHER DEALINGS IN THE SOFTWARE.
22fb796c30SShashank Sharma  *
23fb796c30SShashank Sharma  */
24fb796c30SShashank Sharma #include <linux/sched.h>
25b0328087SShashank Sharma #include <drm/drm_exec.h>
26fb796c30SShashank Sharma #include "amdgpu.h"
27fb796c30SShashank Sharma 
28b0328087SShashank Sharma #define work_to_evf_mgr(w, name) container_of(w, struct amdgpu_eviction_fence_mgr, name)
29b0328087SShashank Sharma #define evf_mgr_to_fpriv(e) container_of(e, struct amdgpu_fpriv, evf_mgr)
30b0328087SShashank Sharma 
31fb796c30SShashank Sharma static const char *
amdgpu_eviction_fence_get_driver_name(struct dma_fence * fence)32fb796c30SShashank Sharma amdgpu_eviction_fence_get_driver_name(struct dma_fence *fence)
33fb796c30SShashank Sharma {
34e125a6e8SPrike Liang 	return "amdgpu_eviction_fence";
35fb796c30SShashank Sharma }
36fb796c30SShashank Sharma 
37fb796c30SShashank Sharma static const char *
amdgpu_eviction_fence_get_timeline_name(struct dma_fence * f)38fb796c30SShashank Sharma amdgpu_eviction_fence_get_timeline_name(struct dma_fence *f)
39fb796c30SShashank Sharma {
40fb796c30SShashank Sharma 	struct amdgpu_eviction_fence *ef;
41fb796c30SShashank Sharma 
42fb796c30SShashank Sharma 	ef = container_of(f, struct amdgpu_eviction_fence, base);
43fb796c30SShashank Sharma 	return ef->timeline_name;
44fb796c30SShashank Sharma }
45fb796c30SShashank Sharma 
46b0328087SShashank Sharma int
amdgpu_eviction_fence_replace_fence(struct amdgpu_eviction_fence_mgr * evf_mgr,struct drm_exec * exec)47b0328087SShashank Sharma amdgpu_eviction_fence_replace_fence(struct amdgpu_eviction_fence_mgr *evf_mgr,
48b0328087SShashank Sharma 				    struct drm_exec *exec)
49b0328087SShashank Sharma {
50b0328087SShashank Sharma 	struct amdgpu_eviction_fence *old_ef, *new_ef;
51b0328087SShashank Sharma 	struct drm_gem_object *obj;
52b0328087SShashank Sharma 	unsigned long index;
53b0328087SShashank Sharma 	int ret;
54b0328087SShashank Sharma 
5532bd8b3eSArvind Yadav 	if (evf_mgr->ev_fence &&
5632bd8b3eSArvind Yadav 	    !dma_fence_is_signaled(&evf_mgr->ev_fence->base))
5732bd8b3eSArvind Yadav 		return 0;
58b0328087SShashank Sharma 	/*
59b0328087SShashank Sharma 	 * Steps to replace eviction fence:
60b0328087SShashank Sharma 	 * * lock all objects in exec (caller)
61b0328087SShashank Sharma 	 * * create a new eviction fence
62b0328087SShashank Sharma 	 * * update new eviction fence in evf_mgr
63b0328087SShashank Sharma 	 * * attach the new eviction fence to BOs
64b0328087SShashank Sharma 	 * * release the old fence
65b0328087SShashank Sharma 	 * * unlock the objects (caller)
66b0328087SShashank Sharma 	 */
67b0328087SShashank Sharma 	new_ef = amdgpu_eviction_fence_create(evf_mgr);
68b0328087SShashank Sharma 	if (!new_ef) {
69b0328087SShashank Sharma 		DRM_ERROR("Failed to create new eviction fence\n");
70b0328087SShashank Sharma 		return -ENOMEM;
71b0328087SShashank Sharma 	}
72b0328087SShashank Sharma 
73b0328087SShashank Sharma 	/* Update the eviction fence now */
74b0328087SShashank Sharma 	spin_lock(&evf_mgr->ev_fence_lock);
75b0328087SShashank Sharma 	old_ef = evf_mgr->ev_fence;
76b0328087SShashank Sharma 	evf_mgr->ev_fence = new_ef;
77b0328087SShashank Sharma 	spin_unlock(&evf_mgr->ev_fence_lock);
78b0328087SShashank Sharma 
79b0328087SShashank Sharma 	/* Attach the new fence */
80b0328087SShashank Sharma 	drm_exec_for_each_locked_object(exec, index, obj) {
81b0328087SShashank Sharma 		struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj);
82b0328087SShashank Sharma 
83b0328087SShashank Sharma 		if (!bo)
84b0328087SShashank Sharma 			continue;
85b0328087SShashank Sharma 		ret = amdgpu_eviction_fence_attach(evf_mgr, bo);
86b0328087SShashank Sharma 		if (ret) {
87b0328087SShashank Sharma 			DRM_ERROR("Failed to attch new eviction fence\n");
88b0328087SShashank Sharma 			goto free_err;
89b0328087SShashank Sharma 		}
90b0328087SShashank Sharma 	}
91b0328087SShashank Sharma 
92b0328087SShashank Sharma 	/* Free old fence */
93a242a3e4SShashank Sharma 	if (old_ef)
94b0328087SShashank Sharma 		dma_fence_put(&old_ef->base);
95b0328087SShashank Sharma 	return 0;
96b0328087SShashank Sharma 
97b0328087SShashank Sharma free_err:
98b0328087SShashank Sharma 	kfree(new_ef);
99b0328087SShashank Sharma 	return ret;
100b0328087SShashank Sharma }
101b0328087SShashank Sharma 
102b0328087SShashank Sharma static void
amdgpu_eviction_fence_suspend_worker(struct work_struct * work)103b0328087SShashank Sharma amdgpu_eviction_fence_suspend_worker(struct work_struct *work)
104b0328087SShashank Sharma {
105b0328087SShashank Sharma 	struct amdgpu_eviction_fence_mgr *evf_mgr = work_to_evf_mgr(work, suspend_work.work);
106b0328087SShashank Sharma 	struct amdgpu_fpriv *fpriv = evf_mgr_to_fpriv(evf_mgr);
107b0328087SShashank Sharma 	struct amdgpu_userq_mgr *uq_mgr = &fpriv->userq_mgr;
108a242a3e4SShashank Sharma 	struct amdgpu_eviction_fence *ev_fence;
109b0328087SShashank Sharma 
110a242a3e4SShashank Sharma 	mutex_lock(&uq_mgr->userq_mutex);
111*b2c11e27SPrike Liang 	spin_lock(&evf_mgr->ev_fence_lock);
112a242a3e4SShashank Sharma 	ev_fence = evf_mgr->ev_fence;
113*b2c11e27SPrike Liang 	if (ev_fence)
114*b2c11e27SPrike Liang 		dma_fence_get(&ev_fence->base);
115*b2c11e27SPrike Liang 	else
116a242a3e4SShashank Sharma 		goto unlock;
117*b2c11e27SPrike Liang 	spin_unlock(&evf_mgr->ev_fence_lock);
118b0328087SShashank Sharma 
11942a66677SAlex Deucher 	amdgpu_userq_evict(uq_mgr, ev_fence);
120b0328087SShashank Sharma 
121*b2c11e27SPrike Liang 	mutex_unlock(&uq_mgr->userq_mutex);
122*b2c11e27SPrike Liang 	dma_fence_put(&ev_fence->base);
123*b2c11e27SPrike Liang 	return;
124*b2c11e27SPrike Liang 
125a242a3e4SShashank Sharma unlock:
126*b2c11e27SPrike Liang 	spin_unlock(&evf_mgr->ev_fence_lock);
127a242a3e4SShashank Sharma 	mutex_unlock(&uq_mgr->userq_mutex);
128b0328087SShashank Sharma }
129b0328087SShashank Sharma 
amdgpu_eviction_fence_enable_signaling(struct dma_fence * f)130b0328087SShashank Sharma static bool amdgpu_eviction_fence_enable_signaling(struct dma_fence *f)
131b0328087SShashank Sharma {
132b0328087SShashank Sharma 	struct amdgpu_eviction_fence_mgr *evf_mgr;
133b0328087SShashank Sharma 	struct amdgpu_eviction_fence *ev_fence;
134b0328087SShashank Sharma 
135b0328087SShashank Sharma 	if (!f)
136b0328087SShashank Sharma 		return true;
137b0328087SShashank Sharma 
138b0328087SShashank Sharma 	ev_fence = to_ev_fence(f);
139b0328087SShashank Sharma 	evf_mgr = ev_fence->evf_mgr;
140b0328087SShashank Sharma 
141b0328087SShashank Sharma 	schedule_delayed_work(&evf_mgr->suspend_work, 0);
142b0328087SShashank Sharma 	return true;
143b0328087SShashank Sharma }
144b0328087SShashank Sharma 
145fb796c30SShashank Sharma static const struct dma_fence_ops amdgpu_eviction_fence_ops = {
146fb796c30SShashank Sharma 	.use_64bit_seqno = true,
147fb796c30SShashank Sharma 	.get_driver_name = amdgpu_eviction_fence_get_driver_name,
148fb796c30SShashank Sharma 	.get_timeline_name = amdgpu_eviction_fence_get_timeline_name,
149b0328087SShashank Sharma 	.enable_signaling = amdgpu_eviction_fence_enable_signaling,
150fb796c30SShashank Sharma };
151fb796c30SShashank Sharma 
amdgpu_eviction_fence_signal(struct amdgpu_eviction_fence_mgr * evf_mgr,struct amdgpu_eviction_fence * ev_fence)152a242a3e4SShashank Sharma void amdgpu_eviction_fence_signal(struct amdgpu_eviction_fence_mgr *evf_mgr,
153a242a3e4SShashank Sharma 				  struct amdgpu_eviction_fence *ev_fence)
154fb796c30SShashank Sharma {
155fb796c30SShashank Sharma 	spin_lock(&evf_mgr->ev_fence_lock);
156a242a3e4SShashank Sharma 	dma_fence_signal(&ev_fence->base);
157fb796c30SShashank Sharma 	spin_unlock(&evf_mgr->ev_fence_lock);
158fb796c30SShashank Sharma }
159fb796c30SShashank Sharma 
160fb796c30SShashank Sharma struct amdgpu_eviction_fence *
amdgpu_eviction_fence_create(struct amdgpu_eviction_fence_mgr * evf_mgr)161fb796c30SShashank Sharma amdgpu_eviction_fence_create(struct amdgpu_eviction_fence_mgr *evf_mgr)
162fb796c30SShashank Sharma {
163fb796c30SShashank Sharma 	struct amdgpu_eviction_fence *ev_fence;
164fb796c30SShashank Sharma 
165fb796c30SShashank Sharma 	ev_fence = kzalloc(sizeof(*ev_fence), GFP_KERNEL);
166fb796c30SShashank Sharma 	if (!ev_fence)
167fb796c30SShashank Sharma 		return NULL;
168fb796c30SShashank Sharma 
169fb796c30SShashank Sharma 	ev_fence->evf_mgr = evf_mgr;
170fb796c30SShashank Sharma 	get_task_comm(ev_fence->timeline_name, current);
171fb796c30SShashank Sharma 	spin_lock_init(&ev_fence->lock);
172fb796c30SShashank Sharma 	dma_fence_init(&ev_fence->base, &amdgpu_eviction_fence_ops,
173fb796c30SShashank Sharma 		       &ev_fence->lock, evf_mgr->ev_fence_ctx,
174fb796c30SShashank Sharma 		       atomic_inc_return(&evf_mgr->ev_fence_seq));
175fb796c30SShashank Sharma 	return ev_fence;
176fb796c30SShashank Sharma }
177fb796c30SShashank Sharma 
amdgpu_eviction_fence_destroy(struct amdgpu_eviction_fence_mgr * evf_mgr)178fb796c30SShashank Sharma void amdgpu_eviction_fence_destroy(struct amdgpu_eviction_fence_mgr *evf_mgr)
179fb796c30SShashank Sharma {
180fb796c30SShashank Sharma 	struct amdgpu_eviction_fence *ev_fence;
181fb796c30SShashank Sharma 
182b8e6d3f6SShashank Sharma 	/* Wait for any pending work to execute */
183b8e6d3f6SShashank Sharma 	flush_delayed_work(&evf_mgr->suspend_work);
184b8e6d3f6SShashank Sharma 
185fb796c30SShashank Sharma 	spin_lock(&evf_mgr->ev_fence_lock);
186fb796c30SShashank Sharma 	ev_fence = evf_mgr->ev_fence;
187fb796c30SShashank Sharma 	spin_unlock(&evf_mgr->ev_fence_lock);
188fb796c30SShashank Sharma 
189fb796c30SShashank Sharma 	if (!ev_fence)
190fb796c30SShashank Sharma 		return;
191fb796c30SShashank Sharma 
19231f7efcdSShashank Sharma 	dma_fence_wait(&ev_fence->base, false);
19331f7efcdSShashank Sharma 
194fb796c30SShashank Sharma 	/* Last unref of ev_fence */
19513d0724fSArvind Yadav 	dma_fence_put(&ev_fence->base);
196fb796c30SShashank Sharma }
197fb796c30SShashank Sharma 
amdgpu_eviction_fence_attach(struct amdgpu_eviction_fence_mgr * evf_mgr,struct amdgpu_bo * bo)198fb796c30SShashank Sharma int amdgpu_eviction_fence_attach(struct amdgpu_eviction_fence_mgr *evf_mgr,
199fb796c30SShashank Sharma 				 struct amdgpu_bo *bo)
200fb796c30SShashank Sharma {
201fb796c30SShashank Sharma 	struct amdgpu_eviction_fence *ev_fence;
202fb796c30SShashank Sharma 	struct dma_resv *resv = bo->tbo.base.resv;
203fb796c30SShashank Sharma 	int ret;
204fb796c30SShashank Sharma 
205fb796c30SShashank Sharma 	if (!resv)
206fb796c30SShashank Sharma 		return 0;
207fb796c30SShashank Sharma 
208fb796c30SShashank Sharma 	ret = dma_resv_reserve_fences(resv, 1);
209fb796c30SShashank Sharma 	if (ret) {
210fb796c30SShashank Sharma 		DRM_DEBUG_DRIVER("Failed to resv fence space\n");
211fb796c30SShashank Sharma 		return ret;
212fb796c30SShashank Sharma 	}
213fb796c30SShashank Sharma 
214fb796c30SShashank Sharma 	spin_lock(&evf_mgr->ev_fence_lock);
215fb796c30SShashank Sharma 	ev_fence = evf_mgr->ev_fence;
216af7160c2SPrike Liang 	if (ev_fence)
217af7160c2SPrike Liang 		dma_resv_add_fence(resv, &ev_fence->base, DMA_RESV_USAGE_BOOKKEEP);
218fb796c30SShashank Sharma 	spin_unlock(&evf_mgr->ev_fence_lock);
219a242a3e4SShashank Sharma 
220fb796c30SShashank Sharma 	return 0;
221fb796c30SShashank Sharma }
222fb796c30SShashank Sharma 
amdgpu_eviction_fence_detach(struct amdgpu_eviction_fence_mgr * evf_mgr,struct amdgpu_bo * bo)223fb796c30SShashank Sharma void amdgpu_eviction_fence_detach(struct amdgpu_eviction_fence_mgr *evf_mgr,
224fb796c30SShashank Sharma 				  struct amdgpu_bo *bo)
225fb796c30SShashank Sharma {
226fb796c30SShashank Sharma 	struct dma_fence *stub = dma_fence_get_stub();
227fb796c30SShashank Sharma 
228fb796c30SShashank Sharma 	dma_resv_replace_fences(bo->tbo.base.resv, evf_mgr->ev_fence_ctx,
229fb796c30SShashank Sharma 				stub, DMA_RESV_USAGE_BOOKKEEP);
230fb796c30SShashank Sharma 	dma_fence_put(stub);
231fb796c30SShashank Sharma }
232fb796c30SShashank Sharma 
amdgpu_eviction_fence_init(struct amdgpu_eviction_fence_mgr * evf_mgr)233fb796c30SShashank Sharma int amdgpu_eviction_fence_init(struct amdgpu_eviction_fence_mgr *evf_mgr)
234fb796c30SShashank Sharma {
235fb796c30SShashank Sharma 	/* This needs to be done one time per open */
236fb796c30SShashank Sharma 	atomic_set(&evf_mgr->ev_fence_seq, 0);
237fb796c30SShashank Sharma 	evf_mgr->ev_fence_ctx = dma_fence_context_alloc(1);
238fb796c30SShashank Sharma 	spin_lock_init(&evf_mgr->ev_fence_lock);
239fb796c30SShashank Sharma 
240b0328087SShashank Sharma 	INIT_DELAYED_WORK(&evf_mgr->suspend_work, amdgpu_eviction_fence_suspend_worker);
241fb796c30SShashank Sharma 	return 0;
242fb796c30SShashank Sharma }
243