blob: 7ac7accfda3a3d357253d7caae74420d1d22fd0d [file] [log] [blame]
/*
* 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);
}