xref: /linux/drivers/platform/mellanox/mlxbf-pmc.c (revision 1193e205dbb6feca917dc8e1862ffcdf2194234b)
1 // SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB
2 /*
3  * Mellanox BlueField Performance Monitoring Counters driver
4  *
5  * This driver provides a sysfs interface for monitoring
6  * performance statistics in BlueField SoC.
7  *
8  * Copyright (c) 2020, NVIDIA CORPORATION.  All rights reserved.
9  */
10 
11 #include <linux/acpi.h>
12 #include <linux/arm-smccc.h>
13 #include <linux/bitfield.h>
14 #include <linux/errno.h>
15 #include <linux/hwmon.h>
16 #include <linux/platform_device.h>
17 #include <linux/string.h>
18 #include <uapi/linux/psci.h>
19 
20 #define MLXBF_PMC_WRITE_REG_32 0x82000009
21 #define MLXBF_PMC_READ_REG_32 0x8200000A
22 #define MLXBF_PMC_WRITE_REG_64 0x8200000B
23 #define MLXBF_PMC_READ_REG_64 0x8200000C
24 #define MLXBF_PMC_SIP_SVC_UID 0x8200ff01
25 #define MLXBF_PMC_SIP_SVC_VERSION 0x8200ff03
26 #define MLXBF_PMC_SVC_REQ_MAJOR 0
27 #define MLXBF_PMC_SVC_MIN_MINOR 3
28 
29 #define MLXBF_PMC_SMCCC_ACCESS_VIOLATION -4
30 
31 #define MLXBF_PMC_EVENT_SET_BF1 0
32 #define MLXBF_PMC_EVENT_SET_BF2 1
33 #define MLXBF_PMC_EVENT_SET_BF3 2
34 #define MLXBF_PMC_EVENT_INFO_LEN 100
35 
36 #define MLXBF_PMC_MAX_BLOCKS 40
37 #define MLXBF_PMC_MAX_ATTRS 70
38 #define MLXBF_PMC_INFO_SZ 4
39 #define MLXBF_PMC_REG_SIZE 8
40 #define MLXBF_PMC_L3C_REG_SIZE 4
41 
42 #define MLXBF_PMC_TYPE_CRSPACE 2
43 #define MLXBF_PMC_TYPE_COUNTER 1
44 #define MLXBF_PMC_TYPE_REGISTER 0
45 
46 #define MLXBF_PMC_PERFCTL 0
47 #define MLXBF_PMC_PERFEVT 1
48 #define MLXBF_PMC_PERFACC0 4
49 
50 #define MLXBF_PMC_PERFMON_CONFIG_WR_R_B BIT(0)
51 #define MLXBF_PMC_PERFMON_CONFIG_STROBE BIT(1)
52 #define MLXBF_PMC_PERFMON_CONFIG_ADDR GENMASK_ULL(4, 2)
53 #define MLXBF_PMC_PERFMON_CONFIG_WDATA GENMASK_ULL(60, 5)
54 
55 #define MLXBF_PMC_PERFCTL_FM0 GENMASK_ULL(18, 16)
56 #define MLXBF_PMC_PERFCTL_MS0 GENMASK_ULL(21, 20)
57 #define MLXBF_PMC_PERFCTL_ACCM0 GENMASK_ULL(26, 24)
58 #define MLXBF_PMC_PERFCTL_AD0 BIT(27)
59 #define MLXBF_PMC_PERFCTL_ETRIG0 GENMASK_ULL(29, 28)
60 #define MLXBF_PMC_PERFCTL_EB0 BIT(30)
61 #define MLXBF_PMC_PERFCTL_EN0 BIT(31)
62 
63 #define MLXBF_PMC_PERFEVT_EVTSEL GENMASK_ULL(31, 24)
64 
65 #define MLXBF_PMC_L3C_PERF_CNT_CFG 0x0
66 #define MLXBF_PMC_L3C_PERF_CNT_SEL 0x10
67 #define MLXBF_PMC_L3C_PERF_CNT_SEL_1 0x14
68 #define MLXBF_PMC_L3C_PERF_CNT_LOW 0x40
69 #define MLXBF_PMC_L3C_PERF_CNT_HIGH 0x60
70 
71 #define MLXBF_PMC_L3C_PERF_CNT_CFG_EN BIT(0)
72 #define MLXBF_PMC_L3C_PERF_CNT_CFG_RST BIT(1)
73 #define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0 GENMASK(5, 0)
74 #define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1 GENMASK(13, 8)
75 #define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2 GENMASK(21, 16)
76 #define MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3 GENMASK(29, 24)
77 
78 #define MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4 GENMASK(5, 0)
79 
80 #define MLXBF_PMC_L3C_PERF_CNT_LOW_VAL GENMASK(31, 0)
81 #define MLXBF_PMC_L3C_PERF_CNT_HIGH_VAL GENMASK(24, 0)
82 
83 #define MLXBF_PMC_CRSPACE_PERFMON_REG0 0x0
84 #define MLXBF_PMC_CRSPACE_PERFSEL_SZ 4
85 #define MLXBF_PMC_CRSPACE_PERFSEL0 GENMASK(23, 16)
86 #define MLXBF_PMC_CRSPACE_PERFSEL1 GENMASK(7, 0)
87 #define MLXBF_PMC_CRSPACE_PERFMON_REG0_SZ 0x2
88 #define MLXBF_PMC_CRSPACE_PERFMON_CTL(n) (n * MLXBF_PMC_CRSPACE_PERFMON_REG0_SZ)
89 #define MLXBF_PMC_CRSPACE_PERFMON_EN BIT(30)
90 #define MLXBF_PMC_CRSPACE_PERFMON_CLR BIT(28)
91 #define MLXBF_PMC_CRSPACE_PERFMON_COUNT_CLOCK(n) (MLXBF_PMC_CRSPACE_PERFMON_CTL(n) + 0x4)
92 #define MLXBF_PMC_CRSPACE_PERFMON_VAL0(n) (MLXBF_PMC_CRSPACE_PERFMON_CTL(n) + 0xc)
93 
94 /**
95  * struct mlxbf_pmc_attribute - Structure to hold attribute and block info
96  * for each sysfs entry
97  * @dev_attr: Device attribute struct
98  * @index: index to identify counter number within a block
99  * @nr: block number to which the sysfs belongs
100  */
101 struct mlxbf_pmc_attribute {
102 	struct device_attribute dev_attr;
103 	unsigned int index;
104 	unsigned int nr;
105 };
106 
107 /**
108  * struct mlxbf_pmc_block_info - Structure to hold info for each HW block
109  *
110  * @mmio_base: The VA at which the PMC block is mapped
111  * @blk_size: Size of each mapped region
112  * @counters: Number of counters in the block
113  * @type: Type of counters in the block
114  * @attr_counter: Attributes for "counter" sysfs files
115  * @attr_event: Attributes for "event" sysfs files
116  * @attr_event_list: Attributes for "event_list" sysfs files
117  * @attr_enable: Attributes for "enable" sysfs files
118  * @attr_count_clock: Attributes for "count_clock" sysfs files
119  * @block_attr: All attributes needed for the block
120  * @block_attr_grp: Attribute group for the block
121  */
122 struct mlxbf_pmc_block_info {
123 	void __iomem *mmio_base;
124 	size_t blk_size;
125 	size_t counters;
126 	unsigned int type;
127 	struct mlxbf_pmc_attribute *attr_counter;
128 	struct mlxbf_pmc_attribute *attr_event;
129 	struct mlxbf_pmc_attribute attr_event_list;
130 	struct mlxbf_pmc_attribute attr_enable;
131 	struct mlxbf_pmc_attribute attr_count_clock;
132 	struct attribute *block_attr[MLXBF_PMC_MAX_ATTRS];
133 	struct attribute_group block_attr_grp;
134 };
135 
136 /**
137  * struct mlxbf_pmc_context - Structure to hold PMC context info
138  *
139  * @pdev: The kernel structure representing the device
140  * @total_blocks: Total number of blocks
141  * @tile_count: Number of tiles in the system
142  * @apt_enable: Info on enabled APTs
143  * @llt_enable: Info on enabled LLTs
144  * @mss_enable: Info on enabled MSSs
145  * @group_num: Group number assigned to each valid block
146  * @hwmon_dev: Hwmon device for bfperf
147  * @block_name: Block name
148  * @block:  Block info
149  * @groups:  Attribute groups from each block
150  * @svc_sreg_support: Whether SMCs are used to access performance registers
151  * @sreg_tbl_perf: Secure register access table number
152  * @event_set: Event set to use
153  */
154 struct mlxbf_pmc_context {
155 	struct platform_device *pdev;
156 	u32 total_blocks;
157 	u32 tile_count;
158 	u8 apt_enable;
159 	u8 llt_enable;
160 	u8 mss_enable;
161 	u32 group_num;
162 	struct device *hwmon_dev;
163 	const char *block_name[MLXBF_PMC_MAX_BLOCKS];
164 	struct mlxbf_pmc_block_info block[MLXBF_PMC_MAX_BLOCKS];
165 	const struct attribute_group *groups[MLXBF_PMC_MAX_BLOCKS];
166 	bool svc_sreg_support;
167 	u32 sreg_tbl_perf;
168 	unsigned int event_set;
169 };
170 
171 /**
172  * struct mlxbf_pmc_events - Structure to hold supported events for each block
173  * @evt_num: Event number used to program counters
174  * @evt_name: Name of the event
175  */
176 struct mlxbf_pmc_events {
177 	u32 evt_num;
178 	char *evt_name;
179 };
180 
181 static const struct mlxbf_pmc_events mlxbf_pmc_pcie_events[] = {
182 	{ 0x0, "IN_P_PKT_CNT" },
183 	{ 0x10, "IN_NP_PKT_CNT" },
184 	{ 0x18, "IN_C_PKT_CNT" },
185 	{ 0x20, "OUT_P_PKT_CNT" },
186 	{ 0x28, "OUT_NP_PKT_CNT" },
187 	{ 0x30, "OUT_C_PKT_CNT" },
188 	{ 0x38, "IN_P_BYTE_CNT" },
189 	{ 0x40, "IN_NP_BYTE_CNT" },
190 	{ 0x48, "IN_C_BYTE_CNT" },
191 	{ 0x50, "OUT_P_BYTE_CNT" },
192 	{ 0x58, "OUT_NP_BYTE_CNT" },
193 	{ 0x60, "OUT_C_BYTE_CNT" },
194 };
195 
196 static const struct mlxbf_pmc_events mlxbf_pmc_smgen_events[] = {
197 	{ 0x0, "AW_REQ" },
198 	{ 0x1, "AW_BEATS" },
199 	{ 0x2, "AW_TRANS" },
200 	{ 0x3, "AW_RESP" },
201 	{ 0x4, "AW_STL" },
202 	{ 0x5, "AW_LAT" },
203 	{ 0x6, "AW_REQ_TBU" },
204 	{ 0x8, "AR_REQ" },
205 	{ 0x9, "AR_BEATS" },
206 	{ 0xa, "AR_TRANS" },
207 	{ 0xb, "AR_STL" },
208 	{ 0xc, "AR_LAT" },
209 	{ 0xd, "AR_REQ_TBU" },
210 	{ 0xe, "TBU_MISS" },
211 	{ 0xf, "TX_DAT_AF" },
212 	{ 0x10, "RX_DAT_AF" },
213 	{ 0x11, "RETRYQ_CRED" },
214 };
215 
216 static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_1[] = {
217 	{ 0x0, "DISABLE" },
218 	{ 0xa0, "TPIO_DATA_BEAT" },
219 	{ 0xa1, "TDMA_DATA_BEAT" },
220 	{ 0xa2, "MAP_DATA_BEAT" },
221 	{ 0xa3, "TXMSG_DATA_BEAT" },
222 	{ 0xa4, "TPIO_DATA_PACKET" },
223 	{ 0xa5, "TDMA_DATA_PACKET" },
224 	{ 0xa6, "MAP_DATA_PACKET" },
225 	{ 0xa7, "TXMSG_DATA_PACKET" },
226 	{ 0xa8, "TDMA_RT_AF" },
227 	{ 0xa9, "TDMA_PBUF_MAC_AF" },
228 	{ 0xaa, "TRIO_MAP_WRQ_BUF_EMPTY" },
229 	{ 0xab, "TRIO_MAP_CPL_BUF_EMPTY" },
230 	{ 0xac, "TRIO_MAP_RDQ0_BUF_EMPTY" },
231 	{ 0xad, "TRIO_MAP_RDQ1_BUF_EMPTY" },
232 	{ 0xae, "TRIO_MAP_RDQ2_BUF_EMPTY" },
233 	{ 0xaf, "TRIO_MAP_RDQ3_BUF_EMPTY" },
234 	{ 0xb0, "TRIO_MAP_RDQ4_BUF_EMPTY" },
235 	{ 0xb1, "TRIO_MAP_RDQ5_BUF_EMPTY" },
236 	{ 0xb2, "TRIO_MAP_RDQ6_BUF_EMPTY" },
237 	{ 0xb3, "TRIO_MAP_RDQ7_BUF_EMPTY" },
238 };
239 
240 static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_2[] = {
241 	{ 0x0, "DISABLE" },
242 	{ 0xa0, "TPIO_DATA_BEAT" },
243 	{ 0xa1, "TDMA_DATA_BEAT" },
244 	{ 0xa2, "MAP_DATA_BEAT" },
245 	{ 0xa3, "TXMSG_DATA_BEAT" },
246 	{ 0xa4, "TPIO_DATA_PACKET" },
247 	{ 0xa5, "TDMA_DATA_PACKET" },
248 	{ 0xa6, "MAP_DATA_PACKET" },
249 	{ 0xa7, "TXMSG_DATA_PACKET" },
250 	{ 0xa8, "TDMA_RT_AF" },
251 	{ 0xa9, "TDMA_PBUF_MAC_AF" },
252 	{ 0xaa, "TRIO_MAP_WRQ_BUF_EMPTY" },
253 	{ 0xab, "TRIO_MAP_CPL_BUF_EMPTY" },
254 	{ 0xac, "TRIO_MAP_RDQ0_BUF_EMPTY" },
255 	{ 0xad, "TRIO_MAP_RDQ1_BUF_EMPTY" },
256 	{ 0xae, "TRIO_MAP_RDQ2_BUF_EMPTY" },
257 	{ 0xaf, "TRIO_MAP_RDQ3_BUF_EMPTY" },
258 	{ 0xb0, "TRIO_MAP_RDQ4_BUF_EMPTY" },
259 	{ 0xb1, "TRIO_MAP_RDQ5_BUF_EMPTY" },
260 	{ 0xb2, "TRIO_MAP_RDQ6_BUF_EMPTY" },
261 	{ 0xb3, "TRIO_MAP_RDQ7_BUF_EMPTY" },
262 	{ 0xb4, "TRIO_RING_TX_FLIT_CH0" },
263 	{ 0xb5, "TRIO_RING_TX_FLIT_CH1" },
264 	{ 0xb6, "TRIO_RING_TX_FLIT_CH2" },
265 	{ 0xb7, "TRIO_RING_TX_FLIT_CH3" },
266 	{ 0xb8, "TRIO_RING_TX_FLIT_CH4" },
267 	{ 0xb9, "TRIO_RING_RX_FLIT_CH0" },
268 	{ 0xba, "TRIO_RING_RX_FLIT_CH1" },
269 	{ 0xbb, "TRIO_RING_RX_FLIT_CH2" },
270 	{ 0xbc, "TRIO_RING_RX_FLIT_CH3" },
271 };
272 
273 static const struct mlxbf_pmc_events mlxbf_pmc_ecc_events[] = {
274 	{ 0x0, "DISABLE" },
275 	{ 0x100, "ECC_SINGLE_ERROR_CNT" },
276 	{ 0x104, "ECC_DOUBLE_ERROR_CNT" },
277 	{ 0x114, "SERR_INJ" },
278 	{ 0x118, "DERR_INJ" },
279 	{ 0x124, "ECC_SINGLE_ERROR_0" },
280 	{ 0x164, "ECC_DOUBLE_ERROR_0" },
281 	{ 0x340, "DRAM_ECC_COUNT" },
282 	{ 0x344, "DRAM_ECC_INJECT" },
283 	{ 0x348, "DRAM_ECC_ERROR" },
284 };
285 
286 static const struct mlxbf_pmc_events mlxbf_pmc_mss_events_1[] = {
287 	{ 0x0, "DISABLE" },
288 	{ 0xc0, "RXREQ_MSS" },
289 	{ 0xc1, "RXDAT_MSS" },
290 	{ 0xc2, "TXRSP_MSS" },
291 	{ 0xc3, "TXDAT_MSS" },
292 };
293 
294 static const struct mlxbf_pmc_events mlxbf_pmc_mss_events_3[] = {
295 	{0, "SKYLIB_CDN_TX_FLITS"},
296 	{1, "SKYLIB_DDN_TX_FLITS"},
297 	{2, "SKYLIB_NDN_TX_FLITS"},
298 	{3, "SKYLIB_SDN_TX_FLITS"},
299 	{4, "SKYLIB_UDN_TX_FLITS"},
300 	{5, "SKYLIB_CDN_RX_FLITS"},
301 	{6, "SKYLIB_DDN_RX_FLITS"},
302 	{7, "SKYLIB_NDN_RX_FLITS"},
303 	{8, "SKYLIB_SDN_RX_FLITS"},
304 	{9, "SKYLIB_UDN_RX_FLITS"},
305 	{10, "SKYLIB_CDN_TX_STALL"},
306 	{11, "SKYLIB_DDN_TX_STALL"},
307 	{12, "SKYLIB_NDN_TX_STALL"},
308 	{13, "SKYLIB_SDN_TX_STALL"},
309 	{14, "SKYLIB_UDN_TX_STALL"},
310 	{15, "SKYLIB_CDN_RX_STALL"},
311 	{16, "SKYLIB_DDN_RX_STALL"},
312 	{17, "SKYLIB_NDN_RX_STALL"},
313 	{18, "SKYLIB_SDN_RX_STALL"},
314 	{19, "SKYLIB_UDN_RX_STALL"},
315 	{20, "SKYLIB_CHI_REQ0_TX_FLITS"},
316 	{21, "SKYLIB_CHI_DATA0_TX_FLITS"},
317 	{22, "SKYLIB_CHI_RESP0_TX_FLITS"},
318 	{23, "SKYLIB_CHI_SNP0_TX_FLITS"},
319 	{24, "SKYLIB_CHI_REQ1_TX_FLITS"},
320 	{25, "SKYLIB_CHI_DATA1_TX_FLITS"},
321 	{26, "SKYLIB_CHI_RESP1_TX_FLITS"},
322 	{27, "SKYLIB_CHI_SNP1_TX_FLITS"},
323 	{28, "SKYLIB_CHI_REQ2_TX_FLITS"},
324 	{29, "SKYLIB_CHI_DATA2_TX_FLITS"},
325 	{30, "SKYLIB_CHI_RESP2_TX_FLITS"},
326 	{31, "SKYLIB_CHI_SNP2_TX_FLITS"},
327 	{32, "SKYLIB_CHI_REQ3_TX_FLITS"},
328 	{33, "SKYLIB_CHI_DATA3_TX_FLITS"},
329 	{34, "SKYLIB_CHI_RESP3_TX_FLITS"},
330 	{35, "SKYLIB_CHI_SNP3_TX_FLITS"},
331 	{36, "SKYLIB_TLP_REQ_TX_FLITS"},
332 	{37, "SKYLIB_TLP_RESP_TX_FLITS"},
333 	{38, "SKYLIB_TLP_META_TX_FLITS"},
334 	{39, "SKYLIB_AXIS_DATA_TX_FLITS"},
335 	{40, "SKYLIB_AXIS_CRED_TX_FLITS"},
336 	{41, "SKYLIB_APB_TX_FLITS"},
337 	{42, "SKYLIB_VW_TX_FLITS"},
338 	{43, "SKYLIB_GGA_MSN_W_TX_FLITS"},
339 	{44, "SKYLIB_GGA_MSN_N_TX_FLITS"},
340 	{45, "SKYLIB_CR_REQ_TX_FLITS"},
341 	{46, "SKYLIB_CR_RESP_TX_FLITS"},
342 	{47, "SKYLIB_MSN_PRNF_TX_FLITS"},
343 	{48, "SKYLIB_DBG_DATA_TX_FLITS"},
344 	{49, "SKYLIB_DBG_CRED_TX_FLITS"},
345 	{50, "SKYLIB_CHI_REQ0_RX_FLITS"},
346 	{51, "SKYLIB_CHI_DATA0_RX_FLITS"},
347 	{52, "SKYLIB_CHI_RESP0_RX_FLITS"},
348 	{53, "SKYLIB_CHI_SNP0_RX_FLITS"},
349 	{54, "SKYLIB_CHI_REQ1_RX_FLITS"},
350 	{55, "SKYLIB_CHI_DATA1_RX_FLITS"},
351 	{56, "SKYLIB_CHI_RESP1_RX_FLITS"},
352 	{57, "SKYLIB_CHI_SNP1_RX_FLITS"},
353 	{58, "SKYLIB_CHI_REQ2_RX_FLITS"},
354 	{59, "SKYLIB_CHI_DATA2_RX_FLITS"},
355 	{60, "SKYLIB_CHI_RESP2_RX_FLITS"},
356 	{61, "SKYLIB_CHI_SNP2_RX_FLITS"},
357 	{62, "SKYLIB_CHI_REQ3_RX_FLITS"},
358 	{63, "SKYLIB_CHI_DATA3_RX_FLITS"},
359 	{64, "SKYLIB_CHI_RESP3_RX_FLITS"},
360 	{65, "SKYLIB_CHI_SNP3_RX_FLITS"},
361 	{66, "SKYLIB_TLP_REQ_RX_FLITS"},
362 	{67, "SKYLIB_TLP_RESP_RX_FLITS"},
363 	{68, "SKYLIB_TLP_META_RX_FLITS"},
364 	{69, "SKYLIB_AXIS_DATA_RX_FLITS"},
365 	{70, "SKYLIB_AXIS_CRED_RX_FLITS"},
366 	{71, "SKYLIB_APB_RX_FLITS"},
367 	{72, "SKYLIB_VW_RX_FLITS"},
368 	{73, "SKYLIB_GGA_MSN_W_RX_FLITS"},
369 	{74, "SKYLIB_GGA_MSN_N_RX_FLITS"},
370 	{75, "SKYLIB_CR_REQ_RX_FLITS"},
371 	{76, "SKYLIB_CR_RESP_RX_FLITS"},
372 	{77, "SKYLIB_MSN_PRNF_RX_FLITS"},
373 	{78, "SKYLIB_DBG_DATA_RX_FLITS"},
374 	{79, "SKYLIB_DBG_CRED_RX_FLITS"},
375 	{80, "SKYLIB_CHI_REQ0_TX_STALL"},
376 	{81, "SKYLIB_CHI_DATA0_TX_STALL"},
377 	{82, "SKYLIB_CHI_RESP0_TX_STALL"},
378 	{83, "SKYLIB_CHI_SNP0_TX_STALL"},
379 	{84, "SKYLIB_CHI_REQ1_TX_STALL"},
380 	{85, "SKYLIB_CHI_DATA1_TX_STALL"},
381 	{86, "SKYLIB_CHI_RESP1_TX_STALL"},
382 	{87, "SKYLIB_CHI_SNP1_TX_STALL"},
383 	{88, "SKYLIB_CHI_REQ2_TX_STALL"},
384 	{89, "SKYLIB_CHI_DATA2_TX_STALL"},
385 	{90, "SKYLIB_CHI_RESP2_TX_STALL"},
386 	{91, "SKYLIB_CHI_SNP2_TX_STALL"},
387 	{92, "SKYLIB_CHI_REQ3_TX_STALL"},
388 	{93, "SKYLIB_CHI_DATA3_TX_STALL"},
389 	{94, "SKYLIB_CHI_RESP3_TX_STALL"},
390 	{95, "SKYLIB_CHI_SNP3_TX_STALL"},
391 	{96, "SKYLIB_TLP_REQ_TX_STALL"},
392 	{97, "SKYLIB_TLP_RESP_TX_STALL"},
393 	{98, "SKYLIB_TLP_META_TX_STALL"},
394 	{99, "SKYLIB_AXIS_DATA_TX_STALL"},
395 	{100, "SKYLIB_AXIS_CRED_TX_STALL"},
396 	{101, "SKYLIB_APB_TX_STALL"},
397 	{102, "SKYLIB_VW_TX_STALL"},
398 	{103, "SKYLIB_GGA_MSN_W_TX_STALL"},
399 	{104, "SKYLIB_GGA_MSN_N_TX_STALL"},
400 	{105, "SKYLIB_CR_REQ_TX_STALL"},
401 	{106, "SKYLIB_CR_RESP_TX_STALL"},
402 	{107, "SKYLIB_MSN_PRNF_TX_STALL"},
403 	{108, "SKYLIB_DBG_DATA_TX_STALL"},
404 	{109, "SKYLIB_DBG_CRED_TX_STALL"},
405 	{110, "SKYLIB_CHI_REQ0_RX_STALL"},
406 	{111, "SKYLIB_CHI_DATA0_RX_STALL"},
407 	{112, "SKYLIB_CHI_RESP0_RX_STALL"},
408 	{113, "SKYLIB_CHI_SNP0_RX_STALL"},
409 	{114, "SKYLIB_CHI_REQ1_RX_STALL"},
410 	{115, "SKYLIB_CHI_DATA1_RX_STALL"},
411 	{116, "SKYLIB_CHI_RESP1_RX_STALL"},
412 	{117, "SKYLIB_CHI_SNP1_RX_STALL"},
413 	{118, "SKYLIB_CHI_REQ2_RX_STALL"},
414 	{119, "SKYLIB_CHI_DATA2_RX_STALL"},
415 	{120, "SKYLIB_CHI_RESP2_RX_STALL"},
416 	{121, "SKYLIB_CHI_SNP2_RX_STALL"},
417 	{122, "SKYLIB_CHI_REQ3_RX_STALL"},
418 	{123, "SKYLIB_CHI_DATA3_RX_STALL"},
419 	{124, "SKYLIB_CHI_RESP3_RX_STALL"},
420 	{125, "SKYLIB_CHI_SNP3_RX_STALL"},
421 	{126, "SKYLIB_TLP_REQ_RX_STALL"},
422 	{127, "SKYLIB_TLP_RESP_RX_STALL"},
423 	{128, "SKYLIB_TLP_META_RX_STALL"},
424 	{129, "SKYLIB_AXIS_DATA_RX_STALL"},
425 	{130, "SKYLIB_AXIS_CRED_RX_STALL"},
426 	{131, "SKYLIB_APB_RX_STALL"},
427 	{132, "SKYLIB_VW_RX_STALL"},
428 	{133, "SKYLIB_GGA_MSN_W_RX_STALL"},
429 	{134, "SKYLIB_GGA_MSN_N_RX_STALL"},
430 	{135, "SKYLIB_CR_REQ_RX_STALL"},
431 	{136, "SKYLIB_CR_RESP_RX_STALL"},
432 	{137, "SKYLIB_MSN_PRNF_RX_STALL"},
433 	{138, "SKYLIB_DBG_DATA_RX_STALL"},
434 	{139, "SKYLIB_DBG_CRED_RX_STALL"},
435 	{140, "SKYLIB_CDN_LOOPBACK_FLITS"},
436 	{141, "SKYLIB_DDN_LOOPBACK_FLITS"},
437 	{142, "SKYLIB_NDN_LOOPBACK_FLITS"},
438 	{143, "SKYLIB_SDN_LOOPBACK_FLITS"},
439 	{144, "SKYLIB_UDN_LOOPBACK_FLITS"},
440 	{145, "HISTOGRAM_HISTOGRAM_BIN0"},
441 	{146, "HISTOGRAM_HISTOGRAM_BIN1"},
442 	{147, "HISTOGRAM_HISTOGRAM_BIN2"},
443 	{148, "HISTOGRAM_HISTOGRAM_BIN3"},
444 	{149, "HISTOGRAM_HISTOGRAM_BIN4"},
445 	{150, "HISTOGRAM_HISTOGRAM_BIN5"},
446 	{151, "HISTOGRAM_HISTOGRAM_BIN6"},
447 	{152, "HISTOGRAM_HISTOGRAM_BIN7"},
448 	{153, "HISTOGRAM_HISTOGRAM_BIN8"},
449 	{154, "HISTOGRAM_HISTOGRAM_BIN9"},
450 };
451 
452 static const struct mlxbf_pmc_events mlxbf_pmc_hnf_events[] = {
453 	{ 0x0, "DISABLE" },
454 	{ 0x45, "HNF_REQUESTS" },
455 	{ 0x46, "HNF_REJECTS" },
456 	{ 0x47, "ALL_BUSY" },
457 	{ 0x48, "MAF_BUSY" },
458 	{ 0x49, "MAF_REQUESTS" },
459 	{ 0x4a, "RNF_REQUESTS" },
460 	{ 0x4b, "REQUEST_TYPE" },
461 	{ 0x4c, "MEMORY_READS" },
462 	{ 0x4d, "MEMORY_WRITES" },
463 	{ 0x4e, "VICTIM_WRITE" },
464 	{ 0x4f, "POC_FULL" },
465 	{ 0x50, "POC_FAIL" },
466 	{ 0x51, "POC_SUCCESS" },
467 	{ 0x52, "POC_WRITES" },
468 	{ 0x53, "POC_READS" },
469 	{ 0x54, "FORWARD" },
470 	{ 0x55, "RXREQ_HNF" },
471 	{ 0x56, "RXRSP_HNF" },
472 	{ 0x57, "RXDAT_HNF" },
473 	{ 0x58, "TXREQ_HNF" },
474 	{ 0x59, "TXRSP_HNF" },
475 	{ 0x5a, "TXDAT_HNF" },
476 	{ 0x5b, "TXSNP_HNF" },
477 	{ 0x5c, "INDEX_MATCH" },
478 	{ 0x5d, "A72_ACCESS" },
479 	{ 0x5e, "IO_ACCESS" },
480 	{ 0x5f, "TSO_WRITE" },
481 	{ 0x60, "TSO_CONFLICT" },
482 	{ 0x61, "DIR_HIT" },
483 	{ 0x62, "HNF_ACCEPTS" },
484 	{ 0x63, "REQ_BUF_EMPTY" },
485 	{ 0x64, "REQ_BUF_IDLE_MAF" },
486 	{ 0x65, "TSO_NOARB" },
487 	{ 0x66, "TSO_NOARB_CYCLES" },
488 	{ 0x67, "MSS_NO_CREDIT" },
489 	{ 0x68, "TXDAT_NO_LCRD" },
490 	{ 0x69, "TXSNP_NO_LCRD" },
491 	{ 0x6a, "TXRSP_NO_LCRD" },
492 	{ 0x6b, "TXREQ_NO_LCRD" },
493 	{ 0x6c, "TSO_CL_MATCH" },
494 	{ 0x6d, "MEMORY_READS_BYPASS" },
495 	{ 0x6e, "TSO_NOARB_TIMEOUT" },
496 	{ 0x6f, "ALLOCATE" },
497 	{ 0x70, "VICTIM" },
498 	{ 0x71, "A72_WRITE" },
499 	{ 0x72, "A72_READ" },
500 	{ 0x73, "IO_WRITE" },
501 	{ 0x74, "IO_READ" },
502 	{ 0x75, "TSO_REJECT" },
503 	{ 0x80, "TXREQ_RN" },
504 	{ 0x81, "TXRSP_RN" },
505 	{ 0x82, "TXDAT_RN" },
506 	{ 0x83, "RXSNP_RN" },
507 	{ 0x84, "RXRSP_RN" },
508 	{ 0x85, "RXDAT_RN" },
509 };
510 
511 static const struct mlxbf_pmc_events mlxbf_pmc_hnfnet_events[] = {
512 	{ 0x0, "DISABLE" },
513 	{ 0x12, "CDN_REQ" },
514 	{ 0x13, "DDN_REQ" },
515 	{ 0x14, "NDN_REQ" },
516 	{ 0x15, "CDN_DIAG_N_OUT_OF_CRED" },
517 	{ 0x16, "CDN_DIAG_S_OUT_OF_CRED" },
518 	{ 0x17, "CDN_DIAG_E_OUT_OF_CRED" },
519 	{ 0x18, "CDN_DIAG_W_OUT_OF_CRED" },
520 	{ 0x19, "CDN_DIAG_C_OUT_OF_CRED" },
521 	{ 0x1a, "CDN_DIAG_N_EGRESS" },
522 	{ 0x1b, "CDN_DIAG_S_EGRESS" },
523 	{ 0x1c, "CDN_DIAG_E_EGRESS" },
524 	{ 0x1d, "CDN_DIAG_W_EGRESS" },
525 	{ 0x1e, "CDN_DIAG_C_EGRESS" },
526 	{ 0x1f, "CDN_DIAG_N_INGRESS" },
527 	{ 0x20, "CDN_DIAG_S_INGRESS" },
528 	{ 0x21, "CDN_DIAG_E_INGRESS" },
529 	{ 0x22, "CDN_DIAG_W_INGRESS" },
530 	{ 0x23, "CDN_DIAG_C_INGRESS" },
531 	{ 0x24, "CDN_DIAG_CORE_SENT" },
532 	{ 0x25, "DDN_DIAG_N_OUT_OF_CRED" },
533 	{ 0x26, "DDN_DIAG_S_OUT_OF_CRED" },
534 	{ 0x27, "DDN_DIAG_E_OUT_OF_CRED" },
535 	{ 0x28, "DDN_DIAG_W_OUT_OF_CRED" },
536 	{ 0x29, "DDN_DIAG_C_OUT_OF_CRED" },
537 	{ 0x2a, "DDN_DIAG_N_EGRESS" },
538 	{ 0x2b, "DDN_DIAG_S_EGRESS" },
539 	{ 0x2c, "DDN_DIAG_E_EGRESS" },
540 	{ 0x2d, "DDN_DIAG_W_EGRESS" },
541 	{ 0x2e, "DDN_DIAG_C_EGRESS" },
542 	{ 0x2f, "DDN_DIAG_N_INGRESS" },
543 	{ 0x30, "DDN_DIAG_S_INGRESS" },
544 	{ 0x31, "DDN_DIAG_E_INGRESS" },
545 	{ 0x32, "DDN_DIAG_W_INGRESS" },
546 	{ 0x33, "DDN_DIAG_C_INGRESS" },
547 	{ 0x34, "DDN_DIAG_CORE_SENT" },
548 	{ 0x35, "NDN_DIAG_N_OUT_OF_CRED" },
549 	{ 0x36, "NDN_DIAG_S_OUT_OF_CRED" },
550 	{ 0x37, "NDN_DIAG_E_OUT_OF_CRED" },
551 	{ 0x38, "NDN_DIAG_W_OUT_OF_CRED" },
552 	{ 0x39, "NDN_DIAG_C_OUT_OF_CRED" },
553 	{ 0x3a, "NDN_DIAG_N_EGRESS" },
554 	{ 0x3b, "NDN_DIAG_S_EGRESS" },
555 	{ 0x3c, "NDN_DIAG_E_EGRESS" },
556 	{ 0x3d, "NDN_DIAG_W_EGRESS" },
557 	{ 0x3e, "NDN_DIAG_C_EGRESS" },
558 	{ 0x3f, "NDN_DIAG_N_INGRESS" },
559 	{ 0x40, "NDN_DIAG_S_INGRESS" },
560 	{ 0x41, "NDN_DIAG_E_INGRESS" },
561 	{ 0x42, "NDN_DIAG_W_INGRESS" },
562 	{ 0x43, "NDN_DIAG_C_INGRESS" },
563 	{ 0x44, "NDN_DIAG_CORE_SENT" },
564 };
565 
566 static const struct mlxbf_pmc_events mlxbf_pmc_l3c_events[] = {
567 	{ 0x00, "DISABLE" },
568 	{ 0x01, "CYCLES" },
569 	{ 0x02, "TOTAL_RD_REQ_IN" },
570 	{ 0x03, "TOTAL_WR_REQ_IN" },
571 	{ 0x04, "TOTAL_WR_DBID_ACK" },
572 	{ 0x05, "TOTAL_WR_DATA_IN" },
573 	{ 0x06, "TOTAL_WR_COMP" },
574 	{ 0x07, "TOTAL_RD_DATA_OUT" },
575 	{ 0x08, "TOTAL_CDN_REQ_IN_BANK0" },
576 	{ 0x09, "TOTAL_CDN_REQ_IN_BANK1" },
577 	{ 0x0a, "TOTAL_DDN_REQ_IN_BANK0" },
578 	{ 0x0b, "TOTAL_DDN_REQ_IN_BANK1" },
579 	{ 0x0c, "TOTAL_EMEM_RD_RES_IN_BANK0" },
580 	{ 0x0d, "TOTAL_EMEM_RD_RES_IN_BANK1" },
581 	{ 0x0e, "TOTAL_CACHE_RD_RES_IN_BANK0" },
582 	{ 0x0f, "TOTAL_CACHE_RD_RES_IN_BANK1" },
583 	{ 0x10, "TOTAL_EMEM_RD_REQ_BANK0" },
584 	{ 0x11, "TOTAL_EMEM_RD_REQ_BANK1" },
585 	{ 0x12, "TOTAL_EMEM_WR_REQ_BANK0" },
586 	{ 0x13, "TOTAL_EMEM_WR_REQ_BANK1" },
587 	{ 0x14, "TOTAL_RD_REQ_OUT" },
588 	{ 0x15, "TOTAL_WR_REQ_OUT" },
589 	{ 0x16, "TOTAL_RD_RES_IN" },
590 	{ 0x17, "HITS_BANK0" },
591 	{ 0x18, "HITS_BANK1" },
592 	{ 0x19, "MISSES_BANK0" },
593 	{ 0x1a, "MISSES_BANK1" },
594 	{ 0x1b, "ALLOCATIONS_BANK0" },
595 	{ 0x1c, "ALLOCATIONS_BANK1" },
596 	{ 0x1d, "EVICTIONS_BANK0" },
597 	{ 0x1e, "EVICTIONS_BANK1" },
598 	{ 0x1f, "DBID_REJECT" },
599 	{ 0x20, "WRDB_REJECT_BANK0" },
600 	{ 0x21, "WRDB_REJECT_BANK1" },
601 	{ 0x22, "CMDQ_REJECT_BANK0" },
602 	{ 0x23, "CMDQ_REJECT_BANK1" },
603 	{ 0x24, "COB_REJECT_BANK0" },
604 	{ 0x25, "COB_REJECT_BANK1" },
605 	{ 0x26, "TRB_REJECT_BANK0" },
606 	{ 0x27, "TRB_REJECT_BANK1" },
607 	{ 0x28, "TAG_REJECT_BANK0" },
608 	{ 0x29, "TAG_REJECT_BANK1" },
609 	{ 0x2a, "ANY_REJECT_BANK0" },
610 	{ 0x2b, "ANY_REJECT_BANK1" },
611 };
612 
613 static const struct mlxbf_pmc_events mlxbf_pmc_llt_events[] = {
614 	{0, "HNF0_CYCLES"},
615 	{1, "HNF0_REQS_RECEIVED"},
616 	{2, "HNF0_REQS_PROCESSED"},
617 	{3, "HNF0_DIR_HIT"},
618 	{4, "HNF0_DIR_MISS"},
619 	{5, "HNF0_DIR_RD_ALLOC"},
620 	{6, "HNF0_DIR_WR_ALLOC"},
621 	{7, "HNF0_DIR_VICTIM"},
622 	{8, "HNF0_CL_HAZARD"},
623 	{9, "HNF0_ALL_HAZARD"},
624 	{10, "HNF0_PIPE_STALLS"},
625 	{11, "HNF0_MEM_READS"},
626 	{12, "HNF0_MEM_WRITES"},
627 	{13, "HNF0_MEM_ACCESS"},
628 	{14, "HNF0_DCL_READ"},
629 	{15, "HNF0_DCL_INVAL"},
630 	{16, "HNF0_CHI_RXDAT"},
631 	{17, "HNF0_CHI_RXRSP"},
632 	{18, "HNF0_CHI_TXDAT"},
633 	{19, "HNF0_CHI_TXRSP"},
634 	{20, "HNF0_CHI_TXSNP"},
635 	{21, "HNF0_DCT_SNP"},
636 	{22, "HNF0_SNP_FWD_DATA"},
637 	{23, "HNF0_SNP_FWD_RSP"},
638 	{24, "HNF0_SNP_RSP"},
639 	{25, "HNF0_EXCL_FULL"},
640 	{26, "HNF0_EXCL_WRITE_F"},
641 	{27, "HNF0_EXCL_WRITE_S"},
642 	{28, "HNF0_EXCL_WRITE"},
643 	{29, "HNF0_EXCL_READ"},
644 	{30, "HNF0_REQ_BUF_EMPTY"},
645 	{31, "HNF0_ALL_MAFS_BUSY"},
646 	{32, "HNF0_TXDAT_NO_LCRD"},
647 	{33, "HNF0_TXSNP_NO_LCRD"},
648 	{34, "HNF0_TXRSP_NO_LCRD"},
649 	{35, "HNF0_TXREQ_NO_LCRD"},
650 	{36, "HNF0_WRITE"},
651 	{37, "HNF0_READ"},
652 	{38, "HNF0_ACCESS"},
653 	{39, "HNF0_MAF_N_BUSY"},
654 	{40, "HNF0_MAF_N_REQS"},
655 	{41, "HNF0_SEL_OPCODE"},
656 	{42, "HNF1_CYCLES"},
657 	{43, "HNF1_REQS_RECEIVED"},
658 	{44, "HNF1_REQS_PROCESSED"},
659 	{45, "HNF1_DIR_HIT"},
660 	{46, "HNF1_DIR_MISS"},
661 	{47, "HNF1_DIR_RD_ALLOC"},
662 	{48, "HNF1_DIR_WR_ALLOC"},
663 	{49, "HNF1_DIR_VICTIM"},
664 	{50, "HNF1_CL_HAZARD"},
665 	{51, "HNF1_ALL_HAZARD"},
666 	{52, "HNF1_PIPE_STALLS"},
667 	{53, "HNF1_MEM_READS"},
668 	{54, "HNF1_MEM_WRITES"},
669 	{55, "HNF1_MEM_ACCESS"},
670 	{56, "HNF1_DCL_READ"},
671 	{57, "HNF1_DCL_INVAL"},
672 	{58, "HNF1_CHI_RXDAT"},
673 	{59, "HNF1_CHI_RXRSP"},
674 	{60, "HNF1_CHI_TXDAT"},
675 	{61, "HNF1_CHI_TXRSP"},
676 	{62, "HNF1_CHI_TXSNP"},
677 	{63, "HNF1_DCT_SNP"},
678 	{64, "HNF1_SNP_FWD_DATA"},
679 	{65, "HNF1_SNP_FWD_RSP"},
680 	{66, "HNF1_SNP_RSP"},
681 	{67, "HNF1_EXCL_FULL"},
682 	{68, "HNF1_EXCL_WRITE_F"},
683 	{69, "HNF1_EXCL_WRITE_S"},
684 	{70, "HNF1_EXCL_WRITE"},
685 	{71, "HNF1_EXCL_READ"},
686 	{72, "HNF1_REQ_BUF_EMPTY"},
687 	{73, "HNF1_ALL_MAFS_BUSY"},
688 	{74, "HNF1_TXDAT_NO_LCRD"},
689 	{75, "HNF1_TXSNP_NO_LCRD"},
690 	{76, "HNF1_TXRSP_NO_LCRD"},
691 	{77, "HNF1_TXREQ_NO_LCRD"},
692 	{78, "HNF1_WRITE"},
693 	{79, "HNF1_READ"},
694 	{80, "HNF1_ACCESS"},
695 	{81, "HNF1_MAF_N_BUSY"},
696 	{82, "HNF1_MAF_N_REQS"},
697 	{83, "HNF1_SEL_OPCODE"},
698 	{84, "GDC_BANK0_RD_REQ"},
699 	{85, "GDC_BANK0_WR_REQ"},
700 	{86, "GDC_BANK0_ALLOCATE"},
701 	{87, "GDC_BANK0_HIT"},
702 	{88, "GDC_BANK0_MISS"},
703 	{89, "GDC_BANK0_INVALIDATE"},
704 	{90, "GDC_BANK0_EVICT"},
705 	{91, "GDC_BANK0_RD_RESP"},
706 	{92, "GDC_BANK0_WR_ACK"},
707 	{93, "GDC_BANK0_SNOOP"},
708 	{94, "GDC_BANK0_SNOOP_NORMAL"},
709 	{95, "GDC_BANK0_SNOOP_FWD"},
710 	{96, "GDC_BANK0_SNOOP_STASH"},
711 	{97, "GDC_BANK0_SNOOP_STASH_INDPND_RD"},
712 	{98, "GDC_BANK0_FOLLOWER"},
713 	{99, "GDC_BANK0_FW"},
714 	{100, "GDC_BANK0_HIT_DCL_BOTH"},
715 	{101, "GDC_BANK0_HIT_DCL_PARTIAL"},
716 	{102, "GDC_BANK0_EVICT_DCL"},
717 	{103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA0"},
718 	{103, "GDC_BANK0_G_RSE_PIPE_CACHE_DATA1"},
719 	{105, "GDC_BANK0_ARB_STRB"},
720 	{106, "GDC_BANK0_ARB_WAIT"},
721 	{107, "GDC_BANK0_GGA_STRB"},
722 	{108, "GDC_BANK0_GGA_WAIT"},
723 	{109, "GDC_BANK0_FW_STRB"},
724 	{110, "GDC_BANK0_FW_WAIT"},
725 	{111, "GDC_BANK0_SNP_STRB"},
726 	{112, "GDC_BANK0_SNP_WAIT"},
727 	{113, "GDC_BANK0_MISS_INARB_STRB"},
728 	{114, "GDC_BANK0_MISS_INARB_WAIT"},
729 	{115, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD0"},
730 	{116, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD1"},
731 	{117, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD2"},
732 	{118, "GDC_BANK0_G_FIFO_FF_GGA_RSP_RD3"},
733 	{119, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR0"},
734 	{120, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR1"},
735 	{121, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR2"},
736 	{122, "GDC_BANK0_G_FIFO_FF_GGA_RSP_WR3"},
737 	{123, "GDC_BANK1_RD_REQ"},
738 	{124, "GDC_BANK1_WR_REQ"},
739 	{125, "GDC_BANK1_ALLOCATE"},
740 	{126, "GDC_BANK1_HIT"},
741 	{127, "GDC_BANK1_MISS"},
742 	{128, "GDC_BANK1_INVALIDATE"},
743 	{129, "GDC_BANK1_EVICT"},
744 	{130, "GDC_BANK1_RD_RESP"},
745 	{131, "GDC_BANK1_WR_ACK"},
746 	{132, "GDC_BANK1_SNOOP"},
747 	{133, "GDC_BANK1_SNOOP_NORMAL"},
748 	{134, "GDC_BANK1_SNOOP_FWD"},
749 	{135, "GDC_BANK1_SNOOP_STASH"},
750 	{136, "GDC_BANK1_SNOOP_STASH_INDPND_RD"},
751 	{137, "GDC_BANK1_FOLLOWER"},
752 	{138, "GDC_BANK1_FW"},
753 	{139, "GDC_BANK1_HIT_DCL_BOTH"},
754 	{140, "GDC_BANK1_HIT_DCL_PARTIAL"},
755 	{141, "GDC_BANK1_EVICT_DCL"},
756 	{142, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA0"},
757 	{143, "GDC_BANK1_G_RSE_PIPE_CACHE_DATA1"},
758 	{144, "GDC_BANK1_ARB_STRB"},
759 	{145, "GDC_BANK1_ARB_WAIT"},
760 	{146, "GDC_BANK1_GGA_STRB"},
761 	{147, "GDC_BANK1_GGA_WAIT"},
762 	{148, "GDC_BANK1_FW_STRB"},
763 	{149, "GDC_BANK1_FW_WAIT"},
764 	{150, "GDC_BANK1_SNP_STRB"},
765 	{151, "GDC_BANK1_SNP_WAIT"},
766 	{152, "GDC_BANK1_MISS_INARB_STRB"},
767 	{153, "GDC_BANK1_MISS_INARB_WAIT"},
768 	{154, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD0"},
769 	{155, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD1"},
770 	{156, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD2"},
771 	{157, "GDC_BANK1_G_FIFO_FF_GGA_RSP_RD3"},
772 	{158, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR0"},
773 	{159, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR1"},
774 	{160, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR2"},
775 	{161, "GDC_BANK1_G_FIFO_FF_GGA_RSP_WR3"},
776 	{162, "HISTOGRAM_HISTOGRAM_BIN0"},
777 	{163, "HISTOGRAM_HISTOGRAM_BIN1"},
778 	{164, "HISTOGRAM_HISTOGRAM_BIN2"},
779 	{165, "HISTOGRAM_HISTOGRAM_BIN3"},
780 	{166, "HISTOGRAM_HISTOGRAM_BIN4"},
781 	{167, "HISTOGRAM_HISTOGRAM_BIN5"},
782 	{168, "HISTOGRAM_HISTOGRAM_BIN6"},
783 	{169, "HISTOGRAM_HISTOGRAM_BIN7"},
784 	{170, "HISTOGRAM_HISTOGRAM_BIN8"},
785 	{171, "HISTOGRAM_HISTOGRAM_BIN9"},
786 };
787 
788 static const struct mlxbf_pmc_events mlxbf_pmc_llt_miss_events[] = {
789 	{0, "GDC_MISS_MACHINE_RD_REQ"},
790 	{1, "GDC_MISS_MACHINE_WR_REQ"},
791 	{2, "GDC_MISS_MACHINE_SNP_REQ"},
792 	{3, "GDC_MISS_MACHINE_EVICT_REQ"},
793 	{4, "GDC_MISS_MACHINE_FW_REQ"},
794 	{5, "GDC_MISS_MACHINE_RD_RESP"},
795 	{6, "GDC_MISS_MACHINE_WR_RESP"},
796 	{7, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP"},
797 	{8, "GDC_MISS_MACHINE_SNP_STASH_DATAPULL_DROP_TXDAT"},
798 	{9, "GDC_MISS_MACHINE_CHI_TXREQ"},
799 	{10, "GDC_MISS_MACHINE_CHI_RXRSP"},
800 	{11, "GDC_MISS_MACHINE_CHI_TXDAT"},
801 	{12, "GDC_MISS_MACHINE_CHI_RXDAT"},
802 	{13, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_0"},
803 	{14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1 "},
804 	{15, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_2"},
805 	{16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3 "},
806 	{17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0 "},
807 	{18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1 "},
808 	{19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2 "},
809 	{20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3 "},
810 	{21, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_0"},
811 	{22, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_1"},
812 	{23, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_2"},
813 	{24, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_3"},
814 	{25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0 "},
815 	{26, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_1"},
816 	{27, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_2"},
817 	{28, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_3"},
818 	{29, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_0"},
819 	{30, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_1"},
820 	{31, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_2"},
821 	{32, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_3"},
822 	{33, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_4"},
823 	{34, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_5"},
824 	{35, "GDC_MISS_MACHINE_GDC_LINK_LIST_FF_6"},
825 	{36, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_0"},
826 	{37, "GDC_MISS_MACHINE_G_RSE_PIPE_TXREQ_1"},
827 	{38, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_0"},
828 	{39, "GDC_MISS_MACHINE_G_CREDIT_TXREQ_1"},
829 	{40, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_0"},
830 	{41, "GDC_MISS_MACHINE_G_RSE_PIPE_TXDAT_1"},
831 	{42, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_0"},
832 	{43, "GDC_MISS_MACHINE_G_CREDIT_TXDAT_1"},
833 	{44, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_0"},
834 	{45, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_1"},
835 	{46, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_2"},
836 	{47, "GDC_MISS_MACHINE_G_FIFO_FF_COMPACK_3"},
837 	{48, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_0"},
838 	{49, "GDC_MISS_MACHINE_G_RSE_PIPE_TXRSP_1"},
839 	{50, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_0"},
840 	{51, "GDC_MISS_MACHINE_G_CREDIT_TXRSP_1"},
841 	{52, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_0"},
842 	{53, "GDC_MISS_MACHINE_G_RSE_PIPE_INARB_1"},
843 	{54, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_0"},
844 	{55, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_1"},
845 	{56, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_2"},
846 	{57, "GDC_MISS_MACHINE_G_FIFO_FF_SNOOP_IN_3"},
847 	{58, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_0"},
848 	{59, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_1"},
849 	{60, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_2"},
850 	{61, "GDC_MISS_MACHINE_G_FIFO_FF_TXRSP_SNOOP_DATAPULL_3"},
851 	{62, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_4"},
852 	{63, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_5"},
853 	{64, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_6"},
854 	{65, "GDC_MISS_MACHINE_G_FIFO_FF_TXDAT_SNOOP_DATAPULL_7"},
855 	{66, "HISTOGRAM_HISTOGRAM_BIN0"},
856 	{67, "HISTOGRAM_HISTOGRAM_BIN1"},
857 	{68, "HISTOGRAM_HISTOGRAM_BIN2"},
858 	{69, "HISTOGRAM_HISTOGRAM_BIN3"},
859 	{70, "HISTOGRAM_HISTOGRAM_BIN4"},
860 	{71, "HISTOGRAM_HISTOGRAM_BIN5"},
861 	{72, "HISTOGRAM_HISTOGRAM_BIN6"},
862 	{73, "HISTOGRAM_HISTOGRAM_BIN7"},
863 	{74, "HISTOGRAM_HISTOGRAM_BIN8"},
864 	{75, "HISTOGRAM_HISTOGRAM_BIN9"},
865 };
866 
867 static const struct mlxbf_pmc_events mlxbf_pmc_clock_events[] = {
868 	{ 0x0, "FMON_CLK_LAST_COUNT_PLL_D1_INST0" },
869 	{ 0x4, "REFERENCE_WINDOW_WIDTH_PLL_D1_INST0" },
870 	{ 0x8, "FMON_CLK_LAST_COUNT_PLL_D1_INST1" },
871 	{ 0xc, "REFERENCE_WINDOW_WIDTH_PLL_D1_INST1" },
872 	{ 0x10, "FMON_CLK_LAST_COUNT_PLL_G1" },
873 	{ 0x14, "REFERENCE_WINDOW_WIDTH_PLL_G1" },
874 	{ 0x18, "FMON_CLK_LAST_COUNT_PLL_W1" },
875 	{ 0x1c, "REFERENCE_WINDOW_WIDTH_PLL_W1" },
876 	{ 0x20, "FMON_CLK_LAST_COUNT_PLL_T1" },
877 	{ 0x24, "REFERENCE_WINDOW_WIDTH_PLL_T1" },
878 	{ 0x28, "FMON_CLK_LAST_COUNT_PLL_A0" },
879 	{ 0x2c, "REFERENCE_WINDOW_WIDTH_PLL_A0" },
880 	{ 0x30, "FMON_CLK_LAST_COUNT_PLL_C0" },
881 	{ 0x34, "REFERENCE_WINDOW_WIDTH_PLL_C0" },
882 	{ 0x38, "FMON_CLK_LAST_COUNT_PLL_N1" },
883 	{ 0x3c, "REFERENCE_WINDOW_WIDTH_PLL_N1" },
884 	{ 0x40, "FMON_CLK_LAST_COUNT_PLL_I1" },
885 	{ 0x44, "REFERENCE_WINDOW_WIDTH_PLL_I1" },
886 	{ 0x48, "FMON_CLK_LAST_COUNT_PLL_R1" },
887 	{ 0x4c, "REFERENCE_WINDOW_WIDTH_PLL_R1" },
888 	{ 0x50, "FMON_CLK_LAST_COUNT_PLL_P1" },
889 	{ 0x54, "REFERENCE_WINDOW_WIDTH_PLL_P1" },
890 	{ 0x58, "FMON_CLK_LAST_COUNT_REF_100_INST0" },
891 	{ 0x5c, "REFERENCE_WINDOW_WIDTH_REF_100_INST0" },
892 	{ 0x60, "FMON_CLK_LAST_COUNT_REF_100_INST1" },
893 	{ 0x64, "REFERENCE_WINDOW_WIDTH_REF_100_INST1" },
894 	{ 0x68, "FMON_CLK_LAST_COUNT_REF_156" },
895 	{ 0x6c, "REFERENCE_WINDOW_WIDTH_REF_156" },
896 };
897 
898 static const struct mlxbf_pmc_events mlxbf_pmc_gga_events[] = {
899 	{ 0, "GGA_PERF_DESC_WQE_STRB" },
900 	{ 5, "GGA_PERF_DESC_CQE_STRB" },
901 	{ 8, "GGA_PERF_DESC_TPT_REQUEST_STRB" },
902 	{ 17, "GGA_PERF_DESC_TPT_RESPONSESTRB" },
903 	{ 120, "GGA_PERF_DESC_ENGINE0_IN_DATA_STRB" },
904 	{ 121, "GGA_PERF_DESC_ENGINE1_IN_DATA_STRB" },
905 	{ 122, "GGA_PERF_DESC_ENGINE2_IN_DATA_STRB" },
906 	{ 123, "GGA_PERF_DESC_ENGINE3_IN_DATA_STRB" },
907 	{ 124, "GGA_PERF_DESC_ENGINE4_IN_DATA_STRB" },
908 	{ 125, "GGA_PERF_DESC_ENGINE5_IN_DATA_STRB" },
909 	{ 126, "GGA_PERF_DESC_ENGINE6_IN_DATA_STRB" },
910 	{ 127, "GGA_PERF_DESC_ENGINE7_IN_DATA_STRB" },
911 	{ 128, "GGA_PERF_DESC_ENGINE8_IN_DATA_STRB" },
912 	{ 129, "GGA_PERF_DESC_ENGINE9_IN_DATA_STRB" },
913 	{ 130, "GGA_PERF_DESC_ENGINE10_IN_DATA_STRB" },
914 	{ 131, "GGA_PERF_DESC_ENGINE11_IN_DATA_STRB" },
915 	{ 132, "GGA_PERF_DESC_ENGINE12_IN_DATA_STRB" },
916 	{ 133, "GGA_PERF_DESC_ENGINE13_IN_DATA_STRB" },
917 	{ 134, "GGA_PERF_DESC_ENGINE14_IN_DATA_STRB" },
918 	{ 195, "GGA_PERF_DESC_ENGINE0_OUT_DATA_STRB" },
919 	{ 196, "GGA_PERF_DESC_ENGINE1_OUT_DATA_STRB" },
920 	{ 197, "GGA_PERF_DESC_ENGINE2_OUT_DATA_STRB" },
921 	{ 198, "GGA_PERF_DESC_ENGINE3_OUT_DATA_STRB" },
922 	{ 199, "GGA_PERF_DESC_ENGINE4_OUT_DATA_STRB" },
923 	{ 200, "GGA_PERF_DESC_ENGINE5_OUT_DATA_STRB" },
924 	{ 201, "GGA_PERF_DESC_ENGINE6_OUT_DATA_STRB" },
925 	{ 202, "GGA_PERF_DESC_ENGINE7_OUT_DATA_STRB" },
926 	{ 203, "GGA_PERF_DESC_ENGINE8_OUT_DATA_STRB" },
927 	{ 204, "GGA_PERF_DESC_ENGINE9_OUT_DATA_STRB" },
928 	{ 205, "GGA_PERF_DESC_ENGINE10_OUT_DATA_STRB" },
929 	{ 206, "GGA_PERF_DESC_ENGINE11_OUT_DATA_STRB" },
930 	{ 207, "GGA_PERF_DESC_ENGINE12_OUT_DATA_STRB" },
931 	{ 208, "GGA_PERF_DESC_ENGINE13_OUT_DATA_STRB" },
932 	{ 209, "GGA_PERF_DESC_ENGINE14_OUT_DATA_STRB" },
933 };
934 
935 static const struct mlxbf_pmc_events mlxbf_pmc_apt_events[] = {
936 	{ 0, "APT_DATA_0" },
937 	{ 1, "APT_DATA_1" },
938 	{ 2, "APT_DATA_2" },
939 	{ 3, "APT_DATA_3" },
940 	{ 4, "APT_DATA_4" },
941 	{ 5, "APT_DATA_5" },
942 	{ 6, "APT_DATA_6" },
943 	{ 7, "APT_DATA_7" },
944 	{ 8, "APT_DATA_8" },
945 	{ 9, "APT_DATA_9" },
946 	{ 10, "APT_DATA_10" },
947 	{ 11, "APT_DATA_11" },
948 	{ 12, "APT_DATA_12" },
949 	{ 13, "APT_DATA_13" },
950 	{ 14, "APT_DATA_14" },
951 	{ 15, "APT_DATA_15" },
952 	{ 16, "APT_DATA_16" },
953 	{ 17, "APT_DATA_17" },
954 	{ 18, "APT_DATA_18" },
955 	{ 19, "APT_DATA_19" },
956 	{ 20, "APT_DATA_20" },
957 	{ 21, "APT_DATA_21" },
958 };
959 
960 static const struct mlxbf_pmc_events mlxbf_pmc_emi_events[] = {
961 	{ 0, "MCH_WR_IN_MCH_REQ_IN_STRB" },
962 	{ 10, "MCH_RD_IN_MCH_REQ_IN_STRB" },
963 	{ 20, "MCH_RD_RESP_DATA_MCH_RESP_OUT_STRB" },
964 	{ 98, "EMI_ARBITER_EARB2CTRL_STRB" },
965 	{ 99, "EMI_ARBITER_EARB2CTRL_RAS_STRB" },
966 	{ 100, "EMI_ARBITER_EARB2CTRL_CAS_STRB" },
967 };
968 
969 static const struct mlxbf_pmc_events mlxbf_pmc_prnf_events[] = {
970 	{ 0, "PRNF_DMA_RD_TLP_REQ" },
971 	{ 1, "PRNF_DMA_RD_ICMC_BYPASS_REQ" },
972 	{ 8, "PRNF_DMA_RD_TLP_SENT_TO_CHI" },
973 	{ 11, "PRNF_DMA_RD_CHI_RES" },
974 	{ 17, "PRNF_DMA_RD_TLP_RES_SENT" },
975 	{ 18, "PRNF_DMA_WR_WR0_SLICE_ALLOC_RO" },
976 	{ 19, "PRNF_DMA_WR_WR0_SLICE_ALLOC_NRO" },
977 	{ 24, "PRNF_DMA_WR_WR1_SLICE_ALLOC_RO" },
978 	{ 25, "PRNF_DMA_WR_WR1_SLICE_ALLOC_NRO" },
979 	{ 30, "PRNF_PIO_POSTED_REQ_PUSH" },
980 	{ 31, "PRNF_PIO_POSTED_REQ_POP" },
981 	{ 32, "PRNF_PIO_NP_REQ_PUSH" },
982 	{ 33, "PRNF_PIO_NP_REQ_POP" },
983 	{ 34, "PRNF_PIO_COMP_RO_PUSH" },
984 	{ 35, "PRNF_PIO_COMP_RO_POP" },
985 	{ 36, "PRNF_PIO_COMP_NRO_PUSH" },
986 	{ 37, "PRNF_PIO_COMP_NRO_POP" },
987 };
988 
989 static const struct mlxbf_pmc_events mlxbf_pmc_msn_events[] = {
990 	{ 46, "MSN_CORE_MMA_WQE_DONE_PUSH_STRB" },
991 	{ 116, "MSN_CORE_MSN2MMA_WQE_STRB" },
992 	{ 164, "MSN_CORE_WQE_TOP_TILE_WQE_STRB" },
993 	{ 168, "MSN_CORE_TPT_TOP_GGA_REQ_STRB" },
994 	{ 171, "MSN_CORE_TPT_TOP_MMA_REQ_STRB" },
995 	{ 174, "MSN_CORE_TPT_TOP_GGA_RES_STRB" },
996 	{ 177, "MSN_CORE_TPT_TOP_MMA_RES_STRB" },
997 };
998 
999 static struct mlxbf_pmc_context *pmc;
1000 
1001 /* UUID used to probe ATF service. */
1002 static const char *mlxbf_pmc_svc_uuid_str = "89c036b4-e7d7-11e6-8797-001aca00bfc4";
1003 
1004 /* Calls an SMC to access a performance register */
mlxbf_pmc_secure_read(void __iomem * addr,u32 command,u64 * result)1005 static int mlxbf_pmc_secure_read(void __iomem *addr, u32 command, u64 *result)
1006 {
1007 	struct arm_smccc_res res;
1008 	int status, err = 0;
1009 
1010 	arm_smccc_smc(command, pmc->sreg_tbl_perf, (uintptr_t)addr, 0, 0, 0, 0,
1011 		      0, &res);
1012 
1013 	status = res.a0;
1014 
1015 	switch (status) {
1016 	case PSCI_RET_NOT_SUPPORTED:
1017 		err = -EINVAL;
1018 		break;
1019 	case MLXBF_PMC_SMCCC_ACCESS_VIOLATION:
1020 		err = -EACCES;
1021 		break;
1022 	default:
1023 		*result = res.a1;
1024 		break;
1025 	}
1026 
1027 	return err;
1028 }
1029 
1030 /* Read from a performance counter */
mlxbf_pmc_read(void __iomem * addr,u32 command,u64 * result)1031 static int mlxbf_pmc_read(void __iomem *addr, u32 command, u64 *result)
1032 {
1033 	if (pmc->svc_sreg_support)
1034 		return mlxbf_pmc_secure_read(addr, command, result);
1035 
1036 	if (command == MLXBF_PMC_READ_REG_32)
1037 		*result = readl(addr);
1038 	else
1039 		*result = readq(addr);
1040 
1041 	return 0;
1042 }
1043 
1044 /* Convenience function for 32-bit reads */
mlxbf_pmc_readl(void __iomem * addr,u32 * result)1045 static int mlxbf_pmc_readl(void __iomem *addr, u32 *result)
1046 {
1047 	u64 read_out;
1048 	int status;
1049 
1050 	status = mlxbf_pmc_read(addr, MLXBF_PMC_READ_REG_32, &read_out);
1051 	if (status)
1052 		return status;
1053 	*result = (u32)read_out;
1054 
1055 	return 0;
1056 }
1057 
1058 /* Calls an SMC to access a performance register */
mlxbf_pmc_secure_write(void __iomem * addr,u32 command,u64 value)1059 static int mlxbf_pmc_secure_write(void __iomem *addr, u32 command, u64 value)
1060 {
1061 	struct arm_smccc_res res;
1062 	int status, err = 0;
1063 
1064 	arm_smccc_smc(command, pmc->sreg_tbl_perf, value, (uintptr_t)addr, 0, 0,
1065 		      0, 0, &res);
1066 
1067 	status = res.a0;
1068 
1069 	switch (status) {
1070 	case PSCI_RET_NOT_SUPPORTED:
1071 		err = -EINVAL;
1072 		break;
1073 	case MLXBF_PMC_SMCCC_ACCESS_VIOLATION:
1074 		err = -EACCES;
1075 		break;
1076 	}
1077 
1078 	return err;
1079 }
1080 
1081 /* Write to a performance counter */
mlxbf_pmc_write(void __iomem * addr,int command,u64 value)1082 static int mlxbf_pmc_write(void __iomem *addr, int command, u64 value)
1083 {
1084 	if (pmc->svc_sreg_support)
1085 		return mlxbf_pmc_secure_write(addr, command, value);
1086 
1087 	if (command == MLXBF_PMC_WRITE_REG_32)
1088 		writel(value, addr);
1089 	else
1090 		writeq(value, addr);
1091 
1092 	return 0;
1093 }
1094 
1095 /* Check if the register offset is within the mapped region for the block */
mlxbf_pmc_valid_range(unsigned int blk_num,u32 offset)1096 static bool mlxbf_pmc_valid_range(unsigned int blk_num, u32 offset)
1097 {
1098 	if ((offset >= 0) && !(offset % MLXBF_PMC_REG_SIZE) &&
1099 	    (offset + MLXBF_PMC_REG_SIZE <= pmc->block[blk_num].blk_size))
1100 		return true; /* inside the mapped PMC space */
1101 
1102 	return false;
1103 }
1104 
1105 /* Get the event list corresponding to a certain block */
mlxbf_pmc_event_list(const char * blk,size_t * psize)1106 static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk, size_t *psize)
1107 {
1108 	const struct mlxbf_pmc_events *events;
1109 	size_t size;
1110 
1111 	if (strstr(blk, "tilenet")) {
1112 		events = mlxbf_pmc_hnfnet_events;
1113 		size = ARRAY_SIZE(mlxbf_pmc_hnfnet_events);
1114 	} else if (strstr(blk, "tile")) {
1115 		events = mlxbf_pmc_hnf_events;
1116 		size = ARRAY_SIZE(mlxbf_pmc_hnf_events);
1117 	} else if (strstr(blk, "triogen")) {
1118 		events = mlxbf_pmc_smgen_events;
1119 		size = ARRAY_SIZE(mlxbf_pmc_smgen_events);
1120 	} else if (strstr(blk, "trio")) {
1121 		switch (pmc->event_set) {
1122 		case MLXBF_PMC_EVENT_SET_BF1:
1123 			events = mlxbf_pmc_trio_events_1;
1124 			size = ARRAY_SIZE(mlxbf_pmc_trio_events_1);
1125 			break;
1126 		case MLXBF_PMC_EVENT_SET_BF2:
1127 			events = mlxbf_pmc_trio_events_2;
1128 			size = ARRAY_SIZE(mlxbf_pmc_trio_events_2);
1129 			break;
1130 		default:
1131 			events = NULL;
1132 			size = 0;
1133 			break;
1134 		}
1135 	} else if (strstr(blk, "mss")) {
1136 		switch (pmc->event_set) {
1137 		case MLXBF_PMC_EVENT_SET_BF1:
1138 		case MLXBF_PMC_EVENT_SET_BF2:
1139 			events = mlxbf_pmc_mss_events_1;
1140 			size = ARRAY_SIZE(mlxbf_pmc_mss_events_1);
1141 			break;
1142 		case MLXBF_PMC_EVENT_SET_BF3:
1143 			events = mlxbf_pmc_mss_events_3;
1144 			size = ARRAY_SIZE(mlxbf_pmc_mss_events_3);
1145 			break;
1146 		default:
1147 			events = NULL;
1148 			size = 0;
1149 			break;
1150 		}
1151 	} else if (strstr(blk, "ecc")) {
1152 		events = mlxbf_pmc_ecc_events;
1153 		size = ARRAY_SIZE(mlxbf_pmc_ecc_events);
1154 	} else if (strstr(blk, "pcie")) {
1155 		events = mlxbf_pmc_pcie_events;
1156 		size = ARRAY_SIZE(mlxbf_pmc_pcie_events);
1157 	} else if (strstr(blk, "l3cache")) {
1158 		events = mlxbf_pmc_l3c_events;
1159 		size = ARRAY_SIZE(mlxbf_pmc_l3c_events);
1160 	} else if (strstr(blk, "gic")) {
1161 		events = mlxbf_pmc_smgen_events;
1162 		size = ARRAY_SIZE(mlxbf_pmc_smgen_events);
1163 	} else if (strstr(blk, "smmu")) {
1164 		events = mlxbf_pmc_smgen_events;
1165 		size = ARRAY_SIZE(mlxbf_pmc_smgen_events);
1166 	} else if (strstr(blk, "llt_miss")) {
1167 		events = mlxbf_pmc_llt_miss_events;
1168 		size = ARRAY_SIZE(mlxbf_pmc_llt_miss_events);
1169 	} else if (strstr(blk, "llt")) {
1170 		events = mlxbf_pmc_llt_events;
1171 		size = ARRAY_SIZE(mlxbf_pmc_llt_events);
1172 	} else if (strstr(blk, "clock_measure")) {
1173 		events = mlxbf_pmc_clock_events;
1174 		size = ARRAY_SIZE(mlxbf_pmc_clock_events);
1175 	} else if (strstr(blk, "gga")) {
1176 		events = mlxbf_pmc_gga_events;
1177 		size = ARRAY_SIZE(mlxbf_pmc_gga_events);
1178 	} else if (strstr(blk, "apt")) {
1179 		events = mlxbf_pmc_apt_events;
1180 		size = ARRAY_SIZE(mlxbf_pmc_apt_events);
1181 	} else if (strstr(blk, "emi")) {
1182 		events = mlxbf_pmc_emi_events;
1183 		size = ARRAY_SIZE(mlxbf_pmc_emi_events);
1184 	} else if (strstr(blk, "prnf")) {
1185 		events = mlxbf_pmc_prnf_events;
1186 		size = ARRAY_SIZE(mlxbf_pmc_prnf_events);
1187 	} else if (strstr(blk, "msn")) {
1188 		events = mlxbf_pmc_msn_events;
1189 		size = ARRAY_SIZE(mlxbf_pmc_msn_events);
1190 	} else {
1191 		events = NULL;
1192 		size = 0;
1193 	}
1194 
1195 	if (psize)
1196 		*psize = size;
1197 
1198 	return events;
1199 }
1200 
mlxbf_pmc_event_supported(const char * blk)1201 static bool mlxbf_pmc_event_supported(const char *blk)
1202 {
1203 	return !!mlxbf_pmc_event_list(blk, NULL);
1204 }
1205 
1206 /* Get the event number given the name */
mlxbf_pmc_get_event_num(const char * blk,const char * evt)1207 static int mlxbf_pmc_get_event_num(const char *blk, const char *evt)
1208 {
1209 	const struct mlxbf_pmc_events *events;
1210 	unsigned int i;
1211 	size_t size;
1212 
1213 	events = mlxbf_pmc_event_list(blk, &size);
1214 	if (!events)
1215 		return -EINVAL;
1216 
1217 	for (i = 0; i < size; ++i) {
1218 		if (!strcmp(evt, events[i].evt_name))
1219 			return events[i].evt_num;
1220 	}
1221 
1222 	return -ENODEV;
1223 }
1224 
1225 /* Get the event number given the name */
mlxbf_pmc_get_event_name(const char * blk,u32 evt)1226 static char *mlxbf_pmc_get_event_name(const char *blk, u32 evt)
1227 {
1228 	const struct mlxbf_pmc_events *events;
1229 	unsigned int i;
1230 	size_t size;
1231 
1232 	events = mlxbf_pmc_event_list(blk, &size);
1233 	if (!events)
1234 		return NULL;
1235 
1236 	for (i = 0; i < size; ++i) {
1237 		if (evt == events[i].evt_num)
1238 			return events[i].evt_name;
1239 	}
1240 
1241 	return NULL;
1242 }
1243 
1244 /* Method to enable/disable/reset l3cache counters */
mlxbf_pmc_config_l3_counters(unsigned int blk_num,bool enable,bool reset)1245 static int mlxbf_pmc_config_l3_counters(unsigned int blk_num, bool enable, bool reset)
1246 {
1247 	u32 perfcnt_cfg = 0;
1248 
1249 	if (enable)
1250 		perfcnt_cfg |= MLXBF_PMC_L3C_PERF_CNT_CFG_EN;
1251 	if (reset)
1252 		perfcnt_cfg |= MLXBF_PMC_L3C_PERF_CNT_CFG_RST;
1253 
1254 	return mlxbf_pmc_write(pmc->block[blk_num].mmio_base +
1255 				       MLXBF_PMC_L3C_PERF_CNT_CFG,
1256 			       MLXBF_PMC_WRITE_REG_32, perfcnt_cfg);
1257 }
1258 
1259 /* Method to handle l3cache counter programming */
mlxbf_pmc_program_l3_counter(unsigned int blk_num,u32 cnt_num,u32 evt)1260 static int mlxbf_pmc_program_l3_counter(unsigned int blk_num, u32 cnt_num, u32 evt)
1261 {
1262 	u32 perfcnt_sel_1 = 0, perfcnt_sel = 0, *wordaddr;
1263 	void __iomem *pmcaddr;
1264 	int ret;
1265 
1266 	/* Disable all counters before programming them */
1267 	if (mlxbf_pmc_config_l3_counters(blk_num, false, false))
1268 		return -EINVAL;
1269 
1270 	/* Select appropriate register information */
1271 	switch (cnt_num) {
1272 	case 0 ... 3:
1273 		pmcaddr = pmc->block[blk_num].mmio_base +
1274 			  MLXBF_PMC_L3C_PERF_CNT_SEL;
1275 		wordaddr = &perfcnt_sel;
1276 		break;
1277 	case 4:
1278 		pmcaddr = pmc->block[blk_num].mmio_base +
1279 			  MLXBF_PMC_L3C_PERF_CNT_SEL_1;
1280 		wordaddr = &perfcnt_sel_1;
1281 		break;
1282 	default:
1283 		return -EINVAL;
1284 	}
1285 
1286 	ret = mlxbf_pmc_readl(pmcaddr, wordaddr);
1287 	if (ret)
1288 		return ret;
1289 
1290 	switch (cnt_num) {
1291 	case 0:
1292 		perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0;
1293 		perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0,
1294 					  evt);
1295 		break;
1296 	case 1:
1297 		perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1;
1298 		perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1,
1299 					  evt);
1300 		break;
1301 	case 2:
1302 		perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2;
1303 		perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2,
1304 					  evt);
1305 		break;
1306 	case 3:
1307 		perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3;
1308 		perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3,
1309 					  evt);
1310 		break;
1311 	case 4:
1312 		perfcnt_sel_1 &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4;
1313 		perfcnt_sel_1 |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4,
1314 					    evt);
1315 		break;
1316 	default:
1317 		return -EINVAL;
1318 	}
1319 
1320 	return mlxbf_pmc_write(pmcaddr, MLXBF_PMC_WRITE_REG_32, *wordaddr);
1321 }
1322 
1323 /* Method to handle crspace counter programming */
mlxbf_pmc_program_crspace_counter(unsigned int blk_num,u32 cnt_num,u32 evt)1324 static int mlxbf_pmc_program_crspace_counter(unsigned int blk_num, u32 cnt_num, u32 evt)
1325 {
1326 	void __iomem *addr;
1327 	u32 word;
1328 	int ret;
1329 
1330 	addr = pmc->block[blk_num].mmio_base +
1331 		((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
1332 	ret = mlxbf_pmc_readl(addr, &word);
1333 	if (ret)
1334 		return ret;
1335 
1336 	if (cnt_num % 2) {
1337 		word &= ~MLXBF_PMC_CRSPACE_PERFSEL1;
1338 		word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL1, evt);
1339 	} else {
1340 		word &= ~MLXBF_PMC_CRSPACE_PERFSEL0;
1341 		word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL0, evt);
1342 	}
1343 
1344 	return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, word);
1345 }
1346 
1347 /* Method to clear crspace counter value */
mlxbf_pmc_clear_crspace_counter(unsigned int blk_num,u32 cnt_num)1348 static int mlxbf_pmc_clear_crspace_counter(unsigned int blk_num, u32 cnt_num)
1349 {
1350 	void __iomem *addr;
1351 
1352 	addr = pmc->block[blk_num].mmio_base +
1353 		MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) +
1354 		(cnt_num * 4);
1355 
1356 	return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, 0x0);
1357 }
1358 
1359 /* Method to program a counter to monitor an event */
mlxbf_pmc_program_counter(unsigned int blk_num,u32 cnt_num,u32 evt,bool is_l3)1360 static int mlxbf_pmc_program_counter(unsigned int blk_num, u32 cnt_num, u32 evt, bool is_l3)
1361 {
1362 	u64 perfctl, perfevt, perfmon_cfg;
1363 
1364 	if (cnt_num >= pmc->block[blk_num].counters)
1365 		return -ENODEV;
1366 
1367 	if (is_l3)
1368 		return mlxbf_pmc_program_l3_counter(blk_num, cnt_num, evt);
1369 
1370 	if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
1371 		return mlxbf_pmc_program_crspace_counter(blk_num, cnt_num,
1372 							 evt);
1373 
1374 	/* Configure the counter */
1375 	perfctl = FIELD_PREP(MLXBF_PMC_PERFCTL_EN0, 1);
1376 	perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_EB0, 0);
1377 	perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_ETRIG0, 1);
1378 	perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_AD0, 0);
1379 	perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_ACCM0, 0);
1380 	perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_MS0, 0);
1381 	perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_FM0, 0);
1382 
1383 	perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WDATA, perfctl);
1384 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR,
1385 				  MLXBF_PMC_PERFCTL);
1386 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1);
1387 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1);
1388 
1389 	if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base +
1390 				    cnt_num * MLXBF_PMC_REG_SIZE,
1391 			    MLXBF_PMC_WRITE_REG_64, perfmon_cfg))
1392 		return -EFAULT;
1393 
1394 	/* Select the event */
1395 	perfevt = FIELD_PREP(MLXBF_PMC_PERFEVT_EVTSEL, evt);
1396 
1397 	perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WDATA, perfevt);
1398 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR,
1399 				  MLXBF_PMC_PERFEVT);
1400 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1);
1401 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1);
1402 
1403 	if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base +
1404 				    cnt_num * MLXBF_PMC_REG_SIZE,
1405 			    MLXBF_PMC_WRITE_REG_64, perfmon_cfg))
1406 		return -EFAULT;
1407 
1408 	/* Clear the accumulator */
1409 	perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR,
1410 				 MLXBF_PMC_PERFACC0);
1411 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1);
1412 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1);
1413 
1414 	if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base +
1415 				    cnt_num * MLXBF_PMC_REG_SIZE,
1416 			    MLXBF_PMC_WRITE_REG_64, perfmon_cfg))
1417 		return -EFAULT;
1418 
1419 	return 0;
1420 }
1421 
1422 /* Method to handle l3 counter reads */
mlxbf_pmc_read_l3_counter(unsigned int blk_num,u32 cnt_num,u64 * result)1423 static int mlxbf_pmc_read_l3_counter(unsigned int blk_num, u32 cnt_num, u64 *result)
1424 {
1425 	u32 perfcnt_low = 0, perfcnt_high = 0;
1426 	int status;
1427 	u64 value;
1428 
1429 	status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
1430 					 MLXBF_PMC_L3C_PERF_CNT_LOW +
1431 					 cnt_num * MLXBF_PMC_L3C_REG_SIZE,
1432 				 &perfcnt_low);
1433 
1434 	if (status)
1435 		return status;
1436 
1437 	status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
1438 					 MLXBF_PMC_L3C_PERF_CNT_HIGH +
1439 					 cnt_num * MLXBF_PMC_L3C_REG_SIZE,
1440 				 &perfcnt_high);
1441 
1442 	if (status)
1443 		return status;
1444 
1445 	value = perfcnt_high;
1446 	value = value << 32;
1447 	value |= perfcnt_low;
1448 	*result = value;
1449 
1450 	return 0;
1451 }
1452 
1453 /* Method to handle crspace counter reads */
mlxbf_pmc_read_crspace_counter(unsigned int blk_num,u32 cnt_num,u64 * result)1454 static int mlxbf_pmc_read_crspace_counter(unsigned int blk_num, u32 cnt_num, u64 *result)
1455 {
1456 	int status = 0;
1457 	u32 value;
1458 
1459 	status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
1460 		MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) +
1461 		(cnt_num * 4), &value);
1462 	if (status)
1463 		return status;
1464 
1465 	*result = value;
1466 
1467 	return 0;
1468 }
1469 
1470 /* Method to read the counter value */
mlxbf_pmc_read_counter(unsigned int blk_num,u32 cnt_num,bool is_l3,u64 * result)1471 static int mlxbf_pmc_read_counter(unsigned int blk_num, u32 cnt_num, bool is_l3, u64 *result)
1472 {
1473 	u32 perfcfg_offset, perfval_offset;
1474 	u64 perfmon_cfg;
1475 	int status;
1476 
1477 	if (cnt_num >= pmc->block[blk_num].counters)
1478 		return -EINVAL;
1479 
1480 	if (is_l3)
1481 		return mlxbf_pmc_read_l3_counter(blk_num, cnt_num, result);
1482 
1483 	if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
1484 		return mlxbf_pmc_read_crspace_counter(blk_num, cnt_num, result);
1485 
1486 	perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE;
1487 	perfval_offset = perfcfg_offset +
1488 			 pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE;
1489 
1490 	/* Set counter in "read" mode */
1491 	perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR,
1492 				 MLXBF_PMC_PERFACC0);
1493 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1);
1494 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0);
1495 
1496 	status = mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset,
1497 				 MLXBF_PMC_WRITE_REG_64, perfmon_cfg);
1498 
1499 	if (status)
1500 		return status;
1501 
1502 	/* Get the counter value */
1503 	return mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset,
1504 			      MLXBF_PMC_READ_REG_64, result);
1505 }
1506 
1507 /* Method to read L3 block event */
mlxbf_pmc_read_l3_event(unsigned int blk_num,u32 cnt_num,u64 * result)1508 static int mlxbf_pmc_read_l3_event(unsigned int blk_num, u32 cnt_num, u64 *result)
1509 {
1510 	u32 perfcnt_sel = 0, perfcnt_sel_1 = 0, *wordaddr;
1511 	void __iomem *pmcaddr;
1512 	u64 evt;
1513 
1514 	/* Select appropriate register information */
1515 	switch (cnt_num) {
1516 	case 0 ... 3:
1517 		pmcaddr = pmc->block[blk_num].mmio_base +
1518 			  MLXBF_PMC_L3C_PERF_CNT_SEL;
1519 		wordaddr = &perfcnt_sel;
1520 		break;
1521 	case 4:
1522 		pmcaddr = pmc->block[blk_num].mmio_base +
1523 			  MLXBF_PMC_L3C_PERF_CNT_SEL_1;
1524 		wordaddr = &perfcnt_sel_1;
1525 		break;
1526 	default:
1527 		return -EINVAL;
1528 	}
1529 
1530 	if (mlxbf_pmc_readl(pmcaddr, wordaddr))
1531 		return -EINVAL;
1532 
1533 	/* Read from appropriate register field for the counter */
1534 	switch (cnt_num) {
1535 	case 0:
1536 		evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0, perfcnt_sel);
1537 		break;
1538 	case 1:
1539 		evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1, perfcnt_sel);
1540 		break;
1541 	case 2:
1542 		evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2, perfcnt_sel);
1543 		break;
1544 	case 3:
1545 		evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3, perfcnt_sel);
1546 		break;
1547 	case 4:
1548 		evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4,
1549 				perfcnt_sel_1);
1550 		break;
1551 	default:
1552 		return -EINVAL;
1553 	}
1554 	*result = evt;
1555 
1556 	return 0;
1557 }
1558 
1559 /* Method to read crspace block event */
mlxbf_pmc_read_crspace_event(unsigned int blk_num,u32 cnt_num,u64 * result)1560 static int mlxbf_pmc_read_crspace_event(unsigned int blk_num, u32 cnt_num, u64 *result)
1561 {
1562 	u32 word, evt;
1563 	void __iomem *addr;
1564 	int ret;
1565 
1566 	addr = pmc->block[blk_num].mmio_base +
1567 		((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ);
1568 	ret = mlxbf_pmc_readl(addr, &word);
1569 	if (ret)
1570 		return ret;
1571 
1572 	if (cnt_num % 2)
1573 		evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL1, word);
1574 	else
1575 		evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL0, word);
1576 
1577 	*result = evt;
1578 
1579 	return 0;
1580 }
1581 
1582 /* Method to find the event currently being monitored by a counter */
mlxbf_pmc_read_event(unsigned int blk_num,u32 cnt_num,bool is_l3,u64 * result)1583 static int mlxbf_pmc_read_event(unsigned int blk_num, u32 cnt_num, bool is_l3, u64 *result)
1584 {
1585 	u32 perfcfg_offset, perfval_offset;
1586 	u64 perfmon_cfg, perfevt;
1587 
1588 	if (cnt_num >= pmc->block[blk_num].counters)
1589 		return -EINVAL;
1590 
1591 	if (is_l3)
1592 		return mlxbf_pmc_read_l3_event(blk_num, cnt_num, result);
1593 
1594 	if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)
1595 		return mlxbf_pmc_read_crspace_event(blk_num, cnt_num, result);
1596 
1597 	perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE;
1598 	perfval_offset = perfcfg_offset +
1599 			 pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE;
1600 
1601 	/* Set counter in "read" mode */
1602 	perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR,
1603 				 MLXBF_PMC_PERFEVT);
1604 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1);
1605 	perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0);
1606 
1607 	if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset,
1608 			    MLXBF_PMC_WRITE_REG_64, perfmon_cfg))
1609 		return -EFAULT;
1610 
1611 	/* Get the event number */
1612 	if (mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset,
1613 			   MLXBF_PMC_READ_REG_64, &perfevt))
1614 		return -EFAULT;
1615 
1616 	*result = FIELD_GET(MLXBF_PMC_PERFEVT_EVTSEL, perfevt);
1617 
1618 	return 0;
1619 }
1620 
1621 /* Method to read a register */
mlxbf_pmc_read_reg(unsigned int blk_num,u32 offset,u64 * result)1622 static int mlxbf_pmc_read_reg(unsigned int blk_num, u32 offset, u64 *result)
1623 {
1624 	u32 reg;
1625 
1626 	if ((strstr(pmc->block_name[blk_num], "ecc")) ||
1627 	    (strstr(pmc->block_name[blk_num], "clock_measure"))) {
1628 		if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + offset,
1629 				    &reg))
1630 			return -EFAULT;
1631 
1632 		*result = reg;
1633 		return 0;
1634 	}
1635 
1636 	if (mlxbf_pmc_valid_range(blk_num, offset))
1637 		return mlxbf_pmc_read(pmc->block[blk_num].mmio_base + offset,
1638 				      MLXBF_PMC_READ_REG_64, result);
1639 
1640 	return -EINVAL;
1641 }
1642 
1643 /* Method to write to a register */
mlxbf_pmc_write_reg(unsigned int blk_num,u32 offset,u64 data)1644 static int mlxbf_pmc_write_reg(unsigned int blk_num, u32 offset, u64 data)
1645 {
1646 	if (strstr(pmc->block_name[blk_num], "clock_measure"))
1647 		return -EINVAL;
1648 
1649 	if (strstr(pmc->block_name[blk_num], "ecc")) {
1650 		return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + offset,
1651 				       MLXBF_PMC_WRITE_REG_32, data);
1652 	}
1653 
1654 	if (mlxbf_pmc_valid_range(blk_num, offset))
1655 		return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + offset,
1656 				       MLXBF_PMC_WRITE_REG_64, data);
1657 
1658 	return -EINVAL;
1659 }
1660 
1661 /* Show function for "counter" sysfs files */
mlxbf_pmc_counter_show(struct device * dev,struct device_attribute * attr,char * buf)1662 static ssize_t mlxbf_pmc_counter_show(struct device *dev,
1663 				      struct device_attribute *attr, char *buf)
1664 {
1665 	struct mlxbf_pmc_attribute *attr_counter = container_of(
1666 		attr, struct mlxbf_pmc_attribute, dev_attr);
1667 	unsigned int blk_num, cnt_num;
1668 	bool is_l3 = false;
1669 	int offset;
1670 	u64 value;
1671 
1672 	blk_num = attr_counter->nr;
1673 	cnt_num = attr_counter->index;
1674 
1675 	if (strstr(pmc->block_name[blk_num], "l3cache"))
1676 		is_l3 = true;
1677 
1678 	if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) ||
1679 	    (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)) {
1680 		if (mlxbf_pmc_read_counter(blk_num, cnt_num, is_l3, &value))
1681 			return -EINVAL;
1682 	} else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) {
1683 		offset = mlxbf_pmc_get_event_num(pmc->block_name[blk_num],
1684 						 attr->attr.name);
1685 		if (offset < 0)
1686 			return -EINVAL;
1687 		if (mlxbf_pmc_read_reg(blk_num, offset, &value))
1688 			return -EINVAL;
1689 	} else
1690 		return -EINVAL;
1691 
1692 	return sysfs_emit(buf, "0x%llx\n", value);
1693 }
1694 
1695 /* Store function for "counter" sysfs files */
mlxbf_pmc_counter_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1696 static ssize_t mlxbf_pmc_counter_store(struct device *dev,
1697 				       struct device_attribute *attr,
1698 				       const char *buf, size_t count)
1699 {
1700 	struct mlxbf_pmc_attribute *attr_counter = container_of(
1701 		attr, struct mlxbf_pmc_attribute, dev_attr);
1702 	unsigned int blk_num, cnt_num, data;
1703 	bool is_l3 = false;
1704 	u64 evt_num;
1705 	int offset;
1706 	int err;
1707 
1708 	blk_num = attr_counter->nr;
1709 	cnt_num = attr_counter->index;
1710 
1711 	err = kstrtouint(buf, 0, &data);
1712 	if (err < 0)
1713 		return err;
1714 
1715 	/* Allow non-zero writes only to the ecc regs */
1716 	if (!(strstr(pmc->block_name[blk_num], "ecc")) && data)
1717 		return -EINVAL;
1718 
1719 	/* Do not allow writes to the L3C regs */
1720 	if (strstr(pmc->block_name[blk_num], "l3cache"))
1721 		return -EINVAL;
1722 
1723 	if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) {
1724 		err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num);
1725 		if (err)
1726 			return err;
1727 		err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt_num,
1728 						is_l3);
1729 		if (err)
1730 			return err;
1731 	} else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) {
1732 		offset = mlxbf_pmc_get_event_num(pmc->block_name[blk_num],
1733 						 attr->attr.name);
1734 		if (offset < 0)
1735 			return -EINVAL;
1736 		err = mlxbf_pmc_write_reg(blk_num, offset, data);
1737 		if (err)
1738 			return err;
1739 	} else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
1740 		if (sscanf(attr->attr.name, "counter%u", &cnt_num) != 1)
1741 			return -EINVAL;
1742 		err = mlxbf_pmc_clear_crspace_counter(blk_num, cnt_num);
1743 	} else
1744 		return -EINVAL;
1745 
1746 	return count;
1747 }
1748 
1749 /* Show function for "event" sysfs files */
mlxbf_pmc_event_show(struct device * dev,struct device_attribute * attr,char * buf)1750 static ssize_t mlxbf_pmc_event_show(struct device *dev,
1751 				    struct device_attribute *attr, char *buf)
1752 {
1753 	struct mlxbf_pmc_attribute *attr_event = container_of(
1754 		attr, struct mlxbf_pmc_attribute, dev_attr);
1755 	unsigned int blk_num, cnt_num;
1756 	bool is_l3 = false;
1757 	char *evt_name;
1758 	u64 evt_num;
1759 	int err;
1760 
1761 	blk_num = attr_event->nr;
1762 	cnt_num = attr_event->index;
1763 
1764 	if (strstr(pmc->block_name[blk_num], "l3cache"))
1765 		is_l3 = true;
1766 
1767 	err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num);
1768 	if (err)
1769 		return sysfs_emit(buf, "No event being monitored\n");
1770 
1771 	evt_name = mlxbf_pmc_get_event_name(pmc->block_name[blk_num], evt_num);
1772 	if (!evt_name)
1773 		return -EINVAL;
1774 
1775 	return sysfs_emit(buf, "0x%llx: %s\n", evt_num, evt_name);
1776 }
1777 
1778 /* Store function for "event" sysfs files */
mlxbf_pmc_event_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1779 static ssize_t mlxbf_pmc_event_store(struct device *dev,
1780 				     struct device_attribute *attr,
1781 				     const char *buf, size_t count)
1782 {
1783 	struct mlxbf_pmc_attribute *attr_event = container_of(
1784 		attr, struct mlxbf_pmc_attribute, dev_attr);
1785 	unsigned int blk_num, cnt_num;
1786 	bool is_l3 = false;
1787 	int evt_num;
1788 	int err;
1789 
1790 	blk_num = attr_event->nr;
1791 	cnt_num = attr_event->index;
1792 
1793 	if (isalpha(buf[0])) {
1794 		evt_num = mlxbf_pmc_get_event_num(pmc->block_name[blk_num],
1795 						  buf);
1796 		if (evt_num < 0)
1797 			return -EINVAL;
1798 	} else {
1799 		err = kstrtouint(buf, 0, &evt_num);
1800 		if (err < 0)
1801 			return err;
1802 	}
1803 
1804 	if (strstr(pmc->block_name[blk_num], "l3cache"))
1805 		is_l3 = true;
1806 
1807 	err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt_num, is_l3);
1808 	if (err)
1809 		return err;
1810 
1811 	return count;
1812 }
1813 
1814 /* Show function for "event_list" sysfs files */
mlxbf_pmc_event_list_show(struct device * dev,struct device_attribute * attr,char * buf)1815 static ssize_t mlxbf_pmc_event_list_show(struct device *dev,
1816 					 struct device_attribute *attr,
1817 					 char *buf)
1818 {
1819 	struct mlxbf_pmc_attribute *attr_event_list = container_of(
1820 		attr, struct mlxbf_pmc_attribute, dev_attr);
1821 	const struct mlxbf_pmc_events *events;
1822 	char e_info[MLXBF_PMC_EVENT_INFO_LEN];
1823 	unsigned int blk_num, i, len = 0;
1824 	size_t size;
1825 	int ret = 0;
1826 
1827 	blk_num = attr_event_list->nr;
1828 
1829 	events = mlxbf_pmc_event_list(pmc->block_name[blk_num], &size);
1830 	if (!events)
1831 		return -EINVAL;
1832 
1833 	for (i = 0, buf[0] = '\0'; i < size; ++i) {
1834 		len += snprintf(e_info, sizeof(e_info), "0x%x: %s\n",
1835 				events[i].evt_num, events[i].evt_name);
1836 		if (len >= PAGE_SIZE)
1837 			break;
1838 		strcat(buf, e_info);
1839 		ret = len;
1840 	}
1841 
1842 	return ret;
1843 }
1844 
1845 /* Show function for "enable" sysfs files - only for l3cache & crspace */
mlxbf_pmc_enable_show(struct device * dev,struct device_attribute * attr,char * buf)1846 static ssize_t mlxbf_pmc_enable_show(struct device *dev,
1847 				     struct device_attribute *attr, char *buf)
1848 {
1849 	struct mlxbf_pmc_attribute *attr_enable = container_of(
1850 		attr, struct mlxbf_pmc_attribute, dev_attr);
1851 	unsigned int blk_num, value;
1852 	u32 perfcnt_cfg, word;
1853 
1854 	blk_num = attr_enable->nr;
1855 
1856 	if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
1857 		if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
1858 				MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
1859 				&word))
1860 			return -EINVAL;
1861 
1862 		value = FIELD_GET(MLXBF_PMC_CRSPACE_PERFMON_EN, word);
1863 	} else {
1864 		if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
1865 					    MLXBF_PMC_L3C_PERF_CNT_CFG,
1866 				    &perfcnt_cfg))
1867 			return -EINVAL;
1868 
1869 		value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg);
1870 	}
1871 
1872 	return sysfs_emit(buf, "%u\n", value);
1873 }
1874 
1875 /* Store function for "enable" sysfs files - only for l3cache & crspace */
mlxbf_pmc_enable_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1876 static ssize_t mlxbf_pmc_enable_store(struct device *dev,
1877 				      struct device_attribute *attr,
1878 				      const char *buf, size_t count)
1879 {
1880 	struct mlxbf_pmc_attribute *attr_enable = container_of(
1881 		attr, struct mlxbf_pmc_attribute, dev_attr);
1882 	unsigned int en, blk_num;
1883 	u32 word;
1884 	int err;
1885 
1886 	blk_num = attr_enable->nr;
1887 
1888 	err = kstrtouint(buf, 0, &en);
1889 	if (err < 0)
1890 		return err;
1891 
1892 	if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
1893 		err = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
1894 			MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
1895 			&word);
1896 		if (err)
1897 			return -EINVAL;
1898 
1899 		word &= ~MLXBF_PMC_CRSPACE_PERFMON_EN;
1900 		word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_EN, en);
1901 		if (en)
1902 			word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_CLR, 1);
1903 
1904 		mlxbf_pmc_write(pmc->block[blk_num].mmio_base +
1905 			MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters),
1906 			MLXBF_PMC_WRITE_REG_32, word);
1907 	} else {
1908 		if (en && en != 1)
1909 			return -EINVAL;
1910 
1911 		err = mlxbf_pmc_config_l3_counters(blk_num, false, !!en);
1912 		if (err)
1913 			return err;
1914 
1915 		if (en == 1) {
1916 			err = mlxbf_pmc_config_l3_counters(blk_num, true, false);
1917 			if (err)
1918 				return err;
1919 		}
1920 	}
1921 
1922 	return count;
1923 }
1924 
1925 /* Show function for "count_clock" sysfs files - only for crspace */
mlxbf_pmc_count_clock_show(struct device * dev,struct device_attribute * attr,char * buf)1926 static ssize_t mlxbf_pmc_count_clock_show(struct device *dev,
1927 					  struct device_attribute *attr, char *buf)
1928 {
1929 	struct mlxbf_pmc_attribute *attr_count_clock = container_of(
1930 		attr, struct mlxbf_pmc_attribute, dev_attr);
1931 	unsigned int blk_num;
1932 	u32 reg;
1933 
1934 	blk_num = attr_count_clock->nr;
1935 
1936 	if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base +
1937 			MLXBF_PMC_CRSPACE_PERFMON_COUNT_CLOCK(pmc->block[blk_num].counters),
1938 			&reg))
1939 		return -EINVAL;
1940 
1941 	return sysfs_emit(buf, "%u\n", reg);
1942 }
1943 
1944 /* Store function for "count_clock" sysfs files - only for crspace */
mlxbf_pmc_count_clock_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)1945 static ssize_t mlxbf_pmc_count_clock_store(struct device *dev,
1946 					   struct device_attribute *attr,
1947 					   const char *buf, size_t count)
1948 {
1949 	struct mlxbf_pmc_attribute *attr_count_clock = container_of(
1950 		attr, struct mlxbf_pmc_attribute, dev_attr);
1951 	unsigned int blk_num;
1952 	u32 reg;
1953 	int err;
1954 
1955 	blk_num = attr_count_clock->nr;
1956 
1957 	err = kstrtouint(buf, 0, &reg);
1958 	if (err < 0)
1959 		return err;
1960 
1961 	mlxbf_pmc_write(pmc->block[blk_num].mmio_base +
1962 		MLXBF_PMC_CRSPACE_PERFMON_COUNT_CLOCK(pmc->block[blk_num].counters),
1963 		MLXBF_PMC_WRITE_REG_32, reg);
1964 
1965 	return count;
1966 }
1967 
1968 /* Populate attributes for blocks with counters to monitor performance */
mlxbf_pmc_init_perftype_counter(struct device * dev,unsigned int blk_num)1969 static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_num)
1970 {
1971 	struct mlxbf_pmc_attribute *attr;
1972 	unsigned int i = 0, j = 0;
1973 
1974 	if (!mlxbf_pmc_event_supported(pmc->block_name[blk_num]))
1975 		return -ENOENT;
1976 
1977 	/* "event_list" sysfs to list events supported by the block */
1978 	attr = &pmc->block[blk_num].attr_event_list;
1979 	sysfs_attr_init(&attr->dev_attr.attr);
1980 	attr->dev_attr.attr.mode = 0444;
1981 	attr->dev_attr.show = mlxbf_pmc_event_list_show;
1982 	attr->nr = blk_num;
1983 	attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, "event_list");
1984 	if (!attr->dev_attr.attr.name)
1985 		return -ENOMEM;
1986 	pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr;
1987 	attr = NULL;
1988 
1989 	/* "enable" sysfs to start/stop the counters. Only in L3C blocks */
1990 	if (strstr(pmc->block_name[blk_num], "l3cache") ||
1991 	    ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) {
1992 		attr = &pmc->block[blk_num].attr_enable;
1993 		sysfs_attr_init(&attr->dev_attr.attr);
1994 		attr->dev_attr.attr.mode = 0644;
1995 		attr->dev_attr.show = mlxbf_pmc_enable_show;
1996 		attr->dev_attr.store = mlxbf_pmc_enable_store;
1997 		attr->nr = blk_num;
1998 		attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
1999 							  "enable");
2000 		if (!attr->dev_attr.attr.name)
2001 			return -ENOMEM;
2002 		pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr;
2003 		attr = NULL;
2004 	}
2005 
2006 	if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) {
2007 		/* Program crspace counters to count clock cycles using "count_clock" sysfs */
2008 		attr = &pmc->block[blk_num].attr_count_clock;
2009 		attr->dev_attr.attr.mode = 0644;
2010 		attr->dev_attr.show = mlxbf_pmc_count_clock_show;
2011 		attr->dev_attr.store = mlxbf_pmc_count_clock_store;
2012 		attr->nr = blk_num;
2013 		attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
2014 							  "count_clock");
2015 		if (!attr->dev_attr.attr.name)
2016 			return -ENOMEM;
2017 		pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr;
2018 		attr = NULL;
2019 	}
2020 
2021 	pmc->block[blk_num].attr_counter = devm_kcalloc(
2022 		dev, pmc->block[blk_num].counters,
2023 		sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL);
2024 	if (!pmc->block[blk_num].attr_counter)
2025 		return -ENOMEM;
2026 
2027 	pmc->block[blk_num].attr_event = devm_kcalloc(
2028 		dev, pmc->block[blk_num].counters,
2029 		sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL);
2030 	if (!pmc->block[blk_num].attr_event)
2031 		return -ENOMEM;
2032 
2033 	/* "eventX" and "counterX" sysfs to program and read counter values */
2034 	for (j = 0; j < pmc->block[blk_num].counters; ++j) {
2035 		attr = &pmc->block[blk_num].attr_counter[j];
2036 		sysfs_attr_init(&attr->dev_attr.attr);
2037 		attr->dev_attr.attr.mode = 0644;
2038 		attr->dev_attr.show = mlxbf_pmc_counter_show;
2039 		attr->dev_attr.store = mlxbf_pmc_counter_store;
2040 		attr->index = j;
2041 		attr->nr = blk_num;
2042 		attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, "counter%u", j);
2043 		if (!attr->dev_attr.attr.name)
2044 			return -ENOMEM;
2045 		pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr;
2046 		attr = NULL;
2047 
2048 		attr = &pmc->block[blk_num].attr_event[j];
2049 		sysfs_attr_init(&attr->dev_attr.attr);
2050 		attr->dev_attr.attr.mode = 0644;
2051 		attr->dev_attr.show = mlxbf_pmc_event_show;
2052 		attr->dev_attr.store = mlxbf_pmc_event_store;
2053 		attr->index = j;
2054 		attr->nr = blk_num;
2055 		attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, "event%u", j);
2056 		if (!attr->dev_attr.attr.name)
2057 			return -ENOMEM;
2058 		pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr;
2059 		attr = NULL;
2060 	}
2061 
2062 	return 0;
2063 }
2064 
2065 /* Populate attributes for blocks with registers to monitor performance */
mlxbf_pmc_init_perftype_reg(struct device * dev,unsigned int blk_num)2066 static int mlxbf_pmc_init_perftype_reg(struct device *dev, unsigned int blk_num)
2067 {
2068 	const struct mlxbf_pmc_events *events;
2069 	struct mlxbf_pmc_attribute *attr;
2070 	unsigned int i = 0;
2071 	size_t count = 0;
2072 
2073 	events = mlxbf_pmc_event_list(pmc->block_name[blk_num], &count);
2074 	if (!events)
2075 		return -ENOENT;
2076 
2077 	pmc->block[blk_num].attr_event = devm_kcalloc(
2078 		dev, count, sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL);
2079 	if (!pmc->block[blk_num].attr_event)
2080 		return -ENOMEM;
2081 
2082 	while (count > 0) {
2083 		--count;
2084 		attr = &pmc->block[blk_num].attr_event[count];
2085 		sysfs_attr_init(&attr->dev_attr.attr);
2086 		attr->dev_attr.attr.mode = 0644;
2087 		attr->dev_attr.show = mlxbf_pmc_counter_show;
2088 		attr->dev_attr.store = mlxbf_pmc_counter_store;
2089 		attr->nr = blk_num;
2090 		attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL,
2091 							  events[count].evt_name);
2092 		if (!attr->dev_attr.attr.name)
2093 			return -ENOMEM;
2094 		pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr;
2095 		attr = NULL;
2096 		i++;
2097 	}
2098 
2099 	return 0;
2100 }
2101 
2102 /* Helper to create the bfperf sysfs sub-directories and files */
mlxbf_pmc_create_groups(struct device * dev,unsigned int blk_num)2103 static int mlxbf_pmc_create_groups(struct device *dev, unsigned int blk_num)
2104 {
2105 	int err;
2106 
2107 	/* Populate attributes based on counter type */
2108 	if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) ||
2109 	    (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))
2110 		err = mlxbf_pmc_init_perftype_counter(dev, blk_num);
2111 	else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER)
2112 		err = mlxbf_pmc_init_perftype_reg(dev, blk_num);
2113 	else
2114 		err = -ENOENT;
2115 
2116 	if (err)
2117 		return err;
2118 
2119 	/* Add a new attribute_group for the block */
2120 	pmc->block[blk_num].block_attr_grp.attrs = pmc->block[blk_num].block_attr;
2121 	pmc->block[blk_num].block_attr_grp.name = devm_kasprintf(
2122 		dev, GFP_KERNEL, pmc->block_name[blk_num]);
2123 	if (!pmc->block[blk_num].block_attr_grp.name)
2124 		return -ENOMEM;
2125 	pmc->groups[pmc->group_num] = &pmc->block[blk_num].block_attr_grp;
2126 	pmc->group_num++;
2127 
2128 	return 0;
2129 }
2130 
mlxbf_pmc_guid_match(const guid_t * guid,const struct arm_smccc_res * res)2131 static bool mlxbf_pmc_guid_match(const guid_t *guid,
2132 				 const struct arm_smccc_res *res)
2133 {
2134 	guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16, res->a2,
2135 			      res->a2 >> 8, res->a2 >> 16, res->a2 >> 24,
2136 			      res->a3, res->a3 >> 8, res->a3 >> 16,
2137 			      res->a3 >> 24);
2138 
2139 	return guid_equal(guid, &id);
2140 }
2141 
2142 /* Helper to map the Performance Counters from the varios blocks */
mlxbf_pmc_map_counters(struct device * dev)2143 static int mlxbf_pmc_map_counters(struct device *dev)
2144 {
2145 	u64 info[MLXBF_PMC_INFO_SZ];
2146 	unsigned int tile_num, i;
2147 	int ret;
2148 
2149 	for (i = 0; i < pmc->total_blocks; ++i) {
2150 		/* Create sysfs for tiles only if block number <  tile_count */
2151 		if (strstr(pmc->block_name[i], "tilenet")) {
2152 			if (sscanf(pmc->block_name[i], "tilenet%u", &tile_num) != 1)
2153 				continue;
2154 
2155 			if (tile_num >= pmc->tile_count)
2156 				continue;
2157 		} else if (strstr(pmc->block_name[i], "tile")) {
2158 			if (sscanf(pmc->block_name[i], "tile%u", &tile_num) != 1)
2159 				continue;
2160 
2161 			if (tile_num >= pmc->tile_count)
2162 				continue;
2163 		}
2164 
2165 		/* Create sysfs only for enabled MSS blocks */
2166 		if (strstr(pmc->block_name[i], "mss") &&
2167 		    pmc->event_set == MLXBF_PMC_EVENT_SET_BF3) {
2168 			unsigned int mss_num;
2169 
2170 			if (sscanf(pmc->block_name[i], "mss%u", &mss_num) != 1)
2171 				continue;
2172 
2173 			if (!((pmc->mss_enable >> mss_num) & 0x1))
2174 				continue;
2175 		}
2176 
2177 		/* Create sysfs only for enabled EMI blocks */
2178 		if (strstr(pmc->block_name[i], "emi") &&
2179 		    pmc->event_set == MLXBF_PMC_EVENT_SET_BF3) {
2180 			unsigned int emi_num;
2181 
2182 			if (sscanf(pmc->block_name[i], "emi%u", &emi_num) != 1)
2183 				continue;
2184 
2185 			if (!((pmc->mss_enable >> (emi_num / 2)) & 0x1))
2186 				continue;
2187 		}
2188 
2189 		/* Create sysfs only for enabled LLT blocks */
2190 		if (strstr(pmc->block_name[i], "llt_miss")) {
2191 			unsigned int llt_num;
2192 
2193 			if (sscanf(pmc->block_name[i], "llt_miss%u", &llt_num) != 1)
2194 				continue;
2195 
2196 			if (!((pmc->llt_enable >> llt_num) & 0x1))
2197 				continue;
2198 		} else if (strstr(pmc->block_name[i], "llt")) {
2199 			unsigned int llt_num;
2200 
2201 			if (sscanf(pmc->block_name[i], "llt%u", &llt_num) != 1)
2202 				continue;
2203 
2204 			if (!((pmc->llt_enable >> llt_num) & 0x1))
2205 				continue;
2206 		}
2207 
2208 		/* Create sysfs only for enabled APT blocks */
2209 		if (strstr(pmc->block_name[i], "apt")) {
2210 			unsigned int apt_num;
2211 
2212 			if (sscanf(pmc->block_name[i], "apt%u", &apt_num) != 1)
2213 				continue;
2214 
2215 			if (!((pmc->apt_enable >> apt_num) & 0x1))
2216 				continue;
2217 		}
2218 
2219 		ret = device_property_read_u64_array(dev, pmc->block_name[i],
2220 						     info, MLXBF_PMC_INFO_SZ);
2221 		if (ret)
2222 			return ret;
2223 
2224 		/*
2225 		 * Do not remap if the proper SMC calls are supported,
2226 		 * since the SMC calls expect physical addresses.
2227 		 */
2228 		if (pmc->svc_sreg_support)
2229 			pmc->block[i].mmio_base = (void __iomem *)info[0];
2230 		else
2231 			pmc->block[i].mmio_base =
2232 				devm_ioremap(dev, info[0], info[1]);
2233 
2234 		pmc->block[i].blk_size = info[1];
2235 		pmc->block[i].counters = info[2];
2236 		pmc->block[i].type = info[3];
2237 
2238 		if (!pmc->block[i].mmio_base)
2239 			return -ENOMEM;
2240 
2241 		ret = mlxbf_pmc_create_groups(dev, i);
2242 		if (ret == -ENOENT) {
2243 			dev_warn(dev, "ignoring unsupported block: '%s'\n", pmc->block_name[i]);
2244 			continue;
2245 		}
2246 		if (ret)
2247 			return ret;
2248 	}
2249 
2250 	return 0;
2251 }
2252 
mlxbf_pmc_probe(struct platform_device * pdev)2253 static int mlxbf_pmc_probe(struct platform_device *pdev)
2254 {
2255 	struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev);
2256 	const char *hid = acpi_device_hid(acpi_dev);
2257 	struct device *dev = &pdev->dev;
2258 	struct arm_smccc_res res;
2259 	guid_t guid;
2260 	int ret;
2261 
2262 	/* Ensure we have the UUID we expect for this service. */
2263 	arm_smccc_smc(MLXBF_PMC_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res);
2264 	guid_parse(mlxbf_pmc_svc_uuid_str, &guid);
2265 	if (!mlxbf_pmc_guid_match(&guid, &res))
2266 		return -ENODEV;
2267 
2268 	pmc = devm_kzalloc(dev, sizeof(struct mlxbf_pmc_context), GFP_KERNEL);
2269 	if (!pmc)
2270 		return -ENOMEM;
2271 
2272 	/*
2273 	 * ACPI indicates whether we use SMCs to access registers or not.
2274 	 * If sreg_tbl_perf is not present, just assume we're not using SMCs.
2275 	 */
2276 	ret = device_property_read_u32(dev, "sec_reg_block",
2277 				       &pmc->sreg_tbl_perf);
2278 	if (ret) {
2279 		pmc->svc_sreg_support = false;
2280 	} else {
2281 		/*
2282 		 * Check service version to see if we actually do support the
2283 		 * needed SMCs. If we have the calls we need, mark support for
2284 		 * them in the pmc struct.
2285 		 */
2286 		arm_smccc_smc(MLXBF_PMC_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0,
2287 			      &res);
2288 		if (res.a0 == MLXBF_PMC_SVC_REQ_MAJOR &&
2289 		    res.a1 >= MLXBF_PMC_SVC_MIN_MINOR)
2290 			pmc->svc_sreg_support = true;
2291 		else
2292 			return -EINVAL;
2293 	}
2294 
2295 	if (!strcmp(hid, "MLNXBFD0"))
2296 		pmc->event_set = MLXBF_PMC_EVENT_SET_BF1;
2297 	else if (!strcmp(hid, "MLNXBFD1"))
2298 		pmc->event_set = MLXBF_PMC_EVENT_SET_BF2;
2299 	else if (!strcmp(hid, "MLNXBFD2"))
2300 		pmc->event_set = MLXBF_PMC_EVENT_SET_BF3;
2301 	else
2302 		return -ENODEV;
2303 
2304 	ret = device_property_read_u32(dev, "block_num", &pmc->total_blocks);
2305 	if (ret)
2306 		return ret;
2307 
2308 	ret = device_property_read_string_array(dev, "block_name",
2309 						pmc->block_name,
2310 						pmc->total_blocks);
2311 	if (ret != pmc->total_blocks)
2312 		return -EFAULT;
2313 
2314 	if (device_property_read_u32(dev, "tile_num", &pmc->tile_count)) {
2315 		if (device_property_read_u8(dev, "apt_enable", &pmc->apt_enable)) {
2316 			dev_warn(dev, "Number of APTs undefined, ignoring blocks\n");
2317 			pmc->apt_enable = 0;
2318 		}
2319 		if (device_property_read_u8(dev, "llt_enable", &pmc->llt_enable)) {
2320 			dev_warn(dev, "Number of LLTs undefined, ignoring blocks\n");
2321 			pmc->llt_enable = 0;
2322 		}
2323 		if (device_property_read_u8(dev, "mss_enable", &pmc->mss_enable)) {
2324 			dev_warn(dev, "Number of MSSs undefined, ignoring blocks\n");
2325 			pmc->mss_enable = 0;
2326 		}
2327 	}
2328 
2329 	pmc->pdev = pdev;
2330 	pmc->group_num = 0;
2331 
2332 	ret = mlxbf_pmc_map_counters(dev);
2333 	if (ret)
2334 		return ret;
2335 
2336 	pmc->hwmon_dev = devm_hwmon_device_register_with_groups(
2337 		dev, "bfperf", pmc, pmc->groups);
2338 	if (IS_ERR(pmc->hwmon_dev))
2339 		return PTR_ERR(pmc->hwmon_dev);
2340 	platform_set_drvdata(pdev, pmc);
2341 
2342 	return 0;
2343 }
2344 
2345 static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0", 0 },
2346 							    { "MLNXBFD1", 0 },
2347 							    { "MLNXBFD2", 0 },
2348 							    {}, };
2349 
2350 MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids);
2351 static struct platform_driver pmc_driver = {
2352 	.driver = { .name = "mlxbf-pmc",
2353 		    .acpi_match_table = ACPI_PTR(mlxbf_pmc_acpi_ids), },
2354 	.probe = mlxbf_pmc_probe,
2355 };
2356 
2357 module_platform_driver(pmc_driver);
2358 
2359 MODULE_AUTHOR("Shravan Kumar Ramani <sramani@mellanox.com>");
2360 MODULE_DESCRIPTION("Mellanox PMC driver");
2361 MODULE_LICENSE("Dual BSD/GPL");
2362