From 4e92d1538cff448e1d3c5c6c5852932b97ecaf0e Mon Sep 17 00:00:00 2001 From: Shijie Qin Date: Sat, 20 Apr 2019 15:17:57 +0800 Subject: [PATCH] MLK-21507 VPU Decoder: kernel panic if seek when video playing The same buffer prepend to the list twice at 'VID_API_EVENT_REL_FRAME_BUFF'event and vpu_buf_queue() cause list form a dead cycle. Add an verification before prepend to list at vpu_buf_queue(). Unable to handle kernel paging request at virtual address dead000000000100 [] wait_right_buffer+0x60/0xac [] vpu_api_event_handler+0xc64/0x1990 [] vpu_msg_instance_work+0xe8/0x12c [] process_one_work+0x140/0x3f8 [] worker_thread+0x138/0x3e4 [] kthread+0x104/0x130 [] ret_from_fork+0x10/0x18 Signed-off-by: Shijie Qin --- drivers/mxc/vpu_malone/vpu_b0.c | 42 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/drivers/mxc/vpu_malone/vpu_b0.c b/drivers/mxc/vpu_malone/vpu_b0.c index 8b2a3186d932..acaddff11f3a 100644 --- a/drivers/mxc/vpu_malone/vpu_b0.c +++ b/drivers/mxc/vpu_malone/vpu_b0.c @@ -84,6 +84,8 @@ static void send_skip_event(struct vpu_ctx* ctx); static void reset_mbi_dcp_count(struct vpu_ctx *ctx); static bool verify_frame_buffer_size(struct queue_data *q_data, struct vb2_data_req *p_data_req); +static void add_buffer_to_queue(struct queue_data *q_data, struct vb2_data_req *data_req); + #define CHECK_BIT(var, pos) (((var) >> (pos)) & 1) static char *cmd2str[] = { @@ -2460,22 +2462,21 @@ static void report_buffer_done(struct vpu_ctx *ctx, void *frame_info) static bool wait_right_buffer(struct queue_data *This) { struct vb2_data_req *p_data_req, *p_temp; + bool ret = false; down(&This->drv_q_lock); - if (!list_empty(&This->drv_q)) { - list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) - if (p_data_req->status == FRAME_ALLOC - || p_data_req->status == FRAME_RELEASE) { - up(&This->drv_q_lock); - if (verify_frame_buffer_size(This, p_data_req)) - return true; - else - return false; - } + + list_for_each_entry_safe(p_data_req, p_temp, &This->drv_q, list) { + if (p_data_req->status == FRAME_ALLOC + || p_data_req->status == FRAME_RELEASE) { + if (verify_frame_buffer_size(This, p_data_req)) + ret = true; + break; + } } up(&This->drv_q_lock); - return false; + return ret; } static void send_skip_event(struct vpu_ctx* ctx) @@ -2518,6 +2519,16 @@ static bool verify_frame_buffer_size(struct queue_data *q_data, return false; } +static void add_buffer_to_queue(struct queue_data *q_data, struct vb2_data_req *data_req) +{ + if (!q_data || !data_req) + return; + if (data_req->queued == true) + return; + list_add_tail(&data_req->list, &q_data->drv_q); + data_req->queued = true; +} + static u32 get_consumed_pic_bytesused(struct vpu_ctx *ctx, u32 pic_start_addr, u32 pic_end_addr) @@ -2926,11 +2937,9 @@ static void vpu_api_event_handler(struct vpu_ctx *ctx, u_int32 uStrIdx, u_int32 vpu_dbg(LVL_WARN, "warning: normal release and previous status %s, frame not for display, queue the buffer to list again\n", bufstat[p_data_req->status]); - if ((p_data_req->status == FRAME_DECODED || p_data_req->status == FRAME_FREE) - && p_data_req->queued == false) { + if ((p_data_req->status == FRAME_DECODED || p_data_req->status == FRAME_FREE)) { v4l2_event_queue_fh(&ctx->fh, &ev); - list_add_tail(&p_data_req->list, &This->drv_q); - p_data_req->queued = true; + add_buffer_to_queue(This, p_data_req); } } set_data_req_status(p_data_req, FRAME_RELEASE); @@ -3437,8 +3446,7 @@ static void vpu_buf_queue(struct vb2_buffer *vb) data_req->phy_addr[1] = *pphy_address_1; } if (data_req->status != FRAME_FREE && data_req->status != FRAME_DECODED) { - list_add_tail(&data_req->list, &This->drv_q); - data_req->queued = true; + add_buffer_to_queue(This, data_req); } else { } if (V4L2_TYPE_IS_OUTPUT(vq->type)) -- 2.17.1