|
@@ -46,7 +46,6 @@ static int i915_gem_phys_pwrite(struct drm_device *dev,
|
|
|
struct drm_i915_gem_object *obj,
|
|
|
struct drm_i915_gem_pwrite *args,
|
|
|
struct drm_file *file);
|
|
|
-static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj);
|
|
|
|
|
|
static void i915_gem_write_fence(struct drm_device *dev, int reg,
|
|
|
struct drm_i915_gem_object *obj);
|
|
@@ -66,7 +65,7 @@ static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj)
|
|
|
/* As we do not have an associated fence register, we will force
|
|
|
* a tiling change if we ever need to acquire one.
|
|
|
*/
|
|
|
- obj->tiling_changed = false;
|
|
|
+ obj->fence_dirty = false;
|
|
|
obj->fence_reg = I915_FENCE_REG_NONE;
|
|
|
}
|
|
|
|
|
@@ -132,7 +131,7 @@ int i915_mutex_lock_interruptible(struct drm_device *dev)
|
|
|
static inline bool
|
|
|
i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
|
|
|
{
|
|
|
- return obj->gtt_space && !obj->active && obj->pin_count == 0;
|
|
|
+ return !obj->active;
|
|
|
}
|
|
|
|
|
|
int
|
|
@@ -141,6 +140,9 @@ i915_gem_init_ioctl(struct drm_device *dev, void *data,
|
|
|
{
|
|
|
struct drm_i915_gem_init *args = data;
|
|
|
|
|
|
+ if (drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
+ return -ENODEV;
|
|
|
+
|
|
|
if (args->gtt_start >= args->gtt_end ||
|
|
|
(args->gtt_end | args->gtt_start) & (PAGE_SIZE - 1))
|
|
|
return -EINVAL;
|
|
@@ -166,13 +168,11 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
|
|
|
struct drm_i915_gem_object *obj;
|
|
|
size_t pinned;
|
|
|
|
|
|
- if (!(dev->driver->driver_features & DRIVER_GEM))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
pinned = 0;
|
|
|
mutex_lock(&dev->struct_mutex);
|
|
|
- list_for_each_entry(obj, &dev_priv->mm.pinned_list, mm_list)
|
|
|
- pinned += obj->gtt_space->size;
|
|
|
+ list_for_each_entry(obj, &dev_priv->mm.gtt_list, gtt_list)
|
|
|
+ if (obj->pin_count)
|
|
|
+ pinned += obj->gtt_space->size;
|
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
|
|
|
args->aper_size = dev_priv->mm.gtt_total;
|
|
@@ -243,6 +243,7 @@ i915_gem_create_ioctl(struct drm_device *dev, void *data,
|
|
|
struct drm_file *file)
|
|
|
{
|
|
|
struct drm_i915_gem_create *args = data;
|
|
|
+
|
|
|
return i915_gem_create(file, dev,
|
|
|
args->size, &args->handle);
|
|
|
}
|
|
@@ -282,8 +283,8 @@ __copy_to_user_swizzled(char __user *cpu_vaddr,
|
|
|
}
|
|
|
|
|
|
static inline int
|
|
|
-__copy_from_user_swizzled(char __user *gpu_vaddr, int gpu_offset,
|
|
|
- const char *cpu_vaddr,
|
|
|
+__copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset,
|
|
|
+ const char __user *cpu_vaddr,
|
|
|
int length)
|
|
|
{
|
|
|
int ret, cpu_offset = 0;
|
|
@@ -558,11 +559,14 @@ fast_user_write(struct io_mapping *mapping,
|
|
|
char __user *user_data,
|
|
|
int length)
|
|
|
{
|
|
|
- char *vaddr_atomic;
|
|
|
+ void __iomem *vaddr_atomic;
|
|
|
+ void *vaddr;
|
|
|
unsigned long unwritten;
|
|
|
|
|
|
vaddr_atomic = io_mapping_map_atomic_wc(mapping, page_base);
|
|
|
- unwritten = __copy_from_user_inatomic_nocache(vaddr_atomic + page_offset,
|
|
|
+ /* We can use the cpu mem copy function because this is X86. */
|
|
|
+ vaddr = (void __force*)vaddr_atomic + page_offset;
|
|
|
+ unwritten = __copy_from_user_inatomic_nocache(vaddr,
|
|
|
user_data, length);
|
|
|
io_mapping_unmap_atomic(vaddr_atomic);
|
|
|
return unwritten;
|
|
@@ -925,9 +929,6 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
|
|
|
uint32_t write_domain = args->write_domain;
|
|
|
int ret;
|
|
|
|
|
|
- if (!(dev->driver->driver_features & DRIVER_GEM))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
/* Only handle setting domains to types used by the CPU. */
|
|
|
if (write_domain & I915_GEM_GPU_DOMAINS)
|
|
|
return -EINVAL;
|
|
@@ -981,9 +982,6 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
|
|
|
struct drm_i915_gem_object *obj;
|
|
|
int ret = 0;
|
|
|
|
|
|
- if (!(dev->driver->driver_features & DRIVER_GEM))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
ret = i915_mutex_lock_interruptible(dev);
|
|
|
if (ret)
|
|
|
return ret;
|
|
@@ -1019,9 +1017,6 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
|
|
|
struct drm_gem_object *obj;
|
|
|
unsigned long addr;
|
|
|
|
|
|
- if (!(dev->driver->driver_features & DRIVER_GEM))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
obj = drm_gem_object_lookup(dev, file, args->handle);
|
|
|
if (obj == NULL)
|
|
|
return -ENOENT;
|
|
@@ -1247,9 +1242,6 @@ i915_gem_mmap_gtt(struct drm_file *file,
|
|
|
struct drm_i915_gem_object *obj;
|
|
|
int ret;
|
|
|
|
|
|
- if (!(dev->driver->driver_features & DRIVER_GEM))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
ret = i915_mutex_lock_interruptible(dev);
|
|
|
if (ret)
|
|
|
return ret;
|
|
@@ -1307,9 +1299,6 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
|
|
|
{
|
|
|
struct drm_i915_gem_mmap_gtt *args = data;
|
|
|
|
|
|
- if (!(dev->driver->driver_features & DRIVER_GEM))
|
|
|
- return -ENODEV;
|
|
|
-
|
|
|
return i915_gem_mmap_gtt(file, dev, args->handle, &args->offset);
|
|
|
}
|
|
|
|
|
@@ -1450,10 +1439,7 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
|
|
|
struct drm_device *dev = obj->base.dev;
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
|
|
|
- if (obj->pin_count != 0)
|
|
|
- list_move_tail(&obj->mm_list, &dev_priv->mm.pinned_list);
|
|
|
- else
|
|
|
- list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
|
|
|
+ list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
|
|
|
|
|
|
BUG_ON(!list_empty(&obj->gpu_write_list));
|
|
|
BUG_ON(!obj->active);
|
|
@@ -1779,20 +1765,6 @@ i915_gem_retire_requests(struct drm_device *dev)
|
|
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
|
|
int i;
|
|
|
|
|
|
- if (!list_empty(&dev_priv->mm.deferred_free_list)) {
|
|
|
- struct drm_i915_gem_object *obj, *next;
|
|
|
-
|
|
|
- /* We must be careful that during unbind() we do not
|
|
|
- * accidentally infinitely recurse into retire requests.
|
|
|
- * Currently:
|
|
|
- * retire -> free -> unbind -> wait -> retire_ring
|
|
|
- */
|
|
|
- list_for_each_entry_safe(obj, next,
|
|
|
- &dev_priv->mm.deferred_free_list,
|
|
|
- mm_list)
|
|
|
- i915_gem_free_object_tail(obj);
|
|
|
- }
|
|
|
-
|
|
|
for (i = 0; i < I915_NUM_RINGS; i++)
|
|
|
i915_gem_retire_requests_ring(&dev_priv->ring[i]);
|
|
|
}
|
|
@@ -1845,20 +1817,10 @@ i915_gem_retire_work_handler(struct work_struct *work)
|
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Waits for a sequence number to be signaled, and cleans up the
|
|
|
- * request and object lists appropriately for that event.
|
|
|
- */
|
|
|
-int
|
|
|
-i915_wait_request(struct intel_ring_buffer *ring,
|
|
|
- uint32_t seqno,
|
|
|
- bool do_retire)
|
|
|
+static int
|
|
|
+i915_gem_check_wedge(struct drm_i915_private *dev_priv)
|
|
|
{
|
|
|
- drm_i915_private_t *dev_priv = ring->dev->dev_private;
|
|
|
- u32 ier;
|
|
|
- int ret = 0;
|
|
|
-
|
|
|
- BUG_ON(seqno == 0);
|
|
|
+ BUG_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
|
|
|
|
|
|
if (atomic_read(&dev_priv->mm.wedged)) {
|
|
|
struct completion *x = &dev_priv->error_completion;
|
|
@@ -1873,6 +1835,20 @@ i915_wait_request(struct intel_ring_buffer *ring,
|
|
|
return recovery_complete ? -EIO : -EAGAIN;
|
|
|
}
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Compare seqno against outstanding lazy request. Emit a request if they are
|
|
|
+ * equal.
|
|
|
+ */
|
|
|
+static int
|
|
|
+i915_gem_check_olr(struct intel_ring_buffer *ring, u32 seqno)
|
|
|
+{
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
|
|
|
+
|
|
|
if (seqno == ring->outstanding_lazy_request) {
|
|
|
struct drm_i915_gem_request *request;
|
|
|
|
|
@@ -1886,56 +1862,67 @@ i915_wait_request(struct intel_ring_buffer *ring,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- seqno = request->seqno;
|
|
|
+ BUG_ON(seqno != request->seqno);
|
|
|
}
|
|
|
|
|
|
- if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
|
|
|
- if (HAS_PCH_SPLIT(ring->dev))
|
|
|
- ier = I915_READ(DEIER) | I915_READ(GTIER);
|
|
|
- else if (IS_VALLEYVIEW(ring->dev))
|
|
|
- ier = I915_READ(GTIER) | I915_READ(VLV_IER);
|
|
|
- else
|
|
|
- ier = I915_READ(IER);
|
|
|
- if (!ier) {
|
|
|
- DRM_ERROR("something (likely vbetool) disabled "
|
|
|
- "interrupts, re-enabling\n");
|
|
|
- ring->dev->driver->irq_preinstall(ring->dev);
|
|
|
- ring->dev->driver->irq_postinstall(ring->dev);
|
|
|
- }
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
|
|
|
+ bool interruptible)
|
|
|
+{
|
|
|
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
|
|
|
+ int ret = 0;
|
|
|
|
|
|
- trace_i915_gem_request_wait_begin(ring, seqno);
|
|
|
+ if (i915_seqno_passed(ring->get_seqno(ring), seqno))
|
|
|
+ return 0;
|
|
|
|
|
|
- ring->waiting_seqno = seqno;
|
|
|
- if (ring->irq_get(ring)) {
|
|
|
- if (dev_priv->mm.interruptible)
|
|
|
- ret = wait_event_interruptible(ring->irq_queue,
|
|
|
- i915_seqno_passed(ring->get_seqno(ring), seqno)
|
|
|
- || atomic_read(&dev_priv->mm.wedged));
|
|
|
- else
|
|
|
- wait_event(ring->irq_queue,
|
|
|
- i915_seqno_passed(ring->get_seqno(ring), seqno)
|
|
|
- || atomic_read(&dev_priv->mm.wedged));
|
|
|
+ trace_i915_gem_request_wait_begin(ring, seqno);
|
|
|
+ if (WARN_ON(!ring->irq_get(ring)))
|
|
|
+ return -ENODEV;
|
|
|
|
|
|
- ring->irq_put(ring);
|
|
|
- } else if (wait_for_atomic(i915_seqno_passed(ring->get_seqno(ring),
|
|
|
- seqno) ||
|
|
|
- atomic_read(&dev_priv->mm.wedged), 3000))
|
|
|
- ret = -EBUSY;
|
|
|
- ring->waiting_seqno = 0;
|
|
|
+#define EXIT_COND \
|
|
|
+ (i915_seqno_passed(ring->get_seqno(ring), seqno) || \
|
|
|
+ atomic_read(&dev_priv->mm.wedged))
|
|
|
|
|
|
- trace_i915_gem_request_wait_end(ring, seqno);
|
|
|
- }
|
|
|
+ if (interruptible)
|
|
|
+ ret = wait_event_interruptible(ring->irq_queue,
|
|
|
+ EXIT_COND);
|
|
|
+ else
|
|
|
+ wait_event(ring->irq_queue, EXIT_COND);
|
|
|
+
|
|
|
+ ring->irq_put(ring);
|
|
|
+ trace_i915_gem_request_wait_end(ring, seqno);
|
|
|
+#undef EXIT_COND
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Waits for a sequence number to be signaled, and cleans up the
|
|
|
+ * request and object lists appropriately for that event.
|
|
|
+ */
|
|
|
+int
|
|
|
+i915_wait_request(struct intel_ring_buffer *ring,
|
|
|
+ uint32_t seqno)
|
|
|
+{
|
|
|
+ drm_i915_private_t *dev_priv = ring->dev->dev_private;
|
|
|
+ int ret = 0;
|
|
|
+
|
|
|
+ BUG_ON(seqno == 0);
|
|
|
+
|
|
|
+ ret = i915_gem_check_wedge(dev_priv);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = i915_gem_check_olr(ring, seqno);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ ret = __wait_seqno(ring, seqno, dev_priv->mm.interruptible);
|
|
|
if (atomic_read(&dev_priv->mm.wedged))
|
|
|
ret = -EAGAIN;
|
|
|
|
|
|
- /* Directly dispatch request retiring. While we have the work queue
|
|
|
- * to handle this, the waiter on a request often wants an associated
|
|
|
- * buffer to have made it to the inactive list, and we would need
|
|
|
- * a separate wait queue to handle that.
|
|
|
- */
|
|
|
- if (ret == 0 && do_retire)
|
|
|
- i915_gem_retire_requests_ring(ring);
|
|
|
-
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
@@ -1957,10 +1944,10 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj)
|
|
|
* it.
|
|
|
*/
|
|
|
if (obj->active) {
|
|
|
- ret = i915_wait_request(obj->ring, obj->last_rendering_seqno,
|
|
|
- true);
|
|
|
+ ret = i915_wait_request(obj->ring, obj->last_rendering_seqno);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
+ i915_gem_retire_requests_ring(obj->ring);
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
@@ -1998,22 +1985,9 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj,
|
|
|
if (seqno <= from->sync_seqno[idx])
|
|
|
return 0;
|
|
|
|
|
|
- if (seqno == from->outstanding_lazy_request) {
|
|
|
- struct drm_i915_gem_request *request;
|
|
|
-
|
|
|
- request = kzalloc(sizeof(*request), GFP_KERNEL);
|
|
|
- if (request == NULL)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- ret = i915_add_request(from, NULL, request);
|
|
|
- if (ret) {
|
|
|
- kfree(request);
|
|
|
- return ret;
|
|
|
- }
|
|
|
-
|
|
|
- seqno = request->seqno;
|
|
|
- }
|
|
|
-
|
|
|
+ ret = i915_gem_check_olr(obj->ring, seqno);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
|
|
|
ret = to->sync_to(to, from, seqno);
|
|
|
if (!ret)
|
|
@@ -2064,7 +2038,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
|
|
|
}
|
|
|
|
|
|
ret = i915_gem_object_finish_gpu(obj);
|
|
|
- if (ret == -ERESTARTSYS)
|
|
|
+ if (ret)
|
|
|
return ret;
|
|
|
/* Continue on if we fail due to EIO, the GPU is hung so we
|
|
|
* should be safe and we need to cleanup or else we might
|
|
@@ -2091,7 +2065,7 @@ i915_gem_object_unbind(struct drm_i915_gem_object *obj)
|
|
|
|
|
|
/* release the fence reg _after_ flushing */
|
|
|
ret = i915_gem_object_put_fence(obj);
|
|
|
- if (ret == -ERESTARTSYS)
|
|
|
+ if (ret)
|
|
|
return ret;
|
|
|
|
|
|
trace_i915_gem_object_unbind(obj);
|
|
@@ -2143,7 +2117,7 @@ i915_gem_flush_ring(struct intel_ring_buffer *ring,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int i915_ring_idle(struct intel_ring_buffer *ring, bool do_retire)
|
|
|
+static int i915_ring_idle(struct intel_ring_buffer *ring)
|
|
|
{
|
|
|
int ret;
|
|
|
|
|
@@ -2157,18 +2131,17 @@ static int i915_ring_idle(struct intel_ring_buffer *ring, bool do_retire)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
- return i915_wait_request(ring, i915_gem_next_request_seqno(ring),
|
|
|
- do_retire);
|
|
|
+ return i915_wait_request(ring, i915_gem_next_request_seqno(ring));
|
|
|
}
|
|
|
|
|
|
-int i915_gpu_idle(struct drm_device *dev, bool do_retire)
|
|
|
+int i915_gpu_idle(struct drm_device *dev)
|
|
|
{
|
|
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
|
|
int ret, i;
|
|
|
|
|
|
/* Flush everything onto the inactive list. */
|
|
|
for (i = 0; i < I915_NUM_RINGS; i++) {
|
|
|
- ret = i915_ring_idle(&dev_priv->ring[i], do_retire);
|
|
|
+ ret = i915_ring_idle(&dev_priv->ring[i]);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
}
|
|
@@ -2357,9 +2330,7 @@ i915_gem_object_flush_fence(struct drm_i915_gem_object *obj)
|
|
|
}
|
|
|
|
|
|
if (obj->last_fenced_seqno) {
|
|
|
- ret = i915_wait_request(obj->ring,
|
|
|
- obj->last_fenced_seqno,
|
|
|
- false);
|
|
|
+ ret = i915_wait_request(obj->ring, obj->last_fenced_seqno);
|
|
|
if (ret)
|
|
|
return ret;
|
|
|
|
|
@@ -2454,7 +2425,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
|
|
|
/* Have we updated the tiling parameters upon the object and so
|
|
|
* will need to serialise the write to the associated fence register?
|
|
|
*/
|
|
|
- if (obj->tiling_changed) {
|
|
|
+ if (obj->fence_dirty) {
|
|
|
ret = i915_gem_object_flush_fence(obj);
|
|
|
if (ret)
|
|
|
return ret;
|
|
@@ -2463,7 +2434,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
|
|
|
/* Just update our place in the LRU if our fence is getting reused. */
|
|
|
if (obj->fence_reg != I915_FENCE_REG_NONE) {
|
|
|
reg = &dev_priv->fence_regs[obj->fence_reg];
|
|
|
- if (!obj->tiling_changed) {
|
|
|
+ if (!obj->fence_dirty) {
|
|
|
list_move_tail(®->lru_list,
|
|
|
&dev_priv->mm.fence_list);
|
|
|
return 0;
|
|
@@ -2486,7 +2457,7 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
|
|
|
return 0;
|
|
|
|
|
|
i915_gem_object_update_fence(obj, reg, enable);
|
|
|
- obj->tiling_changed = false;
|
|
|
+ obj->fence_dirty = false;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -2732,6 +2703,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj)
|
|
|
int
|
|
|
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
|
|
|
{
|
|
|
+ drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
|
|
|
uint32_t old_write_domain, old_read_domains;
|
|
|
int ret;
|
|
|
|
|
@@ -2772,6 +2744,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
|
|
|
old_read_domains,
|
|
|
old_write_domain);
|
|
|
|
|
|
+ /* And bump the LRU for this access */
|
|
|
+ if (i915_gem_object_is_inactive(obj))
|
|
|
+ list_move_tail(&obj->mm_list, &dev_priv->mm.inactive_list);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -3020,28 +2996,7 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
|
|
|
if (seqno == 0)
|
|
|
return 0;
|
|
|
|
|
|
- ret = 0;
|
|
|
- if (!i915_seqno_passed(ring->get_seqno(ring), seqno)) {
|
|
|
- /* And wait for the seqno passing without holding any locks and
|
|
|
- * causing extra latency for others. This is safe as the irq
|
|
|
- * generation is designed to be run atomically and so is
|
|
|
- * lockless.
|
|
|
- */
|
|
|
- if (ring->irq_get(ring)) {
|
|
|
- ret = wait_event_interruptible(ring->irq_queue,
|
|
|
- i915_seqno_passed(ring->get_seqno(ring), seqno)
|
|
|
- || atomic_read(&dev_priv->mm.wedged));
|
|
|
- ring->irq_put(ring);
|
|
|
-
|
|
|
- if (ret == 0 && atomic_read(&dev_priv->mm.wedged))
|
|
|
- ret = -EIO;
|
|
|
- } else if (wait_for_atomic(i915_seqno_passed(ring->get_seqno(ring),
|
|
|
- seqno) ||
|
|
|
- atomic_read(&dev_priv->mm.wedged), 3000)) {
|
|
|
- ret = -EBUSY;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ ret = __wait_seqno(ring, seqno, true);
|
|
|
if (ret == 0)
|
|
|
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
|
|
|
|
|
@@ -3053,12 +3008,9 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
|
|
|
uint32_t alignment,
|
|
|
bool map_and_fenceable)
|
|
|
{
|
|
|
- struct drm_device *dev = obj->base.dev;
|
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
int ret;
|
|
|
|
|
|
BUG_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT);
|
|
|
- WARN_ON(i915_verify_lists(dev));
|
|
|
|
|
|
if (obj->gtt_space != NULL) {
|
|
|
if ((alignment && obj->gtt_offset & (alignment - 1)) ||
|
|
@@ -3086,34 +3038,20 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
|
|
|
if (!obj->has_global_gtt_mapping && map_and_fenceable)
|
|
|
i915_gem_gtt_bind_object(obj, obj->cache_level);
|
|
|
|
|
|
- if (obj->pin_count++ == 0) {
|
|
|
- if (!obj->active)
|
|
|
- list_move_tail(&obj->mm_list,
|
|
|
- &dev_priv->mm.pinned_list);
|
|
|
- }
|
|
|
+ obj->pin_count++;
|
|
|
obj->pin_mappable |= map_and_fenceable;
|
|
|
|
|
|
- WARN_ON(i915_verify_lists(dev));
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
void
|
|
|
i915_gem_object_unpin(struct drm_i915_gem_object *obj)
|
|
|
{
|
|
|
- struct drm_device *dev = obj->base.dev;
|
|
|
- drm_i915_private_t *dev_priv = dev->dev_private;
|
|
|
-
|
|
|
- WARN_ON(i915_verify_lists(dev));
|
|
|
BUG_ON(obj->pin_count == 0);
|
|
|
BUG_ON(obj->gtt_space == NULL);
|
|
|
|
|
|
- if (--obj->pin_count == 0) {
|
|
|
- if (!obj->active)
|
|
|
- list_move_tail(&obj->mm_list,
|
|
|
- &dev_priv->mm.inactive_list);
|
|
|
+ if (--obj->pin_count == 0)
|
|
|
obj->pin_mappable = false;
|
|
|
- }
|
|
|
- WARN_ON(i915_verify_lists(dev));
|
|
|
}
|
|
|
|
|
|
int
|
|
@@ -3237,20 +3175,9 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
|
|
|
if (obj->base.write_domain & I915_GEM_GPU_DOMAINS) {
|
|
|
ret = i915_gem_flush_ring(obj->ring,
|
|
|
0, obj->base.write_domain);
|
|
|
- } else if (obj->ring->outstanding_lazy_request ==
|
|
|
- obj->last_rendering_seqno) {
|
|
|
- struct drm_i915_gem_request *request;
|
|
|
-
|
|
|
- /* This ring is not being cleared by active usage,
|
|
|
- * so emit a request to do so.
|
|
|
- */
|
|
|
- request = kzalloc(sizeof(*request), GFP_KERNEL);
|
|
|
- if (request) {
|
|
|
- ret = i915_add_request(obj->ring, NULL, request);
|
|
|
- if (ret)
|
|
|
- kfree(request);
|
|
|
- } else
|
|
|
- ret = -ENOMEM;
|
|
|
+ } else {
|
|
|
+ ret = i915_gem_check_olr(obj->ring,
|
|
|
+ obj->last_rendering_seqno);
|
|
|
}
|
|
|
|
|
|
/* Update the active list for the hardware's current position.
|
|
@@ -3386,21 +3313,29 @@ int i915_gem_init_object(struct drm_gem_object *obj)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj)
|
|
|
+void i915_gem_free_object(struct drm_gem_object *gem_obj)
|
|
|
{
|
|
|
+ struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
|
|
|
struct drm_device *dev = obj->base.dev;
|
|
|
drm_i915_private_t *dev_priv = dev->dev_private;
|
|
|
- int ret;
|
|
|
-
|
|
|
- ret = i915_gem_object_unbind(obj);
|
|
|
- if (ret == -ERESTARTSYS) {
|
|
|
- list_move(&obj->mm_list,
|
|
|
- &dev_priv->mm.deferred_free_list);
|
|
|
- return;
|
|
|
- }
|
|
|
|
|
|
trace_i915_gem_object_destroy(obj);
|
|
|
|
|
|
+ if (obj->phys_obj)
|
|
|
+ i915_gem_detach_phys_object(dev, obj);
|
|
|
+
|
|
|
+ obj->pin_count = 0;
|
|
|
+ if (WARN_ON(i915_gem_object_unbind(obj) == -ERESTARTSYS)) {
|
|
|
+ bool was_interruptible;
|
|
|
+
|
|
|
+ was_interruptible = dev_priv->mm.interruptible;
|
|
|
+ dev_priv->mm.interruptible = false;
|
|
|
+
|
|
|
+ WARN_ON(i915_gem_object_unbind(obj));
|
|
|
+
|
|
|
+ dev_priv->mm.interruptible = was_interruptible;
|
|
|
+ }
|
|
|
+
|
|
|
if (obj->base.map_list.map)
|
|
|
drm_gem_free_mmap_offset(&obj->base);
|
|
|
|
|
@@ -3411,20 +3346,6 @@ static void i915_gem_free_object_tail(struct drm_i915_gem_object *obj)
|
|
|
kfree(obj);
|
|
|
}
|
|
|
|
|
|
-void i915_gem_free_object(struct drm_gem_object *gem_obj)
|
|
|
-{
|
|
|
- struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
|
|
|
- struct drm_device *dev = obj->base.dev;
|
|
|
-
|
|
|
- while (obj->pin_count > 0)
|
|
|
- i915_gem_object_unpin(obj);
|
|
|
-
|
|
|
- if (obj->phys_obj)
|
|
|
- i915_gem_detach_phys_object(dev, obj);
|
|
|
-
|
|
|
- i915_gem_free_object_tail(obj);
|
|
|
-}
|
|
|
-
|
|
|
int
|
|
|
i915_gem_idle(struct drm_device *dev)
|
|
|
{
|
|
@@ -3438,20 +3359,16 @@ i915_gem_idle(struct drm_device *dev)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- ret = i915_gpu_idle(dev, true);
|
|
|
+ ret = i915_gpu_idle(dev);
|
|
|
if (ret) {
|
|
|
mutex_unlock(&dev->struct_mutex);
|
|
|
return ret;
|
|
|
}
|
|
|
+ i915_gem_retire_requests(dev);
|
|
|
|
|
|
/* Under UMS, be paranoid and evict. */
|
|
|
- if (!drm_core_check_feature(dev, DRIVER_MODESET)) {
|
|
|
- ret = i915_gem_evict_inactive(dev, false);
|
|
|
- if (ret) {
|
|
|
- mutex_unlock(&dev->struct_mutex);
|
|
|
- return ret;
|
|
|
- }
|
|
|
- }
|
|
|
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
+ i915_gem_evict_everything(dev, false);
|
|
|
|
|
|
i915_gem_reset_fences(dev);
|
|
|
|
|
@@ -3489,9 +3406,9 @@ void i915_gem_init_swizzling(struct drm_device *dev)
|
|
|
|
|
|
I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_SWZCTL);
|
|
|
if (IS_GEN6(dev))
|
|
|
- I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_SNB));
|
|
|
+ I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_SNB));
|
|
|
else
|
|
|
- I915_WRITE(ARB_MODE, ARB_MODE_ENABLE(ARB_MODE_SWIZZLE_IVB));
|
|
|
+ I915_WRITE(ARB_MODE, _MASKED_BIT_ENABLE(ARB_MODE_SWIZZLE_IVB));
|
|
|
}
|
|
|
|
|
|
void i915_gem_init_ppgtt(struct drm_device *dev)
|
|
@@ -3540,7 +3457,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
|
|
|
ecochk = I915_READ(GAM_ECOCHK);
|
|
|
I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
|
|
|
ECOCHK_PPGTT_CACHE64B);
|
|
|
- I915_WRITE(GFX_MODE, GFX_MODE_ENABLE(GFX_PPGTT_ENABLE));
|
|
|
+ I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
|
|
|
} else if (INTEL_INFO(dev)->gen >= 7) {
|
|
|
I915_WRITE(GAM_ECOCHK, ECOCHK_PPGTT_CACHE64B);
|
|
|
/* GFX_MODE is per-ring on gen7+ */
|
|
@@ -3551,7 +3468,7 @@ void i915_gem_init_ppgtt(struct drm_device *dev)
|
|
|
|
|
|
if (INTEL_INFO(dev)->gen >= 7)
|
|
|
I915_WRITE(RING_MODE_GEN7(ring),
|
|
|
- GFX_MODE_ENABLE(GFX_PPGTT_ENABLE));
|
|
|
+ _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
|
|
|
|
|
|
I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
|
|
|
I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
|
|
@@ -3595,6 +3512,71 @@ cleanup_render_ring:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static bool
|
|
|
+intel_enable_ppgtt(struct drm_device *dev)
|
|
|
+{
|
|
|
+ if (i915_enable_ppgtt >= 0)
|
|
|
+ return i915_enable_ppgtt;
|
|
|
+
|
|
|
+#ifdef CONFIG_INTEL_IOMMU
|
|
|
+ /* Disable ppgtt on SNB if VT-d is on. */
|
|
|
+ if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
|
|
|
+ return false;
|
|
|
+#endif
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+int i915_gem_init(struct drm_device *dev)
|
|
|
+{
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+ unsigned long gtt_size, mappable_size;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ gtt_size = dev_priv->mm.gtt->gtt_total_entries << PAGE_SHIFT;
|
|
|
+ mappable_size = dev_priv->mm.gtt->gtt_mappable_entries << PAGE_SHIFT;
|
|
|
+
|
|
|
+ mutex_lock(&dev->struct_mutex);
|
|
|
+ if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
|
|
|
+ /* PPGTT pdes are stolen from global gtt ptes, so shrink the
|
|
|
+ * aperture accordingly when using aliasing ppgtt. */
|
|
|
+ gtt_size -= I915_PPGTT_PD_ENTRIES*PAGE_SIZE;
|
|
|
+
|
|
|
+ i915_gem_init_global_gtt(dev, 0, mappable_size, gtt_size);
|
|
|
+
|
|
|
+ ret = i915_gem_init_aliasing_ppgtt(dev);
|
|
|
+ if (ret) {
|
|
|
+ mutex_unlock(&dev->struct_mutex);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ /* Let GEM Manage all of the aperture.
|
|
|
+ *
|
|
|
+ * However, leave one page at the end still bound to the scratch
|
|
|
+ * page. There are a number of places where the hardware
|
|
|
+ * apparently prefetches past the end of the object, and we've
|
|
|
+ * seen multiple hangs with the GPU head pointer stuck in a
|
|
|
+ * batchbuffer bound at the last page of the aperture. One page
|
|
|
+ * should be enough to keep any prefetching inside of the
|
|
|
+ * aperture.
|
|
|
+ */
|
|
|
+ i915_gem_init_global_gtt(dev, 0, mappable_size,
|
|
|
+ gtt_size);
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = i915_gem_init_hw(dev);
|
|
|
+ mutex_unlock(&dev->struct_mutex);
|
|
|
+ if (ret) {
|
|
|
+ i915_gem_cleanup_aliasing_ppgtt(dev);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Allow hardware batchbuffers unless told otherwise, but not for KMS. */
|
|
|
+ if (!drm_core_check_feature(dev, DRIVER_MODESET))
|
|
|
+ dev_priv->dri1.allow_batchbuffer = 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
i915_gem_cleanup_ringbuffer(struct drm_device *dev)
|
|
|
{
|
|
@@ -3694,9 +3676,7 @@ i915_gem_load(struct drm_device *dev)
|
|
|
INIT_LIST_HEAD(&dev_priv->mm.active_list);
|
|
|
INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
|
|
|
INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
|
|
|
- INIT_LIST_HEAD(&dev_priv->mm.pinned_list);
|
|
|
INIT_LIST_HEAD(&dev_priv->mm.fence_list);
|
|
|
- INIT_LIST_HEAD(&dev_priv->mm.deferred_free_list);
|
|
|
INIT_LIST_HEAD(&dev_priv->mm.gtt_list);
|
|
|
for (i = 0; i < I915_NUM_RINGS; i++)
|
|
|
init_ring_lists(&dev_priv->ring[i]);
|
|
@@ -3708,12 +3688,8 @@ i915_gem_load(struct drm_device *dev)
|
|
|
|
|
|
/* On GEN3 we really need to make sure the ARB C3 LP bit is set */
|
|
|
if (IS_GEN3(dev)) {
|
|
|
- u32 tmp = I915_READ(MI_ARB_STATE);
|
|
|
- if (!(tmp & MI_ARB_C3_LP_WRITE_ENABLE)) {
|
|
|
- /* arb state is a masked write, so set bit + bit in mask */
|
|
|
- tmp = MI_ARB_C3_LP_WRITE_ENABLE | (MI_ARB_C3_LP_WRITE_ENABLE << MI_ARB_MASK_SHIFT);
|
|
|
- I915_WRITE(MI_ARB_STATE, tmp);
|
|
|
- }
|
|
|
+ I915_WRITE(MI_ARB_STATE,
|
|
|
+ _MASKED_BIT_ENABLE(MI_ARB_C3_LP_WRITE_ENABLE));
|
|
|
}
|
|
|
|
|
|
dev_priv->relative_constants_mode = I915_EXEC_CONSTANTS_REL_GENERAL;
|
|
@@ -4016,7 +3992,7 @@ rescan:
|
|
|
* This has a dramatic impact to reduce the number of
|
|
|
* OOM-killer events whilst running the GPU aggressively.
|
|
|
*/
|
|
|
- if (i915_gpu_idle(dev, true) == 0)
|
|
|
+ if (i915_gpu_idle(dev) == 0)
|
|
|
goto rescan;
|
|
|
}
|
|
|
mutex_unlock(&dev->struct_mutex);
|