Skip to content

Commit fe5975b

Browse files
committed
Merge branches 'pm-cpuidle' and 'pm-devfreq'
* pm-cpuidle: cpuidle: record state entry rejection statistics cpuidle: psci: Allow PM domain to be initialized even if no OSI mode firmware: psci: Extend psci_set_osi_mode() to allow reset to PC mode ACPI: processor: Print more information when acpi_processor_evaluate_cst() fails cpuidle: tegra: Correctly handle result of arm_cpuidle_simple_enter() * pm-devfreq: PM / devfreq: tegra30: Improve initial hardware resetting PM / devfreq: event: Change prototype of devfreq_event_get_edev_by_phandle function PM / devfreq: Change prototype of devfreq_get_devfreq_by_phandle function PM / devfreq: Add devfreq_get_devfreq_by_node function
3 parents 9c2ff66 + 0b9688e + 4285027 commit fe5975b

17 files changed

Lines changed: 184 additions & 90 deletions

File tree

Documentation/admin-guide/pm/cpuidle.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,10 @@ object corresponding to it, as follows:
528528
Total number of times the hardware has been asked by the given CPU to
529529
enter this idle state.
530530

531+
``rejected``
532+
Total number of times a request to enter this idle state on the given
533+
CPU was rejected.
534+
531535
The :file:`desc` and :file:`name` files both contain strings. The difference
532536
between them is that the name is expected to be more concise, while the
533537
description may be longer and it may contain white space or special characters.
@@ -572,6 +576,11 @@ particular case. For these reasons, the only reliable way to find out how
572576
much time has been spent by the hardware in different idle states supported by
573577
it is to use idle state residency counters in the hardware, if available.
574578

579+
Generally, an interrupt received when trying to enter an idle state causes the
580+
idle state entry request to be rejected, in which case the ``CPUIdle`` driver
581+
may return an error code to indicate that this was the case. The :file:`usage`
582+
and :file:`rejected` files report the number of times the given idle state
583+
was entered successfully or rejected, respectively.
575584

576585
.. _cpu-pm-qos:
577586

drivers/acpi/acpi_processor.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -798,22 +798,34 @@ int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
798798
memset(&cx, 0, sizeof(cx));
799799

800800
element = &cst->package.elements[i];
801-
if (element->type != ACPI_TYPE_PACKAGE)
801+
if (element->type != ACPI_TYPE_PACKAGE) {
802+
acpi_handle_info(handle, "_CST C%d type(%x) is not package, skip...\n",
803+
i, element->type);
802804
continue;
805+
}
803806

804-
if (element->package.count != 4)
807+
if (element->package.count != 4) {
808+
acpi_handle_info(handle, "_CST C%d package count(%d) is not 4, skip...\n",
809+
i, element->package.count);
805810
continue;
811+
}
806812

807813
obj = &element->package.elements[0];
808814

809-
if (obj->type != ACPI_TYPE_BUFFER)
815+
if (obj->type != ACPI_TYPE_BUFFER) {
816+
acpi_handle_info(handle, "_CST C%d package element[0] type(%x) is not buffer, skip...\n",
817+
i, obj->type);
810818
continue;
819+
}
811820

812821
reg = (struct acpi_power_register *)obj->buffer.pointer;
813822

814823
obj = &element->package.elements[1];
815-
if (obj->type != ACPI_TYPE_INTEGER)
824+
if (obj->type != ACPI_TYPE_INTEGER) {
825+
acpi_handle_info(handle, "_CST C[%d] package element[1] type(%x) is not integer, skip...\n",
826+
i, obj->type);
816827
continue;
828+
}
817829

818830
cx.type = obj->integer.value;
819831
/*
@@ -850,28 +862,38 @@ int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
850862
cx.entry_method = ACPI_CSTATE_HALT;
851863
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
852864
} else {
865+
acpi_handle_info(handle, "_CST C%d declares FIXED_HARDWARE C-state but not supported in hardware, skip...\n",
866+
i);
853867
continue;
854868
}
855869
} else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
856870
cx.entry_method = ACPI_CSTATE_SYSTEMIO;
857871
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x",
858872
cx.address);
859873
} else {
874+
acpi_handle_info(handle, "_CST C%d space_id(%x) neither FIXED_HARDWARE nor SYSTEM_IO, skip...\n",
875+
i, reg->space_id);
860876
continue;
861877
}
862878

863879
if (cx.type == ACPI_STATE_C1)
864880
cx.valid = 1;
865881

866882
obj = &element->package.elements[2];
867-
if (obj->type != ACPI_TYPE_INTEGER)
883+
if (obj->type != ACPI_TYPE_INTEGER) {
884+
acpi_handle_info(handle, "_CST C%d package element[2] type(%x) not integer, skip...\n",
885+
i, obj->type);
868886
continue;
887+
}
869888

870889
cx.latency = obj->integer.value;
871890

872891
obj = &element->package.elements[3];
873-
if (obj->type != ACPI_TYPE_INTEGER)
892+
if (obj->type != ACPI_TYPE_INTEGER) {
893+
acpi_handle_info(handle, "_CST C%d package element[3] type(%x) not integer, skip...\n",
894+
i, obj->type);
874895
continue;
896+
}
875897

876898
memcpy(&info->states[++last_index], &cx, sizeof(cx));
877899
}

drivers/cpuidle/cpuidle-psci-domain.c

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ static void psci_pd_free_states(struct genpd_power_state *states,
105105
kfree(states);
106106
}
107107

108-
static int psci_pd_init(struct device_node *np)
108+
static int psci_pd_init(struct device_node *np, bool use_osi)
109109
{
110110
struct generic_pm_domain *pd;
111111
struct psci_pd_provider *pd_provider;
@@ -135,11 +135,16 @@ static int psci_pd_init(struct device_node *np)
135135

136136
pd->free_states = psci_pd_free_states;
137137
pd->name = kbasename(pd->name);
138-
pd->power_off = psci_pd_power_off;
139138
pd->states = states;
140139
pd->state_count = state_count;
141140
pd->flags |= GENPD_FLAG_IRQ_SAFE | GENPD_FLAG_CPU_DOMAIN;
142141

142+
/* Allow power off when OSI has been successfully enabled. */
143+
if (use_osi)
144+
pd->power_off = psci_pd_power_off;
145+
else
146+
pd->flags |= GENPD_FLAG_ALWAYS_ON;
147+
143148
/* Use governor for CPU PM domains if it has some states to manage. */
144149
pd_gov = state_count > 0 ? &pm_domain_cpu_gov : NULL;
145150

@@ -190,7 +195,7 @@ static void psci_pd_remove(void)
190195
}
191196
}
192197

193-
static int psci_pd_init_topology(struct device_node *np, bool add)
198+
static int psci_pd_init_topology(struct device_node *np)
194199
{
195200
struct device_node *node;
196201
struct of_phandle_args child, parent;
@@ -203,9 +208,7 @@ static int psci_pd_init_topology(struct device_node *np, bool add)
203208

204209
child.np = node;
205210
child.args_count = 0;
206-
207-
ret = add ? of_genpd_add_subdomain(&parent, &child) :
208-
of_genpd_remove_subdomain(&parent, &child);
211+
ret = of_genpd_add_subdomain(&parent, &child);
209212
of_node_put(parent.np);
210213
if (ret) {
211214
of_node_put(node);
@@ -216,14 +219,20 @@ static int psci_pd_init_topology(struct device_node *np, bool add)
216219
return 0;
217220
}
218221

219-
static int psci_pd_add_topology(struct device_node *np)
222+
static bool psci_pd_try_set_osi_mode(void)
220223
{
221-
return psci_pd_init_topology(np, true);
222-
}
224+
int ret;
223225

224-
static void psci_pd_remove_topology(struct device_node *np)
225-
{
226-
psci_pd_init_topology(np, false);
226+
if (!psci_has_osi_support())
227+
return false;
228+
229+
ret = psci_set_osi_mode(true);
230+
if (ret) {
231+
pr_warn("failed to enable OSI mode: %d\n", ret);
232+
return false;
233+
}
234+
235+
return true;
227236
}
228237

229238
static void psci_cpuidle_domain_sync_state(struct device *dev)
@@ -244,14 +253,14 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
244253
{
245254
struct device_node *np = pdev->dev.of_node;
246255
struct device_node *node;
256+
bool use_osi;
247257
int ret = 0, pd_count = 0;
248258

249259
if (!np)
250260
return -ENODEV;
251261

252-
/* Currently limit the hierarchical topology to be used in OSI mode. */
253-
if (!psci_has_osi_support())
254-
return 0;
262+
/* If OSI mode is supported, let's try to enable it. */
263+
use_osi = psci_pd_try_set_osi_mode();
255264

256265
/*
257266
* Parse child nodes for the "#power-domain-cells" property and
@@ -261,7 +270,7 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
261270
if (!of_find_property(node, "#power-domain-cells", NULL))
262271
continue;
263272

264-
ret = psci_pd_init(node);
273+
ret = psci_pd_init(node, use_osi);
265274
if (ret)
266275
goto put_node;
267276

@@ -270,30 +279,24 @@ static int psci_cpuidle_domain_probe(struct platform_device *pdev)
270279

271280
/* Bail out if not using the hierarchical CPU topology. */
272281
if (!pd_count)
273-
return 0;
282+
goto no_pd;
274283

275284
/* Link genpd masters/subdomains to model the CPU topology. */
276-
ret = psci_pd_add_topology(np);
285+
ret = psci_pd_init_topology(np);
277286
if (ret)
278287
goto remove_pd;
279288

280-
/* Try to enable OSI mode. */
281-
ret = psci_set_osi_mode();
282-
if (ret) {
283-
pr_warn("failed to enable OSI mode: %d\n", ret);
284-
psci_pd_remove_topology(np);
285-
goto remove_pd;
286-
}
287-
288289
pr_info("Initialized CPU PM domain topology\n");
289290
return 0;
290291

291292
put_node:
292293
of_node_put(node);
293294
remove_pd:
294-
if (pd_count)
295-
psci_pd_remove();
295+
psci_pd_remove();
296296
pr_err("failed to create CPU PM domains ret=%d\n", ret);
297+
no_pd:
298+
if (use_osi)
299+
psci_set_osi_mode(false);
297300
return ret;
298301
}
299302

drivers/cpuidle/cpuidle-tegra.c

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ static int tegra_cpuidle_coupled_barrier(struct cpuidle_device *dev)
172172
static int tegra_cpuidle_state_enter(struct cpuidle_device *dev,
173173
int index, unsigned int cpu)
174174
{
175-
int ret;
175+
int err;
176176

177177
/*
178178
* CC6 state is the "CPU cluster power-off" state. In order to
@@ -183,9 +183,9 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev,
183183
* CPU cores, GIC and L2 cache).
184184
*/
185185
if (index == TEGRA_CC6) {
186-
ret = tegra_cpuidle_coupled_barrier(dev);
187-
if (ret)
188-
return ret;
186+
err = tegra_cpuidle_coupled_barrier(dev);
187+
if (err)
188+
return err;
189189
}
190190

191191
local_fiq_disable();
@@ -194,23 +194,23 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev,
194194

195195
switch (index) {
196196
case TEGRA_C7:
197-
ret = tegra_cpuidle_c7_enter();
197+
err = tegra_cpuidle_c7_enter();
198198
break;
199199

200200
case TEGRA_CC6:
201-
ret = tegra_cpuidle_cc6_enter(cpu);
201+
err = tegra_cpuidle_cc6_enter(cpu);
202202
break;
203203

204204
default:
205-
ret = -EINVAL;
205+
err = -EINVAL;
206206
break;
207207
}
208208

209209
cpu_pm_exit();
210210
tegra_pm_clear_cpu_in_lp2();
211211
local_fiq_enable();
212212

213-
return ret;
213+
return err ?: index;
214214
}
215215

216216
static int tegra_cpuidle_adjust_state_index(int index, unsigned int cpu)
@@ -236,21 +236,27 @@ static int tegra_cpuidle_enter(struct cpuidle_device *dev,
236236
int index)
237237
{
238238
unsigned int cpu = cpu_logical_map(dev->cpu);
239-
int err;
239+
int ret;
240240

241241
index = tegra_cpuidle_adjust_state_index(index, cpu);
242242
if (dev->states_usage[index].disable)
243243
return -1;
244244

245245
if (index == TEGRA_C1)
246-
err = arm_cpuidle_simple_enter(dev, drv, index);
246+
ret = arm_cpuidle_simple_enter(dev, drv, index);
247247
else
248-
err = tegra_cpuidle_state_enter(dev, index, cpu);
248+
ret = tegra_cpuidle_state_enter(dev, index, cpu);
249249

250-
if (err && (err != -EINTR || index != TEGRA_CC6))
251-
pr_err_once("failed to enter state %d err: %d\n", index, err);
250+
if (ret < 0) {
251+
if (ret != -EINTR || index != TEGRA_CC6)
252+
pr_err_once("failed to enter state %d err: %d\n",
253+
index, ret);
254+
index = -1;
255+
} else {
256+
index = ret;
257+
}
252258

253-
return err ? -1 : index;
259+
return index;
254260
}
255261

256262
static int tegra114_enter_s2idle(struct cpuidle_device *dev,

drivers/cpuidle/cpuidle.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
297297
}
298298
} else {
299299
dev->last_residency_ns = 0;
300+
dev->states_usage[index].rejected++;
300301
}
301302

302303
return entered_state;

drivers/cpuidle/sysfs.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ define_show_state_time_function(exit_latency)
256256
define_show_state_time_function(target_residency)
257257
define_show_state_function(power_usage)
258258
define_show_state_ull_function(usage)
259+
define_show_state_ull_function(rejected)
259260
define_show_state_str_function(name)
260261
define_show_state_str_function(desc)
261262
define_show_state_ull_function(above)
@@ -312,6 +313,7 @@ define_one_state_ro(latency, show_state_exit_latency);
312313
define_one_state_ro(residency, show_state_target_residency);
313314
define_one_state_ro(power, show_state_power_usage);
314315
define_one_state_ro(usage, show_state_usage);
316+
define_one_state_ro(rejected, show_state_rejected);
315317
define_one_state_ro(time, show_state_time);
316318
define_one_state_rw(disable, show_state_disable, store_state_disable);
317319
define_one_state_ro(above, show_state_above);
@@ -325,6 +327,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
325327
&attr_residency.attr,
326328
&attr_power.attr,
327329
&attr_usage.attr,
330+
&attr_rejected.attr,
328331
&attr_time.attr,
329332
&attr_disable.attr,
330333
&attr_above.attr,

0 commit comments

Comments
 (0)