aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_gem_tiling.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_tiling.c')
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c112
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 */
388static int
389i915_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
410void
411i915_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
439void
440i915_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}