vdec: avoid decoder run and work executing at the same time [1/1]
authorapollo.ling <apollo.ling@amlogic.com>
Fri, 22 May 2020 07:18:29 +0000 (15:18 +0800)
committerApollo Ling <apollo.ling@amlogic.com>
Fri, 4 Sep 2020 11:51:37 +0000 (04:51 -0700)
PD#SWPL-26671

Problem:
decoder run and work executing at same time will causes race conditions

Solution:
avoid decoder run and work executing at the same time

Verify:
u212

Change-Id: I9e16c7cebc6fb7d0bc36f749d7bc430c515e6c6a
Signed-off-by: apollo.ling <apollo.ling@amlogic.com>
drivers/frame_provider/decoder/avs2/vavs2.c
drivers/frame_provider/decoder/avs_multi/avs_multi.c
drivers/frame_provider/decoder/h264_multi/vmh264.c
drivers/frame_provider/decoder/h265/vh265.c
drivers/frame_provider/decoder/mjpeg/vmjpeg_multi.c
drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c
drivers/frame_provider/decoder/mpeg4/vmpeg4_multi.c
drivers/frame_provider/decoder/utils/vdec.c
drivers/frame_provider/decoder/utils/vdec.h
drivers/frame_provider/decoder/vav1/vav1.c
drivers/frame_provider/decoder/vp9/vvp9.c

index 5504dd3b9b164ce17d4355dc909529c2f56e9a51..53e10a5a8bd4f9e3bb4a36094ba7da86891875c7 100644 (file)
@@ -6946,6 +6946,12 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
 
        if (dec->eos)
                return ret;
+       if (work_pending(&dec->work) ||
+           work_busy(&dec->work)) {
+               avs2_print(dec, PRINT_FLAG_VDEC_DETAIL,
+                          "avs2 work pending,not ready for run.\n");
+               return 0;
+       }
        if (!dec->first_sc_checked) {
                int size = decoder_mmu_box_sc_check(dec->mmu_box, tvp);
                dec->first_sc_checked = 1;
index 1f62c204b4e6b4d8f9de10cd07ea270633663007..0a6da7cf588aa05ecb65ebb37c0042fe7a333c4f 100644 (file)
@@ -2494,6 +2494,14 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
        (struct vdec_avs_hw_s *)vdec->private;
        int ret = 1;
        unsigned buf_busy_mask = (1 << hw->vf_buf_num_used) - 1;
+
+       if (work_pending(&hw->work) ||
+           work_busy(&hw->work)) {
+               debug_print(hw, PRINT_FLAG_RUN_FLOW,
+                          "avs work pending,not ready for run.\n");
+               return 0;
+       }
+
 #ifdef DEBUG_MULTI_FRAME_INS
        if ((DECODE_ID(hw) == 0) && run_count[0] > run_count[1] &&
                run_count[1] < max_run_count[1])
index 58fe8000539fa8a2cb705fe39eaebb1614694c75..c918618a19813c54acf5b0417d338225c75de443 100644 (file)
@@ -6879,10 +6879,16 @@ static void timeout_process(struct vdec_h264_hw_s *hw)
 
        /*
         * In this very timeout point,the vh264_work arrives,
-        * let it to handle the scenario.
+        * or in some cases the system become slow,  then come
+        * this second timeout. In both cases we return.
         */
-       if (work_pending(&hw->work))
+       if (work_pending(&hw->work) ||
+           work_busy(&hw->work) ||
+           work_pending(&hw->timeout_work) ||
+           work_busy(&hw->timeout_work)) {
+               pr_err("%s h264[%d] work pending, do nothing.\n",__func__, vdec->id);
                return;
+       }
 
        hw->timeout_num++;
        amvdec_stop();
@@ -8990,6 +8996,14 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
        int tvp = vdec_secure(hw_to_vdec(hw)) ?
                CODEC_MM_FLAGS_TVP : 0;
 
+       if (work_pending(&hw->work) ||
+           work_busy(&hw->work) ||
+           work_pending(&hw->timeout_work) ||
+           work_busy(&hw->timeout_work)) {
+               dpb_print(DECODE_ID(hw), PRINT_FLAG_VDEC_DETAIL,
+                         "h264 work pending, not ready for run.\n");
+               return 0;
+       }
        if (!hw->first_sc_checked && hw->mmu_enable) {
                int size = decoder_mmu_box_sc_check(hw->mmu_box, tvp);
                hw->first_sc_checked =1;
index 2dfde743adc618982983a845b317c891b8e84808..06a2957caed431bb481099b7265da2a16ccfecf7 100644 (file)
@@ -12077,13 +12077,16 @@ static void timeout_process(struct hevc_state_s *hevc)
 {
        /*
         * In this very timeout point,the vh265_work arrives,
-        * let it to handle the scenario.
+        * or in some cases the system become slow,  then come
+        * this second timeout. In both cases we return.
         */
        if (work_pending(&hevc->work) ||
            work_busy(&hevc->work) ||
            work_pending(&hevc->timeout_work) ||
-           work_busy(&hevc->timeout_work))
+           work_pending(&hevc->timeout_work)) {
+               pr_err("%s h265[%d] work pending, do nothing.\n",__func__, hevc->index);
                return;
+       }
 
        hevc->timeout_num++;
        amhevc_stop();
@@ -12867,6 +12870,14 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
 
        if (hevc->eos)
                return 0;
+       if (work_pending(&hevc->work) ||
+           work_busy(&hevc->work) ||
+           work_pending(&hevc->timeout_work) ||
+           work_pending(&hevc->timeout_work)) {
+               hevc_print(hevc, PRINT_FLAG_VDEC_STATUS,
+                          "h265 work pending,not ready for run.\n");
+               return 0;
+       }
        if (!hevc->first_sc_checked && hevc->mmu_enable) {
                int size = decoder_mmu_box_sc_check(hevc->mmu_box, tvp);
                hevc->first_sc_checked =1;
index 44e238bd6cff5de4d5593a6be57d385a7bdaaa42..583aa42f3769520784f7a486c9a6ca6b2824974b 100644 (file)
@@ -1255,6 +1255,12 @@ static unsigned long run_ready(struct vdec_s *vdec,
        hw->not_run_ready++;
        if (hw->eos)
                return 0;
+       if (work_pending(&hw->work) ||
+           work_busy(&hw->work)) {
+               mmjpeg_debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW,
+                          "mjpeg work pending,not ready for run.\n");
+               return 0;
+       }
        if (vdec_stream_based(vdec) && (hw->init_flag == 0)
                && pre_decode_buf_level != 0) {
                u32 rp, wp, level;
index 03c420a25f755fa5a3cbad5adcbd80d7facfdef4..31e27bde815015bf24ba05c3ea271047e88085f4 100644 (file)
@@ -2730,8 +2730,11 @@ static void timeout_process(struct vdec_mpeg12_hw_s *hw)
 {
        struct vdec_s *vdec = hw_to_vdec(hw);
 
-       if (work_pending(&hw->work)) {
-               pr_err("timeout_process return befor do anything.");
+       if (work_pending(&hw->work) ||
+           work_busy(&hw->work) ||
+           work_pending(&hw->timeout_work) ||
+           work_busy(&hw->timeout_work)) {
+               pr_err("%s mpeg12[%d] timeout_process return befor do anything.\n",__func__, vdec->id);
                return;
        }
        reset_process_time(hw);
@@ -2748,7 +2751,7 @@ static void timeout_process(struct vdec_mpeg12_hw_s *hw)
         * let it to handle the scenario.
         */
        if (work_pending(&hw->work)) {
-               pr_err("timeout_process return befor schedule.");
+               pr_err("%s mpeg12[%d] return befor schedule.", __func__, vdec->id);
                return;
        }
        vdec_schedule_work(&hw->timeout_work);
@@ -3046,6 +3049,14 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
                (struct vdec_mpeg12_hw_s *)vdec->private;
        if (hw->eos)
                return 0;
+       if (work_pending(&hw->work) ||
+           work_busy(&hw->work) ||
+           work_pending(&hw->timeout_work) ||
+           work_busy(&hw->timeout_work)) {
+               debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+                       "mpeg12 work pending,not ready for run.\n");
+               return 0;
+       }
        if (vdec_stream_based(vdec) && (hw->init_flag == 0)
                && pre_decode_buf_level != 0) {
                u32 rp, wp, level;
@@ -3146,6 +3157,7 @@ void (*callback)(struct vdec_s *, void *),
                (struct vdec_mpeg12_hw_s *)vdec->private;
        int save_reg = READ_VREG(POWER_CTL_VLD);
        int size, ret;
+
        /* reset everything except DOS_TOP[1] and APB_CBUS[0]*/
        WRITE_VREG(DOS_SW_RESET0, 0xfffffff0);
        WRITE_VREG(DOS_SW_RESET0, 0);
index ec568a1470d0260c2d1587ac274e9015d80dd72c..5d69fedf66c6f1221352c4f234865ecae96c4a0b 100644 (file)
@@ -2259,6 +2259,12 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
 
        if (hw->eos)
                return 0;
+       if (work_pending(&hw->work) ||
+           work_busy(&hw->work)) {
+               mmpeg4_debug_print(DECODE_ID(hw), PRINT_FLAG_VDEC_STATUS,
+                          "mpeg4 work pending,not ready for run.\n");
+               return 0;
+       }
        if (vdec_stream_based(vdec) && (hw->init_flag == 0)
                && pre_decode_buf_level != 0) {
                u32 rp, wp, level;
index 3a85cbb8fac4cff55797d5f1547454e562694595..092e63d25334357ae176c7efdabcba2f92ef725a 100644 (file)
@@ -2249,9 +2249,6 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k)
        p->get_canvas_ex = get_canvas_ex;
        p->free_canvas_ex = free_canvas_ex;
        p->vdec_fps_detec = vdec_fps_detec;
-       atomic_set(&p->inrelease, 0);
-       atomic_set(&p->inirq_flag, 0);
-       atomic_set(&p->inirq_thread_flag, 0);
        /* todo */
        if (!vdec_dual(vdec)) {
                p->use_vfm_path =
@@ -2668,9 +2665,7 @@ void vdec_release(struct vdec_s *vdec)
                }
        }
 
-       atomic_set(&vdec->inrelease, 1);
-       while ((atomic_read(&vdec->inirq_flag) > 0)
-               || (atomic_read(&vdec->inirq_thread_flag) > 0))
+       while (vdec->irq_cnt > vdec->irq_thread_cnt)
                schedule();
 
 #ifdef FRAME_CHECK
@@ -2919,11 +2914,6 @@ static irqreturn_t vdec_isr(int irq, void *dev_id)
                        vdec = NULL;
        }
 
-       if (vdec) {
-               if (atomic_read(&vdec->inrelease) > 0)
-                       return ret;
-               atomic_set(&vdec->inirq_flag, 1);
-       }
        if (c->dev_isr) {
                ret = c->dev_isr(irq, c->dev_id);
                goto isr_done;
@@ -2955,8 +2945,9 @@ static irqreturn_t vdec_isr(int irq, void *dev_id)
 
        ret = vdec->irq_handler(vdec, c->index);
 isr_done:
-       if (vdec)
-               atomic_set(&vdec->inirq_flag, 0);
+       if (vdec && ret == IRQ_WAKE_THREAD)
+               vdec->irq_cnt++;
+
        return ret;
 }
 
@@ -2976,11 +2967,6 @@ static irqreturn_t vdec_thread_isr(int irq, void *dev_id)
                        vdec = NULL;
        }
 
-       if (vdec) {
-               if (atomic_read(&vdec->inrelease) > 0)
-                       return ret;
-               atomic_set(&vdec->inirq_thread_flag, 1);
-       }
        if (c->dev_threaded_isr) {
                ret = c->dev_threaded_isr(irq, c->dev_id);
                goto thread_isr_done;
@@ -2993,7 +2979,7 @@ static irqreturn_t vdec_thread_isr(int irq, void *dev_id)
        ret = vdec->threaded_irq_handler(vdec, c->index);
 thread_isr_done:
        if (vdec)
-               atomic_set(&vdec->inirq_thread_flag, 0);
+               vdec->irq_thread_cnt++;
        return ret;
 }
 
@@ -3001,6 +2987,11 @@ unsigned long vdec_ready_to_run(struct vdec_s *vdec, unsigned long mask)
 {
        unsigned long ready_mask;
        struct vdec_input_s *input = &vdec->input;
+
+       /* Wait the matching irq_thread finished */
+       if (vdec->irq_cnt > vdec->irq_thread_cnt)
+               return false;
+
        if ((vdec->status != VDEC_STATUS_CONNECTED) &&
            (vdec->status != VDEC_STATUS_ACTIVE))
                return false;
@@ -3340,6 +3331,7 @@ static int vdec_core_thread(void *data)
                        inc_profi_count(mask, vdec->run_count);
                        update_profi_clk_run(vdec, mask, get_current_clk());
 #endif
+
                        vdec->run(vdec, mask, vdec_callback, core);
 
 
index a7bf13e197264b3ee044d71c85ab8587939f43fb..c80005123fc2cf9afb0e294c5820141d416534ce 100644 (file)
@@ -269,9 +269,8 @@ struct vdec_s {
        u64 run_clk[VDEC_MAX];
        u64 start_run_clk[VDEC_MAX];
 #endif
-       atomic_t inirq_thread_flag;
-       atomic_t inirq_flag;
-       atomic_t inrelease;
+       u64 irq_thread_cnt;
+       u64 irq_cnt;
        int parallel_dec;
        struct vdec_frames_s *mvfrm;
        struct vdec_sync sync;
index f46c25b7df5efa33ecbf02647b2803e97621ca0c..c4e81b3ece24f2c9bc3f2adbebae84781602bad3 100644 (file)
@@ -9543,6 +9543,12 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
                CODEC_MM_FLAGS_TVP : 0;
        unsigned long ret = 0;
 
+       if (work_pending(&hw->work) ||
+           work_busy(&hw->work)) {
+               av1_print(hw, PRINT_FLAG_VDEC_DETAIL,
+                          "av1 work pending,not ready for run.\n");
+               return 0;
+       }
        if (!hw->pic_list_init_done2 || hw->eos)
                return ret;
 
index 5717d608f073f4c35b94ade0d5604af67725d4a2..924af1691adc577c4dd16d2e5705b11241d07375 100644 (file)
@@ -10084,6 +10084,12 @@ static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask)
                CODEC_MM_FLAGS_TVP : 0;
        unsigned long ret = 0;
 
+       if (work_pending(&pbi->work) ||
+           work_busy(&pbi->work)) {
+               vp9_print(pbi, PRINT_FLAG_VDEC_DETAIL,
+                         "vp9 work pending,not ready for run.\n");
+               return 0;
+       }
        if (!(pbi->pic_list_init_done && pbi->pic_list_init_done2) || pbi->eos)
                return ret;
        if (!pbi->first_sc_checked && pbi->mmu_enable) {