Skip to content

Commit 8646f11

Browse files
committed
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
2 parents b320789 + 05db359 commit 8646f11

3 files changed

Lines changed: 134 additions & 11 deletions

File tree

drivers/opp/core.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,16 @@ static unsigned long _read_bw(struct dev_pm_opp *opp, int index)
476476
return opp->bandwidth[index].peak;
477477
}
478478

479+
static unsigned long _read_opp_key(struct dev_pm_opp *opp, int index,
480+
struct dev_pm_opp_key *key)
481+
{
482+
key->bw = opp->bandwidth ? opp->bandwidth[index].peak : 0;
483+
key->freq = opp->rates[index];
484+
key->level = opp->level;
485+
486+
return true;
487+
}
488+
479489
/* Generic comparison helpers */
480490
static bool _compare_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
481491
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,
509519
return false;
510520
}
511521

522+
static bool _compare_opp_key_exact(struct dev_pm_opp **opp,
523+
struct dev_pm_opp *temp_opp, struct dev_pm_opp_key *opp_key,
524+
struct dev_pm_opp_key *key)
525+
{
526+
bool level_match = (key->level == OPP_LEVEL_UNSET || opp_key->level == key->level);
527+
bool freq_match = (key->freq == 0 || opp_key->freq == key->freq);
528+
bool bw_match = (key->bw == 0 || opp_key->bw == key->bw);
529+
530+
if (freq_match && level_match && bw_match) {
531+
*opp = temp_opp;
532+
return true;
533+
}
534+
535+
return false;
536+
}
537+
512538
/* Generic key finding helpers */
513539
static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
514540
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,
541567
return opp;
542568
}
543569

570+
static struct dev_pm_opp *_opp_table_find_opp_key(struct opp_table *opp_table,
571+
struct dev_pm_opp_key *key, bool available,
572+
unsigned long (*read)(struct dev_pm_opp *opp, int index,
573+
struct dev_pm_opp_key *key),
574+
bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
575+
struct dev_pm_opp_key *opp_key, struct dev_pm_opp_key *key),
576+
bool (*assert)(struct opp_table *opp_table, unsigned int index))
577+
{
578+
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
579+
struct dev_pm_opp_key temp_key;
580+
581+
/* Assert that the requirement is met */
582+
if (!assert(opp_table, 0))
583+
return ERR_PTR(-EINVAL);
584+
585+
guard(mutex)(&opp_table->lock);
586+
587+
list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
588+
if (temp_opp->available == available) {
589+
read(temp_opp, 0, &temp_key);
590+
if (compare(&opp, temp_opp, &temp_key, key)) {
591+
/* Increment the reference count of OPP */
592+
dev_pm_opp_get(opp);
593+
break;
594+
}
595+
}
596+
}
597+
598+
return opp;
599+
}
600+
544601
static struct dev_pm_opp *
545602
_find_key(struct device *dev, unsigned long *key, int index, bool available,
546603
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,
632689
}
633690
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
634691

692+
/**
693+
* dev_pm_opp_find_key_exact() - Search for an OPP with exact key set
694+
* @dev: Device for which the OPP is being searched
695+
* @key: OPP key set to match
696+
* @available: true/false - match for available OPP
697+
*
698+
* Search for an exact match of the key set in the OPP table.
699+
*
700+
* Return: A matching opp on success, else ERR_PTR in case of error.
701+
* Possible error values:
702+
* EINVAL: for bad pointers
703+
* ERANGE: no match found for search
704+
* ENODEV: if device not found in list of registered devices
705+
*
706+
* Note: 'available' is a modifier for the search. If 'available' == true,
707+
* then the match is for exact matching key and is available in the stored
708+
* OPP table. If false, the match is for exact key which is not available.
709+
*
710+
* This provides a mechanism to enable an OPP which is not available currently
711+
* or the opposite as well.
712+
*
713+
* The callers are required to call dev_pm_opp_put() for the returned OPP after
714+
* use.
715+
*/
716+
struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
717+
struct dev_pm_opp_key *key,
718+
bool available)
719+
{
720+
struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev);
721+
722+
if (IS_ERR(opp_table)) {
723+
dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
724+
PTR_ERR(opp_table));
725+
return ERR_CAST(opp_table);
726+
}
727+
728+
return _opp_table_find_opp_key(opp_table, key, available,
729+
_read_opp_key, _compare_opp_key_exact,
730+
assert_single_clk);
731+
}
732+
EXPORT_SYMBOL_GPL(dev_pm_opp_find_key_exact);
733+
635734
/**
636735
* dev_pm_opp_find_freq_exact_indexed() - Search for an exact freq for the
637736
* clock corresponding to the index

include/linux/pm_opp.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,25 @@ struct dev_pm_opp_data {
9898
unsigned long u_volt;
9999
};
100100

101+
/**
102+
* struct dev_pm_opp_key - Key used to identify OPP entries
103+
* @freq: Frequency in Hz. Use 0 if frequency is not to be matched.
104+
* @level: Performance level associated with the OPP entry.
105+
* Use OPP_LEVEL_UNSET if level is not to be matched.
106+
* @bw: Bandwidth associated with the OPP entry.
107+
* Use 0 if bandwidth is not to be matched.
108+
*
109+
* This structure is used to uniquely identify an OPP entry based on
110+
* frequency, performance level, and bandwidth. Each field can be
111+
* selectively ignored during matching by setting it to its respective
112+
* NOP value.
113+
*/
114+
struct dev_pm_opp_key {
115+
unsigned long freq;
116+
unsigned int level;
117+
u32 bw;
118+
};
119+
101120
#if defined(CONFIG_PM_OPP)
102121

103122
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,
131150
unsigned long freq,
132151
bool available);
133152

153+
struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
154+
struct dev_pm_opp_key *key,
155+
bool available);
156+
134157
struct dev_pm_opp *
135158
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
136159
u32 index, bool available);
@@ -289,6 +312,13 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
289312
return ERR_PTR(-EOPNOTSUPP);
290313
}
291314

315+
static inline struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev,
316+
struct dev_pm_opp_key *key,
317+
bool available)
318+
{
319+
return ERR_PTR(-EOPNOTSUPP);
320+
}
321+
292322
static inline struct dev_pm_opp *
293323
dev_pm_opp_find_freq_exact_indexed(struct device *dev, unsigned long freq,
294324
u32 index, bool available)

rust/kernel/opp.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
clk::Hertz,
1313
cpumask::{Cpumask, CpumaskVar},
1414
device::Device,
15-
error::{code::*, from_err_ptr, from_result, to_result, Error, Result, VTABLE_DEFAULT_ERROR},
15+
error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR},
1616
ffi::c_ulong,
1717
prelude::*,
1818
str::CString,
@@ -500,11 +500,8 @@ impl<T: ConfigOps + Default> Config<T> {
500500
// requirements. The OPP core guarantees not to access fields of [`Config`] after this call
501501
// and so we don't need to save a copy of them for future use.
502502
let ret = unsafe { bindings::dev_pm_opp_set_config(dev.as_raw(), &mut config) };
503-
if ret < 0 {
504-
Err(Error::from_errno(ret))
505-
} else {
506-
Ok(ConfigToken(ret))
507-
}
503+
504+
to_result(ret).map(|()| ConfigToken(ret))
508505
}
509506

510507
/// Config's clk callback.
@@ -713,11 +710,8 @@ impl Table {
713710
// SAFETY: The requirements are satisfied by the existence of [`Device`] and its safety
714711
// requirements.
715712
let ret = unsafe { bindings::dev_pm_opp_get_opp_count(self.dev.as_raw()) };
716-
if ret < 0 {
717-
Err(Error::from_errno(ret))
718-
} else {
719-
Ok(ret as u32)
720-
}
713+
714+
to_result(ret).map(|()| ret as u32)
721715
}
722716

723717
/// Returns max clock latency (in nanoseconds) of the [`OPP`]s in the [`Table`].

0 commit comments

Comments
 (0)