static void tegra_auto_cpuplug_work_func(struct work_struct *work)
{
	bool up = false;
	unsigned int cpu = nr_cpu_ids;

	mutex_lock(tegra3_cpu_lock);
	if (hp_state != TEGRA_HP_DISABLED) {
		switch (last_state) {
		case TEGRA_HP_UP:
			cpu = cpumask_next_zero(0, cpu_online_mask);
			if (cpu < nr_cpu_ids) {
				up = true;
				hp_stats_update(cpu, true);
			}
			break;
		case TEGRA_HP_DOWN:
			cpu = tegra_get_slowest_cpu_n();
			if (cpu < nr_cpu_ids) {
				up = false;
				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
					pr_err(CPU_HOTPLUG_TAG" clk_set_parent fail\n");
			}
			break;
		}
	}
	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));
		}
	}

	mutex_lock(tegra3_cpu_lock);
	is_plugging = false;
	mutex_unlock(tegra3_cpu_lock);
}
예제 #2
0
static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
{
	mutex_lock(tegra3_cpu_lock);

	if ((n >= 2) && is_lp_cluster()) {
		if (!clk_set_parent(cpu_clk, cpu_g_clk)) {
			hp_stats_update(CONFIG_NR_CPUS, false);
			hp_stats_update(0, true);
		}
	}
	/* update governor state machine */
	tegra_cpu_set_speed_cap(NULL);
	mutex_unlock(tegra3_cpu_lock);
	return NOTIFY_OK;
}
static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
{
    mutex_lock(tegra3_cpu_lock);

    if ((n >= 1) && is_lp_cluster()) {
        /* make sure cpu rate is within g-mode range before switching */
        unsigned int speed = max(
                                 tegra_getspeed(0), clk_get_min_rate(cpu_g_clk) / 1000);
        tegra_update_cpu_speed(speed);

        if (!clk_set_parent(cpu_clk, cpu_g_clk)) {
            hp_stats_update(CONFIG_NR_CPUS, false);
            hp_stats_update(0, true);
        }
    }
    /* update governor state machine */
    tegra_cpu_set_speed_cap(NULL);
    mutex_unlock(tegra3_cpu_lock);
    return NOTIFY_OK;
}
static int hp_stats_show(struct seq_file *s, void *data)
{
    int i;
    u64 cur_jiffies = get_jiffies_64();

    mutex_lock(tegra3_cpu_lock);
    if (hp_state != TEGRA_HP_DISABLED) {
        for (i = 0; i <= CONFIG_NR_CPUS; i++) {
            bool was_up = (hp_stats[i].up_down_count & 0x1);
            hp_stats_update(i, was_up);
        }
    }
    mutex_unlock(tegra3_cpu_lock);

    seq_printf(s, "%-15s ", "cpu:");
    for (i = 0; i < CONFIG_NR_CPUS; i++) {
        seq_printf(s, "G%-9d ", i);
    }
    seq_printf(s, "LP\n");

    seq_printf(s, "%-15s ", "transitions:");
    for (i = 0; i <= CONFIG_NR_CPUS; i++) {
        seq_printf(s, "%-10u ", hp_stats[i].up_down_count);
    }
    seq_printf(s, "\n");

    seq_printf(s, "%-15s ", "time plugged:");
    for (i = 0; i <= CONFIG_NR_CPUS; i++) {
        seq_printf(s, "%-10llu ",
                   cputime64_to_clock_t(hp_stats[i].time_up_total));
    }
    seq_printf(s, "\n");

    seq_printf(s, "%-15s %llu\n", "time-stamp:",
               cputime64_to_clock_t(cur_jiffies));

    return 0;
}
void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
{
    unsigned long up_delay, top_freq, bottom_freq;

    if (!is_g_cluster_present())
        return;

    if (hp_state == TEGRA_HP_DISABLED)
        return;

    if (suspend) {
        hp_state = TEGRA_HP_IDLE;

        /* Switch to G-mode if suspend rate is high enough */
        if (is_lp_cluster() && (cpu_freq >= idle_bottom_freq)) {
            if (!clk_set_parent(cpu_clk, cpu_g_clk)) {
                hp_stats_update(CONFIG_NR_CPUS, false);
                hp_stats_update(0, true);
            }
        }
        return;
    }

    if (is_lp_cluster()) {
        up_delay = up2g0_delay;
        top_freq = idle_top_freq;
        bottom_freq = 0;
    } else {
        up_delay = up2gn_delay;
        top_freq = idle_bottom_freq;
        bottom_freq = idle_bottom_freq;
    }

    if (pm_qos_request(PM_QOS_MIN_ONLINE_CPUS) >= 2) {
        if (hp_state != TEGRA_HP_UP) {
            hp_state = TEGRA_HP_UP;
            queue_delayed_work(
                hotplug_wq, &hotplug_work, up_delay);
        }
        return;
    }

    switch (hp_state) {
    case TEGRA_HP_IDLE:
        if (cpu_freq > top_freq) {
            hp_state = TEGRA_HP_UP;
            queue_delayed_work(
                hotplug_wq, &hotplug_work, up_delay);
        } else if (cpu_freq <= bottom_freq) {
            hp_state = TEGRA_HP_DOWN;
            queue_delayed_work(
                hotplug_wq, &hotplug_work, down_delay);
        }
        break;
    case TEGRA_HP_DOWN:
        if (cpu_freq > top_freq) {
            hp_state = TEGRA_HP_UP;
            queue_delayed_work(
                hotplug_wq, &hotplug_work, up_delay);
        } else if (cpu_freq > bottom_freq) {
            hp_state = TEGRA_HP_IDLE;
        }
        break;
    case TEGRA_HP_UP:
        if (cpu_freq <= bottom_freq) {
            hp_state = TEGRA_HP_DOWN;
            queue_delayed_work(
                hotplug_wq, &hotplug_work, down_delay);
        } else if (cpu_freq <= top_freq) {
            hp_state = TEGRA_HP_IDLE;
        }
        break;
    default:
        pr_err("%s: invalid tegra hotplug state %d\n",
               __func__, hp_state);
        BUG();
    }
}
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);
        }
    }
}
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));
		}
	}
}
예제 #8
0
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);
		}
	}
}
예제 #9
0
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);
	}
}
예제 #10
0
static void tegra_auto_cpuplug_work_func(struct work_struct *work)
{
	bool up = false;
	unsigned int cpu = nr_cpu_ids;
	unsigned int min_cpus;

	mutex_lock(tegra3_cpu_lock);
	if (hp_state != TEGRA_HP_DISABLED) {
		switch (last_state) {
		case TEGRA_HP_UP:
			cpu = cpumask_next_zero(0, cpu_online_mask);
			if (cpu < nr_cpu_ids) {
				up = true;
				hp_stats_update(cpu, true);
			}
			break;
		case TEGRA_HP_DOWN:
			cpu = tegra_get_slowest_cpu_n();
			if (cpu < nr_cpu_ids) {
				min_cpus = pm_qos_request(PM_QOS_MIN_ONLINE_CPUS);
				if (min_cpus < num_online_cpus()) {
					up = false;
					hp_stats_update(cpu, false);
				} else {
					cpu = nr_cpu_ids;
				}
			} else if (!is_lp_cluster() && !no_lp) {

				/* For some reason this sometimes results in a null
				   pointer dereference. Set the clocks again if this
				   case occurs.
				   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)) {
					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
					pr_err(CPU_HOTPLUG_TAG" clk_set_parent fail\n");
			}
			break;
		}
	}
	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));
		}
	}

	mutex_lock(tegra3_cpu_lock);
	is_plugging = false;
	mutex_unlock(tegra3_cpu_lock);
}