bool interruptible);
static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
unsigned alignment,
- bool mappable,
- bool need_fence);
+ bool map_and_fenceable);
static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
struct drm_i915_gem_pwrite *args,
else if (obj_priv->tiling_mode == I915_TILING_NONE &&
obj_priv->gtt_space &&
obj->write_domain != I915_GEM_DOMAIN_CPU) {
- ret = i915_gem_object_pin(obj, 0, true, false);
+ ret = i915_gem_object_pin(obj, 0, true);
if (ret)
goto out;
BUG_ON(obj_priv->pin_count && !obj_priv->pin_mappable);
if (obj_priv->gtt_space) {
- if (!obj_priv->mappable ||
- (obj_priv->tiling_mode && !obj_priv->fenceable)) {
+ if (!obj_priv->map_and_fenceable) {
ret = i915_gem_object_unbind(obj);
if (ret)
goto unlock;
}
if (!obj_priv->gtt_space) {
- ret = i915_gem_object_bind_to_gtt(obj, 0,
- true, obj_priv->tiling_mode);
+ ret = i915_gem_object_bind_to_gtt(obj, 0, true);
if (ret)
goto unlock;
}
mutex_unlock(&dev->struct_mutex);
switch (ret) {
+ case -EAGAIN:
+ set_need_resched();
case 0:
case -ERESTARTSYS:
return VM_FAULT_NOPAGE;
case -ENOMEM:
- case -EAGAIN:
return VM_FAULT_OOM;
default:
return VM_FAULT_SIGBUS;
* @obj: object to check
*
* Return the required GTT alignment for an object, taking into account
- * potential fence register mapping if needed.
+ * potential fence register mapping.
*/
static uint32_t
i915_gem_get_gtt_alignment(struct drm_i915_gem_object *obj_priv)
return i915_gem_get_gtt_size(obj_priv);
}
+/**
+ * i915_gem_get_unfenced_gtt_alignment - return required GTT alignment for an
+ * unfenced object
+ * @obj: object to check
+ *
+ * Return the required GTT alignment for an object, only taking into account
+ * unfenced tiled surface requirements.
+ */
+static uint32_t
+i915_gem_get_unfenced_gtt_alignment(struct drm_i915_gem_object *obj_priv)
+{
+ struct drm_device *dev = obj_priv->base.dev;
+ int tile_height;
+
+ /*
+ * Minimum alignment is 4k (GTT page size) for sane hw.
+ */
+ if (INTEL_INFO(dev)->gen >= 4 || IS_G33(dev) ||
+ obj_priv->tiling_mode == I915_TILING_NONE)
+ return 4096;
+
+ /*
+ * Older chips need unfenced tiled buffers to be aligned to the left
+ * edge of an even tile row (where tile rows are counted as if the bo is
+ * placed in a fenced gtt region).
+ */
+ if (IS_GEN2(dev) ||
+ (obj_priv->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)))
+ tile_height = 32;
+ else
+ tile_height = 8;
+
+ return tile_height * obj_priv->stride * 2;
+}
+
static uint32_t
i915_gem_get_gtt_size(struct drm_i915_gem_object *obj_priv)
{
struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
-
- ring->outstanding_lazy_request = true;
- return dev_priv->next_seqno;
+ return ring->outstanding_lazy_request = dev_priv->next_seqno;
}
static void
if (atomic_read(&dev_priv->mm.wedged))
return -EAGAIN;
- if (ring->outstanding_lazy_request) {
+ if (seqno == ring->outstanding_lazy_request) {
struct drm_i915_gem_request *request;
request = kzalloc(sizeof(*request), GFP_KERNEL);
seqno = request->seqno;
}
- BUG_ON(seqno == dev_priv->next_seqno);
if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
if (HAS_PCH_SPLIT(dev))
i915_gem_info_remove_gtt(dev_priv, obj_priv);
list_del_init(&obj_priv->mm_list);
- obj_priv->fenceable = true;
- obj_priv->mappable = true;
+ /* Avoid an unnecessary call to unbind on rebind. */
+ obj_priv->map_and_fenceable = true;
drm_mm_put_block(obj_priv->gtt_space);
obj_priv->gtt_space = NULL;
static int i915_ring_idle(struct drm_device *dev,
struct intel_ring_buffer *ring)
{
- if (list_empty(&ring->gpu_write_list))
+ if (list_empty(&ring->gpu_write_list) && list_empty(&ring->active_list))
return 0;
i915_gem_flush_ring(dev, NULL, ring,
int ret;
lists_empty = (list_empty(&dev_priv->mm.flushing_list) &&
- list_empty(&dev_priv->render_ring.active_list) &&
- list_empty(&dev_priv->bsd_ring.active_list) &&
- list_empty(&dev_priv->blt_ring.active_list));
+ list_empty(&dev_priv->mm.active_list));
if (lists_empty)
return 0;
if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
(obj_priv->gtt_offset & (size - 1))) {
WARN(1, "%s: object 0x%08x [fenceable? %d] not 1M or size (0x%08x) aligned [gtt_space offset=%lx, size=%lx]\n",
- __func__, obj_priv->gtt_offset, obj_priv->fenceable, size,
+ __func__, obj_priv->gtt_offset, obj_priv->map_and_fenceable, size,
obj_priv->gtt_space->start, obj_priv->gtt_space->size);
return;
}
static int
i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
unsigned alignment,
- bool mappable,
- bool need_fence)
+ bool map_and_fenceable)
{
struct drm_device *dev = obj->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
struct drm_mm_node *free_space;
gfp_t gfpmask = __GFP_NORETRY | __GFP_NOWARN;
- u32 size, fence_size, fence_alignment;
+ u32 size, fence_size, fence_alignment, unfenced_alignment;
+ bool mappable, fenceable;
int ret;
if (obj_priv->madv != I915_MADV_WILLNEED) {
fence_size = i915_gem_get_gtt_size(obj_priv);
fence_alignment = i915_gem_get_gtt_alignment(obj_priv);
+ unfenced_alignment = i915_gem_get_unfenced_gtt_alignment(obj_priv);
if (alignment == 0)
- alignment = need_fence ? fence_alignment : 4096;
- if (need_fence && alignment & (fence_alignment - 1)) {
+ alignment = map_and_fenceable ? fence_alignment :
+ unfenced_alignment;
+ if (map_and_fenceable && alignment & (fence_alignment - 1)) {
DRM_ERROR("Invalid object alignment requested %u\n", alignment);
return -EINVAL;
}
- size = need_fence ? fence_size : obj->size;
+ size = map_and_fenceable ? fence_size : obj->size;
/* If the object is bigger than the entire aperture, reject it early
* before evicting everything in a vain attempt to find space.
*/
if (obj->size >
- (mappable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) {
+ (map_and_fenceable ? dev_priv->mm.gtt_mappable_end : dev_priv->mm.gtt_total)) {
DRM_ERROR("Attempting to bind an object larger than the aperture\n");
return -E2BIG;
}
search_free:
- if (mappable)
+ if (map_and_fenceable)
free_space =
drm_mm_search_free_in_range(&dev_priv->mm.gtt_space,
size, alignment, 0,
size, alignment, 0);
if (free_space != NULL) {
- if (mappable)
+ if (map_and_fenceable)
obj_priv->gtt_space =
drm_mm_get_block_range_generic(free_space,
size, alignment, 0,
/* If the gtt is empty and we're still having trouble
* fitting our object in, we're out of memory.
*/
- ret = i915_gem_evict_something(dev, size, alignment, mappable);
+ ret = i915_gem_evict_something(dev, size, alignment,
+ map_and_fenceable);
if (ret)
return ret;
if (ret == -ENOMEM) {
/* first try to clear up some space from the GTT */
ret = i915_gem_evict_something(dev, size,
- alignment, mappable);
+ alignment,
+ map_and_fenceable);
if (ret) {
/* now try to shrink everyone else */
if (gfpmask) {
obj_priv->gtt_space = NULL;
ret = i915_gem_evict_something(dev, size,
- alignment, mappable);
+ alignment, map_and_fenceable);
if (ret)
return ret;
BUG_ON(obj->read_domains & I915_GEM_GPU_DOMAINS);
BUG_ON(obj->write_domain & I915_GEM_GPU_DOMAINS);
- trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, mappable);
+ trace_i915_gem_object_bind(obj, obj_priv->gtt_offset, map_and_fenceable);
- obj_priv->fenceable =
+ fenceable =
obj_priv->gtt_space->size == fence_size &&
(obj_priv->gtt_space->start & (fence_alignment -1)) == 0;
- obj_priv->mappable =
+ mappable =
obj_priv->gtt_offset + obj->size <= dev_priv->mm.gtt_mappable_end;
+ obj_priv->map_and_fenceable = mappable && fenceable;
+
return 0;
}
return 0;
}
+int
+i915_gem_object_flush_gpu(struct drm_i915_gem_object *obj,
+ bool interruptible)
+{
+ if (!obj->active)
+ return 0;
+
+ if (obj->base.write_domain & I915_GEM_GPU_DOMAINS)
+ i915_gem_flush_ring(obj->base.dev, NULL, obj->ring,
+ 0, obj->base.write_domain);
+
+ return i915_gem_object_wait_rendering(&obj->base, interruptible);
+}
+
/**
* Moves a single object to the CPU read, and possibly write domain.
*
entry->relocation_count ? true : need_fence;
/* Check fence reg constraints and rebind if necessary */
- if ((need_fence && !obj->fenceable) ||
- (need_mappable && !obj->mappable)) {
+ if (need_mappable && !obj->map_and_fenceable) {
ret = i915_gem_object_unbind(&obj->base);
if (ret)
break;
ret = i915_gem_object_pin(&obj->base,
entry->alignment,
- need_mappable,
- need_fence);
+ need_mappable);
if (ret)
break;
i915_retire_commands(dev, ring);
if (i915_add_request(dev, file, request, ring))
- ring->outstanding_lazy_request = true;
+ i915_gem_next_request_seqno(dev, ring);
else
request = NULL;
int
i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment,
- bool mappable, bool need_fence)
+ bool map_and_fenceable)
{
struct drm_device *dev = obj->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
+ BUG_ON(map_and_fenceable && !map_and_fenceable);
WARN_ON(i915_verify_lists(dev));
if (obj_priv->gtt_space != NULL) {
if ((alignment && obj_priv->gtt_offset & (alignment - 1)) ||
- (need_fence && !obj_priv->fenceable) ||
- (mappable && !obj_priv->mappable)) {
+ (map_and_fenceable && !obj_priv->map_and_fenceable)) {
WARN(obj_priv->pin_count,
"bo is already pinned with incorrect alignment:"
- " offset=%x, req.alignment=%x, need_fence=%d, fenceable=%d, mappable=%d, cpu_accessible=%d\n",
+ " offset=%x, req.alignment=%x, req.map_and_fenceable=%d,"
+ " obj->map_and_fenceable=%d\n",
obj_priv->gtt_offset, alignment,
- need_fence, obj_priv->fenceable,
- mappable, obj_priv->mappable);
+ map_and_fenceable,
+ obj_priv->map_and_fenceable);
ret = i915_gem_object_unbind(obj);
if (ret)
return ret;
if (obj_priv->gtt_space == NULL) {
ret = i915_gem_object_bind_to_gtt(obj, alignment,
- mappable, need_fence);
+ map_and_fenceable);
if (ret)
return ret;
}
if (obj_priv->pin_count++ == 0) {
- i915_gem_info_add_pin(dev_priv, obj_priv, mappable);
+ i915_gem_info_add_pin(dev_priv, obj_priv, map_and_fenceable);
if (!obj_priv->active)
list_move_tail(&obj_priv->mm_list,
&dev_priv->mm.pinned_list);
}
- BUG_ON(!obj_priv->pin_mappable && mappable);
+ BUG_ON(!obj_priv->pin_mappable && map_and_fenceable);
WARN_ON(i915_verify_lists(dev));
return 0;
obj_priv->user_pin_count++;
obj_priv->pin_filp = file_priv;
if (obj_priv->user_pin_count == 1) {
- ret = i915_gem_object_pin(obj, args->alignment,
- true, obj_priv->tiling_mode);
+ ret = i915_gem_object_pin(obj, args->alignment, true);
if (ret)
goto out;
}
INIT_LIST_HEAD(&obj->ring_list);
INIT_LIST_HEAD(&obj->gpu_write_list);
obj->madv = I915_MADV_WILLNEED;
- obj->fenceable = true;
- obj->mappable = true;
+ /* Avoid an unnecessary call to unbind on the first bind. */
+ obj->map_and_fenceable = true;
return &obj->base;
}
obj_priv = to_intel_bo(obj);
obj_priv->agp_type = AGP_USER_CACHED_MEMORY;
- ret = i915_gem_object_pin(obj, 4096, true, false);
+ ret = i915_gem_object_pin(obj, 4096, true);
if (ret)
goto err_unref;
struct drm_file *file_priv)
{
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
- void *obj_addr;
- int ret;
- char __user *user_data;
+ void *vaddr = obj_priv->phys_obj->handle->vaddr + args->offset;
+ char __user *user_data = (char __user *) (uintptr_t) args->data_ptr;
- user_data = (char __user *) (uintptr_t) args->data_ptr;
- obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
+ DRM_DEBUG_DRIVER("vaddr %p, %lld\n", vaddr, args->size);
- DRM_DEBUG_DRIVER("obj_addr %p, %lld\n", obj_addr, args->size);
- ret = copy_from_user(obj_addr, user_data, args->size);
- if (ret)
- return -EFAULT;
+ if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
+ unsigned long unwritten;
+
+ /* The physical object once assigned is fixed for the lifetime
+ * of the obj, so we can safely drop the lock and continue
+ * to access vaddr.
+ */
+ mutex_unlock(&dev->struct_mutex);
+ unwritten = copy_from_user(vaddr, user_data, args->size);
+ mutex_lock(&dev->struct_mutex);
+ if (unwritten)
+ return -EFAULT;
+ }
drm_agp_chipset_flush(dev);
return 0;