Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thermal: cpu_cooling: Switch to QoS requests for freq limits

The cpufreq core now takes the min/max frequency constraints via QoS
requests and the CPUFREQ_ADJUST notifier shall get removed later on.

Switch over to using the QoS request for maximum frequency constraint
for cpu_cooling driver.

Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
[ rjw: Subject ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Viresh Kumar and committed by
Rafael J. Wysocki
5130802d 6a149036

+26 -84
+26 -84
drivers/thermal/cpu_cooling.c
··· 16 16 #include <linux/err.h> 17 17 #include <linux/idr.h> 18 18 #include <linux/pm_opp.h> 19 + #include <linux/pm_qos.h> 19 20 #include <linux/slab.h> 20 21 #include <linux/cpu.h> 21 22 #include <linux/cpu_cooling.h> ··· 67 66 * @last_load: load measured by the latest call to cpufreq_get_requested_power() 68 67 * @cpufreq_state: integer value representing the current state of cpufreq 69 68 * cooling devices. 70 - * @clipped_freq: integer value representing the absolute value of the clipped 71 - * frequency. 72 69 * @max_level: maximum cooling level. One less than total number of valid 73 70 * cpufreq frequencies. 74 71 * @freq_table: Freq table in descending order of frequencies ··· 83 84 int id; 84 85 u32 last_load; 85 86 unsigned int cpufreq_state; 86 - unsigned int clipped_freq; 87 87 unsigned int max_level; 88 88 struct freq_table *freq_table; /* In descending order */ 89 89 struct cpufreq_policy *policy; 90 90 struct list_head node; 91 91 struct time_in_idle *idle_time; 92 + struct dev_pm_qos_request qos_req; 92 93 }; 93 94 94 95 static DEFINE_IDA(cpufreq_ida); ··· 115 116 break; 116 117 117 118 return level - 1; 118 - } 119 - 120 - /** 121 - * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. 122 - * @nb: struct notifier_block * with callback info. 123 - * @event: value showing cpufreq event for which this function invoked. 124 - * @data: callback-specific data 125 - * 126 - * Callback to hijack the notification on cpufreq policy transition. 127 - * Every time there is a change in policy, we will intercept and 128 - * update the cpufreq policy with thermal constraints. 129 - * 130 - * Return: 0 (success) 131 - */ 132 - static int cpufreq_thermal_notifier(struct notifier_block *nb, 133 - unsigned long event, void *data) 134 - { 135 - struct cpufreq_policy *policy = data; 136 - unsigned long clipped_freq; 137 - struct cpufreq_cooling_device *cpufreq_cdev; 138 - 139 - if (event != CPUFREQ_ADJUST) 140 - return NOTIFY_DONE; 141 - 142 - mutex_lock(&cooling_list_lock); 143 - list_for_each_entry(cpufreq_cdev, &cpufreq_cdev_list, node) { 144 - /* 145 - * A new copy of the policy is sent to the notifier and can't 146 - * compare that directly. 147 - */ 148 - if (policy->cpu != cpufreq_cdev->policy->cpu) 149 - continue; 150 - 151 - /* 152 - * policy->max is the maximum allowed frequency defined by user 153 - * and clipped_freq is the maximum that thermal constraints 154 - * allow. 155 - * 156 - * If clipped_freq is lower than policy->max, then we need to 157 - * readjust policy->max. 158 - * 159 - * But, if clipped_freq is greater than policy->max, we don't 160 - * need to do anything. 161 - */ 162 - clipped_freq = cpufreq_cdev->clipped_freq; 163 - 164 - if (policy->max > clipped_freq) 165 - cpufreq_verify_within_limits(policy, 0, clipped_freq); 166 - break; 167 - } 168 - mutex_unlock(&cooling_list_lock); 169 - 170 - return NOTIFY_OK; 171 119 } 172 120 173 121 /** ··· 320 374 unsigned long state) 321 375 { 322 376 struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata; 323 - unsigned int clip_freq; 324 377 325 378 /* Request state should be less than max_level */ 326 379 if (WARN_ON(state > cpufreq_cdev->max_level)) ··· 329 384 if (cpufreq_cdev->cpufreq_state == state) 330 385 return 0; 331 386 332 - clip_freq = cpufreq_cdev->freq_table[state].frequency; 333 387 cpufreq_cdev->cpufreq_state = state; 334 - cpufreq_cdev->clipped_freq = clip_freq; 335 388 336 - cpufreq_update_policy(cpufreq_cdev->policy->cpu); 337 - 338 - return 0; 389 + return dev_pm_qos_update_request(&cpufreq_cdev->qos_req, 390 + cpufreq_cdev->freq_table[state].frequency); 339 391 } 340 392 341 393 /** ··· 496 554 .power2state = cpufreq_power2state, 497 555 }; 498 556 499 - /* Notifier for cpufreq policy change */ 500 - static struct notifier_block thermal_cpufreq_notifier_block = { 501 - .notifier_call = cpufreq_thermal_notifier, 502 - }; 503 - 504 557 static unsigned int find_next_max(struct cpufreq_frequency_table *table, 505 558 unsigned int prev_max) 506 559 { ··· 533 596 struct cpufreq_cooling_device *cpufreq_cdev; 534 597 char dev_name[THERMAL_NAME_LENGTH]; 535 598 unsigned int freq, i, num_cpus; 599 + struct device *dev; 536 600 int ret; 537 601 struct thermal_cooling_device_ops *cooling_ops; 538 - bool first; 602 + 603 + dev = get_cpu_device(policy->cpu); 604 + if (unlikely(!dev)) { 605 + pr_warn("No cpu device for cpu %d\n", policy->cpu); 606 + return ERR_PTR(-ENODEV); 607 + } 608 + 539 609 540 610 if (IS_ERR_OR_NULL(policy)) { 541 611 pr_err("%s: cpufreq policy isn't valid: %p\n", __func__, policy); ··· 615 671 cooling_ops = &cpufreq_cooling_ops; 616 672 } 617 673 674 + ret = dev_pm_qos_add_request(dev, &cpufreq_cdev->qos_req, 675 + DEV_PM_QOS_MAX_FREQUENCY, 676 + cpufreq_cdev->freq_table[0].frequency); 677 + if (ret < 0) { 678 + pr_err("%s: Failed to add freq constraint (%d)\n", __func__, 679 + ret); 680 + cdev = ERR_PTR(ret); 681 + goto remove_ida; 682 + } 683 + 618 684 cdev = thermal_of_cooling_device_register(np, dev_name, cpufreq_cdev, 619 685 cooling_ops); 620 686 if (IS_ERR(cdev)) 621 - goto remove_ida; 622 - 623 - cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency; 687 + goto remove_qos_req; 624 688 625 689 mutex_lock(&cooling_list_lock); 626 - /* Register the notifier for first cpufreq cooling device */ 627 - first = list_empty(&cpufreq_cdev_list); 628 690 list_add(&cpufreq_cdev->node, &cpufreq_cdev_list); 629 691 mutex_unlock(&cooling_list_lock); 630 692 631 - if (first) 632 - cpufreq_register_notifier(&thermal_cpufreq_notifier_block, 633 - CPUFREQ_POLICY_NOTIFIER); 634 - 635 693 return cdev; 636 694 695 + remove_qos_req: 696 + dev_pm_qos_remove_request(&cpufreq_cdev->qos_req); 637 697 remove_ida: 638 698 ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); 639 699 free_table: ··· 725 777 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 726 778 { 727 779 struct cpufreq_cooling_device *cpufreq_cdev; 728 - bool last; 729 780 730 781 if (!cdev) 731 782 return; ··· 733 786 734 787 mutex_lock(&cooling_list_lock); 735 788 list_del(&cpufreq_cdev->node); 736 - /* Unregister the notifier for the last cpufreq cooling device */ 737 - last = list_empty(&cpufreq_cdev_list); 738 789 mutex_unlock(&cooling_list_lock); 739 790 740 - if (last) 741 - cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, 742 - CPUFREQ_POLICY_NOTIFIER); 743 - 744 791 thermal_cooling_device_unregister(cdev); 792 + dev_pm_qos_remove_request(&cpufreq_cdev->qos_req); 745 793 ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); 746 794 kfree(cpufreq_cdev->idle_time); 747 795 kfree(cpufreq_cdev->freq_table);