2118 lines · c
1// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB2/*3 * Mellanox BlueField Performance Monitoring Counters driver4 *5 * This driver provides a sysfs interface for monitoring6 * 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 0x8200000921#define MLXBF_PMC_READ_REG_32 0x8200000A22#define MLXBF_PMC_WRITE_REG_64 0x8200000B23#define MLXBF_PMC_READ_REG_64 0x8200000C24#define MLXBF_PMC_SIP_SVC_UID 0x8200ff0125#define MLXBF_PMC_SIP_SVC_VERSION 0x8200ff0326#define MLXBF_PMC_SVC_REQ_MAJOR 027#define MLXBF_PMC_SVC_MIN_MINOR 328 29#define MLXBF_PMC_SMCCC_ACCESS_VIOLATION -430 31#define MLXBF_PMC_EVENT_SET_BF1 032#define MLXBF_PMC_EVENT_SET_BF2 133#define MLXBF_PMC_EVENT_SET_BF3 234#define MLXBF_PMC_EVENT_INFO_LEN 10035 36#define MLXBF_PMC_MAX_BLOCKS 3037#define MLXBF_PMC_MAX_ATTRS 7038#define MLXBF_PMC_INFO_SZ 439#define MLXBF_PMC_REG_SIZE 840#define MLXBF_PMC_L3C_REG_SIZE 441 42#define MLXBF_PMC_TYPE_CRSPACE 243#define MLXBF_PMC_TYPE_COUNTER 144#define MLXBF_PMC_TYPE_REGISTER 045 46#define MLXBF_PMC_PERFCTL 047#define MLXBF_PMC_PERFEVT 148#define MLXBF_PMC_PERFACC0 449 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 0x066#define MLXBF_PMC_L3C_PERF_CNT_SEL 0x1067#define MLXBF_PMC_L3C_PERF_CNT_SEL_1 0x1468#define MLXBF_PMC_L3C_PERF_CNT_LOW 0x4069#define MLXBF_PMC_L3C_PERF_CNT_HIGH 0x6070 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 0x084#define MLXBF_PMC_CRSPACE_PERFSEL_SZ 485#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 0x288#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 info95 * for each sysfs entry96 * @dev_attr: Device attribute struct97 * @index: index to identify counter number within a block98 * @nr: block number to which the sysfs belongs99 */100struct 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 block108 *109 * @mmio_base: The VA at which the PMC block is mapped110 * @blk_size: Size of each mapped region111 * @counters: Number of counters in the block112 * @type: Type of counters in the block113 * @attr_counter: Attributes for "counter" sysfs files114 * @attr_event: Attributes for "event" sysfs files115 * @attr_event_list: Attributes for "event_list" sysfs files116 * @attr_enable: Attributes for "enable" sysfs files117 * @block_attr: All attributes needed for the block118 * @block_attr_grp: Attribute group for the block119 */120struct 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 info135 *136 * @pdev: The kernel structure representing the device137 * @total_blocks: Total number of blocks138 * @tile_count: Number of tiles in the system139 * @llt_enable: Info on enabled LLTs140 * @mss_enable: Info on enabled MSSs141 * @group_num: Group number assigned to each valid block142 * @hwmon_dev: Hwmon device for bfperf143 * @block_name: Block name144 * @block: Block info145 * @groups: Attribute groups from each block146 * @svc_sreg_support: Whether SMCs are used to access performance registers147 * @sreg_tbl_perf: Secure register access table number148 * @event_set: Event set to use149 */150struct 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 block168 * @evt_num: Event number used to program counters169 * @evt_name: Name of the event170 */171struct mlxbf_pmc_events {172 u32 evt_num;173 char *evt_name;174};175 176static 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 191static 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 211static 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 235static 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 268static 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 281static 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 289static 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 447static 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 506static 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 561static 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 608static 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 783static 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 862static struct mlxbf_pmc_context *pmc;863 864/* UUID used to probe ATF service. */865static const char *mlxbf_pmc_svc_uuid_str = "89c036b4-e7d7-11e6-8797-001aca00bfc4";866 867/* Calls an SMC to access a performance register */868static 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 */894static 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 else902 *result = readq(addr);903 904 return 0;905}906 907/* Convenience function for 32-bit reads */908static 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 */922static 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 */945static 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 else953 writeq(value, addr);954 955 return 0;956}957 958/* Check if the register offset is within the mapped region for the block */959static 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 */969static 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 1046static 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 */1052static 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 */1071static 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 */1090static 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 */1105static 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 */1169static 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 */1193static 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 */1205static 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 */1268static 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 */1299static 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 */1316static 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 */1353static 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 */1405static 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 else1420 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 */1428static 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 */1467static 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 */1488static 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 */1503static 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 } else1531 return -EINVAL;1532 1533 return sysfs_emit(buf, "0x%llx\n", value);1534}1535 1536/* Store function for "counter" sysfs files */1537static 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 } else1585 return -EINVAL;1586 1587 return count;1588}1589 1590/* Show function for "event" sysfs files */1591static 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 */1620static 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 */1656static 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 */1687static 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 */1717static 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 */1767static 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 */1849static 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 */1886static 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 else1897 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 1914static 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 */1926static 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 else1991 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 2013static 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 the2043 * needed SMCs. If we have the calls we need, mark support for2044 * 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 else2052 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 else2062 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 2101static const struct acpi_device_id mlxbf_pmc_acpi_ids[] = { { "MLNXBFD0", 0 },2102 { "MLNXBFD1", 0 },2103 { "MLNXBFD2", 0 },2104 {}, };2105 2106MODULE_DEVICE_TABLE(acpi, mlxbf_pmc_acpi_ids);2107static 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 2113module_platform_driver(pmc_driver);2114 2115MODULE_AUTHOR("Shravan Kumar Ramani <sramani@mellanox.com>");2116MODULE_DESCRIPTION("Mellanox PMC driver");2117MODULE_LICENSE("Dual BSD/GPL");2118