|
@@ -426,7 +426,65 @@ set_ext_hw_attr(struct hw_perf_event *hwc, struct perf_event_attr *attr)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int x86_setup_perfctr(struct perf_event *event);
|
|
|
+static int x86_setup_perfctr(struct perf_event *event)
|
|
|
+{
|
|
|
+ struct perf_event_attr *attr = &event->attr;
|
|
|
+ struct hw_perf_event *hwc = &event->hw;
|
|
|
+ u64 config;
|
|
|
+
|
|
|
+ if (!hwc->sample_period) {
|
|
|
+ hwc->sample_period = x86_pmu.max_period;
|
|
|
+ hwc->last_period = hwc->sample_period;
|
|
|
+ atomic64_set(&hwc->period_left, hwc->sample_period);
|
|
|
+ } else {
|
|
|
+ /*
|
|
|
+ * If we have a PMU initialized but no APIC
|
|
|
+ * interrupts, we cannot sample hardware
|
|
|
+ * events (user-space has to fall back and
|
|
|
+ * sample via a hrtimer based software event):
|
|
|
+ */
|
|
|
+ if (!x86_pmu.apic)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (attr->type == PERF_TYPE_RAW)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ if (attr->type == PERF_TYPE_HW_CACHE)
|
|
|
+ return set_ext_hw_attr(hwc, attr);
|
|
|
+
|
|
|
+ if (attr->config >= x86_pmu.max_events)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * The generic map:
|
|
|
+ */
|
|
|
+ config = x86_pmu.event_map(attr->config);
|
|
|
+
|
|
|
+ if (config == 0)
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ if (config == -1LL)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Branch tracing:
|
|
|
+ */
|
|
|
+ if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
|
|
|
+ (hwc->sample_period == 1)) {
|
|
|
+ /* BTS is not supported by this architecture. */
|
|
|
+ if (!x86_pmu.bts)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+
|
|
|
+ /* BTS is currently only allowed for user-mode. */
|
|
|
+ if (!attr->exclude_kernel)
|
|
|
+ return -EOPNOTSUPP;
|
|
|
+ }
|
|
|
+
|
|
|
+ hwc->config |= config;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
static int x86_pmu_hw_config(struct perf_event *event)
|
|
|
{
|
|
@@ -493,66 +551,6 @@ static int __hw_perf_event_init(struct perf_event *event)
|
|
|
return x86_setup_perfctr(event);
|
|
|
}
|
|
|
|
|
|
-static int x86_setup_perfctr(struct perf_event *event)
|
|
|
-{
|
|
|
- struct perf_event_attr *attr = &event->attr;
|
|
|
- struct hw_perf_event *hwc = &event->hw;
|
|
|
- u64 config;
|
|
|
-
|
|
|
- if (!hwc->sample_period) {
|
|
|
- hwc->sample_period = x86_pmu.max_period;
|
|
|
- hwc->last_period = hwc->sample_period;
|
|
|
- atomic64_set(&hwc->period_left, hwc->sample_period);
|
|
|
- } else {
|
|
|
- /*
|
|
|
- * If we have a PMU initialized but no APIC
|
|
|
- * interrupts, we cannot sample hardware
|
|
|
- * events (user-space has to fall back and
|
|
|
- * sample via a hrtimer based software event):
|
|
|
- */
|
|
|
- if (!x86_pmu.apic)
|
|
|
- return -EOPNOTSUPP;
|
|
|
- }
|
|
|
-
|
|
|
- if (attr->type == PERF_TYPE_RAW)
|
|
|
- return 0;
|
|
|
-
|
|
|
- if (attr->type == PERF_TYPE_HW_CACHE)
|
|
|
- return set_ext_hw_attr(hwc, attr);
|
|
|
-
|
|
|
- if (attr->config >= x86_pmu.max_events)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- /*
|
|
|
- * The generic map:
|
|
|
- */
|
|
|
- config = x86_pmu.event_map(attr->config);
|
|
|
-
|
|
|
- if (config == 0)
|
|
|
- return -ENOENT;
|
|
|
-
|
|
|
- if (config == -1LL)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- /*
|
|
|
- * Branch tracing:
|
|
|
- */
|
|
|
- if ((attr->config == PERF_COUNT_HW_BRANCH_INSTRUCTIONS) &&
|
|
|
- (hwc->sample_period == 1)) {
|
|
|
- /* BTS is not supported by this architecture. */
|
|
|
- if (!x86_pmu.bts)
|
|
|
- return -EOPNOTSUPP;
|
|
|
-
|
|
|
- /* BTS is currently only allowed for user-mode. */
|
|
|
- if (!attr->exclude_kernel)
|
|
|
- return -EOPNOTSUPP;
|
|
|
- }
|
|
|
-
|
|
|
- hwc->config |= config;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static void x86_pmu_disable_all(void)
|
|
|
{
|
|
|
struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
|