root/arch/powerpc/perf/req-gen/perf.h
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
#define LINUX_POWERPC_PERF_REQ_GEN_PERF_H_

#include <linux/perf_event.h>
#include <linux/stringify.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

/* Generate event list for platforms with counter_info_version 0x6 or below */
static __maybe_unused struct attribute *hv_gpci_event_attrs_v6[] = {
#include REQUEST_FILE
        NULL
};

/*
 * Based on getPerfCountInfo v1.018 documentation, some of the hv-gpci
 * events were deprecated for platform firmware that supports
 * counter_info_version 0x8 or above.
 * Those deprecated events are still part of platform firmware that
 * support counter_info_version 0x6 and below. As per the getPerfCountInfo
 * v1.018 documentation there is no counter_info_version 0x7.
 * Undefining macro ENABLE_EVENTS_COUNTERINFO_V6, to disable the addition of
 * deprecated events in "hv_gpci_event_attrs" attribute group, for platforms
 * that supports counter_info_version 0x8 or above.
 */
#undef ENABLE_EVENTS_COUNTERINFO_V6

/* Generate event list for platforms with counter_info_version 0x8 or above*/
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