summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/cpuidle/governors/menu.c18
1 files changed, 13 insertions, 5 deletions
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index f1fadbecfa1b..af7b3f6b260d 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -226,18 +226,26 @@ again:
}
}
do_div(stddev, divisor);
- stddev = int_sqrt(stddev);
/*
* The typical interval is obtained when standard deviation is small
* or standard deviation is small compared to the average interval.
*
+ * int_sqrt() formal parameter type is unsigned long. When the
+ * greatest difference to an outlier exceeds ~65 ms * sqrt(divisor)
+ * the resulting squared standard deviation exceeds the input domain
+ * of int_sqrt on platforms where unsigned long is 32 bits in size.
+ * In such case reject the candidate average.
+ *
* Use this result only if there is no timer to wake us up sooner.
*/
- if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
+ if (likely(stddev <= ULONG_MAX)) {
+ stddev = int_sqrt(stddev);
+ if (((avg > stddev * 6) && (divisor * 4 >= INTERVALS * 3))
|| stddev <= 20) {
- if (data->expected_us > avg)
- data->predicted_us = avg;
- return;
+ if (data->expected_us > avg)
+ data->predicted_us = avg;
+ return;
+ }
}
/*