]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - drivers/gpu/drm/i915/i915_gem.c
drm/i915: Avoid moving from CPU domain during pwrite
[net-next-2.6.git] / drivers / gpu / drm / i915 / i915_gem.c
index c51495f1571844b8f302d3ec819a0d49a6a60888..4590c78f428393e115c0085a5acd372a1dbfd2df 100644 (file)
@@ -971,7 +971,8 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
        if (obj_priv->phys_obj)
                ret = i915_gem_phys_pwrite(dev, obj, args, file_priv);
        else if (obj_priv->tiling_mode == I915_TILING_NONE &&
-                dev->gtt_total != 0) {
+                dev->gtt_total != 0 &&
+                obj->write_domain != I915_GEM_DOMAIN_CPU) {
                ret = i915_gem_gtt_pwrite_fast(dev, obj, args, file_priv);
                if (ret == -EFAULT) {
                        ret = i915_gem_gtt_pwrite_slow(dev, obj, args,
@@ -2247,6 +2248,9 @@ i915_gem_object_get_pages(struct drm_gem_object *obj,
        struct inode *inode;
        struct page *page;
 
+       BUG_ON(obj_priv->pages_refcount
+                       == DRM_I915_GEM_OBJECT_MAX_PAGES_REFCOUNT);
+
        if (obj_priv->pages_refcount++ != 0)
                return 0;
 
@@ -2645,6 +2649,14 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                return -EINVAL;
        }
 
+       /* 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 > dev->gtt_total) {
+               DRM_ERROR("Attempting to bind an object larger than the aperture\n");
+               return -E2BIG;
+       }
+
  search_free:
        free_space = drm_mm_search_free(&dev_priv->mm.gtt_space,
                                        obj->size, alignment, 0);
@@ -2911,18 +2923,16 @@ i915_gem_object_set_to_display_plane(struct drm_gem_object *obj)
                        return ret;
        }
 
+       i915_gem_object_flush_cpu_write_domain(obj);
+
        old_write_domain = obj->write_domain;
        old_read_domains = obj->read_domains;
 
-       obj->read_domains &= I915_GEM_DOMAIN_GTT;
-
-       i915_gem_object_flush_cpu_write_domain(obj);
-
        /* It should now be out of any other write domains, and we can update
         * the domain values for our changes.
         */
        BUG_ON((obj->write_domain & ~I915_GEM_DOMAIN_GTT) != 0);
-       obj->read_domains |= I915_GEM_DOMAIN_GTT;
+       obj->read_domains = I915_GEM_DOMAIN_GTT;
        obj->write_domain = I915_GEM_DOMAIN_GTT;
        obj_priv->dirty = 1;
 
@@ -3306,9 +3316,13 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
                     obj_priv->tiling_mode != I915_TILING_NONE;
 
        /* Check fence reg constraints and rebind if necessary */
-       if (need_fence && !i915_gem_object_fence_offset_ok(obj,
-           obj_priv->tiling_mode))
-               i915_gem_object_unbind(obj);
+       if (need_fence &&
+           !i915_gem_object_fence_offset_ok(obj,
+                                            obj_priv->tiling_mode)) {
+               ret = i915_gem_object_unbind(obj);
+               if (ret)
+                       return ret;
+       }
 
        /* Choose the GTT offset for our buffer and put it there. */
        ret = i915_gem_object_pin(obj, (uint32_t) entry->alignment);
@@ -3322,9 +3336,6 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
        if (need_fence) {
                ret = i915_gem_object_get_fence_reg(obj);
                if (ret != 0) {
-                       if (ret != -EBUSY && ret != -ERESTARTSYS)
-                               DRM_ERROR("Failure to install fence: %d\n",
-                                         ret);
                        i915_gem_object_unpin(obj);
                        return ret;
                }
@@ -3810,11 +3821,19 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                if (ret != -ENOSPC || pin_tries >= 1) {
                        if (ret != -ERESTARTSYS) {
                                unsigned long long total_size = 0;
-                               for (i = 0; i < args->buffer_count; i++)
+                               int num_fences = 0;
+                               for (i = 0; i < args->buffer_count; i++) {
+                                       obj_priv = object_list[i]->driver_private;
+
                                        total_size += object_list[i]->size;
-                               DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes: %d\n",
+                                       num_fences +=
+                                               exec_list[i].flags & EXEC_OBJECT_NEEDS_FENCE &&
+                                               obj_priv->tiling_mode != I915_TILING_NONE;
+                               }
+                               DRM_ERROR("Failed to pin buffer %d of %d, total %llu bytes, %d fences: %d\n",
                                          pinned+1, args->buffer_count,
-                                         total_size, ret);
+                                         total_size, num_fences,
+                                         ret);
                                DRM_ERROR("%d objects [%d pinned], "
                                          "%d object bytes [%d pinned], "
                                          "%d/%d gtt bytes\n",
@@ -4156,7 +4175,20 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
        struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
        int ret;
 
+       BUG_ON(obj_priv->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
+
        i915_verify_inactive(dev, __FILE__, __LINE__);
+
+       if (obj_priv->gtt_space != NULL) {
+               if (alignment == 0)
+                       alignment = i915_gem_get_gtt_alignment(obj);
+               if (obj_priv->gtt_offset & (alignment - 1)) {
+                       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);
                if (ret)
@@ -4601,23 +4633,40 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        int ret;
+
        dev_priv->render_ring = render_ring;
+
        if (!I915_NEED_GFX_HWS(dev)) {
                dev_priv->render_ring.status_page.page_addr
                        = dev_priv->status_page_dmah->vaddr;
                memset(dev_priv->render_ring.status_page.page_addr,
                                0, PAGE_SIZE);
        }
+
        if (HAS_PIPE_CONTROL(dev)) {
                ret = i915_gem_init_pipe_control(dev);
                if (ret)
                        return ret;
        }
+
        ret = intel_init_ring_buffer(dev, &dev_priv->render_ring);
-       if (!ret && HAS_BSD(dev)) {
+       if (ret)
+               goto cleanup_pipe_control;
+
+       if (HAS_BSD(dev)) {
                dev_priv->bsd_ring = bsd_ring;
                ret = intel_init_ring_buffer(dev, &dev_priv->bsd_ring);
+               if (ret)
+                       goto cleanup_render_ring;
        }
+
+       return 0;
+
+cleanup_render_ring:
+       intel_cleanup_ring_buffer(dev, &dev_priv->render_ring);
+cleanup_pipe_control:
+       if (HAS_PIPE_CONTROL(dev))
+               i915_gem_cleanup_pipe_control(dev);
        return ret;
 }