Skip to content

Commit f1ecbf7

Browse files
committed
Merge branch 'pm-cpuidle'
* pm-cpuidle: cpuidle: Fix three reference count leaks cpuidle: Convert Qualcomm SPM driver to a generic CPUidle driver Documentation: ABI: make current_governer_ro as a candidate for removal Documentation: cpuidle: update the document cpuidle: sysfs: Remove sysfs_switch and switch attributes cpuidle: Make cpuidle governor switchable to be the default behaviour cpuidle: sysfs: Accept governor name with 15 characters cpuidle: sysfs: Fix the overlap for showing available governors cpuidle: psci: Fixup execution order when entering a domain idle state cpuidle: sysfs: Minor coding style corrections cpuidle: sysfs: Remove the unused define_one_r(o/w) macros
2 parents be6018a + c343bf1 commit f1ecbf7

File tree

12 files changed

+124
-179
lines changed

12 files changed

+124
-179
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
What: /sys/devices/system/cpu/cpuidle/current_governor_ro
2+
Date: April, 2020
3+
4+
Description:
5+
current_governor_ro shows current using cpuidle governor, but read only.
6+
with the update that cpuidle governor can be changed at runtime in default,
7+
both current_governor and current_governor_ro co-exist under
8+
/sys/devices/system/cpu/cpuidle/ file, it's duplicate so make
9+
current_governor_ro obselete.

Documentation/ABI/testing/sysfs-devices-system-cpu

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ Description: CPU topology files that describe a logical CPU's relationship
106106
See Documentation/admin-guide/cputopology.rst for more information.
107107

108108

109-
What: /sys/devices/system/cpu/cpuidle/current_driver
110-
/sys/devices/system/cpu/cpuidle/current_governer_ro
111-
/sys/devices/system/cpu/cpuidle/available_governors
109+
What: /sys/devices/system/cpu/cpuidle/available_governors
110+
/sys/devices/system/cpu/cpuidle/current_driver
112111
/sys/devices/system/cpu/cpuidle/current_governor
112+
/sys/devices/system/cpu/cpuidle/current_governer_ro
113113
Date: September 2007
114114
Contact: Linux kernel mailing list <[email protected]>
115115
Description: Discover cpuidle policy and mechanism
@@ -119,24 +119,18 @@ Description: Discover cpuidle policy and mechanism
119119
consumption during idle.
120120

121121
Idle policy (governor) is differentiated from idle mechanism
122-
(driver)
123-
124-
current_driver: (RO) displays current idle mechanism
125-
126-
current_governor_ro: (RO) displays current idle policy
127-
128-
With the cpuidle_sysfs_switch boot option enabled (meant for
129-
developer testing), the following three attributes are visible
130-
instead:
131-
132-
current_driver: same as described above
122+
(driver).
133123

134124
available_governors: (RO) displays a space separated list of
135-
available governors
125+
available governors.
126+
127+
current_driver: (RO) displays current idle mechanism.
136128

137129
current_governor: (RW) displays current idle policy. Users can
138130
switch the governor at runtime by writing to this file.
139131

132+
current_governor_ro: (RO) displays current idle policy.
133+
140134
See Documentation/admin-guide/pm/cpuidle.rst and
141135
Documentation/driver-api/pm/cpuidle.rst for more information.
142136

Documentation/admin-guide/pm/cpuidle.rst

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,15 @@ governor uses that information depends on what algorithm is implemented by it
159159
and that is the primary reason for having more than one governor in the
160160
``CPUIdle`` subsystem.
161161

162-
There are three ``CPUIdle`` governors available, ``menu``, `TEO <teo-gov_>`_
163-
and ``ladder``. Which of them is used by default depends on the configuration
164-
of the kernel and in particular on whether or not the scheduler tick can be
165-
`stopped by the idle loop <idle-cpus-and-tick_>`_. It is possible to change the
166-
governor at run time if the ``cpuidle_sysfs_switch`` command line parameter has
167-
been passed to the kernel, but that is not safe in general, so it should not be
168-
done on production systems (that may change in the future, though). The name of
169-
the ``CPUIdle`` governor currently used by the kernel can be read from the
170-
:file:`current_governor_ro` (or :file:`current_governor` if
171-
``cpuidle_sysfs_switch`` is present in the kernel command line) file under
172-
:file:`/sys/devices/system/cpu/cpuidle/` in ``sysfs``.
162+
There are four ``CPUIdle`` governors available, ``menu``, `TEO <teo-gov_>`_,
163+
``ladder`` and ``haltpoll``. Which of them is used by default depends on the
164+
configuration of the kernel and in particular on whether or not the scheduler
165+
tick can be `stopped by the idle loop <idle-cpus-and-tick_>`_. Available
166+
governors can be read from the :file:`available_governors`, and the governor
167+
can be changed at runtime. The name of the ``CPUIdle`` governor currently
168+
used by the kernel can be read from the :file:`current_governor_ro` or
169+
:file:`current_governor` file under :file:`/sys/devices/system/cpu/cpuidle/`
170+
in ``sysfs``.
173171

174172
Which ``CPUIdle`` driver is used, on the other hand, usually depends on the
175173
platform the kernel is running on, but there are platforms with more than one

Documentation/driver-api/pm/cpuidle.rst

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,8 @@ only one in the list (that is, the list was empty before) or the value of its
6868
governor currently in use, or the name of the new governor was passed to the
6969
kernel as the value of the ``cpuidle.governor=`` command line parameter, the new
7070
governor will be used from that point on (there can be only one ``CPUIdle``
71-
governor in use at a time). Also, if ``cpuidle_sysfs_switch`` is passed to the
72-
kernel in the command line, user space can choose the ``CPUIdle`` governor to
73-
use at run time via ``sysfs``.
71+
governor in use at a time). Also, user space can choose the ``CPUIdle``
72+
governor to use at run time via ``sysfs``.
7473

7574
Once registered, ``CPUIdle`` governors cannot be unregistered, so it is not
7675
practical to put them into loadable kernel modules.

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2225,6 +2225,7 @@ F: drivers/*/qcom*
22252225
F: drivers/*/qcom/
22262226
F: drivers/bluetooth/btqcomsmd.c
22272227
F: drivers/clocksource/timer-qcom.c
2228+
F: drivers/cpuidle/cpuidle-qcom-spm.c
22282229
F: drivers/extcon/extcon-qcom*
22292230
F: drivers/i2c/busses/i2c-qcom-geni.c
22302231
F: drivers/i2c/busses/i2c-qup.c

drivers/cpuidle/Kconfig.arm

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,16 @@ config ARM_TEGRA_CPUIDLE
9494
select ARM_CPU_SUSPEND
9595
help
9696
Select this to enable cpuidle for NVIDIA Tegra20/30/114/124 SoCs.
97+
98+
config ARM_QCOM_SPM_CPUIDLE
99+
bool "CPU Idle Driver for Qualcomm Subsystem Power Manager (SPM)"
100+
depends on (ARCH_QCOM || COMPILE_TEST) && !ARM64
101+
select ARM_CPU_SUSPEND
102+
select CPU_IDLE_MULTIPLE_DRIVERS
103+
select DT_IDLE_STATES
104+
select QCOM_SCM
105+
help
106+
Select this to enable cpuidle for Qualcomm processors.
107+
The Subsystem Power Manager (SPM) controls low power modes for the
108+
CPU and L2 cores. It interface with various system drivers to put
109+
the cores in low power modes.

drivers/cpuidle/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ obj-$(CONFIG_ARM_PSCI_CPUIDLE) += cpuidle_psci.o
2525
cpuidle_psci-y := cpuidle-psci.o
2626
cpuidle_psci-$(CONFIG_PM_GENERIC_DOMAINS_OF) += cpuidle-psci-domain.o
2727
obj-$(CONFIG_ARM_TEGRA_CPUIDLE) += cpuidle-tegra.o
28+
obj-$(CONFIG_ARM_QCOM_SPM_CPUIDLE) += cpuidle-qcom-spm.o
2829

2930
###############################################################################
3031
# MIPS drivers

drivers/cpuidle/cpuidle-psci.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,23 @@ static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
5858
u32 state;
5959
int ret;
6060

61+
ret = cpu_pm_enter();
62+
if (ret)
63+
return -1;
64+
6165
/* Do runtime PM to manage a hierarchical CPU toplogy. */
6266
pm_runtime_put_sync_suspend(pd_dev);
6367

6468
state = psci_get_domain_state();
6569
if (!state)
6670
state = states[idx];
6771

68-
ret = psci_enter_state(idx, state);
72+
ret = psci_cpu_suspend_enter(state) ? -1 : idx;
6973

7074
pm_runtime_get_sync(pd_dev);
7175

76+
cpu_pm_exit();
77+
7278
/* Clear the domain state to start fresh when back from idle. */
7379
psci_set_domain_state(0);
7480
return ret;

drivers/soc/qcom/spm.c renamed to drivers/cpuidle/cpuidle-qcom-spm.c

Lines changed: 52 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@
1919
#include <linux/cpu_pm.h>
2020
#include <linux/qcom_scm.h>
2121

22-
#include <asm/cpuidle.h>
2322
#include <asm/proc-fns.h>
2423
#include <asm/suspend.h>
2524

25+
#include "dt_idle_states.h"
26+
2627
#define MAX_PMIC_DATA 2
2728
#define MAX_SEQ_DATA 64
2829
#define SPM_CTL_INDEX 0x7f
@@ -62,6 +63,7 @@ struct spm_reg_data {
6263
};
6364

6465
struct spm_driver_data {
66+
struct cpuidle_driver cpuidle_driver;
6567
void __iomem *reg_base;
6668
const struct spm_reg_data *reg_data;
6769
};
@@ -107,11 +109,6 @@ static const struct spm_reg_data spm_reg_8064_cpu = {
107109
.start_index[PM_SLEEP_MODE_SPC] = 2,
108110
};
109111

110-
static DEFINE_PER_CPU(struct spm_driver_data *, cpu_spm_drv);
111-
112-
typedef int (*idle_fn)(void);
113-
static DEFINE_PER_CPU(idle_fn*, qcom_idle_ops);
114-
115112
static inline void spm_register_write(struct spm_driver_data *drv,
116113
enum spm_reg reg, u32 val)
117114
{
@@ -172,10 +169,9 @@ static int qcom_pm_collapse(unsigned long int unused)
172169
return -1;
173170
}
174171

175-
static int qcom_cpu_spc(void)
172+
static int qcom_cpu_spc(struct spm_driver_data *drv)
176173
{
177174
int ret;
178-
struct spm_driver_data *drv = __this_cpu_read(cpu_spm_drv);
179175

180176
spm_set_low_power_mode(drv, PM_SLEEP_MODE_SPC);
181177
ret = cpu_suspend(0, qcom_pm_collapse);
@@ -190,94 +186,49 @@ static int qcom_cpu_spc(void)
190186
return ret;
191187
}
192188

193-
static int qcom_idle_enter(unsigned long index)
189+
static int spm_enter_idle_state(struct cpuidle_device *dev,
190+
struct cpuidle_driver *drv, int idx)
194191
{
195-
return __this_cpu_read(qcom_idle_ops)[index]();
192+
struct spm_driver_data *data = container_of(drv, struct spm_driver_data,
193+
cpuidle_driver);
194+
195+
return CPU_PM_CPU_IDLE_ENTER_PARAM(qcom_cpu_spc, idx, data);
196196
}
197197

198-
static const struct of_device_id qcom_idle_state_match[] __initconst = {
199-
{ .compatible = "qcom,idle-state-spc", .data = qcom_cpu_spc },
198+
static struct cpuidle_driver qcom_spm_idle_driver = {
199+
.name = "qcom_spm",
200+
.owner = THIS_MODULE,
201+
.states[0] = {
202+
.enter = spm_enter_idle_state,
203+
.exit_latency = 1,
204+
.target_residency = 1,
205+
.power_usage = UINT_MAX,
206+
.name = "WFI",
207+
.desc = "ARM WFI",
208+
}
209+
};
210+
211+
static const struct of_device_id qcom_idle_state_match[] = {
212+
{ .compatible = "qcom,idle-state-spc", .data = spm_enter_idle_state },
200213
{ },
201214
};
202215

203-
static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu)
216+
static int spm_cpuidle_init(struct cpuidle_driver *drv, int cpu)
204217
{
205-
const struct of_device_id *match_id;
206-
struct device_node *state_node;
207-
int i;
208-
int state_count = 1;
209-
idle_fn idle_fns[CPUIDLE_STATE_MAX];
210-
idle_fn *fns;
211-
cpumask_t mask;
212-
bool use_scm_power_down = false;
213-
214-
if (!qcom_scm_is_available())
215-
return -EPROBE_DEFER;
216-
217-
for (i = 0; ; i++) {
218-
state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
219-
if (!state_node)
220-
break;
221-
222-
if (!of_device_is_available(state_node))
223-
continue;
224-
225-
if (i == CPUIDLE_STATE_MAX) {
226-
pr_warn("%s: cpuidle states reached max possible\n",
227-
__func__);
228-
break;
229-
}
230-
231-
match_id = of_match_node(qcom_idle_state_match, state_node);
232-
if (!match_id)
233-
return -ENODEV;
234-
235-
idle_fns[state_count] = match_id->data;
236-
237-
/* Check if any of the states allow power down */
238-
if (match_id->data == qcom_cpu_spc)
239-
use_scm_power_down = true;
240-
241-
state_count++;
242-
}
243-
244-
if (state_count == 1)
245-
goto check_spm;
246-
247-
fns = devm_kcalloc(get_cpu_device(cpu), state_count, sizeof(*fns),
248-
GFP_KERNEL);
249-
if (!fns)
250-
return -ENOMEM;
251-
252-
for (i = 1; i < state_count; i++)
253-
fns[i] = idle_fns[i];
218+
int ret;
254219

255-
if (use_scm_power_down) {
256-
/* We have atleast one power down mode */
257-
cpumask_clear(&mask);
258-
cpumask_set_cpu(cpu, &mask);
259-
qcom_scm_set_warm_boot_addr(cpu_resume_arm, &mask);
260-
}
220+
memcpy(drv, &qcom_spm_idle_driver, sizeof(*drv));
221+
drv->cpumask = (struct cpumask *)cpumask_of(cpu);
261222

262-
per_cpu(qcom_idle_ops, cpu) = fns;
223+
/* Parse idle states from device tree */
224+
ret = dt_init_idle_driver(drv, qcom_idle_state_match, 1);
225+
if (ret <= 0)
226+
return ret ? : -ENODEV;
263227

264-
/*
265-
* SPM probe for the cpu should have happened by now, if the
266-
* SPM device does not exist, return -ENXIO to indicate that the
267-
* cpu does not support idle states.
268-
*/
269-
check_spm:
270-
return per_cpu(cpu_spm_drv, cpu) ? 0 : -ENXIO;
228+
/* We have atleast one power down mode */
229+
return qcom_scm_set_warm_boot_addr(cpu_resume_arm, drv->cpumask);
271230
}
272231

273-
static const struct cpuidle_ops qcom_cpuidle_ops __initconst = {
274-
.suspend = qcom_idle_enter,
275-
.init = qcom_cpuidle_init,
276-
};
277-
278-
CPUIDLE_METHOD_OF_DECLARE(qcom_idle_v1, "qcom,kpss-acc-v1", &qcom_cpuidle_ops);
279-
CPUIDLE_METHOD_OF_DECLARE(qcom_idle_v2, "qcom,kpss-acc-v2", &qcom_cpuidle_ops);
280-
281232
static struct spm_driver_data *spm_get_drv(struct platform_device *pdev,
282233
int *spm_cpu)
283234
{
@@ -323,11 +274,15 @@ static int spm_dev_probe(struct platform_device *pdev)
323274
struct resource *res;
324275
const struct of_device_id *match_id;
325276
void __iomem *addr;
326-
int cpu;
277+
int cpu, ret;
278+
279+
if (!qcom_scm_is_available())
280+
return -EPROBE_DEFER;
327281

328282
drv = spm_get_drv(pdev, &cpu);
329283
if (!drv)
330284
return -EINVAL;
285+
platform_set_drvdata(pdev, drv);
331286

332287
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
333288
drv->reg_base = devm_ioremap_resource(&pdev->dev, res);
@@ -340,6 +295,10 @@ static int spm_dev_probe(struct platform_device *pdev)
340295

341296
drv->reg_data = match_id->data;
342297

298+
ret = spm_cpuidle_init(&drv->cpuidle_driver, cpu);
299+
if (ret)
300+
return ret;
301+
343302
/* Write the SPM sequences first.. */
344303
addr = drv->reg_base + drv->reg_data->reg_offset[SPM_REG_SEQ_ENTRY];
345304
__iowrite32_copy(addr, drv->reg_data->seq,
@@ -362,13 +321,20 @@ static int spm_dev_probe(struct platform_device *pdev)
362321
/* Set up Standby as the default low power mode */
363322
spm_set_low_power_mode(drv, PM_SLEEP_MODE_STBY);
364323

365-
per_cpu(cpu_spm_drv, cpu) = drv;
324+
return cpuidle_register(&drv->cpuidle_driver, NULL);
325+
}
326+
327+
static int spm_dev_remove(struct platform_device *pdev)
328+
{
329+
struct spm_driver_data *drv = platform_get_drvdata(pdev);
366330

331+
cpuidle_unregister(&drv->cpuidle_driver);
367332
return 0;
368333
}
369334

370335
static struct platform_driver spm_driver = {
371336
.probe = spm_dev_probe,
337+
.remove = spm_dev_remove,
372338
.driver = {
373339
.name = "saw",
374340
.of_match_table = spm_match_table,

0 commit comments

Comments
 (0)