Blob Blame History Raw
From: Hendrik Brueckner <brueckner@linux.ibm.com>
Date: Mon, 6 Aug 2018 17:43:07 +0200
Subject: s390/cpum_cf: prepare for in-kernel counter measurements
Git-commit: 3d33345aa3d9ab2ee9b5a5bf2a8842c43603d537
Patch-mainline: v5.1-rc1
References: jsc#SLE-6904 FATE#327581

Prepare the counter facility support to be used by other in-kernel
users.  The first step introduces the __kernel_cpumcf_begin() and
__kernel_cpumcf_end() functions to reserve the counter facility
for doing measurements and to release after the measurements are
done.

Signed-off-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 arch/s390/include/asm/cpu_mcf.h |    3 +++
 arch/s390/kernel/perf_cpum_cf.c |   32 ++++++++++++++++++++++++++------
 2 files changed, 29 insertions(+), 6 deletions(-)

--- a/arch/s390/include/asm/cpu_mcf.h
+++ b/arch/s390/include/asm/cpu_mcf.h
@@ -49,4 +49,7 @@ static inline void ctr_set_stop(u64 *sta
 	*state &= ~(cpumf_ctr_ctl[ctr_set] << CPUMF_LCCTL_ACTCTL_SHIFT);
 }
 
+int __kernel_cpumcf_begin(void);
+void __kernel_cpumcf_end(void);
+
 #endif /* _ASM_S390_CPU_MCF_H */
--- a/arch/s390/kernel/perf_cpum_cf.c
+++ b/arch/s390/kernel/perf_cpum_cf.c
@@ -239,25 +239,45 @@ static void setup_pmc_cpu(void *flags)
 	lcctl(0);
 }
 
-/* Initialize the CPU-measurement facility */
-static int reserve_pmc_hardware(void)
+/* Reserve/release functions for sharing perf hardware */
+static DEFINE_SPINLOCK(cpumcf_owner_lock);
+static void *cpumcf_owner;
+
+/* Initialize the CPU-measurement counter facility */
+int __kernel_cpumcf_begin(void)
 {
 	int flags = PMC_INIT;
+	int err = 0;
+
+	spin_lock(&cpumcf_owner_lock);
+	if (cpumcf_owner)
+		err = -EBUSY;
+	else
+		cpumcf_owner = __builtin_return_address(0);
+	spin_unlock(&cpumcf_owner_lock);
+	if (err)
+		return err;
 
 	on_each_cpu(setup_pmc_cpu, &flags, 1);
 	irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
 
 	return 0;
 }
+EXPORT_SYMBOL(__kernel_cpumcf_begin);
 
-/* Release the CPU-measurement facility */
-static void release_pmc_hardware(void)
+/* Release the CPU-measurement counter facility */
+void __kernel_cpumcf_end(void)
 {
 	int flags = PMC_RELEASE;
 
 	on_each_cpu(setup_pmc_cpu, &flags, 1);
 	irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
+
+	spin_lock(&cpumcf_owner_lock);
+	cpumcf_owner = NULL;
+	spin_unlock(&cpumcf_owner_lock);
 }
+EXPORT_SYMBOL(__kernel_cpumcf_end);
 
 /* Release the PMU if event is the last perf event */
 static void hw_perf_event_destroy(struct perf_event *event)
@@ -265,7 +285,7 @@ static void hw_perf_event_destroy(struct
 	if (!atomic_add_unless(&num_events, -1, 1)) {
 		mutex_lock(&pmc_reserve_mutex);
 		if (atomic_dec_return(&num_events) == 0)
-			release_pmc_hardware();
+			__kernel_cpumcf_end();
 		mutex_unlock(&pmc_reserve_mutex);
 	}
 }
@@ -366,7 +386,7 @@ static int __hw_perf_event_init(struct p
 	/* Initialize for using the CPU-measurement counter facility */
 	if (!atomic_inc_not_zero(&num_events)) {
 		mutex_lock(&pmc_reserve_mutex);
-		if (atomic_read(&num_events) == 0 && reserve_pmc_hardware())
+		if (atomic_read(&num_events) == 0 && __kernel_cpumcf_begin())
 			err = -EBUSY;
 		else
 			atomic_inc(&num_events);