THERMALD: add sysfs to my custom thermald module

file:de69ebac30d545c60ed7bc2d5ad0257785739c53 -> file:f39b330b391ab1390e78c038ef65bf3f70644945
--- a/drivers/thermal/msm_thermal.c
+++ b/drivers/thermal/msm_thermal.c
@@ -19,23 +19,74 @@
#include <linux/msm_tsens.h>
#include <linux/workqueue.h>
#include <linux/cpu.h>
+#include <linux/reboot.h>
#define DEF_TEMP_SENSOR 0
-#define DEF_THERMAL_CHECK_MS 1000
-#define DEF_ALLOWED_MAX_HIGH 60
-#define DEF_ALLOWED_MAX_FREQ 918000
+
+//shutdown temp
+#define DEF_SHUTDOWNTEMP 80
+
+//max thermal limit
+#define DEF_ALLOWED_MAX_HIGH 76
+#define DEF_ALLOWED_MAX_FREQ 384000
+
+//mid thermal limit
+#define DEF_ALLOWED_MID_HIGH 72
+#define DEF_ALLOWED_MID_FREQ 1026000
+
+//low thermal limit
+#define DEF_ALLOWED_LOW_HIGH 70
+#define DEF_ALLOWED_LOW_FREQ 1350000
+
+//Sampling interval
+#define DEF_THERMAL_CHECK_MS 250
+
+static DEFINE_MUTEX(emergency_shutdown_mutex);
static int enabled;
-static int allowed_max_high = DEF_ALLOWED_MAX_HIGH;
-static int allowed_max_low = (DEF_ALLOWED_MAX_HIGH - 10);
-static int allowed_max_freq = DEF_ALLOWED_MAX_FREQ;
-static int check_interval_ms = DEF_THERMAL_CHECK_MS;
-
-module_param(allowed_max_high, int, 0);
-module_param(allowed_max_freq, int, 0);
-module_param(check_interval_ms, int, 0);
+
+//Throttling indicator, 0=not throttled, 1=low, 2=mid, 3=max
+static int thermal_throttled = 0;
+
+//Safe the cpu max freq before throttling
+static int pre_throttled_max = 0;
static struct delayed_work check_temp_work;
+static struct workqueue_struct *check_temp_workq;
+
+static struct msm_thermal_tuners {
+ unsigned int shutdown_temp;
+
+ unsigned int allowed_max_high;
+ unsigned int allowed_max_low;
+ unsigned int allowed_max_freq;
+
+ unsigned int allowed_mid_high;
+ unsigned int allowed_mid_low;
+ unsigned int allowed_mid_freq;
+
+ unsigned int allowed_low_high;
+ unsigned int allowed_low_low;
+ unsigned int allowed_low_freq;
+
+ unsigned int check_interval_ms;
+} msm_thermal_tuners_ins = {
+ .shutdown_temp = DEF_SHUTDOWNTEMP,
+
+ .allowed_max_high = DEF_ALLOWED_MAX_HIGH,
+ .allowed_max_low = (DEF_ALLOWED_MAX_HIGH - 5),
+ .allowed_max_freq = DEF_ALLOWED_MAX_FREQ,
+
+ .allowed_mid_high = DEF_ALLOWED_MID_HIGH,
+ .allowed_mid_low = (DEF_ALLOWED_MID_HIGH - 5),
+ .allowed_mid_freq = DEF_ALLOWED_MID_FREQ,
+
+ .allowed_low_high = DEF_ALLOWED_LOW_HIGH,
+ .allowed_low_low = (DEF_ALLOWED_LOW_HIGH - 6),
+ .allowed_low_freq = DEF_ALLOWED_LOW_FREQ,
+
+ .check_interval_ms = DEF_THERMAL_CHECK_MS,
+};
static int update_cpu_max_freq(struct cpufreq_policy *cpu_policy,
int cpu, int max_freq)
@@ -47,7 +98,6 @@ static int update_cpu_max_freq(struct cp
cpufreq_verify_within_limits(cpu_policy,
cpu_policy->min, max_freq);
- if (max_freq > 1512000) max_freq = 1512000;
cpu_policy->user_policy.max = max_freq;
ret = cpufreq_update_policy(cpu);
@@ -76,6 +126,20 @@ static void check_temp(struct work_struc
goto reschedule;
}
+ if (temp >= (msm_thermal_tuners_ins.shutdown_temp)) {
+ mutex_lock(&emergency_shutdown_mutex);
+ pr_warn("################################\n");
+ pr_warn("################################\n");
+ pr_warn("- %u OVERTEMP! SHUTTING DOWN! -\n", msm_thermal_tuners_ins.shutdown_temp);
+ pr_warn("################################\n");
+ pr_warn("################################\n");
+ /* orderly poweroff tries to power down gracefully
+ if it fails it will force it. */
+ orderly_poweroff(true);
+ cancel_delayed_work_sync(&check_temp_work);
+ mutex_unlock(&emergency_shutdown_mutex);
+ }
+
for_each_possible_cpu(cpu) {
update_policy = 0;
cpu_policy = cpufreq_cpu_get(cpu);
@@ -83,32 +147,72 @@ static void check_temp(struct work_struc
pr_debug("msm_thermal: NULL policy on cpu %d\n", cpu);
continue;
}
- if (temp >= allowed_max_high) {
- if (cpu_policy->max > allowed_max_freq) {
+
+ /* save pre-throttled max freq value */
+ if (thermal_throttled == 0)
+ pre_throttled_max = cpu_policy->max;
+
+ //low trip point
+ if ((temp >= msm_thermal_tuners_ins.allowed_low_high) &&
+ (temp < msm_thermal_tuners_ins.allowed_mid_high) &&
+ (cpu_policy->max > msm_thermal_tuners_ins.allowed_low_freq)) {
+ update_policy = 1;
+ max_freq = msm_thermal_tuners_ins.allowed_low_freq;
+ thermal_throttled = 1;
+ pr_warn("msm_thermal: Thermal Throttled (low)! temp: %lu\n", temp);
+ //low clr point
+ } else if ((temp < msm_thermal_tuners_ins.allowed_low_low) &&
+ (thermal_throttled > 0)) {
+ if (cpu_policy->max < cpu_policy->cpuinfo.max_freq) {
+ if (pre_throttled_max != 0)
+ max_freq = pre_throttled_max;
+ else {
+ max_freq = 1728000;
+ pr_warn("msm_thermal: ERROR! pre_throttled_max=0, falling back to %u\n", max_freq);
+ }
update_policy = 1;
- max_freq = allowed_max_freq;
- } else {
- pr_debug("msm_thermal: policy max for cpu %d "
- "already < allowed_max_freq\n", cpu);
+ /* wait until 4th core is unthrottled */
+ if (cpu == 3)
+ thermal_throttled = 0;
+ pr_warn("msm_thermal: Low Thermal Throttling Ended! temp: %lu\n", temp);
}
- } else if (temp < allowed_max_low) {
-#ifdef CONFIG_SEC_DVFS
- if (cpufreq_get_dvfs_state() != 1) {
- if (cpu_policy->max < 1512000) {
- max_freq = 1512000;
- update_policy = 1;
- }
- } else
- update_policy = 0;
-#else
+ //mid trip point
+ } else if ((temp >= msm_thermal_tuners_ins.allowed_low_high) &&
+ (temp < msm_thermal_tuners_ins.allowed_mid_low) &&
+ (cpu_policy->max > msm_thermal_tuners_ins.allowed_mid_freq)) {
+ update_policy = 1;
+ max_freq = msm_thermal_tuners_ins.allowed_low_freq;
+ thermal_throttled = 2;
+ pr_warn("msm_thermal: Thermal Throttled (mid)! temp: %lu\n", temp);
+ //mid clr point
+ } else if ( (temp < msm_thermal_tuners_ins.allowed_mid_low) &&
+ (thermal_throttled > 1)) {
+ if (cpu_policy->max < cpu_policy->cpuinfo.max_freq) {
+ max_freq = msm_thermal_tuners_ins.allowed_low_freq;
+ update_policy = 1;
+ /* wait until 4th core is unthrottled */
+ if (cpu == 3)
+ thermal_throttled = 1;
+ pr_warn("msm_thermal: Mid Thermal Throttling Ended! temp: %lu\n", temp);
+ }
+ //max trip point
+ } else if ((temp >= msm_thermal_tuners_ins.allowed_max_high) &&
+ (cpu_policy->max > msm_thermal_tuners_ins.allowed_max_freq)) {
+ update_policy = 1;
+ max_freq = msm_thermal_tuners_ins.allowed_max_freq;
+ thermal_throttled = 3;
+ pr_warn("msm_thermal: Thermal Throttled (max)! temp: %lu\n", temp);
+ //max clr point
+ } else if ((temp < msm_thermal_tuners_ins.allowed_max_low) &&
+ (thermal_throttled > 2)) {
if (cpu_policy->max < cpu_policy->cpuinfo.max_freq) {
- max_freq = cpu_policy->cpuinfo.max_freq;
+ max_freq = msm_thermal_tuners_ins.allowed_mid_freq;
update_policy = 1;
- } else {
- pr_debug("msm_thermal: policy max for cpu %d "
- "already at max allowed\n", cpu);
+ /* wait until 4th core is unthrottled */
+ if (cpu == 3)
+ thermal_throttled = 2;
+ pr_warn("msm_thermal: Max Thermal Throttling Ended! temp: %lu\n", temp);
}
-#endif
}
if (update_policy)
@@ -119,8 +223,8 @@ static void check_temp(struct work_struc
reschedule:
if (enabled)
- schedule_delayed_work(&check_temp_work,
- msecs_to_jiffies(check_interval_ms));
+ queue_delayed_work(check_temp_workq, &check_temp_work,
+ msecs_to_jiffies(msm_thermal_tuners_ins.check_interval_ms));
}
static void disable_msm_thermal(void)
@@ -128,6 +232,10 @@ static void disable_msm_thermal(void)
int cpu = 0;
struct cpufreq_policy *cpu_policy = NULL;
+ /* make sure check_temp is no longer running */
+ cancel_delayed_work_sync(&check_temp_work);
+ flush_scheduled_work();
+
for_each_possible_cpu(cpu) {
cpu_policy = cpufreq_cpu_get(cpu);
if (cpu_policy) {
@@ -163,14 +271,237 @@ static struct kernel_param_ops module_op
module_param_cb(enabled, &module_ops, &enabled, 0644);
MODULE_PARM_DESC(enabled, "enforce thermal limit on cpu");
+/**************************** SYSFS START ****************************/
+struct kobject *msm_thermal_kobject;
+
+#define show_one(file_name, object) \
+static ssize_t show_##file_name \
+(struct kobject *kobj, struct attribute *attr, char *buf) \
+{ \
+ return sprintf(buf, "%u\n", msm_thermal_tuners_ins.object); \
+}
+
+show_one(shutdown_temp, shutdown_temp);
+show_one(allowed_max_high, allowed_max_high);
+show_one(allowed_max_low, allowed_max_low);
+show_one(allowed_max_freq, allowed_max_freq);
+show_one(allowed_mid_high, allowed_mid_high);
+show_one(allowed_mid_low, allowed_mid_low);
+show_one(allowed_mid_freq, allowed_mid_freq);
+show_one(allowed_low_high, allowed_low_high);
+show_one(allowed_low_low, allowed_low_low);
+show_one(allowed_low_freq, allowed_low_freq);
+show_one(check_interval_ms, check_interval_ms);
+
+static ssize_t store_shutdown_temp(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.shutdown_temp = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_max_high(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_max_high = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_max_low(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_max_low = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_max_freq(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_max_freq = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_mid_high(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_mid_high = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_mid_low(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_mid_low = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_mid_freq(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_mid_freq = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_low_high(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_low_high = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_low_low(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_low_low = input;
+
+ return count;
+}
+
+static ssize_t store_allowed_low_freq(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.allowed_low_freq = input;
+
+ return count;
+}
+
+static ssize_t store_check_interval_ms(struct kobject *a, struct attribute *b,
+ const char *buf, size_t count)
+{
+ unsigned int input;
+ int ret;
+ ret = sscanf(buf, "%u", &input);
+ if (ret != 1)
+ return -EINVAL;
+
+ msm_thermal_tuners_ins.check_interval_ms = input;
+
+ return count;
+}
+
+define_one_global_rw(shutdown_temp);
+define_one_global_rw(allowed_max_high);
+define_one_global_rw(allowed_max_low);
+define_one_global_rw(allowed_max_freq);
+define_one_global_rw(allowed_mid_high);
+define_one_global_rw(allowed_mid_low);
+define_one_global_rw(allowed_mid_freq);
+define_one_global_rw(allowed_low_high);
+define_one_global_rw(allowed_low_low);
+define_one_global_rw(allowed_low_freq);
+define_one_global_rw(check_interval_ms);
+
+static struct attribute *msm_thermal_attributes[] = {
+ &shutdown_temp.attr,
+ &allowed_max_high.attr,
+ &allowed_max_low.attr,
+ &allowed_max_freq.attr,
+ &allowed_mid_high.attr,
+ &allowed_mid_low.attr,
+ &allowed_mid_freq.attr,
+ &allowed_low_high.attr,
+ &allowed_low_low.attr,
+ &allowed_low_freq.attr,
+ &check_interval_ms.attr,
+ NULL
+};
+
+
+static struct attribute_group msm_thermal_attr_group = {
+ .attrs = msm_thermal_attributes,
+ .name = "conf",
+};
+/**************************** SYSFS END ****************************/
+
static int __init msm_thermal_init(void)
{
- int ret = 0;
+ int rc, ret = 0;
enabled = 1;
- INIT_DELAYED_WORK(&check_temp_work, check_temp);
-
- schedule_delayed_work(&check_temp_work, 0);
+ check_temp_workq = alloc_workqueue(
+ "msm_thermal", WQ_UNBOUND | WQ_RESCUER, 1);
+ if (!check_temp_workq)
+ BUG_ON(ENOMEM);
+ INIT_DELAYED_WORK(&check_temp_work, check_temp);
+ queue_delayed_work(check_temp_workq, &check_temp_work, 0);
+
+ msm_thermal_kobject = kobject_create_and_add("msm_thermal", kernel_kobj);
+ if (msm_thermal_kobject) {
+ rc = sysfs_create_group(msm_thermal_kobject,
+ &msm_thermal_attr_group);
+ if (rc) {
+ pr_warn("msm_thermal: sysfs: ERROR, could not create sysfs group");
+ }
+ } else
+ pr_warn("msm_thermal: sysfs: ERROR, could not create sysfs kobj");
return ret;
}