diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_tiling.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_tiling.c | 112 |
1 files changed, 109 insertions, 3 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 6be3f927c86a..52a059354e83 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c | |||
@@ -25,6 +25,8 @@ | |||
25 | * | 25 | * |
26 | */ | 26 | */ |
27 | 27 | ||
28 | #include "linux/string.h" | ||
29 | #include "linux/bitops.h" | ||
28 | #include "drmP.h" | 30 | #include "drmP.h" |
29 | #include "drm.h" | 31 | #include "drm.h" |
30 | #include "i915_drm.h" | 32 | #include "i915_drm.h" |
@@ -127,8 +129,8 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) | |||
127 | swizzle_y = I915_BIT_6_SWIZZLE_9_11; | 129 | swizzle_y = I915_BIT_6_SWIZZLE_9_11; |
128 | } else { | 130 | } else { |
129 | /* Bit 17 swizzling by the CPU in addition. */ | 131 | /* Bit 17 swizzling by the CPU in addition. */ |
130 | swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; | 132 | swizzle_x = I915_BIT_6_SWIZZLE_9_10_17; |
131 | swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; | 133 | swizzle_y = I915_BIT_6_SWIZZLE_9_17; |
132 | } | 134 | } |
133 | break; | 135 | break; |
134 | } | 136 | } |
@@ -281,13 +283,25 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, | |||
281 | mutex_lock(&dev->struct_mutex); | 283 | mutex_lock(&dev->struct_mutex); |
282 | 284 | ||
283 | if (args->tiling_mode == I915_TILING_NONE) { | 285 | if (args->tiling_mode == I915_TILING_NONE) { |
284 | obj_priv->tiling_mode = I915_TILING_NONE; | ||
285 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; | 286 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; |
286 | } else { | 287 | } else { |
287 | if (args->tiling_mode == I915_TILING_X) | 288 | if (args->tiling_mode == I915_TILING_X) |
288 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; | 289 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; |
289 | else | 290 | else |
290 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y; | 291 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_y; |
292 | |||
293 | /* Hide bit 17 swizzling from the user. This prevents old Mesa | ||
294 | * from aborting the application on sw fallbacks to bit 17, | ||
295 | * and we use the pread/pwrite bit17 paths to swizzle for it. | ||
296 | * If there was a user that was relying on the swizzle | ||
297 | * information for drm_intel_bo_map()ed reads/writes this would | ||
298 | * break it, but we don't have any of those. | ||
299 | */ | ||
300 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17) | ||
301 | args->swizzle_mode = I915_BIT_6_SWIZZLE_9; | ||
302 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17) | ||
303 | args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10; | ||
304 | |||
291 | /* If we can't handle the swizzling, make it untiled. */ | 305 | /* If we can't handle the swizzling, make it untiled. */ |
292 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { | 306 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { |
293 | args->tiling_mode = I915_TILING_NONE; | 307 | args->tiling_mode = I915_TILING_NONE; |
@@ -354,8 +368,100 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, | |||
354 | DRM_ERROR("unknown tiling mode\n"); | 368 | DRM_ERROR("unknown tiling mode\n"); |
355 | } | 369 | } |
356 | 370 | ||
371 | /* Hide bit 17 from the user -- see comment in i915_gem_set_tiling */ | ||
372 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_17) | ||
373 | args->swizzle_mode = I915_BIT_6_SWIZZLE_9; | ||
374 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_9_10_17) | ||
375 | args->swizzle_mode = I915_BIT_6_SWIZZLE_9_10; | ||
376 | |||
357 | drm_gem_object_unreference(obj); | 377 | drm_gem_object_unreference(obj); |
358 | mutex_unlock(&dev->struct_mutex); | 378 | mutex_unlock(&dev->struct_mutex); |
359 | 379 | ||
360 | return 0; | 380 | return 0; |
361 | } | 381 | } |
382 | |||
383 | /** | ||
384 | * Swap every 64 bytes of this page around, to account for it having a new | ||
385 | * bit 17 of its physical address and therefore being interpreted differently | ||
386 | * by the GPU. | ||
387 | */ | ||
388 | static int | ||
389 | i915_gem_swizzle_page(struct page *page) | ||
390 | { | ||
391 | char *vaddr; | ||
392 | int i; | ||
393 | char temp[64]; | ||
394 | |||
395 | vaddr = kmap(page); | ||
396 | if (vaddr == NULL) | ||
397 | return -ENOMEM; | ||
398 | |||
399 | for (i = 0; i < PAGE_SIZE; i += 128) { | ||
400 | memcpy(temp, &vaddr[i], 64); | ||
401 | memcpy(&vaddr[i], &vaddr[i + 64], 64); | ||
402 | memcpy(&vaddr[i + 64], temp, 64); | ||
403 | } | ||
404 | |||
405 | kunmap(page); | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | void | ||
411 | i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj) | ||
412 | { | ||
413 | struct drm_device *dev = obj->dev; | ||
414 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
415 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
416 | int page_count = obj->size >> PAGE_SHIFT; | ||
417 | int i; | ||
418 | |||
419 | if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17) | ||
420 | return; | ||
421 | |||
422 | if (obj_priv->bit_17 == NULL) | ||
423 | return; | ||
424 | |||
425 | for (i = 0; i < page_count; i++) { | ||
426 | char new_bit_17 = page_to_phys(obj_priv->pages[i]) >> 17; | ||
427 | if ((new_bit_17 & 0x1) != | ||
428 | (test_bit(i, obj_priv->bit_17) != 0)) { | ||
429 | int ret = i915_gem_swizzle_page(obj_priv->pages[i]); | ||
430 | if (ret != 0) { | ||
431 | DRM_ERROR("Failed to swizzle page\n"); | ||
432 | return; | ||
433 | } | ||
434 | set_page_dirty(obj_priv->pages[i]); | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | |||
439 | void | ||
440 | i915_gem_object_save_bit_17_swizzle(struct drm_gem_object *obj) | ||
441 | { | ||
442 | struct drm_device *dev = obj->dev; | ||
443 | drm_i915_private_t *dev_priv = dev->dev_private; | ||
444 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
445 | int page_count = obj->size >> PAGE_SHIFT; | ||
446 | int i; | ||
447 | |||
448 | if (dev_priv->mm.bit_6_swizzle_x != I915_BIT_6_SWIZZLE_9_10_17) | ||
449 | return; | ||
450 | |||
451 | if (obj_priv->bit_17 == NULL) { | ||
452 | obj_priv->bit_17 = kmalloc(BITS_TO_LONGS(page_count) * | ||
453 | sizeof(long), GFP_KERNEL); | ||
454 | if (obj_priv->bit_17 == NULL) { | ||
455 | DRM_ERROR("Failed to allocate memory for bit 17 " | ||
456 | "record\n"); | ||
457 | return; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | for (i = 0; i < page_count; i++) { | ||
462 | if (page_to_phys(obj_priv->pages[i]) & (1 << 17)) | ||
463 | __set_bit(i, obj_priv->bit_17); | ||
464 | else | ||
465 | __clear_bit(i, obj_priv->bit_17); | ||
466 | } | ||
467 | } | ||