mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
PM / devfreq: memlat: Add support for compute-bound logic
Currently, an entirely separate governor is used to handle compute-bound cases. Roll this functionality into the existing memlat governor and allow devices to choose which logic to target by specifying different drivers in the 'compatible' field. Change-Id: I8dc41bf0474309c3564dec8e6c813511b8a7fc02 Signed-off-by: Jonathan Avila <avilaj@codeaurora.org>
This commit is contained in:
parent
a85abb445c
commit
aaa9357227
@ -4,7 +4,7 @@ arm-memlat-mon is a device that represents the use of the PMU in ARM cores
|
||||
to measure the parameters for latency driven memory access patterns.
|
||||
|
||||
Required properties:
|
||||
- compatible: Must be "qcom,arm-memlat-mon"
|
||||
- compatible: Must be "qcom,arm-memlat-mon" or "qcom,arm-cpu-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
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "governor.h"
|
||||
#include "governor_memlat.h"
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
enum ev_index {
|
||||
INST_IDX,
|
||||
@ -60,6 +61,10 @@ struct cpu_grp_info {
|
||||
struct memlat_hwmon hw;
|
||||
};
|
||||
|
||||
struct memlat_mon_spec {
|
||||
bool is_compute;
|
||||
};
|
||||
|
||||
#define to_cpustats(cpu_grp, cpu) \
|
||||
(&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)])
|
||||
#define to_devstats(cpu_grp, cpu) \
|
||||
@ -91,6 +96,9 @@ static inline unsigned long read_event(struct event_data *event)
|
||||
unsigned long ev_count;
|
||||
u64 total, enabled, running;
|
||||
|
||||
if (!event->pevent)
|
||||
return 0;
|
||||
|
||||
total = perf_event_read_value(event->pevent, &enabled, &running);
|
||||
ev_count = total - event->prev_count;
|
||||
event->prev_count = total;
|
||||
@ -257,6 +265,7 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev)
|
||||
struct device *dev = &pdev->dev;
|
||||
struct memlat_hwmon *hw;
|
||||
struct cpu_grp_info *cpu_grp;
|
||||
const struct memlat_mon_spec *spec;
|
||||
int cpu, ret;
|
||||
u32 event_id;
|
||||
|
||||
@ -290,6 +299,22 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev)
|
||||
|
||||
cpu_grp->event_ids[CYC_IDX] = CYC_EV;
|
||||
|
||||
for_each_cpu(cpu, &cpu_grp->cpus)
|
||||
to_devstats(cpu_grp, cpu)->id = cpu;
|
||||
|
||||
hw->start_hwmon = &start_hwmon;
|
||||
hw->stop_hwmon = &stop_hwmon;
|
||||
hw->get_cnt = &get_cnt;
|
||||
|
||||
spec = of_device_get_match_data(dev);
|
||||
if (spec && spec->is_compute) {
|
||||
ret = register_compute(dev, hw);
|
||||
if (ret)
|
||||
pr_err("Compute Gov registration failed\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev",
|
||||
&event_id);
|
||||
if (ret) {
|
||||
@ -314,24 +339,21 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev)
|
||||
else
|
||||
cpu_grp->event_ids[STALL_CYC_IDX] = event_id;
|
||||
|
||||
for_each_cpu(cpu, &cpu_grp->cpus)
|
||||
to_devstats(cpu_grp, cpu)->id = cpu;
|
||||
|
||||
hw->start_hwmon = &start_hwmon;
|
||||
hw->stop_hwmon = &stop_hwmon;
|
||||
hw->get_cnt = &get_cnt;
|
||||
|
||||
ret = register_memlat(dev, hw);
|
||||
if (ret) {
|
||||
if (ret)
|
||||
pr_err("Mem Latency Gov registration failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct memlat_mon_spec spec[] = {
|
||||
[0] = { false },
|
||||
[1] = { true },
|
||||
};
|
||||
|
||||
static const struct of_device_id memlat_match_table[] = {
|
||||
{ .compatible = "qcom,arm-memlat-mon" },
|
||||
{ .compatible = "qcom,arm-memlat-mon", .data = &spec[0] },
|
||||
{ .compatible = "qcom,arm-cpu-mon", .data = &spec[1] },
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -48,7 +48,8 @@ struct memlat_node {
|
||||
static LIST_HEAD(memlat_list);
|
||||
static DEFINE_MUTEX(list_lock);
|
||||
|
||||
static int use_cnt;
|
||||
static int memlat_use_cnt;
|
||||
static int compute_use_cnt;
|
||||
static DEFINE_MUTEX(state_lock);
|
||||
|
||||
#define show_attr(name) \
|
||||
@ -240,8 +241,7 @@ static int devfreq_memlat_get_freq(struct devfreq *df,
|
||||
if (hw->core_stats[i].mem_count)
|
||||
ratio /= hw->core_stats[i].mem_count;
|
||||
|
||||
if (!hw->core_stats[i].inst_count
|
||||
|| !hw->core_stats[i].freq)
|
||||
if (!hw->core_stats[i].freq)
|
||||
continue;
|
||||
|
||||
trace_memlat_dev_meas(dev_name(df->dev.parent),
|
||||
@ -280,16 +280,26 @@ static int devfreq_memlat_get_freq(struct devfreq *df,
|
||||
gov_attr(ratio_ceil, 1U, 10000U);
|
||||
gov_attr(stall_floor, 0U, 100U);
|
||||
|
||||
static struct attribute *dev_attr[] = {
|
||||
static struct attribute *memlat_dev_attr[] = {
|
||||
&dev_attr_ratio_ceil.attr,
|
||||
&dev_attr_stall_floor.attr,
|
||||
&dev_attr_freq_map.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group dev_attr_group = {
|
||||
static struct attribute *compute_dev_attr[] = {
|
||||
&dev_attr_freq_map.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group memlat_dev_attr_group = {
|
||||
.name = "mem_latency",
|
||||
.attrs = dev_attr,
|
||||
.attrs = memlat_dev_attr,
|
||||
};
|
||||
|
||||
static struct attribute_group compute_dev_attr_group = {
|
||||
.name = "compute",
|
||||
.attrs = compute_dev_attr,
|
||||
};
|
||||
|
||||
#define MIN_MS 10U
|
||||
@ -338,6 +348,12 @@ static struct devfreq_governor devfreq_gov_memlat = {
|
||||
.event_handler = devfreq_memlat_ev_handler,
|
||||
};
|
||||
|
||||
static struct devfreq_governor devfreq_gov_compute = {
|
||||
.name = "compute",
|
||||
.get_target_freq = devfreq_memlat_get_freq,
|
||||
.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)
|
||||
@ -380,20 +396,17 @@ static struct core_dev_map *init_core_dev_map(struct device *dev,
|
||||
return tbl;
|
||||
}
|
||||
|
||||
int register_memlat(struct device *dev, struct memlat_hwmon *hw)
|
||||
static struct memlat_node *register_common(struct device *dev,
|
||||
struct memlat_hwmon *hw)
|
||||
{
|
||||
int ret = 0;
|
||||
struct memlat_node *node;
|
||||
|
||||
if (!hw->dev && !hw->of_node)
|
||||
return -EINVAL;
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL);
|
||||
if (!node)
|
||||
return -ENOMEM;
|
||||
|
||||
node->gov = &devfreq_gov_memlat;
|
||||
node->attr_grp = &dev_attr_group;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
node->ratio_ceil = 10;
|
||||
node->hw = hw;
|
||||
@ -401,20 +414,68 @@ int register_memlat(struct device *dev, struct memlat_hwmon *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;
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
mutex_lock(&list_lock);
|
||||
list_add_tail(&node->list, &memlat_list);
|
||||
mutex_unlock(&list_lock);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
int register_compute(struct device *dev, struct memlat_hwmon *hw)
|
||||
{
|
||||
struct memlat_node *node;
|
||||
int ret = 0;
|
||||
|
||||
node = register_common(dev, hw);
|
||||
if (IS_ERR(node)) {
|
||||
ret = PTR_ERR(node);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&state_lock);
|
||||
if (!use_cnt)
|
||||
ret = devfreq_add_governor(&devfreq_gov_memlat);
|
||||
node->gov = &devfreq_gov_compute;
|
||||
node->attr_grp = &compute_dev_attr_group;
|
||||
|
||||
if (!compute_use_cnt)
|
||||
ret = devfreq_add_governor(&devfreq_gov_compute);
|
||||
if (!ret)
|
||||
use_cnt++;
|
||||
compute_use_cnt++;
|
||||
mutex_unlock(&state_lock);
|
||||
|
||||
out:
|
||||
if (!ret)
|
||||
dev_info(dev, "Compute governor registered.\n");
|
||||
else
|
||||
dev_err(dev, "Compute governor registration failed!\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int register_memlat(struct device *dev, struct memlat_hwmon *hw)
|
||||
{
|
||||
struct memlat_node *node;
|
||||
int ret = 0;
|
||||
|
||||
node = register_common(dev, hw);
|
||||
if (IS_ERR(node)) {
|
||||
ret = PTR_ERR(node);
|
||||
goto out;
|
||||
}
|
||||
|
||||
mutex_lock(&state_lock);
|
||||
node->gov = &devfreq_gov_memlat;
|
||||
node->attr_grp = &memlat_dev_attr_group;
|
||||
|
||||
if (!memlat_use_cnt)
|
||||
ret = devfreq_add_governor(&devfreq_gov_memlat);
|
||||
if (!ret)
|
||||
memlat_use_cnt++;
|
||||
mutex_unlock(&state_lock);
|
||||
|
||||
out:
|
||||
if (!ret)
|
||||
dev_info(dev, "Memory Latency governor registered.\n");
|
||||
else
|
||||
|
@ -74,10 +74,16 @@ struct memlat_hwmon {
|
||||
|
||||
#ifdef CONFIG_DEVFREQ_GOV_MEMLAT
|
||||
int register_memlat(struct device *dev, struct memlat_hwmon *hw);
|
||||
int register_compute(struct device *dev, struct memlat_hwmon *hw);
|
||||
int update_memlat(struct memlat_hwmon *hw);
|
||||
#else
|
||||
static inline int register_memlat(struct device *dev,
|
||||
struct memlat_hwmon *hw)
|
||||
struct memlat_hwmon *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int register_compute(struct device *dev,
|
||||
struct memlat_hwmon *hw)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user