mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-18 11:16:42 +07:00
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:
commit
6a900f884e
@ -111,8 +111,8 @@ Example 3:
|
||||
==PM domain consumers==
|
||||
|
||||
Required properties:
|
||||
- power-domains : A phandle and PM domain specifier as defined by bindings of
|
||||
the power controller specified by phandle.
|
||||
- power-domains : A list of PM domain specifiers, as defined by bindings of
|
||||
the power controller that is the PM domain provider.
|
||||
|
||||
Example:
|
||||
|
||||
@ -122,9 +122,18 @@ Example:
|
||||
power-domains = <&power 0>;
|
||||
};
|
||||
|
||||
The node above defines a typical PM domain consumer device, which is located
|
||||
inside a PM domain with index 0 of a power controller represented by a node
|
||||
with the label "power".
|
||||
leaky-device@12351000 {
|
||||
compatible = "foo,i-leak-current";
|
||||
reg = <0x12351000 0x1000>;
|
||||
power-domains = <&power 0>, <&power 1> ;
|
||||
};
|
||||
|
||||
The first example above defines a typical PM domain consumer device, which is
|
||||
located inside a PM domain with index 0 of a power controller represented by a
|
||||
node with the label "power".
|
||||
In the second example the consumer device are partitioned across two PM domains,
|
||||
the first with index 0 and the second with index 1, of a power controller that
|
||||
is represented by a node with the label "power.
|
||||
|
||||
Optional properties:
|
||||
- required-opps: This contains phandle to an OPP node in another device's OPP
|
||||
|
@ -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 @@ unsigned int of_genpd_opp_to_performance_state(struct device *dev,
|
||||
}
|
||||
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 */
|
||||
|
||||
|
||||
|
@ -237,6 +237,8 @@ unsigned int of_genpd_opp_to_performance_state(struct device *dev,
|
||||
struct device_node *opp_node);
|
||||
|
||||
int genpd_dev_pm_attach(struct device *dev);
|
||||
struct device *genpd_dev_pm_attach_by_id(struct device *dev,
|
||||
unsigned int index);
|
||||
#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */
|
||||
static inline int of_genpd_add_provider_simple(struct device_node *np,
|
||||
struct generic_pm_domain *genpd)
|
||||
@ -282,6 +284,12 @@ static inline int genpd_dev_pm_attach(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct device *genpd_dev_pm_attach_by_id(struct device *dev,
|
||||
unsigned int index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline
|
||||
struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
|
||||
{
|
||||
@ -291,6 +299,8 @@ struct generic_pm_domain *of_genpd_remove_last(struct device_node *np)
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int dev_pm_domain_attach(struct device *dev, bool power_on);
|
||||
struct device *dev_pm_domain_attach_by_id(struct device *dev,
|
||||
unsigned int index);
|
||||
void dev_pm_domain_detach(struct device *dev, bool power_off);
|
||||
void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd);
|
||||
#else
|
||||
@ -298,6 +308,11 @@ static inline int dev_pm_domain_attach(struct device *dev, bool power_on)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline struct device *dev_pm_domain_attach_by_id(struct device *dev,
|
||||
unsigned int index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {}
|
||||
static inline void dev_pm_domain_set(struct device *dev,
|
||||
struct dev_pm_domain *pd) {}
|
||||
|
@ -104,7 +104,7 @@ FILE *prepare_output(const char *dirname)
|
||||
dirname, time(NULL));
|
||||
}
|
||||
|
||||
dprintf("logilename: %s\n", filename);
|
||||
dprintf("logfilename: %s\n", filename);
|
||||
|
||||
output = fopen(filename, "w+");
|
||||
if (output == NULL) {
|
||||
|
@ -126,6 +126,20 @@ void fix_up_intel_idle_driver_name(char *tmp, int num)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __powerpc__
|
||||
void map_power_idle_state_name(char *tmp)
|
||||
{
|
||||
if (!strncmp(tmp, "stop0_lite", CSTATE_NAME_LEN))
|
||||
strcpy(tmp, "stop0L");
|
||||
else if (!strncmp(tmp, "stop1_lite", CSTATE_NAME_LEN))
|
||||
strcpy(tmp, "stop1L");
|
||||
else if (!strncmp(tmp, "stop2_lite", CSTATE_NAME_LEN))
|
||||
strcpy(tmp, "stop2L");
|
||||
}
|
||||
#else
|
||||
void map_power_idle_state_name(char *tmp) { }
|
||||
#endif
|
||||
|
||||
static struct cpuidle_monitor *cpuidle_register(void)
|
||||
{
|
||||
int num;
|
||||
@ -145,6 +159,7 @@ static struct cpuidle_monitor *cpuidle_register(void)
|
||||
if (tmp == NULL)
|
||||
continue;
|
||||
|
||||
map_power_idle_state_name(tmp);
|
||||
fix_up_intel_idle_driver_name(tmp, num);
|
||||
strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1);
|
||||
free(tmp);
|
||||
|
@ -70,36 +70,43 @@ void print_n_spaces(int n)
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
/* size of s must be at least n + 1 */
|
||||
/*s is filled with left and right spaces
|
||||
*to make its length atleast n+1
|
||||
*/
|
||||
int fill_string_with_spaces(char *s, int n)
|
||||
{
|
||||
char *temp;
|
||||
int len = strlen(s);
|
||||
if (len > n)
|
||||
|
||||
if (len >= n)
|
||||
return -1;
|
||||
|
||||
temp = malloc(sizeof(char) * (n+1));
|
||||
for (; len < n; len++)
|
||||
s[len] = ' ';
|
||||
s[len] = '\0';
|
||||
snprintf(temp, n+1, " %s", s);
|
||||
strcpy(s, temp);
|
||||
free(temp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define MAX_COL_WIDTH 6
|
||||
void print_header(int topology_depth)
|
||||
{
|
||||
int unsigned mon;
|
||||
int state, need_len;
|
||||
cstate_t s;
|
||||
char buf[128] = "";
|
||||
int percent_width = 4;
|
||||
|
||||
fill_string_with_spaces(buf, topology_depth * 5 - 1);
|
||||
printf("%s|", buf);
|
||||
|
||||
for (mon = 0; mon < avail_monitors; mon++) {
|
||||
need_len = monitors[mon]->hw_states_num * (percent_width + 3)
|
||||
need_len = monitors[mon]->hw_states_num * (MAX_COL_WIDTH + 1)
|
||||
- 1;
|
||||
if (mon != 0) {
|
||||
printf("|| ");
|
||||
need_len--;
|
||||
}
|
||||
if (mon != 0)
|
||||
printf("||");
|
||||
sprintf(buf, "%s", monitors[mon]->name);
|
||||
fill_string_with_spaces(buf, need_len);
|
||||
printf("%s", buf);
|
||||
@ -107,23 +114,21 @@ void print_header(int topology_depth)
|
||||
printf("\n");
|
||||
|
||||
if (topology_depth > 2)
|
||||
printf("PKG |");
|
||||
printf(" PKG|");
|
||||
if (topology_depth > 1)
|
||||
printf("CORE|");
|
||||
if (topology_depth > 0)
|
||||
printf("CPU |");
|
||||
printf(" CPU|");
|
||||
|
||||
for (mon = 0; mon < avail_monitors; mon++) {
|
||||
if (mon != 0)
|
||||
printf("|| ");
|
||||
else
|
||||
printf(" ");
|
||||
printf("||");
|
||||
for (state = 0; state < monitors[mon]->hw_states_num; state++) {
|
||||
if (state != 0)
|
||||
printf(" | ");
|
||||
printf("|");
|
||||
s = monitors[mon]->hw_states[state];
|
||||
sprintf(buf, "%s", s.name);
|
||||
fill_string_with_spaces(buf, percent_width);
|
||||
fill_string_with_spaces(buf, MAX_COL_WIDTH);
|
||||
printf("%s", buf);
|
||||
}
|
||||
printf(" ");
|
||||
|
@ -15,7 +15,16 @@
|
||||
|
||||
#define MONITORS_MAX 20
|
||||
#define MONITOR_NAME_LEN 20
|
||||
|
||||
/* CSTATE_NAME_LEN is limited by header field width defined
|
||||
* in cpupower-monitor.c. Header field width is defined to be
|
||||
* sum of percent width and two spaces for padding.
|
||||
*/
|
||||
#ifdef __powerpc__
|
||||
#define CSTATE_NAME_LEN 7
|
||||
#else
|
||||
#define CSTATE_NAME_LEN 5
|
||||
#endif
|
||||
#define CSTATE_DESC_LEN 60
|
||||
|
||||
int cpu_count;
|
||||
|
Loading…
Reference in New Issue
Block a user