- 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: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -1319,7 +1319,7 @@ static const struct intel_cdclk_vals adlp_cdclk_table[] = { · 1318 unmodified lines | ||
| 1319 | 1319 | { .refclk = 24000, .cdclk = 192000, .divider = 2, .ratio = 16 }, |
| 1320 | 1320 | { .refclk = 24000, .cdclk = 312000, .divider = 2, .ratio = 26 }, |
| 1321 | 1321 | { .refclk = 24000, .cdclk = 552000, .divider = 2, .ratio = 46 }, |
| 1322 | − { .refclk = 24400, .cdclk = 648000, .divider = 2, .ratio = 54 }, | |
| 1322 | + { .refclk = 24000, .cdclk = 648000, .divider = 2, .ratio = 54 }, | |
| 1323 | 1323 | |
| 1324 | 1324 | { .refclk = 38400, .cdclk = 179200, .divider = 3, .ratio = 14 }, |
| 1325 | 1325 | { .refclk = 38400, .cdclk = 192000, .divider = 2, .ratio = 10 }, |
| @@ -1861,11 +1861,19 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv, · 1860 unmodified lines | ||
| 1861 | 1861 | vm = ctx->vm; |
| 1862 | 1862 | GEM_BUG_ON(!vm); |
| 1863 | 1863 | |
| 1864 | + /* | |
| 1865 | + * Get a reference for the allocated handle. Once the handle is | |
| 1866 | + * visible in the vm_xa table, userspace could try to close it | |
| 1867 | + * from under our feet, so we need to hold the extra reference | |
| 1868 | + * first. | |
| 1869 | + */ | |
| 1870 | + i915_vm_get(vm); | |
| 1871 | + | |
| 1864 | 1872 | err = xa_alloc(&file_priv->vm_xa, &id, vm, xa_limit_32b, GFP_KERNEL); |
| 1865 | − if (err) | |
| 1873 | + if (err) { | |
| 1874 | + i915_vm_put(vm); | |
| 1866 | 1875 | return err; |
| 1867 | − | |
| 1868 | − i915_vm_get(vm); | |
| 1876 | + } | |
| 1869 | 1877 | |
| 1870 | 1878 | GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */ |
| 1871 | 1879 | args->value = id; |
| @@ -305,10 +305,6 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, · 304 unmodified lines | ||
| 305 | 305 | spin_unlock(&obj->vma.lock); |
| 306 | 306 | |
| 307 | 307 | obj->tiling_and_stride = tiling | stride; |
| 308 | − i915_gem_object_unlock(obj); | |
| 309 | − | |
| 310 | − /* Force the fence to be reacquired for GTT access */ | |
| 311 | − i915_gem_object_release_mmap_gtt(obj); | |
| 312 | 308 | |
| 313 | 309 | /* Try to preallocate memory required to save swizzling on put-pages */ |
| 314 | 310 | if (i915_gem_object_needs_bit17_swizzle(obj)) { |
| @@ -321,6 +317,11 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, · 6 unmodified lines | ||
| 321 | 317 | obj->bit_17 = NULL; |
| 322 | 318 | } |
| 323 | 319 | |
| 320 | + i915_gem_object_unlock(obj); | |
| 321 | + | |
| 322 | + /* Force the fence to be reacquired for GTT access */ | |
| 323 | + i915_gem_object_release_mmap_gtt(obj); | |
| 324 | + | |
| 324 | 325 | return 0; |
| 325 | 326 | } |
| 326 | 327 | |
| @@ -528,7 +528,7 @@ retry: · 527 unmodified lines | ||
| 528 | 528 | return rq; |
| 529 | 529 | } |
| 530 | 530 | |
| 531 | −struct i915_request *intel_context_find_active_request(struct intel_context *ce) | |
| 531 | +struct i915_request *intel_context_get_active_request(struct intel_context *ce) | |
| 532 | 532 | { |
| 533 | 533 | struct intel_context *parent = intel_context_to_parent(ce); |
| 534 | 534 | struct i915_request *rq, *active = NULL; |
| @@ -552,6 +552,8 @@ struct i915_request *intel_context_find_active_request(struct intel_context *ce) · 17 unmodified lines | ||
| 552 | 552 | |
| 553 | 553 | active = rq; |
| 554 | 554 | } |
| 555 | + if (active) | |
| 556 | + active = i915_request_get_rcu(active); | |
| 555 | 557 | spin_unlock_irqrestore(&parent->guc_state.lock, flags); |
| 556 | 558 | |
| 557 | 559 | return active; |
| @@ -268,8 +268,7 @@ int intel_context_prepare_remote_request(struct intel_context *ce, · 267 unmodified lines | ||
| 268 | 268 | |
| 269 | 269 | struct i915_request *intel_context_create_request(struct intel_context *ce); |
| 270 | 270 | |
| 271 | −struct i915_request * | |
| 272 | −intel_context_find_active_request(struct intel_context *ce); | |
| 271 | +struct i915_request *intel_context_get_active_request(struct intel_context *ce); | |
| 273 | 272 | |
| 274 | 273 | static inline bool intel_context_is_barrier(const struct intel_context *ce) |
| 275 | 274 | { |
| @@ -248,8 +248,8 @@ void intel_engine_dump_active_requests(struct list_head *requests, · 247 unmodified lines | ||
| 248 | 248 | ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine, |
| 249 | 249 | ktime_t *now); |
| 250 | 250 | |
| 251 | −struct i915_request * | |
| 252 | −intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine); | |
| 251 | +void intel_engine_get_hung_entity(struct intel_engine_cs *engine, | |
| 252 | + struct intel_context **ce, struct i915_request **rq); | |
| 253 | 253 | |
| 254 | 254 | u32 intel_engine_context_size(struct intel_gt *gt, u8 class); |
| 255 | 255 | struct intel_context * |
| @@ -2094,17 +2094,6 @@ static void print_request_ring(struct drm_printer *m, struct i915_request *rq) · 2093 unmodified lines | ||
| 2094 | 2094 | } |
| 2095 | 2095 | } |
| 2096 | 2096 | |
| 2097 | −static unsigned long list_count(struct list_head *list) | |
| 2098 | −{ | |
| 2099 | − struct list_head *pos; | |
| 2100 | − unsigned long count = 0; | |
| 2101 | − | |
| 2102 | − list_for_each(pos, list) | |
| 2103 | − count++; | |
| 2104 | − | |
| 2105 | − return count; | |
| 2106 | −} | |
| 2107 | − | |
| 2108 | 2097 | static unsigned long read_ul(void *p, size_t x) |
| 2109 | 2098 | { |
| 2110 | 2099 | return *(unsigned long *)(p + x); |
| @@ -2196,11 +2185,11 @@ void intel_engine_dump_active_requests(struct list_head *requests, · 85 unmodified lines | ||
| 2196 | 2185 | } |
| 2197 | 2186 | } |
| 2198 | 2187 | |
| 2199 | −static void engine_dump_active_requests(struct intel_engine_cs *engine, struct drm_printer *m) | |
| 2188 | +static void engine_dump_active_requests(struct intel_engine_cs *engine, | |
| 2189 | + struct drm_printer *m) | |
| 2200 | 2190 | { |
| 2191 | + struct intel_context *hung_ce = NULL; | |
| 2201 | 2192 | struct i915_request *hung_rq = NULL; |
| 2202 | − struct intel_context *ce; | |
| 2203 | − bool guc; | |
| 2204 | 2193 | |
| 2205 | 2194 | /* |
| 2206 | 2195 | * 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 · 2 unmodified lines | ||
| 2209 | 2198 | * But the intention here is just to report an instantaneous snapshot |
| 2210 | 2199 | * so that's fine. |
| 2211 | 2200 | */ |
| 2212 | − lockdep_assert_held(&engine->sched_engine->lock); | |
| 2201 | + intel_engine_get_hung_entity(engine, &hung_ce, &hung_rq); | |
| 2213 | 2202 | |
| 2214 | 2203 | drm_printf(m, "\tRequests:\n"); |
| 2215 | 2204 | |
| 2216 | − guc = intel_uc_uses_guc_submission(&engine->gt->uc); | |
| 2217 | − if (guc) { | |
| 2218 | − ce = intel_engine_get_hung_context(engine); | |
| 2219 | − if (ce) | |
| 2220 | − hung_rq = intel_context_find_active_request(ce); | |
| 2221 | − } else { | |
| 2222 | − hung_rq = intel_engine_execlist_find_hung_request(engine); | |
| 2223 | − } | |
| 2224 | − | |
| 2225 | 2205 | if (hung_rq) |
| 2226 | 2206 | engine_dump_request(hung_rq, m, "\t\thung"); |
| 2207 | + else if (hung_ce) | |
| 2208 | + drm_printf(m, "\t\tGot hung ce but no hung rq!\n"); | |
| 2227 | 2209 | |
| 2228 | − if (guc) | |
| 2210 | + if (intel_uc_uses_guc_submission(&engine->gt->uc)) | |
| 2229 | 2211 | intel_guc_dump_active_requests(engine, hung_rq, m); |
| 2230 | 2212 | else |
| 2231 | − intel_engine_dump_active_requests(&engine->sched_engine->requests, | |
| 2232 | − hung_rq, m); | |
| 2213 | + intel_execlists_dump_active_requests(engine, hung_rq, m); | |
| 2214 | + | |
| 2215 | + if (hung_rq) | |
| 2216 | + i915_request_put(hung_rq); | |
| 2233 | 2217 | } |
| 2234 | 2218 | |
| 2235 | 2219 | void intel_engine_dump(struct intel_engine_cs *engine, |
| @@ -2239,7 +2223,6 @@ void intel_engine_dump(struct intel_engine_cs *engine, · 3 unmodified lines | ||
| 2239 | 2223 | struct i915_gpu_error * const error = &engine->i915->gpu_error; |
| 2240 | 2224 | struct i915_request *rq; |
| 2241 | 2225 | intel_wakeref_t wakeref; |
| 2242 | − unsigned long flags; | |
| 2243 | 2226 | ktime_t dummy; |
| 2244 | 2227 | |
| 2245 | 2228 | if (header) { |
| @@ -2276,13 +2259,8 @@ void intel_engine_dump(struct intel_engine_cs *engine, · 30 unmodified lines | ||
| 2276 | 2259 | i915_reset_count(error)); |
| 2277 | 2260 | print_properties(engine, m); |
| 2278 | 2261 | |
| 2279 | − spin_lock_irqsave(&engine->sched_engine->lock, flags); | |
| 2280 | 2262 | engine_dump_active_requests(engine, m); |
| 2281 | 2263 | |
| 2282 | − drm_printf(m, "\tOn hold?: %lu\n", | |
| 2283 | − list_count(&engine->sched_engine->hold)); | |
| 2284 | − spin_unlock_irqrestore(&engine->sched_engine->lock, flags); | |
| 2285 | − | |
| 2286 | 2264 | drm_printf(m, "\tMMIO base: 0x%08x\n", engine->mmio_base); |
| 2287 | 2265 | wakeref = intel_runtime_pm_get_if_in_use(engine->uncore->rpm); |
| 2288 | 2266 | if (wakeref) { |
| @@ -2328,8 +2306,7 @@ intel_engine_create_virtual(struct intel_engine_cs **siblings, · 39 unmodified lines | ||
| 2328 | 2306 | return siblings[0]->cops->create_virtual(siblings, count, flags); |
| 2329 | 2307 | } |
| 2330 | 2308 | |
| 2331 | −struct i915_request * | |
| 2332 | −intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine) | |
| 2309 | +static struct i915_request *engine_execlist_find_hung_request(struct intel_engine_cs *engine) | |
| 2333 | 2310 | { |
| 2334 | 2311 | struct i915_request *request, *active = NULL; |
| 2335 | 2312 | |
| @@ -2381,6 +2358,33 @@ intel_engine_execlist_find_hung_request(struct intel_engine_cs *engine) · 45 unmodified lines | ||
| 2381 | 2358 | return active; |
| 2382 | 2359 | } |
| 2383 | 2360 | |
| 2361 | +void intel_engine_get_hung_entity(struct intel_engine_cs *engine, | |
| 2362 | + struct intel_context **ce, struct i915_request **rq) | |
| 2363 | +{ | |
| 2364 | + unsigned long flags; | |
| 2365 | + | |
| 2366 | + *ce = intel_engine_get_hung_context(engine); | |
| 2367 | + if (*ce) { | |
| 2368 | + intel_engine_clear_hung_context(engine); | |
| 2369 | + | |
| 2370 | + *rq = intel_context_get_active_request(*ce); | |
| 2371 | + return; | |
| 2372 | + } | |
| 2373 | + | |
| 2374 | + /* | |
| 2375 | + * Getting here with GuC enabled means it is a forced error capture | |
| 2376 | + * with no actual hang. So, no need to attempt the execlist search. | |
| 2377 | + */ | |
| 2378 | + if (intel_uc_uses_guc_submission(&engine->gt->uc)) | |
| 2379 | + return; | |
| 2380 | + | |
| 2381 | + spin_lock_irqsave(&engine->sched_engine->lock, flags); | |
| 2382 | + *rq = engine_execlist_find_hung_request(engine); | |
| 2383 | + if (*rq) | |
| 2384 | + *rq = i915_request_get_rcu(*rq); | |
| 2385 | + spin_unlock_irqrestore(&engine->sched_engine->lock, flags); | |
| 2386 | +} | |
| 2387 | + | |
| 2384 | 2388 | void xehp_enable_ccs_engines(struct intel_engine_cs *engine) |
| 2385 | 2389 | { |
| 2386 | 2390 | /* |
| @@ -4148,6 +4148,33 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine, · 4147 unmodified lines | ||
| 4148 | 4148 | spin_unlock_irqrestore(&sched_engine->lock, flags); |
| 4149 | 4149 | } |
| 4150 | 4150 | |
| 4151 | +static unsigned long list_count(struct list_head *list) | |
| 4152 | +{ | |
| 4153 | + struct list_head *pos; | |
| 4154 | + unsigned long count = 0; | |
| 4155 | + | |
| 4156 | + list_for_each(pos, list) | |
| 4157 | + count++; | |
| 4158 | + | |
| 4159 | + return count; | |
| 4160 | +} | |
| 4161 | + | |
| 4162 | +void intel_execlists_dump_active_requests(struct intel_engine_cs *engine, | |
| 4163 | + struct i915_request *hung_rq, | |
| 4164 | + struct drm_printer *m) | |
| 4165 | +{ | |
| 4166 | + unsigned long flags; | |
| 4167 | + | |
| 4168 | + spin_lock_irqsave(&engine->sched_engine->lock, flags); | |
| 4169 | + | |
| 4170 | + intel_engine_dump_active_requests(&engine->sched_engine->requests, hung_rq, m); | |
| 4171 | + | |
| 4172 | + drm_printf(m, "\tOn hold?: %lu\n", | |
| 4173 | + list_count(&engine->sched_engine->hold)); | |
| 4174 | + | |
| 4175 | + spin_unlock_irqrestore(&engine->sched_engine->lock, flags); | |
| 4176 | +} | |
| 4177 | + | |
| 4151 | 4178 | #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) |
| 4152 | 4179 | #include "selftest_execlists.c" |
| 4153 | 4180 | #endif |
| @@ -32,6 +32,10 @@ void intel_execlists_show_requests(struct intel_engine_cs *engine, · 31 unmodified lines | ||
| 32 | 32 | int indent), |
| 33 | 33 | unsigned int max); |
| 34 | 34 | |
| 35 | +void intel_execlists_dump_active_requests(struct intel_engine_cs *engine, | |
| 36 | + struct i915_request *hung_rq, | |
| 37 | + struct drm_printer *m); | |
| 38 | + | |
| 35 | 39 | bool |
| 36 | 40 | intel_engine_in_execlists_submission_mode(const struct intel_engine_cs *engine); |
| 37 | 41 | |
| @@ -1702,7 +1702,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st · 1701 unmodified lines | ||
| 1702 | 1702 | goto next_context; |
| 1703 | 1703 | |
| 1704 | 1704 | guilty = false; |
| 1705 | − rq = intel_context_find_active_request(ce); | |
| 1705 | + rq = intel_context_get_active_request(ce); | |
| 1706 | 1706 | if (!rq) { |
| 1707 | 1707 | head = ce->ring->tail; |
| 1708 | 1708 | goto out_replay; |
| @@ -1715,6 +1715,7 @@ static void __guc_reset_context(struct intel_context *ce, intel_engine_mask_t st · 6 unmodified lines | ||
| 1715 | 1715 | head = intel_ring_wrap(ce->ring, rq->head); |
| 1716 | 1716 | |
| 1717 | 1717 | __i915_request_reset(rq, guilty); |
| 1718 | + i915_request_put(rq); | |
| 1718 | 1719 | out_replay: |
| 1719 | 1720 | guc_reset_state(ce, head, guilty); |
| 1720 | 1721 | next_context: |
| @@ -4817,6 +4818,8 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) · 3096 unmodified lines | ||
| 4817 | 4818 | |
| 4818 | 4819 | xa_lock_irqsave(&guc->context_lookup, flags); |
| 4819 | 4820 | xa_for_each(&guc->context_lookup, index, ce) { |
| 4821 | + bool found; | |
| 4822 | + | |
| 4820 | 4823 | if (!kref_get_unless_zero(&ce->ref)) |
| 4821 | 4824 | continue; |
| 4822 | 4825 | |
| @@ -4833,10 +4836,18 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) · 10 unmodified lines | ||
| 4833 | 4836 | goto next; |
| 4834 | 4837 | } |
| 4835 | 4838 | |
| 4839 | + found = false; | |
| 4840 | + spin_lock(&ce->guc_state.lock); | |
| 4836 | 4841 | list_for_each_entry(rq, &ce->guc_state.requests, sched.link) { |
| 4837 | 4842 | if (i915_test_request_state(rq) != I915_REQUEST_ACTIVE) |
| 4838 | 4843 | continue; |
| 4839 | 4844 | |
| 4845 | + found = true; | |
| 4846 | + break; | |
| 4847 | + } | |
| 4848 | + spin_unlock(&ce->guc_state.lock); | |
| 4849 | + | |
| 4850 | + if (found) { | |
| 4840 | 4851 | intel_engine_set_hung_context(engine, ce); |
| 4841 | 4852 | |
| 4842 | 4853 | /* Can only cope with one hang at a time... */ |
| @@ -4844,6 +4855,7 @@ void intel_guc_find_hung_context(struct intel_engine_cs *engine) · 1 unmodified line | ||
| 4844 | 4855 | xa_lock(&guc->context_lookup); |
| 4845 | 4856 | goto done; |
| 4846 | 4857 | } |
| 4858 | + | |
| 4847 | 4859 | next: |
| 4848 | 4860 | intel_context_put(ce); |
| 4849 | 4861 | xa_lock(&guc->context_lookup); |
| @@ -1596,43 +1596,20 @@ capture_engine(struct intel_engine_cs *engine, · 1595 unmodified lines | ||
| 1596 | 1596 | { |
| 1597 | 1597 | struct intel_engine_capture_vma *capture = NULL; |
| 1598 | 1598 | struct intel_engine_coredump *ee; |
| 1599 | − struct intel_context *ce; | |
| 1599 | + struct intel_context *ce = NULL; | |
| 1600 | 1600 | struct i915_request *rq = NULL; |
| 1601 | − unsigned long flags; | |
| 1602 | 1601 | |
| 1603 | 1602 | ee = intel_engine_coredump_alloc(engine, ALLOW_FAIL, dump_flags); |
| 1604 | 1603 | if (!ee) |
| 1605 | 1604 | return NULL; |
| 1606 | 1605 | |
| 1607 | − ce = intel_engine_get_hung_context(engine); | |
| 1608 | − if (ce) { | |
| 1609 | − intel_engine_clear_hung_context(engine); | |
| 1610 | − rq = intel_context_find_active_request(ce); | |
| 1611 | − if (!rq || !i915_request_started(rq)) | |
| 1612 | − goto no_request_capture; | |
| 1613 | − } else { | |
| 1614 | − /* | |
| 1615 | − * Getting here with GuC enabled means it is a forced error capture | |
| 1616 | − * with no actual hang. So, no need to attempt the execlist search. | |
| 1617 | − */ | |
| 1618 | − if (!intel_uc_uses_guc_submission(&engine->gt->uc)) { | |
| 1619 | − spin_lock_irqsave(&engine->sched_engine->lock, flags); | |
| 1620 | − rq = intel_engine_execlist_find_hung_request(engine); | |
| 1621 | − spin_unlock_irqrestore(&engine->sched_engine->lock, | |
| 1622 | − flags); | |
| 1623 | − } | |
| 1624 | − } | |
| 1625 | − if (rq) | |
| 1626 | − rq = i915_request_get_rcu(rq); | |
| 1627 | − | |
| 1628 | − if (!rq) | |
| 1606 | + intel_engine_get_hung_entity(engine, &ce, &rq); | |
| 1607 | + if (!rq || !i915_request_started(rq)) | |
| 1629 | 1608 | goto no_request_capture; |
| 1630 | 1609 | |
| 1631 | 1610 | capture = intel_engine_coredump_add_request(ee, rq, ATOMIC_MAYFAIL); |
| 1632 | − if (!capture) { | |
| 1633 | − i915_request_put(rq); | |
| 1611 | + if (!capture) | |
| 1634 | 1612 | goto no_request_capture; |
| 1635 | − } | |
| 1636 | 1613 | if (dump_flags & CORE_DUMP_FLAG_IS_GUC_CAPTURE) |
| 1637 | 1614 | intel_guc_capture_get_matching_node(engine->gt, ee, ce); |
| 1638 | 1615 | |
| @@ -1642,6 +1619,8 @@ capture_engine(struct intel_engine_cs *engine, · 3 unmodified lines | ||
| 1642 | 1619 | return ee; |
| 1643 | 1620 | |
| 1644 | 1621 | no_request_capture: |
| 1622 | + if (rq) | |
| 1623 | + i915_request_put(rq); | |
| 1645 | 1624 | kfree(ee); |
| 1646 | 1625 | return NULL; |
| 1647 | 1626 | } |