diff options
| -rw-r--r-- | drivers/base/power/opp/core.c | 27 | ||||
| -rw-r--r-- | drivers/base/power/opp/opp.h | 3 | ||||
| -rw-r--r-- | include/linux/pm_opp.h | 3 |
3 files changed, 18 insertions, 15 deletions
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index ab9499e3ba02..9870ee54d708 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c | |||
| @@ -949,20 +949,10 @@ static void _kfree_opp_rcu(struct rcu_head *head) | |||
| 949 | kfree_rcu(opp, rcu_head); | 949 | kfree_rcu(opp, rcu_head); |
| 950 | } | 950 | } |
| 951 | 951 | ||
| 952 | /** | 952 | static void _opp_kref_release(struct kref *kref) |
| 953 | * _opp_remove() - Remove an OPP from a table definition | ||
| 954 | * @opp_table: points back to the opp_table struct this opp belongs to | ||
| 955 | * @opp: pointer to the OPP to remove | ||
| 956 | * | ||
| 957 | * This function removes an opp definition from the opp table. | ||
| 958 | * | ||
| 959 | * Locking: The internal opp_table and opp structures are RCU protected. | ||
| 960 | * It is assumed that the caller holds required mutex for an RCU updater | ||
| 961 | * strategy. | ||
| 962 | */ | ||
| 963 | static void _opp_remove(struct opp_table *opp_table, struct dev_pm_opp *opp) | ||
| 964 | { | 953 | { |
| 965 | mutex_lock(&opp_table->lock); | 954 | struct dev_pm_opp *opp = container_of(kref, struct dev_pm_opp, kref); |
| 955 | struct opp_table *opp_table = opp->opp_table; | ||
| 966 | 956 | ||
| 967 | /* | 957 | /* |
| 968 | * Notify the changes in the availability of the operable | 958 | * Notify the changes in the availability of the operable |
| @@ -977,6 +967,12 @@ static void _opp_remove(struct opp_table *opp_table, struct dev_pm_opp *opp) | |||
| 977 | dev_pm_opp_put_opp_table(opp_table); | 967 | dev_pm_opp_put_opp_table(opp_table); |
| 978 | } | 968 | } |
| 979 | 969 | ||
| 970 | void dev_pm_opp_put(struct dev_pm_opp *opp) | ||
| 971 | { | ||
| 972 | kref_put_mutex(&opp->kref, _opp_kref_release, &opp->opp_table->lock); | ||
| 973 | } | ||
| 974 | EXPORT_SYMBOL_GPL(dev_pm_opp_put); | ||
| 975 | |||
| 980 | /** | 976 | /** |
| 981 | * dev_pm_opp_remove() - Remove an OPP from OPP table | 977 | * dev_pm_opp_remove() - Remove an OPP from OPP table |
| 982 | * @dev: device for which we do this operation | 978 | * @dev: device for which we do this operation |
| @@ -1020,7 +1016,7 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) | |||
| 1020 | goto unlock; | 1016 | goto unlock; |
| 1021 | } | 1017 | } |
| 1022 | 1018 | ||
| 1023 | _opp_remove(opp_table, opp); | 1019 | dev_pm_opp_put(opp); |
| 1024 | unlock: | 1020 | unlock: |
| 1025 | mutex_unlock(&opp_table_lock); | 1021 | mutex_unlock(&opp_table_lock); |
| 1026 | } | 1022 | } |
| @@ -1124,6 +1120,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, | |||
| 1124 | mutex_unlock(&opp_table->lock); | 1120 | mutex_unlock(&opp_table->lock); |
| 1125 | 1121 | ||
| 1126 | new_opp->opp_table = opp_table; | 1122 | new_opp->opp_table = opp_table; |
| 1123 | kref_init(&new_opp->kref); | ||
| 1127 | 1124 | ||
| 1128 | /* Get a reference to the OPP table */ | 1125 | /* Get a reference to the OPP table */ |
| 1129 | _get_opp_table_kref(opp_table); | 1126 | _get_opp_table_kref(opp_table); |
| @@ -1819,7 +1816,7 @@ void _dev_pm_opp_remove_table(struct opp_table *opp_table, struct device *dev, | |||
| 1819 | /* Free static OPPs */ | 1816 | /* Free static OPPs */ |
| 1820 | list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) { | 1817 | list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) { |
| 1821 | if (remove_all || !opp->dynamic) | 1818 | if (remove_all || !opp->dynamic) |
| 1822 | _opp_remove(opp_table, opp); | 1819 | dev_pm_opp_put(opp); |
| 1823 | } | 1820 | } |
| 1824 | } else { | 1821 | } else { |
| 1825 | _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table); | 1822 | _remove_opp_dev(_find_opp_dev(dev, opp_table), opp_table); |
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h index a01724363347..586f36f94e28 100644 --- a/drivers/base/power/opp/opp.h +++ b/drivers/base/power/opp/opp.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include <linux/device.h> | 17 | #include <linux/device.h> |
| 18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
| 19 | #include <linux/kref.h> | ||
| 19 | #include <linux/list.h> | 20 | #include <linux/list.h> |
| 20 | #include <linux/limits.h> | 21 | #include <linux/limits.h> |
| 21 | #include <linux/pm_opp.h> | 22 | #include <linux/pm_opp.h> |
| @@ -56,6 +57,7 @@ extern struct list_head opp_tables; | |||
| 56 | * are protected by the opp_table_lock for integrity. | 57 | * are protected by the opp_table_lock for integrity. |
| 57 | * IMPORTANT: the opp nodes should be maintained in increasing | 58 | * IMPORTANT: the opp nodes should be maintained in increasing |
| 58 | * order. | 59 | * order. |
| 60 | * @kref: for reference count of the OPP. | ||
| 59 | * @available: true/false - marks if this OPP as available or not | 61 | * @available: true/false - marks if this OPP as available or not |
| 60 | * @dynamic: not-created from static DT entries. | 62 | * @dynamic: not-created from static DT entries. |
| 61 | * @turbo: true if turbo (boost) OPP | 63 | * @turbo: true if turbo (boost) OPP |
| @@ -73,6 +75,7 @@ extern struct list_head opp_tables; | |||
| 73 | */ | 75 | */ |
| 74 | struct dev_pm_opp { | 76 | struct dev_pm_opp { |
| 75 | struct list_head node; | 77 | struct list_head node; |
| 78 | struct kref kref; | ||
| 76 | 79 | ||
| 77 | bool available; | 80 | bool available; |
| 78 | bool dynamic; | 81 | bool dynamic; |
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index 99787cbcaab2..731d548657aa 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h | |||
| @@ -102,6 +102,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, | |||
| 102 | 102 | ||
| 103 | struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, | 103 | struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, |
| 104 | unsigned long *freq); | 104 | unsigned long *freq); |
| 105 | void dev_pm_opp_put(struct dev_pm_opp *opp); | ||
| 105 | 106 | ||
| 106 | int dev_pm_opp_add(struct device *dev, unsigned long freq, | 107 | int dev_pm_opp_add(struct device *dev, unsigned long freq, |
| 107 | unsigned long u_volt); | 108 | unsigned long u_volt); |
| @@ -193,6 +194,8 @@ static inline struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, | |||
| 193 | return ERR_PTR(-ENOTSUPP); | 194 | return ERR_PTR(-ENOTSUPP); |
| 194 | } | 195 | } |
| 195 | 196 | ||
| 197 | static inline void dev_pm_opp_put(struct dev_pm_opp *opp) {} | ||
| 198 | |||
| 196 | static inline int dev_pm_opp_add(struct device *dev, unsigned long freq, | 199 | static inline int dev_pm_opp_add(struct device *dev, unsigned long freq, |
| 197 | unsigned long u_volt) | 200 | unsigned long u_volt) |
| 198 | { | 201 | { |
