diff options
| author | Viresh Kumar <viresh.kumar@linaro.org> | 2017-01-22 23:41:48 -0500 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-01-30 03:22:22 -0500 |
| commit | 5b650b388844f26c61c70564865598836d05dcb3 (patch) | |
| tree | 93ae6faaad201381793f8322b6d9c227e2c489b0 /drivers/base | |
| parent | 8a31d9d94297b1ecae3012069d35d78c959693c2 (diff) | |
PM / OPP: Take kref from _find_opp_table()
Take reference of the OPP table from within _find_opp_table(). Also
update the callers of _find_opp_table() to call
dev_pm_opp_put_opp_table() after they have used the OPP table.
Note that _find_opp_table() increments the reference under the
opp_table_lock.
Now that the OPP table wouldn't get freed until the callers of
_find_opp_table() call dev_pm_opp_put_opp_table(), there is no need to
take the opp_table_lock or rcu_read_lock() around it. Drop them.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/base')
| -rw-r--r-- | drivers/base/power/opp/core.c | 191 | ||||
| -rw-r--r-- | drivers/base/power/opp/cpu.c | 26 |
2 files changed, 95 insertions, 122 deletions
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c index a6efa818029a..69452a4bcda7 100644 --- a/drivers/base/power/opp/core.c +++ b/drivers/base/power/opp/core.c | |||
| @@ -54,6 +54,21 @@ static struct opp_device *_find_opp_dev(const struct device *dev, | |||
| 54 | return NULL; | 54 | return NULL; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | struct opp_table *_find_opp_table_unlocked(struct device *dev) | ||
| 58 | { | ||
| 59 | struct opp_table *opp_table; | ||
| 60 | |||
| 61 | list_for_each_entry(opp_table, &opp_tables, node) { | ||
| 62 | if (_find_opp_dev(dev, opp_table)) { | ||
| 63 | _get_opp_table_kref(opp_table); | ||
| 64 | |||
| 65 | return opp_table; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | return ERR_PTR(-ENODEV); | ||
| 70 | } | ||
| 71 | |||
| 57 | /** | 72 | /** |
| 58 | * _find_opp_table() - find opp_table struct using device pointer | 73 | * _find_opp_table() - find opp_table struct using device pointer |
| 59 | * @dev: device pointer used to lookup OPP table | 74 | * @dev: device pointer used to lookup OPP table |
| @@ -64,28 +79,22 @@ static struct opp_device *_find_opp_dev(const struct device *dev, | |||
| 64 | * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or | 79 | * Return: pointer to 'struct opp_table' if found, otherwise -ENODEV or |
| 65 | * -EINVAL based on type of error. | 80 | * -EINVAL based on type of error. |
| 66 | * | 81 | * |
| 67 | * Locking: For readers, this function must be called under rcu_read_lock(). | 82 | * The callers must call dev_pm_opp_put_opp_table() after the table is used. |
| 68 | * opp_table is a RCU protected pointer, which means that opp_table is valid | ||
| 69 | * as long as we are under RCU lock. | ||
| 70 | * | ||
| 71 | * For Writers, this function must be called with opp_table_lock held. | ||
| 72 | */ | 83 | */ |
| 73 | struct opp_table *_find_opp_table(struct device *dev) | 84 | struct opp_table *_find_opp_table(struct device *dev) |
| 74 | { | 85 | { |
| 75 | struct opp_table *opp_table; | 86 | struct opp_table *opp_table; |
| 76 | 87 | ||
| 77 | opp_rcu_lockdep_assert(); | ||
| 78 | |||
| 79 | if (IS_ERR_OR_NULL(dev)) { | 88 | if (IS_ERR_OR_NULL(dev)) { |
| 80 | pr_err("%s: Invalid parameters\n", __func__); | 89 | pr_err("%s: Invalid parameters\n", __func__); |
| 81 | return ERR_PTR(-EINVAL); | 90 | return ERR_PTR(-EINVAL); |
| 82 | } | 91 | } |
| 83 | 92 | ||
| 84 | list_for_each_entry_rcu(opp_table, &opp_tables, node) | 93 | mutex_lock(&opp_table_lock); |
| 85 | if (_find_opp_dev(dev, opp_table)) | 94 | opp_table = _find_opp_table_unlocked(dev); |
| 86 | return opp_table; | 95 | mutex_unlock(&opp_table_lock); |
| 87 | 96 | ||
| 88 | return ERR_PTR(-ENODEV); | 97 | return opp_table; |
| 89 | } | 98 | } |
| 90 | 99 | ||
| 91 | /** | 100 | /** |
| @@ -175,23 +184,20 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_is_turbo); | |||
| 175 | * @dev: device for which we do this operation | 184 | * @dev: device for which we do this operation |
| 176 | * | 185 | * |
| 177 | * Return: This function returns the max clock latency in nanoseconds. | 186 | * Return: This function returns the max clock latency in nanoseconds. |
| 178 | * | ||
| 179 | * Locking: This function takes rcu_read_lock(). | ||
| 180 | */ | 187 | */ |
| 181 | unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev) | 188 | unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev) |
| 182 | { | 189 | { |
| 183 | struct opp_table *opp_table; | 190 | struct opp_table *opp_table; |
| 184 | unsigned long clock_latency_ns; | 191 | unsigned long clock_latency_ns; |
| 185 | 192 | ||
| 186 | rcu_read_lock(); | ||
| 187 | |||
| 188 | opp_table = _find_opp_table(dev); | 193 | opp_table = _find_opp_table(dev); |
| 189 | if (IS_ERR(opp_table)) | 194 | if (IS_ERR(opp_table)) |
| 190 | clock_latency_ns = 0; | 195 | return 0; |
| 191 | else | 196 | |
| 192 | clock_latency_ns = opp_table->clock_latency_ns_max; | 197 | clock_latency_ns = opp_table->clock_latency_ns_max; |
| 198 | |||
| 199 | dev_pm_opp_put_opp_table(opp_table); | ||
| 193 | 200 | ||
| 194 | rcu_read_unlock(); | ||
| 195 | return clock_latency_ns; | 201 | return clock_latency_ns; |
| 196 | } | 202 | } |
| 197 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency); | 203 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency); |
| @@ -201,15 +207,13 @@ static int _get_regulator_count(struct device *dev) | |||
| 201 | struct opp_table *opp_table; | 207 | struct opp_table *opp_table; |
| 202 | int count; | 208 | int count; |
| 203 | 209 | ||
| 204 | rcu_read_lock(); | ||
| 205 | |||
| 206 | opp_table = _find_opp_table(dev); | 210 | opp_table = _find_opp_table(dev); |
| 207 | if (!IS_ERR(opp_table)) | 211 | if (IS_ERR(opp_table)) |
| 208 | count = opp_table->regulator_count; | 212 | return 0; |
| 209 | else | ||
| 210 | count = 0; | ||
| 211 | 213 | ||
| 212 | rcu_read_unlock(); | 214 | count = opp_table->regulator_count; |
| 215 | |||
| 216 | dev_pm_opp_put_opp_table(opp_table); | ||
| 213 | 217 | ||
| 214 | return count; | 218 | return count; |
| 215 | } | 219 | } |
| @@ -248,13 +252,11 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev) | |||
| 248 | if (!uV) | 252 | if (!uV) |
| 249 | goto free_regulators; | 253 | goto free_regulators; |
| 250 | 254 | ||
| 251 | rcu_read_lock(); | ||
| 252 | |||
| 253 | opp_table = _find_opp_table(dev); | 255 | opp_table = _find_opp_table(dev); |
| 254 | if (IS_ERR(opp_table)) { | 256 | if (IS_ERR(opp_table)) |
| 255 | rcu_read_unlock(); | ||
| 256 | goto free_uV; | 257 | goto free_uV; |
| 257 | } | 258 | |
| 259 | rcu_read_lock(); | ||
| 258 | 260 | ||
| 259 | memcpy(regulators, opp_table->regulators, count * sizeof(*regulators)); | 261 | memcpy(regulators, opp_table->regulators, count * sizeof(*regulators)); |
| 260 | 262 | ||
| @@ -274,6 +276,7 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev) | |||
| 274 | } | 276 | } |
| 275 | 277 | ||
| 276 | rcu_read_unlock(); | 278 | rcu_read_unlock(); |
| 279 | dev_pm_opp_put_opp_table(opp_table); | ||
| 277 | 280 | ||
| 278 | /* | 281 | /* |
| 279 | * The caller needs to ensure that opp_table (and hence the regulator) | 282 | * The caller needs to ensure that opp_table (and hence the regulator) |
| @@ -323,17 +326,15 @@ unsigned long dev_pm_opp_get_suspend_opp_freq(struct device *dev) | |||
| 323 | struct opp_table *opp_table; | 326 | struct opp_table *opp_table; |
| 324 | unsigned long freq = 0; | 327 | unsigned long freq = 0; |
| 325 | 328 | ||
| 326 | rcu_read_lock(); | ||
| 327 | |||
| 328 | opp_table = _find_opp_table(dev); | 329 | opp_table = _find_opp_table(dev); |
| 329 | if (IS_ERR(opp_table) || !opp_table->suspend_opp || | 330 | if (IS_ERR(opp_table)) |
| 330 | !opp_table->suspend_opp->available) | 331 | return 0; |
| 331 | goto unlock; | ||
| 332 | 332 | ||
| 333 | freq = dev_pm_opp_get_freq(opp_table->suspend_opp); | 333 | if (opp_table->suspend_opp && opp_table->suspend_opp->available) |
| 334 | freq = dev_pm_opp_get_freq(opp_table->suspend_opp); | ||
| 335 | |||
| 336 | dev_pm_opp_put_opp_table(opp_table); | ||
| 334 | 337 | ||
| 335 | unlock: | ||
| 336 | rcu_read_unlock(); | ||
| 337 | return freq; | 338 | return freq; |
| 338 | } | 339 | } |
| 339 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); | 340 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp_freq); |
| @@ -353,23 +354,24 @@ int dev_pm_opp_get_opp_count(struct device *dev) | |||
| 353 | struct dev_pm_opp *temp_opp; | 354 | struct dev_pm_opp *temp_opp; |
| 354 | int count = 0; | 355 | int count = 0; |
| 355 | 356 | ||
| 356 | rcu_read_lock(); | ||
| 357 | |||
| 358 | opp_table = _find_opp_table(dev); | 357 | opp_table = _find_opp_table(dev); |
| 359 | if (IS_ERR(opp_table)) { | 358 | if (IS_ERR(opp_table)) { |
| 360 | count = PTR_ERR(opp_table); | 359 | count = PTR_ERR(opp_table); |
| 361 | dev_err(dev, "%s: OPP table not found (%d)\n", | 360 | dev_err(dev, "%s: OPP table not found (%d)\n", |
| 362 | __func__, count); | 361 | __func__, count); |
| 363 | goto out_unlock; | 362 | return count; |
| 364 | } | 363 | } |
| 365 | 364 | ||
| 365 | rcu_read_lock(); | ||
| 366 | |||
| 366 | list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { | 367 | list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { |
| 367 | if (temp_opp->available) | 368 | if (temp_opp->available) |
| 368 | count++; | 369 | count++; |
| 369 | } | 370 | } |
| 370 | 371 | ||
| 371 | out_unlock: | ||
| 372 | rcu_read_unlock(); | 372 | rcu_read_unlock(); |
| 373 | dev_pm_opp_put_opp_table(opp_table); | ||
| 374 | |||
| 373 | return count; | 375 | return count; |
| 374 | } | 376 | } |
| 375 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count); | 377 | EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count); |
| @@ -404,17 +406,16 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, | |||
| 404 | struct opp_table *opp_table; | 406 | struct opp_table *opp_table; |
| 405 | struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); | 407 | struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE); |
| 406 | 408 | ||
| 407 | rcu_read_lock(); | ||
| 408 | |||
| 409 | opp_table = _find_opp_table(dev); | 409 | opp_table = _find_opp_table(dev); |
| 410 | if (IS_ERR(opp_table)) { | 410 | if (IS_ERR(opp_table)) { |
| 411 | int r = PTR_ERR(opp_table); | 411 | int r = PTR_ERR(opp_table); |
| 412 | 412 | ||
| 413 | dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r); | 413 | dev_err(dev, "%s: OPP table not found (%d)\n", __func__, r); |
| 414 | rcu_read_unlock(); | ||
| 415 | return ERR_PTR(r); | 414 | return ERR_PTR(r); |
| 416 | } | 415 | } |
| 417 | 416 | ||
| 417 | rcu_read_lock(); | ||
| 418 | |||
| 418 | list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { | 419 | list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { |
| 419 | if (temp_opp->available == available && | 420 | if (temp_opp->available == available && |
| 420 | temp_opp->rate == freq) { | 421 | temp_opp->rate == freq) { |
| @@ -427,6 +428,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, | |||
| 427 | } | 428 | } |
| 428 | 429 | ||
| 429 | rcu_read_unlock(); | 430 | rcu_read_unlock(); |
| 431 | dev_pm_opp_put_opp_table(opp_table); | ||
| 430 | 432 | ||
| 431 | return opp; | 433 | return opp; |
| 432 | } | 434 | } |
| @@ -480,17 +482,16 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev, | |||
| 480 | return ERR_PTR(-EINVAL); | 482 | return ERR_PTR(-EINVAL); |
| 481 | } | 483 | } |
| 482 | 484 | ||
| 483 | rcu_read_lock(); | ||
| 484 | |||
| 485 | opp_table = _find_opp_table(dev); | 485 | opp_table = _find_opp_table(dev); |
| 486 | if (IS_ERR(opp_table)) { | 486 | if (IS_ERR(opp_table)) |
| 487 | rcu_read_unlock(); | ||
| 488 | return ERR_CAST(opp_table); | 487 | return ERR_CAST(opp_table); |
| 489 | } | 488 | |
| 489 | rcu_read_lock(); | ||
| 490 | 490 | ||
| 491 | opp = _find_freq_ceil(opp_table, freq); | 491 | opp = _find_freq_ceil(opp_table, freq); |
| 492 | 492 | ||
| 493 | rcu_read_unlock(); | 493 | rcu_read_unlock(); |
| 494 | dev_pm_opp_put_opp_table(opp_table); | ||
| 494 | 495 | ||
| 495 | return opp; | 496 | return opp; |
| 496 | } | 497 | } |
| @@ -525,13 +526,11 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, | |||
| 525 | return ERR_PTR(-EINVAL); | 526 | return ERR_PTR(-EINVAL); |
| 526 | } | 527 | } |
| 527 | 528 | ||
| 528 | rcu_read_lock(); | ||
| 529 | |||
| 530 | opp_table = _find_opp_table(dev); | 529 | opp_table = _find_opp_table(dev); |
| 531 | if (IS_ERR(opp_table)) { | 530 | if (IS_ERR(opp_table)) |
| 532 | rcu_read_unlock(); | ||
| 533 | return ERR_CAST(opp_table); | 531 | return ERR_CAST(opp_table); |
| 534 | } | 532 | |
| 533 | rcu_read_lock(); | ||
| 535 | 534 | ||
| 536 | list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { | 535 | list_for_each_entry_rcu(temp_opp, &opp_table->opp_list, node) { |
| 537 | if (temp_opp->available) { | 536 | if (temp_opp->available) { |
| @@ -547,6 +546,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev, | |||
| 547 | if (!IS_ERR(opp)) | 546 | if (!IS_ERR(opp)) |
| 548 | dev_pm_opp_get(opp); | 547 | dev_pm_opp_get(opp); |
| 549 | rcu_read_unlock(); | 548 | rcu_read_unlock(); |
| 549 | dev_pm_opp_put_opp_table(opp_table); | ||
| 550 | 550 | ||
| 551 | if (!IS_ERR(opp)) | 551 | if (!IS_ERR(opp)) |
| 552 | *freq = opp->rate; | 552 | *freq = opp->rate; |
| @@ -564,22 +564,18 @@ static struct clk *_get_opp_clk(struct device *dev) | |||
| 564 | struct opp_table *opp_table; | 564 | struct opp_table *opp_table; |
| 565 | struct clk *clk; | 565 | struct clk *clk; |
| 566 | 566 | ||
| 567 | rcu_read_lock(); | ||
| 568 | |||
| 569 | opp_table = _find_opp_table(dev); | 567 | opp_table = _find_opp_table(dev); |
| 570 | if (IS_ERR(opp_table)) { | 568 | if (IS_ERR(opp_table)) { |
| 571 | dev_err(dev, "%s: device opp doesn't exist\n", __func__); | 569 | dev_err(dev, "%s: device opp doesn't exist\n", __func__); |
| 572 | clk = ERR_CAST(opp_table); | 570 | return ERR_CAST(opp_table); |
| 573 | goto unlock; | ||
| 574 | } | 571 | } |
| 575 | 572 | ||
| 576 | clk = opp_table->clk; | 573 | clk = opp_table->clk; |
| 577 | if (IS_ERR(clk)) | 574 | if (IS_ERR(clk)) |
| 578 | dev_err(dev, "%s: No clock available for the device\n", | 575 | dev_err(dev, "%s: No clock available for the device\n", |
| 579 | __func__); | 576 | __func__); |
| 577 | dev_pm_opp_put_opp_table(opp_table); | ||
| 580 | 578 | ||
| 581 | unlock: | ||
| 582 | rcu_read_unlock(); | ||
| 583 | return clk; | 579 | return clk; |
| 584 | } | 580 | } |
| 585 | 581 | ||
| @@ -715,15 +711,14 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) | |||
| 715 | return 0; | 711 | return 0; |
| 716 | } | 712 | } |
| 717 | 713 | ||
| 718 | rcu_read_lock(); | ||
| 719 | |||
| 720 | opp_table = _find_opp_table(dev); | 714 | opp_table = _find_opp_table(dev); |
| 721 | if (IS_ERR(opp_table)) { | 715 | if (IS_ERR(opp_table)) { |
| 722 | dev_err(dev, "%s: device opp doesn't exist\n", __func__); | 716 | dev_err(dev, "%s: device opp doesn't exist\n", __func__); |
| 723 | rcu_read_unlock(); | ||
| 724 | return PTR_ERR(opp_table); | 717 | return PTR_ERR(opp_table); |
| 725 | } | 718 | } |
| 726 | 719 | ||
| 720 | rcu_read_lock(); | ||
| 721 | |||
| 727 | old_opp = _find_freq_ceil(opp_table, &old_freq); | 722 | old_opp = _find_freq_ceil(opp_table, &old_freq); |
| 728 | if (IS_ERR(old_opp)) { | 723 | if (IS_ERR(old_opp)) { |
| 729 | dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n", | 724 | dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n", |
| @@ -738,6 +733,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) | |||
| 738 | if (!IS_ERR(old_opp)) | 733 | if (!IS_ERR(old_opp)) |
| 739 | dev_pm_opp_put(old_opp); | 734 | dev_pm_opp_put(old_opp); |
| 740 | rcu_read_unlock(); | 735 | rcu_read_unlock(); |
| 736 | dev_pm_opp_put_opp_table(opp_table); | ||
| 741 | return ret; | 737 | return ret; |
| 742 | } | 738 | } |
| 743 | 739 | ||
| @@ -752,6 +748,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) | |||
| 752 | if (!IS_ERR(old_opp)) | 748 | if (!IS_ERR(old_opp)) |
| 753 | dev_pm_opp_put(old_opp); | 749 | dev_pm_opp_put(old_opp); |
| 754 | rcu_read_unlock(); | 750 | rcu_read_unlock(); |
| 751 | dev_pm_opp_put_opp_table(opp_table); | ||
| 755 | return _generic_set_opp_clk_only(dev, clk, old_freq, freq); | 752 | return _generic_set_opp_clk_only(dev, clk, old_freq, freq); |
| 756 | } | 753 | } |
| 757 | 754 | ||
| @@ -780,6 +777,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) | |||
| 780 | if (!IS_ERR(old_opp)) | 777 | if (!IS_ERR(old_opp)) |
| 781 | dev_pm_opp_put(old_opp); | 778 | dev_pm_opp_put(old_opp); |
| 782 | rcu_read_unlock(); | 779 | rcu_read_unlock(); |
| 780 | dev_pm_opp_put_opp_table(opp_table); | ||
| 783 | 781 | ||
| 784 | return set_opp(data); | 782 | return set_opp(data); |
| 785 | } | 783 | } |
| @@ -893,11 +891,9 @@ struct opp_table *dev_pm_opp_get_opp_table(struct device *dev) | |||
| 893 | /* Hold our table modification lock here */ | 891 | /* Hold our table modification lock here */ |
| 894 | mutex_lock(&opp_table_lock); | 892 | mutex_lock(&opp_table_lock); |
| 895 | 893 | ||
| 896 | opp_table = _find_opp_table(dev); | 894 | opp_table = _find_opp_table_unlocked(dev); |
| 897 | if (!IS_ERR(opp_table)) { | 895 | if (!IS_ERR(opp_table)) |
| 898 | _get_opp_table_kref(opp_table); | ||
| 899 | goto unlock; | 896 | goto unlock; |
| 900 | } | ||
| 901 | 897 | ||
| 902 | opp_table = _allocate_opp_table(dev); | 898 | opp_table = _allocate_opp_table(dev); |
| 903 | 899 | ||
| @@ -1004,12 +1000,9 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) | |||
| 1004 | struct opp_table *opp_table; | 1000 | struct opp_table *opp_table; |
| 1005 | bool found = false; | 1001 | bool found = false; |
| 1006 | 1002 | ||
| 1007 | /* Hold our table modification lock here */ | ||
| 1008 | mutex_lock(&opp_table_lock); | ||
| 1009 | |||
| 1010 | opp_table = _find_opp_table(dev); | 1003 | opp_table = _find_opp_table(dev); |
| 1011 | if (IS_ERR(opp_table)) | 1004 | if (IS_ERR(opp_table)) |
| 1012 | goto unlock; | 1005 | return; |
| 1013 | 1006 | ||
| 1014 | mutex_lock(&opp_table->lock); | 1007 | mutex_lock(&opp_table->lock); |
| 1015 | 1008 | ||
| @@ -1022,15 +1015,14 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq) | |||
| 1022 | 1015 | ||
| 1023 | mutex_unlock(&opp_table->lock); | 1016 | mutex_unlock(&opp_table->lock); |
| 1024 | 1017 | ||
| 1025 | if (!found) { | 1018 | if (found) { |
| 1019 | dev_pm_opp_put(opp); | ||
| 1020 | } else { | ||
| 1026 | dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n", | 1021 | dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n", |
| 1027 | __func__, freq); | 1022 | __func__, freq); |
| 1028 | goto unlock; | ||
| 1029 | } | 1023 | } |
| 1030 | 1024 | ||
| 1031 | dev_pm_opp_put(opp); | 1025 | dev_pm_opp_put_opp_table(opp_table); |
| 1032 | unlock: | ||
| 1033 | mutex_unlock(&opp_table_lock); | ||
| 1034 | } | 1026 | } |
| 1035 | EXPORT_SYMBOL_GPL(dev_pm_opp_remove); | 1027 | EXPORT_SYMBOL_GPL(dev_pm_opp_remove); |
| 1036 | 1028 | ||
| @@ -1648,14 +1640,12 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, | |||
| 1648 | if (!new_opp) | 1640 | if (!new_opp) |
| 1649 | return -ENOMEM; | 1641 | return -ENOMEM; |
| 1650 | 1642 | ||
| 1651 | mutex_lock(&opp_table_lock); | ||
| 1652 | |||
| 1653 | /* Find the opp_table */ | 1643 | /* Find the opp_table */ |
| 1654 | opp_table = _find_opp_table(dev); | 1644 | opp_table = _find_opp_table(dev); |
| 1655 | if (IS_ERR(opp_table)) { | 1645 | if (IS_ERR(opp_table)) { |
| 1656 | r = PTR_ERR(opp_table); | 1646 | r = PTR_ERR(opp_table); |
| 1657 | dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); | 1647 | dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r); |
| 1658 | goto unlock; | 1648 | goto free_opp; |
| 1659 | } | 1649 | } |
| 1660 | 1650 | ||
| 1661 | mutex_lock(&opp_table->lock); | 1651 | mutex_lock(&opp_table->lock); |
| @@ -1668,8 +1658,6 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, | |||
| 1668 | } | 1658 | } |
| 1669 | } | 1659 | } |
| 1670 | 1660 | ||
| 1671 | mutex_unlock(&opp_table->lock); | ||
| 1672 | |||
| 1673 | if (IS_ERR(opp)) { | 1661 | if (IS_ERR(opp)) { |
| 1674 | r = PTR_ERR(opp); | 1662 | r = PTR_ERR(opp); |
| 1675 | goto unlock; | 1663 | goto unlock; |
| @@ -1685,7 +1673,6 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, | |||
| 1685 | new_opp->available = availability_req; | 1673 | new_opp->available = availability_req; |
| 1686 | 1674 | ||
| 1687 | list_replace_rcu(&opp->node, &new_opp->node); | 1675 | list_replace_rcu(&opp->node, &new_opp->node); |
| 1688 | mutex_unlock(&opp_table_lock); | ||
| 1689 | call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); | 1676 | call_srcu(&opp_table->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu); |
| 1690 | 1677 | ||
| 1691 | /* Notify the change of the OPP availability */ | 1678 | /* Notify the change of the OPP availability */ |
| @@ -1696,10 +1683,14 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, | |||
| 1696 | srcu_notifier_call_chain(&opp_table->srcu_head, | 1683 | srcu_notifier_call_chain(&opp_table->srcu_head, |
| 1697 | OPP_EVENT_DISABLE, new_opp); | 1684 | OPP_EVENT_DISABLE, new_opp); |
| 1698 | 1685 | ||
| 1686 | mutex_unlock(&opp_table->lock); | ||
| 1687 | dev_pm_opp_put_opp_table(opp_table); | ||
| 1699 | return 0; | 1688 | return 0; |
| 1700 | 1689 | ||
| 1701 | unlock: | 1690 | unlock: |
| 1702 | mutex_unlock(&opp_table_lock); | 1691 | mutex_unlock(&opp_table->lock); |
| 1692 | dev_pm_opp_put_opp_table(opp_table); | ||
| 1693 | free_opp: | ||
| 1703 | kfree(new_opp); | 1694 | kfree(new_opp); |
| 1704 | return r; | 1695 | return r; |
| 1705 | } | 1696 | } |
| @@ -1767,18 +1758,16 @@ int dev_pm_opp_register_notifier(struct device *dev, struct notifier_block *nb) | |||
| 1767 | struct opp_table *opp_table; | 1758 | struct opp_table *opp_table; |
| 1768 | int ret; | 1759 | int ret; |
| 1769 | 1760 | ||
| 1770 | rcu_read_lock(); | ||
| 1771 | |||
| 1772 | opp_table = _find_opp_table(dev); | 1761 | opp_table = _find_opp_table(dev); |
| 1773 | if (IS_ERR(opp_table)) { | 1762 | if (IS_ERR(opp_table)) |
| 1774 | ret = PTR_ERR(opp_table); | 1763 | return PTR_ERR(opp_table); |
| 1775 | goto unlock; | 1764 | |
| 1776 | } | 1765 | rcu_read_lock(); |
| 1777 | 1766 | ||
| 1778 | ret = srcu_notifier_chain_register(&opp_table->srcu_head, nb); | 1767 | ret = srcu_notifier_chain_register(&opp_table->srcu_head, nb); |
| 1779 | 1768 | ||
| 1780 | unlock: | ||
| 1781 | rcu_read_unlock(); | 1769 | rcu_read_unlock(); |
| 1770 | dev_pm_opp_put_opp_table(opp_table); | ||
| 1782 | 1771 | ||
| 1783 | return ret; | 1772 | return ret; |
| 1784 | } | 1773 | } |
| @@ -1797,18 +1786,14 @@ int dev_pm_opp_unregister_notifier(struct device *dev, | |||
| 1797 | struct opp_table *opp_table; | 1786 | struct opp_table *opp_table; |
| 1798 | int ret; | 1787 | int ret; |
| 1799 | 1788 | ||
| 1800 | rcu_read_lock(); | ||
| 1801 | |||
| 1802 | opp_table = _find_opp_table(dev); | 1789 | opp_table = _find_opp_table(dev); |
| 1803 | if (IS_ERR(opp_table)) { | 1790 | if (IS_ERR(opp_table)) |
| 1804 | ret = PTR_ERR(opp_table); | 1791 | return PTR_ERR(opp_table); |
| 1805 | goto unlock; | ||
| 1806 | } | ||
| 1807 | 1792 | ||
| 1808 | ret = srcu_notifier_chain_unregister(&opp_table->srcu_head, nb); | 1793 | ret = srcu_notifier_chain_unregister(&opp_table->srcu_head, nb); |
| 1809 | 1794 | ||
| 1810 | unlock: | ||
| 1811 | rcu_read_unlock(); | 1795 | rcu_read_unlock(); |
| 1796 | dev_pm_opp_put_opp_table(opp_table); | ||
| 1812 | 1797 | ||
| 1813 | return ret; | 1798 | return ret; |
| 1814 | } | 1799 | } |
| @@ -1839,9 +1824,6 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all) | |||
| 1839 | { | 1824 | { |
| 1840 | struct opp_table *opp_table; | 1825 | struct opp_table *opp_table; |
| 1841 | 1826 | ||
| 1842 | /* Hold our table modification lock here */ | ||
| 1843 | mutex_lock(&opp_table_lock); | ||
| 1844 | |||
| 1845 | /* Check for existing table for 'dev' */ | 1827 | /* Check for existing table for 'dev' */ |
| 1846 | opp_table = _find_opp_table(dev); | 1828 | opp_table = _find_opp_table(dev); |
| 1847 | if (IS_ERR(opp_table)) { | 1829 | if (IS_ERR(opp_table)) { |
| @@ -1852,13 +1834,12 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev, bool remove_all) | |||
| 1852 | IS_ERR_OR_NULL(dev) ? | 1834 | IS_ERR_OR_NULL(dev) ? |
| 1853 | "Invalid device" : dev_name(dev), | 1835 | "Invalid device" : dev_name(dev), |
| 1854 | error); | 1836 | error); |
| 1855 | goto unlock; | 1837 | return; |
| 1856 | } | 1838 | } |
| 1857 | 1839 | ||
| 1858 | _dev_pm_opp_remove_table(opp_table, dev, remove_all); | 1840 | _dev_pm_opp_remove_table(opp_table, dev, remove_all); |
| 1859 | 1841 | ||
| 1860 | unlock: | 1842 | dev_pm_opp_put_opp_table(opp_table); |
| 1861 | mutex_unlock(&opp_table_lock); | ||
| 1862 | } | 1843 | } |
| 1863 | 1844 | ||
| 1864 | /** | 1845 | /** |
diff --git a/drivers/base/power/opp/cpu.c b/drivers/base/power/opp/cpu.c index adef788862d5..df29f08eecc4 100644 --- a/drivers/base/power/opp/cpu.c +++ b/drivers/base/power/opp/cpu.c | |||
| @@ -174,13 +174,9 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, | |||
| 174 | struct device *dev; | 174 | struct device *dev; |
| 175 | int cpu, ret = 0; | 175 | int cpu, ret = 0; |
| 176 | 176 | ||
| 177 | mutex_lock(&opp_table_lock); | ||
| 178 | |||
| 179 | opp_table = _find_opp_table(cpu_dev); | 177 | opp_table = _find_opp_table(cpu_dev); |
| 180 | if (IS_ERR(opp_table)) { | 178 | if (IS_ERR(opp_table)) |
| 181 | ret = PTR_ERR(opp_table); | 179 | return PTR_ERR(opp_table); |
| 182 | goto unlock; | ||
| 183 | } | ||
| 184 | 180 | ||
| 185 | for_each_cpu(cpu, cpumask) { | 181 | for_each_cpu(cpu, cpumask) { |
| 186 | if (cpu == cpu_dev->id) | 182 | if (cpu == cpu_dev->id) |
| @@ -203,8 +199,8 @@ int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, | |||
| 203 | /* Mark opp-table as multiple CPUs are sharing it now */ | 199 | /* Mark opp-table as multiple CPUs are sharing it now */ |
| 204 | opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; | 200 | opp_table->shared_opp = OPP_TABLE_ACCESS_SHARED; |
| 205 | } | 201 | } |
| 206 | unlock: | 202 | |
| 207 | mutex_unlock(&opp_table_lock); | 203 | dev_pm_opp_put_opp_table(opp_table); |
| 208 | 204 | ||
| 209 | return ret; | 205 | return ret; |
| 210 | } | 206 | } |
| @@ -232,17 +228,13 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) | |||
| 232 | struct opp_table *opp_table; | 228 | struct opp_table *opp_table; |
| 233 | int ret = 0; | 229 | int ret = 0; |
| 234 | 230 | ||
| 235 | mutex_lock(&opp_table_lock); | ||
| 236 | |||
| 237 | opp_table = _find_opp_table(cpu_dev); | 231 | opp_table = _find_opp_table(cpu_dev); |
| 238 | if (IS_ERR(opp_table)) { | 232 | if (IS_ERR(opp_table)) |
| 239 | ret = PTR_ERR(opp_table); | 233 | return PTR_ERR(opp_table); |
| 240 | goto unlock; | ||
| 241 | } | ||
| 242 | 234 | ||
| 243 | if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) { | 235 | if (opp_table->shared_opp == OPP_TABLE_ACCESS_UNKNOWN) { |
| 244 | ret = -EINVAL; | 236 | ret = -EINVAL; |
| 245 | goto unlock; | 237 | goto put_opp_table; |
| 246 | } | 238 | } |
| 247 | 239 | ||
| 248 | cpumask_clear(cpumask); | 240 | cpumask_clear(cpumask); |
| @@ -254,8 +246,8 @@ int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) | |||
| 254 | cpumask_set_cpu(cpu_dev->id, cpumask); | 246 | cpumask_set_cpu(cpu_dev->id, cpumask); |
| 255 | } | 247 | } |
| 256 | 248 | ||
| 257 | unlock: | 249 | put_opp_table: |
| 258 | mutex_unlock(&opp_table_lock); | 250 | dev_pm_opp_put_opp_table(opp_table); |
| 259 | 251 | ||
| 260 | return ret; | 252 | return ret; |
| 261 | } | 253 | } |
