amstream: fix crash when update ext stbuf metainfo. [1/1]
authorshihong.zheng <shihong.zheng@amlogic.com>
Thu, 10 Sep 2020 09:18:51 +0000 (17:18 +0800)
committerHui Zhang <hui.zhang@amlogic.com>
Thu, 15 Oct 2020 08:33:05 +0000 (01:33 -0700)
PD#SWPL-33180

Problem:
1. fix crash when update ext stbuf metainfo.
2. delay put fd cause playback stuck.

Solution:
1. add some null check for metainfo update.
2. If it is the single instance that the pipeline of DTV used,
   then have to check that the resources which is work on the
   tunnel are being released.

Verify:
ah212

Change-Id: Iaa68a6c2b4fcd0b8dbea30603c2d6e4e3463160e
Signed-off-by: shihong.zheng <shihong.zheng@amlogic.com>
drivers/frame_provider/decoder/utils/vdec.c
drivers/frame_provider/decoder/utils/vdec.h
drivers/stream_input/amports/amstream.c

index 7113a7e3827b7e8de43d39db51d0a2dc5e0f76fb..3784ef35559b4304eaa1d08abc9bc8d2e0110951 100644 (file)
@@ -202,6 +202,7 @@ struct vdec_core_s {
        unsigned long buff_flag;
        unsigned long stream_buff_flag;
        struct power_manager_s *pm;
+       u32 vdec_resouce_status;
 };
 
 struct canvas_status_s {
@@ -2195,6 +2196,41 @@ int vdec_destroy(struct vdec_s *vdec)
 }
 EXPORT_SYMBOL(vdec_destroy);
 
+static bool is_tunnel_pipeline(u32 pl)
+{
+       return ((pl & BIT(FRAME_BASE_PATH_DTV_TUNNEL_MODE)) ||
+               (pl & BIT(FRAME_BASE_PATH_AMLVIDEO_AMVIDEO))) ?
+               true : false;
+}
+
+static bool is_res_locked(u32 pre, u32 cur)
+{
+       return is_tunnel_pipeline(pre) ?
+               (is_tunnel_pipeline(cur) ? true : false) : false;
+}
+
+int vdec_resource_checking(struct vdec_s *vdec)
+{
+       /*
+        * If it is the single instance that the pipeline of DTV used,
+        * then have to check that the resources which is belong tunnel
+        * pipeline these are being released.
+        */
+       ulong expires = jiffies + msecs_to_jiffies(2000);
+
+       while (is_res_locked(vdec_core->vdec_resouce_status,
+               BIT(vdec->frame_base_video_path))) {
+               if (time_after(jiffies, expires)) {
+                       pr_err("wait vdec resource timeout.\n");
+                       return -EBUSY;
+               }
+               schedule();
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(vdec_resource_checking);
+
 /*
  *register vdec_device
  * create output, vfm or create ionvideo output
@@ -2206,6 +2242,10 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k)
        const char *dev_name;
        int id = PLATFORM_DEVID_AUTO;/*if have used my self*/
 
+       if (is_res_locked(vdec_core->vdec_resouce_status,
+               BIT(vdec->frame_base_video_path)))
+               return -EBUSY;
+
        //pr_err("%s [pid=%d,tgid=%d]\n", __func__, current->pid, current->tgid);
        dev_name = get_dev_name(vdec_single(vdec), vdec->format);
 
@@ -2508,7 +2548,8 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k)
                                vdec->vf_receiver_name);
                        snprintf(vdec->vfm_map_id, VDEC_MAP_NAME_SIZE,
                                "vdec-map-%d", vdec->id);
-               } else if (p->frame_base_video_path == FRAME_BASE_PATH_DTV_TUNNEL_MODE) {
+               } else if (p->frame_base_video_path ==
+                       FRAME_BASE_PATH_DTV_TUNNEL_MODE) {
                        snprintf(vdec->vfm_map_chain, VDEC_MAP_NAME_SIZE,
                                "%s deinterlace %s", vdec->vf_provider_name,
                                "amvideo");
@@ -2585,6 +2626,11 @@ s32 vdec_init(struct vdec_s *vdec, int is_4k)
        p->dolby_meta_with_el = 0;
        pr_debug("vdec_init, vf_provider_name = %s, b %d\n",
                p->vf_provider_name, is_cpu_tm2_revb());
+
+       mutex_lock(&vdec_mutex);
+       vdec_core->vdec_resouce_status |= BIT(p->frame_base_video_path);
+       mutex_unlock(&vdec_mutex);
+
        vdec_input_prepare_bufs(/*prepared buffer for fast playing.*/
                &vdec->input,
                vdec->sys_info->width,
@@ -2691,12 +2737,16 @@ void vdec_release(struct vdec_s *vdec)
 
        pr_debug("vdec_release instance %p, total %d\n", vdec,
                atomic_read(&vdec_core->vdec_nr));
+
+       mutex_lock(&vdec_mutex);
+       vdec_core->vdec_resouce_status &= ~BIT(vdec->frame_base_video_path);
+       mutex_unlock(&vdec_mutex);
+
        vdec_destroy(vdec);
 
        mutex_lock(&vdec_mutex);
        inited_vcodec_num--;
        mutex_unlock(&vdec_mutex);
-
 }
 EXPORT_SYMBOL(vdec_release);
 
index df2b409308a320e3629a910556c3927f853c22eb..16caa952c36100251bf8e8ab12a53e307e401d2a 100644 (file)
@@ -475,4 +475,7 @@ int show_stream_buffer_status(char *buf,
 bool is_support_no_parser(void);
 
 extern u32 timestamp_avsync_counter_get(void);
+
+int vdec_resource_checking(struct vdec_s *vdec);
+
 #endif                         /* VDEC_H */
index 6b42a548d75f12c4726c39ec773273512d85e45e..b38676c1c5c6dfdf4b3af113015b413cc4545eb1 100644 (file)
@@ -920,6 +920,10 @@ static int amstream_port_init(struct port_priv_s *priv)
        struct stream_port_s *port = priv->port;
        struct vdec_s *vdec = priv->vdec;
 
+       r = vdec_resource_checking(vdec);
+       if (r < 0)
+               return r;
+
        mutex_lock(&amstream_mutex);
 
        if ((get_cpu_major_id() >= AM_MESON_CPU_MAJOR_ID_G12A) &&
@@ -1088,7 +1092,7 @@ static int amstream_port_release(struct port_priv_s *priv)
                sub_port_release(port, psbuf);
 
        port->pcr_inited = 0;
-       port->flag = 0;
+
        return 0;
 }
 
@@ -1602,6 +1606,7 @@ static int amstream_open(struct inode *inode, struct file *file)
        struct stream_port_s *s;
        struct stream_port_s *port = &ports[iminor(inode)];
        struct port_priv_s *priv;
+
        VDEC_PRINT_FUN_LINENO(__func__, __LINE__);
 #ifdef G12A_BRINGUP_DEBUG
        if (vdec_get_debug_flags() & 0xff0000) {
@@ -1756,7 +1761,6 @@ static int amstream_release(struct inode *inode, struct file *file)
 #ifdef CONFIG_AMLOGIC_MEDIA_MULTI_DEC
        u32 port_flag = 0;
 #endif
-
        if (iminor(inode) >= amstream_port_num)
                return -ENODEV;
 
@@ -1790,7 +1794,6 @@ static int amstream_release(struct inode *inode, struct file *file)
                if (i == amstream_port_num)
                        timestamp_firstvpts_set(0);
        }
-       port->flag = 0;
 
        /* timestamp_pcrscr_set(0); */
 
@@ -3491,7 +3494,18 @@ static long amstream_do_ioctl_old(struct port_priv_s *priv,
        }
        case AMSTREAM_IOC_INIT_EX_STBUF: {
                struct stream_buffer_metainfo parm;
-               struct stream_buf_s *vbuf = &priv->vdec->vbuf;
+               struct stream_buf_s *vbuf = NULL;
+
+               if (priv->vdec == NULL) {
+                       pr_err("init %s, no vdec.\n", __func__);
+                       return -EFAULT;
+               }
+
+               vbuf = &priv->vdec->vbuf;
+               if (vbuf == NULL) {
+                       pr_err("init %s, no stbuf.\n", __func__);
+                       return -EFAULT;
+               }
 
                if (copy_from_user(&parm, (void __user *)arg,
                        sizeof(struct stream_buffer_metainfo))) {
@@ -3503,7 +3517,23 @@ static long amstream_do_ioctl_old(struct port_priv_s *priv,
        }
        case AMSTREAM_IOC_WR_STBUF_META: {
                struct stream_buffer_metainfo meta;
-               struct stream_buf_s *vbuf = &priv->vdec->vbuf;
+               struct stream_buf_s *vbuf = NULL;
+
+               if (priv->vdec == NULL) {
+                       pr_err("write %s, no vdec.\n", __func__);
+                       return -EFAULT;
+               }
+
+               vbuf = &priv->vdec->vbuf;
+               if (vbuf == NULL) {
+                       pr_err("write %s, no stbuf.\n", __func__);
+                       return -EFAULT;
+               }
+
+               if (vbuf->ops == NULL) {
+                       pr_err("write %s, no ops.\n", __func__);
+                       return -EFAULT;
+               }
 
                if (copy_from_user(&meta, (void __user *)arg,
                        sizeof(struct stream_buffer_metainfo))) {
@@ -3517,7 +3547,23 @@ static long amstream_do_ioctl_old(struct port_priv_s *priv,
        }
        case AMSTREAM_IOC_GET_STBUF_STATUS: {
                struct stream_buffer_status st;
-               struct stream_buf_s *pbuf = &priv->vdec->vbuf;
+               struct stream_buf_s *pbuf = NULL;
+
+               if (priv->vdec == NULL) {
+                       pr_err("get status %s, no vdec.\n", __func__);
+                       return -EFAULT;
+               }
+
+               pbuf = &priv->vdec->vbuf;
+               if (pbuf == NULL) {
+                       pr_err("get status %s, no stbuf.\n", __func__);
+                       return -EFAULT;
+               }
+
+               if (pbuf->ops == NULL) {
+                       pr_err("get status %s, no ops.\n", __func__);
+                       return -EFAULT;
+               }
 
                st.stbuf_start = pbuf->ext_buf_addr;
                st.stbuf_size = pbuf->buf_size;