/* * resume callback */ static int hps_resume(struct platform_device *pdev) { hps_warn("hps_resume\n"); if (!hps_ctxt.suspend_enabled) goto resume_end; mutex_lock(&hps_ctxt.lock); hps_ctxt.enabled = hps_ctxt.enabled_backup; mutex_unlock(&hps_ctxt.lock); resume_end: hps_ctxt.state = STATE_EARLY_SUSPEND; hps_warn("state: %u, enabled: %u, early_suspend_enabled: %u, suspend_enabled: %u, rush_boost_enabled: %u\n", hps_ctxt.state, hps_ctxt.enabled, hps_ctxt.early_suspend_enabled, hps_ctxt.suspend_enabled, hps_ctxt.rush_boost_enabled); return 0; }
/* * suspend callback */ static int hps_suspend(struct device *dev) { hps_warn("%s\n", __func__); if (!hps_ctxt.suspend_enabled) goto suspend_end; mutex_lock(&hps_ctxt.lock); hps_ctxt.enabled_backup = hps_ctxt.enabled; hps_ctxt.enabled = 0; mutex_unlock(&hps_ctxt.lock); suspend_end: hps_ctxt.state = STATE_SUSPEND; hps_warn("state: %u, enabled: %u, early_suspend_enabled: %u, suspend_enabled: %u, rush_boost_enabled: %u\n", hps_ctxt.state, hps_ctxt.enabled, hps_ctxt.early_suspend_enabled, hps_ctxt.suspend_enabled, hps_ctxt.rush_boost_enabled); return 0; }
void hps_ctxt_print_algo_stats_tlp(int toUart) { if (toUart) { hps_warn("hps_ctxt.tlp_sum: %u\n", hps_ctxt.tlp_sum); hps_warn("hps_ctxt.tlp_count: %u\n", hps_ctxt.tlp_count); hps_warn("hps_ctxt.tlp_history_index: %u\n", hps_ctxt.tlp_history_index); hps_warn("hps_ctxt.tlp_avg: %u\n", hps_ctxt.tlp_avg); hps_warn("hps_ctxt.rush_count: %u\n", hps_ctxt.rush_count); } else { hps_debug("hps_ctxt.tlp_sum: %u\n", hps_ctxt.tlp_sum); hps_debug("hps_ctxt.tlp_count: %u\n", hps_ctxt.tlp_count); hps_debug("hps_ctxt.tlp_history_index: %u\n", hps_ctxt.tlp_history_index); hps_debug("hps_ctxt.tlp_avg: %u\n", hps_ctxt.tlp_avg); hps_debug("hps_ctxt.rush_count: %u\n", hps_ctxt.rush_count); } }
/* * suspend callback */ static int hps_suspend(struct platform_device *pdev, pm_message_t state) { hps_warn("hps_suspend\n"); if (!hps_ctxt.suspend_enabled) goto suspend_end; mutex_lock(&hps_ctxt.lock); hps_ctxt.enabled_backup = hps_ctxt.enabled; hps_ctxt.enabled = 0; mutex_unlock(&hps_ctxt.lock); suspend_end: hps_ctxt.state = STATE_SUSPEND; hps_warn("state: %u, enabled: %u, early_suspend_enabled: %u, suspend_enabled: %u, rush_boost_enabled: %u\n", hps_ctxt.state, hps_ctxt.enabled, hps_ctxt.early_suspend_enabled, hps_ctxt.suspend_enabled, hps_ctxt.rush_boost_enabled); return 0; }
/* * module exit function */ static void __exit hps_exit(void) { int r = 0; hps_warn("hps_exit\n"); hps_ctxt.init_state = INIT_STATE_NOT_READY; r = hps_core_deinit(); if (r) hps_error("hps_core_deinit fail(%d)\n", r); }
/* * hps task control interface */ int hps_task_start(void) { struct sched_param param = {.sched_priority = HPS_TASK_PRIORITY }; if (hps_ctxt.tsk_struct_ptr == NULL) { hps_ctxt.tsk_struct_ptr = kthread_create(_hps_task_main, NULL, "hps_main"); if (IS_ERR(hps_ctxt.tsk_struct_ptr)) return PTR_ERR(hps_ctxt.tsk_struct_ptr); sched_setscheduler_nocheck(hps_ctxt.tsk_struct_ptr, SCHED_FIFO, ¶m); get_task_struct(hps_ctxt.tsk_struct_ptr); wake_up_process(hps_ctxt.tsk_struct_ptr); hps_warn("hps_task_start success, ptr: %p, pid: %d\n", hps_ctxt.tsk_struct_ptr, hps_ctxt.tsk_struct_ptr->pid); } else { hps_warn("hps task already exist, ptr: %p, pid: %d\n", hps_ctxt.tsk_struct_ptr, hps_ctxt.tsk_struct_ptr->pid); } return 0; }
static void hps_late_resume(struct early_suspend *h) { hps_warn("hps_late_resume\n"); mutex_lock(&hps_ctxt.lock); hps_ctxt.rush_boost_enabled = hps_ctxt.rush_boost_enabled_backup; //Reset data structure of statistics process while enter late resume mode. hps_ctxt.up_loads_sum = 0; hps_ctxt.up_loads_count = 0; hps_ctxt.up_loads_history_index = 0; hps_ctxt.up_loads_history[hps_ctxt.up_times - 1] = 0; hps_ctxt.down_loads_sum = 0; hps_ctxt.down_loads_count = 0; hps_ctxt.down_loads_history_index = 0; hps_ctxt.down_loads_history[hps_ctxt.down_times - 1] = 0; hps_ctxt.state = STATE_LATE_RESUME; mutex_unlock(&hps_ctxt.lock); hps_warn("state: %u, enabled: %u, early_suspend_enabled: %u, suspend_enabled: %u, rush_boost_enabled: %u\n", hps_ctxt.state, hps_ctxt.enabled, hps_ctxt.early_suspend_enabled, hps_ctxt.suspend_enabled, hps_ctxt.rush_boost_enabled); return; }
static void hps_early_suspend(struct early_suspend *h) { hps_warn("hps_early_suspend\n"); mutex_lock(&hps_ctxt.lock); hps_ctxt.state = STATE_EARLY_SUSPEND; hps_ctxt.rush_boost_enabled_backup = hps_ctxt.rush_boost_enabled; hps_ctxt.rush_boost_enabled = 0; //Reset data structure of statistics process while enter early suspend mode. hps_ctxt.up_loads_sum = 0; hps_ctxt.up_loads_count = 0; hps_ctxt.up_loads_history_index = 0; hps_ctxt.up_loads_history[hps_ctxt.es_up_times - 1] = 0; hps_ctxt.down_loads_sum = 0; hps_ctxt.down_loads_count = 0; hps_ctxt.down_loads_history_index = 0; hps_ctxt.down_loads_history[hps_ctxt.es_down_times - 1] = 0; if (hps_ctxt.is_hmp && hps_ctxt.early_suspend_enabled) { unsigned int cpu; for (cpu = hps_ctxt.big_cpu_id_max; cpu >= hps_ctxt.big_cpu_id_min; --cpu) { if (cpu_online(cpu)) cpu_down(cpu); } } mutex_unlock(&hps_ctxt.lock); atomic_set(&hps_ctxt.is_ondemand, 1); hps_warn("state: %u, enabled: %u, early_suspend_enabled: %u, suspend_enabled: %u, rush_boost_enabled: %u\n", hps_ctxt.state, hps_ctxt.enabled, hps_ctxt.early_suspend_enabled, hps_ctxt.suspend_enabled, hps_ctxt.rush_boost_enabled); return; }
/* * hps task main loop */ static int _hps_task_main(void *data) { int cnt = 0; void (*algo_func_ptr)(void); hps_ctxt_print_basic(1); if (hps_ctxt.is_hmp) algo_func_ptr = hps_algo_hmp; else algo_func_ptr = hps_algo_smp; while (1) { /* TODO: showld we do dvfs? * struct cpufreq_policy *policy; * policy = cpufreq_cpu_get(0); * dbs_freq_increase(policy, policy->max); * cpufreq_cpu_put(policy); */ (*algo_func_ptr) (); if (hps_ctxt.periodical_by == HPS_PERIODICAL_BY_WAIT_QUEUE) { wait_event_timeout(hps_ctxt.wait_queue, atomic_read(&hps_ctxt.is_ondemand) != 0, msecs_to_jiffies(HPS_TIMER_INTERVAL_MS)); } else if (hps_ctxt.periodical_by == HPS_PERIODICAL_BY_TIMER) { if (atomic_read(&hps_ctxt.is_ondemand) == 0) { mod_timer(&hps_ctxt.tmr_list, (jiffies + msecs_to_jiffies(HPS_TIMER_INTERVAL_MS))); set_current_state(TASK_INTERRUPTIBLE); schedule(); } } else if (hps_ctxt.periodical_by == HPS_PERIODICAL_BY_HR_TIMER) { hrtimer_cancel(&hps_ctxt.hr_timer); hrtimer_start(&hps_ctxt.hr_timer, ktime, HRTIMER_MODE_REL); set_current_state(TASK_INTERRUPTIBLE); schedule(); } if (kthread_should_stop()) break; } hps_warn("leave _hps_task_main, cnt:%08d\n", cnt++); return 0; }
/* * deinit */ int hps_core_deinit(void) { int r = 0; hps_warn("hps_core_deinit\n"); if (hps_ctxt.periodical_by == HPS_PERIODICAL_BY_TIMER) { /*deinit timer */ del_timer_sync(&hps_ctxt.tmr_list); } else if (hps_ctxt.periodical_by == HPS_PERIODICAL_BY_HR_TIMER) { /*deinit timer */ r = hrtimer_cancel(&hps_ctxt.hr_timer); if (r) hps_error("hps hr timer delete error!\n"); } hps_task_stop(); return r; }
void hps_ctxt_print_algo_bound(int toUart) { if (toUart) { hps_warn("hps_ctxt.little_num_base_perf_serv: %u\n", hps_ctxt.little_num_base_perf_serv); hps_warn("hps_ctxt.little_num_limit_thermal: %u\n", hps_ctxt.little_num_limit_thermal); hps_warn("hps_ctxt.little_num_limit_low_battery: %u\n", hps_ctxt.little_num_limit_low_battery); hps_warn("hps_ctxt.big_num_base_perf_serv: %u\n", hps_ctxt.big_num_base_perf_serv); hps_warn("hps_ctxt.big_num_limit_thermal: %u\n", hps_ctxt.big_num_limit_thermal); hps_warn("hps_ctxt.big_num_limit_low_battery: %u\n", hps_ctxt.big_num_limit_low_battery); } else { hps_debug("hps_ctxt.little_num_base_perf_serv: %u\n", hps_ctxt.little_num_base_perf_serv); hps_debug("hps_ctxt.little_num_limit_thermal: %u\n", hps_ctxt.little_num_limit_thermal); hps_debug("hps_ctxt.little_num_limit_low_battery: %u\n", hps_ctxt.little_num_limit_low_battery); hps_debug("hps_ctxt.big_num_base_perf_serv: %u\n", hps_ctxt.big_num_base_perf_serv); hps_debug("hps_ctxt.big_num_limit_thermal: %u\n", hps_ctxt.big_num_limit_thermal); hps_debug("hps_ctxt.big_num_limit_low_battery: %u\n", hps_ctxt.big_num_limit_low_battery); } }
/* * probe callback */ static int hps_probe(struct platform_device *pdev) { hps_warn("hps_probe\n"); return 0; }
/* * hps algo - hmp */ void hps_algo_hmp(void) { unsigned int cpu; unsigned int val; struct cpumask little_online_cpumask; struct cpumask big_online_cpumask; unsigned int little_num_base, little_num_limit, little_num_online; unsigned int big_num_base, big_num_limit, big_num_online; //log purpose char str1[64]; char str2[64]; int i, j; char * str1_ptr = str1; char * str2_ptr = str2; /* * run algo or not by hps_ctxt.enabled */ if (!hps_ctxt.enabled) { atomic_set(&hps_ctxt.is_ondemand, 0); return; } /* * calculate cpu loading */ hps_ctxt.cur_loads = 0; str1_ptr = str1; str2_ptr = str2; for_each_possible_cpu(cpu) { per_cpu(hps_percpu_ctxt, cpu).load = hps_cpu_get_percpu_load(cpu); hps_ctxt.cur_loads += per_cpu(hps_percpu_ctxt, cpu).load; if (hps_ctxt.cur_dump_enabled) { if (cpu_online(cpu)) i = sprintf(str1_ptr, "%4u", 1); else i = sprintf(str1_ptr, "%4u", 0); str1_ptr += i; j = sprintf(str2_ptr, "%4u", per_cpu(hps_percpu_ctxt, cpu).load); str2_ptr += j; } } hps_ctxt.cur_nr_heavy_task = hps_cpu_get_nr_heavy_task(); hps_cpu_get_tlp(&hps_ctxt.cur_tlp, &hps_ctxt.cur_iowait); /* * algo - begin */ mutex_lock(&hps_ctxt.lock); hps_ctxt.action = ACTION_NONE; atomic_set(&hps_ctxt.is_ondemand, 0); /* * algo - get boundary */ little_num_limit = min(hps_ctxt.little_num_limit_thermal, hps_ctxt.little_num_limit_low_battery); little_num_base = hps_ctxt.little_num_base_perf_serv; cpumask_and(&little_online_cpumask, &hps_ctxt.little_cpumask, cpu_online_mask); little_num_online = cpumask_weight(&little_online_cpumask); //TODO: no need if is_hmp big_num_limit = min(hps_ctxt.big_num_limit_thermal, hps_ctxt.big_num_limit_low_battery); big_num_base = max(hps_ctxt.cur_nr_heavy_task, hps_ctxt.big_num_base_perf_serv); cpumask_and(&big_online_cpumask, &hps_ctxt.big_cpumask, cpu_online_mask); big_num_online = cpumask_weight(&big_online_cpumask); if (hps_ctxt.cur_dump_enabled) { hps_debug(" CPU:%s\n", str1); hps_debug("LOAD:%s\n", str2); hps_debug("loads(%u), hvy_tsk(%u), tlp(%u), iowait(%u), limit_t(%u)(%u), limit_lb(%u)(%u), base_ps(%u)(%u)\n", hps_ctxt.cur_loads, hps_ctxt.cur_nr_heavy_task, hps_ctxt.cur_tlp, hps_ctxt.cur_iowait, hps_ctxt.little_num_limit_thermal, hps_ctxt.big_num_limit_thermal, hps_ctxt.little_num_limit_low_battery, hps_ctxt.big_num_limit_low_battery, hps_ctxt.little_num_base_perf_serv, hps_ctxt.big_num_base_perf_serv); } //ALGO_LIMIT: /* * algo - thermal, low battery */ if (big_num_online > big_num_limit) { val = big_num_online - big_num_limit; for (cpu = hps_ctxt.big_cpu_id_max; cpu >= hps_ctxt.big_cpu_id_min; --cpu) { if (cpumask_test_cpu(cpu, &big_online_cpumask)) { cpu_down(cpu); cpumask_clear_cpu(cpu, &big_online_cpumask); --big_num_online; if (--val == 0) break; } } BUG_ON(val); set_bit(ACTION_LIMIT_BIG, (unsigned long *)&hps_ctxt.action); } if (little_num_online > little_num_limit) { val = little_num_online - little_num_limit; for (cpu = hps_ctxt.little_cpu_id_max; cpu > hps_ctxt.little_cpu_id_min; --cpu) { if (cpumask_test_cpu(cpu, &little_online_cpumask)) { cpu_down(cpu); cpumask_clear_cpu(cpu, &little_online_cpumask); --little_num_online; if (--val == 0) break; } } BUG_ON(val); set_bit(ACTION_LIMIT_LITTLE, (unsigned long *)&hps_ctxt.action); } if (hps_ctxt.action) goto ALGO_END_WITH_ACTION; //ALGO_BASE: /* * algo - PerfService, heavy task detect */ BUG_ON(big_num_online > big_num_limit); BUG_ON(little_num_online > little_num_limit); if ((big_num_online < big_num_base) && (big_num_online < big_num_limit) && (hps_ctxt.state == STATE_LATE_RESUME)) { val = min(big_num_base, big_num_limit) - big_num_online; for (cpu = hps_ctxt.big_cpu_id_min; cpu <= hps_ctxt.big_cpu_id_max; ++cpu) { if (!cpumask_test_cpu(cpu, &big_online_cpumask)) { cpu_up(cpu); cpumask_set_cpu(cpu, &big_online_cpumask); ++big_num_online; if (--val == 0) break; } } BUG_ON(val); set_bit(ACTION_BASE_BIG, (unsigned long *)&hps_ctxt.action); } if ((little_num_online < little_num_base) && (little_num_online < little_num_limit) && (little_num_online + big_num_online < hps_ctxt.little_num_base_perf_serv + hps_ctxt.big_num_base_perf_serv)) { val = min(little_num_base, little_num_limit) - little_num_online; if (big_num_online > hps_ctxt.big_num_base_perf_serv) val -= big_num_online - hps_ctxt.big_num_base_perf_serv; for (cpu = hps_ctxt.little_cpu_id_min; cpu <= hps_ctxt.little_cpu_id_max; ++cpu) { if (!cpumask_test_cpu(cpu, &little_online_cpumask)) { cpu_up(cpu); cpumask_set_cpu(cpu, &little_online_cpumask); ++little_num_online; if (--val == 0) break; } } BUG_ON(val); set_bit(ACTION_BASE_LITTLE, (unsigned long *)&hps_ctxt.action); } if (hps_ctxt.action) goto ALGO_END_WITH_ACTION; /* * update history - tlp */ val = hps_ctxt.tlp_history[hps_ctxt.tlp_history_index]; hps_ctxt.tlp_history[hps_ctxt.tlp_history_index] = hps_ctxt.cur_tlp; hps_ctxt.tlp_sum += hps_ctxt.cur_tlp; hps_ctxt.tlp_history_index = (hps_ctxt.tlp_history_index + 1 == hps_ctxt.tlp_times) ? 0 : hps_ctxt.tlp_history_index + 1; ++hps_ctxt.tlp_count; if (hps_ctxt.tlp_count > hps_ctxt.tlp_times) { BUG_ON(hps_ctxt.tlp_sum < val); hps_ctxt.tlp_sum -= val; hps_ctxt.tlp_avg = hps_ctxt.tlp_sum / hps_ctxt.tlp_times; } else { hps_ctxt.tlp_avg = hps_ctxt.tlp_sum / hps_ctxt.tlp_count; } if (hps_ctxt.stats_dump_enabled) hps_ctxt_print_algo_stats_tlp(0); //ALGO_RUSH_BOOST: /* * algo - rush boost */ if (hps_ctxt.rush_boost_enabled) { if (hps_ctxt.cur_loads > hps_ctxt.rush_boost_threshold * (little_num_online + big_num_online)) ++hps_ctxt.rush_count; else hps_ctxt.rush_count = 0; if ((hps_ctxt.rush_count >= hps_ctxt.rush_boost_times) && ((little_num_online + big_num_online) * 100 < hps_ctxt.tlp_avg)) { val = hps_ctxt.tlp_avg / 100 + (hps_ctxt.tlp_avg % 100 ? 1 : 0); BUG_ON(!(val > little_num_online + big_num_online)); if (val > num_possible_cpus()) val = num_possible_cpus(); val -= little_num_online + big_num_online; if ((val) && (little_num_online < little_num_limit)) { for (cpu = hps_ctxt.little_cpu_id_min; cpu <= hps_ctxt.little_cpu_id_max; ++cpu) { if (!cpumask_test_cpu(cpu, &little_online_cpumask)) { cpu_up(cpu); cpumask_set_cpu(cpu, &little_online_cpumask); ++little_num_online; if (--val == 0) break; } } set_bit(ACTION_RUSH_BOOST_LITTLE, (unsigned long *)&hps_ctxt.action); } else if ((val) && (big_num_online < big_num_limit) && (hps_ctxt.state == STATE_LATE_RESUME)) { for (cpu = hps_ctxt.big_cpu_id_min; cpu <= hps_ctxt.big_cpu_id_max; ++cpu) { if (!cpumask_test_cpu(cpu, &big_online_cpumask)) { cpu_up(cpu); cpumask_set_cpu(cpu, &big_online_cpumask); ++big_num_online; if (--val == 0) break; } } set_bit(ACTION_RUSH_BOOST_BIG, (unsigned long *)&hps_ctxt.action); } } } //if (hps_ctxt.rush_boost_enabled) if (hps_ctxt.action) goto ALGO_END_WITH_ACTION; //ALGO_UP: /* * algo - cpu up */ if ((little_num_online + big_num_online) < num_possible_cpus()) { /* * update history - up */ val = hps_ctxt.up_loads_history[hps_ctxt.up_loads_history_index]; hps_ctxt.up_loads_history[hps_ctxt.up_loads_history_index] = hps_ctxt.cur_loads; hps_ctxt.up_loads_sum += hps_ctxt.cur_loads; hps_ctxt.up_loads_history_index = (hps_ctxt.up_loads_history_index + 1 == hps_ctxt.up_times) ? 0 : hps_ctxt.up_loads_history_index + 1; ++hps_ctxt.up_loads_count; //XXX: use >= or >, which is benifit? use > if (hps_ctxt.up_loads_count > hps_ctxt.up_times) { BUG_ON(hps_ctxt.up_loads_sum < val); hps_ctxt.up_loads_sum -= val; } if (hps_ctxt.stats_dump_enabled) hps_ctxt_print_algo_stats_up(0); if (hps_ctxt.up_loads_count >= hps_ctxt.up_times) { if (hps_ctxt.up_loads_sum > hps_ctxt.up_threshold * hps_ctxt.up_times * (little_num_online + big_num_online)) { if (little_num_online < little_num_limit) { for (cpu = hps_ctxt.little_cpu_id_min; cpu <= hps_ctxt.little_cpu_id_max; ++cpu) { if (!cpumask_test_cpu(cpu, &little_online_cpumask)) { cpu_up(cpu); cpumask_set_cpu(cpu, &little_online_cpumask); ++little_num_online; break; } } set_bit(ACTION_UP_LITTLE, (unsigned long *)&hps_ctxt.action); } else if ((big_num_online < big_num_limit) && (hps_ctxt.state == STATE_LATE_RESUME)) { for (cpu = hps_ctxt.big_cpu_id_min; cpu <= hps_ctxt.big_cpu_id_max; ++cpu) { if (!cpumask_test_cpu(cpu, &big_online_cpumask)) { cpu_up(cpu); cpumask_set_cpu(cpu, &big_online_cpumask); ++big_num_online; break; } } set_bit(ACTION_UP_BIG, (unsigned long *)&hps_ctxt.action); } } } //if (hps_ctxt.up_loads_count >= hps_ctxt.up_times) } //if ((little_num_online + big_num_online) < num_possible_cpus()) if (hps_ctxt.action) goto ALGO_END_WITH_ACTION; //ALGO_DOWN: /* * algo - cpu down (inc. quick landing) */ if (little_num_online + big_num_online > 1) { /* * update history - down */ val = hps_ctxt.down_loads_history[hps_ctxt.down_loads_history_index]; hps_ctxt.down_loads_history[hps_ctxt.down_loads_history_index] = hps_ctxt.cur_loads; hps_ctxt.down_loads_sum += hps_ctxt.cur_loads; hps_ctxt.down_loads_history_index = (hps_ctxt.down_loads_history_index + 1 == hps_ctxt.down_times) ? 0 : hps_ctxt.down_loads_history_index + 1; ++hps_ctxt.down_loads_count; //XXX: use >= or >, which is benifit? use > if (hps_ctxt.down_loads_count > hps_ctxt.down_times) { BUG_ON(hps_ctxt.down_loads_sum < val); hps_ctxt.down_loads_sum -= val; } if (hps_ctxt.stats_dump_enabled) hps_ctxt_print_algo_stats_down(0); if (hps_ctxt.down_loads_count >= hps_ctxt.down_times) { unsigned int down_threshold = hps_ctxt.down_threshold * hps_ctxt.down_times; val = little_num_online + big_num_online; while (hps_ctxt.down_loads_sum < down_threshold * (val - 1)) --val; val = little_num_online + big_num_online - val; if ((val) && (big_num_online > big_num_base)) { for (cpu = hps_ctxt.big_cpu_id_max; cpu >= hps_ctxt.big_cpu_id_min; --cpu) { if (cpumask_test_cpu(cpu, &big_online_cpumask)) { cpu_down(cpu); cpumask_clear_cpu(cpu, &big_online_cpumask); --big_num_online; if (--val == 0) break; } } set_bit(ACTION_DOWN_BIG, (unsigned long *)&hps_ctxt.action); } else if ((val) && (little_num_online > little_num_base)) { for (cpu = hps_ctxt.little_cpu_id_max; cpu > hps_ctxt.little_cpu_id_min; --cpu) { if (cpumask_test_cpu(cpu, &little_online_cpumask)) { cpu_down(cpu); cpumask_clear_cpu(cpu, &little_online_cpumask); --little_num_online; if (--val == 0) break; } } set_bit(ACTION_DOWN_LITTLE, (unsigned long *)&hps_ctxt.action); } } //if (hps_ctxt.down_loads_count >= hps_ctxt.down_times) } //if (little_num_online + big_num_online > 1) if (hps_ctxt.action) goto ALGO_END_WITH_ACTION; //ALGO_BIG_TO_LITTLE: /* * algo - b2L */ if (hps_ctxt.down_loads_count >= hps_ctxt.down_times) { if ((little_num_online < little_num_limit) && (big_num_online > big_num_base)) { //find last online big for (val = hps_ctxt.big_cpu_id_max; val >= hps_ctxt.big_cpu_id_min; --val) { if (cpumask_test_cpu(val, &big_online_cpumask)) break; } BUG_ON(val < hps_ctxt.big_cpu_id_min); //verify whether b2L will open 1 little if (per_cpu(hps_percpu_ctxt, val).load * CPU_DMIPS_BIG_LITTLE_DIFF / 100 + hps_ctxt.up_loads_sum / hps_ctxt.up_times <= hps_ctxt.up_threshold * (little_num_online + big_num_online)) { //up 1 little for (cpu = hps_ctxt.little_cpu_id_min; cpu <= hps_ctxt.little_cpu_id_max; ++cpu) { if (!cpumask_test_cpu(cpu, &little_online_cpumask)) { cpu_up(cpu); cpumask_set_cpu(cpu, &little_online_cpumask); ++little_num_online; break; } } //down 1 big cpu_down(val); cpumask_clear_cpu(cpu, &big_online_cpumask); --big_num_online; set_bit(ACTION_BIG_TO_LITTLE, (unsigned long *)&hps_ctxt.action); } } //if ((little_num_online < little_num_limit) && (big_num_online > big_num_base)) } //if (hps_ctxt.down_loads_count >= hps_ctxt.down_times) if (!hps_ctxt.action) goto ALGO_END_WO_ACTION; /* * algo - end */ ALGO_END_WITH_ACTION: hps_warn("(%04x)(%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)\n", hps_ctxt.action, little_num_online, big_num_online, hps_ctxt.cur_loads, hps_ctxt.cur_tlp, hps_ctxt.cur_iowait, hps_ctxt.cur_nr_heavy_task, hps_ctxt.little_num_limit_thermal, hps_ctxt.big_num_limit_thermal, hps_ctxt.little_num_limit_low_battery, hps_ctxt.big_num_limit_low_battery, hps_ctxt.little_num_base_perf_serv, hps_ctxt.big_num_base_perf_serv, hps_ctxt.up_loads_sum, hps_ctxt.up_loads_count, hps_ctxt.up_loads_history_index, hps_ctxt.down_loads_sum, hps_ctxt.down_loads_count, hps_ctxt.down_loads_history_index, hps_ctxt.rush_count, hps_ctxt.tlp_sum, hps_ctxt.tlp_count, hps_ctxt.tlp_history_index, hps_ctxt.tlp_avg); hps_ctxt_reset_stas_nolock(); ALGO_END_WO_ACTION: mutex_unlock(&hps_ctxt.lock); return; }