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