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

Commit b82c5427 authored by Ram Chandrasekar's avatar Ram Chandrasekar Committed by Gerrit - the friendly Code Review server
Browse files

msm: lmh_lite: Enable interrupt inside critical section



Interrupt enable code is outside the critical section and
this can lead to race condition between multiple threads.
This race condition can result in enabling the interrupt,
which is disabled by the interrupt service routine. This
can lead to interrupt storm.

To avoid this, the interrupt enable is done inside critical
section to avoid any race condition.

CRs-Fixed: 850290
Change-Id: Ifeea212601e39b554740d88da0c662e4a9be0d87
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent af8bd7c7
Loading
Loading
Loading
Loading
+18 −14
Original line number Diff line number Diff line
@@ -278,7 +278,8 @@ static int lmh_reset(struct lmh_sensor_ops *ops)
		trace_lmh_sensor_interrupt(lmh_sensor->sensor_name,
			lmh_sensor->last_read_value);
	} else {
		goto reset_exit;
		pr_err("Sensor:[%s] is already in reset state\n",
			lmh_sensor->sensor_name);
	}

	if (!lmh_data->intr_status_val) {
@@ -299,20 +300,21 @@ static int lmh_reset(struct lmh_sensor_ops *ops)
					lmh_iter_sensor->last_read_value);
			}
		}
		if (!lmh_data->intr_status_val)
			lmh_data->intr_state = LMH_ISR_MONITOR;
	}

reset_exit:
	up_write(&lmh_sensor_access);
		if (!lmh_data->intr_status_val) {
		/* cancel the poll work after releasing the lock to avoid
		** deadlock situation */
			lmh_data->intr_state = LMH_ISR_MONITOR;
			pr_debug("Zero throttling. Re-enabling interrupt\n");
		cancel_delayed_work_sync(&lmh_data->poll_work);
			/*
			 * Don't use cancel_delayed_work_sync as it will lead
			 * to deadlock because of the mutex
			 */
			cancel_delayed_work(&lmh_data->poll_work);
			trace_lmh_event_call("Lmh Interrupt Clear");
			enable_irq(lmh_data->irq_num);
		}
	}

reset_exit:
	up_write(&lmh_sensor_access);
	return ret;
}

@@ -446,10 +448,13 @@ static void lmh_trim_error(void)

static void lmh_notify(struct work_struct *work)
{
	struct lmh_driver_data *lmh_dat;
	struct lmh_driver_data *lmh_dat = container_of(work,
			struct lmh_driver_data, isr_work);

	/* Cancel any pending polling work event before scheduling new one */
	cancel_delayed_work_sync(&lmh_dat->poll_work);
	down_write(&lmh_sensor_access);
	lmh_dat = container_of(work, struct lmh_driver_data, isr_work);
	lmh_dat->intr_state = LMH_ISR_POLLING;
	if (!lmh_data->trim_err_disable) {
		lmh_dat->intr_reg_val = readl_relaxed(lmh_dat->intr_addr);
		pr_debug("Lmh hw interrupt:%d\n", lmh_dat->intr_reg_val);
@@ -480,13 +485,12 @@ notify_exit:

static irqreturn_t lmh_handle_isr(int irq, void *data)
{
	struct lmh_driver_data *lmh_dat = (struct lmh_driver_data *)data;
	struct lmh_driver_data *lmh_dat = data;

	pr_debug("LMH Interrupt triggered\n");
	trace_lmh_event_call("Lmh Interrupt");
	if (lmh_dat->intr_state == LMH_ISR_MONITOR) {
		disable_irq_nosync(lmh_dat->irq_num);
		lmh_dat->intr_state = LMH_ISR_POLLING;
		queue_work(lmh_dat->isr_wq, &lmh_dat->isr_work);
	}