When perf runs event operations, it calls event_function() which takes a
raw_spinlock_t. This can eventually lead to i915_pmu_enable() taking a
spinlock_t, which causes lockdep to throw "Bug: Invalid wait context".
The call chain:

 event_function()
    __perf_ctx_lock()
      raw_spin_lock(&ctx->lock)
    __perf_event_enable()                          // efs->func()
      ctx_resched()
        perf_event_sched_in()
          ctx_sched_in()
            __pmu_ctx_sched_in()
              merge_sched_in()
                group_sched_in()
                  event_sched_in()
                    event->pmu->add()              // = i915_pmu_event_add()
                      i915_pmu_event_start()
                        i915_pmu_enable()
                          spin_lock_irqsave(&pmu->lock)

On systems running an RT kernel, spinlock_t can sleep which can cause a
sleep-in-atomic error.

Fix this by using raw_spinlock_t for i915_pmu->lock instead of
spinlock_t.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anubhav Shelat <[email protected]>
---
 drivers/gpu/drm/i915/i915_pmu.c | 22 +++++++++++-----------
 drivers/gpu/drm/i915/i915_pmu.h |  2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
index 1c3bafda9c70..65771e54b9b5 100644
--- a/drivers/gpu/drm/i915/i915_pmu.c
+++ b/drivers/gpu/drm/i915/i915_pmu.c
@@ -232,7 +232,7 @@ static u64 get_rc6(struct intel_gt *gt)
                intel_gt_pm_put_async(gt, wakeref);
        }
 
-       spin_lock_irqsave(&pmu->lock, flags);
+       raw_spin_lock_irqsave(&pmu->lock, flags);
 
        if (wakeref) {
                store_sample(pmu, gt_id, __I915_SAMPLE_RC6, val);
@@ -253,7 +253,7 @@ static u64 get_rc6(struct intel_gt *gt)
        else
                store_sample(pmu, gt_id, __I915_SAMPLE_RC6_LAST_REPORTED, val);
 
-       spin_unlock_irqrestore(&pmu->lock, flags);
+       raw_spin_unlock_irqrestore(&pmu->lock, flags);
 
        return val;
 }
@@ -304,7 +304,7 @@ void i915_pmu_gt_parked(struct intel_gt *gt)
        if (!pmu->registered)
                return;
 
-       spin_lock_irq(&pmu->lock);
+       raw_spin_lock_irq(&pmu->lock);
 
        park_rc6(gt);
 
@@ -316,7 +316,7 @@ void i915_pmu_gt_parked(struct intel_gt *gt)
        if (pmu->unparked == 0)
                pmu->timer_enabled = false;
 
-       spin_unlock_irq(&pmu->lock);
+       raw_spin_unlock_irq(&pmu->lock);
 }
 
 void i915_pmu_gt_unparked(struct intel_gt *gt)
@@ -326,7 +326,7 @@ void i915_pmu_gt_unparked(struct intel_gt *gt)
        if (!pmu->registered)
                return;
 
-       spin_lock_irq(&pmu->lock);
+       raw_spin_lock_irq(&pmu->lock);
 
        /*
         * Re-enable sampling timer when GPU goes active.
@@ -336,7 +336,7 @@ void i915_pmu_gt_unparked(struct intel_gt *gt)
 
        pmu->unparked |= BIT(gt->info.id);
 
-       spin_unlock_irq(&pmu->lock);
+       raw_spin_unlock_irq(&pmu->lock);
 }
 
 static void
@@ -742,7 +742,7 @@ static void i915_pmu_enable(struct perf_event *event)
        if (bit == -1)
                goto update;
 
-       spin_lock_irqsave(&pmu->lock, flags);
+       raw_spin_lock_irqsave(&pmu->lock, flags);
 
        /*
         * Update the bitmask of enabled events and increment
@@ -784,7 +784,7 @@ static void i915_pmu_enable(struct perf_event *event)
                engine->pmu.enable_count[sample]++;
        }
 
-       spin_unlock_irqrestore(&pmu->lock, flags);
+       raw_spin_unlock_irqrestore(&pmu->lock, flags);
 
 update:
        /*
@@ -805,7 +805,7 @@ static void i915_pmu_disable(struct perf_event *event)
        if (bit == -1)
                return;
 
-       spin_lock_irqsave(&pmu->lock, flags);
+       raw_spin_lock_irqsave(&pmu->lock, flags);
 
        if (is_engine_event(event)) {
                u8 sample = engine_event_sample(event);
@@ -838,7 +838,7 @@ static void i915_pmu_disable(struct perf_event *event)
                pmu->timer_enabled &= pmu_needs_timer(pmu);
        }
 
-       spin_unlock_irqrestore(&pmu->lock, flags);
+       raw_spin_unlock_irqrestore(&pmu->lock, flags);
 }
 
 static void i915_pmu_event_start(struct perf_event *event, int flags)
@@ -1156,7 +1156,7 @@ void i915_pmu_register(struct drm_i915_private *i915)
        };
        int ret = -ENOMEM;
 
-       spin_lock_init(&pmu->lock);
+       raw_spin_lock_init(&pmu->lock);
        hrtimer_setup(&pmu->timer, i915_sample, CLOCK_MONOTONIC, 
HRTIMER_MODE_REL);
        init_rc6(pmu);
 
diff --git a/drivers/gpu/drm/i915/i915_pmu.h b/drivers/gpu/drm/i915/i915_pmu.h
index 5826cc81858c..52d4b602310a 100644
--- a/drivers/gpu/drm/i915/i915_pmu.h
+++ b/drivers/gpu/drm/i915/i915_pmu.h
@@ -71,7 +71,7 @@ struct i915_pmu {
        /**
         * @lock: Lock protecting enable mask and ref count handling.
         */
-       spinlock_t lock;
+       raw_spinlock_t lock;
        /**
         * @unparked: GT unparked mask.
         */
-- 
2.55.0

Reply via email to