xref: /netbsd-src/sys/external/bsd/drm2/dist/drm/amd/amdgpu/amdgpu_ctx.c (revision 8e26f2b9b1486b9a968ae7db2fb37c284a0a13fc)
1*8e26f2b9Sriastradh /*	$NetBSD: amdgpu_ctx.c,v 1.8 2021/12/19 12:38:41 riastradh Exp $	*/
2efa246c0Sriastradh 
3efa246c0Sriastradh /*
4efa246c0Sriastradh  * Copyright 2015 Advanced Micro Devices, Inc.
5efa246c0Sriastradh  *
6efa246c0Sriastradh  * Permission is hereby granted, free of charge, to any person obtaining a
7efa246c0Sriastradh  * copy of this software and associated documentation files (the "Software"),
8efa246c0Sriastradh  * to deal in the Software without restriction, including without limitation
9efa246c0Sriastradh  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10efa246c0Sriastradh  * and/or sell copies of the Software, and to permit persons to whom the
11efa246c0Sriastradh  * Software is furnished to do so, subject to the following conditions:
12efa246c0Sriastradh  *
13efa246c0Sriastradh  * The above copyright notice and this permission notice shall be included in
14efa246c0Sriastradh  * all copies or substantial portions of the Software.
15efa246c0Sriastradh  *
16efa246c0Sriastradh  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17efa246c0Sriastradh  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18efa246c0Sriastradh  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19efa246c0Sriastradh  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20efa246c0Sriastradh  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21efa246c0Sriastradh  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22efa246c0Sriastradh  * OTHER DEALINGS IN THE SOFTWARE.
23efa246c0Sriastradh  *
24efa246c0Sriastradh  * Authors: monk liu <monk.liu@amd.com>
25efa246c0Sriastradh  */
26efa246c0Sriastradh 
27efa246c0Sriastradh #include <sys/cdefs.h>
28*8e26f2b9Sriastradh __KERNEL_RCSID(0, "$NetBSD: amdgpu_ctx.c,v 1.8 2021/12/19 12:38:41 riastradh Exp $");
29efa246c0Sriastradh 
3041ec0267Sriastradh #include <drm/drm_auth.h>
31efa246c0Sriastradh #include "amdgpu.h"
3241ec0267Sriastradh #include "amdgpu_sched.h"
3341ec0267Sriastradh #include "amdgpu_ras.h"
34efa246c0Sriastradh 
351b46a69aSriastradh #include <linux/nbsd-namespace.h>
3641ec0267Sriastradh #define to_amdgpu_ctx_entity(e)	\
3741ec0267Sriastradh 	container_of((e), struct amdgpu_ctx_entity, entity)
381b46a69aSriastradh 
3941ec0267Sriastradh const unsigned int amdgpu_ctx_num_entities[AMDGPU_HW_IP_NUM] = {
4041ec0267Sriastradh 	[AMDGPU_HW_IP_GFX]	=	1,
4141ec0267Sriastradh 	[AMDGPU_HW_IP_COMPUTE]	=	4,
4241ec0267Sriastradh 	[AMDGPU_HW_IP_DMA]	=	2,
4341ec0267Sriastradh 	[AMDGPU_HW_IP_UVD]	=	1,
4441ec0267Sriastradh 	[AMDGPU_HW_IP_VCE]	=	1,
4541ec0267Sriastradh 	[AMDGPU_HW_IP_UVD_ENC]	=	1,
4641ec0267Sriastradh 	[AMDGPU_HW_IP_VCN_DEC]	=	1,
4741ec0267Sriastradh 	[AMDGPU_HW_IP_VCN_ENC]	=	1,
4841ec0267Sriastradh 	[AMDGPU_HW_IP_VCN_JPEG]	=	1,
4941ec0267Sriastradh };
5041ec0267Sriastradh 
amdgpu_ctx_priority_permit(struct drm_file * filp,enum drm_sched_priority priority)5141ec0267Sriastradh static int amdgpu_ctx_priority_permit(struct drm_file *filp,
5241ec0267Sriastradh 				      enum drm_sched_priority priority)
53efa246c0Sriastradh {
5441ec0267Sriastradh 	if (priority < 0 || priority >= DRM_SCHED_PRIORITY_MAX)
5541ec0267Sriastradh 		return -EINVAL;
5641ec0267Sriastradh 
5741ec0267Sriastradh 	/* NORMAL and below are accessible by everyone */
5841ec0267Sriastradh 	if (priority <= DRM_SCHED_PRIORITY_NORMAL)
5941ec0267Sriastradh 		return 0;
6041ec0267Sriastradh 
6141ec0267Sriastradh 	if (capable(CAP_SYS_NICE))
6241ec0267Sriastradh 		return 0;
6341ec0267Sriastradh 
6441ec0267Sriastradh 	if (drm_is_current_master(filp))
6541ec0267Sriastradh 		return 0;
6641ec0267Sriastradh 
6741ec0267Sriastradh 	return -EACCES;
6841ec0267Sriastradh }
6941ec0267Sriastradh 
amdgpu_ctx_init_entity(struct amdgpu_ctx * ctx,const u32 hw_ip,const u32 ring)7041ec0267Sriastradh static int amdgpu_ctx_init_entity(struct amdgpu_ctx *ctx, const u32 hw_ip, const u32 ring)
7141ec0267Sriastradh {
7241ec0267Sriastradh 	struct amdgpu_device *adev = ctx->adev;
7341ec0267Sriastradh 	struct amdgpu_ctx_entity *entity;
7441ec0267Sriastradh 	struct drm_gpu_scheduler **scheds = NULL, *sched = NULL;
7541ec0267Sriastradh 	unsigned num_scheds = 0;
7641ec0267Sriastradh 	enum drm_sched_priority priority;
77efa246c0Sriastradh 	int r;
78efa246c0Sriastradh 
7941ec0267Sriastradh 	entity = kcalloc(1, offsetof(typeof(*entity), fences[amdgpu_sched_jobs]),
8041ec0267Sriastradh 			 GFP_KERNEL);
8141ec0267Sriastradh 	if (!entity)
8241ec0267Sriastradh 		return  -ENOMEM;
83efa246c0Sriastradh 
8441ec0267Sriastradh 	entity->sequence = 1;
8541ec0267Sriastradh 	priority = (ctx->override_priority == DRM_SCHED_PRIORITY_UNSET) ?
8641ec0267Sriastradh 				ctx->init_priority : ctx->override_priority;
8741ec0267Sriastradh 	switch (hw_ip) {
8841ec0267Sriastradh 		case AMDGPU_HW_IP_GFX:
8941ec0267Sriastradh 			sched = &adev->gfx.gfx_ring[0].sched;
9041ec0267Sriastradh 			scheds = &sched;
9141ec0267Sriastradh 			num_scheds = 1;
9241ec0267Sriastradh 			break;
9341ec0267Sriastradh 		case AMDGPU_HW_IP_COMPUTE:
9441ec0267Sriastradh 			scheds = adev->gfx.compute_sched;
9541ec0267Sriastradh 			num_scheds = adev->gfx.num_compute_sched;
9641ec0267Sriastradh 			break;
9741ec0267Sriastradh 		case AMDGPU_HW_IP_DMA:
9841ec0267Sriastradh 			scheds = adev->sdma.sdma_sched;
9941ec0267Sriastradh 			num_scheds = adev->sdma.num_sdma_sched;
10041ec0267Sriastradh 			break;
10141ec0267Sriastradh 		case AMDGPU_HW_IP_UVD:
10241ec0267Sriastradh 			sched = &adev->uvd.inst[0].ring.sched;
10341ec0267Sriastradh 			scheds = &sched;
10441ec0267Sriastradh 			num_scheds = 1;
10541ec0267Sriastradh 			break;
10641ec0267Sriastradh 		case AMDGPU_HW_IP_VCE:
10741ec0267Sriastradh 			sched = &adev->vce.ring[0].sched;
10841ec0267Sriastradh 			scheds = &sched;
10941ec0267Sriastradh 			num_scheds = 1;
11041ec0267Sriastradh 			break;
11141ec0267Sriastradh 		case AMDGPU_HW_IP_UVD_ENC:
11241ec0267Sriastradh 			sched = &adev->uvd.inst[0].ring_enc[0].sched;
11341ec0267Sriastradh 			scheds = &sched;
11441ec0267Sriastradh 			num_scheds = 1;
11541ec0267Sriastradh 			break;
11641ec0267Sriastradh 		case AMDGPU_HW_IP_VCN_DEC:
11741ec0267Sriastradh 			scheds = adev->vcn.vcn_dec_sched;
11841ec0267Sriastradh 			num_scheds =  adev->vcn.num_vcn_dec_sched;
11941ec0267Sriastradh 			break;
12041ec0267Sriastradh 		case AMDGPU_HW_IP_VCN_ENC:
12141ec0267Sriastradh 			scheds = adev->vcn.vcn_enc_sched;
12241ec0267Sriastradh 			num_scheds =  adev->vcn.num_vcn_enc_sched;
12341ec0267Sriastradh 			break;
12441ec0267Sriastradh 		case AMDGPU_HW_IP_VCN_JPEG:
12541ec0267Sriastradh 			scheds = adev->jpeg.jpeg_sched;
12641ec0267Sriastradh 			num_scheds =  adev->jpeg.num_jpeg_sched;
127efa246c0Sriastradh 			break;
128efa246c0Sriastradh 	}
129efa246c0Sriastradh 
13041ec0267Sriastradh 	r = drm_sched_entity_init(&entity->entity, priority, scheds, num_scheds,
13141ec0267Sriastradh 				  &ctx->guilty);
13241ec0267Sriastradh 	if (r)
13341ec0267Sriastradh 		goto error_free_entity;
13441ec0267Sriastradh 
13541ec0267Sriastradh 	ctx->entities[hw_ip][ring] = entity;
13641ec0267Sriastradh 	return 0;
13741ec0267Sriastradh 
13841ec0267Sriastradh error_free_entity:
13941ec0267Sriastradh 	kfree(entity);
14041ec0267Sriastradh 
141efa246c0Sriastradh 	return r;
142efa246c0Sriastradh }
14341ec0267Sriastradh 
amdgpu_ctx_init(struct amdgpu_device * adev,enum drm_sched_priority priority,struct drm_file * filp,struct amdgpu_ctx * ctx)14441ec0267Sriastradh static int amdgpu_ctx_init(struct amdgpu_device *adev,
14541ec0267Sriastradh 			   enum drm_sched_priority priority,
14641ec0267Sriastradh 			   struct drm_file *filp,
14741ec0267Sriastradh 			   struct amdgpu_ctx *ctx)
14841ec0267Sriastradh {
14941ec0267Sriastradh 	int r;
15041ec0267Sriastradh 
15141ec0267Sriastradh 	r = amdgpu_ctx_priority_permit(filp, priority);
15241ec0267Sriastradh 	if (r)
15341ec0267Sriastradh 		return r;
15441ec0267Sriastradh 
15541ec0267Sriastradh 	memset(ctx, 0, sizeof(*ctx));
15641ec0267Sriastradh 
15741ec0267Sriastradh 	ctx->adev = adev;
15841ec0267Sriastradh 
15941ec0267Sriastradh 	kref_init(&ctx->refcount);
16041ec0267Sriastradh 	spin_lock_init(&ctx->ring_lock);
16141ec0267Sriastradh 	mutex_init(&ctx->lock);
16241ec0267Sriastradh 
16341ec0267Sriastradh 	ctx->reset_counter = atomic_read(&adev->gpu_reset_counter);
16441ec0267Sriastradh 	ctx->reset_counter_query = ctx->reset_counter;
16541ec0267Sriastradh 	ctx->vram_lost_counter = atomic_read(&adev->vram_lost_counter);
16641ec0267Sriastradh 	ctx->init_priority = priority;
16741ec0267Sriastradh 	ctx->override_priority = DRM_SCHED_PRIORITY_UNSET;
16841ec0267Sriastradh 
169efa246c0Sriastradh 	return 0;
17041ec0267Sriastradh 
171efa246c0Sriastradh }
172efa246c0Sriastradh 
amdgpu_ctx_fini_entity(struct amdgpu_ctx_entity * entity)17341ec0267Sriastradh static void amdgpu_ctx_fini_entity(struct amdgpu_ctx_entity *entity)
174efa246c0Sriastradh {
17541ec0267Sriastradh 
17641ec0267Sriastradh 	int i;
17741ec0267Sriastradh 
17841ec0267Sriastradh 	if (!entity)
17941ec0267Sriastradh 		return;
18041ec0267Sriastradh 
18141ec0267Sriastradh 	for (i = 0; i < amdgpu_sched_jobs; ++i)
18241ec0267Sriastradh 		dma_fence_put(entity->fences[i]);
18341ec0267Sriastradh 
18441ec0267Sriastradh 	kfree(entity);
18541ec0267Sriastradh }
18641ec0267Sriastradh 
amdgpu_ctx_fini(struct kref * ref)18741ec0267Sriastradh static void amdgpu_ctx_fini(struct kref *ref)
18841ec0267Sriastradh {
18941ec0267Sriastradh 	struct amdgpu_ctx *ctx = container_of(ref, struct amdgpu_ctx, refcount);
190efa246c0Sriastradh 	struct amdgpu_device *adev = ctx->adev;
191efa246c0Sriastradh 	unsigned i, j;
192efa246c0Sriastradh 
193efa246c0Sriastradh 	if (!adev)
194efa246c0Sriastradh 		return;
195efa246c0Sriastradh 
19641ec0267Sriastradh 	for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
19741ec0267Sriastradh 		for (j = 0; j < AMDGPU_MAX_ENTITY_NUM; ++j) {
19841ec0267Sriastradh 			amdgpu_ctx_fini_entity(ctx->entities[i][j]);
19941ec0267Sriastradh 			ctx->entities[i][j] = NULL;
200efa246c0Sriastradh 		}
201efa246c0Sriastradh 	}
202efa246c0Sriastradh 
20341ec0267Sriastradh 	mutex_destroy(&ctx->lock);
20407eb61ceSriastradh 	spin_lock_destroy(&ctx->ring_lock);
20541ec0267Sriastradh 	kfree(ctx);
20641ec0267Sriastradh }
20741ec0267Sriastradh 
amdgpu_ctx_get_entity(struct amdgpu_ctx * ctx,u32 hw_ip,u32 instance,u32 ring,struct drm_sched_entity ** entity)20841ec0267Sriastradh int amdgpu_ctx_get_entity(struct amdgpu_ctx *ctx, u32 hw_ip, u32 instance,
20941ec0267Sriastradh 			  u32 ring, struct drm_sched_entity **entity)
21041ec0267Sriastradh {
21141ec0267Sriastradh 	int r;
21241ec0267Sriastradh 
21341ec0267Sriastradh 	if (hw_ip >= AMDGPU_HW_IP_NUM) {
21441ec0267Sriastradh 		DRM_ERROR("unknown HW IP type: %d\n", hw_ip);
21541ec0267Sriastradh 		return -EINVAL;
21641ec0267Sriastradh 	}
21741ec0267Sriastradh 
21841ec0267Sriastradh 	/* Right now all IPs have only one instance - multiple rings. */
21941ec0267Sriastradh 	if (instance != 0) {
22041ec0267Sriastradh 		DRM_DEBUG("invalid ip instance: %d\n", instance);
22141ec0267Sriastradh 		return -EINVAL;
22241ec0267Sriastradh 	}
22341ec0267Sriastradh 
22441ec0267Sriastradh 	if (ring >= amdgpu_ctx_num_entities[hw_ip]) {
22541ec0267Sriastradh 		DRM_DEBUG("invalid ring: %d %d\n", hw_ip, ring);
22641ec0267Sriastradh 		return -EINVAL;
22741ec0267Sriastradh 	}
22841ec0267Sriastradh 
22941ec0267Sriastradh 	if (ctx->entities[hw_ip][ring] == NULL) {
23041ec0267Sriastradh 		r = amdgpu_ctx_init_entity(ctx, hw_ip, ring);
23141ec0267Sriastradh 		if (r)
23241ec0267Sriastradh 			return r;
23341ec0267Sriastradh 	}
23441ec0267Sriastradh 
23541ec0267Sriastradh 	*entity = &ctx->entities[hw_ip][ring]->entity;
23641ec0267Sriastradh 	return 0;
23741ec0267Sriastradh }
23841ec0267Sriastradh 
amdgpu_ctx_alloc(struct amdgpu_device * adev,struct amdgpu_fpriv * fpriv,struct drm_file * filp,enum drm_sched_priority priority,uint32_t * id)239efa246c0Sriastradh static int amdgpu_ctx_alloc(struct amdgpu_device *adev,
240efa246c0Sriastradh 			    struct amdgpu_fpriv *fpriv,
24141ec0267Sriastradh 			    struct drm_file *filp,
24241ec0267Sriastradh 			    enum drm_sched_priority priority,
243efa246c0Sriastradh 			    uint32_t *id)
244efa246c0Sriastradh {
245efa246c0Sriastradh 	struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
246efa246c0Sriastradh 	struct amdgpu_ctx *ctx;
247efa246c0Sriastradh 	int r;
248efa246c0Sriastradh 
249efa246c0Sriastradh 	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
250efa246c0Sriastradh 	if (!ctx)
251efa246c0Sriastradh 		return -ENOMEM;
252efa246c0Sriastradh 
253b013193aSriastradh 	idr_preload(GFP_KERNEL);
254efa246c0Sriastradh 	mutex_lock(&mgr->lock);
25541ec0267Sriastradh 	r = idr_alloc(&mgr->ctx_handles, ctx, 1, AMDGPU_VM_MAX_NUM_CTX, GFP_KERNEL);
256efa246c0Sriastradh 	if (r < 0) {
257efa246c0Sriastradh 		mutex_unlock(&mgr->lock);
258b013193aSriastradh 		idr_preload_end();
259efa246c0Sriastradh 		kfree(ctx);
260efa246c0Sriastradh 		return r;
261efa246c0Sriastradh 	}
26241ec0267Sriastradh 
263efa246c0Sriastradh 	*id = (uint32_t)r;
26441ec0267Sriastradh 	r = amdgpu_ctx_init(adev, priority, filp, ctx);
26541ec0267Sriastradh 	if (r) {
26641ec0267Sriastradh 		idr_remove(&mgr->ctx_handles, *id);
26741ec0267Sriastradh 		*id = 0;
26841ec0267Sriastradh 		kfree(ctx);
26941ec0267Sriastradh 	}
270efa246c0Sriastradh 	mutex_unlock(&mgr->lock);
271b013193aSriastradh 	idr_preload_end();
272efa246c0Sriastradh 
273efa246c0Sriastradh 	return r;
274efa246c0Sriastradh }
275efa246c0Sriastradh 
amdgpu_ctx_do_release(struct kref * ref)276efa246c0Sriastradh static void amdgpu_ctx_do_release(struct kref *ref)
277efa246c0Sriastradh {
278efa246c0Sriastradh 	struct amdgpu_ctx *ctx;
27941ec0267Sriastradh 	u32 i, j;
280efa246c0Sriastradh 
281efa246c0Sriastradh 	ctx = container_of(ref, struct amdgpu_ctx, refcount);
28241ec0267Sriastradh 	for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
28341ec0267Sriastradh 		for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) {
28441ec0267Sriastradh 			if (!ctx->entities[i][j])
28541ec0267Sriastradh 				continue;
286efa246c0Sriastradh 
28741ec0267Sriastradh 			drm_sched_entity_destroy(&ctx->entities[i][j]->entity);
28841ec0267Sriastradh 		}
28941ec0267Sriastradh 	}
290efa246c0Sriastradh 
29141ec0267Sriastradh 	amdgpu_ctx_fini(ref);
292efa246c0Sriastradh }
293efa246c0Sriastradh 
amdgpu_ctx_free(struct amdgpu_fpriv * fpriv,uint32_t id)294efa246c0Sriastradh static int amdgpu_ctx_free(struct amdgpu_fpriv *fpriv, uint32_t id)
295efa246c0Sriastradh {
296efa246c0Sriastradh 	struct amdgpu_ctx_mgr *mgr = &fpriv->ctx_mgr;
297efa246c0Sriastradh 	struct amdgpu_ctx *ctx;
298efa246c0Sriastradh 
299efa246c0Sriastradh 	mutex_lock(&mgr->lock);
30041ec0267Sriastradh 	ctx = idr_remove(&mgr->ctx_handles, id);
30141ec0267Sriastradh 	if (ctx)
302efa246c0Sriastradh 		kref_put(&ctx->refcount, amdgpu_ctx_do_release);
303efa246c0Sriastradh 	mutex_unlock(&mgr->lock);
30441ec0267Sriastradh 	return ctx ? 0 : -EINVAL;
305efa246c0Sriastradh }
306efa246c0Sriastradh 
amdgpu_ctx_query(struct amdgpu_device * adev,struct amdgpu_fpriv * fpriv,uint32_t id,union drm_amdgpu_ctx_out * out)307efa246c0Sriastradh static int amdgpu_ctx_query(struct amdgpu_device *adev,
308efa246c0Sriastradh 			    struct amdgpu_fpriv *fpriv, uint32_t id,
309efa246c0Sriastradh 			    union drm_amdgpu_ctx_out *out)
310efa246c0Sriastradh {
311efa246c0Sriastradh 	struct amdgpu_ctx *ctx;
312efa246c0Sriastradh 	struct amdgpu_ctx_mgr *mgr;
313efa246c0Sriastradh 	unsigned reset_counter;
314efa246c0Sriastradh 
315efa246c0Sriastradh 	if (!fpriv)
316efa246c0Sriastradh 		return -EINVAL;
317efa246c0Sriastradh 
318efa246c0Sriastradh 	mgr = &fpriv->ctx_mgr;
319efa246c0Sriastradh 	mutex_lock(&mgr->lock);
320efa246c0Sriastradh 	ctx = idr_find(&mgr->ctx_handles, id);
321efa246c0Sriastradh 	if (!ctx) {
322efa246c0Sriastradh 		mutex_unlock(&mgr->lock);
323efa246c0Sriastradh 		return -EINVAL;
324efa246c0Sriastradh 	}
325efa246c0Sriastradh 
326efa246c0Sriastradh 	/* TODO: these two are always zero */
327efa246c0Sriastradh 	out->state.flags = 0x0;
328efa246c0Sriastradh 	out->state.hangs = 0x0;
329efa246c0Sriastradh 
330efa246c0Sriastradh 	/* determine if a GPU reset has occured since the last call */
331efa246c0Sriastradh 	reset_counter = atomic_read(&adev->gpu_reset_counter);
332efa246c0Sriastradh 	/* TODO: this should ideally return NO, GUILTY, or INNOCENT. */
33341ec0267Sriastradh 	if (ctx->reset_counter_query == reset_counter)
334efa246c0Sriastradh 		out->state.reset_status = AMDGPU_CTX_NO_RESET;
335efa246c0Sriastradh 	else
336efa246c0Sriastradh 		out->state.reset_status = AMDGPU_CTX_UNKNOWN_RESET;
33741ec0267Sriastradh 	ctx->reset_counter_query = reset_counter;
33841ec0267Sriastradh 
33941ec0267Sriastradh 	mutex_unlock(&mgr->lock);
34041ec0267Sriastradh 	return 0;
34141ec0267Sriastradh }
34241ec0267Sriastradh 
amdgpu_ctx_query2(struct amdgpu_device * adev,struct amdgpu_fpriv * fpriv,uint32_t id,union drm_amdgpu_ctx_out * out)34341ec0267Sriastradh static int amdgpu_ctx_query2(struct amdgpu_device *adev,
34441ec0267Sriastradh 	struct amdgpu_fpriv *fpriv, uint32_t id,
34541ec0267Sriastradh 	union drm_amdgpu_ctx_out *out)
34641ec0267Sriastradh {
34741ec0267Sriastradh 	struct amdgpu_ctx *ctx;
34841ec0267Sriastradh 	struct amdgpu_ctx_mgr *mgr;
34941ec0267Sriastradh 	unsigned long ras_counter;
35041ec0267Sriastradh 
35141ec0267Sriastradh 	if (!fpriv)
35241ec0267Sriastradh 		return -EINVAL;
35341ec0267Sriastradh 
35441ec0267Sriastradh 	mgr = &fpriv->ctx_mgr;
35541ec0267Sriastradh 	mutex_lock(&mgr->lock);
35641ec0267Sriastradh 	ctx = idr_find(&mgr->ctx_handles, id);
35741ec0267Sriastradh 	if (!ctx) {
35841ec0267Sriastradh 		mutex_unlock(&mgr->lock);
35941ec0267Sriastradh 		return -EINVAL;
36041ec0267Sriastradh 	}
36141ec0267Sriastradh 
36241ec0267Sriastradh 	out->state.flags = 0x0;
36341ec0267Sriastradh 	out->state.hangs = 0x0;
36441ec0267Sriastradh 
36541ec0267Sriastradh 	if (ctx->reset_counter != atomic_read(&adev->gpu_reset_counter))
36641ec0267Sriastradh 		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RESET;
36741ec0267Sriastradh 
36841ec0267Sriastradh 	if (ctx->vram_lost_counter != atomic_read(&adev->vram_lost_counter))
36941ec0267Sriastradh 		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_VRAMLOST;
37041ec0267Sriastradh 
37141ec0267Sriastradh 	if (atomic_read(&ctx->guilty))
37241ec0267Sriastradh 		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_GUILTY;
37341ec0267Sriastradh 
37441ec0267Sriastradh 	/*query ue count*/
37541ec0267Sriastradh 	ras_counter = amdgpu_ras_query_error_count(adev, false);
37641ec0267Sriastradh 	/*ras counter is monotonic increasing*/
37741ec0267Sriastradh 	if (ras_counter != ctx->ras_counter_ue) {
37841ec0267Sriastradh 		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RAS_UE;
37941ec0267Sriastradh 		ctx->ras_counter_ue = ras_counter;
38041ec0267Sriastradh 	}
38141ec0267Sriastradh 
38241ec0267Sriastradh 	/*query ce count*/
38341ec0267Sriastradh 	ras_counter = amdgpu_ras_query_error_count(adev, true);
38441ec0267Sriastradh 	if (ras_counter != ctx->ras_counter_ce) {
38541ec0267Sriastradh 		out->state.flags |= AMDGPU_CTX_QUERY2_FLAGS_RAS_CE;
38641ec0267Sriastradh 		ctx->ras_counter_ce = ras_counter;
38741ec0267Sriastradh 	}
388efa246c0Sriastradh 
389efa246c0Sriastradh 	mutex_unlock(&mgr->lock);
390efa246c0Sriastradh 	return 0;
391efa246c0Sriastradh }
392efa246c0Sriastradh 
amdgpu_ctx_ioctl(struct drm_device * dev,void * data,struct drm_file * filp)393efa246c0Sriastradh int amdgpu_ctx_ioctl(struct drm_device *dev, void *data,
394efa246c0Sriastradh 		     struct drm_file *filp)
395efa246c0Sriastradh {
396efa246c0Sriastradh 	int r;
397efa246c0Sriastradh 	uint32_t id;
39841ec0267Sriastradh 	enum drm_sched_priority priority;
399efa246c0Sriastradh 
400efa246c0Sriastradh 	union drm_amdgpu_ctx *args = data;
401efa246c0Sriastradh 	struct amdgpu_device *adev = dev->dev_private;
402efa246c0Sriastradh 	struct amdgpu_fpriv *fpriv = filp->driver_priv;
403efa246c0Sriastradh 
404efa246c0Sriastradh 	r = 0;
405efa246c0Sriastradh 	id = args->in.ctx_id;
40641ec0267Sriastradh 	priority = amdgpu_to_sched_priority(args->in.priority);
40741ec0267Sriastradh 
40841ec0267Sriastradh 	/* For backwards compatibility reasons, we need to accept
40941ec0267Sriastradh 	 * ioctls with garbage in the priority field */
41041ec0267Sriastradh 	if (priority == DRM_SCHED_PRIORITY_INVALID)
41141ec0267Sriastradh 		priority = DRM_SCHED_PRIORITY_NORMAL;
412efa246c0Sriastradh 
413efa246c0Sriastradh 	switch (args->in.op) {
414efa246c0Sriastradh 	case AMDGPU_CTX_OP_ALLOC_CTX:
41541ec0267Sriastradh 		r = amdgpu_ctx_alloc(adev, fpriv, filp, priority, &id);
416efa246c0Sriastradh 		args->out.alloc.ctx_id = id;
417efa246c0Sriastradh 		break;
418efa246c0Sriastradh 	case AMDGPU_CTX_OP_FREE_CTX:
419efa246c0Sriastradh 		r = amdgpu_ctx_free(fpriv, id);
420efa246c0Sriastradh 		break;
421efa246c0Sriastradh 	case AMDGPU_CTX_OP_QUERY_STATE:
422efa246c0Sriastradh 		r = amdgpu_ctx_query(adev, fpriv, id, &args->out);
423efa246c0Sriastradh 		break;
42441ec0267Sriastradh 	case AMDGPU_CTX_OP_QUERY_STATE2:
42541ec0267Sriastradh 		r = amdgpu_ctx_query2(adev, fpriv, id, &args->out);
42641ec0267Sriastradh 		break;
427efa246c0Sriastradh 	default:
428efa246c0Sriastradh 		return -EINVAL;
429efa246c0Sriastradh 	}
430efa246c0Sriastradh 
431efa246c0Sriastradh 	return r;
432efa246c0Sriastradh }
433efa246c0Sriastradh 
amdgpu_ctx_get(struct amdgpu_fpriv * fpriv,uint32_t id)434efa246c0Sriastradh struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id)
435efa246c0Sriastradh {
436efa246c0Sriastradh 	struct amdgpu_ctx *ctx;
437efa246c0Sriastradh 	struct amdgpu_ctx_mgr *mgr;
438efa246c0Sriastradh 
439efa246c0Sriastradh 	if (!fpriv)
440efa246c0Sriastradh 		return NULL;
441efa246c0Sriastradh 
442efa246c0Sriastradh 	mgr = &fpriv->ctx_mgr;
443efa246c0Sriastradh 
444efa246c0Sriastradh 	mutex_lock(&mgr->lock);
445efa246c0Sriastradh 	ctx = idr_find(&mgr->ctx_handles, id);
446efa246c0Sriastradh 	if (ctx)
447efa246c0Sriastradh 		kref_get(&ctx->refcount);
448efa246c0Sriastradh 	mutex_unlock(&mgr->lock);
449efa246c0Sriastradh 	return ctx;
450efa246c0Sriastradh }
451efa246c0Sriastradh 
amdgpu_ctx_put(struct amdgpu_ctx * ctx)452efa246c0Sriastradh int amdgpu_ctx_put(struct amdgpu_ctx *ctx)
453efa246c0Sriastradh {
454efa246c0Sriastradh 	if (ctx == NULL)
455efa246c0Sriastradh 		return -EINVAL;
456efa246c0Sriastradh 
457efa246c0Sriastradh 	kref_put(&ctx->refcount, amdgpu_ctx_do_release);
458efa246c0Sriastradh 	return 0;
459efa246c0Sriastradh }
460efa246c0Sriastradh 
amdgpu_ctx_add_fence(struct amdgpu_ctx * ctx,struct drm_sched_entity * entity,struct dma_fence * fence,uint64_t * handle)46141ec0267Sriastradh void amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx,
46241ec0267Sriastradh 			  struct drm_sched_entity *entity,
46341ec0267Sriastradh 			  struct dma_fence *fence, uint64_t* handle)
464efa246c0Sriastradh {
46541ec0267Sriastradh 	struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity);
466*8e26f2b9Sriastradh 	uint64_t seq;
46741ec0267Sriastradh 	struct dma_fence *other = NULL;
468efa246c0Sriastradh 	unsigned idx = 0;
469efa246c0Sriastradh 
470*8e26f2b9Sriastradh 	spin_lock(&ctx->ring_lock);
471*8e26f2b9Sriastradh 	seq = centity->sequence;
47241ec0267Sriastradh 	idx = seq & (amdgpu_sched_jobs - 1);
47341ec0267Sriastradh 	other = centity->fences[idx];
47441ec0267Sriastradh 	if (other)
47541ec0267Sriastradh 		BUG_ON(!dma_fence_is_signaled(other));
476efa246c0Sriastradh 
47741ec0267Sriastradh 	dma_fence_get(fence);
47841ec0267Sriastradh 	centity->fences[idx] = fence;
47941ec0267Sriastradh 	centity->sequence++;
480efa246c0Sriastradh 	spin_unlock(&ctx->ring_lock);
481efa246c0Sriastradh 
48241ec0267Sriastradh 	dma_fence_put(other);
48341ec0267Sriastradh 	if (handle)
48441ec0267Sriastradh 		*handle = seq;
485efa246c0Sriastradh }
486efa246c0Sriastradh 
amdgpu_ctx_get_fence(struct amdgpu_ctx * ctx,struct drm_sched_entity * entity,uint64_t seq)48741ec0267Sriastradh struct dma_fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx,
48841ec0267Sriastradh 				       struct drm_sched_entity *entity,
48941ec0267Sriastradh 				       uint64_t seq)
490efa246c0Sriastradh {
49141ec0267Sriastradh 	struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity);
49241ec0267Sriastradh 	struct dma_fence *fence;
493efa246c0Sriastradh 
494efa246c0Sriastradh 	spin_lock(&ctx->ring_lock);
495efa246c0Sriastradh 
49641ec0267Sriastradh 	if (seq == ~0ull)
49741ec0267Sriastradh 		seq = centity->sequence - 1;
49841ec0267Sriastradh 
49941ec0267Sriastradh 	if (seq >= centity->sequence) {
500efa246c0Sriastradh 		spin_unlock(&ctx->ring_lock);
501efa246c0Sriastradh 		return ERR_PTR(-EINVAL);
502efa246c0Sriastradh 	}
503efa246c0Sriastradh 
504efa246c0Sriastradh 
50541ec0267Sriastradh 	if (seq + amdgpu_sched_jobs < centity->sequence) {
506efa246c0Sriastradh 		spin_unlock(&ctx->ring_lock);
507efa246c0Sriastradh 		return NULL;
508efa246c0Sriastradh 	}
509efa246c0Sriastradh 
51041ec0267Sriastradh 	fence = dma_fence_get(centity->fences[seq & (amdgpu_sched_jobs - 1)]);
511efa246c0Sriastradh 	spin_unlock(&ctx->ring_lock);
512efa246c0Sriastradh 
513efa246c0Sriastradh 	return fence;
514efa246c0Sriastradh }
515efa246c0Sriastradh 
amdgpu_ctx_priority_override(struct amdgpu_ctx * ctx,enum drm_sched_priority priority)51641ec0267Sriastradh void amdgpu_ctx_priority_override(struct amdgpu_ctx *ctx,
51741ec0267Sriastradh 				  enum drm_sched_priority priority)
51841ec0267Sriastradh {
51941ec0267Sriastradh 	enum drm_sched_priority ctx_prio;
52041ec0267Sriastradh 	unsigned i, j;
52141ec0267Sriastradh 
52241ec0267Sriastradh 	ctx->override_priority = priority;
52341ec0267Sriastradh 
52441ec0267Sriastradh 	ctx_prio = (ctx->override_priority == DRM_SCHED_PRIORITY_UNSET) ?
52541ec0267Sriastradh 			ctx->init_priority : ctx->override_priority;
52641ec0267Sriastradh 	for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
52741ec0267Sriastradh 		for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) {
52841ec0267Sriastradh 			struct drm_sched_entity *entity;
52941ec0267Sriastradh 
53041ec0267Sriastradh 			if (!ctx->entities[i][j])
53141ec0267Sriastradh 				continue;
53241ec0267Sriastradh 
53341ec0267Sriastradh 			entity = &ctx->entities[i][j]->entity;
53441ec0267Sriastradh 			drm_sched_entity_set_priority(entity, ctx_prio);
53541ec0267Sriastradh 		}
53641ec0267Sriastradh 	}
53741ec0267Sriastradh }
53841ec0267Sriastradh 
amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx * ctx,struct drm_sched_entity * entity)53941ec0267Sriastradh int amdgpu_ctx_wait_prev_fence(struct amdgpu_ctx *ctx,
54041ec0267Sriastradh 			       struct drm_sched_entity *entity)
54141ec0267Sriastradh {
54241ec0267Sriastradh 	struct amdgpu_ctx_entity *centity = to_amdgpu_ctx_entity(entity);
54341ec0267Sriastradh 	struct dma_fence *other;
54441ec0267Sriastradh 	unsigned idx;
54541ec0267Sriastradh 	long r;
54641ec0267Sriastradh 
54741ec0267Sriastradh 	spin_lock(&ctx->ring_lock);
54841ec0267Sriastradh 	idx = centity->sequence & (amdgpu_sched_jobs - 1);
54941ec0267Sriastradh 	other = dma_fence_get(centity->fences[idx]);
55041ec0267Sriastradh 	spin_unlock(&ctx->ring_lock);
55141ec0267Sriastradh 
55241ec0267Sriastradh 	if (!other)
55341ec0267Sriastradh 		return 0;
55441ec0267Sriastradh 
55541ec0267Sriastradh 	r = dma_fence_wait(other, true);
55641ec0267Sriastradh 	if (r < 0 && r != -ERESTARTSYS)
55741ec0267Sriastradh 		DRM_ERROR("Error (%ld) waiting for fence!\n", r);
55841ec0267Sriastradh 
55941ec0267Sriastradh 	dma_fence_put(other);
56041ec0267Sriastradh 	return r;
56141ec0267Sriastradh }
56241ec0267Sriastradh 
amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr * mgr)563efa246c0Sriastradh void amdgpu_ctx_mgr_init(struct amdgpu_ctx_mgr *mgr)
564efa246c0Sriastradh {
565efa246c0Sriastradh 	mutex_init(&mgr->lock);
566efa246c0Sriastradh 	idr_init(&mgr->ctx_handles);
567efa246c0Sriastradh }
568efa246c0Sriastradh 
amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr * mgr,long timeout)56941ec0267Sriastradh long amdgpu_ctx_mgr_entity_flush(struct amdgpu_ctx_mgr *mgr, long timeout)
57041ec0267Sriastradh {
57141ec0267Sriastradh 	struct amdgpu_ctx *ctx;
57241ec0267Sriastradh 	struct idr *idp;
57341ec0267Sriastradh 	uint32_t id, i, j;
57441ec0267Sriastradh 
57541ec0267Sriastradh 	idp = &mgr->ctx_handles;
57641ec0267Sriastradh 
57741ec0267Sriastradh 	mutex_lock(&mgr->lock);
57841ec0267Sriastradh 	idr_for_each_entry(idp, ctx, id) {
57941ec0267Sriastradh 		for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
58041ec0267Sriastradh 			for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) {
58141ec0267Sriastradh 				struct drm_sched_entity *entity;
58241ec0267Sriastradh 
58341ec0267Sriastradh 				if (!ctx->entities[i][j])
58441ec0267Sriastradh 					continue;
58541ec0267Sriastradh 
58641ec0267Sriastradh 				entity = &ctx->entities[i][j]->entity;
58741ec0267Sriastradh 				timeout = drm_sched_entity_flush(entity, timeout);
58841ec0267Sriastradh 			}
58941ec0267Sriastradh 		}
59041ec0267Sriastradh 	}
59141ec0267Sriastradh 	mutex_unlock(&mgr->lock);
59241ec0267Sriastradh 	return timeout;
59341ec0267Sriastradh }
59441ec0267Sriastradh 
amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr * mgr)59541ec0267Sriastradh void amdgpu_ctx_mgr_entity_fini(struct amdgpu_ctx_mgr *mgr)
59641ec0267Sriastradh {
59741ec0267Sriastradh 	struct amdgpu_ctx *ctx;
59841ec0267Sriastradh 	struct idr *idp;
59941ec0267Sriastradh 	uint32_t id, i, j;
60041ec0267Sriastradh 
60141ec0267Sriastradh 	idp = &mgr->ctx_handles;
60241ec0267Sriastradh 
60341ec0267Sriastradh 	idr_for_each_entry(idp, ctx, id) {
60441ec0267Sriastradh 		if (kref_read(&ctx->refcount) != 1) {
60541ec0267Sriastradh 			DRM_ERROR("ctx %p is still alive\n", ctx);
60641ec0267Sriastradh 			continue;
60741ec0267Sriastradh 		}
60841ec0267Sriastradh 
60941ec0267Sriastradh 		for (i = 0; i < AMDGPU_HW_IP_NUM; ++i) {
61041ec0267Sriastradh 			for (j = 0; j < amdgpu_ctx_num_entities[i]; ++j) {
61141ec0267Sriastradh 				struct drm_sched_entity *entity;
61241ec0267Sriastradh 
61341ec0267Sriastradh 				if (!ctx->entities[i][j])
61441ec0267Sriastradh 					continue;
61541ec0267Sriastradh 
61641ec0267Sriastradh 				entity = &ctx->entities[i][j]->entity;
61741ec0267Sriastradh 				drm_sched_entity_fini(entity);
61841ec0267Sriastradh 			}
61941ec0267Sriastradh 		}
62041ec0267Sriastradh 	}
62141ec0267Sriastradh }
62241ec0267Sriastradh 
amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr * mgr)623efa246c0Sriastradh void amdgpu_ctx_mgr_fini(struct amdgpu_ctx_mgr *mgr)
624efa246c0Sriastradh {
625efa246c0Sriastradh 	struct amdgpu_ctx *ctx;
626efa246c0Sriastradh 	struct idr *idp;
627efa246c0Sriastradh 	uint32_t id;
628efa246c0Sriastradh 
62941ec0267Sriastradh 	amdgpu_ctx_mgr_entity_fini(mgr);
63041ec0267Sriastradh 
631efa246c0Sriastradh 	idp = &mgr->ctx_handles;
632efa246c0Sriastradh 
633efa246c0Sriastradh 	idr_for_each_entry(idp, ctx, id) {
63441ec0267Sriastradh 		if (kref_put(&ctx->refcount, amdgpu_ctx_fini) != 1)
635efa246c0Sriastradh 			DRM_ERROR("ctx %p is still alive\n", ctx);
636efa246c0Sriastradh 	}
637efa246c0Sriastradh 
638efa246c0Sriastradh 	idr_destroy(&mgr->ctx_handles);
639efa246c0Sriastradh 	mutex_destroy(&mgr->lock);
640efa246c0Sriastradh }
64141ec0267Sriastradh 
amdgpu_ctx_init_sched(struct amdgpu_device * adev)64241ec0267Sriastradh void amdgpu_ctx_init_sched(struct amdgpu_device *adev)
64341ec0267Sriastradh {
64441ec0267Sriastradh 	int i, j;
64541ec0267Sriastradh 
64641ec0267Sriastradh 	for (i = 0; i < adev->gfx.num_gfx_rings; i++) {
64741ec0267Sriastradh 		adev->gfx.gfx_sched[i] = &adev->gfx.gfx_ring[i].sched;
64841ec0267Sriastradh 		adev->gfx.num_gfx_sched++;
64941ec0267Sriastradh 	}
65041ec0267Sriastradh 
65141ec0267Sriastradh 	for (i = 0; i < adev->gfx.num_compute_rings; i++) {
65241ec0267Sriastradh 		adev->gfx.compute_sched[i] = &adev->gfx.compute_ring[i].sched;
65341ec0267Sriastradh 		adev->gfx.num_compute_sched++;
65441ec0267Sriastradh 	}
65541ec0267Sriastradh 
65641ec0267Sriastradh 	for (i = 0; i < adev->sdma.num_instances; i++) {
65741ec0267Sriastradh 		adev->sdma.sdma_sched[i] = &adev->sdma.instance[i].ring.sched;
65841ec0267Sriastradh 		adev->sdma.num_sdma_sched++;
65941ec0267Sriastradh 	}
66041ec0267Sriastradh 
66141ec0267Sriastradh 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
66241ec0267Sriastradh 		if (adev->vcn.harvest_config & (1 << i))
66341ec0267Sriastradh 			continue;
66441ec0267Sriastradh 		adev->vcn.vcn_dec_sched[adev->vcn.num_vcn_dec_sched++] =
66541ec0267Sriastradh 			&adev->vcn.inst[i].ring_dec.sched;
66641ec0267Sriastradh 	}
66741ec0267Sriastradh 
66841ec0267Sriastradh 	for (i = 0; i < adev->vcn.num_vcn_inst; ++i) {
66941ec0267Sriastradh 		if (adev->vcn.harvest_config & (1 << i))
67041ec0267Sriastradh 			continue;
67141ec0267Sriastradh 		for (j = 0; j < adev->vcn.num_enc_rings; ++j)
67241ec0267Sriastradh 			adev->vcn.vcn_enc_sched[adev->vcn.num_vcn_enc_sched++] =
67341ec0267Sriastradh 				&adev->vcn.inst[i].ring_enc[j].sched;
67441ec0267Sriastradh 	}
67541ec0267Sriastradh 
67641ec0267Sriastradh 	for (i = 0; i < adev->jpeg.num_jpeg_inst; ++i) {
67741ec0267Sriastradh 		if (adev->jpeg.harvest_config & (1 << i))
67841ec0267Sriastradh 			continue;
67941ec0267Sriastradh 		adev->jpeg.jpeg_sched[adev->jpeg.num_jpeg_sched++] =
68041ec0267Sriastradh 			&adev->jpeg.inst[i].ring_dec.sched;
68141ec0267Sriastradh 	}
68241ec0267Sriastradh }
683