Loading Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading drivers/devfreq/arm-memlat-mon.c +34 −12 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -63,6 +64,10 @@ struct cpu_grp_info { struct list_head mon_list; }; 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) \ Loading Loading @@ -96,6 +101,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; Loading Loading @@ -314,6 +322,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; Loading Loading @@ -348,6 +357,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) { Loading @@ -372,24 +397,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; } 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] }, {} }; Loading drivers/devfreq/governor_memlat.c +77 −16 Original line number Diff line number Diff line Loading @@ -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) \ Loading Loading @@ -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), Loading Loading @@ -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 Loading Loading @@ -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) Loading Loading @@ -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; Loading @@ -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) 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) 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) use_cnt++; memlat_use_cnt++; mutex_unlock(&state_lock); out: if (!ret) dev_info(dev, "Memory Latency governor registered.\n"); else Loading drivers/devfreq/governor_memlat.h +7 −1 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ 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, Loading @@ -81,6 +82,11 @@ static inline int register_memlat(struct device *dev, { return 0; } static inline int register_compute(struct device *dev, struct memlat_hwmon *hw) { return 0; } static inline int update_memlat(struct memlat_hwmon *hw) { return 0; Loading Loading
Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt +1 −1 Original line number Diff line number Diff line Loading @@ -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 Loading
drivers/devfreq/arm-memlat-mon.c +34 −12 Original line number Diff line number Diff line Loading @@ -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, Loading Loading @@ -63,6 +64,10 @@ struct cpu_grp_info { struct list_head mon_list; }; 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) \ Loading Loading @@ -96,6 +101,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; Loading Loading @@ -314,6 +322,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; Loading Loading @@ -348,6 +357,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) { Loading @@ -372,24 +397,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; } 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] }, {} }; Loading
drivers/devfreq/governor_memlat.c +77 −16 Original line number Diff line number Diff line Loading @@ -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) \ Loading Loading @@ -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), Loading Loading @@ -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 Loading Loading @@ -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) Loading Loading @@ -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; Loading @@ -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) 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) 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) use_cnt++; memlat_use_cnt++; mutex_unlock(&state_lock); out: if (!ret) dev_info(dev, "Memory Latency governor registered.\n"); else Loading
drivers/devfreq/governor_memlat.h +7 −1 Original line number Diff line number Diff line Loading @@ -74,6 +74,7 @@ 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, Loading @@ -81,6 +82,11 @@ static inline int register_memlat(struct device *dev, { return 0; } static inline int register_compute(struct device *dev, struct memlat_hwmon *hw) { return 0; } static inline int update_memlat(struct memlat_hwmon *hw) { return 0; Loading