mtk_cooler_amddulthro.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. #include <linux/version.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>
  4. #include <linux/types.h>
  5. #include <linux/kobject.h>
  6. #include <linux/proc_fs.h>
  7. #include <asm/uaccess.h>
  8. #include <linux/err.h>
  9. #include <linux/syscalls.h>
  10. #include <linux/timer.h>
  11. #include "mt-plat/mtk_thermal_monitor.h"
  12. #include <linux/uidgid.h>
  13. #define CONFIG_SIGNAL_USER_SPACE (1)
  14. #if CONFIG_SIGNAL_USER_SPACE
  15. #include <linux/pid.h>
  16. #endif
  17. #define cl_type_upper "cl-amddulthro-u"
  18. #define cl_type_lower "cl-amddulthro-l"
  19. #define mtk_cooler_amddulthro_dprintk_always(fmt, args...) \
  20. pr_debug("thermal/cooler/amddulthro" fmt, ##args)
  21. #define mtk_cooler_amddulthro_dprintk(fmt, args...) \
  22. do { \
  23. if (1 == cl_amddulthro_klog_on) { \
  24. pr_debug("thermal/cooler/amddulthro" fmt, ##args);\
  25. } \
  26. } while (0)
  27. #define MAX_NUM_INSTANCE_MTK_COOLER_MDULTHRO 1
  28. static kuid_t uid = KUIDT_INIT(0);
  29. static kgid_t gid = KGIDT_INIT(1000);
  30. static int cl_amddulthro_klog_on;
  31. /* over_up_time * polling interval > up_duration --> throttling */
  32. static unsigned int over_up_time; /* polling time */
  33. static unsigned int up_duration = 30; /* sec */
  34. static unsigned int up_step = 1; /* step */
  35. /* below_low_time * polling interval > low_duration --> throttling */
  36. static unsigned int below_low_time; /* polling time */
  37. static unsigned int low_duration = 20; /* sec */
  38. static unsigned int low_step = 1; /* step */
  39. static unsigned int low_rst_time;
  40. static unsigned int low_rst_max = 3;
  41. /* static unsigned int deepest_step = 0; */
  42. static int polling_interval = 1; /* second */
  43. #define UNK_STAT -1
  44. #define LOW_STAT 0
  45. #define MID_STAT 1
  46. #define HIGH_STAT 2
  47. #define MAX_LEN 256
  48. #define COOLER_STEPS 10
  49. #if CONFIG_SIGNAL_USER_SPACE
  50. static unsigned int tm_pid;
  51. static unsigned int tm_input_pid;
  52. static struct task_struct g_task;
  53. static struct task_struct *pg_task = &g_task;
  54. #endif
  55. static unsigned int cl_upper_dev_state;
  56. static unsigned int cl_lower_dev_state;
  57. static struct thermal_cooling_device *cl_upper_dev;
  58. static struct thermal_cooling_device *cl_lower_dev;
  59. typedef int (*activate_cooler_opp_func) (int level);
  60. static activate_cooler_opp_func opp_func[COOLER_STEPS] = { 0 };
  61. typedef struct adaptive_cooler {
  62. int cur_level;
  63. int max_level;
  64. activate_cooler_opp_func *opp_func_array;
  65. } adaptive_coolers;
  66. static adaptive_coolers amddulthro;
  67. #if CONFIG_SIGNAL_USER_SPACE
  68. static int wmt_send_signal(int level)
  69. {
  70. int ret = 0;
  71. int thro = level;
  72. if (tm_input_pid == 0) {
  73. mtk_cooler_amddulthro_dprintk("[%s] pid is empty\n", __func__);
  74. ret = -1;
  75. }
  76. mtk_cooler_amddulthro_dprintk_always("[%s] pid is %d, %d, %d\n", __func__, tm_pid,
  77. tm_input_pid, thro);
  78. if (ret == 0 && tm_input_pid != tm_pid) {
  79. tm_pid = tm_input_pid;
  80. pg_task = get_pid_task(find_vpid(tm_pid), PIDTYPE_PID);
  81. }
  82. if (ret == 0 && pg_task) {
  83. siginfo_t info;
  84. info.si_signo = SIGIO;
  85. info.si_errno = 2; /* for md dul throttling */
  86. info.si_code = thro;
  87. info.si_addr = NULL;
  88. ret = send_sig_info(SIGIO, &info, pg_task);
  89. }
  90. if (ret != 0)
  91. mtk_cooler_amddulthro_dprintk("[%s] ret=%d\n", __func__, ret);
  92. return ret;
  93. }
  94. #endif /* CONFIG_SIGNAL_USER_SPACE */
  95. int amddulthro_backoff(int level)
  96. {
  97. int ret;
  98. if (level == 0) {
  99. /* no throttle */
  100. wmt_send_signal(10);
  101. mtk_cooler_amddulthro_dprintk_always("[%s] unlimit mddulthro\n", __func__);
  102. } else if (level >= 1 && level <= 9) {
  103. /* throttle */
  104. wmt_send_signal(COOLER_STEPS - level);
  105. mtk_cooler_amddulthro_dprintk_always("[%s] limit mddulthro %d\n", __func__,
  106. COOLER_STEPS - level);
  107. } else {
  108. /* error... */
  109. ret = -1;
  110. mtk_cooler_amddulthro_dprintk_always("[%s] ouf of range\n", __func__);
  111. }
  112. return ret;
  113. }
  114. EXPORT_SYMBOL(amddulthro_backoff);
  115. static int down_throttle(adaptive_coolers *p, int step)
  116. {
  117. if (NULL == p)
  118. return -1;
  119. if (step <= 0)
  120. return p->cur_level;
  121. if (p->cur_level + step > p->max_level) {
  122. p->cur_level = p->max_level;
  123. p->opp_func_array[p->cur_level] (p->cur_level);
  124. return p->cur_level;
  125. }
  126. p->cur_level += step;
  127. p->opp_func_array[p->cur_level] (p->cur_level);
  128. return p->cur_level;
  129. }
  130. static int up_throttle(adaptive_coolers *p, int step)
  131. {
  132. if (NULL == p)
  133. return -1;
  134. if (step <= 0)
  135. return p->cur_level;
  136. if (p->cur_level - step < 0) {
  137. p->cur_level = 0;
  138. p->opp_func_array[p->cur_level] (p->cur_level);
  139. return p->cur_level;
  140. }
  141. p->cur_level -= step;
  142. p->opp_func_array[p->cur_level] (p->cur_level);
  143. return p->cur_level;
  144. }
  145. static int rst_throttle(adaptive_coolers *p)
  146. {
  147. if (NULL == p)
  148. return -1;
  149. p->cur_level = 0;
  150. p->opp_func_array[p->cur_level] (p->cur_level);
  151. return p->cur_level;
  152. }
  153. /* index --> 0, lower; 1, upper */
  154. /* is_on --> 0, off; 1, on */
  155. static int judge_throttling(int index, int is_on, int interval)
  156. {
  157. /*
  158. * throttling_stat
  159. * 2 ( upper=1,lower=1 )
  160. * UPPER ----
  161. * 1 ( upper=0,lower=1 )
  162. * LOWER ----
  163. * 0 ( upper=0,lower=0 )
  164. */
  165. static unsigned int throttling_pre_stat;
  166. static int mail_box[2] = { -1, -1 };
  167. static bool is_reset;
  168. /* unsigned long cur_thro = tx_throughput; */
  169. /* static unsigned long thro_constraint = 99 * 1000; */
  170. int cur_wifi_stat = 0;
  171. mtk_cooler_amddulthro_dprintk("[%s]+ [0]=%d, [1]=%d || [%d] is %s\n", __func__, mail_box[0],
  172. mail_box[1], index, (is_on == 1 ? "ON" : "OFF"));
  173. mail_box[index] = is_on;
  174. if (mail_box[0] >= 0 && mail_box[1] >= 0) {
  175. cur_wifi_stat = mail_box[0] + mail_box[1];
  176. switch (cur_wifi_stat) {
  177. case HIGH_STAT:
  178. if (throttling_pre_stat < HIGH_STAT) {
  179. /* 1st down throttle */
  180. int new_step = down_throttle(&amddulthro, up_step);
  181. mtk_cooler_amddulthro_dprintk_always("LOW/MID-->HIGH: step %d\n",
  182. new_step);
  183. throttling_pre_stat = HIGH_STAT;
  184. over_up_time = 0;
  185. } else if (throttling_pre_stat == HIGH_STAT) {
  186. /* keep down throttle */
  187. over_up_time++;
  188. if ((over_up_time * interval) >= up_duration) {
  189. int new_step = down_throttle(&amddulthro, up_step);
  190. mtk_cooler_amddulthro_dprintk_always
  191. ("HIGH-->HIGH: step %d\n", new_step);
  192. over_up_time = 0;
  193. }
  194. } else {
  195. mtk_cooler_amddulthro_dprintk("[%s] Error state1!!\n", __func__,
  196. throttling_pre_stat);
  197. }
  198. mtk_cooler_amddulthro_dprintk_always("case2 time=%d\n", over_up_time);
  199. break;
  200. case MID_STAT:
  201. if (throttling_pre_stat == LOW_STAT) {
  202. below_low_time = 0;
  203. throttling_pre_stat = MID_STAT;
  204. mtk_cooler_amddulthro_dprintk_always("[%s] Go up!!\n", __func__);
  205. } else if (throttling_pre_stat == HIGH_STAT) {
  206. over_up_time = 0;
  207. throttling_pre_stat = MID_STAT;
  208. mtk_cooler_amddulthro_dprintk_always("[%s] Go down!!\n", __func__);
  209. } else {
  210. throttling_pre_stat = MID_STAT;
  211. mtk_cooler_amddulthro_dprintk("[%s] pre_stat=%d!!\n", __func__,
  212. throttling_pre_stat);
  213. }
  214. break;
  215. case LOW_STAT:
  216. if (throttling_pre_stat > LOW_STAT) {
  217. /* 1st up throttle */
  218. int new_step = up_throttle(&amddulthro, low_step);
  219. mtk_cooler_amddulthro_dprintk_always("MID/HIGH-->LOW: step %d\n",
  220. new_step);
  221. throttling_pre_stat = LOW_STAT;
  222. below_low_time = 0;
  223. low_rst_time = 0;
  224. is_reset = false;
  225. } else if (throttling_pre_stat == LOW_STAT) {
  226. below_low_time++;
  227. if ((below_low_time * interval) >= low_duration) {
  228. if (low_rst_time >= low_rst_max && !is_reset) {
  229. /* rst */
  230. rst_throttle(&amddulthro);
  231. mtk_cooler_amddulthro_dprintk_always
  232. ("over rst time=%d\n", low_rst_time);
  233. low_rst_time = low_rst_max;
  234. is_reset = true;
  235. } else if (!is_reset) {
  236. /* keep up throttle */
  237. int new_step = up_throttle(&amddulthro, low_step);
  238. low_rst_time++;
  239. mtk_cooler_amddulthro_dprintk_always
  240. ("LOW-->LOW: step %d\n", new_step);
  241. below_low_time = 0;
  242. } else {
  243. mtk_cooler_amddulthro_dprintk
  244. ("Have reset, no control!!");
  245. }
  246. }
  247. } else {
  248. mtk_cooler_amddulthro_dprintk_always("[%s] Error state3 %d!!\n",
  249. __func__, throttling_pre_stat);
  250. }
  251. mtk_cooler_amddulthro_dprintk("case0 time=%d, rst=%d %d\n", below_low_time,
  252. low_rst_time, is_reset);
  253. break;
  254. default:
  255. mtk_cooler_amddulthro_dprintk_always("[%s] Error cur_wifi_stat=%d!!\n",
  256. __func__, cur_wifi_stat);
  257. break;
  258. }
  259. mail_box[0] = UNK_STAT;
  260. mail_box[1] = UNK_STAT;
  261. } else {
  262. mtk_cooler_amddulthro_dprintk("[%s] dont get all info!!\n", __func__);
  263. }
  264. return 0;
  265. }
  266. /* +amddulthro_cooler_upper_ops+ */
  267. static int amddulthro_cooler_upper_get_max_state(struct thermal_cooling_device *cool_dev,
  268. unsigned long *pv)
  269. {
  270. *pv = 1;
  271. mtk_cooler_amddulthro_dprintk("[%s] %d\n", __func__, *pv);
  272. return 0;
  273. }
  274. static int amddulthro_cooler_upper_get_cur_state(struct thermal_cooling_device *cool_dev,
  275. unsigned long *pv)
  276. {
  277. *pv = cl_upper_dev_state;
  278. mtk_cooler_amddulthro_dprintk("[%s] %d\n", __func__, *pv);
  279. return 0;
  280. }
  281. static int amddulthro_cooler_upper_set_cur_state(struct thermal_cooling_device *cool_dev,
  282. unsigned long v)
  283. {
  284. int ret = 0;
  285. mtk_cooler_amddulthro_dprintk("[%s] %d\n", __func__, v);
  286. cl_upper_dev_state = (unsigned int)v;
  287. if (cl_upper_dev_state == 1)
  288. ret = judge_throttling(1, 1, polling_interval);
  289. else
  290. ret = judge_throttling(1, 0, polling_interval);
  291. if (ret != 0)
  292. mtk_cooler_amddulthro_dprintk_always("[%s] ret=%d\n", __func__, ret);
  293. return ret;
  294. }
  295. static struct thermal_cooling_device_ops amddulthro_cooler_upper_ops = {
  296. .get_max_state = amddulthro_cooler_upper_get_max_state,
  297. .get_cur_state = amddulthro_cooler_upper_get_cur_state,
  298. .set_cur_state = amddulthro_cooler_upper_set_cur_state,
  299. };
  300. /* -amddulthro_cooler_upper_ops- */
  301. /* +amddulthro_cooler_lower_ops+ */
  302. static int amddulthro_cooler_lower_get_max_state(struct thermal_cooling_device *cool_dev,
  303. unsigned long *pv)
  304. {
  305. *pv = 1;
  306. mtk_cooler_amddulthro_dprintk("[%s] %d\n", __func__, *pv);
  307. return 0;
  308. }
  309. static int amddulthro_cooler_lower_get_cur_state(struct thermal_cooling_device *cool_dev,
  310. unsigned long *pv)
  311. {
  312. *pv = cl_lower_dev_state;
  313. mtk_cooler_amddulthro_dprintk("[%s] %d\n", __func__, *pv);
  314. return 0;
  315. }
  316. static int amddulthro_cooler_lower_set_cur_state(struct thermal_cooling_device *cool_dev,
  317. unsigned long v)
  318. {
  319. int ret = 0;
  320. mtk_cooler_amddulthro_dprintk("[%s] %d\n", __func__, v);
  321. cl_lower_dev_state = (unsigned int)v;
  322. if (cl_lower_dev_state == 1)
  323. ret = judge_throttling(0, 1, polling_interval);
  324. else
  325. ret = judge_throttling(0, 0, polling_interval);
  326. if (ret != 0)
  327. mtk_cooler_amddulthro_dprintk_always("[%s] ret=%d\n", __func__, ret);
  328. return ret;
  329. }
  330. static struct thermal_cooling_device_ops amddulthro_cooler_lower_ops = {
  331. .get_max_state = amddulthro_cooler_lower_get_max_state,
  332. .get_cur_state = amddulthro_cooler_lower_get_cur_state,
  333. .set_cur_state = amddulthro_cooler_lower_set_cur_state,
  334. };
  335. /* -amddulthro_cooler_lower_ops- */
  336. static int mtk_cooler_amddulthro_register_ltf(void)
  337. {
  338. mtk_cooler_amddulthro_dprintk("[%s]\n", __func__);
  339. cl_upper_dev = mtk_thermal_cooling_device_register("cl-amddulthro-upper", NULL,
  340. &amddulthro_cooler_upper_ops);
  341. cl_lower_dev = mtk_thermal_cooling_device_register("cl-amddulthro-lower", NULL,
  342. &amddulthro_cooler_lower_ops);
  343. return 0;
  344. }
  345. static void mtk_cooler_amddulthro_unregister_ltf(void)
  346. {
  347. mtk_cooler_amddulthro_dprintk("[%s]\n", __func__);
  348. if (cl_upper_dev) {
  349. mtk_thermal_cooling_device_unregister(cl_upper_dev);
  350. cl_upper_dev = NULL;
  351. }
  352. if (cl_lower_dev) {
  353. mtk_thermal_cooling_device_unregister(cl_lower_dev);
  354. cl_lower_dev = NULL;
  355. }
  356. }
  357. int amddulthro_param_read(struct seq_file *m, void *v)
  358. {
  359. seq_printf(m,
  360. "[up]\t%3d(sec)\t%2d\n[low]\t%3d(sec)\t%2d\nrst=%2d\ninterval=%d\nmax_step=%d",
  361. up_duration, up_step, low_duration, low_step, low_rst_max, polling_interval,
  362. amddulthro.max_level);
  363. #if 0
  364. int ret;
  365. char tmp[MAX_LEN] = { 0 };
  366. sprintf(tmp, "[up]\t%3d(sec)\t%2d\n[low]\t%3d(sec)\t%2d\nrst=%2d\ninterval=%d\nmax_step=%d",
  367. up_duration, up_step, low_duration, low_step, low_rst_max, polling_interval,
  368. amddulthro.max_level);
  369. ret = strlen(tmp);
  370. memcpy(buf, tmp, ret * sizeof(char));
  371. #endif
  372. mtk_cooler_amddulthro_dprintk_always
  373. ("[%s] [up]%d %d, [low]%d %d, rst=%d, interval=%d, max_step=%d\n", __func__,
  374. up_duration, up_step, low_duration, low_step, low_rst_max, polling_interval,
  375. amddulthro.max_level);
  376. return 0;
  377. }
  378. ssize_t amddulthro_param_write(struct file *file, const char __user *buf, size_t len,
  379. loff_t *data)
  380. {
  381. char desc[MAX_LEN] = { 0 };
  382. unsigned int tmp_up_dur = 30;
  383. unsigned int tmp_up_step = 1;
  384. unsigned int tmp_low_dur = 20;
  385. unsigned int tmp_low_step = 1;
  386. unsigned int tmp_low_rst_max = 3;
  387. int tmp_polling_interval = 1;
  388. unsigned int tmp_deepest_step = COOLER_STEPS - 1;
  389. unsigned int tmp_log = 0;
  390. len = (len < (sizeof(desc) - 1)) ? len : (sizeof(desc) - 1);
  391. /* write data to the buffer */
  392. if (copy_from_user(desc, buf, len))
  393. return -EFAULT;
  394. if (sscanf(desc, "%d %d %d %d %d %d %d", &tmp_up_dur, &tmp_up_step, &tmp_low_dur,
  395. &tmp_low_step, &tmp_low_rst_max, &tmp_polling_interval,
  396. &tmp_deepest_step) >= 6) {
  397. up_duration = tmp_up_dur;
  398. up_step = tmp_up_step;
  399. low_duration = tmp_low_dur;
  400. low_step = tmp_low_step;
  401. low_rst_max = tmp_low_rst_max;
  402. polling_interval = tmp_polling_interval;
  403. if (tmp_deepest_step > 0 && tmp_deepest_step < COOLER_STEPS)
  404. amddulthro.max_level = tmp_deepest_step;
  405. over_up_time = 0;
  406. below_low_time = 0;
  407. low_rst_time = 0;
  408. mtk_cooler_amddulthro_dprintk_always
  409. ("[%s] %s [up]%d %d, [low]%d %d, rst=%d, interval=%d, max_step=%d\n", __func__,
  410. desc, up_duration, up_step, low_duration, low_step, low_rst_max,
  411. polling_interval, amddulthro.max_level);
  412. return len;
  413. } else if (sscanf(desc, "log=%d", &tmp_log) == 1) {
  414. if (tmp_log == 1)
  415. cl_amddulthro_klog_on = 1;
  416. else
  417. cl_amddulthro_klog_on = 0;
  418. return len;
  419. }
  420. mtk_cooler_amddulthro_dprintk_always("[%s] bad argument = %s\n", __func__, desc);
  421. return -EINVAL;
  422. }
  423. static int amddulthro_param_open(struct inode *inode, struct file *file)
  424. {
  425. return single_open(file, amddulthro_param_read, NULL);
  426. }
  427. static const struct file_operations amddulthro_param_fops = {
  428. .owner = THIS_MODULE,
  429. .open = amddulthro_param_open,
  430. .read = seq_read,
  431. .llseek = seq_lseek,
  432. .write = amddulthro_param_write,
  433. .release = single_release,
  434. };
  435. #if CONFIG_SIGNAL_USER_SPACE
  436. int amddulthro_pid_read(struct seq_file *m, void *v)
  437. {
  438. seq_printf(m, "%d\n", tm_input_pid);
  439. #if 0
  440. int ret;
  441. char tmp[MAX_LEN] = { 0 };
  442. sprintf(tmp, "%d\n", tm_input_pid);
  443. ret = strlen(tmp);
  444. memcpy(buf, tmp, ret * sizeof(char));
  445. #endif
  446. mtk_cooler_amddulthro_dprintk_always("[%s] %d\n", __func__, tm_input_pid);
  447. return 0;
  448. }
  449. ssize_t amddulthro_pid_write(struct file *file, const char __user *buf, size_t count, loff_t *data)
  450. {
  451. int ret = 0;
  452. char tmp[MAX_LEN] = { 0 };
  453. int len = 0;
  454. /* write data to the buffer */
  455. len = (count < (sizeof(tmp) - 1)) ? count : (sizeof(tmp) - 1);
  456. if (copy_from_user(tmp, buf, len))
  457. return -EFAULT;
  458. ret = kstrtouint(tmp, 10, &tm_input_pid);
  459. if (ret)
  460. WARN_ON(1);
  461. mtk_cooler_amddulthro_dprintk_always("[%s] %s = %d\n", __func__, tmp, tm_input_pid);
  462. return len;
  463. }
  464. static int amddulthro_pid_open(struct inode *inode, struct file *file)
  465. {
  466. return single_open(file, amddulthro_pid_read, NULL);
  467. }
  468. static const struct file_operations amddulthro_pid_fops = {
  469. .owner = THIS_MODULE,
  470. .open = amddulthro_pid_open,
  471. .read = seq_read,
  472. .llseek = seq_lseek,
  473. .write = amddulthro_pid_write,
  474. .release = single_release,
  475. };
  476. #endif /* CONFIG_SIGNAL_USER_SPACE */
  477. int amddulthro_dbg_read(struct seq_file *m, void *v)
  478. {
  479. seq_printf(m, "cur=%d max=%d\n", amddulthro.cur_level, amddulthro.max_level);
  480. #if 0
  481. int ret;
  482. char tmp[MAX_LEN] = { 0 };
  483. sprintf(tmp, "cur=%d max=%d\n", amddulthro.cur_level, amddulthro.max_level);
  484. ret = strlen(tmp);
  485. memcpy(buf, tmp, ret * sizeof(char));
  486. #endif
  487. mtk_cooler_amddulthro_dprintk_always("[%s] cur=%d max=%d\n", __func__, amddulthro.cur_level,
  488. amddulthro.max_level);
  489. return 0;
  490. }
  491. ssize_t amddulthro_dbg_write(struct file *file, const char __user *buf, size_t len, loff_t *data)
  492. {
  493. char desc[MAX_LEN] = { 0 };
  494. int new_level = -1;
  495. len = (len < (sizeof(desc) - 1)) ? len : (sizeof(desc) - 1);
  496. /* write data to the buffer */
  497. if (copy_from_user(desc, buf, len))
  498. return -EFAULT;
  499. if (kstrtoint(desc, 10, &new_level) == 0) {
  500. if (new_level >= 0 && new_level < COOLER_STEPS) {
  501. /* valid input */
  502. mtk_cooler_amddulthro_dprintk_always("[%s] new level %d\n", __func__,
  503. new_level);
  504. amddulthro.cur_level = new_level;
  505. amddulthro.opp_func_array[new_level] (new_level);
  506. } else
  507. mtk_cooler_amddulthro_dprintk_always("[%s] invalid %d\n", __func__,
  508. new_level);
  509. return len;
  510. }
  511. mtk_cooler_amddulthro_dprintk_always("[%s] bad argument = %s\n", __func__, desc);
  512. return -EINVAL;
  513. }
  514. static int amddulthro_dbg_open(struct inode *inode, struct file *file)
  515. {
  516. return single_open(file, amddulthro_dbg_read, NULL);
  517. }
  518. static const struct file_operations amddulthro_dbg_fops = {
  519. .owner = THIS_MODULE,
  520. .open = amddulthro_dbg_open,
  521. .read = seq_read,
  522. .llseek = seq_lseek,
  523. .write = amddulthro_dbg_write,
  524. .release = single_release,
  525. };
  526. static int amddulthro_proc_register(void)
  527. {
  528. struct proc_dir_entry *entry = NULL;
  529. struct proc_dir_entry *amddulthro_proc_dir = NULL;
  530. mtk_cooler_amddulthro_dprintk("[%s]\n", __func__);
  531. amddulthro_proc_dir = proc_mkdir("amddulthro", NULL);
  532. if (!amddulthro_proc_dir) {
  533. mtk_cooler_amddulthro_dprintk("[%s] mkdir /proc/amddulthro failed\n", __func__);
  534. } else {
  535. #if CONFIG_SIGNAL_USER_SPACE
  536. entry =
  537. proc_create("tm_pid", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
  538. amddulthro_proc_dir, &amddulthro_pid_fops);
  539. if (entry)
  540. proc_set_user(entry, uid, gid);
  541. entry =
  542. proc_create("amddulthro_param", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
  543. amddulthro_proc_dir, &amddulthro_param_fops);
  544. if (entry)
  545. proc_set_user(entry, uid, gid);
  546. entry =
  547. proc_create("amddulthro_dbg", S_IRUSR | S_IWUSR, amddulthro_proc_dir,
  548. &amddulthro_dbg_fops);
  549. }
  550. return 0;
  551. }
  552. static int __init mtk_cooler_amddulthro_init(void)
  553. {
  554. int err = 0, i = 0;
  555. mtk_cooler_amddulthro_dprintk("[%s]\n", __func__);
  556. for (; i < COOLER_STEPS; i++)
  557. opp_func[i] = amddulthro_backoff;
  558. amddulthro.cur_level = 0;
  559. amddulthro.max_level = COOLER_STEPS - 1;
  560. amddulthro.opp_func_array = &opp_func[0];
  561. err = amddulthro_proc_register();
  562. if (err)
  563. return err;
  564. err = mtk_cooler_amddulthro_register_ltf();
  565. if (err)
  566. goto err_unreg;
  567. return 0;
  568. err_unreg:
  569. mtk_cooler_amddulthro_unregister_ltf();
  570. return err;
  571. }
  572. static void __exit mtk_cooler_amddulthro_exit(void)
  573. {
  574. mtk_cooler_amddulthro_dprintk("[%s]\n", __func__);
  575. /* remove the proc file */
  576. /* remove_proc_entry("amddulthro", NULL); */
  577. mtk_cooler_amddulthro_unregister_ltf();
  578. }
  579. module_init(mtk_cooler_amddulthro_init);
  580. module_exit(mtk_cooler_amddulthro_exit);