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

Commit 7128076d authored by Krishnankutty Kolathappilly's avatar Krishnankutty Kolathappilly
Browse files

msm: cpp: Synchronize writing payload to cpp hardware



When the system is slow, interrupt is received from cpp hardware
just after driver times out. Tasklet processes the interrupt and
sends buffer done. A new frame is send from userspace and is
written to the hardware at the same time firmware is written.
This causes CPP hardware to be in bad state and poll failures are
observed. This can cause stability crashes. The fix is to
synchronize writing payload from user thread and firmware from
work queue.

CRs-Fixed: 910559 919550
Change-Id: I75594b5202f0bed39840b36064f4e21b03e83355
Signed-off-by: default avatarKrishnankutty Kolathappilly <kkolatha@codeaurora.org>
parent 09deb55f
Loading
Loading
Loading
Loading
+41 −19
Original line number Diff line number Diff line
@@ -183,7 +183,7 @@ static struct msm_bus_scale_pdata msm_cpp_bus_scale_data = {
	qcmd;			 \
})

#define MSM_CPP_MAX_TIMEOUT_TRIAL 0
#define MSM_CPP_MAX_TIMEOUT_TRIAL 1

struct msm_cpp_timer_data_t {
	struct cpp_device *cpp_dev;
@@ -1716,7 +1716,6 @@ static void msm_cpp_flush_queue_and_release_buffer(struct cpp_device *cpp_dev,
	atomic_set(&cpp_timer.used, 0);
	for (i = 0; i < MAX_CPP_PROCESSING_FRAME; i++)
		cpp_timer.data.processed_frame[i] = NULL;
	cpp_dev->timeout_trial_cnt = 0;
}

static void msm_cpp_set_micro_irq_mask(struct cpp_device *cpp_dev,
@@ -1760,7 +1759,7 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
	queue = &cpp_timer.data.cpp_dev->processing_q;
	queue_len = queue->len;

	pr_debug("Reloading firmware\n");
	pr_debug("Reloading firmware %d\n", queue_len);
	rc = cpp_load_fw(cpp_timer.data.cpp_dev,
		cpp_timer.data.cpp_dev->fw_name_bin);
	if (rc) {
@@ -1769,6 +1768,7 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
		/* clean buf queue here */
		msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len);
		msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x0);
		cpp_dev->timeout_trial_cnt = 0;
		goto end;
	} else {
		pr_debug("Firmware loading done\n");
@@ -1778,20 +1778,20 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
		pr_warn("Delayed trigger, IRQ serviced\n");
		/* Do not flush queue here as it is not a fatal error */
		msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
		cpp_dev->timeout_trial_cnt = 0;
		goto end;
	}

	if (cpp_dev->timeout_trial_cnt >=
		cpp_dev->max_timeout_trial_cnt) {
		pr_warn("Max trial reached\n");
		cpp_dev->state = CPP_STATE_OFF;
		msm_cpp_flush_queue_and_release_buffer(cpp_dev, queue_len);
		msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x0);
		msm_cpp_set_micro_irq_mask(cpp_dev, 1, 0x8);
		goto end;
	}

	atomic_set(&cpp_timer.used, 1);
	pr_debug("Starting timer to fire in %d ms. (jiffies=%lu)\n",
	pr_warn("Starting timer to fire in %d ms. (jiffies=%lu)\n",
		CPP_CMD_TIMEOUT_MS, jiffies);
	mod_timer(&cpp_timer.cpp_timer,
		jiffies + msecs_to_jiffies(CPP_CMD_TIMEOUT_MS));
@@ -1817,6 +1817,7 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
					cpp_dev->state = CPP_STATE_OFF;
					msm_cpp_set_micro_irq_mask(cpp_dev,
						0, 0x0);
					cpp_dev->timeout_trial_cnt = 0;
					goto end;
				}
			}
@@ -1831,6 +1832,7 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
			msm_cpp_flush_queue_and_release_buffer(cpp_dev,
				queue_len);
			msm_cpp_set_micro_irq_mask(cpp_dev, 0, 0x0);
			cpp_dev->timeout_trial_cnt = 0;
			goto end;
		}
		/* send stripes */
@@ -1860,6 +1862,7 @@ static void msm_cpp_do_timeout_work(struct work_struct *work)
			msm_cpp_flush_queue_and_release_buffer(cpp_dev,
				queue_len);
			msm_cpp_set_micro_irq_mask(cpp_dev, 0, 0x0);
			cpp_dev->timeout_trial_cnt = 0;
			goto end;
		}
		/* send trailer */
@@ -3568,13 +3571,16 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
			vdev, cpp_dev);
		return -EINVAL;
	}
	mutex_lock(&cpp_dev->mutex);
	/*
	 * copy the user space 32 bit pointer to kernel space 32 bit compat
	 * pointer
	 */
	if (copy_from_user(&up32_ioctl, (void __user *)up,
		sizeof(up32_ioctl)))
		sizeof(up32_ioctl))) {
		mutex_unlock(&cpp_dev->mutex);
		return -EFAULT;
	}

	/* copy the data from 32 bit compat to kernel space 64 bit pointer */
	kp_ioctl.id = up32_ioctl.id;
@@ -3584,6 +3590,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
	kp_ioctl.ioctl_ptr = compat_ptr(up32_ioctl.ioctl_ptr);
	if (!kp_ioctl.ioctl_ptr) {
		pr_err("%s: Invalid ioctl pointer\n", __func__);
		mutex_unlock(&cpp_dev->mutex);
		return -EINVAL;
	}

@@ -3601,8 +3608,10 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,

		if (copy_from_user(&k32_frame_info,
			(void __user *)kp_ioctl.ioctl_ptr,
			sizeof(k32_frame_info)))
			sizeof(k32_frame_info))) {
			mutex_unlock(&cpp_dev->mutex);
			return -EFAULT;
		}
		/* Get the cpp frame pointer */
		cpp_frame = get_64bit_cpp_frame_from_compat(&kp_ioctl);

@@ -3620,6 +3629,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
			}
		} else {
			pr_err("%s: Error getting frame\n", __func__);
			mutex_unlock(&cpp_dev->mutex);
			rc = -EINVAL;
		}

@@ -3634,8 +3644,10 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,

		if (copy_to_user((void __user *)kp_ioctl.ioctl_ptr,
			&k32_frame_info,
			sizeof(k32_frame_info)))
			sizeof(k32_frame_info))) {
			mutex_unlock(&cpp_dev->mutex);
			return -EFAULT;
		}

		cmd = VIDIOC_MSM_CPP_CFG;
		break;
@@ -3657,8 +3669,10 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
		u32_cpp_hw_info.freq_tbl_count =
			cpp_dev->hw_info.freq_tbl_count;
		if (copy_to_user((void __user *)kp_ioctl.ioctl_ptr,
			&u32_cpp_hw_info, sizeof(struct cpp_hw_info_32_t)))
			&u32_cpp_hw_info, sizeof(struct cpp_hw_info_32_t))) {
			mutex_unlock(&cpp_dev->mutex);
			return -EFAULT;
		}

		cmd = VIDIOC_MSM_CPP_GET_HW_INFO;
		break;
@@ -3683,6 +3697,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
		if (copy_to_user(
				(void __user *)kp_ioctl.ioctl_ptr, &inst_info,
				sizeof(struct msm_cpp_frame_info32_t))) {
			mutex_unlock(&cpp_dev->mutex);
			return -EFAULT;
		}
		cmd = VIDIOC_MSM_CPP_GET_INST_INFO;
@@ -3709,12 +3724,14 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
		kp_ioctl.ioctl_ptr = (void *)&k_cpp_buff_info;
		if (is_compat_task()) {
			if (kp_ioctl.len != sizeof(
				struct msm_cpp_stream_buff_info32_t))
				struct msm_cpp_stream_buff_info32_t)) {
				mutex_unlock(&cpp_dev->mutex);
				return -EINVAL;
			else
			} else {
				kp_ioctl.len =
				  sizeof(struct msm_cpp_stream_buff_info_t);
			}
		}
		if (cmd == VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO32)
			cmd = VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO;
		else if (cmd == VIDIOC_MSM_CPP_DELETE_STREAM_BUFF32)
@@ -3740,7 +3757,6 @@ 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, POP_FRONT);
		if (!event_qcmd) {
			pr_err("no queue cmd available");
@@ -3767,7 +3783,6 @@ 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:
@@ -3781,12 +3796,14 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
		kp_ioctl.ioctl_ptr = (void *)&clock_settings;
		if (is_compat_task()) {
			if (kp_ioctl.len != sizeof(
				struct msm_cpp_clock_settings32_t))
				struct msm_cpp_clock_settings32_t)) {
				mutex_unlock(&cpp_dev->mutex);
				return -EINVAL;
			else
			} else {
				kp_ioctl.len =
					sizeof(struct msm_cpp_clock_settings_t);
			}
		}
		cmd = VIDIOC_MSM_CPP_SET_CLOCK;
		break;
	}
@@ -3824,15 +3841,19 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
	}
	case VIDIOC_MSM_CPP_POP_STREAM_BUFFER32:
	{
		if (kp_ioctl.len != sizeof(struct msm_cpp_frame_info32_t))
		if (kp_ioctl.len != sizeof(struct msm_cpp_frame_info32_t)) {
			mutex_unlock(&cpp_dev->mutex);
			return -EINVAL;
		else
		} else {
			kp_ioctl.len = sizeof(struct msm_cpp_frame_info_t);
		}

		if (copy_from_user(&k32_frame_info,
			(void __user *)kp_ioctl.ioctl_ptr,
			sizeof(k32_frame_info)))
			sizeof(k32_frame_info))) {
			mutex_unlock(&cpp_dev->mutex);
			return -EFAULT;
		}

		memset(&k64_frame_info, 0, sizeof(k64_frame_info));
		k64_frame_info.identity = k32_frame_info.identity;
@@ -3859,6 +3880,7 @@ static long msm_cpp_subdev_fops_compat_ioctl(struct file *file,
		break;
	}

	mutex_unlock(&cpp_dev->mutex);
	switch (cmd) {
	case VIDIOC_MSM_CPP_LOAD_FIRMWARE:
	case VIDIOC_MSM_CPP_FLUSH_QUEUE: