summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/devfreq/governor_memlat.c146
-rw-r--r--drivers/devfreq/governor_memlat.h8
2 files changed, 106 insertions, 48 deletions
diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c
index 2851e9935fab..010f9defe33e 100644
--- a/drivers/devfreq/governor_memlat.c
+++ b/drivers/devfreq/governor_memlat.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -35,8 +35,6 @@
struct memlat_node {
unsigned int ratio_ceil;
- unsigned int freq_thresh_mhz;
- unsigned int mult_factor;
bool mon_started;
struct list_head list;
void *orig_data;
@@ -83,45 +81,25 @@ show_attr(__attr) \
store_attr(__attr, min, max) \
static DEVICE_ATTR(__attr, 0644, show_##__attr, store_##__attr)
-static unsigned long compute_dev_vote(struct devfreq *df)
+static unsigned long core_to_dev_freq(struct memlat_node *node,
+ unsigned long coref)
{
- int i, lat_dev;
- struct memlat_node *node = df->data;
struct memlat_hwmon *hw = node->hw;
- unsigned long max_freq = 0;
- unsigned int ratio;
-
- hw->get_cnt(hw);
+ struct core_dev_map *map = hw->freq_map;
+ unsigned long freq = 0;
- for (i = 0; i < hw->num_cores; i++) {
- ratio = hw->core_stats[i].inst_count;
-
- if (hw->core_stats[i].mem_count)
- ratio /= hw->core_stats[i].mem_count;
-
- trace_memlat_dev_meas(dev_name(df->dev.parent),
- hw->core_stats[i].id,
- hw->core_stats[i].inst_count,
- hw->core_stats[i].mem_count,
- hw->core_stats[i].freq, ratio);
-
- if (ratio && ratio <= node->ratio_ceil
- && hw->core_stats[i].freq >= node->freq_thresh_mhz
- && hw->core_stats[i].freq > max_freq) {
- lat_dev = i;
- max_freq = hw->core_stats[i].freq;
- }
- }
+ if (!map)
+ goto out;
- if (max_freq)
- trace_memlat_dev_update(dev_name(df->dev.parent),
- hw->core_stats[lat_dev].id,
- hw->core_stats[lat_dev].inst_count,
- hw->core_stats[lat_dev].mem_count,
- hw->core_stats[lat_dev].freq,
- max_freq * node->mult_factor);
+ while (map->core_mhz && map->core_mhz < coref)
+ map++;
+ if (!map->core_mhz)
+ map--;
+ freq = map->target_freq;
- return max_freq;
+out:
+ pr_debug("freq: %lu -> dev: %lu\n", coref, freq);
+ return freq;
}
static struct memlat_node *find_memlat_node(struct devfreq *df)
@@ -224,23 +202,51 @@ static int devfreq_memlat_get_freq(struct devfreq *df,
unsigned long *freq,
u32 *flag)
{
- unsigned long mhz;
+ int i, lat_dev;
struct memlat_node *node = df->data;
+ struct memlat_hwmon *hw = node->hw;
+ unsigned long max_freq = 0;
+ unsigned int ratio;
+
+ hw->get_cnt(hw);
+
+ for (i = 0; i < hw->num_cores; i++) {
+ ratio = hw->core_stats[i].inst_count;
- mhz = compute_dev_vote(df);
- *freq = mhz ? (mhz * node->mult_factor) : 0;
+ if (hw->core_stats[i].mem_count)
+ ratio /= hw->core_stats[i].mem_count;
+
+ trace_memlat_dev_meas(dev_name(df->dev.parent),
+ hw->core_stats[i].id,
+ hw->core_stats[i].inst_count,
+ hw->core_stats[i].mem_count,
+ hw->core_stats[i].freq, ratio);
+
+ if (ratio && ratio <= node->ratio_ceil
+ && hw->core_stats[i].freq > max_freq) {
+ lat_dev = i;
+ max_freq = hw->core_stats[i].freq;
+ }
+ }
+
+ if (max_freq) {
+ max_freq = core_to_dev_freq(node, max_freq);
+ trace_memlat_dev_update(dev_name(df->dev.parent),
+ hw->core_stats[lat_dev].id,
+ hw->core_stats[lat_dev].inst_count,
+ hw->core_stats[lat_dev].mem_count,
+ hw->core_stats[lat_dev].freq,
+ max_freq);
+ }
+ *freq = max_freq;
return 0;
}
-gov_attr(ratio_ceil, 1U, 1000U);
-gov_attr(freq_thresh_mhz, 300U, 5000U);
-gov_attr(mult_factor, 1U, 10U);
+gov_attr(ratio_ceil, 1U, 10000U);
static struct attribute *dev_attr[] = {
&dev_attr_ratio_ceil.attr,
- &dev_attr_freq_thresh_mhz.attr,
- &dev_attr_mult_factor.attr,
NULL,
};
@@ -295,6 +301,48 @@ static struct devfreq_governor devfreq_gov_memlat = {
.event_handler = devfreq_memlat_ev_handler,
};
+#define NUM_COLS 2
+static struct core_dev_map *init_core_dev_map(struct device *dev,
+ char *prop_name)
+{
+ int len, nf, i, j;
+ u32 data;
+ struct core_dev_map *tbl;
+ int ret;
+
+ if (!of_find_property(dev->of_node, prop_name, &len))
+ return NULL;
+ len /= sizeof(data);
+
+ if (len % NUM_COLS || len == 0)
+ return NULL;
+ nf = len / NUM_COLS;
+
+ tbl = devm_kzalloc(dev, (nf + 1) * sizeof(struct core_dev_map),
+ GFP_KERNEL);
+ if (!tbl)
+ return NULL;
+
+ for (i = 0, j = 0; i < nf; i++, j += 2) {
+ ret = of_property_read_u32_index(dev->of_node, prop_name, j,
+ &data);
+ if (ret)
+ return NULL;
+ tbl[i].core_mhz = data / 1000;
+
+ ret = of_property_read_u32_index(dev->of_node, prop_name, j + 1,
+ &data);
+ if (ret)
+ return NULL;
+ tbl[i].target_freq = data;
+ pr_debug("Entry%d CPU:%u, Dev:%u\n", i, tbl[i].core_mhz,
+ tbl[i].target_freq);
+ }
+ tbl[i].core_mhz = 0;
+
+ return tbl;
+}
+
int register_memlat(struct device *dev, struct memlat_hwmon *hw)
{
int ret = 0;
@@ -311,10 +359,14 @@ int register_memlat(struct device *dev, struct memlat_hwmon *hw)
node->attr_grp = &dev_attr_group;
node->ratio_ceil = 10;
- node->freq_thresh_mhz = 900;
- node->mult_factor = 8;
node->hw = hw;
+ hw->freq_map = init_core_dev_map(dev, "qcom,core-dev-table");
+ if (!hw->freq_map) {
+ dev_err(dev, "Couldn't find the core-dev freq table!\n");
+ return -EINVAL;
+ }
+
mutex_lock(&list_lock);
list_add_tail(&node->list, &memlat_list);
mutex_unlock(&list_lock);
diff --git a/drivers/devfreq/governor_memlat.h b/drivers/devfreq/governor_memlat.h
index 19a35009a4a0..a0e52a0997ad 100644
--- a/drivers/devfreq/governor_memlat.h
+++ b/drivers/devfreq/governor_memlat.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -31,6 +31,11 @@ struct dev_stats {
unsigned long freq;
};
+struct core_dev_map {
+ unsigned int core_mhz;
+ unsigned int target_freq;
+};
+
/**
* struct memlat_hwmon - Memory Latency HW monitor info
* @start_hwmon: Start the HW monitoring
@@ -63,6 +68,7 @@ struct memlat_hwmon {
struct dev_stats *core_stats;
struct devfreq *df;
+ struct core_dev_map *freq_map;
};
#ifdef CONFIG_DEVFREQ_GOV_MEMLAT