Loading Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt +1 −1 Original line number Original line 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. to measure the parameters for latency driven memory access patterns. Required properties: 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,cpulist: List of CPU phandles to be monitored in a cluster - qcom,target-dev: The DT device that corresponds to this master port - 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 - 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 Original line Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "governor.h" #include "governor.h" #include "governor_memlat.h" #include "governor_memlat.h" #include <linux/perf_event.h> #include <linux/perf_event.h> #include <linux/of_device.h> enum ev_index { enum ev_index { INST_IDX, INST_IDX, Loading Loading @@ -52,6 +53,10 @@ struct cpu_grp_info { struct memlat_hwmon hw; struct memlat_hwmon hw; }; }; struct memlat_mon_spec { bool is_compute; }; #define to_cpustats(cpu_grp, cpu) \ #define to_cpustats(cpu_grp, cpu) \ (&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)]) (&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)]) #define to_devstats(cpu_grp, cpu) \ #define to_devstats(cpu_grp, cpu) \ Loading Loading @@ -83,6 +88,9 @@ static inline unsigned long read_event(struct event_data *event) unsigned long ev_count; unsigned long ev_count; u64 total, enabled, running; u64 total, enabled, running; if (!event->pevent) return 0; total = perf_event_read_value(event->pevent, &enabled, &running); total = perf_event_read_value(event->pevent, &enabled, &running); ev_count = total - event->prev_count; ev_count = total - event->prev_count; event->prev_count = total; event->prev_count = total; Loading Loading @@ -249,6 +257,7 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device *dev = &pdev->dev; struct memlat_hwmon *hw; struct memlat_hwmon *hw; struct cpu_grp_info *cpu_grp; struct cpu_grp_info *cpu_grp; const struct memlat_mon_spec *spec; int cpu, ret; int cpu, ret; u32 event_id; u32 event_id; Loading Loading @@ -282,6 +291,22 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) cpu_grp->event_ids[CYC_IDX] = CYC_EV; 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", ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev", &event_id); &event_id); if (ret) { if (ret) { Loading @@ -306,24 +331,21 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) else else cpu_grp->event_ids[STALL_CYC_IDX] = event_id; 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); ret = register_memlat(dev, hw); if (ret) { if (ret) pr_err("Mem Latency Gov registration failed\n"); pr_err("Mem Latency Gov registration failed\n"); return ret; return ret; } } return 0; static const struct memlat_mon_spec spec[] = { } [0] = { false }, [1] = { true }, }; static const struct of_device_id memlat_match_table[] = { 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/bimc-bwmon.c +17 −1 Original line number Original line Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only /* /* * Copyright (c) 2014-2017, 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2018, 2019, The Linux Foundation. All rights reserved. */ */ #define pr_fmt(fmt) "bimc-bwmon: " fmt #define pr_fmt(fmt) "bimc-bwmon: " fmt Loading Loading @@ -168,6 +168,14 @@ void mon_clear(struct bwmon *m, bool clear_all, enum mon_reg_type type) writel_relaxed(MON_CLEAR_ALL_BIT, MON3_CLEAR(m)); writel_relaxed(MON_CLEAR_ALL_BIT, MON3_CLEAR(m)); else else writel_relaxed(MON_CLEAR_BIT, MON3_CLEAR(m)); writel_relaxed(MON_CLEAR_BIT, MON3_CLEAR(m)); /* * In some hardware versions since MON3_CLEAR(m) register does * not have self-clearing capability it needs to be cleared * explicitly. But we also need to ensure the writes to it * are successful before clearing it. */ wmb(); writel_relaxed(0, MON3_CLEAR(m)); break; break; } } /* /* Loading Loading @@ -357,6 +365,14 @@ void mon_irq_clear(struct bwmon *m, enum mon_reg_type type) break; break; case MON3: case MON3: writel_relaxed(MON3_INT_STATUS_MASK, MON3_INT_CLR(m)); writel_relaxed(MON3_INT_STATUS_MASK, MON3_INT_CLR(m)); /* * In some hardware versions since MON3_INT_CLEAR(m) register * does not have self-clearing capability it needs to be * cleared explicitly. But we also need to ensure the writes * to it are successful before clearing it. */ wmb(); writel_relaxed(0, MON3_INT_CLR(m)); break; break; } } } } Loading drivers/devfreq/devfreq.c +1 −3 Original line number Original line Diff line number Diff line Loading @@ -560,7 +560,6 @@ struct devfreq *devfreq_add_device(struct device *dev, { { struct devfreq *devfreq; struct devfreq *devfreq; struct devfreq_governor *governor; struct devfreq_governor *governor; static atomic_t devfreq_no = ATOMIC_INIT(-1); int err = 0; int err = 0; if (!dev || !profile || !governor_name) { if (!dev || !profile || !governor_name) { Loading Loading @@ -620,8 +619,7 @@ struct devfreq *devfreq_add_device(struct device *dev, } } devfreq->max_freq = devfreq->scaling_max_freq; devfreq->max_freq = devfreq->scaling_max_freq; dev_set_name(&devfreq->dev, "devfreq%d", dev_set_name(&devfreq->dev, "%s", dev_name(dev)); atomic_inc_return(&devfreq_no)); err = device_register(&devfreq->dev); err = device_register(&devfreq->dev); if (err) { if (err) { mutex_unlock(&devfreq->lock); mutex_unlock(&devfreq->lock); Loading drivers/devfreq/governor_memlat.c +77 −16 Original line number Original line Diff line number Diff line Loading @@ -40,7 +40,8 @@ struct memlat_node { static LIST_HEAD(memlat_list); static LIST_HEAD(memlat_list); static DEFINE_MUTEX(list_lock); static DEFINE_MUTEX(list_lock); static int use_cnt; static int memlat_use_cnt; static int compute_use_cnt; static DEFINE_MUTEX(state_lock); static DEFINE_MUTEX(state_lock); #define show_attr(name) \ #define show_attr(name) \ Loading Loading @@ -232,8 +233,7 @@ static int devfreq_memlat_get_freq(struct devfreq *df, if (hw->core_stats[i].mem_count) if (hw->core_stats[i].mem_count) ratio /= hw->core_stats[i].mem_count; ratio /= hw->core_stats[i].mem_count; if (!hw->core_stats[i].inst_count if (!hw->core_stats[i].freq) || !hw->core_stats[i].freq) continue; continue; trace_memlat_dev_meas(dev_name(df->dev.parent), trace_memlat_dev_meas(dev_name(df->dev.parent), Loading Loading @@ -272,16 +272,26 @@ static int devfreq_memlat_get_freq(struct devfreq *df, gov_attr(ratio_ceil, 1U, 10000U); gov_attr(ratio_ceil, 1U, 10000U); gov_attr(stall_floor, 0U, 100U); gov_attr(stall_floor, 0U, 100U); static struct attribute *dev_attr[] = { static struct attribute *memlat_dev_attr[] = { &dev_attr_ratio_ceil.attr, &dev_attr_ratio_ceil.attr, &dev_attr_stall_floor.attr, &dev_attr_stall_floor.attr, &dev_attr_freq_map.attr, &dev_attr_freq_map.attr, NULL, 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", .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 #define MIN_MS 10U Loading Loading @@ -330,6 +340,12 @@ static struct devfreq_governor devfreq_gov_memlat = { .event_handler = devfreq_memlat_ev_handler, .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 #define NUM_COLS 2 static struct core_dev_map *init_core_dev_map(struct device *dev, static struct core_dev_map *init_core_dev_map(struct device *dev, char *prop_name) char *prop_name) Loading Loading @@ -372,20 +388,17 @@ static struct core_dev_map *init_core_dev_map(struct device *dev, return tbl; 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; struct memlat_node *node; if (!hw->dev && !hw->of_node) if (!hw->dev && !hw->of_node) return -EINVAL; return ERR_PTR(-EINVAL); node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL); node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL); if (!node) if (!node) return -ENOMEM; return ERR_PTR(-ENOMEM); node->gov = &devfreq_gov_memlat; node->attr_grp = &dev_attr_group; node->ratio_ceil = 10; node->ratio_ceil = 10; node->hw = hw; node->hw = hw; Loading @@ -393,20 +406,68 @@ int register_memlat(struct device *dev, struct memlat_hwmon *hw) hw->freq_map = init_core_dev_map(dev, "qcom,core-dev-table"); hw->freq_map = init_core_dev_map(dev, "qcom,core-dev-table"); if (!hw->freq_map) { if (!hw->freq_map) { dev_err(dev, "Couldn't find the core-dev freq table!\n"); dev_err(dev, "Couldn't find the core-dev freq table!\n"); return -EINVAL; return ERR_PTR(-EINVAL); } } mutex_lock(&list_lock); mutex_lock(&list_lock); list_add_tail(&node->list, &memlat_list); list_add_tail(&node->list, &memlat_list); mutex_unlock(&list_lock); 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); 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); ret = devfreq_add_governor(&devfreq_gov_memlat); if (!ret) if (!ret) use_cnt++; memlat_use_cnt++; mutex_unlock(&state_lock); mutex_unlock(&state_lock); out: if (!ret) if (!ret) dev_info(dev, "Memory Latency governor registered.\n"); dev_info(dev, "Memory Latency governor registered.\n"); else else Loading Loading
Documentation/devicetree/bindings/devfreq/arm-memlat-mon.txt +1 −1 Original line number Original line 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. to measure the parameters for latency driven memory access patterns. Required properties: 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,cpulist: List of CPU phandles to be monitored in a cluster - qcom,target-dev: The DT device that corresponds to this master port - 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 - 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 Original line Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include "governor.h" #include "governor.h" #include "governor_memlat.h" #include "governor_memlat.h" #include <linux/perf_event.h> #include <linux/perf_event.h> #include <linux/of_device.h> enum ev_index { enum ev_index { INST_IDX, INST_IDX, Loading Loading @@ -52,6 +53,10 @@ struct cpu_grp_info { struct memlat_hwmon hw; struct memlat_hwmon hw; }; }; struct memlat_mon_spec { bool is_compute; }; #define to_cpustats(cpu_grp, cpu) \ #define to_cpustats(cpu_grp, cpu) \ (&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)]) (&cpu_grp->cpustats[cpu - cpumask_first(&cpu_grp->cpus)]) #define to_devstats(cpu_grp, cpu) \ #define to_devstats(cpu_grp, cpu) \ Loading Loading @@ -83,6 +88,9 @@ static inline unsigned long read_event(struct event_data *event) unsigned long ev_count; unsigned long ev_count; u64 total, enabled, running; u64 total, enabled, running; if (!event->pevent) return 0; total = perf_event_read_value(event->pevent, &enabled, &running); total = perf_event_read_value(event->pevent, &enabled, &running); ev_count = total - event->prev_count; ev_count = total - event->prev_count; event->prev_count = total; event->prev_count = total; Loading Loading @@ -249,6 +257,7 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct device *dev = &pdev->dev; struct memlat_hwmon *hw; struct memlat_hwmon *hw; struct cpu_grp_info *cpu_grp; struct cpu_grp_info *cpu_grp; const struct memlat_mon_spec *spec; int cpu, ret; int cpu, ret; u32 event_id; u32 event_id; Loading Loading @@ -282,6 +291,22 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) cpu_grp->event_ids[CYC_IDX] = CYC_EV; 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", ret = of_property_read_u32(dev->of_node, "qcom,cachemiss-ev", &event_id); &event_id); if (ret) { if (ret) { Loading @@ -306,24 +331,21 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) else else cpu_grp->event_ids[STALL_CYC_IDX] = event_id; 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); ret = register_memlat(dev, hw); if (ret) { if (ret) pr_err("Mem Latency Gov registration failed\n"); pr_err("Mem Latency Gov registration failed\n"); return ret; return ret; } } return 0; static const struct memlat_mon_spec spec[] = { } [0] = { false }, [1] = { true }, }; static const struct of_device_id memlat_match_table[] = { 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/bimc-bwmon.c +17 −1 Original line number Original line Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only /* /* * Copyright (c) 2014-2017, 2019, The Linux Foundation. All rights reserved. * Copyright (c) 2014-2018, 2019, The Linux Foundation. All rights reserved. */ */ #define pr_fmt(fmt) "bimc-bwmon: " fmt #define pr_fmt(fmt) "bimc-bwmon: " fmt Loading Loading @@ -168,6 +168,14 @@ void mon_clear(struct bwmon *m, bool clear_all, enum mon_reg_type type) writel_relaxed(MON_CLEAR_ALL_BIT, MON3_CLEAR(m)); writel_relaxed(MON_CLEAR_ALL_BIT, MON3_CLEAR(m)); else else writel_relaxed(MON_CLEAR_BIT, MON3_CLEAR(m)); writel_relaxed(MON_CLEAR_BIT, MON3_CLEAR(m)); /* * In some hardware versions since MON3_CLEAR(m) register does * not have self-clearing capability it needs to be cleared * explicitly. But we also need to ensure the writes to it * are successful before clearing it. */ wmb(); writel_relaxed(0, MON3_CLEAR(m)); break; break; } } /* /* Loading Loading @@ -357,6 +365,14 @@ void mon_irq_clear(struct bwmon *m, enum mon_reg_type type) break; break; case MON3: case MON3: writel_relaxed(MON3_INT_STATUS_MASK, MON3_INT_CLR(m)); writel_relaxed(MON3_INT_STATUS_MASK, MON3_INT_CLR(m)); /* * In some hardware versions since MON3_INT_CLEAR(m) register * does not have self-clearing capability it needs to be * cleared explicitly. But we also need to ensure the writes * to it are successful before clearing it. */ wmb(); writel_relaxed(0, MON3_INT_CLR(m)); break; break; } } } } Loading
drivers/devfreq/devfreq.c +1 −3 Original line number Original line Diff line number Diff line Loading @@ -560,7 +560,6 @@ struct devfreq *devfreq_add_device(struct device *dev, { { struct devfreq *devfreq; struct devfreq *devfreq; struct devfreq_governor *governor; struct devfreq_governor *governor; static atomic_t devfreq_no = ATOMIC_INIT(-1); int err = 0; int err = 0; if (!dev || !profile || !governor_name) { if (!dev || !profile || !governor_name) { Loading Loading @@ -620,8 +619,7 @@ struct devfreq *devfreq_add_device(struct device *dev, } } devfreq->max_freq = devfreq->scaling_max_freq; devfreq->max_freq = devfreq->scaling_max_freq; dev_set_name(&devfreq->dev, "devfreq%d", dev_set_name(&devfreq->dev, "%s", dev_name(dev)); atomic_inc_return(&devfreq_no)); err = device_register(&devfreq->dev); err = device_register(&devfreq->dev); if (err) { if (err) { mutex_unlock(&devfreq->lock); mutex_unlock(&devfreq->lock); Loading
drivers/devfreq/governor_memlat.c +77 −16 Original line number Original line Diff line number Diff line Loading @@ -40,7 +40,8 @@ struct memlat_node { static LIST_HEAD(memlat_list); static LIST_HEAD(memlat_list); static DEFINE_MUTEX(list_lock); static DEFINE_MUTEX(list_lock); static int use_cnt; static int memlat_use_cnt; static int compute_use_cnt; static DEFINE_MUTEX(state_lock); static DEFINE_MUTEX(state_lock); #define show_attr(name) \ #define show_attr(name) \ Loading Loading @@ -232,8 +233,7 @@ static int devfreq_memlat_get_freq(struct devfreq *df, if (hw->core_stats[i].mem_count) if (hw->core_stats[i].mem_count) ratio /= hw->core_stats[i].mem_count; ratio /= hw->core_stats[i].mem_count; if (!hw->core_stats[i].inst_count if (!hw->core_stats[i].freq) || !hw->core_stats[i].freq) continue; continue; trace_memlat_dev_meas(dev_name(df->dev.parent), trace_memlat_dev_meas(dev_name(df->dev.parent), Loading Loading @@ -272,16 +272,26 @@ static int devfreq_memlat_get_freq(struct devfreq *df, gov_attr(ratio_ceil, 1U, 10000U); gov_attr(ratio_ceil, 1U, 10000U); gov_attr(stall_floor, 0U, 100U); gov_attr(stall_floor, 0U, 100U); static struct attribute *dev_attr[] = { static struct attribute *memlat_dev_attr[] = { &dev_attr_ratio_ceil.attr, &dev_attr_ratio_ceil.attr, &dev_attr_stall_floor.attr, &dev_attr_stall_floor.attr, &dev_attr_freq_map.attr, &dev_attr_freq_map.attr, NULL, 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", .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 #define MIN_MS 10U Loading Loading @@ -330,6 +340,12 @@ static struct devfreq_governor devfreq_gov_memlat = { .event_handler = devfreq_memlat_ev_handler, .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 #define NUM_COLS 2 static struct core_dev_map *init_core_dev_map(struct device *dev, static struct core_dev_map *init_core_dev_map(struct device *dev, char *prop_name) char *prop_name) Loading Loading @@ -372,20 +388,17 @@ static struct core_dev_map *init_core_dev_map(struct device *dev, return tbl; 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; struct memlat_node *node; if (!hw->dev && !hw->of_node) if (!hw->dev && !hw->of_node) return -EINVAL; return ERR_PTR(-EINVAL); node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL); node = devm_kzalloc(dev, sizeof(*node), GFP_KERNEL); if (!node) if (!node) return -ENOMEM; return ERR_PTR(-ENOMEM); node->gov = &devfreq_gov_memlat; node->attr_grp = &dev_attr_group; node->ratio_ceil = 10; node->ratio_ceil = 10; node->hw = hw; node->hw = hw; Loading @@ -393,20 +406,68 @@ int register_memlat(struct device *dev, struct memlat_hwmon *hw) hw->freq_map = init_core_dev_map(dev, "qcom,core-dev-table"); hw->freq_map = init_core_dev_map(dev, "qcom,core-dev-table"); if (!hw->freq_map) { if (!hw->freq_map) { dev_err(dev, "Couldn't find the core-dev freq table!\n"); dev_err(dev, "Couldn't find the core-dev freq table!\n"); return -EINVAL; return ERR_PTR(-EINVAL); } } mutex_lock(&list_lock); mutex_lock(&list_lock); list_add_tail(&node->list, &memlat_list); list_add_tail(&node->list, &memlat_list); mutex_unlock(&list_lock); 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); 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); ret = devfreq_add_governor(&devfreq_gov_memlat); if (!ret) if (!ret) use_cnt++; memlat_use_cnt++; mutex_unlock(&state_lock); mutex_unlock(&state_lock); out: if (!ret) if (!ret) dev_info(dev, "Memory Latency governor registered.\n"); dev_info(dev, "Memory Latency governor registered.\n"); else else Loading