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 ®))
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 ®))
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, ®);
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