diff --git a/drivers/video/rockchip/rve/include/rve_drv.h b/drivers/video/rockchip/rve/include/rve_drv.h index 311475f13889..0d070bc3e928 100644 --- a/drivers/video/rockchip/rve/include/rve_drv.h +++ b/drivers/video/rockchip/rve/include/rve_drv.h @@ -116,9 +116,16 @@ struct rve_fence_waiter { struct rve_scheduler_t; struct rve_internal_ctx_t; +struct rve_session { + int id; + + pid_t tgid; +}; + struct rve_job { struct list_head head; struct rve_scheduler_t *scheduler; + struct rve_session *session; struct rve_cmd_reg_array_t *regcmd_data; @@ -220,6 +227,7 @@ struct rve_ctx_debug_info_t { struct rve_internal_ctx_t { struct rve_scheduler_t *scheduler; + struct rve_session *session; struct rve_cmd_reg_array_t *regcmd_data; uint32_t cmd_num; @@ -260,6 +268,14 @@ struct rve_pending_ctx_manager { int ctx_count; }; +struct rve_session_manager { + struct mutex lock; + + struct idr ctx_id_idr; + + int session_cnt; +}; + struct rve_drvdata_t { struct rve_fence_context *fence_ctx; @@ -277,6 +293,8 @@ struct rve_drvdata_t { /* rve_job pending manager, import by RVE_IOC_START_CONFIG */ struct rve_pending_ctx_manager *pend_ctx_manager; + struct rve_session_manager *session_manager; + #ifdef CONFIG_ROCKCHIP_RVE_DEBUGGER struct rve_debugger *debugger; #endif diff --git a/drivers/video/rockchip/rve/include/rve_job.h b/drivers/video/rockchip/rve/include/rve_job.h index 39f5f1b23c1b..364be1ab58f8 100644 --- a/drivers/video/rockchip/rve/include/rve_job.h +++ b/drivers/video/rockchip/rve/include/rve_job.h @@ -27,16 +27,18 @@ struct rve_internal_ctx_t *rve_job_get_internal_ctx(struct rve_job *job); void rve_job_done(struct rve_scheduler_t *rve_scheduler, int ret); int rve_job_commit(struct rve_internal_ctx_t *ctx); -int rve_ctx_manager_init(struct rve_pending_ctx_manager **ctx_manager_session); -int rve_ctx_manager_remove(struct rve_pending_ctx_manager **ctx_manager_session); - -int rve_internal_ctx_alloc_to_get_idr_id(void); -void rve_internal_ctx_kref_release(struct kref *ref); - int rve_job_config_by_user_ctx(struct rve_user_ctx_t *user_ctx); int rve_job_commit_by_user_ctx(struct rve_user_ctx_t *user_ctx); int rve_job_cancel_by_user_ctx(uint32_t ctx_id); +void rve_job_session_destroy(struct rve_session *session); + +int rve_ctx_manager_init(struct rve_pending_ctx_manager **ctx_manager_session); +int rve_ctx_manager_remove(struct rve_pending_ctx_manager **ctx_manager_session); + +int rve_internal_ctx_alloc_to_get_idr_id(struct rve_session *session); +void rve_internal_ctx_kref_release(struct kref *ref); + struct rve_job * rve_scheduler_get_pending_job_list(struct rve_scheduler_t *scheduler); diff --git a/drivers/video/rockchip/rve/rve_drv.c b/drivers/video/rockchip/rve/rve_drv.c index 30a009ebff1e..f6d2959aa933 100644 --- a/drivers/video/rockchip/rve/rve_drv.c +++ b/drivers/video/rockchip/rve/rve_drv.c @@ -157,12 +157,140 @@ int rve_power_disable(struct rve_scheduler_t *scheduler) #endif //RVE_PD_AWAYS_ON -static long rve_ioctl_cmd_start(unsigned long arg) +static int rve_session_manager_init(struct rve_session_manager **session_manager_ptr) +{ + struct rve_session_manager *session_manager = NULL; + + *session_manager_ptr = kzalloc(sizeof(struct rve_session_manager), GFP_KERNEL); + if (*session_manager_ptr == NULL) { + pr_err("can not kzalloc for rve_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 rve session's id references. + */ +static int rve_session_free_remove_idr_cb(int id, void *ptr, void *data) +{ + struct rve_session *session = ptr; + + idr_remove(&rve_drvdata->session_manager->ctx_id_idr, session->id); + kfree(session); + + return 0; +} + +static int rve_session_free_remove_idr(struct rve_session *session) +{ + struct rve_session_manager *session_manager; + + session_manager = rve_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 rve_session_manager_remove(struct rve_session_manager **session_manager_ptr) +{ + struct rve_session_manager *session_manager = *session_manager_ptr; + + mutex_lock(&session_manager->lock); + + idr_for_each(&session_manager->ctx_id_idr, &rve_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 rve_session *rve_session_init(void) +{ + struct rve_session_manager *session_manager = NULL; + struct rve_session *session = kzalloc(sizeof(*session), GFP_KERNEL); + + session_manager = rve_drvdata->session_manager; + if (session_manager == NULL) { + pr_err("rve_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); + + session->tgid = current->tgid; + + return session; +} + +static int rve_session_deinit(struct rve_session *session) +{ + pid_t pid; + int ctx_id; + struct rve_pending_ctx_manager *ctx_manager; + struct rve_internal_ctx_t *ctx; + unsigned long flags; + + pid = current->pid; + + ctx_manager = rve_drvdata->pend_ctx_manager; + + spin_lock_irqsave(&ctx_manager->lock, flags); + + idr_for_each_entry(&ctx_manager->ctx_id_idr, ctx, ctx_id) { + + spin_unlock_irqrestore(&ctx_manager->lock, flags); + + if (session == ctx->session) { + pr_err("[pid:%d] destroy ctx[%d] when the user exits", pid, ctx->id); + kref_put(&ctx->refcount, rve_internal_ctx_kref_release); + } + + spin_lock_irqsave(&ctx_manager->lock, flags); + } + + spin_unlock_irqrestore(&ctx_manager->lock, flags); + + rve_job_session_destroy(session); + + rve_session_free_remove_idr(session); + kfree(session); + + return 0; +} + +static long rve_ioctl_cmd_start(unsigned long arg, struct rve_session *session) { int rve_user_ctx_id; int ret = 0; - rve_user_ctx_id = rve_internal_ctx_alloc_to_get_idr_id(); + rve_user_ctx_id = rve_internal_ctx_alloc_to_get_idr_id(session); if (copy_to_user((void *)arg, &rve_user_ctx_id, sizeof(int))) ret = -EFAULT; @@ -269,6 +397,7 @@ static long rve_ioctl(struct file *file, uint32_t cmd, unsigned long arg) int i = 0; struct rve_version_t driver_version; struct rve_hw_versions_t hw_versions; + struct rve_session *session = file->private_data; if (!rve) { pr_err("rve_drvdata is null, rve is not init\n"); @@ -312,7 +441,7 @@ static long rve_ioctl(struct file *file, uint32_t cmd, unsigned long arg) break; case RVE_IOC_START_CONFIG: - ret = rve_ioctl_cmd_start(arg); + ret = rve_ioctl_cmd_start(arg, session); break; @@ -383,37 +512,22 @@ static int rve_debugger_remove(struct rve_debugger **debugger_p) static int rve_open(struct inode *inode, struct file *file) { + struct rve_session *session = NULL; + + session = rve_session_init(); + if (!session) + return -ENOMEM; + + file->private_data = (void *)session; + return nonseekable_open(inode, file); } static int rve_release(struct inode *inode, struct file *file) { - struct rve_pending_ctx_manager *ctx_manager; - struct rve_internal_ctx_t *ctx; - pid_t pid; - int ctx_id; - unsigned long flags; + struct rve_session *session = file->private_data; - pid = current->pid; - - ctx_manager = rve_drvdata->pend_ctx_manager; - - spin_lock_irqsave(&ctx_manager->lock, flags); - - idr_for_each_entry(&ctx_manager->ctx_id_idr, ctx, ctx_id) { - - spin_unlock_irqrestore(&ctx_manager->lock, flags); - - if (pid == ctx->debug_info.pid) { - if (DEBUGGER_EN(MSG)) - pr_info("[pid:%d] destroy ctx[%d] when the user exits", pid, ctx->id); - kref_put(&ctx->refcount, rve_internal_ctx_kref_release); - } - - spin_lock_irqsave(&ctx_manager->lock, flags); - } - - spin_unlock_irqrestore(&ctx_manager->lock, flags); + rve_session_deinit(session); return 0; } @@ -733,6 +847,8 @@ static int __init rve_init(void) rve_ctx_manager_init(&rve_drvdata->pend_ctx_manager); + rve_session_manager_init(&rve_drvdata->session_manager); + rve_init_timer(); #ifdef CONFIG_ROCKCHIP_RVE_DEBUGGER @@ -752,6 +868,8 @@ static void __exit rve_exit(void) rve_ctx_manager_remove(&rve_drvdata->pend_ctx_manager); + rve_session_manager_remove(&rve_drvdata->session_manager); + wake_lock_destroy(&rve_drvdata->wake_lock); #ifdef CONFIG_SYNC_FILE diff --git a/drivers/video/rockchip/rve/rve_job.c b/drivers/video/rockchip/rve/rve_job.c index 1987e6b1df8c..558baf163106 100644 --- a/drivers/video/rockchip/rve/rve_job.c +++ b/drivers/video/rockchip/rve/rve_job.c @@ -75,6 +75,35 @@ static int rve_job_cleanup(struct rve_job *job) return 0; } +void rve_job_session_destroy(struct rve_session *session) +{ + struct rve_scheduler_t *scheduler = NULL; + struct rve_job *job_pos, *job_q; + int i; + + unsigned long flags; + + for (i = 0; i < rve_drvdata->num_of_scheduler; i++) { + scheduler = rve_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); + + rve_job_free(job_pos); + + spin_lock_irqsave(&scheduler->irq_lock, flags); + } + } + + spin_unlock_irqrestore(&scheduler->irq_lock, flags); + } +} + static struct rve_job *rve_job_alloc(struct rve_internal_ctx_t *ctx) { struct rve_job *job = NULL; @@ -96,6 +125,7 @@ static struct rve_job *rve_job_alloc(struct rve_internal_ctx_t *ctx) job->core = rve_drvdata->scheduler[0]->core; job->ctx = ctx; ctx->scheduler = job->scheduler; + job->session = ctx->session; if (ctx->priority > 0) { if (ctx->priority > RVE_SCHED_PRIORITY_MAX) @@ -570,7 +600,7 @@ static void rve_input_fence_signaled(struct dma_fence *fence, } #endif -int rve_internal_ctx_alloc_to_get_idr_id(void) +int rve_internal_ctx_alloc_to_get_idr_id(struct rve_session *session) { struct rve_pending_ctx_manager *ctx_manager; struct rve_internal_ctx_t *ctx; @@ -610,6 +640,7 @@ int rve_internal_ctx_alloc_to_get_idr_id(void) ctx->debug_info.pid = current->pid; ctx->debug_info.timestamp = ktime_get(); + ctx->session = session; spin_unlock_irqrestore(&ctx_manager->lock, flags);