Skip to content

Commit aab8ced

Browse files
committed
OPP: Add generic key finding helpers and use them for freq APIs
There are three type of helpers, to find exact, ceil, and floor values, replicated for multiple key types, freq, level, bw. And all of these helpers share a lot of boilerplate code. Add generic key finding helpers to reduce code redundancy. Also update the freq finder helpers to use the new infrastructure. Tested-by: Dmitry Osipenko <[email protected]> Signed-off-by: Viresh Kumar <[email protected]>
1 parent 9fbb626 commit aab8ced

File tree

1 file changed

+130
-99
lines changed

1 file changed

+130
-99
lines changed

drivers/opp/core.c

Lines changed: 130 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,131 @@ int dev_pm_opp_get_opp_count(struct device *dev)
427427
}
428428
EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
429429

430+
/* Helpers to read keys */
431+
static unsigned long _read_freq(struct dev_pm_opp *opp, int index)
432+
{
433+
return opp->rate;
434+
}
435+
436+
/* Generic comparison helpers */
437+
static bool _compare_exact(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
438+
unsigned long opp_key, unsigned long key)
439+
{
440+
if (opp_key == key) {
441+
*opp = temp_opp;
442+
return true;
443+
}
444+
445+
return false;
446+
}
447+
448+
static bool _compare_ceil(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
449+
unsigned long opp_key, unsigned long key)
450+
{
451+
if (opp_key >= key) {
452+
*opp = temp_opp;
453+
return true;
454+
}
455+
456+
return false;
457+
}
458+
459+
static bool _compare_floor(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
460+
unsigned long opp_key, unsigned long key)
461+
{
462+
if (opp_key > key)
463+
return true;
464+
465+
*opp = temp_opp;
466+
return false;
467+
}
468+
469+
/* Generic key finding helpers */
470+
static struct dev_pm_opp *_opp_table_find_key(struct opp_table *opp_table,
471+
unsigned long *key, int index, bool available,
472+
unsigned long (*read)(struct dev_pm_opp *opp, int index),
473+
bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
474+
unsigned long opp_key, unsigned long key))
475+
{
476+
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
477+
478+
mutex_lock(&opp_table->lock);
479+
480+
list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
481+
if (temp_opp->available == available) {
482+
if (compare(&opp, temp_opp, read(temp_opp, index), *key))
483+
break;
484+
}
485+
}
486+
487+
/* Increment the reference count of OPP */
488+
if (!IS_ERR(opp)) {
489+
*key = read(opp, index);
490+
dev_pm_opp_get(opp);
491+
}
492+
493+
mutex_unlock(&opp_table->lock);
494+
495+
return opp;
496+
}
497+
498+
static struct dev_pm_opp *
499+
_find_key(struct device *dev, unsigned long *key, int index, bool available,
500+
unsigned long (*read)(struct dev_pm_opp *opp, int index),
501+
bool (*compare)(struct dev_pm_opp **opp, struct dev_pm_opp *temp_opp,
502+
unsigned long opp_key, unsigned long key))
503+
{
504+
struct opp_table *opp_table;
505+
struct dev_pm_opp *opp;
506+
507+
opp_table = _find_opp_table(dev);
508+
if (IS_ERR(opp_table)) {
509+
dev_err(dev, "%s: OPP table not found (%ld)\n", __func__,
510+
PTR_ERR(opp_table));
511+
return ERR_CAST(opp_table);
512+
}
513+
514+
opp = _opp_table_find_key(opp_table, key, index, available, read,
515+
compare);
516+
517+
dev_pm_opp_put_opp_table(opp_table);
518+
519+
return opp;
520+
}
521+
522+
static struct dev_pm_opp *_find_key_exact(struct device *dev,
523+
unsigned long key, int index, bool available,
524+
unsigned long (*read)(struct dev_pm_opp *opp, int index))
525+
{
526+
/*
527+
* The value of key will be updated here, but will be ignored as the
528+
* caller doesn't need it.
529+
*/
530+
return _find_key(dev, &key, index, available, read, _compare_exact);
531+
}
532+
533+
static struct dev_pm_opp *_opp_table_find_key_ceil(struct opp_table *opp_table,
534+
unsigned long *key, int index, bool available,
535+
unsigned long (*read)(struct dev_pm_opp *opp, int index))
536+
{
537+
return _opp_table_find_key(opp_table, key, index, available, read,
538+
_compare_ceil);
539+
}
540+
541+
static struct dev_pm_opp *_find_key_ceil(struct device *dev, unsigned long *key,
542+
int index, bool available,
543+
unsigned long (*read)(struct dev_pm_opp *opp, int index))
544+
{
545+
return _find_key(dev, key, index, available, read, _compare_ceil);
546+
}
547+
548+
static struct dev_pm_opp *_find_key_floor(struct device *dev,
549+
unsigned long *key, int index, bool available,
550+
unsigned long (*read)(struct dev_pm_opp *opp, int index))
551+
{
552+
return _find_key(dev, key, index, available, read, _compare_floor);
553+
}
554+
430555
/**
431556
* dev_pm_opp_find_freq_exact() - search for an exact frequency
432557
* @dev: device for which we do this operation
@@ -451,61 +576,16 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
451576
* use.
452577
*/
453578
struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
454-
unsigned long freq,
455-
bool available)
579+
unsigned long freq, bool available)
456580
{
457-
struct opp_table *opp_table;
458-
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
459-
460-
opp_table = _find_opp_table(dev);
461-
if (IS_ERR(opp_table)) {
462-
int r = PTR_ERR(opp_table);
463-
464-
dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r);
465-
return ERR_PTR(r);
466-
}
467-
468-
mutex_lock(&opp_table->lock);
469-
470-
list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
471-
if (temp_opp->available == available &&
472-
temp_opp->rate == freq) {
473-
opp = temp_opp;
474-
475-
/* Increment the reference count of OPP */
476-
dev_pm_opp_get(opp);
477-
break;
478-
}
479-
}
480-
481-
mutex_unlock(&opp_table->lock);
482-
dev_pm_opp_put_opp_table(opp_table);
483-
484-
return opp;
581+
return _find_key_exact(dev, freq, 0, available, _read_freq);
485582
}
486583
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
487584

488585
static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
489586
unsigned long *freq)
490587
{
491-
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
492-
493-
mutex_lock(&opp_table->lock);
494-
495-
list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
496-
if (temp_opp->available && temp_opp->rate >= *freq) {
497-
opp = temp_opp;
498-
*freq = opp->rate;
499-
500-
/* Increment the reference count of OPP */
501-
dev_pm_opp_get(opp);
502-
break;
503-
}
504-
}
505-
506-
mutex_unlock(&opp_table->lock);
507-
508-
return opp;
588+
return _opp_table_find_key_ceil(opp_table, freq, 0, true, _read_freq);
509589
}
510590

511591
/**
@@ -529,23 +609,7 @@ static noinline struct dev_pm_opp *_find_freq_ceil(struct opp_table *opp_table,
529609
struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
530610
unsigned long *freq)
531611
{
532-
struct opp_table *opp_table;
533-
struct dev_pm_opp *opp;
534-
535-
if (!dev || !freq) {
536-
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
537-
return ERR_PTR(-EINVAL);
538-
}
539-
540-
opp_table = _find_opp_table(dev);
541-
if (IS_ERR(opp_table))
542-
return ERR_CAST(opp_table);
543-
544-
opp = _find_freq_ceil(opp_table, freq);
545-
546-
dev_pm_opp_put_opp_table(opp_table);
547-
548-
return opp;
612+
return _find_key_ceil(dev, freq, 0, true, _read_freq);
549613
}
550614
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
551615

@@ -570,40 +634,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
570634
struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
571635
unsigned long *freq)
572636
{
573-
struct opp_table *opp_table;
574-
struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
575-
576-
if (!dev || !freq) {
577-
dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
578-
return ERR_PTR(-EINVAL);
579-
}
580-
581-
opp_table = _find_opp_table(dev);
582-
if (IS_ERR(opp_table))
583-
return ERR_CAST(opp_table);
584-
585-
mutex_lock(&opp_table->lock);
586-
587-
list_for_each_entry(temp_opp, &opp_table->opp_list, node) {
588-
if (temp_opp->available) {
589-
/* go to the next node, before choosing prev */
590-
if (temp_opp->rate > *freq)
591-
break;
592-
else
593-
opp = temp_opp;
594-
}
595-
}
596-
597-
/* Increment the reference count of OPP */
598-
if (!IS_ERR(opp))
599-
dev_pm_opp_get(opp);
600-
mutex_unlock(&opp_table->lock);
601-
dev_pm_opp_put_opp_table(opp_table);
602-
603-
if (!IS_ERR(opp))
604-
*freq = opp->rate;
605-
606-
return opp;
637+
return _find_key_floor(dev, freq, 0, true, _read_freq);
607638
}
608639
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
609640

0 commit comments

Comments
 (0)