#include <linux/debugfs.h>
#include <linux/cpu.h>
#include <linux/regulator/consumer.h>
+#include <linux/pm_qos.h>
#include <mach/edp.h>
static int edp_thermal_index;
static cpumask_t edp_cpumask;
static unsigned int edp_limit;
+static struct pm_qos_request edp_max_cpus;
unsigned int tegra_get_edp_limit(int *get_edp_thermal_index)
{
return limit;
}
-/* Must be called while holding cpu_tegra_lock */
-static void edp_update_limit(void)
+static unsigned int get_edp_freq_limit(unsigned int nr_cpus)
{
- unsigned int limit = edp_predict_limit(cpumask_weight(&edp_cpumask));
- BUG_ON(!mutex_is_locked(&tegra_cpu_lock));
-#ifdef CONFIG_TEGRA_EDP_EXACT_FREQ
- edp_limit = limit;
-#else
+ unsigned int limit = edp_predict_limit(nr_cpus);
+#ifndef CONFIG_TEGRA_EDP_EXACT_FREQ
unsigned int i;
for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
if (freq_table[i].frequency > limit) {
}
}
BUG_ON(i == 0); /* min freq above the limit or table empty */
- edp_limit = freq_table[i-1].frequency;
+ limit = freq_table[i-1].frequency;
#endif
+ return limit;
+}
+
+/*
+ * Returns the ideal nr of cpus to have online for maximum performance given
+ * edp constraints at the current temperature
+ */
+static int get_edp_max_cpus(void)
+{
+ unsigned int i, limit;
+ unsigned int max_mips = 0;
+ int max_nr_cpus = PM_QOS_DEFAULT_VALUE;
+
+ for (i = 1; i <= num_possible_cpus(); i++) {
+ limit = get_edp_freq_limit(i);
+ if (limit * i >= max_mips) {
+ max_mips = limit * i;
+ max_nr_cpus = i;
+ }
+ }
+ return max_nr_cpus;
+}
+
+/*
+ * Shouldn't be called with tegra_cpu_lock held. Will result in a deadlock
+ * otherwise
+ */
+static void edp_update_max_cpus(void)
+{
+ unsigned int max_cpus = get_edp_max_cpus();
+
+ if (!pm_qos_request_active(&edp_max_cpus))
+ pm_qos_add_request(&edp_max_cpus, PM_QOS_MAX_ONLINE_CPUS,
+ max_cpus);
+ else
+ pm_qos_update_request(&edp_max_cpus, max_cpus);
+}
+
+/* Must be called while holding cpu_tegra_lock */
+static void edp_update_limit(void)
+{
+ BUG_ON(!mutex_is_locked(&tegra_cpu_lock));
+ edp_limit = get_edp_freq_limit(cpumask_weight(&edp_cpumask));
}
static unsigned int edp_governor_speed(unsigned int requested_speed)
tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false, 0);
mutex_unlock(&tegra_cpu_lock);
+ edp_update_max_cpus();
+
return 0;
}
return ret;
}
-bool tegra_cpu_edp_favor_up(unsigned int n, int mp_overhead)
-{
- unsigned int current_limit, next_limit;
-
- if (n == 0)
- return true;
-
- if (n >= ARRAY_SIZE(cpu_edp_limits->freq_limits))
- return false;
-
- current_limit = edp_predict_limit(n);
- next_limit = edp_predict_limit(n + 1);
-
- return ((next_limit * (n + 1)) >=
- (current_limit * n * (100 + mp_overhead) / 100));
-}
-
-bool tegra_cpu_edp_favor_down(unsigned int n, int mp_overhead)
-{
- unsigned int current_limit, next_limit;
-
- if (n <= 1)
- return false;
-
- if (n > ARRAY_SIZE(cpu_edp_limits->freq_limits))
- return true;
-
- current_limit = edp_predict_limit(n);
- next_limit = edp_predict_limit(n - 1);
-
- return ((next_limit * (n - 1) * (100 + mp_overhead) / 100)) >
- (current_limit * n);
-}
-
static int tegra_cpu_edp_notify(
struct notifier_block *nb, unsigned long event, void *hcpu)
{
static unsigned long up_delay;
static unsigned long down_delay;
static unsigned long hotplug_timeout;
-static int mp_overhead = 10;
static unsigned int idle_top_freq;
static unsigned int idle_bottom_freq;
static int update_core_config(unsigned int cpunumber, bool up)
{
int ret = 0;
- unsigned int nr_cpus = num_online_cpus();
mutex_lock(tegra_cpu_lock);
cpumask_clear_cpu(cpunumber, &cr_offline_requests);
if (is_lp_cluster())
ret = -EBUSY;
- else if (tegra_cpu_edp_favor_up(nr_cpus, mp_overhead))
+ else
queue_work(cpuquiet_wq, &cpuquiet_work);
} else {
if (is_lp_cluster()) {
CPQ_BASIC_ATTRIBUTE(idle_top_freq, 0644, uint);
CPQ_BASIC_ATTRIBUTE(idle_bottom_freq, 0644, uint);
-CPQ_BASIC_ATTRIBUTE(mp_overhead, 0644, int);
CPQ_ATTRIBUTE_CUSTOM(no_lp, 0644, show_int_attribute, store_no_lp);
CPQ_ATTRIBUTE(up_delay, 0644, ulong, delay_callback);
CPQ_ATTRIBUTE(down_delay, 0644, ulong, delay_callback);
&down_delay_attr.attr,
&idle_top_freq_attr.attr,
&idle_bottom_freq_attr.attr,
- &mp_overhead_attr.attr,
&enable_attr.attr,
&hotplug_timeout_attr.attr,
NULL,