Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[media] mtk-vcodec: check the vp9 decoder buffer index from VPU

VPU firmware has a bug and may return invalid buffer index for
some vp9 videos. Check the buffer indexes before accessing the
buffer.

Signed-off-by: Wu-Cheng Li <wuchengli@chromium.org>
Acked-by: Tiffany Lin <Tiffany.lin@mediatek.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

authored by

Wu-Cheng Li and committed by
Mauro Carvalho Chehab
e8a2a41e 586fd401

+56 -7
+26 -7
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
··· 420 420 dst_buf->index, 421 421 ret, res_chg); 422 422 src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); 423 + if (ret == -EIO) { 424 + mutex_lock(&ctx->lock); 425 + src_buf_info->error = true; 426 + mutex_unlock(&ctx->lock); 427 + } 423 428 v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR); 424 429 } else if (res_chg == false) { 425 430 /* ··· 1175 1170 */ 1176 1171 1177 1172 src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); 1178 - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), 1179 - VB2_BUF_STATE_DONE); 1173 + if (ret == -EIO) { 1174 + mtk_v4l2_err("[%d] Unrecoverable error in vdec_if_decode.", 1175 + ctx->id); 1176 + ctx->state = MTK_STATE_ABORT; 1177 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), 1178 + VB2_BUF_STATE_ERROR); 1179 + } else { 1180 + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), 1181 + VB2_BUF_STATE_DONE); 1182 + } 1180 1183 mtk_v4l2_debug(ret ? 0 : 1, 1181 1184 "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", 1182 1185 ctx->id, src_buf->index, ··· 1229 1216 struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); 1230 1217 struct vb2_v4l2_buffer *vb2_v4l2; 1231 1218 struct mtk_video_dec_buf *buf; 1232 - 1233 - if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) 1234 - return; 1219 + bool buf_error; 1235 1220 1236 1221 vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); 1237 1222 buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb); 1238 1223 mutex_lock(&ctx->lock); 1239 - buf->queued_in_v4l2 = false; 1240 - buf->queued_in_vb2 = false; 1224 + if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { 1225 + buf->queued_in_v4l2 = false; 1226 + buf->queued_in_vb2 = false; 1227 + } 1228 + buf_error = buf->error; 1241 1229 mutex_unlock(&ctx->lock); 1230 + 1231 + if (buf_error) { 1232 + mtk_v4l2_err("Unrecoverable error on buffer."); 1233 + ctx->state = MTK_STATE_ABORT; 1234 + } 1242 1235 } 1243 1236 1244 1237 static int vb2ops_vdec_buf_init(struct vb2_buffer *vb)
+2
drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h
··· 50 50 * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2 51 51 * queue yet 52 52 * @lastframe: Intput buffer is last buffer - EOS 53 + * @error: An unrecoverable error occurs on this buffer. 53 54 * @frame_buffer: Decode status, and buffer information of Capture buffer 54 55 * 55 56 * Note : These status information help us track and debug buffer state ··· 64 63 bool queued_in_vb2; 65 64 bool queued_in_v4l2; 66 65 bool lastframe; 66 + bool error; 67 67 struct vdec_fb frame_buffer; 68 68 }; 69 69
+26
drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
··· 718 718 *out_fb = fb; 719 719 } 720 720 721 + static int validate_vsi_array_indexes(struct vdec_vp9_inst *inst, 722 + struct vdec_vp9_vsi *vsi) { 723 + if (vsi->sf_frm_idx >= VP9_MAX_FRM_BUF_NUM - 1) { 724 + mtk_vcodec_err(inst, "Invalid vsi->sf_frm_idx=%u.", 725 + vsi->sf_frm_idx); 726 + return -EIO; 727 + } 728 + if (vsi->frm_to_show_idx >= VP9_MAX_FRM_BUF_NUM) { 729 + mtk_vcodec_err(inst, "Invalid vsi->frm_to_show_idx=%u.", 730 + vsi->frm_to_show_idx); 731 + return -EIO; 732 + } 733 + if (vsi->new_fb_idx >= VP9_MAX_FRM_BUF_NUM) { 734 + mtk_vcodec_err(inst, "Invalid vsi->new_fb_idx=%u.", 735 + vsi->new_fb_idx); 736 + return -EIO; 737 + } 738 + return 0; 739 + } 740 + 721 741 static void vdec_vp9_deinit(unsigned long h_vdec) 722 742 { 723 743 struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; ··· 851 831 ret = vpu_dec_start(&inst->vpu, data, 3); 852 832 if (ret) { 853 833 mtk_vcodec_err(inst, "vpu_dec_start failed"); 834 + goto DECODE_ERROR; 835 + } 836 + 837 + ret = validate_vsi_array_indexes(inst, vsi); 838 + if (ret) { 839 + mtk_vcodec_err(inst, "Invalid values from VPU."); 854 840 goto DECODE_ERROR; 855 841 } 856 842
+2
drivers/media/platform/mtk-vcodec/vdec_drv_if.h
··· 85 85 * @res_chg : [out] resolution change happens if current bs have different 86 86 * picture width/height 87 87 * Note: To flush the decoder when reaching EOF, set input bitstream as NULL. 88 + * 89 + * Return: 0 on success. -EIO on unrecoverable error. 88 90 */ 89 91 int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, 90 92 struct vdec_fb *fb, bool *res_chg);