On 20-08-25, 13:58, Krishna Chaitanya Chundru wrote: > Some clients, such as PCIe, may operate at the same clock frequency > across different data rates by varying link width. In such cases, > frequency alone is not sufficient to uniquely identify an OPP. > To support these scenarios, introduce a new API > dev_pm_opp_find_key_exact() that allows OPP lookup with different > set of keys like freq, level & bandwidth. > > Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@xxxxxxxxxxxxxxxx> > --- > drivers/opp/core.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ > include/linux/pm_opp.h | 30 ++++++++++++++++ > 2 files changed, 127 insertions(+) Applied with this diff: diff --git a/drivers/opp/core.c b/drivers/opp/core.c index a36c3daac39c..bba4f7daff8c 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -476,7 +476,8 @@ static unsigned long _read_bw(struct dev_pm_opp *opp, int index) return opp->bandwidth[index].peak; } -static unsigned long _read_opp_key(struct dev_pm_opp *opp, int index, struct dev_pm_opp_key *key) +static unsigned long _read_opp_key(struct dev_pm_opp *opp, int index, + struct dev_pm_opp_key *key) { key->bw = opp->bandwidth ? opp->bandwidth[index].peak : 0; key->freq = opp->rates[index]; @@ -518,12 +519,13 @@ static bool _compare_floor(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp, return false; } -static bool _compare_opp_key_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp, - struct dev_pm_opp_key opp_key, struct dev_pm_opp_key key) +static bool _compare_opp_key_exact(struct dev_pm_opp **opp, + struct dev_pm_opp *temp_opp, struct dev_pm_opp_key *opp_key, + struct dev_pm_opp_key *key) { - bool level_match = (key.level == OPP_LEVEL_UNSET || opp_key.level == key.level); - bool freq_match = (key.freq == 0 || opp_key.freq == key.freq); - bool bw_match = (key.bw == 0 || opp_key.bw == key.bw); + bool level_match = (key->level == OPP_LEVEL_UNSET || opp_key->level == key->level); + bool freq_match = (key->freq == 0 || opp_key->freq == key->freq); + bool bw_match = (key->bw == 0 || opp_key->bw == key->bw); if (freq_match && level_match && bw_match) { *opp = temp_opp; @@ -570,7 +572,7 @@ static struct dev_pm_opp *_opp_table_find_opp_key(struct opp_table *opp_table, unsigned long (*read)(struct dev_pm_opp *opp, int index, struct dev_pm_opp_key *key), bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp, - struct dev_pm_opp_key opp_key, struct dev_pm_opp_key key), + struct dev_pm_opp_key *opp_key, struct dev_pm_opp_key *key), bool (*assert)(struct opp_table *opp_table, unsigned int index)) { struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); @@ -585,9 +587,8 @@ static struct dev_pm_opp *_opp_table_find_opp_key(struct opp_table *opp_table, list_for_each_entry(temp_opp, &opp_table->opp_list, node) { if (temp_opp->available == available) { read(temp_opp, 0, &temp_key); - if (compare(&opp, temp_opp, temp_key, *key)) { + if (compare(&opp, temp_opp, &temp_key, key)) { /* Increment the reference count of OPP */ - *key = temp_key; dev_pm_opp_get(opp); break; } @@ -689,20 +690,20 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact); /** - * dev_pm_opp_find_key_exact() - Search for an exact OPP key - * @dev: Device for which the OPP is being searched - * @key: OPP key to match - * @available: true/false - match for available OPP + * dev_pm_opp_find_key_exact() - Search for an OPP with exact key set + * @dev: Device for which the OPP is being searched + * @key: OPP key set to match + * @available: true/false - match for available OPP * - * Search for an exact match the OPP key in the OPP table. + * Search for an exact match of the key set in the OPP table. * - * Return: matching *opp, else returns ERR_PTR in case of error and should - * be using IS_ERR. Error return values can be: - * EINVAL: for bad pointer - * ERANGE: no match found for search - * ENODEV: if device not found in list of registered devices + * Return: A matching opp on success, else ERR_PTR in case of error. + * Possible error values: + * EINVAL: for bad pointers + * ERANGE: no match found for search + * ENODEV: if device not found in list of registered devices * - * Note: 'available' is a modifier for the search. If 'available'=true, + * Note: 'available' is a modifier for the search. If 'available' == true, * then the match is for exact matching key and is available in the stored * OPP table. If false, the match is for exact key which is not available. * @@ -713,7 +714,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact); * use. */ struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, - struct dev_pm_opp_key key, + struct dev_pm_opp_key *key, bool available) { struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev); @@ -724,8 +725,9 @@ struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, return ERR_CAST(opp_table); } - return _opp_table_find_opp_key(opp_table, &key, available, _read_opp_key, - _compare_opp_key_exact, assert_single_clk); + return _opp_table_find_opp_key(opp_table, key, available, + _read_opp_key, _compare_opp_key_exact, + assert_single_clk); } EXPORT_SYMBOL_GPL(dev_pm_opp_find_key_exact); diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 5d244bf97489..789406d95e69 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -151,7 +151,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, bool available); struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, - struct dev_pm_opp_key key, + struct dev_pm_opp_key *key, bool available); struct dev_pm_opp * @@ -313,7 +313,7 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, } static inline struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, - struct dev_pm_opp_key key, + struct dev_pm_opp_key *key, bool available) { return ERR_PTR(-EOPNOTSUPP); -- viresh