Commit 74d6c8ea authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm-intel-fixes-2023-02-02' of...

Merge tag 'drm-intel-fixes-2023-02-02' of git://anongit.freedesktop.org/drm/drm-intel into drm-fixes

- Fixes for potential use-after-free and double-free (Rob)
- GuC locking and refcount fixes (John)
- Display's reference clock value fix (Chaitanya)
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/Y9u5pHjOYcxzS5Z7@intel.com
parents abf301e1 47a2bd9d
...@@ -1319,7 +1319,7 @@ static const struct intel_cdclk_vals adlp_cdclk_table[] = { ...@@ -1319,7 +1319,7 @@ static const struct intel_cdclk_vals adlp_cdclk_table[] = {
{ .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 },
{ .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 },
{ .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 },
{ .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 }, { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 },
{ .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 }, { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 },
{ .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 },
......
...@@ -1861,11 +1861,19 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv, ...@@ -1861,11 +1861,19 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
vm = ctx->vm; vm = ctx->vm;
GEM_BUG_ON(!vm); GEM_BUG_ON(!vm);
/*
* Get a reference for the allocated handle. Once the handle is
* visible in the vm_xa table, userspace could try to close it
* from under our feet, so we need to hold the extra reference
* first.
*/
i915_vm_get(vm);
err = xa_alloc(&file_priv->vm_xa, &id, vm, xa_limit_32b, GFP_KERNEL); err = xa_alloc(&file_priv->vm_xa, &id, vm, xa_limit_32b, GFP_KERNEL);
if (err) if (err) {
i915_vm_put(vm);
return err; return err;
}
i915_vm_get(vm);
GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */ GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */
args->value = id; args->value = id;
......
...@@ -305,10 +305,6 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, ...@@ -305,10 +305,6 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
spin_unlock(&obj->vma.lock); spin_unlock(&obj->vma.lock);
obj->tiling_and_stride = tiling | stride; obj->tiling_and_stride = tiling | stride;
i915_gem_object_unlock(obj);
/* Force the fence to be reacquired for GTT access */
i915_gem_object_release_mmap_gtt(obj);
/* Try to preallocate memory required to save swizzling on put-pages */ /* Try to preallocate memory required to save swizzling on put-pages */
if (i915_gem_object_needs_bit17_swizzle(obj)) { if (i915_gem_object_needs_bit17_swizzle(obj)) {
...@@ -321,6 +317,11 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, ...@@ -321,6 +317,11 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
obj->bit_17 = NULL; obj->bit_17 = NULL;
} }
i915_gem_object_unlock(obj);
/* Force the fence to be reacquired for GTT access */
i915_gem_object_release_mmap_gtt(obj);
return 0; return 0;
} }
......
...@@ -528,7 +528,7 @@ struct i915_request *intel_context_create_request(struct intel_context *ce) ...@@ -528,7 +528,7 @@ struct i915_request *intel_context_create_request(struct intel_context *ce)
return rq; return rq;
} }
struct i915_request *intel_context_find_active_request(struct intel_context *ce) struct i915_request *intel_context_get_active_request(struct intel_context *ce)
{ {
struct intel_context *parent = intel_context_to_parent(ce); struct intel_context *parent = intel_context_to_parent(ce);
struct i915_request *rq, *active = NULL; struct i915_request *rq, *active = NULL;
...@@ -552,6 +552,8 @@ struct i915_request *intel_context_find_active_request(struct intel_context *ce) ...@@ -552,6 +552,8 @@ struct i915_request *intel_context_find_active_request(struct intel_context *ce)
active = rq; active = rq;
} }
if (active)
active = i915_request_get_rcu(active);
spin_unlock_irqrestore(&parent->guc_state.lock, flags); spin_unlock_irqrestore(&parent->guc_state.lock, flags);
return active; return active;
......
...@@ -268,8 +268,7 @@ int intel_context_prepare_remote_request(struct intel_context *ce, ...@@ -268,8 +268,7 @@ int intel_context_prepare_remote_request(struct intel_context *ce,
struct i915_request *intel_context_create_request(struct intel_context *ce); struct i915_request *intel_context_create_request(struct intel_context *ce);
struct i915_request * struct i915_request *intel_context_get_active_request(struct intel_context *ce);
intel_context_find_active_request(struct intel_context *ce);
static inline bool intel_context_is_barrier(const struct intel_context *ce) static inline bool intel_context_is_barrier(const struct intel_context *ce)
{ {
......
...@@ -248,8 +248,8 @@ void intel_engine_dump_active_requests(struct list_head *requests, ...@@ -248,8 +248,8 @@ void intel_engine_dump_active_requests(struct list_head *requests,
ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine, ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine,
ktime_t *now); ktime_t *now);
struct i915_request * void intel_engine_get_hung_entity(struct intel_engine_cs *engine,
intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine); struct intel_context **ce, struct i915_request **rq);
u32 intel_engine_context_size(struct intel_gt *gt, u8 class); u32 intel_engine_context_size(struct intel_gt *gt, u8 class);
struct intel_context * struct intel_context *
......
...@@ -2094,17 +2094,6 @@ static void print_request_ring(struct drm_printer *m, struct i915_request *rq) ...@@ -2094,17 +2094,6 @@ static void print_request_ring(struct drm_printer *m, struct i915_request *rq)
} }
} }
static unsigned long list_count(struct list_head *list)
{
struct list_head *pos;
unsigned long count = 0;
list_for_each(pos, list)
count++;
return count;
}
static unsigned long read_ul(void *p, size_t x) static unsigned long read_ul(void *p, size_t x)
{ {
return *(unsigned long *)(p + x); return *(unsigned long *)(p + x);
...@@ -2196,11 +2185,11 @@ void intel_engine_dump_active_requests(struct list_head *requests, ...@@ -2196,11 +2185,11 @@ void intel_engine_dump_active_requests(struct list_head *requests,
} }
} }
static void engine_dump_active_requests(struct intel_engine_cs *engine, struct drm_printer *m) static void engine_dump_active_requests(struct intel_engine_cs *engine,
struct drm_printer *m)
{ {
struct intel_context *hung_ce = NULL;
struct i915_request *hung_rq = NULL; struct i915_request *hung_rq = NULL;
struct intel_context *ce;
bool guc;
/* /*
* No need for an engine->irq_seqno_barrier() before the seqno reads. * No need for an engine->irq_seqno_barrier() before the seqno reads.
...@@ -2209,27 +2198,22 @@ static void engine_dump_active_requests(struct intel_engine_cs *engine, struct d ...@@ -2209,27 +2198,22 @@ static void engine_dump_active_requests(struct intel_engine_cs *engine, struct d
* But the intention here is just to report an instantaneous snapshot * But the intention here is just to report an instantaneous snapshot
* so that's fine. * so that's fine.
*/ */
lockdep_assert_held(&engine->sched_engine->lock); intel_engine_get_hung_entity(engine, &hung_ce, &hung_rq);
drm_printf(m, "\tRequests:\n"); drm_printf(m, "\tRequests:\n");
guc = intel_uc_uses_guc_submission(&engine->gt->uc);
if (guc) {
ce = intel_engine_get_hung_context(engine);
if (ce)
hung_rq = intel_context_find_active_request(ce);
} else {
hung_rq = intel_engine_execlist_find_hung_request(engine);
}
if (hung_rq) if (hung_rq)
engine_dump_request(hung_rq, m, "\t\thung"); engine_dump_request(hung_rq, m, "\t\thung");
else if (hung_ce)
drm_printf(m, "\t\tGot hung ce but no hung rq!\n");
if (guc) if (intel_uc_uses_guc_submission(&engine->gt->uc))
intel_guc_dump_active_requests(engine, hung_rq, m); intel_guc_dump_active_requests(engine, hung_rq, m);
else else
intel_engine_dump_active_requests(&engine->sched_engine->requests, intel_execlists_dump_active_requests(engine, hung_rq, m);
hung_rq, m);
if (hung_rq)
i915_request_put(hung_rq);
} }
void intel_engine_dump(struct intel_engine_cs *engine, void intel_engine_dump(struct intel_engine_cs *engine,
...@@ -2239,7 +2223,6 @@ void intel_engine_dump(struct intel_engine_cs *engine, ...@@ -2239,7 +2223,6 @@ void intel_engine_dump(struct intel_engine_cs *engine,
struct i915_gpu_error * const error = &engine->i915->gpu_error; struct i915_gpu_error * const error = &engine->i915->gpu_error;
struct i915_request *rq; struct i915_request *rq;
intel_wakeref_t wakeref; intel_wakeref_t wakeref;
unsigned long flags;
ktime_t dummy; ktime_t dummy;
if (header) { if (header) {
...@@ -2276,13 +2259,8 @@ void intel_engine_dump(struct intel_engine_cs *engine, ...@@ -2276,13 +2259,8 @@ void intel_engine_dump(struct intel_engine_cs *engine,
i915_reset_count(error)); i915_reset_count(error));
print_properties(engine, m); print_properties(engine, m);
spin_lock_irqsave(&engine->sched_engine->lock, flags);
engine_dump_active_requests(engine, m); engine_dump_active_requests(engine, m);
drm_printf(m, "\tOn hold?: %lu\n",
list_count(&engine->sched_engine->hold));
spin_unlock_irqrestore(&engine->sched_engine->lock, flags);
drm_printf(m, "\tMMIO base: 0x%08x\n", engine->mmio_base); drm_printf(m, "\tMMIO base: 0x%08x\n", engine->mmio_base);
wakeref = intel_runtime_pm_get_if_in_use(engine->uncore->rpm); wakeref = intel_runtime_pm_get_if_in_use(engine->uncore->rpm);
if (wakeref) { if (wakeref) {
...@@ -2328,8 +2306,7 @@ intel_engine_create_virtual(struct intel_engine_cs **siblings, ...@@ -2328,8 +2306,7 @@ intel_engine_create_virtual(struct intel_engine_cs **siblings,
return siblings[0]->cops->create_virtual(siblings, count, flags); return siblings[0]->cops->create_virtual(siblings, count, flags);
} }
struct i915_request * static struct i915_request *engine_execlist_find_hung_request(struct intel_engine_cs *engine)
intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine)
{ {
struct i915_request *request, *active = NULL; struct i915_request *request, *active = NULL;
...@@ -2381,6 +2358,33 @@ intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine) ...@@ -2381,6 +2358,33 @@ intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine)
return active; return active;
} }
void intel_engine_get_hung_entity(struct intel_engine_cs *engine,
struct intel_context **ce, struct i915_request **rq)
{
unsigned long flags;
*ce = intel_engine_get_hung_context(engine);
if (*ce) {
intel_engine_clear_hung_context(engine);
*rq = intel_context_get_active_request(*ce);
return;
}
/*
* Getting here with GuC enabled means it is a forced error capture
* with no actual hang. So, no need to attempt the execlist search.
*/
if (intel_uc_uses_guc_submission(&engine->gt->uc))
return;
spin_lock_irqsave(&engine->sched_engine->lock, flags);
*rq = engine_execlist_find_hung_request(engine);
if (*rq)
*rq = i915_request_get_rcu(*rq);
spin_unlock_irqrestore(&engine->sched_engine->lock, flags);
}
void xehp_enable_ccs_engines(struct intel_engine_cs *engine) void xehp_enable_ccs_engines(struct intel_engine_cs *engine)
{ {
/* /*
......
...@@ -4148,6 +4148,33 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine, ...@@ -4148,6 +4148,33 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine,
spin_unlock_irqrestore(&sched_engine->lock, flags); spin_unlock_irqrestore(&sched_engine->lock, flags);
} }
static unsigned long list_count(struct list_head *list)
{
struct list_head *pos;
unsigned long count = 0;
list_for_each(pos, list)
count++;
return count;
}
void intel_execlists_dump_active_requests(struct intel_engine_cs *engine,
struct i915_request *hung_rq,
struct drm_printer *m)
{
unsigned long flags;
spin_lock_irqsave(&engine->sched_engine->lock, flags);
intel_engine_dump_active_requests(&engine->sched_engine->requests, hung_rq, m);
drm_printf(m, "\tOn hold?: %lu\n",
list_count(&engine->sched_engine->hold));
spin_unlock_irqrestore(&engine->sched_engine->lock, flags);
}
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "selftest_execlists.c" #include "selftest_execlists.c"
#endif #endif
...@@ -32,6 +32,10 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine, ...@@ -32,6 +32,10 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine,
int indent), int indent),
unsigned int max); unsigned int max);
void intel_execlists_dump_active_requests(struct intel_engine_cs *engine,
struct i915_request *hung_rq,
struct drm_printer *m);
bool bool
intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine); intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine);
......
...@@ -1702,7 +1702,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st ...@@ -1702,7 +1702,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st
goto next_context; goto next_context;
guilty = false; guilty = false;
rq = intel_context_find_active_request(ce); rq = intel_context_get_active_request(ce);
if (!rq) { if (!rq) {
head = ce->ring->tail; head = ce->ring->tail;
goto out_replay; goto out_replay;
...@@ -1715,6 +1715,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st ...@@ -1715,6 +1715,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st
head = intel_ring_wrap(ce->ring, rq->head); head = intel_ring_wrap(ce->ring, rq->head);
__i915_request_reset(rq, guilty); __i915_request_reset(rq, guilty);
i915_request_put(rq);
out_replay: out_replay:
guc_reset_state(ce, head, guilty); guc_reset_state(ce, head, guilty);
next_context: next_context:
...@@ -4817,6 +4818,8 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) ...@@ -4817,6 +4818,8 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine)
xa_lock_irqsave(&guc->context_lookup, flags); xa_lock_irqsave(&guc->context_lookup, flags);
xa_for_each(&guc->context_lookup, index, ce) { xa_for_each(&guc->context_lookup, index, ce) {
bool found;
if (!kref_get_unless_zero(&ce->ref)) if (!kref_get_unless_zero(&ce->ref))
continue; continue;
...@@ -4833,10 +4836,18 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) ...@@ -4833,10 +4836,18 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine)
goto next; goto next;
} }
found = false;
spin_lock(&ce->guc_state.lock);
list_for_each_entry(rq, &ce->guc_state.requests, sched.link) { list_for_each_entry(rq, &ce->guc_state.requests, sched.link) {
if (i915_test_request_state(rq) != I915_REQUEST_ACTIVE) if (i915_test_request_state(rq) != I915_REQUEST_ACTIVE)
continue; continue;
found = true;
break;
}
spin_unlock(&ce->guc_state.lock);
if (found) {
intel_engine_set_hung_context(engine, ce); intel_engine_set_hung_context(engine, ce);
/* Can only cope with one hang at a time... */ /* Can only cope with one hang at a time... */
...@@ -4844,6 +4855,7 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) ...@@ -4844,6 +4855,7 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine)
xa_lock(&guc->context_lookup); xa_lock(&guc->context_lookup);
goto done; goto done;
} }
next: next:
intel_context_put(ce); intel_context_put(ce);
xa_lock(&guc->context_lookup); xa_lock(&guc->context_lookup);
......
...@@ -1596,43 +1596,20 @@ capture_engine(struct intel_engine_cs *engine, ...@@ -1596,43 +1596,20 @@ capture_engine(struct intel_engine_cs *engine,
{ {
struct intel_engine_capture_vma *capture = NULL; struct intel_engine_capture_vma *capture = NULL;
struct intel_engine_coredump *ee; struct intel_engine_coredump *ee;
struct intel_context *ce; struct intel_context *ce = NULL;
struct i915_request *rq = NULL; struct i915_request *rq = NULL;
unsigned long flags;
ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL, dump_flags); ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL, dump_flags);
if (!ee) if (!ee)
return NULL; return NULL;
ce = intel_engine_get_hung_context(engine); intel_engine_get_hung_entity(engine, &ce, &rq);
if (ce) { if (!rq || !i915_request_started(rq))
intel_engine_clear_hung_context(engine);
rq = intel_context_find_active_request(ce);
if (!rq || !i915_request_started(rq))
goto no_request_capture;
} else {
/*
* Getting here with GuC enabled means it is a forced error capture
* with no actual hang. So, no need to attempt the execlist search.
*/
if (!intel_uc_uses_guc_submission(&engine->gt->uc)) {
spin_lock_irqsave(&engine->sched_engine->lock, flags);
rq = intel_engine_execlist_find_hung_request(engine);
spin_unlock_irqrestore(&engine->sched_engine->lock,
flags);
}
}
if (rq)
rq = i915_request_get_rcu(rq);
if (!rq)
goto no_request_capture; goto no_request_capture;
capture = intel_engine_coredump_add_request(ee, rq, ATOMIC_MAYFAIL); capture = intel_engine_coredump_add_request(ee, rq, ATOMIC_MAYFAIL);
if (!capture) { if (!capture)
i915_request_put(rq);
goto no_request_capture; goto no_request_capture;
}
if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE) if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE)
intel_guc_capture_get_matching_node(engine->gt, ee, ce); intel_guc_capture_get_matching_node(engine->gt, ee, ce);
...@@ -1642,6 +1619,8 @@ capture_engine(struct intel_engine_cs *engine, ...@@ -1642,6 +1619,8 @@ capture_engine(struct intel_engine_cs *engine,
return ee; return ee;
no_request_capture: no_request_capture:
if (rq)
i915_request_put(rq);
kfree(ee); kfree(ee);
return NULL; return NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment