Merge branches 'pm-domains' and 'pm-tools'
Additional updates of the generic power domains (genpd) framework (support for devices attached to multiple domains) and the cpupower utility (minor fixes) for 4.18-rc1. * pm-domains: PM / Domains: Add dev_pm_domain_attach_by_id() to manage multi PM domains PM / Domains: Add support for multi PM domains per device to genpd PM / Domains: Split genpd_dev_pm_attach() PM / Domains: Don't attach devices in genpd with multi PM domains PM / Domains: dt: Allow power-domain property to be a list of specifiers * pm-tools: cpupower : Fix header name to read idle state name cpupower: fix spelling mistake: "logilename" -> "logfilename"
This commit is contained in:
@@ -116,14 +116,51 @@ int dev_pm_domain_attach(struct device *dev, bool power_on)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_domain_attach);
|
||||
|
||||
/**
|
||||
* dev_pm_domain_attach_by_id - Associate a device with one of its PM domains.
|
||||
* @dev: The device used to lookup the PM domain.
|
||||
* @index: The index of the PM domain.
|
||||
*
|
||||
* As @dev may only be attached to a single PM domain, the backend PM domain
|
||||
* provider creates a virtual device to attach instead. If attachment succeeds,
|
||||
* the ->detach() callback in the struct dev_pm_domain are assigned by the
|
||||
* corresponding backend attach function, as to deal with detaching of the
|
||||
* created virtual device.
|
||||
*
|
||||
* This function should typically be invoked by a driver during the probe phase,
|
||||
* in case its device requires power management through multiple PM domains. The
|
||||
* driver may benefit from using the received device, to configure device-links
|
||||
* towards its original device. Depending on the use-case and if needed, the
|
||||
* links may be dynamically changed by the driver, which allows it to control
|
||||
* the power to the PM domains independently from each other.
|
||||
*
|
||||
* Callers must ensure proper synchronization of this function with power
|
||||
* management callbacks.
|
||||
*
|
||||
* Returns the virtual created device when successfully attached to its PM
|
||||
* domain, NULL in case @dev don't need a PM domain, else an ERR_PTR().
|
||||
* Note that, to detach the returned virtual device, the driver shall call
|
||||
* dev_pm_domain_detach() on it, typically during the remove phase.
|
||||
*/
|
||||
struct device *dev_pm_domain_attach_by_id(struct device *dev,
|
||||
unsigned int index)
|
||||
{
|
||||
if (dev->pm_domain)
|
||||
return ERR_PTR(-EEXIST);
|
||||
|
||||
return genpd_dev_pm_attach_by_id(dev, index);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_domain_attach_by_id);
|
||||
|
||||
/**
|
||||
* dev_pm_domain_detach - Detach a device from its PM domain.
|
||||
* @dev: Device to detach.
|
||||
* @power_off: Used to indicate whether we should power off the device.
|
||||
*
|
||||
* This functions will reverse the actions from dev_pm_domain_attach() and thus
|
||||
* try to detach the @dev from its PM domain. Typically it should be invoked
|
||||
* from subsystem level code during the remove phase.
|
||||
* This functions will reverse the actions from dev_pm_domain_attach() and
|
||||
* dev_pm_domain_attach_by_id(), thus it detaches @dev from its PM domain.
|
||||
* Typically it should be invoked during the remove phase, either from
|
||||
* subsystem level code or from drivers.
|
||||
*
|
||||
* Callers must ensure proper synchronization of this function with power
|
||||
* management callbacks.
|
||||
|
@@ -2171,6 +2171,15 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_remove_last);
|
||||
|
||||
static void genpd_release_dev(struct device *dev)
|
||||
{
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct bus_type genpd_bus_type = {
|
||||
.name = "genpd",
|
||||
};
|
||||
|
||||
/**
|
||||
* genpd_dev_pm_detach - Detach a device from its PM domain.
|
||||
* @dev: Device to detach.
|
||||
@@ -2208,6 +2217,10 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
|
||||
|
||||
/* Check if PM domain can be powered off after removing this device. */
|
||||
genpd_queue_power_off_work(pd);
|
||||
|
||||
/* Unregister the device if it was created by genpd. */
|
||||
if (dev->bus == &genpd_bus_type)
|
||||
device_unregister(dev);
|
||||
}
|
||||
|
||||
static void genpd_dev_pm_sync(struct device *dev)
|
||||
@@ -2221,32 +2234,17 @@ static void genpd_dev_pm_sync(struct device *dev)
|
||||
genpd_queue_power_off_work(pd);
|
||||
}
|
||||
|
||||
/**
|
||||
* genpd_dev_pm_attach - Attach a device to its PM domain using DT.
|
||||
* @dev: Device to attach.
|
||||
*
|
||||
* Parse device's OF node to find a PM domain specifier. If such is found,
|
||||
* attaches the device to retrieved pm_domain ops.
|
||||
*
|
||||
* Returns 1 on successfully attached PM domain, 0 when the device don't need a
|
||||
* PM domain or a negative error code in case of failures. 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)
|
||||
static int __genpd_dev_pm_attach(struct device *dev, struct device_node *np,
|
||||
unsigned int index)
|
||||
{
|
||||
struct of_phandle_args pd_args;
|
||||
struct generic_pm_domain *pd;
|
||||
int ret;
|
||||
|
||||
if (!dev->of_node)
|
||||
return 0;
|
||||
|
||||
ret = of_parse_phandle_with_args(dev->of_node, "power-domains",
|
||||
"#power-domain-cells", 0, &pd_args);
|
||||
ret = of_parse_phandle_with_args(np, "power-domains",
|
||||
"#power-domain-cells", index, &pd_args);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
return ret;
|
||||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
pd = genpd_get_from_provider(&pd_args);
|
||||
@@ -2282,8 +2280,98 @@ int genpd_dev_pm_attach(struct device *dev)
|
||||
|
||||
return ret ? -EPROBE_DEFER : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* genpd_dev_pm_attach - Attach a device to its PM domain using DT.
|
||||
* @dev: Device to attach.
|
||||
*
|
||||
* Parse device's OF node to find a PM domain specifier. If such is found,
|
||||
* attaches the device to retrieved pm_domain ops.
|
||||
*
|
||||
* Returns 1 on successfully attached PM domain, 0 when the device don't need a
|
||||
* PM domain or when multiple power-domains exists for it, else a 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)
|
||||
{
|
||||
if (!dev->of_node)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Devices with multiple PM domains must be attached separately, as we
|
||||
* can only attach one PM domain per device.
|
||||
*/
|
||||
if (of_count_phandle_with_args(dev->of_node, "power-domains",
|
||||
"#power-domain-cells") != 1)
|
||||
return 0;
|
||||
|
||||
return __genpd_dev_pm_attach(dev, dev->of_node, 0);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
|
||||
|
||||
/**
|
||||
* genpd_dev_pm_attach_by_id - Associate a device with one of its PM domains.
|
||||
* @dev: The device used to lookup the PM domain.
|
||||
* @index: The index of the PM domain.
|
||||
*
|
||||
* Parse device's OF node to find a PM domain specifier at the provided @index.
|
||||
* If such is found, creates a virtual device and attaches it to the retrieved
|
||||
* pm_domain ops. To deal with detaching of the virtual device, the ->detach()
|
||||
* callback in the struct dev_pm_domain are assigned to genpd_dev_pm_detach().
|
||||
*
|
||||
* Returns the created virtual device if successfully attached PM domain, NULL
|
||||
* when the device don't need a PM domain, else an ERR_PTR() in case of
|
||||
* failures. If a power-domain exists for the device, but cannot be found or
|
||||
* turned on, then ERR_PTR(-EPROBE_DEFER) is returned to ensure that the device
|
||||
* is not probed and to re-try again later.
|
||||
*/
|
||||
struct device *genpd_dev_pm_attach_by_id(struct device *dev,
|
||||
unsigned int index)
|
||||
{
|
||||
struct device *genpd_dev;
|
||||
int num_domains;
|
||||
int ret;
|
||||
|
||||
if (!dev->of_node)
|
||||
return NULL;
|
||||
|
||||
/* Deal only with devices using multiple PM domains. */
|
||||
num_domains = of_count_phandle_with_args(dev->of_node, "power-domains",
|
||||
"#power-domain-cells");
|
||||
if (num_domains < 2 || index >= num_domains)
|
||||
return NULL;
|
||||
|
||||
/* Allocate and register device on the genpd bus. */
|
||||
genpd_dev = kzalloc(sizeof(*genpd_dev), GFP_KERNEL);
|
||||
if (!genpd_dev)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dev_set_name(genpd_dev, "genpd:%u:%s", index, dev_name(dev));
|
||||
genpd_dev->bus = &genpd_bus_type;
|
||||
genpd_dev->release = genpd_release_dev;
|
||||
|
||||
ret = device_register(genpd_dev);
|
||||
if (ret) {
|
||||
kfree(genpd_dev);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/* Try to attach the device to the PM domain at the specified index. */
|
||||
ret = __genpd_dev_pm_attach(genpd_dev, dev->of_node, index);
|
||||
if (ret < 1) {
|
||||
device_unregister(genpd_dev);
|
||||
return ret ? ERR_PTR(ret) : NULL;
|
||||
}
|
||||
|
||||
pm_runtime_set_active(genpd_dev);
|
||||
pm_runtime_enable(genpd_dev);
|
||||
|
||||
return genpd_dev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach_by_id);
|
||||
|
||||
static const struct of_device_id idle_state_match[] = {
|
||||
{ .compatible = "domain-idle-state", },
|
||||
{ }
|
||||
@@ -2443,6 +2531,12 @@ unlock:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_genpd_opp_to_performance_state);
|
||||
|
||||
static int __init genpd_bus_init(void)
|
||||
{
|
||||
return bus_register(&genpd_bus_type);
|
||||
}
|
||||
core_initcall(genpd_bus_init);
|
||||
|
||||
#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user