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

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.orgSigned-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent fe4a3308
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/device.h>
#include <asm/apic.h> #include <asm/apic.h>
#include <asm/stacktrace.h> #include <asm/stacktrace.h>
...@@ -1210,6 +1211,7 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) ...@@ -1210,6 +1211,7 @@ x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
break; break;
case CPU_STARTING: case CPU_STARTING:
if (x86_pmu.attr_rdpmc)
set_in_cr4(X86_CR4_PCE); set_in_cr4(X86_CR4_PCE);
if (x86_pmu.cpu_starting) if (x86_pmu.cpu_starting)
x86_pmu.cpu_starting(cpu); x86_pmu.cpu_starting(cpu);
...@@ -1320,6 +1322,8 @@ static int __init init_hw_perf_events(void) ...@@ -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("... version: %d\n", x86_pmu.version);
pr_info("... bit width: %d\n", x86_pmu.cntval_bits); pr_info("... bit width: %d\n", x86_pmu.cntval_bits);
pr_info("... generic registers: %d\n", x86_pmu.num_counters); pr_info("... generic registers: %d\n", x86_pmu.num_counters);
...@@ -1555,10 +1559,59 @@ static int x86_pmu_event_idx(struct perf_event *event) ...@@ -1555,10 +1559,59 @@ static int x86_pmu_event_idx(struct perf_event *event)
return idx + 1; 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 = { static struct pmu pmu = {
.pmu_enable = x86_pmu_enable, .pmu_enable = x86_pmu_enable,
.pmu_disable = x86_pmu_disable, .pmu_disable = x86_pmu_disable,
.attr_groups = x86_pmu_attr_groups,
.event_init = x86_pmu_event_init, .event_init = x86_pmu_event_init,
.add = x86_pmu_add, .add = x86_pmu_add,
......
...@@ -307,6 +307,14 @@ struct x86_pmu { ...@@ -307,6 +307,14 @@ struct x86_pmu {
struct x86_pmu_quirk *quirks; struct x86_pmu_quirk *quirks;
int perfctr_second_write; int perfctr_second_write;
/*
* sysfs attrs
*/
int attr_rdpmc;
/*
* CPU Hotplug hooks
*/
int (*cpu_prepare)(int cpu); int (*cpu_prepare)(int cpu);
void (*cpu_starting)(int cpu); void (*cpu_starting)(int cpu);
void (*cpu_dying)(int cpu); void (*cpu_dying)(int cpu);
......
...@@ -615,6 +615,7 @@ struct pmu { ...@@ -615,6 +615,7 @@ struct pmu {
struct list_head entry; struct list_head entry;
struct device *dev; struct device *dev;
const struct attribute_group **attr_groups;
char *name; char *name;
int type; int type;
......
...@@ -5505,6 +5505,7 @@ static int pmu_dev_alloc(struct pmu *pmu) ...@@ -5505,6 +5505,7 @@ static int pmu_dev_alloc(struct pmu *pmu)
if (!pmu->dev) if (!pmu->dev)
goto out; goto out;
pmu->dev->groups = pmu->attr_groups;
device_initialize(pmu->dev); device_initialize(pmu->dev);
ret = dev_set_name(pmu->dev, "%s", pmu->name); ret = dev_set_name(pmu->dev, "%s", pmu->name);
if (ret) if (ret)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment