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

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

s390/perf,oprofile: Share sampling facility



Introduce reserve/release functions to share the sampling facility
between perf and oprofile.
Also improve error handling for the sampling facility support in perf.

Signed-off-by: default avatarHendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 55baa2f8
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -52,5 +52,9 @@ extern unsigned long perf_misc_flags(struct pt_regs *regs);
#define TEAR_REG(hwc)		((hwc)->last_tag)
#define SAMPL_RATE(hwc)		((hwc)->event_base)

/* Perf hardware reserve and release functions */
int perf_reserve_sampling(void);
void perf_release_sampling(void);

#endif /* CONFIG_64BIT */
#endif /* _ASM_S390_PERF_EVENT_H */
+12 −5
Original line number Diff line number Diff line
@@ -260,16 +260,12 @@ static int sf_disable(void)

#define PMC_INIT      0
#define PMC_RELEASE   1
#define PMC_FAILURE   2
static void setup_pmc_cpu(void *flags)
{
	int err;
	struct cpu_hw_sf *cpusf = &__get_cpu_var(cpu_hw_sf);

	/* XXX Improve error handling and pass a flag in the *flags
	 *     variable to indicate failures.  Alternatively, ignore
	 *     (print) errors here and let the PMU functions fail if
	 *     the per-cpu PMU_F_RESERVED flag is not.
	 */
	err = 0;
	switch (*((int *) flags)) {
	case PMC_INIT:
@@ -299,6 +295,8 @@ static void setup_pmc_cpu(void *flags)
				    "setup_pmc_cpu: released: cpuhw=%p\n", cpusf);
		break;
	}
	if (err)
		*((int *) flags) |= PMC_FAILURE;
}

static void release_pmc_hardware(void)
@@ -307,13 +305,22 @@ static void release_pmc_hardware(void)

	irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
	on_each_cpu(setup_pmc_cpu, &flags, 1);
	perf_release_sampling();
}

static int reserve_pmc_hardware(void)
{
	int flags = PMC_INIT;
	int err;

	err = perf_reserve_sampling();
	if (err)
		return err;
	on_each_cpu(setup_pmc_cpu, &flags, 1);
	if (flags & PMC_FAILURE) {
		release_pmc_hardware();
		return -ENODEV;
	}
	irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);

	return 0;
+30 −0
Original line number Diff line number Diff line
@@ -208,3 +208,33 @@ ssize_t cpumf_events_sysfs_show(struct device *dev,
	return sprintf(page, "event=0x%04llx,name=%s\n",
		       pmu_attr->id, attr->attr.name);
}

/* Reserve/release functions for sharing perf hardware */
static DEFINE_SPINLOCK(perf_hw_owner_lock);
static void *perf_sampling_owner;

int perf_reserve_sampling(void)
{
	int err;

	err = 0;
	spin_lock(&perf_hw_owner_lock);
	if (perf_sampling_owner) {
		pr_warn("The sampling facility is already reserved by %p\n",
			perf_sampling_owner);
		err = -EBUSY;
	} else
		perf_sampling_owner = __builtin_return_address(0);
	spin_unlock(&perf_hw_owner_lock);
	return err;
}
EXPORT_SYMBOL(perf_reserve_sampling);

void perf_release_sampling(void)
{
	spin_lock(&perf_hw_owner_lock);
	WARN_ON(!perf_sampling_owner);
	perf_sampling_owner = NULL;
	spin_unlock(&perf_hw_owner_lock);
}
EXPORT_SYMBOL(perf_release_sampling);
+7 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ static DEFINE_MUTEX(hws_sem_oom);

static unsigned char hws_flush_all;
static unsigned int hws_oom;
static unsigned int hws_alert;
static struct workqueue_struct *hws_wq;

static unsigned int hws_state;
@@ -182,6 +183,9 @@ static void hws_ext_handler(struct ext_code ext_code,
	if (!(param32 & CPU_MF_INT_SF_MASK))
		return;

	if (!hws_alert)
		return;

	inc_irq_stat(IRQEXT_CMS);
	atomic_xchg(&cb->ext_params, atomic_read(&cb->ext_params) | param32);

@@ -941,6 +945,7 @@ int hwsampler_deallocate(void)
		goto deallocate_exit;

	irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
	hws_alert = 0;
	deallocate_sdbt();

	hws_state = HWS_DEALLOCATED;
@@ -1055,6 +1060,7 @@ int hwsampler_shutdown(void)

		if (hws_state == HWS_STOPPED) {
			irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
			hws_alert = 0;
			deallocate_sdbt();
		}
		if (hws_wq) {
@@ -1129,6 +1135,7 @@ int hwsampler_start_all(unsigned long rate)
	hws_oom = 1;
	hws_flush_all = 0;
	/* now let them in, 1407 CPUMF external interrupts */
	hws_alert = 1;
	irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);

	return 0;
+20 −3
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
 */

#include <linux/oprofile.h>
#include <linux/perf_event.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/fs.h>
@@ -67,6 +68,21 @@ module_param_call(cpu_type, set_cpu_type, NULL, NULL, 0);
MODULE_PARM_DESC(cpu_type, "Force legacy basic mode sampling"
		           "(report cpu_type \"timer\"");

static int __oprofile_hwsampler_start(void)
{
	int retval;

	retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
	if (retval)
		return retval;

	retval = hwsampler_start_all(oprofile_hw_interval);
	if (retval)
		hwsampler_deallocate();

	return retval;
}

static int oprofile_hwsampler_start(void)
{
	int retval;
@@ -76,13 +92,13 @@ static int oprofile_hwsampler_start(void)
	if (!hwsampler_running)
		return timer_ops.start();

	retval = hwsampler_allocate(oprofile_sdbt_blocks, oprofile_sdb_blocks);
	retval = perf_reserve_sampling();
	if (retval)
		return retval;

	retval = hwsampler_start_all(oprofile_hw_interval);
	retval = __oprofile_hwsampler_start();
	if (retval)
		hwsampler_deallocate();
		perf_release_sampling();

	return retval;
}
@@ -96,6 +112,7 @@ static void oprofile_hwsampler_stop(void)

	hwsampler_stop_all();
	hwsampler_deallocate();
	perf_release_sampling();
	return;
}