diff options
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r-- | drivers/gpu/drm/i915/i915_drv.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 37 | ||||
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_tiling.c | 67 |
3 files changed, 88 insertions, 17 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 451b547352b7..7a84f04e8439 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -647,6 +647,7 @@ int i915_gem_object_unbind(struct drm_gem_object *obj); | |||
647 | void i915_gem_lastclose(struct drm_device *dev); | 647 | void i915_gem_lastclose(struct drm_device *dev); |
648 | uint32_t i915_get_gem_seqno(struct drm_device *dev); | 648 | uint32_t i915_get_gem_seqno(struct drm_device *dev); |
649 | int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); | 649 | int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); |
650 | int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); | ||
650 | void i915_gem_retire_requests(struct drm_device *dev); | 651 | void i915_gem_retire_requests(struct drm_device *dev); |
651 | void i915_gem_retire_work_handler(struct work_struct *work); | 652 | void i915_gem_retire_work_handler(struct work_struct *work); |
652 | void i915_gem_clflush_object(struct drm_gem_object *obj); | 653 | void i915_gem_clflush_object(struct drm_gem_object *obj); |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4f345414fe7c..174aef2d6481 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -2162,7 +2162,6 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) | |||
2162 | val |= I830_FENCE_REG_VALID; | 2162 | val |= I830_FENCE_REG_VALID; |
2163 | 2163 | ||
2164 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); | 2164 | I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); |
2165 | |||
2166 | } | 2165 | } |
2167 | 2166 | ||
2168 | /** | 2167 | /** |
@@ -2329,6 +2328,42 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) | |||
2329 | } | 2328 | } |
2330 | 2329 | ||
2331 | /** | 2330 | /** |
2331 | * i915_gem_object_put_fence_reg - waits on outstanding fenced access | ||
2332 | * to the buffer to finish, and then resets the fence register. | ||
2333 | * @obj: tiled object holding a fence register. | ||
2334 | * | ||
2335 | * Zeroes out the fence register itself and clears out the associated | ||
2336 | * data structures in dev_priv and obj_priv. | ||
2337 | */ | ||
2338 | int | ||
2339 | i915_gem_object_put_fence_reg(struct drm_gem_object *obj) | ||
2340 | { | ||
2341 | struct drm_device *dev = obj->dev; | ||
2342 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
2343 | |||
2344 | if (obj_priv->fence_reg == I915_FENCE_REG_NONE) | ||
2345 | return 0; | ||
2346 | |||
2347 | /* On the i915, GPU access to tiled buffers is via a fence, | ||
2348 | * therefore we must wait for any outstanding access to complete | ||
2349 | * before clearing the fence. | ||
2350 | */ | ||
2351 | if (!IS_I965G(dev)) { | ||
2352 | int ret; | ||
2353 | |||
2354 | i915_gem_object_flush_gpu_write_domain(obj); | ||
2355 | i915_gem_object_flush_gtt_write_domain(obj); | ||
2356 | ret = i915_gem_object_wait_rendering(obj); | ||
2357 | if (ret != 0) | ||
2358 | return ret; | ||
2359 | } | ||
2360 | |||
2361 | i915_gem_clear_fence_reg (obj); | ||
2362 | |||
2363 | return 0; | ||
2364 | } | ||
2365 | |||
2366 | /** | ||
2332 | * Finds free space in the GTT aperture and binds the object there. | 2367 | * Finds free space in the GTT aperture and binds the object there. |
2333 | */ | 2368 | */ |
2334 | static int | 2369 | static int |
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 9a05cadaa4ad..5c1ceec49f5b 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c | |||
@@ -408,7 +408,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) | |||
408 | if (stride & (stride - 1)) | 408 | if (stride & (stride - 1)) |
409 | return false; | 409 | return false; |
410 | 410 | ||
411 | /* We don't handle the aperture area covered by the fence being bigger | 411 | /* We don't 0handle the aperture area covered by the fence being bigger |
412 | * than the object size. | 412 | * than the object size. |
413 | */ | 413 | */ |
414 | if (i915_get_fence_size(dev, size) != size) | 414 | if (i915_get_fence_size(dev, size) != size) |
@@ -417,6 +417,33 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) | |||
417 | return true; | 417 | return true; |
418 | } | 418 | } |
419 | 419 | ||
420 | static bool | ||
421 | i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) | ||
422 | { | ||
423 | struct drm_device *dev = obj->dev; | ||
424 | struct drm_i915_gem_object *obj_priv = obj->driver_private; | ||
425 | |||
426 | if (obj_priv->gtt_space == NULL) | ||
427 | return true; | ||
428 | |||
429 | if (tiling_mode == I915_TILING_NONE) | ||
430 | return true; | ||
431 | |||
432 | if (!IS_I965G(dev)) { | ||
433 | if (obj_priv->gtt_offset & (obj->size - 1)) | ||
434 | return false; | ||
435 | if (IS_I9XX(dev)) { | ||
436 | if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) | ||
437 | return false; | ||
438 | } else { | ||
439 | if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) | ||
440 | return false; | ||
441 | } | ||
442 | } | ||
443 | |||
444 | return true; | ||
445 | } | ||
446 | |||
420 | /** | 447 | /** |
421 | * Sets the tiling mode of an object, returning the required swizzling of | 448 | * Sets the tiling mode of an object, returning the required swizzling of |
422 | * bit 6 of addresses in the object. | 449 | * bit 6 of addresses in the object. |
@@ -429,6 +456,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, | |||
429 | drm_i915_private_t *dev_priv = dev->dev_private; | 456 | drm_i915_private_t *dev_priv = dev->dev_private; |
430 | struct drm_gem_object *obj; | 457 | struct drm_gem_object *obj; |
431 | struct drm_i915_gem_object *obj_priv; | 458 | struct drm_i915_gem_object *obj_priv; |
459 | int ret = 0; | ||
432 | 460 | ||
433 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); | 461 | obj = drm_gem_object_lookup(dev, file_priv, args->handle); |
434 | if (obj == NULL) | 462 | if (obj == NULL) |
@@ -436,14 +464,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, | |||
436 | obj_priv = obj->driver_private; | 464 | obj_priv = obj->driver_private; |
437 | 465 | ||
438 | if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) { | 466 | if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) { |
467 | mutex_lock(&dev->struct_mutex); | ||
439 | drm_gem_object_unreference(obj); | 468 | drm_gem_object_unreference(obj); |
469 | mutex_unlock(&dev->struct_mutex); | ||
440 | return -EINVAL; | 470 | return -EINVAL; |
441 | } | 471 | } |
442 | 472 | ||
443 | mutex_lock(&dev->struct_mutex); | ||
444 | |||
445 | if (args->tiling_mode == I915_TILING_NONE) { | 473 | if (args->tiling_mode == I915_TILING_NONE) { |
446 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; | 474 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; |
475 | args->stride = 0; | ||
447 | } else { | 476 | } else { |
448 | if (args->tiling_mode == I915_TILING_X) | 477 | if (args->tiling_mode == I915_TILING_X) |
449 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; | 478 | args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; |
@@ -466,32 +495,38 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, | |||
466 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { | 495 | if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { |
467 | args->tiling_mode = I915_TILING_NONE; | 496 | args->tiling_mode = I915_TILING_NONE; |
468 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; | 497 | args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; |
498 | args->stride = 0; | ||
469 | } | 499 | } |
470 | } | 500 | } |
471 | if (args->tiling_mode != obj_priv->tiling_mode) { | ||
472 | int ret; | ||
473 | 501 | ||
474 | /* Unbind the object, as switching tiling means we're | 502 | mutex_lock(&dev->struct_mutex); |
475 | * switching the cache organization due to fencing, probably. | 503 | if (args->tiling_mode != obj_priv->tiling_mode || |
504 | args->stride != obj_priv->stride) { | ||
505 | /* We need to rebind the object if its current allocation | ||
506 | * no longer meets the alignment restrictions for its new | ||
507 | * tiling mode. Otherwise we can just leave it alone, but | ||
508 | * need to ensure that any fence register is cleared. | ||
476 | */ | 509 | */ |
477 | ret = i915_gem_object_unbind(obj); | 510 | if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode)) |
511 | ret = i915_gem_object_unbind(obj); | ||
512 | else | ||
513 | ret = i915_gem_object_put_fence_reg(obj); | ||
478 | if (ret != 0) { | 514 | if (ret != 0) { |
479 | WARN(ret != -ERESTARTSYS, | 515 | WARN(ret != -ERESTARTSYS, |
480 | "failed to unbind object for tiling switch"); | 516 | "failed to reset object for tiling switch"); |
481 | args->tiling_mode = obj_priv->tiling_mode; | 517 | args->tiling_mode = obj_priv->tiling_mode; |
482 | mutex_unlock(&dev->struct_mutex); | 518 | args->stride = obj_priv->stride; |
483 | drm_gem_object_unreference(obj); | 519 | goto err; |
484 | |||
485 | return ret; | ||
486 | } | 520 | } |
521 | |||
487 | obj_priv->tiling_mode = args->tiling_mode; | 522 | obj_priv->tiling_mode = args->tiling_mode; |
523 | obj_priv->stride = args->stride; | ||
488 | } | 524 | } |
489 | obj_priv->stride = args->stride; | 525 | err: |
490 | |||
491 | drm_gem_object_unreference(obj); | 526 | drm_gem_object_unreference(obj); |
492 | mutex_unlock(&dev->struct_mutex); | 527 | mutex_unlock(&dev->struct_mutex); |
493 | 528 | ||
494 | return 0; | 529 | return ret; |
495 | } | 530 | } |
496 | 531 | ||
497 | /** | 532 | /** |