Skip to content

Commit 1b597e1

Browse files
committed
Merge tag 'pmdomain-v6.12-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm
Pull pmdomain fixes from Ulf Hansson: "pmdomain core: - Add GENPD_FLAG_DEV_NAME_FW flag to generate unique names pmdomain providers: - arm: Use FLAG_DEV_NAME_FW to ensure unique names - imx93-blk-ctrl: Fix the remove path arm_scmi/qcom-cpucp: - Report duplicate OPPs as firmware bugs for arm_scmi - Skip OPP duplicates for arm_scmi - Mark the qcom-cpucp mailbox irq with IRQF_NO_SUSPEND flag" * tag 'pmdomain-v6.12-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/linux-pm: mailbox: qcom-cpucp: Mark the irq with IRQF_NO_SUSPEND flag firmware: arm_scmi: Report duplicate opps as firmware bugs firmware: arm_scmi: Skip opp duplicates pmdomain: imx93-blk-ctrl: correct remove path pmdomain: arm: Use FLAG_DEV_NAME_FW to ensure unique names pmdomain: core: Add GENPD_FLAG_DEV_NAME_FW flag
2 parents aa35f54 + d2fab3f commit 1b597e1

File tree

6 files changed

+78
-30
lines changed

6 files changed

+78
-30
lines changed

drivers/firmware/arm_scmi/perf.c

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ static int iter_perf_levels_update_state(struct scmi_iterator_state *st,
373373
return 0;
374374
}
375375

376-
static inline void
376+
static inline int
377377
process_response_opp(struct device *dev, struct perf_dom_info *dom,
378378
struct scmi_opp *opp, unsigned int loop_idx,
379379
const struct scmi_msg_resp_perf_describe_levels *r)
@@ -386,12 +386,16 @@ process_response_opp(struct device *dev, struct perf_dom_info *dom,
386386
le16_to_cpu(r->opp[loop_idx].transition_latency_us);
387387

388388
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
389-
if (ret)
390-
dev_warn(dev, "Failed to add opps_by_lvl at %d for %s - ret:%d\n",
389+
if (ret) {
390+
dev_info(dev, FW_BUG "Failed to add opps_by_lvl at %d for %s - ret:%d\n",
391391
opp->perf, dom->info.name, ret);
392+
return ret;
393+
}
394+
395+
return 0;
392396
}
393397

394-
static inline void
398+
static inline int
395399
process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
396400
struct scmi_opp *opp, unsigned int loop_idx,
397401
const struct scmi_msg_resp_perf_describe_levels_v4 *r)
@@ -404,9 +408,11 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
404408
le16_to_cpu(r->opp[loop_idx].transition_latency_us);
405409

406410
ret = xa_insert(&dom->opps_by_lvl, opp->perf, opp, GFP_KERNEL);
407-
if (ret)
408-
dev_warn(dev, "Failed to add opps_by_lvl at %d for %s - ret:%d\n",
411+
if (ret) {
412+
dev_info(dev, FW_BUG "Failed to add opps_by_lvl at %d for %s - ret:%d\n",
409413
opp->perf, dom->info.name, ret);
414+
return ret;
415+
}
410416

411417
/* Note that PERF v4 reports always five 32-bit words */
412418
opp->indicative_freq = le32_to_cpu(r->opp[loop_idx].indicative_freq);
@@ -415,30 +421,44 @@ process_response_opp_v4(struct device *dev, struct perf_dom_info *dom,
415421

416422
ret = xa_insert(&dom->opps_by_idx, opp->level_index, opp,
417423
GFP_KERNEL);
418-
if (ret)
424+
if (ret) {
419425
dev_warn(dev,
420426
"Failed to add opps_by_idx at %d for %s - ret:%d\n",
421427
opp->level_index, dom->info.name, ret);
422428

429+
/* Cleanup by_lvl too */
430+
xa_erase(&dom->opps_by_lvl, opp->perf);
431+
432+
return ret;
433+
}
434+
423435
hash_add(dom->opps_by_freq, &opp->hash, opp->indicative_freq);
424436
}
437+
438+
return 0;
425439
}
426440

427441
static int
428442
iter_perf_levels_process_response(const struct scmi_protocol_handle *ph,
429443
const void *response,
430444
struct scmi_iterator_state *st, void *priv)
431445
{
446+
int ret;
432447
struct scmi_opp *opp;
433448
struct scmi_perf_ipriv *p = priv;
434449

435-
opp = &p->perf_dom->opp[st->desc_index + st->loop_idx];
450+
opp = &p->perf_dom->opp[p->perf_dom->opp_count];
436451
if (PROTOCOL_REV_MAJOR(p->version) <= 0x3)
437-
process_response_opp(ph->dev, p->perf_dom, opp, st->loop_idx,
438-
response);
452+
ret = process_response_opp(ph->dev, p->perf_dom, opp,
453+
st->loop_idx, response);
439454
else
440-
process_response_opp_v4(ph->dev, p->perf_dom, opp, st->loop_idx,
441-
response);
455+
ret = process_response_opp_v4(ph->dev, p->perf_dom, opp,
456+
st->loop_idx, response);
457+
458+
/* Skip BAD duplicates received from firmware */
459+
if (ret)
460+
return ret == -EBUSY ? 0 : ret;
461+
442462
p->perf_dom->opp_count++;
443463

444464
dev_dbg(ph->dev, "Level %d Power %d Latency %dus Ifreq %d Index %d\n",

drivers/mailbox/qcom-cpucp-mbox.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ static int qcom_cpucp_mbox_probe(struct platform_device *pdev)
138138
return irq;
139139

140140
ret = devm_request_irq(dev, irq, qcom_cpucp_mbox_irq_fn,
141-
IRQF_TRIGGER_HIGH, "apss_cpucp_mbox", cpucp);
141+
IRQF_TRIGGER_HIGH | IRQF_NO_SUSPEND, "apss_cpucp_mbox", cpucp);
142142
if (ret < 0)
143143
return dev_err_probe(dev, ret, "Failed to register irq: %d\n", irq);
144144

drivers/pmdomain/arm/scmi_perf_domain.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ static int scmi_perf_domain_probe(struct scmi_device *sdev)
125125
scmi_pd->ph = ph;
126126
scmi_pd->genpd.name = scmi_pd->info->name;
127127
scmi_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON |
128-
GENPD_FLAG_OPP_TABLE_FW;
128+
GENPD_FLAG_OPP_TABLE_FW |
129+
GENPD_FLAG_DEV_NAME_FW;
129130
scmi_pd->genpd.set_performance_state = scmi_pd_set_perf_state;
130131
scmi_pd->genpd.attach_dev = scmi_pd_attach_dev;
131132
scmi_pd->genpd.detach_dev = scmi_pd_detach_dev;

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);

drivers/pmdomain/imx/imx93-blk-ctrl.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,9 @@ static void imx93_blk_ctrl_remove(struct platform_device *pdev)
313313

314314
of_genpd_del_provider(pdev->dev.of_node);
315315

316-
for (i = 0; bc->onecell_data.num_domains; i++) {
316+
pm_runtime_disable(&pdev->dev);
317+
318+
for (i = 0; i < bc->onecell_data.num_domains; i++) {
317319
struct imx93_blk_ctrl_domain *domain = &bc->domains[i];
318320

319321
pm_genpd_remove(&domain->genpd);

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)