aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-06-06 04:46:01 -0400
committerEric Anholt <eric@anholt.net>2009-06-18 15:40:50 -0400
commit52dc7d32b88156248167864f77a9026abe27b432 (patch)
tree6323469d7d42ac41ce179221c3d19f2789ccdebd /drivers/gpu/drm
parent8c4b8c3f34de4e2da20df042bba173fe557f8b45 (diff)
drm/i915: Clear fence register on tiling stride change.
The fence register value also depends upon the stride of the object, so we need to clear the fence if that is changed as well. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> [anholt: Added 8xx and 965 paths, and renamed the confusing i915_gem_object_tiling_ok function to i915_gem_object_fence_offset_ok] Signed-off-by: Eric Anholt <eric@anholt.net>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c37
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c67
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);
647void i915_gem_lastclose(struct drm_device *dev); 647void i915_gem_lastclose(struct drm_device *dev);
648uint32_t i915_get_gem_seqno(struct drm_device *dev); 648uint32_t i915_get_gem_seqno(struct drm_device *dev);
649int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); 649int i915_gem_object_get_fence_reg(struct drm_gem_object *obj);
650int i915_gem_object_put_fence_reg(struct drm_gem_object *obj);
650void i915_gem_retire_requests(struct drm_device *dev); 651void i915_gem_retire_requests(struct drm_device *dev);
651void i915_gem_retire_work_handler(struct work_struct *work); 652void i915_gem_retire_work_handler(struct work_struct *work);
652void i915_gem_clflush_object(struct drm_gem_object *obj); 653void 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 */
2338int
2339i915_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 */
2334static int 2369static 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
420static bool
421i915_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; 525err:
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/**