hwc->last_tag == cpuc->tags[i];
 }
 
-static void __x86_pmu_disable(struct perf_event *event, struct cpu_hw_events *cpuc);
+static void x86_pmu_stop(struct perf_event *event);
 
 void hw_perf_enable(void)
 {
                            match_prev_assignment(hwc, cpuc, i))
                                continue;
 
-                       __x86_pmu_disable(event, cpuc);
+                       x86_pmu_stop(event);
 
                        hwc->idx = -1;
                }
        return 0;
 }
 
+static int x86_pmu_start(struct perf_event *event)
+{
+       struct hw_perf_event *hwc = &event->hw;
+
+       if (hwc->idx == -1)
+               return -EAGAIN;
+
+       x86_perf_event_set_period(event, hwc, hwc->idx);
+       x86_pmu.enable(hwc, hwc->idx);
+
+       return 0;
+}
+
 static void x86_pmu_unthrottle(struct perf_event *event)
 {
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        event->pending_kill = POLL_IN;
 }
 
-static void __x86_pmu_disable(struct perf_event *event, struct cpu_hw_events *cpuc)
+static void x86_pmu_stop(struct perf_event *event)
 {
+       struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        struct hw_perf_event *hwc = &event->hw;
        int idx = hwc->idx;
 
        struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
        int i;
 
-       __x86_pmu_disable(event, cpuc);
+       x86_pmu_stop(event);
 
        for (i = 0; i < cpuc->n_events; i++) {
                if (event == cpuc->event_list[i]) {
 static const struct pmu pmu = {
        .enable         = x86_pmu_enable,
        .disable        = x86_pmu_disable,
+       .start          = x86_pmu_start,
+       .stop           = x86_pmu_stop,
        .read           = x86_pmu_read,
        .unthrottle     = x86_pmu_unthrottle,
 };
 
 struct pmu {
        int (*enable)                   (struct perf_event *event);
        void (*disable)                 (struct perf_event *event);
+       int (*start)                    (struct perf_event *event);
+       void (*stop)                    (struct perf_event *event);
        void (*read)                    (struct perf_event *event);
        void (*unthrottle)              (struct perf_event *event);
 };
 
        return div64_u64(dividend, divisor);
 }
 
+static void perf_event_stop(struct perf_event *event)
+{
+       if (!event->pmu->stop)
+               return event->pmu->disable(event);
+
+       return event->pmu->stop(event);
+}
+
+static int perf_event_start(struct perf_event *event)
+{
+       if (!event->pmu->start)
+               return event->pmu->enable(event);
+
+       return event->pmu->start(event);
+}
+
 static void perf_adjust_period(struct perf_event *event, u64 nsec, u64 count)
 {
        struct hw_perf_event *hwc = &event->hw;
 
        if (atomic64_read(&hwc->period_left) > 8*sample_period) {
                perf_disable();
-               event->pmu->disable(event);
+               perf_event_stop(event);
                atomic64_set(&hwc->period_left, 0);
-               event->pmu->enable(event);
+               perf_event_start(event);
                perf_enable();
        }
 }