summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRohit Gupta <rohgup@codeaurora.org>2016-04-13 16:55:04 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-08-17 16:37:23 -0700
commit3087c5f20db68ae27013593f332de06a9ac114aa (patch)
tree2aaf1d917ff2ba6ba40d06f93ff952d239764dfd
parent573979dee2a76e4d7f61cb867c12afbaed7e1eb5 (diff)
PM / devfreq: memlat: Add a core to memory frequency mapping table
Add a core to memory frequency mapping table, which establishes a relationship between the core frequency and its corresponding bandwidth vote. The governor expects a "qcom,core-dev-table" table as part of a given memlat hardware monitor's device tree node. This table is read upon registration of the memlat governor. The table is then used to determine the memory bandwidth vote corresponding to the maximum of the core frequencies. CRs-Fixed: 1054146 Change-Id: I9df118da1433125b02c937bf1799a0944b110fac Signed-off-by: Rohit Gupta <rohgup@codeaurora.org> Signed-off-by: David Keitel <dkeitel@codeaurora.org> Suggested-by: Saravana Kannan <skannan@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt6
-rw-r--r--drivers/devfreq/governor_memlat.c146
-rw-r--r--drivers/devfreq/governor_memlat.h8
3 files changed, 112 insertions, 48 deletions
diff --git a/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt b/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
index ecfab3617a75..01b2424359e1 100644
--- a/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
+++ b/Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt
@@ -7,10 +7,16 @@ Required properties:
- compatible: Must be "qcom,arm-memlat-mon"
- qcom,cpulist: List of CPU phandles to be monitored in a cluster
- qcom,target-dev: The DT device that corresponds to this master port
+- qcom,core-dev-table: A mapping table of core frequency to a required bandwidth vote at the
+ given core frequency.
Example:
qcom,arm-memlat-mon {
compatible = "qcom,arm-memlat-mon";
qcom,cpulist = <&CPU0 &CPU1>;
qcom,target-dev = <&memlat0>;
+ qcom,core-dev-table =
+ < 300000 1525>,
+ < 499200 3143>,
+ < 1881600 5859>;
};
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