diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2018-10-03 04:24:22 -0400 |
---|---|---|
committer | Rodrigo Vivi <rodrigo.vivi@intel.com> | 2018-10-03 11:02:42 -0400 |
commit | 4c9613ce556fdeb671e779668b627ea3a2b61728 (patch) | |
tree | 0b79560066e47e1b1b08f00164883824d77a0dc5 | |
parent | 4ca8ca9fe7dc792000c3762de5081a4d6dc33667 (diff) |
drm/i915: Handle incomplete Z_FINISH for compressed error states
The final call to zlib_deflate(Z_FINISH) may require more output
space to be allocated and so needs to re-invoked. Failure to do so in
the current code leads to incomplete zlib streams (albeit intact due to
the use of Z_SYNC_FLUSH) resulting in the occasional short object
capture.
v2: Check against overrunning our pre-allocated page array
v3: Drop Z_SYNC_FLUSH entirely
Testcase: igt/i915-error-capture.js
Fixes: 0a97015d45ee ("drm/i915: Compress GPU objects in error state")
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: <stable@vger.kernel.org> # v4.10+
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181003082422.23214-1-chris@chris-wilson.co.uk
(cherry picked from commit 83bc0f5b432f60394466deef16fc753e27371d0b)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
-rw-r--r-- | drivers/gpu/drm/i915/i915_gpu_error.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gpu_error.h | 1 |
2 files changed, 64 insertions, 25 deletions
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index f7f2aa71d8d9..a262a64f5625 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c | |||
@@ -232,6 +232,20 @@ static bool compress_init(struct compress *c) | |||
232 | return true; | 232 | return true; |
233 | } | 233 | } |
234 | 234 | ||
235 | static void *compress_next_page(struct drm_i915_error_object *dst) | ||
236 | { | ||
237 | unsigned long page; | ||
238 | |||
239 | if (dst->page_count >= dst->num_pages) | ||
240 | return ERR_PTR(-ENOSPC); | ||
241 | |||
242 | page = __get_free_page(GFP_ATOMIC | __GFP_NOWARN); | ||
243 | if (!page) | ||
244 | return ERR_PTR(-ENOMEM); | ||
245 | |||
246 | return dst->pages[dst->page_count++] = (void *)page; | ||
247 | } | ||
248 | |||
235 | static int compress_page(struct compress *c, | 249 | static int compress_page(struct compress *c, |
236 | void *src, | 250 | void *src, |
237 | struct drm_i915_error_object *dst) | 251 | struct drm_i915_error_object *dst) |
@@ -245,19 +259,14 @@ static int compress_page(struct compress *c, | |||
245 | 259 | ||
246 | do { | 260 | do { |
247 | if (zstream->avail_out == 0) { | 261 | if (zstream->avail_out == 0) { |
248 | unsigned long page; | 262 | zstream->next_out = compress_next_page(dst); |
249 | 263 | if (IS_ERR(zstream->next_out)) | |
250 | page = __get_free_page(GFP_ATOMIC | __GFP_NOWARN); | 264 | return PTR_ERR(zstream->next_out); |
251 | if (!page) | ||
252 | return -ENOMEM; | ||
253 | 265 | ||
254 | dst->pages[dst->page_count++] = (void *)page; | ||
255 | |||
256 | zstream->next_out = (void *)page; | ||
257 | zstream->avail_out = PAGE_SIZE; | 266 | zstream->avail_out = PAGE_SIZE; |
258 | } | 267 | } |
259 | 268 | ||
260 | if (zlib_deflate(zstream, Z_SYNC_FLUSH) != Z_OK) | 269 | if (zlib_deflate(zstream, Z_NO_FLUSH) != Z_OK) |
261 | return -EIO; | 270 | return -EIO; |
262 | } while (zstream->avail_in); | 271 | } while (zstream->avail_in); |
263 | 272 | ||
@@ -268,19 +277,42 @@ static int compress_page(struct compress *c, | |||
268 | return 0; | 277 | return 0; |
269 | } | 278 | } |
270 | 279 | ||
271 | static void compress_fini(struct compress *c, | 280 | static int compress_flush(struct compress *c, |
272 | struct drm_i915_error_object *dst) | 281 | struct drm_i915_error_object *dst) |
273 | { | 282 | { |
274 | struct z_stream_s *zstream = &c->zstream; | 283 | struct z_stream_s *zstream = &c->zstream; |
275 | 284 | ||
276 | if (dst) { | 285 | do { |
277 | zlib_deflate(zstream, Z_FINISH); | 286 | switch (zlib_deflate(zstream, Z_FINISH)) { |
278 | dst->unused = zstream->avail_out; | 287 | case Z_OK: /* more space requested */ |
279 | } | 288 | zstream->next_out = compress_next_page(dst); |
289 | if (IS_ERR(zstream->next_out)) | ||
290 | return PTR_ERR(zstream->next_out); | ||
291 | |||
292 | zstream->avail_out = PAGE_SIZE; | ||
293 | break; | ||
294 | |||
295 | case Z_STREAM_END: | ||
296 | goto end; | ||
297 | |||
298 | default: /* any error */ | ||
299 | return -EIO; | ||
300 | } | ||
301 | } while (1); | ||
302 | |||
303 | end: | ||
304 | memset(zstream->next_out, 0, zstream->avail_out); | ||
305 | dst->unused = zstream->avail_out; | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static void compress_fini(struct compress *c, | ||
310 | struct drm_i915_error_object *dst) | ||
311 | { | ||
312 | struct z_stream_s *zstream = &c->zstream; | ||
280 | 313 | ||
281 | zlib_deflateEnd(zstream); | 314 | zlib_deflateEnd(zstream); |
282 | kfree(zstream->workspace); | 315 | kfree(zstream->workspace); |
283 | |||
284 | if (c->tmp) | 316 | if (c->tmp) |
285 | free_page((unsigned long)c->tmp); | 317 | free_page((unsigned long)c->tmp); |
286 | } | 318 | } |
@@ -319,6 +351,12 @@ static int compress_page(struct compress *c, | |||
319 | return 0; | 351 | return 0; |
320 | } | 352 | } |
321 | 353 | ||
354 | static int compress_flush(struct compress *c, | ||
355 | struct drm_i915_error_object *dst) | ||
356 | { | ||
357 | return 0; | ||
358 | } | ||
359 | |||
322 | static void compress_fini(struct compress *c, | 360 | static void compress_fini(struct compress *c, |
323 | struct drm_i915_error_object *dst) | 361 | struct drm_i915_error_object *dst) |
324 | { | 362 | { |
@@ -917,6 +955,7 @@ i915_error_object_create(struct drm_i915_private *i915, | |||
917 | unsigned long num_pages; | 955 | unsigned long num_pages; |
918 | struct sgt_iter iter; | 956 | struct sgt_iter iter; |
919 | dma_addr_t dma; | 957 | dma_addr_t dma; |
958 | int ret; | ||
920 | 959 | ||
921 | if (!vma) | 960 | if (!vma) |
922 | return NULL; | 961 | return NULL; |
@@ -930,6 +969,7 @@ i915_error_object_create(struct drm_i915_private *i915, | |||
930 | 969 | ||
931 | dst->gtt_offset = vma->node.start; | 970 | dst->gtt_offset = vma->node.start; |
932 | dst->gtt_size = vma->node.size; | 971 | dst->gtt_size = vma->node.size; |
972 | dst->num_pages = num_pages; | ||
933 | dst->page_count = 0; | 973 | dst->page_count = 0; |
934 | dst->unused = 0; | 974 | dst->unused = 0; |
935 | 975 | ||
@@ -938,28 +978,26 @@ i915_error_object_create(struct drm_i915_private *i915, | |||
938 | return NULL; | 978 | return NULL; |
939 | } | 979 | } |
940 | 980 | ||
981 | ret = -EINVAL; | ||
941 | for_each_sgt_dma(dma, iter, vma->pages) { | 982 | for_each_sgt_dma(dma, iter, vma->pages) { |
942 | void __iomem *s; | 983 | void __iomem *s; |
943 | int ret; | ||
944 | 984 | ||
945 | ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0); | 985 | ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0); |
946 | 986 | ||
947 | s = io_mapping_map_atomic_wc(&ggtt->iomap, slot); | 987 | s = io_mapping_map_atomic_wc(&ggtt->iomap, slot); |
948 | ret = compress_page(&compress, (void __force *)s, dst); | 988 | ret = compress_page(&compress, (void __force *)s, dst); |
949 | io_mapping_unmap_atomic(s); | 989 | io_mapping_unmap_atomic(s); |
950 | |||
951 | if (ret) | 990 | if (ret) |
952 | goto unwind; | 991 | break; |
953 | } | 992 | } |
954 | goto out; | ||
955 | 993 | ||
956 | unwind: | 994 | if (ret || compress_flush(&compress, dst)) { |
957 | while (dst->page_count--) | 995 | while (dst->page_count--) |
958 | free_page((unsigned long)dst->pages[dst->page_count]); | 996 | free_page((unsigned long)dst->pages[dst->page_count]); |
959 | kfree(dst); | 997 | kfree(dst); |
960 | dst = NULL; | 998 | dst = NULL; |
999 | } | ||
961 | 1000 | ||
962 | out: | ||
963 | compress_fini(&compress, dst); | 1001 | compress_fini(&compress, dst); |
964 | ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); | 1002 | ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); |
965 | return dst; | 1003 | return dst; |
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h index f893a4e8b783..8710fb18ed74 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.h +++ b/drivers/gpu/drm/i915/i915_gpu_error.h | |||
@@ -135,6 +135,7 @@ struct i915_gpu_state { | |||
135 | struct drm_i915_error_object { | 135 | struct drm_i915_error_object { |
136 | u64 gtt_offset; | 136 | u64 gtt_offset; |
137 | u64 gtt_size; | 137 | u64 gtt_size; |
138 | int num_pages; | ||
138 | int page_count; | 139 | int page_count; |
139 | int unused; | 140 | int unused; |
140 | u32 *pages[0]; | 141 | u32 *pages[0]; |