diff --git a/drivers/devfreq/arm-memlat-mon.c b/drivers/devfreq/arm-memlat-mon.c index 76f13daa5565..cbc51baf2991 100644 --- a/drivers/devfreq/arm-memlat-mon.c +++ b/drivers/devfreq/arm-memlat-mon.c @@ -28,6 +28,7 @@ enum ev_index { INST_IDX, CM_IDX, CYC_IDX, + STALL_CYC_IDX, NUM_EVENTS }; #define INST_EV 0x08 @@ -92,12 +93,19 @@ static void read_perf_counters(int cpu, struct cpu_grp_info *cpu_grp) { struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu); struct dev_stats *devstats = to_devstats(cpu_grp, cpu); - unsigned long cyc_cnt; + unsigned long cyc_cnt, stall_cnt; devstats->inst_count = read_event(&cpustats->events[INST_IDX]); devstats->mem_count = read_event(&cpustats->events[CM_IDX]); cyc_cnt = read_event(&cpustats->events[CYC_IDX]); devstats->freq = compute_freq(cpustats, cyc_cnt); + if (cpustats->events[STALL_CYC_IDX].pevent) { + stall_cnt = read_event(&cpustats->events[STALL_CYC_IDX]); + stall_cnt = min(stall_cnt, cyc_cnt); + devstats->stall_pct = mult_frac(100, stall_cnt, cyc_cnt); + } else { + devstats->stall_pct = 100; + } } static unsigned long get_cnt(struct memlat_hwmon *hw) @@ -117,7 +125,10 @@ static void delete_events(struct cpu_pmu_stats *cpustats) for (i = 0; i < ARRAY_SIZE(cpustats->events); i++) { cpustats->events[i].prev_count = 0; - perf_event_release_kernel(cpustats->events[i].pevent); + if (cpustats->events[i].pevent) { + perf_event_release_kernel(cpustats->events[i].pevent); + cpustats->events[i].pevent = NULL; + } } } @@ -135,6 +146,7 @@ static void stop_hwmon(struct memlat_hwmon *hw) devstats->inst_count = 0; devstats->mem_count = 0; devstats->freq = 0; + devstats->stall_pct = 0; } } @@ -158,6 +170,7 @@ static int set_events(struct cpu_grp_info *cpu_grp, int cpu) struct perf_event *pevent; struct perf_event_attr *attr; int err, i; + unsigned int event_id; struct cpu_pmu_stats *cpustats = to_cpustats(cpu_grp, cpu); /* Allocate an attribute for event initialization */ @@ -166,7 +179,11 @@ static int set_events(struct cpu_grp_info *cpu_grp, int cpu) return -ENOMEM; for (i = 0; i < ARRAY_SIZE(cpustats->events); i++) { - attr->config = cpu_grp->event_ids[i]; + event_id = cpu_grp->event_ids[i]; + if (!event_id) + continue; + + attr->config = event_id; pevent = perf_event_create_kernel_counter(attr, cpu, NULL, NULL, NULL); if (IS_ERR(pevent)) @@ -282,6 +299,13 @@ static int arm_memlat_mon_driver_probe(struct platform_device *pdev) } cpu_grp->event_ids[INST_IDX] = event_id; + ret = of_property_read_u32(dev->of_node, "qcom,stall-cycle-ev", + &event_id); + if (ret) + dev_dbg(dev, "Stall cycle event not specified. Event ignored.\n"); + else + cpu_grp->event_ids[STALL_CYC_IDX] = event_id; + for_each_cpu(cpu, &cpu_grp->cpus) to_devstats(cpu_grp, cpu)->id = cpu; diff --git a/drivers/devfreq/governor_memlat.c b/drivers/devfreq/governor_memlat.c index b7415b0eaeef..9f1186542cea 100644 --- a/drivers/devfreq/governor_memlat.c +++ b/drivers/devfreq/governor_memlat.c @@ -27,6 +27,7 @@ struct memlat_node { unsigned int ratio_ceil; + unsigned int stall_floor; bool mon_started; bool already_zero; struct list_head list; @@ -234,9 +235,11 @@ static int devfreq_memlat_get_freq(struct devfreq *df, hw->core_stats[i].id, hw->core_stats[i].inst_count, hw->core_stats[i].mem_count, - hw->core_stats[i].freq, ratio); + hw->core_stats[i].freq, + hw->core_stats[i].stall_pct, ratio); if (ratio <= node->ratio_ceil + && hw->core_stats[i].stall_pct >= node->stall_floor && hw->core_stats[i].freq > max_freq) { lat_dev = i; max_freq = hw->core_stats[i].freq; @@ -264,9 +267,13 @@ static int devfreq_memlat_get_freq(struct devfreq *df, show_attr(ratio_ceil); store_attr(ratio_ceil, 1U, 20000U); static DEVICE_ATTR_RW(ratio_ceil); +show_attr(stall_floor); +store_attr(stall_floor, 0U, 100U); +static DEVICE_ATTR_RW(stall_floor); static struct attribute *dev_attr[] = { &dev_attr_ratio_ceil.attr, + &dev_attr_stall_floor.attr, &dev_attr_freq_map.attr, NULL, }; diff --git a/drivers/devfreq/governor_memlat.h b/drivers/devfreq/governor_memlat.h index 6eb3dee6ae0f..335ba7598b6b 100644 --- a/drivers/devfreq/governor_memlat.h +++ b/drivers/devfreq/governor_memlat.h @@ -21,6 +21,7 @@ struct dev_stats { unsigned long inst_count; unsigned long mem_count; unsigned long freq; + unsigned long stall_pct; }; struct core_dev_map { diff --git a/include/trace/events/power.h b/include/trace/events/power.h index f95eb5bba10a..04bd8831dd2b 100644 --- a/include/trace/events/power.h +++ b/include/trace/events/power.h @@ -631,9 +631,10 @@ TRACE_EVENT(cache_hwmon_update, TRACE_EVENT(memlat_dev_meas, TP_PROTO(const char *name, unsigned int dev_id, unsigned long inst, - unsigned long mem, unsigned long freq, unsigned int ratio), + unsigned long mem, unsigned long freq, unsigned int stall, + unsigned int ratio), - TP_ARGS(name, dev_id, inst, mem, freq, ratio), + TP_ARGS(name, dev_id, inst, mem, freq, stall, ratio), TP_STRUCT__entry( __string(name, name) @@ -641,6 +642,7 @@ TRACE_EVENT(memlat_dev_meas, __field(unsigned long, inst) __field(unsigned long, mem) __field(unsigned long, freq) + __field(unsigned int, stall) __field(unsigned int, ratio) ), @@ -650,15 +652,17 @@ TRACE_EVENT(memlat_dev_meas, __entry->inst = inst; __entry->mem = mem; __entry->freq = freq; + __entry->stall = stall; __entry->ratio = ratio; ), - TP_printk("dev: %s, id=%u, inst=%lu, mem=%lu, freq=%lu, ratio=%u", + TP_printk("dev: %s, id=%u, inst=%lu, mem=%lu, freq=%lu, stall=%u, ratio=%u", __get_str(name), __entry->dev_id, __entry->inst, __entry->mem, __entry->freq, + __entry->stall, __entry->ratio) );