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

Commit a5b2aa73 authored by Saravana Kannan's avatar Saravana Kannan Committed by Gerrit - the friendly Code Review server
Browse files

PM / devfreq: bw_hwmon: Fix race condition in polling interval update



When the polling interval is updated, the delayed workqueue is cancelled
and requeued with the new polling interval. However, the bw_hwmon IRQ can
come at the same time and try to stop and restart the delayed work (in the
IRQ thread). This can cause a race where the work might be queued twice or
canceled twice and cause a crash.

Fix this race condition by suspending and resuming the HW monitor when we
are updating the polling interval. This entirely avoids the race because
suspending the HW monitor also avoid the possibility of the IRQ coming
during the polling interval update.

CRs-Fixed: 954082
Change-Id: Ic7baf2a3da4ed8f8a9023617059e22fd81c3ba45
Signed-off-by: default avatarSaravana Kannan <skannan@codeaurora.org>
parent 193d7f5c
Loading
Loading
Loading
Loading
+18 −1
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2013-2016, 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
@@ -764,6 +764,8 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df,
{
	int ret;
	unsigned int sample_ms;
	struct hwmon_node *node;
	struct bw_hwmon *hw;

	switch (event) {
	case DEVFREQ_GOV_START:
@@ -790,7 +792,22 @@ static int devfreq_bw_hwmon_ev_handler(struct devfreq *df,
		sample_ms = *(unsigned int *)data;
		sample_ms = max(MIN_MS, sample_ms);
		sample_ms = min(MAX_MS, sample_ms);
		/*
		 * Suspend/resume the HW monitor around the interval update
		 * to prevent the HW monitor IRQ from trying to change
		 * stop/start the delayed workqueue while the interval update
		 * is happening.
		 */
		node = df->data;
		hw = node->hw;
		hw->suspend_hwmon(hw);
		devfreq_interval_update(df, &sample_ms);
		ret = hw->resume_hwmon(hw);
		if (ret) {
			dev_err(df->dev.parent,
				"Unable to resume HW monitor (%d)\n", ret);
			return ret;
		}
		break;

	case DEVFREQ_GOV_SUSPEND: