Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

arm64: perf: Add support caps under sysfs

ARMv8.4-PMU introduces the PMMIR_EL1 registers and some new PMU events,
like STALL_SLOT etc, are related to it. Let's add a caps directory to
/sys/bus/event_source/devices/armv8_pmuv3_0/ and support slots from
PMMIR_EL1 registers in this entry. The user programs can get the slots
from sysfs directly.

/sys/bus/event_source/devices/armv8_pmuv3_0/caps/slots is exposed
under sysfs. Both ARMv8.4-PMU and STALL_SLOT event are implemented,
it returns the slots from PMMIR_EL1, otherwise it will return 0.

Signed-off-by: Shaokun Zhang <zhangshaokun@hisilicon.com>
Cc: Will Deacon <will@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Link: https://lore.kernel.org/r/1600754025-53535-1-git-send-email-zhangshaokun@hisilicon.com
Signed-off-by: Will Deacon <will@kernel.org>

authored by

Shaokun Zhang and committed by
Will Deacon
f5be3a61 688494a4

+78 -33
+3
arch/arm64/include/asm/perf_event.h
··· 236 236 #define ARMV8_PMU_USERENR_CR (1 << 2) /* Cycle counter can be read at EL0 */ 237 237 #define ARMV8_PMU_USERENR_ER (1 << 3) /* Event counter can be read at EL0 */ 238 238 239 + /* PMMIR_EL1.SLOTS mask */ 240 + #define ARMV8_PMU_SLOTS_MASK 0xff 241 + 239 242 #ifdef CONFIG_PERF_EVENTS 240 243 struct pt_regs; 241 244 extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
+2
arch/arm64/include/asm/sysreg.h
··· 321 321 #define SYS_PMINTENSET_EL1 sys_reg(3, 0, 9, 14, 1) 322 322 #define SYS_PMINTENCLR_EL1 sys_reg(3, 0, 9, 14, 2) 323 323 324 + #define SYS_PMMIR_EL1 sys_reg(3, 0, 9, 14, 6) 325 + 324 326 #define SYS_MAIR_EL1 sys_reg(3, 0, 10, 2, 0) 325 327 #define SYS_AMAIR_EL1 sys_reg(3, 0, 10, 3, 0) 326 328
+70 -33
arch/arm64/kernel/perf_event.c
··· 305 305 .attrs = armv8_pmuv3_format_attrs, 306 306 }; 307 307 308 + static ssize_t slots_show(struct device *dev, struct device_attribute *attr, 309 + char *page) 310 + { 311 + struct pmu *pmu = dev_get_drvdata(dev); 312 + struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu); 313 + u32 slots = cpu_pmu->reg_pmmir & ARMV8_PMU_SLOTS_MASK; 314 + 315 + return snprintf(page, PAGE_SIZE, "0x%08x\n", slots); 316 + } 317 + 318 + static DEVICE_ATTR_RO(slots); 319 + 320 + static struct attribute *armv8_pmuv3_caps_attrs[] = { 321 + &dev_attr_slots.attr, 322 + NULL, 323 + }; 324 + 325 + static struct attribute_group armv8_pmuv3_caps_attr_group = { 326 + .name = "caps", 327 + .attrs = armv8_pmuv3_caps_attrs, 328 + }; 329 + 308 330 /* 309 331 * Perf Events' indices 310 332 */ ··· 1006 984 1007 985 bitmap_from_arr32(cpu_pmu->pmceid_ext_bitmap, 1008 986 pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS); 987 + 988 + /* store PMMIR_EL1 register for sysfs */ 989 + if (pmuver >= ID_AA64DFR0_PMUVER_8_4 && (pmceid_raw[1] & BIT(31))) 990 + cpu_pmu->reg_pmmir = read_cpuid(PMMIR_EL1); 991 + else 992 + cpu_pmu->reg_pmmir = 0; 1009 993 } 1010 994 1011 995 static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu) ··· 1034 1006 static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name, 1035 1007 int (*map_event)(struct perf_event *event), 1036 1008 const struct attribute_group *events, 1037 - const struct attribute_group *format) 1009 + const struct attribute_group *format, 1010 + const struct attribute_group *caps) 1038 1011 { 1039 1012 int ret = armv8pmu_probe_pmu(cpu_pmu); 1040 1013 if (ret) ··· 1060 1031 events : &armv8_pmuv3_events_attr_group; 1061 1032 cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = format ? 1062 1033 format : &armv8_pmuv3_format_attr_group; 1034 + cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_CAPS] = caps ? 1035 + caps : &armv8_pmuv3_caps_attr_group; 1063 1036 1064 1037 return 0; 1065 1038 } 1066 1039 1040 + static int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name, 1041 + int (*map_event)(struct perf_event *event)) 1042 + { 1043 + return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL); 1044 + } 1045 + 1067 1046 static int armv8_pmuv3_init(struct arm_pmu *cpu_pmu) 1068 1047 { 1069 - return armv8_pmu_init(cpu_pmu, "armv8_pmuv3", 1070 - armv8_pmuv3_map_event, NULL, NULL); 1048 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_pmuv3", 1049 + armv8_pmuv3_map_event); 1071 1050 } 1072 1051 1073 1052 static int armv8_a34_pmu_init(struct arm_pmu *cpu_pmu) 1074 1053 { 1075 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a34", 1076 - armv8_pmuv3_map_event, NULL, NULL); 1054 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a34", 1055 + armv8_pmuv3_map_event); 1077 1056 } 1078 1057 1079 1058 static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu) 1080 1059 { 1081 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a35", 1082 - armv8_a53_map_event, NULL, NULL); 1060 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a35", 1061 + armv8_a53_map_event); 1083 1062 } 1084 1063 1085 1064 static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu) 1086 1065 { 1087 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a53", 1088 - armv8_a53_map_event, NULL, NULL); 1066 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a53", 1067 + armv8_a53_map_event); 1089 1068 } 1090 1069 1091 1070 static int armv8_a55_pmu_init(struct arm_pmu *cpu_pmu) 1092 1071 { 1093 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a55", 1094 - armv8_pmuv3_map_event, NULL, NULL); 1072 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a55", 1073 + armv8_pmuv3_map_event); 1095 1074 } 1096 1075 1097 1076 static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu) 1098 1077 { 1099 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a57", 1100 - armv8_a57_map_event, NULL, NULL); 1078 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57", 1079 + armv8_a57_map_event); 1101 1080 } 1102 1081 1103 1082 static int armv8_a65_pmu_init(struct arm_pmu *cpu_pmu) 1104 1083 { 1105 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a65", 1106 - armv8_pmuv3_map_event, NULL, NULL); 1084 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a65", 1085 + armv8_pmuv3_map_event); 1107 1086 } 1108 1087 1109 1088 static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu) 1110 1089 { 1111 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a72", 1112 - armv8_a57_map_event, NULL, NULL); 1090 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72", 1091 + armv8_a57_map_event); 1113 1092 } 1114 1093 1115 1094 static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu) 1116 1095 { 1117 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a73", 1118 - armv8_a73_map_event, NULL, NULL); 1096 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a73", 1097 + armv8_a73_map_event); 1119 1098 } 1120 1099 1121 1100 static int armv8_a75_pmu_init(struct arm_pmu *cpu_pmu) 1122 1101 { 1123 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a75", 1124 - armv8_pmuv3_map_event, NULL, NULL); 1102 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a75", 1103 + armv8_pmuv3_map_event); 1125 1104 } 1126 1105 1127 1106 static int armv8_a76_pmu_init(struct arm_pmu *cpu_pmu) 1128 1107 { 1129 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a76", 1130 - armv8_pmuv3_map_event, NULL, NULL); 1108 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a76", 1109 + armv8_pmuv3_map_event); 1131 1110 } 1132 1111 1133 1112 static int armv8_a77_pmu_init(struct arm_pmu *cpu_pmu) 1134 1113 { 1135 - return armv8_pmu_init(cpu_pmu, "armv8_cortex_a77", 1136 - armv8_pmuv3_map_event, NULL, NULL); 1114 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a77", 1115 + armv8_pmuv3_map_event); 1137 1116 } 1138 1117 1139 1118 static int armv8_e1_pmu_init(struct arm_pmu *cpu_pmu) 1140 1119 { 1141 - return armv8_pmu_init(cpu_pmu, "armv8_neoverse_e1", 1142 - armv8_pmuv3_map_event, NULL, NULL); 1120 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_e1", 1121 + armv8_pmuv3_map_event); 1143 1122 } 1144 1123 1145 1124 static int armv8_n1_pmu_init(struct arm_pmu *cpu_pmu) 1146 1125 { 1147 - return armv8_pmu_init(cpu_pmu, "armv8_neoverse_n1", 1148 - armv8_pmuv3_map_event, NULL, NULL); 1126 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_n1", 1127 + armv8_pmuv3_map_event); 1149 1128 } 1150 1129 1151 1130 static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu) 1152 1131 { 1153 - return armv8_pmu_init(cpu_pmu, "armv8_cavium_thunder", 1154 - armv8_thunder_map_event, NULL, NULL); 1132 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder", 1133 + armv8_thunder_map_event); 1155 1134 } 1156 1135 1157 1136 static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu) 1158 1137 { 1159 - return armv8_pmu_init(cpu_pmu, "armv8_brcm_vulcan", 1160 - armv8_vulcan_map_event, NULL, NULL); 1138 + return armv8_pmu_init_nogroups(cpu_pmu, "armv8_brcm_vulcan", 1139 + armv8_vulcan_map_event); 1161 1140 } 1162 1141 1163 1142 static const struct of_device_id armv8_pmu_of_device_ids[] = {
+3
include/linux/perf/arm_pmu.h
··· 73 73 ARMPMU_ATTR_GROUP_COMMON, 74 74 ARMPMU_ATTR_GROUP_EVENTS, 75 75 ARMPMU_ATTR_GROUP_FORMATS, 76 + ARMPMU_ATTR_GROUP_CAPS, 76 77 ARMPMU_NR_ATTR_GROUPS 77 78 }; 78 79 ··· 110 109 struct notifier_block cpu_pm_nb; 111 110 /* the attr_groups array must be NULL-terminated */ 112 111 const struct attribute_group *attr_groups[ARMPMU_NR_ATTR_GROUPS + 1]; 112 + /* store the PMMIR_EL1 to expose slots */ 113 + u64 reg_pmmir; 113 114 114 115 /* Only to be used by ACPI probing code */ 115 116 unsigned long acpi_cpuid;