Commit f5be3a61 authored by Shaokun Zhang's avatar Shaokun Zhang Committed by Will Deacon
Browse files

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: default avatarShaokun 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: default avatarWill Deacon <will@kernel.org>
parent 688494a4
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -236,6 +236,9 @@
#define ARMV8_PMU_USERENR_CR	(1 << 2) /* Cycle counter can be read at EL0 */
#define ARMV8_PMU_USERENR_ER	(1 << 3) /* Event counter can be read at EL0 */

/* PMMIR_EL1.SLOTS mask */
#define ARMV8_PMU_SLOTS_MASK	0xff

#ifdef CONFIG_PERF_EVENTS
struct pt_regs;
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
+2 −0
Original line number Diff line number Diff line
@@ -321,6 +321,8 @@
#define SYS_PMINTENSET_EL1		sys_reg(3, 0, 9, 14, 1)
#define SYS_PMINTENCLR_EL1		sys_reg(3, 0, 9, 14, 2)

#define SYS_PMMIR_EL1			sys_reg(3, 0, 9, 14, 6)

#define SYS_MAIR_EL1			sys_reg(3, 0, 10, 2, 0)
#define SYS_AMAIR_EL1			sys_reg(3, 0, 10, 3, 0)

+70 −33
Original line number Diff line number Diff line
@@ -305,6 +305,28 @@ static struct attribute_group armv8_pmuv3_format_attr_group = {
	.attrs = armv8_pmuv3_format_attrs,
};

static ssize_t slots_show(struct device *dev, struct device_attribute *attr,
			  char *page)
{
	struct pmu *pmu = dev_get_drvdata(dev);
	struct arm_pmu *cpu_pmu = container_of(pmu, struct arm_pmu, pmu);
	u32 slots = cpu_pmu->reg_pmmir & ARMV8_PMU_SLOTS_MASK;

	return snprintf(page, PAGE_SIZE, "0x%08x\n", slots);
}

static DEVICE_ATTR_RO(slots);

static struct attribute *armv8_pmuv3_caps_attrs[] = {
	&dev_attr_slots.attr,
	NULL,
};

static struct attribute_group armv8_pmuv3_caps_attr_group = {
	.name = "caps",
	.attrs = armv8_pmuv3_caps_attrs,
};

/*
 * Perf Events' indices
 */
@@ -984,6 +1006,12 @@ static void __armv8pmu_probe_pmu(void *info)

	bitmap_from_arr32(cpu_pmu->pmceid_ext_bitmap,
			     pmceid, ARMV8_PMUV3_MAX_COMMON_EVENTS);

	/* store PMMIR_EL1 register for sysfs */
	if (pmuver >= ID_AA64DFR0_PMUVER_8_4 && (pmceid_raw[1] & BIT(31)))
		cpu_pmu->reg_pmmir = read_cpuid(PMMIR_EL1);
	else
		cpu_pmu->reg_pmmir = 0;
}

static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu)
@@ -1006,7 +1034,8 @@ static int armv8pmu_probe_pmu(struct arm_pmu *cpu_pmu)
static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name,
			  int (*map_event)(struct perf_event *event),
			  const struct attribute_group *events,
			  const struct attribute_group *format)
			  const struct attribute_group *format,
			  const struct attribute_group *caps)
{
	int ret = armv8pmu_probe_pmu(cpu_pmu);
	if (ret)
@@ -1031,104 +1060,112 @@ static int armv8_pmu_init(struct arm_pmu *cpu_pmu, char *name,
			events : &armv8_pmuv3_events_attr_group;
	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_FORMATS] = format ?
			format : &armv8_pmuv3_format_attr_group;
	cpu_pmu->attr_groups[ARMPMU_ATTR_GROUP_CAPS] = caps ?
			caps : &armv8_pmuv3_caps_attr_group;

	return 0;
}

static int armv8_pmu_init_nogroups(struct arm_pmu *cpu_pmu, char *name,
				   int (*map_event)(struct perf_event *event))
{
	return armv8_pmu_init(cpu_pmu, name, map_event, NULL, NULL, NULL);
}

static int armv8_pmuv3_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_pmuv3",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_pmuv3",
				       armv8_pmuv3_map_event);
}

static int armv8_a34_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a34",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a34",
				       armv8_pmuv3_map_event);
}

static int armv8_a35_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a35",
			      armv8_a53_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a35",
				       armv8_a53_map_event);
}

static int armv8_a53_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a53",
			      armv8_a53_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a53",
				       armv8_a53_map_event);
}

static int armv8_a55_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a55",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a55",
				       armv8_pmuv3_map_event);
}

static int armv8_a57_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a57",
			      armv8_a57_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a57",
				       armv8_a57_map_event);
}

static int armv8_a65_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a65",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a65",
				       armv8_pmuv3_map_event);
}

static int armv8_a72_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a72",
			      armv8_a57_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a72",
				       armv8_a57_map_event);
}

static int armv8_a73_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a73",
			      armv8_a73_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a73",
				       armv8_a73_map_event);
}

static int armv8_a75_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a75",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a75",
				       armv8_pmuv3_map_event);
}

static int armv8_a76_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a76",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a76",
				       armv8_pmuv3_map_event);
}

static int armv8_a77_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cortex_a77",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cortex_a77",
				       armv8_pmuv3_map_event);
}

static int armv8_e1_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_neoverse_e1",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_e1",
				       armv8_pmuv3_map_event);
}

static int armv8_n1_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_neoverse_n1",
			      armv8_pmuv3_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_neoverse_n1",
				       armv8_pmuv3_map_event);
}

static int armv8_thunder_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_cavium_thunder",
			      armv8_thunder_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_cavium_thunder",
				       armv8_thunder_map_event);
}

static int armv8_vulcan_pmu_init(struct arm_pmu *cpu_pmu)
{
	return armv8_pmu_init(cpu_pmu, "armv8_brcm_vulcan",
			      armv8_vulcan_map_event, NULL, NULL);
	return armv8_pmu_init_nogroups(cpu_pmu, "armv8_brcm_vulcan",
				       armv8_vulcan_map_event);
}

static const struct of_device_id armv8_pmu_of_device_ids[] = {
+3 −0
Original line number Diff line number Diff line
@@ -73,6 +73,7 @@ enum armpmu_attr_groups {
	ARMPMU_ATTR_GROUP_COMMON,
	ARMPMU_ATTR_GROUP_EVENTS,
	ARMPMU_ATTR_GROUP_FORMATS,
	ARMPMU_ATTR_GROUP_CAPS,
	ARMPMU_NR_ATTR_GROUPS
};

@@ -109,6 +110,8 @@ struct arm_pmu {
	struct notifier_block	cpu_pm_nb;
	/* the attr_groups array must be NULL-terminated */
	const struct attribute_group *attr_groups[ARMPMU_NR_ATTR_GROUPS + 1];
	/* store the PMMIR_EL1 to expose slots */
	u64		reg_pmmir;

	/* Only to be used by ACPI probing code */
	unsigned long acpi_cpuid;