Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8c069ff4 authored by Hendrik Brueckner's avatar Hendrik Brueckner Committed by Martin Schwidefsky
Browse files

s390/perf: add support for the CPU-Measurement Sampling Facility



Introduce a perf PMU, "cpum_sf", to support the CPU-Measurement
Sampling Facility.  You can control the sampling facility through
this perf PMU interfaces.  Perf sampling events are created for
hardware samples.

For details about the CPU-Measurement Sampling Facility, see
"The Load-Program-Parameter and the CPU-Measurement Facilities" (SA23-2260).

Signed-off-by: default avatarHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent c7168325
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -210,6 +210,20 @@ static inline int lsctl(struct hws_lsctl_request_block *req)

/* Sampling control helper functions */

#include <linux/time.h>

static inline unsigned long freq_to_sample_rate(struct hws_qsi_info_block *qsi,
						unsigned long freq)
{
	return (USEC_PER_SEC / freq) * qsi->cpu_speed;
}

static inline unsigned long sample_rate_to_freq(struct hws_qsi_info_block *qsi,
						unsigned long rate)
{
	return USEC_PER_SEC * qsi->cpu_speed / rate;
}

#define SDB_TE_ALERT_REQ_MASK	0x4000000000000000UL
#define SDB_TE_BUFFER_FULL_MASK 0x8000000000000000UL

+14 −3
Original line number Diff line number Diff line
@@ -15,12 +15,13 @@
#include <linux/device.h>
#include <asm/cpu_mf.h>

/* CPU-measurement counter facility */
#define PERF_CPUM_CF_MAX_CTR		256

/* Per-CPU flags for PMU states */
#define PMU_F_RESERVED			0x1000
#define PMU_F_ENABLED			0x2000
#define PMU_F_IN_USE			0x4000
#define PMU_F_ERR_IBE			0x0100
#define PMU_F_ERR_LSDA			0x0200
#define PMU_F_ERR_MASK			(PMU_F_ERR_IBE|PMU_F_ERR_LSDA)

/* Perf defintions for PMU event attributes in sysfs */
extern __init const struct attribute_group **cpumf_cf_event_group(void);
@@ -41,5 +42,15 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define perf_misc_flags(regs) perf_misc_flags(regs)

/* Perf PMU definitions for the counter facility */
#define PERF_CPUM_CF_MAX_CTR		256

/* Perf PMU definitions for the sampling facility */
#define PERF_CPUM_SF_MAX_CTR		1
#define PERF_EVENT_CPUM_SF		0xB0000UL	/* Raw event ID */

#define TEAR_REG(hwc)		((hwc)->last_tag)
#define SAMPL_RATE(hwc)		((hwc)->event_base)

#endif /* CONFIG_64BIT */
#endif /* _ASM_S390_PERF_EVENT_H */
+1 −1
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o
obj-$(CONFIG_CRASH_DUMP)	+= crash_dump.o

ifdef CONFIG_64BIT
obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_cpum_cf.o \
obj-$(CONFIG_PERF_EVENTS)	+= perf_event.o perf_cpum_cf.o perf_cpum_sf.o \
						perf_cpum_cf_events.o
obj-y				+= runtime_instr.o cache.o
endif
+1024 −0

File added.

Preview size limit exceeded, changes collapsed.

+33 −9
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/kvm_host.h>
#include <linux/percpu.h>
#include <linux/export.h>
#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <asm/irq.h>
#include <asm/cpu_mf.h>
@@ -36,6 +37,8 @@ int perf_num_counters(void)

	if (cpum_cf_avail())
		num += PERF_CPUM_CF_MAX_CTR;
	if (cpum_sf_avail())
		num += PERF_CPUM_SF_MAX_CTR;

	return num;
}
@@ -93,24 +96,45 @@ unsigned long perf_misc_flags(struct pt_regs *regs)
			       : PERF_RECORD_MISC_KERNEL;
}

void perf_event_print_debug(void)
void print_debug_cf(void)
{
	struct cpumf_ctr_info cf_info;
	unsigned long flags;
	int cpu;

	if (!cpum_cf_avail())
		return;

	local_irq_save(flags);
	int cpu = smp_processor_id();

	cpu = smp_processor_id();
	memset(&cf_info, 0, sizeof(cf_info));
	if (!qctri(&cf_info))
		pr_info("CPU[%i] CPUM_CF: ver=%u.%u A=%04x E=%04x C=%04x\n",
			cpu, cf_info.cfvn, cf_info.csvn,
			cf_info.auth_ctl, cf_info.enable_ctl, cf_info.act_ctl);
}

static void print_debug_sf(void)
{
	struct hws_qsi_info_block si;
	int cpu = smp_processor_id();

	memset(&si, 0, sizeof(si));
	if (qsi(&si)) {
		pr_err("CPU[%i]: CPM_SF: qsi failed\n");
		return;
	}

	pr_info("CPU[%i]: CPM_SF: as=%i es=%i cs=%i bsdes=%i dsdes=%i"
		" min=%i max=%i cpu_speed=%i tear=%p dear=%p\n",
		cpu, si.as, si.es, si.cs, si.bsdes, si.dsdes,
		si.min_sampl_rate, si.max_sampl_rate, si.cpu_speed,
		si.tear, si.dear);
}

void perf_event_print_debug(void)
{
	unsigned long flags;

	local_irq_save(flags);
	if (cpum_cf_avail())
		print_debug_cf();
	if (cpum_sf_avail())
		print_debug_sf();
	local_irq_restore(flags);
}