1// SPDX-License-Identifier: GPL-2.0+
2//
3// Copyright 2019 Madhavan Srinivasan, IBM Corporation.
4
5#define pr_fmt(fmt)	"generic-compat-pmu: " fmt
6
7#include "isa207-common.h"
8
9/*
10 * Raw event encoding:
11 *
12 *        60        56        52        48        44        40        36        32
13 * | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
14 *
15 *        28        24        20        16        12         8         4         0
16 * | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - | - - - - |
17 *                                 [ pmc ]   [unit ]   [ ]   m   [    pmcxsel    ]
18 *                                                     |     |
19 *                                                     |     *- mark
20 *                                                     |
21 *                                                     |
22 *                                                     *- combine
23 *
24 * Below uses IBM bit numbering.
25 *
26 * MMCR1[x:y] = unit    (PMCxUNIT)
27 * MMCR1[24]   = pmc1combine[0]
28 * MMCR1[25]   = pmc1combine[1]
29 * MMCR1[26]   = pmc2combine[0]
30 * MMCR1[27]   = pmc2combine[1]
31 * MMCR1[28]   = pmc3combine[0]
32 * MMCR1[29]   = pmc3combine[1]
33 * MMCR1[30]   = pmc4combine[0]
34 * MMCR1[31]   = pmc4combine[1]
35 *
36 */
37
38/*
39 * Some power9 event codes.
40 */
41#define EVENT(_name, _code)	_name = _code,
42
43enum {
44EVENT(PM_CYC,					0x0001e)
45EVENT(PM_INST_CMPL,				0x00002)
46};
47
48#undef EVENT
49
50GENERIC_EVENT_ATTR(cpu-cycles,			PM_CYC);
51GENERIC_EVENT_ATTR(instructions,		PM_INST_CMPL);
52
53static struct attribute *generic_compat_events_attr[] = {
54	GENERIC_EVENT_PTR(PM_CYC),
55	GENERIC_EVENT_PTR(PM_INST_CMPL),
56	NULL
57};
58
59static struct attribute_group generic_compat_pmu_events_group = {
60	.name = "events",
61	.attrs = generic_compat_events_attr,
62};
63
64PMU_FORMAT_ATTR(event,		"config:0-19");
65PMU_FORMAT_ATTR(pmcxsel,	"config:0-7");
66PMU_FORMAT_ATTR(mark,		"config:8");
67PMU_FORMAT_ATTR(combine,	"config:10-11");
68PMU_FORMAT_ATTR(unit,		"config:12-15");
69PMU_FORMAT_ATTR(pmc,		"config:16-19");
70
71static struct attribute *generic_compat_pmu_format_attr[] = {
72	&format_attr_event.attr,
73	&format_attr_pmcxsel.attr,
74	&format_attr_mark.attr,
75	&format_attr_combine.attr,
76	&format_attr_unit.attr,
77	&format_attr_pmc.attr,
78	NULL,
79};
80
81static struct attribute_group generic_compat_pmu_format_group = {
82	.name = "format",
83	.attrs = generic_compat_pmu_format_attr,
84};
85
86static const struct attribute_group *generic_compat_pmu_attr_groups[] = {
87	&generic_compat_pmu_format_group,
88	&generic_compat_pmu_events_group,
89	NULL,
90};
91
92static int compat_generic_events[] = {
93	[PERF_COUNT_HW_CPU_CYCLES] =			PM_CYC,
94	[PERF_COUNT_HW_INSTRUCTIONS] =			PM_INST_CMPL,
95};
96
97#define C(x)	PERF_COUNT_HW_CACHE_##x
98
99/*
100 * Table of generalized cache-related events.
101 * 0 means not supported, -1 means nonsensical, other values
102 * are event codes.
103 */
104static u64 generic_compat_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
105	[ C(L1D) ] = {
106		[ C(OP_READ) ] = {
107			[ C(RESULT_ACCESS) ] = 0,
108			[ C(RESULT_MISS)   ] = 0,
109		},
110		[ C(OP_WRITE) ] = {
111			[ C(RESULT_ACCESS) ] = 0,
112			[ C(RESULT_MISS)   ] = 0,
113		},
114		[ C(OP_PREFETCH) ] = {
115			[ C(RESULT_ACCESS) ] = 0,
116			[ C(RESULT_MISS)   ] = 0,
117		},
118	},
119	[ C(L1I) ] = {
120		[ C(OP_READ) ] = {
121			[ C(RESULT_ACCESS) ] = 0,
122			[ C(RESULT_MISS)   ] = 0,
123		},
124		[ C(OP_WRITE) ] = {
125			[ C(RESULT_ACCESS) ] = 0,
126			[ C(RESULT_MISS)   ] = -1,
127		},
128		[ C(OP_PREFETCH) ] = {
129			[ C(RESULT_ACCESS) ] = 0,
130			[ C(RESULT_MISS)   ] = 0,
131		},
132	},
133	[ C(LL) ] = {
134		[ C(OP_READ) ] = {
135			[ C(RESULT_ACCESS) ] = 0,
136			[ C(RESULT_MISS)   ] = 0,
137		},
138		[ C(OP_WRITE) ] = {
139			[ C(RESULT_ACCESS) ] = 0,
140			[ C(RESULT_MISS)   ] = 0,
141		},
142		[ C(OP_PREFETCH) ] = {
143			[ C(RESULT_ACCESS) ] = 0,
144			[ C(RESULT_MISS)   ] = 0,
145		},
146	},
147	[ C(DTLB) ] = {
148		[ C(OP_READ) ] = {
149			[ C(RESULT_ACCESS) ] = 0,
150			[ C(RESULT_MISS)   ] = 0,
151		},
152		[ C(OP_WRITE) ] = {
153			[ C(RESULT_ACCESS) ] = -1,
154			[ C(RESULT_MISS)   ] = -1,
155		},
156		[ C(OP_PREFETCH) ] = {
157			[ C(RESULT_ACCESS) ] = -1,
158			[ C(RESULT_MISS)   ] = -1,
159		},
160	},
161	[ C(ITLB) ] = {
162		[ C(OP_READ) ] = {
163			[ C(RESULT_ACCESS) ] = 0,
164			[ C(RESULT_MISS)   ] = 0,
165		},
166		[ C(OP_WRITE) ] = {
167			[ C(RESULT_ACCESS) ] = -1,
168			[ C(RESULT_MISS)   ] = -1,
169		},
170		[ C(OP_PREFETCH) ] = {
171			[ C(RESULT_ACCESS) ] = -1,
172			[ C(RESULT_MISS)   ] = -1,
173		},
174	},
175	[ C(BPU) ] = {
176		[ C(OP_READ) ] = {
177			[ C(RESULT_ACCESS) ] = 0,
178			[ C(RESULT_MISS)   ] = 0,
179		},
180		[ C(OP_WRITE) ] = {
181			[ C(RESULT_ACCESS) ] = -1,
182			[ C(RESULT_MISS)   ] = -1,
183		},
184		[ C(OP_PREFETCH) ] = {
185			[ C(RESULT_ACCESS) ] = -1,
186			[ C(RESULT_MISS)   ] = -1,
187		},
188	},
189	[ C(NODE) ] = {
190		[ C(OP_READ) ] = {
191			[ C(RESULT_ACCESS) ] = -1,
192			[ C(RESULT_MISS)   ] = -1,
193		},
194		[ C(OP_WRITE) ] = {
195			[ C(RESULT_ACCESS) ] = -1,
196			[ C(RESULT_MISS)   ] = -1,
197		},
198		[ C(OP_PREFETCH) ] = {
199			[ C(RESULT_ACCESS) ] = -1,
200			[ C(RESULT_MISS)   ] = -1,
201		},
202	},
203};
204
205#undef C
206
207static struct power_pmu generic_compat_pmu = {
208	.name			= "GENERIC_COMPAT",
209	.n_counter		= MAX_PMU_COUNTERS,
210	.add_fields		= ISA207_ADD_FIELDS,
211	.test_adder		= ISA207_TEST_ADDER,
212	.compute_mmcr		= isa207_compute_mmcr,
213	.get_constraint		= isa207_get_constraint,
214	.disable_pmc		= isa207_disable_pmc,
215	.flags			= PPMU_HAS_SIER | PPMU_ARCH_207S,
216	.n_generic		= ARRAY_SIZE(compat_generic_events),
217	.generic_events		= compat_generic_events,
218	.cache_events		= &generic_compat_cache_events,
219	.attr_groups		= generic_compat_pmu_attr_groups,
220};
221
222int init_generic_compat_pmu(void)
223{
224	int rc = 0;
225
226	rc = register_power_pmu(&generic_compat_pmu);
227	if (rc)
228		return rc;
229
230	/* Tell userspace that EBB is supported */
231	cur_cpu_spec->cpu_user_features2 |= PPC_FEATURE2_EBB;
232
233	return 0;
234}
235