// SPDX-License-Identifier: GPL-2.0 OR MIT /* Copyright 2018-2019 Qiang Yu */ #include #include "lima_device.h" #include "lima_ctx.h" int lima_ctx_create(struct lima_device *dev, struct lima_ctx_mgr *mgr, u32 *id) { struct lima_ctx *ctx; int i, err; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; ctx->dev = dev; ctx->mgr = mgr; kref_init(&ctx->refcnt); for (i = 0; i < lima_pipe_num; i++) { err = lima_sched_context_init(dev->pipe + i, ctx->context + i, &ctx->guilty); if (err) goto err_out0; } err = xa_alloc(&mgr->handles, id, ctx, xa_limit_32b, GFP_KERNEL); if (err < 0) goto err_out0; ctx->pid = task_pid_nr(current); get_task_comm(ctx->pname, current); return 0; err_out0: for (i--; i >= 0; i--) lima_sched_context_fini(dev->pipe + i, ctx->context + i); kfree(ctx); return err; } static void lima_ctx_do_release(struct kref *ref) { struct lima_ctx *ctx = container_of(ref, struct lima_ctx, refcnt); struct lima_ctx_mgr *mgr = ctx->mgr; int i; for (i = 0; i < lima_pipe_num; i++) { struct lima_sched_context *context = &ctx->context[i]; struct drm_sched_entity *entity = &context->base; mgr->elapsed_ns[i] += entity->elapsed_ns; lima_sched_context_fini(ctx->dev->pipe + i, ctx->context + i); } kfree(ctx); } int lima_ctx_free(struct lima_ctx_mgr *mgr, u32 id) { struct lima_ctx *ctx; int ret = 0; mutex_lock(&mgr->lock); ctx = xa_erase(&mgr->handles, id); if (ctx) kref_put(&ctx->refcnt, lima_ctx_do_release); else ret = -EINVAL; mutex_unlock(&mgr->lock); return ret; } struct lima_ctx *lima_ctx_get(struct lima_ctx_mgr *mgr, u32 id) { struct lima_ctx *ctx; mutex_lock(&mgr->lock); ctx = xa_load(&mgr->handles, id); if (ctx) kref_get(&ctx->refcnt); mutex_unlock(&mgr->lock); return ctx; } void lima_ctx_put(struct lima_ctx *ctx) { kref_put(&ctx->refcnt, lima_ctx_do_release); } void lima_ctx_mgr_init(struct lima_ctx_mgr *mgr) { mutex_init(&mgr->lock); xa_init_flags(&mgr->handles, XA_FLAGS_ALLOC); } void lima_ctx_mgr_fini(struct lima_ctx_mgr *mgr) { struct lima_ctx *ctx; unsigned long id; xa_for_each(&mgr->handles, id, ctx) { kref_put(&ctx->refcnt, lima_ctx_do_release); } xa_destroy(&mgr->handles); mutex_destroy(&mgr->lock); } void lima_ctx_mgr_usage(struct lima_ctx_mgr *mgr, u64 usage[lima_pipe_num]) { struct lima_ctx *ctx; unsigned long id; for (int i = 0; i < lima_pipe_num; i++) usage[i] = mgr->elapsed_ns[i]; mutex_lock(&mgr->lock); xa_for_each(&mgr->handles, id, ctx) { for (int i = 0; i < lima_pipe_num; i++) { struct lima_sched_context *context = &ctx->context[i]; struct drm_sched_entity *entity = &context->base; usage[i] += entity->elapsed_ns; } } mutex_unlock(&mgr->lock); }