video: rockchip: rga3: fixup crash on rga_job_next

1. Free job resource when user exit to call release
2. Support rga_seesion.

Signed-off-by: Li Huang <putin.li@rock-chips.com>
Change-Id: I87d01ce24d80769bb379c6117798063133e922b3
This commit is contained in:
Li Huang
2022-03-31 16:23:00 +08:00
committed by Tao Huang
parent 295acc8ce8
commit c002048f4f
4 changed files with 210 additions and 33 deletions

View File

@@ -248,10 +248,15 @@ struct rga2_mmu_other_t {
struct rga_scheduler_t;
struct rga_session {
int id;
};
struct rga_job {
struct list_head head;
struct rga_scheduler_t *scheduler;
struct rga_session *session;
struct rga_req rga_command_base;
uint32_t cmd_reg[32 * 8];
@@ -334,6 +339,8 @@ struct rga_scheduler_t {
struct rga_internal_ctx_t {
struct rga_req *cached_cmd;
struct rga_session *session;
int cmd_num;
int flags;
int id;
@@ -370,6 +377,14 @@ struct rga_pending_ctx_manager {
int ctx_count;
};
struct rga_session_manager {
struct mutex lock;
struct idr ctx_id_idr;
int session_cnt;
};
struct rga_drvdata_t {
struct miscdevice miscdev;
@@ -386,6 +401,8 @@ struct rga_drvdata_t {
/* rga_job pending manager, import by RGA_START_CONFIG */
struct rga_pending_ctx_manager *pend_ctx_manager;
struct rga_session_manager *session_manager;
#ifdef CONFIG_ROCKCHIP_RGA_ASYNC
struct rga_fence_context *fence_ctx;
#endif

View File

@@ -23,6 +23,8 @@ enum job_flags {
struct rga_scheduler_t *rga_job_get_scheduler(struct rga_job *job);
void rga_job_session_destroy(struct rga_session *session);
void rga_job_done(struct rga_scheduler_t *scheduler, int ret);
int rga_job_commit(struct rga_req *rga_command_base, struct rga_internal_ctx_t *ctx);
@@ -36,7 +38,9 @@ int rga_ctx_manager_remove(struct rga_pending_ctx_manager **ctx_manager_session)
struct rga_internal_ctx_t *
rga_internal_ctx_lookup(struct rga_pending_ctx_manager *ctx_manager, uint32_t id);
uint32_t rga_internal_ctx_alloc_to_get_idr_id(uint32_t flags);
uint32_t rga_internal_ctx_alloc_to_get_idr_id(uint32_t flags, struct rga_session *session);
void rga_internal_ctx_kref_release(struct kref *ref);
int rga_internal_ctx_config_by_user_ctx(struct rga_user_ctx_t *user_ctx);
int rga_internal_ctx_commit_by_user_ctx(struct rga_user_ctx_t *user_ctx);

View File

@@ -394,6 +394,131 @@ static void rga_power_disable_all(void)
#endif //CONFIG_ROCKCHIP_FPGA
static int rga_session_manager_init(struct rga_session_manager **session_manager_ptr)
{
struct rga_session_manager *session_manager = NULL;
*session_manager_ptr = kzalloc(sizeof(struct rga_session_manager), GFP_KERNEL);
if (*session_manager_ptr == NULL) {
pr_err("can not kzalloc for rga_session_manager\n");
return -ENOMEM;
}
session_manager = *session_manager_ptr;
mutex_init(&session_manager->lock);
idr_init_base(&session_manager->ctx_id_idr, 1);
return 0;
}
/*
* Called at driver close to release the rga session's id references.
*/
static int rga_session_free_remove_idr_cb(int id, void *ptr, void *data)
{
struct rga_session *session = ptr;
idr_remove(&rga_drvdata->session_manager->ctx_id_idr, session->id);
kfree(session);
return 0;
}
static int rga_session_free_remove_idr(struct rga_session *session)
{
struct rga_session_manager *session_manager;
session_manager = rga_drvdata->session_manager;
mutex_lock(&session_manager->lock);
session_manager->session_cnt--;
idr_remove(&session_manager->ctx_id_idr, session->id);
mutex_unlock(&session_manager->lock);
return 0;
}
static int rga_session_manager_remove(struct rga_session_manager **session_manager_ptr)
{
struct rga_session_manager *session_manager = *session_manager_ptr;
mutex_lock(&session_manager->lock);
idr_for_each(&session_manager->ctx_id_idr, &rga_session_free_remove_idr_cb, session_manager);
idr_destroy(&session_manager->ctx_id_idr);
mutex_unlock(&session_manager->lock);
kfree(*session_manager_ptr);
*session_manager_ptr = NULL;
return 0;
}
static struct rga_session *rga_session_init(void)
{
struct rga_session_manager *session_manager = NULL;
struct rga_session *session = kzalloc(sizeof(*session), GFP_KERNEL);
session_manager = rga_drvdata->session_manager;
if (session_manager == NULL) {
pr_err("rga_session_manager is null!\n");
kfree(session);
return NULL;
}
mutex_lock(&session_manager->lock);
idr_preload(GFP_KERNEL);
session->id = idr_alloc(&session_manager->ctx_id_idr, session, 1, 0, GFP_ATOMIC);
session_manager->session_cnt++;
idr_preload_end();
mutex_unlock(&session_manager->lock);
return session;
}
static int rga_session_deinit(struct rga_session *session)
{
pid_t pid;
int ctx_id;
struct rga_pending_ctx_manager *ctx_manager;
struct rga_internal_ctx_t *ctx;
pid = current->pid;
ctx_manager = rga_drvdata->pend_ctx_manager;
mutex_lock(&ctx_manager->lock);
idr_for_each_entry(&ctx_manager->ctx_id_idr, ctx, ctx_id) {
mutex_unlock(&ctx_manager->lock);
if (session == ctx->session) {
pr_err("[pid:%d] destroy ctx[%d] when the user exits", pid, ctx->id);
kref_put(&ctx->refcount, rga_internal_ctx_kref_release);
}
mutex_lock(&ctx_manager->lock);
}
mutex_unlock(&ctx_manager->lock);
rga_session_free_remove_idr(session);
rga_job_session_destroy(session);
kfree(session);
return 0;
}
static long rga_ioctl_import_buffer(unsigned long arg)
{
int i;
@@ -517,7 +642,7 @@ err_free_external_buffer:
return ret;
}
static long rga_ioctl_cmd_start(unsigned long arg)
static long rga_ioctl_cmd_start(unsigned long arg, struct rga_session *session)
{
uint32_t rga_user_ctx_id;
uint32_t flags;
@@ -526,7 +651,7 @@ static long rga_ioctl_cmd_start(unsigned long arg)
if (copy_from_user(&flags, (void *)arg, sizeof(uint32_t)))
ret = -EFAULT;
rga_user_ctx_id = rga_internal_ctx_alloc_to_get_idr_id(flags);
rga_user_ctx_id = rga_internal_ctx_alloc_to_get_idr_id(flags, session);
if (copy_to_user((void *)arg, &rga_user_ctx_id, sizeof(uint32_t)))
ret = -EFAULT;
@@ -638,9 +763,9 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
char version[16] = { 0 };
struct rga_version_t driver_version;
struct rga_hw_versions_t hw_versions;
struct rga_internal_ctx_t ctx;
struct rga_internal_ctx_t *ctx;
memset(&ctx, 0x0, sizeof(ctx));
struct rga_session *session = file->private_data;
if (!rga) {
pr_err("rga_drvdata is null, rga is not init\n");
@@ -663,10 +788,17 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
if (DEBUGGER_EN(MSG))
rga_cmd_print_debug_info(&req_rga);
ctx.sync_mode = cmd;
ctx.use_batch_mode = false;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) {
pr_err("can not kzalloc for ctx!\n");
return -ENOMEM;
}
ret = rga_job_commit(&req_rga, &ctx);
ctx->sync_mode = cmd;
ctx->use_batch_mode = false;
ctx->session = session;
ret = rga_job_commit(&req_rga, ctx);
if (ret < 0) {
if (ret == -ERESTARTSYS) {
if (DEBUGGER_EN(MSG))
@@ -685,6 +817,8 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
break;
}
kfree(ctx);
break;
case RGA_CACHE_FLUSH:
case RGA_FLUSH:
@@ -779,7 +913,7 @@ static long rga_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
break;
case RGA_START_CONFIG:
ret = rga_ioctl_cmd_start(arg);
ret = rga_ioctl_cmd_start(arg, session);
break;
@@ -852,35 +986,22 @@ static int rga_debugger_remove(struct rga_debugger **debugger_p)
static int rga_open(struct inode *inode, struct file *file)
{
struct rga_session *session = NULL;
session = rga_session_init();
if (!session)
return -ENOMEM;
file->private_data = (void *)session;
return nonseekable_open(inode, file);
}
static int rga_release(struct inode *inode, struct file *file)
{
pid_t pid;
int ctx_id;
struct rga_pending_ctx_manager *ctx_manager;
struct rga_internal_ctx_t *ctx;
struct rga_session *session = file->private_data;
pid = current->pid;
ctx_manager = rga_drvdata->pend_ctx_manager;
mutex_lock(&ctx_manager->lock);
idr_for_each_entry(&ctx_manager->ctx_id_idr, ctx, ctx_id) {
mutex_unlock(&ctx_manager->lock);
if (pid == ctx->pid) {
pr_err("[pid:%d] destroy ctx[%d] when the user exits", pid, ctx->id);
kref_put(&ctx->refcount, rga_internal_ctx_kref_release);
}
mutex_lock(&ctx_manager->lock);
}
mutex_unlock(&ctx_manager->lock);
rga_session_deinit(session);
return 0;
}
@@ -1377,6 +1498,8 @@ static int __init rga_init(void)
rga_ctx_manager_init(&rga_drvdata->pend_ctx_manager);
rga_session_manager_init(&rga_drvdata->session_manager);
#ifdef CONFIG_ROCKCHIP_RGA_ASYNC
rga_fence_context_init(&rga_drvdata->fence_ctx);
#endif
@@ -1408,6 +1531,8 @@ static void __exit rga_exit(void)
rga_ctx_manager_remove(&rga_drvdata->pend_ctx_manager);
rga_session_manager_remove(&rga_drvdata->session_manager);
rga_cancel_timer();
platform_driver_unregister(&rga3_core0_driver);

View File

@@ -119,6 +119,35 @@ static void rga_job_free(struct rga_job *job)
free_page((unsigned long)job);
}
void rga_job_session_destroy(struct rga_session *session)
{
struct rga_scheduler_t *scheduler = NULL;
struct rga_job *job_pos, *job_q;
int i;
unsigned long flags;
for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
scheduler = rga_drvdata->scheduler[i];
spin_lock_irqsave(&scheduler->irq_lock, flags);
list_for_each_entry_safe(job_pos, job_q, &scheduler->todo_list, head) {
if (session == job_pos->session) {
list_del(&job_pos->head);
spin_unlock_irqrestore(&scheduler->irq_lock, flags);
rga_job_free(job_pos);
spin_lock_irqsave(&scheduler->irq_lock, flags);
}
}
spin_unlock_irqrestore(&scheduler->irq_lock, flags);
}
}
static int rga_job_cleanup(struct rga_job *job)
{
ktime_t now = ktime_get();
@@ -638,6 +667,7 @@ int rga_job_commit(struct rga_req *rga_command_base, struct rga_internal_ctx_t *
job->use_batch_mode = ctx->use_batch_mode;
job->ctx_id = ctx->id;
job->session = ctx->session;
/*
* because fd can not pass on other thread,
@@ -908,7 +938,7 @@ int rga_internal_ctx_signal(struct rga_scheduler_t *scheduler, struct rga_job *j
return 0;
}
uint32_t rga_internal_ctx_alloc_to_get_idr_id(uint32_t flags)
uint32_t rga_internal_ctx_alloc_to_get_idr_id(uint32_t flags, struct rga_session *session)
{
struct rga_pending_ctx_manager *ctx_manager;
struct rga_internal_ctx_t *ctx;
@@ -944,6 +974,7 @@ uint32_t rga_internal_ctx_alloc_to_get_idr_id(uint32_t flags)
kref_init(&ctx->refcount);
ctx->pid = current->pid;
ctx->flags = flags;
ctx->session = session;
mutex_unlock(&ctx_manager->lock);