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 unsigned int index; 103 unsigned 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 unsigned 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 u32 total_blocks; 153 u32 tile_count; 154 u8 llt_enable; 155 u8 mss_enable; 156 u32 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 u32 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 u32 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, u32 command, u64 *result) 869 { 870 struct arm_smccc_res res; 871 int status, err = 0; 872 873 arm_smccc_smc(command, pmc->sreg_tbl_perf, (uintptr_t)addr, 0, 0, 0, 0, 874 0, &res); 875 876 status = res.a0; 877 878 switch (status) { 879 case PSCI_RET_NOT_SUPPORTED: 880 err = -EINVAL; 881 break; 882 case MLXBF_PMC_SMCCC_ACCESS_VIOLATION: 883 err = -EACCES; 884 break; 885 default: 886 *result = res.a1; 887 break; 888 } 889 890 return err; 891 } 892 893 /* Read from a performance counter */ 894 static int mlxbf_pmc_read(void __iomem *addr, u32 command, u64 *result) 895 { 896 if (pmc->svc_sreg_support) 897 return mlxbf_pmc_secure_read(addr, command, result); 898 899 if (command == MLXBF_PMC_READ_REG_32) 900 *result = readl(addr); 901 else 902 *result = readq(addr); 903 904 return 0; 905 } 906 907 /* Convenience function for 32-bit reads */ 908 static int mlxbf_pmc_readl(void __iomem *addr, u32 *result) 909 { 910 u64 read_out; 911 int status; 912 913 status = mlxbf_pmc_read(addr, MLXBF_PMC_READ_REG_32, &read_out); 914 if (status) 915 return status; 916 *result = (u32)read_out; 917 918 return 0; 919 } 920 921 /* Calls an SMC to access a performance register */ 922 static int mlxbf_pmc_secure_write(void __iomem *addr, u32 command, u64 value) 923 { 924 struct arm_smccc_res res; 925 int status, err = 0; 926 927 arm_smccc_smc(command, pmc->sreg_tbl_perf, value, (uintptr_t)addr, 0, 0, 928 0, 0, &res); 929 930 status = res.a0; 931 932 switch (status) { 933 case PSCI_RET_NOT_SUPPORTED: 934 err = -EINVAL; 935 break; 936 case MLXBF_PMC_SMCCC_ACCESS_VIOLATION: 937 err = -EACCES; 938 break; 939 } 940 941 return err; 942 } 943 944 /* Write to a performance counter */ 945 static int mlxbf_pmc_write(void __iomem *addr, int command, u64 value) 946 { 947 if (pmc->svc_sreg_support) 948 return mlxbf_pmc_secure_write(addr, command, value); 949 950 if (command == MLXBF_PMC_WRITE_REG_32) 951 writel(value, addr); 952 else 953 writeq(value, addr); 954 955 return 0; 956 } 957 958 /* Check if the register offset is within the mapped region for the block */ 959 static bool mlxbf_pmc_valid_range(unsigned int blk_num, u32 offset) 960 { 961 if ((offset >= 0) && !(offset % MLXBF_PMC_REG_SIZE) && 962 (offset + MLXBF_PMC_REG_SIZE <= pmc->block[blk_num].blk_size)) 963 return true; /* inside the mapped PMC space */ 964 965 return false; 966 } 967 968 /* Get the event list corresponding to a certain block */ 969 static const struct mlxbf_pmc_events *mlxbf_pmc_event_list(const char *blk, size_t *psize) 970 { 971 const struct mlxbf_pmc_events *events; 972 size_t size; 973 974 if (strstr(blk, "tilenet")) { 975 events = mlxbf_pmc_hnfnet_events; 976 size = ARRAY_SIZE(mlxbf_pmc_hnfnet_events); 977 } else if (strstr(blk, "tile")) { 978 events = mlxbf_pmc_hnf_events; 979 size = ARRAY_SIZE(mlxbf_pmc_hnf_events); 980 } else if (strstr(blk, "triogen")) { 981 events = mlxbf_pmc_smgen_events; 982 size = ARRAY_SIZE(mlxbf_pmc_smgen_events); 983 } else if (strstr(blk, "trio")) { 984 switch (pmc->event_set) { 985 case MLXBF_PMC_EVENT_SET_BF1: 986 events = mlxbf_pmc_trio_events_1; 987 size = ARRAY_SIZE(mlxbf_pmc_trio_events_1); 988 break; 989 case MLXBF_PMC_EVENT_SET_BF2: 990 events = mlxbf_pmc_trio_events_2; 991 size = ARRAY_SIZE(mlxbf_pmc_trio_events_2); 992 break; 993 default: 994 events = NULL; 995 size = 0; 996 break; 997 } 998 } else if (strstr(blk, "mss")) { 999 switch (pmc->event_set) { 1000 case MLXBF_PMC_EVENT_SET_BF1: 1001 case MLXBF_PMC_EVENT_SET_BF2: 1002 events = mlxbf_pmc_mss_events_1; 1003 size = ARRAY_SIZE(mlxbf_pmc_mss_events_1); 1004 break; 1005 case MLXBF_PMC_EVENT_SET_BF3: 1006 events = mlxbf_pmc_mss_events_3; 1007 size = ARRAY_SIZE(mlxbf_pmc_mss_events_3); 1008 break; 1009 default: 1010 events = NULL; 1011 size = 0; 1012 break; 1013 } 1014 } else if (strstr(blk, "ecc")) { 1015 events = mlxbf_pmc_ecc_events; 1016 size = ARRAY_SIZE(mlxbf_pmc_ecc_events); 1017 } else if (strstr(blk, "pcie")) { 1018 events = mlxbf_pmc_pcie_events; 1019 size = ARRAY_SIZE(mlxbf_pmc_pcie_events); 1020 } else if (strstr(blk, "l3cache")) { 1021 events = mlxbf_pmc_l3c_events; 1022 size = ARRAY_SIZE(mlxbf_pmc_l3c_events); 1023 } else if (strstr(blk, "gic")) { 1024 events = mlxbf_pmc_smgen_events; 1025 size = ARRAY_SIZE(mlxbf_pmc_smgen_events); 1026 } else if (strstr(blk, "smmu")) { 1027 events = mlxbf_pmc_smgen_events; 1028 size = ARRAY_SIZE(mlxbf_pmc_smgen_events); 1029 } else if (strstr(blk, "llt_miss")) { 1030 events = mlxbf_pmc_llt_miss_events; 1031 size = ARRAY_SIZE(mlxbf_pmc_llt_miss_events); 1032 } else if (strstr(blk, "llt")) { 1033 events = mlxbf_pmc_llt_events; 1034 size = ARRAY_SIZE(mlxbf_pmc_llt_events); 1035 } else { 1036 events = NULL; 1037 size = 0; 1038 } 1039 1040 if (psize) 1041 *psize = size; 1042 1043 return events; 1044 } 1045 1046 static bool mlxbf_pmc_event_supported(const char *blk) 1047 { 1048 return !!mlxbf_pmc_event_list(blk, NULL); 1049 } 1050 1051 /* Get the event number given the name */ 1052 static int mlxbf_pmc_get_event_num(const char *blk, const char *evt) 1053 { 1054 const struct mlxbf_pmc_events *events; 1055 unsigned int i; 1056 size_t size; 1057 1058 events = mlxbf_pmc_event_list(blk, &size); 1059 if (!events) 1060 return -EINVAL; 1061 1062 for (i = 0; i < size; ++i) { 1063 if (!strcmp(evt, events[i].evt_name)) 1064 return events[i].evt_num; 1065 } 1066 1067 return -ENODEV; 1068 } 1069 1070 /* Get the event number given the name */ 1071 static char *mlxbf_pmc_get_event_name(const char *blk, u32 evt) 1072 { 1073 const struct mlxbf_pmc_events *events; 1074 unsigned int i; 1075 size_t size; 1076 1077 events = mlxbf_pmc_event_list(blk, &size); 1078 if (!events) 1079 return NULL; 1080 1081 for (i = 0; i < size; ++i) { 1082 if (evt == events[i].evt_num) 1083 return events[i].evt_name; 1084 } 1085 1086 return NULL; 1087 } 1088 1089 /* Method to enable/disable/reset l3cache counters */ 1090 static int mlxbf_pmc_config_l3_counters(unsigned int blk_num, bool enable, bool reset) 1091 { 1092 u32 perfcnt_cfg = 0; 1093 1094 if (enable) 1095 perfcnt_cfg |= MLXBF_PMC_L3C_PERF_CNT_CFG_EN; 1096 if (reset) 1097 perfcnt_cfg |= MLXBF_PMC_L3C_PERF_CNT_CFG_RST; 1098 1099 return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + 1100 MLXBF_PMC_L3C_PERF_CNT_CFG, 1101 MLXBF_PMC_WRITE_REG_32, perfcnt_cfg); 1102 } 1103 1104 /* Method to handle l3cache counter programming */ 1105 static int mlxbf_pmc_program_l3_counter(unsigned int blk_num, u32 cnt_num, u32 evt) 1106 { 1107 u32 perfcnt_sel_1 = 0, perfcnt_sel = 0, *wordaddr; 1108 void __iomem *pmcaddr; 1109 int ret; 1110 1111 /* Disable all counters before programming them */ 1112 if (mlxbf_pmc_config_l3_counters(blk_num, false, false)) 1113 return -EINVAL; 1114 1115 /* Select appropriate register information */ 1116 switch (cnt_num) { 1117 case 0 ... 3: 1118 pmcaddr = pmc->block[blk_num].mmio_base + 1119 MLXBF_PMC_L3C_PERF_CNT_SEL; 1120 wordaddr = &perfcnt_sel; 1121 break; 1122 case 4: 1123 pmcaddr = pmc->block[blk_num].mmio_base + 1124 MLXBF_PMC_L3C_PERF_CNT_SEL_1; 1125 wordaddr = &perfcnt_sel_1; 1126 break; 1127 default: 1128 return -EINVAL; 1129 } 1130 1131 ret = mlxbf_pmc_readl(pmcaddr, wordaddr); 1132 if (ret) 1133 return ret; 1134 1135 switch (cnt_num) { 1136 case 0: 1137 perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0; 1138 perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0, 1139 evt); 1140 break; 1141 case 1: 1142 perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1; 1143 perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1, 1144 evt); 1145 break; 1146 case 2: 1147 perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2; 1148 perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2, 1149 evt); 1150 break; 1151 case 3: 1152 perfcnt_sel &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3; 1153 perfcnt_sel |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3, 1154 evt); 1155 break; 1156 case 4: 1157 perfcnt_sel_1 &= ~MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4; 1158 perfcnt_sel_1 |= FIELD_PREP(MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4, 1159 evt); 1160 break; 1161 default: 1162 return -EINVAL; 1163 } 1164 1165 return mlxbf_pmc_write(pmcaddr, MLXBF_PMC_WRITE_REG_32, *wordaddr); 1166 } 1167 1168 /* Method to handle crspace counter programming */ 1169 static int mlxbf_pmc_program_crspace_counter(unsigned int blk_num, u32 cnt_num, u32 evt) 1170 { 1171 void *addr; 1172 u32 word; 1173 int ret; 1174 1175 addr = pmc->block[blk_num].mmio_base + 1176 ((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); 1177 ret = mlxbf_pmc_readl(addr, &word); 1178 if (ret) 1179 return ret; 1180 1181 if (cnt_num % 2) { 1182 word &= ~MLXBF_PMC_CRSPACE_PERFSEL1; 1183 word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL1, evt); 1184 } else { 1185 word &= ~MLXBF_PMC_CRSPACE_PERFSEL0; 1186 word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFSEL0, evt); 1187 } 1188 1189 return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, word); 1190 } 1191 1192 /* Method to clear crspace counter value */ 1193 static int mlxbf_pmc_clear_crspace_counter(unsigned int blk_num, u32 cnt_num) 1194 { 1195 void *addr; 1196 1197 addr = pmc->block[blk_num].mmio_base + 1198 MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) + 1199 (cnt_num * 4); 1200 1201 return mlxbf_pmc_write(addr, MLXBF_PMC_WRITE_REG_32, 0x0); 1202 } 1203 1204 /* Method to program a counter to monitor an event */ 1205 static int mlxbf_pmc_program_counter(unsigned int blk_num, u32 cnt_num, u32 evt, bool is_l3) 1206 { 1207 u64 perfctl, perfevt, perfmon_cfg; 1208 1209 if (cnt_num >= pmc->block[blk_num].counters) 1210 return -ENODEV; 1211 1212 if (is_l3) 1213 return mlxbf_pmc_program_l3_counter(blk_num, cnt_num, evt); 1214 1215 if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) 1216 return mlxbf_pmc_program_crspace_counter(blk_num, cnt_num, 1217 evt); 1218 1219 /* Configure the counter */ 1220 perfctl = FIELD_PREP(MLXBF_PMC_PERFCTL_EN0, 1); 1221 perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_EB0, 0); 1222 perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_ETRIG0, 1); 1223 perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_AD0, 0); 1224 perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_ACCM0, 0); 1225 perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_MS0, 0); 1226 perfctl |= FIELD_PREP(MLXBF_PMC_PERFCTL_FM0, 0); 1227 1228 perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WDATA, perfctl); 1229 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, 1230 MLXBF_PMC_PERFCTL); 1231 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); 1232 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); 1233 1234 if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + 1235 cnt_num * MLXBF_PMC_REG_SIZE, 1236 MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) 1237 return -EFAULT; 1238 1239 /* Select the event */ 1240 perfevt = FIELD_PREP(MLXBF_PMC_PERFEVT_EVTSEL, evt); 1241 1242 perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WDATA, perfevt); 1243 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, 1244 MLXBF_PMC_PERFEVT); 1245 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); 1246 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); 1247 1248 if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + 1249 cnt_num * MLXBF_PMC_REG_SIZE, 1250 MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) 1251 return -EFAULT; 1252 1253 /* Clear the accumulator */ 1254 perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, 1255 MLXBF_PMC_PERFACC0); 1256 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); 1257 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 1); 1258 1259 if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + 1260 cnt_num * MLXBF_PMC_REG_SIZE, 1261 MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) 1262 return -EFAULT; 1263 1264 return 0; 1265 } 1266 1267 /* Method to handle l3 counter reads */ 1268 static int mlxbf_pmc_read_l3_counter(unsigned int blk_num, u32 cnt_num, u64 *result) 1269 { 1270 u32 perfcnt_low = 0, perfcnt_high = 0; 1271 int status; 1272 u64 value; 1273 1274 status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + 1275 MLXBF_PMC_L3C_PERF_CNT_LOW + 1276 cnt_num * MLXBF_PMC_L3C_REG_SIZE, 1277 &perfcnt_low); 1278 1279 if (status) 1280 return status; 1281 1282 status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + 1283 MLXBF_PMC_L3C_PERF_CNT_HIGH + 1284 cnt_num * MLXBF_PMC_L3C_REG_SIZE, 1285 &perfcnt_high); 1286 1287 if (status) 1288 return status; 1289 1290 value = perfcnt_high; 1291 value = value << 32; 1292 value |= perfcnt_low; 1293 *result = value; 1294 1295 return 0; 1296 } 1297 1298 /* Method to handle crspace counter reads */ 1299 static int mlxbf_pmc_read_crspace_counter(unsigned int blk_num, u32 cnt_num, u64 *result) 1300 { 1301 int status = 0; 1302 u32 value; 1303 1304 status = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + 1305 MLXBF_PMC_CRSPACE_PERFMON_VAL0(pmc->block[blk_num].counters) + 1306 (cnt_num * 4), &value); 1307 if (status) 1308 return status; 1309 1310 *result = value; 1311 1312 return 0; 1313 } 1314 1315 /* Method to read the counter value */ 1316 static int mlxbf_pmc_read_counter(unsigned int blk_num, u32 cnt_num, bool is_l3, u64 *result) 1317 { 1318 u32 perfcfg_offset, perfval_offset; 1319 u64 perfmon_cfg; 1320 int status; 1321 1322 if (cnt_num >= pmc->block[blk_num].counters) 1323 return -EINVAL; 1324 1325 if (is_l3) 1326 return mlxbf_pmc_read_l3_counter(blk_num, cnt_num, result); 1327 1328 if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) 1329 return mlxbf_pmc_read_crspace_counter(blk_num, cnt_num, result); 1330 1331 perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE; 1332 perfval_offset = perfcfg_offset + 1333 pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE; 1334 1335 /* Set counter in "read" mode */ 1336 perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, 1337 MLXBF_PMC_PERFACC0); 1338 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); 1339 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); 1340 1341 status = mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, 1342 MLXBF_PMC_WRITE_REG_64, perfmon_cfg); 1343 1344 if (status) 1345 return status; 1346 1347 /* Get the counter value */ 1348 return mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, 1349 MLXBF_PMC_READ_REG_64, result); 1350 } 1351 1352 /* Method to read L3 block event */ 1353 static int mlxbf_pmc_read_l3_event(unsigned int blk_num, u32 cnt_num, u64 *result) 1354 { 1355 u32 perfcnt_sel = 0, perfcnt_sel_1 = 0, *wordaddr; 1356 void __iomem *pmcaddr; 1357 u64 evt; 1358 1359 /* Select appropriate register information */ 1360 switch (cnt_num) { 1361 case 0 ... 3: 1362 pmcaddr = pmc->block[blk_num].mmio_base + 1363 MLXBF_PMC_L3C_PERF_CNT_SEL; 1364 wordaddr = &perfcnt_sel; 1365 break; 1366 case 4: 1367 pmcaddr = pmc->block[blk_num].mmio_base + 1368 MLXBF_PMC_L3C_PERF_CNT_SEL_1; 1369 wordaddr = &perfcnt_sel_1; 1370 break; 1371 default: 1372 return -EINVAL; 1373 } 1374 1375 if (mlxbf_pmc_readl(pmcaddr, wordaddr)) 1376 return -EINVAL; 1377 1378 /* Read from appropriate register field for the counter */ 1379 switch (cnt_num) { 1380 case 0: 1381 evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_0, perfcnt_sel); 1382 break; 1383 case 1: 1384 evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_1, perfcnt_sel); 1385 break; 1386 case 2: 1387 evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_2, perfcnt_sel); 1388 break; 1389 case 3: 1390 evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_CNT_3, perfcnt_sel); 1391 break; 1392 case 4: 1393 evt = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_SEL_1_CNT_4, 1394 perfcnt_sel_1); 1395 break; 1396 default: 1397 return -EINVAL; 1398 } 1399 *result = evt; 1400 1401 return 0; 1402 } 1403 1404 /* Method to read crspace block event */ 1405 static int mlxbf_pmc_read_crspace_event(unsigned int blk_num, u32 cnt_num, u64 *result) 1406 { 1407 u32 word, evt; 1408 void *addr; 1409 int ret; 1410 1411 addr = pmc->block[blk_num].mmio_base + 1412 ((cnt_num / 2) * MLXBF_PMC_CRSPACE_PERFSEL_SZ); 1413 ret = mlxbf_pmc_readl(addr, &word); 1414 if (ret) 1415 return ret; 1416 1417 if (cnt_num % 2) 1418 evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL1, word); 1419 else 1420 evt = FIELD_GET(MLXBF_PMC_CRSPACE_PERFSEL0, word); 1421 1422 *result = evt; 1423 1424 return 0; 1425 } 1426 1427 /* Method to find the event currently being monitored by a counter */ 1428 static int mlxbf_pmc_read_event(unsigned int blk_num, u32 cnt_num, bool is_l3, u64 *result) 1429 { 1430 u32 perfcfg_offset, perfval_offset; 1431 u64 perfmon_cfg, perfevt; 1432 1433 if (cnt_num >= pmc->block[blk_num].counters) 1434 return -EINVAL; 1435 1436 if (is_l3) 1437 return mlxbf_pmc_read_l3_event(blk_num, cnt_num, result); 1438 1439 if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) 1440 return mlxbf_pmc_read_crspace_event(blk_num, cnt_num, result); 1441 1442 perfcfg_offset = cnt_num * MLXBF_PMC_REG_SIZE; 1443 perfval_offset = perfcfg_offset + 1444 pmc->block[blk_num].counters * MLXBF_PMC_REG_SIZE; 1445 1446 /* Set counter in "read" mode */ 1447 perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, 1448 MLXBF_PMC_PERFEVT); 1449 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); 1450 perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); 1451 1452 if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, 1453 MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) 1454 return -EFAULT; 1455 1456 /* Get the event number */ 1457 if (mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, 1458 MLXBF_PMC_READ_REG_64, &perfevt)) 1459 return -EFAULT; 1460 1461 *result = FIELD_GET(MLXBF_PMC_PERFEVT_EVTSEL, perfevt); 1462 1463 return 0; 1464 } 1465 1466 /* Method to read a register */ 1467 static int mlxbf_pmc_read_reg(unsigned int blk_num, u32 offset, u64 *result) 1468 { 1469 u32 ecc_out; 1470 1471 if (strstr(pmc->block_name[blk_num], "ecc")) { 1472 if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + offset, 1473 &ecc_out)) 1474 return -EFAULT; 1475 1476 *result = ecc_out; 1477 return 0; 1478 } 1479 1480 if (mlxbf_pmc_valid_range(blk_num, offset)) 1481 return mlxbf_pmc_read(pmc->block[blk_num].mmio_base + offset, 1482 MLXBF_PMC_READ_REG_64, result); 1483 1484 return -EINVAL; 1485 } 1486 1487 /* Method to write to a register */ 1488 static int mlxbf_pmc_write_reg(unsigned int blk_num, u32 offset, u64 data) 1489 { 1490 if (strstr(pmc->block_name[blk_num], "ecc")) { 1491 return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + offset, 1492 MLXBF_PMC_WRITE_REG_32, data); 1493 } 1494 1495 if (mlxbf_pmc_valid_range(blk_num, offset)) 1496 return mlxbf_pmc_write(pmc->block[blk_num].mmio_base + offset, 1497 MLXBF_PMC_WRITE_REG_64, data); 1498 1499 return -EINVAL; 1500 } 1501 1502 /* Show function for "counter" sysfs files */ 1503 static ssize_t mlxbf_pmc_counter_show(struct device *dev, 1504 struct device_attribute *attr, char *buf) 1505 { 1506 struct mlxbf_pmc_attribute *attr_counter = container_of( 1507 attr, struct mlxbf_pmc_attribute, dev_attr); 1508 unsigned int blk_num, cnt_num; 1509 bool is_l3 = false; 1510 int offset; 1511 u64 value; 1512 1513 blk_num = attr_counter->nr; 1514 cnt_num = attr_counter->index; 1515 1516 if (strstr(pmc->block_name[blk_num], "l3cache")) 1517 is_l3 = true; 1518 1519 if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) || 1520 (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)) { 1521 if (mlxbf_pmc_read_counter(blk_num, cnt_num, is_l3, &value)) 1522 return -EINVAL; 1523 } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) { 1524 offset = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], 1525 attr->attr.name); 1526 if (offset < 0) 1527 return -EINVAL; 1528 if (mlxbf_pmc_read_reg(blk_num, offset, &value)) 1529 return -EINVAL; 1530 } else 1531 return -EINVAL; 1532 1533 return sysfs_emit(buf, "0x%llx\n", value); 1534 } 1535 1536 /* Store function for "counter" sysfs files */ 1537 static ssize_t mlxbf_pmc_counter_store(struct device *dev, 1538 struct device_attribute *attr, 1539 const char *buf, size_t count) 1540 { 1541 struct mlxbf_pmc_attribute *attr_counter = container_of( 1542 attr, struct mlxbf_pmc_attribute, dev_attr); 1543 unsigned int blk_num, cnt_num, data; 1544 bool is_l3 = false; 1545 u64 evt_num; 1546 int offset; 1547 int err; 1548 1549 blk_num = attr_counter->nr; 1550 cnt_num = attr_counter->index; 1551 1552 err = kstrtouint(buf, 0, &data); 1553 if (err < 0) 1554 return err; 1555 1556 /* Allow non-zero writes only to the ecc regs */ 1557 if (!(strstr(pmc->block_name[blk_num], "ecc")) && data) 1558 return -EINVAL; 1559 1560 /* Do not allow writes to the L3C regs */ 1561 if (strstr(pmc->block_name[blk_num], "l3cache")) 1562 return -EINVAL; 1563 1564 if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) { 1565 err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num); 1566 if (err) 1567 return err; 1568 err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt_num, 1569 is_l3); 1570 if (err) 1571 return err; 1572 } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) { 1573 offset = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], 1574 attr->attr.name); 1575 if (offset < 0) 1576 return -EINVAL; 1577 err = mlxbf_pmc_write_reg(blk_num, offset, data); 1578 if (err) 1579 return err; 1580 } else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) { 1581 if (sscanf(attr->attr.name, "counter%u", &cnt_num) != 1) 1582 return -EINVAL; 1583 err = mlxbf_pmc_clear_crspace_counter(blk_num, cnt_num); 1584 } else 1585 return -EINVAL; 1586 1587 return count; 1588 } 1589 1590 /* Show function for "event" sysfs files */ 1591 static ssize_t mlxbf_pmc_event_show(struct device *dev, 1592 struct device_attribute *attr, char *buf) 1593 { 1594 struct mlxbf_pmc_attribute *attr_event = container_of( 1595 attr, struct mlxbf_pmc_attribute, dev_attr); 1596 unsigned int blk_num, cnt_num; 1597 bool is_l3 = false; 1598 char *evt_name; 1599 u64 evt_num; 1600 int err; 1601 1602 blk_num = attr_event->nr; 1603 cnt_num = attr_event->index; 1604 1605 if (strstr(pmc->block_name[blk_num], "l3cache")) 1606 is_l3 = true; 1607 1608 err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num); 1609 if (err) 1610 return sysfs_emit(buf, "No event being monitored\n"); 1611 1612 evt_name = mlxbf_pmc_get_event_name(pmc->block_name[blk_num], evt_num); 1613 if (!evt_name) 1614 return -EINVAL; 1615 1616 return sysfs_emit(buf, "0x%llx: %s\n", evt_num, evt_name); 1617 } 1618 1619 /* Store function for "event" sysfs files */ 1620 static ssize_t mlxbf_pmc_event_store(struct device *dev, 1621 struct device_attribute *attr, 1622 const char *buf, size_t count) 1623 { 1624 struct mlxbf_pmc_attribute *attr_event = container_of( 1625 attr, struct mlxbf_pmc_attribute, dev_attr); 1626 unsigned int blk_num, cnt_num; 1627 bool is_l3 = false; 1628 int evt_num; 1629 int err; 1630 1631 blk_num = attr_event->nr; 1632 cnt_num = attr_event->index; 1633 1634 if (isalpha(buf[0])) { 1635 evt_num = mlxbf_pmc_get_event_num(pmc->block_name[blk_num], 1636 buf); 1637 if (evt_num < 0) 1638 return -EINVAL; 1639 } else { 1640 err = kstrtouint(buf, 0, &evt_num); 1641 if (err < 0) 1642 return err; 1643 } 1644 1645 if (strstr(pmc->block_name[blk_num], "l3cache")) 1646 is_l3 = true; 1647 1648 err = mlxbf_pmc_program_counter(blk_num, cnt_num, evt_num, is_l3); 1649 if (err) 1650 return err; 1651 1652 return count; 1653 } 1654 1655 /* Show function for "event_list" sysfs files */ 1656 static ssize_t mlxbf_pmc_event_list_show(struct device *dev, 1657 struct device_attribute *attr, 1658 char *buf) 1659 { 1660 struct mlxbf_pmc_attribute *attr_event_list = container_of( 1661 attr, struct mlxbf_pmc_attribute, dev_attr); 1662 const struct mlxbf_pmc_events *events; 1663 char e_info[MLXBF_PMC_EVENT_INFO_LEN]; 1664 unsigned int blk_num, i, len = 0; 1665 size_t size; 1666 int ret = 0; 1667 1668 blk_num = attr_event_list->nr; 1669 1670 events = mlxbf_pmc_event_list(pmc->block_name[blk_num], &size); 1671 if (!events) 1672 return -EINVAL; 1673 1674 for (i = 0, buf[0] = '\0'; i < size; ++i) { 1675 len += snprintf(e_info, sizeof(e_info), "0x%x: %s\n", 1676 events[i].evt_num, events[i].evt_name); 1677 if (len >= PAGE_SIZE) 1678 break; 1679 strcat(buf, e_info); 1680 ret = len; 1681 } 1682 1683 return ret; 1684 } 1685 1686 /* Show function for "enable" sysfs files - only for l3cache & crspace */ 1687 static ssize_t mlxbf_pmc_enable_show(struct device *dev, 1688 struct device_attribute *attr, char *buf) 1689 { 1690 struct mlxbf_pmc_attribute *attr_enable = container_of( 1691 attr, struct mlxbf_pmc_attribute, dev_attr); 1692 unsigned int blk_num, value; 1693 u32 perfcnt_cfg, word; 1694 1695 blk_num = attr_enable->nr; 1696 1697 if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) { 1698 if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + 1699 MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), 1700 &word)) 1701 return -EINVAL; 1702 1703 value = FIELD_GET(MLXBF_PMC_CRSPACE_PERFMON_EN, word); 1704 } else { 1705 if (mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + 1706 MLXBF_PMC_L3C_PERF_CNT_CFG, 1707 &perfcnt_cfg)) 1708 return -EINVAL; 1709 1710 value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg); 1711 } 1712 1713 return sysfs_emit(buf, "%u\n", value); 1714 } 1715 1716 /* Store function for "enable" sysfs files - only for l3cache & crspace */ 1717 static ssize_t mlxbf_pmc_enable_store(struct device *dev, 1718 struct device_attribute *attr, 1719 const char *buf, size_t count) 1720 { 1721 struct mlxbf_pmc_attribute *attr_enable = container_of( 1722 attr, struct mlxbf_pmc_attribute, dev_attr); 1723 unsigned int en, blk_num; 1724 u32 word; 1725 int err; 1726 1727 blk_num = attr_enable->nr; 1728 1729 err = kstrtouint(buf, 0, &en); 1730 if (err < 0) 1731 return err; 1732 1733 if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE) { 1734 err = mlxbf_pmc_readl(pmc->block[blk_num].mmio_base + 1735 MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), 1736 &word); 1737 if (err) 1738 return -EINVAL; 1739 1740 word &= ~MLXBF_PMC_CRSPACE_PERFMON_EN; 1741 word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_EN, en); 1742 if (en) 1743 word |= FIELD_PREP(MLXBF_PMC_CRSPACE_PERFMON_CLR, 1); 1744 1745 mlxbf_pmc_write(pmc->block[blk_num].mmio_base + 1746 MLXBF_PMC_CRSPACE_PERFMON_CTL(pmc->block[blk_num].counters), 1747 MLXBF_PMC_WRITE_REG_32, word); 1748 } else { 1749 if (en && en != 1) 1750 return -EINVAL; 1751 1752 err = mlxbf_pmc_config_l3_counters(blk_num, false, !!en); 1753 if (err) 1754 return err; 1755 1756 if (en == 1) { 1757 err = mlxbf_pmc_config_l3_counters(blk_num, true, false); 1758 if (err) 1759 return err; 1760 } 1761 } 1762 1763 return count; 1764 } 1765 1766 /* Populate attributes for blocks with counters to monitor performance */ 1767 static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_num) 1768 { 1769 struct mlxbf_pmc_attribute *attr; 1770 unsigned int i = 0, j = 0; 1771 1772 if (!mlxbf_pmc_event_supported(pmc->block_name[blk_num])) 1773 return -ENOENT; 1774 1775 /* "event_list" sysfs to list events supported by the block */ 1776 attr = &pmc->block[blk_num].attr_event_list; 1777 sysfs_attr_init(&attr->dev_attr.attr); 1778 attr->dev_attr.attr.mode = 0444; 1779 attr->dev_attr.show = mlxbf_pmc_event_list_show; 1780 attr->nr = blk_num; 1781 attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, "event_list"); 1782 if (!attr->dev_attr.attr.name) 1783 return -ENOMEM; 1784 pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr; 1785 attr = NULL; 1786 1787 /* "enable" sysfs to start/stop the counters. Only in L3C blocks */ 1788 if (strstr(pmc->block_name[blk_num], "l3cache") || 1789 ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) { 1790 attr = &pmc->block[blk_num].attr_enable; 1791 sysfs_attr_init(&attr->dev_attr.attr); 1792 attr->dev_attr.attr.mode = 0644; 1793 attr->dev_attr.show = mlxbf_pmc_enable_show; 1794 attr->dev_attr.store = mlxbf_pmc_enable_store; 1795 attr->nr = blk_num; 1796 attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, 1797 "enable"); 1798 if (!attr->dev_attr.attr.name) 1799 return -ENOMEM; 1800 pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; 1801 attr = NULL; 1802 } 1803 1804 pmc->block[blk_num].attr_counter = devm_kcalloc( 1805 dev, pmc->block[blk_num].counters, 1806 sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); 1807 if (!pmc->block[blk_num].attr_counter) 1808 return -ENOMEM; 1809 1810 pmc->block[blk_num].attr_event = devm_kcalloc( 1811 dev, pmc->block[blk_num].counters, 1812 sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); 1813 if (!pmc->block[blk_num].attr_event) 1814 return -ENOMEM; 1815 1816 /* "eventX" and "counterX" sysfs to program and read counter values */ 1817 for (j = 0; j < pmc->block[blk_num].counters; ++j) { 1818 attr = &pmc->block[blk_num].attr_counter[j]; 1819 sysfs_attr_init(&attr->dev_attr.attr); 1820 attr->dev_attr.attr.mode = 0644; 1821 attr->dev_attr.show = mlxbf_pmc_counter_show; 1822 attr->dev_attr.store = mlxbf_pmc_counter_store; 1823 attr->index = j; 1824 attr->nr = blk_num; 1825 attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, "counter%u", j); 1826 if (!attr->dev_attr.attr.name) 1827 return -ENOMEM; 1828 pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; 1829 attr = NULL; 1830 1831 attr = &pmc->block[blk_num].attr_event[j]; 1832 sysfs_attr_init(&attr->dev_attr.attr); 1833 attr->dev_attr.attr.mode = 0644; 1834 attr->dev_attr.show = mlxbf_pmc_event_show; 1835 attr->dev_attr.store = mlxbf_pmc_event_store; 1836 attr->index = j; 1837 attr->nr = blk_num; 1838 attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, "event%u", j); 1839 if (!attr->dev_attr.attr.name) 1840 return -ENOMEM; 1841 pmc->block[blk_num].block_attr[++i] = &attr->dev_attr.attr; 1842 attr = NULL; 1843 } 1844 1845 return 0; 1846 } 1847 1848 /* Populate attributes for blocks with registers to monitor performance */ 1849 static int mlxbf_pmc_init_perftype_reg(struct device *dev, unsigned int blk_num) 1850 { 1851 const struct mlxbf_pmc_events *events; 1852 struct mlxbf_pmc_attribute *attr; 1853 unsigned int i = 0; 1854 size_t count = 0; 1855 1856 events = mlxbf_pmc_event_list(pmc->block_name[blk_num], &count); 1857 if (!events) 1858 return -ENOENT; 1859 1860 pmc->block[blk_num].attr_event = devm_kcalloc( 1861 dev, count, sizeof(struct mlxbf_pmc_attribute), GFP_KERNEL); 1862 if (!pmc->block[blk_num].attr_event) 1863 return -ENOMEM; 1864 1865 while (count > 0) { 1866 --count; 1867 attr = &pmc->block[blk_num].attr_event[count]; 1868 sysfs_attr_init(&attr->dev_attr.attr); 1869 attr->dev_attr.attr.mode = 0644; 1870 attr->dev_attr.show = mlxbf_pmc_counter_show; 1871 attr->dev_attr.store = mlxbf_pmc_counter_store; 1872 attr->nr = blk_num; 1873 attr->dev_attr.attr.name = devm_kasprintf(dev, GFP_KERNEL, 1874 events[count].evt_name); 1875 if (!attr->dev_attr.attr.name) 1876 return -ENOMEM; 1877 pmc->block[blk_num].block_attr[i] = &attr->dev_attr.attr; 1878 attr = NULL; 1879 i++; 1880 } 1881 1882 return 0; 1883 } 1884 1885 /* Helper to create the bfperf sysfs sub-directories and files */ 1886 static int mlxbf_pmc_create_groups(struct device *dev, unsigned int blk_num) 1887 { 1888 int err; 1889 1890 /* Populate attributes based on counter type */ 1891 if ((pmc->block[blk_num].type == MLXBF_PMC_TYPE_COUNTER) || 1892 (pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE)) 1893 err = mlxbf_pmc_init_perftype_counter(dev, blk_num); 1894 else if (pmc->block[blk_num].type == MLXBF_PMC_TYPE_REGISTER) 1895 err = mlxbf_pmc_init_perftype_reg(dev, blk_num); 1896 else 1897 err = -ENOENT; 1898 1899 if (err) 1900 return err; 1901 1902 /* Add a new attribute_group for the block */ 1903 pmc->block[blk_num].block_attr_grp.attrs = pmc->block[blk_num].block_attr; 1904 pmc->block[blk_num].block_attr_grp.name = devm_kasprintf( 1905 dev, GFP_KERNEL, pmc->block_name[blk_num]); 1906 if (!pmc->block[blk_num].block_attr_grp.name) 1907 return -ENOMEM; 1908 pmc->groups[pmc->group_num] = &pmc->block[blk_num].block_attr_grp; 1909 pmc->group_num++; 1910 1911 return 0; 1912 } 1913 1914 static bool mlxbf_pmc_guid_match(const guid_t *guid, 1915 const struct arm_smccc_res *res) 1916 { 1917 guid_t id = GUID_INIT(res->a0, res->a1, res->a1 >> 16, res->a2, 1918 res->a2 >> 8, res->a2 >> 16, res->a2 >> 24, 1919 res->a3, res->a3 >> 8, res->a3 >> 16, 1920 res->a3 >> 24); 1921 1922 return guid_equal(guid, &id); 1923 } 1924 1925 /* Helper to map the Performance Counters from the varios blocks */ 1926 static int mlxbf_pmc_map_counters(struct device *dev) 1927 { 1928 u64 info[MLXBF_PMC_INFO_SZ]; 1929 unsigned int tile_num, i; 1930 int ret; 1931 1932 for (i = 0; i < pmc->total_blocks; ++i) { 1933 /* Create sysfs for tiles only if block number < tile_count */ 1934 if (strstr(pmc->block_name[i], "tilenet")) { 1935 if (sscanf(pmc->block_name[i], "tilenet%u", &tile_num) != 1) 1936 continue; 1937 1938 if (tile_num >= pmc->tile_count) 1939 continue; 1940 } else if (strstr(pmc->block_name[i], "tile")) { 1941 if (sscanf(pmc->block_name[i], "tile%u", &tile_num) != 1) 1942 continue; 1943 1944 if (tile_num >= pmc->tile_count) 1945 continue; 1946 } 1947 1948 /* Create sysfs only for enabled MSS blocks */ 1949 if (strstr(pmc->block_name[i], "mss") && 1950 pmc->event_set == MLXBF_PMC_EVENT_SET_BF3) { 1951 unsigned int mss_num; 1952 1953 if (sscanf(pmc->block_name[i], "mss%u", &mss_num) != 1) 1954 continue; 1955 1956 if (!((pmc->mss_enable >> mss_num) & 0x1)) 1957 continue; 1958 } 1959 1960 /* Create sysfs only for enabled LLT blocks */ 1961 if (strstr(pmc->block_name[i], "llt_miss")) { 1962 unsigned int llt_num; 1963 1964 if (sscanf(pmc->block_name[i], "llt_miss%u", &llt_num) != 1) 1965 continue; 1966 1967 if (!((pmc->llt_enable >> llt_num) & 0x1)) 1968 continue; 1969 } else if (strstr(pmc->block_name[i], "llt")) { 1970 unsigned int llt_num; 1971 1972 if (sscanf(pmc->block_name[i], "llt%u", &llt_num) != 1) 1973 continue; 1974 1975 if (!((pmc->llt_enable >> llt_num) & 0x1)) 1976 continue; 1977 } 1978 1979 ret = device_property_read_u64_array(dev, pmc->block_name[i], 1980 info, MLXBF_PMC_INFO_SZ); 1981 if (ret) 1982 return ret; 1983 1984 /* 1985 * Do not remap if the proper SMC calls are supported, 1986 * since the SMC calls expect physical addresses. 1987 */ 1988 if (pmc->svc_sreg_support) 1989 pmc->block[i].mmio_base = (void __iomem *)info[0]; 1990 else 1991 pmc->block[i].mmio_base = 1992 devm_ioremap(dev, info[0], info[1]); 1993 1994 pmc->block[i].blk_size = info[1]; 1995 pmc->block[i].counters = info[2]; 1996 pmc->block[i].type = info[3]; 1997 1998 if (!pmc->block[i].mmio_base) 1999 return -ENOMEM; 2000 2001 ret = mlxbf_pmc_create_groups(dev, i); 2002 if (ret == -ENOENT) { 2003 dev_warn(dev, "ignoring unsupported block: '%s'\n", pmc->block_name[i]); 2004 continue; 2005 } 2006 if (ret) 2007 return ret; 2008 } 2009 2010 return 0; 2011 } 2012 2013 static int mlxbf_pmc_probe(struct platform_device *pdev) 2014 { 2015 struct acpi_device *acpi_dev = ACPI_COMPANION(&pdev->dev); 2016 const char *hid = acpi_device_hid(acpi_dev); 2017 struct device *dev = &pdev->dev; 2018 struct arm_smccc_res res; 2019 guid_t guid; 2020 int ret; 2021 2022 /* Ensure we have the UUID we expect for this service. */ 2023 arm_smccc_smc(MLXBF_PMC_SIP_SVC_UID, 0, 0, 0, 0, 0, 0, 0, &res); 2024 guid_parse(mlxbf_pmc_svc_uuid_str, &guid); 2025 if (!mlxbf_pmc_guid_match(&guid, &res)) 2026 return -ENODEV; 2027 2028 pmc = devm_kzalloc(dev, sizeof(struct mlxbf_pmc_context), GFP_KERNEL); 2029 if (!pmc) 2030 return -ENOMEM; 2031 2032 /* 2033 * ACPI indicates whether we use SMCs to access registers or not. 2034 * If sreg_tbl_perf is not present, just assume we're not using SMCs. 2035 */ 2036 ret = device_property_read_u32(dev, "sec_reg_block", 2037 &pmc->sreg_tbl_perf); 2038 if (ret) { 2039 pmc->svc_sreg_support = false; 2040 } else { 2041 /* 2042 * Check service version to see if we actually do support the 2043 * needed SMCs. If we have the calls we need, mark support for 2044 * them in the pmc struct. 2045 */ 2046 arm_smccc_smc(MLXBF_PMC_SIP_SVC_VERSION, 0, 0, 0, 0, 0, 0, 0, 2047 &res); 2048 if (res.a0 == MLXBF_PMC_SVC_REQ_MAJOR && 2049 res.a1 >= MLXBF_PMC_SVC_MIN_MINOR) 2050 pmc->svc_sreg_support = true; 2051 else 2052 return -EINVAL; 2053 } 2054 2055 if (!strcmp(hid, "MLNXBFD0")) 2056 pmc->event_set = MLXBF_PMC_EVENT_SET_BF1; 2057 else if (!strcmp(hid, "MLNXBFD1")) 2058 pmc->event_set = MLXBF_PMC_EVENT_SET_BF2; 2059 else if (!strcmp(hid, "MLNXBFD2")) 2060 pmc->event_set = MLXBF_PMC_EVENT_SET_BF3; 2061 else 2062 return -ENODEV; 2063 2064 ret = device_property_read_u32(dev, "block_num", &pmc->total_blocks); 2065 if (ret) 2066 return ret; 2067 2068 ret = device_property_read_string_array(dev, "block_name", 2069 pmc->block_name, 2070 pmc->total_blocks); 2071 if (ret != pmc->total_blocks) 2072 return -EFAULT; 2073 2074 if (device_property_read_u32(dev, "tile_num", &pmc->tile_count)) { 2075 if (device_property_read_u8(dev, "llt_enable", &pmc->llt_enable)) { 2076 dev_err(dev, "Number of tiles/LLTs undefined\n"); 2077 return -EINVAL; 2078 } 2079 if (device_property_read_u8(dev, "mss_enable", &pmc->mss_enable)) { 2080 dev_err(dev, "Number of tiles/MSSs undefined\n"); 2081 return -EINVAL; 2082 } 2083 } 2084 2085 pmc->pdev = pdev; 2086 pmc->group_num = 0; 2087 2088 ret = mlxbf_pmc_map_counters(dev); 2089 if (ret) 2090 return ret; 2091 2092 pmc->hwmon_dev = devm_hwmon_device_register_with_groups( 2093 dev, "bfperf", pmc, pmc->groups); 2094 if (IS_ERR(pmc->hwmon_dev)) 2095 return PTR_ERR(pmc->hwmon_dev); 2096 platform_set_drvdata(pdev, pmc); 2097 2098 return 0; 2099 } 2100 2101 static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0", 0 }, 2102 { "MLNXBFD1", 0 }, 2103 { "MLNXBFD2", 0 }, 2104 {}, }; 2105 2106 MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids); 2107 static struct platform_driver pmc_driver = { 2108 .driver = { .name = "mlxbf-pmc", 2109 .acpi_match_table = ACPI_PTR(mlxbf_pmc_acpi_ids), }, 2110 .probe = mlxbf_pmc_probe, 2111 }; 2112 2113 module_platform_driver(pmc_driver); 2114 2115 MODULE_AUTHOR("Shravan Kumar Ramani <sramani@mellanox.com>"); 2116 MODULE_DESCRIPTION("Mellanox PMC driver"); 2117 MODULE_LICENSE("Dual BSD/GPL"); 2118