mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-16 10:17:32 +00:00
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
This commit is contained in:
commit
de1c2722e0
@ -333,7 +333,7 @@ struct pci_dev.
|
||||
The PCI subsystem's first task related to device power management is to
|
||||
prepare the device for power management and initialize the fields of struct
|
||||
pci_dev used for this purpose. This happens in two functions defined in
|
||||
drivers/pci/pci.c, pci_pm_init() and platform_pci_wakeup_init().
|
||||
drivers/pci/, pci_pm_init() and pci_acpi_setup().
|
||||
|
||||
The first of these functions checks if the device supports native PCI PM
|
||||
and if that's the case the offset of its power management capability structure
|
||||
|
@ -1494,20 +1494,26 @@ _get_dt_power(struct device *dev, unsigned long *uW, unsigned long *kHz)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback function provided to the Energy Model framework upon registration.
|
||||
/**
|
||||
* dev_pm_opp_calc_power() - Calculate power value for device with EM
|
||||
* @dev : Device for which an Energy Model has to be registered
|
||||
* @uW : New power value that is calculated
|
||||
* @kHz : Frequency for which the new power is calculated
|
||||
*
|
||||
* This computes the power estimated by @dev at @kHz if it is the frequency
|
||||
* of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
|
||||
* (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
|
||||
* frequency and @uW to the associated power. The power is estimated as
|
||||
* P = C * V^2 * f with C being the device's capacitance and V and f
|
||||
* respectively the voltage and frequency of the OPP.
|
||||
* It is also used as a callback function provided to the Energy Model
|
||||
* framework upon registration.
|
||||
*
|
||||
* Returns -EINVAL if the power calculation failed because of missing
|
||||
* parameters, 0 otherwise.
|
||||
*/
|
||||
static int __maybe_unused _get_power(struct device *dev, unsigned long *uW,
|
||||
unsigned long *kHz)
|
||||
int dev_pm_opp_calc_power(struct device *dev, unsigned long *uW,
|
||||
unsigned long *kHz)
|
||||
{
|
||||
struct dev_pm_opp *opp;
|
||||
struct device_node *np;
|
||||
@ -1544,6 +1550,7 @@ static int __maybe_unused _get_power(struct device *dev, unsigned long *uW,
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_calc_power);
|
||||
|
||||
static bool _of_has_opp_microwatt_property(struct device *dev)
|
||||
{
|
||||
@ -1619,7 +1626,7 @@ int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
EM_SET_ACTIVE_POWER_CB(em_cb, _get_power);
|
||||
EM_SET_ACTIVE_POWER_CB(em_cb, dev_pm_opp_calc_power);
|
||||
|
||||
register_em:
|
||||
ret = em_dev_register_perf_domain(dev, nr_opp, &em_cb, cpus, true);
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/energy_model.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pm_opp.h>
|
||||
@ -97,9 +98,16 @@ static int exynos_asv_update_opps(struct exynos_asv *asv)
|
||||
last_opp_table = opp_table;
|
||||
|
||||
ret = exynos_asv_update_cpu_opps(asv, cpu);
|
||||
if (ret < 0)
|
||||
if (!ret) {
|
||||
/*
|
||||
* Update EM power values since OPP
|
||||
* voltage values may have changed.
|
||||
*/
|
||||
em_dev_update_chip_binning(cpu);
|
||||
} else {
|
||||
dev_err(asv->dev, "Couldn't udate OPPs for cpu%d\n",
|
||||
cpuid);
|
||||
}
|
||||
}
|
||||
|
||||
dev_pm_opp_put_opp_table(opp_table);
|
||||
|
@ -172,6 +172,7 @@ struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd);
|
||||
void em_table_free(struct em_perf_table __rcu *table);
|
||||
int em_dev_compute_costs(struct device *dev, struct em_perf_state *table,
|
||||
int nr_states);
|
||||
int em_dev_update_chip_binning(struct device *dev);
|
||||
|
||||
/**
|
||||
* 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,
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline int em_dev_update_chip_binning(struct device *dev)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -476,6 +476,8 @@ struct device_node *dev_pm_opp_get_of_node(struct dev_pm_opp *opp);
|
||||
int of_get_required_opp_performance_state(struct device_node *np, int index);
|
||||
int dev_pm_opp_of_find_icc_paths(struct device *dev, struct opp_table *opp_table);
|
||||
int dev_pm_opp_of_register_em(struct device *dev, struct cpumask *cpus);
|
||||
int dev_pm_opp_calc_power(struct device *dev, unsigned long *uW,
|
||||
unsigned long *kHz);
|
||||
static inline void dev_pm_opp_of_unregister_em(struct device *dev)
|
||||
{
|
||||
em_dev_unregister_perf_domain(dev);
|
||||
@ -539,6 +541,12 @@ static inline void dev_pm_opp_of_unregister_em(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dev_pm_opp_calc_power(struct device *dev, unsigned long *uW,
|
||||
unsigned long *kHz)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int of_get_required_opp_performance_state(struct device_node *np, int index)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -674,23 +674,15 @@ void em_dev_unregister_perf_domain(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(em_dev_unregister_perf_domain);
|
||||
|
||||
/*
|
||||
* Adjustment of CPU performance values after boot, when all CPUs capacites
|
||||
* are correctly calculated.
|
||||
*/
|
||||
static void em_adjust_new_capacity(struct device *dev,
|
||||
struct em_perf_domain *pd,
|
||||
u64 max_cap)
|
||||
static struct em_perf_table __rcu *em_table_dup(struct em_perf_domain *pd)
|
||||
{
|
||||
struct em_perf_table __rcu *em_table;
|
||||
struct em_perf_state *ps, *new_ps;
|
||||
int ret, ps_size;
|
||||
int ps_size;
|
||||
|
||||
em_table = em_table_alloc(pd);
|
||||
if (!em_table) {
|
||||
dev_warn(dev, "EM: allocation failed\n");
|
||||
return;
|
||||
}
|
||||
if (!em_table)
|
||||
return NULL;
|
||||
|
||||
new_ps = em_table->state;
|
||||
|
||||
@ -702,24 +694,52 @@ static void em_adjust_new_capacity(struct device *dev,
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
em_init_performance(dev, pd, new_ps, pd->nr_perf_states);
|
||||
ret = em_compute_costs(dev, new_ps, NULL, pd->nr_perf_states,
|
||||
return em_table;
|
||||
}
|
||||
|
||||
static int em_recalc_and_update(struct device *dev, struct em_perf_domain *pd,
|
||||
struct em_perf_table __rcu *em_table)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = em_compute_costs(dev, em_table->state, NULL, pd->nr_perf_states,
|
||||
pd->flags);
|
||||
if (ret) {
|
||||
dev_warn(dev, "EM: compute costs failed\n");
|
||||
return;
|
||||
}
|
||||
if (ret)
|
||||
goto free_em_table;
|
||||
|
||||
ret = em_dev_update_perf_domain(dev, em_table);
|
||||
if (ret)
|
||||
dev_warn(dev, "EM: update failed %d\n", ret);
|
||||
goto free_em_table;
|
||||
|
||||
/*
|
||||
* This is one-time-update, so give up the ownership in this updater.
|
||||
* The EM framework has incremented the usage counter and from now
|
||||
* will keep the reference (then free the memory when needed).
|
||||
*/
|
||||
free_em_table:
|
||||
em_table_free(em_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjustment of CPU performance values after boot, when all CPUs capacites
|
||||
* are correctly calculated.
|
||||
*/
|
||||
static void em_adjust_new_capacity(struct device *dev,
|
||||
struct em_perf_domain *pd,
|
||||
u64 max_cap)
|
||||
{
|
||||
struct em_perf_table __rcu *em_table;
|
||||
|
||||
em_table = em_table_dup(pd);
|
||||
if (!em_table) {
|
||||
dev_warn(dev, "EM: allocation failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
em_init_performance(dev, pd, em_table->state, pd->nr_perf_states);
|
||||
|
||||
em_recalc_and_update(dev, pd, em_table);
|
||||
}
|
||||
|
||||
static void em_check_capacity_update(void)
|
||||
@ -788,3 +808,51 @@ static void em_update_workfn(struct work_struct *work)
|
||||
{
|
||||
em_check_capacity_update();
|
||||
}
|
||||
|
||||
/**
|
||||
* em_dev_update_chip_binning() - Update Energy Model after the new voltage
|
||||
* information is present in the OPPs.
|
||||
* @dev : Device for which the Energy Model has to be updated.
|
||||
*
|
||||
* This function allows to update easily the EM with new values available in
|
||||
* the OPP framework and DT. It can be used after the chip has been properly
|
||||
* verified by device drivers and the voltages adjusted for the 'chip binning'.
|
||||
*/
|
||||
int em_dev_update_chip_binning(struct device *dev)
|
||||
{
|
||||
struct em_perf_table __rcu *em_table;
|
||||
struct em_perf_domain *pd;
|
||||
int i, ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(dev))
|
||||
return -EINVAL;
|
||||
|
||||
pd = em_pd_get(dev);
|
||||
if (!pd) {
|
||||
dev_warn(dev, "Couldn't find Energy Model\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
em_table = em_table_dup(pd);
|
||||
if (!em_table) {
|
||||
dev_warn(dev, "EM: allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Update power values which might change due to new voltage in OPPs */
|
||||
for (i = 0; i < pd->nr_perf_states; i++) {
|
||||
unsigned long freq = em_table->state[i].frequency;
|
||||
unsigned long power;
|
||||
|
||||
ret = dev_pm_opp_calc_power(dev, &power, &freq);
|
||||
if (ret) {
|
||||
em_table_free(em_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
em_table->state[i].power = power;
|
||||
}
|
||||
|
||||
return em_recalc_and_update(dev, pd, em_table);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(em_dev_update_chip_binning);
|
||||
|
Loading…
x
Reference in New Issue
Block a user