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 <rplsssn@codeaurora.org>
This commit is contained in:
committed by
Lina Iyer
parent
687d4ad9f6
commit
8b6b8fd39a
@@ -39,8 +39,8 @@
|
||||
#include <linux/sched/stat.h>
|
||||
#include <soc/qcom/pm.h>
|
||||
#include <soc/qcom/event_timer.h>
|
||||
#include <soc/qcom/lpm_levels.h>
|
||||
#include <soc/qcom/lpm-stats.h>
|
||||
#include <soc/qcom/system_pm.h>
|
||||
#include <soc/qcom/minidump.h>
|
||||
#include <asm/arch_timer.h>
|
||||
#include <asm/suspend.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -13,11 +13,9 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <soc/qcom/rpmh.h>
|
||||
#include <soc/qcom/system_pm.h>
|
||||
|
||||
#include <clocksource/arm_arch_timer.h>
|
||||
#include <soc/qcom/lpm_levels.h>
|
||||
|
||||
#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[] = {
|
||||
|
||||
30
include/soc/qcom/lpm_levels.h
Normal file
30
include/soc/qcom/lpm_levels.h
Normal file
@@ -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
|
||||
@@ -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__ */
|
||||
Reference in New Issue
Block a user