aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/opp/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/opp/core.c')
-rw-r--r--drivers/opp/core.c63
1 files changed, 58 insertions, 5 deletions
diff --git a/drivers/opp/core.c b/drivers/opp/core.c
index e5507add8f04..18f1639dbc4a 100644
--- a/drivers/opp/core.c
+++ b/drivers/opp/core.c
@@ -988,11 +988,9 @@ void _opp_free(struct dev_pm_opp *opp)
988 kfree(opp); 988 kfree(opp);
989} 989}
990 990
991static void _opp_kref_release(struct kref *kref) 991static void _opp_kref_release(struct dev_pm_opp *opp,
992 struct opp_table *opp_table)
992{ 993{
993 struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
994 struct opp_table *opp_table = opp->opp_table;
995
996 /* 994 /*
997 * Notify the changes in the availability of the operable 995 * Notify the changes in the availability of the operable
998 * frequency/voltage list. 996 * frequency/voltage list.
@@ -1002,7 +1000,22 @@ static void _opp_kref_release(struct kref *kref)
1002 opp_debug_remove_one(opp); 1000 opp_debug_remove_one(opp);
1003 list_del(&opp->node); 1001 list_del(&opp->node);
1004 kfree(opp); 1002 kfree(opp);
1003}
1005 1004
1005static void _opp_kref_release_unlocked(struct kref *kref)
1006{
1007 struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
1008 struct opp_table *opp_table = opp->opp_table;
1009
1010 _opp_kref_release(opp, opp_table);
1011}
1012
1013static void _opp_kref_release_locked(struct kref *kref)
1014{
1015 struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref);
1016 struct opp_table *opp_table = opp->opp_table;
1017
1018 _opp_kref_release(opp, opp_table);
1006 mutex_unlock(&opp_table->lock); 1019 mutex_unlock(&opp_table->lock);
1007} 1020}
1008 1021
@@ -1013,10 +1026,16 @@ void dev_pm_opp_get(struct dev_pm_opp *opp)
1013 1026
1014void dev_pm_opp_put(struct dev_pm_opp *opp) 1027void dev_pm_opp_put(struct dev_pm_opp *opp)
1015{ 1028{
1016 kref_put_mutex(&opp->kref, _opp_kref_release, &opp->opp_table->lock); 1029 kref_put_mutex(&opp->kref, _opp_kref_release_locked,
1030 &opp->opp_table->lock);
1017} 1031}
1018EXPORT_SYMBOL_GPL(dev_pm_opp_put); 1032EXPORT_SYMBOL_GPL(dev_pm_opp_put);
1019 1033
1034static void dev_pm_opp_put_unlocked(struct dev_pm_opp *opp)
1035{
1036 kref_put(&opp->kref, _opp_kref_release_unlocked);
1037}
1038
1020/** 1039/**
1021 * dev_pm_opp_remove() - Remove an OPP from OPP table 1040 * dev_pm_opp_remove() - Remove an OPP from OPP table
1022 * @dev: device for which we do this operation 1041 * @dev: device for which we do this operation
@@ -1060,6 +1079,40 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
1060} 1079}
1061EXPORT_SYMBOL_GPL(dev_pm_opp_remove); 1080EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
1062 1081
1082/**
1083 * dev_pm_opp_remove_all_dynamic() - Remove all dynamically created OPPs
1084 * @dev: device for which we do this operation
1085 *
1086 * This function removes all dynamically created OPPs from the opp table.
1087 */
1088void dev_pm_opp_remove_all_dynamic(struct device *dev)
1089{
1090 struct opp_table *opp_table;
1091 struct dev_pm_opp *opp, *temp;
1092 int count = 0;
1093
1094 opp_table = _find_opp_table(dev);
1095 if (IS_ERR(opp_table))
1096 return;
1097
1098 mutex_lock(&opp_table->lock);
1099 list_for_each_entry_safe(opp, temp, &opp_table->opp_list, node) {
1100 if (opp->dynamic) {
1101 dev_pm_opp_put_unlocked(opp);
1102 count++;
1103 }
1104 }
1105 mutex_unlock(&opp_table->lock);
1106
1107 /* Drop the references taken by dev_pm_opp_add() */
1108 while (count--)
1109 dev_pm_opp_put_opp_table(opp_table);
1110
1111 /* Drop the reference taken by _find_opp_table() */
1112 dev_pm_opp_put_opp_table(opp_table);
1113}
1114EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic);
1115
1063struct dev_pm_opp *_opp_allocate(struct opp_table *table) 1116struct dev_pm_opp *_opp_allocate(struct opp_table *table)
1064{ 1117{
1065 struct dev_pm_opp *opp; 1118 struct dev_pm_opp *opp;