msm: Add frequency backoff to thermal monitor
Make thermal monitor performance hit more gradual by stepping down
limit frequency instead of jumping directly to that frequency.
The monitor now steps down to the lowest available cpufreq
frequency, instead of fixing the limit frequency to 918MHz. Also
update the polling frequency to 250ms to improve responsiveness.
Change-Id: I6edb0cfc057284023978de04d7835e9783da5ebd
Signed-off-by: Eugene Seah <eseah@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index d3af1a7..ce1c829 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -1751,10 +1751,10 @@
static struct msm_thermal_data msm_thermal_pdata = {
.sensor_id = 7,
- .poll_ms = 1000,
- .limit_temp = 60,
- .temp_hysteresis = 10,
- .limit_freq = 918000,
+ .poll_ms = 250,
+ .limit_temp_degC = 60,
+ .temp_hysteresis_degC = 10,
+ .freq_step = 2,
};
#define MSM_SHARED_RAM_PHYS 0x80000000
diff --git a/arch/arm/mach-msm/board-8930.c b/arch/arm/mach-msm/board-8930.c
index 9110849..ed0cc82 100644
--- a/arch/arm/mach-msm/board-8930.c
+++ b/arch/arm/mach-msm/board-8930.c
@@ -2095,10 +2095,10 @@
static struct msm_thermal_data msm_thermal_pdata = {
.sensor_id = 9,
- .poll_ms = 1000,
- .limit_temp = 60,
- .temp_hysteresis = 10,
- .limit_freq = 918000,
+ .poll_ms = 250,
+ .limit_temp_degC = 60,
+ .temp_hysteresis_degC = 10,
+ .freq_step = 2,
};
#ifdef CONFIG_MSM_FAKE_BATTERY
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index 251123b..63eef4a 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -2382,10 +2382,10 @@
static struct msm_thermal_data msm_thermal_pdata = {
.sensor_id = 0,
- .poll_ms = 1000,
- .limit_temp = 60,
- .temp_hysteresis = 10,
- .limit_freq = 918000,
+ .poll_ms = 250,
+ .limit_temp_degC = 60,
+ .temp_hysteresis_degC = 10,
+ .freq_step = 2,
};
#ifdef CONFIG_MSM_FAKE_BATTERY
diff --git a/drivers/thermal/msm_thermal.c b/drivers/thermal/msm_thermal.c
index a8d3720..0575d80 100644
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -28,6 +28,33 @@
static uint32_t limited_max_freq = MSM_CPUFREQ_NO_LIMIT;
static struct delayed_work check_temp_work;
+static int limit_idx;
+static int limit_idx_low;
+static int limit_idx_high;
+static struct cpufreq_frequency_table *table;
+
+static int msm_thermal_get_freq_table(void)
+{
+ int ret = 0;
+ int i = 0;
+
+ table = cpufreq_frequency_get_table(0);
+ if (table == NULL) {
+ pr_debug("%s: error reading cpufreq table\n", __func__);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ while (table[i].frequency != CPUFREQ_TABLE_END)
+ i++;
+
+ limit_idx_low = 0;
+ limit_idx_high = limit_idx = i - 1;
+ BUG_ON(limit_idx_high <= 0 || limit_idx_high <= limit_idx_low);
+fail:
+ return ret;
+}
+
static int update_cpu_max_freq(int cpu, uint32_t max_freq)
{
int ret = 0;
@@ -36,10 +63,6 @@
if (ret)
return ret;
- ret = cpufreq_update_policy(cpu);
- if (ret)
- return ret;
-
limited_max_freq = max_freq;
if (max_freq != MSM_CPUFREQ_NO_LIMIT)
pr_info("msm_thermal: Limiting cpu%d max frequency to %d\n",
@@ -47,11 +70,14 @@
else
pr_info("msm_thermal: Max frequency reset for cpu%d\n", cpu);
+ ret = cpufreq_update_policy(cpu);
+
return ret;
}
static void check_temp(struct work_struct *work)
{
+ static int limit_init;
struct tsens_device tsens_dev;
unsigned long temp = 0;
uint32_t max_freq = limited_max_freq;
@@ -66,12 +92,34 @@
goto reschedule;
}
- if (temp >= msm_thermal_info.limit_temp)
- max_freq = msm_thermal_info.limit_freq;
- else if (temp <
- msm_thermal_info.limit_temp - msm_thermal_info.temp_hysteresis)
- max_freq = MSM_CPUFREQ_NO_LIMIT;
+ if (!limit_init) {
+ ret = msm_thermal_get_freq_table();
+ if (ret)
+ goto reschedule;
+ else
+ limit_init = 1;
+ }
+ if (temp >= msm_thermal_info.limit_temp_degC) {
+ if (limit_idx == limit_idx_low)
+ goto reschedule;
+
+ limit_idx -= msm_thermal_info.freq_step;
+ if (limit_idx < limit_idx_low)
+ limit_idx = limit_idx_low;
+ max_freq = table[limit_idx].frequency;
+ } else if (temp < msm_thermal_info.limit_temp_degC -
+ msm_thermal_info.temp_hysteresis_degC) {
+ if (limit_idx == limit_idx_high)
+ goto reschedule;
+
+ limit_idx += msm_thermal_info.freq_step;
+ if (limit_idx >= limit_idx_high) {
+ limit_idx = limit_idx_high;
+ max_freq = MSM_CPUFREQ_NO_LIMIT;
+ } else
+ max_freq = table[limit_idx].frequency;
+ }
if (max_freq == limited_max_freq)
goto reschedule;
diff --git a/include/linux/msm_thermal.h b/include/linux/msm_thermal.h
index fe9be89..47a8753 100644
--- a/include/linux/msm_thermal.h
+++ b/include/linux/msm_thermal.h
@@ -17,9 +17,9 @@
struct msm_thermal_data {
uint32_t sensor_id;
uint32_t poll_ms;
- uint32_t limit_temp;
- uint32_t temp_hysteresis;
- uint32_t limit_freq;
+ uint32_t limit_temp_degC;
+ uint32_t temp_hysteresis_degC;
+ uint32_t freq_step;
};
#ifdef CONFIG_THERMAL_MONITOR