forked from Minki/linux
9e9f601084
This adds (in req-gen/) a framework for defining gpci counter requests. It uses macro magic similar to ftrace. Also convert the existing hv-gpci request structures and enum values to use the new framework (and adjust old users of the structs and enum values to cope with changes in naming). In exchange for this macro disaster, we get autogenerated event listing for GPCI in sysfs, build time field offset checking, and zero duplication of information about GPCI requests. Signed-off-by: Cody P Schafer <cody@linux.vnet.ibm.com> Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
156 lines
4.6 KiB
C
156 lines
4.6 KiB
C
#ifndef LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
|
|
#define LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
|
|
|
|
#include <linux/perf_event.h>
|
|
|
|
#ifndef REQUEST_FILE
|
|
#error "REQUEST_FILE must be defined before including"
|
|
#endif
|
|
|
|
#ifndef NAME_LOWER
|
|
#error "NAME_LOWER must be defined before including"
|
|
#endif
|
|
|
|
#ifndef NAME_UPPER
|
|
#error "NAME_UPPER must be defined before including"
|
|
#endif
|
|
|
|
#define BE_TYPE_b1 __u8
|
|
#define BE_TYPE_b2 __be16
|
|
#define BE_TYPE_b4 __be32
|
|
#define BE_TYPE_b8 __be64
|
|
|
|
#define BYTES_TO_BE_TYPE(bytes) \
|
|
BE_TYPE_b##bytes
|
|
|
|
#define CAT2_(a, b) a ## b
|
|
#define CAT2(a, b) CAT2_(a, b)
|
|
#define CAT3_(a, b, c) a ## b ## c
|
|
#define CAT3(a, b, c) CAT3_(a, b, c)
|
|
|
|
/*
|
|
* enumerate the request values as
|
|
* <NAME_UPPER>_<request name> = <request value>
|
|
*/
|
|
#define REQUEST_VALUE__(name_upper, r_name) name_upper ## _ ## r_name
|
|
#define REQUEST_VALUE_(name_upper, r_name) REQUEST_VALUE__(name_upper, r_name)
|
|
#define REQUEST_VALUE(r_name) REQUEST_VALUE_(NAME_UPPER, r_name)
|
|
|
|
#include "_clear.h"
|
|
#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
|
|
REQUEST_VALUE(r_name) = r_value,
|
|
enum CAT2(NAME_LOWER, _requests) {
|
|
#include REQUEST_FILE
|
|
};
|
|
|
|
/*
|
|
* For each request:
|
|
* struct <NAME_LOWER>_<request name> {
|
|
* r_fields
|
|
* };
|
|
*/
|
|
#include "_clear.h"
|
|
#define STRUCT_NAME__(name_lower, r_name) name_lower ## _ ## r_name
|
|
#define STRUCT_NAME_(name_lower, r_name) STRUCT_NAME__(name_lower, r_name)
|
|
#define STRUCT_NAME(r_name) STRUCT_NAME_(NAME_LOWER, r_name)
|
|
#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
|
|
struct STRUCT_NAME(r_name) { \
|
|
r_fields \
|
|
};
|
|
#define __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \
|
|
BYTES_TO_BE_TYPE(f_bytes) f_name;
|
|
#define __count_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \
|
|
__field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name)
|
|
#define __array_(r_name, r_value, r_idx_1, a_offset, a_bytes, a_name) \
|
|
__u8 a_name[a_bytes];
|
|
|
|
#include REQUEST_FILE
|
|
|
|
/*
|
|
* Generate a check of the field offsets
|
|
* <NAME_LOWER>_assert_offsets_correct()
|
|
*/
|
|
#include "_clear.h"
|
|
#define REQUEST_(r_name, r_value, index, r_fields) \
|
|
r_fields
|
|
#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) \
|
|
BUILD_BUG_ON(offsetof(struct STRUCT_NAME(r_name), f_name) != f_offset);
|
|
#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
|
|
__field_(r_name, r_value, r_idx_1, c_offset, c_size, c_name)
|
|
#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) \
|
|
__field_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
|
|
|
|
static inline void CAT2(NAME_LOWER, _assert_offsets_correct)(void)
|
|
{
|
|
#include REQUEST_FILE
|
|
}
|
|
|
|
/*
|
|
* Generate event attributes:
|
|
* PMU_EVENT_ATTR_STRING(<request name>_<field name>,
|
|
* <NAME_LOWER>_event_attr_<request name>_<field name>,
|
|
* "request=<request value>"
|
|
* "starting_index=<starting index type>"
|
|
* "counter_info_version=CURRENT_COUNTER_INFO_VERSION"
|
|
* "length=<f_size>"
|
|
* "offset=<f_offset>")
|
|
*
|
|
* TODO: counter_info_version may need to vary, we should interperate the
|
|
* value to some extent
|
|
*/
|
|
#define EVENT_ATTR_NAME__(name, r_name, c_name) \
|
|
name ## _event_attr_ ## r_name ## _ ## c_name
|
|
#define EVENT_ATTR_NAME_(name, r_name, c_name) \
|
|
EVENT_ATTR_NAME__(name, r_name, c_name)
|
|
#define EVENT_ATTR_NAME(r_name, c_name) \
|
|
EVENT_ATTR_NAME_(NAME_LOWER, r_name, c_name)
|
|
|
|
#include "_clear.h"
|
|
#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name)
|
|
#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
|
|
#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
|
|
PMU_EVENT_ATTR_STRING( \
|
|
CAT3(r_name, _, c_name), \
|
|
EVENT_ATTR_NAME(r_name, c_name), \
|
|
"request=" __stringify(r_value) "," \
|
|
r_idx_1 "," \
|
|
"counter_info_version=" \
|
|
__stringify(COUNTER_INFO_VERSION_CURRENT) "," \
|
|
"length=" #c_size "," \
|
|
"offset=" #c_offset)
|
|
#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
|
|
r_fields
|
|
|
|
#include REQUEST_FILE
|
|
|
|
/*
|
|
* Define event attribute array
|
|
* static struct attribute *hv_gpci_event_attrs[] = {
|
|
* &<NAME_LOWER>_event_attr_<request name>_<field name>.attr,
|
|
* };
|
|
*/
|
|
#include "_clear.h"
|
|
#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name)
|
|
#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
|
|
&EVENT_ATTR_NAME(r_name, c_name).attr.attr,
|
|
#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
|
|
#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
|
|
r_fields
|
|
|
|
static __maybe_unused struct attribute *hv_gpci_event_attrs[] = {
|
|
#include REQUEST_FILE
|
|
NULL
|
|
};
|
|
|
|
/* cleanup */
|
|
#include "_clear.h"
|
|
#undef EVENT_ATTR_NAME
|
|
#undef EVENT_ATTR_NAME_
|
|
#undef BIT_NAME
|
|
#undef BIT_NAME_
|
|
#undef STRUCT_NAME
|
|
#undef REQUEST_VALUE
|
|
#undef REQUEST_VALUE_
|
|
|
|
#endif
|