Skip to content

Commit 3665672

Browse files
committed
OPP: Rework _set_required_devs() to manage a single device per call
JIRA: https://issues.redhat.com/browse/RHEL-81536 commit 0e8158b Author: Ulf Hansson <ulf.hansson@linaro.org> Date: Wed Oct 2 14:22:24 2024 +0200 At this point there are no consumer drivers that makes use of _set_required_devs(), hence it should be straightforward to rework the code to enable it to better integrate with the PM domain attach procedure. During attach, one device at the time is being hooked up to its corresponding PM domain. Therefore, let's update the _set_required_devs() to align to this behaviour, allowing callers to fill out one required_dev per call. Subsequent changes starts making use of this. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> Acked-by: Viresh Kumar <viresh.kumar@linaro.org> Link: https://lore.kernel.org/r/20241002122232.194245-4-ulf.hansson@linaro.org Signed-off-by: Mark Langsdorf <mlangsdo@redhat.com>
1 parent 7b9d621 commit 3665672

File tree

3 files changed

+65
-33
lines changed

3 files changed

+65
-33
lines changed

drivers/opp/core.c

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,47 +2509,73 @@ static int _opp_attach_genpd(struct opp_table *opp_table, struct device *dev,
25092509

25102510
}
25112511

2512-
static int _opp_set_required_devs(struct opp_table *opp_table,
2513-
struct device *dev,
2514-
struct device **required_devs)
2512+
static int _opp_set_required_dev(struct opp_table *opp_table,
2513+
struct device *dev,
2514+
struct device *required_dev,
2515+
unsigned int index)
25152516
{
2516-
int i;
2517+
struct opp_table *required_table, *pd_table;
2518+
struct device *gdev;
25172519

2518-
if (!opp_table->required_devs) {
2520+
/* Genpd core takes care of propagation to parent genpd */
2521+
if (opp_table->is_genpd) {
2522+
dev_err(dev, "%s: Operation not supported for genpds\n", __func__);
2523+
return -EOPNOTSUPP;
2524+
}
2525+
2526+
if (index >= opp_table->required_opp_count) {
25192527
dev_err(dev, "Required OPPs not available, can't set required devs\n");
25202528
return -EINVAL;
25212529
}
25222530

2523-
/* Another device that shares the OPP table has set the required devs ? */
2524-
if (opp_table->required_devs[0])
2525-
return 0;
2531+
required_table = opp_table->required_opp_tables[index];
2532+
if (IS_ERR(required_table)) {
2533+
dev_err(dev, "Missing OPP table, unable to set the required devs\n");
2534+
return -ENODEV;
2535+
}
25262536

2527-
for (i = 0; i < opp_table->required_opp_count; i++) {
2528-
/* Genpd core takes care of propagation to parent genpd */
2529-
if (required_devs[i] && opp_table->is_genpd &&
2530-
opp_table->required_opp_tables[i]->is_genpd) {
2531-
dev_err(dev, "%s: Operation not supported for genpds\n", __func__);
2532-
return -EOPNOTSUPP;
2537+
/*
2538+
* The required_opp_tables parsing is not perfect, as the OPP core does
2539+
* the parsing solely based on the DT node pointers. The core sets the
2540+
* required_opp_tables entry to the first OPP table in the "opp_tables"
2541+
* list, that matches with the node pointer.
2542+
*
2543+
* If the target DT OPP table is used by multiple devices and they all
2544+
* create separate instances of 'struct opp_table' from it, then it is
2545+
* possible that the required_opp_tables entry may be set to the
2546+
* incorrect sibling device.
2547+
*
2548+
* Cross check it again and fix if required.
2549+
*/
2550+
gdev = dev_to_genpd_dev(required_dev);
2551+
if (IS_ERR(gdev))
2552+
return PTR_ERR(gdev);
2553+
2554+
pd_table = _find_opp_table(gdev);
2555+
if (!IS_ERR(pd_table)) {
2556+
if (pd_table != required_table) {
2557+
dev_pm_opp_put_opp_table(required_table);
2558+
opp_table->required_opp_tables[index] = pd_table;
2559+
} else {
2560+
dev_pm_opp_put_opp_table(pd_table);
25332561
}
2534-
2535-
opp_table->required_devs[i] = required_devs[i];
25362562
}
25372563

2564+
opp_table->required_devs[index] = required_dev;
25382565
return 0;
25392566
}
25402567

2541-
static void _opp_put_required_devs(struct opp_table *opp_table)
2568+
static void _opp_put_required_dev(struct opp_table *opp_table,
2569+
unsigned int index)
25422570
{
2543-
int i;
2544-
2545-
for (i = 0; i < opp_table->required_opp_count; i++)
2546-
opp_table->required_devs[i] = NULL;
2571+
opp_table->required_devs[index] = NULL;
25472572
}
25482573

25492574
static void _opp_clear_config(struct opp_config_data *data)
25502575
{
2551-
if (data->flags & OPP_CONFIG_REQUIRED_DEVS)
2552-
_opp_put_required_devs(data->opp_table);
2576+
if (data->flags & OPP_CONFIG_REQUIRED_DEV)
2577+
_opp_put_required_dev(data->opp_table,
2578+
data->required_dev_index);
25532579
else if (data->flags & OPP_CONFIG_GENPD)
25542580
_opp_detach_genpd(data->opp_table);
25552581

@@ -2666,7 +2692,7 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
26662692

26672693
/* Attach genpds */
26682694
if (config->genpd_names) {
2669-
if (config->required_devs) {
2695+
if (config->required_dev) {
26702696
ret = -EINVAL;
26712697
goto err;
26722698
}
@@ -2677,13 +2703,15 @@ int dev_pm_opp_set_config(struct device *dev, struct dev_pm_opp_config *config)
26772703
goto err;
26782704

26792705
data->flags |= OPP_CONFIG_GENPD;
2680-
} else if (config->required_devs) {
2681-
ret = _opp_set_required_devs(opp_table, dev,
2682-
config->required_devs);
2706+
} else if (config->required_dev) {
2707+
ret = _opp_set_required_dev(opp_table, dev,
2708+
config->required_dev,
2709+
config->required_dev_index);
26832710
if (ret)
26842711
goto err;
26852712

2686-
data->flags |= OPP_CONFIG_REQUIRED_DEVS;
2713+
data->required_dev_index = config->required_dev_index;
2714+
data->flags |= OPP_CONFIG_REQUIRED_DEV;
26872715
}
26882716

26892717
ret = xa_alloc(&opp_configs, &id, data, XA_LIMIT(1, INT_MAX),

drivers/opp/opp.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,21 @@ extern struct list_head opp_tables;
3535
#define OPP_CONFIG_PROP_NAME BIT(3)
3636
#define OPP_CONFIG_SUPPORTED_HW BIT(4)
3737
#define OPP_CONFIG_GENPD BIT(5)
38-
#define OPP_CONFIG_REQUIRED_DEVS BIT(6)
38+
#define OPP_CONFIG_REQUIRED_DEV BIT(6)
3939

4040
/**
4141
* struct opp_config_data - data for set config operations
4242
* @opp_table: OPP table
4343
* @flags: OPP config flags
44+
* @required_dev_index: The position in the array of required_devs
4445
*
4546
* This structure stores the OPP config information for each OPP table
4647
* configuration by the callers.
4748
*/
4849
struct opp_config_data {
4950
struct opp_table *opp_table;
5051
unsigned int flags;
52+
unsigned int required_dev_index;
5153
};
5254

5355
/*

include/linux/pm_opp.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ typedef int (*config_clks_t)(struct device *dev, struct opp_table *opp_table,
7474
* @supported_hw_count: Number of elements in the array.
7575
* @regulator_names: Array of pointers to the names of the regulator, NULL terminated.
7676
* @genpd_names: Null terminated array of pointers containing names of genpd to
77-
* attach. Mutually exclusive with required_devs.
77+
* attach. Mutually exclusive with required_dev.
7878
* @virt_devs: Pointer to return the array of genpd virtual devices. Mutually
79-
* exclusive with required_devs.
80-
* @required_devs: Required OPP devices. Mutually exclusive with genpd_names/virt_devs.
79+
* exclusive with required_dev.
80+
* @required_dev: Required OPP device. Mutually exclusive with genpd_names/virt_devs.
81+
* @required_dev_index: The index of the required OPP for the @required_dev.
8182
*
8283
* This structure contains platform specific OPP configurations for the device.
8384
*/
@@ -92,7 +93,8 @@ struct dev_pm_opp_config {
9293
const char * const *regulator_names;
9394
const char * const *genpd_names;
9495
struct device ***virt_devs;
95-
struct device **required_devs;
96+
struct device *required_dev;
97+
unsigned int required_dev_index;
9698
};
9799

98100
#define OPP_LEVEL_UNSET U32_MAX

0 commit comments

Comments
 (0)