From 90172a99bb75aa35ffbb5efa2c0e6af6d233d6b0 Mon Sep 17 00:00:00 2001 From: Cho KyongHo Date: Fri, 13 Jul 2018 17:10:32 +0900 Subject: [PATCH] g2d: fix using virt_to_phys against stack variable If CONFIG_VMAP_STACK is enabled, kernel stack is not physically linear any more. Instead, it is allocated from vmap area and virt_to_phys and similar macros are not available on that area. G2D driver needs to get phyical address of a structure that describes job properties to deliver the information to the secure world if G2D H/W is not capable of protecting secure content leak. Instead allocating the descriptor from the kernel stack, it is now placed in g2d_task. It helps reducing data redundancy because all values of the descriptor are also stored in g2d_task. Change-Id: I91f9c9c5f3806890b4625db87e8b01627d58e5a0 Signed-off-by: Cho KyongHo --- drivers/gpu/exynos/g2d/g2d_command.c | 69 ++++++++++++----------- drivers/gpu/exynos/g2d/g2d_debug.c | 14 ++--- drivers/gpu/exynos/g2d/g2d_drv.c | 13 +++-- drivers/gpu/exynos/g2d/g2d_regs.c | 47 ++++++--------- drivers/gpu/exynos/g2d/g2d_task.c | 12 ++-- drivers/gpu/exynos/g2d/g2d_task.h | 12 +++- drivers/gpu/exynos/g2d/g2d_uapi_process.c | 6 +- 7 files changed, 86 insertions(+), 87 deletions(-) diff --git a/drivers/gpu/exynos/g2d/g2d_command.c b/drivers/gpu/exynos/g2d/g2d_command.c index cdd15e3b776f..2ba17800b995 100644 --- a/drivers/gpu/exynos/g2d/g2d_command.c +++ b/drivers/gpu/exynos/g2d/g2d_command.c @@ -71,7 +71,7 @@ void g2d_init_commands(struct g2d_task *task) { memcpy(page_address(task->cmd_page), &g2d_setup_commands, sizeof(g2d_setup_commands)); - task->cmd_count = ARRAY_SIZE(g2d_setup_commands); + task->sec.cmd_count = ARRAY_SIZE(g2d_setup_commands); } static void g2d_set_taskctl_commands(struct g2d_task *task) @@ -96,15 +96,15 @@ static void g2d_set_taskctl_commands(struct g2d_task *task) if (rot > n_rot) { u32 mode = task->target.commands[G2DSFR_IMG_COLORMODE].value; - regs[task->cmd_count].offset = G2D_TILE_DIRECTION_ORDER_REG; - regs[task->cmd_count].value = G2D_TILE_DIRECTION_VERTICAL; + regs[task->sec.cmd_count].offset = G2D_TILE_DIRECTION_ORDER_REG; + regs[task->sec.cmd_count].value = G2D_TILE_DIRECTION_VERTICAL; if (!IS_HWFC(task->flags) && (IS_YUV420(mode) || IS_YUV422_2P(mode))) - regs[task->cmd_count].value |= + regs[task->sec.cmd_count].value |= G2D_TILE_DIRECTION_ZORDER; - task->cmd_count++; + task->sec.cmd_count++; } /* @@ -112,22 +112,22 @@ static void g2d_set_taskctl_commands(struct g2d_task *task) * and let the H/W work in parallel. * split index is half the width divided by 16 */ - regs[task->cmd_count].offset = G2D_DST_SPLIT_TILE_IDX_REG; - regs[task->cmd_count].value = (layer_width(&task->target) / 2) >> 4; - regs[task->cmd_count].value |= G2D_DST_SPLIT_TILE_IDX_VFLAG; - task->cmd_count++; + regs[task->sec.cmd_count].offset = G2D_DST_SPLIT_TILE_IDX_REG; + regs[task->sec.cmd_count].value = (layer_width(&task->target) / 2) >> 4; + regs[task->sec.cmd_count].value |= G2D_DST_SPLIT_TILE_IDX_VFLAG; + task->sec.cmd_count++; } static void g2d_set_hwfc_commands(struct g2d_task *task) { struct g2d_reg *regs = (struct g2d_reg *)page_address(task->cmd_page); - regs[task->cmd_count].offset = G2D_HWFC_CAPTURE_IDX_REG; - regs[task->cmd_count].value = IS_HWFC(task->flags) ? + regs[task->sec.cmd_count].offset = G2D_HWFC_CAPTURE_IDX_REG; + regs[task->sec.cmd_count].value = IS_HWFC(task->flags) ? G2D_HWFC_CAPTURE_HWFC_JOB : 0; - regs[task->cmd_count].value |= task->job_id; + regs[task->sec.cmd_count].value |= task->sec.job_id; - task->cmd_count++; + task->sec.cmd_count++; } static void g2d_set_start_commands(struct g2d_task *task) @@ -142,10 +142,11 @@ static void g2d_set_start_commands(struct g2d_task *task) * Number of commands should be multiple of 8. * If it is not, then pad dummy commands with no side effect. */ - while ((task->cmd_count & 7) != 0) { - regs[task->cmd_count].offset = G2D_LAYER_UPDATE_REG; - regs[task->cmd_count].value = regs[TASK_REG_LAYER_UPDATE].value; - task->cmd_count++; + while ((task->sec.cmd_count & 7) != 0) { + regs[task->sec.cmd_count].offset = G2D_LAYER_UPDATE_REG; + regs[task->sec.cmd_count].value = + regs[TASK_REG_LAYER_UPDATE].value; + task->sec.cmd_count++; } } @@ -153,7 +154,7 @@ void g2d_complete_commands(struct g2d_task *task) { /* 832 is the total number of the G2D registers */ /* Tuned tone mapping LUT (66 entries) might be specified */ - BUG_ON(task->cmd_count > 896); + BUG_ON(task->sec.cmd_count > 896); g2d_set_taskctl_commands(task); @@ -846,7 +847,7 @@ int g2d_import_commands(struct g2d_device *g2d_dev, struct g2d_task *task, return -EINVAL; } - cmdaddr += task->cmd_count; + cmdaddr += task->sec.cmd_count; copied = g2d_copy_commands(g2d_dev, -1, cmdaddr, cmds->target, target_command_checker, G2DSFR_DST_FIELD_COUNT); @@ -856,7 +857,7 @@ int g2d_import_commands(struct g2d_device *g2d_dev, struct g2d_task *task, task->target.commands = cmdaddr; cmdaddr += copied; - task->cmd_count += copied; + task->sec.cmd_count += copied; for (i = 0; i < num_sources; i++) { u32 srccmds[G2DSFR_SRC_FIELD_COUNT]; @@ -874,7 +875,7 @@ int g2d_import_commands(struct g2d_device *g2d_dev, struct g2d_task *task, task->source[i].commands = cmdaddr; cmdaddr += copied; - task->cmd_count += copied; + task->sec.cmd_count += copied; } if (copy_from_user(cmdaddr, cmds->extra, @@ -887,7 +888,7 @@ int g2d_import_commands(struct g2d_device *g2d_dev, struct g2d_task *task, if (!g2d_validate_extra_command(g2d_dev, cmdaddr, cmds->num_extra_regs)) return -EINVAL; - task->cmd_count += cmds->num_extra_regs; + task->sec.cmd_count += cmds->num_extra_regs; /* overwrite if TM LUT values are specified: consumes 66 entries */ if (exynos_hdr_get_tm_lut(tm_tuned_lut)) { @@ -900,7 +901,7 @@ int g2d_import_commands(struct g2d_device *g2d_dev, struct g2d_task *task, (unsigned long)(base + i * sizeof(u32)); cmdaddr->value = tm_tuned_lut[i]; cmdaddr++; - task->cmd_count++; + task->sec.cmd_count++; } } } @@ -915,7 +916,7 @@ static unsigned int g2d_set_image_buffer(struct g2d_task *task, const struct g2d_fmt *fmt = g2d_find_format(colormode, task->g2d_dev->caps); struct g2d_reg *reg = (struct g2d_reg *)page_address(task->cmd_page); - unsigned int cmd_count = task->cmd_count; + unsigned int cmd_count = task->sec.cmd_count; u32 width = layer_width(layer); u32 height = layer_height(layer); unsigned int i; @@ -1024,17 +1025,17 @@ static unsigned int g2d_set_afbc_buffer(struct g2d_task *task, return 0; } - reg[task->cmd_count].offset = base_offset + reg_offset[2]; - reg[task->cmd_count].value = layer->buffer[0].dma_addr; - reg[task->cmd_count + 1].offset = base_offset + reg_offset[3]; + reg[task->sec.cmd_count].offset = base_offset + reg_offset[2]; + reg[task->sec.cmd_count].value = layer->buffer[0].dma_addr; + reg[task->sec.cmd_count + 1].offset = base_offset + reg_offset[3]; if (base_offset == TARGET_OFFSET) - reg[task->cmd_count + 1].value = + reg[task->sec.cmd_count + 1].value = ALIGN(AFBC_HEADER_SIZE(layer->commands) + layer->buffer[0].dma_addr, align); else - reg[task->cmd_count + 1].value = layer->buffer[0].dma_addr; + reg[task->sec.cmd_count + 1].value = layer->buffer[0].dma_addr; - return task->cmd_count + 2; + return task->sec.cmd_count + 2; } bool g2d_prepare_source(struct g2d_task *task, @@ -1054,7 +1055,7 @@ bool g2d_prepare_source(struct g2d_task *task, if ((layer->flags & G2D_LAYERFLAG_COLORFILL) != 0) return true; - task->cmd_count = ((colormode & G2D_DATAFORMAT_AFBC) != 0) + task->sec.cmd_count = ((colormode & G2D_DATAFORMAT_AFBC) != 0) ? g2d_set_afbc_buffer(task, layer, LAYER_OFFSET(index)) : g2d_set_image_buffer(task, layer, colormode, offsets, LAYER_OFFSET(index)); @@ -1062,18 +1063,18 @@ bool g2d_prepare_source(struct g2d_task *task, * It is alright to set task->cmd_count to 0 * because this task is to be discarded. */ - return task->cmd_count != 0; + return task->sec.cmd_count != 0; } bool g2d_prepare_target(struct g2d_task *task) { u32 colormode = task->target.commands[G2DSFR_IMG_COLORMODE].value; - task->cmd_count = ((colormode & G2D_DATAFORMAT_AFBC) != 0) + task->sec.cmd_count = ((colormode & G2D_DATAFORMAT_AFBC) != 0) ? g2d_set_afbc_buffer(task, &task->target, TARGET_OFFSET) : g2d_set_image_buffer(task, &task->target, colormode, dst_base_reg_offset, TARGET_OFFSET); - return task->cmd_count != 0; + return task->sec.cmd_count != 0; } diff --git a/drivers/gpu/exynos/g2d/g2d_debug.c b/drivers/gpu/exynos/g2d/g2d_debug.c index 4f4e0c2eaeff..9e931ff2420b 100644 --- a/drivers/gpu/exynos/g2d/g2d_debug.c +++ b/drivers/gpu/exynos/g2d/g2d_debug.c @@ -193,9 +193,9 @@ static int g2d_debug_tasks_show(struct seq_file *s, void *unused) for (task = g2d_dev->tasks; task; task = task->next) { seq_printf(s, "TASK[%d]: state %#lx flags %#x ", - task->job_id, task->state, task->flags); + task->sec.job_id, task->state, task->flags); seq_printf(s, "prio %d begin@%llu end@%llu nr_src %d\n", - task->priority, ktime_to_us(task->ktime_begin), + task->sec.priority, ktime_to_us(task->ktime_begin), ktime_to_us(task->ktime_end), task->num_source); } @@ -342,7 +342,7 @@ void g2d_dump_cmd(struct g2d_task *task) regs = page_address(task->cmd_page); - for (i = 0; i < task->cmd_count; i++) + for (i = 0; i < task->sec.cmd_count; i++) pr_info("G2D: CMD[%03d] %#06x, %#010x\n", i, regs[i].offset, regs[i].value); } @@ -365,7 +365,7 @@ void g2d_stamp_task(struct g2d_task *task, u32 stampid, s32 val) if (task) { stamp->state = task->state; - stamp->job_id = task->job_id; + stamp->job_id = task->sec.job_id; } else { stamp->job_id = 0; stamp->state = 0; @@ -380,7 +380,7 @@ void g2d_stamp_task(struct g2d_task *task, u32 stampid, s32 val) if (g2d_debug == 1) { dev_info(task->g2d_dev->dev, "Job %u consumed %06u usec. by H/W\n", - task->job_id, val); + task->sec.job_id, val); } else if (g2d_debug == 2) { g2d_dump_info(task->g2d_dev, task); } @@ -390,8 +390,8 @@ void g2d_stamp_task(struct g2d_task *task, u32 stampid, s32 val) /* media/exynos_tsmux.h includes below functions */ if (task != NULL && IS_HWFC(task->flags)) { if (stampid == G2D_STAMP_STATE_PUSH) - g2d_blending_start(task->job_id); + g2d_blending_start(task->sec.job_id); if (stampid == G2D_STAMP_STATE_DONE) - g2d_blending_end(task->job_id); + g2d_blending_end(task->sec.job_id); } } diff --git a/drivers/gpu/exynos/g2d/g2d_drv.c b/drivers/gpu/exynos/g2d/g2d_drv.c index e0d90217a644..d5ec2a07b928 100644 --- a/drivers/gpu/exynos/g2d/g2d_drv.c +++ b/drivers/gpu/exynos/g2d/g2d_drv.c @@ -57,7 +57,8 @@ static int g2d_update_priority(struct g2d_context *ctx, spin_lock_irqsave(&g2d_dev->lock_task, flags); for (task = g2d_dev->tasks; task != NULL; task = task->next) { - if (!is_task_state_idle(task) && (task->priority < priority)) { + if (!is_task_state_idle(task) && + (task->sec.priority < priority)) { spin_unlock_irqrestore(&g2d_dev->lock_task, flags); return -EBUSY; } @@ -77,13 +78,13 @@ void g2d_hw_timeout_handler(unsigned long arg) spin_lock_irqsave(&g2d_dev->lock_task, flags); - job_state = g2d_hw_get_job_state(g2d_dev, task->job_id); + job_state = g2d_hw_get_job_state(g2d_dev, task->sec.job_id); g2d_stamp_task(task, G2D_STAMP_STATE_TIMEOUT_HW, job_state); dev_err(g2d_dev->dev, "%s: Time is up: %d msec for job %u %lu %u\n", __func__, G2D_HW_TIMEOUT_MSEC, - task->job_id, task->state, job_state); + task->sec.job_id, task->state, job_state); if (!is_task_state_active(task)) /* @@ -124,7 +125,7 @@ void g2d_hw_timeout_handler(unsigned long arg) mark_task_state_killed(task); - g2d_hw_kill_task(g2d_dev, task->job_id); + g2d_hw_kill_task(g2d_dev, task->sec.job_id); out: spin_unlock_irqrestore(&g2d_dev->lock_task, flags); @@ -143,7 +144,7 @@ int g2d_device_run(struct g2d_device *g2d_dev, struct g2d_task *task) task->ktime_begin = ktime_get(); if (IS_HWFC(task->flags)) - hwfc_set_valid_buffer(task->job_id, task->job_id); + hwfc_set_valid_buffer(task->sec.job_id, task->sec.job_id); return 0; } @@ -413,7 +414,7 @@ static long g2d_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } - g2d_stamp_task(task, G2D_STAMP_STATE_BEGIN, task->priority); + g2d_stamp_task(task, G2D_STAMP_STATE_BEGIN, task->sec.priority); g2d_start_task(task); diff --git a/drivers/gpu/exynos/g2d/g2d_regs.c b/drivers/gpu/exynos/g2d/g2d_regs.c index 7e3540c749d4..fd3ae69d0a72 100644 --- a/drivers/gpu/exynos/g2d/g2d_regs.c +++ b/drivers/gpu/exynos/g2d/g2d_regs.c @@ -25,40 +25,27 @@ #include "g2d_debug.h" #include "g2d_secure.h" -struct g2d_task_secbuf { - unsigned long cmd_paddr; - int cmd_count; - int priority; - int job_id; - int secure_layer; -}; - static void g2d_hw_push_task_by_smc(struct g2d_device *g2d_dev, struct g2d_task *task) { - struct g2d_task_secbuf sec_task; int i; - sec_task.cmd_paddr = (unsigned long)page_to_phys(task->cmd_page); - sec_task.cmd_count = task->cmd_count; - sec_task.priority = task->priority; - sec_task.job_id = task->job_id; - sec_task.secure_layer = 0; + task->sec.secure_layer_mask = 0; - for (i = 0; i < task->num_source; i++) { + for (i = 0; i < task->num_source; i++) if (!!(task->source[i].flags & G2D_LAYERFLAG_SECURE)) - sec_task.secure_layer |= 1 << i; - } + task->sec.secure_layer_mask |= 1 << i; + if (!!(task->target.flags & G2D_LAYERFLAG_SECURE) || - !!(sec_task.secure_layer)) - sec_task.secure_layer |= 1 << 24; + !!(task->sec.secure_layer_mask)) + task->sec.secure_layer_mask |= 1 << 24; - __flush_dcache_area(&sec_task, sizeof(sec_task)); + __flush_dcache_area(&task->sec, sizeof(task->sec)); __flush_dcache_area(page_address(task->cmd_page), G2D_CMD_LIST_SIZE); - if (exynos_smc(SMC_DRM_G2D_CMD_DATA, virt_to_phys(&sec_task), 0, 0)) { + if (exynos_smc(SMC_DRM_G2D_CMD_DATA, virt_to_phys(&task->sec), 0, 0)) { dev_err(g2d_dev->dev, "%s : Failed to push %d %d %d %d\n", - __func__, sec_task.cmd_count, sec_task.priority, - sec_task.job_id, sec_task.secure_layer); + __func__, task->sec.cmd_count, task->sec.priority, + task->sec.job_id, task->sec.secure_layer_mask); g2d_dump_info(g2d_dev, task); BUG(); @@ -68,11 +55,11 @@ static void g2d_hw_push_task_by_smc(struct g2d_device *g2d_dev, void g2d_hw_push_task(struct g2d_device *g2d_dev, struct g2d_task *task) { bool self_prot = g2d_dev->caps & G2D_DEVICE_CAPS_SELF_PROTECTION; - u32 state = g2d_hw_get_job_state(g2d_dev, task->job_id); + u32 state = g2d_hw_get_job_state(g2d_dev, task->sec.job_id); if (state != G2D_JOB_STATE_DONE) dev_err(g2d_dev->dev, "%s: Unexpected state %#x of JOB %d\n", - __func__, state, task->job_id); + __func__, state, task->sec.job_id); if (IS_ENABLED(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)) { unsigned int i; @@ -93,17 +80,19 @@ void g2d_hw_push_task(struct g2d_device *g2d_dev, struct g2d_task *task) writel_relaxed(state, g2d_dev->reg + - G2D_JOBn_LAYER_SECURE_REG(task->job_id)); + G2D_JOBn_LAYER_SECURE_REG(task->sec.job_id)); } - writel_relaxed(G2D_JOB_HEADER_DATA(task->priority, task->job_id), + writel_relaxed(G2D_JOB_HEADER_DATA(task->sec.priority, + task->sec.job_id), g2d_dev->reg + G2D_JOB_HEADER_REG); writel_relaxed(G2D_ERR_INT_ENABLE, g2d_dev->reg + G2D_INTEN_REG); writel_relaxed(task->cmd_addr, g2d_dev->reg + G2D_JOB_BASEADDR_REG); - writel_relaxed(task->cmd_count, g2d_dev->reg + G2D_JOB_SFRNUM_REG); - writel_relaxed(1 << task->job_id, g2d_dev->reg + G2D_JOB_INT_ID_REG); + writel_relaxed(task->sec.cmd_count, g2d_dev->reg + G2D_JOB_SFRNUM_REG); + writel_relaxed(1 << task->sec.job_id, + g2d_dev->reg + G2D_JOB_INT_ID_REG); writel(G2D_JOBPUSH_INT_ENABLE, g2d_dev->reg + G2D_JOB_PUSH_REG); } diff --git a/drivers/gpu/exynos/g2d/g2d_task.c b/drivers/gpu/exynos/g2d/g2d_task.c index 671bee037cd5..61ca6b937377 100644 --- a/drivers/gpu/exynos/g2d/g2d_task.c +++ b/drivers/gpu/exynos/g2d/g2d_task.c @@ -68,7 +68,7 @@ struct g2d_task *g2d_get_active_task_from_id(struct g2d_device *g2d_dev, struct g2d_task *task; list_for_each_entry(task, &g2d_dev->tasks_active, node) { - if (task->job_id == id) + if (task->sec.job_id == id) return task; } @@ -156,7 +156,7 @@ void g2d_flush_all_tasks(struct g2d_device *g2d_dev) struct g2d_task, node); dev_err(g2d_dev->dev, "%s: Flushed task of ID %d\n", - __func__, task->job_id); + __func__, task->sec.job_id); mark_task_state_killed(task); @@ -346,7 +346,7 @@ struct g2d_task *g2d_get_free_task(struct g2d_device *g2d_dev, INIT_WORK(&task->work, g2d_task_schedule_work); init_task_state(task); - task->priority = g2d_ctx->priority; + task->sec.priority = g2d_ctx->priority; g2d_init_commands(task); @@ -369,7 +369,7 @@ void g2d_put_free_task(struct g2d_device *g2d_dev, struct g2d_task *task) if (IS_HWFC(task->flags)) { /* hwfc job id will be set from repeater driver info */ - task->job_id = G2D_MAX_JOBS; + task->sec.job_id = G2D_MAX_JOBS; list_add(&task->node, &g2d_dev->tasks_free_hwfc); } else { list_add(&task->node, &g2d_dev->tasks_free); @@ -430,7 +430,7 @@ static struct g2d_task *g2d_create_task(struct g2d_device *g2d_dev, int id) goto err_page; } - task->job_id = id; + task->sec.job_id = id; task->bufidx = -1; task->g2d_dev = g2d_dev; @@ -438,6 +438,8 @@ static struct g2d_task *g2d_create_task(struct g2d_device *g2d_dev, int id) if (ret) goto err_map; + task->sec.cmd_paddr = (unsigned long)page_to_phys(task->cmd_page); + for (i = 0; i < g2d_dev->max_layers; i++) task->source[i].task = task; task->target.task = task; diff --git a/drivers/gpu/exynos/g2d/g2d_task.h b/drivers/gpu/exynos/g2d/g2d_task.h index 79d912f18a84..6e00ee8efe6f 100644 --- a/drivers/gpu/exynos/g2d/g2d_task.h +++ b/drivers/gpu/exynos/g2d/g2d_task.h @@ -88,7 +88,6 @@ struct g2d_task { struct g2d_device *g2d_dev; unsigned int flags; - unsigned int job_id; unsigned int bufidx; unsigned long state; struct sync_file *release_fence; @@ -103,9 +102,16 @@ struct g2d_task { /* Command list */ struct page *cmd_page; dma_addr_t cmd_addr; - unsigned int cmd_count; - unsigned int priority; + struct { + unsigned long cmd_paddr; + unsigned int cmd_count; + unsigned int priority; + unsigned int job_id; + /* temporarily used by g2d_hw_push_task_by_smc */ + int secure_layer_mask; + } sec; + ktime_t ktime_begin; ktime_t ktime_end; diff --git a/drivers/gpu/exynos/g2d/g2d_uapi_process.c b/drivers/gpu/exynos/g2d/g2d_uapi_process.c index e3a1aeb9b9c6..3e49fa321314 100644 --- a/drivers/gpu/exynos/g2d/g2d_uapi_process.c +++ b/drivers/gpu/exynos/g2d/g2d_uapi_process.c @@ -210,7 +210,7 @@ static int g2d_get_dmabuf(struct g2d_task *task, return PTR_ERR(dmabuf); } } else { - dmabuf = ctx->hwfc_info->bufs[task->job_id]; + dmabuf = ctx->hwfc_info->bufs[task->sec.job_id]; get_dma_buf(dmabuf); } @@ -681,7 +681,7 @@ static int g2d_get_target(struct g2d_device *g2d_dev, struct g2d_context *ctx, ptask = ptask->next; continue; } - if ((ptask->job_id == task->bufidx) && + if ((ptask->sec.job_id == task->bufidx) && !is_task_state_idle(ptask)) { dev_err(dev, "%s: The %d task is not idle\n", __func__, task->bufidx); @@ -696,7 +696,7 @@ static int g2d_get_target(struct g2d_device *g2d_dev, struct g2d_context *ctx, g2d_stamp_task(task, G2D_STAMP_STATE_HWFCBUF, task->bufidx); - task->job_id = task->bufidx; + task->sec.job_id = task->bufidx; spin_unlock_irqrestore(&task->g2d_dev->lock_task, flags); -- 2.20.1