1 // SPDX-License-Identifier: GPL-2.0 OR MIT 2 /* Copyright 2018-2019 Qiang Yu <yuq825@gmail.com> */ 3 4 #include <linux/slab.h> 5 6 #include "lima_device.h" 7 #include "lima_ctx.h" 8 9 int lima_ctx_create(struct lima_device *dev, struct lima_ctx_mgr *mgr, u32 *id) 10 { 11 struct lima_ctx *ctx; 12 int i, err; 13 14 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 15 if (!ctx) 16 return -ENOMEM; 17 ctx->dev = dev; 18 ctx->mgr = mgr; 19 kref_init(&ctx->refcnt); 20 21 for (i = 0; i < lima_pipe_num; i++) { 22 err = lima_sched_context_init(dev->pipe + i, ctx->context + i, &ctx->guilty); 23 if (err) 24 goto err_out0; 25 } 26 27 err = xa_alloc(&mgr->handles, id, ctx, xa_limit_32b, GFP_KERNEL); 28 if (err < 0) 29 goto err_out0; 30 31 ctx->pid = task_pid_nr(current); 32 get_task_comm(ctx->pname, current); 33 34 return 0; 35 36 err_out0: 37 for (i--; i >= 0; i--) 38 lima_sched_context_fini(dev->pipe + i, ctx->context + i); 39 kfree(ctx); 40 return err; 41 } 42 43 static void lima_ctx_do_release(struct kref *ref) 44 { 45 struct lima_ctx *ctx = container_of(ref, struct lima_ctx, refcnt); 46 struct lima_ctx_mgr *mgr = ctx->mgr; 47 int i; 48 49 for (i = 0; i < lima_pipe_num; i++) { 50 struct lima_sched_context *context = &ctx->context[i]; 51 struct drm_sched_entity *entity = &context->base; 52 53 mgr->elapsed_ns[i] += entity->elapsed_ns; 54 55 lima_sched_context_fini(ctx->dev->pipe + i, ctx->context + i); 56 } 57 kfree(ctx); 58 } 59 60 int lima_ctx_free(struct lima_ctx_mgr *mgr, u32 id) 61 { 62 struct lima_ctx *ctx; 63 int ret = 0; 64 65 mutex_lock(&mgr->lock); 66 ctx = xa_erase(&mgr->handles, id); 67 if (ctx) 68 kref_put(&ctx->refcnt, lima_ctx_do_release); 69 else 70 ret = -EINVAL; 71 mutex_unlock(&mgr->lock); 72 return ret; 73 } 74 75 struct lima_ctx *lima_ctx_get(struct lima_ctx_mgr *mgr, u32 id) 76 { 77 struct lima_ctx *ctx; 78 79 mutex_lock(&mgr->lock); 80 ctx = xa_load(&mgr->handles, id); 81 if (ctx) 82 kref_get(&ctx->refcnt); 83 mutex_unlock(&mgr->lock); 84 return ctx; 85 } 86 87 void lima_ctx_put(struct lima_ctx *ctx) 88 { 89 kref_put(&ctx->refcnt, lima_ctx_do_release); 90 } 91 92 void lima_ctx_mgr_init(struct lima_ctx_mgr *mgr) 93 { 94 mutex_init(&mgr->lock); 95 xa_init_flags(&mgr->handles, XA_FLAGS_ALLOC); 96 } 97 98 void lima_ctx_mgr_fini(struct lima_ctx_mgr *mgr) 99 { 100 struct lima_ctx *ctx; 101 unsigned long id; 102 103 xa_for_each(&mgr->handles, id, ctx) { 104 kref_put(&ctx->refcnt, lima_ctx_do_release); 105 } 106 107 xa_destroy(&mgr->handles); 108 mutex_destroy(&mgr->lock); 109 } 110 111 void lima_ctx_mgr_usage(struct lima_ctx_mgr *mgr, u64 usage[lima_pipe_num]) 112 { 113 struct lima_ctx *ctx; 114 unsigned long id; 115 116 for (int i = 0; i < lima_pipe_num; i++) 117 usage[i] = mgr->elapsed_ns[i]; 118 119 mutex_lock(&mgr->lock); 120 xa_for_each(&mgr->handles, id, ctx) { 121 for (int i = 0; i < lima_pipe_num; i++) { 122 struct lima_sched_context *context = &ctx->context[i]; 123 struct drm_sched_entity *entity = &context->base; 124 125 usage[i] += entity->elapsed_ns; 126 } 127 } 128 mutex_unlock(&mgr->lock); 129 } 130