aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCody P Schafer <cody@linux.vnet.ibm.com>2015-01-30 16:46:01 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2015-02-02 01:56:39 -0500
commit9e9f60108423f18a99c9cc93ef7f23490ecc709b (patch)
tree69bcabb2b279dd0d677a162f68d8095523a73953
parent5c5cd7b502595f6b90509b8aa4bba6f81b69315c (diff)
powerpc/perf/{hv-gpci, hv-common}: generate requests with counters annotated
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>
-rw-r--r--arch/powerpc/perf/hv-common.c10
-rw-r--r--arch/powerpc/perf/hv-gpci-requests.h76
-rw-r--r--arch/powerpc/perf/hv-gpci.c23
-rw-r--r--arch/powerpc/perf/hv-gpci.h37
-rw-r--r--arch/powerpc/perf/req-gen/_begin.h13
-rw-r--r--arch/powerpc/perf/req-gen/_clear.h5
-rw-r--r--arch/powerpc/perf/req-gen/_end.h4
-rw-r--r--arch/powerpc/perf/req-gen/_request-begin.h15
-rw-r--r--arch/powerpc/perf/req-gen/_request-end.h8
-rw-r--r--arch/powerpc/perf/req-gen/perf.h155
10 files changed, 316 insertions, 30 deletions
diff --git a/arch/powerpc/perf/hv-common.c b/arch/powerpc/perf/hv-common.c
index 47e02b366f58..7dce8f109967 100644
--- a/arch/powerpc/perf/hv-common.c
+++ b/arch/powerpc/perf/hv-common.c
@@ -9,13 +9,13 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps)
9 unsigned long r; 9 unsigned long r;
10 struct p { 10 struct p {
11 struct hv_get_perf_counter_info_params params; 11 struct hv_get_perf_counter_info_params params;
12 struct cv_system_performance_capabilities caps; 12 struct hv_gpci_system_performance_capabilities caps;
13 } __packed __aligned(sizeof(uint64_t)); 13 } __packed __aligned(sizeof(uint64_t));
14 14
15 struct p arg = { 15 struct p arg = {
16 .params = { 16 .params = {
17 .counter_request = cpu_to_be32( 17 .counter_request = cpu_to_be32(
18 CIR_SYSTEM_PERFORMANCE_CAPABILITIES), 18 HV_GPCI_system_performance_capabilities),
19 .starting_index = cpu_to_be32(-1), 19 .starting_index = cpu_to_be32(-1),
20 .counter_info_version_in = 0, 20 .counter_info_version_in = 0,
21 } 21 }
@@ -31,9 +31,9 @@ unsigned long hv_perf_caps_get(struct hv_perf_caps *caps)
31 31
32 caps->version = arg.params.counter_info_version_out; 32 caps->version = arg.params.counter_info_version_out;
33 caps->collect_privileged = !!arg.caps.perf_collect_privileged; 33 caps->collect_privileged = !!arg.caps.perf_collect_privileged;
34 caps->ga = !!(arg.caps.capability_mask & CV_CM_GA); 34 caps->ga = !!(arg.caps.capability_mask & HV_GPCI_CM_GA);
35 caps->expanded = !!(arg.caps.capability_mask & CV_CM_EXPANDED); 35 caps->expanded = !!(arg.caps.capability_mask & HV_GPCI_CM_EXPANDED);
36 caps->lab = !!(arg.caps.capability_mask & CV_CM_LAB); 36 caps->lab = !!(arg.caps.capability_mask & HV_GPCI_CM_LAB);
37 37
38 return r; 38 return r;
39} 39}
diff --git a/arch/powerpc/perf/hv-gpci-requests.h b/arch/powerpc/perf/hv-gpci-requests.h
new file mode 100644
index 000000000000..80085444b1a0
--- /dev/null
+++ b/arch/powerpc/perf/hv-gpci-requests.h
@@ -0,0 +1,76 @@
1
2#include "req-gen/_begin.h"
3
4/*
5 * Based on the document "getPerfCountInfo v1.07"
6 */
7
8/*
9 * #define REQUEST_NAME counter_request_name
10 * #define REQUEST_NUM r_num
11 * #define REQUEST_IDX_KIND starting_index_kind
12 * #include I(REQUEST_BEGIN)
13 * REQUEST(
14 * __field(...)
15 * __field(...)
16 * __array(...)
17 * __count(...)
18 * )
19 * #include I(REQUEST_END)
20 *
21 * - starting_index_kind is one of the following, depending on the event:
22 *
23 * chip_id: hardware chip id or -1 for current hw chip
24 * phys_processor_idx:
25 * 0xffffffffffffffff: or -1, which means it is irrelavant for the event
26 *
27 * __count(offset, bytes, name):
28 * a counter that should be exposed via perf
29 * __field(offset, bytes, name)
30 * a normal field
31 * __array(offset, bytes, name)
32 * an array of bytes
33 *
34 *
35 * @bytes for __count, and __field _must_ be a numeral token
36 * in decimal, not an expression and not in hex.
37 *
38 *
39 * TODO:
40 * - expose secondary index (if any counter ever uses it, only 0xA0
41 * appears to use it right now, and it doesn't have any counters)
42 * - embed versioning info
43 * - include counter descriptions
44 */
45#define REQUEST_NAME dispatch_timebase_by_processor
46#define REQUEST_NUM 0x10
47#define REQUEST_IDX_KIND "phys_processor_idx=?"
48#include I(REQUEST_BEGIN)
49REQUEST(__count(0, 8, processor_time_in_timebase_cycles)
50 __field(0x8, 4, hw_processor_id)
51 __field(0xC, 2, owning_part_id)
52 __field(0xE, 1, processor_state)
53 __field(0xF, 1, version)
54 __field(0x10, 4, hw_chip_id)
55 __field(0x14, 4, phys_module_id)
56 __field(0x18, 4, primary_affinity_domain_idx)
57 __field(0x1C, 4, secondary_affinity_domain_idx)
58 __field(0x20, 4, processor_version)
59 __field(0x24, 2, logical_processor_idx)
60 __field(0x26, 2, reserved)
61 __field(0x28, 4, processor_id_register)
62 __field(0x2C, 4, phys_processor_idx)
63)
64#include I(REQUEST_END)
65
66#define REQUEST_NAME system_performance_capabilities
67#define REQUEST_NUM 0x40
68#define REQUEST_IDX_KIND "starting_index=0xffffffffffffffff"
69#include I(REQUEST_BEGIN)
70REQUEST(__field(0, 1, perf_collect_privileged)
71 __field(0x1, 1, capability_mask)
72 __array(0x2, 0xE, reserved)
73)
74#include I(REQUEST_END)
75
76#include "req-gen/_end.h"
diff --git a/arch/powerpc/perf/hv-gpci.c b/arch/powerpc/perf/hv-gpci.c
index a051fe946c63..856fe6e03c2a 100644
--- a/arch/powerpc/perf/hv-gpci.c
+++ b/arch/powerpc/perf/hv-gpci.c
@@ -31,7 +31,18 @@
31/* u32 */ 31/* u32 */
32EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31); 32EVENT_DEFINE_RANGE_FORMAT(request, config, 0, 31);
33/* u32 */ 33/* u32 */
34/*
35 * Note that starting_index, phys_processor_idx, sibling_part_id,
36 * hw_chip_id, partition_id all refer to the same bit range. They
37 * are basically aliases for the starting_index. The specific alias
38 * used depends on the event. See REQUEST_IDX_KIND in hv-gpci-requests.h
39 */
34EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63); 40EVENT_DEFINE_RANGE_FORMAT(starting_index, config, 32, 63);
41EVENT_DEFINE_RANGE_FORMAT_LITE(phys_processor_idx, config, 32, 63);
42EVENT_DEFINE_RANGE_FORMAT_LITE(sibling_part_id, config, 32, 63);
43EVENT_DEFINE_RANGE_FORMAT_LITE(hw_chip_id, config, 32, 63);
44EVENT_DEFINE_RANGE_FORMAT_LITE(partition_id, config, 32, 63);
45
35/* u16 */ 46/* u16 */
36EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15); 47EVENT_DEFINE_RANGE_FORMAT(secondary_index, config1, 0, 15);
37/* u8 */ 48/* u8 */
@@ -44,6 +55,10 @@ EVENT_DEFINE_RANGE_FORMAT(offset, config1, 32, 63);
44static struct attribute *format_attrs[] = { 55static struct attribute *format_attrs[] = {
45 &format_attr_request.attr, 56 &format_attr_request.attr,
46 &format_attr_starting_index.attr, 57 &format_attr_starting_index.attr,
58 &format_attr_phys_processor_idx.attr,
59 &format_attr_sibling_part_id.attr,
60 &format_attr_hw_chip_id.attr,
61 &format_attr_partition_id.attr,
47 &format_attr_secondary_index.attr, 62 &format_attr_secondary_index.attr,
48 &format_attr_counter_info_version.attr, 63 &format_attr_counter_info_version.attr,
49 64
@@ -57,6 +72,11 @@ static struct attribute_group format_group = {
57 .attrs = format_attrs, 72 .attrs = format_attrs,
58}; 73};
59 74
75static struct attribute_group event_group = {
76 .name = "events",
77 .attrs = hv_gpci_event_attrs,
78};
79
60#define HV_CAPS_ATTR(_name, _format) \ 80#define HV_CAPS_ATTR(_name, _format) \
61static ssize_t _name##_show(struct device *dev, \ 81static ssize_t _name##_show(struct device *dev, \
62 struct device_attribute *attr, \ 82 struct device_attribute *attr, \
@@ -102,6 +122,7 @@ static struct attribute_group interface_group = {
102 122
103static const struct attribute_group *attr_groups[] = { 123static const struct attribute_group *attr_groups[] = {
104 &format_group, 124 &format_group,
125 &event_group,
105 &interface_group, 126 &interface_group,
106 NULL, 127 NULL,
107}; 128};
@@ -265,6 +286,8 @@ static int hv_gpci_init(void)
265 unsigned long hret; 286 unsigned long hret;
266 struct hv_perf_caps caps; 287 struct hv_perf_caps caps;
267 288
289 hv_gpci_assert_offsets_correct();
290
268 if (!firmware_has_feature(FW_FEATURE_LPAR)) { 291 if (!firmware_has_feature(FW_FEATURE_LPAR)) {
269 pr_debug("not a virtualized system, not enabling\n"); 292 pr_debug("not a virtualized system, not enabling\n");
270 return -ENODEV; 293 return -ENODEV;
diff --git a/arch/powerpc/perf/hv-gpci.h b/arch/powerpc/perf/hv-gpci.h
index b25f460c9cce..86ede8275961 100644
--- a/arch/powerpc/perf/hv-gpci.h
+++ b/arch/powerpc/perf/hv-gpci.h
@@ -42,32 +42,19 @@ struct hv_get_perf_counter_info_params {
42 */ 42 */
43#define COUNTER_INFO_VERSION_CURRENT 0x8 43#define COUNTER_INFO_VERSION_CURRENT 0x8
44 44
45/* 45/* capability mask masks. */
46 * These determine the counter_value[] layout and the meaning of starting_index 46enum {
47 * and secondary_index. 47 HV_GPCI_CM_GA = (1 << 7),
48 * 48 HV_GPCI_CM_EXPANDED = (1 << 6),
49 * Unless otherwise noted, @secondary_index is unused and ignored. 49 HV_GPCI_CM_LAB = (1 << 5)
50 */
51enum counter_info_requests {
52
53 /* GENERAL */
54
55 /* @starting_index: must be -1 (to refer to the current partition)
56 */
57 CIR_SYSTEM_PERFORMANCE_CAPABILITIES = 0X40,
58}; 50};
59 51
60struct cv_system_performance_capabilities { 52#define REQUEST_FILE "../hv-gpci-requests.h"
61 /* If != 0, allowed to collect data from other partitions */ 53#define NAME_LOWER hv_gpci
62 __u8 perf_collect_privileged; 54#define NAME_UPPER HV_GPCI
63 55#include "req-gen/perf.h"
64 /* These following are only valid if counter_info_version >= 0x3 */ 56#undef REQUEST_FILE
65#define CV_CM_GA (1 << 7) 57#undef NAME_LOWER
66#define CV_CM_EXPANDED (1 << 6) 58#undef NAME_UPPER
67#define CV_CM_LAB (1 << 5)
68 /* remaining bits are reserved */
69 __u8 capability_mask;
70 __u8 reserved[0xE];
71} __packed;
72 59
73#endif 60#endif
diff --git a/arch/powerpc/perf/req-gen/_begin.h b/arch/powerpc/perf/req-gen/_begin.h
new file mode 100644
index 000000000000..acfb17a55c16
--- /dev/null
+++ b/arch/powerpc/perf/req-gen/_begin.h
@@ -0,0 +1,13 @@
1/* Include paths to be used in interface defining headers */
2#ifndef POWERPC_PERF_REQ_GEN_H_
3#define POWERPC_PERF_REQ_GEN_H_
4
5#define CAT2_STR_(t, s) __stringify(t/s)
6#define CAT2_STR(t, s) CAT2_STR_(t, s)
7#define I(...) __VA_ARGS__
8
9#endif
10
11#define REQ_GEN_PREFIX req-gen
12#define REQUEST_BEGIN CAT2_STR(REQ_GEN_PREFIX, _request-begin.h)
13#define REQUEST_END CAT2_STR(REQ_GEN_PREFIX, _request-end.h)
diff --git a/arch/powerpc/perf/req-gen/_clear.h b/arch/powerpc/perf/req-gen/_clear.h
new file mode 100644
index 000000000000..422974f89573
--- /dev/null
+++ b/arch/powerpc/perf/req-gen/_clear.h
@@ -0,0 +1,5 @@
1
2#undef __field_
3#undef __count_
4#undef __array_
5#undef REQUEST_
diff --git a/arch/powerpc/perf/req-gen/_end.h b/arch/powerpc/perf/req-gen/_end.h
new file mode 100644
index 000000000000..8a406980b6bf
--- /dev/null
+++ b/arch/powerpc/perf/req-gen/_end.h
@@ -0,0 +1,4 @@
1
2#undef REQ_GEN_PREFIX
3#undef REQUEST_BEGIN
4#undef REQUEST_END
diff --git a/arch/powerpc/perf/req-gen/_request-begin.h b/arch/powerpc/perf/req-gen/_request-begin.h
new file mode 100644
index 000000000000..f6d98642cf1d
--- /dev/null
+++ b/arch/powerpc/perf/req-gen/_request-begin.h
@@ -0,0 +1,15 @@
1
2#define REQUEST(r_contents) \
3 REQUEST_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, I(r_contents))
4
5#define __field(f_offset, f_bytes, f_name) \
6 __field_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \
7 f_offset, f_bytes, f_name)
8
9#define __array(f_offset, f_bytes, f_name) \
10 __array_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \
11 f_offset, f_bytes, f_name)
12
13#define __count(f_offset, f_bytes, f_name) \
14 __count_(REQUEST_NAME, REQUEST_NUM, REQUEST_IDX_KIND, \
15 f_offset, f_bytes, f_name)
diff --git a/arch/powerpc/perf/req-gen/_request-end.h b/arch/powerpc/perf/req-gen/_request-end.h
new file mode 100644
index 000000000000..5573be6c3588
--- /dev/null
+++ b/arch/powerpc/perf/req-gen/_request-end.h
@@ -0,0 +1,8 @@
1#undef REQUEST
2#undef __field
3#undef __array
4#undef __count
5
6#undef REQUEST_NAME
7#undef REQUEST_NUM
8#undef REQUEST_IDX_KIND
diff --git a/arch/powerpc/perf/req-gen/perf.h b/arch/powerpc/perf/req-gen/perf.h
new file mode 100644
index 000000000000..1b122469323d
--- /dev/null
+++ b/arch/powerpc/perf/req-gen/perf.h
@@ -0,0 +1,155 @@
1#ifndef LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
2#define LINUX_POWERPC_PERF_REQ_GEN_PERF_H_
3
4#include <linux/perf_event.h>
5
6#ifndef REQUEST_FILE
7#error "REQUEST_FILE must be defined before including"
8#endif
9
10#ifndef NAME_LOWER
11#error "NAME_LOWER must be defined before including"
12#endif
13
14#ifndef NAME_UPPER
15#error "NAME_UPPER must be defined before including"
16#endif
17
18#define BE_TYPE_b1 __u8
19#define BE_TYPE_b2 __be16
20#define BE_TYPE_b4 __be32
21#define BE_TYPE_b8 __be64
22
23#define BYTES_TO_BE_TYPE(bytes) \
24 BE_TYPE_b##bytes
25
26#define CAT2_(a, b) a ## b
27#define CAT2(a, b) CAT2_(a, b)
28#define CAT3_(a, b, c) a ## b ## c
29#define CAT3(a, b, c) CAT3_(a, b, c)
30
31/*
32 * enumerate the request values as
33 * <NAME_UPPER>_<request name> = <request value>
34 */
35#define REQUEST_VALUE__(name_upper, r_name) name_upper ## _ ## r_name
36#define REQUEST_VALUE_(name_upper, r_name) REQUEST_VALUE__(name_upper, r_name)
37#define REQUEST_VALUE(r_name) REQUEST_VALUE_(NAME_UPPER, r_name)
38
39#include "_clear.h"
40#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
41 REQUEST_VALUE(r_name) = r_value,
42enum CAT2(NAME_LOWER, _requests) {
43#include REQUEST_FILE
44};
45
46/*
47 * For each request:
48 * struct <NAME_LOWER>_<request name> {
49 * r_fields
50 * };
51 */
52#include "_clear.h"
53#define STRUCT_NAME__(name_lower, r_name) name_lower ## _ ## r_name
54#define STRUCT_NAME_(name_lower, r_name) STRUCT_NAME__(name_lower, r_name)
55#define STRUCT_NAME(r_name) STRUCT_NAME_(NAME_LOWER, r_name)
56#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
57struct STRUCT_NAME(r_name) { \
58 r_fields \
59};
60#define __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \
61 BYTES_TO_BE_TYPE(f_bytes) f_name;
62#define __count_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name) \
63 __field_(r_name, r_value, r_idx_1, f_offset, f_bytes, f_name)
64#define __array_(r_name, r_value, r_idx_1, a_offset, a_bytes, a_name) \
65 __u8 a_name[a_bytes];
66
67#include REQUEST_FILE
68
69/*
70 * Generate a check of the field offsets
71 * <NAME_LOWER>_assert_offsets_correct()
72 */
73#include "_clear.h"
74#define REQUEST_(r_name, r_value, index, r_fields) \
75r_fields
76#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name) \
77 BUILD_BUG_ON(offsetof(struct STRUCT_NAME(r_name), f_name) != f_offset);
78#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
79 __field_(r_name, r_value, r_idx_1, c_offset, c_size, c_name)
80#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name) \
81 __field_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
82
83static inline void CAT2(NAME_LOWER, _assert_offsets_correct)(void)
84{
85#include REQUEST_FILE
86}
87
88/*
89 * Generate event attributes:
90 * PMU_EVENT_ATTR_STRING(<request name>_<field name>,
91 * <NAME_LOWER>_event_attr_<request name>_<field name>,
92 * "request=<request value>"
93 * "starting_index=<starting index type>"
94 * "counter_info_version=CURRENT_COUNTER_INFO_VERSION"
95 * "length=<f_size>"
96 * "offset=<f_offset>")
97 *
98 * TODO: counter_info_version may need to vary, we should interperate the
99 * value to some extent
100 */
101#define EVENT_ATTR_NAME__(name, r_name, c_name) \
102 name ## _event_attr_ ## r_name ## _ ## c_name
103#define EVENT_ATTR_NAME_(name, r_name, c_name) \
104 EVENT_ATTR_NAME__(name, r_name, c_name)
105#define EVENT_ATTR_NAME(r_name, c_name) \
106 EVENT_ATTR_NAME_(NAME_LOWER, r_name, c_name)
107
108#include "_clear.h"
109#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name)
110#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
111#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
112PMU_EVENT_ATTR_STRING( \
113 CAT3(r_name, _, c_name), \
114 EVENT_ATTR_NAME(r_name, c_name), \
115 "request=" __stringify(r_value) "," \
116 r_idx_1 "," \
117 "counter_info_version=" \
118 __stringify(COUNTER_INFO_VERSION_CURRENT) "," \
119 "length=" #c_size "," \
120 "offset=" #c_offset)
121#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
122 r_fields
123
124#include REQUEST_FILE
125
126/*
127 * Define event attribute array
128 * static struct attribute *hv_gpci_event_attrs[] = {
129 * &<NAME_LOWER>_event_attr_<request name>_<field name>.attr,
130 * };
131 */
132#include "_clear.h"
133#define __field_(r_name, r_value, r_idx_1, f_offset, f_size, f_name)
134#define __count_(r_name, r_value, r_idx_1, c_offset, c_size, c_name) \
135 &EVENT_ATTR_NAME(r_name, c_name).attr.attr,
136#define __array_(r_name, r_value, r_idx_1, a_offset, a_size, a_name)
137#define REQUEST_(r_name, r_value, r_idx_1, r_fields) \
138 r_fields
139
140static __maybe_unused struct attribute *hv_gpci_event_attrs[] = {
141#include REQUEST_FILE
142 NULL
143};
144
145/* cleanup */
146#include "_clear.h"
147#undef EVENT_ATTR_NAME
148#undef EVENT_ATTR_NAME_
149#undef BIT_NAME
150#undef BIT_NAME_
151#undef STRUCT_NAME
152#undef REQUEST_VALUE
153#undef REQUEST_VALUE_
154
155#endif