special i915-gem-next pull as requested - Conversion to dma_resv_locking, obj->mm.lock is gone (Maarten, with help from Thomas Hellström) - watchdog (Tvrtko, one patch to cancel individual request from Chris) - legacy ioctl cleanup (Jason+Ashutosh) - i915-gem TODO and RFC process doc (me) - i915_ prefix for vma_lookup (Liam Howlett) just because I spotted it and put it in here too Signed-off-by: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -16,6 +16,7 @@ Linux GPU Driver Developer's Guide · 15 unmodified lines | ||
| 16 | 16 | vga-switcheroo |
| 17 | 17 | vgaarbiter |
| 18 | 18 | todo |
| 19 | + rfc/index | |
| 19 | 20 | |
| 20 | 21 | .. only:: subproject and html |
| 21 | 22 | |
| @@ -0,0 +1,17 @@ | ||
| 1 | +=============== | |
| 2 | +GPU RFC Section | |
| 3 | +=============== | |
| 4 | + | |
| 5 | +For complex work, especially new uapi, it is often good to nail the high level | |
| 6 | +design issues before getting lost in the code details. This section is meant to | |
| 7 | +host such documentation: | |
| 8 | + | |
| 9 | +* Each RFC should be a section in this file, explaining the goal and main design | |
| 10 | + considerations. Especially for uapi make sure you Cc: all relevant project | |
| 11 | + mailing lists and involved people outside of dri-devel. | |
| 12 | + | |
| 13 | +* For uapi structures add a file to this directory with and then pull the | |
| 14 | + kerneldoc in like with real uapi headers. | |
| 15 | + | |
| 16 | +* Once the code has landed move all the documentation to the right places in | |
| 17 | + the main core, helper or driver sections. | |
| @@ -1,3 +1,17 @@ | ||
| 1 | +config DRM_I915_REQUEST_TIMEOUT | |
| 2 | + int "Default timeout for requests (ms)" | |
| 3 | + default 20000 # milliseconds | |
| 4 | + help | |
| 5 | + Configures the default timeout after which any user submissions will | |
| 6 | + be forcefully terminated. | |
| 7 | + | |
| 8 | + Beware setting this value lower, or close to heartbeat interval | |
| 9 | + rounded to whole seconds times three, in order to avoid allowing | |
| 10 | + misbehaving applications causing total rendering failure in unrelated | |
| 11 | + clients. | |
| 12 | + | |
| 13 | + May be 0 to disable the timeout. | |
| 14 | + | |
| 1 | 15 | config DRM_I915_FENCE_TIMEOUT |
| 2 | 16 | int "Timeout for unsignaled foreign fences (ms, jiffy granularity)" |
| 3 | 17 | default 10000 # milliseconds |
| @@ -139,7 +139,6 @@ gem-y += \ · 138 unmodified lines | ||
| 139 | 139 | gem/i915_gem_dmabuf.o \ |
| 140 | 140 | gem/i915_gem_domain.o \ |
| 141 | 141 | gem/i915_gem_execbuffer.o \ |
| 142 | − gem/i915_gem_fence.o \ | |
| 143 | 142 | gem/i915_gem_internal.o \ |
| 144 | 143 | gem/i915_gem_object.o \ |
| 145 | 144 | gem/i915_gem_object_blt.o \ |
| @@ -0,0 +1,41 @@ | ||
| 1 | +gem/gt TODO items | |
| 2 | +----------------- | |
| 3 | + | |
| 4 | +- For discrete memory manager, merge enough dg1 to be able to refactor it to | |
| 5 | + TTM. Then land pci ids (just in case that turns up an uapi problem). TTM has | |
| 6 | + improved a lot the past 2 years, there's no reason anymore not to use it. | |
| 7 | + | |
| 8 | +- Come up with a plan what to do with drm/scheduler and how to get there. | |
| 9 | + | |
| 10 | +- Roll out dma_fence critical section annotations. | |
| 11 | + | |
| 12 | +- There's a lot of complexity added past few years to make relocations faster. | |
| 13 | + That doesn't make sense given hw and gpu apis moved away from this model years | |
| 14 | + ago: | |
| 15 | + 1. Land a modern pre-bound uapi like VM_BIND | |
| 16 | + 2. Any complexity added in this area past few years which can't be justified | |
| 17 | + with VM_BIND using userspace should be removed. Looking at amdgpu dma_resv on | |
| 18 | + the bo and vm, plus some lru locks is all that needed. No complex rcu, | |
| 19 | + refcounts, caching, ... on everything. | |
| 20 | + This is the matching task on the vm side compared to ttm/dma_resv on the | |
| 21 | + backing storage side. | |
| 22 | + | |
| 23 | +- i915_sw_fence seems to be the main structure for the i915-gem dma_fence model. | |
| 24 | + How-to-dma_fence is core and drivers really shouldn't build their own world | |
| 25 | + here, treating everything else as a fixed platform. i915_sw_fence concepts | |
| 26 | + should be moved to dma_fence, drm/scheduler or atomic commit helpers. Or | |
| 27 | + removed if dri-devel consensus is that it's not a good idea. Once that's done | |
| 28 | + maybe even remove it if there's nothing left. | |
| 29 | + | |
| 30 | +Smaller things: | |
| 31 | +- i915_utils.h needs to be moved to the right places. | |
| 32 | + | |
| 33 | +- dma_fence_work should be in drivers/dma-buf | |
| 34 | + | |
| 35 | +- i915_mm.c should be moved to the right places. Some of the helpers also look a | |
| 36 | + bit fishy: | |
| 37 | + | |
| 38 | + https://lore.kernel.org/linux-mm/20210301083320.943079-1-hch@lst.de/ | |
| 39 | + | |
| 40 | +- tasklet helpers in i915_gem.h also look a bit misplaced and should | |
| 41 | + probably be moved to tasklet headers. | |
| @@ -1091,6 +1091,7 @@ static bool intel_plane_uses_fence(const struct intel_plane_state *plane_state) · 1090 unmodified lines | ||
| 1091 | 1091 | |
| 1092 | 1092 | struct i915_vma * |
| 1093 | 1093 | intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, |
| 1094 | + bool phys_cursor, | |
| 1094 | 1095 | const struct i915_ggtt_view *view, |
| 1095 | 1096 | bool uses_fence, |
| 1096 | 1097 | unsigned long *out_flags) |
| @@ -1099,14 +1100,19 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, · 2 unmodified lines | ||
| 1099 | 1100 | struct drm_i915_private *dev_priv = to_i915(dev); |
| 1100 | 1101 | struct drm_i915_gem_object *obj = intel_fb_obj(fb); |
| 1101 | 1102 | intel_wakeref_t wakeref; |
| 1103 | + struct i915_gem_ww_ctx ww; | |
| 1102 | 1104 | struct i915_vma *vma; |
| 1103 | 1105 | unsigned int pinctl; |
| 1104 | 1106 | u32 alignment; |
| 1107 | + int ret; | |
| 1105 | 1108 | |
| 1106 | 1109 | if (drm_WARN_ON(dev, !i915_gem_object_is_framebuffer(obj))) |
| 1107 | 1110 | return ERR_PTR(-EINVAL); |
| 1108 | 1111 | |
| 1109 | − alignment = intel_surf_alignment(fb, 0); | |
| 1112 | + if (phys_cursor) | |
| 1113 | + alignment = intel_cursor_alignment(dev_priv); | |
| 1114 | + else | |
| 1115 | + alignment = intel_surf_alignment(fb, 0); | |
| 1110 | 1116 | if (drm_WARN_ON(dev, alignment && !is_power_of_2(alignment))) |
| 1111 | 1117 | return ERR_PTR(-EINVAL); |
| 1112 | 1118 | |
| @@ -1141,14 +1147,26 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, · 28 unmodified lines | ||
| 1141 | 1147 | if (HAS_GMCH(dev_priv)) |
| 1142 | 1148 | pinctl |= PIN_MAPPABLE; |
| 1143 | 1149 | |
| 1144 | − vma = i915_gem_object_pin_to_display_plane(obj, | |
| 1145 | − alignment, view, pinctl); | |
| 1146 | − if (IS_ERR(vma)) | |
| 1150 | + i915_gem_ww_ctx_init(&ww, true); | |
| 1151 | +retry: | |
| 1152 | + ret = i915_gem_object_lock(obj, &ww); | |
| 1153 | + if (!ret && phys_cursor) | |
| 1154 | + ret = i915_gem_object_attach_phys(obj, alignment); | |
| 1155 | + if (!ret) | |
| 1156 | + ret = i915_gem_object_pin_pages(obj); | |
| 1157 | + if (ret) | |
| 1147 | 1158 | goto err; |
| 1148 | 1159 | |
| 1149 | − if (uses_fence && i915_vma_is_map_and_fenceable(vma)) { | |
| 1150 | − int ret; | |
| 1160 | + if (!ret) { | |
| 1161 | + vma = i915_gem_object_pin_to_display_plane(obj, &ww, alignment, | |
| 1162 | + view, pinctl); | |
| 1163 | + if (IS_ERR(vma)) { | |
| 1164 | + ret = PTR_ERR(vma); | |
| 1165 | + goto err_unpin; | |
| 1166 | + } | |
| 1167 | + } | |
| 1151 | 1168 | |
| 1169 | + if (uses_fence && i915_vma_is_map_and_fenceable(vma)) { | |
| 1152 | 1170 | /* |
| 1153 | 1171 | * Install a fence for tiled scan-out. Pre-i965 always needs a |
| 1154 | 1172 | * fence, whereas 965+ only requires a fence if using |
| @@ -1169,16 +1187,28 @@ intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, · 14 unmodified lines | ||
| 1169 | 1187 | ret = i915_vma_pin_fence(vma); |
| 1170 | 1188 | if (ret != 0 && INTEL_GEN(dev_priv) < 4) { |
| 1171 | 1189 | i915_vma_unpin(vma); |
| 1172 | − vma = ERR_PTR(ret); | |
| 1173 | − goto err; | |
| 1190 | + goto err_unpin; | |
| 1174 | 1191 | } |
| 1192 | + ret = 0; | |
| 1175 | 1193 | |
| 1176 | − if (ret == 0 && vma->fence) | |
| 1194 | + if (vma->fence) | |
| 1177 | 1195 | *out_flags |= PLANE_HAS_FENCE; |
| 1178 | 1196 | } |
| 1179 | 1197 | |
| 1180 | 1198 | i915_vma_get(vma); |
| 1199 | + | |
| 1200 | +err_unpin: | |
| 1201 | + i915_gem_object_unpin_pages(obj); | |
| 1181 | 1202 | err: |
| 1203 | + if (ret == -EDEADLK) { | |
| 1204 | + ret = i915_gem_ww_ctx_backoff(&ww); | |
| 1205 | + if (!ret) | |
| 1206 | + goto retry; | |
| 1207 | + } | |
| 1208 | + i915_gem_ww_ctx_fini(&ww); | |
| 1209 | + if (ret) | |
| 1210 | + vma = ERR_PTR(ret); | |
| 1211 | + | |
| 1182 | 1212 | atomic_dec(&dev_priv->gpu_error.pending_fb_pin); |
| 1183 | 1213 | intel_runtime_pm_put(&dev_priv->runtime_pm, wakeref); |
| 1184 | 1214 | return vma; |
| @@ -11333,19 +11363,11 @@ int intel_plane_pin_fb(struct intel_plane_state *plane_state) · 10148 unmodified lines | ||
| 11333 | 11363 | struct drm_i915_private *dev_priv = to_i915(plane->base.dev); |
| 11334 | 11364 | struct drm_framebuffer *fb = plane_state->hw.fb; |
| 11335 | 11365 | struct i915_vma *vma; |
| 11366 | + bool phys_cursor = | |
| 11367 | + plane->id == PLANE_CURSOR && | |
| 11368 | + INTEL_INFO(dev_priv)->display.cursor_needs_physical; | |
| 11336 | 11369 | |
| 11337 | − if (plane->id == PLANE_CURSOR && | |
| 11338 | − INTEL_INFO(dev_priv)->display.cursor_needs_physical) { | |
| 11339 | − struct drm_i915_gem_object *obj = intel_fb_obj(fb); | |
| 11340 | − const int align = intel_cursor_alignment(dev_priv); | |
| 11341 | − int err; | |
| 11342 | − | |
| 11343 | − err = i915_gem_object_attach_phys(obj, align); | |
| 11344 | − if (err) | |
| 11345 | − return err; | |
| 11346 | − } | |
| 11347 | − | |
| 11348 | − vma = intel_pin_and_fence_fb_obj(fb, | |
| 11370 | + vma = intel_pin_and_fence_fb_obj(fb, phys_cursor, | |
| 11349 | 11371 | &plane_state->view, |
| 11350 | 11372 | intel_plane_uses_fence(plane_state), |
| 11351 | 11373 | &plane_state->flags); |
| @@ -11437,13 +11459,8 @@ intel_prepare_plane_fb(struct drm_plane *_plane, · 85 unmodified lines | ||
| 11437 | 11459 | if (!obj) |
| 11438 | 11460 | return 0; |
| 11439 | 11461 | |
| 11440 | − ret = i915_gem_object_pin_pages(obj); | |
| 11441 | − if (ret) | |
| 11442 | − return ret; | |
| 11443 | 11462 | |
| 11444 | 11463 | ret = intel_plane_pin_fb(new_plane_state); |
| 11445 | − | |
| 11446 | − i915_gem_object_unpin_pages(obj); | |
| 11447 | 11464 | if (ret) |
| 11448 | 11465 | return ret; |
| 11449 | 11466 | |
| @@ -11905,7 +11922,7 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, · 455 unmodified lines | ||
| 11905 | 11922 | struct drm_i915_gem_object *obj = intel_fb_obj(fb); |
| 11906 | 11923 | struct drm_i915_private *i915 = to_i915(obj->base.dev); |
| 11907 | 11924 | |
| 11908 | − if (obj->userptr.mm) { | |
| 11925 | + if (i915_gem_object_is_userptr(obj)) { | |
| 11909 | 11926 | drm_dbg(&i915->drm, |
| 11910 | 11927 | "attempting to use a userptr for a framebuffer, denied\n"); |
| 11911 | 11928 | return -EINVAL; |
| @@ -573,7 +573,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, · 572 unmodified lines | ||
| 573 | 573 | struct intel_load_detect_pipe *old, |
| 574 | 574 | struct drm_modeset_acquire_ctx *ctx); |
| 575 | 575 | struct i915_vma * |
| 576 | −intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, | |
| 576 | +intel_pin_and_fence_fb_obj(struct drm_framebuffer *fb, bool phys_cursor, | |
| 577 | 577 | const struct i915_ggtt_view *view, |
| 578 | 578 | bool uses_fence, |
| 579 | 579 | unsigned long *out_flags); |
| @@ -293,7 +293,7 @@ void intel_dsb_prepare(struct intel_crtc_state *crtc_state) · 292 unmodified lines | ||
| 293 | 293 | goto out; |
| 294 | 294 | } |
| 295 | 295 | |
| 296 | − buf = i915_gem_object_pin_map(vma->obj, I915_MAP_WC); | |
| 296 | + buf = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WC); | |
| 297 | 297 | if (IS_ERR(buf)) { |
| 298 | 298 | drm_err(&i915->drm, "Command buffer creation failed\n"); |
| 299 | 299 | i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP); |
| @@ -211,7 +211,7 @@ static int intelfb_create(struct drm_fb_helper *helper, · 210 unmodified lines | ||
| 211 | 211 | * This also validates that any existing fb inherited from the |
| 212 | 212 | * BIOS is suitable for own access. |
| 213 | 213 | */ |
| 214 | − vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, | |
| 214 | + vma = intel_pin_and_fence_fb_obj(&ifbdev->fb->base, false, | |
| 215 | 215 | &view, false, &flags); |
| 216 | 216 | if (IS_ERR(vma)) { |
| 217 | 217 | ret = PTR_ERR(vma); |
| @@ -755,6 +755,32 @@ static u32 overlay_cmd_reg(struct drm_intel_overlay_put_image *params) · 754 unmodified lines | ||
| 755 | 755 | return cmd; |
| 756 | 756 | } |
| 757 | 757 | |
| 758 | +static struct i915_vma *intel_overlay_pin_fb(struct drm_i915_gem_object *new_bo) | |
| 759 | +{ | |
| 760 | + struct i915_gem_ww_ctx ww; | |
| 761 | + struct i915_vma *vma; | |
| 762 | + int ret; | |
| 763 | + | |
| 764 | + i915_gem_ww_ctx_init(&ww, true); | |
| 765 | +retry: | |
| 766 | + ret = i915_gem_object_lock(new_bo, &ww); | |
| 767 | + if (!ret) { | |
| 768 | + vma = i915_gem_object_pin_to_display_plane(new_bo, &ww, 0, | |
| 769 | + NULL, PIN_MAPPABLE); | |
| 770 | + ret = PTR_ERR_OR_ZERO(vma); | |
| 771 | + } | |
| 772 | + if (ret == -EDEADLK) { | |
| 773 | + ret = i915_gem_ww_ctx_backoff(&ww); | |
| 774 | + if (!ret) | |
| 775 | + goto retry; | |
| 776 | + } | |
| 777 | + i915_gem_ww_ctx_fini(&ww); | |
| 778 | + if (ret) | |
| 779 | + return ERR_PTR(ret); | |
| 780 | + | |
| 781 | + return vma; | |
| 782 | +} | |
| 783 | + | |
| 758 | 784 | static int intel_overlay_do_put_image(struct intel_overlay *overlay, |
| 759 | 785 | struct drm_i915_gem_object *new_bo, |
| 760 | 786 | struct drm_intel_overlay_put_image *params) |
| @@ -776,12 +802,10 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, · 15 unmodified lines | ||
| 776 | 802 | |
| 777 | 803 | atomic_inc(&dev_priv->gpu_error.pending_fb_pin); |
| 778 | 804 | |
| 779 | − vma = i915_gem_object_pin_to_display_plane(new_bo, | |
| 780 | − 0, NULL, PIN_MAPPABLE); | |
| 781 | − if (IS_ERR(vma)) { | |
| 782 | − ret = PTR_ERR(vma); | |
| 805 | + vma = intel_overlay_pin_fb(new_bo); | |
| 806 | + if (IS_ERR(vma)) | |
| 783 | 807 | goto out_pin_section; |
| 784 | − } | |
| 808 | + | |
| 785 | 809 | i915_gem_object_flush_frontbuffer(new_bo, ORIGIN_DIRTYFB); |
| 786 | 810 | |
| 787 | 811 | if (!overlay->active) { |
| @@ -27,15 +27,8 @@ static void __do_clflush(struct drm_i915_gem_object *obj) · 26 unmodified lines | ||
| 27 | 27 | static int clflush_work(struct dma_fence_work *base) |
| 28 | 28 | { |
| 29 | 29 | struct clflush *clflush = container_of(base, typeof(*clflush), base); |
| 30 | − struct drm_i915_gem_object *obj = clflush->obj; | |
| 31 | − int err; | |
| 32 | 30 | |
| 33 | − err = i915_gem_object_pin_pages(obj); | |
| 34 | − if (err) | |
| 35 | − return err; | |
| 36 | − | |
| 37 | − __do_clflush(obj); | |
| 38 | − i915_gem_object_unpin_pages(obj); | |
| 31 | + __do_clflush(clflush->obj); | |
| 39 | 32 | |
| 40 | 33 | return 0; |
| 41 | 34 | } |
| @@ -44,6 +37,7 @@ static void clflush_release(struct dma_fence_work *base) · 2 unmodified lines | ||
| 44 | 37 | { |
| 45 | 38 | struct clflush *clflush = container_of(base, typeof(*clflush), base); |
| 46 | 39 | |
| 40 | + i915_gem_object_unpin_pages(clflush->obj); | |
| 47 | 41 | i915_gem_object_put(clflush->obj); |
| 48 | 42 | } |
| 49 | 43 | |
| @@ -63,6 +57,11 @@ static struct clflush *clflush_work_create(struct drm_i915_gem_object *obj) · 13 unmodified lines | ||
| 63 | 57 | if (!clflush) |
| 64 | 58 | return NULL; |
| 65 | 59 | |
| 60 | + if (__i915_gem_object_get_pages(obj) < 0) { | |
| 61 | + kfree(clflush); | |
| 62 | + return NULL; | |
| 63 | + } | |
| 64 | + | |
| 66 | 65 | dma_fence_work_init(&clflush->base, &clflush_ops); |
| 67 | 66 | clflush->obj = i915_gem_object_get(obj); /* obj <-> clflush cycle */ |
| 68 | 67 | |
| @@ -232,6 +232,8 @@ static void intel_context_set_gem(struct intel_context *ce, · 231 unmodified lines | ||
| 232 | 232 | if (ctx->sched.priority >= I915_PRIORITY_NORMAL && |
| 233 | 233 | intel_engine_has_timeslices(ce->engine)) |
| 234 | 234 | __set_bit(CONTEXT_USE_SEMAPHORES, &ce->flags); |
| 235 | + | |
| 236 | + intel_context_set_watchdog_us(ce, ctx->watchdog.timeout_us); | |
| 235 | 237 | } |
| 236 | 238 | |
| 237 | 239 | static void __free_engines(struct i915_gem_engines *e, unsigned int count) |
| @@ -386,38 +388,6 @@ static bool __cancel_engine(struct intel_engine_cs *engine) · 148 unmodified lines | ||
| 386 | 388 | return intel_engine_pulse(engine) == 0; |
| 387 | 389 | } |
| 388 | 390 | |
| 389 | −static bool | |
| 390 | −__active_engine(struct i915_request *rq, struct intel_engine_cs **active) | |
| 391 | −{ | |
| 392 | − struct intel_engine_cs *engine, *locked; | |
| 393 | − bool ret = false; | |
| 394 | − | |
| 395 | − /* | |
| 396 | − * Serialise with __i915_request_submit() so that it sees | |
| 397 | − * is-banned?, or we know the request is already inflight. | |
| 398 | − * | |
| 399 | − * Note that rq->engine is unstable, and so we double | |
| 400 | − * check that we have acquired the lock on the final engine. | |
| 401 | − */ | |
| 402 | − locked = READ_ONCE(rq->engine); | |
| 403 | − spin_lock_irq(&locked->active.lock); | |
| 404 | − while (unlikely(locked != (engine = READ_ONCE(rq->engine)))) { | |
| 405 | − spin_unlock(&locked->active.lock); | |
| 406 | − locked = engine; | |
| 407 | − spin_lock(&locked->active.lock); | |
| 408 | − } | |
| 409 | − | |
| 410 | − if (i915_request_is_active(rq)) { | |
| 411 | − if (!__i915_request_is_complete(rq)) | |
| 412 | − *active = locked; | |
| 413 | − ret = true; | |
| 414 | − } | |
| 415 | − | |
| 416 | − spin_unlock_irq(&locked->active.lock); | |
| 417 | − | |
| 418 | − return ret; | |
| 419 | −} | |
| 420 | − | |
| 421 | 391 | static struct intel_engine_cs *active_engine(struct intel_context *ce) |
| 422 | 392 | { |
| 423 | 393 | struct intel_engine_cs *engine = NULL; |
| @@ -445,7 +415,7 @@ static struct intel_engine_cs *active_engine(struct intel_context *ce) · 21 unmodified lines | ||
| 445 | 415 | /* Check with the backend if the request is inflight */ |
| 446 | 416 | found = true; |
| 447 | 417 | if (likely(rcu_access_pointer(rq->timeline) == ce->timeline)) |
| 448 | − found = __active_engine(rq, &engine); | |
| 418 | + found = i915_request_active_engine(rq, &engine); | |
| 449 | 419 | |
| 450 | 420 | i915_request_put(rq); |
| 451 | 421 | if (found) |
| @@ -822,6 +792,41 @@ static void __assign_timeline(struct i915_gem_context *ctx, · 370 unmodified lines | ||
| 822 | 792 | context_apply_all(ctx, __apply_timeline, timeline); |
| 823 | 793 | } |
| 824 | 794 | |
| 795 | +static int __apply_watchdog(struct intel_context *ce, void *timeout_us) | |
| 796 | +{ | |
| 797 | + return intel_context_set_watchdog_us(ce, (uintptr_t)timeout_us); | |
| 798 | +} | |
| 799 | + | |
| 800 | +static int | |
| 801 | +__set_watchdog(struct i915_gem_context *ctx, unsigned long timeout_us) | |
| 802 | +{ | |
| 803 | + int ret; | |
| 804 | + | |
| 805 | + ret = context_apply_all(ctx, __apply_watchdog, | |
| 806 | + (void *)(uintptr_t)timeout_us); | |
| 807 | + if (!ret) | |
| 808 | + ctx->watchdog.timeout_us = timeout_us; | |
| 809 | + | |
| 810 | + return ret; | |
| 811 | +} | |
| 812 | + | |
| 813 | +static void __set_default_fence_expiry(struct i915_gem_context *ctx) | |
| 814 | +{ | |
| 815 | + struct drm_i915_private *i915 = ctx->i915; | |
| 816 | + int ret; | |
| 817 | + | |
| 818 | + if (!IS_ACTIVE(CONFIG_DRM_I915_REQUEST_TIMEOUT) || | |
| 819 | + !i915->params.request_timeout_ms) | |
| 820 | + return; | |
| 821 | + | |
| 822 | + /* Default expiry for user fences. */ | |
| 823 | + ret = __set_watchdog(ctx, i915->params.request_timeout_ms * 1000); | |
| 824 | + if (ret) | |
| 825 | + drm_notice(&i915->drm, | |
| 826 | + "Failed to configure default fence expiry! (%d)", | |
| 827 | + ret); | |
| 828 | +} | |
| 829 | + | |
| 825 | 830 | static struct i915_gem_context * |
| 826 | 831 | i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags) |
| 827 | 832 | { |
| @@ -866,6 +871,8 @@ i915_gem_create_context(struct drm_i915_private *i915, unsigned int flags) · 38 unmodified lines | ||
| 866 | 871 | intel_timeline_put(timeline); |
| 867 | 872 | } |
| 868 | 873 | |
| 874 | + __set_default_fence_expiry(ctx); | |
| 875 | + | |
| 869 | 876 | trace_i915_context_create(ctx); |
| 870 | 877 | |
| 871 | 878 | return ctx; |
| @@ -154,6 +154,10 @@ struct i915_gem_context { · 153 unmodified lines | ||
| 154 | 154 | */ |
| 155 | 155 | atomic_t active_count; |
| 156 | 156 | |
| 157 | + struct { | |
| 158 | + u64 timeout_us; | |
| 159 | + } watchdog; | |
| 160 | + | |
| 157 | 161 | /** |
| 158 | 162 | * @hang_timestamp: The last time(s) this context caused a GPU hang |
| 159 | 163 | */ |
| @@ -25,7 +25,7 @@ static struct sg_table *i915_gem_map_dma_buf(struct dma_buf_attachment *attachme · 24 unmodified lines | ||
| 25 | 25 | struct scatterlist *src, *dst; |
| 26 | 26 | int ret, i; |
| 27 | 27 | |
| 28 | − ret = i915_gem_object_pin_pages(obj); | |
| 28 | + ret = i915_gem_object_pin_pages_unlocked(obj); | |
| 29 | 29 | if (ret) |
| 30 | 30 | goto err; |
| 31 | 31 | |
| @@ -82,7 +82,7 @@ static int i915_gem_dmabuf_vmap(struct dma_buf *dma_buf, struct dma_buf_map *map · 50 unmodified lines | ||
| 82 | 82 | struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); |
| 83 | 83 | void *vaddr; |
| 84 | 84 | |
| 85 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 85 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 86 | 86 | if (IS_ERR(vaddr)) |
| 87 | 87 | return PTR_ERR(vaddr); |
| 88 | 88 | |
| @@ -123,42 +123,48 @@ static int i915_gem_begin_cpu_access(struct dma_buf *dma_buf, enum dma_data_dire · 34 unmodified lines | ||
| 123 | 123 | { |
| 124 | 124 | struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); |
| 125 | 125 | bool write = (direction == DMA_BIDIRECTIONAL || direction == DMA_TO_DEVICE); |
| 126 | + struct i915_gem_ww_ctx ww; | |
| 126 | 127 | int err; |
| 127 | 128 | |
| 128 | − err = i915_gem_object_pin_pages(obj); | |
| 129 | − if (err) | |
| 130 | − return err; | |
| 131 | − | |
| 132 | − err = i915_gem_object_lock_interruptible(obj, NULL); | |
| 133 | − if (err) | |
| 134 | − goto out; | |
| 135 | − | |
| 136 | − err = i915_gem_object_set_to_cpu_domain(obj, write); | |
| 137 | − i915_gem_object_unlock(obj); | |
| 138 | − | |
| 139 | −out: | |
| 140 | − i915_gem_object_unpin_pages(obj); | |
| 129 | + i915_gem_ww_ctx_init(&ww, true); | |
| 130 | +retry: | |
| 131 | + err = i915_gem_object_lock(obj, &ww); | |
| 132 | + if (!err) | |
| 133 | + err = i915_gem_object_pin_pages(obj); | |
| 134 | + if (!err) { | |
| 135 | + err = i915_gem_object_set_to_cpu_domain(obj, write); | |
| 136 | + i915_gem_object_unpin_pages(obj); | |
| 137 | + } | |
| 138 | + if (err == -EDEADLK) { | |
| 139 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 140 | + if (!err) | |
| 141 | + goto retry; | |
| 142 | + } | |
| 143 | + i915_gem_ww_ctx_fini(&ww); | |
| 141 | 144 | return err; |
| 142 | 145 | } |
| 143 | 146 | |
| 144 | 147 | static int i915_gem_end_cpu_access(struct dma_buf *dma_buf, enum dma_data_direction direction) |
| 145 | 148 | { |
| 146 | 149 | struct drm_i915_gem_object *obj = dma_buf_to_obj(dma_buf); |
| 150 | + struct i915_gem_ww_ctx ww; | |
| 147 | 151 | int err; |
| 148 | 152 | |
| 149 | − err = i915_gem_object_pin_pages(obj); | |
| 150 | − if (err) | |
| 151 | − return err; | |
| 152 | − | |
| 153 | − err = i915_gem_object_lock_interruptible(obj, NULL); | |
| 154 | − if (err) | |
| 155 | − goto out; | |
| 156 | − | |
| 157 | − err = i915_gem_object_set_to_gtt_domain(obj, false); | |
| 158 | − i915_gem_object_unlock(obj); | |
| 159 | − | |
| 160 | −out: | |
| 161 | − i915_gem_object_unpin_pages(obj); | |
| 153 | + i915_gem_ww_ctx_init(&ww, true); | |
| 154 | +retry: | |
| 155 | + err = i915_gem_object_lock(obj, &ww); | |
| 156 | + if (!err) | |
| 157 | + err = i915_gem_object_pin_pages(obj); | |
| 158 | + if (!err) { | |
| 159 | + err = i915_gem_object_set_to_gtt_domain(obj, false); | |
| 160 | + i915_gem_object_unpin_pages(obj); | |
| 161 | + } | |
| 162 | + if (err == -EDEADLK) { | |
| 163 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 164 | + if (!err) | |
| 165 | + goto retry; | |
| 166 | + } | |
| 167 | + i915_gem_ww_ctx_fini(&ww); | |
| 162 | 168 | return err; |
| 163 | 169 | } |
| 164 | 170 | |
| @@ -258,7 +264,7 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, · 93 unmodified lines | ||
| 258 | 264 | } |
| 259 | 265 | |
| 260 | 266 | drm_gem_private_object_init(dev, &obj->base, dma_buf->size); |
| 261 | − i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops, &lock_class); | |
| 267 | + i915_gem_object_init(obj, &i915_gem_object_dmabuf_ops, &lock_class, 0); | |
| 262 | 268 | obj->base.import_attach = attach; |
| 263 | 269 | obj->base.resv = dma_buf->resv; |
| 264 | 270 | |
| @@ -335,7 +335,14 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, · 334 unmodified lines | ||
| 335 | 335 | * not allowed to be changed by userspace. |
| 336 | 336 | */ |
| 337 | 337 | if (i915_gem_object_is_proxy(obj)) { |
| 338 | − ret = -ENXIO; | |
| 338 | + /* | |
| 339 | + * Silently allow cached for userptr; the vulkan driver | |
| 340 | + * sets all objects to cached | |
| 341 | + */ | |
| 342 | + if (!i915_gem_object_is_userptr(obj) || | |
| 343 | + args->caching != I915_CACHING_CACHED) | |
| 344 | + ret = -ENXIO; | |
| 345 | + | |
| 339 | 346 | goto out; |
| 340 | 347 | } |
| 341 | 348 | |
| @@ -359,12 +366,12 @@ out: · 17 unmodified lines | ||
| 359 | 366 | */ |
| 360 | 367 | struct i915_vma * |
| 361 | 368 | i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, |
| 369 | + struct i915_gem_ww_ctx *ww, | |
| 362 | 370 | u32 alignment, |
| 363 | 371 | const struct i915_ggtt_view *view, |
| 364 | 372 | unsigned int flags) |
| 365 | 373 | { |
| 366 | 374 | struct drm_i915_private *i915 = to_i915(obj->base.dev); |
| 367 | − struct i915_gem_ww_ctx ww; | |
| 368 | 375 | struct i915_vma *vma; |
| 369 | 376 | int ret; |
| 370 | 377 | |
| @@ -372,11 +379,6 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, · 1 unmodified line | ||
| 372 | 379 | if (HAS_LMEM(i915) && !i915_gem_object_is_lmem(obj)) |
| 373 | 380 | return ERR_PTR(-EINVAL); |
| 374 | 381 | |
| 375 | − i915_gem_ww_ctx_init(&ww, true); | |
| 376 | −retry: | |
| 377 | − ret = i915_gem_object_lock(obj, &ww); | |
| 378 | − if (ret) | |
| 379 | − goto err; | |
| 380 | 382 | /* |
| 381 | 383 | * The display engine is not coherent with the LLC cache on gen6. As |
| 382 | 384 | * a result, we make sure that the pinning that is about to occur is |
| @@ -391,7 +393,7 @@ retry: · 8 unmodified lines | ||
| 391 | 393 | HAS_WT(i915) ? |
| 392 | 394 | I915_CACHE_WT : I915_CACHE_NONE); |
| 393 | 395 | if (ret) |
| 394 | − goto err; | |
| 396 | + return ERR_PTR(ret); | |
| 395 | 397 | |
| 396 | 398 | /* |
| 397 | 399 | * As the user may map the buffer once pinned in the display plane |
| @@ -404,33 +406,20 @@ retry: · 6 unmodified lines | ||
| 404 | 406 | vma = ERR_PTR(-ENOSPC); |
| 405 | 407 | if ((flags & PIN_MAPPABLE) == 0 && |
| 406 | 408 | (!view || view->type == I915_GGTT_VIEW_NORMAL)) |
| 407 | − vma = i915_gem_object_ggtt_pin_ww(obj, &ww, view, 0, alignment, | |
| 409 | + vma = i915_gem_object_ggtt_pin_ww(obj, ww, view, 0, alignment, | |
| 408 | 410 | flags | PIN_MAPPABLE | |
| 409 | 411 | PIN_NONBLOCK); |
| 410 | 412 | if (IS_ERR(vma) && vma != ERR_PTR(-EDEADLK)) |
| 411 | − vma = i915_gem_object_ggtt_pin_ww(obj, &ww, view, 0, | |
| 413 | + vma = i915_gem_object_ggtt_pin_ww(obj, ww, view, 0, | |
| 412 | 414 | alignment, flags); |
| 413 | − if (IS_ERR(vma)) { | |
| 414 | − ret = PTR_ERR(vma); | |
| 415 | − goto err; | |
| 416 | − } | |
| 415 | + if (IS_ERR(vma)) | |
| 416 | + return vma; | |
| 417 | 417 | |
| 418 | 418 | vma->display_alignment = max_t(u64, vma->display_alignment, alignment); |
| 419 | 419 | i915_vma_mark_scanout(vma); |
| 420 | 420 | |
| 421 | 421 | i915_gem_object_flush_if_display_locked(obj); |
| 422 | 422 | |
| 423 | −err: | |
| 424 | − if (ret == -EDEADLK) { | |
| 425 | − ret = i915_gem_ww_ctx_backoff(&ww); | |
| 426 | − if (!ret) | |
| 427 | − goto retry; | |
| 428 | − } | |
| 429 | − i915_gem_ww_ctx_fini(&ww); | |
| 430 | − | |
| 431 | − if (ret) | |
| 432 | − return ERR_PTR(ret); | |
| 433 | − | |
| 434 | 423 | return vma; |
| 435 | 424 | } |
| 436 | 425 | |
| @@ -526,6 +515,21 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, · 89 unmodified lines | ||
| 526 | 515 | if (err) |
| 527 | 516 | goto out; |
| 528 | 517 | |
| 518 | + if (i915_gem_object_is_userptr(obj)) { | |
| 519 | + /* | |
| 520 | + * Try to grab userptr pages, iris uses set_domain to check | |
| 521 | + * userptr validity | |
| 522 | + */ | |
| 523 | + err = i915_gem_object_userptr_validate(obj); | |
| 524 | + if (!err) | |
| 525 | + err = i915_gem_object_wait(obj, | |
| 526 | + I915_WAIT_INTERRUPTIBLE | | |
| 527 | + I915_WAIT_PRIORITY | | |
| 528 | + (write_domain ? I915_WAIT_ALL : 0), | |
| 529 | + MAX_SCHEDULE_TIMEOUT); | |
| 530 | + goto out; | |
| 531 | + } | |
| 532 | + | |
| 529 | 533 | /* |
| 530 | 534 | * Proxy objects do not control access to the backing storage, ergo |
| 531 | 535 | * they cannot be used as a means to manipulate the cache domain |
| @@ -537,6 +541,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, · 5 unmodified lines | ||
| 537 | 541 | goto out; |
| 538 | 542 | } |
| 539 | 543 | |
| 544 | + err = i915_gem_object_lock_interruptible(obj, NULL); | |
| 545 | + if (err) | |
| 546 | + goto out; | |
| 547 | + | |
| 540 | 548 | /* |
| 541 | 549 | * Flush and acquire obj->pages so that we are coherent through |
| 542 | 550 | * direct access in memory with previous cached writes through |
| @@ -548,7 +556,7 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, · 5 unmodified lines | ||
| 548 | 556 | */ |
| 549 | 557 | err = i915_gem_object_pin_pages(obj); |
| 550 | 558 | if (err) |
| 551 | − goto out; | |
| 559 | + goto out_unlock; | |
| 552 | 560 | |
| 553 | 561 | /* |
| 554 | 562 | * Already in the desired write domain? Nothing for us to do! |
| @@ -563,10 +571,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, · 8 unmodified lines | ||
| 563 | 571 | if (READ_ONCE(obj->write_domain) == read_domains) |
| 564 | 572 | goto out_unpin; |
| 565 | 573 | |
| 566 | − err = i915_gem_object_lock_interruptible(obj, NULL); | |
| 567 | − if (err) | |
| 568 | − goto out_unpin; | |
| 569 | − | |
| 570 | 574 | if (read_domains & I915_GEM_DOMAIN_WC) |
| 571 | 575 | err = i915_gem_object_set_to_wc_domain(obj, write_domain); |
| 572 | 576 | else if (read_domains & I915_GEM_DOMAIN_GTT) |
| @@ -574,13 +578,15 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, · 1 unmodified line | ||
| 574 | 578 | else |
| 575 | 579 | err = i915_gem_object_set_to_cpu_domain(obj, write_domain); |
| 576 | 580 | |
| 581 | +out_unpin: | |
| 582 | + i915_gem_object_unpin_pages(obj); | |
| 583 | + | |
| 584 | +out_unlock: | |
| 577 | 585 | i915_gem_object_unlock(obj); |
| 578 | 586 | |
| 579 | − if (write_domain) | |
| 587 | + if (!err && write_domain) | |
| 580 | 588 | i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU); |
| 581 | 589 | |
| 582 | −out_unpin: | |
| 583 | − i915_gem_object_unpin_pages(obj); | |
| 584 | 590 | out: |
| 585 | 591 | i915_gem_object_put(obj); |
| 586 | 592 | return err; |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #include "i915_sw_fence_work.h" |
| 29 | 29 | #include "i915_trace.h" |
| 30 | 30 | #include "i915_user_extensions.h" |
| 31 | +#include "i915_memcpy.h" | |
| 31 | 32 | |
| 32 | 33 | struct eb_vma { |
| 33 | 34 | struct i915_vma *vma; |
| @@ -49,16 +50,19 @@ enum { · 15 unmodified lines | ||
| 49 | 50 | #define DBG_FORCE_RELOC 0 /* choose one of the above! */ |
| 50 | 51 | }; |
| 51 | 52 | |
| 52 | −#define __EXEC_OBJECT_HAS_PIN BIT(31) | |
| 53 | −#define __EXEC_OBJECT_HAS_FENCE BIT(30) | |
| 54 | −#define __EXEC_OBJECT_NEEDS_MAP BIT(29) | |
| 55 | −#define __EXEC_OBJECT_NEEDS_BIAS BIT(28) | |
| 56 | −#define __EXEC_OBJECT_INTERNAL_FLAGS (~0u << 28) /* all of the above */ | |
| 53 | +/* __EXEC_OBJECT_NO_RESERVE is BIT(31), defined in i915_vma.h */ | |
| 54 | +#define __EXEC_OBJECT_HAS_PIN BIT(30) | |
| 55 | +#define __EXEC_OBJECT_HAS_FENCE BIT(29) | |
| 56 | +#define __EXEC_OBJECT_USERPTR_INIT BIT(28) | |
| 57 | +#define __EXEC_OBJECT_NEEDS_MAP BIT(27) | |
| 58 | +#define __EXEC_OBJECT_NEEDS_BIAS BIT(26) | |
| 59 | +#define __EXEC_OBJECT_INTERNAL_FLAGS (~0u << 26) /* all of the above + */ | |
| 57 | 60 | #define __EXEC_OBJECT_RESERVED (__EXEC_OBJECT_HAS_PIN | __EXEC_OBJECT_HAS_FENCE) |
| 58 | 61 | |
| 59 | 62 | #define __EXEC_HAS_RELOC BIT(31) |
| 60 | 63 | #define __EXEC_ENGINE_PINNED BIT(30) |
| 61 | −#define __EXEC_INTERNAL_FLAGS (~0u << 30) | |
| 64 | +#define __EXEC_USERPTR_USED BIT(29) | |
| 65 | +#define __EXEC_INTERNAL_FLAGS (~0u << 29) | |
| 62 | 66 | #define UPDATE PIN_OFFSET_FIXED |
| 63 | 67 | |
| 64 | 68 | #define BATCH_OFFSET_BIAS (256*1024) |
| @@ -419,13 +423,14 @@ static u64 eb_pin_flags(const struct drm_i915_gem_exec_object2 *entry, · 354 unmodified lines | ||
| 419 | 423 | return pin_flags; |
| 420 | 424 | } |
| 421 | 425 | |
| 422 | −static inline bool | |
| 426 | +static inline int | |
| 423 | 427 | eb_pin_vma(struct i915_execbuffer *eb, |
| 424 | 428 | const struct drm_i915_gem_exec_object2 *entry, |
| 425 | 429 | struct eb_vma *ev) |
| 426 | 430 | { |
| 427 | 431 | struct i915_vma *vma = ev->vma; |
| 428 | 432 | u64 pin_flags; |
| 433 | + int err; | |
| 429 | 434 | |
| 430 | 435 | if (vma->node.size) |
| 431 | 436 | pin_flags = vma->node.start; |
| @@ -437,24 +442,29 @@ eb_pin_vma(struct i915_execbuffer *eb, · 5 unmodified lines | ||
| 437 | 442 | pin_flags |= PIN_GLOBAL; |
| 438 | 443 | |
| 439 | 444 | /* Attempt to reuse the current location if available */ |
| 440 | − /* TODO: Add -EDEADLK handling here */ | |
| 441 | − if (unlikely(i915_vma_pin_ww(vma, &eb->ww, 0, 0, pin_flags))) { | |
| 445 | + err = i915_vma_pin_ww(vma, &eb->ww, 0, 0, pin_flags); | |
| 446 | + if (err == -EDEADLK) | |
| 447 | + return err; | |
| 448 | + | |
| 449 | + if (unlikely(err)) { | |
| 442 | 450 | if (entry->flags & EXEC_OBJECT_PINNED) |
| 443 | − return false; | |
| 451 | + return err; | |
| 444 | 452 | |
| 445 | 453 | /* Failing that pick any _free_ space if suitable */ |
| 446 | − if (unlikely(i915_vma_pin_ww(vma, &eb->ww, | |
| 454 | + err = i915_vma_pin_ww(vma, &eb->ww, | |
| 447 | 455 | entry->pad_to_size, |
| 448 | 456 | entry->alignment, |
| 449 | 457 | eb_pin_flags(entry, ev->flags) | |
| 450 | − PIN_USER | PIN_NOEVICT))) | |
| 451 | − return false; | |
| 458 | + PIN_USER | PIN_NOEVICT); | |
| 459 | + if (unlikely(err)) | |
| 460 | + return err; | |
| 452 | 461 | } |
| 453 | 462 | |
| 454 | 463 | if (unlikely(ev->flags & EXEC_OBJECT_NEEDS_FENCE)) { |
| 455 | − if (unlikely(i915_vma_pin_fence(vma))) { | |
| 464 | + err = i915_vma_pin_fence(vma); | |
| 465 | + if (unlikely(err)) { | |
| 456 | 466 | i915_vma_unpin(vma); |
| 457 | − return false; | |
| 467 | + return err; | |
| 458 | 468 | } |
| 459 | 469 | |
| 460 | 470 | if (vma->fence) |
| @@ -462,7 +472,10 @@ eb_pin_vma(struct i915_execbuffer *eb, · 1 unmodified line | ||
| 462 | 472 | } |
| 463 | 473 | |
| 464 | 474 | ev->flags |= __EXEC_OBJECT_HAS_PIN; |
| 465 | − return !eb_vma_misplaced(entry, vma, ev->flags); | |
| 475 | + if (eb_vma_misplaced(entry, vma, ev->flags)) | |
| 476 | + return -EBADSLT; | |
| 477 | + | |
| 478 | + return 0; | |
| 466 | 479 | } |
| 467 | 480 | |
| 468 | 481 | static inline void |
| @@ -483,6 +496,13 @@ eb_validate_vma(struct i915_execbuffer *eb, · 14 unmodified lines | ||
| 483 | 496 | struct drm_i915_gem_exec_object2 *entry, |
| 484 | 497 | struct i915_vma *vma) |
| 485 | 498 | { |
| 499 | + /* Relocations are disallowed for all platforms after TGL-LP. This | |
| 500 | + * also covers all platforms with local memory. | |
| 501 | + */ | |
| 502 | + if (entry->relocation_count && | |
| 503 | + INTEL_GEN(eb->i915) >= 12 && !IS_TIGERLAKE(eb->i915)) | |
| 504 | + return -EINVAL; | |
| 505 | + | |
| 486 | 506 | if (unlikely(entry->flags & eb->invalid_flags)) |
| 487 | 507 | return -EINVAL; |
| 488 | 508 | |
| @@ -853,6 +873,26 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) · 364 unmodified lines | ||
| 853 | 873 | } |
| 854 | 874 | |
| 855 | 875 | eb_add_vma(eb, i, batch, vma); |
| 876 | + | |
| 877 | + if (i915_gem_object_is_userptr(vma->obj)) { | |
| 878 | + err = i915_gem_object_userptr_submit_init(vma->obj); | |
| 879 | + if (err) { | |
| 880 | + if (i + 1 < eb->buffer_count) { | |
| 881 | + /* | |
| 882 | + * Execbuffer code expects last vma entry to be NULL, | |
| 883 | + * since we already initialized this entry, | |
| 884 | + * set the next value to NULL or we mess up | |
| 885 | + * cleanup handling. | |
| 886 | + */ | |
| 887 | + eb->vma[i + 1].vma = NULL; | |
| 888 | + } | |
| 889 | + | |
| 890 | + return err; | |
| 891 | + } | |
| 892 | + | |
| 893 | + eb->vma[i].flags |= __EXEC_OBJECT_USERPTR_INIT; | |
| 894 | + eb->args->flags |= __EXEC_USERPTR_USED; | |
| 895 | + } | |
| 856 | 896 | } |
| 857 | 897 | |
| 858 | 898 | if (unlikely(eb->batch->flags & EXEC_OBJECT_WRITE)) { |
| @@ -898,7 +938,11 @@ static int eb_validate_vmas(struct i915_execbuffer *eb) · 39 unmodified lines | ||
| 898 | 938 | if (err) |
| 899 | 939 | return err; |
| 900 | 940 | |
| 901 | − if (eb_pin_vma(eb, entry, ev)) { | |
| 941 | + err = eb_pin_vma(eb, entry, ev); | |
| 942 | + if (err == -EDEADLK) | |
| 943 | + return err; | |
| 944 | + | |
| 945 | + if (!err) { | |
| 902 | 946 | if (entry->offset != vma->node.start) { |
| 903 | 947 | entry->offset = vma->node.start | UPDATE; |
| 904 | 948 | eb->args->flags |= __EXEC_HAS_RELOC; |
| @@ -914,6 +958,12 @@ static int eb_validate_vmas(struct i915_execbuffer *eb) · 9 unmodified lines | ||
| 914 | 958 | } |
| 915 | 959 | } |
| 916 | 960 | |
| 961 | + if (!(ev->flags & EXEC_OBJECT_WRITE)) { | |
| 962 | + err = dma_resv_reserve_shared(vma->resv, 1); | |
| 963 | + if (err) | |
| 964 | + return err; | |
| 965 | + } | |
| 966 | + | |
| 917 | 967 | GEM_BUG_ON(drm_mm_node_allocated(&vma->node) && |
| 918 | 968 | eb_vma_misplaced(&eb->exec[i], vma, ev->flags)); |
| 919 | 969 | } |
| @@ -944,7 +994,7 @@ eb_get_vma(const struct i915_execbuffer *eb, unsigned long handle) · 24 unmodified lines | ||
| 944 | 994 | } |
| 945 | 995 | } |
| 946 | 996 | |
| 947 | −static void eb_release_vmas(struct i915_execbuffer *eb, bool final) | |
| 997 | +static void eb_release_vmas(struct i915_execbuffer *eb, bool final, bool release_userptr) | |
| 948 | 998 | { |
| 949 | 999 | const unsigned int count = eb->buffer_count; |
| 950 | 1000 | unsigned int i; |
| @@ -958,6 +1008,11 @@ static void eb_release_vmas(struct i915_execbuffer *eb, bool final) · 7 unmodified lines | ||
| 958 | 1008 | |
| 959 | 1009 | eb_unreserve_vma(ev); |
| 960 | 1010 | |
| 1011 | + if (release_userptr && ev->flags & __EXEC_OBJECT_USERPTR_INIT) { | |
| 1012 | + ev->flags &= ~__EXEC_OBJECT_USERPTR_INIT; | |
| 1013 | + i915_gem_object_userptr_submit_fini(vma->obj); | |
| 1014 | + } | |
| 1015 | + | |
| 961 | 1016 | if (final) |
| 962 | 1017 | i915_vma_put(vma); |
| 963 | 1018 | } |
| @@ -1294,6 +1349,7 @@ static int __reloc_gpu_alloc(struct i915_execbuffer *eb, · 330 unmodified lines | ||
| 1294 | 1349 | err = PTR_ERR(cmd); |
| 1295 | 1350 | goto err_pool; |
| 1296 | 1351 | } |
| 1352 | + intel_gt_buffer_pool_mark_used(pool); | |
| 1297 | 1353 | |
| 1298 | 1354 | memset32(cmd, 0, pool->obj->base.size / sizeof(u32)); |
| 1299 | 1355 | |
| @@ -1895,6 +1951,31 @@ static int eb_prefault_relocations(const struct i915_execbuffer *eb) · 595 unmodified lines | ||
| 1895 | 1951 | return 0; |
| 1896 | 1952 | } |
| 1897 | 1953 | |
| 1954 | +static int eb_reinit_userptr(struct i915_execbuffer *eb) | |
| 1955 | +{ | |
| 1956 | + const unsigned int count = eb->buffer_count; | |
| 1957 | + unsigned int i; | |
| 1958 | + int ret; | |
| 1959 | + | |
| 1960 | + if (likely(!(eb->args->flags & __EXEC_USERPTR_USED))) | |
| 1961 | + return 0; | |
| 1962 | + | |
| 1963 | + for (i = 0; i < count; i++) { | |
| 1964 | + struct eb_vma *ev = &eb->vma[i]; | |
| 1965 | + | |
| 1966 | + if (!i915_gem_object_is_userptr(ev->vma->obj)) | |
| 1967 | + continue; | |
| 1968 | + | |
| 1969 | + ret = i915_gem_object_userptr_submit_init(ev->vma->obj); | |
| 1970 | + if (ret) | |
| 1971 | + return ret; | |
| 1972 | + | |
| 1973 | + ev->flags |= __EXEC_OBJECT_USERPTR_INIT; | |
| 1974 | + } | |
| 1975 | + | |
| 1976 | + return 0; | |
| 1977 | +} | |
| 1978 | + | |
| 1898 | 1979 | static noinline int eb_relocate_parse_slow(struct i915_execbuffer *eb, |
| 1899 | 1980 | struct i915_request *rq) |
| 1900 | 1981 | { |
| @@ -1909,7 +1990,7 @@ repeat: · 8 unmodified lines | ||
| 1909 | 1990 | } |
| 1910 | 1991 | |
| 1911 | 1992 | /* We may process another execbuffer during the unlock... */ |
| 1912 | − eb_release_vmas(eb, false); | |
| 1993 | + eb_release_vmas(eb, false, true); | |
| 1913 | 1994 | i915_gem_ww_ctx_fini(&eb->ww); |
| 1914 | 1995 | |
| 1915 | 1996 | if (rq) { |
| @@ -1951,7 +2032,7 @@ repeat: · 35 unmodified lines | ||
| 1951 | 2032 | } |
| 1952 | 2033 | |
| 1953 | 2034 | if (!err) |
| 1954 | − flush_workqueue(eb->i915->mm.userptr_wq); | |
| 2035 | + err = eb_reinit_userptr(eb); | |
| 1955 | 2036 | |
| 1956 | 2037 | err_relock: |
| 1957 | 2038 | i915_gem_ww_ctx_init(&eb->ww, true); |
| @@ -2013,7 +2094,7 @@ repeat_validate: · 55 unmodified lines | ||
| 2013 | 2094 | |
| 2014 | 2095 | err: |
| 2015 | 2096 | if (err == -EDEADLK) { |
| 2016 | − eb_release_vmas(eb, false); | |
| 2097 | + eb_release_vmas(eb, false, false); | |
| 2017 | 2098 | err = i915_gem_ww_ctx_backoff(&eb->ww); |
| 2018 | 2099 | if (!err) |
| 2019 | 2100 | goto repeat_validate; |
| @@ -2110,7 +2191,7 @@ retry: · 90 unmodified lines | ||
| 2110 | 2191 | |
| 2111 | 2192 | err: |
| 2112 | 2193 | if (err == -EDEADLK) { |
| 2113 | − eb_release_vmas(eb, false); | |
| 2194 | + eb_release_vmas(eb, false, false); | |
| 2114 | 2195 | err = i915_gem_ww_ctx_backoff(&eb->ww); |
| 2115 | 2196 | if (!err) |
| 2116 | 2197 | goto retry; |
| @@ -2181,8 +2262,33 @@ static int eb_move_to_gpu(struct i915_execbuffer *eb) · 64 unmodified lines | ||
| 2181 | 2262 | } |
| 2182 | 2263 | |
| 2183 | 2264 | if (err == 0) |
| 2184 | − err = i915_vma_move_to_active(vma, eb->request, flags); | |
| 2265 | + err = i915_vma_move_to_active(vma, eb->request, | |
| 2266 | + flags | __EXEC_OBJECT_NO_RESERVE); | |
| 2267 | + } | |
| 2268 | + | |
| 2269 | +#ifdef CONFIG_MMU_NOTIFIER | |
| 2270 | + if (!err && (eb->args->flags & __EXEC_USERPTR_USED)) { | |
| 2271 | + spin_lock(&eb->i915->mm.notifier_lock); | |
| 2272 | + | |
| 2273 | + /* | |
| 2274 | + * count is always at least 1, otherwise __EXEC_USERPTR_USED | |
| 2275 | + * could not have been set | |
| 2276 | + */ | |
| 2277 | + for (i = 0; i < count; i++) { | |
| 2278 | + struct eb_vma *ev = &eb->vma[i]; | |
| 2279 | + struct drm_i915_gem_object *obj = ev->vma->obj; | |
| 2280 | + | |
| 2281 | + if (!i915_gem_object_is_userptr(obj)) | |
| 2282 | + continue; | |
| 2283 | + | |
| 2284 | + err = i915_gem_object_userptr_submit_done(obj); | |
| 2285 | + if (err) | |
| 2286 | + break; | |
| 2287 | + } | |
| 2288 | + | |
| 2289 | + spin_unlock(&eb->i915->mm.notifier_lock); | |
| 2185 | 2290 | } |
| 2291 | +#endif | |
| 2186 | 2292 | |
| 2187 | 2293 | if (unlikely(err)) |
| 2188 | 2294 | goto err_skip; |
| @@ -2274,24 +2380,45 @@ struct eb_parse_work { · 85 unmodified lines | ||
| 2274 | 2380 | struct i915_vma *trampoline; |
| 2275 | 2381 | unsigned long batch_offset; |
| 2276 | 2382 | unsigned long batch_length; |
| 2383 | + unsigned long *jump_whitelist; | |
| 2384 | + const void *batch_map; | |
| 2385 | + void *shadow_map; | |
| 2277 | 2386 | }; |
| 2278 | 2387 | |
| 2279 | 2388 | static int __eb_parse(struct dma_fence_work *work) |
| 2280 | 2389 | { |
| 2281 | 2390 | struct eb_parse_work *pw = container_of(work, typeof(*pw), base); |
| 2391 | + int ret; | |
| 2392 | + bool cookie; | |
| 2282 | 2393 | |
| 2283 | − return intel_engine_cmd_parser(pw->engine, | |
| 2284 | − pw->batch, | |
| 2285 | − pw->batch_offset, | |
| 2286 | − pw->batch_length, | |
| 2287 | − pw->shadow, | |
| 2288 | − pw->trampoline); | |
| 2394 | + cookie = dma_fence_begin_signalling(); | |
| 2395 | + ret = intel_engine_cmd_parser(pw->engine, | |
| 2396 | + pw->batch, | |
| 2397 | + pw->batch_offset, | |
| 2398 | + pw->batch_length, | |
| 2399 | + pw->shadow, | |
| 2400 | + pw->jump_whitelist, | |
| 2401 | + pw->shadow_map, | |
| 2402 | + pw->batch_map); | |
| 2403 | + dma_fence_end_signalling(cookie); | |
| 2404 | + | |
| 2405 | + return ret; | |
| 2289 | 2406 | } |
| 2290 | 2407 | |
| 2291 | 2408 | static void __eb_parse_release(struct dma_fence_work *work) |
| 2292 | 2409 | { |
| 2293 | 2410 | struct eb_parse_work *pw = container_of(work, typeof(*pw), base); |
| 2294 | 2411 | |
| 2412 | + if (!IS_ERR_OR_NULL(pw->jump_whitelist)) | |
| 2413 | + kfree(pw->jump_whitelist); | |
| 2414 | + | |
| 2415 | + if (pw->batch_map) | |
| 2416 | + i915_gem_object_unpin_map(pw->batch->obj); | |
| 2417 | + else | |
| 2418 | + i915_gem_object_unpin_pages(pw->batch->obj); | |
| 2419 | + | |
| 2420 | + i915_gem_object_unpin_map(pw->shadow->obj); | |
| 2421 | + | |
| 2295 | 2422 | if (pw->trampoline) |
| 2296 | 2423 | i915_active_release(&pw->trampoline->active); |
| 2297 | 2424 | i915_active_release(&pw->shadow->active); |
| @@ -2341,6 +2468,8 @@ static int eb_parse_pipeline(struct i915_execbuffer *eb, · 43 unmodified lines | ||
| 2341 | 2468 | struct i915_vma *trampoline) |
| 2342 | 2469 | { |
| 2343 | 2470 | struct eb_parse_work *pw; |
| 2471 | + struct drm_i915_gem_object *batch = eb->batch->vma->obj; | |
| 2472 | + bool needs_clflush; | |
| 2344 | 2473 | int err; |
| 2345 | 2474 | |
| 2346 | 2475 | GEM_BUG_ON(overflows_type(eb->batch_start_offset, pw->batch_offset)); |
| @@ -2364,6 +2493,34 @@ static int eb_parse_pipeline(struct i915_execbuffer *eb, · 17 unmodified lines | ||
| 2364 | 2493 | goto err_shadow; |
| 2365 | 2494 | } |
| 2366 | 2495 | |
| 2496 | + pw->shadow_map = i915_gem_object_pin_map(shadow->obj, I915_MAP_WB); | |
| 2497 | + if (IS_ERR(pw->shadow_map)) { | |
| 2498 | + err = PTR_ERR(pw->shadow_map); | |
| 2499 | + goto err_trampoline; | |
| 2500 | + } | |
| 2501 | + | |
| 2502 | + needs_clflush = | |
| 2503 | + !(batch->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ); | |
| 2504 | + | |
| 2505 | + pw->batch_map = ERR_PTR(-ENODEV); | |
| 2506 | + if (needs_clflush && i915_has_memcpy_from_wc()) | |
| 2507 | + pw->batch_map = i915_gem_object_pin_map(batch, I915_MAP_WC); | |
| 2508 | + | |
| 2509 | + if (IS_ERR(pw->batch_map)) { | |
| 2510 | + err = i915_gem_object_pin_pages(batch); | |
| 2511 | + if (err) | |
| 2512 | + goto err_unmap_shadow; | |
| 2513 | + pw->batch_map = NULL; | |
| 2514 | + } | |
| 2515 | + | |
| 2516 | + pw->jump_whitelist = | |
| 2517 | + intel_engine_cmd_parser_alloc_jump_whitelist(eb->batch_len, | |
| 2518 | + trampoline); | |
| 2519 | + if (IS_ERR(pw->jump_whitelist)) { | |
| 2520 | + err = PTR_ERR(pw->jump_whitelist); | |
| 2521 | + goto err_unmap_batch; | |
| 2522 | + } | |
| 2523 | + | |
| 2367 | 2524 | dma_fence_work_init(&pw->base, &eb_parse_ops); |
| 2368 | 2525 | |
| 2369 | 2526 | pw->engine = eb->engine; |
| @@ -2382,6 +2539,10 @@ static int eb_parse_pipeline(struct i915_execbuffer *eb, · 12 unmodified lines | ||
| 2382 | 2539 | if (err) |
| 2383 | 2540 | goto err_commit; |
| 2384 | 2541 | |
| 2542 | + err = dma_resv_reserve_shared(shadow->resv, 1); | |
| 2543 | + if (err) | |
| 2544 | + goto err_commit; | |
| 2545 | + | |
| 2385 | 2546 | /* Wait for all writes (and relocs) into the batch to complete */ |
| 2386 | 2547 | err = i915_sw_fence_await_reservation(&pw->base.chain, |
| 2387 | 2548 | pw->batch->resv, NULL, false, |
| @@ -2403,6 +2564,16 @@ err_commit: · 15 unmodified lines | ||
| 2403 | 2564 | dma_fence_work_commit_imm(&pw->base); |
| 2404 | 2565 | return err; |
| 2405 | 2566 | |
| 2567 | +err_unmap_batch: | |
| 2568 | + if (pw->batch_map) | |
| 2569 | + i915_gem_object_unpin_map(batch); | |
| 2570 | + else | |
| 2571 | + i915_gem_object_unpin_pages(batch); | |
| 2572 | +err_unmap_shadow: | |
| 2573 | + i915_gem_object_unpin_map(shadow->obj); | |
| 2574 | +err_trampoline: | |
| 2575 | + if (trampoline) | |
| 2576 | + i915_active_release(&trampoline->active); | |
| 2406 | 2577 | err_shadow: |
| 2407 | 2578 | i915_active_release(&shadow->active); |
| 2408 | 2579 | err_batch: |
| @@ -2474,6 +2645,7 @@ static int eb_parse(struct i915_execbuffer *eb) · 65 unmodified lines | ||
| 2474 | 2645 | err = PTR_ERR(shadow); |
| 2475 | 2646 | goto err; |
| 2476 | 2647 | } |
| 2648 | + intel_gt_buffer_pool_mark_used(pool); | |
| 2477 | 2649 | i915_gem_object_set_readonly(shadow->obj); |
| 2478 | 2650 | shadow->private = pool; |
| 2479 | 2651 | |
| @@ -3263,7 +3435,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, · 783 unmodified lines | ||
| 3263 | 3435 | |
| 3264 | 3436 | err = eb_lookup_vmas(&eb); |
| 3265 | 3437 | if (err) { |
| 3266 | − eb_release_vmas(&eb, true); | |
| 3438 | + eb_release_vmas(&eb, true, true); | |
| 3267 | 3439 | goto err_engine; |
| 3268 | 3440 | } |
| 3269 | 3441 | |
| @@ -3335,6 +3507,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, · 65 unmodified lines | ||
| 3335 | 3507 | |
| 3336 | 3508 | trace_i915_request_queue(eb.request, eb.batch_flags); |
| 3337 | 3509 | err = eb_submit(&eb, batch); |
| 3510 | + | |
| 3338 | 3511 | err_request: |
| 3339 | 3512 | i915_request_get(eb.request); |
| 3340 | 3513 | err = eb_request_add(&eb, err); |
| @@ -3355,7 +3528,7 @@ err_request: · 14 unmodified lines | ||
| 3355 | 3528 | i915_request_put(eb.request); |
| 3356 | 3529 | |
| 3357 | 3530 | err_vma: |
| 3358 | − eb_release_vmas(&eb, true); | |
| 3531 | + eb_release_vmas(&eb, true, true); | |
| 3359 | 3532 | if (eb.trampoline) |
| 3360 | 3533 | i915_vma_unpin(eb.trampoline); |
| 3361 | 3534 | WARN_ON(err == -EDEADLK); |
| @@ -3401,106 +3574,6 @@ static bool check_buffer_count(size_t count) · 39 unmodified lines | ||
| 3401 | 3574 | return !(count < 1 || count > INT_MAX || count > SIZE_MAX / sz - 1); |
| 3402 | 3575 | } |
| 3403 | 3576 | |
| 3404 | −/* | |
| 3405 | − * Legacy execbuffer just creates an exec2 list from the original exec object | |
| 3406 | − * list array and passes it to the real function. | |
| 3407 | − */ | |
| 3408 | −int | |
| 3409 | −i915_gem_execbuffer_ioctl(struct drm_device *dev, void *data, | |
| 3410 | − struct drm_file *file) | |
| 3411 | −{ | |
| 3412 | − struct drm_i915_private *i915 = to_i915(dev); | |
| 3413 | − struct drm_i915_gem_execbuffer *args = data; | |
| 3414 | − struct drm_i915_gem_execbuffer2 exec2; | |
| 3415 | − struct drm_i915_gem_exec_object *exec_list = NULL; | |
| 3416 | − struct drm_i915_gem_exec_object2 *exec2_list = NULL; | |
| 3417 | − const size_t count = args->buffer_count; | |
| 3418 | − unsigned int i; | |
| 3419 | − int err; | |
| 3420 | − | |
| 3421 | − if (!check_buffer_count(count)) { | |
| 3422 | − drm_dbg(&i915->drm, "execbuf2 with %zd buffers\n", count); | |
| 3423 | − return -EINVAL; | |
| 3424 | − } | |
| 3425 | − | |
| 3426 | − exec2.buffers_ptr = args->buffers_ptr; | |
| 3427 | − exec2.buffer_count = args->buffer_count; | |
| 3428 | − exec2.batch_start_offset = args->batch_start_offset; | |
| 3429 | − exec2.batch_len = args->batch_len; | |
| 3430 | − exec2.DR1 = args->DR1; | |
| 3431 | − exec2.DR4 = args->DR4; | |
| 3432 | − exec2.num_cliprects = args->num_cliprects; | |
| 3433 | − exec2.cliprects_ptr = args->cliprects_ptr; | |
| 3434 | − exec2.flags = I915_EXEC_RENDER; | |
| 3435 | − i915_execbuffer2_set_context_id(exec2, 0); | |
| 3436 | − | |
| 3437 | − err = i915_gem_check_execbuffer(&exec2); | |
| 3438 | − if (err) | |
| 3439 | − return err; | |
| 3440 | − | |
| 3441 | − /* Copy in the exec list from userland */ | |
| 3442 | − exec_list = kvmalloc_array(count, sizeof(*exec_list), | |
| 3443 | − __GFP_NOWARN | GFP_KERNEL); | |
| 3444 | − | |
| 3445 | − /* Allocate extra slots for use by the command parser */ | |
| 3446 | − exec2_list = kvmalloc_array(count + 2, eb_element_size(), | |
| 3447 | − __GFP_NOWARN | GFP_KERNEL); | |
| 3448 | − if (exec_list == NULL || exec2_list == NULL) { | |
| 3449 | − drm_dbg(&i915->drm, | |
| 3450 | − "Failed to allocate exec list for %d buffers\n", | |
| 3451 | − args->buffer_count); | |
| 3452 | − kvfree(exec_list); | |
| 3453 | − kvfree(exec2_list); | |
| 3454 | − return -ENOMEM; | |
| 3455 | − } | |
| 3456 | − err = copy_from_user(exec_list, | |
| 3457 | − u64_to_user_ptr(args->buffers_ptr), | |
| 3458 | − sizeof(*exec_list) * count); | |
| 3459 | − if (err) { | |
| 3460 | − drm_dbg(&i915->drm, "copy %d exec entries failed %d\n", | |
| 3461 | − args->buffer_count, err); | |
| 3462 | − kvfree(exec_list); | |
| 3463 | − kvfree(exec2_list); | |
| 3464 | − return -EFAULT; | |
| 3465 | − } | |
| 3466 | − | |
| 3467 | − for (i = 0; i < args->buffer_count; i++) { | |
| 3468 | − exec2_list[i].handle = exec_list[i].handle; | |
| 3469 | − exec2_list[i].relocation_count = exec_list[i].relocation_count; | |
| 3470 | − exec2_list[i].relocs_ptr = exec_list[i].relocs_ptr; | |
| 3471 | − exec2_list[i].alignment = exec_list[i].alignment; | |
| 3472 | − exec2_list[i].offset = exec_list[i].offset; | |
| 3473 | − if (INTEL_GEN(to_i915(dev)) < 4) | |
| 3474 | − exec2_list[i].flags = EXEC_OBJECT_NEEDS_FENCE; | |
| 3475 | − else | |
| 3476 | − exec2_list[i].flags = 0; | |
| 3477 | − } | |
| 3478 | − | |
| 3479 | − err = i915_gem_do_execbuffer(dev, file, &exec2, exec2_list); | |
| 3480 | − if (exec2.flags & __EXEC_HAS_RELOC) { | |
| 3481 | − struct drm_i915_gem_exec_object __user *user_exec_list = | |
| 3482 | − u64_to_user_ptr(args->buffers_ptr); | |
| 3483 | − | |
| 3484 | − /* Copy the new buffer offsets back to the user's exec list. */ | |
| 3485 | − for (i = 0; i < args->buffer_count; i++) { | |
| 3486 | − if (!(exec2_list[i].offset & UPDATE)) | |
| 3487 | − continue; | |
| 3488 | − | |
| 3489 | − exec2_list[i].offset = | |
| 3490 | − gen8_canonical_addr(exec2_list[i].offset & PIN_OFFSET_MASK); | |
| 3491 | − exec2_list[i].offset &= PIN_OFFSET_MASK; | |
| 3492 | − if (__copy_to_user(&user_exec_list[i].offset, | |
| 3493 | − &exec2_list[i].offset, | |
| 3494 | − sizeof(user_exec_list[i].offset))) | |
| 3495 | − break; | |
| 3496 | − } | |
| 3497 | − } | |
| 3498 | − | |
| 3499 | − kvfree(exec_list); | |
| 3500 | − kvfree(exec2_list); | |
| 3501 | − return err; | |
| 3502 | −} | |
| 3503 | − | |
| 3504 | 3577 | int |
| 3505 | 3578 | i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, |
| 3506 | 3579 | struct drm_file *file) |
| @@ -1,95 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * SPDX-License-Identifier: MIT | |
| 3 | − * | |
| 4 | − * Copyright © 2019 Intel Corporation | |
| 5 | − */ | |
| 6 | − | |
| 7 | −#include "i915_drv.h" | |
| 8 | −#include "i915_gem_object.h" | |
| 9 | − | |
| 10 | −struct stub_fence { | |
| 11 | − struct dma_fence dma; | |
| 12 | − struct i915_sw_fence chain; | |
| 13 | −}; | |
| 14 | − | |
| 15 | −static int __i915_sw_fence_call | |
| 16 | −stub_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) | |
| 17 | −{ | |
| 18 | − struct stub_fence *stub = container_of(fence, typeof(*stub), chain); | |
| 19 | − | |
| 20 | − switch (state) { | |
| 21 | − case FENCE_COMPLETE: | |
| 22 | − dma_fence_signal(&stub->dma); | |
| 23 | − break; | |
| 24 | − | |
| 25 | − case FENCE_FREE: | |
| 26 | − dma_fence_put(&stub->dma); | |
| 27 | − break; | |
| 28 | − } | |
| 29 | − | |
| 30 | − return NOTIFY_DONE; | |
| 31 | −} | |
| 32 | − | |
| 33 | −static const char *stub_driver_name(struct dma_fence *fence) | |
| 34 | −{ | |
| 35 | − return DRIVER_NAME; | |
| 36 | −} | |
| 37 | − | |
| 38 | −static const char *stub_timeline_name(struct dma_fence *fence) | |
| 39 | −{ | |
| 40 | − return "object"; | |
| 41 | −} | |
| 42 | − | |
| 43 | −static void stub_release(struct dma_fence *fence) | |
| 44 | −{ | |
| 45 | − struct stub_fence *stub = container_of(fence, typeof(*stub), dma); | |
| 46 | − | |
| 47 | − i915_sw_fence_fini(&stub->chain); | |
| 48 | − | |
| 49 | − BUILD_BUG_ON(offsetof(typeof(*stub), dma)); | |
| 50 | − dma_fence_free(&stub->dma); | |
| 51 | −} | |
| 52 | − | |
| 53 | −static const struct dma_fence_ops stub_fence_ops = { | |
| 54 | − .get_driver_name = stub_driver_name, | |
| 55 | − .get_timeline_name = stub_timeline_name, | |
| 56 | − .release = stub_release, | |
| 57 | −}; | |
| 58 | − | |
| 59 | −struct dma_fence * | |
| 60 | −i915_gem_object_lock_fence(struct drm_i915_gem_object *obj) | |
| 61 | −{ | |
| 62 | − struct stub_fence *stub; | |
| 63 | − | |
| 64 | − assert_object_held(obj); | |
| 65 | − | |
| 66 | − stub = kmalloc(sizeof(*stub), GFP_KERNEL); | |
| 67 | − if (!stub) | |
| 68 | − return NULL; | |
| 69 | − | |
| 70 | − i915_sw_fence_init(&stub->chain, stub_notify); | |
| 71 | − dma_fence_init(&stub->dma, &stub_fence_ops, &stub->chain.wait.lock, | |
| 72 | − 0, 0); | |
| 73 | − | |
| 74 | − if (i915_sw_fence_await_reservation(&stub->chain, | |
| 75 | − obj->base.resv, NULL, true, | |
| 76 | − i915_fence_timeout(to_i915(obj->base.dev)), | |
| 77 | − I915_FENCE_GFP) < 0) | |
| 78 | − goto err; | |
| 79 | − | |
| 80 | − dma_resv_add_excl_fence(obj->base.resv, &stub->dma); | |
| 81 | − | |
| 82 | − return &stub->dma; | |
| 83 | − | |
| 84 | −err: | |
| 85 | − stub_release(&stub->dma); | |
| 86 | − return NULL; | |
| 87 | −} | |
| 88 | − | |
| 89 | −void i915_gem_object_unlock_fence(struct drm_i915_gem_object *obj, | |
| 90 | − struct dma_fence *fence) | |
| 91 | −{ | |
| 92 | − struct stub_fence *stub = container_of(fence, typeof(*stub), dma); | |
| 93 | − | |
| 94 | − i915_sw_fence_commit(&stub->chain); | |
| 95 | −} | |
| @@ -138,8 +138,7 @@ static void i915_gem_object_put_pages_internal(struct drm_i915_gem_object *obj, · 137 unmodified lines | ||
| 138 | 138 | |
| 139 | 139 | static const struct drm_i915_gem_object_ops i915_gem_object_internal_ops = { |
| 140 | 140 | .name = "i915_gem_object_internal", |
| 141 | − .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE | | |
| 142 | − I915_GEM_OBJECT_IS_SHRINKABLE, | |
| 141 | + .flags = I915_GEM_OBJECT_IS_SHRINKABLE, | |
| 143 | 142 | .get_pages = i915_gem_object_get_pages_internal, |
| 144 | 143 | .put_pages = i915_gem_object_put_pages_internal, |
| 145 | 144 | }; |
| @@ -178,7 +177,8 @@ i915_gem_object_create_internal(struct drm_i915_private *i915, · 32 unmodified lines | ||
| 178 | 177 | return ERR_PTR(-ENOMEM); |
| 179 | 178 | |
| 180 | 179 | drm_gem_private_object_init(&i915->drm, &obj->base, size); |
| 181 | − i915_gem_object_init(obj, &i915_gem_object_internal_ops, &lock_class); | |
| 180 | + i915_gem_object_init(obj, &i915_gem_object_internal_ops, &lock_class, | |
| 181 | + I915_BO_ALLOC_STRUCT_PAGE); | |
| 182 | 182 | |
| 183 | 183 | /* |
| 184 | 184 | * Mark the object as volatile, such that the pages are marked as |
| @@ -14,8 +14,6 @@ int i915_gem_busy_ioctl(struct drm_device *dev, void *data, · 13 unmodified lines | ||
| 14 | 14 | struct drm_file *file); |
| 15 | 15 | int i915_gem_create_ioctl(struct drm_device *dev, void *data, |
| 16 | 16 | struct drm_file *file); |
| 17 | −int i915_gem_execbuffer_ioctl(struct drm_device *dev, void *data, | |
| 18 | − struct drm_file *file); | |
| 19 | 17 | int i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, |
| 20 | 18 | struct drm_file *file); |
| 21 | 19 | int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, |
| @@ -40,13 +40,13 @@ int __i915_gem_lmem_object_init(struct intel_memory_region *mem, · 39 unmodified lines | ||
| 40 | 40 | struct drm_i915_private *i915 = mem->i915; |
| 41 | 41 | |
| 42 | 42 | drm_gem_private_object_init(&i915->drm, &obj->base, size); |
| 43 | − i915_gem_object_init(obj, &i915_gem_lmem_obj_ops, &lock_class); | |
| 43 | + i915_gem_object_init(obj, &i915_gem_lmem_obj_ops, &lock_class, flags); | |
| 44 | 44 | |
| 45 | 45 | obj->read_domains = I915_GEM_DOMAIN_WC | I915_GEM_DOMAIN_GTT; |
| 46 | 46 | |
| 47 | 47 | i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); |
| 48 | 48 | |
| 49 | − i915_gem_object_init_memory_region(obj, mem, flags); | |
| 49 | + i915_gem_object_init_memory_region(obj, mem); | |
| 50 | 50 | |
| 51 | 51 | return 0; |
| 52 | 52 | } |
| @@ -246,12 +246,15 @@ static vm_fault_t vm_fault_cpu(struct vm_fault *vmf) · 245 unmodified lines | ||
| 246 | 246 | area->vm_flags & VM_WRITE)) |
| 247 | 247 | return VM_FAULT_SIGBUS; |
| 248 | 248 | |
| 249 | + if (i915_gem_object_lock_interruptible(obj, NULL)) | |
| 250 | + return VM_FAULT_NOPAGE; | |
| 251 | + | |
| 249 | 252 | err = i915_gem_object_pin_pages(obj); |
| 250 | 253 | if (err) |
| 251 | 254 | goto out; |
| 252 | 255 | |
| 253 | 256 | iomap = -1; |
| 254 | − if (!i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_STRUCT_PAGE)) { | |
| 257 | + if (!i915_gem_object_has_struct_page(obj)) { | |
| 255 | 258 | iomap = obj->mm.region->iomap.base; |
| 256 | 259 | iomap -= obj->mm.region->region.start; |
| 257 | 260 | } |
| @@ -269,6 +272,7 @@ static vm_fault_t vm_fault_cpu(struct vm_fault *vmf) · 11 unmodified lines | ||
| 269 | 272 | i915_gem_object_unpin_pages(obj); |
| 270 | 273 | |
| 271 | 274 | out: |
| 275 | + i915_gem_object_unlock(obj); | |
| 272 | 276 | return i915_error_to_vmf_fault(err); |
| 273 | 277 | } |
| 274 | 278 | |
| @@ -417,7 +421,9 @@ vm_access(struct vm_area_struct *area, unsigned long addr, · 142 unmodified lines | ||
| 417 | 421 | { |
| 418 | 422 | struct i915_mmap_offset *mmo = area->vm_private_data; |
| 419 | 423 | struct drm_i915_gem_object *obj = mmo->obj; |
| 424 | + struct i915_gem_ww_ctx ww; | |
| 420 | 425 | void *vaddr; |
| 426 | + int err = 0; | |
| 421 | 427 | |
| 422 | 428 | if (i915_gem_object_is_readonly(obj) && write) |
| 423 | 429 | return -EACCES; |
| @@ -426,10 +432,18 @@ vm_access(struct vm_area_struct *area, unsigned long addr, · 2 unmodified lines | ||
| 426 | 432 | if (addr >= obj->base.size) |
| 427 | 433 | return -EINVAL; |
| 428 | 434 | |
| 435 | + i915_gem_ww_ctx_init(&ww, true); | |
| 436 | +retry: | |
| 437 | + err = i915_gem_object_lock(obj, &ww); | |
| 438 | + if (err) | |
| 439 | + goto out; | |
| 440 | + | |
| 429 | 441 | /* As this is primarily for debugging, let's focus on simplicity */ |
| 430 | 442 | vaddr = i915_gem_object_pin_map(obj, I915_MAP_FORCE_WC); |
| 431 | − if (IS_ERR(vaddr)) | |
| 432 | − return PTR_ERR(vaddr); | |
| 443 | + if (IS_ERR(vaddr)) { | |
| 444 | + err = PTR_ERR(vaddr); | |
| 445 | + goto out; | |
| 446 | + } | |
| 433 | 447 | |
| 434 | 448 | if (write) { |
| 435 | 449 | memcpy(vaddr + addr, buf, len); |
| @@ -439,6 +453,16 @@ vm_access(struct vm_area_struct *area, unsigned long addr, · 3 unmodified lines | ||
| 439 | 453 | } |
| 440 | 454 | |
| 441 | 455 | i915_gem_object_unpin_map(obj); |
| 456 | +out: | |
| 457 | + if (err == -EDEADLK) { | |
| 458 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 459 | + if (!err) | |
| 460 | + goto retry; | |
| 461 | + } | |
| 462 | + i915_gem_ww_ctx_fini(&ww); | |
| 463 | + | |
| 464 | + if (err) | |
| 465 | + return err; | |
| 442 | 466 | |
| 443 | 467 | return len; |
| 444 | 468 | } |
| @@ -653,9 +677,8 @@ __assign_mmap_offset(struct drm_file *file, · 208 unmodified lines | ||
| 653 | 677 | } |
| 654 | 678 | |
| 655 | 679 | if (mmap_type != I915_MMAP_TYPE_GTT && |
| 656 | − !i915_gem_object_type_has(obj, | |
| 657 | − I915_GEM_OBJECT_HAS_STRUCT_PAGE | | |
| 658 | − I915_GEM_OBJECT_HAS_IOMEM)) { | |
| 680 | + !i915_gem_object_has_struct_page(obj) && | |
| 681 | + !i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_IOMEM)) { | |
| 659 | 682 | err = -ENODEV; |
| 660 | 683 | goto out; |
| 661 | 684 | } |
| @@ -60,10 +60,8 @@ void i915_gem_object_free(struct drm_i915_gem_object *obj) · 59 unmodified lines | ||
| 60 | 60 | |
| 61 | 61 | void i915_gem_object_init(struct drm_i915_gem_object *obj, |
| 62 | 62 | const struct drm_i915_gem_object_ops *ops, |
| 63 | − struct lock_class_key *key) | |
| 63 | + struct lock_class_key *key, unsigned flags) | |
| 64 | 64 | { |
| 65 | − __mutex_init(&obj->mm.lock, ops->name ?: "obj->mm.lock", key); | |
| 66 | − | |
| 67 | 65 | spin_lock_init(&obj->vma.lock); |
| 68 | 66 | INIT_LIST_HEAD(&obj->vma.list); |
| 69 | 67 | |
| @@ -78,16 +76,14 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, · 8 unmodified lines | ||
| 78 | 76 | init_rcu_head(&obj->rcu); |
| 79 | 77 | |
| 80 | 78 | obj->ops = ops; |
| 79 | + GEM_BUG_ON(flags & ~I915_BO_ALLOC_FLAGS); | |
| 80 | + obj->flags = flags; | |
| 81 | 81 | |
| 82 | 82 | obj->mm.madv = I915_MADV_WILLNEED; |
| 83 | 83 | INIT_RADIX_TREE(&obj->mm.get_page.radix, GFP_KERNEL | __GFP_NOWARN); |
| 84 | 84 | mutex_init(&obj->mm.get_page.lock); |
| 85 | 85 | INIT_RADIX_TREE(&obj->mm.get_dma_page.radix, GFP_KERNEL | __GFP_NOWARN); |
| 86 | 86 | mutex_init(&obj->mm.get_dma_page.lock); |
| 87 | − | |
| 88 | − if (IS_ENABLED(CONFIG_LOCKDEP) && i915_gem_object_is_shrinkable(obj)) | |
| 89 | − i915_gem_shrinker_taints_mutex(to_i915(obj->base.dev), | |
| 90 | − &obj->mm.lock); | |
| 91 | 87 | } |
| 92 | 88 | |
| 93 | 89 | /** |
| @@ -23,7 +23,8 @@ void i915_gem_object_free(struct drm_i915_gem_object *obj); · 22 unmodified lines | ||
| 23 | 23 | |
| 24 | 24 | void i915_gem_object_init(struct drm_i915_gem_object *obj, |
| 25 | 25 | const struct drm_i915_gem_object_ops *ops, |
| 26 | − struct lock_class_key *key); | |
| 26 | + struct lock_class_key *key, | |
| 27 | + unsigned alloc_flags); | |
| 27 | 28 | struct drm_i915_gem_object * |
| 28 | 29 | i915_gem_object_create_shmem(struct drm_i915_private *i915, |
| 29 | 30 | resource_size_t size); |
| @@ -32,11 +33,21 @@ i915_gem_object_create_shmem_from_data(struct drm_i915_private *i915, · 2 unmodified lines | ||
| 32 | 33 | const void *data, resource_size_t size); |
| 33 | 34 | |
| 34 | 35 | extern const struct drm_i915_gem_object_ops i915_gem_shmem_ops; |
| 36 | + | |
| 35 | 37 | void __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj, |
| 36 | 38 | struct sg_table *pages, |
| 37 | 39 | bool needs_clflush); |
| 38 | 40 | |
| 41 | +int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj, | |
| 42 | + const struct drm_i915_gem_pwrite *args); | |
| 43 | +int i915_gem_object_pread_phys(struct drm_i915_gem_object *obj, | |
| 44 | + const struct drm_i915_gem_pread *args); | |
| 45 | + | |
| 39 | 46 | int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align); |
| 47 | +void i915_gem_object_put_pages_shmem(struct drm_i915_gem_object *obj, | |
| 48 | + struct sg_table *pages); | |
| 49 | +void i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, | |
| 50 | + struct sg_table *pages); | |
| 40 | 51 | |
| 41 | 52 | void i915_gem_flush_free_objects(struct drm_i915_private *i915); |
| 42 | 53 | |
| @@ -107,6 +118,20 @@ i915_gem_object_put(struct drm_i915_gem_object *obj) · 64 unmodified lines | ||
| 107 | 118 | |
| 108 | 119 | #define assert_object_held(obj) dma_resv_assert_held((obj)->base.resv) |
| 109 | 120 | |
| 121 | +/* | |
| 122 | + * If more than one potential simultaneous locker, assert held. | |
| 123 | + */ | |
| 124 | +static inline void assert_object_held_shared(struct drm_i915_gem_object *obj) | |
| 125 | +{ | |
| 126 | + /* | |
| 127 | + * Note mm list lookup is protected by | |
| 128 | + * kref_get_unless_zero(). | |
| 129 | + */ | |
| 130 | + if (IS_ENABLED(CONFIG_LOCKDEP) && | |
| 131 | + kref_read(&obj->base.refcount) > 0) | |
| 132 | + assert_object_held(obj); | |
| 133 | +} | |
| 134 | + | |
| 110 | 135 | static inline int __i915_gem_object_lock(struct drm_i915_gem_object *obj, |
| 111 | 136 | struct i915_gem_ww_ctx *ww, |
| 112 | 137 | bool intr) |
| @@ -152,11 +177,6 @@ static inline void i915_gem_object_unlock(struct drm_i915_gem_object *obj) · 39 unmodified lines | ||
| 152 | 177 | dma_resv_unlock(obj->base.resv); |
| 153 | 178 | } |
| 154 | 179 | |
| 155 | −struct dma_fence * | |
| 156 | −i915_gem_object_lock_fence(struct drm_i915_gem_object *obj); | |
| 157 | −void i915_gem_object_unlock_fence(struct drm_i915_gem_object *obj, | |
| 158 | − struct dma_fence *fence); | |
| 159 | − | |
| 160 | 180 | static inline void |
| 161 | 181 | i915_gem_object_set_readonly(struct drm_i915_gem_object *obj) |
| 162 | 182 | { |
| @@ -215,7 +235,7 @@ i915_gem_object_type_has(const struct drm_i915_gem_object *obj, · 52 unmodified lines | ||
| 215 | 235 | static inline bool |
| 216 | 236 | i915_gem_object_has_struct_page(const struct drm_i915_gem_object *obj) |
| 217 | 237 | { |
| 218 | − return i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_STRUCT_PAGE); | |
| 238 | + return obj->flags & I915_BO_ALLOC_STRUCT_PAGE; | |
| 219 | 239 | } |
| 220 | 240 | |
| 221 | 241 | static inline bool |
| @@ -242,12 +262,6 @@ i915_gem_object_never_mmap(const struct drm_i915_gem_object *obj) · 20 unmodified lines | ||
| 242 | 262 | return i915_gem_object_type_has(obj, I915_GEM_OBJECT_NO_MMAP); |
| 243 | 263 | } |
| 244 | 264 | |
| 245 | −static inline bool | |
| 246 | −i915_gem_object_needs_async_cancel(const struct drm_i915_gem_object *obj) | |
| 247 | −{ | |
| 248 | − return i915_gem_object_type_has(obj, I915_GEM_OBJECT_ASYNC_CANCEL); | |
| 249 | −} | |
| 250 | − | |
| 251 | 265 | static inline bool |
| 252 | 266 | i915_gem_object_is_framebuffer(const struct drm_i915_gem_object *obj) |
| 253 | 267 | { |
| @@ -299,22 +313,22 @@ struct scatterlist * · 45 unmodified lines | ||
| 299 | 313 | __i915_gem_object_get_sg(struct drm_i915_gem_object *obj, |
| 300 | 314 | struct i915_gem_object_page_iter *iter, |
| 301 | 315 | unsigned int n, |
| 302 | − unsigned int *offset); | |
| 316 | + unsigned int *offset, bool allow_alloc); | |
| 303 | 317 | |
| 304 | 318 | static inline struct scatterlist * |
| 305 | 319 | i915_gem_object_get_sg(struct drm_i915_gem_object *obj, |
| 306 | 320 | unsigned int n, |
| 307 | − unsigned int *offset) | |
| 321 | + unsigned int *offset, bool allow_alloc) | |
| 308 | 322 | { |
| 309 | − return __i915_gem_object_get_sg(obj, &obj->mm.get_page, n, offset); | |
| 323 | + return __i915_gem_object_get_sg(obj, &obj->mm.get_page, n, offset, allow_alloc); | |
| 310 | 324 | } |
| 311 | 325 | |
| 312 | 326 | static inline struct scatterlist * |
| 313 | 327 | i915_gem_object_get_sg_dma(struct drm_i915_gem_object *obj, |
| 314 | 328 | unsigned int n, |
| 315 | − unsigned int *offset) | |
| 329 | + unsigned int *offset, bool allow_alloc) | |
| 316 | 330 | { |
| 317 | − return __i915_gem_object_get_sg(obj, &obj->mm.get_dma_page, n, offset); | |
| 331 | + return __i915_gem_object_get_sg(obj, &obj->mm.get_dma_page, n, offset, allow_alloc); | |
| 318 | 332 | } |
| 319 | 333 | |
| 320 | 334 | struct page * |
| @@ -341,27 +355,10 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, · 20 unmodified lines | ||
| 341 | 355 | int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj); |
| 342 | 356 | int __i915_gem_object_get_pages(struct drm_i915_gem_object *obj); |
| 343 | 357 | |
| 344 | −enum i915_mm_subclass { /* lockdep subclass for obj->mm.lock/struct_mutex */ | |
| 345 | − I915_MM_NORMAL = 0, | |
| 346 | − /* | |
| 347 | − * Only used by struct_mutex, when called "recursively" from | |
| 348 | − * direct-reclaim-esque. Safe because there is only every one | |
| 349 | − * struct_mutex in the entire system. | |
| 350 | − */ | |
| 351 | − I915_MM_SHRINKER = 1, | |
| 352 | − /* | |
| 353 | − * Used for obj->mm.lock when allocating pages. Safe because the object | |
| 354 | − * isn't yet on any LRU, and therefore the shrinker can't deadlock on | |
| 355 | − * it. As soon as the object has pages, obj->mm.lock nests within | |
| 356 | − * fs_reclaim. | |
| 357 | − */ | |
| 358 | − I915_MM_GET_PAGES = 1, | |
| 359 | −}; | |
| 360 | − | |
| 361 | 358 | static inline int __must_check |
| 362 | 359 | i915_gem_object_pin_pages(struct drm_i915_gem_object *obj) |
| 363 | 360 | { |
| 364 | − might_lock_nested(&obj->mm.lock, I915_MM_GET_PAGES); | |
| 361 | + assert_object_held(obj); | |
| 365 | 362 | |
| 366 | 363 | if (atomic_inc_not_zero(&obj->mm.pages_pin_count)) |
| 367 | 364 | return 0; |
| @@ -369,6 +366,8 @@ i915_gem_object_pin_pages(struct drm_i915_gem_object *obj) · 1 unmodified line | ||
| 369 | 366 | return __i915_gem_object_get_pages(obj); |
| 370 | 367 | } |
| 371 | 368 | |
| 369 | +int i915_gem_object_pin_pages_unlocked(struct drm_i915_gem_object *obj); | |
| 370 | + | |
| 372 | 371 | static inline bool |
| 373 | 372 | i915_gem_object_has_pages(struct drm_i915_gem_object *obj) |
| 374 | 373 | { |
| @@ -427,6 +426,9 @@ void i915_gem_object_writeback(struct drm_i915_gem_object *obj); · 52 unmodified lines | ||
| 427 | 426 | void *__must_check i915_gem_object_pin_map(struct drm_i915_gem_object *obj, |
| 428 | 427 | enum i915_map_type type); |
| 429 | 428 | |
| 429 | +void *__must_check i915_gem_object_pin_map_unlocked(struct drm_i915_gem_object *obj, | |
| 430 | + enum i915_map_type type); | |
| 431 | + | |
| 430 | 432 | void __i915_gem_object_flush_map(struct drm_i915_gem_object *obj, |
| 431 | 433 | unsigned long offset, |
| 432 | 434 | unsigned long size); |
| @@ -495,6 +497,7 @@ int __must_check · 62 unmodified lines | ||
| 495 | 497 | i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write); |
| 496 | 498 | struct i915_vma * __must_check |
| 497 | 499 | i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, |
| 500 | + struct i915_gem_ww_ctx *ww, | |
| 498 | 501 | u32 alignment, |
| 499 | 502 | const struct i915_ggtt_view *view, |
| 500 | 503 | unsigned int flags); |
| @@ -558,4 +561,25 @@ int i915_gem_object_read_from_page(struct drm_i915_gem_object *obj, u64 offset, · 57 unmodified lines | ||
| 558 | 561 | |
| 559 | 562 | bool i915_gem_object_is_shmem(const struct drm_i915_gem_object *obj); |
| 560 | 563 | |
| 564 | +#ifdef CONFIG_MMU_NOTIFIER | |
| 565 | +static inline bool | |
| 566 | +i915_gem_object_is_userptr(struct drm_i915_gem_object *obj) | |
| 567 | +{ | |
| 568 | + return obj->userptr.notifier.mm; | |
| 569 | +} | |
| 570 | + | |
| 571 | +int i915_gem_object_userptr_submit_init(struct drm_i915_gem_object *obj); | |
| 572 | +int i915_gem_object_userptr_submit_done(struct drm_i915_gem_object *obj); | |
| 573 | +void i915_gem_object_userptr_submit_fini(struct drm_i915_gem_object *obj); | |
| 574 | +int i915_gem_object_userptr_validate(struct drm_i915_gem_object *obj); | |
| 575 | +#else | |
| 576 | +static inline bool i915_gem_object_is_userptr(struct drm_i915_gem_object *obj) { return false; } | |
| 577 | + | |
| 578 | +static inline int i915_gem_object_userptr_submit_init(struct drm_i915_gem_object *obj) { GEM_BUG_ON(1); return -ENODEV; } | |
| 579 | +static inline int i915_gem_object_userptr_submit_done(struct drm_i915_gem_object *obj) { GEM_BUG_ON(1); return -ENODEV; } | |
| 580 | +static inline void i915_gem_object_userptr_submit_fini(struct drm_i915_gem_object *obj) { GEM_BUG_ON(1); } | |
| 581 | +static inline int i915_gem_object_userptr_validate(struct drm_i915_gem_object *obj) { GEM_BUG_ON(1); return -ENODEV; } | |
| 582 | + | |
| 583 | +#endif | |
| 584 | + | |
| 561 | 585 | #endif |
| @@ -55,6 +55,9 @@ struct i915_vma *intel_emit_vma_fill_blt(struct intel_context *ce, · 54 unmodified lines | ||
| 55 | 55 | if (unlikely(err)) |
| 56 | 56 | goto out_put; |
| 57 | 57 | |
| 58 | + /* we pinned the pool, mark it as such */ | |
| 59 | + intel_gt_buffer_pool_mark_used(pool); | |
| 60 | + | |
| 58 | 61 | cmd = i915_gem_object_pin_map(pool->obj, pool->type); |
| 59 | 62 | if (IS_ERR(cmd)) { |
| 60 | 63 | err = PTR_ERR(cmd); |
| @@ -277,6 +280,9 @@ struct i915_vma *intel_emit_vma_copy_blt(struct intel_context *ce, · 216 unmodified lines | ||
| 277 | 280 | if (unlikely(err)) |
| 278 | 281 | goto out_put; |
| 279 | 282 | |
| 283 | + /* we pinned the pool, mark it as such */ | |
| 284 | + intel_gt_buffer_pool_mark_used(pool); | |
| 285 | + | |
| 280 | 286 | cmd = i915_gem_object_pin_map(pool->obj, pool->type); |
| 281 | 287 | if (IS_ERR(cmd)) { |
| 282 | 288 | err = PTR_ERR(cmd); |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | ||
| 7 | 7 | #ifndef __I915_GEM_OBJECT_TYPES_H__ |
| 8 | 8 | #define __I915_GEM_OBJECT_TYPES_H__ |
| 9 | 9 | |
| 10 | +#include <linux/mmu_notifier.h> | |
| 11 | + | |
| 10 | 12 | #include <drm/drm_gem.h> |
| 11 | 13 | #include <uapi/drm/i915_drm.h> |
| 12 | 14 | |
| @@ -30,12 +32,10 @@ struct i915_lut_handle { · 17 unmodified lines | ||
| 30 | 32 | |
| 31 | 33 | struct drm_i915_gem_object_ops { |
| 32 | 34 | unsigned int flags; |
| 33 | −#define I915_GEM_OBJECT_HAS_STRUCT_PAGE BIT(0) | |
| 34 | 35 | #define I915_GEM_OBJECT_HAS_IOMEM BIT(1) |
| 35 | 36 | #define I915_GEM_OBJECT_IS_SHRINKABLE BIT(2) |
| 36 | 37 | #define I915_GEM_OBJECT_IS_PROXY BIT(3) |
| 37 | 38 | #define I915_GEM_OBJECT_NO_MMAP BIT(4) |
| 38 | −#define I915_GEM_OBJECT_ASYNC_CANCEL BIT(5) | |
| 39 | 39 | |
| 40 | 40 | /* Interface between the GEM object and its backing storage. |
| 41 | 41 | * get_pages() is called once prior to the use of the associated set |
| @@ -171,9 +171,12 @@ struct drm_i915_gem_object { · 129 unmodified lines | ||
| 171 | 171 | unsigned long flags; |
| 172 | 172 | #define I915_BO_ALLOC_CONTIGUOUS BIT(0) |
| 173 | 173 | #define I915_BO_ALLOC_VOLATILE BIT(1) |
| 174 | −#define I915_BO_ALLOC_FLAGS (I915_BO_ALLOC_CONTIGUOUS | I915_BO_ALLOC_VOLATILE) | |
| 175 | −#define I915_BO_READONLY BIT(2) | |
| 176 | −#define I915_TILING_QUIRK_BIT 3 /* unknown swizzling; do not release! */ | |
| 174 | +#define I915_BO_ALLOC_STRUCT_PAGE BIT(2) | |
| 175 | +#define I915_BO_ALLOC_FLAGS (I915_BO_ALLOC_CONTIGUOUS | \ | |
| 176 | + I915_BO_ALLOC_VOLATILE | \ | |
| 177 | + I915_BO_ALLOC_STRUCT_PAGE) | |
| 178 | +#define I915_BO_READONLY BIT(3) | |
| 179 | +#define I915_TILING_QUIRK_BIT 4 /* unknown swizzling; do not release! */ | |
| 177 | 180 | |
| 178 | 181 | /* |
| 179 | 182 | * Is the object to be mapped as read-only to the GPU |
| @@ -213,7 +216,6 @@ struct drm_i915_gem_object { · 33 unmodified lines | ||
| 213 | 216 | * Protects the pages and their use. Do not use directly, but |
| 214 | 217 | * instead go through the pin/unpin interfaces. |
| 215 | 218 | */ |
| 216 | − struct mutex lock; | |
| 217 | 219 | atomic_t pages_pin_count; |
| 218 | 220 | atomic_t shrink_pin; |
| 219 | 221 | |
| @@ -288,13 +290,16 @@ struct drm_i915_gem_object { · 68 unmodified lines | ||
| 288 | 290 | unsigned long *bit_17; |
| 289 | 291 | |
| 290 | 292 | union { |
| 293 | +#ifdef CONFIG_MMU_NOTIFIER | |
| 291 | 294 | struct i915_gem_userptr { |
| 292 | 295 | uintptr_t ptr; |
| 296 | + unsigned long notifier_seq; | |
| 293 | 297 | |
| 294 | − struct i915_mm_struct *mm; | |
| 295 | − struct i915_mmu_object *mmu_object; | |
| 296 | − struct work_struct *work; | |
| 298 | + struct mmu_interval_notifier notifier; | |
| 299 | + struct page **pvec; | |
| 300 | + int page_ref; | |
| 297 | 301 | } userptr; |
| 302 | +#endif | |
| 298 | 303 | |
| 299 | 304 | struct drm_mm_node *stolen; |
| 300 | 305 | |
| @@ -19,7 +19,7 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, · 18 unmodified lines | ||
| 19 | 19 | bool shrinkable; |
| 20 | 20 | int i; |
| 21 | 21 | |
| 22 | − lockdep_assert_held(&obj->mm.lock); | |
| 22 | + assert_object_held_shared(obj); | |
| 23 | 23 | |
| 24 | 24 | if (i915_gem_object_is_volatile(obj)) |
| 25 | 25 | obj->mm.madv = I915_MADV_DONTNEED; |
| @@ -70,6 +70,7 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj, · 44 unmodified lines | ||
| 70 | 70 | struct list_head *list; |
| 71 | 71 | unsigned long flags; |
| 72 | 72 | |
| 73 | + assert_object_held(obj); | |
| 73 | 74 | spin_lock_irqsave(&i915->mm.obj_lock, flags); |
| 74 | 75 | |
| 75 | 76 | i915->mm.shrink_count++; |
| @@ -91,6 +92,8 @@ int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj) · 15 unmodified lines | ||
| 91 | 92 | struct drm_i915_private *i915 = to_i915(obj->base.dev); |
| 92 | 93 | int err; |
| 93 | 94 | |
| 95 | + assert_object_held_shared(obj); | |
| 96 | + | |
| 94 | 97 | if (unlikely(obj->mm.madv != I915_MADV_WILLNEED)) { |
| 95 | 98 | drm_dbg(&i915->drm, |
| 96 | 99 | "Attempting to obtain a purgeable object\n"); |
| @@ -114,23 +117,41 @@ int __i915_gem_object_get_pages(struct drm_i915_gem_object *obj) · 17 unmodified lines | ||
| 114 | 117 | { |
| 115 | 118 | int err; |
| 116 | 119 | |
| 117 | − err = mutex_lock_interruptible_nested(&obj->mm.lock, I915_MM_GET_PAGES); | |
| 118 | − if (err) | |
| 119 | − return err; | |
| 120 | + assert_object_held(obj); | |
| 121 | + | |
| 122 | + assert_object_held_shared(obj); | |
| 120 | 123 | |
| 121 | 124 | if (unlikely(!i915_gem_object_has_pages(obj))) { |
| 122 | 125 | GEM_BUG_ON(i915_gem_object_has_pinned_pages(obj)); |
| 123 | 126 | |
| 124 | 127 | err = ____i915_gem_object_get_pages(obj); |
| 125 | 128 | if (err) |
| 126 | − goto unlock; | |
| 129 | + return err; | |
| 127 | 130 | |
| 128 | 131 | smp_mb__before_atomic(); |
| 129 | 132 | } |
| 130 | 133 | atomic_inc(&obj->mm.pages_pin_count); |
| 131 | 134 | |
| 132 | −unlock: | |
| 133 | − mutex_unlock(&obj->mm.lock); | |
| 135 | + return 0; | |
| 136 | +} | |
| 137 | + | |
| 138 | +int i915_gem_object_pin_pages_unlocked(struct drm_i915_gem_object *obj) | |
| 139 | +{ | |
| 140 | + struct i915_gem_ww_ctx ww; | |
| 141 | + int err; | |
| 142 | + | |
| 143 | + i915_gem_ww_ctx_init(&ww, true); | |
| 144 | +retry: | |
| 145 | + err = i915_gem_object_lock(obj, &ww); | |
| 146 | + if (!err) | |
| 147 | + err = i915_gem_object_pin_pages(obj); | |
| 148 | + | |
| 149 | + if (err == -EDEADLK) { | |
| 150 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 151 | + if (!err) | |
| 152 | + goto retry; | |
| 153 | + } | |
| 154 | + i915_gem_ww_ctx_fini(&ww); | |
| 134 | 155 | return err; |
| 135 | 156 | } |
| 136 | 157 | |
| @@ -145,7 +166,7 @@ void i915_gem_object_truncate(struct drm_i915_gem_object *obj) · 8 unmodified lines | ||
| 145 | 166 | /* Try to discard unwanted pages */ |
| 146 | 167 | void i915_gem_object_writeback(struct drm_i915_gem_object *obj) |
| 147 | 168 | { |
| 148 | − lockdep_assert_held(&obj->mm.lock); | |
| 169 | + assert_object_held_shared(obj); | |
| 149 | 170 | GEM_BUG_ON(i915_gem_object_has_pages(obj)); |
| 150 | 171 | |
| 151 | 172 | if (obj->ops->writeback) |
| @@ -176,6 +197,8 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj) · 24 unmodified lines | ||
| 176 | 197 | { |
| 177 | 198 | struct sg_table *pages; |
| 178 | 199 | |
| 200 | + assert_object_held_shared(obj); | |
| 201 | + | |
| 179 | 202 | pages = fetch_and_zero(&obj->mm.pages); |
| 180 | 203 | if (IS_ERR_OR_NULL(pages)) |
| 181 | 204 | return pages; |
| @@ -199,17 +222,12 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj) · 17 unmodified lines | ||
| 199 | 222 | int __i915_gem_object_put_pages(struct drm_i915_gem_object *obj) |
| 200 | 223 | { |
| 201 | 224 | struct sg_table *pages; |
| 202 | − int err; | |
| 203 | 225 | |
| 204 | 226 | if (i915_gem_object_has_pinned_pages(obj)) |
| 205 | 227 | return -EBUSY; |
| 206 | 228 | |
| 207 | 229 | /* May be called by shrinker from within get_pages() (on another bo) */ |
| 208 | − mutex_lock(&obj->mm.lock); | |
| 209 | − if (unlikely(atomic_read(&obj->mm.pages_pin_count))) { | |
| 210 | − err = -EBUSY; | |
| 211 | − goto unlock; | |
| 212 | − } | |
| 230 | + assert_object_held_shared(obj); | |
| 213 | 231 | |
| 214 | 232 | i915_gem_object_release_mmap_offset(obj); |
| 215 | 233 | |
| @@ -226,17 +244,10 @@ int __i915_gem_object_put_pages(struct drm_i915_gem_object *obj) · 10 unmodified lines | ||
| 226 | 244 | * get_pages backends we should be better able to handle the |
| 227 | 245 | * cancellation of the async task in a more uniform manner. |
| 228 | 246 | */ |
| 229 | − if (!pages && !i915_gem_object_needs_async_cancel(obj)) | |
| 230 | − pages = ERR_PTR(-EINVAL); | |
| 231 | − | |
| 232 | − if (!IS_ERR(pages)) | |
| 247 | + if (!IS_ERR_OR_NULL(pages)) | |
| 233 | 248 | obj->ops->put_pages(obj, pages); |
| 234 | 249 | |
| 235 | − err = 0; | |
| 236 | −unlock: | |
| 237 | − mutex_unlock(&obj->mm.lock); | |
| 238 | − | |
| 239 | − return err; | |
| 250 | + return 0; | |
| 240 | 251 | } |
| 241 | 252 | |
| 242 | 253 | /* The 'mapping' part of i915_gem_object_pin_map() below */ |
| @@ -333,18 +344,15 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, · 90 unmodified lines | ||
| 333 | 344 | enum i915_map_type type) |
| 334 | 345 | { |
| 335 | 346 | enum i915_map_type has_type; |
| 336 | − unsigned int flags; | |
| 337 | 347 | bool pinned; |
| 338 | 348 | void *ptr; |
| 339 | 349 | int err; |
| 340 | 350 | |
| 341 | − flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE | I915_GEM_OBJECT_HAS_IOMEM; | |
| 342 | − if (!i915_gem_object_type_has(obj, flags)) | |
| 351 | + if (!i915_gem_object_has_struct_page(obj) && | |
| 352 | + !i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_IOMEM)) | |
| 343 | 353 | return ERR_PTR(-ENXIO); |
| 344 | 354 | |
| 345 | − err = mutex_lock_interruptible_nested(&obj->mm.lock, I915_MM_GET_PAGES); | |
| 346 | − if (err) | |
| 347 | − return ERR_PTR(err); | |
| 355 | + assert_object_held(obj); | |
| 348 | 356 | |
| 349 | 357 | pinned = !(type & I915_MAP_OVERRIDE); |
| 350 | 358 | type &= ~I915_MAP_OVERRIDE; |
| @@ -354,10 +362,8 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, · 3 unmodified lines | ||
| 354 | 362 | GEM_BUG_ON(i915_gem_object_has_pinned_pages(obj)); |
| 355 | 363 | |
| 356 | 364 | err = ____i915_gem_object_get_pages(obj); |
| 357 | − if (err) { | |
| 358 | − ptr = ERR_PTR(err); | |
| 359 | − goto out_unlock; | |
| 360 | − } | |
| 365 | + if (err) | |
| 366 | + return ERR_PTR(err); | |
| 361 | 367 | |
| 362 | 368 | smp_mb__before_atomic(); |
| 363 | 369 | } |
| @@ -392,13 +398,23 @@ void *i915_gem_object_pin_map(struct drm_i915_gem_object *obj, · 28 unmodified lines | ||
| 392 | 398 | obj->mm.mapping = page_pack_bits(ptr, type); |
| 393 | 399 | } |
| 394 | 400 | |
| 395 | −out_unlock: | |
| 396 | − mutex_unlock(&obj->mm.lock); | |
| 397 | 401 | return ptr; |
| 398 | 402 | |
| 399 | 403 | err_unpin: |
| 400 | 404 | atomic_dec(&obj->mm.pages_pin_count); |
| 401 | − goto out_unlock; | |
| 405 | + return ptr; | |
| 406 | +} | |
| 407 | + | |
| 408 | +void *i915_gem_object_pin_map_unlocked(struct drm_i915_gem_object *obj, | |
| 409 | + enum i915_map_type type) | |
| 410 | +{ | |
| 411 | + void *ret; | |
| 412 | + | |
| 413 | + i915_gem_object_lock(obj, NULL); | |
| 414 | + ret = i915_gem_object_pin_map(obj, type); | |
| 415 | + i915_gem_object_unlock(obj); | |
| 416 | + | |
| 417 | + return ret; | |
| 402 | 418 | } |
| 403 | 419 | |
| 404 | 420 | void __i915_gem_object_flush_map(struct drm_i915_gem_object *obj, |
| @@ -448,7 +464,8 @@ struct scatterlist * · 43 unmodified lines | ||
| 448 | 464 | __i915_gem_object_get_sg(struct drm_i915_gem_object *obj, |
| 449 | 465 | struct i915_gem_object_page_iter *iter, |
| 450 | 466 | unsigned int n, |
| 451 | − unsigned int *offset) | |
| 467 | + unsigned int *offset, | |
| 468 | + bool allow_alloc) | |
| 452 | 469 | { |
| 453 | 470 | const bool dma = iter == &obj->mm.get_dma_page; |
| 454 | 471 | struct scatterlist *sg; |
| @@ -470,6 +487,9 @@ __i915_gem_object_get_sg(struct drm_i915_gem_object *obj, · 15 unmodified lines | ||
| 470 | 487 | if (n < READ_ONCE(iter->sg_idx)) |
| 471 | 488 | goto lookup; |
| 472 | 489 | |
| 490 | + if (!allow_alloc) | |
| 491 | + goto manual_lookup; | |
| 492 | + | |
| 473 | 493 | mutex_lock(&iter->lock); |
| 474 | 494 | |
| 475 | 495 | /* We prefer to reuse the last sg so that repeated lookup of this |
| @@ -519,7 +539,16 @@ scan: · 43 unmodified lines | ||
| 519 | 539 | if (unlikely(n < idx)) /* insertion completed by another thread */ |
| 520 | 540 | goto lookup; |
| 521 | 541 | |
| 522 | − /* In case we failed to insert the entry into the radixtree, we need | |
| 542 | + goto manual_walk; | |
| 543 | + | |
| 544 | +manual_lookup: | |
| 545 | + idx = 0; | |
| 546 | + sg = obj->mm.pages->sgl; | |
| 547 | + count = __sg_page_count(sg); | |
| 548 | + | |
| 549 | +manual_walk: | |
| 550 | + /* | |
| 551 | + * In case we failed to insert the entry into the radixtree, we need | |
| 523 | 552 | * to look beyond the current sg. |
| 524 | 553 | */ |
| 525 | 554 | while (idx + count <= n) { |
| @@ -566,7 +595,7 @@ i915_gem_object_get_page(struct drm_i915_gem_object *obj, unsigned int n) · 40 unmodified lines | ||
| 566 | 595 | |
| 567 | 596 | GEM_BUG_ON(!i915_gem_object_has_struct_page(obj)); |
| 568 | 597 | |
| 569 | − sg = i915_gem_object_get_sg(obj, n, &offset); | |
| 598 | + sg = i915_gem_object_get_sg(obj, n, &offset, true); | |
| 570 | 599 | return nth_page(sg_page(sg), offset); |
| 571 | 600 | } |
| 572 | 601 | |
| @@ -592,7 +621,7 @@ i915_gem_object_get_dma_address_len(struct drm_i915_gem_object *obj, · 19 unmodified lines | ||
| 592 | 621 | struct scatterlist *sg; |
| 593 | 622 | unsigned int offset; |
| 594 | 623 | |
| 595 | − sg = i915_gem_object_get_sg_dma(obj, n, &offset); | |
| 624 | + sg = i915_gem_object_get_sg_dma(obj, n, &offset, true); | |
| 596 | 625 | |
| 597 | 626 | if (len) |
| 598 | 627 | *len = sg_dma_len(sg) - (offset << PAGE_SHIFT); |
| @@ -76,6 +76,8 @@ static int i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) · 75 unmodified lines | ||
| 76 | 76 | |
| 77 | 77 | intel_gt_chipset_flush(&to_i915(obj->base.dev)->gt); |
| 78 | 78 | |
| 79 | + /* We're no longer struct page backed */ | |
| 80 | + obj->flags &= ~I915_BO_ALLOC_STRUCT_PAGE; | |
| 79 | 81 | __i915_gem_object_set_pages(obj, st, sg->length); |
| 80 | 82 | |
| 81 | 83 | return 0; |
| @@ -89,7 +91,7 @@ err_pci: · 7 unmodified lines | ||
| 89 | 91 | return -ENOMEM; |
| 90 | 92 | } |
| 91 | 93 | |
| 92 | −static void | |
| 94 | +void | |
| 93 | 95 | i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, |
| 94 | 96 | struct sg_table *pages) |
| 95 | 97 | { |
| @@ -134,9 +136,8 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, · 38 unmodified lines | ||
| 134 | 136 | vaddr, dma); |
| 135 | 137 | } |
| 136 | 138 | |
| 137 | −static int | |
| 138 | −phys_pwrite(struct drm_i915_gem_object *obj, | |
| 139 | − const struct drm_i915_gem_pwrite *args) | |
| 139 | +int i915_gem_object_pwrite_phys(struct drm_i915_gem_object *obj, | |
| 140 | + const struct drm_i915_gem_pwrite *args) | |
| 140 | 141 | { |
| 141 | 142 | void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset; |
| 142 | 143 | char __user *user_data = u64_to_user_ptr(args->data_ptr); |
| @@ -165,9 +166,8 @@ phys_pwrite(struct drm_i915_gem_object *obj, · 22 unmodified lines | ||
| 165 | 166 | return 0; |
| 166 | 167 | } |
| 167 | 168 | |
| 168 | −static int | |
| 169 | −phys_pread(struct drm_i915_gem_object *obj, | |
| 170 | − const struct drm_i915_gem_pread *args) | |
| 169 | +int i915_gem_object_pread_phys(struct drm_i915_gem_object *obj, | |
| 170 | + const struct drm_i915_gem_pread *args) | |
| 171 | 171 | { |
| 172 | 172 | void *vaddr = sg_page(obj->mm.pages->sgl) + args->offset; |
| 173 | 173 | char __user *user_data = u64_to_user_ptr(args->data_ptr); |
| @@ -186,62 +186,14 @@ phys_pread(struct drm_i915_gem_object *obj, · 12 unmodified lines | ||
| 186 | 186 | return 0; |
| 187 | 187 | } |
| 188 | 188 | |
| 189 | −static void phys_release(struct drm_i915_gem_object *obj) | |
| 190 | −{ | |
| 191 | − fput(obj->base.filp); | |
| 192 | −} | |
| 193 | − | |
| 194 | −static const struct drm_i915_gem_object_ops i915_gem_phys_ops = { | |
| 195 | − .name = "i915_gem_object_phys", | |
| 196 | − .get_pages = i915_gem_object_get_pages_phys, | |
| 197 | − .put_pages = i915_gem_object_put_pages_phys, | |
| 198 | − | |
| 199 | − .pread = phys_pread, | |
| 200 | − .pwrite = phys_pwrite, | |
| 201 | − | |
| 202 | − .release = phys_release, | |
| 203 | −}; | |
| 204 | − | |
| 205 | −int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) | |
| 189 | +static int i915_gem_object_shmem_to_phys(struct drm_i915_gem_object *obj) | |
| 206 | 190 | { |
| 207 | 191 | struct sg_table *pages; |
| 208 | 192 | int err; |
| 209 | 193 | |
| 210 | − if (align > obj->base.size) | |
| 211 | − return -EINVAL; | |
| 212 | − | |
| 213 | − if (obj->ops == &i915_gem_phys_ops) | |
| 214 | − return 0; | |
| 215 | − | |
| 216 | − if (!i915_gem_object_is_shmem(obj)) | |
| 217 | − return -EINVAL; | |
| 218 | − | |
| 219 | − err = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE); | |
| 220 | − if (err) | |
| 221 | − return err; | |
| 222 | − | |
| 223 | − mutex_lock_nested(&obj->mm.lock, I915_MM_GET_PAGES); | |
| 224 | − | |
| 225 | − if (obj->mm.madv != I915_MADV_WILLNEED) { | |
| 226 | − err = -EFAULT; | |
| 227 | − goto err_unlock; | |
| 228 | − } | |
| 229 | − | |
| 230 | − if (i915_gem_object_has_tiling_quirk(obj)) { | |
| 231 | − err = -EFAULT; | |
| 232 | − goto err_unlock; | |
| 233 | − } | |
| 234 | − | |
| 235 | − if (obj->mm.mapping) { | |
| 236 | − err = -EBUSY; | |
| 237 | − goto err_unlock; | |
| 238 | − } | |
| 239 | − | |
| 240 | 194 | pages = __i915_gem_object_unset_pages(obj); |
| 241 | 195 | |
| 242 | − obj->ops = &i915_gem_phys_ops; | |
| 243 | − | |
| 244 | − err = ____i915_gem_object_get_pages(obj); | |
| 196 | + err = i915_gem_object_get_pages_phys(obj); | |
| 245 | 197 | if (err) |
| 246 | 198 | goto err_xfer; |
| 247 | 199 | |
| @@ -249,25 +201,57 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) · 1 unmodified line | ||
| 249 | 201 | __i915_gem_object_pin_pages(obj); |
| 250 | 202 | |
| 251 | 203 | if (!IS_ERR_OR_NULL(pages)) |
| 252 | − i915_gem_shmem_ops.put_pages(obj, pages); | |
| 204 | + i915_gem_object_put_pages_shmem(obj, pages); | |
| 253 | 205 | |
| 254 | 206 | i915_gem_object_release_memory_region(obj); |
| 255 | − | |
| 256 | − mutex_unlock(&obj->mm.lock); | |
| 257 | 207 | return 0; |
| 258 | 208 | |
| 259 | 209 | err_xfer: |
| 260 | − obj->ops = &i915_gem_shmem_ops; | |
| 261 | 210 | if (!IS_ERR_OR_NULL(pages)) { |
| 262 | 211 | unsigned int sg_page_sizes = i915_sg_page_sizes(pages->sgl); |
| 263 | 212 | |
| 264 | 213 | __i915_gem_object_set_pages(obj, pages, sg_page_sizes); |
| 265 | 214 | } |
| 266 | −err_unlock: | |
| 267 | − mutex_unlock(&obj->mm.lock); | |
| 268 | 215 | return err; |
| 269 | 216 | } |
| 270 | 217 | |
| 218 | +int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) | |
| 219 | +{ | |
| 220 | + int err; | |
| 221 | + | |
| 222 | + assert_object_held(obj); | |
| 223 | + | |
| 224 | + if (align > obj->base.size) | |
| 225 | + return -EINVAL; | |
| 226 | + | |
| 227 | + if (!i915_gem_object_is_shmem(obj)) | |
| 228 | + return -EINVAL; | |
| 229 | + | |
| 230 | + if (!i915_gem_object_has_struct_page(obj)) | |
| 231 | + return 0; | |
| 232 | + | |
| 233 | + err = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE); | |
| 234 | + if (err) | |
| 235 | + return err; | |
| 236 | + | |
| 237 | + if (obj->mm.madv != I915_MADV_WILLNEED) | |
| 238 | + return -EFAULT; | |
| 239 | + | |
| 240 | + if (i915_gem_object_has_tiling_quirk(obj)) | |
| 241 | + return -EFAULT; | |
| 242 | + | |
| 243 | + if (obj->mm.mapping || i915_gem_object_has_pinned_pages(obj)) | |
| 244 | + return -EBUSY; | |
| 245 | + | |
| 246 | + if (unlikely(obj->mm.madv != I915_MADV_WILLNEED)) { | |
| 247 | + drm_dbg(obj->base.dev, | |
| 248 | + "Attempting to obtain a purgeable object\n"); | |
| 249 | + return -EFAULT; | |
| 250 | + } | |
| 251 | + | |
| 252 | + return i915_gem_object_shmem_to_phys(obj); | |
| 253 | +} | |
| 254 | + | |
| 271 | 255 | #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) |
| 272 | 256 | #include "selftests/i915_gem_phys.c" |
| 273 | 257 | #endif |
| @@ -116,7 +116,7 @@ int i915_gem_freeze_late(struct drm_i915_private *i915) · 115 unmodified lines | ||
| 116 | 116 | */ |
| 117 | 117 | |
| 118 | 118 | with_intel_runtime_pm(&i915->runtime_pm, wakeref) |
| 119 | − i915_gem_shrink(i915, -1UL, NULL, ~0); | |
| 119 | + i915_gem_shrink(NULL, i915, -1UL, NULL, ~0); | |
| 120 | 120 | i915_gem_drain_freed_objects(i915); |
| 121 | 121 | |
| 122 | 122 | wbinvd_on_all_cpus(); |
| @@ -106,13 +106,11 @@ err_free_sg: · 105 unmodified lines | ||
| 106 | 106 | } |
| 107 | 107 | |
| 108 | 108 | void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj, |
| 109 | − struct intel_memory_region *mem, | |
| 110 | − unsigned long flags) | |
| 109 | + struct intel_memory_region *mem) | |
| 111 | 110 | { |
| 112 | 111 | INIT_LIST_HEAD(&obj->mm.blocks); |
| 113 | 112 | obj->mm.region = intel_memory_region_get(mem); |
| 114 | 113 | |
| 115 | − obj->flags |= flags; | |
| 116 | 114 | if (obj->base.size <= mem->min_page_size) |
| 117 | 115 | obj->flags |= I915_BO_ALLOC_CONTIGUOUS; |
| 118 | 116 | |
| @@ -17,8 +17,7 @@ void i915_gem_object_put_pages_buddy(struct drm_i915_gem_object *obj, · 16 unmodified lines | ||
| 17 | 17 | struct sg_table *pages); |
| 18 | 18 | |
| 19 | 19 | void i915_gem_object_init_memory_region(struct drm_i915_gem_object *obj, |
| 20 | − struct intel_memory_region *mem, | |
| 21 | − unsigned long flags); | |
| 20 | + struct intel_memory_region *mem); | |
| 22 | 21 | void i915_gem_object_release_memory_region(struct drm_i915_gem_object *obj); |
| 23 | 22 | |
| 24 | 23 | struct drm_i915_gem_object * |
| @@ -99,7 +99,7 @@ rebuild_st: · 98 unmodified lines | ||
| 99 | 99 | goto err_sg; |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | − i915_gem_shrink(i915, 2 * page_count, NULL, *s++); | |
| 102 | + i915_gem_shrink(NULL, i915, 2 * page_count, NULL, *s++); | |
| 103 | 103 | |
| 104 | 104 | /* |
| 105 | 105 | * We've tried hard to allocate the memory by reaping |
| @@ -296,8 +296,7 @@ __i915_gem_object_release_shmem(struct drm_i915_gem_object *obj, · 190 unmodified lines | ||
| 296 | 296 | __start_cpu_write(obj); |
| 297 | 297 | } |
| 298 | 298 | |
| 299 | −static void | |
| 300 | −shmem_put_pages(struct drm_i915_gem_object *obj, struct sg_table *pages) | |
| 299 | +void i915_gem_object_put_pages_shmem(struct drm_i915_gem_object *obj, struct sg_table *pages) | |
| 301 | 300 | { |
| 302 | 301 | struct sgt_iter sgt_iter; |
| 303 | 302 | struct pagevec pvec; |
| @@ -331,6 +330,15 @@ shmem_put_pages(struct drm_i915_gem_object *obj, struct sg_table *pages) · 27 unmodified lines | ||
| 331 | 330 | kfree(pages); |
| 332 | 331 | } |
| 333 | 332 | |
| 333 | +static void | |
| 334 | +shmem_put_pages(struct drm_i915_gem_object *obj, struct sg_table *pages) | |
| 335 | +{ | |
| 336 | + if (likely(i915_gem_object_has_struct_page(obj))) | |
| 337 | + i915_gem_object_put_pages_shmem(obj, pages); | |
| 338 | + else | |
| 339 | + i915_gem_object_put_pages_phys(obj, pages); | |
| 340 | +} | |
| 341 | + | |
| 334 | 342 | static int |
| 335 | 343 | shmem_pwrite(struct drm_i915_gem_object *obj, |
| 336 | 344 | const struct drm_i915_gem_pwrite *arg) |
| @@ -343,6 +351,9 @@ shmem_pwrite(struct drm_i915_gem_object *obj, · 6 unmodified lines | ||
| 343 | 351 | /* Caller already validated user args */ |
| 344 | 352 | GEM_BUG_ON(!access_ok(user_data, arg->size)); |
| 345 | 353 | |
| 354 | + if (!i915_gem_object_has_struct_page(obj)) | |
| 355 | + return i915_gem_object_pwrite_phys(obj, arg); | |
| 356 | + | |
| 346 | 357 | /* |
| 347 | 358 | * Before we instantiate/pin the backing store for our use, we |
| 348 | 359 | * can prepopulate the shmemfs filp efficiently using a write into |
| @@ -421,17 +432,27 @@ shmem_pwrite(struct drm_i915_gem_object *obj, · 72 unmodified lines | ||
| 421 | 432 | return 0; |
| 422 | 433 | } |
| 423 | 434 | |
| 435 | +static int | |
| 436 | +shmem_pread(struct drm_i915_gem_object *obj, | |
| 437 | + const struct drm_i915_gem_pread *arg) | |
| 438 | +{ | |
| 439 | + if (!i915_gem_object_has_struct_page(obj)) | |
| 440 | + return i915_gem_object_pread_phys(obj, arg); | |
| 441 | + | |
| 442 | + return -ENODEV; | |
| 443 | +} | |
| 444 | + | |
| 424 | 445 | static void shmem_release(struct drm_i915_gem_object *obj) |
| 425 | 446 | { |
| 426 | − i915_gem_object_release_memory_region(obj); | |
| 447 | + if (obj->flags & I915_BO_ALLOC_STRUCT_PAGE) | |
| 448 | + i915_gem_object_release_memory_region(obj); | |
| 427 | 449 | |
| 428 | 450 | fput(obj->base.filp); |
| 429 | 451 | } |
| 430 | 452 | |
| 431 | 453 | const struct drm_i915_gem_object_ops i915_gem_shmem_ops = { |
| 432 | 454 | .name = "i915_gem_object_shmem", |
| 433 | − .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE | | |
| 434 | − I915_GEM_OBJECT_IS_SHRINKABLE, | |
| 455 | + .flags = I915_GEM_OBJECT_IS_SHRINKABLE, | |
| 435 | 456 | |
| 436 | 457 | .get_pages = shmem_get_pages, |
| 437 | 458 | .put_pages = shmem_put_pages, |
| @@ -439,6 +460,7 @@ const struct drm_i915_gem_object_ops i915_gem_shmem_ops = { · 1 unmodified line | ||
| 439 | 460 | .writeback = shmem_writeback, |
| 440 | 461 | |
| 441 | 462 | .pwrite = shmem_pwrite, |
| 463 | + .pread = shmem_pread, | |
| 442 | 464 | |
| 443 | 465 | .release = shmem_release, |
| 444 | 466 | }; |
| @@ -491,7 +513,8 @@ static int shmem_object_init(struct intel_memory_region *mem, · 46 unmodified lines | ||
| 491 | 513 | mapping_set_gfp_mask(mapping, mask); |
| 492 | 514 | GEM_BUG_ON(!(mapping_gfp_mask(mapping) & __GFP_RECLAIM)); |
| 493 | 515 | |
| 494 | − i915_gem_object_init(obj, &i915_gem_shmem_ops, &lock_class); | |
| 516 | + i915_gem_object_init(obj, &i915_gem_shmem_ops, &lock_class, | |
| 517 | + I915_BO_ALLOC_STRUCT_PAGE); | |
| 495 | 518 | |
| 496 | 519 | obj->write_domain = I915_GEM_DOMAIN_CPU; |
| 497 | 520 | obj->read_domains = I915_GEM_DOMAIN_CPU; |
| @@ -515,7 +538,7 @@ static int shmem_object_init(struct intel_memory_region *mem, · 17 unmodified lines | ||
| 515 | 538 | |
| 516 | 539 | i915_gem_object_set_cache_coherency(obj, cache_level); |
| 517 | 540 | |
| 518 | − i915_gem_object_init_memory_region(obj, mem, 0); | |
| 541 | + i915_gem_object_init_memory_region(obj, mem); | |
| 519 | 542 | |
| 520 | 543 | return 0; |
| 521 | 544 | } |
| @@ -49,9 +49,9 @@ static bool unsafe_drop_pages(struct drm_i915_gem_object *obj, · 48 unmodified lines | ||
| 49 | 49 | flags = I915_GEM_OBJECT_UNBIND_TEST; |
| 50 | 50 | |
| 51 | 51 | if (i915_gem_object_unbind(obj, flags) == 0) |
| 52 | − __i915_gem_object_put_pages(obj); | |
| 52 | + return true; | |
| 53 | 53 | |
| 54 | − return !i915_gem_object_has_pages(obj); | |
| 54 | + return false; | |
| 55 | 55 | } |
| 56 | 56 | |
| 57 | 57 | static void try_to_writeback(struct drm_i915_gem_object *obj, |
| @@ -94,7 +94,8 @@ static void try_to_writeback(struct drm_i915_gem_object *obj, · 36 unmodified lines | ||
| 94 | 94 | * The number of pages of backing storage actually released. |
| 95 | 95 | */ |
| 96 | 96 | unsigned long |
| 97 | −i915_gem_shrink(struct drm_i915_private *i915, | |
| 97 | +i915_gem_shrink(struct i915_gem_ww_ctx *ww, | |
| 98 | + struct drm_i915_private *i915, | |
| 98 | 99 | unsigned long target, |
| 99 | 100 | unsigned long *nr_scanned, |
| 100 | 101 | unsigned int shrink) |
| @@ -113,6 +114,7 @@ i915_gem_shrink(struct drm_i915_private *i915, · 12 unmodified lines | ||
| 113 | 114 | intel_wakeref_t wakeref = 0; |
| 114 | 115 | unsigned long count = 0; |
| 115 | 116 | unsigned long scanned = 0; |
| 117 | + int err; | |
| 116 | 118 | |
| 117 | 119 | trace_i915_gem_shrink(i915, target, shrink); |
| 118 | 120 | |
| @@ -200,25 +202,40 @@ i915_gem_shrink(struct drm_i915_private *i915, · 81 unmodified lines | ||
| 200 | 202 | |
| 201 | 203 | spin_unlock_irqrestore(&i915->mm.obj_lock, flags); |
| 202 | 204 | |
| 205 | + err = 0; | |
| 203 | 206 | if (unsafe_drop_pages(obj, shrink)) { |
| 204 | 207 | /* May arrive from get_pages on another bo */ |
| 205 | − mutex_lock(&obj->mm.lock); | |
| 206 | − if (!i915_gem_object_has_pages(obj)) { | |
| 208 | + if (!ww) { | |
| 209 | + if (!i915_gem_object_trylock(obj)) | |
| 210 | + goto skip; | |
| 211 | + } else { | |
| 212 | + err = i915_gem_object_lock(obj, ww); | |
| 213 | + if (err) | |
| 214 | + goto skip; | |
| 215 | + } | |
| 216 | + | |
| 217 | + if (!__i915_gem_object_put_pages(obj)) { | |
| 207 | 218 | try_to_writeback(obj, shrink); |
| 208 | 219 | count += obj->base.size >> PAGE_SHIFT; |
| 209 | 220 | } |
| 210 | − mutex_unlock(&obj->mm.lock); | |
| 221 | + if (!ww) | |
| 222 | + i915_gem_object_unlock(obj); | |
| 211 | 223 | } |
| 212 | 224 | |
| 213 | 225 | dma_resv_prune(obj->base.resv); |
| 214 | 226 | |
| 215 | 227 | scanned += obj->base.size >> PAGE_SHIFT; |
| 228 | +skip: | |
| 216 | 229 | i915_gem_object_put(obj); |
| 217 | 230 | |
| 218 | 231 | spin_lock_irqsave(&i915->mm.obj_lock, flags); |
| 232 | + if (err) | |
| 233 | + break; | |
| 219 | 234 | } |
| 220 | 235 | list_splice_tail(&still_in_list, phase->list); |
| 221 | 236 | spin_unlock_irqrestore(&i915->mm.obj_lock, flags); |
| 237 | + if (err) | |
| 238 | + return err; | |
| 222 | 239 | } |
| 223 | 240 | |
| 224 | 241 | if (shrink & I915_SHRINK_BOUND) |
| @@ -249,7 +266,7 @@ unsigned long i915_gem_shrink_all(struct drm_i915_private *i915) · 24 unmodified lines | ||
| 249 | 266 | unsigned long freed = 0; |
| 250 | 267 | |
| 251 | 268 | with_intel_runtime_pm(&i915->runtime_pm, wakeref) { |
| 252 | − freed = i915_gem_shrink(i915, -1UL, NULL, | |
| 269 | + freed = i915_gem_shrink(NULL, i915, -1UL, NULL, | |
| 253 | 270 | I915_SHRINK_BOUND | |
| 254 | 271 | I915_SHRINK_UNBOUND); |
| 255 | 272 | } |
| @@ -295,7 +312,7 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) · 39 unmodified lines | ||
| 295 | 312 | |
| 296 | 313 | sc->nr_scanned = 0; |
| 297 | 314 | |
| 298 | − freed = i915_gem_shrink(i915, | |
| 315 | + freed = i915_gem_shrink(NULL, i915, | |
| 299 | 316 | sc->nr_to_scan, |
| 300 | 317 | &sc->nr_scanned, |
| 301 | 318 | I915_SHRINK_BOUND | |
| @@ -304,7 +321,7 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) · 2 unmodified lines | ||
| 304 | 321 | intel_wakeref_t wakeref; |
| 305 | 322 | |
| 306 | 323 | with_intel_runtime_pm(&i915->runtime_pm, wakeref) { |
| 307 | − freed += i915_gem_shrink(i915, | |
| 324 | + freed += i915_gem_shrink(NULL, i915, | |
| 308 | 325 | sc->nr_to_scan - sc->nr_scanned, |
| 309 | 326 | &sc->nr_scanned, |
| 310 | 327 | I915_SHRINK_ACTIVE | |
| @@ -329,7 +346,7 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr) · 18 unmodified lines | ||
| 329 | 346 | |
| 330 | 347 | freed_pages = 0; |
| 331 | 348 | with_intel_runtime_pm(&i915->runtime_pm, wakeref) |
| 332 | − freed_pages += i915_gem_shrink(i915, -1UL, NULL, | |
| 349 | + freed_pages += i915_gem_shrink(NULL, i915, -1UL, NULL, | |
| 333 | 350 | I915_SHRINK_BOUND | |
| 334 | 351 | I915_SHRINK_UNBOUND | |
| 335 | 352 | I915_SHRINK_WRITEBACK); |
| @@ -367,7 +384,7 @@ i915_gem_shrinker_vmap(struct notifier_block *nb, unsigned long event, void *ptr · 31 unmodified lines | ||
| 367 | 384 | intel_wakeref_t wakeref; |
| 368 | 385 | |
| 369 | 386 | with_intel_runtime_pm(&i915->runtime_pm, wakeref) |
| 370 | − freed_pages += i915_gem_shrink(i915, -1UL, NULL, | |
| 387 | + freed_pages += i915_gem_shrink(NULL, i915, -1UL, NULL, | |
| 371 | 388 | I915_SHRINK_BOUND | |
| 372 | 389 | I915_SHRINK_UNBOUND | |
| 373 | 390 | I915_SHRINK_VMAPS); |
| @@ -9,10 +9,12 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/bits.h> |
| 10 | 10 | |
| 11 | 11 | struct drm_i915_private; |
| 12 | +struct i915_gem_ww_ctx; | |
| 12 | 13 | struct mutex; |
| 13 | 14 | |
| 14 | 15 | /* i915_gem_shrinker.c */ |
| 15 | −unsigned long i915_gem_shrink(struct drm_i915_private *i915, | |
| 16 | +unsigned long i915_gem_shrink(struct i915_gem_ww_ctx *ww, | |
| 17 | + struct drm_i915_private *i915, | |
| 16 | 18 | unsigned long target, |
| 17 | 19 | unsigned long *nr_scanned, |
| 18 | 20 | unsigned flags); |
| @@ -630,20 +630,22 @@ static int __i915_gem_object_create_stolen(struct intel_memory_region *mem, · 629 unmodified lines | ||
| 630 | 630 | int err; |
| 631 | 631 | |
| 632 | 632 | drm_gem_private_object_init(&mem->i915->drm, &obj->base, stolen->size); |
| 633 | − i915_gem_object_init(obj, &i915_gem_object_stolen_ops, &lock_class); | |
| 633 | + i915_gem_object_init(obj, &i915_gem_object_stolen_ops, &lock_class, 0); | |
| 634 | 634 | |
| 635 | 635 | obj->stolen = stolen; |
| 636 | 636 | obj->read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT; |
| 637 | 637 | cache_level = HAS_LLC(mem->i915) ? I915_CACHE_LLC : I915_CACHE_NONE; |
| 638 | 638 | i915_gem_object_set_cache_coherency(obj, cache_level); |
| 639 | 639 | |
| 640 | − err = i915_gem_object_pin_pages(obj); | |
| 641 | − if (err) | |
| 642 | − return err; | |
| 640 | + if (WARN_ON(!i915_gem_object_trylock(obj))) | |
| 641 | + return -EBUSY; | |
| 643 | 642 | |
| 644 | − i915_gem_object_init_memory_region(obj, mem, 0); | |
| 643 | + err = i915_gem_object_pin_pages(obj); | |
| 644 | + if (!err) | |
| 645 | + i915_gem_object_init_memory_region(obj, mem); | |
| 646 | + i915_gem_object_unlock(obj); | |
| 645 | 647 | |
| 646 | − return 0; | |
| 648 | + return err; | |
| 647 | 649 | } |
| 648 | 650 | |
| 649 | 651 | static int _i915_gem_object_stolen_init(struct intel_memory_region *mem, |
| @@ -265,7 +265,6 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, · 264 unmodified lines | ||
| 265 | 265 | * pages to prevent them being swapped out and causing corruption |
| 266 | 266 | * due to the change in swizzling. |
| 267 | 267 | */ |
| 268 | − mutex_lock(&obj->mm.lock); | |
| 269 | 268 | if (i915_gem_object_has_pages(obj) && |
| 270 | 269 | obj->mm.madv == I915_MADV_WILLNEED && |
| 271 | 270 | i915->quirks & QUIRK_PIN_SWIZZLED_PAGES) { |
| @@ -280,7 +279,6 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj, · 8 unmodified lines | ||
| 280 | 279 | i915_gem_object_set_tiling_quirk(obj); |
| 281 | 280 | } |
| 282 | 281 | } |
| 283 | − mutex_unlock(&obj->mm.lock); | |
| 284 | 282 | |
| 285 | 283 | spin_lock(&obj->vma.lock); |
| 286 | 284 | for_each_ggtt_vma(vma, obj) { |
| @@ -2,10 +2,39 @@ · 1 unmodified line | ||
| 2 | 2 | * SPDX-License-Identifier: MIT |
| 3 | 3 | * |
| 4 | 4 | * Copyright © 2012-2014 Intel Corporation |
| 5 | + * | |
| 6 | + * Based on amdgpu_mn, which bears the following notice: | |
| 7 | + * | |
| 8 | + * Copyright 2014 Advanced Micro Devices, Inc. | |
| 9 | + * All Rights Reserved. | |
| 10 | + * | |
| 11 | + * Permission is hereby granted, free of charge, to any person obtaining a | |
| 12 | + * copy of this software and associated documentation files (the | |
| 13 | + * "Software"), to deal in the Software without restriction, including | |
| 14 | + * without limitation the rights to use, copy, modify, merge, publish, | |
| 15 | + * distribute, sub license, and/or sell copies of the Software, and to | |
| 16 | + * permit persons to whom the Software is furnished to do so, subject to | |
| 17 | + * the following conditions: | |
| 18 | + * | |
| 19 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 20 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 21 | + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL | |
| 22 | + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, | |
| 23 | + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
| 24 | + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |
| 25 | + * USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| 26 | + * | |
| 27 | + * The above copyright notice and this permission notice (including the | |
| 28 | + * next paragraph) shall be included in all copies or substantial portions | |
| 29 | + * of the Software. | |
| 30 | + * | |
| 31 | + */ | |
| 32 | +/* | |
| 33 | + * Authors: | |
| 34 | + * Christian König <christian.koenig@amd.com> | |
| 5 | 35 | */ |
| 6 | 36 | |
| 7 | 37 | #include <linux/mmu_context.h> |
| 8 | −#include <linux/mmu_notifier.h> | |
| 9 | 38 | #include <linux/mempolicy.h> |
| 10 | 39 | #include <linux/swap.h> |
| 11 | 40 | #include <linux/sched/mm.h> |
| @@ -15,408 +44,121 @@ · 3 unmodified lines | ||
| 15 | 44 | #include "i915_gem_object.h" |
| 16 | 45 | #include "i915_scatterlist.h" |
| 17 | 46 | |
| 18 | −struct i915_mm_struct { | |
| 19 | − struct mm_struct *mm; | |
| 20 | − struct drm_i915_private *i915; | |
| 21 | − struct i915_mmu_notifier *mn; | |
| 22 | − struct hlist_node node; | |
| 23 | − struct kref kref; | |
| 24 | − struct rcu_work work; | |
| 25 | −}; | |
| 26 | − | |
| 27 | −#if defined(CONFIG_MMU_NOTIFIER) | |
| 28 | −#include <linux/interval_tree.h> | |
| 47 | +#ifdef CONFIG_MMU_NOTIFIER | |
| 29 | 48 | |
| 30 | −struct i915_mmu_notifier { | |
| 31 | − spinlock_t lock; | |
| 32 | − struct hlist_node node; | |
| 33 | − struct mmu_notifier mn; | |
| 34 | − struct rb_root_cached objects; | |
| 35 | − struct i915_mm_struct *mm; | |
| 36 | −}; | |
| 37 | − | |
| 38 | −struct i915_mmu_object { | |
| 39 | − struct i915_mmu_notifier *mn; | |
| 40 | − struct drm_i915_gem_object *obj; | |
| 41 | − struct interval_tree_node it; | |
| 42 | −}; | |
| 43 | − | |
| 44 | −static void add_object(struct i915_mmu_object *mo) | |
| 49 | +/** | |
| 50 | + * i915_gem_userptr_invalidate - callback to notify about mm change | |
| 51 | + * | |
| 52 | + * @mni: the range (mm) is about to update | |
| 53 | + * @range: details on the invalidation | |
| 54 | + * @cur_seq: Value to pass to mmu_interval_set_seq() | |
| 55 | + * | |
| 56 | + * Block for operations on BOs to finish and mark pages as accessed and | |
| 57 | + * potentially dirty. | |
| 58 | + */ | |
| 59 | +static bool i915_gem_userptr_invalidate(struct mmu_interval_notifier *mni, | |
| 60 | + const struct mmu_notifier_range *range, | |
| 61 | + unsigned long cur_seq) | |
| 45 | 62 | { |
| 46 | − GEM_BUG_ON(!RB_EMPTY_NODE(&mo->it.rb)); | |
| 47 | − interval_tree_insert(&mo->it, &mo->mn->objects); | |
| 48 | −} | |
| 63 | + struct drm_i915_gem_object *obj = container_of(mni, struct drm_i915_gem_object, userptr.notifier); | |
| 64 | + struct drm_i915_private *i915 = to_i915(obj->base.dev); | |
| 65 | + long r; | |
| 49 | 66 | |
| 50 | −static void del_object(struct i915_mmu_object *mo) | |
| 51 | −{ | |
| 52 | − if (RB_EMPTY_NODE(&mo->it.rb)) | |
| 53 | − return; | |
| 67 | + if (!mmu_notifier_range_blockable(range)) | |
| 68 | + return false; | |
| 54 | 69 | |
| 55 | − interval_tree_remove(&mo->it, &mo->mn->objects); | |
| 56 | − RB_CLEAR_NODE(&mo->it.rb); | |
| 57 | −} | |
| 70 | + spin_lock(&i915->mm.notifier_lock); | |
| 58 | 71 | |
| 59 | −static void | |
| 60 | −__i915_gem_userptr_set_active(struct drm_i915_gem_object *obj, bool value) | |
| 61 | −{ | |
| 62 | − struct i915_mmu_object *mo = obj->userptr.mmu_object; | |
| 72 | + mmu_interval_set_seq(mni, cur_seq); | |
| 73 | + | |
| 74 | + spin_unlock(&i915->mm.notifier_lock); | |
| 63 | 75 | |
| 64 | 76 | /* |
| 65 | − * During mm_invalidate_range we need to cancel any userptr that | |
| 66 | − * overlaps the range being invalidated. Doing so requires the | |
| 67 | − * struct_mutex, and that risks recursion. In order to cause | |
| 68 | − * recursion, the user must alias the userptr address space with | |
| 69 | − * a GTT mmapping (possible with a MAP_FIXED) - then when we have | |
| 70 | − * to invalidate that mmaping, mm_invalidate_range is called with | |
| 71 | − * the userptr address *and* the struct_mutex held. To prevent that | |
| 72 | − * we set a flag under the i915_mmu_notifier spinlock to indicate | |
| 73 | − * whether this object is valid. | |
| 77 | + * We don't wait when the process is exiting. This is valid | |
| 78 | + * because the object will be cleaned up anyway. | |
| 79 | + * | |
| 80 | + * This is also temporarily required as a hack, because we | |
| 81 | + * cannot currently force non-consistent batch buffers to preempt | |
| 82 | + * and reschedule by waiting on it, hanging processes on exit. | |
| 74 | 83 | */ |
| 75 | − if (!mo) | |
| 76 | − return; | |
| 84 | + if (current->flags & PF_EXITING) | |
| 85 | + return true; | |
| 77 | 86 | |
| 78 | − spin_lock(&mo->mn->lock); | |
| 79 | − if (value) | |
| 80 | − add_object(mo); | |
| 81 | − else | |
| 82 | − del_object(mo); | |
| 83 | − spin_unlock(&mo->mn->lock); | |
| 84 | −} | |
| 85 | − | |
| 86 | −static int | |
| 87 | −userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, | |
| 88 | − const struct mmu_notifier_range *range) | |
| 89 | −{ | |
| 90 | − struct i915_mmu_notifier *mn = | |
| 91 | − container_of(_mn, struct i915_mmu_notifier, mn); | |
| 92 | − struct interval_tree_node *it; | |
| 93 | − unsigned long end; | |
| 94 | − int ret = 0; | |
| 95 | − | |
| 96 | − if (RB_EMPTY_ROOT(&mn->objects.rb_root)) | |
| 97 | − return 0; | |
| 98 | − | |
| 99 | − /* interval ranges are inclusive, but invalidate range is exclusive */ | |
| 100 | − end = range->end - 1; | |
| 101 | − | |
| 102 | − spin_lock(&mn->lock); | |
| 103 | − it = interval_tree_iter_first(&mn->objects, range->start, end); | |
| 104 | − while (it) { | |
| 105 | − struct drm_i915_gem_object *obj; | |
| 106 | − | |
| 107 | − if (!mmu_notifier_range_blockable(range)) { | |
| 108 | − ret = -EAGAIN; | |
| 109 | − break; | |
| 110 | − } | |
| 111 | − | |
| 112 | − /* | |
| 113 | − * The mmu_object is released late when destroying the | |
| 114 | − * GEM object so it is entirely possible to gain a | |
| 115 | − * reference on an object in the process of being freed | |
| 116 | − * since our serialisation is via the spinlock and not | |
| 117 | − * the struct_mutex - and consequently use it after it | |
| 118 | − * is freed and then double free it. To prevent that | |
| 119 | − * use-after-free we only acquire a reference on the | |
| 120 | − * object if it is not in the process of being destroyed. | |
| 121 | − */ | |
| 122 | − obj = container_of(it, struct i915_mmu_object, it)->obj; | |
| 123 | − if (!kref_get_unless_zero(&obj->base.refcount)) { | |
| 124 | − it = interval_tree_iter_next(it, range->start, end); | |
| 125 | − continue; | |
| 126 | − } | |
| 127 | − spin_unlock(&mn->lock); | |
| 128 | − | |
| 129 | − ret = i915_gem_object_unbind(obj, | |
| 130 | − I915_GEM_OBJECT_UNBIND_ACTIVE | | |
| 131 | − I915_GEM_OBJECT_UNBIND_BARRIER); | |
| 132 | − if (ret == 0) | |
| 133 | − ret = __i915_gem_object_put_pages(obj); | |
| 134 | − i915_gem_object_put(obj); | |
| 135 | − if (ret) | |
| 136 | − return ret; | |
| 137 | − | |
| 138 | − spin_lock(&mn->lock); | |
| 139 | − | |
| 140 | − /* | |
| 141 | − * As we do not (yet) protect the mmu from concurrent insertion | |
| 142 | − * over this range, there is no guarantee that this search will | |
| 143 | − * terminate given a pathologic workload. | |
| 144 | − */ | |
| 145 | − it = interval_tree_iter_first(&mn->objects, range->start, end); | |
| 146 | − } | |
| 147 | − spin_unlock(&mn->lock); | |
| 148 | − | |
| 149 | − return ret; | |
| 87 | + /* we will unbind on next submission, still have userptr pins */ | |
| 88 | + r = dma_resv_wait_timeout_rcu(obj->base.resv, true, false, | |
| 89 | + MAX_SCHEDULE_TIMEOUT); | |
| 90 | + if (r <= 0) | |
| 91 | + drm_err(&i915->drm, "(%ld) failed to wait for idle\n", r); | |
| 150 | 92 | |
| 93 | + return true; | |
| 151 | 94 | } |
| 152 | 95 | |
| 153 | −static const struct mmu_notifier_ops i915_gem_userptr_notifier = { | |
| 154 | − .invalidate_range_start = userptr_mn_invalidate_range_start, | |
| 96 | +static const struct mmu_interval_notifier_ops i915_gem_userptr_notifier_ops = { | |
| 97 | + .invalidate = i915_gem_userptr_invalidate, | |
| 155 | 98 | }; |
| 156 | 99 | |
| 157 | −static struct i915_mmu_notifier * | |
| 158 | −i915_mmu_notifier_create(struct i915_mm_struct *mm) | |
| 159 | −{ | |
| 160 | − struct i915_mmu_notifier *mn; | |
| 161 | − | |
| 162 | − mn = kmalloc(sizeof(*mn), GFP_KERNEL); | |
| 163 | − if (mn == NULL) | |
| 164 | − return ERR_PTR(-ENOMEM); | |
| 165 | − | |
| 166 | − spin_lock_init(&mn->lock); | |
| 167 | − mn->mn.ops = &i915_gem_userptr_notifier; | |
| 168 | − mn->objects = RB_ROOT_CACHED; | |
| 169 | − mn->mm = mm; | |
| 170 | − | |
| 171 | − return mn; | |
| 172 | −} | |
| 173 | − | |
| 174 | −static void | |
| 175 | −i915_gem_userptr_release__mmu_notifier(struct drm_i915_gem_object *obj) | |
| 176 | −{ | |
| 177 | − struct i915_mmu_object *mo; | |
| 178 | − | |
| 179 | − mo = fetch_and_zero(&obj->userptr.mmu_object); | |
| 180 | − if (!mo) | |
| 181 | − return; | |
| 182 | − | |
| 183 | − spin_lock(&mo->mn->lock); | |
| 184 | − del_object(mo); | |
| 185 | − spin_unlock(&mo->mn->lock); | |
| 186 | − kfree(mo); | |
| 187 | −} | |
| 188 | − | |
| 189 | −static struct i915_mmu_notifier * | |
| 190 | −i915_mmu_notifier_find(struct i915_mm_struct *mm) | |
| 191 | −{ | |
| 192 | − struct i915_mmu_notifier *mn, *old; | |
| 193 | − int err; | |
| 194 | − | |
| 195 | − mn = READ_ONCE(mm->mn); | |
| 196 | − if (likely(mn)) | |
| 197 | − return mn; | |
| 198 | − | |
| 199 | − mn = i915_mmu_notifier_create(mm); | |
| 200 | − if (IS_ERR(mn)) | |
| 201 | − return mn; | |
| 202 | − | |
| 203 | − err = mmu_notifier_register(&mn->mn, mm->mm); | |
| 204 | − if (err) { | |
| 205 | − kfree(mn); | |
| 206 | − return ERR_PTR(err); | |
| 207 | − } | |
| 208 | − | |
| 209 | − old = cmpxchg(&mm->mn, NULL, mn); | |
| 210 | − if (old) { | |
| 211 | − mmu_notifier_unregister(&mn->mn, mm->mm); | |
| 212 | − kfree(mn); | |
| 213 | − mn = old; | |
| 214 | − } | |
| 215 | − | |
| 216 | − return mn; | |
| 217 | −} | |
| 218 | − | |
| 219 | −static int | |
| 220 | −i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, | |
| 221 | − unsigned flags) | |
| 222 | −{ | |
| 223 | − struct i915_mmu_notifier *mn; | |
| 224 | − struct i915_mmu_object *mo; | |
| 225 | − | |
| 226 | − if (flags & I915_USERPTR_UNSYNCHRONIZED) | |
| 227 | − return capable(CAP_SYS_ADMIN) ? 0 : -EPERM; | |
| 228 | − | |
| 229 | − if (GEM_WARN_ON(!obj->userptr.mm)) | |
| 230 | − return -EINVAL; | |
| 231 | − | |
| 232 | − mn = i915_mmu_notifier_find(obj->userptr.mm); | |
| 233 | − if (IS_ERR(mn)) | |
| 234 | − return PTR_ERR(mn); | |
| 235 | − | |
| 236 | − mo = kzalloc(sizeof(*mo), GFP_KERNEL); | |
| 237 | − if (!mo) | |
| 238 | − return -ENOMEM; | |
| 239 | − | |
| 240 | − mo->mn = mn; | |
| 241 | − mo->obj = obj; | |
| 242 | − mo->it.start = obj->userptr.ptr; | |
| 243 | − mo->it.last = obj->userptr.ptr + obj->base.size - 1; | |
| 244 | − RB_CLEAR_NODE(&mo->it.rb); | |
| 245 | − | |
| 246 | − obj->userptr.mmu_object = mo; | |
| 247 | − return 0; | |
| 248 | −} | |
| 249 | − | |
| 250 | −static void | |
| 251 | −i915_mmu_notifier_free(struct i915_mmu_notifier *mn, | |
| 252 | − struct mm_struct *mm) | |
| 253 | −{ | |
| 254 | − if (mn == NULL) | |
| 255 | − return; | |
| 256 | − | |
| 257 | − mmu_notifier_unregister(&mn->mn, mm); | |
| 258 | − kfree(mn); | |
| 259 | −} | |
| 260 | − | |
| 261 | −#else | |
| 262 | − | |
| 263 | −static void | |
| 264 | −__i915_gem_userptr_set_active(struct drm_i915_gem_object *obj, bool value) | |
| 265 | −{ | |
| 266 | −} | |
| 267 | − | |
| 268 | −static void | |
| 269 | −i915_gem_userptr_release__mmu_notifier(struct drm_i915_gem_object *obj) | |
| 270 | −{ | |
| 271 | −} | |
| 272 | − | |
| 273 | 100 | static int |
| 274 | −i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj, | |
| 275 | − unsigned flags) | |
| 101 | +i915_gem_userptr_init__mmu_notifier(struct drm_i915_gem_object *obj) | |
| 276 | 102 | { |
| 277 | − if ((flags & I915_USERPTR_UNSYNCHRONIZED) == 0) | |
| 278 | − return -ENODEV; | |
| 279 | − | |
| 280 | − if (!capable(CAP_SYS_ADMIN)) | |
| 281 | − return -EPERM; | |
| 282 | − | |
| 283 | − return 0; | |
| 103 | + return mmu_interval_notifier_insert(&obj->userptr.notifier, current->mm, | |
| 104 | + obj->userptr.ptr, obj->base.size, | |
| 105 | + &i915_gem_userptr_notifier_ops); | |
| 284 | 106 | } |
| 285 | 107 | |
| 286 | −static void | |
| 287 | −i915_mmu_notifier_free(struct i915_mmu_notifier *mn, | |
| 288 | − struct mm_struct *mm) | |
| 289 | −{ | |
| 290 | −} | |
| 291 | − | |
| 292 | −#endif | |
| 293 | − | |
| 294 | −static struct i915_mm_struct * | |
| 295 | −__i915_mm_struct_find(struct drm_i915_private *i915, struct mm_struct *real) | |
| 296 | −{ | |
| 297 | − struct i915_mm_struct *it, *mm = NULL; | |
| 298 | − | |
| 299 | − rcu_read_lock(); | |
| 300 | − hash_for_each_possible_rcu(i915->mm_structs, | |
| 301 | − it, node, | |
| 302 | − (unsigned long)real) | |
| 303 | − if (it->mm == real && kref_get_unless_zero(&it->kref)) { | |
| 304 | − mm = it; | |
| 305 | − break; | |
| 306 | − } | |
| 307 | − rcu_read_unlock(); | |
| 308 | − | |
| 309 | − return mm; | |
| 310 | −} | |
| 311 | − | |
| 312 | −static int | |
| 313 | −i915_gem_userptr_init__mm_struct(struct drm_i915_gem_object *obj) | |
| 108 | +static void i915_gem_object_userptr_drop_ref(struct drm_i915_gem_object *obj) | |
| 314 | 109 | { |
| 315 | 110 | struct drm_i915_private *i915 = to_i915(obj->base.dev); |
| 316 | − struct i915_mm_struct *mm, *new; | |
| 317 | − int ret = 0; | |
| 318 | − | |
| 319 | − /* During release of the GEM object we hold the struct_mutex. This | |
| 320 | − * precludes us from calling mmput() at that time as that may be | |
| 321 | − * the last reference and so call exit_mmap(). exit_mmap() will | |
| 322 | − * attempt to reap the vma, and if we were holding a GTT mmap | |
| 323 | − * would then call drm_gem_vm_close() and attempt to reacquire | |
| 324 | − * the struct mutex. So in order to avoid that recursion, we have | |
| 325 | − * to defer releasing the mm reference until after we drop the | |
| 326 | − * struct_mutex, i.e. we need to schedule a worker to do the clean | |
| 327 | − * up. | |
| 328 | − */ | |
| 329 | − mm = __i915_mm_struct_find(i915, current->mm); | |
| 330 | − if (mm) | |
| 331 | − goto out; | |
| 332 | − | |
| 333 | − new = kmalloc(sizeof(*mm), GFP_KERNEL); | |
| 334 | − if (!new) | |
| 335 | − return -ENOMEM; | |
| 111 | + struct page **pvec = NULL; | |
| 336 | 112 | |
| 337 | − kref_init(&new->kref); | |
| 338 | − new->i915 = to_i915(obj->base.dev); | |
| 339 | − new->mm = current->mm; | |
| 340 | − new->mn = NULL; | |
| 341 | − | |
| 342 | − spin_lock(&i915->mm_lock); | |
| 343 | − mm = __i915_mm_struct_find(i915, current->mm); | |
| 344 | − if (!mm) { | |
| 345 | − hash_add_rcu(i915->mm_structs, | |
| 346 | − &new->node, | |
| 347 | − (unsigned long)new->mm); | |
| 348 | − mmgrab(current->mm); | |
| 349 | − mm = new; | |
| 113 | + spin_lock(&i915->mm.notifier_lock); | |
| 114 | + if (!--obj->userptr.page_ref) { | |
| 115 | + pvec = obj->userptr.pvec; | |
| 116 | + obj->userptr.pvec = NULL; | |
| 350 | 117 | } |
| 351 | − spin_unlock(&i915->mm_lock); | |
| 352 | − if (mm != new) | |
| 353 | − kfree(new); | |
| 118 | + GEM_BUG_ON(obj->userptr.page_ref < 0); | |
| 119 | + spin_unlock(&i915->mm.notifier_lock); | |
| 354 | 120 | |
| 355 | −out: | |
| 356 | − obj->userptr.mm = mm; | |
| 357 | − return ret; | |
| 358 | −} | |
| 359 | − | |
| 360 | −static void | |
| 361 | −__i915_mm_struct_free__worker(struct work_struct *work) | |
| 362 | −{ | |
| 363 | − struct i915_mm_struct *mm = container_of(work, typeof(*mm), work.work); | |
| 364 | − | |
| 365 | − i915_mmu_notifier_free(mm->mn, mm->mm); | |
| 366 | − mmdrop(mm->mm); | |
| 367 | − kfree(mm); | |
| 368 | −} | |
| 369 | − | |
| 370 | −static void | |
| 371 | −__i915_mm_struct_free(struct kref *kref) | |
| 372 | −{ | |
| 373 | − struct i915_mm_struct *mm = container_of(kref, typeof(*mm), kref); | |
| 121 | + if (pvec) { | |
| 122 | + const unsigned long num_pages = obj->base.size >> PAGE_SHIFT; | |
| 374 | 123 | |
| 375 | − spin_lock(&mm->i915->mm_lock); | |
| 376 | − hash_del_rcu(&mm->node); | |
| 377 | − spin_unlock(&mm->i915->mm_lock); | |
| 378 | − | |
| 379 | − INIT_RCU_WORK(&mm->work, __i915_mm_struct_free__worker); | |
| 380 | − queue_rcu_work(system_wq, &mm->work); | |
| 381 | −} | |
| 382 | − | |
| 383 | −static void | |
| 384 | −i915_gem_userptr_release__mm_struct(struct drm_i915_gem_object *obj) | |
| 385 | −{ | |
| 386 | − if (obj->userptr.mm == NULL) | |
| 387 | − return; | |
| 388 | − | |
| 389 | − kref_put(&obj->userptr.mm->kref, __i915_mm_struct_free); | |
| 390 | − obj->userptr.mm = NULL; | |
| 124 | + unpin_user_pages(pvec, num_pages); | |
| 125 | + kvfree(pvec); | |
| 126 | + } | |
| 391 | 127 | } |
| 392 | 128 | |
| 393 | −struct get_pages_work { | |
| 394 | − struct work_struct work; | |
| 395 | − struct drm_i915_gem_object *obj; | |
| 396 | − struct task_struct *task; | |
| 397 | −}; | |
| 398 | − | |
| 399 | −static struct sg_table * | |
| 400 | −__i915_gem_userptr_alloc_pages(struct drm_i915_gem_object *obj, | |
| 401 | − struct page **pvec, unsigned long num_pages) | |
| 129 | +static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) | |
| 402 | 130 | { |
| 131 | + struct drm_i915_private *i915 = to_i915(obj->base.dev); | |
| 132 | + const unsigned long num_pages = obj->base.size >> PAGE_SHIFT; | |
| 403 | 133 | unsigned int max_segment = i915_sg_segment_size(); |
| 404 | 134 | struct sg_table *st; |
| 405 | 135 | unsigned int sg_page_sizes; |
| 406 | 136 | struct scatterlist *sg; |
| 137 | + struct page **pvec; | |
| 407 | 138 | int ret; |
| 408 | 139 | |
| 409 | 140 | st = kmalloc(sizeof(*st), GFP_KERNEL); |
| 410 | 141 | if (!st) |
| 411 | − return ERR_PTR(-ENOMEM); | |
| 142 | + return -ENOMEM; | |
| 143 | + | |
| 144 | + spin_lock(&i915->mm.notifier_lock); | |
| 145 | + if (GEM_WARN_ON(!obj->userptr.page_ref)) { | |
| 146 | + spin_unlock(&i915->mm.notifier_lock); | |
| 147 | + ret = -EFAULT; | |
| 148 | + goto err_free; | |
| 149 | + } | |
| 150 | + | |
| 151 | + obj->userptr.page_ref++; | |
| 152 | + pvec = obj->userptr.pvec; | |
| 153 | + spin_unlock(&i915->mm.notifier_lock); | |
| 412 | 154 | |
| 413 | 155 | alloc_table: |
| 414 | 156 | sg = __sg_alloc_table_from_pages(st, pvec, num_pages, 0, |
| 415 | 157 | num_pages << PAGE_SHIFT, max_segment, |
| 416 | 158 | NULL, 0, GFP_KERNEL); |
| 417 | 159 | if (IS_ERR(sg)) { |
| 418 | − kfree(st); | |
| 419 | − return ERR_CAST(sg); | |
| 160 | + ret = PTR_ERR(sg); | |
| 161 | + goto err; | |
| 420 | 162 | } |
| 421 | 163 | |
| 422 | 164 | ret = i915_gem_gtt_prepare_pages(obj, st); |
| @@ -428,203 +170,20 @@ alloc_table: · 5 unmodified lines | ||
| 428 | 170 | goto alloc_table; |
| 429 | 171 | } |
| 430 | 172 | |
| 431 | − kfree(st); | |
| 432 | − return ERR_PTR(ret); | |
| 173 | + goto err; | |
| 433 | 174 | } |
| 434 | 175 | |
| 435 | 176 | sg_page_sizes = i915_sg_page_sizes(st->sgl); |
| 436 | 177 | |
| 437 | 178 | __i915_gem_object_set_pages(obj, st, sg_page_sizes); |
| 438 | 179 | |
| 439 | − return st; | |
| 440 | −} | |
| 441 | − | |
| 442 | −static void | |
| 443 | −__i915_gem_userptr_get_pages_worker(struct work_struct *_work) | |
| 444 | −{ | |
| 445 | − struct get_pages_work *work = container_of(_work, typeof(*work), work); | |
| 446 | − struct drm_i915_gem_object *obj = work->obj; | |
| 447 | − const unsigned long npages = obj->base.size >> PAGE_SHIFT; | |
| 448 | − unsigned long pinned; | |
| 449 | − struct page **pvec; | |
| 450 | − int ret; | |
| 451 | − | |
| 452 | − ret = -ENOMEM; | |
| 453 | − pinned = 0; | |
| 454 | − | |
| 455 | − pvec = kvmalloc_array(npages, sizeof(struct page *), GFP_KERNEL); | |
| 456 | − if (pvec != NULL) { | |
| 457 | − struct mm_struct *mm = obj->userptr.mm->mm; | |
| 458 | − unsigned int flags = 0; | |
| 459 | − int locked = 0; | |
| 460 | − | |
| 461 | − if (!i915_gem_object_is_readonly(obj)) | |
| 462 | − flags |= FOLL_WRITE; | |
| 463 | − | |
| 464 | − ret = -EFAULT; | |
| 465 | − if (mmget_not_zero(mm)) { | |
| 466 | − while (pinned < npages) { | |
| 467 | − if (!locked) { | |
| 468 | − mmap_read_lock(mm); | |
| 469 | − locked = 1; | |
| 470 | − } | |
| 471 | − ret = pin_user_pages_remote | |
| 472 | − (mm, | |
| 473 | − obj->userptr.ptr + pinned * PAGE_SIZE, | |
| 474 | − npages - pinned, | |
| 475 | − flags, | |
| 476 | − pvec + pinned, NULL, &locked); | |
| 477 | − if (ret < 0) | |
| 478 | − break; | |
| 479 | − | |
| 480 | − pinned += ret; | |
| 481 | − } | |
| 482 | − if (locked) | |
| 483 | − mmap_read_unlock(mm); | |
| 484 | − mmput(mm); | |
| 485 | − } | |
| 486 | − } | |
| 487 | − | |
| 488 | − mutex_lock_nested(&obj->mm.lock, I915_MM_GET_PAGES); | |
| 489 | − if (obj->userptr.work == &work->work) { | |
| 490 | − struct sg_table *pages = ERR_PTR(ret); | |
| 491 | − | |
| 492 | − if (pinned == npages) { | |
| 493 | − pages = __i915_gem_userptr_alloc_pages(obj, pvec, | |
| 494 | − npages); | |
| 495 | − if (!IS_ERR(pages)) { | |
| 496 | − pinned = 0; | |
| 497 | − pages = NULL; | |
| 498 | − } | |
| 499 | − } | |
| 500 | − | |
| 501 | − obj->userptr.work = ERR_CAST(pages); | |
| 502 | − if (IS_ERR(pages)) | |
| 503 | − __i915_gem_userptr_set_active(obj, false); | |
| 504 | − } | |
| 505 | − mutex_unlock(&obj->mm.lock); | |
| 506 | − | |
| 507 | − unpin_user_pages(pvec, pinned); | |
| 508 | − kvfree(pvec); | |
| 509 | − | |
| 510 | − i915_gem_object_put(obj); | |
| 511 | − put_task_struct(work->task); | |
| 512 | − kfree(work); | |
| 513 | −} | |
| 514 | − | |
| 515 | −static struct sg_table * | |
| 516 | −__i915_gem_userptr_get_pages_schedule(struct drm_i915_gem_object *obj) | |
| 517 | −{ | |
| 518 | − struct get_pages_work *work; | |
| 519 | − | |
| 520 | − /* Spawn a worker so that we can acquire the | |
| 521 | − * user pages without holding our mutex. Access | |
| 522 | − * to the user pages requires mmap_lock, and we have | |
| 523 | − * a strict lock ordering of mmap_lock, struct_mutex - | |
| 524 | − * we already hold struct_mutex here and so cannot | |
| 525 | − * call gup without encountering a lock inversion. | |
| 526 | − * | |
| 527 | − * Userspace will keep on repeating the operation | |
| 528 | − * (thanks to EAGAIN) until either we hit the fast | |
| 529 | − * path or the worker completes. If the worker is | |
| 530 | − * cancelled or superseded, the task is still run | |
| 531 | − * but the results ignored. (This leads to | |
| 532 | − * complications that we may have a stray object | |
| 533 | − * refcount that we need to be wary of when | |
| 534 | − * checking for existing objects during creation.) | |
| 535 | − * If the worker encounters an error, it reports | |
| 536 | − * that error back to this function through | |
| 537 | − * obj->userptr.work = ERR_PTR. | |
| 538 | − */ | |
| 539 | − work = kmalloc(sizeof(*work), GFP_KERNEL); | |
| 540 | − if (work == NULL) | |
| 541 | − return ERR_PTR(-ENOMEM); | |
| 542 | − | |
| 543 | − obj->userptr.work = &work->work; | |
| 544 | − | |
| 545 | − work->obj = i915_gem_object_get(obj); | |
| 546 | − | |
| 547 | − work->task = current; | |
| 548 | − get_task_struct(work->task); | |
| 549 | − | |
| 550 | − INIT_WORK(&work->work, __i915_gem_userptr_get_pages_worker); | |
| 551 | − queue_work(to_i915(obj->base.dev)->mm.userptr_wq, &work->work); | |
| 552 | − | |
| 553 | − return ERR_PTR(-EAGAIN); | |
| 554 | −} | |
| 555 | − | |
| 556 | −static int i915_gem_userptr_get_pages(struct drm_i915_gem_object *obj) | |
| 557 | −{ | |
| 558 | − const unsigned long num_pages = obj->base.size >> PAGE_SHIFT; | |
| 559 | − struct mm_struct *mm = obj->userptr.mm->mm; | |
| 560 | − struct page **pvec; | |
| 561 | − struct sg_table *pages; | |
| 562 | − bool active; | |
| 563 | − int pinned; | |
| 564 | − unsigned int gup_flags = 0; | |
| 565 | − | |
| 566 | − /* If userspace should engineer that these pages are replaced in | |
| 567 | − * the vma between us binding this page into the GTT and completion | |
| 568 | − * of rendering... Their loss. If they change the mapping of their | |
| 569 | − * pages they need to create a new bo to point to the new vma. | |
| 570 | − * | |
| 571 | − * However, that still leaves open the possibility of the vma | |
| 572 | − * being copied upon fork. Which falls under the same userspace | |
| 573 | − * synchronisation issue as a regular bo, except that this time | |
| 574 | − * the process may not be expecting that a particular piece of | |
| 575 | − * memory is tied to the GPU. | |
| 576 | − * | |
| 577 | − * Fortunately, we can hook into the mmu_notifier in order to | |
| 578 | − * discard the page references prior to anything nasty happening | |
| 579 | − * to the vma (discard or cloning) which should prevent the more | |
| 580 | − * egregious cases from causing harm. | |
| 581 | − */ | |
| 582 | − | |
| 583 | − if (obj->userptr.work) { | |
| 584 | − /* active flag should still be held for the pending work */ | |
| 585 | − if (IS_ERR(obj->userptr.work)) | |
| 586 | − return PTR_ERR(obj->userptr.work); | |
| 587 | − else | |
| 588 | − return -EAGAIN; | |
| 589 | − } | |
| 590 | − | |
| 591 | − pvec = NULL; | |
| 592 | − pinned = 0; | |
| 593 | − | |
| 594 | − if (mm == current->mm) { | |
| 595 | − pvec = kvmalloc_array(num_pages, sizeof(struct page *), | |
| 596 | − GFP_KERNEL | | |
| 597 | − __GFP_NORETRY | | |
| 598 | − __GFP_NOWARN); | |
| 599 | − if (pvec) { | |
| 600 | − /* defer to worker if malloc fails */ | |
| 601 | − if (!i915_gem_object_is_readonly(obj)) | |
| 602 | − gup_flags |= FOLL_WRITE; | |
| 603 | − pinned = pin_user_pages_fast_only(obj->userptr.ptr, | |
| 604 | − num_pages, gup_flags, | |
| 605 | − pvec); | |
| 606 | − } | |
| 607 | − } | |
| 608 | − | |
| 609 | − active = false; | |
| 610 | − if (pinned < 0) { | |
| 611 | − pages = ERR_PTR(pinned); | |
| 612 | − pinned = 0; | |
| 613 | − } else if (pinned < num_pages) { | |
| 614 | − pages = __i915_gem_userptr_get_pages_schedule(obj); | |
| 615 | − active = pages == ERR_PTR(-EAGAIN); | |
| 616 | − } else { | |
| 617 | − pages = __i915_gem_userptr_alloc_pages(obj, pvec, num_pages); | |
| 618 | − active = !IS_ERR(pages); | |
| 619 | − } | |
| 620 | − if (active) | |
| 621 | − __i915_gem_userptr_set_active(obj, true); | |
| 622 | − | |
| 623 | − if (IS_ERR(pages)) | |
| 624 | − unpin_user_pages(pvec, pinned); | |
| 625 | − kvfree(pvec); | |
| 180 | + return 0; | |
| 626 | 181 | |
| 627 | − return PTR_ERR_OR_ZERO(pages); | |
| 182 | +err: | |
| 183 | + i915_gem_object_userptr_drop_ref(obj); | |
| 184 | +err_free: | |
| 185 | + kfree(st); | |
| 186 | + return ret; | |
| 628 | 187 | } |
| 629 | 188 | |
| 630 | 189 | static void |
| @@ -634,9 +193,6 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj, · 3 unmodified lines | ||
| 634 | 193 | struct sgt_iter sgt_iter; |
| 635 | 194 | struct page *page; |
| 636 | 195 | |
| 637 | − /* Cancel any inflight work and force them to restart their gup */ | |
| 638 | − obj->userptr.work = NULL; | |
| 639 | − __i915_gem_userptr_set_active(obj, false); | |
| 640 | 196 | if (!pages) |
| 641 | 197 | return; |
| 642 | 198 | |
| @@ -676,42 +232,224 @@ i915_gem_userptr_put_pages(struct drm_i915_gem_object *obj, · 33 unmodified lines | ||
| 676 | 232 | } |
| 677 | 233 | |
| 678 | 234 | mark_page_accessed(page); |
| 679 | − unpin_user_page(page); | |
| 680 | 235 | } |
| 681 | 236 | obj->mm.dirty = false; |
| 682 | 237 | |
| 683 | 238 | sg_free_table(pages); |
| 684 | 239 | kfree(pages); |
| 240 | + | |
| 241 | + i915_gem_object_userptr_drop_ref(obj); | |
| 242 | +} | |
| 243 | + | |
| 244 | +static int i915_gem_object_userptr_unbind(struct drm_i915_gem_object *obj, bool get_pages) | |
| 245 | +{ | |
| 246 | + struct sg_table *pages; | |
| 247 | + int err; | |
| 248 | + | |
| 249 | + err = i915_gem_object_unbind(obj, I915_GEM_OBJECT_UNBIND_ACTIVE); | |
| 250 | + if (err) | |
| 251 | + return err; | |
| 252 | + | |
| 253 | + if (GEM_WARN_ON(i915_gem_object_has_pinned_pages(obj))) | |
| 254 | + return -EBUSY; | |
| 255 | + | |
| 256 | + assert_object_held(obj); | |
| 257 | + | |
| 258 | + pages = __i915_gem_object_unset_pages(obj); | |
| 259 | + if (!IS_ERR_OR_NULL(pages)) | |
| 260 | + i915_gem_userptr_put_pages(obj, pages); | |
| 261 | + | |
| 262 | + if (get_pages) | |
| 263 | + err = ____i915_gem_object_get_pages(obj); | |
| 264 | + | |
| 265 | + return err; | |
| 266 | +} | |
| 267 | + | |
| 268 | +int i915_gem_object_userptr_submit_init(struct drm_i915_gem_object *obj) | |
| 269 | +{ | |
| 270 | + struct drm_i915_private *i915 = to_i915(obj->base.dev); | |
| 271 | + const unsigned long num_pages = obj->base.size >> PAGE_SHIFT; | |
| 272 | + struct page **pvec; | |
| 273 | + unsigned int gup_flags = 0; | |
| 274 | + unsigned long notifier_seq; | |
| 275 | + int pinned, ret; | |
| 276 | + | |
| 277 | + if (obj->userptr.notifier.mm != current->mm) | |
| 278 | + return -EFAULT; | |
| 279 | + | |
| 280 | + ret = i915_gem_object_lock_interruptible(obj, NULL); | |
| 281 | + if (ret) | |
| 282 | + return ret; | |
| 283 | + | |
| 284 | + /* optimistically try to preserve current pages while unlocked */ | |
| 285 | + if (i915_gem_object_has_pages(obj) && | |
| 286 | + !mmu_interval_check_retry(&obj->userptr.notifier, | |
| 287 | + obj->userptr.notifier_seq)) { | |
| 288 | + spin_lock(&i915->mm.notifier_lock); | |
| 289 | + if (obj->userptr.pvec && | |
| 290 | + !mmu_interval_read_retry(&obj->userptr.notifier, | |
| 291 | + obj->userptr.notifier_seq)) { | |
| 292 | + obj->userptr.page_ref++; | |
| 293 | + | |
| 294 | + /* We can keep using the current binding, this is the fastpath */ | |
| 295 | + ret = 1; | |
| 296 | + } | |
| 297 | + spin_unlock(&i915->mm.notifier_lock); | |
| 298 | + } | |
| 299 | + | |
| 300 | + if (!ret) { | |
| 301 | + /* Make sure userptr is unbound for next attempt, so we don't use stale pages. */ | |
| 302 | + ret = i915_gem_object_userptr_unbind(obj, false); | |
| 303 | + } | |
| 304 | + i915_gem_object_unlock(obj); | |
| 305 | + if (ret < 0) | |
| 306 | + return ret; | |
| 307 | + | |
| 308 | + if (ret > 0) | |
| 309 | + return 0; | |
| 310 | + | |
| 311 | + notifier_seq = mmu_interval_read_begin(&obj->userptr.notifier); | |
| 312 | + | |
| 313 | + pvec = kvmalloc_array(num_pages, sizeof(struct page *), GFP_KERNEL); | |
| 314 | + if (!pvec) | |
| 315 | + return -ENOMEM; | |
| 316 | + | |
| 317 | + if (!i915_gem_object_is_readonly(obj)) | |
| 318 | + gup_flags |= FOLL_WRITE; | |
| 319 | + | |
| 320 | + pinned = ret = 0; | |
| 321 | + while (pinned < num_pages) { | |
| 322 | + ret = pin_user_pages_fast(obj->userptr.ptr + pinned * PAGE_SIZE, | |
| 323 | + num_pages - pinned, gup_flags, | |
| 324 | + &pvec[pinned]); | |
| 325 | + if (ret < 0) | |
| 326 | + goto out; | |
| 327 | + | |
| 328 | + pinned += ret; | |
| 329 | + } | |
| 330 | + ret = 0; | |
| 331 | + | |
| 332 | + spin_lock(&i915->mm.notifier_lock); | |
| 333 | + | |
| 334 | + if (mmu_interval_read_retry(&obj->userptr.notifier, | |
| 335 | + !obj->userptr.page_ref ? notifier_seq : | |
| 336 | + obj->userptr.notifier_seq)) { | |
| 337 | + ret = -EAGAIN; | |
| 338 | + goto out_unlock; | |
| 339 | + } | |
| 340 | + | |
| 341 | + if (!obj->userptr.page_ref++) { | |
| 342 | + obj->userptr.pvec = pvec; | |
| 343 | + obj->userptr.notifier_seq = notifier_seq; | |
| 344 | + | |
| 345 | + pvec = NULL; | |
| 346 | + } | |
| 347 | + | |
| 348 | +out_unlock: | |
| 349 | + spin_unlock(&i915->mm.notifier_lock); | |
| 350 | + | |
| 351 | +out: | |
| 352 | + if (pvec) { | |
| 353 | + unpin_user_pages(pvec, pinned); | |
| 354 | + kvfree(pvec); | |
| 355 | + } | |
| 356 | + | |
| 357 | + return ret; | |
| 358 | +} | |
| 359 | + | |
| 360 | +int i915_gem_object_userptr_submit_done(struct drm_i915_gem_object *obj) | |
| 361 | +{ | |
| 362 | + if (mmu_interval_read_retry(&obj->userptr.notifier, | |
| 363 | + obj->userptr.notifier_seq)) { | |
| 364 | + /* We collided with the mmu notifier, need to retry */ | |
| 365 | + | |
| 366 | + return -EAGAIN; | |
| 367 | + } | |
| 368 | + | |
| 369 | + return 0; | |
| 370 | +} | |
| 371 | + | |
| 372 | +void i915_gem_object_userptr_submit_fini(struct drm_i915_gem_object *obj) | |
| 373 | +{ | |
| 374 | + i915_gem_object_userptr_drop_ref(obj); | |
| 375 | +} | |
| 376 | + | |
| 377 | +int i915_gem_object_userptr_validate(struct drm_i915_gem_object *obj) | |
| 378 | +{ | |
| 379 | + int err; | |
| 380 | + | |
| 381 | + err = i915_gem_object_userptr_submit_init(obj); | |
| 382 | + if (err) | |
| 383 | + return err; | |
| 384 | + | |
| 385 | + err = i915_gem_object_lock_interruptible(obj, NULL); | |
| 386 | + if (!err) { | |
| 387 | + /* | |
| 388 | + * Since we only check validity, not use the pages, | |
| 389 | + * it doesn't matter if we collide with the mmu notifier, | |
| 390 | + * and -EAGAIN handling is not required. | |
| 391 | + */ | |
| 392 | + err = i915_gem_object_pin_pages(obj); | |
| 393 | + if (!err) | |
| 394 | + i915_gem_object_unpin_pages(obj); | |
| 395 | + | |
| 396 | + i915_gem_object_unlock(obj); | |
| 397 | + } | |
| 398 | + | |
| 399 | + i915_gem_object_userptr_submit_fini(obj); | |
| 400 | + return err; | |
| 685 | 401 | } |
| 686 | 402 | |
| 687 | 403 | static void |
| 688 | 404 | i915_gem_userptr_release(struct drm_i915_gem_object *obj) |
| 689 | 405 | { |
| 690 | − i915_gem_userptr_release__mmu_notifier(obj); | |
| 691 | − i915_gem_userptr_release__mm_struct(obj); | |
| 406 | + GEM_WARN_ON(obj->userptr.page_ref); | |
| 407 | + | |
| 408 | + mmu_interval_notifier_remove(&obj->userptr.notifier); | |
| 409 | + obj->userptr.notifier.mm = NULL; | |
| 692 | 410 | } |
| 693 | 411 | |
| 694 | 412 | static int |
| 695 | 413 | i915_gem_userptr_dmabuf_export(struct drm_i915_gem_object *obj) |
| 696 | 414 | { |
| 697 | − if (obj->userptr.mmu_object) | |
| 698 | − return 0; | |
| 415 | + drm_dbg(obj->base.dev, "Exporting userptr no longer allowed\n"); | |
| 699 | 416 | |
| 700 | − return i915_gem_userptr_init__mmu_notifier(obj, 0); | |
| 417 | + return -EINVAL; | |
| 418 | +} | |
| 419 | + | |
| 420 | +static int | |
| 421 | +i915_gem_userptr_pwrite(struct drm_i915_gem_object *obj, | |
| 422 | + const struct drm_i915_gem_pwrite *args) | |
| 423 | +{ | |
| 424 | + drm_dbg(obj->base.dev, "pwrite to userptr no longer allowed\n"); | |
| 425 | + | |
| 426 | + return -EINVAL; | |
| 427 | +} | |
| 428 | + | |
| 429 | +static int | |
| 430 | +i915_gem_userptr_pread(struct drm_i915_gem_object *obj, | |
| 431 | + const struct drm_i915_gem_pread *args) | |
| 432 | +{ | |
| 433 | + drm_dbg(obj->base.dev, "pread from userptr no longer allowed\n"); | |
| 434 | + | |
| 435 | + return -EINVAL; | |
| 701 | 436 | } |
| 702 | 437 | |
| 703 | 438 | static const struct drm_i915_gem_object_ops i915_gem_userptr_ops = { |
| 704 | 439 | .name = "i915_gem_object_userptr", |
| 705 | − .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE | | |
| 706 | − I915_GEM_OBJECT_IS_SHRINKABLE | | |
| 440 | + .flags = I915_GEM_OBJECT_IS_SHRINKABLE | | |
| 707 | 441 | I915_GEM_OBJECT_NO_MMAP | |
| 708 | − I915_GEM_OBJECT_ASYNC_CANCEL, | |
| 442 | + I915_GEM_OBJECT_IS_PROXY, | |
| 709 | 443 | .get_pages = i915_gem_userptr_get_pages, |
| 710 | 444 | .put_pages = i915_gem_userptr_put_pages, |
| 711 | 445 | .dmabuf_export = i915_gem_userptr_dmabuf_export, |
| 446 | + .pwrite = i915_gem_userptr_pwrite, | |
| 447 | + .pread = i915_gem_userptr_pread, | |
| 712 | 448 | .release = i915_gem_userptr_release, |
| 713 | 449 | }; |
| 714 | 450 | |
| 451 | +#endif | |
| 452 | + | |
| 715 | 453 | /* |
| 716 | 454 | * Creates a new mm object that wraps some normal memory from the process |
| 717 | 455 | * context - user memory. |
| @@ -752,12 +490,12 @@ i915_gem_userptr_ioctl(struct drm_device *dev, · 34 unmodified lines | ||
| 752 | 490 | void *data, |
| 753 | 491 | struct drm_file *file) |
| 754 | 492 | { |
| 755 | − static struct lock_class_key lock_class; | |
| 493 | + static struct lock_class_key __maybe_unused lock_class; | |
| 756 | 494 | struct drm_i915_private *dev_priv = to_i915(dev); |
| 757 | 495 | struct drm_i915_gem_userptr *args = data; |
| 758 | − struct drm_i915_gem_object *obj; | |
| 759 | − int ret; | |
| 760 | − u32 handle; | |
| 496 | + struct drm_i915_gem_object __maybe_unused *obj; | |
| 497 | + int __maybe_unused ret; | |
| 498 | + u32 __maybe_unused handle; | |
| 761 | 499 | |
| 762 | 500 | if (!HAS_LLC(dev_priv) && !HAS_SNOOP(dev_priv)) { |
| 763 | 501 | /* We cannot support coherent userptr objects on hw without |
| @@ -796,6 +534,9 @@ i915_gem_userptr_ioctl(struct drm_device *dev, · 32 unmodified lines | ||
| 796 | 534 | if (!access_ok((char __user *)(unsigned long)args->user_ptr, args->user_size)) |
| 797 | 535 | return -EFAULT; |
| 798 | 536 | |
| 537 | + if (args->flags & I915_USERPTR_UNSYNCHRONIZED) | |
| 538 | + return -ENODEV; | |
| 539 | + | |
| 799 | 540 | if (args->flags & I915_USERPTR_READ_ONLY) { |
| 800 | 541 | /* |
| 801 | 542 | * On almost all of the older hw, we cannot tell the GPU that |
| @@ -805,17 +546,20 @@ i915_gem_userptr_ioctl(struct drm_device *dev, · 3 unmodified lines | ||
| 805 | 546 | return -ENODEV; |
| 806 | 547 | } |
| 807 | 548 | |
| 549 | +#ifdef CONFIG_MMU_NOTIFIER | |
| 808 | 550 | obj = i915_gem_object_alloc(); |
| 809 | 551 | if (obj == NULL) |
| 810 | 552 | return -ENOMEM; |
| 811 | 553 | |
| 812 | 554 | drm_gem_private_object_init(dev, &obj->base, args->user_size); |
| 813 | − i915_gem_object_init(obj, &i915_gem_userptr_ops, &lock_class); | |
| 555 | + i915_gem_object_init(obj, &i915_gem_userptr_ops, &lock_class, | |
| 556 | + I915_BO_ALLOC_STRUCT_PAGE); | |
| 814 | 557 | obj->read_domains = I915_GEM_DOMAIN_CPU; |
| 815 | 558 | obj->write_domain = I915_GEM_DOMAIN_CPU; |
| 816 | 559 | i915_gem_object_set_cache_coherency(obj, I915_CACHE_LLC); |
| 817 | 560 | |
| 818 | 561 | obj->userptr.ptr = args->user_ptr; |
| 562 | + obj->userptr.notifier_seq = ULONG_MAX; | |
| 819 | 563 | if (args->flags & I915_USERPTR_READ_ONLY) |
| 820 | 564 | i915_gem_object_set_readonly(obj); |
| 821 | 565 | |
| @@ -823,9 +567,7 @@ i915_gem_userptr_ioctl(struct drm_device *dev, · 1 unmodified line | ||
| 823 | 567 | * at binding. This means that we need to hook into the mmu_notifier |
| 824 | 568 | * in order to detect if the mmu is destroyed. |
| 825 | 569 | */ |
| 826 | − ret = i915_gem_userptr_init__mm_struct(obj); | |
| 827 | − if (ret == 0) | |
| 828 | − ret = i915_gem_userptr_init__mmu_notifier(obj, args->flags); | |
| 570 | + ret = i915_gem_userptr_init__mmu_notifier(obj); | |
| 829 | 571 | if (ret == 0) |
| 830 | 572 | ret = drm_gem_handle_create(file, &obj->base, &handle); |
| 831 | 573 | |
| @@ -836,24 +578,20 @@ i915_gem_userptr_ioctl(struct drm_device *dev, · 4 unmodified lines | ||
| 836 | 578 | |
| 837 | 579 | args->handle = handle; |
| 838 | 580 | return 0; |
| 581 | +#else | |
| 582 | + return -ENODEV; | |
| 583 | +#endif | |
| 839 | 584 | } |
| 840 | 585 | |
| 841 | 586 | int i915_gem_init_userptr(struct drm_i915_private *dev_priv) |
| 842 | 587 | { |
| 843 | − spin_lock_init(&dev_priv->mm_lock); | |
| 844 | − hash_init(dev_priv->mm_structs); | |
| 845 | − | |
| 846 | − dev_priv->mm.userptr_wq = | |
| 847 | − alloc_workqueue("i915-userptr-acquire", | |
| 848 | − WQ_HIGHPRI | WQ_UNBOUND, | |
| 849 | − 0); | |
| 850 | − if (!dev_priv->mm.userptr_wq) | |
| 851 | − return -ENOMEM; | |
| 588 | +#ifdef CONFIG_MMU_NOTIFIER | |
| 589 | + spin_lock_init(&dev_priv->mm.notifier_lock); | |
| 590 | +#endif | |
| 852 | 591 | |
| 853 | 592 | return 0; |
| 854 | 593 | } |
| 855 | 594 | |
| 856 | 595 | void i915_gem_cleanup_userptr(struct drm_i915_private *dev_priv) |
| 857 | 596 | { |
| 858 | − destroy_workqueue(dev_priv->mm.userptr_wq); | |
| 859 | 597 | } |
| @@ -89,7 +89,6 @@ static void huge_put_pages(struct drm_i915_gem_object *obj, · 88 unmodified lines | ||
| 89 | 89 | |
| 90 | 90 | static const struct drm_i915_gem_object_ops huge_ops = { |
| 91 | 91 | .name = "huge-gem", |
| 92 | − .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE, | |
| 93 | 92 | .get_pages = huge_get_pages, |
| 94 | 93 | .put_pages = huge_put_pages, |
| 95 | 94 | }; |
| @@ -115,7 +114,8 @@ huge_gem_object(struct drm_i915_private *i915, · 19 unmodified lines | ||
| 115 | 114 | return ERR_PTR(-ENOMEM); |
| 116 | 115 | |
| 117 | 116 | drm_gem_private_object_init(&i915->drm, &obj->base, dma_size); |
| 118 | − i915_gem_object_init(obj, &huge_ops, &lock_class); | |
| 117 | + i915_gem_object_init(obj, &huge_ops, &lock_class, | |
| 118 | + I915_BO_ALLOC_STRUCT_PAGE); | |
| 119 | 119 | |
| 120 | 120 | obj->read_domains = I915_GEM_DOMAIN_CPU; |
| 121 | 121 | obj->write_domain = I915_GEM_DOMAIN_CPU; |
| @@ -140,8 +140,7 @@ static void put_huge_pages(struct drm_i915_gem_object *obj, · 139 unmodified lines | ||
| 140 | 140 | |
| 141 | 141 | static const struct drm_i915_gem_object_ops huge_page_ops = { |
| 142 | 142 | .name = "huge-gem", |
| 143 | − .flags = I915_GEM_OBJECT_HAS_STRUCT_PAGE | | |
| 144 | − I915_GEM_OBJECT_IS_SHRINKABLE, | |
| 143 | + .flags = I915_GEM_OBJECT_IS_SHRINKABLE, | |
| 145 | 144 | .get_pages = get_huge_pages, |
| 146 | 145 | .put_pages = put_huge_pages, |
| 147 | 146 | }; |
| @@ -168,7 +167,8 @@ huge_pages_object(struct drm_i915_private *i915, · 20 unmodified lines | ||
| 168 | 167 | return ERR_PTR(-ENOMEM); |
| 169 | 168 | |
| 170 | 169 | drm_gem_private_object_init(&i915->drm, &obj->base, size); |
| 171 | − i915_gem_object_init(obj, &huge_page_ops, &lock_class); | |
| 170 | + i915_gem_object_init(obj, &huge_page_ops, &lock_class, | |
| 171 | + I915_BO_ALLOC_STRUCT_PAGE); | |
| 172 | 172 | |
| 173 | 173 | i915_gem_object_set_volatile(obj); |
| 174 | 174 | |
| @@ -319,9 +319,9 @@ fake_huge_pages_object(struct drm_i915_private *i915, u64 size, bool single) · 144 unmodified lines | ||
| 319 | 319 | drm_gem_private_object_init(&i915->drm, &obj->base, size); |
| 320 | 320 | |
| 321 | 321 | if (single) |
| 322 | − i915_gem_object_init(obj, &fake_ops_single, &lock_class); | |
| 322 | + i915_gem_object_init(obj, &fake_ops_single, &lock_class, 0); | |
| 323 | 323 | else |
| 324 | − i915_gem_object_init(obj, &fake_ops, &lock_class); | |
| 324 | + i915_gem_object_init(obj, &fake_ops, &lock_class, 0); | |
| 325 | 325 | |
| 326 | 326 | i915_gem_object_set_volatile(obj); |
| 327 | 327 | |
| @@ -589,7 +589,7 @@ static int igt_mock_ppgtt_misaligned_dma(void *arg) · 261 unmodified lines | ||
| 589 | 589 | goto out_put; |
| 590 | 590 | } |
| 591 | 591 | |
| 592 | − err = i915_gem_object_pin_pages(obj); | |
| 592 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 593 | 593 | if (err) |
| 594 | 594 | goto out_put; |
| 595 | 595 | |
| @@ -653,15 +653,19 @@ static int igt_mock_ppgtt_misaligned_dma(void *arg) · 57 unmodified lines | ||
| 653 | 653 | break; |
| 654 | 654 | } |
| 655 | 655 | |
| 656 | + i915_gem_object_lock(obj, NULL); | |
| 656 | 657 | i915_gem_object_unpin_pages(obj); |
| 657 | 658 | __i915_gem_object_put_pages(obj); |
| 659 | + i915_gem_object_unlock(obj); | |
| 658 | 660 | i915_gem_object_put(obj); |
| 659 | 661 | } |
| 660 | 662 | |
| 661 | 663 | return 0; |
| 662 | 664 | |
| 663 | 665 | out_unpin: |
| 666 | + i915_gem_object_lock(obj, NULL); | |
| 664 | 667 | i915_gem_object_unpin_pages(obj); |
| 668 | + i915_gem_object_unlock(obj); | |
| 665 | 669 | out_put: |
| 666 | 670 | i915_gem_object_put(obj); |
| 667 | 671 | |
| @@ -675,8 +679,10 @@ static void close_object_list(struct list_head *objects, · 7 unmodified lines | ||
| 675 | 679 | |
| 676 | 680 | list_for_each_entry_safe(obj, on, objects, st_link) { |
| 677 | 681 | list_del(&obj->st_link); |
| 682 | + i915_gem_object_lock(obj, NULL); | |
| 678 | 683 | i915_gem_object_unpin_pages(obj); |
| 679 | 684 | __i915_gem_object_put_pages(obj); |
| 685 | + i915_gem_object_unlock(obj); | |
| 680 | 686 | i915_gem_object_put(obj); |
| 681 | 687 | } |
| 682 | 688 | } |
| @@ -713,7 +719,7 @@ static int igt_mock_ppgtt_huge_fill(void *arg) · 30 unmodified lines | ||
| 713 | 719 | break; |
| 714 | 720 | } |
| 715 | 721 | |
| 716 | − err = i915_gem_object_pin_pages(obj); | |
| 722 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 717 | 723 | if (err) { |
| 718 | 724 | i915_gem_object_put(obj); |
| 719 | 725 | break; |
| @@ -889,7 +895,7 @@ static int igt_mock_ppgtt_64K(void *arg) · 169 unmodified lines | ||
| 889 | 895 | if (IS_ERR(obj)) |
| 890 | 896 | return PTR_ERR(obj); |
| 891 | 897 | |
| 892 | − err = i915_gem_object_pin_pages(obj); | |
| 898 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 893 | 899 | if (err) |
| 894 | 900 | goto out_object_put; |
| 895 | 901 | |
| @@ -943,8 +949,10 @@ static int igt_mock_ppgtt_64K(void *arg) · 47 unmodified lines | ||
| 943 | 949 | } |
| 944 | 950 | |
| 945 | 951 | i915_vma_unpin(vma); |
| 952 | + i915_gem_object_lock(obj, NULL); | |
| 946 | 953 | i915_gem_object_unpin_pages(obj); |
| 947 | 954 | __i915_gem_object_put_pages(obj); |
| 955 | + i915_gem_object_unlock(obj); | |
| 948 | 956 | i915_gem_object_put(obj); |
| 949 | 957 | } |
| 950 | 958 | } |
| @@ -954,7 +962,9 @@ static int igt_mock_ppgtt_64K(void *arg) · 3 unmodified lines | ||
| 954 | 962 | out_vma_unpin: |
| 955 | 963 | i915_vma_unpin(vma); |
| 956 | 964 | out_object_unpin: |
| 965 | + i915_gem_object_lock(obj, NULL); | |
| 957 | 966 | i915_gem_object_unpin_pages(obj); |
| 967 | + i915_gem_object_unlock(obj); | |
| 958 | 968 | out_object_put: |
| 959 | 969 | i915_gem_object_put(obj); |
| 960 | 970 | |
| @@ -1024,7 +1034,7 @@ static int __cpu_check_vmap(struct drm_i915_gem_object *obj, u32 dword, u32 val) · 63 unmodified lines | ||
| 1024 | 1034 | if (err) |
| 1025 | 1035 | return err; |
| 1026 | 1036 | |
| 1027 | − ptr = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 1037 | + ptr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 1028 | 1038 | if (IS_ERR(ptr)) |
| 1029 | 1039 | return PTR_ERR(ptr); |
| 1030 | 1040 | |
| @@ -1304,7 +1314,7 @@ try_again: · 273 unmodified lines | ||
| 1304 | 1314 | return err; |
| 1305 | 1315 | } |
| 1306 | 1316 | |
| 1307 | − err = i915_gem_object_pin_pages(obj); | |
| 1317 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 1308 | 1318 | if (err) { |
| 1309 | 1319 | if (err == -ENXIO || err == -E2BIG) { |
| 1310 | 1320 | i915_gem_object_put(obj); |
| @@ -1327,8 +1337,10 @@ try_again: · 16 unmodified lines | ||
| 1327 | 1337 | __func__, size, i); |
| 1328 | 1338 | } |
| 1329 | 1339 | out_unpin: |
| 1340 | + i915_gem_object_lock(obj, NULL); | |
| 1330 | 1341 | i915_gem_object_unpin_pages(obj); |
| 1331 | 1342 | __i915_gem_object_put_pages(obj); |
| 1343 | + i915_gem_object_unlock(obj); | |
| 1332 | 1344 | out_put: |
| 1333 | 1345 | i915_gem_object_put(obj); |
| 1334 | 1346 | |
| @@ -1402,7 +1414,7 @@ static int igt_ppgtt_sanity_check(void *arg) · 67 unmodified lines | ||
| 1402 | 1414 | return err; |
| 1403 | 1415 | } |
| 1404 | 1416 | |
| 1405 | − err = i915_gem_object_pin_pages(obj); | |
| 1417 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 1406 | 1418 | if (err) { |
| 1407 | 1419 | i915_gem_object_put(obj); |
| 1408 | 1420 | goto out; |
| @@ -1416,8 +1428,10 @@ static int igt_ppgtt_sanity_check(void *arg) · 7 unmodified lines | ||
| 1416 | 1428 | |
| 1417 | 1429 | err = igt_write_huge(ctx, obj); |
| 1418 | 1430 | |
| 1431 | + i915_gem_object_lock(obj, NULL); | |
| 1419 | 1432 | i915_gem_object_unpin_pages(obj); |
| 1420 | 1433 | __i915_gem_object_put_pages(obj); |
| 1434 | + i915_gem_object_unlock(obj); | |
| 1421 | 1435 | i915_gem_object_put(obj); |
| 1422 | 1436 | |
| 1423 | 1437 | if (err) { |
| @@ -1462,7 +1476,7 @@ static int igt_tmpfs_fallback(void *arg) · 38 unmodified lines | ||
| 1462 | 1476 | goto out_restore; |
| 1463 | 1477 | } |
| 1464 | 1478 | |
| 1465 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 1479 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 1466 | 1480 | if (IS_ERR(vaddr)) { |
| 1467 | 1481 | err = PTR_ERR(vaddr); |
| 1468 | 1482 | goto out_put; |
| @@ -45,7 +45,7 @@ static int __igt_client_fill(struct intel_engine_cs *engine) · 44 unmodified lines | ||
| 45 | 45 | goto err_flush; |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 48 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 49 | 49 | if (IS_ERR(vaddr)) { |
| 50 | 50 | err = PTR_ERR(vaddr); |
| 51 | 51 | goto err_put; |
| @@ -157,7 +157,7 @@ static int prepare_blit(const struct tiled_blits *t, · 105 unmodified lines | ||
| 157 | 157 | u32 src_pitch, dst_pitch; |
| 158 | 158 | u32 cmd, *cs; |
| 159 | 159 | |
| 160 | − cs = i915_gem_object_pin_map(batch, I915_MAP_WC); | |
| 160 | + cs = i915_gem_object_pin_map_unlocked(batch, I915_MAP_WC); | |
| 161 | 161 | if (IS_ERR(cs)) |
| 162 | 162 | return PTR_ERR(cs); |
| 163 | 163 | |
| @@ -377,7 +377,7 @@ static int verify_buffer(const struct tiled_blits *t, · 213 unmodified lines | ||
| 377 | 377 | y = i915_prandom_u32_max_state(t->height, prng); |
| 378 | 378 | p = y * t->width + x; |
| 379 | 379 | |
| 380 | − vaddr = i915_gem_object_pin_map(buf->vma->obj, I915_MAP_WC); | |
| 380 | + vaddr = i915_gem_object_pin_map_unlocked(buf->vma->obj, I915_MAP_WC); | |
| 381 | 381 | if (IS_ERR(vaddr)) |
| 382 | 382 | return PTR_ERR(vaddr); |
| 383 | 383 | |
| @@ -564,7 +564,7 @@ static int tiled_blits_prepare(struct tiled_blits *t, · 180 unmodified lines | ||
| 564 | 564 | int err; |
| 565 | 565 | int i; |
| 566 | 566 | |
| 567 | − map = i915_gem_object_pin_map(t->scratch.vma->obj, I915_MAP_WC); | |
| 567 | + map = i915_gem_object_pin_map_unlocked(t->scratch.vma->obj, I915_MAP_WC); | |
| 568 | 568 | if (IS_ERR(map)) |
| 569 | 569 | return PTR_ERR(map); |
| 570 | 570 | |
| @@ -160,7 +160,7 @@ static int wc_set(struct context *ctx, unsigned long offset, u32 v) · 159 unmodified lines | ||
| 160 | 160 | if (err) |
| 161 | 161 | return err; |
| 162 | 162 | |
| 163 | − map = i915_gem_object_pin_map(ctx->obj, I915_MAP_WC); | |
| 163 | + map = i915_gem_object_pin_map_unlocked(ctx->obj, I915_MAP_WC); | |
| 164 | 164 | if (IS_ERR(map)) |
| 165 | 165 | return PTR_ERR(map); |
| 166 | 166 | |
| @@ -183,7 +183,7 @@ static int wc_get(struct context *ctx, unsigned long offset, u32 *v) · 16 unmodified lines | ||
| 183 | 183 | if (err) |
| 184 | 184 | return err; |
| 185 | 185 | |
| 186 | − map = i915_gem_object_pin_map(ctx->obj, I915_MAP_WC); | |
| 186 | + map = i915_gem_object_pin_map_unlocked(ctx->obj, I915_MAP_WC); | |
| 187 | 187 | if (IS_ERR(map)) |
| 188 | 188 | return PTR_ERR(map); |
| 189 | 189 | |
| @@ -200,17 +200,15 @@ static int gpu_set(struct context *ctx, unsigned long offset, u32 v) · 10 unmodified lines | ||
| 200 | 200 | u32 *cs; |
| 201 | 201 | int err; |
| 202 | 202 | |
| 203 | + vma = i915_gem_object_ggtt_pin(ctx->obj, NULL, 0, 0, 0); | |
| 204 | + if (IS_ERR(vma)) | |
| 205 | + return PTR_ERR(vma); | |
| 206 | + | |
| 203 | 207 | i915_gem_object_lock(ctx->obj, NULL); |
| 204 | 208 | err = i915_gem_object_set_to_gtt_domain(ctx->obj, true); |
| 205 | 209 | if (err) |
| 206 | 210 | goto out_unlock; |
| 207 | 211 | |
| 208 | − vma = i915_gem_object_ggtt_pin(ctx->obj, NULL, 0, 0, 0); | |
| 209 | − if (IS_ERR(vma)) { | |
| 210 | − err = PTR_ERR(vma); | |
| 211 | − goto out_unlock; | |
| 212 | − } | |
| 213 | − | |
| 214 | 212 | rq = intel_engine_create_kernel_request(ctx->engine); |
| 215 | 213 | if (IS_ERR(rq)) { |
| 216 | 214 | err = PTR_ERR(rq); |
| @@ -1094,7 +1094,7 @@ __read_slice_count(struct intel_context *ce, · 1093 unmodified lines | ||
| 1094 | 1094 | if (ret < 0) |
| 1095 | 1095 | return ret; |
| 1096 | 1096 | |
| 1097 | − buf = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 1097 | + buf = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 1098 | 1098 | if (IS_ERR(buf)) { |
| 1099 | 1099 | ret = PTR_ERR(buf); |
| 1100 | 1100 | return ret; |
| @@ -1511,7 +1511,7 @@ static int write_to_scratch(struct i915_gem_context *ctx, · 410 unmodified lines | ||
| 1511 | 1511 | if (IS_ERR(obj)) |
| 1512 | 1512 | return PTR_ERR(obj); |
| 1513 | 1513 | |
| 1514 | − cmd = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 1514 | + cmd = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 1515 | 1515 | if (IS_ERR(cmd)) { |
| 1516 | 1516 | err = PTR_ERR(cmd); |
| 1517 | 1517 | goto out; |
| @@ -1622,7 +1622,7 @@ static int read_from_scratch(struct i915_gem_context *ctx, · 104 unmodified lines | ||
| 1622 | 1622 | if (err) |
| 1623 | 1623 | goto out_vm; |
| 1624 | 1624 | |
| 1625 | − cmd = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 1625 | + cmd = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 1626 | 1626 | if (IS_ERR(cmd)) { |
| 1627 | 1627 | err = PTR_ERR(cmd); |
| 1628 | 1628 | goto out; |
| @@ -1658,7 +1658,7 @@ static int read_from_scratch(struct i915_gem_context *ctx, · 29 unmodified lines | ||
| 1658 | 1658 | if (err) |
| 1659 | 1659 | goto out_vm; |
| 1660 | 1660 | |
| 1661 | − cmd = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 1661 | + cmd = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 1662 | 1662 | if (IS_ERR(cmd)) { |
| 1663 | 1663 | err = PTR_ERR(cmd); |
| 1664 | 1664 | goto out; |
| @@ -1715,7 +1715,7 @@ static int read_from_scratch(struct i915_gem_context *ctx, · 50 unmodified lines | ||
| 1715 | 1715 | if (err) |
| 1716 | 1716 | goto out_vm; |
| 1717 | 1717 | |
| 1718 | − cmd = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 1718 | + cmd = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 1719 | 1719 | if (IS_ERR(cmd)) { |
| 1720 | 1720 | err = PTR_ERR(cmd); |
| 1721 | 1721 | goto out_vm; |
| @@ -194,7 +194,7 @@ static int igt_dmabuf_import_ownership(void *arg) · 193 unmodified lines | ||
| 194 | 194 | |
| 195 | 195 | dma_buf_put(dmabuf); |
| 196 | 196 | |
| 197 | − err = i915_gem_object_pin_pages(obj); | |
| 197 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 198 | 198 | if (err) { |
| 199 | 199 | pr_err("i915_gem_object_pin_pages failed with err=%d\n", err); |
| 200 | 200 | goto out_obj; |
| @@ -116,7 +116,7 @@ static int igt_gpu_reloc(void *arg) · 115 unmodified lines | ||
| 116 | 116 | if (IS_ERR(scratch)) |
| 117 | 117 | return PTR_ERR(scratch); |
| 118 | 118 | |
| 119 | − map = i915_gem_object_pin_map(scratch, I915_MAP_WC); | |
| 119 | + map = i915_gem_object_pin_map_unlocked(scratch, I915_MAP_WC); | |
| 120 | 120 | if (IS_ERR(map)) { |
| 121 | 121 | err = PTR_ERR(map); |
| 122 | 122 | goto err_scratch; |
| @@ -322,7 +322,7 @@ static int igt_partial_tiling(void *arg) · 321 unmodified lines | ||
| 322 | 322 | if (IS_ERR(obj)) |
| 323 | 323 | return PTR_ERR(obj); |
| 324 | 324 | |
| 325 | − err = i915_gem_object_pin_pages(obj); | |
| 325 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 326 | 326 | if (err) { |
| 327 | 327 | pr_err("Failed to allocate %u pages (%lu total), err=%d\n", |
| 328 | 328 | nreal, obj->base.size / PAGE_SIZE, err); |
| @@ -459,7 +459,7 @@ static int igt_smoke_tiling(void *arg) · 130 unmodified lines | ||
| 459 | 459 | if (IS_ERR(obj)) |
| 460 | 460 | return PTR_ERR(obj); |
| 461 | 461 | |
| 462 | − err = i915_gem_object_pin_pages(obj); | |
| 462 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 463 | 463 | if (err) { |
| 464 | 464 | pr_err("Failed to allocate %u pages (%lu total), err=%d\n", |
| 465 | 465 | nreal, obj->base.size / PAGE_SIZE, err); |
| @@ -798,7 +798,7 @@ static int wc_set(struct drm_i915_gem_object *obj) · 332 unmodified lines | ||
| 798 | 798 | { |
| 799 | 799 | void *vaddr; |
| 800 | 800 | |
| 801 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 801 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 802 | 802 | if (IS_ERR(vaddr)) |
| 803 | 803 | return PTR_ERR(vaddr); |
| 804 | 804 | |
| @@ -814,7 +814,7 @@ static int wc_check(struct drm_i915_gem_object *obj) · 9 unmodified lines | ||
| 814 | 814 | void *vaddr; |
| 815 | 815 | int err = 0; |
| 816 | 816 | |
| 817 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 817 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 818 | 818 | if (IS_ERR(vaddr)) |
| 819 | 819 | return PTR_ERR(vaddr); |
| 820 | 820 | |
| @@ -835,9 +835,8 @@ static bool can_mmap(struct drm_i915_gem_object *obj, enum i915_mmap_type type) · 14 unmodified lines | ||
| 835 | 835 | return false; |
| 836 | 836 | |
| 837 | 837 | if (type != I915_MMAP_TYPE_GTT && |
| 838 | − !i915_gem_object_type_has(obj, | |
| 839 | − I915_GEM_OBJECT_HAS_STRUCT_PAGE | | |
| 840 | − I915_GEM_OBJECT_HAS_IOMEM)) | |
| 838 | + !i915_gem_object_has_struct_page(obj) && | |
| 839 | + !i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_IOMEM)) | |
| 841 | 840 | return false; |
| 842 | 841 | |
| 843 | 842 | return true; |
| @@ -977,10 +976,8 @@ static const char *repr_mmap_type(enum i915_mmap_type type) · 133 unmodified lines | ||
| 977 | 976 | |
| 978 | 977 | static bool can_access(const struct drm_i915_gem_object *obj) |
| 979 | 978 | { |
| 980 | − unsigned int flags = | |
| 981 | − I915_GEM_OBJECT_HAS_STRUCT_PAGE | I915_GEM_OBJECT_HAS_IOMEM; | |
| 982 | − | |
| 983 | − return i915_gem_object_type_has(obj, flags); | |
| 979 | + return i915_gem_object_has_struct_page(obj) || | |
| 980 | + i915_gem_object_type_has(obj, I915_GEM_OBJECT_HAS_IOMEM); | |
| 984 | 981 | } |
| 985 | 982 | |
| 986 | 983 | static int __igt_mmap_access(struct drm_i915_private *i915, |
| @@ -1319,7 +1316,9 @@ static int __igt_mmap_revoke(struct drm_i915_private *i915, · 332 unmodified lines | ||
| 1319 | 1316 | } |
| 1320 | 1317 | |
| 1321 | 1318 | if (type != I915_MMAP_TYPE_GTT) { |
| 1319 | + i915_gem_object_lock(obj, NULL); | |
| 1322 | 1320 | __i915_gem_object_put_pages(obj); |
| 1321 | + i915_gem_object_unlock(obj); | |
| 1323 | 1322 | if (i915_gem_object_has_pages(obj)) { |
| 1324 | 1323 | pr_err("Failed to put-pages object!\n"); |
| 1325 | 1324 | err = -EINVAL; |
| @@ -47,7 +47,7 @@ static int igt_gem_huge(void *arg) · 46 unmodified lines | ||
| 47 | 47 | if (IS_ERR(obj)) |
| 48 | 48 | return PTR_ERR(obj); |
| 49 | 49 | |
| 50 | − err = i915_gem_object_pin_pages(obj); | |
| 50 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 51 | 51 | if (err) { |
| 52 | 52 | pr_err("Failed to allocate %u pages (%lu total), err=%d\n", |
| 53 | 53 | nreal, obj->base.size / PAGE_SIZE, err); |
| @@ -262,7 +262,7 @@ static int igt_fill_blt_thread(void *arg) · 261 unmodified lines | ||
| 262 | 262 | goto err_flush; |
| 263 | 263 | } |
| 264 | 264 | |
| 265 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 265 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 266 | 266 | if (IS_ERR(vaddr)) { |
| 267 | 267 | err = PTR_ERR(vaddr); |
| 268 | 268 | goto err_put; |
| @@ -380,7 +380,7 @@ static int igt_copy_blt_thread(void *arg) · 111 unmodified lines | ||
| 380 | 380 | goto err_flush; |
| 381 | 381 | } |
| 382 | 382 | |
| 383 | − vaddr = i915_gem_object_pin_map(src, I915_MAP_WB); | |
| 383 | + vaddr = i915_gem_object_pin_map_unlocked(src, I915_MAP_WB); | |
| 384 | 384 | if (IS_ERR(vaddr)) { |
| 385 | 385 | err = PTR_ERR(vaddr); |
| 386 | 386 | goto err_put_src; |
| @@ -400,7 +400,7 @@ static int igt_copy_blt_thread(void *arg) · 13 unmodified lines | ||
| 400 | 400 | goto err_put_src; |
| 401 | 401 | } |
| 402 | 402 | |
| 403 | − vaddr = i915_gem_object_pin_map(dst, I915_MAP_WB); | |
| 403 | + vaddr = i915_gem_object_pin_map_unlocked(dst, I915_MAP_WB); | |
| 404 | 404 | if (IS_ERR(vaddr)) { |
| 405 | 405 | err = PTR_ERR(vaddr); |
| 406 | 406 | goto err_put_dst; |
| @@ -25,13 +25,21 @@ static int mock_phys_object(void *arg) · 24 unmodified lines | ||
| 25 | 25 | goto out; |
| 26 | 26 | } |
| 27 | 27 | |
| 28 | + if (!i915_gem_object_has_struct_page(obj)) { | |
| 29 | + err = -EINVAL; | |
| 30 | + pr_err("shmem has no struct page\n"); | |
| 31 | + goto out_obj; | |
| 32 | + } | |
| 33 | + | |
| 34 | + i915_gem_object_lock(obj, NULL); | |
| 28 | 35 | err = i915_gem_object_attach_phys(obj, PAGE_SIZE); |
| 36 | + i915_gem_object_unlock(obj); | |
| 29 | 37 | if (err) { |
| 30 | 38 | pr_err("i915_gem_object_attach_phys failed, err=%d\n", err); |
| 31 | 39 | goto out_obj; |
| 32 | 40 | } |
| 33 | 41 | |
| 34 | − if (obj->ops != &i915_gem_phys_ops) { | |
| 42 | + if (i915_gem_object_has_struct_page(obj)) { | |
| 35 | 43 | pr_err("i915_gem_object_attach_phys did not create a phys object\n"); |
| 36 | 44 | err = -EINVAL; |
| 37 | 45 | goto out_obj; |
| @@ -55,7 +55,7 @@ igt_emit_store_dw(struct i915_vma *vma, · 54 unmodified lines | ||
| 55 | 55 | if (IS_ERR(obj)) |
| 56 | 56 | return ERR_CAST(obj); |
| 57 | 57 | |
| 58 | − cmd = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 58 | + cmd = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 59 | 59 | if (IS_ERR(cmd)) { |
| 60 | 60 | err = PTR_ERR(cmd); |
| 61 | 61 | goto err; |
| @@ -143,7 +143,7 @@ static u32 *__gen2_emit_breadcrumb(struct i915_request *rq, u32 *cs, · 142 unmodified lines | ||
| 143 | 143 | int flush, int post) |
| 144 | 144 | { |
| 145 | 145 | GEM_BUG_ON(i915_request_active_timeline(rq)->hwsp_ggtt != rq->engine->status_page.vma); |
| 146 | − GEM_BUG_ON(offset_in_page(i915_request_active_timeline(rq)->hwsp_offset) != I915_GEM_HWS_SEQNO_ADDR); | |
| 146 | + GEM_BUG_ON(offset_in_page(rq->hwsp_seqno) != I915_GEM_HWS_SEQNO_ADDR); | |
| 147 | 147 | |
| 148 | 148 | *cs++ = MI_FLUSH; |
| 149 | 149 | |
| @@ -161,7 +161,7 @@ u32 *gen6_emit_breadcrumb_rcs(struct i915_request *rq, u32 *cs) · 160 unmodified lines | ||
| 161 | 161 | PIPE_CONTROL_DC_FLUSH_ENABLE | |
| 162 | 162 | PIPE_CONTROL_QW_WRITE | |
| 163 | 163 | PIPE_CONTROL_CS_STALL); |
| 164 | − *cs++ = i915_request_active_timeline(rq)->hwsp_offset | | |
| 164 | + *cs++ = i915_request_active_seqno(rq) | | |
| 165 | 165 | PIPE_CONTROL_GLOBAL_GTT; |
| 166 | 166 | *cs++ = rq->fence.seqno; |
| 167 | 167 | |
| @@ -359,7 +359,7 @@ u32 *gen7_emit_breadcrumb_rcs(struct i915_request *rq, u32 *cs) · 191 unmodified lines | ||
| 359 | 359 | PIPE_CONTROL_QW_WRITE | |
| 360 | 360 | PIPE_CONTROL_GLOBAL_GTT_IVB | |
| 361 | 361 | PIPE_CONTROL_CS_STALL); |
| 362 | − *cs++ = i915_request_active_timeline(rq)->hwsp_offset; | |
| 362 | + *cs++ = i915_request_active_seqno(rq); | |
| 363 | 363 | *cs++ = rq->fence.seqno; |
| 364 | 364 | |
| 365 | 365 | *cs++ = MI_USER_INTERRUPT; |
| @@ -374,7 +374,7 @@ u32 *gen7_emit_breadcrumb_rcs(struct i915_request *rq, u32 *cs) · 8 unmodified lines | ||
| 374 | 374 | u32 *gen6_emit_breadcrumb_xcs(struct i915_request *rq, u32 *cs) |
| 375 | 375 | { |
| 376 | 376 | GEM_BUG_ON(i915_request_active_timeline(rq)->hwsp_ggtt != rq->engine->status_page.vma); |
| 377 | − GEM_BUG_ON(offset_in_page(i915_request_active_timeline(rq)->hwsp_offset) != I915_GEM_HWS_SEQNO_ADDR); | |
| 377 | + GEM_BUG_ON(offset_in_page(rq->hwsp_seqno) != I915_GEM_HWS_SEQNO_ADDR); | |
| 378 | 378 | |
| 379 | 379 | *cs++ = MI_FLUSH_DW | MI_FLUSH_DW_OP_STOREDW | MI_FLUSH_DW_STORE_INDEX; |
| 380 | 380 | *cs++ = I915_GEM_HWS_SEQNO_ADDR | MI_FLUSH_DW_USE_GTT; |
| @@ -394,7 +394,7 @@ u32 *gen7_emit_breadcrumb_xcs(struct i915_request *rq, u32 *cs) · 13 unmodified lines | ||
| 394 | 394 | int i; |
| 395 | 395 | |
| 396 | 396 | GEM_BUG_ON(i915_request_active_timeline(rq)->hwsp_ggtt != rq->engine->status_page.vma); |
| 397 | − GEM_BUG_ON(offset_in_page(i915_request_active_timeline(rq)->hwsp_offset) != I915_GEM_HWS_SEQNO_ADDR); | |
| 397 | + GEM_BUG_ON(offset_in_page(rq->hwsp_seqno) != I915_GEM_HWS_SEQNO_ADDR); | |
| 398 | 398 | |
| 399 | 399 | *cs++ = MI_FLUSH_DW | MI_INVALIDATE_TLB | |
| 400 | 400 | MI_FLUSH_DW_OP_STOREDW | MI_FLUSH_DW_STORE_INDEX; |
| @@ -338,15 +338,14 @@ static u32 preempt_address(struct intel_engine_cs *engine) · 337 unmodified lines | ||
| 338 | 338 | |
| 339 | 339 | static u32 hwsp_offset(const struct i915_request *rq) |
| 340 | 340 | { |
| 341 | − const struct intel_timeline_cacheline *cl; | |
| 341 | + const struct intel_timeline *tl; | |
| 342 | 342 | |
| 343 | − /* Before the request is executed, the timeline/cachline is fixed */ | |
| 343 | + /* Before the request is executed, the timeline is fixed */ | |
| 344 | + tl = rcu_dereference_protected(rq->timeline, | |
| 345 | + !i915_request_signaled(rq)); | |
| 344 | 346 | |
| 345 | − cl = rcu_dereference_protected(rq->hwsp_cacheline, 1); | |
| 346 | − if (cl) | |
| 347 | − return cl->ggtt_offset; | |
| 348 | − | |
| 349 | − return rcu_dereference_protected(rq->timeline, 1)->hwsp_offset; | |
| 347 | + /* See the comment in i915_request_active_seqno(). */ | |
| 348 | + return page_mask_bits(tl->hwsp_offset) + offset_in_page(rq->hwsp_seqno); | |
| 350 | 349 | } |
| 351 | 350 | |
| 352 | 351 | int gen8_emit_init_breadcrumb(struct i915_request *rq) |
| @@ -6,9 +6,18 @@ · 5 unmodified lines | ||
| 6 | 6 | #ifndef INTEL_CONTEXT_PARAM_H |
| 7 | 7 | #define INTEL_CONTEXT_PARAM_H |
| 8 | 8 | |
| 9 | −struct intel_context; | |
| 9 | +#include <linux/types.h> | |
| 10 | + | |
| 11 | +#include "intel_context.h" | |
| 10 | 12 | |
| 11 | 13 | int intel_context_set_ring_size(struct intel_context *ce, long sz); |
| 12 | 14 | long intel_context_get_ring_size(struct intel_context *ce); |
| 13 | 15 | |
| 16 | +static inline int | |
| 17 | +intel_context_set_watchdog_us(struct intel_context *ce, u64 timeout_us) | |
| 18 | +{ | |
| 19 | + ce->watchdog.timeout_us = timeout_us; | |
| 20 | + return 0; | |
| 21 | +} | |
| 22 | + | |
| 14 | 23 | #endif /* INTEL_CONTEXT_PARAM_H */ |
| @@ -97,6 +97,10 @@ struct intel_context { · 96 unmodified lines | ||
| 97 | 97 | #define CONTEXT_FORCE_SINGLE_SUBMISSION 7 |
| 98 | 98 | #define CONTEXT_NOPREEMPT 8 |
| 99 | 99 | |
| 100 | + struct { | |
| 101 | + u64 timeout_us; | |
| 102 | + } watchdog; | |
| 103 | + | |
| 100 | 104 | u32 *lrc_reg_state; |
| 101 | 105 | union { |
| 102 | 106 | struct { |
| @@ -619,6 +619,7 @@ static void cleanup_status_page(struct intel_engine_cs *engine) · 618 unmodified lines | ||
| 619 | 619 | } |
| 620 | 620 | |
| 621 | 621 | static int pin_ggtt_status_page(struct intel_engine_cs *engine, |
| 622 | + struct i915_gem_ww_ctx *ww, | |
| 622 | 623 | struct i915_vma *vma) |
| 623 | 624 | { |
| 624 | 625 | unsigned int flags; |
| @@ -639,12 +640,13 @@ static int pin_ggtt_status_page(struct intel_engine_cs *engine, · 14 unmodified lines | ||
| 639 | 640 | else |
| 640 | 641 | flags = PIN_HIGH; |
| 641 | 642 | |
| 642 | − return i915_ggtt_pin(vma, NULL, 0, flags); | |
| 643 | + return i915_ggtt_pin(vma, ww, 0, flags); | |
| 643 | 644 | } |
| 644 | 645 | |
| 645 | 646 | static int init_status_page(struct intel_engine_cs *engine) |
| 646 | 647 | { |
| 647 | 648 | struct drm_i915_gem_object *obj; |
| 649 | + struct i915_gem_ww_ctx ww; | |
| 648 | 650 | struct i915_vma *vma; |
| 649 | 651 | void *vaddr; |
| 650 | 652 | int ret; |
| @@ -670,30 +672,39 @@ static int init_status_page(struct intel_engine_cs *engine) · 19 unmodified lines | ||
| 670 | 672 | vma = i915_vma_instance(obj, &engine->gt->ggtt->vm, NULL); |
| 671 | 673 | if (IS_ERR(vma)) { |
| 672 | 674 | ret = PTR_ERR(vma); |
| 673 | − goto err; | |
| 675 | + goto err_put; | |
| 674 | 676 | } |
| 675 | 677 | |
| 678 | + i915_gem_ww_ctx_init(&ww, true); | |
| 679 | +retry: | |
| 680 | + ret = i915_gem_object_lock(obj, &ww); | |
| 681 | + if (!ret && !HWS_NEEDS_PHYSICAL(engine->i915)) | |
| 682 | + ret = pin_ggtt_status_page(engine, &ww, vma); | |
| 683 | + if (ret) | |
| 684 | + goto err; | |
| 685 | + | |
| 676 | 686 | vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); |
| 677 | 687 | if (IS_ERR(vaddr)) { |
| 678 | 688 | ret = PTR_ERR(vaddr); |
| 679 | − goto err; | |
| 689 | + goto err_unpin; | |
| 680 | 690 | } |
| 681 | 691 | |
| 682 | 692 | engine->status_page.addr = memset(vaddr, 0, PAGE_SIZE); |
| 683 | 693 | engine->status_page.vma = vma; |
| 684 | 694 | |
| 685 | − if (!HWS_NEEDS_PHYSICAL(engine->i915)) { | |
| 686 | − ret = pin_ggtt_status_page(engine, vma); | |
| 687 | − if (ret) | |
| 688 | − goto err_unpin; | |
| 689 | − } | |
| 690 | − | |
| 691 | − return 0; | |
| 692 | − | |
| 693 | 695 | err_unpin: |
| 694 | − i915_gem_object_unpin_map(obj); | |
| 696 | + if (ret) | |
| 697 | + i915_vma_unpin(vma); | |
| 695 | 698 | err: |
| 696 | − i915_gem_object_put(obj); | |
| 699 | + if (ret == -EDEADLK) { | |
| 700 | + ret = i915_gem_ww_ctx_backoff(&ww); | |
| 701 | + if (!ret) | |
| 702 | + goto retry; | |
| 703 | + } | |
| 704 | + i915_gem_ww_ctx_fini(&ww); | |
| 705 | +err_put: | |
| 706 | + if (ret) | |
| 707 | + i915_gem_object_put(obj); | |
| 697 | 708 | return ret; |
| 698 | 709 | } |
| 699 | 710 | |
| @@ -763,6 +774,7 @@ static int measure_breadcrumb_dw(struct intel_context *ce) · 63 unmodified lines | ||
| 763 | 774 | frame->rq.engine = engine; |
| 764 | 775 | frame->rq.context = ce; |
| 765 | 776 | rcu_assign_pointer(frame->rq.timeline, ce->timeline); |
| 777 | + frame->rq.hwsp_seqno = ce->timeline->hwsp_seqno; | |
| 766 | 778 | |
| 767 | 779 | frame->ring.vaddr = frame->cs; |
| 768 | 780 | frame->ring.size = sizeof(frame->cs); |
| @@ -279,6 +279,7 @@ int intel_engine_pulse(struct intel_engine_cs *engine) · 278 unmodified lines | ||
| 279 | 279 | mutex_unlock(&ce->timeline->mutex); |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | + intel_engine_flush_submission(engine); | |
| 282 | 283 | intel_engine_pm_put(engine); |
| 283 | 284 | return err; |
| 284 | 285 | } |
| @@ -27,12 +27,16 @@ static void dbg_poison_ce(struct intel_context *ce) · 26 unmodified lines | ||
| 27 | 27 | int type = i915_coherent_map_type(ce->engine->i915); |
| 28 | 28 | void *map; |
| 29 | 29 | |
| 30 | + if (!i915_gem_object_trylock(obj)) | |
| 31 | + return; | |
| 32 | + | |
| 30 | 33 | map = i915_gem_object_pin_map(obj, type); |
| 31 | 34 | if (!IS_ERR(map)) { |
| 32 | 35 | memset(map, CONTEXT_REDZONE, obj->base.size); |
| 33 | 36 | i915_gem_object_flush_map(obj); |
| 34 | 37 | i915_gem_object_unpin_map(obj); |
| 35 | 38 | } |
| 39 | + i915_gem_object_unlock(obj); | |
| 36 | 40 | } |
| 37 | 41 | } |
| 38 | 42 | |
| @@ -470,6 +470,11 @@ static void reset_active(struct i915_request *rq, · 469 unmodified lines | ||
| 470 | 470 | ce->lrc.lrca = lrc_update_regs(ce, engine, head); |
| 471 | 471 | } |
| 472 | 472 | |
| 473 | +static bool bad_request(const struct i915_request *rq) | |
| 474 | +{ | |
| 475 | + return rq->fence.error && i915_request_started(rq); | |
| 476 | +} | |
| 477 | + | |
| 473 | 478 | static struct intel_engine_cs * |
| 474 | 479 | __execlists_schedule_in(struct i915_request *rq) |
| 475 | 480 | { |
| @@ -482,7 +487,7 @@ __execlists_schedule_in(struct i915_request *rq) · 6 unmodified lines | ||
| 482 | 487 | !intel_engine_has_heartbeat(engine))) |
| 483 | 488 | intel_context_set_banned(ce); |
| 484 | 489 | |
| 485 | − if (unlikely(intel_context_is_banned(ce))) | |
| 490 | + if (unlikely(intel_context_is_banned(ce) || bad_request(rq))) | |
| 486 | 491 | reset_active(rq, engine); |
| 487 | 492 | |
| 488 | 493 | if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) |
| @@ -752,9 +757,8 @@ assert_pending_valid(const struct intel_engine_execlists *execlists, · 263 unmodified lines | ||
| 752 | 757 | { |
| 753 | 758 | struct intel_engine_cs *engine = |
| 754 | 759 | container_of(execlists, typeof(*engine), execlists); |
| 755 | − struct i915_request * const *port, *rq; | |
| 760 | + struct i915_request * const *port, *rq, *prev = NULL; | |
| 756 | 761 | struct intel_context *ce = NULL; |
| 757 | − bool sentinel = false; | |
| 758 | 762 | u32 ccid = -1; |
| 759 | 763 | |
| 760 | 764 | trace_ports(execlists, msg, execlists->pending); |
| @@ -804,15 +808,20 @@ assert_pending_valid(const struct intel_engine_execlists *execlists, · 43 unmodified lines | ||
| 804 | 808 | * Sentinels are supposed to be the last request so they flush |
| 805 | 809 | * the current execution off the HW. Check that they are the only |
| 806 | 810 | * request in the pending submission. |
| 811 | + * | |
| 812 | + * NB: Due to the async nature of preempt-to-busy and request | |
| 813 | + * cancellation we need to handle the case where request | |
| 814 | + * becomes a sentinel in parallel to CSB processing. | |
| 807 | 815 | */ |
| 808 | − if (sentinel) { | |
| 816 | + if (prev && i915_request_has_sentinel(prev) && | |
| 817 | + !READ_ONCE(prev->fence.error)) { | |
| 809 | 818 | GEM_TRACE_ERR("%s: context:%llx after sentinel in pending[%zd]\n", |
| 810 | 819 | engine->name, |
| 811 | 820 | ce->timeline->fence_context, |
| 812 | 821 | port - execlists->pending); |
| 813 | 822 | return false; |
| 814 | 823 | } |
| 815 | − sentinel = i915_request_has_sentinel(rq); | |
| 824 | + prev = rq; | |
| 816 | 825 | |
| 817 | 826 | /* |
| 818 | 827 | * We want virtual requests to only be in the first slot so |
| @@ -948,7 +957,7 @@ static bool can_merge_rq(const struct i915_request *prev, · 129 unmodified lines | ||
| 948 | 957 | if (__i915_request_is_complete(next)) |
| 949 | 958 | return true; |
| 950 | 959 | |
| 951 | − if (unlikely((i915_request_flags(prev) ^ i915_request_flags(next)) & | |
| 960 | + if (unlikely((i915_request_flags(prev) | i915_request_flags(next)) & | |
| 952 | 961 | (BIT(I915_FENCE_FLAG_NOPREEMPT) | |
| 953 | 962 | BIT(I915_FENCE_FLAG_SENTINEL)))) |
| 954 | 963 | return false; |
| @@ -1208,7 +1217,7 @@ static unsigned long active_preempt_timeout(struct intel_engine_cs *engine, · 253 unmodified lines | ||
| 1208 | 1217 | return 0; |
| 1209 | 1218 | |
| 1210 | 1219 | /* Force a fast reset for terminated contexts (ignoring sysfs!) */ |
| 1211 | − if (unlikely(intel_context_is_banned(rq->context))) | |
| 1220 | + if (unlikely(intel_context_is_banned(rq->context) || bad_request(rq))) | |
| 1212 | 1221 | return 1; |
| 1213 | 1222 | |
| 1214 | 1223 | return READ_ONCE(engine->props.preempt_timeout_ms); |
| @@ -2457,11 +2466,31 @@ static void execlists_submit_request(struct i915_request *request) · 1242 unmodified lines | ||
| 2457 | 2466 | spin_unlock_irqrestore(&engine->active.lock, flags); |
| 2458 | 2467 | } |
| 2459 | 2468 | |
| 2469 | +static int | |
| 2470 | +__execlists_context_pre_pin(struct intel_context *ce, | |
| 2471 | + struct intel_engine_cs *engine, | |
| 2472 | + struct i915_gem_ww_ctx *ww, void **vaddr) | |
| 2473 | +{ | |
| 2474 | + int err; | |
| 2475 | + | |
| 2476 | + err = lrc_pre_pin(ce, engine, ww, vaddr); | |
| 2477 | + if (err) | |
| 2478 | + return err; | |
| 2479 | + | |
| 2480 | + if (!__test_and_set_bit(CONTEXT_INIT_BIT, &ce->flags)) { | |
| 2481 | + lrc_init_state(ce, engine, *vaddr); | |
| 2482 | + | |
| 2483 | + __i915_gem_object_flush_map(ce->state->obj, 0, engine->context_size); | |
| 2484 | + } | |
| 2485 | + | |
| 2486 | + return 0; | |
| 2487 | +} | |
| 2488 | + | |
| 2460 | 2489 | static int execlists_context_pre_pin(struct intel_context *ce, |
| 2461 | 2490 | struct i915_gem_ww_ctx *ww, |
| 2462 | 2491 | void **vaddr) |
| 2463 | 2492 | { |
| 2464 | − return lrc_pre_pin(ce, ce->engine, ww, vaddr); | |
| 2493 | + return __execlists_context_pre_pin(ce, ce->engine, ww, vaddr); | |
| 2465 | 2494 | } |
| 2466 | 2495 | |
| 2467 | 2496 | static int execlists_context_pin(struct intel_context *ce, void *vaddr) |
| @@ -3365,8 +3394,8 @@ static int virtual_context_pre_pin(struct intel_context *ce, · 897 unmodified lines | ||
| 3365 | 3394 | { |
| 3366 | 3395 | struct virtual_engine *ve = container_of(ce, typeof(*ve), context); |
| 3367 | 3396 | |
| 3368 | − /* Note: we must use a real engine class for setting up reg state */ | |
| 3369 | − return lrc_pre_pin(ce, ve->siblings[0], ww, vaddr); | |
| 3397 | + /* Note: we must use a real engine class for setting up reg state */ | |
| 3398 | + return __execlists_context_pre_pin(ce, ve->siblings[0], ww, vaddr); | |
| 3370 | 3399 | } |
| 3371 | 3400 | |
| 3372 | 3401 | static int virtual_context_pin(struct intel_context *ce, void *vaddr) |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #ifndef __INTEL_EXECLISTS_SUBMISSION_H__ |
| 7 | 7 | #define __INTEL_EXECLISTS_SUBMISSION_H__ |
| 8 | 8 | |
| 9 | +#include <linux/llist.h> | |
| 9 | 10 | #include <linux/types.h> |
| 10 | 11 | |
| 11 | 12 | struct drm_printer; |
| @@ -13,6 +14,7 @@ struct drm_printer; · 1 unmodified line | ||
| 13 | 14 | struct i915_request; |
| 14 | 15 | struct intel_context; |
| 15 | 16 | struct intel_engine_cs; |
| 17 | +struct intel_gt; | |
| 16 | 18 | |
| 17 | 19 | enum { |
| 18 | 20 | INTEL_CONTEXT_SCHEDULE_IN = 0, |
| @@ -647,7 +647,9 @@ static int init_aliasing_ppgtt(struct i915_ggtt *ggtt) · 646 unmodified lines | ||
| 647 | 647 | if (err) |
| 648 | 648 | goto err_ppgtt; |
| 649 | 649 | |
| 650 | + i915_gem_object_lock(ppgtt->vm.scratch[0], NULL); | |
| 650 | 651 | err = i915_vm_pin_pt_stash(&ppgtt->vm, &stash); |
| 652 | + i915_gem_object_unlock(ppgtt->vm.scratch[0]); | |
| 651 | 653 | if (err) |
| 652 | 654 | goto err_stash; |
| 653 | 655 | |
| @@ -734,6 +736,7 @@ static void ggtt_cleanup_hw(struct i915_ggtt *ggtt) · 80 unmodified lines | ||
| 734 | 736 | |
| 735 | 737 | mutex_unlock(&ggtt->vm.mutex); |
| 736 | 738 | i915_address_space_fini(&ggtt->vm); |
| 739 | + dma_resv_fini(&ggtt->vm.resv); | |
| 737 | 740 | |
| 738 | 741 | arch_phys_wc_del(ggtt->mtrr); |
| 739 | 742 | |
| @@ -1115,6 +1118,7 @@ static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt) · 375 unmodified lines | ||
| 1115 | 1118 | ggtt->vm.gt = gt; |
| 1116 | 1119 | ggtt->vm.i915 = i915; |
| 1117 | 1120 | ggtt->vm.dma = i915->drm.dev; |
| 1121 | + dma_resv_init(&ggtt->vm.resv); | |
| 1118 | 1122 | |
| 1119 | 1123 | if (INTEL_GEN(i915) <= 5) |
| 1120 | 1124 | ret = i915_gmch_probe(ggtt); |
| @@ -1122,8 +1126,10 @@ static int ggtt_probe_hw(struct i915_ggtt *ggtt, struct intel_gt *gt) · 1 unmodified line | ||
| 1122 | 1126 | ret = gen6_gmch_probe(ggtt); |
| 1123 | 1127 | else |
| 1124 | 1128 | ret = gen8_gmch_probe(ggtt); |
| 1125 | − if (ret) | |
| 1129 | + if (ret) { | |
| 1130 | + dma_resv_fini(&ggtt->vm.resv); | |
| 1126 | 1131 | return ret; |
| 1132 | + } | |
| 1127 | 1133 | |
| 1128 | 1134 | if ((ggtt->vm.total - 1) >> 32) { |
| 1129 | 1135 | drm_err(&i915->drm, |
| @@ -1420,7 +1426,7 @@ intel_partial_pages(const struct i915_ggtt_view *view, · 290 unmodified lines | ||
| 1420 | 1426 | if (ret) |
| 1421 | 1427 | goto err_sg_alloc; |
| 1422 | 1428 | |
| 1423 | − iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset); | |
| 1429 | + iter = i915_gem_object_get_sg_dma(obj, view->partial.offset, &offset, true); | |
| 1424 | 1430 | GEM_BUG_ON(!iter); |
| 1425 | 1431 | |
| 1426 | 1432 | sg = st->sgl; |
| @@ -29,6 +29,9 @@ void intel_gt_init_early(struct intel_gt *gt, struct drm_i915_private *i915) · 28 unmodified lines | ||
| 29 | 29 | INIT_LIST_HEAD(>->closed_vma); |
| 30 | 30 | spin_lock_init(>->closed_lock); |
| 31 | 31 | |
| 32 | + init_llist_head(>->watchdog.list); | |
| 33 | + INIT_WORK(>->watchdog.work, intel_gt_watchdog_work); | |
| 34 | + | |
| 32 | 35 | intel_gt_init_buffer_pool(gt); |
| 33 | 36 | intel_gt_init_reset(gt); |
| 34 | 37 | intel_gt_init_requests(gt); |
| @@ -77,4 +77,6 @@ static inline bool intel_gt_is_wedged(const struct intel_gt *gt) · 76 unmodified lines | ||
| 77 | 77 | void intel_gt_info_print(const struct intel_gt_info *info, |
| 78 | 78 | struct drm_printer *p); |
| 79 | 79 | |
| 80 | +void intel_gt_watchdog_work(struct work_struct *work); | |
| 81 | + | |
| 80 | 82 | #endif /* __INTEL_GT_H__ */ |
| @@ -98,28 +98,6 @@ static void pool_free_work(struct work_struct *wrk) · 97 unmodified lines | ||
| 98 | 98 | round_jiffies_up_relative(HZ)); |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | −static int pool_active(struct i915_active *ref) | |
| 102 | −{ | |
| 103 | − struct intel_gt_buffer_pool_node *node = | |
| 104 | − container_of(ref, typeof(*node), active); | |
| 105 | − struct dma_resv *resv = node->obj->base.resv; | |
| 106 | − int err; | |
| 107 | − | |
| 108 | − if (dma_resv_trylock(resv)) { | |
| 109 | − dma_resv_add_excl_fence(resv, NULL); | |
| 110 | − dma_resv_unlock(resv); | |
| 111 | − } | |
| 112 | − | |
| 113 | − err = i915_gem_object_pin_pages(node->obj); | |
| 114 | − if (err) | |
| 115 | − return err; | |
| 116 | − | |
| 117 | − /* Hide this pinned object from the shrinker until retired */ | |
| 118 | − i915_gem_object_make_unshrinkable(node->obj); | |
| 119 | − | |
| 120 | − return 0; | |
| 121 | −} | |
| 122 | − | |
| 123 | 101 | __i915_active_call |
| 124 | 102 | static void pool_retire(struct i915_active *ref) |
| 125 | 103 | { |
| @@ -129,10 +107,13 @@ static void pool_retire(struct i915_active *ref) · 3 unmodified lines | ||
| 129 | 107 | struct list_head *list = bucket_for_size(pool, node->obj->base.size); |
| 130 | 108 | unsigned long flags; |
| 131 | 109 | |
| 132 | − i915_gem_object_unpin_pages(node->obj); | |
| 110 | + if (node->pinned) { | |
| 111 | + i915_gem_object_unpin_pages(node->obj); | |
| 133 | 112 | |
| 134 | − /* Return this object to the shrinker pool */ | |
| 135 | − i915_gem_object_make_purgeable(node->obj); | |
| 113 | + /* Return this object to the shrinker pool */ | |
| 114 | + i915_gem_object_make_purgeable(node->obj); | |
| 115 | + node->pinned = false; | |
| 116 | + } | |
| 136 | 117 | |
| 137 | 118 | GEM_BUG_ON(node->age); |
| 138 | 119 | spin_lock_irqsave(&pool->lock, flags); |
| @@ -144,6 +125,19 @@ static void pool_retire(struct i915_active *ref) · 5 unmodified lines | ||
| 144 | 125 | round_jiffies_up_relative(HZ)); |
| 145 | 126 | } |
| 146 | 127 | |
| 128 | +void intel_gt_buffer_pool_mark_used(struct intel_gt_buffer_pool_node *node) | |
| 129 | +{ | |
| 130 | + assert_object_held(node->obj); | |
| 131 | + | |
| 132 | + if (node->pinned) | |
| 133 | + return; | |
| 134 | + | |
| 135 | + __i915_gem_object_pin_pages(node->obj); | |
| 136 | + /* Hide this pinned object from the shrinker until retired */ | |
| 137 | + i915_gem_object_make_unshrinkable(node->obj); | |
| 138 | + node->pinned = true; | |
| 139 | +} | |
| 140 | + | |
| 147 | 141 | static struct intel_gt_buffer_pool_node * |
| 148 | 142 | node_create(struct intel_gt_buffer_pool *pool, size_t sz, |
| 149 | 143 | enum i915_map_type type) |
| @@ -159,7 +153,8 @@ node_create(struct intel_gt_buffer_pool *pool, size_t sz, · 9 unmodified lines | ||
| 159 | 153 | |
| 160 | 154 | node->age = 0; |
| 161 | 155 | node->pool = pool; |
| 162 | − i915_active_init(&node->active, pool_active, pool_retire); | |
| 156 | + node->pinned = false; | |
| 157 | + i915_active_init(&node->active, NULL, pool_retire); | |
| 163 | 158 | |
| 164 | 159 | obj = i915_gem_object_create_internal(gt->i915, sz); |
| 165 | 160 | if (IS_ERR(obj)) { |
| @@ -18,10 +18,15 @@ struct intel_gt_buffer_pool_node * · 17 unmodified lines | ||
| 18 | 18 | intel_gt_get_buffer_pool(struct intel_gt *gt, size_t size, |
| 19 | 19 | enum i915_map_type type); |
| 20 | 20 | |
| 21 | +void intel_gt_buffer_pool_mark_used(struct intel_gt_buffer_pool_node *node); | |
| 22 | + | |
| 21 | 23 | static inline int |
| 22 | 24 | intel_gt_buffer_pool_mark_active(struct intel_gt_buffer_pool_node *node, |
| 23 | 25 | struct i915_request *rq) |
| 24 | 26 | { |
| 27 | + /* did we call mark_used? */ | |
| 28 | + GEM_WARN_ON(!node->pinned); | |
| 29 | + | |
| 25 | 30 | return i915_active_add_request(&node->active, rq); |
| 26 | 31 | } |
| 27 | 32 | |
| @@ -31,6 +31,7 @@ struct intel_gt_buffer_pool_node { · 30 unmodified lines | ||
| 31 | 31 | }; |
| 32 | 32 | unsigned long age; |
| 33 | 33 | enum i915_map_type type; |
| 34 | + u32 pinned; | |
| 34 | 35 | }; |
| 35 | 36 | |
| 36 | 37 | #endif /* INTEL_GT_BUFFER_POOL_TYPES_H */ |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "i915_drv.h" /* for_each_engine() */ |
| 10 | 10 | #include "i915_request.h" |
| 11 | 11 | #include "intel_engine_heartbeat.h" |
| 12 | +#include "intel_execlists_submission.h" | |
| 12 | 13 | #include "intel_gt.h" |
| 13 | 14 | #include "intel_gt_pm.h" |
| 14 | 15 | #include "intel_gt_requests.h" |
| @@ -243,4 +244,31 @@ void intel_gt_fini_requests(struct intel_gt *gt) · 228 unmodified lines | ||
| 243 | 244 | { |
| 244 | 245 | /* Wait until the work is marked as finished before unloading! */ |
| 245 | 246 | cancel_delayed_work_sync(>->requests.retire_work); |
| 247 | + | |
| 248 | + flush_work(>->watchdog.work); | |
| 249 | +} | |
| 250 | + | |
| 251 | +void intel_gt_watchdog_work(struct work_struct *work) | |
| 252 | +{ | |
| 253 | + struct intel_gt *gt = | |
| 254 | + container_of(work, typeof(*gt), watchdog.work); | |
| 255 | + struct i915_request *rq, *rn; | |
| 256 | + struct llist_node *first; | |
| 257 | + | |
| 258 | + first = llist_del_all(>->watchdog.list); | |
| 259 | + if (!first) | |
| 260 | + return; | |
| 261 | + | |
| 262 | + llist_for_each_entry_safe(rq, rn, first, watchdog.link) { | |
| 263 | + if (!i915_request_completed(rq)) { | |
| 264 | + struct dma_fence *f = &rq->fence; | |
| 265 | + | |
| 266 | + pr_notice("Fence expiration time out i915-%s:%s:%llx!\n", | |
| 267 | + f->ops->get_driver_name(f), | |
| 268 | + f->ops->get_timeline_name(f), | |
| 269 | + f->seqno); | |
| 270 | + i915_request_cancel(rq, -EINTR); | |
| 271 | + } | |
| 272 | + i915_request_put(rq); | |
| 273 | + } | |
| 246 | 274 | } |
| @@ -8,10 +8,12 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | #include <linux/ktime.h> |
| 10 | 10 | #include <linux/list.h> |
| 11 | +#include <linux/llist.h> | |
| 11 | 12 | #include <linux/mutex.h> |
| 12 | 13 | #include <linux/notifier.h> |
| 13 | 14 | #include <linux/spinlock.h> |
| 14 | 15 | #include <linux/types.h> |
| 16 | +#include <linux/workqueue.h> | |
| 15 | 17 | |
| 16 | 18 | #include "uc/intel_uc.h" |
| 17 | 19 | |
| @@ -39,10 +41,6 @@ struct intel_gt { · 21 unmodified lines | ||
| 39 | 41 | struct intel_gt_timelines { |
| 40 | 42 | spinlock_t lock; /* protects active_list */ |
| 41 | 43 | struct list_head active_list; |
| 42 | − | |
| 43 | − /* Pack multiple timelines' seqnos into the same page */ | |
| 44 | − spinlock_t hwsp_lock; | |
| 45 | − struct list_head hwsp_free_list; | |
| 46 | 44 | } timelines; |
| 47 | 45 | |
| 48 | 46 | struct intel_gt_requests { |
| @@ -56,6 +54,11 @@ struct intel_gt { · 7 unmodified lines | ||
| 56 | 54 | struct delayed_work retire_work; |
| 57 | 55 | } requests; |
| 58 | 56 | |
| 57 | + struct { | |
| 58 | + struct llist_head list; | |
| 59 | + struct work_struct work; | |
| 60 | + } watchdog; | |
| 61 | + | |
| 59 | 62 | struct intel_wakeref wakeref; |
| 60 | 63 | atomic_t user_wakeref; |
| 61 | 64 | |
| @@ -13,16 +13,36 @@ · 12 unmodified lines | ||
| 13 | 13 | |
| 14 | 14 | struct drm_i915_gem_object *alloc_pt_dma(struct i915_address_space *vm, int sz) |
| 15 | 15 | { |
| 16 | + struct drm_i915_gem_object *obj; | |
| 17 | + | |
| 16 | 18 | if (I915_SELFTEST_ONLY(should_fail(&vm->fault_attr, 1))) |
| 17 | 19 | i915_gem_shrink_all(vm->i915); |
| 18 | 20 | |
| 19 | − return i915_gem_object_create_internal(vm->i915, sz); | |
| 21 | + obj = i915_gem_object_create_internal(vm->i915, sz); | |
| 22 | + /* ensure all dma objects have the same reservation class */ | |
| 23 | + if (!IS_ERR(obj)) | |
| 24 | + obj->base.resv = &vm->resv; | |
| 25 | + return obj; | |
| 20 | 26 | } |
| 21 | 27 | |
| 22 | 28 | int pin_pt_dma(struct i915_address_space *vm, struct drm_i915_gem_object *obj) |
| 23 | 29 | { |
| 24 | 30 | int err; |
| 25 | 31 | |
| 32 | + i915_gem_object_lock(obj, NULL); | |
| 33 | + err = i915_gem_object_pin_pages(obj); | |
| 34 | + i915_gem_object_unlock(obj); | |
| 35 | + if (err) | |
| 36 | + return err; | |
| 37 | + | |
| 38 | + i915_gem_object_make_unshrinkable(obj); | |
| 39 | + return 0; | |
| 40 | +} | |
| 41 | + | |
| 42 | +int pin_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object *obj) | |
| 43 | +{ | |
| 44 | + int err; | |
| 45 | + | |
| 26 | 46 | err = i915_gem_object_pin_pages(obj); |
| 27 | 47 | if (err) |
| 28 | 48 | return err; |
| @@ -56,6 +76,20 @@ void __i915_vm_close(struct i915_address_space *vm) · 27 unmodified lines | ||
| 56 | 76 | mutex_unlock(&vm->mutex); |
| 57 | 77 | } |
| 58 | 78 | |
| 79 | +/* lock the vm into the current ww, if we lock one, we lock all */ | |
| 80 | +int i915_vm_lock_objects(struct i915_address_space *vm, | |
| 81 | + struct i915_gem_ww_ctx *ww) | |
| 82 | +{ | |
| 83 | + if (vm->scratch[0]->base.resv == &vm->resv) { | |
| 84 | + return i915_gem_object_lock(vm->scratch[0], ww); | |
| 85 | + } else { | |
| 86 | + struct i915_ppgtt *ppgtt = i915_vm_to_ppgtt(vm); | |
| 87 | + | |
| 88 | + /* We borrowed the scratch page from ggtt, take the top level object */ | |
| 89 | + return i915_gem_object_lock(ppgtt->pd->pt.base, ww); | |
| 90 | + } | |
| 91 | +} | |
| 92 | + | |
| 59 | 93 | void i915_address_space_fini(struct i915_address_space *vm) |
| 60 | 94 | { |
| 61 | 95 | drm_mm_takedown(&vm->mm); |
| @@ -69,6 +103,7 @@ static void __i915_vm_release(struct work_struct *work) · 7 unmodified lines | ||
| 69 | 103 | |
| 70 | 104 | vm->cleanup(vm); |
| 71 | 105 | i915_address_space_fini(vm); |
| 106 | + dma_resv_fini(&vm->resv); | |
| 72 | 107 | |
| 73 | 108 | kfree(vm); |
| 74 | 109 | } |
| @@ -98,6 +133,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass) · 23 unmodified lines | ||
| 98 | 133 | mutex_init(&vm->mutex); |
| 99 | 134 | lockdep_set_subclass(&vm->mutex, subclass); |
| 100 | 135 | i915_gem_shrinker_taints_mutex(vm->i915, &vm->mutex); |
| 136 | + dma_resv_init(&vm->resv); | |
| 101 | 137 | |
| 102 | 138 | GEM_BUG_ON(!vm->total); |
| 103 | 139 | drm_mm_init(&vm->mm, 0, vm->total); |
| @@ -427,7 +463,6 @@ __vm_create_scratch_for_read(struct i915_address_space *vm, unsigned long size) · 323 unmodified lines | ||
| 427 | 463 | { |
| 428 | 464 | struct drm_i915_gem_object *obj; |
| 429 | 465 | struct i915_vma *vma; |
| 430 | − int err; | |
| 431 | 466 | |
| 432 | 467 | obj = i915_gem_object_create_internal(vm->i915, PAGE_ALIGN(size)); |
| 433 | 468 | if (IS_ERR(obj)) |
| @@ -441,6 +476,19 @@ __vm_create_scratch_for_read(struct i915_address_space *vm, unsigned long size) · 7 unmodified lines | ||
| 441 | 476 | return vma; |
| 442 | 477 | } |
| 443 | 478 | |
| 479 | + return vma; | |
| 480 | +} | |
| 481 | + | |
| 482 | +struct i915_vma * | |
| 483 | +__vm_create_scratch_for_read_pinned(struct i915_address_space *vm, unsigned long size) | |
| 484 | +{ | |
| 485 | + struct i915_vma *vma; | |
| 486 | + int err; | |
| 487 | + | |
| 488 | + vma = __vm_create_scratch_for_read(vm, size); | |
| 489 | + if (IS_ERR(vma)) | |
| 490 | + return vma; | |
| 491 | + | |
| 444 | 492 | err = i915_vma_pin(vma, 0, 0, |
| 445 | 493 | i915_vma_is_ggtt(vma) ? PIN_GLOBAL : PIN_USER); |
| 446 | 494 | if (err) { |
| @@ -238,6 +238,7 @@ struct i915_address_space { · 237 unmodified lines | ||
| 238 | 238 | atomic_t open; |
| 239 | 239 | |
| 240 | 240 | struct mutex mutex; /* protects vma and our lists */ |
| 241 | + struct dma_resv resv; /* reservation lock for all pd objects, and buffer pool */ | |
| 241 | 242 | #define VM_CLASS_GGTT 0 |
| 242 | 243 | #define VM_CLASS_PPGTT 1 |
| 243 | 244 | |
| @@ -346,6 +347,9 @@ struct i915_ppgtt { · 102 unmodified lines | ||
| 346 | 347 | |
| 347 | 348 | #define i915_is_ggtt(vm) ((vm)->is_ggtt) |
| 348 | 349 | |
| 350 | +int __must_check | |
| 351 | +i915_vm_lock_objects(struct i915_address_space *vm, struct i915_gem_ww_ctx *ww); | |
| 352 | + | |
| 349 | 353 | static inline bool |
| 350 | 354 | i915_vm_is_4lvl(const struct i915_address_space *vm) |
| 351 | 355 | { |
| @@ -522,6 +526,7 @@ struct i915_page_directory *alloc_pd(struct i915_address_space *vm); · 170 unmodified lines | ||
| 522 | 526 | struct i915_page_directory *__alloc_pd(int npde); |
| 523 | 527 | |
| 524 | 528 | int pin_pt_dma(struct i915_address_space *vm, struct drm_i915_gem_object *obj); |
| 529 | +int pin_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object *obj); | |
| 525 | 530 | |
| 526 | 531 | void free_px(struct i915_address_space *vm, |
| 527 | 532 | struct i915_page_table *pt, int lvl); |
| @@ -576,6 +581,9 @@ void i915_vm_free_pt_stash(struct i915_address_space *vm, · 48 unmodified lines | ||
| 576 | 581 | struct i915_vma * |
| 577 | 582 | __vm_create_scratch_for_read(struct i915_address_space *vm, unsigned long size); |
| 578 | 583 | |
| 584 | +struct i915_vma * | |
| 585 | +__vm_create_scratch_for_read_pinned(struct i915_address_space *vm, unsigned long size); | |
| 586 | + | |
| 579 | 587 | static inline struct sgt_dma { |
| 580 | 588 | struct scatterlist *sg; |
| 581 | 589 | dma_addr_t dma, max; |
| @@ -1417,7 +1417,7 @@ gen10_init_indirectctx_bb(struct intel_engine_cs *engine, u32 *batch) · 1416 unmodified lines | ||
| 1417 | 1417 | |
| 1418 | 1418 | #define CTX_WA_BB_SIZE (PAGE_SIZE) |
| 1419 | 1419 | |
| 1420 | −static int lrc_setup_wa_ctx(struct intel_engine_cs *engine) | |
| 1420 | +static int lrc_create_wa_ctx(struct intel_engine_cs *engine) | |
| 1421 | 1421 | { |
| 1422 | 1422 | struct drm_i915_gem_object *obj; |
| 1423 | 1423 | struct i915_vma *vma; |
| @@ -1433,10 +1433,6 @@ static int lrc_setup_wa_ctx(struct intel_engine_cs *engine) · 9 unmodified lines | ||
| 1433 | 1433 | goto err; |
| 1434 | 1434 | } |
| 1435 | 1435 | |
| 1436 | − err = i915_ggtt_pin(vma, NULL, 0, PIN_HIGH); | |
| 1437 | − if (err) | |
| 1438 | − goto err; | |
| 1439 | − | |
| 1440 | 1436 | engine->wa_ctx.vma = vma; |
| 1441 | 1437 | return 0; |
| 1442 | 1438 | |
| @@ -1448,9 +1444,6 @@ err: · 5 unmodified lines | ||
| 1448 | 1444 | void lrc_fini_wa_ctx(struct intel_engine_cs *engine) |
| 1449 | 1445 | { |
| 1450 | 1446 | i915_vma_unpin_and_release(&engine->wa_ctx.vma, 0); |
| 1451 | − | |
| 1452 | − /* Called on error unwind, clear all flags to prevent further use */ | |
| 1453 | − memset(&engine->wa_ctx, 0, sizeof(engine->wa_ctx)); | |
| 1454 | 1447 | } |
| 1455 | 1448 | |
| 1456 | 1449 | typedef u32 *(*wa_bb_func_t)(struct intel_engine_cs *engine, u32 *batch); |
| @@ -1462,6 +1455,7 @@ void lrc_init_wa_ctx(struct intel_engine_cs *engine) · 5 unmodified lines | ||
| 1462 | 1455 | &wa_ctx->indirect_ctx, &wa_ctx->per_ctx |
| 1463 | 1456 | }; |
| 1464 | 1457 | wa_bb_func_t wa_bb_fn[ARRAY_SIZE(wa_bb)]; |
| 1458 | + struct i915_gem_ww_ctx ww; | |
| 1465 | 1459 | void *batch, *batch_ptr; |
| 1466 | 1460 | unsigned int i; |
| 1467 | 1461 | int err; |
| @@ -1490,7 +1484,7 @@ void lrc_init_wa_ctx(struct intel_engine_cs *engine) · 22 unmodified lines | ||
| 1490 | 1484 | return; |
| 1491 | 1485 | } |
| 1492 | 1486 | |
| 1493 | − err = lrc_setup_wa_ctx(engine); | |
| 1487 | + err = lrc_create_wa_ctx(engine); | |
| 1494 | 1488 | if (err) { |
| 1495 | 1489 | /* |
| 1496 | 1490 | * We continue even if we fail to initialize WA batch |
| @@ -1503,7 +1497,22 @@ void lrc_init_wa_ctx(struct intel_engine_cs *engine) · 6 unmodified lines | ||
| 1503 | 1497 | return; |
| 1504 | 1498 | } |
| 1505 | 1499 | |
| 1500 | + if (!engine->wa_ctx.vma) | |
| 1501 | + return; | |
| 1502 | + | |
| 1503 | + i915_gem_ww_ctx_init(&ww, true); | |
| 1504 | +retry: | |
| 1505 | + err = i915_gem_object_lock(wa_ctx->vma->obj, &ww); | |
| 1506 | + if (!err) | |
| 1507 | + err = i915_ggtt_pin(wa_ctx->vma, &ww, 0, PIN_HIGH); | |
| 1508 | + if (err) | |
| 1509 | + goto err; | |
| 1510 | + | |
| 1506 | 1511 | batch = i915_gem_object_pin_map(wa_ctx->vma->obj, I915_MAP_WB); |
| 1512 | + if (IS_ERR(batch)) { | |
| 1513 | + err = PTR_ERR(batch); | |
| 1514 | + goto err_unpin; | |
| 1515 | + } | |
| 1507 | 1516 | |
| 1508 | 1517 | /* |
| 1509 | 1518 | * Emit the two workaround batch buffers, recording the offset from the |
| @@ -1528,8 +1537,26 @@ void lrc_init_wa_ctx(struct intel_engine_cs *engine) · 18 unmodified lines | ||
| 1528 | 1537 | __i915_gem_object_release_map(wa_ctx->vma->obj); |
| 1529 | 1538 | |
| 1530 | 1539 | /* Verify that we can handle failure to setup the wa_ctx */ |
| 1531 | − if (err || i915_inject_probe_error(engine->i915, -ENODEV)) | |
| 1532 | − lrc_fini_wa_ctx(engine); | |
| 1540 | + if (!err) | |
| 1541 | + err = i915_inject_probe_error(engine->i915, -ENODEV); | |
| 1542 | + | |
| 1543 | +err_unpin: | |
| 1544 | + if (err) | |
| 1545 | + i915_vma_unpin(wa_ctx->vma); | |
| 1546 | +err: | |
| 1547 | + if (err == -EDEADLK) { | |
| 1548 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 1549 | + if (!err) | |
| 1550 | + goto retry; | |
| 1551 | + } | |
| 1552 | + i915_gem_ww_ctx_fini(&ww); | |
| 1553 | + | |
| 1554 | + if (err) { | |
| 1555 | + i915_vma_put(engine->wa_ctx.vma); | |
| 1556 | + | |
| 1557 | + /* Clear all flags to prevent further use */ | |
| 1558 | + memset(wa_ctx, 0, sizeof(*wa_ctx)); | |
| 1559 | + } | |
| 1533 | 1560 | } |
| 1534 | 1561 | |
| 1535 | 1562 | static void st_update_runtime_underflow(struct intel_context *ce, s32 dt) |
| @@ -262,7 +262,7 @@ int i915_vm_pin_pt_stash(struct i915_address_space *vm, · 261 unmodified lines | ||
| 262 | 262 | |
| 263 | 263 | for (n = 0; n < ARRAY_SIZE(stash->pt); n++) { |
| 264 | 264 | for (pt = stash->pt[n]; pt; pt = pt->stash) { |
| 265 | − err = pin_pt_dma(vm, pt->base); | |
| 265 | + err = pin_pt_dma_locked(vm, pt->base); | |
| 266 | 266 | if (err) |
| 267 | 267 | return err; |
| 268 | 268 | } |
| @@ -304,6 +304,7 @@ void ppgtt_init(struct i915_ppgtt *ppgtt, struct intel_gt *gt) · 35 unmodified lines | ||
| 304 | 304 | ppgtt->vm.dma = i915->drm.dev; |
| 305 | 305 | ppgtt->vm.total = BIT_ULL(INTEL_INFO(i915)->ppgtt_size); |
| 306 | 306 | |
| 307 | + dma_resv_init(&ppgtt->vm.resv); | |
| 307 | 308 | i915_address_space_init(&ppgtt->vm, VM_CLASS_PPGTT); |
| 308 | 309 | |
| 309 | 310 | ppgtt->vm.vma_ops.bind_vma = ppgtt_bind_vma; |
| @@ -197,7 +197,7 @@ retry: · 196 unmodified lines | ||
| 197 | 197 | if (err) |
| 198 | 198 | goto err_context; |
| 199 | 199 | |
| 200 | − err = i915_vma_pin(so->vma, 0, 0, PIN_GLOBAL | PIN_HIGH); | |
| 200 | + err = i915_vma_pin_ww(so->vma, &so->ww, 0, 0, PIN_GLOBAL | PIN_HIGH); | |
| 201 | 201 | if (err) |
| 202 | 202 | goto err_context; |
| 203 | 203 | |
| @@ -974,8 +974,6 @@ static int do_reset(struct intel_gt *gt, intel_engine_mask_t stalled_mask) · 973 unmodified lines | ||
| 974 | 974 | { |
| 975 | 975 | int err, i; |
| 976 | 976 | |
| 977 | − gt_revoke(gt); | |
| 978 | − | |
| 979 | 977 | err = __intel_gt_reset(gt, ALL_ENGINES); |
| 980 | 978 | for (i = 0; err && i < RESET_MAX_RETRIES; i++) { |
| 981 | 979 | msleep(10 * (i + 1)); |
| @@ -1030,6 +1028,13 @@ void intel_gt_reset(struct intel_gt *gt, · 48 unmodified lines | ||
| 1030 | 1028 | |
| 1031 | 1029 | might_sleep(); |
| 1032 | 1030 | GEM_BUG_ON(!test_bit(I915_RESET_BACKOFF, >->reset.flags)); |
| 1031 | + | |
| 1032 | + /* | |
| 1033 | + * FIXME: Revoking cpu mmap ptes cannot be done from a dma_fence | |
| 1034 | + * critical section like gpu reset. | |
| 1035 | + */ | |
| 1036 | + gt_revoke(gt); | |
| 1037 | + | |
| 1033 | 1038 | mutex_lock(>->reset.mutex); |
| 1034 | 1039 | |
| 1035 | 1040 | /* Clear any previous failed attempts at recovery. Time to try again. */ |
| @@ -466,6 +466,26 @@ static void ring_context_destroy(struct kref *ref) · 465 unmodified lines | ||
| 466 | 466 | intel_context_free(ce); |
| 467 | 467 | } |
| 468 | 468 | |
| 469 | +static int ring_context_init_default_state(struct intel_context *ce, | |
| 470 | + struct i915_gem_ww_ctx *ww) | |
| 471 | +{ | |
| 472 | + struct drm_i915_gem_object *obj = ce->state->obj; | |
| 473 | + void *vaddr; | |
| 474 | + | |
| 475 | + vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 476 | + if (IS_ERR(vaddr)) | |
| 477 | + return PTR_ERR(vaddr); | |
| 478 | + | |
| 479 | + shmem_read(ce->engine->default_state, 0, | |
| 480 | + vaddr, ce->engine->context_size); | |
| 481 | + | |
| 482 | + i915_gem_object_flush_map(obj); | |
| 483 | + __i915_gem_object_release_map(obj); | |
| 484 | + | |
| 485 | + __set_bit(CONTEXT_VALID_BIT, &ce->flags); | |
| 486 | + return 0; | |
| 487 | +} | |
| 488 | + | |
| 469 | 489 | static int ring_context_pre_pin(struct intel_context *ce, |
| 470 | 490 | struct i915_gem_ww_ctx *ww, |
| 471 | 491 | void **unused) |
| @@ -473,6 +493,13 @@ static int ring_context_pre_pin(struct intel_context *ce, · 1 unmodified line | ||
| 473 | 493 | struct i915_address_space *vm; |
| 474 | 494 | int err = 0; |
| 475 | 495 | |
| 496 | + if (ce->engine->default_state && | |
| 497 | + !test_bit(CONTEXT_VALID_BIT, &ce->flags)) { | |
| 498 | + err = ring_context_init_default_state(ce, ww); | |
| 499 | + if (err) | |
| 500 | + return err; | |
| 501 | + } | |
| 502 | + | |
| 476 | 503 | vm = vm_alias(ce->vm); |
| 477 | 504 | if (vm) |
| 478 | 505 | err = gen6_ppgtt_pin(i915_vm_to_ppgtt((vm)), ww); |
| @@ -528,22 +555,6 @@ alloc_context_vma(struct intel_engine_cs *engine) · 49 unmodified lines | ||
| 528 | 555 | if (IS_IVYBRIDGE(i915)) |
| 529 | 556 | i915_gem_object_set_cache_coherency(obj, I915_CACHE_L3_LLC); |
| 530 | 557 | |
| 531 | − if (engine->default_state) { | |
| 532 | − void *vaddr; | |
| 533 | − | |
| 534 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 535 | − if (IS_ERR(vaddr)) { | |
| 536 | − err = PTR_ERR(vaddr); | |
| 537 | − goto err_obj; | |
| 538 | − } | |
| 539 | − | |
| 540 | − shmem_read(engine->default_state, 0, | |
| 541 | − vaddr, engine->context_size); | |
| 542 | − | |
| 543 | − i915_gem_object_flush_map(obj); | |
| 544 | − __i915_gem_object_release_map(obj); | |
| 545 | − } | |
| 546 | − | |
| 547 | 558 | vma = i915_vma_instance(obj, &engine->gt->ggtt->vm, NULL); |
| 548 | 559 | if (IS_ERR(vma)) { |
| 549 | 560 | err = PTR_ERR(vma); |
| @@ -575,8 +586,6 @@ static int ring_context_alloc(struct intel_context *ce) · 25 unmodified lines | ||
| 575 | 586 | return PTR_ERR(vma); |
| 576 | 587 | |
| 577 | 588 | ce->state = vma; |
| 578 | − if (engine->default_state) | |
| 579 | − __set_bit(CONTEXT_VALID_BIT, &ce->flags); | |
| 580 | 589 | } |
| 581 | 590 | |
| 582 | 591 | return 0; |
| @@ -1176,37 +1185,15 @@ static int gen7_ctx_switch_bb_setup(struct intel_engine_cs * const engine, · 593 unmodified lines | ||
| 1176 | 1185 | return gen7_setup_clear_gpr_bb(engine, vma); |
| 1177 | 1186 | } |
| 1178 | 1187 | |
| 1179 | −static int gen7_ctx_switch_bb_init(struct intel_engine_cs *engine) | |
| 1188 | +static int gen7_ctx_switch_bb_init(struct intel_engine_cs *engine, | |
| 1189 | + struct i915_gem_ww_ctx *ww, | |
| 1190 | + struct i915_vma *vma) | |
| 1180 | 1191 | { |
| 1181 | − struct drm_i915_gem_object *obj; | |
| 1182 | − struct i915_vma *vma; | |
| 1183 | − int size; | |
| 1184 | 1192 | int err; |
| 1185 | 1193 | |
| 1186 | − size = gen7_ctx_switch_bb_setup(engine, NULL /* probe size */); | |
| 1187 | − if (size <= 0) | |
| 1188 | − return size; | |
| 1189 | − | |
| 1190 | − size = ALIGN(size, PAGE_SIZE); | |
| 1191 | − obj = i915_gem_object_create_internal(engine->i915, size); | |
| 1192 | − if (IS_ERR(obj)) | |
| 1193 | − return PTR_ERR(obj); | |
| 1194 | − | |
| 1195 | − vma = i915_vma_instance(obj, engine->gt->vm, NULL); | |
| 1196 | − if (IS_ERR(vma)) { | |
| 1197 | − err = PTR_ERR(vma); | |
| 1198 | − goto err_obj; | |
| 1199 | − } | |
| 1200 | − | |
| 1201 | − vma->private = intel_context_create(engine); /* dummy residuals */ | |
| 1202 | − if (IS_ERR(vma->private)) { | |
| 1203 | − err = PTR_ERR(vma->private); | |
| 1204 | − goto err_obj; | |
| 1205 | − } | |
| 1206 | − | |
| 1207 | − err = i915_vma_pin(vma, 0, 0, PIN_USER | PIN_HIGH); | |
| 1194 | + err = i915_vma_pin_ww(vma, ww, 0, 0, PIN_USER | PIN_HIGH); | |
| 1208 | 1195 | if (err) |
| 1209 | − goto err_private; | |
| 1196 | + return err; | |
| 1210 | 1197 | |
| 1211 | 1198 | err = i915_vma_sync(vma); |
| 1212 | 1199 | if (err) |
| @@ -1221,17 +1208,53 @@ static int gen7_ctx_switch_bb_init(struct intel_engine_cs *engine) · 8 unmodified lines | ||
| 1221 | 1208 | |
| 1222 | 1209 | err_unpin: |
| 1223 | 1210 | i915_vma_unpin(vma); |
| 1224 | −err_private: | |
| 1225 | − intel_context_put(vma->private); | |
| 1226 | −err_obj: | |
| 1227 | − i915_gem_object_put(obj); | |
| 1228 | 1211 | return err; |
| 1229 | 1212 | } |
| 1230 | 1213 | |
| 1214 | +static struct i915_vma *gen7_ctx_vma(struct intel_engine_cs *engine) | |
| 1215 | +{ | |
| 1216 | + struct drm_i915_gem_object *obj; | |
| 1217 | + struct i915_vma *vma; | |
| 1218 | + int size, err; | |
| 1219 | + | |
| 1220 | + if (!IS_GEN(engine->i915, 7) || engine->class != RENDER_CLASS) | |
| 1221 | + return 0; | |
| 1222 | + | |
| 1223 | + err = gen7_ctx_switch_bb_setup(engine, NULL /* probe size */); | |
| 1224 | + if (err < 0) | |
| 1225 | + return ERR_PTR(err); | |
| 1226 | + if (!err) | |
| 1227 | + return NULL; | |
| 1228 | + | |
| 1229 | + size = ALIGN(err, PAGE_SIZE); | |
| 1230 | + | |
| 1231 | + obj = i915_gem_object_create_internal(engine->i915, size); | |
| 1232 | + if (IS_ERR(obj)) | |
| 1233 | + return ERR_CAST(obj); | |
| 1234 | + | |
| 1235 | + vma = i915_vma_instance(obj, engine->gt->vm, NULL); | |
| 1236 | + if (IS_ERR(vma)) { | |
| 1237 | + i915_gem_object_put(obj); | |
| 1238 | + return ERR_CAST(vma); | |
| 1239 | + } | |
| 1240 | + | |
| 1241 | + vma->private = intel_context_create(engine); /* dummy residuals */ | |
| 1242 | + if (IS_ERR(vma->private)) { | |
| 1243 | + err = PTR_ERR(vma->private); | |
| 1244 | + vma->private = NULL; | |
| 1245 | + i915_gem_object_put(obj); | |
| 1246 | + return ERR_PTR(err); | |
| 1247 | + } | |
| 1248 | + | |
| 1249 | + return vma; | |
| 1250 | +} | |
| 1251 | + | |
| 1231 | 1252 | int intel_ring_submission_setup(struct intel_engine_cs *engine) |
| 1232 | 1253 | { |
| 1254 | + struct i915_gem_ww_ctx ww; | |
| 1233 | 1255 | struct intel_timeline *timeline; |
| 1234 | 1256 | struct intel_ring *ring; |
| 1257 | + struct i915_vma *gen7_wa_vma; | |
| 1235 | 1258 | int err; |
| 1236 | 1259 | |
| 1237 | 1260 | setup_common(engine); |
| @@ -1262,43 +1285,72 @@ int intel_ring_submission_setup(struct intel_engine_cs *engine) · 24 unmodified lines | ||
| 1262 | 1285 | } |
| 1263 | 1286 | GEM_BUG_ON(timeline->has_initial_breadcrumb); |
| 1264 | 1287 | |
| 1265 | − err = intel_timeline_pin(timeline, NULL); | |
| 1266 | − if (err) | |
| 1267 | − goto err_timeline; | |
| 1268 | − | |
| 1269 | 1288 | ring = intel_engine_create_ring(engine, SZ_16K); |
| 1270 | 1289 | if (IS_ERR(ring)) { |
| 1271 | 1290 | err = PTR_ERR(ring); |
| 1272 | − goto err_timeline_unpin; | |
| 1291 | + goto err_timeline; | |
| 1273 | 1292 | } |
| 1274 | 1293 | |
| 1275 | − err = intel_ring_pin(ring, NULL); | |
| 1276 | − if (err) | |
| 1277 | − goto err_ring; | |
| 1278 | − | |
| 1279 | 1294 | GEM_BUG_ON(engine->legacy.ring); |
| 1280 | 1295 | engine->legacy.ring = ring; |
| 1281 | 1296 | engine->legacy.timeline = timeline; |
| 1282 | 1297 | |
| 1283 | − GEM_BUG_ON(timeline->hwsp_ggtt != engine->status_page.vma); | |
| 1298 | + gen7_wa_vma = gen7_ctx_vma(engine); | |
| 1299 | + if (IS_ERR(gen7_wa_vma)) { | |
| 1300 | + err = PTR_ERR(gen7_wa_vma); | |
| 1301 | + goto err_ring; | |
| 1302 | + } | |
| 1284 | 1303 | |
| 1285 | − if (IS_GEN(engine->i915, 7) && engine->class == RENDER_CLASS) { | |
| 1286 | − err = gen7_ctx_switch_bb_init(engine); | |
| 1304 | + i915_gem_ww_ctx_init(&ww, false); | |
| 1305 | + | |
| 1306 | +retry: | |
| 1307 | + err = i915_gem_object_lock(timeline->hwsp_ggtt->obj, &ww); | |
| 1308 | + if (!err && gen7_wa_vma) | |
| 1309 | + err = i915_gem_object_lock(gen7_wa_vma->obj, &ww); | |
| 1310 | + if (!err && engine->legacy.ring->vma->obj) | |
| 1311 | + err = i915_gem_object_lock(engine->legacy.ring->vma->obj, &ww); | |
| 1312 | + if (!err) | |
| 1313 | + err = intel_timeline_pin(timeline, &ww); | |
| 1314 | + if (!err) { | |
| 1315 | + err = intel_ring_pin(ring, &ww); | |
| 1287 | 1316 | if (err) |
| 1288 | − goto err_ring_unpin; | |
| 1317 | + intel_timeline_unpin(timeline); | |
| 1318 | + } | |
| 1319 | + if (err) | |
| 1320 | + goto out; | |
| 1321 | + | |
| 1322 | + GEM_BUG_ON(timeline->hwsp_ggtt != engine->status_page.vma); | |
| 1323 | + | |
| 1324 | + if (gen7_wa_vma) { | |
| 1325 | + err = gen7_ctx_switch_bb_init(engine, &ww, gen7_wa_vma); | |
| 1326 | + if (err) { | |
| 1327 | + intel_ring_unpin(ring); | |
| 1328 | + intel_timeline_unpin(timeline); | |
| 1329 | + } | |
| 1289 | 1330 | } |
| 1290 | 1331 | |
| 1332 | +out: | |
| 1333 | + if (err == -EDEADLK) { | |
| 1334 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 1335 | + if (!err) | |
| 1336 | + goto retry; | |
| 1337 | + } | |
| 1338 | + i915_gem_ww_ctx_fini(&ww); | |
| 1339 | + if (err) | |
| 1340 | + goto err_gen7_put; | |
| 1341 | + | |
| 1291 | 1342 | /* Finally, take ownership and responsibility for cleanup! */ |
| 1292 | 1343 | engine->release = ring_release; |
| 1293 | 1344 | |
| 1294 | 1345 | return 0; |
| 1295 | 1346 | |
| 1296 | −err_ring_unpin: | |
| 1297 | − intel_ring_unpin(ring); | |
| 1347 | +err_gen7_put: | |
| 1348 | + if (gen7_wa_vma) { | |
| 1349 | + intel_context_put(gen7_wa_vma->private); | |
| 1350 | + i915_gem_object_put(gen7_wa_vma->obj); | |
| 1351 | + } | |
| 1298 | 1352 | err_ring: |
| 1299 | 1353 | intel_ring_put(ring); |
| 1300 | −err_timeline_unpin: | |
| 1301 | − intel_timeline_unpin(timeline); | |
| 1302 | 1354 | err_timeline: |
| 1303 | 1355 | intel_timeline_put(timeline); |
| 1304 | 1356 | err: |
| @@ -12,21 +12,9 @@ · 11 unmodified lines | ||
| 12 | 12 | #include "intel_ring.h" |
| 13 | 13 | #include "intel_timeline.h" |
| 14 | 14 | |
| 15 | −#define ptr_set_bit(ptr, bit) ((typeof(ptr))((unsigned long)(ptr) | BIT(bit))) | |
| 16 | −#define ptr_test_bit(ptr, bit) ((unsigned long)(ptr) & BIT(bit)) | |
| 15 | +#define TIMELINE_SEQNO_BYTES 8 | |
| 17 | 16 | |
| 18 | −#define CACHELINE_BITS 6 | |
| 19 | −#define CACHELINE_FREE CACHELINE_BITS | |
| 20 | − | |
| 21 | −struct intel_timeline_hwsp { | |
| 22 | − struct intel_gt *gt; | |
| 23 | − struct intel_gt_timelines *gt_timelines; | |
| 24 | − struct list_head free_link; | |
| 25 | − struct i915_vma *vma; | |
| 26 | − u64 free_bitmap; | |
| 27 | −}; | |
| 28 | − | |
| 29 | −static struct i915_vma *__hwsp_alloc(struct intel_gt *gt) | |
| 17 | +static struct i915_vma *hwsp_alloc(struct intel_gt *gt) | |
| 30 | 18 | { |
| 31 | 19 | struct drm_i915_private *i915 = gt->i915; |
| 32 | 20 | struct drm_i915_gem_object *obj; |
| @@ -45,174 +33,42 @@ static struct i915_vma *__hwsp_alloc(struct intel_gt *gt) · 12 unmodified lines | ||
| 45 | 33 | return vma; |
| 46 | 34 | } |
| 47 | 35 | |
| 48 | −static struct i915_vma * | |
| 49 | −hwsp_alloc(struct intel_timeline *timeline, unsigned int *cacheline) | |
| 50 | −{ | |
| 51 | − struct intel_gt_timelines *gt = &timeline->gt->timelines; | |
| 52 | − struct intel_timeline_hwsp *hwsp; | |
| 53 | − | |
| 54 | − BUILD_BUG_ON(BITS_PER_TYPE(u64) * CACHELINE_BYTES > PAGE_SIZE); | |
| 55 | − | |
| 56 | − spin_lock_irq(>->hwsp_lock); | |
| 57 | − | |
| 58 | − /* hwsp_free_list only contains HWSP that have available cachelines */ | |
| 59 | − hwsp = list_first_entry_or_null(>->hwsp_free_list, | |
| 60 | − typeof(*hwsp), free_link); | |
| 61 | − if (!hwsp) { | |
| 62 | − struct i915_vma *vma; | |
| 63 | − | |
| 64 | − spin_unlock_irq(>->hwsp_lock); | |
| 65 | − | |
| 66 | − hwsp = kmalloc(sizeof(*hwsp), GFP_KERNEL); | |
| 67 | − if (!hwsp) | |
| 68 | − return ERR_PTR(-ENOMEM); | |
| 69 | − | |
| 70 | − vma = __hwsp_alloc(timeline->gt); | |
| 71 | − if (IS_ERR(vma)) { | |
| 72 | − kfree(hwsp); | |
| 73 | − return vma; | |
| 74 | − } | |
| 75 | − | |
| 76 | − GT_TRACE(timeline->gt, "new HWSP allocated\n"); | |
| 77 | − | |
| 78 | − vma->private = hwsp; | |
| 79 | − hwsp->gt = timeline->gt; | |
| 80 | − hwsp->vma = vma; | |
| 81 | − hwsp->free_bitmap = ~0ull; | |
| 82 | − hwsp->gt_timelines = gt; | |
| 83 | − | |
| 84 | − spin_lock_irq(>->hwsp_lock); | |
| 85 | − list_add(&hwsp->free_link, >->hwsp_free_list); | |
| 86 | − } | |
| 87 | − | |
| 88 | − GEM_BUG_ON(!hwsp->free_bitmap); | |
| 89 | − *cacheline = __ffs64(hwsp->free_bitmap); | |
| 90 | − hwsp->free_bitmap &= ~BIT_ULL(*cacheline); | |
| 91 | − if (!hwsp->free_bitmap) | |
| 92 | − list_del(&hwsp->free_link); | |
| 93 | − | |
| 94 | − spin_unlock_irq(>->hwsp_lock); | |
| 95 | − | |
| 96 | − GEM_BUG_ON(hwsp->vma->private != hwsp); | |
| 97 | − return hwsp->vma; | |
| 98 | −} | |
| 99 | − | |
| 100 | −static void __idle_hwsp_free(struct intel_timeline_hwsp *hwsp, int cacheline) | |
| 101 | −{ | |
| 102 | − struct intel_gt_timelines *gt = hwsp->gt_timelines; | |
| 103 | − unsigned long flags; | |
| 104 | − | |
| 105 | − spin_lock_irqsave(>->hwsp_lock, flags); | |
| 106 | − | |
| 107 | − /* As a cacheline becomes available, publish the HWSP on the freelist */ | |
| 108 | − if (!hwsp->free_bitmap) | |
| 109 | − list_add_tail(&hwsp->free_link, >->hwsp_free_list); | |
| 110 | − | |
| 111 | − GEM_BUG_ON(cacheline >= BITS_PER_TYPE(hwsp->free_bitmap)); | |
| 112 | − hwsp->free_bitmap |= BIT_ULL(cacheline); | |
| 113 | − | |
| 114 | − /* And if no one is left using it, give the page back to the system */ | |
| 115 | − if (hwsp->free_bitmap == ~0ull) { | |
| 116 | − i915_vma_put(hwsp->vma); | |
| 117 | − list_del(&hwsp->free_link); | |
| 118 | − kfree(hwsp); | |
| 119 | − } | |
| 120 | − | |
| 121 | − spin_unlock_irqrestore(>->hwsp_lock, flags); | |
| 122 | −} | |
| 123 | − | |
| 124 | −static void __rcu_cacheline_free(struct rcu_head *rcu) | |
| 125 | −{ | |
| 126 | − struct intel_timeline_cacheline *cl = | |
| 127 | − container_of(rcu, typeof(*cl), rcu); | |
| 128 | − | |
| 129 | − /* Must wait until after all *rq->hwsp are complete before removing */ | |
| 130 | − i915_gem_object_unpin_map(cl->hwsp->vma->obj); | |
| 131 | − __idle_hwsp_free(cl->hwsp, ptr_unmask_bits(cl->vaddr, CACHELINE_BITS)); | |
| 132 | − | |
| 133 | − i915_active_fini(&cl->active); | |
| 134 | − kfree(cl); | |
| 135 | −} | |
| 136 | − | |
| 137 | −static void __idle_cacheline_free(struct intel_timeline_cacheline *cl) | |
| 138 | −{ | |
| 139 | − GEM_BUG_ON(!i915_active_is_idle(&cl->active)); | |
| 140 | − call_rcu(&cl->rcu, __rcu_cacheline_free); | |
| 141 | −} | |
| 142 | − | |
| 143 | 36 | __i915_active_call |
| 144 | −static void __cacheline_retire(struct i915_active *active) | |
| 37 | +static void __timeline_retire(struct i915_active *active) | |
| 145 | 38 | { |
| 146 | − struct intel_timeline_cacheline *cl = | |
| 147 | − container_of(active, typeof(*cl), active); | |
| 39 | + struct intel_timeline *tl = | |
| 40 | + container_of(active, typeof(*tl), active); | |
| 148 | 41 | |
| 149 | − i915_vma_unpin(cl->hwsp->vma); | |
| 150 | − if (ptr_test_bit(cl->vaddr, CACHELINE_FREE)) | |
| 151 | − __idle_cacheline_free(cl); | |
| 42 | + i915_vma_unpin(tl->hwsp_ggtt); | |
| 43 | + intel_timeline_put(tl); | |
| 152 | 44 | } |
| 153 | 45 | |
| 154 | −static int __cacheline_active(struct i915_active *active) | |
| 46 | +static int __timeline_active(struct i915_active *active) | |
| 155 | 47 | { |
| 156 | − struct intel_timeline_cacheline *cl = | |
| 157 | − container_of(active, typeof(*cl), active); | |
| 48 | + struct intel_timeline *tl = | |
| 49 | + container_of(active, typeof(*tl), active); | |
| 158 | 50 | |
| 159 | − __i915_vma_pin(cl->hwsp->vma); | |
| 51 | + __i915_vma_pin(tl->hwsp_ggtt); | |
| 52 | + intel_timeline_get(tl); | |
| 160 | 53 | return 0; |
| 161 | 54 | } |
| 162 | 55 | |
| 163 | −static struct intel_timeline_cacheline * | |
| 164 | −cacheline_alloc(struct intel_timeline_hwsp *hwsp, unsigned int cacheline) | |
| 56 | +I915_SELFTEST_EXPORT int | |
| 57 | +intel_timeline_pin_map(struct intel_timeline *timeline) | |
| 165 | 58 | { |
| 166 | − struct intel_timeline_cacheline *cl; | |
| 59 | + struct drm_i915_gem_object *obj = timeline->hwsp_ggtt->obj; | |
| 60 | + u32 ofs = offset_in_page(timeline->hwsp_offset); | |
| 167 | 61 | void *vaddr; |
| 168 | 62 | |
| 169 | − GEM_BUG_ON(cacheline >= BIT(CACHELINE_BITS)); | |
| 170 | − | |
| 171 | − cl = kmalloc(sizeof(*cl), GFP_KERNEL); | |
| 172 | − if (!cl) | |
| 173 | − return ERR_PTR(-ENOMEM); | |
| 174 | − | |
| 175 | − vaddr = i915_gem_object_pin_map(hwsp->vma->obj, I915_MAP_WB); | |
| 176 | − if (IS_ERR(vaddr)) { | |
| 177 | − kfree(cl); | |
| 178 | − return ERR_CAST(vaddr); | |
| 179 | − } | |
| 180 | − | |
| 181 | − cl->hwsp = hwsp; | |
| 182 | − cl->vaddr = page_pack_bits(vaddr, cacheline); | |
| 183 | − | |
| 184 | − i915_active_init(&cl->active, __cacheline_active, __cacheline_retire); | |
| 185 | − | |
| 186 | − return cl; | |
| 187 | −} | |
| 188 | − | |
| 189 | −static void cacheline_acquire(struct intel_timeline_cacheline *cl, | |
| 190 | − u32 ggtt_offset) | |
| 191 | −{ | |
| 192 | − if (!cl) | |
| 193 | − return; | |
| 194 | − | |
| 195 | − cl->ggtt_offset = ggtt_offset; | |
| 196 | − i915_active_acquire(&cl->active); | |
| 197 | −} | |
| 198 | − | |
| 199 | −static void cacheline_release(struct intel_timeline_cacheline *cl) | |
| 200 | −{ | |
| 201 | − if (cl) | |
| 202 | − i915_active_release(&cl->active); | |
| 203 | −} | |
| 204 | − | |
| 205 | −static void cacheline_free(struct intel_timeline_cacheline *cl) | |
| 206 | −{ | |
| 207 | − if (!i915_active_acquire_if_busy(&cl->active)) { | |
| 208 | − __idle_cacheline_free(cl); | |
| 209 | − return; | |
| 210 | − } | |
| 63 | + vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 64 | + if (IS_ERR(vaddr)) | |
| 65 | + return PTR_ERR(vaddr); | |
| 211 | 66 | |
| 212 | − GEM_BUG_ON(ptr_test_bit(cl->vaddr, CACHELINE_FREE)); | |
| 213 | − cl->vaddr = ptr_set_bit(cl->vaddr, CACHELINE_FREE); | |
| 67 | + timeline->hwsp_map = vaddr; | |
| 68 | + timeline->hwsp_seqno = memset(vaddr + ofs, 0, TIMELINE_SEQNO_BYTES); | |
| 69 | + clflush(vaddr + ofs); | |
| 214 | 70 | |
| 215 | − i915_active_release(&cl->active); | |
| 71 | + return 0; | |
| 216 | 72 | } |
| 217 | 73 | |
| 218 | 74 | static int intel_timeline_init(struct intel_timeline *timeline, |
| @@ -220,45 +76,25 @@ static int intel_timeline_init(struct intel_timeline *timeline, · 1 unmodified line | ||
| 220 | 76 | struct i915_vma *hwsp, |
| 221 | 77 | unsigned int offset) |
| 222 | 78 | { |
| 223 | − void *vaddr; | |
| 224 | − | |
| 225 | 79 | kref_init(&timeline->kref); |
| 226 | 80 | atomic_set(&timeline->pin_count, 0); |
| 227 | 81 | |
| 228 | 82 | timeline->gt = gt; |
| 229 | 83 | |
| 230 | − timeline->has_initial_breadcrumb = !hwsp; | |
| 231 | − timeline->hwsp_cacheline = NULL; | |
| 232 | − | |
| 233 | − if (!hwsp) { | |
| 234 | − struct intel_timeline_cacheline *cl; | |
| 235 | − unsigned int cacheline; | |
| 236 | − | |
| 237 | − hwsp = hwsp_alloc(timeline, &cacheline); | |
| 84 | + if (hwsp) { | |
| 85 | + timeline->hwsp_offset = offset; | |
| 86 | + timeline->hwsp_ggtt = i915_vma_get(hwsp); | |
| 87 | + } else { | |
| 88 | + timeline->has_initial_breadcrumb = true; | |
| 89 | + hwsp = hwsp_alloc(gt); | |
| 238 | 90 | if (IS_ERR(hwsp)) |
| 239 | 91 | return PTR_ERR(hwsp); |
| 240 | − | |
| 241 | − cl = cacheline_alloc(hwsp->private, cacheline); | |
| 242 | − if (IS_ERR(cl)) { | |
| 243 | − __idle_hwsp_free(hwsp->private, cacheline); | |
| 244 | − return PTR_ERR(cl); | |
| 245 | − } | |
| 246 | − | |
| 247 | − timeline->hwsp_cacheline = cl; | |
| 248 | − timeline->hwsp_offset = cacheline * CACHELINE_BYTES; | |
| 249 | − | |
| 250 | − vaddr = page_mask_bits(cl->vaddr); | |
| 251 | − } else { | |
| 252 | − timeline->hwsp_offset = offset; | |
| 253 | − vaddr = i915_gem_object_pin_map(hwsp->obj, I915_MAP_WB); | |
| 254 | − if (IS_ERR(vaddr)) | |
| 255 | − return PTR_ERR(vaddr); | |
| 92 | + timeline->hwsp_ggtt = hwsp; | |
| 256 | 93 | } |
| 257 | 94 | |
| 258 | − timeline->hwsp_seqno = | |
| 259 | − memset(vaddr + timeline->hwsp_offset, 0, CACHELINE_BYTES); | |
| 95 | + timeline->hwsp_map = NULL; | |
| 96 | + timeline->hwsp_seqno = (void *)(long)timeline->hwsp_offset; | |
| 260 | 97 | |
| 261 | − timeline->hwsp_ggtt = i915_vma_get(hwsp); | |
| 262 | 98 | GEM_BUG_ON(timeline->hwsp_offset >= hwsp->size); |
| 263 | 99 | |
| 264 | 100 | timeline->fence_context = dma_fence_context_alloc(1); |
| @@ -269,6 +105,7 @@ static int intel_timeline_init(struct intel_timeline *timeline, · 4 unmodified lines | ||
| 269 | 105 | INIT_LIST_HEAD(&timeline->requests); |
| 270 | 106 | |
| 271 | 107 | i915_syncmap_init(&timeline->sync); |
| 108 | + i915_active_init(&timeline->active, __timeline_active, __timeline_retire); | |
| 272 | 109 | |
| 273 | 110 | return 0; |
| 274 | 111 | } |
| @@ -279,23 +116,19 @@ void intel_gt_init_timelines(struct intel_gt *gt) · 4 unmodified lines | ||
| 279 | 116 | |
| 280 | 117 | spin_lock_init(&timelines->lock); |
| 281 | 118 | INIT_LIST_HEAD(&timelines->active_list); |
| 282 | − | |
| 283 | − spin_lock_init(&timelines->hwsp_lock); | |
| 284 | − INIT_LIST_HEAD(&timelines->hwsp_free_list); | |
| 285 | 119 | } |
| 286 | 120 | |
| 287 | −static void intel_timeline_fini(struct intel_timeline *timeline) | |
| 121 | +static void intel_timeline_fini(struct rcu_head *rcu) | |
| 288 | 122 | { |
| 289 | − GEM_BUG_ON(atomic_read(&timeline->pin_count)); | |
| 290 | − GEM_BUG_ON(!list_empty(&timeline->requests)); | |
| 291 | − GEM_BUG_ON(timeline->retire); | |
| 123 | + struct intel_timeline *timeline = | |
| 124 | + container_of(rcu, struct intel_timeline, rcu); | |
| 292 | 125 | |
| 293 | − if (timeline->hwsp_cacheline) | |
| 294 | − cacheline_free(timeline->hwsp_cacheline); | |
| 295 | − else | |
| 126 | + if (timeline->hwsp_map) | |
| 296 | 127 | i915_gem_object_unpin_map(timeline->hwsp_ggtt->obj); |
| 297 | 128 | |
| 298 | 129 | i915_vma_put(timeline->hwsp_ggtt); |
| 130 | + i915_active_fini(&timeline->active); | |
| 131 | + kfree(timeline); | |
| 299 | 132 | } |
| 300 | 133 | |
| 301 | 134 | struct intel_timeline * |
| @@ -351,6 +184,12 @@ int intel_timeline_pin(struct intel_timeline *tl, struct i915_gem_ww_ctx *ww) · 49 unmodified lines | ||
| 351 | 184 | if (atomic_add_unless(&tl->pin_count, 1, 0)) |
| 352 | 185 | return 0; |
| 353 | 186 | |
| 187 | + if (!tl->hwsp_map) { | |
| 188 | + err = intel_timeline_pin_map(tl); | |
| 189 | + if (err) | |
| 190 | + return err; | |
| 191 | + } | |
| 192 | + | |
| 354 | 193 | err = i915_ggtt_pin(tl->hwsp_ggtt, ww, 0, PIN_HIGH); |
| 355 | 194 | if (err) |
| 356 | 195 | return err; |
| @@ -361,9 +200,9 @@ int intel_timeline_pin(struct intel_timeline *tl, struct i915_gem_ww_ctx *ww) · 4 unmodified lines | ||
| 361 | 200 | GT_TRACE(tl->gt, "timeline:%llx using HWSP offset:%x\n", |
| 362 | 201 | tl->fence_context, tl->hwsp_offset); |
| 363 | 202 | |
| 364 | − cacheline_acquire(tl->hwsp_cacheline, tl->hwsp_offset); | |
| 203 | + i915_active_acquire(&tl->active); | |
| 365 | 204 | if (atomic_fetch_inc(&tl->pin_count)) { |
| 366 | − cacheline_release(tl->hwsp_cacheline); | |
| 205 | + i915_active_release(&tl->active); | |
| 367 | 206 | __i915_vma_unpin(tl->hwsp_ggtt); |
| 368 | 207 | } |
| 369 | 208 | |
| @@ -372,9 +211,13 @@ int intel_timeline_pin(struct intel_timeline *tl, struct i915_gem_ww_ctx *ww) · 2 unmodified lines | ||
| 372 | 211 | |
| 373 | 212 | void intel_timeline_reset_seqno(const struct intel_timeline *tl) |
| 374 | 213 | { |
| 214 | + u32 *hwsp_seqno = (u32 *)tl->hwsp_seqno; | |
| 375 | 215 | /* Must be pinned to be writable, and no requests in flight. */ |
| 376 | 216 | GEM_BUG_ON(!atomic_read(&tl->pin_count)); |
| 377 | − WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno); | |
| 217 | + | |
| 218 | + memset(hwsp_seqno + 1, 0, TIMELINE_SEQNO_BYTES - sizeof(*hwsp_seqno)); | |
| 219 | + WRITE_ONCE(*hwsp_seqno, tl->seqno); | |
| 220 | + clflush(hwsp_seqno); | |
| 378 | 221 | } |
| 379 | 222 | |
| 380 | 223 | void intel_timeline_enter(struct intel_timeline *tl) |
| @@ -450,106 +293,23 @@ static u32 timeline_advance(struct intel_timeline *tl) · 69 unmodified lines | ||
| 450 | 293 | return tl->seqno += 1 + tl->has_initial_breadcrumb; |
| 451 | 294 | } |
| 452 | 295 | |
| 453 | −static void timeline_rollback(struct intel_timeline *tl) | |
| 454 | −{ | |
| 455 | − tl->seqno -= 1 + tl->has_initial_breadcrumb; | |
| 456 | −} | |
| 457 | − | |
| 458 | 296 | static noinline int |
| 459 | 297 | __intel_timeline_get_seqno(struct intel_timeline *tl, |
| 460 | − struct i915_request *rq, | |
| 461 | 298 | u32 *seqno) |
| 462 | 299 | { |
| 463 | − struct intel_timeline_cacheline *cl; | |
| 464 | − unsigned int cacheline; | |
| 465 | − struct i915_vma *vma; | |
| 466 | − void *vaddr; | |
| 467 | − int err; | |
| 468 | − | |
| 469 | − might_lock(&tl->gt->ggtt->vm.mutex); | |
| 470 | − GT_TRACE(tl->gt, "timeline:%llx wrapped\n", tl->fence_context); | |
| 471 | − | |
| 472 | − /* | |
| 473 | − * If there is an outstanding GPU reference to this cacheline, | |
| 474 | − * such as it being sampled by a HW semaphore on another timeline, | |
| 475 | − * we cannot wraparound our seqno value (the HW semaphore does | |
| 476 | − * a strict greater-than-or-equals compare, not i915_seqno_passed). | |
| 477 | − * So if the cacheline is still busy, we must detach ourselves | |
| 478 | − * from it and leave it inflight alongside its users. | |
| 479 | − * | |
| 480 | − * However, if nobody is watching and we can guarantee that nobody | |
| 481 | − * will, we could simply reuse the same cacheline. | |
| 482 | − * | |
| 483 | − * if (i915_active_request_is_signaled(&tl->last_request) && | |
| 484 | − * i915_active_is_signaled(&tl->hwsp_cacheline->active)) | |
| 485 | − * return 0; | |
| 486 | − * | |
| 487 | − * That seems unlikely for a busy timeline that needed to wrap in | |
| 488 | − * the first place, so just replace the cacheline. | |
| 489 | − */ | |
| 490 | − | |
| 491 | − vma = hwsp_alloc(tl, &cacheline); | |
| 492 | − if (IS_ERR(vma)) { | |
| 493 | − err = PTR_ERR(vma); | |
| 494 | − goto err_rollback; | |
| 495 | − } | |
| 496 | − | |
| 497 | − err = i915_ggtt_pin(vma, NULL, 0, PIN_HIGH); | |
| 498 | − if (err) { | |
| 499 | − __idle_hwsp_free(vma->private, cacheline); | |
| 500 | − goto err_rollback; | |
| 501 | − } | |
| 502 | − | |
| 503 | − cl = cacheline_alloc(vma->private, cacheline); | |
| 504 | − if (IS_ERR(cl)) { | |
| 505 | − err = PTR_ERR(cl); | |
| 506 | − __idle_hwsp_free(vma->private, cacheline); | |
| 507 | − goto err_unpin; | |
| 508 | − } | |
| 509 | − GEM_BUG_ON(cl->hwsp->vma != vma); | |
| 510 | − | |
| 511 | − /* | |
| 512 | − * Attach the old cacheline to the current request, so that we only | |
| 513 | − * free it after the current request is retired, which ensures that | |
| 514 | − * all writes into the cacheline from previous requests are complete. | |
| 515 | − */ | |
| 516 | − err = i915_active_ref(&tl->hwsp_cacheline->active, | |
| 517 | − tl->fence_context, | |
| 518 | − &rq->fence); | |
| 519 | − if (err) | |
| 520 | − goto err_cacheline; | |
| 521 | − | |
| 522 | − cacheline_release(tl->hwsp_cacheline); /* ownership now xfered to rq */ | |
| 523 | − cacheline_free(tl->hwsp_cacheline); | |
| 524 | − | |
| 525 | − i915_vma_unpin(tl->hwsp_ggtt); /* binding kept alive by old cacheline */ | |
| 526 | − i915_vma_put(tl->hwsp_ggtt); | |
| 527 | − | |
| 528 | − tl->hwsp_ggtt = i915_vma_get(vma); | |
| 300 | + u32 next_ofs = offset_in_page(tl->hwsp_offset + TIMELINE_SEQNO_BYTES); | |
| 529 | 301 | |
| 530 | − vaddr = page_mask_bits(cl->vaddr); | |
| 531 | − tl->hwsp_offset = cacheline * CACHELINE_BYTES; | |
| 532 | − tl->hwsp_seqno = | |
| 533 | − memset(vaddr + tl->hwsp_offset, 0, CACHELINE_BYTES); | |
| 302 | + /* w/a: bit 5 needs to be zero for MI_FLUSH_DW address. */ | |
| 303 | + if (TIMELINE_SEQNO_BYTES <= BIT(5) && (next_ofs & BIT(5))) | |
| 304 | + next_ofs = offset_in_page(next_ofs + BIT(5)); | |
| 534 | 305 | |
| 535 | − tl->hwsp_offset += i915_ggtt_offset(vma); | |
| 536 | − GT_TRACE(tl->gt, "timeline:%llx using HWSP offset:%x\n", | |
| 537 | − tl->fence_context, tl->hwsp_offset); | |
| 538 | − | |
| 539 | − cacheline_acquire(cl, tl->hwsp_offset); | |
| 540 | − tl->hwsp_cacheline = cl; | |
| 306 | + tl->hwsp_offset = i915_ggtt_offset(tl->hwsp_ggtt) + next_ofs; | |
| 307 | + tl->hwsp_seqno = tl->hwsp_map + next_ofs; | |
| 308 | + intel_timeline_reset_seqno(tl); | |
| 541 | 309 | |
| 542 | 310 | *seqno = timeline_advance(tl); |
| 543 | 311 | GEM_BUG_ON(i915_seqno_passed(*tl->hwsp_seqno, *seqno)); |
| 544 | 312 | return 0; |
| 545 | − | |
| 546 | −err_cacheline: | |
| 547 | − cacheline_free(cl); | |
| 548 | −err_unpin: | |
| 549 | − i915_vma_unpin(vma); | |
| 550 | −err_rollback: | |
| 551 | − timeline_rollback(tl); | |
| 552 | − return err; | |
| 553 | 313 | } |
| 554 | 314 | |
| 555 | 315 | int intel_timeline_get_seqno(struct intel_timeline *tl, |
| @@ -559,51 +319,52 @@ int intel_timeline_get_seqno(struct intel_timeline *tl, · 3 unmodified lines | ||
| 559 | 319 | *seqno = timeline_advance(tl); |
| 560 | 320 | |
| 561 | 321 | /* Replace the HWSP on wraparound for HW semaphores */ |
| 562 | − if (unlikely(!*seqno && tl->hwsp_cacheline)) | |
| 563 | − return __intel_timeline_get_seqno(tl, rq, seqno); | |
| 322 | + if (unlikely(!*seqno && tl->has_initial_breadcrumb)) | |
| 323 | + return __intel_timeline_get_seqno(tl, seqno); | |
| 564 | 324 | |
| 565 | 325 | return 0; |
| 566 | 326 | } |
| 567 | 327 | |
| 568 | −static int cacheline_ref(struct intel_timeline_cacheline *cl, | |
| 569 | − struct i915_request *rq) | |
| 570 | −{ | |
| 571 | − return i915_active_add_request(&cl->active, rq); | |
| 572 | −} | |
| 573 | − | |
| 574 | 328 | int intel_timeline_read_hwsp(struct i915_request *from, |
| 575 | 329 | struct i915_request *to, |
| 576 | 330 | u32 *hwsp) |
| 577 | 331 | { |
| 578 | − struct intel_timeline_cacheline *cl; | |
| 332 | + struct intel_timeline *tl; | |
| 579 | 333 | int err; |
| 580 | 334 | |
| 581 | − GEM_BUG_ON(!rcu_access_pointer(from->hwsp_cacheline)); | |
| 582 | − | |
| 583 | 335 | rcu_read_lock(); |
| 584 | − cl = rcu_dereference(from->hwsp_cacheline); | |
| 585 | − if (i915_request_signaled(from)) /* confirm cacheline is valid */ | |
| 586 | − goto unlock; | |
| 587 | − if (unlikely(!i915_active_acquire_if_busy(&cl->active))) | |
| 588 | − goto unlock; /* seqno wrapped and completed! */ | |
| 589 | − if (unlikely(__i915_request_is_complete(from))) | |
| 590 | − goto release; | |
| 336 | + tl = rcu_dereference(from->timeline); | |
| 337 | + if (i915_request_signaled(from) || | |
| 338 | + !i915_active_acquire_if_busy(&tl->active)) | |
| 339 | + tl = NULL; | |
| 340 | + | |
| 341 | + if (tl) { | |
| 342 | + /* hwsp_offset may wraparound, so use from->hwsp_seqno */ | |
| 343 | + *hwsp = i915_ggtt_offset(tl->hwsp_ggtt) + | |
| 344 | + offset_in_page(from->hwsp_seqno); | |
| 345 | + } | |
| 346 | + | |
| 347 | + /* ensure we wait on the right request, if not, we completed */ | |
| 348 | + if (tl && __i915_request_is_complete(from)) { | |
| 349 | + i915_active_release(&tl->active); | |
| 350 | + tl = NULL; | |
| 351 | + } | |
| 591 | 352 | rcu_read_unlock(); |
| 592 | 353 | |
| 593 | − err = cacheline_ref(cl, to); | |
| 594 | − if (err) | |
| 354 | + if (!tl) | |
| 355 | + return 1; | |
| 356 | + | |
| 357 | + /* Can't do semaphore waits on kernel context */ | |
| 358 | + if (!tl->has_initial_breadcrumb) { | |
| 359 | + err = -EINVAL; | |
| 595 | 360 | goto out; |
| 361 | + } | |
| 362 | + | |
| 363 | + err = i915_active_add_request(&tl->active, to); | |
| 596 | 364 | |
| 597 | − *hwsp = cl->ggtt_offset; | |
| 598 | 365 | out: |
| 599 | − i915_active_release(&cl->active); | |
| 366 | + i915_active_release(&tl->active); | |
| 600 | 367 | return err; |
| 601 | − | |
| 602 | −release: | |
| 603 | − i915_active_release(&cl->active); | |
| 604 | −unlock: | |
| 605 | − rcu_read_unlock(); | |
| 606 | − return 1; | |
| 607 | 368 | } |
| 608 | 369 | |
| 609 | 370 | void intel_timeline_unpin(struct intel_timeline *tl) |
| @@ -612,8 +373,7 @@ void intel_timeline_unpin(struct intel_timeline *tl) · 2 unmodified lines | ||
| 612 | 373 | if (!atomic_dec_and_test(&tl->pin_count)) |
| 613 | 374 | return; |
| 614 | 375 | |
| 615 | − cacheline_release(tl->hwsp_cacheline); | |
| 616 | − | |
| 376 | + i915_active_release(&tl->active); | |
| 617 | 377 | __i915_vma_unpin(tl->hwsp_ggtt); |
| 618 | 378 | } |
| 619 | 379 | |
| @@ -622,8 +382,11 @@ void __intel_timeline_free(struct kref *kref) · 2 unmodified lines | ||
| 622 | 382 | struct intel_timeline *timeline = |
| 623 | 383 | container_of(kref, typeof(*timeline), kref); |
| 624 | 384 | |
| 625 | − intel_timeline_fini(timeline); | |
| 626 | − kfree_rcu(timeline, rcu); | |
| 385 | + GEM_BUG_ON(atomic_read(&timeline->pin_count)); | |
| 386 | + GEM_BUG_ON(!list_empty(&timeline->requests)); | |
| 387 | + GEM_BUG_ON(timeline->retire); | |
| 388 | + | |
| 389 | + call_rcu(&timeline->rcu, intel_timeline_fini); | |
| 627 | 390 | } |
| 628 | 391 | |
| 629 | 392 | void intel_gt_fini_timelines(struct intel_gt *gt) |
| @@ -631,7 +394,6 @@ void intel_gt_fini_timelines(struct intel_gt *gt) · 1 unmodified line | ||
| 631 | 394 | struct intel_gt_timelines *timelines = >->timelines; |
| 632 | 395 | |
| 633 | 396 | GEM_BUG_ON(!list_empty(&timelines->active_list)); |
| 634 | − GEM_BUG_ON(!list_empty(&timelines->hwsp_free_list)); | |
| 635 | 397 | } |
| 636 | 398 | |
| 637 | 399 | void intel_gt_show_timelines(struct intel_gt *gt, |
| @@ -117,4 +117,6 @@ intel_timeline_is_last(const struct intel_timeline *tl, · 116 unmodified lines | ||
| 117 | 117 | return list_is_last_rcu(&rq->link, &tl->requests); |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | +I915_SELFTEST_DECLARE(int intel_timeline_pin_map(struct intel_timeline *tl)); | |
| 121 | + | |
| 120 | 122 | #endif |
| @@ -18,7 +18,6 @@ · 17 unmodified lines | ||
| 18 | 18 | struct i915_vma; |
| 19 | 19 | struct i915_syncmap; |
| 20 | 20 | struct intel_gt; |
| 21 | −struct intel_timeline_hwsp; | |
| 22 | 21 | |
| 23 | 22 | struct intel_timeline { |
| 24 | 23 | u64 fence_context; |
| @@ -45,12 +44,11 @@ struct intel_timeline { · 20 unmodified lines | ||
| 45 | 44 | atomic_t pin_count; |
| 46 | 45 | atomic_t active_count; |
| 47 | 46 | |
| 47 | + void *hwsp_map; | |
| 48 | 48 | const u32 *hwsp_seqno; |
| 49 | 49 | struct i915_vma *hwsp_ggtt; |
| 50 | 50 | u32 hwsp_offset; |
| 51 | 51 | |
| 52 | − struct intel_timeline_cacheline *hwsp_cacheline; | |
| 53 | − | |
| 54 | 52 | bool has_initial_breadcrumb; |
| 55 | 53 | |
| 56 | 54 | /** |
| @@ -67,6 +65,8 @@ struct intel_timeline { · 10 unmodified lines | ||
| 67 | 65 | */ |
| 68 | 66 | struct i915_active_fence last_request; |
| 69 | 67 | |
| 68 | + struct i915_active active; | |
| 69 | + | |
| 70 | 70 | /** A chain of completed timelines ready for early retirement. */ |
| 71 | 71 | struct intel_timeline *retire; |
| 72 | 72 | |
| @@ -90,15 +90,4 @@ struct intel_timeline { · 17 unmodified lines | ||
| 90 | 90 | struct rcu_head rcu; |
| 91 | 91 | }; |
| 92 | 92 | |
| 93 | −struct intel_timeline_cacheline { | |
| 94 | − struct i915_active active; | |
| 95 | − | |
| 96 | − struct intel_timeline_hwsp *hwsp; | |
| 97 | − void *vaddr; | |
| 98 | − | |
| 99 | − u32 ggtt_offset; | |
| 100 | − | |
| 101 | − struct rcu_head rcu; | |
| 102 | −}; | |
| 103 | − | |
| 104 | 93 | #endif /* __I915_TIMELINE_TYPES_H__ */ |
| @@ -2213,10 +2213,15 @@ retry: · 2212 unmodified lines | ||
| 2213 | 2213 | if (err) |
| 2214 | 2214 | goto err_pm; |
| 2215 | 2215 | |
| 2216 | + err = i915_vma_pin_ww(vma, &ww, 0, 0, | |
| 2217 | + i915_vma_is_ggtt(vma) ? PIN_GLOBAL : PIN_USER); | |
| 2218 | + if (err) | |
| 2219 | + goto err_unpin; | |
| 2220 | + | |
| 2216 | 2221 | rq = i915_request_create(ce); |
| 2217 | 2222 | if (IS_ERR(rq)) { |
| 2218 | 2223 | err = PTR_ERR(rq); |
| 2219 | − goto err_unpin; | |
| 2224 | + goto err_vma; | |
| 2220 | 2225 | } |
| 2221 | 2226 | |
| 2222 | 2227 | err = i915_request_await_object(rq, vma->obj, true); |
| @@ -2257,6 +2262,8 @@ retry: · 34 unmodified lines | ||
| 2257 | 2262 | |
| 2258 | 2263 | err_rq: |
| 2259 | 2264 | i915_request_put(rq); |
| 2265 | +err_vma: | |
| 2266 | + i915_vma_unpin(vma); | |
| 2260 | 2267 | err_unpin: |
| 2261 | 2268 | intel_context_unpin(ce); |
| 2262 | 2269 | err_pm: |
| @@ -2267,7 +2274,6 @@ err_pm: · 4 unmodified lines | ||
| 2267 | 2274 | } |
| 2268 | 2275 | i915_gem_ww_ctx_fini(&ww); |
| 2269 | 2276 | intel_engine_pm_put(ce->engine); |
| 2270 | − i915_vma_unpin(vma); | |
| 2271 | 2277 | i915_vma_put(vma); |
| 2272 | 2278 | return err; |
| 2273 | 2279 | } |
| @@ -32,9 +32,20 @@ · 31 unmodified lines | ||
| 32 | 32 | #include "mock_engine.h" |
| 33 | 33 | #include "selftests/mock_request.h" |
| 34 | 34 | |
| 35 | −static void mock_timeline_pin(struct intel_timeline *tl) | |
| 35 | +static int mock_timeline_pin(struct intel_timeline *tl) | |
| 36 | 36 | { |
| 37 | + int err; | |
| 38 | + | |
| 39 | + if (WARN_ON(!i915_gem_object_trylock(tl->hwsp_ggtt->obj))) | |
| 40 | + return -EBUSY; | |
| 41 | + | |
| 42 | + err = intel_timeline_pin_map(tl); | |
| 43 | + i915_gem_object_unlock(tl->hwsp_ggtt->obj); | |
| 44 | + if (err) | |
| 45 | + return err; | |
| 46 | + | |
| 37 | 47 | atomic_inc(&tl->pin_count); |
| 48 | + return 0; | |
| 38 | 49 | } |
| 39 | 50 | |
| 40 | 51 | static void mock_timeline_unpin(struct intel_timeline *tl) |
| @@ -152,6 +163,8 @@ static void mock_context_destroy(struct kref *ref) · 111 unmodified lines | ||
| 152 | 163 | |
| 153 | 164 | static int mock_context_alloc(struct intel_context *ce) |
| 154 | 165 | { |
| 166 | + int err; | |
| 167 | + | |
| 155 | 168 | ce->ring = mock_ring(ce->engine); |
| 156 | 169 | if (!ce->ring) |
| 157 | 170 | return -ENOMEM; |
| @@ -162,7 +175,12 @@ static int mock_context_alloc(struct intel_context *ce) · 4 unmodified lines | ||
| 162 | 175 | return PTR_ERR(ce->timeline); |
| 163 | 176 | } |
| 164 | 177 | |
| 165 | − mock_timeline_pin(ce->timeline); | |
| 178 | + err = mock_timeline_pin(ce->timeline); | |
| 179 | + if (err) { | |
| 180 | + intel_timeline_put(ce->timeline); | |
| 181 | + ce->timeline = NULL; | |
| 182 | + return err; | |
| 183 | + } | |
| 166 | 184 | |
| 167 | 185 | return 0; |
| 168 | 186 | } |
| @@ -88,8 +88,8 @@ static int __live_context_size(struct intel_engine_cs *engine) · 87 unmodified lines | ||
| 88 | 88 | if (err) |
| 89 | 89 | goto err; |
| 90 | 90 | |
| 91 | − vaddr = i915_gem_object_pin_map(ce->state->obj, | |
| 92 | − i915_coherent_map_type(engine->i915)); | |
| 91 | + vaddr = i915_gem_object_pin_map_unlocked(ce->state->obj, | |
| 92 | + i915_coherent_map_type(engine->i915)); | |
| 93 | 93 | if (IS_ERR(vaddr)) { |
| 94 | 94 | err = PTR_ERR(vaddr); |
| 95 | 95 | intel_context_unpin(ce); |
| @@ -42,6 +42,9 @@ static int perf_end(struct intel_gt *gt) · 41 unmodified lines | ||
| 42 | 42 | |
| 43 | 43 | static int write_timestamp(struct i915_request *rq, int slot) |
| 44 | 44 | { |
| 45 | + struct intel_timeline *tl = | |
| 46 | + rcu_dereference_protected(rq->timeline, | |
| 47 | + !i915_request_signaled(rq)); | |
| 45 | 48 | u32 cmd; |
| 46 | 49 | u32 *cs; |
| 47 | 50 | |
| @@ -54,7 +57,7 @@ static int write_timestamp(struct i915_request *rq, int slot) · 6 unmodified lines | ||
| 54 | 57 | cmd++; |
| 55 | 58 | *cs++ = cmd; |
| 56 | 59 | *cs++ = i915_mmio_reg_offset(RING_TIMESTAMP(rq->engine->mmio_base)); |
| 57 | − *cs++ = i915_request_timeline(rq)->hwsp_offset + slot * sizeof(u32); | |
| 60 | + *cs++ = tl->hwsp_offset + slot * sizeof(u32); | |
| 58 | 61 | *cs++ = 0; |
| 59 | 62 | |
| 60 | 63 | intel_ring_advance(rq, cs); |
| @@ -73,7 +76,7 @@ static struct i915_vma *create_empty_batch(struct intel_context *ce) · 12 unmodified lines | ||
| 73 | 76 | if (IS_ERR(obj)) |
| 74 | 77 | return ERR_CAST(obj); |
| 75 | 78 | |
| 76 | − cs = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 79 | + cs = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 77 | 80 | if (IS_ERR(cs)) { |
| 78 | 81 | err = PTR_ERR(cs); |
| 79 | 82 | goto err_put; |
| @@ -209,7 +212,7 @@ static struct i915_vma *create_nop_batch(struct intel_context *ce) · 129 unmodified lines | ||
| 209 | 212 | if (IS_ERR(obj)) |
| 210 | 213 | return ERR_CAST(obj); |
| 211 | 214 | |
| 212 | − cs = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 215 | + cs = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 213 | 216 | if (IS_ERR(cs)) { |
| 214 | 217 | err = PTR_ERR(cs); |
| 215 | 218 | goto err_put; |
| @@ -989,7 +989,7 @@ static int live_timeslice_preempt(void *arg) · 988 unmodified lines | ||
| 989 | 989 | goto err_obj; |
| 990 | 990 | } |
| 991 | 991 | |
| 992 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 992 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 993 | 993 | if (IS_ERR(vaddr)) { |
| 994 | 994 | err = PTR_ERR(vaddr); |
| 995 | 995 | goto err_obj; |
| @@ -1297,7 +1297,7 @@ static int live_timeslice_queue(void *arg) · 301 unmodified lines | ||
| 1297 | 1297 | goto err_obj; |
| 1298 | 1298 | } |
| 1299 | 1299 | |
| 1300 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 1300 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 1301 | 1301 | if (IS_ERR(vaddr)) { |
| 1302 | 1302 | err = PTR_ERR(vaddr); |
| 1303 | 1303 | goto err_obj; |
| @@ -1544,7 +1544,7 @@ static int live_busywait_preempt(void *arg) · 240 unmodified lines | ||
| 1544 | 1544 | goto err_ctx_lo; |
| 1545 | 1545 | } |
| 1546 | 1546 | |
| 1547 | − map = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 1547 | + map = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 1548 | 1548 | if (IS_ERR(map)) { |
| 1549 | 1549 | err = PTR_ERR(map); |
| 1550 | 1550 | goto err_obj; |
| @@ -2714,7 +2714,7 @@ static int create_gang(struct intel_engine_cs *engine, · 1163 unmodified lines | ||
| 2714 | 2714 | if (err) |
| 2715 | 2715 | goto err_obj; |
| 2716 | 2716 | |
| 2717 | − cs = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 2717 | + cs = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 2718 | 2718 | if (IS_ERR(cs)) { |
| 2719 | 2719 | err = PTR_ERR(cs); |
| 2720 | 2720 | goto err_obj; |
| @@ -2997,7 +2997,7 @@ static int live_preempt_gang(void *arg) · 276 unmodified lines | ||
| 2997 | 2997 | * it will terminate the next lowest spinner until there |
| 2998 | 2998 | * are no more spinners and the gang is complete. |
| 2999 | 2999 | */ |
| 3000 | − cs = i915_gem_object_pin_map(rq->batch->obj, I915_MAP_WC); | |
| 3000 | + cs = i915_gem_object_pin_map_unlocked(rq->batch->obj, I915_MAP_WC); | |
| 3001 | 3001 | if (!IS_ERR(cs)) { |
| 3002 | 3002 | *cs = 0; |
| 3003 | 3003 | i915_gem_object_unpin_map(rq->batch->obj); |
| @@ -3062,7 +3062,7 @@ create_gpr_user(struct intel_engine_cs *engine, · 58 unmodified lines | ||
| 3062 | 3062 | return ERR_PTR(err); |
| 3063 | 3063 | } |
| 3064 | 3064 | |
| 3065 | − cs = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 3065 | + cs = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 3066 | 3066 | if (IS_ERR(cs)) { |
| 3067 | 3067 | i915_vma_put(vma); |
| 3068 | 3068 | return ERR_CAST(cs); |
| @@ -3269,7 +3269,7 @@ static int live_preempt_user(void *arg) · 200 unmodified lines | ||
| 3269 | 3269 | if (IS_ERR(global)) |
| 3270 | 3270 | return PTR_ERR(global); |
| 3271 | 3271 | |
| 3272 | − result = i915_gem_object_pin_map(global->obj, I915_MAP_WC); | |
| 3272 | + result = i915_gem_object_pin_map_unlocked(global->obj, I915_MAP_WC); | |
| 3273 | 3273 | if (IS_ERR(result)) { |
| 3274 | 3274 | i915_vma_unpin_and_release(&global, 0); |
| 3275 | 3275 | return PTR_ERR(result); |
| @@ -3658,7 +3658,7 @@ static int live_preempt_smoke(void *arg) · 382 unmodified lines | ||
| 3658 | 3658 | goto err_free; |
| 3659 | 3659 | } |
| 3660 | 3660 | |
| 3661 | − cs = i915_gem_object_pin_map(smoke.batch, I915_MAP_WB); | |
| 3661 | + cs = i915_gem_object_pin_map_unlocked(smoke.batch, I915_MAP_WB); | |
| 3662 | 3662 | if (IS_ERR(cs)) { |
| 3663 | 3663 | err = PTR_ERR(cs); |
| 3664 | 3664 | goto err_batch; |
| @@ -4197,8 +4197,9 @@ static int preserved_virtual_engine(struct intel_gt *gt, · 532 unmodified lines | ||
| 4197 | 4197 | int err = 0; |
| 4198 | 4198 | u32 *cs; |
| 4199 | 4199 | |
| 4200 | − scratch = __vm_create_scratch_for_read(&siblings[0]->gt->ggtt->vm, | |
| 4201 | − PAGE_SIZE); | |
| 4200 | + scratch = | |
| 4201 | + __vm_create_scratch_for_read_pinned(&siblings[0]->gt->ggtt->vm, | |
| 4202 | + PAGE_SIZE); | |
| 4202 | 4203 | if (IS_ERR(scratch)) |
| 4203 | 4204 | return PTR_ERR(scratch); |
| 4204 | 4205 | |
| @@ -4262,7 +4263,7 @@ static int preserved_virtual_engine(struct intel_gt *gt, · 57 unmodified lines | ||
| 4262 | 4263 | goto out_end; |
| 4263 | 4264 | } |
| 4264 | 4265 | |
| 4265 | − cs = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB); | |
| 4266 | + cs = i915_gem_object_pin_map_unlocked(scratch->obj, I915_MAP_WB); | |
| 4266 | 4267 | if (IS_ERR(cs)) { |
| 4267 | 4268 | err = PTR_ERR(cs); |
| 4268 | 4269 | goto out_end; |
| @@ -80,15 +80,15 @@ static int hang_init(struct hang *h, struct intel_gt *gt) · 79 unmodified lines | ||
| 80 | 80 | } |
| 81 | 81 | |
| 82 | 82 | i915_gem_object_set_cache_coherency(h->hws, I915_CACHE_LLC); |
| 83 | − vaddr = i915_gem_object_pin_map(h->hws, I915_MAP_WB); | |
| 83 | + vaddr = i915_gem_object_pin_map_unlocked(h->hws, I915_MAP_WB); | |
| 84 | 84 | if (IS_ERR(vaddr)) { |
| 85 | 85 | err = PTR_ERR(vaddr); |
| 86 | 86 | goto err_obj; |
| 87 | 87 | } |
| 88 | 88 | h->seqno = memset(vaddr, 0xff, PAGE_SIZE); |
| 89 | 89 | |
| 90 | − vaddr = i915_gem_object_pin_map(h->obj, | |
| 91 | − i915_coherent_map_type(gt->i915)); | |
| 90 | + vaddr = i915_gem_object_pin_map_unlocked(h->obj, | |
| 91 | + i915_coherent_map_type(gt->i915)); | |
| 92 | 92 | if (IS_ERR(vaddr)) { |
| 93 | 93 | err = PTR_ERR(vaddr); |
| 94 | 94 | goto err_unpin_hws; |
| @@ -149,7 +149,7 @@ hang_create_request(struct hang *h, struct intel_engine_cs *engine) · 54 unmodified lines | ||
| 149 | 149 | return ERR_CAST(obj); |
| 150 | 150 | } |
| 151 | 151 | |
| 152 | − vaddr = i915_gem_object_pin_map(obj, i915_coherent_map_type(gt->i915)); | |
| 152 | + vaddr = i915_gem_object_pin_map_unlocked(obj, i915_coherent_map_type(gt->i915)); | |
| 153 | 153 | if (IS_ERR(vaddr)) { |
| 154 | 154 | i915_gem_object_put(obj); |
| 155 | 155 | i915_vm_put(vm); |
| @@ -27,7 +27,7 @@ · 26 unmodified lines | ||
| 27 | 27 | |
| 28 | 28 | static struct i915_vma *create_scratch(struct intel_gt *gt) |
| 29 | 29 | { |
| 30 | − return __vm_create_scratch_for_read(>->ggtt->vm, PAGE_SIZE); | |
| 30 | + return __vm_create_scratch_for_read_pinned(>->ggtt->vm, PAGE_SIZE); | |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | static bool is_active(struct i915_request *rq) |
| @@ -627,7 +627,7 @@ static int __live_lrc_gpr(struct intel_engine_cs *engine, · 593 unmodified lines | ||
| 627 | 627 | goto err_rq; |
| 628 | 628 | } |
| 629 | 629 | |
| 630 | − cs = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB); | |
| 630 | + cs = i915_gem_object_pin_map_unlocked(scratch->obj, I915_MAP_WB); | |
| 631 | 631 | if (IS_ERR(cs)) { |
| 632 | 632 | err = PTR_ERR(cs); |
| 633 | 633 | goto err_rq; |
| @@ -921,7 +921,7 @@ store_context(struct intel_context *ce, struct i915_vma *scratch) · 287 unmodified lines | ||
| 921 | 921 | if (IS_ERR(batch)) |
| 922 | 922 | return batch; |
| 923 | 923 | |
| 924 | − cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); | |
| 924 | + cs = i915_gem_object_pin_map_unlocked(batch->obj, I915_MAP_WC); | |
| 925 | 925 | if (IS_ERR(cs)) { |
| 926 | 926 | i915_vma_put(batch); |
| 927 | 927 | return ERR_CAST(cs); |
| @@ -1085,7 +1085,7 @@ static struct i915_vma *load_context(struct intel_context *ce, u32 poison) · 157 unmodified lines | ||
| 1085 | 1085 | if (IS_ERR(batch)) |
| 1086 | 1086 | return batch; |
| 1087 | 1087 | |
| 1088 | − cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); | |
| 1088 | + cs = i915_gem_object_pin_map_unlocked(batch->obj, I915_MAP_WC); | |
| 1089 | 1089 | if (IS_ERR(cs)) { |
| 1090 | 1090 | i915_vma_put(batch); |
| 1091 | 1091 | return ERR_CAST(cs); |
| @@ -1199,29 +1199,29 @@ static int compare_isolation(struct intel_engine_cs *engine, · 107 unmodified lines | ||
| 1199 | 1199 | u32 *defaults; |
| 1200 | 1200 | int err = 0; |
| 1201 | 1201 | |
| 1202 | − A[0] = i915_gem_object_pin_map(ref[0]->obj, I915_MAP_WC); | |
| 1202 | + A[0] = i915_gem_object_pin_map_unlocked(ref[0]->obj, I915_MAP_WC); | |
| 1203 | 1203 | if (IS_ERR(A[0])) |
| 1204 | 1204 | return PTR_ERR(A[0]); |
| 1205 | 1205 | |
| 1206 | − A[1] = i915_gem_object_pin_map(ref[1]->obj, I915_MAP_WC); | |
| 1206 | + A[1] = i915_gem_object_pin_map_unlocked(ref[1]->obj, I915_MAP_WC); | |
| 1207 | 1207 | if (IS_ERR(A[1])) { |
| 1208 | 1208 | err = PTR_ERR(A[1]); |
| 1209 | 1209 | goto err_A0; |
| 1210 | 1210 | } |
| 1211 | 1211 | |
| 1212 | − B[0] = i915_gem_object_pin_map(result[0]->obj, I915_MAP_WC); | |
| 1212 | + B[0] = i915_gem_object_pin_map_unlocked(result[0]->obj, I915_MAP_WC); | |
| 1213 | 1213 | if (IS_ERR(B[0])) { |
| 1214 | 1214 | err = PTR_ERR(B[0]); |
| 1215 | 1215 | goto err_A1; |
| 1216 | 1216 | } |
| 1217 | 1217 | |
| 1218 | − B[1] = i915_gem_object_pin_map(result[1]->obj, I915_MAP_WC); | |
| 1218 | + B[1] = i915_gem_object_pin_map_unlocked(result[1]->obj, I915_MAP_WC); | |
| 1219 | 1219 | if (IS_ERR(B[1])) { |
| 1220 | 1220 | err = PTR_ERR(B[1]); |
| 1221 | 1221 | goto err_B0; |
| 1222 | 1222 | } |
| 1223 | 1223 | |
| 1224 | − lrc = i915_gem_object_pin_map(ce->state->obj, | |
| 1224 | + lrc = i915_gem_object_pin_map_unlocked(ce->state->obj, | |
| 1225 | 1225 | i915_coherent_map_type(engine->i915)); |
| 1226 | 1226 | if (IS_ERR(lrc)) { |
| 1227 | 1227 | err = PTR_ERR(lrc); |
| @@ -75,11 +75,12 @@ static int live_mocs_init(struct live_mocs *arg, struct intel_gt *gt) · 74 unmodified lines | ||
| 75 | 75 | if (flags & (HAS_GLOBAL_MOCS | HAS_ENGINE_MOCS)) |
| 76 | 76 | arg->mocs = table; |
| 77 | 77 | |
| 78 | − arg->scratch = __vm_create_scratch_for_read(>->ggtt->vm, PAGE_SIZE); | |
| 78 | + arg->scratch = | |
| 79 | + __vm_create_scratch_for_read_pinned(>->ggtt->vm, PAGE_SIZE); | |
| 79 | 80 | if (IS_ERR(arg->scratch)) |
| 80 | 81 | return PTR_ERR(arg->scratch); |
| 81 | 82 | |
| 82 | − arg->vaddr = i915_gem_object_pin_map(arg->scratch->obj, I915_MAP_WB); | |
| 83 | + arg->vaddr = i915_gem_object_pin_map_unlocked(arg->scratch->obj, I915_MAP_WB); | |
| 83 | 84 | if (IS_ERR(arg->vaddr)) { |
| 84 | 85 | err = PTR_ERR(arg->vaddr); |
| 85 | 86 | goto err_scratch; |
| @@ -35,7 +35,7 @@ static struct i915_vma *create_wally(struct intel_engine_cs *engine) · 34 unmodified lines | ||
| 35 | 35 | return ERR_PTR(err); |
| 36 | 36 | } |
| 37 | 37 | |
| 38 | − cs = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 38 | + cs = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 39 | 39 | if (IS_ERR(cs)) { |
| 40 | 40 | i915_gem_object_put(obj); |
| 41 | 41 | return ERR_CAST(cs); |
| @@ -212,7 +212,7 @@ static int __live_ctx_switch_wa(struct intel_engine_cs *engine) · 170 unmodified lines | ||
| 212 | 212 | if (IS_ERR(bb)) |
| 213 | 213 | return PTR_ERR(bb); |
| 214 | 214 | |
| 215 | − result = i915_gem_object_pin_map(bb->obj, I915_MAP_WC); | |
| 215 | + result = i915_gem_object_pin_map_unlocked(bb->obj, I915_MAP_WC); | |
| 216 | 216 | if (IS_ERR(result)) { |
| 217 | 217 | intel_context_put(bb->private); |
| 218 | 218 | i915_vma_unpin_and_release(&bb, 0); |
| @@ -35,10 +35,31 @@ static unsigned long hwsp_cacheline(struct intel_timeline *tl) · 34 unmodified lines | ||
| 35 | 35 | { |
| 36 | 36 | unsigned long address = (unsigned long)page_address(hwsp_page(tl)); |
| 37 | 37 | |
| 38 | − return (address + tl->hwsp_offset) / CACHELINE_BYTES; | |
| 38 | + return (address + offset_in_page(tl->hwsp_offset)) / TIMELINE_SEQNO_BYTES; | |
| 39 | 39 | } |
| 40 | 40 | |
| 41 | −#define CACHELINES_PER_PAGE (PAGE_SIZE / CACHELINE_BYTES) | |
| 41 | +static int selftest_tl_pin(struct intel_timeline *tl) | |
| 42 | +{ | |
| 43 | + struct i915_gem_ww_ctx ww; | |
| 44 | + int err; | |
| 45 | + | |
| 46 | + i915_gem_ww_ctx_init(&ww, false); | |
| 47 | +retry: | |
| 48 | + err = i915_gem_object_lock(tl->hwsp_ggtt->obj, &ww); | |
| 49 | + if (!err) | |
| 50 | + err = intel_timeline_pin(tl, &ww); | |
| 51 | + | |
| 52 | + if (err == -EDEADLK) { | |
| 53 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 54 | + if (!err) | |
| 55 | + goto retry; | |
| 56 | + } | |
| 57 | + i915_gem_ww_ctx_fini(&ww); | |
| 58 | + return err; | |
| 59 | +} | |
| 60 | + | |
| 61 | +/* Only half of seqno's are usable, see __intel_timeline_get_seqno() */ | |
| 62 | +#define CACHELINES_PER_PAGE (PAGE_SIZE / TIMELINE_SEQNO_BYTES / 2) | |
| 42 | 63 | |
| 43 | 64 | struct mock_hwsp_freelist { |
| 44 | 65 | struct intel_gt *gt; |
| @@ -59,6 +80,7 @@ static void __mock_hwsp_record(struct mock_hwsp_freelist *state, · 14 unmodified lines | ||
| 59 | 80 | tl = xchg(&state->history[idx], tl); |
| 60 | 81 | if (tl) { |
| 61 | 82 | radix_tree_delete(&state->cachelines, hwsp_cacheline(tl)); |
| 83 | + intel_timeline_unpin(tl); | |
| 62 | 84 | intel_timeline_put(tl); |
| 63 | 85 | } |
| 64 | 86 | } |
| @@ -78,6 +100,12 @@ static int __mock_hwsp_timeline(struct mock_hwsp_freelist *state, · 13 unmodified lines | ||
| 78 | 100 | if (IS_ERR(tl)) |
| 79 | 101 | return PTR_ERR(tl); |
| 80 | 102 | |
| 103 | + err = selftest_tl_pin(tl); | |
| 104 | + if (err) { | |
| 105 | + intel_timeline_put(tl); | |
| 106 | + return err; | |
| 107 | + } | |
| 108 | + | |
| 81 | 109 | cacheline = hwsp_cacheline(tl); |
| 82 | 110 | err = radix_tree_insert(&state->cachelines, cacheline, tl); |
| 83 | 111 | if (err) { |
| @@ -85,6 +113,7 @@ static int __mock_hwsp_timeline(struct mock_hwsp_freelist *state, · 1 unmodified line | ||
| 85 | 113 | pr_err("HWSP cacheline %lu already used; duplicate allocation!\n", |
| 86 | 114 | cacheline); |
| 87 | 115 | } |
| 116 | + intel_timeline_unpin(tl); | |
| 88 | 117 | intel_timeline_put(tl); |
| 89 | 118 | return err; |
| 90 | 119 | } |
| @@ -452,17 +481,24 @@ static int emit_ggtt_store_dw(struct i915_request *rq, u32 addr, u32 value) · 361 unmodified lines | ||
| 452 | 481 | } |
| 453 | 482 | |
| 454 | 483 | static struct i915_request * |
| 455 | −tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value) | |
| 484 | +checked_tl_write(struct intel_timeline *tl, struct intel_engine_cs *engine, u32 value) | |
| 456 | 485 | { |
| 457 | 486 | struct i915_request *rq; |
| 458 | 487 | int err; |
| 459 | 488 | |
| 460 | − err = intel_timeline_pin(tl, NULL); | |
| 489 | + err = selftest_tl_pin(tl); | |
| 461 | 490 | if (err) { |
| 462 | 491 | rq = ERR_PTR(err); |
| 463 | 492 | goto out; |
| 464 | 493 | } |
| 465 | 494 | |
| 495 | + if (READ_ONCE(*tl->hwsp_seqno) != tl->seqno) { | |
| 496 | + pr_err("Timeline created with incorrect breadcrumb, found %x, expected %x\n", | |
| 497 | + *tl->hwsp_seqno, tl->seqno); | |
| 498 | + intel_timeline_unpin(tl); | |
| 499 | + return ERR_PTR(-EINVAL); | |
| 500 | + } | |
| 501 | + | |
| 466 | 502 | rq = intel_engine_create_kernel_request(engine); |
| 467 | 503 | if (IS_ERR(rq)) |
| 468 | 504 | goto out_unpin; |
| @@ -484,25 +520,6 @@ out: · 15 unmodified lines | ||
| 484 | 520 | return rq; |
| 485 | 521 | } |
| 486 | 522 | |
| 487 | −static struct intel_timeline * | |
| 488 | −checked_intel_timeline_create(struct intel_gt *gt) | |
| 489 | −{ | |
| 490 | − struct intel_timeline *tl; | |
| 491 | − | |
| 492 | − tl = intel_timeline_create(gt); | |
| 493 | − if (IS_ERR(tl)) | |
| 494 | − return tl; | |
| 495 | − | |
| 496 | − if (READ_ONCE(*tl->hwsp_seqno) != tl->seqno) { | |
| 497 | − pr_err("Timeline created with incorrect breadcrumb, found %x, expected %x\n", | |
| 498 | − *tl->hwsp_seqno, tl->seqno); | |
| 499 | − intel_timeline_put(tl); | |
| 500 | − return ERR_PTR(-EINVAL); | |
| 501 | − } | |
| 502 | − | |
| 503 | − return tl; | |
| 504 | −} | |
| 505 | − | |
| 506 | 523 | static int live_hwsp_engine(void *arg) |
| 507 | 524 | { |
| 508 | 525 | #define NUM_TIMELINES 4096 |
| @@ -535,13 +552,13 @@ static int live_hwsp_engine(void *arg) · 26 unmodified lines | ||
| 535 | 552 | struct intel_timeline *tl; |
| 536 | 553 | struct i915_request *rq; |
| 537 | 554 | |
| 538 | − tl = checked_intel_timeline_create(gt); | |
| 555 | + tl = intel_timeline_create(gt); | |
| 539 | 556 | if (IS_ERR(tl)) { |
| 540 | 557 | err = PTR_ERR(tl); |
| 541 | 558 | break; |
| 542 | 559 | } |
| 543 | 560 | |
| 544 | − rq = tl_write(tl, engine, count); | |
| 561 | + rq = checked_tl_write(tl, engine, count); | |
| 545 | 562 | if (IS_ERR(rq)) { |
| 546 | 563 | intel_timeline_put(tl); |
| 547 | 564 | err = PTR_ERR(rq); |
| @@ -608,14 +625,14 @@ static int live_hwsp_alternate(void *arg) · 60 unmodified lines | ||
| 608 | 625 | if (!intel_engine_can_store_dword(engine)) |
| 609 | 626 | continue; |
| 610 | 627 | |
| 611 | − tl = checked_intel_timeline_create(gt); | |
| 628 | + tl = intel_timeline_create(gt); | |
| 612 | 629 | if (IS_ERR(tl)) { |
| 613 | 630 | err = PTR_ERR(tl); |
| 614 | 631 | goto out; |
| 615 | 632 | } |
| 616 | 633 | |
| 617 | 634 | intel_engine_pm_get(engine); |
| 618 | − rq = tl_write(tl, engine, count); | |
| 635 | + rq = checked_tl_write(tl, engine, count); | |
| 619 | 636 | intel_engine_pm_put(engine); |
| 620 | 637 | if (IS_ERR(rq)) { |
| 621 | 638 | intel_timeline_put(tl); |
| @@ -666,10 +683,10 @@ static int live_hwsp_wrap(void *arg) · 44 unmodified lines | ||
| 666 | 683 | if (IS_ERR(tl)) |
| 667 | 684 | return PTR_ERR(tl); |
| 668 | 685 | |
| 669 | − if (!tl->has_initial_breadcrumb || !tl->hwsp_cacheline) | |
| 686 | + if (!tl->has_initial_breadcrumb) | |
| 670 | 687 | goto out_free; |
| 671 | 688 | |
| 672 | − err = intel_timeline_pin(tl, NULL); | |
| 689 | + err = selftest_tl_pin(tl); | |
| 673 | 690 | if (err) |
| 674 | 691 | goto out_free; |
| 675 | 692 | |
| @@ -816,13 +833,13 @@ static int setup_watcher(struct hwsp_watcher *w, struct intel_gt *gt) · 140 unmodified lines | ||
| 816 | 833 | if (IS_ERR(obj)) |
| 817 | 834 | return PTR_ERR(obj); |
| 818 | 835 | |
| 819 | − w->map = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 836 | + w->map = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 820 | 837 | if (IS_ERR(w->map)) { |
| 821 | 838 | i915_gem_object_put(obj); |
| 822 | 839 | return PTR_ERR(w->map); |
| 823 | 840 | } |
| 824 | 841 | |
| 825 | − vma = i915_gem_object_ggtt_pin_ww(obj, NULL, NULL, 0, 0, 0); | |
| 842 | + vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, 0); | |
| 826 | 843 | if (IS_ERR(vma)) { |
| 827 | 844 | i915_gem_object_put(obj); |
| 828 | 845 | return PTR_ERR(vma); |
| @@ -833,12 +850,26 @@ static int setup_watcher(struct hwsp_watcher *w, struct intel_gt *gt) · 4 unmodified lines | ||
| 833 | 850 | return 0; |
| 834 | 851 | } |
| 835 | 852 | |
| 853 | +static void switch_tl_lock(struct i915_request *from, struct i915_request *to) | |
| 854 | +{ | |
| 855 | + /* some light mutex juggling required; think co-routines */ | |
| 856 | + | |
| 857 | + if (from) { | |
| 858 | + lockdep_unpin_lock(&from->context->timeline->mutex, from->cookie); | |
| 859 | + mutex_unlock(&from->context->timeline->mutex); | |
| 860 | + } | |
| 861 | + | |
| 862 | + if (to) { | |
| 863 | + mutex_lock(&to->context->timeline->mutex); | |
| 864 | + to->cookie = lockdep_pin_lock(&to->context->timeline->mutex); | |
| 865 | + } | |
| 866 | +} | |
| 867 | + | |
| 836 | 868 | static int create_watcher(struct hwsp_watcher *w, |
| 837 | 869 | struct intel_engine_cs *engine, |
| 838 | 870 | int ringsz) |
| 839 | 871 | { |
| 840 | 872 | struct intel_context *ce; |
| 841 | − struct intel_timeline *tl; | |
| 842 | 873 | |
| 843 | 874 | ce = intel_context_create(engine); |
| 844 | 875 | if (IS_ERR(ce)) |
| @@ -851,11 +882,8 @@ static int create_watcher(struct hwsp_watcher *w, · 6 unmodified lines | ||
| 851 | 882 | return PTR_ERR(w->rq); |
| 852 | 883 | |
| 853 | 884 | w->addr = i915_ggtt_offset(w->vma); |
| 854 | − tl = w->rq->context->timeline; | |
| 855 | 885 | |
| 856 | − /* some light mutex juggling required; think co-routines */ | |
| 857 | − lockdep_unpin_lock(&tl->mutex, w->rq->cookie); | |
| 858 | − mutex_unlock(&tl->mutex); | |
| 886 | + switch_tl_lock(w->rq, NULL); | |
| 859 | 887 | |
| 860 | 888 | return 0; |
| 861 | 889 | } |
| @@ -864,15 +892,13 @@ static int check_watcher(struct hwsp_watcher *w, const char *name, · 2 unmodified lines | ||
| 864 | 892 | bool (*op)(u32 hwsp, u32 seqno)) |
| 865 | 893 | { |
| 866 | 894 | struct i915_request *rq = fetch_and_zero(&w->rq); |
| 867 | − struct intel_timeline *tl = rq->context->timeline; | |
| 868 | 895 | u32 offset, end; |
| 869 | 896 | int err; |
| 870 | 897 | |
| 871 | 898 | GEM_BUG_ON(w->addr - i915_ggtt_offset(w->vma) > w->vma->size); |
| 872 | 899 | |
| 873 | 900 | i915_request_get(rq); |
| 874 | − mutex_lock(&tl->mutex); | |
| 875 | − rq->cookie = lockdep_pin_lock(&tl->mutex); | |
| 901 | + switch_tl_lock(NULL, rq); | |
| 876 | 902 | i915_request_add(rq); |
| 877 | 903 | |
| 878 | 904 | if (i915_request_wait(rq, 0, HZ) < 0) { |
| @@ -901,10 +927,7 @@ out: · 22 unmodified lines | ||
| 901 | 927 | static void cleanup_watcher(struct hwsp_watcher *w) |
| 902 | 928 | { |
| 903 | 929 | if (w->rq) { |
| 904 | − struct intel_timeline *tl = w->rq->context->timeline; | |
| 905 | − | |
| 906 | − mutex_lock(&tl->mutex); | |
| 907 | − w->rq->cookie = lockdep_pin_lock(&tl->mutex); | |
| 930 | + switch_tl_lock(NULL, w->rq); | |
| 908 | 931 | |
| 909 | 932 | i915_request_add(w->rq); |
| 910 | 933 | } |
| @@ -942,7 +965,7 @@ static struct i915_request *wrap_timeline(struct i915_request *rq) · 31 unmodified lines | ||
| 942 | 965 | } |
| 943 | 966 | |
| 944 | 967 | i915_request_put(rq); |
| 945 | − rq = intel_context_create_request(ce); | |
| 968 | + rq = i915_request_create(ce); | |
| 946 | 969 | if (IS_ERR(rq)) |
| 947 | 970 | return rq; |
| 948 | 971 | |
| @@ -977,7 +1000,7 @@ static int live_hwsp_read(void *arg) · 28 unmodified lines | ||
| 977 | 1000 | if (IS_ERR(tl)) |
| 978 | 1001 | return PTR_ERR(tl); |
| 979 | 1002 | |
| 980 | − if (!tl->hwsp_cacheline) | |
| 1003 | + if (!tl->has_initial_breadcrumb) | |
| 981 | 1004 | goto out_free; |
| 982 | 1005 | |
| 983 | 1006 | for (i = 0; i < ARRAY_SIZE(watcher); i++) { |
| @@ -999,7 +1022,7 @@ static int live_hwsp_read(void *arg) · 15 unmodified lines | ||
| 999 | 1022 | do { |
| 1000 | 1023 | struct i915_sw_fence *submit; |
| 1001 | 1024 | struct i915_request *rq; |
| 1002 | − u32 hwsp; | |
| 1025 | + u32 hwsp, dummy; | |
| 1003 | 1026 | |
| 1004 | 1027 | submit = heap_fence_create(GFP_KERNEL); |
| 1005 | 1028 | if (!submit) { |
| @@ -1017,14 +1040,26 @@ static int live_hwsp_read(void *arg) · 11 unmodified lines | ||
| 1017 | 1040 | goto out; |
| 1018 | 1041 | } |
| 1019 | 1042 | |
| 1020 | − /* Skip to the end, saving 30 minutes of nops */ | |
| 1021 | − tl->seqno = -10u + 2 * (count & 3); | |
| 1022 | − WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno); | |
| 1023 | 1043 | ce->timeline = intel_timeline_get(tl); |
| 1024 | 1044 | |
| 1025 | − rq = intel_context_create_request(ce); | |
| 1045 | + /* Ensure timeline is mapped, done during first pin */ | |
| 1046 | + err = intel_context_pin(ce); | |
| 1047 | + if (err) { | |
| 1048 | + intel_context_put(ce); | |
| 1049 | + goto out; | |
| 1050 | + } | |
| 1051 | + | |
| 1052 | + /* | |
| 1053 | + * Start at a new wrap, and set seqno right before another wrap, | |
| 1054 | + * saving 30 minutes of nops | |
| 1055 | + */ | |
| 1056 | + tl->seqno = -12u + 2 * (count & 3); | |
| 1057 | + __intel_timeline_get_seqno(tl, &dummy); | |
| 1058 | + | |
| 1059 | + rq = i915_request_create(ce); | |
| 1026 | 1060 | if (IS_ERR(rq)) { |
| 1027 | 1061 | err = PTR_ERR(rq); |
| 1062 | + intel_context_unpin(ce); | |
| 1028 | 1063 | intel_context_put(ce); |
| 1029 | 1064 | goto out; |
| 1030 | 1065 | } |
| @@ -1034,32 +1069,35 @@ static int live_hwsp_read(void *arg) · 3 unmodified lines | ||
| 1034 | 1069 | GFP_KERNEL); |
| 1035 | 1070 | if (err < 0) { |
| 1036 | 1071 | i915_request_add(rq); |
| 1072 | + intel_context_unpin(ce); | |
| 1037 | 1073 | intel_context_put(ce); |
| 1038 | 1074 | goto out; |
| 1039 | 1075 | } |
| 1040 | 1076 | |
| 1041 | − mutex_lock(&watcher[0].rq->context->timeline->mutex); | |
| 1077 | + switch_tl_lock(rq, watcher[0].rq); | |
| 1042 | 1078 | err = intel_timeline_read_hwsp(rq, watcher[0].rq, &hwsp); |
| 1043 | 1079 | if (err == 0) |
| 1044 | 1080 | err = emit_read_hwsp(watcher[0].rq, /* before */ |
| 1045 | 1081 | rq->fence.seqno, hwsp, |
| 1046 | 1082 | &watcher[0].addr); |
| 1047 | − mutex_unlock(&watcher[0].rq->context->timeline->mutex); | |
| 1083 | + switch_tl_lock(watcher[0].rq, rq); | |
| 1048 | 1084 | if (err) { |
| 1049 | 1085 | i915_request_add(rq); |
| 1086 | + intel_context_unpin(ce); | |
| 1050 | 1087 | intel_context_put(ce); |
| 1051 | 1088 | goto out; |
| 1052 | 1089 | } |
| 1053 | 1090 | |
| 1054 | − mutex_lock(&watcher[1].rq->context->timeline->mutex); | |
| 1091 | + switch_tl_lock(rq, watcher[1].rq); | |
| 1055 | 1092 | err = intel_timeline_read_hwsp(rq, watcher[1].rq, &hwsp); |
| 1056 | 1093 | if (err == 0) |
| 1057 | 1094 | err = emit_read_hwsp(watcher[1].rq, /* after */ |
| 1058 | 1095 | rq->fence.seqno, hwsp, |
| 1059 | 1096 | &watcher[1].addr); |
| 1060 | − mutex_unlock(&watcher[1].rq->context->timeline->mutex); | |
| 1097 | + switch_tl_lock(watcher[1].rq, rq); | |
| 1061 | 1098 | if (err) { |
| 1062 | 1099 | i915_request_add(rq); |
| 1100 | + intel_context_unpin(ce); | |
| 1063 | 1101 | intel_context_put(ce); |
| 1064 | 1102 | goto out; |
| 1065 | 1103 | } |
| @@ -1068,6 +1106,7 @@ static int live_hwsp_read(void *arg) · 2 unmodified lines | ||
| 1068 | 1106 | i915_request_add(rq); |
| 1069 | 1107 | |
| 1070 | 1108 | rq = wrap_timeline(rq); |
| 1109 | + intel_context_unpin(ce); | |
| 1071 | 1110 | intel_context_put(ce); |
| 1072 | 1111 | if (IS_ERR(rq)) { |
| 1073 | 1112 | err = PTR_ERR(rq); |
| @@ -1107,8 +1146,8 @@ static int live_hwsp_read(void *arg) · 33 unmodified lines | ||
| 1107 | 1146 | 3 * watcher[1].rq->ring->size) |
| 1108 | 1147 | break; |
| 1109 | 1148 | |
| 1110 | − } while (!__igt_timeout(end_time, NULL)); | |
| 1111 | − WRITE_ONCE(*(u32 *)tl->hwsp_seqno, 0xdeadbeef); | |
| 1149 | + } while (!__igt_timeout(end_time, NULL) && | |
| 1150 | + count < (PAGE_SIZE / TIMELINE_SEQNO_BYTES - 1) / 2); | |
| 1112 | 1151 | |
| 1113 | 1152 | pr_info("%s: simulated %lu wraps\n", engine->name, count); |
| 1114 | 1153 | err = check_watcher(&watcher[1], "after", cmp_gte); |
| @@ -1153,9 +1192,7 @@ static int live_hwsp_rollover_kernel(void *arg) · 38 unmodified lines | ||
| 1153 | 1192 | } |
| 1154 | 1193 | |
| 1155 | 1194 | GEM_BUG_ON(i915_active_fence_isset(&tl->last_request)); |
| 1156 | − tl->seqno = 0; | |
| 1157 | − timeline_rollback(tl); | |
| 1158 | − timeline_rollback(tl); | |
| 1195 | + tl->seqno = -2u; | |
| 1159 | 1196 | WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno); |
| 1160 | 1197 | |
| 1161 | 1198 | for (i = 0; i < ARRAY_SIZE(rq); i++) { |
| @@ -1235,11 +1272,14 @@ static int live_hwsp_rollover_user(void *arg) · 73 unmodified lines | ||
| 1235 | 1272 | goto out; |
| 1236 | 1273 | |
| 1237 | 1274 | tl = ce->timeline; |
| 1238 | − if (!tl->has_initial_breadcrumb || !tl->hwsp_cacheline) | |
| 1275 | + if (!tl->has_initial_breadcrumb) | |
| 1276 | + goto out; | |
| 1277 | + | |
| 1278 | + err = intel_context_pin(ce); | |
| 1279 | + if (err) | |
| 1239 | 1280 | goto out; |
| 1240 | 1281 | |
| 1241 | − timeline_rollback(tl); | |
| 1242 | − timeline_rollback(tl); | |
| 1282 | + tl->seqno = -4u; | |
| 1243 | 1283 | WRITE_ONCE(*(u32 *)tl->hwsp_seqno, tl->seqno); |
| 1244 | 1284 | |
| 1245 | 1285 | for (i = 0; i < ARRAY_SIZE(rq); i++) { |
| @@ -1248,7 +1288,7 @@ static int live_hwsp_rollover_user(void *arg) · 2 unmodified lines | ||
| 1248 | 1288 | this = intel_context_create_request(ce); |
| 1249 | 1289 | if (IS_ERR(this)) { |
| 1250 | 1290 | err = PTR_ERR(this); |
| 1251 | − goto out; | |
| 1291 | + goto out_unpin; | |
| 1252 | 1292 | } |
| 1253 | 1293 | |
| 1254 | 1294 | pr_debug("%s: create fence.seqnp:%d\n", |
| @@ -1267,17 +1307,18 @@ static int live_hwsp_rollover_user(void *arg) · 12 unmodified lines | ||
| 1267 | 1307 | if (i915_request_wait(rq[2], 0, HZ / 5) < 0) { |
| 1268 | 1308 | pr_err("Wait for timeline wrap timed out!\n"); |
| 1269 | 1309 | err = -EIO; |
| 1270 | − goto out; | |
| 1310 | + goto out_unpin; | |
| 1271 | 1311 | } |
| 1272 | 1312 | |
| 1273 | 1313 | for (i = 0; i < ARRAY_SIZE(rq); i++) { |
| 1274 | 1314 | if (!i915_request_completed(rq[i])) { |
| 1275 | 1315 | pr_err("Pre-wrap request not completed!\n"); |
| 1276 | 1316 | err = -EINVAL; |
| 1277 | − goto out; | |
| 1317 | + goto out_unpin; | |
| 1278 | 1318 | } |
| 1279 | 1319 | } |
| 1280 | − | |
| 1320 | +out_unpin: | |
| 1321 | + intel_context_unpin(ce); | |
| 1281 | 1322 | out: |
| 1282 | 1323 | for (i = 0; i < ARRAY_SIZE(rq); i++) |
| 1283 | 1324 | i915_request_put(rq[i]); |
| @@ -1319,13 +1360,13 @@ static int live_hwsp_recycle(void *arg) · 35 unmodified lines | ||
| 1319 | 1360 | struct intel_timeline *tl; |
| 1320 | 1361 | struct i915_request *rq; |
| 1321 | 1362 | |
| 1322 | − tl = checked_intel_timeline_create(gt); | |
| 1363 | + tl = intel_timeline_create(gt); | |
| 1323 | 1364 | if (IS_ERR(tl)) { |
| 1324 | 1365 | err = PTR_ERR(tl); |
| 1325 | 1366 | break; |
| 1326 | 1367 | } |
| 1327 | 1368 | |
| 1328 | − rq = tl_write(tl, engine, count); | |
| 1369 | + rq = checked_tl_write(tl, engine, count); | |
| 1329 | 1370 | if (IS_ERR(rq)) { |
| 1330 | 1371 | intel_timeline_put(tl); |
| 1331 | 1372 | err = PTR_ERR(rq); |
| @@ -112,7 +112,7 @@ read_nonprivs(struct intel_context *ce) · 111 unmodified lines | ||
| 112 | 112 | |
| 113 | 113 | i915_gem_object_set_cache_coherency(result, I915_CACHE_LLC); |
| 114 | 114 | |
| 115 | − cs = i915_gem_object_pin_map(result, I915_MAP_WB); | |
| 115 | + cs = i915_gem_object_pin_map_unlocked(result, I915_MAP_WB); | |
| 116 | 116 | if (IS_ERR(cs)) { |
| 117 | 117 | err = PTR_ERR(cs); |
| 118 | 118 | goto err_obj; |
| @@ -218,7 +218,7 @@ static int check_whitelist(struct intel_context *ce) · 99 unmodified lines | ||
| 218 | 218 | i915_gem_object_lock(results, NULL); |
| 219 | 219 | intel_wedge_on_timeout(&wedge, engine->gt, HZ / 5) /* safety net! */ |
| 220 | 220 | err = i915_gem_object_set_to_cpu_domain(results, false); |
| 221 | − i915_gem_object_unlock(results); | |
| 221 | + | |
| 222 | 222 | if (intel_gt_is_wedged(engine->gt)) |
| 223 | 223 | err = -EIO; |
| 224 | 224 | if (err) |
| @@ -246,6 +246,7 @@ static int check_whitelist(struct intel_context *ce) · 21 unmodified lines | ||
| 246 | 246 | |
| 247 | 247 | i915_gem_object_unpin_map(results); |
| 248 | 248 | out_put: |
| 249 | + i915_gem_object_unlock(results); | |
| 249 | 250 | i915_gem_object_put(results); |
| 250 | 251 | return err; |
| 251 | 252 | } |
| @@ -490,7 +491,7 @@ static int check_dirty_whitelist(struct intel_context *ce) · 238 unmodified lines | ||
| 490 | 491 | u32 *cs, *results; |
| 491 | 492 | |
| 492 | 493 | sz = (2 * ARRAY_SIZE(values) + 1) * sizeof(u32); |
| 493 | − scratch = __vm_create_scratch_for_read(ce->vm, sz); | |
| 494 | + scratch = __vm_create_scratch_for_read_pinned(ce->vm, sz); | |
| 494 | 495 | if (IS_ERR(scratch)) |
| 495 | 496 | return PTR_ERR(scratch); |
| 496 | 497 | |
| @@ -502,6 +503,7 @@ static int check_dirty_whitelist(struct intel_context *ce) · 5 unmodified lines | ||
| 502 | 503 | |
| 503 | 504 | for (i = 0; i < engine->whitelist.count; i++) { |
| 504 | 505 | u32 reg = i915_mmio_reg_offset(engine->whitelist.list[i].reg); |
| 506 | + struct i915_gem_ww_ctx ww; | |
| 505 | 507 | u64 addr = scratch->node.start; |
| 506 | 508 | struct i915_request *rq; |
| 507 | 509 | u32 srm, lrm, rsvd; |
| @@ -517,6 +519,29 @@ static int check_dirty_whitelist(struct intel_context *ce) · 9 unmodified lines | ||
| 517 | 519 | |
| 518 | 520 | ro_reg = ro_register(reg); |
| 519 | 521 | |
| 522 | + i915_gem_ww_ctx_init(&ww, false); | |
| 523 | +retry: | |
| 524 | + cs = NULL; | |
| 525 | + err = i915_gem_object_lock(scratch->obj, &ww); | |
| 526 | + if (!err) | |
| 527 | + err = i915_gem_object_lock(batch->obj, &ww); | |
| 528 | + if (!err) | |
| 529 | + err = intel_context_pin_ww(ce, &ww); | |
| 530 | + if (err) | |
| 531 | + goto out; | |
| 532 | + | |
| 533 | + cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); | |
| 534 | + if (IS_ERR(cs)) { | |
| 535 | + err = PTR_ERR(cs); | |
| 536 | + goto out_ctx; | |
| 537 | + } | |
| 538 | + | |
| 539 | + results = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB); | |
| 540 | + if (IS_ERR(results)) { | |
| 541 | + err = PTR_ERR(results); | |
| 542 | + goto out_unmap_batch; | |
| 543 | + } | |
| 544 | + | |
| 520 | 545 | /* Clear non priv flags */ |
| 521 | 546 | reg &= RING_FORCE_TO_NONPRIV_ADDRESS_MASK; |
| 522 | 547 | |
| @@ -528,12 +553,6 @@ static int check_dirty_whitelist(struct intel_context *ce) · 5 unmodified lines | ||
| 528 | 553 | pr_debug("%s: Writing garbage to %x\n", |
| 529 | 554 | engine->name, reg); |
| 530 | 555 | |
| 531 | − cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); | |
| 532 | − if (IS_ERR(cs)) { | |
| 533 | − err = PTR_ERR(cs); | |
| 534 | − goto out_batch; | |
| 535 | − } | |
| 536 | − | |
| 537 | 556 | /* SRM original */ |
| 538 | 557 | *cs++ = srm; |
| 539 | 558 | *cs++ = reg; |
| @@ -580,11 +599,12 @@ static int check_dirty_whitelist(struct intel_context *ce) · 40 unmodified lines | ||
| 580 | 599 | i915_gem_object_flush_map(batch->obj); |
| 581 | 600 | i915_gem_object_unpin_map(batch->obj); |
| 582 | 601 | intel_gt_chipset_flush(engine->gt); |
| 602 | + cs = NULL; | |
| 583 | 603 | |
| 584 | − rq = intel_context_create_request(ce); | |
| 604 | + rq = i915_request_create(ce); | |
| 585 | 605 | if (IS_ERR(rq)) { |
| 586 | 606 | err = PTR_ERR(rq); |
| 587 | − goto out_batch; | |
| 607 | + goto out_unmap_scratch; | |
| 588 | 608 | } |
| 589 | 609 | |
| 590 | 610 | if (engine->emit_init_breadcrumb) { /* Be nice if we hang */ |
| @@ -593,20 +613,16 @@ static int check_dirty_whitelist(struct intel_context *ce) · 2 unmodified lines | ||
| 593 | 613 | goto err_request; |
| 594 | 614 | } |
| 595 | 615 | |
| 596 | − i915_vma_lock(batch); | |
| 597 | 616 | err = i915_request_await_object(rq, batch->obj, false); |
| 598 | 617 | if (err == 0) |
| 599 | 618 | err = i915_vma_move_to_active(batch, rq, 0); |
| 600 | − i915_vma_unlock(batch); | |
| 601 | 619 | if (err) |
| 602 | 620 | goto err_request; |
| 603 | 621 | |
| 604 | − i915_vma_lock(scratch); | |
| 605 | 622 | err = i915_request_await_object(rq, scratch->obj, true); |
| 606 | 623 | if (err == 0) |
| 607 | 624 | err = i915_vma_move_to_active(scratch, rq, |
| 608 | 625 | EXEC_OBJECT_WRITE); |
| 609 | − i915_vma_unlock(scratch); | |
| 610 | 626 | if (err) |
| 611 | 627 | goto err_request; |
| 612 | 628 | |
| @@ -622,13 +638,7 @@ err_request: · 9 unmodified lines | ||
| 622 | 638 | pr_err("%s: Futzing %x timedout; cancelling test\n", |
| 623 | 639 | engine->name, reg); |
| 624 | 640 | intel_gt_set_wedged(engine->gt); |
| 625 | − goto out_batch; | |
| 626 | − } | |
| 627 | − | |
| 628 | − results = i915_gem_object_pin_map(scratch->obj, I915_MAP_WB); | |
| 629 | − if (IS_ERR(results)) { | |
| 630 | − err = PTR_ERR(results); | |
| 631 | − goto out_batch; | |
| 641 | + goto out_unmap_scratch; | |
| 632 | 642 | } |
| 633 | 643 | |
| 634 | 644 | GEM_BUG_ON(values[ARRAY_SIZE(values) - 1] != 0xffffffff); |
| @@ -639,7 +649,7 @@ err_request: · 4 unmodified lines | ||
| 639 | 649 | pr_err("%s: Unable to write to whitelisted register %x\n", |
| 640 | 650 | engine->name, reg); |
| 641 | 651 | err = -EINVAL; |
| 642 | − goto out_unpin; | |
| 652 | + goto out_unmap_scratch; | |
| 643 | 653 | } |
| 644 | 654 | } else { |
| 645 | 655 | rsvd = 0; |
| @@ -705,15 +715,27 @@ err_request: · 59 unmodified lines | ||
| 705 | 715 | |
| 706 | 716 | err = -EINVAL; |
| 707 | 717 | } |
| 708 | −out_unpin: | |
| 718 | +out_unmap_scratch: | |
| 709 | 719 | i915_gem_object_unpin_map(scratch->obj); |
| 720 | +out_unmap_batch: | |
| 721 | + if (cs) | |
| 722 | + i915_gem_object_unpin_map(batch->obj); | |
| 723 | +out_ctx: | |
| 724 | + intel_context_unpin(ce); | |
| 725 | +out: | |
| 726 | + if (err == -EDEADLK) { | |
| 727 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 728 | + if (!err) | |
| 729 | + goto retry; | |
| 730 | + } | |
| 731 | + i915_gem_ww_ctx_fini(&ww); | |
| 710 | 732 | if (err) |
| 711 | 733 | break; |
| 712 | 734 | } |
| 713 | 735 | |
| 714 | 736 | if (igt_flush_test(engine->i915)) |
| 715 | 737 | err = -EIO; |
| 716 | −out_batch: | |
| 738 | + | |
| 717 | 739 | i915_vma_unpin_and_release(&batch, 0); |
| 718 | 740 | out_scratch: |
| 719 | 741 | i915_vma_unpin_and_release(&scratch, 0); |
| @@ -847,7 +869,7 @@ static int scrub_whitelisted_registers(struct intel_context *ce) · 127 unmodified lines | ||
| 847 | 869 | if (IS_ERR(batch)) |
| 848 | 870 | return PTR_ERR(batch); |
| 849 | 871 | |
| 850 | − cs = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); | |
| 872 | + cs = i915_gem_object_pin_map_unlocked(batch->obj, I915_MAP_WC); | |
| 851 | 873 | if (IS_ERR(cs)) { |
| 852 | 874 | err = PTR_ERR(cs); |
| 853 | 875 | goto err_batch; |
| @@ -982,11 +1004,11 @@ check_whitelisted_registers(struct intel_engine_cs *engine, · 128 unmodified lines | ||
| 982 | 1004 | u32 *a, *b; |
| 983 | 1005 | int i, err; |
| 984 | 1006 | |
| 985 | − a = i915_gem_object_pin_map(A->obj, I915_MAP_WB); | |
| 1007 | + a = i915_gem_object_pin_map_unlocked(A->obj, I915_MAP_WB); | |
| 986 | 1008 | if (IS_ERR(a)) |
| 987 | 1009 | return PTR_ERR(a); |
| 988 | 1010 | |
| 989 | − b = i915_gem_object_pin_map(B->obj, I915_MAP_WB); | |
| 1011 | + b = i915_gem_object_pin_map_unlocked(B->obj, I915_MAP_WB); | |
| 990 | 1012 | if (IS_ERR(b)) { |
| 991 | 1013 | err = PTR_ERR(b); |
| 992 | 1014 | goto err_a; |
| @@ -1030,14 +1052,14 @@ static int live_isolated_whitelist(void *arg) · 37 unmodified lines | ||
| 1030 | 1052 | |
| 1031 | 1053 | for (i = 0; i < ARRAY_SIZE(client); i++) { |
| 1032 | 1054 | client[i].scratch[0] = |
| 1033 | − __vm_create_scratch_for_read(gt->vm, 4096); | |
| 1055 | + __vm_create_scratch_for_read_pinned(gt->vm, 4096); | |
| 1034 | 1056 | if (IS_ERR(client[i].scratch[0])) { |
| 1035 | 1057 | err = PTR_ERR(client[i].scratch[0]); |
| 1036 | 1058 | goto err; |
| 1037 | 1059 | } |
| 1038 | 1060 | |
| 1039 | 1061 | client[i].scratch[1] = |
| 1040 | − __vm_create_scratch_for_read(gt->vm, 4096); | |
| 1062 | + __vm_create_scratch_for_read_pinned(gt->vm, 4096); | |
| 1041 | 1063 | if (IS_ERR(client[i].scratch[1])) { |
| 1042 | 1064 | err = PTR_ERR(client[i].scratch[1]); |
| 1043 | 1065 | i915_vma_unpin_and_release(&client[i].scratch[0], 0); |
| @@ -39,7 +39,7 @@ struct file *shmem_create_from_object(struct drm_i915_gem_object *obj) · 38 unmodified lines | ||
| 39 | 39 | return file; |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | − ptr = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 42 | + ptr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 43 | 43 | if (IS_ERR(ptr)) |
| 44 | 44 | return ERR_CAST(ptr); |
| 45 | 45 | |
| @@ -682,7 +682,7 @@ int intel_guc_allocate_and_map_vma(struct intel_guc *guc, u32 size, · 681 unmodified lines | ||
| 682 | 682 | if (IS_ERR(vma)) |
| 683 | 683 | return PTR_ERR(vma); |
| 684 | 684 | |
| 685 | − vaddr = i915_gem_object_pin_map(vma->obj, I915_MAP_WB); | |
| 685 | + vaddr = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WB); | |
| 686 | 686 | if (IS_ERR(vaddr)) { |
| 687 | 687 | i915_vma_unpin_and_release(&vma, 0); |
| 688 | 688 | return PTR_ERR(vaddr); |
| @@ -335,7 +335,7 @@ static int guc_log_map(struct intel_guc_log *log) · 334 unmodified lines | ||
| 335 | 335 | * buffer pages, so that we can directly get the data |
| 336 | 336 | * (up-to-date) from memory. |
| 337 | 337 | */ |
| 338 | − vaddr = i915_gem_object_pin_map(log->vma->obj, I915_MAP_WC); | |
| 338 | + vaddr = i915_gem_object_pin_map_unlocked(log->vma->obj, I915_MAP_WC); | |
| 339 | 339 | if (IS_ERR(vaddr)) |
| 340 | 340 | return PTR_ERR(vaddr); |
| 341 | 341 | |
| @@ -744,7 +744,7 @@ int intel_guc_log_dump(struct intel_guc_log *log, struct drm_printer *p, · 402 unmodified lines | ||
| 744 | 744 | if (!obj) |
| 745 | 745 | return 0; |
| 746 | 746 | |
| 747 | − map = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 747 | + map = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 748 | 748 | if (IS_ERR(map)) { |
| 749 | 749 | DRM_DEBUG("Failed to pin object\n"); |
| 750 | 750 | drm_puts(p, "(log data unaccessible)\n"); |
| @@ -82,7 +82,7 @@ static int intel_huc_rsa_data_create(struct intel_huc *huc) · 81 unmodified lines | ||
| 82 | 82 | if (IS_ERR(vma)) |
| 83 | 83 | return PTR_ERR(vma); |
| 84 | 84 | |
| 85 | − vaddr = i915_gem_object_pin_map(vma->obj, I915_MAP_WB); | |
| 85 | + vaddr = i915_gem_object_pin_map_unlocked(vma->obj, I915_MAP_WB); | |
| 86 | 86 | if (IS_ERR(vaddr)) { |
| 87 | 87 | i915_vma_unpin_and_release(&vma, 0); |
| 88 | 88 | return PTR_ERR(vaddr); |
| @@ -539,7 +539,7 @@ int intel_uc_fw_init(struct intel_uc_fw *uc_fw) · 538 unmodified lines | ||
| 539 | 539 | if (!intel_uc_fw_is_available(uc_fw)) |
| 540 | 540 | return -ENOEXEC; |
| 541 | 541 | |
| 542 | − err = i915_gem_object_pin_pages(uc_fw->obj); | |
| 542 | + err = i915_gem_object_pin_pages_unlocked(uc_fw->obj); | |
| 543 | 543 | if (err) { |
| 544 | 544 | DRM_DEBUG_DRIVER("%s fw pin-pages err=%d\n", |
| 545 | 545 | intel_uc_fw_type_repr(uc_fw->type), err); |
| @@ -218,7 +218,7 @@ static struct drm_i915_gem_object *vgpu_create_gem(struct drm_device *dev, · 217 unmodified lines | ||
| 218 | 218 | |
| 219 | 219 | drm_gem_private_object_init(dev, &obj->base, |
| 220 | 220 | roundup(info->size, PAGE_SIZE)); |
| 221 | − i915_gem_object_init(obj, &intel_vgpu_gem_ops, &lock_class); | |
| 221 | + i915_gem_object_init(obj, &intel_vgpu_gem_ops, &lock_class, 0); | |
| 222 | 222 | i915_gem_object_set_readonly(obj); |
| 223 | 223 | |
| 224 | 224 | obj->read_domains = I915_GEM_DOMAIN_GTT; |
| @@ -293,18 +293,13 @@ static struct active_node *__active_lookup(struct i915_active *ref, u64 idx) · 292 unmodified lines | ||
| 293 | 293 | static struct i915_active_fence * |
| 294 | 294 | active_instance(struct i915_active *ref, u64 idx) |
| 295 | 295 | { |
| 296 | − struct active_node *node, *prealloc; | |
| 296 | + struct active_node *node; | |
| 297 | 297 | struct rb_node **p, *parent; |
| 298 | 298 | |
| 299 | 299 | node = __active_lookup(ref, idx); |
| 300 | 300 | if (likely(node)) |
| 301 | 301 | return &node->base; |
| 302 | 302 | |
| 303 | − /* Preallocate a replacement, just in case */ | |
| 304 | − prealloc = kmem_cache_alloc(global.slab_cache, GFP_KERNEL); | |
| 305 | − if (!prealloc) | |
| 306 | − return NULL; | |
| 307 | − | |
| 308 | 303 | spin_lock_irq(&ref->tree_lock); |
| 309 | 304 | GEM_BUG_ON(i915_active_is_idle(ref)); |
| 310 | 305 | |
| @@ -314,10 +309,8 @@ active_instance(struct i915_active *ref, u64 idx) · 3 unmodified lines | ||
| 314 | 309 | parent = *p; |
| 315 | 310 | |
| 316 | 311 | node = rb_entry(parent, struct active_node, node); |
| 317 | − if (node->timeline == idx) { | |
| 318 | − kmem_cache_free(global.slab_cache, prealloc); | |
| 312 | + if (node->timeline == idx) | |
| 319 | 313 | goto out; |
| 320 | − } | |
| 321 | 314 | |
| 322 | 315 | if (node->timeline < idx) |
| 323 | 316 | p = &parent->rb_right; |
| @@ -325,7 +318,14 @@ active_instance(struct i915_active *ref, u64 idx) · 1 unmodified line | ||
| 325 | 318 | p = &parent->rb_left; |
| 326 | 319 | } |
| 327 | 320 | |
| 328 | − node = prealloc; | |
| 321 | + /* | |
| 322 | + * XXX: We should preallocate this before i915_active_ref() is ever | |
| 323 | + * called, but we cannot call into fs_reclaim() anyway, so use GFP_ATOMIC. | |
| 324 | + */ | |
| 325 | + node = kmem_cache_alloc(global.slab_cache, GFP_ATOMIC); | |
| 326 | + if (!node) | |
| 327 | + goto out; | |
| 328 | + | |
| 329 | 329 | __i915_active_fence_init(&node->base, NULL, node_retire); |
| 330 | 330 | node->ref = ref; |
| 331 | 331 | node->timeline = idx; |
| @@ -1144,38 +1144,20 @@ find_reg(const struct intel_engine_cs *engine, u32 addr) · 1143 unmodified lines | ||
| 1144 | 1144 | /* Returns a vmap'd pointer to dst_obj, which the caller must unmap */ |
| 1145 | 1145 | static u32 *copy_batch(struct drm_i915_gem_object *dst_obj, |
| 1146 | 1146 | struct drm_i915_gem_object *src_obj, |
| 1147 | − unsigned long offset, unsigned long length) | |
| 1147 | + unsigned long offset, unsigned long length, | |
| 1148 | + void *dst, const void *src) | |
| 1148 | 1149 | { |
| 1149 | − bool needs_clflush; | |
| 1150 | − void *dst, *src; | |
| 1151 | − int ret; | |
| 1152 | − | |
| 1153 | − dst = i915_gem_object_pin_map(dst_obj, I915_MAP_WB); | |
| 1154 | − if (IS_ERR(dst)) | |
| 1155 | − return dst; | |
| 1156 | − | |
| 1157 | − ret = i915_gem_object_pin_pages(src_obj); | |
| 1158 | − if (ret) { | |
| 1159 | − i915_gem_object_unpin_map(dst_obj); | |
| 1160 | − return ERR_PTR(ret); | |
| 1161 | − } | |
| 1162 | − | |
| 1163 | − needs_clflush = | |
| 1150 | + bool needs_clflush = | |
| 1164 | 1151 | !(src_obj->cache_coherent & I915_BO_CACHE_COHERENT_FOR_READ); |
| 1165 | 1152 | |
| 1166 | − src = ERR_PTR(-ENODEV); | |
| 1167 | − if (needs_clflush && i915_has_memcpy_from_wc()) { | |
| 1168 | − src = i915_gem_object_pin_map(src_obj, I915_MAP_WC); | |
| 1169 | − if (!IS_ERR(src)) { | |
| 1170 | − i915_unaligned_memcpy_from_wc(dst, | |
| 1171 | − src + offset, | |
| 1172 | − length); | |
| 1173 | − i915_gem_object_unpin_map(src_obj); | |
| 1174 | − } | |
| 1175 | − } | |
| 1176 | − if (IS_ERR(src)) { | |
| 1177 | − unsigned long x, n, remain; | |
| 1153 | + if (src) { | |
| 1154 | + GEM_BUG_ON(!needs_clflush); | |
| 1155 | + i915_unaligned_memcpy_from_wc(dst, src + offset, length); | |
| 1156 | + } else { | |
| 1157 | + struct scatterlist *sg; | |
| 1178 | 1158 | void *ptr; |
| 1159 | + unsigned int x, sg_ofs; | |
| 1160 | + unsigned long remain; | |
| 1179 | 1161 | |
| 1180 | 1162 | /* |
| 1181 | 1163 | * We can avoid clflushing partial cachelines before the write |
| @@ -1192,23 +1174,31 @@ static u32 *copy_batch(struct drm_i915_gem_object *dst_obj, · 10 unmodified lines | ||
| 1192 | 1174 | |
| 1193 | 1175 | ptr = dst; |
| 1194 | 1176 | x = offset_in_page(offset); |
| 1195 | − for (n = offset >> PAGE_SHIFT; remain; n++) { | |
| 1196 | − int len = min(remain, PAGE_SIZE - x); | |
| 1197 | − | |
| 1198 | − src = kmap_atomic(i915_gem_object_get_page(src_obj, n)); | |
| 1199 | − if (needs_clflush) | |
| 1200 | − drm_clflush_virt_range(src + x, len); | |
| 1201 | − memcpy(ptr, src + x, len); | |
| 1202 | − kunmap_atomic(src); | |
| 1203 | − | |
| 1204 | − ptr += len; | |
| 1205 | − remain -= len; | |
| 1206 | − x = 0; | |
| 1177 | + sg = i915_gem_object_get_sg(src_obj, offset >> PAGE_SHIFT, &sg_ofs, false); | |
| 1178 | + | |
| 1179 | + while (remain) { | |
| 1180 | + unsigned long sg_max = sg->length >> PAGE_SHIFT; | |
| 1181 | + | |
| 1182 | + for (; remain && sg_ofs < sg_max; sg_ofs++) { | |
| 1183 | + unsigned long len = min(remain, PAGE_SIZE - x); | |
| 1184 | + void *map; | |
| 1185 | + | |
| 1186 | + map = kmap_atomic(nth_page(sg_page(sg), sg_ofs)); | |
| 1187 | + if (needs_clflush) | |
| 1188 | + drm_clflush_virt_range(map + x, len); | |
| 1189 | + memcpy(ptr, map + x, len); | |
| 1190 | + kunmap_atomic(map); | |
| 1191 | + | |
| 1192 | + ptr += len; | |
| 1193 | + remain -= len; | |
| 1194 | + x = 0; | |
| 1195 | + } | |
| 1196 | + | |
| 1197 | + sg_ofs = 0; | |
| 1198 | + sg = sg_next(sg); | |
| 1207 | 1199 | } |
| 1208 | 1200 | } |
| 1209 | 1201 | |
| 1210 | − i915_gem_object_unpin_pages(src_obj); | |
| 1211 | − | |
| 1212 | 1202 | memset32(dst + length, 0, (dst_obj->base.size - length) / sizeof(u32)); |
| 1213 | 1203 | |
| 1214 | 1204 | /* dst_obj is returned with vmap pinned */ |
| @@ -1370,9 +1360,6 @@ static int check_bbstart(u32 *cmd, u32 offset, u32 length, · 155 unmodified lines | ||
| 1370 | 1360 | if (target_cmd_index == offset) |
| 1371 | 1361 | return 0; |
| 1372 | 1362 | |
| 1373 | − if (IS_ERR(jump_whitelist)) | |
| 1374 | − return PTR_ERR(jump_whitelist); | |
| 1375 | − | |
| 1376 | 1363 | if (!test_bit(target_cmd_index, jump_whitelist)) { |
| 1377 | 1364 | DRM_DEBUG("CMD: BB_START to 0x%llx not a previously executed cmd\n", |
| 1378 | 1365 | jump_target); |
| @@ -1382,10 +1369,14 @@ static int check_bbstart(u32 *cmd, u32 offset, u32 length, · 3 unmodified lines | ||
| 1382 | 1369 | return 0; |
| 1383 | 1370 | } |
| 1384 | 1371 | |
| 1385 | −static unsigned long *alloc_whitelist(u32 batch_length) | |
| 1372 | +unsigned long *intel_engine_cmd_parser_alloc_jump_whitelist(u32 batch_length, | |
| 1373 | + bool trampoline) | |
| 1386 | 1374 | { |
| 1387 | 1375 | unsigned long *jmp; |
| 1388 | 1376 | |
| 1377 | + if (trampoline) | |
| 1378 | + return NULL; | |
| 1379 | + | |
| 1389 | 1380 | /* |
| 1390 | 1381 | * We expect batch_length to be less than 256KiB for known users, |
| 1391 | 1382 | * i.e. we need at most an 8KiB bitmap allocation which should be |
| @@ -1423,14 +1414,16 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, · 31 unmodified lines | ||
| 1423 | 1414 | unsigned long batch_offset, |
| 1424 | 1415 | unsigned long batch_length, |
| 1425 | 1416 | struct i915_vma *shadow, |
| 1426 | − bool trampoline) | |
| 1417 | + unsigned long *jump_whitelist, | |
| 1418 | + void *shadow_map, | |
| 1419 | + const void *batch_map) | |
| 1427 | 1420 | { |
| 1428 | 1421 | u32 *cmd, *batch_end, offset = 0; |
| 1429 | 1422 | struct drm_i915_cmd_descriptor default_desc = noop_desc; |
| 1430 | 1423 | const struct drm_i915_cmd_descriptor *desc = &default_desc; |
| 1431 | − unsigned long *jump_whitelist; | |
| 1432 | 1424 | u64 batch_addr, shadow_addr; |
| 1433 | 1425 | int ret = 0; |
| 1426 | + bool trampoline = !jump_whitelist; | |
| 1434 | 1427 | |
| 1435 | 1428 | GEM_BUG_ON(!IS_ALIGNED(batch_offset, sizeof(*cmd))); |
| 1436 | 1429 | GEM_BUG_ON(!IS_ALIGNED(batch_length, sizeof(*cmd))); |
| @@ -1438,16 +1431,8 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, · 1 unmodified line | ||
| 1438 | 1431 | batch->size)); |
| 1439 | 1432 | GEM_BUG_ON(!batch_length); |
| 1440 | 1433 | |
| 1441 | − cmd = copy_batch(shadow->obj, batch->obj, batch_offset, batch_length); | |
| 1442 | − if (IS_ERR(cmd)) { | |
| 1443 | − DRM_DEBUG("CMD: Failed to copy batch\n"); | |
| 1444 | − return PTR_ERR(cmd); | |
| 1445 | − } | |
| 1446 | − | |
| 1447 | − jump_whitelist = NULL; | |
| 1448 | − if (!trampoline) | |
| 1449 | − /* Defer failure until attempted use */ | |
| 1450 | − jump_whitelist = alloc_whitelist(batch_length); | |
| 1434 | + cmd = copy_batch(shadow->obj, batch->obj, batch_offset, batch_length, | |
| 1435 | + shadow_map, batch_map); | |
| 1451 | 1436 | |
| 1452 | 1437 | shadow_addr = gen8_canonical_addr(shadow->node.start); |
| 1453 | 1438 | batch_addr = gen8_canonical_addr(batch->node.start + batch_offset); |
| @@ -1548,9 +1533,6 @@ int intel_engine_cmd_parser(struct intel_engine_cs *engine, · 94 unmodified lines | ||
| 1548 | 1533 | |
| 1549 | 1534 | i915_gem_object_flush_map(shadow->obj); |
| 1550 | 1535 | |
| 1551 | − if (!IS_ERR_OR_NULL(jump_whitelist)) | |
| 1552 | − kfree(jump_whitelist); | |
| 1553 | − i915_gem_object_unpin_map(shadow->obj); | |
| 1554 | 1536 | return ret; |
| 1555 | 1537 | } |
| 1556 | 1538 | |
| @@ -904,10 +904,10 @@ i915_drop_caches_set(void *data, u64 val) · 903 unmodified lines | ||
| 904 | 904 | |
| 905 | 905 | fs_reclaim_acquire(GFP_KERNEL); |
| 906 | 906 | if (val & DROP_BOUND) |
| 907 | − i915_gem_shrink(i915, LONG_MAX, NULL, I915_SHRINK_BOUND); | |
| 907 | + i915_gem_shrink(NULL, i915, LONG_MAX, NULL, I915_SHRINK_BOUND); | |
| 908 | 908 | |
| 909 | 909 | if (val & DROP_UNBOUND) |
| 910 | − i915_gem_shrink(i915, LONG_MAX, NULL, I915_SHRINK_UNBOUND); | |
| 910 | + i915_gem_shrink(NULL, i915, LONG_MAX, NULL, I915_SHRINK_UNBOUND); | |
| 911 | 911 | |
| 912 | 912 | if (val & DROP_SHRINK_ALL) |
| 913 | 913 | i915_gem_shrink_all(i915); |
| @@ -1691,7 +1691,7 @@ static const struct drm_ioctl_desc i915_ioctls[] = { · 1690 unmodified lines | ||
| 1691 | 1691 | DRM_IOCTL_DEF_DRV(I915_VBLANK_SWAP, drm_noop, DRM_AUTH), |
| 1692 | 1692 | DRM_IOCTL_DEF_DRV(I915_HWS_ADDR, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 1693 | 1693 | DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), |
| 1694 | − DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer_ioctl, DRM_AUTH), | |
| 1694 | + DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, drm_invalid_op, DRM_AUTH), | |
| 1695 | 1695 | DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2_WR, i915_gem_execbuffer2_ioctl, DRM_RENDER_ALLOW), |
| 1696 | 1696 | DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), |
| 1697 | 1697 | DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY), |
| @@ -554,12 +554,13 @@ struct i915_gem_mm { · 553 unmodified lines | ||
| 554 | 554 | struct notifier_block vmap_notifier; |
| 555 | 555 | struct shrinker shrinker; |
| 556 | 556 | |
| 557 | +#ifdef CONFIG_MMU_NOTIFIER | |
| 557 | 558 | /** |
| 558 | − * Workqueue to fault in userptr pages, flushed by the execbuf | |
| 559 | − * when required but otherwise left to userspace to try again | |
| 560 | − * on EAGAIN. | |
| 559 | + * notifier_lock for mmu notifiers, memory may not be allocated | |
| 560 | + * while holding this lock. | |
| 561 | 561 | */ |
| 562 | − struct workqueue_struct *userptr_wq; | |
| 562 | + spinlock_t notifier_lock; | |
| 563 | +#endif | |
| 563 | 564 | |
| 564 | 565 | /* shrinker accounting, also useful for userland debugging */ |
| 565 | 566 | u64 shrink_memory; |
| @@ -938,8 +939,6 @@ struct drm_i915_private { · 372 unmodified lines | ||
| 938 | 939 | struct i915_ggtt ggtt; /* VM representing the global address space */ |
| 939 | 940 | |
| 940 | 941 | struct i915_gem_mm mm; |
| 941 | − DECLARE_HASHTABLE(mm_structs, 7); | |
| 942 | − spinlock_t mm_lock; | |
| 943 | 942 | |
| 944 | 943 | /* Kernel Modesetting */ |
| 945 | 944 | |
| @@ -1946,12 +1945,17 @@ const char *i915_cache_level_str(struct drm_i915_private *i915, int type); · 1000 unmodified lines | ||
| 1946 | 1945 | int i915_cmd_parser_get_version(struct drm_i915_private *dev_priv); |
| 1947 | 1946 | int intel_engine_init_cmd_parser(struct intel_engine_cs *engine); |
| 1948 | 1947 | void intel_engine_cleanup_cmd_parser(struct intel_engine_cs *engine); |
| 1948 | +unsigned long *intel_engine_cmd_parser_alloc_jump_whitelist(u32 batch_length, | |
| 1949 | + bool trampoline); | |
| 1950 | + | |
| 1949 | 1951 | int intel_engine_cmd_parser(struct intel_engine_cs *engine, |
| 1950 | 1952 | struct i915_vma *batch, |
| 1951 | 1953 | unsigned long batch_offset, |
| 1952 | 1954 | unsigned long batch_length, |
| 1953 | 1955 | struct i915_vma *shadow, |
| 1954 | − bool trampoline); | |
| 1956 | + unsigned long *jump_whitelist, | |
| 1957 | + void *shadow_map, | |
| 1958 | + const void *batch_map); | |
| 1955 | 1959 | #define I915_CMD_PARSER_TRAMPOLINE_SIZE 8 |
| 1956 | 1960 | |
| 1957 | 1961 | /* intel_device_info.c */ |
| @@ -204,7 +204,6 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj, · 203 unmodified lines | ||
| 204 | 204 | { |
| 205 | 205 | unsigned int needs_clflush; |
| 206 | 206 | unsigned int idx, offset; |
| 207 | − struct dma_fence *fence; | |
| 208 | 207 | char __user *user_data; |
| 209 | 208 | u64 remain; |
| 210 | 209 | int ret; |
| @@ -213,19 +212,17 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj, · 2 unmodified lines | ||
| 213 | 212 | if (ret) |
| 214 | 213 | return ret; |
| 215 | 214 | |
| 215 | + ret = i915_gem_object_pin_pages(obj); | |
| 216 | + if (ret) | |
| 217 | + goto err_unlock; | |
| 218 | + | |
| 216 | 219 | ret = i915_gem_object_prepare_read(obj, &needs_clflush); |
| 217 | − if (ret) { | |
| 218 | − i915_gem_object_unlock(obj); | |
| 219 | − return ret; | |
| 220 | − } | |
| 220 | + if (ret) | |
| 221 | + goto err_unpin; | |
| 221 | 222 | |
| 222 | − fence = i915_gem_object_lock_fence(obj); | |
| 223 | 223 | i915_gem_object_finish_access(obj); |
| 224 | 224 | i915_gem_object_unlock(obj); |
| 225 | 225 | |
| 226 | − if (!fence) | |
| 227 | − return -ENOMEM; | |
| 228 | − | |
| 229 | 226 | remain = args->size; |
| 230 | 227 | user_data = u64_to_user_ptr(args->data_ptr); |
| 231 | 228 | offset = offset_in_page(args->offset); |
| @@ -243,7 +240,13 @@ i915_gem_shmem_pread(struct drm_i915_gem_object *obj, · 11 unmodified lines | ||
| 243 | 240 | offset = 0; |
| 244 | 241 | } |
| 245 | 242 | |
| 246 | − i915_gem_object_unlock_fence(obj, fence); | |
| 243 | + i915_gem_object_unpin_pages(obj); | |
| 244 | + return ret; | |
| 245 | + | |
| 246 | +err_unpin: | |
| 247 | + i915_gem_object_unpin_pages(obj); | |
| 248 | +err_unlock: | |
| 249 | + i915_gem_object_unlock(obj); | |
| 247 | 250 | return ret; |
| 248 | 251 | } |
| 249 | 252 | |
| @@ -271,52 +274,102 @@ gtt_user_read(struct io_mapping *mapping, · 21 unmodified lines | ||
| 271 | 274 | return unwritten; |
| 272 | 275 | } |
| 273 | 276 | |
| 274 | −static int | |
| 275 | −i915_gem_gtt_pread(struct drm_i915_gem_object *obj, | |
| 276 | − const struct drm_i915_gem_pread *args) | |
| 277 | +static struct i915_vma *i915_gem_gtt_prepare(struct drm_i915_gem_object *obj, | |
| 278 | + struct drm_mm_node *node, | |
| 279 | + bool write) | |
| 277 | 280 | { |
| 278 | 281 | struct drm_i915_private *i915 = to_i915(obj->base.dev); |
| 279 | 282 | struct i915_ggtt *ggtt = &i915->ggtt; |
| 280 | − intel_wakeref_t wakeref; | |
| 281 | − struct drm_mm_node node; | |
| 282 | − struct dma_fence *fence; | |
| 283 | − void __user *user_data; | |
| 284 | 283 | struct i915_vma *vma; |
| 285 | − u64 remain, offset; | |
| 284 | + struct i915_gem_ww_ctx ww; | |
| 286 | 285 | int ret; |
| 287 | 286 | |
| 288 | − wakeref = intel_runtime_pm_get(&i915->runtime_pm); | |
| 287 | + i915_gem_ww_ctx_init(&ww, true); | |
| 288 | +retry: | |
| 289 | 289 | vma = ERR_PTR(-ENODEV); |
| 290 | + ret = i915_gem_object_lock(obj, &ww); | |
| 291 | + if (ret) | |
| 292 | + goto err_ww; | |
| 293 | + | |
| 294 | + ret = i915_gem_object_set_to_gtt_domain(obj, write); | |
| 295 | + if (ret) | |
| 296 | + goto err_ww; | |
| 297 | + | |
| 290 | 298 | if (!i915_gem_object_is_tiled(obj)) |
| 291 | − vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, | |
| 292 | − PIN_MAPPABLE | | |
| 293 | − PIN_NONBLOCK /* NOWARN */ | | |
| 294 | − PIN_NOEVICT); | |
| 295 | − if (!IS_ERR(vma)) { | |
| 296 | − node.start = i915_ggtt_offset(vma); | |
| 297 | − node.flags = 0; | |
| 299 | + vma = i915_gem_object_ggtt_pin_ww(obj, &ww, NULL, 0, 0, | |
| 300 | + PIN_MAPPABLE | | |
| 301 | + PIN_NONBLOCK /* NOWARN */ | | |
| 302 | + PIN_NOEVICT); | |
| 303 | + if (vma == ERR_PTR(-EDEADLK)) { | |
| 304 | + ret = -EDEADLK; | |
| 305 | + goto err_ww; | |
| 306 | + } else if (!IS_ERR(vma)) { | |
| 307 | + node->start = i915_ggtt_offset(vma); | |
| 308 | + node->flags = 0; | |
| 298 | 309 | } else { |
| 299 | − ret = insert_mappable_node(ggtt, &node, PAGE_SIZE); | |
| 310 | + ret = insert_mappable_node(ggtt, node, PAGE_SIZE); | |
| 300 | 311 | if (ret) |
| 301 | − goto out_rpm; | |
| 302 | − GEM_BUG_ON(!drm_mm_node_allocated(&node)); | |
| 312 | + goto err_ww; | |
| 313 | + GEM_BUG_ON(!drm_mm_node_allocated(node)); | |
| 314 | + vma = NULL; | |
| 303 | 315 | } |
| 304 | 316 | |
| 305 | − ret = i915_gem_object_lock_interruptible(obj, NULL); | |
| 306 | − if (ret) | |
| 307 | − goto out_unpin; | |
| 308 | − | |
| 309 | − ret = i915_gem_object_set_to_gtt_domain(obj, false); | |
| 317 | + ret = i915_gem_object_pin_pages(obj); | |
| 310 | 318 | if (ret) { |
| 311 | − i915_gem_object_unlock(obj); | |
| 312 | − goto out_unpin; | |
| 319 | + if (drm_mm_node_allocated(node)) { | |
| 320 | + ggtt->vm.clear_range(&ggtt->vm, node->start, node->size); | |
| 321 | + remove_mappable_node(ggtt, node); | |
| 322 | + } else { | |
| 323 | + i915_vma_unpin(vma); | |
| 324 | + } | |
| 313 | 325 | } |
| 314 | 326 | |
| 315 | − fence = i915_gem_object_lock_fence(obj); | |
| 316 | − i915_gem_object_unlock(obj); | |
| 317 | − if (!fence) { | |
| 318 | − ret = -ENOMEM; | |
| 319 | − goto out_unpin; | |
| 327 | +err_ww: | |
| 328 | + if (ret == -EDEADLK) { | |
| 329 | + ret = i915_gem_ww_ctx_backoff(&ww); | |
| 330 | + if (!ret) | |
| 331 | + goto retry; | |
| 332 | + } | |
| 333 | + i915_gem_ww_ctx_fini(&ww); | |
| 334 | + | |
| 335 | + return ret ? ERR_PTR(ret) : vma; | |
| 336 | +} | |
| 337 | + | |
| 338 | +static void i915_gem_gtt_cleanup(struct drm_i915_gem_object *obj, | |
| 339 | + struct drm_mm_node *node, | |
| 340 | + struct i915_vma *vma) | |
| 341 | +{ | |
| 342 | + struct drm_i915_private *i915 = to_i915(obj->base.dev); | |
| 343 | + struct i915_ggtt *ggtt = &i915->ggtt; | |
| 344 | + | |
| 345 | + i915_gem_object_unpin_pages(obj); | |
| 346 | + if (drm_mm_node_allocated(node)) { | |
| 347 | + ggtt->vm.clear_range(&ggtt->vm, node->start, node->size); | |
| 348 | + remove_mappable_node(ggtt, node); | |
| 349 | + } else { | |
| 350 | + i915_vma_unpin(vma); | |
| 351 | + } | |
| 352 | +} | |
| 353 | + | |
| 354 | +static int | |
| 355 | +i915_gem_gtt_pread(struct drm_i915_gem_object *obj, | |
| 356 | + const struct drm_i915_gem_pread *args) | |
| 357 | +{ | |
| 358 | + struct drm_i915_private *i915 = to_i915(obj->base.dev); | |
| 359 | + struct i915_ggtt *ggtt = &i915->ggtt; | |
| 360 | + intel_wakeref_t wakeref; | |
| 361 | + struct drm_mm_node node; | |
| 362 | + void __user *user_data; | |
| 363 | + struct i915_vma *vma; | |
| 364 | + u64 remain, offset; | |
| 365 | + int ret = 0; | |
| 366 | + | |
| 367 | + wakeref = intel_runtime_pm_get(&i915->runtime_pm); | |
| 368 | + | |
| 369 | + vma = i915_gem_gtt_prepare(obj, &node, false); | |
| 370 | + if (IS_ERR(vma)) { | |
| 371 | + ret = PTR_ERR(vma); | |
| 372 | + goto out_rpm; | |
| 320 | 373 | } |
| 321 | 374 | |
| 322 | 375 | user_data = u64_to_user_ptr(args->data_ptr); |
| @@ -353,14 +406,7 @@ i915_gem_gtt_pread(struct drm_i915_gem_object *obj, · 30 unmodified lines | ||
| 353 | 406 | offset += page_length; |
| 354 | 407 | } |
| 355 | 408 | |
| 356 | − i915_gem_object_unlock_fence(obj, fence); | |
| 357 | −out_unpin: | |
| 358 | − if (drm_mm_node_allocated(&node)) { | |
| 359 | − ggtt->vm.clear_range(&ggtt->vm, node.start, node.size); | |
| 360 | − remove_mappable_node(ggtt, &node); | |
| 361 | − } else { | |
| 362 | − i915_vma_unpin(vma); | |
| 363 | − } | |
| 409 | + i915_gem_gtt_cleanup(obj, &node, vma); | |
| 364 | 410 | out_rpm: |
| 365 | 411 | intel_runtime_pm_put(&i915->runtime_pm, wakeref); |
| 366 | 412 | return ret; |
| @@ -378,10 +424,17 @@ int · 11 unmodified lines | ||
| 378 | 424 | i915_gem_pread_ioctl(struct drm_device *dev, void *data, |
| 379 | 425 | struct drm_file *file) |
| 380 | 426 | { |
| 427 | + struct drm_i915_private *i915 = to_i915(dev); | |
| 381 | 428 | struct drm_i915_gem_pread *args = data; |
| 382 | 429 | struct drm_i915_gem_object *obj; |
| 383 | 430 | int ret; |
| 384 | 431 | |
| 432 | + /* PREAD is disallowed for all platforms after TGL-LP. This also | |
| 433 | + * covers all platforms with local memory. | |
| 434 | + */ | |
| 435 | + if (INTEL_GEN(i915) >= 12 && !IS_TIGERLAKE(i915)) | |
| 436 | + return -EOPNOTSUPP; | |
| 437 | + | |
| 385 | 438 | if (args->size == 0) |
| 386 | 439 | return 0; |
| 387 | 440 | |
| @@ -400,6 +453,11 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, · 12 unmodified lines | ||
| 400 | 453 | } |
| 401 | 454 | |
| 402 | 455 | trace_i915_gem_object_pread(obj, args->offset, args->size); |
| 456 | + ret = -ENODEV; | |
| 457 | + if (obj->ops->pread) | |
| 458 | + ret = obj->ops->pread(obj, args); | |
| 459 | + if (ret != -ENODEV) | |
| 460 | + goto out; | |
| 403 | 461 | |
| 404 | 462 | ret = -ENODEV; |
| 405 | 463 | if (obj->ops->pread) |
| @@ -413,15 +471,10 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, · 7 unmodified lines | ||
| 413 | 471 | if (ret) |
| 414 | 472 | goto out; |
| 415 | 473 | |
| 416 | − ret = i915_gem_object_pin_pages(obj); | |
| 417 | − if (ret) | |
| 418 | − goto out; | |
| 419 | − | |
| 420 | 474 | ret = i915_gem_shmem_pread(obj, args); |
| 421 | 475 | if (ret == -EFAULT || ret == -ENODEV) |
| 422 | 476 | ret = i915_gem_gtt_pread(obj, args); |
| 423 | 477 | |
| 424 | − i915_gem_object_unpin_pages(obj); | |
| 425 | 478 | out: |
| 426 | 479 | i915_gem_object_put(obj); |
| 427 | 480 | return ret; |
| @@ -469,11 +522,10 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, · 41 unmodified lines | ||
| 469 | 522 | struct intel_runtime_pm *rpm = &i915->runtime_pm; |
| 470 | 523 | intel_wakeref_t wakeref; |
| 471 | 524 | struct drm_mm_node node; |
| 472 | − struct dma_fence *fence; | |
| 473 | 525 | struct i915_vma *vma; |
| 474 | 526 | u64 remain, offset; |
| 475 | 527 | void __user *user_data; |
| 476 | − int ret; | |
| 528 | + int ret = 0; | |
| 477 | 529 | |
| 478 | 530 | if (i915_gem_object_has_struct_page(obj)) { |
| 479 | 531 | /* |
| @@ -491,37 +543,10 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, · 11 unmodified lines | ||
| 491 | 543 | wakeref = intel_runtime_pm_get(rpm); |
| 492 | 544 | } |
| 493 | 545 | |
| 494 | − vma = ERR_PTR(-ENODEV); | |
| 495 | − if (!i915_gem_object_is_tiled(obj)) | |
| 496 | − vma = i915_gem_object_ggtt_pin(obj, NULL, 0, 0, | |
| 497 | − PIN_MAPPABLE | | |
| 498 | − PIN_NONBLOCK /* NOWARN */ | | |
| 499 | − PIN_NOEVICT); | |
| 500 | − if (!IS_ERR(vma)) { | |
| 501 | − node.start = i915_ggtt_offset(vma); | |
| 502 | − node.flags = 0; | |
| 503 | − } else { | |
| 504 | − ret = insert_mappable_node(ggtt, &node, PAGE_SIZE); | |
| 505 | − if (ret) | |
| 506 | − goto out_rpm; | |
| 507 | − GEM_BUG_ON(!drm_mm_node_allocated(&node)); | |
| 508 | − } | |
| 509 | − | |
| 510 | − ret = i915_gem_object_lock_interruptible(obj, NULL); | |
| 511 | − if (ret) | |
| 512 | − goto out_unpin; | |
| 513 | − | |
| 514 | − ret = i915_gem_object_set_to_gtt_domain(obj, true); | |
| 515 | − if (ret) { | |
| 516 | − i915_gem_object_unlock(obj); | |
| 517 | − goto out_unpin; | |
| 518 | − } | |
| 519 | − | |
| 520 | − fence = i915_gem_object_lock_fence(obj); | |
| 521 | − i915_gem_object_unlock(obj); | |
| 522 | − if (!fence) { | |
| 523 | − ret = -ENOMEM; | |
| 524 | − goto out_unpin; | |
| 546 | + vma = i915_gem_gtt_prepare(obj, &node, true); | |
| 547 | + if (IS_ERR(vma)) { | |
| 548 | + ret = PTR_ERR(vma); | |
| 549 | + goto out_rpm; | |
| 525 | 550 | } |
| 526 | 551 | |
| 527 | 552 | i915_gem_object_invalidate_frontbuffer(obj, ORIGIN_CPU); |
| @@ -570,14 +595,7 @@ i915_gem_gtt_pwrite_fast(struct drm_i915_gem_object *obj, · 42 unmodified lines | ||
| 570 | 595 | intel_gt_flush_ggtt_writes(ggtt->vm.gt); |
| 571 | 596 | i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU); |
| 572 | 597 | |
| 573 | − i915_gem_object_unlock_fence(obj, fence); | |
| 574 | −out_unpin: | |
| 575 | − if (drm_mm_node_allocated(&node)) { | |
| 576 | − ggtt->vm.clear_range(&ggtt->vm, node.start, node.size); | |
| 577 | − remove_mappable_node(ggtt, &node); | |
| 578 | − } else { | |
| 579 | − i915_vma_unpin(vma); | |
| 580 | − } | |
| 598 | + i915_gem_gtt_cleanup(obj, &node, vma); | |
| 581 | 599 | out_rpm: |
| 582 | 600 | intel_runtime_pm_put(rpm, wakeref); |
| 583 | 601 | return ret; |
| @@ -617,7 +635,6 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, · 33 unmodified lines | ||
| 617 | 635 | unsigned int partial_cacheline_write; |
| 618 | 636 | unsigned int needs_clflush; |
| 619 | 637 | unsigned int offset, idx; |
| 620 | − struct dma_fence *fence; | |
| 621 | 638 | void __user *user_data; |
| 622 | 639 | u64 remain; |
| 623 | 640 | int ret; |
| @@ -626,19 +643,17 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, · 2 unmodified lines | ||
| 626 | 643 | if (ret) |
| 627 | 644 | return ret; |
| 628 | 645 | |
| 646 | + ret = i915_gem_object_pin_pages(obj); | |
| 647 | + if (ret) | |
| 648 | + goto err_unlock; | |
| 649 | + | |
| 629 | 650 | ret = i915_gem_object_prepare_write(obj, &needs_clflush); |
| 630 | − if (ret) { | |
| 631 | − i915_gem_object_unlock(obj); | |
| 632 | − return ret; | |
| 633 | − } | |
| 651 | + if (ret) | |
| 652 | + goto err_unpin; | |
| 634 | 653 | |
| 635 | − fence = i915_gem_object_lock_fence(obj); | |
| 636 | 654 | i915_gem_object_finish_access(obj); |
| 637 | 655 | i915_gem_object_unlock(obj); |
| 638 | 656 | |
| 639 | − if (!fence) | |
| 640 | − return -ENOMEM; | |
| 641 | − | |
| 642 | 657 | /* If we don't overwrite a cacheline completely we need to be |
| 643 | 658 | * careful to have up-to-date data by first clflushing. Don't |
| 644 | 659 | * overcomplicate things and flush the entire patch. |
| @@ -666,8 +681,14 @@ i915_gem_shmem_pwrite(struct drm_i915_gem_object *obj, · 21 unmodified lines | ||
| 666 | 681 | } |
| 667 | 682 | |
| 668 | 683 | i915_gem_object_flush_frontbuffer(obj, ORIGIN_CPU); |
| 669 | − i915_gem_object_unlock_fence(obj, fence); | |
| 670 | 684 | |
| 685 | + i915_gem_object_unpin_pages(obj); | |
| 686 | + return ret; | |
| 687 | + | |
| 688 | +err_unpin: | |
| 689 | + i915_gem_object_unpin_pages(obj); | |
| 690 | +err_unlock: | |
| 691 | + i915_gem_object_unlock(obj); | |
| 671 | 692 | return ret; |
| 672 | 693 | } |
| 673 | 694 | |
| @@ -683,10 +704,17 @@ int · 9 unmodified lines | ||
| 683 | 704 | i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, |
| 684 | 705 | struct drm_file *file) |
| 685 | 706 | { |
| 707 | + struct drm_i915_private *i915 = to_i915(dev); | |
| 686 | 708 | struct drm_i915_gem_pwrite *args = data; |
| 687 | 709 | struct drm_i915_gem_object *obj; |
| 688 | 710 | int ret; |
| 689 | 711 | |
| 712 | + /* PWRITE is disallowed for all platforms after TGL-LP. This also | |
| 713 | + * covers all platforms with local memory. | |
| 714 | + */ | |
| 715 | + if (INTEL_GEN(i915) >= 12 && !IS_TIGERLAKE(i915)) | |
| 716 | + return -EOPNOTSUPP; | |
| 717 | + | |
| 690 | 718 | if (args->size == 0) |
| 691 | 719 | return 0; |
| 692 | 720 | |
| @@ -724,10 +752,6 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, · 31 unmodified lines | ||
| 724 | 752 | if (ret) |
| 725 | 753 | goto err; |
| 726 | 754 | |
| 727 | − ret = i915_gem_object_pin_pages(obj); | |
| 728 | − if (ret) | |
| 729 | − goto err; | |
| 730 | − | |
| 731 | 755 | ret = -EFAULT; |
| 732 | 756 | /* We can only do the GTT pwrite on untiled buffers, as otherwise |
| 733 | 757 | * it would end up going through the fenced access, and we'll get |
| @@ -748,7 +772,6 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, · 14 unmodified lines | ||
| 748 | 772 | ret = i915_gem_shmem_pwrite(obj, args); |
| 749 | 773 | } |
| 750 | 774 | |
| 751 | − i915_gem_object_unpin_pages(obj); | |
| 752 | 775 | err: |
| 753 | 776 | i915_gem_object_put(obj); |
| 754 | 777 | return ret; |
| @@ -909,7 +932,11 @@ new_vma: · 154 unmodified lines | ||
| 909 | 932 | return ERR_PTR(ret); |
| 910 | 933 | } |
| 911 | 934 | |
| 912 | − ret = i915_vma_pin_ww(vma, ww, size, alignment, flags | PIN_GLOBAL); | |
| 935 | + if (ww) | |
| 936 | + ret = i915_vma_pin_ww(vma, ww, size, alignment, flags | PIN_GLOBAL); | |
| 937 | + else | |
| 938 | + ret = i915_vma_pin(vma, size, alignment, flags | PIN_GLOBAL); | |
| 939 | + | |
| 913 | 940 | if (ret) |
| 914 | 941 | return ERR_PTR(ret); |
| 915 | 942 | |
| @@ -949,7 +976,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, · 33 unmodified lines | ||
| 949 | 976 | if (!obj) |
| 950 | 977 | return -ENOENT; |
| 951 | 978 | |
| 952 | − err = mutex_lock_interruptible(&obj->mm.lock); | |
| 979 | + err = i915_gem_object_lock_interruptible(obj, NULL); | |
| 953 | 980 | if (err) |
| 954 | 981 | goto out; |
| 955 | 982 | |
| @@ -995,8 +1022,8 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, · 39 unmodified lines | ||
| 995 | 1022 | i915_gem_object_truncate(obj); |
| 996 | 1023 | |
| 997 | 1024 | args->retained = obj->mm.madv != __I915_MADV_PURGED; |
| 998 | − mutex_unlock(&obj->mm.lock); | |
| 999 | 1025 | |
| 1026 | + i915_gem_object_unlock(obj); | |
| 1000 | 1027 | out: |
| 1001 | 1028 | i915_gem_object_put(obj); |
| 1002 | 1029 | return err; |
| @@ -1050,10 +1077,8 @@ int i915_gem_init(struct drm_i915_private *dev_priv) · 47 unmodified lines | ||
| 1050 | 1077 | err_unlock: |
| 1051 | 1078 | i915_gem_drain_workqueue(dev_priv); |
| 1052 | 1079 | |
| 1053 | − if (ret != -EIO) { | |
| 1080 | + if (ret != -EIO) | |
| 1054 | 1081 | intel_uc_cleanup_firmwares(&dev_priv->gt.uc); |
| 1055 | − i915_gem_cleanup_userptr(dev_priv); | |
| 1056 | − } | |
| 1057 | 1082 | |
| 1058 | 1083 | if (ret == -EIO) { |
| 1059 | 1084 | /* |
| @@ -1110,7 +1135,6 @@ void i915_gem_driver_release(struct drm_i915_private *dev_priv) · 50 unmodified lines | ||
| 1110 | 1135 | intel_wa_list_free(&dev_priv->gt_wa_list); |
| 1111 | 1136 | |
| 1112 | 1137 | intel_uc_cleanup_firmwares(&dev_priv->gt.uc); |
| 1113 | − i915_gem_cleanup_userptr(dev_priv); | |
| 1114 | 1138 | |
| 1115 | 1139 | i915_gem_drain_freed_objects(dev_priv); |
| 1116 | 1140 | |
| @@ -44,7 +44,7 @@ int i915_gem_gtt_prepare_pages(struct drm_i915_gem_object *obj, · 43 unmodified lines | ||
| 44 | 44 | * the DMA remapper, i915_gem_shrink will return 0. |
| 45 | 45 | */ |
| 46 | 46 | GEM_BUG_ON(obj->mm.pages == pages); |
| 47 | − } while (i915_gem_shrink(to_i915(obj->base.dev), | |
| 47 | + } while (i915_gem_shrink(NULL, to_i915(obj->base.dev), | |
| 48 | 48 | obj->base.size >> PAGE_SHIFT, NULL, |
| 49 | 49 | I915_SHRINK_BOUND | |
| 50 | 50 | I915_SHRINK_UNBOUND)); |
| @@ -135,7 +135,7 @@ bool i915_memcpy_from_wc(void *dst, const void *src, unsigned long len) · 134 unmodified lines | ||
| 135 | 135 | * accepts that its arguments may not be aligned, but are valid for the |
| 136 | 136 | * potential 16-byte read past the end. |
| 137 | 137 | */ |
| 138 | −void i915_unaligned_memcpy_from_wc(void *dst, void *src, unsigned long len) | |
| 138 | +void i915_unaligned_memcpy_from_wc(void *dst, const void *src, unsigned long len) | |
| 139 | 139 | { |
| 140 | 140 | unsigned long addr; |
| 141 | 141 | |
| @@ -13,7 +13,7 @@ struct drm_i915_private; · 12 unmodified lines | ||
| 13 | 13 | void i915_memcpy_init_early(struct drm_i915_private *i915); |
| 14 | 14 | |
| 15 | 15 | bool i915_memcpy_from_wc(void *dst, const void *src, unsigned long len); |
| 16 | −void i915_unaligned_memcpy_from_wc(void *dst, void *src, unsigned long len); | |
| 16 | +void i915_unaligned_memcpy_from_wc(void *dst, const void *src, unsigned long len); | |
| 17 | 17 | |
| 18 | 18 | /* The movntdqa instructions used for memcpy-from-wc require 16-byte alignment, |
| 19 | 19 | * as well as SSE4.1 support. i915_memcpy_from_wc() will report if it cannot |
| @@ -197,6 +197,11 @@ i915_param_named_unsafe(fake_lmem_start, ulong, 0400, · 196 unmodified lines | ||
| 197 | 197 | "Fake LMEM start offset (default: 0)"); |
| 198 | 198 | #endif |
| 199 | 199 | |
| 200 | +#if CONFIG_DRM_I915_REQUEST_TIMEOUT | |
| 201 | +i915_param_named_unsafe(request_timeout_ms, uint, 0600, | |
| 202 | + "Default request/fence/batch buffer expiration timeout."); | |
| 203 | +#endif | |
| 204 | + | |
| 200 | 205 | static __always_inline void _print_param(struct drm_printer *p, |
| 201 | 206 | const char *name, |
| 202 | 207 | const char *type, |
| @@ -72,6 +72,7 @@ struct drm_printer; · 71 unmodified lines | ||
| 72 | 72 | param(int, enable_dpcd_backlight, -1, 0600) \ |
| 73 | 73 | param(char *, force_probe, CONFIG_DRM_I915_FORCE_PROBE, 0400) \ |
| 74 | 74 | param(unsigned long, fake_lmem_start, 0, 0400) \ |
| 75 | + param(unsigned int, request_timeout_ms, CONFIG_DRM_I915_REQUEST_TIMEOUT, 0600) \ | |
| 75 | 76 | /* leave bools at the end to not create holes */ \ |
| 76 | 77 | param(bool, enable_hangcheck, true, 0600) \ |
| 77 | 78 | param(bool, load_detect_test, false, 0600) \ |
| @@ -1573,7 +1573,7 @@ static int alloc_oa_buffer(struct i915_perf_stream *stream) · 1572 unmodified lines | ||
| 1573 | 1573 | stream->oa_buffer.vma = vma; |
| 1574 | 1574 | |
| 1575 | 1575 | stream->oa_buffer.vaddr = |
| 1576 | − i915_gem_object_pin_map(bo, I915_MAP_WB); | |
| 1576 | + i915_gem_object_pin_map_unlocked(bo, I915_MAP_WB); | |
| 1577 | 1577 | if (IS_ERR(stream->oa_buffer.vaddr)) { |
| 1578 | 1578 | ret = PTR_ERR(stream->oa_buffer.vaddr); |
| 1579 | 1579 | goto err_unpin; |
| @@ -1627,6 +1627,7 @@ static int alloc_noa_wait(struct i915_perf_stream *stream) · 47 unmodified lines | ||
| 1627 | 1627 | const u32 base = stream->engine->mmio_base; |
| 1628 | 1628 | #define CS_GPR(x) GEN8_RING_CS_GPR(base, x) |
| 1629 | 1629 | u32 *batch, *ts0, *cs, *jump; |
| 1630 | + struct i915_gem_ww_ctx ww; | |
| 1630 | 1631 | int ret, i; |
| 1631 | 1632 | enum { |
| 1632 | 1633 | START_TS, |
| @@ -1644,15 +1645,21 @@ static int alloc_noa_wait(struct i915_perf_stream *stream) · 11 unmodified lines | ||
| 1644 | 1645 | return PTR_ERR(bo); |
| 1645 | 1646 | } |
| 1646 | 1647 | |
| 1648 | + i915_gem_ww_ctx_init(&ww, true); | |
| 1649 | +retry: | |
| 1650 | + ret = i915_gem_object_lock(bo, &ww); | |
| 1651 | + if (ret) | |
| 1652 | + goto out_ww; | |
| 1653 | + | |
| 1647 | 1654 | /* |
| 1648 | 1655 | * We pin in GGTT because we jump into this buffer now because |
| 1649 | 1656 | * multiple OA config BOs will have a jump to this address and it |
| 1650 | 1657 | * needs to be fixed during the lifetime of the i915/perf stream. |
| 1651 | 1658 | */ |
| 1652 | − vma = i915_gem_object_ggtt_pin(bo, NULL, 0, 0, PIN_HIGH); | |
| 1659 | + vma = i915_gem_object_ggtt_pin_ww(bo, &ww, NULL, 0, 0, PIN_HIGH); | |
| 1653 | 1660 | if (IS_ERR(vma)) { |
| 1654 | 1661 | ret = PTR_ERR(vma); |
| 1655 | − goto err_unref; | |
| 1662 | + goto out_ww; | |
| 1656 | 1663 | } |
| 1657 | 1664 | |
| 1658 | 1665 | batch = cs = i915_gem_object_pin_map(bo, I915_MAP_WB); |
| @@ -1786,12 +1793,19 @@ static int alloc_noa_wait(struct i915_perf_stream *stream) · 127 unmodified lines | ||
| 1786 | 1793 | __i915_gem_object_release_map(bo); |
| 1787 | 1794 | |
| 1788 | 1795 | stream->noa_wait = vma; |
| 1789 | − return 0; | |
| 1796 | + goto out_ww; | |
| 1790 | 1797 | |
| 1791 | 1798 | err_unpin: |
| 1792 | 1799 | i915_vma_unpin_and_release(&vma, 0); |
| 1793 | −err_unref: | |
| 1794 | − i915_gem_object_put(bo); | |
| 1800 | +out_ww: | |
| 1801 | + if (ret == -EDEADLK) { | |
| 1802 | + ret = i915_gem_ww_ctx_backoff(&ww); | |
| 1803 | + if (!ret) | |
| 1804 | + goto retry; | |
| 1805 | + } | |
| 1806 | + i915_gem_ww_ctx_fini(&ww); | |
| 1807 | + if (ret) | |
| 1808 | + i915_gem_object_put(bo); | |
| 1795 | 1809 | return ret; |
| 1796 | 1810 | } |
| 1797 | 1811 | |
| @@ -1834,6 +1848,7 @@ alloc_oa_config_buffer(struct i915_perf_stream *stream, · 36 unmodified lines | ||
| 1834 | 1848 | { |
| 1835 | 1849 | struct drm_i915_gem_object *obj; |
| 1836 | 1850 | struct i915_oa_config_bo *oa_bo; |
| 1851 | + struct i915_gem_ww_ctx ww; | |
| 1837 | 1852 | size_t config_length = 0; |
| 1838 | 1853 | u32 *cs; |
| 1839 | 1854 | int err; |
| @@ -1854,10 +1869,16 @@ alloc_oa_config_buffer(struct i915_perf_stream *stream, · 14 unmodified lines | ||
| 1854 | 1869 | goto err_free; |
| 1855 | 1870 | } |
| 1856 | 1871 | |
| 1872 | + i915_gem_ww_ctx_init(&ww, true); | |
| 1873 | +retry: | |
| 1874 | + err = i915_gem_object_lock(obj, &ww); | |
| 1875 | + if (err) | |
| 1876 | + goto out_ww; | |
| 1877 | + | |
| 1857 | 1878 | cs = i915_gem_object_pin_map(obj, I915_MAP_WB); |
| 1858 | 1879 | if (IS_ERR(cs)) { |
| 1859 | 1880 | err = PTR_ERR(cs); |
| 1860 | − goto err_oa_bo; | |
| 1881 | + goto out_ww; | |
| 1861 | 1882 | } |
| 1862 | 1883 | |
| 1863 | 1884 | cs = write_cs_mi_lri(cs, |
| @@ -1885,19 +1906,28 @@ alloc_oa_config_buffer(struct i915_perf_stream *stream, · 21 unmodified lines | ||
| 1885 | 1906 | NULL); |
| 1886 | 1907 | if (IS_ERR(oa_bo->vma)) { |
| 1887 | 1908 | err = PTR_ERR(oa_bo->vma); |
| 1888 | − goto err_oa_bo; | |
| 1909 | + goto out_ww; | |
| 1889 | 1910 | } |
| 1890 | 1911 | |
| 1891 | 1912 | oa_bo->oa_config = i915_oa_config_get(oa_config); |
| 1892 | 1913 | llist_add(&oa_bo->node, &stream->oa_config_bos); |
| 1893 | 1914 | |
| 1894 | − return oa_bo; | |
| 1915 | +out_ww: | |
| 1916 | + if (err == -EDEADLK) { | |
| 1917 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 1918 | + if (!err) | |
| 1919 | + goto retry; | |
| 1920 | + } | |
| 1921 | + i915_gem_ww_ctx_fini(&ww); | |
| 1895 | 1922 | |
| 1896 | −err_oa_bo: | |
| 1897 | − i915_gem_object_put(obj); | |
| 1923 | + if (err) | |
| 1924 | + i915_gem_object_put(obj); | |
| 1898 | 1925 | err_free: |
| 1899 | − kfree(oa_bo); | |
| 1900 | − return ERR_PTR(err); | |
| 1926 | + if (err) { | |
| 1927 | + kfree(oa_bo); | |
| 1928 | + return ERR_PTR(err); | |
| 1929 | + } | |
| 1930 | + return oa_bo; | |
| 1901 | 1931 | } |
| 1902 | 1932 | |
| 1903 | 1933 | static struct i915_vma * |
| @@ -33,7 +33,10 @@ · 32 unmodified lines | ||
| 33 | 33 | #include "gem/i915_gem_context.h" |
| 34 | 34 | #include "gt/intel_breadcrumbs.h" |
| 35 | 35 | #include "gt/intel_context.h" |
| 36 | +#include "gt/intel_engine.h" | |
| 37 | +#include "gt/intel_engine_heartbeat.h" | |
| 36 | 38 | #include "gt/intel_gpu_commands.h" |
| 39 | +#include "gt/intel_reset.h" | |
| 37 | 40 | #include "gt/intel_ring.h" |
| 38 | 41 | #include "gt/intel_rps.h" |
| 39 | 42 | |
| @@ -244,6 +247,50 @@ static void __i915_request_fill(struct i915_request *rq, u8 val) · 204 unmodified lines | ||
| 244 | 247 | memset(vaddr + head, val, rq->postfix - head); |
| 245 | 248 | } |
| 246 | 249 | |
| 250 | +/** | |
| 251 | + * i915_request_active_engine | |
| 252 | + * @rq: request to inspect | |
| 253 | + * @active: pointer in which to return the active engine | |
| 254 | + * | |
| 255 | + * Fills the currently active engine to the @active pointer if the request | |
| 256 | + * is active and still not completed. | |
| 257 | + * | |
| 258 | + * Returns true if request was active or false otherwise. | |
| 259 | + */ | |
| 260 | +bool | |
| 261 | +i915_request_active_engine(struct i915_request *rq, | |
| 262 | + struct intel_engine_cs **active) | |
| 263 | +{ | |
| 264 | + struct intel_engine_cs *engine, *locked; | |
| 265 | + bool ret = false; | |
| 266 | + | |
| 267 | + /* | |
| 268 | + * Serialise with __i915_request_submit() so that it sees | |
| 269 | + * is-banned?, or we know the request is already inflight. | |
| 270 | + * | |
| 271 | + * Note that rq->engine is unstable, and so we double | |
| 272 | + * check that we have acquired the lock on the final engine. | |
| 273 | + */ | |
| 274 | + locked = READ_ONCE(rq->engine); | |
| 275 | + spin_lock_irq(&locked->active.lock); | |
| 276 | + while (unlikely(locked != (engine = READ_ONCE(rq->engine)))) { | |
| 277 | + spin_unlock(&locked->active.lock); | |
| 278 | + locked = engine; | |
| 279 | + spin_lock(&locked->active.lock); | |
| 280 | + } | |
| 281 | + | |
| 282 | + if (i915_request_is_active(rq)) { | |
| 283 | + if (!__i915_request_is_complete(rq)) | |
| 284 | + *active = locked; | |
| 285 | + ret = true; | |
| 286 | + } | |
| 287 | + | |
| 288 | + spin_unlock_irq(&locked->active.lock); | |
| 289 | + | |
| 290 | + return ret; | |
| 291 | +} | |
| 292 | + | |
| 293 | + | |
| 247 | 294 | static void remove_from_engine(struct i915_request *rq) |
| 248 | 295 | { |
| 249 | 296 | struct intel_engine_cs *engine, *locked; |
| @@ -274,6 +321,53 @@ static void remove_from_engine(struct i915_request *rq) · 24 unmodified lines | ||
| 274 | 321 | __notify_execute_cb_imm(rq); |
| 275 | 322 | } |
| 276 | 323 | |
| 324 | +static void __rq_init_watchdog(struct i915_request *rq) | |
| 325 | +{ | |
| 326 | + rq->watchdog.timer.function = NULL; | |
| 327 | +} | |
| 328 | + | |
| 329 | +static enum hrtimer_restart __rq_watchdog_expired(struct hrtimer *hrtimer) | |
| 330 | +{ | |
| 331 | + struct i915_request *rq = | |
| 332 | + container_of(hrtimer, struct i915_request, watchdog.timer); | |
| 333 | + struct intel_gt *gt = rq->engine->gt; | |
| 334 | + | |
| 335 | + if (!i915_request_completed(rq)) { | |
| 336 | + if (llist_add(&rq->watchdog.link, >->watchdog.list)) | |
| 337 | + schedule_work(>->watchdog.work); | |
| 338 | + } else { | |
| 339 | + i915_request_put(rq); | |
| 340 | + } | |
| 341 | + | |
| 342 | + return HRTIMER_NORESTART; | |
| 343 | +} | |
| 344 | + | |
| 345 | +static void __rq_arm_watchdog(struct i915_request *rq) | |
| 346 | +{ | |
| 347 | + struct i915_request_watchdog *wdg = &rq->watchdog; | |
| 348 | + struct intel_context *ce = rq->context; | |
| 349 | + | |
| 350 | + if (!ce->watchdog.timeout_us) | |
| 351 | + return; | |
| 352 | + | |
| 353 | + hrtimer_init(&wdg->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | |
| 354 | + wdg->timer.function = __rq_watchdog_expired; | |
| 355 | + hrtimer_start_range_ns(&wdg->timer, | |
| 356 | + ns_to_ktime(ce->watchdog.timeout_us * | |
| 357 | + NSEC_PER_USEC), | |
| 358 | + NSEC_PER_MSEC, | |
| 359 | + HRTIMER_MODE_REL); | |
| 360 | + i915_request_get(rq); | |
| 361 | +} | |
| 362 | + | |
| 363 | +static void __rq_cancel_watchdog(struct i915_request *rq) | |
| 364 | +{ | |
| 365 | + struct i915_request_watchdog *wdg = &rq->watchdog; | |
| 366 | + | |
| 367 | + if (wdg->timer.function && hrtimer_try_to_cancel(&wdg->timer) > 0) | |
| 368 | + i915_request_put(rq); | |
| 369 | +} | |
| 370 | + | |
| 277 | 371 | bool i915_request_retire(struct i915_request *rq) |
| 278 | 372 | { |
| 279 | 373 | if (!__i915_request_is_complete(rq)) |
| @@ -285,6 +379,8 @@ bool i915_request_retire(struct i915_request *rq) · 5 unmodified lines | ||
| 285 | 379 | trace_i915_request_retire(rq); |
| 286 | 380 | i915_request_mark_complete(rq); |
| 287 | 381 | |
| 382 | + __rq_cancel_watchdog(rq); | |
| 383 | + | |
| 288 | 384 | /* |
| 289 | 385 | * We know the GPU must have read the request to have |
| 290 | 386 | * sent us the seqno + interrupt, so use the position |
| @@ -498,20 +594,22 @@ void __i915_request_skip(struct i915_request *rq) · 207 unmodified lines | ||
| 498 | 594 | rq->infix = rq->postfix; |
| 499 | 595 | } |
| 500 | 596 | |
| 501 | −void i915_request_set_error_once(struct i915_request *rq, int error) | |
| 597 | +bool i915_request_set_error_once(struct i915_request *rq, int error) | |
| 502 | 598 | { |
| 503 | 599 | int old; |
| 504 | 600 | |
| 505 | 601 | GEM_BUG_ON(!IS_ERR_VALUE((long)error)); |
| 506 | 602 | |
| 507 | 603 | if (i915_request_signaled(rq)) |
| 508 | − return; | |
| 604 | + return false; | |
| 509 | 605 | |
| 510 | 606 | old = READ_ONCE(rq->fence.error); |
| 511 | 607 | do { |
| 512 | 608 | if (fatal_error(old)) |
| 513 | − return; | |
| 609 | + return false; | |
| 514 | 610 | } while (!try_cmpxchg(&rq->fence.error, &old, error)); |
| 611 | + | |
| 612 | + return true; | |
| 515 | 613 | } |
| 516 | 614 | |
| 517 | 615 | void i915_request_mark_eio(struct i915_request *rq) |
| @@ -678,6 +776,28 @@ void i915_request_unsubmit(struct i915_request *request) · 160 unmodified lines | ||
| 678 | 776 | spin_unlock_irqrestore(&engine->active.lock, flags); |
| 679 | 777 | } |
| 680 | 778 | |
| 779 | +static void __cancel_request(struct i915_request *rq) | |
| 780 | +{ | |
| 781 | + struct intel_engine_cs *engine = NULL; | |
| 782 | + | |
| 783 | + i915_request_active_engine(rq, &engine); | |
| 784 | + | |
| 785 | + if (engine && intel_engine_pulse(engine)) | |
| 786 | + intel_gt_handle_error(engine->gt, engine->mask, 0, | |
| 787 | + "request cancellation by %s", | |
| 788 | + current->comm); | |
| 789 | +} | |
| 790 | + | |
| 791 | +void i915_request_cancel(struct i915_request *rq, int error) | |
| 792 | +{ | |
| 793 | + if (!i915_request_set_error_once(rq, error)) | |
| 794 | + return; | |
| 795 | + | |
| 796 | + set_bit(I915_FENCE_FLAG_SENTINEL, &rq->fence.flags); | |
| 797 | + | |
| 798 | + __cancel_request(rq); | |
| 799 | +} | |
| 800 | + | |
| 681 | 801 | static int __i915_sw_fence_call |
| 682 | 802 | submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) |
| 683 | 803 | { |
| @@ -690,6 +810,8 @@ submit_notify(struct i915_sw_fence *fence, enum i915_sw_fence_notify state) · 6 unmodified lines | ||
| 690 | 810 | |
| 691 | 811 | if (unlikely(fence->error)) |
| 692 | 812 | i915_request_set_error_once(request, fence->error); |
| 813 | + else | |
| 814 | + __rq_arm_watchdog(request); | |
| 693 | 815 | |
| 694 | 816 | /* |
| 695 | 817 | * We need to serialize use of the submit_request() callback |
| @@ -863,7 +985,6 @@ __i915_request_create(struct intel_context *ce, gfp_t gfp) · 167 unmodified lines | ||
| 863 | 985 | rq->fence.seqno = seqno; |
| 864 | 986 | |
| 865 | 987 | RCU_INIT_POINTER(rq->timeline, tl); |
| 866 | − RCU_INIT_POINTER(rq->hwsp_cacheline, tl->hwsp_cacheline); | |
| 867 | 988 | rq->hwsp_seqno = tl->hwsp_seqno; |
| 868 | 989 | GEM_BUG_ON(__i915_request_is_complete(rq)); |
| 869 | 990 | |
| @@ -877,6 +998,7 @@ __i915_request_create(struct intel_context *ce, gfp_t gfp) · 7 unmodified lines | ||
| 877 | 998 | |
| 878 | 999 | /* No zalloc, everything must be cleared after use */ |
| 879 | 1000 | rq->batch = NULL; |
| 1001 | + __rq_init_watchdog(rq); | |
| 880 | 1002 | GEM_BUG_ON(rq->capture_list); |
| 881 | 1003 | GEM_BUG_ON(!llist_empty(&rq->execute_cb)); |
| 882 | 1004 | |
| @@ -1108,9 +1230,6 @@ emit_semaphore_wait(struct i915_request *to, · 225 unmodified lines | ||
| 1108 | 1230 | if (i915_request_has_initial_breadcrumb(to)) |
| 1109 | 1231 | goto await_fence; |
| 1110 | 1232 | |
| 1111 | − if (!rcu_access_pointer(from->hwsp_cacheline)) | |
| 1112 | − goto await_fence; | |
| 1113 | − | |
| 1114 | 1233 | /* |
| 1115 | 1234 | * If this or its dependents are waiting on an external fence |
| 1116 | 1235 | * that may fail catastrophically, then we want to avoid using |
| @@ -26,7 +26,9 @@ · 25 unmodified lines | ||
| 26 | 26 | #define I915_REQUEST_H |
| 27 | 27 | |
| 28 | 28 | #include <linux/dma-fence.h> |
| 29 | +#include <linux/hrtimer.h> | |
| 29 | 30 | #include <linux/irq_work.h> |
| 31 | +#include <linux/llist.h> | |
| 30 | 32 | #include <linux/lockdep.h> |
| 31 | 33 | |
| 32 | 34 | #include "gem/i915_gem_context_types.h" |
| @@ -237,16 +239,6 @@ struct i915_request { · 204 unmodified lines | ||
| 237 | 239 | */ |
| 238 | 240 | const u32 *hwsp_seqno; |
| 239 | 241 | |
| 240 | − /* | |
| 241 | − * If we need to access the timeline's seqno for this request in | |
| 242 | − * another request, we need to keep a read reference to this associated | |
| 243 | − * cacheline, so that we do not free and recycle it before the foreign | |
| 244 | − * observers have completed. Hence, we keep a pointer to the cacheline | |
| 245 | − * inside the timeline's HWSP vma, but it is only valid while this | |
| 246 | − * request has not completed and guarded by the timeline mutex. | |
| 247 | − */ | |
| 248 | − struct intel_timeline_cacheline __rcu *hwsp_cacheline; | |
| 249 | − | |
| 250 | 242 | /** Position in the ring of the start of the request */ |
| 251 | 243 | u32 head; |
| 252 | 244 | |
| @@ -287,6 +279,12 @@ struct i915_request { · 34 unmodified lines | ||
| 287 | 279 | /** timeline->request entry for this request */ |
| 288 | 280 | struct list_head link; |
| 289 | 281 | |
| 282 | + /** Watchdog support fields. */ | |
| 283 | + struct i915_request_watchdog { | |
| 284 | + struct llist_node link; | |
| 285 | + struct hrtimer timer; | |
| 286 | + } watchdog; | |
| 287 | + | |
| 290 | 288 | I915_SELFTEST_DECLARE(struct { |
| 291 | 289 | struct list_head link; |
| 292 | 290 | unsigned long delay; |
| @@ -310,7 +308,7 @@ struct i915_request * __must_check · 17 unmodified lines | ||
| 310 | 308 | i915_request_create(struct intel_context *ce); |
| 311 | 309 | |
| 312 | 310 | void __i915_request_skip(struct i915_request *rq); |
| 313 | −void i915_request_set_error_once(struct i915_request *rq, int error); | |
| 311 | +bool i915_request_set_error_once(struct i915_request *rq, int error); | |
| 314 | 312 | void i915_request_mark_eio(struct i915_request *rq); |
| 315 | 313 | |
| 316 | 314 | struct i915_request *__i915_request_commit(struct i915_request *request); |
| @@ -366,6 +364,8 @@ void i915_request_submit(struct i915_request *request); · 49 unmodified lines | ||
| 366 | 364 | void __i915_request_unsubmit(struct i915_request *request); |
| 367 | 365 | void i915_request_unsubmit(struct i915_request *request); |
| 368 | 366 | |
| 367 | +void i915_request_cancel(struct i915_request *rq, int error); | |
| 368 | + | |
| 369 | 369 | long i915_request_wait(struct i915_request *rq, |
| 370 | 370 | unsigned int flags, |
| 371 | 371 | long timeout) |
| @@ -616,4 +616,29 @@ i915_request_active_timeline(const struct i915_request *rq) · 244 unmodified lines | ||
| 616 | 616 | lockdep_is_held(&rq->engine->active.lock)); |
| 617 | 617 | } |
| 618 | 618 | |
| 619 | +static inline u32 | |
| 620 | +i915_request_active_seqno(const struct i915_request *rq) | |
| 621 | +{ | |
| 622 | + u32 hwsp_phys_base = | |
| 623 | + page_mask_bits(i915_request_active_timeline(rq)->hwsp_offset); | |
| 624 | + u32 hwsp_relative_offset = offset_in_page(rq->hwsp_seqno); | |
| 625 | + | |
| 626 | + /* | |
| 627 | + * Because of wraparound, we cannot simply take tl->hwsp_offset, | |
| 628 | + * but instead use the fact that the relative for vaddr is the | |
| 629 | + * offset as for hwsp_offset. Take the top bits from tl->hwsp_offset | |
| 630 | + * and combine them with the relative offset in rq->hwsp_seqno. | |
| 631 | + * | |
| 632 | + * As rw->hwsp_seqno is rewritten when signaled, this only works | |
| 633 | + * when the request isn't signaled yet, but at that point you | |
| 634 | + * no longer need the offset. | |
| 635 | + */ | |
| 636 | + | |
| 637 | + return hwsp_phys_base + hwsp_relative_offset; | |
| 638 | +} | |
| 639 | + | |
| 640 | +bool | |
| 641 | +i915_request_active_engine(struct i915_request *rq, | |
| 642 | + struct intel_engine_cs **active); | |
| 643 | + | |
| 619 | 644 | #endif /* I915_REQUEST_H */ |
| @@ -107,6 +107,7 @@ int __i915_subtests(const char *caller, · 106 unmodified lines | ||
| 107 | 107 | |
| 108 | 108 | #define I915_SELFTEST_DECLARE(x) x |
| 109 | 109 | #define I915_SELFTEST_ONLY(x) unlikely(x) |
| 110 | +#define I915_SELFTEST_EXPORT | |
| 110 | 111 | |
| 111 | 112 | #else /* !IS_ENABLED(CONFIG_DRM_I915_SELFTEST) */ |
| 112 | 113 | |
| @@ -116,6 +117,7 @@ static inline int i915_perf_selftests(struct pci_dev *pdev) { return 0; } · 3 unmodified lines | ||
| 116 | 117 | |
| 117 | 118 | #define I915_SELFTEST_DECLARE(x) |
| 118 | 119 | #define I915_SELFTEST_ONLY(x) 0 |
| 120 | +#define I915_SELFTEST_EXPORT static | |
| 119 | 121 | |
| 120 | 122 | #endif |
| 121 | 123 | |
| @@ -230,7 +230,7 @@ err_vma: · 229 unmodified lines | ||
| 230 | 230 | } |
| 231 | 231 | |
| 232 | 232 | static struct i915_vma * |
| 233 | −vma_lookup(struct drm_i915_gem_object *obj, | |
| 233 | +i915_vma_lookup(struct drm_i915_gem_object *obj, | |
| 234 | 234 | struct i915_address_space *vm, |
| 235 | 235 | const struct i915_ggtt_view *view) |
| 236 | 236 | { |
| @@ -278,7 +278,7 @@ i915_vma_instance(struct drm_i915_gem_object *obj, · 41 unmodified lines | ||
| 278 | 278 | GEM_BUG_ON(!atomic_read(&vm->open)); |
| 279 | 279 | |
| 280 | 280 | spin_lock(&obj->vma.lock); |
| 281 | − vma = vma_lookup(obj, vm, view); | |
| 281 | + vma = i915_vma_lookup(obj, vm, view); | |
| 282 | 282 | spin_unlock(&obj->vma.lock); |
| 283 | 283 | |
| 284 | 284 | /* vma_create() will resolve the race if another creates the vma */ |
| @@ -863,8 +863,8 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, · 578 unmodified lines | ||
| 863 | 863 | int err; |
| 864 | 864 | |
| 865 | 865 | #ifdef CONFIG_PROVE_LOCKING |
| 866 | − if (debug_locks && lockdep_is_held(&vma->vm->i915->drm.struct_mutex)) | |
| 867 | − WARN_ON(!ww); | |
| 866 | + if (debug_locks && !WARN_ON(!ww) && vma->resv) | |
| 867 | + assert_vma_held(vma); | |
| 868 | 868 | #endif |
| 869 | 869 | |
| 870 | 870 | BUILD_BUG_ON(PIN_GLOBAL != I915_VMA_GLOBAL_BIND); |
| @@ -884,6 +884,11 @@ int i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, · 13 unmodified lines | ||
| 884 | 884 | wakeref = intel_runtime_pm_get(&vma->vm->i915->runtime_pm); |
| 885 | 885 | |
| 886 | 886 | if (flags & vma->vm->bind_async_flags) { |
| 887 | + /* lock VM */ | |
| 888 | + err = i915_vm_lock_objects(vma->vm, ww); | |
| 889 | + if (err) | |
| 890 | + goto err_rpm; | |
| 891 | + | |
| 887 | 892 | work = i915_vma_work(); |
| 888 | 893 | if (!work) { |
| 889 | 894 | err = -ENOMEM; |
| @@ -1020,8 +1025,15 @@ int i915_ggtt_pin(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, · 130 unmodified lines | ||
| 1020 | 1025 | |
| 1021 | 1026 | GEM_BUG_ON(!i915_vma_is_ggtt(vma)); |
| 1022 | 1027 | |
| 1028 | +#ifdef CONFIG_LOCKDEP | |
| 1029 | + WARN_ON(!ww && vma->resv && dma_resv_held(vma->resv)); | |
| 1030 | +#endif | |
| 1031 | + | |
| 1023 | 1032 | do { |
| 1024 | − err = i915_vma_pin_ww(vma, ww, 0, align, flags | PIN_GLOBAL); | |
| 1033 | + if (ww) | |
| 1034 | + err = i915_vma_pin_ww(vma, ww, 0, align, flags | PIN_GLOBAL); | |
| 1035 | + else | |
| 1036 | + err = i915_vma_pin(vma, 0, align, flags | PIN_GLOBAL); | |
| 1025 | 1037 | if (err != -ENOSPC) { |
| 1026 | 1038 | if (!err) { |
| 1027 | 1039 | err = i915_vma_wait_for_bind(vma); |
| @@ -1238,9 +1250,11 @@ int i915_vma_move_to_active(struct i915_vma *vma, · 210 unmodified lines | ||
| 1238 | 1250 | obj->write_domain = I915_GEM_DOMAIN_RENDER; |
| 1239 | 1251 | obj->read_domains = 0; |
| 1240 | 1252 | } else { |
| 1241 | − err = dma_resv_reserve_shared(vma->resv, 1); | |
| 1242 | − if (unlikely(err)) | |
| 1243 | − return err; | |
| 1253 | + if (!(flags & __EXEC_OBJECT_NO_RESERVE)) { | |
| 1254 | + err = dma_resv_reserve_shared(vma->resv, 1); | |
| 1255 | + if (unlikely(err)) | |
| 1256 | + return err; | |
| 1257 | + } | |
| 1244 | 1258 | |
| 1245 | 1259 | dma_resv_add_shared_fence(vma->resv, &rq->fence); |
| 1246 | 1260 | obj->write_domain = 0; |
| @@ -52,6 +52,9 @@ static inline bool i915_vma_is_active(const struct i915_vma *vma) · 51 unmodified lines | ||
| 52 | 52 | return !i915_active_is_idle(&vma->active); |
| 53 | 53 | } |
| 54 | 54 | |
| 55 | +/* do not reserve memory to prevent deadlocks */ | |
| 56 | +#define __EXEC_OBJECT_NO_RESERVE BIT(31) | |
| 57 | + | |
| 55 | 58 | int __must_check __i915_vma_move_to_active(struct i915_vma *vma, |
| 56 | 59 | struct i915_request *rq); |
| 57 | 60 | int __must_check i915_vma_move_to_active(struct i915_vma *vma, |
| @@ -243,7 +246,22 @@ i915_vma_pin_ww(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, · 185 unmodified lines | ||
| 243 | 246 | static inline int __must_check |
| 244 | 247 | i915_vma_pin(struct i915_vma *vma, u64 size, u64 alignment, u64 flags) |
| 245 | 248 | { |
| 246 | − return i915_vma_pin_ww(vma, NULL, size, alignment, flags); | |
| 249 | + struct i915_gem_ww_ctx ww; | |
| 250 | + int err; | |
| 251 | + | |
| 252 | + i915_gem_ww_ctx_init(&ww, true); | |
| 253 | +retry: | |
| 254 | + err = i915_gem_object_lock(vma->obj, &ww); | |
| 255 | + if (!err) | |
| 256 | + err = i915_vma_pin_ww(vma, &ww, size, alignment, flags); | |
| 257 | + if (err == -EDEADLK) { | |
| 258 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 259 | + if (!err) | |
| 260 | + goto retry; | |
| 261 | + } | |
| 262 | + i915_gem_ww_ctx_fini(&ww); | |
| 263 | + | |
| 264 | + return err; | |
| 247 | 265 | } |
| 248 | 266 | |
| 249 | 267 | int i915_ggtt_pin(struct i915_vma *vma, struct i915_gem_ww_ctx *ww, |
| @@ -121,7 +121,7 @@ fake_dma_object(struct drm_i915_private *i915, u64 size) · 120 unmodified lines | ||
| 121 | 121 | goto err; |
| 122 | 122 | |
| 123 | 123 | drm_gem_private_object_init(&i915->drm, &obj->base, size); |
| 124 | − i915_gem_object_init(obj, &fake_ops, &lock_class); | |
| 124 | + i915_gem_object_init(obj, &fake_ops, &lock_class, 0); | |
| 125 | 125 | |
| 126 | 126 | i915_gem_object_set_volatile(obj); |
| 127 | 127 | |
| @@ -130,7 +130,7 @@ fake_dma_object(struct drm_i915_private *i915, u64 size) · 2 unmodified lines | ||
| 130 | 130 | obj->cache_level = I915_CACHE_NONE; |
| 131 | 131 | |
| 132 | 132 | /* Preallocate the "backing storage" */ |
| 133 | − if (i915_gem_object_pin_pages(obj)) | |
| 133 | + if (i915_gem_object_pin_pages_unlocked(obj)) | |
| 134 | 134 | goto err_obj; |
| 135 | 135 | |
| 136 | 136 | i915_gem_object_unpin_pages(obj); |
| @@ -146,6 +146,7 @@ static int igt_ppgtt_alloc(void *arg) · 9 unmodified lines | ||
| 146 | 146 | { |
| 147 | 147 | struct drm_i915_private *dev_priv = arg; |
| 148 | 148 | struct i915_ppgtt *ppgtt; |
| 149 | + struct i915_gem_ww_ctx ww; | |
| 149 | 150 | u64 size, last, limit; |
| 150 | 151 | int err = 0; |
| 151 | 152 | |
| @@ -171,6 +172,12 @@ static int igt_ppgtt_alloc(void *arg) · 19 unmodified lines | ||
| 171 | 172 | limit = totalram_pages() << PAGE_SHIFT; |
| 172 | 173 | limit = min(ppgtt->vm.total, limit); |
| 173 | 174 | |
| 175 | + i915_gem_ww_ctx_init(&ww, false); | |
| 176 | +retry: | |
| 177 | + err = i915_vm_lock_objects(&ppgtt->vm, &ww); | |
| 178 | + if (err) | |
| 179 | + goto err_ppgtt_cleanup; | |
| 180 | + | |
| 174 | 181 | /* Check we can allocate the entire range */ |
| 175 | 182 | for (size = 4096; size <= limit; size <<= 2) { |
| 176 | 183 | struct i915_vm_pt_stash stash = {}; |
| @@ -215,6 +222,13 @@ static int igt_ppgtt_alloc(void *arg) · 38 unmodified lines | ||
| 215 | 222 | } |
| 216 | 223 | |
| 217 | 224 | err_ppgtt_cleanup: |
| 225 | + if (err == -EDEADLK) { | |
| 226 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 227 | + if (!err) | |
| 228 | + goto retry; | |
| 229 | + } | |
| 230 | + i915_gem_ww_ctx_fini(&ww); | |
| 231 | + | |
| 218 | 232 | i915_vm_put(&ppgtt->vm); |
| 219 | 233 | return err; |
| 220 | 234 | } |
| @@ -276,7 +290,7 @@ static int lowlevel_hole(struct i915_address_space *vm, · 55 unmodified lines | ||
| 276 | 290 | |
| 277 | 291 | GEM_BUG_ON(obj->base.size != BIT_ULL(size)); |
| 278 | 292 | |
| 279 | − if (i915_gem_object_pin_pages(obj)) { | |
| 293 | + if (i915_gem_object_pin_pages_unlocked(obj)) { | |
| 280 | 294 | i915_gem_object_put(obj); |
| 281 | 295 | kfree(order); |
| 282 | 296 | break; |
| @@ -297,20 +311,36 @@ static int lowlevel_hole(struct i915_address_space *vm, · 14 unmodified lines | ||
| 297 | 311 | |
| 298 | 312 | if (vm->allocate_va_range) { |
| 299 | 313 | struct i915_vm_pt_stash stash = {}; |
| 314 | + struct i915_gem_ww_ctx ww; | |
| 315 | + int err; | |
| 316 | + | |
| 317 | + i915_gem_ww_ctx_init(&ww, false); | |
| 318 | +retry: | |
| 319 | + err = i915_vm_lock_objects(vm, &ww); | |
| 320 | + if (err) | |
| 321 | + goto alloc_vm_end; | |
| 300 | 322 | |
| 323 | + err = -ENOMEM; | |
| 301 | 324 | if (i915_vm_alloc_pt_stash(vm, &stash, |
| 302 | 325 | BIT_ULL(size))) |
| 303 | − break; | |
| 304 | − | |
| 305 | − if (i915_vm_pin_pt_stash(vm, &stash)) { | |
| 306 | − i915_vm_free_pt_stash(vm, &stash); | |
| 307 | − break; | |
| 308 | − } | |
| 326 | + goto alloc_vm_end; | |
| 309 | 327 | |
| 310 | − vm->allocate_va_range(vm, &stash, | |
| 311 | − addr, BIT_ULL(size)); | |
| 328 | + err = i915_vm_pin_pt_stash(vm, &stash); | |
| 329 | + if (!err) | |
| 330 | + vm->allocate_va_range(vm, &stash, | |
| 331 | + addr, BIT_ULL(size)); | |
| 312 | 332 | |
| 313 | 333 | i915_vm_free_pt_stash(vm, &stash); |
| 334 | +alloc_vm_end: | |
| 335 | + if (err == -EDEADLK) { | |
| 336 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 337 | + if (!err) | |
| 338 | + goto retry; | |
| 339 | + } | |
| 340 | + i915_gem_ww_ctx_fini(&ww); | |
| 341 | + | |
| 342 | + if (err) | |
| 343 | + break; | |
| 314 | 344 | } |
| 315 | 345 | |
| 316 | 346 | mock_vma->pages = obj->mm.pages; |
| @@ -1166,7 +1196,7 @@ static int igt_ggtt_page(void *arg) · 849 unmodified lines | ||
| 1166 | 1196 | if (IS_ERR(obj)) |
| 1167 | 1197 | return PTR_ERR(obj); |
| 1168 | 1198 | |
| 1169 | − err = i915_gem_object_pin_pages(obj); | |
| 1199 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 1170 | 1200 | if (err) |
| 1171 | 1201 | goto out_free; |
| 1172 | 1202 | |
| @@ -1333,7 +1363,7 @@ static int igt_gtt_reserve(void *arg) · 160 unmodified lines | ||
| 1333 | 1363 | goto out; |
| 1334 | 1364 | } |
| 1335 | 1365 | |
| 1336 | − err = i915_gem_object_pin_pages(obj); | |
| 1366 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 1337 | 1367 | if (err) { |
| 1338 | 1368 | i915_gem_object_put(obj); |
| 1339 | 1369 | goto out; |
| @@ -1385,7 +1415,7 @@ static int igt_gtt_reserve(void *arg) · 45 unmodified lines | ||
| 1385 | 1415 | goto out; |
| 1386 | 1416 | } |
| 1387 | 1417 | |
| 1388 | − err = i915_gem_object_pin_pages(obj); | |
| 1418 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 1389 | 1419 | if (err) { |
| 1390 | 1420 | i915_gem_object_put(obj); |
| 1391 | 1421 | goto out; |
| @@ -1549,7 +1579,7 @@ static int igt_gtt_insert(void *arg) · 157 unmodified lines | ||
| 1549 | 1579 | goto out; |
| 1550 | 1580 | } |
| 1551 | 1581 | |
| 1552 | − err = i915_gem_object_pin_pages(obj); | |
| 1582 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 1553 | 1583 | if (err) { |
| 1554 | 1584 | i915_gem_object_put(obj); |
| 1555 | 1585 | goto out; |
| @@ -1658,7 +1688,7 @@ static int igt_gtt_insert(void *arg) · 102 unmodified lines | ||
| 1658 | 1688 | goto out; |
| 1659 | 1689 | } |
| 1660 | 1690 | |
| 1661 | − err = i915_gem_object_pin_pages(obj); | |
| 1691 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 1662 | 1692 | if (err) { |
| 1663 | 1693 | i915_gem_object_put(obj); |
| 1664 | 1694 | goto out; |
| @@ -1829,7 +1859,7 @@ static int igt_cs_tlb(void *arg) · 164 unmodified lines | ||
| 1829 | 1859 | goto out_vm; |
| 1830 | 1860 | } |
| 1831 | 1861 | |
| 1832 | − batch = i915_gem_object_pin_map(bbe, I915_MAP_WC); | |
| 1862 | + batch = i915_gem_object_pin_map_unlocked(bbe, I915_MAP_WC); | |
| 1833 | 1863 | if (IS_ERR(batch)) { |
| 1834 | 1864 | err = PTR_ERR(batch); |
| 1835 | 1865 | goto out_put_bbe; |
| @@ -1845,7 +1875,7 @@ static int igt_cs_tlb(void *arg) · 9 unmodified lines | ||
| 1845 | 1875 | } |
| 1846 | 1876 | |
| 1847 | 1877 | /* Track the execution of each request by writing into different slot */ |
| 1848 | − batch = i915_gem_object_pin_map(act, I915_MAP_WC); | |
| 1878 | + batch = i915_gem_object_pin_map_unlocked(act, I915_MAP_WC); | |
| 1849 | 1879 | if (IS_ERR(batch)) { |
| 1850 | 1880 | err = PTR_ERR(batch); |
| 1851 | 1881 | goto out_put_act; |
| @@ -1892,7 +1922,7 @@ static int igt_cs_tlb(void *arg) · 40 unmodified lines | ||
| 1892 | 1922 | goto out_put_out; |
| 1893 | 1923 | GEM_BUG_ON(vma->node.start != vm->total - PAGE_SIZE); |
| 1894 | 1924 | |
| 1895 | − result = i915_gem_object_pin_map(out, I915_MAP_WB); | |
| 1925 | + result = i915_gem_object_pin_map_unlocked(out, I915_MAP_WB); | |
| 1896 | 1926 | if (IS_ERR(result)) { |
| 1897 | 1927 | err = PTR_ERR(result); |
| 1898 | 1928 | goto out_put_out; |
| @@ -1908,6 +1938,7 @@ static int igt_cs_tlb(void *arg) · 9 unmodified lines | ||
| 1908 | 1938 | while (!__igt_timeout(end_time, NULL)) { |
| 1909 | 1939 | struct i915_vm_pt_stash stash = {}; |
| 1910 | 1940 | struct i915_request *rq; |
| 1941 | + struct i915_gem_ww_ctx ww; | |
| 1911 | 1942 | u64 offset; |
| 1912 | 1943 | |
| 1913 | 1944 | offset = igt_random_offset(&prng, |
| @@ -1926,19 +1957,30 @@ static int igt_cs_tlb(void *arg) · 12 unmodified lines | ||
| 1926 | 1957 | if (err) |
| 1927 | 1958 | goto end; |
| 1928 | 1959 | |
| 1960 | + i915_gem_ww_ctx_init(&ww, false); | |
| 1961 | +retry: | |
| 1962 | + err = i915_vm_lock_objects(vm, &ww); | |
| 1963 | + if (err) | |
| 1964 | + goto end_ww; | |
| 1965 | + | |
| 1929 | 1966 | err = i915_vm_alloc_pt_stash(vm, &stash, chunk_size); |
| 1930 | 1967 | if (err) |
| 1931 | − goto end; | |
| 1968 | + goto end_ww; | |
| 1932 | 1969 | |
| 1933 | 1970 | err = i915_vm_pin_pt_stash(vm, &stash); |
| 1934 | − if (err) { | |
| 1935 | − i915_vm_free_pt_stash(vm, &stash); | |
| 1936 | − goto end; | |
| 1937 | − } | |
| 1938 | − | |
| 1939 | − vm->allocate_va_range(vm, &stash, offset, chunk_size); | |
| 1971 | + if (!err) | |
| 1972 | + vm->allocate_va_range(vm, &stash, offset, chunk_size); | |
| 1940 | 1973 | |
| 1941 | 1974 | i915_vm_free_pt_stash(vm, &stash); |
| 1975 | +end_ww: | |
| 1976 | + if (err == -EDEADLK) { | |
| 1977 | + err = i915_gem_ww_ctx_backoff(&ww); | |
| 1978 | + if (!err) | |
| 1979 | + goto retry; | |
| 1980 | + } | |
| 1981 | + i915_gem_ww_ctx_fini(&ww); | |
| 1982 | + if (err) | |
| 1983 | + goto end; | |
| 1942 | 1984 | |
| 1943 | 1985 | /* Prime the TLB with the dummy pages */ |
| 1944 | 1986 | for (i = 0; i < count; i++) { |
| @@ -609,6 +609,206 @@ static int live_nop_request(void *arg) · 608 unmodified lines | ||
| 609 | 609 | return err; |
| 610 | 610 | } |
| 611 | 611 | |
| 612 | +static int __cancel_inactive(struct intel_engine_cs *engine) | |
| 613 | +{ | |
| 614 | + struct intel_context *ce; | |
| 615 | + struct igt_spinner spin; | |
| 616 | + struct i915_request *rq; | |
| 617 | + int err = 0; | |
| 618 | + | |
| 619 | + if (igt_spinner_init(&spin, engine->gt)) | |
| 620 | + return -ENOMEM; | |
| 621 | + | |
| 622 | + ce = intel_context_create(engine); | |
| 623 | + if (IS_ERR(ce)) { | |
| 624 | + err = PTR_ERR(ce); | |
| 625 | + goto out_spin; | |
| 626 | + } | |
| 627 | + | |
| 628 | + rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK); | |
| 629 | + if (IS_ERR(rq)) { | |
| 630 | + err = PTR_ERR(rq); | |
| 631 | + goto out_ce; | |
| 632 | + } | |
| 633 | + | |
| 634 | + pr_debug("%s: Cancelling inactive request\n", engine->name); | |
| 635 | + i915_request_cancel(rq, -EINTR); | |
| 636 | + i915_request_get(rq); | |
| 637 | + i915_request_add(rq); | |
| 638 | + | |
| 639 | + if (i915_request_wait(rq, 0, HZ / 5) < 0) { | |
| 640 | + struct drm_printer p = drm_info_printer(engine->i915->drm.dev); | |
| 641 | + | |
| 642 | + pr_err("%s: Failed to cancel inactive request\n", engine->name); | |
| 643 | + intel_engine_dump(engine, &p, "%s\n", engine->name); | |
| 644 | + err = -ETIME; | |
| 645 | + goto out_rq; | |
| 646 | + } | |
| 647 | + | |
| 648 | + if (rq->fence.error != -EINTR) { | |
| 649 | + pr_err("%s: fence not cancelled (%u)\n", | |
| 650 | + engine->name, rq->fence.error); | |
| 651 | + err = -EINVAL; | |
| 652 | + } | |
| 653 | + | |
| 654 | +out_rq: | |
| 655 | + i915_request_put(rq); | |
| 656 | +out_ce: | |
| 657 | + intel_context_put(ce); | |
| 658 | +out_spin: | |
| 659 | + igt_spinner_fini(&spin); | |
| 660 | + if (err) | |
| 661 | + pr_err("%s: %s error %d\n", __func__, engine->name, err); | |
| 662 | + return err; | |
| 663 | +} | |
| 664 | + | |
| 665 | +static int __cancel_active(struct intel_engine_cs *engine) | |
| 666 | +{ | |
| 667 | + struct intel_context *ce; | |
| 668 | + struct igt_spinner spin; | |
| 669 | + struct i915_request *rq; | |
| 670 | + int err = 0; | |
| 671 | + | |
| 672 | + if (igt_spinner_init(&spin, engine->gt)) | |
| 673 | + return -ENOMEM; | |
| 674 | + | |
| 675 | + ce = intel_context_create(engine); | |
| 676 | + if (IS_ERR(ce)) { | |
| 677 | + err = PTR_ERR(ce); | |
| 678 | + goto out_spin; | |
| 679 | + } | |
| 680 | + | |
| 681 | + rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK); | |
| 682 | + if (IS_ERR(rq)) { | |
| 683 | + err = PTR_ERR(rq); | |
| 684 | + goto out_ce; | |
| 685 | + } | |
| 686 | + | |
| 687 | + pr_debug("%s: Cancelling active request\n", engine->name); | |
| 688 | + i915_request_get(rq); | |
| 689 | + i915_request_add(rq); | |
| 690 | + if (!igt_wait_for_spinner(&spin, rq)) { | |
| 691 | + struct drm_printer p = drm_info_printer(engine->i915->drm.dev); | |
| 692 | + | |
| 693 | + pr_err("Failed to start spinner on %s\n", engine->name); | |
| 694 | + intel_engine_dump(engine, &p, "%s\n", engine->name); | |
| 695 | + err = -ETIME; | |
| 696 | + goto out_rq; | |
| 697 | + } | |
| 698 | + i915_request_cancel(rq, -EINTR); | |
| 699 | + | |
| 700 | + if (i915_request_wait(rq, 0, HZ / 5) < 0) { | |
| 701 | + struct drm_printer p = drm_info_printer(engine->i915->drm.dev); | |
| 702 | + | |
| 703 | + pr_err("%s: Failed to cancel active request\n", engine->name); | |
| 704 | + intel_engine_dump(engine, &p, "%s\n", engine->name); | |
| 705 | + err = -ETIME; | |
| 706 | + goto out_rq; | |
| 707 | + } | |
| 708 | + | |
| 709 | + if (rq->fence.error != -EINTR) { | |
| 710 | + pr_err("%s: fence not cancelled (%u)\n", | |
| 711 | + engine->name, rq->fence.error); | |
| 712 | + err = -EINVAL; | |
| 713 | + } | |
| 714 | + | |
| 715 | +out_rq: | |
| 716 | + i915_request_put(rq); | |
| 717 | +out_ce: | |
| 718 | + intel_context_put(ce); | |
| 719 | +out_spin: | |
| 720 | + igt_spinner_fini(&spin); | |
| 721 | + if (err) | |
| 722 | + pr_err("%s: %s error %d\n", __func__, engine->name, err); | |
| 723 | + return err; | |
| 724 | +} | |
| 725 | + | |
| 726 | +static int __cancel_completed(struct intel_engine_cs *engine) | |
| 727 | +{ | |
| 728 | + struct intel_context *ce; | |
| 729 | + struct igt_spinner spin; | |
| 730 | + struct i915_request *rq; | |
| 731 | + int err = 0; | |
| 732 | + | |
| 733 | + if (igt_spinner_init(&spin, engine->gt)) | |
| 734 | + return -ENOMEM; | |
| 735 | + | |
| 736 | + ce = intel_context_create(engine); | |
| 737 | + if (IS_ERR(ce)) { | |
| 738 | + err = PTR_ERR(ce); | |
| 739 | + goto out_spin; | |
| 740 | + } | |
| 741 | + | |
| 742 | + rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK); | |
| 743 | + if (IS_ERR(rq)) { | |
| 744 | + err = PTR_ERR(rq); | |
| 745 | + goto out_ce; | |
| 746 | + } | |
| 747 | + igt_spinner_end(&spin); | |
| 748 | + i915_request_get(rq); | |
| 749 | + i915_request_add(rq); | |
| 750 | + | |
| 751 | + if (i915_request_wait(rq, 0, HZ / 5) < 0) { | |
| 752 | + err = -ETIME; | |
| 753 | + goto out_rq; | |
| 754 | + } | |
| 755 | + | |
| 756 | + pr_debug("%s: Cancelling completed request\n", engine->name); | |
| 757 | + i915_request_cancel(rq, -EINTR); | |
| 758 | + if (rq->fence.error) { | |
| 759 | + pr_err("%s: fence not cancelled (%u)\n", | |
| 760 | + engine->name, rq->fence.error); | |
| 761 | + err = -EINVAL; | |
| 762 | + } | |
| 763 | + | |
| 764 | +out_rq: | |
| 765 | + i915_request_put(rq); | |
| 766 | +out_ce: | |
| 767 | + intel_context_put(ce); | |
| 768 | +out_spin: | |
| 769 | + igt_spinner_fini(&spin); | |
| 770 | + if (err) | |
| 771 | + pr_err("%s: %s error %d\n", __func__, engine->name, err); | |
| 772 | + return err; | |
| 773 | +} | |
| 774 | + | |
| 775 | +static int live_cancel_request(void *arg) | |
| 776 | +{ | |
| 777 | + struct drm_i915_private *i915 = arg; | |
| 778 | + struct intel_engine_cs *engine; | |
| 779 | + | |
| 780 | + /* | |
| 781 | + * Check cancellation of requests. We expect to be able to immediately | |
| 782 | + * cancel active requests, even if they are currently on the GPU. | |
| 783 | + */ | |
| 784 | + | |
| 785 | + for_each_uabi_engine(engine, i915) { | |
| 786 | + struct igt_live_test t; | |
| 787 | + int err, err2; | |
| 788 | + | |
| 789 | + if (!intel_engine_has_preemption(engine)) | |
| 790 | + continue; | |
| 791 | + | |
| 792 | + err = igt_live_test_begin(&t, i915, __func__, engine->name); | |
| 793 | + if (err) | |
| 794 | + return err; | |
| 795 | + | |
| 796 | + err = __cancel_inactive(engine); | |
| 797 | + if (err == 0) | |
| 798 | + err = __cancel_active(engine); | |
| 799 | + if (err == 0) | |
| 800 | + err = __cancel_completed(engine); | |
| 801 | + | |
| 802 | + err2 = igt_live_test_end(&t); | |
| 803 | + if (err) | |
| 804 | + return err; | |
| 805 | + if (err2) | |
| 806 | + return err2; | |
| 807 | + } | |
| 808 | + | |
| 809 | + return 0; | |
| 810 | +} | |
| 811 | + | |
| 612 | 812 | static struct i915_vma *empty_batch(struct drm_i915_private *i915) |
| 613 | 813 | { |
| 614 | 814 | struct drm_i915_gem_object *obj; |
| @@ -620,7 +820,7 @@ static struct i915_vma *empty_batch(struct drm_i915_private *i915) · 5 unmodified lines | ||
| 620 | 820 | if (IS_ERR(obj)) |
| 621 | 821 | return ERR_CAST(obj); |
| 622 | 822 | |
| 623 | − cmd = i915_gem_object_pin_map(obj, I915_MAP_WB); | |
| 823 | + cmd = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WB); | |
| 624 | 824 | if (IS_ERR(cmd)) { |
| 625 | 825 | err = PTR_ERR(cmd); |
| 626 | 826 | goto err; |
| @@ -782,7 +982,7 @@ static struct i915_vma *recursive_batch(struct drm_i915_private *i915) · 155 unmodified lines | ||
| 782 | 982 | if (err) |
| 783 | 983 | goto err; |
| 784 | 984 | |
| 785 | − cmd = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 985 | + cmd = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 786 | 986 | if (IS_ERR(cmd)) { |
| 787 | 987 | err = PTR_ERR(cmd); |
| 788 | 988 | goto err; |
| @@ -817,7 +1017,7 @@ static int recursive_batch_resolve(struct i915_vma *batch) · 28 unmodified lines | ||
| 817 | 1017 | { |
| 818 | 1018 | u32 *cmd; |
| 819 | 1019 | |
| 820 | − cmd = i915_gem_object_pin_map(batch->obj, I915_MAP_WC); | |
| 1020 | + cmd = i915_gem_object_pin_map_unlocked(batch->obj, I915_MAP_WC); | |
| 821 | 1021 | if (IS_ERR(cmd)) |
| 822 | 1022 | return PTR_ERR(cmd); |
| 823 | 1023 | |
| @@ -1070,8 +1270,8 @@ out_request: · 246 unmodified lines | ||
| 1070 | 1270 | if (!request[idx]) |
| 1071 | 1271 | break; |
| 1072 | 1272 | |
| 1073 | − cmd = i915_gem_object_pin_map(request[idx]->batch->obj, | |
| 1074 | − I915_MAP_WC); | |
| 1273 | + cmd = i915_gem_object_pin_map_unlocked(request[idx]->batch->obj, | |
| 1274 | + I915_MAP_WC); | |
| 1075 | 1275 | if (!IS_ERR(cmd)) { |
| 1076 | 1276 | *cmd = MI_BATCH_BUFFER_END; |
| 1077 | 1277 | |
| @@ -1486,6 +1686,7 @@ int i915_request_live_selftests(struct drm_i915_private *i915) · 408 unmodified lines | ||
| 1486 | 1686 | SUBTEST(live_sequential_engines), |
| 1487 | 1687 | SUBTEST(live_parallel_engines), |
| 1488 | 1688 | SUBTEST(live_empty_request), |
| 1689 | + SUBTEST(live_cancel_request), | |
| 1489 | 1690 | SUBTEST(live_breadcrumbs_smoketest), |
| 1490 | 1691 | }; |
| 1491 | 1692 | |
| @@ -12,8 +12,6 @@ · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | int igt_spinner_init(struct igt_spinner *spin, struct intel_gt *gt) |
| 14 | 14 | { |
| 15 | − unsigned int mode; | |
| 16 | − void *vaddr; | |
| 17 | 15 | int err; |
| 18 | 16 | |
| 19 | 17 | memset(spin, 0, sizeof(*spin)); |
| @@ -24,6 +22,7 @@ int igt_spinner_init(struct igt_spinner *spin, struct intel_gt *gt) · 4 unmodified lines | ||
| 24 | 22 | err = PTR_ERR(spin->hws); |
| 25 | 23 | goto err; |
| 26 | 24 | } |
| 25 | + i915_gem_object_set_cache_coherency(spin->hws, I915_CACHE_LLC); | |
| 27 | 26 | |
| 28 | 27 | spin->obj = i915_gem_object_create_internal(gt->i915, PAGE_SIZE); |
| 29 | 28 | if (IS_ERR(spin->obj)) { |
| @@ -31,34 +30,83 @@ int igt_spinner_init(struct igt_spinner *spin, struct intel_gt *gt) · 1 unmodified line | ||
| 31 | 30 | goto err_hws; |
| 32 | 31 | } |
| 33 | 32 | |
| 34 | − i915_gem_object_set_cache_coherency(spin->hws, I915_CACHE_LLC); | |
| 35 | − vaddr = i915_gem_object_pin_map(spin->hws, I915_MAP_WB); | |
| 36 | − if (IS_ERR(vaddr)) { | |
| 37 | − err = PTR_ERR(vaddr); | |
| 38 | − goto err_obj; | |
| 39 | − } | |
| 40 | − spin->seqno = memset(vaddr, 0xff, PAGE_SIZE); | |
| 41 | − | |
| 42 | − mode = i915_coherent_map_type(gt->i915); | |
| 43 | − vaddr = i915_gem_object_pin_map(spin->obj, mode); | |
| 44 | − if (IS_ERR(vaddr)) { | |
| 45 | − err = PTR_ERR(vaddr); | |
| 46 | − goto err_unpin_hws; | |
| 47 | − } | |
| 48 | − spin->batch = vaddr; | |
| 49 | − | |
| 50 | 33 | return 0; |
| 51 | 34 | |
| 52 | −err_unpin_hws: | |
| 53 | − i915_gem_object_unpin_map(spin->hws); | |
| 54 | −err_obj: | |
| 55 | − i915_gem_object_put(spin->obj); | |
| 56 | 35 | err_hws: |
| 57 | 36 | i915_gem_object_put(spin->hws); |
| 58 | 37 | err: |
| 59 | 38 | return err; |
| 60 | 39 | } |
| 61 | 40 | |
| 41 | +static void *igt_spinner_pin_obj(struct intel_context *ce, | |
| 42 | + struct i915_gem_ww_ctx *ww, | |
| 43 | + struct drm_i915_gem_object *obj, | |
| 44 | + unsigned int mode, struct i915_vma **vma) | |
| 45 | +{ | |
| 46 | + void *vaddr; | |
| 47 | + int ret; | |
| 48 | + | |
| 49 | + *vma = i915_vma_instance(obj, ce->vm, NULL); | |
| 50 | + if (IS_ERR(*vma)) | |
| 51 | + return ERR_CAST(*vma); | |
| 52 | + | |
| 53 | + ret = i915_gem_object_lock(obj, ww); | |
| 54 | + if (ret) | |
| 55 | + return ERR_PTR(ret); | |
| 56 | + | |
| 57 | + vaddr = i915_gem_object_pin_map(obj, mode); | |
| 58 | + | |
| 59 | + if (!ww) | |
| 60 | + i915_gem_object_unlock(obj); | |
| 61 | + | |
| 62 | + if (IS_ERR(vaddr)) | |
| 63 | + return vaddr; | |
| 64 | + | |
| 65 | + if (ww) | |
| 66 | + ret = i915_vma_pin_ww(*vma, ww, 0, 0, PIN_USER); | |
| 67 | + else | |
| 68 | + ret = i915_vma_pin(*vma, 0, 0, PIN_USER); | |
| 69 | + | |
| 70 | + if (ret) { | |
| 71 | + i915_gem_object_unpin_map(obj); | |
| 72 | + return ERR_PTR(ret); | |
| 73 | + } | |
| 74 | + | |
| 75 | + return vaddr; | |
| 76 | +} | |
| 77 | + | |
| 78 | +int igt_spinner_pin(struct igt_spinner *spin, | |
| 79 | + struct intel_context *ce, | |
| 80 | + struct i915_gem_ww_ctx *ww) | |
| 81 | +{ | |
| 82 | + void *vaddr; | |
| 83 | + | |
| 84 | + if (spin->ce && WARN_ON(spin->ce != ce)) | |
| 85 | + return -ENODEV; | |
| 86 | + spin->ce = ce; | |
| 87 | + | |
| 88 | + if (!spin->seqno) { | |
| 89 | + vaddr = igt_spinner_pin_obj(ce, ww, spin->hws, I915_MAP_WB, &spin->hws_vma); | |
| 90 | + if (IS_ERR(vaddr)) | |
| 91 | + return PTR_ERR(vaddr); | |
| 92 | + | |
| 93 | + spin->seqno = memset(vaddr, 0xff, PAGE_SIZE); | |
| 94 | + } | |
| 95 | + | |
| 96 | + if (!spin->batch) { | |
| 97 | + unsigned int mode = | |
| 98 | + i915_coherent_map_type(spin->gt->i915); | |
| 99 | + | |
| 100 | + vaddr = igt_spinner_pin_obj(ce, ww, spin->obj, mode, &spin->batch_vma); | |
| 101 | + if (IS_ERR(vaddr)) | |
| 102 | + return PTR_ERR(vaddr); | |
| 103 | + | |
| 104 | + spin->batch = vaddr; | |
| 105 | + } | |
| 106 | + | |
| 107 | + return 0; | |
| 108 | +} | |
| 109 | + | |
| 62 | 110 | static unsigned int seqno_offset(u64 fence) |
| 63 | 111 | { |
| 64 | 112 | return offset_in_page(sizeof(u32) * fence); |
| @@ -103,27 +151,18 @@ igt_spinner_create_request(struct igt_spinner *spin, · 38 unmodified lines | ||
| 103 | 151 | if (!intel_engine_can_store_dword(ce->engine)) |
| 104 | 152 | return ERR_PTR(-ENODEV); |
| 105 | 153 | |
| 106 | − vma = i915_vma_instance(spin->obj, ce->vm, NULL); | |
| 107 | − if (IS_ERR(vma)) | |
| 108 | − return ERR_CAST(vma); | |
| 109 | − | |
| 110 | − hws = i915_vma_instance(spin->hws, ce->vm, NULL); | |
| 111 | − if (IS_ERR(hws)) | |
| 112 | − return ERR_CAST(hws); | |
| 154 | + if (!spin->batch) { | |
| 155 | + err = igt_spinner_pin(spin, ce, NULL); | |
| 156 | + if (err) | |
| 157 | + return ERR_PTR(err); | |
| 158 | + } | |
| 113 | 159 | |
| 114 | − err = i915_vma_pin(vma, 0, 0, PIN_USER); | |
| 115 | − if (err) | |
| 116 | − return ERR_PTR(err); | |
| 117 | − | |
| 118 | − err = i915_vma_pin(hws, 0, 0, PIN_USER); | |
| 119 | − if (err) | |
| 120 | − goto unpin_vma; | |
| 160 | + hws = spin->hws_vma; | |
| 161 | + vma = spin->batch_vma; | |
| 121 | 162 | |
| 122 | 163 | rq = intel_context_create_request(ce); |
| 123 | − if (IS_ERR(rq)) { | |
| 124 | − err = PTR_ERR(rq); | |
| 125 | − goto unpin_hws; | |
| 126 | − } | |
| 164 | + if (IS_ERR(rq)) | |
| 165 | + return ERR_CAST(rq); | |
| 127 | 166 | |
| 128 | 167 | err = move_to_active(vma, rq, 0); |
| 129 | 168 | if (err) |
| @@ -186,10 +225,6 @@ cancel_rq: · 56 unmodified lines | ||
| 186 | 225 | i915_request_set_error_once(rq, err); |
| 187 | 226 | i915_request_add(rq); |
| 188 | 227 | } |
| 189 | −unpin_hws: | |
| 190 | − i915_vma_unpin(hws); | |
| 191 | −unpin_vma: | |
| 192 | − i915_vma_unpin(vma); | |
| 193 | 228 | return err ? ERR_PTR(err) : rq; |
| 194 | 229 | } |
| 195 | 230 | |
| @@ -203,6 +238,9 @@ hws_seqno(const struct igt_spinner *spin, const struct i915_request *rq) · 7 unmodified lines | ||
| 203 | 238 | |
| 204 | 239 | void igt_spinner_end(struct igt_spinner *spin) |
| 205 | 240 | { |
| 241 | + if (!spin->batch) | |
| 242 | + return; | |
| 243 | + | |
| 206 | 244 | *spin->batch = MI_BATCH_BUFFER_END; |
| 207 | 245 | intel_gt_chipset_flush(spin->gt); |
| 208 | 246 | } |
| @@ -211,10 +249,16 @@ void igt_spinner_fini(struct igt_spinner *spin) · 2 unmodified lines | ||
| 211 | 249 | { |
| 212 | 250 | igt_spinner_end(spin); |
| 213 | 251 | |
| 214 | − i915_gem_object_unpin_map(spin->obj); | |
| 252 | + if (spin->batch) { | |
| 253 | + i915_vma_unpin(spin->batch_vma); | |
| 254 | + i915_gem_object_unpin_map(spin->obj); | |
| 255 | + } | |
| 215 | 256 | i915_gem_object_put(spin->obj); |
| 216 | 257 | |
| 217 | − i915_gem_object_unpin_map(spin->hws); | |
| 258 | + if (spin->seqno) { | |
| 259 | + i915_vma_unpin(spin->hws_vma); | |
| 260 | + i915_gem_object_unpin_map(spin->hws); | |
| 261 | + } | |
| 218 | 262 | i915_gem_object_put(spin->hws); |
| 219 | 263 | } |
| 220 | 264 | |
| @@ -20,11 +20,16 @@ struct igt_spinner { · 19 unmodified lines | ||
| 20 | 20 | struct intel_gt *gt; |
| 21 | 21 | struct drm_i915_gem_object *hws; |
| 22 | 22 | struct drm_i915_gem_object *obj; |
| 23 | + struct intel_context *ce; | |
| 24 | + struct i915_vma *hws_vma, *batch_vma; | |
| 23 | 25 | u32 *batch; |
| 24 | 26 | void *seqno; |
| 25 | 27 | }; |
| 26 | 28 | |
| 27 | 29 | int igt_spinner_init(struct igt_spinner *spin, struct intel_gt *gt); |
| 30 | +int igt_spinner_pin(struct igt_spinner *spin, | |
| 31 | + struct intel_context *ce, | |
| 32 | + struct i915_gem_ww_ctx *ww); | |
| 28 | 33 | void igt_spinner_fini(struct igt_spinner *spin); |
| 29 | 34 | |
| 30 | 35 | struct i915_request * |
| @@ -31,10 +31,12 @@ static void close_objects(struct intel_memory_region *mem, · 30 unmodified lines | ||
| 31 | 31 | struct drm_i915_gem_object *obj, *on; |
| 32 | 32 | |
| 33 | 33 | list_for_each_entry_safe(obj, on, objects, st_link) { |
| 34 | + i915_gem_object_lock(obj, NULL); | |
| 34 | 35 | if (i915_gem_object_has_pinned_pages(obj)) |
| 35 | 36 | i915_gem_object_unpin_pages(obj); |
| 36 | 37 | /* No polluting the memory region between tests */ |
| 37 | 38 | __i915_gem_object_put_pages(obj); |
| 39 | + i915_gem_object_unlock(obj); | |
| 38 | 40 | list_del(&obj->st_link); |
| 39 | 41 | i915_gem_object_put(obj); |
| 40 | 42 | } |
| @@ -69,7 +71,7 @@ static int igt_mock_fill(void *arg) · 28 unmodified lines | ||
| 69 | 71 | break; |
| 70 | 72 | } |
| 71 | 73 | |
| 72 | − err = i915_gem_object_pin_pages(obj); | |
| 74 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 73 | 75 | if (err) { |
| 74 | 76 | i915_gem_object_put(obj); |
| 75 | 77 | break; |
| @@ -109,7 +111,7 @@ igt_object_create(struct intel_memory_region *mem, · 33 unmodified lines | ||
| 109 | 111 | if (IS_ERR(obj)) |
| 110 | 112 | return obj; |
| 111 | 113 | |
| 112 | − err = i915_gem_object_pin_pages(obj); | |
| 114 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 113 | 115 | if (err) |
| 114 | 116 | goto put; |
| 115 | 117 | |
| @@ -123,8 +125,10 @@ put: · 7 unmodified lines | ||
| 123 | 125 | |
| 124 | 126 | static void igt_object_release(struct drm_i915_gem_object *obj) |
| 125 | 127 | { |
| 128 | + i915_gem_object_lock(obj, NULL); | |
| 126 | 129 | i915_gem_object_unpin_pages(obj); |
| 127 | 130 | __i915_gem_object_put_pages(obj); |
| 131 | + i915_gem_object_unlock(obj); | |
| 128 | 132 | list_del(&obj->st_link); |
| 129 | 133 | i915_gem_object_put(obj); |
| 130 | 134 | } |
| @@ -433,7 +437,7 @@ static int igt_cpu_check(struct drm_i915_gem_object *obj, u32 dword, u32 val) · 302 unmodified lines | ||
| 433 | 437 | if (err) |
| 434 | 438 | return err; |
| 435 | 439 | |
| 436 | − ptr = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 440 | + ptr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 437 | 441 | if (IS_ERR(ptr)) |
| 438 | 442 | return PTR_ERR(ptr); |
| 439 | 443 | |
| @@ -538,7 +542,7 @@ static int igt_lmem_create(void *arg) · 98 unmodified lines | ||
| 538 | 542 | if (IS_ERR(obj)) |
| 539 | 543 | return PTR_ERR(obj); |
| 540 | 544 | |
| 541 | − err = i915_gem_object_pin_pages(obj); | |
| 545 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 542 | 546 | if (err) |
| 543 | 547 | goto out_put; |
| 544 | 548 | |
| @@ -577,7 +581,7 @@ static int igt_lmem_write_gpu(void *arg) · 32 unmodified lines | ||
| 577 | 581 | goto out_file; |
| 578 | 582 | } |
| 579 | 583 | |
| 580 | − err = i915_gem_object_pin_pages(obj); | |
| 584 | + err = i915_gem_object_pin_pages_unlocked(obj); | |
| 581 | 585 | if (err) |
| 582 | 586 | goto out_put; |
| 583 | 587 | |
| @@ -649,7 +653,7 @@ static int igt_lmem_write_cpu(void *arg) · 65 unmodified lines | ||
| 649 | 653 | if (IS_ERR(obj)) |
| 650 | 654 | return PTR_ERR(obj); |
| 651 | 655 | |
| 652 | − vaddr = i915_gem_object_pin_map(obj, I915_MAP_WC); | |
| 656 | + vaddr = i915_gem_object_pin_map_unlocked(obj, I915_MAP_WC); | |
| 653 | 657 | if (IS_ERR(vaddr)) { |
| 654 | 658 | err = PTR_ERR(vaddr); |
| 655 | 659 | goto out_put; |
| @@ -753,7 +757,7 @@ create_region_for_mapping(struct intel_memory_region *mr, u64 size, u32 type, · 97 unmodified lines | ||
| 753 | 757 | return obj; |
| 754 | 758 | } |
| 755 | 759 | |
| 756 | − addr = i915_gem_object_pin_map(obj, type); | |
| 760 | + addr = i915_gem_object_pin_map_unlocked(obj, type); | |
| 757 | 761 | if (IS_ERR(addr)) { |
| 758 | 762 | i915_gem_object_put(obj); |
| 759 | 763 | if (PTR_ERR(addr) == -ENXIO) |
| @@ -27,13 +27,13 @@ static int mock_object_init(struct intel_memory_region *mem, · 26 unmodified lines | ||
| 27 | 27 | return -E2BIG; |
| 28 | 28 | |
| 29 | 29 | drm_gem_private_object_init(&i915->drm, &obj->base, size); |
| 30 | − i915_gem_object_init(obj, &mock_region_obj_ops, &lock_class); | |
| 30 | + i915_gem_object_init(obj, &mock_region_obj_ops, &lock_class, flags); | |
| 31 | 31 | |
| 32 | 32 | obj->read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT; |
| 33 | 33 | |
| 34 | 34 | i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); |
| 35 | 35 | |
| 36 | − i915_gem_object_init_memory_region(obj, mem, flags); | |
| 36 | + i915_gem_object_init_memory_region(obj, mem); | |
| 37 | 37 | |
| 38 | 38 | return 0; |
| 39 | 39 | } |
| @@ -943,6 +943,7 @@ struct drm_i915_gem_exec_object { · 942 unmodified lines | ||
| 943 | 943 | __u64 offset; |
| 944 | 944 | }; |
| 945 | 945 | |
| 946 | +/* DRM_IOCTL_I915_GEM_EXECBUFFER was removed in Linux 5.13 */ | |
| 946 | 947 | struct drm_i915_gem_execbuffer { |
| 947 | 948 | /** |
| 948 | 949 | * List of buffers to be validated with their relocations to be |