mt_hotplug_strategy_algo.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. /*
  2. * Copyright (c) 2015 MediaTek Inc.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/module.h>
  16. #include <linux/init.h>
  17. #include <linux/cpu.h>
  18. #include <linux/kthread.h>
  19. #include <linux/wakelock.h>
  20. #include <linux/delay.h>
  21. #include <asm-generic/bug.h>
  22. #include "mt_hotplug_strategy_internal.h"
  23. /*
  24. * hps algo - hmp
  25. */
  26. static void algo_hmp_limit(
  27. struct cpumask *little_online_cpumask,
  28. struct cpumask *big_online_cpumask,
  29. unsigned int little_num_base,
  30. unsigned int little_num_limit,
  31. unsigned int little_num_online,
  32. unsigned int big_num_base,
  33. unsigned int big_num_limit,
  34. unsigned int big_num_online)
  35. {
  36. unsigned int cpu;
  37. unsigned int val;
  38. if (big_num_online > big_num_limit) {
  39. val = big_num_online - big_num_limit;
  40. for (cpu = hps_ctxt.big_cpu_id_max;
  41. cpu >= hps_ctxt.big_cpu_id_min; --cpu) {
  42. if (!cpumask_test_cpu(cpu, big_online_cpumask))
  43. continue;
  44. cpu_down(cpu);
  45. cpumask_clear_cpu(cpu, big_online_cpumask);
  46. --big_num_online;
  47. if (--val == 0)
  48. break;
  49. }
  50. BUG_ON(val);
  51. hps_ctxt.action |= BIT(ACTION_LIMIT_BIG);
  52. }
  53. if (little_num_online > little_num_limit) {
  54. val = little_num_online - little_num_limit;
  55. for (cpu = hps_ctxt.little_cpu_id_max;
  56. cpu > hps_ctxt.little_cpu_id_min; --cpu) {
  57. if (!cpumask_test_cpu(cpu, little_online_cpumask))
  58. continue;
  59. cpu_down(cpu);
  60. cpumask_clear_cpu(cpu, little_online_cpumask);
  61. --little_num_online;
  62. if (--val == 0)
  63. break;
  64. }
  65. BUG_ON(val);
  66. hps_ctxt.action |= BIT(ACTION_LIMIT_LITTLE);
  67. }
  68. }
  69. static void algo_hmp_base(
  70. struct cpumask *little_online_cpumask,
  71. struct cpumask *big_online_cpumask,
  72. unsigned int lb /* little_num_base */,
  73. unsigned int ll /* little_num_limit */,
  74. unsigned int lo /* little_num_online */,
  75. unsigned int bb /* big_num_base */,
  76. unsigned int bl /* big_num_limit */,
  77. unsigned int bo /* big_num_online */)
  78. {
  79. unsigned int cpu;
  80. unsigned int val;
  81. unsigned int num_online = lo + bo;
  82. BUG_ON(bo > bl);
  83. BUG_ON(lo > ll);
  84. if (bo < bb && bo < bl && hps_ctxt.state == STATE_LATE_RESUME) {
  85. val = min(bb, bl) - bo;
  86. for (cpu = hps_ctxt.big_cpu_id_min;
  87. cpu <= hps_ctxt.big_cpu_id_max; ++cpu) {
  88. if (cpumask_test_cpu(cpu, big_online_cpumask))
  89. continue;
  90. cpu_up(cpu);
  91. cpumask_set_cpu(cpu, big_online_cpumask);
  92. ++bo;
  93. if (--val == 0)
  94. break;
  95. }
  96. BUG_ON(val);
  97. hps_ctxt.action |= BIT(ACTION_BASE_BIG);
  98. }
  99. if (lo < lb && lo < ll &&
  100. (num_online < hps_ctxt.little_num_base_perf_serv +
  101. hps_ctxt.big_num_base_perf_serv)) {
  102. val = min(lb, ll) - lo;
  103. if (bo > hps_ctxt.big_num_base_perf_serv)
  104. val -= bo - hps_ctxt.big_num_base_perf_serv;
  105. for (cpu = hps_ctxt.little_cpu_id_min;
  106. cpu <= hps_ctxt.little_cpu_id_max; ++cpu) {
  107. if (cpumask_test_cpu(cpu, little_online_cpumask))
  108. continue;
  109. cpu_up(cpu);
  110. cpumask_set_cpu(cpu, little_online_cpumask);
  111. ++lo;
  112. if (--val == 0)
  113. break;
  114. }
  115. BUG_ON(val);
  116. hps_ctxt.action |= BIT(ACTION_BASE_LITTLE);
  117. }
  118. }
  119. static void algo_hmp_rush_boost(
  120. struct cpumask *little_online_cpumask,
  121. struct cpumask *big_online_cpumask,
  122. unsigned int little_num_base,
  123. unsigned int little_num_limit,
  124. unsigned int little_num_online,
  125. unsigned int big_num_base,
  126. unsigned int big_num_limit,
  127. unsigned int big_num_online)
  128. {
  129. unsigned int cpu;
  130. unsigned int val;
  131. unsigned int num_online = little_num_online + big_num_online;
  132. if (!hps_ctxt.rush_boost_enabled)
  133. return;
  134. if (hps_ctxt.cur_loads > hps_ctxt.rush_boost_threshold * num_online)
  135. ++hps_ctxt.rush_count;
  136. else
  137. hps_ctxt.rush_count = 0;
  138. if (hps_ctxt.rush_count < hps_ctxt.rush_boost_times ||
  139. num_online * 100 >= hps_ctxt.tlp_avg)
  140. return;
  141. val = hps_ctxt.tlp_avg / 100 + (hps_ctxt.tlp_avg % 100 ? 1 : 0);
  142. BUG_ON(!(val > num_online));
  143. if (val > num_possible_cpus())
  144. val = num_possible_cpus();
  145. val -= num_online;
  146. if (val && little_num_online < little_num_limit) {
  147. for (cpu = hps_ctxt.little_cpu_id_min;
  148. cpu <= hps_ctxt.little_cpu_id_max; ++cpu) {
  149. if (cpumask_test_cpu(cpu, little_online_cpumask))
  150. continue;
  151. cpu_up(cpu);
  152. cpumask_set_cpu(cpu, little_online_cpumask);
  153. ++little_num_online;
  154. if (--val == 0)
  155. break;
  156. }
  157. hps_ctxt.action |= BIT(ACTION_RUSH_BOOST_LITTLE);
  158. } else if (val && big_num_online < big_num_limit &&
  159. hps_ctxt.state == STATE_LATE_RESUME) {
  160. for (cpu = hps_ctxt.big_cpu_id_min;
  161. cpu <= hps_ctxt.big_cpu_id_max; ++cpu) {
  162. if (cpumask_test_cpu(cpu, big_online_cpumask))
  163. continue;
  164. cpu_up(cpu);
  165. cpumask_set_cpu(cpu, big_online_cpumask);
  166. ++big_num_online;
  167. if (--val == 0)
  168. break;
  169. }
  170. hps_ctxt.action |= BIT(ACTION_RUSH_BOOST_BIG);
  171. }
  172. }
  173. static void algo_hmp_up(
  174. struct cpumask *little_online_cpumask,
  175. struct cpumask *big_online_cpumask,
  176. unsigned int little_num_base,
  177. unsigned int little_num_limit,
  178. unsigned int little_num_online,
  179. unsigned int big_num_base,
  180. unsigned int big_num_limit,
  181. unsigned int big_num_online)
  182. {
  183. unsigned int cpu;
  184. unsigned int val;
  185. unsigned int num_online = little_num_online + big_num_online;
  186. if (num_online >= num_possible_cpus())
  187. return;
  188. /*
  189. * update history - up
  190. */
  191. val = hps_ctxt.up_loads_history[hps_ctxt.up_loads_history_index];
  192. hps_ctxt.up_loads_history[hps_ctxt.up_loads_history_index] =
  193. hps_ctxt.cur_loads;
  194. hps_ctxt.up_loads_sum += hps_ctxt.cur_loads;
  195. hps_ctxt.up_loads_history_index =
  196. (hps_ctxt.up_loads_history_index + 1 == hps_ctxt.up_times) ?
  197. 0 : hps_ctxt.up_loads_history_index + 1;
  198. ++hps_ctxt.up_loads_count;
  199. if (hps_ctxt.up_loads_count > hps_ctxt.up_times) {
  200. BUG_ON(hps_ctxt.up_loads_sum < val);
  201. hps_ctxt.up_loads_sum -= val;
  202. }
  203. if (hps_ctxt.stats_dump_enabled)
  204. hps_ctxt_print_algo_stats_up(0);
  205. if (hps_ctxt.up_loads_count < hps_ctxt.up_times)
  206. return;
  207. if (hps_ctxt.up_loads_sum <=
  208. hps_ctxt.up_threshold * hps_ctxt.up_times * num_online)
  209. return;
  210. if (little_num_online < little_num_limit) {
  211. for (cpu = hps_ctxt.little_cpu_id_min;
  212. cpu <= hps_ctxt.little_cpu_id_max; ++cpu) {
  213. if (!cpumask_test_cpu(cpu, little_online_cpumask)) {
  214. cpu_up(cpu);
  215. cpumask_set_cpu(cpu, little_online_cpumask);
  216. ++little_num_online;
  217. break;
  218. }
  219. }
  220. hps_ctxt.action |= BIT(ACTION_UP_LITTLE);
  221. } else if (big_num_online < big_num_limit &&
  222. hps_ctxt.state == STATE_LATE_RESUME) {
  223. for (cpu = hps_ctxt.big_cpu_id_min;
  224. cpu <= hps_ctxt.big_cpu_id_max; ++cpu) {
  225. if (!cpumask_test_cpu(cpu, big_online_cpumask)) {
  226. cpu_up(cpu);
  227. cpumask_set_cpu(cpu, big_online_cpumask);
  228. ++big_num_online;
  229. break;
  230. }
  231. }
  232. hps_ctxt.action |= BIT(ACTION_UP_BIG);
  233. }
  234. }
  235. static void algo_hmp_down(
  236. struct cpumask *little_online_cpumask,
  237. struct cpumask *big_online_cpumask,
  238. unsigned int little_num_base,
  239. unsigned int little_num_limit,
  240. unsigned int little_num_online,
  241. unsigned int big_num_base,
  242. unsigned int big_num_limit,
  243. unsigned int big_num_online)
  244. {
  245. unsigned int cpu;
  246. unsigned int val;
  247. unsigned int down_threshold;
  248. unsigned int num_online = little_num_online + big_num_online;
  249. if (num_online <= 1)
  250. return;
  251. /*
  252. * update history - down
  253. */
  254. val = hps_ctxt.down_loads_history[hps_ctxt.down_loads_history_index];
  255. hps_ctxt.down_loads_history[hps_ctxt.down_loads_history_index] =
  256. hps_ctxt.cur_loads;
  257. hps_ctxt.down_loads_sum += hps_ctxt.cur_loads;
  258. hps_ctxt.down_loads_history_index =
  259. (hps_ctxt.down_loads_history_index + 1 == hps_ctxt.down_times) ?
  260. 0 : hps_ctxt.down_loads_history_index + 1;
  261. ++hps_ctxt.down_loads_count;
  262. if (hps_ctxt.down_loads_count > hps_ctxt.down_times) {
  263. BUG_ON(hps_ctxt.down_loads_sum < val);
  264. hps_ctxt.down_loads_sum -= val;
  265. }
  266. if (hps_ctxt.stats_dump_enabled)
  267. hps_ctxt_print_algo_stats_down(0);
  268. if (hps_ctxt.down_loads_count < hps_ctxt.down_times)
  269. return;
  270. down_threshold = hps_ctxt.down_threshold * hps_ctxt.down_times;
  271. val = num_online;
  272. while (hps_ctxt.down_loads_sum < down_threshold * (val - 1))
  273. --val;
  274. val = num_online - val;
  275. if (val && big_num_online > big_num_base) {
  276. for (cpu = hps_ctxt.big_cpu_id_max;
  277. cpu >= hps_ctxt.big_cpu_id_min; --cpu) {
  278. if (!cpumask_test_cpu(cpu, big_online_cpumask))
  279. continue;
  280. cpu_down(cpu);
  281. cpumask_clear_cpu(cpu, big_online_cpumask);
  282. --big_num_online;
  283. if (--val == 0)
  284. break;
  285. }
  286. hps_ctxt.action |= BIT(ACTION_DOWN_BIG);
  287. } else if (val && little_num_online > little_num_base) {
  288. for (cpu = hps_ctxt.little_cpu_id_max;
  289. cpu > hps_ctxt.little_cpu_id_min; --cpu) {
  290. if (!cpumask_test_cpu(cpu, little_online_cpumask))
  291. continue;
  292. cpu_down(cpu);
  293. cpumask_clear_cpu(cpu, little_online_cpumask);
  294. --little_num_online;
  295. if (--val == 0)
  296. break;
  297. }
  298. hps_ctxt.action |= BIT(ACTION_DOWN_LITTLE);
  299. }
  300. }
  301. static void algo_hmp_big_to_little(
  302. struct cpumask *little_online_cpumask,
  303. struct cpumask *big_online_cpumask,
  304. unsigned int little_num_base,
  305. unsigned int little_num_limit,
  306. unsigned int little_num_online,
  307. unsigned int big_num_base,
  308. unsigned int big_num_limit,
  309. unsigned int big_num_online)
  310. {
  311. unsigned int cpu;
  312. unsigned int val;
  313. unsigned int load;
  314. unsigned int num_online = little_num_online + big_num_online;
  315. if (hps_ctxt.down_loads_count < hps_ctxt.down_times)
  316. return;
  317. if (little_num_online >= little_num_limit ||
  318. big_num_online <= big_num_base)
  319. return;
  320. /* find last online big */
  321. for (val = hps_ctxt.big_cpu_id_max;
  322. val >= hps_ctxt.big_cpu_id_min; --val) {
  323. if (cpumask_test_cpu(val, big_online_cpumask))
  324. break;
  325. }
  326. BUG_ON(val < hps_ctxt.big_cpu_id_min);
  327. /* verify whether b2L will open 1 little */
  328. load = per_cpu(hps_percpu_ctxt, val).load * CPU_DMIPS_BIG_LITTLE_DIFF;
  329. load /= 100;
  330. load += hps_ctxt.up_loads_sum / hps_ctxt.up_times;
  331. if (load > hps_ctxt.up_threshold * num_online)
  332. return;
  333. /* up 1 little */
  334. for (cpu = hps_ctxt.little_cpu_id_min;
  335. cpu <= hps_ctxt.little_cpu_id_max; ++cpu) {
  336. if (cpumask_test_cpu(cpu, little_online_cpumask))
  337. continue;
  338. cpu_up(cpu);
  339. cpumask_set_cpu(cpu, little_online_cpumask);
  340. ++little_num_online;
  341. break;
  342. }
  343. /* down 1 big */
  344. cpu_down(val);
  345. cpumask_clear_cpu(cpu, big_online_cpumask);
  346. --big_num_online;
  347. hps_ctxt.action |= BIT(ACTION_BIG_TO_LITTLE);
  348. }
  349. void hps_algo_hmp(void)
  350. {
  351. unsigned int cpu;
  352. unsigned int val;
  353. struct cpumask little_online_cpumask;
  354. struct cpumask big_online_cpumask;
  355. unsigned int little_num_base, little_num_limit, little_num_online;
  356. unsigned int big_num_base, big_num_limit, big_num_online;
  357. /* log purpose */
  358. char str1[64];
  359. char str2[64];
  360. int i, j;
  361. char *str1_ptr = str1;
  362. char *str2_ptr = str2;
  363. /*
  364. * run algo or not by hps_ctxt.enabled
  365. */
  366. if (!hps_ctxt.enabled) {
  367. atomic_set(&hps_ctxt.is_ondemand, 0);
  368. return;
  369. }
  370. /*
  371. * calculate cpu loading
  372. */
  373. hps_ctxt.cur_loads = 0;
  374. str1_ptr = str1;
  375. str2_ptr = str2;
  376. for_each_possible_cpu(cpu) {
  377. per_cpu(hps_percpu_ctxt, cpu).load =
  378. hps_cpu_get_percpu_load(cpu);
  379. hps_ctxt.cur_loads += per_cpu(hps_percpu_ctxt, cpu).load;
  380. if (hps_ctxt.cur_dump_enabled) {
  381. if (cpu_online(cpu))
  382. i = sprintf(str1_ptr, "%4u", 1);
  383. else
  384. i = sprintf(str1_ptr, "%4u", 0);
  385. str1_ptr += i;
  386. j = sprintf(str2_ptr, "%4u",
  387. per_cpu(hps_percpu_ctxt, cpu).load);
  388. str2_ptr += j;
  389. }
  390. }
  391. hps_ctxt.cur_nr_heavy_task = hps_cpu_get_nr_heavy_task();
  392. hps_cpu_get_tlp(&hps_ctxt.cur_tlp, &hps_ctxt.cur_iowait);
  393. /*
  394. * algo - begin
  395. */
  396. mutex_lock(&hps_ctxt.lock);
  397. hps_ctxt.action = ACTION_NONE;
  398. atomic_set(&hps_ctxt.is_ondemand, 0);
  399. /*
  400. * algo - get boundary
  401. */
  402. little_num_limit = min(hps_ctxt.little_num_limit_thermal,
  403. hps_ctxt.little_num_limit_low_battery);
  404. little_num_limit = min3(little_num_limit,
  405. hps_ctxt.little_num_limit_ultra_power_saving,
  406. hps_ctxt.little_num_limit_power_serv);
  407. little_num_base = max(hps_ctxt.little_num_base_perf_serv,
  408. hps_ctxt.little_num_base_wifi);
  409. cpumask_and(&little_online_cpumask, &hps_ctxt.little_cpumask,
  410. cpu_online_mask);
  411. little_num_online = cpumask_weight(&little_online_cpumask);
  412. /* TODO: no need if is_hmp */
  413. big_num_limit = min(hps_ctxt.big_num_limit_thermal,
  414. hps_ctxt.big_num_limit_low_battery);
  415. big_num_limit = min3(big_num_limit,
  416. hps_ctxt.big_num_limit_ultra_power_saving,
  417. hps_ctxt.big_num_limit_power_serv);
  418. big_num_base = max3(hps_ctxt.cur_nr_heavy_task,
  419. hps_ctxt.big_num_base_perf_serv,
  420. hps_ctxt.big_num_base_wifi);
  421. cpumask_and(&big_online_cpumask, &hps_ctxt.big_cpumask,
  422. cpu_online_mask);
  423. big_num_online = cpumask_weight(&big_online_cpumask);
  424. if (hps_ctxt.cur_dump_enabled) {
  425. hps_debug(" CPU:%s\n", str1);
  426. hps_debug("LOAD:%s\n", str2);
  427. hps_debug(
  428. "loads(%u), hvy_tsk(%u), tlp(%u), iowait(%u), limit_t(%u)(%u), limit_lb(%u)(%u), limit_ups(%u)(%u), limit_pos(%u)(%u), base_pes(%u)(%u)\n",
  429. hps_ctxt.cur_loads, hps_ctxt.cur_nr_heavy_task,
  430. hps_ctxt.cur_tlp, hps_ctxt.cur_iowait,
  431. hps_ctxt.little_num_limit_thermal,
  432. hps_ctxt.big_num_limit_thermal,
  433. hps_ctxt.little_num_limit_low_battery,
  434. hps_ctxt.big_num_limit_low_battery,
  435. hps_ctxt.little_num_limit_ultra_power_saving,
  436. hps_ctxt.big_num_limit_ultra_power_saving,
  437. hps_ctxt.little_num_limit_power_serv,
  438. hps_ctxt.big_num_limit_power_serv,
  439. hps_ctxt.little_num_base_perf_serv,
  440. hps_ctxt.big_num_base_perf_serv);
  441. }
  442. /*
  443. * algo - thermal, low battery
  444. */
  445. algo_hmp_limit(&little_online_cpumask, &big_online_cpumask,
  446. little_num_base, little_num_limit, little_num_online,
  447. big_num_base, big_num_limit, big_num_online);
  448. if (hps_ctxt.action)
  449. goto ALGO_END_WITH_ACTION;
  450. /*
  451. * algo - PerfService, heavy task detect
  452. */
  453. algo_hmp_base(&little_online_cpumask, &big_online_cpumask,
  454. little_num_base, little_num_limit, little_num_online,
  455. big_num_base, big_num_limit, big_num_online);
  456. if (hps_ctxt.action)
  457. goto ALGO_END_WITH_ACTION;
  458. /*
  459. * update history - tlp
  460. */
  461. val = hps_ctxt.tlp_history[hps_ctxt.tlp_history_index];
  462. hps_ctxt.tlp_history[hps_ctxt.tlp_history_index] = hps_ctxt.cur_tlp;
  463. hps_ctxt.tlp_sum += hps_ctxt.cur_tlp;
  464. hps_ctxt.tlp_history_index =
  465. (hps_ctxt.tlp_history_index + 1 == hps_ctxt.tlp_times) ?
  466. 0 : hps_ctxt.tlp_history_index + 1;
  467. ++hps_ctxt.tlp_count;
  468. if (hps_ctxt.tlp_count > hps_ctxt.tlp_times) {
  469. BUG_ON(hps_ctxt.tlp_sum < val);
  470. hps_ctxt.tlp_sum -= val;
  471. hps_ctxt.tlp_avg = hps_ctxt.tlp_sum / hps_ctxt.tlp_times;
  472. } else {
  473. hps_ctxt.tlp_avg = hps_ctxt.tlp_sum / hps_ctxt.tlp_count;
  474. }
  475. if (hps_ctxt.stats_dump_enabled)
  476. hps_ctxt_print_algo_stats_tlp(0);
  477. /*
  478. * algo - rush boost
  479. */
  480. algo_hmp_rush_boost(&little_online_cpumask, &big_online_cpumask,
  481. little_num_base, little_num_limit, little_num_online,
  482. big_num_base, big_num_limit, big_num_online);
  483. if (hps_ctxt.action)
  484. goto ALGO_END_WITH_ACTION;
  485. /*
  486. * algo - cpu up
  487. */
  488. algo_hmp_up(&little_online_cpumask, &big_online_cpumask,
  489. little_num_base, little_num_limit, little_num_online,
  490. big_num_base, big_num_limit, big_num_online);
  491. if (hps_ctxt.action)
  492. goto ALGO_END_WITH_ACTION;
  493. /*
  494. * algo - cpu down (inc. quick landing)
  495. */
  496. algo_hmp_down(&little_online_cpumask, &big_online_cpumask,
  497. little_num_base, little_num_limit, little_num_online,
  498. big_num_base, big_num_limit, big_num_online);
  499. if (hps_ctxt.action)
  500. goto ALGO_END_WITH_ACTION;
  501. /*
  502. * algo - b2L
  503. */
  504. algo_hmp_big_to_little(&little_online_cpumask, &big_online_cpumask,
  505. little_num_base, little_num_limit, little_num_online,
  506. big_num_base, big_num_limit, big_num_online);
  507. if (!hps_ctxt.action)
  508. goto ALGO_END_WO_ACTION;
  509. /*
  510. * algo - end
  511. */
  512. ALGO_END_WITH_ACTION:
  513. hps_warn(
  514. "(%04lx)(%u)(%u)action end(%u)(%u)(%u)(%u) (%u)(%u)(%u)(%u)(%u)(%u)(%u)(%u)(%u)(%u) (%u)(%u)(%u) (%u)(%u)(%u) (%u)(%u)(%u)(%u)(%u) wifi_base(%u)(%u)\n",
  515. hps_ctxt.action, little_num_online, big_num_online,
  516. hps_ctxt.cur_loads, hps_ctxt.cur_tlp,
  517. hps_ctxt.cur_iowait, hps_ctxt.cur_nr_heavy_task,
  518. hps_ctxt.little_num_limit_thermal,
  519. hps_ctxt.big_num_limit_thermal,
  520. hps_ctxt.little_num_limit_low_battery,
  521. hps_ctxt.big_num_limit_low_battery,
  522. hps_ctxt.little_num_limit_ultra_power_saving,
  523. hps_ctxt.big_num_limit_ultra_power_saving,
  524. hps_ctxt.little_num_limit_power_serv,
  525. hps_ctxt.big_num_limit_power_serv,
  526. hps_ctxt.little_num_base_perf_serv,
  527. hps_ctxt.big_num_base_perf_serv,
  528. hps_ctxt.up_loads_sum, hps_ctxt.up_loads_count,
  529. hps_ctxt.up_loads_history_index,
  530. hps_ctxt.down_loads_sum, hps_ctxt.down_loads_count,
  531. hps_ctxt.down_loads_history_index,
  532. hps_ctxt.rush_count, hps_ctxt.tlp_sum, hps_ctxt.tlp_count,
  533. hps_ctxt.tlp_history_index, hps_ctxt.tlp_avg,
  534. hps_ctxt.little_num_base_wifi,
  535. hps_ctxt.big_num_base_wifi);
  536. hps_ctxt_reset_stas_nolock();
  537. ALGO_END_WO_ACTION:
  538. mutex_unlock(&hps_ctxt.lock);
  539. }
  540. /*
  541. * hps algo - smp
  542. */
  543. static void algo_smp_limit(
  544. struct cpumask *little_online_cpumask,
  545. unsigned int little_num_base,
  546. unsigned int little_num_limit,
  547. unsigned int little_num_online)
  548. {
  549. unsigned int cpu;
  550. unsigned int val;
  551. if (little_num_online <= little_num_limit)
  552. return;
  553. val = little_num_online - little_num_limit;
  554. for (cpu = hps_ctxt.little_cpu_id_max;
  555. cpu > hps_ctxt.little_cpu_id_min; --cpu) {
  556. if (!cpumask_test_cpu(cpu, little_online_cpumask))
  557. continue;
  558. cpu_down(cpu);
  559. cpumask_clear_cpu(cpu, little_online_cpumask);
  560. --little_num_online;
  561. if (--val == 0)
  562. break;
  563. }
  564. BUG_ON(val);
  565. hps_ctxt.action |= BIT(ACTION_LIMIT_LITTLE);
  566. }
  567. static void algo_smp_base(
  568. struct cpumask *little_online_cpumask,
  569. unsigned int little_num_base,
  570. unsigned int little_num_limit,
  571. unsigned int little_num_online)
  572. {
  573. unsigned int cpu;
  574. unsigned int val;
  575. BUG_ON(little_num_online > little_num_limit);
  576. if (little_num_online >= little_num_base ||
  577. little_num_online >= little_num_limit)
  578. return;
  579. val = min(little_num_base, little_num_limit) - little_num_online;
  580. for (cpu = hps_ctxt.little_cpu_id_min;
  581. cpu <= hps_ctxt.little_cpu_id_max; ++cpu) {
  582. if (cpumask_test_cpu(cpu, little_online_cpumask))
  583. continue;
  584. cpu_up(cpu);
  585. cpumask_set_cpu(cpu, little_online_cpumask);
  586. ++little_num_online;
  587. if (--val == 0)
  588. break;
  589. }
  590. BUG_ON(val);
  591. hps_ctxt.action |= BIT(ACTION_BASE_LITTLE);
  592. }
  593. static void algo_smp_rush_boost(
  594. struct cpumask *little_online_cpumask,
  595. unsigned int little_num_base,
  596. unsigned int little_num_limit,
  597. unsigned int little_num_online)
  598. {
  599. unsigned int cpu;
  600. unsigned int val;
  601. if (!hps_ctxt.rush_boost_enabled)
  602. return;
  603. if (hps_ctxt.cur_loads >
  604. hps_ctxt.rush_boost_threshold * little_num_online)
  605. ++hps_ctxt.rush_count;
  606. else
  607. hps_ctxt.rush_count = 0;
  608. if (hps_ctxt.rush_count < hps_ctxt.rush_boost_times ||
  609. little_num_online * 100 >= hps_ctxt.tlp_avg)
  610. return;
  611. val = hps_ctxt.tlp_avg / 100 + (hps_ctxt.tlp_avg % 100 ? 1 : 0);
  612. BUG_ON(!(val > little_num_online));
  613. if (val > num_possible_cpus())
  614. val = num_possible_cpus();
  615. val -= little_num_online;
  616. if (!val || little_num_online >= little_num_limit)
  617. return;
  618. for (cpu = hps_ctxt.little_cpu_id_min;
  619. cpu <= hps_ctxt.little_cpu_id_max; ++cpu) {
  620. if (cpumask_test_cpu(cpu, little_online_cpumask))
  621. continue;
  622. cpu_up(cpu);
  623. cpumask_set_cpu(cpu, little_online_cpumask);
  624. ++little_num_online;
  625. if (--val == 0)
  626. break;
  627. }
  628. hps_ctxt.action |= BIT(ACTION_RUSH_BOOST_LITTLE);
  629. }
  630. static void algo_smp_up(
  631. struct cpumask *little_online_cpumask,
  632. unsigned int little_num_base,
  633. unsigned int little_num_limit,
  634. unsigned int little_num_online)
  635. {
  636. unsigned int cpu;
  637. unsigned int val;
  638. if (little_num_online >= num_possible_cpus())
  639. return;
  640. /*
  641. * update history - up
  642. */
  643. val = hps_ctxt.up_loads_history[hps_ctxt.up_loads_history_index];
  644. hps_ctxt.up_loads_history[hps_ctxt.up_loads_history_index] =
  645. hps_ctxt.cur_loads;
  646. hps_ctxt.up_loads_sum += hps_ctxt.cur_loads;
  647. hps_ctxt.up_loads_history_index =
  648. (hps_ctxt.up_loads_history_index + 1 == hps_ctxt.up_times) ?
  649. 0 : hps_ctxt.up_loads_history_index + 1;
  650. ++hps_ctxt.up_loads_count;
  651. if (hps_ctxt.up_loads_count > hps_ctxt.up_times) {
  652. BUG_ON(hps_ctxt.up_loads_sum < val);
  653. hps_ctxt.up_loads_sum -= val;
  654. }
  655. if (hps_ctxt.stats_dump_enabled)
  656. hps_ctxt_print_algo_stats_up(0);
  657. if (hps_ctxt.up_loads_count < hps_ctxt.up_times)
  658. return;
  659. if (hps_ctxt.up_loads_sum <=
  660. hps_ctxt.up_threshold * hps_ctxt.up_times * little_num_online)
  661. return;
  662. if (little_num_online >= little_num_limit)
  663. return;
  664. for (cpu = hps_ctxt.little_cpu_id_min;
  665. cpu <= hps_ctxt.little_cpu_id_max; ++cpu) {
  666. if (cpumask_test_cpu(cpu, little_online_cpumask))
  667. continue;
  668. cpu_up(cpu);
  669. cpumask_set_cpu(cpu, little_online_cpumask);
  670. ++little_num_online;
  671. break;
  672. }
  673. hps_ctxt.action |= BIT(ACTION_UP_LITTLE);
  674. }
  675. static void algo_smp_down(
  676. struct cpumask *little_online_cpumask,
  677. unsigned int little_num_base,
  678. unsigned int little_num_limit,
  679. unsigned int little_num_online)
  680. {
  681. unsigned int cpu;
  682. unsigned int val;
  683. unsigned int down_threshold;
  684. if (little_num_online <= 1)
  685. return;
  686. /*
  687. * update history - down
  688. */
  689. val = hps_ctxt.down_loads_history[hps_ctxt.down_loads_history_index];
  690. hps_ctxt.down_loads_history[hps_ctxt.down_loads_history_index] =
  691. hps_ctxt.cur_loads;
  692. hps_ctxt.down_loads_sum += hps_ctxt.cur_loads;
  693. hps_ctxt.down_loads_history_index =
  694. (hps_ctxt.down_loads_history_index + 1 == hps_ctxt.down_times) ?
  695. 0 : hps_ctxt.down_loads_history_index + 1;
  696. ++hps_ctxt.down_loads_count;
  697. if (hps_ctxt.down_loads_count > hps_ctxt.down_times) {
  698. BUG_ON(hps_ctxt.down_loads_sum < val);
  699. hps_ctxt.down_loads_sum -= val;
  700. }
  701. if (hps_ctxt.stats_dump_enabled)
  702. hps_ctxt_print_algo_stats_down(0);
  703. if (hps_ctxt.down_loads_count < hps_ctxt.down_times)
  704. return;
  705. down_threshold = hps_ctxt.down_threshold * hps_ctxt.down_times;
  706. val = little_num_online;
  707. while (hps_ctxt.down_loads_sum < down_threshold * (val - 1))
  708. --val;
  709. val = little_num_online - val;
  710. if (!val || little_num_online <= little_num_base)
  711. return;
  712. for (cpu = hps_ctxt.little_cpu_id_max;
  713. cpu > hps_ctxt.little_cpu_id_min; --cpu) {
  714. if (!cpumask_test_cpu(cpu, little_online_cpumask))
  715. continue;
  716. cpu_down(cpu);
  717. cpumask_clear_cpu(cpu, little_online_cpumask);
  718. --little_num_online;
  719. if (--val == 0)
  720. break;
  721. }
  722. hps_ctxt.action |= BIT(ACTION_DOWN_LITTLE);
  723. }
  724. void hps_algo_smp(void)
  725. {
  726. unsigned int cpu;
  727. unsigned int val;
  728. struct cpumask little_online_cpumask;
  729. unsigned int little_num_base, little_num_limit, little_num_online;
  730. static unsigned int hps_count;
  731. /* log purpose */
  732. char str1[64];
  733. char str2[64];
  734. int i, j;
  735. char *str1_ptr = str1;
  736. char *str2_ptr = str2;
  737. /*
  738. * run algo or not by hps_ctxt.enabled
  739. */
  740. if (!hps_ctxt.enabled) {
  741. atomic_set(&hps_ctxt.is_ondemand, 0);
  742. return;
  743. }
  744. /*
  745. * calculate cpu loading
  746. */
  747. hps_ctxt.cur_loads = 0;
  748. str1_ptr = str1;
  749. str2_ptr = str2;
  750. for_each_possible_cpu(cpu) {
  751. per_cpu(hps_percpu_ctxt, cpu).load =
  752. hps_cpu_get_percpu_load(cpu);
  753. hps_ctxt.cur_loads += per_cpu(hps_percpu_ctxt, cpu).load;
  754. if (hps_ctxt.cur_dump_enabled) {
  755. if (cpu_online(cpu))
  756. i = sprintf(str1_ptr, "%4u", 1);
  757. else
  758. i = sprintf(str1_ptr, "%4u", 0);
  759. str1_ptr += i;
  760. j = sprintf(str2_ptr, "%4u",
  761. per_cpu(hps_percpu_ctxt, cpu).load);
  762. str2_ptr += j;
  763. }
  764. }
  765. hps_ctxt.cur_nr_heavy_task = hps_cpu_get_nr_heavy_task();
  766. hps_cpu_get_tlp(&hps_ctxt.cur_tlp, &hps_ctxt.cur_iowait);
  767. /*
  768. * algo - begin
  769. */
  770. mutex_lock(&hps_ctxt.lock);
  771. hps_ctxt.action = ACTION_NONE;
  772. atomic_set(&hps_ctxt.is_ondemand, 0);
  773. /*
  774. * algo - get boundary
  775. */
  776. little_num_limit = min(hps_ctxt.little_num_limit_thermal,
  777. hps_ctxt.little_num_limit_low_battery);
  778. little_num_limit = min3(little_num_limit,
  779. hps_ctxt.little_num_limit_ultra_power_saving,
  780. hps_ctxt.little_num_limit_power_serv);
  781. little_num_base = max(hps_ctxt.little_num_base_perf_serv,
  782. hps_ctxt.little_num_base_wifi);
  783. cpumask_and(&little_online_cpumask,
  784. &hps_ctxt.little_cpumask, cpu_online_mask);
  785. little_num_online = cpumask_weight(&little_online_cpumask);
  786. if (hps_ctxt.cur_dump_enabled) {
  787. hps_debug(" CPU:%s\n", str1);
  788. hps_debug("LOAD:%s\n", str2);
  789. hps_debug(
  790. "loads(%u), hvy_tsk(%u), tlp(%u), iowait(%u), limit_t(%u), limit_lb(%u), limit_ups(%u), limit_pos(%u), base_pes(%u)\n",
  791. hps_ctxt.cur_loads, hps_ctxt.cur_nr_heavy_task,
  792. hps_ctxt.cur_tlp, hps_ctxt.cur_iowait,
  793. hps_ctxt.little_num_limit_thermal,
  794. hps_ctxt.little_num_limit_low_battery,
  795. hps_ctxt.little_num_limit_ultra_power_saving,
  796. hps_ctxt.little_num_limit_power_serv,
  797. hps_ctxt.little_num_base_perf_serv);
  798. }
  799. /*
  800. * algo - thermal, low battery
  801. */
  802. algo_smp_limit(&little_online_cpumask,
  803. little_num_base, little_num_limit, little_num_online);
  804. if (hps_ctxt.action)
  805. goto ALGO_END_WITH_ACTION;
  806. /*
  807. * algo - PerfService, heavy task detect
  808. */
  809. algo_smp_base(&little_online_cpumask,
  810. little_num_base, little_num_limit, little_num_online);
  811. if (hps_ctxt.action)
  812. goto ALGO_END_WITH_ACTION;
  813. /*
  814. * update history - tlp
  815. */
  816. val = hps_ctxt.tlp_history[hps_ctxt.tlp_history_index];
  817. hps_ctxt.tlp_history[hps_ctxt.tlp_history_index] = hps_ctxt.cur_tlp;
  818. hps_ctxt.tlp_sum += hps_ctxt.cur_tlp;
  819. hps_ctxt.tlp_history_index =
  820. (hps_ctxt.tlp_history_index + 1 == hps_ctxt.tlp_times) ?
  821. 0 : hps_ctxt.tlp_history_index + 1;
  822. ++hps_ctxt.tlp_count;
  823. if (hps_ctxt.tlp_count > hps_ctxt.tlp_times) {
  824. BUG_ON(hps_ctxt.tlp_sum < val);
  825. hps_ctxt.tlp_sum -= val;
  826. hps_ctxt.tlp_avg = hps_ctxt.tlp_sum / hps_ctxt.tlp_times;
  827. } else {
  828. hps_ctxt.tlp_avg = hps_ctxt.tlp_sum / hps_ctxt.tlp_count;
  829. }
  830. if (hps_ctxt.stats_dump_enabled)
  831. hps_ctxt_print_algo_stats_tlp(0);
  832. /*
  833. * algo - rush boost
  834. */
  835. algo_smp_rush_boost(&little_online_cpumask,
  836. little_num_base, little_num_limit, little_num_online);
  837. if (hps_ctxt.action)
  838. goto ALGO_END_WITH_ACTION;
  839. /*
  840. * algo - cpu up
  841. */
  842. algo_smp_up(&little_online_cpumask,
  843. little_num_base, little_num_limit, little_num_online);
  844. if (hps_ctxt.action)
  845. goto ALGO_END_WITH_ACTION;
  846. /*
  847. * algo - cpu down (inc. quick landing)
  848. */
  849. algo_smp_down(&little_online_cpumask,
  850. little_num_base, little_num_limit, little_num_online);
  851. if (!hps_ctxt.action)
  852. goto ALGO_END_WO_ACTION;
  853. /*
  854. * algo - end
  855. */
  856. ALGO_END_WITH_ACTION:
  857. hps_warn(
  858. "(%04lx)(%u)action end(%u)(%u)(%u)(%u) (%u)(%u)(%u)(%u)(%u) (%u)(%u)(%u) (%u)(%u)(%u) (%u)(%u)(%u)(%u)(%u) wifi_base(%u)\n",
  859. hps_ctxt.action, little_num_online,
  860. hps_ctxt.cur_loads, hps_ctxt.cur_tlp, hps_ctxt.cur_iowait,
  861. hps_ctxt.cur_nr_heavy_task,
  862. hps_ctxt.little_num_limit_thermal,
  863. hps_ctxt.little_num_limit_low_battery,
  864. hps_ctxt.little_num_limit_ultra_power_saving,
  865. hps_ctxt.little_num_limit_power_serv,
  866. hps_ctxt.little_num_base_perf_serv,
  867. hps_ctxt.up_loads_sum, hps_ctxt.up_loads_count,
  868. hps_ctxt.up_loads_history_index,
  869. hps_ctxt.down_loads_sum, hps_ctxt.down_loads_count,
  870. hps_ctxt.down_loads_history_index,
  871. hps_ctxt.rush_count, hps_ctxt.tlp_sum, hps_ctxt.tlp_count,
  872. hps_ctxt.tlp_history_index, hps_ctxt.tlp_avg,
  873. hps_ctxt.little_num_base_wifi);
  874. hps_ctxt_reset_stas_nolock();
  875. ALGO_END_WO_ACTION:
  876. hps_count++;
  877. if ((hps_count%0xf) == 0) {
  878. hps_warn(
  879. "(%04lx)(%u)DBG_HRT(%u)(%u)(%u)(%u) (%u)(%u)(%u)(%u)(%u) (%u)(%u)(%u) (%u)(%u)(%u) (%u)(%u)(%u)(%u)(%u) wifi_base(%u)\n",
  880. hps_ctxt.action, little_num_online,
  881. hps_ctxt.cur_loads, hps_ctxt.cur_tlp, hps_ctxt.cur_iowait,
  882. hps_ctxt.cur_nr_heavy_task,
  883. hps_ctxt.little_num_limit_thermal,
  884. hps_ctxt.little_num_limit_low_battery,
  885. hps_ctxt.little_num_limit_ultra_power_saving,
  886. hps_ctxt.little_num_limit_power_serv,
  887. hps_ctxt.little_num_base_perf_serv,
  888. hps_ctxt.up_loads_sum, hps_ctxt.up_loads_count,
  889. hps_ctxt.up_loads_history_index,
  890. hps_ctxt.down_loads_sum, hps_ctxt.down_loads_count,
  891. hps_ctxt.down_loads_history_index,
  892. hps_ctxt.rush_count, hps_ctxt.tlp_sum, hps_ctxt.tlp_count,
  893. hps_ctxt.tlp_history_index, hps_ctxt.tlp_avg,
  894. hps_ctxt.little_num_base_wifi);
  895. hps_count = 0;
  896. }
  897. mutex_unlock(&hps_ctxt.lock);
  898. }