diff options
-rw-r--r-- | drivers/thermal/cpu_cooling.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 7687922cb02e..cb5a4b914187 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c | |||
@@ -65,6 +65,7 @@ struct cpufreq_cooling_device { | |||
65 | unsigned int cpufreq_state; | 65 | unsigned int cpufreq_state; |
66 | unsigned int cpufreq_val; | 66 | unsigned int cpufreq_val; |
67 | unsigned int max_level; | 67 | unsigned int max_level; |
68 | unsigned int *freq_table; /* In descending order */ | ||
68 | struct cpumask allowed_cpus; | 69 | struct cpumask allowed_cpus; |
69 | struct list_head node; | 70 | struct list_head node; |
70 | }; | 71 | }; |
@@ -352,6 +353,20 @@ static struct notifier_block thermal_cpufreq_notifier_block = { | |||
352 | .notifier_call = cpufreq_thermal_notifier, | 353 | .notifier_call = cpufreq_thermal_notifier, |
353 | }; | 354 | }; |
354 | 355 | ||
356 | static unsigned int find_next_max(struct cpufreq_frequency_table *table, | ||
357 | unsigned int prev_max) | ||
358 | { | ||
359 | struct cpufreq_frequency_table *pos; | ||
360 | unsigned int max = 0; | ||
361 | |||
362 | cpufreq_for_each_valid_entry(pos, table) { | ||
363 | if (pos->frequency > max && pos->frequency < prev_max) | ||
364 | max = pos->frequency; | ||
365 | } | ||
366 | |||
367 | return max; | ||
368 | } | ||
369 | |||
355 | /** | 370 | /** |
356 | * __cpufreq_cooling_register - helper function to create cpufreq cooling device | 371 | * __cpufreq_cooling_register - helper function to create cpufreq cooling device |
357 | * @np: a valid struct device_node to the cooling device device tree node | 372 | * @np: a valid struct device_node to the cooling device device tree node |
@@ -374,6 +389,7 @@ __cpufreq_cooling_register(struct device_node *np, | |||
374 | struct cpufreq_cooling_device *cpufreq_dev; | 389 | struct cpufreq_cooling_device *cpufreq_dev; |
375 | char dev_name[THERMAL_NAME_LENGTH]; | 390 | char dev_name[THERMAL_NAME_LENGTH]; |
376 | struct cpufreq_frequency_table *pos, *table; | 391 | struct cpufreq_frequency_table *pos, *table; |
392 | unsigned int freq, i; | ||
377 | int ret; | 393 | int ret; |
378 | 394 | ||
379 | table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); | 395 | table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); |
@@ -397,6 +413,14 @@ __cpufreq_cooling_register(struct device_node *np, | |||
397 | cpufreq_for_each_valid_entry(pos, table) | 413 | cpufreq_for_each_valid_entry(pos, table) |
398 | cpufreq_dev->max_level++; | 414 | cpufreq_dev->max_level++; |
399 | 415 | ||
416 | cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) * | ||
417 | cpufreq_dev->max_level, GFP_KERNEL); | ||
418 | if (!cpufreq_dev->freq_table) { | ||
419 | return ERR_PTR(-ENOMEM); | ||
420 | cool_dev = ERR_PTR(-ENOMEM); | ||
421 | goto free_cdev; | ||
422 | } | ||
423 | |||
400 | /* max_level is an index, not a counter */ | 424 | /* max_level is an index, not a counter */ |
401 | cpufreq_dev->max_level--; | 425 | cpufreq_dev->max_level--; |
402 | 426 | ||
@@ -405,7 +429,7 @@ __cpufreq_cooling_register(struct device_node *np, | |||
405 | ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); | 429 | ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); |
406 | if (ret) { | 430 | if (ret) { |
407 | cool_dev = ERR_PTR(ret); | 431 | cool_dev = ERR_PTR(ret); |
408 | goto free_cdev; | 432 | goto free_table; |
409 | } | 433 | } |
410 | 434 | ||
411 | snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", | 435 | snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", |
@@ -416,6 +440,18 @@ __cpufreq_cooling_register(struct device_node *np, | |||
416 | if (IS_ERR(cool_dev)) | 440 | if (IS_ERR(cool_dev)) |
417 | goto remove_idr; | 441 | goto remove_idr; |
418 | 442 | ||
443 | /* Fill freq-table in descending order of frequencies */ | ||
444 | for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { | ||
445 | freq = find_next_max(table, freq); | ||
446 | cpufreq_dev->freq_table[i] = freq; | ||
447 | |||
448 | /* Warn for duplicate entries */ | ||
449 | if (!freq) | ||
450 | pr_warn("%s: table has duplicate entries\n", __func__); | ||
451 | else | ||
452 | pr_debug("%s: freq:%u KHz\n", __func__, freq); | ||
453 | } | ||
454 | |||
419 | cpufreq_dev->cool_dev = cool_dev; | 455 | cpufreq_dev->cool_dev = cool_dev; |
420 | 456 | ||
421 | mutex_lock(&cooling_cpufreq_lock); | 457 | mutex_lock(&cooling_cpufreq_lock); |
@@ -432,6 +468,8 @@ __cpufreq_cooling_register(struct device_node *np, | |||
432 | 468 | ||
433 | remove_idr: | 469 | remove_idr: |
434 | release_idr(&cpufreq_idr, cpufreq_dev->id); | 470 | release_idr(&cpufreq_idr, cpufreq_dev->id); |
471 | free_table: | ||
472 | kfree(cpufreq_dev->freq_table); | ||
435 | free_cdev: | 473 | free_cdev: |
436 | kfree(cpufreq_dev); | 474 | kfree(cpufreq_dev); |
437 | 475 | ||
@@ -505,6 +543,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) | |||
505 | 543 | ||
506 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); | 544 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); |
507 | release_idr(&cpufreq_idr, cpufreq_dev->id); | 545 | release_idr(&cpufreq_idr, cpufreq_dev->id); |
546 | kfree(cpufreq_dev->freq_table); | ||
508 | kfree(cpufreq_dev); | 547 | kfree(cpufreq_dev); |
509 | } | 548 | } |
510 | EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); | 549 | EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); |