diff options
Diffstat (limited to 'drivers/opp/core.c')
| -rw-r--r-- | drivers/opp/core.c | 63 |
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 | ||
| 991 | static void _opp_kref_release(struct kref *kref) | 991 | static 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 | ||
| 1005 | static 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 | |||
| 1013 | static 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 | ||
| 1014 | void dev_pm_opp_put(struct dev_pm_opp *opp) | 1027 | void 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 | } |
| 1018 | EXPORT_SYMBOL_GPL(dev_pm_opp_put); | 1032 | EXPORT_SYMBOL_GPL(dev_pm_opp_put); |
| 1019 | 1033 | ||
| 1034 | static 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 | } |
| 1061 | EXPORT_SYMBOL_GPL(dev_pm_opp_remove); | 1080 | EXPORT_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 | */ | ||
| 1088 | void 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 | } | ||
| 1114 | EXPORT_SYMBOL_GPL(dev_pm_opp_remove_all_dynamic); | ||
| 1115 | |||
| 1063 | struct dev_pm_opp *_opp_allocate(struct opp_table *table) | 1116 | struct dev_pm_opp *_opp_allocate(struct opp_table *table) |
| 1064 | { | 1117 | { |
| 1065 | struct dev_pm_opp *opp; | 1118 | struct dev_pm_opp *opp; |
