diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gpu_error.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gpu_error.c | 88 |
1 files changed, 63 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; |