xref: /linux/drivers/gpu/drm/amd/amdgpu/amdgpu_job.c (revision 068c330419ffb3422a43cb7d34351f1ef033950f)
10856cab1SChristian König /*
20856cab1SChristian König  * Copyright 2015 Advanced Micro Devices, Inc.
30856cab1SChristian König  *
40856cab1SChristian König  * Permission is hereby granted, free of charge, to any person obtaining a
50856cab1SChristian König  * copy of this software and associated documentation files (the "Software"),
60856cab1SChristian König  * to deal in the Software without restriction, including without limitation
70856cab1SChristian König  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
80856cab1SChristian König  * and/or sell copies of the Software, and to permit persons to whom the
90856cab1SChristian König  * Software is furnished to do so, subject to the following conditions:
100856cab1SChristian König  *
110856cab1SChristian König  * The above copyright notice and this permission notice shall be included in
120856cab1SChristian König  * all copies or substantial portions of the Software.
130856cab1SChristian König  *
140856cab1SChristian König  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
150856cab1SChristian König  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
160856cab1SChristian König  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
170856cab1SChristian König  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
180856cab1SChristian König  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
190856cab1SChristian König  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
200856cab1SChristian König  * OTHER DEALINGS IN THE SOFTWARE.
210856cab1SChristian König  *
220856cab1SChristian König  *
230856cab1SChristian König  */
240856cab1SChristian König #include <linux/kthread.h>
250856cab1SChristian König #include <linux/wait.h>
260856cab1SChristian König #include <linux/sched.h>
270856cab1SChristian König #include <drm/drmP.h>
280856cab1SChristian König #include "amdgpu.h"
290856cab1SChristian König #include "amdgpu_trace.h"
300856cab1SChristian König 
311b1f42d8SLucas Stach static void amdgpu_job_timedout(struct drm_sched_job *s_job)
320de2479cSMonk Liu {
333320b8d2SChristian König 	struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
343320b8d2SChristian König 	struct amdgpu_job *job = to_amdgpu_job(s_job);
350e51a772SChristian König 
36f024e883SChristian König 	DRM_ERROR("ring %s timeout, signaled seq=%u, emitted seq=%u\n",
373320b8d2SChristian König 		  job->base.sched->name, atomic_read(&ring->fence_drv.last_seq),
383320b8d2SChristian König 		  ring->fence_drv.sync_seq);
394fbf87e2SMonk Liu 
40a1917b73SChristian König 	amdgpu_device_gpu_recover(ring->adev, job, false);
410de2479cSMonk Liu }
420de2479cSMonk Liu 
430856cab1SChristian König int amdgpu_job_alloc(struct amdgpu_device *adev, unsigned num_ibs,
44c5637837SMonk Liu 		     struct amdgpu_job **job, struct amdgpu_vm *vm)
450856cab1SChristian König {
460856cab1SChristian König 	size_t size = sizeof(struct amdgpu_job);
470856cab1SChristian König 
480856cab1SChristian König 	if (num_ibs == 0)
490856cab1SChristian König 		return -EINVAL;
500856cab1SChristian König 
510856cab1SChristian König 	size += sizeof(struct amdgpu_ib) * num_ibs;
520856cab1SChristian König 
530856cab1SChristian König 	*job = kzalloc(size, GFP_KERNEL);
540856cab1SChristian König 	if (!*job)
550856cab1SChristian König 		return -ENOMEM;
560856cab1SChristian König 
57a1917b73SChristian König 	/*
58a1917b73SChristian König 	 * Initialize the scheduler to at least some ring so that we always
59a1917b73SChristian König 	 * have a pointer to adev.
60a1917b73SChristian König 	 */
61a1917b73SChristian König 	(*job)->base.sched = &adev->rings[0]->sched;
62c5637837SMonk Liu 	(*job)->vm = vm;
630856cab1SChristian König 	(*job)->ibs = (void *)&(*job)[1];
640856cab1SChristian König 	(*job)->num_ibs = num_ibs;
650856cab1SChristian König 
66e86f9ceeSChristian König 	amdgpu_sync_create(&(*job)->sync);
67df83d1ebSChunming Zhou 	amdgpu_sync_create(&(*job)->sched_sync);
68c70b78a7SMonk Liu 	(*job)->vram_lost_counter = atomic_read(&adev->vram_lost_counter);
69e86f9ceeSChristian König 
700856cab1SChristian König 	return 0;
710856cab1SChristian König }
720856cab1SChristian König 
730856cab1SChristian König int amdgpu_job_alloc_with_ib(struct amdgpu_device *adev, unsigned size,
740856cab1SChristian König 			     struct amdgpu_job **job)
750856cab1SChristian König {
760856cab1SChristian König 	int r;
770856cab1SChristian König 
78c5637837SMonk Liu 	r = amdgpu_job_alloc(adev, 1, job, NULL);
790856cab1SChristian König 	if (r)
800856cab1SChristian König 		return r;
810856cab1SChristian König 
820856cab1SChristian König 	r = amdgpu_ib_get(adev, NULL, size, &(*job)->ibs[0]);
830856cab1SChristian König 	if (r)
840856cab1SChristian König 		kfree(*job);
85df264f9eSChristian König 	else
86df264f9eSChristian König 		(*job)->vm_pd_addr = adev->gart.table_addr;
870856cab1SChristian König 
880856cab1SChristian König 	return r;
890856cab1SChristian König }
900856cab1SChristian König 
91a5fb4ec2SChristian König void amdgpu_job_free_resources(struct amdgpu_job *job)
920856cab1SChristian König {
93a1917b73SChristian König 	struct amdgpu_ring *ring = to_amdgpu_ring(job->base.sched);
94f54d1867SChris Wilson 	struct dma_fence *f;
951ab0d211SChristian König 	unsigned i;
961ab0d211SChristian König 
97676d8c24SMonk Liu 	/* use sched fence if available */
986fc13675SChristian König 	f = job->base.s_fence ? &job->base.s_fence->finished : job->fence;
990856cab1SChristian König 
1000856cab1SChristian König 	for (i = 0; i < job->num_ibs; ++i)
101a1917b73SChristian König 		amdgpu_ib_free(ring->adev, &job->ibs[i], f);
1020856cab1SChristian König }
1030856cab1SChristian König 
1041b1f42d8SLucas Stach static void amdgpu_job_free_cb(struct drm_sched_job *s_job)
105b6723c8dSMonk Liu {
1063320b8d2SChristian König 	struct amdgpu_ring *ring = to_amdgpu_ring(s_job->sched);
1073320b8d2SChristian König 	struct amdgpu_job *job = to_amdgpu_job(s_job);
108c5f74f78SChristian König 
1093320b8d2SChristian König 	amdgpu_ring_priority_put(ring, s_job->s_priority);
110f54d1867SChris Wilson 	dma_fence_put(job->fence);
111a79a5bdcSChristian König 	amdgpu_sync_free(&job->sync);
112df83d1ebSChunming Zhou 	amdgpu_sync_free(&job->sched_sync);
113b6723c8dSMonk Liu 	kfree(job);
114b6723c8dSMonk Liu }
115b6723c8dSMonk Liu 
1161e24e31fSChristian König void amdgpu_job_free(struct amdgpu_job *job)
1171e24e31fSChristian König {
1181e24e31fSChristian König 	amdgpu_job_free_resources(job);
119a79a5bdcSChristian König 
120f54d1867SChris Wilson 	dma_fence_put(job->fence);
121a79a5bdcSChristian König 	amdgpu_sync_free(&job->sync);
122df83d1ebSChunming Zhou 	amdgpu_sync_free(&job->sched_sync);
1231e24e31fSChristian König 	kfree(job);
1241e24e31fSChristian König }
1251e24e31fSChristian König 
1260e28b10fSChristian König int amdgpu_job_submit(struct amdgpu_job *job, struct drm_sched_entity *entity,
1270e28b10fSChristian König 		      void *owner, struct dma_fence **f)
1280856cab1SChristian König {
129b5286801SChristian König 	enum drm_sched_priority priority;
130b5286801SChristian König 	struct amdgpu_ring *ring;
131e686941aSMonk Liu 	int r;
1320856cab1SChristian König 
133e686941aSMonk Liu 	if (!f)
134e686941aSMonk Liu 		return -EINVAL;
135e686941aSMonk Liu 
136cdc50176SNayan Deshmukh 	r = drm_sched_job_init(&job->base, entity, owner);
137e686941aSMonk Liu 	if (r)
138e686941aSMonk Liu 		return r;
1390856cab1SChristian König 
1400856cab1SChristian König 	job->owner = owner;
141f54d1867SChris Wilson 	*f = dma_fence_get(&job->base.s_fence->finished);
142a5fb4ec2SChristian König 	amdgpu_job_free_resources(job);
143b5286801SChristian König 	priority = job->base.s_priority;
1441b1f42d8SLucas Stach 	drm_sched_entity_push_job(&job->base, entity);
1450856cab1SChristian König 
146*068c3304SNayan Deshmukh 	ring = to_amdgpu_ring(entity->rq->sched);
147b5286801SChristian König 	amdgpu_ring_priority_get(ring, priority);
148b5286801SChristian König 
1490856cab1SChristian König 	return 0;
1500856cab1SChristian König }
1510856cab1SChristian König 
152ee913fd9SChristian König int amdgpu_job_submit_direct(struct amdgpu_job *job, struct amdgpu_ring *ring,
153ee913fd9SChristian König 			     struct dma_fence **fence)
154ee913fd9SChristian König {
155ee913fd9SChristian König 	int r;
156ee913fd9SChristian König 
157ee913fd9SChristian König 	job->base.sched = &ring->sched;
158ee913fd9SChristian König 	r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, NULL, fence);
159ee913fd9SChristian König 	job->fence = dma_fence_get(*fence);
160ee913fd9SChristian König 	if (r)
161ee913fd9SChristian König 		return r;
162ee913fd9SChristian König 
163ee913fd9SChristian König 	amdgpu_job_free(job);
164ee913fd9SChristian König 	return 0;
165ee913fd9SChristian König }
166ee913fd9SChristian König 
1671b1f42d8SLucas Stach static struct dma_fence *amdgpu_job_dependency(struct drm_sched_job *sched_job,
1681b1f42d8SLucas Stach 					       struct drm_sched_entity *s_entity)
1690856cab1SChristian König {
170*068c3304SNayan Deshmukh 	struct amdgpu_ring *ring = to_amdgpu_ring(s_entity->rq->sched);
1710856cab1SChristian König 	struct amdgpu_job *job = to_amdgpu_job(sched_job);
172c5637837SMonk Liu 	struct amdgpu_vm *vm = job->vm;
173f024e883SChristian König 	struct dma_fence *fence;
174cebb52b7SAndrey Grodzovsky 	bool explicit = false;
175df83d1ebSChunming Zhou 	int r;
1760856cab1SChristian König 
177f024e883SChristian König 	fence = amdgpu_sync_get_fence(&job->sync, &explicit);
178cebb52b7SAndrey Grodzovsky 	if (fence && explicit) {
1791b1f42d8SLucas Stach 		if (drm_sched_dependency_optimized(fence, s_entity)) {
180a1917b73SChristian König 			r = amdgpu_sync_fence(ring->adev, &job->sched_sync,
181a1917b73SChristian König 					      fence, false);
182a340c7bcSChunming Zhou 			if (r)
183f024e883SChristian König 				DRM_ERROR("Error adding fence (%d)\n", r);
184a340c7bcSChunming Zhou 		}
185cebb52b7SAndrey Grodzovsky 	}
186cebb52b7SAndrey Grodzovsky 
187c4f46f22SChristian König 	while (fence == NULL && vm && !job->vmid) {
188620f774fSChristian König 		r = amdgpu_vmid_grab(vm, ring, &job->sync,
1896fc13675SChristian König 				     &job->base.s_fence->finished,
190fd53be30SChunming Zhou 				     job);
1910856cab1SChristian König 		if (r)
1920856cab1SChristian König 			DRM_ERROR("Error getting VM ID (%d)\n", r);
1930856cab1SChristian König 
194cebb52b7SAndrey Grodzovsky 		fence = amdgpu_sync_get_fence(&job->sync, NULL);
1950856cab1SChristian König 	}
1960856cab1SChristian König 
1970856cab1SChristian König 	return fence;
1980856cab1SChristian König }
1990856cab1SChristian König 
2001b1f42d8SLucas Stach static struct dma_fence *amdgpu_job_run(struct drm_sched_job *sched_job)
2010856cab1SChristian König {
2023320b8d2SChristian König 	struct amdgpu_ring *ring = to_amdgpu_ring(sched_job->sched);
20348f05f29SMonk Liu 	struct dma_fence *fence = NULL, *finished;
2040856cab1SChristian König 	struct amdgpu_job *job;
2050856cab1SChristian König 	int r;
2060856cab1SChristian König 
2070856cab1SChristian König 	job = to_amdgpu_job(sched_job);
20848f05f29SMonk Liu 	finished = &job->base.s_fence->finished;
209e86f9ceeSChristian König 
2101fbb2e92SChristian König 	BUG_ON(amdgpu_sync_peek_fence(&job->sync, NULL));
211e86f9ceeSChristian König 
2120856cab1SChristian König 	trace_amdgpu_sched_run_job(job);
21348f05f29SMonk Liu 
214a1917b73SChristian König 	if (job->vram_lost_counter != atomic_read(&ring->adev->vram_lost_counter))
21548f05f29SMonk Liu 		dma_fence_set_error(finished, -ECANCELED);/* skip IB as well if VRAM lost */
21648f05f29SMonk Liu 
21748f05f29SMonk Liu 	if (finished->error < 0) {
21848f05f29SMonk Liu 		DRM_INFO("Skip scheduling IBs!\n");
21914e47f93SChristian König 	} else {
2203320b8d2SChristian König 		r = amdgpu_ib_schedule(ring, job->num_ibs, job->ibs, job,
22114e47f93SChristian König 				       &fence);
22222a77cf6SChristian König 		if (r)
2230856cab1SChristian König 			DRM_ERROR("Error scheduling IBs (%d)\n", r);
22415d73ce6SChunming Zhou 	}
225c7c5fbcdSChunming Zhou 	/* if gpu reset, hw fence will be replaced here */
226f54d1867SChris Wilson 	dma_fence_put(job->fence);
227f54d1867SChris Wilson 	job->fence = dma_fence_get(fence);
228b2ff0e8aSAndres Rodriguez 
22922a77cf6SChristian König 	amdgpu_job_free_resources(job);
2300856cab1SChristian König 	return fence;
2310856cab1SChristian König }
2320856cab1SChristian König 
2331b1f42d8SLucas Stach const struct drm_sched_backend_ops amdgpu_sched_ops = {
2340856cab1SChristian König 	.dependency = amdgpu_job_dependency,
2350856cab1SChristian König 	.run_job = amdgpu_job_run,
2360e51a772SChristian König 	.timedout_job = amdgpu_job_timedout,
237c5f74f78SChristian König 	.free_job = amdgpu_job_free_cb
2380856cab1SChristian König };
239