summaryrefslogtreecommitdiff
path: root/drivers/cpuidle/lpm-levels.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/cpuidle/lpm-levels.c')
-rw-r--r--drivers/cpuidle/lpm-levels.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c
index 4224b594f1b8..584a1857624a 100644
--- a/drivers/cpuidle/lpm-levels.c
+++ b/drivers/cpuidle/lpm-levels.c
@@ -363,6 +363,24 @@ static int lpm_cpu_callback(struct notifier_block *cpu_nb,
return NOTIFY_OK;
}
+#ifdef CONFIG_ARM_PSCI
+
+static int __init set_cpuidle_ops(void)
+{
+ int ret = 0, cpu;
+
+ for_each_possible_cpu(cpu) {
+ ret = arm_cpuidle_init(cpu);
+ if (ret)
+ goto exit;
+ }
+
+exit:
+ return ret;
+}
+
+#endif
+
static enum hrtimer_restart lpm_hrtimer_cb(struct hrtimer *h)
{
return HRTIMER_NORESTART;
@@ -676,22 +694,21 @@ static int cpu_power_select(struct cpuidle_device *dev,
int best_level = -1;
uint32_t latency_us = pm_qos_request_for_cpu(PM_QOS_CPU_DMA_LATENCY,
dev->cpu);
- uint32_t sleep_us =
- (uint32_t)(ktime_to_us(tick_nohz_get_sleep_length()));
+ s64 sleep_us = ktime_to_us(tick_nohz_get_sleep_length());
uint32_t modified_time_us = 0;
uint32_t next_event_us = 0;
int i, idx_restrict;
uint32_t lvl_latency_us = 0;
uint64_t predicted = 0;
uint32_t htime = 0, idx_restrict_time = 0;
- uint32_t next_wakeup_us = sleep_us;
+ uint32_t next_wakeup_us = (uint32_t)sleep_us;
uint32_t *min_residency = get_per_cpu_min_residency(dev->cpu);
uint32_t *max_residency = get_per_cpu_max_residency(dev->cpu);
if (!cpu)
return -EINVAL;
- if (sleep_disabled && !cpu_isolated(dev->cpu))
+ if ((sleep_disabled && !cpu_isolated(dev->cpu)) || sleep_us < 0)
return 0;
idx_restrict = cpu->nlevels + 1;
@@ -732,8 +749,8 @@ static int cpu_power_select(struct cpuidle_device *dev,
if (next_wakeup_us > max_residency[i]) {
predicted = lpm_cpuidle_predict(dev, cpu,
&idx_restrict, &idx_restrict_time);
- if (predicted < min_residency[i])
- predicted = 0;
+ if (predicted && (predicted < min_residency[i]))
+ predicted = min_residency[i];
} else
invalidate_predict_history(dev);
}
@@ -1101,10 +1118,14 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx,
bool from_idle, int predicted)
{
struct lpm_cluster_level *level = &cluster->levels[idx];
+ struct cpumask online_cpus;
int ret, i;
+ cpumask_and(&online_cpus, &cluster->num_children_in_sync,
+ cpu_online_mask);
+
if (!cpumask_equal(&cluster->num_children_in_sync, &cluster->child_cpus)
- || is_IPI_pending(&cluster->num_children_in_sync)) {
+ || is_IPI_pending(&online_cpus)) {
return -EPERM;
}
@@ -1954,6 +1975,14 @@ static int __init lpm_levels_module_init(void)
goto fail;
}
+#ifdef CONFIG_ARM_PSCI
+ rc = set_cpuidle_ops();
+ if (rc) {
+ pr_err("%s(): Failed to set cpuidle ops\n", __func__);
+ goto fail;
+ }
+#endif
+
fail:
return rc;
}