author | apollo.ling <apollo.ling@amlogic.com> | 2019-10-17 12:31:08 (GMT) |
---|---|---|
committer | Apollo Ling <apollo.ling@amlogic.com> | 2019-10-29 02:04:47 (GMT) |
commit | bdf00f956395d7169988436b23122a6816694464 (patch) | |
tree | 4501f2f2b6efe585f8b3ef176764152f6308380a | |
parent | b0f90dfa1fbf955fb3f6df6f94037f38d734c018 (diff) | |
download | media_modules-bdf00f956395d7169988436b23122a6816694464.zip media_modules-bdf00f956395d7169988436b23122a6816694464.tar.gz media_modules-bdf00f956395d7169988436b23122a6816694464.tar.bz2 |
vdec: improve timeout handling for vmmpeg12/vmmh264/vmmh265 [1/1]
PD#SWPL-14196
Problem:
{stress test} trunk crash and watchdog reboot happen when
do DTV h264 2s channel switch and 15s suspend.(1/5,none)
Solution:
improve the timout handling mechanism
Verify:
X301
Change-Id: Id7bad614c3aff15630daef13ac598e3a86405e01
Signed-off-by: apollo.ling <apollo.ling@amlogic.com>
-rw-r--r-- | drivers/frame_provider/decoder/h264_multi/vmh264.c | 84 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/h265/vh265.c | 56 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c | 63 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/vdec.c | 13 | ||||
-rw-r--r-- | drivers/frame_provider/decoder/utils/vdec.h | 2 |
5 files changed, 187 insertions, 31 deletions
diff --git a/drivers/frame_provider/decoder/h264_multi/vmh264.c b/drivers/frame_provider/decoder/h264_multi/vmh264.c index bd1cd1f..4992872 100644 --- a/drivers/frame_provider/decoder/h264_multi/vmh264.c +++ b/drivers/frame_provider/decoder/h264_multi/vmh264.c @@ -483,6 +483,7 @@ static void vh264_vf_put(struct vframe_s *, void *); static int vh264_vf_states(struct vframe_states *states, void *); static int vh264_event_cb(int type, void *data, void *private_data); static void vh264_work(struct work_struct *work); +static void vh264_timeout_work(struct work_struct *work); static void vh264_notify_work(struct work_struct *work); #ifdef MH264_USERDATA_ENABLE static void user_data_ready_notify_work(struct work_struct *work); @@ -846,10 +847,13 @@ struct vdec_h264_hw_s { bool new_iframe_flag; bool ref_err_flush_dpb_flag; unsigned int first_i_policy; + u32 tfn_cnt; + u64 tfn_ns; }; static u32 again_threshold; +static void timeout_process(struct vdec_h264_hw_s *hw); static void dump_bufspec(struct vdec_h264_hw_s *hw, const char *caller); static void h264_reconfig(struct vdec_h264_hw_s *hw); @@ -5327,6 +5331,20 @@ static irqreturn_t vh264_isr_thread_fn(struct vdec_s *vdec, int irq) unsigned int dec_dpb_status = p_H264_Dpb->dec_dpb_status; u32 debug_tag; int ret; + if (++hw->tfn_cnt == 1) { + hw->tfn_ns = local_clock(); + } else if (hw->tfn_cnt >= 10) { + u64 tenth_ns = local_clock(); + /* Here borrow the varible debug_tag for use */ + debug_tag = tenth_ns - hw->tfn_ns; + hw->tfn_cnt = 1; + hw->tfn_cnt = tenth_ns; + if (debug_tag <= 10000000) { + pr_err("Within 10ms 10 vh264_isr_thread_fn. Abnormal!\n"); + timeout_process(hw); + return IRQ_HANDLED; + } + } if (dec_dpb_status == H264_CONFIG_REQUEST) { #if 1 @@ -6210,6 +6228,13 @@ static void timeout_process(struct vdec_h264_hw_s *hw) struct vdec_s *vdec = hw_to_vdec(hw); struct h264_dpb_stru *p_H264_Dpb = &hw->dpb; + /* + * In this very timeout point,the vh264_work arrives, + * let it to handle the scenario. + */ + if (work_pending(&hw->work)) + return; + hw->timeout_num++; amvdec_stop(); vdec->mc_loaded = 0; @@ -6224,7 +6249,10 @@ static void timeout_process(struct vdec_h264_hw_s *hw) release_cur_decoding_buf(hw); hw->dec_result = DEC_RESULT_DONE; hw->data_flag |= ERROR_FLAG; - vdec_schedule_work(&hw->work); + + if (work_pending(&hw->work)) + return; + vdec_schedule_work(&hw->timeout_work); } static void dump_bufspec(struct vdec_h264_hw_s *hw, @@ -6454,7 +6482,7 @@ static void check_timer_func(unsigned long arg) if (hw->decode_timeout_count == 0) { reset_process_time(hw); - vdec_schedule_work(&hw->timeout_work); + timeout_process(hw); } } else start_process_time(hw); @@ -6466,7 +6494,7 @@ static void check_timer_func(unsigned long arg) if (hw->decode_timeout_count == 0) { reset_process_time(hw); - vdec_schedule_work(&hw->timeout_work); + timeout_process(hw); } } } @@ -6791,14 +6819,6 @@ static void vh264_local_init(struct vdec_h264_hw_s *hw) return; } -static void timeout_process_work(struct work_struct *work) -{ - struct vdec_h264_hw_s *hw = container_of(work, - struct vdec_h264_hw_s, timeout_work); - - timeout_process(hw); -} - static s32 vh264_init(struct vdec_h264_hw_s *hw) { int size = -1; @@ -6826,7 +6846,7 @@ static s32 vh264_init(struct vdec_h264_hw_s *hw) vh264_local_init(hw); INIT_WORK(&hw->work, vh264_work); INIT_WORK(&hw->notify_work, vh264_notify_work); - INIT_WORK(&hw->timeout_work, timeout_process_work); + INIT_WORK(&hw->timeout_work, vh264_timeout_work); #ifdef MH264_USERDATA_ENABLE INIT_WORK(&hw->user_data_ready_work, user_data_ready_notify_work); #endif @@ -7754,11 +7774,9 @@ static void vmh264_wakeup_userdata_poll(struct vdec_s *vdec) #endif -static void vh264_work(struct work_struct *work) +static void vh264_work_implement(struct vdec_h264_hw_s *hw, + struct vdec_s *vdec, int from) { - struct vdec_h264_hw_s *hw = container_of(work, - struct vdec_h264_hw_s, work); - struct vdec_s *vdec = hw_to_vdec(hw); /* finished decoding one frame or error, * notify vdec core to switch context */ @@ -7992,6 +8010,17 @@ result_done: vdec_set_next_sched(vdec, vdec); #endif + if (from == 1) { + /* This is a timeout work */ + if (work_pending(&hw->work)) { + /* + * The vh264_work arrives at the last second, + * give it a chance to handle the scenario. + */ + return; + } + } + /* mark itself has all HW resource released and input released */ if (vdec->parallel_dec == 1) { if (hw->mmu_enable == 0) @@ -8006,6 +8035,29 @@ result_done: hw->vdec_cb(hw_to_vdec(hw), hw->vdec_cb_arg); } + +static void vh264_work(struct work_struct *work) +{ + struct vdec_h264_hw_s *hw = container_of(work, + struct vdec_h264_hw_s, work); + struct vdec_s *vdec = hw_to_vdec(hw); + + vh264_work_implement(hw, vdec, 0); +} + + +static void vh264_timeout_work(struct work_struct *work) +{ + struct vdec_h264_hw_s *hw = container_of(work, + struct vdec_h264_hw_s, timeout_work); + struct vdec_s *vdec = hw_to_vdec(hw); + + if (work_pending(&hw->work)) + return; + + vh264_work_implement(hw, vdec, 1); +} + static unsigned long run_ready(struct vdec_s *vdec, unsigned long mask) { bool ret = 0; diff --git a/drivers/frame_provider/decoder/h265/vh265.c b/drivers/frame_provider/decoder/h265/vh265.c index 9cb3f22..e74aa4f 100644 --- a/drivers/frame_provider/decoder/h265/vh265.c +++ b/drivers/frame_provider/decoder/h265/vh265.c @@ -1426,6 +1426,7 @@ struct tile_s { #define DEC_RESULT_FORCE_EXIT 10 static void vh265_work(struct work_struct *work); +static void vh265_timeout_work(struct work_struct *work); static void vh265_notify_work(struct work_struct *work); #endif @@ -1443,6 +1444,7 @@ struct hevc_state_s { struct vframe_chunk_s *chunk; int dec_result; struct work_struct work; + struct work_struct timeout_work; struct work_struct notify_work; struct work_struct set_clk_work; /* timeout handle */ @@ -10765,6 +10767,7 @@ static s32 vh265_init(struct hevc_state_s *hevc) */ INIT_WORK(&hevc->work, vh265_work); + INIT_WORK(&hevc->timeout_work, vh265_timeout_work); hevc->fw = fw; @@ -11034,6 +11037,13 @@ static void restart_process_time(struct hevc_state_s *hevc) static void timeout_process(struct hevc_state_s *hevc) { + /* + * In this very timeout point,the vh265_work arrives, + * let it to handle the scenario. + */ + if (work_pending(&hevc->work)) + return; + hevc->timeout_num++; amhevc_stop(); read_decode_info(hevc); @@ -11046,7 +11056,10 @@ static void timeout_process(struct hevc_state_s *hevc) hevc->decoding_pic = NULL; hevc->dec_result = DEC_RESULT_DONE; reset_process_time(hevc); - vdec_schedule_work(&hevc->work); + + if (work_pending(&hevc->work)) + return; + vdec_schedule_work(&hevc->timeout_work); } #ifdef CONSTRAIN_MAX_BUF_NUM @@ -11201,6 +11214,7 @@ static int vmh265_stop(struct hevc_state_s *hevc) cancel_work_sync(&hevc->notify_work); cancel_work_sync(&hevc->set_clk_work); cancel_work_sync(&hevc->work); + cancel_work_sync(&hevc->timeout_work); uninit_mmu_buffers(hevc); vfree(hevc->fw); @@ -11266,12 +11280,9 @@ static void vh265_notify_work(struct work_struct *work) return; } -static void vh265_work(struct work_struct *work) +static void vh265_work_implement(struct hevc_state_s *hevc, + struct vdec_s *vdec,int from) { - struct hevc_state_s *hevc = container_of(work, - struct hevc_state_s, work); - struct vdec_s *vdec = hw_to_vdec(hevc); - if (hevc->uninit_list) { /*USE_BUF_BLOCK*/ uninit_pic_list(hevc); @@ -11661,6 +11672,18 @@ static void vh265_work(struct work_struct *work) vdec_set_next_sched(vdec, vdec); #endif + if (from == 1) { + /* This is a timeout work */ + if (work_pending(&hevc->work)) { + /* + * The vh265_work arrives at the last second, + * give it a chance to handle the scenario. + */ + return; + //cancel_work_sync(&hevc->work);//reserved for future considraion + } + } + /* mark itself has all HW resource released and input released */ if (vdec->parallel_dec == 1) vdec_core_finish_run(vdec, CORE_MASK_HEVC); @@ -11671,6 +11694,27 @@ static void vh265_work(struct work_struct *work) hevc->vdec_cb(hw_to_vdec(hevc), hevc->vdec_cb_arg); } +static void vh265_work(struct work_struct *work) +{ + struct hevc_state_s *hevc = container_of(work, + struct hevc_state_s, work); + struct vdec_s *vdec = hw_to_vdec(hevc); + + vh265_work_implement(hevc, vdec, 0); +} + +static void vh265_timeout_work(struct work_struct *work) +{ + struct hevc_state_s *hevc = container_of(work, + struct hevc_state_s, timeout_work); + struct vdec_s *vdec = hw_to_vdec(hevc); + + if (work_pending(&hevc->work)) + return; + vh265_work_implement(hevc, vdec, 1); +} + + static int vh265_hw_ctx_restore(struct hevc_state_s *hevc) { /* new to do ... */ diff --git a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c index 6f64b7c..a466b2a 100644 --- a/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c +++ b/drivers/frame_provider/decoder/mpeg12/vmpeg12_multi.c @@ -245,6 +245,7 @@ struct vdec_mpeg12_hw_s { s32 refs[2]; int dec_result; struct work_struct work; + struct work_struct timeout_work; struct work_struct notify_work; void (*vdec_cb)(struct vdec_s *, void *); void *vdec_cb_arg; @@ -1088,9 +1089,10 @@ static void userdata_push_do_work(struct work_struct *work) } if (hw->cur_ud_idx >= MAX_UD_RECORDS) { - debug_print(DECODE_ID(hw), 0, + debug_print(DECODE_ID(hw), PRINT_FLAG_DEC_DETAIL, "UD Records over: %d, skip it\n", MAX_UD_RECORDS); WRITE_VREG(AV_SCRATCH_J, 0); + hw->cur_ud_idx = 0; return; } @@ -1658,12 +1660,9 @@ static void flush_output(struct vdec_mpeg12_hw_s *hw) prepare_display_buf(hw, &hw->pics[index]); } -static void vmpeg12_work(struct work_struct *work) +static void vmpeg12_work_implement(struct vdec_mpeg12_hw_s *hw, + struct vdec_s *vdec, int from) { - struct vdec_mpeg12_hw_s *hw = - container_of(work, struct vdec_mpeg12_hw_s, work); - struct vdec_s *vdec = hw_to_vdec(hw); - if (hw->dec_result != DEC_RESULT_DONE) debug_print(DECODE_ID(hw), PRINT_FLAG_RUN_FLOW, "%s, result=%d, status=%d\n", __func__, @@ -1729,6 +1728,19 @@ static void vmpeg12_work(struct work_struct *work) amvdec_stop(); hw->stat &= ~STAT_VDEC_RUN; } + + if (from == 1) { + /*This is a timeout work*/ + if (work_pending(&hw->work)) { + pr_err("timeout work return befor finishing."); + /* + * The vmpeg12_work arrives at the last second, + * give it a chance to handle the scenario. + */ + return; + } + } + /*disable mbox interrupt */ WRITE_VREG(ASSIST_MBOX1_MASK, 0); wait_vmmpeg12_search_done(hw); @@ -1743,6 +1755,28 @@ static void vmpeg12_work(struct work_struct *work) hw->vdec_cb(vdec, hw->vdec_cb_arg); } +static void vmpeg12_work(struct work_struct *work) +{ + struct vdec_mpeg12_hw_s *hw = + container_of(work, struct vdec_mpeg12_hw_s, work); + struct vdec_s *vdec = hw_to_vdec(hw); + + vmpeg12_work_implement(hw, vdec, 0); +} +static void vmpeg12_timeout_work(struct work_struct *work) +{ + struct vdec_mpeg12_hw_s *hw = + container_of(work, struct vdec_mpeg12_hw_s, timeout_work); + struct vdec_s *vdec = hw_to_vdec(hw); + + if (work_pending(&hw->work)) { + pr_err("timeout work return befor executing."); + return; + } + + vmpeg12_work_implement(hw, vdec, 1); +} + static struct vframe_s *vmpeg_vf_peek(void *op_arg) { struct vframe_s *vf; @@ -2081,6 +2115,10 @@ 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."); + return; + } reset_process_time(hw); amvdec_stop(); debug_print(DECODE_ID(hw), PRINT_FLAG_ERROR, @@ -2088,7 +2126,16 @@ static void timeout_process(struct vdec_mpeg12_hw_s *hw) __func__, vdec->status, READ_VREG(VLD_MEM_VIFIFO_LEVEL)); hw->dec_result = DEC_RESULT_DONE; hw->first_i_frame_ready = 0; - vdec_schedule_work(&hw->work); + + /* + * In this very timeout point,the vmpeg12_work arrives, + * let it to handle the scenario. + */ + if (work_pending(&hw->work)) { + pr_err("timeout_process return befor schedule."); + return; + } + vdec_schedule_work(&hw->timeout_work); } static void check_timer_func(unsigned long arg) @@ -2312,6 +2359,7 @@ static s32 vmpeg12_init(struct vdec_mpeg12_hw_s *hw) INIT_WORK(&hw->userdata_push_work, userdata_push_do_work); INIT_WORK(&hw->work, vmpeg12_work); + INIT_WORK(&hw->timeout_work, vmpeg12_timeout_work); INIT_WORK(&hw->notify_work, vmpeg12_notify_work); if (NULL == hw->user_data_buffer) { @@ -2665,6 +2713,7 @@ static int ammvdec_mpeg12_remove(struct platform_device *pdev) cancel_work_sync(&hw->userdata_push_work); cancel_work_sync(&hw->notify_work); cancel_work_sync(&hw->work); + cancel_work_sync(&hw->timeout_work); if (hw->mm_blk_handle) { decoder_bmmu_box_free(hw->mm_blk_handle); diff --git a/drivers/frame_provider/decoder/utils/vdec.c b/drivers/frame_provider/decoder/utils/vdec.c index 44f0934..54f9051 100644 --- a/drivers/frame_provider/decoder/utils/vdec.c +++ b/drivers/frame_provider/decoder/utils/vdec.c @@ -2544,8 +2544,10 @@ static irqreturn_t vdec_isr(int irq, void *dev_id) vdec = NULL; } - if (vdec) + if (vdec) { atomic_set(&vdec->inirq_flag, 1); + vdec->isr_ns = local_clock(); + } if (c->dev_isr) { ret = c->dev_isr(irq, c->dev_id); goto isr_done; @@ -2598,8 +2600,15 @@ static irqreturn_t vdec_thread_isr(int irq, void *dev_id) vdec = NULL; } - if (vdec) + if (vdec) { + u32 isr2tfn = 0; atomic_set(&vdec->inirq_thread_flag, 1); + vdec->tfn_ns = local_clock(); + isr2tfn = vdec->tfn_ns - vdec->isr_ns; + if (isr2tfn > 10000000) + pr_err("!!!!!!! %s vdec_isr to %s took %uns !!!\n", + vdec->vf_provider_name, __func__, isr2tfn); + } if (c->dev_threaded_isr) { ret = c->dev_threaded_isr(irq, c->dev_id); goto thread_isr_done; diff --git a/drivers/frame_provider/decoder/utils/vdec.h b/drivers/frame_provider/decoder/utils/vdec.h index 18d7cd1..80fa8dc 100644 --- a/drivers/frame_provider/decoder/utils/vdec.h +++ b/drivers/frame_provider/decoder/utils/vdec.h @@ -262,6 +262,8 @@ struct vdec_s { atomic_t inirq_thread_flag; atomic_t inirq_flag; int parallel_dec; + volatile u64 isr_ns; + volatile u64 tfn_ns; }; /* common decoder vframe provider name to use default vfm path */ |