* [PATCH v2] drm/i915/pmu: convert i915_pmu->lock to raw_spinlock_t from spinlock_t
@ 2026-10-05 19:56 Anubhav Shelat
0 siblings, 0 replies; only message in thread
From: Anubhav Shelat @ 2026-10-05 19:56 UTC (permalink / raw)
To: Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin,
David Airlie, Simona Vetter, intel-gfx, dri-devel, linux-kernel
Cc: Anubhav Shelat
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. As a result, in i915_pmu_gt_parked(), we need to call and
store the return value of get_rc6(), because its call chain will take
a spinlock_t. This requires modifying park_rc6() to include it as an
argument.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anubhav Shelat <ashelat@redhat.com>
---
drivers/gpu/drm/i915/i915_pmu.c | 31 +++++++++++++++++--------------
drivers/gpu/drm/i915/i915_pmu.h | 2 +-
2 files changed, 18 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_pmu.c b/drivers/gpu/drm/i915/i915_pmu.c
index 1c3bafda9c70..31630e8f80c7 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;
}
@@ -278,11 +278,11 @@ static void init_rc6(struct i915_pmu *pmu)
}
}
-static void park_rc6(struct intel_gt *gt)
+static void park_rc6(struct intel_gt *gt, u64 val)
{
struct i915_pmu *pmu = >->i915->pmu;
- store_sample(pmu, gt->info.id, __I915_SAMPLE_RC6, __get_rc6(gt));
+ store_sample(pmu, gt->info.id, __I915_SAMPLE_RC6, val);
pmu->sleep_last[gt->info.id] = ktime_get_raw();
}
@@ -300,13 +300,16 @@ static void __i915_pmu_maybe_start_timer(struct i915_pmu *pmu)
void i915_pmu_gt_parked(struct intel_gt *gt)
{
struct i915_pmu *pmu = >->i915->pmu;
+ u64 val;
if (!pmu->registered)
return;
- spin_lock_irq(&pmu->lock);
+ val = __get_rc6(gt);
+
+ raw_spin_lock_irq(&pmu->lock);
- park_rc6(gt);
+ park_rc6(gt, val);
/*
* Signal sampling timer to stop if only engine events are enabled and
@@ -316,7 +319,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 +329,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 +339,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 +745,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 +787,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 +808,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 +841,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 +1159,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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-05 19:58 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-05 19:56 [PATCH v2] drm/i915/pmu: convert i915_pmu->lock to raw_spinlock_t from spinlock_t Anubhav Shelat
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®