Skip to content

Commit 899f445

Browse files
Sibi Sankarstorulf
authored andcommitted
pmdomain: core: Add GENPD_FLAG_DEV_NAME_FW flag
Introduce GENPD_FLAG_DEV_NAME_FW flag which instructs genpd to generate an unique device name using ida. It is aimed to be used by genpd providers which derive their names directly from FW making them susceptible to debugfs node creation failures. Reported-by: Johan Hovold <[email protected]> Closes: https://lore.kernel.org/lkml/[email protected]/ Fixes: 718072c ("PM: domains: create debugfs nodes when adding power domains") Suggested-by: Ulf Hansson <[email protected]> Suggested-by: Dmitry Baryshkov <[email protected]> Signed-off-by: Sibi Sankar <[email protected]> Cc: [email protected] Message-ID: <[email protected]> Signed-off-by: Ulf Hansson <[email protected]>
1 parent 7738568 commit 899f445

File tree

2 files changed

+40
-15
lines changed

2 files changed

+40
-15
lines changed

drivers/pmdomain/core.c

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define pr_fmt(fmt) "PM: " fmt
88

99
#include <linux/delay.h>
10+
#include <linux/idr.h>
1011
#include <linux/kernel.h>
1112
#include <linux/io.h>
1213
#include <linux/platform_device.h>
@@ -23,6 +24,9 @@
2324
#include <linux/cpu.h>
2425
#include <linux/debugfs.h>
2526

27+
/* Provides a unique ID for each genpd device */
28+
static DEFINE_IDA(genpd_ida);
29+
2630
#define GENPD_RETRY_MAX_MS 250 /* Approximate */
2731

2832
#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
@@ -171,6 +175,7 @@ static const struct genpd_lock_ops genpd_raw_spin_ops = {
171175
#define genpd_is_cpu_domain(genpd) (genpd->flags & GENPD_FLAG_CPU_DOMAIN)
172176
#define genpd_is_rpm_always_on(genpd) (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON)
173177
#define genpd_is_opp_table_fw(genpd) (genpd->flags & GENPD_FLAG_OPP_TABLE_FW)
178+
#define genpd_is_dev_name_fw(genpd) (genpd->flags & GENPD_FLAG_DEV_NAME_FW)
174179

175180
static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,
176181
const struct generic_pm_domain *genpd)
@@ -189,7 +194,7 @@ static inline bool irq_safe_dev_in_sleep_domain(struct device *dev,
189194

190195
if (ret)
191196
dev_warn_once(dev, "PM domain %s will not be powered off\n",
192-
genpd->name);
197+
dev_name(&genpd->dev));
193198

194199
return ret;
195200
}
@@ -274,7 +279,7 @@ static void genpd_debug_remove(struct generic_pm_domain *genpd)
274279
if (!genpd_debugfs_dir)
275280
return;
276281

277-
debugfs_lookup_and_remove(genpd->name, genpd_debugfs_dir);
282+
debugfs_lookup_and_remove(dev_name(&genpd->dev), genpd_debugfs_dir);
278283
}
279284

280285
static void genpd_update_accounting(struct generic_pm_domain *genpd)
@@ -731,7 +736,7 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
731736
genpd->states[state_idx].power_on_latency_ns = elapsed_ns;
732737
genpd->gd->max_off_time_changed = true;
733738
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
734-
genpd->name, "on", elapsed_ns);
739+
dev_name(&genpd->dev), "on", elapsed_ns);
735740

736741
out:
737742
raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_ON, NULL);
@@ -782,7 +787,7 @@ static int _genpd_power_off(struct generic_pm_domain *genpd, bool timed)
782787
genpd->states[state_idx].power_off_latency_ns = elapsed_ns;
783788
genpd->gd->max_off_time_changed = true;
784789
pr_debug("%s: Power-%s latency exceeded, new value %lld ns\n",
785-
genpd->name, "off", elapsed_ns);
790+
dev_name(&genpd->dev), "off", elapsed_ns);
786791

787792
out:
788793
raw_notifier_call_chain(&genpd->power_notifiers, GENPD_NOTIFY_OFF,
@@ -1940,7 +1945,7 @@ int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb)
19401945

19411946
if (ret) {
19421947
dev_warn(dev, "failed to add notifier for PM domain %s\n",
1943-
genpd->name);
1948+
dev_name(&genpd->dev));
19441949
return ret;
19451950
}
19461951

@@ -1987,7 +1992,7 @@ int dev_pm_genpd_remove_notifier(struct device *dev)
19871992

19881993
if (ret) {
19891994
dev_warn(dev, "failed to remove notifier for PM domain %s\n",
1990-
genpd->name);
1995+
dev_name(&genpd->dev));
19911996
return ret;
19921997
}
19931998

@@ -2013,7 +2018,7 @@ static int genpd_add_subdomain(struct generic_pm_domain *genpd,
20132018
*/
20142019
if (!genpd_is_irq_safe(genpd) && genpd_is_irq_safe(subdomain)) {
20152020
WARN(1, "Parent %s of subdomain %s must be IRQ safe\n",
2016-
genpd->name, subdomain->name);
2021+
dev_name(&genpd->dev), subdomain->name);
20172022
return -EINVAL;
20182023
}
20192024

@@ -2088,7 +2093,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
20882093

20892094
if (!list_empty(&subdomain->parent_links) || subdomain->device_count) {
20902095
pr_warn("%s: unable to remove subdomain %s\n",
2091-
genpd->name, subdomain->name);
2096+
dev_name(&genpd->dev), subdomain->name);
20922097
ret = -EBUSY;
20932098
goto out;
20942099
}
@@ -2225,6 +2230,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
22252230
genpd->status = is_off ? GENPD_STATE_OFF : GENPD_STATE_ON;
22262231
genpd->device_count = 0;
22272232
genpd->provider = NULL;
2233+
genpd->device_id = -ENXIO;
22282234
genpd->has_provider = false;
22292235
genpd->accounting_time = ktime_get_mono_fast_ns();
22302236
genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
@@ -2265,7 +2271,18 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
22652271
return ret;
22662272

22672273
device_initialize(&genpd->dev);
2268-
dev_set_name(&genpd->dev, "%s", genpd->name);
2274+
2275+
if (!genpd_is_dev_name_fw(genpd)) {
2276+
dev_set_name(&genpd->dev, "%s", genpd->name);
2277+
} else {
2278+
ret = ida_alloc(&genpd_ida, GFP_KERNEL);
2279+
if (ret < 0) {
2280+
put_device(&genpd->dev);
2281+
return ret;
2282+
}
2283+
genpd->device_id = ret;
2284+
dev_set_name(&genpd->dev, "%s_%u", genpd->name, genpd->device_id);
2285+
}
22692286

22702287
mutex_lock(&gpd_list_lock);
22712288
list_add(&genpd->gpd_list_node, &gpd_list);
@@ -2287,13 +2304,13 @@ static int genpd_remove(struct generic_pm_domain *genpd)
22872304

22882305
if (genpd->has_provider) {
22892306
genpd_unlock(genpd);
2290-
pr_err("Provider present, unable to remove %s\n", genpd->name);
2307+
pr_err("Provider present, unable to remove %s\n", dev_name(&genpd->dev));
22912308
return -EBUSY;
22922309
}
22932310

22942311
if (!list_empty(&genpd->parent_links) || genpd->device_count) {
22952312
genpd_unlock(genpd);
2296-
pr_err("%s: unable to remove %s\n", __func__, genpd->name);
2313+
pr_err("%s: unable to remove %s\n", __func__, dev_name(&genpd->dev));
22972314
return -EBUSY;
22982315
}
22992316

@@ -2307,9 +2324,11 @@ static int genpd_remove(struct generic_pm_domain *genpd)
23072324
genpd_unlock(genpd);
23082325
genpd_debug_remove(genpd);
23092326
cancel_work_sync(&genpd->power_off_work);
2327+
if (genpd->device_id != -ENXIO)
2328+
ida_free(&genpd_ida, genpd->device_id);
23102329
genpd_free_data(genpd);
23112330

2312-
pr_debug("%s: removed %s\n", __func__, genpd->name);
2331+
pr_debug("%s: removed %s\n", __func__, dev_name(&genpd->dev));
23132332

23142333
return 0;
23152334
}
@@ -3272,12 +3291,12 @@ static int genpd_summary_one(struct seq_file *s,
32723291
else
32733292
snprintf(state, sizeof(state), "%s",
32743293
status_lookup[genpd->status]);
3275-
seq_printf(s, "%-30s %-30s %u", genpd->name, state, genpd->performance_state);
3294+
seq_printf(s, "%-30s %-30s %u", dev_name(&genpd->dev), state, genpd->performance_state);
32763295

32773296
/*
32783297
* Modifications on the list require holding locks on both
32793298
* parent and child, so we are safe.
3280-
* Also genpd->name is immutable.
3299+
* Also the device name is immutable.
32813300
*/
32823301
list_for_each_entry(link, &genpd->parent_links, parent_node) {
32833302
if (list_is_first(&link->parent_node, &genpd->parent_links))
@@ -3502,7 +3521,7 @@ static void genpd_debug_add(struct generic_pm_domain *genpd)
35023521
if (!genpd_debugfs_dir)
35033522
return;
35043523

3505-
d = debugfs_create_dir(genpd->name, genpd_debugfs_dir);
3524+
d = debugfs_create_dir(dev_name(&genpd->dev), genpd_debugfs_dir);
35063525

35073526
debugfs_create_file("current_state", 0444,
35083527
d, genpd, &status_fops);

include/linux/pm_domain.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ struct dev_pm_domain_list {
9292
* GENPD_FLAG_OPP_TABLE_FW: The genpd provider supports performance states,
9393
* but its corresponding OPP tables are not
9494
* described in DT, but are given directly by FW.
95+
*
96+
* GENPD_FLAG_DEV_NAME_FW: Instructs genpd to generate an unique device name
97+
* using ida. It is used by genpd providers which
98+
* get their genpd-names directly from FW.
9599
*/
96100
#define GENPD_FLAG_PM_CLK (1U << 0)
97101
#define GENPD_FLAG_IRQ_SAFE (1U << 1)
@@ -101,6 +105,7 @@ struct dev_pm_domain_list {
101105
#define GENPD_FLAG_RPM_ALWAYS_ON (1U << 5)
102106
#define GENPD_FLAG_MIN_RESIDENCY (1U << 6)
103107
#define GENPD_FLAG_OPP_TABLE_FW (1U << 7)
108+
#define GENPD_FLAG_DEV_NAME_FW (1U << 8)
104109

105110
enum gpd_status {
106111
GENPD_STATE_ON = 0, /* PM domain is on */
@@ -163,6 +168,7 @@ struct generic_pm_domain {
163168
atomic_t sd_count; /* Number of subdomains with power "on" */
164169
enum gpd_status status; /* Current state of the domain */
165170
unsigned int device_count; /* Number of devices */
171+
unsigned int device_id; /* unique device id */
166172
unsigned int suspended_count; /* System suspend device counter */
167173
unsigned int prepared_count; /* Suspend counter of prepared devices */
168174
unsigned int performance_state; /* Aggregated max performance state */

0 commit comments

Comments
 (0)