summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSaravana Kannan <skannan@codeaurora.org>2016-02-18 18:28:29 -0800
committerJeevan Shriram <jshriram@codeaurora.org>2016-04-07 16:00:11 -0700
commitd274d4f31737c4a28bcc239ec1f0dd420b0e0db4 (patch)
treed018bbbf2703eddc0d2ffea6b2d1f2989e5b7a0f
parente9b36267d6d8e16cbe2b7ca65d4201cca34b0110 (diff)
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: Saravana Kannan <skannan@codeaurora.org>
-rw-r--r--drivers/devfreq/governor_bw_hwmon.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/drivers/devfreq/governor_bw_hwmon.c b/drivers/devfreq/governor_bw_hwmon.c
index 05198a17ad5f..e0f75b0022fc 100644
--- a/drivers/devfreq/governor_bw_hwmon.c
+++ b/drivers/devfreq/governor_bw_hwmon.c
@@ -1,5 +1,5 @@
/*
- * 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: