static void tegra_auto_hotplug_work_func(struct work_struct *work) { bool up = false; unsigned int cpu = nr_cpu_ids; unsigned long now = jiffies; static unsigned long last_change_time; mutex_lock(tegra3_cpu_lock); switch (hp_state) { case TEGRA_HP_DISABLED: case TEGRA_HP_IDLE: break; case TEGRA_HP_DOWN: cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) { up = false; } else if (!is_lp_cluster() && !no_lp && !pm_qos_request(PM_QOS_MIN_ONLINE_CPUS)) { if(!clk_set_parent(cpu_clk, cpu_lp_clk)) { hp_stats_update(CONFIG_NR_CPUS, true); hp_stats_update(0, false); /* catch-up with governor target speed */ tegra_cpu_set_speed_cap(NULL); break; } } queue_delayed_work( hotplug_wq, &hotplug_work, down_delay); break; case TEGRA_HP_UP: if (is_lp_cluster() && !no_lp) { if(!clk_set_parent(cpu_clk, cpu_g_clk)) { hp_stats_update(CONFIG_NR_CPUS, false); hp_stats_update(0, true); /* catch-up with governor target speed */ tegra_cpu_set_speed_cap(NULL); } } else { switch (tegra_cpu_speed_balance()) { /* cpu speed is up and balanced - one more on-line */ case TEGRA_CPU_SPEED_BALANCED: cpu = cpumask_next_zero(0, cpu_online_mask); if (cpu < nr_cpu_ids) up = true; break; /* cpu speed is up, but skewed - remove one core */ case TEGRA_CPU_SPEED_SKEWED: cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) up = false; break; /* cpu speed is up, but under-utilized - do nothing */ case TEGRA_CPU_SPEED_BIASED: default: break; } } queue_delayed_work( hotplug_wq, &hotplug_work, up2gn_delay); break; default: pr_err("%s: invalid tegra hotplug state %d\n", __func__, hp_state); } if (!up && ((now - last_change_time) < down_delay)) cpu = nr_cpu_ids; if (cpu < nr_cpu_ids) { last_change_time = now; hp_stats_update(cpu, up); } mutex_unlock(tegra3_cpu_lock); if (cpu < nr_cpu_ids) { if (up) { printk("cpu_up(%u)+\n",cpu); cpu_up(cpu); printk("cpu_up(%u)-\n",cpu); } else { printk("cpu_down(%u)+\n",cpu); cpu_down(cpu); printk("cpu_down(%u)-\n",cpu); } } }
void gcpu_plug(unsigned int cpu_freq) { unsigned long up_delay, top_freq, bottom_freq; static bool first_call = true; static cputime64_t total_time = 0; static cputime64_t last_time; cputime64_t current_time; cputime64_t this_time = 0; if (is_plugging) { return; } current_time = ktime_to_ms(ktime_get()); if (first_call) { first_call = false; } else { this_time = current_time - last_time; } total_time += this_time; up_delay = up2gn_delay; top_freq = idle_bottom_freq; bottom_freq = idle_bottom_freq; if (smp_processor_id() == 0) mp_state = __cpu_plug(); else mp_state = TEGRA_HP_IDLE; switch (hp_state) { case TEGRA_HP_DISABLED: total_time = 0; break; case TEGRA_HP_IDLE: if (cpu_freq > top_freq) { hp_state = TEGRA_HP_UP; } else if (cpu_freq <= bottom_freq) { hp_state = TEGRA_HP_DOWN; } total_time = 0; break; case TEGRA_HP_DOWN: if (cpu_freq > top_freq) { hp_state = TEGRA_HP_UP; total_time = 0; } break; case TEGRA_HP_UP: if (cpu_freq <= bottom_freq) { hp_state = TEGRA_HP_DOWN; total_time = 0; } break; } if (hp_state == TEGRA_HP_UP) { switch (tegra_cpu_speed_balance()) { /* cpu speed is up and balanced - one more on-line */ case TEGRA_CPU_SPEED_BALANCED: if ((total_time >= up_time) && (mp_state == TEGRA_HP_UP)) { is_plugging = true; last_state = TEGRA_HP_UP; queue_work(cpuplug_wq, &cpuplug_work); total_time = 0; } break; /* cpu speed is up, but skewed - remove one core */ case TEGRA_CPU_SPEED_SKEWED: if ((total_time >= down_time) && (mp_state == TEGRA_HP_DOWN)) { is_plugging = true; last_state = TEGRA_HP_DOWN; queue_work(cpuplug_wq, &cpuplug_work); total_time = 0; } break; /* cpu speed is up, but under-utilized - do nothing */ case TEGRA_CPU_SPEED_BIASED: if (total_time >= up_time) total_time = 0; default: break; } } else if (hp_state == TEGRA_HP_DOWN) { if ((total_time >= down_time) && (mp_state == TEGRA_HP_DOWN)) { is_plugging = true; last_state = TEGRA_HP_DOWN; queue_work(cpuplug_wq, &cpuplug_work); total_time = 0; } } last_time = ktime_to_ms(ktime_get()); }
static void tegra_auto_hotplug_work_func(struct work_struct *work) { bool up = false; unsigned int cpu = nr_cpu_ids; unsigned long now = jiffies; mutex_lock(tegra3_cpu_lock); switch (hp_state) { case TEGRA_HP_DISABLED: case TEGRA_HP_IDLE: break; case TEGRA_HP_DOWN: cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) { up = false; } else if (!is_lp_cluster() && !no_lp && ((now - last_change_time) >= down_delay)) { /* start show-p1984, 2012.05.13 */ if (!cpu_clk) { printk(KERN_INFO "[cpu-tegra3]: re setting cpu_clk"); cpu_clk = clk_get_sys(NULL, "cpu"); } if (!cpu_lp_clk) { printk(KERN_INFO "[cpu-tegra3]: re setting cpu_lp_clk"); cpu_lp_clk = clk_get_sys(NULL, "cpu_lp"); } if (IS_ERR(cpu_clk) || IS_ERR(cpu_lp_clk)) { printk(KERN_INFO "[cpu-tegra3]: Error, cpu_clk/cpu_lp_lck not set"); break; } /* end show-p1984, 2012.05.13 */ if(!clk_set_parent(cpu_clk, cpu_lp_clk)) { hp_stats_update(CONFIG_NR_CPUS, true); hp_stats_update(0, false); /* catch-up with governor target speed */ tegra_cpu_set_speed_cap(NULL); break; } } queue_delayed_work( hotplug_wq, &hotplug_work, up2gn_delay); break; case TEGRA_HP_UP: if (is_lp_cluster() && !no_lp) { if(!clk_set_parent(cpu_clk, cpu_g_clk)) { last_change_time = now; hp_stats_update(CONFIG_NR_CPUS, false); hp_stats_update(0, true); /* catch-up with governor target speed */ tegra_cpu_set_speed_cap(NULL); } } else { switch (tegra_cpu_speed_balance()) { /* cpu speed is up and balanced - one more on-line */ case TEGRA_CPU_SPEED_BALANCED: cpu = cpumask_next_zero(0, cpu_online_mask); if (cpu < nr_cpu_ids) up = true; break; /* cpu speed is up, but skewed - remove one core */ case TEGRA_CPU_SPEED_SKEWED: cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) up = false; break; /* cpu speed is up, but under-utilized - do nothing */ case TEGRA_CPU_SPEED_BIASED: default: break; } } queue_delayed_work( hotplug_wq, &hotplug_work, up2gn_delay); break; default: pr_err("%s: invalid tegra hotplug state %d\n", __func__, hp_state); } if (!up && ((now - last_change_time) < down_delay)) cpu = nr_cpu_ids; if (cpu < nr_cpu_ids) { last_change_time = now; hp_stats_update(cpu, up); } mutex_unlock(tegra3_cpu_lock); /* Ignore hotplug during shutdown. This prevents us doing * work that can fail. */ if (system_state <= SYSTEM_RUNNING && cpu < nr_cpu_ids) { if (up){ printk(KERN_INFO "cpu_up(%u)+\n",cpu); cpu_up(cpu); printk(KERN_INFO "cpu_up(%u)-\n",cpu); } else{ printk(KERN_INFO "cpu_down(%u)+\n",cpu); cpu_down(cpu); printk(KERN_INFO "cpu_down(%u)-\n",cpu); } } }
static void tegra_auto_hotplug_work_func(struct work_struct *work) { bool up = false; unsigned int cpu = nr_cpu_ids; mutex_lock(tegra3_cpu_lock); if (mp_policy && !is_lp_cluster()) { mutex_unlock(tegra3_cpu_lock); return; } switch (hp_state) { case TEGRA_HP_DISABLED: case TEGRA_HP_IDLE: break; case TEGRA_HP_DOWN: cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) { up = false; queue_delayed_work( hotplug_wq, &hotplug_work, down_delay); hp_stats_update(cpu, false); } else if (!is_lp_cluster() && !no_lp) { if(!clk_set_parent(cpu_clk, cpu_lp_clk)) { CPU_DEBUG_PRINTK(CPU_DEBUG_HOTPLUG, " enter LPCPU"); hp_stats_update(CONFIG_NR_CPUS, true); hp_stats_update(0, false); /* catch-up with governor target speed */ tegra_cpu_set_speed_cap(NULL); } else queue_delayed_work( hotplug_wq, &hotplug_work, down_delay); } break; case TEGRA_HP_UP: if (is_lp_cluster() && !no_lp) { if(!clk_set_parent(cpu_clk, cpu_g_clk)) { CPU_DEBUG_PRINTK(CPU_DEBUG_HOTPLUG, " leave LPCPU (%s)", __func__); hp_stats_update(CONFIG_NR_CPUS, false); hp_stats_update(0, true); /* catch-up with governor target speed */ tegra_cpu_set_speed_cap(NULL); } } else { switch (tegra_cpu_speed_balance()) { /* cpu speed is up and balanced - one more on-line */ case TEGRA_CPU_SPEED_BALANCED: cpu = cpumask_next_zero(0, cpu_online_mask); if (cpu < nr_cpu_ids) { up = true; hp_stats_update(cpu, true); } break; /* cpu speed is up, but skewed - remove one core */ case TEGRA_CPU_SPEED_SKEWED: cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) { up = false; hp_stats_update(cpu, false); } break; /* cpu speed is up, but under-utilized - do nothing */ case TEGRA_CPU_SPEED_BIASED: default: break; } } queue_delayed_work( hotplug_wq, &hotplug_work, up2gn_delay); break; default: pr_err(CPU_HOTPLUG_TAG"%s: invalid tegra hotplug state %d\n", __func__, hp_state); } mutex_unlock(tegra3_cpu_lock); if (system_state > SYSTEM_RUNNING) { pr_info(CPU_HOTPLUG_TAG" system is not running\n"); } else if (cpu < nr_cpu_ids) { if (up) { updateCurrentCPUTotalActiveTime(); cpu_up(cpu); pr_info(CPU_HOTPLUG_TAG" turn on CPU %d, online CPU 0-3=[%d%d%d%d]\n", cpu, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3)); } else { updateCurrentCPUTotalActiveTime(); cpu_down(cpu); pr_info(CPU_HOTPLUG_TAG" turn off CPU %d, online CPU 0-3=[%d%d%d%d]\n", cpu, cpu_online(0), cpu_online(1), cpu_online(2), cpu_online(3)); } } }
static void tegra_auto_hotplug_work_func(struct work_struct *work) { bool up = false; unsigned int cpu = nr_cpu_ids; mutex_lock(tegra3_cpu_lock); switch (hp_state) { case TEGRA_HP_DISABLED: case TEGRA_HP_IDLE: break; case TEGRA_HP_DOWN: cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) { up = false; queue_delayed_work( hotplug_wq, &hotplug_work, down_delay); hp_stats_update(cpu, false); } else if (!is_lp_cluster() && !no_lp) { if(!clk_set_parent(cpu_clk, cpu_lp_clk)) { hp_stats_update(CONFIG_NR_CPUS, true); hp_stats_update(0, false); /* catch-up with governor target speed */ tegra_cpu_set_speed_cap(NULL); } else queue_delayed_work( hotplug_wq, &hotplug_work, down_delay); } break; case TEGRA_HP_UP: if (is_lp_cluster() && !no_lp) { if(!clk_set_parent(cpu_clk, cpu_g_clk)) { hp_stats_update(CONFIG_NR_CPUS, false); hp_stats_update(0, true); /* catch-up with governor target speed */ tegra_cpu_set_speed_cap(NULL); } } else { switch (tegra_cpu_speed_balance()) { /* cpu speed is up and balanced - one more on-line */ case TEGRA_CPU_SPEED_BALANCED: cpu = cpumask_next_zero(0, cpu_online_mask); if (cpu < nr_cpu_ids) { up = true; hp_stats_update(cpu, true); } break; /* cpu speed is up, but skewed - remove one core */ case TEGRA_CPU_SPEED_SKEWED: cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) { up = false; hp_stats_update(cpu, false); } break; /* cpu speed is up, but under-utilized - do nothing */ case TEGRA_CPU_SPEED_BIASED: default: break; } } queue_delayed_work( hotplug_wq, &hotplug_work, up2gn_delay); break; default: pr_err("%s: invalid tegra hotplug state %d\n", __func__, hp_state); } mutex_unlock(tegra3_cpu_lock); if (cpu < nr_cpu_ids) { /*if (up) cpu_up(cpu); else cpu_down(cpu);*/ if (up){ if (num_online_cpus() < hotplug_num) cpu_up(cpu); else printk("tegra_auto_hotplug_work_func: need up , but hotplug_num=%u num_online_cpus()=%u \n",hotplug_num, num_online_cpus()); } else cpu_down(cpu); } }