container_of(event->pmu, typeof(*i915), pmu.base);
 
        drm_WARN_ON(&i915->drm, event->parent);
+
+       drm_dev_put(&i915->drm);
 }
 
 static int
 {
        struct drm_i915_private *i915 =
                container_of(event->pmu, typeof(*i915), pmu.base);
+       struct i915_pmu *pmu = &i915->pmu;
        int ret;
 
+       if (pmu->closed)
+               return -ENODEV;
+
        if (event->attr.type != event->pmu->type)
                return -ENOENT;
 
        if (ret)
                return ret;
 
-       if (!event->parent)
+       if (!event->parent) {
+               drm_dev_get(&i915->drm);
                event->destroy = i915_pmu_event_destroy;
+       }
 
        return 0;
 }
 
 static void i915_pmu_event_read(struct perf_event *event)
 {
+       struct drm_i915_private *i915 =
+               container_of(event->pmu, typeof(*i915), pmu.base);
        struct hw_perf_event *hwc = &event->hw;
+       struct i915_pmu *pmu = &i915->pmu;
        u64 prev, new;
 
+       if (pmu->closed) {
+               event->hw.state = PERF_HES_STOPPED;
+               return;
+       }
 again:
        prev = local64_read(&hwc->prev_count);
        new = __i915_pmu_event_read(event);
 
 static void i915_pmu_event_start(struct perf_event *event, int flags)
 {
+       struct drm_i915_private *i915 =
+               container_of(event->pmu, typeof(*i915), pmu.base);
+       struct i915_pmu *pmu = &i915->pmu;
+
+       if (pmu->closed)
+               return;
+
        i915_pmu_enable(event);
        event->hw.state = 0;
 }
 
 static int i915_pmu_event_add(struct perf_event *event, int flags)
 {
+       struct drm_i915_private *i915 =
+               container_of(event->pmu, typeof(*i915), pmu.base);
+       struct i915_pmu *pmu = &i915->pmu;
+
+       if (pmu->closed)
+               return -ENODEV;
+
        if (flags & PERF_EF_START)
                i915_pmu_event_start(event, flags);
 
        if (!pmu->base.event_init)
                return;
 
-       drm_WARN_ON(&i915->drm, pmu->enable);
+       /*
+        * "Disconnect" the PMU callbacks - since all are atomic synchronize_rcu
+        * ensures all currently executing ones will have exited before we
+        * proceed with unregistration.
+        */
+       pmu->closed = true;
+       synchronize_rcu();
 
        hrtimer_cancel(&pmu->timer);