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

Commit fd7aadcb authored by Ravi Kishore Tanuku's avatar Ravi Kishore Tanuku Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: Add spinlock protection for flags in CCI driver



The race conditions in accessing the CCI queue control flags
are resulting in CCI timeout issues. Added spinlocks to avoid
these issues.

Change-Id: I13ceeb4f5a139d7d66bbf98ac541590d65ca526b
Signed-off-by: default avatarRavi Kishore Tanuku <rktanuku@codeaurora.org>
parent 272879fc
Loading
Loading
Loading
Loading
+58 −1
Original line number Diff line number Diff line
@@ -201,6 +201,7 @@ static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
	enum cci_i2c_queue_t queue)
{
	int32_t rc = 0;
	unsigned long flags;
	uint32_t read_val = 0;
	uint32_t reg_offset = master * 0x200 + queue * 0x100;
	read_val = msm_camera_io_r_mb(cci_dev->base +
@@ -223,6 +224,8 @@ static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
			CCI_I2C_M0_Q0_EXEC_WORD_CNT_ADDR + reg_offset);
		reg_val = 1 << ((master * 2) + queue);
		CDBG("%s:%d CCI_QUEUE_START_ADDR\n", __func__, __LINE__);
		spin_lock_irqsave(&cci_dev->cci_master_info[master].
						lock_q[queue], flags);
		atomic_set(&cci_dev->cci_master_info[master].
						done_pending[queue], 1);
		msm_camera_io_w_mb(reg_val, cci_dev->base +
@@ -230,6 +233,8 @@ static int32_t msm_cci_validate_queue(struct cci_device *cci_dev,
		CDBG("%s line %d wait_for_completion_timeout\n",
			__func__, __LINE__);
		atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
						lock_q[queue], flags);
		rc = wait_for_completion_timeout(&cci_dev->
			cci_master_info[master].report_q[queue], CCI_TIMEOUT);
		if (rc <= 0) {
@@ -438,10 +443,17 @@ static int32_t msm_cci_wait_report_cmd(struct cci_device *cci_dev,
	enum cci_i2c_master_t master,
	enum cci_i2c_queue_t queue)
{
	unsigned long flags;
	uint32_t reg_val = 1 << ((master * 2) + queue);
	msm_cci_load_report_cmd(cci_dev, master, queue);

	spin_lock_irqsave(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);
	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
	atomic_set(&cci_dev->cci_master_info[master].done_pending[queue], 1);
	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);

	msm_camera_io_w_mb(reg_val, cci_dev->base +
		CCI_QUEUE_START_ADDR);
	return msm_cci_wait(cci_dev, master, queue);
@@ -451,13 +463,19 @@ static void msm_cci_process_half_q(struct cci_device *cci_dev,
	enum cci_i2c_master_t master,
	enum cci_i2c_queue_t queue)
{
	unsigned long flags;
	uint32_t reg_val = 1 << ((master * 2) + queue);

	spin_lock_irqsave(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);
	if (0 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) {
		msm_cci_load_report_cmd(cci_dev, master, queue);
		atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 1);
		msm_camera_io_w_mb(reg_val, cci_dev->base +
			CCI_QUEUE_START_ADDR);
	}
	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);
}

static int32_t msm_cci_process_full_q(struct cci_device *cci_dev,
@@ -465,15 +483,23 @@ static int32_t msm_cci_process_full_q(struct cci_device *cci_dev,
	enum cci_i2c_queue_t queue)
{
	int32_t rc = 0;
	unsigned long flags;

	spin_lock_irqsave(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);
	if (1 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) {
		atomic_set(&cci_dev->cci_master_info[master].
						done_pending[queue], 1);
		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);
		rc = msm_cci_wait(cci_dev, master, queue);
		if (rc < 0) {
			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
			return rc;
		}
	} else {
		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
						lock_q[queue], flags);
		rc = msm_cci_wait_report_cmd(cci_dev, master, queue);
		if (rc < 0) {
			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
@@ -501,8 +527,13 @@ static int32_t msm_cci_transfer_end(struct cci_device *cci_dev,
	enum cci_i2c_queue_t queue)
{
	int32_t rc = 0;
	unsigned long flags;

	spin_lock_irqsave(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);
	if (0 == atomic_read(&cci_dev->cci_master_info[master].q_free[queue])) {
		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
						lock_q[queue], flags);
		rc = msm_cci_lock_queue(cci_dev, master, queue, 0);
		if (rc < 0) {
			pr_err("%s failed line %d\n", __func__, __LINE__);
@@ -516,6 +547,8 @@ static int32_t msm_cci_transfer_end(struct cci_device *cci_dev,
	} else {
		atomic_set(&cci_dev->cci_master_info[master].
						done_pending[queue], 1);
		spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
						lock_q[queue], flags);
		rc = msm_cci_wait(cci_dev, master, queue);
		if (rc < 0) {
			pr_err("%s: %d failed rc %d\n", __func__, __LINE__, rc);
@@ -570,6 +603,7 @@ static int32_t msm_cci_data_queue(struct cci_device *cci_dev,
	uint32_t reg_offset;
	uint32_t val = 0;
	uint32_t max_queue_size;
	unsigned long flags;

	if (i2c_cmd == NULL) {
		pr_err("%s:%d Failed line\n", __func__,
@@ -613,7 +647,11 @@ static int32_t msm_cci_data_queue(struct cci_device *cci_dev,
	msm_camera_io_w_mb(val, cci_dev->base + CCI_I2C_M0_Q0_LOAD_DATA_ADDR +
		reg_offset);

	spin_lock_irqsave(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);
	atomic_set(&cci_dev->cci_master_info[master].q_free[queue], 0);
	spin_unlock_irqrestore(&cci_dev->cci_master_info[master].
					lock_q[queue], flags);

	max_queue_size = cci_dev->cci_i2c_queue_info[master][queue].
			max_queue_size;
@@ -1641,6 +1679,7 @@ static int32_t msm_cci_config(struct v4l2_subdev *sd,
static irqreturn_t msm_cci_irq(int irq_num, void *data)
{
	uint32_t irq;
	unsigned long flags;
	struct cci_device *cci_dev = data;
	irq = msm_camera_io_r_mb(cci_dev->base + CCI_IRQ_STATUS_0_ADDR);
	msm_camera_io_w_mb(irq, cci_dev->base + CCI_IRQ_CLEAR_0_ADDR);
@@ -1667,22 +1706,30 @@ static irqreturn_t msm_cci_irq(int irq_num, void *data)
	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0_REPORT_BMSK) {
		struct msm_camera_cci_master_info *cci_master_info;
		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
		spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_0].
						lock_q[QUEUE_0], flags);
		atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
		cci_master_info->status = 0;
		if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
			complete(&cci_master_info->report_q[QUEUE_0]);
			atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
		}
		spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_0].
					lock_q[QUEUE_0], flags);
	}
	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q1_REPORT_BMSK) {
		struct msm_camera_cci_master_info *cci_master_info;
		cci_master_info = &cci_dev->cci_master_info[MASTER_0];
		spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_0].
						lock_q[QUEUE_1], flags);
		atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
		cci_master_info->status = 0;
		if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
			complete(&cci_master_info->report_q[QUEUE_1]);
			atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
		}
		spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_0].
						lock_q[QUEUE_1], flags);
	}
	if (irq & CCI_IRQ_STATUS_0_I2C_M1_RD_DONE_BMSK) {
		cci_dev->cci_master_info[MASTER_1].status = 0;
@@ -1691,22 +1738,30 @@ static irqreturn_t msm_cci_irq(int irq_num, void *data)
	if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q0_REPORT_BMSK) {
		struct msm_camera_cci_master_info *cci_master_info;
		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
		spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_1].
						lock_q[QUEUE_0], flags);
		atomic_set(&cci_master_info->q_free[QUEUE_0], 0);
		cci_master_info->status = 0;
		if (atomic_read(&cci_master_info->done_pending[QUEUE_0]) == 1) {
			complete(&cci_master_info->report_q[QUEUE_0]);
			atomic_set(&cci_master_info->done_pending[QUEUE_0], 0);
		}
		spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_1].
						lock_q[QUEUE_0], flags);
	}
	if (irq & CCI_IRQ_STATUS_0_I2C_M1_Q1_REPORT_BMSK) {
		struct msm_camera_cci_master_info *cci_master_info;
		cci_master_info = &cci_dev->cci_master_info[MASTER_1];
		spin_lock_irqsave(&cci_dev->cci_master_info[MASTER_1].
						lock_q[QUEUE_1], flags);
		atomic_set(&cci_master_info->q_free[QUEUE_1], 0);
		cci_master_info->status = 0;
		if (atomic_read(&cci_master_info->done_pending[QUEUE_1]) == 1) {
			complete(&cci_master_info->report_q[QUEUE_1]);
			atomic_set(&cci_master_info->done_pending[QUEUE_1], 0);
		}
		spin_unlock_irqrestore(&cci_dev->cci_master_info[MASTER_1].
						lock_q[QUEUE_1], flags);
	}
	if (irq & CCI_IRQ_STATUS_0_I2C_M0_Q0Q1_HALT_ACK_BMSK) {
		cci_dev->cci_master_info[MASTER_0].reset_pending = TRUE;
@@ -1795,6 +1850,8 @@ static void msm_cci_init_cci_params(struct cci_device *new_cci_dev)
			mutex_init(&new_cci_dev->cci_master_info[i].mutex_q[j]);
			init_completion(&new_cci_dev->
				cci_master_info[i].report_q[j]);
			spin_lock_init(&new_cci_dev->
				cci_master_info[i].lock_q[j]);
		}
	}
	return;
+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -125,6 +125,7 @@ struct msm_camera_cci_master_info {
	struct mutex mutex_q[NUM_QUEUES];
	struct completion report_q[NUM_QUEUES];
	atomic_t done_pending[NUM_QUEUES];
	spinlock_t lock_q[NUM_QUEUES];
};

struct msm_cci_clk_params_t {