diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-03-25 13:47:29 -0400 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2012-03-27 07:19:11 -0400 |
commit | dbf7bff074d5fdc87c61b1b41d8e809109cf0bf8 (patch) | |
tree | a0adbbbc73b75dd97b8b134d1c4b289c20f2fa56 | |
parent | e244a443bf72bccb44c75cadf04720101d1f313a (diff) |
drm/i915: merge shmem_pread slow&fast-path
With the previous rewrite, they've become essential identical.
v2: Simplify the page_do_bit17_swizzling logic as suggested by Chris
Wilson.
Tested-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 108 |
1 files changed, 27 insertions, 81 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a2547528a9d4..1855e72859a8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -239,66 +239,6 @@ static int i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj) | |||
239 | obj->tiling_mode != I915_TILING_NONE; | 239 | obj->tiling_mode != I915_TILING_NONE; |
240 | } | 240 | } |
241 | 241 | ||
242 | /** | ||
243 | * This is the fast shmem pread path, which attempts to copy_from_user directly | ||
244 | * from the backing pages of the object to the user's address space. On a | ||
245 | * fault, it fails so we can fall back to i915_gem_shmem_pwrite_slow(). | ||
246 | */ | ||
247 | static int | ||
248 | i915_gem_shmem_pread_fast(struct drm_device *dev, | ||
249 | struct drm_i915_gem_object *obj, | ||
250 | struct drm_i915_gem_pread *args, | ||
251 | struct drm_file *file) | ||
252 | { | ||
253 | struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; | ||
254 | ssize_t remain; | ||
255 | loff_t offset; | ||
256 | char __user *user_data; | ||
257 | int page_offset, page_length; | ||
258 | |||
259 | user_data = (char __user *) (uintptr_t) args->data_ptr; | ||
260 | remain = args->size; | ||
261 | |||
262 | offset = args->offset; | ||
263 | |||
264 | while (remain > 0) { | ||
265 | struct page *page; | ||
266 | char *vaddr; | ||
267 | int ret; | ||
268 | |||
269 | /* Operation in this page | ||
270 | * | ||
271 | * page_offset = offset within page | ||
272 | * page_length = bytes to copy for this page | ||
273 | */ | ||
274 | page_offset = offset_in_page(offset); | ||
275 | page_length = remain; | ||
276 | if ((page_offset + remain) > PAGE_SIZE) | ||
277 | page_length = PAGE_SIZE - page_offset; | ||
278 | |||
279 | page = shmem_read_mapping_page(mapping, offset >> PAGE_SHIFT); | ||
280 | if (IS_ERR(page)) | ||
281 | return PTR_ERR(page); | ||
282 | |||
283 | vaddr = kmap_atomic(page); | ||
284 | ret = __copy_to_user_inatomic(user_data, | ||
285 | vaddr + page_offset, | ||
286 | page_length); | ||
287 | kunmap_atomic(vaddr); | ||
288 | |||
289 | mark_page_accessed(page); | ||
290 | page_cache_release(page); | ||
291 | if (ret) | ||
292 | return -EFAULT; | ||
293 | |||
294 | remain -= page_length; | ||
295 | user_data += page_length; | ||
296 | offset += page_length; | ||
297 | } | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static inline int | 242 | static inline int |
303 | __copy_to_user_swizzled(char __user *cpu_vaddr, | 243 | __copy_to_user_swizzled(char __user *cpu_vaddr, |
304 | const char *gpu_vaddr, int gpu_offset, | 244 | const char *gpu_vaddr, int gpu_offset, |
@@ -351,17 +291,11 @@ __copy_from_user_swizzled(char __user *gpu_vaddr, int gpu_offset, | |||
351 | return 0; | 291 | return 0; |
352 | } | 292 | } |
353 | 293 | ||
354 | /** | ||
355 | * This is the fallback shmem pread path, which allocates temporary storage | ||
356 | * in kernel space to copy_to_user into outside of the struct_mutex, so we | ||
357 | * can copy out of the object's backing pages while holding the struct mutex | ||
358 | * and not take page faults. | ||
359 | */ | ||
360 | static int | 294 | static int |
361 | i915_gem_shmem_pread_slow(struct drm_device *dev, | 295 | i915_gem_shmem_pread(struct drm_device *dev, |
362 | struct drm_i915_gem_object *obj, | 296 | struct drm_i915_gem_object *obj, |
363 | struct drm_i915_gem_pread *args, | 297 | struct drm_i915_gem_pread *args, |
364 | struct drm_file *file) | 298 | struct drm_file *file) |
365 | { | 299 | { |
366 | struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; | 300 | struct address_space *mapping = obj->base.filp->f_path.dentry->d_inode->i_mapping; |
367 | char __user *user_data; | 301 | char __user *user_data; |
@@ -369,6 +303,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, | |||
369 | loff_t offset; | 303 | loff_t offset; |
370 | int shmem_page_offset, page_length, ret = 0; | 304 | int shmem_page_offset, page_length, ret = 0; |
371 | int obj_do_bit17_swizzling, page_do_bit17_swizzling; | 305 | int obj_do_bit17_swizzling, page_do_bit17_swizzling; |
306 | int hit_slowpath = 0; | ||
372 | 307 | ||
373 | user_data = (char __user *) (uintptr_t) args->data_ptr; | 308 | user_data = (char __user *) (uintptr_t) args->data_ptr; |
374 | remain = args->size; | 309 | remain = args->size; |
@@ -377,8 +312,6 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, | |||
377 | 312 | ||
378 | offset = args->offset; | 313 | offset = args->offset; |
379 | 314 | ||
380 | mutex_unlock(&dev->struct_mutex); | ||
381 | |||
382 | while (remain > 0) { | 315 | while (remain > 0) { |
383 | struct page *page; | 316 | struct page *page; |
384 | char *vaddr; | 317 | char *vaddr; |
@@ -402,6 +335,20 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, | |||
402 | page_do_bit17_swizzling = obj_do_bit17_swizzling && | 335 | page_do_bit17_swizzling = obj_do_bit17_swizzling && |
403 | (page_to_phys(page) & (1 << 17)) != 0; | 336 | (page_to_phys(page) & (1 << 17)) != 0; |
404 | 337 | ||
338 | if (!page_do_bit17_swizzling) { | ||
339 | vaddr = kmap_atomic(page); | ||
340 | ret = __copy_to_user_inatomic(user_data, | ||
341 | vaddr + shmem_page_offset, | ||
342 | page_length); | ||
343 | kunmap_atomic(vaddr); | ||
344 | if (ret == 0) | ||
345 | goto next_page; | ||
346 | } | ||
347 | |||
348 | hit_slowpath = 1; | ||
349 | |||
350 | mutex_unlock(&dev->struct_mutex); | ||
351 | |||
405 | vaddr = kmap(page); | 352 | vaddr = kmap(page); |
406 | if (page_do_bit17_swizzling) | 353 | if (page_do_bit17_swizzling) |
407 | ret = __copy_to_user_swizzled(user_data, | 354 | ret = __copy_to_user_swizzled(user_data, |
@@ -413,6 +360,8 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, | |||
413 | page_length); | 360 | page_length); |
414 | kunmap(page); | 361 | kunmap(page); |
415 | 362 | ||
363 | mutex_lock(&dev->struct_mutex); | ||
364 | next_page: | ||
416 | mark_page_accessed(page); | 365 | mark_page_accessed(page); |
417 | page_cache_release(page); | 366 | page_cache_release(page); |
418 | 367 | ||
@@ -427,10 +376,11 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, | |||
427 | } | 376 | } |
428 | 377 | ||
429 | out: | 378 | out: |
430 | mutex_lock(&dev->struct_mutex); | 379 | if (hit_slowpath) { |
431 | /* Fixup: Kill any reinstated backing storage pages */ | 380 | /* Fixup: Kill any reinstated backing storage pages */ |
432 | if (obj->madv == __I915_MADV_PURGED) | 381 | if (obj->madv == __I915_MADV_PURGED) |
433 | i915_gem_object_truncate(obj); | 382 | i915_gem_object_truncate(obj); |
383 | } | ||
434 | 384 | ||
435 | return ret; | 385 | return ret; |
436 | } | 386 | } |
@@ -486,11 +436,7 @@ i915_gem_pread_ioctl(struct drm_device *dev, void *data, | |||
486 | if (ret) | 436 | if (ret) |
487 | goto out; | 437 | goto out; |
488 | 438 | ||
489 | ret = -EFAULT; | 439 | ret = i915_gem_shmem_pread(dev, obj, args, file); |
490 | if (!i915_gem_object_needs_bit17_swizzle(obj)) | ||
491 | ret = i915_gem_shmem_pread_fast(dev, obj, args, file); | ||
492 | if (ret == -EFAULT) | ||
493 | ret = i915_gem_shmem_pread_slow(dev, obj, args, file); | ||
494 | 440 | ||
495 | out: | 441 | out: |
496 | drm_gem_object_unreference(&obj->base); | 442 | drm_gem_object_unreference(&obj->base); |