mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2026-01-27 12:47:24 +01:00
OPP updates for 6.18
- Add support to find OPP for a set of keys (Krishna Chaitanya Chundru). - Minor optimization to OPP Rust implementation (Onur Özkan). -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEx73Crsp7f6M6scA70rkcPK6BEhwFAmi5LbAACgkQ0rkcPK6B EhxcTRAAhecgcxZo7kGK4xbj/QzflGTqfNGeJ93mShTBPmJt+Rjjme14HdI2sNHS PW6Zu84IFKWS2H9CVM72JVCq1sGnX6a+E3ciTAMC1PKXoN7UWx1jHxw2+xx55dJc 4gK146md14Ec8llhCf2oaRfhRbcHhs6v1l/4WgD2MSsEuKEyf/E7oj+RALe2+fSc gCgfKjlX+JPyuMeMVqB7XkjtZ9RPrtEz2x9f1F5yD3CgZxfhH/9qvby4CLgPkF7j AjjF+zE6YlfUr720h1fnXhk3YE7CE/66bwukyTXLTnjz6S/mE/oFAWjganUBV5DC 88S7FlkFyMHKV/WcMYqlU+8trcT51be4dQxzrCZm+DGBlrH9wKyYXi50VSMnpokp YDZgIZKzbejBBXnXYy9vfQ6qIgn2Q+zyYa2EJBjNTjsUtR9OlLP+EBlshLrdcNLz QhTLGbqE+B1UXcxpdCnAswLay1HR3uaDQegTcFTpKYx90b533zo0JAU3nQy3Se+c xLtSbSV7nUDOKXserCSK06rPvpOYbDf6OMIrYn54Lq6oIIdoQhYeXmaUjX3/OSQ9 WI2YBeUVrscEHKw2oOB7CQak8bOzfkqy1A0TS93j/xNa+yLs7YZ+qnDGULDQadmG JJ6cWG0sVR0VWg4WLP1qAm7/I/673qLtNQ4Oc5Q5Igedbh1XjuU= =sHvS -----END PGP SIGNATURE----- Merge tag 'opp-updates-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm Merge OPP (operating performance points) updates for 6.18 from Viresh Kumar: "- Add support to find OPP for a set of keys (Krishna Chaitanya Chundru). - Minor optimization to OPP Rust implementation (Onur Özkan)." * tag 'opp-updates-6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/vireshk/pm: OPP: Add support to find OPP for a set of keys rust: opp: use to_result for error handling
This commit is contained in:
commit
8646f111fa
|
|
@ -476,6 +476,16 @@ 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)
|
||||
{
|
||||
key->bw = opp->bandwidth ? opp->bandwidth[index].peak : 0;
|
||||
key->freq = opp->rates[index];
|
||||
key->level = opp->level;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Generic comparison helpers */
|
||||
static bool _compare_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
|
||||
unsigned long opp_key, unsigned long key)
|
||||
|
|
@ -509,6 +519,22 @@ 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)
|
||||
{
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Generic key finding helpers */
|
||||
static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
|
||||
unsigned long *key, int index, bool available,
|
||||
|
|
@ -541,6 +567,37 @@ static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
|
|||
return opp;
|
||||
}
|
||||
|
||||
static struct dev_pm_opp *_opp_table_find_opp_key(struct opp_table *opp_table,
|
||||
struct dev_pm_opp_key *key, bool available,
|
||||
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),
|
||||
bool (*assert)(struct opp_table *opp_table, unsigned int index))
|
||||
{
|
||||
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
|
||||
struct dev_pm_opp_key temp_key;
|
||||
|
||||
/* Assert that the requirement is met */
|
||||
if (!assert(opp_table, 0))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
guard(mutex)(&opp_table->lock);
|
||||
|
||||
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)) {
|
||||
/* Increment the reference count of OPP */
|
||||
dev_pm_opp_get(opp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return opp;
|
||||
}
|
||||
|
||||
static struct dev_pm_opp *
|
||||
_find_key(struct device *dev, unsigned long *key, int index, bool available,
|
||||
unsigned long (*read)(struct dev_pm_opp *opp, int index),
|
||||
|
|
@ -632,6 +689,48 @@ 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 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 of the key set in the OPP table.
|
||||
*
|
||||
* 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,
|
||||
* 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.
|
||||
*
|
||||
* This provides a mechanism to enable an OPP which is not available currently
|
||||
* or the opposite as well.
|
||||
*
|
||||
* The callers are required to call dev_pm_opp_put() for the returned OPP after
|
||||
* use.
|
||||
*/
|
||||
struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
|
||||
struct dev_pm_opp_key *key,
|
||||
bool available)
|
||||
{
|
||||
struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev);
|
||||
|
||||
if (IS_ERR(opp_table)) {
|
||||
dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
|
||||
PTR_ERR(opp_table));
|
||||
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);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_find_key_exact);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_find_freq_exact_indexed() - Search for an exact freq for the
|
||||
* clock corresponding to the index
|
||||
|
|
|
|||
|
|
@ -98,6 +98,25 @@ struct dev_pm_opp_data {
|
|||
unsigned long u_volt;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dev_pm_opp_key - Key used to identify OPP entries
|
||||
* @freq: Frequency in Hz. Use 0 if frequency is not to be matched.
|
||||
* @level: Performance level associated with the OPP entry.
|
||||
* Use OPP_LEVEL_UNSET if level is not to be matched.
|
||||
* @bw: Bandwidth associated with the OPP entry.
|
||||
* Use 0 if bandwidth is not to be matched.
|
||||
*
|
||||
* This structure is used to uniquely identify an OPP entry based on
|
||||
* frequency, performance level, and bandwidth. Each field can be
|
||||
* selectively ignored during matching by setting it to its respective
|
||||
* NOP value.
|
||||
*/
|
||||
struct dev_pm_opp_key {
|
||||
unsigned long freq;
|
||||
unsigned int level;
|
||||
u32 bw;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_PM_OPP)
|
||||
|
||||
struct opp_table *dev_pm_opp_get_opp_table(struct device *dev);
|
||||
|
|
@ -131,6 +150,10 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
|
|||
unsigned long freq,
|
||||
bool available);
|
||||
|
||||
struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
|
||||
struct dev_pm_opp_key *key,
|
||||
bool available);
|
||||
|
||||
struct dev_pm_opp *
|
||||
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
|
||||
u32 index, bool available);
|
||||
|
|
@ -289,6 +312,13 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
|
|||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
|
||||
struct dev_pm_opp_key *key,
|
||||
bool available)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
static inline struct dev_pm_opp *
|
||||
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
|
||||
u32 index, bool available)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::{
|
|||
clk::Hertz,
|
||||
cpumask::{Cpumask, CpumaskVar},
|
||||
device::Device,
|
||||
error::{code::*, from_err_ptr, from_result, to_result, Error, Result, VTABLE_DEFAULT_ERROR},
|
||||
error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR},
|
||||
ffi::c_ulong,
|
||||
prelude::*,
|
||||
str::CString,
|
||||
|
|
@ -500,11 +500,8 @@ impl<T: ConfigOps + Default> Config<T> {
|
|||
// requirements. The OPP core guarantees not to access fields of [`Config`] after this call
|
||||
// and so we don't need to save a copy of them for future use.
|
||||
let ret = unsafe { bindings::dev_pm_opp_set_config(dev.as_raw(), &mut config) };
|
||||
if ret < 0 {
|
||||
Err(Error::from_errno(ret))
|
||||
} else {
|
||||
Ok(ConfigToken(ret))
|
||||
}
|
||||
|
||||
to_result(ret).map(|()| ConfigToken(ret))
|
||||
}
|
||||
|
||||
/// Config's clk callback.
|
||||
|
|
@ -713,11 +710,8 @@ impl Table {
|
|||
// SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
|
||||
// requirements.
|
||||
let ret = unsafe { bindings::dev_pm_opp_get_opp_count(self.dev.as_raw()) };
|
||||
if ret < 0 {
|
||||
Err(Error::from_errno(ret))
|
||||
} else {
|
||||
Ok(ret as u32)
|
||||
}
|
||||
|
||||
to_result(ret).map(|()| ret as u32)
|
||||
}
|
||||
|
||||
/// Returns max clock latency (in nanoseconds) of the [`OPP`]s in the [`Table`].
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user