Merge tag 'pm+acpi-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management and ACPI updates from Rafael Wysocki:
 "From the number of commits perspective, the biggest items are ACPICA
  and cpufreq changes with the latter taking the lead (over 50 commits).

  On the cpufreq front, there are many cleanups and minor fixes in the
  core and governors, driver updates etc.  We also have a new cpufreq
  driver for Mediatek MT8173 chips.

  ACPICA mostly updates its debug infrastructure and adds a number of
  fixes and cleanups for a good measure.

  The Operating Performance Points (OPP) framework is updated with new
  DT bindings and support for them among other things.

  We have a few updates of the generic power domains framework and a
  reorganization of the ACPI device enumeration code and bus type
  operations.

  And a lot of fixes and cleanups all over.

  Included is one branch from the MFD tree as it contains some
  PM-related driver core and ACPI PM changes a few other commits are
  based on.

  Specifics:

   - ACPICA update to upstream revision 20150818 including method
     tracing extensions to allow more in-depth AML debugging in the
     kernel and a number of assorted fixes and cleanups (Bob Moore, Lv
     Zheng, Markus Elfring).

   - ACPI sysfs code updates and a documentation update related to AML
     method tracing (Lv Zheng).

   - ACPI EC driver fix related to serialized evaluations of _Qxx
     methods and ACPI tools updates allowing the EC userspace tool to be
     built from the kernel source (Lv Zheng).

   - ACPI processor driver updates preparing it for future introduction
     of CPPC support and ACPI PCC mailbox driver updates (Ashwin
     Chaugule).

   - ACPI interrupts enumeration fix for a regression related to the
     handling of IRQ attribute conflicts between MADT and the ACPI
     namespace (Jiang Liu).

   - Fixes related to ACPI device PM (Mika Westerberg, Srinidhi
     Kasagar).

   - ACPI device registration code reorganization to separate the
     sysfs-related code and bus type operations from the rest (Rafael J
     Wysocki).

   - Assorted cleanups in the ACPI core (Jarkko Nikula, Mathias Krause,
     Andy Shevchenko, Rafael J Wysocki, Nicolas Iooss).

   - ACPI cpufreq driver and ia64 cpufreq driver fixes and cleanups (Pan
     Xinhui, Rafael J Wysocki).

   - cpufreq core cleanups on top of the previous changes allowing it to
     preseve its sysfs directories over system suspend/resume (Viresh
     Kumar, Rafael J Wysocki, Sebastian Andrzej Siewior).

   - cpufreq fixes and cleanups related to governors (Viresh Kumar).

   - cpufreq updates (core and the cpufreq-dt driver) related to the
     turbo/boost mode support (Viresh Kumar, Bartlomiej Zolnierkiewicz).

   - New DT bindings for Operating Performance Points (OPP), support for
     them in the OPP framework and in the cpufreq-dt driver plus related
     OPP framework fixes and cleanups (Viresh Kumar).

   - cpufreq powernv driver updates (Shilpasri G Bhat).

   - New cpufreq driver for Mediatek MT8173 (Pi-Cheng Chen).

   - Assorted cpufreq driver (speedstep-lib, sfi, integrator) cleanups
     and fixes (Abhilash Jindal, Andrzej Hajda, Cristian Ardelean).

   - intel_pstate driver updates including Skylake-S support, support
     for enabling HW P-states per CPU and an additional vendor bypass
     list entry (Kristen Carlson Accardi, Chen Yu, Ethan Zhao).

   - cpuidle core fixes related to the handling of coupled idle states
     (Xunlei Pang).

   - intel_idle driver updates including Skylake Client support and
     support for freeze-mode-specific idle states (Len Brown).

   - Driver core updates related to power management (Andy Shevchenko,
     Rafael J Wysocki).

   - Generic power domains framework fixes and cleanups (Jon Hunter,
     Geert Uytterhoeven, Rajendra Nayak, Ulf Hansson).

   - Device PM QoS framework update to allow the latency tolerance
     setting to be exposed to user space via sysfs (Mika Westerberg).

   - devfreq support for PPMUv2 in Exynos5433 and a fix for an incorrect
     exynos-ppmu DT binding (Chanwoo Choi, Javier Martinez Canillas).

   - System sleep support updates (Alan Stern, Len Brown, SungEun Kim).

   - rockchip-io AVS support updates (Heiko Stuebner).

   - PM core clocks support fixup (Colin Ian King).

   - Power capping RAPL driver update including support for Skylake H/S
     and Broadwell-H (Radivoje Jovanovic, Seiichi Ikarashi).

   - Generic device properties framework fixes related to the handling
     of static (driver-provided) property sets (Andy Shevchenko).

   - turbostat and cpupower updates (Len Brown, Shilpasri G Bhat,
     Shreyas B Prabhu)"

* tag 'pm+acpi-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (180 commits)
  cpufreq: speedstep-lib: Use monotonic clock
  cpufreq: powernv: Increase the verbosity of OCC console messages
  cpufreq: sfi: use kmemdup rather than duplicating its implementation
  cpufreq: drop !cpufreq_driver check from cpufreq_parse_governor()
  cpufreq: rename cpufreq_real_policy as cpufreq_user_policy
  cpufreq: remove redundant 'policy' field from user_policy
  cpufreq: remove redundant 'governor' field from user_policy
  cpufreq: update user_policy.* on success
  cpufreq: use memcpy() to copy policy
  cpufreq: remove redundant CPUFREQ_INCOMPATIBLE notifier event
  cpufreq: mediatek: Add MT8173 cpufreq driver
  dt-bindings: mediatek: Add MT8173 CPU DVFS clock bindings
  PM / Domains: Fix typo in description of genpd_dev_pm_detach()
  PM / Domains: Remove unusable governor dummies
  PM / Domains: Make pm_genpd_init() available to modules
  PM / domains: Align column headers and data in pm_genpd_summary output
  powercap / RAPL: disable the 2nd power limit properly
  tools: cpupower: Fix error when running cpupower monitor
  PM / OPP: Drop unlikely before IS_ERR(_OR_NULL)
  PM / OPP: Fix static checker warning (broken 64bit big endian systems)
  ...
此提交包含在:
Linus Torvalds
2015-09-01 19:45:46 -07:00
當前提交 ae98207309
共有 212 個檔案被更改,包括 8432 行新增3365 行删除

查看文件

@@ -1301,6 +1301,19 @@ void device_unregister(struct device *dev)
}
EXPORT_SYMBOL_GPL(device_unregister);
static struct device *prev_device(struct klist_iter *i)
{
struct klist_node *n = klist_prev(i);
struct device *dev = NULL;
struct device_private *p;
if (n) {
p = to_device_private_parent(n);
dev = p->device;
}
return dev;
}
static struct device *next_device(struct klist_iter *i)
{
struct klist_node *n = klist_next(i);
@@ -1389,6 +1402,36 @@ int device_for_each_child(struct device *parent, void *data,
}
EXPORT_SYMBOL_GPL(device_for_each_child);
/**
* device_for_each_child_reverse - device child iterator in reversed order.
* @parent: parent struct device.
* @fn: function to be called for each device.
* @data: data for the callback.
*
* Iterate over @parent's child devices, and call @fn for each,
* passing it @data.
*
* We check the return of @fn each time. If it returns anything
* other than 0, we break out and return that value.
*/
int device_for_each_child_reverse(struct device *parent, void *data,
int (*fn)(struct device *dev, void *data))
{
struct klist_iter i;
struct device *child;
int error = 0;
if (!parent->p)
return 0;
klist_iter_init(&parent->p->klist_children, &i);
while ((child = prev_device(&i)) && !error)
error = fn(child, data);
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(device_for_each_child_reverse);
/**
* device_find_child - device iterator for locating a particular device.
* @parent: parent struct device

查看文件

@@ -407,6 +407,8 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe);
*
* This function must be called with @dev lock held. When called for a
* USB interface, @dev->parent lock must be held as well.
*
* If the device has a parent, runtime-resume the parent before driver probing.
*/
int driver_probe_device(struct device_driver *drv, struct device *dev)
{
@@ -418,10 +420,16 @@ int driver_probe_device(struct device_driver *drv, struct device *dev)
pr_debug("bus: '%s': %s: matched device %s with driver %s\n",
drv->bus->name, __func__, dev_name(dev), drv->name);
if (dev->parent)
pm_runtime_get_sync(dev->parent);
pm_runtime_barrier(dev);
ret = really_probe(dev, drv);
pm_request_idle(dev);
if (dev->parent)
pm_runtime_put(dev->parent);
return ret;
}
@@ -515,11 +523,17 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie)
device_lock(dev);
if (dev->parent)
pm_runtime_get_sync(dev->parent);
bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver);
dev_dbg(dev, "async probe completed\n");
pm_request_idle(dev);
if (dev->parent)
pm_runtime_put(dev->parent);
device_unlock(dev);
put_device(dev);
@@ -549,6 +563,9 @@ static int __device_attach(struct device *dev, bool allow_async)
.want_async = false,
};
if (dev->parent)
pm_runtime_get_sync(dev->parent);
ret = bus_for_each_drv(dev->bus, NULL, &data,
__device_attach_driver);
if (!ret && allow_async && data.have_async) {
@@ -565,6 +582,9 @@ static int __device_attach(struct device *dev, bool allow_async)
} else {
pm_request_idle(dev);
}
if (dev->parent)
pm_runtime_put(dev->parent);
}
out_unlock:
device_unlock(dev);

查看文件

@@ -38,7 +38,7 @@ struct pm_clock_entry {
* @dev: The device for the given clock
* @ce: PM clock entry corresponding to the clock.
*/
static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce)
static inline void __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce)
{
int ret;
@@ -50,8 +50,6 @@ static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce)
dev_err(dev, "%s: failed to enable clk %p, error %d\n",
__func__, ce->clk, ret);
}
return ret;
}
/**

查看文件

@@ -114,8 +114,12 @@ static int genpd_stop_dev(struct generic_pm_domain *genpd, struct device *dev)
stop_latency_ns, "stop");
}
static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev)
static int genpd_start_dev(struct generic_pm_domain *genpd, struct device *dev,
bool timed)
{
if (!timed)
return GENPD_DEV_CALLBACK(genpd, int, start, dev);
return GENPD_DEV_TIMED_CALLBACK(genpd, int, start, dev,
start_latency_ns, "start");
}
@@ -136,41 +140,6 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
smp_mb__after_atomic();
}
static void genpd_acquire_lock(struct generic_pm_domain *genpd)
{
DEFINE_WAIT(wait);
mutex_lock(&genpd->lock);
/*
* Wait for the domain to transition into either the active,
* or the power off state.
*/
for (;;) {
prepare_to_wait(&genpd->status_wait_queue, &wait,
TASK_UNINTERRUPTIBLE);
if (genpd->status == GPD_STATE_ACTIVE
|| genpd->status == GPD_STATE_POWER_OFF)
break;
mutex_unlock(&genpd->lock);
schedule();
mutex_lock(&genpd->lock);
}
finish_wait(&genpd->status_wait_queue, &wait);
}
static void genpd_release_lock(struct generic_pm_domain *genpd)
{
mutex_unlock(&genpd->lock);
}
static void genpd_set_active(struct generic_pm_domain *genpd)
{
if (genpd->resume_count == 0)
genpd->status = GPD_STATE_ACTIVE;
}
static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
{
s64 usecs64;
@@ -251,35 +220,14 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed)
* resume a device belonging to it.
*/
static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
__releases(&genpd->lock) __acquires(&genpd->lock)
{
struct gpd_link *link;
DEFINE_WAIT(wait);
int ret = 0;
/* If the domain's master is being waited for, we have to wait too. */
for (;;) {
prepare_to_wait(&genpd->status_wait_queue, &wait,
TASK_UNINTERRUPTIBLE);
if (genpd->status != GPD_STATE_WAIT_MASTER)
break;
mutex_unlock(&genpd->lock);
schedule();
mutex_lock(&genpd->lock);
}
finish_wait(&genpd->status_wait_queue, &wait);
if (genpd->status == GPD_STATE_ACTIVE
|| (genpd->prepared_count > 0 && genpd->suspend_power_off))
return 0;
if (genpd->status != GPD_STATE_POWER_OFF) {
genpd_set_active(genpd);
return 0;
}
if (genpd->cpuidle_data) {
cpuidle_pause_and_lock();
genpd->cpuidle_data->idle_state->disabled = true;
@@ -294,20 +242,8 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
*/
list_for_each_entry(link, &genpd->slave_links, slave_node) {
genpd_sd_counter_inc(link->master);
genpd->status = GPD_STATE_WAIT_MASTER;
mutex_unlock(&genpd->lock);
ret = pm_genpd_poweron(link->master);
mutex_lock(&genpd->lock);
/*
* The "wait for parent" status is guaranteed not to change
* while the master is powering on.
*/
genpd->status = GPD_STATE_POWER_OFF;
wake_up_all(&genpd->status_wait_queue);
if (ret) {
genpd_sd_counter_dec(link->master);
goto err;
@@ -319,8 +255,7 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
goto err;
out:
genpd_set_active(genpd);
genpd->status = GPD_STATE_ACTIVE;
return 0;
err:
@@ -356,20 +291,18 @@ int pm_genpd_name_poweron(const char *domain_name)
return genpd ? pm_genpd_poweron(genpd) : -EINVAL;
}
static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd,
struct device *dev)
{
return GENPD_DEV_CALLBACK(genpd, int, start, dev);
}
static int genpd_save_dev(struct generic_pm_domain *genpd, struct device *dev)
{
return GENPD_DEV_TIMED_CALLBACK(genpd, int, save_state, dev,
save_state_latency_ns, "state save");
}
static int genpd_restore_dev(struct generic_pm_domain *genpd, struct device *dev)
static int genpd_restore_dev(struct generic_pm_domain *genpd,
struct device *dev, bool timed)
{
if (!timed)
return GENPD_DEV_CALLBACK(genpd, int, restore_state, dev);
return GENPD_DEV_TIMED_CALLBACK(genpd, int, restore_state, dev,
restore_state_latency_ns,
"state restore");
@@ -415,89 +348,6 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
}
/**
* __pm_genpd_save_device - Save the pre-suspend state of a device.
* @pdd: Domain data of the device to save the state of.
* @genpd: PM domain the device belongs to.
*/
static int __pm_genpd_save_device(struct pm_domain_data *pdd,
struct generic_pm_domain *genpd)
__releases(&genpd->lock) __acquires(&genpd->lock)
{
struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
struct device *dev = pdd->dev;
int ret = 0;
if (gpd_data->need_restore > 0)
return 0;
/*
* If the value of the need_restore flag is still unknown at this point,
* we trust that pm_genpd_poweroff() has verified that the device is
* already runtime PM suspended.
*/
if (gpd_data->need_restore < 0) {
gpd_data->need_restore = 1;
return 0;
}
mutex_unlock(&genpd->lock);
genpd_start_dev(genpd, dev);
ret = genpd_save_dev(genpd, dev);
genpd_stop_dev(genpd, dev);
mutex_lock(&genpd->lock);
if (!ret)
gpd_data->need_restore = 1;
return ret;
}
/**
* __pm_genpd_restore_device - Restore the pre-suspend state of a device.
* @pdd: Domain data of the device to restore the state of.
* @genpd: PM domain the device belongs to.
*/
static void __pm_genpd_restore_device(struct pm_domain_data *pdd,
struct generic_pm_domain *genpd)
__releases(&genpd->lock) __acquires(&genpd->lock)
{
struct generic_pm_domain_data *gpd_data = to_gpd_data(pdd);
struct device *dev = pdd->dev;
int need_restore = gpd_data->need_restore;
gpd_data->need_restore = 0;
mutex_unlock(&genpd->lock);
genpd_start_dev(genpd, dev);
/*
* Call genpd_restore_dev() for recently added devices too (need_restore
* is negative then).
*/
if (need_restore)
genpd_restore_dev(genpd, dev);
mutex_lock(&genpd->lock);
}
/**
* genpd_abort_poweroff - Check if a PM domain power off should be aborted.
* @genpd: PM domain to check.
*
* Return true if a PM domain's status changed to GPD_STATE_ACTIVE during
* a "power off" operation, which means that a "power on" has occured in the
* meantime, or if its resume_count field is different from zero, which means
* that one of its devices has been resumed in the meantime.
*/
static bool genpd_abort_poweroff(struct generic_pm_domain *genpd)
{
return genpd->status == GPD_STATE_WAIT_MASTER
|| genpd->status == GPD_STATE_ACTIVE || genpd->resume_count > 0;
}
/**
* genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff().
* @genpd: PM domait to power off.
@@ -515,34 +365,26 @@ static void genpd_queue_power_off_work(struct generic_pm_domain *genpd)
* @genpd: PM domain to power down.
*
* If all of the @genpd's devices have been suspended and all of its subdomains
* have been powered down, run the runtime suspend callbacks provided by all of
* the @genpd's devices' drivers and remove power from @genpd.
* have been powered down, remove power from @genpd.
*/
static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
__releases(&genpd->lock) __acquires(&genpd->lock)
{
struct pm_domain_data *pdd;
struct gpd_link *link;
unsigned int not_suspended;
int ret = 0;
unsigned int not_suspended = 0;
start:
/*
* Do not try to power off the domain in the following situations:
* (1) The domain is already in the "power off" state.
* (2) The domain is waiting for its master to power up.
* (3) One of the domain's devices is being resumed right now.
* (4) System suspend is in progress.
* (2) System suspend is in progress.
*/
if (genpd->status == GPD_STATE_POWER_OFF
|| genpd->status == GPD_STATE_WAIT_MASTER
|| genpd->resume_count > 0 || genpd->prepared_count > 0)
|| genpd->prepared_count > 0)
return 0;
if (atomic_read(&genpd->sd_count) > 0)
return -EBUSY;
not_suspended = 0;
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
enum pm_qos_flags_status stat;
@@ -560,41 +402,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
if (not_suspended > genpd->in_progress)
return -EBUSY;
if (genpd->poweroff_task) {
/*
* Another instance of pm_genpd_poweroff() is executing
* callbacks, so tell it to start over and return.
*/
genpd->status = GPD_STATE_REPEAT;
return 0;
}
if (genpd->gov && genpd->gov->power_down_ok) {
if (!genpd->gov->power_down_ok(&genpd->domain))
return -EAGAIN;
}
genpd->status = GPD_STATE_BUSY;
genpd->poweroff_task = current;
list_for_each_entry_reverse(pdd, &genpd->dev_list, list_node) {
ret = atomic_read(&genpd->sd_count) == 0 ?
__pm_genpd_save_device(pdd, genpd) : -EBUSY;
if (genpd_abort_poweroff(genpd))
goto out;
if (ret) {
genpd_set_active(genpd);
goto out;
}
if (genpd->status == GPD_STATE_REPEAT) {
genpd->poweroff_task = NULL;
goto start;
}
}
if (genpd->cpuidle_data) {
/*
* If cpuidle_data is set, cpuidle should turn the domain off
@@ -607,14 +419,14 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
cpuidle_pause_and_lock();
genpd->cpuidle_data->idle_state->disabled = false;
cpuidle_resume_and_unlock();
goto out;
return 0;
}
if (genpd->power_off) {
if (atomic_read(&genpd->sd_count) > 0) {
ret = -EBUSY;
goto out;
}
int ret;
if (atomic_read(&genpd->sd_count) > 0)
return -EBUSY;
/*
* If sd_count > 0 at this point, one of the subdomains hasn't
@@ -625,10 +437,8 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
* happen very often).
*/
ret = genpd_power_off(genpd, true);
if (ret == -EBUSY) {
genpd_set_active(genpd);
goto out;
}
if (ret)
return ret;
}
genpd->status = GPD_STATE_POWER_OFF;
@@ -638,10 +448,7 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
genpd_queue_power_off_work(link->master);
}
out:
genpd->poweroff_task = NULL;
wake_up_all(&genpd->status_wait_queue);
return ret;
return 0;
}
/**
@@ -654,9 +461,9 @@ static void genpd_power_off_work_fn(struct work_struct *work)
genpd = container_of(work, struct generic_pm_domain, power_off_work);
genpd_acquire_lock(genpd);
mutex_lock(&genpd->lock);
pm_genpd_poweroff(genpd);
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
}
/**
@@ -670,7 +477,6 @@ static void genpd_power_off_work_fn(struct work_struct *work)
static int pm_genpd_runtime_suspend(struct device *dev)
{
struct generic_pm_domain *genpd;
struct generic_pm_domain_data *gpd_data;
bool (*stop_ok)(struct device *__dev);
int ret;
@@ -684,10 +490,16 @@ static int pm_genpd_runtime_suspend(struct device *dev)
if (stop_ok && !stop_ok(dev))
return -EBUSY;
ret = genpd_stop_dev(genpd, dev);
ret = genpd_save_dev(genpd, dev);
if (ret)
return ret;
ret = genpd_stop_dev(genpd, dev);
if (ret) {
genpd_restore_dev(genpd, dev, true);
return ret;
}
/*
* If power.irq_safe is set, this routine will be run with interrupts
* off, so it can't use mutexes.
@@ -696,16 +508,6 @@ static int pm_genpd_runtime_suspend(struct device *dev)
return 0;
mutex_lock(&genpd->lock);
/*
* If we have an unknown state of the need_restore flag, it means none
* of the runtime PM callbacks has been invoked yet. Let's update the
* flag to reflect that the current state is active.
*/
gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
if (gpd_data->need_restore < 0)
gpd_data->need_restore = 0;
genpd->in_progress++;
pm_genpd_poweroff(genpd);
genpd->in_progress--;
@@ -725,8 +527,8 @@ static int pm_genpd_runtime_suspend(struct device *dev)
static int pm_genpd_runtime_resume(struct device *dev)
{
struct generic_pm_domain *genpd;
DEFINE_WAIT(wait);
int ret;
bool timed = true;
dev_dbg(dev, "%s()\n", __func__);
@@ -735,40 +537,22 @@ static int pm_genpd_runtime_resume(struct device *dev)
return -EINVAL;
/* If power.irq_safe, the PM domain is never powered off. */
if (dev->power.irq_safe)
return genpd_start_dev_no_timing(genpd, dev);
if (dev->power.irq_safe) {
timed = false;
goto out;
}
mutex_lock(&genpd->lock);
ret = __pm_genpd_poweron(genpd);
if (ret) {
mutex_unlock(&genpd->lock);
return ret;
}
genpd->status = GPD_STATE_BUSY;
genpd->resume_count++;
for (;;) {
prepare_to_wait(&genpd->status_wait_queue, &wait,
TASK_UNINTERRUPTIBLE);
/*
* If current is the powering off task, we have been called
* reentrantly from one of the device callbacks, so we should
* not wait.
*/
if (!genpd->poweroff_task || genpd->poweroff_task == current)
break;
mutex_unlock(&genpd->lock);
schedule();
mutex_lock(&genpd->lock);
}
finish_wait(&genpd->status_wait_queue, &wait);
__pm_genpd_restore_device(dev->power.subsys_data->domain_data, genpd);
genpd->resume_count--;
genpd_set_active(genpd);
wake_up_all(&genpd->status_wait_queue);
mutex_unlock(&genpd->lock);
if (ret)
return ret;
out:
genpd_start_dev(genpd, dev, timed);
genpd_restore_dev(genpd, dev, timed);
return 0;
}
@@ -883,7 +667,7 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd,
{
struct gpd_link *link;
if (genpd->status != GPD_STATE_POWER_OFF)
if (genpd->status == GPD_STATE_ACTIVE)
return;
list_for_each_entry(link, &genpd->slave_links, slave_node) {
@@ -960,14 +744,14 @@ static int pm_genpd_prepare(struct device *dev)
if (resume_needed(dev, genpd))
pm_runtime_resume(dev);
genpd_acquire_lock(genpd);
mutex_lock(&genpd->lock);
if (genpd->prepared_count++ == 0) {
genpd->suspended_count = 0;
genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
}
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
if (genpd->suspend_power_off) {
pm_runtime_put_noidle(dev);
@@ -1102,7 +886,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
pm_genpd_sync_poweron(genpd, true);
genpd->suspended_count--;
return genpd_start_dev(genpd, dev);
return genpd_start_dev(genpd, dev, true);
}
/**
@@ -1230,7 +1014,7 @@ static int pm_genpd_thaw_noirq(struct device *dev)
if (IS_ERR(genpd))
return -EINVAL;
return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev);
return genpd->suspend_power_off ? 0 : genpd_start_dev(genpd, dev, true);
}
/**
@@ -1324,7 +1108,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
pm_genpd_sync_poweron(genpd, true);
return genpd_start_dev(genpd, dev);
return genpd_start_dev(genpd, dev, true);
}
/**
@@ -1440,7 +1224,6 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
gpd_data->td = *td;
gpd_data->base.dev = dev;
gpd_data->need_restore = -1;
gpd_data->td.constraint_changed = true;
gpd_data->td.effective_constraint_ns = -1;
gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
@@ -1502,7 +1285,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
if (IS_ERR(gpd_data))
return PTR_ERR(gpd_data);
genpd_acquire_lock(genpd);
mutex_lock(&genpd->lock);
if (genpd->prepared_count > 0) {
ret = -EAGAIN;
@@ -1519,7 +1302,7 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
out:
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
if (ret)
genpd_free_dev_data(dev, gpd_data);
@@ -1563,7 +1346,7 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
gpd_data = to_gpd_data(pdd);
dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
genpd_acquire_lock(genpd);
mutex_lock(&genpd->lock);
if (genpd->prepared_count > 0) {
ret = -EAGAIN;
@@ -1578,14 +1361,14 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
list_del_init(&pdd->list_node);
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
genpd_free_dev_data(dev, gpd_data);
return 0;
out:
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
dev_pm_qos_add_notifier(dev, &gpd_data->nb);
return ret;
@@ -1606,17 +1389,9 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
|| genpd == subdomain)
return -EINVAL;
start:
genpd_acquire_lock(genpd);
mutex_lock(&genpd->lock);
mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
if (subdomain->status != GPD_STATE_POWER_OFF
&& subdomain->status != GPD_STATE_ACTIVE) {
mutex_unlock(&subdomain->lock);
genpd_release_lock(genpd);
goto start;
}
if (genpd->status == GPD_STATE_POWER_OFF
&& subdomain->status != GPD_STATE_POWER_OFF) {
ret = -EINVAL;
@@ -1644,7 +1419,7 @@ int pm_genpd_add_subdomain(struct generic_pm_domain *genpd,
out:
mutex_unlock(&subdomain->lock);
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
return ret;
}
@@ -1692,8 +1467,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(subdomain))
return -EINVAL;
start:
genpd_acquire_lock(genpd);
mutex_lock(&genpd->lock);
list_for_each_entry(link, &genpd->master_links, master_node) {
if (link->slave != subdomain)
@@ -1701,13 +1475,6 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
mutex_lock_nested(&subdomain->lock, SINGLE_DEPTH_NESTING);
if (subdomain->status != GPD_STATE_POWER_OFF
&& subdomain->status != GPD_STATE_ACTIVE) {
mutex_unlock(&subdomain->lock);
genpd_release_lock(genpd);
goto start;
}
list_del(&link->master_node);
list_del(&link->slave_node);
kfree(link);
@@ -1720,7 +1487,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
break;
}
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
return ret;
}
@@ -1744,7 +1511,7 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
if (IS_ERR_OR_NULL(genpd) || state < 0)
return -EINVAL;
genpd_acquire_lock(genpd);
mutex_lock(&genpd->lock);
if (genpd->cpuidle_data) {
ret = -EEXIST;
@@ -1775,7 +1542,7 @@ int pm_genpd_attach_cpuidle(struct generic_pm_domain *genpd, int state)
genpd_recalc_cpu_exit_latency(genpd);
out:
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
return ret;
err:
@@ -1812,7 +1579,7 @@ int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd)
if (IS_ERR_OR_NULL(genpd))
return -EINVAL;
genpd_acquire_lock(genpd);
mutex_lock(&genpd->lock);
cpuidle_data = genpd->cpuidle_data;
if (!cpuidle_data) {
@@ -1830,7 +1597,7 @@ int pm_genpd_detach_cpuidle(struct generic_pm_domain *genpd)
kfree(cpuidle_data);
out:
genpd_release_lock(genpd);
mutex_unlock(&genpd->lock);
return ret;
}
@@ -1912,9 +1679,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
genpd->in_progress = 0;
atomic_set(&genpd->sd_count, 0);
genpd->status = is_off ? GPD_STATE_POWER_OFF : GPD_STATE_ACTIVE;
init_waitqueue_head(&genpd->status_wait_queue);
genpd->poweroff_task = NULL;
genpd->resume_count = 0;
genpd->device_count = 0;
genpd->max_off_time_ns = -1;
genpd->max_off_time_changed = true;
@@ -1952,6 +1716,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
list_add(&genpd->gpd_list_node, &gpd_list);
mutex_unlock(&gpd_list_lock);
}
EXPORT_SYMBOL_GPL(pm_genpd_init);
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
/*
@@ -2125,7 +1890,7 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
/**
* genpd_dev_pm_detach - Detach a device from its PM domain.
* @dev: Device to attach.
* @dev: Device to detach.
* @power_off: Currently not used
*
* Try to locate a corresponding generic PM domain, which the device was
@@ -2183,7 +1948,10 @@ static void genpd_dev_pm_sync(struct device *dev)
* Both generic and legacy Samsung-specific DT bindings are supported to keep
* backwards compatibility with existing DTBs.
*
* Returns 0 on successfully attached PM domain or negative error code.
* Returns 0 on successfully attached PM domain or negative error code. Note
* that if a power-domain exists for the device, but it cannot be found or
* turned on, then return -EPROBE_DEFER to ensure that the device is not
* probed and to re-try again later.
*/
int genpd_dev_pm_attach(struct device *dev)
{
@@ -2220,7 +1988,7 @@ int genpd_dev_pm_attach(struct device *dev)
dev_dbg(dev, "%s() failed to find PM domain: %ld\n",
__func__, PTR_ERR(pd));
of_node_put(dev->of_node);
return PTR_ERR(pd);
return -EPROBE_DEFER;
}
dev_dbg(dev, "adding to PM domain %s\n", pd->name);
@@ -2238,14 +2006,15 @@ int genpd_dev_pm_attach(struct device *dev)
dev_err(dev, "failed to add to PM domain %s: %d",
pd->name, ret);
of_node_put(dev->of_node);
return ret;
goto out;
}
dev->pm_domain->detach = genpd_dev_pm_detach;
dev->pm_domain->sync = genpd_dev_pm_sync;
pm_genpd_poweron(pd);
ret = pm_genpd_poweron(pd);
return 0;
out:
return ret ? -EPROBE_DEFER : 0;
}
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
@@ -2293,9 +2062,6 @@ static int pm_genpd_summary_one(struct seq_file *s,
{
static const char * const status_lookup[] = {
[GPD_STATE_ACTIVE] = "on",
[GPD_STATE_WAIT_MASTER] = "wait-master",
[GPD_STATE_BUSY] = "busy",
[GPD_STATE_REPEAT] = "off-in-progress",
[GPD_STATE_POWER_OFF] = "off"
};
struct pm_domain_data *pm_data;
@@ -2309,7 +2075,7 @@ static int pm_genpd_summary_one(struct seq_file *s,
if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup)))
goto exit;
seq_printf(s, "%-30s %-15s ", genpd->name, status_lookup[genpd->status]);
seq_printf(s, "%-30s %-15s ", genpd->name, status_lookup[genpd->status]);
/*
* Modifications on the list require holding locks on both
@@ -2344,8 +2110,8 @@ static int pm_genpd_summary_show(struct seq_file *s, void *data)
struct generic_pm_domain *genpd;
int ret = 0;
seq_puts(s, " domain status slaves\n");
seq_puts(s, " /device runtime status\n");
seq_puts(s, "domain status slaves\n");
seq_puts(s, " /device runtime status\n");
seq_puts(s, "----------------------------------------------------------------------\n");
ret = mutex_lock_interruptible(&gpd_list_lock);

查看文件

@@ -1377,7 +1377,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (dev->power.direct_complete) {
if (pm_runtime_status_suspended(dev)) {
pm_runtime_disable(dev);
if (pm_runtime_suspended_if_enabled(dev))
if (pm_runtime_status_suspended(dev))
goto Complete;
pm_runtime_enable(dev);

檔案差異因為檔案過大而無法顯示 載入差異

查看文件

@@ -73,6 +73,8 @@ extern int pm_qos_sysfs_add_resume_latency(struct device *dev);
extern void pm_qos_sysfs_remove_resume_latency(struct device *dev);
extern int pm_qos_sysfs_add_flags(struct device *dev);
extern void pm_qos_sysfs_remove_flags(struct device *dev);
extern int pm_qos_sysfs_add_latency_tolerance(struct device *dev);
extern void pm_qos_sysfs_remove_latency_tolerance(struct device *dev);
#else /* CONFIG_PM */

查看文件

@@ -883,3 +883,40 @@ int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
mutex_unlock(&dev_pm_qos_mtx);
return ret;
}
/**
* dev_pm_qos_expose_latency_tolerance - Expose latency tolerance to userspace
* @dev: Device whose latency tolerance to expose
*/
int dev_pm_qos_expose_latency_tolerance(struct device *dev)
{
int ret;
if (!dev->power.set_latency_tolerance)
return -EINVAL;
mutex_lock(&dev_pm_qos_sysfs_mtx);
ret = pm_qos_sysfs_add_latency_tolerance(dev);
mutex_unlock(&dev_pm_qos_sysfs_mtx);
return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_tolerance);
/**
* dev_pm_qos_hide_latency_tolerance - Hide latency tolerance from userspace
* @dev: Device whose latency tolerance to hide
*/
void dev_pm_qos_hide_latency_tolerance(struct device *dev)
{
mutex_lock(&dev_pm_qos_sysfs_mtx);
pm_qos_sysfs_remove_latency_tolerance(dev);
mutex_unlock(&dev_pm_qos_sysfs_mtx);
/* Remove the request from user space now */
pm_runtime_get_sync(dev);
dev_pm_qos_update_user_latency_tolerance(dev,
PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT);
pm_runtime_put(dev);
}
EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_tolerance);

查看文件

@@ -738,6 +738,17 @@ void pm_qos_sysfs_remove_flags(struct device *dev)
sysfs_unmerge_group(&dev->kobj, &pm_qos_flags_attr_group);
}
int pm_qos_sysfs_add_latency_tolerance(struct device *dev)
{
return sysfs_merge_group(&dev->kobj,
&pm_qos_latency_tolerance_attr_group);
}
void pm_qos_sysfs_remove_latency_tolerance(struct device *dev)
{
sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group);
}
void rpm_sysfs_remove(struct device *dev)
{
sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group);

查看文件

@@ -27,9 +27,10 @@
*/
void device_add_property_set(struct device *dev, struct property_set *pset)
{
if (pset)
pset->fwnode.type = FWNODE_PDATA;
if (!pset)
return;
pset->fwnode.type = FWNODE_PDATA;
set_secondary_fwnode(dev, &pset->fwnode);
}
EXPORT_SYMBOL_GPL(device_add_property_set);
@@ -461,7 +462,8 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode,
return acpi_dev_prop_read(to_acpi_node(fwnode), propname,
DEV_PROP_STRING, val, 1);
return -ENXIO;
return pset_prop_read_array(to_pset(fwnode), propname,
DEV_PROP_STRING, val, 1);
}
EXPORT_SYMBOL_GPL(fwnode_property_read_string);