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, result: &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(val: value, addr); |
955 | else |
956 | writeq(val: 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: &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: &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(addr: pmc->block[blk_num].mmio_base + |
1093 | MLXBF_PMC_L3C_PERF_CNT_CFG, |
1094 | MLXBF_PMC_WRITE_REG_32, value: 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, enable: false, reset: 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(addr: pmcaddr, result: 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(addr: pmcaddr, MLXBF_PMC_WRITE_REG_32, value: *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 | (rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); |
1174 | ret = mlxbf_pmc_readl(addr, result: &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, value: 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, value: 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(addr: pmc->block[blk_num].mmio_base + |
1233 | cnt_num * MLXBF_PMC_REG_SIZE, |
1234 | MLXBF_PMC_WRITE_REG_64, value: 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(addr: pmc->block[blk_num].mmio_base + |
1247 | cnt_num * MLXBF_PMC_REG_SIZE, |
1248 | MLXBF_PMC_WRITE_REG_64, value: 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(addr: pmc->block[blk_num].mmio_base + |
1258 | cnt_num * MLXBF_PMC_REG_SIZE, |
1259 | MLXBF_PMC_WRITE_REG_64, value: 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(addr: pmc->block[blk_num].mmio_base + |
1274 | MLXBF_PMC_L3C_PERF_CNT_LOW + |
1275 | cnt_num * MLXBF_PMC_L3C_REG_SIZE, |
1276 | result: &perfcnt_low); |
1277 | |
1278 | if (status) |
1279 | return status; |
1280 | |
1281 | status = mlxbf_pmc_readl(addr: pmc->block[blk_num].mmio_base + |
1282 | MLXBF_PMC_L3C_PERF_CNT_HIGH + |
1283 | cnt_num * MLXBF_PMC_L3C_REG_SIZE, |
1284 | result: &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(addr: pmc->block[blk_num].mmio_base + |
1305 | MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) + |
1306 | (cnt_num * 4), result: &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(addr: pmc->block[blk_num].mmio_base + perfcfg_offset, |
1343 | MLXBF_PMC_WRITE_REG_64, value: perfmon_cfg); |
1344 | |
1345 | if (status) |
1346 | return status; |
1347 | |
1348 | /* Get the counter value */ |
1349 | return mlxbf_pmc_read(addr: 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(addr: pmcaddr, result: 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 | (rounddown(cnt_num, 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); |
1417 | ret = mlxbf_pmc_readl(addr, result: &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(addr: pmc->block[blk_num].mmio_base + perfcfg_offset, |
1458 | MLXBF_PMC_WRITE_REG_64, value: perfmon_cfg)) |
1459 | return -EFAULT; |
1460 | |
1461 | /* Get the event number */ |
1462 | if (mlxbf_pmc_read(addr: pmc->block[blk_num].mmio_base + perfval_offset, |
1463 | MLXBF_PMC_READ_REG_64, result: &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(addr: pmc->block[blk_num].mmio_base + offset, |
1478 | result: &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(addr: 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(addr: pmc->block[blk_num].mmio_base + offset, |
1497 | MLXBF_PMC_WRITE_REG_32, value: data); |
1498 | } |
1499 | |
1500 | if (mlxbf_pmc_valid_range(blk_num, offset)) |
1501 | return mlxbf_pmc_write(addr: pmc->block[blk_num].mmio_base + offset, |
1502 | MLXBF_PMC_WRITE_REG_64, value: 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, result: &value)) |
1526 | return -EINVAL; |
1527 | } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) { |
1528 | offset = mlxbf_pmc_get_event_num(blk: pmc->block_name[blk_num], |
1529 | evt: attr->attr.name); |
1530 | if (offset < 0) |
1531 | return -EINVAL; |
1532 | if (mlxbf_pmc_read_reg(blk_num, offset, result: &value)) |
1533 | return -EINVAL; |
1534 | } else |
1535 | return -EINVAL; |
1536 | |
1537 | return sysfs_emit(buf, fmt: "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(s: buf, base: 0, res: &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, result: &evt_num); |
1568 | if (err) |
1569 | return err; |
1570 | err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt: 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(blk: pmc->block_name[blk_num], |
1576 | evt: 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, result: &evt_num); |
1610 | if (err) |
1611 | return sysfs_emit(buf, fmt: "No event being monitored\n" ); |
1612 | |
1613 | evt_name = mlxbf_pmc_get_event_name(blk: pmc->block_name[blk_num], evt: evt_num); |
1614 | if (!evt_name) |
1615 | return -EINVAL; |
1616 | |
1617 | return sysfs_emit(buf, fmt: "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(blk: pmc->block_name[blk_num], |
1635 | evt: buf); |
1636 | if (evt_num < 0) |
1637 | return -EINVAL; |
1638 | } else { |
1639 | err = kstrtoint(s: buf, base: 0, res: &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: 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(blk: pmc->block_name[blk_num], size: &size); |
1668 | if (!events) |
1669 | return -EINVAL; |
1670 | |
1671 | for (i = 0, buf[0] = '\0'; i < size; ++i) { |
1672 | len += snprintf(buf: e_info, size: sizeof(e_info), fmt: "0x%x: %s\n" , |
1673 | events[i].evt_num, events[i].evt_name); |
1674 | if (len >= PAGE_SIZE) |
1675 | break; |
1676 | strcat(p: buf, q: 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(addr: pmc->block[blk_num].mmio_base + |
1696 | MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), |
1697 | result: &word)) |
1698 | return -EINVAL; |
1699 | |
1700 | value = FIELD_GET(MLXBF_PMC_CRSPACE_PERFMON_EN, word); |
1701 | } else { |
1702 | if (mlxbf_pmc_readl(addr: pmc->block[blk_num].mmio_base + |
1703 | MLXBF_PMC_L3C_PERF_CNT_CFG, |
1704 | result: &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, fmt: "%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(s: buf, base: 0, res: &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(addr: pmc->block[blk_num].mmio_base + |
1731 | MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), |
1732 | result: &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(addr: pmc->block[blk_num].mmio_base + |
1742 | MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), |
1743 | MLXBF_PMC_WRITE_REG_32, value: word); |
1744 | } else { |
1745 | if (en && en != 1) |
1746 | return -EINVAL; |
1747 | |
1748 | err = mlxbf_pmc_config_l3_counters(blk_num, enable: false, reset: !!en); |
1749 | if (err) |
1750 | return err; |
1751 | |
1752 | if (en == 1) { |
1753 | err = mlxbf_pmc_config_l3_counters(blk_num, enable: true, reset: 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, fmt: "event_list" ); |
1774 | pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr; |
1775 | attr = NULL; |
1776 | |
1777 | /* "enable" sysfs to start/stop the counters. Only in L3C blocks */ |
1778 | if (strstr(pmc->block_name[blk_num], "l3cache" ) || |
1779 | ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) { |
1780 | attr = &pmc->block[blk_num].attr_enable; |
1781 | attr->dev_attr.attr.mode = 0644; |
1782 | attr->dev_attr.show = mlxbf_pmc_enable_show; |
1783 | attr->dev_attr.store = mlxbf_pmc_enable_store; |
1784 | attr->nr = blk_num; |
1785 | attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, |
1786 | fmt: "enable" ); |
1787 | pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; |
1788 | attr = NULL; |
1789 | } |
1790 | |
1791 | pmc->block[blk_num].attr_counter = devm_kcalloc( |
1792 | dev, n: pmc->block[blk_num].counters, |
1793 | size: sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); |
1794 | if (!pmc->block[blk_num].attr_counter) |
1795 | return -ENOMEM; |
1796 | |
1797 | pmc->block[blk_num].attr_event = devm_kcalloc( |
1798 | dev, n: pmc->block[blk_num].counters, |
1799 | size: sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); |
1800 | if (!pmc->block[blk_num].attr_event) |
1801 | return -ENOMEM; |
1802 | |
1803 | /* "eventX" and "counterX" sysfs to program and read counter values */ |
1804 | for (j = 0; j < pmc->block[blk_num].counters; ++j) { |
1805 | attr = &pmc->block[blk_num].attr_counter[j]; |
1806 | attr->dev_attr.attr.mode = 0644; |
1807 | attr->dev_attr.show = mlxbf_pmc_counter_show; |
1808 | attr->dev_attr.store = mlxbf_pmc_counter_store; |
1809 | attr->index = j; |
1810 | attr->nr = blk_num; |
1811 | attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, |
1812 | fmt: "counter%d" , j); |
1813 | pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; |
1814 | attr = NULL; |
1815 | |
1816 | attr = &pmc->block[blk_num].attr_event[j]; |
1817 | attr->dev_attr.attr.mode = 0644; |
1818 | attr->dev_attr.show = mlxbf_pmc_event_show; |
1819 | attr->dev_attr.store = mlxbf_pmc_event_store; |
1820 | attr->index = j; |
1821 | attr->nr = blk_num; |
1822 | attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, |
1823 | fmt: "event%d" , j); |
1824 | pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; |
1825 | attr = NULL; |
1826 | } |
1827 | |
1828 | return 0; |
1829 | } |
1830 | |
1831 | /* Populate attributes for blocks with registers to monitor performance */ |
1832 | static int mlxbf_pmc_init_perftype_reg(struct device *dev, int blk_num) |
1833 | { |
1834 | struct mlxbf_pmc_attribute *attr; |
1835 | const struct mlxbf_pmc_events *events; |
1836 | int i = 0, j = 0; |
1837 | |
1838 | events = mlxbf_pmc_event_list(blk: pmc->block_name[blk_num], size: &j); |
1839 | if (!events) |
1840 | return -EINVAL; |
1841 | |
1842 | pmc->block[blk_num].attr_event = devm_kcalloc( |
1843 | dev, n: j, size: sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); |
1844 | if (!pmc->block[blk_num].attr_event) |
1845 | return -ENOMEM; |
1846 | |
1847 | while (j > 0) { |
1848 | --j; |
1849 | attr = &pmc->block[blk_num].attr_event[j]; |
1850 | attr->dev_attr.attr.mode = 0644; |
1851 | attr->dev_attr.show = mlxbf_pmc_counter_show; |
1852 | attr->dev_attr.store = mlxbf_pmc_counter_store; |
1853 | attr->nr = blk_num; |
1854 | attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, |
1855 | fmt: events[j].evt_name); |
1856 | pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr; |
1857 | attr = NULL; |
1858 | i++; |
1859 | } |
1860 | |
1861 | return 0; |
1862 | } |
1863 | |
1864 | /* Helper to create the bfperf sysfs sub-directories and files */ |
1865 | static int mlxbf_pmc_create_groups(struct device *dev, int blk_num) |
1866 | { |
1867 | int err; |
1868 | |
1869 | /* Populate attributes based on counter type */ |
1870 | if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) || |
1871 | (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)) |
1872 | err = mlxbf_pmc_init_perftype_counter(dev, blk_num); |
1873 | else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) |
1874 | err = mlxbf_pmc_init_perftype_reg(dev, blk_num); |
1875 | else |
1876 | err = -EINVAL; |
1877 | |
1878 | if (err) |
1879 | return err; |
1880 | |
1881 | /* Add a new attribute_group for the block */ |
1882 | pmc->block[blk_num].block_attr_grp.attrs = pmc->block[blk_num].block_attr; |
1883 | pmc->block[blk_num].block_attr_grp.name = devm_kasprintf( |
1884 | dev, GFP_KERNEL, fmt: pmc->block_name[blk_num]); |
1885 | pmc->groups[pmc->group_num] = &pmc->block[blk_num].block_attr_grp; |
1886 | pmc->group_num++; |
1887 | |
1888 | return 0; |
1889 | } |
1890 | |
1891 | static bool mlxbf_pmc_guid_match(const guid_t *guid, |
1892 | const struct arm_smccc_res *res) |
1893 | { |
1894 | guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16, res->a2, |
1895 | res->a2 >> 8, res->a2 >> 16, res->a2 >> 24, |
1896 | res->a3, res->a3 >> 8, res->a3 >> 16, |
1897 | res->a3 >> 24); |
1898 | |
1899 | return guid_equal(u1: guid, u2: &id); |
1900 | } |
1901 | |
1902 | /* Helper to map the Performance Counters from the varios blocks */ |
1903 | static int mlxbf_pmc_map_counters(struct device *dev) |
1904 | { |
1905 | uint64_t info[MLXBF_PMC_INFO_SZ]; |
1906 | int i, tile_num, ret; |
1907 | |
1908 | for (i = 0; i < pmc->total_blocks; ++i) { |
1909 | /* Create sysfs for tiles only if block number < tile_count */ |
1910 | if (strstr(pmc->block_name[i], "tilenet" )) { |
1911 | if (sscanf(pmc->block_name[i], "tilenet%d" , &tile_num) != 1) |
1912 | continue; |
1913 | |
1914 | if (tile_num >= pmc->tile_count) |
1915 | continue; |
1916 | } else if (strstr(pmc->block_name[i], "tile" )) { |
1917 | if (sscanf(pmc->block_name[i], "tile%d" , &tile_num) != 1) |
1918 | continue; |
1919 | |
1920 | if (tile_num >= pmc->tile_count) |
1921 | continue; |
1922 | } |
1923 | |
1924 | /* Create sysfs only for enabled MSS blocks */ |
1925 | if (strstr(pmc->block_name[i], "mss" ) && |
1926 | pmc->event_set == MLXBF_PMC_EVENT_SET_BF3) { |
1927 | int mss_num; |
1928 | |
1929 | if (sscanf(pmc->block_name[i], "mss%d" , &mss_num) != 1) |
1930 | continue; |
1931 | |
1932 | if (!((pmc->mss_enable >> mss_num) & 0x1)) |
1933 | continue; |
1934 | } |
1935 | |
1936 | /* Create sysfs only for enabled LLT blocks */ |
1937 | if (strstr(pmc->block_name[i], "llt_miss" )) { |
1938 | int llt_num; |
1939 | |
1940 | if (sscanf(pmc->block_name[i], "llt_miss%d" , &llt_num) != 1) |
1941 | continue; |
1942 | |
1943 | if (!((pmc->llt_enable >> llt_num) & 0x1)) |
1944 | continue; |
1945 | } else if (strstr(pmc->block_name[i], "llt" )) { |
1946 | int llt_num; |
1947 | |
1948 | if (sscanf(pmc->block_name[i], "llt%d" , &llt_num) != 1) |
1949 | continue; |
1950 | |
1951 | if (!((pmc->llt_enable >> llt_num) & 0x1)) |
1952 | continue; |
1953 | } |
1954 | |
1955 | ret = device_property_read_u64_array(dev, propname: pmc->block_name[i], |
1956 | val: info, MLXBF_PMC_INFO_SZ); |
1957 | if (ret) |
1958 | return ret; |
1959 | |
1960 | /* |
1961 | * Do not remap if the proper SMC calls are supported, |
1962 | * since the SMC calls expect physical addresses. |
1963 | */ |
1964 | if (pmc->svc_sreg_support) |
1965 | pmc->block[i].mmio_base = (void __iomem *)info[0]; |
1966 | else |
1967 | pmc->block[i].mmio_base = |
1968 | devm_ioremap(dev, offset: info[0], size: info[1]); |
1969 | |
1970 | pmc->block[i].blk_size = info[1]; |
1971 | pmc->block[i].counters = info[2]; |
1972 | pmc->block[i].type = info[3]; |
1973 | |
1974 | if (!pmc->block[i].mmio_base) |
1975 | return -ENOMEM; |
1976 | |
1977 | ret = mlxbf_pmc_create_groups(dev, blk_num: i); |
1978 | if (ret) |
1979 | return ret; |
1980 | } |
1981 | |
1982 | return 0; |
1983 | } |
1984 | |
1985 | static int mlxbf_pmc_probe(struct platform_device *pdev) |
1986 | { |
1987 | struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); |
1988 | const char *hid = acpi_device_hid(device: acpi_dev); |
1989 | struct device *dev = &pdev->dev; |
1990 | struct arm_smccc_res res; |
1991 | guid_t guid; |
1992 | int ret; |
1993 | |
1994 | /* Ensure we have the UUID we expect for this service. */ |
1995 | arm_smccc_smc(MLXBF_PMC_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res); |
1996 | guid_parse(uuid: mlxbf_pmc_svc_uuid_str, u: &guid); |
1997 | if (!mlxbf_pmc_guid_match(guid: &guid, res: &res)) |
1998 | return -ENODEV; |
1999 | |
2000 | pmc = devm_kzalloc(dev, size: sizeof(struct mlxbf_pmc_context), GFP_KERNEL); |
2001 | if (!pmc) |
2002 | return -ENOMEM; |
2003 | |
2004 | /* |
2005 | * ACPI indicates whether we use SMCs to access registers or not. |
2006 | * If sreg_tbl_perf is not present, just assume we're not using SMCs. |
2007 | */ |
2008 | ret = device_property_read_u32(dev, propname: "sec_reg_block" , |
2009 | val: &pmc->sreg_tbl_perf); |
2010 | if (ret) { |
2011 | pmc->svc_sreg_support = false; |
2012 | } else { |
2013 | /* |
2014 | * Check service version to see if we actually do support the |
2015 | * needed SMCs. If we have the calls we need, mark support for |
2016 | * them in the pmc struct. |
2017 | */ |
2018 | arm_smccc_smc(MLXBF_PMC_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, |
2019 | &res); |
2020 | if (res.a0 == MLXBF_PMC_SVC_REQ_MAJOR && |
2021 | res.a1 >= MLXBF_PMC_SVC_MIN_MINOR) |
2022 | pmc->svc_sreg_support = true; |
2023 | else |
2024 | return -EINVAL; |
2025 | } |
2026 | |
2027 | if (!strcmp(hid, "MLNXBFD0" )) |
2028 | pmc->event_set = MLXBF_PMC_EVENT_SET_BF1; |
2029 | else if (!strcmp(hid, "MLNXBFD1" )) |
2030 | pmc->event_set = MLXBF_PMC_EVENT_SET_BF2; |
2031 | else if (!strcmp(hid, "MLNXBFD2" )) |
2032 | pmc->event_set = MLXBF_PMC_EVENT_SET_BF3; |
2033 | else |
2034 | return -ENODEV; |
2035 | |
2036 | ret = device_property_read_u32(dev, propname: "block_num" , val: &pmc->total_blocks); |
2037 | if (ret) |
2038 | return ret; |
2039 | |
2040 | ret = device_property_read_string_array(dev, propname: "block_name" , |
2041 | val: pmc->block_name, |
2042 | nval: pmc->total_blocks); |
2043 | if (ret != pmc->total_blocks) |
2044 | return -EFAULT; |
2045 | |
2046 | if (device_property_read_u32(dev, propname: "tile_num" , val: &pmc->tile_count)) { |
2047 | if (device_property_read_u8(dev, propname: "llt_enable" , val: &pmc->llt_enable)) { |
2048 | dev_err(dev, "Number of tiles/LLTs undefined\n" ); |
2049 | return -EINVAL; |
2050 | } |
2051 | if (device_property_read_u8(dev, propname: "mss_enable" , val: &pmc->mss_enable)) { |
2052 | dev_err(dev, "Number of tiles/MSSs undefined\n" ); |
2053 | return -EINVAL; |
2054 | } |
2055 | } |
2056 | |
2057 | pmc->pdev = pdev; |
2058 | pmc->group_num = 0; |
2059 | |
2060 | ret = mlxbf_pmc_map_counters(dev); |
2061 | if (ret) |
2062 | return ret; |
2063 | |
2064 | pmc->hwmon_dev = devm_hwmon_device_register_with_groups( |
2065 | dev, name: "bfperf" , drvdata: pmc, groups: pmc->groups); |
2066 | platform_set_drvdata(pdev, data: pmc); |
2067 | |
2068 | return 0; |
2069 | } |
2070 | |
2071 | static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0" , 0 }, |
2072 | { "MLNXBFD1" , 0 }, |
2073 | { "MLNXBFD2" , 0 }, |
2074 | {}, }; |
2075 | |
2076 | MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids); |
2077 | static struct platform_driver pmc_driver = { |
2078 | .driver = { .name = "mlxbf-pmc" , |
2079 | .acpi_match_table = ACPI_PTR(mlxbf_pmc_acpi_ids), }, |
2080 | .probe = mlxbf_pmc_probe, |
2081 | }; |
2082 | |
2083 | module_platform_driver(pmc_driver); |
2084 | |
2085 | MODULE_AUTHOR("Shravan Kumar Ramani <sramani@mellanox.com>" ); |
2086 | MODULE_DESCRIPTION("Mellanox PMC driver" ); |
2087 | MODULE_LICENSE("Dual BSD/GPL" ); |
2088 | |