aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2018-10-03 04:24:22 -0400
committerRodrigo Vivi <rodrigo.vivi@intel.com>2018-10-03 11:02:42 -0400
commit4c9613ce556fdeb671e779668b627ea3a2b61728 (patch)
tree0b79560066e47e1b1b08f00164883824d77a0dc5
parent4ca8ca9fe7dc792000c3762de5081a4d6dc33667 (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.c88
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.h1
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
235static 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
235static int compress_page(struct compress *c, 249static 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
271static void compress_fini(struct compress *c, 280static 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
303end:
304 memset(zstream->next_out, 0, zstream->avail_out);
305 dst->unused = zstream->avail_out;
306 return 0;
307}
308
309static 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
354static int compress_flush(struct compress *c,
355 struct drm_i915_error_object *dst)
356{
357 return 0;
358}
359
322static void compress_fini(struct compress *c, 360static 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
956unwind: 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
962out:
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];