Commit 93d3fb35 authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab
Browse files

media: atomisp: Remove watchdog timer



The watchdog timer code to recover from the ISP getting stuck has several
major issues:

1. There is no way to do fault injection and normally the ISP does not
get stuck, so is it is impossible to test it.

2. It in essence just stops all streams, resets the ISP and then brings
everything back up. Userspace can easily do this itself by using a
timeout on dqbuf and then closing (which causes a poweroff) +
re-opening the device. Doing this in userspace (if it ever turns out
to be necessary) greatly simplifies the kernel code and in general
will be a more robust solution.

Even just a quick look at the code finds several more issues:

3. The need to sync-cancel the timers + work on streamoff requires
isp->mutex to be dropped halfway during the ioctl opening all sorts of
races.

4. The atomisp code supports setting up 2 pipelines, streaming from
two sensors at the same time. But there is only a single wdt_work
and stopping one of the 2 streams will cancel the timers + work,
stopping the wdt even though the other stream might still be running.

5. In case atomisp_css_flush() the sync cancel is done while keeping
isp->mutex locked, causing a deadlock when racing with wdt_work which
also takes isp->mutex.

6. Even though the watchdog is purely a software/driver thing which
just checkes that new frames keep coming in, there are 2 completely
different implementations for the ISP2400/ISP2401 which is not
necessary at all.

So all in all I believe that it is better to just remove the current
watchdog implementation. Fixing all the issues with the current
implementation will be so much work, that if it turns out that we do
need something like this then doing a clean re-implementation from
scratch will be better anyways.

wdt_work was also (ab)used to reset the ISP after the firmware signalled
an fw-assert error through the irq, add a new assert_recover_work to
replace this.

Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@kernel.org>
parent f315c1ac
Loading
Loading
Loading
Loading
+4 −357
Original line number Diff line number Diff line
@@ -897,7 +897,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
	enum atomisp_metadata_type md_type;
	struct atomisp_device *isp = asd->isp;
	struct v4l2_control ctrl;
	bool reset_wdt_timer = false;

	lockdep_assert_held(&isp->mutex);

@@ -1006,9 +1005,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
		break;
	case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
	case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
		if (IS_ISP2401)
			reset_wdt_timer = true;

		pipe->buffers_in_css--;
		frame = buffer.css_buffer.data.frame;
		if (!frame) {
@@ -1061,9 +1057,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
		break;
	case IA_CSS_BUFFER_TYPE_OUTPUT_FRAME:
	case IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME:
		if (IS_ISP2401)
			reset_wdt_timer = true;

		pipe->buffers_in_css--;
		frame = buffer.css_buffer.data.frame;
		if (!frame) {
@@ -1231,8 +1224,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
		 */
		wake_up(&vb->done);
	}
	if (IS_ISP2401)
		atomic_set(&pipe->wdt_count, 0);

	/*
	 * Requeue should only be done for 3a and dis buffers.
@@ -1249,19 +1240,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
	}
	if (!error && q_buffers)
		atomisp_qbuffers_to_css(asd);

	if (IS_ISP2401) {
		/* If there are no buffers queued then
		* delete wdt timer. */
		if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
			return;
		if (!atomisp_buffers_queued_pipe(pipe))
			atomisp_wdt_stop_pipe(pipe, false);
		else if (reset_wdt_timer)
			/* SOF irq should not reset wdt timer. */
			atomisp_wdt_refresh_pipe(pipe,
						ATOMISP_WDT_KEEP_CURRENT_DELAY);
	}
}

void atomisp_delayed_init_work(struct work_struct *work)
@@ -1450,350 +1428,32 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout)
	}
}

void atomisp_wdt_work(struct work_struct *work)
void atomisp_assert_recovery_work(struct work_struct *work)
{
	struct atomisp_device *isp = container_of(work, struct atomisp_device,
				     wdt_work);
	int i;
	unsigned int pipe_wdt_cnt[MAX_STREAM_NUM][4] = { {0} };
	bool css_recover = true;
						  assert_recovery_work);

	mutex_lock(&isp->mutex);
	if (!atomisp_streaming_count(isp)) {
		atomic_set(&isp->wdt_work_queued, 0);
		mutex_unlock(&isp->mutex);
		return;
	}

	if (!IS_ISP2401) {
		dev_err(isp->dev, "timeout %d of %d\n",
			atomic_read(&isp->wdt_count) + 1,
			ATOMISP_ISP_MAX_TIMEOUT_COUNT);
	} else {
		for (i = 0; i < isp->num_of_streams; i++) {
			struct atomisp_sub_device *asd = &isp->asd[i];

			pipe_wdt_cnt[i][0] +=
			    atomic_read(&asd->video_out_capture.wdt_count);
			pipe_wdt_cnt[i][1] +=
			    atomic_read(&asd->video_out_vf.wdt_count);
			pipe_wdt_cnt[i][2] +=
			    atomic_read(&asd->video_out_preview.wdt_count);
			pipe_wdt_cnt[i][3] +=
			    atomic_read(&asd->video_out_video_capture.wdt_count);
			css_recover =
			    (pipe_wdt_cnt[i][0] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT &&
			    pipe_wdt_cnt[i][1] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT &&
			    pipe_wdt_cnt[i][2] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT &&
			    pipe_wdt_cnt[i][3] <= ATOMISP_ISP_MAX_TIMEOUT_COUNT)
			    ? true : false;
			dev_err(isp->dev,
				"pipe on asd%d timeout cnt: (%d, %d, %d, %d) of %d, recover = %d\n",
				asd->index, pipe_wdt_cnt[i][0], pipe_wdt_cnt[i][1],
				pipe_wdt_cnt[i][2], pipe_wdt_cnt[i][3],
				ATOMISP_ISP_MAX_TIMEOUT_COUNT, css_recover);
		}
	}

	if (css_recover) {
		ia_css_debug_dump_sp_sw_debug_info();
		ia_css_debug_dump_debug_info(__func__);
		for (i = 0; i < isp->num_of_streams; i++) {
			struct atomisp_sub_device *asd = &isp->asd[i];

			if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
				continue;
			dev_err(isp->dev, "%s, vdev %s buffers in css: %d\n",
				__func__,
				asd->video_out_capture.vdev.name,
				asd->video_out_capture.
				buffers_in_css);
			dev_err(isp->dev,
				"%s, vdev %s buffers in css: %d\n",
				__func__,
				asd->video_out_vf.vdev.name,
				asd->video_out_vf.
				buffers_in_css);
			dev_err(isp->dev,
				"%s, vdev %s buffers in css: %d\n",
				__func__,
				asd->video_out_preview.vdev.name,
				asd->video_out_preview.
				buffers_in_css);
			dev_err(isp->dev,
				"%s, vdev %s buffers in css: %d\n",
				__func__,
				asd->video_out_video_capture.vdev.name,
				asd->video_out_video_capture.
				buffers_in_css);
			dev_err(isp->dev,
				"%s, s3a buffers in css preview pipe:%d\n",
				__func__,
				asd->s3a_bufs_in_css[IA_CSS_PIPE_ID_PREVIEW]);
			dev_err(isp->dev,
				"%s, s3a buffers in css capture pipe:%d\n",
				__func__,
				asd->s3a_bufs_in_css[IA_CSS_PIPE_ID_CAPTURE]);
			dev_err(isp->dev,
				"%s, s3a buffers in css video pipe:%d\n",
				__func__,
				asd->s3a_bufs_in_css[IA_CSS_PIPE_ID_VIDEO]);
			dev_err(isp->dev,
				"%s, dis buffers in css: %d\n",
				__func__, asd->dis_bufs_in_css);
			dev_err(isp->dev,
				"%s, metadata buffers in css preview pipe:%d\n",
				__func__,
				asd->metadata_bufs_in_css
				[ATOMISP_INPUT_STREAM_GENERAL]
				[IA_CSS_PIPE_ID_PREVIEW]);
			dev_err(isp->dev,
				"%s, metadata buffers in css capture pipe:%d\n",
				__func__,
				asd->metadata_bufs_in_css
				[ATOMISP_INPUT_STREAM_GENERAL]
				[IA_CSS_PIPE_ID_CAPTURE]);
			dev_err(isp->dev,
				"%s, metadata buffers in css video pipe:%d\n",
				__func__,
				asd->metadata_bufs_in_css
				[ATOMISP_INPUT_STREAM_GENERAL]
				[IA_CSS_PIPE_ID_VIDEO]);
			if (asd->enable_raw_buffer_lock->val) {
				unsigned int j;

				dev_err(isp->dev, "%s, raw_buffer_locked_count %d\n",
					__func__, asd->raw_buffer_locked_count);
				for (j = 0; j <= ATOMISP_MAX_EXP_ID / 32; j++)
					dev_err(isp->dev, "%s, raw_buffer_bitmap[%d]: 0x%x\n",
						__func__, j,
						asd->raw_buffer_bitmap[j]);
			}
		}

		/*sh_css_dump_sp_state();*/
		/*sh_css_dump_isp_state();*/
	} else {
		for (i = 0; i < isp->num_of_streams; i++) {
			struct atomisp_sub_device *asd = &isp->asd[i];

			if (asd->streaming ==
			    ATOMISP_DEVICE_STREAMING_ENABLED) {
				atomisp_clear_css_buffer_counters(asd);
				atomisp_flush_bufs_and_wakeup(asd);
				complete(&asd->init_done);
			}
			if (IS_ISP2401)
				atomisp_wdt_stop(asd, false);
		}

		if (!IS_ISP2401) {
			atomic_set(&isp->wdt_count, 0);
		} else {
			isp->isp_fatal_error = true;
			atomic_set(&isp->wdt_work_queued, 0);

			mutex_unlock(&isp->mutex);
			return;
		}
	}

	if (atomisp_streaming_count(isp))
		__atomisp_css_recover(isp, true);
	if (IS_ISP2401) {
		for (i = 0; i < isp->num_of_streams; i++) {
			struct atomisp_sub_device *asd = &isp->asd[i];

			if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
				continue;

			atomisp_wdt_refresh(asd, ATOMISP_ISP_TIMEOUT_DURATION);
		}
	}

	dev_err(isp->dev, "timeout recovery handling done\n");
	atomic_set(&isp->wdt_work_queued, 0);

	mutex_unlock(&isp->mutex);
}

void atomisp_css_flush(struct atomisp_device *isp)
{
	int i;

	lockdep_assert_held(&isp->mutex);

	if (!atomisp_streaming_count(isp))
		return;

	/* Disable wdt */
	for (i = 0; i < isp->num_of_streams; i++) {
		struct atomisp_sub_device *asd = &isp->asd[i];

		atomisp_wdt_stop(asd, true);
	}

	/* Start recover */
	__atomisp_css_recover(isp, false);
	/* Restore wdt */
	for (i = 0; i < isp->num_of_streams; i++) {
		struct atomisp_sub_device *asd = &isp->asd[i];

		if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
			continue;

		atomisp_wdt_refresh(asd, ATOMISP_ISP_TIMEOUT_DURATION);
	}
	dev_dbg(isp->dev, "atomisp css flush done\n");
}

void atomisp_wdt(struct timer_list *t)
{
	struct atomisp_sub_device *asd;
	struct atomisp_device *isp;

	if (!IS_ISP2401) {
		asd = from_timer(asd, t, wdt);
		isp = asd->isp;
	} else {
		struct atomisp_video_pipe *pipe = from_timer(pipe, t, wdt);

		asd = pipe->asd;
		isp = asd->isp;

		atomic_inc(&pipe->wdt_count);
		dev_warn(isp->dev,
			"[WARNING]asd %d pipe %s ISP timeout %d!\n",
			asd->index, pipe->vdev.name,
			atomic_read(&pipe->wdt_count));
	}

	if (atomic_read(&isp->wdt_work_queued)) {
		dev_dbg(isp->dev, "ISP watchdog was put into workqueue\n");
		return;
	}
	atomic_set(&isp->wdt_work_queued, 1);
	queue_work(isp->wdt_work_queue, &isp->wdt_work);
}

/* ISP2400 */
void atomisp_wdt_start(struct atomisp_sub_device *asd)
{
	atomisp_wdt_refresh(asd, ATOMISP_ISP_TIMEOUT_DURATION);
}

/* ISP2401 */
void atomisp_wdt_refresh_pipe(struct atomisp_video_pipe *pipe,
			      unsigned int delay)
{
	unsigned long next;

	if (!pipe->asd) {
		dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
			__func__, pipe->vdev.name);
		return;
	}

	if (delay != ATOMISP_WDT_KEEP_CURRENT_DELAY)
		pipe->wdt_duration = delay;

	next = jiffies + pipe->wdt_duration;

	/* Override next if it has been pushed beyon the "next" time */
	if (atomisp_is_wdt_running(pipe) && time_after(pipe->wdt_expires, next))
		next = pipe->wdt_expires;

	pipe->wdt_expires = next;

	if (atomisp_is_wdt_running(pipe))
		dev_dbg(pipe->asd->isp->dev, "WDT will hit after %d ms (%s)\n",
			((int)(next - jiffies) * 1000 / HZ), pipe->vdev.name);
	else
		dev_dbg(pipe->asd->isp->dev, "WDT starts with %d ms period (%s)\n",
			((int)(next - jiffies) * 1000 / HZ), pipe->vdev.name);

	mod_timer(&pipe->wdt, next);
}

void atomisp_wdt_refresh(struct atomisp_sub_device *asd, unsigned int delay)
{
	if (!IS_ISP2401) {
		unsigned long next;

		if (delay != ATOMISP_WDT_KEEP_CURRENT_DELAY)
			asd->wdt_duration = delay;

		next = jiffies + asd->wdt_duration;

		/* Override next if it has been pushed beyon the "next" time */
		if (atomisp_is_wdt_running(asd) && time_after(asd->wdt_expires, next))
			next = asd->wdt_expires;

		asd->wdt_expires = next;

		if (atomisp_is_wdt_running(asd))
			dev_dbg(asd->isp->dev, "WDT will hit after %d ms\n",
				((int)(next - jiffies) * 1000 / HZ));
		else
			dev_dbg(asd->isp->dev, "WDT starts with %d ms period\n",
				((int)(next - jiffies) * 1000 / HZ));

		mod_timer(&asd->wdt, next);
		atomic_set(&asd->isp->wdt_count, 0);
	} else {
		dev_dbg(asd->isp->dev, "WDT refresh all:\n");
		if (atomisp_is_wdt_running(&asd->video_out_capture))
			atomisp_wdt_refresh_pipe(&asd->video_out_capture, delay);
		if (atomisp_is_wdt_running(&asd->video_out_preview))
			atomisp_wdt_refresh_pipe(&asd->video_out_preview, delay);
		if (atomisp_is_wdt_running(&asd->video_out_vf))
			atomisp_wdt_refresh_pipe(&asd->video_out_vf, delay);
		if (atomisp_is_wdt_running(&asd->video_out_video_capture))
			atomisp_wdt_refresh_pipe(&asd->video_out_video_capture, delay);
	}
}

/* ISP2401 */
void atomisp_wdt_stop_pipe(struct atomisp_video_pipe *pipe, bool sync)
{
	if (!atomisp_is_wdt_running(pipe))
		return;

	dev_dbg(pipe->asd->isp->dev,
		"WDT stop asd %d (%s)\n", pipe->asd->index, pipe->vdev.name);

	if (sync) {
		del_timer_sync(&pipe->wdt);
		cancel_work_sync(&pipe->asd->isp->wdt_work);
	} else {
		del_timer(&pipe->wdt);
	}
}

/* ISP 2401 */
void atomisp_wdt_start_pipe(struct atomisp_video_pipe *pipe)
{
	atomisp_wdt_refresh_pipe(pipe, ATOMISP_ISP_TIMEOUT_DURATION);
}

void atomisp_wdt_stop(struct atomisp_sub_device *asd, bool sync)
{
	dev_dbg(asd->isp->dev, "WDT stop:\n");

	if (!IS_ISP2401) {
		if (sync) {
			del_timer_sync(&asd->wdt);
			cancel_work_sync(&asd->isp->wdt_work);
		} else {
			del_timer(&asd->wdt);
		}
	} else {
		atomisp_wdt_stop_pipe(&asd->video_out_capture, sync);
		atomisp_wdt_stop_pipe(&asd->video_out_preview, sync);
		atomisp_wdt_stop_pipe(&asd->video_out_vf, sync);
		atomisp_wdt_stop_pipe(&asd->video_out_video_capture, sync);
	}
}

void atomisp_setup_flash(struct atomisp_sub_device *asd)
{
	struct atomisp_device *isp = asd->isp;
@@ -4122,19 +3782,6 @@ void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
		return;

	atomisp_qbuffers_to_css(asd);

	if (!IS_ISP2401) {
		if (!atomisp_is_wdt_running(asd) && atomisp_buffers_queued(asd))
			atomisp_wdt_start(asd);
	} else {
		if (atomisp_buffers_queued_pipe(pipe)) {
			if (!atomisp_is_wdt_running(pipe))
				atomisp_wdt_start_pipe(pipe);
			else
				atomisp_wdt_refresh_pipe(pipe,
							ATOMISP_WDT_KEEP_CURRENT_DELAY);
		}
	}
}

/*
+1 −2
Original line number Diff line number Diff line
@@ -65,8 +65,7 @@ bool atomisp_buffers_queued_pipe(struct atomisp_video_pipe *pipe);
/* Interrupt functions */
void atomisp_msi_irq_init(struct atomisp_device *isp);
void atomisp_msi_irq_uninit(struct atomisp_device *isp);
void atomisp_wdt_work(struct work_struct *work);
void atomisp_wdt(struct timer_list *t);
void atomisp_assert_recovery_work(struct work_struct *work);
void atomisp_setup_flash(struct atomisp_sub_device *asd);
irqreturn_t atomisp_isr(int irq, void *dev);
irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr);
+1 −42
Original line number Diff line number Diff line
@@ -3796,8 +3796,6 @@ int atomisp_css_isr_thread(struct atomisp_device *isp,
	enum atomisp_input_stream_id stream_id = 0;
	struct atomisp_css_event current_event;
	struct atomisp_sub_device *asd;
	bool reset_wdt_timer[MAX_STREAM_NUM] = {false};
	int i;

	lockdep_assert_held(&isp->mutex);

@@ -3813,14 +3811,8 @@ int atomisp_css_isr_thread(struct atomisp_device *isp,
				__func__,
				current_event.event.fw_assert_module_id,
				current_event.event.fw_assert_line_no);
			for (i = 0; i < isp->num_of_streams; i++)
				atomisp_wdt_stop(&isp->asd[i], 0);

			if (!IS_ISP2401)
				atomisp_wdt(&isp->asd[0].wdt);
			else
				queue_work(isp->wdt_work_queue, &isp->wdt_work);

			queue_work(system_long_wq, &isp->assert_recovery_work);
			return -EINVAL;
		} else if (current_event.event.type == IA_CSS_EVENT_TYPE_FW_WARNING) {
			dev_warn(isp->dev, "%s: ISP reports warning, code is %d, exp_id %d\n",
@@ -3849,20 +3841,12 @@ int atomisp_css_isr_thread(struct atomisp_device *isp,
			frame_done_found[asd->index] = true;
			atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_OUTPUT_FRAME,
					 current_event.pipe, true, stream_id);

			if (!IS_ISP2401)
				reset_wdt_timer[asd->index] = true; /* ISP running */

			break;
		case IA_CSS_EVENT_TYPE_SECOND_OUTPUT_FRAME_DONE:
			dev_dbg(isp->dev, "event: Second output frame done");
			frame_done_found[asd->index] = true;
			atomisp_buf_done(asd, 0, IA_CSS_BUFFER_TYPE_SEC_OUTPUT_FRAME,
					 current_event.pipe, true, stream_id);

			if (!IS_ISP2401)
				reset_wdt_timer[asd->index] = true; /* ISP running */

			break;
		case IA_CSS_EVENT_TYPE_3A_STATISTICS_DONE:
			dev_dbg(isp->dev, "event: 3A stats frame done");
@@ -3883,19 +3867,12 @@ int atomisp_css_isr_thread(struct atomisp_device *isp,
			atomisp_buf_done(asd, 0,
					 IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME,
					 current_event.pipe, true, stream_id);

			if (!IS_ISP2401)
				reset_wdt_timer[asd->index] = true; /* ISP running */

			break;
		case IA_CSS_EVENT_TYPE_SECOND_VF_OUTPUT_FRAME_DONE:
			dev_dbg(isp->dev, "event: second VF output frame done");
			atomisp_buf_done(asd, 0,
					 IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME,
					 current_event.pipe, true, stream_id);
			if (!IS_ISP2401)
				reset_wdt_timer[asd->index] = true; /* ISP running */

			break;
		case IA_CSS_EVENT_TYPE_DIS_STATISTICS_DONE:
			dev_dbg(isp->dev, "event: dis stats frame done");
@@ -3918,24 +3895,6 @@ int atomisp_css_isr_thread(struct atomisp_device *isp,
		}
	}

	if (IS_ISP2401)
		return 0;

	/* ISP2400: If there are no buffers queued then delete wdt timer. */
	for (i = 0; i < isp->num_of_streams; i++) {
		asd = &isp->asd[i];
		if (!asd)
			continue;
		if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED)
			continue;
		if (!atomisp_buffers_queued(asd))
			atomisp_wdt_stop(asd, false);
		else if (reset_wdt_timer[i])
			/* SOF irq should not reset wdt timer. */
			atomisp_wdt_refresh(asd,
					    ATOMISP_WDT_KEEP_CURRENT_DELAY);
	}

	return 0;
}

+1 −23
Original line number Diff line number Diff line
@@ -258,13 +258,7 @@ struct atomisp_device {
	/* isp timeout status flag */
	bool isp_timeout;
	bool isp_fatal_error;
	struct workqueue_struct *wdt_work_queue;
	struct work_struct wdt_work;

	/* ISP2400 */
	atomic_t wdt_count;

	atomic_t wdt_work_queued;
	struct work_struct assert_recovery_work;

	spinlock_t lock; /* Protects asd[i].streaming */

@@ -282,20 +276,4 @@ struct atomisp_device {

extern struct device *atomisp_dev;

#define atomisp_is_wdt_running(a) timer_pending(&(a)->wdt)

/* ISP2401 */
void atomisp_wdt_refresh_pipe(struct atomisp_video_pipe *pipe,
			      unsigned int delay);
void atomisp_wdt_refresh(struct atomisp_sub_device *asd, unsigned int delay);

/* ISP2400 */
void atomisp_wdt_start(struct atomisp_sub_device *asd);

/* ISP2401 */
void atomisp_wdt_start_pipe(struct atomisp_video_pipe *pipe);
void atomisp_wdt_stop_pipe(struct atomisp_video_pipe *pipe, bool sync);

void atomisp_wdt_stop(struct atomisp_sub_device *asd, bool sync);

#endif /* __ATOMISP_INTERNAL_H__ */
+0 −60
Original line number Diff line number Diff line
@@ -1363,15 +1363,6 @@ static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
			atomisp_handle_parameter_and_buffer(pipe);
		} else {
			atomisp_qbuffers_to_css(asd);

			if (!IS_ISP2401) {
				if (!atomisp_is_wdt_running(asd) && atomisp_buffers_queued(asd))
					atomisp_wdt_start(asd);
			} else {
				if (!atomisp_is_wdt_running(pipe) &&
				    atomisp_buffers_queued_pipe(pipe))
					atomisp_wdt_start_pipe(pipe);
			}
		}
	}

@@ -1594,33 +1585,6 @@ int atomisp_stream_on_master_slave_sensor(struct atomisp_device *isp,
	return 0;
}

/* FIXME! ISP2400 */
static void __wdt_on_master_slave_sensor(struct atomisp_device *isp,
					 unsigned int wdt_duration)
{
	if (atomisp_buffers_queued(&isp->asd[0]))
		atomisp_wdt_refresh(&isp->asd[0], wdt_duration);
	if (atomisp_buffers_queued(&isp->asd[1]))
		atomisp_wdt_refresh(&isp->asd[1], wdt_duration);
}

/* FIXME! ISP2401 */
static void __wdt_on_master_slave_sensor_pipe(struct atomisp_video_pipe *pipe,
					      unsigned int wdt_duration,
					      bool enable)
{
	static struct atomisp_video_pipe *pipe0;

	if (enable) {
		if (atomisp_buffers_queued_pipe(pipe0))
			atomisp_wdt_refresh_pipe(pipe0, wdt_duration);
		if (atomisp_buffers_queued_pipe(pipe))
			atomisp_wdt_refresh_pipe(pipe, wdt_duration);
	} else {
		pipe0 = pipe;
	}
}

static void atomisp_pause_buffer_event(struct atomisp_device *isp)
{
	struct v4l2_event event = {0};
@@ -1670,7 +1634,6 @@ static int atomisp_streamon(struct file *file, void *fh,
	struct pci_dev *pdev = to_pci_dev(isp->dev);
	enum ia_css_pipe_id css_pipe_id;
	unsigned int sensor_start_stream;
	unsigned int wdt_duration = ATOMISP_ISP_TIMEOUT_DURATION;
	unsigned long irqflags;
	int ret;

@@ -1845,15 +1808,9 @@ static int atomisp_streamon(struct file *file, void *fh,
			dev_err(isp->dev, "master slave sensor stream on failed!\n");
			goto out;
		}
		if (!IS_ISP2401)
			__wdt_on_master_slave_sensor(isp, wdt_duration);
		else
			__wdt_on_master_slave_sensor_pipe(pipe, wdt_duration, true);
		goto start_delay_wq;
	} else if (asd->depth_mode->val && (atomisp_streaming_count(isp) <
					    ATOMISP_DEPTH_SENSOR_STREAMON_COUNT)) {
		if (IS_ISP2401)
			__wdt_on_master_slave_sensor_pipe(pipe, wdt_duration, false);
		goto start_delay_wq;
	}

@@ -1875,14 +1832,6 @@ static int atomisp_streamon(struct file *file, void *fh,
		goto out;
	}

	if (!IS_ISP2401) {
		if (atomisp_buffers_queued(asd))
			atomisp_wdt_refresh(asd, wdt_duration);
	} else {
		if (atomisp_buffers_queued_pipe(pipe))
			atomisp_wdt_refresh_pipe(pipe, wdt_duration);
	}

start_delay_wq:
	if (asd->continuous_mode->val) {
		struct v4l2_mbus_framefmt *sink;
@@ -1986,16 +1935,7 @@ int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
		asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING;
		first_streamoff = true;
	}
	spin_unlock_irqrestore(&isp->lock, flags);

	if (first_streamoff) {
		/* if other streams are running, should not disable watch dog */
		mutex_unlock(&isp->mutex);
		atomisp_wdt_stop(asd, true);
		mutex_lock(&isp->mutex);
	}

	spin_lock_irqsave(&isp->lock, flags);
	if (atomisp_subdev_streaming_count(asd) == 1)
		asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED;
	spin_unlock_irqrestore(&isp->lock, flags);
Loading