Skip to content

Commit de1c272

Browse files
committed
Merge branches 'pm-em' and 'pm-docs'
Merge Enery Model update and a power management documentation update for 6.10: - Make the Samsung exynos-asv driver update the Energy Model after adjusting voltage on top of some preliminary changes of the OPP and Enery Model generic code (Lukasz Luba). - Remove a reference to a function that has been dropped from the power management documentation (Bjorn Helgaas). * pm-em: soc: samsung: exynos-asv: Update Energy Model after adjusting voltage PM: EM: Add em_dev_update_chip_binning() PM: EM: Refactor em_adjust_new_capacity() OPP: OF: Export dev_opp_pm_calc_power() for usage from EM * pm-docs: Documentation: PM: Update platform_pci_wakeup_init() reference
3 parents 440f9d4 + a5bb5e0 + eb68d90 commit de1c272

File tree

6 files changed

+122
-26
lines changed

6 files changed

+122
-26
lines changed

Documentation/power/pci.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ struct pci_dev.
333333
The PCI subsystem's first task related to device power management is to
334334
prepare the device for power management and initialize the fields of struct
335335
pci_dev used for this purpose. This happens in two functions defined in
336-
drivers/pci/pci.c, pci_pm_init() and platform_pci_wakeup_init().
336+
drivers/pci/, pci_pm_init() and pci_acpi_setup().
337337

338338
The first of these functions checks if the device supports native PCI PM
339339
and if that's the case the offset of its power management capability structure

drivers/opp/of.c

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,20 +1494,26 @@ _get_dt_power(struct device *dev, unsigned long *uW, unsigned long *kHz)
14941494
return 0;
14951495
}
14961496

1497-
/*
1498-
* Callback function provided to the Energy Model framework upon registration.
1497+
/**
1498+
* dev_pm_opp_calc_power() - Calculate power value for device with EM
1499+
* @dev : Device for which an Energy Model has to be registered
1500+
* @uW : New power value that is calculated
1501+
* @kHz : Frequency for which the new power is calculated
1502+
*
14991503
* This computes the power estimated by @dev at @kHz if it is the frequency
15001504
* of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
15011505
* (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
15021506
* frequency and @uW to the associated power. The power is estimated as
15031507
* P = C * V^2 * f with C being the device's capacitance and V and f
15041508
* respectively the voltage and frequency of the OPP.
1509+
* It is also used as a callback function provided to the Energy Model
1510+
* framework upon registration.
15051511
*
15061512
* Returns -EINVAL if the power calculation failed because of missing
15071513
* parameters, 0 otherwise.
15081514
*/
1509-
static int __maybe_unused _get_power(struct device *dev, unsigned long *uW,
1510-
unsigned long *kHz)
1515+
int dev_pm_opp_calc_power(struct device *dev, unsigned long *uW,
1516+
unsigned long *kHz)
15111517
{
15121518
struct dev_pm_opp *opp;
15131519
struct device_node *np;
@@ -1544,6 +1550,7 @@ static int __maybe_unused _get_power(struct device *dev, unsigned long *uW,
15441550

15451551
return 0;
15461552
}
1553+
EXPORT_SYMBOL_GPL(dev_pm_opp_calc_power);
15471554

15481555
static bool _of_has_opp_microwatt_property(struct device *dev)
15491556
{
@@ -1619,7 +1626,7 @@ int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
16191626
goto failed;
16201627
}
16211628

1622-
EM_SET_ACTIVE_POWER_CB(em_cb, _get_power);
1629+
EM_SET_ACTIVE_POWER_CB(em_cb, dev_pm_opp_calc_power);
16231630

16241631
register_em:
16251632
ret = em_dev_register_perf_domain(dev, nr_opp, &em_cb, cpus, true);

drivers/soc/samsung/exynos-asv.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <linux/cpu.h>
1313
#include <linux/device.h>
14+
#include <linux/energy_model.h>
1415
#include <linux/errno.h>
1516
#include <linux/of.h>
1617
#include <linux/pm_opp.h>
@@ -97,9 +98,16 @@ static int exynos_asv_update_opps(struct exynos_asv *asv)
9798
last_opp_table = opp_table;
9899

99100
ret = exynos_asv_update_cpu_opps(asv, cpu);
100-
if (ret < 0)
101+
if (!ret) {
102+
/*
103+
* Update EM power values since OPP
104+
* voltage values may have changed.
105+
*/
106+
em_dev_update_chip_binning(cpu);
107+
} else {
101108
dev_err(asv->dev, "Couldn't udate OPPs for cpu%d\n",
102109
cpuid);
110+
}
103111
}
104112

105113
dev_pm_opp_put_opp_table(opp_table);

include/linux/energy_model.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd);
172172
void em_table_free(struct em_perf_table __rcu *table);
173173
int em_dev_compute_costs(struct device *dev, struct em_perf_state *table,
174174
int nr_states);
175+
int em_dev_update_chip_binning(struct device *dev);
175176

176177
/**
177178
* em_pd_get_efficient_state() - Get an efficient performance state from the EM
@@ -386,6 +387,10 @@ int em_dev_compute_costs(struct device *dev, struct em_perf_state *table,
386387
{
387388
return -EINVAL;
388389
}
390+
static inline int em_dev_update_chip_binning(struct device *dev)
391+
{
392+
return -EINVAL;
393+
}
389394
#endif
390395

391396
#endif

include/linux/pm_opp.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@ struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp);
476476
int of_get_required_opp_performance_state(struct device_node *np, int index);
477477
int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_table *opp_table);
478478
int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus);
479+
int dev_pm_opp_calc_power(struct device *dev, unsigned long *uW,
480+
unsigned long *kHz);
479481
static inline void dev_pm_opp_of_unregister_em(struct device *dev)
480482
{
481483
em_dev_unregister_perf_domain(dev);
@@ -539,6 +541,12 @@ static inline void dev_pm_opp_of_unregister_em(struct device *dev)
539541
{
540542
}
541543

544+
static inline int dev_pm_opp_calc_power(struct device *dev, unsigned long *uW,
545+
unsigned long *kHz)
546+
{
547+
return -EOPNOTSUPP;
548+
}
549+
542550
static inline int of_get_required_opp_performance_state(struct device_node *np, int index)
543551
{
544552
return -EOPNOTSUPP;

kernel/power/energy_model.c

Lines changed: 87 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -674,23 +674,15 @@ void em_dev_unregister_perf_domain(struct device *dev)
674674
}
675675
EXPORT_SYMBOL_GPL(em_dev_unregister_perf_domain);
676676

677-
/*
678-
* Adjustment of CPU performance values after boot, when all CPUs capacites
679-
* are correctly calculated.
680-
*/
681-
static void em_adjust_new_capacity(struct device *dev,
682-
struct em_perf_domain *pd,
683-
u64 max_cap)
677+
static struct em_perf_table __rcu *em_table_dup(struct em_perf_domain *pd)
684678
{
685679
struct em_perf_table __rcu *em_table;
686680
struct em_perf_state *ps, *new_ps;
687-
int ret, ps_size;
681+
int ps_size;
688682

689683
em_table = em_table_alloc(pd);
690-
if (!em_table) {
691-
dev_warn(dev, "EM: allocation failed\n");
692-
return;
693-
}
684+
if (!em_table)
685+
return NULL;
694686

695687
new_ps = em_table->state;
696688

@@ -702,24 +694,52 @@ static void em_adjust_new_capacity(struct device *dev,
702694

703695
rcu_read_unlock();
704696

705-
em_init_performance(dev, pd, new_ps, pd->nr_perf_states);
706-
ret = em_compute_costs(dev, new_ps, NULL, pd->nr_perf_states,
697+
return em_table;
698+
}
699+
700+
static int em_recalc_and_update(struct device *dev, struct em_perf_domain *pd,
701+
struct em_perf_table __rcu *em_table)
702+
{
703+
int ret;
704+
705+
ret = em_compute_costs(dev, em_table->state, NULL, pd->nr_perf_states,
707706
pd->flags);
708-
if (ret) {
709-
dev_warn(dev, "EM: compute costs failed\n");
710-
return;
711-
}
707+
if (ret)
708+
goto free_em_table;
712709

713710
ret = em_dev_update_perf_domain(dev, em_table);
714711
if (ret)
715-
dev_warn(dev, "EM: update failed %d\n", ret);
712+
goto free_em_table;
716713

717714
/*
718715
* This is one-time-update, so give up the ownership in this updater.
719716
* The EM framework has incremented the usage counter and from now
720717
* will keep the reference (then free the memory when needed).
721718
*/
719+
free_em_table:
722720
em_table_free(em_table);
721+
return ret;
722+
}
723+
724+
/*
725+
* Adjustment of CPU performance values after boot, when all CPUs capacites
726+
* are correctly calculated.
727+
*/
728+
static void em_adjust_new_capacity(struct device *dev,
729+
struct em_perf_domain *pd,
730+
u64 max_cap)
731+
{
732+
struct em_perf_table __rcu *em_table;
733+
734+
em_table = em_table_dup(pd);
735+
if (!em_table) {
736+
dev_warn(dev, "EM: allocation failed\n");
737+
return;
738+
}
739+
740+
em_init_performance(dev, pd, em_table->state, pd->nr_perf_states);
741+
742+
em_recalc_and_update(dev, pd, em_table);
723743
}
724744

725745
static void em_check_capacity_update(void)
@@ -788,3 +808,51 @@ static void em_update_workfn(struct work_struct *work)
788808
{
789809
em_check_capacity_update();
790810
}
811+
812+
/**
813+
* em_dev_update_chip_binning() - Update Energy Model after the new voltage
814+
* information is present in the OPPs.
815+
* @dev : Device for which the Energy Model has to be updated.
816+
*
817+
* This function allows to update easily the EM with new values available in
818+
* the OPP framework and DT. It can be used after the chip has been properly
819+
* verified by device drivers and the voltages adjusted for the 'chip binning'.
820+
*/
821+
int em_dev_update_chip_binning(struct device *dev)
822+
{
823+
struct em_perf_table __rcu *em_table;
824+
struct em_perf_domain *pd;
825+
int i, ret;
826+
827+
if (IS_ERR_OR_NULL(dev))
828+
return -EINVAL;
829+
830+
pd = em_pd_get(dev);
831+
if (!pd) {
832+
dev_warn(dev, "Couldn't find Energy Model\n");
833+
return -EINVAL;
834+
}
835+
836+
em_table = em_table_dup(pd);
837+
if (!em_table) {
838+
dev_warn(dev, "EM: allocation failed\n");
839+
return -ENOMEM;
840+
}
841+
842+
/* Update power values which might change due to new voltage in OPPs */
843+
for (i = 0; i < pd->nr_perf_states; i++) {
844+
unsigned long freq = em_table->state[i].frequency;
845+
unsigned long power;
846+
847+
ret = dev_pm_opp_calc_power(dev, &power, &freq);
848+
if (ret) {
849+
em_table_free(em_table);
850+
return ret;
851+
}
852+
853+
em_table->state[i].power = power;
854+
}
855+
856+
return em_recalc_and_update(dev, pd, em_table);
857+
}
858+
EXPORT_SYMBOL_GPL(em_dev_update_chip_binning);

0 commit comments

Comments
 (0)