MLK-21507 VPU Decoder: kernel panic if seek when video playing
authorShijie Qin <shijie.qin@nxp.com>
Sat, 20 Apr 2019 07:17:57 +0000 (15:17 +0800)
committerShijie Qin <shijie.qin@nxp.com>
Mon, 22 Apr 2019 09:45:46 +0000 (17:45 +0800)
    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
[<ffff000008bce7f4>] wait_right_buffer+0x60/0xac
[<ffff000008bd28f0>] vpu_api_event_handler+0xc64/0x1990
[<ffff000008bd3704>] vpu_msg_instance_work+0xe8/0x12c
[<ffff0000080f8518>] process_one_work+0x140/0x3f8
[<ffff0000080f8908>] worker_thread+0x138/0x3e4
[<ffff0000080fed70>] kthread+0x104/0x130
[<ffff000008085064>] ret_from_fork+0x10/0x18

Signed-off-by: Shijie Qin <shijie.qin@nxp.com>
drivers/mxc/vpu_malone/vpu_b0.c

index 8b2a318..acaddff 100644 (file)
@@ -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))