Loading Documentation/devicetree/bindings/arm/msm/msm_thermal.txt +27 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,29 @@ Optional properties - qcpm,cpu-sensors: List of type names in thermal zone device struct which maps to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many cpus there are. - qcom,freq-mitigation-temp: Threshold temperature to mitigate the CPU max frequency in degC. This will be used when polling based frequency control is disabled. The difference between freq-mitigation-temp and limit-temp is that limit-temp is used during early boot prior to thermal_sys being available for registering temperature thresholds. Also, this emergency frequency mitigation is a single step frequency mitigation to a predefined value as opposed to the step by step frequency mitigation during boot-up. - qcom,freq-mitigation-temp-hysteresis: Degrees C below which thermal will not mitigate the cpu max frequency. - qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal should mitigate the CPU, when the freq-mitigation-temp threshold is reached. - qcom,freq-mitigation-control-mask: The frequency mitigation bitmask that will be used to determine if KTM should do emergency frequency mitigation for a core or not. A mask of 0x00 indicates the mitigation is disabled for all the cores and a mask of 0x05 indicates this mitigation is enabled for cpu-0 and cpu-2. Note: For KTM's frequency mitigation to work, the data for all the above four properties (qcom,freq-mitigation-temp; qcom, freq-mitigation-temp-hysteresis; qcom,freq-mitigation-value and qcom,freq-mitigation-control-mask) should be populated. - qcom,vdd-restriction-temp: When temperature is below this threshold, will enable vdd restriction which will set higher voltage on key voltage rails, in degC. Loading Loading @@ -97,6 +120,10 @@ Example: qcom,hotplug-temp-hysteresis = <20>; qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6", "tsens_tz_sensor7", "tsens_tz_sensor8"; qcom,freq-mitigation-temp = <110>; qcom,freq-mitigation-temp-hysteresis = <20>; qcom,freq-mitigation-value = <960000>; qcom,freq-mitigation-control-mask = <0x01>; qcom,pmic-sw-mode-temp = <90>; qcom,pmic-sw-mode-temp-hysteresis = <80>; qcom,pmic-sw-mode-regs = "vdd-dig"; Loading drivers/thermal/msm_thermal.c +271 −79 Original line number Diff line number Diff line Loading @@ -40,8 +40,6 @@ #define MAX_THRESHOLD 2 static struct msm_thermal_data msm_thermal_info; static uint32_t limited_max_freq = UINT_MAX; static uint32_t limited_min_freq; static struct delayed_work check_temp_work; static bool core_control_enabled; static uint32_t cpus_offlined; Loading @@ -52,7 +50,9 @@ static struct kobject *tt_kobj; static struct kobject *cc_kobj; static struct work_struct timer_work; static struct task_struct *hotplug_task; static struct task_struct *freq_mitigation_task; static struct completion hotplug_notify_complete; static struct completion freq_mitigation_complete; static int enabled; static int rails_cnt; Loading @@ -70,18 +70,32 @@ static bool vdd_rstr_probed; static bool psm_enabled; static bool psm_nodes_called; static bool psm_probed; static bool freq_mitigation_enabled; static int *tsens_id_map; static DEFINE_MUTEX(vdd_rstr_mutex); static DEFINE_MUTEX(psm_mutex); static uint32_t min_freq_limit; enum thermal_threshold { HOTPLUG_THRESHOLD_HIGH, HOTPLUG_THRESHOLD_LOW, FREQ_THRESHOLD_HIGH, FREQ_THRESHOLD_LOW, THRESHOLD_MAX_NR, }; struct cpu_info { uint32_t cpu; bool offline; bool user_offline; bool thresh_cleared; const char *sensor_type; uint32_t sensor_id; struct sensor_threshold thresh[MAX_THRESHOLD]; bool offline; bool user_offline; bool hotplug_thresh_clear; struct sensor_threshold threshold[THRESHOLD_MAX_NR]; bool max_freq; uint32_t limited_max_freq; uint32_t limited_min_freq; bool freq_thresh_clear; }; struct rail { Loading Loading @@ -162,11 +176,20 @@ static int msm_thermal_cpufreq_callback(struct notifier_block *nfb, unsigned long event, void *data) { struct cpufreq_policy *policy = data; uint32_t max_freq_req = cpus[policy->cpu].limited_max_freq; uint32_t min_freq_req = cpus[policy->cpu].limited_min_freq; switch (event) { case CPUFREQ_INCOMPATIBLE: cpufreq_verify_within_limits(policy, limited_min_freq, limited_max_freq); pr_debug("%s: mitigating cpu %d to freq max: %u min: %u\n", KBUILD_MODNAME, policy->cpu, max_freq_req, min_freq_req); cpufreq_verify_within_limits(policy, min_freq_req, max_freq_req); if (max_freq_req < min_freq_req) pr_err("Invalid frequency request Max:%u Min:%u\n", max_freq_req, min_freq_req); break; } return NOTIFY_OK; Loading @@ -192,9 +215,17 @@ static int check_freq_table(void) return ret; } static void update_cpu_freq(int cpu) { if (cpu_online(cpu)) { if (cpufreq_update_policy(cpu)) pr_err("Unable to update policy for cpu:%d\n", cpu); } } static int update_cpu_min_freq_all(uint32_t min) { int cpu = 0; uint32_t cpu = 0; int ret = 0; if (!freq_table_get) { Loading @@ -207,15 +238,17 @@ static int update_cpu_min_freq_all(uint32_t min) /* If min is larger than allowed max */ min = min(min, table[limit_idx_high].frequency); limited_min_freq = min; if (freq_mitigation_task) { min_freq_limit = min; complete(&freq_mitigation_complete); } else { get_online_cpus(); for_each_online_cpu(cpu) { if (cpufreq_update_policy(cpu)) pr_info("%s: Unable to update policy for cpu:%d\n", KBUILD_MODNAME, cpu); for_each_possible_cpu(cpu) { cpus[cpu].limited_min_freq = min; update_cpu_freq(cpu); } put_online_cpus(); } return ret; } Loading Loading @@ -606,27 +639,6 @@ fail: return ret; } static int update_cpu_max_freq(int cpu, uint32_t max_freq) { int ret = 0; if (max_freq != UINT_MAX) pr_info("%s: Limiting cpu%d max frequency to %d\n", KBUILD_MODNAME, cpu, max_freq); else pr_info("%s: Max frequency reset for cpu%d\n", KBUILD_MODNAME, cpu); get_online_cpus(); for_each_online_cpu(cpu) { if (cpufreq_update_policy(cpu)) pr_info("%s: Unable to update policy for cpu:%d\n", KBUILD_MODNAME, cpu); } put_online_cpus(); return ret; } static int set_and_activate_threshold(uint32_t sensor_id, struct sensor_threshold *threshold) { Loading Loading @@ -786,10 +798,11 @@ static __ref int do_hotplug(void *data) mutex_lock(&core_control_mutex); for_each_possible_cpu(cpu) { if (cpus[cpu].thresh_cleared) { if (cpus[cpu].hotplug_thresh_clear) { set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh); cpus[cpu].thresh_cleared = false; &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH]); cpus[cpu].hotplug_thresh_clear = false; } if (cpus[cpu].offline || cpus[cpu].user_offline) mask |= BIT(cpu); Loading Loading @@ -913,14 +926,14 @@ exit: static void do_freq_control(long temp) { int cpu = 0; uint32_t max_freq = limited_max_freq; uint32_t cpu = 0; uint32_t max_freq = cpus[cpu].limited_max_freq; if (temp >= msm_thermal_info.limit_temp_degC) { if (limit_idx == limit_idx_low) return; limit_idx -= msm_thermal_info.freq_step; limit_idx -= msm_thermal_info.bootup_freq_step; if (limit_idx < limit_idx_low) limit_idx = limit_idx_low; max_freq = table[limit_idx].frequency; Loading @@ -929,7 +942,7 @@ static void do_freq_control(long temp) if (limit_idx == limit_idx_high) return; limit_idx += msm_thermal_info.freq_step; limit_idx += msm_thermal_info.bootup_freq_step; if (limit_idx >= limit_idx_high) { limit_idx = limit_idx_high; max_freq = UINT_MAX; Loading @@ -937,16 +950,18 @@ static void do_freq_control(long temp) max_freq = table[limit_idx].frequency; } if (max_freq == limited_max_freq) if (max_freq == cpus[cpu].limited_max_freq) return; limited_max_freq = max_freq; /* Update new limits */ get_online_cpus(); for_each_possible_cpu(cpu) { if (!(msm_thermal_info.freq_control_mask & BIT(cpu))) if (!(msm_thermal_info.bootup_freq_control_mask & BIT(cpu))) continue; update_cpu_max_freq(cpu, max_freq); cpus[cpu].limited_max_freq = max_freq; update_cpu_freq(cpu); } put_online_cpus(); } static void check_temp(struct work_struct *work) Loading Loading @@ -986,7 +1001,7 @@ reschedule: static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; uint32_t cpu = (uint32_t)hcpu; if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) { if (core_control_enabled && Loading Loading @@ -1058,7 +1073,7 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data) break; } if (hotplug_task) { cpu_node->thresh_cleared = true; cpu_node->hotplug_thresh_clear = true; complete(&hotplug_notify_complete); } else pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME); Loading @@ -1069,7 +1084,7 @@ static int hotplug_init_cpu_offlined(void) { struct tsens_device tsens_dev; long temp = 0; int cpu = 0; uint32_t cpu = 0; mutex_lock(&core_control_mutex); for_each_possible_cpu(cpu) { Loading Loading @@ -1102,29 +1117,29 @@ static int hotplug_init_cpu_offlined(void) static void hotplug_init(void) { int cpu = 0; uint32_t cpu = 0; struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL; if (hotplug_task) return; for_each_possible_cpu(cpu) { cpus[cpu].cpu = (uint32_t)cpu; cpus[cpu].thresh_cleared = false; cpus[cpu].sensor_id = sensor_get_id((char *)cpus[cpu].sensor_type); if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) continue; cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC; cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; cpus[cpu].thresh[0].notify = hotplug_notify; cpus[cpu].thresh[0].data = (void *)&cpus[cpu]; cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC - hi_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH]; low_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_LOW]; hi_thresh->temp = msm_thermal_info.hotplug_temp_degC; hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI; low_thresh->temp = msm_thermal_info.hotplug_temp_degC - msm_thermal_info.hotplug_temp_hysteresis_degC; cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW; cpus[cpu].thresh[1].notify = hotplug_notify; cpus[cpu].thresh[1].data = (void *)&cpus[cpu]; set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh); low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW; hi_thresh->notify = low_thresh->notify = hotplug_notify; hi_thresh->data = low_thresh->data = (void *)&cpus[cpu]; set_threshold(cpus[cpu].sensor_id, hi_thresh); } init_completion(&hotplug_notify_complete); hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug"); Loading @@ -1141,6 +1156,124 @@ static void hotplug_init(void) kthread_stop(hotplug_task); } static __ref int do_freq_mitigation(void *data) { int ret = 0; uint32_t cpu = 0, max_freq_req = 0; while (!kthread_should_stop()) { wait_for_completion(&freq_mitigation_complete); INIT_COMPLETION(freq_mitigation_complete); get_online_cpus(); for_each_possible_cpu(cpu) { max_freq_req = (cpus[cpu].max_freq) ? msm_thermal_info.freq_limit : UINT_MAX; if ((max_freq_req == cpus[cpu].limited_max_freq) && (min_freq_limit == cpus[cpu].limited_min_freq)) goto reset_threshold; cpus[cpu].limited_max_freq = max_freq_req; cpus[cpu].limited_min_freq = min_freq_limit; update_cpu_freq(cpu); reset_threshold: if (cpus[cpu].freq_thresh_clear) { set_threshold(cpus[cpu].sensor_id, &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]); cpus[cpu].freq_thresh_clear = false; } } put_online_cpus(); } return ret; } static int freq_mitigation_notify(enum thermal_trip_type type, int temp, void *data) { struct cpu_info *cpu_node = (struct cpu_info *) data; pr_debug("%s: %s reached temp threshold: %d\n", KBUILD_MODNAME, cpu_node->sensor_type, temp); if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu_node->cpu))) return 0; switch (type) { case THERMAL_TRIP_CONFIGURABLE_HI: if (!cpu_node->max_freq) { pr_info("%s: Mitigating cpu %d frequency to %d\n", KBUILD_MODNAME, cpu_node->cpu, msm_thermal_info.freq_limit); cpu_node->max_freq = true; } break; case THERMAL_TRIP_CONFIGURABLE_LOW: if (cpu_node->max_freq) { pr_info("%s: Removing frequency mitigation for cpu%d\n", KBUILD_MODNAME, cpu_node->cpu); cpu_node->max_freq = false; } break; default: break; } if (freq_mitigation_task) { cpu_node->freq_thresh_clear = true; complete(&freq_mitigation_complete); } else { pr_err("%s: Frequency mitigation task is not initialized\n", KBUILD_MODNAME); } return 0; } static void freq_mitigation_init(void) { uint32_t cpu = 0; struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL; if (!freq_mitigation_enabled || freq_mitigation_task) return; for_each_possible_cpu(cpu) { if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu))) continue; hi_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]; low_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_LOW]; hi_thresh->temp = msm_thermal_info.freq_mitig_temp_degc; hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI; low_thresh->temp = msm_thermal_info.freq_mitig_temp_degc - msm_thermal_info.freq_mitig_temp_hysteresis_degc; low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW; hi_thresh->notify = low_thresh->notify = freq_mitigation_notify; hi_thresh->data = low_thresh->data = (void *)&cpus[cpu]; set_threshold(cpus[cpu].sensor_id, hi_thresh); } init_completion(&freq_mitigation_complete); freq_mitigation_task = kthread_run(do_freq_mitigation, NULL, "msm_thermal:freq_mitig"); if (IS_ERR(freq_mitigation_task)) { pr_err("%s: Failed to create frequency mitigation thread\n", KBUILD_MODNAME); return; } } /* * We will reset the cpu frequencies limits here. The core online/offline * status will be carried over to the process stopping the msm_thermal, as Loading @@ -1148,21 +1281,20 @@ static void hotplug_init(void) */ static void __ref disable_msm_thermal(void) { int cpu = 0; uint32_t cpu = 0; /* make sure check_temp is no longer running */ cancel_delayed_work(&check_temp_work); flush_scheduled_work(); if (limited_max_freq == UINT_MAX) return; limited_max_freq = UINT_MAX; get_online_cpus(); for_each_online_cpu(cpu) { if (cpufreq_update_policy(cpu)) pr_info("%s: Unable to update policy for cpu:%d\n", KBUILD_MODNAME, cpu); for_each_possible_cpu(cpu) { if (cpus[cpu].limited_max_freq == UINT_MAX && cpus[cpu].limited_min_freq == 0) continue; cpus[cpu].limited_max_freq = UINT_MAX; cpus[cpu].limited_min_freq = 0; update_cpu_freq(cpu); } put_online_cpus(); } Loading @@ -1175,6 +1307,7 @@ static int __ref set_enabled(const char *val, const struct kernel_param *kp) if (!enabled) { disable_msm_thermal(); hotplug_init(); freq_mitigation_init(); } else pr_info("%s: no action for enabled = %d\n", KBUILD_MODNAME, enabled); Loading Loading @@ -1242,7 +1375,7 @@ static ssize_t __ref store_cpus_offlined(struct kobject *kobj, { int ret = 0; uint32_t val = 0; int cpu; uint32_t cpu; mutex_lock(&core_control_mutex); ret = kstrtouint(buf, 10, &val); Loading Loading @@ -1407,6 +1540,7 @@ failed: int msm_thermal_init(struct msm_thermal_data *pdata) { int ret = 0; uint32_t cpu; BUG_ON(!pdata); tsens_get_max_sensor_num(&max_tsens_num); Loading @@ -1418,7 +1552,10 @@ int msm_thermal_init(struct msm_thermal_data *pdata) return -EINVAL; enabled = 1; for_each_possible_cpu(cpu) { cpus[cpu].limited_max_freq = UINT_MAX; cpus[cpu].limited_min_freq = 0; } ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier, CPUFREQ_POLICY_NOTIFIER); if (ret) Loading Loading @@ -1839,9 +1976,9 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data, struct platform_device *pdev) { char *key = NULL; int cpu_cnt = 0; uint32_t cpu_cnt = 0; int ret = 0; int cpu = 0; uint32_t cpu = 0; key = "qcom,core-limit-temp"; ret = of_property_read_u32(node, key, &data->core_limit_temp_degC); Loading Loading @@ -1880,6 +2017,7 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data, cpus[cpu].cpu = cpu; cpus[cpu].offline = 0; cpus[cpu].user_offline = 0; cpus[cpu].hotplug_thresh_clear = false; ret = of_property_read_string_index(node, key, cpu, &cpus[cpu].sensor_type); if (ret) Loading @@ -1900,6 +2038,53 @@ read_node_fail: return ret; } static int probe_freq_mitigation(struct device_node *node, struct msm_thermal_data *data, struct platform_device *pdev) { char *key = NULL; int ret = 0; uint32_t cpu; key = "qcom,freq-mitigation-temp"; ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc); if (ret) goto PROBE_FREQ_EXIT; key = "qcom,freq-mitigation-temp-hysteresis"; ret = of_property_read_u32(node, key, &data->freq_mitig_temp_hysteresis_degc); if (ret) goto PROBE_FREQ_EXIT; key = "qcom,freq-mitigation-value"; ret = of_property_read_u32(node, key, &data->freq_limit); if (ret) goto PROBE_FREQ_EXIT; key = "qcom,freq-mitigation-control-mask"; ret = of_property_read_u32(node, key, &data->freq_mitig_control_mask); if (ret) goto PROBE_FREQ_EXIT; freq_mitigation_enabled = 1; for_each_possible_cpu(cpu) { cpus[cpu].max_freq = false; cpus[cpu].limited_max_freq = UINT_MAX; cpus[cpu].limited_min_freq = 0; cpus[cpu].freq_thresh_clear = false; } PROBE_FREQ_EXIT: if (ret) { dev_info(&pdev->dev, "%s:Failed reading node=%s, key=%s. KTM continues\n", __func__, node->full_name, key); freq_mitigation_enabled = 0; } return ret; } static int msm_thermal_dev_probe(struct platform_device *pdev) { int ret = 0; Loading Loading @@ -1930,14 +2115,16 @@ static int msm_thermal_dev_probe(struct platform_device *pdev) goto fail; key = "qcom,freq-step"; ret = of_property_read_u32(node, key, &data.freq_step); ret = of_property_read_u32(node, key, &data.bootup_freq_step); if (ret) goto fail; key = "qcom,freq-control-mask"; ret = of_property_read_u32(node, key, &data.freq_control_mask); ret = of_property_read_u32(node, key, &data.bootup_freq_control_mask); ret = probe_cc(node, &data, pdev); ret = probe_freq_mitigation(node, &data, pdev); /* * Probe optional properties below. Call probe_psm before * probe_vdd_rstr because rpm_regulator_get has to be called Loading Loading @@ -1973,6 +2160,10 @@ fail: return ret; } static int msm_thermal_dev_exit(struct platform_device *inp_dev) { return 0; } static struct of_device_id msm_thermal_match_table[] = { {.compatible = "qcom,msm-thermal"}, Loading @@ -1986,6 +2177,7 @@ static struct platform_driver msm_thermal_device_driver = { .owner = THIS_MODULE, .of_match_table = msm_thermal_match_table, }, .remove = msm_thermal_dev_exit, }; int __init msm_thermal_device_init(void) Loading include/linux/msm_thermal.h +6 −2 Original line number Diff line number Diff line Loading @@ -19,13 +19,17 @@ struct msm_thermal_data { uint32_t poll_ms; int32_t limit_temp_degC; int32_t temp_hysteresis_degC; uint32_t freq_step; uint32_t freq_control_mask; uint32_t bootup_freq_step; uint32_t bootup_freq_control_mask; int32_t core_limit_temp_degC; int32_t core_temp_hysteresis_degC; int32_t hotplug_temp_degC; int32_t hotplug_temp_hysteresis_degC; uint32_t core_control_mask; uint32_t freq_mitig_temp_degc; uint32_t freq_mitig_temp_hysteresis_degc; uint32_t freq_mitig_control_mask; uint32_t freq_limit; int32_t vdd_rstr_temp_degC; int32_t vdd_rstr_temp_hyst_degC; int32_t psm_temp_degC; Loading Loading
Documentation/devicetree/bindings/arm/msm/msm_thermal.txt +27 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,29 @@ Optional properties - qcpm,cpu-sensors: List of type names in thermal zone device struct which maps to cpu0, cpu1, cpu2, cpu3 in sequence depending on how many cpus there are. - qcom,freq-mitigation-temp: Threshold temperature to mitigate the CPU max frequency in degC. This will be used when polling based frequency control is disabled. The difference between freq-mitigation-temp and limit-temp is that limit-temp is used during early boot prior to thermal_sys being available for registering temperature thresholds. Also, this emergency frequency mitigation is a single step frequency mitigation to a predefined value as opposed to the step by step frequency mitigation during boot-up. - qcom,freq-mitigation-temp-hysteresis: Degrees C below which thermal will not mitigate the cpu max frequency. - qcom,freq-mitigation-value: The frequency value (in kHz) to which the thermal should mitigate the CPU, when the freq-mitigation-temp threshold is reached. - qcom,freq-mitigation-control-mask: The frequency mitigation bitmask that will be used to determine if KTM should do emergency frequency mitigation for a core or not. A mask of 0x00 indicates the mitigation is disabled for all the cores and a mask of 0x05 indicates this mitigation is enabled for cpu-0 and cpu-2. Note: For KTM's frequency mitigation to work, the data for all the above four properties (qcom,freq-mitigation-temp; qcom, freq-mitigation-temp-hysteresis; qcom,freq-mitigation-value and qcom,freq-mitigation-control-mask) should be populated. - qcom,vdd-restriction-temp: When temperature is below this threshold, will enable vdd restriction which will set higher voltage on key voltage rails, in degC. Loading Loading @@ -97,6 +120,10 @@ Example: qcom,hotplug-temp-hysteresis = <20>; qcom,cpu-sensors = "tsens_tz_sensor5", "tsens_tz_sensor6", "tsens_tz_sensor7", "tsens_tz_sensor8"; qcom,freq-mitigation-temp = <110>; qcom,freq-mitigation-temp-hysteresis = <20>; qcom,freq-mitigation-value = <960000>; qcom,freq-mitigation-control-mask = <0x01>; qcom,pmic-sw-mode-temp = <90>; qcom,pmic-sw-mode-temp-hysteresis = <80>; qcom,pmic-sw-mode-regs = "vdd-dig"; Loading
drivers/thermal/msm_thermal.c +271 −79 Original line number Diff line number Diff line Loading @@ -40,8 +40,6 @@ #define MAX_THRESHOLD 2 static struct msm_thermal_data msm_thermal_info; static uint32_t limited_max_freq = UINT_MAX; static uint32_t limited_min_freq; static struct delayed_work check_temp_work; static bool core_control_enabled; static uint32_t cpus_offlined; Loading @@ -52,7 +50,9 @@ static struct kobject *tt_kobj; static struct kobject *cc_kobj; static struct work_struct timer_work; static struct task_struct *hotplug_task; static struct task_struct *freq_mitigation_task; static struct completion hotplug_notify_complete; static struct completion freq_mitigation_complete; static int enabled; static int rails_cnt; Loading @@ -70,18 +70,32 @@ static bool vdd_rstr_probed; static bool psm_enabled; static bool psm_nodes_called; static bool psm_probed; static bool freq_mitigation_enabled; static int *tsens_id_map; static DEFINE_MUTEX(vdd_rstr_mutex); static DEFINE_MUTEX(psm_mutex); static uint32_t min_freq_limit; enum thermal_threshold { HOTPLUG_THRESHOLD_HIGH, HOTPLUG_THRESHOLD_LOW, FREQ_THRESHOLD_HIGH, FREQ_THRESHOLD_LOW, THRESHOLD_MAX_NR, }; struct cpu_info { uint32_t cpu; bool offline; bool user_offline; bool thresh_cleared; const char *sensor_type; uint32_t sensor_id; struct sensor_threshold thresh[MAX_THRESHOLD]; bool offline; bool user_offline; bool hotplug_thresh_clear; struct sensor_threshold threshold[THRESHOLD_MAX_NR]; bool max_freq; uint32_t limited_max_freq; uint32_t limited_min_freq; bool freq_thresh_clear; }; struct rail { Loading Loading @@ -162,11 +176,20 @@ static int msm_thermal_cpufreq_callback(struct notifier_block *nfb, unsigned long event, void *data) { struct cpufreq_policy *policy = data; uint32_t max_freq_req = cpus[policy->cpu].limited_max_freq; uint32_t min_freq_req = cpus[policy->cpu].limited_min_freq; switch (event) { case CPUFREQ_INCOMPATIBLE: cpufreq_verify_within_limits(policy, limited_min_freq, limited_max_freq); pr_debug("%s: mitigating cpu %d to freq max: %u min: %u\n", KBUILD_MODNAME, policy->cpu, max_freq_req, min_freq_req); cpufreq_verify_within_limits(policy, min_freq_req, max_freq_req); if (max_freq_req < min_freq_req) pr_err("Invalid frequency request Max:%u Min:%u\n", max_freq_req, min_freq_req); break; } return NOTIFY_OK; Loading @@ -192,9 +215,17 @@ static int check_freq_table(void) return ret; } static void update_cpu_freq(int cpu) { if (cpu_online(cpu)) { if (cpufreq_update_policy(cpu)) pr_err("Unable to update policy for cpu:%d\n", cpu); } } static int update_cpu_min_freq_all(uint32_t min) { int cpu = 0; uint32_t cpu = 0; int ret = 0; if (!freq_table_get) { Loading @@ -207,15 +238,17 @@ static int update_cpu_min_freq_all(uint32_t min) /* If min is larger than allowed max */ min = min(min, table[limit_idx_high].frequency); limited_min_freq = min; if (freq_mitigation_task) { min_freq_limit = min; complete(&freq_mitigation_complete); } else { get_online_cpus(); for_each_online_cpu(cpu) { if (cpufreq_update_policy(cpu)) pr_info("%s: Unable to update policy for cpu:%d\n", KBUILD_MODNAME, cpu); for_each_possible_cpu(cpu) { cpus[cpu].limited_min_freq = min; update_cpu_freq(cpu); } put_online_cpus(); } return ret; } Loading Loading @@ -606,27 +639,6 @@ fail: return ret; } static int update_cpu_max_freq(int cpu, uint32_t max_freq) { int ret = 0; if (max_freq != UINT_MAX) pr_info("%s: Limiting cpu%d max frequency to %d\n", KBUILD_MODNAME, cpu, max_freq); else pr_info("%s: Max frequency reset for cpu%d\n", KBUILD_MODNAME, cpu); get_online_cpus(); for_each_online_cpu(cpu) { if (cpufreq_update_policy(cpu)) pr_info("%s: Unable to update policy for cpu:%d\n", KBUILD_MODNAME, cpu); } put_online_cpus(); return ret; } static int set_and_activate_threshold(uint32_t sensor_id, struct sensor_threshold *threshold) { Loading Loading @@ -786,10 +798,11 @@ static __ref int do_hotplug(void *data) mutex_lock(&core_control_mutex); for_each_possible_cpu(cpu) { if (cpus[cpu].thresh_cleared) { if (cpus[cpu].hotplug_thresh_clear) { set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh); cpus[cpu].thresh_cleared = false; &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH]); cpus[cpu].hotplug_thresh_clear = false; } if (cpus[cpu].offline || cpus[cpu].user_offline) mask |= BIT(cpu); Loading Loading @@ -913,14 +926,14 @@ exit: static void do_freq_control(long temp) { int cpu = 0; uint32_t max_freq = limited_max_freq; uint32_t cpu = 0; uint32_t max_freq = cpus[cpu].limited_max_freq; if (temp >= msm_thermal_info.limit_temp_degC) { if (limit_idx == limit_idx_low) return; limit_idx -= msm_thermal_info.freq_step; limit_idx -= msm_thermal_info.bootup_freq_step; if (limit_idx < limit_idx_low) limit_idx = limit_idx_low; max_freq = table[limit_idx].frequency; Loading @@ -929,7 +942,7 @@ static void do_freq_control(long temp) if (limit_idx == limit_idx_high) return; limit_idx += msm_thermal_info.freq_step; limit_idx += msm_thermal_info.bootup_freq_step; if (limit_idx >= limit_idx_high) { limit_idx = limit_idx_high; max_freq = UINT_MAX; Loading @@ -937,16 +950,18 @@ static void do_freq_control(long temp) max_freq = table[limit_idx].frequency; } if (max_freq == limited_max_freq) if (max_freq == cpus[cpu].limited_max_freq) return; limited_max_freq = max_freq; /* Update new limits */ get_online_cpus(); for_each_possible_cpu(cpu) { if (!(msm_thermal_info.freq_control_mask & BIT(cpu))) if (!(msm_thermal_info.bootup_freq_control_mask & BIT(cpu))) continue; update_cpu_max_freq(cpu, max_freq); cpus[cpu].limited_max_freq = max_freq; update_cpu_freq(cpu); } put_online_cpus(); } static void check_temp(struct work_struct *work) Loading Loading @@ -986,7 +1001,7 @@ reschedule: static int __ref msm_thermal_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; uint32_t cpu = (uint32_t)hcpu; if (action == CPU_UP_PREPARE || action == CPU_UP_PREPARE_FROZEN) { if (core_control_enabled && Loading Loading @@ -1058,7 +1073,7 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data) break; } if (hotplug_task) { cpu_node->thresh_cleared = true; cpu_node->hotplug_thresh_clear = true; complete(&hotplug_notify_complete); } else pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME); Loading @@ -1069,7 +1084,7 @@ static int hotplug_init_cpu_offlined(void) { struct tsens_device tsens_dev; long temp = 0; int cpu = 0; uint32_t cpu = 0; mutex_lock(&core_control_mutex); for_each_possible_cpu(cpu) { Loading Loading @@ -1102,29 +1117,29 @@ static int hotplug_init_cpu_offlined(void) static void hotplug_init(void) { int cpu = 0; uint32_t cpu = 0; struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL; if (hotplug_task) return; for_each_possible_cpu(cpu) { cpus[cpu].cpu = (uint32_t)cpu; cpus[cpu].thresh_cleared = false; cpus[cpu].sensor_id = sensor_get_id((char *)cpus[cpu].sensor_type); if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu))) continue; cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC; cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI; cpus[cpu].thresh[0].notify = hotplug_notify; cpus[cpu].thresh[0].data = (void *)&cpus[cpu]; cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC - hi_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_HIGH]; low_thresh = &cpus[cpu].threshold[HOTPLUG_THRESHOLD_LOW]; hi_thresh->temp = msm_thermal_info.hotplug_temp_degC; hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI; low_thresh->temp = msm_thermal_info.hotplug_temp_degC - msm_thermal_info.hotplug_temp_hysteresis_degC; cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW; cpus[cpu].thresh[1].notify = hotplug_notify; cpus[cpu].thresh[1].data = (void *)&cpus[cpu]; set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh); low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW; hi_thresh->notify = low_thresh->notify = hotplug_notify; hi_thresh->data = low_thresh->data = (void *)&cpus[cpu]; set_threshold(cpus[cpu].sensor_id, hi_thresh); } init_completion(&hotplug_notify_complete); hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug"); Loading @@ -1141,6 +1156,124 @@ static void hotplug_init(void) kthread_stop(hotplug_task); } static __ref int do_freq_mitigation(void *data) { int ret = 0; uint32_t cpu = 0, max_freq_req = 0; while (!kthread_should_stop()) { wait_for_completion(&freq_mitigation_complete); INIT_COMPLETION(freq_mitigation_complete); get_online_cpus(); for_each_possible_cpu(cpu) { max_freq_req = (cpus[cpu].max_freq) ? msm_thermal_info.freq_limit : UINT_MAX; if ((max_freq_req == cpus[cpu].limited_max_freq) && (min_freq_limit == cpus[cpu].limited_min_freq)) goto reset_threshold; cpus[cpu].limited_max_freq = max_freq_req; cpus[cpu].limited_min_freq = min_freq_limit; update_cpu_freq(cpu); reset_threshold: if (cpus[cpu].freq_thresh_clear) { set_threshold(cpus[cpu].sensor_id, &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]); cpus[cpu].freq_thresh_clear = false; } } put_online_cpus(); } return ret; } static int freq_mitigation_notify(enum thermal_trip_type type, int temp, void *data) { struct cpu_info *cpu_node = (struct cpu_info *) data; pr_debug("%s: %s reached temp threshold: %d\n", KBUILD_MODNAME, cpu_node->sensor_type, temp); if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu_node->cpu))) return 0; switch (type) { case THERMAL_TRIP_CONFIGURABLE_HI: if (!cpu_node->max_freq) { pr_info("%s: Mitigating cpu %d frequency to %d\n", KBUILD_MODNAME, cpu_node->cpu, msm_thermal_info.freq_limit); cpu_node->max_freq = true; } break; case THERMAL_TRIP_CONFIGURABLE_LOW: if (cpu_node->max_freq) { pr_info("%s: Removing frequency mitigation for cpu%d\n", KBUILD_MODNAME, cpu_node->cpu); cpu_node->max_freq = false; } break; default: break; } if (freq_mitigation_task) { cpu_node->freq_thresh_clear = true; complete(&freq_mitigation_complete); } else { pr_err("%s: Frequency mitigation task is not initialized\n", KBUILD_MODNAME); } return 0; } static void freq_mitigation_init(void) { uint32_t cpu = 0; struct sensor_threshold *hi_thresh = NULL, *low_thresh = NULL; if (!freq_mitigation_enabled || freq_mitigation_task) return; for_each_possible_cpu(cpu) { if (!(msm_thermal_info.freq_mitig_control_mask & BIT(cpu))) continue; hi_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_HIGH]; low_thresh = &cpus[cpu].threshold[FREQ_THRESHOLD_LOW]; hi_thresh->temp = msm_thermal_info.freq_mitig_temp_degc; hi_thresh->trip = THERMAL_TRIP_CONFIGURABLE_HI; low_thresh->temp = msm_thermal_info.freq_mitig_temp_degc - msm_thermal_info.freq_mitig_temp_hysteresis_degc; low_thresh->trip = THERMAL_TRIP_CONFIGURABLE_LOW; hi_thresh->notify = low_thresh->notify = freq_mitigation_notify; hi_thresh->data = low_thresh->data = (void *)&cpus[cpu]; set_threshold(cpus[cpu].sensor_id, hi_thresh); } init_completion(&freq_mitigation_complete); freq_mitigation_task = kthread_run(do_freq_mitigation, NULL, "msm_thermal:freq_mitig"); if (IS_ERR(freq_mitigation_task)) { pr_err("%s: Failed to create frequency mitigation thread\n", KBUILD_MODNAME); return; } } /* * We will reset the cpu frequencies limits here. The core online/offline * status will be carried over to the process stopping the msm_thermal, as Loading @@ -1148,21 +1281,20 @@ static void hotplug_init(void) */ static void __ref disable_msm_thermal(void) { int cpu = 0; uint32_t cpu = 0; /* make sure check_temp is no longer running */ cancel_delayed_work(&check_temp_work); flush_scheduled_work(); if (limited_max_freq == UINT_MAX) return; limited_max_freq = UINT_MAX; get_online_cpus(); for_each_online_cpu(cpu) { if (cpufreq_update_policy(cpu)) pr_info("%s: Unable to update policy for cpu:%d\n", KBUILD_MODNAME, cpu); for_each_possible_cpu(cpu) { if (cpus[cpu].limited_max_freq == UINT_MAX && cpus[cpu].limited_min_freq == 0) continue; cpus[cpu].limited_max_freq = UINT_MAX; cpus[cpu].limited_min_freq = 0; update_cpu_freq(cpu); } put_online_cpus(); } Loading @@ -1175,6 +1307,7 @@ static int __ref set_enabled(const char *val, const struct kernel_param *kp) if (!enabled) { disable_msm_thermal(); hotplug_init(); freq_mitigation_init(); } else pr_info("%s: no action for enabled = %d\n", KBUILD_MODNAME, enabled); Loading Loading @@ -1242,7 +1375,7 @@ static ssize_t __ref store_cpus_offlined(struct kobject *kobj, { int ret = 0; uint32_t val = 0; int cpu; uint32_t cpu; mutex_lock(&core_control_mutex); ret = kstrtouint(buf, 10, &val); Loading Loading @@ -1407,6 +1540,7 @@ failed: int msm_thermal_init(struct msm_thermal_data *pdata) { int ret = 0; uint32_t cpu; BUG_ON(!pdata); tsens_get_max_sensor_num(&max_tsens_num); Loading @@ -1418,7 +1552,10 @@ int msm_thermal_init(struct msm_thermal_data *pdata) return -EINVAL; enabled = 1; for_each_possible_cpu(cpu) { cpus[cpu].limited_max_freq = UINT_MAX; cpus[cpu].limited_min_freq = 0; } ret = cpufreq_register_notifier(&msm_thermal_cpufreq_notifier, CPUFREQ_POLICY_NOTIFIER); if (ret) Loading Loading @@ -1839,9 +1976,9 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data, struct platform_device *pdev) { char *key = NULL; int cpu_cnt = 0; uint32_t cpu_cnt = 0; int ret = 0; int cpu = 0; uint32_t cpu = 0; key = "qcom,core-limit-temp"; ret = of_property_read_u32(node, key, &data->core_limit_temp_degC); Loading Loading @@ -1880,6 +2017,7 @@ static int probe_cc(struct device_node *node, struct msm_thermal_data *data, cpus[cpu].cpu = cpu; cpus[cpu].offline = 0; cpus[cpu].user_offline = 0; cpus[cpu].hotplug_thresh_clear = false; ret = of_property_read_string_index(node, key, cpu, &cpus[cpu].sensor_type); if (ret) Loading @@ -1900,6 +2038,53 @@ read_node_fail: return ret; } static int probe_freq_mitigation(struct device_node *node, struct msm_thermal_data *data, struct platform_device *pdev) { char *key = NULL; int ret = 0; uint32_t cpu; key = "qcom,freq-mitigation-temp"; ret = of_property_read_u32(node, key, &data->freq_mitig_temp_degc); if (ret) goto PROBE_FREQ_EXIT; key = "qcom,freq-mitigation-temp-hysteresis"; ret = of_property_read_u32(node, key, &data->freq_mitig_temp_hysteresis_degc); if (ret) goto PROBE_FREQ_EXIT; key = "qcom,freq-mitigation-value"; ret = of_property_read_u32(node, key, &data->freq_limit); if (ret) goto PROBE_FREQ_EXIT; key = "qcom,freq-mitigation-control-mask"; ret = of_property_read_u32(node, key, &data->freq_mitig_control_mask); if (ret) goto PROBE_FREQ_EXIT; freq_mitigation_enabled = 1; for_each_possible_cpu(cpu) { cpus[cpu].max_freq = false; cpus[cpu].limited_max_freq = UINT_MAX; cpus[cpu].limited_min_freq = 0; cpus[cpu].freq_thresh_clear = false; } PROBE_FREQ_EXIT: if (ret) { dev_info(&pdev->dev, "%s:Failed reading node=%s, key=%s. KTM continues\n", __func__, node->full_name, key); freq_mitigation_enabled = 0; } return ret; } static int msm_thermal_dev_probe(struct platform_device *pdev) { int ret = 0; Loading Loading @@ -1930,14 +2115,16 @@ static int msm_thermal_dev_probe(struct platform_device *pdev) goto fail; key = "qcom,freq-step"; ret = of_property_read_u32(node, key, &data.freq_step); ret = of_property_read_u32(node, key, &data.bootup_freq_step); if (ret) goto fail; key = "qcom,freq-control-mask"; ret = of_property_read_u32(node, key, &data.freq_control_mask); ret = of_property_read_u32(node, key, &data.bootup_freq_control_mask); ret = probe_cc(node, &data, pdev); ret = probe_freq_mitigation(node, &data, pdev); /* * Probe optional properties below. Call probe_psm before * probe_vdd_rstr because rpm_regulator_get has to be called Loading Loading @@ -1973,6 +2160,10 @@ fail: return ret; } static int msm_thermal_dev_exit(struct platform_device *inp_dev) { return 0; } static struct of_device_id msm_thermal_match_table[] = { {.compatible = "qcom,msm-thermal"}, Loading @@ -1986,6 +2177,7 @@ static struct platform_driver msm_thermal_device_driver = { .owner = THIS_MODULE, .of_match_table = msm_thermal_match_table, }, .remove = msm_thermal_dev_exit, }; int __init msm_thermal_device_init(void) Loading
include/linux/msm_thermal.h +6 −2 Original line number Diff line number Diff line Loading @@ -19,13 +19,17 @@ struct msm_thermal_data { uint32_t poll_ms; int32_t limit_temp_degC; int32_t temp_hysteresis_degC; uint32_t freq_step; uint32_t freq_control_mask; uint32_t bootup_freq_step; uint32_t bootup_freq_control_mask; int32_t core_limit_temp_degC; int32_t core_temp_hysteresis_degC; int32_t hotplug_temp_degC; int32_t hotplug_temp_hysteresis_degC; uint32_t core_control_mask; uint32_t freq_mitig_temp_degc; uint32_t freq_mitig_temp_hysteresis_degc; uint32_t freq_mitig_control_mask; uint32_t freq_limit; int32_t vdd_rstr_temp_degC; int32_t vdd_rstr_temp_hyst_degC; int32_t psm_temp_degC; Loading