From 8b6b8fd39aa0ddb78abc4d9aebe7200ea7cd1e8a Mon Sep 17 00:00:00 2001 From: "Raju P.L.S.S.S.N" Date: Thu, 7 Dec 2017 00:09:01 +0530 Subject: [PATCH] cpuidle: lpm-levels: Add system_pm ops for system level LPMs Add system_pm ops that are used by LPM driver to configure sleep and wake votes as well as next wake up time. LPM driver uses them during system level LPMs. Change-Id: I72b89aeb3408b89a73d1f0c821649f4f998ab85c Signed-off-by: Raju P.L.S.S.S.N --- drivers/cpuidle/lpm-levels.c | 119 +++++++++++++++++++--------------- drivers/cpuidle/lpm-levels.h | 2 - drivers/soc/qcom/system_pm.c | 28 ++++---- include/soc/qcom/lpm_levels.h | 30 +++++++++ include/soc/qcom/system_pm.h | 39 ----------- 5 files changed, 110 insertions(+), 108 deletions(-) create mode 100644 include/soc/qcom/lpm_levels.h delete mode 100644 include/soc/qcom/system_pm.h diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index cbda188a8149..30a78e6cf1fb 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -39,8 +39,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -79,6 +79,9 @@ struct lpm_debug { uint32_t arg4; }; +static struct system_pm_ops *sys_pm_ops; + + struct lpm_cluster *lpm_root_node; #define MAXSAMPLES 5 @@ -123,11 +126,6 @@ static void cluster_prepare(struct lpm_cluster *cluster, const struct cpumask *cpu, int child_idx, bool from_idle, int64_t time); -static int msm_pm_sleep_time_override; -module_param_named(sleep_time_override, - msm_pm_sleep_time_override, int, 0664); -static uint64_t suspend_wake_time; - static bool print_parsed_dt; module_param_named(print_parsed_dt, print_parsed_dt, bool, 0664); @@ -145,20 +143,15 @@ s32 msm_cpuidle_get_deep_idle_latency(void) } EXPORT_SYMBOL(msm_cpuidle_get_deep_idle_latency); -void lpm_suspend_wake_time(uint64_t wakeup_time) +uint32_t register_system_pm_ops(struct system_pm_ops *pm_ops) { - if (wakeup_time <= 0) { - suspend_wake_time = msm_pm_sleep_time_override; - return; - } + if (sys_pm_ops) + return -EUSERS; - if (msm_pm_sleep_time_override && - (msm_pm_sleep_time_override < wakeup_time)) - suspend_wake_time = msm_pm_sleep_time_override; - else - suspend_wake_time = wakeup_time; + sys_pm_ops = pm_ops; + + return 0; } -EXPORT_SYMBOL(lpm_suspend_wake_time); static uint32_t least_cluster_latency(struct lpm_cluster *cluster, struct latency_level *lat_level) @@ -703,32 +696,16 @@ done_select: return best_level; } -static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster, - struct cpumask *mask, bool from_idle, uint32_t *pred_time) +static unsigned int get_next_online_cpu(bool from_idle) { - int cpu; - int next_cpu = raw_smp_processor_id(); + unsigned int cpu; ktime_t next_event; - struct cpumask online_cpus_in_cluster; - struct lpm_history *history; - int64_t prediction = LONG_MAX; + unsigned int next_cpu = raw_smp_processor_id(); + if (!from_idle) + return next_cpu; next_event = KTIME_MAX; - if (!suspend_wake_time) - suspend_wake_time = msm_pm_sleep_time_override; - if (!from_idle) { - if (mask) - cpumask_copy(mask, cpumask_of(raw_smp_processor_id())); - if (!suspend_wake_time) - return ~0ULL; - else - return USEC_PER_SEC * suspend_wake_time; - } - - cpumask_and(&online_cpus_in_cluster, - &cluster->num_children_in_sync, cpu_online_mask); - - for_each_cpu(cpu, &online_cpus_in_cluster) { + for_each_online_cpu(cpu) { ktime_t *next_event_c; next_event_c = get_next_event_cpu(cpu); @@ -736,6 +713,32 @@ static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster, next_event = *next_event_c; next_cpu = cpu; } + } + return next_cpu; +} + +static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster, + bool from_idle, uint32_t *pred_time) +{ + int cpu; + ktime_t next_event; + struct cpumask online_cpus_in_cluster; + struct lpm_history *history; + int64_t prediction = LONG_MAX; + + if (!from_idle) + return ~0ULL; + + next_event = KTIME_MAX; + cpumask_and(&online_cpus_in_cluster, + &cluster->num_children_in_sync, cpu_online_mask); + + for_each_cpu(cpu, &online_cpus_in_cluster) { + ktime_t *next_event_c; + + next_event_c = get_next_event_cpu(cpu); + if (*next_event_c < next_event) + next_event = *next_event_c; if (from_idle && lpm_prediction) { history = &per_cpu(hist, cpu); @@ -744,9 +747,6 @@ static uint64_t get_cluster_sleep_time(struct lpm_cluster *cluster, } } - if (mask) - cpumask_copy(mask, cpumask_of(next_cpu)); - if (from_idle && lpm_prediction) { if (prediction > ktime_to_us(ktime_get())) *pred_time = prediction - ktime_to_us(ktime_get()); @@ -929,7 +929,7 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle, if (!cluster) return -EINVAL; - sleep_us = (uint32_t)get_cluster_sleep_time(cluster, NULL, + sleep_us = (uint32_t)get_cluster_sleep_time(cluster, from_idle, &cpupred_us); if (from_idle) { @@ -980,8 +980,12 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle, if (suspend_in_progress && from_idle && level->notify_rpm) continue; - if (level->notify_rpm && !system_sleep_allowed()) - continue; + if (level->notify_rpm) { + if (!(sys_pm_ops && sys_pm_ops->sleep_allowed)) + continue; + if (!sys_pm_ops->sleep_allowed()) + continue; + } best_level = i; @@ -1015,6 +1019,11 @@ 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, cpumask; + unsigned int cpu; + + 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)) { @@ -1036,10 +1045,13 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, } if (level->notify_rpm) { + cpu = get_next_online_cpu(from_idle); + cpumask_copy(&cpumask, cpumask_of(cpu)); clear_predict_history(); clear_cl_predict_history(); - if (system_sleep_enter()) - return -EBUSY; + if (sys_pm_ops && sys_pm_ops->enter) + if ((sys_pm_ops->enter(&cpumask))) + return -EBUSY; } /* Notify cluster enter event after successfully config completion */ cluster_notify(cluster, level, true); @@ -1170,7 +1182,8 @@ static void cluster_unprepare(struct lpm_cluster *cluster, level = &cluster->levels[cluster->last_level]; if (level->notify_rpm) - system_sleep_exit(); + if (sys_pm_ops && sys_pm_ops->exit) + sys_pm_ops->exit(); update_debug_pc_event(CLUSTER_EXIT, cluster->last_level, cluster->num_children_in_sync.bits[0], @@ -1223,7 +1236,8 @@ static inline void cpu_unprepare(struct lpm_cpu *cpu, int cpu_index, cpu_pm_exit(); } -int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) +static int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl, + bool from_idle) { int state_id = 0; @@ -1236,7 +1250,7 @@ int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) &cluster->child_cpus)) goto unlock_and_return; - state_id |= get_cluster_id(cluster->parent, aff_lvl); + state_id |= get_cluster_id(cluster->parent, aff_lvl, from_idle); if (cluster->last_level != cluster->default_level) { struct lpm_cluster_level *level @@ -1250,7 +1264,8 @@ int get_cluster_id(struct lpm_cluster *cluster, int *aff_lvl) * the wakeup value by reading the bc timer directly. */ if (level->notify_rpm) - system_sleep_update_wakeup(); + if (sys_pm_ops && sys_pm_ops->update_wakeup) + sys_pm_ops->update_wakeup(from_idle); if (level->psci_id) (*aff_lvl)++; } @@ -1279,7 +1294,7 @@ static bool psci_enter_sleep(struct lpm_cpu *cpu, int idx, bool from_idle) return success; } - state_id = get_cluster_id(cpu->parent, &affinity_level); + state_id = get_cluster_id(cpu->parent, &affinity_level, from_idle); power_state = PSCI_POWER_STATE(cpu->levels[idx].is_reset); affinity_level = PSCI_AFFINITY_LEVEL(affinity_level); state_id |= power_state | affinity_level | cpu->levels[idx].psci_id; diff --git a/drivers/cpuidle/lpm-levels.h b/drivers/cpuidle/lpm-levels.h index 67aaa91db1d7..8c66bd73402c 100644 --- a/drivers/cpuidle/lpm-levels.h +++ b/drivers/cpuidle/lpm-levels.h @@ -108,8 +108,6 @@ struct lpm_cluster { struct hrtimer histtimer; }; -void lpm_suspend_wake_time(uint64_t wakeup_time); - struct lpm_cluster *lpm_of_parse_cluster(struct platform_device *pdev); void free_cluster_node(struct lpm_cluster *cluster); void cluster_dt_walkthrough(struct lpm_cluster *cluster); diff --git a/drivers/soc/qcom/system_pm.c b/drivers/soc/qcom/system_pm.c index 6164b445f1f4..0921f18f2f39 100644 --- a/drivers/soc/qcom/system_pm.c +++ b/drivers/soc/qcom/system_pm.c @@ -13,11 +13,9 @@ #include #include - #include -#include - #include +#include #define PDC_TIME_VALID_SHIFT 31 #define PDC_TIME_UPPER_MASK 0xFFFFFF @@ -35,7 +33,7 @@ static int setup_wakeup(uint32_t lo, uint32_t hi) return rpmh_write_control(rpmh_client, cmd, ARRAY_SIZE(cmd)); } -int system_sleep_update_wakeup(void) +static int system_sleep_update_wakeup(bool from_idle) { uint32_t lo = ~0U, hi = ~0U; @@ -44,16 +42,14 @@ int system_sleep_update_wakeup(void) return setup_wakeup(lo, hi); } -EXPORT_SYMBOL(system_sleep_update_wakeup); /** * system_sleep_allowed() - Returns if its okay to enter system low power modes */ -bool system_sleep_allowed(void) +static bool system_sleep_allowed(void) { return (rpmh_ctrlr_idle(rpmh_client) == 0); } -EXPORT_SYMBOL(system_sleep_allowed); /** * system_sleep_enter() - Activties done when entering system low power modes @@ -61,22 +57,24 @@ EXPORT_SYMBOL(system_sleep_allowed); * Returns 0 for success or error values from writing the sleep/wake values to * the hardware block. */ -int system_sleep_enter(void) +static int system_sleep_enter(struct cpumask *mask) { - if (IS_ERR_OR_NULL(rpmh_client)) - return -EFAULT; - return rpmh_flush(rpmh_client); } -EXPORT_SYMBOL(system_sleep_enter); /** * system_sleep_exit() - Activities done when exiting system low power modes */ -void system_sleep_exit(void) +static void system_sleep_exit(void) { } -EXPORT_SYMBOL(system_sleep_exit); + +static struct system_pm_ops pm_ops = { + .enter = system_sleep_enter, + .exit = system_sleep_exit, + .update_wakeup = system_sleep_update_wakeup, + .sleep_allowed = system_sleep_allowed, +}; static int sys_pm_probe(struct platform_device *pdev) { @@ -84,7 +82,7 @@ static int sys_pm_probe(struct platform_device *pdev) if (IS_ERR_OR_NULL(rpmh_client)) return PTR_ERR(rpmh_client); - return 0; + return register_system_pm_ops(&pm_ops); } static const struct of_device_id sys_pm_drv_match[] = { diff --git a/include/soc/qcom/lpm_levels.h b/include/soc/qcom/lpm_levels.h new file mode 100644 index 000000000000..f838665d2fdc --- /dev/null +++ b/include/soc/qcom/lpm_levels.h @@ -0,0 +1,30 @@ +/* Copyright (c) 2018, 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 + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#ifndef __SOC_QCOM_LPM_LEVEL_H__ +#define __SOC_QCOM_LPM_LEVEL_H__ + +struct system_pm_ops { + int (*enter)(struct cpumask *mask); + void (*exit)(void); + int (*update_wakeup)(bool); + bool (*sleep_allowed)(void); +}; + +#ifdef CONFIG_MSM_PM +uint32_t register_system_pm_ops(struct system_pm_ops *pm_ops); +#else +static inline uint32_t register_system_pm_ops(struct system_pm_ops *pm_ops) +{ return -ENODEV; } +#endif + +#endif diff --git a/include/soc/qcom/system_pm.h b/include/soc/qcom/system_pm.h deleted file mode 100644 index 028c729718f4..000000000000 --- a/include/soc/qcom/system_pm.h +++ /dev/null @@ -1,39 +0,0 @@ -/* Copyright (c) 2016-2017, 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 - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#ifndef __SOC_QCOM_SYS_PM_H__ -#define __SOC_QCOM_SYS_PM_H__ - -#ifdef CONFIG_QTI_SYSTEM_PM -int system_sleep_enter(void); - -void system_sleep_exit(void); - -bool system_sleep_allowed(void); - -int system_sleep_update_wakeup(void); -#else -static inline int system_sleep_enter(void) -{ return -ENODEV; } - -static inline void system_sleep_exit(void) -{ } - -static inline bool system_sleep_allowed(void) -{ return false; } - -static inline int system_sleep_update_wakeup(void) -{ return -ENODEV; } - -#endif /* CONFIG_QTI_SYSTEM_PM */ - -#endif /* __SOC_QCOM_SYS_PM_H__ */