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