Skip to content

Commit

Permalink
Merge branches 'pm-core', 'pm-domains', 'pm-sleep', 'acpi-pm' and 'pm…
Browse files Browse the repository at this point in the history
…-cpuidle'

Merge changes in the PM core, system-wide PM infrastructure, generic
power domains (genpd) framework, ACPI PM infrastructure and cpuidle
for 4.19.

* pm-core:
  driver core: Add flag to autoremove device link on supplier unbind
  driver core: Rename flag AUTOREMOVE to AUTOREMOVE_CONSUMER

* pm-domains:
  PM / Domains: Introduce dev_pm_domain_attach_by_name()
  PM / Domains: Introduce option to attach a device by name to genpd
  PM / Domains: dt: Add a power-domain-names property

* pm-sleep:
  PM / reboot: Eliminate race between reboot and suspend
  PM / hibernate: Mark expected switch fall-through
  x86/power/hibernate_64: Remove VLA usage
  PM / hibernate: cast PAGE_SIZE to int when comparing with error code

* acpi-pm:
  ACPI / PM: save NVS memory for ASUS 1025C laptop
  ACPI / PM: Default to s2idle in all machines supporting LP S0

* pm-cpuidle:
  ARM: cpuidle: silence error on driver registration failure
  • Loading branch information
rafaeljw committed Aug 14, 2018
6 parents 9b7c19e + 1689cac + 27dceb8 + 55f2503 + 231f941 + 818489e commit 17bc343
Show file tree
Hide file tree
Showing 25 changed files with 186 additions and 89 deletions.
8 changes: 8 additions & 0 deletions Documentation/devicetree/bindings/power/power_domain.txt
Original file line number Diff line number Diff line change
Expand Up @@ -114,18 +114,26 @@ Required properties:
- power-domains : A list of PM domain specifiers, as defined by bindings of
the power controller that is the PM domain provider.

Optional properties:
- power-domain-names : A list of power domain name strings sorted in the same
order as the power-domains property. Consumers drivers will use
power-domain-names to match power domains with power-domains
specifiers.

Example:

leaky-device@12350000 {
compatible = "foo,i-leak-current";
reg = <0x12350000 0x1000>;
power-domains = <&power 0>;
power-domain-names = "io";
};

leaky-device@12351000 {
compatible = "foo,i-leak-current";
reg = <0x12351000 0x1000>;
power-domains = <&power 0>, <&power 1> ;
power-domain-names = "io", "clk";
};

The first example above defines a typical PM domain consumer device, which is
Expand Down
12 changes: 8 additions & 4 deletions Documentation/driver-api/device_link.rst
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,14 @@ integration is desired.
Two other flags are specifically targeted at use cases where the device
link is added from the consumer's ``->probe`` callback: ``DL_FLAG_RPM_ACTIVE``
can be specified to runtime resume the supplier upon addition of the
device link. ``DL_FLAG_AUTOREMOVE`` causes the device link to be automatically
purged when the consumer fails to probe or later unbinds. This obviates
the need to explicitly delete the link in the ``->remove`` callback or in
the error path of the ``->probe`` callback.
device link. ``DL_FLAG_AUTOREMOVE_CONSUMER`` causes the device link to be
automatically purged when the consumer fails to probe or later unbinds.
This obviates the need to explicitly delete the link in the ``->remove``
callback or in the error path of the ``->probe`` callback.

Similarly, when the device link is added from supplier's ``->probe`` callback,
``DL_FLAG_AUTOREMOVE_SUPPLIER`` causes the device link to be automatically
purged when the supplier fails to probe or later unbinds.

Limitations
===========
Expand Down
12 changes: 6 additions & 6 deletions Documentation/power/freezing-of-tasks.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,26 +204,26 @@ VI. Are there any precautions to be taken to prevent freezing failures?

Yes, there are.

First of all, grabbing the 'pm_mutex' lock to mutually exclude a piece of code
First of all, grabbing the 'system_transition_mutex' lock to mutually exclude a piece of code
from system-wide sleep such as suspend/hibernation is not encouraged.
If possible, that piece of code must instead hook onto the suspend/hibernation
notifiers to achieve mutual exclusion. Look at the CPU-Hotplug code
(kernel/cpu.c) for an example.

However, if that is not feasible, and grabbing 'pm_mutex' is deemed necessary,
it is strongly discouraged to directly call mutex_[un]lock(&pm_mutex) since
However, if that is not feasible, and grabbing 'system_transition_mutex' is deemed necessary,
it is strongly discouraged to directly call mutex_[un]lock(&system_transition_mutex) since
that could lead to freezing failures, because if the suspend/hibernate code
successfully acquired the 'pm_mutex' lock, and hence that other entity failed
successfully acquired the 'system_transition_mutex' lock, and hence that other entity failed
to acquire the lock, then that task would get blocked in TASK_UNINTERRUPTIBLE
state. As a consequence, the freezer would not be able to freeze that task,
leading to freezing failure.

However, the [un]lock_system_sleep() APIs are safe to use in this scenario,
since they ask the freezer to skip freezing this task, since it is anyway
"frozen enough" as it is blocked on 'pm_mutex', which will be released
"frozen enough" as it is blocked on 'system_transition_mutex', which will be released
only after the entire suspend/hibernation sequence is complete.
So, to summarize, use [un]lock_system_sleep() instead of directly using
mutex_[un]lock(&pm_mutex). That would prevent freezing failures.
mutex_[un]lock(&system_transition_mutex). That would prevent freezing failures.

V. Miscellaneous
/sys/power/pm_freeze_timeout controls how long it will cost at most to freeze
Expand Down
6 changes: 3 additions & 3 deletions Documentation/power/suspend-and-cpuhotplug.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ More details follow:
sysfs file
|
v
Acquire pm_mutex lock
Acquire system_transition_mutex lock
|
v
Send PM_SUSPEND_PREPARE
Expand Down Expand Up @@ -96,10 +96,10 @@ execution during resume):

* thaw tasks
* send PM_POST_SUSPEND notifications
* Release pm_mutex lock.
* Release system_transition_mutex lock.


It is to be noted here that the pm_mutex lock is acquired at the very
It is to be noted here that the system_transition_mutex lock is acquired at the very
beginning, when we are just starting out to suspend, and then released only
after the entire cycle is complete (i.e., suspend + resume).

Expand Down
36 changes: 21 additions & 15 deletions arch/x86/power/hibernate_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -233,29 +233,35 @@ struct restore_data_record {
*/
static int get_e820_md5(struct e820_table *table, void *buf)
{
struct scatterlist sg;
struct crypto_ahash *tfm;
struct crypto_shash *tfm;
struct shash_desc *desc;
int size;
int ret = 0;

tfm = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC);
tfm = crypto_alloc_shash("md5", 0, 0);
if (IS_ERR(tfm))
return -ENOMEM;

{
AHASH_REQUEST_ON_STACK(req, tfm);
size = offsetof(struct e820_table, entries) + sizeof(struct e820_entry) * table->nr_entries;
ahash_request_set_tfm(req, tfm);
sg_init_one(&sg, (u8 *)table, size);
ahash_request_set_callback(req, 0, NULL, NULL);
ahash_request_set_crypt(req, &sg, buf, size);

if (crypto_ahash_digest(req))
ret = -EINVAL;
ahash_request_zero(req);
desc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm),
GFP_KERNEL);
if (!desc) {
ret = -ENOMEM;
goto free_tfm;
}
crypto_free_ahash(tfm);

desc->tfm = tfm;
desc->flags = 0;

size = offsetof(struct e820_table, entries) +
sizeof(struct e820_entry) * table->nr_entries;

if (crypto_shash_digest(desc, (u8 *)table, size, buf))
ret = -EINVAL;

kzfree(desc);

free_tfm:
crypto_free_shash(tfm);
return ret;
}

Expand Down
30 changes: 16 additions & 14 deletions drivers/acpi/sleep.c
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,14 @@ static const struct dmi_system_id acpisleep_dmi_table[] __initconst = {
DMI_MATCH(DMI_PRODUCT_NAME, "K54HR"),
},
},
{
.callback = init_nvs_save_s3,
.ident = "Asus 1025C",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_PRODUCT_NAME, "1025C"),
},
},
/*
* https://bugzilla.kernel.org/show_bug.cgi?id=189431
* Lenovo G50-45 is a platform later than 2012, but needs nvs memory
Expand Down Expand Up @@ -718,9 +726,6 @@ static const struct acpi_device_id lps0_device_ids[] = {
#define ACPI_LPS0_ENTRY 5
#define ACPI_LPS0_EXIT 6

#define ACPI_LPS0_SCREEN_MASK ((1 << ACPI_LPS0_SCREEN_OFF) | (1 << ACPI_LPS0_SCREEN_ON))
#define ACPI_LPS0_PLATFORM_MASK ((1 << ACPI_LPS0_ENTRY) | (1 << ACPI_LPS0_EXIT))

static acpi_handle lps0_device_handle;
static guid_t lps0_dsm_guid;
static char lps0_dsm_func_mask;
Expand Down Expand Up @@ -924,17 +929,14 @@ static int lps0_device_attach(struct acpi_device *adev,
if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
char bitmask = *(char *)out_obj->buffer.pointer;

if ((bitmask & ACPI_LPS0_PLATFORM_MASK) == ACPI_LPS0_PLATFORM_MASK ||
(bitmask & ACPI_LPS0_SCREEN_MASK) == ACPI_LPS0_SCREEN_MASK) {
lps0_dsm_func_mask = bitmask;
lps0_device_handle = adev->handle;
/*
* Use suspend-to-idle by default if the default
* suspend mode was not set from the command line.
*/
if (mem_sleep_default > PM_SUSPEND_MEM)
mem_sleep_current = PM_SUSPEND_TO_IDLE;
}
lps0_dsm_func_mask = bitmask;
lps0_device_handle = adev->handle;
/*
* Use suspend-to-idle by default if the default
* suspend mode was not set from the command line.
*/
if (mem_sleep_default > PM_SUSPEND_MEM)
mem_sleep_current = PM_SUSPEND_TO_IDLE;

acpi_handle_debug(adev->handle, "_DSM function mask: 0x%x\n",
bitmask);
Expand Down
25 changes: 18 additions & 7 deletions drivers/base/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,10 @@ void device_pm_move_to_tail(struct device *dev)
* of the link. If DL_FLAG_PM_RUNTIME is not set, DL_FLAG_RPM_ACTIVE will be
* ignored.
*
* If the DL_FLAG_AUTOREMOVE is set, the link will be removed automatically
* when the consumer device driver unbinds from it. The combination of both
* DL_FLAG_AUTOREMOVE and DL_FLAG_STATELESS set is invalid and will cause NULL
* to be returned.
* If the DL_FLAG_AUTOREMOVE_CONSUMER is set, the link will be removed
* automatically when the consumer device driver unbinds from it.
* The combination of both DL_FLAG_AUTOREMOVE_CONSUMER and DL_FLAG_STATELESS
* set is invalid and will cause NULL to be returned.
*
* A side effect of the link creation is re-ordering of dpm_list and the
* devices_kset list by moving the consumer device and all devices depending
Expand All @@ -198,7 +198,8 @@ struct device_link *device_link_add(struct device *consumer,
struct device_link *link;

if (!consumer || !supplier ||
((flags & DL_FLAG_STATELESS) && (flags & DL_FLAG_AUTOREMOVE)))
((flags & DL_FLAG_STATELESS) &&
(flags & DL_FLAG_AUTOREMOVE_CONSUMER)))
return NULL;

device_links_write_lock();
Expand Down Expand Up @@ -479,7 +480,7 @@ static void __device_links_no_driver(struct device *dev)
if (link->flags & DL_FLAG_STATELESS)
continue;

if (link->flags & DL_FLAG_AUTOREMOVE)
if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER)
kref_put(&link->kref, __device_link_del);
else if (link->status != DL_STATE_SUPPLIER_UNBIND)
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
Expand Down Expand Up @@ -515,8 +516,18 @@ void device_links_driver_cleanup(struct device *dev)
if (link->flags & DL_FLAG_STATELESS)
continue;

WARN_ON(link->flags & DL_FLAG_AUTOREMOVE);
WARN_ON(link->flags & DL_FLAG_AUTOREMOVE_CONSUMER);
WARN_ON(link->status != DL_STATE_SUPPLIER_UNBIND);

/*
* autoremove the links between this @dev and its consumer
* devices that are not active, i.e. where the link state
* has moved to DL_STATE_SUPPLIER_UNBIND.
*/
if (link->status == DL_STATE_SUPPLIER_UNBIND &&
link->flags & DL_FLAG_AUTOREMOVE_SUPPLIER)
kref_put(&link->kref, __device_link_del);

WRITE_ONCE(link->status, DL_STATE_DORMANT);
}

Expand Down
17 changes: 17 additions & 0 deletions drivers/base/power/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,23 @@ struct device *dev_pm_domain_attach_by_id(struct device *dev,
}
EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_id);

/**
* dev_pm_domain_attach_by_name - Associate a device with one of its PM domains.
* @dev: The device used to lookup the PM domain.
* @name: The name of the PM domain.
*
* For a detailed function description, see dev_pm_domain_attach_by_id().
*/
struct device *dev_pm_domain_attach_by_name(struct device *dev,
char *name)
{
if (dev->pm_domain)
return ERR_PTR(-EEXIST);

return genpd_dev_pm_attach_by_name(dev, name);
}
EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_name);

/**
* dev_pm_domain_detach - Detach a device from its PM domain.
* @dev: Device to detach.
Expand Down
24 changes: 24 additions & 0 deletions drivers/base/power/domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -2374,6 +2374,30 @@ struct device *genpd_dev_pm_attach_by_id(struct device *dev,
}
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach_by_id);

/**
* genpd_dev_pm_attach_by_name - Associate a device with one of its PM domains.
* @dev: The device used to lookup the PM domain.
* @name: The name of the PM domain.
*
* Parse device's OF node to find a PM domain specifier using the
* power-domain-names DT property. For further description see
* genpd_dev_pm_attach_by_id().
*/
struct device *genpd_dev_pm_attach_by_name(struct device *dev, char *name)
{
int index;

if (!dev->of_node)
return NULL;

index = of_property_match_string(dev->of_node, "power-domain-names",
name);
if (index < 0)
return NULL;

return genpd_dev_pm_attach_by_id(dev, index);
}

static const struct of_device_id idle_state_match[] = {
{ .compatible = "domain-idle-state", },
{ }
Expand Down
3 changes: 2 additions & 1 deletion drivers/cpuidle/cpuidle-arm.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ static int __init arm_idle_init_cpu(int cpu)

ret = cpuidle_register_driver(drv);
if (ret) {
pr_err("Failed to register cpuidle driver\n");
if (ret != -EBUSY)
pr_err("Failed to register cpuidle driver\n");
goto out_kfree_drv;
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/tegra/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2312,7 +2312,7 @@ static int tegra_dc_couple(struct tegra_dc *dc)
* POWER_CONTROL registers during CRTC enabling.
*/
if (dc->soc->coupled_pm && dc->pipe == 1) {
u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE;
u32 flags = DL_FLAG_PM_RUNTIME | DL_FLAG_AUTOREMOVE_CONSUMER;
struct device_link *link;
struct device *partner;

Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/ipu-v3/ipu-pre.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ ipu_pre_lookup_by_phandle(struct device *dev, const char *name, int index)
list_for_each_entry(pre, &ipu_pre_list, list) {
if (pre_node == pre->dev->of_node) {
mutex_unlock(&ipu_pre_list_mutex);
device_link_add(dev, pre->dev, DL_FLAG_AUTOREMOVE);
device_link_add(dev, pre->dev,
DL_FLAG_AUTOREMOVE_CONSUMER);
of_node_put(pre_node);
return pre;
}
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/ipu-v3/ipu-prg.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ ipu_prg_lookup_by_phandle(struct device *dev, const char *name, int ipu_id)
list_for_each_entry(prg, &ipu_prg_list, list) {
if (prg_node == prg->dev->of_node) {
mutex_unlock(&ipu_prg_list_mutex);
device_link_add(dev, prg->dev, DL_FLAG_AUTOREMOVE);
device_link_add(dev, prg->dev,
DL_FLAG_AUTOREMOVE_CONSUMER);
prg->id = ipu_id;
of_node_put(prg_node);
return prg;
Expand Down
2 changes: 1 addition & 1 deletion drivers/soc/imx/gpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ static int imx_pgc_power_domain_probe(struct platform_device *pdev)
goto genpd_err;
}

device_link_add(dev, dev->parent, DL_FLAG_AUTOREMOVE);
device_link_add(dev, dev->parent, DL_FLAG_AUTOREMOVE_CONSUMER);

return 0;

Expand Down
14 changes: 8 additions & 6 deletions include/linux/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
* @num_vf: Called to find out how many virtual functions a device on this
* bus supports.
* @dma_configure: Called to setup DMA configuration on a device on
this bus.
* this bus.
* @pm: Power management operations of this bus, callback the specific
* device driver's pm-ops.
* @iommu_ops: IOMMU specific operations for this bus, used to attach IOMMU
Expand Down Expand Up @@ -784,14 +784,16 @@ enum device_link_state {
* Device link flags.
*
* STATELESS: The core won't track the presence of supplier/consumer drivers.
* AUTOREMOVE: Remove this link automatically on consumer driver unbind.
* AUTOREMOVE_CONSUMER: Remove the link automatically on consumer driver unbind.
* PM_RUNTIME: If set, the runtime PM framework will use this link.
* RPM_ACTIVE: Run pm_runtime_get_sync() on the supplier during link creation.
* AUTOREMOVE_SUPPLIER: Remove the link automatically on supplier driver unbind.
*/
#define DL_FLAG_STATELESS BIT(0)
#define DL_FLAG_AUTOREMOVE BIT(1)
#define DL_FLAG_PM_RUNTIME BIT(2)
#define DL_FLAG_RPM_ACTIVE BIT(3)
#define DL_FLAG_STATELESS BIT(0)
#define DL_FLAG_AUTOREMOVE_CONSUMER BIT(1)
#define DL_FLAG_PM_RUNTIME BIT(2)
#define DL_FLAG_RPM_ACTIVE BIT(3)
#define DL_FLAG_AUTOREMOVE_SUPPLIER BIT(4)

/**
* struct device_link - Device link representation.
Expand Down
Loading

0 comments on commit 17bc343

Please sign in to comment.