Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e0100bc1 authored by Rajakumar Govindaram's avatar Rajakumar Govindaram
Browse files

msm: camera2: cpp: Enhance timeout handler for multi-frame processing



The CPP driver can schedule multiple frames to achieve higher
performance. This results in multiple frames to be in pending state
in the driver. When timeout handler is invoked, the condition
of NACK and user event callbacks need to be sequeunced properly.
This change helps to serialize in such a way that the timeout
handler is allowed to complete the frame notification before any
user event callback is handled.

Change-Id: Ie883b1823000085094e39f4c0ae7e10a3d377d16
Signed-off-by: default avatarRajakumar Govindaram <rajakuma@codeaurora.org>
parent 1121aaf9
Loading
Loading
Loading
Loading
+66 −51
Original line number Diff line number Diff line
@@ -305,7 +305,8 @@ static int get_clock_index(const char *clk_name)
}


static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev);
static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
	uint8_t put_buf, uint8_t modify_timer);
static void cpp_load_fw(struct cpp_device *cpp_dev, char *fw_name_bin);
static void cpp_timer_callback(unsigned long data);

@@ -818,13 +819,15 @@ void msm_cpp_do_tasklet(unsigned long data)
					/* delete CPP timer */
					CPP_DBG("delete timer.\n");
					msm_cpp_timer_queue_update(cpp_dev);
					msm_cpp_notify_frame_done(cpp_dev);
					msm_cpp_notify_frame_done(cpp_dev,
						0, 1);
				} else if (msg_id ==
					MSM_CPP_MSG_ID_FRAME_NACK) {
					pr_err("NACK error from hw!!\n");
					CPP_DBG("delete timer.\n");
					msm_cpp_timer_queue_update(cpp_dev);
					msm_cpp_notify_frame_done(cpp_dev);
					msm_cpp_notify_frame_done(cpp_dev,
						0, 1);
				}
				i += cmd_len + 2;
			}
@@ -1433,7 +1436,8 @@ static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev,
	return rc;
}

static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev,
	uint8_t put_buf, uint8_t modify_timer)
{
	struct v4l2_event v4l2_evt;
	struct msm_queue_cmd *frame_qcmd = NULL;
@@ -1476,6 +1480,15 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
			buff_mgr_info.reserved = processed_frame->reserved;
			buff_mgr_info.index =
				processed_frame->output_buffer_info[0].index;
			if (put_buf) {
				rc = msm_cpp_buffer_ops(cpp_dev,
					VIDIOC_MSM_BUF_MNGR_PUT_BUF,
					&buff_mgr_info);
				if (rc < 0) {
					pr_err("error putting buffer\n");
					rc = -EINVAL;
				}
			} else {
				rc = msm_cpp_buffer_ops(cpp_dev,
					VIDIOC_MSM_BUF_MNGR_BUF_DONE,
					&buff_mgr_info);
@@ -1484,6 +1497,7 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
					rc = -EINVAL;
				}
			}
		}

		if (processed_frame->duplicate_output  &&
			!processed_frame->
@@ -1499,6 +1513,15 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
			buff_mgr_info.timestamp = processed_frame->timestamp;
			buff_mgr_info.index =
				processed_frame->output_buffer_info[1].index;
			if (put_buf) {
				rc = msm_cpp_buffer_ops(cpp_dev,
					VIDIOC_MSM_BUF_MNGR_PUT_BUF,
					&buff_mgr_info);
				if (rc < 0) {
					pr_err("error putting buffer\n");
					rc = -EINVAL;
				}
			} else {
				rc = msm_cpp_buffer_ops(cpp_dev,
					VIDIOC_MSM_BUF_MNGR_BUF_DONE,
					&buff_mgr_info);
@@ -1507,12 +1530,13 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev)
					rc = -EINVAL;
				}
			}
		}
NOTIFY_FRAME_DONE:
		v4l2_evt.id = processed_frame->inst_id;
		v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE;
		v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt);

		if (queue->len > 0) {
		if (modify_timer && (queue->len > 0)) {
			rc = mod_timer(&cpp_timer.cpp_timer,
				jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
			if (rc < 0)
@@ -1557,11 +1581,11 @@ static int msm_cpp_dump_frame_cmd(struct msm_cpp_frame_info_t *frame_info)

static void msm_cpp_do_timeout_work(struct work_struct *work)
{
	int ret;
	uint32_t i = 0, j = 0;
	struct msm_cpp_frame_info_t *this_frame = NULL;
	uint32_t i = 0;
	int32_t queue_len = 0;
	struct msm_device_queue *queue = NULL;

	pr_err("cpp_timer_callback called. (jiffies=%lu)\n",
	pr_info("cpp_timer_callback called. (jiffies=%lu)\n",
		jiffies);
	if (!work || cpp_timer.data.cpp_dev->state != CPP_STATE_ACTIVE) {
		pr_err("Invalid work:%p or state:%d\n", work,
@@ -1569,15 +1593,15 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
		return;
	}
	if (!atomic_read(&cpp_timer.used)) {
		pr_err("Delayed trigger, IRQ serviced\n");
		pr_info("Delayed trigger, IRQ serviced\n");
		return;
	}

	disable_irq(cpp_timer.data.cpp_dev->irq->start);
	pr_err("Reloading firmware\n");
	pr_info("Reloading firmware\n");
	cpp_load_fw(cpp_timer.data.cpp_dev,
		cpp_timer.data.cpp_dev->fw_name_bin);
	pr_err("Firmware loading done\n");
	pr_info("Firmware loading done\n");
	enable_irq(cpp_timer.data.cpp_dev->irq->start);
	msm_camera_io_w_mb(0x8, cpp_timer.data.cpp_dev->base +
		MSM_CPP_MICRO_IRQGEN_MASK);
@@ -1586,39 +1610,27 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
		MSM_CPP_MICRO_IRQGEN_CLR);

	if (!atomic_read(&cpp_timer.used)) {
		pr_err("Delayed trigger, IRQ serviced\n");
		pr_info("Delayed trigger, IRQ serviced\n");
		return;
	}

	if (cpp_timer.data.cpp_dev->timeout_trial_cnt >=
		MSM_CPP_MAX_TIMEOUT_TRIAL) {
		pr_info("Max trial reached\n");
		msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev);
		cpp_timer.data.cpp_dev->timeout_trial_cnt = 0;
		return;
	}
	queue = &cpp_timer.data.cpp_dev->processing_q;
	queue_len = queue->len;
	mutex_lock(&cpp_timer.data.cpp_dev->mutex);
	for (i = 0; i < MAX_CPP_PROCESSING_FRAME; i++)
		msm_cpp_dump_frame_cmd(cpp_timer.data.processed_frame[i]);

	for (j = 0; j < MAX_CPP_PROCESSING_FRAME; j++)
		msm_cpp_dump_frame_cmd(cpp_timer.data.processed_frame[j]);
	while (queue_len) {
		msm_cpp_notify_frame_done(cpp_timer.data.cpp_dev, 1, 0);
		queue_len--;
	}
	atomic_set(&cpp_timer.used, 0);
	for (i = 0; i < MAX_CPP_PROCESSING_FRAME; i++)
		cpp_timer.data.processed_frame[i] = NULL;
	cpp_timer.data.cpp_dev->timeout_trial_cnt = 0;
	mutex_unlock(&cpp_timer.data.cpp_dev->mutex);

	CPP_DBG("Starting timer to fire in %d ms. (jiffies=%lu)\n",
		CPP_CMD_TIMEOUT_MS, jiffies);
	ret = mod_timer(&cpp_timer.cpp_timer,
		jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
	if (ret)
		CPP_DBG("Timer has not expired yet\n");
	for (j = 0; j < MAX_CPP_PROCESSING_FRAME; j++) {
		this_frame = cpp_timer.data.processed_frame[j];
		if (this_frame) {
			pr_err("Rescheduling for identity=0x%x, frame_id=%03d\n",
				this_frame->identity, this_frame->frame_id);
			msm_cpp_write(0x6, cpp_timer.data.cpp_dev->base);
			for (i = 0; i < this_frame->msg_len; i++)
				msm_cpp_write(this_frame->cpp_cmd_msg[i],
					cpp_timer.data.cpp_dev->base);
		}
	}
	cpp_timer.data.cpp_dev->timeout_trial_cnt++;
	pr_info("exit\n");
	return;
}

@@ -2964,9 +2976,11 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
		struct msm_cpp_frame_info32_t k32_process_frame;

		CPP_DBG("VIDIOC_MSM_CPP_GET_EVENTPAYLOAD\n");
		mutex_lock(&cpp_dev->mutex);
		event_qcmd = msm_dequeue(queue, list_eventdata);
		if (!event_qcmd) {
			pr_err("no queue cmd available");
			mutex_unlock(&cpp_dev->mutex);
			return -EINVAL;
		}
		process_frame = event_qcmd->command;
@@ -2985,6 +2999,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
		kfree(process_frame);
		kfree(event_qcmd);
		cmd = VIDIOC_MSM_CPP_GET_EVENTPAYLOAD;
		mutex_unlock(&cpp_dev->mutex);
		break;
	}
	case VIDIOC_MSM_CPP_SET_CLOCK32:
+1 −1
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@
#define MSM_CPP_START_ADDRESS		0x0
#define MSM_CPP_END_ADDRESS			0x3F00

#define MSM_CPP_POLL_RETRIES		20
#define MSM_CPP_POLL_RETRIES		200
#define MSM_CPP_TASKLETQ_SIZE		16
#define MSM_CPP_TX_FIFO_LEVEL		16
#define MSM_CPP_RX_FIFO_LEVEL		512