diff --git a/drivers/soc/qcom/msm_performance.c b/drivers/soc/qcom/msm_performance.c index bd8dedfe3515..0cbc86ac31c2 100644 --- a/drivers/soc/qcom/msm_performance.c +++ b/drivers/soc/qcom/msm_performance.c @@ -18,6 +18,11 @@ #include #include #include +#include +#include +#include +#include +#include /* * Sched will provide the data for every 20ms window, @@ -26,6 +31,7 @@ */ #define POLL_INT 25 #define NODE_NAME_MAX_CHARS 16 +#define QUEUE_POOL_SIZE 512 /*2^8 always keep in 2^x */ enum cpu_clusters { MIN = 0, @@ -42,6 +48,25 @@ struct cpu_status { static DEFINE_PER_CPU(struct cpu_status, msm_perf_cpu_stats); static DEFINE_PER_CPU(struct freq_qos_request, qos_req_min); static DEFINE_PER_CPU(struct freq_qos_request, qos_req_max); +static DECLARE_COMPLETION(gfx_evt_arrival); + +struct gpu_data { + pid_t pid; + int ctx_id; + unsigned int timestamp; + ktime_t arrive_ts; + int evt_typ; +}; + +static struct gpu_data gpu_circ_buff[QUEUE_POOL_SIZE]; + +struct queue_indicies { + int head; + int tail; +}; +static struct queue_indicies curr_pos; + +static DEFINE_SPINLOCK(gfx_circ_buff_lock); struct events { spinlock_t cpu_hotplug_lock; @@ -59,6 +84,9 @@ static unsigned int curr_cap[CLUSTER_MAX]; static cpumask_var_t limit_mask_min; static cpumask_var_t limit_mask_max; +static atomic_t game_status; +static atomic_t game_status_pid; + static bool ready_for_freq_updates; static int freq_qos_request_init(void) @@ -314,6 +342,45 @@ static struct attribute_group events_attr_group = { .attrs = events_attrs, }; +static ssize_t show_perf_gfx_evts(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + struct queue_indicies updated_pos; + unsigned long flags; + ssize_t retval = 0; + int idx = 0, size, act_idx, ret = -1; + + ret = wait_for_completion_interruptible(&gfx_evt_arrival); + if (ret) + return 0; + spin_lock_irqsave(&gfx_circ_buff_lock, flags); + updated_pos.head = curr_pos.head; + updated_pos.tail = curr_pos.tail; + size = CIRC_CNT(updated_pos.head, updated_pos.tail, QUEUE_POOL_SIZE); + curr_pos.tail = (curr_pos.tail + size) % QUEUE_POOL_SIZE; + spin_unlock_irqrestore(&gfx_circ_buff_lock, flags); + + for (idx = 0; idx < size; idx++) { + act_idx = (updated_pos.tail + idx) % QUEUE_POOL_SIZE; + retval += scnprintf(buf + retval, PAGE_SIZE - retval, + "%d %d %u %d %lu :", + gpu_circ_buff[act_idx].pid, + gpu_circ_buff[act_idx].ctx_id, + gpu_circ_buff[act_idx].timestamp, + gpu_circ_buff[act_idx].evt_typ, + ktime_to_us(gpu_circ_buff[act_idx].arrive_ts)); + if (retval >= PAGE_SIZE) { + pr_err("msm_perf:data limit exceed\n"); + break; + } + } + return retval; +} + +static struct kobj_attribute gfx_event_info_attr = +__ATTR(gfx_evt, 0444, show_perf_gfx_evts, NULL); + static ssize_t show_big_nr(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -364,6 +431,7 @@ static struct attribute *notify_attrs[] = { &top_load_attr.attr, &cluster_top_load_attr.attr, &cluster_curr_cap_attr.attr, + &gfx_event_info_attr.attr, NULL, }; @@ -554,6 +622,84 @@ static const struct kernel_param_ops param_ops_cc_register = { module_param_cb(core_ctl_register, ¶m_ops_cc_register, &core_ctl_register, 0644); +void msm_perf_events_update(enum evt_update_t update_typ, + enum gfx_evt_t evt_typ, pid_t pid, + uint32_t ctx_id, uint32_t timestamp) +{ + unsigned long flags; + int idx = 0; + + if (update_typ != MSM_PERF_GFX) + return; + + if (!atomic_read(&game_status) || + (pid != atomic_read(&game_status_pid))) + return; + + spin_lock_irqsave(&gfx_circ_buff_lock, flags); + idx = curr_pos.head; + curr_pos.head = ((curr_pos.head + 1) % QUEUE_POOL_SIZE); + spin_unlock_irqrestore(&gfx_circ_buff_lock, flags); + gpu_circ_buff[idx].pid = pid; + gpu_circ_buff[idx].ctx_id = ctx_id; + gpu_circ_buff[idx].timestamp = timestamp; + gpu_circ_buff[idx].evt_typ = evt_typ; + gpu_circ_buff[idx].arrive_ts = ktime_get(); + + if (evt_typ == MSM_PERF_QUEUE || evt_typ == MSM_PERF_RETIRED) + complete(&gfx_evt_arrival); +} + + + +static int set_game_start_event(const char *buf, const struct kernel_param *kp) +{ + long usr_val = 0; + int ret = strlen(buf); + + kstrtol(buf, 0, &usr_val); + atomic_set(&game_status, usr_val); + return ret; +} + +static int get_game_start_event(char *buf, const struct kernel_param *kp) +{ + long usr_val = atomic_read(&game_status); + + return scnprintf(buf, PAGE_SIZE, "%ld\n", usr_val); +} + +static const struct kernel_param_ops param_ops_game_start_evt = { + .set = set_game_start_event, + .get = get_game_start_event, +}; +module_param_cb(evnt_gplaf_status, ¶m_ops_game_start_evt, NULL, 0644); + +static int set_game_start_pid(const char *buf, const struct kernel_param *kp) +{ + long usr_val = 0; + int ret = strlen(buf); + + kstrtol(buf, 0, &usr_val); + atomic_set(&game_status_pid, usr_val); + return ret; +} + +static int get_game_start_pid(char *buf, const struct kernel_param *kp) +{ + long usr_val = atomic_read(&game_status_pid); + + return scnprintf(buf, PAGE_SIZE, "%ld\n", usr_val); +} + +static const struct kernel_param_ops param_ops_game_start_pid = { + .set = set_game_start_pid, + .get = get_game_start_pid, +}; +module_param_cb(evnt_gplaf_pid, ¶m_ops_game_start_pid, NULL, 0644); + +/*******************************GFX Call************************************/ + static int __init msm_performance_init(void) { int ret; diff --git a/include/soc/qcom/msm_performance.h b/include/soc/qcom/msm_performance.h new file mode 100644 index 000000000000..abf70aeda4a7 --- /dev/null +++ b/include/soc/qcom/msm_performance.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ + +#ifndef __MSM_PERFORMANCE_H +#define __MSM_PERFORMANCE_H + +enum gfx_evt_t { + MSM_PERF_INVAL, + MSM_PERF_QUEUE, + MSM_PERF_SUBMIT, + MSM_PERF_RETIRED +}; + +enum evt_update_t { + MSM_PERF_GFX, +}; + +#ifdef CONFIG_MSM_PERFORMANCE +void msm_perf_events_update(enum evt_update_t update_typ, + enum gfx_evt_t evt_typ, pid_t pid, + uint32_t ctx_id, uint32_t timestamp); +#else +static inline void msm_perf_events_update(enum evt_update_t update_typ, + enum gfx_evt_t evt_typ, pid_t pid, + uint32_t ctx_id, uint32_t timestamp){} +#endif +#endif