summaryrefslogtreecommitdiff
path: root/gxp-usage-stats.c
blob: 1e5d3f98be29280d082aa4380cd4fac4f5db0025 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// SPDX-License-Identifier: GPL-2.0
/*
 * DSP usage stats
 *
 * Copyright (C) 2022 Google LLC
 */

#include <linux/device.h>

#include <gcip/gcip-usage-stats.h>

#include "gxp-config.h"
#include "gxp-mcu-platform.h"
#include "gxp-mcu.h"
#include "gxp-pm.h"
#include "gxp-usage-stats.h"

/* Core usage. */
static GCIP_USAGE_STATS_ATTR_RW(GCIP_USAGE_STATS_METRIC_TYPE_CORE_USAGE, 0, 0, dsp_usage_0, NULL,
				NULL);

static GCIP_USAGE_STATS_ATTR_RW(GCIP_USAGE_STATS_METRIC_TYPE_CORE_USAGE, 0, 1, dsp_usage_1, NULL,
				NULL);

static GCIP_USAGE_STATS_ATTR_RW(GCIP_USAGE_STATS_METRIC_TYPE_CORE_USAGE, 0, 2, dsp_usage_2, NULL,
				NULL);

/* Counter. */
static GCIP_USAGE_STATS_ATTR_RW(GCIP_USAGE_STATS_METRIC_TYPE_COUNTER,
				GCIP_USAGE_STATS_COUNTER_WORKLOAD,
				GCIP_USAGE_STATS_ATTR_ALL_SUBCOMPONENTS, dsp_workload_count, NULL,
				NULL);

static GCIP_USAGE_STATS_ATTR_RW(GCIP_USAGE_STATS_METRIC_TYPE_COUNTER,
				GCIP_USAGE_STATS_COUNTER_CONTEXT_SWITCHES,
				GCIP_USAGE_STATS_ATTR_ALL_SUBCOMPONENTS, context_switch_count, NULL,
				NULL);

static GCIP_USAGE_STATS_ATTR_RW(GCIP_USAGE_STATS_METRIC_TYPE_COUNTER,
				GCIP_USAGE_STATS_COUNTER_CONTEXT_PREEMPTIONS,
				GCIP_USAGE_STATS_ATTR_ALL_SUBCOMPONENTS, preempt_count, NULL, NULL);

/* Thread statistics. */
static GCIP_USAGE_STATS_ATTR_RW(GCIP_USAGE_STATS_METRIC_TYPE_THREAD_STATS, 0, 0, fw_thread_stats,
				NULL, NULL);

/* DVFS frequency info. */
static GCIP_USAGE_STATS_ATTR_RO(GCIP_USAGE_STATS_METRIC_TYPE_DVFS_FREQUENCY_INFO, 0, 0,
				scaling_available_frequencies, NULL);

static struct gcip_usage_stats_attr *attrs[] = {
	&gcip_usage_stats_attr_dsp_usage_0,
	&gcip_usage_stats_attr_dsp_usage_1,
	&gcip_usage_stats_attr_dsp_usage_2,
	&gcip_usage_stats_attr_dsp_workload_count,
	&gcip_usage_stats_attr_context_switch_count,
	&gcip_usage_stats_attr_preempt_count,
	&gcip_usage_stats_attr_fw_thread_stats,
	&gcip_usage_stats_attr_scaling_available_frequencies,
};

static int update_usage_kci(void *data)
{
	struct gxp_usage_stats *ustats = data;
	struct gxp_dev *gxp = ustats->gxp;
	struct gxp_mcu *mcu = &to_mcu_dev(gxp)->mcu;

	return gxp_kci_update_usage(&mcu->kci);
}

static int get_default_dvfs_freqs_num(void *data)
{
	return AUR_NUM_POWER_STATE;
}

static int get_default_dvfs_freq(int idx, void *data)
{
	if (idx >= AUR_NUM_POWER_STATE)
		return 0;
	return aur_power_state2rate[idx];
}

static const struct gcip_usage_stats_ops stats_ops = {
	.update_usage_kci = update_usage_kci,
	.get_default_dvfs_freqs_num = get_default_dvfs_freqs_num,
	.get_default_dvfs_freq = get_default_dvfs_freq,
};

void gxp_usage_stats_process_buffer(struct gxp_dev *gxp, void *buf)
{
	if (!gxp->usage_stats)
		return;
	gcip_usage_stats_process_buffer(&gxp->usage_stats->ustats, buf);
}

void gxp_usage_stats_init(struct gxp_dev *gxp)
{
	struct gxp_usage_stats *ustats;
	struct gcip_usage_stats_args args;
	int ret;

	ustats = devm_kzalloc(gxp->dev, sizeof(*gxp->usage_stats), GFP_KERNEL);
	if (!ustats) {
		dev_warn(gxp->dev, "failed to allocate memory for usage stats\n");
		return;
	}

	args.version = GXP_USAGE_METRIC_VERSION;
	args.dev = gxp->dev;
	args.ops = &stats_ops;
	args.attrs = attrs;
	args.num_attrs = ARRAY_SIZE(attrs);
	args.subcomponents = GXP_NUM_CORES;
	args.data = ustats;
	ustats->gxp = gxp;

	ret = gcip_usage_stats_init(&ustats->ustats, &args);
	if (ret) {
		dev_warn(gxp->dev, "failed to create the usage_stats attrs\n");
		devm_kfree(gxp->dev, ustats);
		return;
	}

	gxp->usage_stats = ustats;
}

void gxp_usage_stats_exit(struct gxp_dev *gxp)
{
	if (gxp->usage_stats) {
		gcip_usage_stats_exit(&gxp->usage_stats->ustats);
		devm_kfree(gxp->dev, gxp->usage_stats);
	}
	gxp->usage_stats = NULL;
}