blob: 50aaf0ca8d710217e50074ea64b53e88166eb1b2 [file] [log] [blame]
/*
* Samsung Exynos SoC series VPU driver
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/sched/rt.h>
#include <linux/bug.h>
#include "vpu-framemgr.h"
#include "vpu-device.h"
#include "vpu-graphmgr.h"
#define TIMER_CHECK_POINT(v) graphmgr->tick_pos = v
#define GRAPH_CHECK_POINT(v) graphmgr->sched_pos = v
static void __vpu_gframe_s_free(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
gframe->state = VPU_GFRAME_STATE_FREE;
list_add_tail(&gframe->list, &graphmgr->gfre_list);
graphmgr->gfre_cnt++;
}
static void __vpu_gframe_free_head(struct vpu_graphmgr *graphmgr, struct vpu_gframe **gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
if (graphmgr->gfre_cnt)
*gframe = container_of(graphmgr->gfre_list.next, struct vpu_gframe, list);
else
*gframe = NULL;
}
static void __vpu_gframe_s_ready(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
gframe->state = VPU_GFRAME_STATE_FREE;
list_add_tail(&gframe->list, &graphmgr->grdy_list);
graphmgr->grdy_cnt++;
}
static void __vpu_gframe_g_ready(struct vpu_graphmgr *graphmgr,
struct vpu_gframe **gframe)
{
if (graphmgr->grdy_cnt &&
(*gframe = container_of(graphmgr->grdy_list.next, struct vpu_gframe, list))) {
list_del(&(*gframe)->list);
graphmgr->grdy_cnt--;
(*gframe)->state = VPU_FRAME_STATE_INVALID;
} else {
*gframe = NULL;
}
}
static void __vpu_gframe_s_request(struct vpu_graphmgr *graphmgr,
struct vpu_gframe *prev,
struct vpu_gframe *gframe,
struct vpu_gframe *next)
{
gframe->state = VPU_GFRAME_STATE_REQUEST;
if (prev && next) {
next->list.prev = &gframe->list;
gframe->list.next = &next->list;
gframe->list.prev = &prev->list;
prev->list.next = &gframe->list;
} else if (prev) {
list_add_tail(&gframe->list, &graphmgr->greq_list);
} else {
list_add(&gframe->list, &graphmgr->greq_list);
}
graphmgr->greq_cnt++;
}
static void __vpu_gframe_s_alloc(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
gframe->state = VPU_GFRAME_STATE_ALLOC;
list_add_tail(&gframe->list, &graphmgr->galc_list);
graphmgr->galc_cnt++;
}
void __vpu_gframe_s_process(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
gframe->state = VPU_GFRAME_STATE_PROCESS;
list_add_tail(&gframe->list, &graphmgr->gpro_list);
graphmgr->gpro_cnt++;
}
static void __vpu_gframe_s_complete(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
gframe->state = VPU_GFRAME_STATE_COMPLETE;
list_add_tail(&gframe->list, &graphmgr->gcom_list);
graphmgr->gcom_cnt++;
}
void __vpu_gframe_trans_fre_to_rdy(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->gfre_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_FREE);
list_del(&gframe->list);
graphmgr->gfre_cnt--;
__vpu_gframe_s_ready(graphmgr, gframe);
}
void __vpu_gframe_trans_rdy_to_fre(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->grdy_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_READY);
list_del(&gframe->list);
graphmgr->grdy_cnt--;
__vpu_gframe_s_free(graphmgr, gframe);
}
void __vpu_gframe_trans_req_to_alc(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->greq_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_REQUEST);
list_del(&gframe->list);
graphmgr->greq_cnt--;
__vpu_gframe_s_alloc(graphmgr, gframe);
}
void __vpu_gframe_trans_req_to_pro(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->greq_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_REQUEST);
list_del(&gframe->list);
graphmgr->greq_cnt--;
__vpu_gframe_s_process(graphmgr, gframe);
}
void __vpu_gframe_trans_req_to_fre(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->greq_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_REQUEST);
list_del(&gframe->list);
graphmgr->greq_cnt--;
__vpu_gframe_s_free(graphmgr, gframe);
}
void __vpu_gframe_trans_alc_to_pro(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->galc_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_ALLOC);
list_del(&gframe->list);
graphmgr->galc_cnt--;
__vpu_gframe_s_process(graphmgr, gframe);
}
void __vpu_gframe_trans_alc_to_fre(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->galc_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_ALLOC);
list_del(&gframe->list);
graphmgr->galc_cnt--;
__vpu_gframe_s_free(graphmgr, gframe);
}
static void __vpu_gframe_trans_pro_to_com(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->gpro_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_PROCESS);
list_del(&gframe->list);
graphmgr->gpro_cnt--;
__vpu_gframe_s_complete(graphmgr, gframe);
}
void __vpu_gframe_trans_pro_to_fre(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->gpro_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_PROCESS);
list_del(&gframe->list);
graphmgr->gpro_cnt--;
__vpu_gframe_s_free(graphmgr, gframe);
}
static void __vpu_gframe_trans_com_to_fre(struct vpu_graphmgr *graphmgr, struct vpu_gframe *gframe)
{
BUG_ON(!graphmgr);
BUG_ON(!gframe);
BUG_ON(!graphmgr->gcom_cnt);
BUG_ON(gframe->state != VPU_GFRAME_STATE_COMPLETE);
list_del(&gframe->list);
graphmgr->gcom_cnt--;
__vpu_gframe_s_free(graphmgr, gframe);
}
void vpu_gframe_print(struct vpu_graphmgr *graphmgr)
{
DLOG_INIT();
struct vpu_gframe *gframe, *gtemp;
BUG_ON(!graphmgr);
DLOG("READY LIST(%d) :", graphmgr->grdy_cnt);
list_for_each_entry_safe(gframe, gtemp, &graphmgr->grdy_list, list) {
BUG_ON(!gframe->graph);
BUG_ON(!gframe->frame);
DLOG(" %2d(%d, %d)", gframe->graph->id, gframe->index, gframe->frame->id);
}
vpu_info("%s\n", DLOG_OUT());
DLOG("REQUEST LIST(%d) :", graphmgr->greq_cnt);
list_for_each_entry_safe(gframe, gtemp, &graphmgr->greq_list, list) {
BUG_ON(!gframe->graph);
BUG_ON(!gframe->frame);
DLOG(" %2d(%d, %d)", gframe->graph->id, gframe->index, gframe->frame->id);
}
vpu_info("%s\n", DLOG_OUT());
DLOG("ALLOC LIST(%d) :", graphmgr->galc_cnt);
list_for_each_entry_safe(gframe, gtemp, &graphmgr->gpro_list, list) {
BUG_ON(!gframe->graph);
BUG_ON(!gframe->frame);
DLOG(" %2d(%d, %d)", gframe->graph->id, gframe->index, gframe->frame->id);
}
vpu_info("%s\n", DLOG_OUT());
DLOG("PROCESS LIST(%d) :", graphmgr->gpro_cnt);
list_for_each_entry_safe(gframe, gtemp, &graphmgr->gpro_list, list) {
BUG_ON(!gframe->graph);
BUG_ON(!gframe->frame);
DLOG(" %2d(%d, %d)", gframe->graph->id, gframe->index, gframe->frame->id);
}
vpu_info("%s\n", DLOG_OUT());
DLOG("COMPLETE LIST(%d) :", graphmgr->gcom_cnt);
list_for_each_entry_safe(gframe, gtemp, &graphmgr->gcom_list, list) {
BUG_ON(!gframe->graph);
BUG_ON(!gframe->frame);
DLOG(" %2d(%d, %d)", gframe->graph->id, gframe->index, gframe->frame->id);
}
vpu_info("%s\n", DLOG_OUT());
}
static int __vpu_itf_enum(struct vpu_interface *interface,
struct vpu_graph *graph)
{
int ret = 0;
unsigned long flags;
struct vpu_framemgr *iframemgr;
struct vpu_frame *iframe;
BUG_ON(!interface);
BUG_ON(!graph);
iframemgr = &interface->framemgr;
ret = vpu_hw_enum(interface);
if (ret) {
vpu_err("vpu_hw_enum is fail(%d)\n", ret);
goto p_err;
}
framemgr_e_barrier_irqs(iframemgr, 0, flags);
vpu_frame_pick_fre_to_req(iframemgr, &iframe);
framemgr_x_barrier_irqr(iframemgr, 0, flags);
if (!iframe) {
vpu_err("iframe is NULL\n");
ret = -ENOMEM;
goto p_err;
}
iframe->id = 0;
iframe->lock = &graph->local_lock;
iframe->findex = VPU_MAX_FRAME;
iframe->gindex = VPU_MAX_GFRAME;
iframe->message = VPU_FRAME_INIT;
iframe->param0 = 0;
iframe->param1 = graph->id;
iframe->param2 = 0;
iframe->param3 = 0;
ret = vpu_hw_init(interface, iframe);
if (ret) {
vpu_err("vpu_hw_init is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
static int __vpu_itf_create(struct vpu_interface *interface,
struct vpu_graph *graph)
{
int ret = 0;
unsigned long flags;
struct vpu_framemgr *iframemgr;
struct vpu_frame *iframe;
struct vpuo_pu *pu, *temp;
struct vpu_mark_for_invoke_ext_mem_vec_ds mem_mark;
u32 i;
BUG_ON(!interface);
BUG_ON(!graph);
iframemgr = &interface->framemgr;
mem_mark.num_of_buffers = 0;
framemgr_e_barrier_irqs(iframemgr, 0, flags);
vpu_frame_pick_fre_to_req(iframemgr, &iframe);
framemgr_x_barrier_irqr(iframemgr, 0, flags);
if (!iframe) {
vpu_err("iframe is NULL\n");
ret = -ENOMEM;
goto p_err;
}
#ifdef DBG_TIMEMEASURE
vpu_get_timestamp(&iframe->time[VPU_TMP_REQUEST]);
#endif
if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) {
for (i = 0; i < graph->iobuffer_cnt; ++i) {
mem_mark.external_mem_index[i] = graph->iobuffer_idx[i];
mem_mark.num_of_buffers++;
}
goto p_skip_primitive;
}
list_for_each_entry_safe(pu, temp, &graph->inleaf_list, gleaf_entry) {
for (i = 0; i < pu->buffer_cnt; ++i) {
if (!pu->buffer_ptr[i])
continue;
if (mem_mark.num_of_buffers >= VPUL_MAX_MAPS_DESC) {
vpu_err("mem_mark.num_of_buffers is over1(%d)\n", mem_mark.num_of_buffers);
break;
}
if (!pu->buffer_shm[i]) {
mem_mark.external_mem_index[mem_mark.num_of_buffers] = pu->buffer_idx[i];
mem_mark.num_of_buffers++;
}
}
}
list_for_each_entry_safe(pu, temp, &graph->otleaf_list, gleaf_entry) {
for (i = 0; i < pu->buffer_cnt; ++i) {
if (!pu->buffer_ptr[i])
continue;
if (mem_mark.num_of_buffers >= VPUL_MAX_MAPS_DESC) {
vpu_err("mem_mark.num_of_buffers is over2(%d)\n", mem_mark.num_of_buffers);
break;
}
if (!pu->buffer_shm[i]) {
mem_mark.external_mem_index[mem_mark.num_of_buffers] = pu->buffer_idx[i];
mem_mark.num_of_buffers++;
}
}
}
p_skip_primitive:
iframe->id = 0;
iframe->lock = &graph->local_lock;
iframe->findex = VPU_MAX_FRAME;
iframe->gindex = VPU_MAX_GFRAME;
iframe->message = VPU_FRAME_CREATE;
iframe->param0 = (ulong)graph->desc_mtask;
iframe->param1 = graph->id;
iframe->param2 = (ulong)&mem_mark;
iframe->param3 = 0;
ret = vpu_hw_create(interface, iframe);
if (ret) {
vpu_err("vpu_hw_create is fail(%d)\n", ret);
goto p_err;
}
#ifdef DBG_TIMEMEASURE
vpu_iinfo("[TM] C : %ldus, %ldus\n", graph,
VPU_TIME_IN_US(iframe->time[VPU_TMP_PROCESS]) -
VPU_TIME_IN_US(iframe->time[VPU_TMP_REQUEST]),
VPU_TIME_IN_US(iframe->time[VPU_TMP_DONE]) -
VPU_TIME_IN_US(iframe->time[VPU_TMP_PROCESS]));
#endif
p_err:
return ret;
}
static int __vpu_itf_destroy(struct vpu_interface *interface,
struct vpu_graph *graph)
{
int ret = 0;
unsigned long flags;
struct vpu_framemgr *iframemgr;
struct vpu_frame *iframe;
BUG_ON(!interface);
BUG_ON(!graph);
iframemgr = &interface->framemgr;
framemgr_e_barrier_irqs(iframemgr, 0, flags);
vpu_frame_pick_fre_to_req(iframemgr, &iframe);
framemgr_x_barrier_irqr(iframemgr, 0, flags);
if (!iframe) {
vpu_err("iframe is NULL\n");
ret = -ENOMEM;
goto p_err;
}
#ifdef DBG_TIMEMEASURE
vpu_get_timestamp(&iframe->time[VPU_TMP_REQUEST]);
#endif
iframe->id = 0;
iframe->lock = &graph->local_lock;
iframe->findex = VPU_MAX_FRAME;
iframe->gindex = VPU_MAX_GFRAME;
iframe->message = VPU_FRAME_DESTROY;
iframe->param0 = (ulong)graph->desc_mtask;
iframe->param1 = graph->id;
iframe->param2 = 0;
iframe->param3 = 0;
ret = vpu_hw_destroy(interface, iframe);
if (ret) {
vpu_err("vpu_hw_destory is fail(%d)\n", ret);
goto p_err;
}
#ifdef DBG_TIMEMEASURE
vpu_iinfo("[TM] D : %ldus, %ldus\n", graph,
VPU_TIME_IN_US(iframe->time[VPU_TMP_PROCESS]) -
VPU_TIME_IN_US(iframe->time[VPU_TMP_REQUEST]),
VPU_TIME_IN_US(iframe->time[VPU_TMP_DONE]) -
VPU_TIME_IN_US(iframe->time[VPU_TMP_PROCESS]));
#endif
p_err:
return ret;
}
static int __vpu_itf_allocate(struct vpu_interface *interface,
struct vpu_graph *graph)
{
int ret = 0;
unsigned long flags;
struct vpu_framemgr *iframemgr;
struct vpu_frame *iframe;
BUG_ON(!interface);
BUG_ON(!graph);
iframemgr = &interface->framemgr;
framemgr_e_barrier_irqs(iframemgr, 0, flags);
vpu_frame_pick_fre_to_req(iframemgr, &iframe);
framemgr_x_barrier_irqr(iframemgr, 0, flags);
if (!iframe) {
vpu_err("iframe is NULL\n");
ret = -ENOMEM;
goto p_err;
}
#ifdef DBG_TIMEMEASURE
vpu_get_timestamp(&iframe->time[VPU_TMP_REQUEST]);
#endif
iframe->id = 0;
iframe->lock = &graph->local_lock;
iframe->findex = VPU_MAX_FRAME;
iframe->gindex = VPU_MAX_GFRAME;
iframe->message = VPU_FRAME_ALLOCATE;
iframe->param0 = (ulong)graph->desc_mtask;
iframe->param1 = graph->id;
iframe->param2 = 0;
iframe->param3 = 0;
ret = vpu_hw_allocate(interface, iframe);
if (ret) {
vpu_err("vpu_hw_allocate is fail(%d)\n", ret);
goto p_err;
}
#ifdef DBG_TIMEMEASURE
vpu_iinfo("[TM] A : %ldus, %ldus\n", graph,
VPU_TIME_IN_US(iframe->time[VPU_TMP_PROCESS]) -
VPU_TIME_IN_US(iframe->time[VPU_TMP_REQUEST]),
VPU_TIME_IN_US(iframe->time[VPU_TMP_DONE]) -
VPU_TIME_IN_US(iframe->time[VPU_TMP_PROCESS]));
#endif
p_err:
return ret;
}
static int __vpu_itf_process(struct vpu_interface *interface,
struct vpu_graph *graph,
struct vpu_frame *frame)
{
int ret = 0;
unsigned long flags;
struct vpu_framemgr *iframemgr;
struct vpu_frame *iframe;
struct vpuo_pu *pu, *temp;
struct vpu_invoke_external_mem_vector_ds mvectors;
union vpul_pu_parameters *update_array;
u32 i;
BUG_ON(!interface);
BUG_ON(!graph);
BUG_ON(!frame);
iframemgr = &interface->framemgr;
mvectors.num_of_buffers = 0;
update_array = NULL;
framemgr_e_barrier_irqs(iframemgr, 0, flags);
vpu_frame_pick_fre_to_req(iframemgr, &iframe);
framemgr_x_barrier_irqr(iframemgr, 0, flags);
if (!iframe) {
vpu_err("iframe is NULL\n");
ret = -ENOMEM;
goto p_err;
}
if (test_bit(VS4L_GRAPH_FLAG_PRIMITIVE, &graph->flags)) {
for (i = 0; i < graph->iobuffer_cnt; ++i) {
mvectors.addresses_vector[i] = graph->iobuffer_dat[i];
mvectors.num_of_buffers++;
}
goto p_skip_primitive;
}
list_for_each_entry_safe(pu, temp, &graph->inleaf_list, gleaf_entry) {
for (i = 0; i < pu->buffer_cnt; ++i) {
if (!pu->buffer_ptr[i])
continue;
if (mvectors.num_of_buffers >= VPUL_MAX_MAPS_DESC) {
vpu_err("mvectors.num_of_buffers is over1(%d)\n", mvectors.num_of_buffers);
break;
}
if (!pu->buffer_shm[i]) {
mvectors.addresses_vector[mvectors.num_of_buffers] = *pu->buffer_ptr[i];
mvectors.num_of_buffers++;
}
}
}
list_for_each_entry_safe(pu, temp, &graph->otleaf_list, gleaf_entry) {
for (i = 0; i < pu->buffer_cnt; ++i) {
if (!pu->buffer_ptr[i])
continue;
if (mvectors.num_of_buffers >= VPUL_MAX_MAPS_DESC) {
vpu_err("mvectors.num_of_buffers is over2(%d)\n", mvectors.num_of_buffers);
break;
}
if (!pu->buffer_shm[i]){
mvectors.addresses_vector[mvectors.num_of_buffers] = *pu->buffer_ptr[i];
mvectors.num_of_buffers++;
}
}
}
p_skip_primitive:
if (test_bit(VPU_GRAPH_FLAG_UPDATE_PARAM, &graph->flags)) {
ret = CALL_GOPS(graph, update_param, frame);
if (ret) {
vpu_err("GOPS(update_param) is fail(%d)\n", ret);
goto p_err;
}
update_array = graph->update_array;
clear_bit(VPU_GRAPH_FLAG_UPDATE_PARAM, &graph->flags);
}
iframe->id = frame->id;
iframe->lock = &graph->local_lock;
iframe->findex = frame->index;
iframe->gindex = frame->gindex;
iframe->message = VPU_FRAME_PROCESS;
iframe->param0 = (ulong)graph->desc_mtask;
iframe->param1 = graph->id;
iframe->param2 = (ulong)&mvectors; /* return : DONE or NDONE */
iframe->param3 = (ulong)update_array; /* return : error code if param2 is NDONE */
iframe->flags = frame->flags;
iframe->incl = frame->incl;
iframe->otcl = frame->otcl;
ret = CALL_GOPS(graph, process, frame);
if (ret) {
vpu_err("GOPS(process) is fail(%d)\n", ret);
goto p_err;
}
ret = vpu_hw_process(interface, iframe);
if (ret) {
vpu_err("vpu_hw_process is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
static void __vpu_graphmgr_sched(struct vpu_graphmgr *graphmgr)
{
int ret = 0;
struct vpu_graph *graph;
struct vpu_frame *frame;
struct vpu_gframe *ready, *request, *process, *prev, *next, *temp;
struct vpu_interface *interface;
struct vpu_resource *resource;
interface = graphmgr->interface;
resource = graphmgr->resource;
ready = NULL;
request = NULL;
prev = NULL;
next = NULL;
GRAPH_CHECK_POINT(20);
mutex_lock(&graphmgr->glock);
/* 1. priority order */
while (1) {
__vpu_gframe_g_ready(graphmgr, &ready);
if (!ready)
break;
list_for_each_entry_safe(next, temp, &graphmgr->greq_list, list) {
if (ready->priority > next->priority)
break;
prev = next;
next = NULL;
}
__vpu_gframe_s_request(graphmgr, prev, ready, next);
}
GRAPH_CHECK_POINT(21);
/* 2. resource allocation */
list_for_each_entry_safe(request, temp, &graphmgr->greq_list, list) {
graph = request->graph;
frame = request->frame;
#ifdef VPU_DYNAMIC_RESOURCE
ret = CALL_GOPS(graph, get_resource, frame);
if (ret)
continue;
#endif
__vpu_gframe_trans_req_to_pro(graphmgr, request);
}
mutex_unlock(&graphmgr->glock);
GRAPH_CHECK_POINT(22);
/* 3. process graph */
list_for_each_entry_safe(process, temp, &graphmgr->gpro_list, list) {
graph = process->graph;
frame = process->frame;
ret = __vpu_itf_process(interface, graph, frame);
if (ret) {
vpu_err("__vpu_itf_process is fail(%d)\n", ret);
ret = CALL_GOPS(graph, cancel, frame);
if (ret) {
vpu_err("CALL_GOPS(cancel) is fail(%d)\n", ret);
BUG();
}
ret = CALL_GOPS(graph, put_resource, frame);
if (ret) {
vpu_err("CALL_GOPS(put_resource) is fail(%d)\n", ret);
BUG();
}
process->graph = NULL;
process->frame = NULL;
__vpu_gframe_trans_pro_to_fre(graphmgr, process);
continue;
}
__vpu_gframe_trans_pro_to_com(graphmgr, process);
}
GRAPH_CHECK_POINT(23);
graphmgr->sched_cnt++;
}
static int vpu_time_thread(void *data)
{
struct vpu_graphmgr *graphmgr = (struct vpu_graphmgr *)data;
struct vpu_gframe *request, *temp1, *temp2;
struct vpu_gframe *next, *prev;
struct vpu_graph *graph;
BUG_ON(!graphmgr);
while (!kthread_should_stop()) {
TIMER_CHECK_POINT(1);
msleep(VPU_TIME_TICK);
if (!test_bit(VPU_GRAPHMGR_OPEN, &graphmgr->state))
return 0;
if (!atomic_read(&graphmgr->periodics))
goto p_noperiodic;
mutex_lock(&graphmgr->glock);
TIMER_CHECK_POINT(2);
list_for_each_entry_safe(request, temp1, &graphmgr->greq_list, list) {
graph = request->graph;
if (!test_bit(VPU_GRAPH_STATE_START, &graph->state)) {
vpu_err("graph %d is NOT start\n", graph->id);
BUG();
}
if (test_bit(VS4L_GRAPH_FLAG_PERIODIC, &graph->flags)) {
if (--request->ticks > 0)
continue;
TIMER_CHECK_POINT(3);
vpu_iinfo("priority changed(%d -> %d)\n", graph,
request->priority, VPU_GRAPH_MAX_PRIORITY + 1);
request->priority = VPU_GRAPH_MAX_PRIORITY + 1;
request->ticks = graph->period_ticks;
list_del(&request->list);
graphmgr->greq_cnt--;
next = NULL;
prev = NULL;
list_for_each_entry_safe(next, temp2, &graphmgr->greq_list, list) {
if (request->priority > next->priority)
break;
prev = next;
next = NULL;
}
TIMER_CHECK_POINT(4);
__vpu_gframe_s_request(graphmgr, prev, request, next);
}
}
mutex_unlock(&graphmgr->glock);
p_noperiodic:
TIMER_CHECK_POINT(5);
graphmgr->tick_cnt++;
}
return 0;
}
static void vpu_graph_thread(struct kthread_work *work)
{
int ret = 0;
struct vpu_graphmgr *graphmgr;
struct vpu_graph *graph;
struct vpu_frame *frame;
struct vpu_gframe *gframe, * temp;
BUG_ON(!work);
frame = container_of(work, struct vpu_frame, work);
graph = frame->owner;
graphmgr = graph->cookie;
GRAPH_CHECK_POINT(1);
switch (frame->message) {
case VPU_FRAME_REQUEST:
GRAPH_CHECK_POINT(2);
ret = CALL_GOPS(graph, request, frame);
if (ret) {
vpu_err("CALL_GOPS(request) is fail(%d)\n", ret);
BUG();
}
__vpu_gframe_free_head(graphmgr, &gframe);
if (!gframe) {
vpu_err("gframe is NULL\n");
BUG();
}
frame->gindex = gframe->index;
gframe->graph = graph;
gframe->frame = frame;
gframe->priority = graph->priority;
gframe->ticks = graph->period_ticks;
__vpu_gframe_trans_fre_to_rdy(graphmgr, gframe);
GRAPH_CHECK_POINT(3);
break;
case VPU_CTRL_STOP:
GRAPH_CHECK_POINT(4);
list_for_each_entry_safe(gframe, temp, &graphmgr->grdy_list, list) {
if (gframe->graph->id != graph->id)
continue;
ret = CALL_GOPS(graph, cancel, gframe->frame);
if (ret) {
vpu_err("CALL_GOPS(cancel) is fail(%d)\n", ret);
BUG();
}
gframe->graph = NULL;
gframe->frame = NULL;
__vpu_gframe_trans_rdy_to_fre(graphmgr, gframe);
}
GRAPH_CHECK_POINT(5);
mutex_lock(&graphmgr->glock);
list_for_each_entry_safe(gframe, temp, &graphmgr->greq_list, list) {
if (gframe->graph->id != graph->id)
continue;
ret = CALL_GOPS(graph, cancel, gframe->frame);
if (ret) {
vpu_err("CALL_GOPS(cancel) is fail(%d)\n", ret);
BUG();
}
ret = CALL_GOPS(graph, put_resource, gframe->frame);
if (ret) {
vpu_err("CALL_GOPS(put_resource) is fail(%d)\n", ret);
BUG();
}
gframe->graph = NULL;
gframe->frame = NULL;
__vpu_gframe_trans_req_to_fre(graphmgr, gframe);
}
mutex_unlock(&graphmgr->glock);
GRAPH_CHECK_POINT(6);
ret = CALL_GOPS(graph, control, frame);
if (ret) {
vpu_err("CALL_GOPS(control) is fail(%d)\n", ret);
BUG();
}
return;
default:
BUG();
break;
}
GRAPH_CHECK_POINT(7);
__vpu_graphmgr_sched(graphmgr);
}
static void vpu_interface_thread(struct kthread_work *work)
{
int ret = 0;
u32 frame_index;
u32 gframe_index;
unsigned long flag;
struct vpu_graphmgr *graphmgr;
struct vpu_graph *graph;
struct vpu_framemgr *iframemgr;
struct vpu_frame *frame, *iframe;
struct vpu_gframe *gframe;
struct vpu_interface *interface;
BUG_ON(!work);
iframe = container_of(work, struct vpu_frame, work);
interface = iframe->owner;
iframemgr = &interface->framemgr;
graphmgr = interface->cookie;
GRAPH_CHECK_POINT(10);
switch (iframe->message) {
case VPU_FRAME_ALLOCATE:
GRAPH_CHECK_POINT(11);
frame_index = iframe->findex;
gframe_index = iframe->gindex;
if (gframe_index >= VPU_MAX_GFRAME) {
vpu_err("gframe index(%d) is invalid\n", gframe_index);
BUG();
}
if (frame_index >= VPU_MAX_FRAME) {
vpu_err("frame index(%d) is invalid\n", frame_index);
BUG();
}
gframe = &graphmgr->gframe[gframe_index];
if (gframe->state != VPU_GFRAME_STATE_ALLOC) {
vpu_err("gframe state is invalid(%d)\n", gframe->state);
vpu_gframe_print(graphmgr);
BUG();
}
graph = gframe->graph;
if (!graph) {
vpu_err("graph is NULL(%d)\n", gframe_index);
BUG();
}
frame = gframe->frame;
if (!frame) {
vpu_err("frame is NULL(%d)\n", gframe_index);
BUG();
}
frame->message = iframe->message;
frame->param0 = iframe->param2;
frame->param1 = iframe->param3;
/* return status check */
if (frame->param0) {
vpu_err("allocation is fail(%ld, %ld)\n", frame->param0, frame->param1);
ret = CALL_GOPS(graph, cancel, frame);
if (ret) {
vpu_err("CALL_GOPS(cancel) is fail(%d)\n", ret);
BUG();
}
ret = CALL_GOPS(graph, put_resource, frame);
if (ret) {
vpu_err("CALL_GOPS(put_resource) is fail(%d)\n", ret);
BUG();
}
/* gframe cleanup */
mutex_lock(&graphmgr->glock);
gframe->graph = NULL;
gframe->frame = NULL;
__vpu_gframe_trans_alc_to_fre(graphmgr, gframe);
mutex_unlock(&graphmgr->glock);
} else {
/* gframe transition */
mutex_lock(&graphmgr->glock);
__vpu_gframe_trans_alc_to_pro(graphmgr, gframe);
mutex_unlock(&graphmgr->glock);
}
/* iframe cleanup */
framemgr_e_barrier_irqs(iframemgr, 0, flag);
vpu_frame_trans_com_to_fre(iframemgr, iframe);
framemgr_x_barrier_irqr(iframemgr, 0, flag);
break;
case VPU_FRAME_PROCESS:
GRAPH_CHECK_POINT(12);
frame_index = iframe->findex;
gframe_index = iframe->gindex;
if (gframe_index >= VPU_MAX_GFRAME) {
vpu_err("gframe index(%d) is invalid\n", gframe_index);
BUG();
}
if (frame_index >= VPU_MAX_FRAME) {
vpu_err("frame index(%d) is invalid\n", frame_index);
BUG();
}
gframe = &graphmgr->gframe[gframe_index];
if (gframe->state != VPU_GFRAME_STATE_COMPLETE) {
vpu_err("gframe state is invalid(%d)\n", gframe->state);
vpu_gframe_print(graphmgr);
BUG();
}
graph = gframe->graph;
if (!graph) {
vpu_err("graph is NULL(%d)\n", gframe_index);
BUG();
}
frame = gframe->frame;
if (!frame) {
vpu_err("frame is NULL(%d)\n", gframe_index);
BUG();
}
frame->message = iframe->message;
frame->gindex = VPU_MAX_GFRAME;
frame->param0 = iframe->param2;
frame->param1 = iframe->param3;
#ifdef VPU_DYNAMIC_RESOURCE
ret = CALL_GOPS(graph, put_resource, frame);
if (ret) {
vpu_err("CALL_GOPS(put_resource) is fail(%d)\n", ret);
BUG();
}
#endif
ret = CALL_GOPS(graph, done, frame);
if (ret) {
vpu_err("CALL_GOPS(done) is fail(%d)\n", ret);
BUG();
}
/* gframe cleanup */
gframe->graph = NULL;
gframe->frame = NULL;
gframe->ticks = 0;
__vpu_gframe_trans_com_to_fre(graphmgr, gframe);
/* iframe cleanup */
framemgr_e_barrier_irqs(iframemgr, 0, flag);
vpu_frame_trans_com_to_fre(iframemgr, iframe);
framemgr_x_barrier_irqr(iframemgr, 0, flag);
break;
default:
BUG();
break;
}
GRAPH_CHECK_POINT(13);
__vpu_graphmgr_sched(graphmgr);
}
int vpu_graphmgr_grp_register(struct vpu_graphmgr *graphmgr, struct vpu_graph *graph)
{
int ret = 0;
u32 index;
BUG_ON(!graphmgr);
BUG_ON(!graph);
mutex_lock(&graphmgr->mlock);
for (index = 0; index < VPU_MAX_GRAPH; index++) {
if (!graphmgr->graph[index]) {
graphmgr->graph[index] = graph;
graph->id = index;
break;
}
}
mutex_unlock(&graphmgr->mlock);
if (index >= VPU_MAX_GRAPH) {
vpu_err("graph slot is lack\n");
ret = -EINVAL;
goto p_err;
}
init_kthread_work(&graph->control.work, vpu_graph_thread);
for (index = 0; index < VPU_MAX_FRAME; ++index)
init_kthread_work(&graph->framemgr.frame[index].work, vpu_graph_thread);
graph->global_lock = &graphmgr->mlock;
p_err:
return ret;
}
int vpu_graphmgr_grp_unregister(struct vpu_graphmgr *graphmgr, struct vpu_graph *graph)
{
int ret = 0;
BUG_ON(!graphmgr);
BUG_ON(!graph);
mutex_lock(&graphmgr->mlock);
graphmgr->graph[graph->id] = NULL;
mutex_unlock(&graphmgr->mlock);
return ret;
}
int vpu_graphmgr_grp_start(struct vpu_graphmgr *graphmgr, struct vpu_graph *graph)
{
int ret = 0;
if (test_bit(VS4L_GRAPH_FLAG_PERIODIC, &graph->flags))
atomic_inc(&graphmgr->periodics);
mutex_lock(&graphmgr->mlock);
if (test_bit(VPU_GRAPHMGR_ENUM, &graphmgr->state)) {
mutex_unlock(&graphmgr->mlock);
goto p_skip_enum;
}
ret = __vpu_itf_enum(graphmgr->interface, graph);
if (ret) {
mutex_unlock(&graphmgr->mlock);
vpu_err("__vpu_itf_enum is fail(%d)\n", ret);
goto p_err;
}
set_bit(VPU_GRAPHMGR_ENUM, &graphmgr->state);
mutex_unlock(&graphmgr->mlock);
p_skip_enum:
ret = __vpu_itf_create(graphmgr->interface, graph);
if (ret) {
vpu_err("__vpu_itf_create is fail(%d)\n", ret);
goto p_err;
}
ret = __vpu_itf_allocate(graphmgr->interface, graph);
if (ret) {
vpu_err("__vpu_itf_allocate is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
int vpu_graphmgr_grp_stop(struct vpu_graphmgr *graphmgr, struct vpu_graph *graph)
{
int ret = 0;
if (test_bit(VS4L_GRAPH_FLAG_PERIODIC, &graph->flags))
atomic_dec(&graphmgr->periodics);
ret = __vpu_itf_destroy(graphmgr->interface, graph);
if (ret) {
vpu_err("__vpu_itf_destroy is fail(%d)\n", ret);
goto p_err;
}
p_err:
return ret;
}
int vpu_graphmgr_itf_register(struct vpu_graphmgr *graphmgr, struct vpu_interface *interface)
{
int ret = 0;
u32 index;
BUG_ON(!graphmgr);
BUG_ON(!interface);
graphmgr->interface = interface;
for (index = 0; index < VPU_MAX_FRAME; ++index)
init_kthread_work(&interface->framemgr.frame[index].work, vpu_interface_thread);
return ret;
}
int vpu_graphmgr_itf_unregister(struct vpu_graphmgr *graphmgr, struct vpu_interface *interface)
{
int ret = 0;
BUG_ON(!graphmgr);
BUG_ON(!interface);
graphmgr->interface = NULL;
return ret;
}
void vpu_graphmgr_queue(struct vpu_graphmgr *graphmgr, struct vpu_frame *frame)
{
BUG_ON(!graphmgr);
BUG_ON(!frame);
queue_kthread_work(&graphmgr->worker, &frame->work);
}
int vpu_graphmgr_probe(struct vpu_graphmgr *graphmgr,
struct vpu_resource *resource)
{
int ret = 0;
u32 index;
struct vpu_device *device = container_of(graphmgr, struct vpu_device, graphmgr);
BUG_ON(!graphmgr);
BUG_ON(!device);
graphmgr->tick_cnt = 0;
graphmgr->tick_pos = 0;
graphmgr->sched_cnt = 0;
graphmgr->sched_pos = 0;
graphmgr->task_graph = NULL;
graphmgr->task_timer = NULL;
graphmgr->resource = resource;
atomic_set(&graphmgr->periodics, 0);
mutex_init(&graphmgr->mlock);
mutex_init(&graphmgr->glock);
clear_bit(VPU_GRAPHMGR_OPEN, &graphmgr->state);
clear_bit(VPU_GRAPHMGR_ENUM, &graphmgr->state);
for (index = 0; index < VPU_MAX_GRAPH; ++index)
graphmgr->graph[index] = NULL;
INIT_LIST_HEAD(&graphmgr->gfre_list);
INIT_LIST_HEAD(&graphmgr->grdy_list);
INIT_LIST_HEAD(&graphmgr->greq_list);
INIT_LIST_HEAD(&graphmgr->galc_list);
INIT_LIST_HEAD(&graphmgr->gpro_list);
INIT_LIST_HEAD(&graphmgr->gcom_list);
graphmgr->gfre_cnt = 0;
graphmgr->grdy_cnt = 0;
graphmgr->greq_cnt = 0;
graphmgr->galc_cnt = 0;
graphmgr->gpro_cnt = 0;
graphmgr->gcom_cnt = 0;
for (index = 0; index < VPU_MAX_GFRAME; ++index) {
graphmgr->gframe[index].index = index;
graphmgr->gframe[index].graph = NULL;
graphmgr->gframe[index].frame = NULL;
graphmgr->gframe[index].state = VPU_GFRAME_STATE_INVALID;
graphmgr->gframe[index].ticks = 0;
__vpu_gframe_s_free(graphmgr, &graphmgr->gframe[index]);
}
return ret;
}
int vpu_graphmgr_open(struct vpu_graphmgr *graphmgr)
{
int ret = 0;
char name[30];
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
BUG_ON(!graphmgr);
init_kthread_worker(&graphmgr->worker);
snprintf(name, sizeof(name), "vpu_graph");
graphmgr->task_graph = kthread_run(kthread_worker_fn, &graphmgr->worker, name);
if (IS_ERR_OR_NULL(graphmgr->task_graph)) {
vpu_err("kthread_run is fail\n");
ret = -EINVAL;
goto p_err;
}
ret = sched_setscheduler_nocheck(graphmgr->task_graph, SCHED_FIFO, &param);
if (ret) {
vpu_err("sched_setscheduler_nocheck is fail(%d)\n", ret);
goto p_err;
}
snprintf(name, sizeof(name), "vpu_timer");
graphmgr->task_timer = kthread_run(vpu_time_thread, graphmgr, name);
if (IS_ERR_OR_NULL(graphmgr->task_timer)) {
vpu_err("kthread_run is fail\n");
ret = -EINVAL;
goto p_err;
}
ret = sched_setscheduler_nocheck(graphmgr->task_timer, SCHED_FIFO, &param);
if (ret) {
vpu_err("sched_setscheduler_nocheck is fail(%d)\n", ret);
goto p_err;
}
set_bit(VPU_GRAPHMGR_OPEN, &graphmgr->state);
p_err:
return ret;
}
int vpu_graphmgr_close(struct vpu_graphmgr *graphmgr)
{
int ret = 0;
struct vpu_gframe *gframe, *temp;
BUG_ON(!graphmgr);
if (graphmgr->grdy_cnt > 0) {
ret++;
vpu_err("ready gframe is NOT empty(%d)\n", graphmgr->grdy_cnt);
list_for_each_entry_safe(gframe, temp, &graphmgr->grdy_list, list) {
list_del(&gframe->list);
graphmgr->grdy_cnt--;
__vpu_gframe_s_free(graphmgr, gframe);
}
}
if (graphmgr->greq_cnt > 0) {
ret++;
vpu_err("request gframe is NOT empty(%d)\n", graphmgr->greq_cnt);
list_for_each_entry_safe(gframe, temp, &graphmgr->greq_list, list) {
list_del(&gframe->list);
graphmgr->greq_cnt--;
__vpu_gframe_s_free(graphmgr, gframe);
}
}
if (graphmgr->gpro_cnt > 0) {
ret++;
vpu_err("process gframe is NOT empty(%d)\n", graphmgr->gpro_cnt);
list_for_each_entry_safe(gframe, temp, &graphmgr->gpro_list, list) {
list_del(&gframe->list);
graphmgr->gpro_cnt--;
__vpu_gframe_s_free(graphmgr, gframe);
}
}
kthread_stop(graphmgr->task_timer);
kthread_stop(graphmgr->task_graph);
clear_bit(VPU_GRAPHMGR_OPEN, &graphmgr->state);
clear_bit(VPU_GRAPHMGR_ENUM, &graphmgr->state);
return ret;
}