1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
3#define LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
4
5#include <linux/perf_event.h>
6#include <linux/stringify.h>
7
8#ifndef REQUEST_FILE
9#error "REQUEST_FILE must be defined before including"
10#endif
11
12#ifndef NAME_LOWER
13#error "NAME_LOWER must be defined before including"
14#endif
15
16#ifndef NAME_UPPER
17#error "NAME_UPPER must be defined before including"
18#endif
19
20#define BE_TYPE_b1 __u8
21#define BE_TYPE_b2 __be16
22#define BE_TYPE_b4 __be32
23#define BE_TYPE_b8 __be64
24
25#define BYTES_TO_BE_TYPE(bytes) \
26		BE_TYPE_b##bytes
27
28#define CAT2_(a, b) a ## b
29#define CAT2(a, b) CAT2_(a, b)
30#define CAT3_(a, b, c) a ## b ## c
31#define CAT3(a, b, c) CAT3_(a, b, c)
32
33/*
34 * enumerate the request values as
35 * <NAME_UPPER>_<request name> = <request value>
36 */
37#define REQUEST_VALUE__(name_upper, r_name) name_upper ## _ ## r_name
38#define REQUEST_VALUE_(name_upper, r_name) REQUEST_VALUE__(name_upper, r_name)
39#define REQUEST_VALUE(r_name) REQUEST_VALUE_(NAME_UPPER, r_name)
40
41#include "_clear.h"
42#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
43	REQUEST_VALUE(r_name) = r_value,
44enum CAT2(NAME_LOWER, _requests) {
45#include REQUEST_FILE
46};
47
48/*
49 * For each request:
50 * struct <NAME_LOWER>_<request name> {
51 *	r_fields
52 * };
53 */
54#include "_clear.h"
55#define STRUCT_NAME__(name_lower, r_name) name_lower ## _ ## r_name
56#define STRUCT_NAME_(name_lower, r_name) STRUCT_NAME__(name_lower, r_name)
57#define STRUCT_NAME(r_name) STRUCT_NAME_(NAME_LOWER, r_name)
58#define REQUEST_(r_name, r_value, r_idx_1, r_fields)	\
59struct STRUCT_NAME(r_name) {				\
60	r_fields					\
61};
62#define __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \
63	BYTES_TO_BE_TYPE(f_bytes) f_name;
64#define __count_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \
65	__field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name)
66#define __array_(r_name, r_value, r_idx_1, a_offset, a_bytes, a_name) \
67	__u8 a_name[a_bytes];
68
69#include REQUEST_FILE
70
71/*
72 * Generate a check of the field offsets
73 * <NAME_LOWER>_assert_offsets_correct()
74 */
75#include "_clear.h"
76#define REQUEST_(r_name, r_value, index, r_fields)			\
77r_fields
78#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) \
79	BUILD_BUG_ON(offsetof(struct STRUCT_NAME(r_name), f_name) != f_offset);
80#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
81	__field_(r_name, r_value, r_idx_1, c_offset, c_size, c_name)
82#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) \
83	__field_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
84
85static inline void CAT2(NAME_LOWER, _assert_offsets_correct)(void)
86{
87#include REQUEST_FILE
88}
89
90/*
91 * Generate event attributes:
92 * PMU_EVENT_ATTR_STRING(<request name>_<field name>,
93 *	<NAME_LOWER>_event_attr_<request name>_<field name>,
94 *		"request=<request value>"
95 *		"starting_index=<starting index type>"
96 *		"counter_info_version=CURRENT_COUNTER_INFO_VERSION"
97 *		"length=<f_size>"
98 *		"offset=<f_offset>")
99 *
100 *	TODO: counter_info_version may need to vary, we should interperate the
101 *	value to some extent
102 */
103#define EVENT_ATTR_NAME__(name, r_name, c_name) \
104	name ## _event_attr_ ## r_name ## _ ## c_name
105#define EVENT_ATTR_NAME_(name, r_name, c_name) \
106	EVENT_ATTR_NAME__(name, r_name, c_name)
107#define EVENT_ATTR_NAME(r_name, c_name) \
108	EVENT_ATTR_NAME_(NAME_LOWER, r_name, c_name)
109
110#include "_clear.h"
111#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name)
112#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
113#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name)	\
114PMU_EVENT_ATTR_STRING(							\
115		CAT3(r_name, _, c_name),				\
116		EVENT_ATTR_NAME(r_name, c_name),			\
117		"request=" __stringify(r_value) ","			\
118		r_idx_1 ","						\
119		"counter_info_version="					\
120			__stringify(COUNTER_INFO_VERSION_CURRENT) ","	\
121		"length=" #c_size ","					\
122		"offset=" #c_offset)
123#define REQUEST_(r_name, r_value, r_idx_1, r_fields)			\
124	r_fields
125
126#include REQUEST_FILE
127
128/*
129 * Define event attribute array
130 * static struct attribute *hv_gpci_event_attrs[] = {
131 *	&<NAME_LOWER>_event_attr_<request name>_<field name>.attr,
132 * };
133 */
134#include "_clear.h"
135#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name)
136#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name)	\
137	&EVENT_ATTR_NAME(r_name, c_name).attr.attr,
138#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
139#define REQUEST_(r_name, r_value, r_idx_1, r_fields)			\
140	r_fields
141
142/* Generate event list for platforms with counter_info_version 0x6 or below */
143static __maybe_unused struct attribute *hv_gpci_event_attrs_v6[] = {
144#include REQUEST_FILE
145	NULL
146};
147
148/*
149 * Based on getPerfCountInfo v1.018 documentation, some of the hv-gpci
150 * events were deprecated for platform firmware that supports
151 * counter_info_version 0x8 or above.
152 * Those deprecated events are still part of platform firmware that
153 * support counter_info_version 0x6 and below. As per the getPerfCountInfo
154 * v1.018 documentation there is no counter_info_version 0x7.
155 * Undefining macro ENABLE_EVENTS_COUNTERINFO_V6, to disable the addition of
156 * deprecated events in "hv_gpci_event_attrs" attribute group, for platforms
157 * that supports counter_info_version 0x8 or above.
158 */
159#undef ENABLE_EVENTS_COUNTERINFO_V6
160
161/* Generate event list for platforms with counter_info_version 0x8 or above*/
162static __maybe_unused struct attribute *hv_gpci_event_attrs[] = {
163#include REQUEST_FILE
164	NULL
165};
166
167/* cleanup */
168#include "_clear.h"
169#undef EVENT_ATTR_NAME
170#undef EVENT_ATTR_NAME_
171#undef BIT_NAME
172#undef BIT_NAME_
173#undef STRUCT_NAME
174#undef REQUEST_VALUE
175#undef REQUEST_VALUE_
176
177#endif
178