Skip to content

Commit 8713024

Browse files
committed
Merge branches 'pm-em' and 'pm-runtime'
Merge Energy Model handling code updates and updates of the runtime PM core code for 6.15-rc1: - Clean up the Energy Model handling code somewhat (Rafael Wysocki). - Use kfree_rcu() to simplify the handling of runtime Energy Model updates (Li RongQing). - Add an entry for the Energy Model framework to MAINTAINERS as properly maintained (Lukasz Luba). - Address RCU-related sparse warnings in the Energy Model code (Rafael Wysocki). - Remove ENERGY_MODEL dependency on SMP and allow it to be selected when DEVFREQ is set without CPUFREQ so it can be used on a wider range of systems (Jeson Gao). - Unify error handling during runtime suspend and runtime resume in the core to help drivers to implement more consistent runtime PM error handling (Rafael Wysocki). - Drop a redundant check from pm_runtime_force_resume() and rearrange documentation related to __pm_runtime_disable() (Rafael Wysocki). * pm-em: PM: EM: Rework the depends on for CONFIG_ENERGY_MODEL PM: EM: Address RCU-related sparse warnings PM: EM: Consify two parameters of em_dev_register_perf_domain() MAINTAINERS: Add Energy Model framework as properly maintained PM: EM: use kfree_rcu() to simplify the code PM: EM: Slightly reduce em_check_capacity_update() overhead PM: EM: Drop unused parameter from em_adjust_new_capacity() * pm-runtime: PM: runtime: Unify error handling during suspend and resume PM: runtime: Drop status check from pm_runtime_force_resume() PM: Rearrange documentation related to __pm_runtime_disable()
3 parents 7a9072d + 17f0828 + 7226386 commit 8713024

File tree

8 files changed

+92
-86
lines changed

8 files changed

+92
-86
lines changed

MAINTAINERS

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8528,6 +8528,15 @@ M: Maxim Levitsky <maximlevitsky@gmail.com>
85288528
S: Maintained
85298529
F: drivers/media/rc/ene_ir.*
85308530

8531+
ENERGY MODEL
8532+
M: Lukasz Luba <lukasz.luba@arm.com>
8533+
M: "Rafael J. Wysocki" <rafael@kernel.org>
8534+
L: linux-pm@vger.kernel.org
8535+
S: Maintained
8536+
F: kernel/power/energy_model.c
8537+
F: include/linux/energy_model.h
8538+
F: Documentation/power/energy-model.rst
8539+
85318540
EPAPR HYPERVISOR BYTE CHANNEL DEVICE DRIVER
85328541
M: Laurentiu Tudor <laurentiu.tudor@nxp.com>
85338542
L: linuxppc-dev@lists.ozlabs.org

drivers/base/power/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,10 @@ static int device_suspend_late(struct device *dev, pm_message_t state, bool asyn
14041404
TRACE_DEVICE(dev);
14051405
TRACE_SUSPEND(0);
14061406

1407+
/*
1408+
* Disable runtime PM for the device without checking if there is a
1409+
* pending resume request for it.
1410+
*/
14071411
__pm_runtime_disable(dev, false);
14081412

14091413
dpm_wait_for_subordinate(dev, async);

drivers/base/power/runtime.c

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,19 @@ static int rpm_callback(int (*cb)(struct device *), struct device *dev)
448448
retval = __rpm_callback(cb, dev);
449449
}
450450

451-
dev->power.runtime_error = retval;
452-
return retval != -EACCES ? retval : -EIO;
451+
/*
452+
* Since -EACCES means that runtime PM is disabled for the given device,
453+
* it should not be returned by runtime PM callbacks. If it is returned
454+
* nevertheless, assume it to be a transient error and convert it to
455+
* -EAGAIN.
456+
*/
457+
if (retval == -EACCES)
458+
retval = -EAGAIN;
459+
460+
if (retval != -EAGAIN && retval != -EBUSY)
461+
dev->power.runtime_error = retval;
462+
463+
return retval;
453464
}
454465

455466
/**
@@ -725,21 +736,18 @@ static int rpm_suspend(struct device *dev, int rpmflags)
725736
dev->power.deferred_resume = false;
726737
wake_up_all(&dev->power.wait_queue);
727738

728-
if (retval == -EAGAIN || retval == -EBUSY) {
729-
dev->power.runtime_error = 0;
739+
/*
740+
* On transient errors, if the callback routine failed an autosuspend,
741+
* and if the last_busy time has been updated so that there is a new
742+
* autosuspend expiration time, automatically reschedule another
743+
* autosuspend.
744+
*/
745+
if (!dev->power.runtime_error && (rpmflags & RPM_AUTO) &&
746+
pm_runtime_autosuspend_expiration(dev) != 0)
747+
goto repeat;
748+
749+
pm_runtime_cancel_pending(dev);
730750

731-
/*
732-
* If the callback routine failed an autosuspend, and
733-
* if the last_busy time has been updated so that there
734-
* is a new autosuspend expiration time, automatically
735-
* reschedule another autosuspend.
736-
*/
737-
if ((rpmflags & RPM_AUTO) &&
738-
pm_runtime_autosuspend_expiration(dev) != 0)
739-
goto repeat;
740-
} else {
741-
pm_runtime_cancel_pending(dev);
742-
}
743751
goto out;
744752
}
745753

@@ -1460,20 +1468,6 @@ int pm_runtime_barrier(struct device *dev)
14601468
}
14611469
EXPORT_SYMBOL_GPL(pm_runtime_barrier);
14621470

1463-
/**
1464-
* __pm_runtime_disable - Disable runtime PM of a device.
1465-
* @dev: Device to handle.
1466-
* @check_resume: If set, check if there's a resume request for the device.
1467-
*
1468-
* Increment power.disable_depth for the device and if it was zero previously,
1469-
* cancel all pending runtime PM requests for the device and wait for all
1470-
* operations in progress to complete. The device can be either active or
1471-
* suspended after its runtime PM has been disabled.
1472-
*
1473-
* If @check_resume is set and there's a resume request pending when
1474-
* __pm_runtime_disable() is called and power.disable_depth is zero, the
1475-
* function will wake up the device before disabling its runtime PM.
1476-
*/
14771471
void __pm_runtime_disable(struct device *dev, bool check_resume)
14781472
{
14791473
spin_lock_irq(&dev->power.lock);
@@ -1959,7 +1953,7 @@ int pm_runtime_force_resume(struct device *dev)
19591953
int (*callback)(struct device *);
19601954
int ret = 0;
19611955

1962-
if (!pm_runtime_status_suspended(dev) || !dev->power.needs_force_resume)
1956+
if (!dev->power.needs_force_resume)
19631957
goto out;
19641958

19651959
/*

drivers/powercap/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ config DTPM
8282

8383
config DTPM_CPU
8484
bool "Add CPU power capping based on the energy model"
85-
depends on DTPM && ENERGY_MODEL
85+
depends on DTPM && ENERGY_MODEL && SMP
8686
help
8787
This enables support for CPU power limitation based on
8888
energy model.

include/linux/energy_model.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,13 @@ struct em_data_callback {
167167
struct em_perf_domain *em_cpu_get(int cpu);
168168
struct em_perf_domain *em_pd_get(struct device *dev);
169169
int em_dev_update_perf_domain(struct device *dev,
170-
struct em_perf_table __rcu *new_table);
170+
struct em_perf_table *new_table);
171171
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
172-
struct em_data_callback *cb, cpumask_t *span,
173-
bool microwatts);
172+
const struct em_data_callback *cb,
173+
const cpumask_t *cpus, bool microwatts);
174174
void em_dev_unregister_perf_domain(struct device *dev);
175-
struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd);
176-
void em_table_free(struct em_perf_table __rcu *table);
175+
struct em_perf_table *em_table_alloc(struct em_perf_domain *pd);
176+
void em_table_free(struct em_perf_table *table);
177177
int em_dev_compute_costs(struct device *dev, struct em_perf_state *table,
178178
int nr_states);
179179
int em_dev_update_chip_binning(struct device *dev);
@@ -346,8 +346,8 @@ struct em_data_callback {};
346346

347347
static inline
348348
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
349-
struct em_data_callback *cb, cpumask_t *span,
350-
bool microwatts)
349+
const struct em_data_callback *cb,
350+
const cpumask_t *cpus, bool microwatts)
351351
{
352352
return -EINVAL;
353353
}
@@ -373,14 +373,14 @@ static inline int em_pd_nr_perf_states(struct em_perf_domain *pd)
373373
return 0;
374374
}
375375
static inline
376-
struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd)
376+
struct em_perf_table *em_table_alloc(struct em_perf_domain *pd)
377377
{
378378
return NULL;
379379
}
380-
static inline void em_table_free(struct em_perf_table __rcu *table) {}
380+
static inline void em_table_free(struct em_perf_table *table) {}
381381
static inline
382382
int em_dev_update_perf_domain(struct device *dev,
383-
struct em_perf_table __rcu *new_table)
383+
struct em_perf_table *new_table)
384384
{
385385
return -EINVAL;
386386
}

include/linux/pm_runtime.h

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -556,11 +556,18 @@ static inline int pm_runtime_set_suspended(struct device *dev)
556556
* pm_runtime_disable - Disable runtime PM for a device.
557557
* @dev: Target device.
558558
*
559-
* Prevent the runtime PM framework from working with @dev (by incrementing its
560-
* "blocking" counter).
561-
*
562-
* For each invocation of this function for @dev there must be a matching
563-
* pm_runtime_enable() call in order for runtime PM to be enabled for it.
559+
* Prevent the runtime PM framework from working with @dev by incrementing its
560+
* "disable" counter.
561+
*
562+
* If the counter is zero when this function runs and there is a pending runtime
563+
* resume request for @dev, it will be resumed. If the counter is still zero at
564+
* that point, all of the pending runtime PM requests for @dev will be canceled
565+
* and all runtime PM operations in progress involving it will be waited for to
566+
* complete.
567+
*
568+
* For each invocation of this function for @dev, there must be a matching
569+
* pm_runtime_enable() call, so that runtime PM is eventually enabled for it
570+
* again.
564571
*/
565572
static inline void pm_runtime_disable(struct device *dev)
566573
{

kernel/power/Kconfig

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,7 @@ config CPU_PM
380380

381381
config ENERGY_MODEL
382382
bool "Energy Model for devices with DVFS (CPUs, GPUs, etc)"
383-
depends on SMP
384-
depends on CPU_FREQ
383+
depends on CPU_FREQ || PM_DEVFREQ
385384
help
386385
Several subsystems (thermal and/or the task scheduler for example)
387386
can leverage information about the energy consumed by devices to

kernel/power/energy_model.c

Lines changed: 30 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -161,22 +161,10 @@ static void em_debug_create_pd(struct device *dev) {}
161161
static void em_debug_remove_pd(struct device *dev) {}
162162
#endif
163163

164-
static void em_destroy_table_rcu(struct rcu_head *rp)
165-
{
166-
struct em_perf_table __rcu *table;
167-
168-
table = container_of(rp, struct em_perf_table, rcu);
169-
kfree(table);
170-
}
171-
172164
static void em_release_table_kref(struct kref *kref)
173165
{
174-
struct em_perf_table __rcu *table;
175-
176166
/* It was the last owner of this table so we can free */
177-
table = container_of(kref, struct em_perf_table, kref);
178-
179-
call_rcu(&table->rcu, em_destroy_table_rcu);
167+
kfree_rcu(container_of(kref, struct em_perf_table, kref), rcu);
180168
}
181169

182170
/**
@@ -185,7 +173,7 @@ static void em_release_table_kref(struct kref *kref)
185173
*
186174
* No return values.
187175
*/
188-
void em_table_free(struct em_perf_table __rcu *table)
176+
void em_table_free(struct em_perf_table *table)
189177
{
190178
kref_put(&table->kref, em_release_table_kref);
191179
}
@@ -198,9 +186,9 @@ void em_table_free(struct em_perf_table __rcu *table)
198186
* has a user.
199187
* Returns allocated table or NULL.
200188
*/
201-
struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd)
189+
struct em_perf_table *em_table_alloc(struct em_perf_domain *pd)
202190
{
203-
struct em_perf_table __rcu *table;
191+
struct em_perf_table *table;
204192
int table_size;
205193

206194
table_size = sizeof(struct em_perf_state) * pd->nr_perf_states;
@@ -239,7 +227,7 @@ static void em_init_performance(struct device *dev, struct em_perf_domain *pd,
239227
}
240228

241229
static int em_compute_costs(struct device *dev, struct em_perf_state *table,
242-
struct em_data_callback *cb, int nr_states,
230+
const struct em_data_callback *cb, int nr_states,
243231
unsigned long flags)
244232
{
245233
unsigned long prev_cost = ULONG_MAX;
@@ -308,9 +296,9 @@ int em_dev_compute_costs(struct device *dev, struct em_perf_state *table,
308296
* Return 0 on success or an error code on failure.
309297
*/
310298
int em_dev_update_perf_domain(struct device *dev,
311-
struct em_perf_table __rcu *new_table)
299+
struct em_perf_table *new_table)
312300
{
313-
struct em_perf_table __rcu *old_table;
301+
struct em_perf_table *old_table;
314302
struct em_perf_domain *pd;
315303

316304
if (!dev)
@@ -327,7 +315,8 @@ int em_dev_update_perf_domain(struct device *dev,
327315

328316
kref_get(&new_table->kref);
329317

330-
old_table = pd->em_table;
318+
old_table = rcu_dereference_protected(pd->em_table,
319+
lockdep_is_held(&em_pd_mutex));
331320
rcu_assign_pointer(pd->em_table, new_table);
332321

333322
em_cpufreq_update_efficiencies(dev, new_table->state);
@@ -341,7 +330,7 @@ EXPORT_SYMBOL_GPL(em_dev_update_perf_domain);
341330

342331
static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
343332
struct em_perf_state *table,
344-
struct em_data_callback *cb,
333+
const struct em_data_callback *cb,
345334
unsigned long flags)
346335
{
347336
unsigned long power, freq, prev_freq = 0;
@@ -396,10 +385,11 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
396385
}
397386

398387
static int em_create_pd(struct device *dev, int nr_states,
399-
struct em_data_callback *cb, cpumask_t *cpus,
388+
const struct em_data_callback *cb,
389+
const cpumask_t *cpus,
400390
unsigned long flags)
401391
{
402-
struct em_perf_table __rcu *em_table;
392+
struct em_perf_table *em_table;
403393
struct em_perf_domain *pd;
404394
struct device *cpu_dev;
405395
int cpu, ret, num_cpus;
@@ -556,9 +546,10 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
556546
* Return 0 on success
557547
*/
558548
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
559-
struct em_data_callback *cb, cpumask_t *cpus,
560-
bool microwatts)
549+
const struct em_data_callback *cb,
550+
const cpumask_t *cpus, bool microwatts)
561551
{
552+
struct em_perf_table *em_table;
562553
unsigned long cap, prev_cap = 0;
563554
unsigned long flags = 0;
564555
int cpu, ret;
@@ -631,7 +622,9 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
631622
dev->em_pd->min_perf_state = 0;
632623
dev->em_pd->max_perf_state = nr_states - 1;
633624

634-
em_cpufreq_update_efficiencies(dev, dev->em_pd->em_table->state);
625+
em_table = rcu_dereference_protected(dev->em_pd->em_table,
626+
lockdep_is_held(&em_pd_mutex));
627+
em_cpufreq_update_efficiencies(dev, em_table->state);
635628

636629
em_debug_create_pd(dev);
637630
dev_info(dev, "EM: created perf domain\n");
@@ -668,17 +661,18 @@ void em_dev_unregister_perf_domain(struct device *dev)
668661
mutex_lock(&em_pd_mutex);
669662
em_debug_remove_pd(dev);
670663

671-
em_table_free(dev->em_pd->em_table);
664+
em_table_free(rcu_dereference_protected(dev->em_pd->em_table,
665+
lockdep_is_held(&em_pd_mutex)));
672666

673667
kfree(dev->em_pd);
674668
dev->em_pd = NULL;
675669
mutex_unlock(&em_pd_mutex);
676670
}
677671
EXPORT_SYMBOL_GPL(em_dev_unregister_perf_domain);
678672

679-
static struct em_perf_table __rcu *em_table_dup(struct em_perf_domain *pd)
673+
static struct em_perf_table *em_table_dup(struct em_perf_domain *pd)
680674
{
681-
struct em_perf_table __rcu *em_table;
675+
struct em_perf_table *em_table;
682676
struct em_perf_state *ps, *new_ps;
683677
int ps_size;
684678

@@ -700,7 +694,7 @@ static struct em_perf_table __rcu *em_table_dup(struct em_perf_domain *pd)
700694
}
701695

702696
static int em_recalc_and_update(struct device *dev, struct em_perf_domain *pd,
703-
struct em_perf_table __rcu *em_table)
697+
struct em_perf_table *em_table)
704698
{
705699
int ret;
706700

@@ -728,10 +722,9 @@ static int em_recalc_and_update(struct device *dev, struct em_perf_domain *pd,
728722
* are correctly calculated.
729723
*/
730724
static void em_adjust_new_capacity(struct device *dev,
731-
struct em_perf_domain *pd,
732-
u64 max_cap)
725+
struct em_perf_domain *pd)
733726
{
734-
struct em_perf_table __rcu *em_table;
727+
struct em_perf_table *em_table;
735728

736729
em_table = em_table_dup(pd);
737730
if (!em_table) {
@@ -775,7 +768,8 @@ static void em_check_capacity_update(void)
775768
}
776769
cpufreq_cpu_put(policy);
777770

778-
pd = em_cpu_get(cpu);
771+
dev = get_cpu_device(cpu);
772+
pd = em_pd_get(dev);
779773
if (!pd || em_is_artificial(pd))
780774
continue;
781775

@@ -799,8 +793,7 @@ static void em_check_capacity_update(void)
799793
pr_debug("updating cpu%d cpu_cap=%lu old capacity=%lu\n",
800794
cpu, cpu_capacity, em_max_perf);
801795

802-
dev = get_cpu_device(cpu);
803-
em_adjust_new_capacity(dev, pd, cpu_capacity);
796+
em_adjust_new_capacity(dev, pd);
804797
}
805798

806799
free_cpumask_var(cpu_done_mask);
@@ -822,7 +815,7 @@ static void em_update_workfn(struct work_struct *work)
822815
*/
823816
int em_dev_update_chip_binning(struct device *dev)
824817
{
825-
struct em_perf_table __rcu *em_table;
818+
struct em_perf_table *em_table;
826819
struct em_perf_domain *pd;
827820
int i, ret;
828821

0 commit comments

Comments
 (0)