在调试GMSL相机时,使用gst拉取视频流时,当vi通道没有视频流数据时,vi道通会超时复位,出现内核奔溃死机。
修改相机平台驱动,解决此种内核奔溃现象。参考官方补丁修改。
commit 29f211921e128ee01b24f75c37abdf8ba0010240
Author: edgar <edgar_xia@aliyun.com>
Date: Mon Apr 28 10:46:14 2025 +0800
修改相机平台驱动:解决当无视频流时,vi通道复位死机现象
diff --git a/kernel/nvidia/drivers/media/platform/tegra/camera/csi/csi.c b/kernel/nvidia/drivers/media/platform/tegra/camera/csi/csi.c
index d788f7041..2353c1ce0 100644
--- a/kernel/nvidia/drivers/media/platform/tegra/camera/csi/csi.c
+++ b/kernel/nvidia/drivers/media/platform/tegra/camera/csi/csi.c
@@ -229,6 +229,7 @@ static int tegra_csi_s_power(struct v4l2_subdev *subdev, int enable)
return err;
}
+#if(0)
static int tegra_csi_sync_event(struct v4l2_subdev *subdev,
unsigned int sync_events)
{
@@ -242,7 +243,7 @@ static int tegra_csi_sync_event(struct v4l2_subdev *subdev,
return err;
}
-
+#endif
/*
* -----------------------------------------------------------------------------
* CSI Subdevice Video Operations
@@ -738,7 +739,7 @@ static struct v4l2_subdev_pad_ops tegra_csi_pad_ops = {
static struct v4l2_subdev_core_ops tegra_csi_core_ops = {
.s_power = tegra_csi_s_power,
- .sync = tegra_csi_sync_event,
+ //.sync = tegra_csi_sync_event,
};
static struct v4l2_subdev_ops tegra_csi_ops = {
diff --git a/kernel/nvidia/drivers/media/platform/tegra/camera/vi/vi5_fops.c b/kernel/nvidia/drivers/media/platform/tegra/camera/vi/vi5_fops.c
index 8404249f9..957089a6c 100644
--- a/kernel/nvidia/drivers/media/platform/tegra/camera/vi/vi5_fops.c
+++ b/kernel/nvidia/drivers/media/platform/tegra/camera/vi/vi5_fops.c
@@ -324,6 +324,9 @@ static int tegra_channel_capture_setup(struct tegra_channel *chan, unsigned int
chan->request[vi_port] = dma_alloc_coherent(chan->tegra_vi_channel[vi_port]->rtcpu_dev,
setup.queue_depth * setup.request_size,
&setup.iova, GFP_KERNEL);
+
+ chan->request_iova[vi_port] = setup.iova;
+
if (chan->request[vi_port] == NULL) {
dev_err(chan->vi->dev, "dma_alloc_coherent failed\n");
return -ENOMEM;
@@ -740,7 +743,16 @@ static int vi5_channel_error_recover(struct tegra_channel *chan,
/* stop vi channel */
for (vi_port = 0; vi_port < chan->valid_ports; vi_port++) {
- filp_close(chan->fp[vi_port], NULL);
+ //filp_close(chan->fp[vi_port], NULL);
+ err = vi_capture_release(chan->tegra_vi_channel[vi_port],
+ CAPTURE_CHANNEL_RESET_FLAG_IMMEDIATE);
+ if(err) {
+ dev_err(&chan->video->dev, "vi capture release failed\n");
+ goto done;
+ }
+ vi_channel_close_ex(chan->vi_channel_id[vi_port],
+ chan->tegra_vi_channel[vi_port]);
+
chan->tegra_vi_channel[vi_port] = NULL;
kfree(chan->tegra_vi_channel[vi_port]);
}
@@ -772,10 +784,10 @@ static int vi5_channel_error_recover(struct tegra_channel *chan,
err = -1;
goto done;
}
-
+#if(0)
v4l2_subdev_call(csi_subdev, core, sync,
V4L2_SYNC_EVENT_SUBDEV_ERROR_RECOVER);
-
+#endif
/* restart vi channel */
for (vi_port = 0; vi_port < chan->valid_ports; vi_port++) {
err = vi5_channel_open(chan, vi_port);
@@ -1078,7 +1090,9 @@ err_set_stream:
err_setup:
if (!chan->bypass)
for (vi_port = 0; vi_port < chan->valid_ports; vi_port++) {
- filp_close(chan->fp[vi_port], NULL);
+ //filp_close(chan->fp[vi_port], NULL);
+ vi_channel_close_ex(chan->vi_channel_id[vi_port],
+ chan->tegra_vi_channel[vi_port]);
chan->tegra_vi_channel[vi_port] = NULL;
}
@@ -1093,6 +1107,8 @@ static int vi5_channel_stop_streaming(struct vb2_queue *vq)
{
struct tegra_channel *chan = vb2_get_drv_priv(vq);
int vi_port = 0;
+ int err;
+
if (!chan->bypass)
vi5_channel_stop_kthreads(chan);
@@ -1101,7 +1117,35 @@ static int vi5_channel_stop_streaming(struct vb2_queue *vq)
if (!chan->bypass) {
for (vi_port = 0; vi_port < chan->valid_ports; vi_port++) {
- filp_close(chan->fp[vi_port], NULL);
+ //filp_close(chan->fp[vi_port], NULL);
+ err = vi_capture_release(chan->tegra_vi_channel[vi_port],
+ CAPTURE_CHANNEL_RESET_FLAG_IMMEDIATE);
+
+ if(err)
+ dev_err(&chan->video->dev, "vi capture release failed\n");
+
+ /* Release capture requests */
+ if(chan->request[vi_port] != NULL) {
+ dma_free_coherent(chan->tegra_vi_channel[vi_port]->rtcpu_dev,
+ chan->capture_queue_depth * sizeof(struct capture_descriptor),
+ chan->request[vi_port], chan->request_iova[vi_port]);
+ }
+ chan->request[vi_port] = NULL;
+
+ /* Release emd data buffers */
+ if(chan->emb_buf_size > 0) {
+ struct device *vi_unit_dev;
+
+ vi5_unit_get_device_handle(chan->vi->ndev, chan->port[0],
+ &vi_unit_dev);
+ dma_free_coherent(vi_unit_dev, chan->emb_buf_size,
+ chan->emb_buf_addr, chan->emb_buf);
+ chan->emb_buf_size = 0;
+ }
+
+ vi_channel_close_ex(chan->vi_channel_id[vi_port],
+ chan->tegra_vi_channel[vi_port]);
+
chan->tegra_vi_channel[vi_port] = NULL;
kfree(chan->tegra_vi_channel[vi_port]);
}
diff --git a/kernel/nvidia/include/media/mc_common.h b/kernel/nvidia/include/media/mc_common.h
index 3b8ad289c..b2143d0d4 100644
--- a/kernel/nvidia/include/media/mc_common.h
+++ b/kernel/nvidia/include/media/mc_common.h
@@ -276,6 +276,8 @@ struct tegra_channel {
struct nvcsi_deskew_context *deskew_ctx;
struct tegra_vi_channel *tegra_vi_channel[TEGRA_CSI_BLOCKS];
struct capture_descriptor *request[TEGRA_CSI_BLOCKS];
+ dma_addr_t request_iova[TEGRA_CSI_BLOCKS];
+
bool is_slvsec;
int is_interlaced;
enum interlaced_type interlace_type;