ACPICA: avoid "Info: mapping multiple BARs. Your kernel is fine."
[safe/jmp/linux-2.6] / drivers / gpu / drm / i915 / i915_gem.c
index 67e2cd5..abfc27b 100644 (file)
@@ -50,8 +50,7 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
                                           unsigned alignment);
 static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
 static int i915_gem_evict_something(struct drm_device *dev, int min_size);
-static int i915_gem_evict_from_list(struct drm_device *dev,
-                                   struct list_head *head);
+static int i915_gem_evict_from_inactive_list(struct drm_device *dev);
 static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
                                struct drm_i915_gem_pwrite *args,
                                struct drm_file *file_priv);
@@ -1201,26 +1200,21 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        mutex_lock(&dev->struct_mutex);
        if (!obj_priv->gtt_space) {
                ret = i915_gem_object_bind_to_gtt(obj, 0);
-               if (ret) {
-                       mutex_unlock(&dev->struct_mutex);
-                       return VM_FAULT_SIGBUS;
-               }
+               if (ret)
+                       goto unlock;
+
                list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list);
 
                ret = i915_gem_object_set_to_gtt_domain(obj, write);
-               if (ret) {
-                       mutex_unlock(&dev->struct_mutex);
-                       return VM_FAULT_SIGBUS;
-               }
+               if (ret)
+                       goto unlock;
        }
 
        /* Need a new fence register? */
        if (obj_priv->tiling_mode != I915_TILING_NONE) {
                ret = i915_gem_object_get_fence_reg(obj);
-               if (ret) {
-                       mutex_unlock(&dev->struct_mutex);
-                       return VM_FAULT_SIGBUS;
-               }
+               if (ret)
+                       goto unlock;
        }
 
        pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
@@ -1228,18 +1222,18 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        /* Finally, remap it using the new GTT offset */
        ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
-
+unlock:
        mutex_unlock(&dev->struct_mutex);
 
        switch (ret) {
+       case 0:
+       case -ERESTARTSYS:
+               return VM_FAULT_NOPAGE;
        case -ENOMEM:
        case -EAGAIN:
                return VM_FAULT_OOM;
-       case -EFAULT:
-       case -EINVAL:
-               return VM_FAULT_SIGBUS;
        default:
-               return VM_FAULT_NOPAGE;
+               return VM_FAULT_SIGBUS;
        }
 }
 
@@ -1432,6 +1426,14 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
 
        obj_priv = obj->driver_private;
 
+       if (obj_priv->madv != I915_MADV_WILLNEED) {
+               DRM_ERROR("Attempting to mmap a purgeable buffer\n");
+               drm_gem_object_unreference(obj);
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
+       }
+
+
        if (!obj_priv->mmap_offset) {
                ret = i915_gem_create_mmap_offset(obj);
                if (ret) {
@@ -1471,6 +1473,7 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
        int i;
 
        BUG_ON(obj_priv->pages_refcount == 0);
+       BUG_ON(obj_priv->madv == __I915_MADV_PURGED);
 
        if (--obj_priv->pages_refcount != 0)
                return;
@@ -1479,7 +1482,7 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
                i915_gem_object_save_bit_17_swizzle(obj);
 
        if (obj_priv->madv == I915_MADV_DONTNEED)
-           obj_priv->dirty = 0;
+               obj_priv->dirty = 0;
 
        for (i = 0; i < page_count; i++) {
                if (obj_priv->pages[i] == NULL)
@@ -1489,7 +1492,7 @@ i915_gem_object_put_pages(struct drm_gem_object *obj)
                        set_page_dirty(obj_priv->pages[i]);
 
                if (obj_priv->madv == I915_MADV_WILLNEED)
-                   mark_page_accessed(obj_priv->pages[i]);
+                       mark_page_accessed(obj_priv->pages[i]);
 
                page_cache_release(obj_priv->pages[i]);
        }
@@ -1531,6 +1534,26 @@ i915_gem_object_move_to_flushing(struct drm_gem_object *obj)
        obj_priv->last_rendering_seqno = 0;
 }
 
+/* Immediately discard the backing storage */
+static void
+i915_gem_object_truncate(struct drm_gem_object *obj)
+{
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       struct inode *inode;
+
+       inode = obj->filp->f_path.dentry->d_inode;
+       if (inode->i_op->truncate)
+               inode->i_op->truncate (inode);
+
+       obj_priv->madv = __I915_MADV_PURGED;
+}
+
+static inline int
+i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj_priv)
+{
+       return obj_priv->madv == I915_MADV_DONTNEED;
+}
+
 static void
 i915_gem_object_move_to_inactive(struct drm_gem_object *obj)
 {
@@ -1747,7 +1770,7 @@ i915_gem_retire_requests(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t seqno;
 
-       if (!dev_priv->hw_status_page)
+       if (!dev_priv->hw_status_page || list_empty(&dev_priv->mm.request_list))
                return;
 
        seqno = i915_get_gem_seqno(dev);
@@ -1771,6 +1794,12 @@ i915_gem_retire_requests(struct drm_device *dev)
                } else
                        break;
        }
+
+       if (unlikely (dev_priv->trace_irq_seqno &&
+                     i915_seqno_passed(dev_priv->trace_irq_seqno, seqno))) {
+               i915_user_irq_put(dev);
+               dev_priv->trace_irq_seqno = 0;
+       }
 }
 
 void
@@ -2005,6 +2034,7 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
        }
 
        i915_gem_object_put_pages(obj);
+       BUG_ON(obj_priv->pages_refcount);
 
        if (obj_priv->gtt_space) {
                atomic_dec(&dev->gtt_count);
@@ -2018,17 +2048,14 @@ i915_gem_object_unbind(struct drm_gem_object *obj)
        if (!list_empty(&obj_priv->list))
                list_del_init(&obj_priv->list);
 
+       if (i915_gem_object_is_purgeable(obj_priv))
+               i915_gem_object_truncate(obj);
+
        trace_i915_gem_object_unbind(obj);
 
        return 0;
 }
 
-static inline int
-i915_gem_object_is_purgeable(struct drm_i915_gem_object *obj_priv)
-{
-       return !obj_priv->dirty || obj_priv->madv == I915_MADV_DONTNEED;
-}
-
 static struct drm_gem_object *
 i915_gem_find_inactive_object(struct drm_device *dev, int min_size)
 {
@@ -2041,7 +2068,8 @@ i915_gem_find_inactive_object(struct drm_device *dev, int min_size)
        list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
                struct drm_gem_object *obj = obj_priv->obj;
                if (obj->size >= min_size) {
-                       if (i915_gem_object_is_purgeable(obj_priv) &&
+                       if ((!obj_priv->dirty ||
+                            i915_gem_object_is_purgeable(obj_priv)) &&
                            (!best || obj->size < best->size)) {
                                best = obj;
                                if (best->size == min_size)
@@ -2063,27 +2091,14 @@ i915_gem_evict_everything(struct drm_device *dev)
        int ret;
        bool lists_empty;
 
-       DRM_INFO("GTT full, evicting everything: "
-                "%d objects [%d pinned], "
-                "%d object bytes [%d pinned], "
-                "%d/%d gtt bytes\n",
-                atomic_read(&dev->object_count),
-                atomic_read(&dev->pin_count),
-                atomic_read(&dev->object_memory),
-                atomic_read(&dev->pin_memory),
-                atomic_read(&dev->gtt_memory),
-                dev->gtt_total);
-
        spin_lock(&dev_priv->mm.active_list_lock);
        lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
                       list_empty(&dev_priv->mm.flushing_list) &&
                       list_empty(&dev_priv->mm.active_list));
        spin_unlock(&dev_priv->mm.active_list_lock);
 
-       if (lists_empty) {
-               DRM_ERROR("GTT full, but lists empty!\n");
+       if (lists_empty)
                return -ENOSPC;
-       }
 
        /* Flush everything (on to the inactive lists) and evict */
        i915_gem_flush(dev, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
@@ -2095,7 +2110,7 @@ i915_gem_evict_everything(struct drm_device *dev)
        if (ret)
                return ret;
 
-       ret = i915_gem_evict_from_list(dev, &dev_priv->mm.inactive_list);
+       ret = i915_gem_evict_from_inactive_list(dev);
        if (ret)
                return ret;
 
@@ -2114,7 +2129,6 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_gem_object *obj;
-       int have_waited = 0;
        int ret;
 
        for (;;) {
@@ -2138,9 +2152,6 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
                        return i915_gem_object_unbind(obj);
                }
 
-               if (have_waited)
-                       return 0;
-
                /* If we didn't get anything, but the ring is still processing
                 * things, wait for the next to finish and hopefully leave us
                 * a buffer to evict.
@@ -2156,7 +2167,6 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
                        if (ret)
                                return ret;
 
-                       have_waited = 1;
                        continue;
                }
 
@@ -2167,37 +2177,41 @@ i915_gem_evict_something(struct drm_device *dev, int min_size)
                 */
                if (!list_empty(&dev_priv->mm.flushing_list)) {
                        struct drm_i915_gem_object *obj_priv;
-                       uint32_t seqno;
 
-                       obj_priv = list_first_entry(&dev_priv->mm.flushing_list,
-                                                   struct drm_i915_gem_object,
-                                                   list);
-                       obj = obj_priv->obj;
+                       /* Find an object that we can immediately reuse */
+                       list_for_each_entry(obj_priv, &dev_priv->mm.flushing_list, list) {
+                               obj = obj_priv->obj;
+                               if (obj->size >= min_size)
+                                       break;
 
-                       i915_gem_flush(dev,
-                                      obj->write_domain,
-                                      obj->write_domain);
-                       seqno = i915_add_request(dev, NULL, obj->write_domain);
-                       if (seqno == 0)
-                               return -ENOMEM;
+                               obj = NULL;
+                       }
 
-                       ret = i915_wait_request(dev, seqno);
-                       if (ret)
-                               return ret;
+                       if (obj != NULL) {
+                               uint32_t seqno;
 
-                       have_waited = 1;
-                       continue;
+                               i915_gem_flush(dev,
+                                              obj->write_domain,
+                                              obj->write_domain);
+                               seqno = i915_add_request(dev, NULL, obj->write_domain);
+                               if (seqno == 0)
+                                       return -ENOMEM;
+
+                               ret = i915_wait_request(dev, seqno);
+                               if (ret)
+                                       return ret;
+
+                               continue;
+                       }
                }
 
                /* If we didn't do any of the above, there's no single buffer
                 * large enough to swap out for the new one, so just evict
                 * everything and start again. (This should be rare.)
                 */
-               if (!list_empty (&dev_priv->mm.inactive_list)) {
-                       DRM_INFO("GTT full, evicting inactive buffers\n");
-                       return i915_gem_evict_from_list(dev,
-                                                       &dev_priv->mm.inactive_list);
-               } else
+               if (!list_empty (&dev_priv->mm.inactive_list))
+                       return i915_gem_evict_from_inactive_list(dev);
+               else
                        return i915_gem_evict_everything(dev);
        }
 }
@@ -2222,7 +2236,6 @@ i915_gem_object_get_pages(struct drm_gem_object *obj)
        BUG_ON(obj_priv->pages != NULL);
        obj_priv->pages = drm_calloc_large(page_count, sizeof(struct page *));
        if (obj_priv->pages == NULL) {
-               DRM_ERROR("Failed to allocate page list\n");
                obj_priv->pages_refcount--;
                return -ENOMEM;
        }
@@ -2559,7 +2572,7 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
        if (dev_priv->mm.suspended)
                return -EBUSY;
 
-       if (obj_priv->madv == I915_MADV_DONTNEED) {
+       if (obj_priv->madv != I915_MADV_WILLNEED) {
                DRM_ERROR("Attempting to bind a purgeable object\n");
                return -EINVAL;
        }
@@ -2590,11 +2603,9 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                DRM_INFO("%s: GTT full, evicting something\n", __func__);
 #endif
                ret = i915_gem_evict_something(dev, obj->size);
-               if (ret != 0) {
-                       if (ret != -ERESTARTSYS)
-                               DRM_ERROR("Failed to evict a buffer %d\n", ret);
+               if (ret)
                        return ret;
-               }
+
                goto search_free;
        }
 
@@ -2619,9 +2630,6 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                        /* first try to clear up some space from the GTT */
                        ret = i915_gem_evict_something(dev, obj->size);
                        if (ret) {
-                               if (ret != -ERESTARTSYS)
-                                       DRM_ERROR("Failed to allocate space for backing pages %d\n", ret);
-
                                /* now try to shrink everyone else */
                                if (! retry_alloc) {
                                    retry_alloc = true;
@@ -2651,11 +2659,8 @@ i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment)
                obj_priv->gtt_space = NULL;
 
                ret = i915_gem_evict_something(dev, obj->size);
-               if (ret) {
-                       if (ret != -ERESTARTSYS)
-                               DRM_ERROR("Failed to allocate space to bind AGP: %d\n", ret);
+               if (ret)
                        return ret;
-               }
 
                goto search_free;
        }
@@ -3353,7 +3358,7 @@ i915_dispatch_gem_execbuffer(struct drm_device *dev,
        exec_start = (uint32_t) exec_offset + exec->batch_start_offset;
        exec_len = (uint32_t) exec->batch_len;
 
-       trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno);
+       trace_i915_gem_request_submit(dev, dev_priv->mm.next_gem_seqno + 1);
 
        count = nbox ? nbox : 1;
 
@@ -3855,11 +3860,8 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
        i915_verify_inactive(dev, __FILE__, __LINE__);
        if (obj_priv->gtt_space == NULL) {
                ret = i915_gem_object_bind_to_gtt(obj, alignment);
-               if (ret != 0) {
-                       if (ret != -EBUSY && ret != -ERESTARTSYS)
-                               DRM_ERROR("Failure to bind: %d\n", ret);
+               if (ret)
                        return ret;
-               }
        }
        /*
         * Pre-965 chips need a fence register set up in order to
@@ -3939,8 +3941,8 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        }
        obj_priv = obj->driver_private;
 
-       if (obj_priv->madv == I915_MADV_DONTNEED) {
-               DRM_ERROR("Attempting to pin a I915_MADV_DONTNEED buffer\n");
+       if (obj_priv->madv != I915_MADV_WILLNEED) {
+               DRM_ERROR("Attempting to pin a purgeable buffer\n");
                drm_gem_object_unreference(obj);
                mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
@@ -4092,8 +4094,15 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       obj_priv->madv = args->madv;
-       args->retained = obj_priv->gtt_space != NULL;
+       if (obj_priv->madv != __I915_MADV_PURGED)
+               obj_priv->madv = args->madv;
+
+       /* if the object is no longer bound, discard its backing storage */
+       if (i915_gem_object_is_purgeable(obj_priv) &&
+           obj_priv->gtt_space == NULL)
+               i915_gem_object_truncate(obj);
+
+       args->retained = obj_priv->madv != __I915_MADV_PURGED;
 
        drm_gem_object_unreference(obj);
        mutex_unlock(&dev->struct_mutex);
@@ -4155,36 +4164,27 @@ void i915_gem_free_object(struct drm_gem_object *obj)
        kfree(obj->driver_private);
 }
 
-/** Unbinds all objects that are on the given buffer list. */
+/** Unbinds all inactive objects. */
 static int
-i915_gem_evict_from_list(struct drm_device *dev, struct list_head *head)
+i915_gem_evict_from_inactive_list(struct drm_device *dev)
 {
-       struct drm_gem_object *obj;
-       struct drm_i915_gem_object *obj_priv;
-       int ret;
+       drm_i915_private_t *dev_priv = dev->dev_private;
 
-       while (!list_empty(head)) {
-               obj_priv = list_first_entry(head,
-                                           struct drm_i915_gem_object,
-                                           list);
-               obj = obj_priv->obj;
+       while (!list_empty(&dev_priv->mm.inactive_list)) {
+               struct drm_gem_object *obj;
+               int ret;
 
-               if (obj_priv->pin_count != 0) {
-                       DRM_ERROR("Pinned object in unbind list\n");
-                       mutex_unlock(&dev->struct_mutex);
-                       return -EINVAL;
-               }
+               obj = list_first_entry(&dev_priv->mm.inactive_list,
+                                      struct drm_i915_gem_object,
+                                      list)->obj;
 
                ret = i915_gem_object_unbind(obj);
                if (ret != 0) {
-                       DRM_ERROR("Error unbinding object in LeaveVT: %d\n",
-                                 ret);
-                       mutex_unlock(&dev->struct_mutex);
+                       DRM_ERROR("Error unbinding object: %d\n", ret);
                        return ret;
                }
        }
 
-
        return 0;
 }
 
@@ -4301,7 +4301,7 @@ i915_gem_idle(struct drm_device *dev)
 
 
        /* Move all inactive buffers out of the GTT. */
-       ret = i915_gem_evict_from_list(dev, &dev_priv->mm.inactive_list);
+       ret = i915_gem_evict_from_inactive_list(dev);
        WARN_ON(!list_empty(&dev_priv->mm.inactive_list));
        if (ret) {
                mutex_unlock(&dev->struct_mutex);
@@ -4555,15 +4555,11 @@ int
 i915_gem_leavevt_ioctl(struct drm_device *dev, void *data,
                       struct drm_file *file_priv)
 {
-       int ret;
-
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return 0;
 
-       ret = i915_gem_idle(dev);
        drm_irq_uninstall(dev);
-
-       return ret;
+       return i915_gem_idle(dev);
 }
 
 void
@@ -4817,19 +4813,6 @@ void i915_gem_release(struct drm_device * dev, struct drm_file *file_priv)
        mutex_unlock(&dev->struct_mutex);
 }
 
-/* Immediately discard the backing storage */
-static void
-i915_gem_object_truncate(struct drm_gem_object *obj)
-{
-    struct inode *inode;
-
-    inode = obj->filp->f_path.dentry->d_inode;
-
-    mutex_lock(&inode->i_mutex);
-    truncate_inode_pages(inode->i_mapping, 0);
-    mutex_unlock(&inode->i_mutex);
-}
-
 static int
 i915_gem_shrink(int nr_to_scan, gfp_t gfp_mask)
 {
@@ -4875,10 +4858,7 @@ i915_gem_shrink(int nr_to_scan, gfp_t gfp_mask)
                                         &dev_priv->mm.inactive_list,
                                         list) {
                        if (i915_gem_object_is_purgeable(obj_priv)) {
-                               struct drm_gem_object *obj = obj_priv->obj;
-                               i915_gem_object_unbind(obj);
-                               i915_gem_object_truncate(obj);
-
+                               i915_gem_object_unbind(obj_priv->obj);
                                if (--nr_to_scan <= 0)
                                        break;
                        }
@@ -4887,6 +4867,8 @@ i915_gem_shrink(int nr_to_scan, gfp_t gfp_mask)
                spin_lock(&shrink_list_lock);
                mutex_unlock(&dev->struct_mutex);
 
+               would_deadlock = 0;
+
                if (nr_to_scan <= 0)
                        break;
        }
@@ -4905,11 +4887,7 @@ i915_gem_shrink(int nr_to_scan, gfp_t gfp_mask)
                                         &dev_priv->mm.inactive_list,
                                         list) {
                        if (nr_to_scan > 0) {
-                               struct drm_gem_object *obj = obj_priv->obj;
-                               i915_gem_object_unbind(obj);
-                               if (i915_gem_object_is_purgeable(obj_priv))
-                                       i915_gem_object_truncate(obj);
-
+                               i915_gem_object_unbind(obj_priv->obj);
                                nr_to_scan--;
                        } else
                                cnt++;