| /* |
| * Copyright(c) 2018 NXP. All rights reserved. |
| * |
| * This file is provided under a dual BSD/GPLv2 license. When using or |
| * redistributing this file, you may do so under either license. |
| * |
| * vpu_event_msg.c |
| * |
| * Author Ming Qian<ming.qian@nxp.com> |
| */ |
| #define TAG "[VPU Encoder Msg]\t " |
| #include <linux/kernel.h> |
| #include <linux/list.h> |
| #include <linux/vmalloc.h> |
| |
| #include "vpu_encoder_b0.h" |
| #include "vpu_event_msg.h" |
| |
| static atomic64_t total_ext_data = ATOMIC64_INIT(0); |
| |
| static struct vpu_event_msg *alloc_event_msg(void) |
| { |
| struct vpu_event_msg *msg = NULL; |
| |
| msg = vzalloc(sizeof(*msg)); |
| |
| return msg; |
| } |
| |
| static void free_event_msg(struct vpu_event_msg *msg) |
| { |
| if (!msg) |
| return; |
| |
| free_msg_ext_buffer(msg); |
| VPU_SAFE_RELEASE(msg, vfree); |
| } |
| |
| static void set_msg_count(struct vpu_ctx *ctx, unsigned long count) |
| { |
| struct vpu_attr *attr = get_vpu_ctx_attr(ctx); |
| |
| if (attr) |
| attr->msg_count = count; |
| } |
| |
| static void inc_msg_count(struct vpu_ctx *ctx) |
| { |
| struct vpu_attr *attr = get_vpu_ctx_attr(ctx); |
| |
| if (attr) |
| attr->msg_count++; |
| } |
| |
| static void dec_msg_count(struct vpu_ctx *ctx) |
| { |
| struct vpu_attr *attr = get_vpu_ctx_attr(ctx); |
| |
| if (attr) |
| attr->msg_count--; |
| } |
| |
| static bool is_msg_count_full(struct vpu_ctx *ctx) |
| { |
| struct vpu_attr *attr = get_vpu_ctx_attr(ctx); |
| |
| if (!attr) |
| return false; |
| if (attr->msg_count > MSG_COUNT_THD) |
| return true; |
| return false; |
| } |
| |
| void cleanup_ctx_msg_queue(struct vpu_ctx *ctx) |
| { |
| struct vpu_event_msg *msg; |
| struct vpu_event_msg *tmp; |
| |
| WARN_ON(!ctx); |
| |
| vpu_log_func(); |
| mutex_lock(&ctx->instance_mutex); |
| list_for_each_entry_safe(msg, tmp, &ctx->msg_q, list) { |
| list_del_init(&msg->list); |
| vpu_dbg(LVL_MSG, "drop core[%d] ctx[%d] msg:[%d]\n", |
| ctx->core_dev->id, ctx->str_index, msg->msgid); |
| VPU_SAFE_RELEASE(msg, free_event_msg); |
| dec_msg_count(ctx); |
| } |
| |
| list_for_each_entry_safe(msg, tmp, &ctx->idle_q, list) { |
| list_del_init(&msg->list); |
| VPU_SAFE_RELEASE(msg, free_event_msg); |
| dec_msg_count(ctx); |
| } |
| mutex_unlock(&ctx->instance_mutex); |
| } |
| |
| static int increase_idle_msg(struct vpu_ctx *ctx, u32 count) |
| { |
| int i; |
| |
| for (i = 0; i < count; i++) { |
| struct vpu_event_msg *msg = alloc_event_msg(); |
| |
| if (!msg) |
| continue; |
| list_add_tail(&msg->list, &ctx->idle_q); |
| inc_msg_count(ctx); |
| } |
| |
| return 0; |
| } |
| |
| int init_ctx_msg_queue(struct vpu_ctx *ctx) |
| { |
| WARN_ON(!ctx); |
| if (!ctx) |
| return -EINVAL; |
| |
| vpu_log_func(); |
| mutex_lock(&ctx->instance_mutex); |
| |
| set_msg_count(ctx, 0); |
| INIT_LIST_HEAD(&ctx->msg_q); |
| INIT_LIST_HEAD(&ctx->idle_q); |
| |
| mutex_unlock(&ctx->instance_mutex); |
| |
| return 0; |
| } |
| |
| struct vpu_event_msg *get_idle_msg(struct vpu_ctx *ctx) |
| { |
| struct vpu_event_msg *msg = NULL; |
| |
| WARN_ON(!ctx); |
| |
| mutex_lock(&ctx->instance_mutex); |
| if (list_empty(&ctx->idle_q)) |
| increase_idle_msg(ctx, 1); |
| |
| msg = list_first_entry(&ctx->idle_q, struct vpu_event_msg, list); |
| if (msg) |
| list_del_init(&msg->list); |
| |
| mutex_unlock(&ctx->instance_mutex); |
| |
| return msg; |
| } |
| |
| void put_idle_msg(struct vpu_ctx *ctx, struct vpu_event_msg *msg) |
| { |
| WARN_ON(!ctx); |
| |
| if (!ctx || !msg) |
| return; |
| |
| free_msg_ext_buffer(msg); |
| |
| mutex_lock(&ctx->instance_mutex); |
| if (is_msg_count_full(ctx)) { |
| VPU_SAFE_RELEASE(msg, free_event_msg); |
| dec_msg_count(ctx); |
| } else { |
| list_add_tail(&msg->list, &ctx->idle_q); |
| } |
| mutex_unlock(&ctx->instance_mutex); |
| } |
| |
| struct vpu_event_msg *pop_event_msg(struct vpu_ctx *ctx) |
| { |
| struct vpu_event_msg *msg = NULL; |
| |
| WARN_ON(!ctx); |
| |
| mutex_lock(&ctx->instance_mutex); |
| if (list_empty(&ctx->msg_q)) |
| goto exit; |
| |
| msg = list_first_entry(&ctx->msg_q, struct vpu_event_msg, list); |
| if (msg) |
| list_del_init(&msg->list); |
| |
| exit: |
| mutex_unlock(&ctx->instance_mutex); |
| return msg; |
| } |
| |
| void push_back_event_msg(struct vpu_ctx *ctx, struct vpu_event_msg *msg) |
| { |
| WARN_ON(!ctx); |
| |
| if (!ctx || !msg) |
| return; |
| |
| mutex_lock(&ctx->instance_mutex); |
| list_add_tail(&msg->list, &ctx->msg_q); |
| mutex_unlock(&ctx->instance_mutex); |
| } |
| |
| int alloc_msg_ext_buffer(struct vpu_event_msg *msg, u32 number) |
| { |
| WARN_ON(!msg); |
| |
| if (!msg || !number) |
| return -EINVAL; |
| |
| msg->ext_data = vzalloc(number * sizeof(u32)); |
| if (!msg->ext_data) |
| return -ENOMEM; |
| msg->number = number; |
| |
| atomic64_add(number, &total_ext_data); |
| vpu_dbg(LVL_MSG, "++++alloc %d msg ext data: %lld\n", |
| number, get_total_ext_data_number()); |
| |
| return 0; |
| } |
| |
| void free_msg_ext_buffer(struct vpu_event_msg *msg) |
| { |
| WARN_ON(!msg); |
| |
| if (!msg || !msg->ext_data) |
| return; |
| |
| atomic64_sub(msg->number, &total_ext_data); |
| VPU_SAFE_RELEASE(msg->ext_data, vfree); |
| vpu_dbg(LVL_MSG, "----free %d msg ext data: %lld\n", |
| msg->number, get_total_ext_data_number()); |
| } |
| |
| long long get_total_ext_data_number(void) |
| { |
| return atomic64_read(&total_ext_data); |
| } |