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