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

Commit 0c9d42ed authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

perf, x86: Provide means for disabling userspace RDPMC



Allow the disabling of RDPMC via a pmu specific attribute:

  echo 0 > /sys/bus/event_source/devices/cpu/rdpmc

Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Arun Sharma <asharma@fb.com>
Link: http://lkml.kernel.org/n/tip-pqeog465zo5hsimtkfz73f27@git.kernel.org


Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent fe4a3308
Loading
Loading
Loading
Loading
+54 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/bitops.h>
#include <linux/device.h>

#include <asm/apic.h>
#include <asm/stacktrace.h>
@@ -1210,6 +1211,7 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
		break;

	case CPU_STARTING:
		if (x86_pmu.attr_rdpmc)
			set_in_cr4(X86_CR4_PCE);
		if (x86_pmu.cpu_starting)
			x86_pmu.cpu_starting(cpu);
@@ -1320,6 +1322,8 @@ static int __init init_hw_perf_events(void)
		}
	}

	x86_pmu.attr_rdpmc = 1; /* enable userspace RDPMC usage by default */

	pr_info("... version:                %d\n",     x86_pmu.version);
	pr_info("... bit width:              %d\n",     x86_pmu.cntval_bits);
	pr_info("... generic registers:      %d\n",     x86_pmu.num_counters);
@@ -1555,10 +1559,59 @@ static int x86_pmu_event_idx(struct perf_event *event)
	return idx + 1;
}

static ssize_t get_attr_rdpmc(struct device *cdev,
			      struct device_attribute *attr,
			      char *buf)
{
	return snprintf(buf, 40, "%d\n", x86_pmu.attr_rdpmc);
}

static void change_rdpmc(void *info)
{
	bool enable = !!(unsigned long)info;

	if (enable)
		set_in_cr4(X86_CR4_PCE);
	else
		clear_in_cr4(X86_CR4_PCE);
}

static ssize_t set_attr_rdpmc(struct device *cdev,
			      struct device_attribute *attr,
			      const char *buf, size_t count)
{
	unsigned long val = simple_strtoul(buf, NULL, 0);

	if (!!val != !!x86_pmu.attr_rdpmc) {
		x86_pmu.attr_rdpmc = !!val;
		smp_call_function(change_rdpmc, (void *)val, 1);
	}

	return count;
}

static DEVICE_ATTR(rdpmc, S_IRUSR | S_IWUSR, get_attr_rdpmc, set_attr_rdpmc);

static struct attribute *x86_pmu_attrs[] = {
	&dev_attr_rdpmc.attr,
	NULL,
};

static struct attribute_group x86_pmu_attr_group = {
	.attrs = x86_pmu_attrs,
};

static const struct attribute_group *x86_pmu_attr_groups[] = {
	&x86_pmu_attr_group,
	NULL,
};

static struct pmu pmu = {
	.pmu_enable	= x86_pmu_enable,
	.pmu_disable	= x86_pmu_disable,

	.attr_groups	= x86_pmu_attr_groups,

	.event_init	= x86_pmu_event_init,

	.add		= x86_pmu_add,
+8 −0
Original line number Diff line number Diff line
@@ -307,6 +307,14 @@ struct x86_pmu {
	struct x86_pmu_quirk *quirks;
	int		perfctr_second_write;

	/*
	 * sysfs attrs
	 */
	int		attr_rdpmc;

	/*
	 * CPU Hotplug hooks
	 */
	int		(*cpu_prepare)(int cpu);
	void		(*cpu_starting)(int cpu);
	void		(*cpu_dying)(int cpu);
+1 −0
Original line number Diff line number Diff line
@@ -615,6 +615,7 @@ struct pmu {
	struct list_head		entry;

	struct device			*dev;
	const struct attribute_group	**attr_groups;
	char				*name;
	int				type;

+1 −0
Original line number Diff line number Diff line
@@ -5505,6 +5505,7 @@ static int pmu_dev_alloc(struct pmu *pmu)
	if (!pmu->dev)
		goto out;

	pmu->dev->groups = pmu->attr_groups;
	device_initialize(pmu->dev);
	ret = dev_set_name(pmu->dev, "%s", pmu->name);
	if (ret)