mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 03:15:31 +09:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user